Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Step 12 -- Lid-Driven Cavity Flow

Authors
Affiliations
University of Valencia

The lid-driven cavity is the canonical benchmark for 2D incompressible Navier--Stokes solvers. A square box has no-slip walls on all four sides, with the top lid sliding at constant velocity ulid=1u_{\text{lid}} = 1.

PDE -- vorticity-streamfunction formulation:

∂ω∂t+u∂ω∂x+v∂ω∂y=ν ∇2ω\frac{\partial \omega}{\partial t} + u\frac{\partial \omega}{\partial x} + v\frac{\partial \omega}{\partial y} = \nu\,\nabla^2 \omega
∇2ψ=−ω,u=∂ψ∂y,v=−∂ψ∂x\nabla^2 \psi = -\omega, \qquad u = \frac{\partial \psi}{\partial y}, \qquad v = -\frac{\partial \psi}{\partial x}

At each time step we:

  1. Invert the Poisson equation ∇2ψ=−ω\nabla^2\psi = -\omega to get the streamfunction (Step 10 solver)

  2. Compute velocity from ψ\psi

  3. Advect and diffuse ω\omega

  4. Apply wall BCs (Thom’s formula for wall vorticity)

The Reynolds number is Re=ulidL/νRe = u_{\text{lid}} L / \nu. At Re=100Re = 100 the flow is steady and well-characterised by the Ghia et al. (1982) benchmark data.

What you will learn:

  1. How to set up and integrate a Navier--Stokes model in somax

  2. How to recover velocity and streamfunction via model.diagnose()

  3. How to compare against the Ghia benchmark

Arakawa C-Grid and Boundary Conditions

The vorticity ω\omega and streamfunction ψ\psi live at cell centres on the Arakawa C-grid, while velocity components sit on cell faces:

       V_{j+1/2}
    ┌─────●─────┐
    │           │
 U  ●     T     ●  U
i-1/2   (i,j)    i+1/2
    │           │
    └─────●─────┘
       V_{j-1/2}

Lid-driven cavity BCs:

             u_lid = 1  (moving lid)
        ┌──────────────────────┐
        │                      │
 u=0    │    omega, psi        │  u=0
 v=0    │    (interior)        │  v=0
        │                      │
        └──────────────────────┘
             u=0, v=0  (no-slip)

At walls, vorticity is computed via Thom’s formula:

ωwall=−2(ψinterior−ψwall)Δn2\omega_{wall} = -\frac{2(\psi_{interior} - \psi_{wall})}{\Delta n^2}

At the top lid (moving at ulidu_{lid}), an extra term accounts for the wall velocity:

ωtop=−2ψinteriorΔy2−2ulidΔy\omega_{top} = -\frac{2\psi_{interior}}{\Delta y^2} - \frac{2 u_{lid}}{\Delta y}

1. Create the model

We use a 64x64 grid with ν=0.01\nu = 0.01 (Re=100Re = 100).

Grid: 34 x 34 (including ghost cells)
dx = 0.0312, dy = 0.0312
Re = 20

2. Initial condition and integration

Start from rest (ω=0\omega = 0 everywhere) and integrate until the flow reaches a statistical steady state. At Re=100Re = 100 the flow converges within t≈5t \approx 5--10.

We use the default Tsit5() solver with a small time step for stability of the explicit advection.

Final omega range: [-64.0000, 7.1936]
All finite: True

3. Diagnostics: velocity and streamfunction

model.diagnose() recovers the streamfunction ψ\psi and velocity components (u,v)(u, v) from the vorticity field, along with kinetic energy and enstrophy.

Kinetic energy: 0.008409
Enstrophy:      0.500323

4. Visualise the flow

We plot the vorticity field and streamfunction contours.

<Figure size 1600x500 with 6 Axes>

5. Ghia benchmark comparison

Ghia, Ghia & Shin (1982) tabulated centreline velocity profiles for the lid-driven cavity at various Reynolds numbers. The data for Re=100Re = 100 is bundled in somax.

We extract:

  • uu-velocity along the vertical centreline (x=0.5x = 0.5)

  • vv-velocity along the horizontal centreline (y=0.5y = 0.5)

<Figure size 1200x500 with 2 Axes>

At 64x64 the agreement is qualitatively good but not pixel-perfect. The overall shape -- the primary vortex, wall jets, and centreline profiles -- matches the benchmark. Higher resolution (128x128 or 256x256) and/or higher-order advection schemes would improve the match.

6. Vorticity-streamfunction formulation: why?

The vorticity-streamfunction form eliminates pressure entirely. In the primitive-variable form (u,v,pu, v, p), one must solve a pressure Poisson equation to enforce ∇⋅u=0\nabla \cdot \mathbf{u} = 0. In the vorticity form, the divergence-free constraint is built in: any velocity derived from a streamfunction is automatically divergence-free.

The trade-off: we must still solve a Poisson equation (for ψ\psi from ω\omega), but there is no pressure variable at all. This simplifies the numerics significantly for 2D flows.

7. Differentiability -- gradient through the NS solver

We compute ∂E/∂ν\partial \mathcal{E} / \partial \nu where E\mathcal{E} is the final enstrophy. This gradient tells us how viscosity affects the flow at steady state.

dEnstrophy/dnu = -0.305957

Summary

ConceptAPI
Create NS modelIncompressibleNS2D.create(nx, ny, nu, problem="cavity")
Initial stateNSVorticityState(omega=jnp.zeros(...))
Integratemodel.integrate(state0, t0, t1, dt, saveat=...)
Recover velocitymodel.diagnose(state) returns ψ,u,v,KE\psi, u, v, KE
Ghia dataGHIA_RE100_Y, GHIA_RE100_U, etc.

Next: Step 13 applies the same solver to pressure-driven channel (Poiseuille) flow with an analytical solution and demonstrates differentiating through the simulation.