Skip to content

Outcropping zones: the fault zone leaves its band on the surface - #526

Merged
lmoresi merged 2 commits into
developmentfrom
feature/zone-outcrop-band
Aug 11, 2026
Merged

Outcropping zones: the fault zone leaves its band on the surface#526
lmoresi merged 2 commits into
developmentfrom
feature/zone-outcrop-band

Conversation

@lmoresi

@lmoresi lmoresi commented Aug 11, 2026

Copy link
Copy Markdown
Member

Completes the outcrop implementation (with #525): the thin-volume form. A fault ZONE specified past the box is clipped in OCC; its clipped face becomes the BAND on the surface; the gap's boundary is one closed surface of three discrete pieces (interior shell + cap-annulus with the band outline as its hole, pre-meshed by the 2-D fill + interior skin, rim-matched). Band faces carry BOTH the zone's skin label and the wall's labels; the cap annulus is relabelled explicitly with full closures, counts gated.

Measured serial and np=2,4: identical zone counts, P2 FE-exactness (5e-11–7e-11) with Dirichlet gripping the remeshed Top, full Top-label coverage face-by-face. Interior zones byte-for-byte unaffected — suites 0853–0856 (45 serial) and the placement ptests green. Band contract test in test_0855.

Stated residuals (refuse with reasons): box-edge bands / multi-wall contact; curved or deformed tops (the manifold-prep slot); removal of an OUTCROPPING object (its cavity legitimately touches the wall — the removal carve does not yet take open_wall; next small instalment if needed).

Underworld development team with AI support from Claude Code

The thin-volume form of the outcrop, completing "get all the
implementation done". The assembly is clipped against the domain box in
OCC (specify-long: patches may protrude; clipped faces snap exactly onto
the wall plane), and a clipped face left in ONE wall plane becomes the
zone's BAND. The gap's boundary is then ONE closed surface of three
discrete pieces — the interior shell, the pre-meshed CAP (an annulus in
the wall plane: rim ring verbatim, the band outline as its HOLE, via the
2-D fill), and the interior part of the skin, rim-matched to the cap's
hole. The band's triangles become boundary faces carrying BOTH the zone's
skin label and the wall's own labels; the cap's annulus is relabelled the
same way, full closures, counts gated.

The volume carve gains open_wall (victims may lie in the open wall's
plane; the shell may open there via the shared _closed_shell_3d);
box-edge bands and multi-wall contact refuse with the reason.

Measured serial and np=2,4: identical zone counts, P2 quadratic FE-exact
(5e-11..7e-11) with Dirichlet gripping the remeshed Top, full Top
coverage. Interior zones unchanged: suites 0853-0856 (45 serial) and the
placement ptests green. Band contract test added to test_0855.

Underworld development team with AI support from Claude Code
Copilot AI lite review requested due to automatic review settings August 11, 2026 12:04
@lmoresi

lmoresi commented Aug 11, 2026

Copy link
Copy Markdown
Member Author

Adversarial review (self, posted per project practice):

The three-piece boundary is the risk we attacked. The gap's closed surface is assembled from three independently produced triangulations sharing nodes only by tag identity: shell↔cap at the wall rim, cap↔skin at the band outline. Every sharing is gated — moved-nodes zero across all constrained sets, cap/skin triangle counts refused if remeshed, and every band and cap face recovered by join with the relabel count compared against the expectation. The FE oracle with Dirichlet on the remeshed Top then closes over the whole chain: a single mis-sewn edge or unlabelled patch cannot reproduce the quadratic.

A subtlety we verified rather than assumed: OCC's clipped faces land within rounding of the wall plane, not on it; the band logic keys on EXACT plane values, so assembly nodes within 1e-9 snap onto the plane before anything reads them. Without the snap the band detection silently returns empty and the placement refuses at the wall — loud, but wrong.

Stated residuals: removal of an outcropping object is the one asymmetry left (the removal carve does not yet pass open_wall — a spent outcropping fault currently refuses removal rather than clearing its band); box-edge bands and curved tops refuse with reasons as before.

Underworld development team with AI support from Claude Code

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

Completes the “outcropping zones” path for place_thin_volume() by clipping the OCC-built zone assembly to the domain box and treating the clipped wall-face as a surface “band”, including explicit wall relabelling and a contract test that validates the full chain via a P2 Poisson exactness oracle.

Changes:

  • Extend _occ_assembly_3d() to optionally intersect the assembly solids with the domain box (“specify-long”) and snap clipped faces to exact wall-plane coordinates.
  • Add band/cap plumbing for outcropping thin volumes: split skin into interior vs band, allow the carve to open onto one wall, pre-mesh a cap annulus with a hole matching the band outline, and explicitly relabel new wall faces with the replaced wall-label closures.
  • Add test_an_outcropping_zone_leaves_a_band_on_the_surface() to assert band existence/labels and FE exactness after outcrop remeshing.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/underworld3/utilities/place_surface.py Implements outcropping-zone “band on wall” handling: box-clipped OCC assembly, band extraction, open-wall carve, cap-annulus gap fill, and explicit relabelling gates.
tests/test_0855_place_thin_volume.py Adds a contract test covering the outcropping zone band + relabel + P2 exactness check chain.

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

Comment on lines +4185 to +4199
if wall_code is not None:
axis, side = wall_code // 2, wall_code % 2
open_wall = (int(axis),
float(box_hi[axis] if side else box_lo[axis]))
from collections import Counter as _Counter
band_edge = _Counter()
for t in skin_tris[band_idx]:
a, b, c = sorted(int(v) for v in t)
for e in ((a, b), (a, c), (b, c)):
band_edge[e] += 1
band_outline = _single_loop(
[e for e, k in band_edge.items() if k == 1],
"zone's outcrop band outline")
skin_tris_fill = (skin_tris[interior_idx] if open_wall is not None
else skin_tris)
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