Path: blob/main/src/equations/acoustic_perturbation_2d.jl
5586 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)71return ("v1_prime", "v2_prime", "p_prime_scaled",72"v1_mean", "v2_mean", "c_mean", "rho_mean")73end74function varnames(::typeof(cons2prim), ::AcousticPerturbationEquations2D)75return ("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)89return ("v1_prime", "v2_prime", "p_prime_scaled")90end91function varnames(::typeof(cons2mean), ::AcousticPerturbationEquations2D)92return ("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).152153References for the method of manufactured solutions (MMS):154- Kambiz Salari and Patrick Knupp (2000)155Code Verification by the Method of Manufactured Solutions156[DOI: 10.2172/759450](https://doi.org/10.2172/759450)157- Patrick J. Roache (2002)158Code Verification by the Method of Manufactured Solutions159[DOI: 10.1115/1.1436090](https://doi.org/10.1115/1.1436090)160"""161function source_terms_convergence_test(u, x, t,162equations::AcousticPerturbationEquations2D)163v1_mean, v2_mean, c_mean, rho_mean = cons2mean(u, equations)164165RealT = eltype(u)166a = 1167c = 2168L = 2169f = 2.0f0 / L170A = convert(RealT, 0.2)171omega = 2 * convert(RealT, pi) * f172173si, co = sincos(omega * (x[1] + x[2] - a * t))174tmp = v1_mean + v2_mean - a175176du1 = du2 = A * omega * co * (2 * c / rho_mean + tmp + 2 / rho_mean * A * si)177du3 = A * omega * co * (2 * c_mean^2 * rho_mean + 2 * c * tmp + 2 * A * tmp * si) /178c_mean^2179180du4 = du5 = du6 = du7 = 0181182return SVector(du1, du2, du3, du4, du5, du6, du7)183end184185"""186initial_condition_gauss(x, t, equations::AcousticPerturbationEquations2D)187188A Gaussian pulse in a constant mean flow. Uses the global mean values from `equations`.189"""190function initial_condition_gauss(x, t, equations::AcousticPerturbationEquations2D)191v1_prime = 0192v2_prime = 0193p_prime = exp(-4 * (x[1]^2 + x[2]^2))194195prim = SVector(v1_prime, v2_prime, p_prime, global_mean_vars(equations)...)196197return prim2cons(prim, equations)198end199200"""201boundary_condition_wall(u_inner, orientation, direction, x, t, surface_flux_function,202equations::AcousticPerturbationEquations2D)203204Boundary conditions for a solid wall.205"""206function boundary_condition_wall(u_inner, orientation, direction, x, t,207surface_flux_function,208equations::AcousticPerturbationEquations2D)209# Boundary state is equal to the inner state except for the perturbed velocity. For boundaries210# in the -x/+x direction, we multiply the perturbed velocity in the x direction by -1.211# Similarly, for boundaries in the -y/+y direction, we multiply the perturbed velocity in the212# y direction by -1213if direction in (1, 2) # x direction214u_boundary = SVector(-u_inner[1], u_inner[2], u_inner[3],215cons2mean(u_inner, equations)...)216else # y direction217u_boundary = SVector(u_inner[1], -u_inner[2], u_inner[3],218cons2mean(u_inner, equations)...)219end220221# Calculate boundary flux222if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary223flux = surface_flux_function(u_inner, u_boundary, orientation, equations)224else # u_boundary is "left" of boundary, u_inner is "right" of boundary225flux = surface_flux_function(u_boundary, u_inner, orientation, equations)226end227228return flux229end230231"""232boundary_condition_slip_wall(u_inner, normal_direction, x, t, surface_flux_function,233equations::AcousticPerturbationEquations2D)234235Use an orthogonal projection of the perturbed velocities to zero out the normal velocity236while retaining the possibility of a tangential velocity in the boundary state.237Further details are available in the paper:238- Marcus Bauer, Jürgen Dierke and Roland Ewert (2011)239Application of a discontinuous Galerkin method to discretize acoustic perturbation equations240[DOI: 10.2514/1.J050333](https://doi.org/10.2514/1.J050333)241"""242function boundary_condition_slip_wall(u_inner, normal_direction::AbstractVector, x, t,243surface_flux_function,244equations::AcousticPerturbationEquations2D)245# normalize the outward pointing direction246normal = normal_direction / norm(normal_direction)247248# compute the normal perturbed velocity249u_normal = normal[1] * u_inner[1] + normal[2] * u_inner[2]250251# create the "external" boundary solution state252u_boundary = SVector(u_inner[1] - 2 * u_normal * normal[1],253u_inner[2] - 2 * u_normal * normal[2],254u_inner[3], cons2mean(u_inner, equations)...)255256# calculate the boundary flux257flux = surface_flux_function(u_inner, u_boundary, normal_direction, equations)258259return flux260end261262# Calculate 1D flux for a single point263@inline function flux(u, orientation::Integer,264equations::AcousticPerturbationEquations2D)265v1_prime, v2_prime, p_prime_scaled = cons2state(u, equations)266v1_mean, v2_mean, c_mean, rho_mean = cons2mean(u, equations)267268# Calculate flux for conservative state variables269RealT = eltype(u)270if orientation == 1271f1 = v1_mean * v1_prime + v2_mean * v2_prime +272c_mean^2 * p_prime_scaled / rho_mean273f2 = zero(RealT)274f3 = rho_mean * v1_prime + v1_mean * p_prime_scaled275else276f1 = zero(RealT)277f2 = v1_mean * v1_prime + v2_mean * v2_prime +278c_mean^2 * p_prime_scaled / rho_mean279f3 = rho_mean * v2_prime + v2_mean * p_prime_scaled280end281282# The rest of the state variables are actually variable coefficients, hence the flux should be283# zero. See https://github.com/trixi-framework/Trixi.jl/issues/358#issuecomment-784828762284# for details.285f4 = f5 = f6 = f7 = 0286287return SVector(f1, f2, f3, f4, f5, f6, f7)288end289290# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation291@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,292equations::AcousticPerturbationEquations2D)293# Calculate v = v_prime + v_mean294v_prime_ll = u_ll[orientation]295v_prime_rr = u_rr[orientation]296v_mean_ll = u_ll[orientation + 3]297v_mean_rr = u_rr[orientation + 3]298299v_ll = v_prime_ll + v_mean_ll300v_rr = v_prime_rr + v_mean_rr301302c_mean_ll = u_ll[6]303c_mean_rr = u_rr[6]304305return max(abs(v_ll), abs(v_rr)) + max(c_mean_ll, c_mean_rr)306end307308# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`309@inline function max_abs_speed(u_ll, u_rr, orientation::Integer,310equations::AcousticPerturbationEquations2D)311# Calculate v = v_prime + v_mean312v_prime_ll = u_ll[orientation]313v_prime_rr = u_rr[orientation]314v_mean_ll = u_ll[orientation + 3]315v_mean_rr = u_rr[orientation + 3]316317v_ll = v_prime_ll + v_mean_ll318v_rr = v_prime_rr + v_mean_rr319320c_mean_ll = u_ll[6]321c_mean_rr = u_rr[6]322323return max(abs(v_ll) + c_mean_ll, abs(v_rr) + c_mean_rr)324end325326# Calculate 1D flux for a single point in the normal direction327# Note, this directional vector is not normalized328@inline function flux(u, normal_direction::AbstractVector,329equations::AcousticPerturbationEquations2D)330v1_prime, v2_prime, p_prime_scaled = cons2state(u, equations)331v1_mean, v2_mean, c_mean, rho_mean = cons2mean(u, equations)332333f1 = normal_direction[1] * (v1_mean * v1_prime + v2_mean * v2_prime +334c_mean^2 * p_prime_scaled / rho_mean)335f2 = normal_direction[2] * (v1_mean * v1_prime + v2_mean * v2_prime +336c_mean^2 * p_prime_scaled / rho_mean)337f3 = (normal_direction[1] * (rho_mean * v1_prime + v1_mean * p_prime_scaled)338+339normal_direction[2] * (rho_mean * v2_prime + v2_mean * p_prime_scaled))340341# The rest of the state variables are actually variable coefficients, hence the flux should be342# zero. See https://github.com/trixi-framework/Trixi.jl/issues/358#issuecomment-784828762343# for details.344f4 = f5 = f6 = f7 = 0345346return SVector(f1, f2, f3, f4, f5, f6, f7)347end348349# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation350@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,351equations::AcousticPerturbationEquations2D)352# Calculate v = v_prime + v_mean353v_prime_ll = normal_direction[1] * u_ll[1] + normal_direction[2] * u_ll[2]354v_prime_rr = normal_direction[1] * u_rr[1] + normal_direction[2] * u_rr[2]355v_mean_ll = normal_direction[1] * u_ll[4] + normal_direction[2] * u_ll[5]356v_mean_rr = normal_direction[1] * u_rr[4] + normal_direction[2] * u_rr[5]357358v_ll = v_prime_ll + v_mean_ll359v_rr = v_prime_rr + v_mean_rr360361c_mean_ll = u_ll[6]362c_mean_rr = u_rr[6]363364# The v_normals are already scaled by the norm365return (max(abs(v_ll), abs(v_rr)) +366max(c_mean_ll, c_mean_rr) * norm(normal_direction))367end368369# Less "cautious", i.e., less overestimating `λ_max` compared to `max_abs_speed_naive`370@inline function max_abs_speed(u_ll, u_rr, normal_direction::AbstractVector,371equations::AcousticPerturbationEquations2D)372# Calculate v = v_prime + v_mean373v_prime_ll = normal_direction[1] * u_ll[1] + normal_direction[2] * u_ll[2]374v_prime_rr = normal_direction[1] * u_rr[1] + normal_direction[2] * u_rr[2]375v_mean_ll = normal_direction[1] * u_ll[4] + normal_direction[2] * u_ll[5]376v_mean_rr = normal_direction[1] * u_rr[4] + normal_direction[2] * u_rr[5]377378v_ll = v_prime_ll + v_mean_ll379v_rr = v_prime_rr + v_mean_rr380381c_mean_ll = u_ll[6]382c_mean_rr = u_rr[6]383384norm_ = norm(normal_direction)385# The v_normals are already scaled by the norm386return max(abs(v_ll) + c_mean_ll * norm_, abs(v_rr) + c_mean_rr * norm_)387end388389# Specialized `DissipationLocalLaxFriedrichs` to avoid spurious dissipation in the mean values390@inline function (dissipation::DissipationLocalLaxFriedrichs)(u_ll, u_rr,391orientation_or_normal_direction,392equations::AcousticPerturbationEquations2D)393λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction,394equations)395diss = -0.5f0 * λ * (u_rr - u_ll)396z = 0397398return SVector(diss[1], diss[2], diss[3], z, z, z, z)399end400401"""402have_constant_speed(::AcousticPerturbationEquations2D)403404Indicates whether the characteristic speeds are constant, i.e., independent of the solution.405Queried in the timestep computation [`StepsizeCallback`](@ref).406407The acoustic perturbation equations are in principle linear for **constant** mean flow fields.408However, the mean flow variables are part of the solution vector in409[`AcousticPerturbationEquations2D`](@ref) and only the **global** mean flow variables are constant,410similar to the [`LinearizedEulerEquations2D`](@ref).411412Moreover, when coupling to the [`CompressibleEulerEquations2D`](@ref) equations via413[`SemidiscretizationEulerAcoustics`](@ref), the mean field variables are updated414on the fly, see [`EulerAcousticsCouplingCallback`](@ref).415416# Returns417- `False()`418"""419@inline have_constant_speed(::AcousticPerturbationEquations2D) = False()420421@inline function max_abs_speeds(u, equations::AcousticPerturbationEquations2D)422v1_mean = u[4]423v2_mean = u[5]424c_mean = u[6]425426return abs(v1_mean) + c_mean, abs(v2_mean) + c_mean427end428429# Convert conservative variables to primitive430@inline function cons2prim(u, equations::AcousticPerturbationEquations2D)431p_prime_scaled = u[3]432c_mean = u[6]433p_prime = p_prime_scaled * c_mean^2434435return SVector(u[1], u[2], p_prime, u[4], u[5], u[6], u[7])436end437438# Convert primitive variables to conservative439@inline function prim2cons(u, equations::AcousticPerturbationEquations2D)440p_prime = u[3]441c_mean = u[6]442p_prime_scaled = p_prime / c_mean^2443444return SVector(u[1], u[2], p_prime_scaled, u[4], u[5], u[6], u[7])445end446447# Convert conservative variables to entropy variables448@inline cons2entropy(u, equations::AcousticPerturbationEquations2D) = u449end # @muladd450451452