Path: blob/main/src/equations/compressible_navier_stokes_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"""8CompressibleNavierStokesDiffusion3D(equations; mu, Pr,9gradient_variables=GradientVariablesPrimitive())1011Contains the diffusion (i.e. parabolic) terms applied12to mass, momenta, and total energy together with the advective terms from13the [`CompressibleEulerEquations3D`](@ref).1415- `equations`: instance of the [`CompressibleEulerEquations3D`](@ref)16- `mu`: dynamic viscosity,17- `Pr`: Prandtl number,18- `gradient_variables`: which variables the gradients are taken with respect to.19Defaults to [`GradientVariablesPrimitive()`](@ref).20For an entropy stable formulation, use [`GradientVariablesEntropy()`](@ref).2122Fluid properties such as the dynamic viscosity ``\mu`` can be provided in any consistent unit system, e.g.,23[``\mu``] = kg m⁻¹ s⁻¹.24The viscosity ``\mu`` may be a constant or a function of the current state, e.g.,25depending on temperature (Sutherland's law): ``\mu = \mu(T)``.26In the latter case, the function `mu` needs to have the signature `mu(u, equations)`.2728The particular form of the compressible Navier-Stokes implemented is29```math30\frac{\partial}{\partial t}31\begin{pmatrix}32\rho \\ \rho \mathbf{v} \\ \rho e33\end{pmatrix}34+35\nabla \cdot36\begin{pmatrix}37\rho \mathbf{v} \\ \rho \mathbf{v}\mathbf{v}^T + p \underline{I} \\ (\rho e + p) \mathbf{v}38\end{pmatrix}39=40\nabla \cdot41\begin{pmatrix}420 \\ \underline{\tau} \\ \underline{\tau}\mathbf{v} - \mathbf{q}43\end{pmatrix}44```45where the system is closed with the ideal gas assumption giving46```math47p = (\gamma - 1) \left( \rho e - \frac{1}{2} \rho (v_1^2+v_2^2+v_3^2) \right)48```49as the pressure. The value of the adiabatic constant `gamma` is taken from the [`CompressibleEulerEquations2D`](@ref).50The terms on the right hand side of the system above51are built from the viscous stress tensor52```math53\underline{\tau} = \mu \left(\nabla\mathbf{v} + \left(\nabla\mathbf{v}\right)^T\right) - \frac{2}{3} \mu \left(\nabla\cdot\mathbf{v}\right)\underline{I}54```55where ``\underline{I}`` is the ``3\times 3`` identity matrix and the heat flux is56```math57\mathbf{q} = -\kappa\nabla\left(T\right),\quad T = \frac{p}{R\rho}58```59where ``T`` is the temperature and ``\kappa`` is the thermal conductivity for Fick's law.60Under the assumption that the gas has a constant Prandtl number,61the thermal conductivity is62```math63\kappa = \frac{\gamma \mu R}{(\gamma - 1)\textrm{Pr}}.64```65From this combination of temperature ``T`` and thermal conductivity ``\kappa`` we see66that the gas constant `R` cancels and the heat flux becomes67```math68\mathbf{q} = -\kappa\nabla\left(T\right) = -\frac{\gamma \mu}{(\gamma - 1)\textrm{Pr}}\nabla\left(\frac{p}{\rho}\right)69```70which is the form implemented below in the [`flux`](@ref) function.7172In two spatial dimensions we require gradients for three quantities, e.g.,73primitive quantities74```math75\nabla v_1,\, \nabla v_2,\, \nabla v_3,\, \nabla T76```77or the entropy variables78```math79\nabla w_2,\, \nabla w_3,\, \nabla w_4\, \nabla w_580```81where82```math83w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = \frac{\rho v_3}{p},\, w_5 = -\frac{\rho}{p}84```85"""86struct CompressibleNavierStokesDiffusion3D{GradientVariables, RealT <: Real, Mu,87E <: AbstractCompressibleEulerEquations{3}} <:88AbstractCompressibleNavierStokesDiffusion{3, 5, GradientVariables}89# TODO: parabolic90# 1) For now save gamma and inv(gamma-1) again, but could potentially reuse them from the Euler equations91# 2) Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function92gamma::RealT # ratio of specific heats93inv_gamma_minus_one::RealT # = inv(gamma - 1); can be used to write slow divisions as fast multiplications9495mu::Mu # viscosity96Pr::RealT # Prandtl number97kappa::RealT # thermal diffusivity for Fick's law9899equations_hyperbolic::E # CompressibleEulerEquations3D100gradient_variables::GradientVariables # GradientVariablesPrimitive or GradientVariablesEntropy101end102103# default to primitive gradient variables104function CompressibleNavierStokesDiffusion3D(equations::CompressibleEulerEquations3D;105mu, Prandtl,106gradient_variables = GradientVariablesPrimitive())107gamma = equations.gamma108inv_gamma_minus_one = equations.inv_gamma_minus_one109110# Under the assumption of constant Prandtl number the thermal conductivity111# constant is kappa = gamma μ / ((gamma-1) Prandtl).112# Important note! Factor of μ is accounted for later in `flux`.113# This avoids recomputation of kappa for non-constant μ.114kappa = gamma * inv_gamma_minus_one / Prandtl115116CompressibleNavierStokesDiffusion3D{typeof(gradient_variables), typeof(gamma),117typeof(mu),118typeof(equations)}(gamma, inv_gamma_minus_one,119mu, Prandtl, kappa,120equations,121gradient_variables)122end123124# TODO: parabolic125# This is the flexibility a user should have to select the different gradient variable types126# varnames(::typeof(cons2prim) , ::CompressibleNavierStokesDiffusion3D) = ("v1", "v2", "v3", "T")127# varnames(::typeof(cons2entropy), ::CompressibleNavierStokesDiffusion3D) = ("w2", "w3", "w4", "w5")128129function varnames(variable_mapping,130equations_parabolic::CompressibleNavierStokesDiffusion3D)131varnames(variable_mapping, equations_parabolic.equations_hyperbolic)132end133134# we specialize this function to compute gradients of primitive variables instead of135# conservative variables.136function gradient_variable_transformation(::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})137cons2prim138end139function gradient_variable_transformation(::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy})140cons2entropy141end142143# Explicit formulas for the diffusive Navier-Stokes fluxes are available, e.g., in Section 2144# of the paper by Rueda-Ramírez, Hennemann, Hindenlang, Winters, and Gassner145# "An Entropy Stable Nodal Discontinuous Galerkin Method for the resistive146# MHD Equations. Part II: Subcell Finite Volume Shock Capturing"147# where one sets the magnetic field components equal to 0.148function flux(u, gradients, orientation::Integer,149equations::CompressibleNavierStokesDiffusion3D)150# Here, `u` is assumed to be the "transformed" variables specified by `gradient_variable_transformation`.151_, v1, v2, v3, _ = convert_transformed_to_primitive(u, equations)152# Here `gradients` is assumed to contain the gradients of the primitive variables (rho, v1, v2, v3, T)153# either computed directly or reverse engineered from the gradient of the entropy variables154# by way of the `convert_gradient_variables` function.155_, dv1dx, dv2dx, dv3dx, dTdx = convert_derivative_to_primitive(u, gradients[1],156equations)157_, dv1dy, dv2dy, dv3dy, dTdy = convert_derivative_to_primitive(u, gradients[2],158equations)159_, dv1dz, dv2dz, dv3dz, dTdz = convert_derivative_to_primitive(u, gradients[3],160equations)161162# Components of viscous stress tensor163164# Diagonal parts165# (4 * (v1)_x / 3 - 2 * ((v2)_y + (v3)_z)) / 3)166tau_11 = 4 * dv1dx / 3 - 2 * (dv2dy + dv3dz) / 3167# (4 * (v2)_y / 3 - 2 * ((v1)_x + (v3)_z) / 3)168tau_22 = 4 * dv2dy / 3 - 2 * (dv1dx + dv3dz) / 3169# (4 * (v3)_z / 3 - 2 * ((v1)_x + (v2)_y) / 3)170tau_33 = 4 * dv3dz / 3 - 2 * (dv1dx + dv2dy) / 3171172# Off diagonal parts, exploit that stress tensor is symmetric173# ((v1)_y + (v2)_x)174tau_12 = dv1dy + dv2dx # = tau_21175# ((v1)_z + (v3)_x)176tau_13 = dv1dz + dv3dx # = tau_31177# ((v2)_z + (v3)_y)178tau_23 = dv2dz + dv3dy # = tau_32179180# Fick's law q = -kappa * grad(T) = -kappa * grad(p / (R rho))181# with thermal diffusivity constant kappa = gamma μ R / ((gamma-1) Pr)182# Note, the gas constant cancels under this formulation, so it is not present183# in the implementation184q1 = equations.kappa * dTdx185q2 = equations.kappa * dTdy186q3 = equations.kappa * dTdz187188# In the simplest cases, the user passed in `mu` or `mu()`189# (which returns just a constant) but190# more complex functions like Sutherland's law are possible.191# `dynamic_viscosity` is a helper function that handles both cases192# by dispatching on the type of `equations.mu`.193mu = dynamic_viscosity(u, equations)194195if orientation == 1196# viscous flux components in the x-direction197f1 = 0198f2 = tau_11 * mu199f3 = tau_12 * mu200f4 = tau_13 * mu201f5 = (v1 * tau_11 + v2 * tau_12 + v3 * tau_13 + q1) * mu202203return SVector(f1, f2, f3, f4, f5)204elseif orientation == 2205# viscous flux components in the y-direction206# Note, symmetry is exploited for tau_12 = tau_21207g1 = 0208g2 = tau_12 * mu # tau_21 * mu209g3 = tau_22 * mu210g4 = tau_23 * mu211g5 = (v1 * tau_12 + v2 * tau_22 + v3 * tau_23 + q2) * mu212213return SVector(g1, g2, g3, g4, g5)214else # if orientation == 3215# viscous flux components in the z-direction216# Note, symmetry is exploited for tau_13 = tau_31, tau_23 = tau_32217h1 = 0218h2 = tau_13 * mu # tau_31 * mu219h3 = tau_23 * mu # tau_32 * mu220h4 = tau_33 * mu221h5 = (v1 * tau_13 + v2 * tau_23 + v3 * tau_33 + q3) * mu222223return SVector(h1, h2, h3, h4, h5)224end225end226227# Convert conservative variables to primitive228@inline function cons2prim(u, equations::CompressibleNavierStokesDiffusion3D)229rho, rho_v1, rho_v2, rho_v3, _ = u230231v1 = rho_v1 / rho232v2 = rho_v2 / rho233v3 = rho_v3 / rho234T = temperature(u, equations)235236return SVector(rho, v1, v2, v3, T)237end238239# Convert conservative variables to entropy240# TODO: parabolic. We can improve efficiency by not computing w_1, which involves logarithms241# This can be done by specializing `cons2entropy` and `entropy2cons` to `CompressibleNavierStokesDiffusion2D`,242# but this may be confusing to new users.243function cons2entropy(u, equations::CompressibleNavierStokesDiffusion3D)244cons2entropy(u, equations.equations_hyperbolic)245end246function entropy2cons(w, equations::CompressibleNavierStokesDiffusion3D)247entropy2cons(w, equations.equations_hyperbolic)248end249250# the `flux` function takes in transformed variables `u` which depend on the type of the gradient variables.251# For CNS, it is simplest to formulate the viscous terms in primitive variables, so we transform the transformed252# variables into primitive variables.253@inline function convert_transformed_to_primitive(u_transformed,254equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})255return u_transformed256end257258# TODO: parabolic. Make this more efficient!259@inline function convert_transformed_to_primitive(u_transformed,260equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy})261# note: this uses CompressibleNavierStokesDiffusion3D versions of cons2prim and entropy2cons262return cons2prim(entropy2cons(u_transformed, equations), equations)263end264265# Takes the solution values `u` and gradient of the entropy variables (w_2, w_3, w_4, w_5) and266# reverse engineers the gradients to be terms of the primitive variables (v1, v2, v3, T).267# Helpful because then the diffusive fluxes have the same form as on paper.268# Note, the first component of `gradient_entropy_vars` contains gradient(rho) which is unused.269# TODO: parabolic; entropy stable viscous terms270@inline function convert_derivative_to_primitive(u, gradient,271::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})272return gradient273end274275# the first argument is always the "transformed" variables.276@inline function convert_derivative_to_primitive(w, gradient_entropy_vars,277equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy})278279# TODO: parabolic. This is inefficient to pass in transformed variables but then transform them back.280# We can fix this if we directly compute v1, v2, v3, T from the entropy variables281u = entropy2cons(w, equations) # calls a "modified" entropy2cons defined for CompressibleNavierStokesDiffusion3D282rho, rho_v1, rho_v2, rho_v3, _ = u283284v1 = rho_v1 / rho285v2 = rho_v2 / rho286v3 = rho_v3 / rho287T = temperature(u, equations)288289return SVector(gradient_entropy_vars[1],290T * (gradient_entropy_vars[2] + v1 * gradient_entropy_vars[5]), # grad(u) = T*(grad(w_2)+v1*grad(w_5))291T * (gradient_entropy_vars[3] + v2 * gradient_entropy_vars[5]), # grad(v) = T*(grad(w_3)+v2*grad(w_5))292T * (gradient_entropy_vars[4] + v3 * gradient_entropy_vars[5]), # grad(v) = T*(grad(w_4)+v3*grad(w_5))293T * T * gradient_entropy_vars[5])294end295296# This routine is required because `prim2cons` is called in `initial_condition`, which297# is called with `equations::CompressibleEulerEquations3D`. This means it is inconsistent298# with `cons2prim(..., ::CompressibleNavierStokesDiffusion3D)` as defined above.299# TODO: parabolic. Is there a way to clean this up?300@inline function prim2cons(u, equations::CompressibleNavierStokesDiffusion3D)301prim2cons(u, equations.equations_hyperbolic)302end303304@inline function temperature(u, equations::CompressibleNavierStokesDiffusion3D)305rho, rho_v1, rho_v2, rho_v3, rho_e = u306307p = (equations.gamma - 1) * (rho_e - 0.5f0 * (rho_v1^2 + rho_v2^2 + rho_v3^2) / rho)308T = p / rho309return T310end311312@inline function velocity(u, equations::CompressibleNavierStokesDiffusion3D)313rho = u[1]314v1 = u[2] / rho315v2 = u[3] / rho316v3 = u[4] / rho317return SVector(v1, v2, v3)318end319320@doc raw"""321enstrophy(u, gradients, equations::CompressibleNavierStokesDiffusion3D)322323Computes the (node-wise) enstrophy, defined as324```math325\mathcal{E} = \frac{1}{2} \rho \boldsymbol{\omega} \cdot \boldsymbol{\omega}326```327where ``\boldsymbol{\omega} = \nabla \times \boldsymbol{v}`` is the [`vorticity`](@ref).328In 3D, ``\boldsymbol{\omega}`` is a full three-component vector.329"""330@inline function enstrophy(u, gradients, equations::CompressibleNavierStokesDiffusion3D)331# Enstrophy is 0.5 rho ω⋅ω where ω = ∇ × v332333omega = vorticity(u, gradients, equations)334return 0.5f0 * u[1] * (omega[1]^2 + omega[2]^2 + omega[3]^2)335end336337@doc raw"""338vorticity(u, gradients, equations::CompressibleNavierStokesDiffusion3D)339340Computes the (node-wise) vorticity, defined in 3D as341```math342\boldsymbol{\omega} = \nabla \times \boldsymbol{v} =343\begin{pmatrix}344\frac{\partial v_3}{\partial y} - \frac{\partial v_2}{\partial z} \\345\frac{\partial v_1}{\partial z} - \frac{\partial v_3}{\partial x} \\346\frac{\partial v_2}{\partial x} - \frac{\partial v_1}{\partial y}347\end{pmatrix}348```349"""350@inline function vorticity(u, gradients, equations::CompressibleNavierStokesDiffusion3D)351# Ensure that we have velocity `gradients` by way of the `convert_gradient_variables` function.352_, _, dv2dx, dv3dx, _ = convert_derivative_to_primitive(u, gradients[1], equations)353_, dv1dy, _, dv3dy, _ = convert_derivative_to_primitive(u, gradients[2], equations)354_, dv1dz, dv2dz, _, _ = convert_derivative_to_primitive(u, gradients[3], equations)355356return SVector(dv3dy - dv2dz, dv1dz - dv3dx, dv2dx - dv1dy)357end358359@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,360<:Adiabatic})(flux_inner,361u_inner,362normal::AbstractVector,363x,364t,365operator_type::Gradient,366equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})367v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,368t,369equations)370return SVector(u_inner[1], v1, v2, v3, u_inner[5])371end372373@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,374<:Adiabatic})(flux_inner,375u_inner,376normal::AbstractVector,377x,378t,379operator_type::Divergence,380equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})381normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x,382t,383equations)384v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,385t,386equations)387_, tau_1n, tau_2n, tau_3n, _ = flux_inner # extract fluxes for 2nd, 3rd, and 4th equations388normal_energy_flux = v1 * tau_1n + v2 * tau_2n + v3 * tau_3n + normal_heat_flux389return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4],390normal_energy_flux)391end392393@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,394<:Isothermal})(flux_inner,395u_inner,396normal::AbstractVector,397x,398t,399operator_type::Gradient,400equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})401v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,402t,403equations)404T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t,405equations)406return SVector(u_inner[1], v1, v2, v3, T)407end408409@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,410<:Isothermal})(flux_inner,411u_inner,412normal::AbstractVector,413x,414t,415operator_type::Divergence,416equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})417return flux_inner418end419420# specialized BC impositions for GradientVariablesEntropy.421422# This should return a SVector containing the boundary values of entropy variables.423# Here, `w_inner` are the transformed variables (e.g., entropy variables).424#425# Taken from "Entropy stable modal discontinuous Galerkin schemes and wall boundary conditions426# for the compressible Navier-Stokes equations" by Chan, Lin, Warburton 2022.427# DOI: 10.1016/j.jcp.2021.110723428@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,429<:Adiabatic})(flux_inner,430w_inner,431normal::AbstractVector,432x,433t,434operator_type::Gradient,435equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy})436v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,437t,438equations)439negative_rho_inv_p = w_inner[5] # w_5 = -rho / p440return SVector(w_inner[1], -v1 * negative_rho_inv_p, -v2 * negative_rho_inv_p,441-v3 * negative_rho_inv_p, negative_rho_inv_p)442end443444# this is actually identical to the specialization for GradientVariablesPrimitive, but included for completeness.445@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,446<:Adiabatic})(flux_inner,447w_inner,448normal::AbstractVector,449x,450t,451operator_type::Divergence,452equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy})453normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x,454t,455equations)456v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,457t,458equations)459_, tau_1n, tau_2n, tau_3n, _ = flux_inner # extract fluxes for 2nd, 3rd, and 4th equations460normal_energy_flux = v1 * tau_1n + v2 * tau_2n + v3 * tau_3n + normal_heat_flux461return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4],462normal_energy_flux)463end464465@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,466<:Isothermal})(flux_inner,467w_inner,468normal::AbstractVector,469x,470t,471operator_type::Gradient,472equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy})473v1, v2, v3 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,474t,475equations)476T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t,477equations)478479# the entropy variables w2 = rho * v1 / p = v1 / T = -v1 * w5. Similarly for w3 and w4480w5 = -1 / T481return SVector(w_inner[1], -v1 * w5, -v2 * w5, -v3 * w5, w5)482end483484@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,485<:Isothermal})(flux_inner,486w_inner,487normal::AbstractVector,488x,489t,490operator_type::Divergence,491equations::CompressibleNavierStokesDiffusion3D{GradientVariablesEntropy})492return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4],493flux_inner[5])494end495496# Computes the mirror velocity across a symmetry plane which enforces497# a tangential velocity that is aligned with the symmetry plane, i.e.,498# which is normal to the `normal_direction`.499# See also `boundary_condition_slip_wall` and `rotate_to_x`.500@inline function velocity_symmetry_plane(normal_direction::AbstractVector, v1, v2, v3)501norm_ = norm(normal_direction)502normal = normal_direction / norm_503504# Compute alignment of velocity with normal direction505v_normal = v1 * normal[1] + v2 * normal[2] + v3 * normal[3]506507v1_outer = v1 - 2 * v_normal * normal[1]508v2_outer = v2 - 2 * v_normal * normal[2]509v3_outer = v3 - 2 * v_normal * normal[3]510511return v1_outer, v2_outer, v3_outer512end513514# Note: This should be used with `boundary_condition_slip_wall` for the hyperbolic (Euler) part.515@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:Slip,516<:Adiabatic})(flux_inner,517u_inner,518normal::AbstractVector,519x,520t,521operator_type::Gradient,522equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})523v1_outer, v2_outer, v3_outer = velocity_symmetry_plane(normal,524u_inner[2],525u_inner[3],526u_inner[4])527528return SVector(u_inner[1], v1_outer, v2_outer, v3_outer, u_inner[5])529end530531# Note: This should be used with `boundary_condition_slip_wall` for the hyperbolic (Euler) part.532@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:Slip,533<:Adiabatic})(flux_inner,534u_inner,535normal::AbstractVector,536x,537t,538operator_type::Divergence,539equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})540normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x,541t,542equations)543# Normal stresses should be 0. This implies also that `normal_energy_flux = normal_heat_flux`.544# For details, see Section 4.2 of545# "Entropy stable modal discontinuous Galerkin schemes and wall boundary conditions546# for the compressible Navier-Stokes equations" by Chan, Lin, Warburton 2022.547# DOI: 10.1016/j.jcp.2021.110723548return SVector(flux_inner[1], 0, 0, 0, normal_heat_flux)549end550551# Dirichlet Boundary Condition for e.g. P4est mesh552@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner,553u_inner,554normal::AbstractVector,555x, t,556operator_type::Gradient,557equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})558# BCs are usually specified as conservative variables so we convert them to primitive variables559# because the gradients are assumed to be with respect to the primitive variables560u_boundary = boundary_condition.boundary_value_function(x, t, equations)561562return cons2prim(u_boundary, equations)563end564565@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner,566u_inner,567normal::AbstractVector,568x, t,569operator_type::Divergence,570equations::CompressibleNavierStokesDiffusion3D{GradientVariablesPrimitive})571# for Dirichlet boundary conditions, we do not impose any conditions on the viscous fluxes572return flux_inner573end574end # @muladd575576577