From: Ansys Fluent Rust Computational fluid dynamics
Code: https://github.com/A1i98/rust-cfd-cylinder-flow
Bind
[[meta bind projects]]Simulation in ANSYS
Problem: 2D Flow Over a Circular Cylinder
Flow type: Incompressible, laminar, unsteady
Reynolds number: Re = 100
Solver type: Transient Navier-Stokes
Domain length: L = 20 m Domain height: H = 10 m Cylinder diameter: D = 1 m Cylinder radius: R = 0.5 m Cylinder center: xc = 1 m yc = 5 m
Density: rho = 1
Inlet velocity: U∞ = 1
Cylinder diameter: D = 1
Re = 100
mu = rho * U∞ * D / Re
mu = 1 * 1 * 1 / 100
mu = 0.01
rho = 1
mu = 0.01
nu = mu / rho = 0.01


Simulation in Rust
Case definition
| Quantity | Value |
|---|---|
| Domain length, | |
| Domain height, | |
| Cylinder diameter, | |
| Cylinder radius, | |
| Cylinder center | |
| Density, | |
| Free-stream velocity, | |
| Reynolds number, | |
| Dynamic viscosity, | |
| Kinematic viscosity, | |
| Mesh | |
| Grid spacing | |
| Physical time step | |
| End time | |
| Cylinder resolution | cells |
| Blockage ratio |
The Reynolds number is
Expected flow physics
At , flow past a circular cylinder is expected to be laminar but unsteady. The symmetric steady wake is unstable, and the developed solution should exhibit periodic vortex shedding known as the von Kármán vortex street.
Governing equations
The incompressible Navier–Stokes equations are
The LBM solver recovers these equations in the low-Mach hydrodynamic limit.
D2Q9 lattice Boltzmann formulation
The D2Q9 discrete velocities are
The weights are
The equilibrium distribution is
Macroscopic density and velocity are reconstructed from
The physical-to-lattice conversion gives
TRT collision model
The distribution and equilibrium functions are split into even and odd parts with respect to the opposite lattice direction :
The TRT collision step is
The even relaxation rate controls viscosity:
The odd rate is determined from the TRT magic parameter :
Using
produces approximately
Why TRT is used hereTRT separates the viscous even modes from the odd kinetic modes. This significantly improves robustness for halfway bounce-back when is close to .
TRT code section
let omega_plus = self.cfg.omega_plus();let omega_minus = self.cfg.omega_minus();
for k in 0..Q { let ko = OPP[k]; let f_plus = 0.5 * (self.f[base + k] + self.f[base + ko]); let f_minus = 0.5 * (self.f[base + k] - self.f[base + ko]); let eq_plus = 0.5 * (eq[k] + eq[ko]); let eq_minus = 0.5 * (eq[k] - eq[ko]);
f_post[k] = self.f[base + k] - omega_plus * (f_plus - eq_plus) - omega_minus * (f_minus - eq_minus);}Boundary conditions
| Boundary | Physical condition | Numerical implementation |
|---|---|---|
| Inlet | , | Zou/He velocity reconstruction |
| Outlet | , , | inner populations copied and normalized to |
| Cylinder | , | halfway bounce-back |
| Top/bottom | , | specular reflection |
Outlet implementation
At the outlet, the distribution shape from the adjacent internal cell is copied and normalized:
Therefore,
while the velocity is inherited from the adjacent cell, approximating a zero streamwise gradient.
let bi = self.base(nx - 2, j);let rho_inner: f64 = (0..Q).map(|k| self.f[bi + k]).sum();let scale = 1.0 / rho_inner;
for k in 0..Q { self.f[b + k] = self.f[bi + k] * scale;}Symmetry-breaking perturbation
A perfectly symmetric grid, centered cylinder, symmetric boundaries, and initial field can preserve the unstable symmetric numerical branch. A small perturbation is therefore introduced behind the cylinder.
Version 3 uses a localized streamfunction perturbation:
Velocity perturbations are obtained from
with the code sign convention chosen consistently. Because the perturbation comes from a streamfunction,
This breaks wake symmetry without creating a strong compressibility pulse.
let g = (-((x - x0).powi(2) + (y - y0).powi(2)) / (2.0 * sigma2)) .exp();let psi = amp * sigma * g;let du = -(y - y0) * psi / sigma2;let dv = (x - x0) * psi / sigma2;let ux = u_lu + du;let uy = dv;Force coefficients
The momentum-exchange method calculates the force on the cylinder during bounce-back.
In lattice units, the denominator is
Version 3 averages force over each output_every interval:
This reduces high-frequency lattice noise without suppressing the physical shedding frequency.
Running the solver
Clean short test
rm -rf results_test
cargo run --release -- \ --out results_test \ --t-end 4 \ --output-every 100 \ --print-every 500 \ --frame-every 500 \ --diagnostic-every 100 \ --perturb 1e-3Full simulation
rm -rf results
cargo run --release -- \ --out results \ --output-every 100 \ --print-every 1000 \ --frame-every 1000 \ --diagnostic-every 100 \ --perturb 1e-3Important runtime parameters
| Argument | Default | Purpose |
|---|---|---|
--output-every | 100 | CSV force/probe interval |
--print-every | 1000 | terminal log interval |
--frame-every | 1000 | BMP animation interval |
--diagnostic-every | 100 | finite-value and stability check interval |
--perturb | 1e-3 | divergence-free wake seed amplitude |
--trt-lambda | 0.1875 | TRT magic parameter |
Output files
case_summary.txtfield.csvfield_tecplot.datforce_coefficients.csvprobe_wake.csvwake_centerline_y5.csvvertical_profile_x10.csvframes/speed_00000.bmpframes/speed_00001.bmpframes/vorticity_00000.bmpframes/vorticity_00001.bmpimages/speed.svgimages/u_velocity.svgimages/v_velocity.svgimages/pressure.svgimages/vorticity.svgimages/streamfunction.svgimages/force_coefficients.svgimages/wake_v_probe.svgAnimation workflow
The signed vorticity field is the clearest visualization of alternating shedding.
ffmpeg -framerate 10 -i results/frames/vorticity_%05d.bmp \ -c:v libx264 -pix_fmt yuv420p vorticity.mp4Speed animation:
ffmpeg -framerate 10 -i results/frames/speed_%05d.bmp \ -c:v libx264 -pix_fmt yuv420p speed.mp4Frame interpretation
speed_00000.bmpandvorticity_00000.bmprepresent the initial field. Subsequent files represent intervals offrame_everysolver steps.
Plots
Speed magnitude
Streamwise velocity

Transverse velocity

Relative pressure

Vorticity field
Streamfunction diagnostic

Drag and lift coefficients

Wake transverse-velocity probes
