/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.math3.ode.nonstiff;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import org.apache.commons.math3.ode.AbstractIntegrator;
import org.apache.commons.math3.ode.EquationsMapper;
import org.apache.commons.math3.ode.sampling.AbstractStepInterpolator;

This class represents an interpolator over the last step during an ODE integration for Runge-Kutta and embedded Runge-Kutta integrators.
See Also:
Since:1.2
/** This class represents an interpolator over the last step during an * ODE integration for Runge-Kutta and embedded Runge-Kutta integrators. * * @see RungeKuttaIntegrator * @see EmbeddedRungeKuttaIntegrator * * @since 1.2 */
abstract class RungeKuttaStepInterpolator extends AbstractStepInterpolator {
Previous state.
/** Previous state. */
protected double[] previousState;
Slopes at the intermediate points
/** Slopes at the intermediate points */
protected double[][] yDotK;
Reference to the integrator.
/** Reference to the integrator. */
protected AbstractIntegrator integrator;
Simple constructor. This constructor builds an instance that is not usable yet, the AbstractStepInterpolator.reinitialize method should be called before using the instance in order to initialize the internal arrays. This constructor is used only in order to delay the initialization in some cases. The RungeKuttaIntegrator and EmbeddedRungeKuttaIntegrator classes use the prototyping design pattern to create the step interpolators by cloning an uninitialized model and latter initializing the copy.
/** Simple constructor. * This constructor builds an instance that is not usable yet, the * {@link #reinitialize} method should be called before using the * instance in order to initialize the internal arrays. This * constructor is used only in order to delay the initialization in * some cases. The {@link RungeKuttaIntegrator} and {@link * EmbeddedRungeKuttaIntegrator} classes use the prototyping design * pattern to create the step interpolators by cloning an * uninitialized model and latter initializing the copy. */
protected RungeKuttaStepInterpolator() { previousState = null; yDotK = null; integrator = null; }
Copy constructor.

The copied interpolator should have been finalized before the copy, otherwise the copy will not be able to perform correctly any interpolation and will throw a NullPointerException later. Since we don't want this constructor to throw the exceptions finalization may involve and since we don't want this method to modify the state of the copied interpolator, finalization is not done automatically, it remains under user control.

The copy is a deep copy: its arrays are separated from the original arrays of the instance.

Params:
  • interpolator – interpolator to copy from.
/** Copy constructor. * <p>The copied interpolator should have been finalized before the * copy, otherwise the copy will not be able to perform correctly any * interpolation and will throw a {@link NullPointerException} * later. Since we don't want this constructor to throw the * exceptions finalization may involve and since we don't want this * method to modify the state of the copied interpolator, * finalization is <strong>not</strong> done automatically, it * remains under user control.</p> * <p>The copy is a deep copy: its arrays are separated from the * original arrays of the instance.</p> * @param interpolator interpolator to copy from. */
RungeKuttaStepInterpolator(final RungeKuttaStepInterpolator interpolator) { super(interpolator); if (interpolator.currentState != null) { previousState = interpolator.previousState.clone(); yDotK = new double[interpolator.yDotK.length][]; for (int k = 0; k < interpolator.yDotK.length; ++k) { yDotK[k] = interpolator.yDotK[k].clone(); } } else { previousState = null; yDotK = null; } // we cannot keep any reference to the equations in the copy // the interpolator should have been finalized before integrator = null; }
Reinitialize the instance

Some Runge-Kutta integrators need fewer functions evaluations than their counterpart step interpolators. So the interpolator should perform the last evaluations they need by themselves. The RungeKuttaIntegrator and EmbeddedRungeKuttaIntegrator abstract classes call this method in order to let the step interpolator perform the evaluations it needs. These evaluations will be performed during the call to doFinalize if any, i.e. only if the step handler either calls the finalizeStep method or the getInterpolatedState method (for an interpolator which needs a finalization) or if it clones the step interpolator.

Params:
  • rkIntegrator – integrator being used
  • y – reference to the integrator array holding the state at the end of the step
  • yDotArray – reference to the integrator array holding all the intermediate slopes
  • forward – integration direction indicator
  • primaryMapper – equations mapper for the primary equations set
  • secondaryMappers – equations mappers for the secondary equations sets
/** Reinitialize the instance * <p>Some Runge-Kutta integrators need fewer functions evaluations * than their counterpart step interpolators. So the interpolator * should perform the last evaluations they need by themselves. The * {@link RungeKuttaIntegrator RungeKuttaIntegrator} and {@link * EmbeddedRungeKuttaIntegrator EmbeddedRungeKuttaIntegrator} * abstract classes call this method in order to let the step * interpolator perform the evaluations it needs. These evaluations * will be performed during the call to <code>doFinalize</code> if * any, i.e. only if the step handler either calls the {@link * AbstractStepInterpolator#finalizeStep finalizeStep} method or the * {@link AbstractStepInterpolator#getInterpolatedState * getInterpolatedState} method (for an interpolator which needs a * finalization) or if it clones the step interpolator.</p> * @param rkIntegrator integrator being used * @param y reference to the integrator array holding the state at * the end of the step * @param yDotArray reference to the integrator array holding all the * intermediate slopes * @param forward integration direction indicator * @param primaryMapper equations mapper for the primary equations set * @param secondaryMappers equations mappers for the secondary equations sets */
public void reinitialize(final AbstractIntegrator rkIntegrator, final double[] y, final double[][] yDotArray, final boolean forward, final EquationsMapper primaryMapper, final EquationsMapper[] secondaryMappers) { reinitialize(y, forward, primaryMapper, secondaryMappers); this.previousState = null; this.yDotK = yDotArray; this.integrator = rkIntegrator; }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void shift() { previousState = currentState.clone(); super.shift(); }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void writeExternal(final ObjectOutput out) throws IOException { // save the state of the base class writeBaseExternal(out); // save the local attributes final int n = (currentState == null) ? -1 : currentState.length; for (int i = 0; i < n; ++i) { out.writeDouble(previousState[i]); } final int kMax = (yDotK == null) ? -1 : yDotK.length; out.writeInt(kMax); for (int k = 0; k < kMax; ++k) { for (int i = 0; i < n; ++i) { out.writeDouble(yDotK[k][i]); } } // we do not save any reference to the equations }
{@inheritDoc}
/** {@inheritDoc} */
@Override public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { // read the base class final double t = readBaseExternal(in); // read the local attributes final int n = (currentState == null) ? -1 : currentState.length; if (n < 0) { previousState = null; } else { previousState = new double[n]; for (int i = 0; i < n; ++i) { previousState[i] = in.readDouble(); } } final int kMax = in.readInt(); yDotK = (kMax < 0) ? null : new double[kMax][]; for (int k = 0; k < kMax; ++k) { yDotK[k] = (n < 0) ? null : new double[n]; for (int i = 0; i < n; ++i) { yDotK[k][i] = in.readDouble(); } } integrator = null; if (currentState != null) { // we can now set the interpolated time and state setInterpolatedTime(t); } else { interpolatedTime = t; } } }