Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/equations/acoustic_perturbation_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
AcousticPerturbationEquations2D(v_mean_global, c_mean_global, rho_mean_global)
10
11
Acoustic perturbation equations (APE) in two space dimensions. The equations are given by
12
```math
13
\begin{aligned}
14
\frac{\partial\mathbf{v'}}{\partial t} + \nabla (\bar{\mathbf{v}}\cdot\mathbf{v'})
15
+ \nabla\left( \frac{\bar{c}^2 \tilde{p}'}{\bar{\rho}} \right) &= 0 \\
16
\frac{\partial \tilde{p}'}{\partial t} +
17
\nabla\cdot (\bar{\rho} \mathbf{v'} + \bar{\mathbf{v}} \tilde{p}') &= 0.
18
\end{aligned}
19
```
20
The bar ``\bar{(\cdot)}`` indicates time-averaged quantities. The unknowns of the APE are the
21
perturbed velocities ``\mathbf{v'} = (v_1', v_2')^T`` and the scaled perturbed pressure
22
``\tilde{p}' = \frac{p'}{\bar{c}^2}``, where ``p'`` denotes the perturbed pressure and the
23
perturbed variables are defined by ``\phi' = \phi - \bar{\phi}``.
24
25
In addition to the unknowns, Trixi.jl currently stores the mean values in the state vector,
26
i.e. the state vector used internally is given by
27
```math
28
\mathbf{u} =
29
\begin{pmatrix}
30
v_1' \\ v_2' \\ \tilde{p}' \\ \bar{v}_1 \\ \bar{v}_2 \\ \bar{c} \\ \bar{\rho}
31
\end{pmatrix}.
32
```
33
This affects the implementation and use of these equations in various ways:
34
* The flux values corresponding to the mean values must be zero.
35
* The mean values have to be considered when defining initial conditions, boundary conditions or
36
source terms.
37
* [`AnalysisCallback`](@ref) analyzes these variables too.
38
* Trixi.jl's visualization tools will visualize the mean values by default.
39
40
The constructor accepts a 2-tuple `v_mean_global` and scalars `c_mean_global` and `rho_mean_global`
41
which can be used to make the definition of initial conditions for problems with constant mean flow
42
more flexible. These values are ignored if the mean values are defined internally in an initial
43
condition.
44
45
The equations are based on the APE-4 system introduced in the following paper:
46
- Roland Ewert and Wolfgang Schröder (2003)
47
Acoustic perturbation equations based on flow decomposition via source filtering
48
[DOI: 10.1016/S0021-9991(03)00168-2](https://doi.org/10.1016/S0021-9991(03)00168-2)
49
"""
50
struct AcousticPerturbationEquations2D{RealT <: Real} <:
51
AbstractAcousticPerturbationEquations{2, 7}
52
v_mean_global::SVector{2, RealT}
53
c_mean_global::RealT
54
rho_mean_global::RealT
55
end
56
57
function AcousticPerturbationEquations2D(v_mean_global::NTuple{2, <:Real},
58
c_mean_global::Real,
59
rho_mean_global::Real)
60
return AcousticPerturbationEquations2D(SVector(v_mean_global), c_mean_global,
61
rho_mean_global)
62
end
63
64
function AcousticPerturbationEquations2D(; v_mean_global::NTuple{2, <:Real},
65
c_mean_global::Real,
66
rho_mean_global::Real)
67
return AcousticPerturbationEquations2D(SVector(v_mean_global), c_mean_global,
68
rho_mean_global)
69
end
70
71
function varnames(::typeof(cons2cons), ::AcousticPerturbationEquations2D)
72
("v1_prime", "v2_prime", "p_prime_scaled",
73
"v1_mean", "v2_mean", "c_mean", "rho_mean")
74
end
75
function varnames(::typeof(cons2prim), ::AcousticPerturbationEquations2D)
76
("v1_prime", "v2_prime", "p_prime",
77
"v1_mean", "v2_mean", "c_mean", "rho_mean")
78
end
79
80
# Convenience functions for retrieving state variables and mean variables
81
function cons2state(u, equations::AcousticPerturbationEquations2D)
82
return SVector(u[1], u[2], u[3])
83
end
84
85
function cons2mean(u, equations::AcousticPerturbationEquations2D)
86
return SVector(u[4], u[5], u[6], u[7])
87
end
88
89
function varnames(::typeof(cons2state), ::AcousticPerturbationEquations2D)
90
("v1_prime", "v2_prime", "p_prime_scaled")
91
end
92
function varnames(::typeof(cons2mean), ::AcousticPerturbationEquations2D)
93
("v1_mean", "v2_mean", "c_mean", "rho_mean")
94
end
95
96
"""
97
global_mean_vars(equations::AcousticPerturbationEquations2D)
98
99
Returns the global mean variables stored in `equations`. This makes it easier
100
to define flexible initial conditions for problems with constant mean flow.
101
"""
102
function global_mean_vars(equations::AcousticPerturbationEquations2D)
103
return equations.v_mean_global[1], equations.v_mean_global[2],
104
equations.c_mean_global,
105
equations.rho_mean_global
106
end
107
108
"""
109
initial_condition_constant(x, t, equations::AcousticPerturbationEquations2D)
110
111
A constant initial condition where the state variables are zero and the mean flow is constant.
112
Uses the global mean values from `equations`.
113
"""
114
function initial_condition_constant(x, t, equations::AcousticPerturbationEquations2D)
115
v1_prime = 0
116
v2_prime = 0
117
p_prime_scaled = 0
118
119
return SVector(v1_prime, v2_prime, p_prime_scaled, global_mean_vars(equations)...)
120
end
121
122
"""
123
initial_condition_convergence_test(x, t, equations::AcousticPerturbationEquations2D)
124
125
A smooth initial condition used for convergence tests in combination with
126
[`source_terms_convergence_test`](@ref). Uses the global mean values from `equations`.
127
"""
128
function initial_condition_convergence_test(x, t,
129
equations::AcousticPerturbationEquations2D)
130
RealT = eltype(x)
131
a = 1
132
c = 2
133
L = 2
134
f = 2.0f0 / L
135
A = convert(RealT, 0.2)
136
omega = 2 * convert(RealT, pi) * f
137
init = c + A * sin(omega * (x[1] + x[2] - a * t))
138
139
v1_prime = init
140
v2_prime = init
141
p_prime = init^2
142
143
prim = SVector(v1_prime, v2_prime, p_prime, global_mean_vars(equations)...)
144
145
return prim2cons(prim, equations)
146
end
147
148
"""
149
source_terms_convergence_test(u, x, t, equations::AcousticPerturbationEquations2D)
150
151
Source terms used for convergence tests in combination with
152
[`initial_condition_convergence_test`](@ref).
153
"""
154
function source_terms_convergence_test(u, x, t,
155
equations::AcousticPerturbationEquations2D)
156
v1_mean, v2_mean, c_mean, rho_mean = cons2mean(u, equations)
157
158
RealT = eltype(u)
159
a = 1
160
c = 2
161
L = 2
162
f = 2.0f0 / L
163
A = convert(RealT, 0.2)
164
omega = 2 * convert(RealT, pi) * f
165
166
si, co = sincos(omega * (x[1] + x[2] - a * t))
167
tmp = v1_mean + v2_mean - a
168
169
du1 = du2 = A * omega * co * (2 * c / rho_mean + tmp + 2 / rho_mean * A * si)
170
du3 = A * omega * co * (2 * c_mean^2 * rho_mean + 2 * c * tmp + 2 * A * tmp * si) /
171
c_mean^2
172
173
du4 = du5 = du6 = du7 = 0
174
175
return SVector(du1, du2, du3, du4, du5, du6, du7)
176
end
177
178
"""
179
initial_condition_gauss(x, t, equations::AcousticPerturbationEquations2D)
180
181
A Gaussian pulse in a constant mean flow. Uses the global mean values from `equations`.
182
"""
183
function initial_condition_gauss(x, t, equations::AcousticPerturbationEquations2D)
184
v1_prime = 0
185
v2_prime = 0
186
p_prime = exp(-4 * (x[1]^2 + x[2]^2))
187
188
prim = SVector(v1_prime, v2_prime, p_prime, global_mean_vars(equations)...)
189
190
return prim2cons(prim, equations)
191
end
192
193
"""
194
boundary_condition_wall(u_inner, orientation, direction, x, t, surface_flux_function,
195
equations::AcousticPerturbationEquations2D)
196
197
Boundary conditions for a solid wall.
198
"""
199
function boundary_condition_wall(u_inner, orientation, direction, x, t,
200
surface_flux_function,
201
equations::AcousticPerturbationEquations2D)
202
# Boundary state is equal to the inner state except for the perturbed velocity. For boundaries
203
# in the -x/+x direction, we multiply the perturbed velocity in the x direction by -1.
204
# Similarly, for boundaries in the -y/+y direction, we multiply the perturbed velocity in the
205
# y direction by -1
206
if direction in (1, 2) # x direction
207
u_boundary = SVector(-u_inner[1], u_inner[2], u_inner[3],
208
cons2mean(u_inner, equations)...)
209
else # y direction
210
u_boundary = SVector(u_inner[1], -u_inner[2], u_inner[3],
211
cons2mean(u_inner, equations)...)
212
end
213
214
# Calculate boundary flux
215
if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary
216
flux = surface_flux_function(u_inner, u_boundary, orientation, equations)
217
else # u_boundary is "left" of boundary, u_inner is "right" of boundary
218
flux = surface_flux_function(u_boundary, u_inner, orientation, equations)
219
end
220
221
return flux
222
end
223
224
"""
225
boundary_condition_slip_wall(u_inner, normal_direction, x, t, surface_flux_function,
226
equations::AcousticPerturbationEquations2D)
227
228
Use an orthogonal projection of the perturbed velocities to zero out the normal velocity
229
while retaining the possibility of a tangential velocity in the boundary state.
230
Further details are available in the paper:
231
- Marcus Bauer, Jürgen Dierke and Roland Ewert (2011)
232
Application of a discontinuous Galerkin method to discretize acoustic perturbation equations
233
[DOI: 10.2514/1.J050333](https://doi.org/10.2514/1.J050333)
234
"""
235
function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t,
236
surface_flux_function,
237
equations::AcousticPerturbationEquations2D)
238
# normalize the outward pointing direction
239
normal = normal_direction / norm(normal_direction)
240
241
# compute the normal perturbed velocity
242
u_normal = normal[1] * u_inner[1] + normal[2] * u_inner[2]
243
244
# create the "external" boundary solution state
245
u_boundary = SVector(u_inner[1] - 2 * u_normal * normal[1],
246
u_inner[2] - 2 * u_normal * normal[2],
247
u_inner[3], cons2mean(u_inner, equations)...)
248
249
# calculate the boundary flux
250
flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations)
251
252
return flux
253
end
254
255
# Calculate 1D flux for a single point
256
@inline function flux(u, orientation::Integer,
257
equations::AcousticPerturbationEquations2D)
258
v1_prime, v2_prime, p_prime_scaled = cons2state(u, equations)
259
v1_mean, v2_mean, c_mean, rho_mean = cons2mean(u, equations)
260
261
# Calculate flux for conservative state variables
262
RealT = eltype(u)
263
if orientation == 1
264
f1 = v1_mean * v1_prime + v2_mean * v2_prime +
265
c_mean^2 * p_prime_scaled / rho_mean
266
f2 = zero(RealT)
267
f3 = rho_mean * v1_prime + v1_mean * p_prime_scaled
268
else
269
f1 = zero(RealT)
270
f2 = v1_mean * v1_prime + v2_mean * v2_prime +
271
c_mean^2 * p_prime_scaled / rho_mean
272
f3 = rho_mean * v2_prime + v2_mean * p_prime_scaled
273
end
274
275
# The rest of the state variables are actually variable coefficients, hence the flux should be
276
# zero. See https://github.com/trixi-framework/Trixi.jl/issues/358#issuecomment-784828762
277
# for details.
278
f4 = f5 = f6 = f7 = 0
279
280
return SVector(f1, f2, f3, f4, f5, f6, f7)
281
end
282
283
# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation
284
@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,
285
equations::AcousticPerturbationEquations2D)
286
# Calculate v = v_prime + v_mean
287
v_prime_ll = u_ll[orientation]
288
v_prime_rr = u_rr[orientation]
289
v_mean_ll = u_ll[orientation + 3]
290
v_mean_rr = u_rr[orientation + 3]
291
292
v_ll = v_prime_ll + v_mean_ll
293
v_rr = v_prime_rr + v_mean_rr
294
295
c_mean_ll = u_ll[6]
296
c_mean_rr = u_rr[6]
297
298
return max(abs(v_ll), abs(v_rr)) + max(c_mean_ll, c_mean_rr)
299
end
300
301
# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`
302
@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,
303
equations::AcousticPerturbationEquations2D)
304
# Calculate v = v_prime + v_mean
305
v_prime_ll = u_ll[orientation]
306
v_prime_rr = u_rr[orientation]
307
v_mean_ll = u_ll[orientation + 3]
308
v_mean_rr = u_rr[orientation + 3]
309
310
v_ll = v_prime_ll + v_mean_ll
311
v_rr = v_prime_rr + v_mean_rr
312
313
c_mean_ll = u_ll[6]
314
c_mean_rr = u_rr[6]
315
316
return max(abs(v_ll) + c_mean_ll, abs(v_rr) + c_mean_rr)
317
end
318
319
# Calculate 1D flux for a single point in the normal direction
320
# Note, this directional vector is not normalized
321
@inline function flux(u, normal_direction::AbstractVector,
322
equations::AcousticPerturbationEquations2D)
323
v1_prime, v2_prime, p_prime_scaled = cons2state(u, equations)
324
v1_mean, v2_mean, c_mean, rho_mean = cons2mean(u, equations)
325
326
f1 = normal_direction[1] * (v1_mean * v1_prime + v2_mean * v2_prime +
327
c_mean^2 * p_prime_scaled / rho_mean)
328
f2 = normal_direction[2] * (v1_mean * v1_prime + v2_mean * v2_prime +
329
c_mean^2 * p_prime_scaled / rho_mean)
330
f3 = (normal_direction[1] * (rho_mean * v1_prime + v1_mean * p_prime_scaled)
331
+
332
normal_direction[2] * (rho_mean * v2_prime + v2_mean * p_prime_scaled))
333
334
# The rest of the state variables are actually variable coefficients, hence the flux should be
335
# zero. See https://github.com/trixi-framework/Trixi.jl/issues/358#issuecomment-784828762
336
# for details.
337
f4 = f5 = f6 = f7 = 0
338
339
return SVector(f1, f2, f3, f4, f5, f6, f7)
340
end
341
342
# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation
343
@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,
344
equations::AcousticPerturbationEquations2D)
345
# Calculate v = v_prime + v_mean
346
v_prime_ll = normal_direction[1] * u_ll[1] + normal_direction[2] * u_ll[2]
347
v_prime_rr = normal_direction[1] * u_rr[1] + normal_direction[2] * u_rr[2]
348
v_mean_ll = normal_direction[1] * u_ll[4] + normal_direction[2] * u_ll[5]
349
v_mean_rr = normal_direction[1] * u_rr[4] + normal_direction[2] * u_rr[5]
350
351
v_ll = v_prime_ll + v_mean_ll
352
v_rr = v_prime_rr + v_mean_rr
353
354
c_mean_ll = u_ll[6]
355
c_mean_rr = u_rr[6]
356
357
# The v_normals are already scaled by the norm
358
return (max(abs(v_ll), abs(v_rr)) +
359
max(c_mean_ll, c_mean_rr) * norm(normal_direction))
360
end
361
362
# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`
363
@inline function max_abs_speed(u_ll, u_rr, normal_direction::AbstractVector,
364
equations::AcousticPerturbationEquations2D)
365
# Calculate v = v_prime + v_mean
366
v_prime_ll = normal_direction[1] * u_ll[1] + normal_direction[2] * u_ll[2]
367
v_prime_rr = normal_direction[1] * u_rr[1] + normal_direction[2] * u_rr[2]
368
v_mean_ll = normal_direction[1] * u_ll[4] + normal_direction[2] * u_ll[5]
369
v_mean_rr = normal_direction[1] * u_rr[4] + normal_direction[2] * u_rr[5]
370
371
v_ll = v_prime_ll + v_mean_ll
372
v_rr = v_prime_rr + v_mean_rr
373
374
c_mean_ll = u_ll[6]
375
c_mean_rr = u_rr[6]
376
377
norm_ = norm(normal_direction)
378
# The v_normals are already scaled by the norm
379
return max(abs(v_ll) + c_mean_ll * norm_, abs(v_rr) + c_mean_rr * norm_)
380
end
381
382
# Specialized `DissipationLocalLaxFriedrichs` to avoid spurious dissipation in the mean values
383
@inline function (dissipation::DissipationLocalLaxFriedrichs)(u_ll, u_rr,
384
orientation_or_normal_direction,
385
equations::AcousticPerturbationEquations2D)
386
λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction,
387
equations)
388
diss = -0.5f0 * λ * (u_rr - u_ll)
389
z = 0
390
391
return SVector(diss[1], diss[2], diss[3], z, z, z, z)
392
end
393
394
@inline have_constant_speed(::AcousticPerturbationEquations2D) = False()
395
396
@inline function max_abs_speeds(u, equations::AcousticPerturbationEquations2D)
397
v1_mean = u[4]
398
v2_mean = u[5]
399
c_mean = u[6]
400
401
return abs(v1_mean) + c_mean, abs(v2_mean) + c_mean
402
end
403
404
# Convert conservative variables to primitive
405
@inline function cons2prim(u, equations::AcousticPerturbationEquations2D)
406
p_prime_scaled = u[3]
407
c_mean = u[6]
408
p_prime = p_prime_scaled * c_mean^2
409
410
return SVector(u[1], u[2], p_prime, u[4], u[5], u[6], u[7])
411
end
412
413
# Convert primitive variables to conservative
414
@inline function prim2cons(u, equations::AcousticPerturbationEquations2D)
415
p_prime = u[3]
416
c_mean = u[6]
417
p_prime_scaled = p_prime / c_mean^2
418
419
return SVector(u[1], u[2], p_prime_scaled, u[4], u[5], u[6], u[7])
420
end
421
422
# Convert conservative variables to entropy variables
423
@inline cons2entropy(u, equations::AcousticPerturbationEquations2D) = u
424
end # @muladd
425
426