Inviscid flow around bodies

A finite-difference stream-function solver for steady, inviscid 2D flow around cylinders, airfoils and arbitrary shapes.

Streamlines around a NACA 0009 section at 10 degrees angle of attack, coloured by the value of the stream function.

Overview

How does air flow around a cylinder, an airfoil, or even a car? We wrote a Python solver that computes the steady, inviscid flow around any two-dimensional body, from simple shapes to outlines traced from a picture, by solving Laplace’s equation for the stream function on a grid. From it come the velocity and pressure fields and the lift, and an interactive window lets you change the shape, the angle of attack and the grid to see how each one changes the flow.

Model and assumptions

The flow is steady, two-dimensional, incompressible and inviscid. Incompressibility lets the velocity be written with a stream function ψ\psi, and for irrotational flow ψ\psi satisfies Laplace’s equation:

∇2ψ=∂2ψ∂x2+∂2ψ∂y2=0\nabla^2 \psi = \frac{\partial^2 \psi}{\partial x^2} + \frac{\partial^2 \psi}{\partial y^2} = 0

The velocity components follow from u=∂ψ/∂yu = \partial\psi/\partial y and v=−∂ψ/∂xv = -\partial\psi/\partial x, and the pressure from Bernoulli’s equation:

p=p∞+12ρ(U∞2−∣V∣2)p = p_\infty + \tfrac{1}{2}\rho\left(U_\infty^2 - |\mathbf{V}|^2\right)

The outer boundaries carry a uniform stream. The body is impermeable, so its wall is a streamline with a constant value of ψ\psi. We used U∞=60U_\infty = 60 m/s in air at 20 °C, well below Mach 0.3, so the incompressible assumption holds.

Numerical method

The domain is a Cartesian grid and the body is a mask of grid points. With a centred five-point discretisation and equal spacing in xx and yy, each interior value is the mean of its four neighbours:

ψi,j=14(ψi+1,j+ψi−1,j+ψi,j+1+ψi,j−1)\psi_{i,j} = \tfrac{1}{4}\left(\psi_{i+1,j} + \psi_{i-1,j} + \psi_{i,j+1} + \psi_{i,j-1}\right)
Grid diagram showing the point i, j and its four neighbours, with spacings delta x and delta y.
The five-point stencil: each grid value is updated from its four neighbours. Source: Team presentation.

A Jacobi iteration repeats this update until the largest change falls below a tolerance. The first version ran the loops in plain Python; a later version compiled the iteration and the velocity calculation with Numba and ran the grid rows in parallel, because computation time limited how fine the grid could be. Velocities come from centred differences of ψ\psi. For lift and drag, the pressure field is interpolated onto the body outline and integrated.

The program runs in a Matplotlib window with sliders for the circulation constant, the angle of attack and the grid spacing. It handles a cylinder, a rotating cylinder, a Joukowski airfoil, NACA sections read from coordinate files, and any outline traced from an image.

Velocity fields around three shapes traced from images: a house, a rugby ball and a car, with colour bars in metres per second.
Shapes traced from images: the speed of the flow around a house, a rugby ball and a car (m/s). The flow speeds up over the top and bottom of each body and slows down in front of it and behind it. Source: Team presentation, program output.
Velocity magnitude and pressure fields around a cylinder without circulation, with colour bars in metres per second and pascals.
Cylinder without circulation: speed (left, m/s) and pressure (right, Pa). The flow speeds up over the top and bottom and stagnates at the front and back. Source: Team project, program output.

What the results show

For a cylinder, the solver reproduces the expected picture: symmetric fields and no lift without circulation, and lift in the expected direction once a circulation is added, as for a rotating cylinder.

For airfoils, the value of ψ\psi on the body sets the circulation, and nothing in the solver fixes it. In the real flow the Kutta condition picks the one circulation that makes the flow leave the trailing edge smoothly. We knew this, but the code did not impose it: we chose the constant by eye until the streamlines looked right.

CaseLift coefficient computed
NACA 0009, 5°0.203
NACA 0009, 10°0.418
NACA 0015, 5°0.285
NACA 4415, 5°0.719

For a thin symmetric section at 5°, thin-airfoil theory gives Cl=2πα≈0.55C_l = 2\pi\alpha \approx 0.55. The computed values are well below that, which is what a hand-set circulation produces.

Pressure field around a NACA 0009 section at 10 degrees, with a colour bar in pascals.
Pressure field around the same NACA 0009 section at 10°, in pascals: low pressure over the upper surface near the leading edge. Source: Team project, program output.