Skip to content

Commit 087bdb7

Browse files
author
Your Name
committed
LowStorageRK: unify 2N family on LowStorageRKTableau
1 parent 8cf2552 commit 087bdb7

5 files changed

Lines changed: 97 additions & 70 deletions

File tree

lib/OrdinaryDiffEqLowStorageRK/src/OrdinaryDiffEqLowStorageRK.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ using Reexport
2525
include("arrayfuse.jl")
2626
include("algorithms.jl")
2727
include("alg_utils.jl")
28+
include("low_storage_tableaus.jl")
2829
include("low_storage_rk_caches.jl")
2930
include("low_storage_rk_perform_step.jl")
31+
include("generic_low_storage_perform_step.jl")
3032

3133
import PrecompileTools
3234
import Preferences
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Generic LowStorageRK perform_step! driven by `LowStorageRKTableau{form,...}`.
2+
# Plain dispatch on the form tag (no @generated); each form gets one method.
3+
4+
@muladd function _perform_step_iip!(
5+
integrator, cache, tab::LowStorageRKTableau{:two_n}
6+
)
7+
(; t, dt, u, f, p) = integrator
8+
(; k, tmp, williamson_condition, stage_limiter!, step_limiter!, thread) = cache
9+
(; A2end, B1, B2end, c2end) = tab
10+
11+
f(k, u, p, t)
12+
OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
13+
@.. broadcast=false thread=thread tmp = dt * k
14+
@.. broadcast=false thread=thread u = u + B1 * tmp
15+
16+
for i in eachindex(A2end)
17+
if williamson_condition
18+
f(ArrayFuse(tmp, u, (A2end[i], dt, B2end[i])), u, p, t + c2end[i] * dt)
19+
else
20+
@.. broadcast=false thread=thread tmp = A2end[i] * tmp
21+
stage_limiter!(u, integrator, p, t + c2end[i] * dt)
22+
f(k, u, p, t + c2end[i] * dt)
23+
@.. broadcast=false thread=thread tmp = tmp + dt * k
24+
@.. broadcast=false thread=thread u = u + B2end[i] * tmp
25+
end
26+
OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
27+
end
28+
stage_limiter!(u, integrator, p, t + dt)
29+
step_limiter!(u, integrator, p, t + dt)
30+
return nothing
31+
end
32+
33+
@muladd function _perform_step_oop!(
34+
integrator, tab::LowStorageRKTableau{:two_n}
35+
)
36+
(; t, dt, u, f, p) = integrator
37+
(; A2end, B1, B2end, c2end) = tab
38+
39+
tmp = dt * integrator.fsalfirst
40+
u = u + B1 * tmp
41+
42+
for i in eachindex(A2end)
43+
k = f(u, p, t + c2end[i] * dt)
44+
OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
45+
tmp = A2end[i] * tmp + dt * k
46+
u = u + B2end[i] * tmp
47+
end
48+
49+
integrator.k[1] = integrator.fsalfirst
50+
integrator.fsalfirst = f(u, p, t + dt)
51+
OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
52+
integrator.u = u
53+
return nothing
54+
end

