Skip to content

Commit feb19ce

Browse files
committed
Adaptive order version of ExplicitTaylor
1 parent 2239fc8 commit feb19ce

File tree

5 files changed

+136
-16
lines changed

5 files changed

+136
-16
lines changed

lib/OrdinaryDiffEqTaylorSeries/src/OrdinaryDiffEqTaylorSeries.jl

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
module OrdinaryDiffEqTaylorSeries
22

3-
import OrdinaryDiffEqCore: alg_order, alg_stability_size, explicit_rk_docstring,
3+
import OrdinaryDiffEqCore: alg_order, get_current_adaptive_order, get_current_alg_order,
4+
alg_stability_size, explicit_rk_docstring,
45
OrdinaryDiffEqAdaptiveAlgorithm, OrdinaryDiffEqMutableCache,
56
alg_cache,
67
OrdinaryDiffEqConstantCache, @fold, trivial_limiter!,
8+
step_accept_controller!,
9+
stepsize_controller!,
10+
unwrap_alg,
711
constvalue, @unpack, perform_step!, calculate_residuals, @cache,
812
calculate_residuals!, _ode_interpolant, _ode_interpolant!,
913
CompiledFloats, @OnDemandTableauExtract, initialize!,
@@ -55,6 +59,6 @@ PrecompileTools.@compile_workload begin
5559
solver_list = nothing
5660
end
5761

58-
export ExplicitTaylor2, ExplicitTaylor, DAETS
62+
export ExplicitTaylor2, ExplicitTaylor, ExplicitTaylorAdaptiveOrder
5963

6064
end

lib/OrdinaryDiffEqTaylorSeries/src/TaylorSeries_caches.jl

+46-7
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ end
3939
get_fsalfirstlast(cache::ExplicitTaylor2Cache, u) = (cache.k1, cache.k1)
4040

4141
@cache struct ExplicitTaylorCache{
42-
P, jetType, uType, taylorType, uNoUnitsType, StageLimiter, StepLimiter,
42+
P, uType, taylorType, uNoUnitsType, StageLimiter, StepLimiter,
4343
Thread} <: OrdinaryDiffEqMutableCache
4444
order::Val{P}
45-
jet::jetType
45+
jet::Function
4646
u::uType
4747
uprev::uType
4848
utaylor::taylorType
@@ -54,17 +54,17 @@ get_fsalfirstlast(cache::ExplicitTaylor2Cache, u) = (cache.k1, cache.k1)
5454
thread::Thread
5555
end
5656

