All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.math.ode.jacobians.package.html Maven / Gradle / Ivy

Go to download

The Math project is a library of lightweight, self-contained mathematics and statistics components addressing the most common practical problems not immediately available in the Java programming language or commons-lang.

There is a newer version: 2.2
Show newest version


    

This package provides classes to solve Ordinary Differential Equations problems and also compute derivatives of the solution.

This package solves Initial Value Problems of the form y'=f(t,y,p) with t0, y(t0)=y0 and dy(t0)/dp known. The provided integrator computes estimates of y(t), dy(t)/dy0 and dy(t)/dp from t=t0 to t=t1, where y is the state and p is a parameters array.

The classes in this package mimic the behavior of classes and interfaces from the org.apache.commons.math.ode, org.apache.commons.math.ode.events and org.apache.commons.math.ode.sampling packages, adding the jacobians dy(t)/dy0 and dy(t)/dp to the methods signatures.

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)/dy0 and dy(t0)/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.

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.

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

  • y'0(t) = ω × (c1 - y1(t))
  • y'1(t) = ω × (y0(t) - c0)
with some initial state y(t0) = (y0(t0), y1(t0)).

The point trajectory depends on the initial state y(t0) and on the ODE parameter ω. We want to compute both the final point position y(tend) and the sensitivity of this point with respect to the initial state: dy(tend)/dy(t0) which is a 2×2 matrix and its sensitivity with respect to the parameter: dy(tend)/dω which is a 2×1 matrix.

We consider first the simplest implementation: we define only the ODE and let the classes compute the necessary jacobians by itself:

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;
    }

}

We compute the results we want as follows:

    // 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);

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:

    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);

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):

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];

    }

}
With this implementation, the hY and hP arrays are not needed anymore:
    ODEWithJacobians ode = new EnhancedCircleODE(new double[] { cx, cy }, omega);
    FirstOrderIntegratorWithJacobians integrator =
            new FirstOrderIntegratorWithJacobians(lowIntegrator, ode);





© 2015 - 2024 Weber Informatics LLC | Privacy Policy