GraggBulirschStoerStateInterpolator.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.GraggBulirschStoerIntegrator;
  21. import org.hipparchus.ode.sampling.AbstractODEStateInterpolator;
  22. import org.hipparchus.util.FastMath;

  23. /**
  24.  * This class implements an interpolator for the Gragg-Bulirsch-Stoer
  25.  * integrator.
  26.  *
  27.  * <p>This interpolator compute dense output inside the last step
  28.  * produced by a Gragg-Bulirsch-Stoer integrator.</p>
  29.  *
  30.  * <p>
  31.  * This implementation is basically a reimplementation in Java of the
  32.  * <a
  33.  * href="http://www.unige.ch/math/folks/hairer/prog/nonstiff/odex.f">odex</a>
  34.  * fortran code by E. Hairer and G. Wanner. The redistribution policy
  35.  * for this code is available <a
  36.  * href="http://www.unige.ch/~hairer/prog/licence.txt">here</a>, for
  37.  * convenience, it is reproduced below.</p>
  38.  *
  39.  * <blockquote>
  40.  * <p>Copyright (c) 2004, Ernst Hairer</p>
  41.  *
  42.  * <p>Redistribution and use in source and binary forms, with or
  43.  * without modification, are permitted provided that the following
  44.  * conditions are met:</p>
  45.  * <ul>
  46.  *  <li>Redistributions of source code must retain the above copyright
  47.  *      notice, this list of conditions and the following disclaimer.</li>
  48.  *  <li>Redistributions in binary form must reproduce the above copyright
  49.  *      notice, this list of conditions and the following disclaimer in the
  50.  *      documentation and/or other materials provided with the distribution.</li>
  51.  * </ul>
  52.  *
  53.  * <p><strong>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  54.  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
  55.  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  56.  * FOR A  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
  57.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  58.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  59.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  60.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  61.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  62.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  63.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</strong></p>
  64.  * </blockquote>
  65.  *
  66.  * @see GraggBulirschStoerIntegrator
  67.  */

  68. public class GraggBulirschStoerStateInterpolator extends AbstractODEStateInterpolator {

  69.     /** Serializable version identifier. */
  70.     private static final long serialVersionUID = 20160329L;

  71.     /** Scaled derivatives at the middle of the step $\tau$.
  72.      * (element k is $h^{k} d^{k}y(\tau)/dt^{k}$ where h is step size...)
  73.      */
  74.     private final double[][] yMidDots;

  75.     /** Interpolation polynomials. */
  76.     private final double[][] polynomials;

  77.     /** Error coefficients for the interpolation. */
  78.     private final double[] errfac;

  79.     /** Degree of the interpolation polynomials. */
  80.     private final int currentDegree;

  81.     /** Simple constructor.
  82.      * @param forward integration direction indicator
  83.      * @param globalPreviousState start of the global step
  84.      * @param globalCurrentState end of the global step
  85.      * @param softPreviousState start of the restricted step
  86.      * @param softCurrentState end of the restricted step
  87.      * @param mapper equations mapper for the all equations
  88.      * @param yMidDots scaled derivatives at the middle of the step $\tau$
  89.      * (element k is $h^{k} d^{k}y(\tau)/dt^{k}$ where h is step size...)
  90.      * @param mu degree of the interpolation polynomial
  91.      */
  92.     public GraggBulirschStoerStateInterpolator(final boolean forward,
  93.                                                final ODEStateAndDerivative globalPreviousState,
  94.                                                final ODEStateAndDerivative globalCurrentState,
  95.                                                final ODEStateAndDerivative softPreviousState,
  96.                                                final ODEStateAndDerivative softCurrentState,
  97.                                                final EquationsMapper mapper,
  98.                                                final double[][] yMidDots,
  99.                                                final int mu) {
  100.         super(forward, globalPreviousState, globalCurrentState, softPreviousState, softCurrentState, mapper);

  101.         this.yMidDots      = yMidDots.clone();
  102.         this.currentDegree = mu + 4;
  103.         this.polynomials   = new double[currentDegree + 1][getCurrentState().getCompleteStateDimension()];

  104.         // initialize the error factors array for interpolation
  105.         if (currentDegree <= 4) {
  106.             errfac = null;
  107.         } else {
  108.             errfac = new double[currentDegree - 4];
  109.             for (int i = 0; i < errfac.length; ++i) {
  110.                 final int ip5 = i + 5;
  111.                 errfac[i] = 1.0 / (ip5 * ip5);
  112.                 final double e = 0.5 * FastMath.sqrt (((double) (i + 1)) / ip5);
  113.                 for (int j = 0; j <= i; ++j) {
  114.                     errfac[i] *= e / (j + 1);
  115.                 }
  116.             }
  117.         }

  118.         // compute the interpolation coefficients
  119.         computeCoefficients(mu);

  120.     }

  121.     /** {@inheritDoc} */
  122.     @Override
  123.     protected GraggBulirschStoerStateInterpolator create(final boolean newForward,
  124.                                                          final ODEStateAndDerivative newGlobalPreviousState,
  125.                                                          final ODEStateAndDerivative newGlobalCurrentState,
  126.                                                          final ODEStateAndDerivative newSoftPreviousState,
  127.                                                          final ODEStateAndDerivative newSoftCurrentState,
  128.                                                          final EquationsMapper newMapper) {
  129.         return new GraggBulirschStoerStateInterpolator(newForward,
  130.                                                        newGlobalPreviousState, newGlobalCurrentState,
  131.                                                        newSoftPreviousState, newSoftCurrentState,
  132.                                                        newMapper, yMidDots, currentDegree - 4);
  133.     }

  134.     /** Compute the interpolation coefficients for dense output.
  135.      * @param mu degree of the interpolation polynomial
  136.      */
  137.     private void computeCoefficients(final int mu) {

  138.         final double[] y0Dot = getGlobalPreviousState().getCompleteDerivative();
  139.         final double[] y1Dot = getGlobalCurrentState().getCompleteDerivative();
  140.         final double[] y1    = getGlobalCurrentState().getCompleteState();

  141.         final double[] previousState = getGlobalPreviousState().getCompleteState();
  142.         final double h = getGlobalCurrentState().getTime() - getGlobalPreviousState().getTime();
  143.         for (int i = 0; i < previousState.length; ++i) {

  144.             final double yp0   = h * y0Dot[i];
  145.             final double yp1   = h * y1Dot[i];
  146.             final double ydiff = y1[i] - previousState[i];
  147.             final double aspl  = ydiff - yp1;
  148.             final double bspl  = yp0 - ydiff;

  149.             polynomials[0][i] = previousState[i];
  150.             polynomials[1][i] = ydiff;
  151.             polynomials[2][i] = aspl;
  152.             polynomials[3][i] = bspl;

  153.             if (mu < 0) {
  154.                 return;
  155.             }

  156.             // compute the remaining coefficients
  157.             final double ph0 = 0.5 * (previousState[i] + y1[i]) + 0.125 * (aspl + bspl);
  158.             polynomials[4][i] = 16 * (yMidDots[0][i] - ph0);

  159.             if (mu > 0) {
  160.                 final double ph1 = ydiff + 0.25 * (aspl - bspl);
  161.                 polynomials[5][i] = 16 * (yMidDots[1][i] - ph1);

  162.                 if (mu > 1) {
  163.                     final double ph2 = yp1 - yp0;
  164.                     polynomials[6][i] = 16 * (yMidDots[2][i] - ph2 + polynomials[4][i]);

  165.                     if (mu > 2) {
  166.                         final double ph3 = 6 * (bspl - aspl);
  167.                         polynomials[7][i] = 16 * (yMidDots[3][i] - ph3 + 3 * polynomials[5][i]);

  168.                         for (int j = 4; j <= mu; ++j) {
  169.                             final double fac1 = 0.5 * j * (j - 1);
  170.                             final double fac2 = 2 * fac1 * (j - 2) * (j - 3);
  171.                             polynomials[j+4][i] =
  172.                                             16 * (yMidDots[j][i] + fac1 * polynomials[j+2][i] - fac2 * polynomials[j][i]);
  173.                         }

  174.                     }
  175.                 }
  176.             }
  177.         }

  178.     }

  179.     /** Estimate interpolation error.
  180.      * @param scale scaling array
  181.      * @return estimate of the interpolation error
  182.      */
  183.     public double estimateError(final double[] scale) {
  184.         double error = 0;
  185.         if (currentDegree >= 5) {
  186.             for (int i = 0; i < scale.length; ++i) {
  187.                 final double e = polynomials[currentDegree][i] / scale[i];
  188.                 error += e * e;
  189.             }
  190.             error = FastMath.sqrt(error / scale.length) * errfac[currentDegree - 5];
  191.         }
  192.         return error;
  193.     }

  194.     /** {@inheritDoc} */
  195.     @Override
  196.     protected ODEStateAndDerivative computeInterpolatedStateAndDerivatives(final EquationsMapper mapper,
  197.                                                                            final double time, final double theta,
  198.                                                                            final double thetaH, final double oneMinusThetaH) {

  199.         final int dimension = mapper.getTotalDimension();

  200.         final double h             = thetaH / theta;
  201.         final double oneMinusTheta = 1.0 - theta;
  202.         final double theta05       = theta - 0.5;
  203.         final double tOmT          = theta * oneMinusTheta;
  204.         final double t4            = tOmT * tOmT;
  205.         final double t4Dot         = 2 * tOmT * (1 - 2 * theta);
  206.         final double dot1          = 1.0 / h;
  207.         final double dot2          = theta * (2 - 3 * theta) / h;
  208.         final double dot3          = ((3 * theta - 4) * theta + 1) / h;

  209.         final double[] interpolatedState       = new double[dimension];
  210.         final double[] interpolatedDerivatives = new double[dimension];
  211.         for (int i = 0; i < dimension; ++i) {

  212.             final double p0 = polynomials[0][i];
  213.             final double p1 = polynomials[1][i];
  214.             final double p2 = polynomials[2][i];
  215.             final double p3 = polynomials[3][i];
  216.             interpolatedState[i] = p0 + theta * (p1 + oneMinusTheta * (p2 * theta + p3 * oneMinusTheta));
  217.             interpolatedDerivatives[i] = dot1 * p1 + dot2 * p2 + dot3 * p3;

  218.             if (currentDegree > 3) {
  219.                 double cDot = 0;
  220.                 double c = polynomials[currentDegree][i];
  221.                 for (int j = currentDegree - 1; j > 3; --j) {
  222.                     final double d = 1.0 / (j - 3);
  223.                     cDot = d * (theta05 * cDot + c);
  224.                     c = polynomials[j][i] + c * d * theta05;
  225.                 }
  226.                 interpolatedState[i]       += t4 * c;
  227.                 interpolatedDerivatives[i] += (t4 * cDot + t4Dot * c) / h;
  228.             }

  229.         }

  230.         if (h == 0) {
  231.             // in this degenerated case, the previous computation leads to NaN for derivatives
  232.             // we fix this by using the derivatives at midpoint
  233.             System.arraycopy(yMidDots[1], 0, interpolatedDerivatives, 0, dimension);
  234.         }

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

  236.     }

  237. }