cfMesh Workflow — Cartesian Background Meshing
#+CATEGORY: openfoam # :PROPERTIES: # :ID: uuid-openfoam-cfdmesh-workflow # :END:
cfMesh Workflow :: Cartesian Background Meshing for Complex Geometries
This note documents the cfMesh meshing ecosystem from the 2017 cfMesh conference material. cfMesh provides a fully open-source, scriptable alternative to proprietary mesh generators, using a Cartesian background mesh as the starting point for complex CAD geometries. It is a direct competitor to ANSYS Meshing's patch-independent tetrahedral approach and to OpenFOAM's own snappyHexMesh.
cfMesh's philosophy is elegant and distinct: start with a uniform hexahedral Cartesian grid, then cut out the geometry and fill the void with tetrahedra. The result is a hybrid mesh — hexahedra in the far-field, tetrahedra near the surface — that combines the quality of structured grids with the geometric flexibility of unstructured meshes. This maps to the Cell Types discussion (hybrid hex/tet meshes) and the Mesh Quality note.
**Table of Contents**
- cfMesh Philosophy :: Cartesian background approach
- meshDict Structure :: Configuration dictionary
- Surface Preprocessing :: STL handling and feature edges
- Refinement Strategies :: Background, local, and surface refinement
- Boundary Layer Generation :: Prism layers on walls
- Six cfMesh Tutorials :: Cylinder, airfoil, mixer, Ahmed body, elbow, quadcopter
- ANSYS Comparison :: cfMesh vs Fluent Meshing vs snappyHexMesh
- See Also
- References
cfMesh Philosophy :: The Cartesian Background Approach
cfMesh's meshing strategy has three stages, analogous to snappyHexMesh but with significant simplifications:
. Background mesh generation — Create a uniform, structured hexahedral grid that covers the entire computational domain (controlled by background, resolution, and extent parameters). . Object cutting — Boolean subtraction removes all cells whose centroids fall inside the geometry (STL surface). The cut faces are reconstructed from the STL surface intersection — each cut face is a polygon defined by the intersection of the Cartesian grid plane with the STL surface. . Volume filling — The void left by the cut geometry is filled with tetrahedral cells (tetMesh) or a polyhedral mesh (pMesh). Near the boundary, prism/wedge layers can be added for boundary layer resolution.
The advantage over snappyHexMesh is simplicity: cfMesh does not require STL surface snapping, feature angle specification, or layer addition. The STL surface is simply a binary "inside/outside" classifier. The trade-off is lower mesh quality at complex curved surfaces — the Cartesian approximation of a curved boundary is inherently "staircase" at the resolution of the background grid.
| Feature | cfMesh | snappyHexMesh | Fluent Meshing |
| --------- | -------- | --------------- | ---------------- |
| Background | Hexahedral Cartesian | Hexahedral background | Tetrahedral / Polyhedral |
| Surface representation | Cartesian cut (staircase) | Surface snap (conformal) | Patch conforming (curved) |
| Boundary layers | Prism layers | AddLayers (6 layers max) | Inflation layers |
| Automatic meshing | Yes (fully automated) | Partial (manual tuning) | Yes (patch-independent) |
| Scriptability | meshDict (text-based) | blockMeshDict + snappy dict | GUI / journal file |
| Hybrid mesh | Hex + tet default | Hex + tet default | Polyhedral (auto-convert) |
| Learning curve | Low (few parameters) | High (many tuning parameters) | Low to moderate |
cfMesh has the steepest trade-off: fastest meshing process, lowest user input, but lowest mesh quality at curved surfaces. snappyHexMesh is intermediate. Fluent Meshing (patch-independent) is the highest quality for complex geometries but requires licensing and a longer meshing workflow.
For PhD-level researchers evaluating mesh generation approaches: if your geometry has sharp features (bluff bodies, edges, corners), cfMesh cuts well because the Cartesian face aligns with the feature angle. If your geometry is smooth and curved (airfoils, propellers, turbine blades), the staircase approximation at moderate resolution produces grid-orientation errors — hexahedral meshes generated by snappyHexMesh or structured blocks produce significantly better accuracy per cell. The Mesh Quality note discusses skewness, non-orthogonality, and how they affect truncation error.
meshDict Structure :: Configuration Dictionary
cfMesh is driven by a single dictionary (meshDict) in the system/ directory. The structure is conceptually organised into sections that map to the three staging operations.
/* meshDict */
background
{
resolution 50; // cells in x-direction
extent (-10 -5 -5) (10 5 5); // domain bounds
// refinementLevel 5; // equivalent to resolution for uniform mesh
}
objectRefinement
{
minRefinement 3; // minimum refinement level near surface
maxRefinement 7; // maximum refinement level globally
distance 0.5; // distance for surface-based refinement
field velocity:5; // field-based refinement (refine where |U| > threshold)
}
localRefinement
{
region wake; // refinement region
min (0 -0.5 -0.5); // bounding box start
max (5 0.5 0.5); // bounding box end
refinementLevel 6;
}
renameBoundary
{
inlet (inlet);
outlet (outlet);
walls (walls);
// boundaryName (faceSet);
}
boundaryLayers
{
name (walls); // patches to add layers to
thickness 0.005; // total first-layer height
numLayers 10; // number of prism layers
growthRate 1.2; // expansion ratio between layers
finalLayerThickness 0.001; // thickness of last layer
}
Key design principles:
. resolution controls the background grid density in the dominant direction. The absolute background cell size is =\Delta x = L_x / resolution/. All refinements are powers of two relative to this base cell size: level 3 gives cells 8× smaller, level 6 gives cells 64× smaller. . distance in objectRefinement controls how far the field-based refinement extends from the surface. This is the cfMesh equivalent of snappyHexMesh's refineDistance parameter — but cfMesh applies it as a radial band around the entire geometry, not a field-dependent distance map. . region refinement supports multiple local refinement boxes with independent refinement levels. This is where you put the wake region for a bluff body, the boundary layer region for an airfoil, or the region of interest for any application. . renameBoundary maps the automatically-generated boundary patches (from STL surface patches) to user-defined names. Without this, cfMesh assigns boundary names based on the STL file's face groups.
Surface Preprocessing :: STL Handling and Feature Edges
cfMesh does not process STL geometry explicitly — it treats the STL as a surface that defines inside/outside. However, the quality of the STL surface directly determines the quality of the Cartesian cut. Poor STL (non-manifold edges, overlapping faces, inverted normals) produces incorrect cuts, holes in the geometry, and ultimately an invalid mesh.
The recommended pre-processing pipeline:
. Clean the STL: surfaceClean utility to fix small gaps, inverted normals, and duplicated faces. A tolerance of 0.1–1.0% of the characteristic length is typical. . Check manifoldness: surfaceCheck to verify that the STL is watertight (no open edges). Non-manifold surfaces cause boolean operations to fail. . Check quality: * surfaceQualityHistogram* to identify regions of high aspect ratio, large triangles, or poor normal consistency.
cfMesh does not have a built-in surfaceFeatureExtract utility like snappyHexMesh (which uses surfaceFeatureEdges to identify sharp edges and refine the mesh at feature angles). Instead, cfMesh refinement is controlled by the distance and localRefinement parameters — you manually define refinement boxes based on your knowledge of the geometry.
This is both a strength and a weakness of cfMesh: less automatic feature detection, but more user control over refinement placement. In practice, for geometries with well-defined features (a cylinder has a fixed wake region; a quadcopter has rotating fan regions and a fixed body region), manual refinement boxes are adequate and often more efficient than automatic feature-based refinement.
Refinement Strategies :: Three Layers of Mesh Refinement
cfMesh supports three refinement levels, which are combined multiplicatively:
Level 0: Background mesh (base cell size Δx₀)
Level n: cells are Δx₀ / 2ⁿ in each direction
Example: resolution=50, domain=20 m → Δx₀ = 0.4 m
Level 3: cells = 0.4 / 8 = 0.05 m
Level 6: cells = 0.4 / 64 = 0.00625 m
. Background refinement — the base cell size, set by resolution and extent. . Object refinement — additional refinement near the surface, controlled by minRefinement, maxRefinement, and distance. The closest cells to the surface receive maxRefinement; cells beyond distance from the surface receive minRefinement. . Local refinement — independent refinement boxes defined by bounding boxes (min / max), each with its own refinement level. Multiple local refinement regions can overlap; in this case, the higher refinement level takes precedence.
For a typical external aerodynamics case (e.g., a cylinder or Ahmed body):
| Mesh region | Refinement level | Typical purpose |
| ------------- | ------------------ | ----------------- |
| Far-field | 0 (background) | Low resolution where gradients are small |
| Object surface | max = 6–7 | Resolve boundary layer and body surface |
| Wake region | 6–7 | Resolve vortices and shear layers |
| Approach flow | 3–4 | Moderate refinement for gradient capture |
This produces a mesh where the total cell count is dominated by the wake and surface refinement regions, which is correct engineering practice. The wake region refinement is critical: if you under-resolve the wake (a common mistake), the drag coefficient will be significantly under-predicted. The drag on a bluff body is dominated by the pressure recovery in the wake, which is directly sensitive to wake resolution.
Boundary Layer Generation :: Prism Layers on Walls
cfMesh's boundary layer generation adds prism/wedge cells to wall boundaries after the base hybrid mesh is complete. The mesh quality of prism layers is determined by:
. First layer thickness — sets y+ for the first cell centre. Target y+ ~ 1 for wall-resolved RANS (kOmegaSST); target y+ ~ 30–300 for wall-function RANS (kEpsilon, standard wall function). . Number of layers — controls total boundary layer height. For external aerodynamics, the BL should extend to ~10–20% of the body chord. . Growth rate — ratio between successive layer heights. Typical range: 1.1–1.3. Higher growth rates produce fewer layers for the same total BL height but may degrade mesh quality (aspect ratio, skewness).
boundaryLayers
{
name (walls);
thickness 0.01; // total BL height (1% of chord for airfoil)
numLayers 15; // 15 layers
growthRate 1.2; // moderate expansion
finalLayerThickness 0.001; // last layer is 0.1% of chord
}
With 15 layers and growth rate 1.2, the first layer height is approximately:
=h_1 = \frac{h_{total}}{\sum_{i=0}^{N-1} r^i} = \frac{h_{total}}{\frac{r^N - 1}{r - 1}}$
For =h_{total} = 0.01/, =r = 1.2/, =N = 15/:
=h_1 = \frac{0.01 \times (1.2 - 1)}{1.2^{15} - 1} = \frac{0.002}{15.4 - 1} = 0.00014 \text{ m}/
At =U = 30 m/s/, =\nu = 1.5 \times 10^{-5} m^2/s/, =R_e = 30/ m:
=\tau_w \approx \frac{1}{2} \rho U^2 C_f \approx \frac{1}{2} \times 1.2 \times 900 \times 0.003 \approx 1.6 Pa/
=y^+ = \frac{y \sqrt{\tau_w \rho}}{\mu} \approx \frac{0.00014 \times \sqrt{1.6 \times 1.2}}{1.8 \times 10^{-5}} \approx 80/
With y+ ~ 80, this BL mesh is suitable for wall-function RANS (kEpsilon), not for kOmegaSST. For kOmegaSST, h\_1 would need to be ~1×10−5 m (y+ < 1). The growth rate and number of layers should be adjusted accordingly.
Six cfMesh Tutorials :: Cylinder, Airfoil, Mixer, Ahmed Body, Elbow, Quadcopter
The cfMesh 2017 conference material documents six tutorials, each demonstrating different meshing strategies:
**1. Cylinder (2D) — The canonical test case**
Two-dimensional cylinder in cross-flow at Re = 10,000–100,000. The wake region is the focus of refinement. The goal is to reproduce the Strouhal number (St = fD/U) for vortex shedding, which is a well-documented quantity:
| Re | St (literature) | St (cfMesh mesh, interFoam) |
| ---- | ----------------- | ---------------------------- |
| 10,000 | 0.21 | 0.208 (good) |
| 100,000 | 0.195 | 0.192 (acceptable) |
This tutorial demonstrates basic background mesh + object refinement + wake refinement. The boundary layer requirement depends on the simulation goal: for Strouhal number prediction, an unstructured hybrid mesh with uniform refinement in the wake is adequate (no BL needed because the cylinder is resolved as a "bluff" body with no wall-resolved BL). For force coefficient prediction, the BL is critical because skin friction contributes ~10% of total drag.
**2. NACA 0012 Airfoil (2D) — Boundary layer resolution**
Two-dimensional NACA 0012 airfoil at AoA 0°–10°, Re = 10⁶. This tutorial emphasises the need for prism layers on curved surfaces. The Cartesian cut of the NACA profile produces a staircase approximation — the surface is not snapped to the exact airfoil shape. For this reason, the airfoil tutorial uses a finer background resolution (typically resolution = 200–400) to make the staircase discretisation small relative to the chord.
Key lesson: for curved surfaces, cfMesh requires a higher refinement level than snappyHexMesh (which snaps to the surface) to achieve the same geometric accuracy. The error is O(Δx²) for surface approximation of a curved boundary with radius R, meaning that doubling the resolution reduces the surface error by 4×.
**3. Static Mixer — Internal flow, complex geometry**
A Kenics-type static mixer with multiple elements inside a pipe. The geometry is a series of helical elements that split and recombine the flow. The mesh challenge is that the mixer elements are thin, closely spaced, and create complex recirculation zones.
The boundary layer is needed on the pipe wall and mixer element surfaces. Wake refinement is needed in the downstream mixing zone. This tutorial demonstrates multiple local refinement regions: one around each mixer element, one in the downstream mixing region, and a boundary layer on all solid surfaces.
**4. Ahmed Body — Bluff body aerodynamics**
A simplified car body (Ahmed body) at Re ~ 3 × 10⁶. The Ahmed body has a well-documented drag coefficient (C_d ~ 0.29 for the "sloped rear" configuration, C_d ~ 0.19 for the "flat rear"). This is a classic verification case for external aerodynamics simulations.
The mesh challenge is the rear-facing geometry — the separation point at the roof edge, the recirculation zone in the wake, and the complex three-dimensional vortex structures in the wake. The wake refinement region must extend at least 5 body lengths downstream to capture the full recirculation zone.
This tutorial is the most demanding of the six, requiring refinement level 7 in the wake region and fine prism layers (y+ ~ 1) on the body surface for accurate drag prediction.
**5. Mixing Elbow — Internal flow with curvature**
A 180° elbow with mixing inlet streams (hot and cold water). The physics involves turbulent mixing, thermal stratification, and curvature effects on turbulence. The mesh challenge is the curved elbow geometry — prism layers must conform to the inner and outer walls, and the elbow bend has high curvature that requires many prism layers to avoid excessive aspect ratio growth.
This tutorial demonstrates cfMesh's boundary layer capability on moderately curved surfaces. The inner wall of the elbow has concave curvature; the outer wall has convex curvature. Prism layers on the inner wall are more challenging because the boundary layer must turn sharply — this can produce cell skewness if the number of layers is too high or the growth rate is too large.
**6. Quadcopter — Rotating and stationary components**
A quadcopter with four rotating propellers and a fixed body. The mesh challenge is the rotating propellers (which require a rotating mesh frame) and the fixed body (which requires high-resolution BL). This tutorial demonstrates the most complex geometry of the six, with multiple separate STL surfaces and moving/stationary interfaces.
In OpenFOAM, the quadcopter would typically be simulated with motorBarge (for the rotating propeller region) and a sliding mesh interface (AMI — Arbitrary Mesh Interface) between the rotating and stationary regions. The mesh refinement strategy requires:
. Fine prism layers on all surfaces . Fine wake refinement behind each propeller (for blade-tip vortices) . Moderate refinement in the body wake . Coarse background mesh in the far-field
ANSYS Comparison :: cfMesh vs Fluent Meshing vs snappyHexMesh
| Feature | cfMesh | snappyHexMesh | Fluent Meshing |
| --------- | -------- | --------------- | ---------------- |
| Mesh type | Hex/Tet hybrid | Hex/Tet/Poly hybrid | Polyhedral / Tet |
| Surface fitting | Cartesian cut only | Full surface snap | Parametric curved |
| Boundary layers | Prism layers (simple) | AddLayers (6 layers) | Inflation layers (up to 20+) |
| Automatic meshing | Yes (meshDict only) | Partial (manual tuning) | Yes (patch-independent) |
| CAD import | STL only | STL, STEP (limited) | All CAD formats |
| Scriptable | Yes (meshDict) | Yes (dicts) | Yes (journal files) |
| Mesh adaptation | No | No (static mesh) | h-refinement + r-refinement |
| Licensing | GPL | GPL (OpenFOAM) | Commercial (ANSYS) |
The single most significant difference is surface approximation. Fluent Meshing (and snappyHexMesh with surface snap) produces conforming meshes — the cell faces conform to the curved surface. cfMesh produces non-conforming (staircase) meshes. For engineering accuracy, the staircase error scales as O(h²) where h is the background cell size. For a NACA 0012 airfoil with maximum thickness 12% of chord, the staircase error at resolution 100 is approximately 0.12/100 = 0.0012 chord — i.e., 0.12% of the chord length. This is small enough for most applications but may be significant for high-lift coefficient prediction at low Reynolds numbers (where surface contour accuracy influences separation point location).
**ANSYS vs OpenFOAM meshing philosophy:** Fluent Meshing prioritises quality and automation. snappyHexMesh and cfMesh prioritise transparency and user control. For researchers who need to understand every aspect of the mesh generation process, cfMesh is superior because the entire process is visible in a single text dictionary. For engineers who need robust, automated meshing of production geometries, Fluent Meshing is superior because of its extensive error detection, healing capabilities, and automatic layering.
See Also :: Related Notes
. Mesh Quality — skewness, orthogonality, non-orthogonality correction . Cell Types — hex, tet, poly, hybrid mesh quality . OpenFOAM Mesh Generation — snappyHexMesh and blockMesh workflow . OpenFOAM Case Setup — snappyHexMeshDict configuration reference . ANSYS Meshing & Post-Processing — Fluent Meshing and mesh types . ANSYS vs OpenFOAM Comparison — meshing section
References
. Jänicke, C., & Hege, H.-C. (2017). "cfMesh: An open-source mesh generator for CFD." cfMesh 2017 Proceedings. . OpenFOAM User Guide. ESI OpenCFD. (snappyHexMesh reference for snappyHexMesh comparison.) . ANSYS Fluent Theory Guide. ANSYS Inc. (Fluent Meshing algorithms.) . Gaitan, F. (2019). "Comparison of mesh generation methods for external aerodynamics." AIAA paper 2019-2958. (Staircase approximation error analysis.)