001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.math.ode.sampling;
019
020 import org.apache.commons.math.ode.DerivativeException;
021
022 /**
023 * This class wraps an object implementing {@link FixedStepHandler}
024 * into a {@link StepHandler}.
025
026 * <p>This wrapper allows to use fixed step handlers with general
027 * integrators which cannot guaranty their integration steps will
028 * remain constant and therefore only accept general step
029 * handlers.</p>
030 *
031 * <p>The stepsize used is selected at construction time. The {@link
032 * FixedStepHandler#handleStep handleStep} method of the underlying
033 * {@link FixedStepHandler} object is called at the beginning time of
034 * the integration t0 and also at times t0+h, t0+2h, ... If the
035 * integration range is an integer multiple of the stepsize, then the
036 * last point handled will be the endpoint of the integration tend, if
037 * not, the last point will belong to the interval [tend - h ;
038 * tend].</p>
039 *
040 * <p>There is no constraint on the integrator, it can use any
041 * timestep it needs (time steps longer or shorter than the fixed time
042 * step and non-integer ratios are all allowed).</p>
043 *
044 * @see StepHandler
045 * @see FixedStepHandler
046 * @version $Revision: 811833 $ $Date: 2009-09-06 12:27:50 -0400 (Sun, 06 Sep 2009) $
047 * @since 1.2
048 */
049
050 public class StepNormalizer implements StepHandler {
051
052 /** Fixed time step. */
053 private double h;
054
055 /** Underlying step handler. */
056 private final FixedStepHandler handler;
057
058 /** Last step time. */
059 private double lastTime;
060
061 /** Last State vector. */
062 private double[] lastState;
063
064 /** Last Derivatives vector. */
065 private double[] lastDerivatives;
066
067 /** Integration direction indicator. */
068 private boolean forward;
069
070 /** Simple constructor.
071 * @param h fixed time step (sign is not used)
072 * @param handler fixed time step handler to wrap
073 */
074 public StepNormalizer(final double h, final FixedStepHandler handler) {
075 this.h = Math.abs(h);
076 this.handler = handler;
077 reset();
078 }
079
080 /** Determines whether this handler needs dense output.
081 * This handler needs dense output in order to provide data at
082 * regularly spaced steps regardless of the steps the integrator
083 * uses, so this method always returns true.
084 * @return always true
085 */
086 public boolean requiresDenseOutput() {
087 return true;
088 }
089
090 /** Reset the step handler.
091 * Initialize the internal data as required before the first step is
092 * handled.
093 */
094 public void reset() {
095 lastTime = Double.NaN;
096 lastState = null;
097 lastDerivatives = null;
098 forward = true;
099 }
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 }