FixedStepRungeKuttaFieldIntegrator.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.  *      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. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.ode.nonstiff;


  22. import org.hipparchus.CalculusFieldElement;
  23. import org.hipparchus.Field;
  24. import org.hipparchus.exception.MathIllegalArgumentException;
  25. import org.hipparchus.exception.MathIllegalStateException;
  26. import org.hipparchus.ode.AbstractFieldIntegrator;
  27. import org.hipparchus.ode.FieldEquationsMapper;
  28. import org.hipparchus.ode.FieldExpandableODE;
  29. import org.hipparchus.ode.FieldODEState;
  30. import org.hipparchus.ode.FieldODEStateAndDerivative;
  31. import org.hipparchus.ode.nonstiff.interpolators.RungeKuttaFieldStateInterpolator;
  32. import org.hipparchus.util.MathArrays;

  33. /**
  34.  * This class implements the common part of all fixed step Runge-Kutta
  35.  * integrators for Ordinary Differential Equations.
  36.  *
  37.  * <p>These methods are explicit Runge-Kutta methods, their Butcher
  38.  * arrays are as follows :</p>
  39.  * <pre>
  40.  *    0  |
  41.  *   c2  | a21
  42.  *   c3  | a31  a32
  43.  *   ... |        ...
  44.  *   cs  | as1  as2  ...  ass-1
  45.  *       |--------------------------
  46.  *       |  b1   b2  ...   bs-1  bs
  47.  * </pre>
  48.  *
  49.  * @see EulerFieldIntegrator
  50.  * @see ClassicalRungeKuttaFieldIntegrator
  51.  * @see GillFieldIntegrator
  52.  * @see MidpointFieldIntegrator
  53.  * @param <T> the type of the field elements
  54.  */

  55. public abstract class FixedStepRungeKuttaFieldIntegrator<T extends CalculusFieldElement<T>>
  56.     extends AbstractFieldIntegrator<T> implements FieldExplicitRungeKuttaIntegrator<T> {

  57.     /** Time steps from Butcher array (without the first zero). */
  58.     private final T[] c;

  59.     /** Internal weights from Butcher array (without the first empty row). */
  60.     private final T[][] a;

  61.     /** External weights for the high order method from Butcher array. */
  62.     private final T[] b;

  63.     /** Time steps from Butcher array (without the first zero). */
  64.     private double[] realC = new double[0];

  65.     /** Internal weights from Butcher array (without the first empty row). Real version, optional. */
  66.     private double[][] realA = new double[0][];

  67.     /** External weights for the high order method from Butcher array. Real version, optional. */
  68.     private double[] realB = new double[0];

  69.     /** Integration step. */
  70.     private final T step;

  71.     /** Flag setting whether coefficients in Butcher array are interpreted as Field or real numbers. */
  72.     private boolean usingFieldCoefficients;

  73.     /** Simple constructor.
  74.      * Build a Runge-Kutta integrator with the given
  75.      * step. The default step handler does nothing.
  76.      * @param field field to which the time and state vector elements belong
  77.      * @param name name of the method
  78.      * @param step integration step
  79.      */
  80.     protected FixedStepRungeKuttaFieldIntegrator(final Field<T> field, final String name, final T step) {
  81.         super(field, name);
  82.         this.c    = getC();
  83.         this.a    = getA();
  84.         this.b    = getB();
  85.         this.step = step.abs();
  86.         this.usingFieldCoefficients = false;
  87.     }

  88.     /** Getter for the default, positive step-size assigned at constructor level.
  89.      * @return step
  90.      */
  91.     public T getDefaultStep() {
  92.         return this.step;
  93.     }

  94.     /**
  95.      * Setter for the flag between real or Field coefficients in the Butcher array.
  96.      *
  97.      * @param usingFieldCoefficients new value for flag
  98.      */
  99.     public void setUsingFieldCoefficients(boolean usingFieldCoefficients) {
  100.         this.usingFieldCoefficients = usingFieldCoefficients;
  101.     }

  102.     /** {@inheritDoc} */
  103.     @Override
  104.     public boolean isUsingFieldCoefficients() {
  105.         return usingFieldCoefficients;
  106.     }

  107.     /** {@inheritDoc} */
  108.     @Override
  109.     public int getNumberOfStages() {
  110.         return b.length;
  111.     }

  112.     /** Create an interpolator.
  113.      * @param forward integration direction indicator
  114.      * @param yDotK slopes at the intermediate points
  115.      * @param globalPreviousState start of the global step
  116.      * @param globalCurrentState end of the global step
  117.      * @param mapper equations mapper for the all equations
  118.      * @return external weights for the high order method from Butcher array
  119.      */
  120.     protected abstract RungeKuttaFieldStateInterpolator<T> createInterpolator(boolean forward, T[][] yDotK,
  121.                                                                               FieldODEStateAndDerivative<T> globalPreviousState,
  122.                                                                               FieldODEStateAndDerivative<T> globalCurrentState,
  123.                                                                               FieldEquationsMapper<T> mapper);

  124.     /** {@inheritDoc} */
  125.     @Override
  126.     protected FieldODEStateAndDerivative<T> initIntegration(FieldExpandableODE<T> eqn, FieldODEState<T> s0, T t) {
  127.         if (!isUsingFieldCoefficients()) {
  128.             realA = getRealA();
  129.             realB = getRealB();
  130.             realC = getRealC();
  131.         }
  132.         return super.initIntegration(eqn, s0, t);
  133.     }

  134.     /** {@inheritDoc} */
  135.     @Override
  136.     public FieldODEStateAndDerivative<T> integrate(final FieldExpandableODE<T> equations,
  137.                                                    final FieldODEState<T> initialState, final T finalTime)
  138.         throws MathIllegalArgumentException, MathIllegalStateException {

  139.         sanityChecks(initialState, finalTime);
  140.         setStepStart(initIntegration(equations, initialState, finalTime));
  141.         final boolean forward = finalTime.subtract(initialState.getTime()).getReal() > 0;

  142.         // create some internal working arrays
  143.         final int   stages = getNumberOfStages();
  144.         final T[][] yDotK  = MathArrays.buildArray(getField(), stages, -1);
  145.         MathArrays.buildArray(getField(), equations.getMapper().getTotalDimension());

  146.         // set up integration control objects
  147.         if (forward) {
  148.             if (getStepStart().getTime().add(step).subtract(finalTime).getReal() >= 0) {
  149.                 setStepSize(finalTime.subtract(getStepStart().getTime()));
  150.             } else {
  151.                 setStepSize(step);
  152.             }
  153.         } else {
  154.             if (getStepStart().getTime().subtract(step).subtract(finalTime).getReal() <= 0) {
  155.                 setStepSize(finalTime.subtract(getStepStart().getTime()));
  156.             } else {
  157.                 setStepSize(step.negate());
  158.             }
  159.         }

  160.         // main integration loop
  161.         setIsLastStep(false);
  162.         do {

  163.             // first stage
  164.             final T[] y = getStepStart().getCompleteState();
  165.             yDotK[0]    = getStepStart().getCompleteDerivative();

  166.             // next stages
  167.             final T[] yTmp;
  168.             if (isUsingFieldCoefficients()) {
  169.                 FieldExplicitRungeKuttaIntegrator.applyInternalButcherWeights(getEquations(), getStepStart().getTime(),
  170.                         y, getStepSize(), a, c, yDotK);
  171.                 yTmp = FieldExplicitRungeKuttaIntegrator.applyExternalButcherWeights(y, yDotK, getStepSize(), b);
  172.             } else {
  173.                 FieldExplicitRungeKuttaIntegrator.applyInternalButcherWeights(getEquations(), getStepStart().getTime(),
  174.                         y, getStepSize(), realA, realC, yDotK);
  175.                 yTmp = FieldExplicitRungeKuttaIntegrator.applyExternalButcherWeights(y, yDotK, getStepSize(), realB);
  176.             }

  177.             incrementEvaluations(stages - 1);

  178.             final T stepEnd   = getStepStart().getTime().add(getStepSize());
  179.             final T[] yDotTmp = computeDerivatives(stepEnd, yTmp);
  180.             final FieldODEStateAndDerivative<T> stateTmp = equations.getMapper().mapStateAndDerivative(stepEnd, yTmp, yDotTmp);

  181.             // discrete events handling
  182.             setStepStart(acceptStep(createInterpolator(forward, yDotK, getStepStart(), stateTmp, equations.getMapper()),
  183.                                     finalTime));

  184.             if (!isLastStep()) {

  185.                 // stepsize control for next step
  186.                 final T  nextT      = getStepStart().getTime().add(getStepSize());
  187.                 final boolean nextIsLast = forward ?
  188.                                            (nextT.subtract(finalTime).getReal() >= 0) :
  189.                                            (nextT.subtract(finalTime).getReal() <= 0);
  190.                 if (nextIsLast) {
  191.                     setStepSize(finalTime.subtract(getStepStart().getTime()));
  192.                 }
  193.             }

  194.         } while (!isLastStep());

  195.         final FieldODEStateAndDerivative<T> finalState = getStepStart();
  196.         setStepStart(null);
  197.         setStepSize(null);
  198.         return finalState;

  199.     }

  200. }