Path: blob/main/src/equations/linear_scalar_advection_1d.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"""8LinearScalarAdvectionEquation1D910The linear scalar advection equation11```math12\partial_t u + a \partial_1 u = 013```14in one space dimension with constant velocity `a`.15"""16struct LinearScalarAdvectionEquation1D{RealT <: Real} <:17AbstractLinearScalarAdvectionEquation{1}18advection_velocity::SVector{1, RealT}19end2021function LinearScalarAdvectionEquation1D(a::Real)22LinearScalarAdvectionEquation1D(SVector(a))23end2425varnames(::typeof(cons2cons), ::LinearScalarAdvectionEquation1D) = ("scalar",)26varnames(::typeof(cons2prim), ::LinearScalarAdvectionEquation1D) = ("scalar",)2728# Set initial conditions at physical location `x` for time `t`29"""30initial_condition_constant(x, t, equations::LinearScalarAdvectionEquation1D)3132A constant initial condition to test free-stream preservation.33"""34function initial_condition_constant(x, t, equation::LinearScalarAdvectionEquation1D)35RealT = eltype(x)36return SVector(RealT(2))37end3839"""40initial_condition_convergence_test(x, t, equations::LinearScalarAdvectionEquation1D)4142A smooth initial condition used for convergence tests43(in combination with [`BoundaryConditionDirichlet(initial_condition_convergence_test)`](@ref)44in non-periodic domains).45"""46function initial_condition_convergence_test(x, t,47equation::LinearScalarAdvectionEquation1D)48# Store translated coordinate for easy use of exact solution49RealT = eltype(x)50x_trans = x - equation.advection_velocity * t5152c = 153A = 0.5f054L = 255f = 1.0f0 / L56omega = 2 * convert(RealT, pi) * f57scalar = c + A * sin(omega * sum(x_trans))58return SVector(scalar)59end6061"""62initial_condition_gauss(x, t, equations::LinearScalarAdvectionEquation1D)6364A Gaussian pulse used together with65[`BoundaryConditionDirichlet(initial_condition_gauss)`](@ref).66"""67function initial_condition_gauss(x, t, equation::LinearScalarAdvectionEquation1D)68# Store translated coordinate for easy use of exact solution69x_trans = x - equation.advection_velocity * t7071scalar = exp(-(x_trans[1]^2))72return SVector(scalar)73end7475"""76initial_condition_sin(x, t, equations::LinearScalarAdvectionEquation1D)7778A sine wave in the conserved variable.79"""80function initial_condition_sin(x, t, equation::LinearScalarAdvectionEquation1D)81# Store translated coordinate for easy use of exact solution82x_trans = x - equation.advection_velocity * t8384scalar = sinpi(2 * x_trans[1])85return SVector(scalar)86end8788"""89initial_condition_linear_x(x, t, equations::LinearScalarAdvectionEquation1D)9091A linear function of `x[1]` used together with92[`boundary_condition_linear_x`](@ref).93"""94function initial_condition_linear_x(x, t, equation::LinearScalarAdvectionEquation1D)95# Store translated coordinate for easy use of exact solution96x_trans = x - equation.advection_velocity * t9798return SVector(x_trans[1])99end100101"""102boundary_condition_linear_x(u_inner, orientation, direction, x, t,103surface_flux_function,104equation::LinearScalarAdvectionEquation1D)105106Boundary conditions for107[`initial_condition_linear_x`](@ref).108"""109function boundary_condition_linear_x(u_inner, orientation, direction, x, t,110surface_flux_function,111equation::LinearScalarAdvectionEquation1D)112u_boundary = initial_condition_linear_x(x, t, equation)113114# Calculate boundary flux115if direction == 2 # u_inner is "left" of boundary, u_boundary is "right" of boundary116flux = surface_flux_function(u_inner, u_boundary, orientation, equation)117else # u_boundary is "left" of boundary, u_inner is "right" of boundary118flux = surface_flux_function(u_boundary, u_inner, orientation, equation)119end120121return flux122end123124# Pre-defined source terms should be implemented as125# function source_terms_WHATEVER(u, x, t, equations::LinearScalarAdvectionEquation1D)126127# Calculate 1D flux for a single point128@inline function flux(u, orientation::Integer,129equation::LinearScalarAdvectionEquation1D)130a = equation.advection_velocity[orientation]131return a * u132end133134# Calculate maximum wave speed for local Lax-Friedrichs-type dissipation135@inline function max_abs_speed_naive(u_ll, u_rr, orientation::Int,136equation::LinearScalarAdvectionEquation1D)137return abs(equation.advection_velocity[orientation])138end139140"""141flux_godunov(u_ll, u_rr, orientation,142equations::LinearScalarAdvectionEquation1D)143144Godunov (upwind) flux for the 1D linear scalar advection equation.145Essentially first order upwind, see e.g. https://math.stackexchange.com/a/4355076/805029 .146"""147function flux_godunov(u_ll, u_rr, orientation::Int,148equation::LinearScalarAdvectionEquation1D)149u_L = u_ll[1]150u_R = u_rr[1]151152v_normal = equation.advection_velocity[orientation]153if v_normal >= 0154return SVector(v_normal * u_L)155else156return SVector(v_normal * u_R)157end158end159160# See https://metaphor.ethz.ch/x/2019/hs/401-4671-00L/literature/mishra_hyperbolic_pdes.pdf ,161# section 4.2.5 and especially equation (4.33).162function flux_engquist_osher(u_ll, u_rr, orientation::Int,163equation::LinearScalarAdvectionEquation1D)164u_L = u_ll[1]165u_R = u_rr[1]166167return SVector(0.5f0 * (flux(u_L, orientation, equation) +168flux(u_R, orientation, equation) -169abs(equation.advection_velocity[orientation]) * (u_R - u_L)))170end171172@inline have_constant_speed(::LinearScalarAdvectionEquation1D) = True()173174@inline function max_abs_speeds(equation::LinearScalarAdvectionEquation1D)175return abs.(equation.advection_velocity)176end177178"""179splitting_lax_friedrichs(u, orientation::Integer,180equations::LinearScalarAdvectionEquation1D)181splitting_lax_friedrichs(u, which::Union{Val{:minus}, Val{:plus}}182orientation::Integer,183equations::LinearScalarAdvectionEquation1D)184185Naive local Lax-Friedrichs style flux splitting of the form `f⁺ = 0.5 (f + λ u)`186and `f⁻ = 0.5 (f - λ u)` where `λ` is the absolute value of the advection187velocity.188189Returns a tuple of the fluxes "minus" (associated with waves going into the190negative axis direction) and "plus" (associated with waves going into the191positive axis direction). If only one of the fluxes is required, use the192function signature with argument `which` set to `Val{:minus}()` or `Val{:plus}()`.193194!!! warning "Experimental implementation (upwind SBP)"195This is an experimental feature and may change in future releases.196"""197@inline function splitting_lax_friedrichs(u, orientation::Integer,198equations::LinearScalarAdvectionEquation1D)199fm = splitting_lax_friedrichs(u, Val{:minus}(), orientation, equations)200fp = splitting_lax_friedrichs(u, Val{:plus}(), orientation, equations)201return fm, fp202end203204@inline function splitting_lax_friedrichs(u, ::Val{:plus}, orientation::Integer,205equations::LinearScalarAdvectionEquation1D)206RealT = eltype(u)207a = equations.advection_velocity[1]208return a > 0 ? flux(u, orientation, equations) : SVector(zero(RealT))209end210211@inline function splitting_lax_friedrichs(u, ::Val{:minus}, orientation::Integer,212equations::LinearScalarAdvectionEquation1D)213RealT = eltype(u)214a = equations.advection_velocity[1]215return a < 0 ? flux(u, orientation, equations) : SVector(zero(RealT))216end217218# Convert conservative variables to primitive219@inline cons2prim(u, equation::LinearScalarAdvectionEquation1D) = u220221# Convert conservative variables to entropy variables222@inline cons2entropy(u, equation::LinearScalarAdvectionEquation1D) = u223224# Calculate entropy for a conservative state `cons`225@inline entropy(u::Real, ::LinearScalarAdvectionEquation1D) = 0.5f0 * u^2226@inline entropy(u, equation::LinearScalarAdvectionEquation1D) = entropy(u[1], equation)227228# Calculate total energy for a conservative state `cons`229@inline energy_total(u::Real, ::LinearScalarAdvectionEquation1D) = 0.5f0 * u^2230@inline function energy_total(u, equation::LinearScalarAdvectionEquation1D)231energy_total(u[1], equation)232end233end # @muladd234235236