Path: blob/main/src/equations/linear_scalar_advection_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"""8LinearScalarAdvectionEquation3D910The linear scalar advection equation11```math12\partial_t u + a_1 \partial_1 u + a_2 \partial_2 u + a_3 \partial_3 u = 013```14in three space dimensions with constant velocity `a`.15"""16struct LinearScalarAdvectionEquation3D{RealT <: Real} <:17AbstractLinearScalarAdvectionEquation{3}18advection_velocity::SVector{3, RealT}19end2021function LinearScalarAdvectionEquation3D(a::NTuple{3, <:Real})22LinearScalarAdvectionEquation3D(SVector(a))23end2425function LinearScalarAdvectionEquation3D(a1::Real, a2::Real, a3::Real)26LinearScalarAdvectionEquation3D(SVector(a1, a2, a3))27end2829varnames(::typeof(cons2cons), ::LinearScalarAdvectionEquation3D) = ("scalar",)30varnames(::typeof(cons2prim), ::LinearScalarAdvectionEquation3D) = ("scalar",)3132# Set initial conditions at physical location `x` for time `t`33"""34initial_condition_constant(x, t, equations::LinearScalarAdvectionEquation1D)3536A constant initial condition to test free-stream preservation.37"""38function initial_condition_constant(x, t, equation::LinearScalarAdvectionEquation3D)39RealT = eltype(x)40return SVector(RealT(2))41end4243"""44initial_condition_convergence_test(x, t, equations::LinearScalarAdvectionEquation1D)4546A smooth initial condition used for convergence tests.47"""48function initial_condition_convergence_test(x, t,49equation::LinearScalarAdvectionEquation3D)50# Store translated coordinate for easy use of exact solution51RealT = eltype(x)52x_trans = x - equation.advection_velocity * t5354c = 155A = 0.5f056L = 257f = 1.0f0 / L58omega = 2 * convert(RealT, pi) * f59scalar = c + A * sin(omega * sum(x_trans))60return SVector(scalar)61end6263"""64initial_condition_gauss(x, t, equations::LinearScalarAdvectionEquation1D)6566A Gaussian pulse.67"""68function initial_condition_gauss(x, t, equation::LinearScalarAdvectionEquation3D)69# Store translated coordinate for easy use of exact solution70x_trans = x - equation.advection_velocity * t7172scalar = exp(-(x_trans[1]^2 + x_trans[2]^2 + x_trans[3]^2))73return SVector(scalar)74end7576"""77initial_condition_sin(x, t, equations::LinearScalarAdvectionEquation1D)7879A sine wave in the conserved variable.80"""81function initial_condition_sin(x, t, equation::LinearScalarAdvectionEquation3D)82# Store translated coordinate for easy use of exact solution83RealT = eltype(x)84x_trans = x - equation.advection_velocity * t8586scalar = sinpi(2 * x_trans[1]) * sinpi(2 * x_trans[2]) * sinpi(2 * x_trans[3])87return SVector(scalar)88end8990"""91initial_condition_linear_z(x, t, equations::LinearScalarAdvectionEquation1D)9293A linear function of `x[3]` used together with94[`boundary_condition_linear_z`](@ref).95"""96function initial_condition_linear_z(x, t, equation::LinearScalarAdvectionEquation3D)97# Store translated coordinate for easy use of exact solution98x_trans = x - equation.advection_velocity * t99100return SVector(x_trans[3])101end102103"""104boundary_condition_linear_z(u_inner, orientation, direction, x, t,105surface_flux_function,106equation::LinearScalarAdvectionEquation1D)107108Boundary conditions for109[`boundary_condition_linear_z`](@ref).110"""111function boundary_condition_linear_z(u_inner, orientation, direction, x, t,112surface_flux_function,113equation::LinearScalarAdvectionEquation3D)114u_boundary = initial_condition_linear_z(x, t, equation)115116# Calculate boundary flux117if direction in (2, 4, 6) # u_inner is "left" of boundary, u_boundary is "right" of boundary118flux = surface_flux_function(u_inner, u_boundary, orientation, equation)119else # u_boundary is "left" of boundary, u_inner is "right" of boundary120flux = surface_flux_function(u_boundary, u_inner, orientation, equation)121end122123return flux124end125126# Pre-defined source terms should be implemented as127# function source_terms_WHATEVER(u, x, t, equation::LinearScalarAdvectionEquation3D)128129# Calculate 1D flux for a single point130@inline function flux(u, orientation::Integer,131equation::LinearScalarAdvectionEquation3D)132a = equation.advection_velocity[orientation]133return a * u134end135136# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation137@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Integer,138equation::LinearScalarAdvectionEquation3D)139return abs(equation.advection_velocity[orientation])140end141142# Calculate 1D flux for a single point in the normal direction143# Note, this directional vector is not normalized144@inline function flux(u, normal_direction::AbstractVector,145equation::LinearScalarAdvectionEquation3D)146a = dot(equation.advection_velocity, normal_direction) # velocity in normal direction147return a * u148end149150# Calculate maximum wave speed in the normal direction for local Lax-Friedrichs-type dissipation151@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,152equation::LinearScalarAdvectionEquation3D)153a = dot(equation.advection_velocity, normal_direction) # velocity in normal direction154return abs(a)155end156157"""158flux_godunov(u_ll, u_rr, orientation_or_normal_direction,159equations::LinearScalarAdvectionEquation3D)160161Godunov (upwind) flux for the 3D linear scalar advection equation.162Essentially first order upwind, see e.g. https://math.stackexchange.com/a/4355076/805029 .163"""164function flux_godunov(u_ll, u_rr, orientation::Integer,165equation::LinearScalarAdvectionEquation3D)166u_L = u_ll[1]167u_R = u_rr[1]168169v_normal = equation.advection_velocity[orientation]170if v_normal >= 0171return SVector(v_normal * u_L)172else173return SVector(v_normal * u_R)174end175end176177function flux_godunov(u_ll, u_rr, normal_direction::AbstractVector,178equation::LinearScalarAdvectionEquation3D)179u_L = u_ll[1]180u_R = u_rr[1]181182a_normal = dot(equation.advection_velocity, normal_direction)183if a_normal >= 0184return SVector(a_normal * u_L)185else186return SVector(a_normal * u_R)187end188end189190@inline have_constant_speed(::LinearScalarAdvectionEquation3D) = True()191192@inline function max_abs_speeds(equation::LinearScalarAdvectionEquation3D)193return abs.(equation.advection_velocity)194end195196# Convert conservative variables to primitive197@inline cons2prim(u, equation::LinearScalarAdvectionEquation3D) = u198199# Convert conservative variables to entropy variables200@inline cons2entropy(u, equation::LinearScalarAdvectionEquation3D) = u201202# Calculate entropy for a conservative state `cons`203@inline entropy(u::Real, ::LinearScalarAdvectionEquation3D) = 0.5f0 * u^2204@inline entropy(u, equation::LinearScalarAdvectionEquation3D) = entropy(u[1], equation)205206# Calculate total energy for a conservative state `cons`207@inline energy_total(u::Real, ::LinearScalarAdvectionEquation3D) = 0.5f0 * u^2208@inline function energy_total(u, equation::LinearScalarAdvectionEquation3D)209energy_total(u[1], equation)210end211end # @muladd212213214