Path: blob/main/src/equations/numerical_fluxes.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# This file contains general numerical fluxes that are not specific to certain equations89"""10flux_central(u_ll, u_rr, orientation_or_normal_direction, equations::AbstractEquations)1112The classical central numerical flux `f((u_ll) + f(u_rr)) / 2`. When this flux is13used as volume flux, the discretization is equivalent to the classical weak form14DG method (except floating point errors).15"""16@inline function flux_central(u_ll, u_rr, orientation_or_normal_direction,17equations::AbstractEquations)18# Calculate regular 1D fluxes19f_ll = flux(u_ll, orientation_or_normal_direction, equations)20f_rr = flux(u_rr, orientation_or_normal_direction, equations)2122# Average regular fluxes23return 0.5f0 * (f_ll + f_rr)24end2526"""27FluxPlusDissipation(numerical_flux, dissipation)2829Combine a `numerical_flux` with a `dissipation` operator to create a new numerical flux.30"""31struct FluxPlusDissipation{NumericalFlux, Dissipation}32numerical_flux::NumericalFlux33dissipation::Dissipation34end3536@inline function (numflux::FluxPlusDissipation)(u_ll, u_rr,37orientation_or_normal_direction,38equations)39@unpack numerical_flux, dissipation = numflux4041return (numerical_flux(u_ll, u_rr, orientation_or_normal_direction, equations)42+43dissipation(u_ll, u_rr, orientation_or_normal_direction, equations))44end4546function Base.show(io::IO, f::FluxPlusDissipation)47print(io, "FluxPlusDissipation(", f.numerical_flux, ", ", f.dissipation, ")")48end4950"""51FluxRotated(numerical_flux)5253Compute a `numerical_flux` flux in direction of a normal vector by rotating the solution,54computing the numerical flux in x-direction, and rotating the calculated flux back.5556Requires a rotationally invariant equation with equation-specific functions57[`rotate_to_x`](@ref) and [`rotate_from_x`](@ref).58"""59struct FluxRotated{NumericalFlux}60numerical_flux::NumericalFlux61end6263# Rotated surface flux computation (2D version)64@inline function (flux_rotated::FluxRotated)(u,65normal_direction::AbstractVector,66equations::AbstractEquations{2})67@unpack numerical_flux = flux_rotated6869norm_ = norm(normal_direction)70# Normalize the vector without using `normalize` since we need to multiply by the `norm_` later71normal_vector = normal_direction / norm_7273u_rotated = rotate_to_x(u, normal_vector, equations)7475f = numerical_flux(u_rotated, 1, equations)7677return rotate_from_x(f, normal_vector, equations) * norm_78end7980# Rotated surface flux computation (2D version)81@inline function (flux_rotated::FluxRotated)(u_ll, u_rr,82normal_direction::AbstractVector,83equations::AbstractEquations{2})84@unpack numerical_flux = flux_rotated8586norm_ = norm(normal_direction)87# Normalize the vector without using `normalize` since we need to multiply by the `norm_` later88normal_vector = normal_direction / norm_8990u_ll_rotated = rotate_to_x(u_ll, normal_vector, equations)91u_rr_rotated = rotate_to_x(u_rr, normal_vector, equations)9293f = numerical_flux(u_ll_rotated, u_rr_rotated, 1, equations)9495return rotate_from_x(f, normal_vector, equations) * norm_96end9798# Rotated surface flux computation (3D version)99@inline function (flux_rotated::FluxRotated)(u_ll, u_rr,100normal_direction::AbstractVector,101equations::AbstractEquations{3})102@unpack numerical_flux = flux_rotated103104# Storing these vectors could increase the performance by 20 percent105norm_ = norm(normal_direction)106# Normalize the vector without using `normalize` since we need to multiply by the `norm_` later107normal_vector = normal_direction / norm_108109# Some vector that can't be identical to normal_vector (unless normal_vector == 0)110tangent1 = SVector(normal_direction[2], normal_direction[3], -normal_direction[1])111# Orthogonal projection112tangent1 -= dot(normal_vector, tangent1) * normal_vector113tangent1 = normalize(tangent1)114115# Third orthogonal vector116tangent2 = normalize(cross(normal_direction, tangent1))117118u_ll_rotated = rotate_to_x(u_ll, normal_vector, tangent1, tangent2, equations)119u_rr_rotated = rotate_to_x(u_rr, normal_vector, tangent1, tangent2, equations)120121f = numerical_flux(u_ll_rotated, u_rr_rotated, 1, equations)122123return rotate_from_x(f, normal_vector, tangent1, tangent2, equations) * norm_124end125126Base.show(io::IO, f::FluxRotated) = print(io, "FluxRotated(", f.numerical_flux, ")")127128"""129DissipationGlobalLaxFriedrichs(λ)130131Create a global Lax-Friedrichs dissipation operator with dissipation coefficient `λ`.132"""133struct DissipationGlobalLaxFriedrichs{RealT}134λ::RealT135end136137@inline function (dissipation::DissipationGlobalLaxFriedrichs)(u_ll, u_rr,138orientation::Integer,139equations)140@unpack λ = dissipation141return -λ / 2 * (u_rr - u_ll)142end143144@inline function (dissipation::DissipationGlobalLaxFriedrichs)(u_ll, u_rr,145normal_direction::AbstractVector,146equations)147@unpack λ = dissipation148return -λ / 2 * norm(normal_direction) * (u_rr - u_ll)149end150151function Base.show(io::IO, d::DissipationGlobalLaxFriedrichs)152print(io, "DissipationGlobalLaxFriedrichs(", d.λ, ")")153end154155"""156DissipationLocalLaxFriedrichs(max_abs_speed=max_abs_speed)157158Create a local Lax-Friedrichs dissipation operator where the maximum absolute wave speed159is estimated as160`max_abs_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`,161defaulting to [`max_abs_speed`](@ref).162"""163struct DissipationLocalLaxFriedrichs{MaxAbsSpeed}164max_abs_speed::MaxAbsSpeed165end166167DissipationLocalLaxFriedrichs() = DissipationLocalLaxFriedrichs(max_abs_speed)168169@inline function (dissipation::DissipationLocalLaxFriedrichs)(u_ll, u_rr,170orientation_or_normal_direction,171equations)172λ = dissipation.max_abs_speed(u_ll, u_rr, orientation_or_normal_direction,173equations)174return -0.5f0 * λ * (u_rr - u_ll)175end176177function Base.show(io::IO, d::DissipationLocalLaxFriedrichs)178print(io, "DissipationLocalLaxFriedrichs(", d.max_abs_speed, ")")179end180181"""182max_abs_speed_naive(u_ll, u_rr, orientation::Integer, equations)183max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations)184185Simple and fast estimate of the maximal wave speed of the Riemann problem with left and right states186`u_ll, u_rr`, based only on the local wave speeds associated to `u_ll` and `u_rr`.187188For non-integer arguments `normal_direction` in one dimension, `max_abs_speed_naive` returns189`abs(normal_direction[1]) * max_abs_speed_naive(u_ll, u_rr, 1, equations)`.190191Slightly more diffusive/overestimating than [`max_abs_speed`](@ref).192"""193function max_abs_speed_naive end194195# for non-integer `orientation_or_normal` arguments.196@inline function max_abs_speed_naive(u_ll, u_rr, normal_direction::AbstractVector,197equations::AbstractEquations{1})198return abs(normal_direction[1]) * max_abs_speed_naive(u_ll, u_rr, 1, equations)199end200201"""202max_abs_speed(u_ll, u_rr, orientation::Integer, equations)203max_abs_speed(u_ll, u_rr, normal_direction::AbstractVector, equations)204205Simple and fast estimate of the maximal wave speed of the Riemann problem with left and right states206`u_ll, u_rr`, based only on the local wave speeds associated to `u_ll` and `u_rr`.207Less diffusive, i.e., overestimating than [`max_abs_speed_naive`](@ref).208209In particular, `max_abs_speed(u, u, i, equations)` gives the same result as `max_abs_speeds(u, equations)[i]`,210i.e., the wave speeds used in `max_dt` which computes the maximum stable time step size through the211[`StepsizeCallback`](@ref).212213For non-integer arguments `normal_direction` in one dimension, `max_abs_speed_naive` returns214`abs(normal_direction[1]) * max_abs_speed_naive(u_ll, u_rr, 1, equations)`.215216Defaults to [`min_max_speed_naive`](@ref) if no specialized version for the 'equations` at hand is available.217"""218@inline function max_abs_speed(u_ll, u_rr,219orientation_or_normal_direction,220equations::AbstractEquations)221# Use naive version as "backup" if no specialized version for the equations at hand is available222max_abs_speed_naive(u_ll, u_rr, orientation_or_normal_direction, equations)223end224225const FluxLaxFriedrichs{MaxAbsSpeed} = FluxPlusDissipation{typeof(flux_central),226DissipationLocalLaxFriedrichs{MaxAbsSpeed}}227"""228FluxLaxFriedrichs(max_abs_speed=max_abs_speed)229230Local Lax-Friedrichs (Rusanov) flux with maximum wave speed estimate provided by231`max_abs_speed`, cf. [`DissipationLocalLaxFriedrichs`](@ref) and232[`max_abs_speed_naive`](@ref).233"""234function FluxLaxFriedrichs(max_abs_speed = max_abs_speed)235FluxPlusDissipation(flux_central, DissipationLocalLaxFriedrichs(max_abs_speed))236end237238function Base.show(io::IO, f::FluxLaxFriedrichs)239print(io, "FluxLaxFriedrichs(", f.dissipation.max_abs_speed, ")")240end241242"""243flux_lax_friedrichs244245See [`FluxLaxFriedrichs`](@ref).246"""247const flux_lax_friedrichs = FluxLaxFriedrichs()248249@doc raw"""250DissipationLaxFriedrichsEntropyVariables(max_abs_speed=max_abs_speed)251252Create a local Lax-Friedrichs-type dissipation operator that is provably entropy stable. This operator253must be used together with an entropy-conservative two-point flux function (e.g., `flux_ec`) to yield254an entropy-stable surface flux. The surface flux function can be initialized as:255```julia256flux_es = FluxPlusDissipation(flux_ec, DissipationLaxFriedrichsEntropyVariables())257```258259In particular, the numerical flux has the form260```math261f^{\mathrm{ES}} = f^{\mathrm{EC}} - \frac{1}{2} \lambda_{\mathrm{max}} H (w_r - w_l),262```263where ``f^{\mathrm{EC}}`` is the entropy-conservative two-point flux function (computed with, e.g., `flux_ec`), ``\lambda_{\mathrm{max}}``264is the maximum wave speed estimated as `max_abs_speed(u_l, u_r, orientation_or_normal_direction, equations)`,265defaulting to [`max_abs_speed`](@ref), ``H`` is a symmetric positive-definite dissipation matrix that266depends on the left and right states `u_l` and `u_r`, and ``(w_r - w_l)`` is the jump in entropy variables.267Ideally, ``H (w_r - w_l) = (u_r - u_l)``, such that the dissipation operator is consistent with the local268Lax-Friedrichs dissipation.269270The entropy-stable dissipation operator is computed with the function271`function (dissipation::DissipationLaxFriedrichsEntropyVariables)(u_l, u_r, orientation_or_normal_direction, equations)`,272which must be specialized for each equation.273274For the derivation of the dissipation matrix for the multi-ion GLM-MHD equations, see:275- A. Rueda-Ramírez, A. Sikstel, G. Gassner, An Entropy-Stable Discontinuous Galerkin Discretization276of the Ideal Multi-Ion Magnetohydrodynamics System (2024). Journal of Computational Physics.277[DOI: 10.1016/j.jcp.2024.113655](https://doi.org/10.1016/j.jcp.2024.113655).278"""279struct DissipationLaxFriedrichsEntropyVariables{MaxAbsSpeed}280max_abs_speed::MaxAbsSpeed281end282283DissipationLaxFriedrichsEntropyVariables() = DissipationLaxFriedrichsEntropyVariables(max_abs_speed)284285function Base.show(io::IO, d::DissipationLaxFriedrichsEntropyVariables)286print(io, "DissipationLaxFriedrichsEntropyVariables(", d.max_abs_speed, ")")287end288289@doc raw"""290DissipationMatrixWintersEtal()291292Creates the Roe-like entropy-stable matrix dissipation operator from Winters et al. (2017). This operator293must be used together with an entropy-conservative two-point flux function294(e.g., [`flux_ranocha`](@ref) or [`flux_chandrashekar`](@ref)) to yield295an entropy-stable surface flux. The surface flux function can be initialized as:296```julia297flux_es = FluxPlusDissipation(flux_ec, DissipationMatrixWintersEtal())298```299The 1D and 2D implementations are adapted from the [Atum.jl library](https://github.com/mwarusz/Atum.jl/blob/c7ed44f2b7972ac726ef345da7b98b0bda60e2a3/src/balancelaws/euler.jl#L198).300The 3D implementation is adapted from the [FLUXO library](https://github.com/project-fluxo/fluxo)301302For the derivation of the matrix dissipation operator, see:303- A. R. Winters, D. Derigs, G. Gassner, S. Walch, A uniquely defined entropy stable matrix dissipation operator304for high Mach number ideal MHD and compressible Euler simulations (2017). Journal of Computational Physics.305[DOI: 10.1016/j.jcp.2016.12.006](https://doi.org/10.1016/j.jcp.2016.12.006).306"""307struct DissipationMatrixWintersEtal end308309@inline function (dissipation::DissipationMatrixWintersEtal)(u_ll, u_rr,310orientation::Integer,311equations::AbstractEquations{1})312return dissipation(u_ll, u_rr, SVector(1), equations)313end314315@inline function (dissipation::DissipationMatrixWintersEtal)(u_ll, u_rr,316orientation::Integer,317equations::AbstractEquations{2})318if orientation == 1319return dissipation(u_ll, u_rr, SVector(1, 0), equations)320else # orientation == 2321return dissipation(u_ll, u_rr, SVector(0, 1), equations)322end323end324325@inline function (dissipation::DissipationMatrixWintersEtal)(u_ll, u_rr,326orientation::Integer,327equations::AbstractEquations{3})328if orientation == 1329return dissipation(u_ll, u_rr, SVector(1, 0, 0), equations)330elseif orientation == 2331return dissipation(u_ll, u_rr, SVector(0, 1, 0), equations)332else # orientation == 3333return dissipation(u_ll, u_rr, SVector(0, 0, 1), equations)334end335end336337"""338FluxHLL(min_max_speed=min_max_speed_davis)339340Create an HLL (Harten, Lax, van Leer) numerical flux where the minimum and maximum341wave speeds are estimated as342`λ_min, λ_max = min_max_speed(u_ll, u_rr, orientation_or_normal_direction, equations)`,343defaulting to [`min_max_speed_davis`](@ref).344Original paper:345- Amiram Harten, Peter D. Lax, Bram van Leer (1983)346On Upstream Differencing and Godunov-Type Schemes for Hyperbolic Conservation Laws347[DOI: 10.1137/1025002](https://doi.org/10.1137/1025002)348"""349struct FluxHLL{MinMaxSpeed}350min_max_speed::MinMaxSpeed351end352353FluxHLL() = FluxHLL(min_max_speed_davis)354355"""356min_max_speed_naive(u_ll, u_rr, orientation::Integer, equations)357min_max_speed_naive(u_ll, u_rr, normal_direction::AbstractVector, equations)358359Simple and fast estimate(!) of the minimal and maximal wave speed of the Riemann problem with360left and right states `u_ll, u_rr`, usually based only on the local wave speeds associated to361`u_ll` and `u_rr`.362Slightly more diffusive than [`min_max_speed_davis`](@ref).363- Amiram Harten, Peter D. Lax, Bram van Leer (1983)364On Upstream Differencing and Godunov-Type Schemes for Hyperbolic Conservation Laws365[DOI: 10.1137/1025002](https://doi.org/10.1137/1025002)366367See eq. (10.37) from368- Eleuterio F. Toro (2009)369Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction370[DOI: 10.1007/b79761](https://doi.org/10.1007/b79761)371372See also [`FluxHLL`](@ref), [`min_max_speed_davis`](@ref), [`min_max_speed_einfeldt`](@ref).373"""374function min_max_speed_naive end375376"""377min_max_speed_davis(u_ll, u_rr, orientation::Integer, equations)378min_max_speed_davis(u_ll, u_rr, normal_direction::AbstractVector, equations)379380Simple and fast estimates of the minimal and maximal wave speed of the Riemann problem with381left and right states `u_ll, u_rr`, usually based only on the local wave speeds associated to382`u_ll` and `u_rr`.383384- S.F. Davis (1988)385Simplified Second-Order Godunov-Type Methods386[DOI: 10.1137/0909030](https://doi.org/10.1137/0909030)387388See eq. (10.38) from389- Eleuterio F. Toro (2009)390Riemann Solvers and Numerical Methods for Fluid Dynamics: A Practical Introduction391[DOI: 10.1007/b79761](https://doi.org/10.1007/b79761)392See also [`FluxHLL`](@ref), [`min_max_speed_naive`](@ref), [`min_max_speed_einfeldt`](@ref).393"""394function min_max_speed_davis end395396"""397min_max_speed_einfeldt(u_ll, u_rr, orientation::Integer, equations)398min_max_speed_einfeldt(u_ll, u_rr, normal_direction::AbstractVector, equations)399400More advanced mininmal and maximal wave speed computation based on401- Bernd Einfeldt (1988)402On Godunov-type methods for gas dynamics.403[DOI: 10.1137/0725021](https://doi.org/10.1137/0725021)404- Bernd Einfeldt, Claus-Dieter Munz, Philip L. Roe and Björn Sjögreen (1991)405On Godunov-type methods near low densities.406[DOI: 10.1016/0021-9991(91)90211-3](https://doi.org/10.1016/0021-9991(91)90211-3)407408originally developed for the compressible Euler equations.409A compact representation can be found in [this lecture notes, eq. (9.28)](https://metaphor.ethz.ch/x/2019/hs/401-4671-00L/literature/mishra_hyperbolic_pdes.pdf).410411See also [`FluxHLL`](@ref), [`min_max_speed_naive`](@ref), [`min_max_speed_davis`](@ref).412"""413function min_max_speed_einfeldt end414415@inline function (numflux::FluxHLL)(u_ll, u_rr, orientation_or_normal_direction,416equations)417λ_min, λ_max = numflux.min_max_speed(u_ll, u_rr, orientation_or_normal_direction,418equations)419420if λ_min >= 0 && λ_max >= 0421return flux(u_ll, orientation_or_normal_direction, equations)422elseif λ_max <= 0 && λ_min <= 0423return flux(u_rr, orientation_or_normal_direction, equations)424else425f_ll = flux(u_ll, orientation_or_normal_direction, equations)426f_rr = flux(u_rr, orientation_or_normal_direction, equations)427inv_λ_max_minus_λ_min = inv(λ_max - λ_min)428factor_ll = λ_max * inv_λ_max_minus_λ_min429factor_rr = λ_min * inv_λ_max_minus_λ_min430factor_diss = λ_min * λ_max * inv_λ_max_minus_λ_min431return factor_ll * f_ll - factor_rr * f_rr + factor_diss * (u_rr - u_ll)432end433end434435Base.show(io::IO, numflux::FluxHLL) = print(io, "FluxHLL(", numflux.min_max_speed, ")")436437"""438flux_hll439440See [`FluxHLL`](@ref).441"""442const flux_hll = FluxHLL()443444"""445flux_hlle446447See [`min_max_speed_einfeldt`](@ref).448This is a [`FluxHLL`](@ref)-type two-wave solver with special estimates of the wave speeds.449"""450const flux_hlle = FluxHLL(min_max_speed_einfeldt)451452"""453flux_shima_etal_turbo(u_ll, u_rr, orientation_or_normal_direction, equations)454455Equivalent to [`flux_shima_etal`](@ref) except that it may use specialized456methods, e.g., when used with [`VolumeIntegralFluxDifferencing`](@ref).457These specialized methods may enable better use of SIMD instructions to458increase runtime efficiency on modern hardware.459"""460@inline function flux_shima_etal_turbo(u_ll, u_rr, orientation_or_normal_direction,461equations)462flux_shima_etal(u_ll, u_rr, orientation_or_normal_direction, equations)463end464465"""466flux_ranocha_turbo(u_ll, u_rr, orientation_or_normal_direction, equations)467468Equivalent to [`flux_ranocha`](@ref) except that it may use specialized469methods, e.g., when used with [`VolumeIntegralFluxDifferencing`](@ref).470These specialized methods may enable better use of SIMD instructions to471increase runtime efficiency on modern hardware.472"""473@inline function flux_ranocha_turbo(u_ll, u_rr, orientation_or_normal_direction,474equations)475flux_ranocha(u_ll, u_rr, orientation_or_normal_direction, equations)476end477478"""479flux_wintermeyer_etal(u_ll, u_rr, orientation_or_normal_direction, equations)480481Total energy conservative (mathematical entropy for shallow water equations) split form.482When the bottom topography is nonzero this scheme will be well-balanced when used as a `volume_flux`.483For the `surface_flux` either [`flux_wintermeyer_etal`](@ref) or [`flux_fjordholm_etal`](@ref) can484be used to ensure well-balancedness and entropy conservation.485486!!! note487This function is defined in Trixi.jl to have a common interface for the488methods implemented in the subpackages [TrixiAtmo.jl](https://github.com/trixi-framework/TrixiAtmo.jl)489and [TrixiShallowWater.jl](https://github.com/trixi-framework/TrixiShallowWater.jl).490"""491function flux_wintermeyer_etal end492493"""494flux_nonconservative_wintermeyer_etal(u_ll, u_rr, orientation_or_normal_direction, equations)495496Non-symmetric two-point volume flux discretizing the nonconservative (source) term497that contains the gradient of the bottom topography for the shallow water equations.498499Gives entropy conservation and well-balancedness on both the volume and surface when combined with500[`flux_wintermeyer_etal`](@ref).501502!!! note503This function is defined in Trixi.jl to have a common interface for the504methods implemented in the subpackages [TrixiAtmo.jl](https://github.com/trixi-framework/TrixiAtmo.jl)505and [TrixiShallowWater.jl](https://github.com/trixi-framework/TrixiShallowWater.jl).506"""507function flux_nonconservative_wintermeyer_etal end508509"""510flux_fjordholm_etal(u_ll, u_rr, orientation_or_normal_direction, equations)511512Total energy conservative (mathematical entropy for shallow water equations). When the bottom topography513is nonzero this should only be used as a surface flux otherwise the scheme will not be well-balanced.514For well-balancedness in the volume flux use [`flux_wintermeyer_etal`](@ref).515516!!! note517This function is defined in Trixi.jl to have a common interface for the518methods implemented in the subpackages [TrixiAtmo.jl](https://github.com/trixi-framework/TrixiAtmo.jl)519and [TrixiShallowWater.jl](https://github.com/trixi-framework/TrixiShallowWater.jl).520"""521function flux_fjordholm_etal end522523"""524flux_nonconservative_fjordholm_etal(u_ll, u_rr, orientation_or_normal_direction, equations)525526Non-symmetric two-point surface flux discretizing the nonconservative (source) term of527that contains the gradient of the bottom topography for the shallow water equations.528529This flux can be used together with [`flux_fjordholm_etal`](@ref) at interfaces to ensure entropy530conservation and well-balancedness.531532!!! note533This function is defined in Trixi.jl to have a common interface for the534methods implemented in the subpackages [TrixiAtmo.jl](https://github.com/trixi-framework/TrixiAtmo.jl)535and [TrixiShallowWater.jl](https://github.com/trixi-framework/TrixiShallowWater.jl).536"""537function flux_nonconservative_fjordholm_etal end538539"""540FluxUpwind(splitting)541542A numerical flux `f(u_left, u_right) = f⁺(u_left) + f⁻(u_right)` based on543flux vector splitting.544545The [`SurfaceIntegralUpwind`](@ref) with a given `splitting` is equivalent to546the [`SurfaceIntegralStrongForm`](@ref) with `FluxUpwind(splitting)`547as numerical flux (up to floating point differences). Note, that548[`SurfaceIntegralUpwind`](@ref) is only available on [`TreeMesh`](@ref).549550!!! warning "Experimental implementation (upwind SBP)"551This is an experimental feature and may change in future releases.552"""553struct FluxUpwind{Splitting}554splitting::Splitting555end556557@inline function (numflux::FluxUpwind)(u_ll, u_rr, orientation::Int, equations)558@unpack splitting = numflux559fm = splitting(u_rr, Val{:minus}(), orientation, equations)560fp = splitting(u_ll, Val{:plus}(), orientation, equations)561return fm + fp562end563564@inline function (numflux::FluxUpwind)(u_ll, u_rr,565normal_direction::AbstractVector,566equations::AbstractEquations{2})567@unpack splitting = numflux568f_tilde_m = splitting(u_rr, Val{:minus}(), normal_direction, equations)569f_tilde_p = splitting(u_ll, Val{:plus}(), normal_direction, equations)570return f_tilde_m + f_tilde_p571end572573Base.show(io::IO, f::FluxUpwind) = print(io, "FluxUpwind(", f.splitting, ")")574end # @muladd575576577