Documentation of the main branch
These pages follow Mallard's main branch, which is ahead of release 0.8.0: some features they describe come with the next release.
Turbulent channel flow (LES)¶
Turbulent flow between two parallel walls, driven by a constant mass flow, is the canonical wall-bounded flow: its statistics depend only on the friction Reynolds number Re_τ = u_τ h / ν, and the direct numerical simulations of Moser, Kim & Mansour (1999) give them at Re_τ = 180, 395 and 590. This tutorial runs a wall-resolved large-eddy simulation at Re_τ = 180 on a mesh of 49,000 hexahedra from Gmsh, follows the flow from laminar-like rolls to turbulence, collects time averages, and compares the mean velocity and Reynolds stresses with the DNS.
You will use: a structured hexahedral Gmsh mesh with periodic zones
([[periodic]]), an initial state as expressions of x, y and z, the
constant-mass-flow forcing, the Sigma subgrid model and the
kinetic-energy-preserving hybrid flux, running statistics ([statistics]),
the dissipation budget of [integrals], and restart files. Files:
tutorials/channel_les/. Setup:
Tutorials.
1. Geometry¶
Walls at y = 0 and y = 2h; the flow is periodic in x and z over a box of 2πh × 2h × πh, long and wide enough for the largest near-wall structures at this Reynolds number. In units of h and of the bulk density and velocity U_b, the bulk Reynolds number 2 h U_b / ν = 5600 of the DNS fixes μ = 3.57e-4; the friction velocity, and so Re_τ, comes out of the run.
2. Mesh¶
channel.geo extrudes a line of
nodes along y, clustered toward both walls with Mallard's tanh law (the same
nodes as [mesh] stretching gives a generated box), first along x, then
along z. Extrusion makes the faces at x = 0 and x = 2πh carry the same nodes
translated, as [[periodic]] needs.
mkdir -p run/channel_les && cd run/channel_les
cp $MALLARD/tutorials/channel_les/input.toml .
gmsh $MALLARD/tutorials/channel_les/channel.geo -3 -o channel.msh # 32 x 48 x 32
python3 $MALLARD/tutorials/channel_les/plot_channel_les.py mesh channel.msh --out .
With Re_τ ≈ 180 the cells are Δx⁺ = 35 and Δz⁺ = 18 apart, Δy⁺ = 1.2 at the wall and 16 at the center: a coarse wall-resolved LES, which resolves the near-wall streaks but not their finest scales and leaves those to the subgrid model.
3. Input file¶
| Table | In this case |
|---|---|
[run] |
t_stop = 300 h/U_b, at CFL 0.9 |
[mesh], [[periodic]] |
channel.msh; left/right joined with translation = [2π, 0, 0], back/front with [0, 0, π]: their faces become interior and need no [[boundaries]] |
[initialize] |
analytical: the turbulent-like mean profile (8/7)(1 − |y − 1|)^(1/7), whose bulk velocity is 1, plus streamwise and spanwise rolls of about 15% of U_b, divergence-free and zero at the walls, written as expressions of x, y and z |
[[boundaries]] |
bottom, top: wall_isothermal at the bulk temperature, which carries away the heat of dissipation |
[source] |
mass_flow = [1, 0, 0]: a uniform body force holds the bulk mass flow at 1 |
[numerics] |
convective_flux = "hybrid": the kinetic-energy-preserving central flux, with HLLC only at compressions (there are none here); unlimited MUSCL states |
[physics] |
navier_stokes, bulk Mach number 0.2 (p_ref = 1/(γ M²)) |
[les] |
model = "sigma" with Scotti's filter width for the stretched cells |
[statistics] |
Running means of ρ, u, p, T and the covariances u'u', v'v', w'w', u'v', every 10 steps from t = 100 |
[integrals] |
budget = true: the dissipation of kinetic energy split into molecular, subgrid and numerical parts |
[[forces]] |
The force on each wall: its viscous x-component is the wall shear |
[[write_data]] |
Every 50 h/U_b: the flow (u, p, the Q-criterion, the eddy viscosity), the statistics, and a restart file |
4. Run¶
The time step is set by the acoustic speed in the thin wall cells (1e-3 h/U_b), so 300 h/U_b is 300,000 steps: under an hour on one A100, and hours on a CPU.
$MALLARD/build-3d/src/Mallard -i input.toml --kokkos-num-threads=8 # CPU threads
mpirun -n 4 $MALLARD/build-3d/src/Mallard -i input.toml # MPI ranks
A run that stops (a time limit, t_wall_stop, or a crash) continues from
its last restart file, statistics included, bit for bit: set [initialize]
to type = "restart" and file = "restart/channel_<step>.restart".
5. Monitor¶
The rolls break down into turbulence within the first 30 h/U_b, and Re_τ
settles by t ≈ 90. The wall
shear, which sets Re_τ, is in forces_bottom.csv and forces_top.csv as the
run goes; integrals.csv has the kinetic energy and the dissipation budget.
The statistics should start only once Re_τ has settled (t = 100 here) and
run long enough to converge the averages: here 200 h/U_b, about 13 h/u_τ.
6. Post-process and compare¶
averages the last statistics snapshot over x and z (with
tools/plane_average.py, which also adds the dispersive part of the
covariances), folds the two halves of the channel, takes u_τ from the wall
shear averaged over the same window, and compares in wall units with the DNS,
downloaded on first use:
averaging window t = 100 to 299.954 h/U_b (12.7 h/u_tau)
Re_tau = 178.3 (MKM 178.1, +0.1%), Cf = 0.00807 (MKM 0.00814, -0.8%)
peak u_rms+ 2.732 at y+ = 15.6 (MKM 2.658 at 15.3)
peak v_rms+ 0.720 at y+ = 65.7 (MKM 0.836 at 52.2)
peak w_rms+ 0.976 at y+ = 34.4 (MKM 1.087 at 35.1)
peak -u'v'+ 0.682 at y+ = 34.4 (MKM 0.723 at 30.0)
U+(10) = 8.56 (MKM 8.52)
U+(30) = 13.89 (MKM 13.87)
U+(100) = 17.26 (MKM 17.15)
dissipation: molecular 89.0%, SGS 10.0%, numerical 1.0%
Re_τ and the skin friction are within 1% of the DNS and the mean velocity within 1% across the channel. The fluctuations are the resolved part only: u_rms is 3% high at its peak, and v_rms and w_rms are 10-14% low, the energy of the scales the mesh does not resolve (finer meshes in x and z recover it). The subgrid model takes 10% of the dissipation and the central scheme 1%, so the model, not the numerics, does the work of the unresolved scales.
7. Higher Reynolds numbers and wall models¶
The cost of a wall-resolved LES grows steeply with the Reynolds number, since
the near-wall cells must shrink with the viscous length ν / u_τ:
examples/channel_les runs Re_τ = 395 and 590 on 64³ and 96³ cells.
Wall-modeled LES removes that constraint by modeling the inner layer and
resolving only the outer flow; it is under development for Mallard (issue
#256). This tutorial
is set up for it: its mesh is the channel.geo of this page with a uniform
or mildly stretched spacing in y (-setnumber beta 0.5), and its input this
one at a higher bulk Reynolds number, with the wall model's table in place of
the wall-resolution requirement. This section will walk through it once the
wall model is merged.
8. Things to try¶
- No model. Remove
[les]: with the central flux the only dissipation left at the grid scale is numerical, and Re_τ comes out several percent high (seeexamples/channel_les). - Resolution.
-setnumber nx 64 -setnumber nz 64halves Δx⁺ and Δz⁺. - Riemann solver everywhere.
convective_flux = "riemann"and compare the numerical share of the dissipation.