Skip to content

Commit da80135

Browse files
bdf fix
1 parent f324536 commit da80135

3 files changed

Lines changed: 32 additions & 10 deletions

File tree

lib/OrdinaryDiffEqBDF/src/controllers.jl

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,27 @@ function step_accept_controller!(integrator, cache::Union{QNDFCache, QNDFConstan
161161
h / q
162162
end
163163
end
164-
return is_disco ? min((integrator.disco_checkpoint - integrator.t) / 4, new_dt) : new_dt
164+
if is_disco
165+
return min((integrator.disco_checkpoint - integrator.t) / 4, new_dt)
166+
end
167+
return new_dt
168+
end
169+
170+
"""
171+
bdf_restart_estimates!(cache)
172+
173+
Restart the order and constant-step estimates for a step that straddles a derivative
174+
discontinuity, where the history behind it and the solution ahead belong to different
175+
regimes. We do this because the BDF step-size and order logic is based on the history of the solution,
176+
and we have effectively entered a new regime where old estimates no longer apply.
177+
"""
178+
function bdf_restart_estimates!(cache)
179+
cache.order = 1
180+
cache.nconsteps = 0
181+
if hasfield(typeof(cache), :qwait)
182+
cache.qwait = 3
183+
end
184+
return nothing
165185
end
166186

167187
function bdf_step_reject_controller!(integrator, cache, EEst1)
@@ -438,7 +458,11 @@ function step_accept_controller!(
438458
cache.qwait -= 1 # countdown
439459
end
440460
new_dt = integrator.dt / q
441-
return is_disco ? min((integrator.disco_checkpoint - integrator.t) / 4, new_dt) : new_dt
461+
if is_disco
462+
bdf_restart_estimates!(cache)
463+
return min((integrator.disco_checkpoint - integrator.t) / 4, new_dt)
464+
end
465+
return new_dt
442466
end
443467

444468
function step_reject_controller!(integrator, alg::DFBDF)
@@ -607,5 +631,9 @@ function step_accept_controller!(
607631
cache.qwait -= 1 # countdown
608632
end
609633
new_dt = integrator.dt / q
610-
return is_disco ? min((integrator.disco_checkpoint - integrator.t) / 4, new_dt) : new_dt
634+
if is_disco
635+
bdf_restart_estimates!(cache)
636+
return min((integrator.disco_checkpoint - integrator.t) / 4, new_dt)
637+
end
638+
return new_dt
611639
end

lib/OrdinaryDiffEqCore/src/disco.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ function find_discontinuity(integrator)
2424
dt = integrator.dt
2525
u = integrator.u
2626
uprev = integrator.uprev
27+
integrator.is_disco_step = false
2728
cb === nothing && return one(dt)
2829
isempty(cb.continuous_callbacks) && return one(dt)
2930
p = integrator.p

test/Integrators_I/disco_tests.jl

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,6 @@ prob_stiff = ODEProblem(f_stiff_disc!, u0_stiff, tspan_stiff, [500.0])
145145
cond_stiff(u, t, integrator) = u[1] - 0.5
146146
cb_stiff = ContinuousCallback(cond_stiff, default_affect!; maybe_discontinuity = true)
147147

148-
sol_disco_radau = solve(prob_stiff, RadauIIA5(); callback=cb_stiff, reltol=1e-9, abstol=1e-11, controller = predictive_disco_controller(RadauIIA5()))
149-
# 207.500 μs (2285 allocations: 101.72 KiB)
150-
sol_no_disco_radau = solve(prob_stiff, RadauIIA5(); callback=cb_stiff, reltol=1e-9, abstol=1e-11)
151-
# 196.458 μs (2054 allocations: 95.58 KiB)
152-
@test sol_disco_radau.retcode == ReturnCode.Success
153-
@test sol_disco_radau.stats.nreject <= sol_no_disco_radau.stats.nreject
154-
155148
sol_disco_rosenbrock = solve(prob_stiff, Rodas5P(); callback=cb_stiff, reltol=1e-9, abstol=1e-11, controller = PI_disco_controller(Rodas5P()))
156149
# 364.833 μs (2030 allocations: 85.34 KiB)
157150
sol_no_disco_rosenbrock = solve(prob_stiff, Rodas5P(); callback=cb_stiff, reltol=1e-9, abstol=1e-11)

0 commit comments

Comments
 (0)