The 0/ folder is where most OpenFOAM beginners make silent mistakes. A missing patch, wrong dimensions, or zero turbulence fields will not always produce an immediate error — they produce a simulation that runs but gives wrong answers. This guide covers the structure of initial condition files, the most common errors, and how to initialise the flow field correctly.
Each field file in 0/ must contain three mandatory sections: dimensions, internalField, and boundaryField. A minimal velocity field looks like this:
// 0/U
dimensions [0 1 -1 0 0 0 0];
internalField uniform (0 0 0);
boundaryField
{
inlet
{
type fixedValue;
value uniform (10 0 0);
}
outlet
{
type zeroGradient;
}
walls
{
type noSlip;
}
}
The internalField is the starting value everywhere in the domain at t=0. For steady-state solvers, a reasonable initialisation reduces the number of iterations needed to converge.
The OpenFOAM field file header also includes a FoamFile block that identifies the version, format, class, and object name. Although older tutorials show this block, it is optional in modern OpenFOAM versions (v6+). The class must match the field type: volVectorField for U, volScalarField for p, k, epsilon, omega, T, and nut.
// Full header example for 0/p
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object p;
}
The pressure field p has different dimensions depending on the solver. Getting this wrong causes cryptic errors or incorrect force calculations.
p is kinematic pressure, divided by density. Units are m²/s².p is thermodynamic pressure in Pa. Units are kg/(m·s²).// Incompressible p (kinematic)
dimensions [0 2 -2 0 0 0 0];
internalField uniform 0;
// Compressible p (thermodynamic, Pa)
dimensions [1 -1 -2 0 0 0 0];
internalField uniform 101325;
For compressible cases, always initialise p to a physically meaningful value (e.g. 101325 Pa for atmospheric pressure). An initial pressure of 0 Pa will cause negative temperatures during the first iteration.
The dimension vector format is [mass length time temperature mol current luminosity] in SI base units. Velocity [0 1 -1 0 0 0 0] means m/s. Kinematic viscosity [0 2 -1 0 0 0 0] means m²/s. Knowing this system allows you to verify dimensions of any field before running.
Every patch defined in constant/polyMesh/boundary must appear in every field file's boundaryField. If a patch is absent, OpenFOAM either throws a fatal error or silently applies a default, depending on the version.
Check your boundary file:
// Run this to list all patches
checkMesh -allGeometry | grep -A2 "Boundary definition"
For patches you do not want to specify explicitly, use defaultFaces or add the patch with type calculated or type zeroGradient as appropriate. Empty patches (2D wedge, front/back) should use:
frontAndBack
{
type empty;
}
For cyclic (periodic) boundary conditions, the patch must be declared with type cyclic in the mesh boundary file and the paired patch name must be set with neighbourPatch. Both patches must have the same number of faces and be geometrically matched.
// 0/U — cyclic patch pair
periodicLeft
{
type cyclic;
}
periodicRight
{
type cyclic;
}
The internalField can be either uniform (one value for all cells) or nonuniform (a value per cell, stored as a list). When you re-use results from a previous run or use setFields, OpenFOAM writes nonuniform fields. Manually editing these is error-prone — always use the utility tools instead.
A nonuniform field looks like:
internalField nonuniform List<scalar>
4
(
0
0
1.5
1.5
)
;
When OpenFOAM restarts from a time directory (e.g. 500/), it reads the nonuniform field data for each cell. If the cell count changes (e.g. after mesh refinement), the nonuniform field is incompatible and OpenFOAM will error. In this case, reset to a uniform internalField or use mapFields to interpolate from the old mesh.
# Map fields from a coarser mesh to a refined mesh
mapFields ../coarseCase -sourceTime latestTime
Setting k, epsilon, or omega to zero at the inlet or as internalField causes division-by-zero in turbulent viscosity calculations and immediate divergence. Use physically realistic estimates based on turbulence intensity I and a reference length scale L:
// Turbulent kinetic energy: k = 1.5 * (U_ref * I)^2
// For U_ref=10 m/s, I=5%: k ≈ 0.375 m²/s²
// 0/k
dimensions [0 2 -2 0 0 0 0];
internalField uniform 0.375;
boundaryField
{
inlet
{
type turbulentIntensityKineticEnergyInlet;
intensity 0.05;
value uniform 0.375;
}
outlet { type zeroGradient; }
walls { type kqRWallFunction; value uniform 0.375; }
}
// epsilon = C_mu^0.75 * k^1.5 / L, C_mu=0.09, L=0.1 m → epsilon ≈ 14.9
// 0/epsilon
dimensions [0 2 -3 0 0 0 0];
internalField uniform 14.9;
boundaryField
{
inlet
{
type turbulentMixingLengthDissipationRateInlet;
mixingLength 0.1;
value uniform 14.9;
}
outlet { type zeroGradient; }
walls { type epsilonWallFunction; value uniform 14.9; }
}
For the k-omega SST model, the specific dissipation rate omega is related to epsilon by omega = epsilon / (Cmu * k). Using the same example (k=0.375, epsilon=14.9, Cmu=0.09): omega ≈ 44.1 s⁻¹. Set the wall boundary condition for omega to omegaWallFunction instead of epsilonWallFunction.
// 0/omega for k-omega SST
dimensions [0 0 -1 0 0 0 0];
internalField uniform 44.1;
boundaryField
{
inlet
{
type turbulentMixingLengthFrequencyInlet;
mixingLength 0.1;
value uniform 44.1;
}
outlet { type zeroGradient; }
walls { type omegaWallFunction; value uniform 44.1; }
}
The turbulent viscosity field nut (and nuTilda for Spalart-Allmaras) is calculated by the solver at each time step. However, it must still be present in 0/. Set its internalField to uniform 0 and let the wall boundary condition be nutkWallFunction for wall-bounded flows or calculated at far-field boundaries.
For complex geometries, starting simpleFoam from a uniform zero velocity field can cause early divergence. potentialFoam solves the potential flow equations (irrotational, inviscid) to generate a physically consistent initial U field that already satisfies continuity.
# Run potentialFoam before simpleFoam
potentialFoam -writep
simpleFoam
In the fvSolution used by potentialFoam, add a solver for Phi:
solvers
{
Phi
{
solver GAMG;
smoother GaussSeidel;
tolerance 1e-6;
relTol 0.01;
}
}
potentialFoam overwrites 0/U with the irrotational velocity solution. The -writep flag also writes a pressure field, but this is the potential pressure (not kinematic pressure) and should not be used directly as the starting p for simpleFoam. Delete the potentialFoam p field and use the original uniform 0/p for the main solver run.
In OpenFOAM v8 and later, potentialFoam has been superseded by the initialiseFields application in some tutorials, and the potentialFlowInitialiser option can be set inside the main solver's fvSolution. Check your OpenFOAM version's tutorial for the current recommended approach.
setFields allows setting different field values in geometric regions. It is essential for multiphase cases (e.g. setting alpha.water = 1 in a box) and for flow cases where part of the domain should start with a different velocity.
// system/setFieldsDict
defaultFieldValues
(
volScalarFieldValue alpha.water 0
);
regions
(
boxToCell
{
box (0 0 0) (2 1 0.1);
fieldValues
(
volScalarFieldValue alpha.water 1
);
}
);
Run setFields after blockMesh or snappyHexMesh and before the main solver. The output overwrites the 0/ field files with a nonuniform internal field.
Beyond boxToCell, setFields supports several other region types:
// setFieldsDict using sphereToCell
regions
(
sphereToCell
{
centre (0.5 0.5 0.5);
radius 0.2;
fieldValues
(
volScalarFieldValue T 500
);
}
);
OpenFOAM restarts automatically from the latest time directory present in the case folder. The startFrom and startTime settings in system/controlDict control this behaviour:
// system/controlDict — restart options
startFrom latestTime; // restart from highest time directory
// or
startFrom startTime; // use startTime value below
startTime 0; // start from 0/ directory
When restarting, all fields in the restart time directory must be consistent with the current mesh. If you modified the mesh after the previous run, you must re-run decomposePar (for parallel cases) and verify that field dimensions have not changed.
For steady-state solvers that have nearly converged, restart from the latest iteration using startFrom latestTime and tighten the relTol to 0 in fvSolution to push residuals to their absolute tolerance.
Upload your case and CFDpilot flags missing fields, wrong dimensions, and incompatible boundary condition types.
Check my 0/ folder →internalField sets the initial value for all interior cells at t=0. boundaryField defines the boundary condition type and value for each named patch on the mesh boundary. Both are mandatory in every field file inside the 0/ directory.
Incompressible solvers (simpleFoam, pimpleFoam) divide pressure by density, giving kinematic pressure in m²/s² with dimensions [0 2 -2 0 0 0 0]. Compressible solvers (rhoPimpleFoam) use absolute thermodynamic pressure in Pascals: [1 -1 -2 0 0 0 0]. Mixing these up produces incorrect density and force results without an obvious error message.
Setting k or epsilon to zero causes division-by-zero when computing turbulent viscosity (nut = Cmu * k² / epsilon). The solver either crashes immediately or produces nut values of NaN or infinity, which propagates to U and p within the first few iterations. Use the turbulence intensity formula: k = 1.5 * (U_ref × I)² where I is typically 0.01 to 0.10.
Use potentialFoam on geometrically complex cases (external aerodynamics, internal flow with sharp turns) where starting from uniform U = 0 causes the solver to diverge in the first 50–100 iterations. potentialFoam provides a divergence-free velocity field consistent with the geometry, giving simpleFoam or rhoSimpleFoam a much better starting point at the cost of one additional pre-run step.
setFields is an OpenFOAM pre-processing utility that sets different field values inside geometric regions (box, sphere, cylinder, STL surface). It is required for multiphase simulations (interFoam, multiphaseInterFoam) to initialise the phase fraction field alpha, and for thermal cases where different parts of the domain start at different temperatures. Run it after blockMesh or snappyHexMesh and before the main solver.
List all mesh patches with checkMesh or by reading constant/polyMesh/boundary. Every patch name that appears there must appear in the boundaryField of every field file in 0/. Add the missing patch with an appropriate type: zeroGradient for outlet-like patches, empty for 2D front/back faces, and calculated for derived fields like nut.