blob: dc5ca189c2593f0c42dd6c1dc0e46edb2def745c [file] [log] [blame]
/*
* 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.math.ode.jacobians;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.MaxEvaluationsExceededException;
import org.apache.commons.math.ode.DerivativeException;
import org.apache.commons.math.exception.util.LocalizedFormats;
import org.apache.commons.math.ode.ExtendedFirstOrderDifferentialEquations;
import org.apache.commons.math.ode.FirstOrderIntegrator;
import org.apache.commons.math.ode.IntegratorException;
import org.apache.commons.math.ode.events.EventException;
import org.apache.commons.math.ode.events.EventHandler;
import org.apache.commons.math.ode.sampling.StepHandler;
import org.apache.commons.math.ode.sampling.StepInterpolator;
/** This class enhances a first order integrator for differential equations to
* compute also partial derivatives of the solution with respect to initial state
* and parameters.
* <p>In order to compute both the state and its derivatives, the ODE problem
* is extended with jacobians of the raw ODE and the variational equations are
* added to form a new compound problem of higher dimension. If the original ODE
* problem has dimension n and there are p parameters, the compound problem will
* have dimension n &times; (1 + n + p).</p>
* @see ParameterizedODE
* @see ODEWithJacobians
* @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 févr. 2011) $
* @since 2.1
* @deprecated as of 2.2 the complete package is deprecated, it will be replaced
* in 3.0 by a completely rewritten implementation
*/
@Deprecated
public class FirstOrderIntegratorWithJacobians {
/** Underlying integrator for compound problem. */
private final FirstOrderIntegrator integrator;
/** Raw equations to integrate. */
private final ODEWithJacobians ode;
/** Maximal number of evaluations allowed. */
private int maxEvaluations;
/** Number of evaluations already performed. */
private int evaluations;
/** Build an enhanced integrator using internal differentiation to compute jacobians.
* @param integrator underlying integrator to solve the compound problem
* @param ode original problem (f in the equation y' = f(t, y))
* @param p parameters array (may be null if {@link
* ParameterizedODE#getParametersDimension()
* getParametersDimension()} from original problem is zero)
* @param hY step sizes to use for computing the jacobian df/dy, must have the
* same dimension as the original problem
* @param hP step sizes to use for computing the jacobian df/dp, must have the
* same dimension as the original problem parameters dimension
* @see #FirstOrderIntegratorWithJacobians(FirstOrderIntegrator,
* ODEWithJacobians)
*/
public FirstOrderIntegratorWithJacobians(final FirstOrderIntegrator integrator,
final ParameterizedODE ode,
final double[] p, final double[] hY, final double[] hP) {
checkDimension(ode.getDimension(), hY);
checkDimension(ode.getParametersDimension(), p);
checkDimension(ode.getParametersDimension(), hP);
this.integrator = integrator;
this.ode = new FiniteDifferencesWrapper(ode, p, hY, hP);
setMaxEvaluations(-1);
}
/** Build an enhanced integrator using ODE builtin jacobian computation features.
* @param integrator underlying integrator to solve the compound problem
* @param ode original problem, which can compute the jacobians by itself
* @see #FirstOrderIntegratorWithJacobians(FirstOrderIntegrator,
* ParameterizedODE, double[], double[], double[])
*/
public FirstOrderIntegratorWithJacobians(final FirstOrderIntegrator integrator,
final ODEWithJacobians ode) {
this.integrator = integrator;
this.ode = ode;
setMaxEvaluations(-1);
}
/** Add a step handler to this integrator.
* <p>The handler will be called by the integrator for each accepted
* step.</p>
* @param handler handler for the accepted steps
* @see #getStepHandlers()
* @see #clearStepHandlers()
*/
public void addStepHandler(StepHandlerWithJacobians handler) {
final int n = ode.getDimension();
final int k = ode.getParametersDimension();
integrator.addStepHandler(new StepHandlerWrapper(handler, n, k));
}
/** Get all the step handlers that have been added to the integrator.
* @return an unmodifiable collection of the added events handlers
* @see #addStepHandler(StepHandlerWithJacobians)
* @see #clearStepHandlers()
*/
public Collection<StepHandlerWithJacobians> getStepHandlers() {
final Collection<StepHandlerWithJacobians> handlers =
new ArrayList<StepHandlerWithJacobians>();
for (final StepHandler handler : integrator.getStepHandlers()) {
if (handler instanceof StepHandlerWrapper) {
handlers.add(((StepHandlerWrapper) handler).getHandler());
}
}
return handlers;
}
/** Remove all the step handlers that have been added to the integrator.
* @see #addStepHandler(StepHandlerWithJacobians)
* @see #getStepHandlers()
*/
public void clearStepHandlers() {
integrator.clearStepHandlers();
}
/** Add an event handler to the integrator.
* @param handler event handler
* @param maxCheckInterval maximal time interval between switching
* function checks (this interval prevents missing sign changes in
* case the integration steps becomes very large)
* @param convergence convergence threshold in the event time search
* @param maxIterationCount upper limit of the iteration count in
* the event time search
* @see #getEventHandlers()
* @see #clearEventHandlers()
*/
public void addEventHandler(EventHandlerWithJacobians handler,
double maxCheckInterval,
double convergence,
int maxIterationCount) {
final int n = ode.getDimension();
final int k = ode.getParametersDimension();
integrator.addEventHandler(new EventHandlerWrapper(handler, n, k),
maxCheckInterval, convergence, maxIterationCount);
}
/** Get all the event handlers that have been added to the integrator.
* @return an unmodifiable collection of the added events handlers
* @see #addEventHandler(EventHandlerWithJacobians, double, double, int)
* @see #clearEventHandlers()
*/
public Collection<EventHandlerWithJacobians> getEventHandlers() {
final Collection<EventHandlerWithJacobians> handlers =
new ArrayList<EventHandlerWithJacobians>();
for (final EventHandler handler : integrator.getEventHandlers()) {
if (handler instanceof EventHandlerWrapper) {
handlers.add(((EventHandlerWrapper) handler).getHandler());
}
}
return handlers;
}
/** Remove all the event handlers that have been added to the integrator.
* @see #addEventHandler(EventHandlerWithJacobians, double, double, int)
* @see #getEventHandlers()
*/
public void clearEventHandlers() {
integrator.clearEventHandlers();
}
/** Integrate the differential equations and the variational equations up to the given time.
* <p>This method solves an Initial Value Problem (IVP) and also computes the derivatives
* of the solution with respect to initial state and parameters. This can be used as
* a basis to solve Boundary Value Problems (BVP).</p>
* <p>Since this method stores some internal state variables made
* available in its public interface during integration ({@link
* #getCurrentSignedStepsize()}), it is <em>not</em> thread-safe.</p>
* @param t0 initial time
* @param y0 initial value of the state vector at t0
* @param dY0dP initial value of the state vector derivative with respect to the
* parameters at t0
* @param t target time for the integration
* (can be set to a value smaller than <code>t0</code> for backward integration)
* @param y placeholder where to put the state vector at each successful
* step (and hence at the end of integration), can be the same object as y0
* @param dYdY0 placeholder where to put the state vector derivative with respect
* to the initial state (dy[i]/dy0[j] is in element array dYdY0[i][j]) at each successful
* step (and hence at the end of integration)
* @param dYdP placeholder where to put the state vector derivative with respect
* to the parameters (dy[i]/dp[j] is in element array dYdP[i][j]) at each successful
* step (and hence at the end of integration)
* @return stop time, will be the same as target time if integration reached its
* target, but may be different if some event handler stops it at some point.
* @throws IntegratorException if the integrator cannot perform integration
* @throws DerivativeException this exception is propagated to the caller if
* the underlying user function triggers one
*/
public double integrate(final double t0, final double[] y0, final double[][] dY0dP,
final double t, final double[] y,
final double[][] dYdY0, final double[][] dYdP)
throws DerivativeException, IntegratorException {
final int n = ode.getDimension();
final int k = ode.getParametersDimension();
checkDimension(n, y0);
checkDimension(n, y);
checkDimension(n, dYdY0);
checkDimension(n, dYdY0[0]);
if (k != 0) {
checkDimension(n, dY0dP);
checkDimension(k, dY0dP[0]);
checkDimension(n, dYdP);
checkDimension(k, dYdP[0]);
}
// set up initial state, including partial derivatives
// the compound state z contains the raw state y and its derivatives
// with respect to initial state y0 and to parameters p
// y[i] is stored in z[i]
// dy[i]/dy0[j] is stored in z[n + i * n + j]
// dy[i]/dp[j] is stored in z[n * (n + 1) + i * k + j]
final double[] z = new double[n * (1 + n + k)];
System.arraycopy(y0, 0, z, 0, n);
for (int i = 0; i < n; ++i) {
// set diagonal element of dy/dy0 to 1.0 at t = t0
z[i * (1 + n) + n] = 1.0;
// set initial derivatives with respect to parameters
System.arraycopy(dY0dP[i], 0, z, n * (n + 1) + i * k, k);
}
// integrate the compound state variational equations
evaluations = 0;
final double stopTime = integrator.integrate(new MappingWrapper(), t0, z, t, z);
// dispatch the final compound state into the state and partial derivatives arrays
dispatchCompoundState(z, y, dYdY0, dYdP);
return stopTime;
}
/** Dispatch a compound state array into state and jacobians arrays.
* @param z compound state
* @param y raw state array to fill
* @param dydy0 jacobian array to fill
* @param dydp jacobian array to fill
*/
private static void dispatchCompoundState(final double[] z, final double[] y,
final double[][] dydy0, final double[][] dydp) {
final int n = y.length;
final int k = dydp[0].length;
// state
System.arraycopy(z, 0, y, 0, n);
// jacobian with respect to initial state
for (int i = 0; i < n; ++i) {
System.arraycopy(z, n * (i + 1), dydy0[i], 0, n);
}
// jacobian with respect to parameters
for (int i = 0; i < n; ++i) {
System.arraycopy(z, n * (n + 1) + i * k, dydp[i], 0, k);
}
}
/** Get the current value of the step start time t<sub>i</sub>.
* <p>This method can be called during integration (typically by
* the object implementing the {@link org.apache.commons.math.ode.FirstOrderDifferentialEquations
* differential equations} problem) if the value of the current step that
* is attempted is needed.</p>
* <p>The result is undefined if the method is called outside of
* calls to <code>integrate</code>.</p>
* @return current value of the step start time t<sub>i</sub>
*/
public double getCurrentStepStart() {
return integrator.getCurrentStepStart();
}
/** Get the current signed value of the integration stepsize.
* <p>This method can be called during integration (typically by
* the object implementing the {@link org.apache.commons.math.ode.FirstOrderDifferentialEquations
* differential equations} problem) if the signed value of the current stepsize
* that is tried is needed.</p>
* <p>The result is undefined if the method is called outside of
* calls to <code>integrate</code>.</p>
* @return current signed value of the stepsize
*/
public double getCurrentSignedStepsize() {
return integrator.getCurrentSignedStepsize();
}
/** Set the maximal number of differential equations function evaluations.
* <p>The purpose of this method is to avoid infinite loops which can occur
* for example when stringent error constraints are set or when lots of
* discrete events are triggered, thus leading to many rejected steps.</p>
* @param maxEvaluations maximal number of function evaluations (negative
* values are silently converted to maximal integer value, thus representing
* almost unlimited evaluations)
*/
public void setMaxEvaluations(int maxEvaluations) {
this.maxEvaluations = (maxEvaluations < 0) ? Integer.MAX_VALUE : maxEvaluations;
}
/** Get the maximal number of functions evaluations.
* @return maximal number of functions evaluations
*/
public int getMaxEvaluations() {
return maxEvaluations;
}
/** Get the number of evaluations of the differential equations function.
* <p>
* The number of evaluations corresponds to the last call to the
* <code>integrate</code> method. It is 0 if the method has not been called yet.
* </p>
* @return number of evaluations of the differential equations function
*/
public int getEvaluations() {
return evaluations;
}
/** Check array dimensions.
* @param expected expected dimension
* @param array (may be null if expected is 0)
* @throws IllegalArgumentException if the array dimension does not match the expected one
*/
private void checkDimension(final int expected, final Object array)
throws IllegalArgumentException {
int arrayDimension = (array == null) ? 0 : Array.getLength(array);
if (arrayDimension != expected) {
throw MathRuntimeException.createIllegalArgumentException(
LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, arrayDimension, expected);
}
}
/** Wrapper class used to map state and jacobians into compound state. */
private class MappingWrapper implements ExtendedFirstOrderDifferentialEquations {
/** Current state. */
private final double[] y;
/** Time derivative of the current state. */
private final double[] yDot;
/** Derivatives of yDot with respect to state. */
private final double[][] dFdY;
/** Derivatives of yDot with respect to parameters. */
private final double[][] dFdP;
/** Simple constructor.
*/
public MappingWrapper() {
final int n = ode.getDimension();
final int k = ode.getParametersDimension();
y = new double[n];
yDot = new double[n];
dFdY = new double[n][n];
dFdP = new double[n][k];
}
/** {@inheritDoc} */
public int getDimension() {
final int n = y.length;
final int k = dFdP[0].length;
return n * (1 + n + k);
}
/** {@inheritDoc} */
public int getMainSetDimension() {
return ode.getDimension();
}
/** {@inheritDoc} */
public void computeDerivatives(final double t, final double[] z, final double[] zDot)
throws DerivativeException {
final int n = y.length;
final int k = dFdP[0].length;
// compute raw ODE and its jacobians: dy/dt, d[dy/dt]/dy0 and d[dy/dt]/dp
System.arraycopy(z, 0, y, 0, n);
if (++evaluations > maxEvaluations) {
throw new DerivativeException(new MaxEvaluationsExceededException(maxEvaluations));
}
ode.computeDerivatives(t, y, yDot);
ode.computeJacobians(t, y, yDot, dFdY, dFdP);
// state part of the compound equations
System.arraycopy(yDot, 0, zDot, 0, n);
// variational equations: from d[dy/dt]/dy0 to d[dy/dy0]/dt
for (int i = 0; i < n; ++i) {
final double[] dFdYi = dFdY[i];
for (int j = 0; j < n; ++j) {
double s = 0;
final int startIndex = n + j;
int zIndex = startIndex;
for (int l = 0; l < n; ++l) {
s += dFdYi[l] * z[zIndex];
zIndex += n;
}
zDot[startIndex + i * n] = s;
}
}
// variational equations: from d[dy/dt]/dy0 and d[dy/dt]/dp to d[dy/dp]/dt
for (int i = 0; i < n; ++i) {
final double[] dFdYi = dFdY[i];
final double[] dFdPi = dFdP[i];
for (int j = 0; j < k; ++j) {
double s = dFdPi[j];
final int startIndex = n * (n + 1) + j;
int zIndex = startIndex;
for (int l = 0; l < n; ++l) {
s += dFdYi[l] * z[zIndex];
zIndex += k;
}
zDot[startIndex + i * k] = s;
}
}
}
}
/** Wrapper class to compute jacobians by finite differences for ODE which do not compute them themselves. */
private class FiniteDifferencesWrapper implements ODEWithJacobians {
/** Raw ODE without jacobians computation. */
private final ParameterizedODE ode;
/** Parameters array (may be null if parameters dimension from original problem is zero) */
private final double[] p;
/** Step sizes to use for computing the jacobian df/dy. */
private final double[] hY;
/** Step sizes to use for computing the jacobian df/dp. */
private final double[] hP;
/** Temporary array for state derivatives used to compute jacobians. */
private final double[] tmpDot;
/** Simple constructor.
* @param ode original ODE problem, without jacobians computations
* @param p parameters array (may be null if parameters dimension from original problem is zero)
* @param hY step sizes to use for computing the jacobian df/dy
* @param hP step sizes to use for computing the jacobian df/dp
*/
public FiniteDifferencesWrapper(final ParameterizedODE ode,
final double[] p, final double[] hY, final double[] hP) {
this.ode = ode;
this.p = p.clone();
this.hY = hY.clone();
this.hP = hP.clone();
tmpDot = new double[ode.getDimension()];
}
/** {@inheritDoc} */
public int getDimension() {
return ode.getDimension();
}
/** {@inheritDoc} */
public void computeDerivatives(double t, double[] y, double[] yDot) throws DerivativeException {
// this call to computeDerivatives has already been counted,
// we must not increment the counter again
ode.computeDerivatives(t, y, yDot);
}
/** {@inheritDoc} */
public int getParametersDimension() {
return ode.getParametersDimension();
}
/** {@inheritDoc} */
public void computeJacobians(double t, double[] y, double[] yDot,
double[][] dFdY, double[][] dFdP)
throws DerivativeException {
final int n = hY.length;
final int k = hP.length;
evaluations += n + k;
if (evaluations > maxEvaluations) {
throw new DerivativeException(new MaxEvaluationsExceededException(maxEvaluations));
}
// compute df/dy where f is the ODE and y is the state array
for (int j = 0; j < n; ++j) {
final double savedYj = y[j];
y[j] += hY[j];
ode.computeDerivatives(t, y, tmpDot);
for (int i = 0; i < n; ++i) {
dFdY[i][j] = (tmpDot[i] - yDot[i]) / hY[j];
}
y[j] = savedYj;
}
// compute df/dp where f is the ODE and p is the parameters array
for (int j = 0; j < k; ++j) {
ode.setParameter(j, p[j] + hP[j]);
ode.computeDerivatives(t, y, tmpDot);
for (int i = 0; i < n; ++i) {
dFdP[i][j] = (tmpDot[i] - yDot[i]) / hP[j];
}
ode.setParameter(j, p[j]);
}
}
}
/** Wrapper for step handlers. */
private static class StepHandlerWrapper implements StepHandler {
/** Underlying step handler with jacobians. */
private final StepHandlerWithJacobians handler;
/** Dimension of the original ODE. */
private final int n;
/** Number of parameters. */
private final int k;
/** Simple constructor.
* @param handler underlying step handler with jacobians
* @param n dimension of the original ODE
* @param k number of parameters
*/
public StepHandlerWrapper(final StepHandlerWithJacobians handler,
final int n, final int k) {
this.handler = handler;
this.n = n;
this.k = k;
}
/** Get the underlying step handler with jacobians.
* @return underlying step handler with jacobians
*/
public StepHandlerWithJacobians getHandler() {
return handler;
}
/** {@inheritDoc} */
public void handleStep(StepInterpolator interpolator, boolean isLast)
throws DerivativeException {
handler.handleStep(new StepInterpolatorWrapper(interpolator, n, k), isLast);
}
/** {@inheritDoc} */
public boolean requiresDenseOutput() {
return handler.requiresDenseOutput();
}
/** {@inheritDoc} */
public void reset() {
handler.reset();
}
}
/** Wrapper for step interpolators. */
private static class StepInterpolatorWrapper
implements StepInterpolatorWithJacobians {
/** Wrapped interpolator. */
private StepInterpolator interpolator;
/** State array. */
private double[] y;
/** Jacobian with respect to initial state dy/dy0. */
private double[][] dydy0;
/** Jacobian with respect to parameters dy/dp. */
private double[][] dydp;
/** Time derivative of the state array. */
private double[] yDot;
/** Time derivative of the sacobian with respect to initial state dy/dy0. */
private double[][] dydy0Dot;
/** Time derivative of the jacobian with respect to parameters dy/dp. */
private double[][] dydpDot;
/** Simple constructor.
* <p>This constructor is used only for externalization. It does nothing.</p>
*/
@SuppressWarnings("unused")
public StepInterpolatorWrapper() {
}
/** Simple constructor.
* @param interpolator wrapped interpolator
* @param n dimension of the original ODE
* @param k number of parameters
*/
public StepInterpolatorWrapper(final StepInterpolator interpolator,
final int n, final int k) {
this.interpolator = interpolator;
y = new double[n];
dydy0 = new double[n][n];
dydp = new double[n][k];
yDot = new double[n];
dydy0Dot = new double[n][n];
dydpDot = new double[n][k];
}
/** {@inheritDoc} */
public void setInterpolatedTime(double time) {
interpolator.setInterpolatedTime(time);
}
/** {@inheritDoc} */
public boolean isForward() {
return interpolator.isForward();
}
/** {@inheritDoc} */
public double getPreviousTime() {
return interpolator.getPreviousTime();
}
/** {@inheritDoc} */
public double getInterpolatedTime() {
return interpolator.getInterpolatedTime();
}
/** {@inheritDoc} */
public double[] getInterpolatedY() throws DerivativeException {
double[] extendedState = interpolator.getInterpolatedState();
System.arraycopy(extendedState, 0, y, 0, y.length);
return y;
}
/** {@inheritDoc} */
public double[][] getInterpolatedDyDy0() throws DerivativeException {
double[] extendedState = interpolator.getInterpolatedState();
final int n = y.length;
int start = n;
for (int i = 0; i < n; ++i) {
System.arraycopy(extendedState, start, dydy0[i], 0, n);
start += n;
}
return dydy0;
}
/** {@inheritDoc} */
public double[][] getInterpolatedDyDp() throws DerivativeException {
double[] extendedState = interpolator.getInterpolatedState();
final int n = y.length;
final int k = dydp[0].length;
int start = n * (n + 1);
for (int i = 0; i < n; ++i) {
System.arraycopy(extendedState, start, dydp[i], 0, k);
start += k;
}
return dydp;
}
/** {@inheritDoc} */
public double[] getInterpolatedYDot() throws DerivativeException {
double[] extendedDerivatives = interpolator.getInterpolatedDerivatives();
System.arraycopy(extendedDerivatives, 0, yDot, 0, yDot.length);
return yDot;
}
/** {@inheritDoc} */
public double[][] getInterpolatedDyDy0Dot() throws DerivativeException {
double[] extendedDerivatives = interpolator.getInterpolatedDerivatives();
final int n = y.length;
int start = n;
for (int i = 0; i < n; ++i) {
System.arraycopy(extendedDerivatives, start, dydy0Dot[i], 0, n);
start += n;
}
return dydy0Dot;
}
/** {@inheritDoc} */
public double[][] getInterpolatedDyDpDot() throws DerivativeException {
double[] extendedDerivatives = interpolator.getInterpolatedDerivatives();
final int n = y.length;
final int k = dydpDot[0].length;
int start = n * (n + 1);
for (int i = 0; i < n; ++i) {
System.arraycopy(extendedDerivatives, start, dydpDot[i], 0, k);
start += k;
}
return dydpDot;
}
/** {@inheritDoc} */
public double getCurrentTime() {
return interpolator.getCurrentTime();
}
/** {@inheritDoc} */
public StepInterpolatorWithJacobians copy() throws DerivativeException {
final int n = y.length;
final int k = dydp[0].length;
StepInterpolatorWrapper copied =
new StepInterpolatorWrapper(interpolator.copy(), n, k);
copyArray(y, copied.y);
copyArray(dydy0, copied.dydy0);
copyArray(dydp, copied.dydp);
copyArray(yDot, copied.yDot);
copyArray(dydy0Dot, copied.dydy0Dot);
copyArray(dydpDot, copied.dydpDot);
return copied;
}
/** {@inheritDoc} */
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(interpolator);
out.writeInt(y.length);
out.writeInt(dydp[0].length);
writeArray(out, y);
writeArray(out, dydy0);
writeArray(out, dydp);
writeArray(out, yDot);
writeArray(out, dydy0Dot);
writeArray(out, dydpDot);
}
/** {@inheritDoc} */
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
interpolator = (StepInterpolator) in.readObject();
final int n = in.readInt();
final int k = in.readInt();
y = new double[n];
dydy0 = new double[n][n];
dydp = new double[n][k];
yDot = new double[n];
dydy0Dot = new double[n][n];
dydpDot = new double[n][k];
readArray(in, y);
readArray(in, dydy0);
readArray(in, dydp);
readArray(in, yDot);
readArray(in, dydy0Dot);
readArray(in, dydpDot);
}
/** Copy an array.
* @param src source array
* @param dest destination array
*/
private static void copyArray(final double[] src, final double[] dest) {
System.arraycopy(src, 0, dest, 0, src.length);
}
/** Copy an array.
* @param src source array
* @param dest destination array
*/
private static void copyArray(final double[][] src, final double[][] dest) {
for (int i = 0; i < src.length; ++i) {
copyArray(src[i], dest[i]);
}
}
/** Write an array.
* @param out output stream
* @param array array to write
* @exception IOException if array cannot be read
*/
private static void writeArray(final ObjectOutput out, final double[] array)
throws IOException {
for (int i = 0; i < array.length; ++i) {
out.writeDouble(array[i]);
}
}
/** Write an array.
* @param out output stream
* @param array array to write
* @exception IOException if array cannot be read
*/
private static void writeArray(final ObjectOutput out, final double[][] array)
throws IOException {
for (int i = 0; i < array.length; ++i) {
writeArray(out, array[i]);
}
}
/** Read an array.
* @param in input stream
* @param array array to read
* @exception IOException if array cannot be read
*/
private static void readArray(final ObjectInput in, final double[] array)
throws IOException {
for (int i = 0; i < array.length; ++i) {
array[i] = in.readDouble();
}
}
/** Read an array.
* @param in input stream
* @param array array to read
* @exception IOException if array cannot be read
*/
private static void readArray(final ObjectInput in, final double[][] array)
throws IOException {
for (int i = 0; i < array.length; ++i) {
readArray(in, array[i]);
}
}
}
/** Wrapper for event handlers. */
private static class EventHandlerWrapper implements EventHandler {
/** Underlying event handler with jacobians. */
private final EventHandlerWithJacobians handler;
/** State array. */
private double[] y;
/** Jacobian with respect to initial state dy/dy0. */
private double[][] dydy0;
/** Jacobian with respect to parameters dy/dp. */
private double[][] dydp;
/** Simple constructor.
* @param handler underlying event handler with jacobians
* @param n dimension of the original ODE
* @param k number of parameters
*/
public EventHandlerWrapper(final EventHandlerWithJacobians handler,
final int n, final int k) {
this.handler = handler;
y = new double[n];
dydy0 = new double[n][n];
dydp = new double[n][k];
}
/** Get the underlying event handler with jacobians.
* @return underlying event handler with jacobians
*/
public EventHandlerWithJacobians getHandler() {
return handler;
}
/** {@inheritDoc} */
public int eventOccurred(double t, double[] z, boolean increasing)
throws EventException {
dispatchCompoundState(z, y, dydy0, dydp);
return handler.eventOccurred(t, y, dydy0, dydp, increasing);
}
/** {@inheritDoc} */
public double g(double t, double[] z)
throws EventException {
dispatchCompoundState(z, y, dydy0, dydp);
return handler.g(t, y, dydy0, dydp);
}
/** {@inheritDoc} */
public void resetState(double t, double[] z)
throws EventException {
dispatchCompoundState(z, y, dydy0, dydp);
handler.resetState(t, y, dydy0, dydp);
}
}
}