Path: blob/main/src/equations/polytropic_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"""8PolytropicEulerEquations2D(gamma, kappa)910The polytropic Euler equations11```math12\frac{\partial}{\partial t}13\begin{pmatrix}14\rho \\ \rho v_1 \\ \rho v_215\end{pmatrix}16+17\frac{\partial}{\partial x}18\begin{pmatrix}19\rho v_1 \\ \rho v_1^2 + \kappa\rho^\gamma \\ \rho v_1 v_220\end{pmatrix}21+22\frac{\partial}{\partial y}23\begin{pmatrix}24\rho v_2 \\ \rho v_1 v_2 \\ \rho v_2^2 + \kappa\rho^\gamma25\end{pmatrix}26=27\begin{pmatrix}280 \\ 0 \\ 029\end{pmatrix}30```31for an ideal gas with ratio of specific heats `gamma`32in two space dimensions.33Here, ``\rho`` is the density and ``v_1`` and`v_2` the velocities and34```math35p = \kappa\rho^\gamma36```37the pressure, which we replaced using this relation.38"""39struct PolytropicEulerEquations2D{RealT <: Real} <:40AbstractPolytropicEulerEquations{2, 3}41gamma::RealT # ratio of specific heats42kappa::RealT # fluid scaling factor4344function PolytropicEulerEquations2D(gamma, kappa)45gamma_, kappa_ = promote(gamma, kappa)46new{typeof(gamma_)}(gamma_, kappa_)47end48end4950function varnames(::typeof(cons2cons), ::PolytropicEulerEquations2D)51("rho", "rho_v1", "rho_v2")52end53varnames(::typeof(cons2prim), ::PolytropicEulerEquations2D) = ("rho", "v1", "v2")5455"""56initial_condition_convergence_test(x, t, equations::PolytropicEulerEquations2D)5758Manufactured smooth initial condition used for convergence tests59in combination with [`source_terms_convergence_test`](@ref).60"""61function initial_condition_convergence_test(x, t, equations::PolytropicEulerEquations2D)62# manufactured initial condition from Winters (2019) [0.1007/s10543-019-00789-w]63# domain must be set to [0, 1] x [0, 1]64h = 8 + cospi(2 * x[1]) * sinpi(2 * x[2]) * cospi(2 * t)6566return SVector(h, h / 2, 3 * h / 2)67end6869"""70source_terms_convergence_test(u, x, t, equations::PolytropicEulerEquations2D)7172Source terms used for convergence tests in combination with73[`initial_condition_convergence_test`](@ref).74"""75@inline function source_terms_convergence_test(u, x, t,76equations::PolytropicEulerEquations2D)77# Residual from Winters (2019) [0.1007/s10543-019-00789-w] eq. (5.2).78RealT = eltype(u)79h = 8 + cospi(2 * x[1]) * sinpi(2 * x[2]) * cospi(2 * t)80h_t = -2 * convert(RealT, pi) * cospi(2 * x[1]) * sinpi(2 * x[2]) * sinpi(2 * t)81h_x = -2 * convert(RealT, pi) * sinpi(2 * x[1]) * sinpi(2 * x[2]) * cospi(2 * t)82h_y = 2 * convert(RealT, pi) * cospi(2 * x[1]) * cospi(2 * x[2]) * cospi(2 * t)8384rho_x = h_x85rho_y = h_y8687b = equations.kappa * equations.gamma * h^(equations.gamma - 1)8889r_1 = h_t + h_x / 2 + 3 * h_y / 290r_2 = h_t / 2 + h_x / 4 + b * rho_x + 3 * h_y / 491r_3 = 3 * h_t / 2 + 3 * h_x / 4 + 9 * h_y / 4 + b * rho_y9293return SVector(r_1, r_2, r_3)94end9596"""97initial_condition_weak_blast_wave(x, t, equations::PolytropicEulerEquations2D)9899A weak blast wave adapted from100- Sebastian Hennemann, Gregor J. Gassner (2020)101A provably entropy stable subcell shock capturing approach for high order split form DG102[arXiv: 2008.12044](https://arxiv.org/abs/2008.12044)103"""104function initial_condition_weak_blast_wave(x, t, equations::PolytropicEulerEquations2D)105# Adapted MHD version of the weak blast wave from Hennemann & Gassner JCP paper 2020 (Sec. 6.3)106# Set up polar coordinates107inicenter = (0, 0)108x_norm = x[1] - inicenter[1]109y_norm = x[2] - inicenter[2]110r = sqrt(x_norm^2 + y_norm^2)111phi = atan(y_norm, x_norm)112113# Calculate primitive variables114RealT = eltype(x)115rho = r > 0.5f0 ? one(RealT) : convert(RealT, 1.1691)116v1 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * cos(phi)117v2 = r > 0.5f0 ? zero(RealT) : convert(RealT, 0.1882) * sin(phi)118119return prim2cons(SVector(rho, v1, v2), equations)120end121122# Calculate 1D flux for a single point in the normal direction123# Note, this directional vector is not normalized124@inline function flux(u, normal_direction::AbstractVector,125equations::PolytropicEulerEquations2D)126rho, v1, v2 = cons2prim(u, equations)127p = pressure(u, equations)128129v_normal = v1 * normal_direction[1] + v2 * normal_direction[2]130rho_v_normal = rho * v_normal131f1 = rho_v_normal132f2 = rho_v_normal * v1 + p * normal_direction[1]133f3 = rho_v_normal * v2 + p * normal_direction[2]134return SVector(f1, f2, f3)135end136137# Calculate 1D flux for a single point138@inline function flux(u, orientation::Integer, equations::PolytropicEulerEquations2D)139_, v1, v2 = cons2prim(u, equations)140p = pressure(u, equations)141142rho_v1 = u[2]143rho_v2 = u[3]144145if orientation == 1146f1 = rho_v1147f2 = rho_v1 * v1 + p148f3 = rho_v1 * v2149else150f1 = rho_v2151f2 = rho_v2 * v1152f3 = rho_v2 * v2 + p153end154return SVector(f1, f2, f3)155end156157"""158flux_winters_etal(u_ll, u_rr, orientation_or_normal_direction,159equations::PolytropicEulerEquations2D)160161Entropy conserving two-point flux for isothermal or polytropic gases.162Requires a special weighted Stolarsky mean for the evaluation of the density163denoted here as `stolarsky_mean`. Note, for isothermal gases where `gamma = 1`164this `stolarsky_mean` becomes the [`ln_mean`](@ref).165166For details see Section 3.2 of the following reference167- Andrew R. Winters, Christof Czernik, Moritz B. Schily & Gregor J. Gassner (2020)168Entropy stable numerical approximations for the isothermal and polytropic169Euler equations170[DOI: 10.1007/s10543-019-00789-w](https://doi.org/10.1007/s10543-019-00789-w)171"""172@inline function flux_winters_etal(u_ll, u_rr, normal_direction::AbstractVector,173equations::PolytropicEulerEquations2D)174# Unpack left and right state175rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations)176rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations)177p_ll = equations.kappa * rho_ll^equations.gamma178p_rr = equations.kappa * rho_rr^equations.gamma179v_dot_n_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]180v_dot_n_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]181182# Compute the necessary mean values183if equations.gamma == 1 # isothermal gas184rho_mean = ln_mean(rho_ll, rho_rr)185else # equations.gamma > 1 # polytropic gas186rho_mean = stolarsky_mean(rho_ll, rho_rr, equations.gamma)187end188v1_avg = 0.5f0 * (v1_ll + v1_rr)189v2_avg = 0.5f0 * (v2_ll + v2_rr)190p_avg = 0.5f0 * (p_ll + p_rr)191192# Calculate fluxes depending on normal_direction193f1 = rho_mean * 0.5f0 * (v_dot_n_ll + v_dot_n_rr)194f2 = f1 * v1_avg + p_avg * normal_direction[1]195f3 = f1 * v2_avg + p_avg * normal_direction[2]196197return SVector(f1, f2, f3)198end199200@inline function flux_winters_etal(u_ll, u_rr, orientation::Integer,201equations::PolytropicEulerEquations2D)202# Unpack left and right state203rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations)204rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations)205p_ll = equations.kappa * rho_ll^equations.gamma206p_rr = equations.kappa * rho_rr^equations.gamma207208# Compute the necessary mean values209if equations.gamma == 1 # isothermal gas210rho_mean = ln_mean(rho_ll, rho_rr)211else # equations.gamma > 1 # polytropic gas212rho_mean = stolarsky_mean(rho_ll, rho_rr, equations.gamma)213end214v1_avg = 0.5f0 * (v1_ll + v1_rr)215v2_avg = 0.5f0 * (v2_ll + v2_rr)216p_avg = 0.5f0 * (p_ll + p_rr)217218if orientation == 1 # x-direction219f1 = rho_mean * 0.5f0 * (v1_ll + v1_rr)220f2 = f1 * v1_avg + p_avg221f3 = f1 * v2_avg222else # y-direction223f1 = rho_mean * 0.5f0 * (v2_ll + v2_rr)224f2 = f1 * v1_avg225f3 = f1 * v2_avg + p_avg226end227228return SVector(f1, f2, f3)229end230231@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,232equations::PolytropicEulerEquations2D)233rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations)234rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations)235p_ll = equations.kappa * rho_ll^equations.gamma236p_rr = equations.kappa * rho_rr^equations.gamma237238v_normal_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]239v_normal_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]240241norm_ = norm(normal_direction)242# The v_normals are already scaled by the norm243lambda_min = v_normal_ll - sqrt(equations.gamma * p_ll / rho_ll) * norm_244lambda_max = v_normal_rr + sqrt(equations.gamma * p_rr / rho_rr) * norm_245246return lambda_min, lambda_max247end248249# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes250@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer,251equations::PolytropicEulerEquations2D)252rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations)253rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations)254# Pressure for polytropic Euler255p_ll = equations.kappa * rho_ll^equations.gamma256p_rr = equations.kappa * rho_rr^equations.gamma257258c_ll = sqrt(equations.gamma * p_ll / rho_ll)259c_rr = sqrt(equations.gamma * p_rr / rho_rr)260261if orientation == 1 # x-direction262λ_min = min(v1_ll - c_ll, v1_rr - c_rr)263λ_max = max(v1_ll + c_ll, v1_rr + c_rr)264else # y-direction265λ_min = min(v2_ll - c_ll, v2_rr - c_rr)266λ_max = max(v2_ll + c_ll, v2_rr + c_rr)267end268269return λ_min, λ_max270end271272# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes273@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector,274equations::PolytropicEulerEquations2D)275rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations)276rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations)277# Pressure for polytropic Euler278p_ll = equations.kappa * rho_ll^equations.gamma279p_rr = equations.kappa * rho_rr^equations.gamma280281norm_ = norm(normal_direction)282283c_ll = sqrt(equations.gamma * p_ll / rho_ll) * norm_284c_rr = sqrt(equations.gamma * p_rr / rho_rr) * norm_285286v_normal_ll = v1_ll * normal_direction[1] + v2_ll * normal_direction[2]287v_normal_rr = v1_rr * normal_direction[1] + v2_rr * normal_direction[2]288289# The v_normals are already scaled by the norm290λ_min = min(v_normal_ll - c_ll, v_normal_rr - c_rr)291λ_max = max(v_normal_ll + c_ll, v_normal_rr + c_rr)292293return λ_min, λ_max294end295296@inline function max_abs_speeds(u, equations::PolytropicEulerEquations2D)297rho, v1, v2 = cons2prim(u, equations)298c = sqrt(equations.gamma * equations.kappa * rho^(equations.gamma - 1))299300return abs(v1) + c, abs(v2) + c301end302303# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation as the304# maximum velocity magnitude plus the maximum speed of sound305@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,306equations::PolytropicEulerEquations2D)307rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations)308rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations)309310# Get the velocity value in the appropriate direction311if orientation == 1312v_ll = v1_ll313v_rr = v1_rr314else # orientation == 2315v_ll = v2_ll316v_rr = v2_rr317end318# Calculate sound speeds (we have p = kappa * rho^gamma)319c_ll = sqrt(equations.gamma * equations.kappa * rho_ll^(equations.gamma - 1))320c_rr = sqrt(equations.gamma * equations.kappa * rho_rr^(equations.gamma - 1))321322return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr)323end324325@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,326equations::PolytropicEulerEquations2D)327rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations)328rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations)329330# Calculate normal velocities and sound speed (we have p = kappa * rho^gamma)331# left332v_ll = (v1_ll * normal_direction[1] +333v2_ll * normal_direction[2])334c_ll = sqrt(equations.gamma * equations.kappa * rho_ll^(equations.gamma - 1))335# right336v_rr = (v1_rr * normal_direction[1] +337v2_rr * normal_direction[2])338c_rr = sqrt(equations.gamma * equations.kappa * rho_rr^(equations.gamma - 1))339340return max(abs(v_ll), abs(v_rr)) + max(c_ll, c_rr) * norm(normal_direction)341end342343# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`344@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,345equations::PolytropicEulerEquations2D)346rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations)347rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations)348349# Get the velocity value in the appropriate direction350if orientation == 1351v_ll = v1_ll352v_rr = v1_rr353else # orientation == 2354v_ll = v2_ll355v_rr = v2_rr356end357# Calculate sound speeds (we have p = kappa * rho^gamma)358c_ll = sqrt(equations.gamma * equations.kappa * rho_ll^(equations.gamma - 1))359c_rr = sqrt(equations.gamma * equations.kappa * rho_rr^(equations.gamma - 1))360361return max(abs(v_ll) + c_ll, abs(v_rr) + c_rr)362end363364# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`365@inline function max_abs_speed(u_ll, u_rr, normal_direction::AbstractVector,366equations::PolytropicEulerEquations2D)367rho_ll, v1_ll, v2_ll = cons2prim(u_ll, equations)368rho_rr, v1_rr, v2_rr = cons2prim(u_rr, equations)369370# Calculate normal velocities and sound speed (we have p = kappa * rho^gamma)371# left372v_ll = (v1_ll * normal_direction[1] +373v2_ll * normal_direction[2])374c_ll = sqrt(equations.gamma * equations.kappa * rho_ll^(equations.gamma - 1))375# right376v_rr = (v1_rr * normal_direction[1] +377v2_rr * normal_direction[2])378c_rr = sqrt(equations.gamma * equations.kappa * rho_rr^(equations.gamma - 1))379380norm_ = norm(normal_direction)381return max(abs(v_ll) + c_ll * norm_, abs(v_rr) + c_rr * norm_)382end383384# Convert conservative variables to primitive385@inline function cons2prim(u, equations::PolytropicEulerEquations2D)386rho, rho_v1, rho_v2 = u387388v1 = rho_v1 / rho389v2 = rho_v2 / rho390391return SVector(rho, v1, v2)392end393394# Convert conservative variables to entropy395@inline function cons2entropy(u, equations::PolytropicEulerEquations2D)396rho, rho_v1, rho_v2 = u397398v1 = rho_v1 / rho399v2 = rho_v2 / rho400v_square = v1^2 + v2^2401p = pressure(u, equations)402# Form of the internal energy depends on gas type403if equations.gamma == 1 # isothermal gas404internal_energy = equations.kappa * log(rho)405else # equations.gamma > 1 # polytropic gas406internal_energy = equations.kappa * rho^(equations.gamma - 1) /407(equations.gamma - 1)408end409410w1 = internal_energy + p / rho - 0.5f0 * v_square411w2 = v1412w3 = v2413414return SVector(w1, w2, w3)415end416417# Convert primitive to conservative variables418@inline function prim2cons(prim, equations::PolytropicEulerEquations2D)419rho, v1, v2 = prim420rho_v1 = rho * v1421rho_v2 = rho * v2422return SVector(rho, rho_v1, rho_v2)423end424425@inline function density(u, equations::PolytropicEulerEquations2D)426rho = u[1]427return rho428end429430@inline function velocity(u, equations::PolytropicEulerEquations2D)431rho = u[1]432v1 = u[2] / rho433v2 = u[3] / rho434return SVector(v1, v2)435end436437@inline function velocity(u, orientation::Int, equations::PolytropicEulerEquations2D)438rho = u[1]439v = u[orientation + 1] / rho440return v441end442443@inline function pressure(u, equations::PolytropicEulerEquations2D)444rho, _, _ = u445p = equations.kappa * rho^equations.gamma446return p447end448end # @muladd449450451