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