Residuals are the primary signal of whether an OpenFOAM simulation is converging, stalling, or diverging. Understanding what they represent — and how to interpret their behaviour — is essential for diagnosing any simulation problem.
A residual measures how well the discretised equation is satisfied at the current iteration. For a linear system Ax = b, the residual is |b - Ax| normalised by a reference value. A residual of 1e-3 means the equation is satisfied to 0.1% — not to be confused with a 0.1% error in the result.
In the log, each iteration prints the initial and final residual for each solved field:
smoothSolver: Solving for Ux, Initial residual = 0.0234, Final residual = 1.2e-06, No Iterations 3
smoothSolver: Solving for Uy, Initial residual = 0.0187, Final residual = 9.4e-07, No Iterations 3
GAMG: Solving for p, Initial residual = 0.152, Final residual = 0.00741, No Iterations 4
The initial residual is what matters for assessing convergence — it measures the residual at the start of the iteration, before the inner solver runs.
Convergence tolerances are set in fvSolution:
solvers
{
p
{
solver GAMG;
tolerance 1e-06; // absolute convergence threshold
relTol 0.1; // relative: stop when residual drops by 10x
smoother GaussSeidel;
}
U
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-07;
relTol 0.1;
}
}
SIMPLE
{
residualControl
{
U 1e-04; // stop outer iterations when U residual < 1e-4
p 1e-04;
k 1e-04;
epsilon 1e-04;
}
}
residualControl controls when the outer SIMPLE loop stops. The inner solver tolerances (tolerance, relTol) control how tightly each linear system is solved per iteration.
Under-relaxation in SIMPLE damps updates to prevent oscillations. The factors are set in the relaxationFactors block of fvSolution:
relaxationFactors
{
fields
{
p 0.3; // pressure: 0.2-0.4 is standard
}
equations
{
U 0.7; // velocity: 0.5-0.8 typical
k 0.5;
epsilon 0.5;
omega 0.5;
}
}
Lower relaxation factors slow convergence but increase stability. If residuals spike or diverge, halving both U and p factors is the first corrective action. Never exceed 0.9 for U or 0.5 for p in a standard RANS case.
On meshes with non-orthogonality above 40–50°, the pressure equation requires non-orthogonal corrections. Without these, the pressure residual plateaus at an elevated level:
SIMPLE
{
nNonOrthogonalCorrectors 2; // 1-3 for unstructured meshes
}
Each corrector adds a full pressure solve. For max non-orthogonality below 70°, 1–2 correctors suffice. Above 70°, prioritise mesh improvement over increasing correctors.
In transient cases, the outer PIMPLE loop runs multiple predictor-corrector cycles per time step. Convergence within each time step is controlled by:
PIMPLE
{
nOuterCorrectors 3;
nCorrectors 2;
nNonOrthogonalCorrectors 1;
outerCorrectorResidualControl
{
U { tolerance 1e-05; relTol 0; }
p { tolerance 5e-04; relTol 0; }
}
}
In transient runs, the outer PIMPLE loop should converge in 2–3 iterations per time step. If it always runs the maximum correctors, reduce the time step (lower CFL) or increase outer correctors.
Residuals alone are insufficient to declare convergence — forces or pressure drops can still oscillate even when residuals are low. Always monitor engineering quantities:
functions
{
forces
{
type forces;
libs (forces);
patches (bodyWall);
rho rhoInf;
rhoInf 1.225;
CofR (0 0 0);
writeControl timeStep;
writeInterval 1;
}
}
If forces oscillate while residuals are low, the flow is likely inherently unsteady (vortex shedding, recirculation). Switch to a transient solver and time-average the results.
For a steady-state simulation with simpleFoam:
Residuals stuck above 1e-2 and not decreasing:
Gauss linear) — switch to linearUpwindcheckMeshResiduals that decrease initially then spike back up:
pressureInletOutletVelocity on outlet)p residual much higher than U residual:
relTol or increase GAMG agglomeration levelsnNonOrthogonalCorrectorsUse foamMonitor (built-in) or extract with a simple grep:
# Extract initial residuals for Ux from log
grep "Solving for Ux" log.simpleFoam | awk '{print $9}' | tr -d ','
# Extract all fields into logs/ directory for gnuplot
foamLog log.simpleFoam
# Live monitoring during a running simulation
foamMonitor -l postProcessing/residuals/0/residuals.dat
CFDpilot generates residual plots automatically from your uploaded log file.
Upload your solver log and CFDpilot identifies stagnating residuals, oscillations, and the convergence blockers behind them.
Diagnose my residuals →For most engineering RANS simulations with simpleFoam, residuals reaching 1e-4 for U, p, k, and epsilon are sufficient. For aerodynamic force coefficients, heat transfer, or highly sensitive outputs, target 1e-5 or lower. Always verify by checking that your engineering quantities of interest have stabilised, not just that residuals are numerically low.
The initial residual is measured before the inner linear solver runs — this is the outer iteration residual and is the primary convergence indicator. The final residual is after the inner solver completes. Track the initial residual for convergence assessment. A large gap between initial and final residuals means the inner solver is working hard each iteration.
The most common causes: under-relaxation factors too high (reduce alphaU to 0.5 and alphaP to 0.2), unbounded divergence scheme (switch div(phi,U) to Gauss linearUpwind), high mesh non-orthogonality requiring more nNonOrthogonalCorrectors, or physically incorrect boundary conditions that prevent a steady solution from existing.
Low residuals do not guarantee a steady solution — the flow may be inherently unsteady (vortex shedding, separation). If engineering quantities oscillate while residuals are low, switch to pimpleFoam and time-average the results. A steady-state solver trying to converge an unsteady flow will often produce low residuals with physically meaningless results.
Add the residuals function object to controlDict, then use foamMonitor -l postProcessing/residuals/0/residuals.dat in a separate terminal for live plotting. Alternatively, use foamLog after the run to extract individual field residuals into the logs/ directory for plotting with gnuplot or Python matplotlib.
No. Turbulence quantities (k, epsilon, omega) converge more slowly than momentum and pressure. Requiring the same tight tolerance for turbulence as for U and p extends run time without improving the flow solution. Standard residualControl targets: U=1e-4, p=1e-4, k=1e-4, epsilon=1e-4. Inner solver tolerances should be about 10x tighter than residualControl targets.