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