57-
function alg_cache(alg::ExplicitTaylor{P}, u, rate_prototype, ::Type{uEltypeNoUnits},
57+
function alg_cache(alg::ExplicitTaylor, u, rate_prototype, ::Type{uEltypeNoUnits},
5858
::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t,
5959
dt, reltol, p, calck,
60-
::Val{true}) where {P, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits}
61-
_, jet_iip = build_jet(f, p, Val(P), length(u))
62-
utaylor = TaylorDiff.make_seed(u, zero(u), Val(P))
60+
::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits}
61+
_, jet_iip = build_jet(f, p, alg.order, length(u))
62+
utaylor = TaylorDiff.make_seed(u, zero(u), alg.order)
6363
utilde = zero(u)
6464
atmp = similar(u, uEltypeNoUnits)
6565
recursivefill!(atmp, false)
6666
tmp = zero(u)
67-
ExplicitTaylorCache(Val(P), jet_iip, u, uprev, utaylor, utilde, tmp, atmp,
67+
ExplicitTaylorCache(alg.order, jet_iip, u, uprev, utaylor, utilde, tmp, atmp,
6868
alg.stage_limiter!, alg.step_limiter!, alg.thread)
6969
end
7070

@@ -86,3 +86,42 @@ end
8686

8787
# FSAL currently not used, providing dummy implementation to satisfy the interface
8888
get_fsalfirstlast(cache::ExplicitTaylorCache, u) = (cache.u, cache.u)
89+
90+
@cache struct ExplicitTaylorAdaptiveOrderCache{
91+
uType, taylorType, uNoUnitsType, StageLimiter, StepLimiter,
92+
Thread} <: OrdinaryDiffEqMutableCache
93+
min_order::Int
94+
max_order::Int
95+
current_order::Ref{Int}
96+
jets::Vector{Function}
97+
u::uType
98+
uprev::uType
99+
utaylor::taylorType
100+
utilde::uType
101+
tmp::uType
102+
atmp::uNoUnitsType
103+
stage_limiter!::StageLimiter
104+
step_limiter!::StepLimiter
105+
thread::Thread
106+
end
107+
function alg_cache(
108+
alg::ExplicitTaylorAdaptiveOrder, u, rate_prototype, ::Type{uEltypeNoUnits},
109+
::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t,
110+
dt, reltol, p, calck,
111+
::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits}
112+
jets = Function[]
113+
for order in alg.min_order:alg.max_order
114+
_, jet_iip = build_jet(f, p, Val(order), length(u))
115+
push!(jets, jet_iip)
116+
end
117+
utaylor = TaylorDiff.make_seed(u, zero(u), Val(alg.max_order))
118+
utilde = zero(u)
119+
atmp = similar(u, uEltypeNoUnits)
120+
recursivefill!(atmp, false)
121+
tmp = zero(u)
122+
current_order = Ref{Int}(alg.min_order)
123+
ExplicitTaylorAdaptiveOrderCache(alg.min_order, alg.max_order, current_order, jets, u, uprev, utaylor, utilde, tmp, atmp,
124+
alg.stage_limiter!, alg.step_limiter!, alg.thread)
125+
end
126+
127+
get_fsalfirstlast(cache::ExplicitTaylorAdaptiveOrderCache, u) = (cache.u, cache.u)

lib/OrdinaryDiffEqTaylorSeries/src/TaylorSeries_perform_step.jl

+59-1
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,69 @@ end
9090
end
9191
if integrator.opts.adaptive
9292
@.. broadcast=false thread=thread utilde=TaylorDiff.get_coefficient(utaylor, P) *
93-
dt^(P + 1)
93+
dt^P
9494
calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol,
9595
integrator.opts.reltol, integrator.opts.internalnorm, t)
9696
integrator.EEst = integrator.opts.internalnorm(atmp, t)
9797
end
9898
OrdinaryDiffEqCore.increment_nf!(integrator.stats, P + 1)
9999
return nothing
100100
end
101+
102+
function initialize!(integrator, cache::ExplicitTaylorAdaptiveOrderCache)
103+
integrator.kshortsize = cache.max_order
104+
resize!(integrator.k, cache.max_order)
105+
# Setup k pointers
106+
for i in 1:(cache.max_order)
107+
integrator.k[i] = get_coefficient(cache.utaylor, i)
108+
end
109+
return nothing
110+
end
111+
112+
@muladd function perform_step!(
113+
integrator, cache::ExplicitTaylorAdaptiveOrderCache, repeat_step = false)
114+
@unpack t, dt, uprev, u, f, p = integrator
115+
alg = unwrap_alg(integrator, false)
116+
@unpack jets, current_order, min_order, max_order, utaylor, utilde, tmp, atmp, thread = cache
117+
118+
jet_index = current_order[] - min_order + 1
119+
# compute one additional order for adaptive order
120+
jet = jets[jet_index + 1]
121+
jet(utaylor, uprev, t)
122+
for i in eachindex(utaylor)
123+
u[i] = @inline evaluate_polynomial(utaylor[i], dt)
124+
end
125+
OrdinaryDiffEqCore.increment_nf!(integrator.stats, current_order[] + 1)
126+
if integrator.opts.adaptive
127+
min_work = Inf
128+
start_order = max(min_order, current_order[] - 1)
129+
end_order = min(max_order, current_order[] + 1)
130+
for i in start_order:end_order
131+
A = i * i
132+
@.. broadcast=false thread=thread utilde=TaylorDiff.get_coefficient(
133+
utaylor, i) * dt^i
134+
calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol,
135+
integrator.opts.reltol, integrator.opts.internalnorm, t)
136+
EEst = integrator.opts.internalnorm(atmp, t)
137+
138+
# backup
139+
e = integrator.EEst
140+
qold = integrator.qold
141+
# calculate dt
142+
integrator.EEst = EEst
143+
dtpropose = step_accept_controller!(integrator, alg,
144+
stepsize_controller!(integrator, alg))
145+
# restore
146+
integrator.EEst = e
147+
integrator.qold = qold
148+
149+
work = A / dtpropose
150+
if work < min_work
151+
cache.current_order[] = i
152+
min_work = work
153+
integrator.EEst = EEst
154+
end
155+
end
156+
end
157+
return nothing
158+
end

