CFD Meshing — Best Practices and Quality Guide
The mesh is the foundation of every CFD simulation. A poor mesh gives wrong answers regardless of how good your turbulence model or solver is. This guide covers the key quality metrics, boundary layer strategy, domain sizing, and independence verification.
By NovaSolver Contributors (Anonymous Engineers & AI) | CFD / Fluid Analysis | 日本語版 →
1. CFD Mesh Requirements vs. FEA Mesh
I've meshed parts for FEA before. Can I use the same mesh quality rules for CFD? I thought aspect ratio was the main thing to control.
Big difference. In FEA you can tolerate high aspect ratios in the far-field as long as stress gradients are small there — the element is just computing average strains. In CFD, high aspect ratios are actually fine and sometimes essential (you deliberately use very thin, high-aspect-ratio cells in the boundary layer). But what kills CFD accuracy is something FEA doesn't care about much: non-orthogonality — how much the face normal deviates from the vector joining the two cell centers. Non-orthogonal faces create cross-diffusion errors in the discretization of the Laplacian (pressure Poisson and diffusion terms). OpenFOAM's checkMesh reports non-orthogonality as a key metric; above 70° is dangerous, above 85° will likely diverge.
| Mesh Quality Metric | CFD Significance | Acceptable Range | Dangerous Range |
|---|---|---|---|
| Non-orthogonality | Cross-diffusion error in Laplacian; divergence risk | < 45° (ideal), < 70° (OK) | > 70° (add correction iterations), > 85° (divergence likely) |
| Aspect ratio | High AR OK in BL (thin cells aligned with flow) | < 1000 in BL; < 100 in bulk | > 10,000 (conditioning issues in pressure solver) |
| Skewness | Interpolation error at cell faces | < 0.85 | > 0.95 (highly inaccurate) |
| Smoothness (growth ratio) | Interpolation error between neighboring cells | < 1.3 recommended | > 2.0 (large discretization error at interface) |
| Concavity (polyhedra) | Face normal not well-defined on concave faces | Convex cells only | Any concave cell is problematic |
2. Structured vs. Unstructured Mesh
When should I use structured hexahedral meshes vs. unstructured tetrahedral meshes? I usually just let the meshing software do it automatically.
Automatic unstructured tet meshes are fine for getting started, but structured hex meshes can give 2–5x better accuracy per cell in well-aligned flows because hex cells have zero non-orthogonality and the numerical diffusion aligns with the flow direction. The trade-off is meshing complexity — creating a high-quality multi-block structured hex mesh for a complex shape like a car or turbine blade can take days of manual work. For most industrial cases, a hybrid approach wins: structured hex/prism layers in the boundary layer where quality matters most, and unstructured hex (from snappyHexMesh) or polyhedral cells in the bulk. Pure tet is only acceptable if you have very good mesh refinement controls and you run a correction scheme for the large non-orthogonality that tet meshes produce.
| Mesh Type | Quality | Automation | Best Use Case |
|---|---|---|---|
| Structured Hex (block) | Excellent (zero non-ortho) | Manual / low | Simple geometries: channels, aerofoils (2D), pipe sections |
| Unstructured Hex (snappyHexMesh) | Good (<45° non-ortho typical) | High — automated with surface input | Complex 3D shapes: vehicles, machinery (OpenFOAM workflow) |
| Polyhedral (cfMesh, Fluent poly) | Good — fewer cells for same accuracy | High | Complex industrial geometries, chemical equipment |
| Unstructured Tet | Poor near walls (high skewness) | Very high — any geometry | Last resort; only with inflation layers + quality checks |
| Hybrid Tet + Prism layers | Fair to good | Medium — standard in ANSYS Meshing | Industrial CFD in commercial tools (Fluent, CFX) |
3. Boundary Layer Mesh — Prism Layers and y+
How do I calculate the first cell height to get the right y+? I understand y+ should be about 1 for resolved walls, but I don't know how to actually calculate the cell thickness.
The formula is $y_1 = y^+ \nu / u_\tau$, where $u_\tau = \sqrt{\tau_w/\rho}$ is the friction velocity. You estimate the wall shear stress $\tau_w$ from a flat-plate correlation before running: $\tau_w = 0.0594 \rho U^2 Re_L^{-0.2}$ for turbulent flow. For a car at 30 m/s in air: $\nu = 1.5 \times 10^{-5}$, Re ≈ $5 \times 10^6$, so $\tau_w \approx 0.73$ Pa, $u_\tau \approx 0.78$ m/s. For y+ = 1: $y_1 = 1 \times 1.5 \times 10^{-5} / 0.78 \approx 19$ μm. That's a very thin first cell — 0.019 mm — which is typical for automotive external aero.
First cell height calculation from target y+:
$$y_1 = \frac{y^+ \, \nu}{u_\tau}, \quad u_\tau = \sqrt{\frac{\tau_w}{\rho}}, \quad \tau_w \approx 0.0594 \, \rho U_\infty^2 \, Re_L^{-0.2}$$Boundary layer thickness estimate (turbulent flat plate):
$$\delta \approx \frac{0.37 \, L}{Re_L^{0.2}}$$Number of prism layers to span the boundary layer at growth ratio $r$:
$$n_{layers} = \frac{\ln(\delta / y_1)}{\ln(r)}, \quad \text{typical: } r = 1.2, \; n = 15\text{--}25 \text{ layers}$$4. Domain Sizing
| Problem Type | Inlet (upstream) | Outlet (downstream) | Sides / Top |
|---|---|---|---|
| External aero (car/aircraft) | 5D upstream | 15–20D downstream | 5D from model |
| Cylinder in cross-flow | 10D upstream | 20D downstream | 10D from axis |
| Pipe/channel flow | 10D (hydrodynamic entry length) | 5–10D | Wall (no sizing issue) |
| Building wind analysis | 5H upstream (H = building height) | 15H downstream | 5H sides, 5H top |
The goal is to keep blockage ratio below 1%:
$$\text{Blockage} = \frac{A_{frontal}}{A_{domain}} \times 100\% \leq 1\%$$5. Mesh Independence Study — Richardson Extrapolation
How do I know when my mesh is fine enough? Do I just keep refining until the answer stops changing?
The formal method is to run at least three mesh levels — coarse, medium, fine — with consistent refinement ratio (typically r = 1.5 or 2 in all three directions, so roughly 3.4× or 8× more cells per level). Extract your key output — drag, Nusselt number, pressure drop — from each mesh. If the solution is in the asymptotic convergence range, Richardson extrapolation gives you an estimate of the "exact" (zero-mesh-size) solution: $f_h = f_{fine} + (f_{fine} - f_{medium})/(r^p - 1)$ where p is the observed convergence order. If your two finest meshes differ by less than 2%, you're usually in good shape to report the fine mesh result. Also report the Grid Convergence Index (GCI) as the uncertainty metric.
Richardson extrapolation for zero-mesh-size estimate with refinement ratio $r$ and observed order $p$:
$$f_{exact} \approx f_1 + \frac{f_1 - f_2}{r^p - 1}$$Grid Convergence Index (GCI), the accepted ASME standard for reporting discretization error:
$$GCI = F_s \frac{\left|\frac{f_1 - f_2}{f_1}\right|}{r^p - 1} \times 100\%$$where $F_s = 1.25$ is the safety factor for three meshes, $f_1$ is the fine mesh result, $f_2$ is the medium mesh result.
6. OpenFOAM Meshing Tools
| Tool | Type | Best Use | Key Features |
|---|---|---|---|
| blockMesh | Structured hex | Simple geometries, channels, benchmark cases | Pure Python/dict-based; full orthogonality; block decomposition |
| snappyHexMesh | Unstructured hex + prism layers | Complex 3D surfaces (STL input) | Automatic castellated mesh + surface snapping + layer addition |
| cfMesh | Polyhedral/hex-dominant | Industrial complex shapes | Often higher quality than snappy on curved surfaces; commercial-grade |
7. Commercial Meshing Tools
| Tool | Vendor | Strengths |
|---|---|---|
| ANSYS Meshing | ANSYS | Tight integration with Fluent/CFX; inflation layer automation; good for RANS |
| Pointwise | Cadence | High-quality structured and hybrid meshes; aerospace industry standard |
| ICEM CFD | ANSYS (legacy) | Best multi-block structured hex meshing; O-grid topology for airfoils |
| StarCCM+ mesher | Siemens | Polyhedral cells with prism layers; robust for complex geometry |
| Simcenter ANSA | BETA CAE | Automotive industry standard; fast surface cleanup + volume meshing pipeline |
checkMesh before starting a solver. Focus on: max non-orthogonality (<70°), max skewness (<4 for OpenFOAM), and the list of "failed mesh checks." One highly non-orthogonal cell in a critical flow region can cause local divergence that eventually crashes the entire run.