Plan and evaluate mesh generation for numerical simulations...
Provide a consistent workflow for selecting mesh resolution and checking mesh quality for PDE simulations.
| Input | Description | Example |
|---|---|---|
| Domain size | Physical dimensions | 1.0 Γ 1.0 m |
| Feature size | Smallest feature to resolve | 0.01 m |
| Points per feature | Resolution requirement | 10 points |
| Aspect ratio limit | Maximum dx/dy ratio | 5:1 |
| Quality threshold | Skewness limit | < 0.8 |
What is the smallest feature size?
βββ Interface width β dx β€ width / 5
βββ Boundary layer β dx β€ layer_thickness / 10
βββ Wave length β dx β€ lambda / 20
βββ Diffusion length β dx β€ sqrt(D Γ dt) / 2
| Problem | Recommended Mesh |
|---|---|
| Simple geometry, uniform | Structured Cartesian |
| Complex geometry | Unstructured triangular/tetrahedral |
| Boundary layers | Hybrid (structured near walls) |
| Adaptive refinement | Quadtree/Octree or AMR |
All scripts emit a top-level object with inputs (the echoed CLI values) and
results (the computed fields below). Index as result["results"]["..."].
| Script | results Fields |
|---|---|
scripts/grid_sizing.py |
dx, counts (list of per-dimension cell counts, length == dims), notes |
scripts/mesh_quality.py |
aspect_ratio, skewness, size_anisotropy, quality_flags, dims, notes |
mesh_quality.py describes axis-aligned (orthogonal Cartesian) cells defined
purely by edge spacings. For such cells every interior angle is 90Β°, so the true
angular skewness is always 0.0 and high_skewness is never flagged.
Cell elongation is reported separately via aspect_ratio and the redundant
convenience field size_anisotropy (= 1 - 1/aspect_ratio).
scripts/grid_sizing.pyscripts/mesh_quality.pyUser: I need to mesh a 1mm Γ 1mm domain for a phase-field simulation with interface width of 10 ΞΌm.
Agent workflow:
python3 scripts/grid_sizing.py --length 0.001 --resolution 200 --json
# Compute grid sizing for 1D domain
python3 scripts/grid_sizing.py --length 1.0 --resolution 200 --json
# Check mesh quality (3D cell)
python3 scripts/mesh_quality.py --dx 1.0 --dy 0.5 --dz 0.5 --json
# High aspect ratio check (2D cell; --dz omitted is treated as 2D)
python3 scripts/mesh_quality.py --dx 1.0 --dy 0.1 --json
All validation errors are written to stderr and the script exits with code 2.
| Error message | Cause | Resolution |
|---|---|---|
length must be positive, got ... |
Non-positive domain size | Use a positive value |
resolution must be positive, got ... |
Non-positive resolution (resolution=1 is a valid single-cell mesh) |
Use a positive integer |
dims must be one of (1, 2, 3), got ... |
Unsupported dimension count | Use 1, 2, or 3 |
<name> must be a finite positive number, got ... |
dx/dy/dz not finite or not positive |
Use a finite positive value |
<name> exceeds maximum (...), got ... |
Input above the resource-exhaustion bound | Use a smaller value |
| Aspect Ratio | Quality | Impact |
|---|---|---|
| 1:1 | Excellent | Optimal accuracy |
| 1:1 - 3:1 | Good | Acceptable |
| 3:1 - 5:1 | Fair | May affect accuracy |
| > 5:1 | Poor | Solver issues likely |
Skewness is the angular deviation from the ideal cell shape
(max(|90Β° - ΞΈ_i|) / 90Β° for quads/hexes β see references/quality_metrics.md).
mesh_quality.py works from axis-aligned edge spacings, which describe
orthogonal Cartesian cells whose interior angles are all exactly 90Β°; it
therefore always reports skewness = 0.0 for these cells. The thresholds below
apply when a genuine skewness value is obtained from real cell-corner geometry
(e.g. from an unstructured mesh), not from dx/dy/dz spacings.
| Skewness | Quality | Impact |
|---|---|---|
| 0 - 0.25 | Excellent | Optimal |
| 0.25 - 0.50 | Good | Acceptable |
| 0.50 - 0.80 | Fair | May affect accuracy |
| > 0.80 | Poor | Likely problems |
Note: cell elongation is not skewness. An anisotropic but orthogonal cell (e.g. a wall-aligned boundary-layer cell) has high
aspect_ratio/size_anisotropybut zero skewness, and is often perfectly acceptable.
| Application | Points per Feature |
|---|---|
| Phase-field interface | 5-10 |
| Boundary layer | 10-20 |
| Shock | 3-5 (with capturing) |
| Wave propagation | 10-20 per wavelength |
| Smooth gradients | 5-10 |
dx and counts from grid_sizing.py --json and confirmed the smallest physical feature gets enough points (interface β₯5Γdx, boundary layer β₯10Γdx, wavelength β₯20Γdx per Resolution Selection above).grid_sizing.py once per differing edge length (or applied --dx per axis) β did NOT apply a single --length-derived count to unequal edges.notes field for "Grid does not fully cover length" and resolved any partial-coverage warning before trusting counts.aspect_ratio and quality_flags from mesh_quality.py --json; confirmed high_aspect_ratio is absent OR that the elongation is intentional and physics-aligned (e.g. wall-aligned boundary-layer cell with ARβ€100 along the wall).skewness = 0.0 is the expected orthogonal-Cartesian result, NOT a measured quality pass β for unstructured/non-orthogonal cells, obtained a real angle-based skewness from cell-corner geometry and checked it against the <0.8 threshold.dx also satisfies the solver's stability constraint (cross-check with numerical-stability) before committing to the resolution.| Tempting shortcut | Why it's wrong / what to do |
|---|---|
"skewness came back 0.0, so the mesh quality is fine." |
mesh_quality.py always returns skewness = 0.0 for axis-aligned spacings β it is a definitional property of orthogonal cells, not a measurement. Real skewness needs cell-corner angles from an unstructured mesh; don't read 0.0 as a passing quality check. |
| "Two grids gave nearly the same answer, so the mesh is converged." | Two grids cannot establish the observed order or the asymptotic range. Use β₯3 successively refined grids and confirm the quantity of interest is converging before quoting any result as mesh-independent. |
"High aspect_ratio was flagged, so the cell is bad." |
Elongation is not skewness. A wall-aligned boundary-layer cell with AR up to ~100 is acceptable when aligned with the flow/field; check size_anisotropy and the physics, not just the high_aspect_ratio flag. |
"I'll set one --length and reuse the counts for all axes." |
grid_sizing.py is isotropic per call β it applies the single derived count to every dimension. For unequal edges this over/under-resolves axes; run it per edge length or supply --dx per axis. |
"dx = length/resolution resolves my feature because resolution is large." |
Points-per-domain is not points-per-feature. A fine global dx can still place too few cells across a thin interface/layer; check feature_size / dx against the Resolution Guidelines (5-10 for interfaces, 10-20 for boundary layers). |
| "The mesh is fine enough, so I can ignore the time step." | Mesh resolution and temporal stability are coupled: shrinking dx tightens explicit CFL/diffusion limits. A refined mesh that violates the solver's stability constraint diverges β re-check dt against numerical-stability after any refinement. |
length, resolution, dx, dy, dz) are validated as finite positive numbers with upper bounds to prevent resource exhaustiondims is restricted to {1, 2, 3}argparse type parameters reject non-numeric input at the CLI boundary before any processing occursallowed-tools excludes Bash to prevent the agent from executing arbitrary commands when processing user-provided inputseval(), exec(), or dynamic code generationshell=True)Read and Write to prepare inputs and capture outputs rather than constructing shell commands from user textgrid_sizing.py takes a single --length and applies the resulting count to every dimension. For an anisotropic domain (e.g. 10 cm Γ 5 cm), run it once per differing edge length, or compute dx from physics and apply it per axis (e.g. --length 0.10 --dx 5e-5, then --length 0.05 --dx 5e-5).references/mesh_types.md - Structured vs unstructuredreferences/quality_metrics.md - Aspect ratio/skewness thresholdssize_anisotropy, made mesh_quality.py --dz optional (2D cells), fixed grid_sizing off-by-one for resolution-derived counts, surfaced dx-override note, corrected output/error-handling docs