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