grokkingstuff Home Blog Projects Wiki Calculators About

OpenFOAM Mesh Generation — blockMesh and snappyHexMesh

#+CATEGORY: openfoam # :PROPERTIES: # :ID: uuid-openfoam-mesh-generation # :END:

OpenFOAM Mesh Generation :: blockMesh and snappyHexMesh Reference

This note documents OpenFOAM's native mesh generation tools: blockMesh (structured hexahedral blocks) and snappyHexMesh (unstructured hex/tet/poly hybrid mesh from STL geometry). It maps to Mesh Quality for quality metrics and Cell Types for structural considerations.

OpenFOAM mesh generation philosophy: blockMesh is for simple geometries where structured meshing is possible and desirable (rectangular domains, ducts, channels). snappyHexMesh is for complex geometries where an automated mesh generator is needed (external aerodynamics, internal flows with complex parts). The trade-off is that blockMesh produces higher-quality meshes, but snappyHexMesh handles arbitrary CAD.

**Table of Contents**

blockMesh :: Structured Hexahedral Meshing

blockMesh is OpenFOAM's native structured mesh generator. It creates hexahedral meshes from user-defined blocks (O-grids, multi-block decompositions). It is the most basic and most powerful mesh generator in OpenFOAM: every face is controlled, every cell is known, and every mesh quantity can be verified analytically.

The mesh is defined in system/blockMeshDict:

FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    object      blockMeshDict;
}

// Boundary definition
boundary
{
    inlet
    {
        type    patch;
        faces
        (
            (0 0 0) (0 0 1) (0 1 1) (0 1 0)
        );
    }
    outlet
    {
        type    patch;
        faces
        (
            (1 0 0) (1 1 0) (1 1 1) (1 0 1)
        );
    }
    walls
    {
        type    wall;
        faces
        (
            (0 0 0) (0 1 0) (1 1 0) (1 0 0)
            (0 0 1) (1 0 1) (1 1 1) (0 1 1)
        );
    }
}

// Blocks (single block shown)
blocks
(
    hex (0 1 2 3 4 5 6 7) (100 50 50) simpleGrading (1 1 1)
);

// Edge definitions (for O-grid or curved boundaries)
edges
(
);

// Merge regions (for STL surfaces, if merging with snappyHexMesh)
mergeRegions
{
    name    mergeStl;
    patches (inner outer);
}
ParameterDescriptionTypical value
---------------------------------------
verticesMesh node coordinates (XYZ)Defined per block corner
nCellsCell count in each block direction100×50×50 (example)
simpleGradingCell sizing ratio per direction(1 1 1) = uniform; (0.5 1 2) = graded
gradedGraduated cell spacing(0.5 1 1) = cluster at inlet

Graded meshes: simpleGrading = (a b c) applies grading in the x-direction, y-direction, z-direction respectively. A value of =a < 1/ clusters cells near the first face of the block; =a > 1/ clusters cells near the last face. For example, =simpleGrading (0.1 1 1)/ in a 100-cell x-direction block produces:

= \Delta x_i = \Delta x_0 \cdot r^{i-1} /

where =r = 0.1/ (the grading factor). The first cell is 10× smaller than the last cell (geometric progression). The ratio between adjacent cells is:

= \frac{\Delta x_{i+1}}{\Delta x_i} = r /

For =r = 0.1/, the cell size decreases by 10× per cell going from last to first face. This is critical for boundary layer resolution: if you need y+ ~ 1 in the first cell, =h_1 = y^+ \nu / u_*, you use grading in the wall-normal direction.

blockMesh is ideal for:

. Canonical test cases (channel flow, pipe flow, cavity flow) . Verification cases where the mesh is known analytically . Simple domains (rectangular boxes, multi-block O-grids around cylinders) . LES verification where cell alignment with flow is critical (structured hex provides lowest numerical anisotropy)

blockMesh is unsuitable for:

. Complex geometries (external aerodynamics with CAD surfaces) . Detailed internal flows with multiple components . Anything requiring STL import

For complex geometries, snappyHexMesh is the answer — though it can be combined with blockMesh as the background hexahedral mesh.

snappyHexMesh :: Surface-Conforming Meshing Pipeline

snappyHexMesh is OpenFOAM's surface-conforming mesh generator. It starts with a background hexahedral mesh (from blockMesh or a uniform background), then:

1. Cast — "skeleton rays" from background cell centres to determine inside/outside based on STL surface 2. Snap — Move surface-intersecting cell faces to match the STL surface (conformal mesh) 3. Add layers — Add prism layers on specified patches for boundary layer resolution (optional)

