Path: blob/main/src/equations/ideal_glm_mhd_multicomponent_2d.jl
2055 views
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).1# Since these FMAs can increase the performance of many numerical algorithms,2# we need to opt-in explicitly.3# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.4@muladd begin5#! format: noindent67@doc raw"""8IdealGlmMhdMulticomponentEquations2D910The ideal compressible multicomponent GLM-MHD equations in two space dimensions.11"""12struct IdealGlmMhdMulticomponentEquations2D{NVARS, NCOMP, RealT <: Real} <:13AbstractIdealGlmMhdMulticomponentEquations{2, NVARS, NCOMP}14gammas::SVector{NCOMP, RealT}15gas_constants::SVector{NCOMP, RealT}16cv::SVector{NCOMP, RealT}17cp::SVector{NCOMP, RealT}18c_h::RealT # GLM cleaning speed1920function IdealGlmMhdMulticomponentEquations2D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP,21RealT},22gas_constants::SVector{NCOMP,23RealT},24c_h::RealT) where {25NVARS,26NCOMP,27RealT <:28Real29}30NCOMP >= 1 ||31throw(DimensionMismatch("`gammas` and `gas_constants` have to be filled with at least one value"))3233cv = gas_constants ./ (gammas .- 1)34cp = gas_constants + gas_constants ./ (gammas .- 1)3536new(gammas, gas_constants, cv, cp, c_h)37end38end3940function IdealGlmMhdMulticomponentEquations2D(; gammas, gas_constants)41_gammas = promote(gammas...)42_gas_constants = promote(gas_constants...)43RealT = promote_type(eltype(_gammas), eltype(_gas_constants))44__gammas = SVector(map(RealT, _gammas))45__gas_constants = SVector(map(RealT, _gas_constants))4647c_h = convert(RealT, NaN)4849NVARS = length(_gammas) + 850NCOMP = length(_gammas)5152return IdealGlmMhdMulticomponentEquations2D{NVARS, NCOMP, RealT}(__gammas,53__gas_constants,54c_h)55end5657# Outer constructor for `@reset` works correctly58function IdealGlmMhdMulticomponentEquations2D(gammas, gas_constants, cv, cp, c_h)59_gammas = promote(gammas...)60_gas_constants = promote(gas_constants...)61RealT = promote_type(eltype(_gammas), eltype(_gas_constants))62__gammas = SVector(map(RealT, _gammas))63__gas_constants = SVector(map(RealT, _gas_constants))6465c_h = convert(RealT, c_h)6667NVARS = length(_gammas) + 868NCOMP = length(_gammas)6970return IdealGlmMhdMulticomponentEquations2D{NVARS, NCOMP, RealT}(__gammas,71__gas_constants,72c_h)73end7475@inline function Base.real(::IdealGlmMhdMulticomponentEquations2D{NVARS, NCOMP, RealT}) where {76NVARS,77NCOMP,78RealT79}80RealT81end8283have_nonconservative_terms(::IdealGlmMhdMulticomponentEquations2D) = True()8485function varnames(::typeof(cons2cons), equations::IdealGlmMhdMulticomponentEquations2D)86cons = ("rho_v1", "rho_v2", "rho_v3", "rho_e", "B1", "B2", "B3", "psi")87rhos = ntuple(n -> "rho" * string(n), Val(ncomponents(equations)))88return (cons..., rhos...)89end9091function varnames(::typeof(cons2prim), equations::IdealGlmMhdMulticomponentEquations2D)92prim = ("v1", "v2", "v3", "p", "B1", "B2", "B3", "psi")93rhos = ntuple(n -> "rho" * string(n), Val(ncomponents(equations)))94return (prim..., rhos...)95end9697function default_analysis_integrals(::IdealGlmMhdMulticomponentEquations2D)98(entropy_timederivative, Val(:l2_divb), Val(:linf_divb))99end100101# Helper function to extract the magnetic field vector from the conservative variables102magnetic_field(u, equations::IdealGlmMhdMulticomponentEquations2D) = SVector(u[5], u[6],103u[7])104105"""106initial_condition_convergence_test(x, t, equations::IdealGlmMhdMulticomponentEquations2D)107108An Alfvén wave as smooth initial condition used for convergence tests.109"""110function initial_condition_convergence_test(x, t,111equations::IdealGlmMhdMulticomponentEquations2D)112# smooth Alfvén wave test from Derigs et al. FLASH (2016)113# domain must be set to [0, 1/cos(α)] x [0, 1/sin(α)], γ = 5/3114RealT = eltype(x)115alpha = 0.25f0 * convert(RealT, pi)116x_perp = x[1] * cos(alpha) + x[2] * sin(alpha)117B_perp = convert(RealT, 0.1) * sinpi(2 * x_perp)118rho = one(RealT)119prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i - 1) * (1 - 2) *120rho / (1 -1212^ncomponents(equations))122for i in eachcomponent(equations))123124v1 = -B_perp * sin(alpha)125v2 = B_perp * cos(alpha)126v3 = convert(RealT, 0.1) * cospi(2 * x_perp)127p = convert(RealT, 0.1)128B1 = cos(alpha) + v1129B2 = sin(alpha) + v2130B3 = v3131psi = 0132prim_other = SVector(v1, v2, v3, p, B1, B2, B3, psi)133134return prim2cons(vcat(prim_other, prim_rho), equations)135end136137"""138initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdMulticomponentEquations2D)139140A weak blast wave adapted from141- Sebastian Hennemann, Gregor J. Gassner (2020)142A provably entropy stable subcell shock capturing approach for high order split form DG143[arXiv: 2008.12044](https://arxiv.org/abs/2008.12044)144"""145function initial_condition_weak_blast_wave(x, t,146equations::IdealGlmMhdMulticomponentEquations2D)147# Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3)148# Same discontinuity in the velocities but with magnetic fields149# Set up polar coordinates150RealT = eltype(x)151inicenter = SVector(0, 0)152x_norm = x[1] - inicenter[1]153y_norm = x[2] - inicenter[2]154r = sqrt(x_norm^2 + y_norm^2)155phi = atan(y_norm, x_norm)156sin_phi, cos_phi = sincos(phi)157158# We initialize each species with a fraction of the total density `rho`, such159# that the sum of the densities is `rho := density(prim, equations)`. The density of160# a species is double the density of the next species.161prim_rho = SVector{ncomponents(equations), real(equations)}(r > 0.5f0 ?1622^(i - 1) * (1 - 2) /163(RealT(1) -1642^ncomponents(equations)) :1652^(i - 1) * (1 - 2) *166RealT(1.1691) /167(1 -1682^ncomponents(equations))169for i in eachcomponent(equations))170171v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos_phi172v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin_phi173p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245)174175prim_other = SVector(v1, v2, 0, p, 1, 1, 1, 0)176177return prim2cons(vcat(prim_other, prim_rho), equations)178end179180# Calculate 1D flux for a single point181@inline function flux(u, orientation::Integer,182equations::IdealGlmMhdMulticomponentEquations2D)183rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u184@unpack c_h = equations185186rho = density(u, equations)187188v1 = rho_v1 / rho189v2 = rho_v2 / rho190v3 = rho_v3 / rho191kin_en = 0.5f0 * rho * (v1^2 + v2^2 + v3^2)192mag_en = 0.5f0 * (B1^2 + B2^2 + B3^2)193gamma = totalgamma(u, equations)194p = (gamma - 1) * (rho_e - kin_en - mag_en - 0.5f0 * psi^2)195196if orientation == 1197f_rho = densities(u, v1, equations)198f1 = rho_v1 * v1 + p + mag_en - B1^2199f2 = rho_v1 * v2 - B1 * B2200f3 = rho_v1 * v3 - B1 * B3201f4 = (kin_en + gamma * p / (gamma - 1) + 2 * mag_en) * v1 -202B1 * (v1 * B1 + v2 * B2 + v3 * B3) + c_h * psi * B1203f5 = c_h * psi204f6 = v1 * B2 - v2 * B1205f7 = v1 * B3 - v3 * B1206f8 = c_h * B1207else # orientation == 2208f_rho = densities(u, v2, equations)209f1 = rho_v2 * v1 - B1 * B2210f2 = rho_v2 * v2 + p + mag_en - B2^2211f3 = rho_v2 * v3 - B2 * B3212f4 = (kin_en + gamma * p / (gamma - 1) + 2 * mag_en) * v2 -213B2 * (v1 * B1 + v2 * B2 + v3 * B3) + c_h * psi * B2214f5 = v2 * B1 - v1 * B2215f6 = c_h * psi216f7 = v2 * B3 - v3 * B2217f8 = c_h * B2218end219220f_other = SVector(f1, f2, f3, f4, f5, f6, f7, f8)221222return vcat(f_other, f_rho)223end224225"""226flux_nonconservative_powell(u_ll, u_rr, orientation::Integer,227equations::IdealGlmMhdMulticomponentEquations2D)228229Non-symmetric two-point flux discretizing the nonconservative (source) term of230Powell and the Galilean nonconservative term associated with the GLM multiplier231of the [`IdealGlmMhdMulticomponentEquations2D`](@ref).232233## References234- Marvin Bohm, Andrew R.Winters, Gregor J. Gassner, Dominik Derigs,235Florian Hindenlang, Joachim Saur236An entropy stable nodal discontinuous Galerkin method for the resistive MHD237equations. Part I: Theory and numerical verification238[DOI: 10.1016/j.jcp.2018.06.027](https://doi.org/10.1016/j.jcp.2018.06.027)239"""240@inline function flux_nonconservative_powell(u_ll, u_rr, orientation::Integer,241equations::IdealGlmMhdMulticomponentEquations2D)242rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll243rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr244245rho_ll = density(u_ll, equations)246247v1_ll = rho_v1_ll / rho_ll248v2_ll = rho_v2_ll / rho_ll249v3_ll = rho_v3_ll / rho_ll250v_dot_B_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll251252# Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0)253# Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2}, 0, 0, 0, v_{1,2})254# Note that the order of conserved variables is changed compared to the255# standard GLM MHD equations, i.e., the densities are moved to the end256# Here, we compute the non-density components at first and append zero density257# components afterwards258zero_densities = SVector{ncomponents(equations), real(equations)}(ntuple(_ -> zero(real(equations)),259Val(ncomponents(equations))))260if orientation == 1261f = SVector(B1_ll * B1_rr,262B2_ll * B1_rr,263B3_ll * B1_rr,264v_dot_B_ll * B1_rr + v1_ll * psi_ll * psi_rr,265v1_ll * B1_rr,266v2_ll * B1_rr,267v3_ll * B1_rr,268v1_ll * psi_rr)269else # orientation == 2270f = SVector(B1_ll * B2_rr,271B2_ll * B2_rr,272B3_ll * B2_rr,273v_dot_B_ll * B2_rr + v2_ll * psi_ll * psi_rr,274v1_ll * B2_rr,275v2_ll * B2_rr,276v3_ll * B2_rr,277v2_ll * psi_rr)278end279280return vcat(f, zero_densities)281end282283"""284flux_derigs_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdMulticomponentEquations2D)285286Entropy conserving two-point flux adapted by287- Derigs et al. (2018)288Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field289divergence diminishing ideal magnetohydrodynamics equations for multicomponent290[DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002)291"""292function flux_derigs_etal(u_ll, u_rr, orientation::Integer,293equations::IdealGlmMhdMulticomponentEquations2D)294# Unpack left and right states to get velocities, pressure, and inverse temperature (called beta)295rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll296rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr297@unpack gammas, gas_constants, cv, c_h = equations298299rho_ll = density(u_ll, equations)300rho_rr = density(u_rr, equations)301302gamma_ll = totalgamma(u_ll, equations)303gamma_rr = totalgamma(u_rr, equations)304305rhok_mean = SVector{ncomponents(equations), real(equations)}(ln_mean(u_ll[i + 8],306u_rr[i + 8])307for i in eachcomponent(equations))308rhok_avg = SVector{ncomponents(equations), real(equations)}(0.5f0 * (u_ll[i + 8] +309u_rr[i + 8])310for i in eachcomponent(equations))311312v1_ll = rho_v1_ll / rho_ll313v2_ll = rho_v2_ll / rho_ll314v3_ll = rho_v3_ll / rho_ll315v1_rr = rho_v1_rr / rho_rr316v2_rr = rho_v2_rr / rho_rr317v3_rr = rho_v3_rr / rho_rr318v1_sq = 0.5f0 * (v1_ll^2 + v1_rr^2)319v2_sq = 0.5f0 * (v2_ll^2 + v2_rr^2)320v3_sq = 0.5f0 * (v3_ll^2 + v3_rr^2)321v_sq = v1_sq + v2_sq + v3_sq322B1_sq = 0.5f0 * (B1_ll^2 + B1_rr^2)323B2_sq = 0.5f0 * (B2_ll^2 + B2_rr^2)324B3_sq = 0.5f0 * (B3_ll^2 + B3_rr^2)325B_sq = B1_sq + B2_sq + B3_sq326vel_norm_ll = v1_ll^2 + v2_ll^2 + v3_ll^2327vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2328mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2329mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2330# for convenience store v⋅B331vel_dot_mag_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll332vel_dot_mag_rr = v1_rr * B1_rr + v2_rr * B2_rr + v3_rr * B3_rr333334# Compute the necessary mean values needed for either direction335v1_avg = 0.5f0 * (v1_ll + v1_rr)336v2_avg = 0.5f0 * (v2_ll + v2_rr)337v3_avg = 0.5f0 * (v3_ll + v3_rr)338v_sum = v1_avg + v2_avg + v3_avg339B1_avg = 0.5f0 * (B1_ll + B1_rr)340B2_avg = 0.5f0 * (B2_ll + B2_rr)341B3_avg = 0.5f0 * (B3_ll + B3_rr)342psi_avg = 0.5f0 * (psi_ll + psi_rr)343vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr)344mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr)345vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr)346347RealT = eltype(u_ll)348enth = zero(RealT)349help1_ll = zero(RealT)350help1_rr = zero(RealT)351352for i in eachcomponent(equations)353enth += rhok_avg[i] * gas_constants[i]354help1_ll += u_ll[i + 8] * cv[i]355help1_rr += u_rr[i + 8] * cv[i]356end357358T_ll = (rho_e_ll - 0.5f0 * rho_ll * (vel_norm_ll) - 0.5f0 * mag_norm_ll -3590.5f0 * psi_ll^2) / help1_ll360T_rr = (rho_e_rr - 0.5f0 * rho_rr * (vel_norm_rr) - 0.5f0 * mag_norm_rr -3610.5f0 * psi_rr^2) / help1_rr362T = 0.5f0 * (1 / T_ll + 1 / T_rr)363T_log = ln_mean(1 / T_ll, 1 / T_rr)364365# Calculate fluxes depending on orientation with specific direction averages366help1 = zero(RealT)367help2 = zero(RealT)368if orientation == 1369f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * v1_avg370for i in eachcomponent(equations))371for i in eachcomponent(equations)372help1 += f_rho[i] * cv[i]373help2 += f_rho[i]374end375f1 = help2 * v1_avg + enth / T + 0.5f0 * mag_norm_avg - B1_avg * B1_avg376f2 = help2 * v2_avg - B1_avg * B2_avg377f3 = help2 * v3_avg - B1_avg * B3_avg378f5 = c_h * psi_avg379f6 = v1_avg * B2_avg - v2_avg * B1_avg380f7 = v1_avg * B3_avg - v3_avg * B1_avg381f8 = c_h * B1_avg382# total energy flux is complicated and involves the previous eight components383psi_B1_avg = 0.5f0 * (B1_ll * psi_ll + B1_rr * psi_rr)384v1_mag_avg = 0.5f0 * (v1_ll * mag_norm_ll + v1_rr * mag_norm_rr)385386f4 = (help1 / T_log) - 0.5f0 * (vel_norm_avg) * (help2) + f1 * v1_avg +387f2 * v2_avg + f3 * v3_avg +388f5 * B1_avg + f6 * B2_avg + f7 * B3_avg + f8 * psi_avg -3890.5f0 * v1_mag_avg +390B1_avg * vel_dot_mag_avg - c_h * psi_B1_avg391392else393f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * v2_avg394for i in eachcomponent(equations))395for i in eachcomponent(equations)396help1 += f_rho[i] * cv[i]397help2 += f_rho[i]398end399f1 = help2 * v1_avg - B1_avg * B2_avg400f2 = help2 * v2_avg + enth / T + 0.5f0 * mag_norm_avg - B2_avg * B2_avg401f3 = help2 * v3_avg - B2_avg * B3_avg402f5 = v2_avg * B1_avg - v1_avg * B2_avg403f6 = c_h * psi_avg404f7 = v2_avg * B3_avg - v3_avg * B2_avg405f8 = c_h * B2_avg406407# total energy flux is complicated and involves the previous eight components408psi_B2_avg = 0.5f0 * (B2_ll * psi_ll + B2_rr * psi_rr)409v2_mag_avg = 0.5f0 * (v2_ll * mag_norm_ll + v2_rr * mag_norm_rr)410411f4 = (help1 / T_log) - 0.5f0 * (vel_norm_avg) * (help2) + f1 * v1_avg +412f2 * v2_avg + f3 * v3_avg +413f5 * B1_avg + f6 * B2_avg + f7 * B3_avg + f8 * psi_avg -4140.5f0 * v2_mag_avg +415B2_avg * vel_dot_mag_avg - c_h * psi_B2_avg416end417418f_other = SVector(f1, f2, f3, f4, f5, f6, f7, f8)419420return vcat(f_other, f_rho)421end422423"""424flux_hindenlang_gassner(u_ll, u_rr, orientation_or_normal_direction,425equations::IdealGlmMhdMulticomponentEquations2D)426427Adaption of the entropy conserving and kinetic energy preserving two-point flux of428Hindenlang (2019), extending [`flux_ranocha`](@ref) to the MHD equations.429## References430- Florian Hindenlang, Gregor Gassner (2019)431A new entropy conservative two-point flux for ideal MHD equations derived from432first principles.433Presented at HONOM 2019: European workshop on high order numerical methods434for evolutionary PDEs, theory and applications435- Hendrik Ranocha (2018)436Generalised Summation-by-Parts Operators and Entropy Stability of Numerical Methods437for Hyperbolic Balance Laws438[PhD thesis, TU Braunschweig](https://cuvillier.de/en/shop/publications/7743)439- Hendrik Ranocha (2020)440Entropy Conserving and Kinetic Energy Preserving Numerical Methods for441the Euler Equations Using Summation-by-Parts Operators442[Proceedings of ICOSAHOM 2018](https://doi.org/10.1007/978-3-030-39647-3_42)443"""444@inline function flux_hindenlang_gassner(u_ll, u_rr, orientation::Integer,445equations::IdealGlmMhdMulticomponentEquations2D)446# Unpack left and right states447v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll, psi_ll = cons2prim(u_ll, equations)448v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr, psi_rr = cons2prim(u_rr, equations)449450rho_ll = density(u_ll, equations)451rho_rr = density(u_rr, equations)452453# Compute the necessary mean values needed for either direction454# Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)`455# in exact arithmetic since456# log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ)457# = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ)458inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)459v1_avg = 0.5f0 * (v1_ll + v1_rr)460v2_avg = 0.5f0 * (v2_ll + v2_rr)461v3_avg = 0.5f0 * (v3_ll + v3_rr)462p_avg = 0.5f0 * (p_ll + p_rr)463psi_avg = 0.5f0 * (psi_ll + psi_rr)464velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr + v3_ll * v3_rr)465magnetic_square_avg = 0.5f0 * (B1_ll * B1_rr + B2_ll * B2_rr + B3_ll * B3_rr)466467inv_gamma_minus_one = 1 / (totalgamma(0.5f0 * (u_ll + u_rr), equations) - 1)468469rhok_mean = SVector{ncomponents(equations), real(equations)}(ln_mean(u_ll[i + 8],470u_rr[i + 8])471for i in eachcomponent(equations))472rhok_avg = SVector{ncomponents(equations), real(equations)}(0.5f0 * (u_ll[i + 8] +473u_rr[i + 8])474for i in eachcomponent(equations))475476RealT = eltype(u_ll)477if orientation == 1478f1 = zero(RealT)479f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * v1_avg480for i in eachcomponent(equations))481for i in eachcomponent(equations)482f1 += f_rho[i]483end484485# Calculate fluxes depending on orientation with specific direction averages486f2 = f1 * v1_avg + p_avg + magnetic_square_avg -4870.5f0 * (B1_ll * B1_rr + B1_rr * B1_ll)488f3 = f1 * v2_avg - 0.5f0 * (B1_ll * B2_rr + B1_rr * B2_ll)489f4 = f1 * v3_avg - 0.5f0 * (B1_ll * B3_rr + B1_rr * B3_ll)490# f5 below491f6 = f6 = equations.c_h * psi_avg492f7 = 0.5f0 * (v1_ll * B2_ll - v2_ll * B1_ll + v1_rr * B2_rr - v2_rr * B1_rr)493f8 = 0.5f0 * (v1_ll * B3_ll - v3_ll * B1_ll + v1_rr * B3_rr - v3_rr * B1_rr)494f9 = equations.c_h * 0.5f0 * (B1_ll + B1_rr)495# total energy flux is complicated and involves the previous components496f5 = (f1 * (velocity_square_avg + inv_rho_p_mean * inv_gamma_minus_one)497+4980.5f0 * (+p_ll * v1_rr + p_rr * v1_ll499+ (v1_ll * B2_ll * B2_rr + v1_rr * B2_rr * B2_ll)500+ (v1_ll * B3_ll * B3_rr + v1_rr * B3_rr * B3_ll)501-502(v2_ll * B1_ll * B2_rr + v2_rr * B1_rr * B2_ll)503-504(v3_ll * B1_ll * B3_rr + v3_rr * B1_rr * B3_ll)505+506equations.c_h * (B1_ll * psi_rr + B1_rr * psi_ll)))507else508f1 = zero(RealT)509f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * v2_avg510for i in eachcomponent(equations))511for i in eachcomponent(equations)512f1 += f_rho[i]513end514515# Calculate fluxes depending on orientation with specific direction averages516f2 = f1 * v1_avg - 0.5f0 * (B2_ll * B1_rr + B2_rr * B1_ll)517f3 = f1 * v2_avg + p_avg + magnetic_square_avg -5180.5f0 * (B2_ll * B2_rr + B2_rr * B2_ll)519f4 = f1 * v3_avg - 0.5f0 * (B2_ll * B3_rr + B2_rr * B3_ll)520#f5 below521f6 = 0.5f0 * (v2_ll * B1_ll - v1_ll * B2_ll + v2_rr * B1_rr - v1_rr * B2_rr)522f7 = equations.c_h * psi_avg523f8 = 0.5f0 * (v2_ll * B3_ll - v3_ll * B2_ll + v2_rr * B3_rr - v3_rr * B2_rr)524f9 = equations.c_h * 0.5f0 * (B2_ll + B2_rr)525# total energy flux is complicated and involves the previous components526f5 = (f1 * (velocity_square_avg + inv_rho_p_mean * inv_gamma_minus_one)527+5280.5f0 * (+p_ll * v2_rr + p_rr * v2_ll529+ (v2_ll * B1_ll * B1_rr + v2_rr * B1_rr * B1_ll)530+ (v2_ll * B3_ll * B3_rr + v2_rr * B3_rr * B3_ll)531-532(v1_ll * B2_ll * B1_rr + v1_rr * B2_rr * B1_ll)533-534(v3_ll * B2_ll * B3_rr + v3_rr * B2_rr * B3_ll)535+536equations.c_h * (B2_ll * psi_rr + B2_rr * psi_ll)))537end538539f_other = SVector(f2, f3, f4, f5, f6, f7, f8, f9)540541return vcat(f_other, f_rho)542end543544# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation545@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,546equations::IdealGlmMhdMulticomponentEquations2D)547rho_v1_ll, rho_v2_ll, _ = u_ll548rho_v1_rr, rho_v2_rr, _ = u_rr549550rho_ll = density(u_ll, equations)551rho_rr = density(u_rr, equations)552553# Calculate velocities and fast magnetoacoustic wave speeds554if orientation == 1555v_ll = rho_v1_ll / rho_ll556v_rr = rho_v1_rr / rho_rr557else # orientation == 2558v_ll = rho_v2_ll / rho_ll559v_rr = rho_v2_rr / rho_rr560end561cf_ll = calc_fast_wavespeed(u_ll, orientation, equations)562cf_rr = calc_fast_wavespeed(u_rr, orientation, equations)563564return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr)565end566567# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`568@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,569equations::IdealGlmMhdMulticomponentEquations2D)570rho_v1_ll, rho_v2_ll, _ = u_ll571rho_v1_rr, rho_v2_rr, _ = u_rr572573rho_ll = density(u_ll, equations)574rho_rr = density(u_rr, equations)575576# Calculate velocities and fast magnetoacoustic wave speeds577if orientation == 1578v_ll = rho_v1_ll / rho_ll579v_rr = rho_v1_rr / rho_rr580else # orientation == 2581v_ll = rho_v2_ll / rho_ll582v_rr = rho_v2_rr / rho_rr583end584cf_ll = calc_fast_wavespeed(u_ll, orientation, equations)585cf_rr = calc_fast_wavespeed(u_rr, orientation, equations)586587return max(abs(v_ll) + cf_ll, abs(v_rr) + cf_rr)588end589590@inline function max_abs_speeds(u, equations::IdealGlmMhdMulticomponentEquations2D)591rho_v1, rho_v2, _ = u592593rho = density(u, equations)594595v1 = rho_v1 / rho596v2 = rho_v2 / rho597598cf_x_direction = calc_fast_wavespeed(u, 1, equations)599cf_y_direction = calc_fast_wavespeed(u, 2, equations)600601return (abs(v1) + cf_x_direction, abs(v2) + cf_y_direction)602end603604@inline function density_pressure(u, equations::IdealGlmMhdMulticomponentEquations2D)605rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u606rho = density(u, equations)607gamma = totalgamma(u, equations)608p = (gamma - 1) * (rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2 + rho_v3^2) / rho609-6100.5f0 * (B1^2 + B2^2 + B3^2)611-6120.5f0 * psi^2)613return rho * p614end615616# Convert conservative variables to primitive617function cons2prim(u, equations::IdealGlmMhdMulticomponentEquations2D)618rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u619620prim_rho = SVector{ncomponents(equations), real(equations)}(u[i + 8]621for i in eachcomponent(equations))622rho = density(u, equations)623624v1 = rho_v1 / rho625v2 = rho_v2 / rho626v3 = rho_v3 / rho627628gamma = totalgamma(u, equations)629630p = (gamma - 1) *631(rho_e - 0.5f0 * rho * (v1^2 + v2^2 + v3^2) - 0.5f0 * (B1^2 + B2^2 + B3^2) -6320.5f0 * psi^2)633prim_other = SVector(v1, v2, v3, p, B1, B2, B3, psi)634635return vcat(prim_other, prim_rho)636end637638# Convert conservative variables to entropy639@inline function cons2entropy(u, equations::IdealGlmMhdMulticomponentEquations2D)640rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u641@unpack cv, gammas, gas_constants = equations642643rho = density(u, equations)644645v1 = rho_v1 / rho646v2 = rho_v2 / rho647v3 = rho_v3 / rho648v_square = v1^2 + v2^2 + v3^2649gamma = totalgamma(u, equations)650p = (gamma - 1) *651(rho_e - 0.5f0 * rho * v_square - 0.5f0 * (B1^2 + B2^2 + B3^2) - 0.5f0 * psi^2)652s = log(p) - gamma * log(rho)653rho_p = rho / p654655# Multicomponent stuff656help1 = zero(v1)657658for i in eachcomponent(equations)659help1 += u[i + 8] * cv[i]660end661662T = (rho_e - 0.5f0 * rho * v_square - 0.5f0 * (B1^2 + B2^2 + B3^2) - 0.5f0 * psi^2) /663(help1)664665entrop_rho = SVector{ncomponents(equations), real(equations)}(-1 *666(cv[i] * log(T) -667gas_constants[i] *668log(u[i + 8])) +669gas_constants[i] +670cv[i] -671(v_square / (2 * T))672for i in eachcomponent(equations))673674w1 = v1 / T675w2 = v2 / T676w3 = v3 / T677w4 = -1 / T678w5 = B1 / T679w6 = B2 / T680w7 = B3 / T681w8 = psi / T682683entrop_other = SVector(w1, w2, w3, w4, w5, w6, w7, w8)684685return vcat(entrop_other, entrop_rho)686end687688# Convert primitive to conservative variables689@inline function prim2cons(prim, equations::IdealGlmMhdMulticomponentEquations2D)690v1, v2, v3, p, B1, B2, B3, psi = prim691692cons_rho = SVector{ncomponents(equations), real(equations)}(prim[i + 8]693for i in eachcomponent(equations))694rho = density(prim, equations)695696rho_v1 = rho * v1697rho_v2 = rho * v2698rho_v3 = rho * v3699700gamma = totalgamma(prim, equations)701rho_e = p / (gamma - 1) + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) +7020.5f0 * (B1^2 + B2^2 + B3^2) + 0.5f0 * psi^2703704cons_other = SVector(rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3,705psi)706707return vcat(cons_other, cons_rho)708end709710# Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue711@inline function calc_fast_wavespeed(cons, direction,712equations::IdealGlmMhdMulticomponentEquations2D)713rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = cons714rho = density(cons, equations)715v1 = rho_v1 / rho716v2 = rho_v2 / rho717v3 = rho_v3 / rho718v_mag = sqrt(v1^2 + v2^2 + v3^2)719gamma = totalgamma(cons, equations)720p = (gamma - 1) *721(rho_e - 0.5f0 * rho * v_mag^2 - 0.5f0 * (B1^2 + B2^2 + B3^2) - 0.5f0 * psi^2)722a_square = gamma * p / rho723sqrt_rho = sqrt(rho)724b1 = B1 / sqrt_rho725b2 = B2 / sqrt_rho726b3 = B3 / sqrt_rho727b_square = b1^2 + b2^2 + b3^2728if direction == 1 # x-direction729c_f = sqrt(0.5f0 * (a_square + b_square) +7300.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b1^2))731else732c_f = sqrt(0.5f0 * (a_square + b_square) +7330.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b2^2))734end735return c_f736end737738@inline function density(u, equations::IdealGlmMhdMulticomponentEquations2D)739RealT = eltype(u)740rho = zero(RealT)741742for i in eachcomponent(equations)743rho += u[i + 8]744end745746return rho747end748749@inline function totalgamma(u, equations::IdealGlmMhdMulticomponentEquations2D)750@unpack cv, gammas = equations751752RealT = eltype(u)753help1 = zero(RealT)754help2 = zero(RealT)755756for i in eachcomponent(equations)757help1 += u[i + 8] * cv[i] * gammas[i]758help2 += u[i + 8] * cv[i]759end760761return help1 / help2762end763764@inline function densities(u, v, equations::IdealGlmMhdMulticomponentEquations2D)765return SVector{ncomponents(equations), real(equations)}(u[i + 8] * v766for i in eachcomponent(equations))767end768end # @muladd769770771