FieldStepNormalizer.java

  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. package org.apache.commons.math4.legacy.ode.sampling;

  18. import org.apache.commons.math4.legacy.core.RealFieldElement;
  19. import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
  20. import org.apache.commons.math4.legacy.ode.FieldODEStateAndDerivative;
  21. import org.apache.commons.math4.core.jdkmath.JdkMath;
  22. import org.apache.commons.numbers.core.Precision;

  23. /**
  24.  * This class wraps an object implementing {@link FieldFixedStepHandler}
  25.  * into a {@link FieldStepHandler}.

  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.  * FieldFixedStepHandler#handleStep handleStep} method of the underlying
  33.  * {@link FieldFixedStepHandler} object is called at normalized times. The
  34.  * normalized times can be influenced by the {@link StepNormalizerMode} and
  35.  * {@link StepNormalizerBounds}.</p>
  36.  *
  37.  * <p>There is no constraint on the integrator, it can use any time step
  38.  * it needs (time steps longer or shorter than the fixed time step and
  39.  * non-integer ratios are all allowed).</p>
  40.  *
  41.  * <table border="1" style="text-align: center">
  42.  * <caption>Examples (step size = 0.5)</caption>
  43.  * <tr style="background-color: #CCCCFF"><td colspan=6 style="font-size: x-large">Examples (step size = 0.5)</td></tr>
  44.  * <tr style="background-color: #EEEEFF; font-size: large"><td>Start time</td><td>End time</td>
  45.  *  <td>Direction</td><td>{@link StepNormalizerMode Mode}</td>
  46.  *  <td>{@link StepNormalizerBounds Bounds}</td><td>Output</td></tr>
  47.  * <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>
  48.  * <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>
  49.  * <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>
  50.  * <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>
  51.  * <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>
  52.  * <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>
  53.  * <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>
  54.  * <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>
  55.  * <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>
  56.  * <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>
  57.  * <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>
  58.  * <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>
  59.  * <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>
  60.  * <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>
  61.  * <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>
  62.  * <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>
  63.  * <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>
  64.  * <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>
  65.  * <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>
  66.  * <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>
  67.  * <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>
  68.  * <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>
  69.  * <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>
  70.  * <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>
  71.  * <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>
  72.  * <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>
  73.  * <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>
  74.  * <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>
  75.  * <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>
  76.  * <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>
  77.  * <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>
  78.  * <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>
  79.  * </table>
  80.  *
  81.  * @param <T> the type of the field elements
  82.  * @see FieldStepHandler
  83.  * @see FieldFixedStepHandler
  84.  * @see StepNormalizerMode
  85.  * @see StepNormalizerBounds
  86.  * @since 3.6
  87.  */

  88. public class FieldStepNormalizer<T extends RealFieldElement<T>> implements FieldStepHandler<T> {

  89.     /** Fixed time step. */
  90.     private double h;

  91.     /** Underlying step handler. */
  92.     private final FieldFixedStepHandler<T> handler;

  93.     /** First step state. */
  94.     private FieldODEStateAndDerivative<T> first;

  95.     /** Last step step. */
  96.     private FieldODEStateAndDerivative<T> last;

  97.     /** Integration direction indicator. */
  98.     private boolean forward;

  99.     /** The step normalizer bounds settings to use. */
  100.     private final StepNormalizerBounds bounds;

  101.     /** The step normalizer mode to use. */
  102.     private final StepNormalizerMode mode;

  103.     /** Simple constructor. Uses {@link StepNormalizerMode#INCREMENT INCREMENT}
  104.      * mode, and {@link StepNormalizerBounds#FIRST FIRST} bounds setting, for
  105.      * backwards compatibility.
  106.      * @param h fixed time step (sign is not used)
  107.      * @param handler fixed time step handler to wrap
  108.      */
  109.     public FieldStepNormalizer(final double h, final FieldFixedStepHandler<T> handler) {
  110.         this(h, handler, StepNormalizerMode.INCREMENT,
  111.              StepNormalizerBounds.FIRST);
  112.     }

  113.     /** Simple constructor. Uses {@link StepNormalizerBounds#FIRST FIRST}
  114.      * bounds setting.
  115.      * @param h fixed time step (sign is not used)
  116.      * @param handler fixed time step handler to wrap
  117.      * @param mode step normalizer mode to use
  118.      * @since 3.0
  119.      */
  120.     public FieldStepNormalizer(final double h, final FieldFixedStepHandler<T> handler,
  121.                                final StepNormalizerMode mode) {
  122.         this(h, handler, mode, StepNormalizerBounds.FIRST);
  123.     }

  124.     /** Simple constructor. Uses {@link StepNormalizerMode#INCREMENT INCREMENT}
  125.      * mode.
  126.      * @param h fixed time step (sign is not used)
  127.      * @param handler fixed time step handler to wrap
  128.      * @param bounds step normalizer bounds setting to use
  129.      * @since 3.0
  130.      */
  131.     public FieldStepNormalizer(final double h, final FieldFixedStepHandler<T> handler,
  132.                                final StepNormalizerBounds bounds) {
  133.         this(h, handler, StepNormalizerMode.INCREMENT, bounds);
  134.     }

  135.     /** Simple constructor.
  136.      * @param h fixed time step (sign is not used)
  137.      * @param handler fixed time step handler to wrap
  138.      * @param mode step normalizer mode to use
  139.      * @param bounds step normalizer bounds setting to use
  140.      * @since 3.0
  141.      */
  142.     public FieldStepNormalizer(final double h, final FieldFixedStepHandler<T> handler,
  143.                                final StepNormalizerMode mode, final StepNormalizerBounds bounds) {
  144.         this.h       = JdkMath.abs(h);
  145.         this.handler = handler;
  146.         this.mode    = mode;
  147.         this.bounds  = bounds;
  148.         first        = null;
  149.         last         = null;
  150.         forward      = true;
  151.     }

  152.     /** {@inheritDoc} */
  153.     @Override
  154.     public void init(final FieldODEStateAndDerivative<T> initialState, final T finalTime) {

  155.         first   = null;
  156.         last    = null;
  157.         forward = true;

  158.         // initialize the underlying handler
  159.         handler.init(initialState, finalTime);
  160.     }

  161.     /**
  162.      * Handle the last accepted step.
  163.      * @param interpolator interpolator for the last accepted step. For
  164.      * efficiency purposes, the various integrators reuse the same
  165.      * object on each call, so if the instance wants to keep it across
  166.      * all calls (for example to provide at the end of the integration a
  167.      * continuous model valid throughout the integration range), it
  168.      * should build a local copy using the clone method and store this
  169.      * copy.
  170.      * @param isLast true if the step is the last one
  171.      * @exception MaxCountExceededException if the interpolator throws one because
  172.      * the number of functions evaluations is exceeded
  173.      */
  174.     @Override
  175.     public void handleStep(final FieldStepInterpolator<T> interpolator, final boolean isLast)
  176.         throws MaxCountExceededException {
  177.         // The first time, update the last state with the start information.
  178.         if (last == null) {

  179.             first   = interpolator.getPreviousState();
  180.             last    = first;

  181.             // Take the integration direction into account.
  182.             forward = interpolator.isForward();
  183.             if (!forward) {
  184.                 h = -h;
  185.             }
  186.         }

  187.         // Calculate next normalized step time.
  188.         T nextTime = (mode == StepNormalizerMode.INCREMENT) ?
  189.                      last.getTime().add(h) :
  190.                      last.getTime().getField().getZero().add((JdkMath.floor(last.getTime().getReal() / h) + 1) * h);
  191.         if (mode == StepNormalizerMode.MULTIPLES &&
  192.             Precision.equals(nextTime.getReal(), last.getTime().getReal(), 1)) {
  193.             nextTime = nextTime.add(h);
  194.         }

  195.         // Process normalized steps as long as they are in the current step.
  196.         boolean nextInStep = isNextInStep(nextTime, interpolator);
  197.         while (nextInStep) {
  198.             // Output the stored previous step.
  199.             doNormalizedStep(false);

  200.             // Store the next step as last step.
  201.             last = interpolator.getInterpolatedState(nextTime);

  202.             // Move on to the next step.
  203.             nextTime = nextTime.add(h);
  204.             nextInStep = isNextInStep(nextTime, interpolator);
  205.         }

  206.         if (isLast) {
  207.             // There will be no more steps. The stored one should be given to
  208.             // the handler. We may have to output one more step. Only the last
  209.             // one of those should be flagged as being the last.
  210.             final boolean addLast = bounds.lastIncluded() &&
  211.                                     last.getTime().getReal() != interpolator.getCurrentState().getTime().getReal();
  212.             doNormalizedStep(!addLast);
  213.             if (addLast) {
  214.                 last = interpolator.getCurrentState();
  215.                 doNormalizedStep(true);
  216.             }
  217.         }
  218.     }

  219.     /**
  220.      * Returns a value indicating whether the next normalized time is in the
  221.      * current step.
  222.      * @param nextTime the next normalized time
  223.      * @param interpolator interpolator for the last accepted step, to use to
  224.      * get the end time of the current step
  225.      * @return value indicating whether the next normalized time is in the
  226.      * current step
  227.      */
  228.     private boolean isNextInStep(final T nextTime, final FieldStepInterpolator<T> interpolator) {
  229.         return forward ?
  230.                nextTime.getReal() <= interpolator.getCurrentState().getTime().getReal() :
  231.                nextTime.getReal() >= interpolator.getCurrentState().getTime().getReal();
  232.     }

  233.     /**
  234.      * Invokes the underlying step handler for the current normalized step.
  235.      * @param isLast true if the step is the last one
  236.      */
  237.     private void doNormalizedStep(final boolean isLast) {
  238.         if (!bounds.firstIncluded() && first.getTime().getReal() == last.getTime().getReal()) {
  239.             return;
  240.         }
  241.         handler.handleStep(last, isLast);
  242.     }
  243. }