From 731caceee6df30282edbf97b7f8631543a7d6679 Mon Sep 17 00:00:00 2001 From: lmoresi Date: Mon, 27 Jul 2026 17:32:58 +1000 Subject: [PATCH] docs(changelog): local interpolation with a linear-reproduction guarantee Records #430 and #434 at the conceptual level the changelog is for. Underworld development team with AI support from Claude Code --- docs/developer/CHANGELOG.md | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/developer/CHANGELOG.md b/docs/developer/CHANGELOG.md index 761513dcd..1cdbc5dd6 100644 --- a/docs/developer/CHANGELOG.md +++ b/docs/developer/CHANGELOG.md @@ -6,6 +6,49 @@ This log tracks significant development work at a conceptual level, suitable for ## 2026 Q3 (July – September) +### Local Interpolation That Reproduces Linear Fields (July 2026) + +**The local scattered-point interpolator now has a linear-reproduction +guarantee**, and the swarm proxy variables use it by default (#430). + +Underworld's local interpolator was inverse-distance (Shepard) weighting. +Its weights are positive and sum to one, so it reproduced a *constant* exactly +but not a linear field: any field with a gradient was smeared, and the error +did not fall as the points crowded together. Measured on an exactly linear +field — which lies inside both the P1 and P2 proxy space, so the finite element +discretisation contributes nothing and all of the error is particle-to-node +transfer — the swarm proxy carried 1e-3 to 2e-2 relative error, falling only +first order with refinement and **not at all** with stencil size. + +- New `order=1` scheme on `uw.kdtree.KDTree.rbf_interpolator_local`: a + polyharmonic kernel with an affine tail, solved per target point on its own + nearest-neighbour stencil. Constants and linear fields are exact by + construction, and the result stays sparse at `nnn` non-zeros per row. The + existing inverse-distance path is unchanged and remains the KDTree default. +- Proxy error on a linear field falls to round-off; on a quadratic field it + improves roughly ninety-fold in 2D and thirty-fold in 3D. Swarm proxy + variables now default to `order=1`. +- `KDTree.interpolation_matrix()` returns the transfer as a sparse operator. + The weights depend only on geometry, so one build serves every field and + component — the form a multigrid prolongation or a remesh transfer wants. +- Stencils that cannot support an affine fit (collinear in 2D, coplanar in 3D) + are detected, retried on a wider neighbourhood, and only then fall back to + inverse distance with a warning. They never return `NaN`, and never silently. +- An opt-in limiter bounds the non-affine part of the interpolant while leaving + the linear reconstruction untouched, so limiting does not cost the guarantee. + +Two deliberate exclusions, both measured rather than assumed: +`MeshVariable.rbf_interpolate` keeps inverse distance because it is the +fallback rung of the point-location ladder, whose documented contract is that +it is bounded; and `IndexSwarmVariable` material level sets keep it because a +material indicator is piecewise constant — there is nothing for linear +exactness to gain at a discontinuity, and signed weights push level sets +outside `[0, 1]`. + +Related: swarm proxy refresh no longer fails under an active units model +(#426, #434); the units the proxy advertises are tracked separately (#439). +New subsystem documentation: `subsystems/interpolation.md`. + ### Purposeful Adapt / Redistribution Naming (July 2026) **User-facing mesh-modification names now state the capability** (maintainer