001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.math.ode.nonstiff;
019    
020    import junit.framework.*;
021    
022    import org.apache.commons.math.ode.DerivativeException;
023    import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
024    import org.apache.commons.math.ode.FirstOrderIntegrator;
025    import org.apache.commons.math.ode.IntegratorException;
026    import org.apache.commons.math.ode.TestProblem1;
027    import org.apache.commons.math.ode.TestProblem5;
028    import org.apache.commons.math.ode.TestProblemAbstract;
029    import org.apache.commons.math.ode.TestProblemFactory;
030    import org.apache.commons.math.ode.TestProblemHandler;
031    import org.apache.commons.math.ode.events.EventHandler;
032    import org.apache.commons.math.ode.nonstiff.MidpointIntegrator;
033    import org.apache.commons.math.ode.sampling.StepHandler;
034    import org.apache.commons.math.ode.sampling.StepInterpolator;
035    
036    public class MidpointIntegratorTest
037      extends TestCase {
038    
039      public MidpointIntegratorTest(String name) {
040        super(name);
041      }
042    
043      public void testDimensionCheck() {
044        try  {
045          TestProblem1 pb = new TestProblem1();
046          new MidpointIntegrator(0.01).integrate(pb,
047                                                 0.0, new double[pb.getDimension()+10],
048                                                 1.0, new double[pb.getDimension()+10]);
049            fail("an exception should have been thrown");
050        } catch(DerivativeException de) {
051          fail("wrong exception caught");
052        } catch(IntegratorException ie) {
053        }
054      }
055      
056      public void testDecreasingSteps()
057        throws DerivativeException, IntegratorException  {
058          
059        TestProblemAbstract[] problems = TestProblemFactory.getProblems();
060        for (int k = 0; k < problems.length; ++k) {
061    
062          double previousError = Double.NaN;
063          for (int i = 4; i < 10; ++i) {
064    
065            TestProblemAbstract pb = problems[k].copy();
066            double step = (pb.getFinalTime() - pb.getInitialTime())
067              * Math.pow(2.0, -i);
068            FirstOrderIntegrator integ = new MidpointIntegrator(step);
069            TestProblemHandler handler = new TestProblemHandler(pb, integ);
070            integ.addStepHandler(handler);
071            EventHandler[] functions = pb.getEventsHandlers();
072            for (int l = 0; l < functions.length; ++l) {
073              integ.addEventHandler(functions[l],
074                                         Double.POSITIVE_INFINITY, 1.0e-6 * step, 1000);
075            }
076            double stopTime = integ.integrate(pb,
077                                              pb.getInitialTime(), pb.getInitialState(),
078                                              pb.getFinalTime(), new double[pb.getDimension()]);
079            if (functions.length == 0) {
080                assertEquals(pb.getFinalTime(), stopTime, 1.0e-10);
081            }
082    
083            double error = handler.getMaximalValueError();
084            if (i > 4) {
085              assertTrue(error < Math.abs(previousError));
086            }
087            previousError = error;
088            assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
089    
090          }
091    
092        }
093    
094      }
095    
096      public void testSmallStep()
097        throws DerivativeException, IntegratorException {
098    
099        TestProblem1 pb  = new TestProblem1();
100        double step = (pb.getFinalTime() - pb.getInitialTime()) * 0.001;
101    
102        FirstOrderIntegrator integ = new MidpointIntegrator(step);
103        TestProblemHandler handler = new TestProblemHandler(pb, integ);
104        integ.addStepHandler(handler);
105        integ.integrate(pb,
106                        pb.getInitialTime(), pb.getInitialState(),
107                        pb.getFinalTime(), new double[pb.getDimension()]);
108    
109        assertTrue(handler.getLastError() < 2.0e-7);
110        assertTrue(handler.getMaximalValueError() < 1.0e-6);
111        assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
112        assertEquals("midpoint", integ.getName());
113    
114      }
115    
116      public void testBigStep()
117        throws DerivativeException, IntegratorException {
118    
119        TestProblem1 pb  = new TestProblem1();
120        double step = (pb.getFinalTime() - pb.getInitialTime()) * 0.2;
121    
122        FirstOrderIntegrator integ = new MidpointIntegrator(step);
123        TestProblemHandler handler = new TestProblemHandler(pb, integ);
124        integ.addStepHandler(handler);
125        integ.integrate(pb,
126                        pb.getInitialTime(), pb.getInitialState(),
127                        pb.getFinalTime(), new double[pb.getDimension()]);
128    
129        assertTrue(handler.getLastError() > 0.01);
130        assertTrue(handler.getMaximalValueError() > 0.05);
131        assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
132    
133      }
134    
135      public void testBackward()
136          throws DerivativeException, IntegratorException {
137    
138          TestProblem5 pb = new TestProblem5();
139          double step = Math.abs(pb.getFinalTime() - pb.getInitialTime()) * 0.001;
140    
141          FirstOrderIntegrator integ = new MidpointIntegrator(step);
142          TestProblemHandler handler = new TestProblemHandler(pb, integ);
143          integ.addStepHandler(handler);
144          integ.integrate(pb, pb.getInitialTime(), pb.getInitialState(),
145                          pb.getFinalTime(), new double[pb.getDimension()]);
146    
147          assertTrue(handler.getLastError() < 6.0e-4);
148          assertTrue(handler.getMaximalValueError() < 6.0e-4);
149          assertEquals(0, handler.getMaximalTimeError(), 1.0e-12);
150          assertEquals("midpoint", integ.getName());
151      }
152    
153      public void testStepSize()
154        throws DerivativeException, IntegratorException {
155          final double step = 1.23456;
156          FirstOrderIntegrator integ = new MidpointIntegrator(step);
157          integ.addStepHandler(new StepHandler() {
158              public void handleStep(StepInterpolator interpolator, boolean isLast) {
159                  if (! isLast) {
160                      assertEquals(step,
161                                   interpolator.getCurrentTime() - interpolator.getPreviousTime(),
162                                   1.0e-12);
163                  }
164              }
165              public boolean requiresDenseOutput() {
166                  return false;
167              }
168              public void reset() {
169              }          
170          });
171          integ.integrate(new FirstOrderDifferentialEquations() {
172              private static final long serialVersionUID = 0L;
173              public void computeDerivatives(double t, double[] y, double[] dot) {
174                  dot[0] = 1.0;
175              }
176              public int getDimension() {
177                  return 1;
178              }
179          }, 0.0, new double[] { 0.0 }, 5.0, new double[1]);
180      }
181    
182      public static Test suite() {
183        return new TestSuite(MidpointIntegratorTest.class);
184      }
185    
186    }