DormandPrince853Integrator.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.ode.EquationsMapper;
  19. import org.hipparchus.ode.ODEStateAndDerivative;
  20. import org.hipparchus.ode.nonstiff.interpolators.DormandPrince853StateInterpolator;
  21. import org.hipparchus.util.FastMath;


  22. /**
  23.  * This class implements the 8(5,3) Dormand-Prince integrator for Ordinary
  24.  * Differential Equations.
  25.  *
  26.  * <p>This integrator is an embedded Runge-Kutta integrator
  27.  * of order 8(5,3) used in local extrapolation mode (i.e. the solution
  28.  * is computed using the high order formula) with stepsize control
  29.  * (and automatic step initialization) and continuous output. This
  30.  * method uses 12 functions evaluations per step for integration and 4
  31.  * evaluations for interpolation. However, since the first
  32.  * interpolation evaluation is the same as the first integration
  33.  * evaluation of the next step, we have included it in the integrator
  34.  * rather than in the interpolator and specified the method was an
  35.  * <i>fsal</i>. Hence, despite we have 13 stages here, the cost is
  36.  * really 12 evaluations per step even if no interpolation is done,
  37.  * and the overcost of interpolation is only 3 evaluations.</p>
  38.  *
  39.  * <p>This method is based on an 8(6) method by Dormand and Prince
  40.  * (i.e. order 8 for the integration and order 6 for error estimation)
  41.  * modified by Hairer and Wanner to use a 5th order error estimator
  42.  * with 3rd order correction. This modification was introduced because
  43.  * the original method failed in some cases (wrong steps can be
  44.  * accepted when step size is too large, for example in the
  45.  * Brusselator problem) and also had <i>severe difficulties when
  46.  * applied to problems with discontinuities</i>. This modification is
  47.  * explained in the second edition of the first volume (Nonstiff
  48.  * Problems) of the reference book by Hairer, Norsett and Wanner:
  49.  * <i>Solving Ordinary Differential Equations</i> (Springer-Verlag,
  50.  * ISBN 3-540-56670-8).</p>
  51.  *
  52.  */

  53. public class DormandPrince853Integrator extends EmbeddedRungeKuttaIntegrator {

  54.     /** Name of integration scheme. */
  55.     public static final String METHOD_NAME = "Dormand-Prince 8 (5, 3)";

  56.     /** First error weights array, element 1. */
  57.     static final double E1_01 =         116092271.0 / 8848465920.0;

  58.     // elements 2 to 5 are zero, so they are neither stored nor used

  59.     /** First error weights array, element 6. */
  60.     static final double E1_06 =          -1871647.0 / 1527680.0;

  61.     /** First error weights array, element 7. */
  62.     static final double E1_07 =         -69799717.0 / 140793660.0;

  63.     /** First error weights array, element 8. */
  64.     static final double E1_08 =     1230164450203.0 / 739113984000.0;

  65.     /** First error weights array, element 9. */
  66.     static final double E1_09 = -1980813971228885.0 / 5654156025964544.0;

  67.     /** First error weights array, element 10. */
  68.     static final double E1_10 =         464500805.0 / 1389975552.0;

  69.     /** First error weights array, element 11. */
  70.     static final double E1_11 =     1606764981773.0 / 19613062656000.0;

  71.     /** First error weights array, element 12. */
  72.     static final double E1_12 =           -137909.0 / 6168960.0;


  73.     /** Second error weights array, element 1. */
  74.     static final double E2_01 =           -364463.0 / 1920240.0;

  75.     // elements 2 to 5 are zero, so they are neither stored nor used

  76.     /** Second error weights array, element 6. */
  77.     static final double E2_06 =           3399327.0 / 763840.0;

  78.     /** Second error weights array, element 7. */
  79.     static final double E2_07 =          66578432.0 / 35198415.0;

  80.     /** Second error weights array, element 8. */
  81.     static final double E2_08 =       -1674902723.0 / 288716400.0;

  82.     /** Second error weights array, element 9. */
  83.     static final double E2_09 =   -74684743568175.0 / 176692375811392.0;

  84.     /** Second error weights array, element 10. */
  85.     static final double E2_10 =           -734375.0 / 4826304.0;

  86.     /** Second error weights array, element 11. */
  87.     static final double E2_11 =         171414593.0 / 851261400.0;

  88.     /** Second error weights array, element 12. */
  89.     static final double E2_12 =             69869.0 / 3084480.0;

  90.     /** Simple constructor.
  91.      * Build a fifth order Dormand-Prince integrator with the given step bounds
  92.      * @param minStep minimal step (sign is irrelevant, regardless of
  93.      * integration direction, forward or backward), the last step can
  94.      * be smaller than this
  95.      * @param maxStep maximal step (sign is irrelevant, regardless of
  96.      * integration direction, forward or backward), the last step can
  97.      * be smaller than this
  98.      * @param scalAbsoluteTolerance allowed absolute error
  99.      * @param scalRelativeTolerance allowed relative error
  100.      */
  101.     public DormandPrince853Integrator(final double minStep, final double maxStep,
  102.                                       final double scalAbsoluteTolerance,
  103.                                       final double scalRelativeTolerance) {
  104.         super(METHOD_NAME, 12,
  105.               minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
  106.     }

  107.     /** Simple constructor.
  108.      * Build a fifth order Dormand-Prince integrator with the given step bounds
  109.      * @param minStep minimal step (sign is irrelevant, regardless of
  110.      * integration direction, forward or backward), the last step can
  111.      * be smaller than this
  112.      * @param maxStep maximal step (sign is irrelevant, regardless of
  113.      * integration direction, forward or backward), the last step can
  114.      * be smaller than this
  115.      * @param vecAbsoluteTolerance allowed absolute error
  116.      * @param vecRelativeTolerance allowed relative error
  117.      */
  118.     public DormandPrince853Integrator(final double minStep, final double maxStep,
  119.                                       final double[] vecAbsoluteTolerance,
  120.                                       final double[] vecRelativeTolerance) {
  121.         super(METHOD_NAME, 12,
  122.               minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
  123.     }

  124.     /** {@inheritDoc} */
  125.     @Override
  126.     public double[] getC() {
  127.         final double sqrt6 = FastMath.sqrt(6.0);
  128.         return new double[] {
  129.             (12.0 - 2.0 * sqrt6) / 135.0,
  130.             (6.0 - sqrt6) / 45.0,
  131.             (6.0 - sqrt6) / 30.0,
  132.             (6.0 + sqrt6) / 30.0,
  133.             1.0/3.0,
  134.             1.0/4.0,
  135.             4.0/13.0,
  136.             127.0/195.0,
  137.             3.0/5.0,
  138.             6.0/7.0,
  139.             1.0,
  140.             1.0,
  141.             1.0/10.0,
  142.             1.0/5.0,
  143.             7.0/9.0
  144.         };
  145.     }

  146.     /** {@inheritDoc} */
  147.     @Override
  148.     public double[][] getA() {
  149.         final double sqrt6 = FastMath.sqrt(6.0);
  150.         return new double[][] {
  151.             {
  152.                 (12.0 - 2.0 * sqrt6) / 135.0
  153.             }, {
  154.                 (6.0 - sqrt6) / 180.0,
  155.                 (6.0 - sqrt6) / 60.0
  156.             }, {
  157.                 (6.0 - sqrt6) / 120.0,
  158.                 0.0,
  159.                 (6.0 - sqrt6) / 40.0
  160.             }, {
  161.                 (462.0 + 107.0 * sqrt6) / 3000.0,
  162.                 0.0,
  163.                 (-402.0 - 197.0 * sqrt6) / 1000.0,
  164.                 (168.0 + 73.0 * sqrt6) / 375.0
  165.             }, {
  166.                 1.0 / 27.0,
  167.                 0.0,
  168.                 0.0,
  169.                 (16.0 + sqrt6) / 108.0,
  170.                 (16.0 - sqrt6) / 108.0
  171.             }, {
  172.                 19.0 / 512.0,
  173.                 0.0,
  174.                 0.0,
  175.                 (118.0 + 23.0 * sqrt6) / 1024.0,
  176.                 (118.0 - 23.0 * sqrt6) / 1024.0,
  177.                 -9.0 / 512.0
  178.             }, {
  179.                 13772.0 / 371293.0,
  180.                 0.0,
  181.                 0.0,
  182.                 (51544.0 + 4784.0 * sqrt6) / 371293.0,
  183.                 (51544.0 - 4784.0 * sqrt6) / 371293.0,
  184.                 -5688.0 / 371293.0,
  185.                 3072.0 / 371293.0
  186.             }, {
  187.                 58656157643.0 / 93983540625.0,
  188.                 0.0,
  189.                 0.0,
  190.                 (-1324889724104.0 - 318801444819.0 * sqrt6) / 626556937500.0,
  191.                 (-1324889724104.0 + 318801444819.0 * sqrt6) / 626556937500.0,
  192.                 96044563816.0 / 3480871875.0,
  193.                 5682451879168.0 / 281950621875.0,
  194.                 -165125654.0 / 3796875.0
  195.             }, {
  196.                 8909899.0 / 18653125.0,
  197.                 0.0,
  198.                 0.0,
  199.                 (-4521408.0 - 1137963.0 * sqrt6) / 2937500.0,
  200.                 (-4521408.0 + 1137963.0 * sqrt6) / 2937500.0,
  201.                 96663078.0 / 4553125.0,
  202.                 2107245056.0 / 137915625.0,
  203.                 -4913652016.0 / 147609375.0,
  204.                 -78894270.0 / 3880452869.0
  205.             }, {
  206.                 -20401265806.0 / 21769653311.0,
  207.                 0.0,
  208.                 0.0,
  209.                 (354216.0 + 94326.0 * sqrt6) / 112847.0,
  210.                 (354216.0 - 94326.0 * sqrt6) / 112847.0,
  211.                 -43306765128.0 / 5313852383.0,
  212.                 -20866708358144.0 / 1126708119789.0,
  213.                 14886003438020.0 / 654632330667.0,
  214.                 35290686222309375.0 / 14152473387134411.0,
  215.                 -1477884375.0 / 485066827.0
  216.             }, {
  217.                 39815761.0 / 17514443.0,
  218.                 0.0,
  219.                 0.0,
  220.                 (-3457480.0 - 960905.0 * sqrt6) / 551636.0,
  221.                 (-3457480.0 + 960905.0 * sqrt6) / 551636.0,
  222.                 -844554132.0 / 47026969.0,
  223.                 8444996352.0 / 302158619.0,
  224.                 -2509602342.0 / 877790785.0,
  225.                 -28388795297996250.0 / 3199510091356783.0,
  226.                 226716250.0 / 18341897.0,
  227.                 1371316744.0 / 2131383595.0
  228.             }, {
  229.                 // the following stage is both for interpolation and the first stage in next step
  230.                 // (the coefficients are identical to the B array)
  231.                 104257.0/1920240.0,
  232.                 0.0,
  233.                 0.0,
  234.                 0.0,
  235.                 0.0,
  236.                 3399327.0/763840.0,
  237.                 66578432.0/35198415.0,
  238.                 -1674902723.0/288716400.0,
  239.                 54980371265625.0/176692375811392.0,
  240.                 -734375.0/4826304.0,
  241.                 171414593.0/851261400.0,
  242.                 137909.0/3084480.0
  243.             }, {
  244.                 // the following stages are for interpolation only
  245.                 13481885573.0 / 240030000000.0,
  246.                 0.0,
  247.                 0.0,
  248.                 0.0,
  249.                 0.0,
  250.                 0.0,
  251.                 139418837528.0 / 549975234375.0,
  252.                 -11108320068443.0 / 45111937500000.0,
  253.                 -1769651421925959.0 / 14249385146080000.0,
  254.                 57799439.0 / 377055000.0,
  255.                 793322643029.0 / 96734250000000.0,
  256.                 1458939311.0 / 192780000000.0,
  257.                 -4149.0 / 500000.0
  258.             }, {
  259.                 1595561272731.0 / 50120273500000.0,
  260.                 0.0,
  261.                 0.0,
  262.                 0.0,
  263.                 0.0,
  264.                 975183916491.0 /  34457688031250.0,
  265.                 38492013932672.0 /  718912673015625.0,
  266.                 -1114881286517557.0 /  20298710767500000.0,
  267.                 0.0,
  268.                 0.0,
  269.                 -2538710946863.0 /  23431227861250000.0,
  270.                 8824659001.0 /  23066716781250.0,
  271.                 -11518334563.0 /  33831184612500.0,
  272.                 1912306948.0 /  13532473845.0
  273.             }, {
  274.                 -13613986967.0 / 31741908048.0,
  275.                 0.0,
  276.                 0.0,
  277.                 0.0,
  278.                 0.0,
  279.                 -4755612631.0 / 1012344804.0,
  280.                 42939257944576.0 / 5588559685701.0,
  281.                 77881972900277.0 / 19140370552944.0,
  282.                 22719829234375.0 / 63689648654052.0,
  283.                 0.0,
  284.                 0.0,
  285.                 0.0,
  286.                 -1199007803.0 / 857031517296.0,
  287.                 157882067000.0 / 53564469831.0,
  288.                 -290468882375.0 / 31741908048.0
  289.             }
  290.         };
  291.     }

  292.     /** {@inheritDoc} */
  293.     @Override
  294.     public double[] getB() {
  295.         return new double[] {
  296.             104257.0/1920240.0,
  297.             0.0,
  298.             0.0,
  299.             0.0,
  300.             0.0,
  301.             3399327.0/763840.0,
  302.             66578432.0/35198415.0,
  303.             -1674902723.0/288716400.0,
  304.             54980371265625.0/176692375811392.0,
  305.             -734375.0/4826304.0,
  306.             171414593.0/851261400.0,
  307.             137909.0/3084480.0,
  308.             0.0,
  309.             0.0,
  310.             0.0,
  311.             0.0
  312.         };
  313.     }

  314.     /** {@inheritDoc} */
  315.     @Override
  316.     protected DormandPrince853StateInterpolator
  317.     createInterpolator(final boolean forward, double[][] yDotK,
  318.                        final ODEStateAndDerivative globalPreviousState,
  319.                        final ODEStateAndDerivative globalCurrentState,
  320.                        final EquationsMapper mapper) {
  321.         return new DormandPrince853StateInterpolator(forward, yDotK,
  322.                                                     globalPreviousState, globalCurrentState,
  323.                                                     globalPreviousState, globalCurrentState,
  324.                                                     mapper);
  325.     }

  326.     /** {@inheritDoc} */
  327.     @Override
  328.     public int getOrder() {
  329.         return 8;
  330.     }

  331.     /** {@inheritDoc} */
  332.     @Override
  333.     protected double estimateError(final double[][] yDotK,
  334.                                    final double[] y0, final double[] y1,
  335.                                    final double h) {

  336.         final StepsizeHelper helper = getStepSizeHelper();
  337.         double error1 = 0;
  338.         double error2 = 0;

  339.         for (int j = 0; j < helper.getMainSetDimension(); ++j) {
  340.             final double errSum1 = E1_01 * yDotK[0][j]  + E1_06 * yDotK[5][j] +
  341.                                    E1_07 * yDotK[6][j]  + E1_08 * yDotK[7][j] +
  342.                                    E1_09 * yDotK[8][j]  + E1_10 * yDotK[9][j] +
  343.                                    E1_11 * yDotK[10][j] + E1_12 * yDotK[11][j];
  344.             final double errSum2 = E2_01 * yDotK[0][j]  + E2_06 * yDotK[5][j] +
  345.                                    E2_07 * yDotK[6][j]  + E2_08 * yDotK[7][j] +
  346.                                    E2_09 * yDotK[8][j]  + E2_10 * yDotK[9][j] +
  347.                                    E2_11 * yDotK[10][j] + E2_12 * yDotK[11][j];

  348.             final double tol = helper.getTolerance(j, FastMath.max(FastMath.abs(y0[j]), FastMath.abs(y1[j])));
  349.             final double ratio1  = errSum1 / tol;
  350.             error1        += ratio1 * ratio1;
  351.             final double ratio2  = errSum2 / tol;
  352.             error2        += ratio2 * ratio2;
  353.         }

  354.         double den = error1 + 0.01 * error2;
  355.         if (den <= 0.0) {
  356.             den = 1.0;
  357.         }

  358.         return FastMath.abs(h) * error1 / FastMath.sqrt(helper.getMainSetDimension() * den);

  359.     }

  360. }