Peano
Loading...
Searching...
No Matches
navier_stokes.py
Go to the documentation of this file.
1
# This file is part of the ExaHyPE2 project. For conditions of distribution and
2
# use, please see the copyright notice at www.peano-framework.org
3
4
from
.equation
import
Equation
5
6
from
exahype2.solvers.PDETerms
import
PDETerms
7
8
9
class
NavierStokes
(
Equation
):
10
def
__init__
(
11
self,
12
dimensions,
13
use_advection=True,
14
use_background_state=True,
15
use_gravity=True,
16
use_viscosity=True,
17
gamma=1.4,
18
cv=1.0,
19
gas_constant=287.058,
20
reference_viscosity=0.1,
21
Pr=0.71,
22
molecular_diffusion_coeff=0.0,
23
q0=0.0,
24
):
25
self.
dimensions
dimensions
= dimensions
26
27
self.
num_unknowns
num_unknowns
= {
28
"rho"
: 1,
29
"j"
: dimensions,
30
"E"
: 1,
31
}
32
if
use_advection:
33
self.
num_unknowns
num_unknowns
[
"Z"
] = 1
34
35
self.
num_auxiliary_variables
num_auxiliary_variables
= {
36
key: value
37
for
key, value
in
{
38
"height"
: 1
if
use_gravity
else
0,
39
"backgroundstate"
: 2
if
use_background_state
else
0,
40
}.items()
41
if
value > 0
42
}
43
44
self.
_use_advection
= use_advection
45
self.
_use_background_state
= use_background_state
46
self.
_use_gravity
= use_gravity
47
self.
_use_viscosity
= use_viscosity
48
49
self.
_gamma
= gamma
# ratio of specific heats
50
self.
_cv
= cv
# heat capacity at constant volume
51
self.
_gas_constant
= gas_constant
# specific gas constant of a fluid
52
self.
_reference_viscosity
= reference_viscosity
53
self.
_Pr
= Pr
# Prandtl number
54
self.
_molecular_diffusion_coeff
= molecular_diffusion_coeff
55
self.
_q0
= q0
# q0 not explained in the old version, merely marked with ???
56
57
self.
use_diffusive_flux
use_diffusive_flux
=
True
58
59
def
evaluate_pressure
(self):
60
return
(
61
"""
62
auto chemicalEnergy = q0 * Z;
63
"""
64
+ (
65
"""
66
// add gravity Potential to the chemical energy for simplicity,
67
// but it is technically a separate term
68
chemicalEnergy += rho * gravity * height;
69
"""
70
if
self.
_use_gravity
71
else
""
72
)
73
+
"""
74
75
const auto jDot = j[0]*j[0]+j[1]*j[1]
76
#if DIMENSIONS==3
77
+ j[2]*j[2]
78
#endif
79
;
80
81
const auto pressure = (gamma-1) * (E - 0.5 * (1.0/rho) * jDot - chemicalEnergy);
82
"""
83
)
84
85
def
evaluate_energy
(self):
86
return
(
87
"""
88
auto chemicalEnergy = q0 * Z;
89
"""
90
+ (
91
"""
92
// add gravity Potential to the chemical energy for simplicity,
93
// but it is technically a separate term
94
chemicalEnergy += rho * gravity * height;
95
"""
96
if
self.
_use_gravity
97
else
""
98
)
99
+
"""
100
101
const auto jDot = j[0]*j[0]+j[1]*j[1]
102
#if DIMENSIONS==3
103
+ j[2]*j[2]
104
#endif
105
;
106
const auto E = pressure/(gamma - 1) + 0.5 * (jDot/rho) + chemicalEnergy;
107
"""
108
)
109
110
# these get used both here and in the Riemann solver, but need
111
# different factors in their sum (i.e lambda + a * lambda_diff)
112
# in an effort to minimize code duplication we therefore define
113
# both of these once and just refer to them
114
def
eigenvalue_functions
(self):
115
return
(
116
"""
117
constexpr auto gamma = """
118
+ str(self.
_gamma
)
119
+
""";
120
constexpr auto gravity = 9.81;
121
constexpr auto q0 = """
122
+ str(self.
_q0
)
123
+
""";
124
constexpr auto referenceViscosity = """
125
+ str(self.
_reference_viscosity
)
126
+
""";
127
constexpr auto Pr = """
128
+ str(self.
_Pr
)
129
+
"""; //Prandtl number
130
constexpr auto molecularDiffusionCoeff = """
131
+ str(self.
_molecular_diffusion_coeff
)
132
+
""";
133
134
auto maxEval = [&](
135
const {{SOLUTION_STORAGE_PRECISION}}* const NOALIAS Q,
136
const int normal
137
){
138
const auto j = &Q[Shortcuts::j];
139
const auto E = Q[Shortcuts::E];
140
const auto rho = Q[Shortcuts::rho];
141
const auto height = """
142
+ (
"Q[Shortcuts::height]"
if
self.
_use_gravity
else
"0.0"
)
143
+
""";
144
const auto Z = """
145
+ (
"Q[Shortcuts::Z];"
if
self.
_use_advection
else
"0.0;"
)
146
+ self.
evaluate_pressure
()
147
+
"""
148
const auto u_n = Q[Shortcuts::j+normal]/rho;
149
const auto c = std::sqrt(gamma * (pressure/rho));
150
double lambda = std::fmax(
151
std::abs(u_n-c), std::abs(u_n+c)
152
);
153
return lambda;
154
};
155
156
auto diffusiveEval = [&](
157
const {{SOLUTION_STORAGE_PRECISION}}* const NOALIAS Q,
158
const int normal
159
){
160
double smaxDiffusive = molecularDiffusionCoeff;
161
smaxDiffusive = std::fmax(
162
smaxDiffusive, (4./3.) * (referenceViscosity/Q[Shortcuts::rho])
163
);
164
return std::fmax(
165
smaxDiffusive, (gamma * referenceViscosity) / (Pr * Q[Shortcuts::rho])
166
);
167
168
};
169
"""
170
)
171
172
def
eigenvalues
(self):
173
return
(
174
self.
eigenvalue_functions
()
175
+
"""
176
return maxEval(Q, normal)
177
+ diffusiveEval(Q, normal)*2.0/(h[normal]*PNPM);
178
"""
179
)
180
181
def
flux
(self):
182
# define parameters that will be used in the flux
183
flux_init = (
184
""" const auto rho = Q[Shortcuts::rho];
185
const auto j = &Q[Shortcuts::j];
186
const auto E = Q[Shortcuts::E];
187
const auto Z = """
188
+ (
"Q[Shortcuts::Z]"
if
self.
_use_advection
else
"0.0"
)
189
+
""";
190
const auto height = """
191
+ (
"Q[Shortcuts::height]"
if
self.
_use_gravity
else
"0.0"
)
192
+
""";
193
const auto backgroundPressure = """
194
+ (
195
"Q[Shortcuts::backgroundstate+1]"
196
if
self.
_use_background_state
197
else
"0.0"
198
)
199
+
""";
200
201
constexpr auto gravity = 9.81;
202
constexpr auto gamma = """
203
+ str(self.
_gamma
)
204
+
""";
205
constexpr auto gasConstant = """
206
+ str(self.
_gas_constant
)
207
+
""";
208
constexpr auto cv = """
209
+ str(self.
_cv
)
210
+
""";
211
constexpr auto q0 = """
212
+ str(self.
_q0
)
213
+
""";
214
const auto invRho = 1./rho; """
215
+ self.
evaluate_pressure
()
216
)
217
218
# part of the flux which corresponds to the Euler equations
219
flux_euler =
"""
220
F[Shortcuts::rho] = j[normal];
221
F[Shortcuts::j+0] = invRho * j[normal] * j[0];
222
F[Shortcuts::j+1] = invRho * j[normal] * j[1];
223
#if DIMENSIONS==3
224
F[Shortcuts::j+2] = invRho * j[normal] * j[2];
225
#endif
226
F[Shortcuts::E] = invRho * j[normal] * (E+pressure);
227
228
F[Shortcuts::j+normal] += (pressure-backgroundPressure);
229
"""
230
flux_viscous = (
231
"""
232
// TODO Support different visc. models?
233
constexpr auto referenceViscosity = """
234
+ str(self.
_reference_viscosity
)
235
+
""";
236
constexpr auto mu = referenceViscosity;
237
constexpr auto Pr = """
238
+ str(self.
_Pr
)
239
+
"""; //Prandtl number
240
constexpr auto kappa = 1./Pr * referenceViscosity * gamma * cv;
241
242
const auto uu = invRho * Q[Shortcuts::j];
243
const auto uux = invRho * (deltaQ[0][Shortcuts::j+0] - uu * deltaQ[0][Shortcuts::rho]);
244
const auto uuy = invRho * (deltaQ[1][Shortcuts::j+0] - uu * deltaQ[1][Shortcuts::rho]);
245
246
const auto vv = invRho * Q[Shortcuts::j+1];
247
const auto vvx = invRho * (deltaQ[0][Shortcuts::j+1] - vv * deltaQ[0][Shortcuts::rho]);
248
const auto vvy = invRho * (deltaQ[1][Shortcuts::j+1] - vv * deltaQ[1][Shortcuts::rho]);
249
250
#if DIMENSIONS == 2
251
const auto divV23 = 2./3. * (uux + vvy);
252
#else
253
const auto ww = invRho * Q[Shortcuts::j+2];
254
const auto uuz = invRho * (deltaQ[2][Shortcuts::j+0] - uu * deltaQ[2][Shortcuts::rho]);
255
const auto vvz = invRho * (deltaQ[2][Shortcuts::j+1] - vv * deltaQ[2][Shortcuts::rho]);
256
const auto wwx = invRho * (deltaQ[2][Shortcuts::j+2] - ww * deltaQ[0][Shortcuts::rho]);
257
const auto wwy = invRho * (deltaQ[2][Shortcuts::j+2] - ww * deltaQ[1][Shortcuts::rho]);
258
const auto wwz = invRho * (deltaQ[2][Shortcuts::j+2] - ww * deltaQ[2][Shortcuts::rho]);
259
const auto divV23 = 2./3. * (uux + vvy + wwz);
260
#endif
261
262
double Fj[DIMENSIONS];
263
switch(normal){
264
case 0:
265
Fj[0] = mu * (2 * uux - divV23);
266
Fj[1] = mu * (uuy + vvx);
267
#if DIMENSIONS == 3
268
Fj[2] = mu * (uuz + wwx);
269
#endif
270
break;
271
case 1:
272
Fj[0] = mu * (uuy + vvx);
273
Fj[1] = mu * (2 * vvy - divV23);
274
#if DIMENSIONS == 3
275
Fj[2] = mu * (vvz + wwy);
276
break;
277
case 2:
278
Fj[0] = mu * (uuz + wwx);
279
Fj[1] = mu * (vvz + wwy);
280
Fj[2] = mu * (2 * wwz - divV23);
281
#endif
282
}
283
284
F[Shortcuts::j+0] -= Fj[0];
285
F[Shortcuts::j+1] -= Fj[1];
286
F[Shortcuts::E] -= Fj[0]*uu + Fj[1]*vv;
287
#if DIMENSIONS == 3
288
F[Shortcuts::j+2] -= Fj[2];
289
F[Shortcuts::E] -= Fj[2] *ww;
290
#endif
291
"""
292
)
293
flux_heat = (
294
"""
295
const auto invCv = 1/cv;
296
const auto invRho2 = invRho * invRho;
297
const auto invRho3 = invRho2 * invRho;
298
299
#if DIMENSIONS == 2
300
const auto dTdW1 = -1 * Q[Shortcuts::E] * invRho2 +
301
invRho3 * (Q[Shortcuts::j]*Q[Shortcuts::j] + Q[Shortcuts::j+1] * Q[Shortcuts::j+1]);
302
#else
303
const auto dTdW1 = -1 * Q[Shortcuts::E] * invRho2 +
304
invRho3 * (Q[Shortcuts::j]*Q[Shortcuts::j] + Q[Shortcuts::j+1] * Q[Shortcuts::j+1] + Q[Shortcuts::j+2] * Q[Shortcuts::j+2]);
305
#endif
306
const auto dTdW2 = -1 * Q[Shortcuts::j] * invRho2;
307
const auto dTdW3 = -1 * Q[Shortcuts::j+1] * invRho2;
308
#if DIMENSIONS == 3
309
const auto dTdW4 = -1 * Q[Shortcuts::j+2] * invRho2;
310
#endif
311
312
auto T = invCv * (dTdW1 * deltaQ[normal][Shortcuts::rho] +
313
dTdW2 * deltaQ[normal][Shortcuts::j+0] +
314
dTdW3 * deltaQ[normal][Shortcuts::j+1] +
315
#if DIMENSIONS == 3
316
dTdW4 * deltaQ[normal][Shortcuts::j+2] +
317
#endif
318
invRho * deltaQ[normal][Shortcuts::E]);
319
"""
320
+ (
321
"""
322
// Including the gravitational potential in the pressure
323
// implies that we need to change the derivative of the temperature as well,
324
// but only in z direction
325
// Gravity happens in y direction in 2D and in z direction in 3D
326
if(normal==DIMENSIONS-1){
327
T -= (gravity * (gamma - 1)) / gasConstant;
328
} """
329
if
self.
_use_gravity
330
else
""
331
)
332
+
"""
333
// Heat flux
334
F[Shortcuts::E] -= kappa * T;
335
"""
336
)
337
338
flux_advection = (
339
"""
340
// Euler flux
341
F[Shortcuts::Z] = j[normal] * Z * invRho;
342
// Contribution to the Heat flux
343
const auto factor = invCv * q0 * invRho2;
344
T = -factor *
345
(Q[Shortcuts::rho] * deltaQ[normal][Shortcuts::Z] -
346
Q[Shortcuts::Z] * deltaQ[normal][Shortcuts::rho]);
347
F[Shortcuts::E] -= kappa * T;
348
349
// Molecular diffusion for Advection-Reaction-Diffusion part.
350
constexpr auto molecularDiffusionCoeff = """
351
+ str(self.
_molecular_diffusion_coeff
)
352
+
""";
353
F[Shortcuts::rho] -= molecularDiffusionCoeff * deltaQ[normal][Shortcuts::rho];
354
F[Shorcuts::Z] -= molecularDiffusionCoeff * deltaQ[normal][Shortcuts::Z];
355
"""
356
)
357
358
return
(
359
flux_init
360
+ flux_euler
361
+ (flux_viscous
if
self.
_use_viscosity
else
""
)
362
+ flux_heat
363
+ (flux_advection
if
self.
_use_advection
else
""
)
364
)
365
366
def
source
(self):
367
# If both terms are 0, no need for a source
368
if
not
(self.
_use_gravity
or
self.
_use_background_state
):
369
return
PDETerms.None_Implementation
370
return
(
371
"""
372
std::fill_n(S, NumberOfUnknowns, 0.0);
373
374
auto rhoPertubation = Q[Shortcuts::rho];
375
"""
376
+ (
377
"""
378
auto backgroundRho = Q[Shortcuts::backgroundstate+0];
379
rhoPertubation -= backgroundRho;
380
"""
381
if
self.
_use_background_state
382
else
""
383
)
384
+
"""
385
constexpr auto gravity = 9.81;
386
//vertical direction is either y or z
387
S[Shortcuts::j+DIMENSIONS-1] = -1 * rhoPertubation * gravity;
388
"""
389
+ (
""
if
self.
_use_gravity
else
""
)
390
)
391
392
def
riemann_solver
(self):
393
return
(
394
"""
395
constexpr int strideQ = NumberOfUnknowns + NumberOfAuxiliaryVariables;
396
{{CORRECTOR_COMPUTATION_PRECISION}} QavL[strideQ] __attribute__((aligned(16))) = {0.0};
397
{{CORRECTOR_COMPUTATION_PRECISION}} QavR[strideQ] __attribute__((aligned(16))) = {0.0};
398
399
#if DIMENSIONS==3
400
constexpr int faceSize = (Order+1)*(Order+1);
401
#else
402
constexpr int faceSize = (Order+1);
403
#endif
404
405
for (int xy = 0; xy < faceSize; xy++) {
406
for (int n = 0; n < strideQ; n++) {
407
QavL[n] += kernels::{{SOLVER_NAME}}::Quadrature<{{CORRECTOR_COMPUTATION_PRECISION}}>::weights2[xy] * QL[xy * strideQ + n];
408
QavR[n] += kernels::{{SOLVER_NAME}}::Quadrature<{{CORRECTOR_COMPUTATION_PRECISION}}>::weights2[xy] * QR[xy * strideQ + n];
409
}
410
}
411
412
"""
413
+ self.
eigenvalue_functions
()
414
+
"""
415
416
// Compute max eigenvalue over face
417
auto smax = std::fmax(
418
maxEval(&QavL[0], direction),
419
maxEval(&QavR[0], direction)
420
);
421
422
// Add viscous eigenvalue term to max eigenvalue
423
const auto factor = 2 * (2 * Order + 1) / (h[direction] * std::sqrt(0.5 * std::numbers::pi));
424
smax += factor*std::fmax(
425
diffusiveEval(&QavL[0], direction), diffusiveEval(&QavR[0], direction)
426
);
427
428
for (int xy = 0; xy < faceSize; xy++) {
429
for (int n = 0; n < NumberOfUnknowns; n++) {
430
FL[xy*NumberOfUnknowns+n] = 0.5 * (FL[xy * NumberOfUnknowns + n] + FR[xy * NumberOfUnknowns + n]
431
+ smax * (QL[xy * strideQ + n] - QR[xy * strideQ + n]) );
432
}
433
}
434
std::copy_n(FL, faceSize*NumberOfUnknowns, FR);
435
"""
436
)
equations.equation.Equation
Definition
equation.py:6
equations.equation.Equation.num_auxiliary_variables
int num_auxiliary_variables
Definition
equation.py:9
equations.equation.Equation.flux
flux()
Definition
equation.py:18
equations.equation.Equation.riemann_solver
riemann_solver()
Definition
equation.py:30
equations.equation.Equation.use_diffusive_flux
bool use_diffusive_flux
Definition
equation.py:11
equations.equation.Equation.dimensions
int dimensions
Definition
equation.py:7
equations.equation.Equation.source
source()
Definition
equation.py:26
equations.equation.Equation.num_unknowns
int num_unknowns
Definition
equation.py:8
equations.equation.Equation.eigenvalues
eigenvalues()
Definition
equation.py:14
equations.navier_stokes.NavierStokes
Definition
navier_stokes.py:9
equations.navier_stokes.NavierStokes.evaluate_pressure
evaluate_pressure(self)
Definition
navier_stokes.py:59
equations.navier_stokes.NavierStokes.eigenvalue_functions
eigenvalue_functions(self)
Definition
navier_stokes.py:114
equations.navier_stokes.NavierStokes._gamma
_gamma
Definition
navier_stokes.py:49
equations.navier_stokes.NavierStokes.evaluate_energy
evaluate_energy(self)
Definition
navier_stokes.py:85
equations.navier_stokes.NavierStokes._use_background_state
_use_background_state
Definition
navier_stokes.py:45
equations.navier_stokes.NavierStokes._gas_constant
_gas_constant
Definition
navier_stokes.py:51
equations.navier_stokes.NavierStokes.num_unknowns
num_unknowns
Definition
navier_stokes.py:27
equations.navier_stokes.NavierStokes._molecular_diffusion_coeff
_molecular_diffusion_coeff
Definition
navier_stokes.py:54
equations.navier_stokes.NavierStokes.dimensions
dimensions
Definition
navier_stokes.py:25
equations.navier_stokes.NavierStokes.use_diffusive_flux
use_diffusive_flux
Definition
navier_stokes.py:57
equations.navier_stokes.NavierStokes._use_viscosity
_use_viscosity
Definition
navier_stokes.py:47
equations.navier_stokes.NavierStokes.__init__
__init__(self, dimensions, use_advection=True, use_background_state=True, use_gravity=True, use_viscosity=True, gamma=1.4, cv=1.0, gas_constant=287.058, reference_viscosity=0.1, Pr=0.71, molecular_diffusion_coeff=0.0, q0=0.0)
Definition
navier_stokes.py:24
equations.navier_stokes.NavierStokes.num_auxiliary_variables
num_auxiliary_variables
Definition
navier_stokes.py:35
equations.navier_stokes.NavierStokes._q0
_q0
Definition
navier_stokes.py:55
equations.navier_stokes.NavierStokes._use_gravity
_use_gravity
Definition
navier_stokes.py:46
equations.navier_stokes.NavierStokes._use_advection
_use_advection
Definition
navier_stokes.py:44
equations.navier_stokes.NavierStokes._reference_viscosity
_reference_viscosity
Definition
navier_stokes.py:52
equations.navier_stokes.NavierStokes._cv
_cv
Definition
navier_stokes.py:50
equations.navier_stokes.NavierStokes._Pr
_Pr
Definition
navier_stokes.py:53
tests
aderdg
equations
navier_stokes.py
Generated on Wed Apr 1 2026 00:01:45 for Peano by
1.10.0