Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/time_integration/relaxation_methods/methods_vanderHouwen.jl
5590 views
1
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
2
# Since these FMAs can increase the performance of many numerical algorithms,
3
# we need to opt-in explicitly.
4
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
5
@muladd begin
6
#! format: noindent
7
8
@doc raw"""
9
vanderHouwenAlgorithm
10
11
Abstract type for sub-diagonal Runge-Kutta methods, i.e.,
12
methods with a Butcher tableau of the form
13
```math
14
\begin{array}
15
{c|c|c c c c c c}
16
i & \boldsymbol c & & & A & & & \\
17
\hline
18
1 & 0 & & & & & & \\
19
2 & c_2 & a_{21} & & & & & \\
20
3 & c_3 & b_1 & a_{32} & & & & \\
21
4 & c_4 & b_1 & b_2 & a_{43} & & & \\
22
\vdots & \vdots & \vdots & \vdots & \ddots & \ddots & & \\
23
S & c_S & b_1 & b_2 & \dots & b_{S-2} & a_{S, S-1} & \\
24
\hline
25
& & b_1 & b_2 & \dots & b_{S-2} & b_{S-1} & b_S
26
\end{array}
27
```
28
29
Currently implemented methods are the Carpenter-Kennedy-Lewis 4-stage, 3rd-order method [`CKL43`](@ref)
30
and the Carpenter-Kennedy-Lewis 5-stage, 4th-order method [`CKL54`](@ref) which are optimized for the
31
compressible Navier-Stokes equations.
32
"""
33
abstract type vanderHouwenAlgorithm <: AbstractTimeIntegrationAlgorithm end
34
35
"""
36
vanderHouwenRelaxationAlgorithm
37
38
Abstract type for van-der-Houwen type Runge-Kutta algorithms (see [`vanderHouwenAlgorithm`](@ref))
39
with relaxation to achieve entropy-conservation/stability.
40
In addition to the standard Runge-Kutta method, these algorithms are equipped with a
41
relaxation solver [`AbstractRelaxationSolver`](@ref) which is used to compute the relaxation parameter ``\\gamma``.
42
This allows the relaxation methods to suppress entropy defects due to the time stepping.
43
44
For details on the relaxation procedure, see
45
- Ketcheson (2019)
46
Relaxation Runge-Kutta Methods: Conservation and Stability for Inner-Product Norms
47
[DOI: 10.1137/19M1263662](https://doi.org/10.1137/19M1263662)
48
- Ranocha et al. (2020)
49
Relaxation Runge-Kutta Methods: Fully Discrete Explicit Entropy-Stable Schemes for the Compressible Euler and Navier-Stokes Equations
50
[DOI: 10.1137/19M1263480](https://doi.org/10.1137/19M1263480)
51
52
Currently implemented methods are the Carpenter-Kennedy-Lewis 4-stage, 3rd-order method [`RelaxationCKL43`](@ref)
53
and the Carpenter-Kennedy-Lewis 5-stage, 4th-order method [`RelaxationCKL54`](@ref) which are optimized for the
54
compressible Navier-Stokes equations.
55
"""
56
abstract type vanderHouwenRelaxationAlgorithm <:
57
AbstractRelaxationTimeIntegrationAlgorithm end
58
59
"""
60
CKL43()
61
62
Carpenter-Kennedy-Lewis 4-stage, 3rd-order low-storage Runge-Kutta method,
63
optimized for the compressible Navier-Stokes equations.
64
Implemented as a [`vanderHouwenAlgorithm`](@ref).
65
For the exact coefficients consult the original paper:
66
67
- Kennedy, Carpenter, Lewis (2000)
68
Low-storage, explicit Runge-Kutta schemes for the compressible Navier-Stokes equations
69
[DOI: 10.1016/S0168-9274(99)00141-5](https://doi.org/10.1016/S0168-9274(99)00141-5)
70
"""
71
struct CKL43 <: vanderHouwenAlgorithm
72
a::SVector{4, Float64}
73
b::SVector{4, Float64}
74
c::SVector{4, Float64}
75
end
76
function CKL43()
77
a = SVector(0.0,
78
11847461282814 / 36547543011857,
79
3943225443063 / 7078155732230,
80
-346793006927 / 4029903576067)
81
82
b = SVector(1017324711453 / 9774461848756,
83
8237718856693 / 13685301971492,
84
57731312506979 / 19404895981398,
85
-101169746363290 / 37734290219643)
86
c = SVector(0.0,
87
a[2],
88
b[1] + a[3],
89
b[1] + b[2] + a[4])
90
91
return CKL43(a, b, c)
92
end
93
94
"""
95
RelaxationCKL43(; relaxation_solver = RelaxationSolverNewton())
96
97
Relaxation version of the 4-stage, 3rd-order low-storage Runge-Kutta method [`CKL43()`](@ref),
98
implemented as a [`vanderHouwenRelaxationAlgorithm`](@ref).
99
The default relaxation solver [`AbstractRelaxationSolver`](@ref) is [`RelaxationSolverNewton`](@ref).
100
"""
101
struct RelaxationCKL43{AbstractRelaxationSolver} <: vanderHouwenRelaxationAlgorithm
102
van_der_houwen_alg::CKL43
103
relaxation_solver::AbstractRelaxationSolver
104
end
105
function RelaxationCKL43(; relaxation_solver = RelaxationSolverNewton())
106
return RelaxationCKL43{typeof(relaxation_solver)}(CKL43(), relaxation_solver)
107
end
108
109
"""
110
CKL54()
111
112
Carpenter-Kennedy-Lewis 5-stage, 4th-order low-storage Runge-Kutta method,
113
optimized for the compressible Navier-Stokes equations.
114
Implemented as a [`vanderHouwenAlgorithm`](@ref).
115
For the exact coefficients consult the original paper:
116
117
- Kennedy, Carpenter, Lewis (2000)
118
Low-storage, explicit Runge-Kutta schemes for the compressible Navier-Stokes equations
119
[DOI: 10.1016/S0168-9274(99)00141-5](https://doi.org/10.1016/S0168-9274(99)00141-5)
120
"""
121
struct CKL54 <: vanderHouwenAlgorithm
122
a::SVector{5, Float64}
123
b::SVector{5, Float64}
124
c::SVector{5, Float64}
125
end
126
function CKL54()
127
a = SVector(0.0,
128
970286171893 / 4311952581923,
129
6584761158862 / 12103376702013,
130
2251764453980 / 15575788980749,
131
26877169314380 / 34165994151039)
132
133
b = SVector(1153189308089 / 22510343858157,
134
1772645290293 / 4653164025191,
135
-1672844663538 / 4480602732383,
136
2114624349019 / 3568978502595,
137
5198255086312 / 14908931495163)
138
c = SVector(0.0,
139
a[2],
140
b[1] + a[3],
141
b[1] + b[2] + a[4],
142
b[1] + b[2] + b[3] + a[5])
143
144
return CKL54(a, b, c)
145
end
146
147
"""
148
RelaxationCKL54(; relaxation_solver = RelaxationSolverNewton())
149
150
Relaxation version of the 4-stage, 3rd-order low-storage Runge-Kutta method [`CKL54()`](@ref),
151
implemented as a [`vanderHouwenRelaxationAlgorithm`](@ref).
152
The default relaxation solver [`AbstractRelaxationSolver`](@ref) is [`RelaxationSolverNewton`](@ref).
153
"""
154
struct RelaxationCKL54{AbstractRelaxationSolver} <: vanderHouwenRelaxationAlgorithm
155
van_der_houwen_alg::CKL54
156
relaxation_solver::AbstractRelaxationSolver
157
end
158
function RelaxationCKL54(; relaxation_solver = RelaxationSolverNewton())
159
return RelaxationCKL54{typeof(relaxation_solver)}(CKL54(), relaxation_solver)
160
end
161
162
# This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77
163
# This implements the interface components described at
164
# https://diffeq.sciml.ai/v6.8/basics/integrator/#Handing-Integrators-1
165
# which are used in Trixi.jl.
166
mutable struct vanderHouwenRelaxationIntegrator{RealT <: Real, uType <: AbstractVector,
167
Params, Sol, F, Alg,
168
SimpleIntegratorOptions,
169
AbstractRelaxationSolver} <:
170
RelaxationIntegrator
171
u::uType
172
du::uType
173
u_tmp::uType
174
t::RealT
175
dt::RealT # current time step
176
dtcache::RealT # ignored
177
iter::Int # current number of time steps (iteration)
178
p::Params # will be the semidiscretization from Trixi.jl
179
sol::Sol # faked
180
const f::F # `rhs` of the semidiscretization
181
const alg::Alg # `vanderHouwenRelaxationAlgorithm`
182
opts::SimpleIntegratorOptions
183
finalstep::Bool # added for convenience
184
# Addition for efficient implementation
185
k_prev::uType
186
# Addition for Relaxation methodology
187
direction::uType # RK update, i.e., sum of stages K_i times weights b_i
188
gamma::RealT # Relaxation parameter
189
S_old::RealT # Entropy of previous iterate
190
const relaxation_solver::AbstractRelaxationSolver
191
# Note: Could add another register which would store the summed-up
192
# dot products ∑ₖ (wₖ ⋅ kₖ) and then integrate only once and not per stage k
193
# Could also add option `recompute_entropy` for entropy-conservative problems
194
# to save redundant computations.
195
end
196
197
function init(ode::ODEProblem, alg::vanderHouwenRelaxationAlgorithm;
198
dt, callback::Union{CallbackSet, Nothing} = nothing, kwargs...)
199
u = copy(ode.u0)
200
du = similar(u)
201
u_tmp = copy(u)
202
k_prev = similar(u)
203
204
t = first(ode.tspan)
205
iter = 0
206
207
# For entropy relaxation
208
direction = zero(u)
209
gamma = one(eltype(u))
210
semi = ode.p
211
u_wrap = wrap_array(u, semi)
212
S_old = integrate(entropy, u_wrap, semi.mesh, semi.equations, semi.solver,
213
semi.cache)
214
215
integrator = vanderHouwenRelaxationIntegrator(u, du, u_tmp, t, dt, zero(dt), iter,
216
ode.p, (prob = ode,), ode.f,
217
alg.van_der_houwen_alg,
218
SimpleIntegratorOptions(callback,
219
ode.tspan;
220
kwargs...),
221
false,
222
k_prev, direction, gamma, S_old,
223
alg.relaxation_solver)
224
225
initialize_callbacks!(callback, integrator)
226
227
return integrator
228
end
229
230
function step!(integrator::vanderHouwenRelaxationIntegrator)
231
@unpack prob = integrator.sol
232
@unpack alg = integrator
233
t_end = last(prob.tspan)
234
callbacks = integrator.opts.callback
235
236
@assert !integrator.finalstep
237
if isnan(integrator.dt)
238
error("time step size `dt` is NaN")
239
end
240
241
limit_dt!(integrator, t_end)
242
243
@trixi_timeit timer() "Relaxation vdH RK integration step" begin
244
num_stages = length(alg.c)
245
246
mesh, equations, dg, cache = mesh_equations_solver_cache(prob.p)
247
u_wrap = wrap_array(integrator.u, prob.p)
248
u_tmp_wrap = wrap_array(integrator.u_tmp, prob.p)
249
250
# First stage
251
integrator.f(integrator.du, integrator.u, prob.p, integrator.t)
252
# Try to enable optimizations due to `muladd` by computing this factor only once, see
253
# https://github.com/trixi-framework/Trixi.jl/pull/2480#discussion_r2224529532
254
b1dt = alg.b[1] * integrator.dt
255
@threaded for i in eachindex(integrator.u)
256
integrator.direction[i] = b1dt * integrator.du[i]
257
258
integrator.k_prev[i] = integrator.du[i] # Faster than broadcasted version (with .=)
259
end
260
261
du_wrap = wrap_array(integrator.du, prob.p)
262
# Entropy change due to first stage
263
dS = alg.b[1] * integrator.dt *
264
integrate_w_dot_stage(du_wrap, u_wrap, mesh, equations, dg, cache)
265
266
a2_dt = alg.a[2] * integrator.dt
267
@threaded for i in eachindex(integrator.u)
268
integrator.u_tmp[i] = integrator.u[i] + a2_dt * integrator.du[i]
269
end
270
271
# Second to last stage
272
for stage in 2:(num_stages - 1)
273
integrator.f(integrator.du, integrator.u_tmp, prob.p,
274
integrator.t + alg.c[stage] * integrator.dt)
275
276
# Entropy change due to current stage
277
bs_dt = alg.b[stage] * integrator.dt
278
dS += bs_dt *
279
integrate_w_dot_stage(du_wrap, u_tmp_wrap, mesh, equations, dg, cache)
280
281
bsminus1_minus_as = alg.b[stage - 1] - alg.a[stage]
282
@threaded for i in eachindex(integrator.u)
283
# Try to enable optimizations due to `muladd` by avoiding `+=`
284
# https://github.com/trixi-framework/Trixi.jl/pull/2480#discussion_r2224531702
285
integrator.direction[i] = integrator.direction[i] +
286
bs_dt * integrator.du[i]
287
288
# Subtract previous stage contribution from `u_tmp` and add most recent one
289
integrator.u_tmp[i] = integrator.u_tmp[i] +
290
integrator.dt *
291
(bsminus1_minus_as * integrator.k_prev[i] +
292
alg.a[stage + 1] * integrator.du[i])
293
294
integrator.k_prev[i] = integrator.du[i] # Faster than broadcasted version (with .=)
295
end
296
end
297
298
# Last stage
299
integrator.f(integrator.du, integrator.u_tmp, prob.p,
300
integrator.t + alg.c[num_stages] * integrator.dt)
301
302
bs_dt = alg.b[num_stages] * integrator.dt
303
dS += bs_dt *
304
integrate_w_dot_stage(du_wrap, u_tmp_wrap, mesh, equations, dg, cache)
305
306
@threaded for i in eachindex(integrator.u)
307
integrator.direction[i] = integrator.direction[i] + bs_dt * integrator.du[i]
308
end
309
310
direction_wrap = wrap_array(integrator.direction, prob.p)
311
312
@trixi_timeit timer() "Relaxation solver" relaxation_solver!(integrator,
313
u_tmp_wrap, u_wrap,
314
direction_wrap, dS,
315
mesh, equations,
316
dg, cache,
317
integrator.relaxation_solver)
318
319
integrator.iter += 1
320
update_t_relaxation!(integrator)
321
322
# Do relaxed update
323
@threaded for i in eachindex(integrator.u)
324
integrator.u[i] = integrator.u[i] +
325
integrator.gamma * integrator.direction[i]
326
end
327
end
328
329
@trixi_timeit timer() "Step-Callbacks" handle_callbacks!(callbacks, integrator)
330
331
check_max_iter!(integrator)
332
333
return nothing
334
end
335
336
# used for AMR
337
function Base.resize!(integrator::vanderHouwenRelaxationIntegrator, new_size)
338
resize!(integrator.u, new_size)
339
resize!(integrator.du, new_size)
340
resize!(integrator.u_tmp, new_size)
341
resize!(integrator.k_prev, new_size)
342
# Relaxation addition
343
resize!(integrator.direction, new_size)
344
345
return nothing
346
end
347
end # @muladd
348
349