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    *      https://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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.ode.sampling;
24  
25  import org.hipparchus.ode.ODEIntegrator;
26  import org.hipparchus.ode.ODEState;
27  import org.hipparchus.ode.ODEStateAndDerivative;
28  import org.hipparchus.ode.OrdinaryDifferentialEquation;
29  import org.hipparchus.ode.TestProblem3;
30  import org.hipparchus.ode.TestProblemAbstract;
31  import org.hipparchus.ode.nonstiff.DormandPrince54Integrator;
32  import org.hipparchus.util.FastMath;
33  import org.junit.jupiter.api.Test;
34  
35  import static org.junit.jupiter.api.Assertions.assertEquals;
36  
37  
38  class StepNormalizerTest {
39  
40      @Test
41      void testBoundariesDefault() {
42          final TestProblemAbstract pb = new TestProblem3();
43          final double range = pb.getFinalTime() - pb.getInitialTime();
44          final double stepSize = range / 5.5;
45          doTestBoundaries(pb, null, stepSize,
46                           pb.getInitialTime(),
47                           pb.getInitialTime() + FastMath.floor(range / stepSize) * stepSize);
48      }
49  
50      @Test
51      void testBoundariesNeither() {
52          final TestProblemAbstract pb = new TestProblem3();
53          final double range = pb.getFinalTime() - pb.getInitialTime();
54          final double stepSize = range / 5.5;
55          doTestBoundaries(pb, StepNormalizerBounds.NEITHER, stepSize,
56                           pb.getInitialTime() + stepSize,
57                           pb.getInitialTime() + FastMath.floor(range / stepSize) * stepSize);
58      }
59  
60      @Test
61      void testBoundariesFirst() {
62          final TestProblemAbstract pb = new TestProblem3();
63          final double range = pb.getFinalTime() - pb.getInitialTime();
64          final double stepSize = range / 5.5;
65          doTestBoundaries(pb, StepNormalizerBounds.FIRST, stepSize,
66                           pb.getInitialTime(),
67                           pb.getInitialTime() + FastMath.floor(range / stepSize) * stepSize);
68      }
69  
70      @Test
71      void testBoundariesLast() {
72          final TestProblemAbstract pb = new TestProblem3();
73          final double range = pb.getFinalTime() - pb.getInitialTime();
74          final double stepSize = range / 5.5;
75          doTestBoundaries(pb, StepNormalizerBounds.LAST, stepSize,
76                           pb.getInitialTime() + stepSize,
77                           pb.getFinalTime());
78      }
79  
80      @Test
81      void testBoundariesBoth() {
82          final TestProblemAbstract pb = new TestProblem3();
83          final double range = pb.getFinalTime() - pb.getInitialTime();
84          final double stepSize = range / 5.5;
85          doTestBoundaries(pb, StepNormalizerBounds.BOTH, stepSize,
86                           pb.getInitialTime(),
87                           pb.getFinalTime());
88      }
89  
90      @Test
91      void testBeforeEnd() {
92          final TestProblemAbstract pb = new TestProblem3();
93          final double range = pb.getFinalTime() - pb.getInitialTime();
94          final double stepSize = range / 10.5;
95          doTestBoundaries(pb, null, stepSize,
96                           pb.getInitialTime(),
97                           pb.getFinalTime() - range / 21.0);
98      }
99  
100     @Test
101     void testModeForwardMultiples() {
102         doTestStepsAtIntegerTimes(new TestProblem3(), StepNormalizerMode.MULTIPLES,
103                                   2.0, 7.5, 2.5, 7.5, 4.0);
104     }
105 
106     @Test
107     void testModeForwardIncrement() {
108         doTestStepsAtIntegerTimes(new TestProblem3(), StepNormalizerMode.INCREMENT,
109                                   2.0, 7.5, 2.5, 7.5, 3.5);
110     }
111 
112     @Test
113     void testModeBackwardMultiples() {
114         doTestStepsAtIntegerTimes(new TestProblem3(), StepNormalizerMode.MULTIPLES,
115                                   2.0, 2.5, 7.5, 2.5, 6.0);
116     }
117 
118     @Test
119     void testModeBackwardIncrement() {
120         doTestStepsAtIntegerTimes(new TestProblem3(), StepNormalizerMode.INCREMENT,
121                                   2.0, 2.5, 7.5, 2.5, 6.5);
122     }
123 
124     private void doTestBoundaries(final TestProblemAbstract pb,
125                                   final StepNormalizerBounds bounds, final double stepSize,
126                                   final double expectedFirst, final double expectedLast) {
127         double minStep = 0;
128         double maxStep = pb.getFinalTime() - pb.getInitialTime();
129         ODEIntegrator integ = new DormandPrince54Integrator(minStep, maxStep, 10.e-8, 1.0e-8);
130         final Checker checker = new Checker();
131         if (bounds == null) {            
132             integ.addStepHandler(new StepNormalizer(stepSize, checker));
133         } else {
134             integ.addStepHandler(new StepNormalizer(stepSize, checker, bounds));
135         }
136         integ.integrate(pb, pb.getInitialState(), pb.getFinalTime());
137         assertEquals(expectedFirst, checker.firstTime, 1.0e-10);
138         assertEquals(expectedLast,  checker.lastTime,  1.0e-10);
139     }
140 
141     private void doTestStepsAtIntegerTimes(final TestProblemAbstract pb,
142                                            final StepNormalizerMode mode, final double stepSize,
143                                            final double t0, final double t1,
144                                            final double expectedFirst,
145                                            final double expectedLast) {
146         double minStep = 0;
147         double maxStep = pb.getFinalTime() - pb.getInitialTime();
148         ODEIntegrator integ = new DormandPrince54Integrator(minStep, maxStep, 10.e-8, 1.0e-8);
149         final Checker checker = new Checker();
150         integ.addStepHandler(new StepNormalizer(stepSize, checker, mode));
151         integ.integrate(new OrdinaryDifferentialEquation() {
152             public int getDimension() { return 1; }
153             public double[] computeDerivatives(double t, double[] y) { return y; }
154         }, new ODEState(t0, new double[1]), t1);
155         assertEquals(expectedFirst, checker.firstTime, 1.0e-10);
156         assertEquals(expectedLast, checker.lastTime,  1.0e-10);
157     }
158 
159     private static class Checker implements ODEFixedStepHandler {
160 
161         private double firstTime;
162         private double lastTime;
163 
164         public void init(final ODEStateAndDerivative initialState, final double finalTime) {
165             firstTime = Double.NaN;
166             lastTime  = Double.NaN;
167         }
168 
169         public void handleStep(ODEStateAndDerivative s, boolean isLast) {
170             if (Double.isNaN(firstTime)) {
171                 firstTime = s.getTime();
172             }
173             if (isLast) {
174                 lastTime = s.getTime();
175             }
176         }
177 
178     }
179 
180 }