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 java.io.IOException;
21 import java.io.ObjectInput;
22 import java.io.ObjectOutput;
23
24 import org.apache.commons.math4.legacy.ode.EquationsMapper;
25 import org.apache.commons.math4.legacy.ode.sampling.AbstractStepInterpolator;
26 import org.apache.commons.math4.legacy.ode.sampling.StepInterpolator;
27 import org.apache.commons.math4.core.jdkmath.JdkMath;
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 class GraggBulirschStoerStepInterpolator
78 extends AbstractStepInterpolator {
79
80
81 private static final long serialVersionUID = 20110928L;
82
83
84 private double[] y0Dot;
85
86
87 private double[] y1;
88
89
90 private double[] y1Dot;
91
92
93
94
95 private double[][] yMidDots;
96
97
98 private double[][] polynomials;
99
100
101 private double[] errfac;
102
103
104 private int currentDegree;
105
106
107
108
109
110
111
112 public GraggBulirschStoerStepInterpolator() {
113 y0Dot = null;
114 y1 = null;
115 y1Dot = null;
116 yMidDots = null;
117 resetTables(-1);
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 GraggBulirschStoerStepInterpolator(final double[] y, final double[] y0Dot,
136 final double[] y1, final double[] y1Dot,
137 final double[][] yMidDots,
138 final boolean forward,
139 final EquationsMapper primaryMapper,
140 final EquationsMapper[] secondaryMappers) {
141
142 super(y, forward, primaryMapper, secondaryMappers);
143 this.y0Dot = y0Dot;
144 this.y1 = y1;
145 this.y1Dot = y1Dot;
146 this.yMidDots = yMidDots;
147
148 resetTables(yMidDots.length + 4);
149 }
150
151
152
153
154
155
156 GraggBulirschStoerStepInterpolator(final GraggBulirschStoerStepInterpolator interpolator) {
157
158 super(interpolator);
159
160 final int dimension = currentState.length;
161
162
163
164 y0Dot = null;
165 y1 = null;
166 y1Dot = null;
167 yMidDots = null;
168
169
170 if (interpolator.polynomials == null) {
171 polynomials = null;
172 currentDegree = -1;
173 } else {
174 resetTables(interpolator.currentDegree);
175 for (int i = 0; i < polynomials.length; ++i) {
176 polynomials[i] = new double[dimension];
177 System.arraycopy(interpolator.polynomials[i], 0,
178 polynomials[i], 0, dimension);
179 }
180 currentDegree = interpolator.currentDegree;
181 }
182 }
183
184
185
186
187
188
189 private void resetTables(final int maxDegree) {
190
191 if (maxDegree < 0) {
192 polynomials = null;
193 errfac = null;
194 currentDegree = -1;
195 } else {
196
197 final double[][] newPols = new double[maxDegree + 1][];
198 if (polynomials != null) {
199 System.arraycopy(polynomials, 0, newPols, 0, polynomials.length);
200 for (int i = polynomials.length; i < newPols.length; ++i) {
201 newPols[i] = new double[currentState.length];
202 }
203 } else {
204 for (int i = 0; i < newPols.length; ++i) {
205 newPols[i] = new double[currentState.length];
206 }
207 }
208 polynomials = newPols;
209
210
211 if (maxDegree <= 4) {
212 errfac = null;
213 } else {
214 errfac = new double[maxDegree - 4];
215 for (int i = 0; i < errfac.length; ++i) {
216 final int ip5 = i + 5;
217 errfac[i] = 1.0 / (ip5 * ip5);
218 final double e = 0.5 * JdkMath.sqrt (((double) (i + 1)) / ip5);
219 for (int j = 0; j <= i; ++j) {
220 errfac[i] *= e / (j + 1);
221 }
222 }
223 }
224
225 currentDegree = 0;
226 }
227 }
228
229
230 @Override
231 protected StepInterpolator doCopy() {
232 return new GraggBulirschStoerStepInterpolator(this);
233 }
234
235
236
237
238
239
240 public void computeCoefficients(final int mu, final double h) {
241
242 if (polynomials == null || polynomials.length <= (mu + 4)) {
243 resetTables(mu + 4);
244 }
245
246 currentDegree = mu + 4;
247
248 for (int i = 0; i < currentState.length; ++i) {
249
250 final double yp0 = h * y0Dot[i];
251 final double yp1 = h * y1Dot[i];
252 final double ydiff = y1[i] - currentState[i];
253 final double aspl = ydiff - yp1;
254 final double bspl = yp0 - ydiff;
255
256 polynomials[0][i] = currentState[i];
257 polynomials[1][i] = ydiff;
258 polynomials[2][i] = aspl;
259 polynomials[3][i] = bspl;
260
261 if (mu < 0) {
262 return;
263 }
264
265
266 final double ph0 = 0.5 * (currentState[i] + y1[i]) + 0.125 * (aspl + bspl);
267 polynomials[4][i] = 16 * (yMidDots[0][i] - ph0);
268
269 if (mu > 0) {
270 final double ph1 = ydiff + 0.25 * (aspl - bspl);
271 polynomials[5][i] = 16 * (yMidDots[1][i] - ph1);
272
273 if (mu > 1) {
274 final double ph2 = yp1 - yp0;
275 polynomials[6][i] = 16 * (yMidDots[2][i] - ph2 + polynomials[4][i]);
276
277 if (mu > 2) {
278 final double ph3 = 6 * (bspl - aspl);
279 polynomials[7][i] = 16 * (yMidDots[3][i] - ph3 + 3 * polynomials[5][i]);
280
281 for (int j = 4; j <= mu; ++j) {
282 final double fac1 = 0.5 * j * (j - 1);
283 final double fac2 = 2 * fac1 * (j - 2) * (j - 3);
284 polynomials[j+4][i] =
285 16 * (yMidDots[j][i] + fac1 * polynomials[j+2][i] - fac2 * polynomials[j][i]);
286 }
287 }
288 }
289 }
290 }
291 }
292
293
294
295
296
297 public double estimateError(final double[] scale) {
298 double error = 0;
299 if (currentDegree >= 5) {
300 for (int i = 0; i < scale.length; ++i) {
301 final double e = polynomials[currentDegree][i] / scale[i];
302 error += e * e;
303 }
304 error = JdkMath.sqrt(error / scale.length) * errfac[currentDegree - 5];
305 }
306 return error;
307 }
308
309
310 @Override
311 protected void computeInterpolatedStateAndDerivatives(final double theta,
312 final double oneMinusThetaH) {
313
314 final int dimension = currentState.length;
315
316 final double oneMinusTheta = 1.0 - theta;
317 final double theta05 = theta - 0.5;
318 final double tOmT = theta * oneMinusTheta;
319 final double t4 = tOmT * tOmT;
320 final double t4Dot = 2 * tOmT * (1 - 2 * theta);
321 final double dot1 = 1.0 / h;
322 final double dot2 = theta * (2 - 3 * theta) / h;
323 final double dot3 = ((3 * theta - 4) * theta + 1) / h;
324
325 for (int i = 0; i < dimension; ++i) {
326
327 final double p0 = polynomials[0][i];
328 final double p1 = polynomials[1][i];
329 final double p2 = polynomials[2][i];
330 final double p3 = polynomials[3][i];
331 interpolatedState[i] = p0 + theta * (p1 + oneMinusTheta * (p2 * theta + p3 * oneMinusTheta));
332 interpolatedDerivatives[i] = dot1 * p1 + dot2 * p2 + dot3 * p3;
333
334 if (currentDegree > 3) {
335 double cDot = 0;
336 double c = polynomials[currentDegree][i];
337 for (int j = currentDegree - 1; j > 3; --j) {
338 final double d = 1.0 / (j - 3);
339 cDot = d * (theta05 * cDot + c);
340 c = polynomials[j][i] + c * d * theta05;
341 }
342 interpolatedState[i] += t4 * c;
343 interpolatedDerivatives[i] += (t4 * cDot + t4Dot * c) / h;
344 }
345 }
346
347 if (h == 0) {
348
349
350 System.arraycopy(yMidDots[1], 0, interpolatedDerivatives, 0, dimension);
351 }
352 }
353
354
355 @Override
356 public void writeExternal(final ObjectOutput out)
357 throws IOException {
358
359 final int dimension = (currentState == null) ? -1 : currentState.length;
360
361
362 writeBaseExternal(out);
363
364
365 out.writeInt(currentDegree);
366 for (int k = 0; k <= currentDegree; ++k) {
367 for (int l = 0; l < dimension; ++l) {
368 out.writeDouble(polynomials[k][l]);
369 }
370 }
371 }
372
373
374 @Override
375 public void readExternal(final ObjectInput in)
376 throws IOException, ClassNotFoundException {
377
378
379 final double t = readBaseExternal(in);
380 final int dimension = (currentState == null) ? -1 : currentState.length;
381
382
383 final int degree = in.readInt();
384 resetTables(degree);
385 currentDegree = degree;
386
387 for (int k = 0; k <= currentDegree; ++k) {
388 for (int l = 0; l < dimension; ++l) {
389 polynomials[k][l] = in.readDouble();
390 }
391 }
392
393
394 setInterpolatedTime(t);
395 }
396 }