1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math.ode.nonstiff;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertTrue;
22  
23  import org.apache.commons.math.ode.DerivativeException;
24  import org.apache.commons.math.ode.FirstOrderIntegrator;
25  import org.apache.commons.math.ode.IntegratorException;
26  import org.apache.commons.math.ode.TestProblem1;
27  import org.apache.commons.math.ode.TestProblem5;
28  import org.apache.commons.math.ode.TestProblem6;
29  import org.apache.commons.math.ode.TestProblemHandler;
30  import org.junit.Test;
31  
32  public class AdamsMoultonIntegratorTest {
33  
34      @Test(expected=IntegratorException.class)
35      public void dimensionCheck() throws DerivativeException, IntegratorException {
36          TestProblem1 pb = new TestProblem1();
37          FirstOrderIntegrator integ =
38              new AdamsMoultonIntegrator(2, 0.0, 1.0, 1.0e-10, 1.0e-10);
39          integ.integrate(pb,
40                          0.0, new double[pb.getDimension()+10],
41                          1.0, new double[pb.getDimension()+10]);
42      }
43  
44      @Test(expected=IntegratorException.class)
45      public void testMinStep() throws DerivativeException, IntegratorException {
46  
47            TestProblem1 pb = new TestProblem1();
48            double minStep = 0.1 * (pb.getFinalTime() - pb.getInitialTime());
49            double maxStep = pb.getFinalTime() - pb.getInitialTime();
50            double[] vecAbsoluteTolerance = { 1.0e-15, 1.0e-16 };
51            double[] vecRelativeTolerance = { 1.0e-15, 1.0e-16 };
52  
53            FirstOrderIntegrator integ = new AdamsMoultonIntegrator(4, minStep, maxStep,
54                                                                    vecAbsoluteTolerance,
55                                                                    vecRelativeTolerance);
56            TestProblemHandler handler = new TestProblemHandler(pb, integ);
57            integ.addStepHandler(handler);
58            integ.integrate(pb,
59                            pb.getInitialTime(), pb.getInitialState(),
60                            pb.getFinalTime(), new double[pb.getDimension()]);
61  
62      }
63  
64      @Test
65      public void testIncreasingTolerance()
66          throws DerivativeException, IntegratorException {
67  
68          int previousCalls = Integer.MAX_VALUE;
69          for (int i = -12; i < -2; ++i) {
70              TestProblem1 pb = new TestProblem1();
71              double minStep = 0;
72              double maxStep = pb.getFinalTime() - pb.getInitialTime();
73              double scalAbsoluteTolerance = Math.pow(10.0, i);
74              double scalRelativeTolerance = 0.01 * scalAbsoluteTolerance;
75  
76              FirstOrderIntegrator integ = new AdamsMoultonIntegrator(4, minStep, maxStep,
77                                                                      scalAbsoluteTolerance,
78                                                                      scalRelativeTolerance);
79              TestProblemHandler handler = new TestProblemHandler(pb, integ);
80              integ.addStepHandler(handler);
81              integ.integrate(pb,
82                              pb.getInitialTime(), pb.getInitialState(),
83                              pb.getFinalTime(), new double[pb.getDimension()]);
84  
85              // the 0.15 and 3.0 factors are only valid for this test
86              // and has been obtained from trial and error
87              // there is no general relation between local and global errors
88              assertTrue(handler.getMaximalValueError() > (0.15 * scalAbsoluteTolerance));
89              assertTrue(handler.getMaximalValueError() < (3.0 * scalAbsoluteTolerance));
90              assertEquals(0, handler.getMaximalTimeError(), 1.0e-16);
91  
92              int calls = pb.getCalls();
93              assertEquals(integ.getEvaluations(), calls);
94              assertTrue(calls <= previousCalls);
95              previousCalls = calls;
96  
97          }
98  
99      }
100 
101     @Test(expected = DerivativeException.class)
102     public void exceedMaxEvaluations() throws DerivativeException, IntegratorException {
103 
104         TestProblem1 pb  = new TestProblem1();
105         double range = pb.getFinalTime() - pb.getInitialTime();
106 
107         AdamsMoultonIntegrator integ = new AdamsMoultonIntegrator(2, 0, range, 1.0e-12, 1.0e-12);
108         TestProblemHandler handler = new TestProblemHandler(pb, integ);
109         integ.addStepHandler(handler);
110         integ.setMaxEvaluations(650);
111         integ.integrate(pb,
112                         pb.getInitialTime(), pb.getInitialState(),
113                         pb.getFinalTime(), new double[pb.getDimension()]);
114 
115     }
116 
117     @Test
118     public void backward() throws DerivativeException, IntegratorException {
119 
120         TestProblem5 pb = new TestProblem5();
121         double range = Math.abs(pb.getFinalTime() - pb.getInitialTime());
122 
123         FirstOrderIntegrator integ = new AdamsMoultonIntegrator(4, 0, range, 1.0e-12, 1.0e-12);
124         TestProblemHandler handler = new TestProblemHandler(pb, integ);
125         integ.addStepHandler(handler);
126         integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
127                         pb.getFinalTime(), new double[pb.getDimension()]);
128 
129         assertTrue(handler.getLastError() < 1.0e-9);
130         assertTrue(handler.getMaximalValueError() < 1.0e-9);
131         assertEquals(0, handler.getMaximalTimeError(), 1.0e-16);
132         assertEquals("Adams-Moulton", integ.getName());
133     }
134 
135     @Test
136     public void polynomial() throws DerivativeException, IntegratorException {
137         TestProblem6 pb = new TestProblem6();
138         double range = Math.abs(pb.getFinalTime() - pb.getInitialTime());
139 
140         for (int nSteps = 1; nSteps < 7; ++nSteps) {
141             AdamsMoultonIntegrator integ =
142                 new AdamsMoultonIntegrator(nSteps, 1.0e-6 * range, 0.1 * range, 1.0e-9, 1.0e-9);
143             TestProblemHandler handler = new TestProblemHandler(pb, integ);
144             integ.addStepHandler(handler);
145             integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
146                             pb.getFinalTime(), new double[pb.getDimension()]);
147             if (nSteps < 4) {
148                 assertTrue(integ.getEvaluations() > 150);
149             } else {
150                 assertTrue(integ.getEvaluations() < 100);
151             }
152         }
153 
154     }
155 
156 }