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.  *      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.CalculusFieldElement;
  23. import org.hipparchus.ode.FieldODEStateAndDerivative;
  24. import org.hipparchus.util.FastMath;
  25. import org.hipparchus.util.Precision;

  26. /**
  27.  * This class wraps an object implementing {@link FieldODEFixedStepHandler}
  28.  * into a {@link FieldODEStepHandler}.

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

  89. public class FieldStepNormalizer<T extends CalculusFieldElement<T>> implements FieldODEStepHandler<T> {

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

  92.     /** Underlying step handler. */
  93.     private final FieldODEFixedStepHandler<T> handler;

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

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

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

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

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

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

  114.     /** Simple constructor. Uses {@link StepNormalizerBounds#FIRST FIRST}
  115.      * bounds setting.
  116.      * @param h fixed time step (sign is not used)
  117.      * @param handler fixed time step handler to wrap
  118.      * @param mode step normalizer mode to use
  119.      */
  120.     public FieldStepNormalizer(final double h, final FieldODEFixedStepHandler<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.      */
  130.     public FieldStepNormalizer(final double h, final FieldODEFixedStepHandler<T> handler,
  131.                                final StepNormalizerBounds bounds) {
  132.         this(h, handler, StepNormalizerMode.INCREMENT, bounds);
  133.     }

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

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

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

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

  158.     }

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

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

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

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

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

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

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

  192.     /** {@inheritDoc} */
  193.     @Override
  194.     public void finish(final FieldODEStateAndDerivative<T> finalState) {
  195.         // There will be no more steps. The stored one should be given to
  196.         // the handler. We may have to output one more step. Only the last
  197.         // one of those should be flagged as being the last.
  198.         final boolean addLast = bounds.lastIncluded() && last.getTime().getReal() != finalState.getTime().getReal();
  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(final T nextTime, final FieldODEStateInterpolator<T> interpolator) {
  215.         return forward ?
  216.                nextTime.getReal() <= interpolator.getCurrentState().getTime().getReal() :
  217.                nextTime.getReal() >= interpolator.getCurrentState().getTime().getReal();
  218.     }

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

  229. }