LutherStepInterpolator.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.legacy.ode.sampling.StepInterpolator;
  19. import org.apache.commons.math4.core.jdkmath.JdkMath;

  20. /**
  21.  * This class represents an interpolator over the last step during an
  22.  * ODE integration for the 6th order Luther integrator.
  23.  *
  24.  * <p>This interpolator computes dense output inside the last
  25.  * step computed. The interpolation equation is consistent with the
  26.  * integration scheme.</p>
  27.  *
  28.  * @see LutherIntegrator
  29.  * @since 3.3
  30.  */

  31. class LutherStepInterpolator extends RungeKuttaStepInterpolator {

  32.     /** Serializable version identifier. */
  33.     private static final long serialVersionUID = 20140416L;

  34.     /** Square root. */
  35.     private static final double Q = JdkMath.sqrt(21);

  36.     /** Simple constructor.
  37.      * This constructor builds an instance that is not usable yet, the
  38.      * {@link
  39.      * org.apache.commons.math4.legacy.ode.sampling.AbstractStepInterpolator#reinitialize}
  40.      * method should be called before using the instance in order to
  41.      * initialize the internal arrays. This constructor is used only
  42.      * in order to delay the initialization in some cases. The {@link
  43.      * RungeKuttaIntegrator} class uses the prototyping design pattern
  44.      * to create the step interpolators by cloning an uninitialized model
  45.      * and later initializing the copy.
  46.      */
  47.     // CHECKSTYLE: stop RedundantModifier
  48.     // the public modifier here is needed for serialization
  49.     public LutherStepInterpolator() {
  50.     }
  51.     // CHECKSTYLE: resume RedundantModifier

  52.     /** Copy constructor.
  53.      * @param interpolator interpolator to copy from. The copy is a deep
  54.      * copy: its arrays are separated from the original arrays of the
  55.      * instance
  56.      */
  57.     LutherStepInterpolator(final LutherStepInterpolator interpolator) {
  58.         super(interpolator);
  59.     }

  60.     /** {@inheritDoc} */
  61.     @Override
  62.     protected StepInterpolator doCopy() {
  63.         return new LutherStepInterpolator(this);
  64.     }


  65.     /** {@inheritDoc} */
  66.     @Override
  67.     protected void computeInterpolatedStateAndDerivatives(final double theta,
  68.                                                           final double oneMinusThetaH) {

  69.         // the coefficients below have been computed by solving the
  70.         // order conditions from a theorem from Butcher (1963), using
  71.         // the method explained in Folkmar Bornemann paper "Runge-Kutta
  72.         // Methods, Trees, and Maple", Center of Mathematical Sciences, Munich
  73.         // University of Technology, February 9, 2001
  74.         //<http://wwwzenger.informatik.tu-muenchen.de/selcuk/sjam012101.html>

  75.         // the method is implemented in the rkcheck tool
  76.         // <https://www.spaceroots.org/software/rkcheck/index.html>.
  77.         // Running it for order 5 gives the following order conditions
  78.         // for an interpolator:
  79.         // order 1 conditions
  80.         // \sum_{i=1}^{i=s}\left(b_{i} \right) =1
  81.         // order 2 conditions
  82.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}\right) = \frac{\theta}{2}
  83.         // order 3 conditions
  84.         // \sum_{i=2}^{i=s}\left(b_{i} \sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j} \right)}\right) = \frac{\theta^{2}}{6}
  85.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}^{2}\right) = \frac{\theta^{2}}{3}
  86.         // order 4 conditions
  87.         // \sum_{i=3}^{i=s}\left(b_{i} \sum_{j=2}^{j=i-1}{\left(a_{i,j} \sum_{k=1}^{k=j-1}{\left(a_{j,k} c_{k} \right)} \right)}\right) = \frac{\theta^{3}}{24}
  88.         // \sum_{i=2}^{i=s}\left(b_{i} \sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j}^{2} \right)}\right) = \frac{\theta^{3}}{12}
  89.         // \sum_{i=2}^{i=s}\left(b_{i} c_{i}\sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j} \right)}\right) = \frac{\theta^{3}}{8}
  90.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}^{3}\right) = \frac{\theta^{3}}{4}
  91.         // order 5 conditions
  92.         // \sum_{i=4}^{i=s}\left(b_{i} \sum_{j=3}^{j=i-1}{\left(a_{i,j} \sum_{k=2}^{k=j-1}{\left(a_{j,k} \sum_{l=1}^{l=k-1}{\left(a_{k,l} c_{l} \right)} \right)} \right)}\right) = \frac{\theta^{4}}{120}
  93.         // \sum_{i=3}^{i=s}\left(b_{i} \sum_{j=2}^{j=i-1}{\left(a_{i,j} \sum_{k=1}^{k=j-1}{\left(a_{j,k} c_{k}^{2} \right)} \right)}\right) = \frac{\theta^{4}}{60}
  94.         // \sum_{i=3}^{i=s}\left(b_{i} \sum_{j=2}^{j=i-1}{\left(a_{i,j} c_{j}\sum_{k=1}^{k=j-1}{\left(a_{j,k} c_{k} \right)} \right)}\right) = \frac{\theta^{4}}{40}
  95.         // \sum_{i=2}^{i=s}\left(b_{i} \sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j}^{3} \right)}\right) = \frac{\theta^{4}}{20}
  96.         // \sum_{i=3}^{i=s}\left(b_{i} c_{i}\sum_{j=2}^{j=i-1}{\left(a_{i,j} \sum_{k=1}^{k=j-1}{\left(a_{j,k} c_{k} \right)} \right)}\right) = \frac{\theta^{4}}{30}
  97.         // \sum_{i=2}^{i=s}\left(b_{i} c_{i}\sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j}^{2} \right)}\right) = \frac{\theta^{4}}{15}
  98.         // \sum_{i=2}^{i=s}\left(b_{i} \left(\sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j} \right)} \right)^{2}\right) = \frac{\theta^{4}}{20}
  99.         // \sum_{i=2}^{i=s}\left(b_{i} c_{i}^{2}\sum_{j=1}^{j=i-1}{\left(a_{i,j} c_{j} \right)}\right) = \frac{\theta^{4}}{10}
  100.         // \sum_{i=1}^{i=s}\left(b_{i} c_{i}^{4}\right) = \frac{\theta^{4}}{5}

  101.         // The a_{j,k} and c_{k} are given by the integrator Butcher arrays. What remains to solve
  102.         // are the b_i for the interpolator. They are found by solving the above equations.
  103.         // For a given interpolator, some equations are redundant, so in our case when we select
  104.         // all equations from order 1 to 4, we still don't have enough independent equations
  105.         // to solve from b_1 to b_7. We need to also select one equation from order 5. Here,
  106.         // we selected the last equation. It appears this choice implied at least the last 3 equations
  107.         // are fulfilled, but some of the former ones are not, so the resulting interpolator is order 5.
  108.         // At the end, we get the b_i as polynomials in theta.

  109.         final double coeffDot1 =  1 + theta * ( -54            /   5.0 + theta * (   36                   + theta * ( -47                   + theta *   21)));
  110.         final double coeffDot2 =  0;
  111.         final double coeffDot3 =      theta * (-208            /  15.0 + theta * (  320            / 3.0  + theta * (-608            /  3.0 + theta *  112)));
  112.         final double coeffDot4 =      theta * ( 324            /  25.0 + theta * ( -486            / 5.0  + theta * ( 972            /  5.0 + theta * -567           /  5.0)));
  113.         final double coeffDot5 =      theta * ((833 + 343 * Q) / 150.0 + theta * ((-637 - 357 * Q) / 30.0 + theta * ((392 + 287 * Q) / 15.0 + theta * (-49 - 49 * Q) /  5.0)));
  114.         final double coeffDot6 =      theta * ((833 - 343 * Q) / 150.0 + theta * ((-637 + 357 * Q) / 30.0 + theta * ((392 - 287 * Q) / 15.0 + theta * (-49 + 49 * Q) /  5.0)));
  115.         final double coeffDot7 =      theta * (   3            /   5.0 + theta * (   -3                   + theta *     3));

  116.         if (previousState != null && theta <= 0.5) {

  117.             final double coeff1    =  1 + theta * ( -27            /   5.0 + theta * (   12                   + theta * ( -47            /  4.0 + theta *   21           /  5.0)));
  118.             final double coeff2    =  0;
  119.             final double coeff3    =      theta * (-104            /  15.0 + theta * (  320            / 9.0  + theta * (-152            /  3.0 + theta *  112           /  5.0)));
  120.             final double coeff4    =      theta * ( 162            /  25.0 + theta * ( -162            / 5.0  + theta * ( 243            /  5.0 + theta * -567           / 25.0)));
  121.             final double coeff5    =      theta * ((833 + 343 * Q) / 300.0 + theta * ((-637 - 357 * Q) / 90.0 + theta * ((392 + 287 * Q) / 60.0 + theta * (-49 - 49 * Q) / 25.0)));
  122.             final double coeff6    =      theta * ((833 - 343 * Q) / 300.0 + theta * ((-637 + 357 * Q) / 90.0 + theta * ((392 - 287 * Q) / 60.0 + theta * (-49 + 49 * Q) / 25.0)));
  123.             final double coeff7    =      theta * (   3            /  10.0 + theta * (   -1                   + theta * (   3            /  4.0)));
  124.             for (int i = 0; i < interpolatedState.length; ++i) {
  125.                 final double yDot1 = yDotK[0][i];
  126.                 final double yDot2 = yDotK[1][i];
  127.                 final double yDot3 = yDotK[2][i];
  128.                 final double yDot4 = yDotK[3][i];
  129.                 final double yDot5 = yDotK[4][i];
  130.                 final double yDot6 = yDotK[5][i];
  131.                 final double yDot7 = yDotK[6][i];
  132.                 interpolatedState[i] = previousState[i] +
  133.                         theta * h * (coeff1 * yDot1 + coeff2 * yDot2 + coeff3 * yDot3 +
  134.                                      coeff4 * yDot4 + coeff5 * yDot5 + coeff6 * yDot6 + coeff7 * yDot7);
  135.                 interpolatedDerivatives[i] = coeffDot1 * yDot1 + coeffDot2 * yDot2 + coeffDot3 * yDot3 +
  136.                         coeffDot4 * yDot4 + coeffDot5 * yDot5 + coeffDot6 * yDot6 + coeffDot7 * yDot7;
  137.             }
  138.         } else {

  139.             final double coeff1    =  -1 /  20.0 + theta * (  19            /  20.0 + theta * (  -89             /  20.0  + theta * (   151            /  20.0 + theta *  -21           /   5.0)));
  140.             final double coeff2    =  0;
  141.             final double coeff3    = -16 /  45.0 + theta * ( -16            /  45.0 + theta * ( -328             /  45.0  + theta * (   424            /  15.0 + theta * -112           /   5.0)));
  142.             final double coeff4    =               theta * (                          theta * (  162             /  25.0  + theta * (  -648            /  25.0 + theta *  567           /  25.0)));
  143.             final double coeff5    = -49 / 180.0 + theta * ( -49            / 180.0 + theta * ((2254 + 1029 * Q) / 900.0  + theta * ((-1372 - 847 * Q) / 300.0 + theta * ( 49 + 49 * Q) /  25.0)));
  144.             final double coeff6    = -49 / 180.0 + theta * ( -49            / 180.0 + theta * ((2254 - 1029 * Q) / 900.0  + theta * ((-1372 + 847 * Q) / 300.0 + theta * ( 49 - 49 * Q) /  25.0)));
  145.             final double coeff7    =  -1 /  20.0 + theta * (  -1            /  20.0 + theta * (    1             /   4.0  + theta * (    -3            /   4.0)));
  146.             for (int i = 0; i < interpolatedState.length; ++i) {
  147.                 final double yDot1 = yDotK[0][i];
  148.                 final double yDot2 = yDotK[1][i];
  149.                 final double yDot3 = yDotK[2][i];
  150.                 final double yDot4 = yDotK[3][i];
  151.                 final double yDot5 = yDotK[4][i];
  152.                 final double yDot6 = yDotK[5][i];
  153.                 final double yDot7 = yDotK[6][i];
  154.                 interpolatedState[i] = currentState[i] +
  155.                         oneMinusThetaH * (coeff1 * yDot1 + coeff2 * yDot2 + coeff3 * yDot3 +
  156.                                           coeff4 * yDot4 + coeff5 * yDot5 + coeff6 * yDot6 + coeff7 * yDot7);
  157.                 interpolatedDerivatives[i] = coeffDot1 * yDot1 + coeffDot2 * yDot2 + coeffDot3 * yDot3 +
  158.                         coeffDot4 * yDot4 + coeffDot5 * yDot5 + coeffDot6 * yDot6 + coeffDot7 * yDot7;
  159.             }
  160.         }
  161.     }
  162. }