Skip to main content

Module ode_callbacks

Module ode_callbacks 

Source
Expand description

ODE equations defined by C callbacks.

OdeCallbacks implements every flavour of diffsol::OdeEquations on top of a table of C function pointers, OdeCallbacksDesc, one for each closure accepted by diffsol::OdeBuilder plus a user_data argument. See the module documentation for the callback conventions and the ownership of user_data. ODE equations defined by C callbacks.

OdeCallbacks implements diffsol::OdeEquations. It also implements each flavour that the solvers need: implicit, forward sensitivities and adjoint. The equations come from a table of C function pointers, OdeCallbacksDesc. Thus a C host (or a different FFI host) can define its own equations.

There is one callback for each closure of diffsol::OdeBuilder. Each callback has the arguments of its closure, plus a user_data pointer as the last argument. Only rhs and init are necessary.

§Callback conventions

Each pointer points to a contiguous array of the scalar type T (double or float). The table gives the array lengths. The counts are fields of OdeCallbacksDesc.

callbackxpvy (output)
rhs, resetnstatesnparams-nstates
rhs_jac, reset_jac (y = J v)nstatesnparamsnstatesnstates
rhs_sens, reset_sens (y = J_p v)nstatesnparamsnparamsnstates
rhs_adjoint, reset_adjoint (y = -J^T v)nstatesnparamsnstatesnstates
rhs_sens_adjoint, reset_sens_adjoint (y = -J_p^T v)nstatesnparamsnstatesnparams
rootnstatesnparams-nroots
root_jac / root_sensnstatesnparamsnstates / nparamsnroots
root_adjoint / root_sens_adjointnstatesnparamsnrootsnstates / nparams
outnstatesnparams-nout
out_jac / out_sensnstatesnparamsnstates / nparamsnout
out_adjoint / out_sens_adjointnstatesnparamsnoutnstates / nparams
init-nparams-nstates
init_sens / init_sens_adjoint-nparamsnparams / nstatesnstates / nparams
mass / mass_adjoint (y = M v + beta y, M^T for the adjoint)-nparamsnstatesnstates

J is the Jacobian of the function with respect to the state x. J_p is the Jacobian with respect to the parameters p.

Each *_adjoint and *_sens_adjoint callback calculates the negative transposed product. For example, out_adjoint calculates y = -J^T v, and init_sens_adjoint calculates y = -(dy0/dp)^T v. mass_adjoint is the only exception: it calculates y = M^T v + beta y.

Each callback has the same meaning as the related diffsol::OdeBuilder closure. For example, rhs_adjoint is the rhs_adjoint closure of diffsol::OdeBuilder::rhs_adjoint_implicit.

§Return codes

Each callback returns an int. The value 0 means success. A different value means failure. When a callback fails, its output is filled with NaN.

The solver can recover from a failure. For example, it can reject a step and try a smaller step. Thus rhs can return an error for a state that is not in its domain.

If the solve succeeds, the callback failures are ignored.

If the solve fails, its error is the error of the solver. If a callback failed during the solve, the message also gives the first failure, for example (a callback failed during the solve: callback 'rhs' returned error code 7). This failure is often the cause. But it can also be an earlier failure that the solver recovered from.

§Sparsity patterns

For a sparse matrix type (FaerSparse), the construction finds the sparsity pattern of each matrix one time. It calls each derivative callback with NaN in the inputs x and v. Each output that is NaN is a non-zero. This is the same method that diffsol::OdeBuilder uses.

The probe uses the initial state at t = 0, with all parameters zero. The patterns do not change after this, also when the parameters change. Thus, for a sparse matrix type:

  • each callback must accept NaN inputs, and the parameters p = 0;
  • the pattern of each derivative must not depend on the values of x, p or t. For example, do not use an if on an input value to decide whether to write an output.

If a callback does not obey these rules, the matrix can be incorrect. Then the solver can converge slowly or fail. The dense matrix types do not use a pattern.

§Ownership of user_data

Each callback gets user_data as its last argument, with no change.

If free_user_data is set, OdeCallbacks owns user_data from the start of its construction. This is also true if the construction fails. OdeCallbacks calls free_user_data(user_data) one time, when it is dropped.

If free_user_data is not set, user_data must stay valid until the equations are dropped.

§Threads

The callbacks are called one at a time. They are never called at the same time from two threads.

But a solver can move between threads. An OdeWrapper is Send and Sync. Thus the callbacks run on the thread that uses the solver at that time. free_user_data runs on the thread that drops the solver. If user_data must stay on one thread (for example a Python object that needs the GIL, or a JNI local reference), use the solver and drop it only on that thread.

Structs§

OdeCallbacks
ODE equations defined by C callbacks, see the module documentation.
OdeCallbacksDesc
The C callbacks (and the problem dimensions) that define an OdeCallbacks.
OdeCallbacksInit
The initial condition of an OdeCallbacks.
OdeCallbacksMass
The mass matrix of an OdeCallbacks.
OdeCallbacksOut
The output function of an OdeCallbacks.
OdeCallbacksReset
The reset function of an OdeCallbacks.
OdeCallbacksRhs
The right-hand side F(x, p, t) of an OdeCallbacks.
OdeCallbacksRoot
The root function of an OdeCallbacks.

Enums§

OdeCallbackError
An error recorded while evaluating the callbacks of an OdeCallbacks.

Traits§

CallbackScalar
A scalar type that C callbacks can use: f64 or f32.

Type Aliases§

DiffsolOdeCallbacksF32
OdeCallbacksDesc for float precision.
DiffsolOdeCallbacksF64
OdeCallbacksDesc for double precision.
OdeCallbackFn
y = F(x, p, t): used for rhs, root, out and reset.
OdeCallbackFreeFn
Frees user_data, see the module documentation.
OdeCallbackInitFn
y = y0(p, t): the initial state.
OdeCallbackInitMulFn
y = A(p, t) v: used for init_sens and init_sens_adjoint.
OdeCallbackMassFn
y = M(p, t) v + beta y: used for mass (and mass_adjoint, with M^T).
OdeCallbackMulFn
y = A(x, p, t) v: used for every *_jac, *_sens, *_adjoint and *_sens_adjoint callback of rhs, root, out and reset.