The configuration is in system/snappyHexMeshDict:

/* snappyHexMeshDict */

castPoints  -1;    // cast rays n times to improve inside/outside detection
castShadows off;   // cast occlusion shadows for refining in wake of obstructions

// Step 1: Refinement
refinement
{
    // Background refinement (coarse mesh)
    background min 2 max 4 level 3;  // cells = base / 2^level

    // Surface-based refinement (refine near STL surface)
    surfaceRegions
    {
        wall min 3 max 5 level 4;  // refinement near boundary
    }

    // Field-based refinement (refine where field exceeds threshold)
    fields
    (
        "velocity:3"    // refine where |U| > 3 m/s
    )
}

// Step 2: Feature refinement (refine at sharp edges)
refinementRegions
{
    cylinder
    {
        faces (<point1> <point2>); // bounding box
        level (6 6 6);             // refinement level
    }
}

// Step 3: Surface snap
snap
{
    nSmoothSnap   3;      // smoothing iterations
    nSmoother     5;      // face smoothing iterations
    nUnfavourite  3;      // eliminate unfavourable faces
    nFaceDrop     2;      // drop faces if mesh quality is poor
    tolerance     1.0;    // snap tolerance
}

// Step 4: Layer addition
addLayers
{
    layers
    {
        wall  (6 1 1 0.2);  // [nLayers, growthRate, ratio, thickness]
    }
    expansionRatio  1.2;   // growth rate between layers
    finalLayerThickness 0.001;  // thickness of last layer
    thickness       0.01;  // total boundary layer height
    nDimSmooth      3;     // smoothing iterations in nD
    nSmooth         10;    // smoothing iterations
    nRelaxIter      5;     // relaxation iterations (smoothing)
    errorControl    on;    // stop if mesh quality drops below threshold
    maxFirstLayer   yes;   // enforce maximum first-layer height
    absoluteFirstLayer no; // firstLayer absolute (not relative)
    nSmoothTerrain  10;    // terrain smoothing (for surface normals)
}

Key snappyHexMesh concepts:

. CAST (Step 1) — The algorithm casts rays from each background cell centre to the STL surface. Cells whose centres fall inside the geometry (as determined by ray-casting intersection parity) are marked for removal/cutting. The quality of the cast is improved by =castPoints/ and =castShadows/. A value of =castPoints = -1/ means infinite iterations until convergence. =castShadows/ refines cells in the "shadow" of surface protrusions (useful for wake refinement).

. Snap (Step 2) — Face nodes on the STL surface are moved to match the STL geometry. The smoothing algorithm (Laplacian smoothing) preserves mesh quality during snapping by spreading the displacement from snapped nodes to neighbouring nodes. The tolerance parameter controls how far a face node can move — too small, and the surface isn't conformal; too large, and cell quality degrades (skewness, aspect ratio violations).

. Add layers (Step 3) — After snapping, prism layers are added to wall patches. The =addLayers/ control has the same format as cfMesh's boundary layer specifications. However, snappyHexMesh has more parameters for quality control and recovery (errorControl, maxFirstLayer, absoluteFirstLayer). It can also un-layer cells (reverse the layer addition) if the mesh quality drops below a threshold.

Mesh Quality Control :: checkMesh and Thresholds

After mesh generation, checkMesh evaluates the mesh quality:

