Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/equations/linearized_euler_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
LinearizedEulerEquations3D(v_mean_global, c_mean_global, rho_mean_global)
10
11
Linearized Euler equations in three space dimensions. The equations are given by
12
```math
13
\partial_t
14
\begin{pmatrix}
15
\rho' \\ v_1' \\ v_2' \\ v_3' \\ p'
16
\end{pmatrix}
17
+
18
\partial_x
19
\begin{pmatrix}
20
\bar{\rho} v_1' + \bar{v_1} \rho ' \\
21
\bar{v_1} v_1' + \frac{p'}{\bar{\rho}} \\
22
\bar{v_1} v_2' \\
23
\bar{v_1} v_3' \\
24
\bar{v_1} p' + c^2 \bar{\rho} v_1'
25
\end{pmatrix}
26
+
27
\partial_y
28
\begin{pmatrix}
29
\bar{\rho} v_2' + \bar{v_2} \rho ' \\
30
\bar{v_2} v_1' \\
31
\bar{v_2} v_2' + \frac{p'}{\bar{\rho}} \\
32
\bar{v_2} v_3' \\
33
\bar{v_2} p' + c^2 \bar{\rho} v_2'
34
\end{pmatrix}
35
+
36
\partial_z
37
\begin{pmatrix}
38
\bar{\rho} v_3' + \bar{v_3} \rho ' \\
39
\bar{v_3} v_1' \\
40
\bar{v_3} v_2' \\
41
\bar{v_3} v_3' + \frac{p'}{\bar{\rho}} \\
42
\bar{v_3} p' + c^2 \bar{\rho} v_3'
43
\end{pmatrix}
44
=
45
\begin{pmatrix}
46
0 \\ 0 \\ 0 \\ 0 \\ 0
47
\end{pmatrix}
48
```
49
The bar ``\bar{(\cdot)}`` indicates uniform mean flow variables and ``c`` is the speed of sound.
50
The unknowns are the acoustic velocities ``v' = (v_1', v_2, v_3')``, the pressure ``p'`` and the density ``\rho'``.
51
"""
52
struct LinearizedEulerEquations3D{RealT <: Real} <:
53
AbstractLinearizedEulerEquations{3, 5}
54
v_mean_global::SVector{3, RealT}
55
c_mean_global::RealT
56
rho_mean_global::RealT
57
end
58
59
function LinearizedEulerEquations3D(v_mean_global::NTuple{3, <:Real},
60
c_mean_global::Real, rho_mean_global::Real)
61
if rho_mean_global < 0
62
throw(ArgumentError("rho_mean_global must be non-negative"))
63
elseif c_mean_global < 0
64
throw(ArgumentError("c_mean_global must be non-negative"))
65
end
66
67
return LinearizedEulerEquations3D(SVector(v_mean_global), c_mean_global,
68
rho_mean_global)
69
end
70
71
function LinearizedEulerEquations3D(; v_mean_global::NTuple{3, <:Real},
72
c_mean_global::Real, rho_mean_global::Real)
73
return LinearizedEulerEquations3D(v_mean_global, c_mean_global,
74
rho_mean_global)
75
end
76
77
function varnames(::typeof(cons2cons), ::LinearizedEulerEquations3D)
78
("rho_prime", "v1_prime", "v2_prime", "v3_prime", "p_prime")
79
end
80
function varnames(::typeof(cons2prim), ::LinearizedEulerEquations3D)
81
("rho_prime", "v1_prime", "v2_prime", "v3_prime", "p_prime")
82
end
83
84
"""
85
initial_condition_convergence_test(x, t, equations::LinearizedEulerEquations3D)
86
87
A smooth initial condition used for convergence tests.
88
"""
89
function initial_condition_convergence_test(x, t, equations::LinearizedEulerEquations3D)
90
rho_prime = -cospi(2 * t) * (sinpi(2 * x[1]) + sinpi(2 * x[2]) + sinpi(2 * x[3]))
91
v1_prime = sinpi(2 * t) * cospi(2 * x[1])
92
v2_prime = sinpi(2 * t) * cospi(2 * x[2])
93
v3_prime = sinpi(2 * t) * cospi(2 * x[3])
94
p_prime = rho_prime
95
96
return SVector(rho_prime, v1_prime, v2_prime, v3_prime, p_prime)
97
end
98
99
"""
100
boundary_condition_wall(u_inner, orientation, direction, x, t, surface_flux_function,
101
equations::LinearizedEulerEquations3D)
102
103
Boundary conditions for a solid wall.
104
"""
105
function boundary_condition_wall(u_inner, orientation, direction, x, t,
106
surface_flux_function,
107
equations::LinearizedEulerEquations3D)
108
# Boundary state is equal to the inner state except for the velocity. For boundaries
109
# in the -x/+x direction, we multiply the velocity in the x direction by -1.
110
# Similarly, for boundaries in the -y/+y or -z/+z direction, we multiply the
111
# velocity in the y or z direction by -1
112
if direction in (1, 2) # x direction
113
u_boundary = SVector(u_inner[1], -u_inner[2], u_inner[3], u_inner[4],
114
u_inner[5])
115
elseif direction in (3, 4) # y direction
116
u_boundary = SVector(u_inner[1], u_inner[2], -u_inner[3], u_inner[4],
117
u_inner[5])
118
else # z direction = (5, 6)
119
u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], -u_inner[4],
120
u_inner[5])
121
end
122
123
# Calculate boundary flux depending on the orientation of the boundary
124
# Odd directions are in negative coordinate direction,
125
# even directions are in positive coordinate direction.
126
if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary
127
flux = surface_flux_function(u_inner, u_boundary, orientation, equations)
128
else # u_boundary is "left" of boundary, u_inner is "right" of boundary
129
flux = surface_flux_function(u_boundary, u_inner, orientation, equations)
130
end
131
132
return flux
133
end
134
135
# Calculate 1D flux for a single point
136
@inline function flux(u, orientation::Integer, equations::LinearizedEulerEquations3D)
137
@unpack v_mean_global, c_mean_global, rho_mean_global = equations
138
rho_prime, v1_prime, v2_prime, v3_prime, p_prime = u
139
if orientation == 1
140
f1 = v_mean_global[1] * rho_prime + rho_mean_global * v1_prime
141
f2 = v_mean_global[1] * v1_prime + p_prime / rho_mean_global
142
f3 = v_mean_global[1] * v2_prime
143
f4 = v_mean_global[1] * v3_prime
144
f5 = v_mean_global[1] * p_prime + c_mean_global^2 * rho_mean_global * v1_prime
145
elseif orientation == 2
146
f1 = v_mean_global[2] * rho_prime + rho_mean_global * v2_prime
147
f2 = v_mean_global[2] * v1_prime
148
f3 = v_mean_global[2] * v2_prime + p_prime / rho_mean_global
149
f4 = v_mean_global[2] * v3_prime
150
f5 = v_mean_global[2] * p_prime + c_mean_global^2 * rho_mean_global * v2_prime
151
else # orientation == 3
152
f1 = v_mean_global[3] * rho_prime + rho_mean_global * v3_prime
153
f2 = v_mean_global[3] * v1_prime
154
f3 = v_mean_global[3] * v2_prime
155
f4 = v_mean_global[3] * v3_prime + p_prime / rho_mean_global
156
f5 = v_mean_global[3] * p_prime + c_mean_global^2 * rho_mean_global * v3_prime
157
end
158
159
return SVector(f1, f2, f3, f4, f5)
160
end
161
162
# Calculate 1D flux for a single point
163
@inline function flux(u, normal_direction::AbstractVector,
164
equations::LinearizedEulerEquations3D)
165
@unpack v_mean_global, c_mean_global, rho_mean_global = equations
166
rho_prime, v1_prime, v2_prime, v3_prime, p_prime = u
167
168
v_mean_normal = v_mean_global[1] * normal_direction[1] +
169
v_mean_global[2] * normal_direction[2] +
170
v_mean_global[3] * normal_direction[3]
171
v_prime_normal = v1_prime * normal_direction[1] + v2_prime * normal_direction[2] +
172
v3_prime * normal_direction[3]
173
174
f1 = v_mean_normal * rho_prime + rho_mean_global * v_prime_normal
175
f2 = v_mean_normal * v1_prime + normal_direction[1] * p_prime / rho_mean_global
176
f3 = v_mean_normal * v2_prime + normal_direction[2] * p_prime / rho_mean_global
177
f4 = v_mean_normal * v3_prime + normal_direction[3] * p_prime / rho_mean_global
178
f5 = v_mean_normal * p_prime + c_mean_global^2 * rho_mean_global * v_prime_normal
179
180
return SVector(f1, f2, f3, f4, f5)
181
end
182
183
@inline have_constant_speed(::LinearizedEulerEquations3D) = True()
184
185
@inline function max_abs_speeds(equations::LinearizedEulerEquations3D)
186
@unpack v_mean_global, c_mean_global = equations
187
return abs(v_mean_global[1]) + c_mean_global, abs(v_mean_global[2]) + c_mean_global,
188
abs(v_mean_global[3]) + c_mean_global
189
end
190
191
@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,
192
equations::LinearizedEulerEquations3D)
193
@unpack v_mean_global, c_mean_global = equations
194
if orientation == 1
195
return abs(v_mean_global[1]) + c_mean_global
196
elseif orientation == 2
197
return abs(v_mean_global[2]) + c_mean_global
198
else # orientation == 3
199
return abs(v_mean_global[3]) + c_mean_global
200
end
201
end
202
203
@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,
204
equations::LinearizedEulerEquations3D)
205
@unpack v_mean_global, c_mean_global = equations
206
v_mean_normal = normal_direction[1] * v_mean_global[1] +
207
normal_direction[2] * v_mean_global[2] +
208
normal_direction[3] * v_mean_global[3]
209
return abs(v_mean_normal) + c_mean_global * norm(normal_direction)
210
end
211
212
# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes
213
@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer,
214
equations::LinearizedEulerEquations3D)
215
min_max_speed_davis(u_ll, u_rr, orientation, equations)
216
end
217
218
@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,
219
equations::LinearizedEulerEquations3D)
220
min_max_speed_davis(u_ll, u_rr, normal_direction, equations)
221
end
222
223
# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes
224
@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer,
225
equations::LinearizedEulerEquations3D)
226
@unpack v_mean_global, c_mean_global = equations
227
228
λ_min = v_mean_global[orientation] - c_mean_global
229
λ_max = v_mean_global[orientation] + c_mean_global
230
231
return λ_min, λ_max
232
end
233
234
@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector,
235
equations::LinearizedEulerEquations3D)
236
@unpack v_mean_global, c_mean_global = equations
237
238
norm_ = norm(normal_direction)
239
240
v_normal = v_mean_global[1] * normal_direction[1] +
241
v_mean_global[2] * normal_direction[2] +
242
v_mean_global[3] * normal_direction[3]
243
244
# The v_normals are already scaled by the norm
245
λ_min = v_normal - c_mean_global * norm_
246
λ_max = v_normal + c_mean_global * norm_
247
248
return λ_min, λ_max
249
end
250
251
# Convert conservative variables to primitive
252
@inline cons2prim(u, equations::LinearizedEulerEquations3D) = u
253
@inline cons2entropy(u, ::LinearizedEulerEquations3D) = u
254
end # muladd
255
256