Skip to content

Commit b5f2053

Browse files
Document BoundaryValueDiffEqCore developer contracts
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
1 parent 219b502 commit b5f2053

4 files changed

Lines changed: 115 additions & 17 deletions

File tree

lib/BoundaryValueDiffEqCore/src/abstract_types.jl

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@
44
Developer-facing abstract type for BoundaryValueDiffEq solver caches.
55
66
A solver package's `SciMLBase.__init` implementation returns a concrete subtype of this type.
7-
The cache must expose a `prob` field so the default `SciMLBase.isinplace(cache)` method can
8-
delegate to the boundary value problem, and the solver package must implement
9-
`SciMLBase.solve!(cache)`. This is a versioned interface for solver implementations, not an
10-
end-user extension point.
7+
This is a versioned developer interface for solver implementations, not an end-user extension
8+
point.
119
1210
# Interface
1311
14-
- `SciMLBase.isinplace(cache)`: determines whether the cache's problem is in-place.
15-
- `Base.eltype(cache)`: returns the cache element type when the solver needs one.
12+
- Every cache must store the exact problem supplied to `SciMLBase.__init` in a field named
13+
`prob`. The default `SciMLBase.isinplace(cache)` delegates to that field.
14+
- Every cache must implement `SciMLBase.solve!(cache)` and return the solver result expected by
15+
its algorithm.
16+
- Define `Base.eltype(cache)` when the solver's implementation requires an element type.
17+
18+
The cache and its `solve!` method must be owned by the package that owns the corresponding
19+
algorithm subtype. Do not extend another solver package's cache type.
1620
1721
# Examples
1822
@@ -23,7 +27,7 @@ struct MyBVPCache{P} <: AbstractBoundaryValueDiffEqCache
2327
prob::P
2428
end
2529
26-
SciMLBase.solve!(cache::MyBVPCache) = nothing
30+
SciMLBase.solve!(cache::MyBVPCache) = cache.prob
2731
```
2832
"""
2933
abstract type AbstractBoundaryValueDiffEqCache end

lib/BoundaryValueDiffEqCore/src/algorithms.jl

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,39 @@
55
Developer-facing abstract type for boundary value problem algorithms.
66
77
Packages that implement a BoundaryValueDiffEq solver subtype this type and implement the
8-
SciML solve interface for that algorithm. In particular, provide an
9-
`SciMLBase.__init(prob, alg; kwargs...)` method that constructs a solver cache and a
10-
corresponding `SciMLBase.solve!` method for that cache. Solver users should select a concrete
11-
algorithm such as `MIRK4()` or `Shooting()` rather than subtype this interface.
8+
SciML solve interface for that algorithm. This is a versioned developer interface for solver
9+
packages, not an end-user extension point. Solver users should select a concrete algorithm such
10+
as `MIRK4()` or `Shooting()` rather than subtype this interface.
11+
12+
# Interface
13+
14+
For every concrete subtype `Alg`, define:
15+
16+
```julia
17+
SciMLBase.__init(prob::SciMLBase.AbstractBVProblem, alg::Alg, args...; kwargs...)
18+
```
19+
20+
The method must return a concrete [`AbstractBoundaryValueDiffEqCache`](@ref) whose `prob` field
21+
is the supplied problem. It must accept and interpret the positional and keyword arguments that
22+
the solver package supports. The matching cache type must implement `SciMLBase.solve!(cache)`.
23+
`SciMLBase.solve(prob, alg, args...; kwargs...)` dispatches through these two methods in order;
24+
`solve!` returns the solver result. Do not add methods for algorithms owned by another package.
1225
1326
# Examples
1427
1528
```julia
1629
using BoundaryValueDiffEqCore, SciMLBase
1730
1831
struct MyBVPAlgorithm <: AbstractBoundaryValueDiffEqAlgorithm end
19-
20-
function SciMLBase.__init(prob, ::MyBVPAlgorithm; kwargs...)
21-
# Construct and return the cache consumed by SciMLBase.solve!.
32+
struct MyBVPCache{P} <: AbstractBoundaryValueDiffEqCache
33+
prob::P
2234
end
35+
36+
SciMLBase.__init(prob::SciMLBase.AbstractBVProblem, ::MyBVPAlgorithm; kwargs...) =
37+
MyBVPCache(prob)
38+
SciMLBase.solve!(cache::MyBVPCache) = cache.prob
39+
40+
SciMLBase.solve(prob, MyBVPAlgorithm()) # calls __init, then solve!
2341
```
2442
2543
See the concrete solver packages in this repository for complete implementations.

lib/BoundaryValueDiffEqCore/src/calc_errors.jl

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,32 @@
11
"""
22
AbstractErrorControl
33
4-
Abstract type for different error control methods.
4+
Developer-facing abstract type for error-controller tags used by BoundaryValueDiffEq solver
5+
implementations.
6+
7+
This is a narrow versioned interface for solver packages. Subtypes classify how a solver's own
8+
adaptivity implementation manages error estimates; subtyping this type alone does not make a
9+
controller usable by `MIRK`, `FIRK`, or another concrete solver.
10+
11+
# Extension Rules
12+
13+
A solver package that owns both an error controller and the corresponding adaptivity behavior may
14+
subtype `AbstractErrorControl`. It may extend [`__use_both_error_control`](@ref) for that subtype
15+
to declare whether its cache requires separate defect and global-error storage. The method must
16+
return a `Bool`, be side-effect free, and be defined only for the extending package's controller
17+
type. The default is `false`.
18+
19+
The concrete solver package remains responsible for implementing all controller-specific error
20+
estimation and mesh-selection behavior. Applications should use the documented concrete
21+
controllers rather than subtype this type.
22+
23+
# Examples
24+
25+
```julia
26+
struct MyCombinedControl <: AbstractErrorControl end
27+
28+
BoundaryValueDiffEqCore.__use_both_error_control(::MyCombinedControl) = true
29+
```
530
"""
631
abstract type AbstractErrorControl end
732

@@ -118,7 +143,21 @@ struct REErrorControl <: GlobalErrorControlMethod end
118143
"""
119144
__use_both_error_control(controller) -> Bool
120145
121-
Return whether an error controller combines defect and global error control.
146+
Return whether an error controller requires separate defect and global-error storage.
147+
148+
This developer hook is used while a solver cache is constructed. The default implementation
149+
returns `false`. Solver packages may extend it only for their own
150+
[`AbstractErrorControl`](@ref) subtype, return a concrete `Bool`, and perform no mutation. A
151+
`true` result reserves storage for both estimates; it does not by itself add support for a custom
152+
controller to a concrete solver.
153+
154+
# Examples
155+
156+
```julia
157+
struct MyCombinedControl <: AbstractErrorControl end
158+
159+
BoundaryValueDiffEqCore.__use_both_error_control(::MyCombinedControl) = true
160+
```
122161
"""
123162
@inline __use_both_error_control(::HybridErrorControl) = true
124163
@inline __use_both_error_control(_) = false

lib/BoundaryValueDiffEqCore/test/Core/util_tests.jl

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,57 @@
11
using BoundaryValueDiffEqCore
2+
using SciMLBase
23
using Test
34

45
module ExternalBVPAlgorithmExtension
5-
using BoundaryValueDiffEqCore
6+
using BoundaryValueDiffEqCore, SciMLBase
67

78
struct ExternalBVPAlgorithm <: BoundaryValueDiffEqCore.AbstractBoundaryValueDiffEqAlgorithm end
89
struct ExternalBVPCache{P} <: BoundaryValueDiffEqCore.AbstractBoundaryValueDiffEqCache
910
prob::P
11+
init_arg::Symbol
12+
adaptive::Bool
1013
end
14+
15+
SciMLBase.__init(
16+
prob::SciMLBase.AbstractBVProblem, ::ExternalBVPAlgorithm, init_arg::Symbol;
17+
adaptive = true, kwargs...
18+
) = ExternalBVPCache(prob, init_arg, adaptive)
19+
20+
SciMLBase.solve!(cache::ExternalBVPCache) =
21+
(; prob = cache.prob, init_arg = cache.init_arg, adaptive = cache.adaptive)
22+
23+
struct ExternalCombinedErrorControl <: BoundaryValueDiffEqCore.AbstractErrorControl end
24+
25+
BoundaryValueDiffEqCore.__use_both_error_control(::ExternalCombinedErrorControl) = true
1126
end
1227

1328
@testset "AbstractBoundaryValueDiffEqAlgorithm extension interface" begin
1429
@test ExternalBVPAlgorithmExtension.ExternalBVPAlgorithm <:
1530
BoundaryValueDiffEqCore.AbstractBoundaryValueDiffEqAlgorithm
1631
@test ExternalBVPAlgorithmExtension.ExternalBVPCache <:
1732
BoundaryValueDiffEqCore.AbstractBoundaryValueDiffEqCache
33+
34+
f(u, p, t) = u
35+
bc(u, p, t) = u
36+
prob = SciMLBase.BVProblem(f, bc, [1.0], (0.0, 1.0))
37+
sol = SciMLBase.solve(
38+
prob, ExternalBVPAlgorithmExtension.ExternalBVPAlgorithm(), :from_solve;
39+
adaptive = false
40+
)
41+
42+
@test sol.prob === prob
43+
@test sol.init_arg === :from_solve
44+
@test !sol.adaptive
45+
@test !SciMLBase.isinplace(
46+
ExternalBVPAlgorithmExtension.ExternalBVPCache(prob, :test, true)
47+
)
48+
end
49+
50+
@testset "AbstractErrorControl extension interface" begin
51+
@test !BoundaryValueDiffEqCore.__use_both_error_control(DefectControl())
52+
@test BoundaryValueDiffEqCore.__use_both_error_control(
53+
ExternalBVPAlgorithmExtension.ExternalCombinedErrorControl()
54+
)
1855
end
1956

2057
@testset "__extract_lcons_ucons length" begin

0 commit comments

Comments
 (0)