Path: blob/main/src/equations/compressible_euler_multicomponent_2d.jl
2055 views
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).1# Since these FMAs can increase the performance of many numerical algorithms,2# we need to opt-in explicitly.3# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.4@muladd begin5#! format: noindent67@doc raw"""8CompressibleEulerMulticomponentEquations2D(; gammas, gas_constants)910Multicomponent version of the compressible Euler equations11```math12\frac{\partial}{\partial t}13\begin{pmatrix}14\rho v_1 \\ \rho v_2 \\ \rho e \\ \rho_1 \\ \rho_2 \\ \vdots \\ \rho_{n}15\end{pmatrix}16+17\frac{\partial}{\partial x}18\begin{pmatrix}19\rho v_1^2 + p \\ \rho v_1 v_2 \\ ( \rho e +p) v_1 \\ \rho_1 v_1 \\ \rho_2 v_1 \\ \vdots \\ \rho_{n} v_120\end{pmatrix}21+22\frac{\partial}{\partial y}23\begin{pmatrix}24\rho v_1 v_2 \\ \rho v_2^2 + p \\ ( \rho e +p) v_2 \\ \rho_1 v_2 \\ \rho_2 v_2 \\ \vdots \\ \rho_{n} v_225\end{pmatrix}26=27\begin{pmatrix}280 \\ 0 \\ 0 \\ 0 \\ 0 \\ \vdots \\ 029\end{pmatrix}30```31for calorically perfect gas in two space dimensions.32Here, ``\rho_i`` is the density of component ``i``, ``\rho=\sum_{i=1}^n\rho_i`` the sum of the individual ``\rho_i``,33``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```math39\gamma=\frac{\sum_{i=1}^n\rho_i C_{v,i}\gamma_i}{\sum_{i=1}^n\rho_i C_{v,i}}40```41total heat capacity ratio, ``\gamma_i`` heat capacity ratio of component ``i``,42```math43C_{v,i}=\frac{R}{\gamma_i-1}44```45specific heat capacity at constant volume of component ``i``.4647In case of more than one component, the specific heat ratios `gammas` and the gas constants48`gas_constants` in [kJ/(kg*K)] should be passed as tuples, e.g., `gammas=(1.4, 1.667)`.4950The remaining variables like the specific heats at constant volume `cv` or the specific heats at51constant pressure `cp` are then calculated considering a calorically perfect gas.52"""53struct CompressibleEulerMulticomponentEquations2D{NVARS, NCOMP, RealT <: Real} <:54AbstractCompressibleEulerMulticomponentEquations{2, NVARS, NCOMP}55gammas::SVector{NCOMP, RealT}56gas_constants::SVector{NCOMP, RealT}57cv::SVector{NCOMP, RealT}58cp::SVector{NCOMP, RealT}5960function CompressibleEulerMulticomponentEquations2D{NVARS, NCOMP, RealT}(gammas::SVector{NCOMP,61RealT},62gas_constants::SVector{NCOMP,63RealT}) where {64NVARS,65NCOMP,66RealT <:67Real68}69NCOMP >= 1 ||70throw(DimensionMismatch("`gammas` and `gas_constants` have to be filled with at least one value"))7172cv = gas_constants ./ (gammas .- 1)73cp = gas_constants + gas_constants ./ (gammas .- 1)7475new(gammas, gas_constants, cv, cp)76end77end7879function CompressibleEulerMulticomponentEquations2D(; gammas, gas_constants)80_gammas = promote(gammas...)81_gas_constants = promote(gas_constants...)82RealT = promote_type(eltype(_gammas), eltype(_gas_constants),83typeof(gas_constants[1] / (gammas[1] - 1)))84__gammas = SVector(map(RealT, _gammas))85__gas_constants = SVector(map(RealT, _gas_constants))8687NVARS = length(_gammas) + 388NCOMP = length(_gammas)8990return CompressibleEulerMulticomponentEquations2D{NVARS, NCOMP, RealT}(__gammas,91__gas_constants)92end9394@inline function Base.real(::CompressibleEulerMulticomponentEquations2D{NVARS, NCOMP,95RealT}) where {96NVARS,97NCOMP,98RealT99}100RealT101end102103function varnames(::typeof(cons2cons),104equations::CompressibleEulerMulticomponentEquations2D)105cons = ("rho_v1", "rho_v2", "rho_e")106rhos = ntuple(n -> "rho" * string(n), Val(ncomponents(equations)))107return (cons..., rhos...)108end109110function varnames(::typeof(cons2prim),111equations::CompressibleEulerMulticomponentEquations2D)112prim = ("v1", "v2", "p")113rhos = ntuple(n -> "rho" * string(n), Val(ncomponents(equations)))114return (prim..., rhos...)115end116117# Set initial conditions at physical location `x` for time `t`118119"""120initial_condition_convergence_test(x, t, equations::CompressibleEulerMulticomponentEquations2D)121122A smooth initial condition used for convergence tests in combination with123[`source_terms_convergence_test`](@ref)124(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains).125"""126function initial_condition_convergence_test(x, t,127equations::CompressibleEulerMulticomponentEquations2D)128RealT = eltype(x)129c = 2130A = convert(RealT, 0.1)131L = 2132f = 1.0f0 / L133omega = 2 * convert(RealT, pi) * f134ini = c + A * sin(omega * (x[1] + x[2] - t))135136v1 = 1137v2 = 1138139rho = ini140141# Here we compute an arbitrary number of different rhos. (one rho is double the next rho while the sum of all rhos is 1)142prim_rho = SVector{ncomponents(equations), real(equations)}(2^(i - 1) * (1 - 2) *143rho / (1 -1442^ncomponents(equations))145for i in eachcomponent(equations))146147prim1 = rho * v1148prim2 = rho * v2149prim3 = rho^2150151prim_other = SVector(prim1, prim2, prim3)152153return vcat(prim_other, prim_rho)154end155156"""157source_terms_convergence_test(u, x, t, equations::CompressibleEulerMulticomponentEquations2D)158159Source terms used for convergence tests in combination with160[`initial_condition_convergence_test`](@ref)161(and [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref) in non-periodic domains).162"""163@inline function source_terms_convergence_test(u, x, t,164equations::CompressibleEulerMulticomponentEquations2D)165# Same settings as in `initial_condition`166RealT = eltype(u)167c = 2168A = convert(RealT, 0.1)169L = 2170f = 1.0f0 / L171omega = 2 * convert(RealT, pi) * f172173gamma = totalgamma(u, equations)174175x1, x2 = x176si, co = sincos((x1 + x2 - t) * omega)177tmp1 = co * A * omega178tmp2 = si * A179tmp3 = gamma - 1180tmp4 = (2 * c - 1) * tmp3181tmp5 = (2 * tmp2 * gamma - 2 * tmp2 + tmp4 + 1) * tmp1182tmp6 = tmp2 + c183184# Here we compute an arbitrary number of different rhos. (one rho is double the next rho while the sum of all rhos is 1185du_rho = SVector{ncomponents(equations), real(equations)}(2^(i - 1) * (1 - 2) *186tmp1 / (1 -1872^ncomponents(equations))188for i in eachcomponent(equations))189190du1 = tmp5191du2 = tmp5192du3 = 2 * ((tmp6 - 1) * tmp3 + tmp6 * gamma) * tmp1193194du_other = SVector(du1, du2, du3)195196return vcat(du_other, du_rho)197end198199"""200initial_condition_weak_blast_wave(x, t, equations::CompressibleEulerMulticomponentEquations2D)201202A for multicomponent adapted weak blast wave taken from203- Sebastian Hennemann, Gregor J. Gassner (2020)204A provably entropy stable subcell shock capturing approach for high order split form DG205[arXiv: 2008.12044](https://arxiv.org/abs/2008.12044)206"""207function initial_condition_weak_blast_wave(x, t,208equations::CompressibleEulerMulticomponentEquations2D)209# From Hennemann & Gassner JCP paper 2020 (Sec. 6.3)210# Set up polar coordinates211RealT = eltype(x)212inicenter = SVector(0, 0)213x_norm = x[1] - inicenter[1]214y_norm = x[2] - inicenter[2]215r = sqrt(x_norm^2 + y_norm^2)216phi = atan(y_norm, x_norm)217sin_phi, cos_phi = sincos(phi)218219prim_rho = SVector{ncomponents(equations), real(equations)}(r > 0.5f0 ?2202^(i - 1) * (1 - 2) /221(RealT(1) -2222^ncomponents(equations)) :2232^(i - 1) * (1 - 2) *224RealT(1.1691) /225(1 -2262^ncomponents(equations))227for i in eachcomponent(equations))228229v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos_phi230v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin_phi231p = r > 0.5f0 ? one(RealT) : convert(RealT, 1.245)232233prim_other = SVector(v1, v2, p)234235return prim2cons(vcat(prim_other, prim_rho), equations)236end237238# Calculate 1D flux for a single point239@inline function flux(u, orientation::Integer,240equations::CompressibleEulerMulticomponentEquations2D)241rho_v1, rho_v2, rho_e = u242243rho = density(u, equations)244245v1 = rho_v1 / rho246v2 = rho_v2 / rho247gamma = totalgamma(u, equations)248p = (gamma - 1) * (rho_e - 0.5f0 * rho * (v1^2 + v2^2))249250if orientation == 1251f_rho = densities(u, v1, equations)252f1 = rho_v1 * v1 + p253f2 = rho_v2 * v1254f3 = (rho_e + p) * v1255else256f_rho = densities(u, v2, equations)257f1 = rho_v1 * v2258f2 = rho_v2 * v2 + p259f3 = (rho_e + p) * v2260end261262f_other = SVector(f1, f2, f3)263264return vcat(f_other, f_rho)265end266267# Calculate 1D flux for a single point268@inline function flux(u, normal_direction::AbstractVector,269equations::CompressibleEulerMulticomponentEquations2D)270rho_v1, rho_v2, rho_e = u271272rho = density(u, equations)273274v1 = rho_v1 / rho275v2 = rho_v2 / rho276v_normal = v1 * normal_direction[1] + v2 * normal_direction[2]277gamma = totalgamma(u, equations)278p = (gamma - 1) * (rho_e - 0.5f0 * rho * (v1^2 + v2^2))279280f_rho = densities(u, v_normal, equations)281f1 = rho_v1 * v_normal + p * normal_direction[1]282f2 = rho_v2 * v_normal + p * normal_direction[2]283f3 = (rho_e + p) * v_normal284285f_other = SVector(f1, f2, f3)286287return vcat(f_other, f_rho)288end289290"""291flux_chandrashekar(u_ll, u_rr, orientation, equations::CompressibleEulerMulticomponentEquations2D)292293Adaption of the entropy conserving two-point flux by294- Ayoub Gouasmi, Karthik Duraisamy (2020)295"Formulation of Entropy-Stable schemes for the multicomponent compressible Euler equations"296[arXiv:1904.00972v3](https://arxiv.org/abs/1904.00972) [math.NA] 4 Feb 2020297"""298@inline function flux_chandrashekar(u_ll, u_rr, orientation::Integer,299equations::CompressibleEulerMulticomponentEquations2D)300# Unpack left and right state301@unpack gammas, gas_constants, cv = equations302rho_v1_ll, rho_v2_ll, rho_e_ll = u_ll303rho_v1_rr, rho_v2_rr, rho_e_rr = u_rr304rhok_mean = SVector{ncomponents(equations), real(equations)}(ln_mean(u_ll[i + 3],305u_rr[i + 3])306for i in eachcomponent(equations))307rhok_avg = SVector{ncomponents(equations), real(equations)}(0.5f0 * (u_ll[i + 3] +308u_rr[i + 3])309for i in eachcomponent(equations))310311# Iterating over all partial densities312rho_ll = density(u_ll, equations)313rho_rr = density(u_rr, equations)314315# extract velocities316v1_ll = rho_v1_ll / rho_ll317v2_ll = rho_v2_ll / rho_ll318v1_rr = rho_v1_rr / rho_rr319v2_rr = rho_v2_rr / rho_rr320v1_avg = 0.5f0 * (v1_ll + v1_rr)321v2_avg = 0.5f0 * (v2_ll + v2_rr)322v1_square = 0.5f0 * (v1_ll^2 + v1_rr^2)323v2_square = 0.5f0 * (v2_ll^2 + v2_rr^2)324v_sum = v1_avg + v2_avg325326RealT = eltype(u_ll)327enth = zero(RealT)328help1_ll = zero(RealT)329help1_rr = zero(RealT)330331for i in eachcomponent(equations)332enth += rhok_avg[i] * gas_constants[i]333help1_ll += u_ll[i + 3] * cv[i]334help1_rr += u_rr[i + 3] * cv[i]335end336337T_ll = (rho_e_ll - 0.5f0 * rho_ll * (v1_ll^2 + v2_ll^2)) / help1_ll338T_rr = (rho_e_rr - 0.5f0 * rho_rr * (v1_rr^2 + v2_rr^2)) / help1_rr339T = 0.5f0 * (1 / T_ll + 1 / T_rr)340T_log = ln_mean(1 / T_ll, 1 / T_rr)341342# Calculate fluxes depending on orientation343help1 = zero(RealT)344help2 = zero(RealT)345if orientation == 1346f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * v1_avg347for i in eachcomponent(equations))348for i in eachcomponent(equations)349help1 += f_rho[i] * cv[i]350help2 += f_rho[i]351end352f1 = (help2) * v1_avg + enth / T353f2 = (help2) * v2_avg354f3 = (help1) / T_log - 0.5f0 * (v1_square + v2_square) * (help2) + v1_avg * f1 +355v2_avg * f2356else357f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * v2_avg358for i in eachcomponent(equations))359for i in eachcomponent(equations)360help1 += f_rho[i] * cv[i]361help2 += f_rho[i]362end363f1 = (help2) * v1_avg364f2 = (help2) * v2_avg + enth / T365f3 = (help1) / T_log - 0.5f0 * (v1_square + v2_square) * (help2) + v1_avg * f1 +366v2_avg * f2367end368f_other = SVector(f1, f2, f3)369370return vcat(f_other, f_rho)371end372373"""374flux_ranocha(u_ll, u_rr, orientation_or_normal_direction,375equations::CompressibleEulerMulticomponentEquations2D)376377Adaption of the entropy conserving and kinetic energy preserving two-point flux by378- Hendrik Ranocha (2018)379Generalised Summation-by-Parts Operators and Entropy Stability of Numerical Methods380for Hyperbolic Balance Laws381[PhD thesis, TU Braunschweig](https://cuvillier.de/en/shop/publications/7743)382See also383- Hendrik Ranocha (2020)384Entropy Conserving and Kinetic Energy Preserving Numerical Methods for385the Euler Equations Using Summation-by-Parts Operators386[Proceedings of ICOSAHOM 2018](https://doi.org/10.1007/978-3-030-39647-3_42)387"""388@inline function flux_ranocha(u_ll, u_rr, orientation::Integer,389equations::CompressibleEulerMulticomponentEquations2D)390# Unpack left and right state391@unpack gammas, gas_constants, cv = equations392rho_v1_ll, rho_v2_ll, rho_e_ll = u_ll393rho_v1_rr, rho_v2_rr, rho_e_rr = u_rr394rhok_mean = SVector{ncomponents(equations), real(equations)}(ln_mean(u_ll[i + 3],395u_rr[i + 3])396for i in eachcomponent(equations))397rhok_avg = SVector{ncomponents(equations), real(equations)}(0.5f0 * (u_ll[i + 3] +398u_rr[i + 3])399for i in eachcomponent(equations))400401# Iterating over all partial densities402rho_ll = density(u_ll, equations)403rho_rr = density(u_rr, equations)404405# Calculating gamma406gamma = totalgamma(0.5f0 * (u_ll + u_rr), equations)407inv_gamma_minus_one = 1 / (gamma - 1)408409# extract velocities410v1_ll = rho_v1_ll / rho_ll411v1_rr = rho_v1_rr / rho_rr412v1_avg = 0.5f0 * (v1_ll + v1_rr)413v2_ll = rho_v2_ll / rho_ll414v2_rr = rho_v2_rr / rho_rr415v2_avg = 0.5f0 * (v2_ll + v2_rr)416velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr)417418# helpful variables419RealT = eltype(u_ll)420help1_ll = zero(RealT)421help1_rr = zero(RealT)422enth_ll = zero(RealT)423enth_rr = zero(RealT)424for i in eachcomponent(equations)425enth_ll += u_ll[i + 3] * gas_constants[i]426enth_rr += u_rr[i + 3] * gas_constants[i]427help1_ll += u_ll[i + 3] * cv[i]428help1_rr += u_rr[i + 3] * cv[i]429end430431# temperature and pressure432T_ll = (rho_e_ll - 0.5f0 * rho_ll * (v1_ll^2 + v2_ll^2)) / help1_ll433T_rr = (rho_e_rr - 0.5f0 * rho_rr * (v1_rr^2 + v2_rr^2)) / help1_rr434p_ll = T_ll * enth_ll435p_rr = T_rr * enth_rr436p_avg = 0.5f0 * (p_ll + p_rr)437inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)438439f_rho_sum = zero(RealT)440if orientation == 1441f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * v1_avg442for i in eachcomponent(equations))443for i in eachcomponent(equations)444f_rho_sum += f_rho[i]445end446f1 = f_rho_sum * v1_avg + p_avg447f2 = f_rho_sum * v2_avg448f3 = f_rho_sum * (velocity_square_avg + inv_rho_p_mean * inv_gamma_minus_one) +4490.5f0 * (p_ll * v1_rr + p_rr * v1_ll)450else451f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * v2_avg452for i in eachcomponent(equations))453for i in eachcomponent(equations)454f_rho_sum += f_rho[i]455end456f1 = f_rho_sum * v1_avg457f2 = f_rho_sum * v2_avg + p_avg458f3 = f_rho_sum * (velocity_square_avg + inv_rho_p_mean * inv_gamma_minus_one) +4590.5f0 * (p_ll * v2_rr + p_rr * v2_ll)460end461462# momentum and energy flux463f_other = SVector(f1, f2, f3)464465return vcat(f_other, f_rho)466end467468@inline function flux_ranocha(u_ll, u_rr, normal_direction::AbstractVector,469equations::CompressibleEulerMulticomponentEquations2D)470# Unpack left and right state471@unpack gammas, gas_constants, cv = equations472rho_v1_ll, rho_v2_ll, rho_e_ll = u_ll473rho_v1_rr, rho_v2_rr, rho_e_rr = u_rr474rhok_mean = SVector{ncomponents(equations), real(equations)}(ln_mean(u_ll[i + 3],475u_rr[i + 3])476for i in eachcomponent(equations))477rhok_avg = SVector{ncomponents(equations), real(equations)}(0.5f0 * (u_ll[i + 3] +478u_rr[i + 3])479for i in eachcomponent(equations))480481# Iterating over all partial densities482rho_ll = density(u_ll, equations)483rho_rr = density(u_rr, equations)484485# Calculating gamma486gamma = totalgamma(0.5f0 * (u_ll + u_rr), equations)487inv_gamma_minus_one = 1 / (gamma - 1)488489# extract velocities490v1_ll = rho_v1_ll / rho_ll491v1_rr = rho_v1_rr / rho_rr492v1_avg = 0.5f0 * (v1_ll + v1_rr)493v2_ll = rho_v2_ll / rho_ll494v2_rr = rho_v2_rr / rho_rr495v2_avg = 0.5f0 * (v2_ll + v2_rr)496velocity_square_avg = 0.5f0 * (v1_ll * v1_rr + v2_ll * v2_rr)497v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]498v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]499500# helpful variables501RealT = eltype(u_ll)502help1_ll = zero(RealT)503help1_rr = zero(RealT)504enth_ll = zero(RealT)505enth_rr = zero(RealT)506for i in eachcomponent(equations)507enth_ll += u_ll[i + 3] * gas_constants[i]508enth_rr += u_rr[i + 3] * gas_constants[i]509help1_ll += u_ll[i + 3] * cv[i]510help1_rr += u_rr[i + 3] * cv[i]511end512513# temperature and pressure514T_ll = (rho_e_ll - 0.5f0 * rho_ll * (v1_ll^2 + v2_ll^2)) / help1_ll515T_rr = (rho_e_rr - 0.5f0 * rho_rr * (v1_rr^2 + v2_rr^2)) / help1_rr516p_ll = T_ll * enth_ll517p_rr = T_rr * enth_rr518p_avg = 0.5f0 * (p_ll + p_rr)519inv_rho_p_mean = p_ll * p_rr * inv_ln_mean(rho_ll * p_rr, rho_rr * p_ll)520521f_rho_sum = zero(RealT)522f_rho = SVector{ncomponents(equations), real(equations)}(rhok_mean[i] * 0.5f0 *523(v_dot_n_ll + v_dot_n_rr)524for i in eachcomponent(equations))525for i in eachcomponent(equations)526f_rho_sum += f_rho[i]527end528f1 = f_rho_sum * v1_avg + p_avg * normal_direction[1]529f2 = f_rho_sum * v2_avg + p_avg * normal_direction[2]530f3 = f_rho_sum * (velocity_square_avg + inv_rho_p_mean * inv_gamma_minus_one) +5310.5f0 * (p_ll * v_dot_n_rr + p_rr * v_dot_n_ll)532533# momentum and energy flux534f_other = SVector(f1, f2, f3)535536return vcat(f_other, f_rho)537end538539# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation540@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,541equations::CompressibleEulerMulticomponentEquations2D)542rho_v1_ll, rho_v2_ll, rho_e_ll = u_ll543rho_v1_rr, rho_v2_rr, rho_e_rr = u_rr544545# Get the density and gas gamma546rho_ll = density(u_ll, equations)547rho_rr = density(u_rr, equations)548gamma_ll = totalgamma(u_ll, equations)549gamma_rr = totalgamma(u_rr, equations)550551# Get the velocities based on direction552if orientation == 1553v_ll = rho_v1_ll / rho_ll554v_rr = rho_v1_rr / rho_rr555else # orientation == 2556v_ll = rho_v2_ll / rho_ll557v_rr = rho_v2_rr / rho_rr558end559560# Compute the sound speeds on the left and right561p_ll = (gamma_ll - 1) * (rho_e_ll - 0.5f0 * (rho_v1_ll^2 + rho_v2_ll^2) / rho_ll)562c_ll = sqrt(gamma_ll * p_ll / rho_ll)563p_rr = (gamma_rr - 1) * (rho_e_rr - 0.5f0 * (rho_v1_rr^2 + rho_v2_rr^2) / rho_rr)564c_rr = sqrt(gamma_rr * p_rr / rho_rr)565566return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr)567end568569# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`570@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,571equations::CompressibleEulerMulticomponentEquations2D)572rho_v1_ll, rho_v2_ll, rho_e_ll = u_ll573rho_v1_rr, rho_v2_rr, rho_e_rr = u_rr574575# Get the density and gas gamma576rho_ll = density(u_ll, equations)577rho_rr = density(u_rr, equations)578gamma_ll = totalgamma(u_ll, equations)579gamma_rr = totalgamma(u_rr, equations)580581# Get the velocities based on direction582if orientation == 1583v_ll = rho_v1_ll / rho_ll584v_rr = rho_v1_rr / rho_rr585else # orientation == 2586v_ll = rho_v2_ll / rho_ll587v_rr = rho_v2_rr / rho_rr588end589590# Compute the sound speeds on the left and right591p_ll = (gamma_ll - 1) * (rho_e_ll - 0.5f0 * (rho_v1_ll^2 + rho_v2_ll^2) / rho_ll)592c_ll = sqrt(gamma_ll * p_ll / rho_ll)593p_rr = (gamma_rr - 1) * (rho_e_rr - 0.5f0 * (rho_v1_rr^2 + rho_v2_rr^2) / rho_rr)594c_rr = sqrt(gamma_rr * p_rr / rho_rr)595596return max(abs(v_ll) + c_ll, abs(v_rr) + c_rr)597end598599@inline function max_abs_speeds(u,600equations::CompressibleEulerMulticomponentEquations2D)601rho_v1, rho_v2, rho_e = u602603rho = density(u, equations)604v1 = rho_v1 / rho605v2 = rho_v2 / rho606607gamma = totalgamma(u, equations)608p = (gamma - 1) * (rho_e - 0.5f0 * rho * (v1^2 + v2^2))609c = sqrt(gamma * p / rho)610611return (abs(v1) + c, abs(v2) + c)612end613614@inline function rotate_to_x(u, normal_vector,615equations::CompressibleEulerMulticomponentEquations2D)616# cos and sin of the angle between the x-axis and the normalized normal_vector are617# the normalized vector's x and y coordinates respectively (see unit circle).618c = normal_vector[1]619s = normal_vector[2]620621# Apply the 2D rotation matrix with normal and tangent directions of the form622# [ n_1 n_2 0 0;623# t_1 t_2 0 0;624# 0 0 1 0625# 0 0 0 1]626# where t_1 = -n_2 and t_2 = n_1627628densities = @view u[4:end]629return SVector(c * u[1] + s * u[2],630-s * u[1] + c * u[2],631u[3],632densities...)633end634635# Called inside `FluxRotated` in `numerical_fluxes.jl` so the direction636# has been normalized prior to this back-rotation of the state vector637@inline function rotate_from_x(u, normal_vector,638equations::CompressibleEulerMulticomponentEquations2D)639# cos and sin of the angle between the x-axis and the normalized normal_vector are640# the normalized vector's x and y coordinates respectively (see unit circle).641c = normal_vector[1]642s = normal_vector[2]643644# Apply the 2D back-rotation matrix with normal and tangent directions of the form645# [ n_1 t_1 0 0;646# n_2 t_2 0 0;647# 0 0 1 0;648# 0 0 0 1 ]649# where t_1 = -n_2 and t_2 = n_1650651densities = @view u[4:end]652return SVector(c * u[1] - s * u[2],653s * u[1] + c * u[2],654u[3],655densities...)656end657658# Convert conservative variables to primitive659@inline function cons2prim(u, equations::CompressibleEulerMulticomponentEquations2D)660rho_v1, rho_v2, rho_e = u661662prim_rho = SVector{ncomponents(equations), real(equations)}(u[i + 3]663for i in eachcomponent(equations))664665rho = density(u, equations)666v1 = rho_v1 / rho667v2 = rho_v2 / rho668gamma = totalgamma(u, equations)669p = (gamma - 1) * (rho_e - 0.5f0 * rho * (v1^2 + v2^2))670prim_other = SVector(v1, v2, p)671672return vcat(prim_other, prim_rho)673end674675# Convert conservative variables to entropy676@inline function cons2entropy(u, equations::CompressibleEulerMulticomponentEquations2D)677@unpack cv, gammas, gas_constants = equations678rho_v1, rho_v2, rho_e = u679680rho = density(u, equations)681682# Multicomponent stuff683RealT = eltype(u)684help1 = zero(RealT)685gas_constant = zero(RealT)686for i in eachcomponent(equations)687help1 += u[i + 3] * cv[i]688gas_constant += gas_constants[i] * (u[i + 3] / rho)689end690691v1 = rho_v1 / rho692v2 = rho_v2 / rho693v_square = v1^2 + v2^2694gamma = totalgamma(u, equations)695696p = (gamma - 1) * (rho_e - 0.5f0 * rho * v_square)697s = log(p) - gamma * log(rho) - log(gas_constant)698rho_p = rho / p699T = (rho_e - 0.5f0 * rho * v_square) / (help1)700701entrop_rho = SVector{ncomponents(equations), real(equations)}((cv[i] *702(1 - log(T)) +703gas_constants[i] *704(1 + log(u[i + 3])) -705v_square / (2 * T))706for i in eachcomponent(equations))707708w1 = gas_constant * v1 * rho_p709w2 = gas_constant * v2 * rho_p710w3 = gas_constant * (-rho_p)711712entrop_other = SVector(w1, w2, w3)713714return vcat(entrop_other, entrop_rho)715end716717# Convert entropy variables to conservative variables718@inline function entropy2cons(w, equations::CompressibleEulerMulticomponentEquations2D)719@unpack gammas, gas_constants, cp, cv = equations720T = -1 / w[3]721v1 = w[1] * T722v2 = w[2] * T723v_squared = v1^2 + v2^2724cons_rho = SVector{ncomponents(equations), real(equations)}(exp((w[i + 3] -725cv[i] *726(1 - log(T)) +727v_squared /728(2 * T)) /729gas_constants[i] -7301)731for i in eachcomponent(equations))732733RealT = eltype(w)734rho = zero(RealT)735help1 = zero(RealT)736help2 = zero(RealT)737p = zero(RealT)738for i in eachcomponent(equations)739rho += cons_rho[i]740help1 += cons_rho[i] * cv[i] * gammas[i]741help2 += cons_rho[i] * cv[i]742p += cons_rho[i] * gas_constants[i] * T743end744u1 = rho * v1745u2 = rho * v2746gamma = help1 / help2747u3 = p / (gamma - 1) + 0.5f0 * rho * v_squared748cons_other = SVector(u1, u2, u3)749return vcat(cons_other, cons_rho)750end751752# Convert primitive to conservative variables753@inline function prim2cons(prim, equations::CompressibleEulerMulticomponentEquations2D)754@unpack cv, gammas = equations755v1, v2, p = prim756757cons_rho = SVector{ncomponents(equations), real(equations)}(prim[i + 3]758for i in eachcomponent(equations))759rho = density(prim, equations)760gamma = totalgamma(prim, equations)761762rho_v1 = rho * v1763rho_v2 = rho * v2764rho_e = p / (gamma - 1) + 0.5f0 * (rho_v1 * v1 + rho_v2 * v2)765766cons_other = SVector(rho_v1, rho_v2, rho_e)767768return vcat(cons_other, cons_rho)769end770771@inline function total_entropy(u, equations::CompressibleEulerMulticomponentEquations2D)772@unpack cv, gammas, gas_constants = equations773rho = density(u, equations)774T = temperature(u, equations)775776RealT = eltype(u)777total_entropy = zero(RealT)778for i in eachcomponent(equations)779total_entropy -= u[i + 3] * (cv[i] * log(T) - gas_constants[i] * log(u[i + 3]))780end781782return total_entropy783end784785@inline function temperature(u, equations::CompressibleEulerMulticomponentEquations2D)786@unpack cv, gammas, gas_constants = equations787788rho_v1, rho_v2, rho_e = u789790rho = density(u, equations)791RealT = eltype(u)792help1 = zero(RealT)793794for i in eachcomponent(equations)795help1 += u[i + 3] * cv[i]796end797798v1 = rho_v1 / rho799v2 = rho_v2 / rho800v_square = v1^2 + v2^2801T = (rho_e - 0.5f0 * rho * v_square) / help1802803return T804end805806"""807totalgamma(u, equations::CompressibleEulerMulticomponentEquations2D)808809Function that calculates the total gamma out of all partial gammas using the810partial density fractions as well as the partial specific heats at constant volume.811"""812@inline function totalgamma(u, equations::CompressibleEulerMulticomponentEquations2D)813@unpack cv, gammas = equations814815RealT = eltype(u)816help1 = zero(RealT)817help2 = zero(RealT)818819for i in eachcomponent(equations)820help1 += u[i + 3] * cv[i] * gammas[i]821help2 += u[i + 3] * cv[i]822end823824return help1 / help2825end826827@inline function density_pressure(u,828equations::CompressibleEulerMulticomponentEquations2D)829rho_v1, rho_v2, rho_e = u830831rho = density(u, equations)832gamma = totalgamma(u, equations)833rho_times_p = (gamma - 1) * (rho * rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2))834835return rho_times_p836end837838@inline function density(u, equations::CompressibleEulerMulticomponentEquations2D)839RealT = eltype(u)840rho = zero(RealT)841842for i in eachcomponent(equations)843rho += u[i + 3]844end845846return rho847end848849@inline function densities(u, v, equations::CompressibleEulerMulticomponentEquations2D)850return SVector{ncomponents(equations), real(equations)}(u[i + 3] * v851for i in eachcomponent(equations))852end853854@inline function velocity(u, equations::CompressibleEulerMulticomponentEquations2D)855rho = density(u, equations)856v1 = u[1] / rho857v2 = u[2] / rho858return SVector(v1, v2)859end860861@inline function velocity(u, orientation::Int,862equations::CompressibleEulerMulticomponentEquations2D)863rho = density(u, equations)864v = u[orientation] / rho865return v866end867end # @muladd868869870