The cornerstone of the SciML common interface is the problem type definition. These definitions are the encoding of mathematical problems into a numerically computable form.
The symbolic analog to the problem interface is the ModelingToolkit AbstractSystem
. For example, ODESystem
is the symbolic analog to ODEProblem
. Each of these system types have a method for constructing the associated problem and function types.
The following standard principles should be adhered to across all AbstractSciMLProblem
instantiations.
Each AbstractSciMLProblem
type can be called with an "is inplace" (iip) choice. For example:
ODEProblem(f,u0,tspan,p)
+ODEProblem{iip}(f,u0,tspan,p)
which is a boolean for whether the function is in the inplace form (mutating to change the first value). This is automatically determined using the methods table but note that for full type-inferability of the AbstractSciMLProblem
this iip-ness should be specified.
Additionally, the functions are fully specialized to reduce the runtimes. If one would instead like to not specialize on the functions to reduce compile time, then one can set recompile
to false.
Specialization levels in problem definitions are used to control the amount of compilation specialization is performed on the model functions in order to trade off between runtime performance, simplicity, and compile-time performance. The default choice of specialization is AutoSpecialize
, which seeks to allow for using fully precompiled solvers in common scenarios but falls back to a runtime-optimal approach when further customization is used.
Specialization levels are given as the second type parameter in AbstractSciMLProblem
constructors. For example, this is done via:
ODEProblem{iip,specialization}(f,u0,tspan,p)
Note that iip
choice is required for specialization choices to be made.
abstract type AbstractSpecialization
Supertype for the specialization types. Controls the compilation and function specialization behavior of SciMLFunctions, ultimately controlling the runtime vs compile-time trade-off.
sourcestruct AutoSpecialize <: SciMLBase.AbstractSpecialization
The default specialization level for problem functions. AutoSpecialize
works by applying a function wrap just-in-time before the solve process to disable just-in-time re-specialization of the solver to the specific choice of model f
and thus allow for using a cached solver compilation from a different f
. This wrapping process can lead to a small decreased runtime performance with a benefit of a greatly decreased compile-time.
Note About Benchmarking and Runtime Optimality
It is recommended that AutoSpecialize
is not used in any benchmarking due to the potential effect of function wrapping on runtimes. AutoSpecialize
's use case is targeted at decreased latency for REPL performance and not for cases where where top runtime performance is required (such as in optimization loops). Generally, for non-stiff equations the cost will be minimal and potentially not even measurable. For stiff equations, function wrapping has the limitation that only chunk sized 1 Dual numbers are allowed, which can decrease Jacobian construction performance.
Limitations of AutoSpecialize
The following limitations are not fundamental to the implementation of AutoSpecialize
, but are instead chosen as a compromise between default precompilation times and ease of maintenance. Please open an issue to discuss lifting any potential limitations.
AutoSpecialize
is only setup to wrap the functions from in-place ODEs. Other cases are excluded for the time being due to time limitations.AutoSpecialize
will only lead to compilation reuse if the ODEFunction's other functions (such as jac and tgrad) are the default nothing
. These could be JIT wrapped as well in a future version.AutoSpecialize
'd functions are only compatible with Jacobian calculations performed with chunk size 1, and only with tag DiffEqBase.OrdinaryDiffEqTag()
. Thus ODE solvers written on the common interface must be careful to detect the AutoSpecialize
case and perform differentiation under these constraints, use finite differencing, or manually unwrap before solving. This will lead to decreased runtime performance for sufficiently large Jacobians.AutoSpecialize
only wraps on Julia v1.8 and higher.AutoSpecialize
does not handle cases with units. If unitful values are detected, wrapping is automatically disabled.AutoSpecialize
only wraps cases for which promote_rule
is defined between u0
and dual numbers, u0
and t
, and for which ArrayInterface.promote_eltype
is defined on u0
to dual numbers.AutoSpecialize
only wraps cases for which f.mass_matrix isa UniformScaling
, the default.AutoSpecialize
does not wrap cases where f isa AbstractSciMLOperator
- By default, only the
u0 isa Vector{Float64}
, eltype(tspan) isa Float64
, and typeof(p) isa Union{Vector{Float64},SciMLBase.NullParameters}
are specialized by the solver libraries. Other forms can be specialized with AutoSpecialize
, but must be done in the precompilation of downstream libraries. AutoSpecialize
d functions are manually unwrapped in adjoint methods in SciMLSensitivity.jl in order to allow compiler support for automatic differentiation. Improved versions of adjoints which decrease the recompilation surface will come in non-breaking updates.
Cases where automatic wrapping is disabled are equivalent to FullSpecialize
.
Example
f(du,u,p,t) = (du .= u)
+
+# Note this is the same as ODEProblem(f, [1.0], (0.0,1.0))
+# If no preferences are set
+ODEProblem{true, SciMLBase.AutoSpecialize}(f, [1.0], (0.0,1.0))
sourcestruct NoSpecialize <: SciMLBase.AbstractSpecialization
NoSpecialize
forces SciMLFunctions to not specialize on the types of functions wrapped within it. This ultimately contributes to a form such that every prob.f
type is the same, meaning compilation caches are fully reused, with the downside of losing runtime performance. NoSpecialize
is the form that most fully trades off runtime for compile time. Unlike AutoSpecialize
, NoSpecialize
can be used with any SciMLFunction
.
Example
f(du,u,p,t) = (du .= u)
+ODEProblem{true, SciMLBase.NoSpecialize}(f, [1.0], (0.0,1.0))
sourcestruct FunctionWrapperSpecialize <: SciMLBase.AbstractSpecialization
FunctionWrapperSpecialize
is an eager wrapping choice which performs a function wrapping during the ODEProblem
construction. This performs the function wrapping at the earliest possible point, giving the best compile-time vs runtime performance, but with the difficulty that any usage of prob.f
needs to account for the function wrapper's presence. While optimal in a performance sense, this method has many usability issues with nonstandard solvers and analyses as it requires unwrapping before re-wrapping for any type changes. Thus this method is not used by default. Given that the compile-time different is almost undetectable from AutoSpecialize, this method is mostly used as a benchmarking reference for speed of light for AutoSpecialize
.
Limitations of FunctionWrapperSpecialize
FunctionWrapperSpecialize
has all of the limitations of AutoSpecialize
, but also includes the limitations:
prob.f
is directly specialized to the types of (u,p,t)
, and any usage of prob.f
on other types first requires using SciMLBase.unwrapped_f(prob.f)
to remove the function wrapper.FunctionWrapperSpecialize
can only be used by the ODEProblem
constructor. If an ODEFunction
is being constructed, the user must manually use DiffEqBase.wrap_iip
on f
before calling ODEFunction{true,FunctionWrapperSpecialize}(f)
. This is a fundamental limitation of the approach as the types of (u,p,t)
are required in the construction process and not accessible in the AbstactSciMLFunction
constructors.
Example
f(du,u,p,t) = (du .= u)
+ODEProblem{true, SciMLBase.FunctionWrapperSpecialize}(f, [1.0], (0.0,1.0))
sourcestruct FullSpecialize <: SciMLBase.AbstractSpecialization
FullSpecialize
is an eager specialization choice which directly types the AbstractSciMLFunction
struct to match the type of the model f
. This forces recompilation of the solver on each new function type f
, leading to the most compile times with the benefit of having the best runtime performance.
FullSpecialize
should be used in all cases where top runtime performance is required, such as in long-running simulations and benchmarking.
Example
f(du,u,p,t) = (du .= u)
+ODEProblem{true, SciMLBase.FullSpecialize}(f, [1.0], (0.0,1.0))
sourceThe specialization level must be precompile snooped in the appropriate solver package in order to enable the full precompilation and system image generation for zero-latency usage. By default, this is only done with AutoSpecialize and on types u isa Vector{Float64}
, eltype(tspan) isa Float64
, and p isa Union{Vector{Float64}, SciMLBase.NullParameters}
. Precompilation snooping in the solvers can be done using the Preferences.jl setup on the appropriate solver. See the solver library's documentation for more details.
By default, AbstractSciMLProblem
types use the SciMLBase.NullParameters()
singleton to define the absence of parameters by default. The reason is because this throws an informative error if the parameter is used or accessed within the user's function, for example, p[1]
will throw an informative error about forgetting to pass parameters.
All AbstractSciMLProblem
types allow for passing keyword arguments that would get forwarded to the solver. The reason for this is that in many cases, like in EnsembleProblem
usage, a AbstractSciMLProblem
might be associated with some solver configuration, such as a callback or tolerance. Thus, for flexibility the extra keyword arguments to the AbstractSciMLProblem
are carried to the solver.
AbstractSciMLProblem
types include a non-public API definition of problem_type
which holds a trait type corresponding to the way the AbstractSciMLProblem
was constructed. For example, if a SecondOrderODEProblem
constructor is used, the returned problem is simply a ODEProblem
for interoperability with any ODEProblem
algorithm. However, in this case the problem_type
will be populated with the SecondOrderODEProblem
type, indicating the original definition and extra structure.
remake(thing; <keyword arguments>)
Re-construct thing
with new field values specified by the keyword arguments.
sourceremake(prob::ODEProblem; f = missing, u0 = missing, tspan = missing,
+ p = missing, kwargs = missing, _kwargs...)
Remake the given ODEProblem
. If u0
or p
are given as symbolic maps ModelingToolkit.jl
has to be loaded.
sourceremake(prob::SDEProblem; f = missing, u0 = missing, tspan = missing,
+ p = missing, noise = missing, noise_rate_prototype = missing,
+ seed = missing, kwargs = missing, _kwargs...)
Remake the given SDEProblem
.
sourceremake(prob::OptimizationProblem; f = missing, u0 = missing, p = missing,
+ lb = missing, ub = missing, int = missing, lcons = missing, ucons = missing,
+ sense = missing, kwargs = missing, _kwargs...)
Remake the given OptimizationProblem
. If u0
or p
are given as symbolic maps ModelingToolkit.jl
has to be loaded.
sourceremake(prob::NonlinearProblem; f = missing, u0 = missing, p = missing,
+ problem_type = missing, kwargs = missing, _kwargs...)
Remake the given NonlinearProblem
. If u0
or p
are given as symbolic maps ModelingToolkit.jl
has to be loaded.
sourceisinplace(prob::AbstractSciMLProblem)
Determine whether the function of the given problem operates in place or not.
sourceis_diagonal_noise(prob::AbstractSciMLProblem)
sourceSpecializationLevel
at SciMLBase
can be used to set the default specialization level. The following shows how to set the specialization default to FullSpecialize
:
using Preferences, UUIDs
+set_preferences!(UUID("0bca4576-84f4-4d90-8ffe-ffa030f20462"), "SpecializationLevel" => "FullSpecialize")
The default is AutoSpecialize
.
abstract type AbstractSciMLProblem
sourceabstract type AbstractDEProblem <: SciMLBase.AbstractSciMLProblem
Base type for all DifferentialEquations.jl problems. Concrete subtypes of AbstractDEProblem
contain the necessary information to fully define a differential equation of the corresponding type.
sourceabstract type AbstractLinearProblem{bType, isinplace} <: SciMLBase.AbstractSciMLProblem
Base for types which define linear systems.
sourceabstract type AbstractNonlinearProblem{uType, isinplace} <: SciMLBase.AbstractDEProblem
Base for types which define nonlinear solve problems (f(u)=0).
sourceabstract type AbstractIntegralProblem{isinplace} <: SciMLBase.AbstractSciMLProblem
Base for types which define integrals suitable for quadrature.
sourceabstract type AbstractOptimizationProblem{isinplace} <: SciMLBase.AbstractSciMLProblem
Base for types which define equations for optimization.
sourceabstract type AbstractNoiseProblem <: SciMLBase.AbstractDEProblem
sourceabstract type AbstractODEProblem{uType, tType, isinplace} <: SciMLBase.AbstractDEProblem
Base for types which define ODE problems.
sourceabstract type AbstractDiscreteProblem{uType, tType, isinplace} <: SciMLBase.AbstractODEProblem{uType, tType, isinplace}
Base for types which define discrete problems.
sourceabstract type AbstractAnalyticalProblem{uType, tType, isinplace} <: SciMLBase.AbstractODEProblem{uType, tType, isinplace}
sourceabstract type AbstractRODEProblem{uType, tType, isinplace, ND} <: SciMLBase.AbstractDEProblem
Base for types which define RODE problems.
sourceabstract type AbstractSDEProblem{uType, tType, isinplace, ND} <: SciMLBase.AbstractRODEProblem{uType, tType, isinplace, ND}
Base for types which define SDE problems.
sourceabstract type AbstractDAEProblem{uType, duType, tType, isinplace} <: SciMLBase.AbstractDEProblem
Base for types which define DAE problems.
sourceabstract type AbstractDDEProblem{uType, tType, lType, isinplace} <: SciMLBase.AbstractDEProblem
Base for types which define DDE problems.
sourceabstract type AbstractConstantLagDDEProblem{uType, tType, lType, isinplace} <: SciMLBase.AbstractDDEProblem{uType, tType, lType, isinplace}
sourceabstract type AbstractSecondOrderODEProblem{uType, tType, isinplace} <: SciMLBase.AbstractODEProblem{uType, tType, isinplace}
sourceabstract type AbstractBVProblem{uType, tType, isinplace} <: SciMLBase.AbstractODEProblem{uType, tType, isinplace}
Base for types which define BVP problems.
sourceabstract type AbstractJumpProblem{P, J} <: SciMLBase.AbstractDEProblem
Base for types which define jump problems.
sourceabstract type AbstractSDDEProblem{uType, tType, lType, isinplace, ND} <: SciMLBase.AbstractDEProblem
Base for types which define SDDE problems.
sourceabstract type AbstractConstantLagSDDEProblem{uType, tType, lType, isinplace, ND} <: SciMLBase.AbstractSDDEProblem{uType, tType, lType, isinplace, ND}
sourceabstract type AbstractPDEProblem <: SciMLBase.AbstractDEProblem
Base for types which define PDE problems.
source