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 java.io.ObjectInput;
22 import java.io.ObjectOutput;
23
24 import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
25 import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
26 import org.apache.commons.math4.legacy.exception.NoBracketingException;
27 import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
28 import org.apache.commons.math4.legacy.ode.AbstractIntegrator;
29 import org.apache.commons.math4.legacy.ode.ExpandableStatefulODE;
30 import org.apache.commons.math4.legacy.ode.FirstOrderIntegrator;
31 import org.apache.commons.math4.legacy.ode.TestProblem1;
32 import org.apache.commons.math4.legacy.ode.TestProblem5;
33 import org.apache.commons.math4.legacy.ode.TestProblem6;
34 import org.apache.commons.math4.legacy.ode.TestProblemAbstract;
35 import org.apache.commons.math4.legacy.ode.TestProblemHandler;
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 AdamsMoultonIntegratorTest {
43
44 @Test(expected=DimensionMismatchException.class)
45 public void dimensionCheck()
46 throws DimensionMismatchException, NumberIsTooSmallException,
47 MaxCountExceededException, NoBracketingException {
48 TestProblem1 pb = new TestProblem1();
49 FirstOrderIntegrator integ =
50 new AdamsMoultonIntegrator(2, 0.0, 1.0, 1.0e-10, 1.0e-10);
51 integ.integrate(pb,
52 0.0, new double[pb.getDimension()+10],
53 1.0, new double[pb.getDimension()+10]);
54 }
55
56 @Test(expected=NumberIsTooSmallException.class)
57 public void testMinStep()
58 throws DimensionMismatchException, NumberIsTooSmallException,
59 MaxCountExceededException, NoBracketingException {
60
61 TestProblem1 pb = new TestProblem1();
62 double minStep = 0.1 * (pb.getFinalTime() - pb.getInitialTime());
63 double maxStep = pb.getFinalTime() - pb.getInitialTime();
64 double[] vecAbsoluteTolerance = { 1.0e-15, 1.0e-16 };
65 double[] vecRelativeTolerance = { 1.0e-15, 1.0e-16 };
66
67 FirstOrderIntegrator integ = new AdamsMoultonIntegrator(4, minStep, maxStep,
68 vecAbsoluteTolerance,
69 vecRelativeTolerance);
70 TestProblemHandler handler = new TestProblemHandler(pb, integ);
71 integ.addStepHandler(handler);
72 integ.integrate(pb,
73 pb.getInitialTime(), pb.getInitialState(),
74 pb.getFinalTime(), new double[pb.getDimension()]);
75 }
76
77 @Test
78 public void testIncreasingTolerance()
79 throws DimensionMismatchException, NumberIsTooSmallException,
80 MaxCountExceededException, NoBracketingException {
81
82 int previousCalls = Integer.MAX_VALUE;
83 for (int i = -12; i < -2; ++i) {
84 TestProblem1 pb = new TestProblem1();
85 double minStep = 0;
86 double maxStep = pb.getFinalTime() - pb.getInitialTime();
87 double scalAbsoluteTolerance = JdkMath.pow(10.0, i);
88 double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;
89
90 FirstOrderIntegrator integ = new AdamsMoultonIntegrator(4, minStep, maxStep,
91 scalAbsoluteTolerance,
92 scalRelativeTolerance);
93 TestProblemHandler handler = new TestProblemHandler(pb, integ);
94 integ.addStepHandler(handler);
95 integ.integrate(pb,
96 pb.getInitialTime(), pb.getInitialState(),
97 pb.getFinalTime(), new double[pb.getDimension()]);
98
99
100
101
102 Assert.assertTrue(handler.getMaximalValueError() > (0.45 * scalAbsoluteTolerance));
103 Assert.assertTrue(handler.getMaximalValueError() < (8.69 * scalAbsoluteTolerance));
104 Assert.assertEquals(0, handler.getMaximalTimeError(), 1.0e-16);
105
106 int calls = pb.getCalls();
107 Assert.assertEquals(integ.getEvaluations(), calls);
108 Assert.assertTrue(calls <= previousCalls);
109 previousCalls = calls;
110 }
111 }
112
113 @Test(expected = MaxCountExceededException.class)
114 public void exceedMaxEvaluations()
115 throws DimensionMismatchException, NumberIsTooSmallException,
116 MaxCountExceededException, NoBracketingException {
117
118 TestProblem1 pb = new TestProblem1();
119 double range = pb.getFinalTime() - pb.getInitialTime();
120
121 AdamsMoultonIntegrator integ = new AdamsMoultonIntegrator(2, 0, range, 1.0e-12, 1.0e-12);
122 TestProblemHandler handler = new TestProblemHandler(pb, integ);
123 integ.addStepHandler(handler);
124 integ.setMaxEvaluations(650);
125 integ.integrate(pb,
126 pb.getInitialTime(), pb.getInitialState(),
127 pb.getFinalTime(), new double[pb.getDimension()]);
128 }
129
130 @Test
131 public void backward()
132 throws DimensionMismatchException, NumberIsTooSmallException,
133 MaxCountExceededException, NoBracketingException {
134
135 TestProblem5 pb = new TestProblem5();
136 double range = JdkMath.abs(pb.getFinalTime() - pb.getInitialTime());
137
138 FirstOrderIntegrator integ = new AdamsMoultonIntegrator(4, 0, range, 1.0e-12, 1.0e-12);
139 TestProblemHandler handler = new TestProblemHandler(pb, integ);
140 integ.addStepHandler(handler);
141 integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
142 pb.getFinalTime(), new double[pb.getDimension()]);
143
144 Assert.assertTrue(handler.getLastError() < 3.0e-9);
145 Assert.assertTrue(handler.getMaximalValueError() < 3.0e-9);
146 Assert.assertEquals(0, handler.getMaximalTimeError(), 1.0e-16);
147 Assert.assertEquals("Adams-Moulton", integ.getName());
148 }
149
150 @Test
151 public void polynomial()
152 throws DimensionMismatchException, NumberIsTooSmallException,
153 MaxCountExceededException, NoBracketingException {
154 TestProblem6 pb = new TestProblem6();
155 double range = JdkMath.abs(pb.getFinalTime() - pb.getInitialTime());
156
157 for (int nSteps = 2; nSteps < 8; ++nSteps) {
158 AdamsMoultonIntegrator integ =
159 new AdamsMoultonIntegrator(nSteps, 1.0e-6 * range, 0.1 * range, 1.0e-5, 1.0e-5);
160 integ.setStarterIntegrator(new PerfectStarter(pb, nSteps));
161 TestProblemHandler handler = new TestProblemHandler(pb, integ);
162 integ.addStepHandler(handler);
163 integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
164 pb.getFinalTime(), new double[pb.getDimension()]);
165 if (nSteps < 5) {
166 Assert.assertTrue(handler.getMaximalValueError() > 2.2e-05);
167 } else {
168 Assert.assertTrue(handler.getMaximalValueError() < 1.1e-11);
169 }
170 }
171 }
172
173 private static final class PerfectStarter extends AbstractIntegrator {
174
175 private final PerfectInterpolator interpolator;
176 private final int nbSteps;
177
178 PerfectStarter(final TestProblemAbstract problem, final int nbSteps) {
179 this.interpolator = new PerfectInterpolator(problem);
180 this.nbSteps = nbSteps;
181 }
182
183 @Override
184 public void integrate(ExpandableStatefulODE equations, double t) {
185 double tStart = equations.getTime() + 0.01 * (t - equations.getTime());
186 getCounter().increment(nbSteps);
187 for (int i = 0; i < nbSteps; ++i) {
188 double tK = ((nbSteps - 1 - (i + 1)) * equations.getTime() + (i + 1) * tStart) / (nbSteps - 1);
189 interpolator.setPreviousTime(interpolator.getCurrentTime());
190 interpolator.setCurrentTime(tK);
191 interpolator.setInterpolatedTime(tK);
192 for (StepHandler handler : getStepHandlers()) {
193 handler.handleStep(interpolator, i == nbSteps - 1);
194 }
195 }
196 }
197 }
198
199 private static final class PerfectInterpolator implements StepInterpolator {
200 private static final long serialVersionUID = 1;
201 private final TestProblemAbstract problem;
202 private double previousTime;
203 private double currentTime;
204 private double interpolatedTime;
205
206 PerfectInterpolator(final TestProblemAbstract problem) {
207 this.problem = problem;
208 this.previousTime = problem.getInitialTime();
209 this.currentTime = problem.getInitialTime();
210 this.interpolatedTime = problem.getInitialTime();
211 }
212
213 @Override
214 public void readExternal(ObjectInput arg0) {
215 }
216
217 @Override
218 public void writeExternal(ObjectOutput arg0) {
219 }
220
221 @Override
222 public double getPreviousTime() {
223 return previousTime;
224 }
225
226 public void setPreviousTime(double time) {
227 previousTime = time;
228 }
229
230 @Override
231 public double getCurrentTime() {
232 return currentTime;
233 }
234
235 public void setCurrentTime(double time) {
236 currentTime = time;
237 }
238
239 @Override
240 public double getInterpolatedTime() {
241 return interpolatedTime;
242 }
243
244 @Override
245 public void setInterpolatedTime(double time) {
246 interpolatedTime = time;
247 }
248
249 @Override
250 public double[] getInterpolatedState() {
251 return problem.computeTheoreticalState(interpolatedTime);
252 }
253
254 @Override
255 public double[] getInterpolatedDerivatives() {
256 double[] y = problem.computeTheoreticalState(interpolatedTime);
257 double[] yDot = new double[y.length];
258 problem.computeDerivatives(interpolatedTime, y, yDot);
259 return yDot;
260 }
261
262 @Override
263 public double[] getInterpolatedSecondaryState(int index) {
264 return null;
265 }
266
267 @Override
268 public double[] getInterpolatedSecondaryDerivatives(int index) {
269 return null;
270 }
271
272 @Override
273 public boolean isForward() {
274 return problem.getFinalTime() > problem.getInitialTime();
275 }
276
277 @Override
278 public StepInterpolator copy() {
279 return this;
280 }
281 }
282 }