lib/OrdinaryDiffEqLowStorageRK/src/low_storage_rk_caches.jl

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,6 @@ get_fsalfirstlast(cache::LowStorageRKMutableCache, u) = (cache.fsalfirst, cache.
1717
thread::Thread
1818
end
1919

20-
struct LowStorageRK2NConstantCache{N, T, T2} <: OrdinaryDiffEqConstantCache
21-
A2end::NTuple{N, T} # A1 is always zero
22-
B1::T
23-
B2end::NTuple{N, T}
24-
c2end::NTuple{N, T2} # c1 is always zero
25-
end
26-
2720
function ORK256ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
2821
A2 = convert(T, -1.0)
2922
A3 = convert(T, -1.55798)
@@ -44,7 +37,7 @@ function ORK256ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
4437
c5 = convert(T2, 0.8)
4538
c2end = (c2, c3, c4, c5)
4639

47-
return LowStorageRK2NConstantCache(A2end, B1, B2end, c2end)
40+
return LowStorageRKTableau{:two_n}(A2end, B1, B2end, c2end)
4841
end
4942

5043
function alg_cache(
@@ -144,7 +137,7 @@ function CarpenterKennedy2N54ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
144137
c5 = convert(T2, 2802321613138 // 2924317926251)
145138
c2end = (c2, c3, c4, c5)
146139

147-
return LowStorageRK2NConstantCache(A2end, B1, B2end, c2end)
140+
return LowStorageRKTableau{:two_n}(A2end, B1, B2end, c2end)
148141
end
149142

150143
@cache mutable struct SHLDDRK_2NCache{
@@ -359,7 +352,7 @@ function SHLDDRK64ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
359352
c6 = convert(T2, 0.9271047)
360353
c2end = (c2, c3, c4, c5, c6)
361354

362-
return LowStorageRK2NConstantCache(A2end, B1, B2end, c2end)
355+
return LowStorageRKTableau{:two_n}(A2end, B1, B2end, c2end)
363356
end
364357

365358
function DGLDDRK73_CConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
@@ -388,7 +381,7 @@ function DGLDDRK73_CConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
388381
c7 = convert(T2, 0.998046608462379)
389382
c2end = (c2, c3, c4, c5, c6, c7)
390383

391-
return LowStorageRK2NConstantCache(A2end, B1, B2end, c2end)
384+
return LowStorageRKTableau{:two_n}(A2end, B1, B2end, c2end)
392385
end
393386

394387
function DGLDDRK84_CConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
@@ -420,7 +413,7 @@ function DGLDDRK84_CConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
420413
c8 = convert(T2, 0.919902896453866)
421414
c2end = (c2, c3, c4, c5, c6, c7, c8)
422415

423-
return LowStorageRK2NConstantCache(A2end, B1, B2end, c2end)
416+
return LowStorageRKTableau{:two_n}(A2end, B1, B2end, c2end)
424417
end
425418

426419
function DGLDDRK84_FConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
@@ -452,7 +445,7 @@ function DGLDDRK84_FConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
452445
c8 = convert(T2, 0.9484087623348481)
453446
c2end = (c2, c3, c4, c5, c6, c7, c8)
454447

455-
return LowStorageRK2NConstantCache(A2end, B1, B2end, c2end)
448+
return LowStorageRKTableau{:two_n}(A2end, B1, B2end, c2end)
456449
end
457450

458451
function NDBLSRK124ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
@@ -496,7 +489,7 @@ function NDBLSRK124ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
496489
c12 = convert(T2, 0.9032588871651854)
497490
c2end = (c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12)
498491

499-
return LowStorageRK2NConstantCache(A2end, B1, B2end, c2end)
492+
return LowStorageRKTableau{:two_n}(A2end, B1, B2end, c2end)
500493
end
501494

502495
function NDBLSRK134ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
@@ -543,7 +536,7 @@ function NDBLSRK134ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
543536
c13 = convert(T2, 0.9126827615920843)
544537
c2end = (c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13)
545538

546-
return LowStorageRK2NConstantCache(A2end, B1, B2end, c2end)
539+
return LowStorageRKTableau{:two_n}(A2end, B1, B2end, c2end)
547540
end
548541

549542
function NDBLSRK144ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
@@ -593,7 +586,7 @@ function NDBLSRK144ConstantCache(::Type{T}, ::Type{T2}) where {T, T2}
593586
c14 = convert(T2, 0.8734213127600976)
594587
c2end = (c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14)
595588

596-
return LowStorageRK2NConstantCache(A2end, B1, B2end, c2end)
589+
return LowStorageRKTableau{:two_n}(A2end, B1, B2end, c2end)
597590
end
598591

599592
# 2C low storage methods introduced by Calvo, Franco, Rández (2004)

lib/OrdinaryDiffEqLowStorageRK/src/low_storage_rk_perform_step.jl

Lines changed: 8 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,15 @@
1-
# 2N low storage methods
2-
function initialize!(integrator, cache::LowStorageRK2NConstantCache)
3-
integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal
1+
# 2N low storage methods — dispatched via LowStorageRKTableau{:two_n}
2+
function initialize!(integrator, cache::LowStorageRKTableau{:two_n})
3+
integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t)
44
OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
55
integrator.kshortsize = 1
66
integrator.k = typeof(integrator.k)(undef, integrator.kshortsize)
7-
8-
# Avoid undefined entries if k is an array of arrays
97
integrator.fsallast = zero(integrator.fsalfirst)
108
return integrator.k[1] = integrator.fsalfirst
119
end
1210

13-
@muladd function perform_step!(
14-
integrator, cache::LowStorageRK2NConstantCache,
15-
repeat_step = false
16-
)
17-
(; t, dt, u, f, p) = integrator
18-
(; A2end, B1, B2end, c2end) = cache
19-
20-
# u1
21-
tmp = dt * integrator.fsalfirst
22-
u = u + B1 * tmp
23-
24-
# other stages
25-
for i in eachindex(A2end)
26-
k = f(u, p, t + c2end[i] * dt)
27-
OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
28-
tmp = A2end[i] * tmp + dt * k
29-
u = u + B2end[i] * tmp
30-
end
31-
32-
OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
33-
integrator.k[1] = integrator.fsalfirst
34-
integrator.fsalfirst = f(u, p, t + dt) # For interpolation, then FSAL'd
35-
integrator.u = u
11+
function perform_step!(integrator, cache::LowStorageRKTableau{:two_n}, repeat_step = false)
12+
return _perform_step_oop!(integrator, cache)
3613
end
3714

3815
get_fsalfirstlast(cache::LowStorageRK2NCache, u) = (nothing, nothing)
@@ -42,35 +19,12 @@ function initialize!(integrator, cache::LowStorageRK2NCache)
4219
integrator.kshortsize = 1
4320
resize!(integrator.k, integrator.kshortsize)
4421
integrator.k[1] = k
45-
integrator.f(k, integrator.uprev, integrator.p, integrator.t) # FSAL for interpolation
22+
integrator.f(k, integrator.uprev, integrator.p, integrator.t)
4623
return OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
4724
end
4825

49-
@muladd function perform_step!(integrator, cache::LowStorageRK2NCache, repeat_step = false)
50-
(; t, dt, u, f, p) = integrator
51-
(; k, tmp, williamson_condition, stage_limiter!, step_limiter!, thread) = cache
52-
(; A2end, B1, B2end, c2end) = cache.tab
53-
54-
# u1
55-
f(k, u, p, t)
56-
OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
57-
@.. broadcast = false thread = thread tmp = dt * k
58-
@.. broadcast = false thread = thread u = u + B1 * tmp
59-
# other stages
60-
for i in eachindex(A2end)
61-
if williamson_condition
62-
f(ArrayFuse(tmp, u, (A2end[i], dt, B2end[i])), u, p, t + c2end[i] * dt)
63-
else
64-
@.. broadcast = false thread = thread tmp = A2end[i] * tmp
65-
stage_limiter!(u, integrator, p, t + c2end[i] * dt)
66-
f(k, u, p, t + c2end[i] * dt)
67-
@.. broadcast = false thread = thread tmp = tmp + dt * k
68-
@.. broadcast = false thread = thread u = u + B2end[i] * tmp
69-
end
70-
OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1)
71-
end
72-
stage_limiter!(u, integrator, p, t + dt)
73-
step_limiter!(u, integrator, p, t + dt)
26+
function perform_step!(integrator, cache::LowStorageRK2NCache, repeat_step = false)
27+
return _perform_step_iip!(integrator, cache, cache.tab)
7428
end
7529

7630
# 2C low storage methods
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Unified tableau type for LowStorageRK families.
2+
#
3+
# Each method is identified by a `form` symbol tag carried as the first type
4+
# parameter. perform_step! dispatches on the tag via plain methods in
5+
# generic_low_storage_perform_step.jl.
6+
#
7+
# Currently supported forms:
8+
# :two_n — Williamson 2N (A2end, B1, B2end, c2end)
9+
#
10+
# To add a new form: extend the field set if needed, add a constructor flavor,
11+
# and add the corresponding dispatch in generic_low_storage_perform_step.jl.
12+
13+
struct LowStorageRKTableau{form, N, T, T2} <: OrdinaryDiffEqConstantCache
14+
A2end::NTuple{N, T}
15+
B1::T
16+
B2end::NTuple{N, T}
17+
c2end::NTuple{N, T2}
18+
end
19+
20+
function LowStorageRKTableau{form}(
21+
A2end::NTuple{N, T}, B1::T, B2end::NTuple{N, T}, c2end::NTuple{N, T2}
22+
) where {form, N, T, T2}
23+
return LowStorageRKTableau{form, N, T, T2}(A2end, B1, B2end, c2end)
24+
end

0 commit comments

Comments
 (0)