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