[#BEGIN_SRC bash checkMesh -allGeometry -allTopology

#+END_SRC

Quality MetricAcceptableGoodExcellent
---------------------------------------------
Skewness (0–1)< 0.85< 0.7< 0.5
Orthogonality (0–1)> 0.2> 0.5> 0.7
Max non-orthogonality (°)< 70< 50< 30
Face concavity< 5< 2< 1
Face determinant> 0.001> 0.1> 0.5
Cell determinant (high-accuracy)> 0.1> 0.3> 0.5
Cell volumePositiveUniform (no > 10× ratio)Uniform (no > 2× ratio)
Face areaPositiveUniform (no > 10× ratio)Uniform (no > 5× ratio)

The most important quality metrics for simulation accuracy are:

. Skewness — measures how much a cell deviates from a symmetric shape. High skewness introduces interpolation error and degrades gradient accuracy. The relationship is: if a cell is highly skewed, the line between cell centres does not pass through the face centre, and the face interpolation =\phi_f = (\phi_P + \phi_N) / 2/ introduces systematic error.

. Orthogonality — measures the angle between the vector connecting cell centres and the face normal vector:

= \text{orthogonality} = \frac{|\vec{H} \cdot \vec{S}|}{|\vec{H}| \cdot |\vec{S}|}

For orthogonal meshes (H parallel to S), orthogonality = 1. For highly non-orthogonal meshes (H nearly perpendicular to S), orthogonality → 0. The non-orthogonal correction in the laplacian scheme (see Numerical Schemes) accounts for this, but the correction is more expensive and less accurate as orthogonality degrades.

. Cell determinant — measures the quality of the cell's shape by evaluating the Jacobian determinant of the mapping between reference coordinates and physical coordinates. A negative determinant means the cell is inverted (computationally invalid). A determinant near zero means the cell is extremely distorted.

For CFD accuracy, all interior cells should have skewness < 0.7, orthogonality > 0.5, and determinant > 0.1. Boundary cells can tolerate slightly higher skewness because they are near the surface where mesh quality is hardest to control.

Mesh Adaptation :: refineMesh and dynamicRefineFvMesh

OpenFOAM supports mesh refinement and adaptation during simulation (h-refinement):

ToolPurposeDynamic
------------------------
refineMeshStatic refinement (post-processing)No
refineToRegionRefine specified regionsNo
dynamicRefineFvMeshAdaptive mesh during simulationYes
dynamicFvMeshGeneral dynamic mesh (moving)Yes

dynamicRefineFvMesh is the tool for adaptive mesh refinement (AMR). It refines and coarsens the mesh during simulation based on user-defined criteria:

/* dynamicRefineFvMesh */
refineMesh
{
    minRefinement  (1 1 1);    // minimum refinement in each direction
    maxRefinement  (6 6 6);    // maximum refinement per cell
    nBufferLayers 1;           // buffer layers around refined region
    level  4;                  // refinement level for field-based refinement

    // Refine criteria
    fields
    (
        "velocity:1"            // refine where U > 1 m/s
    );

    // Max cells
    maxCells 5e6;              // cap at 5 million cells
}

AMR is particularly useful for LES/DNS simulations where the mesh must resolve the smallest scales in regions of high turbulence. The refinement criteria can be based on any field: vorticity magnitude, strain rate, turbulence kinetic energy gradients, or any user-defined function.

OpenFOAM's AMR is implemented via =polyTopoChange/, which modifies the mesh topology (adds/removes cells, changes connectivity) at each adaptation step. The field data is interpolated from the old mesh to the new mesh. The interpolation preserves conservation for primary flow variables (U, p, rho).

cfMesh Comparison :: cfMesh vs snappyHexMesh vs blockMesh

See also cfMesh Workflow and ANSYS Meshing & Post-Processing.

FeatureblockMeshsnappyHexMeshcfMesh
-------------------------------------------
Mesh typeStructured hexHex/tet/poly hybridHex/tet hybrid
GeometryBoxes, O-gridsSTL conformalSTL cut
Mesh qualityHighestModerate (depends on settings)Lower (staircase surface)
AutomationManual (blocks)High (STL-based)High (meshDict)
Boundary layersNone (manual grading)AddLayers (6+ layers)Prism layers
AMR supportNo (static)No (static)No (static)
Best use caseVerification, canonical casesProduction simulationsRapid mesh generation
Learning curveLow (but skill required)HighLow

snappyHexMesh is the standard choice for production simulations because it offers the best trade-off between quality and automation. blockMesh is the choice for verification and when mesh quality is paramount (LES, DNS). cfMesh is the choice when automation is prioritised over quality (rapid prototyping, initial design exploration).

See Also :: Related Notes

. Mesh Quality — quantifying mesh quality metrics . Cell Types — hex, tet, poly, hybrid mesh quality implications . cfMesh Workflow — cartesian meshing comparison . OpenFOAM Case Setup — mesh files in constant/polyMesh . OpenFOAM Solver Selection — solvers that require specific mesh quality . ANSYS Meshing & Post-Processing — Fluent Meshing comparison

References

. OpenFOAM User Guide. ESI OpenCFD. (blockMesh and snappyHexMesh documentation.) . OpenFOAM V2012 Programming Guide. ESI OpenCFD. (polyTopoChange for dynamic mesh topology.) . Versteeg, H.K. & Malalasekera, W. (2007). An Introduction to CFD. Chapter 4 (Mesh generation). . Jänicke, C., & Hege, H.-C. (2017). "cfMesh: An open-source mesh generator for CFD." cfMesh 2017 Proceedings.