From 512a3e37987ac237d27d3b8b8a99abe00d975583 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Wed, 8 Jul 2026 06:16:20 -0400 Subject: [PATCH] Document output saving public APIs Co-Authored-By: Chris Rackauckas --- docs/src/output_saving.md | 3 ++ src/independentlylinearizedutils.jl | 20 ++++++++++ src/saving.jl | 62 +++++++++++++++++++---------- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/docs/src/output_saving.md b/docs/src/output_saving.md index 02916004..f6c50d37 100644 --- a/docs/src/output_saving.md +++ b/docs/src/output_saving.md @@ -3,8 +3,11 @@ These callbacks extend the output and saving controls available during time stepping. ```@docs +SavedValues SavingCallback FunctionCallingCallback +IndependentlyLinearizedSolution +LinearizingSavingCallback ``` ### Saving Example diff --git a/src/independentlylinearizedutils.jl b/src/independentlylinearizedutils.jl index fef59a1b..52bced69 100644 --- a/src/independentlylinearizedutils.jl +++ b/src/independentlylinearizedutils.jl @@ -157,6 +157,7 @@ end """ IndependentlyLinearizedSolution + IndependentlyLinearizedSolution(prob::SciMLBase.AbstractDEProblem, num_derivatives = 0) Efficient datastructure that holds a set of independently linearized solutions (obtained via the `LinearizingSavingCallback`) with related, but slightly @@ -165,6 +166,25 @@ denoting which `u` vectors are sampled at which timepoints. Provides an efficient `iterate()` method that can be used to reconstruct coherent views of the state variables at all timepoints, as well as an efficient `sample!()` method that can sample at arbitrary timesteps. + +## Arguments + + - `prob`: differential equation problem used to infer the time, state, and storage + dimensions. + - `num_derivatives`: number of derivative rows to store in addition to the primal + state values. + +## Returns + +An `IndependentlyLinearizedSolution` storage object for use with +[`LinearizingSavingCallback`](@ref). + +## Example + +```julia +ils = IndependentlyLinearizedSolution(prob) +sol = solve(prob, solver; callback = LinearizingSavingCallback(ils)) +``` """ mutable struct IndependentlyLinearizedSolution{T, S} # All timepoints, shared by all `us` diff --git a/src/saving.jl b/src/saving.jl index 25efa467..91dbe787 100644 --- a/src/saving.jl +++ b/src/saving.jl @@ -1,8 +1,13 @@ """ SavedValues{tType<:Real, savevalType} -A struct used to save values of the time in `t::Vector{tType}` and -additional values in `saveval::Vector{savevalType}`. +Container used by [`SavingCallback`](@ref) to store saved time points and +user-defined values. + +## Fields + + - `t::Vector{tType}`: saved time points. + - `saveval::Vector{savevalType}`: values returned by the saving function. """ struct SavedValues{tType, savevalType} t::Vector{tType} @@ -10,9 +15,21 @@ struct SavedValues{tType, savevalType} end """ - SavedValues(tType::DataType, savevalType::DataType) + SavedValues(tType::Type, savevalType::Type) Return `SavedValues{tType, savevalType}` with empty storage vectors. + +## Arguments + + - `tType`: the element type of saved time points. + - `savevalType`: the element type of saved values returned by the saving function. + +## Example + +```julia +saved_values = SavedValues(Float64, Tuple{Float64, Float64}) +cb = SavingCallback((u, t, integrator) -> (sum(u), maximum(u)), saved_values) +``` """ function SavedValues(::Type{tType}, ::Type{savevalType}) where {tType, savevalType} return SavedValues{tType, savevalType}(Vector{tType}(), Vector{savevalType}()) @@ -360,34 +377,39 @@ end LinearizingSavingCallback(ils::IndependentlyLinearizedSolution) LinearizingSavingCallback(ilss::Vector{IndependentlyLinearizedSolution}) -Provides a saving callback that inserts interpolation points into your signal such that -a naive linear interpolation of the resultant saved values will be within `abstol`/`reltol` -of the higher-order interpolation of your solution. This essentially makes a time/space -tradeoff, where more points in time are saved, costing more memory, but interpolation is -incredibly cheap and downstream algorithm complexity is reduced by not needing to bother -with multiple interpolation types. +Return a saving callback that inserts interpolation points so that linear interpolation +of the saved values is within `abstol`/`reltol` of the integrator interpolation. The algorithm internally checks 3 equidistant points between each time point to determine goodness of fit versus the linearly interpolated function; this should be sufficient for interpolations up to the 4th order, higher orders may need more points to ensure good fit. This has not been implemented yet. -This callback generator takes in an `IndependentlyLinearizedSolution` object to store -output into. An `IndependentlyLinearizedSolution` object itself controls how many -derivatives (if any) to linearize along with the primal states themselves. +## Arguments + + - `ils`: the [`IndependentlyLinearizedSolution`](@ref) storage object to fill. + - `ilss`: storage objects for multiple independently linearized solutions. + +## Keyword Arguments -Example usage: + - `interpolate_mask`: a `BitVector` selecting the `u` indices for which the + integrator interpolant can be queried. False indices are linearly interpolated + from the solution time points without subdivision. + - `abstol`: absolute tolerance for comparing linearized and integrator interpolation. + Defaults to the integrator absolute tolerance. + - `reltol`: relative tolerance for comparing linearized and integrator interpolation. + Defaults to the integrator relative tolerance. + +## Returns + +A `DiscreteCallback` that stores independently linearized output in `ils`. + +## Example ```julia ils = IndependentlyLinearizedSolution(prob) -solve(prob, solver; callback=LinearizingSavingCallback(ils)) +sol = solve(prob, solver; callback = LinearizingSavingCallback(ils)) ``` - -# Keyword Arguments -- `interpolate_mask::BitVector`: a set of `u` indices for which the integrator - interpolant can be queried. Any false indices will be linearly-interpolated - based on the `sol.t` points instead (no subdivision). This is useful for when - a solution needs to ignore certain indices due to badly-behaved interpolation. """ function LinearizingSavingCallback( ils::IndependentlyLinearizedSolution{T, S};