removed the ode.jacobians package
Jira: MATH-380 git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1037343 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3859aa17cf
commit
22d63af83d
|
@ -1,224 +0,0 @@
|
|||
/*
|
||||
* 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 org.apache.commons.math.ode.events.EventException;
|
||||
|
||||
/** This interface represents a handler for discrete events triggered
|
||||
* during ODE integration.
|
||||
*
|
||||
* <p>Some events can be triggered at discrete times as an ODE problem
|
||||
* is solved. This occurs for example when the integration process
|
||||
* should be stopped as some state is reached (G-stop facility) when the
|
||||
* precise date is unknown a priori, or when the derivatives have
|
||||
* discontinuities, or simply when the user wants to monitor some
|
||||
* states boundaries crossings.
|
||||
* </p>
|
||||
*
|
||||
* <p>These events are defined as occurring when a <code>g</code>
|
||||
* switching function sign changes.</p>
|
||||
*
|
||||
* <p>Since events are only problem-dependent and are triggered by the
|
||||
* independent <i>time</i> variable and the state vector, they can
|
||||
* occur at virtually any time, unknown in advance. The integrators will
|
||||
* take care to avoid sign changes inside the steps, they will reduce
|
||||
* the step size when such an event is detected in order to put this
|
||||
* event exactly at the end of the current step. This guarantees that
|
||||
* step interpolation (which always has a one step scope) is relevant
|
||||
* even in presence of discontinuities. This is independent from the
|
||||
* stepsize control provided by integrators that monitor the local
|
||||
* error (this event handling feature is available for all integrators,
|
||||
* including fixed step ones).</p>
|
||||
*
|
||||
* <p>Note that is is possible to register a {@link
|
||||
* org.apache.commons.math.ode.events.EventHandler classical event handler}
|
||||
* in the low level integrator used to build a {@link FirstOrderIntegratorWithJacobians}
|
||||
* rather than implementing this class. The event handlers registered at low level
|
||||
* will see the big compound state whether the event handlers defined by this interface
|
||||
* see the original state, and its jacobians in separate arrays.</p>
|
||||
*
|
||||
* <p>The compound state is guaranteed to contain the original state in the first
|
||||
* elements, followed by the jacobian with respect to initial state (in row order),
|
||||
* followed by the jacobian with respect to parameters (in row order). If for example
|
||||
* the original state dimension is 6 and there are 3 parameters, the compound state will
|
||||
* be a 60 elements array. The first 6 elements will be the original state, the next 36
|
||||
* elements will be the jacobian with respect to initial state, and the remaining 18 elements
|
||||
* will be the jacobian with respect to parameters.</p>
|
||||
*
|
||||
* <p>Dealing with low level event handlers is cumbersome if one really needs the jacobians
|
||||
* in these methods, but it also prevents many data being copied back and forth between
|
||||
* state and jacobians on one side and compound state on the other side. So for performance
|
||||
* reasons, it is recommended to use this interface <em>only</em> if jacobians are really
|
||||
* needed and to use lower level handlers if only state is needed.</p>
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
* @since 2.1
|
||||
*/
|
||||
|
||||
public interface EventHandlerWithJacobians {
|
||||
|
||||
/** Stop indicator.
|
||||
* <p>This value should be used as the return value of the {@link
|
||||
* #eventOccurred eventOccurred} method when the integration should be
|
||||
* stopped after the event ending the current step.</p>
|
||||
*/
|
||||
int STOP = 0;
|
||||
|
||||
/** Reset state indicator.
|
||||
* <p>This value should be used as the return value of the {@link
|
||||
* #eventOccurred eventOccurred} method when the integration should
|
||||
* go on after the event ending the current step, with a new state
|
||||
* vector (which will be retrieved thanks to the {@link #resetState
|
||||
* resetState} method).</p>
|
||||
*/
|
||||
int RESET_STATE = 1;
|
||||
|
||||
/** Reset derivatives indicator.
|
||||
* <p>This value should be used as the return value of the {@link
|
||||
* #eventOccurred eventOccurred} method when the integration should
|
||||
* go on after the event ending the current step, with a new derivatives
|
||||
* vector (which will be retrieved thanks to the {@link
|
||||
* org.apache.commons.math.ode.FirstOrderDifferentialEquations#computeDerivatives}
|
||||
* method).</p>
|
||||
*/
|
||||
int RESET_DERIVATIVES = 2;
|
||||
|
||||
/** Continue indicator.
|
||||
* <p>This value should be used as the return value of the {@link
|
||||
* #eventOccurred eventOccurred} method when the integration should go
|
||||
* on after the event ending the current step.</p>
|
||||
*/
|
||||
int CONTINUE = 3;
|
||||
|
||||
/** Compute the value of the switching function.
|
||||
|
||||
* <p>The discrete events are generated when the sign of this
|
||||
* switching function changes. The integrator will take care to change
|
||||
* the stepsize in such a way these events occur exactly at step boundaries.
|
||||
* The switching function must be continuous in its roots neighborhood
|
||||
* (but not necessarily smooth), as the integrator will need to find its
|
||||
* roots to locate precisely the events.</p>
|
||||
|
||||
* @param t current value of the independent <i>time</i> variable
|
||||
* @param y array containing the current value of the state vector
|
||||
* @param dydy0 array containing the current value of the jacobian of
|
||||
* the state vector with respect to initial state
|
||||
* @param dydp array containing the current value of the jacobian of
|
||||
* the state vector with respect to parameters
|
||||
* @return value of the g switching function
|
||||
* @exception EventException if the switching function cannot be evaluated
|
||||
*/
|
||||
double g(double t, double[] y, double[][] dydy0, double[][] dydp)
|
||||
throws EventException;
|
||||
|
||||
/** Handle an event and choose what to do next.
|
||||
|
||||
* <p>This method is called when the integrator has accepted a step
|
||||
* ending exactly on a sign change of the function, just <em>before</em>
|
||||
* the step handler itself is called (see below for scheduling). It
|
||||
* allows the user to update his internal data to acknowledge the fact
|
||||
* the event has been handled (for example setting a flag in the {@link
|
||||
* org.apache.commons.math.ode.jacobians.ODEWithJacobians
|
||||
* differential equations} to switch the derivatives computation in
|
||||
* case of discontinuity), or to direct the integrator to either stop
|
||||
* or continue integration, possibly with a reset state or derivatives.</p>
|
||||
|
||||
* <ul>
|
||||
* <li>if {@link #STOP} is returned, the step handler will be called
|
||||
* with the <code>isLast</code> flag of the {@link
|
||||
* org.apache.commons.math.ode.jacobians.StepHandlerWithJacobians#handleStep(
|
||||
* StepInterpolatorWithJacobians, boolean) handleStep} method set to true and
|
||||
* the integration will be stopped,</li>
|
||||
* <li>if {@link #RESET_STATE} is returned, the {@link #resetState
|
||||
* resetState} method will be called once the step handler has
|
||||
* finished its task, and the integrator will also recompute the
|
||||
* derivatives,</li>
|
||||
* <li>if {@link #RESET_DERIVATIVES} is returned, the integrator
|
||||
* will recompute the derivatives,
|
||||
* <li>if {@link #CONTINUE} is returned, no specific action will
|
||||
* be taken (apart from having called this method) and integration
|
||||
* will continue.</li>
|
||||
* </ul>
|
||||
|
||||
* <p>The scheduling between this method and the {@link
|
||||
* org.apache.commons.math.ode.jacobians.StepHandlerWithJacobians
|
||||
* StepHandlerWithJacobians} method {@link
|
||||
* org.apache.commons.math.ode.jacobians.StepHandlerWithJacobians#handleStep(
|
||||
* StepInterpolatorWithJacobians, boolean) handleStep(interpolator, isLast)}
|
||||
* is to call this method first and <code>handleStep</code> afterwards. This
|
||||
* scheduling allows the integrator to pass <code>true</code> as the
|
||||
* <code>isLast</code> parameter to the step handler to make it aware the step
|
||||
* will be the last one if this method returns {@link #STOP}. As the
|
||||
* interpolator may be used to navigate back throughout the last step (as {@link
|
||||
* org.apache.commons.math.ode.sampling.StepNormalizer StepNormalizer}
|
||||
* does for example), user code called by this method and user
|
||||
* code called by step handlers may experience apparently out of order values
|
||||
* of the independent time variable. As an example, if the same user object
|
||||
* implements both this {@link EventHandlerWithJacobians EventHandler} interface and the
|
||||
* {@link org.apache.commons.math.ode.sampling.FixedStepHandler FixedStepHandler}
|
||||
* interface, a <em>forward</em> integration may call its
|
||||
* <code>eventOccurred</code> method with t = 10 first and call its
|
||||
* <code>handleStep</code> method with t = 9 afterwards. Such out of order
|
||||
* calls are limited to the size of the integration step for {@link
|
||||
* org.apache.commons.math.ode.sampling.StepHandler variable step handlers} and
|
||||
* to the size of the fixed step for {@link
|
||||
* org.apache.commons.math.ode.sampling.FixedStepHandler fixed step handlers}.</p>
|
||||
|
||||
* @param t current value of the independent <i>time</i> variable
|
||||
* @param y array containing the current value of the state vector
|
||||
* @param dydy0 array containing the current value of the jacobian of
|
||||
* the state vector with respect to initial state
|
||||
* @param dydp array containing the current value of the jacobian of
|
||||
* the state vector with respect to parameters
|
||||
* @param increasing if true, the value of the switching function increases
|
||||
* when times increases around event (note that increase is measured with respect
|
||||
* to physical time, not with respect to integration which may go backward in time)
|
||||
* @return indication of what the integrator should do next, this
|
||||
* value must be one of {@link #STOP}, {@link #RESET_STATE},
|
||||
* {@link #RESET_DERIVATIVES} or {@link #CONTINUE}
|
||||
* @exception EventException if the event occurrence triggers an error
|
||||
*/
|
||||
int eventOccurred(double t, double[] y, double[][] dydy0, double[][] dydp,
|
||||
boolean increasing) throws EventException;
|
||||
|
||||
/** Reset the state prior to continue the integration.
|
||||
|
||||
* <p>This method is called after the step handler has returned and
|
||||
* before the next step is started, but only when {@link
|
||||
* #eventOccurred} has itself returned the {@link #RESET_STATE}
|
||||
* indicator. It allows the user to reset the state vector for the
|
||||
* next step, without perturbing the step handler of the finishing
|
||||
* step. If the {@link #eventOccurred} never returns the {@link
|
||||
* #RESET_STATE} indicator, this function will never be called, and it is
|
||||
* safe to leave its body empty.</p>
|
||||
|
||||
* @param t current value of the independent <i>time</i> variable
|
||||
* @param y array containing the current value of the state vector
|
||||
* the new state should be put in the same array
|
||||
* @param dydy0 array containing the current value of the jacobian of
|
||||
* the state vector with respect to initial state, the new jacobian
|
||||
* should be put in the same array
|
||||
* @param dydp array containing the current value of the jacobian of
|
||||
* the state vector with respect to parameters, the new jacobian
|
||||
* should be put in the same array
|
||||
* @exception EventException if the state cannot be reseted
|
||||
*/
|
||||
void resetState(double t, double[] y, double[][] dydy0, double[][] dydp)
|
||||
throws EventException;
|
||||
|
||||
}
|
|
@ -1,896 +0,0 @@
|
|||
/*
|
||||
* 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.exception.MathUserException;
|
||||
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$ $Date$
|
||||
* @since 2.1
|
||||
*/
|
||||
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 MathUserException 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 MathUserException, 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 MathUserException {
|
||||
|
||||
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 MathUserException(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 MathUserException {
|
||||
// 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 MathUserException {
|
||||
|
||||
final int n = hY.length;
|
||||
final int k = hP.length;
|
||||
|
||||
evaluations += n + k;
|
||||
if (evaluations > maxEvaluations) {
|
||||
throw new MathUserException(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 MathUserException {
|
||||
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 MathUserException {
|
||||
double[] extendedState = interpolator.getInterpolatedState();
|
||||
System.arraycopy(extendedState, 0, y, 0, y.length);
|
||||
return y;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public double[][] getInterpolatedDyDy0() throws MathUserException {
|
||||
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 MathUserException {
|
||||
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 MathUserException {
|
||||
double[] extendedDerivatives = interpolator.getInterpolatedDerivatives();
|
||||
System.arraycopy(extendedDerivatives, 0, yDot, 0, yDot.length);
|
||||
return yDot;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public double[][] getInterpolatedDyDy0Dot() throws MathUserException {
|
||||
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 MathUserException {
|
||||
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 MathUserException {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* 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 org.apache.commons.math.exception.MathUserException;
|
||||
import org.apache.commons.math.ode.FirstOrderDifferentialEquations;
|
||||
|
||||
|
||||
/** This interface represents {@link ParameterizedODE
|
||||
* first order differential equations} with parameters and partial derivatives.
|
||||
*
|
||||
* @see FirstOrderIntegratorWithJacobians
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
* @since 2.1
|
||||
*/
|
||||
|
||||
public interface ODEWithJacobians extends FirstOrderDifferentialEquations {
|
||||
|
||||
/** Get the number of parameters.
|
||||
* @return number of parameters
|
||||
*/
|
||||
int getParametersDimension();
|
||||
|
||||
/** Compute the partial derivatives of ODE with respect to state.
|
||||
* @param t current value of the independent <I>time</I> variable
|
||||
* @param y array containing the current value of the state vector
|
||||
* @param yDot array containing the current value of the time derivative of the state vector
|
||||
* @param dFdY placeholder array where to put the jacobian of the ODE with respect to the state vector
|
||||
* @param dFdP placeholder array where to put the jacobian of the ODE with respect to the parameters
|
||||
* @throws MathUserException this exception is propagated to the caller if the
|
||||
* underlying user function triggers one
|
||||
*/
|
||||
void computeJacobians(double t, double[] y, double[] yDot, double[][] dFdY, double[][] dFdP)
|
||||
throws MathUserException;
|
||||
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* 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 org.apache.commons.math.ode.FirstOrderDifferentialEquations;
|
||||
|
||||
|
||||
/** This interface represents {@link FirstOrderDifferentialEquations
|
||||
* first order differential equations} with parameters.
|
||||
*
|
||||
* @see FirstOrderIntegratorWithJacobians
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
* @since 2.1
|
||||
*/
|
||||
|
||||
public interface ParameterizedODE extends FirstOrderDifferentialEquations {
|
||||
|
||||
/** Get the number of parameters.
|
||||
* @return number of parameters
|
||||
*/
|
||||
int getParametersDimension();
|
||||
|
||||
/** Set a parameter.
|
||||
* @param i index of the parameters (must be between 0
|
||||
* and {@link #getParametersDimension() getParametersDimension() - 1})
|
||||
* @param value value for the parameter
|
||||
*/
|
||||
void setParameter(int i, double value);
|
||||
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* 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 org.apache.commons.math.exception.MathUserException;
|
||||
|
||||
/**
|
||||
* This interface represents a handler that should be called after
|
||||
* each successful step.
|
||||
*
|
||||
* <p>The ODE integrators compute the evolution of the state vector at
|
||||
* some grid points that depend on their own internal algorithm. Once
|
||||
* they have found a new grid point (possibly after having computed
|
||||
* several evaluation of the derivative at intermediate points), they
|
||||
* provide it to objects implementing this interface. These objects
|
||||
* typically either ignore the intermediate steps and wait for the
|
||||
* last one, store the points in an ephemeris, or forward them to
|
||||
* specialized processing or output methods.</p>
|
||||
*
|
||||
* <p>Note that is is possible to register a {@link
|
||||
* org.apache.commons.math.ode.sampling.StepHandler classical step handler}
|
||||
* in the low level integrator used to build a {@link FirstOrderIntegratorWithJacobians}
|
||||
* rather than implementing this class. The step handlers registered at low level
|
||||
* will see the big compound state whether the step handlers defined by this interface
|
||||
* see the original state, and its jacobians in separate arrays.</p>
|
||||
*
|
||||
* <p>The compound state is guaranteed to contain the original state in the first
|
||||
* elements, followed by the jacobian with respect to initial state (in row order),
|
||||
* followed by the jacobian with respect to parameters (in row order). If for example
|
||||
* the original state dimension is 6 and there are 3 parameters, the compound state will
|
||||
* be a 60 elements array. The first 6 elements will be the original state, the next 36
|
||||
* elements will be the jacobian with respect to initial state, and the remaining 18 elements
|
||||
* will be the jacobian with respect to parameters.</p>
|
||||
*
|
||||
* <p>Dealing with low level step handlers is cumbersome if one really needs the jacobians
|
||||
* in these methods, but it also prevents many data being copied back and forth between
|
||||
* state and jacobians on one side and compound state on the other side. So for performance
|
||||
* reasons, it is recommended to use this interface <em>only</em> if jacobians are really
|
||||
* needed and to use lower level handlers if only state is needed.</p>
|
||||
*
|
||||
* @see FirstOrderIntegratorWithJacobians
|
||||
* @see StepInterpolatorWithJacobians
|
||||
* @version $Revision$ $Date$
|
||||
* @since 2.1
|
||||
*/
|
||||
|
||||
public interface StepHandlerWithJacobians {
|
||||
|
||||
/** Determines whether this handler needs dense output.
|
||||
* <p>This method allows the integrator to avoid performing extra
|
||||
* computation if the handler does not need dense output.</p>
|
||||
* @return true if the handler needs dense output
|
||||
*/
|
||||
boolean requiresDenseOutput();
|
||||
|
||||
/** Reset the step handler.
|
||||
* Initialize the internal data as required before the first step is
|
||||
* handled.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Handle the last accepted step
|
||||
* @param interpolator interpolator for the last accepted step. For
|
||||
* efficiency purposes, the various integrators reuse the same
|
||||
* object on each call, so if the instance wants to keep it across
|
||||
* all calls (for example to provide at the end of the integration a
|
||||
* continuous model valid throughout the integration range, as the
|
||||
* {@link org.apache.commons.math.ode.ContinuousOutputModel
|
||||
* ContinuousOutputModel} class does), it should build a local copy
|
||||
* using the clone method of the interpolator and store this copy.
|
||||
* Keeping only a reference to the interpolator and reusing it will
|
||||
* result in unpredictable behavior (potentially crashing the application).
|
||||
* @param isLast true if the step is the last one
|
||||
* @throws MathUserException this exception is propagated to the
|
||||
* caller if the underlying user function triggers one
|
||||
*/
|
||||
void handleStep(StepInterpolatorWithJacobians interpolator, boolean isLast) throws MathUserException;
|
||||
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* 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.Externalizable;
|
||||
|
||||
import org.apache.commons.math.exception.MathUserException;
|
||||
|
||||
/** This interface represents an interpolator over the last step
|
||||
* during an ODE integration.
|
||||
*
|
||||
* <p>The various ODE integrators provide objects implementing this
|
||||
* interface to the step handlers. These objects are often custom
|
||||
* objects tightly bound to the integrator internal algorithms. The
|
||||
* handlers can use these objects to retrieve the state vector at
|
||||
* intermediate times between the previous and the current grid points
|
||||
* (this feature is often called dense output).</p>
|
||||
* <p>One important thing to note is that the step handlers may be so
|
||||
* tightly bound to the integrators that they often share some internal
|
||||
* state arrays. This imply that one should <em>never</em> use a direct
|
||||
* reference to a step interpolator outside of the step handler, either
|
||||
* for future use or for use in another thread. If such a need arise, the
|
||||
* step interpolator <em>must</em> be copied using the dedicated
|
||||
* {@link #copy()} method.
|
||||
* </p>
|
||||
*
|
||||
* @see FirstOrderIntegratorWithJacobians
|
||||
* @see StepHandlerWithJacobians
|
||||
* @version $Revision$ $Date$
|
||||
* @since 2.1
|
||||
*/
|
||||
|
||||
public interface StepInterpolatorWithJacobians extends Externalizable {
|
||||
|
||||
/**
|
||||
* Get the previous grid point time.
|
||||
* @return previous grid point time
|
||||
*/
|
||||
double getPreviousTime();
|
||||
|
||||
/**
|
||||
* Get the current grid point time.
|
||||
* @return current grid point time
|
||||
*/
|
||||
double getCurrentTime();
|
||||
|
||||
/**
|
||||
* Get the time of the interpolated point.
|
||||
* If {@link #setInterpolatedTime} has not been called, it returns
|
||||
* the current grid point time.
|
||||
* @return interpolation point time
|
||||
*/
|
||||
double getInterpolatedTime();
|
||||
|
||||
/**
|
||||
* Set the time of the interpolated point.
|
||||
* <p>Setting the time outside of the current step is now allowed, but
|
||||
* should be used with care since the accuracy of the interpolator will
|
||||
* probably be very poor far from this step. This allowance has been
|
||||
* added to simplify implementation of search algorithms near the
|
||||
* step endpoints.</p>
|
||||
* <p>Setting the time changes the instance internal state. If a
|
||||
* specific state must be preserved, a copy of the instance must be
|
||||
* created using {@link #copy()}.</p>
|
||||
* @param time time of the interpolated point
|
||||
*/
|
||||
void setInterpolatedTime(double time);
|
||||
|
||||
/**
|
||||
* Get the state vector of the interpolated point.
|
||||
* <p>The returned vector is a reference to a reused array, so
|
||||
* it should not be modified and it should be copied if it needs
|
||||
* to be preserved across several calls.</p>
|
||||
* @return state vector at time {@link #getInterpolatedTime}
|
||||
* @see #getInterpolatedYDot()
|
||||
* @throws MathUserException if this call induces an automatic
|
||||
* step finalization that throws one
|
||||
*/
|
||||
double[] getInterpolatedY() throws MathUserException;
|
||||
|
||||
/**
|
||||
* Get the partial derivatives of the state vector with respect to
|
||||
* the initial state of the interpolated point.
|
||||
* <p>The returned vector is a reference to a reused array, so
|
||||
* it should not be modified and it should be copied if it needs
|
||||
* to be preserved across several calls.</p>
|
||||
* @return partial derivatives of the state vector with respect to
|
||||
* the initial state at time {@link #getInterpolatedTime}
|
||||
* @see #getInterpolatedY()
|
||||
* @throws MathUserException if this call induces an automatic
|
||||
* step finalization that throws one
|
||||
*/
|
||||
double[][] getInterpolatedDyDy0() throws MathUserException;
|
||||
|
||||
/**
|
||||
* Get the partial derivatives of the state vector with respect to
|
||||
* the ODE parameters of the interpolated point.
|
||||
* <p>The returned vector is a reference to a reused array, so
|
||||
* it should not be modified and it should be copied if it needs
|
||||
* to be preserved across several calls.</p>
|
||||
* @return partial derivatives of the state vector with respect to
|
||||
* the ODE parameters at time {@link #getInterpolatedTime}
|
||||
* @see #getInterpolatedY()
|
||||
* @throws MathUserException if this call induces an automatic
|
||||
* step finalization that throws one
|
||||
*/
|
||||
double[][] getInterpolatedDyDp() throws MathUserException;
|
||||
|
||||
/**
|
||||
* Get the time derivatives of the state vector of the interpolated point.
|
||||
* <p>The returned vector is a reference to a reused array, so
|
||||
* it should not be modified and it should be copied if it needs
|
||||
* to be preserved across several calls.</p>
|
||||
* @return derivatives of the state vector at time {@link #getInterpolatedTime}
|
||||
* @see #getInterpolatedY()
|
||||
* @throws MathUserException if this call induces an automatic
|
||||
* step finalization that throws one
|
||||
*/
|
||||
double[] getInterpolatedYDot() throws MathUserException;
|
||||
|
||||
/**
|
||||
* Get the time derivatives of the jacobian of the state vector
|
||||
* with respect to the initial state of the interpolated point.
|
||||
* <p>The returned vector is a reference to a reused array, so
|
||||
* it should not be modified and it should be copied if it needs
|
||||
* to be preserved across several calls.</p>
|
||||
* @return time derivatives of the jacobian of the state vector
|
||||
* with respect to the initial state at time {@link #getInterpolatedTime}
|
||||
* @see #getInterpolatedY()
|
||||
* @throws MathUserException if this call induces an automatic
|
||||
* step finalization that throws one
|
||||
*/
|
||||
double[][] getInterpolatedDyDy0Dot() throws MathUserException;
|
||||
|
||||
/**
|
||||
* Get the time derivatives of the jacobian of the state vector
|
||||
* with respect to the ODE parameters of the interpolated point.
|
||||
* <p>The returned vector is a reference to a reused array, so
|
||||
* it should not be modified and it should be copied if it needs
|
||||
* to be preserved across several calls.</p>
|
||||
* @return time derivatives of the jacobian of the state vector
|
||||
* with respect to the ODE parameters at time {@link #getInterpolatedTime}
|
||||
* @see #getInterpolatedY()
|
||||
* @throws MathUserException if this call induces an automatic
|
||||
* step finalization that throws one
|
||||
*/
|
||||
double[][] getInterpolatedDyDpDot() throws MathUserException;
|
||||
|
||||
/** Check if the natural integration direction is forward.
|
||||
* <p>This method provides the integration direction as specified by
|
||||
* the integrator itself, it avoid some nasty problems in
|
||||
* degenerated cases like null steps due to cancellation at step
|
||||
* initialization, step control or discrete events
|
||||
* triggering.</p>
|
||||
* @return true if the integration variable (time) increases during
|
||||
* integration
|
||||
*/
|
||||
boolean isForward();
|
||||
|
||||
/** Copy the instance.
|
||||
* <p>The copied instance is guaranteed to be independent from the
|
||||
* original one. Both can be used with different settings for
|
||||
* interpolated time without any side effect.</p>
|
||||
* @return a deep copy of the instance, which can be used independently.
|
||||
* @throws MathUserException if this call induces an automatic
|
||||
* step finalization that throws one
|
||||
* @see #setInterpolatedTime(double)
|
||||
*/
|
||||
StepInterpolatorWithJacobians copy() throws MathUserException;
|
||||
|
||||
}
|
|
@ -1,237 +0,0 @@
|
|||
<html>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<!-- $Revision$ -->
|
||||
<body>
|
||||
<p>
|
||||
This package provides classes to solve Ordinary Differential Equations problems
|
||||
and also compute derivatives of the solution.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This package solves Initial Value Problems of the form
|
||||
<code>y'=f(t,y,p)</code> with <code>t<sub>0</sub></code>,
|
||||
<code>y(t<sub>0</sub>)=y<sub>0</sub></code> and
|
||||
<code>dy(t<sub>0</sub>)/dp</sub></code> known. The provided
|
||||
integrator computes estimates of <code>y(t)</code>,
|
||||
<code>dy(t)/dy<sub>0</sub></code> and <code>dy(t)/dp</code>
|
||||
from <code>t=t<sub>0</sub></code> to <code>t=t<sub>1</sub></code>,
|
||||
where <code>y</code> is the state and <code>p</code> is a parameters
|
||||
array.
|
||||
</p>
|
||||
<p>
|
||||
The classes in this package mimic the behavior of classes and interfaces from the
|
||||
<a href="../package-summary.html">org.apache.commons.math.ode</a>,
|
||||
<a href="../events/package-summary.html">org.apache.commons.math.ode.events</a>
|
||||
and <a href="../sampling/package-summary.html">org.apache.commons.math.ode.sampling</a>
|
||||
packages, adding the jacobians <code>dy(t)/dy<sub>0</sub></code> and
|
||||
<code>dy(t)/dp</code> to the methods signatures.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The classes and interfaces in this package mimic the behavior of the classes and
|
||||
interfaces of the top level ode package, only adding parameters arrays for the jacobians.
|
||||
The behavior of these classes is to create a compound state vector z containing both
|
||||
the state y(t) and its derivatives dy(t)/dy<sub>0</sub> and dy(t<sub>0</sub>)/dp and
|
||||
to set up an extended problem by adding the equations for the jacobians automatically.
|
||||
These extended state and problems are then provided to a classical underlying integrator
|
||||
chosen by user.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This behavior imply there will be a top level integrator knowing about state and jacobians
|
||||
and a low level integrator knowing only about compound state (which may be big). If the user
|
||||
wants to deal with the top level only, he will use the specialized step handler and event
|
||||
handler classes registered at top level. He can also register classical step handlers and
|
||||
event handlers, but in this case will see the big compound state. This state is guaranteed
|
||||
to contain the original state in the first elements, followed by the jacobian with respect
|
||||
to initial state (in row order), followed by the jacobian with respect to parameters (in
|
||||
row order). If for example the original state dimension is 6 and there are 3 parameters,
|
||||
the compound state will be a 60 elements array. The first 6 elements will be the original
|
||||
state, the next 36 elements will be the jacobian with respect to initial state, and the
|
||||
remaining 18 will be the jacobian with respect to parameters. Dealing with low level
|
||||
step handlers and event handlers is cumbersome if one really needs the jacobians in these
|
||||
methods, but it also prevents many data being copied back and forth between state and
|
||||
jacobians on one side and compound state on the other side.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here is a simple example of usage. We consider a two-dimensional problem where the
|
||||
state vector y is the solution of the ordinary differential equations
|
||||
<ul>
|
||||
<li>y'<sub>0</sub>(t) = ω × (c<sub>1</sub> - y<sub>1</sub>(t))</li>
|
||||
<li>y'<sub>1</sub>(t) = ω × (y<sub>0</sub>(t) - c<sub>0</sub>)</li>
|
||||
</ul>
|
||||
with some initial state y(t<sub>0</sub>) = (y<sub>0</sub>(t<sub>0</sub>),
|
||||
y<sub>1</sub>(t<sub>0</sub>)).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The point trajectory depends on the initial state y(t<sub>0</sub>) and on the ODE
|
||||
parameter ω. We want to compute both the final point position y(t<sub>end</sub>)
|
||||
and the sensitivity of this point with respect to the initial state:
|
||||
dy(t<sub>end</sub>)/dy(t<sub>0</sub>) which is a 2×2 matrix and its sensitivity
|
||||
with respect to the parameter: dy(t<sub>end</sub>)/dω which is a 2×1 matrix.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We consider first the simplest implementation: we define only the ODE and let
|
||||
the classes compute the necessary jacobians by itself:
|
||||
<code><pre>
|
||||
public class BasicCircleODE implements ParameterizedODE {
|
||||
|
||||
private double[] c;
|
||||
private double omega;
|
||||
|
||||
public BasicCircleODE(double[] c, double omega) {
|
||||
this.c = c;
|
||||
this.omega = omega;
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public void computeDerivatives(double t, double[] y, double[] yDot) {
|
||||
yDot[0] = omega * (c[1] - y[1]);
|
||||
yDot[1] = omega * (y[0] - c[0]);
|
||||
}
|
||||
|
||||
public int getParametersDimension() {
|
||||
// we are only interested in the omega parameter
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void setParameter(int i, double value) {
|
||||
omega = value;
|
||||
}
|
||||
|
||||
}
|
||||
</pre></code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We compute the results we want as follows:
|
||||
<code><pre>
|
||||
// low level integrator
|
||||
FirstOrderIntegrator lowIntegrator =
|
||||
new DormandPrince54Integrator(1.0e-8, 100.0, 1.0e-10, 1.0e-10);
|
||||
|
||||
// set up ODE
|
||||
double cx = 1.0;
|
||||
double cy = 1.0;
|
||||
double omega = 0.1;
|
||||
ParameterizedODE ode = new BasicCircleODE(new double[] { cx, cy }, omega);
|
||||
|
||||
// set up high level integrator, using finite differences step hY and hP to compute jacobians
|
||||
double[] hY = new double[] { 1.0e-5, 1.0e-5 };
|
||||
double[] hP = new double[] { 1.0e-5 };
|
||||
FirstOrderIntegratorWithJacobians integrator =
|
||||
new FirstOrderIntegratorWithJacobians(lowIntegrator, ode, hY, hP);
|
||||
|
||||
// set up initial state and derivatives
|
||||
double t0 = 0.0;
|
||||
double[] y0 = new double[] { 0.0, cy };
|
||||
double[][] dy0dp = new double[2][1] = { { 0.0 }, { 0.0 } }; // y0 does not depend on omega
|
||||
|
||||
// solve problem
|
||||
double t = Math.PI / (2 * omega);
|
||||
double[] y = new double[2];
|
||||
double[][] dydy0 = new double[2][2];
|
||||
double[][] dydp = new double[2][1];
|
||||
integrator.integrate(t0, y0, dy0dp, t, y, dydy0, dydp);
|
||||
</pre></code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If in addition to getting the end state and its derivatives, we want to print the state
|
||||
throughout integration process, we have to register a step handler. Inserting the following
|
||||
before the call to integrate does the trick:
|
||||
<code><pre>
|
||||
StpeHandlerWithJacobians stepHandler = new StpeHandlerWithJacobians() {
|
||||
public void reset() {}
|
||||
|
||||
public boolean requiresDenseOutput() { return false; }
|
||||
|
||||
public void handleStep(StepInterpolatorWithJacobians interpolator, boolean isLast)
|
||||
throws DerivativeException {
|
||||
double t = interpolator.getCurrentTime();
|
||||
double[] y = interpolator.getInterpolatedY();
|
||||
System.out.println(t + " " + y[0] + " " + y[1]);
|
||||
}
|
||||
};
|
||||
integrator.addStepHandler(stepHandler);
|
||||
</pre></code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The implementation above relies on finite differences with small step sizes to compute the
|
||||
internal jacobians. Since the ODE is really simple here, a better way is to compute them
|
||||
exactly. So instead of implementing ParameterizedODE, we implement the ODEWithJacobians
|
||||
interface as follows (i.e. we replace the setParameter method by a computeJacobians method):
|
||||
<code><pre>
|
||||
public class EnhancedCircleODE implements ODEWithJacobians {
|
||||
|
||||
private double[] c;
|
||||
private double omega;
|
||||
|
||||
public EnhancedCircleODE(double[] c, double omega) {
|
||||
this.c = c;
|
||||
this.omega = omega;
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public void computeDerivatives(double t, double[] y, double[] yDot) {
|
||||
yDot[0] = omega * (c[1] - y[1]);
|
||||
yDot[1] = omega * (y[0] - c[0]);
|
||||
}
|
||||
|
||||
public int getParametersDimension() {
|
||||
// we are only interested in the omega parameter
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void computeJacobians(double t, double[] y, double[] yDot, double[][] dFdY, double[][] dFdP) {
|
||||
|
||||
dFdY[0][0] = 0;
|
||||
dFdY[0][1] = -omega;
|
||||
dFdY[1][0] = omega;
|
||||
dFdY[1][1] = 0;
|
||||
|
||||
dFdP[0][0] = 0;
|
||||
dFdP[0][1] = omega;
|
||||
dFdP[0][2] = c[1] - y[1];
|
||||
dFdP[1][0] = -omega;
|
||||
dFdP[1][1] = 0;
|
||||
dFdP[1][2] = y[0] - c[0];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</pre></code>
|
||||
With this implementation, the hY and hP arrays are not needed anymore:
|
||||
<code><pre>
|
||||
ODEWithJacobians ode = new EnhancedCircleODE(new double[] { cx, cy }, omega);
|
||||
FirstOrderIntegratorWithJacobians integrator =
|
||||
new FirstOrderIntegratorWithJacobians(lowIntegrator, ode);
|
||||
</pre></code>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -52,6 +52,9 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
If the output is not quite correct, check for invisible trailing spaces!
|
||||
-->
|
||||
<release version="3.0" date="TBD" description="TBD">
|
||||
<action dev="luc" type="fix" issue="MATH-380">
|
||||
Removed the ode.jacobians package.
|
||||
</action>
|
||||
<action dev="erans" type="update" issue="MATH-440">
|
||||
Removed classes "FunctionEvaluationException", "MatrixVisitorException"
|
||||
and "DerivativeException" (superseded by the new "MathUserException").
|
||||
|
@ -105,6 +108,11 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
</action>
|
||||
</release>
|
||||
<release version="2.2" date="TBD" description="TBD">
|
||||
<action dev="luc" type="fix" issue="MATH-380">
|
||||
Deprecated the whole ode.jacobians package. It is clumsy and difficult to use. It will
|
||||
be replaced by a completely rewritten implementation in 3.0, which will be more tightly
|
||||
bound to the top level ode package
|
||||
</action>
|
||||
<action dev="luc" type="fix" issue="MATH-426" due-to="Erik van Ingen">
|
||||
Added a normalization feature to transform samples so they have zero mean and unit standard deviation
|
||||
</action>
|
||||
|
|
|
@ -1,436 +0,0 @@
|
|||
/*
|
||||
* 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 org.apache.commons.math.exception.MathUserException;
|
||||
import org.apache.commons.math.ode.FirstOrderIntegrator;
|
||||
import org.apache.commons.math.ode.IntegratorException;
|
||||
import org.apache.commons.math.ode.nonstiff.DormandPrince54Integrator;
|
||||
import org.apache.commons.math.stat.descriptive.SummaryStatistics;
|
||||
import org.apache.commons.math.util.FastMath;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FirstOrderIntegratorWithJacobiansTest {
|
||||
|
||||
@Test
|
||||
public void testLowAccuracyExternalDifferentiation()
|
||||
throws IntegratorException, MathUserException {
|
||||
// this test does not really test FirstOrderIntegratorWithJacobians,
|
||||
// it only shows that WITHOUT this class, attempting to recover
|
||||
// the jacobians from external differentiation on simple integration
|
||||
// results with low accuracy gives very poor results. In fact,
|
||||
// the curves dy/dp = g(b) when b varies from 2.88 to 3.08 are
|
||||
// essentially noise.
|
||||
// This test is taken from Hairer, Norsett and Wanner book
|
||||
// Solving Ordinary Differential Equations I (Nonstiff problems),
|
||||
// the curves dy/dp = g(b) are in figure 6.5
|
||||
FirstOrderIntegrator integ =
|
||||
new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-4, 1.0e-4 }, new double[] { 1.0e-4, 1.0e-4 });
|
||||
double hP = 1.0e-12;
|
||||
SummaryStatistics residualsP0 = new SummaryStatistics();
|
||||
SummaryStatistics residualsP1 = new SummaryStatistics();
|
||||
for (double b = 2.88; b < 3.08; b += 0.001) {
|
||||
Brusselator brusselator = new Brusselator(b);
|
||||
double[] y = { 1.3, b };
|
||||
integ.integrate(brusselator, 0, y, 20.0, y);
|
||||
double[] yP = { 1.3, b + hP };
|
||||
brusselator.setParameter(0, b + hP);
|
||||
integ.integrate(brusselator, 0, yP, 20.0, yP);
|
||||
residualsP0.addValue((yP[0] - y[0]) / hP - brusselator.dYdP0());
|
||||
residualsP1.addValue((yP[1] - y[1]) / hP - brusselator.dYdP1());
|
||||
}
|
||||
Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) > 600);
|
||||
Assert.assertTrue(residualsP0.getStandardDeviation() > 30);
|
||||
Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) > 800);
|
||||
Assert.assertTrue(residualsP1.getStandardDeviation() > 50);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighAccuracyExternalDifferentiation()
|
||||
throws IntegratorException, MathUserException {
|
||||
FirstOrderIntegrator integ =
|
||||
new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 });
|
||||
double hP = 1.0e-12;
|
||||
SummaryStatistics residualsP0 = new SummaryStatistics();
|
||||
SummaryStatistics residualsP1 = new SummaryStatistics();
|
||||
for (double b = 2.88; b < 3.08; b += 0.001) {
|
||||
Brusselator brusselator = new Brusselator(b);
|
||||
double[] y = { 1.3, b };
|
||||
integ.integrate(brusselator, 0, y, 20.0, y);
|
||||
double[] yP = { 1.3, b + hP };
|
||||
brusselator.setParameter(0, b + hP);
|
||||
integ.integrate(brusselator, 0, yP, 20.0, yP);
|
||||
residualsP0.addValue((yP[0] - y[0]) / hP - brusselator.dYdP0());
|
||||
residualsP1.addValue((yP[1] - y[1]) / hP - brusselator.dYdP1());
|
||||
}
|
||||
Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) > 0.02);
|
||||
Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.03);
|
||||
Assert.assertTrue(residualsP0.getStandardDeviation() > 0.003);
|
||||
Assert.assertTrue(residualsP0.getStandardDeviation() < 0.004);
|
||||
Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) > 0.04);
|
||||
Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.05);
|
||||
Assert.assertTrue(residualsP1.getStandardDeviation() > 0.007);
|
||||
Assert.assertTrue(residualsP1.getStandardDeviation() < 0.008);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInternalDifferentiation()
|
||||
throws IntegratorException, MathUserException {
|
||||
FirstOrderIntegrator integ =
|
||||
new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-4, 1.0e-4 }, new double[] { 1.0e-4, 1.0e-4 });
|
||||
double hP = 1.0e-12;
|
||||
SummaryStatistics residualsP0 = new SummaryStatistics();
|
||||
SummaryStatistics residualsP1 = new SummaryStatistics();
|
||||
for (double b = 2.88; b < 3.08; b += 0.001) {
|
||||
Brusselator brusselator = new Brusselator(b);
|
||||
brusselator.setParameter(0, b);
|
||||
double[] z = { 1.3, b };
|
||||
double[][] dZdZ0 = new double[2][2];
|
||||
double[][] dZdP = new double[2][1];
|
||||
double hY = 1.0e-12;
|
||||
FirstOrderIntegratorWithJacobians extInt =
|
||||
new FirstOrderIntegratorWithJacobians(integ, brusselator, new double[] { b },
|
||||
new double[] { hY, hY }, new double[] { hP });
|
||||
extInt.setMaxEvaluations(5000);
|
||||
extInt.integrate(0, z, new double[][] { { 0.0 }, { 1.0 } }, 20.0, z, dZdZ0, dZdP);
|
||||
Assert.assertEquals(5000, extInt.getMaxEvaluations());
|
||||
Assert.assertTrue(extInt.getEvaluations() > 1500);
|
||||
Assert.assertTrue(extInt.getEvaluations() < 2100);
|
||||
Assert.assertEquals(4 * integ.getEvaluations(), extInt.getEvaluations());
|
||||
residualsP0.addValue(dZdP[0][0] - brusselator.dYdP0());
|
||||
residualsP1.addValue(dZdP[1][0] - brusselator.dYdP1());
|
||||
}
|
||||
Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.02);
|
||||
Assert.assertTrue(residualsP0.getStandardDeviation() < 0.003);
|
||||
Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.05);
|
||||
Assert.assertTrue(residualsP1.getStandardDeviation() < 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnalyticalDifferentiation()
|
||||
throws IntegratorException, MathUserException {
|
||||
FirstOrderIntegrator integ =
|
||||
new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-4, 1.0e-4 }, new double[] { 1.0e-4, 1.0e-4 });
|
||||
SummaryStatistics residualsP0 = new SummaryStatistics();
|
||||
SummaryStatistics residualsP1 = new SummaryStatistics();
|
||||
for (double b = 2.88; b < 3.08; b += 0.001) {
|
||||
Brusselator brusselator = new Brusselator(b);
|
||||
brusselator.setParameter(0, b);
|
||||
double[] z = { 1.3, b };
|
||||
double[][] dZdZ0 = new double[2][2];
|
||||
double[][] dZdP = new double[2][1];
|
||||
FirstOrderIntegratorWithJacobians extInt =
|
||||
new FirstOrderIntegratorWithJacobians(integ, brusselator);
|
||||
extInt.setMaxEvaluations(5000);
|
||||
extInt.integrate(0, z, new double[][] { { 0.0 }, { 1.0 } }, 20.0, z, dZdZ0, dZdP);
|
||||
Assert.assertEquals(5000, extInt.getMaxEvaluations());
|
||||
Assert.assertTrue(extInt.getEvaluations() > 350);
|
||||
Assert.assertTrue(extInt.getEvaluations() < 510);
|
||||
Assert.assertEquals(integ.getEvaluations(), extInt.getEvaluations());
|
||||
residualsP0.addValue(dZdP[0][0] - brusselator.dYdP0());
|
||||
residualsP1.addValue(dZdP[1][0] - brusselator.dYdP1());
|
||||
}
|
||||
Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.014);
|
||||
Assert.assertTrue(residualsP0.getStandardDeviation() < 0.003);
|
||||
Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.05);
|
||||
Assert.assertTrue(residualsP1.getStandardDeviation() < 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinalResult() throws IntegratorException, MathUserException {
|
||||
FirstOrderIntegrator integ =
|
||||
new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 });
|
||||
double[] y = new double[] { 0.0, 1.0 };
|
||||
Circle circle = new Circle(y, 1.0, 1.0, 0.1);
|
||||
double[][] dydy0 = new double[2][2];
|
||||
double[][] dydp = new double[2][3];
|
||||
double t = 18 * FastMath.PI;
|
||||
FirstOrderIntegratorWithJacobians extInt =
|
||||
new FirstOrderIntegratorWithJacobians(integ, circle);
|
||||
extInt.integrate(0, y, circle.exactDyDp(0), t, y, dydy0, dydp);
|
||||
for (int i = 0; i < y.length; ++i) {
|
||||
Assert.assertEquals(circle.exactY(t)[i], y[i], 1.0e-9);
|
||||
}
|
||||
for (int i = 0; i < dydy0.length; ++i) {
|
||||
for (int j = 0; j < dydy0[i].length; ++j) {
|
||||
Assert.assertEquals(circle.exactDyDy0(t)[i][j], dydy0[i][j], 1.0e-9);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < dydp.length; ++i) {
|
||||
for (int j = 0; j < dydp[i].length; ++j) {
|
||||
Assert.assertEquals(circle.exactDyDp(t)[i][j], dydp[i][j], 1.0e-7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepHandlerResult() throws IntegratorException, MathUserException {
|
||||
FirstOrderIntegrator integ =
|
||||
new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 });
|
||||
double[] y = new double[] { 0.0, 1.0 };
|
||||
final Circle circle = new Circle(y, 1.0, 1.0, 0.1);
|
||||
double[][] dydy0 = new double[2][2];
|
||||
double[][] dydp = new double[2][3];
|
||||
double t = 18 * FastMath.PI;
|
||||
final FirstOrderIntegratorWithJacobians extInt =
|
||||
new FirstOrderIntegratorWithJacobians(integ, circle);
|
||||
extInt.addStepHandler(new StepHandlerWithJacobians() {
|
||||
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
public boolean requiresDenseOutput() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void handleStep(StepInterpolatorWithJacobians interpolator, boolean isLast)
|
||||
throws MathUserException {
|
||||
double t = interpolator.getCurrentTime();
|
||||
double[] y = interpolator.getInterpolatedY();
|
||||
double[][] dydy0 = interpolator.getInterpolatedDyDy0();
|
||||
double[][] dydp = interpolator.getInterpolatedDyDp();
|
||||
Assert.assertEquals(interpolator.getPreviousTime(), extInt.getCurrentStepStart(), 1.0e-10);
|
||||
Assert.assertTrue(extInt.getCurrentSignedStepsize() < 0.5);
|
||||
for (int i = 0; i < y.length; ++i) {
|
||||
Assert.assertEquals(circle.exactY(t)[i], y[i], 1.0e-9);
|
||||
}
|
||||
for (int i = 0; i < dydy0.length; ++i) {
|
||||
for (int j = 0; j < dydy0[i].length; ++j) {
|
||||
Assert.assertEquals(circle.exactDyDy0(t)[i][j], dydy0[i][j], 1.0e-9);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < dydp.length; ++i) {
|
||||
for (int j = 0; j < dydp[i].length; ++j) {
|
||||
Assert.assertEquals(circle.exactDyDp(t)[i][j], dydp[i][j], 3.0e-8);
|
||||
}
|
||||
}
|
||||
|
||||
double[] yDot = interpolator.getInterpolatedYDot();
|
||||
double[][] dydy0Dot = interpolator.getInterpolatedDyDy0Dot();
|
||||
double[][] dydpDot = interpolator.getInterpolatedDyDpDot();
|
||||
|
||||
for (int i = 0; i < yDot.length; ++i) {
|
||||
Assert.assertEquals(circle.exactYDot(t)[i], yDot[i], 1.0e-10);
|
||||
}
|
||||
for (int i = 0; i < dydy0Dot.length; ++i) {
|
||||
for (int j = 0; j < dydy0Dot[i].length; ++j) {
|
||||
Assert.assertEquals(circle.exactDyDy0Dot(t)[i][j], dydy0Dot[i][j], 1.0e-10);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < dydpDot.length; ++i) {
|
||||
for (int j = 0; j < dydpDot[i].length; ++j) {
|
||||
Assert.assertEquals(circle.exactDyDpDot(t)[i][j], dydpDot[i][j], 3.0e-9);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
extInt.integrate(0, y, circle.exactDyDp(0), t, y, dydy0, dydp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventHandler() throws IntegratorException, MathUserException {
|
||||
FirstOrderIntegrator integ =
|
||||
new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 });
|
||||
double[] y = new double[] { 0.0, 1.0 };
|
||||
final Circle circle = new Circle(y, 1.0, 1.0, 0.1);
|
||||
double[][] dydy0 = new double[2][2];
|
||||
double[][] dydp = new double[2][3];
|
||||
double t = 18 * FastMath.PI;
|
||||
final FirstOrderIntegratorWithJacobians extInt =
|
||||
new FirstOrderIntegratorWithJacobians(integ, circle);
|
||||
extInt.addEventHandler(new EventHandlerWithJacobians() {
|
||||
|
||||
public int eventOccurred(double t, double[] y, double[][] dydy0,
|
||||
double[][] dydp, boolean increasing) {
|
||||
Assert.assertEquals(0.1, y[1], 1.0e-11);
|
||||
Assert.assertTrue(!increasing);
|
||||
return STOP;
|
||||
}
|
||||
|
||||
public double g(double t, double[] y, double[][] dydy0,
|
||||
double[][] dydp) {
|
||||
return y[1] - 0.1;
|
||||
}
|
||||
|
||||
public void resetState(double t, double[] y, double[][] dydy0,
|
||||
double[][] dydp) {
|
||||
}
|
||||
}, 10.0, 1.0e-10, 1000);
|
||||
double stopTime = extInt.integrate(0, y, circle.exactDyDp(0), t, y, dydy0, dydp);
|
||||
Assert.assertTrue(stopTime < 5.0 * FastMath.PI);
|
||||
}
|
||||
|
||||
private static class Brusselator implements ParameterizedODE, ODEWithJacobians {
|
||||
|
||||
private double b;
|
||||
|
||||
public Brusselator(double b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public void setParameter(int i, double p) {
|
||||
b = p;
|
||||
}
|
||||
|
||||
public int getParametersDimension() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void computeDerivatives(double t, double[] y, double[] yDot) {
|
||||
double prod = y[0] * y[0] * y[1];
|
||||
yDot[0] = 1 + prod - (b + 1) * y[0];
|
||||
yDot[1] = b * y[0] - prod;
|
||||
}
|
||||
|
||||
public void computeJacobians(double t, double[] y, double[] yDot, double[][] dFdY, double[][] dFdP) {
|
||||
double p = 2 * y[0] * y[1];
|
||||
double y02 = y[0] * y[0];
|
||||
dFdY[0][0] = p - (1 + b);
|
||||
dFdY[0][1] = y02;
|
||||
dFdY[1][0] = b - p;
|
||||
dFdY[1][1] = -y02;
|
||||
dFdP[0][0] = -y[0];
|
||||
dFdP[1][0] = y[0];
|
||||
}
|
||||
|
||||
public double dYdP0() {
|
||||
return -1088.232716447743 + (1050.775747149553 + (-339.012934631828 + 36.52917025056327 * b) * b) * b;
|
||||
}
|
||||
|
||||
public double dYdP1() {
|
||||
return 1502.824469929139 + (-1438.6974831849952 + (460.959476642384 - 49.43847385647082 * b) * b) * b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** ODE representing a point moving on a circle with provided center and angular rate. */
|
||||
private static class Circle implements ODEWithJacobians {
|
||||
|
||||
private final double[] y0;
|
||||
private double cx;
|
||||
private double cy;
|
||||
private double omega;
|
||||
|
||||
public Circle(double[] y0, double cx, double cy, double omega) {
|
||||
this.y0 = y0.clone();
|
||||
this.cx = cx;
|
||||
this.cy = cy;
|
||||
this.omega = omega;
|
||||
}
|
||||
|
||||
public int getDimension() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
public int getParametersDimension() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public void computeDerivatives(double t, double[] y, double[] yDot) {
|
||||
yDot[0] = omega * (cy - y[1]);
|
||||
yDot[1] = omega * (y[0] - cx);
|
||||
}
|
||||
|
||||
public void computeJacobians(double t, double[] y, double[] yDot, double[][] dFdY, double[][] dFdP) {
|
||||
|
||||
dFdY[0][0] = 0;
|
||||
dFdY[0][1] = -omega;
|
||||
dFdY[1][0] = omega;
|
||||
dFdY[1][1] = 0;
|
||||
|
||||
dFdP[0][0] = 0;
|
||||
dFdP[0][1] = omega;
|
||||
dFdP[0][2] = cy - y[1];
|
||||
dFdP[1][0] = -omega;
|
||||
dFdP[1][1] = 0;
|
||||
dFdP[1][2] = y[0] - cx;
|
||||
|
||||
}
|
||||
|
||||
public double[] exactY(double t) {
|
||||
double cos = FastMath.cos(omega * t);
|
||||
double sin = FastMath.sin(omega * t);
|
||||
double dx0 = y0[0] - cx;
|
||||
double dy0 = y0[1] - cy;
|
||||
return new double[] {
|
||||
cx + cos * dx0 - sin * dy0,
|
||||
cy + sin * dx0 + cos * dy0
|
||||
};
|
||||
}
|
||||
|
||||
public double[][] exactDyDy0(double t) {
|
||||
double cos = FastMath.cos(omega * t);
|
||||
double sin = FastMath.sin(omega * t);
|
||||
return new double[][] {
|
||||
{ cos, -sin },
|
||||
{ sin, cos }
|
||||
};
|
||||
}
|
||||
|
||||
public double[][] exactDyDp(double t) {
|
||||
double cos = FastMath.cos(omega * t);
|
||||
double sin = FastMath.sin(omega * t);
|
||||
double dx0 = y0[0] - cx;
|
||||
double dy0 = y0[1] - cy;
|
||||
return new double[][] {
|
||||
{ 1 - cos, sin, -t * (sin * dx0 + cos * dy0) },
|
||||
{ -sin, 1 - cos, t * (cos * dx0 - sin * dy0) }
|
||||
};
|
||||
}
|
||||
|
||||
public double[] exactYDot(double t) {
|
||||
double oCos = omega * FastMath.cos(omega * t);
|
||||
double oSin = omega * FastMath.sin(omega * t);
|
||||
double dx0 = y0[0] - cx;
|
||||
double dy0 = y0[1] - cy;
|
||||
return new double[] {
|
||||
-oSin * dx0 - oCos * dy0,
|
||||
oCos * dx0 - oSin * dy0
|
||||
};
|
||||
}
|
||||
|
||||
public double[][] exactDyDy0Dot(double t) {
|
||||
double oCos = omega * FastMath.cos(omega * t);
|
||||
double oSin = omega * FastMath.sin(omega * t);
|
||||
return new double[][] {
|
||||
{ -oSin, -oCos },
|
||||
{ oCos, -oSin }
|
||||
};
|
||||
}
|
||||
|
||||
public double[][] exactDyDpDot(double t) {
|
||||
double cos = FastMath.cos(omega * t);
|
||||
double sin = FastMath.sin(omega * t);
|
||||
double oCos = omega * cos;
|
||||
double oSin = omega * sin;
|
||||
double dx0 = y0[0] - cx;
|
||||
double dy0 = y0[1] - cy;
|
||||
return new double[][] {
|
||||
{ oSin, oCos, -sin * dx0 - cos * dy0 - t * ( oCos * dx0 - oSin * dy0) },
|
||||
{ -oCos, oSin, cos * dx0 - sin * dy0 + t * (-oSin * dx0 - oCos * dy0) }
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue