1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.hipparchus.ode.nonstiff;
19
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.hipparchus.Field;
23 import org.hipparchus.ode.FieldExpandableODE;
24 import org.hipparchus.ode.FieldODEIntegrator;
25 import org.hipparchus.ode.FieldOrdinaryDifferentialEquation;
26 import org.hipparchus.util.MathArrays;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public interface FieldExplicitRungeKuttaIntegrator<T extends CalculusFieldElement<T>>
53 extends FieldButcherArrayProvider<T>, FieldODEIntegrator<T> {
54
55
56
57
58 default double[] getRealC() {
59 final T[] c = getC();
60 final double[] cReal = new double[c.length];
61 for (int i = 0; i < c.length; i++) {
62 cReal[i] = c[i].getReal();
63 }
64 return cReal;
65 }
66
67
68
69
70 default double[][] getRealA() {
71 final T[][] a = getA();
72 final double[][] aReal = new double[a.length][];
73 for (int i = 0; i < a.length; i++) {
74 aReal[i] = new double[a[i].length];
75 for (int j = 0; j < aReal[i].length; j++) {
76 aReal[i][j] = a[i][j].getReal();
77 }
78 }
79 return aReal;
80 }
81
82
83
84
85 default double[] getRealB() {
86 final T[] b = getB();
87 final double[] bReal = new double[b.length];
88 for (int i = 0; i < b.length; i++) {
89 bReal[i] = b[i].getReal();
90 }
91 return bReal;
92 }
93
94
95
96
97
98
99 boolean isUsingFieldCoefficients();
100
101
102
103
104
105
106 default int getNumberOfStages() {
107 return getB().length;
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 default T[] singleStep(final FieldOrdinaryDifferentialEquation<T> equations, final T t0, final T[] y0, final T t) {
136
137
138 final int stages = getNumberOfStages();
139 final T[][] yDotK = MathArrays.buildArray(t0.getField(), stages, -1);
140
141
142 final T h = t.subtract(t0);
143 final FieldExpandableODE<T> fieldExpandableODE = new FieldExpandableODE<>(equations);
144 yDotK[0] = fieldExpandableODE.computeDerivatives(t0, y0);
145
146 if (isUsingFieldCoefficients()) {
147 FieldExplicitRungeKuttaIntegrator.applyInternalButcherWeights(fieldExpandableODE, t0, y0, h, getA(), getC(),
148 yDotK);
149 return FieldExplicitRungeKuttaIntegrator.applyExternalButcherWeights(y0, yDotK, h, getB());
150 } else {
151 FieldExplicitRungeKuttaIntegrator.applyInternalButcherWeights(fieldExpandableODE, t0, y0, h,
152 getRealA(), getRealC(), yDotK);
153 return FieldExplicitRungeKuttaIntegrator.applyExternalButcherWeights(y0, yDotK, h, getRealB());
154 }
155 }
156
157
158
159
160
161
162
163
164
165
166 static <T extends CalculusFieldElement<T>> T fraction(final Field<T> field, final int p, final int q) {
167 final T zero = field.getZero();
168 return zero.newInstance(p).divide(zero.newInstance(q));
169 }
170
171
172
173
174
175
176
177
178
179 static <T extends CalculusFieldElement<T>> T fraction(final Field<T> field, final double p, final double q) {
180 final T zero = field.getZero();
181 return zero.newInstance(p).divide(zero.newInstance(q));
182 }
183
184
185
186
187
188
189
190
191
192
193
194
195 static <T extends CalculusFieldElement<T>> void applyInternalButcherWeights(final FieldExpandableODE<T> equations,
196 final T t0, final T[] y0, final T h,
197 final T[][] a, final T[] c,
198 final T[][] yDotK) {
199
200 final int stages = c.length + 1;
201 final T[] yTmp = y0.clone();
202
203 for (int k = 1; k < stages; ++k) {
204
205 for (int j = 0; j < y0.length; ++j) {
206 T sum = yDotK[0][j].multiply(a[k - 1][0]);
207 for (int l = 1; l < k; ++l) {
208 sum = sum.add(yDotK[l][j].multiply(a[k - 1][l]));
209 }
210 yTmp[j] = y0[j].add(h.multiply(sum));
211 }
212
213 yDotK[k] = equations.computeDerivatives(t0.add(h.multiply(c[k - 1])), yTmp);
214 }
215 }
216
217
218
219
220
221
222
223
224
225
226
227 static <T extends CalculusFieldElement<T>> void applyInternalButcherWeights(final FieldExpandableODE<T> equations,
228 final T t0, final T[] y0, final T h,
229 final double[][] a, final double[] c,
230 final T[][] yDotK) {
231
232 final int stages = c.length + 1;
233 final T[] yTmp = y0.clone();
234
235 for (int k = 1; k < stages; ++k) {
236
237 for (int j = 0; j < y0.length; ++j) {
238 T sum = yDotK[0][j].multiply(a[k - 1][0]);
239 for (int l = 1; l < k; ++l) {
240 sum = sum.add(yDotK[l][j].multiply(a[k - 1][l]));
241 }
242 yTmp[j] = y0[j].add(h.multiply(sum));
243 }
244
245 yDotK[k] = equations.computeDerivatives(t0.add(h.multiply(c[k - 1])), yTmp);
246 }
247 }
248
249
250
251
252
253
254
255
256
257 static <T extends CalculusFieldElement<T>> T[] applyExternalButcherWeights(final T[] y0, final T[][] yDotK,
258 final T h, final T[] b) {
259 final T[] y = y0.clone();
260 final int stages = b.length;
261 for (int j = 0; j < y0.length; ++j) {
262 T sum = yDotK[0][j].multiply(b[0]);
263 for (int l = 1; l < stages; ++l) {
264 sum = sum.add(yDotK[l][j].multiply(b[l]));
265 }
266 y[j] = y[j].add(h.multiply(sum));
267 }
268 return y;
269 }
270
271
272
273
274
275
276
277
278
279
280 static <T extends CalculusFieldElement<T>> T[] applyExternalButcherWeights(final T[] y0, final T[][] yDotK,
281 final T h, final double[] b) {
282 final T[] y = y0.clone();
283 final int stages = b.length;
284 for (int j = 0; j < y0.length; ++j) {
285 T sum = yDotK[0][j].multiply(b[0]);
286 for (int l = 1; l < stages; ++l) {
287 sum = sum.add(yDotK[l][j].multiply(b[l]));
288 }
289 y[j] = y[j].add(h.multiply(sum));
290 }
291 return y;
292 }
293
294 }