LutherFieldStepInterpolator.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.math4.legacy.ode.nonstiff;

  18. import org.apache.commons.math4.legacy.core.Field;
  19. import org.apache.commons.math4.legacy.core.RealFieldElement;
  20. import org.apache.commons.math4.legacy.ode.FieldEquationsMapper;
  21. import org.apache.commons.math4.legacy.ode.FieldODEStateAndDerivative;

  22. /**
  23.  * This class represents an interpolator over the last step during an
  24.  * ODE integration for the 6th order Luther integrator.
  25.  *
  26.  * <p>This interpolator computes dense output inside the last
  27.  * step computed. The interpolation equation is consistent with the
  28.  * integration scheme.</p>
  29.  *
  30.  * @see LutherFieldIntegrator
  31.  * @param <T> the type of the field elements
  32.  * @since 3.6
  33.  */

  34. class LutherFieldStepInterpolator<T extends RealFieldElement<T>>
  35.     extends RungeKuttaFieldStepInterpolator<T> {

  36.     /** -49 - 49 q. */
  37.     private final T c5a;

  38.     /** 392 + 287 q. */
  39.     private final T c5b;

  40.     /** -637 - 357 q. */
  41.     private final T c5c;

  42.     /** 833 + 343 q. */
  43.     private final T c5d;

  44.     /** -49 + 49 q. */
  45.     private final T c6a;

  46.     /** -392 - 287 q. */
  47.     private final T c6b;

  48.     /** -637 + 357 q. */
  49.     private final T c6c;

  50.     /** 833 - 343 q. */
  51.     private final T c6d;

  52.     /** 49 + 49 q. */
  53.     private final T d5a;

  54.     /** -1372 - 847 q. */
  55.     private final T d5b;

  56.     /** 2254 + 1029 q. */
  57.     private final T d5c;

  58.     /** 49 - 49 q. */
  59.     private final T d6a;

  60.     /** -1372 + 847 q. */
  61.     private final T d6b;

  62.     /** 2254 - 1029 q. */
  63.     private final T d6c;

  64.     /** Simple constructor.
  65.      * @param field field to which the time and state vector elements belong
  66.      * @param forward integration direction indicator
  67.      * @param yDotK slopes at the intermediate points
  68.      * @param globalPreviousState start of the global step
  69.      * @param globalCurrentState end of the global step
  70.      * @param softPreviousState start of the restricted step
  71.      * @param softCurrentState end of the restricted step
  72.      * @param mapper equations mapper for the all equations
  73.      */
  74.     LutherFieldStepInterpolator(final Field<T> field, final boolean forward,
  75.                                 final T[][] yDotK,
  76.                                 final FieldODEStateAndDerivative<T> globalPreviousState,
  77.                                 final FieldODEStateAndDerivative<T> globalCurrentState,
  78.                                 final FieldODEStateAndDerivative<T> softPreviousState,
  79.                                 final FieldODEStateAndDerivative<T> softCurrentState,
  80.                                 final FieldEquationsMapper<T> mapper) {
  81.         super(field, forward, yDotK,
  82.               globalPreviousState, globalCurrentState, softPreviousState, softCurrentState,
  83.               mapper);
  84.         final T q = field.getZero().add(21).sqrt();
  85.         c5a = q.multiply(  -49).add(  -49);
  86.         c5b = q.multiply(  287).add(  392);
  87.         c5c = q.multiply( -357).add( -637);
  88.         c5d = q.multiply(  343).add(  833);
  89.         c6a = q.multiply(   49).add(  -49);
  90.         c6b = q.multiply( -287).add(  392);
  91.         c6c = q.multiply(  357).add( -637);
  92.         c6d = q.multiply( -343).add(  833);
  93.         d5a = q.multiply(   49).add(   49);
  94.         d5b = q.multiply( -847).add(-1372);
  95.         d5c = q.multiply( 1029).add( 2254);
  96.         d6a = q.multiply(  -49).add(   49);
  97.         d6b = q.multiply(  847).add(-1372);
  98.         d6c = q.multiply(-1029).add( 2254);
  99.     }

  100.     /** {@inheritDoc} */
  101.     @Override
  102.     protected LutherFieldStepInterpolator<T> create(final Field<T> newField, final boolean newForward, final T[][] newYDotK,
  103.                                                     final FieldODEStateAndDerivative<T> newGlobalPreviousState,
  104.                                                     final FieldODEStateAndDerivative<T> newGlobalCurrentState,
  105.                                                     final FieldODEStateAndDerivative<T> newSoftPreviousState,
  106.                                                     final FieldODEStateAndDerivative<T> newSoftCurrentState,
  107.                                                     final FieldEquationsMapper<T> newMapper) {
  108.         return new LutherFieldStepInterpolator<>(newField, newForward, newYDotK,
  109.                                                   newGlobalPreviousState, newGlobalCurrentState,
  110.                                                   newSoftPreviousState, newSoftCurrentState,
  111.                                                   newMapper);
  112.     }

  113.     /** {@inheritDoc} */
  114.     @SuppressWarnings("unchecked")
  115.     @Override
  116.     protected FieldODEStateAndDerivative<T> computeInterpolatedStateAndDerivatives(final FieldEquationsMapper<T> mapper,
  117.                                                                                    final T time, final T theta,
  118.                                                                                    final T thetaH, final T oneMinusThetaH) {

  119.         // the coefficients below have been computed by solving the
  120.         // order conditions from a theorem from Butcher (1963), using
  121.         // the method explained in Folkmar Bornemann paper "Runge-Kutta
  122.         // Methods, Trees, and Maple", Center of Mathematical Sciences, Munich
  123.         // University of Technology, February 9, 2001
  124.         //<http://wwwzenger.informatik.tu-muenchen.de/selcuk/sjam012101.html>

  125.         // the method is implemented in the rkcheck tool
  126.         // <https://www.spaceroots.org/software/rkcheck/index.html>.
  127.         // Running it for order 5 gives the following order conditions
  128.         // for an interpolator:
  129.         // order 1 conditions
  130.         // \sum_{i=1}^{i=s}\left(b_{i} \right) =1
  131.         // order 2 conditions
  132.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}\right) = \frac{\theta}{2}
  133.         // order 3 conditions
  134.         // \sum_{i=2}^{i=s}\left(b_{i} \sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j} \right)}\right) = \frac{\theta^{2}}{6}
  135.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}^{2}\right) = \frac{\theta^{2}}{3}
  136.         // order 4 conditions
  137.         // \sum_{i=3}^{i=s}\left(b_{i} \sum_{j=2}^{j=i-1}{\left(a_{i,j} \sum_{k=1}^{k=j-1}{\left(a_{j,k} c_{k} \right)} \right)}\right) = \frac{\theta^{3}}{24}
  138.         // \sum_{i=2}^{i=s}\left(b_{i} \sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j}^{2} \right)}\right) = \frac{\theta^{3}}{12}
  139.         // \sum_{i=2}^{i=s}\left(b_{i} c_{i}\sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j} \right)}\right) = \frac{\theta^{3}}{8}
  140.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}^{3}\right) = \frac{\theta^{3}}{4}
  141.         // order 5 conditions
  142.         // \sum_{i=4}^{i=s}\left(b_{i} \sum_{j=3}^{j=i-1}{\left(a_{i,j} \sum_{k=2}^{k=j-1}{\left(a_{j,k} \sum_{l=1}^{l=k-1}{\left(a_{k,l} c_{l} \right)} \right)} \right)}\right) = \frac{\theta^{4}}{120}
  143.         // \sum_{i=3}^{i=s}\left(b_{i} \sum_{j=2}^{j=i-1}{\left(a_{i,j} \sum_{k=1}^{k=j-1}{\left(a_{j,k} c_{k}^{2} \right)} \right)}\right) = \frac{\theta^{4}}{60}
  144.         // \sum_{i=3}^{i=s}\left(b_{i} \sum_{j=2}^{j=i-1}{\left(a_{i,j} c_{j}\sum_{k=1}^{k=j-1}{\left(a_{j,k} c_{k} \right)} \right)}\right) = \frac{\theta^{4}}{40}
  145.         // \sum_{i=2}^{i=s}\left(b_{i} \sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j}^{3} \right)}\right) = \frac{\theta^{4}}{20}
  146.         // \sum_{i=3}^{i=s}\left(b_{i} c_{i}\sum_{j=2}^{j=i-1}{\left(a_{i,j} \sum_{k=1}^{k=j-1}{\left(a_{j,k} c_{k} \right)} \right)}\right) = \frac{\theta^{4}}{30}
  147.         // \sum_{i=2}^{i=s}\left(b_{i} c_{i}\sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j}^{2} \right)}\right) = \frac{\theta^{4}}{15}
  148.         // \sum_{i=2}^{i=s}\left(b_{i} \left(\sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j} \right)} \right)^{2}\right) = \frac{\theta^{4}}{20}
  149.         // \sum_{i=2}^{i=s}\left(b_{i} c_{i}^{2}\sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j} \right)}\right) = \frac{\theta^{4}}{10}
  150.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}^{4}\right) = \frac{\theta^{4}}{5}

  151.         // The a_{j,k} and c_{k} are given by the integrator Butcher arrays. What remains to solve
  152.         // are the b_i for the interpolator. They are found by solving the above equations.
  153.         // For a given interpolator, some equations are redundant, so in our case when we select
  154.         // all equations from order 1 to 4, we still don't have enough independent equations
  155.         // to solve from b_1 to b_7. We need to also select one equation from order 5. Here,
  156.         // we selected the last equation. It appears this choice implied at least the last 3 equations
  157.         // are fulfilled, but some of the former ones are not, so the resulting interpolator is order 5.
  158.         // At the end, we get the b_i as polynomials in theta.

  159.         final T coeffDot1 =  theta.multiply(theta.multiply(theta.multiply(theta.multiply(   21        ).add( -47          )).add(   36         )).add( -54     /   5.0)).add(1);
  160.         final T coeffDot2 =  time.getField().getZero();
  161.         final T coeffDot3 =  theta.multiply(theta.multiply(theta.multiply(theta.multiply(  112        ).add(-608    /  3.0)).add(  320   / 3.0 )).add(-208    /  15.0));
  162.         final T coeffDot4 =  theta.multiply(theta.multiply(theta.multiply(theta.multiply( -567  /  5.0).add( 972    /  5.0)).add( -486   / 5.0 )).add( 324    /  25.0));
  163.         final T coeffDot5 =  theta.multiply(theta.multiply(theta.multiply(theta.multiply(c5a.divide(5)).add(c5b.divide(15))).add(c5c.divide(30))).add(c5d.divide(150)));
  164.         final T coeffDot6 =  theta.multiply(theta.multiply(theta.multiply(theta.multiply(c6a.divide(5)).add(c6b.divide(15))).add(c6c.divide(30))).add(c6d.divide(150)));
  165.         final T coeffDot7 =  theta.multiply(theta.multiply(theta.multiply(                                             3.0 ).add(   -3         )).add(   3   /   5.0));
  166.         final T[] interpolatedState;
  167.         final T[] interpolatedDerivatives;

  168.         if (getGlobalPreviousState() != null && theta.getReal() <= 0.5) {

  169.             final T s         = thetaH;
  170.             final T coeff1    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply(  21    /  5.0).add( -47    /  4.0)).add(   12         )).add( -27    /   5.0)).add(1));
  171.             final T coeff2    = time.getField().getZero();
  172.             final T coeff3    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply( 112    /  5.0).add(-152    /  3.0)).add(  320   / 9.0 )).add(-104    /  15.0)));
  173.             final T coeff4    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply(-567    / 25.0).add( 243    /  5.0)).add( -162   / 5.0 )).add( 162    /  25.0)));
  174.             final T coeff5    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply(c5a.divide(25)).add(c5b.divide(60))).add(c5c.divide(90))).add(c5d.divide(300))));
  175.             final T coeff6    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply(c6a.divide(25)).add(c6b.divide(60))).add(c6c.divide(90))).add(c6d.divide(300))));
  176.             final T coeff7    = s.multiply(theta.multiply(theta.multiply(theta.multiply(                                      3    /  4.0 ).add(   -1         )).add(   3    /  10.0)));
  177.             interpolatedState       = previousStateLinearCombination(coeff1, coeff2, coeff3, coeff4, coeff5, coeff6, coeff7);
  178.             interpolatedDerivatives = derivativeLinearCombination(coeffDot1, coeffDot2, coeffDot3, coeffDot4, coeffDot5, coeffDot6, coeffDot7);
  179.         } else {

  180.             final T s         = oneMinusThetaH;
  181.             final T coeff1    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply( -21   /   5.0).add(   151  /  20.0)).add( -89   /   20.0)).add(  19 /  20.0)).add(- 1 / 20.0));
  182.             final T coeff2    = time.getField().getZero();
  183.             final T coeff3    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply(-112   /   5.0).add(   424  /  15.0)).add( -328  /   45.0)).add( -16 /  45.0)).add(-16 /  45.0));
  184.             final T coeff4    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply( 567   /  25.0).add(  -648  /  25.0)).add(  162  /   25.0))));
  185.             final T coeff5    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply(d5a.divide(25)).add(d5b.divide(300))).add(d5c.divide(900))).add( -49 / 180.0)).add(-49 / 180.0));
  186.             final T coeff6    = s.multiply(theta.multiply(theta.multiply(theta.multiply(theta.multiply(d6a.divide(25)).add(d6b.divide(300))).add(d6c.divide(900))).add( -49 / 180.0)).add(-49 / 180.0));
  187.             final T coeff7    = s.multiply(               theta.multiply(theta.multiply(theta.multiply(                        -3  /   4.0 ).add(   1   /    4.0)).add(  -1 /  20.0)).add( -1 /  20.0));
  188.             interpolatedState       = currentStateLinearCombination(coeff1, coeff2, coeff3, coeff4, coeff5, coeff6, coeff7);
  189.             interpolatedDerivatives = derivativeLinearCombination(coeffDot1, coeffDot2, coeffDot3, coeffDot4, coeffDot5, coeffDot6, coeffDot7);
  190.         }

  191.         return new FieldODEStateAndDerivative<>(time, interpolatedState, interpolatedDerivatives);
  192.     }
  193. }