Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/src/equations/compressible_navier_stokes_2d.jl
5586 views
1
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).
2
# Since these FMAs can increase the performance of many numerical algorithms,
3
# we need to opt-in explicitly.
4
# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.
5
@muladd begin
6
#! format: noindent
7
8
@doc raw"""
9
CompressibleNavierStokesDiffusion2D(equations; mu, Pr,
10
gradient_variables=GradientVariablesPrimitive())
11
12
Contains the diffusion (i.e. parabolic) terms applied
13
to mass, momenta, and total energy together with the advective terms from
14
the [`CompressibleEulerEquations2D`](@ref).
15
16
- `equations`: instance of the [`CompressibleEulerEquations2D`](@ref)
17
- `mu`: dynamic viscosity,
18
- `Pr`: Prandtl number,
19
- `gradient_variables`: which variables the gradients are taken with respect to.
20
Defaults to [`GradientVariablesPrimitive()`](@ref).
21
For an entropy stable formulation, use [`GradientVariablesEntropy()`](@ref).
22
23
Fluid properties such as the dynamic viscosity ``\mu`` can be provided in any consistent unit system, e.g.,
24
[``\mu``] = kg m⁻¹ s⁻¹.
25
The viscosity ``\mu`` may be a constant or a function of the current state, e.g.,
26
depending on temperature (Sutherland's law): ``\mu = \mu(T)``.
27
In the latter case, the function `mu` needs to have the signature `mu(u, equations)`.
28
29
The particular form of the compressible Navier-Stokes implemented is
30
```math
31
\frac{\partial}{\partial t}
32
\begin{pmatrix}
33
\rho \\ \rho \mathbf{v} \\ \rho e_{\text{total}}
34
\end{pmatrix}
35
+
36
\nabla \cdot
37
\begin{pmatrix}
38
\rho \mathbf{v} \\ \rho \mathbf{v}\mathbf{v}^T + p \underline{I} \\ (\rho e_{\text{total}} + p) \mathbf{v}
39
\end{pmatrix}
40
=
41
\nabla \cdot
42
\begin{pmatrix}
43
0 \\ \underline{\tau} \\ \underline{\tau}\mathbf{v} - \mathbf{q}
44
\end{pmatrix}
45
```
46
where the system is closed with the ideal gas assumption giving
47
```math
48
p = (\gamma - 1) \left( \rho e_{\text{total}} - \frac{1}{2} \rho (v_1^2+v_2^2) \right)
49
```
50
as the pressure. The value of the adiabatic constant `gamma` is taken from the [`CompressibleEulerEquations2D`](@ref).
51
The terms on the right hand side of the system above
52
are built from the viscous stress tensor
53
```math
54
\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}
55
```
56
where ``\underline{I}`` is the ``2\times 2`` identity matrix and the heat flux is
57
```math
58
\mathbf{q} = -\kappa\nabla\left(T\right),\quad T = \frac{p}{R\rho}
59
```
60
where ``T`` is the temperature and ``\kappa`` is the thermal conductivity for Fourier's law.
61
Under the assumption that the gas has a constant Prandtl number,
62
the thermal conductivity is
63
```math
64
\kappa = \frac{\gamma \mu R}{(\gamma - 1)\textrm{Pr}}.
65
```
66
From this combination of temperature ``T`` and thermal conductivity ``\kappa`` we see
67
that the gas constant `R` cancels and the heat flux becomes
68
```math
69
\mathbf{q} = -\kappa\nabla\left(T\right) = -\frac{\gamma \mu}{(\gamma - 1)\textrm{Pr}}\nabla\left(\frac{p}{\rho}\right)
70
```
71
which is the form implemented below in the [`flux`](@ref) function.
72
73
In two spatial dimensions we require gradients for three quantities, e.g.,
74
primitive quantities
75
```math
76
\nabla v_1,\, \nabla v_2,\, \nabla T
77
```
78
or the entropy variables
79
```math
80
\nabla w_2,\, \nabla w_3,\, \nabla w_4
81
```
82
where
83
```math
84
w_2 = \frac{\rho v_1}{p},\, w_3 = \frac{\rho v_2}{p},\, w_4 = -\frac{\rho}{p}
85
```
86
"""
87
struct CompressibleNavierStokesDiffusion2D{GradientVariables, RealT <: Real, Mu,
88
E <: AbstractCompressibleEulerEquations{2}} <:
89
AbstractCompressibleNavierStokesDiffusion{2, 4, GradientVariables}
90
# TODO: parabolic
91
# Add NGRADS as a type parameter here and in AbstractEquationsParabolic, add `ngradients(...)` accessor function
92
93
mu::Mu # viscosity
94
Pr::RealT # Prandtl number
95
kappa::RealT # thermal diffusivity for Fourier's law
96
max_4over3_kappa::RealT # max(4/3, kappa) used for parabolic cfl => `max_diffusivity`
97
98
equations_hyperbolic::E # CompressibleEulerEquations2D
99
gradient_variables::GradientVariables # GradientVariablesPrimitive or GradientVariablesEntropy
100
end
101
102
# default to primitive gradient variables
103
function CompressibleNavierStokesDiffusion2D(equations::CompressibleEulerEquations2D;
104
mu, Prandtl,
105
gradient_variables = GradientVariablesPrimitive())
106
@unpack gamma, inv_gamma_minus_one = equations
107
108
Pr = promote_type(typeof(gamma), typeof(Prandtl))(Prandtl)
109
# Under the assumption of constant Prandtl number the thermal conductivity
110
# constant is kappa = gamma μ / ((gamma-1) Prandtl).
111
# Important note! Factor of μ is accounted for later in `flux`.
112
# This avoids recomputation of kappa for non-constant μ.
113
kappa = gamma * inv_gamma_minus_one / Pr
114
115
return CompressibleNavierStokesDiffusion2D{typeof(gradient_variables),
116
typeof(Pr), typeof(mu),
117
typeof(equations)}(mu, Pr, kappa,
118
max(4 / 3, kappa),
119
equations,
120
gradient_variables)
121
end
122
123
# TODO: parabolic
124
# This is the flexibility a user should have to select the different gradient variable types
125
# varnames(::typeof(cons2prim) , ::CompressibleNavierStokesDiffusion2D) = ("v1", "v2", "T")
126
# varnames(::typeof(cons2entropy), ::CompressibleNavierStokesDiffusion2D) = ("w2", "w3", "w4")
127
128
function varnames(variable_mapping,
129
equations_parabolic::CompressibleNavierStokesDiffusion2D)
130
return varnames(variable_mapping, equations_parabolic.equations_hyperbolic)
131
end
132
133
# we specialize this function to compute gradients of primitive variables instead of
134
# conservative variables.
135
function gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
136
return cons2prim
137
end
138
function gradient_variable_transformation(::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})
139
return cons2entropy
140
end
141
142
# Explicit formulas for the diffusive Navier-Stokes fluxes are available, e.g., in Section 2
143
# of the paper by Rueda-Ramírez, Hennemann, Hindenlang, Winters, and Gassner
144
# "An Entropy Stable Nodal Discontinuous Galerkin Method for the resistive
145
# MHD Equations. Part II: Subcell Finite Volume Shock Capturing"
146
# where one sets the magnetic field components equal to 0.
147
function flux(u, gradients, orientation::Integer,
148
equations::CompressibleNavierStokesDiffusion2D)
149
# Here, `u` is assumed to be the "transformed" variables specified by `gradient_variable_transformation`.
150
_, v1, v2, _ = convert_transformed_to_primitive(u, equations)
151
# Here `gradients` is assumed to contain the gradients of the primitive variables (rho, v1, v2, T)
152
# either computed directly or reverse engineered from the gradient of the entropy variables
153
# by way of the `convert_gradient_variables` function.
154
_, dv1dx, dv2dx, dTdx = convert_derivative_to_primitive(u, gradients[1], equations)
155
_, dv1dy, dv2dy, dTdy = convert_derivative_to_primitive(u, gradients[2], equations)
156
157
# Components of viscous stress tensor
158
159
# (4 * (v1)_x / 3 - 2 * (v2)_y / 3)
160
tau_11 = (4 * dv1dx - 2 * dv2dy) / 3
161
# ((v1)_y + (v2)_x)
162
# stress tensor is symmetric
163
tau_12 = dv1dy + dv2dx # = tau_21
164
# (4/3 * (v2)_y - 2/3 * (v1)_x)
165
tau_22 = (4 * dv2dy - 2 * dv1dx) / 3
166
167
# Fourier's law q = -kappa * grad(T) = -kappa * grad(p / (R rho))
168
# with thermal diffusivity constant kappa = gamma μ R / ((gamma-1) Pr)
169
# Note, the gas constant cancels under this formulation, so it is not present
170
# in the implementation
171
q1 = equations.kappa * dTdx
172
q2 = equations.kappa * dTdy
173
174
# In the simplest cases, the user passed in `mu` or `mu()`
175
# (which returns just a constant) but
176
# more complex functions like Sutherland's law are possible.
177
# `dynamic_viscosity` is a helper function that handles both cases
178
# by dispatching on the type of `equations.mu`.
179
mu = dynamic_viscosity(u, equations)
180
181
if orientation == 1
182
# parabolic flux components in the x-direction
183
f1 = 0
184
f2 = tau_11 * mu
185
f3 = tau_12 * mu
186
f4 = (v1 * tau_11 + v2 * tau_12 + q1) * mu
187
188
return SVector(f1, f2, f3, f4)
189
else # if orientation == 2
190
# parabolic flux components in the y-direction
191
# Note, symmetry is exploited for tau_12 = tau_21
192
g1 = 0
193
g2 = tau_12 * mu # tau_21 * mu
194
g3 = tau_22 * mu
195
g4 = (v1 * tau_12 + v2 * tau_22 + q2) * mu
196
197
return SVector(g1, g2, g3, g4)
198
end
199
end
200
201
@doc raw"""
202
max_diffusivity(u, equations_parabolic::CompressibleNavierStokesDiffusion2D)
203
204
# Returns
205
- `dynamic_viscosity(u, equations_parabolic) / u[1] * equations_parabolic.max_4over3_kappa`
206
where `max_4over3_kappa = max(4/3, kappa)` is computed in the constructor.
207
208
For the diffusive estimate we use the eigenvalues of the diffusivity matrix,
209
as suggested in Section 3.5 of
210
- Krais et. al (2021)
211
FLEXI: A high order discontinuous Galerkin framework for hyperbolic–parabolic conservation laws
212
[DOI: 10.1016/j.camwa.2020.05.004](https://doi.org/10.1016/j.camwa.2020.05.004)
213
214
For details on the derivation of eigenvalues of the diffusivity matrix
215
for the compressible Navier-Stokes equations see for instance
216
- Richard P. Dwight (2006)
217
Efficiency improvements of RANS-based analysis and optimization using implicit and adjoint methods on unstructured grids
218
PhD Thesis, University of Manchester
219
https://elib.dlr.de/50794/1/rdwight-PhDThesis-ImplicitAndAdjoint.pdf
220
See especially equations (2.79), (3.24), and (3.25) from Chapter 3.2.3
221
222
The eigenvalues of the diffusivity matrix in 2D are
223
``-\frac{\mu}{\rho} \{0, 4/3, 1, \kappa\}``
224
and thus the largest absolute eigenvalue is
225
``\frac{\mu}{\rho} \max(4/3, \kappa)``.
226
"""
227
@inline function max_diffusivity(u,
228
equations_parabolic::CompressibleNavierStokesDiffusion2D)
229
# See for instance also the computation in FLUXO:
230
# https://github.com/project-fluxo/fluxo/blob/c7e0cc9b7fd4569dcab67bbb6e5a25c0a84859f1/src/equation/navierstokes/calctimestep.f90#L122-L128
231
#
232
# Accordingly, the spectral radius/largest absolute eigenvalue can be computed as:
233
return dynamic_viscosity(u, equations_parabolic) / u[1] *
234
equations_parabolic.max_4over3_kappa
235
end
236
237
# Convert conservative variables to primitive
238
@inline function cons2prim(u, equations::CompressibleNavierStokesDiffusion2D)
239
rho, rho_v1, rho_v2, _ = u
240
241
v1 = rho_v1 / rho
242
v2 = rho_v2 / rho
243
T = temperature(u, equations)
244
245
return SVector(rho, v1, v2, T)
246
end
247
248
# Convert conservative variables to entropy
249
# TODO: parabolic. We can improve efficiency by not computing w_1, which involves logarithms
250
# This can be done by specializing `cons2entropy` and `entropy2cons` to `CompressibleNavierStokesDiffusion2D`,
251
# but this may be confusing to new users.
252
function cons2entropy(u, equations::CompressibleNavierStokesDiffusion2D)
253
return cons2entropy(u, equations.equations_hyperbolic)
254
end
255
function entropy2cons(w, equations::CompressibleNavierStokesDiffusion2D)
256
return entropy2cons(w, equations.equations_hyperbolic)
257
end
258
259
# the `flux` function takes in transformed variables `u` which depend on the type of the gradient variables.
260
# For CNS, it is simplest to formulate the parabolic terms in primitive variables, so we transform the transformed
261
# variables into primitive variables.
262
@inline function convert_transformed_to_primitive(u_transformed,
263
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
264
return u_transformed
265
end
266
267
# TODO: parabolic. Make this more efficient!
268
@inline function convert_transformed_to_primitive(u_transformed,
269
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})
270
# note: this uses CompressibleNavierStokesDiffusion2D versions of cons2prim and entropy2cons
271
return cons2prim(entropy2cons(u_transformed, equations), equations)
272
end
273
274
# Takes the solution values `u` and gradient of the entropy variables (w_2, w_3, w_4) and
275
# reverse engineers the gradients to be terms of the primitive variables (v1, v2, T).
276
# Helpful because then the diffusive fluxes have the same form as on paper.
277
# Note, the first component of `gradient_entropy_vars` contains gradient(rho) which is unused.
278
# TODO: parabolic; entropy stable parabolic terms
279
@inline function convert_derivative_to_primitive(u, gradient,
280
::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
281
return gradient
282
end
283
284
# the first argument is always the "transformed" variables.
285
@inline function convert_derivative_to_primitive(w, gradient_entropy_vars,
286
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})
287
288
# TODO: parabolic. This is inefficient to pass in transformed variables but then transform them back.
289
# We can fix this if we directly compute v1, v2, T from the entropy variables
290
u = entropy2cons(w, equations) # calls a "modified" entropy2cons defined for CompressibleNavierStokesDiffusion2D
291
rho, rho_v1, rho_v2, _ = u
292
293
v1 = rho_v1 / rho
294
v2 = rho_v2 / rho
295
T = temperature(u, equations)
296
297
return SVector(gradient_entropy_vars[1],
298
T * (gradient_entropy_vars[2] + v1 * gradient_entropy_vars[4]), # grad(u) = T*(grad(w_2)+v1*grad(w_4))
299
T * (gradient_entropy_vars[3] + v2 * gradient_entropy_vars[4]), # grad(v) = T*(grad(w_3)+v2*grad(w_4))
300
T * T * gradient_entropy_vars[4])
301
end
302
303
# This routine is required because `prim2cons` is called in `initial_condition`, which
304
# is called with `equations::CompressibleEulerEquations2D`. This means it is inconsistent
305
# with `cons2prim(..., ::CompressibleNavierStokesDiffusion2D)` as defined above.
306
# TODO: parabolic. Is there a way to clean this up?
307
@inline function prim2cons(u, equations::CompressibleNavierStokesDiffusion2D)
308
return prim2cons(u, equations.equations_hyperbolic)
309
end
310
311
"""
312
temperature(u, equations::CompressibleNavierStokesDiffusion2D)
313
314
Compute the temperature from the conservative variables `u`.
315
In particular, this assumes a specific gas constant ``R = 1``:
316
```math
317
T = \\frac{p}{\\rho}
318
```
319
"""
320
@inline function temperature(u, equations::CompressibleNavierStokesDiffusion2D)
321
rho, rho_v1, rho_v2, rho_e_total = u
322
@unpack gamma = equations
323
324
p = (gamma - 1) * (rho_e_total - 0.5f0 * (rho_v1^2 + rho_v2^2) / rho)
325
T = p / rho # Corresponds to a specific gas constant R = 1
326
return T
327
end
328
329
@inline function velocity(u, equations::CompressibleNavierStokesDiffusion2D)
330
rho = u[1]
331
v1 = u[2] / rho
332
v2 = u[3] / rho
333
return SVector(v1, v2)
334
end
335
336
@doc raw"""
337
enstrophy(u, gradients, equations::CompressibleNavierStokesDiffusion2D)
338
339
Computes the (node-wise) enstrophy, defined as
340
```math
341
\mathcal{E} = \frac{1}{2} \rho \omega \cdot \omega
342
```
343
where ``\omega = \nabla \times \boldsymbol{v}`` is the [`vorticity`](@ref).
344
In 2D, ``\omega`` is just a scalar.
345
"""
346
@inline function enstrophy(u, gradients, equations::CompressibleNavierStokesDiffusion2D)
347
# Enstrophy is 0.5 rho ω⋅ω where ω = ∇ × v
348
349
omega = vorticity(u, gradients, equations)
350
return 0.5f0 * u[1] * omega^2
351
end
352
353
@doc raw"""
354
vorticity(u, gradients, equations::CompressibleNavierStokesDiffusion2D)
355
356
Computes the (node-wise) vorticity, defined in 2D as
357
```math
358
\omega = \nabla \times \boldsymbol{v} = \frac{\partial v_2}{\partial x_1} - \frac{\partial v_1}{\partial x_2}
359
```
360
"""
361
@inline function vorticity(u, gradients, equations::CompressibleNavierStokesDiffusion2D)
362
# Ensure that we have velocity `gradients` by way of the `convert_gradient_variables` function.
363
_, _, dv2dx, _ = convert_derivative_to_primitive(u, gradients[1], equations)
364
_, dv1dy, _, _ = convert_derivative_to_primitive(u, gradients[2], equations)
365
366
return dv2dx - dv1dy
367
end
368
369
@inline function vorticity(u, gradients,
370
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})
371
# Need to convert to entropy variables first for `convert_derivative_to_primitive` to work correctly.
372
w = cons2entropy(u, equations)
373
374
# Ensure that we have velocity `gradients` by way of the `convert_gradient_variables` function.
375
_, _, dv2dx, _ = convert_derivative_to_primitive(w, gradients[1], equations)
376
_, dv1dy, _, _ = convert_derivative_to_primitive(w, gradients[2], equations)
377
378
return dv2dx - dv1dy
379
end
380
381
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,
382
<:Adiabatic})(flux_inner,
383
u_inner,
384
normal::AbstractVector,
385
x,
386
t,
387
operator_type::Gradient,
388
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
389
v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,
390
t,
391
equations)
392
return SVector(u_inner[1], v1, v2, u_inner[4])
393
end
394
395
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,
396
<:Adiabatic})(flux_inner,
397
u_inner,
398
normal::AbstractVector,
399
x,
400
t,
401
operator_type::Divergence,
402
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
403
normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x,
404
t,
405
equations)
406
v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,
407
t,
408
equations)
409
_, tau_1n, tau_2n, _ = flux_inner # extract fluxes for 2nd and 3rd equations
410
normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux
411
return SVector(flux_inner[1], flux_inner[2], flux_inner[3], normal_energy_flux)
412
end
413
414
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,
415
<:Isothermal})(flux_inner,
416
u_inner,
417
normal::AbstractVector,
418
x,
419
t,
420
operator_type::Gradient,
421
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
422
v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,
423
t,
424
equations)
425
T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t,
426
equations)
427
return SVector(u_inner[1], v1, v2, T)
428
end
429
430
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,
431
<:Isothermal})(flux_inner,
432
u_inner,
433
normal::AbstractVector,
434
x,
435
t,
436
operator_type::Divergence,
437
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
438
return flux_inner
439
end
440
441
# specialized BC impositions for GradientVariablesEntropy.
442
443
# This should return a SVector containing the boundary values of entropy variables.
444
# Here, `w_inner` are the transformed variables (e.g., entropy variables).
445
#
446
# Taken from "Entropy stable modal discontinuous Galerkin schemes and wall boundary conditions
447
# for the compressible Navier-Stokes equations" by Chan, Lin, Warburton 2022.
448
# DOI: 10.1016/j.jcp.2021.110723
449
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,
450
<:Adiabatic})(flux_inner,
451
w_inner,
452
normal::AbstractVector,
453
x,
454
t,
455
operator_type::Gradient,
456
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})
457
v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,
458
t,
459
equations)
460
negative_rho_inv_p = w_inner[4] # w_4 = -rho / p
461
return SVector(w_inner[1], -v1 * negative_rho_inv_p, -v2 * negative_rho_inv_p,
462
negative_rho_inv_p)
463
end
464
465
# this is actually identical to the specialization for GradientVariablesPrimitive, but included for completeness.
466
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,
467
<:Adiabatic})(flux_inner,
468
w_inner,
469
normal::AbstractVector,
470
x,
471
t,
472
operator_type::Divergence,
473
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})
474
normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x,
475
t,
476
equations)
477
v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,
478
t,
479
equations)
480
_, tau_1n, tau_2n, _ = flux_inner # extract fluxes for 2nd and 3rd equations
481
normal_energy_flux = v1 * tau_1n + v2 * tau_2n + normal_heat_flux
482
return SVector(flux_inner[1], flux_inner[2], flux_inner[3], normal_energy_flux)
483
end
484
485
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,
486
<:Isothermal})(flux_inner,
487
w_inner,
488
normal::AbstractVector,
489
x,
490
t,
491
operator_type::Gradient,
492
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})
493
v1, v2 = boundary_condition.boundary_condition_velocity.boundary_value_function(x,
494
t,
495
equations)
496
T = boundary_condition.boundary_condition_heat_flux.boundary_value_function(x, t,
497
equations)
498
499
# the entropy variables w2 = rho * v1 / p = v1 / T = -v1 * w4. Similarly for w3
500
w4 = -1 / T
501
return SVector(w_inner[1], -v1 * w4, -v2 * w4, w4)
502
end
503
504
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:NoSlip,
505
<:Isothermal})(flux_inner,
506
w_inner,
507
normal::AbstractVector,
508
x,
509
t,
510
operator_type::Divergence,
511
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesEntropy})
512
return SVector(flux_inner[1], flux_inner[2], flux_inner[3], flux_inner[4])
513
end
514
515
# Computes the mirror velocity across a symmetry plane which enforces
516
# a tangential velocity that is aligned with the symmetry plane, i.e.,
517
# which is normal to the `normal_direction`.
518
# See also `boundary_condition_slip_wall` and `rotate_to_x`.
519
@inline function velocity_symmetry_plane(normal_direction::AbstractVector, v1, v2)
520
norm_ = norm(normal_direction)
521
normal = normal_direction / norm_
522
523
# Compute alignment of velocity with normal direction
524
v_normal = v1 * normal[1] + v2 * normal[2]
525
526
v1_outer = v1 - 2 * v_normal * normal[1]
527
v2_outer = v2 - 2 * v_normal * normal[2]
528
529
return v1_outer, v2_outer
530
end
531
532
# Note: This should be used with `boundary_condition_slip_wall` for the hyperbolic (Euler) part.
533
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:Slip,
534
<:Adiabatic})(flux_inner,
535
u_inner,
536
normal::AbstractVector,
537
x,
538
t,
539
operator_type::Gradient,
540
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
541
v1_outer, v2_outer = velocity_symmetry_plane(normal,
542
u_inner[2],
543
u_inner[3])
544
545
return SVector(u_inner[1], v1_outer, v2_outer, u_inner[4])
546
end
547
548
# Note: This should be used with `boundary_condition_slip_wall` for the hyperbolic (Euler) part.
549
@inline function (boundary_condition::BoundaryConditionNavierStokesWall{<:Slip,
550
<:Adiabatic})(flux_inner,
551
u_inner,
552
normal::AbstractVector,
553
x,
554
t,
555
operator_type::Divergence,
556
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
557
normal_heat_flux = boundary_condition.boundary_condition_heat_flux.boundary_value_normal_flux_function(x,
558
t,
559
equations)
560
561
# Normal stresses should be 0. This implies also that `normal_energy_flux = normal_heat_flux`.
562
# For details, see Section 4.2 of
563
# "Entropy stable modal discontinuous Galerkin schemes and wall boundary conditions
564
# for the compressible Navier-Stokes equations" by Chan, Lin, Warburton 2022.
565
# DOI: 10.1016/j.jcp.2021.110723
566
return SVector(flux_inner[1], 0, 0, normal_heat_flux)
567
end
568
569
# Dirichlet Boundary Condition for e.g. P4est mesh
570
@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner,
571
u_inner,
572
normal::AbstractVector,
573
x, t,
574
operator_type::Gradient,
575
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
576
# BCs are usually specified as conservative variables so we convert them to primitive variables
577
# because the gradients are assumed to be with respect to the primitive variables
578
u_boundary = boundary_condition.boundary_value_function(x, t, equations)
579
580
return cons2prim(u_boundary, equations)
581
end
582
583
@inline function (boundary_condition::BoundaryConditionDirichlet)(flux_inner,
584
u_inner,
585
normal::AbstractVector,
586
x, t,
587
operator_type::Divergence,
588
equations::CompressibleNavierStokesDiffusion2D{GradientVariablesPrimitive})
589
# for Dirichlet boundary conditions, we do not impose any conditions on the parabolic fluxes
590
return flux_inner
591
end
592
end # @muladd
593
594