Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/equations/hyperbolic_diffusion_3d.jl
2055 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
HyperbolicDiffusionEquations3D
10
11
The linear hyperbolic diffusion equations in three space dimensions.
12
A description of this system can be found in Sec. 2.5 of the book "I Do Like CFD, Too: Vol 1".
13
The book is freely available at [http://www.cfdbooks.com/](http://www.cfdbooks.com/) and further analysis can be found in
14
the paper by Nishikawa [DOI: 10.1016/j.jcp.2007.07.029](https://doi.org/10.1016/j.jcp.2007.07.029)
15
"""
16
struct HyperbolicDiffusionEquations3D{RealT <: Real} <:
17
AbstractHyperbolicDiffusionEquations{3, 4}
18
Lr::RealT # reference length scale
19
inv_Tr::RealT # inverse of the reference time scale
20
nu::RealT # diffusion constant
21
end
22
23
function HyperbolicDiffusionEquations3D(; nu = 1.0, Lr = inv(2pi))
24
Tr = Lr^2 / nu
25
HyperbolicDiffusionEquations3D(promote(Lr, inv(Tr), nu)...)
26
end
27
28
function varnames(::typeof(cons2cons), ::HyperbolicDiffusionEquations3D)
29
("phi", "q1", "q2", "q3")
30
end
31
function varnames(::typeof(cons2prim), ::HyperbolicDiffusionEquations3D)
32
("phi", "q1", "q2", "q3")
33
end
34
function default_analysis_errors(::HyperbolicDiffusionEquations3D)
35
(:l2_error, :linf_error, :residual)
36
end
37
38
"""
39
residual_steady_state(du, ::AbstractHyperbolicDiffusionEquations)
40
41
Used to determine the termination criterion of a [`SteadyStateCallback`](@ref).
42
For hyperbolic diffusion, this checks convergence of the potential ``\\phi``.
43
"""
44
@inline function residual_steady_state(du, ::HyperbolicDiffusionEquations3D)
45
abs(du[1])
46
end
47
48
# Set initial conditions at physical location `x` for pseudo-time `t`
49
function initial_condition_poisson_nonperiodic(x, t,
50
equations::HyperbolicDiffusionEquations3D)
51
# elliptic equation: -νΔϕ = f
52
RealT = eltype(x)
53
if t == 0
54
phi = one(RealT)
55
q1 = one(RealT)
56
q2 = one(RealT)
57
q3 = one(RealT)
58
else
59
phi = 2 * cospi(x[1]) *
60
sinpi(2 * x[2]) *
61
sinpi(2 * x[3]) + 2 # ϕ
62
q1 = -2 * convert(RealT, pi) * sinpi(x[1]) *
63
sinpi(2 * x[2]) * sinpi(2 * x[3]) # ϕ_x
64
q2 = 4 * convert(RealT, pi) * cospi(x[1]) *
65
cospi(2 * x[2]) * sinpi(2 * x[3]) # ϕ_y
66
q3 = 4 * convert(RealT, pi) * cospi(x[1]) *
67
sinpi(2 * x[2]) * cospi(2 * x[3]) # ϕ_z
68
end
69
return SVector(phi, q1, q2, q3)
70
end
71
72
@inline function source_terms_poisson_nonperiodic(u, x, t,
73
equations::HyperbolicDiffusionEquations3D)
74
# elliptic equation: -νΔϕ = f
75
# analytical solution: ϕ = 2 cos(πx)sin(2πy)sin(2πz) + 2 and f = 18 π^2 cos(πx)sin(2πy)sin(2πz)
76
RealT = eltype(u)
77
@unpack inv_Tr = equations
78
79
x1, x2, x3 = x
80
du1 = 18 * convert(RealT, pi)^2 * cospi(x1) * sinpi(2 * x2) * sinpi(2 * x3)
81
du2 = -inv_Tr * u[2]
82
du3 = -inv_Tr * u[3]
83
du4 = -inv_Tr * u[4]
84
85
return SVector(du1, du2, du3, du4)
86
end
87
88
function boundary_condition_poisson_nonperiodic(u_inner, orientation, direction, x, t,
89
surface_flux_function,
90
equations::HyperbolicDiffusionEquations3D)
91
# elliptic equation: -νΔϕ = f
92
RealT = eltype(u_inner)
93
phi = 2 * cospi(x[1]) * sinpi(2 * x[2]) *
94
sinpi(2 * x[3]) + 2 # ϕ
95
q1 = -2 * convert(RealT, pi) * sinpi(x[1]) *
96
sinpi(2 * x[2]) * sinpi(2 * x[3]) # ϕ_x
97
q2 = 4 * convert(RealT, pi) * cospi(x[1]) *
98
cospi(2 * x[2]) * sinpi(2 * x[3]) # ϕ_y
99
q3 = 4 * convert(RealT, pi) * cospi(x[1]) *
100
sinpi(2 * x[2]) * cospi(2 * x[3]) # ϕ_z
101
u_boundary = SVector(phi, q1, q2, q3)
102
103
# Calculate boundary flux
104
if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary
105
flux = surface_flux_function(u_inner, u_boundary, orientation, equations)
106
else # u_boundary is "left" of boundary, u_inner is "right" of boundary
107
flux = surface_flux_function(u_boundary, u_inner, orientation, equations)
108
end
109
110
return flux
111
end
112
113
"""
114
source_terms_harmonic(u, x, t, equations::HyperbolicDiffusionEquations3D)
115
116
Source term that only includes the forcing from the hyperbolic diffusion system.
117
"""
118
@inline function source_terms_harmonic(u, x, t,
119
equations::HyperbolicDiffusionEquations3D)
120
# harmonic solution ϕ = (sinh(πx)sin(πy) + sinh(πy)sin(πx))/sinh(π), so f = 0
121
@unpack inv_Tr = equations
122
123
du1 = 0
124
du2 = -inv_Tr * u[2]
125
du3 = -inv_Tr * u[3]
126
du4 = -inv_Tr * u[4]
127
128
return SVector(du1, du2, du3, du4)
129
end
130
131
"""
132
initial_condition_eoc_test_coupled_euler_gravity(x, t, equations::HyperbolicDiffusionEquations3D)
133
134
Setup used for convergence tests of the Euler equations with self-gravity used in
135
- Michael Schlottke-Lakemper, Andrew R. Winters, Hendrik Ranocha, Gregor J. Gassner (2020)
136
A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics
137
[arXiv: 2008.10593](https://arxiv.org/abs/2008.10593)
138
in combination with [`source_terms_harmonic`](@ref).
139
"""
140
function initial_condition_eoc_test_coupled_euler_gravity(x, t,
141
equations::HyperbolicDiffusionEquations3D)
142
143
# Determine phi_x, phi_y
144
RealT = eltype(x)
145
G = 1 # gravitational constant
146
C_grav = -4 * G / (3 * convert(RealT, pi)) # "3" is the number of spatial dimensions # 2D: -2.0*G/pi
147
A = convert(RealT, 0.1) # perturbation coefficient must match Euler setup
148
rho1 = A * sinpi(x[1] + x[2] + x[3] - t)
149
# initialize with ansatz of gravity potential
150
phi = C_grav * rho1
151
q1 = C_grav * A * convert(RealT, pi) *
152
cospi(x[1] + x[2] + x[3] - t) # = gravity acceleration in x-direction
153
q2 = q1 # = gravity acceleration in y-direction
154
q3 = q1 # = gravity acceleration in z-direction
155
156
return SVector(phi, q1, q2, q3)
157
end
158
159
# Calculate 1D flux for a single point
160
@inline function flux(u, orientation::Integer,
161
equations::HyperbolicDiffusionEquations3D)
162
phi, q1, q2, q3 = u
163
164
RealT = eltype(u)
165
if orientation == 1
166
f1 = -equations.nu * q1
167
f2 = -phi * equations.inv_Tr
168
f3 = zero(RealT)
169
f4 = zero(RealT)
170
elseif orientation == 2
171
f1 = -equations.nu * q2
172
f2 = zero(RealT)
173
f3 = -phi * equations.inv_Tr
174
f4 = zero(RealT)
175
else
176
f1 = -equations.nu * q3
177
f2 = zero(RealT)
178
f3 = zero(RealT)
179
f4 = -phi * equations.inv_Tr
180
end
181
182
return SVector(f1, f2, f3, f4)
183
end
184
185
# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation
186
@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,
187
equations::HyperbolicDiffusionEquations3D)
188
return sqrt(equations.nu * equations.inv_Tr)
189
end
190
191
"""
192
flux_godunov(u_ll, u_rr, orientation_or_normal_direction,
193
equations::HyperbolicDiffusionEquations3D)
194
195
Godunov (upwind) flux for the 3D hyperbolic diffusion equations.
196
"""
197
@inline function flux_godunov(u_ll, u_rr, orientation::Integer,
198
equations::HyperbolicDiffusionEquations3D)
199
# Obtain left and right fluxes
200
phi_ll, q1_ll, q2_ll, q3_ll = u_ll
201
phi_rr, q1_rr, q2_rr, q3_rr = u_rr
202
f_ll = flux(u_ll, orientation, equations)
203
f_rr = flux(u_rr, orientation, equations)
204
205
# this is an optimized version of the application of the upwind dissipation matrix:
206
# dissipation = 0.5*R_n*|Λ|*inv(R_n)[[u]]
207
λ_max = sqrt(equations.nu * equations.inv_Tr)
208
f1 = 0.5f0 * (f_ll[1] + f_rr[1]) - 0.5f0 * λ_max * (phi_rr - phi_ll)
209
if orientation == 1 # x-direction
210
f2 = 0.5f0 * (f_ll[2] + f_rr[2]) - 0.5f0 * λ_max * (q1_rr - q1_ll)
211
f3 = 0.5f0 * (f_ll[3] + f_rr[3])
212
f4 = 0.5f0 * (f_ll[4] + f_rr[4])
213
elseif orientation == 2 # y-direction
214
f2 = 0.5f0 * (f_ll[2] + f_rr[2])
215
f3 = 0.5f0 * (f_ll[3] + f_rr[3]) - 0.5f0 * λ_max * (q2_rr - q2_ll)
216
f4 = 0.5f0 * (f_ll[4] + f_rr[4])
217
else # y-direction
218
f2 = 0.5f0 * (f_ll[2] + f_rr[2])
219
f3 = 0.5f0 * (f_ll[3] + f_rr[3])
220
f4 = 0.5f0 * (f_ll[4] + f_rr[4]) - 0.5f0 * λ_max * (q3_rr - q3_ll)
221
end
222
223
return SVector(f1, f2, f3, f4)
224
end
225
226
@inline have_constant_speed(::HyperbolicDiffusionEquations3D) = True()
227
228
@inline function max_abs_speeds(eq::HyperbolicDiffusionEquations3D)
229
λ = sqrt(eq.nu * eq.inv_Tr)
230
return λ, λ, λ
231
end
232
233
# Convert conservative variables to primitive
234
@inline cons2prim(u, equations::HyperbolicDiffusionEquations3D) = u
235
236
# Convert conservative variables to entropy found in I Do Like CFD, Too, Vol. 1
237
@inline function cons2entropy(u, equations::HyperbolicDiffusionEquations3D)
238
phi, q1, q2, q3 = u
239
w1 = phi
240
w2 = equations.Lr^2 * q1
241
w3 = equations.Lr^2 * q2
242
w4 = equations.Lr^2 * q3
243
244
return SVector(w1, w2, w3, w4)
245
end
246
247
# Calculate entropy for a conservative state `u` (here: same as total energy)
248
@inline function entropy(u, equations::HyperbolicDiffusionEquations3D)
249
energy_total(u, equations)
250
end
251
252
# Calculate total energy for a conservative state `u`
253
@inline function energy_total(u, equations::HyperbolicDiffusionEquations3D)
254
# energy function as found in equation (2.5.12) in the book "I Do Like CFD, Vol. 1"
255
phi, q1, q2, q3 = u
256
return 0.5f0 * (phi^2 + equations.Lr^2 * (q1^2 + q2^2 + q3^2))
257
end
258
end # @muladd
259
260