Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/equations/compressible_euler_1d.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
CompressibleEulerEquations1D(gamma)
10
11
The compressible Euler equations
12
```math
13
\frac{\partial}{\partial t}
14
\begin{pmatrix}
15
\rho \\ \rho v_1 \\ \rho e
16
\end{pmatrix}
17
+
18
\frac{\partial}{\partial x}
19
\begin{pmatrix}
20
\rho v_1 \\ \rho v_1^2 + p \\ (\rho e +p) v_1
21
\end{pmatrix}
22
=
23
\begin{pmatrix}
24
0 \\ 0 \\ 0
25
\end{pmatrix}
26
```
27
for an ideal gas with ratio of specific heats `gamma` in one space dimension.
28
Here, ``\rho`` is the density, ``v_1`` the velocity, ``e`` the specific total energy **rather than** specific internal energy, and
29
```math
30
p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho v_1^2 \right)
31
```
32
the pressure.
33
"""
34
struct CompressibleEulerEquations1D{RealT <: Real} <:
35
AbstractCompressibleEulerEquations{1, 3}
36
gamma::RealT # ratio of specific heats
37
inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications
38
39
function CompressibleEulerEquations1D(gamma)
40
γ, inv_gamma_minus_one = promote(gamma, inv(gamma - 1))
41
new{typeof(γ)}(γ, inv_gamma_minus_one)
42
end
43
end
44
45
function varnames(::typeof(cons2cons), ::CompressibleEulerEquations1D)
46
("rho", "rho_v1", "rho_e")
47
end
48
varnames(::typeof(cons2prim), ::CompressibleEulerEquations1D) = ("rho", "v1", "p")
49
50
"""
51
initial_condition_constant(x, t, equations::CompressibleEulerEquations1D)
52
53
A constant initial condition to test free-stream preservation.
54
"""
55
function initial_condition_constant(x, t, equations::CompressibleEulerEquations1D)
56
RealT = eltype(x)
57
rho = 1
58
rho_v1 = convert(RealT, 0.1)
59
rho_e = 10
60
return SVector(rho, rho_v1, rho_e)
61
end
62
63
"""
64
initial_condition_convergence_test(x, t, equations::CompressibleEulerEquations1D)
65
66
A smooth initial condition used for convergence tests in combination with
67
[`source_terms_convergence_test`](@ref)
68
(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains).
69
"""
70
function initial_condition_convergence_test(x, t,
71
equations::CompressibleEulerEquations1D)
72
RealT = eltype(x)
73
c = 2
74
A = convert(RealT, 0.1)
75
L = 2
76
f = 1.0f0 / L
77
ω = 2 * convert(RealT, pi) * f
78
ini = c + A * sin(ω * (x[1] - t))
79
80
rho = ini
81
rho_v1 = ini
82
rho_e = ini^2
83
84
return SVector(rho, rho_v1, rho_e)
85
end
86
87
"""
88
source_terms_convergence_test(u, x, t, equations::CompressibleEulerEquations1D)
89
90
Source terms used for convergence tests in combination with
91
[`initial_condition_convergence_test`](@ref)
92
(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains).
93
"""
94
@inline function source_terms_convergence_test(u, x, t,
95
equations::CompressibleEulerEquations1D)
96
# Same settings as in `initial_condition`
97
RealT = eltype(u)
98
c = 2
99
A = convert(RealT, 0.1)
100
L = 2
101
f = 1.0f0 / L
102
ω = 2 * convert(RealT, pi) * f
103
γ = equations.gamma
104
105
x1, = x
106
107
si, co = sincos(ω * (x1 - t))
108
rho = c + A * si
109
rho_x = ω * A * co
110
111
# Note that d/dt rho = -d/dx rho.
112
# This yields du2 = du3 = d/dx p (derivative of pressure).
113
# Other terms vanish because of v = 1.
114
du1 = 0
115
du2 = rho_x * (2 * rho - 0.5f0) * (γ - 1)
116
du3 = du2
117
118
return SVector(du1, du2, du3)
119
end
120
121
"""
122
initial_condition_density_wave(x, t, equations::CompressibleEulerEquations1D)
123
124
A sine wave in the density with constant velocity and pressure; reduces the
125
compressible Euler equations to the linear advection equations.
126
This setup is the test case for stability of EC fluxes from paper
127
- Gregor J. Gassner, Magnus Svärd, Florian J. Hindenlang (2020)
128
Stability issues of entropy-stable and/or split-form high-order schemes
129
[arXiv: 2007.09026](https://arxiv.org/abs/2007.09026)
130
with the following parameters
131
- domain [-1, 1]
132
- mesh = 4x4
133
- polydeg = 5
134
"""
135
function initial_condition_density_wave(x, t, equations::CompressibleEulerEquations1D)
136
RealT = eltype(x)
137
v1 = convert(RealT, 0.1)
138
rho = 1 + convert(RealT, 0.98) * sinpi(2 * (x[1] - t * v1))
139
rho_v1 = rho * v1
140
p = 20
141
rho_e = p / (equations.gamma - 1) + 0.5f0 * rho * v1^2
142
return SVector(rho, rho_v1, rho_e)
143
end
144
145
"""
146
initial_condition_weak_blast_wave(x, t, equations::CompressibleEulerEquations1D)
147
148
A weak blast wave taken from
149
- Sebastian Hennemann, Gregor J. Gassner (2020)
150
A provably entropy stable subcell shock capturing approach for high order split form DG
151
[arXiv: 2008.12044](https://arxiv.org/abs/2008.12044)
152
"""
153
function initial_condition_weak_blast_wave(x, t,
154
equations::CompressibleEulerEquations1D)
155
# From Hennemann & Gassner JCP paper 2020 (Sec. 6.3)
156
# Set up polar coordinates
157
RealT = eltype(x)
158
inicenter = SVector(0)
159
x_norm = x[1] - inicenter[1]
160
r = abs(x_norm)
161
# The following code is equivalent to
162
# phi = atan(0.0, x_norm)
163
# cos_phi = cos(phi)
164
# in 1D but faster
165
cos_phi = x_norm > 0 ? 1 : -1
166
167
# Calculate primitive variables
168
rho = r > 0.5f0 ? one(RealT) : convert(RealT, 1.1691)
169
v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos_phi
170
p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245)
171
172
return prim2cons(SVector(rho, v1, p), equations)
173
end
174
175
"""
176
initial_condition_eoc_test_coupled_euler_gravity(x, t, equations::CompressibleEulerEquations1D)
177
178
One dimensional variant of the setup used for convergence tests of the Euler equations
179
with self-gravity from
180
- Michael Schlottke-Lakemper, Andrew R. Winters, Hendrik Ranocha, Gregor J. Gassner (2020)
181
A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics
182
[arXiv: 2008.10593](https://arxiv.org/abs/2008.10593)
183
!!! note
184
There is no additional source term necessary for the manufactured solution in one
185
spatial dimension. Thus, [`source_terms_eoc_test_coupled_euler_gravity`](@ref) is not
186
present there.
187
"""
188
function initial_condition_eoc_test_coupled_euler_gravity(x, t,
189
equations::CompressibleEulerEquations1D)
190
# OBS! this assumes that γ = 2 other manufactured source terms are incorrect
191
if equations.gamma != 2
192
error("adiabatic constant must be 2 for the coupling convergence test")
193
end
194
RealT = eltype(x)
195
c = 2
196
A = convert(RealT, 0.1)
197
ini = c + A * sinpi(x[1] - t)
198
G = 1 # gravitational constant
199
200
rho = ini
201
v1 = 1
202
p = 2 * ini^2 * G / convert(RealT, pi) # * 2 / ndims, but ndims==1 here
203
204
return prim2cons(SVector(rho, v1, p), equations)
205
end
206
207
"""
208
boundary_condition_slip_wall(u_inner, orientation, direction, x, t,
209
surface_flux_function, equations::CompressibleEulerEquations1D)
210
Determine the boundary numerical surface flux for a slip wall condition.
211
Imposes a zero normal velocity at the wall.
212
Density is taken from the internal solution state and pressure is computed as an
213
exact solution of a 1D Riemann problem. Further details about this boundary state
214
are available in the paper:
215
- J. J. W. van der Vegt and H. van der Ven (2002)
216
Slip flow boundary conditions in discontinuous Galerkin discretizations of
217
the Euler equations of gas dynamics
218
[PDF](https://reports.nlr.nl/bitstream/handle/10921/692/TP-2002-300.pdf?sequence=1)
219
220
Should be used together with [`TreeMesh`](@ref).
221
"""
222
@inline function boundary_condition_slip_wall(u_inner, orientation,
223
direction, x, t,
224
surface_flux_function,
225
equations::CompressibleEulerEquations1D)
226
# compute the primitive variables
227
rho_local, v_normal, p_local = cons2prim(u_inner, equations)
228
229
if isodd(direction) # flip sign of normal to make it outward pointing
230
v_normal *= -1
231
end
232
233
# Get the solution of the pressure Riemann problem
234
# See Section 6.3.3 of
235
# Eleuterio F. Toro (2009)
236
# Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction
237
# [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761)
238
if v_normal <= 0
239
sound_speed = sqrt(equations.gamma * p_local / rho_local) # local sound speed
240
p_star = p_local *
241
(1 + 0.5f0 * (equations.gamma - 1) * v_normal / sound_speed)^(2 *
242
equations.gamma *
243
equations.inv_gamma_minus_one)
244
else # v_normal > 0
245
A = 2 / ((equations.gamma + 1) * rho_local)
246
B = p_local * (equations.gamma - 1) / (equations.gamma + 1)
247
p_star = p_local +
248
0.5f0 * v_normal / A *
249
(v_normal + sqrt(v_normal^2 + 4 * A * (p_local + B)))
250
end
251
252
# For the slip wall we directly set the flux as the normal velocity is zero
253
return SVector(0, p_star, 0)
254
end
255
256
# Calculate 1D flux for a single point
257
@inline function flux(u, orientation::Integer, equations::CompressibleEulerEquations1D)
258
rho, rho_v1, rho_e = u
259
v1 = rho_v1 / rho
260
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho_v1 * v1)
261
# Ignore orientation since it is always "1" in 1D
262
f1 = rho_v1
263
f2 = rho_v1 * v1 + p
264
f3 = (rho_e + p) * v1
265
return SVector(f1, f2, f3)
266
end
267
268
"""
269
flux_shima_etal(u_ll, u_rr, orientation, equations::CompressibleEulerEquations1D)
270
271
This flux is is a modification of the original kinetic energy preserving two-point flux by
272
- Yuichi Kuya, Kosuke Totani and Soshi Kawai (2018)
273
Kinetic energy and entropy preserving schemes for compressible flows
274
by split convective forms
275
[DOI: 10.1016/j.jcp.2018.08.058](https://doi.org/10.1016/j.jcp.2018.08.058)
276
277
The modification is in the energy flux to guarantee pressure equilibrium and was developed by
278
- Nao Shima, Yuichi Kuya, Yoshiharu Tamaki, Soshi Kawai (JCP 2020)
279
Preventing spurious pressure oscillations in split convective form discretizations for
280
compressible flows
281
[DOI: 10.1016/j.jcp.2020.110060](https://doi.org/10.1016/j.jcp.2020.110060)
282
"""
283
@inline function flux_shima_etal(u_ll, u_rr, orientation::Integer,
284
equations::CompressibleEulerEquations1D)
285
# Unpack left and right state
286
rho_ll, v1_ll, p_ll = cons2prim(u_ll, equations)
287
rho_rr, v1_rr, p_rr = cons2prim(u_rr, equations)
288
289
# Average each factor of products in flux
290
rho_avg = 0.5f0 * (rho_ll + rho_rr)
291
v1_avg = 0.5f0 * (v1_ll + v1_rr)
292
p_avg = 0.5f0 * (p_ll + p_rr)
293
kin_avg = 0.5f0 * (v1_ll * v1_rr)
294
295
# Calculate fluxes
296
# Ignore orientation since it is always "1" in 1D
297
pv1_avg = 0.5f0 * (p_ll * v1_rr + p_rr * v1_ll)
298
f1 = rho_avg * v1_avg
299
f2 = f1 * v1_avg + p_avg
300
f3 = p_avg * v1_avg * equations.inv_gamma_minus_one + f1 * kin_avg + pv1_avg
301
302
return SVector(f1, f2, f3)
303
end
304
305
"""
306
flux_kennedy_gruber(u_ll, u_rr, orientation, equations::CompressibleEulerEquations1D)
307
308
Kinetic energy preserving two-point flux by
309
- Kennedy and Gruber (2008)
310
Reduced aliasing formulations of the convective terms within the
311
Navier-Stokes equations for a compressible fluid
312
[DOI: 10.1016/j.jcp.2007.09.020](https://doi.org/10.1016/j.jcp.2007.09.020)
313
"""
314
@inline function flux_kennedy_gruber(u_ll, u_rr, orientation::Integer,
315
equations::CompressibleEulerEquations1D)
316
# Unpack left and right state
317
rho_e_ll = last(u_ll)
318
rho_e_rr = last(u_rr)
319
rho_ll, v1_ll, p_ll = cons2prim(u_ll, equations)
320
rho_rr, v1_rr, p_rr = cons2prim(u_rr, equations)
321
322
# Average each factor of products in flux
323
rho_avg = 0.5f0 * (rho_ll + rho_rr)
324
v1_avg = 0.5f0 * (v1_ll + v1_rr)
325
p_avg = 0.5f0 * (p_ll + p_rr)
326
e_avg = 0.5f0 * (rho_e_ll / rho_ll + rho_e_rr / rho_rr)
327
328
# Ignore orientation since it is always "1" in 1D
329
f1 = rho_avg * v1_avg
330
f2 = rho_avg * v1_avg * v1_avg + p_avg
331
f3 = (rho_avg * e_avg + p_avg) * v1_avg
332
333
return SVector(f1, f2, f3)
334
end
335
336
"""
337
flux_chandrashekar(u_ll, u_rr, orientation, equations::CompressibleEulerEquations1D)
338
339
Entropy conserving two-point flux by
340
- Chandrashekar (2013)
341
Kinetic Energy Preserving and Entropy Stable Finite Volume Schemes
342
for Compressible Euler and Navier-Stokes Equations
343
[DOI: 10.4208/cicp.170712.010313a](https://doi.org/10.4208/cicp.170712.010313a)
344
"""
345
@inline function flux_chandrashekar(u_ll, u_rr, orientation::Integer,
346
equations::CompressibleEulerEquations1D)
347
# Unpack left and right state
348
rho_ll, v1_ll, p_ll = cons2prim(u_ll, equations)
349
rho_rr, v1_rr, p_rr = cons2prim(u_rr, equations)
350
beta_ll = 0.5f0 * rho_ll / p_ll
351
beta_rr = 0.5f0 * rho_rr / p_rr
352
specific_kin_ll = 0.5f0 * (v1_ll^2)
353
specific_kin_rr = 0.5f0 * (v1_rr^2)
354
355
# Compute the necessary mean values
356
rho_avg = 0.5f0 * (rho_ll + rho_rr)
357
rho_mean = ln_mean(rho_ll, rho_rr)
358
beta_mean = ln_mean(beta_ll, beta_rr)
359
beta_avg = 0.5f0 * (beta_ll + beta_rr)
360
v1_avg = 0.5f0 * (v1_ll + v1_rr)
361
p_mean = 0.5f0 * rho_avg / beta_avg
362
velocity_square_avg = specific_kin_ll + specific_kin_rr
363
364
# Calculate fluxes
365
# Ignore orientation since it is always "1" in 1D
366
f1 = rho_mean * v1_avg
367
f2 = f1 * v1_avg + p_mean
368
f3 = f1 * 0.5f0 * (1 / (equations.gamma - 1) / beta_mean - velocity_square_avg) +
369
f2 * v1_avg
370
371
return SVector(f1, f2, f3)
372
end
373
374
"""
375
flux_ranocha(u_ll, u_rr, orientation_or_normal_direction, equations::CompressibleEulerEquations1D)
376
377
Entropy conserving and kinetic energy preserving two-point flux by
378
- Hendrik Ranocha (2018)
379
Generalised Summation-by-Parts Operators and Entropy Stability of Numerical Methods
380
for Hyperbolic Balance Laws
381
[PhD thesis, TU Braunschweig](https://cuvillier.de/en/shop/publications/7743)
382
See also
383
- Hendrik Ranocha (2020)
384
Entropy Conserving and Kinetic Energy Preserving Numerical Methods for
385
the Euler Equations Using Summation-by-Parts Operators
386
[Proceedings of ICOSAHOM 2018](https://doi.org/10.1007/978-3-030-39647-3_42)
387
"""
388
@inline function flux_ranocha(u_ll, u_rr, orientation::Integer,
389
equations::CompressibleEulerEquations1D)
390
# Unpack left and right state
391
rho_ll, v1_ll, p_ll = cons2prim(u_ll, equations)
392
rho_rr, v1_rr, p_rr = cons2prim(u_rr, equations)
393
394
# Compute the necessary mean values
395
rho_mean = ln_mean(rho_ll, rho_rr)
396
# Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)`
397
# in exact arithmetic since
398
# log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ)
399
# = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ)
400
inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)
401
v1_avg = 0.5f0 * (v1_ll + v1_rr)
402
p_avg = 0.5f0 * (p_ll + p_rr)
403
velocity_square_avg = 0.5f0 * (v1_ll * v1_rr)
404
405
# Calculate fluxes
406
# Ignore orientation since it is always "1" in 1D
407
f1 = rho_mean * v1_avg
408
f2 = f1 * v1_avg + p_avg
409
f3 = f1 * (velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one) +
410
0.5f0 * (p_ll * v1_rr + p_rr * v1_ll)
411
412
return SVector(f1, f2, f3)
413
end
414
415
# While `normal_direction` isn't strictly necessary in 1D, certain solvers assume that
416
# the normal component is incorporated into the numerical flux.
417
#
418
# See `flux(u, normal_direction::AbstractVector, equations::AbstractEquations{1})` for a
419
# similar implementation.
420
@inline function flux_ranocha(u_ll, u_rr, normal_direction::AbstractVector,
421
equations::CompressibleEulerEquations1D)
422
return normal_direction[1] * flux_ranocha(u_ll, u_rr, 1, equations)
423
end
424
425
"""
426
splitting_steger_warming(u, orientation::Integer,
427
equations::CompressibleEulerEquations1D)
428
splitting_steger_warming(u, which::Union{Val{:minus}, Val{:plus}}
429
orientation::Integer,
430
equations::CompressibleEulerEquations1D)
431
432
Splitting of the compressible Euler flux of Steger and Warming.
433
434
Returns a tuple of the fluxes "minus" (associated with waves going into the
435
negative axis direction) and "plus" (associated with waves going into the
436
positive axis direction). If only one of the fluxes is required, use the
437
function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`.
438
439
!!! warning "Experimental implementation (upwind SBP)"
440
This is an experimental feature and may change in future releases.
441
442
## References
443
444
- Joseph L. Steger and R. F. Warming (1979)
445
Flux Vector Splitting of the Inviscid Gasdynamic Equations
446
With Application to Finite Difference Methods
447
[NASA Technical Memorandum](https://ntrs.nasa.gov/api/citations/19790020779/downloads/19790020779.pdf)
448
"""
449
@inline function splitting_steger_warming(u, orientation::Integer,
450
equations::CompressibleEulerEquations1D)
451
fm = splitting_steger_warming(u, Val{:minus}(), orientation, equations)
452
fp = splitting_steger_warming(u, Val{:plus}(), orientation, equations)
453
return fm, fp
454
end
455
456
@inline function splitting_steger_warming(u, ::Val{:plus}, orientation::Integer,
457
equations::CompressibleEulerEquations1D)
458
rho, rho_v1, rho_e = u
459
v1 = rho_v1 / rho
460
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho_v1 * v1)
461
a = sqrt(equations.gamma * p / rho)
462
463
lambda1 = v1
464
lambda2 = v1 + a
465
lambda3 = v1 - a
466
467
lambda1_p = positive_part(lambda1) # Same as (lambda_i + abs(lambda_i)) / 2, but faster :)
468
lambda2_p = positive_part(lambda2)
469
lambda3_p = positive_part(lambda3)
470
471
alpha_p = 2 * (equations.gamma - 1) * lambda1_p + lambda2_p + lambda3_p
472
473
rho_2gamma = 0.5f0 * rho / equations.gamma
474
f1p = rho_2gamma * alpha_p
475
f2p = rho_2gamma * (alpha_p * v1 + a * (lambda2_p - lambda3_p))
476
f3p = rho_2gamma * (alpha_p * 0.5f0 * v1^2 + a * v1 * (lambda2_p - lambda3_p)
477
+ a^2 * (lambda2_p + lambda3_p) * equations.inv_gamma_minus_one)
478
479
return SVector(f1p, f2p, f3p)
480
end
481
482
@inline function splitting_steger_warming(u, ::Val{:minus}, orientation::Integer,
483
equations::CompressibleEulerEquations1D)
484
rho, rho_v1, rho_e = u
485
v1 = rho_v1 / rho
486
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho_v1 * v1)
487
a = sqrt(equations.gamma * p / rho)
488
489
lambda1 = v1
490
lambda2 = v1 + a
491
lambda3 = v1 - a
492
493
lambda1_m = negative_part(lambda1) # Same as (lambda_i - abs(lambda_i)) / 2, but faster :)
494
lambda2_m = negative_part(lambda2)
495
lambda3_m = negative_part(lambda3)
496
497
alpha_m = 2 * (equations.gamma - 1) * lambda1_m + lambda2_m + lambda3_m
498
499
rho_2gamma = 0.5f0 * rho / equations.gamma
500
f1m = rho_2gamma * alpha_m
501
f2m = rho_2gamma * (alpha_m * v1 + a * (lambda2_m - lambda3_m))
502
f3m = rho_2gamma * (alpha_m * 0.5f0 * v1^2 + a * v1 * (lambda2_m - lambda3_m)
503
+ a^2 * (lambda2_m + lambda3_m) * equations.inv_gamma_minus_one)
504
505
return SVector(f1m, f2m, f3m)
506
end
507
508
"""
509
splitting_vanleer_haenel(u, orientation::Integer,
510
equations::CompressibleEulerEquations1D)
511
splitting_vanleer_haenel(u, which::Union{Val{:minus}, Val{:plus}}
512
orientation::Integer,
513
equations::CompressibleEulerEquations1D)
514
515
Splitting of the compressible Euler flux from van Leer. This splitting further
516
contains a reformulation due to Hänel et al. where the energy flux uses the
517
enthalpy. The pressure splitting is independent from the splitting of the
518
convective terms. As such there are many pressure splittings suggested across
519
the literature. We implement the 'p4' variant suggested by Liou and Steffen as
520
it proved the most robust in practice.
521
522
Returns a tuple of the fluxes "minus" (associated with waves going into the
523
negative axis direction) and "plus" (associated with waves going into the
524
positive axis direction). If only one of the fluxes is required, use the
525
function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`.
526
527
!!! warning "Experimental implementation (upwind SBP)"
528
This is an experimental feature and may change in future releases.
529
530
## References
531
532
- Bram van Leer (1982)
533
Flux-Vector Splitting for the Euler Equation
534
[DOI: 10.1007/978-3-642-60543-7_5](https://doi.org/10.1007/978-3-642-60543-7_5)
535
- D. Hänel, R. Schwane and G. Seider (1987)
536
On the accuracy of upwind schemes for the solution of the Navier-Stokes equations
537
[DOI: 10.2514/6.1987-1105](https://doi.org/10.2514/6.1987-1105)
538
- Meng-Sing Liou and Chris J. Steffen, Jr. (1991)
539
High-Order Polynomial Expansions (HOPE) for Flux-Vector Splitting
540
[NASA Technical Memorandum](https://ntrs.nasa.gov/citations/19910016425)
541
"""
542
@inline function splitting_vanleer_haenel(u, orientation::Integer,
543
equations::CompressibleEulerEquations1D)
544
fm = splitting_vanleer_haenel(u, Val{:minus}(), orientation, equations)
545
fp = splitting_vanleer_haenel(u, Val{:plus}(), orientation, equations)
546
return fm, fp
547
end
548
549
@inline function splitting_vanleer_haenel(u, ::Val{:plus}, orientation::Integer,
550
equations::CompressibleEulerEquations1D)
551
rho, rho_v1, rho_e = u
552
v1 = rho_v1 / rho
553
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho_v1 * v1)
554
555
# sound speed and enthalpy
556
a = sqrt(equations.gamma * p / rho)
557
H = (rho_e + p) / rho
558
559
# signed Mach number
560
M = v1 / a
561
562
p_plus = 0.5f0 * (1 + equations.gamma * M) * p
563
564
f1p = 0.25f0 * rho * a * (M + 1)^2
565
f2p = f1p * v1 + p_plus
566
f3p = f1p * H
567
568
return SVector(f1p, f2p, f3p)
569
end
570
571
@inline function splitting_vanleer_haenel(u, ::Val{:minus}, orientation::Integer,
572
equations::CompressibleEulerEquations1D)
573
rho, rho_v1, rho_e = u
574
v1 = rho_v1 / rho
575
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho_v1 * v1)
576
577
# sound speed and enthalpy
578
a = sqrt(equations.gamma * p / rho)
579
H = (rho_e + p) / rho
580
581
# signed Mach number
582
M = v1 / a
583
584
p_minus = 0.5f0 * (1 - equations.gamma * M) * p
585
586
f1m = -0.25f0 * rho * a * (M - 1)^2
587
f2m = f1m * v1 + p_minus
588
f3m = f1m * H
589
590
return SVector(f1m, f2m, f3m)
591
end
592
593
# TODO: FD
594
# This splitting is interesting because it can handle the "el diablo" wave
595
# for long time runs. Computing the eigenvalues of the operator we see
596
# J = jacobian_ad_forward(semi);
597
# lamb = eigvals(J);
598
# maximum(real.(lamb))
599
# 2.1411031631522748e-6
600
# So the instability of this splitting is very weak. However, the 2D variant
601
# of this splitting on "el diablo" still crashes early. Can we learn anything
602
# from the design of this splitting?
603
"""
604
splitting_coirier_vanleer(u, orientation::Integer,
605
equations::CompressibleEulerEquations1D)
606
splitting_coirier_vanleer(u, which::Union{Val{:minus}, Val{:plus}}
607
orientation::Integer,
608
equations::CompressibleEulerEquations1D)
609
610
Splitting of the compressible Euler flux from Coirier and van Leer.
611
The splitting has correction terms in the pressure splitting as well as
612
the mass and energy flux components. The motivation for these corrections
613
are to handle flows at the low Mach number limit.
614
615
Returns a tuple of the fluxes "minus" (associated with waves going into the
616
negative axis direction) and "plus" (associated with waves going into the
617
positive axis direction). If only one of the fluxes is required, use the
618
function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`.
619
620
!!! warning "Experimental implementation (upwind SBP)"
621
This is an experimental feature and may change in future releases.
622
623
## References
624
625
- William Coirier and Bram van Leer (1991)
626
Numerical flux formulas for the Euler and Navier-Stokes equations.
627
II - Progress in flux-vector splitting
628
[DOI: 10.2514/6.1991-1566](https://doi.org/10.2514/6.1991-1566)
629
"""
630
@inline function splitting_coirier_vanleer(u, orientation::Integer,
631
equations::CompressibleEulerEquations1D)
632
fm = splitting_coirier_vanleer(u, Val{:minus}(), orientation, equations)
633
fp = splitting_coirier_vanleer(u, Val{:plus}(), orientation, equations)
634
return fm, fp
635
end
636
637
@inline function splitting_coirier_vanleer(u, ::Val{:plus}, orientation::Integer,
638
equations::CompressibleEulerEquations1D)
639
rho, rho_v1, rho_e = u
640
v1 = rho_v1 / rho
641
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho_v1 * v1)
642
643
# sound speed and enthalpy
644
a = sqrt(equations.gamma * p / rho)
645
H = (rho_e + p) / rho
646
647
# signed Mach number
648
M = v1 / a
649
650
P = 2
651
mu = 1
652
nu = 0.75f0
653
omega = 2 # adjusted from suggested value of 1.5
654
655
p_plus = 0.25f0 * ((M + 1)^2 * (2 - M) - nu * M * (M^2 - 1)^P) * p
656
657
f1p = 0.25f0 * rho * a * ((M + 1)^2 - mu * (M^2 - 1)^P)
658
f2p = f1p * v1 + p_plus
659
f3p = f1p * H - omega * rho * a^3 * M^2 * (M^2 - 1)^2
660
661
return SVector(f1p, f2p, f3p)
662
end
663
664
@inline function splitting_coirier_vanleer(u, ::Val{:minus}, orientation::Integer,
665
equations::CompressibleEulerEquations1D)
666
rho, rho_v1, rho_e = u
667
v1 = rho_v1 / rho
668
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho_v1 * v1)
669
670
# sound speed and enthalpy
671
a = sqrt(equations.gamma * p / rho)
672
H = (rho_e + p) / rho
673
674
# signed Mach number
675
M = v1 / a
676
677
P = 2
678
mu = 1
679
nu = 0.75f0
680
omega = 2 # adjusted from suggested value of 1.5
681
682
p_minus = 0.25f0 * ((M - 1)^2 * (2 + M) + nu * M * (M^2 - 1)^P) * p
683
684
f1m = -0.25f0 * rho * a * ((M - 1)^2 - mu * (M^2 - 1)^P)
685
f2m = f1m * v1 + p_minus
686
f3m = f1m * H + omega * rho * a^3 * M^2 * (M^2 - 1)^2
687
688
return SVector(f1m, f2m, f3m)
689
end
690
691
# Calculate estimates for maximum wave speed for local Lax-Friedrichs-type dissipation as the
692
# maximum velocity magnitude plus the maximum speed of sound
693
@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,
694
equations::CompressibleEulerEquations1D)
695
rho_ll, rho_v1_ll, rho_e_ll = u_ll
696
rho_rr, rho_v1_rr, rho_e_rr = u_rr
697
698
# Calculate primitive variables and speed of sound
699
v1_ll = rho_v1_ll / rho_ll
700
v_mag_ll = abs(v1_ll)
701
p_ll = (equations.gamma - 1) * (rho_e_ll - 0.5f0 * rho_ll * v_mag_ll^2)
702
c_ll = sqrt(equations.gamma * p_ll / rho_ll)
703
v1_rr = rho_v1_rr / rho_rr
704
v_mag_rr = abs(v1_rr)
705
p_rr = (equations.gamma - 1) * (rho_e_rr - 0.5f0 * rho_rr * v_mag_rr^2)
706
c_rr = sqrt(equations.gamma * p_rr / rho_rr)
707
708
return max(v_mag_ll, v_mag_rr) + max(c_ll, c_rr)
709
end
710
711
@inline function (dissipation::DissipationMatrixWintersEtal)(u_ll, u_rr,
712
normal_direction::AbstractVector,
713
equations::CompressibleEulerEquations1D)
714
gamma = equations.gamma
715
716
norm_ = norm(normal_direction)
717
unit_normal_direction = normal_direction / norm_
718
719
rho_ll, v1_ll, p_ll = cons2prim(u_ll, equations)
720
rho_rr, v1_rr, p_rr = cons2prim(u_rr, equations)
721
722
b_ll = rho_ll / (2 * p_ll)
723
b_rr = rho_rr / (2 * p_rr)
724
725
rho_log = ln_mean(rho_ll, rho_rr)
726
b_log = ln_mean(b_ll, b_rr)
727
v1_avg = 0.5f0 * (v1_ll + v1_rr)
728
p_avg = 0.5f0 * (rho_ll + rho_rr) / (b_ll + b_rr) # 2 * b_avg = b_ll + b_rr
729
v1_squared_bar = v1_ll * v1_rr
730
h_bar = gamma / (2 * b_log * (gamma - 1)) + 0.5f0 * v1_squared_bar
731
c_bar = sqrt(gamma * p_avg / rho_log)
732
733
v1_minus_c = v1_avg - c_bar * unit_normal_direction[1]
734
v1_plus_c = v1_avg + c_bar * unit_normal_direction[1]
735
v_avg_normal = v1_avg * unit_normal_direction[1]
736
737
entropy_vars_jump = cons2entropy(u_rr, equations) - cons2entropy(u_ll, equations)
738
739
lambda_1 = abs(v_avg_normal - c_bar) * rho_log / (2 * gamma)
740
lambda_2 = abs(v_avg_normal) * rho_log * (gamma - 1) / gamma
741
lambda_3 = abs(v_avg_normal + c_bar) * rho_log / (2 * gamma)
742
lambda_4 = abs(v_avg_normal) * p_avg
743
744
entropy_var_rho_jump, entropy_var_rho_v1_jump, entropy_var_rho_e_jump = entropy_vars_jump
745
746
w1 = lambda_1 * (entropy_var_rho_jump + v1_minus_c * entropy_var_rho_v1_jump +
747
(h_bar - c_bar * v_avg_normal) * entropy_var_rho_e_jump)
748
w2 = lambda_2 * (entropy_var_rho_jump + v1_avg * entropy_var_rho_v1_jump +
749
v1_squared_bar / 2 * entropy_var_rho_e_jump)
750
w3 = lambda_3 * (entropy_var_rho_jump + v1_plus_c * entropy_var_rho_v1_jump +
751
(h_bar + c_bar * v_avg_normal) * entropy_var_rho_e_jump)
752
753
dissipation_rho = w1 + w2 + w3
754
755
dissipation_rho_v1 = (w1 * v1_minus_c +
756
w2 * v1_avg +
757
w3 * v1_plus_c)
758
759
dissipation_rhoe = (w1 * (h_bar - c_bar * v_avg_normal) +
760
w2 * 0.5f0 * v1_squared_bar +
761
w3 * (h_bar + c_bar * v_avg_normal) +
762
lambda_4 *
763
(entropy_var_rho_e_jump * (v1_avg * v1_avg - v_avg_normal^2)))
764
765
return -0.5f0 * SVector(dissipation_rho, dissipation_rho_v1, dissipation_rhoe) *
766
norm_
767
end
768
769
# Calculate estimates for minimum and maximum wave speeds for HLL-type fluxes
770
@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer,
771
equations::CompressibleEulerEquations1D)
772
rho_ll, v1_ll, p_ll = cons2prim(u_ll, equations)
773
rho_rr, v1_rr, p_rr = cons2prim(u_rr, equations)
774
775
λ_min = v1_ll - sqrt(equations.gamma * p_ll / rho_ll)
776
λ_max = v1_rr + sqrt(equations.gamma * p_rr / rho_rr)
777
778
return λ_min, λ_max
779
end
780
781
# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`
782
@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,
783
equations::CompressibleEulerEquations1D)
784
rho_ll, rho_v1_ll, rho_e_ll = u_ll
785
rho_rr, rho_v1_rr, rho_e_rr = u_rr
786
787
# Calculate primitive variables and speed of sound
788
v1_ll = rho_v1_ll / rho_ll
789
v_mag_ll = abs(v1_ll)
790
p_ll = (equations.gamma - 1) * (rho_e_ll - 0.5f0 * rho_ll * v_mag_ll^2)
791
c_ll = sqrt(equations.gamma * p_ll / rho_ll)
792
v1_rr = rho_v1_rr / rho_rr
793
v_mag_rr = abs(v1_rr)
794
p_rr = (equations.gamma - 1) * (rho_e_rr - 0.5f0 * rho_rr * v_mag_rr^2)
795
c_rr = sqrt(equations.gamma * p_rr / rho_rr)
796
797
return max(v_mag_ll + c_ll, v_mag_rr + c_rr)
798
end
799
800
# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes
801
@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer,
802
equations::CompressibleEulerEquations1D)
803
rho_ll, v1_ll, p_ll = cons2prim(u_ll, equations)
804
rho_rr, v1_rr, p_rr = cons2prim(u_rr, equations)
805
806
c_ll = sqrt(equations.gamma * p_ll / rho_ll)
807
c_rr = sqrt(equations.gamma * p_rr / rho_rr)
808
809
λ_min = min(v1_ll - c_ll, v1_rr - c_rr)
810
λ_max = max(v1_ll + c_ll, v1_rr + c_rr)
811
812
return λ_min, λ_max
813
end
814
815
"""
816
flux_hllc(u_ll, u_rr, orientation, equations::CompressibleEulerEquations1D)
817
818
Computes the HLLC flux (HLL with Contact) for compressible Euler equations developed by E.F. Toro
819
[Lecture slides](http://www.prague-sum.com/download/2012/Toro_2-HLLC-RiemannSolver.pdf)
820
Signal speeds: [DOI: 10.1137/S1064827593260140](https://doi.org/10.1137/S1064827593260140)
821
"""
822
function flux_hllc(u_ll, u_rr, orientation::Integer,
823
equations::CompressibleEulerEquations1D)
824
# Calculate primitive variables and speed of sound
825
rho_ll, rho_v1_ll, rho_e_ll = u_ll
826
rho_rr, rho_v1_rr, rho_e_rr = u_rr
827
828
v1_ll = rho_v1_ll / rho_ll
829
e_ll = rho_e_ll / rho_ll
830
p_ll = (equations.gamma - 1) * (rho_e_ll - 0.5f0 * rho_ll * v1_ll^2)
831
c_ll = sqrt(equations.gamma * p_ll / rho_ll)
832
833
v1_rr = rho_v1_rr / rho_rr
834
e_rr = rho_e_rr / rho_rr
835
p_rr = (equations.gamma - 1) * (rho_e_rr - 0.5f0 * rho_rr * v1_rr^2)
836
c_rr = sqrt(equations.gamma * p_rr / rho_rr)
837
838
# Obtain left and right fluxes
839
f_ll = flux(u_ll, orientation, equations)
840
f_rr = flux(u_rr, orientation, equations)
841
842
# Compute Roe averages
843
sqrt_rho_ll = sqrt(rho_ll)
844
sqrt_rho_rr = sqrt(rho_rr)
845
sum_sqrt_rho = sqrt_rho_ll + sqrt_rho_rr
846
vel_L = v1_ll
847
vel_R = v1_rr
848
vel_roe = (sqrt_rho_ll * vel_L + sqrt_rho_rr * vel_R) / sum_sqrt_rho
849
ekin_roe = 0.5f0 * vel_roe^2
850
H_ll = (rho_e_ll + p_ll) / rho_ll
851
H_rr = (rho_e_rr + p_rr) / rho_rr
852
H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) / sum_sqrt_rho
853
c_roe = sqrt((equations.gamma - 1) * (H_roe - ekin_roe))
854
855
Ssl = min(vel_L - c_ll, vel_roe - c_roe)
856
Ssr = max(vel_R + c_rr, vel_roe + c_roe)
857
sMu_L = Ssl - vel_L
858
sMu_R = Ssr - vel_R
859
if Ssl >= 0
860
f1 = f_ll[1]
861
f2 = f_ll[2]
862
f3 = f_ll[3]
863
elseif Ssr <= 0
864
f1 = f_rr[1]
865
f2 = f_rr[2]
866
f3 = f_rr[3]
867
else
868
SStar = (p_rr - p_ll + rho_ll * vel_L * sMu_L - rho_rr * vel_R * sMu_R) /
869
(rho_ll * sMu_L - rho_rr * sMu_R)
870
if Ssl <= 0 <= SStar
871
densStar = rho_ll * sMu_L / (Ssl - SStar)
872
enerStar = e_ll + (SStar - vel_L) * (SStar + p_ll / (rho_ll * sMu_L))
873
UStar1 = densStar
874
UStar2 = densStar * SStar
875
UStar3 = densStar * enerStar
876
877
f1 = f_ll[1] + Ssl * (UStar1 - rho_ll)
878
f2 = f_ll[2] + Ssl * (UStar2 - rho_v1_ll)
879
f3 = f_ll[3] + Ssl * (UStar3 - rho_e_ll)
880
else
881
densStar = rho_rr * sMu_R / (Ssr - SStar)
882
enerStar = e_rr + (SStar - vel_R) * (SStar + p_rr / (rho_rr * sMu_R))
883
UStar1 = densStar
884
UStar2 = densStar * SStar
885
UStar3 = densStar * enerStar
886
887
#end
888
f1 = f_rr[1] + Ssr * (UStar1 - rho_rr)
889
f2 = f_rr[2] + Ssr * (UStar2 - rho_v1_rr)
890
f3 = f_rr[3] + Ssr * (UStar3 - rho_e_rr)
891
end
892
end
893
return SVector(f1, f2, f3)
894
end
895
896
# While `normal_direction` isn't strictly necessary in 1D, certain solvers assume that
897
# the normal component is incorporated into the numerical flux.
898
#
899
# The HLLC flux along a 1D "normal" can be evaluated by scaling the velocity/momentum by
900
# the normal for the 1D HLLC flux, then scaling the resulting momentum flux again.
901
# Moreover, the 2D HLLC flux reduces to this if the normal vector is [n, 0].
902
function flux_hllc(u_ll, u_rr, normal_direction::AbstractVector,
903
equations::CompressibleEulerEquations1D)
904
norm_ = abs(normal_direction[1])
905
normal_direction_unit = normal_direction[1] * inv(norm_)
906
907
# scale the momentum by the normal direction
908
f = flux_hllc(SVector(u_ll[1], normal_direction_unit * u_ll[2], u_ll[3]),
909
SVector(u_rr[1], normal_direction_unit * u_rr[2], u_rr[3]), 1,
910
equations)
911
912
# rescale the momentum flux by the normal direction and normalize
913
return SVector(f[1], normal_direction_unit * f[2], f[3]) * norm_
914
end
915
916
"""
917
min_max_speed_einfeldt(u_ll, u_rr, orientation, equations::CompressibleEulerEquations1D)
918
919
Computes the HLLE (Harten-Lax-van Leer-Einfeldt) flux for the compressible Euler equations.
920
Special estimates of the signal velocites and linearization of the Riemann problem developed
921
by Einfeldt to ensure that the internal energy and density remain positive during the computation
922
of the numerical flux.
923
924
Original publication:
925
- Bernd Einfeldt (1988)
926
On Godunov-type methods for gas dynamics.
927
[DOI: 10.1137/0725021](https://doi.org/10.1137/0725021)
928
929
Compactly summarized:
930
- Siddhartha Mishra, Ulrik Skre Fjordholm and Rémi Abgrall
931
Numerical methods for conservation laws and related equations.
932
[Link](https://metaphor.ethz.ch/x/2019/hs/401-4671-00L/literature/mishra_hyperbolic_pdes.pdf)
933
"""
934
@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer,
935
equations::CompressibleEulerEquations1D)
936
# Calculate primitive variables, enthalpy and speed of sound
937
rho_ll, v_ll, p_ll = cons2prim(u_ll, equations)
938
rho_rr, v_rr, p_rr = cons2prim(u_rr, equations)
939
940
# `u_ll[3]` is total energy `rho_e_ll` on the left
941
H_ll = (u_ll[3] + p_ll) / rho_ll
942
c_ll = sqrt(equations.gamma * p_ll / rho_ll)
943
944
# `u_rr[3]` is total energy `rho_e_rr` on the right
945
H_rr = (u_rr[3] + p_rr) / rho_rr
946
c_rr = sqrt(equations.gamma * p_rr / rho_rr)
947
948
# Compute Roe averages
949
sqrt_rho_ll = sqrt(rho_ll)
950
sqrt_rho_rr = sqrt(rho_rr)
951
inv_sum_sqrt_rho = inv(sqrt_rho_ll + sqrt_rho_rr)
952
953
v_roe = (sqrt_rho_ll * v_ll + sqrt_rho_rr * v_rr) * inv_sum_sqrt_rho
954
v_roe_mag = v_roe^2
955
956
H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) * inv_sum_sqrt_rho
957
c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5f0 * v_roe_mag))
958
959
# Compute convenience constant for positivity preservation, see
960
# https://doi.org/10.1016/0021-9991(91)90211-3
961
beta = sqrt(0.5f0 * (equations.gamma - 1) / equations.gamma)
962
963
# Estimate the edges of the Riemann fan (with positivity conservation)
964
SsL = min(v_roe - c_roe, v_ll - beta * c_ll, 0)
965
SsR = max(v_roe + c_roe, v_rr + beta * c_rr, 0)
966
967
return SsL, SsR
968
end
969
970
@inline function max_abs_speeds(u, equations::CompressibleEulerEquations1D)
971
rho, rho_v1, rho_e = u
972
v1 = rho_v1 / rho
973
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho * v1^2)
974
c = sqrt(equations.gamma * p / rho)
975
976
return (abs(v1) + c,)
977
end
978
979
# Convert conservative variables to primitive
980
@inline function cons2prim(u, equations::CompressibleEulerEquations1D)
981
rho, rho_v1, rho_e = u
982
983
v1 = rho_v1 / rho
984
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho_v1 * v1)
985
986
return SVector(rho, v1, p)
987
end
988
989
# Convert conservative variables to entropy
990
@inline function cons2entropy(u, equations::CompressibleEulerEquations1D)
991
rho, rho_v1, rho_e = u
992
993
v1 = rho_v1 / rho
994
v_square = v1^2
995
p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho * v_square)
996
s = log(p) - equations.gamma * log(rho)
997
rho_p = rho / p
998
999
w1 = (equations.gamma - s) * equations.inv_gamma_minus_one -
1000
0.5f0 * rho_p * v_square
1001
w2 = rho_p * v1
1002
w3 = -rho_p
1003
1004
return SVector(w1, w2, w3)
1005
end
1006
1007
@inline function entropy2cons(w, equations::CompressibleEulerEquations1D)
1008
# See Hughes, Franca, Mallet (1986) A new finite element formulation for CFD
1009
# [DOI: 10.1016/0045-7825(86)90127-1](https://doi.org/10.1016/0045-7825(86)90127-1)
1010
@unpack gamma = equations
1011
1012
# convert to entropy `-rho * s` used by Hughes, France, Mallet (1986)
1013
# instead of `-rho * s / (gamma - 1)`
1014
V1, V2, V5 = w .* (gamma - 1)
1015
1016
# specific entropy, eq. (53)
1017
s = gamma - V1 + 0.5f0 * (V2^2) / V5
1018
1019
# eq. (52)
1020
energy_internal = ((gamma - 1) / (-V5)^gamma)^(equations.inv_gamma_minus_one) *
1021
exp(-s * equations.inv_gamma_minus_one)
1022
1023
# eq. (51)
1024
rho = -V5 * energy_internal
1025
rho_v1 = V2 * energy_internal
1026
rho_e = (1 - 0.5f0 * (V2^2) / V5) * energy_internal
1027
return SVector(rho, rho_v1, rho_e)
1028
end
1029
1030
# Convert primitive to conservative variables
1031
@inline function prim2cons(prim, equations::CompressibleEulerEquations1D)
1032
rho, v1, p = prim
1033
rho_v1 = rho * v1
1034
rho_e = p * equations.inv_gamma_minus_one + 0.5f0 * (rho_v1 * v1)
1035
return SVector(rho, rho_v1, rho_e)
1036
end
1037
1038
@inline function density(u, equations::CompressibleEulerEquations1D)
1039
rho = u[1]
1040
return rho
1041
end
1042
1043
@inline function velocity(u, orientation_or_normal,
1044
equations::CompressibleEulerEquations1D)
1045
return velocity(u, equations)
1046
end
1047
1048
@inline function velocity(u, equations::CompressibleEulerEquations1D)
1049
rho = u[1]
1050
v1 = u[2] / rho
1051
return v1
1052
end
1053
1054
@inline function pressure(u, equations::CompressibleEulerEquations1D)
1055
rho, rho_v1, rho_e = u
1056
p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1^2) / rho)
1057
return p
1058
end
1059
1060
@inline function density_pressure(u, equations::CompressibleEulerEquations1D)
1061
rho, rho_v1, rho_e = u
1062
rho_times_p = (equations.gamma - 1) * (rho * rho_e - 0.5f0 * (rho_v1^2))
1063
return rho_times_p
1064
end
1065
1066
# Calculate thermodynamic entropy for a conservative state `cons`
1067
@inline function entropy_thermodynamic(cons, equations::CompressibleEulerEquations1D)
1068
# Pressure
1069
p = (equations.gamma - 1) * (cons[3] - 0.5f0 * (cons[2]^2) / cons[1])
1070
1071
# Thermodynamic entropy
1072
s = log(p) - equations.gamma * log(cons[1])
1073
1074
return s
1075
end
1076
1077
# Calculate mathematical entropy for a conservative state `cons`
1078
@inline function entropy_math(cons, equations::CompressibleEulerEquations1D)
1079
# Mathematical entropy
1080
S = -entropy_thermodynamic(cons, equations) * cons[1] *
1081
equations.inv_gamma_minus_one
1082
1083
return S
1084
end
1085
1086
# Default entropy is the mathematical entropy
1087
@inline function entropy(cons, equations::CompressibleEulerEquations1D)
1088
entropy_math(cons, equations)
1089
end
1090
1091
# Calculate total energy for a conservative state `cons`
1092
@inline energy_total(cons, ::CompressibleEulerEquations1D) = cons[3]
1093
1094
# Calculate kinetic energy for a conservative state `cons`
1095
@inline function energy_kinetic(cons, equations::CompressibleEulerEquations1D)
1096
return 0.5f0 * (cons[2]^2) / cons[1]
1097
end
1098
1099
# Calculate internal energy for a conservative state `cons`
1100
@inline function energy_internal(cons, equations::CompressibleEulerEquations1D)
1101
return energy_total(cons, equations) - energy_kinetic(cons, equations)
1102
end
1103
end # @muladd
1104
1105