FixedStepRungeKuttaIntegrator.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;


  18. import org.hipparchus.exception.MathIllegalArgumentException;
  19. import org.hipparchus.exception.MathIllegalStateException;
  20. import org.hipparchus.ode.AbstractIntegrator;
  21. import org.hipparchus.ode.EquationsMapper;
  22. import org.hipparchus.ode.ExpandableODE;
  23. import org.hipparchus.ode.LocalizedODEFormats;
  24. import org.hipparchus.ode.ODEState;
  25. import org.hipparchus.ode.ODEStateAndDerivative;
  26. import org.hipparchus.ode.nonstiff.interpolators.RungeKuttaStateInterpolator;
  27. import org.hipparchus.util.FastMath;

  28. /**
  29.  * This class implements the common part of all fixed step Runge-Kutta
  30.  * integrators for Ordinary Differential Equations.
  31.  *
  32.  * <p>These methods are explicit Runge-Kutta methods, their Butcher
  33.  * arrays are as follows :</p>
  34.  * <pre>
  35.  *    0  |
  36.  *   c2  | a21
  37.  *   c3  | a31  a32
  38.  *   ... |        ...
  39.  *   cs  | as1  as2  ...  ass-1
  40.  *       |--------------------------
  41.  *       |  b1   b2  ...   bs-1  bs
  42.  * </pre>
  43.  *
  44.  * @see EulerIntegrator
  45.  * @see ClassicalRungeKuttaIntegrator
  46.  * @see GillIntegrator
  47.  * @see MidpointIntegrator
  48.  */

  49. public abstract class FixedStepRungeKuttaIntegrator extends AbstractIntegrator
  50.         implements ExplicitRungeKuttaIntegrator {

  51.     /** Time steps from Butcher array (without the first zero). */
  52.     private final double[] c;

  53.     /** Internal weights from Butcher array (without the first empty row). */
  54.     private final double[][] a;

  55.     /** External weights for the high order method from Butcher array. */
  56.     private final double[] b;

  57.     /** Integration step. */
  58.     private final double step;

  59.     /** Simple constructor.
  60.      * Build a Runge-Kutta integrator with the given
  61.      * step. The default step handler does nothing.
  62.      * @param name name of the method
  63.      * @param step integration step
  64.      */
  65.     protected FixedStepRungeKuttaIntegrator(final String name, final double step) {
  66.         super(name);
  67.         this.c    = getC();
  68.         this.a    = getA();
  69.         this.b    = getB();
  70.         this.step = FastMath.abs(step);
  71.     }

  72.     /** Getter for the default, positive step-size assigned at constructor level.
  73.      * @return step
  74.      */
  75.     public double getDefaultStep() {
  76.         return this.step;
  77.     }

  78.     /** Create an interpolator.
  79.      * @param forward integration direction indicator
  80.      * @param yDotK slopes at the intermediate points
  81.      * @param globalPreviousState start of the global step
  82.      * @param globalCurrentState end of the global step
  83.      * @param mapper equations mapper for the all equations
  84.      * @return external weights for the high order method from Butcher array
  85.      */
  86.     protected abstract RungeKuttaStateInterpolator createInterpolator(boolean forward, double[][] yDotK,
  87.                                                                       ODEStateAndDerivative globalPreviousState,
  88.                                                                       ODEStateAndDerivative globalCurrentState,
  89.                                                                       EquationsMapper mapper);

  90.     /** {@inheritDoc} */
  91.     @Override
  92.     public ODEStateAndDerivative integrate(final ExpandableODE equations,
  93.                                            final ODEState initialState, final double finalTime)
  94.         throws MathIllegalArgumentException, MathIllegalStateException {

  95.         sanityChecks(initialState, finalTime);
  96.         setStepStart(initIntegration(equations, initialState, finalTime));
  97.         final boolean forward = finalTime > initialState.getTime();

  98.         // create some internal working arrays
  99.         final int        stages = c.length + 1;
  100.         double[]         y      = getStepStart().getCompleteState();
  101.         final double[][] yDotK  = new double[stages][];
  102.         final double[]   yTmp   = new double[y.length];

  103.         // set up integration control objects
  104.         if (forward) {
  105.             if (getStepStart().getTime() + step >= finalTime) {
  106.                 setStepSize(finalTime - getStepStart().getTime());
  107.             } else {
  108.                 setStepSize(step);
  109.             }
  110.         } else {
  111.             if (getStepStart().getTime() - step <= finalTime) {
  112.                 setStepSize(finalTime - getStepStart().getTime());
  113.             } else {
  114.                 setStepSize(-step);
  115.             }
  116.         }

  117.         // main integration loop
  118.         setIsLastStep(false);
  119.         do {

  120.             // first stage
  121.             y        = getStepStart().getCompleteState();
  122.             yDotK[0] = getStepStart().getCompleteDerivative();

  123.             // next stages
  124.             ExplicitRungeKuttaIntegrator.applyInternalButcherWeights(getEquations(), getStepStart().getTime(), y,
  125.                     getStepSize(), a, c, yDotK);

  126.             incrementEvaluations(stages - 1);

  127.             // estimate the state at the end of the step
  128.             for (int j = 0; j < y.length; ++j) {
  129.                 double sum    = b[0] * yDotK[0][j];
  130.                 for (int l = 1; l < stages; ++l) {
  131.                     sum    += b[l] * yDotK[l][j];
  132.                 }
  133.                 yTmp[j] = y[j] + getStepSize() * sum;
  134.                 if (Double.isNaN(yTmp[j])) {
  135.                     throw new MathIllegalStateException(LocalizedODEFormats.NAN_APPEARING_DURING_INTEGRATION,
  136.                                                         getStepStart().getTime() + getStepSize());
  137.                 }

  138.             }
  139.             final double stepEnd   = getStepStart().getTime() + getStepSize();
  140.             final double[] yDotTmp = computeDerivatives(stepEnd, yTmp);
  141.             final ODEStateAndDerivative stateTmp =
  142.                 equations.getMapper().mapStateAndDerivative(stepEnd, yTmp, yDotTmp);

  143.             // discrete events handling
  144.             System.arraycopy(yTmp, 0, y, 0, y.length);
  145.             setStepStart(acceptStep(createInterpolator(forward, yDotK, getStepStart(), stateTmp,
  146.                                                        equations.getMapper()),
  147.                                     finalTime));

  148.             if (!isLastStep()) {

  149.                 // stepsize control for next step
  150.                 final double  nextT      = getStepStart().getTime() + getStepSize();
  151.                 final boolean nextIsLast = forward ? (nextT >= finalTime) : (nextT <= finalTime);
  152.                 if (nextIsLast) {
  153.                     setStepSize(finalTime - getStepStart().getTime());
  154.                 }
  155.             }

  156.         } while (!isLastStep());

  157.         final ODEStateAndDerivative finalState = getStepStart();
  158.         setStepStart(null);
  159.         setStepSize(Double.NaN);
  160.         return finalState;

  161.     }

  162. }