Repository: commons-math Updated Branches: refs/heads/field-ode 4685d0376 -> 5c647c12e
Interfaces and normalizer for step handling. This corresponds to a continuous output feature. It basically allow to navigate throughout current step instead of having only discrete grid points. It is a major feature of our ode package. JIRA: MATH-1288 Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/5c647c12 Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/5c647c12 Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/5c647c12 Branch: refs/heads/field-ode Commit: 5c647c12e6910b27bd8815b07978f9dc51638795 Parents: 4685d03 Author: Luc Maisonobe <l...@apache.org> Authored: Wed Nov 11 21:23:35 2015 +0100 Committer: Luc Maisonobe <l...@apache.org> Committed: Wed Nov 11 21:23:35 2015 +0100 ---------------------------------------------------------------------- .../ode/sampling/FieldFixedStepHandler.java | 69 +++++ .../math3/ode/sampling/FieldStepHandler.java | 75 +++++ .../ode/sampling/FieldStepInterpolator.java | 78 ++++++ .../math3/ode/sampling/FieldStepNormalizer.java | 272 +++++++++++++++++++ .../ode/sampling/StepNormalizerBounds.java | 1 + .../math3/ode/sampling/StepNormalizerMode.java | 1 + 6 files changed, 496 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-math/blob/5c647c12/src/main/java/org/apache/commons/math3/ode/sampling/FieldFixedStepHandler.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/ode/sampling/FieldFixedStepHandler.java b/src/main/java/org/apache/commons/math3/ode/sampling/FieldFixedStepHandler.java new file mode 100644 index 0000000..9d4fd70 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/ode/sampling/FieldFixedStepHandler.java @@ -0,0 +1,69 @@ +/* + * 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.RealFieldElement; +import org.apache.commons.math3.ode.FieldODEStateAndDerivative; + +/** + * This interface represents a handler that should be called after + * each successful fixed step. + + * <p>This interface should be implemented by anyone who is interested + * in getting the solution of an ordinary differential equation at + * fixed time steps. Objects implementing this interface should be + * wrapped within an instance of {@link FieldStepNormalizer} that itself + * is used as the general {@link FieldStepHandler} by the integrator. The + * {@link FieldStepNormalizer} object is called according to the integrator + * internal algorithms and it calls objects implementing this + * interface as necessary at fixed time steps.</p> + * + * @see FieldStepHandler + * @see FieldStepNormalizer + * @see FieldStepInterpolator + * @param <T> the type of the field elements + * @since 3.6 + */ + +public interface FieldFixedStepHandler<T extends RealFieldElement<T>> { + + /** Initialize step handler at the start of an ODE integration. + * <p> + * This method is called once at the start of the integration. It + * may be used by the step handler to initialize some internal data + * if needed. + * </p> + * @param initialState initial time, state vector and derivative + * @param finalTime target time for the integration + */ + void init(FieldODEStateAndDerivative<T> initialState, T finalTime); + + /** + * Handle the last accepted step + * @param state current value of the independent <i>time</i> variable, + * state vector and derivative + * For efficiency purposes, the {@link FieldStepNormalizer} class reuses + * the same array 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 complete array of all + * steps), it should build a local copy store this copy. + * @param isLast true if the step is the last one + */ + void handleStep(FieldODEStateAndDerivative<T> state, boolean isLast); + +} http://git-wip-us.apache.org/repos/asf/commons-math/blob/5c647c12/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepHandler.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepHandler.java b/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepHandler.java new file mode 100644 index 0000000..f46cc06 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepHandler.java @@ -0,0 +1,75 @@ +/* + * 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.RealFieldElement; +import org.apache.commons.math3.exception.MaxCountExceededException; +import org.apache.commons.math3.ode.FieldODEStateAndDerivative; + +/** + * This interface represents a handler that should be called after + * each successful step. + * + * <p>The ODE integrators compute the evolution of the state vector at + * some grid points that depend on their own internal algorithm. Once + * they have found a new grid point (possibly after having computed + * several evaluation of the derivative at intermediate points), they + * provide it to objects implementing this interface. These objects + * typically either ignore the intermediate steps and wait for the + * last one, store the points in an ephemeris, or forward them to + * specialized processing or output methods.</p> + * + * @see org.apache.commons.math3.ode.FieldFirstOrderIntegrator + * @see FieldStepInterpolator + * @param <T> the type of the field elements + * @since 3.6 + */ + +public interface FieldStepHandler<T extends RealFieldElement<T>> { + + /** Initialize step handler at the start of an ODE integration. + * <p> + * This method is called once at the start of the integration. It + * may be used by the step handler to initialize some internal data + * if needed. + * </p> + * @param initialState initial time, state vector and derivative + * @param finalTime target time for the integration + */ + void init(FieldODEStateAndDerivative<T> initialState, T finalTime); + + /** + * 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, as the + * {@link org.apache.commons.math3.ode.ContinuousOutputModel + * ContinuousOutputModel} class does), it should build a local copy + * using the clone method of the interpolator and store this copy. + * Keeping only a reference to the interpolator and reusing it will + * result in unpredictable behavior (potentially crashing the application). + * @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 + */ + void handleStep(FieldStepInterpolator<T> interpolator, boolean isLast) + throws MaxCountExceededException; + +} http://git-wip-us.apache.org/repos/asf/commons-math/blob/5c647c12/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepInterpolator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepInterpolator.java b/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepInterpolator.java new file mode 100644 index 0000000..b732bc8 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepInterpolator.java @@ -0,0 +1,78 @@ +/* + * 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 java.io.Externalizable; + +import org.apache.commons.math3.RealFieldElement; +import org.apache.commons.math3.ode.FieldODEStateAndDerivative; + +/** This interface represents an interpolator over the last step + * during an ODE integration. + * + * <p>The various ODE integrators provide objects implementing this + * interface to the step handlers. These objects are often custom + * objects tightly bound to the integrator internal algorithms. The + * handlers can use these objects to retrieve the state vector at + * intermediate times between the previous and the current grid points + * (this feature is often called dense output).</p> + * + * @param <T> the type of the field elements + * @see org.apache.commons.math3.ode.FieldFirstOrderIntegrator + * @see FieldStepHandler + * @since 3.6 + */ + +public interface FieldStepInterpolator<T extends RealFieldElement<T>> extends Externalizable { + + /** + * Get the state at previous grid point time. + * @return state at previous grid point time + */ + FieldODEStateAndDerivative<T> getPreviousState(); + + /** + * Get the state at current grid point time. + * @return state at current grid point time + */ + FieldODEStateAndDerivative<T> getCurrentState(); + + /** + * Get the state at interpolated time. + * <p>Setting the time outside of the current step is allowed, but + * should be used with care since the accuracy of the interpolator will + * probably be very poor far from this step. This allowance has been + * added to simplify implementation of search algorithms near the + * step endpoints.</p> + * @param time time of the interpolated point + * @return state at interpolated time + */ + FieldODEStateAndDerivative<T> getInterpolatedState(T time); + + /** Check if the natural integration direction is forward. + * <p>This method provides the integration direction as specified by + * the integrator itself, it avoid some nasty problems in + * degenerated cases like null steps due to cancellation at step + * initialization, step control or discrete events + * triggering.</p> + * @return true if the integration variable (time) increases during + * integration + */ + boolean isForward(); + +} http://git-wip-us.apache.org/repos/asf/commons-math/blob/5c647c12/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepNormalizer.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepNormalizer.java b/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepNormalizer.java new file mode 100644 index 0000000..49a5077 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/ode/sampling/FieldStepNormalizer.java @@ -0,0 +1,272 @@ +/* + * 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.RealFieldElement; +import org.apache.commons.math3.exception.MaxCountExceededException; +import org.apache.commons.math3.ode.FieldODEStateAndDerivative; +import org.apache.commons.math3.util.FastMath; +import org.apache.commons.math3.util.Precision; + +/** + * This class wraps an object implementing {@link FieldFixedStepHandler} + * into a {@link FieldStepHandler}. + + * <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 + * FieldFixedStepHandler#handleStep handleStep} method of the underlying + * {@link FieldFixedStepHandler} 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> + * + * @param <T> the type of the field elements + * @see FieldStepHandler + * @see FieldFixedStepHandler + * @see StepNormalizerMode + * @see StepNormalizerBounds + * @since 3.6 + */ + +public class FieldStepNormalizer<T extends RealFieldElement<T>> implements FieldStepHandler<T> { + /** Fixed time step. */ + private double h; + + /** Underlying step handler. */ + private final FieldFixedStepHandler<T> handler; + + /** First step state. */ + private FieldODEStateAndDerivative<T> first; + + /** Last step step. */ + private FieldODEStateAndDerivative<T> last; + + /** 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 FieldStepNormalizer(final double h, final FieldFixedStepHandler<T> 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 FieldStepNormalizer(final double h, final FieldFixedStepHandler<T> 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 FieldStepNormalizer(final double h, final FieldFixedStepHandler<T> 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 FieldStepNormalizer(final double h, final FieldFixedStepHandler<T> handler, + final StepNormalizerMode mode, final StepNormalizerBounds bounds) { + this.h = FastMath.abs(h); + this.handler = handler; + this.mode = mode; + this.bounds = bounds; + first = null; + last = null; + forward = true; + } + + /** {@inheritDoc} */ + public void init(final FieldODEStateAndDerivative<T> initialState, final T finalTime) { + + first = null; + last = null; + forward = true; + + // initialize the underlying handler + handler.init(initialState, finalTime); + + } + + /** + * 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 FieldStepInterpolator<T> interpolator, final boolean isLast) + throws MaxCountExceededException { + // The first time, update the last state with the start information. + if (last == null) { + + first = interpolator.getPreviousState(); + last = first; + + // Take the integration direction into account. + forward = interpolator.isForward(); + if (!forward) { + h = -h; + } + } + + // Calculate next normalized step time. + T nextTime = (mode == StepNormalizerMode.INCREMENT) ? + last.getTime().add(h) : + last.getTime().getField().getZero().add((FastMath.floor(last.getTime().getReal() / h) + 1) * h); + if (mode == StepNormalizerMode.MULTIPLES && + Precision.equals(nextTime.getReal(), last.getTime().getReal(), 1)) { + nextTime = nextTime.add(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. + last = interpolator.getInterpolatedState(nextTime); + + // Move on to the next step. + nextTime = nextTime.add(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. + final boolean addLast = bounds.lastIncluded() && + last.getTime().getReal() != interpolator.getCurrentState().getTime().getReal(); + doNormalizedStep(!addLast); + if (addLast) { + last = interpolator.getCurrentState(); + 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(final T nextTime, final FieldStepInterpolator<T> interpolator) { + return forward ? + nextTime.getReal() <= interpolator.getCurrentState().getTime().getReal() : + nextTime.getReal() >= interpolator.getCurrentState().getTime().getReal(); + } + + /** + * Invokes the underlying step handler for the current normalized step. + * @param isLast true if the step is the last one + */ + private void doNormalizedStep(final boolean isLast) { + if (!bounds.firstIncluded() && first.getTime().getReal() == last.getTime().getReal()) { + return; + } + handler.handleStep(last, isLast); + } + +} http://git-wip-us.apache.org/repos/asf/commons-math/blob/5c647c12/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerBounds.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerBounds.java b/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerBounds.java index 0ccc58a..ca35e82 100644 --- a/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerBounds.java +++ b/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerBounds.java @@ -22,6 +22,7 @@ package org.apache.commons.math3.ode.sampling; * and last points. Note that if the last point coincides with a normalized * point, then the underlying fixed step size step handler is always called, * regardless of these settings. + * @see FieldStepNormalizer * @see StepNormalizer * @see StepNormalizerMode * @since 3.0 http://git-wip-us.apache.org/repos/asf/commons-math/blob/5c647c12/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerMode.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerMode.java b/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerMode.java index 0a2ddc9..c6f4c69 100644 --- a/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerMode.java +++ b/src/main/java/org/apache/commons/math3/ode/sampling/StepNormalizerMode.java @@ -20,6 +20,7 @@ package org.apache.commons.math3.ode.sampling; /** {@link StepNormalizer Step normalizer} modes. Determines how the step size * is interpreted. + * @see FieldStepNormalizer * @see StepNormalizer * @see StepNormalizerBounds * @since 3.0