NordsieckStepInterpolator.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 java.io.IOException;
  19. import java.io.ObjectInput;
  20. import java.io.ObjectOutput;
  21. import java.util.Arrays;

  22. import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
  23. import org.apache.commons.math4.legacy.linear.Array2DRowRealMatrix;
  24. import org.apache.commons.math4.legacy.ode.EquationsMapper;
  25. import org.apache.commons.math4.core.jdkmath.JdkMath;

  26. /**
  27.  * This class implements an interpolator for integrators using Nordsieck representation.
  28.  *
  29.  * <p>This interpolator computes dense output around the current point.
  30.  * The interpolation equation is based on Taylor series formulas.
  31.  *
  32.  * @see org.apache.commons.math4.legacy.ode.nonstiff.AdamsBashforthIntegrator
  33.  * @see org.apache.commons.math4.legacy.ode.nonstiff.AdamsMoultonIntegrator
  34.  * @since 2.0
  35.  */

  36. public class NordsieckStepInterpolator extends AbstractStepInterpolator {

  37.     /** Serializable version identifier. */
  38.     private static final long serialVersionUID = -7179861704951334960L;

  39.     /** State variation. */
  40.     protected double[] stateVariation;

  41.     /** Step size used in the first scaled derivative and Nordsieck vector. */
  42.     private double scalingH;

  43.     /** Reference time for all arrays.
  44.      * <p>Sometimes, the reference time is the same as previousTime,
  45.      * sometimes it is the same as currentTime, so we use a separate
  46.      * field to avoid any confusion.
  47.      * </p>
  48.      */
  49.     private double referenceTime;

  50.     /** First scaled derivative. */
  51.     private double[] scaled;

  52.     /** Nordsieck vector. */
  53.     private Array2DRowRealMatrix nordsieck;

  54.     /** Simple constructor.
  55.      * This constructor builds an instance that is not usable yet, the
  56.      * {@link AbstractStepInterpolator#reinitialize} method should be called
  57.      * before using the instance in order to initialize the internal arrays. This
  58.      * constructor is used only in order to delay the initialization in
  59.      * some cases.
  60.      */
  61.     public NordsieckStepInterpolator() {
  62.     }

  63.     /** Copy constructor.
  64.      * @param interpolator interpolator to copy from. The copy is a deep
  65.      * copy: its arrays are separated from the original arrays of the
  66.      * instance
  67.      */
  68.     public NordsieckStepInterpolator(final NordsieckStepInterpolator interpolator) {
  69.         super(interpolator);
  70.         scalingH      = interpolator.scalingH;
  71.         referenceTime = interpolator.referenceTime;
  72.         if (interpolator.scaled != null) {
  73.             scaled = interpolator.scaled.clone();
  74.         }
  75.         if (interpolator.nordsieck != null) {
  76.             nordsieck = new Array2DRowRealMatrix(interpolator.nordsieck.getDataRef(), true);
  77.         }
  78.         if (interpolator.stateVariation != null) {
  79.             stateVariation = interpolator.stateVariation.clone();
  80.         }
  81.     }

  82.     /** {@inheritDoc} */
  83.     @Override
  84.     protected StepInterpolator doCopy() {
  85.         return new NordsieckStepInterpolator(this);
  86.     }

  87.     /** Reinitialize the instance.
  88.      * <p>Beware that all arrays <em>must</em> be references to integrator
  89.      * arrays, in order to ensure proper update without copy.</p>
  90.      * @param y reference to the integrator array holding the state at
  91.      * the end of the step
  92.      * @param forward integration direction indicator
  93.      * @param primaryMapper equations mapper for the primary equations set
  94.      * @param secondaryMappers equations mappers for the secondary equations sets
  95.      */
  96.     @Override
  97.     public void reinitialize(final double[] y, final boolean forward,
  98.                              final EquationsMapper primaryMapper,
  99.                              final EquationsMapper[] secondaryMappers) {
  100.         super.reinitialize(y, forward, primaryMapper, secondaryMappers);
  101.         stateVariation = new double[y.length];
  102.     }

  103.     /** Reinitialize the instance.
  104.      * <p>Beware that all arrays <em>must</em> be references to integrator
  105.      * arrays, in order to ensure proper update without copy.</p>
  106.      * @param time time at which all arrays are defined
  107.      * @param stepSize step size used in the scaled and Nordsieck arrays
  108.      * @param scaledDerivative reference to the integrator array holding the first
  109.      * scaled derivative
  110.      * @param nordsieckVector reference to the integrator matrix holding the
  111.      * Nordsieck vector
  112.      */
  113.     public void reinitialize(final double time, final double stepSize,
  114.                              final double[] scaledDerivative,
  115.                              final Array2DRowRealMatrix nordsieckVector) {
  116.         this.referenceTime = time;
  117.         this.scalingH      = stepSize;
  118.         this.scaled        = scaledDerivative;
  119.         this.nordsieck     = nordsieckVector;

  120.         // make sure the state and derivatives will depend on the new arrays
  121.         setInterpolatedTime(getInterpolatedTime());
  122.     }

  123.     /** Rescale the instance.
  124.      * <p>Since the scaled and Nordsieck arrays are shared with the caller,
  125.      * this method has the side effect of rescaling this arrays in the caller too.</p>
  126.      * @param stepSize new step size to use in the scaled and Nordsieck arrays
  127.      */
  128.     public void rescale(final double stepSize) {

  129.         final double ratio = stepSize / scalingH;
  130.         for (int i = 0; i < scaled.length; ++i) {
  131.             scaled[i] *= ratio;
  132.         }

  133.         final double[][] nData = nordsieck.getDataRef();
  134.         double power = ratio;
  135.         for (int i = 0; i < nData.length; ++i) {
  136.             power *= ratio;
  137.             final double[] nDataI = nData[i];
  138.             for (int j = 0; j < nDataI.length; ++j) {
  139.                 nDataI[j] *= power;
  140.             }
  141.         }

  142.         scalingH = stepSize;
  143.     }

  144.     /**
  145.      * Get the state vector variation from current to interpolated state.
  146.      * <p>This method is aimed at computing y(t<sub>interpolation</sub>)
  147.      * -y(t<sub>current</sub>) accurately by avoiding the cancellation errors
  148.      * that would occur if the subtraction were performed explicitly.</p>
  149.      * <p>The returned vector is a reference to a reused array, so
  150.      * it should not be modified and it should be copied if it needs
  151.      * to be preserved across several calls.</p>
  152.      * @return state vector at time {@link #getInterpolatedTime}
  153.      * @see #getInterpolatedDerivatives()
  154.      * @exception MaxCountExceededException if the number of functions evaluations is exceeded
  155.      */
  156.     public double[] getInterpolatedStateVariation() throws MaxCountExceededException {
  157.         // compute and ignore interpolated state
  158.         // to make sure state variation is computed as a side effect
  159.         getInterpolatedState();
  160.         return stateVariation;
  161.     }

  162.     /** {@inheritDoc} */
  163.     @Override
  164.     protected void computeInterpolatedStateAndDerivatives(final double theta, final double oneMinusThetaH) {

  165.         final double x = interpolatedTime - referenceTime;
  166.         final double normalizedAbscissa = x / scalingH;

  167.         Arrays.fill(stateVariation, 0.0);
  168.         Arrays.fill(interpolatedDerivatives, 0.0);

  169.         // apply Taylor formula from high order to low order,
  170.         // for the sake of numerical accuracy
  171.         final double[][] nData = nordsieck.getDataRef();
  172.         for (int i = nData.length - 1; i >= 0; --i) {
  173.             final int order = i + 2;
  174.             final double[] nDataI = nData[i];
  175.             final double power = JdkMath.pow(normalizedAbscissa, order);
  176.             for (int j = 0; j < nDataI.length; ++j) {
  177.                 final double d = nDataI[j] * power;
  178.                 stateVariation[j]          += d;
  179.                 interpolatedDerivatives[j] += order * d;
  180.             }
  181.         }

  182.         for (int j = 0; j < currentState.length; ++j) {
  183.             stateVariation[j] += scaled[j] * normalizedAbscissa;
  184.             interpolatedState[j] = currentState[j] + stateVariation[j];
  185.             interpolatedDerivatives[j] =
  186.                 (interpolatedDerivatives[j] + scaled[j] * normalizedAbscissa) / x;
  187.         }
  188.     }

  189.     /** {@inheritDoc} */
  190.     @Override
  191.     public void writeExternal(final ObjectOutput out)
  192.         throws IOException {

  193.         // save the state of the base class
  194.         writeBaseExternal(out);

  195.         // save the local attributes
  196.         out.writeDouble(scalingH);
  197.         out.writeDouble(referenceTime);

  198.         final int n = (currentState == null) ? -1 : currentState.length;
  199.         if (scaled == null) {
  200.             out.writeBoolean(false);
  201.         } else {
  202.             out.writeBoolean(true);
  203.             for (int j = 0; j < n; ++j) {
  204.                 out.writeDouble(scaled[j]);
  205.             }
  206.         }

  207.         if (nordsieck == null) {
  208.             out.writeBoolean(false);
  209.         } else {
  210.             out.writeBoolean(true);
  211.             out.writeObject(nordsieck);
  212.         }

  213.         // we don't save state variation, it will be recomputed
  214.     }

  215.     /** {@inheritDoc} */
  216.     @Override
  217.     public void readExternal(final ObjectInput in)
  218.         throws IOException, ClassNotFoundException {

  219.         // read the base class
  220.         final double t = readBaseExternal(in);

  221.         // read the local attributes
  222.         scalingH      = in.readDouble();
  223.         referenceTime = in.readDouble();

  224.         final int n = (currentState == null) ? -1 : currentState.length;
  225.         final boolean hasScaled = in.readBoolean();
  226.         if (hasScaled) {
  227.             scaled = new double[n];
  228.             for (int j = 0; j < n; ++j) {
  229.                 scaled[j] = in.readDouble();
  230.             }
  231.         } else {
  232.             scaled = null;
  233.         }

  234.         final boolean hasNordsieck = in.readBoolean();
  235.         if (hasNordsieck) {
  236.             nordsieck = (Array2DRowRealMatrix) in.readObject();
  237.         } else {
  238.             nordsieck = null;
  239.         }

  240.         if (hasScaled && hasNordsieck) {
  241.             // we can now set the interpolated time and state
  242.             stateVariation = new double[n];
  243.             setInterpolatedTime(t);
  244.         } else {
  245.             stateVariation = null;
  246.         }
  247.     }
  248. }