Path: blob/main/src/equations/linearized_euler_3d.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"""8LinearizedEulerEquations3D(v_mean_global, c_mean_global, rho_mean_global)910Linearized Euler equations in three space dimensions. The equations are given by11```math12\partial_t13\begin{pmatrix}14\rho' \\ v_1' \\ v_2' \\ v_3' \\ p'15\end{pmatrix}16+17\partial_x18\begin{pmatrix}19\bar{\rho} v_1' + \bar{v_1} \rho ' \\20\bar{v_1} v_1' + \frac{p'}{\bar{\rho}} \\21\bar{v_1} v_2' \\22\bar{v_1} v_3' \\23\bar{v_1} p' + c^2 \bar{\rho} v_1'24\end{pmatrix}25+26\partial_y27\begin{pmatrix}28\bar{\rho} v_2' + \bar{v_2} \rho ' \\29\bar{v_2} v_1' \\30\bar{v_2} v_2' + \frac{p'}{\bar{\rho}} \\31\bar{v_2} v_3' \\32\bar{v_2} p' + c^2 \bar{\rho} v_2'33\end{pmatrix}34+35\partial_z36\begin{pmatrix}37\bar{\rho} v_3' + \bar{v_3} \rho ' \\38\bar{v_3} v_1' \\39\bar{v_3} v_2' \\40\bar{v_3} v_3' + \frac{p'}{\bar{\rho}} \\41\bar{v_3} p' + c^2 \bar{\rho} v_3'42\end{pmatrix}43=44\begin{pmatrix}450 \\ 0 \\ 0 \\ 0 \\ 046\end{pmatrix}47```48The bar ``\bar{(\cdot)}`` indicates uniform mean flow variables and ``c`` is the speed of sound.49The unknowns are the acoustic velocities ``v' = (v_1', v_2, v_3')``, the pressure ``p'`` and the density ``\rho'``.50"""51struct LinearizedEulerEquations3D{RealT <: Real} <:52AbstractLinearizedEulerEquations{3, 5}53v_mean_global::SVector{3, RealT}54c_mean_global::RealT55rho_mean_global::RealT56end5758function LinearizedEulerEquations3D(v_mean_global::NTuple{3, <:Real},59c_mean_global::Real, rho_mean_global::Real)60if rho_mean_global < 061throw(ArgumentError("rho_mean_global must be non-negative"))62elseif c_mean_global < 063throw(ArgumentError("c_mean_global must be non-negative"))64end6566return LinearizedEulerEquations3D(SVector(v_mean_global), c_mean_global,67rho_mean_global)68end6970function LinearizedEulerEquations3D(; v_mean_global::NTuple{3, <:Real},71c_mean_global::Real, rho_mean_global::Real)72return LinearizedEulerEquations3D(v_mean_global, c_mean_global,73rho_mean_global)74end7576function varnames(::typeof(cons2cons), ::LinearizedEulerEquations3D)77("rho_prime", "v1_prime", "v2_prime", "v3_prime", "p_prime")78end79function varnames(::typeof(cons2prim), ::LinearizedEulerEquations3D)80("rho_prime", "v1_prime", "v2_prime", "v3_prime", "p_prime")81end8283"""84initial_condition_convergence_test(x, t, equations::LinearizedEulerEquations3D)8586A smooth initial condition used for convergence tests.87"""88function initial_condition_convergence_test(x, t, equations::LinearizedEulerEquations3D)89rho_prime = -cospi(2 * t) * (sinpi(2 * x[1]) + sinpi(2 * x[2]) + sinpi(2 * x[3]))90v1_prime = sinpi(2 * t) * cospi(2 * x[1])91v2_prime = sinpi(2 * t) * cospi(2 * x[2])92v3_prime = sinpi(2 * t) * cospi(2 * x[3])93p_prime = rho_prime9495return SVector(rho_prime, v1_prime, v2_prime, v3_prime, p_prime)96end9798"""99boundary_condition_wall(u_inner, orientation, direction, x, t, surface_flux_function,100equations::LinearizedEulerEquations3D)101102Boundary conditions for a solid wall.103"""104function boundary_condition_wall(u_inner, orientation, direction, x, t,105surface_flux_function,106equations::LinearizedEulerEquations3D)107# Boundary state is equal to the inner state except for the velocity. For boundaries108# in the -x/+x direction, we multiply the velocity in the x direction by -1.109# Similarly, for boundaries in the -y/+y or -z/+z direction, we multiply the110# velocity in the y or z direction by -1111if direction in (1, 2) # x direction112u_boundary = SVector(u_inner[1], -u_inner[2], u_inner[3], u_inner[4],113u_inner[5])114elseif direction in (3, 4) # y direction115u_boundary = SVector(u_inner[1], u_inner[2], -u_inner[3], u_inner[4],116u_inner[5])117else # z direction = (5, 6)118u_boundary = SVector(u_inner[1], u_inner[2], u_inner[3], -u_inner[4],119u_inner[5])120end121122# Calculate boundary flux depending on the orientation of the boundary123# Odd directions are in negative coordinate direction,124# even directions are in positive coordinate direction.125if iseven(direction) # u_inner is "left" of boundary, u_boundary is "right" of boundary126flux = surface_flux_function(u_inner, u_boundary, orientation, equations)127else # u_boundary is "left" of boundary, u_inner is "right" of boundary128flux = surface_flux_function(u_boundary, u_inner, orientation, equations)129end130131return flux132end133134# Calculate 1D flux for a single point135@inline function flux(u, orientation::Integer, equations::LinearizedEulerEquations3D)136@unpack v_mean_global, c_mean_global, rho_mean_global = equations137rho_prime, v1_prime, v2_prime, v3_prime, p_prime = u138if orientation == 1139f1 = v_mean_global[1] * rho_prime + rho_mean_global * v1_prime140f2 = v_mean_global[1] * v1_prime + p_prime / rho_mean_global141f3 = v_mean_global[1] * v2_prime142f4 = v_mean_global[1] * v3_prime143f5 = v_mean_global[1] * p_prime + c_mean_global^2 * rho_mean_global * v1_prime144elseif orientation == 2145f1 = v_mean_global[2] * rho_prime + rho_mean_global * v2_prime146f2 = v_mean_global[2] * v1_prime147f3 = v_mean_global[2] * v2_prime + p_prime / rho_mean_global148f4 = v_mean_global[2] * v3_prime149f5 = v_mean_global[2] * p_prime + c_mean_global^2 * rho_mean_global * v2_prime150else # orientation == 3151f1 = v_mean_global[3] * rho_prime + rho_mean_global * v3_prime152f2 = v_mean_global[3] * v1_prime153f3 = v_mean_global[3] * v2_prime154f4 = v_mean_global[3] * v3_prime + p_prime / rho_mean_global155f5 = v_mean_global[3] * p_prime + c_mean_global^2 * rho_mean_global * v3_prime156end157158return SVector(f1, f2, f3, f4, f5)159end160161# Calculate 1D flux for a single point162@inline function flux(u, normal_direction::AbstractVector,163equations::LinearizedEulerEquations3D)164@unpack v_mean_global, c_mean_global, rho_mean_global = equations165rho_prime, v1_prime, v2_prime, v3_prime, p_prime = u166167v_mean_normal = v_mean_global[1] * normal_direction[1] +168v_mean_global[2] * normal_direction[2] +169v_mean_global[3] * normal_direction[3]170v_prime_normal = v1_prime * normal_direction[1] + v2_prime * normal_direction[2] +171v3_prime * normal_direction[3]172173f1 = v_mean_normal * rho_prime + rho_mean_global * v_prime_normal174f2 = v_mean_normal * v1_prime + normal_direction[1] * p_prime / rho_mean_global175f3 = v_mean_normal * v2_prime + normal_direction[2] * p_prime / rho_mean_global176f4 = v_mean_normal * v3_prime + normal_direction[3] * p_prime / rho_mean_global177f5 = v_mean_normal * p_prime + c_mean_global^2 * rho_mean_global * v_prime_normal178179return SVector(f1, f2, f3, f4, f5)180end181182@inline have_constant_speed(::LinearizedEulerEquations3D) = True()183184@inline function max_abs_speeds(equations::LinearizedEulerEquations3D)185@unpack v_mean_global, c_mean_global = equations186return abs(v_mean_global[1]) + c_mean_global, abs(v_mean_global[2]) + c_mean_global,187abs(v_mean_global[3]) + c_mean_global188end189190@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,191equations::LinearizedEulerEquations3D)192@unpack v_mean_global, c_mean_global = equations193if orientation == 1194return abs(v_mean_global[1]) + c_mean_global195elseif orientation == 2196return abs(v_mean_global[2]) + c_mean_global197else # orientation == 3198return abs(v_mean_global[3]) + c_mean_global199end200end201202@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,203equations::LinearizedEulerEquations3D)204@unpack v_mean_global, c_mean_global = equations205v_mean_normal = normal_direction[1] * v_mean_global[1] +206normal_direction[2] * v_mean_global[2] +207normal_direction[3] * v_mean_global[3]208return abs(v_mean_normal) + c_mean_global * norm(normal_direction)209end210211# Calculate estimate for minimum and maximum wave speeds for HLL-type fluxes212@inline function min_max_speed_naive(u_ll, u_rr, orientation::Integer,213equations::LinearizedEulerEquations3D)214min_max_speed_davis(u_ll, u_rr, orientation, equations)215end216217@inline function min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,218equations::LinearizedEulerEquations3D)219min_max_speed_davis(u_ll, u_rr, normal_direction, equations)220end221222# More refined estimates for minimum and maximum wave speeds for HLL-type fluxes223@inline function min_max_speed_davis(u_ll, u_rr, orientation::Integer,224equations::LinearizedEulerEquations3D)225@unpack v_mean_global, c_mean_global = equations226227λ_min = v_mean_global[orientation] - c_mean_global228λ_max = v_mean_global[orientation] + c_mean_global229230return λ_min, λ_max231end232233@inline function min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector,234equations::LinearizedEulerEquations3D)235@unpack v_mean_global, c_mean_global = equations236237norm_ = norm(normal_direction)238239v_normal = v_mean_global[1] * normal_direction[1] +240v_mean_global[2] * normal_direction[2] +241v_mean_global[3] * normal_direction[3]242243# The v_normals are already scaled by the norm244λ_min = v_normal - c_mean_global * norm_245λ_max = v_normal + c_mean_global * norm_246247return λ_min, λ_max248end249250# Convert conservative variables to primitive251@inline cons2prim(u, equations::LinearizedEulerEquations3D) = u252@inline cons2entropy(u, ::LinearizedEulerEquations3D) = u253end # muladd254255256