StepNormalizer.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.  *      https://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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.ode.sampling;

  22. import org.hipparchus.ode.ODEStateAndDerivative;
  23. import org.hipparchus.util.FastMath;
  24. import org.hipparchus.util.Precision;

  25. /**
  26.  * This class wraps an object implementing {@link ODEFixedStepHandler}
  27.  * into a {@link ODEStepHandler}.

  28.  * <p>This wrapper allows to use fixed step handlers with general
  29.  * integrators which cannot guaranty their integration steps will
  30.  * remain constant and therefore only accept general step
  31.  * handlers.</p>
  32.  *
  33.  * <p>The stepsize used is selected at construction time. The {@link
  34.  * ODEFixedStepHandler#handleStep handleStep} method of the underlying
  35.  * {@link ODEFixedStepHandler} object is called at normalized times. The
  36.  * normalized times can be influenced by the {@link StepNormalizerMode} and
  37.  * {@link StepNormalizerBounds}.</p>
  38.  *
  39.  * <p>There is no constraint on the integrator, it can use any time step
  40.  * it needs (time steps longer or shorter than the fixed time step and
  41.  * non-integer ratios are all allowed).</p>
  42.  *
  43.  * <table border="">
  44.  * <caption>Examples (step size = 0.5)</caption>
  45.  * <tr ><td>Start time</td><td>End time</td>
  46.  *  <td>Direction</td><td>{@link StepNormalizerMode Mode}</td>
  47.  *  <td>{@link StepNormalizerBounds Bounds}</td><td>Output</td></tr>
  48.  * <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>
  49.  * <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>
  50.  * <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>
  51.  * <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>
  52.  * <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>
  53.  * <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>
  54.  * <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>
  55.  * <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>
  56.  * <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>
  57.  * <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>
  58.  * <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>
  59.  * <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>
  60.  * <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>
  61.  * <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>
  62.  * <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>
  63.  * <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>
  64.  * <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>
  65.  * <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>
  66.  * <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>
  67.  * <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>
  68.  * <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>
  69.  * <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>
  70.  * <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>
  71.  * <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>
  72.  * <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>
  73.  * <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>
  74.  * <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>
  75.  * <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>
  76.  * <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>
  77.  * <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>
  78.  * <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>
  79.  * <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>
  80.  * </table>
  81.  *
  82.  * @see ODEStepHandler
  83.  * @see ODEFixedStepHandler
  84.  * @see StepNormalizerMode
  85.  * @see StepNormalizerBounds
  86.  */

  87. public class StepNormalizer implements ODEStepHandler {

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

  90.     /** Underlying step handler. */
  91.     private final ODEFixedStepHandler handler;

  92.     /** First step state. */
  93.     private ODEStateAndDerivative first;

  94.     /** Last step step. */
  95.     private ODEStateAndDerivative last;

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

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

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

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

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

  122.     /** Simple constructor. Uses {@link StepNormalizerMode#INCREMENT INCREMENT}
  123.      * mode.
  124.      * @param h fixed time step (sign is not used)
  125.      * @param handler fixed time step handler to wrap
  126.      * @param bounds step normalizer bounds setting to use
  127.      */
  128.     public StepNormalizer(final double h, final ODEFixedStepHandler handler,
  129.                           final StepNormalizerBounds bounds) {
  130.         this(h, handler, StepNormalizerMode.INCREMENT, bounds);
  131.     }

  132.     /** Simple constructor.
  133.      * @param h fixed time step (sign is not used)
  134.      * @param handler fixed time step handler to wrap
  135.      * @param mode step normalizer mode to use
  136.      * @param bounds step normalizer bounds setting to use
  137.      */
  138.     public StepNormalizer(final double h, final ODEFixedStepHandler handler,
  139.                           final StepNormalizerMode mode,
  140.                           final StepNormalizerBounds bounds) {
  141.         this.h          = FastMath.abs(h);
  142.         this.handler    = handler;
  143.         this.mode       = mode;
  144.         this.bounds     = bounds;
  145.         first           = null;
  146.         last            = null;
  147.         forward         = true;
  148.     }

  149.     /** {@inheritDoc} */
  150.     @Override
  151.     public void init(final ODEStateAndDerivative initialState, final double finalTime) {

  152.         first           = null;
  153.         last            = null;
  154.         forward         = true;

  155.         // initialize the underlying handler
  156.         handler.init(initialState, finalTime);

  157.     }

  158.     /** {@inheritDoc} */
  159.     @Override
  160.     public void handleStep(final ODEStateInterpolator interpolator) {
  161.         // The first time, update the last state with the start information.
  162.         if (last == null) {

  163.             first   = interpolator.getPreviousState();
  164.             last    = first;

  165.             // Take the integration direction into account.
  166.             forward = interpolator.isForward();
  167.             if (!forward) {
  168.                 h = -h;
  169.             }
  170.         }

  171.         // Calculate next normalized step time.
  172.         double nextTime = (mode == StepNormalizerMode.INCREMENT) ?
  173.                           last.getTime() + h :
  174.                           (FastMath.floor(last.getTime() / h) + 1) * h;
  175.         if (mode == StepNormalizerMode.MULTIPLES &&
  176.             Precision.equals(nextTime, last.getTime(), 1)) {
  177.             nextTime += h;
  178.         }

  179.         // Process normalized steps as long as they are in the current step.
  180.         boolean nextInStep = isNextInStep(nextTime, interpolator);
  181.         while (nextInStep) {
  182.             // Output the stored previous step.
  183.             doNormalizedStep(false);

  184.             // Store the next step as last step.
  185.             last = interpolator.getInterpolatedState(nextTime);

  186.             // Move on to the next step.
  187.             nextTime += h;
  188.             nextInStep = isNextInStep(nextTime, interpolator);
  189.         }
  190.     }

  191.     /** {@inheritDoc} */
  192.     @Override
  193.     public void finish(ODEStateAndDerivative finalState) {
  194.             // There will be no more steps. The stored one should be given to
  195.             // the handler. We may have to output one more step. Only the last
  196.             // one of those should be flagged as being the last.
  197.             boolean addLast = bounds.lastIncluded() &&
  198.                               last.getTime() != finalState.getTime();
  199.             doNormalizedStep(!addLast);
  200.             if (addLast) {
  201.                 last = finalState;
  202.                 doNormalizedStep(true);
  203.             }
  204.     }

  205.     /**
  206.      * Returns a value indicating whether the next normalized time is in the
  207.      * current step.
  208.      * @param nextTime the next normalized time
  209.      * @param interpolator interpolator for the last accepted step, to use to
  210.      * get the end time of the current step
  211.      * @return value indicating whether the next normalized time is in the
  212.      * current step
  213.      */
  214.     private boolean isNextInStep(double nextTime,
  215.                                  ODEStateInterpolator interpolator) {
  216.         return forward ?
  217.                nextTime <= interpolator.getCurrentState().getTime() :
  218.                nextTime >= interpolator.getCurrentState().getTime();
  219.     }

  220.     /**
  221.      * Invokes the underlying step handler for the current normalized step.
  222.      * @param isLast true if the step is the last one
  223.      */
  224.     private void doNormalizedStep(boolean isLast) {
  225.         if (!bounds.firstIncluded() && first.getTime() == last.getTime()) {
  226.             return;
  227.         }
  228.         handler.handleStep(last, isLast);
  229.     }

  230. }