Fast 2D mesh processing, smoothing, and analysis for triangular, quadrilateral, and mixed-element meshes. Intended for hydrodynamic domains.
Dominik Mattioli1†, Ethan Kubatko2
†Corresponding author | 1Unaffiliated | 2Ohio State University ()
MATLAB users: This Python library is the actively-developed successor to the original MATLAB codebase. The original (no longer maintained) is at
src/@CHILmesh/CHILmesh.mand on
- Status & Roadmap
- Why CHILmesh
- Installation
- Quick start
- Features — Performance · Smoothing · Backends · Engine · Examples · CLI
- Citation
- Contributing · Documentation · License
Current status (June 2026): Stable and actively-maintained. C++ half-edge backend (up to ~15× faster on full init); bit-identical output verified; cross-backend equivalence tests across C++ and Rust; fort.14 + .2dm + fort.13 I/O; mixed-element support; full mesh-mutation API (split/swap/merge/collapse, #94); lazy header-only summary().
- Now: Pre-built binary wheels (cibuildwheel, manylinux/macOS/Windows); Rust layer-peel completion (#163).
- Next: performance optimization; parallelization; conda-forge packaging; mkdocs API site; native
.chilfile format - Future: formal integration within a unified ecosystem including
and
The stable backbone for hydrodynamic mesh generation & tooling.
- Pythonic API —
from chilmesh import Mesh; backwards-compatibleCHILmeshalias preserved. - C++ acceleration, bit-identical output — half-edge extension is up to ~15× faster than pure Python on full init (8.6× on the 272k-element ENPAC mesh below), verified bit-for-bit by the cross-backend equivalence suite (76 tests across C++ and Rust backends).
- One interface for all topologies — triangles, quadrilaterals, and mixed meshes share the same call surface.
- Stable v1.x API — downstream projects can pin
chilmesh>=1.0,<2.
pip install chilmesh # PyPI
uv pip install chilmesh # uv
conda install -c conda-forge chilmesh # conda-forge (pending)
pip install -e . # from sourceBackends & the PyPI wheel. The published PyPI wheel is currently pure-Python — it does not bundle the compiled C++/Rust extensions, so a plain
pip install chilmeshruns the (correct, but slower) Python backend andchilmesh.backend_info()reportsavailable: ['python']. The C++/Rust speedups advertised below require a source build of the extension (pip install ./src/chilmesh_cppwith a C++ toolchain;cargo build --releaseinsrc/chilmesh_corefor Rust). Pre-built binary wheels are tracked in #229.
from chilmesh import Mesh
mesh = Mesh.read_from_fort14("ocean.14")
mesh.smooth_mesh(method="fem", acknowledge_change=True)
quality, angles, stats = mesh.elem_quality()
mesh.plot_quality()The legacy chilmesh.CHILmesh import is preserved for backward compatibility. Built-in fixtures live at chilmesh.examples.{annulus, donut, block_o, structured}(). See examples/ for runnable scripts.
- Fast — C++ backend full-inits the 531,680-element ENPAC2003 mesh in ~1.4 s — 8.6× over pure Python (up to ~15× on smaller meshes)
- Mixed-element — triangles, quads, and mixed meshes share one API
- Smoothing — Balendran direct FEM, Zhou-Shimada angle-based, and ADMESH Spring-Based Truss
- Analysis — element quality, interior angles, layer-based decomposition (peel_layers)
- I/O — ADCIRC
.fort.14and SMS Aquaveo.2dmread/write - Spatial queries — point-in-element, k-nearest vertices, radius search at O(log n)
- Mesh alterations — advancing-front element addition (
add_advancing_front_element), coordinate moves; full mutation suite tracked in #94 - Valence integration —
from_admesh_domain()adapter
Reference workload: EasternPacific_ENPAC2003 — 272,913 vertices · 531,680 elements · 75 layers, from the Valence registry. Medians of 3 runs, single machine, chilmesh 1.2.2.
| Stage | MATLAB (Octave) ‡ | Python | C++ | Rust |
|---|---|---|---|---|
| Fast init (adj, no peel) | 2.738 s | 6.454 s | 0.769 s | tbd |
| Peel only | 12.771 s | 5.814 s | 0.669 s | tbd |
| Full init (adj + peel) | 16.677 s | 12.300 s | 1.438 s | tbd |
| Quality (signed area) | 75 ms | 51 ms | 7 ms | tbd |
Like-for-like: every backend runs the same operation on the same in-memory arrays. No fort.14 parse, signed-area quality. All resolve n_layers = 75; Python↔C++ layers are bit-identical (test_backend_equivalence.py).
- C++ leads every stage — full init 8.6× over Python, 11.6× over Octave.
- Octave builds adjacency 2.4× faster than Python —
sparse()-accumulated, in compiled built-ins. - Python peels 2.2× faster than Octave — ~26% ahead on full init overall.
- Rust — the layer peel matches Python on
n_layers, layer-member sets (OE/IE/OV/IV), per-layerbEdgeIDs(full-mesh edge IDs, ascending), full-meshEdge2Vert/Vert2Edgeordering, and signed areas — verified by therust-equivalenceCI job across all four fixtures incl.block_o(#163). Perf is now measured (the ENPAC cells above staytbd— that mesh lives outside the repo): on the bundled fixtures Rust full-inits ~3–5× faster than Python but ~2–5× slower than C++. Itsget_vertex_edgesquery path was O(n) per call (rebuilt the edge list each call); that defect is now fixed — the vertex→edge index is cached, so queries are O(1) (Block_O 954 μs → 0.32 μs, 76/76 equivalence tests still pass). Full data, methodology, the "should Rust replace Python anywhere?" analysis, and the default-backend/opt-in discussion:docs/RUST_EVALUATION.md. Bottom line: C++ remains the acceleration path; Rust earns no perf niche over it.
‡ Octave 8.4, interpreter. Times are in-memory compute only — fort.14 parse and rendering excluded. Machine-dependent. Full method: docs/BENCHMARK.md.
Figure 1. Scale demo on EasternPacific_ENPAC2003 (272,913 vertices · 531,680 elements). plot_quality() renders per-element skew quality; plot_quality_histogram() emits the matched-colormap distribution beneath. Reproduce: python scripts/generate_enpac_showcase.py.
Full pipeline cost (parse · adjacency · peel · spatial-index · quality · render — render dominates), the cross-backend layer-parity catalog (557 → 273k vertices), and mesh-quality metrics: docs/BENCHMARK.md. The layer peel is distinct from medial axis / skeleton / distance — docs/CONCEPTS.md:
Figure 2. Related, not identical — distance is a scalar field; its ridge is the medial axis; the skeleton is a thinned discrete curve; layers are concentric element bands (what CHILmesh peels). Full write-up: docs/CONCEPTS.md. Reproduce: python scripts/illustrate_mesh_concepts.py.
Three algorithms — each preserves boundary nodes, leaves topology unchanged, and accepts mixed-element meshes.
| Algorithm | API call | Style | Best for |
|---|---|---|---|
| Balendran direct FEM | smooth_mesh(method='fem') |
One-shot sparse solve | General-purpose default; stable on tri/quad/mixed |
| Zhou-Shimada angle-based | smooth_mesh(method='angle-based') |
Iterative, angle-maximising | Difficult mixed meshes where FEM stalls |
| ADMESH Spring-Based Truss | smooth_mesh(method='sdf', sdf=...) |
Spring/force relaxation against SDF | Quality gains with SDF-respecting boundary nodes (triangle-only) |
pip install chilmesh gives you the pure-Python implementation — zero compiled dependencies, runs everywhere, and is the canonical reference every other backend is validated against. The C++ extension is the high-performance opt-in: same algorithms, bit-identical output, up to ~15× faster on full init.
| Language | Role | How to get it |
|---|---|---|
| Python | Reference implementation — the default | pip install chilmesh |
| C++ | High-performance backend (half-edge) — bit-identical output | pip install ./src/chilmesh_cpp (or bash scripts/build_cpp.sh) |
| Rust | ❄️ Frozen (experimental quad-edge); output-equivalent to Python (rust-equivalence CI, all 4 fixtures incl. block_o) but not developed further. Measured ~2–5× slower than C++ on full init (queries were O(n)/call, now cached to O(1)) — docs/RUST_EVALUATION.md concludes it earns no perf niche over C++ |
source build, not recommended |
| MATLAB | Original 2017 implementation, archived & unmaintained | src/@CHILmesh/CHILmesh.m |
import chilmesh
chilmesh.backend_info()
# After a source build of the C++ extension:
# {'available': ['cpp', 'python'],
# 'selected': 'cpp',
# 'versions': {'cpp': '0.6.0.dev0', 'python': '1.2.2'}}PyPI installs are pure-Python. The example above reflects a source build of the C++ extension. A plain
pip install chilmeshfrom PyPI currently ships no compiled extension, sobackend_info()reports{'available': ['python'], 'selected': 'python'}(#229). Build from source (pip install ./src/chilmesh_cpp) for the C++ path until pre-built binary wheels land.
How the backend is chosen. When CHILMESH_BACKEND is unset, CHILmesh auto-selects the fastest available backend, in order C++ → Rust → Python — so a build that has only the Rust extension will use Rust over Python automatically. Force one with CHILMESH_BACKEND=python|cpp|rust, and check what's active with chilmesh.backend_info().
Opt-in reality — both compiled backends are source builds. Neither C++ nor Rust ships in the PyPI wheel, and Rust is not a lighter-weight opt-in than C++: C++ needs a C++ toolchain + CMake (pip install ./src/chilmesh_cpp), Rust needs a Rust toolchain (maturin build …). Until pre-built binary wheels land (#229), a plain pip install chilmesh runs pure-Python everywhere. If you build one, build C++ — it is the recommended accelerator (~5× faster than Rust on full init, bit-identical output); the Rust backend is frozen (kept and output-equivalent, but not developed further — docs/RUST_EVALUATION.md explains why it earns no niche over C++ and should not replace Python). The path to making C++ the zero-opt-in default is prebuilt binary wheels (docs/dev/PREBUILT_WHEELS_PLAN.md, #229), not switching languages. The cpp↔python bit-identity guarantee is gated in CI by the cpp-equivalence job and Rust output-parity by the rust-equivalence job, both of which build the extension and run tests/test_backend_equivalence.py. Pre-built binary wheels (manylinux / macOS / Windows) via cibuildwheel are planned — see docs/ for build-from-source instructions.
CHILmesh is a graph over the mesh — seven adjacency tables (built once) back O(1) edge lookup, O(n log n) adjacency build, O(n) peel, and O(log n) spatial queries. The C++ half-edge backend reproduces them bit-for-bit. Full table + complexities: docs/ARCHITECTURE.md.
python examples/01_quickstart.py # load, stats, plot
python examples/02_fort14_roundtrip.py # fort.14 read/write
python examples/03_smoothing.py # angle-based smoother
python examples/04_spatial_queries.py # find_element, radius search, k-nearestchilmesh info mesh.fort.14 # stats
chilmesh convert mesh.2dm mesh.fort.14 # format conversion
chilmesh smooth mesh.fort.14 -o out.fort.14 --method fem # smooth in-place
chilmesh plot mesh.fort.14 -o mesh.png --quality # renderAlso available as python -m chilmesh. Each subcommand has --help.
docs/API.md— full API referencedocs/BENCHMARK.md— benchmark methodology and raw datadocs/CONCEPTS.md— distance vs medial axis vs skeleton vs layers (definitions, algorithms, math, synonyms)tests/TESTING.md— test guide (pytest markers, local commands)examples/— runnable scripts (quickstart, fort.14 round-trip, smoothing, spatial queries)
CHILmesh originated in MATLAB as the data structure backing a layer-peel-driven indirect tri-to-quad conversion heuristic (Mattioli, OSU MSc Thesis, 2017)
@software{mattioli_chilmesh,
author = {Mattioli, Dominik O. and Kubatko, Ethan J.},
title = {{CHILmesh}: a fast 2D mesh library for triangular,
quadrilateral, and mixed-element grids},
year = {2026},
publisher = {Zenodo},
version = {1.2.2},
doi = {10.5281/zenodo.20263854},
url = {https://github.com/domattioli/CHILmesh}
}Thesis source (Mattioli, 2017). Read thesis (PDF)
@mastersthesis{mattioli2017quadmesh,
author = {Mattioli, Dominik O.},
title = {{QuADMESH+}: A Quadrangular ADvanced Mesh Generator
for Hydrodynamic Models},
school = {The Ohio State University},
year = {2017},
url = {http://rave.ohiolink.edu/etdc/view?acc_num=osu1500627779532088}
}Issues and PRs welcome at github.com/domattioli/CHILmesh. Run pytest -v before opening a PR — see tests/TESTING.md.
Noncommercial / research use only. Licensed under the PolyForm Noncommercial License 1.0.0 with an additional No-AI/ML-training restriction — see LICENSE and .claude/AI-USAGE.md. No commercial use and no use as AI/ML training data without a separate written license. Commercial or AI-training licenses: https://github.com/domattioli
