The fvSchemes dictionary controls how OpenFOAM discretises differential operators in time and space. The wrong scheme choice is one of the leading causes of divergence and inaccurate results. This guide covers the most important choices for each operator type.
ddtSchemes { ... } // time derivative
gradSchemes { ... } // gradient (grad)
divSchemes { ... } // divergence (div) — convective terms
laplacianSchemes { ... } // Laplacian (diffusion)
interpolationSchemes { ... }
snGradSchemes { ... } // surface-normal gradient
ddtSchemes
{
default steadyState; // steady-state: simpleFoam, rhoSimpleFoam
// or:
default Euler; // 1st-order implicit, unconditionally stable
default backward; // 2nd-order implicit, more accurate
default CrankNicolson 0.9; // blended CN (0=Euler, 1=pure CN)
}
For most transient cases: start with Euler for stability, switch to backward or CrankNicolson 0.9 once the simulation is running cleanly.
The convection scheme for momentum (div(phi,U)) has the largest impact on both stability and accuracy:
divSchemes
{
default none;
// Most stable — 1st order, bounded, always safe to start with:
div(phi,U) Gauss upwind;
// Best for production RANS — 2nd order, bounded:
div(phi,U) Gauss linearUpwind grad(U);
// High accuracy for LES — unbounded, only for well-resolved meshes:
div(phi,U) Gauss linear;
// Turbulence scalars — upwind is sufficient and safe:
div(phi,k) Gauss upwind;
div(phi,epsilon) Gauss upwind;
div(phi,omega) Gauss upwind;
}
Never use Gauss linear for RANS — it is unbounded and will diverge on realistic meshes. Reserve it for LES with fine, structured meshes.
gradSchemes
{
default Gauss linear; // standard, 2nd order
// For high non-orthogonality, limit the gradient:
grad(U) cellLimited Gauss linear 1;
grad(p) cellLimited Gauss linear 1;
}
cellLimited prevents gradient overshoots in distorted cells — essential for meshes with non-orthogonality above 60°.
laplacianSchemes
{
default Gauss linear corrected; // best for orthogonal meshes
// For non-orthogonal meshes:
default Gauss linear limited corrected 0.5;
// For highly non-orthogonal meshes (>70°):
default Gauss linear uncorrected;
}
The interpolation (linear) and non-orthogonal correction (corrected, limited, uncorrected) are separate. On poor meshes, corrected can amplify errors — use limited 0.333 as a safe middle ground.
ddtSchemes { default steadyState; }
gradSchemes
{
default Gauss linear;
grad(U) cellLimited Gauss linear 1;
}
divSchemes
{
default none;
div(phi,U) Gauss linearUpwind grad(U);
div(phi,k) Gauss upwind;
div(phi,epsilon) Gauss upwind;
div(phi,omega) Gauss upwind;
div((nuEff*dev2(T(grad(U))))) Gauss linear;
}
laplacianSchemes { default Gauss linear limited corrected 0.5; }
interpolationSchemes { default linear; }
snGradSchemes { default limited corrected 0.5; }
ddtSchemes { default backward; } // 2nd-order implicit
gradSchemes
{
default Gauss linear;
grad(U) cellLimited Gauss linear 1;
}
divSchemes
{
default none;
div(phi,U) Gauss linearUpwind grad(U);
div(phi,k) Gauss upwind;
div(phi,epsilon) Gauss upwind;
div(phi,omega) Gauss upwind;
div((nuEff*dev2(T(grad(U))))) Gauss linear;
}
laplacianSchemes { default Gauss linear corrected; }
interpolationSchemes { default linear; }
snGradSchemes { default corrected; }
Transient RANS with backward gives proper second-order time accuracy. If the simulation is unstable, temporarily revert to Euler for the first few time steps then restart with backward.
ddtSchemes { default backward; }
gradSchemes { default Gauss linear; }
divSchemes
{
default none;
div(phi,U) Gauss linear; // central differencing — LES only
div(phi,k) Gauss linear;
div(phi,B) Gauss linear;
div(B) Gauss linear;
div((nuEff*dev(T(grad(U))))) Gauss linear;
}
laplacianSchemes { default Gauss linear corrected; }
interpolationSchemes { default linear; }
snGradSchemes { default corrected; }
LES requires central differencing (Gauss linear) for momentum to avoid numerical diffusion that would dampen resolved turbulent structures. This is only valid on meshes where the LES resolution length scale is properly resolved — typically max non-orthogonality below 40°.
These two sections are often set to defaults and ignored, but they matter for accuracy:
// interpolationSchemes — face interpolation of cell-centred values
interpolationSchemes
{
default linear; // central interpolation, 2nd order
}
// snGradSchemes — surface-normal gradient at faces
snGradSchemes
{
default limited corrected 0.5; // must match laplacianSchemes correction
}
The snGradSchemes correction must be consistent with the correction in laplacianSchemes. If you use limited corrected 0.5 in laplacianSchemes, use the same in snGradSchemes. Mismatches cause subtle residual errors that are difficult to diagnose.
The appropriate scheme choice depends on mesh quality metrics from checkMesh:
corrected for laplacian and snGrad; Gauss linear for gradients is fine.limited corrected 0.333 for laplacian; use cellLimited for grad(U).uncorrected for laplacian; cellLimited Gauss linear 1 for all gradients; increase nNonOrthogonalCorrectors to 2–3.div(phi,U) to Gauss upwind regardless of the target accuracy.Upload your case and CFDpilot checks your divergence, gradient, and Laplacian schemes against your solver and flow regime.
Review my schemes →Gauss upwind is first-order accurate, highly diffusive, but unconditionally bounded and stable. Gauss linearUpwind is second-order accurate, less diffusive, but requires a gradient argument and can produce small overshoots. For production RANS, linearUpwind gives better accuracy. For initial convergence or difficult meshes, start with upwind and switch once the solution is established.
No. Gauss linear (central differencing) is unbounded and will diverge on realistic unstructured meshes when the mesh Peclet number is greater than 2. It is only appropriate for LES on well-resolved near-orthogonal meshes. For RANS, always use Gauss linearUpwind or Gauss upwind for div(phi,U).
cellLimited applies a slope limiter to prevent gradient overshoots in distorted or non-orthogonal cells. The coefficient (0 to 1) controls how aggressively the gradient is limited. Use cellLimited Gauss linear 1 for grad(U) whenever your mesh has non-orthogonality above 60 degrees or checkMesh reports a high maximum non-orthogonality value.
The corrected keyword applies a non-orthogonality correction to the diffusion term at cell faces. The coefficient (0 to 1) limits how much correction is applied — 0 means no correction, 1 means full correction. A value of 0.333 is a safe compromise for meshes with moderate non-orthogonality (40–70 degrees), preventing correction amplification on distorted cells.
Start with Euler (first-order implicit) for stability during initial flow development, then switch to backward (second-order implicit) or CrankNicolson 0.9 for production runs. CrankNicolson 0.9 blends 10% Euler and 90% Crank-Nicolson to reduce the oscillatory behaviour of pure second-order CN on coarser time steps while retaining near-second-order accuracy.
linearUpwind requires a valid gradient field. If div(phi,U) uses Gauss linearUpwind grad(U) but gradSchemes does not define grad(U) or uses a conflicting scheme, OpenFOAM can produce NaN values. Ensure gradSchemes includes a grad(U) entry (e.g., cellLimited Gauss linear 1). Also verify that your mesh non-orthogonality is below 70 degrees — very distorted meshes cannot support linearUpwind.