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.ODEStateAndDerivative;
26  import org.hipparchus.util.FastMath;
27  import org.hipparchus.util.Precision;
28  
29  /**
30   * This class wraps an object implementing {@link ODEFixedStepHandler}
31   * into a {@link ODEStepHandler}.
32  
33   * <p>This wrapper allows to use fixed step handlers with general
34   * integrators which cannot guaranty their integration steps will
35   * remain constant and therefore only accept general step
36   * handlers.</p>
37   *
38   * <p>The stepsize used is selected at construction time. The {@link
39   * ODEFixedStepHandler#handleStep handleStep} method of the underlying
40   * {@link ODEFixedStepHandler} object is called at normalized times. The
41   * normalized times can be influenced by the {@link StepNormalizerMode} and
42   * {@link StepNormalizerBounds}.</p>
43   *
44   * <p>There is no constraint on the integrator, it can use any time step
45   * it needs (time steps longer or shorter than the fixed time step and
46   * non-integer ratios are all allowed).</p>
47   *
48   * <table border="">
49   * <caption>Examples (step size = 0.5)</caption>
50   * <tr ><td>Start time</td><td>End time</td>
51   *  <td>Direction</td><td>{@link StepNormalizerMode Mode}</td>
52   *  <td>{@link StepNormalizerBounds Bounds}</td><td>Output</td></tr>
53   * <tr><td>0.3</td><td>3.1</td><td>forward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#NEITHER NEITHER}</td><td>0.8, 1.3, 1.8, 2.3, 2.8</td></tr>
54   * <tr><td>0.3</td><td>3.1</td><td>forward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#FIRST FIRST}</td><td>0.3, 0.8, 1.3, 1.8, 2.3, 2.8</td></tr>
55   * <tr><td>0.3</td><td>3.1</td><td>forward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#LAST LAST}</td><td>0.8, 1.3, 1.8, 2.3, 2.8, 3.1</td></tr>
56   * <tr><td>0.3</td><td>3.1</td><td>forward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#BOTH BOTH}</td><td>0.3, 0.8, 1.3, 1.8, 2.3, 2.8, 3.1</td></tr>
57   * <tr><td>0.3</td><td>3.1</td><td>forward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#NEITHER NEITHER}</td><td>0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
58   * <tr><td>0.3</td><td>3.1</td><td>forward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#FIRST FIRST}</td><td>0.3, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
59   * <tr><td>0.3</td><td>3.1</td><td>forward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#LAST LAST}</td><td>0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.1</td></tr>
60   * <tr><td>0.3</td><td>3.1</td><td>forward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#BOTH BOTH}</td><td>0.3, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.1</td></tr>
61   * <tr><td>0.0</td><td>3.0</td><td>forward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#NEITHER NEITHER}</td><td>0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
62   * <tr><td>0.0</td><td>3.0</td><td>forward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#FIRST FIRST}</td><td>0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
63   * <tr><td>0.0</td><td>3.0</td><td>forward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#LAST LAST}</td><td>0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
64   * <tr><td>0.0</td><td>3.0</td><td>forward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#BOTH BOTH}</td><td>0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
65   * <tr><td>0.0</td><td>3.0</td><td>forward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#NEITHER NEITHER}</td><td>0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
66   * <tr><td>0.0</td><td>3.0</td><td>forward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#FIRST FIRST}</td><td>0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
67   * <tr><td>0.0</td><td>3.0</td><td>forward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#LAST LAST}</td><td>0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
68   * <tr><td>0.0</td><td>3.0</td><td>forward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#BOTH BOTH}</td><td>0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0</td></tr>
69   * <tr><td>3.1</td><td>0.3</td><td>backward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#NEITHER NEITHER}</td><td>2.6, 2.1, 1.6, 1.1, 0.6</td></tr>
70   * <tr><td>3.1</td><td>0.3</td><td>backward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#FIRST FIRST}</td><td>3.1, 2.6, 2.1, 1.6, 1.1, 0.6</td></tr>
71   * <tr><td>3.1</td><td>0.3</td><td>backward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#LAST LAST}</td><td>2.6, 2.1, 1.6, 1.1, 0.6, 0.3</td></tr>
72   * <tr><td>3.1</td><td>0.3</td><td>backward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#BOTH BOTH}</td><td>3.1, 2.6, 2.1, 1.6, 1.1, 0.6, 0.3</td></tr>
73   * <tr><td>3.1</td><td>0.3</td><td>backward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#NEITHER NEITHER}</td><td>3.0, 2.5, 2.0, 1.5, 1.0, 0.5</td></tr>
74   * <tr><td>3.1</td><td>0.3</td><td>backward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#FIRST FIRST}</td><td>3.1, 3.0, 2.5, 2.0, 1.5, 1.0, 0.5</td></tr>
75   * <tr><td>3.1</td><td>0.3</td><td>backward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#LAST LAST}</td><td>3.0, 2.5, 2.0, 1.5, 1.0, 0.5, 0.3</td></tr>
76   * <tr><td>3.1</td><td>0.3</td><td>backward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#BOTH BOTH}</td><td>3.1, 3.0, 2.5, 2.0, 1.5, 1.0, 0.5, 0.3</td></tr>
77   * <tr><td>3.0</td><td>0.0</td><td>backward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#NEITHER NEITHER}</td><td>2.5, 2.0, 1.5, 1.0, 0.5, 0.0</td></tr>
78   * <tr><td>3.0</td><td>0.0</td><td>backward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#FIRST FIRST}</td><td>3.0, 2.5, 2.0, 1.5, 1.0, 0.5, 0.0</td></tr>
79   * <tr><td>3.0</td><td>0.0</td><td>backward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#LAST LAST}</td><td>2.5, 2.0, 1.5, 1.0, 0.5, 0.0</td></tr>
80   * <tr><td>3.0</td><td>0.0</td><td>backward</td><td>{@link StepNormalizerMode#INCREMENT INCREMENT}</td><td>{@link StepNormalizerBounds#BOTH BOTH}</td><td>3.0, 2.5, 2.0, 1.5, 1.0, 0.5, 0.0</td></tr>
81   * <tr><td>3.0</td><td>0.0</td><td>backward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#NEITHER NEITHER}</td><td>2.5, 2.0, 1.5, 1.0, 0.5, 0.0</td></tr>
82   * <tr><td>3.0</td><td>0.0</td><td>backward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#FIRST FIRST}</td><td>3.0, 2.5, 2.0, 1.5, 1.0, 0.5, 0.0</td></tr>
83   * <tr><td>3.0</td><td>0.0</td><td>backward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#LAST LAST}</td><td>2.5, 2.0, 1.5, 1.0, 0.5, 0.0</td></tr>
84   * <tr><td>3.0</td><td>0.0</td><td>backward</td><td>{@link StepNormalizerMode#MULTIPLES MULTIPLES}</td><td>{@link StepNormalizerBounds#BOTH BOTH}</td><td>3.0, 2.5, 2.0, 1.5, 1.0, 0.5, 0.0</td></tr>
85   * </table>
86   *
87   * @see ODEStepHandler
88   * @see ODEFixedStepHandler
89   * @see StepNormalizerMode
90   * @see StepNormalizerBounds
91   */
92  
93  public class StepNormalizer implements ODEStepHandler {
94  
95      /** Fixed time step. */
96      private double h;
97  
98      /** Underlying step handler. */
99      private final ODEFixedStepHandler handler;
100 
101     /** First step state. */
102     private ODEStateAndDerivative first;
103 
104     /** Last step step. */
105     private ODEStateAndDerivative last;
106 
107     /** Integration direction indicator. */
108     private boolean forward;
109 
110     /** The step normalizer bounds settings to use. */
111     private final StepNormalizerBounds bounds;
112 
113     /** The step normalizer mode to use. */
114     private final StepNormalizerMode mode;
115 
116     /** Simple constructor. Uses {@link StepNormalizerMode#INCREMENT INCREMENT}
117      * mode, and {@link StepNormalizerBounds#FIRST FIRST} bounds setting, for
118      * backwards compatibility.
119      * @param h fixed time step (sign is not used)
120      * @param handler fixed time step handler to wrap
121      */
122     public StepNormalizer(final double h, final ODEFixedStepHandler handler) {
123         this(h, handler, StepNormalizerMode.INCREMENT,
124              StepNormalizerBounds.FIRST);
125     }
126 
127     /** Simple constructor. Uses {@link StepNormalizerBounds#FIRST FIRST}
128      * bounds setting.
129      * @param h fixed time step (sign is not used)
130      * @param handler fixed time step handler to wrap
131      * @param mode step normalizer mode to use
132      */
133     public StepNormalizer(final double h, final ODEFixedStepHandler handler,
134                           final StepNormalizerMode mode) {
135         this(h, handler, mode, StepNormalizerBounds.FIRST);
136     }
137 
138     /** Simple constructor. Uses {@link StepNormalizerMode#INCREMENT INCREMENT}
139      * mode.
140      * @param h fixed time step (sign is not used)
141      * @param handler fixed time step handler to wrap
142      * @param bounds step normalizer bounds setting to use
143      */
144     public StepNormalizer(final double h, final ODEFixedStepHandler handler,
145                           final StepNormalizerBounds bounds) {
146         this(h, handler, StepNormalizerMode.INCREMENT, bounds);
147     }
148 
149     /** Simple constructor.
150      * @param h fixed time step (sign is not used)
151      * @param handler fixed time step handler to wrap
152      * @param mode step normalizer mode to use
153      * @param bounds step normalizer bounds setting to use
154      */
155     public StepNormalizer(final double h, final ODEFixedStepHandler handler,
156                           final StepNormalizerMode mode,
157                           final StepNormalizerBounds bounds) {
158         this.h          = FastMath.abs(h);
159         this.handler    = handler;
160         this.mode       = mode;
161         this.bounds     = bounds;
162         first           = null;
163         last            = null;
164         forward         = true;
165     }
166 
167     /** {@inheritDoc} */
168     @Override
169     public void init(final ODEStateAndDerivative initialState, final double finalTime) {
170 
171         first           = null;
172         last            = null;
173         forward         = true;
174 
175         // initialize the underlying handler
176         handler.init(initialState, finalTime);
177 
178     }
179 
180     /** {@inheritDoc} */
181     @Override
182     public void handleStep(final ODEStateInterpolator interpolator) {
183         // The first time, update the last state with the start information.
184         if (last == null) {
185 
186             first   = interpolator.getPreviousState();
187             last    = first;
188 
189             // Take the integration direction into account.
190             forward = interpolator.isForward();
191             if (!forward) {
192                 h = -h;
193             }
194         }
195 
196         // Calculate next normalized step time.
197         double nextTime = (mode == StepNormalizerMode.INCREMENT) ?
198                           last.getTime() + h :
199                           (FastMath.floor(last.getTime() / h) + 1) * h;
200         if (mode == StepNormalizerMode.MULTIPLES &&
201             Precision.equals(nextTime, last.getTime(), 1)) {
202             nextTime += h;
203         }
204 
205         // Process normalized steps as long as they are in the current step.
206         boolean nextInStep = isNextInStep(nextTime, interpolator);
207         while (nextInStep) {
208             // Output the stored previous step.
209             doNormalizedStep(false);
210 
211             // Store the next step as last step.
212             last = interpolator.getInterpolatedState(nextTime);
213 
214             // Move on to the next step.
215             nextTime += h;
216             nextInStep = isNextInStep(nextTime, interpolator);
217         }
218     }
219 
220     /** {@inheritDoc} */
221     @Override
222     public void finish(ODEStateAndDerivative finalState) {
223             // There will be no more steps. The stored one should be given to
224             // the handler. We may have to output one more step. Only the last
225             // one of those should be flagged as being the last.
226             boolean addLast = bounds.lastIncluded() &&
227                               last.getTime() != finalState.getTime();
228             doNormalizedStep(!addLast);
229             if (addLast) {
230                 last = finalState;
231                 doNormalizedStep(true);
232             }
233     }
234 
235     /**
236      * Returns a value indicating whether the next normalized time is in the
237      * current step.
238      * @param nextTime the next normalized time
239      * @param interpolator interpolator for the last accepted step, to use to
240      * get the end time of the current step
241      * @return value indicating whether the next normalized time is in the
242      * current step
243      */
244     private boolean isNextInStep(double nextTime,
245                                  ODEStateInterpolator interpolator) {
246         return forward ?
247                nextTime <= interpolator.getCurrentState().getTime() :
248                nextTime >= interpolator.getCurrentState().getTime();
249     }
250 
251     /**
252      * Invokes the underlying step handler for the current normalized step.
253      * @param isLast true if the step is the last one
254      */
255     private void doNormalizedStep(boolean isLast) {
256         if (!bounds.firstIncluded() && first.getTime() == last.getTime()) {
257             return;
258         }
259         handler.handleStep(last, isLast);
260     }
261 
262 }