Skip to content

3D node redistribution: the MMPDE mover drives tetrahedral meshes (capstone round 2)#393

Merged
lmoresi merged 3 commits into
developmentfrom
feature/mmpde-3d
Jul 22, 2026
Merged

3D node redistribution: the MMPDE mover drives tetrahedral meshes (capstone round 2)#393
lmoresi merged 3 commits into
developmentfrom
feature/mmpde-3d

Conversation

@lmoresi

@lmoresi lmoresi commented Jul 22, 2026

Copy link
Copy Markdown
Member

What this adds

mesh.redistribute_nodes() — moving a mesh's nodes so cell sizes follow a metric, with the topology fixed — now works on 3D tetrahedral meshes, serial and parallel. This removes the second of the two issues the adaptivity "capstone" set out to retire (the first, 3D refinement, landed in #378). The user API does not change: the same call, the same metric forms (scalar density or full tensor), the same slip-surface options.

Why changes are considered minor

The mover's mathematics (the Huang–Kamenski variational method, reference [1]) was implemented dimension-generally from the start — the per-element algebra never assumed two dimensions. What kept 3D from working sat at the rim: the cell list, the signed cell measure, and the factorial volume factor were hard-wired for triangles, and the entry points refused anything else. Those now dispatch on dimension (a ten-line signed-volume routine is the only new numerics), and the guards state what is genuinely unsupported (quad/hex meshes, constrained manifolds).

Measured behaviour

  • Serial, on a box with a dipping-fault-plane metric: monotone energy descent, zero folded cells, boundary nodes held exactly on their faces under slip.
  • The grading reaches a ratio of 1.12 between far-field and on-fault cell size, against 1.30 for the identical problem in 2D. That compression is expected, not a defect: cell size follows the metric as its d-th root, so the same metric contrast that ideally gives 4x in 2D can only ever give 2.5x in 3D. Repeated calls hold a stable equilibrium rather than compounding — the same character as 2D, and the useful regime for the intended composition (mild base-grading with bisection refinement on top, the round-3 experiment).
  • Parallel at 1, 2, and 4 ranks: runs clean (exercising the reworked collective sync machinery from Callback-array parallel safety: central view/copy guard, honest exceptions, no dead snapshots (#379 items 3+4b) #381-Intercept out= ufunc writes: close the silent callback bypass (#379 item 4a) #385 in 3D), zero folds, boundary exact, and the near/far cell-size medians agree across partitions to within 2.5 percent — the documented few-percent equilibrium drift from the rank-local step cap, unchanged from 2D.
  • follow_metric runs end-to-end on 3D meshes (its shape-quality polish gained the tetrahedral formula).

Review

An independent adversarial review of the branch found no correctness defects (it verified the orientation-sign conventions of the fold guard against DMPlex's det-negative reference tets, the bit-identity of the 2D boundary mask, and the parallel consistency of the label closure). Its findings — stale "the mover is 2D-only" rationale in two metric-builder error messages, and an incorrect log-capture guard in the new test — are fixed in the final commit; a pre-existing empty-rank hazard shared with the 2D path is marked at the site.

Evidence

Full mover/adapt serial family: 215 tests green. New/flipped contract tests in test_0764 (3D capability: moves, no fold, boundary held exactly) and test_0850_mesh_smoothing (the dimension guard now rejects only dimensions with no discretization). Style gate clean, no allowlist additions.

Design note with the round-2 status and measurements: docs/developer/design/ADAPTIVITY_3D_SPHERICAL_2026-07.md.

[1] Huang & Kamenski, J. Comput. Phys. 301 (2015) 322 (arXiv:1410.7872).

Underworld development team with AI support from Claude Code

lmoresi added 3 commits July 22, 2026 21:26
…dra (capstone round 2)

The mover core was dimension-general all along (the per-element algebra
is written over cdim); 3D existence was blocked by the rim, not the
method:

- cell list / signed measure / volume factor now dispatch on dimension
  (_tet_cells, new _signed_volumes = det(E)/6, fact = d!);
- the honest 2D-only guards (mover, redistribute_nodes,
  node_redistribution, mesh_metric_mismatch) flip to capability for 3D
  simplex meshes, still refusing quad/hex and manifolds;
- follow_metric's shape-quality polish gains the tet formula
  (q = 6*sqrt(2)*V/e_rms^3; regular tet = 1, sliver -> 0);
- THE REAL 3D BLOCKER: _pinned_mask stopped its label closure at edges,
  and 3D gmsh labels tag faces only — so on any 3D mesh NO boundary
  vertex was classified: nothing pinned, nothing slipped, the boundary
  drifted freely into the interior. Every tagged non-vertex point now
  closes down to its vertices (bit-identical mask in 2D, where the
  closure of an edge is exactly its endpoints).

Measured on the dipping-fault-plane box: monotone energy descent, zero
folds, boundary nodes held exactly on their faces under slip, grading
ratio 1.12 vs 1.30 for the same problem in 2D (the equidistribution
exponent compresses the ideal from 4x to 2.5x in 3D; repeated calls
hold a stable equilibrium, matching 2D behaviour). follow_metric runs
end-to-end on 3D. Full mover/adapt family: 215 passed serially.

Underworld development team with AI support from Claude Code
Underworld development team with AI support from Claude Code
…es, honest test guard

The adversarial review of this branch cleared the 3D generalisation
(no correctness defects) and flagged message rot: fault_metric_tensor
and fault_comb_metric refused 3D 'because the MMPDE mover is 2D' — no
longer true on this branch. Both builders stay 2D-only for their OWN
reason (the polyline-band / comb construction is planar geometry) and
now say so, pointing 3D users at building a metric directly for
redistribute_nodes. The new 3D capability test dropped its log-capture
guard: callback-sync failures raise since the #379 rework, so a clean
run is itself the guard. The pre-existing rank-local early-return
hazard in the mover (empty-rank hang class, shared with 2D) is marked
with a TODO(BUG) at the site per the review's note.

Underworld development team with AI support from Claude Code
Copilot AI review requested due to automatic review settings July 22, 2026 23:23

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@lmoresi
lmoresi merged commit b25c09f into development Jul 22, 2026
2 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