LutherStateInterpolator.java

  1. /*
  2.  * Licensed to the Hipparchus project 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 Hipparchus project 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.  *      https://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.hipparchus.ode.nonstiff.interpolators;

  18. import org.hipparchus.ode.EquationsMapper;
  19. import org.hipparchus.ode.ODEStateAndDerivative;
  20. import org.hipparchus.ode.nonstiff.LutherIntegrator;
  21. import org.hipparchus.util.FastMath;

  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 LutherIntegrator
  31.  */

  32. public class LutherStateInterpolator extends RungeKuttaStateInterpolator {

  33.     /** Serializable version identifier */
  34.     private static final long serialVersionUID = 20160328;

  35.     /** Square root. */
  36.     private static final double Q = FastMath.sqrt(21);

  37.     /** Simple constructor.
  38.      * @param forward integration direction indicator
  39.      * @param yDotK slopes at the intermediate points
  40.      * @param globalPreviousState start of the global step
  41.      * @param globalCurrentState end of the global step
  42.      * @param softPreviousState start of the restricted step
  43.      * @param softCurrentState end of the restricted step
  44.      * @param mapper equations mapper for the all equations
  45.      */
  46.     public LutherStateInterpolator(final boolean forward,
  47.                                    final double[][] yDotK,
  48.                                    final ODEStateAndDerivative globalPreviousState,
  49.                                    final ODEStateAndDerivative globalCurrentState,
  50.                                    final ODEStateAndDerivative softPreviousState,
  51.                                    final ODEStateAndDerivative softCurrentState,
  52.                                    final EquationsMapper mapper) {
  53.         super(forward, yDotK, globalPreviousState, globalCurrentState, softPreviousState, softCurrentState, mapper);
  54.     }

  55.     /** {@inheritDoc} */
  56.     @Override
  57.     protected LutherStateInterpolator create(final boolean newForward, final double[][] newYDotK,
  58.                                              final ODEStateAndDerivative newGlobalPreviousState,
  59.                                              final ODEStateAndDerivative newGlobalCurrentState,
  60.                                              final ODEStateAndDerivative newSoftPreviousState,
  61.                                              final ODEStateAndDerivative newSoftCurrentState,
  62.                                              final EquationsMapper newMapper) {
  63.         return new LutherStateInterpolator(newForward, newYDotK,
  64.                                            newGlobalPreviousState, newGlobalCurrentState,
  65.                                            newSoftPreviousState, newSoftCurrentState,
  66.                                            newMapper);
  67.     }

  68.     /** {@inheritDoc} */
  69.     @Override
  70.     protected ODEStateAndDerivative computeInterpolatedStateAndDerivatives(final EquationsMapper mapper,
  71.                                                                            final double time, final double theta,
  72.                                                                            final double thetaH, final double oneMinusThetaH) {

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

  79.         // the method is implemented in the rkcheck tool
  80.         // <https://www.spaceroots.org/software/rkcheck/index.html>.
  81.         // Running it for order 5 gives the following order conditions
  82.         // for an interpolator:
  83.         // order 1 conditions
  84.         // \sum_{i=1}^{i=s}\left(b_{i} \right) =1
  85.         // order 2 conditions
  86.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}\right) = \frac{\theta}{2}
  87.         // order 3 conditions
  88.         // \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}
  89.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}^{2}\right) = \frac{\theta^{2}}{3}
  90.         // order 4 conditions
  91.         // \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}
  92.         // \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}
  93.         // \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}
  94.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}^{3}\right) = \frac{\theta^{3}}{4}
  95.         // order 5 conditions
  96.         // \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}
  97.         // \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}
  98.         // \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}
  99.         // \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}
  100.         // \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}
  101.         // \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}
  102.         // \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}
  103.         // \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}
  104.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}^{4}\right) = \frac{\theta^{4}}{5}

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

  113.         final double[] interpolatedState;
  114.         final double[] interpolatedDerivatives;

  115.         final double coeffDot1 =  1 + theta * ( -54            /   5.0 + theta * (   36                   + theta * ( -47                   + theta *   21)));
  116.         final double coeffDot2 =  0;
  117.         final double coeffDot3 =      theta * (-208            /  15.0 + theta * (  320            / 3.0  + theta * (-608            /  3.0 + theta *  112)));
  118.         final double coeffDot4 =      theta * ( 324            /  25.0 + theta * ( -486            / 5.0  + theta * ( 972            /  5.0 + theta * -567           /  5.0)));
  119.         final double coeffDot5 =      theta * ((833 + 343 * Q) / 150.0 + theta * ((-637 - 357 * Q) / 30.0 + theta * ((392 + 287 * Q) / 15.0 + theta * (-49 - 49 * Q) /  5.0)));
  120.         final double coeffDot6 =      theta * ((833 - 343 * Q) / 150.0 + theta * ((-637 + 357 * Q) / 30.0 + theta * ((392 - 287 * Q) / 15.0 + theta * (-49 + 49 * Q) /  5.0)));
  121.         final double coeffDot7 =      theta * (   3            /   5.0 + theta * (   -3                   + theta *     3));

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

  123.             final double coeff1    =  1 + theta * ( -27            /   5.0 + theta * (   12                   + theta * ( -47            /  4.0 + theta *   21           /  5.0)));
  124.             final double coeff2    =  0;
  125.             final double coeff3    =      theta * (-104            /  15.0 + theta * (  320            / 9.0  + theta * (-152            /  3.0 + theta *  112           /  5.0)));
  126.             final double coeff4    =      theta * ( 162            /  25.0 + theta * ( -162            / 5.0  + theta * ( 243            /  5.0 + theta * -567           / 25.0)));
  127.             final double coeff5    =      theta * ((833 + 343 * Q) / 300.0 + theta * ((-637 - 357 * Q) / 90.0 + theta * ((392 + 287 * Q) / 60.0 + theta * (-49 - 49 * Q) / 25.0)));
  128.             final double coeff6    =      theta * ((833 - 343 * Q) / 300.0 + theta * ((-637 + 357 * Q) / 90.0 + theta * ((392 - 287 * Q) / 60.0 + theta * (-49 + 49 * Q) / 25.0)));
  129.             final double coeff7    =      theta * (   3            /  10.0 + theta * (   -1                   + theta * (   3            /  4.0)));
  130.             interpolatedState       = previousStateLinearCombination(thetaH * coeff1, thetaH * coeff2,
  131.                                                                      thetaH * coeff3, thetaH * coeff4,
  132.                                                                      thetaH * coeff5, thetaH * coeff6,
  133.                                                                      thetaH * coeff7);
  134.             interpolatedDerivatives = derivativeLinearCombination(coeffDot1, coeffDot2, coeffDot3, coeffDot4, coeffDot5, coeffDot6, coeffDot7);
  135.         } else {

  136.             final double coeff1    =  -1 /  20.0 + theta * (  19            /  20.0 + theta * (  -89             /  20.0  + theta * (   151            /  20.0 + theta *  -21           /   5.0)));
  137.             final double coeff2    =  0;
  138.             final double coeff3    = -16 /  45.0 + theta * ( -16            /  45.0 + theta * ( -328             /  45.0  + theta * (   424            /  15.0 + theta * -112           /   5.0)));
  139.             final double coeff4    =               theta * (                          theta * (  162             /  25.0  + theta * (  -648            /  25.0 + theta *  567           /  25.0)));
  140.             final double coeff5    = -49 / 180.0 + theta * ( -49            / 180.0 + theta * ((2254 + 1029 * Q) / 900.0  + theta * ((-1372 - 847 * Q) / 300.0 + theta * ( 49 + 49 * Q) /  25.0)));
  141.             final double coeff6    = -49 / 180.0 + theta * ( -49            / 180.0 + theta * ((2254 - 1029 * Q) / 900.0  + theta * ((-1372 + 847 * Q) / 300.0 + theta * ( 49 - 49 * Q) /  25.0)));
  142.             final double coeff7    =  -1 /  20.0 + theta * (  -1            /  20.0 + theta * (    1             /   4.0  + theta * (    -3            /   4.0)));
  143.             interpolatedState       = currentStateLinearCombination(oneMinusThetaH * coeff1, oneMinusThetaH * coeff2,
  144.                                                                     oneMinusThetaH * coeff3, oneMinusThetaH * coeff4,
  145.                                                                     oneMinusThetaH * coeff5, oneMinusThetaH * coeff6,
  146.                                                                     oneMinusThetaH * coeff7);
  147.             interpolatedDerivatives = derivativeLinearCombination(coeffDot1, coeffDot2, coeffDot3, coeffDot4, coeffDot5, coeffDot6, coeffDot7);
  148.         }

  149.         return mapper.mapStateAndDerivative(time, interpolatedState, interpolatedDerivatives);

  150.     }

  151. }