diff --git a/docs/make.jl b/docs/make.jl index bef651f7662..131a72bc40a 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,17 +1,12 @@ using Documenter, OrdinaryDiffEq, DiffEqDevTools +using DiffEqBase using OrdinaryDiffEqCore # Bring controller API symbols into Main so unqualified @ref links in # docs/src/api/controllers.md resolve. These are not exported by # OrdinaryDiffEqCore but are documented public API. using OrdinaryDiffEqCore: default_controller, resolve_basic, get_EEst, set_EEst!, CompositeController -using OrdinaryDiffEqDifferentiation using OrdinaryDiffEqNonlinearSolve -# Bring the non-exported nonlinear-solver public names referenced by unqualified -# `@ref` links in the docstrings into Main so those links resolve, matching the -# controller-symbol pattern above. -using OrdinaryDiffEqNonlinearSolve: build_nlsolver, nlsolve!, nlsolvefail, - anderson, anderson!, NLNewton, NLFunctional, NLAnderson using ImplicitDiscreteSolve using OrdinaryDiffEqAMF using OrdinaryDiffEqAdamsBashforthMoulton @@ -54,8 +49,8 @@ makedocs( doctest = false, modules = [ OrdinaryDiffEq, + DiffEqBase, OrdinaryDiffEqCore, - OrdinaryDiffEqDifferentiation, OrdinaryDiffEqNonlinearSolve, OrdinaryDiffEqAdamsBashforthMoulton, OrdinaryDiffEqBDF, diff --git a/docs/pages.jl b/docs/pages.jl index 86ada927d34..41962c151fd 100644 --- a/docs/pages.jl +++ b/docs/pages.jl @@ -53,8 +53,9 @@ pages = [ "misc.md", ], "APIs" => [ + "api/diffeqbase.md", + "api/ordinarydiffeqcore.md", "api/controllers.md", - "api/solver_author.md", ], "Developer Documentation" => [ "devtools/index.md", @@ -73,6 +74,7 @@ pages = [ ], "Internal Documentation" => [ "devtools/internals/notes_on_algorithms.md", + "devtools/internals/public_api.md", "devtools/internals/tableaus.md", ], ], diff --git a/docs/src/api/diffeqbase.md b/docs/src/api/diffeqbase.md new file mode 100644 index 00000000000..f106a791655 --- /dev/null +++ b/docs/src/api/diffeqbase.md @@ -0,0 +1,44 @@ +# DiffEqBase API + +This page lists the user-facing DiffEqBase API documented with OrdinaryDiffEq. +Solver-author hooks, callback machinery, and cache types are documented separately +in the [developer extension API](@ref Developer-Extension-API). + +## Default callback behavior + +```@docs +DiffEqBase.ODE_DEFAULT_ISOUTOFDOMAIN +DiffEqBase.ODE_DEFAULT_NORM +DiffEqBase.ODE_DEFAULT_PROG_MESSAGE +DiffEqBase.ODE_DEFAULT_UNSTABLE_CHECK +``` + +## Runge-Kutta tableau types + +```@docs +DiffEqBase.Tableau +DiffEqBase.ODERKTableau +DiffEqBase.ExplicitRKTableau +DiffEqBase.ImplicitRKTableau +``` + +## Cost and convergence helpers + +```@docs +DiffEqBase.ConvergenceSetup +DiffEqBase.DECostFunction +``` + +## DAE initialization + +```@docs +DiffEqBase.DefaultInit +DiffEqBase.BrownFullBasicInit +DiffEqBase.ShampineCollocationInit +``` + +## Sensitivity passthrough + +```@docs +DiffEqBase.SensitivityADPassThrough +``` diff --git a/docs/src/api/ordinarydiffeqcore.md b/docs/src/api/ordinarydiffeqcore.md new file mode 100644 index 00000000000..cd0f5ed036a --- /dev/null +++ b/docs/src/api/ordinarydiffeqcore.md @@ -0,0 +1,52 @@ +# OrdinaryDiffEqCore API + +This page lists user-facing OrdinaryDiffEqCore API. The controller API has its +own page, and solver-author hooks are documented separately in the +[developer extension API](@ref Developer-Extension-API). + +## Integrator objects + +```@docs +OrdinaryDiffEqCore.ODEIntegrator +``` + +## Threading options + +```@docs +OrdinaryDiffEqCore.AbstractThreadingOption +OrdinaryDiffEqCore.Sequential +OrdinaryDiffEqCore.BaseThreads +OrdinaryDiffEqCore.PolyesterThreads +OrdinaryDiffEqCore.isthreaded +``` + +## Automatic algorithm switching + +```@docs +OrdinaryDiffEqCore.AutoAlgSwitch +OrdinaryDiffEqCore.AutoSwitch +``` + +## SSP helpers + +```@docs +OrdinaryDiffEqCore.ssp_coefficient +``` + +## Implicit method predictors + +```@docs +OrdinaryDiffEqCore.Predictor +``` + +## Nonlinear solver algorithms + +These OrdinaryDiffEqNonlinearSolve algorithms are public user API because they +are passed directly through implicit solver constructors as `nlsolve = ...`. +Lower-level nonlinear-solve hooks are internal implementation details. + +```@docs +OrdinaryDiffEqNonlinearSolve.NLAnderson +OrdinaryDiffEqNonlinearSolve.NLFunctional +OrdinaryDiffEqNonlinearSolve.NLNewton +``` diff --git a/docs/src/api/solver_author.md b/docs/src/devtools/internals/public_api.md similarity index 59% rename from docs/src/api/solver_author.md rename to docs/src/devtools/internals/public_api.md index 8769e0c4754..949f2f0a983 100644 --- a/docs/src/api/solver_author.md +++ b/docs/src/devtools/internals/public_api.md @@ -1,14 +1,46 @@ -# Solver-author extension API +# Developer Extension API -This page documents the `public` extension API of the OrdinaryDiffEq.jl core and -solver sublibraries — the names that downstream solver packages (the OrdinaryDiffEq -solver sublibs, StochasticDiffEq.jl, DelayDiffEq.jl, …) subtype, extend, or call -when adding a new solver. These are *not exported*: they are marked `public` so -they are recognized as a supported extension surface rather than internal access. +This page documents the version-controlled API intended for solver authors and +OrdinaryDiffEq monorepo subpackages. These names are not application-facing +OrdinaryDiffEq user API; user-facing DiffEqBase and OrdinaryDiffEqCore APIs are +documented under the API section. -Everyday users do not need this page; it is for people writing new solvers. The -step-size controller interface has its own dedicated page, the -[Controller API](@ref). +!!! warning "Developer API, not user API" + + Do not build application code against these hooks. They exist so solver + packages can extend common traits, controllers, interpolation hooks, and + initialization protocols without depending on undocumented implementation + details. Cache types and low-level nonlinear solve helper functions are not + public API. + +## DiffEqBase solver hooks + +```@docs +DiffEqBase.CallbackCache +DiffEqBase.EvalFunc +DiffEqBase.OrdinaryDiffEqTag +DiffEqBase.apply_callback! +DiffEqBase.apply_discrete_callback! +DiffEqBase.calculate_residuals +DiffEqBase.calculate_residuals! +DiffEqBase.check_prob_alg_pairing +DiffEqBase.default_factorize +DiffEqBase.finalize! +DiffEqBase.find_callback_time +DiffEqBase.find_first_continuous_callback +DiffEqBase.get_condition +DiffEqBase.get_tstops +DiffEqBase.get_tstops_array +DiffEqBase.get_tstops_max +DiffEqBase.initialize! +DiffEqBase.max_vector_callback_length +DiffEqBase.max_vector_callback_length_int +DiffEqBase.merge_problem_kwargs +DiffEqBase.prepare_alg +DiffEqBase.prob2dtmin +DiffEqBase.stripunits +DiffEqBase.timedepentdtmin +``` ## Algorithm type hierarchy @@ -42,8 +74,8 @@ OrdinaryDiffEqCore.ImplicitSecondOrderAlgorithm ### SDE / RODE algorithm hierarchy -Subtyped by StochasticDiffEq.jl; defined in the core so the shared machinery can -dispatch on them. +Subtyped by StochasticDiffEq.jl and defined in the core so shared machinery can +dispatch on these algorithms. ```@docs OrdinaryDiffEqCore.StochasticDiffEqAlgorithm @@ -62,50 +94,10 @@ OrdinaryDiffEqCore.StochasticDiffEqJumpDiffusionAdaptiveAlgorithm OrdinaryDiffEqCore.StochasticDiffEqJumpNewtonDiffusionAdaptiveAlgorithm ``` -## Cache type hierarchy - -```@docs -OrdinaryDiffEqCore.OrdinaryDiffEqCache -OrdinaryDiffEqCore.OrdinaryDiffEqConstantCache -OrdinaryDiffEqCore.OrdinaryDiffEqMutableCache -OrdinaryDiffEqCore.CompositeCache -OrdinaryDiffEqCore.DefaultCache -OrdinaryDiffEqCore.AutoSwitchCache -OrdinaryDiffEqCore.StochasticDiffEqCache -OrdinaryDiffEqCore.StochasticDiffEqConstantCache -OrdinaryDiffEqCore.StochasticDiffEqMutableCache -OrdinaryDiffEqCore.@cache -OrdinaryDiffEqCore.strip_cache -OrdinaryDiffEqCore.is_constant_cache -OrdinaryDiffEqCore.is_composite_cache -OrdinaryDiffEqCore.is_composite_algorithm -OrdinaryDiffEqCore.isdiscretecache -OrdinaryDiffEqCore.get_fsalfirstlast -OrdinaryDiffEqCore.alg_cache -``` - -Example solver-sublibrary caches that are declared public so other sublibraries -can reuse their step: - -```@docs -OrdinaryDiffEqLowOrderRK.BS3Cache -OrdinaryDiffEqLowOrderRK.BS3ConstantCache -OrdinaryDiffEqLowOrderRK.RK4Cache -OrdinaryDiffEqLowOrderRK.RK4ConstantCache -OrdinaryDiffEqTsit5.Tsit5Cache -OrdinaryDiffEqTsit5.Tsit5ConstantCache -OrdinaryDiffEqSDIRK.ESDIRKIMEXCache -OrdinaryDiffEqSDIRK.ESDIRKIMEXConstantCache -OrdinaryDiffEqSDIRK.ImplicitEulerESDIRKIMEXTableau -OrdinaryDiffEqRosenbrock.RosenbrockMutableCache -``` - ## Composite algorithms and automatic switching ```@docs OrdinaryDiffEqCore.CompositeAlgorithm -OrdinaryDiffEqCore.AutoSwitch -OrdinaryDiffEqCore.AutoAlgSwitch OrdinaryDiffEqCore.isautoswitch OrdinaryDiffEqCore.default_autoswitch OrdinaryDiffEqCore.unwrap_alg @@ -114,7 +106,7 @@ OrdinaryDiffEqCore.isdefaultalg ## Algorithm trait functions -Solver sublibraries specialize these to describe their algorithm. +Solver sublibraries specialize these to describe their algorithms. ```@docs OrdinaryDiffEqCore.alg_order @@ -150,7 +142,6 @@ OrdinaryDiffEqCore.issplit OrdinaryDiffEqCore.only_diagonal_mass_matrix OrdinaryDiffEqCore.standardtag OrdinaryDiffEqCore.concrete_jac -OrdinaryDiffEqCore.ssp_coefficient OrdinaryDiffEqCore.fac_default_gamma OrdinaryDiffEqCore.default_linear_interpolation ``` @@ -172,63 +163,35 @@ OrdinaryDiffEqCore.constvalue OrdinaryDiffEqCore.unitfulvalue ``` -## Threading options - -```@docs -OrdinaryDiffEqCore.AbstractThreadingOption -OrdinaryDiffEqCore.Sequential -OrdinaryDiffEqCore.BaseThreads -OrdinaryDiffEqCore.PolyesterThreads -OrdinaryDiffEqCore.isthreaded -``` - ## Enums and status types ```@docs -OrdinaryDiffEqCore.DIRK OrdinaryDiffEqCore.COEFFICIENT_MULTISTEP -OrdinaryDiffEqCore.NORDSIECK_MULTISTEP -OrdinaryDiffEqCore.GLM -OrdinaryDiffEqCore.FastConvergence +OrdinaryDiffEqCore.CompiledFloats OrdinaryDiffEqCore.Convergence -OrdinaryDiffEqCore.SlowConvergence -OrdinaryDiffEqCore.VerySlowConvergence +OrdinaryDiffEqCore.DifferentialVarsUndefined +OrdinaryDiffEqCore.DIRK OrdinaryDiffEqCore.Divergence +OrdinaryDiffEqCore.FastConvergence +OrdinaryDiffEqCore.GLM +OrdinaryDiffEqCore.MethodType +OrdinaryDiffEqCore.NLStatus +OrdinaryDiffEqCore.NORDSIECK_MULTISTEP +OrdinaryDiffEqCore.SlowConvergence OrdinaryDiffEqCore.TryAgain -``` - -## Error and sentinel types - -```@docs -OrdinaryDiffEqCore.CompiledFloats -OrdinaryDiffEqCore.DerivativeOrderNotPossibleError -OrdinaryDiffEqCore.DifferentialVarsUndefined +OrdinaryDiffEqCore.VerySlowConvergence ``` ## Nonlinear solver interface -The nonlinear-solver types and hooks live in `OrdinaryDiffEqNonlinearSolve`; the -abstract types and W-matrix hook stubs live in the core. +The public nonlinear-solver algorithms are documented on the OrdinaryDiffEqCore +API page. These core abstractions and W-matrix hooks are the solver-author +extension points. ```@docs OrdinaryDiffEqCore.AbstractNLSolver OrdinaryDiffEqCore.AbstractNLSolverAlgorithm -OrdinaryDiffEqCore.AbstractNLSolverCache OrdinaryDiffEqCore.nlsolve_f -OrdinaryDiffEqCore.MethodType -OrdinaryDiffEqCore.NLStatus -OrdinaryDiffEqNonlinearSolve.NLNewton -OrdinaryDiffEqNonlinearSolve.NLFunctional -OrdinaryDiffEqNonlinearSolve.NLAnderson -OrdinaryDiffEqNonlinearSolve.build_nlsolver -OrdinaryDiffEqNonlinearSolve.nlsolve! -OrdinaryDiffEqNonlinearSolve.compute_step! -OrdinaryDiffEqNonlinearSolve.nlsolvefail -OrdinaryDiffEqNonlinearSolve.initial_η -OrdinaryDiffEqNonlinearSolve.markfirststage! -OrdinaryDiffEqNonlinearSolve.du_alias_or_new -OrdinaryDiffEqNonlinearSolve.anderson -OrdinaryDiffEqNonlinearSolve.anderson! OrdinaryDiffEqCore.get_W OrdinaryDiffEqCore.set_new_W! OrdinaryDiffEqCore.set_W_γdt! @@ -241,43 +204,13 @@ OrdinaryDiffEqCore.resize_nlsolver! OrdinaryDiffEqCore.default_nlsolve ``` -## Jacobian / W-matrix / differentiation configuration - -Provided by `OrdinaryDiffEqDifferentiation`. - -```@docs -OrdinaryDiffEqDifferentiation.build_J_W -OrdinaryDiffEqDifferentiation.build_uf -OrdinaryDiffEqDifferentiation.build_jac_config -OrdinaryDiffEqDifferentiation.build_grad_config -OrdinaryDiffEqDifferentiation.calc_J -OrdinaryDiffEqDifferentiation.calc_J! -OrdinaryDiffEqDifferentiation.calc_tderivative -OrdinaryDiffEqDifferentiation.calc_tderivative! -OrdinaryDiffEqDifferentiation.calc_rosenbrock_differentiation -OrdinaryDiffEqDifferentiation.calc_rosenbrock_differentiation! -OrdinaryDiffEqDifferentiation.jacobian! -OrdinaryDiffEqDifferentiation.jacobian2W! -OrdinaryDiffEqDifferentiation.update_W! -OrdinaryDiffEqDifferentiation.resize_jac_config! -OrdinaryDiffEqDifferentiation.resize_grad_config! -OrdinaryDiffEqDifferentiation.dolinsolve -OrdinaryDiffEqDifferentiation.wrapprecs -OrdinaryDiffEqDifferentiation.is_always_new -OrdinaryDiffEqDifferentiation.islinearfunction -OrdinaryDiffEqDifferentiation.issuccess_W -``` - ## Integrator step and initialization hooks ```@docs -OrdinaryDiffEqCore.ODEIntegrator -OrdinaryDiffEqCore.DEOptions OrdinaryDiffEqCore.perform_step! OrdinaryDiffEqCore.apply_step! OrdinaryDiffEqCore.postamble! OrdinaryDiffEqCore.last_step_failed -OrdinaryDiffEqCore.handle_callback_modifiers! OrdinaryDiffEqCore.set_discontinuity OrdinaryDiffEqCore.increment_accept! OrdinaryDiffEqCore.increment_reject! @@ -286,6 +219,7 @@ OrdinaryDiffEqCore.ode_determine_initdt OrdinaryDiffEqCore._determine_initdt OrdinaryDiffEqCore._ode_init OrdinaryDiffEqCore._initialize_dae! +OrdinaryDiffEqCore.find_algebraic_vars_eqs OrdinaryDiffEqCore.get_differential_vars ``` @@ -294,6 +228,7 @@ OrdinaryDiffEqCore.get_differential_vars ```@docs OrdinaryDiffEqCore.OrdinaryDiffEqInterpolation OrdinaryDiffEqCore.InterpolationData +OrdinaryDiffEqCore.DerivativeOrderNotPossibleError OrdinaryDiffEqCore.ode_interpolant OrdinaryDiffEqCore.ode_interpolant! OrdinaryDiffEqCore.hermite_interpolant @@ -308,24 +243,9 @@ OrdinaryDiffEqCore._ode_interpolant! OrdinaryDiffEqCore._ode_addsteps! ``` -## Controller caches - -Per-solve caches for the built-in step-size controllers (see the -[Controller API](@ref) for the controllers themselves). - -```@docs -OrdinaryDiffEqCore.IControllerCache -OrdinaryDiffEqCore.PIControllerCache -OrdinaryDiffEqCore.PIDControllerCache -OrdinaryDiffEqCore.PredictiveControllerCache -OrdinaryDiffEqCore.CompositeControllerCache -OrdinaryDiffEqCore.DummyController -OrdinaryDiffEqCore.DummyControllerCache -``` - ## Noise-process hooks -Used by the SDE/RODE solver sublibraries; no-ops for pure ODEs. +Used by SDE/RODE solver sublibraries; no-ops for pure ODEs. ```@docs OrdinaryDiffEqCore.accept_noise! diff --git a/docs/src/misc.md b/docs/src/misc.md index 5c5fa9a232f..aa481bae80d 100644 --- a/docs/src/misc.md +++ b/docs/src/misc.md @@ -16,9 +16,3 @@ IDSolve OrdinaryDiffEqExplicitRK.generic_rk_interpolant OrdinaryDiffEqExplicitRK.generic_rk_interpolant! ``` - -## Mass Matrix Utilities - -```@docs -OrdinaryDiffEqCore.find_algebraic_vars_eqs -``` diff --git a/lib/DiffEqBase/src/DiffEqBase.jl b/lib/DiffEqBase/src/DiffEqBase.jl index cfe597da37c..d469454ceb3 100644 --- a/lib/DiffEqBase/src/DiffEqBase.jl +++ b/lib/DiffEqBase/src/DiffEqBase.jl @@ -154,6 +154,14 @@ include("integrator_accessors.jl") include("verbosity.jl") # This is only used for oop stiff solvers +""" + default_factorize(A) + +Factorize matrix `A` for out-of-place stiff solver paths. + +The default implementation uses unchecked LU factorization and is intended as a +solver-author extension hook. +""" default_factorize(A) = lu(A; check = false) if isdefined(SciMLBase, :AbstractParameterizedFunction) diff --git a/lib/DiffEqBase/src/callbacks.jl b/lib/DiffEqBase/src/callbacks.jl index eb24aca8172..1fe00d0144b 100644 --- a/lib/DiffEqBase/src/callbacks.jl +++ b/lib/DiffEqBase/src/callbacks.jl @@ -136,6 +136,7 @@ function get_condition(integrator::DEIntegrator, callback, abst) end end +# Use a generated function for type stability even when many callbacks are given """ find_first_continuous_callback(integrator, callbacks...) @@ -144,7 +145,6 @@ fires earliest in the current step: the event time, crossing sign, whether an ev the (vector-callback) event index, the identified callback index, and the number of callbacks. A generated method keeps the result type-stable for an arbitrary number of callbacks. """ -# Use a generated function for type stability even when many callbacks are given @inline function find_first_continuous_callback( integrator, callbacks::Vararg{ @@ -633,6 +633,7 @@ function apply_callback!( return false, saved_in_cb end +#Base Case: Just one """ apply_discrete_callback!(integrator, callback...) @@ -641,7 +642,6 @@ true at the current `(u, t)`, run its `affect!` and handle any `saveat`/save boo Returns whether the discrete-callback set modified the integrator and whether a save was performed inside a callback, recursing over multiple callbacks while staying type-stable. """ -#Base Case: Just one @inline function apply_discrete_callback!(integrator, callback::DiscreteCallback) saved_in_cb = false did_modify = false @@ -714,6 +714,14 @@ end return discrete_modified || bool, saved_in_cb || saved_in_cb2 end +""" + max_vector_callback_length_int(cs::CallbackSet) + max_vector_callback_length_int(callbacks...) + +Return the largest `len` among vector continuous callbacks. + +Returns `nothing` when no vector continuous callback is present. +""" function max_vector_callback_length_int(cs::CallbackSet) return max_vector_callback_length_int(cs.continuous_callbacks...) end diff --git a/lib/DiffEqBase/src/common_defaults.jl b/lib/DiffEqBase/src/common_defaults.jl index 078b565bfa5..297285d0465 100644 --- a/lib/DiffEqBase/src/common_defaults.jl +++ b/lib/DiffEqBase/src/common_defaults.jl @@ -179,6 +179,27 @@ function INFINITE_OR_GIANT( ) end INFINITE_OR_GIANT(x::RecursiveArrayTools.ArrayPartition) = any(INFINITE_OR_GIANT, x.x) + +""" + ODE_DEFAULT_UNSTABLE_CHECK(dt, u, p, t) -> Bool + +Return whether the default ODE instability check considers the current state +unstable. + +The generic fallback returns `false`. Numeric scalars, arrays, and +`ArrayPartition`s return `true` when any state entry is infinite or non-finite. +This is the default used by OrdinaryDiffEq solvers when no `unstable_check` +callback is supplied. + +# Arguments +- `dt`: Current step size. +- `u`: Current state. +- `p`: Problem parameters. +- `t`: Current time. + +# Returns +- `Bool`: `true` when the state should be treated as unstable. +""" ODE_DEFAULT_UNSTABLE_CHECK(dt, u, p, t) = false function ODE_DEFAULT_UNSTABLE_CHECK(dt, u::Union{Number, AbstractArray{<:Number}}, p, t) return INFINITE_OR_GIANT(u) diff --git a/lib/DiffEqBase/src/integrator_accessors.jl b/lib/DiffEqBase/src/integrator_accessors.jl index b89dd3d1b04..dc9f884f599 100644 --- a/lib/DiffEqBase/src/integrator_accessors.jl +++ b/lib/DiffEqBase/src/integrator_accessors.jl @@ -1,12 +1,32 @@ # the following are setup per how integrators are implemented in OrdinaryDiffEq and # StochasticDiffEq and provide dispatch points that JumpProcesses and others can use. +""" + get_tstops(integrator) -> Any + +Return the timestep-stop data structure owned by `integrator`. + +Integrator implementations specialize this accessor so callback and jump-process +machinery can inspect pending `tstops` without depending on integrator fields. +""" function get_tstops(integ::DEIntegrator) error("get_tstops not implemented for integrators of type $(nameof(typeof(integ)))") end + +""" + get_tstops_array(integrator) -> AbstractVector + +Return the array-like storage containing pending timestep stops for `integrator`. +""" function get_tstops_array(integ::DEIntegrator) error("get_tstops_array not implemented for integrators of type $(nameof(typeof(integ)))") end + +""" + get_tstops_max(integrator) + +Return the largest pending timestep stop for `integrator`. +""" function get_tstops_max(integ::DEIntegrator) error("get_tstops_max not implemented for integrators of type $(nameof(typeof(integ)))") end diff --git a/lib/DiffEqBase/src/norecompile.jl b/lib/DiffEqBase/src/norecompile.jl index ccfc86f35a1..e9058620fc3 100644 --- a/lib/DiffEqBase/src/norecompile.jl +++ b/lib/DiffEqBase/src/norecompile.jl @@ -1,3 +1,9 @@ +""" + OrdinaryDiffEqTag + +Tag type used by DiffEqBase's no-recompile wrappers for OrdinaryDiffEq-family +solver dispatch. +""" struct OrdinaryDiffEqTag end const NORECOMPILE_ARGUMENT_MESSAGE = """ diff --git a/lib/DiffEqBase/src/solve.jl b/lib/DiffEqBase/src/solve.jl index 380fbfe6975..ecb1ebbf91e 100644 --- a/lib/DiffEqBase/src/solve.jl +++ b/lib/DiffEqBase/src/solve.jl @@ -1,3 +1,12 @@ +""" + EvalFunc(f) + +Callable wrapper used by DiffEqBase solve dispatch to pass an already-prepared +function object through interfaces that expect a function-like value. + +# Fields +- `f`: Wrapped callable object. +""" struct EvalFunc{F} <: Function f::F end @@ -932,6 +941,15 @@ function promote_f( remake(f, _func_cache = copy(f._func_cache)) end end +""" + prepare_alg(alg, u0, p, prob) -> alg + +Return the algorithm object used for a solve after problem-dependent preparation. + +This fallback returns `alg` unchanged. Solver packages specialize it when an +algorithm needs to inspect the initial condition, parameters, or problem before +dispatch reaches `solve`. +""" prepare_alg(alg, u0, p, f) = alg function get_concrete_tspan(prob, isadapt, kwargs, p) @@ -984,6 +1002,21 @@ function __init( end end +""" + check_prob_alg_pairing(prob, alg) -> nothing + +Validate that `alg` is compatible with the problem type `prob`. + +The check catches common dispatch mistakes before solver construction, including +ODE algorithms passed to non-ODE problems, direct AD with algorithms that are not +AD-compatible, and SDE noise-size mismatches. + +# Throws +- `ProblemSolverPairingError`: If the problem and algorithm families do not match. +- `DirectAutodiffError`: If the initial condition uses dual numbers but `alg` is + not autodifferentiable. +- `NoiseSizeIncompatibilityError`: If SDE noise dimensions are inconsistent. +""" function check_prob_alg_pairing(prob, alg) if prob isa ODEProblem && !(alg isa AbstractODEAlgorithm) || prob isa SDEProblem && !(alg isa AbstractSDEAlgorithm) || diff --git a/lib/DiffEqBase/src/utils.jl b/lib/DiffEqBase/src/utils.jl index 7d024005dd9..98d270716ab 100644 --- a/lib/DiffEqBase/src/utils.jl +++ b/lib/DiffEqBase/src/utils.jl @@ -3,6 +3,22 @@ macro tight_loop_macros(ex) end # TODO: would be good to have dtmin a function of dt +""" + prob2dtmin(prob; use_end_time = true) + prob2dtmin(tspan, onet, use_end_time) + +Compute the default minimum timestep implied by a problem or time span. + +# Arguments +- `prob`: Differential-equation problem with a `tspan` field. +- `tspan`: Tuple-like time span. +- `onet`: Unit step value used to preserve units for non-floating time types. +- `use_end_time`: Whether the end of the time span contributes to the floating + point spacing calculation. + +# Returns +- A nonnegative minimum timestep with units compatible with the time span. +""" function prob2dtmin(prob; use_end_time = true) return prob2dtmin(prob.tspan, oneunit(eltype(prob.tspan)), use_end_time) end @@ -22,6 +38,15 @@ prob2dtmin(tspan, ::Integer, ::Any) = 0 # Multiplication is for putting the right units on the constant! prob2dtmin(tspan, onet, ::Any) = onet * 1 // Int64(2)^33 # roughly 10^10 but more likely to turn into a multiplication. +""" + timedepentdtmin(integrator) + timedepentdtmin(t, dtmin) + +Return the time-dependent minimum timestep at the current time. + +Floating-point times are bounded below by machine spacing at `t`; other time +types use `abs(dtmin)`. +""" function timedepentdtmin(integrator::DEIntegrator) return timedepentdtmin(integrator.t, integrator.opts.dtmin) end @@ -56,6 +81,14 @@ _rate_prototype(u, t::T, onet::T) where {T} = u # Tracker, etc.) intact. Extensions for Unitful, DynamicQuantities, and FlexUnits # override this to return the underlying numeric value. # Complementary to `value` (strips everything) and `unitfulvalue` (strips AD, keeps units). +""" + stripunits(x) + +Return `x` with only its unit wrapper removed. + +The default method returns `x` unchanged. Unitful extension packages specialize +this function while preserving AD and uncertainty wrappers. +""" stripunits(x) = x # Nonlinear Solve functionality diff --git a/lib/OrdinaryDiffEqCore/src/OrdinaryDiffEqCore.jl b/lib/OrdinaryDiffEqCore/src/OrdinaryDiffEqCore.jl index b04174b5c0e..5b8c479cdac 100644 --- a/lib/OrdinaryDiffEqCore/src/OrdinaryDiffEqCore.jl +++ b/lib/OrdinaryDiffEqCore/src/OrdinaryDiffEqCore.jl @@ -111,7 +111,25 @@ using EnumX: @enumx import EnzymeCore -# Per-stage Newton initial-guess ("predictor") strategies for implicit RK methods. +""" + Predictor + +Enumeration of per-stage initial-guess strategies for implicit Runge-Kutta +methods. + +# Values +- `Predictor.Trivial`: Use a zero increment. +- `Predictor.Linear`: Use a linear extrapolation from the first-same-as-last + derivative. +- `Predictor.MaxOrder`: Use the full previous-step interpolation order. +- `Predictor.VariableOrder`: Reduce interpolation order as the stage extrapolates + farther from the previous step. +- `Predictor.CutoffOrder`: Use full interpolation order below a cutoff and order + one above it. +- `Predictor.CopyPrev`: Reuse the previous stage derivative. +- `Predictor.StageExtrap`: Extrapolate recent stage derivatives. +- `Predictor.Tableau`: Use the tableau-derived stage guess. +""" @enumx Predictor begin Trivial # zero increment (z = 0) Linear # linear extrapolation (z = dt * fsalfirst) @@ -145,7 +163,7 @@ abstract type AbstractNLSolverCache end Abstract supertype of the algorithm objects that configure a nonlinear solver (e.g. `NLNewton`, `NLFunctional`, `NLAnderson`). Passed as the `nlsolve` keyword -of an implicit algorithm and consumed by [`OrdinaryDiffEqNonlinearSolve.build_nlsolver`](@ref). +of an implicit algorithm and consumed internally by `OrdinaryDiffEqNonlinearSolve.build_nlsolver`. """ abstract type AbstractNLSolverAlgorithm end """ @@ -153,9 +171,9 @@ abstract type AbstractNLSolverAlgorithm end Abstract supertype of the nonlinear solver object that implicit algorithms use to solve their implicit stage equations. Concrete subtypes (e.g. `NLSolver` in -OrdinaryDiffEqNonlinearSolve) are built with [`OrdinaryDiffEqNonlinearSolve.build_nlsolver`](@ref) and driven -with [`OrdinaryDiffEqNonlinearSolve.nlsolve!`](@ref). The type parameters are the nonlinear-solver algorithm -type and the in-place flag `iip`. +OrdinaryDiffEqNonlinearSolve) are built with `OrdinaryDiffEqNonlinearSolve.build_nlsolver` +and driven with `OrdinaryDiffEqNonlinearSolve.nlsolve!`. The type parameters are +the nonlinear-solver algorithm type and the in-place flag `iip`. """ abstract type AbstractNLSolver{algType, iip} end @@ -230,7 +248,7 @@ resize_nlsolver!(args...) = nothing `@enum` classifying how an implicit algorithm forms its `W = M/(γΔt) - J` matrix and stage system. One of [`DIRK`](@ref), [`COEFFICIENT_MULTISTEP`](@ref), [`NORDSIECK_MULTISTEP`](@ref), or [`GLM`](@ref). The nonlinear solver uses it to -scale `γW` appropriately in [`OrdinaryDiffEqNonlinearSolve.nlsolve!`](@ref). +scale `γW` appropriately in `OrdinaryDiffEqNonlinearSolve.nlsolve!`. """ @enum MethodType begin DIRK @@ -274,7 +292,7 @@ GLM from best to worst: [`FastConvergence`](@ref) (`2`), [`Convergence`](@ref) (`1`), [`SlowConvergence`](@ref) (`0`), [`VerySlowConvergence`](@ref) (`-1`), [`Divergence`](@ref) (`-2`). A non-positive value means the solve failed -([`OrdinaryDiffEqNonlinearSolve.nlsolvefail`](@ref)). +(`OrdinaryDiffEqNonlinearSolve.nlsolvefail`). """ @enum NLStatus::Int8 begin FastConvergence = 2 @@ -402,33 +420,33 @@ include("precompilation_setup.jl") eval( Expr( :public, - :AbstractController, :AbstractControllerCache, :AbstractNLSolver, :AbstractNLSolverAlgorithm, :AbstractNLSolverCache, :AbstractThreadingOption, - :accept_step_controller, :alg_adaptive_order, :alg_autodiff, :alg_cache, :alg_difftype, :alg_extrapolates, - :alg_maximum_order, :alg_stability_size, :AutoAlgSwitch, :AutoSwitch, :AutoSwitchCache, :BaseThreads, - :beta1_default, :beta2_default, Symbol("@cache"), :COEFFICIENT_MULTISTEP, :CommonControllerOptions, :CompositeAlgorithm, - :CompositeCache, :CompositeController, :CompositeControllerCache, :constvalue, :Convergence, :current_extrapolant, - :current_interpolant, :DAEAlgorithm, :default_autoswitch, :DefaultCache, :default_controller, :default_linear_interpolation, + :AbstractController, :AbstractControllerCache, :AbstractNLSolver, :AbstractNLSolverAlgorithm, :AbstractThreadingOption, + :accept_step_controller, :alg_adaptive_order, :alg_autodiff, :alg_difftype, :alg_extrapolates, + :alg_maximum_order, :alg_stability_size, :AutoAlgSwitch, :AutoSwitch, :BaseThreads, + :beta1_default, :beta2_default, :COEFFICIENT_MULTISTEP, :CommonControllerOptions, :CompositeAlgorithm, + :CompositeController, :constvalue, :Convergence, :current_extrapolant, + :current_interpolant, :DAEAlgorithm, :default_autoswitch, :default_controller, :default_linear_interpolation, :default_nlsolve, :DEOptions, :DIRK, :Divergence, :dt_required, :DummyController, - :DummyControllerCache, :explicit_rk_docstring, :ExponentialAlgorithm, :FastConvergence, :gamma_default, :generic_solver_docstring, - :get_current_adaptive_order, :get_current_alg_autodiff, :get_differential_vars, :get_EEst, :get_failfactor, :get_fsalfirstlast, + :explicit_rk_docstring, :ExponentialAlgorithm, :FastConvergence, :gamma_default, :generic_solver_docstring, + :get_current_adaptive_order, :get_current_alg_autodiff, :get_differential_vars, :get_EEst, :get_failfactor, :get_gamma, :get_new_W_γdt_cutoff, :get_qmax, :get_qmax_first_step, :get_qmin, :get_qsteady_max, - :get_qsteady_min, :get_W, :GLM, :hermite_interpolant, :IController, :IControllerCache, + :get_qsteady_min, :get_W, :GLM, :hermite_interpolant, :IController, :ImplicitSecondOrderAlgorithm, :increment_accept!, :increment_nf!, :increment_reject!, :InterpolationData, :isautoswitch, - :is_composite_algorithm, :is_composite_cache, :is_constant_cache, :isdefaultalg, :isdtchangeable, :isfirstcall, + :is_composite_algorithm, :isdefaultalg, :isdtchangeable, :isfirstcall, :isfirststage, :isfsal, :isimplicit, :isJcurrent, :is_mass_matrix_alg, :ismultistep, :issplit, :isthreaded, :isWmethod, :MethodType, :NewtonAlgorithm, :nlsolve_f, :NLStatus, :NORDSIECK_MULTISTEP, :_ode_addsteps!, :ode_addsteps!, :ODEIntegrator, :_ode_interpolant, :OrdinaryDiffEqAdamsVarOrderVarStepAlgorithm, :OrdinaryDiffEqAdaptiveAlgorithm, :OrdinaryDiffEqAdaptiveExponentialAlgorithm, :OrdinaryDiffEqAdaptiveImplicitAlgorithm, :OrdinaryDiffEqAdaptiveImplicitSecondOrderAlgorithm, :OrdinaryDiffEqAdaptivePartitionedAlgorithm, - :OrdinaryDiffEqAlgorithm, :OrdinaryDiffEqCache, :OrdinaryDiffEqCompositeAlgorithm, :OrdinaryDiffEqConstantCache, :OrdinaryDiffEqExponentialAlgorithm, :OrdinaryDiffEqImplicitAlgorithm, - :OrdinaryDiffEqImplicitSecondOrderAlgorithm, :OrdinaryDiffEqInterpolation, :OrdinaryDiffEqLinearExponentialAlgorithm, :OrdinaryDiffEqMutableCache, :OrdinaryDiffEqNewtonAdaptiveAlgorithm, :OrdinaryDiffEqNewtonAlgorithm, + :OrdinaryDiffEqAlgorithm, :OrdinaryDiffEqCompositeAlgorithm, :OrdinaryDiffEqExponentialAlgorithm, :OrdinaryDiffEqImplicitAlgorithm, + :OrdinaryDiffEqImplicitSecondOrderAlgorithm, :OrdinaryDiffEqInterpolation, :OrdinaryDiffEqLinearExponentialAlgorithm, :OrdinaryDiffEqNewtonAdaptiveAlgorithm, :OrdinaryDiffEqNewtonAlgorithm, :OrdinaryDiffEqPartitionedAlgorithm, :OrdinaryDiffEqRosenbrockAdaptiveAlgorithm, :OrdinaryDiffEqRosenbrockAlgorithm, :PartitionedAlgorithm, :perform_step!, :PIController, - :PIControllerCache, :PIDController, :PIDControllerCache, :PolyesterThreads, :post_newton_controller!, :PredictiveController, - :PredictiveControllerCache, :qmax_default, :qmin_default, :reinit_controller!, :resize_J_W!, :resize_nlsolver!, + :PIDController, :PolyesterThreads, :post_newton_controller!, :PredictiveController, + :qmax_default, :qmin_default, :reinit_controller!, :resize_J_W!, :resize_nlsolver!, :RosenbrockAlgorithm, :Sequential, :set_EEst!, :set_new_W!, :setup_controller_cache, :set_W_γdt!, :SlowConvergence, :step_accept_controller!, :step_reject_controller!, :stepsize_controller!, :StochasticDiffEqAdaptiveAlgorithm, :StochasticDiffEqAlgorithm, - :StochasticDiffEqCache, :StochasticDiffEqCompositeAlgorithm, :StochasticDiffEqConstantCache, :StochasticDiffEqJumpAdaptiveAlgorithm, :StochasticDiffEqJumpAlgorithm, :StochasticDiffEqJumpDiffusionAdaptiveAlgorithm, - :StochasticDiffEqJumpDiffusionAlgorithm, :StochasticDiffEqJumpNewtonAdaptiveAlgorithm, :StochasticDiffEqJumpNewtonDiffusionAdaptiveAlgorithm, :StochasticDiffEqMutableCache, :StochasticDiffEqNewtonAdaptiveAlgorithm, :StochasticDiffEqNewtonAlgorithm, - :StochasticDiffEqRODEAdaptiveAlgorithm, :StochasticDiffEqRODEAlgorithm, :StochasticDiffEqRODECompositeAlgorithm, :strip_cache, :sync_controllers!, :TryAgain, + :StochasticDiffEqCompositeAlgorithm, :StochasticDiffEqJumpAdaptiveAlgorithm, :StochasticDiffEqJumpAlgorithm, :StochasticDiffEqJumpDiffusionAdaptiveAlgorithm, + :StochasticDiffEqJumpDiffusionAlgorithm, :StochasticDiffEqJumpNewtonAdaptiveAlgorithm, :StochasticDiffEqJumpNewtonDiffusionAdaptiveAlgorithm, :StochasticDiffEqNewtonAdaptiveAlgorithm, :StochasticDiffEqNewtonAlgorithm, + :StochasticDiffEqRODEAdaptiveAlgorithm, :StochasticDiffEqRODEAlgorithm, :StochasticDiffEqRODECompositeAlgorithm, :sync_controllers!, :TryAgain, :unwrap_alg, :uses_uprev, :VerySlowConvergence, # Round 2: remaining cross-sublib / extension surface owned by OrdinaryDiffEqCore. # Error / sentinel / dispatch-helper types shared across solver sublibs. @@ -439,7 +457,7 @@ include("precompilation_setup.jl") # Algorithm-trait predicates extended/queried by solver sublibs. :standardtag, :concrete_jac, :has_autodiff, :has_dtnew_modification, :has_special_newton_error, :has_stiff_interpolation, :alg_can_repeat_jac, - :allows_null_u0, :isaposteriori, :isdiscretealg, :isdiscretecache, :isdp8, + :allows_null_u0, :isaposteriori, :isdiscretealg, :isdp8, :isesdirk, :isfirk, :isnewton, :only_diagonal_mass_matrix, :fsal_typeof, :ssp_coefficient, :fac_default_gamma, :qsteady_max_default, :qsteady_min_default, # Order / stepsize / autodiff-config accessors used across sublibs. @@ -449,7 +467,7 @@ include("precompilation_setup.jl") # Integrator step / cache / initialization hooks. :_ode_init, :_determine_initdt, :ode_determine_initdt, :_initialize_dae!, :find_algebraic_vars_eqs, :postamble!, :apply_step!, :last_step_failed, :reset_alg_dependent_opts!, - :handle_callback_modifiers!, :set_discontinuity, :resolve_basic, + :set_discontinuity, :resolve_basic, # Noise hooks used by the SDE/RODE solver sublibs. :accept_noise!, :reinit_noise!, :reject_noise!, :save_noise!, :noise_curt, :is_noise_saveable, diff --git a/lib/OrdinaryDiffEqDifferentiation/src/OrdinaryDiffEqDifferentiation.jl b/lib/OrdinaryDiffEqDifferentiation/src/OrdinaryDiffEqDifferentiation.jl index 7a508c153de..61fcd696ca7 100644 --- a/lib/OrdinaryDiffEqDifferentiation/src/OrdinaryDiffEqDifferentiation.jl +++ b/lib/OrdinaryDiffEqDifferentiation/src/OrdinaryDiffEqDifferentiation.jl @@ -76,21 +76,4 @@ include("derivative_utils.jl") include("derivative_wrappers.jl") include("operators.jl") -# Documented solver-author extension API: the Jacobian/W-matrix and -# differentiation-config hooks that downstream OrdinaryDiffEq solver sublibraries -# build on. Codegen/perf internals are intentionally left non-public. -@static if VERSION >= v"1.11.0-DEV.469" - eval( - Expr( - :public, - :build_J_W, :build_grad_config, :build_jac_config, :build_uf, - :calc_J, :calc_J!, :calc_tderivative, :calc_tderivative!, - :calc_rosenbrock_differentiation, :calc_rosenbrock_differentiation!, - :jacobian!, :jacobian2W!, :update_W!, - :resize_grad_config!, :resize_jac_config!, - :dolinsolve, :wrapprecs, :is_always_new, :islinearfunction, :issuccess_W - ) - ) -end - end diff --git a/lib/OrdinaryDiffEqNonlinearSolve/src/OrdinaryDiffEqNonlinearSolve.jl b/lib/OrdinaryDiffEqNonlinearSolve/src/OrdinaryDiffEqNonlinearSolve.jl index 8b2a4663410..90760287079 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/src/OrdinaryDiffEqNonlinearSolve.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/src/OrdinaryDiffEqNonlinearSolve.jl @@ -68,26 +68,15 @@ include("initialize_dae.jl") export BrownFullBasicInit, ShampineCollocationInit -# Declare the documented solver-author extension API `public` so downstream solver -# packages (the OrdinaryDiffEq solver sublibs, DelayDiffEq's fixed-point solver, etc.) -# can drop their `OrdinaryDiffEqNonlinearSolve.X` non-public ExplicitImports ignores. -# These are the nonlinear-solver algorithm types and the stepping/build hooks that -# downstream packages legitimately construct and extend. The `public` keyword is only -# parseable on Julia >= 1.11.0-DEV.469, so it is gated to keep the 1.10 floor parsing. -# Pure internal codegen/perf helpers are intentionally left non-public. +# Nonlinear-solver algorithms accepted by OrdinaryDiffEq implicit methods. The +# lower-level build/step/Anderson helpers are implementation details, not public API. +# The `public` keyword is only parseable on Julia >= 1.11.0-DEV.469, so it is +# gated to keep the 1.10 floor parsing. @static if VERSION >= v"1.11.0-DEV.469" eval( Expr( :public, - # Nonlinear-solver algorithm types - :NLNewton, :NLFunctional, :NLAnderson, - # Solver construction - :build_nlsolver, - # Stepping / status hooks extended and called by downstream solvers - :nlsolve!, :nlsolvefail, :compute_step!, :initial_η, - :markfirststage!, :du_alias_or_new, - # Anderson-acceleration kernels (DelayDiffEq fixed-point solver reuses these) - :anderson, :anderson! + :NLNewton, :NLFunctional, :NLAnderson ) ) end diff --git a/lib/OrdinaryDiffEqNonlinearSolve/src/type.jl b/lib/OrdinaryDiffEqNonlinearSolve/src/type.jl index a98eecbecd6..f9397b4362a 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/src/type.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/src/type.jl @@ -28,8 +28,7 @@ end Anderson-accelerated fixed-point iteration for the implicit stage equations. Like [`NLFunctional`](@ref) but mixes in `max_history` previous residuals via a -least-squares update to accelerate convergence (see [`anderson`](@ref) / -[`anderson!`](@ref)). +least-squares update to accelerate convergence. # Keyword arguments