Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
trixi-framework
GitHub Repository: trixi-framework/Trixi.jl
Path: blob/main/examples/dgmulti_3d/elixir_navierstokes_convergence_curved.jl
2055 views
1
using OrdinaryDiffEqLowStorageRK
2
using Trixi
3
4
###############################################################################
5
# semidiscretization of the ideal compressible Navier-Stokes equations
6
7
prandtl_number() = 0.72
8
mu() = 0.01
9
10
equations = CompressibleEulerEquations3D(1.4)
11
equations_parabolic = CompressibleNavierStokesDiffusion3D(equations, mu = mu(),
12
Prandtl = prandtl_number(),
13
gradient_variables = GradientVariablesPrimitive())
14
15
# Create DG solver with polynomial degree = 3 and (local) Lax-Friedrichs/Rusanov flux as surface flux
16
17
# Up to version 0.13.0, `max_abs_speed_naive` was used as the default wave speed estimate of
18
# `const flux_lax_friedrichs = FluxLaxFriedrichs(), i.e., `FluxLaxFriedrichs(max_abs_speed = max_abs_speed_naive)`.
19
# In the `StepsizeCallback`, though, the less diffusive `max_abs_speeds` is employed which is consistent with `max_abs_speed`.
20
# Thus, we exchanged in PR#2458 the default wave speed used in the LLF flux to `max_abs_speed`.
21
# To ensure that every example still runs we specify explicitly `FluxLaxFriedrichs(max_abs_speed_naive)`.
22
# We remark, however, that the now default `max_abs_speed` is in general recommended due to compliance with the
23
# `StepsizeCallback` (CFL-Condition) and less diffusion.
24
dg = DGMulti(polydeg = 3, element_type = Hex(), approximation_type = Polynomial(),
25
surface_integral = SurfaceIntegralWeakForm(FluxLaxFriedrichs(max_abs_speed_naive)),
26
volume_integral = VolumeIntegralWeakForm())
27
28
top_bottom(x, tol = 50 * eps()) = abs(abs(x[2]) - 1) < tol
29
is_on_boundary = Dict(:top_bottom => top_bottom)
30
31
function mapping(xi, eta, zeta)
32
x = xi + 0.1 * sin(pi * xi) * sin(pi * eta)
33
y = eta + 0.1 * sin(pi * xi) * sin(pi * eta)
34
z = zeta + 0.1 * sin(pi * xi) * sin(pi * eta)
35
return SVector(x, y, z)
36
end
37
cells_per_dimension = (8, 8, 8)
38
mesh = DGMultiMesh(dg, cells_per_dimension, mapping; periodicity = (true, false, true),
39
is_on_boundary)
40
41
# This initial condition is taken from `examples/dgmulti_3d/elixir_navierstokes_convergence.jl`
42
43
# Note: the initial condition cannot be specialized to `CompressibleNavierStokesDiffusion3D`
44
# since it is called by both the parabolic solver (which passes in `CompressibleNavierStokesDiffusion3D`)
45
# and by the initial condition (which passes in `CompressibleEulerEquations3D`).
46
# This convergence test setup was originally derived by Andrew Winters (@andrewwinters5000)
47
function initial_condition_navier_stokes_convergence_test(x, t, equations)
48
# Constants. OBS! Must match those in `source_terms_navier_stokes_convergence_test`
49
c = 2.0
50
A1 = 0.5
51
A2 = 1.0
52
A3 = 0.5
53
54
# Convenience values for trig. functions
55
pi_x = pi * x[1]
56
pi_y = pi * x[2]
57
pi_z = pi * x[3]
58
pi_t = pi * t
59
60
rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t)
61
v1 = A2 * sin(pi_x) * log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0))) * sin(pi_z) *
62
cos(pi_t)
63
v2 = v1
64
v3 = v1
65
p = rho^2
66
67
return prim2cons(SVector(rho, v1, v2, v3, p), equations)
68
end
69
70
@inline function source_terms_navier_stokes_convergence_test(u, x, t, equations)
71
# TODO: parabolic
72
# we currently need to hardcode these parameters until we fix the "combined equation" issue
73
# see also https://github.com/trixi-framework/Trixi.jl/pull/1160
74
inv_gamma_minus_one = inv(equations.gamma - 1)
75
Pr = prandtl_number()
76
mu_ = mu()
77
78
# Constants. OBS! Must match those in `initial_condition_navier_stokes_convergence_test`
79
c = 2.0
80
A1 = 0.5
81
A2 = 1.0
82
A3 = 0.5
83
84
# Convenience values for trig. functions
85
pi_x = pi * x[1]
86
pi_y = pi * x[2]
87
pi_z = pi * x[3]
88
pi_t = pi * t
89
90
# Define auxiliary functions for the strange function of the y variable
91
# to make expressions easier to read
92
g = log(x[2] + 2.0) * (1.0 - exp(-A3 * (x[2] - 1.0)))
93
g_y = (A3 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)) +
94
(1.0 - exp(-A3 * (x[2] - 1.0))) / (x[2] + 2.0))
95
g_yy = (2.0 * A3 * exp(-A3 * (x[2] - 1.0)) / (x[2] + 2.0) -
96
(1.0 - exp(-A3 * (x[2] - 1.0))) / ((x[2] + 2.0)^2) -
97
A3^2 * log(x[2] + 2.0) * exp(-A3 * (x[2] - 1.0)))
98
99
# Density and its derivatives
100
rho = c + A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t)
101
rho_t = -pi * A1 * sin(pi_x) * cos(pi_y) * sin(pi_z) * sin(pi_t)
102
rho_x = pi * A1 * cos(pi_x) * cos(pi_y) * sin(pi_z) * cos(pi_t)
103
rho_y = -pi * A1 * sin(pi_x) * sin(pi_y) * sin(pi_z) * cos(pi_t)
104
rho_z = pi * A1 * sin(pi_x) * cos(pi_y) * cos(pi_z) * cos(pi_t)
105
rho_xx = -pi^2 * (rho - c)
106
rho_yy = -pi^2 * (rho - c)
107
rho_zz = -pi^2 * (rho - c)
108
109
# Velocities and their derivatives
110
# v1 terms
111
v1 = A2 * sin(pi_x) * g * sin(pi_z) * cos(pi_t)
112
v1_t = -pi * A2 * sin(pi_x) * g * sin(pi_z) * sin(pi_t)
113
v1_x = pi * A2 * cos(pi_x) * g * sin(pi_z) * cos(pi_t)
114
v1_y = A2 * sin(pi_x) * g_y * sin(pi_z) * cos(pi_t)
115
v1_z = pi * A2 * sin(pi_x) * g * cos(pi_z) * cos(pi_t)
116
v1_xx = -pi^2 * v1
117
v1_yy = A2 * sin(pi_x) * g_yy * sin(pi_z) * cos(pi_t)
118
v1_zz = -pi^2 * v1
119
v1_xy = pi * A2 * cos(pi_x) * g_y * sin(pi_z) * cos(pi_t)
120
v1_xz = pi^2 * A2 * cos(pi_x) * g * cos(pi_z) * cos(pi_t)
121
v1_yz = pi * A2 * sin(pi_x) * g_y * cos(pi_z) * cos(pi_t)
122
# v2 terms (simplifies from ansatz)
123
v2 = v1
124
v2_t = v1_t
125
v2_x = v1_x
126
v2_y = v1_y
127
v2_z = v1_z
128
v2_xx = v1_xx
129
v2_yy = v1_yy
130
v2_zz = v1_zz
131
v2_xy = v1_xy
132
v2_yz = v1_yz
133
# v3 terms (simplifies from ansatz)
134
v3 = v1
135
v3_t = v1_t
136
v3_x = v1_x
137
v3_y = v1_y
138
v3_z = v1_z
139
v3_xx = v1_xx
140
v3_yy = v1_yy
141
v3_zz = v1_zz
142
v3_xz = v1_xz
143
v3_yz = v1_yz
144
145
# Pressure and its derivatives
146
p = rho^2
147
p_t = 2.0 * rho * rho_t
148
p_x = 2.0 * rho * rho_x
149
p_y = 2.0 * rho * rho_y
150
p_z = 2.0 * rho * rho_z
151
152
# Total energy and its derivatives; simiplifies from ansatz that v2 = v1 and v3 = v1
153
E = p * inv_gamma_minus_one + 1.5 * rho * v1^2
154
E_t = p_t * inv_gamma_minus_one + 1.5 * rho_t * v1^2 + 3.0 * rho * v1 * v1_t
155
E_x = p_x * inv_gamma_minus_one + 1.5 * rho_x * v1^2 + 3.0 * rho * v1 * v1_x
156
E_y = p_y * inv_gamma_minus_one + 1.5 * rho_y * v1^2 + 3.0 * rho * v1 * v1_y
157
E_z = p_z * inv_gamma_minus_one + 1.5 * rho_z * v1^2 + 3.0 * rho * v1 * v1_z
158
159
# Divergence of Fick's law ∇⋅∇q = kappa ∇⋅∇T; simplifies because p = rho², so T = p/rho = rho
160
kappa = equations.gamma * inv_gamma_minus_one / Pr
161
q_xx = kappa * rho_xx # kappa T_xx
162
q_yy = kappa * rho_yy # kappa T_yy
163
q_zz = kappa * rho_zz # kappa T_zz
164
165
# Stress tensor and its derivatives (exploit symmetry)
166
tau11 = 4.0 / 3.0 * v1_x - 2.0 / 3.0 * (v2_y + v3_z)
167
tau12 = v1_y + v2_x
168
tau13 = v1_z + v3_x
169
tau22 = 4.0 / 3.0 * v2_y - 2.0 / 3.0 * (v1_x + v3_z)
170
tau23 = v2_z + v3_y
171
tau33 = 4.0 / 3.0 * v3_z - 2.0 / 3.0 * (v1_x + v2_y)
172
173
tau11_x = 4.0 / 3.0 * v1_xx - 2.0 / 3.0 * (v2_xy + v3_xz)
174
tau12_x = v1_xy + v2_xx
175
tau13_x = v1_xz + v3_xx
176
177
tau12_y = v1_yy + v2_xy
178
tau22_y = 4.0 / 3.0 * v2_yy - 2.0 / 3.0 * (v1_xy + v3_yz)
179
tau23_y = v2_yz + v3_yy
180
181
tau13_z = v1_zz + v3_xz
182
tau23_z = v2_zz + v3_yz
183
tau33_z = 4.0 / 3.0 * v3_zz - 2.0 / 3.0 * (v1_xz + v2_yz)
184
185
# Compute the source terms
186
# Density equation
187
du1 = (rho_t + rho_x * v1 + rho * v1_x
188
+ rho_y * v2 + rho * v2_y
189
+ rho_z * v3 + rho * v3_z)
190
# x-momentum equation
191
du2 = (rho_t * v1 + rho * v1_t + p_x + rho_x * v1^2
192
+ 2.0 * rho * v1 * v1_x
193
+ rho_y * v1 * v2
194
+ rho * v1_y * v2
195
+ rho * v1 * v2_y
196
+ rho_z * v1 * v3
197
+ rho * v1_z * v3
198
+ rho * v1 * v3_z -
199
mu_ * (tau11_x + tau12_y + tau13_z))
200
# y-momentum equation
201
du3 = (rho_t * v2 + rho * v2_t + p_y + rho_x * v1 * v2
202
+ rho * v1_x * v2
203
+ rho * v1 * v2_x
204
+ rho_y * v2^2
205
+ 2.0 * rho * v2 * v2_y
206
+ rho_z * v2 * v3
207
+ rho * v2_z * v3
208
+ rho * v2 * v3_z -
209
mu_ * (tau12_x + tau22_y + tau23_z))
210
# z-momentum equation
211
du4 = (rho_t * v3 + rho * v3_t + p_z + rho_x * v1 * v3
212
+ rho * v1_x * v3
213
+ rho * v1 * v3_x
214
+ rho_y * v2 * v3
215
+ rho * v2_y * v3
216
+ rho * v2 * v3_y
217
+ rho_z * v3^2
218
+ 2.0 * rho * v3 * v3_z -
219
mu_ * (tau13_x + tau23_y + tau33_z))
220
# Total energy equation
221
du5 = (E_t + v1_x * (E + p) + v1 * (E_x + p_x)
222
+ v2_y * (E + p) + v2 * (E_y + p_y)
223
+ v3_z * (E + p) + v3 * (E_z + p_z) -
224
# stress tensor and temperature gradient from x-direction
225
mu_ * (q_xx + v1_x * tau11 + v2_x * tau12 + v3_x * tau13
226
+ v1 * tau11_x + v2 * tau12_x + v3 * tau13_x) -
227
# stress tensor and temperature gradient terms from y-direction
228
mu_ * (q_yy + v1_y * tau12 + v2_y * tau22 + v3_y * tau23
229
+ v1 * tau12_y + v2 * tau22_y + v3 * tau23_y) -
230
# stress tensor and temperature gradient terms from z-direction
231
mu_ * (q_zz + v1_z * tau13 + v2_z * tau23 + v3_z * tau33
232
+ v1 * tau13_z + v2 * tau23_z + v3 * tau33_z))
233
234
return SVector(du1, du2, du3, du4, du5)
235
end
236
237
initial_condition = initial_condition_navier_stokes_convergence_test
238
239
# BC types
240
velocity_bc_top_bottom = NoSlip() do x, t, equations_parabolic
241
u_cons = initial_condition_navier_stokes_convergence_test(x, t, equations_parabolic)
242
return SVector(u_cons[2] / u_cons[1], u_cons[3] / u_cons[1], u_cons[4] / u_cons[1])
243
end
244
245
heat_bc_top_bottom = Adiabatic((x, t, equations_parabolic) -> 0.0)
246
boundary_condition_top_bottom = BoundaryConditionNavierStokesWall(velocity_bc_top_bottom,
247
heat_bc_top_bottom)
248
249
# define inviscid boundary conditions
250
boundary_conditions = (; :top_bottom => boundary_condition_slip_wall)
251
252
# define viscous boundary conditions
253
boundary_conditions_parabolic = (; :top_bottom => boundary_condition_top_bottom)
254
255
semi = SemidiscretizationHyperbolicParabolic(mesh, (equations, equations_parabolic),
256
initial_condition, dg;
257
boundary_conditions = (boundary_conditions,
258
boundary_conditions_parabolic),
259
source_terms = source_terms_navier_stokes_convergence_test)
260
261
###############################################################################
262
# ODE solvers, callbacks etc.
263
264
# Create ODE problem with time span `tspan`
265
tspan = (0.0, 1.0)
266
ode = semidiscretize(semi, tspan)
267
268
summary_callback = SummaryCallback()
269
alive_callback = AliveCallback(alive_interval = 10)
270
analysis_interval = 100
271
analysis_callback = AnalysisCallback(semi, interval = analysis_interval, uEltype = real(dg))
272
save_solution = SaveSolutionCallback(interval = analysis_interval,
273
solution_variables = cons2prim)
274
callbacks = CallbackSet(summary_callback, alive_callback, analysis_callback, save_solution)
275
276
###############################################################################
277
# run the simulation
278
279
time_int_tol = 1e-8
280
sol = solve(ode, RDPK3SpFSAL49(); abstol = time_int_tol, reltol = time_int_tol,
281
ode_default_options()..., callback = callbacks)
282
283