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 }