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 * http://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 package org.apache.commons.math.ode.sampling; 19 20 import org.apache.commons.math.ode.DerivativeException; 21 import org.apache.commons.math.util.FastMath; 22 23 /** 24 * This class wraps an object implementing {@link FixedStepHandler} 25 * into a {@link StepHandler}. 26 27 * <p>This wrapper allows to use fixed step handlers with general 28 * integrators which cannot guaranty their integration steps will 29 * remain constant and therefore only accept general step 30 * handlers.</p> 31 * 32 * <p>The stepsize used is selected at construction time. The {@link 33 * FixedStepHandler#handleStep handleStep} method of the underlying 34 * {@link FixedStepHandler} object is called at the beginning time of 35 * the integration t0 and also at times t0+h, t0+2h, ... If the 36 * integration range is an integer multiple of the stepsize, then the 37 * last point handled will be the endpoint of the integration tend, if 38 * not, the last point will belong to the interval [tend - h ; 39 * tend].</p> 40 * 41 * <p>There is no constraint on the integrator, it can use any 42 * timestep it needs (time steps longer or shorter than the fixed time 43 * step and non-integer ratios are all allowed).</p> 44 * 45 * @see StepHandler 46 * @see FixedStepHandler 47 * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 fvr. 2011) $ 48 * @since 1.2 49 */ 50 51 public class StepNormalizer implements StepHandler { 52 53 /** Fixed time step. */ 54 private double h; 55 56 /** Underlying step handler. */ 57 private final FixedStepHandler handler; 58 59 /** Last step time. */ 60 private double lastTime; 61 62 /** Last State vector. */ 63 private double[] lastState; 64 65 /** Last Derivatives vector. */ 66 private double[] lastDerivatives; 67 68 /** Integration direction indicator. */ 69 private boolean forward; 70 71 /** Simple constructor. 72 * @param h fixed time step (sign is not used) 73 * @param handler fixed time step handler to wrap 74 */ 75 public StepNormalizer(final double h, final FixedStepHandler handler) { 76 this.h = FastMath.abs(h); 77 this.handler = handler; 78 reset(); 79 } 80 81 /** Determines whether this handler needs dense output. 82 * This handler needs dense output in order to provide data at 83 * regularly spaced steps regardless of the steps the integrator 84 * uses, so this method always returns true. 85 * @return always true 86 */ 87 public boolean requiresDenseOutput() { 88 return true; 89 } 90 91 /** Reset the step handler. 92 * Initialize the internal data as required before the first step is 93 * handled. 94 */ 95 public void reset() { 96 lastTime = Double.NaN; 97 lastState = null; 98 lastDerivatives = null; 99 forward = true; 100 } 101 102 /** 103 * Handle the last accepted step 104 * @param interpolator interpolator for the last accepted step. For 105 * efficiency purposes, the various integrators reuse the same 106 * object on each call, so if the instance wants to keep it across 107 * all calls (for example to provide at the end of the integration a 108 * continuous model valid throughout the integration range), it 109 * should build a local copy using the clone method and store this 110 * copy. 111 * @param isLast true if the step is the last one 112 * @throws DerivativeException this exception is propagated to the 113 * caller if the underlying user function triggers one 114 */ 115 public void handleStep(final StepInterpolator interpolator, final boolean isLast) 116 throws DerivativeException { 117 118 if (lastState == null) { 119 120 lastTime = interpolator.getPreviousTime(); 121 interpolator.setInterpolatedTime(lastTime); 122 lastState = interpolator.getInterpolatedState().clone(); 123 lastDerivatives = interpolator.getInterpolatedDerivatives().clone(); 124 125 // take the integration direction into account 126 forward = interpolator.getCurrentTime() >= lastTime; 127 if (! forward) { 128 h = -h; 129 } 130 131 } 132 133 double nextTime = lastTime + h; 134 boolean nextInStep = forward ^ (nextTime > interpolator.getCurrentTime()); 135 while (nextInStep) { 136 137 // output the stored previous step 138 handler.handleStep(lastTime, lastState, lastDerivatives, false); 139 140 // store the next step 141 lastTime = nextTime; 142 interpolator.setInterpolatedTime(lastTime); 143 System.arraycopy(interpolator.getInterpolatedState(), 0, 144 lastState, 0, lastState.length); 145 System.arraycopy(interpolator.getInterpolatedDerivatives(), 0, 146 lastDerivatives, 0, lastDerivatives.length); 147 148 nextTime += h; 149 nextInStep = forward ^ (nextTime > interpolator.getCurrentTime()); 150 151 } 152 153 if (isLast) { 154 // there will be no more steps, 155 // the stored one should be flagged as being the last 156 handler.handleStep(lastTime, lastState, lastDerivatives, true); 157 } 158 159 } 160 161 } 162