Path: blob/main/src/equations/ideal_glm_mhd_multiion.jl
2055 views
# This file includes functions that are common for all AbstractIdealGlmMhdMultiIonEquations12# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).3# Since these FMAs can increase the performance of many numerical algorithms,4# we need to opt-in explicitly.5# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.6@muladd begin7#! format: noindent89have_nonconservative_terms(::AbstractIdealGlmMhdMultiIonEquations) = True()1011# Variable names for the multi-ion GLM-MHD equation12# ATTENTION: the variable order for AbstractIdealGlmMhdMultiIonEquations is different than in the reference13# - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization14# of the Ideal Multi-Ion Magnetohydrodynamics System (2024). Journal of Computational Physics.15# [DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655).16# The first three entries of the state vector `cons[1:3]` are the magnetic field components. After that, we have chunks17# of 5 entries for the hydrodynamic quantities of each ion species. Finally, the last entry `cons[end]` is the divergence18# cleaning field.19function varnames(::typeof(cons2cons), equations::AbstractIdealGlmMhdMultiIonEquations)20cons = ("B1", "B2", "B3")21for i in eachcomponent(equations)22cons = (cons...,23tuple("rho_" * string(i), "rho_v1_" * string(i), "rho_v2_" * string(i),24"rho_v3_" * string(i), "rho_e_" * string(i))...)25end26cons = (cons..., "psi")2728return cons29end3031function varnames(::typeof(cons2prim), equations::AbstractIdealGlmMhdMultiIonEquations)32prim = ("B1", "B2", "B3")33for i in eachcomponent(equations)34prim = (prim...,35tuple("rho_" * string(i), "v1_" * string(i), "v2_" * string(i),36"v3_" * string(i), "p_" * string(i))...)37end38prim = (prim..., "psi")3940return prim41end4243function default_analysis_integrals(::AbstractIdealGlmMhdMultiIonEquations)44(entropy_timederivative, Val(:l2_divb), Val(:linf_divb))45end4647"""48source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations)4950Source terms due to the Lorentz' force for plasmas with more than one ion species. These source51terms are a fundamental, inseparable part of the multi-ion GLM-MHD equations, and vanish for52a single-species plasma. In particular, they have to be used for every53simulation of [`IdealGlmMhdMultiIonEquations2D`](@ref) and [`IdealGlmMhdMultiIonEquations3D`](@ref).54"""55function source_terms_lorentz(u, x, t, equations::AbstractIdealGlmMhdMultiIonEquations)56@unpack charge_to_mass = equations57B1, B2, B3 = magnetic_field(u, equations)58v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u,59equations)6061s = zero(MVector{nvariables(equations), eltype(u)})6263for k in eachcomponent(equations)64rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations)65rho_inv = 1 / rho66v1 = rho_v1 * rho_inv67v2 = rho_v2 * rho_inv68v3 = rho_v3 * rho_inv69v1_diff = v1_plus - v170v2_diff = v2_plus - v271v3_diff = v3_plus - v372r_rho = charge_to_mass[k] * rho73s2 = r_rho * (v2_diff * B3 - v3_diff * B2)74s3 = r_rho * (v3_diff * B1 - v1_diff * B3)75s4 = r_rho * (v1_diff * B2 - v2_diff * B1)76s5 = v1 * s2 + v2 * s3 + v3 * s47778set_component!(s, k, 0, s2, s3, s4, s5, equations)79end8081return SVector(s)82end8384"""85electron_pressure_zero(u, equations::AbstractIdealGlmMhdMultiIonEquations)8687Returns the value of zero for the electron pressure. Needed for consistency with the88single-fluid MHD equations in the limit of one ion species.89"""90function electron_pressure_zero(u, equations::AbstractIdealGlmMhdMultiIonEquations)91return zero(u[1])92end9394"""95v1, v2, v3, vk1, vk2, vk3 = charge_averaged_velocities(u,96equations::AbstractIdealGlmMhdMultiIonEquations)979899Compute the charge-averaged velocities (`v1`, `v2`, and `v3`) and each ion species' contribution100to the charge-averaged velocities (`vk1`, `vk2`, and `vk3`). The output variables `vk1`, `vk2`, and `vk3`101are `SVectors` of size `ncomponents(equations)`.102103!!! warning "Experimental implementation"104This is an experimental feature and may change in future releases.105"""106@inline function charge_averaged_velocities(u,107equations::AbstractIdealGlmMhdMultiIonEquations)108total_electron_charge = zero(real(equations))109110vk1_plus = zero(MVector{ncomponents(equations), eltype(u)})111vk2_plus = zero(MVector{ncomponents(equations), eltype(u)})112vk3_plus = zero(MVector{ncomponents(equations), eltype(u)})113114for k in eachcomponent(equations)115rho, rho_v1, rho_v2, rho_v3, _ = get_component(k, u, equations)116117total_electron_charge += rho * equations.charge_to_mass[k]118vk1_plus[k] = rho_v1 * equations.charge_to_mass[k]119vk2_plus[k] = rho_v2 * equations.charge_to_mass[k]120vk3_plus[k] = rho_v3 * equations.charge_to_mass[k]121end122vk1_plus ./= total_electron_charge123vk2_plus ./= total_electron_charge124vk3_plus ./= total_electron_charge125v1_plus = sum(vk1_plus)126v2_plus = sum(vk2_plus)127v3_plus = sum(vk3_plus)128129return v1_plus, v2_plus, v3_plus, SVector(vk1_plus), SVector(vk2_plus),130SVector(vk3_plus)131end132133"""134get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations)135136Get the hydrodynamic variables of component (ion species) `k`.137138!!! warning "Experimental implementation"139This is an experimental feature and may change in future releases.140"""141@inline function get_component(k, u, equations::AbstractIdealGlmMhdMultiIonEquations)142return SVector(u[3 + (k - 1) * 5 + 1],143u[3 + (k - 1) * 5 + 2],144u[3 + (k - 1) * 5 + 3],145u[3 + (k - 1) * 5 + 4],146u[3 + (k - 1) * 5 + 5])147end148149"""150set_component!(u, k, u1, u2, u3, u4, u5,151equations::AbstractIdealGlmMhdMultiIonEquations)152153Set the hydrodynamic variables (`u1` to `u5`) of component (ion species) `k`.154155!!! warning "Experimental implementation"156This is an experimental feature and may change in future releases.157"""158@inline function set_component!(u, k, u1, u2, u3, u4, u5,159equations::AbstractIdealGlmMhdMultiIonEquations)160u[3 + (k - 1) * 5 + 1] = u1161u[3 + (k - 1) * 5 + 2] = u2162u[3 + (k - 1) * 5 + 3] = u3163u[3 + (k - 1) * 5 + 4] = u4164u[3 + (k - 1) * 5 + 5] = u5165166return u167end168169# Extract magnetic field from solution vector170magnetic_field(u, equations::AbstractIdealGlmMhdMultiIonEquations) = SVector(u[1], u[2],171u[3])172173# Extract GLM divergence-cleaning field from solution vector174divergence_cleaning_field(u, equations::AbstractIdealGlmMhdMultiIonEquations) = u[end]175176# Get total density as the sum of the individual densities of the ion species177@inline function density(u, equations::AbstractIdealGlmMhdMultiIonEquations)178rho = zero(real(equations))179for k in eachcomponent(equations)180rho += u[3 + (k - 1) * 5 + 1]181end182return rho183end184185@inline function pressure(u, equations::AbstractIdealGlmMhdMultiIonEquations)186B1, B2, B3, _ = u187p = zero(MVector{ncomponents(equations), real(equations)})188for k in eachcomponent(equations)189rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations)190v1 = rho_v1 / rho191v2 = rho_v2 / rho192v3 = rho_v3 / rho193gamma = equations.gammas[k]194p[k] = (gamma - 1) *195(rho_e - 0.5f0 * rho * (v1^2 + v2^2 + v3^2) -1960.5f0 * (B1^2 + B2^2 + B3^2))197end198return SVector{ncomponents(equations), real(equations)}(p)199end200201#Convert conservative variables to primitive202function cons2prim(u, equations::AbstractIdealGlmMhdMultiIonEquations)203@unpack gammas = equations204B1, B2, B3 = magnetic_field(u, equations)205psi = divergence_cleaning_field(u, equations)206207prim = zero(MVector{nvariables(equations), eltype(u)})208prim[1] = B1209prim[2] = B2210prim[3] = B3211for k in eachcomponent(equations)212rho, rho_v1, rho_v2, rho_v3, rho_e = get_component(k, u, equations)213rho_inv = 1 / rho214v1 = rho_inv * rho_v1215v2 = rho_inv * rho_v2216v3 = rho_inv * rho_v3217218p = (gammas[k] - 1) * (rho_e -2190.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3220+ B1 * B1 + B2 * B2 + B3 * B3221+ psi * psi))222223set_component!(prim, k, rho, v1, v2, v3, p, equations)224end225prim[end] = psi226227return SVector(prim)228end229230#Convert conservative variables to entropy variables231@inline function cons2entropy(u, equations::AbstractIdealGlmMhdMultiIonEquations)232@unpack gammas = equations233B1, B2, B3 = magnetic_field(u, equations)234psi = divergence_cleaning_field(u, equations)235236prim = cons2prim(u, equations)237entropy = zero(MVector{nvariables(equations), eltype(u)})238rho_p_plus = zero(real(equations))239for k in eachcomponent(equations)240rho, v1, v2, v3, p = get_component(k, prim, equations)241s = log(p) - gammas[k] * log(rho)242rho_p = rho / p243w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5f0 * rho_p * (v1^2 + v2^2 + v3^2)244w2 = rho_p * v1245w3 = rho_p * v2246w4 = rho_p * v3247w5 = -rho_p248rho_p_plus += rho_p249250set_component!(entropy, k, w1, w2, w3, w4, w5, equations)251end252253# Additional non-conservative variables254entropy[1] = rho_p_plus * B1255entropy[2] = rho_p_plus * B2256entropy[3] = rho_p_plus * B3257entropy[end] = rho_p_plus * psi258259return SVector(entropy)260end261262# Convert primitive to conservative variables263@inline function prim2cons(prim, equations::AbstractIdealGlmMhdMultiIonEquations)264@unpack gammas = equations265B1, B2, B3 = magnetic_field(prim, equations)266psi = divergence_cleaning_field(prim, equations)267268cons = zero(MVector{nvariables(equations), eltype(prim)})269cons[1] = B1270cons[2] = B2271cons[3] = B3272for k in eachcomponent(equations)273rho, v1, v2, v3, p = get_component(k, prim, equations)274rho_v1 = rho * v1275rho_v2 = rho * v2276rho_v3 = rho * v3277278rho_e = p / (gammas[k] - 1) +2790.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) +2800.5f0 * (B1^2 + B2^2 + B3^2) +2810.5f0 * psi^2282283set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e, equations)284end285cons[end] = psi286287return SVector(cons)288end289290# Specialization of [`DissipationLaxFriedrichsEntropyVariables`](@ref) for the multi-ion GLM-MHD equations291# For details on the multi-ion entropy Jacobian ``H`` see292# - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization293# of the Ideal Multi-Ion Magnetohydrodynamics System (2024). Journal of Computational Physics.294# [DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655).295# Since the entropy Jacobian is a sparse matrix, we do not construct it but directly compute the296# action of its product with the jump in the entropy variables.297#298# ATTENTION: the variable order for AbstractIdealGlmMhdMultiIonEquations is different than in the reference above.299# The first three entries of the state vector `u[1:3]` are the magnetic field components. After that, we have chunks300# of 5 entries for the hydrodynamic quantities of each ion species. Finally, the last entry `u[end]` is the divergence301# cleaning field.302@inline function (dissipation::DissipationLaxFriedrichsEntropyVariables)(u_ll, u_rr,303orientation_or_normal_direction,304equations::AbstractIdealGlmMhdMultiIonEquations)305@unpack gammas = equations306λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction,307equations)308309w_ll = cons2entropy(u_ll, equations)310w_rr = cons2entropy(u_rr, equations)311prim_ll = cons2prim(u_ll, equations)312prim_rr = cons2prim(u_rr, equations)313B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations)314B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations)315psi_ll = divergence_cleaning_field(u_ll, equations)316psi_rr = divergence_cleaning_field(u_rr, equations)317318# Some global averages319B1_avg = 0.5f0 * (B1_ll + B1_rr)320B2_avg = 0.5f0 * (B2_ll + B2_rr)321B3_avg = 0.5f0 * (B3_ll + B3_rr)322psi_avg = 0.5f0 * (psi_ll + psi_rr)323324dissipation = zero(MVector{nvariables(equations), eltype(u_ll)})325326beta_plus_ll = 0327beta_plus_rr = 0328329# Compute the dissipation for the hydrodynamic quantities of each ion species `k`330#################################################################################331332# The for loop below fills the entries of `dissipation` that depend on the entries of the diagonal333# blocks ``A_k`` of the entropy Jacobian ``H`` in the given reference (see equations (80)-(82)),334# but the terms that depend on the magnetic field ``B`` and divergence cleaning field ``psi`` are335# excluded here and considered below. In other words, these are the dissipation values that depend336# on the entries of the entropy Jacobian that are marked in blue in Figure 1 of the reference given above.337for k in eachcomponent(equations)338rho_ll, v1_ll, v2_ll, v3_ll, p_ll = get_component(k, prim_ll, equations)339rho_rr, v1_rr, v2_rr, v3_rr, p_rr = get_component(k, prim_rr, equations)340341w1_ll, w2_ll, w3_ll, w4_ll, w5_ll = get_component(k, w_ll, equations)342w1_rr, w2_rr, w3_rr, w4_rr, w5_rr = get_component(k, w_rr, equations)343344# Auxiliary variables345beta_ll = 0.5f0 * rho_ll / p_ll346beta_rr = 0.5f0 * rho_rr / p_rr347vel_norm_ll = v1_ll^2 + v2_ll^2 + v3_ll^2348vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2349350# Mean variables351rho_ln = ln_mean(rho_ll, rho_rr)352beta_ln = ln_mean(beta_ll, beta_rr)353rho_avg = 0.5f0 * (rho_ll + rho_rr)354v1_avg = 0.5f0 * (v1_ll + v1_rr)355v2_avg = 0.5f0 * (v2_ll + v2_rr)356v3_avg = 0.5f0 * (v3_ll + v3_rr)357beta_avg = 0.5f0 * (beta_ll + beta_rr)358tau = 1 / (beta_ll + beta_rr)359p_mean = 0.5f0 * rho_avg / beta_avg360p_star = 0.5f0 * rho_ln / beta_ln361vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr)362vel_avg_norm = v1_avg^2 + v2_avg^2 + v3_avg^2363E_bar = p_star / (gammas[k] - 1) +3640.5f0 * rho_ln * (2 * vel_avg_norm - vel_norm_avg)365366h11 = rho_ln367h12 = rho_ln * v1_avg368h13 = rho_ln * v2_avg369h14 = rho_ln * v3_avg370h15 = E_bar371d1 = -0.5f0 * λ *372(h11 * (w1_rr - w1_ll) +373h12 * (w2_rr - w2_ll) +374h13 * (w3_rr - w3_ll) +375h14 * (w4_rr - w4_ll) +376h15 * (w5_rr - w5_ll))377378h21 = h12379h22 = rho_ln * v1_avg^2 + p_mean380h23 = h21 * v2_avg381h24 = h21 * v3_avg382h25 = (E_bar + p_mean) * v1_avg383d2 = -0.5f0 * λ *384(h21 * (w1_rr - w1_ll) +385h22 * (w2_rr - w2_ll) +386h23 * (w3_rr - w3_ll) +387h24 * (w4_rr - w4_ll) +388h25 * (w5_rr - w5_ll))389390h31 = h13391h32 = h23392h33 = rho_ln * v2_avg^2 + p_mean393h34 = h31 * v3_avg394h35 = (E_bar + p_mean) * v2_avg395d3 = -0.5f0 * λ *396(h31 * (w1_rr - w1_ll) +397h32 * (w2_rr - w2_ll) +398h33 * (w3_rr - w3_ll) +399h34 * (w4_rr - w4_ll) +400h35 * (w5_rr - w5_ll))401402h41 = h14403h42 = h24404h43 = h34405h44 = rho_ln * v3_avg^2 + p_mean406h45 = (E_bar + p_mean) * v3_avg407d4 = -0.5f0 * λ *408(h41 * (w1_rr - w1_ll) +409h42 * (w2_rr - w2_ll) +410h43 * (w3_rr - w3_ll) +411h44 * (w4_rr - w4_ll) +412h45 * (w5_rr - w5_ll))413414h51 = h15415h52 = h25416h53 = h35417h54 = h45418h55 = ((p_star^2 / (gammas[k] - 1) + E_bar * E_bar) / rho_ln419+420vel_avg_norm * p_mean)421d5 = -0.5f0 * λ *422(h51 * (w1_rr - w1_ll) +423h52 * (w2_rr - w2_ll) +424h53 * (w3_rr - w3_ll) +425h54 * (w4_rr - w4_ll) +426h55 * (w5_rr - w5_ll))427428beta_plus_ll += beta_ll429beta_plus_rr += beta_rr430431set_component!(dissipation, k, d1, d2, d3, d4, d5, equations)432end433434# Compute the dissipation related to the magnetic and divergence-cleaning fields435################################################################################436437h_B_psi = 1 / (beta_plus_ll + beta_plus_rr)438439# Dissipation for the magnetic field components due to the diagonal entries of the440# dissipation matrix ``H``. These are the dissipation values that depend on the diagonal441# entries of the entropy Jacobian that are marked in cyan in Figure 1 of the reference given above.442dissipation[1] = -0.5f0 * λ * h_B_psi * (w_rr[1] - w_ll[1])443dissipation[2] = -0.5f0 * λ * h_B_psi * (w_rr[2] - w_ll[2])444dissipation[3] = -0.5f0 * λ * h_B_psi * (w_rr[3] - w_ll[3])445446# Dissipation for the divergence-cleaning field due to the diagonal entry of the447# dissipation matrix ``H``. This dissipation value depends on the single diagonal448# entry of the entropy Jacobian that is marked in red in Figure 1 of the reference given above.449dissipation[end] = -0.5f0 * λ * h_B_psi * (w_rr[end] - w_ll[end])450451# Dissipation due to the off-diagonal blocks (``B_{off}``) of the dissipation matrix ``H`` and to the entries452# of the block ``A`` that depend on the magnetic field ``B`` and the divergence cleaning field ``psi``.453# See equations (80)-(82) of the given reference.454for k in eachcomponent(equations)455_, _, _, _, w5_ll = get_component(k, w_ll, equations)456_, _, _, _, w5_rr = get_component(k, w_rr, equations)457458# Dissipation for the magnetic field components and divergence cleaning field due to the off-diagonal459# entries of the dissipation matrix ``H`` (block ``B^T`` in equation (80) and Figure 1 of the reference460# given above).461dissipation[1] -= 0.5f0 * λ * h_B_psi * B1_avg * (w5_rr - w5_ll)462dissipation[2] -= 0.5f0 * λ * h_B_psi * B2_avg * (w5_rr - w5_ll)463dissipation[3] -= 0.5f0 * λ * h_B_psi * B3_avg * (w5_rr - w5_ll)464dissipation[end] -= 0.5f0 * λ * h_B_psi * psi_avg * (w5_rr - w5_ll)465466# Dissipation for the energy equation of species `k` depending on `w_1`, `w_2`, `w_3` and `w_end`. These are the467# values of the dissipation that depend on the off-diagonal block ``B`` of the dissipation matrix ``H`` (see equation (80)468# and Figure 1 of the reference given above.469ind_E = 3 + 5 * k # simplified version of 3 + (k - 1) * 5 + 5470dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B1_avg * (w_rr[1] - w_ll[1])471dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B2_avg * (w_rr[2] - w_ll[2])472dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B3_avg * (w_rr[3] - w_ll[3])473dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * psi_avg * (w_rr[end] - w_ll[end])474475# Dissipation for the energy equation of all ion species depending on `w_5`. These are the values of the dissipation476# vector that depend on the magnetic and divergence-cleaning field terms of the entries marked with a red cross in477# Figure 1 of the reference given above.478for kk in eachcomponent(equations)479ind_E = 3 + 5 * kk # simplified version of 3 + (kk - 1) * 5 + 5480dissipation[ind_E] -= 0.5f0 * λ *481(h_B_psi *482(B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2)) *483(w5_rr - w5_ll)484end485end486487return dissipation488end489490@doc raw"""491source_terms_collision_ion_ion(u, x, t,492equations::AbstractIdealGlmMhdMultiIonEquations)493494Compute the ion-ion collision source terms for the momentum and energy equations of each ion species as495```math496\begin{aligned}497\vec{s}_{\rho_k \vec{v}_k} =& \rho_k\sum_{l}\bar{\nu}_{kl}(\vec{v}_{l} - \vec{v}_k),\\498s_{E_k} =&4993 \sum_{l} \left(500\bar{\nu}_{kl} \frac{\rho_k M_1}{M_{l} + M_k} R_1 (T_{l} - T_k)501\right) +502\sum_{l} \left(503\bar{\nu}_{kl} \rho_k \frac{M_{l}}{M_{l} + M_k} \|\vec{v}_{l} - \vec{v}_k\|^2504\right)505+506\vec{v}_k \cdot \vec{s}_{\rho_k \vec{v}_k},507\end{aligned}508```509where ``M_k`` is the molar mass of ion species `k` provided in `equations.molar_masses`,510``R_k`` is the specific gas constant of ion species `k` provided in `equations.gas_constants`, and511``\bar{\nu}_{kl}`` is the effective collision frequency of species `k` with species `l`, which is computed as512```math513\begin{aligned}514\bar{\nu}_{kl} = \bar{\nu}^1_{kl} \tilde{B}_{kl} \frac{\rho_{l}}{T_{k l}^{3/2}},515\end{aligned}516```517with the so-called reduced temperature ``T_{k l}`` and the ion-ion collision constants ``\tilde{B}_{kl}`` provided518in `equations.ion_electron_collision_constants` (see [`IdealGlmMhdMultiIonEquations2D`](@ref)).519520The additional coefficient ``\bar{\nu}^1_{kl}`` is a non-dimensional drift correction factor proposed by Rambo and Denavit.521522References:523- P. Rambo, J. Denavit, Interpenetration and ion separation in colliding plasmas, Physics of Plasmas 1 (1994) 4050–4060.524[DOI: 10.1063/1.870875](https://doi.org/10.1063/1.870875).525- Schunk, R. W., Nagy, A. F. (2000). Ionospheres: Physics, plasma physics, and chemistry.526Cambridge university press. [DOI: 10.1017/CBO9780511635342](https://doi.org/10.1017/CBO9780511635342).527"""528function source_terms_collision_ion_ion(u, x, t,529equations::AbstractIdealGlmMhdMultiIonEquations)530s = zero(MVector{nvariables(equations), eltype(u)})531@unpack gas_constants, molar_masses, ion_ion_collision_constants = equations532533prim = cons2prim(u, equations)534535for k in eachcomponent(equations)536rho_k, v1_k, v2_k, v3_k, p_k = get_component(k, prim, equations)537T_k = p_k / (rho_k * gas_constants[k])538539S_q1 = zero(eltype(u))540S_q2 = zero(eltype(u))541S_q3 = zero(eltype(u))542S_E = zero(eltype(u))543for l in eachcomponent(equations)544# Do not compute collisions of an ion species with itself545k == l && continue546547rho_l, v1_l, v2_l, v3_l, p_l = get_component(l, prim, equations)548T_l = p_l / (rho_l * gas_constants[l])549550# Reduced temperature551T_kl = (molar_masses[l] * T_k + molar_masses[k] * T_l) /552(molar_masses[k] + molar_masses[l])553554delta_v2 = (v1_l - v1_k)^2 + (v2_l - v2_k)^2 + (v3_l - v3_k)^2555556# Compute collision frequency without drifting correction557v_kl = ion_ion_collision_constants[k, l] * rho_l / T_kl^(3 / 2)558559# Correct the collision frequency with the drifting effect560z2 = delta_v2 / (p_l / rho_l + p_k / rho_k)561v_kl /= (1 + (2 / (9 * pi))^(1 / 3) * z2)^(3 / 2)562563S_q1 += rho_k * v_kl * (v1_l - v1_k)564S_q2 += rho_k * v_kl * (v2_l - v2_k)565S_q3 += rho_k * v_kl * (v3_l - v3_k)566567S_E += (3 * molar_masses[1] * gas_constants[1] * (T_l - T_k)568+569molar_masses[l] * delta_v2) * v_kl * rho_k /570(molar_masses[k] + molar_masses[l])571end572573S_E += (v1_k * S_q1 + v2_k * S_q2 + v3_k * S_q3)574575set_component!(s, k, 0, S_q1, S_q2, S_q3, S_E, equations)576end577return SVector{nvariables(equations), real(equations)}(s)578end579580@doc raw"""581source_terms_collision_ion_electron(u, x, t,582equations::AbstractIdealGlmMhdMultiIonEquations)583584Compute the ion-electron collision source terms for the momentum and energy equations of each ion species. We assume ``v_e = v^+``585(no effect of currents on the electron velocity).586587The collision sources read as588```math589\begin{aligned}590\vec{s}_{\rho_k \vec{v}_k} =& \rho_k \bar{\nu}_{ke} (\vec{v}_{e} - \vec{v}_k),591\\592s_{E_k} =&5933 \left(594\bar{\nu}_{ke} \frac{\rho_k M_{1}}{M_k} R_1 (T_{e} - T_k)595\right)596+597\vec{v}_k \cdot \vec{s}_{\rho_k \vec{v}_k},598\end{aligned}599```600where ``T_e`` is the electron temperature computed with the function `equations.electron_temperature`,601``M_k`` is the molar mass of ion species `k` provided in `equations.molar_masses`,602``R_k`` is the specific gas constant of ion species `k` provided in `equations.gas_constants`, and603``\bar{\nu}_{ke}`` is the collision frequency of species `k` with the electrons, which is computed as604```math605\begin{aligned}606\bar{\nu}_{ke} = \tilde{B}_{ke} \frac{e n_e}{T_e^{3/2}},607\end{aligned}608```609with the total electron charge ``e n_e`` (computed assuming quasi-neutrality), and the610ion-electron collision coefficient ``\tilde{B}_{ke}`` provided in `equations.ion_electron_collision_constants`,611which is scaled with the elementary charge (see [`IdealGlmMhdMultiIonEquations2D`](@ref)).612613References:614- P. Rambo, J. Denavit, Interpenetration and ion separation in colliding plasmas, Physics of Plasmas 1 (1994) 4050–4060.615[DOI: 10.1063/1.870875](https://doi.org/10.1063/1.870875).616- Schunk, R. W., Nagy, A. F. (2000). Ionospheres: Physics, plasma physics, and chemistry.617Cambridge university press. [DOI: 10.1017/CBO9780511635342](https://doi.org/10.1017/CBO9780511635342).618"""619function source_terms_collision_ion_electron(u, x, t,620equations::AbstractIdealGlmMhdMultiIonEquations)621s = zero(MVector{nvariables(equations), eltype(u)})622@unpack gas_constants, molar_masses, ion_electron_collision_constants, electron_temperature = equations623624prim = cons2prim(u, equations)625T_e = electron_temperature(u, equations)626T_e_power32 = T_e^(3 / 2)627628v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u,629equations)630631# Compute total electron charge632total_electron_charge = zero(real(equations))633for k in eachcomponent(equations)634rho, _ = get_component(k, u, equations)635total_electron_charge += rho * equations.charge_to_mass[k]636end637638for k in eachcomponent(equations)639rho_k, v1_k, v2_k, v3_k, p_k = get_component(k, prim, equations)640T_k = p_k / (rho_k * gas_constants[k])641642# Compute effective collision frequency643v_ke = ion_electron_collision_constants[k] * total_electron_charge / T_e_power32644645S_q1 = rho_k * v_ke * (v1_plus - v1_k)646S_q2 = rho_k * v_ke * (v2_plus - v2_k)647S_q3 = rho_k * v_ke * (v3_plus - v3_k)648649S_E = 3 * molar_masses[1] * gas_constants[1] * (T_e - T_k) * v_ke * rho_k /650molar_masses[k]651652S_E += (v1_k * S_q1 + v2_k * S_q2 + v3_k * S_q3)653654set_component!(s, k, 0, S_q1, S_q2, S_q3, S_E, equations)655end656return SVector{nvariables(equations), real(equations)}(s)657end658end659660661