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_multiion.jl
2055 views
1
# This file includes functions that are common for all AbstractIdealGlmMhdMultiIonEquations
2
3
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
4
# Since these FMAs can increase the performance of many numerical algorithms,
5
# we need to opt-in explicitly.
6
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
7
@muladd begin
8
#! format: noindent
9
10
have_nonconservative_terms(::AbstractIdealGlmMhdMultiIonEquations) = True()
11
12
# Variable names for the multi-ion GLM-MHD equation
13
# ATTENTION: the variable order for AbstractIdealGlmMhdMultiIonEquations is different than in the reference
14
# - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization
15
# of the Ideal Multi-Ion Magnetohydrodynamics System (2024). Journal of Computational Physics.
16
# [DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655).
17
# The first three entries of the state vector `cons[1:3]` are the magnetic field components. After that, we have chunks
18
# of 5 entries for the hydrodynamic quantities of each ion species. Finally, the last entry `cons[end]` is the divergence
19
# cleaning field.
20
function varnames(::typeof(cons2cons), equations::AbstractIdealGlmMhdMultiIonEquations)
21
cons = ("B1", "B2", "B3")
22
for i in eachcomponent(equations)
23
cons = (cons...,
24
tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i),
25
"rho_v3_" * string(i), "rho_e_" * string(i))...)
26
end
27
cons = (cons..., "psi")
28
29
return cons
30
end
31
32
function varnames(::typeof(cons2prim), equations::AbstractIdealGlmMhdMultiIonEquations)
33
prim = ("B1", "B2", "B3")
34
for i in eachcomponent(equations)
35
prim = (prim...,
36
tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i),
37
"v3_" * string(i), "p_" * string(i))...)
38
end
39
prim = (prim..., "psi")
40
41
return prim
42
end
43
44
function default_analysis_integrals(::AbstractIdealGlmMhdMultiIonEquations)
45
(entropy_timederivative, Val(:l2_divb), Val(:linf_divb))
46
end
47
48
"""
49
source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations)
50
51
Source terms due to the Lorentz' force for plasmas with more than one ion species. These source
52
terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for
53
a single-species plasma. In particular, they have to be used for every
54
simulation of [`IdealGlmMhdMultiIonEquations2D`](@ref) and [`IdealGlmMhdMultiIonEquations3D`](@ref).
55
"""
56
function source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations)
57
@unpack charge_to_mass = equations
58
B1, B2, B3 = magnetic_field(u, equations)
59
v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u,
60
equations)
61
62
s = zero(MVector{nvariables(equations), eltype(u)})
63
64
for k in eachcomponent(equations)
65
rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations)
66
rho_inv = 1 / rho
67
v1 = rho_v1 * rho_inv
68
v2 = rho_v2 * rho_inv
69
v3 = rho_v3 * rho_inv
70
v1_diff = v1_plus - v1
71
v2_diff = v2_plus - v2
72
v3_diff = v3_plus - v3
73
r_rho = charge_to_mass[k] * rho
74
s2 = r_rho * (v2_diff * B3 - v3_diff * B2)
75
s3 = r_rho * (v3_diff * B1 - v1_diff * B3)
76
s4 = r_rho * (v1_diff * B2 - v2_diff * B1)
77
s5 = v1 * s2 + v2 * s3 + v3 * s4
78
79
set_component!(s, k, 0, s2, s3, s4, s5, equations)
80
end
81
82
return SVector(s)
83
end
84
85
"""
86
electron_pressure_zero(u, equations::AbstractIdealGlmMhdMultiIonEquations)
87
88
Returns the value of zero for the electron pressure. Needed for consistency with the
89
single-fluid MHD equations in the limit of one ion species.
90
"""
91
function electron_pressure_zero(u, equations::AbstractIdealGlmMhdMultiIonEquations)
92
return zero(u[1])
93
end
94
95
"""
96
v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u,
97
equations::AbstractIdealGlmMhdMultiIonEquations)
98
99
100
Compute the charge-averaged velocities (`v1`, `v2`, and `v3`) and each ion species' contribution
101
to the charge-averaged velocities (`vk1`, `vk2`, and `vk3`). The output variables `vk1`, `vk2`, and `vk3`
102
are `SVectors` of size `ncomponents(equations)`.
103
104
!!! warning "Experimental implementation"
105
This is an experimental feature and may change in future releases.
106
"""
107
@inline function charge_averaged_velocities(u,
108
equations::AbstractIdealGlmMhdMultiIonEquations)
109
total_electron_charge = zero(real(equations))
110
111
vk1_plus = zero(MVector{ncomponents(equations), eltype(u)})
112
vk2_plus = zero(MVector{ncomponents(equations), eltype(u)})
113
vk3_plus = zero(MVector{ncomponents(equations), eltype(u)})
114
115
for k in eachcomponent(equations)
116
rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations)
117
118
total_electron_charge += rho * equations.charge_to_mass[k]
119
vk1_plus[k] = rho_v1 * equations.charge_to_mass[k]
120
vk2_plus[k] = rho_v2 * equations.charge_to_mass[k]
121
vk3_plus[k] = rho_v3 * equations.charge_to_mass[k]
122
end
123
vk1_plus ./= total_electron_charge
124
vk2_plus ./= total_electron_charge
125
vk3_plus ./= total_electron_charge
126
v1_plus = sum(vk1_plus)
127
v2_plus = sum(vk2_plus)
128
v3_plus = sum(vk3_plus)
129
130
return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus),
131
SVector(vk3_plus)
132
end
133
134
"""
135
get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations)
136
137
Get the hydrodynamic variables of component (ion species) `k`.
138
139
!!! warning "Experimental implementation"
140
This is an experimental feature and may change in future releases.
141
"""
142
@inline function get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations)
143
return SVector(u[3 + (k - 1) * 5 + 1],
144
u[3 + (k - 1) * 5 + 2],
145
u[3 + (k - 1) * 5 + 3],
146
u[3 + (k - 1) * 5 + 4],
147
u[3 + (k - 1) * 5 + 5])
148
end
149
150
"""
151
set_component!(u, k, u1, u2, u3, u4, u5,
152
equations::AbstractIdealGlmMhdMultiIonEquations)
153
154
Set the hydrodynamic variables (`u1` to `u5`) of component (ion species) `k`.
155
156
!!! warning "Experimental implementation"
157
This is an experimental feature and may change in future releases.
158
"""
159
@inline function set_component!(u, k, u1, u2, u3, u4, u5,
160
equations::AbstractIdealGlmMhdMultiIonEquations)
161
u[3 + (k - 1) * 5 + 1] = u1
162
u[3 + (k - 1) * 5 + 2] = u2
163
u[3 + (k - 1) * 5 + 3] = u3
164
u[3 + (k - 1) * 5 + 4] = u4
165
u[3 + (k - 1) * 5 + 5] = u5
166
167
return u
168
end
169
170
# Extract magnetic field from solution vector
171
magnetic_field(u, equations::AbstractIdealGlmMhdMultiIonEquations) = SVector(u[1], u[2],
172
u[3])
173
174
# Extract GLM divergence-cleaning field from solution vector
175
divergence_cleaning_field(u, equations::AbstractIdealGlmMhdMultiIonEquations) = u[end]
176
177
# Get total density as the sum of the individual densities of the ion species
178
@inline function density(u, equations::AbstractIdealGlmMhdMultiIonEquations)
179
rho = zero(real(equations))
180
for k in eachcomponent(equations)
181
rho += u[3 + (k - 1) * 5 + 1]
182
end
183
return rho
184
end
185
186
@inline function pressure(u, equations::AbstractIdealGlmMhdMultiIonEquations)
187
B1, B2, B3, _ = u
188
p = zero(MVector{ncomponents(equations), real(equations)})
189
for k in eachcomponent(equations)
190
rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations)
191
v1 = rho_v1 / rho
192
v2 = rho_v2 / rho
193
v3 = rho_v3 / rho
194
gamma = equations.gammas[k]
195
p[k] = (gamma - 1) *
196
(rho_e - 0.5f0 * rho * (v1^2 + v2^2 + v3^2) -
197
0.5f0 * (B1^2 + B2^2 + B3^2))
198
end
199
return SVector{ncomponents(equations), real(equations)}(p)
200
end
201
202
#Convert conservative variables to primitive
203
function cons2prim(u, equations::AbstractIdealGlmMhdMultiIonEquations)
204
@unpack gammas = equations
205
B1, B2, B3 = magnetic_field(u, equations)
206
psi = divergence_cleaning_field(u, equations)
207
208
prim = zero(MVector{nvariables(equations), eltype(u)})
209
prim[1] = B1
210
prim[2] = B2
211
prim[3] = B3
212
for k in eachcomponent(equations)
213
rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations)
214
rho_inv = 1 / rho
215
v1 = rho_inv * rho_v1
216
v2 = rho_inv * rho_v2
217
v3 = rho_inv * rho_v3
218
219
p = (gammas[k] - 1) * (rho_e -
220
0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3
221
+ B1 * B1 + B2 * B2 + B3 * B3
222
+ psi * psi))
223
224
set_component!(prim, k, rho, v1, v2, v3, p, equations)
225
end
226
prim[end] = psi
227
228
return SVector(prim)
229
end
230
231
#Convert conservative variables to entropy variables
232
@inline function cons2entropy(u, equations::AbstractIdealGlmMhdMultiIonEquations)
233
@unpack gammas = equations
234
B1, B2, B3 = magnetic_field(u, equations)
235
psi = divergence_cleaning_field(u, equations)
236
237
prim = cons2prim(u, equations)
238
entropy = zero(MVector{nvariables(equations), eltype(u)})
239
rho_p_plus = zero(real(equations))
240
for k in eachcomponent(equations)
241
rho, v1, v2, v3, p = get_component(k, prim, equations)
242
s = log(p) - gammas[k] * log(rho)
243
rho_p = rho / p
244
w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5f0 * rho_p * (v1^2 + v2^2 + v3^2)
245
w2 = rho_p * v1
246
w3 = rho_p * v2
247
w4 = rho_p * v3
248
w5 = -rho_p
249
rho_p_plus += rho_p
250
251
set_component!(entropy, k, w1, w2, w3, w4, w5, equations)
252
end
253
254
# Additional non-conservative variables
255
entropy[1] = rho_p_plus * B1
256
entropy[2] = rho_p_plus * B2
257
entropy[3] = rho_p_plus * B3
258
entropy[end] = rho_p_plus * psi
259
260
return SVector(entropy)
261
end
262
263
# Convert primitive to conservative variables
264
@inline function prim2cons(prim, equations::AbstractIdealGlmMhdMultiIonEquations)
265
@unpack gammas = equations
266
B1, B2, B3 = magnetic_field(prim, equations)
267
psi = divergence_cleaning_field(prim, equations)
268
269
cons = zero(MVector{nvariables(equations), eltype(prim)})
270
cons[1] = B1
271
cons[2] = B2
272
cons[3] = B3
273
for k in eachcomponent(equations)
274
rho, v1, v2, v3, p = get_component(k, prim, equations)
275
rho_v1 = rho * v1
276
rho_v2 = rho * v2
277
rho_v3 = rho * v3
278
279
rho_e = p / (gammas[k] - 1) +
280
0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) +
281
0.5f0 * (B1^2 + B2^2 + B3^2) +
282
0.5f0 * psi^2
283
284
set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations)
285
end
286
cons[end] = psi
287
288
return SVector(cons)
289
end
290
291
# Specialization of [`DissipationLaxFriedrichsEntropyVariables`](@ref) for the multi-ion GLM-MHD equations
292
# For details on the multi-ion entropy Jacobian ``H`` see
293
# - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization
294
# of the Ideal Multi-Ion Magnetohydrodynamics System (2024). Journal of Computational Physics.
295
# [DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655).
296
# Since the entropy Jacobian is a sparse matrix, we do not construct it but directly compute the
297
# action of its product with the jump in the entropy variables.
298
#
299
# ATTENTION: the variable order for AbstractIdealGlmMhdMultiIonEquations is different than in the reference above.
300
# The first three entries of the state vector `u[1:3]` are the magnetic field components. After that, we have chunks
301
# of 5 entries for the hydrodynamic quantities of each ion species. Finally, the last entry `u[end]` is the divergence
302
# cleaning field.
303
@inline function (dissipation::DissipationLaxFriedrichsEntropyVariables)(u_ll, u_rr,
304
orientation_or_normal_direction,
305
equations::AbstractIdealGlmMhdMultiIonEquations)
306
@unpack gammas = equations
307
λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction,
308
equations)
309
310
w_ll = cons2entropy(u_ll, equations)
311
w_rr = cons2entropy(u_rr, equations)
312
prim_ll = cons2prim(u_ll, equations)
313
prim_rr = cons2prim(u_rr, equations)
314
B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations)
315
B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations)
316
psi_ll = divergence_cleaning_field(u_ll, equations)
317
psi_rr = divergence_cleaning_field(u_rr, equations)
318
319
# Some global averages
320
B1_avg = 0.5f0 * (B1_ll + B1_rr)
321
B2_avg = 0.5f0 * (B2_ll + B2_rr)
322
B3_avg = 0.5f0 * (B3_ll + B3_rr)
323
psi_avg = 0.5f0 * (psi_ll + psi_rr)
324
325
dissipation = zero(MVector{nvariables(equations), eltype(u_ll)})
326
327
beta_plus_ll = 0
328
beta_plus_rr = 0
329
330
# Compute the dissipation for the hydrodynamic quantities of each ion species `k`
331
#################################################################################
332
333
# The for loop below fills the entries of `dissipation` that depend on the entries of the diagonal
334
# blocks ``A_k`` of the entropy Jacobian ``H`` in the given reference (see equations (80)-(82)),
335
# but the terms that depend on the magnetic field ``B`` and divergence cleaning field ``psi`` are
336
# excluded here and considered below. In other words, these are the dissipation values that depend
337
# on the entries of the entropy Jacobian that are marked in blue in Figure 1 of the reference given above.
338
for k in eachcomponent(equations)
339
rho_ll, v1_ll, v2_ll, v3_ll, p_ll = get_component(k, prim_ll, equations)
340
rho_rr, v1_rr, v2_rr, v3_rr, p_rr = get_component(k, prim_rr, equations)
341
342
w1_ll, w2_ll, w3_ll, w4_ll, w5_ll = get_component(k, w_ll, equations)
343
w1_rr, w2_rr, w3_rr, w4_rr, w5_rr = get_component(k, w_rr, equations)
344
345
# Auxiliary variables
346
beta_ll = 0.5f0 * rho_ll / p_ll
347
beta_rr = 0.5f0 * rho_rr / p_rr
348
vel_norm_ll = v1_ll^2 + v2_ll^2 + v3_ll^2
349
vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2
350
351
# Mean variables
352
rho_ln = ln_mean(rho_ll, rho_rr)
353
beta_ln = ln_mean(beta_ll, beta_rr)
354
rho_avg = 0.5f0 * (rho_ll + rho_rr)
355
v1_avg = 0.5f0 * (v1_ll + v1_rr)
356
v2_avg = 0.5f0 * (v2_ll + v2_rr)
357
v3_avg = 0.5f0 * (v3_ll + v3_rr)
358
beta_avg = 0.5f0 * (beta_ll + beta_rr)
359
tau = 1 / (beta_ll + beta_rr)
360
p_mean = 0.5f0 * rho_avg / beta_avg
361
p_star = 0.5f0 * rho_ln / beta_ln
362
vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr)
363
vel_avg_norm = v1_avg^2 + v2_avg^2 + v3_avg^2
364
E_bar = p_star / (gammas[k] - 1) +
365
0.5f0 * rho_ln * (2 * vel_avg_norm - vel_norm_avg)
366
367
h11 = rho_ln
368
h12 = rho_ln * v1_avg
369
h13 = rho_ln * v2_avg
370
h14 = rho_ln * v3_avg
371
h15 = E_bar
372
d1 = -0.5f0 * λ *
373
(h11 * (w1_rr - w1_ll) +
374
h12 * (w2_rr - w2_ll) +
375
h13 * (w3_rr - w3_ll) +
376
h14 * (w4_rr - w4_ll) +
377
h15 * (w5_rr - w5_ll))
378
379
h21 = h12
380
h22 = rho_ln * v1_avg^2 + p_mean
381
h23 = h21 * v2_avg
382
h24 = h21 * v3_avg
383
h25 = (E_bar + p_mean) * v1_avg
384
d2 = -0.5f0 * λ *
385
(h21 * (w1_rr - w1_ll) +
386
h22 * (w2_rr - w2_ll) +
387
h23 * (w3_rr - w3_ll) +
388
h24 * (w4_rr - w4_ll) +
389
h25 * (w5_rr - w5_ll))
390
391
h31 = h13
392
h32 = h23
393
h33 = rho_ln * v2_avg^2 + p_mean
394
h34 = h31 * v3_avg
395
h35 = (E_bar + p_mean) * v2_avg
396
d3 = -0.5f0 * λ *
397
(h31 * (w1_rr - w1_ll) +
398
h32 * (w2_rr - w2_ll) +
399
h33 * (w3_rr - w3_ll) +
400
h34 * (w4_rr - w4_ll) +
401
h35 * (w5_rr - w5_ll))
402
403
h41 = h14
404
h42 = h24
405
h43 = h34
406
h44 = rho_ln * v3_avg^2 + p_mean
407
h45 = (E_bar + p_mean) * v3_avg
408
d4 = -0.5f0 * λ *
409
(h41 * (w1_rr - w1_ll) +
410
h42 * (w2_rr - w2_ll) +
411
h43 * (w3_rr - w3_ll) +
412
h44 * (w4_rr - w4_ll) +
413
h45 * (w5_rr - w5_ll))
414
415
h51 = h15
416
h52 = h25
417
h53 = h35
418
h54 = h45
419
h55 = ((p_star^2 / (gammas[k] - 1) + E_bar * E_bar) / rho_ln
420
+
421
vel_avg_norm * p_mean)
422
d5 = -0.5f0 * λ *
423
(h51 * (w1_rr - w1_ll) +
424
h52 * (w2_rr - w2_ll) +
425
h53 * (w3_rr - w3_ll) +
426
h54 * (w4_rr - w4_ll) +
427
h55 * (w5_rr - w5_ll))
428
429
beta_plus_ll += beta_ll
430
beta_plus_rr += beta_rr
431
432
set_component!(dissipation, k, d1, d2, d3, d4, d5, equations)
433
end
434
435
# Compute the dissipation related to the magnetic and divergence-cleaning fields
436
################################################################################
437
438
h_B_psi = 1 / (beta_plus_ll + beta_plus_rr)
439
440
# Dissipation for the magnetic field components due to the diagonal entries of the
441
# dissipation matrix ``H``. These are the dissipation values that depend on the diagonal
442
# entries of the entropy Jacobian that are marked in cyan in Figure 1 of the reference given above.
443
dissipation[1] = -0.5f0 * λ * h_B_psi * (w_rr[1] - w_ll[1])
444
dissipation[2] = -0.5f0 * λ * h_B_psi * (w_rr[2] - w_ll[2])
445
dissipation[3] = -0.5f0 * λ * h_B_psi * (w_rr[3] - w_ll[3])
446
447
# Dissipation for the divergence-cleaning field due to the diagonal entry of the
448
# dissipation matrix ``H``. This dissipation value depends on the single diagonal
449
# entry of the entropy Jacobian that is marked in red in Figure 1 of the reference given above.
450
dissipation[end] = -0.5f0 * λ * h_B_psi * (w_rr[end] - w_ll[end])
451
452
# Dissipation due to the off-diagonal blocks (``B_{off}``) of the dissipation matrix ``H`` and to the entries
453
# of the block ``A`` that depend on the magnetic field ``B`` and the divergence cleaning field ``psi``.
454
# See equations (80)-(82) of the given reference.
455
for k in eachcomponent(equations)
456
_, _, _, _, w5_ll = get_component(k, w_ll, equations)
457
_, _, _, _, w5_rr = get_component(k, w_rr, equations)
458
459
# Dissipation for the magnetic field components and divergence cleaning field due to the off-diagonal
460
# entries of the dissipation matrix ``H`` (block ``B^T`` in equation (80) and Figure 1 of the reference
461
# given above).
462
dissipation[1] -= 0.5f0 * λ * h_B_psi * B1_avg * (w5_rr - w5_ll)
463
dissipation[2] -= 0.5f0 * λ * h_B_psi * B2_avg * (w5_rr - w5_ll)
464
dissipation[3] -= 0.5f0 * λ * h_B_psi * B3_avg * (w5_rr - w5_ll)
465
dissipation[end] -= 0.5f0 * λ * h_B_psi * psi_avg * (w5_rr - w5_ll)
466
467
# Dissipation for the energy equation of species `k` depending on `w_1`, `w_2`, `w_3` and `w_end`. These are the
468
# values of the dissipation that depend on the off-diagonal block ``B`` of the dissipation matrix ``H`` (see equation (80)
469
# and Figure 1 of the reference given above.
470
ind_E = 3 + 5 * k # simplified version of 3 + (k - 1) * 5 + 5
471
dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B1_avg * (w_rr[1] - w_ll[1])
472
dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B2_avg * (w_rr[2] - w_ll[2])
473
dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B3_avg * (w_rr[3] - w_ll[3])
474
dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * psi_avg * (w_rr[end] - w_ll[end])
475
476
# Dissipation for the energy equation of all ion species depending on `w_5`. These are the values of the dissipation
477
# vector that depend on the magnetic and divergence-cleaning field terms of the entries marked with a red cross in
478
# Figure 1 of the reference given above.
479
for kk in eachcomponent(equations)
480
ind_E = 3 + 5 * kk # simplified version of 3 + (kk - 1) * 5 + 5
481
dissipation[ind_E] -= 0.5f0 * λ *
482
(h_B_psi *
483
(B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2)) *
484
(w5_rr - w5_ll)
485
end
486
end
487
488
return dissipation
489
end
490
491
@doc raw"""
492
source_terms_collision_ion_ion(u, x, t,
493
equations::AbstractIdealGlmMhdMultiIonEquations)
494
495
Compute the ion-ion collision source terms for the momentum and energy equations of each ion species as
496
```math
497
\begin{aligned}
498
\vec{s}_{\rho_k \vec{v}_k} =& \rho_k\sum_{l}\bar{\nu}_{kl}(\vec{v}_{l} - \vec{v}_k),\\
499
s_{E_k} =&
500
3 \sum_{l} \left(
501
\bar{\nu}_{kl} \frac{\rho_k M_1}{M_{l} + M_k} R_1 (T_{l} - T_k)
502
\right) +
503
\sum_{l} \left(
504
\bar{\nu}_{kl} \rho_k \frac{M_{l}}{M_{l} + M_k} \|\vec{v}_{l} - \vec{v}_k\|^2
505
\right)
506
+
507
\vec{v}_k \cdot \vec{s}_{\rho_k \vec{v}_k},
508
\end{aligned}
509
```
510
where ``M_k`` is the molar mass of ion species `k` provided in `equations.molar_masses`,
511
``R_k`` is the specific gas constant of ion species `k` provided in `equations.gas_constants`, and
512
``\bar{\nu}_{kl}`` is the effective collision frequency of species `k` with species `l`, which is computed as
513
```math
514
\begin{aligned}
515
\bar{\nu}_{kl} = \bar{\nu}^1_{kl} \tilde{B}_{kl} \frac{\rho_{l}}{T_{k l}^{3/2}},
516
\end{aligned}
517
```
518
with the so-called reduced temperature ``T_{k l}`` and the ion-ion collision constants ``\tilde{B}_{kl}`` provided
519
in `equations.ion_electron_collision_constants` (see [`IdealGlmMhdMultiIonEquations2D`](@ref)).
520
521
The additional coefficient ``\bar{\nu}^1_{kl}`` is a non-dimensional drift correction factor proposed by Rambo and Denavit.
522
523
References:
524
- P. Rambo, J. Denavit, Interpenetration and ion separation in colliding plasmas, Physics of Plasmas 1 (1994) 4050–4060.
525
[DOI: 10.1063/1.870875](https://doi.org/10.1063/1.870875).
526
- Schunk, R. W., Nagy, A. F. (2000). Ionospheres: Physics, plasma physics, and chemistry.
527
Cambridge university press. [DOI: 10.1017/CBO9780511635342](https://doi.org/10.1017/CBO9780511635342).
528
"""
529
function source_terms_collision_ion_ion(u, x, t,
530
equations::AbstractIdealGlmMhdMultiIonEquations)
531
s = zero(MVector{nvariables(equations), eltype(u)})
532
@unpack gas_constants, molar_masses, ion_ion_collision_constants = equations
533
534
prim = cons2prim(u, equations)
535
536
for k in eachcomponent(equations)
537
rho_k, v1_k, v2_k, v3_k, p_k = get_component(k, prim, equations)
538
T_k = p_k / (rho_k * gas_constants[k])
539
540
S_q1 = zero(eltype(u))
541
S_q2 = zero(eltype(u))
542
S_q3 = zero(eltype(u))
543
S_E = zero(eltype(u))
544
for l in eachcomponent(equations)
545
# Do not compute collisions of an ion species with itself
546
k == l && continue
547
548
rho_l, v1_l, v2_l, v3_l, p_l = get_component(l, prim, equations)
549
T_l = p_l / (rho_l * gas_constants[l])
550
551
# Reduced temperature
552
T_kl = (molar_masses[l] * T_k + molar_masses[k] * T_l) /
553
(molar_masses[k] + molar_masses[l])
554
555
delta_v2 = (v1_l - v1_k)^2 + (v2_l - v2_k)^2 + (v3_l - v3_k)^2
556
557
# Compute collision frequency without drifting correction
558
v_kl = ion_ion_collision_constants[k, l] * rho_l / T_kl^(3 / 2)
559
560
# Correct the collision frequency with the drifting effect
561
z2 = delta_v2 / (p_l / rho_l + p_k / rho_k)
562
v_kl /= (1 + (2 / (9 * pi))^(1 / 3) * z2)^(3 / 2)
563
564
S_q1 += rho_k * v_kl * (v1_l - v1_k)
565
S_q2 += rho_k * v_kl * (v2_l - v2_k)
566
S_q3 += rho_k * v_kl * (v3_l - v3_k)
567
568
S_E += (3 * molar_masses[1] * gas_constants[1] * (T_l - T_k)
569
+
570
molar_masses[l] * delta_v2) * v_kl * rho_k /
571
(molar_masses[k] + molar_masses[l])
572
end
573
574
S_E += (v1_k * S_q1 + v2_k * S_q2 + v3_k * S_q3)
575
576
set_component!(s, k, 0, S_q1, S_q2, S_q3, S_E, equations)
577
end
578
return SVector{nvariables(equations), real(equations)}(s)
579
end
580
581
@doc raw"""
582
source_terms_collision_ion_electron(u, x, t,
583
equations::AbstractIdealGlmMhdMultiIonEquations)
584
585
Compute the ion-electron collision source terms for the momentum and energy equations of each ion species. We assume ``v_e = v^+``
586
(no effect of currents on the electron velocity).
587
588
The collision sources read as
589
```math
590
\begin{aligned}
591
\vec{s}_{\rho_k \vec{v}_k} =& \rho_k \bar{\nu}_{ke} (\vec{v}_{e} - \vec{v}_k),
592
\\
593
s_{E_k} =&
594
3 \left(
595
\bar{\nu}_{ke} \frac{\rho_k M_{1}}{M_k} R_1 (T_{e} - T_k)
596
\right)
597
+
598
\vec{v}_k \cdot \vec{s}_{\rho_k \vec{v}_k},
599
\end{aligned}
600
```
601
where ``T_e`` is the electron temperature computed with the function `equations.electron_temperature`,
602
``M_k`` is the molar mass of ion species `k` provided in `equations.molar_masses`,
603
``R_k`` is the specific gas constant of ion species `k` provided in `equations.gas_constants`, and
604
``\bar{\nu}_{ke}`` is the collision frequency of species `k` with the electrons, which is computed as
605
```math
606
\begin{aligned}
607
\bar{\nu}_{ke} = \tilde{B}_{ke} \frac{e n_e}{T_e^{3/2}},
608
\end{aligned}
609
```
610
with the total electron charge ``e n_e`` (computed assuming quasi-neutrality), and the
611
ion-electron collision coefficient ``\tilde{B}_{ke}`` provided in `equations.ion_electron_collision_constants`,
612
which is scaled with the elementary charge (see [`IdealGlmMhdMultiIonEquations2D`](@ref)).
613
614
References:
615
- P. Rambo, J. Denavit, Interpenetration and ion separation in colliding plasmas, Physics of Plasmas 1 (1994) 4050–4060.
616
[DOI: 10.1063/1.870875](https://doi.org/10.1063/1.870875).
617
- Schunk, R. W., Nagy, A. F. (2000). Ionospheres: Physics, plasma physics, and chemistry.
618
Cambridge university press. [DOI: 10.1017/CBO9780511635342](https://doi.org/10.1017/CBO9780511635342).
619
"""
620
function source_terms_collision_ion_electron(u, x, t,
621
equations::AbstractIdealGlmMhdMultiIonEquations)
622
s = zero(MVector{nvariables(equations), eltype(u)})
623
@unpack gas_constants, molar_masses, ion_electron_collision_constants, electron_temperature = equations
624
625
prim = cons2prim(u, equations)
626
T_e = electron_temperature(u, equations)
627
T_e_power32 = T_e^(3 / 2)
628
629
v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u,
630
equations)
631
632
# Compute total electron charge
633
total_electron_charge = zero(real(equations))
634
for k in eachcomponent(equations)
635
rho, _ = get_component(k, u, equations)
636
total_electron_charge += rho * equations.charge_to_mass[k]
637
end
638
639
for k in eachcomponent(equations)
640
rho_k, v1_k, v2_k, v3_k, p_k = get_component(k, prim, equations)
641
T_k = p_k / (rho_k * gas_constants[k])
642
643
# Compute effective collision frequency
644
v_ke = ion_electron_collision_constants[k] * total_electron_charge / T_e_power32
645
646
S_q1 = rho_k * v_ke * (v1_plus - v1_k)
647
S_q2 = rho_k * v_ke * (v2_plus - v2_k)
648
S_q3 = rho_k * v_ke * (v3_plus - v3_k)
649
650
S_E = 3 * molar_masses[1] * gas_constants[1] * (T_e - T_k) * v_ke * rho_k /
651
molar_masses[k]
652
653
S_E += (v1_k * S_q1 + v2_k * S_q2 + v3_k * S_q3)
654
655
set_component!(s, k, 0, S_q1, S_q2, S_q3, S_E, equations)
656
end
657
return SVector{nvariables(equations), real(equations)}(s)
658
end
659
end
660
661