StepsizeHelper.java

  1. /*
  2.  * Licensed to the Hipparchus project 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 Hipparchus project 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. package org.hipparchus.ode.nonstiff;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.exception.LocalizedCoreFormats;
  20. import org.hipparchus.exception.MathIllegalArgumentException;
  21. import org.hipparchus.ode.LocalizedODEFormats;
  22. import org.hipparchus.util.FastMath;

  23. /** Helper for adaptive stepsize control.
  24.  * @since 2.0
  25.  */

  26. public class StepsizeHelper {

  27.     /** Allowed absolute scalar error. */
  28.     private double scalAbsoluteTolerance;

  29.     /** Allowed relative scalar error. */
  30.     private double scalRelativeTolerance;

  31.     /** Allowed absolute vectorial error. */
  32.     private double[] vecAbsoluteTolerance;

  33.     /** Allowed relative vectorial error. */
  34.     private double[] vecRelativeTolerance;

  35.     /** Main set dimension. */
  36.     private int mainSetDimension;

  37.     /** User supplied initial step. */
  38.     private double initialStep;

  39.     /** Minimal step. */
  40.     private double minStep;

  41.     /** Maximal step. */
  42.     private double maxStep;

  43.     /** Simple constructor.
  44.      * @param minStep minimal step (sign is irrelevant, regardless of
  45.      * integration direction, forward or backward), the last step can
  46.      * be smaller than this
  47.      * @param maxStep maximal step (sign is irrelevant, regardless of
  48.      * integration direction, forward or backward), the last step can
  49.      * be smaller than this
  50.      * @param scalAbsoluteTolerance allowed absolute error
  51.      * @param scalRelativeTolerance allowed relative error
  52.      */
  53.     public StepsizeHelper(final double minStep, final double maxStep,
  54.                           final double scalAbsoluteTolerance,
  55.                           final double scalRelativeTolerance) {
  56.         this.minStep     = FastMath.abs(minStep);
  57.         this.maxStep     = FastMath.abs(maxStep);
  58.         this.initialStep = -1;

  59.         this.scalAbsoluteTolerance = scalAbsoluteTolerance;
  60.         this.scalRelativeTolerance = scalRelativeTolerance;
  61.         this.vecAbsoluteTolerance  = null;
  62.         this.vecRelativeTolerance  = null;
  63.     }

  64.     /** Simple constructor..
  65.      * @param minStep minimal step (sign is irrelevant, regardless of
  66.      * integration direction, forward or backward), the last step can
  67.      * be smaller than this
  68.      * @param maxStep maximal step (sign is irrelevant, regardless of
  69.      * integration direction, forward or backward), the last step can
  70.      * be smaller than this
  71.      * @param vecAbsoluteTolerance allowed absolute error
  72.      * @param vecRelativeTolerance allowed relative error
  73.      */
  74.     public StepsizeHelper(final double minStep, final double maxStep,
  75.                           final double[] vecAbsoluteTolerance,
  76.                           final double[] vecRelativeTolerance) {

  77.         this.minStep     = FastMath.abs(minStep);
  78.         this.maxStep     = FastMath.abs(maxStep);
  79.         this.initialStep = -1;

  80.        this.scalAbsoluteTolerance = 0;
  81.        this.scalRelativeTolerance = 0;
  82.        this.vecAbsoluteTolerance  = vecAbsoluteTolerance.clone();
  83.        this.vecRelativeTolerance  = vecRelativeTolerance.clone();

  84.     }

  85.     /** Set main set dimension.
  86.      * @param mainSetDimension dimension of the main set
  87.      * @exception MathIllegalArgumentException if adaptive step size integrators
  88.      * tolerance arrays dimensions are not compatible with equations settings
  89.      */
  90.     protected void setMainSetDimension(final int mainSetDimension) throws MathIllegalArgumentException {
  91.         this.mainSetDimension = mainSetDimension;

  92.         if (vecAbsoluteTolerance != null && vecAbsoluteTolerance.length != mainSetDimension) {
  93.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  94.                                                    mainSetDimension, vecAbsoluteTolerance.length);
  95.         }

  96.         if (vecRelativeTolerance != null && vecRelativeTolerance.length != mainSetDimension) {
  97.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  98.                                                    mainSetDimension, vecRelativeTolerance.length);
  99.         }
  100.     }

  101.     /** Get the main set dimension.
  102.      * @return main set dimension
  103.      */
  104.     public int getMainSetDimension() {
  105.         return mainSetDimension;
  106.     }

  107.     /** Get the relative tolerance for one component.
  108.      * @param i component to select
  109.      * @return relative tolerance for selected component
  110.      */
  111.     public double getRelativeTolerance(final int i) {
  112.         return vecAbsoluteTolerance == null ? scalRelativeTolerance : vecRelativeTolerance[i];
  113.     }

  114.     /** Get the tolerance for one component.
  115.      * @param i component to select
  116.      * @param scale scale factor for relative tolerance (i.e. y[i])
  117.      * @return tolerance for selected component
  118.      */
  119.     public double getTolerance(final int i, final double scale) {
  120.         return vecAbsoluteTolerance == null ?
  121.                scalAbsoluteTolerance   + scalRelativeTolerance   * scale :
  122.                vecAbsoluteTolerance[i] + vecRelativeTolerance[i] * scale;
  123.     }

  124.     /** Get the tolerance for one component.
  125.      * @param i component to select
  126.      * @param scale scale factor for relative tolerance (i.e. y[i])
  127.      * @param <T> type of the field elements
  128.      * @return tolerance for selected component
  129.      */
  130.     public <T extends CalculusFieldElement<T>> T getTolerance(final int i, final T scale) {
  131.         return vecAbsoluteTolerance == null ?
  132.                scale.multiply(scalRelativeTolerance).add(scalAbsoluteTolerance) :
  133.                scale.multiply(vecRelativeTolerance[i]).add(vecAbsoluteTolerance[i]);
  134.     }

  135.     /** Filter the integration step.
  136.      * @param h signed step
  137.      * @param forward forward integration indicator
  138.      * @param acceptSmall if true, steps smaller than the minimal value
  139.      * are silently increased up to this value, if false such small
  140.      * steps generate an exception
  141.      * @return a bounded integration step (h if no bound is reach, or a bounded value)
  142.      * @exception MathIllegalArgumentException if the step is too small and acceptSmall is false
  143.      */
  144.     public double filterStep(final double h, final boolean forward, final boolean acceptSmall)
  145.         throws MathIllegalArgumentException {

  146.         double filteredH = h;
  147.         if (FastMath.abs(h) < minStep) {
  148.             if (acceptSmall) {
  149.                 filteredH = forward ? minStep : -minStep;
  150.             } else {
  151.                 throw new MathIllegalArgumentException(LocalizedODEFormats.MINIMAL_STEPSIZE_REACHED_DURING_INTEGRATION,
  152.                                                        FastMath.abs(h), minStep, true);
  153.             }
  154.         }

  155.         if (filteredH > maxStep) {
  156.             filteredH = maxStep;
  157.         } else if (filteredH < -maxStep) {
  158.             filteredH = -maxStep;
  159.         }

  160.         return filteredH;

  161.     }

  162.     /** Filter the integration step.
  163.      * @param h signed step
  164.      * @param forward forward integration indicator
  165.      * @param acceptSmall if true, steps smaller than the minimal value
  166.      * are silently increased up to this value, if false such small
  167.      * steps generate an exception
  168.      * @param <T> type of the field elements
  169.      * @return a bounded integration step (h if no bound is reach, or a bounded value)
  170.      * @exception MathIllegalArgumentException if the step is too small and acceptSmall is false
  171.      */
  172.     public <T extends CalculusFieldElement<T>> T filterStep(final T h, final boolean forward, final boolean acceptSmall)
  173.         throws MathIllegalArgumentException {

  174.         T filteredH = h;
  175.         if (h.abs().subtract(minStep).getReal() < 0) {
  176.             if (acceptSmall) {
  177.                 filteredH = h.getField().getZero().add(forward ? minStep : -minStep);
  178.             } else {
  179.                 throw new MathIllegalArgumentException(LocalizedODEFormats.MINIMAL_STEPSIZE_REACHED_DURING_INTEGRATION,
  180.                                                        FastMath.abs(h.getReal()), minStep, true);
  181.             }
  182.         }

  183.         if (filteredH.subtract(maxStep).getReal() > 0) {
  184.             filteredH = h.getField().getZero().newInstance(maxStep);
  185.         } else if (filteredH.add(maxStep).getReal() < 0) {
  186.             filteredH = h.getField().getZero().newInstance(-maxStep);
  187.         }

  188.         return filteredH;

  189.     }

  190.     /** Set the initial step size.
  191.      * <p>This method allows the user to specify an initial positive
  192.      * step size instead of letting the integrator guess it by
  193.      * itself. If this method is not called before integration is
  194.      * started, the initial step size will be estimated by the
  195.      * integrator.</p>
  196.      * @param initialStepSize initial step size to use (must be positive even
  197.      * for backward integration ; providing a negative value or a value
  198.      * outside of the min/max step interval will lead the integrator to
  199.      * ignore the value and compute the initial step size by itself)
  200.      */
  201.     public void setInitialStepSize(final double initialStepSize) {
  202.         if ((initialStepSize < minStep) || (initialStepSize > maxStep)) {
  203.             initialStep = -1.0;
  204.         } else {
  205.             initialStep = initialStepSize;
  206.         }
  207.     }

  208.     /** Get the initial step.
  209.      * @return initial step
  210.      */
  211.     public double getInitialStep() {
  212.         return initialStep;
  213.     }

  214.     /** Get the minimal step.
  215.      * @return minimal step
  216.      */
  217.     public double getMinStep() {
  218.         return minStep;
  219.     }

  220.     /** Get the maximal step.
  221.      * @return maximal step
  222.      */
  223.     public double getMaxStep() {
  224.         return maxStep;
  225.     }

  226.     /** Get a dummy step size.
  227.      * @return geometric mean of {@link #getMinStep()} and {@link #getMaxStep()}
  228.      */
  229.     public double getDummyStepsize() {
  230.         return FastMath.sqrt(minStep * maxStep);
  231.     }

  232. }