1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.math.ode;
19
20 import org.apache.commons.math.ode.DerivativeException;
21 import org.apache.commons.math.ode.DormandPrince853Integrator;
22 import org.apache.commons.math.ode.DummyStepHandler;
23 import org.apache.commons.math.ode.FirstOrderIntegrator;
24 import org.apache.commons.math.ode.IntegratorException;
25 import org.apache.commons.math.ode.StepHandler;
26 import org.apache.commons.math.ode.StepInterpolator;
27 import org.apache.commons.math.ode.SwitchingFunction;
28
29 import junit.framework.*;
30
31 public class DormandPrince853IntegratorTest
32 extends TestCase {
33
34 public DormandPrince853IntegratorTest(String name) {
35 super(name);
36 }
37
38 public void testDimensionCheck() {
39 try {
40 TestProblem1 pb = new TestProblem1();
41 DormandPrince853Integrator integrator = new DormandPrince853Integrator(0.0, 1.0,
42 1.0e-10, 1.0e-10);
43 integrator.integrate(pb,
44 0.0, new double[pb.getDimension()+10],
45 1.0, new double[pb.getDimension()+10]);
46 fail("an exception should have been thrown");
47 } catch(DerivativeException de) {
48 fail("wrong exception caught");
49 } catch(IntegratorException ie) {
50 }
51 }
52
53 public void testNullIntervalCheck() {
54 try {
55 TestProblem1 pb = new TestProblem1();
56 DormandPrince853Integrator integrator = new DormandPrince853Integrator(0.0, 1.0,
57 1.0e-10, 1.0e-10);
58 integrator.integrate(pb,
59 0.0, new double[pb.getDimension()],
60 0.0, new double[pb.getDimension()]);
61 fail("an exception should have been thrown");
62 } catch(DerivativeException de) {
63 fail("wrong exception caught");
64 } catch(IntegratorException ie) {
65 }
66 }
67
68 public void testMinStep()
69 throws DerivativeException, IntegratorException {
70
71 try {
72 TestProblem1 pb = new TestProblem1();
73 double minStep = 0.1 * (pb.getFinalTime() - pb.getInitialTime());
74 double maxStep = pb.getFinalTime() - pb.getInitialTime();
75 double[] vecAbsoluteTolerance = { 1.0e-15, 1.0e-16 };
76 double[] vecRelativeTolerance = { 1.0e-15, 1.0e-16 };
77
78 FirstOrderIntegrator integ = new DormandPrince853Integrator(minStep, maxStep,
79 vecAbsoluteTolerance,
80 vecRelativeTolerance);
81 TestProblemHandler handler = new TestProblemHandler(pb, integ);
82 integ.setStepHandler(handler);
83 integ.integrate(pb,
84 pb.getInitialTime(), pb.getInitialState(),
85 pb.getFinalTime(), new double[pb.getDimension()]);
86 fail("an exception should have been thrown");
87 } catch(DerivativeException de) {
88 fail("wrong exception caught");
89 } catch(IntegratorException ie) {
90 }
91
92 }
93
94 public void testIncreasingTolerance()
95 throws DerivativeException, IntegratorException {
96
97 int previousCalls = Integer.MAX_VALUE;
98 for (int i = -12; i < -2; ++i) {
99 TestProblem1 pb = new TestProblem1();
100 double minStep = 0;
101 double maxStep = pb.getFinalTime() - pb.getInitialTime();
102 double scalAbsoluteTolerance = Math.pow(10.0, i);
103 double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;
104
105 FirstOrderIntegrator integ = new DormandPrince853Integrator(minStep, maxStep,
106 scalAbsoluteTolerance,
107 scalRelativeTolerance);
108 TestProblemHandler handler = new TestProblemHandler(pb, integ);
109 integ.setStepHandler(handler);
110 integ.integrate(pb,
111 pb.getInitialTime(), pb.getInitialState(),
112 pb.getFinalTime(), new double[pb.getDimension()]);
113
114
115
116
117 assertTrue(handler.getMaximalValueError() < (1.3 * scalAbsoluteTolerance));
118 assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
119
120 int calls = pb.getCalls();
121 assertTrue(calls <= previousCalls);
122 previousCalls = calls;
123
124 }
125
126 }
127
128 public void testSwitchingFunctions()
129 throws DerivativeException, IntegratorException {
130
131 TestProblem4 pb = new TestProblem4();
132 double minStep = 0;
133 double maxStep = pb.getFinalTime() - pb.getInitialTime();
134 double scalAbsoluteTolerance = 1.0e-9;
135 double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;
136
137 FirstOrderIntegrator integ = new DormandPrince853Integrator(minStep, maxStep,
138 scalAbsoluteTolerance,
139 scalRelativeTolerance);
140 TestProblemHandler handler = new TestProblemHandler(pb, integ);
141 integ.setStepHandler(handler);
142 SwitchingFunction[] functions = pb.getSwitchingFunctions();
143 for (int l = 0; l < functions.length; ++l) {
144 integ.addSwitchingFunction(functions[l],
145 Double.POSITIVE_INFINITY, 1.0e-8 * maxStep, 1000);
146 }
147 integ.integrate(pb,
148 pb.getInitialTime(), pb.getInitialState(),
149 pb.getFinalTime(), new double[pb.getDimension()]);
150
151 assertTrue(handler.getMaximalValueError() < 5.0e-8);
152 assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
153 assertEquals(12.0, handler.getLastTime(), 1.0e-8 * maxStep);
154
155 }
156
157 public void testKepler()
158 throws DerivativeException, IntegratorException {
159
160 final TestProblem3 pb = new TestProblem3(0.9);
161 double minStep = 0;
162 double maxStep = pb.getFinalTime() - pb.getInitialTime();
163 double scalAbsoluteTolerance = 1.0e-8;
164 double scalRelativeTolerance = scalAbsoluteTolerance;
165
166 FirstOrderIntegrator integ = new DormandPrince853Integrator(minStep, maxStep,
167 scalAbsoluteTolerance,
168 scalRelativeTolerance);
169 integ.setStepHandler(new KeplerHandler(pb));
170 integ.integrate(pb,
171 pb.getInitialTime(), pb.getInitialState(),
172 pb.getFinalTime(), new double[pb.getDimension()]);
173
174 assertTrue(pb.getCalls() < 2900);
175
176 }
177
178 public void testVariableSteps()
179 throws DerivativeException, IntegratorException {
180
181 final TestProblem3 pb = new TestProblem3(0.9);
182 double minStep = 0;
183 double maxStep = pb.getFinalTime() - pb.getInitialTime();
184 double scalAbsoluteTolerance = 1.0e-8;
185 double scalRelativeTolerance = scalAbsoluteTolerance;
186
187 FirstOrderIntegrator integ = new DormandPrince853Integrator(minStep, maxStep,
188 scalAbsoluteTolerance,
189 scalRelativeTolerance);
190 integ.setStepHandler(new VariableHandler());
191 integ.integrate(pb,
192 pb.getInitialTime(), pb.getInitialState(),
193 pb.getFinalTime(), new double[pb.getDimension()]);
194 assertEquals("Dormand-Prince 8 (5, 3)", integ.getName());
195 }
196
197 public void testNoDenseOutput()
198 throws DerivativeException, IntegratorException {
199 TestProblem1 pb1 = new TestProblem1();
200 TestProblem1 pb2 = (TestProblem1) pb1.clone();
201 double minStep = 0.1 * (pb1.getFinalTime() - pb1.getInitialTime());
202 double maxStep = pb1.getFinalTime() - pb1.getInitialTime();
203 double scalAbsoluteTolerance = 1.0e-4;
204 double scalRelativeTolerance = 1.0e-4;
205
206 FirstOrderIntegrator integ = new DormandPrince853Integrator(minStep, maxStep,
207 scalAbsoluteTolerance,
208 scalRelativeTolerance);
209 integ.setStepHandler(DummyStepHandler.getInstance());
210 integ.integrate(pb1,
211 pb1.getInitialTime(), pb1.getInitialState(),
212 pb1.getFinalTime(), new double[pb1.getDimension()]);
213 int callsWithoutDenseOutput = pb1.getCalls();
214
215 integ.setStepHandler(new InterpolatingStepHandler());
216 integ.integrate(pb2,
217 pb2.getInitialTime(), pb2.getInitialState(),
218 pb2.getFinalTime(), new double[pb2.getDimension()]);
219 int callsWithDenseOutput = pb2.getCalls();
220
221 assertTrue(callsWithDenseOutput > callsWithoutDenseOutput);
222
223 }
224
225 public void testUnstableDerivative()
226 throws DerivativeException, IntegratorException {
227 final StepProblem stepProblem = new StepProblem(0.0, 1.0, 2.0);
228 FirstOrderIntegrator integ =
229 new DormandPrince853Integrator(0.1, 10, 1.0e-12, 0.0);
230 integ.addSwitchingFunction(stepProblem, 1.0, 1.0e-12, 1000);
231 double[] y = { Double.NaN };
232 integ.integrate(stepProblem, 0.0, new double[] { 0.0 }, 10.0, y);
233 assertEquals(8.0, y[0], 1.0e-12);
234 }
235
236 private static class KeplerHandler implements StepHandler {
237 public KeplerHandler(TestProblem3 pb) {
238 this.pb = pb;
239 reset();
240 }
241 public boolean requiresDenseOutput() {
242 return true;
243 }
244 public void reset() {
245 nbSteps = 0;
246 maxError = 0;
247 }
248 public void handleStep(StepInterpolator interpolator,
249 boolean isLast)
250 throws DerivativeException {
251
252 ++nbSteps;
253 for (int a = 1; a < 10; ++a) {
254
255 double prev = interpolator.getPreviousTime();
256 double curr = interpolator.getCurrentTime();
257 double interp = ((10 - a) * prev + a * curr) / 10;
258 interpolator.setInterpolatedTime(interp);
259
260 double[] interpolatedY = interpolator.getInterpolatedState ();
261 double[] theoreticalY = pb.computeTheoreticalState(interpolator.getInterpolatedTime());
262 double dx = interpolatedY[0] - theoreticalY[0];
263 double dy = interpolatedY[1] - theoreticalY[1];
264 double error = dx * dx + dy * dy;
265 if (error > maxError) {
266 maxError = error;
267 }
268 }
269 if (isLast) {
270 assertTrue(maxError < 2.4e-10);
271 assertTrue(nbSteps < 150);
272 }
273 }
274 private int nbSteps;
275 private double maxError;
276 private TestProblem3 pb;
277 }
278
279 private static class VariableHandler implements StepHandler {
280 public VariableHandler() {
281 reset();
282 }
283 public boolean requiresDenseOutput() {
284 return false;
285 }
286 public void reset() {
287 firstTime = true;
288 minStep = 0;
289 maxStep = 0;
290 }
291 public void handleStep(StepInterpolator interpolator,
292 boolean isLast) {
293
294 double step = Math.abs(interpolator.getCurrentTime()
295 - interpolator.getPreviousTime());
296 if (firstTime) {
297 minStep = Math.abs(step);
298 maxStep = minStep;
299 firstTime = false;
300 } else {
301 if (step < minStep) {
302 minStep = step;
303 }
304 if (step > maxStep) {
305 maxStep = step;
306 }
307 }
308
309 if (isLast) {
310 assertTrue(minStep < (1.0 / 100.0));
311 assertTrue(maxStep > (1.0 / 2.0));
312 }
313 }
314 private boolean firstTime = true;
315 private double minStep = 0;
316 private double maxStep = 0;
317 }
318
319 private static class InterpolatingStepHandler implements StepHandler {
320 public boolean requiresDenseOutput() {
321 return true;
322 }
323 public void reset() {
324 }
325 public void handleStep(StepInterpolator interpolator,
326 boolean isLast)
327 throws DerivativeException {
328 double prev = interpolator.getPreviousTime();
329 double curr = interpolator.getCurrentTime();
330 interpolator.setInterpolatedTime(0.5*(prev + curr));
331 }
332 }
333
334 public static Test suite() {
335 return new TestSuite(DormandPrince853IntegratorTest.class);
336 }
337
338 }