Skip to content

2-D fault zones reach the domain boundary: the ribbon outcrops (#549) - #552

Open
lmoresi wants to merge 3 commits into
developmentfrom
bugfix/fault-outcrop-2d
Open

2-D fault zones reach the domain boundary: the ribbon outcrops (#549)#552
lmoresi wants to merge 3 commits into
developmentfrom
bugfix/fault-outcrop-2d

Conversation

@lmoresi

@lmoresi lmoresi commented Aug 13, 2026

Copy link
Copy Markdown
Member

Closes #549 (the ribbon half; the fault_split contact side is a separate design decision, tracked there).

What this does

A 2-D fault zone specified past a domain wall now embeds, with its clipped edge on the wall. This is the 3-D outcrop machinery (#525/#526) brought one dimension down:

  • _occ_assembly_2d gains the box= clip of its 3-D twin — same specify-long contract (polylines may protrude; the assembly is intersected with the domain rectangle in OCC and snapped to exact wall values after meshing). cad_area is computed after the boolean, so the meshed-vs-CAD area gate holds unchanged.
  • _split_skin_band is now dimension-free: facets are triangles against wall planes in 3-D, edges against wall lines in 2-D. One wall only, as before.
  • The 2-D case is simpler than the 3-D one that ships, and the code says so: the clipped skin is still a closed loop (clipping puts part of the loop ON the wall, it does not open it), so _outcrop_chain_2d splits it into the band and an open interior chain; and the cap degenerates from a wall-annulus meshing problem to two straight wall segments. The outcrop fill is therefore one simply-connected polygon — the cavity ring with its wall span replaced by the interior chain (_outcrop_ring_splice) — with no separate cap fill at all.
  • The splice segments and the band are relabelled with exactly the labels the deleted wall span carried, full closures included, gated by an exact count — mirroring the 3-D cap relabel.

What still refuses

  • An interior ribbon whose cavity reaches the wall (the outcrop path must not widen the interior contract — tested).
  • A zone meeting more than one wall (box-edge outcrop bands are not built, matching the 3-D refusal).
  • A zone meeting one wall in more than one band (the 2-D face of the same corner problem).
  • Wall vertices become deletable only in the open wall's line, never at a domain corner.

Tests

Base

Branched from development with #541 (feature/fuse-zone) merged in, because #541 rewrites _occ_assembly_2d — the clip is written against the fuse-era code. Once #541 merges this PR's diff reduces to the outcrop work alone; it should land after #541.

Underworld development team with AI support from Claude Code

The 3-D outcrop machinery brought one dimension down. The ribbon assembly
is clipped to the domain box in OCC under the same specify-long contract
(polylines may run past the domain), skin edges left exactly in one wall
line become the outcrop band, and the carve opens onto that wall.

The 2-D case is simpler than the 3-D one that ships: the clipped skin is
still a closed loop, so the band splits it into band + open interior
chain, and the cap degenerates from a wall-annulus meshing problem to two
straight wall segments — the outcrop fill is one simply-connected polygon,
the cavity ring with its wall span replaced by the interior chain
(_outcrop_ring_splice). The splice segments and the band are relabelled
with what the deleted wall span carried, full closures included, gated by
an exact count.

Refusals keep their teeth: an interior ribbon whose cavity reaches the
wall still refuses, a zone meeting two walls refuses (box-edge outcrop
bands are not built, matching 3-D), and a ribbon meeting one wall in two
bands refuses. Wall vertices become deletable only in the open wall's
line, and never at a domain corner.

Tests: the band census with its interior-twin negative control, the P2
Poisson quadratic-exact oracle on the outcropped mesh, refusal coverage,
and np=2 parallel forms (band present, no top-wall edge left unlabelled,
refusals collective; also run at np=4).

Underworld development team with AI support from Claude Code
@lmoresi

lmoresi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

Adversarial review (self-review, posted per our convention). We went looking for ways this breaks; findings with evidence.

1. Exact-coordinate wall identity — inherited limitation, worth knowing. Band identification, the deletable-wall mask, and the splice all test X[:, axis] == value bitwise. On gmsh box meshes wall coordinates are exact and the assembly is snapped, so this holds; on a mesh whose wall has moved (free surface, MMPDE relaxation) the box min/max would be the extreme vertex only and the outcrop would refuse rather than misbehave. This is exact parity with the 3-D path — not new exposure — and the failure mode is a refusal, not a wrong mesh. The curved/deformed-wall generalisation is #555.

2. Chain orientation at the splice. The chain is oriented by comparing its two end t-coordinates against the left corner. Ambiguity would need the two ends equidistant from the corner, which requires them coincident — excluded because both ends lie strictly inside the corner interval and are distinct band endpoints. No tiebreak needed.

3. Labels on ghost copies after the target-rank relabel. The relabel runs on the surgery rank only. This is safe for the same reason the skin labelling is: the gathered region is rank-interior (the shared-point check refuses otherwise), so every point the relabel touches exists only on the target rank. Evidence: the np=2 and np=4 runs assert no owned top-wall edge is missing its label, and pass.

4. A wall span deleted beyond the band. Wall vertices outside the band interval but within carve reach are deleted and their span is replaced by the straight splice segments — geometry preserved exactly because the wall is straight (finding 1's restriction is load-bearing here). The relabel count gate (2 + n_band edges, exact) would catch a splice that lost an edge.

5. What we could not break in testing: the interior contract (18 serial tests incl. the pre-existing 14, unchanged), area conservation (bitwise gate to 1e-9 relative, exercised in every test), the fill's verbatim-segment gates (any subdivision of a splice segment would refuse), and the three refusals each assert their message.

6. One deliberate asymmetry. place_thin_volume's 3-D path refuses a second wall via _split_skin_band only; the 2-D path additionally refuses a second wall contact by the cavity away from the band ("the carve reached the domain wall in two separate spans"). The 3-D carve handles that case by opening the bowl on the single wall; in 2-D the equivalent would keep old wall edges of dropped cells alive through the rebuild, whose label survival we did not want to assert without a test. Refusal is the conservative choice; the message names clearance as the lever.

Underworld development team with AI support from Claude Code

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

Enables 2‑D place_thin_volume “ribbon” fault zones to legally reach (and outcrop on) a domain boundary by clipping the OCC assembly to the domain box and wiring the outcrop/band machinery that already exists for 3‑D. The PR also generalizes band extraction logic across dimensions and adds an assembly={"fuse","fragment"} option (default "fuse") to avoid sliver‑seam meshes in tangential overlaps.

Changes:

  • Add specify‑long (box‑clipped) OCC assembly support for 2‑D ribbons and implement 2‑D outcrop handling (band identification, ring splice, explicit wall relabel).
  • Generalize _split_skin_band to work for both 3‑D (triangles) and 2‑D (edges), and add assembly boolean selection ("fuse" default) in both 2‑D and 3‑D assembly paths.
  • Add serial + parallel tests for 2‑D outcropping ribbons and for the "fuse" vs "fragment" sliver negative control; update developer docs and add a design note.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/underworld3/utilities/place_surface.py Adds 2‑D assembly clipping and outcrop/band plumbing; makes band split dimension‑free; introduces assembly={"fuse","fragment"} handling.
tests/test_0855_place_thin_volume.py Adds regression tests for tangential merge slivering (fuse vs fragment) and for 2‑D outcropping ribbon embedding + oracle solve.
tests/parallel/ptest_0855_place_thin_volume_parallel.py Adds np≥2 coverage for 2‑D outcrop embedding and collective refusal behavior.
docs/developer/subsystems/conforming-surfaces-and-fault-zones.md Documents the new assembly behavior and rationale (seams vs slivers).
docs/developer/index.md Registers the new design note in the developer docs toctree.
docs/developer/design/fault-zone-hybrid-architecture.md Adds a design note describing a hybrid zone/contact approach and records measured motivation for fused assemblies.

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

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