AdamsIntegrator.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.linear.Array2DRowRealMatrix;
  21. import org.hipparchus.linear.RealMatrix;
  22. import org.hipparchus.ode.EquationsMapper;
  23. import org.hipparchus.ode.ExpandableODE;
  24. import org.hipparchus.ode.LocalizedODEFormats;
  25. import org.hipparchus.ode.MultistepIntegrator;
  26. import org.hipparchus.ode.ODEState;
  27. import org.hipparchus.ode.ODEStateAndDerivative;
  28. import org.hipparchus.ode.nonstiff.interpolators.AdamsStateInterpolator;


  29. /** Base class for {@link AdamsBashforthIntegrator Adams-Bashforth} and
  30.  * {@link AdamsMoultonIntegrator Adams-Moulton} integrators.
  31.  */
  32. public abstract class AdamsIntegrator extends MultistepIntegrator {

  33.     /** Transformer. */
  34.     private final AdamsNordsieckTransformer transformer;

  35.     /**
  36.      * Build an Adams integrator with the given order and step control parameters.
  37.      * @param name name of the method
  38.      * @param nSteps number of steps of the method excluding the one being computed
  39.      * @param order order of the method
  40.      * @param minStep minimal step (sign is irrelevant, regardless of
  41.      * integration direction, forward or backward), the last step can
  42.      * be smaller than this
  43.      * @param maxStep maximal step (sign is irrelevant, regardless of
  44.      * integration direction, forward or backward), the last step can
  45.      * be smaller than this
  46.      * @param scalAbsoluteTolerance allowed absolute error
  47.      * @param scalRelativeTolerance allowed relative error
  48.      * @exception MathIllegalArgumentException if order is 1 or less
  49.      */
  50.     protected AdamsIntegrator(final String name, final int nSteps, final int order,
  51.                               final double minStep, final double maxStep,
  52.                               final double scalAbsoluteTolerance,
  53.                               final double scalRelativeTolerance)
  54.         throws MathIllegalArgumentException {
  55.         super(name, nSteps, order, minStep, maxStep,
  56.               scalAbsoluteTolerance, scalRelativeTolerance);
  57.         transformer = AdamsNordsieckTransformer.getInstance(nSteps);
  58.     }

  59.     /**
  60.      * Build an Adams integrator with the given order and step control parameters.
  61.      * @param name name of the method
  62.      * @param nSteps number of steps of the method excluding the one being computed
  63.      * @param order order of the method
  64.      * @param minStep minimal step (sign is irrelevant, regardless of
  65.      * integration direction, forward or backward), the last step can
  66.      * be smaller than this
  67.      * @param maxStep maximal step (sign is irrelevant, regardless of
  68.      * integration direction, forward or backward), the last step can
  69.      * be smaller than this
  70.      * @param vecAbsoluteTolerance allowed absolute error
  71.      * @param vecRelativeTolerance allowed relative error
  72.      * @exception IllegalArgumentException if order is 1 or less
  73.      */
  74.     protected AdamsIntegrator(final String name, final int nSteps, final int order,
  75.                               final double minStep, final double maxStep,
  76.                               final double[] vecAbsoluteTolerance, final double[] vecRelativeTolerance)
  77.         throws IllegalArgumentException {
  78.         super(name, nSteps, order, minStep, maxStep,
  79.               vecAbsoluteTolerance, vecRelativeTolerance);
  80.         transformer = AdamsNordsieckTransformer.getInstance(nSteps);
  81.     }

  82.     /** {@inheritDoc} */
  83.     @Override
  84.     public ODEStateAndDerivative integrate(final ExpandableODE equations,
  85.                                            final ODEState initialState,
  86.                                            final double finalTime)
  87.         throws MathIllegalArgumentException, MathIllegalStateException {

  88.         sanityChecks(initialState, finalTime);
  89.         setStepStart(initIntegration(equations, initialState, finalTime));
  90.         final boolean forward = finalTime > initialState.getTime();

  91.         // compute the initial Nordsieck vector using the configured starter integrator
  92.         start(equations, getStepStart(), finalTime);

  93.         // reuse the step that was chosen by the starter integrator
  94.         ODEStateAndDerivative stepEnd   =
  95.                         AdamsStateInterpolator.taylor(equations.getMapper(), getStepStart(),
  96.                                                       getStepStart().getTime() + getStepSize(),
  97.                                                       getStepSize(), scaled, nordsieck);

  98.         // main integration loop
  99.         setIsLastStep(false);
  100.         final double[] y  = getStepStart().getCompleteState();
  101.         do {

  102.             double[] predictedY  = null;
  103.             final double[] predictedScaled = new double[y.length];
  104.             Array2DRowRealMatrix predictedNordsieck = null;
  105.             double error = 10;
  106.             while (error >= 1.0) {

  107.                 // predict a first estimate of the state at step end
  108.                 predictedY = stepEnd.getCompleteState();

  109.                 // evaluate the derivative
  110.                 final double[] yDot = computeDerivatives(stepEnd.getTime(), predictedY);

  111.                 // predict Nordsieck vector at step end
  112.                 for (int j = 0; j < predictedScaled.length; ++j) {
  113.                     predictedScaled[j] = getStepSize() * yDot[j];
  114.                 }
  115.                 predictedNordsieck = updateHighOrderDerivativesPhase1(nordsieck);
  116.                 updateHighOrderDerivativesPhase2(scaled, predictedScaled, predictedNordsieck);

  117.                 // evaluate error
  118.                 error = errorEstimation(y, stepEnd.getTime(), predictedY, predictedScaled, predictedNordsieck);
  119.                 if (Double.isNaN(error)) {
  120.                     throw new MathIllegalStateException(LocalizedODEFormats.NAN_APPEARING_DURING_INTEGRATION,
  121.                                                         stepEnd.getTime());
  122.                 }

  123.                 if (error >= 1.0) {
  124.                     // reject the step and attempt to reduce error by stepsize control
  125.                     final double factor = computeStepGrowShrinkFactor(error);
  126.                     rescale(getStepSizeHelper().filterStep(getStepSize() * factor, forward, false));
  127.                     stepEnd = AdamsStateInterpolator.taylor(equations.getMapper(), getStepStart(),
  128.                                                             getStepStart().getTime() + getStepSize(),
  129.                                                             getStepSize(),
  130.                                                             scaled,
  131.                                                             nordsieck);

  132.                 }
  133.             }

  134.             final AdamsStateInterpolator interpolator =
  135.                             finalizeStep(getStepSize(), predictedY, predictedScaled, predictedNordsieck,
  136.                                          forward, getStepStart(), stepEnd, equations.getMapper());

  137.             // discrete events handling
  138.             setStepStart(acceptStep(interpolator, finalTime));
  139.             scaled    = interpolator.getScaled();
  140.             nordsieck = interpolator.getNordsieck();

  141.             if (!isLastStep()) {

  142.                 if (resetOccurred()) {

  143.                     // some events handler has triggered changes that
  144.                     // invalidate the derivatives, we need to restart from scratch
  145.                     start(equations, getStepStart(), finalTime);

  146.                     final double  nextT      = getStepStart().getTime() + getStepSize();
  147.                     final boolean nextIsLast = forward ?
  148.                                                (nextT >= finalTime) :
  149.                                                (nextT <= finalTime);
  150.                     final double hNew = nextIsLast ? finalTime - getStepStart().getTime() : getStepSize();

  151.                     rescale(hNew);
  152.                     System.arraycopy(getStepStart().getCompleteState(), 0, y, 0, y.length);

  153.                 } else {

  154.                     // stepsize control for next step
  155.                     final double  factor     = computeStepGrowShrinkFactor(error);
  156.                     final double  scaledH    = getStepSize() * factor;
  157.                     final double  nextT      = getStepStart().getTime() + scaledH;
  158.                     final boolean nextIsLast = forward ?
  159.                                                (nextT >= finalTime) :
  160.                                                (nextT <= finalTime);
  161.                     double hNew = getStepSizeHelper().filterStep(scaledH, forward, nextIsLast);

  162.                     final double  filteredNextT      = getStepStart().getTime() + hNew;
  163.                     final boolean filteredNextIsLast = forward ? (filteredNextT >= finalTime) : (filteredNextT <= finalTime);
  164.                     if (filteredNextIsLast) {
  165.                         hNew = finalTime - getStepStart().getTime();
  166.                     }

  167.                     rescale(hNew);
  168.                     System.arraycopy(predictedY, 0, y, 0, y.length);

  169.                 }

  170.                 stepEnd = AdamsStateInterpolator.taylor(equations.getMapper(), getStepStart(), getStepStart().getTime() + getStepSize(),
  171.                                                         getStepSize(), scaled, nordsieck);

  172.             }

  173.         } while (!isLastStep());

  174.         final ODEStateAndDerivative finalState = getStepStart();
  175.         setStepStart(null);
  176.         setStepSize(Double.NaN);
  177.         return finalState;

  178.     }

  179.     /** {@inheritDoc} */
  180.     @Override
  181.     protected Array2DRowRealMatrix initializeHighOrderDerivatives(final double h, final double[] t,
  182.                                                                   final double[][] y,
  183.                                                                   final double[][] yDot) {
  184.         return transformer.initializeHighOrderDerivatives(h, t, y, yDot);
  185.     }

  186.     /** Update the high order scaled derivatives for Adams integrators (phase 1).
  187.      * <p>The complete update of high order derivatives has a form similar to:
  188.      * \[
  189.      * r_{n+1} = (s_1(n) - s_1(n+1)) P^{-1} u + P^{-1} A P r_n
  190.      * \]
  191.      * this method computes the P<sup>-1</sup> A P r<sub>n</sub> part.</p>
  192.      * @param highOrder high order scaled derivatives
  193.      * (h<sup>2</sup>/2 y'', ... h<sup>k</sup>/k! y(k))
  194.      * @return updated high order derivatives
  195.      * @see #updateHighOrderDerivativesPhase2(double[], double[], Array2DRowRealMatrix)
  196.      */
  197.     public Array2DRowRealMatrix updateHighOrderDerivativesPhase1(final Array2DRowRealMatrix highOrder) {
  198.         return transformer.updateHighOrderDerivativesPhase1(highOrder);
  199.     }

  200.     /** Update the high order scaled derivatives Adams integrators (phase 2).
  201.      * <p>The complete update of high order derivatives has a form similar to:
  202.      * \[
  203.      * r_{n+1} = (s_1(n) - s_1(n+1)) P^{-1} u + P^{-1} A P r_n
  204.      * \]
  205.      * this method computes the (s<sub>1</sub>(n) - s<sub>1</sub>(n+1)) P<sup>-1</sup> u part.</p>
  206.      * <p>Phase 1 of the update must already have been performed.</p>
  207.      * @param start first order scaled derivatives at step start
  208.      * @param end first order scaled derivatives at step end
  209.      * @param highOrder high order scaled derivatives, will be modified
  210.      * (h<sup>2</sup>/2 y'', ... h<sup>k</sup>/k! y(k))
  211.      * @see #updateHighOrderDerivativesPhase1(Array2DRowRealMatrix)
  212.      */
  213.     public void updateHighOrderDerivativesPhase2(final double[] start,
  214.                                                  final double[] end,
  215.                                                  final Array2DRowRealMatrix highOrder) {
  216.         transformer.updateHighOrderDerivativesPhase2(start, end, highOrder);
  217.     }

  218.     /** Estimate error.
  219.      * @param previousState state vector at step start
  220.      * @param predictedTime time at step end
  221.      * @param predictedState predicted state vector at step end
  222.      * @param predictedScaled predicted value of the scaled derivatives at step end
  223.      * @param predictedNordsieck predicted value of the Nordsieck vector at step end
  224.      * @return estimated normalized local discretization error
  225.      * @since 2.0
  226.      */
  227.     protected abstract double errorEstimation(double[] previousState, double predictedTime,
  228.                                               double[] predictedState, double[] predictedScaled,
  229.                                               RealMatrix predictedNordsieck);

  230.     /** Finalize the step.
  231.      * @param stepSize step size used in the scaled and Nordsieck arrays
  232.      * @param predictedState predicted state at end of step
  233.      * @param predictedScaled predicted first scaled derivative
  234.      * @param predictedNordsieck predicted Nordsieck vector
  235.      * @param isForward integration direction indicator
  236.      * @param globalPreviousState start of the global step
  237.      * @param globalCurrentState end of the global step
  238.      * @param equationsMapper mapper for ODE equations primary and secondary components
  239.      * @return step interpolator
  240.      * @since 2.0
  241.      */
  242.     protected abstract AdamsStateInterpolator finalizeStep(double stepSize, double[] predictedState,
  243.                                                            double[] predictedScaled, Array2DRowRealMatrix predictedNordsieck,
  244.                                                            boolean isForward,
  245.                                                            ODEStateAndDerivative globalPreviousState,
  246.                                                            ODEStateAndDerivative globalCurrentState,
  247.                                                            EquationsMapper equationsMapper);

  248. }