Skip to content

Commit 0a88e06

Browse files
committed
Use 1st order approximation for error estimates in SSPMPRK22
1 parent 019e5e0 commit 0a88e06

1 file changed

Lines changed: 31 additions & 16 deletions

File tree

src/sspmprk.jl

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,13 @@ function get_constant_parameters(alg::SSPMPRK22)
7777

7878
s = (b20 + b21 + a21 * b10^2) / (b10 * (b20 + b21))
7979

80+
τ = 1 + (a21 * b10^2) / (b20 + b21)
81+
8082
# This should never happen
8183
if any(<(0), (a21, a10, a20, b10, b20, b21))
8284
throw(ArgumentError("SSPMPRK22 requires nonnegative SSP coefficients."))
8385
end
84-
return a21, a10, a20, b10, b20, b21, s
86+
return a21, a10, a20, b10, b20, b21, s, τ
8587
end
8688

8789
struct SSPMPRK22ConstantCache{T} <: OrdinaryDiffEqConstantCache
@@ -92,6 +94,7 @@ struct SSPMPRK22ConstantCache{T} <: OrdinaryDiffEqConstantCache
9294
b20::T
9395
b21::T
9496
s::T
97+
τ::T
9598
small_constant::T
9699
end
97100

@@ -104,8 +107,8 @@ function alg_cache(alg::SSPMPRK22, u, rate_prototype, ::Type{uEltypeNoUnits},
104107
throw(ArgumentError("SSPMPRK22 can only be applied to production-destruction systems"))
105108
end
106109

107-
a21, a10, a20, b10, b20, b21, s = get_constant_parameters(alg)
108-
SSPMPRK22ConstantCache(a21, a10, a20, b10, b20, b21, s,
110+
a21, a10, a20, b10, b20, b21, s, τ = get_constant_parameters(alg)
111+
SSPMPRK22ConstantCache(a21, a10, a20, b10, b20, b21, s, τ,
109112
alg.small_constant_function(uEltypeNoUnits))
110113
end
111114

@@ -114,7 +117,7 @@ end
114117

115118
function perform_step!(integrator, cache::SSPMPRK22ConstantCache, repeat_step = false)
116119
@unpack alg, t, dt, uprev, f, p = integrator
117-
@unpack a21, a10, a20, b10, b20, b21, s, small_constant = cache
120+
@unpack a21, a10, a20, b10, b20, b21, s, τ, small_constant = cache
118121

119122
f = integrator.f
120123

@@ -175,10 +178,17 @@ function perform_step!(integrator, cache::SSPMPRK22ConstantCache, repeat_step =
175178
u = sol.u
176179
integrator.stats.nsolve += 1
177180

181+
# Unless τ = 1, σ is not a first order approximation, since
182+
# σ = uprev + τ * dt *(P^n − D^n) + O(dt^2), see (2.7) in
183+
# https://doi.org/10.1007/s10915-018-0852-1.
184+
# But we can compute a 1st order approximation σ2, as follows.
185+
# σ2 may become negative, but still can be used for error estimation.
186+
σ2 =- uprev) / τ + uprev
187+
178188
# If a21 = 0 or b10 = 0, then σ is a first order approximation of the solution and
179189
# can be used for error estimation.
180190
# TODO: Find first order approximation, if a21*b10 ≠ 0.
181-
tmp = u - σ
191+
tmp = u - σ2
182192
atmp = calculate_residuals(tmp, uprev, u, integrator.opts.abstol,
183193
integrator.opts.reltol, integrator.opts.internalnorm, t)
184194
integrator.EEst = integrator.opts.internalnorm(atmp, t)
@@ -213,8 +223,8 @@ function alg_cache(alg::SSPMPRK22, u, rate_prototype, ::Type{uEltypeNoUnits},
213223
::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits},
214224
uprev, uprev2, f, t, dt, reltol, p, calck,
215225
::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits}
216-
a21, a10, a20, b10, b20, b21, s = get_constant_parameters(alg)
217-
tab = SSPMPRK22ConstantCache(a21, a10, a20, b10, b20, b21, s,
226+
a21, a10, a20, b10, b20, b21, s, τ = get_constant_parameters(alg)
227+
tab = SSPMPRK22ConstantCache(a21, a10, a20, b10, b20, b21, s, τ,
218228
alg.small_constant_function(uEltypeNoUnits))
219229
tmp = zero(u)
220230
P = p_prototype(u, f)
@@ -253,7 +263,7 @@ end
253263
function perform_step!(integrator, cache::SSPMPRK22Cache, repeat_step = false)
254264
@unpack t, dt, uprev, u, f, p = integrator
255265
@unpack tmp, P, P2, D, D2, σ, linsolve = cache
256-
@unpack a21, a10, a20, b10, b20, b21, s, small_constant = cache.tab
266+
@unpack a21, a10, a20, b10, b20, b21, s, τ, small_constant = cache.tab
257267

258268
# We use P2 to store the last evaluation of the PDS
259269
# as well as to store the system matrix of the linear system
@@ -311,12 +321,14 @@ function perform_step!(integrator, cache::SSPMPRK22Cache, repeat_step = false)
311321
u .= linres
312322
integrator.stats.nsolve += 1
313323

314-
# If a21 = 0 or b10 = 0, then σ is a first order approximation of the solution and
315-
# can be used for error estimation.
316-
# TODO: Find first order approximation, if a21*b10 ≠ 0.
324+
# Unless τ = 1, σ is not a first order approximation, since
325+
# σ = uprev + τ * dt *(P^n − D^n) + O(dt^2), see (2.7) in
326+
# https://doi.org/10.1007/s10915-018-0852-1.
327+
# But we can compute a 1st order approximation as σ2 = (σ - uprev) / τ + uprev.
328+
# σ2 may become negative, but still can be used for error estimation.
317329

318330
# Now σ stores the error estimate
319-
@.. broadcast=false σ=u - σ
331+
@.. broadcast=false σ=u - - uprev) / τ - uprev
320332

321333
# Now tmp stores error residuals
322334
calculate_residuals!(tmp, σ, uprev, u, integrator.opts.abstol,
@@ -374,11 +386,14 @@ function perform_step!(integrator, cache::SSPMPRK22ConservativeCache, repeat_ste
374386
u .= linres
375387
integrator.stats.nsolve += 1
376388

377-
# If a21 = 0 or b10 = 0, then σ is a first order approximation of the solution and
378-
# can be used for error estimation.
379-
# TODO: Find first order approximation, if a21*b10 ≠ 0.
389+
# Unless τ = 1, σ is not a first order approximation, since
390+
# σ = uprev + τ * dt *(P^n − D^n) + O(dt^2), see (2.7) in
391+
# https://doi.org/10.1007/s10915-018-0852-1.
392+
# But we can compute a 1st order approximation as σ2 = (σ - uprev) / τ + uprev.
393+
# σ2 may become negative, but still can be used for error estimation.
394+
380395
# Now σ stores the error estimate
381-
@.. broadcast=false σ=u - σ
396+
@.. broadcast=false σ=u - - uprev) / τ - uprev
382397

383398
# Now tmp stores error residuals
384399
calculate_residuals!(tmp, σ, uprev, u, integrator.opts.abstol,

0 commit comments

Comments
 (0)