Solver Implementation via OrdinaryDiffEq.jl
ProbNumDiffEq.jl builds directly on OrdinaryDiffEq.jl to benefit from its iterator interface, flexible step-size control, and efficient Jacobian calculations. But, this requires extending non-public APIs. This page is meant to provide an overview on which parts exactly ProbNumDiffEq.jl builds on.
For more discussion on the pros and cons of building on OrdinaryDiffEq.jl, see this thread on discourse.
Building on OrdinaryDiffEq.jl
ProbNumDiffEq.jl shares most of OrdinaryDiffEq.jl's implementation. In particular:
OrdinaryDiffEq.__initbuilds the cache and the integrator, and callsOrdinaryDiffEq.initialize!OrdinaryDiffEq.solve!implements the actual iterator structure, withOrdinaryDiffEq.loopheader!OrdinaryDiffEq.perform_step!OrdinaryDiffEq.loopfooter!OrdinaryDiffEq.postamble!
ProbNumDiffEq.jl builds around this structure and overloads some of the parts:
- Algorithms:
EK0/EK1 <: AbstractEK <: OrdinaryDiffEq.OrdinaryDiffEqAdaptiveAlgorithm./src/algorithms.jlprovides the algorithms themselves./src/alg_utils.jlimplements many traits (relating to automatic differentiation, implicitness, step-size control, etc)
- Cache:
EKCache <: AbstractODEFilterCache <: OrdinaryDiffEq.OrdinaryDiffEqCache./src/caches.jlimplements the cache and its main constructor:OrdinaryDiffEq.alg_cache
- Initialization and
perform_step!: viaOrdinaryDiffEq.initialize!andOrdinaryDiffEq.perform_step!. Implemented in./src/perform_step.jl. - Custom postamble by overloading
OrdinaryDiffEq.postamble!(which should always callOrdinaryDiffEq._postamble!). This is where we do the "smoothing" of the solution. Implemented in./src/integrator_utils.jl. - Custom saving by overloading
OrdinaryDiffEq.savevalues!(which should always callOrdinaryDiffEq._savevalues!). Implemented in./src/integrator_utils.jl.
Building on DiffEqBase.jl
DiffEqBase.__initis currently overloaded to transform OOP problems into IIP problems (in./src/solve.jl).- The solution object:
ProbODESolution <: AbstractProbODESolution <: DiffEqBase.AbstractODESolution./src/solution.jlimplements the main parts. Note that the main constructorDiffEqBase.build_solutionis called byOrdinaryDiffEq.__init, so OrdinaryDiffEq.jl has control over its inputs.MeanProbODESolution <: DiffEqBase.AbstractODESolutionis a wrapper that allows handling the mean of a probabilistic ODE solution the same way one would handle any "standard" ODE solution, by just ignoring the covariances.AbstractODEFilterPosterior <: DiffEqBase.AbstractDiffEqInterpolationhandles the interpolation.- Plot recipe in
./ext/RecipesBaseExt.jl - Sampling in
./src/solution_sampling.jl
DiffEqBase.prepare_alg(::EK1{0}); closely follows a similar function implemented in OrdinaryDiffEq.jl./src/alg_utils.jl- this also required
DiffEqBase.remake(::EK1)
- this also required
Other packages
DiffEqDevTools.appxtrue: We extend this function to work withProbODESolution. This also enablesDiffEqDevTools.WorkPrecisionto work out of the box.