Path: blob/main/src/equations/acoustic_perturbation_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"""8AcousticPerturbationEquations2D(v_mean_global, c_mean_global, rho_mean_global)910Acoustic perturbation equations (APE) in two space dimensions. The equations are given by11```math12\begin{aligned}13\frac{\partial\mathbf{v'}}{\partial t} + \nabla (\bar{\mathbf{v}}\cdot\mathbf{v'})14+ \nabla\left( \frac{\bar{c}^2 \tilde{p}'}{\bar{\rho}} \right) &= 0 \\15\frac{\partial \tilde{p}'}{\partial t} +16\nabla\cdot (\bar{\rho} \mathbf{v'} + \bar{\mathbf{v}} \tilde{p}') &= 0.17\end{aligned}18```19The bar ``\bar{(\cdot)}`` indicates time-averaged quantities. The unknowns of the APE are the20perturbed velocities ``\mathbf{v'} = (v_1', v_2')^T`` and the scaled perturbed pressure21``\tilde{p}' = \frac{p'}{\bar{c}^2}``, where ``p'`` denotes the perturbed pressure and the22perturbed variables are defined by ``\phi' = \phi - \bar{\phi}``.2324In addition to the unknowns, Trixi.jl currently stores the mean values in the state vector,25i.e. the state vector used internally is given by26```math27\mathbf{u} =28\begin{pmatrix}29v_1' \\ v_2' \\ \tilde{p}' \\ \bar{v}_1 \\ \bar{v}_2 \\ \bar{c} \\ \bar{\rho}30\end{pmatrix}.31```32This affects the implementation and use of these equations in various ways:33* The flux values corresponding to the mean values must be zero.34* The mean values have to be considered when defining initial conditions, boundary conditions or35source terms.36* [`AnalysisCallback`](@ref) analyzes these variables too.37* Trixi.jl's visualization tools will visualize the mean values by default.3839The constructor accepts a 2-tuple `v_mean_global` and scalars `c_mean_global` and `rho_mean_global`40which can be used to make the definition of initial conditions for problems with constant mean flow41more flexible. These values are ignored if the mean values are defined internally in an initial42condition.4344The equations are based on the APE-4 system introduced in the following paper:45- Roland Ewert and Wolfgang Schröder (2003)46Acoustic perturbation equations based on flow decomposition via source filtering47[DOI: 10.1016/S0021-9991(03)00168-2](https://doi.org/10.1016/S0021-9991(03)00168-2)48"""49struct AcousticPerturbationEquations2D{RealT <: Real} <:50AbstractAcousticPerturbationEquations{2, 7}51v_mean_global::SVector{2, RealT}52c_mean_global::RealT53rho_mean_global::RealT54end5556function AcousticPerturbationEquations2D(v_mean_global::NTuple{2, <:Real},57c_mean_global::Real,58rho_mean_global::Real)59return AcousticPerturbationEquations2D(SVector(v_mean_global), c_mean_global,60rho_mean_global)61end6263function AcousticPerturbationEquations2D(; v_mean_global::NTuple{2, <:Real},64c_mean_global::Real,65rho_mean_global::Real)66return AcousticPerturbationEquations2D(SVector(v_mean_global), c_mean_global,67rho_mean_global)68end6970function varnames(::typeof(cons2cons), ::AcousticPerturbationEquations2D)71("v1_prime", "v2_prime", "p_prime_scaled",72"v1_mean", "v2_mean", "c_mean", "rho_mean")73end74function varnames(::typeof(cons2prim), ::AcousticPerturbationEquations2D)75("v1_prime", "v2_prime", "p_prime",76"v1_mean", "v2_mean", "c_mean", "rho_mean")77end7879# Convenience functions for retrieving state variables and mean variables80function cons2state(u, equations::AcousticPerturbationEquations2D)81return SVector(u[1], u[2], u[3])82end8384function cons2mean(u, equations::AcousticPerturbationEquations2D)85return SVector(u[4], u[5], u[6], u[7])86end8788function varnames(::typeof(cons2state), ::AcousticPerturbationEquations2D)89("v1_prime", "v2_prime", "p_prime_scaled")90end91function varnames(::typeof(cons2mean), ::AcousticPerturbationEquations2D)92("v1_mean", "v2_mean", "c_mean", "rho_mean")93end9495"""96global_mean_vars(equations::AcousticPerturbationEquations2D)9798Returns the global mean variables stored in `equations`. This makes it easier99to define flexible initial conditions for problems with constant mean flow.100"""101function global_mean_vars(equations::AcousticPerturbationEquations2D)102return equations.v_mean_global[1], equations.v_mean_global[2],103equations.c_mean_global,104equations.rho_mean_global105end106107"""108initial_condition_constant(x, t, equations::AcousticPerturbationEquations2D)109110A constant initial condition where the state variables are zero and the mean flow is constant.111Uses the global mean values from `equations`.112"""113function initial_condition_constant(x, t, equations::AcousticPerturbationEquations2D)114v1_prime = 0115v2_prime = 0116p_prime_scaled = 0117118return SVector(v1_prime, v2_prime, p_prime_scaled, global_mean_vars(equations)...)119end120121"""122initial_condition_convergence_test(x, t, equations::AcousticPerturbationEquations2D)123124A smooth initial condition used for convergence tests in combination with125[`source_terms_convergence_test`](@ref). Uses the global mean values from `equations`.126"""127function initial_condition_convergence_test(x, t,128equations::AcousticPerturbationEquations2D)129RealT = eltype(x)130a = 1131c = 2132L = 2133f = 2.0f0 / L134A = convert(RealT, 0.2)135omega = 2 * convert(RealT, pi) * f136init = c + A * sin(omega * (x[1] + x[2] - a * t))137138v1_prime = init139v2_prime = init140p_prime = init^2141142prim = SVector(v1_prime, v2_prime, p_prime, global_mean_vars(equations)...)143144return prim2cons(prim, equations)145end146147"""148source_terms_convergence_test(u, x, t, equations::AcousticPerturbationEquations2D)149150Source terms used for convergence tests in combination with151[`initial_condition_convergence_test`](@ref).152"""153function source_terms_convergence_test(u, x, t,154equations::AcousticPerturbationEquations2D)155v1_mean, v2_mean, c_mean, rho_mean = cons2mean(u, equations)156157RealT = eltype(u)158a = 1159c = 2160L = 2161f = 2.0f0 / L162A = convert(RealT, 0.2)163omega = 2 * convert(RealT, pi) * f164165si, co = sincos(omega * (x[1] + x[2] - a * t))166tmp = v1_mean + v2_mean - a167168du1 = du2 = A * omega * co * (2 * c / rho_mean + tmp + 2 / rho_mean * A * si)169du3 = A * omega * co * (2 * c_mean^2 * rho_mean + 2 * c * tmp + 2 * A * tmp * si) /170c_mean^2171172du4 = du5 = du6 = du7 = 0173174return SVector(du1, du2, du3, du4, du5, du6, du7)175end176177"""178initial_condition_gauss(x, t, equations::AcousticPerturbationEquations2D)179180A Gaussian pulse in a constant mean flow. Uses the global mean values from `equations`.181"""182function initial_condition_gauss(x, t, equations::AcousticPerturbationEquations2D)183v1_prime = 0184v2_prime = 0185p_prime = exp(-4 * (x[1]^2 + x[2]^2))186187prim = SVector(v1_prime, v2_prime, p_prime, global_mean_vars(equations)...)188189return prim2cons(prim, equations)190end191192"""193boundary_condition_wall(u_inner, orientation, direction, x, t, surface_flux_function,194equations::AcousticPerturbationEquations2D)195196Boundary conditions for a solid wall.197"""198function boundary_condition_wall(u_inner, orientation, direction, x, t,199surface_flux_function,200equations::AcousticPerturbationEquations2D)201# Boundary state is equal to the inner state except for the perturbed velocity. For boundaries202# in the -x/+x direction, we multiply the perturbed velocity in the x direction by -1.203# Similarly, for boundaries in the -y/+y direction, we multiply the perturbed velocity in the204# y direction by -1205if direction in (1, 2) # x direction206u_boundary = SVector(-u_inner[1], u_inner[2], u_inner[3],207cons2mean(u_inner, equations)...)208else # y direction209u_boundary = SVector(u_inner[1], -u_inner[2], u_inner[3],210cons2mean(u_inner, equations)...)211end212213# Calculate boundary flux214if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary215flux = surface_flux_function(u_inner, u_boundary, orientation, equations)216else # u_boundary is "left" of boundary, u_inner is "right" of boundary217flux = surface_flux_function(u_boundary, u_inner, orientation, equations)218end219220return flux221end222223"""224boundary_condition_slip_wall(u_inner, normal_direction, x, t, surface_flux_function,225equations::AcousticPerturbationEquations2D)226227Use an orthogonal projection of the perturbed velocities to zero out the normal velocity228while retaining the possibility of a tangential velocity in the boundary state.229Further details are available in the paper:230- Marcus Bauer, Jürgen Dierke and Roland Ewert (2011)231Application of a discontinuous Galerkin method to discretize acoustic perturbation equations232[DOI: 10.2514/1.J050333](https://doi.org/10.2514/1.J050333)233"""234function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t,235surface_flux_function,236equations::AcousticPerturbationEquations2D)237# normalize the outward pointing direction238normal = normal_direction / norm(normal_direction)239240# compute the normal perturbed velocity241u_normal = normal[1] * u_inner[1] + normal[2] * u_inner[2]242243# create the "external" boundary solution state244u_boundary = SVector(u_inner[1] - 2 * u_normal * normal[1],245u_inner[2] - 2 * u_normal * normal[2],246u_inner[3], cons2mean(u_inner, equations)...)247248# calculate the boundary flux249flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations)250251return flux252end253254# Calculate 1D flux for a single point255@inline function flux(u, orientation::Integer,256equations::AcousticPerturbationEquations2D)257v1_prime, v2_prime, p_prime_scaled = cons2state(u, equations)258v1_mean, v2_mean, c_mean, rho_mean = cons2mean(u, equations)259260# Calculate flux for conservative state variables261RealT = eltype(u)262if orientation == 1263f1 = v1_mean * v1_prime + v2_mean * v2_prime +264c_mean^2 * p_prime_scaled / rho_mean265f2 = zero(RealT)266f3 = rho_mean * v1_prime + v1_mean * p_prime_scaled267else268f1 = zero(RealT)269f2 = v1_mean * v1_prime + v2_mean * v2_prime +270c_mean^2 * p_prime_scaled / rho_mean271f3 = rho_mean * v2_prime + v2_mean * p_prime_scaled272end273274# The rest of the state variables are actually variable coefficients, hence the flux should be275# zero. See https://github.com/trixi-framework/Trixi.jl/issues/358#issuecomment-784828762276# for details.277f4 = f5 = f6 = f7 = 0278279return SVector(f1, f2, f3, f4, f5, f6, f7)280end281282# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation283@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,284equations::AcousticPerturbationEquations2D)285# Calculate v = v_prime + v_mean286v_prime_ll = u_ll[orientation]287v_prime_rr = u_rr[orientation]288v_mean_ll = u_ll[orientation + 3]289v_mean_rr = u_rr[orientation + 3]290291v_ll = v_prime_ll + v_mean_ll292v_rr = v_prime_rr + v_mean_rr293294c_mean_ll = u_ll[6]295c_mean_rr = u_rr[6]296297return max(abs(v_ll), abs(v_rr)) + max(c_mean_ll, c_mean_rr)298end299300# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`301@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,302equations::AcousticPerturbationEquations2D)303# Calculate v = v_prime + v_mean304v_prime_ll = u_ll[orientation]305v_prime_rr = u_rr[orientation]306v_mean_ll = u_ll[orientation + 3]307v_mean_rr = u_rr[orientation + 3]308309v_ll = v_prime_ll + v_mean_ll310v_rr = v_prime_rr + v_mean_rr311312c_mean_ll = u_ll[6]313c_mean_rr = u_rr[6]314315return max(abs(v_ll) + c_mean_ll, abs(v_rr) + c_mean_rr)316end317318# Calculate 1D flux for a single point in the normal direction319# Note, this directional vector is not normalized320@inline function flux(u, normal_direction::AbstractVector,321equations::AcousticPerturbationEquations2D)322v1_prime, v2_prime, p_prime_scaled = cons2state(u, equations)323v1_mean, v2_mean, c_mean, rho_mean = cons2mean(u, equations)324325f1 = normal_direction[1] * (v1_mean * v1_prime + v2_mean * v2_prime +326c_mean^2 * p_prime_scaled / rho_mean)327f2 = normal_direction[2] * (v1_mean * v1_prime + v2_mean * v2_prime +328c_mean^2 * p_prime_scaled / rho_mean)329f3 = (normal_direction[1] * (rho_mean * v1_prime + v1_mean * p_prime_scaled)330+331normal_direction[2] * (rho_mean * v2_prime + v2_mean * p_prime_scaled))332333# The rest of the state variables are actually variable coefficients, hence the flux should be334# zero. See https://github.com/trixi-framework/Trixi.jl/issues/358#issuecomment-784828762335# for details.336f4 = f5 = f6 = f7 = 0337338return SVector(f1, f2, f3, f4, f5, f6, f7)339end340341# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation342@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,343equations::AcousticPerturbationEquations2D)344# Calculate v = v_prime + v_mean345v_prime_ll = normal_direction[1] * u_ll[1] + normal_direction[2] * u_ll[2]346v_prime_rr = normal_direction[1] * u_rr[1] + normal_direction[2] * u_rr[2]347v_mean_ll = normal_direction[1] * u_ll[4] + normal_direction[2] * u_ll[5]348v_mean_rr = normal_direction[1] * u_rr[4] + normal_direction[2] * u_rr[5]349350v_ll = v_prime_ll + v_mean_ll351v_rr = v_prime_rr + v_mean_rr352353c_mean_ll = u_ll[6]354c_mean_rr = u_rr[6]355356# The v_normals are already scaled by the norm357return (max(abs(v_ll), abs(v_rr)) +358max(c_mean_ll, c_mean_rr) * norm(normal_direction))359end360361# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`362@inline function max_abs_speed(u_ll, u_rr, normal_direction::AbstractVector,363equations::AcousticPerturbationEquations2D)364# Calculate v = v_prime + v_mean365v_prime_ll = normal_direction[1] * u_ll[1] + normal_direction[2] * u_ll[2]366v_prime_rr = normal_direction[1] * u_rr[1] + normal_direction[2] * u_rr[2]367v_mean_ll = normal_direction[1] * u_ll[4] + normal_direction[2] * u_ll[5]368v_mean_rr = normal_direction[1] * u_rr[4] + normal_direction[2] * u_rr[5]369370v_ll = v_prime_ll + v_mean_ll371v_rr = v_prime_rr + v_mean_rr372373c_mean_ll = u_ll[6]374c_mean_rr = u_rr[6]375376norm_ = norm(normal_direction)377# The v_normals are already scaled by the norm378return max(abs(v_ll) + c_mean_ll * norm_, abs(v_rr) + c_mean_rr * norm_)379end380381# Specialized `DissipationLocalLaxFriedrichs` to avoid spurious dissipation in the mean values382@inline function (dissipation::DissipationLocalLaxFriedrichs)(u_ll, u_rr,383orientation_or_normal_direction,384equations::AcousticPerturbationEquations2D)385λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction,386equations)387diss = -0.5f0 * λ * (u_rr - u_ll)388z = 0389390return SVector(diss[1], diss[2], diss[3], z, z, z, z)391end392393@inline have_constant_speed(::AcousticPerturbationEquations2D) = False()394395@inline function max_abs_speeds(u, equations::AcousticPerturbationEquations2D)396v1_mean = u[4]397v2_mean = u[5]398c_mean = u[6]399400return abs(v1_mean) + c_mean, abs(v2_mean) + c_mean401end402403# Convert conservative variables to primitive404@inline function cons2prim(u, equations::AcousticPerturbationEquations2D)405p_prime_scaled = u[3]406c_mean = u[6]407p_prime = p_prime_scaled * c_mean^2408409return SVector(u[1], u[2], p_prime, u[4], u[5], u[6], u[7])410end411412# Convert primitive variables to conservative413@inline function prim2cons(u, equations::AcousticPerturbationEquations2D)414p_prime = u[3]415c_mean = u[6]416p_prime_scaled = p_prime / c_mean^2417418return SVector(u[1], u[2], p_prime_scaled, u[4], u[5], u[6], u[7])419end420421# Convert conservative variables to entropy variables422@inline cons2entropy(u, equations::AcousticPerturbationEquations2D) = u423end # @muladd424425426