Path: blob/main/src/equations/ideal_glm_mhd_3d.jl
5586 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"""8IdealGlmMhdEquations3D(gamma)910The ideal compressible GLM-MHD equations11```math12\frac{\partial}{\partial t}13\begin{pmatrix}14\rho \\ \rho \mathbf{v} \\ \rho e_{\text{total}} \\ \mathbf{B} \\ \psi15\end{pmatrix}16+17\nabla \cdot18\begin{pmatrix}19\rho \mathbf{v} \\ \rho (\mathbf{v} \otimes \mathbf{v}) + (p + \frac{1}{2} \Vert \mathbf{B} \Vert_2 ^2) \underline{I} - \mathbf{B} \otimes \mathbf{B} \\20\mathbf{v} (\frac{1}{2} \rho \Vert \mathbf{v} \Vert_2 ^2 + \frac{\gamma p}{\gamma - 1} + \Vert \mathbf{B} \Vert_2 ^2) - \mathbf{B} (\mathbf{v} \cdot \mathbf{B}) + c_h \psi \mathbf{B} \\21\mathbf{v} \otimes \mathbf{B} - \mathbf{B} \otimes \mathbf{v} + c_h \psi \underline{I} \\22c_h \mathbf{B}23\end{pmatrix}24+25(\nabla \cdot \mathbf{B})26\begin{pmatrix}270 \\ \mathbf{B} \\ \mathbf{v} \cdot \mathbf{B} \\ \mathbf{v} \\ 028\end{pmatrix}29+30(\nabla \psi) \cdot31\begin{pmatrix}32\mathbf{0} \\ 0 \\ \mathbf{v} \cdot \psi \\ 0 \\ \mathbf{v}33\end{pmatrix}34=35\begin{pmatrix}360 \\ \mathbf{0} \\ 0 \\ \mathbf{0} \\ 037\end{pmatrix}38```39for an ideal gas in three space dimensions.40Here, ``\mathbf{v}`` is the velocity, ``\mathbf{B}`` the magnetic field, ``c_h`` the hyperbolic divergence cleaning speed,41``\psi`` the generalized Lagrangian Multiplier (GLM),42``e_{\text{total}}`` the specific total energy, and43```math44p = (\gamma - 1) \left( \rho e_{\text{total}} - \frac{1}{2} \rho \Vert \mathbf{v} \Vert_2 ^2 - \frac{1}{2} \Vert \mathbf{B} \Vert_2 ^2 - \frac{1}{2} \psi^2 \right)45```46the pressure, ``\gamma`` the total heat capacity ratio and ``\underline{I}`` the ``3\times 3`` identity matrix.47"""48struct IdealGlmMhdEquations3D{RealT <: Real} <:49AbstractIdealGlmMhdEquations{3, 9}50gamma::RealT # ratio of specific heats51inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications52c_h::RealT # GLM cleaning speed5354function IdealGlmMhdEquations3D(gamma, c_h)55γ, inv_gamma_minus_one, c_h = promote(gamma, inv(gamma - 1), c_h)56return new{typeof(γ)}(γ, inv_gamma_minus_one, c_h)57end58end5960function IdealGlmMhdEquations3D(gamma; initial_c_h = convert(typeof(gamma), NaN))61# Use `promote` to ensure that `gamma` and `initial_c_h` have the same type62return IdealGlmMhdEquations3D(promote(gamma, initial_c_h)...)63end6465# Outer constructor for `@reset` works correctly66function IdealGlmMhdEquations3D(gamma, inv_gamma_minus_one, c_h)67return IdealGlmMhdEquations3D(gamma, c_h)68end6970have_nonconservative_terms(::IdealGlmMhdEquations3D) = True()71function varnames(::typeof(cons2cons), ::IdealGlmMhdEquations3D)72return ("rho", "rho_v1", "rho_v2", "rho_v3", "rho_e_total", "B1", "B2", "B3", "psi")73end74function varnames(::typeof(cons2prim), ::IdealGlmMhdEquations3D)75return ("rho", "v1", "v2", "v3", "p", "B1", "B2", "B3", "psi")76end77function default_analysis_integrals(::IdealGlmMhdEquations3D)78return (entropy_timederivative, Val(:l2_divb), Val(:linf_divb))79end8081# Helper function to extract the magnetic field vector from the conservative variables82magnetic_field(u, equations::IdealGlmMhdEquations3D) = SVector(u[6], u[7], u[8])8384# Set initial conditions at physical location `x` for time `t`85"""86initial_condition_constant(x, t, equations::IdealGlmMhdEquations3D)8788A constant initial condition to test free-stream preservation.89"""90function initial_condition_constant(x, t, equations::IdealGlmMhdEquations3D)91RealT = eltype(x)92rho = 193rho_v1 = convert(RealT, 0.1)94rho_v2 = -convert(RealT, 0.2)95rho_v3 = -0.5f096rho_e_total = 5097B1 = 398B2 = -convert(RealT, 1.2)99B3 = 0.5f0100psi = 0101return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi)102end103104"""105initial_condition_convergence_test(x, t, equations::IdealGlmMhdEquations3D)106107An Alfvén wave as smooth initial condition used for convergence tests.108See for reference section 5.1 in109- Christoph Altmann (2012)110Explicit Discontinuous Galerkin Methods for Magnetohydrodynamics111[DOI: 10.18419/opus-3895](http://dx.doi.org/10.18419/opus-3895)112"""113function initial_condition_convergence_test(x, t, equations::IdealGlmMhdEquations3D)114# Alfvén wave in three space dimensions115# domain must be set to [-1, 1]^3, γ = 5/3116RealT = eltype(x)117p = 1118omega = 2 * convert(RealT, pi) # may be multiplied by frequency119# r: length-variable = length of computational domain120r = convert(RealT, 2)121# e: epsilon = 0.2122e = convert(RealT, 0.2)123nx = 1 / sqrt(r^2 + 1)124ny = r / sqrt(r^2 + 1)125sqr = 1126Va = omega / (ny * sqr)127phi_alv = omega / ny * (nx * (x[1] - 0.5f0 * r) + ny * (x[2] - 0.5f0 * r)) - Va * t128129rho = 1130v1 = -e * ny * cos(phi_alv) / rho131v2 = e * nx * cos(phi_alv) / rho132v3 = e * sin(phi_alv) / rho133B1 = nx - rho * v1 * sqr134B2 = ny - rho * v2 * sqr135B3 = -rho * v3 * sqr136psi = 0137138return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations)139end140141"""142initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdEquations3D)143144A weak blast wave adapted from145- Sebastian Hennemann, Gregor J. Gassner (2020)146A provably entropy stable subcell shock capturing approach for high order split form DG147[arXiv: 2008.12044](https://arxiv.org/abs/2008.12044)148"""149function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdEquations3D)150# Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3)151# Same discontinuity in the velocities but with magnetic fields152# Set up polar coordinates153RealT = eltype(x)154inicenter = (0, 0, 0)155x_norm = x[1] - inicenter[1]156y_norm = x[2] - inicenter[2]157z_norm = x[3] - inicenter[3]158r = sqrt(x_norm^2 + y_norm^2 + z_norm^2)159phi = atan(y_norm, x_norm)160theta = iszero(r) ? zero(RealT) : acos(z_norm / r)161162# Calculate primitive variables163rho = r > 0.5f0 ? one(RealT) : convert(RealT, 1.1691)164v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(phi) * sin(theta)165v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin(phi) * sin(theta)166v3 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(theta)167p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245)168169return prim2cons(SVector(rho, v1, v2, v3, p, 1, 1, 1, 0), equations)170end171172# Pre-defined source terms should be implemented as173# function source_terms_WHATEVER(u, x, t, equations::IdealGlmMhdEquations3D)174175# Calculate 1D flux for a single point176@inline function flux(u, orientation::Integer, equations::IdealGlmMhdEquations3D)177rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi = u178v1 = rho_v1 / rho179v2 = rho_v2 / rho180v3 = rho_v3 / rho181kin_en = 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3)182mag_en = 0.5f0 * (B1 * B1 + B2 * B2 + B3 * B3)183p_over_gamma_minus_one = (rho_e_total - kin_en - mag_en - 0.5f0 * psi^2)184p = (equations.gamma - 1) * p_over_gamma_minus_one185if orientation == 1186f1 = rho_v1187f2 = rho_v1 * v1 + p + mag_en - B1^2188f3 = rho_v1 * v2 - B1 * B2189f4 = rho_v1 * v3 - B1 * B3190f5 = (kin_en + equations.gamma * p_over_gamma_minus_one + 2 * mag_en) * v1 -191B1 * (v1 * B1 + v2 * B2 + v3 * B3) + equations.c_h * psi * B1192f6 = equations.c_h * psi193f7 = v1 * B2 - v2 * B1194f8 = v1 * B3 - v3 * B1195f9 = equations.c_h * B1196elseif orientation == 2197f1 = rho_v2198f2 = rho_v2 * v1 - B2 * B1199f3 = rho_v2 * v2 + p + mag_en - B2^2200f4 = rho_v2 * v3 - B2 * B3201f5 = (kin_en + equations.gamma * p_over_gamma_minus_one + 2 * mag_en) * v2 -202B2 * (v1 * B1 + v2 * B2 + v3 * B3) + equations.c_h * psi * B2203f6 = v2 * B1 - v1 * B2204f7 = equations.c_h * psi205f8 = v2 * B3 - v3 * B2206f9 = equations.c_h * B2207else208f1 = rho_v3209f2 = rho_v3 * v1 - B3 * B1210f3 = rho_v3 * v2 - B3 * B2211f4 = rho_v3 * v3 + p + mag_en - B3^2212f5 = (kin_en + equations.gamma * p_over_gamma_minus_one + 2 * mag_en) * v3 -213B3 * (v1 * B1 + v2 * B2 + v3 * B3) + equations.c_h * psi * B3214f6 = v3 * B1 - v1 * B3215f7 = v3 * B2 - v2 * B3216f8 = equations.c_h * psi217f9 = equations.c_h * B3218end219220return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)221end222223# Calculate 1D flux for a single point in the normal direction224# Note, this directional vector is not normalized225@inline function flux(u, normal_direction::AbstractVector,226equations::IdealGlmMhdEquations3D)227rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi = u228v1 = rho_v1 / rho229v2 = rho_v2 / rho230v3 = rho_v3 / rho231kin_en = 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3)232mag_en = 0.5f0 * (B1 * B1 + B2 * B2 + B3 * B3)233p_over_gamma_minus_one = (rho_e_total - kin_en - mag_en - 0.5f0 * psi^2)234p = (equations.gamma - 1) * p_over_gamma_minus_one235236v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] +237v3 * normal_direction[3]238B_normal = B1 * normal_direction[1] + B2 * normal_direction[2] +239B3 * normal_direction[3]240rho_v_normal = rho * v_normal241242f1 = rho_v_normal243f2 = rho_v_normal * v1 - B1 * B_normal + (p + mag_en) * normal_direction[1]244f3 = rho_v_normal * v2 - B2 * B_normal + (p + mag_en) * normal_direction[2]245f4 = rho_v_normal * v3 - B3 * B_normal + (p + mag_en) * normal_direction[3]246f5 = ((kin_en + equations.gamma * p_over_gamma_minus_one + 2 * mag_en) * v_normal247-248B_normal * (v1 * B1 + v2 * B2 + v3 * B3) + equations.c_h * psi * B_normal)249f6 = (equations.c_h * psi * normal_direction[1] +250(v2 * B1 - v1 * B2) * normal_direction[2] +251(v3 * B1 - v1 * B3) * normal_direction[3])252f7 = ((v1 * B2 - v2 * B1) * normal_direction[1] +253equations.c_h * psi * normal_direction[2] +254(v3 * B2 - v2 * B3) * normal_direction[3])255f8 = ((v1 * B3 - v3 * B1) * normal_direction[1] +256(v2 * B3 - v3 * B2) * normal_direction[2] +257equations.c_h * psi * normal_direction[3])258f9 = equations.c_h * B_normal259260return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)261end262263"""264flux_nonconservative_powell(u_ll, u_rr, orientation::Integer,265equations::IdealGlmMhdEquations3D)266flux_nonconservative_powell(u_ll, u_rr,267normal_direction::AbstractVector,268equations::IdealGlmMhdEquations3D)269270Non-symmetric two-point flux discretizing the nonconservative (source) term of271Powell and the Galilean nonconservative term associated with the GLM multiplier272of the [`IdealGlmMhdEquations3D`](@ref).273274On curvilinear meshes, the implementation differs from the reference since we use the averaged275normal direction for the metrics dealiasing.276277## References278- Marvin Bohm, Andrew R.Winters, Gregor J. Gassner, Dominik Derigs,279Florian Hindenlang, Joachim Saur280An entropy stable nodal discontinuous Galerkin method for the resistive MHD281equations. Part I: Theory and numerical verification282[DOI: 10.1016/j.jcp.2018.06.027](https://doi.org/10.1016/j.jcp.2018.06.027)283"""284@inline function flux_nonconservative_powell(u_ll, u_rr, orientation::Integer,285equations::IdealGlmMhdEquations3D)286rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_total_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll287rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_total_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr288289v1_ll = rho_v1_ll / rho_ll290v2_ll = rho_v2_ll / rho_ll291v3_ll = rho_v3_ll / rho_ll292v_dot_B_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll293294# Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0)295# Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2,3}, 0, 0, 0, v_{1,2,3})296if orientation == 1297f = SVector(0,298B1_ll * B1_rr,299B2_ll * B1_rr,300B3_ll * B1_rr,301v_dot_B_ll * B1_rr + v1_ll * psi_ll * psi_rr,302v1_ll * B1_rr,303v2_ll * B1_rr,304v3_ll * B1_rr,305v1_ll * psi_rr)306elseif orientation == 2307f = SVector(0,308B1_ll * B2_rr,309B2_ll * B2_rr,310B3_ll * B2_rr,311v_dot_B_ll * B2_rr + v2_ll * psi_ll * psi_rr,312v1_ll * B2_rr,313v2_ll * B2_rr,314v3_ll * B2_rr,315v2_ll * psi_rr)316else # orientation == 3317f = SVector(0,318B1_ll * B3_rr,319B2_ll * B3_rr,320B3_ll * B3_rr,321v_dot_B_ll * B3_rr + v3_ll * psi_ll * psi_rr,322v1_ll * B3_rr,323v2_ll * B3_rr,324v3_ll * B3_rr,325v3_ll * psi_rr)326end327328return f329end330331@inline function flux_nonconservative_powell(u_ll, u_rr,332normal_direction::AbstractVector,333equations::IdealGlmMhdEquations3D)334rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_total_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll335rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_total_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr336337v1_ll = rho_v1_ll / rho_ll338v2_ll = rho_v2_ll / rho_ll339v3_ll = rho_v3_ll / rho_ll340v_dot_B_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll341342v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] +343v3_ll * normal_direction[3]344B_dot_n_rr = B1_rr * normal_direction[1] +345B2_rr * normal_direction[2] +346B3_rr * normal_direction[3]347348# Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0)349# Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2,3}, 0, 0, 0, v_{1,2,3})350f = SVector(0,351B1_ll * B_dot_n_rr,352B2_ll * B_dot_n_rr,353B3_ll * B_dot_n_rr,354v_dot_B_ll * B_dot_n_rr + v_dot_n_ll * psi_ll * psi_rr,355v1_ll * B_dot_n_rr,356v2_ll * B_dot_n_rr,357v3_ll * B_dot_n_rr,358v_dot_n_ll * psi_rr)359360return f361end362363# For `VolumeIntegralSubcellLimiting` the nonconservative flux is created as a callable struct to364# enable dispatch on the type of the nonconservative term (symmetric / jump).365"""366flux_nonconservative_powell_local_symmetric(u_ll, u_rr,367normal_direction::AbstractVector,368equations::IdealGlmMhdEquations3D)369370Non-symmetric two-point flux discretizing the nonconservative (source) term of371Powell and the Galilean nonconservative term associated with the GLM multiplier372of the [`IdealGlmMhdEquations3D`](@ref).373374This implementation uses a non-conservative term that can be written as the product375of local and symmetric parts. It is equivalent to the non-conservative flux of Bohm376et al. [`flux_nonconservative_powell`](@ref) for conforming meshes but it yields different377results on non-conforming meshes(!). On curvilinear meshes this formulation applies the378local normal direction compared to the averaged one used in [`flux_nonconservative_powell`](@ref).379380The two other flux functions with the same name return either the local381or symmetric portion of the non-conservative flux based on the type of the382nonconservative_type argument, employing multiple dispatch. They are used to383compute the subcell fluxes in dg_3d_subcell_limiters.jl.384385## References386- Rueda-Ramírez, Gassner (2023). A Flux-Differencing Formula for Split-Form Summation By Parts387Discretizations of Non-Conservative Systems.388[DOI: 10.1016/j.jcp.2023.112607](https://doi.org/10.1016/j.jcp.2023.112607).389[arXiv: 2211.14009](https://doi.org/10.48550/arXiv.2211.14009).390"""391@inline function (noncons_flux::FluxNonConservativePowellLocalSymmetric)(u_ll, u_rr,392normal_direction::AbstractVector,393equations::IdealGlmMhdEquations3D)394rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_total_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll395rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_total_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr396397v1_ll = rho_v1_ll / rho_ll398v2_ll = rho_v2_ll / rho_ll399v3_ll = rho_v3_ll / rho_ll400v_dot_B_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll401402# The factor 0.5 of the averages can be omitted since it is already applied when this403# function is called.404psi_avg = (psi_ll + psi_rr)405B1_avg = (B1_ll + B1_rr)406B2_avg = (B2_ll + B2_rr)407B3_avg = (B3_ll + B3_rr)408409B_dot_n_avg = B1_avg * normal_direction[1] + B2_avg * normal_direction[2] +410B3_avg * normal_direction[3]411v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] +412v3_ll * normal_direction[3]413414# Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0)415# Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2,3}, 0, 0, 0, v_{1,2,3})416f = SVector(0,417B1_ll * B_dot_n_avg,418B2_ll * B_dot_n_avg,419B3_ll * B_dot_n_avg,420v_dot_B_ll * B_dot_n_avg + v_dot_n_ll * psi_ll * psi_avg,421v1_ll * B_dot_n_avg,422v2_ll * B_dot_n_avg,423v3_ll * B_dot_n_avg,424v_dot_n_ll * psi_avg)425426return f427end428429"""430flux_nonconservative_powell_local_symmetric(u_ll, normal_direction_ll::AbstractVector,431equations::IdealGlmMhdEquations3D,432nonconservative_type::NonConservativeLocal,433nonconservative_term::Integer)434435Local part of the Powell and GLM non-conservative terms. Needed for the calculation of436the non-conservative staggered "fluxes" for subcell limiting. See, e.g.,437- Rueda-Ramírez, Gassner (2023). A Flux-Differencing Formula for Split-Form Summation By Parts438Discretizations of Non-Conservative Systems.439[DOI: 10.1016/j.jcp.2023.112607](https://doi.org/10.1016/j.jcp.2023.112607).440[arXiv: 2211.14009](https://doi.org/10.48550/arXiv.2211.14009).441442This function is used to compute the subcell fluxes in dg_3d_subcell_limiters.jl.443"""444@inline function (noncons_flux::FluxNonConservativePowellLocalSymmetric)(u_ll,445normal_direction_ll::AbstractVector,446equations::IdealGlmMhdEquations3D,447nonconservative_type::NonConservativeLocal,448nonconservative_term::Integer)449rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_total_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll450451if nonconservative_term == 1452# Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0)453v1_ll = rho_v1_ll / rho_ll454v2_ll = rho_v2_ll / rho_ll455v3_ll = rho_v3_ll / rho_ll456v_dot_B_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll457458f = SVector(0,459B1_ll,460B2_ll,461B3_ll,462v_dot_B_ll,463v1_ll,464v2_ll,465v3_ll,4660)467else # nonconservative_term == 2468# Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2}, 0, 0, 0, v_{1,2})469v1_ll = rho_v1_ll / rho_ll470v2_ll = rho_v2_ll / rho_ll471v3_ll = rho_v3_ll / rho_ll472v_dot_n_ll = v1_ll * normal_direction_ll[1] + v2_ll * normal_direction_ll[2] +473v3_ll * normal_direction_ll[3]474475f = SVector(0,4760,4770,4780,479v_dot_n_ll * psi_ll,4800,4810,4820,483v_dot_n_ll)484end485return f486end487488"""489flux_nonconservative_powell_local_symmetric(u_ll, normal_direction_avg::AbstractVector,490equations::IdealGlmMhdEquations3D,491nonconservative_type::NonConservativeSymmetric,492nonconservative_term::Integer)493494Symmetric part of the Powell and GLM non-conservative terms. Needed for the calculation of495the non-conservative staggered "fluxes" for subcell limiting. See, e.g.,496- Rueda-Ramírez, Gassner (2023). A Flux-Differencing Formula for Split-Form Summation By Parts497Discretizations of Non-Conservative Systems.498[DOI: 10.1016/j.jcp.2023.112607](https://doi.org/10.1016/j.jcp.2023.112607).499[arXiv: 2211.14009](https://doi.org/10.48550/arXiv.2211.14009).500501This function is used to compute the subcell fluxes in dg_3d_subcell_limiters.jl.502"""503@inline function (noncons_flux::FluxNonConservativePowellLocalSymmetric)(u_ll, u_rr,504normal_direction_avg::AbstractVector,505equations::IdealGlmMhdEquations3D,506nonconservative_type::NonConservativeSymmetric,507nonconservative_term::Integer)508rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_total_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll509rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_total_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr510511if nonconservative_term == 1512# Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0)513# The factor 0.5 of the average can be omitted since it is already applied when this514# function is called.515B_dot_n_avg = ((B1_ll + B1_rr) * normal_direction_avg[1] +516(B2_ll + B2_rr) * normal_direction_avg[2] +517(B3_ll + B3_rr) * normal_direction_avg[3])518f = SVector(0,519B_dot_n_avg,520B_dot_n_avg,521B_dot_n_avg,522B_dot_n_avg,523B_dot_n_avg,524B_dot_n_avg,525B_dot_n_avg,5260)527else # nonconservative_term == 2528# Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2}, 0, 0, 0, v_{1,2})529# The factor 0.5 of the average can be omitted since it is already applied when this530# function is called.531psi_avg = (psi_ll + psi_rr)532f = SVector(0,5330,5340,5350,536psi_avg,5370,5380,5390,540psi_avg)541end542543return f544end545546"""547flux_derigs_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations3D)548549Entropy conserving two-point flux by550- Derigs et al. (2018)551Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field552divergence diminishing ideal magnetohydrodynamics equations553[DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002)554"""555function flux_derigs_etal(u_ll, u_rr, orientation::Integer,556equations::IdealGlmMhdEquations3D)557# Unpack left and right states to get velocities, pressure, and inverse temperature (called beta)558rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll, psi_ll = cons2prim(u_ll,559equations)560rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr, psi_rr = cons2prim(u_rr,561equations)562563vel_norm_ll = v1_ll^2 + v2_ll^2 + v3_ll^2564vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2565mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2566mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2567beta_ll = 0.5f0 * rho_ll / p_ll568beta_rr = 0.5f0 * rho_rr / p_rr569# for convenience store v⋅B570vel_dot_mag_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll571vel_dot_mag_rr = v1_rr * B1_rr + v2_rr * B2_rr + v3_rr * B3_rr572573# Compute the necessary mean values needed for either direction574rho_avg = 0.5f0 * (rho_ll + rho_rr)575rho_mean = ln_mean(rho_ll, rho_rr)576beta_mean = ln_mean(beta_ll, beta_rr)577beta_avg = 0.5f0 * (beta_ll + beta_rr)578v1_avg = 0.5f0 * (v1_ll + v1_rr)579v2_avg = 0.5f0 * (v2_ll + v2_rr)580v3_avg = 0.5f0 * (v3_ll + v3_rr)581p_mean = 0.5f0 * rho_avg / beta_avg582B1_avg = 0.5f0 * (B1_ll + B1_rr)583B2_avg = 0.5f0 * (B2_ll + B2_rr)584B3_avg = 0.5f0 * (B3_ll + B3_rr)585psi_avg = 0.5f0 * (psi_ll + psi_rr)586vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr)587mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr)588vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr)589590# Calculate fluxes depending on orientation with specific direction averages591if orientation == 1592f1 = rho_mean * v1_avg593f2 = f1 * v1_avg + p_mean + 0.5f0 * mag_norm_avg - B1_avg * B1_avg594f3 = f1 * v2_avg - B1_avg * B2_avg595f4 = f1 * v3_avg - B1_avg * B3_avg596f6 = equations.c_h * psi_avg597f7 = v1_avg * B2_avg - v2_avg * B1_avg598f8 = v1_avg * B3_avg - v3_avg * B1_avg599f9 = equations.c_h * B1_avg600# total energy flux is complicated and involves the previous eight components601psi_B1_avg = 0.5f0 * (B1_ll * psi_ll + B1_rr * psi_rr)602v1_mag_avg = 0.5f0 * (v1_ll * mag_norm_ll + v1_rr * mag_norm_rr)603f5 = (f1 * 0.5f0 * (1 / (equations.gamma - 1) / beta_mean - vel_norm_avg) +604f2 * v1_avg + f3 * v2_avg +605f4 * v3_avg + f6 * B1_avg + f7 * B2_avg + f8 * B3_avg + f9 * psi_avg -6060.5f0 * v1_mag_avg +607B1_avg * vel_dot_mag_avg - equations.c_h * psi_B1_avg)608elseif orientation == 2609f1 = rho_mean * v2_avg610f2 = f1 * v1_avg - B2_avg * B1_avg611f3 = f1 * v2_avg + p_mean + 0.5f0 * mag_norm_avg - B2_avg * B2_avg612f4 = f1 * v3_avg - B2_avg * B3_avg613f6 = v2_avg * B1_avg - v1_avg * B2_avg614f7 = equations.c_h * psi_avg615f8 = v2_avg * B3_avg - v3_avg * B2_avg616f9 = equations.c_h * B2_avg617# total energy flux is complicated and involves the previous eight components618psi_B2_avg = 0.5f0 * (B2_ll * psi_ll + B2_rr * psi_rr)619v2_mag_avg = 0.5f0 * (v2_ll * mag_norm_ll + v2_rr * mag_norm_rr)620f5 = (f1 * 0.5f0 * (1 / (equations.gamma - 1) / beta_mean - vel_norm_avg) +621f2 * v1_avg + f3 * v2_avg +622f4 * v3_avg + f6 * B1_avg + f7 * B2_avg + f8 * B3_avg + f9 * psi_avg -6230.5f0 * v2_mag_avg +624B2_avg * vel_dot_mag_avg - equations.c_h * psi_B2_avg)625else626f1 = rho_mean * v3_avg627f2 = f1 * v1_avg - B3_avg * B1_avg628f3 = f1 * v2_avg - B3_avg * B2_avg629f4 = f1 * v3_avg + p_mean + 0.5f0 * mag_norm_avg - B3_avg * B3_avg630f6 = v3_avg * B1_avg - v1_avg * B3_avg631f7 = v3_avg * B2_avg - v2_avg * B3_avg632f8 = equations.c_h * psi_avg633f9 = equations.c_h * B3_avg634# total energy flux is complicated and involves the previous eight components635psi_B3_avg = 0.5f0 * (B3_ll * psi_ll + B3_rr * psi_rr)636v3_mag_avg = 0.5f0 * (v3_ll * mag_norm_ll + v3_rr * mag_norm_rr)637f5 = (f1 * 0.5f0 * (1 / (equations.gamma - 1) / beta_mean - vel_norm_avg) +638f2 * v1_avg + f3 * v2_avg +639f4 * v3_avg + f6 * B1_avg + f7 * B2_avg + f8 * B3_avg + f9 * psi_avg -6400.5f0 * v3_mag_avg +641B3_avg * vel_dot_mag_avg - equations.c_h * psi_B3_avg)642end643644return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)645end646647"""648flux_hindenlang_gassner(u_ll, u_rr, orientation_or_normal_direction,649equations::IdealGlmMhdEquations3D)650651Entropy conserving and kinetic energy preserving two-point flux of652Hindenlang and Gassner (2019), extending [`flux_ranocha`](@ref) to the MHD equations.653654## References655- Florian Hindenlang, Gregor Gassner (2019)656A new entropy conservative two-point flux for ideal MHD equations derived from657first principles.658Presented at HONOM 2019: European workshop on high order numerical methods659for evolutionary PDEs, theory and applications660- Hendrik Ranocha (2018)661Generalised Summation-by-Parts Operators and Entropy Stability of Numerical Methods662for Hyperbolic Balance Laws663[PhD thesis, TU Braunschweig](https://cuvillier.de/en/shop/publications/7743)664- Hendrik Ranocha (2020)665Entropy Conserving and Kinetic Energy Preserving Numerical Methods for666the Euler Equations Using Summation-by-Parts Operators667[Proceedings of ICOSAHOM 2018](https://doi.org/10.1007/978-3-030-39647-3_42)668"""669@inline function flux_hindenlang_gassner(u_ll, u_rr, orientation::Integer,670equations::IdealGlmMhdEquations3D)671# Unpack left and right states672rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll, psi_ll = cons2prim(u_ll,673equations)674rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr, psi_rr = cons2prim(u_rr,675equations)676677# Compute the necessary mean values needed for either direction678rho_mean = ln_mean(rho_ll, rho_rr)679# Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)`680# in exact arithmetic since681# log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ)682# = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ)683inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)684v1_avg = 0.5f0 * (v1_ll + v1_rr)685v2_avg = 0.5f0 * (v2_ll + v2_rr)686v3_avg = 0.5f0 * (v3_ll + v3_rr)687p_avg = 0.5f0 * (p_ll + p_rr)688psi_avg = 0.5f0 * (psi_ll + psi_rr)689velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr + v3_ll * v3_rr)690magnetic_square_avg = 0.5f0 * (B1_ll * B1_rr + B2_ll * B2_rr + B3_ll * B3_rr)691692# Calculate fluxes depending on orientation with specific direction averages693if orientation == 1694f1 = rho_mean * v1_avg695f2 = f1 * v1_avg + p_avg + magnetic_square_avg -6960.5f0 * (B1_ll * B1_rr + B1_rr * B1_ll)697f3 = f1 * v2_avg - 0.5f0 * (B1_ll * B2_rr + B1_rr * B2_ll)698f4 = f1 * v3_avg - 0.5f0 * (B1_ll * B3_rr + B1_rr * B3_ll)699#f5 below700f6 = equations.c_h * psi_avg701f7 = 0.5f0 * (v1_ll * B2_ll - v2_ll * B1_ll + v1_rr * B2_rr - v2_rr * B1_rr)702f8 = 0.5f0 * (v1_ll * B3_ll - v3_ll * B1_ll + v1_rr * B3_rr - v3_rr * B1_rr)703f9 = equations.c_h * 0.5f0 * (B1_ll + B1_rr)704# total energy flux is complicated and involves the previous components705f5 = (f1 *706(velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)707+7080.5f0 * (+p_ll * v1_rr + p_rr * v1_ll709+ (v1_ll * B2_ll * B2_rr + v1_rr * B2_rr * B2_ll)710+ (v1_ll * B3_ll * B3_rr + v1_rr * B3_rr * B3_ll)711-712(v2_ll * B1_ll * B2_rr + v2_rr * B1_rr * B2_ll)713-714(v3_ll * B1_ll * B3_rr + v3_rr * B1_rr * B3_ll)715+716equations.c_h * (B1_ll * psi_rr + B1_rr * psi_ll)))717elseif orientation == 2718f1 = rho_mean * v2_avg719f2 = f1 * v1_avg - 0.5f0 * (B2_ll * B1_rr + B2_rr * B1_ll)720f3 = f1 * v2_avg + p_avg + magnetic_square_avg -7210.5f0 * (B2_ll * B2_rr + B2_rr * B2_ll)722f4 = f1 * v3_avg - 0.5f0 * (B2_ll * B3_rr + B2_rr * B3_ll)723#f5 below724f6 = 0.5f0 * (v2_ll * B1_ll - v1_ll * B2_ll + v2_rr * B1_rr - v1_rr * B2_rr)725f7 = equations.c_h * psi_avg726f8 = 0.5f0 * (v2_ll * B3_ll - v3_ll * B2_ll + v2_rr * B3_rr - v3_rr * B2_rr)727f9 = equations.c_h * 0.5f0 * (B2_ll + B2_rr)728# total energy flux is complicated and involves the previous components729f5 = (f1 *730(velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)731+7320.5f0 * (+p_ll * v2_rr + p_rr * v2_ll733+ (v2_ll * B1_ll * B1_rr + v2_rr * B1_rr * B1_ll)734+ (v2_ll * B3_ll * B3_rr + v2_rr * B3_rr * B3_ll)735-736(v1_ll * B2_ll * B1_rr + v1_rr * B2_rr * B1_ll)737-738(v3_ll * B2_ll * B3_rr + v3_rr * B2_rr * B3_ll)739+740equations.c_h * (B2_ll * psi_rr + B2_rr * psi_ll)))741else # orientation == 3742f1 = rho_mean * v3_avg743f2 = f1 * v1_avg - 0.5f0 * (B3_ll * B1_rr + B3_rr * B1_ll)744f3 = f1 * v2_avg - 0.5f0 * (B3_ll * B2_rr + B3_rr * B2_ll)745f4 = f1 * v3_avg + p_avg + magnetic_square_avg -7460.5f0 * (B3_ll * B3_rr + B3_rr * B3_ll)747#f5 below748f6 = 0.5f0 * (v3_ll * B1_ll - v1_ll * B3_ll + v3_rr * B1_rr - v1_rr * B3_rr)749f7 = 0.5f0 * (v3_ll * B2_ll - v2_ll * B3_ll + v3_rr * B2_rr - v2_rr * B3_rr)750f8 = equations.c_h * psi_avg751f9 = equations.c_h * 0.5f0 * (B3_ll + B3_rr)752# total energy flux is complicated and involves the previous components753f5 = (f1 *754(velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)755+7560.5f0 * (+p_ll * v3_rr + p_rr * v3_ll757+ (v3_ll * B1_ll * B1_rr + v3_rr * B1_rr * B1_ll)758+ (v3_ll * B2_ll * B2_rr + v3_rr * B2_rr * B2_ll)759-760(v1_ll * B3_ll * B1_rr + v1_rr * B3_rr * B1_ll)761-762(v2_ll * B3_ll * B2_rr + v2_rr * B3_rr * B2_ll)763+764equations.c_h * (B3_ll * psi_rr + B3_rr * psi_ll)))765end766767return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)768end769770@inline function flux_hindenlang_gassner(u_ll, u_rr, normal_direction::AbstractVector,771equations::IdealGlmMhdEquations3D)772# Unpack left and right states773rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll, psi_ll = cons2prim(u_ll,774equations)775rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr, psi_rr = cons2prim(u_rr,776equations)777v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] +778v3_ll * normal_direction[3]779v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] +780v3_rr * normal_direction[3]781B_dot_n_ll = B1_ll * normal_direction[1] + B2_ll * normal_direction[2] +782B3_ll * normal_direction[3]783B_dot_n_rr = B1_rr * normal_direction[1] + B2_rr * normal_direction[2] +784B3_rr * normal_direction[3]785786# Compute the necessary mean values needed for either direction787rho_mean = ln_mean(rho_ll, rho_rr)788# Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)`789# in exact arithmetic since790# log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ)791# = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ)792inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)793v1_avg = 0.5f0 * (v1_ll + v1_rr)794v2_avg = 0.5f0 * (v2_ll + v2_rr)795v3_avg = 0.5f0 * (v3_ll + v3_rr)796p_avg = 0.5f0 * (p_ll + p_rr)797psi_avg = 0.5f0 * (psi_ll + psi_rr)798velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr + v3_ll * v3_rr)799magnetic_square_avg = 0.5f0 * (B1_ll * B1_rr + B2_ll * B2_rr + B3_ll * B3_rr)800801# Calculate fluxes depending on normal_direction802f1 = rho_mean * 0.5f0 * (v_dot_n_ll + v_dot_n_rr)803f2 = (f1 * v1_avg + (p_avg + magnetic_square_avg) * normal_direction[1]804-8050.5f0 * (B_dot_n_ll * B1_rr + B_dot_n_rr * B1_ll))806f3 = (f1 * v2_avg + (p_avg + magnetic_square_avg) * normal_direction[2]807-8080.5f0 * (B_dot_n_ll * B2_rr + B_dot_n_rr * B2_ll))809f4 = (f1 * v3_avg + (p_avg + magnetic_square_avg) * normal_direction[3]810-8110.5f0 * (B_dot_n_ll * B3_rr + B_dot_n_rr * B3_ll))812#f5 below813f6 = (equations.c_h * psi_avg * normal_direction[1]814+8150.5f0 * (v_dot_n_ll * B1_ll - v1_ll * B_dot_n_ll +816v_dot_n_rr * B1_rr - v1_rr * B_dot_n_rr))817f7 = (equations.c_h * psi_avg * normal_direction[2]818+8190.5f0 * (v_dot_n_ll * B2_ll - v2_ll * B_dot_n_ll +820v_dot_n_rr * B2_rr - v2_rr * B_dot_n_rr))821f8 = (equations.c_h * psi_avg * normal_direction[3]822+8230.5f0 * (v_dot_n_ll * B3_ll - v3_ll * B_dot_n_ll +824v_dot_n_rr * B3_rr - v3_rr * B_dot_n_rr))825f9 = equations.c_h * 0.5f0 * (B_dot_n_ll + B_dot_n_rr)826# total energy flux is complicated and involves the previous components827f5 = (f1 * (velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)828+8290.5f0 * (+p_ll * v_dot_n_rr + p_rr * v_dot_n_ll830+ (v_dot_n_ll * B1_ll * B1_rr + v_dot_n_rr * B1_rr * B1_ll)831+ (v_dot_n_ll * B2_ll * B2_rr + v_dot_n_rr * B2_rr * B2_ll)832+ (v_dot_n_ll * B3_ll * B3_rr + v_dot_n_rr * B3_rr * B3_ll)833-834(v1_ll * B_dot_n_ll * B1_rr + v1_rr * B_dot_n_rr * B1_ll)835-836(v2_ll * B_dot_n_ll * B2_rr + v2_rr * B_dot_n_rr * B2_ll)837-838(v3_ll * B_dot_n_ll * B3_rr + v3_rr * B_dot_n_rr * B3_ll)839+840equations.c_h * (B_dot_n_ll * psi_rr + B_dot_n_rr * psi_ll)))841842return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)843end844845# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation846@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,847equations::IdealGlmMhdEquations3D)848rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll849rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr850851# Calculate the left/right velocities and fast magnetoacoustic wave speeds852if orientation == 1853v_ll = rho_v1_ll / rho_ll854v_rr = rho_v1_rr / rho_rr855elseif orientation == 2856v_ll = rho_v2_ll / rho_ll857v_rr = rho_v2_rr / rho_rr858else # orientation == 3859v_ll = rho_v3_ll / rho_ll860v_rr = rho_v3_rr / rho_rr861end862cf_ll = calc_fast_wavespeed(u_ll, orientation, equations)863cf_rr = calc_fast_wavespeed(u_rr, orientation, equations)864865return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr)866end867868@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,869equations::IdealGlmMhdEquations3D)870rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll871rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr872873# Calculate normal velocities and fast magnetoacoustic wave speeds874# left875v1_ll = rho_v1_ll / rho_ll876v2_ll = rho_v2_ll / rho_ll877v3_ll = rho_v3_ll / rho_ll878v_ll = (v1_ll * normal_direction[1]879+ v2_ll * normal_direction[2]880+ v3_ll * normal_direction[3])881cf_ll = calc_fast_wavespeed(u_ll, normal_direction, equations)882# right883v1_rr = rho_v1_rr / rho_rr884v2_rr = rho_v2_rr / rho_rr885v3_rr = rho_v3_rr / rho_rr886v_rr = (v1_rr * normal_direction[1]887+ v2_rr * normal_direction[2]888+ v3_rr * normal_direction[3])889cf_rr = calc_fast_wavespeed(u_rr, normal_direction, equations)890891# wave speeds already scaled by norm(normal_direction) in [`calc_fast_wavespeed`](@ref)892return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr)893end894895# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`896@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,897equations::IdealGlmMhdEquations3D)898rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll899rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr900901# Calculate the left/right velocities and fast magnetoacoustic wave speeds902if orientation == 1903v_ll = rho_v1_ll / rho_ll904v_rr = rho_v1_rr / rho_rr905elseif orientation == 2906v_ll = rho_v2_ll / rho_ll907v_rr = rho_v2_rr / rho_rr908else # orientation == 3909v_ll = rho_v3_ll / rho_ll910v_rr = rho_v3_rr / rho_rr911end912cf_ll = calc_fast_wavespeed(u_ll, orientation, equations)913cf_rr = calc_fast_wavespeed(u_rr, orientation, equations)914915return max(abs(v_ll) + cf_ll, abs(v_rr) + cf_rr)916end917918# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`919@inline function max_abs_speed(u_ll, u_rr, normal_direction::AbstractVector,920equations::IdealGlmMhdEquations3D)921rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll922rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr923924# Calculate normal velocities and fast magnetoacoustic wave speeds925# left926v1_ll = rho_v1_ll / rho_ll927v2_ll = rho_v2_ll / rho_ll928v3_ll = rho_v3_ll / rho_ll929v_ll = (v1_ll * normal_direction[1]930+ v2_ll * normal_direction[2]931+ v3_ll * normal_direction[3])932cf_ll = calc_fast_wavespeed(u_ll, normal_direction, equations)933# right934v1_rr = rho_v1_rr / rho_rr935v2_rr = rho_v2_rr / rho_rr936v3_rr = rho_v3_rr / rho_rr937v_rr = (v1_rr * normal_direction[1]938+ v2_rr * normal_direction[2]939+ v3_rr * normal_direction[3])940cf_rr = calc_fast_wavespeed(u_rr, normal_direction, equations)941942# wave speeds already scaled by norm(normal_direction) in [`calc_fast_wavespeed`](@ref)943return max(abs(v_ll) + cf_ll, abs(v_rr) + cf_rr)944end945946# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes947@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer,948equations::IdealGlmMhdEquations3D)949rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll950rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr951952# Calculate primitive variables and speed of sound953v1_ll = rho_v1_ll / rho_ll954v2_ll = rho_v2_ll / rho_ll955v3_ll = rho_v3_ll / rho_ll956957v1_rr = rho_v1_rr / rho_rr958v2_rr = rho_v2_rr / rho_rr959v3_rr = rho_v3_rr / rho_rr960961# Approximate the left-most and right-most eigenvalues in the Riemann fan962if orientation == 1 # x-direction963λ_min = v1_ll - calc_fast_wavespeed(u_ll, orientation, equations)964λ_max = v1_rr + calc_fast_wavespeed(u_rr, orientation, equations)965elseif orientation == 2 # y-direction966λ_min = v2_ll - calc_fast_wavespeed(u_ll, orientation, equations)967λ_max = v2_rr + calc_fast_wavespeed(u_rr, orientation, equations)968else # z-direction969λ_min = v3_ll - calc_fast_wavespeed(u_ll, orientation, equations)970λ_max = v3_rr + calc_fast_wavespeed(u_rr, orientation, equations)971end972973return λ_min, λ_max974end975976@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,977equations::IdealGlmMhdEquations3D)978rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll979rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr980981# Calculate primitive velocity variables982v1_ll = rho_v1_ll / rho_ll983v2_ll = rho_v2_ll / rho_ll984v3_ll = rho_v3_ll / rho_ll985986v1_rr = rho_v1_rr / rho_rr987v2_rr = rho_v2_rr / rho_rr988v3_rr = rho_v3_rr / rho_rr989990v_normal_ll = (v1_ll * normal_direction[1] +991v2_ll * normal_direction[2] +992v3_ll * normal_direction[3])993v_normal_rr = (v1_rr * normal_direction[1] +994v2_rr * normal_direction[2] +995v3_rr * normal_direction[3])996997# Estimate the min/max eigenvalues in the normal direction998λ_min = v_normal_ll - calc_fast_wavespeed(u_ll, normal_direction, equations)999λ_max = v_normal_rr + calc_fast_wavespeed(u_rr, normal_direction, equations)10001001return λ_min, λ_max1002end10031004# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes1005@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer,1006equations::IdealGlmMhdEquations3D)1007rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll1008rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr10091010# Calculate primitive variables and speed of sound1011v1_ll = rho_v1_ll / rho_ll1012v2_ll = rho_v2_ll / rho_ll1013v3_ll = rho_v3_ll / rho_ll10141015v1_rr = rho_v1_rr / rho_rr1016v2_rr = rho_v2_rr / rho_rr1017v3_rr = rho_v3_rr / rho_rr10181019# Approximate the left-most and right-most eigenvalues in the Riemann fan1020if orientation == 1 # x-direction1021c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)1022c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)10231024λ_min = min(v1_ll - c_f_ll, v1_rr - c_f_rr)1025λ_max = max(v1_ll + c_f_ll, v1_rr + c_f_rr)1026elseif orientation == 2 # y-direction1027c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)1028c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)10291030λ_min = min(v2_ll - c_f_ll, v2_rr - c_f_rr)1031λ_max = max(v2_ll + c_f_ll, v2_rr + c_f_rr)1032else # z-direction1033c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)1034c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)10351036λ_min = min(v3_ll - c_f_ll, v3_rr - c_f_rr)1037λ_max = max(v3_ll + c_f_ll, v3_rr + c_f_rr)1038end10391040return λ_min, λ_max1041end10421043# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes1044@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector,1045equations::IdealGlmMhdEquations3D)1046rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll1047rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr10481049# Calculate primitive velocity variables1050v1_ll = rho_v1_ll / rho_ll1051v2_ll = rho_v2_ll / rho_ll1052v3_ll = rho_v3_ll / rho_ll10531054v1_rr = rho_v1_rr / rho_rr1055v2_rr = rho_v2_rr / rho_rr1056v3_rr = rho_v3_rr / rho_rr10571058v_normal_ll = (v1_ll * normal_direction[1] +1059v2_ll * normal_direction[2] +1060v3_ll * normal_direction[3])1061v_normal_rr = (v1_rr * normal_direction[1] +1062v2_rr * normal_direction[2] +1063v3_rr * normal_direction[3])10641065c_f_ll = calc_fast_wavespeed(u_ll, normal_direction, equations)1066c_f_rr = calc_fast_wavespeed(u_rr, normal_direction, equations)10671068# Estimate the min/max eigenvalues in the normal direction1069λ_min = min(v_normal_ll - c_f_ll, v_normal_rr - c_f_rr)1070λ_max = max(v_normal_ll + c_f_ll, v_normal_rr + c_f_rr)10711072return λ_min, λ_max1073end10741075"""1076min_max_speed_einfeldt(u_ll, u_rr, orientation_or_normal_direction, equations::IdealGlmMhdEquations3D)10771078Calculate minimum and maximum wave speeds for HLL-type fluxes as in1079- Li (2005)1080An HLLC Riemann solver for magneto-hydrodynamics1081[DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020)1082"""1083@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer,1084equations::IdealGlmMhdEquations3D)1085rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll1086rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr10871088# Calculate primitive variables and speed of sound1089v1_ll = rho_v1_ll / rho_ll1090v2_ll = rho_v2_ll / rho_ll1091v3_ll = rho_v3_ll / rho_ll10921093v1_rr = rho_v1_rr / rho_rr1094v2_rr = rho_v2_rr / rho_rr1095v3_rr = rho_v3_rr / rho_rr10961097# Approximate the left-most and right-most eigenvalues in the Riemann fan1098if orientation == 1 # x-direction1099c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)1100c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)1101vel_roe, c_f_roe = calc_fast_wavespeed_roe(u_ll, u_rr, orientation, equations)1102λ_min = min(v1_ll - c_f_ll, vel_roe - c_f_roe)1103λ_max = max(v1_rr + c_f_rr, vel_roe + c_f_roe)1104elseif orientation == 2 # y-direction1105c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)1106c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)1107vel_roe, c_f_roe = calc_fast_wavespeed_roe(u_ll, u_rr, orientation, equations)1108λ_min = min(v2_ll - c_f_ll, vel_roe - c_f_roe)1109λ_max = max(v2_rr + c_f_rr, vel_roe + c_f_roe)1110else # z-direction1111c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)1112c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)1113vel_roe, c_f_roe = calc_fast_wavespeed_roe(u_ll, u_rr, orientation, equations)1114λ_min = min(v3_ll - c_f_ll, vel_roe - c_f_roe)1115λ_max = max(v3_rr + c_f_rr, vel_roe + c_f_roe)1116end11171118return λ_min, λ_max1119end11201121@inline function min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector,1122equations::IdealGlmMhdEquations3D)1123rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll1124rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr11251126# Calculate primitive velocity variables1127v1_ll = rho_v1_ll / rho_ll1128v2_ll = rho_v2_ll / rho_ll1129v3_ll = rho_v3_ll / rho_ll11301131v1_rr = rho_v1_rr / rho_rr1132v2_rr = rho_v2_rr / rho_rr1133v3_rr = rho_v3_rr / rho_rr11341135v_normal_ll = (v1_ll * normal_direction[1] +1136v2_ll * normal_direction[2] +1137v3_ll * normal_direction[3])1138v_normal_rr = (v1_rr * normal_direction[1] +1139v2_rr * normal_direction[2] +1140v3_rr * normal_direction[3])11411142c_f_ll = calc_fast_wavespeed(u_ll, normal_direction, equations)1143c_f_rr = calc_fast_wavespeed(u_rr, normal_direction, equations)1144v_roe, c_f_roe = calc_fast_wavespeed_roe(u_ll, u_rr, normal_direction, equations)11451146# Estimate the min/max eigenvalues in the normal direction1147λ_min = min(v_normal_ll - c_f_ll, v_roe - c_f_roe)1148λ_max = max(v_normal_rr + c_f_rr, v_roe + c_f_roe)11491150return λ_min, λ_max1151end11521153# Rotate normal vector to x-axis; normal, tangent1 and tangent2 need to be orthonormal1154# Called inside `FluxRotated` in `numerical_fluxes.jl` so the directions1155# has been normalized prior to this rotation of the state vector1156# Note, for ideal GLM-MHD only the velocities and magnetic field variables rotate1157@inline function rotate_to_x(u, normal_vector, tangent1, tangent2,1158equations::IdealGlmMhdEquations3D)1159# Multiply with [ 1 0 0 0 0 0 0 0 0;1160# 0 ― normal_vector ― 0 0 0 0 0;1161# 0 ― tangent1 ― 0 0 0 0 0;1162# 0 ― tangent2 ― 0 0 0 0 0;1163# 0 0 0 0 1 0 0 0 0;1164# 0 0 0 0 0 ― normal_vector ― 0;1165# 0 0 0 0 0 ― tangent1 ― 0;1166# 0 0 0 0 0 ― tangent2 ― 0;1167# 0 0 0 0 0 0 0 0 1 ]1168return SVector(u[1],1169normal_vector[1] * u[2] + normal_vector[2] * u[3] +1170normal_vector[3] * u[4],1171tangent1[1] * u[2] + tangent1[2] * u[3] + tangent1[3] * u[4],1172tangent2[1] * u[2] + tangent2[2] * u[3] + tangent2[3] * u[4],1173u[5],1174normal_vector[1] * u[6] + normal_vector[2] * u[7] +1175normal_vector[3] * u[8],1176tangent1[1] * u[6] + tangent1[2] * u[7] + tangent1[3] * u[8],1177tangent2[1] * u[6] + tangent2[2] * u[7] + tangent2[3] * u[8],1178u[9])1179end11801181# Rotate x-axis to normal vector; normal, tangent1 and tangent2 need to be orthonormal1182# Called inside `FluxRotated` in `numerical_fluxes.jl` so the directions1183# has been normalized prior to this back-rotation of the state vector1184# Note, for ideal GLM-MHD only the velocities and magnetic field variables back-rotate1185@inline function rotate_from_x(u, normal_vector, tangent1, tangent2,1186equations::IdealGlmMhdEquations3D)1187# Multiply with [ 1 0 0 0 0 0 0 0 0;1188# 0 | | | 0 0 0 0 0;1189# 0 normal_vector tangent1 tangent2 0 0 0 0 0;1190# 0 | | | 0 0 0 0 0;1191# 0 0 0 0 1 0 0 0 0;1192# 0 0 0 0 0 | | | 0;1193# 0 0 0 0 0 normal_vector tangent1 tangent2 0;1194# 0 0 0 0 0 | | | 0;1195# 0 0 0 0 0 0 0 0 1 ]1196return SVector(u[1],1197normal_vector[1] * u[2] + tangent1[1] * u[3] + tangent2[1] * u[4],1198normal_vector[2] * u[2] + tangent1[2] * u[3] + tangent2[2] * u[4],1199normal_vector[3] * u[2] + tangent1[3] * u[3] + tangent2[3] * u[4],1200u[5],1201normal_vector[1] * u[6] + tangent1[1] * u[7] + tangent2[1] * u[8],1202normal_vector[2] * u[6] + tangent1[2] * u[7] + tangent2[2] * u[8],1203normal_vector[3] * u[6] + tangent1[3] * u[7] + tangent2[3] * u[8],1204u[9])1205end12061207@inline function max_abs_speeds(u, equations::IdealGlmMhdEquations3D)1208rho, rho_v1, rho_v2, rho_v3, _ = u1209v1 = rho_v1 / rho1210v2 = rho_v2 / rho1211v3 = rho_v3 / rho1212cf_x_direction = calc_fast_wavespeed(u, 1, equations)1213cf_y_direction = calc_fast_wavespeed(u, 2, equations)1214cf_z_direction = calc_fast_wavespeed(u, 3, equations)12151216return abs(v1) + cf_x_direction, abs(v2) + cf_y_direction, abs(v3) + cf_z_direction1217end12181219# Convert conservative variables to primitive1220@inline function cons2prim(u, equations::IdealGlmMhdEquations3D)1221rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi = u12221223v1 = rho_v1 / rho1224v2 = rho_v2 / rho1225v3 = rho_v3 / rho1226p = (equations.gamma - 1) * (rho_e_total -12270.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v31228+ B1 * B1 + B2 * B2 + B3 * B31229+ psi * psi))12301231return SVector(rho, v1, v2, v3, p, B1, B2, B3, psi)1232end12331234# Convert conservative variables to entropy1235@inline function cons2entropy(u, equations::IdealGlmMhdEquations3D)1236rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi = u1237v1 = rho_v1 / rho1238v2 = rho_v2 / rho1239v3 = rho_v3 / rho1240v_square = v1^2 + v2^2 + v3^21241p = (equations.gamma - 1) *1242(rho_e_total - 0.5f0 * rho * v_square - 0.5f0 * (B1^2 + B2^2 + B3^2) -12430.5f0 * psi^2)1244s = log(p) - equations.gamma * log(rho)1245rho_p = rho / p12461247w1 = (equations.gamma - s) * equations.inv_gamma_minus_one -12480.5f0 * rho_p * v_square1249w2 = rho_p * v11250w3 = rho_p * v21251w4 = rho_p * v31252w5 = -rho_p1253w6 = rho_p * B11254w7 = rho_p * B21255w8 = rho_p * B31256w9 = rho_p * psi12571258return SVector(w1, w2, w3, w4, w5, w6, w7, w8, w9)1259end12601261# Convert primitive to conservative variables1262@inline function prim2cons(prim, equations::IdealGlmMhdEquations3D)1263rho, v1, v2, v3, p, B1, B2, B3, psi = prim12641265rho_v1 = rho * v11266rho_v2 = rho * v21267rho_v3 = rho * v31268rho_e_total = p * equations.inv_gamma_minus_one +12690.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) +12700.5f0 * (B1^2 + B2^2 + B3^2) + 0.5f0 * psi^212711272return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi)1273end12741275@inline function density(u, equations::IdealGlmMhdEquations3D)1276rho = u[1]1277return rho1278end12791280@inline function velocity(u, equations::IdealGlmMhdEquations3D)1281rho = u[1]1282v1 = u[2] / rho1283v2 = u[3] / rho1284v3 = u[4] / rho1285return SVector(v1, v2, v3)1286end12871288@inline function velocity(u, orientation::Int, equations::IdealGlmMhdEquations3D)1289rho = u[1]1290v = u[orientation + 1] / rho1291return v1292end12931294@doc raw"""1295pressure(u, equations::IdealGlmMhdEquations3D)12961297Computes the pressure for an ideal equation of state with1298isentropic exponent/adiabatic index ``\gamma`` from the conserved variables `u`.1299```math1300\begin{aligned}1301p &= (\gamma - 1) \left( \rho e_{\text{total}} - \rho e_{\text{kinetic}} - \rho e_{\text{magnetic}} - \frac{1}{2} \psi^2 \right) \\1302&= (\gamma - 1) \left( \rho e - \frac{1}{2}1303\left[\rho \Vert v \Vert_2^2 + \Vert B \Vert_2^2 + \psi^2 \right] \right)1304\end{aligned}1305```1306"""1307@inline function pressure(u, equations::IdealGlmMhdEquations3D)1308rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi = u1309p = (equations.gamma - 1) * (rho_e_total -13100.5f0 *1311((rho_v1^2 + rho_v2^2 + rho_v3^2) / rho +1312(B1^2 + B2^2 + B3^2) + psi^2))1313return p1314end13151316# Transformation from conservative variables u to d(p)/d(u)1317@inline function gradient_conservative(::typeof(pressure),1318u, equations::IdealGlmMhdEquations3D)1319rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi = u13201321v1 = rho_v1 / rho1322v2 = rho_v2 / rho1323v3 = rho_v3 / rho1324v_square = v1^2 + v2^2 + v3^213251326return (equations.gamma - 1) *1327SVector(0.5f0 * v_square, -v1, -v2, -v3, 1, -B1, -B2, -B3, -psi)1328end13291330@inline function density_pressure(u, equations::IdealGlmMhdEquations3D)1331rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi = u1332rho_times_p = (equations.gamma - 1) * (rho * rho_e_total -13330.5f0 * (rho_v1^2 + rho_v2^2 + rho_v3^2 +1334rho * (B1^2 + B2^2 + B3^2 + psi^2)))1335return rho_times_p1336end13371338# Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue1339@inline function calc_fast_wavespeed(cons, orientation::Integer,1340equations::IdealGlmMhdEquations3D)1341rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi = cons1342v1 = rho_v1 / rho1343v2 = rho_v2 / rho1344v3 = rho_v3 / rho1345kin_en = 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3)1346mag_en = 0.5f0 * (B1 * B1 + B2 * B2 + B3 * B3)1347p = (equations.gamma - 1) * (rho_e_total - kin_en - mag_en - 0.5f0 * psi^2)1348a_square = equations.gamma * p / rho1349sqrt_rho = sqrt(rho)1350b1 = B1 / sqrt_rho1351b2 = B2 / sqrt_rho1352b3 = B3 / sqrt_rho1353b_square = b1 * b1 + b2 * b2 + b3 * b31354if orientation == 1 # x-direction1355c_f = sqrt(0.5f0 * (a_square + b_square) +13560.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b1^2))1357elseif orientation == 2 # y-direction1358c_f = sqrt(0.5f0 * (a_square + b_square) +13590.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b2^2))1360else # z-direction1361c_f = sqrt(0.5f0 * (a_square + b_square) +13620.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b3^2))1363end1364return c_f1365end13661367@inline function calc_fast_wavespeed(cons, normal_direction::AbstractVector,1368equations::IdealGlmMhdEquations3D)1369rho, rho_v1, rho_v2, rho_v3, rho_e_total, B1, B2, B3, psi = cons1370v1 = rho_v1 / rho1371v2 = rho_v2 / rho1372v3 = rho_v3 / rho1373kin_en = 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3)1374mag_en = 0.5f0 * (B1 * B1 + B2 * B2 + B3 * B3)1375p = (equations.gamma - 1) * (rho_e_total - kin_en - mag_en - 0.5f0 * psi^2)1376a_square = equations.gamma * p / rho1377sqrt_rho = sqrt(rho)1378b1 = B1 / sqrt_rho1379b2 = B2 / sqrt_rho1380b3 = B3 / sqrt_rho1381b_square = b1 * b1 + b2 * b2 + b3 * b31382norm_squared = (normal_direction[1] * normal_direction[1] +1383normal_direction[2] * normal_direction[2] +1384normal_direction[3] * normal_direction[3])1385b_dot_n_squared = (b1 * normal_direction[1] +1386b2 * normal_direction[2] +1387b3 * normal_direction[3])^2 / norm_squared13881389c_f = sqrt((0.5f0 * (a_square + b_square) +13900.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b_dot_n_squared)) *1391norm_squared)1392return c_f1393end13941395"""1396calc_fast_wavespeed_roe(u_ll, u_rr, orientation_or_normal_direction, equations::IdealGlmMhdEquations3D)13971398Compute the fast magnetoacoustic wave speed using Roe averages as given by1399- Cargo and Gallice (1997)1400Roe Matrices for Ideal MHD and Systematic Construction1401of Roe Matrices for Systems of Conservation Laws1402[DOI: 10.1006/jcph.1997.5773](https://doi.org/10.1006/jcph.1997.5773)1403"""1404@inline function calc_fast_wavespeed_roe(u_ll, u_rr, orientation::Integer,1405equations::IdealGlmMhdEquations3D)1406rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_total_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll1407rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_total_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr14081409# Calculate primitive variables1410v1_ll = rho_v1_ll / rho_ll1411v2_ll = rho_v2_ll / rho_ll1412v3_ll = rho_v3_ll / rho_ll1413kin_en_ll = 0.5f0 * (rho_v1_ll * v1_ll + rho_v2_ll * v2_ll + rho_v3_ll * v3_ll)1414mag_norm_ll = B1_ll * B1_ll + B2_ll * B2_ll + B3_ll * B3_ll1415p_ll = (equations.gamma - 1) *1416(rho_e_total_ll - kin_en_ll - 0.5f0 * mag_norm_ll - 0.5f0 * psi_ll^2)14171418v1_rr = rho_v1_rr / rho_rr1419v2_rr = rho_v2_rr / rho_rr1420v3_rr = rho_v3_rr / rho_rr1421kin_en_rr = 0.5f0 * (rho_v1_rr * v1_rr + rho_v2_rr * v2_rr + rho_v3_rr * v3_rr)1422mag_norm_rr = B1_rr * B1_rr + B2_rr * B2_rr + B3_rr * B3_rr1423p_rr = (equations.gamma - 1) *1424(rho_e_total_rr - kin_en_rr - 0.5f0 * mag_norm_rr - 0.5f0 * psi_rr^2)14251426# compute total pressure which is thermal + magnetic pressures1427p_total_ll = p_ll + 0.5f0 * mag_norm_ll1428p_total_rr = p_rr + 0.5f0 * mag_norm_rr14291430# compute the Roe density averages1431sqrt_rho_ll = sqrt(rho_ll)1432sqrt_rho_rr = sqrt(rho_rr)1433inv_sqrt_rho_add = 1 / (sqrt_rho_ll + sqrt_rho_rr)1434inv_sqrt_rho_prod = 1 / (sqrt_rho_ll * sqrt_rho_rr)1435rho_ll_roe = sqrt_rho_ll * inv_sqrt_rho_add1436rho_rr_roe = sqrt_rho_rr * inv_sqrt_rho_add1437# Roe averages1438# velocities and magnetic fields1439v1_roe = v1_ll * rho_ll_roe + v1_rr * rho_rr_roe1440v2_roe = v2_ll * rho_ll_roe + v2_rr * rho_rr_roe1441v3_roe = v3_ll * rho_ll_roe + v3_rr * rho_rr_roe1442B1_roe = B1_ll * rho_ll_roe + B1_rr * rho_rr_roe1443B2_roe = B2_ll * rho_ll_roe + B2_rr * rho_rr_roe1444B3_roe = B3_ll * rho_ll_roe + B3_rr * rho_rr_roe1445# enthalpy1446H_ll = (rho_e_total_ll + p_total_ll) / rho_ll1447H_rr = (rho_e_total_rr + p_total_rr) / rho_rr1448H_roe = H_ll * rho_ll_roe + H_rr * rho_rr_roe1449# temporary variable see equation (4.12) in Cargo and Gallice1450X = 0.5f0 * ((B1_ll - B1_rr)^2 + (B2_ll - B2_rr)^2 + (B3_ll - B3_rr)^2) *1451inv_sqrt_rho_add^21452# averaged components needed to compute c_f, the fast magnetoacoustic wave speed1453b_square_roe = (B1_roe^2 + B2_roe^2 + B3_roe^2) * inv_sqrt_rho_prod # scaled magnectic sum1454a_square_roe = ((2 - equations.gamma) * X +1455(equations.gamma - 1) *1456(H_roe - 0.5f0 * (v1_roe^2 + v2_roe^2 + v3_roe^2) -1457b_square_roe)) # acoustic speed1458# finally compute the average wave speed and set the output velocity (depends on orientation)1459if orientation == 1 # x-direction1460c_a_roe = B1_roe^2 * inv_sqrt_rho_prod # (squared) Alfvén wave speed1461a_star_roe = sqrt((a_square_roe + b_square_roe)^2 -14624 * a_square_roe * c_a_roe)1463c_f_roe = sqrt(0.5f0 * (a_square_roe + b_square_roe + a_star_roe))1464vel_out_roe = v1_roe1465elseif orientation == 2 # y-direction1466c_a_roe = B2_roe^2 * inv_sqrt_rho_prod # (squared) Alfvén wave speed1467a_star_roe = sqrt((a_square_roe + b_square_roe)^2 -14684 * a_square_roe * c_a_roe)1469c_f_roe = sqrt(0.5f0 * (a_square_roe + b_square_roe + a_star_roe))1470vel_out_roe = v2_roe1471else # z-direction1472c_a_roe = B3_roe^2 * inv_sqrt_rho_prod # (squared) Alfvén wave speed1473a_star_roe = sqrt((a_square_roe + b_square_roe)^2 -14744 * a_square_roe * c_a_roe)1475c_f_roe = sqrt(0.5f0 * (a_square_roe + b_square_roe + a_star_roe))1476vel_out_roe = v3_roe1477end14781479return vel_out_roe, c_f_roe1480end14811482@inline function calc_fast_wavespeed_roe(u_ll, u_rr, normal_direction::AbstractVector,1483equations::IdealGlmMhdEquations3D)1484rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_total_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll1485rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_total_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr14861487# Calculate primitive variables1488v1_ll = rho_v1_ll / rho_ll1489v2_ll = rho_v2_ll / rho_ll1490v3_ll = rho_v3_ll / rho_ll1491kin_en_ll = 0.5f0 * (rho_v1_ll * v1_ll + rho_v2_ll * v2_ll + rho_v3_ll * v3_ll)1492mag_norm_ll = B1_ll * B1_ll + B2_ll * B2_ll + B3_ll * B3_ll1493p_ll = (equations.gamma - 1) *1494(rho_e_total_ll - kin_en_ll - 0.5f0 * mag_norm_ll - 0.5f0 * psi_ll^2)14951496v1_rr = rho_v1_rr / rho_rr1497v2_rr = rho_v2_rr / rho_rr1498v3_rr = rho_v3_rr / rho_rr1499kin_en_rr = 0.5f0 * (rho_v1_rr * v1_rr + rho_v2_rr * v2_rr + rho_v3_rr * v3_rr)1500mag_norm_rr = B1_rr * B1_rr + B2_rr * B2_rr + B3_rr * B3_rr1501p_rr = (equations.gamma - 1) *1502(rho_e_total_rr - kin_en_rr - 0.5f0 * mag_norm_rr - 0.5f0 * psi_rr^2)15031504# compute total pressure which is thermal + magnetic pressures1505p_total_ll = p_ll + 0.5f0 * mag_norm_ll1506p_total_rr = p_rr + 0.5f0 * mag_norm_rr15071508# compute the Roe density averages1509sqrt_rho_ll = sqrt(rho_ll)1510sqrt_rho_rr = sqrt(rho_rr)1511inv_sqrt_rho_add = 1 / (sqrt_rho_ll + sqrt_rho_rr)1512inv_sqrt_rho_prod = 1 / (sqrt_rho_ll * sqrt_rho_rr)1513rho_ll_roe = sqrt_rho_ll * inv_sqrt_rho_add1514rho_rr_roe = sqrt_rho_rr * inv_sqrt_rho_add1515# Roe averages1516# velocities and magnetic fields1517v1_roe = v1_ll * rho_ll_roe + v1_rr * rho_rr_roe1518v2_roe = v2_ll * rho_ll_roe + v2_rr * rho_rr_roe1519v3_roe = v3_ll * rho_ll_roe + v3_rr * rho_rr_roe1520B1_roe = B1_ll * rho_ll_roe + B1_rr * rho_rr_roe1521B2_roe = B2_ll * rho_ll_roe + B2_rr * rho_rr_roe1522B3_roe = B3_ll * rho_ll_roe + B3_rr * rho_rr_roe1523# enthalpy1524H_ll = (rho_e_total_ll + p_total_ll) / rho_ll1525H_rr = (rho_e_total_rr + p_total_rr) / rho_rr1526H_roe = H_ll * rho_ll_roe + H_rr * rho_rr_roe1527# temporary variable see equation (4.12) in Cargo and Gallice1528X = 0.5f0 * ((B1_ll - B1_rr)^2 + (B2_ll - B2_rr)^2 + (B3_ll - B3_rr)^2) *1529inv_sqrt_rho_add^21530# averaged components needed to compute c_f, the fast magnetoacoustic wave speed1531b_square_roe = (B1_roe^2 + B2_roe^2 + B3_roe^2) * inv_sqrt_rho_prod # scaled magnectic sum1532a_square_roe = ((2 - equations.gamma) * X +1533(equations.gamma - 1) *1534(H_roe - 0.5f0 * (v1_roe^2 + v2_roe^2 + v3_roe^2) -1535b_square_roe)) # acoustic speed15361537# finally compute the average wave speed and set the output velocity (depends on orientation)1538norm_squared = (normal_direction[1] * normal_direction[1] +1539normal_direction[2] * normal_direction[2] +1540normal_direction[3] * normal_direction[3])1541B_roe_dot_n_squared = (B1_roe * normal_direction[1] +1542B2_roe * normal_direction[2] +1543B3_roe * normal_direction[3])^2 / norm_squared15441545c_a_roe = B_roe_dot_n_squared * inv_sqrt_rho_prod # (squared) Alfvén wave speed1546a_star_roe = sqrt((a_square_roe + b_square_roe)^2 - 4 * a_square_roe * c_a_roe)1547c_f_roe = sqrt(0.5f0 * (a_square_roe + b_square_roe + a_star_roe) * norm_squared)1548vel_out_roe = (v1_roe * normal_direction[1] +1549v2_roe * normal_direction[2] +1550v3_roe * normal_direction[3])15511552return vel_out_roe, c_f_roe1553end15541555# Calculate thermodynamic entropy for a conservative state `cons`1556@inline function entropy_thermodynamic(cons, equations::IdealGlmMhdEquations3D)1557# Pressure1558p = (equations.gamma - 1) *1559(cons[5] - 0.5f0 * (cons[2]^2 + cons[3]^2 + cons[4]^2) / cons[1]1560-15610.5f0 * (cons[6]^2 + cons[7]^2 + cons[8]^2)1562-15630.5f0 * cons[9]^2)15641565# Thermodynamic entropy1566s = log(p) - equations.gamma * log(cons[1])15671568return s1569end15701571# Calculate mathematical entropy for a conservative state `cons`1572@inline function entropy_math(cons, equations::IdealGlmMhdEquations3D)1573S = -entropy_thermodynamic(cons, equations) * cons[1] *1574equations.inv_gamma_minus_one15751576return S1577end15781579# Default entropy is the mathematical entropy1580@inline entropy(cons, equations::IdealGlmMhdEquations3D) = entropy_math(cons, equations)15811582# Calculate total energy for a conservative state `cons`1583@inline energy_total(cons, ::IdealGlmMhdEquations3D) = cons[5]15841585# Calculate kinetic energy for a conservative state `cons`1586@inline function energy_kinetic(cons, equations::IdealGlmMhdEquations3D)1587return 0.5f0 * (cons[2]^2 + cons[3]^2 + cons[4]^2) / cons[1]1588end15891590# Calculate the magnetic energy for a conservative state `cons`.1591# OBS! For non-dinmensional form of the ideal MHD magnetic pressure ≡ magnetic energy1592@inline function energy_magnetic(cons, ::IdealGlmMhdEquations3D)1593return 0.5f0 * (cons[6]^2 + cons[7]^2 + cons[8]^2)1594end15951596# Calculate internal energy for a conservative state `cons`1597@inline function energy_internal(cons, equations::IdealGlmMhdEquations3D)1598return (energy_total(cons, equations)1599-1600energy_kinetic(cons, equations)1601-1602energy_magnetic(cons, equations)1603-1604cons[9]^2 / 2)1605end16061607# State validation for Newton-bisection method of subcell IDP limiting1608@inline function Base.isvalid(u, equations::IdealGlmMhdEquations3D)1609if u[1] <= 0 || pressure(u, equations) <= 01610return false1611end1612return true1613end16141615# Calculate the cross helicity (\vec{v}⋅\vec{B}) for a conservative state `cons`1616@inline function cross_helicity(cons, ::IdealGlmMhdEquations3D)1617return (cons[2] * cons[6] + cons[3] * cons[7] + cons[4] * cons[8]) / cons[1]1618end1619end # @muladd162016211622