Skip to content

fix: adaptive rectangular meshes report their true pixel centres - #668

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/adaptive-rect-mesh-node-positions
Oct 30, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
feature/adaptive-rect-mesh-node-positions

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

For the four adaptive rectangular meshes (RectangularBilinearAdaptDensity/Image, RectangularRTUAdaptDensity/Image), mapper.source_plane_mesh_grid returned the uniform overlay the interpolator is built from, not the source-plane positions where the mapper's interpolant takes each reconstruction value. The mapper works on a regular lattice in CDF space; the real pixel centres are that lattice mapped back through the inverse CDF, and they bunch up where the mesh adapts.

On autolens_workspace imaging/simple__no_lens_light (28×28 BilinearAdaptDensity) the overlay spacing was a uniform 0.11″ while the true central spacing is ~0.036″, so griddata of the reconstruction from the reported positions integrated ~4.6× too high (interpolation-route magnification 6.9 vs mesh-route 31.6 vs truth 34.9).

Everything that places the reconstruction from those positions was wrong and is fixed by this PR:

  • source_plane_reconstruction_{i}.csv y/x columns (inversion_plots.py)
  • inversion.max_pixel_centre → PyAutoLens automatic position updating (result.py). Measured shift on a centred source: brightest pixel at (−0.055″, 0.044″) → (0.018″, 0.020″) (truth (0, 0)); larger for sources offset within the mesh.
  • Mapper.extent_from zoom-to-brightest for plots
  • PyAutoLens potential correction (interpolates the source from these points)
  • workspace interpolation of the source (autolens_workspace#605, follows this PR)

Plots of the mesh itself were already right (they use edges_transformed). Areas (areas_for_magnification) are untouched.

Regularization — deliberately unchanged. Kernel regularizations (ExponentialKernel, GaussianKernel, MaternKernel, MaternAdaptKernel) and MaternSparse have always measured distances on the lattice (the mesh's stretched coordinates). Tuned separately on the test lens, lattice distances beat true distances on Bayesian evidence (Matern 1923.5 vs 1812.1; Gaussian 2105.3 vs 1758.6) while true distances were ~1 point better on magnification. Human ruling: keep the lattice explicitly (new regularization_mesh_grid), so no likelihood changes; the question goes to an end-to-end research study (Mind draft/research/autolens_inference/kernel_regularization_distances_adaptive_rectangular.md).

Heart at ship: STALE — "release validation stale: source moved since rehearsal (PyAutoFit, PyAutoArray, PyAutoGalaxy, PyAutoLens)"; acknowledged by the human 2026-10-30.

Release note: the reconstruction CSV's y/x columns change for adaptive rectangular meshes (now the true pixel centres).

API Changes

Mapper.source_plane_mesh_grid now returns the true source-plane pixel centres for adaptive rectangular meshes (was the uniform overlay). New MeshGeometryRectangular.node_centres and Mapper.regularization_mesh_grid (the lattice kernel regularizations measure distances on). Likelihoods are unchanged.
See full details below.

Test Plan

  • New test_autoarray/inversion/pixelization/mesh_geometry/test_node_centres.py: each node's interpolation weight is ~1 at its reported centre (all 4 adaptive meshes, on a distorted lensing-like grid); centres form a row-major lattice inside the data span; interpolating a least-squares reconstruction from the centres recovers the analytic integral (density meshes ~2%; image-adaptive meshes much closer than the overlay); RectangularUniform unchanged.
  • PyAutoArray full suite: 2264 passed, 4 xfailed (before the final duck-typing fallback; regularization + node-centre tests re-run after it: 145 passed)
  • PyAutoGalaxy suite: 1452 passed
  • PyAutoLens suite: 1014 passed + the one potential-correction failure (duck-typed DpsiLinearObj) fixed by regularization_mesh_grid_from's fallback; test_autolens/potential_correction 60 passed
  • autolens_workspace_test scripts/imaging/mesh_magnification.py: all meshes within tolerance, identical to before
Full API Changes (for automation & release notes)

Added

  • autoarray.inversion.mesh.interpolator.rectangular.adaptive_rectangular_node_centres_from(source_grid_shape, data_grid, mesh_weight_map=None, bandwidth=, n_knots=, transform=, xp=np) — source-plane centre of every adaptive-mesh node, in mapper order
  • MeshGeometryRectangular.node_centres — true pixel centres (mesh_grid for RectangularUniform)
  • AbstractInterpolator.source_plane_mesh_grid, AbstractInterpolator.regularization_mesh_grid (both default to mesh_grid)
  • Mapper.regularization_mesh_grid — positions kernel regularizations measure distances on
  • autoarray.inversion.regularization.abstract.regularization_mesh_grid_from(linear_obj) — regularization_mesh_grid, falling back to source_plane_mesh_grid for duck-typed linear objects

Changed Behaviour

  • Mapper.source_plane_mesh_grid (via InterpolatorRectangular.source_plane_mesh_grid) — true pixel centres for adaptive rectangular meshes; downstream: reconstruction CSV y/x, max_pixel_centre, extent_from, PyAutoLens potential correction
  • Kernel regularizations and MaternSparse read regularization_mesh_grid_from(linear_obj) instead of linear_obj.source_plane_mesh_grid — same values as before for every mesh (lattice for adaptive rectangular), so no likelihood change

Migration

  • Code that wants the lattice (e.g. a grid Laplacian) should read mapper.regularization_mesh_grid (or mapper.interpolator.mesh_grid), not source_plane_mesh_grid.

Generated by the PyAutoLabs agent workflow.

🤖 Generated with Claude Code

`mapper.source_plane_mesh_grid` for the four adaptive rectangular meshes
returned the uniform overlay the interpolator is built from, not the
source-plane positions where the mapper's interpolant takes each
reconstruction value (the regular CDF lattice mapped back through the
inverse CDF). Anything placing the reconstruction from those positions
was wrong: the reconstruction CSV, `max_pixel_centre` (used by PyAutoLens
automatic position updating), plot zoom (`extent_from`), PyAutoLens
potential correction and workspace interpolation of the source.

- `adaptive_rectangular_node_centres_from` + `MeshGeometryRectangular.node_centres`
- `InterpolatorRectangular.source_plane_mesh_grid` returns the node centres
- kernel regularizations and MaternSparse keep measuring distances on the
  lattice, now explicitly via `regularization_mesh_grid` /
  `regularization_mesh_grid_from` (likelihoods unchanged; true-distance
  kernels are a separate research question)

Closes #667

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Jammy2211
Jammy2211 merged commit 8ce5bae into main Oct 30, 2026
3 checks passed
@Jammy2211
Jammy2211 deleted the feature/adaptive-rect-mesh-node-positions branch October 30, 2026 11:42
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Oct 30, 2026
@Jammy2211

Copy link
Copy Markdown
Collaborator Author

Workspace PR: PyAutoLabs/autolens_workspace#606

@pyautolabs-bot pyautolabs-bot Bot removed the pending-release PR queued for the next release build label Nov 1, 2026
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.

1 participant