The Courant number (Co) is the ratio of the distance a fluid particle travels in one time step to the size of a mesh cell. When Co exceeds 1, information propagates faster than the mesh can resolve it — and the simulation diverges. Understanding and controlling Co is essential for any transient OpenFOAM simulation.
The CFL (Courant-Friedrichs-Lewy) condition states:
Co = U · Δt / Δx
Where U is the local fluid velocity, Δt is the time step, and Δx is the local cell size. For an explicit time-marching scheme, numerical stability requires Co < 1 in every cell.
In the OpenFOAM log you'll see:
Courant Number mean: 0.127 max: 0.843
The max value is what matters for stability. It occurs in the smallest cells or highest-velocity regions — typically near wall boundaries or in refined regions of the mesh.
When Co > 1, a fluid particle travels more than one cell width per time step. This means the upstream information that should influence the current cell is not accounted for — the scheme is trying to extrapolate beyond its stencil. For explicit schemes (like the pure PISO algorithm in icoFoam), this produces velocities that violate physical bounds and grow without limit.
For implicit schemes (like PIMPLE with multiple outer correctors), the coupling between pressure and velocity allows larger Co. However, accuracy degrades as Co increases even if the simulation remains stable — temporal discretisation error grows proportionally to Co above 1.
Before running, estimate the maximum velocity in your domain and the minimum cell size:
// Co_target = 0.8 (conservative)
// Δt = Co_target * Δx_min / U_max
//
// Example: U_max = 5 m/s, Δx_min = 0.002 m (snappyHexMesh refinement)
// Δt = 0.8 * 0.002 / 5 = 3.2e-4 s
Find Δx_min from the checkMesh output (look for Minimum face area or estimate from your refinement levels).
If you know your base mesh cell size and refinement levels, you can estimate the minimum cell size directly. Each refinement level halves the cell size:
// Base mesh: 0.1 m cells (blockMesh)
// Refinement level 3: 0.1 / 2^3 = 0.0125 m
// Refinement level 5: 0.1 / 2^5 = 0.003125 m
//
// U_max = 20 m/s, Co_target = 0.5
// Δt = 0.5 * 0.003125 / 20 = 7.8e-5 s ≈ 1e-4 s (rounded down for safety)
Always round deltaT down rather than up when setting it manually. The cost of halving deltaT is doubled computation time — but the cost of a diverged simulation is starting over entirely.
The best practice for transient simulations is to let OpenFOAM automatically adjust deltaT to maintain a target Courant number. Configure in controlDict:
application pimpleFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 1.0;
deltaT 1e-4; // initial deltaT
adjustTimeStep yes;
maxCo 0.8; // target max Courant number
maxDeltaT 0.01; // upper bound
writeControl adjustableRunTime;
writeInterval 0.1;
With adjustable time stepping, OpenFOAM increases deltaT when Co is low (saving computation time) and reduces it when Co approaches the limit (maintaining stability).
At each time step, pimpleFoam computes the current maximum Courant number Co_max. It then scales deltaT for the next step by the factor maxCo / Co_max: if Co_max is 0.4 and maxCo is 0.8, deltaT doubles. If Co_max is 0.9 and maxCo is 0.8, deltaT is reduced by 11%. The maxDeltaT parameter prevents deltaT from growing too large during quiet flow periods. Use writeControl adjustableRunTime to ensure outputs occur at regular physical time intervals despite varying deltaT.
The acceptable Courant number depends on the solver and time integration scheme:
maxAlphaCoWhen using pimpleFoam with multiple outer correctors, configure the PIMPLE block in fvSolution:
PIMPLE
{
nOuterCorrectors 3; // allows Co up to ~5-10
nCorrectors 2; // inner pressure correctors
nNonOrthogonalCorrectors 1;
turbOnFinalIterationOnly yes; // efficiency: update turbulence last
}
Each outer corrector performs a full PISO loop. Three outer correctors allow larger deltaT but increase computational cost per time step — the trade-off is worthwhile when the required physical simulation time is long relative to the Courant-limited deltaT.
simpleFoam and other steady-state solvers do not use time stepping in the physical sense — they use pseudo-time iterations. The Courant number displayed in the log for these solvers is a pseudo-Co and does not directly control stability. For steady-state simulations, the Courant number is not the root cause of divergence — look at relaxation factors and discretisation schemes instead.
A very high pseudo-Co (e.g. 5000) in a simpleFoam log is often a symptom of divergence, not its cause.
For VOF simulations with interFoam, there are two Courant numbers to watch: the standard Co and the interface Co (maxAlphaCo). The interface requires a tighter limit to prevent smearing:
adjustTimeStep yes;
maxCo 1.0;
maxAlphaCo 0.5; // interface Courant limit
maxDeltaT 1e-3;
In VOF methods, the interface is represented by the gradient of the alpha field. The MULES (Multidimensional Limiter for Explicit Solutions) algorithm used by interFoam to advect alpha has its own stability constraint, independent of the velocity field stability. For sharp interfaces, maxAlphaCo 0.5 is required to prevent the interface from smearing over multiple cells within a single time step. When interFoam output shows Interface Courant Number mean: X max: Y, the alpha-Co constrained by maxAlphaCo overrides the bulk Co constraint when it is the binding limit.
When the simulation is approaching instability due to high Co, the log shows a characteristic pattern before the crash:
Time = 0.0018
Courant Number mean: 0.543 max: 0.872
...
Time = 0.0019
Courant Number mean: 1.23 max: 3.45
...
Time = 0.0019
Courant Number mean: 45.2 max: 187.3
Floating point exception (core dumped)
The jump from Co=0.87 to Co=3.45 in one step indicates a sudden velocity spike in one or a few cells — the beginning of the CFL instability cascade. Within a few more steps, NaN propagates through the domain. The fix is to either reduce deltaT so the initial spike never happens, or use adjustable time stepping so the solver automatically reduces deltaT when Co climbs toward the limit.
For compressible flows with rhoCentralFoam, the CFL condition must be satisfied for both convective and acoustic waves. The acoustic Courant number is based on the speed of sound rather than the flow velocity:
// Acoustic Co = (U + c) * deltaT / deltaX
// c = speed of sound = sqrt(gamma * R * T)
// For air at 300K: c = sqrt(1.4 * 287 * 300) = 347 m/s
//
// Example: U=50 m/s, c=347 m/s, deltaX=0.01m, deltaT=1e-5s
// Acoustic Co = (50 + 347) * 1e-5 / 0.01 = 0.397 — OK
In supersonic flows (Mach > 1), the acoustic Courant number requirement dominates and forces very small deltaT, making compressible simulations significantly more expensive than incompressible ones at similar Reynolds numbers.
Upload your case and CFDpilot recommends optimal Courant number limits and timestep based on your solver, mesh, and flow velocity.
Optimise my deltaT →With pimpleFoam using 1 outer corrector (nOuterCorrectors 1), Co < 1 is required — it behaves identically to pisoFoam. With 2–3 outer correctors, Co up to 5–10 is typically stable because the implicit pressure-velocity coupling handles the larger time step. In practice, Co < 5 with 3 outer correctors is a reliable operating point for most incompressible turbulent flows. Above 10, temporal accuracy suffers significantly even if stability is maintained.
Co = U*deltaT/deltaX. To reduce Co without reducing deltaT, you must increase the minimum cell size — which means coarsening the mesh in regions where small cells coincide with high velocity. This is often impractical. The correct solution is to use adjustTimeStep yes; maxCo 0.8; in controlDict and let OpenFOAM manage deltaT automatically. This is the recommended approach for all transient simulations.
In interFoam (VOF multiphase), Co is the convective Courant number for the velocity field — controlling velocity field stability. maxAlphaCo is the interface Courant number, controlling how fast the volume fraction (alpha) advects across the interface. The MULES algorithm for alpha advection has a stricter CFL constraint than the momentum equation. Set both independently: maxCo 1.0 for bulk flow stability and maxAlphaCo 0.5 for interface sharpness.
A high initial Courant number is common when deltaT was set before the mesh was refined, or when the initial velocity field is higher than anticipated. The fix is straightforward: add adjustTimeStep yes; maxCo 0.8; to controlDict. OpenFOAM will immediately reduce deltaT in the first step to meet the Co limit. Alternatively, manually estimate deltaT = Co_target * dx_min / U_max using the minimum cell size from checkMesh.
No. simpleFoam uses pseudo-time iterations without physical time stepping. The Courant number printed in the log is a pseudo-Co computed from the iteration increment and has no direct stability meaning. A high pseudo-Co (e.g. 5000) is a symptom that the solver is diverging — not the cause. For steady-state simulations, ignore the Courant number and focus on relaxation factors and div scheme boundedness instead.
At each time step, pimpleFoam computes the current maximum Courant number Co_max. It scales the next deltaT by maxCo / Co_max: if Co_max is half of maxCo, deltaT doubles; if Co_max exceeds maxCo, deltaT is reduced proportionally. The maxDeltaT parameter caps the maximum deltaT to prevent excessive time steps during quiet flow periods. Use writeControl adjustableRunTime to ensure outputs occur at regular physical time intervals despite the varying deltaT.