DiffEqCallbackLibrary.jl provides a library of various helpful callbacks which can be used with any component solver which implements the callback interface. It adds the following callbacks which are available to users of DifferentialEquations.jl.
Manifold Conservation and Projection
In many cases, you may want to declare a manifold on which a solution lives. Mathematically, a manifold
M is defined by a function
g as the set of points where
g(u)=0. An embedded manifold can be a lower dimensional object which constrains the solution. For example,
E is the energy of the system in state
u, meaning that the energy must be constant (energy preservation). Thus by defining the manifold the solution should live on, you can retain desired properties of the solution.
It is a consequence of convergence proofs both in the deterministic and stochastic cases that post-step projection to manifolds keep the same convergence rate (stochastic requires a truncation in the proof, details details), thus any algorithm can be easily extended to conserve properties. If the solution is supposed to live on a specific manifold or conserve such property, this guarantees the conservation law without modifying the convergence properties.
g: The residual function for the manifold:
g(u,resid). This is an inplace function which writes to the residual the difference from the manifold components.
nlsolve: A nonlinear solver as defined in the nlsolve format
save: Whether to do the standard saving (applied after the callback)
Here we solve the harmonic oscillator:
u0 = ones(2) f = function (t,u,du) du = u du = -u end prob = ODEProblem(f,u0,(0.0,100.0))
However, this problem is supposed to conserve energy, and thus we define our manifold to conserve the sum of squares:
function g(u,resid) resid = u^2 + u^2 - 2 resid = 0 end
To build the callback, we just call
cb = ManifoldProjection(g)
Using this callback, the Runge-Kutta method
Vern7 conserves energy:
sol = solve(prob,Vern7(),callback=cb) @test sol[end]^2 + sol[end]^2 ≈ 2
Many problem solving environments such as MATLAB provide a way to automatically adapt the absolute tolerance to the problem. This helps the solvers automatically "learn" what appropriate limits are. Via the callback interface, DiffEqCallbacks.jl implements a callback
AutoAbstol which has the same behavior as the MATLAB implementation, that is the absolute tolerance starts and at each iteration it is set to the maximum value that the state has thus far reached times the relative tolerance. If
init_curmax is zero, then the initial value is determined by the
abstol of the solver. Otherwise this is the initial value for the current maximum abstol.
To generate the callback, use the constructor: