Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/clock.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,60 @@ discrete-time systems that assume a fixed sample time, such as PID controllers a
filters.
""" SolverStepClock

"""
isclock(clock)

Returns `true` if the object is a valid clock type (specifically a `PeriodicClock`).
This function is used for type checking in clock-dependent logic.
"""
isclock(c::Clocks.Type) = @match c begin
PeriodicClock() => true
_ => false
end
isclock(::TimeDomain) = false

"""
issolverstepclock(clock)

Returns `true` if the clock is a `SolverStepClock` that triggers at every solver step.
This is useful for monitoring solver progress or implementing step-dependent logic.
"""
issolverstepclock(c::Clocks.Type) = @match c begin
SolverStepClock() => true
_ => false
end
issolverstepclock(::TimeDomain) = false

"""
iscontinuous(clock)

Returns `true` if the clock operates in continuous time (i.e., is a `ContinuousClock`).
Continuous clocks allow events to occur at any real-valued time instant.
"""
iscontinuous(c::Clocks.Type) = @match c begin
ContinuousClock() => true
_ => false
end
iscontinuous(::TimeDomain) = false

"""
iseventclock(clock)

Returns `true` if the clock is an `EventClock` that triggers based on specific events.
Event clocks are used for condition-based triggering in hybrid systems.
"""
iseventclock(c::Clocks.Type) = @match c begin
EventClock() => true
_ => false
end
iseventclock(::TimeDomain) = false

"""
is_discrete_time_domain(clock)

Returns `true` if the clock operates in discrete time (i.e., is not a continuous clock).
Discrete time domains have specific sampling intervals or event-based triggering.
"""
is_discrete_time_domain(c::TimeDomain) = !iscontinuous(c)

# workaround for https://github.com/Roger-luo/Moshi.jl/issues/43
Expand Down
129 changes: 129 additions & 0 deletions src/function_wrappers.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
"""
AbstractWrappedFunction{iip}

Abstract base type for function wrappers used in automatic differentiation and sensitivity analysis.
These wrappers provide specialized interfaces for computing derivatives with respect to different variables.

# Type Parameter
- `iip`: Boolean indicating if the function is in-place (`true`) or out-of-place (`false`)
"""
abstract type AbstractWrappedFunction{iip} end
isinplace(f::AbstractWrappedFunction{iip}) where {iip} = iip

"""
TimeGradientWrapper{iip, fType, uType, P} <: AbstractWrappedFunction{iip}

Wraps functions to compute gradients with respect to time. This wrapper is particularly useful for
sensitivity analysis and optimization problems where the time dependence of the solution is critical.

# Fields
- `f`: The function to wrap
- `uprev`: Previous state value
- `p`: Parameters

# Type Parameters
- `iip`: Boolean indicating if the function is in-place (`true`) or out-of-place (`false`)
- `fType`: Type of the wrapped function
- `uType`: Type of the state variables
- `P`: Type of the parameters

This wrapper enables automatic differentiation with respect to time by providing a consistent
interface for computing `∂f/∂t` across different AD systems.
"""
mutable struct TimeGradientWrapper{iip, fType, uType, P} <: AbstractWrappedFunction{iip}
f::fType
uprev::uType
Expand All @@ -20,6 +50,27 @@ end

(ff::TimeGradientWrapper{false})(t) = ff.f(ff.uprev, ff.p, t)

"""
UJacobianWrapper{iip, fType, tType, P} <: AbstractWrappedFunction{iip}

Wraps functions to compute Jacobians with respect to state variables `u`. This is one of the most
commonly used wrappers in the SciML ecosystem for computing the derivative of the right-hand side
function with respect to the state variables.

# Fields
- `f`: The function to wrap
- `t`: Time value
- `p`: Parameters

# Type Parameters
- `iip`: Boolean indicating if the function is in-place (`true`) or out-of-place (`false`)
- `fType`: Type of the wrapped function
- `tType`: Type of the time variable
- `P`: Type of the parameters

This wrapper enables efficient computation of `∂f/∂u` for Jacobian calculations in numerical solvers
and automatic differentiation systems.
"""
mutable struct UJacobianWrapper{iip, fType, tType, P} <: AbstractWrappedFunction{iip}
f::fType
t::tType
Expand All @@ -43,6 +94,26 @@ end
(ff::UJacobianWrapper{false})(uprev) = ff.f(uprev, ff.p, ff.t)
(ff::UJacobianWrapper{false})(uprev, p, t) = ff.f(uprev, p, t)

"""
TimeDerivativeWrapper{iip, F, uType, P} <: AbstractWrappedFunction{iip}

Wraps functions to compute derivatives with respect to time. This wrapper is used when you need to
compute `∂f/∂t` for sensitivity analysis or when the function has explicit time dependence.

# Fields
- `f`: The function to wrap
- `u`: State variables
- `p`: Parameters

# Type Parameters
- `iip`: Boolean indicating if the function is in-place (`true`) or out-of-place (`false`)
- `F`: Type of the wrapped function
- `uType`: Type of the state variables
- `P`: Type of the parameters

This wrapper provides a consistent interface for time derivative computations across different
automatic differentiation backends.
"""
mutable struct TimeDerivativeWrapper{iip, F, uType, P} <: AbstractWrappedFunction{iip}
f::F
u::uType
Expand All @@ -60,6 +131,26 @@ end
(ff::TimeDerivativeWrapper{true})(du1, t) = ff.f(du1, ff.u, ff.p, t)
(ff::TimeDerivativeWrapper{true})(t) = (du1 = similar(ff.u); ff.f(du1, ff.u, ff.p, t); du1)

"""
UDerivativeWrapper{iip, F, tType, P} <: AbstractWrappedFunction{iip}

Wraps functions to compute derivatives with respect to state variables. This wrapper is used for
computing `∂f/∂u` and is fundamental for Jacobian computations in numerical solvers.

# Fields
- `f`: The function to wrap
- `t`: Time value
- `p`: Parameters

# Type Parameters
- `iip`: Boolean indicating if the function is in-place (`true`) or out-of-place (`false`)
- `F`: Type of the wrapped function
- `tType`: Type of the time variable
- `P`: Type of the parameters

This wrapper enables efficient state derivative computations for use in automatic differentiation
and numerical analysis algorithms.
"""
mutable struct UDerivativeWrapper{iip, F, tType, P} <: AbstractWrappedFunction{iip}
f::F
t::tType
Expand All @@ -75,6 +166,26 @@ UDerivativeWrapper(f::F, t, p) where {F} = UDerivativeWrapper{isinplace(f, 4)}(f
(ff::UDerivativeWrapper{true})(du1, u) = ff.f(du1, u, ff.p, ff.t)
(ff::UDerivativeWrapper{true})(u) = (du1 = similar(u); ff.f(du1, u, ff.p, ff.t); du1)

"""
ParamJacobianWrapper{iip, fType, tType, uType} <: AbstractWrappedFunction{iip}

Wraps functions to compute Jacobians with respect to parameters `p`. This wrapper is essential for
parameter estimation, inverse problems, and sensitivity analysis with respect to model parameters.

# Fields
- `f`: The function to wrap
- `t`: Time value
- `u`: State variables

# Type Parameters
- `iip`: Boolean indicating if the function is in-place (`true`) or out-of-place (`false`)
- `fType`: Type of the wrapped function
- `tType`: Type of the time variable
- `uType`: Type of the state variables

This wrapper enables efficient computation of `∂f/∂p` for parameter sensitivity analysis and
optimization algorithms.
"""
mutable struct ParamJacobianWrapper{iip, fType, tType, uType} <: AbstractWrappedFunction{iip}
f::fType
t::tType
Expand All @@ -97,6 +208,24 @@ function (ff::ParamJacobianWrapper{false})(du1, p)
du1 .= ff.f(ff.u, p, ff.t)
end

"""
JacobianWrapper{iip, fType, pType} <: AbstractWrappedFunction{iip}

A general-purpose Jacobian wrapper that can be configured for different types of Jacobian computations.
This wrapper provides a unified interface for various Jacobian calculations across the SciML ecosystem.

# Fields
- `f`: The function to wrap
- `p`: Parameters

# Type Parameters
- `iip`: Boolean indicating if the function is in-place (`true`) or out-of-place (`false`)
- `fType`: Type of the wrapped function
- `pType`: Type of the parameters

This wrapper provides a flexible interface for Jacobian computations that can adapt to different
automatic differentiation backends and numerical methods.
"""
mutable struct JacobianWrapper{iip, fType, pType} <: AbstractWrappedFunction{iip}
f::fType
p::pType
Expand Down
34 changes: 34 additions & 0 deletions src/integrator_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,50 @@ The length of the tuple is dependent on the method.
function get_tmp_cache(i::DEIntegrator)
error("get_tmp_cache!: method has not been implemented for the integrator")
end
"""
user_cache(integrator::DEIntegrator)

Returns user-accessible cache components from the integrator. These are cache arrays that users
can safely access and modify without breaking the internal integrator state.
"""
function user_cache(i::DEIntegrator)
error("user_cache: method has not been implemented for the integrator")
end

"""
u_cache(integrator::DEIntegrator)

Returns the state variable cache arrays used by the integrator. These contain intermediate
state values during the integration process.
"""
function u_cache(i::DEIntegrator)
error("u_cache: method has not been implemented for the integrator")
end

"""
du_cache(integrator::DEIntegrator)

Returns the derivative cache arrays used by the integrator. These contain intermediate
derivative values during the integration process.
"""
function du_cache(i::DEIntegrator)
error("du_cache: method has not been implemented for the integrator")
end

"""
ratenoise_cache(integrator::DEIntegrator)

Returns cache arrays for rate noise in stochastic differential equations.
Returns an empty tuple by default for deterministic problems.
"""
ratenoise_cache(i::DEIntegrator) = ()

"""
rand_cache(integrator::DEIntegrator)

Returns cache arrays for random number generation in stochastic differential equations.
Returns an empty tuple by default for deterministic problems.
"""
rand_cache(i::DEIntegrator) = ()

"""
Expand Down
Loading