FieldExplicitRungeKuttaIntegrator.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.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.ode.FieldExpandableODE;
  21. import org.hipparchus.ode.FieldODEIntegrator;
  22. import org.hipparchus.ode.FieldOrdinaryDifferentialEquation;
  23. import org.hipparchus.util.MathArrays;

  24. /**
  25.  * This interface implements the part of Runge-Kutta
  26.  * Field integrators for Ordinary Differential Equations
  27.  * common to fixed- and adaptive steps.
  28.  *
  29.  * <p>These methods are explicit Runge-Kutta methods, their Butcher
  30.  * arrays are as follows :</p>
  31.  * <pre>
  32.  *    0  |
  33.  *   c2  | a21
  34.  *   c3  | a31  a32
  35.  *   ... |        ...
  36.  *   cs  | as1  as2  ...  ass-1
  37.  *       |--------------------------
  38.  *       |  b1   b2  ...   bs-1  bs
  39.  * </pre>
  40.  *
  41.  * @see FieldButcherArrayProvider
  42.  * @see FixedStepRungeKuttaFieldIntegrator
  43.  * @see EmbeddedRungeKuttaFieldIntegrator
  44.  * @param <T> the type of the field elements
  45.  * @since 3.1
  46.  */

  47. public interface FieldExplicitRungeKuttaIntegrator<T extends CalculusFieldElement<T>>
  48.     extends FieldButcherArrayProvider<T>, FieldODEIntegrator<T> {

  49.     /** Get the time steps from Butcher array (without the first zero). Real version (non-Field).
  50.      * @return time steps from Butcher array (without the first zero).
  51.      */
  52.     default double[] getRealC() {
  53.         final T[] c = getC();
  54.         final double[] cReal = new double[c.length];
  55.         for (int i = 0; i < c.length; i++) {
  56.             cReal[i] = c[i].getReal();
  57.         }
  58.         return cReal;
  59.     }

  60.     /** Get the internal weights from Butcher array (without the first empty row). Real version (non-Field).
  61.      * @return internal weights from Butcher array (without the first empty row)
  62.      */
  63.     default double[][] getRealA() {
  64.         final T[][] a = getA();
  65.         final double[][] aReal = new double[a.length][];
  66.         for (int i = 0; i < a.length; i++) {
  67.             aReal[i] = new double[a[i].length];
  68.             for (int j = 0; j < aReal[i].length; j++) {
  69.                 aReal[i][j] = a[i][j].getReal();
  70.             }
  71.         }
  72.         return aReal;
  73.     }

  74.     /** Get the external weights for the high order method from Butcher array. Real version (non-Field).
  75.      * @return external weights for the high order method from Butcher array
  76.      */
  77.     default double[] getRealB() {
  78.         final T[] b = getB();
  79.         final double[] bReal = new double[b.length];
  80.         for (int i = 0; i < b.length; i++) {
  81.             bReal[i] = b[i].getReal();
  82.         }
  83.         return bReal;
  84.     }

  85.     /**
  86.      * Getter for the flag between real or Field coefficients in the Butcher array.
  87.      *
  88.      * @return flag
  89.      */
  90.     boolean isUsingFieldCoefficients();

  91.     /**
  92.      * Getter for the number of stages corresponding to the Butcher array.
  93.      *
  94.      * @return number of stages
  95.      */
  96.     default int getNumberOfStages() {
  97.         return getB().length;
  98.     }

  99.     /** Fast computation of a single step of ODE integration.
  100.      * <p>This method is intended for the limited use case of
  101.      * very fast computation of only one step without using any of the
  102.      * rich features of general integrators that may take some time
  103.      * to set up (i.e. no step handlers, no events handlers, no additional
  104.      * states, no interpolators, no error control, no evaluations count,
  105.      * no sanity checks ...). It handles the strict minimum of computation,
  106.      * so it can be embedded in outer loops.</p>
  107.      * <p>
  108.      * This method is <em>not</em> used at all by the {@link #integrate(FieldExpandableODE,
  109.      * org.hipparchus.ode.FieldODEState, CalculusFieldElement)} method. It also completely ignores the step set at
  110.      * construction time, and uses only a single step to go from {@code t0} to {@code t}.
  111.      * </p>
  112.      * <p>
  113.      * As this method does not use any of the state-dependent features of the integrator,
  114.      * it should be reasonably thread-safe <em>if and only if</em> the provided differential
  115.      * equations are themselves thread-safe.
  116.      * </p>
  117.      * @param equations differential equations to integrate
  118.      * @param t0 initial time
  119.      * @param y0 initial value of the state vector at t0
  120.      * @param t target time for the integration
  121.      * (can be set to a value smaller than {@code t0} for backward integration)
  122.      * @return state vector at {@code t}
  123.      */
  124.     default T[] singleStep(final FieldOrdinaryDifferentialEquation<T> equations, final T t0, final T[] y0, final T t) {

  125.         // create some internal working arrays
  126.         final int stages  = getNumberOfStages();
  127.         final T[][] yDotK = MathArrays.buildArray(t0.getField(), stages, -1);

  128.         // first stage
  129.         final T h = t.subtract(t0);
  130.         final FieldExpandableODE<T> fieldExpandableODE = new FieldExpandableODE<>(equations);
  131.         yDotK[0] = fieldExpandableODE.computeDerivatives(t0, y0);

  132.         if (isUsingFieldCoefficients()) {
  133.             applyInternalButcherWeights(fieldExpandableODE, t0, y0, h, getA(), getC(), yDotK);
  134.             return applyExternalButcherWeights(y0, yDotK, h, getB());
  135.         } else {
  136.             applyInternalButcherWeights(fieldExpandableODE, t0, y0, h, getRealA(), getRealC(), yDotK);
  137.             return applyExternalButcherWeights(y0, yDotK, h, getRealB());
  138.         }
  139.     }

  140.     /**
  141.      * Create a fraction from integers.
  142.      *
  143.      * @param <T> the type of the field elements
  144.      * @param field field to which elements belong
  145.      * @param p numerator
  146.      * @param q denominator
  147.      * @return p/q computed in the instance field
  148.      */
  149.     static <T extends CalculusFieldElement<T>> T fraction(final Field<T> field, final int p, final int q) {
  150.         final T zero = field.getZero();
  151.         return zero.newInstance(p).divide(zero.newInstance(q));
  152.     }

  153.     /**
  154.      * Create a fraction from doubles.
  155.      * @param <T> the type of the field elements
  156.      * @param field field to which elements belong
  157.      * @param p numerator
  158.      * @param q denominator
  159.      * @return p/q computed in the instance field
  160.      */
  161.     static <T extends CalculusFieldElement<T>> T fraction(final Field<T> field, final double p, final double q) {
  162.         final T zero = field.getZero();
  163.         return zero.newInstance(p).divide(zero.newInstance(q));
  164.     }

  165.     /**
  166.      * Apply internal weights of Butcher array, with corresponding times.
  167.      * @param <T> the type of the field elements
  168.      * @param equations differential equations to integrate
  169.      * @param t0        initial time
  170.      * @param y0        initial value of the state vector at t0
  171.      * @param h         step size
  172.      * @param a         internal weights of Butcher array
  173.      * @param c         times of Butcher array
  174.      * @param yDotK     array where to store result
  175.      */
  176.     static <T extends CalculusFieldElement<T>> void applyInternalButcherWeights(final FieldExpandableODE<T> equations,
  177.                                                                                 final T t0, final T[] y0, final T h,
  178.                                                                                 final T[][] a, final T[] c,
  179.                                                                                 final T[][] yDotK) {
  180.         // create some internal working arrays
  181.         final int stages = c.length + 1;
  182.         final T[] yTmp = y0.clone();

  183.         for (int k = 1; k < stages; ++k) {

  184.             for (int j = 0; j < y0.length; ++j) {
  185.                 T sum = yDotK[0][j].multiply(a[k - 1][0]);
  186.                 for (int l = 1; l < k; ++l) {
  187.                     sum = sum.add(yDotK[l][j].multiply(a[k - 1][l]));
  188.                 }
  189.                 yTmp[j] = y0[j].add(h.multiply(sum));
  190.             }

  191.             yDotK[k] = equations.computeDerivatives(t0.add(h.multiply(c[k - 1])), yTmp);
  192.         }
  193.     }

  194.     /** Apply internal weights of Butcher array, with corresponding times. Version with real Butcher array (non-Field).
  195.      * @param <T> the type of the field elements
  196.      * @param equations differential equations to integrate
  197.      * @param t0 initial time
  198.      * @param y0 initial value of the state vector at t0
  199.      * @param h step size
  200.      * @param a internal weights of Butcher array
  201.      * @param c times of Butcher array
  202.      * @param yDotK array where to store result
  203.      */
  204.     static <T extends CalculusFieldElement<T>> void applyInternalButcherWeights(final FieldExpandableODE<T> equations,
  205.                                                                                 final T t0, final T[] y0, final T h,
  206.                                                                                 final double[][] a, final double[] c,
  207.                                                                                 final T[][] yDotK) {
  208.         // create some internal working arrays
  209.         final int stages = c.length + 1;
  210.         final T[] yTmp = y0.clone();

  211.         for (int k = 1; k < stages; ++k) {

  212.             for (int j = 0; j < y0.length; ++j) {
  213.                 T sum = yDotK[0][j].multiply(a[k - 1][0]);
  214.                 for (int l = 1; l < k; ++l) {
  215.                     sum = sum.add(yDotK[l][j].multiply(a[k - 1][l]));
  216.                 }
  217.                 yTmp[j] = y0[j].add(h.multiply(sum));
  218.             }

  219.             yDotK[k] = equations.computeDerivatives(t0.add(h.multiply(c[k - 1])), yTmp);
  220.         }
  221.     }

  222.     /** Apply external weights of Butcher array, assuming internal ones have been applied.
  223.      * @param <T> the type of the field elements
  224.      * @param yDotK output of stages
  225.      * @param y0 initial value of the state vector at t0
  226.      * @param h step size
  227.      * @param b external weights of Butcher array
  228.      * @return state vector
  229.      */
  230.     static <T extends CalculusFieldElement<T>> T[] applyExternalButcherWeights(final T[] y0, final T[][] yDotK,
  231.                                                                                final T h, final T[] b) {
  232.         final T[] y = y0.clone();
  233.         final int stages = b.length;
  234.         for (int j = 0; j < y0.length; ++j) {
  235.             T sum = yDotK[0][j].multiply(b[0]);
  236.             for (int l = 1; l < stages; ++l) {
  237.                 sum = sum.add(yDotK[l][j].multiply(b[l]));
  238.             }
  239.             y[j] = y[j].add(h.multiply(sum));
  240.         }
  241.         return y;
  242.     }

  243.     /** Apply external weights of Butcher array, assuming internal ones have been applied. Version with real Butcher
  244.      * array (non-Field version).
  245.      * @param <T> the type of the field elements
  246.      * @param yDotK output of stages
  247.      * @param y0 initial value of the state vector at t0
  248.      * @param h step size
  249.      * @param b external weights of Butcher array
  250.      * @return state vector
  251.      */
  252.     static <T extends CalculusFieldElement<T>> T[] applyExternalButcherWeights(final T[] y0, final T[][] yDotK,
  253.                                                                                final T h, final double[] b) {
  254.         final T[] y = y0.clone();
  255.         final int stages = b.length;
  256.         for (int j = 0; j < y0.length; ++j) {
  257.             T sum = yDotK[0][j].multiply(b[0]);
  258.             for (int l = 1; l < stages; ++l) {
  259.                 sum = sum.add(yDotK[l][j].multiply(b[l]));
  260.             }
  261.             y[j] = y[j].add(h.multiply(sum));
  262.         }
  263.         return y;
  264.     }

  265. }