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
21 import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
22 import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
23 import org.apache.commons.math4.legacy.exception.NoBracketingException;
24 import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
25 import org.apache.commons.math4.legacy.ode.FirstOrderDifferentialEquations;
26 import org.apache.commons.math4.legacy.ode.FirstOrderIntegrator;
27 import org.apache.commons.math4.legacy.ode.TestProblem1;
28 import org.apache.commons.math4.legacy.ode.TestProblem2;
29 import org.apache.commons.math4.legacy.ode.TestProblem3;
30 import org.apache.commons.math4.legacy.ode.TestProblem4;
31 import org.apache.commons.math4.legacy.ode.TestProblem5;
32 import org.apache.commons.math4.legacy.ode.TestProblem6;
33 import org.apache.commons.math4.legacy.ode.TestProblemAbstract;
34 import org.apache.commons.math4.legacy.ode.TestProblemHandler;
35 import org.apache.commons.math4.legacy.ode.events.EventHandler;
36 import org.apache.commons.math4.legacy.ode.sampling.StepHandler;
37 import org.apache.commons.math4.legacy.ode.sampling.StepInterpolator;
38 import org.apache.commons.math4.core.jdkmath.JdkMath;
39 import org.junit.Assert;
40 import org.junit.Test;
41
42 public class LutherIntegratorTest {
43
44 @Test
45 public void testMissedEndEvent()
46 throws DimensionMismatchException, NumberIsTooSmallException,
47 MaxCountExceededException, NoBracketingException {
48 final double t0 = 1878250320.0000029;
49 final double tEvent = 1878250379.9999986;
50 final double[] k = { 1.0e-4, 1.0e-5, 1.0e-6 };
51 FirstOrderDifferentialEquations ode = new FirstOrderDifferentialEquations() {
52
53 @Override
54 public int getDimension() {
55 return k.length;
56 }
57
58 @Override
59 public void computeDerivatives(double t, double[] y, double[] yDot) {
60 for (int i = 0; i < y.length; ++i) {
61 yDot[i] = k[i] * y[i];
62 }
63 }
64 };
65
66 LutherIntegrator integrator = new LutherIntegrator(60.0);
67
68 double[] y0 = new double[k.length];
69 for (int i = 0; i < y0.length; ++i) {
70 y0[i] = i + 1;
71 }
72 double[] y = new double[k.length];
73
74 double finalT = integrator.integrate(ode, t0, y0, tEvent, y);
75 Assert.assertEquals(tEvent, finalT, 1.0e-15);
76 for (int i = 0; i < y.length; ++i) {
77 Assert.assertEquals(y0[i] * JdkMath.exp(k[i] * (finalT - t0)), y[i], 1.0e-15);
78 }
79
80 integrator.addEventHandler(new EventHandler() {
81
82 @Override
83 public void init(double t0, double[] y0, double t) {
84 }
85
86 @Override
87 public void resetState(double t, double[] y) {
88 }
89
90 @Override
91 public double g(double t, double[] y) {
92 return t - tEvent;
93 }
94
95 @Override
96 public Action eventOccurred(double t, double[] y, boolean increasing) {
97 Assert.assertEquals(tEvent, t, 1.0e-15);
98 return Action.CONTINUE;
99 }
100 }, Double.POSITIVE_INFINITY, 1.0e-20, 100);
101 finalT = integrator.integrate(ode, t0, y0, tEvent + 120, y);
102 Assert.assertEquals(tEvent + 120, finalT, 1.0e-15);
103 for (int i = 0; i < y.length; ++i) {
104 Assert.assertEquals(y0[i] * JdkMath.exp(k[i] * (finalT - t0)), y[i], 1.0e-15);
105 }
106 }
107
108 @Test
109 public void testSanityChecks()
110 throws DimensionMismatchException, NumberIsTooSmallException,
111 MaxCountExceededException, NoBracketingException {
112 try {
113 TestProblem1 pb = new TestProblem1();
114 new LutherIntegrator(0.01).integrate(pb,
115 0.0, new double[pb.getDimension()+10],
116 1.0, new double[pb.getDimension()]);
117 Assert.fail("an exception should have been thrown");
118 } catch(DimensionMismatchException ie) {
119 }
120 try {
121 TestProblem1 pb = new TestProblem1();
122 new LutherIntegrator(0.01).integrate(pb,
123 0.0, new double[pb.getDimension()],
124 1.0, new double[pb.getDimension()+10]);
125 Assert.fail("an exception should have been thrown");
126 } catch(DimensionMismatchException ie) {
127 }
128 try {
129 TestProblem1 pb = new TestProblem1();
130 new LutherIntegrator(0.01).integrate(pb,
131 0.0, new double[pb.getDimension()],
132 0.0, new double[pb.getDimension()]);
133 Assert.fail("an exception should have been thrown");
134 } catch(NumberIsTooSmallException ie) {
135 }
136 }
137
138 @Test
139 public void testDecreasingSteps()
140 throws DimensionMismatchException, NumberIsTooSmallException,
141 MaxCountExceededException, NoBracketingException {
142
143 for (TestProblemAbstract pb : new TestProblemAbstract[] {
144 new TestProblem1(), new TestProblem2(), new TestProblem3(),
145 new TestProblem4(), new TestProblem5(), new TestProblem6()
146 }) {
147
148 double previousValueError = Double.NaN;
149 double previousTimeError = Double.NaN;
150 for (int i = 4; i < 10; ++i) {
151
152 double step = (pb.getFinalTime() - pb.getInitialTime()) * JdkMath.pow(2.0, -i);
153
154 FirstOrderIntegrator integ = new LutherIntegrator(step);
155 TestProblemHandler handler = new TestProblemHandler(pb, integ);
156 integ.addStepHandler(handler);
157 EventHandler[] functions = pb.getEventsHandlers();
158 for (int l = 0; l < functions.length; ++l) {
159 integ.addEventHandler(functions[l],
160 Double.POSITIVE_INFINITY, 1.0e-6 * step, 1000);
161 }
162 Assert.assertEquals(functions.length, integ.getEventHandlers().size());
163 double stopTime = integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
164 pb.getFinalTime(), new double[pb.getDimension()]);
165 if (functions.length == 0) {
166 Assert.assertEquals(pb.getFinalTime(), stopTime, 1.0e-10);
167 }
168
169 double error = handler.getMaximalValueError();
170 if (i > 4) {
171 Assert.assertTrue(error < 1.01 * JdkMath.abs(previousValueError));
172 }
173 previousValueError = error;
174
175 double timeError = handler.getMaximalTimeError();
176 if (i > 4) {
177 Assert.assertTrue(timeError <= JdkMath.abs(previousTimeError));
178 }
179 previousTimeError = timeError;
180
181 integ.clearEventHandlers();
182 Assert.assertEquals(0, integ.getEventHandlers().size());
183 }
184 }
185 }
186
187 @Test
188 public void testSmallStep()
189 throws DimensionMismatchException, NumberIsTooSmallException,
190 MaxCountExceededException, NoBracketingException {
191
192 TestProblem1 pb = new TestProblem1();
193 double step = (pb.getFinalTime() - pb.getInitialTime()) * 0.001;
194
195 FirstOrderIntegrator integ = new LutherIntegrator(step);
196 TestProblemHandler handler = new TestProblemHandler(pb, integ);
197 integ.addStepHandler(handler);
198 integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
199 pb.getFinalTime(), new double[pb.getDimension()]);
200
201 Assert.assertTrue(handler.getLastError() < 9.0e-17);
202 Assert.assertTrue(handler.getMaximalValueError() < 4.0e-15);
203 Assert.assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
204 Assert.assertEquals("Luther", integ.getName());
205 }
206
207 @Test
208 public void testBigStep()
209 throws DimensionMismatchException, NumberIsTooSmallException,
210 MaxCountExceededException, NoBracketingException {
211
212 TestProblem1 pb = new TestProblem1();
213 double step = (pb.getFinalTime() - pb.getInitialTime()) * 0.2;
214
215 FirstOrderIntegrator integ = new LutherIntegrator(step);
216 TestProblemHandler handler = new TestProblemHandler(pb, integ);
217 integ.addStepHandler(handler);
218 integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
219 pb.getFinalTime(), new double[pb.getDimension()]);
220
221 Assert.assertTrue(handler.getLastError() > 0.00002);
222 Assert.assertTrue(handler.getMaximalValueError() > 0.001);
223 Assert.assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
224 }
225
226 @Test
227 public void testBackward()
228 throws DimensionMismatchException, NumberIsTooSmallException,
229 MaxCountExceededException, NoBracketingException {
230
231 TestProblem5 pb = new TestProblem5();
232 double step = JdkMath.abs(pb.getFinalTime() - pb.getInitialTime()) * 0.001;
233
234 FirstOrderIntegrator integ = new LutherIntegrator(step);
235 TestProblemHandler handler = new TestProblemHandler(pb, integ);
236 integ.addStepHandler(handler);
237 integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
238 pb.getFinalTime(), new double[pb.getDimension()]);
239
240 Assert.assertTrue(handler.getLastError() < 3.0e-13);
241 Assert.assertTrue(handler.getMaximalValueError() < 5.0e-13);
242 Assert.assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
243 Assert.assertEquals("Luther", integ.getName());
244 }
245
246 @Test
247 public void testKepler()
248 throws DimensionMismatchException, NumberIsTooSmallException,
249 MaxCountExceededException, NoBracketingException {
250
251 final TestProblem3 pb = new TestProblem3(0.9);
252 double step = (pb.getFinalTime() - pb.getInitialTime()) * 0.0003;
253
254 FirstOrderIntegrator integ = new LutherIntegrator(step);
255 integ.addStepHandler(new KeplerHandler(pb));
256 integ.integrate(pb,
257 pb.getInitialTime(), pb.getInitialState(),
258 pb.getFinalTime(), new double[pb.getDimension()]);
259 }
260
261 private static final class KeplerHandler implements StepHandler {
262 KeplerHandler(TestProblem3 pb) {
263 this.pb = pb;
264 maxError = 0;
265 }
266 @Override
267 public void init(double t0, double[] y0, double t) {
268 maxError = 0;
269 }
270 @Override
271 public void handleStep(StepInterpolator interpolator, boolean isLast) {
272
273 double[] interpolatedY = interpolator.getInterpolatedState ();
274 double[] theoreticalY = pb.computeTheoreticalState(interpolator.getCurrentTime());
275 double dx = interpolatedY[0] - theoreticalY[0];
276 double dy = interpolatedY[1] - theoreticalY[1];
277 double error = dx * dx + dy * dy;
278 if (error > maxError) {
279 maxError = error;
280 }
281 if (isLast) {
282 Assert.assertTrue(maxError < 2.2e-7);
283 }
284 }
285 private double maxError = 0;
286 private TestProblem3 pb;
287 }
288
289 @Test
290 public void testStepSize()
291 throws DimensionMismatchException, NumberIsTooSmallException,
292 MaxCountExceededException, NoBracketingException {
293 final double step = 1.23456;
294 FirstOrderIntegrator integ = new LutherIntegrator(step);
295 integ.addStepHandler(new StepHandler() {
296 @Override
297 public void handleStep(StepInterpolator interpolator, boolean isLast) {
298 if (! isLast) {
299 Assert.assertEquals(step,
300 interpolator.getCurrentTime() - interpolator.getPreviousTime(),
301 1.0e-12);
302 }
303 }
304 @Override
305 public void init(double t0, double[] y0, double t) {
306 }
307 });
308 integ.integrate(new FirstOrderDifferentialEquations() {
309 @Override
310 public void computeDerivatives(double t, double[] y, double[] dot) {
311 dot[0] = 1.0;
312 }
313 @Override
314 public int getDimension() {
315 return 1;
316 }
317 }, 0.0, new double[] { 0.0 }, 5.0, new double[1]);
318 }
319
320 @Test
321 public void testSingleStep() {
322
323 final TestProblem3 pb = new TestProblem3(0.9);
324 double h = (pb.getFinalTime() - pb.getInitialTime()) * 0.0003;
325
326 RungeKuttaIntegrator integ = new LutherIntegrator(Double.NaN);
327 double t = pb.getInitialTime();
328 double[] y = pb.getInitialState();
329 for (int i = 0; i < 100; ++i) {
330 y = integ.singleStep(pb, t, y, t + h);
331 t += h;
332 }
333 double[] yth = pb.computeTheoreticalState(t);
334 double dx = y[0] - yth[0];
335 double dy = y[1] - yth[1];
336 double error = dx * dx + dy * dy;
337 Assert.assertEquals(0.0, error, 1.0e-11);
338 }
339 }