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 19 import org.hipparchus.ode.ExpandableODE; 20 import org.hipparchus.ode.ODEIntegrator; 21 import org.hipparchus.ode.ODEState; 22 import org.hipparchus.ode.OrdinaryDifferentialEquation; 23 24 25 /** 26 * This interface implements the part of Runge-Kutta 27 * integrators for Ordinary Differential Equations 28 * common to fixed- and adaptive steps. 29 * 30 * <p>These methods are explicit Runge-Kutta methods, their Butcher 31 * arrays are as follows :</p> 32 * <pre> 33 * 0 | 34 * c2 | a21 35 * c3 | a31 a32 36 * ... | ... 37 * cs | as1 as2 ... ass-1 38 * |-------------------------- 39 * | b1 b2 ... bs-1 bs 40 * </pre> 41 * 42 * @see ButcherArrayProvider 43 * @see RungeKuttaIntegrator 44 * @see EmbeddedRungeKuttaIntegrator 45 * @since 3.1 46 */ 47 48 public interface ExplicitRungeKuttaIntegrator extends ButcherArrayProvider, ODEIntegrator { 49 50 /** 51 * Getter for the number of stages corresponding to the Butcher array. 52 * 53 * @return number of stages 54 */ 55 default int getNumberOfStages() { 56 return getB().length; 57 } 58 59 /** Fast computation of a single step of ODE integration. 60 * <p>This method is intended for the limited use case of 61 * very fast computation of only one step without using any of the 62 * rich features of general integrators that may take some time 63 * to set up (i.e. no step handlers, no events handlers, no additional 64 * states, no interpolators, no error control, no evaluations count, 65 * no sanity checks ...). It handles the strict minimum of computation, 66 * so it can be embedded in outer loops.</p> 67 * <p> 68 * This method is <em>not</em> used at all by the {@link #integrate(ExpandableODE, ODEState, double)} 69 * method. It also completely ignores the step set at construction time, and 70 * uses only a single step to go from {@code t0} to {@code t}. 71 * </p> 72 * <p> 73 * As this method does not use any of the state-dependent features of the integrator, 74 * it should be reasonably thread-safe <em>if and only if</em> the provided differential 75 * equations are themselves thread-safe. 76 * </p> 77 * @param equations differential equations to integrate 78 * @param t0 initial time 79 * @param y0 initial value of the state vector at t0 80 * @param t target time for the integration 81 * (can be set to a value smaller than {@code t0} for backward integration) 82 * @return state vector at {@code t} 83 */ 84 default double[] singleStep(final OrdinaryDifferentialEquation equations, final double t0, final double[] y0, 85 final double t) { 86 87 // create some internal working arrays 88 final int stages = getNumberOfStages(); 89 final double[][] yDotK = new double[stages][]; 90 91 // first stage 92 final double h = t - t0; 93 final ExpandableODE expandableODE = new ExpandableODE(equations); 94 yDotK[0] = expandableODE.computeDerivatives(t0, y0); 95 96 // next stages 97 ExplicitRungeKuttaIntegrator.applyInternalButcherWeights(expandableODE, t0, y0, h, getA(), getC(), yDotK); 98 99 // estimate the state at the end of the step 100 return ExplicitRungeKuttaIntegrator.applyExternalButcherWeights(y0, yDotK, h, getB()); 101 102 } 103 104 /** 105 * Apply internal weights of Butcher array, with corresponding times. 106 * @param equations differential equations to integrate 107 * @param t0 initial time 108 * @param y0 initial value of the state vector at t0 109 * @param h step size 110 * @param a internal weights of Butcher array 111 * @param c times of Butcher array 112 * @param yDotK array where to store result 113 */ 114 static void applyInternalButcherWeights(final ExpandableODE equations, final double t0, final double[] y0, 115 final double h, final double[][] a, final double[] c, 116 final double[][] yDotK) { 117 // create some internal working arrays 118 final int stages = c.length + 1; 119 final double[] yTmp = y0.clone(); 120 121 for (int k = 1; k < stages; ++k) { 122 123 for (int j = 0; j < y0.length; ++j) { 124 double sum = yDotK[0][j] * a[k - 1][0]; 125 for (int l = 1; l < k; ++l) { 126 sum += yDotK[l][j] * a[k - 1][l]; 127 } 128 yTmp[j] = y0[j] + h * sum; 129 } 130 131 yDotK[k] = equations.computeDerivatives(t0 + h * c[k - 1], yTmp); 132 } 133 } 134 135 /** Apply external weights of Butcher array, assuming internal ones have been applied. 136 * @param yDotK output of stages 137 * @param y0 initial value of the state vector at t0 138 * @param h step size 139 * @param b external weights of Butcher array 140 * @return state vector 141 */ 142 static double[] applyExternalButcherWeights(final double[] y0, final double[][] yDotK, final double h, 143 final double[] b) { 144 final double[] y = y0.clone(); 145 final int stages = b.length; 146 for (int j = 0; j < y0.length; ++j) { 147 double sum = yDotK[0][j] * b[0]; 148 for (int l = 1; l < stages; ++l) { 149 sum += yDotK[l][j] * b[l]; 150 } 151 y[j] += h * sum; 152 } 153 return y; 154 } 155 }