Lid-driven cavity, Re = 100
State: written up. The comparison table below is complete and may be cited.
Case: Lid-driven cavity (validation)
Reference: Ghia U., Ghia K.N., Shin C.T., “High-Re solutions for
incompressible flow using the Navier–Stokes equations and a multigrid method”,
Journal of Computational Physics 48 (1982) 387–411, Table I.
Last run: 2026-08-07, against the tree at that date, bundled OpenFOAM v2606.
The standard verification problem for an incompressible code: a square box of still fluid with the top wall dragged sideways. It has no analytic solution, but Ghia et al. solved it on a 129×129 grid with a multigrid method and tabulated the velocity along the centrelines, and those tables have been the check on incompressible solvers ever since.
Set-up
Section titled “Set-up”| Domain | 0.1 m square, one cell thick, frontAndBack empty |
| Mesh | 20 × 20 cells, uniform (400 cells) |
| Lid | 1 m/s, movingWallVelocity; the other three walls no-slip |
| Fluid | ρ = 1 kg/m³, ν = 10⁻³ m²/s → Re = UL/ν = 100 |
| Solver | icoFoam — laminar, transient, PISO |
| Run | to t = 40 s on Δt = 0.002 s, Courant 0.4 |
Forty seconds is four viscous diffusion times (L²/ν = 10 s), which is what the cavity settles on. It is steady well before the end: between t = 30 s and t = 40 s the largest change anywhere in the field is 4 × 10⁻⁸ m/s.
Result
Section titled “Result”u along the vertical centreline, normalised by the lid speed:
| y/L | Ghia et al. | SHD Sim CFD | difference |
|---|---|---|---|
| 1.0000 | +1.00000 | +1.00000 | +0.00000 |
| 0.9766 | +0.84123 | +0.83133 | −0.00990 |
| 0.9688 | +0.78871 | +0.78117 | −0.00754 |
| 0.9609 | +0.73722 | +0.73196 | −0.00526 |
| 0.9531 | +0.68717 | +0.68337 | −0.00380 |
| 0.8516 | +0.23151 | +0.23338 | +0.00187 |
| 0.7344 | +0.00332 | +0.00293 | −0.00039 |
| 0.6172 | −0.13641 | −0.13429 | +0.00212 |
| 0.5000 | −0.20581 | −0.19896 | +0.00685 |
| 0.4531 | −0.21090 | −0.20324 | +0.00766 |
| 0.2813 | −0.15662 | −0.15062 | +0.00600 |
| 0.1719 | −0.10150 | −0.09787 | +0.00363 |
| 0.1016 | −0.06434 | −0.06215 | +0.00219 |
| 0.0703 | −0.04775 | −0.04530 | +0.00245 |
| 0.0625 | −0.04192 | −0.04064 | +0.00128 |
| 0.0547 | −0.03717 | −0.03599 | +0.00118 |
| 0.0000 | +0.00000 | +0.00000 | +0.00000 |
RMS difference 0.0047. Worst point 0.0099 — that is 0.5% and 1.0% of the lid speed.
The zero crossing, which is where the primary vortex sits and the most demanding thing on the table to get right, is at y/L = 0.734 against Ghia’s 0.7344.
What the remaining difference is
Section titled “What the remaining difference is”Mesh, not physics. This is 400 cells against Ghia’s 16 641, and the two largest differences are both in the top 5% of the box, where the lid drags a thin shear layer that twenty cells cannot resolve. The interior agrees to about half a percent. Refining the mesh in the app closes the gap; the coarse mesh is used here deliberately, because a benchmark that only agrees when it is expensive is not much of a reassurance.
Two defects this found
Section titled “Two defects this found”Building this benchmark was the first time the product had ever been asked for a published answer, and it immediately found two faults that had been in the software the whole time:
- PISO cases could not run at all.
fvSolutionnamed its transient blockPIMPLEwhatever the algorithm was, withnOuterCorrectors 1standing in for PISO.pimpleFoamaccepts that;pisoFoamandicoFoamdo not — they build apisoControl, which wants aPISOsub-dictionary and stops without one. Selecting the PISO algorithm selectspisoFoam, so every PISO case the app had ever written stopped at start-up. - Closed domains could not run at all. With no pressure outlet the pressure
level is undetermined and OpenFOAM asks for
pRefCellandpRefValue. The app’s own validation rule said these “will be written to pin the level”. Nothing wrote them — the string appeared nowhere in the product. Any sealed case — a cavity, a tank, a stirred vessel — stopped with “Unable to set reference cell for field p”. This is almost certainly why the buoyant cavity example had never been solved end to end.
Both are fixed, and the second is the more embarrassing: the software described a thing it did not do.
This section is kept because it is the evidence that the process works. A benchmark that only ever confirms what was already believed is not being used for anything.
What this benchmark does not cover
Section titled “What this benchmark does not cover”The cavity checks four things: incompressible laminar flow, the pressure–velocity coupling, wall conditions, and 2-D handling. It says nothing about the rest of the product, and in particular nothing about:
- Turbulence. There is no turbulence model in the case at all —
icoFoamhas none. Every RANS and LES model in the product is untouched by this page. - Wall functions and near-wall treatment. No wall model is exercised; the walls are resolved no-slip on a uniform mesh.
- Separation and reattachment. The recirculation here is fixed by the geometry — it is driven into a corner. Nothing asks the solver to predict where a shear layer detaches or lands.
- Unsteady flow. The run is transient only as a route to a steady answer. No periodic or genuinely unsteady behaviour is checked.
- Inlets and outlets. The domain is sealed. Inlet profiles, outlet conditions and far-field boundaries are all unexercised.
- Meshing. This is a uniform block, not a snapped mesh.
snappyHexMesh, surface refinement and boundary layers are not involved. - Compressibility, heat, buoyancy, multiphase, particles, reacting flow — none of it. Those solvers share the case machinery, not the answer.
- Three dimensions. The case is a plane problem solved one cell thick.
Everything in that list is why the benchmark list exists.
Reproducing this from the application
Section titled “Reproducing this from the application”Nothing here is set up by hand or outside the product.
- Worked example →
Lid-driven cavity (validation) - Generate mesh
- Run
The example seeds the domain, the two-dimensional setting, the icoFoam
solver, the fluid properties and the run control listed above. If any of those
values differ from the set-up table, the table is what was actually run and the
example has since changed — say so rather than editing the numbers.
Format for new benchmarks: _TEMPLATE.md.