Complete
CFD with Python
A fluid-flow solver written from scratch that shows Von Kármán vortex shedding.
- Strouhal number at Re = 2000.159
From scratch
A computational fluid dynamics solver built from scratch in Python: a direct numerical simulation of 2D incompressible flow past a cylinder, to watch vortex shedding (the Von Kármán vortex street) appear.
- It solves the 2D incompressible Navier–Stokes equations at , in a channel long and wide with the cylinder at one fifth of the length.
- Chorin's projection method on a staggered grid, with the cylinder added by an immersed boundary method.
- Numba compiles the grid loops to parallel machine code.
- The run saves velocity and vorticity frames, a video of the simulation, and a dataset (
.npz) for later surrogate modelling with a PINN. - The repo has the explanation (
Explanation.ipynb) and the code (CFD.ipynb) side by side.
The cell below runs the same method live in your browser. Drag the cylinder to move it.
The equations
With the free-stream speed , the cylinder diameter and the density all set to 1, the equations are already non-dimensional, and the only parameter left is the Reynolds number :
The first says the fluid is incompressible (no velocity divergence). The second is Newton's second law for each bit of fluid: it is pushed by pressure differences, slowed by viscosity, and pushed by , the force that stands in for the cylinder (see below).
A staggered grid
The domain is cut into cells (). Pressure lives at cell centres, the horizontal velocity on the left and right faces, and the vertical velocity on the top and bottom faces. This staggered (MAC) layout puts each velocity exactly between the two pressures that push it, so the pressure gradient and the divergence of a cell are plain differences of neighbours:
Diffusion uses the 5-point stencil , and advection () uses first-order upwind differences: each derivative looks at the neighbour the flow is coming from. Where a velocity component isn't stored (for example at a face), it is the average of the four nearest values.
One time step: Chorin's projection
Stepping the momentum equation forward on its own would not keep the flow divergence-free, and it gives no way to update the pressure. Chorin's projection method splits each step in three:
- Predict a velocity from advection, diffusion and the cylinder's force, ignoring pressure: .
- Solve for the pressure that removes the divergence of . Asking for in step 3 gives a Poisson equation: .
- Correct the velocity with the pressure gradient: , which is now divergence-free.
The Poisson equation becomes a linear system with one row per cell (73,728 of them). never changes, so it is built once as a sparse matrix and factorised once with SciPy; each step then only solves for a new . Stored as a dense NumPy array, would need 40.5 GiB.
The walls have (each wall cell copies its pressure into a ghost cell, which just adds the missing neighbour's coefficient to the diagonal), and one cell is pinned to , because pressure is only defined up to a constant.
The cylinder: an immersed boundary
The grid is a plain rectangle and never changes. The cylinder is 200 points on its surface, , and each step:
- Interpolate the velocity at every surface point from the four nearest grid values (bilinear weights).
- Compute the force that would stop the fluid there (the cylinder is still): , with a relaxation factor so interpolation errors don't produce excessive forces.
- Spread each force back onto the same four grid points with the same weights, and add it to .
Because the cylinder is only a list of points, moving it means moving the points. That is why you can drag it around in the live cell.
Boundaries and stability
The fluid comes in from the left at speed 1 and a small angle of , so the flow isn't perfectly symmetric and the wake can start to oscillate. The walls are frictionless (no flow through them), and the outlet is open: velocities don't change across it.
The explicit time step has two limits, from diffusion and from advection:
(taking as a worst case). The notebook uses to stay safely inside it and to capture the shedding smoothly.
Results: lift, drag and the Strouhal number
The force the cylinder exerts on the fluid, summed over its surface points, gives the drag and lift, and their coefficients and (since ). As vortices peel off one side and then the other, oscillates. Its frequency , found with a fast Fourier transform, gives the Strouhal number .
The empirical relation predicts about at . The notebook measures , which matches . The reason is the first-order upwind scheme: its truncation error acts like extra, numerical viscosity, so the flow behaves as if the Reynolds number were lower:
The live cell shows the same effect. Its grid is coarser (256 × 128, ), so it
has more numerical viscosity and measures about at (watch St
in the Variables pane). Raise the Reynolds number and it creeps towards the textbook value.
A second method: lattice-Boltzmann
The cell below is a different solver for the same flow, written for this site to compare (it is not in the notebook). Instead of velocities and pressure, the lattice-Boltzmann method tracks how many fluid particles move in each of 9 directions at every grid point (D2Q9). Each step they stream to the neighbouring point and collide, relaxing towards equilibrium at a rate set by the viscosity. The cylinder is cells that bounce particles back. Pressure is never solved for, which makes each step very cheap.
References
From the notebook's sources:
- C. H. K. Williamson and G. L. Brown, A series in to represent the Strouhal–Reynolds number relationship of the cylinder wake, Journal of Fluids and Structures, 1998.
- A. Placzek, J.-F. Sigrist and A. Hamdouni, Numerical simulation of vortex shedding past a circular cylinder in a cross-flow at low Reynolds number with finite volume technique, ASME Pressure Vessels and Piping Conference, 2007.
- J. Kim, D. Kim and H. Choi, An immersed-boundary finite-volume method for simulations of flow in complex geometries, Journal of Computational Physics, 2001.
- F. H. Harlow and J. E. Welch, Numerical calculation of time-dependent viscous incompressible flow of fluid with free surface, Physics of Fluids, 1965.
- Flow Science, What are artificial and numerical viscosities?