<?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.
  -->
  
<?xml-stylesheet type="text/xsl" href="./xdoc.xsl"?>
<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 mean to get both the state and its derivative
          between the time steps. They do so through classes extending the
          <a href="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/ode/FirstOrderDifferentialEquations.html">FirstOrderDifferentialEquations</a>
          interface (or  <a href="../apidocs/org/apache/commons/math3/ode/FirstOrderFieldDifferentialEquations.html">FirstOrderFieldDifferentialEquations</a>
          interface). Then he should pass it to the integrator he prefers among all the classes that implement
          the <a href="../apidocs/org/apache/commons/math3/ode/FirstOrderIntegrator.html">FirstOrderIntegrator</a>
          interface (or the <a href="../apidocs/org/apache/commons/math3/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) = &#x3c9; &#xD7; (c<sub>1</sub> - y<sub>1</sub>(t))</li>
            <li>y'<sub>1</sub>(t) = &#x3c9; &#xD7; (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 &#x3c9;.
        </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="../apidocs/org/apache/commons/math3/ode/sampling/StepHandler.html">StepHandler</a> interface or a
          <a href="../apidocs/org/apache/commons/math3/ode/sampling/StepNormalizer.html">StepNormalizer</a> object wrapping
          a user-specified object implementing the
          <a href="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/ode/sampling/StepHandler.html">StepHandler</a>
          interface are available for general needs
          (<a href="../apidocs/org/apache/commons/math3/ode/sampling/DummyStepHandler.html">DummyStepHandler</a>,
          <a href="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/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 he prefers 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="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/ode/nonstiff/EulerIntegrator.html">Euler</a></td><td>1</td></tr>
          <tr><td><a href="../apidocs/org/apache/commons/math3/ode/nonstiff/MidpointIntegrator.html">Midpoint</a></td><td>2</td></tr>
          <tr><td><a href="../apidocs/org/apache/commons/math3/ode/nonstiff/ClassicalRungeKuttaIntegrator.html">Classical Runge-Kutta</a></td><td>4</td></tr>
          <tr><td><a href="../apidocs/org/apache/commons/math3/ode/nonstiff/GillIntegrator.html">Gill</a></td><td>4</td></tr>
          <tr><td><a href="../apidocs/org/apache/commons/math3/ode/nonstiff/ThreeEighthesIntegrator.html">3/8</a></td><td>4</td></tr>
          <tr><td><a href="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/ode/nonstiff/HighamHall54Integrator.html">Higham and Hall</a></td><td>5</td><td>4</td></tr>
          <tr><td><a href="../apidocs/org/apache/commons/math3/ode/nonstiff/DormandPrince54Integrator.html">Dormand-Prince 5(4)</a></td><td>5</td><td>4</td></tr>
          <tr><td><a href="../apidocs/org/apache/commons/math3/ode/nonstiff/DormandPrince853Integrator.html">Dormand-Prince 8(5,3)</a></td><td>8</td><td>5 and 3</td></tr>
          <tr><td><a href="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/ode/nonstiff/AdamsBashforthIntegrator.html">Adams-Bashforth</a></td><td>variable</td><td>variable</td></tr>
          <tr><td><a href="../apidocs/org/apache/commons/math3/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>), he needs 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="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/ode/FirstOrderDifferentialEquations.html">FirstOrderDifferentialEquations</a>
          interface only, the user should rather provide an implementation of the <a
          href="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/ode/FirstOrderDifferentialEquations.html">FirstOrderDifferentialEquations</a>
          interface and given as such to another constructor of the <a
          href="../apidocs/org/apache/commons/math3/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="../apidocs/org/apache/commons/math3/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 he can provide one or more classes implementing the <a
          href="../apidocs/org/apache/commons/math3/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&lt;String&gt; 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>
