org.apache.commons.math3.ode.nonstiff.RungeKuttaStepInterpolator Maven / Gradle / Ivy
Show all versions of commons-math3 Show documentation
/*
* 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 RungeKuttaIntegrator
* @see EmbeddedRungeKuttaIntegrator
*
* @since 1.2
*/
abstract class RungeKuttaStepInterpolator
extends AbstractStepInterpolator {
/** Previous state. */
protected double[] previousState;
/** Slopes at the intermediate points */
protected double[][] yDotK;
/** Reference to the integrator. */
protected AbstractIntegrator integrator;
/** 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 {@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 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.
* @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
* {@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 doFinalize
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.
* @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} */
@Override
public void shift() {
previousState = currentState.clone();
super.shift();
}
/** {@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} */
@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;
}
}
}