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 }