Path: blob/main/src/equations/compressible_navier_stokes_2d.jl
5586 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"""8CompressibleNavierStokesDiffusion2D(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 [`CompressibleEulerEquations2D`](@ref).1415- `equations`: instance of the [`CompressibleEulerEquations2D`](@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 e_{\text{total}}33\end{pmatrix}34+35\nabla \cdot36\begin{pmatrix}37\rho \mathbf{v} \\ \rho \mathbf{v}\mathbf{v}^T + p \underline{I} \\ (\rho e_{\text{total}} + 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_{\text{total}} - \frac{1}{2} \rho (v_1^2+v_2^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 ``2\times 2`` 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 Fourier'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 T76```77or the entropy variables78```math79\nabla w_2,\, \nabla w_3,\, \nabla w_480```81where82```math83w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p}84```85"""86struct CompressibleNavierStokesDiffusion2D{GradientVariables, RealT <: Real, Mu,87E <: AbstractCompressibleEulerEquations{2}} <:88AbstractCompressibleNavierStokesDiffusion{2, 4, GradientVariables}89# TODO: parabolic90# Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function9192mu::Mu # viscosity93Pr::RealT # Prandtl number94kappa::RealT # thermal diffusivity for Fourier's law95max_4over3_kappa::RealT # max(4/3, kappa) used for parabolic cfl => `max_diffusivity`9697equations_hyperbolic::E # CompressibleEulerEquations2D98gradient_variables::GradientVariables # GradientVariablesPrimitive or GradientVariablesEntropy99end100101# default to primitive gradient variables102function CompressibleNavierStokesDiffusion2D(equations::CompressibleEulerEquations2D;103mu, Prandtl,104gradient_variables = GradientVariablesPrimitive())105@unpack gamma, inv_gamma_minus_one = equations106107Pr = promote_type(typeof(gamma), typeof(Prandtl))(Prandtl)108# Under the assumption of constant Prandtl number the thermal conductivity109# constant is kappa = gamma μ / ((gamma-1) Prandtl).110# Important note! Factor of μ is accounted for later in `flux`.111# This avoids recomputation of kappa for non-constant μ.112kappa = gamma * inv_gamma_minus_one / Pr113114return CompressibleNavierStokesDiffusion2D{typeof(gradient_variables),115typeof(Pr), typeof(mu),116typeof(equations)}(mu, Pr, kappa,117max(4 / 3, kappa),118equations,119gradient_variables)120end121122# TODO: parabolic123# This is the flexibility a user should have to select the different gradient variable types124# varnames(::typeof(cons2prim) , ::CompressibleNavierStokesDiffusion2D) = ("v1", "v2", "T")125# varnames(::typeof(cons2entropy), ::CompressibleNavierStokesDiffusion2D) = ("w2", "w3", "w4")126127function varnames(variable_mapping,128equations_parabolic::CompressibleNavierStokesDiffusion2D)129return varnames(variable_mapping, equations_parabolic.equations_hyperbolic)130end131132# we specialize this function to compute gradients of primitive variables instead of133# conservative variables.134function gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})135return cons2prim136end137function gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})138return cons2entropy139end140141# Explicit formulas for the diffusive Navier-Stokes fluxes are available, e.g., in Section 2142# of the paper by Rueda-Ramírez, Hennemann, Hindenlang, Winters, and Gassner143# "An Entropy Stable Nodal Discontinuous Galerkin Method for the resistive144# MHD Equations. Part II: Subcell Finite Volume Shock Capturing"145# where one sets the magnetic field components equal to 0.146function flux(u, gradients, orientation::Integer,147equations::CompressibleNavierStokesDiffusion2D)148# Here, `u` is assumed to be the "transformed" variables specified by `gradient_variable_transformation`.149_, v1, v2, _ = convert_transformed_to_primitive(u, equations)150# Here `gradients` is assumed to contain the gradients of the primitive variables (rho, v1, v2, T)151# either computed directly or reverse engineered from the gradient of the entropy variables152# by way of the `convert_gradient_variables` function.153_, dv1dx, dv2dx, dTdx = convert_derivative_to_primitive(u, gradients[1], equations)154_, dv1dy, dv2dy, dTdy = convert_derivative_to_primitive(u, gradients[2], equations)155156# Components of viscous stress tensor157158# (4 * (v1)_x / 3 - 2 * (v2)_y / 3)159tau_11 = (4 * dv1dx - 2 * dv2dy) / 3160# ((v1)_y + (v2)_x)161# stress tensor is symmetric162tau_12 = dv1dy + dv2dx # = tau_21163# (4/3 * (v2)_y - 2/3 * (v1)_x)164tau_22 = (4 * dv2dy - 2 * dv1dx) / 3165166# Fourier's law q = -kappa * grad(T) = -kappa * grad(p / (R rho))167# with thermal diffusivity constant kappa = gamma μ R / ((gamma-1) Pr)168# Note, the gas constant cancels under this formulation, so it is not present169# in the implementation170q1 = equations.kappa * dTdx171q2 = equations.kappa * dTdy172173# In the simplest cases, the user passed in `mu` or `mu()`174# (which returns just a constant) but175# more complex functions like Sutherland's law are possible.176# `dynamic_viscosity` is a helper function that handles both cases177# by dispatching on the type of `equations.mu`.178mu = dynamic_viscosity(u, equations)179180if orientation == 1181# parabolic flux components in the x-direction182f1 = 0183f2 = tau_11 * mu184f3 = tau_12 * mu185f4 = (v1 * tau_11 + v2 * tau_12 + q1) * mu186187return SVector(f1, f2, f3, f4)188else # if orientation == 2189# parabolic flux components in the y-direction190# Note, symmetry is exploited for tau_12 = tau_21191g1 = 0192g2 = tau_12 * mu # tau_21 * mu193g3 = tau_22 * mu194g4 = (v1 * tau_12 + v2 * tau_22 + q2) * mu195196return SVector(g1, g2, g3, g4)197end198end199200@doc raw"""201max_diffusivity(u, equations_parabolic::CompressibleNavierStokesDiffusion2D)202203# Returns204- `dynamic_viscosity(u, equations_parabolic) / u[1] * equations_parabolic.max_4over3_kappa`205where `max_4over3_kappa = max(4/3, kappa)` is computed in the constructor.206207For the diffusive estimate we use the eigenvalues of the diffusivity matrix,208as suggested in Section 3.5 of209- Krais et. al (2021)210FLEXI: A high order discontinuous Galerkin framework for hyperbolic–parabolic conservation laws211[DOI: 10.1016/j.camwa.2020.05.004](https://doi.org/10.1016/j.camwa.2020.05.004)212213For details on the derivation of eigenvalues of the diffusivity matrix214for the compressible Navier-Stokes equations see for instance215- Richard P. Dwight (2006)216Efficiency improvements of RANS-based analysis and optimization using implicit and adjoint methods on unstructured grids217PhD Thesis, University of Manchester218https://elib.dlr.de/50794/1/rdwight-PhDThesis-ImplicitAndAdjoint.pdf219See especially equations (2.79), (3.24), and (3.25) from Chapter 3.2.3220221The eigenvalues of the diffusivity matrix in 2D are222``-\frac{\mu}{\rho} \{0, 4/3, 1, \kappa\}``223and thus the largest absolute eigenvalue is224``\frac{\mu}{\rho} \max(4/3, \kappa)``.225"""226@inline function max_diffusivity(u,227equations_parabolic::CompressibleNavierStokesDiffusion2D)228# See for instance also the computation in FLUXO:229# https://github.com/project-fluxo/fluxo/blob/c7e0cc9b7fd4569dcab67bbb6e5a25c0a84859f1/src/equation/navierstokes/calctimestep.f90#L122-L128230#231# Accordingly, the spectral radius/largest absolute eigenvalue can be computed as:232return dynamic_viscosity(u, equations_parabolic) / u[1] *233equations_parabolic.max_4over3_kappa234end235236# Convert conservative variables to primitive237@inline function cons2prim(u, equations::CompressibleNavierStokesDiffusion2D)238rho, rho_v1, rho_v2, _ = u239240v1 = rho_v1 / rho241v2 = rho_v2 / rho242T = temperature(u, equations)243244return SVector(rho, v1, v2, T)245end246247# Convert conservative variables to entropy248# TODO: parabolic. We can improve efficiency by not computing w_1, which involves logarithms249# This can be done by specializing `cons2entropy` and `entropy2cons` to `CompressibleNavierStokesDiffusion2D`,250# but this may be confusing to new users.251function cons2entropy(u, equations::CompressibleNavierStokesDiffusion2D)252return cons2entropy(u, equations.equations_hyperbolic)253end254function entropy2cons(w, equations::CompressibleNavierStokesDiffusion2D)255return entropy2cons(w, equations.equations_hyperbolic)256end257258# the `flux` function takes in transformed variables `u` which depend on the type of the gradient variables.259# For CNS, it is simplest to formulate the parabolic terms in primitive variables, so we transform the transformed260# variables into primitive variables.261@inline function convert_transformed_to_primitive(u_transformed,262equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})263return u_transformed264end265266# TODO: parabolic. Make this more efficient!267@inline function convert_transformed_to_primitive(u_transformed,268equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})269# note: this uses CompressibleNavierStokesDiffusion2D versions of cons2prim and entropy2cons270return cons2prim(entropy2cons(u_transformed, equations), equations)271end272273# Takes the solution values `u` and gradient of the entropy variables (w_2, w_3, w_4) and274# reverse engineers the gradients to be terms of the primitive variables (v1, v2, T).275# Helpful because then the diffusive fluxes have the same form as on paper.276# Note, the first component of `gradient_entropy_vars` contains gradient(rho) which is unused.277# TODO: parabolic; entropy stable parabolic terms278@inline function convert_derivative_to_primitive(u, gradient,279::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})280return gradient281end282283# the first argument is always the "transformed" variables.284@inline function convert_derivative_to_primitive(w, gradient_entropy_vars,285equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})286287# TODO: parabolic. This is inefficient to pass in transformed variables but then transform them back.288# We can fix this if we directly compute v1, v2, T from the entropy variables289u = entropy2cons(w, equations) # calls a "modified" entropy2cons defined for CompressibleNavierStokesDiffusion2D290rho, rho_v1, rho_v2, _ = u291292v1 = rho_v1 / rho293v2 = rho_v2 / rho294T = temperature(u, equations)295296return SVector(gradient_entropy_vars[1],297T * (gradient_entropy_vars[2] + v1 * gradient_entropy_vars[4]), # grad(u) = T*(grad(w_2)+v1*grad(w_4))298T * (gradient_entropy_vars[3] + v2 * gradient_entropy_vars[4]), # grad(v) = T*(grad(w_3)+v2*grad(w_4))299T * T * gradient_entropy_vars[4])300end301302# This routine is required because `prim2cons` is called in `initial_condition`, which303# is called with `equations::CompressibleEulerEquations2D`. This means it is inconsistent304# with `cons2prim(..., ::CompressibleNavierStokesDiffusion2D)` as defined above.305# TODO: parabolic. Is there a way to clean this up?306@inline function prim2cons(u, equations::CompressibleNavierStokesDiffusion2D)307return prim2cons(u, equations.equations_hyperbolic)308end309310"""311temperature(u, equations::CompressibleNavierStokesDiffusion2D)312313Compute the temperature from the conservative variables `u`.314In particular, this assumes a specific gas constant ``R = 1``:315```math316T = \\frac{p}{\\rho}317```318"""319@inline function temperature(u, equations::CompressibleNavierStokesDiffusion2D)320rho, rho_v1, rho_v2, rho_e_total = u321@unpack gamma = equations322323p = (gamma - 1) * (rho_e_total - 0.5f0 * (rho_v1^2 + rho_v2^2) / rho)324T = p / rho # Corresponds to a specific gas constant R = 1325return T326end327328@inline function velocity(u, equations::CompressibleNavierStokesDiffusion2D)329rho = u[1]330v1 = u[2] / rho331v2 = u[3] / rho332return SVector(v1, v2)333end334335@doc raw"""336enstrophy(u, gradients, equations::CompressibleNavierStokesDiffusion2D)337338Computes the (node-wise) enstrophy, defined as339```math340\mathcal{E} = \frac{1}{2} \rho \omega \cdot \omega341```342where ``\omega = \nabla \times \boldsymbol{v}`` is the [`vorticity`](@ref).343In 2D, ``\omega`` is just a scalar.344"""345@inline function enstrophy(u, gradients, equations::CompressibleNavierStokesDiffusion2D)346# Enstrophy is 0.5 rho ω⋅ω where ω = ∇ × v347348omega = vorticity(u, gradients, equations)349return 0.5f0 * u[1] * omega^2350end351352@doc raw"""353vorticity(u, gradients, equations::CompressibleNavierStokesDiffusion2D)354355Computes the (node-wise) vorticity, defined in 2D as356```math357\omega = \nabla \times \boldsymbol{v} = \frac{\partial v_2}{\partial x_1} - \frac{\partial v_1}{\partial x_2}358```359"""360@inline function vorticity(u, gradients, equations::CompressibleNavierStokesDiffusion2D)361# Ensure that we have velocity `gradients` by way of the `convert_gradient_variables` function.362_, _, dv2dx, _ = convert_derivative_to_primitive(u, gradients[1], equations)363_, dv1dy, _, _ = convert_derivative_to_primitive(u, gradients[2], equations)364365return dv2dx - dv1dy366end367368@inline function vorticity(u, gradients,369equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})370# Need to convert to entropy variables first for `convert_derivative_to_primitive` to work correctly.371w = cons2entropy(u, equations)372373# Ensure that we have velocity `gradients` by way of the `convert_gradient_variables` function.374_, _, dv2dx, _ = convert_derivative_to_primitive(w, gradients[1], equations)375_, dv1dy, _, _ = convert_derivative_to_primitive(w, gradients[2], equations)376377return dv2dx - dv1dy378end379380@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,381<:Adiabatic})(flux_inner,382u_inner,383normal::AbstractVector,384x,385t,386operator_type::Gradient,387equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})388v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,389t,390equations)391return SVector(u_inner[1], v1, v2, u_inner[4])392end393394@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,395<:Adiabatic})(flux_inner,396u_inner,397normal::AbstractVector,398x,399t,400operator_type::Divergence,401equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})402normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x,403t,404equations)405v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,406t,407equations)408_, tau_1n, tau_2n, _ = flux_inner # extract fluxes for 2nd and 3rd equations409normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux410return SVector(flux_inner[1], flux_inner[2], flux_inner[3], normal_energy_flux)411end412413@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,414<:Isothermal})(flux_inner,415u_inner,416normal::AbstractVector,417x,418t,419operator_type::Gradient,420equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})421v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,422t,423equations)424T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t,425equations)426return SVector(u_inner[1], v1, v2, T)427end428429@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,430<:Isothermal})(flux_inner,431u_inner,432normal::AbstractVector,433x,434t,435operator_type::Divergence,436equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})437return flux_inner438end439440# specialized BC impositions for GradientVariablesEntropy.441442# This should return a SVector containing the boundary values of entropy variables.443# Here, `w_inner` are the transformed variables (e.g., entropy variables).444#445# Taken from "Entropy stable modal discontinuous Galerkin schemes and wall boundary conditions446# for the compressible Navier-Stokes equations" by Chan, Lin, Warburton 2022.447# DOI: 10.1016/j.jcp.2021.110723448@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,449<:Adiabatic})(flux_inner,450w_inner,451normal::AbstractVector,452x,453t,454operator_type::Gradient,455equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})456v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,457t,458equations)459negative_rho_inv_p = w_inner[4] # w_4 = -rho / p460return SVector(w_inner[1], -v1 * negative_rho_inv_p, -v2 * negative_rho_inv_p,461negative_rho_inv_p)462end463464# this is actually identical to the specialization for GradientVariablesPrimitive, but included for completeness.465@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,466<:Adiabatic})(flux_inner,467w_inner,468normal::AbstractVector,469x,470t,471operator_type::Divergence,472equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})473normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x,474t,475equations)476v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,477t,478equations)479_, tau_1n, tau_2n, _ = flux_inner # extract fluxes for 2nd and 3rd equations480normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux481return SVector(flux_inner[1], flux_inner[2], flux_inner[3], normal_energy_flux)482end483484@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,485<:Isothermal})(flux_inner,486w_inner,487normal::AbstractVector,488x,489t,490operator_type::Gradient,491equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})492v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,493t,494equations)495T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t,496equations)497498# the entropy variables w2 = rho * v1 / p = v1 / T = -v1 * w4. Similarly for w3499w4 = -1 / T500return SVector(w_inner[1], -v1 * w4, -v2 * w4, w4)501end502503@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,504<:Isothermal})(flux_inner,505w_inner,506normal::AbstractVector,507x,508t,509operator_type::Divergence,510equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})511return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4])512end513514# Computes the mirror velocity across a symmetry plane which enforces515# a tangential velocity that is aligned with the symmetry plane, i.e.,516# which is normal to the `normal_direction`.517# See also `boundary_condition_slip_wall` and `rotate_to_x`.518@inline function velocity_symmetry_plane(normal_direction::AbstractVector, v1, v2)519norm_ = norm(normal_direction)520normal = normal_direction / norm_521522# Compute alignment of velocity with normal direction523v_normal = v1 * normal[1] + v2 * normal[2]524525v1_outer = v1 - 2 * v_normal * normal[1]526v2_outer = v2 - 2 * v_normal * normal[2]527528return v1_outer, v2_outer529end530531# 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::Gradient,539equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})540v1_outer, v2_outer = velocity_symmetry_plane(normal,541u_inner[2],542u_inner[3])543544return SVector(u_inner[1], v1_outer, v2_outer, u_inner[4])545end546547# Note: This should be used with `boundary_condition_slip_wall` for the hyperbolic (Euler) part.548@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:Slip,549<:Adiabatic})(flux_inner,550u_inner,551normal::AbstractVector,552x,553t,554operator_type::Divergence,555equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})556normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x,557t,558equations)559560# Normal stresses should be 0. This implies also that `normal_energy_flux = normal_heat_flux`.561# For details, see Section 4.2 of562# "Entropy stable modal discontinuous Galerkin schemes and wall boundary conditions563# for the compressible Navier-Stokes equations" by Chan, Lin, Warburton 2022.564# DOI: 10.1016/j.jcp.2021.110723565return SVector(flux_inner[1], 0, 0, normal_heat_flux)566end567568# Dirichlet Boundary Condition for e.g. P4est mesh569@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner,570u_inner,571normal::AbstractVector,572x, t,573operator_type::Gradient,574equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})575# BCs are usually specified as conservative variables so we convert them to primitive variables576# because the gradients are assumed to be with respect to the primitive variables577u_boundary = boundary_condition.boundary_value_function(x, t, equations)578579return cons2prim(u_boundary, equations)580end581582@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner,583u_inner,584normal::AbstractVector,585x, t,586operator_type::Divergence,587equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})588# for Dirichlet boundary conditions, we do not impose any conditions on the parabolic fluxes589return flux_inner590end591end # @muladd592593594