Path: blob/main/src/equations/ideal_glm_mhd_multiion.jl
5586 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_total_" * 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)44return (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_total = 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@doc raw"""177density(u, equations::AbstractIdealGlmMhdMultiIonEquations)178179Computes the total density ``\rho = \sum_{i=1}^n \rho_i`` from the conserved variables `u`,180where ``i`` is the index of **ion** species.181"""182@inline function density(u, equations::AbstractIdealGlmMhdMultiIonEquations)183rho = zero(real(equations))184for k in eachcomponent(equations)185rho += u[3 + (k - 1) * 5 + 1]186end187return rho188end189190@doc raw"""191pressure(u, equations::AbstractIdealGlmMhdMultiIonEquations)192193Computes the pressure of every component ``k`` analogouos to194[`pressure(u, equations::IdealGlmMhdEquations1D)`](@ref).195"""196@inline function pressure(u, equations::AbstractIdealGlmMhdMultiIonEquations)197B1, B2, B3, _ = u198p = zero(MVector{ncomponents(equations), real(equations)})199for k in eachcomponent(equations)200rho, rho_v1, rho_v2, rho_v3, rho_e_total = get_component(k, u, equations)201v1 = rho_v1 / rho202v2 = rho_v2 / rho203v3 = rho_v3 / rho204gamma = equations.gammas[k]205p[k] = (gamma - 1) * (rho_e_total - 0.5f0 *206(rho * (v1^2 + v2^2 + v3^2) + B1^2 + B2^2 + B3^2))207end208return SVector{ncomponents(equations), real(equations)}(p)209end210211#Convert conservative variables to primitive212function cons2prim(u, equations::AbstractIdealGlmMhdMultiIonEquations)213@unpack gammas = equations214B1, B2, B3 = magnetic_field(u, equations)215psi = divergence_cleaning_field(u, equations)216217prim = zero(MVector{nvariables(equations), eltype(u)})218prim[1] = B1219prim[2] = B2220prim[3] = B3221for k in eachcomponent(equations)222rho, rho_v1, rho_v2, rho_v3, rho_e_total = get_component(k, u, equations)223rho_inv = 1 / rho224v1 = rho_inv * rho_v1225v2 = rho_inv * rho_v2226v3 = rho_inv * rho_v3227228p = (gammas[k] - 1) * (rho_e_total -2290.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3230+ B1 * B1 + B2 * B2 + B3 * B3231+ psi * psi))232233set_component!(prim, k, rho, v1, v2, v3, p, equations)234end235prim[end] = psi236237return SVector(prim)238end239240#Convert conservative variables to entropy variables241@inline function cons2entropy(u, equations::AbstractIdealGlmMhdMultiIonEquations)242@unpack gammas = equations243B1, B2, B3 = magnetic_field(u, equations)244psi = divergence_cleaning_field(u, equations)245246prim = cons2prim(u, equations)247entropy = zero(MVector{nvariables(equations), eltype(u)})248rho_p_plus = zero(real(equations))249for k in eachcomponent(equations)250rho, v1, v2, v3, p = get_component(k, prim, equations)251s = log(p) - gammas[k] * log(rho)252rho_p = rho / p253w1 = (gammas[k] - s) / (gammas[k] - 1) - 0.5f0 * rho_p * (v1^2 + v2^2 + v3^2)254w2 = rho_p * v1255w3 = rho_p * v2256w4 = rho_p * v3257w5 = -rho_p258rho_p_plus += rho_p259260set_component!(entropy, k, w1, w2, w3, w4, w5, equations)261end262263# Additional non-conservative variables264entropy[1] = rho_p_plus * B1265entropy[2] = rho_p_plus * B2266entropy[3] = rho_p_plus * B3267entropy[end] = rho_p_plus * psi268269return SVector(entropy)270end271272# Convert primitive to conservative variables273@inline function prim2cons(prim, equations::AbstractIdealGlmMhdMultiIonEquations)274@unpack gammas = equations275B1, B2, B3 = magnetic_field(prim, equations)276psi = divergence_cleaning_field(prim, equations)277278cons = zero(MVector{nvariables(equations), eltype(prim)})279cons[1] = B1280cons[2] = B2281cons[3] = B3282for k in eachcomponent(equations)283rho, v1, v2, v3, p = get_component(k, prim, equations)284rho_v1 = rho * v1285rho_v2 = rho * v2286rho_v3 = rho * v3287288rho_e_total = p / (gammas[k] - 1) +2890.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) +2900.5f0 * (B1^2 + B2^2 + B3^2) +2910.5f0 * psi^2292293set_component!(cons, k, rho, rho_v1, rho_v2, rho_v3, rho_e_total, equations)294end295cons[end] = psi296297return SVector(cons)298end299300# Specialization of [`DissipationLaxFriedrichsEntropyVariables`](@ref) for the multi-ion GLM-MHD equations301# For details on the multi-ion entropy Jacobian ``H`` see302# - A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization303# of the Ideal Multi-Ion Magnetohydrodynamics System (2024). Journal of Computational Physics.304# [DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655).305# Since the entropy Jacobian is a sparse matrix, we do not construct it but directly compute the306# action of its product with the jump in the entropy variables.307#308# ATTENTION: the variable order for AbstractIdealGlmMhdMultiIonEquations is different than in the reference above.309# The first three entries of the state vector `u[1:3]` are the magnetic field components. After that, we have chunks310# of 5 entries for the hydrodynamic quantities of each ion species. Finally, the last entry `u[end]` is the divergence311# cleaning field.312@inline function (dissipation::DissipationLaxFriedrichsEntropyVariables)(u_ll, u_rr,313orientation_or_normal_direction,314equations::AbstractIdealGlmMhdMultiIonEquations)315@unpack gammas = equations316λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction,317equations)318319w_ll = cons2entropy(u_ll, equations)320w_rr = cons2entropy(u_rr, equations)321prim_ll = cons2prim(u_ll, equations)322prim_rr = cons2prim(u_rr, equations)323B1_ll, B2_ll, B3_ll = magnetic_field(u_ll, equations)324B1_rr, B2_rr, B3_rr = magnetic_field(u_rr, equations)325psi_ll = divergence_cleaning_field(u_ll, equations)326psi_rr = divergence_cleaning_field(u_rr, equations)327328# Some global averages329B1_avg = 0.5f0 * (B1_ll + B1_rr)330B2_avg = 0.5f0 * (B2_ll + B2_rr)331B3_avg = 0.5f0 * (B3_ll + B3_rr)332psi_avg = 0.5f0 * (psi_ll + psi_rr)333334dissipation = zero(MVector{nvariables(equations), eltype(u_ll)})335336beta_plus_ll = 0337beta_plus_rr = 0338339# Compute the dissipation for the hydrodynamic quantities of each ion species `k`340#################################################################################341342# The for loop below fills the entries of `dissipation` that depend on the entries of the diagonal343# blocks ``A_k`` of the entropy Jacobian ``H`` in the given reference (see equations (80)-(82)),344# but the terms that depend on the magnetic field ``B`` and divergence cleaning field ``psi`` are345# excluded here and considered below. In other words, these are the dissipation values that depend346# on the entries of the entropy Jacobian that are marked in blue in Figure 1 of the reference given above.347for k in eachcomponent(equations)348rho_ll, v1_ll, v2_ll, v3_ll, p_ll = get_component(k, prim_ll, equations)349rho_rr, v1_rr, v2_rr, v3_rr, p_rr = get_component(k, prim_rr, equations)350351w1_ll, w2_ll, w3_ll, w4_ll, w5_ll = get_component(k, w_ll, equations)352w1_rr, w2_rr, w3_rr, w4_rr, w5_rr = get_component(k, w_rr, equations)353354# Auxiliary variables355beta_ll = 0.5f0 * rho_ll / p_ll356beta_rr = 0.5f0 * rho_rr / p_rr357vel_norm_ll = v1_ll^2 + v2_ll^2 + v3_ll^2358vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2359360# Mean variables361rho_ln = ln_mean(rho_ll, rho_rr)362beta_ln = ln_mean(beta_ll, beta_rr)363rho_avg = 0.5f0 * (rho_ll + rho_rr)364v1_avg = 0.5f0 * (v1_ll + v1_rr)365v2_avg = 0.5f0 * (v2_ll + v2_rr)366v3_avg = 0.5f0 * (v3_ll + v3_rr)367beta_avg = 0.5f0 * (beta_ll + beta_rr)368tau = 1 / (beta_ll + beta_rr)369p_mean = 0.5f0 * rho_avg / beta_avg370p_star = 0.5f0 * rho_ln / beta_ln371vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr)372vel_avg_norm = v1_avg^2 + v2_avg^2 + v3_avg^2373E_bar = p_star / (gammas[k] - 1) +3740.5f0 * rho_ln * (2 * vel_avg_norm - vel_norm_avg)375376h11 = rho_ln377h12 = rho_ln * v1_avg378h13 = rho_ln * v2_avg379h14 = rho_ln * v3_avg380h15 = E_bar381d1 = -0.5f0 * λ *382(h11 * (w1_rr - w1_ll) +383h12 * (w2_rr - w2_ll) +384h13 * (w3_rr - w3_ll) +385h14 * (w4_rr - w4_ll) +386h15 * (w5_rr - w5_ll))387388h21 = h12389h22 = rho_ln * v1_avg^2 + p_mean390h23 = h21 * v2_avg391h24 = h21 * v3_avg392h25 = (E_bar + p_mean) * v1_avg393d2 = -0.5f0 * λ *394(h21 * (w1_rr - w1_ll) +395h22 * (w2_rr - w2_ll) +396h23 * (w3_rr - w3_ll) +397h24 * (w4_rr - w4_ll) +398h25 * (w5_rr - w5_ll))399400h31 = h13401h32 = h23402h33 = rho_ln * v2_avg^2 + p_mean403h34 = h31 * v3_avg404h35 = (E_bar + p_mean) * v2_avg405d3 = -0.5f0 * λ *406(h31 * (w1_rr - w1_ll) +407h32 * (w2_rr - w2_ll) +408h33 * (w3_rr - w3_ll) +409h34 * (w4_rr - w4_ll) +410h35 * (w5_rr - w5_ll))411412h41 = h14413h42 = h24414h43 = h34415h44 = rho_ln * v3_avg^2 + p_mean416h45 = (E_bar + p_mean) * v3_avg417d4 = -0.5f0 * λ *418(h41 * (w1_rr - w1_ll) +419h42 * (w2_rr - w2_ll) +420h43 * (w3_rr - w3_ll) +421h44 * (w4_rr - w4_ll) +422h45 * (w5_rr - w5_ll))423424h51 = h15425h52 = h25426h53 = h35427h54 = h45428h55 = ((p_star^2 / (gammas[k] - 1) + E_bar * E_bar) / rho_ln429+430vel_avg_norm * p_mean)431d5 = -0.5f0 * λ *432(h51 * (w1_rr - w1_ll) +433h52 * (w2_rr - w2_ll) +434h53 * (w3_rr - w3_ll) +435h54 * (w4_rr - w4_ll) +436h55 * (w5_rr - w5_ll))437438beta_plus_ll += beta_ll439beta_plus_rr += beta_rr440441set_component!(dissipation, k, d1, d2, d3, d4, d5, equations)442end443444# Compute the dissipation related to the magnetic and divergence-cleaning fields445################################################################################446447h_B_psi = 1 / (beta_plus_ll + beta_plus_rr)448449# Dissipation for the magnetic field components due to the diagonal entries of the450# dissipation matrix ``H``. These are the dissipation values that depend on the diagonal451# entries of the entropy Jacobian that are marked in cyan in Figure 1 of the reference given above.452dissipation[1] = -0.5f0 * λ * h_B_psi * (w_rr[1] - w_ll[1])453dissipation[2] = -0.5f0 * λ * h_B_psi * (w_rr[2] - w_ll[2])454dissipation[3] = -0.5f0 * λ * h_B_psi * (w_rr[3] - w_ll[3])455456# Dissipation for the divergence-cleaning field due to the diagonal entry of the457# dissipation matrix ``H``. This dissipation value depends on the single diagonal458# entry of the entropy Jacobian that is marked in red in Figure 1 of the reference given above.459dissipation[end] = -0.5f0 * λ * h_B_psi * (w_rr[end] - w_ll[end])460461# Dissipation due to the off-diagonal blocks (``B_{off}``) of the dissipation matrix ``H`` and to the entries462# of the block ``A`` that depend on the magnetic field ``B`` and the divergence cleaning field ``psi``.463# See equations (80)-(82) of the given reference.464for k in eachcomponent(equations)465_, _, _, _, w5_ll = get_component(k, w_ll, equations)466_, _, _, _, w5_rr = get_component(k, w_rr, equations)467468# Dissipation for the magnetic field components and divergence cleaning field due to the off-diagonal469# entries of the dissipation matrix ``H`` (block ``B^T`` in equation (80) and Figure 1 of the reference470# given above).471dissipation[1] -= 0.5f0 * λ * h_B_psi * B1_avg * (w5_rr - w5_ll)472dissipation[2] -= 0.5f0 * λ * h_B_psi * B2_avg * (w5_rr - w5_ll)473dissipation[3] -= 0.5f0 * λ * h_B_psi * B3_avg * (w5_rr - w5_ll)474dissipation[end] -= 0.5f0 * λ * h_B_psi * psi_avg * (w5_rr - w5_ll)475476# Dissipation for the energy equation of species `k` depending on `w_1`, `w_2`, `w_3` and `w_end`. These are the477# values of the dissipation that depend on the off-diagonal block ``B`` of the dissipation matrix ``H`` (see equation (80)478# and Figure 1 of the reference given above.479ind_E = 3 + 5 * k # simplified version of 3 + (k - 1) * 5 + 5480dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B1_avg * (w_rr[1] - w_ll[1])481dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B2_avg * (w_rr[2] - w_ll[2])482dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * B3_avg * (w_rr[3] - w_ll[3])483dissipation[ind_E] -= 0.5f0 * λ * h_B_psi * psi_avg * (w_rr[end] - w_ll[end])484485# Dissipation for the energy equation of all ion species depending on `w_5`. These are the values of the dissipation486# vector that depend on the magnetic and divergence-cleaning field terms of the entries marked with a red cross in487# Figure 1 of the reference given above.488for kk in eachcomponent(equations)489ind_E = 3 + 5 * kk # simplified version of 3 + (kk - 1) * 5 + 5490dissipation[ind_E] -= 0.5f0 * λ *491(h_B_psi *492(B1_avg^2 + B2_avg^2 + B3_avg^2 + psi_avg^2)) *493(w5_rr - w5_ll)494end495end496497return dissipation498end499500@doc raw"""501source_terms_collision_ion_ion(u, x, t,502equations::AbstractIdealGlmMhdMultiIonEquations)503504Compute the ion-ion collision source terms for the momentum and energy equations of each ion species as505```math506\begin{aligned}507\vec{s}_{\rho_k \vec{v}_k} =& \rho_k\sum_{l}\bar{\nu}_{kl}(\vec{v}_{l} - \vec{v}_k),\\508s_{E_k} =&5093 \sum_{l} \left(510\bar{\nu}_{kl} \frac{\rho_k M_1}{M_{l} + M_k} R_1 (T_{l} - T_k)511\right) +512\sum_{l} \left(513\bar{\nu}_{kl} \rho_k \frac{M_{l}}{M_{l} + M_k} \|\vec{v}_{l} - \vec{v}_k\|^2514\right)515+516\vec{v}_k \cdot \vec{s}_{\rho_k \vec{v}_k},517\end{aligned}518```519where ``M_k`` is the molar mass of ion species `k` provided in `equations.molar_masses`,520``R_k`` is the specific gas constant of ion species `k` provided in `equations.gas_constants`, and521``\bar{\nu}_{kl}`` is the effective collision frequency of species `k` with species `l`, which is computed as522```math523\begin{aligned}524\bar{\nu}_{kl} = \bar{\nu}^1_{kl} \tilde{B}_{kl} \frac{\rho_{l}}{T_{k l}^{3/2}},525\end{aligned}526```527with the so-called reduced temperature ``T_{k l}`` and the ion-ion collision constants ``\tilde{B}_{kl}`` provided528in `equations.ion_electron_collision_constants` (see [`IdealGlmMhdMultiIonEquations2D`](@ref)).529530The additional coefficient ``\bar{\nu}^1_{kl}`` is a non-dimensional drift correction factor proposed by Rambo and Denavit.531532References:533- P. Rambo, J. Denavit, Interpenetration and ion separation in colliding plasmas, Physics of Plasmas 1 (1994) 4050–4060.534[DOI: 10.1063/1.870875](https://doi.org/10.1063/1.870875).535- Schunk, R. W., Nagy, A. F. (2000). Ionospheres: Physics, plasma physics, and chemistry.536Cambridge university press. [DOI: 10.1017/CBO9780511635342](https://doi.org/10.1017/CBO9780511635342).537"""538function source_terms_collision_ion_ion(u, x, t,539equations::AbstractIdealGlmMhdMultiIonEquations)540s = zero(MVector{nvariables(equations), eltype(u)})541@unpack gas_constants, molar_masses, ion_ion_collision_constants = equations542543prim = cons2prim(u, equations)544545for k in eachcomponent(equations)546rho_k, v1_k, v2_k, v3_k, p_k = get_component(k, prim, equations)547T_k = p_k / (rho_k * gas_constants[k])548549S_q1 = zero(eltype(u))550S_q2 = zero(eltype(u))551S_q3 = zero(eltype(u))552S_E = zero(eltype(u))553for l in eachcomponent(equations)554# Do not compute collisions of an ion species with itself555k == l && continue556557rho_l, v1_l, v2_l, v3_l, p_l = get_component(l, prim, equations)558T_l = p_l / (rho_l * gas_constants[l])559560# Reduced temperature561T_kl = (molar_masses[l] * T_k + molar_masses[k] * T_l) /562(molar_masses[k] + molar_masses[l])563564delta_v2 = (v1_l - v1_k)^2 + (v2_l - v2_k)^2 + (v3_l - v3_k)^2565566# Compute collision frequency without drifting correction567v_kl = ion_ion_collision_constants[k, l] * rho_l / T_kl^(3 / 2)568569# Correct the collision frequency with the drifting effect570z2 = delta_v2 / (p_l / rho_l + p_k / rho_k)571v_kl /= (1 + (2 / (9 * pi))^(1 / 3) * z2)^(3 / 2)572573S_q1 += rho_k * v_kl * (v1_l - v1_k)574S_q2 += rho_k * v_kl * (v2_l - v2_k)575S_q3 += rho_k * v_kl * (v3_l - v3_k)576577S_E += (3 * molar_masses[1] * gas_constants[1] * (T_l - T_k)578+579molar_masses[l] * delta_v2) * v_kl * rho_k /580(molar_masses[k] + molar_masses[l])581end582583S_E += (v1_k * S_q1 + v2_k * S_q2 + v3_k * S_q3)584585set_component!(s, k, 0, S_q1, S_q2, S_q3, S_E, equations)586end587return SVector{nvariables(equations), real(equations)}(s)588end589590@doc raw"""591source_terms_collision_ion_electron(u, x, t,592equations::AbstractIdealGlmMhdMultiIonEquations)593594Compute the ion-electron collision source terms for the momentum and energy equations of each ion species. We assume ``v_e = v^+``595(no effect of currents on the electron velocity).596597The collision sources read as598```math599\begin{aligned}600\vec{s}_{\rho_k \vec{v}_k} =& \rho_k \bar{\nu}_{ke} (\vec{v}_{e} - \vec{v}_k),601\\602s_{E_k} =&6033 \left(604\bar{\nu}_{ke} \frac{\rho_k M_{1}}{M_k} R_1 (T_{e} - T_k)605\right)606+607\vec{v}_k \cdot \vec{s}_{\rho_k \vec{v}_k},608\end{aligned}609```610where ``T_e`` is the electron temperature computed with the function `equations.electron_temperature`,611``M_k`` is the molar mass of ion species `k` provided in `equations.molar_masses`,612``R_k`` is the specific gas constant of ion species `k` provided in `equations.gas_constants`, and613``\bar{\nu}_{ke}`` is the collision frequency of species `k` with the electrons, which is computed as614```math615\begin{aligned}616\bar{\nu}_{ke} = \tilde{B}_{ke} \frac{e n_e}{T_e^{3/2}},617\end{aligned}618```619with the total electron charge ``e n_e`` (computed assuming quasi-neutrality), and the620ion-electron collision coefficient ``\tilde{B}_{ke}`` provided in `equations.ion_electron_collision_constants`,621which is scaled with the elementary charge (see [`IdealGlmMhdMultiIonEquations2D`](@ref)).622623References:624- P. Rambo, J. Denavit, Interpenetration and ion separation in colliding plasmas, Physics of Plasmas 1 (1994) 4050–4060.625[DOI: 10.1063/1.870875](https://doi.org/10.1063/1.870875).626- Schunk, R. W., Nagy, A. F. (2000). Ionospheres: Physics, plasma physics, and chemistry.627Cambridge university press. [DOI: 10.1017/CBO9780511635342](https://doi.org/10.1017/CBO9780511635342).628"""629function source_terms_collision_ion_electron(u, x, t,630equations::AbstractIdealGlmMhdMultiIonEquations)631s = zero(MVector{nvariables(equations), eltype(u)})632@unpack gas_constants, molar_masses, ion_electron_collision_constants, electron_temperature = equations633634prim = cons2prim(u, equations)635T_e = electron_temperature(u, equations)636T_e_power32 = T_e^(3 / 2)637638v1_plus, v2_plus, v3_plus, vk1_plus, vk2_plus, vk3_plus = charge_averaged_velocities(u,639equations)640641# Compute total electron charge642total_electron_charge = zero(real(equations))643for k in eachcomponent(equations)644rho, _ = get_component(k, u, equations)645total_electron_charge += rho * equations.charge_to_mass[k]646end647648for k in eachcomponent(equations)649rho_k, v1_k, v2_k, v3_k, p_k = get_component(k, prim, equations)650T_k = p_k / (rho_k * gas_constants[k])651652# Compute effective collision frequency653v_ke = ion_electron_collision_constants[k] * total_electron_charge / T_e_power32654655S_q1 = rho_k * v_ke * (v1_plus - v1_k)656S_q2 = rho_k * v_ke * (v2_plus - v2_k)657S_q3 = rho_k * v_ke * (v3_plus - v3_k)658659S_E = 3 * molar_masses[1] * gas_constants[1] * (T_e - T_k) * v_ke * rho_k /660molar_masses[k]661662S_E += (v1_k * S_q1 + v2_k * S_q2 + v3_k * S_q3)663664set_component!(s, k, 0, S_q1, S_q2, S_q3, S_E, equations)665end666return SVector{nvariables(equations), real(equations)}(s)667end668end669670671