1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.math4.legacy.ode.nonstiff;
19
20 import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
21 import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
22 import org.apache.commons.math4.legacy.exception.NoBracketingException;
23 import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
24 import org.apache.commons.math4.legacy.ode.ExpandableStatefulODE;
25 import org.apache.commons.math4.core.jdkmath.JdkMath;
26
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
53
54
55
56
57
58
59
60
61
62 public abstract class EmbeddedRungeKuttaIntegrator
63 extends AdaptiveStepsizeIntegrator {
64
65
66 private final boolean fsal;
67
68
69 private final double[] c;
70
71
72 private final double[][] a;
73
74
75 private final double[] b;
76
77
78 private final RungeKuttaStepInterpolator prototype;
79
80
81 private final double exp;
82
83
84 private double safety;
85
86
87 private double minReduction;
88
89
90 private double maxGrowth;
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 protected EmbeddedRungeKuttaIntegrator(final String name, final boolean fsal,
109 final double[] c, final double[][] a, final double[] b,
110 final RungeKuttaStepInterpolator prototype,
111 final double minStep, final double maxStep,
112 final double scalAbsoluteTolerance,
113 final double scalRelativeTolerance) {
114
115 super(name, minStep, maxStep, scalAbsoluteTolerance, scalRelativeTolerance);
116
117 this.fsal = fsal;
118 this.c = c;
119 this.a = a;
120 this.b = b;
121 this.prototype = prototype;
122
123 exp = -1.0 / getOrder();
124
125
126 setSafety(0.9);
127 setMinReduction(0.2);
128 setMaxGrowth(10.0);
129 }
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 protected EmbeddedRungeKuttaIntegrator(final String name, final boolean fsal,
146 final double[] c, final double[][] a, final double[] b,
147 final RungeKuttaStepInterpolator prototype,
148 final double minStep, final double maxStep,
149 final double[] vecAbsoluteTolerance,
150 final double[] vecRelativeTolerance) {
151
152 super(name, minStep, maxStep, vecAbsoluteTolerance, vecRelativeTolerance);
153
154 this.fsal = fsal;
155 this.c = c;
156 this.a = a;
157 this.b = b;
158 this.prototype = prototype;
159
160 exp = -1.0 / getOrder();
161
162
163 setSafety(0.9);
164 setMinReduction(0.2);
165 setMaxGrowth(10.0);
166 }
167
168
169
170
171 public abstract int getOrder();
172
173
174
175
176 public double getSafety() {
177 return safety;
178 }
179
180
181
182
183 public void setSafety(final double safety) {
184 this.safety = safety;
185 }
186
187
188 @Override
189 public void integrate(final ExpandableStatefulODE equations, final double t)
190 throws NumberIsTooSmallException, DimensionMismatchException,
191 MaxCountExceededException, NoBracketingException {
192
193 sanityChecks(equations, t);
194 setEquations(equations);
195 final boolean forward = t > equations.getTime();
196
197
198 final double[] y0 = equations.getCompleteState();
199 final double[] y = y0.clone();
200 final int stages = c.length + 1;
201 final double[][] yDotK = new double[stages][y.length];
202 final double[] yTmp = y0.clone();
203 final double[] yDotTmp = new double[y.length];
204
205
206 final RungeKuttaStepInterpolator interpolator = (RungeKuttaStepInterpolator) prototype.copy();
207 interpolator.reinitialize(this, yTmp, yDotK, forward,
208 equations.getPrimaryMapper(), equations.getSecondaryMappers());
209 interpolator.storeTime(equations.getTime());
210
211
212 stepStart = equations.getTime();
213 double hNew = 0;
214 boolean firstTime = true;
215 initIntegration(equations.getTime(), y0, t);
216
217
218 isLastStep = false;
219 do {
220
221 interpolator.shift();
222
223
224 double error = 10;
225 while (error >= 1.0) {
226
227 if (firstTime || !fsal) {
228
229 computeDerivatives(stepStart, y, yDotK[0]);
230 }
231
232 if (firstTime) {
233 final double[] scale = new double[mainSetDimension];
234 if (vecAbsoluteTolerance == null) {
235 for (int i = 0; i < scale.length; ++i) {
236 scale[i] = scalAbsoluteTolerance + scalRelativeTolerance * JdkMath.abs(y[i]);
237 }
238 } else {
239 for (int i = 0; i < scale.length; ++i) {
240 scale[i] = vecAbsoluteTolerance[i] + vecRelativeTolerance[i] * JdkMath.abs(y[i]);
241 }
242 }
243 hNew = initializeStep(forward, getOrder(), scale,
244 stepStart, y, yDotK[0], yTmp, yDotK[1]);
245 firstTime = false;
246 }
247
248 stepSize = hNew;
249 if (forward) {
250 if (stepStart + stepSize >= t) {
251 stepSize = t - stepStart;
252 }
253 } else {
254 if (stepStart + stepSize <= t) {
255 stepSize = t - stepStart;
256 }
257 }
258
259
260 for (int k = 1; k < stages; ++k) {
261
262 for (int j = 0; j < y0.length; ++j) {
263 double sum = a[k-1][0] * yDotK[0][j];
264 for (int l = 1; l < k; ++l) {
265 sum += a[k-1][l] * yDotK[l][j];
266 }
267 yTmp[j] = y[j] + stepSize * sum;
268 }
269
270 computeDerivatives(stepStart + c[k-1] * stepSize, yTmp, yDotK[k]);
271 }
272
273
274 for (int j = 0; j < y0.length; ++j) {
275 double sum = b[0] * yDotK[0][j];
276 for (int l = 1; l < stages; ++l) {
277 sum += b[l] * yDotK[l][j];
278 }
279 yTmp[j] = y[j] + stepSize * sum;
280 }
281
282
283 error = estimateError(yDotK, y, yTmp, stepSize);
284 if (error >= 1.0) {
285
286 final double factor =
287 JdkMath.min(maxGrowth,
288 JdkMath.max(minReduction, safety * JdkMath.pow(error, exp)));
289 hNew = filterStep(stepSize * factor, forward, false);
290 }
291 }
292
293
294 interpolator.storeTime(stepStart + stepSize);
295 System.arraycopy(yTmp, 0, y, 0, y0.length);
296 System.arraycopy(yDotK[stages - 1], 0, yDotTmp, 0, y0.length);
297 stepStart = acceptStep(interpolator, y, yDotTmp, t);
298 System.arraycopy(y, 0, yTmp, 0, y.length);
299
300 if (!isLastStep) {
301
302
303 interpolator.storeTime(stepStart);
304
305 if (fsal) {
306
307 System.arraycopy(yDotTmp, 0, yDotK[0], 0, y0.length);
308 }
309
310
311 final double factor =
312 JdkMath.min(maxGrowth, JdkMath.max(minReduction, safety * JdkMath.pow(error, exp)));
313 final double scaledH = stepSize * factor;
314 final double nextT = stepStart + scaledH;
315 final boolean nextIsLast = forward ? (nextT >= t) : (nextT <= t);
316 hNew = filterStep(scaledH, forward, nextIsLast);
317
318 final double filteredNextT = stepStart + hNew;
319 final boolean filteredNextIsLast = forward ? (filteredNextT >= t) : (filteredNextT <= t);
320 if (filteredNextIsLast) {
321 hNew = t - stepStart;
322 }
323 }
324 } while (!isLastStep);
325
326
327 equations.setTime(stepStart);
328 equations.setCompleteState(y);
329
330 resetInternalState();
331 }
332
333
334
335
336 public double getMinReduction() {
337 return minReduction;
338 }
339
340
341
342
343 public void setMinReduction(final double minReduction) {
344 this.minReduction = minReduction;
345 }
346
347
348
349
350 public double getMaxGrowth() {
351 return maxGrowth;
352 }
353
354
355
356
357 public void setMaxGrowth(final double maxGrowth) {
358 this.maxGrowth = maxGrowth;
359 }
360
361
362
363
364
365
366
367
368 protected abstract double estimateError(double[][] yDotK,
369 double[] y0, double[] y1,
370 double h);
371 }