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 }