DormandPrince54Integrator.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.  *      http://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.apache.commons.math4.legacy.ode.nonstiff;

  18. import org.apache.commons.math4.core.jdkmath.JdkMath;


  19. /**
  20.  * This class implements the 5(4) Dormand-Prince integrator for Ordinary
  21.  * Differential Equations.

  22.  * <p>This integrator is an embedded Runge-Kutta integrator
  23.  * of order 5(4) used in local extrapolation mode (i.e. the solution
  24.  * is computed using the high order formula) with stepsize control
  25.  * (and automatic step initialization) and continuous output. This
  26.  * method uses 7 functions evaluations per step. However, since this
  27.  * is an <i>fsal</i>, the last evaluation of one step is the same as
  28.  * the first evaluation of the next step and hence can be avoided. So
  29.  * the cost is really 6 functions evaluations per step.</p>
  30.  *
  31.  * <p>This method has been published (whithout the continuous output
  32.  * that was added by Shampine in 1986) in the following article :
  33.  * <pre>
  34.  *  A family of embedded Runge-Kutta formulae
  35.  *  J. R. Dormand and P. J. Prince
  36.  *  Journal of Computational and Applied Mathematics
  37.  *  volume 6, no 1, 1980, pp. 19-26
  38.  * </pre>
  39.  *
  40.  * @since 1.2
  41.  */

  42. public class DormandPrince54Integrator extends EmbeddedRungeKuttaIntegrator {

  43.   /** Integrator method name. */
  44.   private static final String METHOD_NAME = "Dormand-Prince 5(4)";

  45.   /** Time steps Butcher array. */
  46.   private static final double[] STATIC_C = {
  47.     1.0/5.0, 3.0/10.0, 4.0/5.0, 8.0/9.0, 1.0, 1.0
  48.   };

  49.   /** Internal weights Butcher array. */
  50.   private static final double[][] STATIC_A = {
  51.     {1.0/5.0},
  52.     {3.0/40.0, 9.0/40.0},
  53.     {44.0/45.0, -56.0/15.0, 32.0/9.0},
  54.     {19372.0/6561.0, -25360.0/2187.0, 64448.0/6561.0,  -212.0/729.0},
  55.     {9017.0/3168.0, -355.0/33.0, 46732.0/5247.0, 49.0/176.0, -5103.0/18656.0},
  56.     {35.0/384.0, 0.0, 500.0/1113.0, 125.0/192.0, -2187.0/6784.0, 11.0/84.0}
  57.   };

  58.   /** Propagation weights Butcher array. */
  59.   private static final double[] STATIC_B = {
  60.     35.0/384.0, 0.0, 500.0/1113.0, 125.0/192.0, -2187.0/6784.0, 11.0/84.0, 0.0
  61.   };

  62.   /** Error array, element 1. */
  63.   private static final double E1 =     71.0 / 57600.0;

  64.   // element 2 is zero, so it is neither stored nor used

  65.   /** Error array, element 3. */
  66.   private static final double E3 =    -71.0 / 16695.0;

  67.   /** Error array, element 4. */
  68.   private static final double E4 =     71.0 / 1920.0;

  69.   /** Error array, element 5. */
  70.   private static final double E5 = -17253.0 / 339200.0;

  71.   /** Error array, element 6. */
  72.   private static final double E6 =     22.0 / 525.0;

  73.   /** Error array, element 7. */
  74.   private static final double E7 =     -1.0 / 40.0;

  75.   /** Simple constructor.
  76.    * Build a fifth order Dormand-Prince integrator with the given step bounds
  77.    * @param minStep minimal step (sign is irrelevant, regardless of
  78.    * integration direction, forward or backward), the last step can
  79.    * be smaller than this
  80.    * @param maxStep maximal step (sign is irrelevant, regardless of
  81.    * integration direction, forward or backward), the last step can
  82.    * be smaller than this
  83.    * @param scalAbsoluteTolerance allowed absolute error
  84.    * @param scalRelativeTolerance allowed relative error
  85.    */
  86.   public DormandPrince54Integrator(final double minStep, final double maxStep,
  87.                                    final double scalAbsoluteTolerance,
  88.                                    final double scalRelativeTolerance) {
  89.     super(METHOD_NAME, true, STATIC_C, STATIC_A, STATIC_B, new DormandPrince54StepInterpolator(),
  90.           minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
  91.   }

  92.   /** Simple constructor.
  93.    * Build a fifth order Dormand-Prince integrator with the given step bounds
  94.    * @param minStep minimal step (sign is irrelevant, regardless of
  95.    * integration direction, forward or backward), the last step can
  96.    * be smaller than this
  97.    * @param maxStep maximal step (sign is irrelevant, regardless of
  98.    * integration direction, forward or backward), the last step can
  99.    * be smaller than this
  100.    * @param vecAbsoluteTolerance allowed absolute error
  101.    * @param vecRelativeTolerance allowed relative error
  102.    */
  103.   public DormandPrince54Integrator(final double minStep, final double maxStep,
  104.                                    final double[] vecAbsoluteTolerance,
  105.                                    final double[] vecRelativeTolerance) {
  106.     super(METHOD_NAME, true, STATIC_C, STATIC_A, STATIC_B, new DormandPrince54StepInterpolator(),
  107.           minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
  108.   }

  109.   /** {@inheritDoc} */
  110.   @Override
  111.   public int getOrder() {
  112.     return 5;
  113.   }

  114.   /** {@inheritDoc} */
  115.   @Override
  116.   protected double estimateError(final double[][] yDotK,
  117.                                  final double[] y0, final double[] y1,
  118.                                  final double h) {

  119.     double error = 0;

  120.     for (int j = 0; j < mainSetDimension; ++j) {
  121.         final double errSum = E1 * yDotK[0][j] +  E3 * yDotK[2][j] +
  122.                               E4 * yDotK[3][j] +  E5 * yDotK[4][j] +
  123.                               E6 * yDotK[5][j] +  E7 * yDotK[6][j];

  124.         final double yScale = JdkMath.max(JdkMath.abs(y0[j]), JdkMath.abs(y1[j]));
  125.         final double tol = (vecAbsoluteTolerance == null) ?
  126.                            (scalAbsoluteTolerance + scalRelativeTolerance * yScale) :
  127.                                (vecAbsoluteTolerance[j] + vecRelativeTolerance[j] * yScale);
  128.         final double ratio  = h * errSum / tol;
  129.         error += ratio * ratio;
  130.     }

  131.     return JdkMath.sqrt(error / mainSetDimension);
  132.   }
  133. }