Output and Saving Controls
These callbacks extend the output and saving controls available during time stepping.
DiffEqCallbacks.SavingCallback — FunctionSavingCallback(save_func, saved_values::SavedValues;
saveat = Vector{eltype(saved_values.t)}(),
save_everystep = isempty(saveat),
save_start = true,
tdir = 1)The saving callback lets you define a function save_func(u, t, integrator) which returns quantities of interest that shall be saved.
Arguments
save_func(u, t, integrator)returns the quantities which shall be saved. Note that this should allocate the output (not as a view tou).saved_values::SavedValuesis the types thatsave_funcwill return, i.e.save_func(t, u, integrator)::savevalType. It's specified viaSavedValues(typeof(t),savevalType), i.e. give the type for time and the type thatsave_funcwill output (or higher compatible type).
Keyword Arguments
saveatmimicssaveatinsolvefromsolve.save_everystepmimicssave_everystepfromsolve.save_startmimicssave_startfromsolve.save_endmimicssave_endfromsolve.tdirshould besign(tspan[end]-tspan[1]). It defaults to1and should be adapted iftspan[1] > tspan[end].
The outputted values are saved into saved_values. Time points are found via saved_values.t and the values are saved_values.saveval.
DiffEqCallbacks.FunctionCallingCallback — FunctionFunctionCallingCallback(func;
funcat = Vector{Float64}(),
func_everystep = isempty(funcat),
func_start = true,
tdir = 1)The function calling callback lets you define a function func(u,t,integrator) which gets called at the time points of interest. The constructor is:
func(u, t, integrator)is the function to be called.funcatvalues or interval that the function is sure to be evaluated at.func_everystepwhether to call the function after each integrator step.func_startwhether the function is called at the initial condition.tdirshould besign(tspan[end]-tspan[1]). It defaults to1and should be adapted iftspan[1] > tspan[end].
Saving Example
In this example, we will solve a matrix equation and at each step save a tuple of values which contains the current trace and the norm of the matrix. We build the SavedValues cache to use Float64 for time and Tuple{Float64,Float64} for the saved values, and then call the solver with the callback.
using DiffEqCallbacks, OrdinaryDiffEq, LinearAlgebra
prob = ODEProblem((du, u, p, t) -> du .= u, rand(4, 4), (0.0, 1.0))
saved_values = SavedValues(Float64, Tuple{Float64, Float64})
cb = SavingCallback((u, t, integrator) -> (tr(u), norm(u)), saved_values)
sol = solve(prob, Tsit5(), callback = cb)
print(saved_values.saveval)[(2.3304426481770166, 2.274693045462265), (2.5763262914890723, 2.51469458073814), (3.303728030182394, 3.224695179790503), (4.622412906084299, 4.5118340496171285), (6.334799625114206, 6.18325649975391)]Note that the values are retrieved from the cache as .saveval, and the time points are found as .t. If we want to control the saved times, we use saveat in the callback. The save controls like saveat act analogously to how they act in the solve function.
saved_values = SavedValues(Float64, Tuple{Float64, Float64})
cb = SavingCallback((u, t, integrator) -> (tr(u), norm(u)), saved_values,
saveat = 0.0:0.1:1.0)
sol = solve(prob, Tsit5(), callback = cb)
print(saved_values.saveval)
print(saved_values.t)[(2.3304426481770166, 2.274693045462265), (2.5755374410625906, 2.5139246014466816), (2.846409182127877, 2.7783164611199687), (3.145768341081635, 3.0705142534579255), (3.476612526339016, 3.393443877117744), (3.842250184289253, 3.7503346327641527), (4.2463416883723, 4.14475932919988), (4.692935172498543, 4.580669259566708), (5.186495915003302, 5.062422882367509), (5.731962178512552, 5.59484032551264), (6.334799625114206, 6.18325649975391)][0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]