Path: blob/main/src/equations/compressible_euler_2d.jl
2055 views
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).1# Since these FMAs can increase the performance of many numerical algorithms,2# we need to opt-in explicitly.3# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.4@muladd begin5#! format: noindent67@doc raw"""8CompressibleEulerEquations2D(gamma)910The compressible Euler equations11```math12\frac{\partial}{\partial t}13\begin{pmatrix}14\rho \\ \rho v_1 \\ \rho v_2 \\ \rho e15\end{pmatrix}16+17\frac{\partial}{\partial x}18\begin{pmatrix}19\rho v_1 \\ \rho v_1^2 + p \\ \rho v_1 v_2 \\ (\rho e +p) v_120\end{pmatrix}21+22\frac{\partial}{\partial y}23\begin{pmatrix}24\rho v_2 \\ \rho v_1 v_2 \\ \rho v_2^2 + p \\ (\rho e +p) v_225\end{pmatrix}26=27\begin{pmatrix}280 \\ 0 \\ 0 \\ 029\end{pmatrix}30```31for an ideal gas with ratio of specific heats `gamma`32in two space dimensions.33Here, ``\rho`` is the density, ``v_1``, ``v_2`` the velocities, ``e`` the specific total energy **rather than** specific internal energy, and34```math35p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2+v_2^2) \right)36```37the pressure.38"""39struct CompressibleEulerEquations2D{RealT <: Real} <:40AbstractCompressibleEulerEquations{2, 4}41gamma::RealT # ratio of specific heats42inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications4344function CompressibleEulerEquations2D(gamma)45γ, inv_gamma_minus_one = promote(gamma, inv(gamma - 1))46new{typeof(γ)}(γ, inv_gamma_minus_one)47end48end4950function varnames(::typeof(cons2cons), ::CompressibleEulerEquations2D)51("rho", "rho_v1", "rho_v2", "rho_e")52end53varnames(::typeof(cons2prim), ::CompressibleEulerEquations2D) = ("rho", "v1", "v2", "p")5455# Set initial conditions at physical location `x` for time `t`56"""57initial_condition_constant(x, t, equations::CompressibleEulerEquations2D)5859A constant initial condition to test free-stream preservation.60"""61function initial_condition_constant(x, t, equations::CompressibleEulerEquations2D)62RealT = eltype(x)63rho = 164rho_v1 = convert(RealT, 0.1)65rho_v2 = convert(RealT, -0.2)66rho_e = 1067return SVector(rho, rho_v1, rho_v2, rho_e)68end6970"""71initial_condition_convergence_test(x, t, equations::CompressibleEulerEquations2D)7273A smooth initial condition used for convergence tests in combination with74[`source_terms_convergence_test`](@ref)75(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains).76"""77function initial_condition_convergence_test(x, t,78equations::CompressibleEulerEquations2D)79RealT = eltype(x)80c = 281A = convert(RealT, 0.1)82L = 283f = 1.0f0 / L84ω = 2 * convert(RealT, pi) * f85ini = c + A * sin(ω * (x[1] + x[2] - t))8687rho = ini88rho_v1 = ini89rho_v2 = ini90rho_e = ini^29192return SVector(rho, rho_v1, rho_v2, rho_e)93end9495"""96source_terms_convergence_test(u, x, t, equations::CompressibleEulerEquations2D)9798Source terms used for convergence tests in combination with99[`initial_condition_convergence_test`](@ref)100(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains).101"""102@inline function source_terms_convergence_test(u, x, t,103equations::CompressibleEulerEquations2D)104# Same settings as in `initial_condition`105RealT = eltype(u)106c = 2107A = convert(RealT, 0.1)108L = 2109f = 1.0f0 / L110ω = 2 * convert(RealT, pi) * f111γ = equations.gamma112113x1, x2 = x114si, co = sincos(ω * (x1 + x2 - t))115rho = c + A * si116rho_x = ω * A * co117# Note that d/dt rho = -d/dx rho = -d/dy rho.118119tmp = (2 * rho - 1) * (γ - 1)120121du1 = rho_x122du2 = rho_x * (1 + tmp)123du3 = du2124du4 = 2 * rho_x * (rho + tmp)125126return SVector(du1, du2, du3, du4)127end128129"""130initial_condition_density_wave(x, t, equations::CompressibleEulerEquations2D)131132A sine wave in the density with constant velocity and pressure; reduces the133compressible Euler equations to the linear advection equations.134This setup is the test case for stability of EC fluxes from paper135- Gregor J. Gassner, Magnus Svärd, Florian J. Hindenlang (2020)136Stability issues of entropy-stable and/or split-form high-order schemes137[arXiv: 2007.09026](https://arxiv.org/abs/2007.09026)138with the following parameters139- domain [-1, 1]140- mesh = 4x4141- polydeg = 5142"""143function initial_condition_density_wave(x, t, equations::CompressibleEulerEquations2D)144RealT = eltype(x)145v1 = convert(RealT, 0.1)146v2 = convert(RealT, 0.2)147rho = 1 + convert(RealT, 0.98) * sinpi(2 * (x[1] + x[2] - t * (v1 + v2)))148rho_v1 = rho * v1149rho_v2 = rho * v2150p = 20151rho_e = p / (equations.gamma - 1) + 0.5f0 * rho * (v1^2 + v2^2)152return SVector(rho, rho_v1, rho_v2, rho_e)153end154155"""156initial_condition_weak_blast_wave(x, t, equations::CompressibleEulerEquations2D)157158A weak blast wave taken from159- Sebastian Hennemann, Gregor J. Gassner (2020)160A provably entropy stable subcell shock capturing approach for high order split form DG161[arXiv: 2008.12044](https://arxiv.org/abs/2008.12044)162"""163function initial_condition_weak_blast_wave(x, t,164equations::CompressibleEulerEquations2D)165# From Hennemann & Gassner JCP paper 2020 (Sec. 6.3)166# Set up polar coordinates167inicenter = SVector(0, 0)168x_norm = x[1] - inicenter[1]169y_norm = x[2] - inicenter[2]170r = sqrt(x_norm^2 + y_norm^2)171phi = atan(y_norm, x_norm)172sin_phi, cos_phi = sincos(phi)173174# Calculate primitive variables175RealT = eltype(x)176rho = r > 0.5f0 ? one(RealT) : convert(RealT, 1.1691)177v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos_phi178v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin_phi179p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245)180181return prim2cons(SVector(rho, v1, v2, p), equations)182end183184"""185initial_condition_eoc_test_coupled_euler_gravity(x, t, equations::CompressibleEulerEquations2D)186187Setup used for convergence tests of the Euler equations with self-gravity used in188- Michael Schlottke-Lakemper, Andrew R. Winters, Hendrik Ranocha, Gregor J. Gassner (2020)189A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics190[arXiv: 2008.10593](https://arxiv.org/abs/2008.10593)191in combination with [`source_terms_eoc_test_coupled_euler_gravity`](@ref)192or [`source_terms_eoc_test_euler`](@ref).193"""194function initial_condition_eoc_test_coupled_euler_gravity(x, t,195equations::CompressibleEulerEquations2D)196# OBS! this assumes that γ = 2 other manufactured source terms are incorrect197if equations.gamma != 2198error("adiabatic constant must be 2 for the coupling convergence test")199end200RealT = eltype(x)201c = 2202A = convert(RealT, 0.1)203ini = c + A * sinpi(x[1] + x[2] - t)204G = 1 # gravitational constant205206rho = ini207v1 = 1208v2 = 1209p = ini^2 * G / convert(RealT, pi) # * 2 / ndims, but ndims==2 here210211return prim2cons(SVector(rho, v1, v2, p), equations)212end213214"""215source_terms_eoc_test_coupled_euler_gravity(u, x, t, equations::CompressibleEulerEquations2D)216217Setup used for convergence tests of the Euler equations with self-gravity used in218- Michael Schlottke-Lakemper, Andrew R. Winters, Hendrik Ranocha, Gregor J. Gassner (2020)219A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics220[arXiv: 2008.10593](https://arxiv.org/abs/2008.10593)221in combination with [`initial_condition_eoc_test_coupled_euler_gravity`](@ref).222"""223@inline function source_terms_eoc_test_coupled_euler_gravity(u, x, t,224equations::CompressibleEulerEquations2D)225# Same settings as in `initial_condition_eoc_test_coupled_euler_gravity`226RealT = eltype(u)227c = 2228A = convert(RealT, 0.1)229G = 1 # gravitational constant, must match coupling solver230C_grav = -2 * G / convert(RealT, pi) # 2 == 4 / ndims231232x1, x2 = x233si, co = sincospi(x1 + x2 - t)234rhox = A * convert(RealT, pi) * co235rho = c + A * si236237du1 = rhox238du2 = rhox239du3 = rhox240du4 = (1 - C_grav * rho) * rhox241242return SVector(du1, du2, du3, du4)243end244245"""246source_terms_eoc_test_euler(u, x, t, equations::CompressibleEulerEquations2D)247248Setup used for convergence tests of the Euler equations with self-gravity used in249- Michael Schlottke-Lakemper, Andrew R. Winters, Hendrik Ranocha, Gregor J. Gassner (2020)250A purely hyperbolic discontinuous Galerkin approach for self-gravitating gas dynamics251[arXiv: 2008.10593](https://arxiv.org/abs/2008.10593)252in combination with [`initial_condition_eoc_test_coupled_euler_gravity`](@ref).253"""254@inline function source_terms_eoc_test_euler(u, x, t,255equations::CompressibleEulerEquations2D)256# Same settings as in `initial_condition_eoc_test_coupled_euler_gravity`257RealT = eltype(u)258c = 2259A = convert(RealT, 0.1)260G = 1261C_grav = -2 * G / convert(RealT, pi) # 2 == 4 / ndims262263x1, x2 = x264si, co = sincospi(x1 + x2 - t)265rhox = A * convert(RealT, pi) * co266rho = c + A * si267268du1 = rhox269du2 = rhox * (1 - C_grav * rho)270du3 = rhox * (1 - C_grav * rho)271du4 = rhox * (1 - 3 * C_grav * rho)272273return SVector(du1, du2, du3, du4)274end275276"""277boundary_condition_slip_wall(u_inner, normal_direction, x, t, surface_flux_function,278equations::CompressibleEulerEquations2D)279280Determine the boundary numerical surface flux for a slip wall condition.281Imposes a zero normal velocity at the wall.282Density is taken from the internal solution state and pressure is computed as an283exact solution of a 1D Riemann problem. Further details about this boundary state284are available in the paper:285- J. J. W. van der Vegt and H. van der Ven (2002)286Slip flow boundary conditions in discontinuous Galerkin discretizations of287the Euler equations of gas dynamics288[PDF](https://reports.nlr.nl/bitstream/handle/10921/692/TP-2002-300.pdf?sequence=1)289290Details about the 1D pressure Riemann solution can be found in Section 6.3.3 of the book291- Eleuterio F. Toro (2009)292Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction2933rd edition294[DOI: 10.1007/b79761](https://doi.org/10.1007/b79761)295296Should be used together with [`UnstructuredMesh2D`](@ref), [`P4estMesh`](@ref), or [`T8codeMesh`](@ref).297"""298@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector,299x, t,300surface_flux_function,301equations::CompressibleEulerEquations2D)302norm_ = norm(normal_direction)303# Normalize the vector without using `normalize` since we need to multiply by the `norm_` later304normal = normal_direction / norm_305306# rotate the internal solution state307u_local = rotate_to_x(u_inner, normal, equations)308309# compute the primitive variables310rho_local, v_normal, v_tangent, p_local = cons2prim(u_local, equations)311312# Get the solution of the pressure Riemann problem313# See Section 6.3.3 of314# Eleuterio F. Toro (2009)315# Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction316# [DOI: 10.1007/b79761](https://doi.org/10.1007/b79761)317if v_normal <= 0318sound_speed = sqrt(equations.gamma * p_local / rho_local) # local sound speed319p_star = p_local *320(1 + 0.5f0 * (equations.gamma - 1) * v_normal / sound_speed)^(2 *321equations.gamma *322equations.inv_gamma_minus_one)323else # v_normal > 0324A = 2 / ((equations.gamma + 1) * rho_local)325B = p_local * (equations.gamma - 1) / (equations.gamma + 1)326p_star = p_local +3270.5f0 * v_normal / A *328(v_normal + sqrt(v_normal^2 + 4 * A * (p_local + B)))329end330331# For the slip wall we directly set the flux as the normal velocity is zero332return SVector(0,333p_star * normal[1],334p_star * normal[2],3350) * norm_336end337338"""339boundary_condition_slip_wall(u_inner, orientation, direction, x, t,340surface_flux_function, equations::CompressibleEulerEquations2D)341342Should be used together with [`TreeMesh`](@ref).343"""344@inline function boundary_condition_slip_wall(u_inner, orientation,345direction, x, t,346surface_flux_function,347equations::CompressibleEulerEquations2D)348# get the appropriate normal vector from the orientation349RealT = eltype(u_inner)350if orientation == 1351normal_direction = SVector(one(RealT), zero(RealT))352else # orientation == 2353normal_direction = SVector(zero(RealT), one(RealT))354end355356# compute and return the flux using `boundary_condition_slip_wall` routine below357return boundary_condition_slip_wall(u_inner, normal_direction, direction,358x, t, surface_flux_function, equations)359end360361"""362boundary_condition_slip_wall(u_inner, normal_direction, direction, x, t,363surface_flux_function, equations::CompressibleEulerEquations2D)364365Should be used together with [`StructuredMesh`](@ref).366"""367@inline function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector,368direction, x, t,369surface_flux_function,370equations::CompressibleEulerEquations2D)371# flip sign of normal to make it outward pointing, then flip the sign of the normal flux back372# to be inward pointing on the -x and -y sides due to the orientation convention used by StructuredMesh373if isodd(direction)374boundary_flux = -boundary_condition_slip_wall(u_inner, -normal_direction,375x, t, surface_flux_function,376equations)377else378boundary_flux = boundary_condition_slip_wall(u_inner, normal_direction,379x, t, surface_flux_function,380equations)381end382383return boundary_flux384end385386# Calculate 1D flux for a single point387@inline function flux(u, orientation::Integer, equations::CompressibleEulerEquations2D)388rho, rho_v1, rho_v2, rho_e = u389v1 = rho_v1 / rho390v2 = rho_v2 / rho391p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))392if orientation == 1393f1 = rho_v1394f2 = rho_v1 * v1 + p395f3 = rho_v1 * v2396f4 = (rho_e + p) * v1397else398f1 = rho_v2399f2 = rho_v2 * v1400f3 = rho_v2 * v2 + p401f4 = (rho_e + p) * v2402end403return SVector(f1, f2, f3, f4)404end405406# Calculate 1D flux for a single point in the normal direction407# Note, this directional vector is not normalized408@inline function flux(u, normal_direction::AbstractVector,409equations::CompressibleEulerEquations2D)410rho_e = last(u)411rho, v1, v2, p = cons2prim(u, equations)412413v_normal = v1 * normal_direction[1] + v2 * normal_direction[2]414rho_v_normal = rho * v_normal415f1 = rho_v_normal416f2 = rho_v_normal * v1 + p * normal_direction[1]417f3 = rho_v_normal * v2 + p * normal_direction[2]418f4 = (rho_e + p) * v_normal419return SVector(f1, f2, f3, f4)420end421422"""423flux_shima_etal(u_ll, u_rr, orientation_or_normal_direction,424equations::CompressibleEulerEquations2D)425426This flux is is a modification of the original kinetic energy preserving two-point flux by427- Yuichi Kuya, Kosuke Totani and Soshi Kawai (2018)428Kinetic energy and entropy preserving schemes for compressible flows429by split convective forms430[DOI: 10.1016/j.jcp.2018.08.058](https://doi.org/10.1016/j.jcp.2018.08.058)431432The modification is in the energy flux to guarantee pressure equilibrium and was developed by433- Nao Shima, Yuichi Kuya, Yoshiharu Tamaki, Soshi Kawai (JCP 2020)434Preventing spurious pressure oscillations in split convective form discretizations for435compressible flows436[DOI: 10.1016/j.jcp.2020.110060](https://doi.org/10.1016/j.jcp.2020.110060)437"""438@inline function flux_shima_etal(u_ll, u_rr, orientation::Integer,439equations::CompressibleEulerEquations2D)440# Unpack left and right state441rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)442rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)443444# Average each factor of products in flux445rho_avg = 0.5f0 * (rho_ll + rho_rr)446v1_avg = 0.5f0 * (v1_ll + v1_rr)447v2_avg = 0.5f0 * (v2_ll + v2_rr)448p_avg = 0.5f0 * (p_ll + p_rr)449kin_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr)450451# Calculate fluxes depending on orientation452if orientation == 1453pv1_avg = 0.5f0 * (p_ll * v1_rr + p_rr * v1_ll)454f1 = rho_avg * v1_avg455f2 = f1 * v1_avg + p_avg456f3 = f1 * v2_avg457f4 = p_avg * v1_avg * equations.inv_gamma_minus_one + f1 * kin_avg + pv1_avg458else459pv2_avg = 0.5f0 * (p_ll * v2_rr + p_rr * v2_ll)460f1 = rho_avg * v2_avg461f2 = f1 * v1_avg462f3 = f1 * v2_avg + p_avg463f4 = p_avg * v2_avg * equations.inv_gamma_minus_one + f1 * kin_avg + pv2_avg464end465466return SVector(f1, f2, f3, f4)467end468469@inline function flux_shima_etal(u_ll, u_rr, normal_direction::AbstractVector,470equations::CompressibleEulerEquations2D)471# Unpack left and right state472rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)473rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)474v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]475v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]476477# Average each factor of products in flux478rho_avg = 0.5f0 * (rho_ll + rho_rr)479v1_avg = 0.5f0 * (v1_ll + v1_rr)480v2_avg = 0.5f0 * (v2_ll + v2_rr)481v_dot_n_avg = 0.5f0 * (v_dot_n_ll + v_dot_n_rr)482p_avg = 0.5f0 * (p_ll + p_rr)483velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr)484485# Calculate fluxes depending on normal_direction486f1 = rho_avg * v_dot_n_avg487f2 = f1 * v1_avg + p_avg * normal_direction[1]488f3 = f1 * v2_avg + p_avg * normal_direction[2]489f4 = (f1 * velocity_square_avg +490p_avg * v_dot_n_avg * equations.inv_gamma_minus_one491+ 0.5f0 * (p_ll * v_dot_n_rr + p_rr * v_dot_n_ll))492493return SVector(f1, f2, f3, f4)494end495496"""497flux_kennedy_gruber(u_ll, u_rr, orientation_or_normal_direction,498equations::CompressibleEulerEquations2D)499500Kinetic energy preserving two-point flux by501- Kennedy and Gruber (2008)502Reduced aliasing formulations of the convective terms within the503Navier-Stokes equations for a compressible fluid504[DOI: 10.1016/j.jcp.2007.09.020](https://doi.org/10.1016/j.jcp.2007.09.020)505"""506@inline function flux_kennedy_gruber(u_ll, u_rr, orientation::Integer,507equations::CompressibleEulerEquations2D)508# Unpack left and right state509rho_e_ll = last(u_ll)510rho_e_rr = last(u_rr)511rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)512rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)513514# Average each factor of products in flux515rho_avg = 0.5f0 * (rho_ll + rho_rr)516v1_avg = 0.5f0 * (v1_ll + v1_rr)517v2_avg = 0.5f0 * (v2_ll + v2_rr)518p_avg = 0.5f0 * (p_ll + p_rr)519e_avg = 0.5f0 * (rho_e_ll / rho_ll + rho_e_rr / rho_rr)520521# Calculate fluxes depending on orientation522if orientation == 1523f1 = rho_avg * v1_avg524f2 = rho_avg * v1_avg * v1_avg + p_avg525f3 = rho_avg * v1_avg * v2_avg526f4 = (rho_avg * e_avg + p_avg) * v1_avg527else528f1 = rho_avg * v2_avg529f2 = rho_avg * v2_avg * v1_avg530f3 = rho_avg * v2_avg * v2_avg + p_avg531f4 = (rho_avg * e_avg + p_avg) * v2_avg532end533534return SVector(f1, f2, f3, f4)535end536537@inline function flux_kennedy_gruber(u_ll, u_rr, normal_direction::AbstractVector,538equations::CompressibleEulerEquations2D)539# Unpack left and right state540rho_e_ll = last(u_ll)541rho_e_rr = last(u_rr)542rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)543rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)544545# Average each factor of products in flux546rho_avg = 0.5f0 * (rho_ll + rho_rr)547v1_avg = 0.5f0 * (v1_ll + v1_rr)548v2_avg = 0.5f0 * (v2_ll + v2_rr)549v_dot_n_avg = v1_avg * normal_direction[1] + v2_avg * normal_direction[2]550p_avg = 0.5f0 * (p_ll + p_rr)551e_avg = 0.5f0 * (rho_e_ll / rho_ll + rho_e_rr / rho_rr)552553# Calculate fluxes depending on normal_direction554f1 = rho_avg * v_dot_n_avg555f2 = f1 * v1_avg + p_avg * normal_direction[1]556f3 = f1 * v2_avg + p_avg * normal_direction[2]557f4 = f1 * e_avg + p_avg * v_dot_n_avg558559return SVector(f1, f2, f3, f4)560end561562"""563flux_chandrashekar(u_ll, u_rr, orientation_or_normal_direction, equations::CompressibleEulerEquations2D)564565Entropy conserving two-point flux by566- Chandrashekar (2013)567Kinetic Energy Preserving and Entropy Stable Finite Volume Schemes568for Compressible Euler and Navier-Stokes Equations569[DOI: 10.4208/cicp.170712.010313a](https://doi.org/10.4208/cicp.170712.010313a)570"""571@inline function flux_chandrashekar(u_ll, u_rr, orientation::Integer,572equations::CompressibleEulerEquations2D)573# Unpack left and right state574rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)575rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)576beta_ll = 0.5f0 * rho_ll / p_ll577beta_rr = 0.5f0 * rho_rr / p_rr578specific_kin_ll = 0.5f0 * (v1_ll^2 + v2_ll^2)579specific_kin_rr = 0.5f0 * (v1_rr^2 + v2_rr^2)580581# Compute the necessary mean values582rho_avg = 0.5f0 * (rho_ll + rho_rr)583rho_mean = ln_mean(rho_ll, rho_rr)584beta_mean = ln_mean(beta_ll, beta_rr)585beta_avg = 0.5f0 * (beta_ll + beta_rr)586v1_avg = 0.5f0 * (v1_ll + v1_rr)587v2_avg = 0.5f0 * (v2_ll + v2_rr)588p_mean = 0.5f0 * rho_avg / beta_avg589velocity_square_avg = specific_kin_ll + specific_kin_rr590591# Calculate fluxes depending on orientation592if orientation == 1593f1 = rho_mean * v1_avg594f2 = f1 * v1_avg + p_mean595f3 = f1 * v2_avg596f4 = f1 * 0.5f0 *597(1 / (equations.gamma - 1) / beta_mean - velocity_square_avg) +598f2 * v1_avg + f3 * v2_avg599else600f1 = rho_mean * v2_avg601f2 = f1 * v1_avg602f3 = f1 * v2_avg + p_mean603f4 = f1 * 0.5f0 *604(1 / (equations.gamma - 1) / beta_mean - velocity_square_avg) +605f2 * v1_avg + f3 * v2_avg606end607608return SVector(f1, f2, f3, f4)609end610611@inline function flux_chandrashekar(u_ll, u_rr, normal_direction::AbstractVector,612equations::CompressibleEulerEquations2D)613# Unpack left and right state614rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)615rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)616v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]617v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]618beta_ll = 0.5f0 * rho_ll / p_ll619beta_rr = 0.5f0 * rho_rr / p_rr620specific_kin_ll = 0.5f0 * (v1_ll^2 + v2_ll^2)621specific_kin_rr = 0.5f0 * (v1_rr^2 + v2_rr^2)622623# Compute the necessary mean values624rho_avg = 0.5f0 * (rho_ll + rho_rr)625rho_mean = ln_mean(rho_ll, rho_rr)626beta_mean = ln_mean(beta_ll, beta_rr)627beta_avg = 0.5f0 * (beta_ll + beta_rr)628v1_avg = 0.5f0 * (v1_ll + v1_rr)629v2_avg = 0.5f0 * (v2_ll + v2_rr)630p_mean = 0.5f0 * rho_avg / beta_avg631velocity_square_avg = specific_kin_ll + specific_kin_rr632633# Multiply with average of normal velocities634f1 = rho_mean * 0.5f0 * (v_dot_n_ll + v_dot_n_rr)635f2 = f1 * v1_avg + p_mean * normal_direction[1]636f3 = f1 * v2_avg + p_mean * normal_direction[2]637f4 = f1 * 0.5f0 * (1 / (equations.gamma - 1) / beta_mean - velocity_square_avg) +638f2 * v1_avg + f3 * v2_avg639640return SVector(f1, f2, f3, f4)641end642643"""644flux_ranocha(u_ll, u_rr, orientation_or_normal_direction,645equations::CompressibleEulerEquations2D)646647Entropy conserving and kinetic energy preserving two-point flux by648- Hendrik Ranocha (2018)649Generalised Summation-by-Parts Operators and Entropy Stability of Numerical Methods650for Hyperbolic Balance Laws651[PhD thesis, TU Braunschweig](https://cuvillier.de/en/shop/publications/7743)652See also653- Hendrik Ranocha (2020)654Entropy Conserving and Kinetic Energy Preserving Numerical Methods for655the Euler Equations Using Summation-by-Parts Operators656[Proceedings of ICOSAHOM 2018](https://doi.org/10.1007/978-3-030-39647-3_42)657"""658@inline function flux_ranocha(u_ll, u_rr, orientation::Integer,659equations::CompressibleEulerEquations2D)660# Unpack left and right state661rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)662rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)663664# Compute the necessary mean values665rho_mean = ln_mean(rho_ll, rho_rr)666# Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)`667# in exact arithmetic since668# log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ)669# = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ)670inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)671v1_avg = 0.5f0 * (v1_ll + v1_rr)672v2_avg = 0.5f0 * (v2_ll + v2_rr)673p_avg = 0.5f0 * (p_ll + p_rr)674velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr)675676# Calculate fluxes depending on orientation677if orientation == 1678f1 = rho_mean * v1_avg679f2 = f1 * v1_avg + p_avg680f3 = f1 * v2_avg681f4 = f1 *682(velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one) +6830.5f0 * (p_ll * v1_rr + p_rr * v1_ll)684else685f1 = rho_mean * v2_avg686f2 = f1 * v1_avg687f3 = f1 * v2_avg + p_avg688f4 = f1 *689(velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one) +6900.5f0 * (p_ll * v2_rr + p_rr * v2_ll)691end692693return SVector(f1, f2, f3, f4)694end695696@inline function flux_ranocha(u_ll, u_rr, normal_direction::AbstractVector,697equations::CompressibleEulerEquations2D)698# Unpack left and right state699rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)700rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)701v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]702v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]703704# Compute the necessary mean values705rho_mean = ln_mean(rho_ll, rho_rr)706# Algebraically equivalent to `inv_ln_mean(rho_ll / p_ll, rho_rr / p_rr)`707# in exact arithmetic since708# log((ϱₗ/pₗ) / (ϱᵣ/pᵣ)) / (ϱₗ/pₗ - ϱᵣ/pᵣ)709# = pₗ pᵣ log((ϱₗ pᵣ) / (ϱᵣ pₗ)) / (ϱₗ pᵣ - ϱᵣ pₗ)710inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)711v1_avg = 0.5f0 * (v1_ll + v1_rr)712v2_avg = 0.5f0 * (v2_ll + v2_rr)713p_avg = 0.5f0 * (p_ll + p_rr)714velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr)715716# Calculate fluxes depending on normal_direction717f1 = rho_mean * 0.5f0 * (v_dot_n_ll + v_dot_n_rr)718f2 = f1 * v1_avg + p_avg * normal_direction[1]719f3 = f1 * v2_avg + p_avg * normal_direction[2]720f4 = (f1 * (velocity_square_avg + inv_rho_p_mean * equations.inv_gamma_minus_one)721+7220.5f0 * (p_ll * v_dot_n_rr + p_rr * v_dot_n_ll))723724return SVector(f1, f2, f3, f4)725end726727"""728splitting_steger_warming(u, orientation::Integer,729equations::CompressibleEulerEquations2D)730splitting_steger_warming(u, which::Union{Val{:minus}, Val{:plus}}731orientation::Integer,732equations::CompressibleEulerEquations2D)733734Splitting of the compressible Euler flux of Steger and Warming. For735curvilinear coordinates use the improved Steger-Warming-type splitting736[`splitting_drikakis_tsangaris`](@ref).737738Returns a tuple of the fluxes "minus" (associated with waves going into the739negative axis direction) and "plus" (associated with waves going into the740positive axis direction). If only one of the fluxes is required, use the741function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`.742743!!! warning "Experimental implementation (upwind SBP)"744This is an experimental feature and may change in future releases.745746## References747748- Joseph L. Steger and R. F. Warming (1979)749Flux Vector Splitting of the Inviscid Gasdynamic Equations750With Application to Finite Difference Methods751[NASA Technical Memorandum](https://ntrs.nasa.gov/api/citations/19790020779/downloads/19790020779.pdf)752"""753@inline function splitting_steger_warming(u, orientation::Integer,754equations::CompressibleEulerEquations2D)755fm = splitting_steger_warming(u, Val{:minus}(), orientation, equations)756fp = splitting_steger_warming(u, Val{:plus}(), orientation, equations)757return fm, fp758end759760@inline function splitting_steger_warming(u, ::Val{:plus}, orientation::Integer,761equations::CompressibleEulerEquations2D)762rho, rho_v1, rho_v2, rho_e = u763v1 = rho_v1 / rho764v2 = rho_v2 / rho765p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))766a = sqrt(equations.gamma * p / rho)767768if orientation == 1769lambda1 = v1770lambda2 = v1 + a771lambda3 = v1 - a772773lambda1_p = positive_part(lambda1) # Same as (lambda_i + abs(lambda_i)) / 2, but faster :)774lambda2_p = positive_part(lambda2)775lambda3_p = positive_part(lambda3)776777alpha_p = 2 * (equations.gamma - 1) * lambda1_p + lambda2_p + lambda3_p778779rho_2gamma = 0.5f0 * rho / equations.gamma780f1p = rho_2gamma * alpha_p781f2p = rho_2gamma * (alpha_p * v1 + a * (lambda2_p - lambda3_p))782f3p = rho_2gamma * alpha_p * v2783f4p = rho_2gamma *784(alpha_p * 0.5f0 * (v1^2 + v2^2) + a * v1 * (lambda2_p - lambda3_p)785+ a^2 * (lambda2_p + lambda3_p) * equations.inv_gamma_minus_one)786else # orientation == 2787lambda1 = v2788lambda2 = v2 + a789lambda3 = v2 - a790791lambda1_p = positive_part(lambda1) # Same as (lambda_i + abs(lambda_i)) / 2, but faster :)792lambda2_p = positive_part(lambda2)793lambda3_p = positive_part(lambda3)794795alpha_p = 2 * (equations.gamma - 1) * lambda1_p + lambda2_p + lambda3_p796797rho_2gamma = 0.5f0 * rho / equations.gamma798f1p = rho_2gamma * alpha_p799f2p = rho_2gamma * alpha_p * v1800f3p = rho_2gamma * (alpha_p * v2 + a * (lambda2_p - lambda3_p))801f4p = rho_2gamma *802(alpha_p * 0.5f0 * (v1^2 + v2^2) + a * v2 * (lambda2_p - lambda3_p)803+ a^2 * (lambda2_p + lambda3_p) * equations.inv_gamma_minus_one)804end805return SVector(f1p, f2p, f3p, f4p)806end807808@inline function splitting_steger_warming(u, ::Val{:minus}, orientation::Integer,809equations::CompressibleEulerEquations2D)810rho, rho_v1, rho_v2, rho_e = u811v1 = rho_v1 / rho812v2 = rho_v2 / rho813p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))814a = sqrt(equations.gamma * p / rho)815816if orientation == 1817lambda1 = v1818lambda2 = v1 + a819lambda3 = v1 - a820821lambda1_m = negative_part(lambda1) # Same as (lambda_i - abs(lambda_i)) / 2, but faster :)822lambda2_m = negative_part(lambda2)823lambda3_m = negative_part(lambda3)824825alpha_m = 2 * (equations.gamma - 1) * lambda1_m + lambda2_m + lambda3_m826827rho_2gamma = 0.5f0 * rho / equations.gamma828f1m = rho_2gamma * alpha_m829f2m = rho_2gamma * (alpha_m * v1 + a * (lambda2_m - lambda3_m))830f3m = rho_2gamma * alpha_m * v2831f4m = rho_2gamma *832(alpha_m * 0.5f0 * (v1^2 + v2^2) + a * v1 * (lambda2_m - lambda3_m)833+ a^2 * (lambda2_m + lambda3_m) * equations.inv_gamma_minus_one)834else # orientation == 2835lambda1 = v2836lambda2 = v2 + a837lambda3 = v2 - a838839lambda1_m = negative_part(lambda1) # Same as (lambda_i - abs(lambda_i)) / 2, but faster :)840lambda2_m = negative_part(lambda2)841lambda3_m = negative_part(lambda3)842843alpha_m = 2 * (equations.gamma - 1) * lambda1_m + lambda2_m + lambda3_m844845rho_2gamma = 0.5f0 * rho / equations.gamma846f1m = rho_2gamma * alpha_m847f2m = rho_2gamma * alpha_m * v1848f3m = rho_2gamma * (alpha_m * v2 + a * (lambda2_m - lambda3_m))849f4m = rho_2gamma *850(alpha_m * 0.5f0 * (v1^2 + v2^2) + a * v2 * (lambda2_m - lambda3_m)851+ a^2 * (lambda2_m + lambda3_m) * equations.inv_gamma_minus_one)852end853return SVector(f1m, f2m, f3m, f4m)854end855856"""857splitting_drikakis_tsangaris(u, orientation_or_normal_direction,858equations::CompressibleEulerEquations2D)859splitting_drikakis_tsangaris(u, which::Union{Val{:minus}, Val{:plus}}860orientation_or_normal_direction,861equations::CompressibleEulerEquations2D)862863Improved variant of the Steger-Warming flux vector splitting864[`splitting_steger_warming`](@ref) for generalized coordinates.865This splitting also reformulates the energy866flux as in Hänel et al. to obtain conservation of the total temperature867for inviscid flows.868869Returns a tuple of the fluxes "minus" (associated with waves going into the870negative axis direction) and "plus" (associated with waves going into the871positive axis direction). If only one of the fluxes is required, use the872function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`.873874!!! warning "Experimental implementation (upwind SBP)"875This is an experimental feature and may change in future releases.876877## References878879- D. Drikakis and S. Tsangaris (1993)880On the solution of the compressible Navier-Stokes equations using881improved flux vector splitting methods882[DOI: 10.1016/0307-904X(93)90054-K](https://doi.org/10.1016/0307-904X(93)90054-K)883- D. Hänel, R. Schwane and G. Seider (1987)884On the accuracy of upwind schemes for the solution of the Navier-Stokes equations885[DOI: 10.2514/6.1987-1105](https://doi.org/10.2514/6.1987-1105)886"""887@inline function splitting_drikakis_tsangaris(u, orientation_or_normal_direction,888equations::CompressibleEulerEquations2D)889fm = splitting_drikakis_tsangaris(u, Val{:minus}(), orientation_or_normal_direction,890equations)891fp = splitting_drikakis_tsangaris(u, Val{:plus}(), orientation_or_normal_direction,892equations)893return fm, fp894end895896@inline function splitting_drikakis_tsangaris(u, ::Val{:plus}, orientation::Integer,897equations::CompressibleEulerEquations2D)898rho, rho_v1, rho_v2, rho_e = u899v1 = rho_v1 / rho900v2 = rho_v2 / rho901p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))902a = sqrt(equations.gamma * p / rho)903H = (rho_e + p) / rho904905if orientation == 1906lambda1 = v1 + a907lambda2 = v1 - a908909lambda1_p = positive_part(lambda1) # Same as (lambda_i + abs(lambda_i)) / 2, but faster :)910lambda2_p = positive_part(lambda2)911912rhoa_2gamma = 0.5f0 * rho * a / equations.gamma913f1p = 0.5f0 * rho * (lambda1_p + lambda2_p)914f2p = f1p * v1 + rhoa_2gamma * (lambda1_p - lambda2_p)915f3p = f1p * v2916f4p = f1p * H917else # orientation == 2918lambda1 = v2 + a919lambda2 = v2 - a920921lambda1_p = positive_part(lambda1) # Same as (lambda_i + abs(lambda_i)) / 2, but faster :)922lambda2_p = positive_part(lambda2)923924rhoa_2gamma = 0.5f0 * rho * a / equations.gamma925f1p = 0.5f0 * rho * (lambda1_p + lambda2_p)926f2p = f1p * v1927f3p = f1p * v2 + rhoa_2gamma * (lambda1_p - lambda2_p)928f4p = f1p * H929end930return SVector(f1p, f2p, f3p, f4p)931end932933@inline function splitting_drikakis_tsangaris(u, ::Val{:minus}, orientation::Integer,934equations::CompressibleEulerEquations2D)935rho, rho_v1, rho_v2, rho_e = u936v1 = rho_v1 / rho937v2 = rho_v2 / rho938p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))939a = sqrt(equations.gamma * p / rho)940H = (rho_e + p) / rho941942if orientation == 1943lambda1 = v1 + a944lambda2 = v1 - a945946lambda1_m = negative_part(lambda1) # Same as (lambda_i - abs(lambda_i)) / 2, but faster :)947lambda2_m = negative_part(lambda2)948949rhoa_2gamma = 0.5f0 * rho * a / equations.gamma950f1m = 0.5f0 * rho * (lambda1_m + lambda2_m)951f2m = f1m * v1 + rhoa_2gamma * (lambda1_m - lambda2_m)952f3m = f1m * v2953f4m = f1m * H954else # orientation == 2955lambda1 = v2 + a956lambda2 = v2 - a957958lambda1_m = negative_part(lambda1) # Same as (lambda_i - abs(lambda_i)) / 2, but faster :)959lambda2_m = negative_part(lambda2)960961rhoa_2gamma = 0.5f0 * rho * a / equations.gamma962f1m = 0.5f0 * rho * (lambda1_m + lambda2_m)963f2m = f1m * v1964f3m = f1m * v2 + rhoa_2gamma * (lambda1_m - lambda2_m)965f4m = f1m * H966end967return SVector(f1m, f2m, f3m, f4m)968end969970@inline function splitting_drikakis_tsangaris(u, ::Val{:plus},971normal_direction::AbstractVector,972equations::CompressibleEulerEquations2D)973rho, rho_v1, rho_v2, rho_e = u974v1 = rho_v1 / rho975v2 = rho_v2 / rho976p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))977a = sqrt(equations.gamma * p / rho)978H = (rho_e + p) / rho979980v_n = normal_direction[1] * v1 + normal_direction[2] * v2981982lambda1 = v_n + a983lambda2 = v_n - a984985lambda1_p = positive_part(lambda1) # Same as (lambda_i + abs(lambda_i)) / 2, but faster :)986lambda2_p = positive_part(lambda2)987988rhoa_2gamma = 0.5f0 * rho * a / equations.gamma989f1p = 0.5f0 * rho * (lambda1_p + lambda2_p)990f2p = f1p * v1 + rhoa_2gamma * normal_direction[1] * (lambda1_p - lambda2_p)991f3p = f1p * v2 + rhoa_2gamma * normal_direction[2] * (lambda1_p - lambda2_p)992f4p = f1p * H993994return SVector(f1p, f2p, f3p, f4p)995end996997@inline function splitting_drikakis_tsangaris(u, ::Val{:minus},998normal_direction::AbstractVector,999equations::CompressibleEulerEquations2D)1000rho, rho_v1, rho_v2, rho_e = u1001v1 = rho_v1 / rho1002v2 = rho_v2 / rho1003p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))1004a = sqrt(equations.gamma * p / rho)1005H = (rho_e + p) / rho10061007v_n = normal_direction[1] * v1 + normal_direction[2] * v210081009lambda1 = v_n + a1010lambda2 = v_n - a10111012lambda1_m = negative_part(lambda1) # Same as (lambda_i - abs(lambda_i)) / 2, but faster :)1013lambda2_m = negative_part(lambda2)10141015rhoa_2gamma = 0.5f0 * rho * a / equations.gamma1016f1m = 0.5f0 * rho * (lambda1_m + lambda2_m)1017f2m = f1m * v1 + rhoa_2gamma * normal_direction[1] * (lambda1_m - lambda2_m)1018f3m = f1m * v2 + rhoa_2gamma * normal_direction[2] * (lambda1_m - lambda2_m)1019f4m = f1m * H10201021return SVector(f1m, f2m, f3m, f4m)1022end10231024"""1025FluxLMARS(c)(u_ll, u_rr, orientation_or_normal_direction,1026equations::CompressibleEulerEquations2D)10271028Low Mach number approximate Riemann solver (LMARS) for atmospheric flows using1029an estimate `c` of the speed of sound.10301031References:1032- Xi Chen et al. (2013)1033A Control-Volume Model of the Compressible Euler Equations with a Vertical1034Lagrangian Coordinate1035[DOI: 10.1175/MWR-D-12-00129.1](https://doi.org/10.1175/mwr-d-12-00129.1)1036"""1037struct FluxLMARS{SpeedOfSound}1038# Estimate for the speed of sound1039speed_of_sound::SpeedOfSound1040end10411042@inline function (flux_lmars::FluxLMARS)(u_ll, u_rr, orientation::Integer,1043equations::CompressibleEulerEquations2D)1044c = flux_lmars.speed_of_sound10451046# Unpack left and right state1047rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1048rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)10491050if orientation == 11051v_ll = v1_ll1052v_rr = v1_rr1053else # orientation == 21054v_ll = v2_ll1055v_rr = v2_rr1056end10571058rho = 0.5f0 * (rho_ll + rho_rr)1059p = 0.5f0 * (p_ll + p_rr) - 0.5f0 * c * rho * (v_rr - v_ll)1060v = 0.5f0 * (v_ll + v_rr) - 1 / (2 * c * rho) * (p_rr - p_ll)10611062# We treat the energy term analogous to the potential temperature term in the paper by1063# Chen et al., i.e. we use p_ll and p_rr, and not p1064if v >= 01065f1, f2, f3, f4 = v * u_ll1066f4 = f4 + p_ll * v1067else1068f1, f2, f3, f4 = v * u_rr1069f4 = f4 + p_rr * v1070end10711072if orientation == 11073f2 = f2 + p1074else # orientation == 21075f3 = f3 + p1076end10771078return SVector(f1, f2, f3, f4)1079end10801081@inline function (flux_lmars::FluxLMARS)(u_ll, u_rr, normal_direction::AbstractVector,1082equations::CompressibleEulerEquations2D)1083c = flux_lmars.speed_of_sound10841085# Unpack left and right state1086rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1087rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)10881089v_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]1090v_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]10911092# Note that this is the same as computing v_ll and v_rr with a normalized normal vector1093# and then multiplying v by `norm_` again, but this version is slightly faster.1094norm_ = norm(normal_direction)10951096rho = 0.5f0 * (rho_ll + rho_rr)1097p = 0.5f0 * (p_ll + p_rr) - 0.5f0 * c * rho * (v_rr - v_ll) / norm_1098v = 0.5f0 * (v_ll + v_rr) - 1 / (2 * c * rho) * (p_rr - p_ll) * norm_10991100# We treat the energy term analogous to the potential temperature term in the paper by1101# Chen et al., i.e. we use p_ll and p_rr, and not p1102if v >= 01103f1, f2, f3, f4 = u_ll * v1104f4 = f4 + p_ll * v1105else1106f1, f2, f3, f4 = u_rr * v1107f4 = f4 + p_rr * v1108end11091110return SVector(f1,1111f2 + p * normal_direction[1],1112f3 + p * normal_direction[2],1113f4)1114end11151116"""1117splitting_vanleer_haenel(u, orientation_or_normal_direction,1118equations::CompressibleEulerEquations2D)1119splitting_vanleer_haenel(u, which::Union{Val{:minus}, Val{:plus}}1120orientation_or_normal_direction,1121equations::CompressibleEulerEquations2D)11221123Splitting of the compressible Euler flux from van Leer. This splitting further1124contains a reformulation due to Hänel et al. where the energy flux uses the1125enthalpy. The pressure splitting is independent from the splitting of the1126convective terms. As such there are many pressure splittings suggested across1127the literature. We implement the 'p4' variant suggested by Liou and Steffen as1128it proved the most robust in practice. For details on the curvilinear variant1129of this flux vector splitting see Anderson et al.11301131Returns a tuple of the fluxes "minus" (associated with waves going into the1132negative axis direction) and "plus" (associated with waves going into the1133positive axis direction). If only one of the fluxes is required, use the1134function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`.11351136!!! warning "Experimental implementation (upwind SBP)"1137This is an experimental feature and may change in future releases.11381139## References11401141- Bram van Leer (1982)1142Flux-Vector Splitting for the Euler Equation1143[DOI: 10.1007/978-3-642-60543-7_5](https://doi.org/10.1007/978-3-642-60543-7_5)1144- D. Hänel, R. Schwane and G. Seider (1987)1145On the accuracy of upwind schemes for the solution of the Navier-Stokes equations1146[DOI: 10.2514/6.1987-1105](https://doi.org/10.2514/6.1987-1105)1147- Meng-Sing Liou and Chris J. Steffen, Jr. (1991)1148High-Order Polynomial Expansions (HOPE) for Flux-Vector Splitting1149[NASA Technical Memorandum](https://ntrs.nasa.gov/citations/19910016425)1150- W. Kyle Anderson, James L. Thomas, and Bram van Leer (1986)1151Comparison of Finite Volume Flux Vector Splittings for the Euler Equations1152[DOI: 10.2514/3.9465](https://doi.org/10.2514/3.9465)1153"""1154@inline function splitting_vanleer_haenel(u, orientation_or_normal_direction,1155equations::CompressibleEulerEquations2D)1156fm = splitting_vanleer_haenel(u, Val{:minus}(), orientation_or_normal_direction,1157equations)1158fp = splitting_vanleer_haenel(u, Val{:plus}(), orientation_or_normal_direction,1159equations)1160return fm, fp1161end11621163@inline function splitting_vanleer_haenel(u, ::Val{:plus}, orientation::Integer,1164equations::CompressibleEulerEquations2D)1165rho, rho_v1, rho_v2, rho_e = u1166v1 = rho_v1 / rho1167v2 = rho_v2 / rho1168p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))11691170a = sqrt(equations.gamma * p / rho)1171H = (rho_e + p) / rho11721173if orientation == 11174M = v1 / a1175p_plus = 0.5f0 * (1 + equations.gamma * M) * p11761177f1p = 0.25f0 * rho * a * (M + 1)^21178f2p = f1p * v1 + p_plus1179f3p = f1p * v21180f4p = f1p * H1181else # orientation == 21182M = v2 / a1183p_plus = 0.5f0 * (1 + equations.gamma * M) * p11841185f1p = 0.25f0 * rho * a * (M + 1)^21186f2p = f1p * v11187f3p = f1p * v2 + p_plus1188f4p = f1p * H1189end1190return SVector(f1p, f2p, f3p, f4p)1191end11921193@inline function splitting_vanleer_haenel(u, ::Val{:minus}, orientation::Integer,1194equations::CompressibleEulerEquations2D)1195rho, rho_v1, rho_v2, rho_e = u1196v1 = rho_v1 / rho1197v2 = rho_v2 / rho1198p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))11991200a = sqrt(equations.gamma * p / rho)1201H = (rho_e + p) / rho12021203if orientation == 11204M = v1 / a1205p_minus = 0.5f0 * (1 - equations.gamma * M) * p12061207f1m = -0.25f0 * rho * a * (M - 1)^21208f2m = f1m * v1 + p_minus1209f3m = f1m * v21210f4m = f1m * H1211else # orientation == 21212M = v2 / a1213p_minus = 0.5f0 * (1 - equations.gamma * M) * p12141215f1m = -0.25f0 * rho * a * (M - 1)^21216f2m = f1m * v11217f3m = f1m * v2 + p_minus1218f4m = f1m * H1219end1220return SVector(f1m, f2m, f3m, f4m)1221end12221223@inline function splitting_vanleer_haenel(u, ::Val{:plus},1224normal_direction::AbstractVector,1225equations::CompressibleEulerEquations2D)1226rho, rho_v1, rho_v2, rho_e = u1227v1 = rho_v1 / rho1228v2 = rho_v2 / rho1229p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))12301231a = sqrt(equations.gamma * p / rho)1232H = (rho_e + p) / rho12331234v_n = normal_direction[1] * v1 + normal_direction[2] * v21235M = v_n / a1236p_plus = 0.5f0 * (1 + equations.gamma * M) * p12371238f1p = 0.25f0 * rho * a * (M + 1)^21239f2p = f1p * v1 + normal_direction[1] * p_plus1240f3p = f1p * v2 + normal_direction[2] * p_plus1241f4p = f1p * H12421243return SVector(f1p, f2p, f3p, f4p)1244end12451246@inline function splitting_vanleer_haenel(u, ::Val{:minus},1247normal_direction::AbstractVector,1248equations::CompressibleEulerEquations2D)1249rho, rho_v1, rho_v2, rho_e = u1250v1 = rho_v1 / rho1251v2 = rho_v2 / rho1252p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))12531254a = sqrt(equations.gamma * p / rho)1255H = (rho_e + p) / rho12561257v_n = normal_direction[1] * v1 + normal_direction[2] * v21258M = v_n / a1259p_minus = 0.5f0 * (1 - equations.gamma * M) * p12601261f1m = -0.25f0 * rho * a * (M - 1)^21262f2m = f1m * v1 + normal_direction[1] * p_minus1263f3m = f1m * v2 + normal_direction[2] * p_minus1264f4m = f1m * H12651266return SVector(f1m, f2m, f3m, f4m)1267end12681269"""1270splitting_lax_friedrichs(u, orientation_or_normal_direction,1271equations::CompressibleEulerEquations2D)1272splitting_lax_friedrichs(u, which::Union{Val{:minus}, Val{:plus}}1273orientation_or_normal_direction,1274equations::CompressibleEulerEquations2D)12751276Naive local Lax-Friedrichs style flux splitting of the form `f⁺ = 0.5 (f + λ u)`1277and `f⁻ = 0.5 (f - λ u)` similar to a flux splitting one would apply, e.g.,1278to Burgers' equation.12791280Returns a tuple of the fluxes "minus" (associated with waves going into the1281negative axis direction) and "plus" (associated with waves going into the1282positive axis direction). If only one of the fluxes is required, use the1283function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`.12841285!!! warning "Experimental implementation (upwind SBP)"1286This is an experimental feature and may change in future releases.1287"""1288@inline function splitting_lax_friedrichs(u, orientation_or_normal_direction,1289equations::CompressibleEulerEquations2D)1290fm = splitting_lax_friedrichs(u, Val{:minus}(), orientation_or_normal_direction,1291equations)1292fp = splitting_lax_friedrichs(u, Val{:plus}(), orientation_or_normal_direction,1293equations)1294return fm, fp1295end12961297@inline function splitting_lax_friedrichs(u, ::Val{:plus}, orientation::Integer,1298equations::CompressibleEulerEquations2D)1299rho, rho_v1, rho_v2, rho_e = u1300v1 = rho_v1 / rho1301v2 = rho_v2 / rho1302p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))13031304a = sqrt(equations.gamma * p / rho)1305H = (rho_e + p) / rho1306lambda = 0.5f0 * (sqrt(v1^2 + v2^2) + a)13071308if orientation == 11309#lambda = 0.5 * (abs(v1) + a)1310f1p = 0.5f0 * rho * v1 + lambda * u[1]1311f2p = 0.5f0 * rho * v1 * v1 + 0.5f0 * p + lambda * u[2]1312f3p = 0.5f0 * rho * v1 * v2 + lambda * u[3]1313f4p = 0.5f0 * rho * v1 * H + lambda * u[4]1314else # orientation == 21315#lambda = 0.5 * (abs(v2) + a)1316f1p = 0.5f0 * rho * v2 + lambda * u[1]1317f2p = 0.5f0 * rho * v2 * v1 + lambda * u[2]1318f3p = 0.5f0 * rho * v2 * v2 + 0.5f0 * p + lambda * u[3]1319f4p = 0.5f0 * rho * v2 * H + lambda * u[4]1320end1321return SVector(f1p, f2p, f3p, f4p)1322end13231324@inline function splitting_lax_friedrichs(u, ::Val{:minus}, orientation::Integer,1325equations::CompressibleEulerEquations2D)1326rho, rho_v1, rho_v2, rho_e = u1327v1 = rho_v1 / rho1328v2 = rho_v2 / rho1329p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))13301331a = sqrt(equations.gamma * p / rho)1332H = (rho_e + p) / rho1333lambda = 0.5f0 * (sqrt(v1^2 + v2^2) + a)13341335if orientation == 11336#lambda = 0.5 * (abs(v1) + a)1337f1m = 0.5f0 * rho * v1 - lambda * u[1]1338f2m = 0.5f0 * rho * v1 * v1 + 0.5f0 * p - lambda * u[2]1339f3m = 0.5f0 * rho * v1 * v2 - lambda * u[3]1340f4m = 0.5f0 * rho * v1 * H - lambda * u[4]1341else # orientation == 21342#lambda = 0.5 * (abs(v2) + a)1343f1m = 0.5f0 * rho * v2 - lambda * u[1]1344f2m = 0.5f0 * rho * v2 * v1 - lambda * u[2]1345f3m = 0.5f0 * rho * v2 * v2 + 0.5f0 * p - lambda * u[3]1346f4m = 0.5f0 * rho * v2 * H - lambda * u[4]1347end1348return SVector(f1m, f2m, f3m, f4m)1349end13501351@inline function splitting_lax_friedrichs(u, ::Val{:plus},1352normal_direction::AbstractVector,1353equations::CompressibleEulerEquations2D)1354rho_e = last(u)1355rho, v1, v2, p = cons2prim(u, equations)13561357a = sqrt(equations.gamma * p / rho)1358H = (rho_e + p) / rho1359lambda = 0.5f0 * (sqrt(v1^2 + v2^2) + a)13601361v_normal = v1 * normal_direction[1] + v2 * normal_direction[2]1362rho_v_normal = rho * v_normal13631364f1p = 0.5f0 * rho_v_normal + lambda * u[1]1365f2p = 0.5f0 * rho_v_normal * v1 + 0.5f0 * p * normal_direction[1] + lambda * u[2]1366f3p = 0.5f0 * rho_v_normal * v2 + 0.5f0 * p * normal_direction[2] + lambda * u[3]1367f4p = 0.5f0 * rho_v_normal * H + lambda * u[4]13681369return SVector(f1p, f2p, f3p, f4p)1370end13711372@inline function splitting_lax_friedrichs(u, ::Val{:minus},1373normal_direction::AbstractVector,1374equations::CompressibleEulerEquations2D)1375rho_e = last(u)1376rho, v1, v2, p = cons2prim(u, equations)13771378a = sqrt(equations.gamma * p / rho)1379H = (rho_e + p) / rho1380lambda = 0.5f0 * (sqrt(v1^2 + v2^2) + a)13811382v_normal = v1 * normal_direction[1] + v2 * normal_direction[2]1383rho_v_normal = rho * v_normal13841385f1m = 0.5f0 * rho_v_normal - lambda * u[1]1386f2m = 0.5f0 * rho_v_normal * v1 + 0.5f0 * p * normal_direction[1] - lambda * u[2]1387f3m = 0.5f0 * rho_v_normal * v2 + 0.5f0 * p * normal_direction[2] - lambda * u[3]1388f4m = 0.5f0 * rho_v_normal * H - lambda * u[4]13891390return SVector(f1m, f2m, f3m, f4m)1391end13921393# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation as the1394# maximum velocity magnitude plus the maximum speed of sound1395@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,1396equations::CompressibleEulerEquations2D)1397rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1398rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)13991400# Get the velocity value in the appropriate direction1401if orientation == 11402v_ll = v1_ll1403v_rr = v1_rr1404else # orientation == 21405v_ll = v2_ll1406v_rr = v2_rr1407end1408# Calculate sound speeds1409c_ll = sqrt(equations.gamma * p_ll / rho_ll)1410c_rr = sqrt(equations.gamma * p_rr / rho_rr)14111412return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr)1413end14141415@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,1416equations::CompressibleEulerEquations2D)1417rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1418rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)14191420# Calculate normal velocities and sound speed1421# left1422v_ll = (v1_ll * normal_direction[1]1423+1424v2_ll * normal_direction[2])1425c_ll = sqrt(equations.gamma * p_ll / rho_ll)1426# right1427v_rr = (v1_rr * normal_direction[1]1428+1429v2_rr * normal_direction[2])1430c_rr = sqrt(equations.gamma * p_rr / rho_rr)14311432return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr) * norm(normal_direction)1433end14341435# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`1436@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,1437equations::CompressibleEulerEquations2D)1438rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1439rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)14401441# Get the velocity value in the appropriate direction1442if orientation == 11443v_ll = v1_ll1444v_rr = v1_rr1445else # orientation == 21446v_ll = v2_ll1447v_rr = v2_rr1448end1449# Calculate sound speeds1450c_ll = sqrt(equations.gamma * p_ll / rho_ll)1451c_rr = sqrt(equations.gamma * p_rr / rho_rr)14521453return max(abs(v_ll) + c_ll, abs(v_rr) + c_rr)1454end14551456# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`1457@inline function max_abs_speed(u_ll, u_rr, normal_direction::AbstractVector,1458equations::CompressibleEulerEquations2D)1459rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1460rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)14611462# Calculate normal velocities and sound speeds1463# left1464v_ll = (v1_ll * normal_direction[1]1465+1466v2_ll * normal_direction[2])1467c_ll = sqrt(equations.gamma * p_ll / rho_ll)1468# right1469v_rr = (v1_rr * normal_direction[1]1470+1471v2_rr * normal_direction[2])1472c_rr = sqrt(equations.gamma * p_rr / rho_rr)14731474norm_ = norm(normal_direction)1475return max(abs(v_ll) + c_ll * norm_,1476abs(v_rr) + c_rr * norm_)1477end14781479# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes1480@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer,1481equations::CompressibleEulerEquations2D)1482rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1483rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)14841485if orientation == 1 # x-direction1486λ_min = v1_ll - sqrt(equations.gamma * p_ll / rho_ll)1487λ_max = v1_rr + sqrt(equations.gamma * p_rr / rho_rr)1488else # y-direction1489λ_min = v2_ll - sqrt(equations.gamma * p_ll / rho_ll)1490λ_max = v2_rr + sqrt(equations.gamma * p_rr / rho_rr)1491end14921493return λ_min, λ_max1494end14951496@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,1497equations::CompressibleEulerEquations2D)1498rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1499rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)15001501v_normal_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]1502v_normal_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]15031504norm_ = norm(normal_direction)1505# The v_normals are already scaled by the norm1506λ_min = v_normal_ll - sqrt(equations.gamma * p_ll / rho_ll) * norm_1507λ_max = v_normal_rr + sqrt(equations.gamma * p_rr / rho_rr) * norm_15081509return λ_min, λ_max1510end15111512# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes1513@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer,1514equations::CompressibleEulerEquations2D)1515rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1516rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)15171518c_ll = sqrt(equations.gamma * p_ll / rho_ll)1519c_rr = sqrt(equations.gamma * p_rr / rho_rr)15201521if orientation == 1 # x-direction1522λ_min = min(v1_ll - c_ll, v1_rr - c_rr)1523λ_max = max(v1_ll + c_ll, v1_rr + c_rr)1524else # y-direction1525λ_min = min(v2_ll - c_ll, v2_rr - c_rr)1526λ_max = max(v2_ll + c_ll, v2_rr + c_rr)1527end15281529return λ_min, λ_max1530end15311532# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes1533@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector,1534equations::CompressibleEulerEquations2D)1535rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1536rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)15371538norm_ = norm(normal_direction)15391540c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_1541c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_15421543v_normal_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]1544v_normal_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]15451546# The v_normals are already scaled by the norm1547λ_min = min(v_normal_ll - c_ll, v_normal_rr - c_rr)1548λ_max = max(v_normal_ll + c_ll, v_normal_rr + c_rr)15491550return λ_min, λ_max1551end15521553@inline function (dissipation::DissipationMatrixWintersEtal)(u_ll, u_rr,1554normal_direction::AbstractVector,1555equations::CompressibleEulerEquations2D)1556(; gamma) = equations15571558norm_ = norm(normal_direction)1559unit_normal_direction = normal_direction / norm_15601561rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1562rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)15631564b_ll = rho_ll / (2 * p_ll)1565b_rr = rho_rr / (2 * p_rr)15661567rho_log = ln_mean(rho_ll, rho_rr)1568b_log = ln_mean(b_ll, b_rr)1569v1_avg = 0.5f0 * (v1_ll + v1_rr)1570v2_avg = 0.5f0 * (v2_ll + v2_rr)1571p_avg = 0.5f0 * (rho_ll + rho_rr) / (b_ll + b_rr) # 2 * b_avg = b_ll + b_rr1572v_squared_bar = v1_ll * v1_rr + v2_ll * v2_rr1573h_bar = gamma / (2 * b_log * (gamma - 1)) + 0.5f0 * v_squared_bar1574c_bar = sqrt(gamma * p_avg / rho_log)15751576v_avg_normal = dot(SVector(v1_avg, v2_avg), unit_normal_direction)15771578lambda_1 = abs(v_avg_normal - c_bar) * rho_log / (2 * gamma)1579lambda_2 = abs(v_avg_normal) * rho_log * (gamma - 1) / gamma1580lambda_3 = abs(v_avg_normal + c_bar) * rho_log / (2 * gamma)1581lambda_4 = abs(v_avg_normal) * p_avg15821583v1_minus_c = v1_avg - c_bar * unit_normal_direction[1]1584v2_minus_c = v2_avg - c_bar * unit_normal_direction[2]1585v1_plus_c = v1_avg + c_bar * unit_normal_direction[1]1586v2_plus_c = v2_avg + c_bar * unit_normal_direction[2]1587v1_tangential = v1_avg - v_avg_normal * unit_normal_direction[1]1588v2_tangential = v2_avg - v_avg_normal * unit_normal_direction[2]15891590entropy_vars_jump = cons2entropy(u_rr, equations) - cons2entropy(u_ll, equations)1591entropy_var_rho_jump, entropy_var_rho_v1_jump,1592entropy_var_rho_v2_jump, entropy_var_rho_e_jump = entropy_vars_jump15931594velocity_minus_c_dot_entropy_vars_jump = v1_minus_c * entropy_var_rho_v1_jump +1595v2_minus_c * entropy_var_rho_v2_jump1596velocity_plus_c_dot_entropy_vars_jump = v1_plus_c * entropy_var_rho_v1_jump +1597v2_plus_c * entropy_var_rho_v2_jump1598velocity_avg_dot_vjump = v1_avg * entropy_var_rho_v1_jump +1599v2_avg * entropy_var_rho_v2_jump1600w1 = lambda_1 * (entropy_var_rho_jump + velocity_minus_c_dot_entropy_vars_jump +1601(h_bar - c_bar * v_avg_normal) * entropy_var_rho_e_jump)1602w2 = lambda_2 * (entropy_var_rho_jump + velocity_avg_dot_vjump +1603v_squared_bar / 2 * entropy_var_rho_e_jump)1604w3 = lambda_3 * (entropy_var_rho_jump + velocity_plus_c_dot_entropy_vars_jump +1605(h_bar + c_bar * v_avg_normal) * entropy_var_rho_e_jump)16061607entropy_var_v_normal_jump = dot(SVector(entropy_var_rho_v1_jump,1608entropy_var_rho_v2_jump),1609unit_normal_direction)16101611dissipation_rho = w1 + w2 + w316121613dissipation_rho_v1 = (w1 * v1_minus_c +1614w2 * v1_avg +1615w3 * v1_plus_c +1616lambda_4 * (entropy_var_rho_v1_jump -1617unit_normal_direction[1] * entropy_var_v_normal_jump +1618entropy_var_rho_e_jump * v1_tangential))16191620dissipation_rho_v2 = (w1 * v2_minus_c +1621w2 * v2_avg +1622w3 * v2_plus_c +1623lambda_4 * (entropy_var_rho_v2_jump -1624unit_normal_direction[2] * entropy_var_v_normal_jump +1625entropy_var_rho_e_jump * v2_tangential))16261627v_tangential_dot_entropy_vars_jump = v1_tangential * entropy_var_rho_v1_jump +1628v2_tangential * entropy_var_rho_v2_jump16291630dissipation_rhoe = (w1 * (h_bar - c_bar * v_avg_normal) +1631w2 * 0.5f0 * v_squared_bar +1632w3 * (h_bar + c_bar * v_avg_normal) +1633lambda_4 * (v_tangential_dot_entropy_vars_jump +1634entropy_var_rho_e_jump *1635(v1_avg^2 + v2_avg^2 - v_avg_normal^2)))16361637return -0.5f0 *1638SVector(dissipation_rho, dissipation_rho_v1, dissipation_rho_v2,1639dissipation_rhoe) * norm_1640end16411642# Called inside `FluxRotated` in `numerical_fluxes.jl` so the direction1643# has been normalized prior to this rotation of the state vector1644@inline function rotate_to_x(u, normal_vector, equations::CompressibleEulerEquations2D)1645# cos and sin of the angle between the x-axis and the normalized normal_vector are1646# the normalized vector's x and y coordinates respectively (see unit circle).1647c = normal_vector[1]1648s = normal_vector[2]16491650# Apply the 2D rotation matrix with normal and tangent directions of the form1651# [ 1 0 0 0;1652# 0 n_1 n_2 0;1653# 0 t_1 t_2 0;1654# 0 0 0 1 ]1655# where t_1 = -n_2 and t_2 = n_116561657return SVector(u[1],1658c * u[2] + s * u[3],1659-s * u[2] + c * u[3],1660u[4])1661end16621663# Called inside `FluxRotated` in `numerical_fluxes.jl` so the direction1664# has been normalized prior to this back-rotation of the state vector1665@inline function rotate_from_x(u, normal_vector,1666equations::CompressibleEulerEquations2D)1667# cos and sin of the angle between the x-axis and the normalized normal_vector are1668# the normalized vector's x and y coordinates respectively (see unit circle).1669c = normal_vector[1]1670s = normal_vector[2]16711672# Apply the 2D back-rotation matrix with normal and tangent directions of the form1673# [ 1 0 0 0;1674# 0 n_1 t_1 0;1675# 0 n_2 t_2 0;1676# 0 0 0 1 ]1677# where t_1 = -n_2 and t_2 = n_116781679return SVector(u[1],1680c * u[2] - s * u[3],1681s * u[2] + c * u[3],1682u[4])1683end16841685"""1686flux_hllc(u_ll, u_rr, orientation_or_normal_direction, equations::CompressibleEulerEquations2D)16871688Computes the HLLC flux (HLL with Contact) for compressible Euler equations developed by E.F. Toro1689[Lecture slides](http://www.prague-sum.com/download/2012/Toro_2-HLLC-RiemannSolver.pdf)1690Signal speeds: [DOI: 10.1137/S1064827593260140](https://doi.org/10.1137/S1064827593260140)1691"""1692function flux_hllc(u_ll, u_rr, orientation::Integer,1693equations::CompressibleEulerEquations2D)1694# Calculate primitive variables and speed of sound1695rho_ll, rho_v1_ll, rho_v2_ll, rho_e_ll = u_ll1696rho_rr, rho_v1_rr, rho_v2_rr, rho_e_rr = u_rr16971698v1_ll = rho_v1_ll / rho_ll1699v2_ll = rho_v2_ll / rho_ll1700e_ll = rho_e_ll / rho_ll1701p_ll = (equations.gamma - 1) * (rho_e_ll - 0.5f0 * rho_ll * (v1_ll^2 + v2_ll^2))1702c_ll = sqrt(equations.gamma * p_ll / rho_ll)17031704v1_rr = rho_v1_rr / rho_rr1705v2_rr = rho_v2_rr / rho_rr1706e_rr = rho_e_rr / rho_rr1707p_rr = (equations.gamma - 1) * (rho_e_rr - 0.5f0 * rho_rr * (v1_rr^2 + v2_rr^2))1708c_rr = sqrt(equations.gamma * p_rr / rho_rr)17091710# Obtain left and right fluxes1711f_ll = flux(u_ll, orientation, equations)1712f_rr = flux(u_rr, orientation, equations)17131714# Compute Roe averages1715sqrt_rho_ll = sqrt(rho_ll)1716sqrt_rho_rr = sqrt(rho_rr)1717sum_sqrt_rho = sqrt_rho_ll + sqrt_rho_rr1718if orientation == 1 # x-direction1719vel_L = v1_ll1720vel_R = v1_rr1721elseif orientation == 2 # y-direction1722vel_L = v2_ll1723vel_R = v2_rr1724end1725vel_roe = (sqrt_rho_ll * vel_L + sqrt_rho_rr * vel_R) / sum_sqrt_rho1726v1_roe = sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr1727v2_roe = sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr1728vel_roe_mag = (v1_roe^2 + v2_roe^2) / sum_sqrt_rho^21729H_ll = (rho_e_ll + p_ll) / rho_ll1730H_rr = (rho_e_rr + p_rr) / rho_rr1731H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) / sum_sqrt_rho1732c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5f0 * vel_roe_mag))1733Ssl = min(vel_L - c_ll, vel_roe - c_roe)1734Ssr = max(vel_R + c_rr, vel_roe + c_roe)1735sMu_L = Ssl - vel_L1736sMu_R = Ssr - vel_R17371738if Ssl >= 01739f1 = f_ll[1]1740f2 = f_ll[2]1741f3 = f_ll[3]1742f4 = f_ll[4]1743elseif Ssr <= 01744f1 = f_rr[1]1745f2 = f_rr[2]1746f3 = f_rr[3]1747f4 = f_rr[4]1748else1749SStar = (p_rr - p_ll + rho_ll * vel_L * sMu_L - rho_rr * vel_R * sMu_R) /1750(rho_ll * sMu_L - rho_rr * sMu_R)1751if Ssl <= 0 <= SStar1752densStar = rho_ll * sMu_L / (Ssl - SStar)1753enerStar = e_ll + (SStar - vel_L) * (SStar + p_ll / (rho_ll * sMu_L))1754UStar1 = densStar1755UStar4 = densStar * enerStar1756if orientation == 1 # x-direction1757UStar2 = densStar * SStar1758UStar3 = densStar * v2_ll1759elseif orientation == 2 # y-direction1760UStar2 = densStar * v1_ll1761UStar3 = densStar * SStar1762end1763f1 = f_ll[1] + Ssl * (UStar1 - rho_ll)1764f2 = f_ll[2] + Ssl * (UStar2 - rho_v1_ll)1765f3 = f_ll[3] + Ssl * (UStar3 - rho_v2_ll)1766f4 = f_ll[4] + Ssl * (UStar4 - rho_e_ll)1767else1768densStar = rho_rr * sMu_R / (Ssr - SStar)1769enerStar = e_rr + (SStar - vel_R) * (SStar + p_rr / (rho_rr * sMu_R))1770UStar1 = densStar1771UStar4 = densStar * enerStar1772if orientation == 1 # x-direction1773UStar2 = densStar * SStar1774UStar3 = densStar * v2_rr1775elseif orientation == 2 # y-direction1776UStar2 = densStar * v1_rr1777UStar3 = densStar * SStar1778end1779f1 = f_rr[1] + Ssr * (UStar1 - rho_rr)1780f2 = f_rr[2] + Ssr * (UStar2 - rho_v1_rr)1781f3 = f_rr[3] + Ssr * (UStar3 - rho_v2_rr)1782f4 = f_rr[4] + Ssr * (UStar4 - rho_e_rr)1783end1784end1785return SVector(f1, f2, f3, f4)1786end17871788function flux_hllc(u_ll, u_rr, normal_direction::AbstractVector,1789equations::CompressibleEulerEquations2D)1790# Calculate primitive variables and speed of sound1791rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1792rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)17931794v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]1795v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]17961797norm_ = norm(normal_direction)1798norm_sq = norm_ * norm_1799inv_norm_sq = inv(norm_sq)18001801c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_1802c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_18031804# Obtain left and right fluxes1805f_ll = flux(u_ll, normal_direction, equations)1806f_rr = flux(u_rr, normal_direction, equations)18071808# Compute Roe averages1809sqrt_rho_ll = sqrt(rho_ll)1810sqrt_rho_rr = sqrt(rho_rr)1811sum_sqrt_rho = sqrt_rho_ll + sqrt_rho_rr18121813v1_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr) / sum_sqrt_rho1814v2_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr) / sum_sqrt_rho1815vel_roe = v1_roe * normal_direction[1] + v2_roe * normal_direction[2]1816vel_roe_mag = v1_roe^2 + v2_roe^218171818e_ll = u_ll[4] / rho_ll1819e_rr = u_rr[4] / rho_rr18201821H_ll = (u_ll[4] + p_ll) / rho_ll1822H_rr = (u_rr[4] + p_rr) / rho_rr18231824H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) / sum_sqrt_rho1825c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5f0 * vel_roe_mag)) * norm_18261827Ssl = min(v_dot_n_ll - c_ll, vel_roe - c_roe)1828Ssr = max(v_dot_n_rr + c_rr, vel_roe + c_roe)1829sMu_L = Ssl - v_dot_n_ll1830sMu_R = Ssr - v_dot_n_rr18311832if Ssl >= 01833f1 = f_ll[1]1834f2 = f_ll[2]1835f3 = f_ll[3]1836f4 = f_ll[4]1837elseif Ssr <= 01838f1 = f_rr[1]1839f2 = f_rr[2]1840f3 = f_rr[3]1841f4 = f_rr[4]1842else1843SStar = (rho_ll * v_dot_n_ll * sMu_L - rho_rr * v_dot_n_rr * sMu_R +1844(p_rr - p_ll) * norm_sq) / (rho_ll * sMu_L - rho_rr * sMu_R)1845if Ssl <= 0 <= SStar1846densStar = rho_ll * sMu_L / (Ssl - SStar)1847enerStar = e_ll +1848(SStar - v_dot_n_ll) *1849(SStar * inv_norm_sq + p_ll / (rho_ll * sMu_L))1850UStar1 = densStar1851UStar2 = densStar *1852(v1_ll + (SStar - v_dot_n_ll) * normal_direction[1] * inv_norm_sq)1853UStar3 = densStar *1854(v2_ll + (SStar - v_dot_n_ll) * normal_direction[2] * inv_norm_sq)1855UStar4 = densStar * enerStar1856f1 = f_ll[1] + Ssl * (UStar1 - u_ll[1])1857f2 = f_ll[2] + Ssl * (UStar2 - u_ll[2])1858f3 = f_ll[3] + Ssl * (UStar3 - u_ll[3])1859f4 = f_ll[4] + Ssl * (UStar4 - u_ll[4])1860else1861densStar = rho_rr * sMu_R / (Ssr - SStar)1862enerStar = e_rr +1863(SStar - v_dot_n_rr) *1864(SStar * inv_norm_sq + p_rr / (rho_rr * sMu_R))1865UStar1 = densStar1866UStar2 = densStar *1867(v1_rr + (SStar - v_dot_n_rr) * normal_direction[1] * inv_norm_sq)1868UStar3 = densStar *1869(v2_rr + (SStar - v_dot_n_rr) * normal_direction[2] * inv_norm_sq)1870UStar4 = densStar * enerStar1871f1 = f_rr[1] + Ssr * (UStar1 - u_rr[1])1872f2 = f_rr[2] + Ssr * (UStar2 - u_rr[2])1873f3 = f_rr[3] + Ssr * (UStar3 - u_rr[3])1874f4 = f_rr[4] + Ssr * (UStar4 - u_rr[4])1875end1876end1877return SVector(f1, f2, f3, f4)1878end18791880"""1881min_max_speed_einfeldt(u_ll, u_rr, orientation, equations::CompressibleEulerEquations2D)18821883Computes the HLLE (Harten-Lax-van Leer-Einfeldt) flux for the compressible Euler equations.1884Special estimates of the signal velocites and linearization of the Riemann problem developed1885by Einfeldt to ensure that the internal energy and density remain positive during the computation1886of the numerical flux.18871888- Bernd Einfeldt (1988)1889On Godunov-type methods for gas dynamics.1890[DOI: 10.1137/0725021](https://doi.org/10.1137/0725021)1891- Bernd Einfeldt, Claus-Dieter Munz, Philip L. Roe and Björn Sjögreen (1991)1892On Godunov-type methods near low densities.1893[DOI: 10.1016/0021-9991(91)90211-3](https://doi.org/10.1016/0021-9991(91)90211-3)1894"""1895@inline function min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer,1896equations::CompressibleEulerEquations2D)1897# Calculate primitive variables, enthalpy and speed of sound1898rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1899rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)19001901# `u_ll[4]` is total energy `rho_e_ll` on the left1902H_ll = (u_ll[4] + p_ll) / rho_ll1903c_ll = sqrt(equations.gamma * p_ll / rho_ll)19041905# `u_rr[4]` is total energy `rho_e_rr` on the right1906H_rr = (u_rr[4] + p_rr) / rho_rr1907c_rr = sqrt(equations.gamma * p_rr / rho_rr)19081909# Compute Roe averages1910sqrt_rho_ll = sqrt(rho_ll)1911sqrt_rho_rr = sqrt(rho_rr)1912inv_sum_sqrt_rho = inv(sqrt_rho_ll + sqrt_rho_rr)19131914v1_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr) * inv_sum_sqrt_rho1915v2_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr) * inv_sum_sqrt_rho1916v_roe_mag = v1_roe^2 + v2_roe^219171918H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) * inv_sum_sqrt_rho1919c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5f0 * v_roe_mag))19201921# Compute convenience constant for positivity preservation, see1922# https://doi.org/10.1016/0021-9991(91)90211-31923beta = sqrt(0.5f0 * (equations.gamma - 1) / equations.gamma)19241925# Estimate the edges of the Riemann fan (with positivity conservation)1926if orientation == 1 # x-direction1927SsL = min(v1_roe - c_roe, v1_ll - beta * c_ll, 0)1928SsR = max(v1_roe + c_roe, v1_rr + beta * c_rr, 0)1929elseif orientation == 2 # y-direction1930SsL = min(v2_roe - c_roe, v2_ll - beta * c_ll, 0)1931SsR = max(v2_roe + c_roe, v2_rr + beta * c_rr, 0)1932end19331934return SsL, SsR1935end19361937"""1938min_max_speed_einfeldt(u_ll, u_rr, normal_direction, equations::CompressibleEulerEquations2D)19391940Computes the HLLE (Harten-Lax-van Leer-Einfeldt) flux for the compressible Euler equations.1941Special estimates of the signal velocites and linearization of the Riemann problem developed1942by Einfeldt to ensure that the internal energy and density remain positive during the computation1943of the numerical flux.19441945- Bernd Einfeldt (1988)1946On Godunov-type methods for gas dynamics.1947[DOI: 10.1137/0725021](https://doi.org/10.1137/0725021)1948- Bernd Einfeldt, Claus-Dieter Munz, Philip L. Roe and Björn Sjögreen (1991)1949On Godunov-type methods near low densities.1950[DOI: 10.1016/0021-9991(91)90211-3](https://doi.org/10.1016/0021-9991(91)90211-3)1951"""1952@inline function min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector,1953equations::CompressibleEulerEquations2D)1954# Calculate primitive variables, enthalpy and speed of sound1955rho_ll, v1_ll, v2_ll, p_ll = cons2prim(u_ll, equations)1956rho_rr, v1_rr, v2_rr, p_rr = cons2prim(u_rr, equations)19571958v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]1959v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]19601961norm_ = norm(normal_direction)19621963# `u_ll[4]` is total energy `rho_e_ll` on the left1964H_ll = (u_ll[4] + p_ll) / rho_ll1965c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_19661967# `u_rr[4]` is total energy `rho_e_rr` on the right1968H_rr = (u_rr[4] + p_rr) / rho_rr1969c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_19701971# Compute Roe averages1972sqrt_rho_ll = sqrt(rho_ll)1973sqrt_rho_rr = sqrt(rho_rr)1974inv_sum_sqrt_rho = inv(sqrt_rho_ll + sqrt_rho_rr)19751976v1_roe = (sqrt_rho_ll * v1_ll + sqrt_rho_rr * v1_rr) * inv_sum_sqrt_rho1977v2_roe = (sqrt_rho_ll * v2_ll + sqrt_rho_rr * v2_rr) * inv_sum_sqrt_rho1978v_roe = v1_roe * normal_direction[1] + v2_roe * normal_direction[2]1979v_roe_mag = v1_roe^2 + v2_roe^219801981H_roe = (sqrt_rho_ll * H_ll + sqrt_rho_rr * H_rr) * inv_sum_sqrt_rho1982c_roe = sqrt((equations.gamma - 1) * (H_roe - 0.5f0 * v_roe_mag)) * norm_19831984# Compute convenience constant for positivity preservation, see1985# https://doi.org/10.1016/0021-9991(91)90211-31986beta = sqrt(0.5f0 * (equations.gamma - 1) / equations.gamma)19871988# Estimate the edges of the Riemann fan (with positivity conservation)1989SsL = min(v_roe - c_roe, v_dot_n_ll - beta * c_ll, 0)1990SsR = max(v_roe + c_roe, v_dot_n_rr + beta * c_rr, 0)19911992return SsL, SsR1993end19941995@inline function max_abs_speeds(u, equations::CompressibleEulerEquations2D)1996rho, v1, v2, p = cons2prim(u, equations)1997c = sqrt(equations.gamma * p / rho)19981999return abs(v1) + c, abs(v2) + c2000end20012002# Convert conservative variables to primitive2003@inline function cons2prim(u, equations::CompressibleEulerEquations2D)2004rho, rho_v1, rho_v2, rho_e = u20052006v1 = rho_v1 / rho2007v2 = rho_v2 / rho2008p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1 * v1 + rho_v2 * v2))20092010return SVector(rho, v1, v2, p)2011end20122013# Convert conservative variables to entropy2014@inline function cons2entropy(u, equations::CompressibleEulerEquations2D)2015rho, rho_v1, rho_v2, rho_e = u20162017v1 = rho_v1 / rho2018v2 = rho_v2 / rho2019v_square = v1^2 + v2^22020p = (equations.gamma - 1) * (rho_e - 0.5f0 * rho * v_square)2021s = log(p) - equations.gamma * log(rho)2022rho_p = rho / p20232024w1 = (equations.gamma - s) * equations.inv_gamma_minus_one -20250.5f0 * rho_p * v_square2026w2 = rho_p * v12027w3 = rho_p * v22028w4 = -rho_p20292030return SVector(w1, w2, w3, w4)2031end20322033# Transformation from conservative variables u to entropy vector ds_0/du,2034# using the modified specific entropy of Guermond et al. (2019): s_0 = p * rho^(-gamma) / (gamma-1).2035# Note: This is *not* the "conventional" specific entropy s = ln(p / rho^(gamma)).2036@inline function cons2entropy_guermond_etal(u, equations::CompressibleEulerEquations2D)2037rho, rho_v1, rho_v2, rho_e = u20382039v1 = rho_v1 / rho2040v2 = rho_v2 / rho2041v_square = v1^2 + v2^22042inv_rho_gammap1 = (1 / rho)^(equations.gamma + 1)20432044# The derivative vector for the modified specific entropy of Guermond et al.2045w1 = inv_rho_gammap1 *2046(0.5f0 * rho * (equations.gamma + 1) * v_square - equations.gamma * rho_e)2047w2 = -rho_v1 * inv_rho_gammap12048w3 = -rho_v2 * inv_rho_gammap12049w4 = (1 / rho)^equations.gamma20502051return SVector(w1, w2, w3, w4)2052end20532054@inline function entropy2cons(w, equations::CompressibleEulerEquations2D)2055# See Hughes, Franca, Mallet (1986) A new finite element formulation for CFD2056# [DOI: 10.1016/0045-7825(86)90127-1](https://doi.org/10.1016/0045-7825(86)90127-1)2057@unpack gamma = equations20582059# convert to entropy `-rho * s` used by Hughes, France, Mallet (1986)2060# instead of `-rho * s / (gamma - 1)`2061V1, V2, V3, V5 = w .* (gamma - 1)20622063# s = specific entropy, eq. (53)2064s = gamma - V1 + (V2^2 + V3^2) / (2 * V5)20652066# eq. (52)2067rho_iota = ((gamma - 1) / (-V5)^gamma)^(equations.inv_gamma_minus_one) *2068exp(-s * equations.inv_gamma_minus_one)20692070# eq. (51)2071rho = -rho_iota * V52072rho_v1 = rho_iota * V22073rho_v2 = rho_iota * V32074rho_e = rho_iota * (1 - (V2^2 + V3^2) / (2 * V5))2075return SVector(rho, rho_v1, rho_v2, rho_e)2076end20772078# Convert primitive to conservative variables2079@inline function prim2cons(prim, equations::CompressibleEulerEquations2D)2080rho, v1, v2, p = prim2081rho_v1 = rho * v12082rho_v2 = rho * v22083rho_e = p * equations.inv_gamma_minus_one + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2)2084return SVector(rho, rho_v1, rho_v2, rho_e)2085end20862087@inline function density(u, equations::CompressibleEulerEquations2D)2088rho = u[1]2089return rho2090end20912092@inline function velocity(u, equations::CompressibleEulerEquations2D)2093rho = u[1]2094v1 = u[2] / rho2095v2 = u[3] / rho2096return SVector(v1, v2)2097end20982099@inline function velocity(u, orientation::Int, equations::CompressibleEulerEquations2D)2100rho = u[1]2101v = u[orientation + 1] / rho2102return v2103end21042105@inline function pressure(u, equations::CompressibleEulerEquations2D)2106rho, rho_v1, rho_v2, rho_e = u2107p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2) / rho)2108return p2109end21102111# Transformation from conservative variables u to d(p)/d(u)2112@inline function gradient_conservative(::typeof(pressure),2113u, equations::CompressibleEulerEquations2D)2114rho, rho_v1, rho_v2, rho_e = u21152116v1 = rho_v1 / rho2117v2 = rho_v2 / rho2118v_square = v1^2 + v2^221192120return (equations.gamma - 1) * SVector(0.5f0 * v_square, -v1, -v2, 1)2121end21222123@inline function density_pressure(u, equations::CompressibleEulerEquations2D)2124rho, rho_v1, rho_v2, rho_e = u2125rho_times_p = (equations.gamma - 1) * (rho * rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2))2126return rho_times_p2127end21282129# Calculates the entropy flux in direction "orientation" and the entropy variables for a state cons2130# NOTE: This method seems to work currently (b82534e) but is never used anywhere. Thus it is2131# commented here until someone uses it or writes a test for it.2132# @inline function cons2entropyvars_and_flux(gamma::Float64, cons, orientation::Int)2133# entropy = MVector{4, Float64}(undef)2134# v = (cons[2] / cons[1] , cons[3] / cons[1])2135# v_square= v[1]*v[1]+v[2]*v[2]2136# p = (gamma - 1) * (cons[4] - 1/2 * (cons[2] * v[1] + cons[3] * v[2]))2137# rho_p = cons[1] / p2138# # thermodynamic entropy2139# s = log(p) - gamma*log(cons[1])2140# # mathematical entropy2141# S = - s*cons[1]/(gamma-1)2142# # entropy variables2143# entropy[1] = (gamma - s)/(gamma-1) - 0.5*rho_p*v_square2144# entropy[2] = rho_p*v[1]2145# entropy[3] = rho_p*v[2]2146# entropy[4] = -rho_p2147# # entropy flux2148# entropy_flux = S*v[orientation]2149# return entropy, entropy_flux2150# end21512152# Calculate thermodynamic entropy for a conservative state `cons`2153@inline function entropy_thermodynamic(cons, equations::CompressibleEulerEquations2D)2154# Pressure2155p = (equations.gamma - 1) * (cons[4] - 0.5f0 * (cons[2]^2 + cons[3]^2) / cons[1])21562157# Thermodynamic entropy2158s = log(p) - equations.gamma * log(cons[1])21592160return s2161end21622163# Calculate mathematical entropy for a conservative state `cons`2164@inline function entropy_math(cons, equations::CompressibleEulerEquations2D)2165# Mathematical entropy2166S = -entropy_thermodynamic(cons, equations) * cons[1] *2167equations.inv_gamma_minus_one21682169return S2170end21712172# Transformation from conservative variables u to d(s)/d(u)2173@inline function gradient_conservative(::typeof(entropy_math),2174u, equations::CompressibleEulerEquations2D)2175return cons2entropy(u, equations)2176end21772178@doc raw"""2179entropy_guermond_etal(u, equations::CompressibleEulerEquations2D)21802181Calculate the modified specific entropy of Guermond et al. (2019):2182```math2183s_0 = p * \rho^{-\gamma} / (\gamma-1).2184```2185Note: This is *not* the "conventional" specific entropy ``s = ln(p / \rho^\gamma)``.2186- Guermond at al. (2019)2187Invariant domain preserving discretization-independent schemes and convex limiting for hyperbolic systems.2188[DOI: 10.1016/j.cma.2018.11.036](https://doi.org/10.1016/j.cma.2018.11.036)2189"""2190@inline function entropy_guermond_etal(u, equations::CompressibleEulerEquations2D)2191rho, rho_v1, rho_v2, rho_e = u21922193# Modified specific entropy from Guermond et al. (2019)2194s = (rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2) / rho) * (1 / rho)^equations.gamma21952196return s2197end21982199# Transformation from conservative variables u to d(s)/d(u)2200@inline function gradient_conservative(::typeof(entropy_guermond_etal),2201u, equations::CompressibleEulerEquations2D)2202return cons2entropy_guermond_etal(u, equations)2203end22042205# Default entropy is the mathematical entropy2206@inline function entropy(cons, equations::CompressibleEulerEquations2D)2207entropy_math(cons, equations)2208end22092210# Calculate total energy for a conservative state `cons`2211@inline energy_total(cons, ::CompressibleEulerEquations2D) = cons[4]22122213# Calculate kinetic energy for a conservative state `cons`2214@inline function energy_kinetic(u, equations::CompressibleEulerEquations2D)2215rho, rho_v1, rho_v2, rho_e = u2216return (rho_v1^2 + rho_v2^2) / (2 * rho)2217end22182219# Calculate internal energy for a conservative state `cons`2220@inline function energy_internal(cons, equations::CompressibleEulerEquations2D)2221return energy_total(cons, equations) - energy_kinetic(cons, equations)2222end22232224# State validation for Newton-bisection method of subcell IDP limiting2225@inline function Base.isvalid(u, equations::CompressibleEulerEquations2D)2226p = pressure(u, equations)2227if u[1] <= 0 || p <= 02228return false2229end2230return true2231end2232end # @muladd223322342235