summaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizer.java')
-rw-r--r--src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizer.java300
1 files changed, 300 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizer.java b/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizer.java
new file mode 100644
index 0000000..307c0d9
--- /dev/null
+++ b/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizer.java
@@ -0,0 +1,300 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math3.ode.sampling;
+
+import org.apache.commons.math3.exception.MaxCountExceededException;
+import org.apache.commons.math3.util.FastMath;
+import org.apache.commons.math3.util.Precision;
+
+/**
+ * This class wraps an object implementing {@link FixedStepHandler}
+ * into a {@link StepHandler}.
+
+ * <p>This wrapper allows to use fixed step handlers with general
+ * integrators which cannot guaranty their integration steps will
+ * remain constant and therefore only accept general step
+ * handlers.</p>
+ *
+ * <p>The stepsize used is selected at construction time. The {@link
+ * FixedStepHandler#handleStep handleStep} method of the underlying
+ * {@link FixedStepHandler} object is called at normalized times. The
+ * normalized times can be influenced by the {@link StepNormalizerMode} and
+ * {@link StepNormalizerBounds}.</p>
+ *
+ * <p>There is no constraint on the integrator, it can use any time step
+ * it needs (time steps longer or shorter than the fixed time step and
+ * non-integer ratios are all allowed).</p>
+ *
+ * <p>
+ * <table border="1" align="center">
+ * <tr BGCOLOR="#CCCCFF"><td colspan=6><font size="+2">Examples (step size = 0.5)</font></td></tr>
+ * <tr BGCOLOR="#EEEEFF"><font size="+1"><td>Start time</td><td>End time</td>
+ * <td>Direction</td><td>{@link StepNormalizerMode Mode}</td>
+ * <td>{@link StepNormalizerBounds Bounds}</td><td>Output</td></font></tr>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * <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>
+ * </table>
+ * </p>
+ *
+ * @see StepHandler
+ * @see FixedStepHandler
+ * @see StepNormalizerMode
+ * @see StepNormalizerBounds
+ * @since 1.2
+ */
+
+public class StepNormalizer implements StepHandler {
+ /** Fixed time step. */
+ private double h;
+
+ /** Underlying step handler. */
+ private final FixedStepHandler handler;
+
+ /** First step time. */
+ private double firstTime;
+
+ /** Last step time. */
+ private double lastTime;
+
+ /** Last state vector. */
+ private double[] lastState;
+
+ /** Last derivatives vector. */
+ private double[] lastDerivatives;
+
+ /** Integration direction indicator. */
+ private boolean forward;
+
+ /** The step normalizer bounds settings to use. */
+ private final StepNormalizerBounds bounds;
+
+ /** The step normalizer mode to use. */
+ private final StepNormalizerMode mode;
+
+ /** Simple constructor. Uses {@link StepNormalizerMode#INCREMENT INCREMENT}
+ * mode, and {@link StepNormalizerBounds#FIRST FIRST} bounds setting, for
+ * backwards compatibility.
+ * @param h fixed time step (sign is not used)
+ * @param handler fixed time step handler to wrap
+ */
+ public StepNormalizer(final double h, final FixedStepHandler handler) {
+ this(h, handler, StepNormalizerMode.INCREMENT,
+ StepNormalizerBounds.FIRST);
+ }
+
+ /** Simple constructor. Uses {@link StepNormalizerBounds#FIRST FIRST}
+ * bounds setting.
+ * @param h fixed time step (sign is not used)
+ * @param handler fixed time step handler to wrap
+ * @param mode step normalizer mode to use
+ * @since 3.0
+ */
+ public StepNormalizer(final double h, final FixedStepHandler handler,
+ final StepNormalizerMode mode) {
+ this(h, handler, mode, StepNormalizerBounds.FIRST);
+ }
+
+ /** Simple constructor. Uses {@link StepNormalizerMode#INCREMENT INCREMENT}
+ * mode.
+ * @param h fixed time step (sign is not used)
+ * @param handler fixed time step handler to wrap
+ * @param bounds step normalizer bounds setting to use
+ * @since 3.0
+ */
+ public StepNormalizer(final double h, final FixedStepHandler handler,
+ final StepNormalizerBounds bounds) {
+ this(h, handler, StepNormalizerMode.INCREMENT, bounds);
+ }
+
+ /** Simple constructor.
+ * @param h fixed time step (sign is not used)
+ * @param handler fixed time step handler to wrap
+ * @param mode step normalizer mode to use
+ * @param bounds step normalizer bounds setting to use
+ * @since 3.0
+ */
+ public StepNormalizer(final double h, final FixedStepHandler handler,
+ final StepNormalizerMode mode,
+ final StepNormalizerBounds bounds) {
+ this.h = FastMath.abs(h);
+ this.handler = handler;
+ this.mode = mode;
+ this.bounds = bounds;
+ firstTime = Double.NaN;
+ lastTime = Double.NaN;
+ lastState = null;
+ lastDerivatives = null;
+ forward = true;
+ }
+
+ /** {@inheritDoc} */
+ public void init(double t0, double[] y0, double t) {
+
+ firstTime = Double.NaN;
+ lastTime = Double.NaN;
+ lastState = null;
+ lastDerivatives = null;
+ forward = true;
+
+ // initialize the underlying handler
+ handler.init(t0, y0, t);
+
+ }
+
+ /**
+ * Handle the last accepted step
+ * @param interpolator interpolator for the last accepted step. For
+ * efficiency purposes, the various integrators reuse the same
+ * object on each call, so if the instance wants to keep it across
+ * all calls (for example to provide at the end of the integration a
+ * continuous model valid throughout the integration range), it
+ * should build a local copy using the clone method and store this
+ * copy.
+ * @param isLast true if the step is the last one
+ * @exception MaxCountExceededException if the interpolator throws one because
+ * the number of functions evaluations is exceeded
+ */
+ public void handleStep(final StepInterpolator interpolator, final boolean isLast)
+ throws MaxCountExceededException {
+ // The first time, update the last state with the start information.
+ if (lastState == null) {
+ firstTime = interpolator.getPreviousTime();
+ lastTime = interpolator.getPreviousTime();
+ interpolator.setInterpolatedTime(lastTime);
+ lastState = interpolator.getInterpolatedState().clone();
+ lastDerivatives = interpolator.getInterpolatedDerivatives().clone();
+
+ // Take the integration direction into account.
+ forward = interpolator.getCurrentTime() >= lastTime;
+ if (!forward) {
+ h = -h;
+ }
+ }
+
+ // Calculate next normalized step time.
+ double nextTime = (mode == StepNormalizerMode.INCREMENT) ?
+ lastTime + h :
+ (FastMath.floor(lastTime / h) + 1) * h;
+ if (mode == StepNormalizerMode.MULTIPLES &&
+ Precision.equals(nextTime, lastTime, 1)) {
+ nextTime += h;
+ }
+
+ // Process normalized steps as long as they are in the current step.
+ boolean nextInStep = isNextInStep(nextTime, interpolator);
+ while (nextInStep) {
+ // Output the stored previous step.
+ doNormalizedStep(false);
+
+ // Store the next step as last step.
+ storeStep(interpolator, nextTime);
+
+ // Move on to the next step.
+ nextTime += h;
+ nextInStep = isNextInStep(nextTime, interpolator);
+ }
+
+ if (isLast) {
+ // There will be no more steps. The stored one should be given to
+ // the handler. We may have to output one more step. Only the last
+ // one of those should be flagged as being the last.
+ boolean addLast = bounds.lastIncluded() &&
+ lastTime != interpolator.getCurrentTime();
+ doNormalizedStep(!addLast);
+ if (addLast) {
+ storeStep(interpolator, interpolator.getCurrentTime());
+ doNormalizedStep(true);
+ }
+ }
+ }
+
+ /**
+ * Returns a value indicating whether the next normalized time is in the
+ * current step.
+ * @param nextTime the next normalized time
+ * @param interpolator interpolator for the last accepted step, to use to
+ * get the end time of the current step
+ * @return value indicating whether the next normalized time is in the
+ * current step
+ */
+ private boolean isNextInStep(double nextTime,
+ StepInterpolator interpolator) {
+ return forward ?
+ nextTime <= interpolator.getCurrentTime() :
+ nextTime >= interpolator.getCurrentTime();
+ }
+
+ /**
+ * Invokes the underlying step handler for the current normalized step.
+ * @param isLast true if the step is the last one
+ */
+ private void doNormalizedStep(boolean isLast) {
+ if (!bounds.firstIncluded() && firstTime == lastTime) {
+ return;
+ }
+ handler.handleStep(lastTime, lastState, lastDerivatives, isLast);
+ }
+
+ /** Stores the interpolated information for the given time in the current
+ * state.
+ * @param interpolator interpolator for the last accepted step, to use to
+ * get the interpolated information
+ * @param t the time for which to store the interpolated information
+ * @exception MaxCountExceededException if the interpolator throws one because
+ * the number of functions evaluations is exceeded
+ */
+ private void storeStep(StepInterpolator interpolator, double t)
+ throws MaxCountExceededException {
+ lastTime = t;
+ interpolator.setInterpolatedTime(lastTime);
+ System.arraycopy(interpolator.getInterpolatedState(), 0,
+ lastState, 0, lastState.length);
+ System.arraycopy(interpolator.getInterpolatedDerivatives(), 0,
+ lastDerivatives, 0, lastDerivatives.length);
+ }
+}