Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
f1b3753
feat(fort14_io): add table-only read mode; tolerate float vertex tokens
domattioli Jul 10, 2026
04425d4
fix(fort14_io): tolerate float-formatted node/element/header ids
domattioli Jul 10, 2026
87ead23
chore: refresh DomI pin → cfa7f02
domattioli Jul 10, 2026
d6e56a1
fix(smooth_mesh): forward **kwargs so smoother options reach smoother…
domattioli Jul 10, 2026
0a2c11a
fix(fort14_io): tolerate prose-annotated NOPE/NBOU headers + truncate…
domattioli Jul 10, 2026
c1923d1
feat(geometry): CRS-aware edge length + haversine great-circle distan…
domattioli Jul 10, 2026
90f3e1b
feat(geometry): convex hull, bbox IoU, antimeridian split, Hausdorff …
domattioli Jul 10, 2026
33ae4db
feat(quality): CFL / Courant number gate for hydrodynamic meshes (#238)
domattioli Jul 10, 2026
fce31f1
refactor: ratify #187 layer lexicon — verb=peel, noun=layer, skeleton…
domattioli Jul 10, 2026
9ec7bd8
chore: prep v2.0.0 release — changelog, version bumps, README lexicon…
domattioli Jul 10, 2026
3ef3de4
docs: regenerate README hero GIF — peel_layers open/close + interpola…
domattioli Jul 10, 2026
26ee59f
feat(hero): real solver playback — history capture hook + seed/truss/…
domattioli Jul 10, 2026
b4cfca1
fix(hero): render GIF at dpi 72 (864px) — 6.7MB → 3.8MB so GitHub REA…
domattioli Jul 10, 2026
c4fa8a5
docs: add spec 002-hero-gif-refinement — README hero GIF rework (paci…
domattioli Jul 10, 2026
3f177c5
docs: resolve spec 002 clarifications — solver-side culling, convert-…
domattioli Jul 10, 2026
debcd26
docs: spec 002 plan artifacts — probe-verified design (solver snapsho…
domattioli Jul 10, 2026
f9a849c
docs: spec 002 tasks — 25-task breakdown by user story (TDD solver ch…
domattioli Jul 10, 2026
d35308b
docs: spec 002 visual-quality checklist — 35-item pre-merge gate
domattioli Jul 10, 2026
f9016d0
docs: spec 002 analyze cycle-1 fixes — peel metrics wiring, hist[-1] …
domattioli Jul 10, 2026
1b5d97b
docs: spec 002 analyze cycle-2 residuals — symmetric k=0 audit, P_tru…
domattioli Jul 10, 2026
c2fb2ab
feat(fort15_io): opt-in deep parse of leading scalar block (#249)
domattioli Jul 11, 2026
f5cd3c6
test: drift-proof version-string assertion
domattioli Jul 11, 2026
cc34234
feat(node_match): cross-mesh node matching + nodal-field deltas (#239)
domattioli Jul 11, 2026
3a9c3ef
feat(summary): lazy header read for fort.13 + fort.15 (#201)
domattioli Jul 11, 2026
af19025
feat(summary): lazy header read for .npy + .npz (#201)
domattioli Jul 11, 2026
8a47533
feat: additive snapshot_retriangulate kwargs on distmesh2d_warmstart …
domattioli Jul 11, 2026
391f865
feat: hero GIF rework — equal-motion pacing, peel layer reveal w/ sta…
domattioli Jul 11, 2026
6aaa2b3
docs: regenerate README hero GIF — 2.2MB, 265 logical frames, all SC …
domattioli Jul 11, 2026
45aa9d0
test: close T015 gap — k=0 pixel-equality leg in peel-invariance audi…
domattioli Jul 11, 2026
1c90aed
feat: freeze final hero peel frame for 5s (operator request)
domattioli Jul 11, 2026
f632fff
docs: regenerate hero GIF with 5s final freeze
domattioli Jul 11, 2026
9e6ca8e
chore: spec 002 pipeline complete — implement phase succeeded
domattioli Jul 11, 2026
df21dd2
feat: add gmsh .msh support to summary() lazy reader (#201)
domattioli Jul 12, 2026
e6afccd
feat: summary() generic fort.NNN fallback — closes last mesh_read_gua…
domattioli Jul 12, 2026
0f6f1c0
fix: lazy-load heavy surface so fort.14 import stays stdlib-only (#255)
domattioli Jul 13, 2026
d8f7a25
chore: adopt DomI release-ignore canon (generated ignore blocks)
domattioli Jul 14, 2026
bde4a1e
docs: measure Rust backend vs C++/Python, fill tbd perf, record recom…
domattioli Jul 14, 2026
8efeee6
fix: cache Vert2Edge in Rust backend so get_vertex_edges is O(1)
domattioli Jul 14, 2026
5f77347
docs: reflect O(1) query fix + surface backend selection/opt-in to co…
domattioli Jul 14, 2026
4672141
docs: freeze Rust backend + add prebuilt C++ wheels plan
domattioli Jul 14, 2026
d4583d2
docs: add ready-to-apply snippets appendix to prebuilt C++ wheels plan
domattioli Jul 14, 2026
abf8104
docs: apply peel lexicon + document why Rust frozen (data-structure d…
domattioli Jul 14, 2026
5d70a60
chore: prep 2.0.1 release (version bump, changelog, citation)
domattioli Jul 14, 2026
5aa7f4e
chore: correct release version to 1.4.1 (last published was 1.4.0, no…
domattioli Jul 14, 2026
f1444b6
Merge origin/main into development — reconcile 1.4.x release metadata…
domattioli Jul 14, 2026
769bcdc
docs: refresh README roadmap — Now=publish C++ wheels (#256), Next=.c…
domattioli Jul 14, 2026
9735003
docs: add brief MATLAB→Python bridge note (py. gives the C++ backend,…
domattioli Jul 14, 2026
2bfb838
docs: unify Zenodo DOI to 21199161 + clickable Citation badges
domattioli Jul 14, 2026
309d48a
chore: sync DomI@bf09fb5 (from cfa7f02)
domattioli Jul 14, 2026
a54f88d
docs: replace stale '57 tests' with 'the full pytest suite' (#247)
domattioli Jul 14, 2026
adbcbb8
chore: sync DomI@c430fc2 (from bf09fb5)
domattioli Jul 15, 2026
db6f290
test: add .grd summary reroute-target regression guard (#201)
domattioli Jul 16, 2026
183652f
fix: quad min_angle/max_angle use raw interior angles, not triangle-s…
domattioli Jul 18, 2026
11e2a49
fix: expose fort.14 boundary-section presence, empty != absent (#259)
domattioli Jul 19, 2026
a4de4dd
docs: set primary-author affiliation to Unaffiliated per operator (#247)
domattioli Jul 20, 2026
7768cb4
docs: add v1.4.0 #187 breaking-rename migration section (#257)
domattioli Jul 21, 2026
65c2236
docs: fill Rust ENPAC2003 benchmark cells, mesh now in-environment (#…
domattioli Jul 23, 2026
f97104e
docs: spec option-1 medial rule for skeletonize(), flag CONCEPTS.md c…
domattioli Jul 24, 2026
811110f
test: run real full_init smoke in cpp-wheel CI, replace hasattr probe…
domattioli Jul 25, 2026
75cf769
ci: add release-gated publish-cpp-wheels.yml (#256 Phase 2)
domattioli Jul 26, 2026
2b850ed
docs: research.md for mesh cartograms grounded in current API (#219)
domattioli Jul 26, 2026
34e8296
docs: mark .planning/project_plan.md stale, point to README live stat…
domattioli Jul 27, 2026
82881d3
chore: gmsh reader validation helper + drop hardcoded /tmp paths in s…
domattioli Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Edge2Elem: ndarray[n_edges, 2] # Edge adjacent elements (-1 if boundary)
- ✅ Skeletonization algorithm behavior
- ✅ Public method signatures
- ✅ Mixed-element (tri + quad) support
- ✅ Test pass rate (currently 57 tests)
- ✅ Test pass rate (the full pytest suite)

### Must Improve
- 🚀 O(n²) edge building → O(n log n) or O(n)
Expand Down
6 changes: 3 additions & 3 deletions .domi-pin
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

upstream: domattioli/DomI
branch: main
sha: cfa7f02a4661ed0db8cce9eee7cf3c93b4f0e863
manifest_sha256: 124153ce0aa71c06ee4836c51488d067032327312c36be5451ad6b0e02af7341
pinned_at: 2026-07-10T15:13:24Z
sha: c430fc2d3711e70934d32578a90eb6fc409fdb71
manifest_sha256: 48c018894b19176816e9d0fb66a62cf5862f401ed575ba83167a66f8b8324094
pinned_at: 2026-07-15T14:12:54Z
30 changes: 22 additions & 8 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
# Exclude Claude/agent + dev-process files from source archives
# (git archive, PyPI sdist, GitHub release tarball, Zenodo snapshot).
# Strictly library-running code ships downstream; these stay in the repo.
.claude/ export-ignore
CLAUDE.md export-ignore
AGENTS.md export-ignore
.specify/ export-ignore
.planning/ export-ignore
specs/ export-ignore
docs/sessions/ export-ignore

# >>> release-ignore:begin (generated by DomI release-integrity — do not edit inside; edit .release-ignore.toml + regenerate)
.claude/ export-ignore
.claude-plugin/ export-ignore
.introspect/ export-ignore
.githooks/ export-ignore
.specify/ export-ignore
.planning/ export-ignore
.domi-pin export-ignore
.zenodoignore export-ignore
.release-ignore.toml export-ignore
CLAUDE.md export-ignore
AGENTS.md export-ignore
claude_routine_instructions.md export-ignore
instructions_on_start.sh export-ignore
scripts/hooks/ export-ignore
docs/sessions/ export-ignore
docs/introspections/ export-ignore
.domi-pin export-ignore
specs/ export-ignore
*introspect*.yml export-ignore
.github/ export-ignore
docs/LEXICON_PROPOSAL.md export-ignore
# <<< release-ignore:end
1 change: 1 addition & 0 deletions .github/workflows/LOCAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ workflows fail the workflow-conformance gate.
| `python-package.yml` | full cross-OS test matrix incl. macOS lanes (main-push gated) — macOS gating is repo-local by design (spec-010 v2.2 rule 8) |
| `publish-pypi.yml` | PyPI release, tag-triggered — repo-specific release pipeline |
| `build-cpp-wheels.yml` | build-only manylinux wheel validation for the chilmesh_cpp binary backend (workflow_dispatch, artifacts only, no publish) — repo-specific packaging (#229) |
| `publish-cpp-wheels.yml` | release/dispatch-gated PyPI publish of chilmesh_cpp wheels + sdist (no push trigger; `environment: pypi` protected; Trusted Publishing/OIDC) — repo-specific packaging (#256 Phase 2) |
23 changes: 21 additions & 2 deletions .github/workflows/build-cpp-wheels.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
name: build-cpp-wheels

# Build-only validation of the chilmesh_cpp binary (manylinux) wheels.
# Build + functional-smoke validation of the chilmesh_cpp binary (manylinux) wheels.
# Manual dispatch; uploads wheels as artifacts ONLY — does NOT publish to PyPI.
# The cibuildwheel test step RUNS full_init on a tiny mesh (not just a hasattr
# probe) so a broken/empty binary fails the build (#256 Phase 1a).
# Linux manylinux runs on the free ubuntu runner (not gated by the macOS/Windows
# runner-billing question in #225), so the binary path can be validated in the
# real manylinux container before any publish job is wired up. Refs #229, #163, #234.
Expand Down Expand Up @@ -31,7 +33,24 @@ jobs:
CIBW_BUILD: "cp310-* cp311-* cp312-*"
CIBW_ARCHS_LINUX: "x86_64"
CIBW_SKIP: "*-musllinux*"
CIBW_TEST_COMMAND: "python -c \"import chilmesh_cpp; assert hasattr(chilmesh_cpp, 'full_init'), 'cpp extension missing full_init'\""
CIBW_TEST_REQUIRES: "numpy"
# Real functional smoke (#256 Phase 1a): actually RUN full_init on a
# 2-triangle unit square and assert the built adjacency + skeleton, not
# just that the symbol exists. Topology invariants: 4 verts, 2 elems,
# 5 unique edges (4 boundary + 1 shared diagonal), adjacency built,
# >=1 peel layer, edge2vert shape (5, 2).
CIBW_TEST_COMMAND: >-
python -c "import numpy as np, chilmesh_cpp;
pts = np.array([[0.,0.],[1.,0.],[1.,1.],[0.,1.]], dtype=np.float64);
conn = np.array([[0,1,2],[0,2,3]], dtype=np.int32);
m = chilmesh_cpp.full_init(pts, conn);
assert m.n_verts == 4, m.n_verts;
assert m.n_elems == 2, m.n_elems;
assert m.n_edges == 5, m.n_edges;
assert m.adjacency_built, 'adjacency not built';
assert m.n_layers >= 1, m.n_layers;
assert np.asarray(m.edge2vert).shape == (5, 2), np.asarray(m.edge2vert).shape;
print('chilmesh_cpp full_init smoke OK:', m.n_verts, 'v', m.n_elems, 'e', m.n_edges, 'edges', m.n_layers, 'layers')"
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
Expand Down
104 changes: 104 additions & 0 deletions .github/workflows/publish-cpp-wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: publish-cpp-wheels

# Release/tag-gated PyPI publish of the chilmesh_cpp binary wheels + sdist (#256 Phase 2).
#
# Triggers ONLY on a published GitHub release or a deliberate manual dispatch —
# there is NO push trigger, so nothing publishes from `development`. The build
# leg reuses the manylinux cibuildwheel path validated in build-cpp-wheels.yml
# (Phase 1a). macOS/Windows legs are intentionally absent here: they are Phase 1b,
# gated on the runner-billing decision in #225 — add them to the build matrix
# below once #225 resolves.
#
# Auth: PyPI Trusted Publishing (OIDC, id-token: write) is preferred (no
# long-lived token). A token fallback mirroring publish-pypi.yml is shown as a
# commented alternative on the publish step. Refs #256, #229, #225, #163, #234.

on:
release:
types: [published]
workflow_dispatch:

permissions:
contents: read

jobs:
build-manylinux:
name: cibuildwheel chilmesh_cpp (manylinux x86_64)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.12"
cache: pip
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.21.3
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse src/chilmesh_cpp
env:
CIBW_BUILD: "cp310-* cp311-* cp312-*"
CIBW_ARCHS_LINUX: "x86_64"
CIBW_SKIP: "*-musllinux*"
CIBW_TEST_REQUIRES: "numpy"
# Same functional smoke as build-cpp-wheels.yml: run full_init on a
# 2-triangle unit square and assert adjacency + skeleton so a broken
# binary cannot be published.
CIBW_TEST_COMMAND: >-
python -c "import numpy as np, chilmesh_cpp;
pts = np.array([[0.,0.],[1.,0.],[1.,1.],[0.,1.]], dtype=np.float64);
conn = np.array([[0,1,2],[0,2,3]], dtype=np.int32);
m = chilmesh_cpp.full_init(pts, conn);
assert m.n_verts == 4, m.n_verts;
assert m.n_elems == 2, m.n_elems;
assert m.n_edges == 5, m.n_edges;
assert m.adjacency_built, 'adjacency not built';
assert m.n_layers >= 1, m.n_layers;
assert np.asarray(m.edge2vert).shape == (5, 2), np.asarray(m.edge2vert).shape;
print('chilmesh_cpp full_init smoke OK:', m.n_verts, 'v', m.n_elems, 'e', m.n_edges, 'edges', m.n_layers, 'layers')"
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: chilmesh-cpp-manylinux-wheels
path: wheelhouse/*.whl
if-no-files-found: error

sdist:
name: build chilmesh_cpp sdist
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v5
- name: Build sdist
run: pipx run build --sdist --outdir dist src/chilmesh_cpp
- name: Upload sdist
uses: actions/upload-artifact@v4
with:
name: chilmesh-cpp-sdist
path: dist/*.tar.gz
if-no-files-found: error

publish:
name: publish chilmesh_cpp to PyPI
needs: [build-manylinux, sdist]
runs-on: ubuntu-latest
timeout-minutes: 15
# Protect with required reviewers in repo settings (Settings → Environments → pypi).
environment: pypi
permissions:
id-token: write # PyPI Trusted Publishing (OIDC) — no long-lived secret
steps:
- name: Download all wheel + sdist artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
# Token fallback — if PyPI Trusted Publishing is NOT configured for
# chilmesh-cpp, drop the `id-token: write` permission above and uncomment:
# with:
# password: ${{ secrets.PYPI_API_TOKEN }}
with:
packages-dir: dist
skip-existing: true
9 changes: 9 additions & 0 deletions .planning/008-DECISION.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
**Date:** 2026-05-22
**Status:** FINAL (pending benchmark data)

> **UPDATE 2026-07-14 — superseded outcome.** The Rust/quad-edge port described
> here was built (`src/chilmesh_core`) and has since been measured and **FROZEN**:
> it is output-equivalent to Python but ~2–5× slower than the C++ backend on full
> init, with no performance niche over it. The "pending benchmark data" is now
> filled — see [`docs/RUST_EVALUATION.md`](../docs/RUST_EVALUATION.md) and
> `src/chilmesh_core/STATUS.md`. C++ is the acceleration path; the forward plan is
> prebuilt C++ wheels ([`docs/dev/PREBUILT_WHEELS_PLAN.md`](../docs/dev/PREBUILT_WHEELS_PLAN.md)),
> not further Rust work. This decision record is retained as history.

---

## Executive Summary
Expand Down
8 changes: 8 additions & 0 deletions .planning/codebase/CONCERNS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

**Analysis Date:** 2026-05-21

> **UPDATE 2026-07-14.** The "Rust/C++ extension" optimization opportunity below
> has been resolved: the **C++** half-edge backend is built, bit-identical, and is
> the acceleration path (~5× faster than the Rust port). The **Rust** extension was
> also built, measured, and is now **FROZEN** (no perf niche over C++) — see
> [`docs/RUST_EVALUATION.md`](../../docs/RUST_EVALUATION.md). The remaining lever is
> distribution (prebuilt C++ wheels), not a new language port:
> [`docs/dev/PREBUILT_WHEELS_PLAN.md`](../../docs/dev/PREBUILT_WHEELS_PLAN.md).

## Language & Performance Optimization Opportunities

### 1. Skeletonization Bottleneck (Medium Priority)
Expand Down
5 changes: 5 additions & 0 deletions .planning/project_plan.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHILmesh Project Plan & Roadmap

> ⚠️ **STALE — historical, not the live roadmap (banner added 2026-07-27).**
> This document describes the 2026-04-26 `v0.1.1 → v0.2.0` plan. The repo is now **v1.4.1** (stable; C++/Rust half-edge backends, full mutation API `#94`, fort.14/.2dm/fort.13 I/O, lazy `summary()`). The "You are here" / Phase-0 markers below are ~15 months out of date.
> **Live status & roadmap → [README §Status & Roadmap](../README.md#status--roadmap).**
> Disposition (retire this file vs. refresh it) is an open operator decision — see [#261](https://github.com/domattioli/CHILmesh/issues/261). Banner added pending that call; the content below is preserved unmodified as a historical record.

**Current Version:** 0.1.1 (Alpha)
**Planning Date:** 2026-04-26
**Horizon:** 12 months (through Q1 2027)
Expand Down
10 changes: 10 additions & 0 deletions .release-ignore.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Repo-local extension of DomI's canonical release-ignore baseline
# (DomI skills/release-integrity/policy/release-ignore.toml). Additive only.
# Regenerate channel files: python release_ignore.py generate (release-integrity skill).

[extend]
# docs/BENCHMARK.md and other computational docs ship (operator ruling
# 2026-07-14); only AI dev-workflow material is excluded.
exclude = [
"docs/LEXICON_PROPOSAL.md",
]
Loading