Path: blob/main/src/equations/ideal_glm_mhd_3d.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"""8IdealGlmMhdEquations3D(gamma)910The ideal compressible GLM-MHD equations for an ideal gas with ratio of11specific heats `gamma` in three space dimensions.12"""13struct IdealGlmMhdEquations3D{RealT <: Real} <:14AbstractIdealGlmMhdEquations{3, 9}15gamma::RealT # ratio of specific heats16inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications17c_h::RealT # GLM cleaning speed1819function IdealGlmMhdEquations3D(gamma, c_h)20γ, inv_gamma_minus_one, c_h = promote(gamma, inv(gamma - 1), c_h)21new{typeof(γ)}(γ, inv_gamma_minus_one, c_h)22end23end2425function IdealGlmMhdEquations3D(gamma; initial_c_h = convert(typeof(gamma), NaN))26# Use `promote` to ensure that `gamma` and `initial_c_h` have the same type27IdealGlmMhdEquations3D(promote(gamma, initial_c_h)...)28end2930# Outer constructor for `@reset` works correctly31function IdealGlmMhdEquations3D(gamma, inv_gamma_minus_one, c_h)32IdealGlmMhdEquations3D(gamma, c_h)33end3435have_nonconservative_terms(::IdealGlmMhdEquations3D) = True()36function varnames(::typeof(cons2cons), ::IdealGlmMhdEquations3D)37("rho", "rho_v1", "rho_v2", "rho_v3", "rho_e", "B1", "B2", "B3", "psi")38end39function varnames(::typeof(cons2prim), ::IdealGlmMhdEquations3D)40("rho", "v1", "v2", "v3", "p", "B1", "B2", "B3", "psi")41end42function default_analysis_integrals(::IdealGlmMhdEquations3D)43(entropy_timederivative, Val(:l2_divb), Val(:linf_divb))44end4546# Helper function to extract the magnetic field vector from the conservative variables47magnetic_field(u, equations::IdealGlmMhdEquations3D) = SVector(u[6], u[7], u[8])4849# Set initial conditions at physical location `x` for time `t`50"""51initial_condition_constant(x, t, equations::IdealGlmMhdEquations3D)5253A constant initial condition to test free-stream preservation.54"""55function initial_condition_constant(x, t, equations::IdealGlmMhdEquations3D)56RealT = eltype(x)57rho = 158rho_v1 = convert(RealT, 0.1)59rho_v2 = -convert(RealT, 0.2)60rho_v3 = -0.5f061rho_e = 5062B1 = 363B2 = -convert(RealT, 1.2)64B3 = 0.5f065psi = 066return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi)67end6869"""70initial_condition_convergence_test(x, t, equations::IdealGlmMhdEquations3D)7172An Alfvén wave as smooth initial condition used for convergence tests.73See for reference section 5.1 in74- Christoph Altmann (2012)75Explicit Discontinuous Galerkin Methods for Magnetohydrodynamics76[DOI: 10.18419/opus-3895](http://dx.doi.org/10.18419/opus-3895)77"""78function initial_condition_convergence_test(x, t, equations::IdealGlmMhdEquations3D)79# Alfvén wave in three space dimensions80# domain must be set to [-1, 1]^3, γ = 5/381RealT = eltype(x)82p = 183omega = 2 * convert(RealT, pi) # may be multiplied by frequency84# r: length-variable = length of computational domain85r = convert(RealT, 2)86# e: epsilon = 0.287e = convert(RealT, 0.2)88nx = 1 / sqrt(r^2 + 1)89ny = r / sqrt(r^2 + 1)90sqr = 191Va = omega / (ny * sqr)92phi_alv = omega / ny * (nx * (x[1] - 0.5f0 * r) + ny * (x[2] - 0.5f0 * r)) - Va * t9394rho = 195v1 = -e * ny * cos(phi_alv) / rho96v2 = e * nx * cos(phi_alv) / rho97v3 = e * sin(phi_alv) / rho98B1 = nx - rho * v1 * sqr99B2 = ny - rho * v2 * sqr100B3 = -rho * v3 * sqr101psi = 0102103return prim2cons(SVector(rho, v1, v2, v3, p, B1, B2, B3, psi), equations)104end105106"""107initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdEquations3D)108109A weak blast wave adapted from110- Sebastian Hennemann, Gregor J. Gassner (2020)111A provably entropy stable subcell shock capturing approach for high order split form DG112[arXiv: 2008.12044](https://arxiv.org/abs/2008.12044)113"""114function initial_condition_weak_blast_wave(x, t, equations::IdealGlmMhdEquations3D)115# Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3)116# Same discontinuity in the velocities but with magnetic fields117# Set up polar coordinates118RealT = eltype(x)119inicenter = (0, 0, 0)120x_norm = x[1] - inicenter[1]121y_norm = x[2] - inicenter[2]122z_norm = x[3] - inicenter[3]123r = sqrt(x_norm^2 + y_norm^2 + z_norm^2)124phi = atan(y_norm, x_norm)125theta = iszero(r) ? zero(RealT) : acos(z_norm / r)126127# Calculate primitive variables128rho = r > 0.5f0 ? one(RealT) : convert(RealT, 1.1691)129v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(phi) * sin(theta)130v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin(phi) * sin(theta)131v3 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(theta)132p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245)133134return prim2cons(SVector(rho, v1, v2, v3, p, 1, 1, 1, 0), equations)135end136137# Pre-defined source terms should be implemented as138# function source_terms_WHATEVER(u, x, t, equations::IdealGlmMhdEquations3D)139140# Calculate 1D flux for a single point141@inline function flux(u, orientation::Integer, equations::IdealGlmMhdEquations3D)142rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u143v1 = rho_v1 / rho144v2 = rho_v2 / rho145v3 = rho_v3 / rho146kin_en = 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3)147mag_en = 0.5f0 * (B1 * B1 + B2 * B2 + B3 * B3)148p_over_gamma_minus_one = (rho_e - kin_en - mag_en - 0.5f0 * psi^2)149p = (equations.gamma - 1) * p_over_gamma_minus_one150if orientation == 1151f1 = rho_v1152f2 = rho_v1 * v1 + p + mag_en - B1^2153f3 = rho_v1 * v2 - B1 * B2154f4 = rho_v1 * v3 - B1 * B3155f5 = (kin_en + equations.gamma * p_over_gamma_minus_one + 2 * mag_en) * v1 -156B1 * (v1 * B1 + v2 * B2 + v3 * B3) + equations.c_h * psi * B1157f6 = equations.c_h * psi158f7 = v1 * B2 - v2 * B1159f8 = v1 * B3 - v3 * B1160f9 = equations.c_h * B1161elseif orientation == 2162f1 = rho_v2163f2 = rho_v2 * v1 - B2 * B1164f3 = rho_v2 * v2 + p + mag_en - B2^2165f4 = rho_v2 * v3 - B2 * B3166f5 = (kin_en + equations.gamma * p_over_gamma_minus_one + 2 * mag_en) * v2 -167B2 * (v1 * B1 + v2 * B2 + v3 * B3) + equations.c_h * psi * B2168f6 = v2 * B1 - v1 * B2169f7 = equations.c_h * psi170f8 = v2 * B3 - v3 * B2171f9 = equations.c_h * B2172else173f1 = rho_v3174f2 = rho_v3 * v1 - B3 * B1175f3 = rho_v3 * v2 - B3 * B2176f4 = rho_v3 * v3 + p + mag_en - B3^2177f5 = (kin_en + equations.gamma * p_over_gamma_minus_one + 2 * mag_en) * v3 -178B3 * (v1 * B1 + v2 * B2 + v3 * B3) + equations.c_h * psi * B3179f6 = v3 * B1 - v1 * B3180f7 = v3 * B2 - v2 * B3181f8 = equations.c_h * psi182f9 = equations.c_h * B3183end184185return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)186end187188# Calculate 1D flux for a single point in the normal direction189# Note, this directional vector is not normalized190@inline function flux(u, normal_direction::AbstractVector,191equations::IdealGlmMhdEquations3D)192rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u193v1 = rho_v1 / rho194v2 = rho_v2 / rho195v3 = rho_v3 / rho196kin_en = 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3)197mag_en = 0.5f0 * (B1 * B1 + B2 * B2 + B3 * B3)198p_over_gamma_minus_one = (rho_e - kin_en - mag_en - 0.5f0 * psi^2)199p = (equations.gamma - 1) * p_over_gamma_minus_one200201v_normal = v1 * normal_direction[1] + v2 * normal_direction[2] +202v3 * normal_direction[3]203B_normal = B1 * normal_direction[1] + B2 * normal_direction[2] +204B3 * normal_direction[3]205rho_v_normal = rho * v_normal206207f1 = rho_v_normal208f2 = rho_v_normal * v1 - B1 * B_normal + (p + mag_en) * normal_direction[1]209f3 = rho_v_normal * v2 - B2 * B_normal + (p + mag_en) * normal_direction[2]210f4 = rho_v_normal * v3 - B3 * B_normal + (p + mag_en) * normal_direction[3]211f5 = ((kin_en + equations.gamma * p_over_gamma_minus_one + 2 * mag_en) * v_normal212-213B_normal * (v1 * B1 + v2 * B2 + v3 * B3) + equations.c_h * psi * B_normal)214f6 = (equations.c_h * psi * normal_direction[1] +215(v2 * B1 - v1 * B2) * normal_direction[2] +216(v3 * B1 - v1 * B3) * normal_direction[3])217f7 = ((v1 * B2 - v2 * B1) * normal_direction[1] +218equations.c_h * psi * normal_direction[2] +219(v3 * B2 - v2 * B3) * normal_direction[3])220f8 = ((v1 * B3 - v3 * B1) * normal_direction[1] +221(v2 * B3 - v3 * B2) * normal_direction[2] +222equations.c_h * psi * normal_direction[3])223f9 = equations.c_h * B_normal224225return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)226end227228"""229flux_nonconservative_powell(u_ll, u_rr, orientation::Integer,230equations::IdealGlmMhdEquations3D)231flux_nonconservative_powell(u_ll, u_rr,232normal_direction::AbstractVector,233equations::IdealGlmMhdEquations3D)234235Non-symmetric two-point flux discretizing the nonconservative (source) term of236Powell and the Galilean nonconservative term associated with the GLM multiplier237of the [`IdealGlmMhdEquations3D`](@ref).238239On curvilinear meshes, the implementation differs from the reference since we use the averaged240normal direction for the metrics dealiasing.241242## References243- Marvin Bohm, Andrew R.Winters, Gregor J. Gassner, Dominik Derigs,244Florian Hindenlang, Joachim Saur245An entropy stable nodal discontinuous Galerkin method for the resistive MHD246equations. Part I: Theory and numerical verification247[DOI: 10.1016/j.jcp.2018.06.027](https://doi.org/10.1016/j.jcp.2018.06.027)248"""249@inline function flux_nonconservative_powell(u_ll, u_rr, orientation::Integer,250equations::IdealGlmMhdEquations3D)251rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll252rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr253254v1_ll = rho_v1_ll / rho_ll255v2_ll = rho_v2_ll / rho_ll256v3_ll = rho_v3_ll / rho_ll257v_dot_B_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll258259# Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0)260# Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2,3}, 0, 0, 0, v_{1,2,3})261if orientation == 1262f = SVector(0,263B1_ll * B1_rr,264B2_ll * B1_rr,265B3_ll * B1_rr,266v_dot_B_ll * B1_rr + v1_ll * psi_ll * psi_rr,267v1_ll * B1_rr,268v2_ll * B1_rr,269v3_ll * B1_rr,270v1_ll * psi_rr)271elseif orientation == 2272f = SVector(0,273B1_ll * B2_rr,274B2_ll * B2_rr,275B3_ll * B2_rr,276v_dot_B_ll * B2_rr + v2_ll * psi_ll * psi_rr,277v1_ll * B2_rr,278v2_ll * B2_rr,279v3_ll * B2_rr,280v2_ll * psi_rr)281else # orientation == 3282f = SVector(0,283B1_ll * B3_rr,284B2_ll * B3_rr,285B3_ll * B3_rr,286v_dot_B_ll * B3_rr + v3_ll * psi_ll * psi_rr,287v1_ll * B3_rr,288v2_ll * B3_rr,289v3_ll * B3_rr,290v3_ll * psi_rr)291end292293return f294end295296@inline function flux_nonconservative_powell(u_ll, u_rr,297normal_direction::AbstractVector,298equations::IdealGlmMhdEquations3D)299rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll300rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr301302v1_ll = rho_v1_ll / rho_ll303v2_ll = rho_v2_ll / rho_ll304v3_ll = rho_v3_ll / rho_ll305v_dot_B_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll306307v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] +308v3_ll * normal_direction[3]309B_dot_n_rr = B1_rr * normal_direction[1] +310B2_rr * normal_direction[2] +311B3_rr * normal_direction[3]312313# Powell nonconservative term: (0, B_1, B_2, B_3, v⋅B, v_1, v_2, v_3, 0)314# Galilean nonconservative term: (0, 0, 0, 0, ψ v_{1,2,3}, 0, 0, 0, v_{1,2,3})315f = SVector(0,316B1_ll * B_dot_n_rr,317B2_ll * B_dot_n_rr,318B3_ll * B_dot_n_rr,319v_dot_B_ll * B_dot_n_rr + v_dot_n_ll * psi_ll * psi_rr,320v1_ll * B_dot_n_rr,321v2_ll * B_dot_n_rr,322v3_ll * B_dot_n_rr,323v_dot_n_ll * psi_rr)324325return f326end327328"""329flux_derigs_etal(u_ll, u_rr, orientation, equations::IdealGlmMhdEquations3D)330331Entropy conserving two-point flux by332- Derigs et al. (2018)333Ideal GLM-MHD: About the entropy consistent nine-wave magnetic field334divergence diminishing ideal magnetohydrodynamics equations335[DOI: 10.1016/j.jcp.2018.03.002](https://doi.org/10.1016/j.jcp.2018.03.002)336"""337function flux_derigs_etal(u_ll, u_rr, orientation::Integer,338equations::IdealGlmMhdEquations3D)339# Unpack left and right states to get velocities, pressure, and inverse temperature (called beta)340rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll, psi_ll = cons2prim(u_ll,341equations)342rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr, psi_rr = cons2prim(u_rr,343equations)344345vel_norm_ll = v1_ll^2 + v2_ll^2 + v3_ll^2346vel_norm_rr = v1_rr^2 + v2_rr^2 + v3_rr^2347mag_norm_ll = B1_ll^2 + B2_ll^2 + B3_ll^2348mag_norm_rr = B1_rr^2 + B2_rr^2 + B3_rr^2349beta_ll = 0.5f0 * rho_ll / p_ll350beta_rr = 0.5f0 * rho_rr / p_rr351# for convenience store v⋅B352vel_dot_mag_ll = v1_ll * B1_ll + v2_ll * B2_ll + v3_ll * B3_ll353vel_dot_mag_rr = v1_rr * B1_rr + v2_rr * B2_rr + v3_rr * B3_rr354355# Compute the necessary mean values needed for either direction356rho_avg = 0.5f0 * (rho_ll + rho_rr)357rho_mean = ln_mean(rho_ll, rho_rr)358beta_mean = ln_mean(beta_ll, beta_rr)359beta_avg = 0.5f0 * (beta_ll + beta_rr)360v1_avg = 0.5f0 * (v1_ll + v1_rr)361v2_avg = 0.5f0 * (v2_ll + v2_rr)362v3_avg = 0.5f0 * (v3_ll + v3_rr)363p_mean = 0.5f0 * rho_avg / beta_avg364B1_avg = 0.5f0 * (B1_ll + B1_rr)365B2_avg = 0.5f0 * (B2_ll + B2_rr)366B3_avg = 0.5f0 * (B3_ll + B3_rr)367psi_avg = 0.5f0 * (psi_ll + psi_rr)368vel_norm_avg = 0.5f0 * (vel_norm_ll + vel_norm_rr)369mag_norm_avg = 0.5f0 * (mag_norm_ll + mag_norm_rr)370vel_dot_mag_avg = 0.5f0 * (vel_dot_mag_ll + vel_dot_mag_rr)371372# Calculate fluxes depending on orientation with specific direction averages373if orientation == 1374f1 = rho_mean * v1_avg375f2 = f1 * v1_avg + p_mean + 0.5f0 * mag_norm_avg - B1_avg * B1_avg376f3 = f1 * v2_avg - B1_avg * B2_avg377f4 = f1 * v3_avg - B1_avg * B3_avg378f6 = equations.c_h * psi_avg379f7 = v1_avg * B2_avg - v2_avg * B1_avg380f8 = v1_avg * B3_avg - v3_avg * B1_avg381f9 = equations.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)385f5 = (f1 * 0.5f0 * (1 / (equations.gamma - 1) / beta_mean - vel_norm_avg) +386f2 * v1_avg + f3 * v2_avg +387f4 * v3_avg + f6 * B1_avg + f7 * B2_avg + f8 * B3_avg + f9 * psi_avg -3880.5f0 * v1_mag_avg +389B1_avg * vel_dot_mag_avg - equations.c_h * psi_B1_avg)390elseif orientation == 2391f1 = rho_mean * v2_avg392f2 = f1 * v1_avg - B2_avg * B1_avg393f3 = f1 * v2_avg + p_mean + 0.5f0 * mag_norm_avg - B2_avg * B2_avg394f4 = f1 * v3_avg - B2_avg * B3_avg395f6 = v2_avg * B1_avg - v1_avg * B2_avg396f7 = equations.c_h * psi_avg397f8 = v2_avg * B3_avg - v3_avg * B2_avg398f9 = equations.c_h * B2_avg399# total energy flux is complicated and involves the previous eight components400psi_B2_avg = 0.5f0 * (B2_ll * psi_ll + B2_rr * psi_rr)401v2_mag_avg = 0.5f0 * (v2_ll * mag_norm_ll + v2_rr * mag_norm_rr)402f5 = (f1 * 0.5f0 * (1 / (equations.gamma - 1) / beta_mean - vel_norm_avg) +403f2 * v1_avg + f3 * v2_avg +404f4 * v3_avg + f6 * B1_avg + f7 * B2_avg + f8 * B3_avg + f9 * psi_avg -4050.5f0 * v2_mag_avg +406B2_avg * vel_dot_mag_avg - equations.c_h * psi_B2_avg)407else408f1 = rho_mean * v3_avg409f2 = f1 * v1_avg - B3_avg * B1_avg410f3 = f1 * v2_avg - B3_avg * B2_avg411f4 = f1 * v3_avg + p_mean + 0.5f0 * mag_norm_avg - B3_avg * B3_avg412f6 = v3_avg * B1_avg - v1_avg * B3_avg413f7 = v3_avg * B2_avg - v2_avg * B3_avg414f8 = equations.c_h * psi_avg415f9 = equations.c_h * B3_avg416# total energy flux is complicated and involves the previous eight components417psi_B3_avg = 0.5f0 * (B3_ll * psi_ll + B3_rr * psi_rr)418v3_mag_avg = 0.5f0 * (v3_ll * mag_norm_ll + v3_rr * mag_norm_rr)419f5 = (f1 * 0.5f0 * (1 / (equations.gamma - 1) / beta_mean - vel_norm_avg) +420f2 * v1_avg + f3 * v2_avg +421f4 * v3_avg + f6 * B1_avg + f7 * B2_avg + f8 * B3_avg + f9 * psi_avg -4220.5f0 * v3_mag_avg +423B3_avg * vel_dot_mag_avg - equations.c_h * psi_B3_avg)424end425426return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)427end428429"""430flux_hindenlang_gassner(u_ll, u_rr, orientation_or_normal_direction,431equations::IdealGlmMhdEquations3D)432433Entropy conserving and kinetic energy preserving two-point flux of434Hindenlang and Gassner (2019), extending [`flux_ranocha`](@ref) to the MHD equations.435436## References437- Florian Hindenlang, Gregor Gassner (2019)438A new entropy conservative two-point flux for ideal MHD equations derived from439first principles.440Presented at HONOM 2019: European workshop on high order numerical methods441for evolutionary PDEs, theory and applications442- Hendrik Ranocha (2018)443Generalised Summation-by-Parts Operators and Entropy Stability of Numerical Methods444for Hyperbolic Balance Laws445[PhD thesis, TU Braunschweig](https://cuvillier.de/en/shop/publications/7743)446- Hendrik Ranocha (2020)447Entropy Conserving and Kinetic Energy Preserving Numerical Methods for448the Euler Equations Using Summation-by-Parts Operators449[Proceedings of ICOSAHOM 2018](https://doi.org/10.1007/978-3-030-39647-3_42)450"""451@inline function flux_hindenlang_gassner(u_ll, u_rr, orientation::Integer,452equations::IdealGlmMhdEquations3D)453# Unpack left and right states454rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll, psi_ll = cons2prim(u_ll,455equations)456rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr, psi_rr = cons2prim(u_rr,457equations)458459# Compute the necessary mean values needed for either direction460rho_mean = ln_mean(rho_ll, rho_rr)461# Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)`462# in exact arithmetic since463# log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ)464# = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ)465inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)466v1_avg = 0.5f0 * (v1_ll + v1_rr)467v2_avg = 0.5f0 * (v2_ll + v2_rr)468v3_avg = 0.5f0 * (v3_ll + v3_rr)469p_avg = 0.5f0 * (p_ll + p_rr)470psi_avg = 0.5f0 * (psi_ll + psi_rr)471velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr + v3_ll * v3_rr)472magnetic_square_avg = 0.5f0 * (B1_ll * B1_rr + B2_ll * B2_rr + B3_ll * B3_rr)473474# Calculate fluxes depending on orientation with specific direction averages475if orientation == 1476f1 = rho_mean * v1_avg477f2 = f1 * v1_avg + p_avg + magnetic_square_avg -4780.5f0 * (B1_ll * B1_rr + B1_rr * B1_ll)479f3 = f1 * v2_avg - 0.5f0 * (B1_ll * B2_rr + B1_rr * B2_ll)480f4 = f1 * v3_avg - 0.5f0 * (B1_ll * B3_rr + B1_rr * B3_ll)481#f5 below482f6 = equations.c_h * psi_avg483f7 = 0.5f0 * (v1_ll * B2_ll - v2_ll * B1_ll + v1_rr * B2_rr - v2_rr * B1_rr)484f8 = 0.5f0 * (v1_ll * B3_ll - v3_ll * B1_ll + v1_rr * B3_rr - v3_rr * B1_rr)485f9 = equations.c_h * 0.5f0 * (B1_ll + B1_rr)486# total energy flux is complicated and involves the previous components487f5 = (f1 *488(velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)489+4900.5f0 * (+p_ll * v1_rr + p_rr * v1_ll491+ (v1_ll * B2_ll * B2_rr + v1_rr * B2_rr * B2_ll)492+ (v1_ll * B3_ll * B3_rr + v1_rr * B3_rr * B3_ll)493-494(v2_ll * B1_ll * B2_rr + v2_rr * B1_rr * B2_ll)495-496(v3_ll * B1_ll * B3_rr + v3_rr * B1_rr * B3_ll)497+498equations.c_h * (B1_ll * psi_rr + B1_rr * psi_ll)))499elseif orientation == 2500f1 = rho_mean * v2_avg501f2 = f1 * v1_avg - 0.5f0 * (B2_ll * B1_rr + B2_rr * B1_ll)502f3 = f1 * v2_avg + p_avg + magnetic_square_avg -5030.5f0 * (B2_ll * B2_rr + B2_rr * B2_ll)504f4 = f1 * v3_avg - 0.5f0 * (B2_ll * B3_rr + B2_rr * B3_ll)505#f5 below506f6 = 0.5f0 * (v2_ll * B1_ll - v1_ll * B2_ll + v2_rr * B1_rr - v1_rr * B2_rr)507f7 = equations.c_h * psi_avg508f8 = 0.5f0 * (v2_ll * B3_ll - v3_ll * B2_ll + v2_rr * B3_rr - v3_rr * B2_rr)509f9 = equations.c_h * 0.5f0 * (B2_ll + B2_rr)510# total energy flux is complicated and involves the previous components511f5 = (f1 *512(velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)513+5140.5f0 * (+p_ll * v2_rr + p_rr * v2_ll515+ (v2_ll * B1_ll * B1_rr + v2_rr * B1_rr * B1_ll)516+ (v2_ll * B3_ll * B3_rr + v2_rr * B3_rr * B3_ll)517-518(v1_ll * B2_ll * B1_rr + v1_rr * B2_rr * B1_ll)519-520(v3_ll * B2_ll * B3_rr + v3_rr * B2_rr * B3_ll)521+522equations.c_h * (B2_ll * psi_rr + B2_rr * psi_ll)))523else # orientation == 3524f1 = rho_mean * v3_avg525f2 = f1 * v1_avg - 0.5f0 * (B3_ll * B1_rr + B3_rr * B1_ll)526f3 = f1 * v2_avg - 0.5f0 * (B3_ll * B2_rr + B3_rr * B2_ll)527f4 = f1 * v3_avg + p_avg + magnetic_square_avg -5280.5f0 * (B3_ll * B3_rr + B3_rr * B3_ll)529#f5 below530f6 = 0.5f0 * (v3_ll * B1_ll - v1_ll * B3_ll + v3_rr * B1_rr - v1_rr * B3_rr)531f7 = 0.5f0 * (v3_ll * B2_ll - v2_ll * B3_ll + v3_rr * B2_rr - v2_rr * B3_rr)532f8 = equations.c_h * psi_avg533f9 = equations.c_h * 0.5f0 * (B3_ll + B3_rr)534# total energy flux is complicated and involves the previous components535f5 = (f1 *536(velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)537+5380.5f0 * (+p_ll * v3_rr + p_rr * v3_ll539+ (v3_ll * B1_ll * B1_rr + v3_rr * B1_rr * B1_ll)540+ (v3_ll * B2_ll * B2_rr + v3_rr * B2_rr * B2_ll)541-542(v1_ll * B3_ll * B1_rr + v1_rr * B3_rr * B1_ll)543-544(v2_ll * B3_ll * B2_rr + v2_rr * B3_rr * B2_ll)545+546equations.c_h * (B3_ll * psi_rr + B3_rr * psi_ll)))547end548549return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)550end551552@inline function flux_hindenlang_gassner(u_ll, u_rr, normal_direction::AbstractVector,553equations::IdealGlmMhdEquations3D)554# Unpack left and right states555rho_ll, v1_ll, v2_ll, v3_ll, p_ll, B1_ll, B2_ll, B3_ll, psi_ll = cons2prim(u_ll,556equations)557rho_rr, v1_rr, v2_rr, v3_rr, p_rr, B1_rr, B2_rr, B3_rr, psi_rr = cons2prim(u_rr,558equations)559v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2] +560v3_ll * normal_direction[3]561v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2] +562v3_rr * normal_direction[3]563B_dot_n_ll = B1_ll * normal_direction[1] + B2_ll * normal_direction[2] +564B3_ll * normal_direction[3]565B_dot_n_rr = B1_rr * normal_direction[1] + B2_rr * normal_direction[2] +566B3_rr * normal_direction[3]567568# Compute the necessary mean values needed for either direction569rho_mean = ln_mean(rho_ll, rho_rr)570# Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)`571# in exact arithmetic since572# log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ)573# = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ)574inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)575v1_avg = 0.5f0 * (v1_ll + v1_rr)576v2_avg = 0.5f0 * (v2_ll + v2_rr)577v3_avg = 0.5f0 * (v3_ll + v3_rr)578p_avg = 0.5f0 * (p_ll + p_rr)579psi_avg = 0.5f0 * (psi_ll + psi_rr)580velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr + v3_ll * v3_rr)581magnetic_square_avg = 0.5f0 * (B1_ll * B1_rr + B2_ll * B2_rr + B3_ll * B3_rr)582583# Calculate fluxes depending on normal_direction584f1 = rho_mean * 0.5f0 * (v_dot_n_ll + v_dot_n_rr)585f2 = (f1 * v1_avg + (p_avg + magnetic_square_avg) * normal_direction[1]586-5870.5f0 * (B_dot_n_ll * B1_rr + B_dot_n_rr * B1_ll))588f3 = (f1 * v2_avg + (p_avg + magnetic_square_avg) * normal_direction[2]589-5900.5f0 * (B_dot_n_ll * B2_rr + B_dot_n_rr * B2_ll))591f4 = (f1 * v3_avg + (p_avg + magnetic_square_avg) * normal_direction[3]592-5930.5f0 * (B_dot_n_ll * B3_rr + B_dot_n_rr * B3_ll))594#f5 below595f6 = (equations.c_h * psi_avg * normal_direction[1]596+5970.5f0 * (v_dot_n_ll * B1_ll - v1_ll * B_dot_n_ll +598v_dot_n_rr * B1_rr - v1_rr * B_dot_n_rr))599f7 = (equations.c_h * psi_avg * normal_direction[2]600+6010.5f0 * (v_dot_n_ll * B2_ll - v2_ll * B_dot_n_ll +602v_dot_n_rr * B2_rr - v2_rr * B_dot_n_rr))603f8 = (equations.c_h * psi_avg * normal_direction[3]604+6050.5f0 * (v_dot_n_ll * B3_ll - v3_ll * B_dot_n_ll +606v_dot_n_rr * B3_rr - v3_rr * B_dot_n_rr))607f9 = equations.c_h * 0.5f0 * (B_dot_n_ll + B_dot_n_rr)608# total energy flux is complicated and involves the previous components609f5 = (f1 * (velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)610+6110.5f0 * (+p_ll * v_dot_n_rr + p_rr * v_dot_n_ll612+ (v_dot_n_ll * B1_ll * B1_rr + v_dot_n_rr * B1_rr * B1_ll)613+ (v_dot_n_ll * B2_ll * B2_rr + v_dot_n_rr * B2_rr * B2_ll)614+ (v_dot_n_ll * B3_ll * B3_rr + v_dot_n_rr * B3_rr * B3_ll)615-616(v1_ll * B_dot_n_ll * B1_rr + v1_rr * B_dot_n_rr * B1_ll)617-618(v2_ll * B_dot_n_ll * B2_rr + v2_rr * B_dot_n_rr * B2_ll)619-620(v3_ll * B_dot_n_ll * B3_rr + v3_rr * B_dot_n_rr * B3_ll)621+622equations.c_h * (B_dot_n_ll * psi_rr + B_dot_n_rr * psi_ll)))623624return SVector(f1, f2, f3, f4, f5, f6, f7, f8, f9)625end626627# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation628@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,629equations::IdealGlmMhdEquations3D)630rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll631rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr632633# Calculate the left/right velocities and fast magnetoacoustic wave speeds634if orientation == 1635v_ll = rho_v1_ll / rho_ll636v_rr = rho_v1_rr / rho_rr637elseif orientation == 2638v_ll = rho_v2_ll / rho_ll639v_rr = rho_v2_rr / rho_rr640else # orientation == 3641v_ll = rho_v3_ll / rho_ll642v_rr = rho_v3_rr / rho_rr643end644cf_ll = calc_fast_wavespeed(u_ll, orientation, equations)645cf_rr = calc_fast_wavespeed(u_rr, orientation, equations)646647return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr)648end649650@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,651equations::IdealGlmMhdEquations3D)652rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll653rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr654655# Calculate normal velocities and fast magnetoacoustic wave speeds656# left657v1_ll = rho_v1_ll / rho_ll658v2_ll = rho_v2_ll / rho_ll659v3_ll = rho_v3_ll / rho_ll660v_ll = (v1_ll * normal_direction[1]661+ v2_ll * normal_direction[2]662+ v3_ll * normal_direction[3])663cf_ll = calc_fast_wavespeed(u_ll, normal_direction, equations)664# right665v1_rr = rho_v1_rr / rho_rr666v2_rr = rho_v2_rr / rho_rr667v3_rr = rho_v3_rr / rho_rr668v_rr = (v1_rr * normal_direction[1]669+ v2_rr * normal_direction[2]670+ v3_rr * normal_direction[3])671cf_rr = calc_fast_wavespeed(u_rr, normal_direction, equations)672673# wave speeds already scaled by norm(normal_direction) in [`calc_fast_wavespeed`](@ref)674return max(abs(v_ll), abs(v_rr)) + max(cf_ll, cf_rr)675end676677# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`678@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,679equations::IdealGlmMhdEquations3D)680rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll681rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr682683# Calculate the left/right velocities and fast magnetoacoustic wave speeds684if orientation == 1685v_ll = rho_v1_ll / rho_ll686v_rr = rho_v1_rr / rho_rr687elseif orientation == 2688v_ll = rho_v2_ll / rho_ll689v_rr = rho_v2_rr / rho_rr690else # orientation == 3691v_ll = rho_v3_ll / rho_ll692v_rr = rho_v3_rr / rho_rr693end694cf_ll = calc_fast_wavespeed(u_ll, orientation, equations)695cf_rr = calc_fast_wavespeed(u_rr, orientation, equations)696697return max(abs(v_ll) + cf_ll, abs(v_rr) + cf_rr)698end699700# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`701@inline function max_abs_speed(u_ll, u_rr, normal_direction::AbstractVector,702equations::IdealGlmMhdEquations3D)703rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll704rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr705706# Calculate normal velocities and fast magnetoacoustic wave speeds707# left708v1_ll = rho_v1_ll / rho_ll709v2_ll = rho_v2_ll / rho_ll710v3_ll = rho_v3_ll / rho_ll711v_ll = (v1_ll * normal_direction[1]712+ v2_ll * normal_direction[2]713+ v3_ll * normal_direction[3])714cf_ll = calc_fast_wavespeed(u_ll, normal_direction, equations)715# right716v1_rr = rho_v1_rr / rho_rr717v2_rr = rho_v2_rr / rho_rr718v3_rr = rho_v3_rr / rho_rr719v_rr = (v1_rr * normal_direction[1]720+ v2_rr * normal_direction[2]721+ v3_rr * normal_direction[3])722cf_rr = calc_fast_wavespeed(u_rr, normal_direction, equations)723724# wave speeds already scaled by norm(normal_direction) in [`calc_fast_wavespeed`](@ref)725return max(abs(v_ll) + cf_ll, abs(v_rr) + cf_rr)726end727728# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes729@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer,730equations::IdealGlmMhdEquations3D)731rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll732rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr733734# Calculate primitive variables and speed of sound735v1_ll = rho_v1_ll / rho_ll736v2_ll = rho_v2_ll / rho_ll737v3_ll = rho_v3_ll / rho_ll738739v1_rr = rho_v1_rr / rho_rr740v2_rr = rho_v2_rr / rho_rr741v3_rr = rho_v3_rr / rho_rr742743# Approximate the left-most and right-most eigenvalues in the Riemann fan744if orientation == 1 # x-direction745λ_min = v1_ll - calc_fast_wavespeed(u_ll, orientation, equations)746λ_max = v1_rr + calc_fast_wavespeed(u_rr, orientation, equations)747elseif orientation == 2 # y-direction748λ_min = v2_ll - calc_fast_wavespeed(u_ll, orientation, equations)749λ_max = v2_rr + calc_fast_wavespeed(u_rr, orientation, equations)750else # z-direction751λ_min = v3_ll - calc_fast_wavespeed(u_ll, orientation, equations)752λ_max = v3_rr + calc_fast_wavespeed(u_rr, orientation, equations)753end754755return λ_min, λ_max756end757758@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,759equations::IdealGlmMhdEquations3D)760rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll761rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr762763# Calculate primitive velocity variables764v1_ll = rho_v1_ll / rho_ll765v2_ll = rho_v2_ll / rho_ll766v3_ll = rho_v3_ll / rho_ll767768v1_rr = rho_v1_rr / rho_rr769v2_rr = rho_v2_rr / rho_rr770v3_rr = rho_v3_rr / rho_rr771772v_normal_ll = (v1_ll * normal_direction[1] +773v2_ll * normal_direction[2] +774v3_ll * normal_direction[3])775v_normal_rr = (v1_rr * normal_direction[1] +776v2_rr * normal_direction[2] +777v3_rr * normal_direction[3])778779# Estimate the min/max eigenvalues in the normal direction780λ_min = v_normal_ll - calc_fast_wavespeed(u_ll, normal_direction, equations)781λ_max = v_normal_rr + calc_fast_wavespeed(u_rr, normal_direction, equations)782783return λ_min, λ_max784end785786# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes787@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer,788equations::IdealGlmMhdEquations3D)789rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll790rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr791792# Calculate primitive variables and speed of sound793v1_ll = rho_v1_ll / rho_ll794v2_ll = rho_v2_ll / rho_ll795v3_ll = rho_v3_ll / rho_ll796797v1_rr = rho_v1_rr / rho_rr798v2_rr = rho_v2_rr / rho_rr799v3_rr = rho_v3_rr / rho_rr800801# Approximate the left-most and right-most eigenvalues in the Riemann fan802if orientation == 1 # x-direction803c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)804c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)805806λ_min = min(v1_ll - c_f_ll, v1_rr - c_f_rr)807λ_max = max(v1_ll + c_f_ll, v1_rr + c_f_rr)808elseif orientation == 2 # y-direction809c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)810c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)811812λ_min = min(v2_ll - c_f_ll, v2_rr - c_f_rr)813λ_max = max(v2_ll + c_f_ll, v2_rr + c_f_rr)814else # z-direction815c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)816c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)817818λ_min = min(v3_ll - c_f_ll, v3_rr - c_f_rr)819λ_max = max(v3_ll + c_f_ll, v3_rr + c_f_rr)820end821822return λ_min, λ_max823end824825# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes826@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector,827equations::IdealGlmMhdEquations3D)828rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll829rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr830831# Calculate primitive velocity variables832v1_ll = rho_v1_ll / rho_ll833v2_ll = rho_v2_ll / rho_ll834v3_ll = rho_v3_ll / rho_ll835836v1_rr = rho_v1_rr / rho_rr837v2_rr = rho_v2_rr / rho_rr838v3_rr = rho_v3_rr / rho_rr839840v_normal_ll = (v1_ll * normal_direction[1] +841v2_ll * normal_direction[2] +842v3_ll * normal_direction[3])843v_normal_rr = (v1_rr * normal_direction[1] +844v2_rr * normal_direction[2] +845v3_rr * normal_direction[3])846847c_f_ll = calc_fast_wavespeed(u_ll, normal_direction, equations)848c_f_rr = calc_fast_wavespeed(u_rr, normal_direction, equations)849850# Estimate the min/max eigenvalues in the normal direction851λ_min = min(v_normal_ll - c_f_ll, v_normal_rr - c_f_rr)852λ_max = max(v_normal_ll + c_f_ll, v_normal_rr + c_f_rr)853854return λ_min, λ_max855end856857"""858min_max_speed_einfeldt(u_ll, u_rr, orientation_or_normal_direction, equations::IdealGlmMhdEquations3D)859860Calculate minimum and maximum wave speeds for HLL-type fluxes as in861- Li (2005)862An HLLC Riemann solver for magneto-hydrodynamics863[DOI: 10.1016/j.jcp.2004.08.020](https://doi.org/10.1016/j.jcp.2004.08.020)864"""865@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer,866equations::IdealGlmMhdEquations3D)867rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll868rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr869870# Calculate primitive variables and speed of sound871v1_ll = rho_v1_ll / rho_ll872v2_ll = rho_v2_ll / rho_ll873v3_ll = rho_v3_ll / rho_ll874875v1_rr = rho_v1_rr / rho_rr876v2_rr = rho_v2_rr / rho_rr877v3_rr = rho_v3_rr / rho_rr878879# Approximate the left-most and right-most eigenvalues in the Riemann fan880if orientation == 1 # x-direction881c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)882c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)883vel_roe, c_f_roe = calc_fast_wavespeed_roe(u_ll, u_rr, orientation, equations)884λ_min = min(v1_ll - c_f_ll, vel_roe - c_f_roe)885λ_max = max(v1_rr + c_f_rr, vel_roe + c_f_roe)886elseif orientation == 2 # y-direction887c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)888c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)889vel_roe, c_f_roe = calc_fast_wavespeed_roe(u_ll, u_rr, orientation, equations)890λ_min = min(v2_ll - c_f_ll, vel_roe - c_f_roe)891λ_max = max(v2_rr + c_f_rr, vel_roe + c_f_roe)892else # z-direction893c_f_ll = calc_fast_wavespeed(u_ll, orientation, equations)894c_f_rr = calc_fast_wavespeed(u_rr, orientation, equations)895vel_roe, c_f_roe = calc_fast_wavespeed_roe(u_ll, u_rr, orientation, equations)896λ_min = min(v3_ll - c_f_ll, vel_roe - c_f_roe)897λ_max = max(v3_rr + c_f_rr, vel_roe + c_f_roe)898end899900return λ_min, λ_max901end902903@inline function min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector,904equations::IdealGlmMhdEquations3D)905rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, _ = u_ll906rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, _ = u_rr907908# Calculate primitive velocity variables909v1_ll = rho_v1_ll / rho_ll910v2_ll = rho_v2_ll / rho_ll911v3_ll = rho_v3_ll / rho_ll912913v1_rr = rho_v1_rr / rho_rr914v2_rr = rho_v2_rr / rho_rr915v3_rr = rho_v3_rr / rho_rr916917v_normal_ll = (v1_ll * normal_direction[1] +918v2_ll * normal_direction[2] +919v3_ll * normal_direction[3])920v_normal_rr = (v1_rr * normal_direction[1] +921v2_rr * normal_direction[2] +922v3_rr * normal_direction[3])923924c_f_ll = calc_fast_wavespeed(u_ll, normal_direction, equations)925c_f_rr = calc_fast_wavespeed(u_rr, normal_direction, equations)926v_roe, c_f_roe = calc_fast_wavespeed_roe(u_ll, u_rr, normal_direction, equations)927928# Estimate the min/max eigenvalues in the normal direction929λ_min = min(v_normal_ll - c_f_ll, v_roe - c_f_roe)930λ_max = max(v_normal_rr + c_f_rr, v_roe + c_f_roe)931932return λ_min, λ_max933end934935# Rotate normal vector to x-axis; normal, tangent1 and tangent2 need to be orthonormal936# Called inside `FluxRotated` in `numerical_fluxes.jl` so the directions937# has been normalized prior to this rotation of the state vector938# Note, for ideal GLM-MHD only the velocities and magnetic field variables rotate939@inline function rotate_to_x(u, normal_vector, tangent1, tangent2,940equations::IdealGlmMhdEquations3D)941# Multiply with [ 1 0 0 0 0 0 0 0 0;942# 0 ― normal_vector ― 0 0 0 0 0;943# 0 ― tangent1 ― 0 0 0 0 0;944# 0 ― tangent2 ― 0 0 0 0 0;945# 0 0 0 0 1 0 0 0 0;946# 0 0 0 0 0 ― normal_vector ― 0;947# 0 0 0 0 0 ― tangent1 ― 0;948# 0 0 0 0 0 ― tangent2 ― 0;949# 0 0 0 0 0 0 0 0 1 ]950return SVector(u[1],951normal_vector[1] * u[2] + normal_vector[2] * u[3] +952normal_vector[3] * u[4],953tangent1[1] * u[2] + tangent1[2] * u[3] + tangent1[3] * u[4],954tangent2[1] * u[2] + tangent2[2] * u[3] + tangent2[3] * u[4],955u[5],956normal_vector[1] * u[6] + normal_vector[2] * u[7] +957normal_vector[3] * u[8],958tangent1[1] * u[6] + tangent1[2] * u[7] + tangent1[3] * u[8],959tangent2[1] * u[6] + tangent2[2] * u[7] + tangent2[3] * u[8],960u[9])961end962963# Rotate x-axis to normal vector; normal, tangent1 and tangent2 need to be orthonormal964# Called inside `FluxRotated` in `numerical_fluxes.jl` so the directions965# has been normalized prior to this back-rotation of the state vector966# Note, for ideal GLM-MHD only the velocities and magnetic field variables back-rotate967@inline function rotate_from_x(u, normal_vector, tangent1, tangent2,968equations::IdealGlmMhdEquations3D)969# Multiply with [ 1 0 0 0 0 0 0 0 0;970# 0 | | | 0 0 0 0 0;971# 0 normal_vector tangent1 tangent2 0 0 0 0 0;972# 0 | | | 0 0 0 0 0;973# 0 0 0 0 1 0 0 0 0;974# 0 0 0 0 0 | | | 0;975# 0 0 0 0 0 normal_vector tangent1 tangent2 0;976# 0 0 0 0 0 | | | 0;977# 0 0 0 0 0 0 0 0 1 ]978return SVector(u[1],979normal_vector[1] * u[2] + tangent1[1] * u[3] + tangent2[1] * u[4],980normal_vector[2] * u[2] + tangent1[2] * u[3] + tangent2[2] * u[4],981normal_vector[3] * u[2] + tangent1[3] * u[3] + tangent2[3] * u[4],982u[5],983normal_vector[1] * u[6] + tangent1[1] * u[7] + tangent2[1] * u[8],984normal_vector[2] * u[6] + tangent1[2] * u[7] + tangent2[2] * u[8],985normal_vector[3] * u[6] + tangent1[3] * u[7] + tangent2[3] * u[8],986u[9])987end988989@inline function max_abs_speeds(u, equations::IdealGlmMhdEquations3D)990rho, rho_v1, rho_v2, rho_v3, _ = u991v1 = rho_v1 / rho992v2 = rho_v2 / rho993v3 = rho_v3 / rho994cf_x_direction = calc_fast_wavespeed(u, 1, equations)995cf_y_direction = calc_fast_wavespeed(u, 2, equations)996cf_z_direction = calc_fast_wavespeed(u, 3, equations)997998return abs(v1) + cf_x_direction, abs(v2) + cf_y_direction, abs(v3) + cf_z_direction999end10001001# Convert conservative variables to primitive1002@inline function cons2prim(u, equations::IdealGlmMhdEquations3D)1003rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u10041005v1 = rho_v1 / rho1006v2 = rho_v2 / rho1007v3 = rho_v3 / rho1008p = (equations.gamma - 1) * (rho_e -10090.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v31010+ B1 * B1 + B2 * B2 + B3 * B31011+ psi * psi))10121013return SVector(rho, v1, v2, v3, p, B1, B2, B3, psi)1014end10151016# Convert conservative variables to entropy1017@inline function cons2entropy(u, equations::IdealGlmMhdEquations3D)1018rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u1019v1 = rho_v1 / rho1020v2 = rho_v2 / rho1021v3 = rho_v3 / rho1022v_square = v1^2 + v2^2 + v3^21023p = (equations.gamma - 1) *1024(rho_e - 0.5f0 * rho * v_square - 0.5f0 * (B1^2 + B2^2 + B3^2) - 0.5f0 * psi^2)1025s = log(p) - equations.gamma * log(rho)1026rho_p = rho / p10271028w1 = (equations.gamma - s) * equations.inv_gamma_minus_one -10290.5f0 * rho_p * v_square1030w2 = rho_p * v11031w3 = rho_p * v21032w4 = rho_p * v31033w5 = -rho_p1034w6 = rho_p * B11035w7 = rho_p * B21036w8 = rho_p * B31037w9 = rho_p * psi10381039return SVector(w1, w2, w3, w4, w5, w6, w7, w8, w9)1040end10411042# Convert primitive to conservative variables1043@inline function prim2cons(prim, equations::IdealGlmMhdEquations3D)1044rho, v1, v2, v3, p, B1, B2, B3, psi = prim10451046rho_v1 = rho * v11047rho_v2 = rho * v21048rho_v3 = rho * v31049rho_e = p * equations.inv_gamma_minus_one +10500.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3) +10510.5f0 * (B1^2 + B2^2 + B3^2) + 0.5f0 * psi^210521053return SVector(rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi)1054end10551056@inline function density(u, equations::IdealGlmMhdEquations3D)1057return u[1]1058end10591060@inline function velocity(u, equations::IdealGlmMhdEquations3D)1061rho = u[1]1062v1 = u[2] / rho1063v2 = u[3] / rho1064v3 = u[4] / rho1065return SVector(v1, v2, v3)1066end10671068@inline function velocity(u, orientation::Int, equations::IdealGlmMhdEquations3D)1069rho = u[1]1070v = u[orientation + 1] / rho1071return v1072end10731074@inline function pressure(u, equations::IdealGlmMhdEquations3D)1075rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u1076p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2 + rho_v3^2) / rho1077-10780.5f0 * (B1^2 + B2^2 + B3^2)1079-10800.5f0 * psi^2)1081return p1082end10831084@inline function density_pressure(u, equations::IdealGlmMhdEquations3D)1085rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = u1086p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2 + rho_v3^2) / rho1087-10880.5f0 * (B1^2 + B2^2 + B3^2)1089-10900.5f0 * psi^2)1091return rho * p1092end10931094# Compute the fastest wave speed for ideal MHD equations: c_f, the fast magnetoacoustic eigenvalue1095@inline function calc_fast_wavespeed(cons, orientation::Integer,1096equations::IdealGlmMhdEquations3D)1097rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = cons1098v1 = rho_v1 / rho1099v2 = rho_v2 / rho1100v3 = rho_v3 / rho1101kin_en = 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3)1102mag_en = 0.5f0 * (B1 * B1 + B2 * B2 + B3 * B3)1103p = (equations.gamma - 1) * (rho_e - kin_en - mag_en - 0.5f0 * psi^2)1104a_square = equations.gamma * p / rho1105sqrt_rho = sqrt(rho)1106b1 = B1 / sqrt_rho1107b2 = B2 / sqrt_rho1108b3 = B3 / sqrt_rho1109b_square = b1 * b1 + b2 * b2 + b3 * b31110if orientation == 1 # x-direction1111c_f = sqrt(0.5f0 * (a_square + b_square) +11120.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b1^2))1113elseif orientation == 2 # y-direction1114c_f = sqrt(0.5f0 * (a_square + b_square) +11150.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b2^2))1116else # z-direction1117c_f = sqrt(0.5f0 * (a_square + b_square) +11180.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b3^2))1119end1120return c_f1121end11221123@inline function calc_fast_wavespeed(cons, normal_direction::AbstractVector,1124equations::IdealGlmMhdEquations3D)1125rho, rho_v1, rho_v2, rho_v3, rho_e, B1, B2, B3, psi = cons1126v1 = rho_v1 / rho1127v2 = rho_v2 / rho1128v3 = rho_v3 / rho1129kin_en = 0.5f0 * (rho_v1 * v1 + rho_v2 * v2 + rho_v3 * v3)1130mag_en = 0.5f0 * (B1 * B1 + B2 * B2 + B3 * B3)1131p = (equations.gamma - 1) * (rho_e - kin_en - mag_en - 0.5f0 * psi^2)1132a_square = equations.gamma * p / rho1133sqrt_rho = sqrt(rho)1134b1 = B1 / sqrt_rho1135b2 = B2 / sqrt_rho1136b3 = B3 / sqrt_rho1137b_square = b1 * b1 + b2 * b2 + b3 * b31138norm_squared = (normal_direction[1] * normal_direction[1] +1139normal_direction[2] * normal_direction[2] +1140normal_direction[3] * normal_direction[3])1141b_dot_n_squared = (b1 * normal_direction[1] +1142b2 * normal_direction[2] +1143b3 * normal_direction[3])^2 / norm_squared11441145c_f = sqrt((0.5f0 * (a_square + b_square) +11460.5f0 * sqrt((a_square + b_square)^2 - 4 * a_square * b_dot_n_squared)) *1147norm_squared)1148return c_f1149end11501151"""1152calc_fast_wavespeed_roe(u_ll, u_rr, orientation_or_normal_direction, equations::IdealGlmMhdEquations3D)11531154Compute the fast magnetoacoustic wave speed using Roe averages as given by1155- Cargo and Gallice (1997)1156Roe Matrices for Ideal MHD and Systematic Construction1157of Roe Matrices for Systems of Conservation Laws1158[DOI: 10.1006/jcph.1997.5773](https://doi.org/10.1006/jcph.1997.5773)1159"""1160@inline function calc_fast_wavespeed_roe(u_ll, u_rr, orientation::Integer,1161equations::IdealGlmMhdEquations3D)1162rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll1163rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr11641165# Calculate primitive variables1166v1_ll = rho_v1_ll / rho_ll1167v2_ll = rho_v2_ll / rho_ll1168v3_ll = rho_v3_ll / rho_ll1169kin_en_ll = 0.5f0 * (rho_v1_ll * v1_ll + rho_v2_ll * v2_ll + rho_v3_ll * v3_ll)1170mag_norm_ll = B1_ll * B1_ll + B2_ll * B2_ll + B3_ll * B3_ll1171p_ll = (equations.gamma - 1) *1172(rho_e_ll - kin_en_ll - 0.5f0 * mag_norm_ll - 0.5f0 * psi_ll^2)11731174v1_rr = rho_v1_rr / rho_rr1175v2_rr = rho_v2_rr / rho_rr1176v3_rr = rho_v3_rr / rho_rr1177kin_en_rr = 0.5f0 * (rho_v1_rr * v1_rr + rho_v2_rr * v2_rr + rho_v3_rr * v3_rr)1178mag_norm_rr = B1_rr * B1_rr + B2_rr * B2_rr + B3_rr * B3_rr1179p_rr = (equations.gamma - 1) *1180(rho_e_rr - kin_en_rr - 0.5f0 * mag_norm_rr - 0.5f0 * psi_rr^2)11811182# compute total pressure which is thermal + magnetic pressures1183p_total_ll = p_ll + 0.5f0 * mag_norm_ll1184p_total_rr = p_rr + 0.5f0 * mag_norm_rr11851186# compute the Roe density averages1187sqrt_rho_ll = sqrt(rho_ll)1188sqrt_rho_rr = sqrt(rho_rr)1189inv_sqrt_rho_add = 1 / (sqrt_rho_ll + sqrt_rho_rr)1190inv_sqrt_rho_prod = 1 / (sqrt_rho_ll * sqrt_rho_rr)1191rho_ll_roe = sqrt_rho_ll * inv_sqrt_rho_add1192rho_rr_roe = sqrt_rho_rr * inv_sqrt_rho_add1193# Roe averages1194# velocities and magnetic fields1195v1_roe = v1_ll * rho_ll_roe + v1_rr * rho_rr_roe1196v2_roe = v2_ll * rho_ll_roe + v2_rr * rho_rr_roe1197v3_roe = v3_ll * rho_ll_roe + v3_rr * rho_rr_roe1198B1_roe = B1_ll * rho_ll_roe + B1_rr * rho_rr_roe1199B2_roe = B2_ll * rho_ll_roe + B2_rr * rho_rr_roe1200B3_roe = B3_ll * rho_ll_roe + B3_rr * rho_rr_roe1201# enthalpy1202H_ll = (rho_e_ll + p_total_ll) / rho_ll1203H_rr = (rho_e_rr + p_total_rr) / rho_rr1204H_roe = H_ll * rho_ll_roe + H_rr * rho_rr_roe1205# temporary variable see equation (4.12) in Cargo and Gallice1206X = 0.5f0 * ((B1_ll - B1_rr)^2 + (B2_ll - B2_rr)^2 + (B3_ll - B3_rr)^2) *1207inv_sqrt_rho_add^21208# averaged components needed to compute c_f, the fast magnetoacoustic wave speed1209b_square_roe = (B1_roe^2 + B2_roe^2 + B3_roe^2) * inv_sqrt_rho_prod # scaled magnectic sum1210a_square_roe = ((2 - equations.gamma) * X +1211(equations.gamma - 1) *1212(H_roe - 0.5f0 * (v1_roe^2 + v2_roe^2 + v3_roe^2) -1213b_square_roe)) # acoustic speed1214# finally compute the average wave speed and set the output velocity (depends on orientation)1215if orientation == 1 # x-direction1216c_a_roe = B1_roe^2 * inv_sqrt_rho_prod # (squared) Alfvén wave speed1217a_star_roe = sqrt((a_square_roe + b_square_roe)^2 -12184 * a_square_roe * c_a_roe)1219c_f_roe = sqrt(0.5f0 * (a_square_roe + b_square_roe + a_star_roe))1220vel_out_roe = v1_roe1221elseif orientation == 2 # y-direction1222c_a_roe = B2_roe^2 * inv_sqrt_rho_prod # (squared) Alfvén wave speed1223a_star_roe = sqrt((a_square_roe + b_square_roe)^2 -12244 * a_square_roe * c_a_roe)1225c_f_roe = sqrt(0.5f0 * (a_square_roe + b_square_roe + a_star_roe))1226vel_out_roe = v2_roe1227else # z-direction1228c_a_roe = B3_roe^2 * inv_sqrt_rho_prod # (squared) Alfvén wave speed1229a_star_roe = sqrt((a_square_roe + b_square_roe)^2 -12304 * a_square_roe * c_a_roe)1231c_f_roe = sqrt(0.5f0 * (a_square_roe + b_square_roe + a_star_roe))1232vel_out_roe = v3_roe1233end12341235return vel_out_roe, c_f_roe1236end12371238@inline function calc_fast_wavespeed_roe(u_ll, u_rr, normal_direction::AbstractVector,1239equations::IdealGlmMhdEquations3D)1240rho_ll, rho_v1_ll, rho_v2_ll, rho_v3_ll, rho_e_ll, B1_ll, B2_ll, B3_ll, psi_ll = u_ll1241rho_rr, rho_v1_rr, rho_v2_rr, rho_v3_rr, rho_e_rr, B1_rr, B2_rr, B3_rr, psi_rr = u_rr12421243# Calculate primitive variables1244v1_ll = rho_v1_ll / rho_ll1245v2_ll = rho_v2_ll / rho_ll1246v3_ll = rho_v3_ll / rho_ll1247kin_en_ll = 0.5f0 * (rho_v1_ll * v1_ll + rho_v2_ll * v2_ll + rho_v3_ll * v3_ll)1248mag_norm_ll = B1_ll * B1_ll + B2_ll * B2_ll + B3_ll * B3_ll1249p_ll = (equations.gamma - 1) *1250(rho_e_ll - kin_en_ll - 0.5f0 * mag_norm_ll - 0.5f0 * psi_ll^2)12511252v1_rr = rho_v1_rr / rho_rr1253v2_rr = rho_v2_rr / rho_rr1254v3_rr = rho_v3_rr / rho_rr1255kin_en_rr = 0.5f0 * (rho_v1_rr * v1_rr + rho_v2_rr * v2_rr + rho_v3_rr * v3_rr)1256mag_norm_rr = B1_rr * B1_rr + B2_rr * B2_rr + B3_rr * B3_rr1257p_rr = (equations.gamma - 1) *1258(rho_e_rr - kin_en_rr - 0.5f0 * mag_norm_rr - 0.5f0 * psi_rr^2)12591260# compute total pressure which is thermal + magnetic pressures1261p_total_ll = p_ll + 0.5f0 * mag_norm_ll1262p_total_rr = p_rr + 0.5f0 * mag_norm_rr12631264# compute the Roe density averages1265sqrt_rho_ll = sqrt(rho_ll)1266sqrt_rho_rr = sqrt(rho_rr)1267inv_sqrt_rho_add = 1 / (sqrt_rho_ll + sqrt_rho_rr)1268inv_sqrt_rho_prod = 1 / (sqrt_rho_ll * sqrt_rho_rr)1269rho_ll_roe = sqrt_rho_ll * inv_sqrt_rho_add1270rho_rr_roe = sqrt_rho_rr * inv_sqrt_rho_add1271# Roe averages1272# velocities and magnetic fields1273v1_roe = v1_ll * rho_ll_roe + v1_rr * rho_rr_roe1274v2_roe = v2_ll * rho_ll_roe + v2_rr * rho_rr_roe1275v3_roe = v3_ll * rho_ll_roe + v3_rr * rho_rr_roe1276B1_roe = B1_ll * rho_ll_roe + B1_rr * rho_rr_roe1277B2_roe = B2_ll * rho_ll_roe + B2_rr * rho_rr_roe1278B3_roe = B3_ll * rho_ll_roe + B3_rr * rho_rr_roe1279# enthalpy1280H_ll = (rho_e_ll + p_total_ll) / rho_ll1281H_rr = (rho_e_rr + p_total_rr) / rho_rr1282H_roe = H_ll * rho_ll_roe + H_rr * rho_rr_roe1283# temporary variable see equation (4.12) in Cargo and Gallice1284X = 0.5f0 * ((B1_ll - B1_rr)^2 + (B2_ll - B2_rr)^2 + (B3_ll - B3_rr)^2) *1285inv_sqrt_rho_add^21286# averaged components needed to compute c_f, the fast magnetoacoustic wave speed1287b_square_roe = (B1_roe^2 + B2_roe^2 + B3_roe^2) * inv_sqrt_rho_prod # scaled magnectic sum1288a_square_roe = ((2 - equations.gamma) * X +1289(equations.gamma - 1) *1290(H_roe - 0.5f0 * (v1_roe^2 + v2_roe^2 + v3_roe^2) -1291b_square_roe)) # acoustic speed12921293# finally compute the average wave speed and set the output velocity (depends on orientation)1294norm_squared = (normal_direction[1] * normal_direction[1] +1295normal_direction[2] * normal_direction[2] +1296normal_direction[3] * normal_direction[3])1297B_roe_dot_n_squared = (B1_roe * normal_direction[1] +1298B2_roe * normal_direction[2] +1299B3_roe * normal_direction[3])^2 / norm_squared13001301c_a_roe = B_roe_dot_n_squared * inv_sqrt_rho_prod # (squared) Alfvén wave speed1302a_star_roe = sqrt((a_square_roe + b_square_roe)^2 - 4 * a_square_roe * c_a_roe)1303c_f_roe = sqrt(0.5f0 * (a_square_roe + b_square_roe + a_star_roe) * norm_squared)1304vel_out_roe = (v1_roe * normal_direction[1] +1305v2_roe * normal_direction[2] +1306v3_roe * normal_direction[3])13071308return vel_out_roe, c_f_roe1309end13101311# Calculate thermodynamic entropy for a conservative state `cons`1312@inline function entropy_thermodynamic(cons, equations::IdealGlmMhdEquations3D)1313# Pressure1314p = (equations.gamma - 1) *1315(cons[5] - 0.5f0 * (cons[2]^2 + cons[3]^2 + cons[4]^2) / cons[1]1316-13170.5f0 * (cons[6]^2 + cons[7]^2 + cons[8]^2)1318-13190.5f0 * cons[9]^2)13201321# Thermodynamic entropy1322s = log(p) - equations.gamma * log(cons[1])13231324return s1325end13261327# Calculate mathematical entropy for a conservative state `cons`1328@inline function entropy_math(cons, equations::IdealGlmMhdEquations3D)1329S = -entropy_thermodynamic(cons, equations) * cons[1] *1330equations.inv_gamma_minus_one13311332return S1333end13341335# Default entropy is the mathematical entropy1336@inline entropy(cons, equations::IdealGlmMhdEquations3D) = entropy_math(cons, equations)13371338# Calculate total energy for a conservative state `cons`1339@inline energy_total(cons, ::IdealGlmMhdEquations3D) = cons[5]13401341# Calculate kinetic energy for a conservative state `cons`1342@inline function energy_kinetic(cons, equations::IdealGlmMhdEquations3D)1343return 0.5f0 * (cons[2]^2 + cons[3]^2 + cons[4]^2) / cons[1]1344end13451346# Calculate the magnetic energy for a conservative state `cons'.1347# OBS! For non-dinmensional form of the ideal MHD magnetic pressure ≡ magnetic energy1348@inline function energy_magnetic(cons, ::IdealGlmMhdEquations3D)1349return 0.5f0 * (cons[6]^2 + cons[7]^2 + cons[8]^2)1350end13511352# Calculate internal energy for a conservative state `cons`1353@inline function energy_internal(cons, equations::IdealGlmMhdEquations3D)1354return (energy_total(cons, equations)1355-1356energy_kinetic(cons, equations)1357-1358energy_magnetic(cons, equations)1359-1360cons[9]^2 / 2)1361end13621363# Calculate the cross helicity (\vec{v}⋅\vec{B}) for a conservative state `cons'1364@inline function cross_helicity(cons, ::IdealGlmMhdEquations3D)1365return (cons[2] * cons[6] + cons[3] * cons[7] + cons[4] * cons[8]) / cons[1]1366end1367end # @muladd136813691370