lib/OrdinaryDiffEqTaylorSeries/src/alg_utils.jl

+12-5
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ alg_stability_size(alg::ExplicitTaylor2) = 1
44
alg_order(::ExplicitTaylor{P}) where {P} = P
55
alg_stability_size(alg::ExplicitTaylor) = 1
66

7-
JET_CACHE = IdDict()
7+
alg_order(alg::ExplicitTaylorAdaptiveOrder) = alg.min_order
8+
get_current_adaptive_order(::ExplicitTaylorAdaptiveOrder, cache) = cache.current_order[]
9+
get_current_alg_order(::ExplicitTaylorAdaptiveOrder, cache) = cache.current_order[]
810

9-
function build_jet(f::ODEFunction{iip}, p, order, length = nothing) where {iip}
10-
build_jet(f, Val{iip}(), p, order, length)
11+
TaylorScalar{T, P}(x::TaylorScalar{T, Q}) where {T, P, Q} = TaylorScalar{P}(x)
12+
13+
const JET_CACHE = IdDict()
14+
15+
function make_term(a)
16+
term(TaylorScalar, Symbolics.unwrap(a.value), map(Symbolics.unwrap, a.partials))
1117
end
1218

13-
function build_jet(f, ::Val{iip}, p, order::Val{P}, length = nothing) where {P, iip}
19+
function build_jet(f::ODEFunction{iip}, p, order::Val{P}, length = nothing) where {P, iip}
1420
if haskey(JET_CACHE, f)
1521
list = JET_CACHE[f]
1622
index = findfirst(x -> x[1] == order && x[2] == p, list)
@@ -37,7 +43,8 @@ function build_jet(f, ::Val{iip}, p, order::Val{P}, length = nothing) where {P,
3743
d = get_coefficient(fu, index - 1) / index
3844
u = append_coefficient(u, d)
3945
end
40-
jet = build_function(u, u0, t0; expression = Val(false), cse = true)
46+
u_term = make_term.(u)
47+
jet = build_function(u_term, u0, t0; expression = Val(false), cse = true)
4148
if !haskey(JET_CACHE, f)
4249
JET_CACHE[f] = []
4350
end

lib/OrdinaryDiffEqTaylorSeries/src/algorithms.jl

+13-1
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,23 @@ end
1515

1616
@doc explicit_rk_docstring(
1717
"An arbitrary-order explicit Taylor series method.",
18-
"ExplicitTaylor2")
18+
"ExplicitTaylor")
1919
Base.@kwdef struct ExplicitTaylor{P, StageLimiter, StepLimiter, Thread} <:
2020
OrdinaryDiffEqAdaptiveAlgorithm
2121
order::Val{P} = Val{1}()
2222
stage_limiter!::StageLimiter = trivial_limiter!
2323
step_limiter!::StepLimiter = trivial_limiter!
2424
thread::Thread = False()
2525
end
26+
27+
@doc explicit_rk_docstring(
28+
"An adaptive order explicit Taylor series method.",
29+
"ExplicitTaylorAdaptiveOrder")
30+
Base.@kwdef struct ExplicitTaylorAdaptiveOrder{StageLimiter, StepLimiter, Thread} <:
31+
OrdinaryDiffEqAdaptiveAlgorithm
32+
min_order::Int = 1
33+
max_order::Int = 10
34+
stage_limiter!::StageLimiter = trivial_limiter!
35+
step_limiter!::StepLimiter = trivial_limiter!
36+
thread::Thread = False()
37+
end

0 commit comments

Comments
 (0)