| <?xml version="1.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. |
| --> |
| |
| <document url="ode.html"> |
| |
| <properties> |
| <title>The Commons Math User Guide - Ordinary Differential Equations Integration</title> |
| </properties> |
| |
| <body> |
| <section name="15 Ordinary Differential Equations Integration"> |
| <subsection name="15.1 Overview" href="overview"> |
| <p> |
| The ode package provides classes to solve Ordinary Differential Equations problems. |
| </p> |
| <p> |
| This package solves Initial Value Problems of the form y'=f(t,y) with t<sub>0</sub> |
| and y(t<sub>0</sub>)=y<sub>0</sub> known. The provided integrators compute an estimate |
| of y(t) from t=t<sub>0</sub> to t=t<sub>1</sub>. |
| </p> |
| <p> |
| All integrators provide dense output. This means that besides computing the state vector |
| at discrete times, they also provide a cheap means to get both the state and its derivative |
| between the time steps. They do so through classes extending the |
| <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/sampling/StepInterpolator.html">StepInterpolator</a> |
| abstract class, which are made available to the user at the end of each step. |
| </p> |
| <p> |
| All integrators handle multiple discrete events detection based on switching |
| functions. This means that the integrator can be driven by user specified discrete events |
| (occurring when the sign of user-supplied <i>switching function</i> changes). The steps are |
| shortened as needed to ensure the events occur at step boundaries (even if the integrator |
| is a fixed-step integrator). When the events are triggered, integration can |
| be stopped (this is called a G-stop facility), the state vector can be changed, or integration |
| can simply go on. The latter case is useful to handle discontinuities in the differential |
| equations gracefully and get accurate dense output even close to the discontinuity. |
| </p> |
| <p> |
| All integrators support setting a maximal number of evaluations of differential |
| equations function. If this number is exceeded, an exception will be thrown during |
| integration. This can be used to prevent infinite loops if for example error control or |
| discrete events create a really large number of extremely small steps. By default, the |
| maximal number of evaluation is set to <code>Integer.MAX_VALUE</code> (i.e. 2<sup>31</sup>-1 |
| or 2147483647). It is recommended to set this maximal number to a value suited to the ODE |
| problem, integration range, and step size or error control settings. |
| </p> |
| <p> |
| All integrators support expanding the main ODE with one or more secondary ODE to manage |
| additional state that will be integrated together with the main state. This can be used |
| for example to integrate variational equations and compute not only the main state but also |
| its partial derivatives with respect to either the initial state or some parameters, these |
| derivatives being handled be secondary ODE (see below for an example). |
| </p> |
| <p> |
| Two parallel APIs are available. The first is devoted to solve ode for which the integration free |
| variable t and the state y(t) are primitive double and primitive double array respectively. Starting |
| with version 3.6, a second API is devoted to solve ode for which the integration free |
| variable t and the state y(t) are <code>RealFieldElement</code> and <code>RealFieldElement</code> |
| array respectively. This allow for example users to integrate ode where the computation values |
| are for example <code>DerivativeStructure</code> elements, hence automatically computing |
| partial derivatives with respect to some equations parameters without a need to set up the |
| variational equations. Another example is to use <code>Dfp</code> elements in order to solve |
| ode with extended precision. As of 3.6, the API are slightly different, mainly in the way they |
| handle arrays. Both API will become more similar in 4.0 and future versions as the older |
| primitive double API will be modified to match the newer field API. This cannot be done in |
| 3.6 for compatibility reasons. |
| </p> |
| <p> |
| The user should describe his problem in his own classes which should implement the |
| <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/FirstOrderDifferentialEquations.html">FirstOrderDifferentialEquations</a> |
| interface (or <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/FirstOrderFieldDifferentialEquations.html">FirstOrderFieldDifferentialEquations</a> |
| interface). Then they should pass it to the integrator they prefer among all the classes that implement |
| the <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/FirstOrderIntegrator.html">FirstOrderIntegrator</a> |
| interface (or the <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/FirstOrderFieldIntegrator.html">FirstOrderFieldIntegrator</a> |
| interface). The following example shows how to implement the simple two-dimensional problem using double primitives: |
| <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>)). |
| In fact, the exact solution of this problem is that y(t) moves along a circle |
| centered at c = (c<sub>0</sub>, c<sub>1</sub>) with constant angular rate ω. |
| </p> |
| <source> |
| private static class CircleODE implements FirstOrderDifferentialEquations { |
| |
| private double[] c; |
| private double omega; |
| |
| public CircleODE(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]); |
| } |
| |
| } |
| </source> |
| <p> |
| Computing the state y(16.0) starting from y(0.0) = (0.0, 1.0) and integrating the ODE |
| is done as follows (using Dormand-Prince 8(5,3) integrator as an example): |
| </p> |
| <source> |
| FirstOrderIntegrator dp853 = new DormandPrince853Integrator(1.0e-8, 100.0, 1.0e-10, 1.0e-10); |
| FirstOrderDifferentialEquations ode = new CircleODE(new double[] { 1.0, 1.0 }, 0.1); |
| double[] y = new double[] { 0.0, 1.0 }; // initial state |
| dp853.integrate(ode, 0.0, y, 16.0, y); // now y contains final state at time t=16.0 |
| </source> |
| </subsection> |
| <subsection name="15.2 Continuous Output" href="continuous"> |
| <p> |
| The solution of the integration problem is provided by two means. The first one is aimed towards |
| simple use: the state vector at the end of the integration process is copied in the y array of the |
| <code>FirstOrderIntegrator.integrate</code> method, as shown by previous example. The second one |
| should be used when more in-depth information is needed throughout the integration process. The user |
| can register an object implementing the |
| <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/sampling/StepHandler.html">StepHandler</a> interface or a |
| <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/sampling/StepNormalizer.html">StepNormalizer</a> object wrapping |
| a user-specified object implementing the |
| <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/sampling/FixedStepHandler.html">FixedStepHandler</a> interface |
| into the integrator before calling the <code>FirstOrderIntegrator.integrate</code> method. The user object |
| will be called appropriately during the integration process, allowing the user to process intermediate |
| results. The default step handler does nothing. Considering again the previous example, we want to print the |
| trajectory of the point to check it really is a circle arc. We simply add the following before the call |
| to integrator.integrate: |
| </p> |
| <source> |
| StepHandler stepHandler = new StepHandler() { |
| public void init(double t0, double[] y0, double t) { |
| } |
| |
| public void handleStep(StepInterpolator interpolator, boolean isLast) { |
| double t = interpolator.getCurrentTime(); |
| double[] y = interpolator.getInterpolatedState(); |
| System.out.println(t + " " + y[0] + " " + y[1]); |
| } |
| }; |
| integrator.addStepHandler(stepHandler); |
| </source> |
| <p> |
| <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/ContinuousOutputModel.html">ContinuousOutputModel</a> |
| is a special-purpose step handler that is able to store all steps and to provide transparent access to |
| any intermediate result once the integration is over. An important feature of this class is that it |
| implements the <code>Serializable</code> interface. This means that a complete continuous model of the |
| integrated function throughout the integration range can be serialized and reused later (if stored into |
| a persistent medium like a file system or a database) or elsewhere (if sent to another application). |
| Only the result of the integration is stored, there is no reference to the integrated problem by itself. |
| </p> |
| <p> |
| Other default implementations of the <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/sampling/StepHandler.html">StepHandler</a> |
| interface are available for general needs |
| (<a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/sampling/DummyStepHandler.html">DummyStepHandler</a>, |
| <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/sampling/StepNormalizer.html">StepNormalizer</a>) and custom |
| implementations can be developed for specific needs. As an example, if an application is to be |
| completely driven by the integration process, then most of the application code will be run inside a |
| step handler specific to this application. |
| </p> |
| <p> |
| Some integrators (the simple ones) use fixed steps that are set at creation time. The more efficient |
| integrators use variable steps that are handled internally in order to control the integration error |
| of the main state with respect to a specified accuracy (these integrators extend the |
| <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/AdaptiveStepsizeIntegrator.html">AdaptiveStepsizeIntegrator</a> |
| abstract class). The secondary equations are explicitly ignored for step size control, in order to get reproducible |
| results regardless of the secondary equations being integrated or not. The step handler which is called after each |
| successful step shows up the variable stepsize. The <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/sampling/StepNormalizer.html">StepNormalizer</a> |
| class can be used to convert the variable stepsize into a fixed stepsize that can be handled by classes |
| implementing the <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/sampling/FixedStepHandler.html">FixedStepHandler</a> |
| interface. Adaptive stepsize integrators can automatically compute the initial stepsize by themselves, |
| however the user can specify it if they prefer to retain full control over the integration or if the |
| automatic guess is wrong. |
| </p> |
| </subsection> |
| <subsection name="15.3 Discrete Events Handling" href="events"> |
| <p> |
| ODE problems are continuous ones. However, sometimes discrete events must be |
| taken into account. The most frequent case is the stop condition of the integrator |
| is not defined by the time t but by a target condition on state y (say y[0] = 1.0 |
| for example). |
| </p> |
| <p> |
| Discrete events detection is based on switching functions. The user provides |
| a simple <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/events/EventHandler.html">g(t, y)</a> |
| function depending on the current time and state. The integrator will monitor |
| the value of the function throughout integration range and will trigger the |
| event when its sign changes. The magnitude of the value is almost irrelevant. |
| For the sake of root finding, it should however be continuous (but not necessarily smooth) |
| at least in the roots vicinity. The steps are shortened as needed to ensure the events occur |
| at step boundaries (even if the integrator is a fixed-step integrator). |
| </p> |
| <p> |
| When an event is triggered, the event time, current state and an indicator |
| whether the switching function was increasing or decreasing at event time |
| are provided to the user. Several different options are available to him: |
| </p> |
| <ul> |
| <li>integration can be stopped (this is called a G-stop facility),</li> |
| <li>the state vector or the derivatives can be changed,</li> |
| <li>or integration can simply go on.</li> |
| </ul> |
| |
| <p> |
| The first case, G-stop, is the most common one. A typical use case is when an |
| ODE must be solved up to some target state is reached, with a known value of |
| the state but an unknown occurrence time. As an example, if we want to monitor |
| a chemical reaction up to some predefined concentration for the first substance, |
| we can use the following switching function setting: |
| </p> |
| <source> |
| public double g(double t, double[] y) { |
| return y[0] - targetConcentration; |
| } |
| |
| public int eventOccurred(double t, double[] y, boolean increasing) { |
| return STOP; |
| } |
| </source> |
| |
| <p> |
| The second case, change state vector or derivatives is encountered when dealing |
| with discontinuous dynamical models. A typical case would be the motion of a |
| spacecraft when thrusters are fired for orbital maneuvers. The acceleration is |
| smooth as long as no maneuvers are performed, depending only on gravity, drag, |
| third body attraction, radiation pressure. Firing a thruster introduces a |
| discontinuity that must be handled appropriately by the integrator. In such a case, |
| we would use a switching function setting similar to this: |
| </p> |
| <source> |
| public double g(double t, double[] y) { |
| return (t - tManeuverStart) * (t - tManeuverStop); |
| } |
| |
| public int eventOccurred(double t, double[] y, boolean increasing) { |
| return RESET_DERIVATIVES; |
| } |
| </source> |
| |
| <p> |
| The third case is useful mainly for monitoring purposes, a simple example is: |
| </p> |
| <source> |
| public double g(double t, double[] y) { |
| return y[0] - y[1]; |
| } |
| |
| public int eventOccurred(double t, double[] y, boolean increasing) { |
| logger.log("y0(t) and y1(t) curves cross at t = " + t); |
| return CONTINUE; |
| } |
| </source> |
| </subsection> |
| <subsection name="15.4 Available Integrators" href="integrators"> |
| <p> |
| The tables below show the various integrators available for non-stiff problems. Note that the |
| implementations of Adams-Bashforth and Adams-Moulton are adaptive stepsize, not fixed stepsize |
| as is usual for these multi-step integrators. This is due to the fact the implementation relies |
| on the Nordsieck vector representation of the state. |
| </p> |
| <p> |
| <table border="1" align="center"> |
| <tr BGCOLOR="#CCCCFF"><td colspan="2"><font size="+1">Fixed Step Integrators</font></td></tr> |
| <tr BGCOLOR="#EEEEFF"><font size="+1"><td>Name</td><td>Order</td></font></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/EulerIntegrator.html">Euler</a></td><td>1</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/MidpointIntegrator.html">Midpoint</a></td><td>2</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/ClassicalRungeKuttaIntegrator.html">Classical Runge-Kutta</a></td><td>4</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/GillIntegrator.html">Gill</a></td><td>4</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/ThreeEighthesIntegrator.html">3/8</a></td><td>4</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/LutherIntegrator.html">Luther</a></td><td>6</td></tr> |
| </table> |
| </p> |
| <p> |
| <table border="1" align="center"> |
| <tr BGCOLOR="#CCCCFF"><td colspan="3"><font size="+1">Adaptive Stepsize Integrators</font></td></tr> |
| <tr BGCOLOR="#EEEEFF"><font size="+1"><td>Name</td><td>Integration Order</td><td>Error Estimation Order</td></font></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/HighamHall54Integrator.html">Higham and Hall</a></td><td>5</td><td>4</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/DormandPrince54Integrator.html">Dormand-Prince 5(4)</a></td><td>5</td><td>4</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/DormandPrince853Integrator.html">Dormand-Prince 8(5,3)</a></td><td>8</td><td>5 and 3</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/GraggBulirschStoerIntegrator.html">Gragg-Bulirsch-Stoer</a></td><td>variable (up to 18 by default)</td><td>variable</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/AdamsBashforthIntegrator.html">Adams-Bashforth</a></td><td>variable</td><td>variable</td></tr> |
| <tr><td><a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/nonstiff/AdamsMoultonIntegrator.html">Adams-Moulton</a></td><td>variable</td><td>variable</td></tr> |
| </table> |
| </p> |
| </subsection> |
| <subsection name="15.5 Derivatives" href="derivatives"> |
| <p> |
| If in addition to state y(t) the user needs to compute the sensitivity of the final state with respect to |
| the initial state (dy/dy<sub>0</sub>) or the sensitivity of the final state with respect to some parameters |
| of the ODE (dy/dp<sub>k</sub>), they need to register the variational equations as a set of secondary equations |
| appended to the main state before the integration starts. Then the integration will propagate the compound |
| state composed of both the main state and its partial derivatives. At the end of the integration, the Jacobian |
| matrices are extracted from the integrated secondary state. The <a |
| href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/JacobianMatrices.html">JacobianMatrices</a> class can do most of |
| this as long as the local derivatives are provided to it. It will set up the variational equations, register |
| them as secondary equations into the ODE, and it will set up the initial values and retrieve the intermediate |
| and final values as Jacobian matrices. |
| </p> |
| <p> |
| 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 represent the 6x6 |
| Jacobian matrix of the final state with respect to the initial state, and the remaining 18 elements will |
| represent the 6x3 Jacobian matrix of the final state with respect to the 3 parameters. The <a |
| href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/JacobianMatrices.html">JacobianMatrices</a> class does the mapping |
| between the 60 elements compound state and the Jacobian matrices and sets up the correcsponding secondary equations. |
| </p> |
| <p> |
| As the variational equations are considered to be secondary equations here, variable step integrators ignore |
| them for step size control: they rely only on the main state. This feature is a design choice. The rationale is |
| to get exactly the same steps, regardless of the Jacobians being computed or not, hence ensuring reproducible |
| results in both cases. |
| </p> |
| <p> |
| What remains of user responsibility is to provide the local Jacobians df(t, y, p)/dy and df(t, y, p)/dp<sub>k</sub> |
| corresponding the the main ODE y'=f(t, y, p). The main ODE is as usual provided by the user as a class implementing |
| the <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/FirstOrderDifferentialEquations.html">FirstOrderDifferentialEquations</a> |
| interface or a sub-interface. |
| </p> |
| <p> |
| If the ODE is simple enough that the user can implement df(t, y, p)/dy directly, then instead of providing an |
| implementation of the <a |
| href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/FirstOrderDifferentialEquations.html">FirstOrderDifferentialEquations</a> |
| interface only, the user should rather provide an implementation of the <a |
| href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/MainStateJacobianProvider.html">MainStateJacobianProvider</a> interface, |
| which extends the previous interface by adding a method to compute df(t, y, p)/dy. The user class is used as a |
| constructor parameter of the <a href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/JacobianMatrices.html">JacobianMatrices</a> |
| class. If the ODE is too complex or the user simply does not bother implementing df(t, y, p)/dy directly, then |
| the ODE can still be implemented using the simple <a |
| href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/FirstOrderDifferentialEquations.html">FirstOrderDifferentialEquations</a> |
| interface and given as such to another constructor of the <a |
| href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/JacobianMatrices.html">JacobianMatrices</a> class, but in this case an array |
| hy must also be provided that will contain the step size to use form each component of the main state vector y, and |
| the Jacobian f(t, y, p)/dy will be computed internally using finite differences. This will of course trigger more evaluations |
| of the ODE at each step and will suffer from finite differences errors, but it is much simpler to implement from a user |
| point of view. |
| </p> |
| <p> |
| The parameters are identified by a name (a simple user-defined string), which are also specified at <a |
| href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/JacobianMatrices.html">JacobianMatrices</a> class construction. If the ODE |
| is simple enough that the user can implement df(t, y, p)/dp<sub>k</sub> directly for some of the parameters p<sub>k</sub>, |
| then they can provide one or more classes implementing the <a |
| href="../commons-math-docs/apidocs/org/apache/commons/math4/legacy/ode/ParameterJacobianProvider.html">ParameterJacobianProvider</a> interface by |
| calling the JacobianMatrices.addParameterJacobianProvide method. The parameters are handled one at a time, but all the calls to |
| ParameterJacobianProvider.computeParameterJacobian will be grouped in one sequence after the call to MainStateJacobianProvider.computeMainStateJacobian |
| This feature can be used when all the derivatives share a lot of costly computation. In this case, the user |
| is advised to compute all the needed derivatives at once during the call to computeMainStateJacobian, including the |
| partial derivatives with respect to the parameters and to store the derivatives temporary. Then when the next calls to |
| computeParameterJacobian will be triggerred, it will be sufficient to return the already computed derivatives. With this |
| architecture, many computation can be saved. This of course implies that the classes implementing both interfaces know |
| each other (they can even be the same class if desired, but it is not required). If the ODE is too complex or the user |
| simply does not bother implementing df(t, y, p)/dp<sub>k</sub> directly for some k, then |
| the JacobianMatrices.setParameterStep method should be called so finite differences are used to compute the derivatives |
| for this parameter. It is possible to have some parameters for which derivatives are provided by a direct implementation |
| while other parameters are computed using finite differences during the same integration. |
| </p> |
| <p> |
| The following example corresponds to a simple case where all derivatives can be computed analytically. The state is |
| a 2D point travelling along a circle. There are three parameters : the two coordinates of the center and the |
| angular velocity. |
| </p> |
| <source> |
| public class CircleODE implements MainStateJacobianProvider, ParameterJacobianProvider { |
| |
| public static final String CENTER_X = "cx"; |
| public static final String CENTER_Y = "cy"; |
| public static final String OMEGA = "omega"; |
| |
| private double[] c; |
| private double omega; |
| private double[][] savedDfDp; |
| |
| public CircleODE(double[] c, double omega) { |
| this.c = c; |
| this.omega = omega; |
| this.savedDfDp = new double[2][3]; |
| } |
| |
| public int getDimension() { |
| return 2; |
| } |
| |
| public void computeDerivatives(double t, double[] y, double[] yDot) { |
| // the state is a 2D point, the ODE therefore corresponds to the velocity |
| yDot[0] = omega * (c[1] - y[1]); |
| yDot[1] = omega * (y[0] - c[0]); |
| } |
| |
| public Collection<String> getParametersNames() { |
| return Arrays.asList(CENTER_X, CENTER_Y, OMEGA); |
| } |
| |
| public boolean isSupported(String name) { |
| return CENTER_X.equals(name) || CENTER_Y.equals(name) || OMEGA.equals(name); |
| } |
| |
| public void computeMainStateJacobian(double t, double[] y, double[] yDot, double[][] dFdY) { |
| |
| // compute the Jacobian of the main state |
| dFdY[0][0] = 0; |
| dFdY[0][1] = -omega; |
| dFdY[1][0] = omega; |
| dFdY[1][1] = 0; |
| |
| // precompute the derivatives with respect to the parameters, |
| // they will be provided back when computeParameterJacobian are called later on |
| savedDfDp[0][0] = 0; |
| savedDfDp[0][1] = omega; |
| savedDfDp[0][2] = c[1] - y[1]; |
| savedDfDp[1][0] = -omega; |
| savedDfDp[1][1] = 0; |
| savedDfDp[1][2] = y[0] - c[0]; |
| |
| } |
| |
| public void computeParameterJacobian(double t, double[] y, double[] yDot, |
| String paramName, double[] dFdP) { |
| // we simply return the derivatives precomputed earlier |
| if (CENTER_X.equals(paramName)) { |
| dFdP[0] = savedDfDp[0][0]; |
| dFdP[1] = savedDfDp[1][0]; |
| } else if (CENTER_Y.equals(paramName)) { |
| dFdP[0] = savedDfDp[0][1]; |
| dFdP[1] = savedDfDp[1][1]; |
| } else { |
| dFdP[0] = savedDfDp[0][2]; |
| dFdP[1] = savedDfDp[1][2]; |
| } |
| } |
| |
| } |
| </source> |
| <p> |
| This ODE is integrated as follows: |
| </p> |
| <source> |
| CircleODE circle = new CircleODE(new double[] {1.0, 1.0 }, 0.1); |
| |
| // here, we could select only a subset of the parameters, or use another order |
| JacobianMatrices jm = new JacobianMatrices(circle, CircleODE.CENTER_X, CircleODE.CENTER_Y, CircleODE.OMEGA); |
| jm.addParameterJacobianProvider(circle); |
| |
| ExpandableStatefulODE efode = new ExpandableStatefulODE(circle); |
| efode.setTime(0); |
| double[] y = { 1.0, 0.0 }; |
| efode.setPrimaryState(y); |
| |
| // create the variational equations and append them to the main equations, as secondary equations |
| jm.registerVariationalEquations(efode); |
| |
| // integrate the compound state, with both main and additional equations |
| DormandPrince853Integrator integrator = new DormandPrince853Integrator(1.0e-6, 1.0e3, 1.0e-10, 1.0e-12); |
| integrator.setMaxEvaluations(5000); |
| integrator.integrate(efode, 20.0); |
| |
| // retrieve the Jacobian of the final state with respect to initial state |
| double[][] dYdY0 = new double[2][2]; |
| jm.getCurrentMainSetJacobian(dYdY0); |
| |
| // retrieve the Jacobians of the final state with resepct to the various parameters |
| double[] dYdCx = new double[2]; |
| double[] dYdCy = new double[2]; |
| double[] dYdOm = new double[2]; |
| jm.getCurrentParameterJacobian(CircleODE.CENTER_X, dYdCx); |
| jm.getCurrentParameterJacobian(CircleODE.CENTER_Y, dYdCy); |
| jm.getCurrentParameterJacobian(CircleODE.OMEGA, dYdOm); |
| </source> |
| </subsection> |
| </section> |
| </body> |
| </document> |