View Javadoc
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.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 GillIntegratorTest {
43  
44    @Test(expected=DimensionMismatchException.class)
45    public void testDimensionCheck()
46        throws DimensionMismatchException, NumberIsTooSmallException,
47               MaxCountExceededException, NoBracketingException {
48        TestProblem1 pb = new TestProblem1();
49        new GillIntegrator(0.01).integrate(pb,
50                                           0.0, new double[pb.getDimension()+10],
51                                           1.0, new double[pb.getDimension()+10]);
52          Assert.fail("an exception should have been thrown");
53    }
54  
55    @Test
56    public void testDecreasingSteps()
57        throws DimensionMismatchException, NumberIsTooSmallException,
58               MaxCountExceededException, NoBracketingException {
59  
60        for (TestProblemAbstract pb : new TestProblemAbstract[] {
61            new TestProblem1(), new TestProblem2(), new TestProblem3(),
62            new TestProblem4(), new TestProblem5(), new TestProblem6()
63        }) {
64  
65        double previousValueError = Double.NaN;
66        double previousTimeError = Double.NaN;
67        for (int i = 5; i < 10; ++i) {
68  
69          double step = (pb.getFinalTime() - pb.getInitialTime()) * JdkMath.pow(2.0, -i);
70  
71          FirstOrderIntegrator integ = new GillIntegrator(step);
72          TestProblemHandler handler = new TestProblemHandler(pb, integ);
73          integ.addStepHandler(handler);
74          EventHandler[] functions = pb.getEventsHandlers();
75          for (int l = 0; l < functions.length; ++l) {
76            integ.addEventHandler(functions[l],
77                                       Double.POSITIVE_INFINITY, 1.0e-6 * step, 1000);
78          }
79          double stopTime = integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
80                                            pb.getFinalTime(), new double[pb.getDimension()]);
81          if (functions.length == 0) {
82              Assert.assertEquals(pb.getFinalTime(), stopTime, 1.0e-10);
83          }
84  
85          double valueError = handler.getMaximalValueError();
86          if (i > 5) {
87            Assert.assertTrue(valueError < 1.01 * JdkMath.abs(previousValueError));
88          }
89          previousValueError = valueError;
90  
91          double timeError = handler.getMaximalTimeError();
92          if (i > 5) {
93            Assert.assertTrue(timeError <= JdkMath.abs(previousTimeError));
94          }
95          previousTimeError = timeError;
96        }
97      }
98    }
99  
100   @Test
101   public void testSmallStep()
102       throws DimensionMismatchException, NumberIsTooSmallException,
103              MaxCountExceededException, NoBracketingException {
104 
105     TestProblem1 pb = new TestProblem1();
106     double step = (pb.getFinalTime() - pb.getInitialTime()) * 0.001;
107 
108     FirstOrderIntegrator integ = new GillIntegrator(step);
109     TestProblemHandler handler = new TestProblemHandler(pb, integ);
110     integ.addStepHandler(handler);
111     integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
112                     pb.getFinalTime(), new double[pb.getDimension()]);
113 
114     Assert.assertTrue(handler.getLastError() < 2.0e-13);
115     Assert.assertTrue(handler.getMaximalValueError() < 4.0e-12);
116     Assert.assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
117     Assert.assertEquals("Gill", integ.getName());
118   }
119 
120   @Test
121   public void testBigStep()
122       throws DimensionMismatchException, NumberIsTooSmallException,
123              MaxCountExceededException, NoBracketingException {
124 
125     TestProblem1 pb = new TestProblem1();
126     double step = (pb.getFinalTime() - pb.getInitialTime()) * 0.2;
127 
128     FirstOrderIntegrator integ = new GillIntegrator(step);
129     TestProblemHandler handler = new TestProblemHandler(pb, integ);
130     integ.addStepHandler(handler);
131     integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
132                     pb.getFinalTime(), new double[pb.getDimension()]);
133 
134     Assert.assertTrue(handler.getLastError() > 0.0004);
135     Assert.assertTrue(handler.getMaximalValueError() > 0.005);
136     Assert.assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
137   }
138 
139   @Test
140   public void testBackward()
141       throws DimensionMismatchException, NumberIsTooSmallException,
142              MaxCountExceededException, NoBracketingException {
143 
144       TestProblem5 pb = new TestProblem5();
145       double step = JdkMath.abs(pb.getFinalTime() - pb.getInitialTime()) * 0.001;
146 
147       FirstOrderIntegrator integ = new GillIntegrator(step);
148       TestProblemHandler handler = new TestProblemHandler(pb, integ);
149       integ.addStepHandler(handler);
150       integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
151                       pb.getFinalTime(), new double[pb.getDimension()]);
152 
153       Assert.assertTrue(handler.getLastError() < 5.0e-10);
154       Assert.assertTrue(handler.getMaximalValueError() < 7.0e-10);
155       Assert.assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
156       Assert.assertEquals("Gill", integ.getName());
157   }
158 
159   @Test
160   public void testKepler()
161       throws DimensionMismatchException, NumberIsTooSmallException,
162              MaxCountExceededException, NoBracketingException {
163 
164     final TestProblem3 pb  = new TestProblem3(0.9);
165     double step = (pb.getFinalTime() - pb.getInitialTime()) * 0.0003;
166 
167     FirstOrderIntegrator integ = new GillIntegrator(step);
168     integ.addStepHandler(new KeplerStepHandler(pb));
169     integ.integrate(pb,
170                     pb.getInitialTime(), pb.getInitialState(),
171                     pb.getFinalTime(), new double[pb.getDimension()]);
172   }
173 
174   @Test
175   public void testUnstableDerivative()
176       throws DimensionMismatchException, NumberIsTooSmallException,
177              MaxCountExceededException, NoBracketingException {
178     final StepProblem stepProblem = new StepProblem(0.0, 1.0, 2.0);
179     FirstOrderIntegrator integ = new GillIntegrator(0.3);
180     integ.addEventHandler(stepProblem, 1.0, 1.0e-12, 1000);
181     double[] y = { Double.NaN };
182     integ.integrate(stepProblem, 0.0, new double[] { 0.0 }, 10.0, y);
183     Assert.assertEquals(8.0, y[0], 1.0e-12);
184   }
185 
186   private static final class KeplerStepHandler implements StepHandler {
187     KeplerStepHandler(TestProblem3 pb) {
188       this.pb = pb;
189     }
190     @Override
191     public void init(double t0, double[] y0, double t) {
192       maxError = 0;
193     }
194     @Override
195     public void handleStep(StepInterpolator interpolator, boolean isLast)
196         throws MaxCountExceededException {
197 
198       double[] interpolatedY = interpolator.getInterpolatedState();
199       double[] theoreticalY  = pb.computeTheoreticalState(interpolator.getCurrentTime());
200       double dx = interpolatedY[0] - theoreticalY[0];
201       double dy = interpolatedY[1] - theoreticalY[1];
202       double error = dx * dx + dy * dy;
203       if (error > maxError) {
204         maxError = error;
205       }
206       if (isLast) {
207         // even with more than 1000 evaluations per period,
208         // Gill is not able to integrate such an eccentric
209         // orbit with a good accuracy
210         Assert.assertTrue(maxError > 0.001);
211       }
212     }
213     private double maxError;
214     private TestProblem3 pb;
215   }
216 
217   @Test
218   public void testStepSize()
219       throws DimensionMismatchException, NumberIsTooSmallException,
220              MaxCountExceededException, NoBracketingException {
221       final double step = 1.23456;
222       FirstOrderIntegrator integ = new GillIntegrator(step);
223       integ.addStepHandler(new StepHandler() {
224           @Override
225         public void handleStep(StepInterpolator interpolator, boolean isLast) {
226               if (! isLast) {
227                   Assert.assertEquals(step,
228                                interpolator.getCurrentTime() - interpolator.getPreviousTime(),
229                                1.0e-12);
230               }
231           }
232           @Override
233         public void init(double t0, double[] y0, double t) {
234           }
235       });
236       integ.integrate(new FirstOrderDifferentialEquations() {
237           @Override
238         public void computeDerivatives(double t, double[] y, double[] dot) {
239               dot[0] = 1.0;
240           }
241           @Override
242         public int getDimension() {
243               return 1;
244           }
245       }, 0.0, new double[] { 0.0 }, 5.0, new double[1]);
246   }
247 }