| /* |
| * 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 × (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); |
| } |
| |
| } |
| |
| } |