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_subdiagonal.jl
5591 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
SubDiagonalAlgorithm
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}
16
i & \boldsymbol c & & & A & & \\
17
\hline
18
1 & 0 & & & & &\\
19
2 & c_2 & c_2 & & & & \\
20
3 & c_3 & 0 & c_3 & & & \\
21
4 & c_4 & 0 & 0 & c_4 & \\
22
\vdots & & \vdots & \vdots & \ddots & \ddots & \\
23
S & c_S & 0 & & \dots & 0 & c_S \\
24
\hline
25
& & b_1 & b_2 & \dots & & b_S
26
\end{array}
27
```
28
29
Currently implemented are the third-order, three-stage method by Ralston [`Ralston3`](@ref)
30
and the canonical fourth-order, four-stage method by Kutta [`RK44`](@ref).
31
"""
32
abstract type SubDiagonalAlgorithm <: AbstractTimeIntegrationAlgorithm end
33
34
"""
35
SubDiagonalRelaxationAlgorithm
36
37
Abstract type for sub-diagonal Runge-Kutta algorithms (see [`SubDiagonalAlgorithm`](@ref))
38
with relaxation to achieve entropy conservation/stability.
39
In addition to the standard Runge-Kutta method, these algorithms are equipped with a
40
relaxation solver [`AbstractRelaxationSolver`](@ref) which is used to compute the relaxation parameter ``\\gamma``.
41
This allows the relaxation methods to suppress entropy defects due to the time stepping.
42
43
For details on the relaxation procedure, see
44
- Ketcheson (2019)
45
Relaxation Runge-Kutta Methods: Conservation and Stability for Inner-Product Norms
46
[DOI: 10.1137/19M1263662](https://doi.org/10.1137/19M1263662)
47
- Ranocha et al. (2020)
48
Relaxation Runge-Kutta Methods: Fully Discrete Explicit Entropy-Stable Schemes for the Compressible Euler and Navier-Stokes Equations
49
[DOI: 10.1137/19M1263480](https://doi.org/10.1137/19M1263480)
50
51
Currently implemented are the third-order, three-stage method by Ralston [`Ralston3`](@ref)
52
and the canonical fourth-order, four-stage method by Kutta [`RK44`](@ref).
53
"""
54
abstract type SubDiagonalRelaxationAlgorithm <:
55
AbstractRelaxationTimeIntegrationAlgorithm end
56
57
"""
58
Ralston3()
59
60
Relaxation version of Ralston's third-order Runge-Kutta method, implemented as a [`SubDiagonalAlgorithm`](@ref).
61
The weight vector is given by ``\\boldsymbol b = [2/9, 1/3, 4/9]`` and the
62
abscissae/timesteps by ``\\boldsymbol c = [0.0, 0.5, 0.75]``.
63
64
This method has minimum local error bound among the ``S=p=3`` methods.
65
- Ralston (1962)
66
Runge-Kutta Methods with Minimum Error Bounds
67
[DOI: 10.1090/S0025-5718-1962-0150954-0](https://doi.org/10.1090/S0025-5718-1962-0150954-0)
68
"""
69
struct Ralston3 <: SubDiagonalAlgorithm
70
b::SVector{3, Float64}
71
c::SVector{3, Float64}
72
end
73
function Ralston3()
74
b = SVector(2 / 9, 1 / 3, 4 / 9)
75
c = SVector(0.0, 0.5, 0.75)
76
77
return Ralston3(b, c)
78
end
79
80
"""
81
RelaxationRalston3(; relaxation_solver = RelaxationSolverNewton())
82
83
Relaxation version of Ralston's third-order Runge-Kutta method [`Ralston3()`](@ref),
84
implemented as a [`SubDiagonalRelaxationAlgorithm`](@ref).
85
The default relaxation solver [`AbstractRelaxationSolver`](@ref) is [`RelaxationSolverNewton`](@ref).
86
"""
87
struct RelaxationRalston3{AbstractRelaxationSolver} <: SubDiagonalRelaxationAlgorithm
88
sub_diagonal_alg::Ralston3
89
relaxation_solver::AbstractRelaxationSolver
90
end
91
function RelaxationRalston3(; relaxation_solver = RelaxationSolverNewton())
92
return RelaxationRalston3{typeof(relaxation_solver)}(Ralston3(), relaxation_solver)
93
end
94
95
"""
96
RK44()
97
98
The canonical fourth-order Runge-Kutta method, implemented as a [`SubDiagonalAlgorithm`](@ref).
99
The weight vector is given by ``\\boldsymbol b = [1/6, 1/3, 1/3, 1/6]`` and the
100
abscissae/timesteps by ``\\boldsymbol c = [0.0, 0.5, 0.5, 1.0]``.
101
"""
102
struct RK44 <: SubDiagonalAlgorithm
103
b::SVector{4, Float64}
104
c::SVector{4, Float64}
105
end
106
function RK44()
107
b = SVector(1 / 6, 1 / 3, 1 / 3, 1 / 6)
108
c = SVector(0.0, 0.5, 0.5, 1.0)
109
110
return RK44(b, c)
111
end
112
113
"""
114
RelaxationRK44(; relaxation_solver = RelaxationSolverNewton())
115
116
Relaxation version of the canonical fourth-order Runge-Kutta method [`RK44()`](@ref),
117
implemented as a [`SubDiagonalRelaxationAlgorithm`](@ref).
118
The default relaxation solver [`AbstractRelaxationSolver`](@ref) is [`RelaxationSolverNewton`](@ref).
119
"""
120
struct RelaxationRK44{AbstractRelaxationSolver} <: SubDiagonalRelaxationAlgorithm
121
sub_diagonal_alg::RK44
122
relaxation_solver::AbstractRelaxationSolver
123
end
124
function RelaxationRK44(; relaxation_solver = RelaxationSolverNewton())
125
return RelaxationRK44{typeof(relaxation_solver)}(RK44(), relaxation_solver)
126
end
127
128
# This struct is needed to fake https://github.com/SciML/OrdinaryDiffEq.jl/blob/0c2048a502101647ac35faabd80da8a5645beac7/src/integrators/type.jl#L77
129
# This implements the interface components described at
130
# https://diffeq.sciml.ai/v6.8/basics/integrator/#Handing-Integrators-1
131
# which are used in Trixi.jl.
132
mutable struct SubDiagonalRelaxationIntegrator{RealT <: Real, uType <: AbstractVector,
133
Params, Sol, F, Alg,
134
SimpleIntegratorOptions,
135
AbstractRelaxationSolver} <:
136
RelaxationIntegrator
137
u::uType
138
du::uType
139
u_tmp::uType
140
t::RealT
141
dt::RealT # current time step
142
dtcache::RealT # ignored
143
iter::Int # current number of time steps (iteration)
144
p::Params # will be the semidiscretization from Trixi.jl
145
sol::Sol # faked
146
const f::F # `rhs` of the semidiscretization
147
const alg::Alg # `SubDiagonalRelaxationAlgorithm`
148
opts::SimpleIntegratorOptions
149
finalstep::Bool # added for convenience
150
# Addition for Relaxation methodology
151
direction::uType # RK update, i.e., sum of stages K_i times weights b_i
152
gamma::RealT # Relaxation parameter
153
S_old::RealT # Entropy of previous iterate
154
const relaxation_solver::AbstractRelaxationSolver
155
# Note: Could add another register which would store the summed-up
156
# dot products ∑ₖ (wₖ ⋅ kₖ) and then integrate only once and not per stage k
157
# Could also add option `recompute_entropy` for entropy-conservative problems
158
# to save redundant computations.
159
end
160
161
function init(ode::ODEProblem, alg::SubDiagonalRelaxationAlgorithm;
162
dt, callback::Union{CallbackSet, Nothing} = nothing, kwargs...)
163
u = copy(ode.u0)
164
du = zero(u)
165
u_tmp = zero(u)
166
167
t = first(ode.tspan)
168
iter = 0
169
170
# For entropy relaxation
171
direction = zero(u)
172
gamma = one(eltype(u))
173
semi = ode.p
174
u_wrap = wrap_array(u, semi)
175
S_old = integrate(entropy, u_wrap, semi.mesh, semi.equations, semi.solver,
176
semi.cache)
177
178
integrator = SubDiagonalRelaxationIntegrator(u, du, u_tmp, t, dt, zero(dt), iter,
179
ode.p, (prob = ode,), ode.f,
180
alg.sub_diagonal_alg,
181
SimpleIntegratorOptions(callback,
182
ode.tspan;
183
kwargs...),
184
false,
185
direction, gamma, S_old,
186
alg.relaxation_solver)
187
188
initialize_callbacks!(callback, integrator)
189
190
return integrator
191
end
192
193
function step!(integrator::SubDiagonalRelaxationIntegrator)
194
@unpack prob = integrator.sol
195
@unpack alg = integrator
196
t_end = last(prob.tspan)
197
callbacks = integrator.opts.callback
198
199
@assert !integrator.finalstep
200
if isnan(integrator.dt)
201
error("time step size `dt` is NaN")
202
end
203
204
limit_dt!(integrator, t_end)
205
206
@trixi_timeit timer() "Relaxation sub-diagonal RK integration step" begin
207
mesh, equations, dg, cache = mesh_equations_solver_cache(prob.p)
208
209
u_wrap = wrap_array(integrator.u, prob.p)
210
u_tmp_wrap = wrap_array(integrator.u_tmp, prob.p)
211
212
# First stage
213
integrator.f(integrator.du, integrator.u, prob.p, integrator.t)
214
# Try to enable optimizations due to `muladd` by computing this factor only once, see
215
# https://github.com/trixi-framework/Trixi.jl/pull/2480#discussion_r2224529532
216
b1_dt = alg.b[1] * integrator.dt
217
@threaded for i in eachindex(integrator.u)
218
integrator.direction[i] = b1_dt * integrator.du[i]
219
end
220
221
du_wrap = wrap_array(integrator.du, prob.p)
222
# Entropy change due to first stage
223
dS = b1_dt * integrate_w_dot_stage(du_wrap, u_wrap, mesh, equations, dg, cache)
224
225
# Second to last stage
226
for stage in 2:length(alg.c)
227
c_dt = alg.c[stage] * integrator.dt
228
@threaded for i in eachindex(integrator.u)
229
integrator.u_tmp[i] = integrator.u[i] + c_dt * integrator.du[i]
230
end
231
integrator.f(integrator.du, integrator.u_tmp, prob.p,
232
integrator.t + alg.c[stage] * integrator.dt)
233
b_dt = alg.b[stage] * integrator.dt
234
@threaded for i in eachindex(integrator.u)
235
integrator.direction[i] = integrator.direction[i] +
236
b_dt * integrator.du[i]
237
end
238
239
# Entropy change due to current stage
240
dS += b_dt *
241
integrate_w_dot_stage(du_wrap, u_tmp_wrap, mesh, equations, dg, cache)
242
end
243
244
direction_wrap = wrap_array(integrator.direction, prob.p)
245
246
@trixi_timeit timer() "Relaxation solver" relaxation_solver!(integrator,
247
u_tmp_wrap, u_wrap,
248
direction_wrap, dS,
249
mesh, equations,
250
dg, cache,
251
integrator.relaxation_solver)
252
253
integrator.iter += 1
254
update_t_relaxation!(integrator)
255
256
# Do relaxed update
257
@threaded for i in eachindex(integrator.u)
258
integrator.u[i] = integrator.u[i] +
259
integrator.gamma * integrator.direction[i]
260
end
261
end
262
263
@trixi_timeit timer() "Step-Callbacks" handle_callbacks!(callbacks, integrator)
264
265
check_max_iter!(integrator)
266
267
return nothing
268
end
269
270
# used for AMR
271
function Base.resize!(integrator::SubDiagonalRelaxationIntegrator, new_size)
272
resize!(integrator.u, new_size)
273
resize!(integrator.du, new_size)
274
resize!(integrator.u_tmp, new_size)
275
# Relaxation addition
276
resize!(integrator.direction, new_size)
277
278
return nothing
279
end
280
end # @muladd
281
282