@@ -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, τ
8587end
8688
8789struct 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
9699end
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))
110113end
111114
114117
115118function 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)
253263function 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