feat(meshing): purposeful adapt/redistribution naming — node_redistribution + engine-less adapt()#372
Merged
Merged
Conversation
…closes #346, #353) Maintainer ruling 2026-07-16 (retirement: mmpde superseded spring/MA/OT via the isotropic-metric equivalence; deletion sign-off given 2026-07-16). Deleted: smoothing/{spring,monge_ampere,anisotropic}.py, meshing/ _ot_adapt.py, mesh.OT_adapt / OT_adapt_reset_reference (tombstone raises RuntimeError), tests/test_0760_mesh_ot_adapt.py, the WC-13 spring-shim tests. BEHAVIOUR CHANGE (sanctioned): smooth_mesh_interior's default method= is now 'mmpde' (was 'spring'). Retired method spellings raise a clear ValueError naming the replacement; strategy= now routes to mmpde (fixes #353's TypeError); #346's latent spring MPI deadlock dies with the file. follow_metric now drives the MMPDE mover (theta=0.5, pure equidistribution weighting for its scalar-density contract). Kept: the graph-Laplacian Jacobi smoother, the MMPDE mover, the Taubin surface smoother, all metric builders (fault_comb_metric, fault_metric_tensor, metric_density_from_gradient). Boundary-facet / slip primitives moved from _ot_adapt.py to smoothing/graph.py. Style-gate allowlist shrank by the deleted files' four entries; scanner green with no stale entries. Gates: serial 'level_1 and tier_a' 390 passed / 11 skipped / 1 xfailed; smoothing batch green; np2 test_0855 to follow. Underworld development team with AI support from Claude Code
…bution + engine-less adapt() Maintainer naming ruling 2026-07-16: user-facing names state the CAPABILITY; algorithm names (NVB, MMPDE) live in internals and docs. - New user entry uw.meshing.node_redistribution(mesh, metric, ...), a thin dispatch through the new mesh-controlled method Mesh.redistribute_nodes(metric, **kwargs) — the architecture by which meshes control how they can be modified. Base implementation: 2D simplex -> the MMPDE mover via smooth_mesh_interior; quad/hex, 3D, manifolds -> honest NotImplementedError stating what exists. Exported from meshing/__init__ (+__all__). smooth_mesh_interior stays as the machinery (docstring points at the new entry; no deprecation warning — it is not a wrong name). - mesh.adapt(metric, max_levels=...) needs no engine=: default engine is NVB on 2D meshes (NVB is 2D-only this pass, so 3D resolves to SBR — an engine-less 3D adapt keeps working); engine= stays as the advanced/internal selector. test_0835 (the SBR contract file) pins engine='sbr' explicitly. - Retirement ValueError now points at node_redistribution. - New contract tests tests/test_0763_node_redistribution.py (7 tests, level_1 tier_a). Docs + skills teach the purposeful spellings first. Gates: serial 'level_1 and tier_a' 397 passed / 11 skipped / 1 xfailed (PR 1 baseline 390/11/1 + the 7 new tests); np2 test_0839 6 passed; scanner green; docs build green. Underworld development team with AI support from Claude Code
…afe follow_metric envelope bound CI runs tests/test_07*/test_08* by file range without marker filtering, which caught two unmarked tests (test_0762_bounding_surfaces, test_0763_boundary_slip_correctness) importing the deleted meshing._ot_adapt for the relocated slip helpers — repointed to meshing.smoothing. The follow_metric envelope bound is widened to 1.5x target: the MMPDE mover's achieved h_min is platform-dependent (1.27x on macOS, 1.40x on Linux CI at refinement=2); the bound now catches over-refinement and gross under-refinement, not platform jitter. Local CI-mirror batches green: tests/test_07* 314 passed / 2 skipped / 8 xfailed / 1 xpassed; tests/test_08* 408 passed / 10 skipped / 11 xfailed. Underworld development team with AI support from Claude Code
…as taken by boundary_slip_correctness) Underworld development team with AI support from Claude Code
lmoresi
changed the base branch from
chore/retire-superseded-movers
to
development
July 16, 2026 18:13
…identical content plus this PR's edits Underworld development team with AI support from Claude Code
…nt SBR fallback Maintainer ruling 2026-07-17: an engine-less 3D adapt must say honestly that default adaptive refinement is 2D-only (3D refinement is committed future work), rather than silently selecting a different algorithm. engine='sbr' remains the explicit 3D opt-in. Regression test added. Underworld development team with AI support from Claude Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #371 (
chore/retire-superseded-movers) — the redistribution entry point depends on the pruned dispatch. Re-target todevelopmentafter #371 merges (or merge in order 371 → this).Ruling
Maintainer naming ruling, 2026-07-16: user-facing names state the capability; algorithm names (NVB, MMPDE) live in internals and docstrings. Quote on the architecture: the mesh-controlled method "will be how we allow meshes to control how they can be modified".
What this adds
uw.meshing.node_redistribution(mesh, metric, ...)__all__); thin dispatch to the mesh-controlled methodMesh.redistribute_nodes(metric, **kwargs)smooth_mesh_interiormachinery; quad/hex, 3D simplex, constrained manifolds → honestNotImplementedErrorstating what exists and what doesn't (each guard message names the 2D-simplex support and points atmesh.adaptfor topology change)mesh.adapt()mesh.adapt(metric, max_levels=...)works withoutengine=. Default engine is NVB on 2D meshes;engine=remains accepted, documented as an advanced/internal selector. Verified at post-#369 base: the default was still"sbr", so this is a real change, not docs-onlysmooth_mesh_interiornode_redistribution; no deprecation warningValueErrorfrom #371 now namesnode_redistributionas the replacementDecision surfaced for review
NVB is 2D-only this pass, so a blanket NVB default would have made every engine-less 3D
adapt()raise where SBR previously worked. The default is therefore dimension-aware:engine=Noneresolves to"nvb"whencdim == 2,"sbr"otherwise (commented at the resolution site). Explicitengine=is always honoured. If the ruling intended a hard NVB default even in 3D, say so and I'll change it.tests/test_0835_sbr_adapt_on_top.py(the SBR engine's own contract file, written under the old implicit default) now pinsengine="sbr"on all 13adapt()calls.Tests (new:
tests/test_0764_node_redistribution.py, level_1 tier_a, 7 tests)node_redistributionmoves nodes, topology preserved, zero warnings (DeprecationWarning-as-error guard);StructuredQuadBox→NotImplementedError(match "2D simplex");NotImplementedError;adapt()returns a child (child.parent is base);engine="nvb"child.Docs
docs/advanced/mesh-adaptation.md, theadaptive-meshingandadapt-on-top-faultsskills now teach the purposeful spellings first (algorithm names second, as implementation detail); CHANGELOG entry.Gates (strictly serial; amr-dev env)
pytest tests/ -m "level_1 and tier_a"tests/test_0839_nvb_parallel_adapt.pypixi run docs-buildUnderworld development team with AI support from Claude Code