Skip to content

Commit c2aad37

Browse files
authored
Merge branch 'main' into vc/turbo
2 parents 1453a50 + f5d7a79 commit c2aad37

File tree

6 files changed

+520
-22
lines changed

6 files changed

+520
-22
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
2+
using OrdinaryDiffEqLowStorageRK
3+
using Trixi
4+
5+
###############################################################################
6+
# This elixir describes the frictional slowing of an ionized carbon fluid (C6+) with respect to another species
7+
# of a background ionized carbon fluid with an initially nonzero relative velocity. It is the second slow-down
8+
# test (fluids with different densities) described in:
9+
# - Ghosh, D., Chapman, T. D., Berger, R. L., Dimits, A., & Banks, J. W. (2019). A
10+
# multispecies, multifluid model for laser–induced counterstreaming plasma simulations.
11+
# Computers & Fluids, 186, 38-57. [DOI: 10.1016/j.compfluid.2019.04.012](https://doi.org/10.1016/j.compfluid.2019.04.012).
12+
#
13+
# This is effectively a zero-dimensional case because the spatial gradients are zero, and we use it to test the
14+
# collision source terms.
15+
#
16+
# To run this physically relevant test, we use the following characteristic quantities to non-dimensionalize
17+
# the equations:
18+
# Characteristic length: L_inf = 1.00E-03 m (domain size)
19+
# Characteristic density: rho_inf = 1.99E+00 kg/m^3 (corresponds to a number density of 1e20 cm^{-3})
20+
# Characteristic vacuum permeability: mu0_inf = 1.26E-06 N/A^2 (for equations with mu0 = 1)
21+
# Characteristic gas constant: R_inf = 6.92237E+02 J/kg/K (specific gas constant for a Carbon fluid)
22+
# Characteristic velocity: V_inf = 1.00E+06 m/s
23+
#
24+
# The results of the paper can be reproduced using `source_terms = source_terms_collision_ion_ion` (i.e., only
25+
# taking into account ion-ion collisions). However, we include ion-electron collisions assuming a constant
26+
# electron temperature of 1 keV in this elixir to test the function `source_terms_collision_ion_electron`
27+
28+
# Return the electron pressure for a constant electron temperature Te = 1 keV
29+
function electron_pressure_constantTe(u, equations::IdealGlmMhdMultiIonEquations2D)
30+
@unpack charge_to_mass = equations
31+
Te = electron_temperature_constantTe(u, equations)
32+
total_electron_charge = zero(eltype(u))
33+
for k in eachcomponent(equations)
34+
rho_k = u[3 + (k - 1) * 5 + 1]
35+
total_electron_charge += rho_k * charge_to_mass[k]
36+
end
37+
38+
# Boltzmann constant divided by elementary charge
39+
RealT = eltype(u)
40+
kB_e = convert(RealT, 7.86319034E-02) #[nondimensional]
41+
42+
return total_electron_charge * kB_e * Te
43+
end
44+
45+
# Return the constant electron temperature Te = 1 keV
46+
function electron_temperature_constantTe(u, equations::IdealGlmMhdMultiIonEquations2D)
47+
RealT = eltype(u)
48+
return convert(RealT, 0.008029953773) # [nondimensional] = 1 [keV]
49+
end
50+
51+
# semidiscretization of the ideal MHD equations
52+
equations = IdealGlmMhdMultiIonEquations2D(gammas = (5 / 3, 5 / 3),
53+
charge_to_mass = (76.3049060157692000,
54+
76.3049060157692000), # [nondimensional]
55+
gas_constants = (1.0, 1.0), # [nondimensional]
56+
molar_masses = (1.0, 1.0), # [nondimensional]
57+
ion_ion_collision_constants = [0.0 0.4079382480442680;
58+
0.4079382480442680 0.0], # [nondimensional] (computed with eq (4.142) of Schunk & Nagy (2009))
59+
ion_electron_collision_constants = (8.56368379833E-06,
60+
8.56368379833E-06), # [nondimensional] (computed with eq (9) of Ghosh et al. (2019))
61+
electron_pressure = electron_pressure_constantTe,
62+
electron_temperature = electron_temperature_constantTe,
63+
initial_c_h = 0.0) # Deactivate GLM divergence cleaning
64+
65+
# Frictional slowing of an ionized carbon fluid with respect to another background carbon fluid in motion
66+
function initial_condition_slow_down(x, t, equations::IdealGlmMhdMultiIonEquations2D)
67+
RealT = eltype(x)
68+
69+
v11 = convert(RealT, 0.6550877)
70+
v21 = zero(RealT)
71+
v2 = v3 = zero(RealT)
72+
B1 = B2 = B3 = zero(RealT)
73+
rho1 = convert(RealT, 0.1)
74+
rho2 = one(RealT)
75+
76+
p1 = convert(RealT, 0.00040170535986)
77+
p2 = convert(RealT, 0.00401705359856)
78+
79+
psi = zero(RealT)
80+
81+
return prim2cons(SVector(B1, B2, B3, rho1, v11, v2, v3, p1, rho2, v21, v2, v3, p2, psi),
82+
equations)
83+
end
84+
85+
# Temperature of ion 1
86+
function temperature1(u, equations::IdealGlmMhdMultiIonEquations2D)
87+
rho_1, _ = Trixi.get_component(1, u, equations)
88+
p = pressure(u, equations)
89+
90+
return p[1] / (rho_1 * equations.gas_constants[1])
91+
end
92+
93+
# Temperature of ion 2
94+
function temperature2(u, equations::IdealGlmMhdMultiIonEquations2D)
95+
rho_2, _ = Trixi.get_component(2, u, equations)
96+
p = pressure(u, equations)
97+
98+
return p[2] / (rho_2 * equations.gas_constants[2])
99+
end
100+
101+
initial_condition = initial_condition_slow_down
102+
tspan = (0.0, 0.1) # 100 [ps]
103+
104+
# Entropy conservative volume numerical fluxes with standard LLF dissipation at interfaces
105+
volume_flux = (flux_ruedaramirez_etal, flux_nonconservative_ruedaramirez_etal)
106+
surface_flux = (flux_lax_friedrichs, flux_nonconservative_central)
107+
108+
solver = DGSEM(polydeg = 3, surface_flux = surface_flux,
109+
volume_integral = VolumeIntegralFluxDifferencing(volume_flux))
110+
111+
coordinates_min = (0.0, 0.0)
112+
coordinates_max = (1.0, 1.0)
113+
# We use a very coarse mesh because this is a 0-dimensional case
114+
mesh = TreeMesh(coordinates_min, coordinates_max,
115+
initial_refinement_level = 1,
116+
n_cells_max = 1_000_000)
117+
118+
# Ion-ion and ion-electron collision source terms
119+
# In this particular case, we can omit source_terms_lorentz because the magnetic field is zero!
120+
function source_terms(u, x, t, equations::IdealGlmMhdMultiIonEquations2D)
121+
source_terms_collision_ion_ion(u, x, t, equations) +
122+
source_terms_collision_ion_electron(u, x, t, equations)
123+
end
124+
125+
semi = SemidiscretizationHyperbolic(mesh, equations, initial_condition, solver,
126+
source_terms = source_terms)
127+
128+
###############################################################################
129+
# ODE solvers, callbacks etc.
130+
131+
ode = semidiscretize(semi, tspan)
132+
133+
summary_callback = SummaryCallback()
134+
135+
analysis_interval = 1
136+
analysis_callback = AnalysisCallback(semi,
137+
save_analysis = true,
138+
interval = analysis_interval,
139+
extra_analysis_integrals = (temperature1,
140+
temperature2))
141+
alive_callback = AliveCallback(analysis_interval = analysis_interval)
142+
143+
stepsize_callback = StepsizeCallback(cfl = 0.01) # Very small CFL due to the stiff source terms
144+
145+
save_restart = SaveRestartCallback(interval = 100,
146+
save_final_restart = true)
147+
148+
callbacks = CallbackSet(summary_callback,
149+
analysis_callback, alive_callback,
150+
save_restart,
151+
stepsize_callback)
152+
153+
###############################################################################
154+
155+
sol = solve(ode, CarpenterKennedy2N54(williamson_condition = false);
156+
dt = 1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
157+
ode_default_options()..., callback = callbacks);

src/Trixi.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ export boundary_condition_do_nothing,
226226
BoundaryConditionCoupled
227227

228228
export initial_condition_convergence_test, source_terms_convergence_test,
229-
source_terms_lorentz
229+
source_terms_lorentz, source_terms_collision_ion_electron,
230+
source_terms_collision_ion_ion
230231
export source_terms_harmonic
231232
export initial_condition_poisson_nonperiodic, source_terms_poisson_nonperiodic,
232233
boundary_condition_poisson_nonperiodic

src/equations/ideal_glm_mhd_multiion.jl

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,22 @@ divergence_cleaning_field(u, equations::AbstractIdealGlmMhdMultiIonEquations) =
183183
return rho
184184
end
185185

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+
186202
#Convert conservative variables to primitive
187203
function cons2prim(u, equations::AbstractIdealGlmMhdMultiIonEquations)
188204
@unpack gammas = equations
@@ -471,4 +487,173 @@ end
471487

472488
return dissipation
473489
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
474659
end

0 commit comments

Comments
 (0)