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.
| callback | x | p | v | y (output) |
|---|---|---|---|---|
rhs, reset | nstates | nparams | - | nstates |
rhs_jac, reset_jac (y = J v) | nstates | nparams | nstates | nstates |
rhs_sens, reset_sens (y = J_p v) | nstates | nparams | nparams | nstates |
rhs_adjoint, reset_adjoint (y = -J^T v) | nstates | nparams | nstates | nstates |
rhs_sens_adjoint, reset_sens_adjoint (y = -J_p^T v) | nstates | nparams | nstates | nparams |
root | nstates | nparams | - | nroots |
root_jac / root_sens | nstates | nparams | nstates / nparams | nroots |
root_adjoint / root_sens_adjoint | nstates | nparams | nroots | nstates / nparams |
out | nstates | nparams | - | nout |
out_jac / out_sens | nstates | nparams | nstates / nparams | nout |
out_adjoint / out_sens_adjoint | nstates | nparams | nout | nstates / nparams |
init | - | nparams | - | nstates |
init_sens / init_sens_adjoint | - | nparams | nparams / nstates | nstates / nparams |
mass / mass_adjoint (y = M v + beta y, M^T for the adjoint) | - | nparams | nstates | nstates |
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,port. For example, do not use anifon 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.
- OdeCallbacks
Desc - The C callbacks (and the problem dimensions) that define an
OdeCallbacks. - OdeCallbacks
Init - The initial condition of an
OdeCallbacks. - OdeCallbacks
Mass - The mass matrix of an
OdeCallbacks. - OdeCallbacks
Out - The output function of an
OdeCallbacks. - OdeCallbacks
Reset - The reset function of an
OdeCallbacks. - OdeCallbacks
Rhs - The right-hand side
F(x, p, t)of anOdeCallbacks. - OdeCallbacks
Root - The root function of an
OdeCallbacks.
Enums§
- OdeCallback
Error - An error recorded while evaluating the callbacks of an
OdeCallbacks.
Traits§
- Callback
Scalar - A scalar type that C callbacks can use:
f64orf32.
Type Aliases§
- Diffsol
OdeCallbacks F32 OdeCallbacksDescforfloatprecision.- Diffsol
OdeCallbacks F64 OdeCallbacksDescfordoubleprecision.- OdeCallback
Fn y = F(x, p, t): used forrhs,root,outandreset.- OdeCallback
Free Fn - Frees
user_data, see the module documentation. - OdeCallback
Init Fn y = y0(p, t): the initial state.- OdeCallback
Init MulFn y = A(p, t) v: used forinit_sensandinit_sens_adjoint.- OdeCallback
Mass Fn y = M(p, t) v + beta y: used formass(andmass_adjoint, withM^T).- OdeCallback
MulFn y = A(x, p, t) v: used for every*_jac,*_sens,*_adjointand*_sens_adjointcallback ofrhs,root,outandreset.