Skip to content

place_sheet: the 3-D placed surface (serial), with a gated gmsh cavity fill - #517

Merged
lmoresi merged 1 commit into
developmentfrom
feature/mesh-surgery-3d
Aug 9, 2026
Merged

place_sheet: the 3-D placed surface (serial), with a gated gmsh cavity fill#517
lmoresi merged 1 commit into
developmentfrom
feature/mesh-surgery-3d

Conversation

@lmoresi

@lmoresi lmoresi commented Aug 9, 2026

Copy link
Copy Markdown
Member

The 3-D single-cut surface on an existing mesh — the capability the fault streams were waiting on. A triangulated sheet's points become mesh vertices and every sheet triangle a labelled interior face, with the rim free inside the mesh: the case a cut cannot represent and a two-sub-volume construction cannot fake.

Mechanism

Carve (clearance + crossed tets, every victim's whole star), fill, sew on a compacted vertex set, carry every label topologically (vertex numbering through the rebuild is defined, so faces and edges transfer by vertex tuple — coordinates are never consulted). The fill is delegated to gmsh — a cavity shell has no total order to walk, and constrained tetrahedralisation with Steiner insertion is what a mesh generator is for — and gated, not trusted: both constraint surfaces bit-identical, every sheet triangle an interior face, conformity / Euler / degeneracy / wall-label preservation checked per call.

Measured basis: sheet_cavity_spike.py (study dir), 6/6 across tilt, resolution, clearance and sub-h sheet spacing — gmsh inserting its own Steiner points without touching either constraint, which retires the plan's constrained-tetrahedralisation STOP-gate.

Guards, ported from the 2-D lessons

Cells owning an interior labelled face are held out of the cavity; a sheet needing them is refused; every earlier surface's interior-face count is re-read off the result mesh (a partial corruption satisfies any identity summed over per-placement bookkeeping — learned the hard way in 2-D).

Scope

Serial by design: the parallel route is gather-first (redistribute so the sheet's star is rank-interior — the contact stream's measured policy — then this operation is the rank-local step, and no placed point is ever shared). reconnect.py untouched; the chart-surgery generalisation belongs to the parallel stage. Test number 0854 claimed in the coordination ledger.

Handoff

The deliverable contract for split_along_label_3d (fault-split-node): a labelled facet patch — every sheet triangle a face under one (name, value), interior with two cells, an open manifold with single rim edges — asserted as test_0854 (5 tests). Full surgery regression: 77 tests green (0844 x2, 0853, 0854); style gate clean.

Underworld development team with AI support from Claude Code

The 3-D form of the placed surface. The sheet's points become mesh vertices
and every sheet triangle becomes a labelled interior face, with the rim free
inside the mesh - the case a cut cannot represent and a two-sub-volume trick
cannot fake. Carve (clearance plus crossed tets, every victim's star), fill,
sew (createFromCellList on a compacted vertex set), and carry every label
topologically: vertex numbering through the rebuild is DEFINED, so faces and
edges transfer by vertex tuple and coordinates are never consulted.

The fill is delegated to gmsh and GATED, not trusted: the cavity shell and
the sheet must come through bit-identical, every sheet triangle must be an
interior face of the sewn mesh, and conformity, Euler number, degeneracy and
the wall labels are checked on every call. Measured basis: the cavity spike,
6/6 across tilt, resolution, clearance and sub-h sheet spacing - including
gmsh inserting its own Steiner points without touching either constraint,
which retires the plan's constrained-tetrahedralisation STOP gate.

The 2-D guards are ported, faces standing where edges stood: cells owning an
interior labelled face are held out of the cavity, a sheet needing them is
refused, and every earlier surface's interior-face count is re-read off the
RESULT mesh - the lesson that a partial corruption satisfies any identity
summed over per-placement bookkeeping.

Serial by design: the parallel route is gather-first (redistribute so the
sheet's star is rank-interior, place locally, renumber), after which this
serial operation is the rank-local step and no placed point is ever shared.
reconnect.py is untouched; the chart-surgery generalisation belongs to that
stage.

Deliverable contract for the fault module: a labelled facet patch - every
sheet triangle a face under one (name, value), interior with two cells,
an open manifold with its rim edges single - asserted as test_0854.

Underworld development team with AI support from Claude Code
Copilot AI lite review requested due to automatic review settings August 9, 2026 21:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new 3‑D “placed surface” capability (place_sheet) that embeds a triangulated sheet into an existing 3‑D simplex mesh by carving a cavity, delegating the cavity fill to gmsh, and then sewing the result back while preserving labels topologically. It also adds a dedicated regression test suite establishing the contract expected by downstream fault-splitting functionality.

Changes:

  • Add place_sheet() and supporting 3‑D cavity-carve / gmsh-fill / sew / label-transfer helpers to underworld3.utilities.place_surface.
  • Add test_0854_place_sheet.py to assert the 3‑D placed-sheet contract (interior labelled faces, open-manifold rim, label preservation, and dimension-dispatch guards).
  • Expand module “Scope” documentation in place_surface.py to reflect 3‑D support and the gated gmsh fill approach.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/underworld3/utilities/place_surface.py Implements 3‑D sheet placement with gated gmsh cavity fill, sewing, and topological label transfer.
tests/test_0854_place_sheet.py Adds contract/regression coverage for the new 3‑D place_sheet() behavior and key guards.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

def _interior_face_counts_3d(dm):
"""{(label, value): count of interior faces} — the breach detector."""
interface = _interface_faces_3d(dm)
fS, fE = dm.getHeightStratum(1)
Comment on lines +1535 to +1536
sheet_pts = np.asarray(points, dtype=float).reshape(-1, 3)
sheet_tris = np.asarray(triangles, dtype=np.int64).reshape(-1, 3)
Comment on lines +1577 to +1583
keep_cell = np.ones(len(cells), dtype=bool)
keep_cell[drop_ids] = False
keep_vertex = np.ones(len(X), dtype=bool)
keep_vertex[victims] = False
old_to_new = -np.ones(len(X), dtype=np.int64)
old_to_new[keep_vertex] = np.arange(int(keep_vertex.sum()))
n_survivors = int(keep_vertex.sum())

@lmoresi lmoresi left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review (authoring session).

Where we attacked it: (1) The fill's trust boundary — gmsh output is gated per call (constraint surfaces bit-identical, sheet triangles all interior faces, conformity/Euler/degeneracy/wall counts); the inert-DB-write and misattributed-crash lessons from #515/#510 are why nothing here trusts a library return without reading the result back. (2) The silent-corruption class from 2-D — both cells of a labelled facet cleared while every corner is protected — is guarded with faces standing where edges stood, and the too-close-sheet test accepts either refusal path (held-cell or shell-manifold) while asserting the first sheet is intact afterwards, since which guard trips first is geometry-dependent. (3) Label transfer is topological (vertex tuples through a defined renumbering), never coordinate matching — the property the 2-D rebuilds were built on. (4) Serial-only refusal states the gather-first rationale so the parallel stage has its design recorded at the refusal site.

Known limits, stated rather than discovered later: one sheet per cavity (close pairs are one thin volume — the next work item); no cavity-growth retry loop in 3-D yet (a wedged fill raises with guidance rather than growing, unlike 2-D); test_0854 asserts the handoff contract shape only — the wire-up to split_along_label_3d runs on the fault branch, per the ledger.

Recommend merge (squash — single-purpose branch, no shared ancestry).

Underworld development team with AI support from Claude Code

@lmoresi
lmoresi merged commit 7174b6d into development Aug 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants