Wall functions are boundary conditions for turbulence quantities (k, epsilon, omega, nut) that model the near-wall region without resolving it directly. Choosing the right wall treatment — and the right y+ — is one of the most impactful decisions in any RANS simulation.
There are two approaches to modelling the boundary layer in RANS:
The critical constraint: do not mix them. If you use wall functions, your first cell must be at y+ 30–300. If you use low-Re treatment, you need y+ ≈ 1. A mesh with y+ = 5 is in the buffer layer — both approaches fail there.
The non-dimensional wall distance y+ is defined as:
y+ = y * u_tau / nu
where:
y = distance from wall to first cell centroid [m]
u_tau = friction velocity = sqrt(tau_w / rho) [m/s]
nu = kinematic viscosity [m²/s]
A practical estimate for the friction velocity in turbulent boundary layers is u_tau ≈ 0.05 * U_ref. For a more precise estimate, use the Blasius correlation for flat-plate flows or the Moody chart for pipe flow. The required first-cell height is then:
# Target y+ = 50, U_ref = 10 m/s, air (nu = 1.5e-5 m²/s)
u_tau ≈ 0.05 * 10 = 0.5 m/s
y = y+ * nu / u_tau = 50 * 1.5e-5 / 0.5 = 1.5e-3 m
# Target y+ = 1 (low-Re, resolving viscous sublayer)
y = 1 * 1.5e-5 / 0.5 = 3.0e-5 m (30 microns)
This calculation gives a starting point. Always verify by running the simulation and checking actual y+ values using the yPlus function object.
Add this to your controlDict functions block to compute y+ at runtime:
functions
{
yPlus
{
type yPlus;
libs (fieldFunctionObjects);
writeControl writeTime;
}
}
After running, open postProcessing/yPlus/ and check the min/max values. Target: y+ max < 300, y+ min > 30 for wall functions.
You can also post-process y+ directly after a completed steady-state run:
# Post-process y+ from the final time step
simpleFoam -postProcess -func yPlus
The resulting yPlus field can be visualised in ParaView — look for patches where y+ falls below 30 or above 300 and adjust your mesh grading accordingly.
Standard configuration for wall patches in 0/k, 0/epsilon, 0/nut:
// 0/k
wall
{
type kqRWallFunction;
value uniform 0;
}
// 0/epsilon
wall
{
type epsilonWallFunction;
value uniform 0;
}
// 0/nut
wall
{
type nutkWallFunction;
value uniform 0;
}
The kqRWallFunction type applies a Neumann (zero-gradient) condition on k, leaving k free to be determined by the turbulence model in the near-wall cell. The epsilonWallFunction imposes the production-equals-dissipation equilibrium assumption from the log-law, computing epsilon from the local k and cell height.
k-ω SST has a built-in blending between log-law and viscous sublayer. It handles both y+ ≈ 1 and y+ 30–300, but the recommended practice is to target one or the other consistently:
// 0/k — same for both y+ regimes
wall
{
type kqRWallFunction;
value uniform 0;
}
// 0/omega
wall
{
type omegaWallFunction;
value uniform 0;
}
// 0/nut — for high-Re (y+ 30-300)
wall
{
type nutkWallFunction;
value uniform 0;
}
// 0/nut — for low-Re (y+ ~1)
wall
{
type nutLowReWallFunction;
value uniform 0;
}
The omegaWallFunction in OpenFOAM uses Menter's blending: it computes omega from both the viscous sublayer formula and the log-law, then takes the maximum. This makes it robust across y+ regimes, but does not eliminate the accuracy penalty of sitting in the buffer layer.
SA solves a single transport equation for modified eddy viscosity nuTilda. At walls:
// 0/nuTilda
wall
{
type fixedValue;
value uniform 0;
}
// 0/nut
wall
{
type fixedValue;
value uniform 0;
}
SA is designed for low-Re wall treatment (y+ ≈ 1). Using it with y+ 30–300 degrades accuracy significantly.
When running buoyantSimpleFoam or conjugate heat transfer cases, temperature also requires a wall function. The standard choice is alphatJayatillekeWallFunction for turbulent thermal diffusivity:
// 0/alphat — turbulent thermal diffusivity
wall
{
type compressible::alphatJayatillekeWallFunction;
Prt 0.85; // turbulent Prandtl number
value uniform 0;
}
// 0/T — temperature at wall (isothermal)
heatedWall
{
type fixedValue;
value uniform 350; // 350 K
}
// 0/T — adiabatic wall (zero heat flux)
adiabaticWall
{
type zeroGradient;
}
The Jayatilleke function models the thermal sub-layer using the universal temperature profile, analogous to how velocity wall functions model the velocity sub-layer. The turbulent Prandtl number Prt is typically 0.85 for air and most gases.
For surfaces with significant roughness (sand-grain roughness height Ks), OpenFOAM provides roughness-modified wall functions. These shift the log-law downward based on the roughness Reynolds number:
// 0/nut — rough wall
roughWall
{
type nutkRoughWallFunction;
Ks uniform 5e-4; // sand-grain roughness height [m]
Cs uniform 0.5; // roughness constant (0.5 for sand-grain)
value uniform 0;
}
The roughness Reynolds number Ks+ = Ks * u_tau / nu determines the roughness regime: hydraulically smooth for Ks+ < 5, fully rough for Ks+ > 70. Ensure y+ > Ks+ to avoid the roughness elements extending beyond the first cell.
Recent OpenFOAM versions introduced automatically-blended wall functions that reduce sensitivity to y+ placement. The nutBlendedWallFunction blends between viscous and log-law formulations continuously:
// 0/nut — blended, less sensitive to y+ in 5-30 range
wall
{
type nutBlendedWallFunction;
value uniform 0;
}
While these reduce the sensitivity to buffer-layer y+ values, they do not fully replace the need for a properly designed mesh. The blended functions are particularly useful during early-stage simulations where the exact y+ distribution is not yet known.
fixedValue 0 for k at a wall with wall functions — this overrides the wall function and sets k=0, which causes the solver to compute nut=0 and essentially ignore turbulence near the wall.nutkWallFunction requires y+ > 30. For y+ ≈ 1, use nutLowReWallFunction.0/nut, OpenFOAM uses a zero-gradient default, which is wrong.omegaWallFunction, not epsilonWallFunction.Upload your case and CFDpilot checks your y+ range and recommends the correct wall function for each turbulence model.
Check my wall treatment →For standard wall functions (nutkWallFunction, epsilonWallFunction), target y+ between 30 and 300. The first cell centroid must sit in the log-law region. Values below 30 fall into the buffer layer where wall functions are inaccurate. Values above 300 push beyond the range where the log-law holds for most turbulent flows.
nutkWallFunction computes turbulent viscosity from the log-law and is designed for meshes with y+ between 30 and 300. nutLowReWallFunction is for fully resolved boundary layers with y+ near 1, where the viscous sublayer is explicitly captured by the mesh. Using nutkWallFunction on a y+ = 1 mesh gives incorrect nut values at the wall.
Yes — k-omega SST blends between the viscous sublayer and log-law formulations. However, target one regime consistently. The buffer layer (y+ 5 to 30) should be avoided regardless of the turbulence model. The omegaWallFunction in OpenFOAM uses Menter's blending to handle intermediate y+ values, but accuracy is still degraded in the buffer layer.
y+ is a local quantity that depends on local wall shear stress, which varies across the geometry. A uniform first-cell height will produce non-uniform y+. Near stagnation points, y+ will be very low; near high-shear regions (e.g., throat of a nozzle), y+ will be higher. Check y+ distribution in ParaView and identify whether the outlier regions are critical for your quantities of interest.
Use nutkRoughWallFunction with the Ks (sand-grain roughness height) and Cs (roughness constant, typically 0.5) parameters. Ensure the first-cell y+ is greater than the roughness Reynolds number Ks+ = Ks × u_tau / nu to avoid the roughness extending beyond the first cell height.
No. The velocity boundary condition at a wall is always noSlip (or fixedValue with zero velocity). Wall functions apply only to turbulence quantities: k, epsilon, omega, and nut. The velocity gradient at the wall is handled implicitly through the turbulent viscosity computed by the wall function.