Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/equations/ideal_glm_mhd_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
IdealGlmMhdEquations1D(gamma)
10
11
The ideal compressible GLM-MHD equations for an ideal gas with ratio of
12
specific heats `gamma` in one space dimension.
13
14
!!! note
15
There is no divergence cleaning variable `psi` because the divergence-free constraint
16
is satisfied trivially in one spatial dimension.
17
"""
18
struct IdealGlmMhdEquations1D{RealT <: Real} <: AbstractIdealGlmMhdEquations{1, 8}
19
gamma::RealT # ratio of specific heats
20
inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications
21
22
function IdealGlmMhdEquations1D(gamma)
23
γ, inv_gamma_minus_one = promote(gamma, inv(gamma - 1))
24
new{typeof(γ)}(γ, inv_gamma_minus_one)
25
end
26
end
27
28
have_nonconservative_terms(::IdealGlmMhdEquations1D) = False()
29
function varnames(::typeof(cons2cons), ::IdealGlmMhdEquations1D)
30
("rho", "rho_v1", "rho_v2", "rho_v3", "rho_e", "B1", "B2", "B3")
31
end
32
function varnames(::typeof(cons2prim), ::IdealGlmMhdEquations1D)
33
("rho", "v1", "v2", "v3", "p", "B1", "B2", "B3")
34
end
35
function default_analysis_integrals(::IdealGlmMhdEquations1D)
36
(entropy_timederivative, Val(:l2_divb), Val(:linf_divb))
37
end
38
39
"""
40
initial_condition_constant(x, t, equations::IdealGlmMhdEquations1D)
41
42
A constant initial condition to test free-stream preservation.
43
"""
44
function initial_condition_constant(x, t, equations::IdealGlmMhdEquations1D)
45
RealT = eltype(x)
46
rho = 1
47
rho_v1 = convert(RealT, 0.1)
48
rho_v2 = -convert(RealT, 0.2)
49
rho_v3 = -0.5f0
50
rho_e = 50
51
B1 = 3
52
B2 = -convert(RealT, 1.2)
53
B3 = 0.5f0
54
return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3)
55
end
56
57
"""
58
initial_condition_convergence_test(x, t, equations::IdealGlmMhdEquations1D)
59
60
An Alfvén wave as smooth initial condition used for convergence tests.
61
See for reference section 4.2 in
62
- Dominik Derigs, Andrew R. Winters, Gregor J. Gassner, and Stefanie Walch (2016)
63
A novel high-order, entropy stable, 3D AMR MHD solver with guaranteed positive pressure
64
[DOI: 10.1016/j.jcp.2016.04.048](https://doi.org/10.1016/j.jcp.2016.04.048)
65
"""
66
function initial_condition_convergence_test(x, t, equations::IdealGlmMhdEquations1D)
67
# smooth Alfvén wave test from Derigs et al. (2016)
68
# domain must be set to [0, 1], γ = 5/3
69
RealT = eltype(x)
70
rho = 1
71
v1 = 0
72
si, co = sincospi(2 * (x[1] + t)) # Adding `t` makes non-integer time valid
73
v2 = convert(RealT, 0.1) * si
74
v3 = convert(RealT, 0.1) * co
75
p = convert(RealT, 0.1)
76
B1 = 1
77
B2 = v2
78
B3 = v3
79
return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3), equations)
80
end
81
82
"""
83
initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdEquations1D)
84
85
A weak blast wave adapted from
86
- Sebastian Hennemann, Gregor J. Gassner (2020)
87
A provably entropy stable subcell shock capturing approach for high order split form DG
88
[arXiv: 2008.12044](https://arxiv.org/abs/2008.12044)
89
"""
90
function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdEquations1D)
91
# Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3)
92
# Same discontinuity in the velocities but with magnetic fields
93
# Set up polar coordinates
94
RealT = eltype(x)
95
inicenter = (0,)
96
x_norm = x[1] - inicenter[1]
97
r = sqrt(x_norm^2)
98
phi = atan(x_norm)
99
100
# Calculate primitive variables
101
rho = r > 0.5f0 ? one(RealT) : convert(RealT, 1.1691)
102
v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(phi)
103
p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245)
104
105
return prim2cons(SVector(rho, v1, 0, 0, p, 1, 1, 1, 0), equations)
106
end
107
108
# Calculate 1D flux for a single point
109
@inline function flux(u, orientation::Integer, equations::IdealGlmMhdEquations1D)
110
rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u
111
v1 = rho_v1 / rho
112
v2 = rho_v2 / rho
113
v3 = rho_v3 / rho
114
kin_en = 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3)
115
mag_en = 0.5f0 * (B1 * B1 + B2 * B2 + B3 * B3)
116
p_over_gamma_minus_one = (rho_e - kin_en - mag_en)
117
p = (equations.gamma - 1) * p_over_gamma_minus_one
118
119
# Ignore orientation since it is always "1" in 1D
120
f1 = rho_v1
121
f2 = rho_v1 * v1 + p + mag_en - B1^2
122
f3 = rho_v1 * v2 - B1 * B2
123
f4 = rho_v1 * v3 - B1 * B3
124
f5 = (kin_en + equations.gamma * p_over_gamma_minus_one + 2 * mag_en) * v1 -
125
B1 * (v1 * B1 + v2 * B2 + v3 * B3)
126
f6 = 0
127
f7 = v1 * B2 - v2 * B1
128
f8 = v1 * B3 - v3 * B1
129
130
return SVector(f1, f2, f3, f4, f5, f6, f7, f8)
131
end
132
133
"""
134
flux_derigs_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D)
135
136
Entropy conserving two-point flux by
137
- Derigs et al. (2018)
138
Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field
139
divergence diminishing ideal magnetohydrodynamics equations
140
[DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002)
141
"""
142
function flux_derigs_etal(u_ll, u_rr, orientation::Integer,
143
equations::IdealGlmMhdEquations1D)
144
# Unpack left and right states to get velocities, pressure, and inverse temperature (called beta)
145
rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll = u_ll
146
rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr = u_rr
147
148
v1_ll = rho_v1_ll / rho_ll
149
v2_ll = rho_v2_ll / rho_ll
150
v3_ll = rho_v3_ll / rho_ll
151
v1_rr = rho_v1_rr / rho_rr
152
v2_rr = rho_v2_rr / rho_rr
153
v3_rr = rho_v3_rr / rho_rr
154
vel_norm_ll = v1_ll^2 + v2_ll^2 + v3_ll^2
155
vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2
156
mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2
157
mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2
158
p_ll = (equations.gamma - 1) *
159
(rho_e_ll - 0.5f0 * rho_ll * vel_norm_ll - 0.5f0 * mag_norm_ll)
160
p_rr = (equations.gamma - 1) *
161
(rho_e_rr - 0.5f0 * rho_rr * vel_norm_rr - 0.5f0 * mag_norm_rr)
162
beta_ll = 0.5f0 * rho_ll / p_ll
163
beta_rr = 0.5f0 * rho_rr / p_rr
164
# for convenience store v⋅B
165
vel_dot_mag_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll
166
vel_dot_mag_rr = v1_rr * B1_rr + v2_rr * B2_rr + v3_rr * B3_rr
167
168
# Compute the necessary mean values needed for either direction
169
rho_avg = 0.5f0 * (rho_ll + rho_rr)
170
rho_mean = ln_mean(rho_ll, rho_rr)
171
beta_mean = ln_mean(beta_ll, beta_rr)
172
beta_avg = 0.5f0 * (beta_ll + beta_rr)
173
v1_avg = 0.5f0 * (v1_ll + v1_rr)
174
v2_avg = 0.5f0 * (v2_ll + v2_rr)
175
v3_avg = 0.5f0 * (v3_ll + v3_rr)
176
p_mean = 0.5f0 * rho_avg / beta_avg
177
B1_avg = 0.5f0 * (B1_ll + B1_rr)
178
B2_avg = 0.5f0 * (B2_ll + B2_rr)
179
B3_avg = 0.5f0 * (B3_ll + B3_rr)
180
vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr)
181
mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr)
182
vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr)
183
184
# Ignore orientation since it is always "1" in 1D
185
f1 = rho_mean * v1_avg
186
f2 = f1 * v1_avg + p_mean + 0.5f0 * mag_norm_avg - B1_avg * B1_avg
187
f3 = f1 * v2_avg - B1_avg * B2_avg
188
f4 = f1 * v3_avg - B1_avg * B3_avg
189
f6 = 0
190
f7 = v1_avg * B2_avg - v2_avg * B1_avg
191
f8 = v1_avg * B3_avg - v3_avg * B1_avg
192
# total energy flux is complicated and involves the previous eight components
193
v1_mag_avg = 0.5f0 * (v1_ll * mag_norm_ll + v1_rr * mag_norm_rr)
194
f5 = (f1 * 0.5f0 * (1 / (equations.gamma - 1) / beta_mean - vel_norm_avg) +
195
f2 * v1_avg + f3 * v2_avg +
196
f4 * v3_avg + f6 * B1_avg + f7 * B2_avg + f8 * B3_avg - 0.5f0 * v1_mag_avg +
197
B1_avg * vel_dot_mag_avg)
198
199
return SVector(f1, f2, f3, f4, f5, f6, f7, f8)
200
end
201
202
"""
203
flux_hindenlang_gassner(u_ll, u_rr, orientation_or_normal_direction,
204
equations::IdealGlmMhdEquations1D)
205
206
Entropy conserving and kinetic energy preserving two-point flux of
207
Hindenlang and Gassner (2019), extending [`flux_ranocha`](@ref) to the MHD equations.
208
209
## References
210
- Florian Hindenlang, Gregor Gassner (2019)
211
A new entropy conservative two-point flux for ideal MHD equations derived from
212
first principles.
213
Presented at HONOM 2019: European workshop on high order numerical methods
214
for evolutionary PDEs, theory and applications
215
- Hendrik Ranocha (2018)
216
Generalised Summation-by-Parts Operators and Entropy Stability of Numerical Methods
217
for Hyperbolic Balance Laws
218
[PhD thesis, TU Braunschweig](https://cuvillier.de/en/shop/publications/7743)
219
- Hendrik Ranocha (2020)
220
Entropy Conserving and Kinetic Energy Preserving Numerical Methods for
221
the Euler Equations Using Summation-by-Parts Operators
222
[Proceedings of ICOSAHOM 2018](https://doi.org/10.1007/978-3-030-39647-3_42)
223
"""
224
@inline function flux_hindenlang_gassner(u_ll, u_rr, orientation::Integer,
225
equations::IdealGlmMhdEquations1D)
226
# Unpack left and right states
227
rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll = cons2prim(u_ll, equations)
228
rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr = cons2prim(u_rr, equations)
229
230
# Compute the necessary mean values needed for either direction
231
rho_mean = ln_mean(rho_ll, rho_rr)
232
# Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)`
233
# in exact arithmetic since
234
# log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ)
235
# = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ)
236
inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)
237
v1_avg = 0.5f0 * (v1_ll + v1_rr)
238
v2_avg = 0.5f0 * (v2_ll + v2_rr)
239
v3_avg = 0.5f0 * (v3_ll + v3_rr)
240
p_avg = 0.5f0 * (p_ll + p_rr)
241
velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr + v3_ll * v3_rr)
242
magnetic_square_avg = 0.5f0 * (B1_ll * B1_rr + B2_ll * B2_rr + B3_ll * B3_rr)
243
244
# Calculate fluxes depending on orientation with specific direction averages
245
f1 = rho_mean * v1_avg
246
f2 = f1 * v1_avg + p_avg + magnetic_square_avg -
247
0.5f0 * (B1_ll * B1_rr + B1_rr * B1_ll)
248
f3 = f1 * v2_avg - 0.5f0 * (B1_ll * B2_rr + B1_rr * B2_ll)
249
f4 = f1 * v3_avg - 0.5f0 * (B1_ll * B3_rr + B1_rr * B3_ll)
250
#f5 below
251
f6 = 0
252
f7 = 0.5f0 * (v1_ll * B2_ll - v2_ll * B1_ll + v1_rr * B2_rr - v2_rr * B1_rr)
253
f8 = 0.5f0 * (v1_ll * B3_ll - v3_ll * B1_ll + v1_rr * B3_rr - v3_rr * B1_rr)
254
# total energy flux is complicated and involves the previous components
255
f5 = (f1 * (velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)
256
+
257
0.5f0 * (+p_ll * v1_rr + p_rr * v1_ll
258
+ (v1_ll * B2_ll * B2_rr + v1_rr * B2_rr * B2_ll)
259
+ (v1_ll * B3_ll * B3_rr + v1_rr * B3_rr * B3_ll)
260
-
261
(v2_ll * B1_ll * B2_rr + v2_rr * B1_rr * B2_ll)
262
-
263
(v3_ll * B1_ll * B3_rr + v3_rr * B1_rr * B3_ll)))
264
265
return SVector(f1, f2, f3, f4, f5, f6, f7, f8)
266
end
267
268
"""
269
flux_hllc(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations1D)
270
271
- Li (2005)
272
An HLLC Riemann solver for magneto-hydrodynamics
273
[DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020).
274
"""
275
function flux_hllc(u_ll, u_rr, orientation::Integer,
276
equations::IdealGlmMhdEquations1D)
277
# Unpack left and right states
278
rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll = cons2prim(u_ll, equations)
279
rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr = cons2prim(u_rr, equations)
280
281
# Total pressure, i.e., thermal + magnetic pressures (eq. (12))
282
p_tot_ll = p_ll + 0.5f0 * (B1_ll^2 + B2_ll^2 + B3_ll^2)
283
p_tot_rr = p_rr + 0.5f0 * (B1_rr^2 + B2_rr^2 + B3_rr^2)
284
285
# Conserved variables
286
rho_v1_ll = u_ll[2]
287
rho_v2_ll = u_ll[3]
288
rho_v3_ll = u_ll[4]
289
290
rho_v1_rr = u_rr[2]
291
rho_v2_rr = u_rr[3]
292
rho_v3_rr = u_rr[4]
293
294
# Obtain left and right fluxes
295
f_ll = flux(u_ll, orientation, equations)
296
f_rr = flux(u_rr, orientation, equations)
297
298
SsL, SsR = min_max_speed_einfeldt(u_ll, u_rr, orientation, equations)
299
sMu_L = SsL - v1_ll
300
sMu_R = SsR - v1_rr
301
if SsL >= 0
302
f1 = f_ll[1]
303
f2 = f_ll[2]
304
f3 = f_ll[3]
305
f4 = f_ll[4]
306
f5 = f_ll[5]
307
f6 = f_ll[6]
308
f7 = f_ll[7]
309
f8 = f_ll[8]
310
elseif SsR <= 0
311
f1 = f_rr[1]
312
f2 = f_rr[2]
313
f3 = f_rr[3]
314
f4 = f_rr[4]
315
f5 = f_rr[5]
316
f6 = f_rr[6]
317
f7 = f_rr[7]
318
f8 = f_rr[8]
319
else
320
# Compute the "HLLC-speed", eq. (14) from paper mentioned above
321
#=
322
SStar = (rho_rr * v1_rr * sMu_R - rho_ll * v1_ll * sMu_L + p_tot_ll - p_tot_rr - B1_ll^2 + B1_rr^2 ) /
323
(rho_rr * sMu_R - rho_ll * sMu_L)
324
=#
325
# Simplification for 1D: B1 is constant
326
SStar = (rho_rr * v1_rr * sMu_R - rho_ll * v1_ll * sMu_L + p_tot_ll - p_tot_rr) /
327
(rho_rr * sMu_R - rho_ll * sMu_L)
328
329
Sdiff = SsR - SsL
330
331
# Compute HLL values for vStar, BStar
332
# These correspond to eq. (28) and (30) from the referenced paper
333
# and the classic HLL intermediate state given by (2)
334
rho_HLL = (SsR * rho_rr - SsL * rho_ll - (f_rr[1] - f_ll[1])) / Sdiff
335
336
v1Star = (SsR * rho_v1_rr - SsL * rho_v1_ll - (f_rr[2] - f_ll[2])) /
337
(Sdiff * rho_HLL)
338
v2Star = (SsR * rho_v2_rr - SsL * rho_v2_ll - (f_rr[3] - f_ll[3])) /
339
(Sdiff * rho_HLL)
340
v3Star = (SsR * rho_v3_rr - SsL * rho_v3_ll - (f_rr[4] - f_ll[4])) /
341
(Sdiff * rho_HLL)
342
343
#B1Star = (SsR * B1_rr - SsL * B1_ll - (f_rr[6] - f_ll[6])) / Sdiff
344
# 1D B1 = constant => B1_ll = B1_rr = B1Star
345
B1Star = B1_ll
346
347
B2Star = (SsR * B2_rr - SsL * B2_ll - (f_rr[7] - f_ll[7])) / Sdiff
348
B3Star = (SsR * B3_rr - SsL * B3_ll - (f_rr[8] - f_ll[8])) / Sdiff
349
if SsL <= SStar
350
SdiffStar = SsL - SStar
351
352
densStar = rho_ll * sMu_L / SdiffStar # (19)
353
354
mom_1_Star = densStar * SStar # (20)
355
mom_2_Star = densStar * v2_ll -
356
(B1Star * B2Star - B1_ll * B2_ll) / SdiffStar # (21)
357
mom_3_Star = densStar * v3_ll -
358
(B1Star * B3Star - B1_ll * B3_ll) / SdiffStar # (22)
359
360
#p_tot_Star = rho_ll * sMu_L * (SStar - v1_ll) + p_tot_ll - B1_ll^2 + B1Star^2 # (17)
361
# 1D B1 = constant => B1_ll = B1_rr = B1Star
362
p_tot_Star = rho_ll * sMu_L * (SStar - v1_ll) + p_tot_ll # (17)
363
364
enerStar = u_ll[5] * sMu_L / SdiffStar +
365
(p_tot_Star * SStar - p_tot_ll * v1_ll - (B1Star *
366
(B1Star * v1Star + B2Star * v2Star + B3Star * v3Star) -
367
B1_ll * (B1_ll * v1_ll + B2_ll * v2_ll + B3_ll * v3_ll))) /
368
SdiffStar # (23)
369
370
# Classic HLLC update (32)
371
f1 = f_ll[1] + SsL * (densStar - u_ll[1])
372
f2 = f_ll[2] + SsL * (mom_1_Star - u_ll[2])
373
f3 = f_ll[3] + SsL * (mom_2_Star - u_ll[3])
374
f4 = f_ll[4] + SsL * (mom_3_Star - u_ll[4])
375
f5 = f_ll[5] + SsL * (enerStar - u_ll[5])
376
f6 = f_ll[6] + SsL * (B1Star - u_ll[6])
377
f7 = f_ll[7] + SsL * (B2Star - u_ll[7])
378
f8 = f_ll[8] + SsL * (B3Star - u_ll[8])
379
else # SStar <= Ssr
380
SdiffStar = SsR - SStar
381
382
densStar = rho_rr * sMu_R / SdiffStar # (19)
383
384
mom_1_Star = densStar * SStar # (20)
385
mom_2_Star = densStar * v2_rr -
386
(B1Star * B2Star - B1_rr * B2_rr) / SdiffStar # (21)
387
mom_3_Star = densStar * v3_rr -
388
(B1Star * B3Star - B1_rr * B3_rr) / SdiffStar # (22)
389
390
#p_tot_Star = rho_rr * sMu_R * (SStar - v1_rr) + p_tot_rr - B1_rr^2 + B1Star^2 # (17)
391
# 1D B1 = constant => B1_ll = B1_rr = B1Star
392
p_tot_Star = rho_rr * sMu_R * (SStar - v1_rr) + p_tot_rr # (17)
393
394
enerStar = u_rr[5] * sMu_R / SdiffStar +
395
(p_tot_Star * SStar - p_tot_rr * v1_rr - (B1Star *
396
(B1Star * v1Star + B2Star * v2Star + B3Star * v3Star) -
397
B1_rr * (B1_rr * v1_rr + B2_rr * v2_rr + B3_rr * v3_rr))) /
398
SdiffStar # (23)
399
400
# Classic HLLC update (32)
401
f1 = f_rr[1] + SsR * (densStar - u_rr[1])
402
f2 = f_rr[2] + SsR * (mom_1_Star - u_rr[2])
403
f3 = f_rr[3] + SsR * (mom_2_Star - u_rr[3])
404
f4 = f_rr[4] + SsR * (mom_3_Star - u_rr[4])
405
f5 = f_rr[5] + SsR * (enerStar - u_rr[5])
406
f6 = f_rr[6] + SsR * (B1Star - u_rr[6])
407
f7 = f_rr[7] + SsR * (B2Star - u_rr[7])
408
f8 = f_rr[8] + SsR * (B3Star - u_rr[8])
409
end
410
end
411
return SVector(f1, f2, f3, f4, f5, f6, f7, f8)
412
end
413
414
# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation
415
@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,
416
equations::IdealGlmMhdEquations1D)
417
rho_ll, rho_v1_ll, _ = u_ll
418
rho_rr, rho_v1_rr, _ = u_rr
419
420
# Calculate velocities (ignore orientation since it is always "1" in 1D)
421
# and fast magnetoacoustic wave speeds
422
# left
423
v_ll = rho_v1_ll / rho_ll
424
cf_ll = calc_fast_wavespeed(u_ll, orientation, equations)
425
# right
426
v_rr = rho_v1_rr / rho_rr
427
cf_rr = calc_fast_wavespeed(u_rr, orientation, equations)
428
429
return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr)
430
end
431
432
# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`
433
@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,
434
equations::IdealGlmMhdEquations1D)
435
rho_ll, rho_v1_ll, _ = u_ll
436
rho_rr, rho_v1_rr, _ = u_rr
437
438
# Calculate velocities (ignore orientation since it is always "1" in 1D)
439
# and fast magnetoacoustic wave speeds
440
# left
441
v_ll = rho_v1_ll / rho_ll
442
cf_ll = calc_fast_wavespeed(u_ll, orientation, equations)
443
# right
444
v_rr = rho_v1_rr / rho_rr
445
cf_rr = calc_fast_wavespeed(u_rr, orientation, equations)
446
447
return max(abs(v_ll) + cf_ll, abs(v_rr) + cf_rr)
448
end
449
450
# Calculate estimates for minimum and maximum wave speeds for HLL-type fluxes
451
@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer,
452
equations::IdealGlmMhdEquations1D)
453
rho_ll, rho_v1_ll, _ = u_ll
454
rho_rr, rho_v1_rr, _ = u_rr
455
456
# Calculate primitive variables
457
v1_ll = rho_v1_ll / rho_ll
458
v1_rr = rho_v1_rr / rho_rr
459
460
λ_min = v1_ll - calc_fast_wavespeed(u_ll, orientation, equations)
461
λ_max = v1_rr + calc_fast_wavespeed(u_rr, orientation, equations)
462
463
return λ_min, λ_max
464
end
465
466
# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes
467
@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer,
468
equations::IdealGlmMhdEquations1D)
469
rho_ll, rho_v1_ll, _ = u_ll
470
rho_rr, rho_v1_rr, _ = u_rr
471
472
# Calculate primitive variables
473
v1_ll = rho_v1_ll / rho_ll
474
v1_rr = rho_v1_rr / rho_rr
475
476
# Approximate the left-most and right-most eigenvalues in the Riemann fan
477
c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)
478
c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)
479
480
λ_min = min(v1_ll - c_f_ll, v1_rr - c_f_rr)
481
λ_max = max(v1_ll + c_f_ll, v1_rr + c_f_rr)
482
483
return λ_min, λ_max
484
end
485
486
"""
487
min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, equations::IdealGlmMhdEquations1D)
488
489
Calculate minimum and maximum wave speeds for HLL-type fluxes as in
490
- Li (2005)
491
An HLLC Riemann solver for magneto-hydrodynamics
492
[DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020).
493
"""
494
@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer,
495
equations::IdealGlmMhdEquations1D)
496
rho_ll, rho_v1_ll, _ = u_ll
497
rho_rr, rho_v1_rr, _ = u_rr
498
499
# Calculate primitive variables
500
v1_ll = rho_v1_ll / rho_ll
501
v1_rr = rho_v1_rr / rho_rr
502
503
# Approximate the left-most and right-most eigenvalues in the Riemann fan
504
c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)
505
c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)
506
vel_roe, c_f_roe = calc_fast_wavespeed_roe(u_ll, u_rr, orientation, equations)
507
λ_min = min(v1_ll - c_f_ll, vel_roe - c_f_roe)
508
λ_max = max(v1_rr + c_f_rr, vel_roe + c_f_roe)
509
510
return λ_min, λ_max
511
end
512
513
@inline function max_abs_speeds(u, equations::IdealGlmMhdEquations1D)
514
rho, rho_v1, _ = u
515
v1 = rho_v1 / rho
516
cf_x_direction = calc_fast_wavespeed(u, 1, equations)
517
518
return abs(v1) + cf_x_direction
519
end
520
521
# Convert conservative variables to primitive
522
@inline function cons2prim(u, equations::IdealGlmMhdEquations1D)
523
rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u
524
525
v1 = rho_v1 / rho
526
v2 = rho_v2 / rho
527
v3 = rho_v3 / rho
528
p = (equations.gamma - 1) * (rho_e -
529
0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3
530
+ B1 * B1 + B2 * B2 + B3 * B3))
531
532
return SVector(rho, v1, v2, v3, p, B1, B2, B3)
533
end
534
535
# Convert conservative variables to entropy
536
@inline function cons2entropy(u, equations::IdealGlmMhdEquations1D)
537
rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u
538
539
v1 = rho_v1 / rho
540
v2 = rho_v2 / rho
541
v3 = rho_v3 / rho
542
v_square = v1^2 + v2^2 + v3^2
543
p = (equations.gamma - 1) *
544
(rho_e - 0.5f0 * rho * v_square - 0.5f0 * (B1^2 + B2^2 + B3^2))
545
s = log(p) - equations.gamma * log(rho)
546
rho_p = rho / p
547
548
w1 = (equations.gamma - s) / (equations.gamma - 1) - 0.5f0 * rho_p * v_square
549
w2 = rho_p * v1
550
w3 = rho_p * v2
551
w4 = rho_p * v3
552
w5 = -rho_p
553
w6 = rho_p * B1
554
w7 = rho_p * B2
555
w8 = rho_p * B3
556
557
return SVector(w1, w2, w3, w4, w5, w6, w7, w8)
558
end
559
560
# Convert primitive to conservative variables
561
@inline function prim2cons(prim, equations::IdealGlmMhdEquations1D)
562
rho, v1, v2, v3, p, B1, B2, B3 = prim
563
564
rho_v1 = rho * v1
565
rho_v2 = rho * v2
566
rho_v3 = rho * v3
567
rho_e = p / (equations.gamma - 1) +
568
0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) +
569
0.5f0 * (B1^2 + B2^2 + B3^2)
570
571
return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3)
572
end
573
574
@inline function density(u, equations::IdealGlmMhdEquations1D)
575
rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u
576
return rho
577
end
578
579
@inline function velocity(u, equations::IdealGlmMhdEquations1D)
580
rho = u[1]
581
v1 = u[2] / rho
582
v2 = u[3] / rho
583
v3 = u[4] / rho
584
return SVector(v1, v2, v3)
585
end
586
587
@inline function velocity(u, orientation::Int, equations::IdealGlmMhdEquations1D)
588
rho = u[1]
589
v = u[orientation + 1] / rho
590
return v
591
end
592
593
@inline function pressure(u, equations::IdealGlmMhdEquations1D)
594
rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u
595
p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2 + rho_v3^2) / rho
596
-
597
0.5f0 * (B1^2 + B2^2 + B3^2))
598
return p
599
end
600
601
@inline function density_pressure(u, equations::IdealGlmMhdEquations1D)
602
rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = u
603
p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2 + rho_v3^2) / rho
604
-
605
0.5f0 * (B1^2 + B2^2 + B3^2))
606
return rho * p
607
end
608
609
# Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue
610
@inline function calc_fast_wavespeed(cons, direction, equations::IdealGlmMhdEquations1D)
611
rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3 = cons
612
v1 = rho_v1 / rho
613
v2 = rho_v2 / rho
614
v3 = rho_v3 / rho
615
v_mag = sqrt(v1^2 + v2^2 + v3^2)
616
p = (equations.gamma - 1) *
617
(rho_e - 0.5f0 * rho * v_mag^2 - 0.5f0 * (B1^2 + B2^2 + B3^2))
618
a_square = equations.gamma * p / rho
619
sqrt_rho = sqrt(rho)
620
b1 = B1 / sqrt_rho
621
b2 = B2 / sqrt_rho
622
b3 = B3 / sqrt_rho
623
b_square = b1^2 + b2^2 + b3^2
624
625
c_f = sqrt(0.5f0 * (a_square + b_square) +
626
0.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b1^2))
627
return c_f
628
end
629
630
"""
631
calc_fast_wavespeed_roe(u_ll, u_rr, direction, equations::IdealGlmMhdEquations1D)
632
633
Compute the fast magnetoacoustic wave speed using Roe averages
634
as given by
635
- Cargo and Gallice (1997)
636
Roe Matrices for Ideal MHD and Systematic Construction
637
of Roe Matrices for Systems of Conservation Laws
638
[DOI: 10.1006/jcph.1997.5773](https://doi.org/10.1006/jcph.1997.5773)
639
"""
640
@inline function calc_fast_wavespeed_roe(u_ll, u_rr, direction,
641
equations::IdealGlmMhdEquations1D)
642
rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll = u_ll
643
rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr = u_rr
644
645
# Calculate primitive variables
646
v1_ll = rho_v1_ll / rho_ll
647
v2_ll = rho_v2_ll / rho_ll
648
v3_ll = rho_v3_ll / rho_ll
649
vel_norm_ll = v1_ll^2 + v2_ll^2 + v3_ll^2
650
mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2
651
p_ll = (equations.gamma - 1) *
652
(rho_e_ll - 0.5f0 * rho_ll * vel_norm_ll - 0.5f0 * mag_norm_ll)
653
654
v1_rr = rho_v1_rr / rho_rr
655
v2_rr = rho_v2_rr / rho_rr
656
v3_rr = rho_v3_rr / rho_rr
657
vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2
658
mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2
659
p_rr = (equations.gamma - 1) *
660
(rho_e_rr - 0.5f0 * rho_rr * vel_norm_rr - 0.5f0 * mag_norm_rr)
661
662
# compute total pressure which is thermal + magnetic pressures
663
p_total_ll = p_ll + 0.5f0 * mag_norm_ll
664
p_total_rr = p_rr + 0.5f0 * mag_norm_rr
665
666
# compute the Roe density averages
667
sqrt_rho_ll = sqrt(rho_ll)
668
sqrt_rho_rr = sqrt(rho_rr)
669
inv_sqrt_rho_add = 1 / (sqrt_rho_ll + sqrt_rho_rr)
670
inv_sqrt_rho_prod = 1 / (sqrt_rho_ll * sqrt_rho_rr)
671
rho_ll_roe = sqrt_rho_ll * inv_sqrt_rho_add
672
rho_rr_roe = sqrt_rho_rr * inv_sqrt_rho_add
673
# Roe averages
674
# velocities and magnetic fields
675
v1_roe = v1_ll * rho_ll_roe + v1_rr * rho_rr_roe
676
v2_roe = v2_ll * rho_ll_roe + v2_rr * rho_rr_roe
677
v3_roe = v3_ll * rho_ll_roe + v3_rr * rho_rr_roe
678
B1_roe = B1_ll * rho_ll_roe + B1_rr * rho_rr_roe
679
B2_roe = B2_ll * rho_ll_roe + B2_rr * rho_rr_roe
680
B3_roe = B3_ll * rho_ll_roe + B3_rr * rho_rr_roe
681
# enthalpy
682
H_ll = (rho_e_ll + p_total_ll) / rho_ll
683
H_rr = (rho_e_rr + p_total_rr) / rho_rr
684
H_roe = H_ll * rho_ll_roe + H_rr * rho_rr_roe
685
# temporary variable see equations (4.12) in Cargo and Gallice
686
X = 0.5f0 * ((B1_ll - B1_rr)^2 + (B2_ll - B2_rr)^2 + (B3_ll - B3_rr)^2) *
687
inv_sqrt_rho_add^2
688
# averaged components needed to compute c_f, the fast magnetoacoustic wave speed
689
b_square_roe = (B1_roe^2 + B2_roe^2 + B3_roe^2) * inv_sqrt_rho_prod # scaled magnectic sum
690
a_square_roe = ((2 - equations.gamma) * X +
691
(equations.gamma - 1) *
692
(H_roe - 0.5f0 * (v1_roe^2 + v2_roe^2 + v3_roe^2) -
693
b_square_roe)) # acoustic speed
694
# finally compute the average wave speed and set the output velocity
695
# Ignore orientation since it is always "1" in 1D
696
c_a_roe = B1_roe^2 * inv_sqrt_rho_prod # (squared) Alfvén wave speed
697
a_star_roe = sqrt((a_square_roe + b_square_roe)^2 - 4 * a_square_roe * c_a_roe)
698
c_f_roe = sqrt(0.5f0 * (a_square_roe + b_square_roe + a_star_roe))
699
700
return v1_roe, c_f_roe
701
end
702
703
# Calculate thermodynamic entropy for a conservative state `cons`
704
@inline function entropy_thermodynamic(cons, equations::IdealGlmMhdEquations1D)
705
# Pressure
706
p = (equations.gamma - 1) *
707
(cons[5] - 0.5f0 * (cons[2]^2 + cons[3]^2 + cons[4]^2) / cons[1]
708
-
709
0.5f0 * (cons[6]^2 + cons[7]^2 + cons[8]^2))
710
711
# Thermodynamic entropy
712
s = log(p) - equations.gamma * log(cons[1])
713
714
return s
715
end
716
717
# Calculate mathematical entropy for a conservative state `cons`
718
@inline function entropy_math(cons, equations::IdealGlmMhdEquations1D)
719
S = -entropy_thermodynamic(cons, equations) * cons[1] / (equations.gamma - 1)
720
721
return S
722
end
723
724
# Default entropy is the mathematical entropy
725
@inline entropy(cons, equations::IdealGlmMhdEquations1D) = entropy_math(cons, equations)
726
727
# Calculate total energy for a conservative state `cons`
728
@inline energy_total(cons, ::IdealGlmMhdEquations1D) = cons[5]
729
730
# Calculate kinetic energy for a conservative state `cons`
731
@inline function energy_kinetic(cons, equations::IdealGlmMhdEquations1D)
732
return 0.5f0 * (cons[2]^2 + cons[3]^2 + cons[4]^2) / cons[1]
733
end
734
735
# Calculate the magnetic energy for a conservative state `cons'.
736
# OBS! For non-dinmensional form of the ideal MHD magnetic pressure ≡ magnetic energy
737
@inline function energy_magnetic(cons, ::IdealGlmMhdEquations1D)
738
return 0.5f0 * (cons[6]^2 + cons[7]^2 + cons[8]^2)
739
end
740
741
# Calculate internal energy for a conservative state `cons`
742
@inline function energy_internal(cons, equations::IdealGlmMhdEquations1D)
743
return (energy_total(cons, equations)
744
-
745
energy_kinetic(cons, equations)
746
-
747
energy_magnetic(cons, equations))
748
end
749
750
# Calculate the cross helicity (\vec{v}⋅\vec{B}) for a conservative state `cons'
751
@inline function cross_helicity(cons, ::IdealGlmMhdEquations1D)
752
return (cons[2] * cons[6] + cons[3] * cons[7] + cons[4] * cons[8]) / cons[1]
753
end
754
end # @muladd
755
756