Skip to content

fix: name adapt_images when an adaptive mesh has no image-plane grid (#332) - #442

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/autoarray-adapt-images-precondition
Aug 9, 2026
Merged

fix: name adapt_images when an adaptive mesh has no image-plane grid (#332)#442
Jammy2211 merged 1 commit into
mainfrom
feature/autoarray-adapt-images-precondition

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Closes #332. Phase 3 of the @rhayes777 API audit epic #415.

⚠️ The meshes are not broken

The issue's headline says Delaunay and KNNBarycentric are "unusable in FitImaging". That is false, and the reply already posted on #332 corrects it while crediting the underlying finding. This PR keeps that framing.

Re-verified on this branch — with adapt_images supplied, everything fits:

Configuration Result
Delaunay + Constant + adapt_images fits
Delaunay + ConstantSplit + adapt_images fits
KNNBarycentric + Constant + adapt_images fits
RectangularUniform + Constant (no adapt_images needed) fits
Delaunay / KNNBarycentric, no adapt_images raises, clearly

So the defect is the error, not the mesh.

What this fixes

Omitting adapt_images used to surface as:

AttributeError: 'NoneType' object has no attribute 'array'
  autoarray/inversion/mesh/border_relocator.py, in relocated_mesh_grid_from

— naming nothing the caller controls, in a file they have never opened. It now raises MeshException at the point the precondition is known to be unmet, naming adapt_images, showing the AdaptImages idiom, and noting that the rectangular family needs no adapt_images at all.

The guard sits at Delaunay.interpolator_from, the entry point KNearestNeighbor and KNNBarycentric both inherit, so one check covers all three adaptive meshes.

Option 1 vs option 2 — recorded, as the issue asked

The issue offered two routes, and @rhayes777 raised the first himself ("the wiring ... probably needs to move inside the mesh classes themselves"):

  1. the mesh wires the image-plane grid up itself, or
  2. construction fails immediately, naming adapt_images.

Chose option 2. Building an image-plane mesh grid requires a weighting policy — which is exactly what adapt_images carries. Inventing one inside the mesh would silently make a science choice on the user's behalf, and would do it invisibly, in the case where the user has given no indication of what they want. Failing fast keeps that choice explicit.

It also matches how phase 1 handled the rectangular-mesh / split-regularization case (#417): an explicit "you must supply X" exception rather than implementing a missing capability.

Declining option 1 is a judgement call, not a shortcut — happy to revisit if the intended API really is for Delaunay(pixels=N) to self-wire.

One correction to the recorded diagnosis

The prompt for this task states the None is the grid passed into BorderRelocator.relocated_mesh_grid_from(). It is actually mesh_gridborder_relocator.py:450 (mesh_grid.array), not line 446 (grid.array). Same fix, but the note is wrong in the campaign record and worth correcting there.

API Changes

No signatures, names or return types change. An adaptive mesh given no source_plane_mesh_grid now raises exc.MeshException at interpolator_from instead of AttributeError several frames deeper. Both were failures; only the message changes.

RectangularUniform and the rest of the rectangular family are explicitly unaffected — they build their own grid, and a control test pins that the guard does not fire for them.

Test Plan

  • New: test_autoarray/inversion/pixelization/mesh/test_adapt_images_precondition.py — 10 cases.
    • The guard fires for all three adaptive meshes.
    • Assertions are on the message, not just the exception type — that is the entire point of this issue, since the old failure raised too, it just said nothing useful.
    • Controls pin the headline correction: each adaptive mesh, given the grid adapt_images carries, still builds its interpolator. If those ever fail, the mesh really is broken and the posted reply needs revisiting.
    • A control pins that RectangularUniform needs no adapt_images.
  • Tests assert the clear failure, never that bare construction succeeds — doing the latter would enshrine the reporter's misreading, which is the specific trap recorded for this task.
  • Full suite: 991 passed, 51 skipped. The 3 test_transformer.py pynufft failures are pre-existing on main (baselined) and tracked separately. Zero regressions.

Out of scope


Generated by Claude Code

…332)

Omitting adapt_images with Delaunay / KNearestNeighbor / KNNBarycentric used to
surface as:

    AttributeError: 'NoneType' object has no attribute 'array'
      autoarray/inversion/mesh/border_relocator.py, relocated_mesh_grid_from

naming nothing the caller controls, in a file they have never opened. It now
raises MeshException at the point the precondition is known to be unmet, naming
adapt_images, showing the AdaptImages idiom, and noting that the rectangular
family needs no adapt_images at all.

The guard sits at Delaunay.interpolator_from, the entry point the whole adaptive
family inherits, so one check covers all three meshes.

Chose fail-fast over having the mesh wire the grid up itself (the reporter's own
suggestion). Building an image-plane mesh grid requires a weighting policy —
which is exactly what adapt_images carries — so inventing one here would silently
make a science choice on the user's behalf. This matches how phase 1 handled the
rectangular/split combination: an explicit "you must supply X" rather than
implementing a missing capability.

THE MESHES ARE NOT BROKEN. The issue headline says Delaunay and KNNBarycentric
are "unusable in FitImaging"; that is false and the reply on #332 already
corrects it. Verified again here: with adapt_images supplied, Delaunay+Constant,
KNNBarycentric+Constant and Delaunay+ConstantSplit all fit, and
RectangularUniform+Constant fits with no adapt_images at all. The tests assert
the CLEAR FAILURE plus those controls — asserting bare construction succeeds
would have enshrined the misreading.

One correction to the recorded diagnosis: the None is `mesh_grid`
(border_relocator.py:450), not `grid` (line 446) as the prompt stated.

Part 2 of #332 (ConstantSplit on RectangularUniform) shipped in phase 1 and is
untouched.

Tests: 10 new cases in
test_autoarray/inversion/pixelization/mesh/test_adapt_images_precondition.py.
Suite 991 passed; the 3 pynufft failures in test_transformer.py are pre-existing
on main and tracked separately.

Closes #332.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013PgqSCLTemK5bApVAwhVM4
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Aug 9, 2026 — with Claude
@Jammy2211
Jammy2211 merged commit 5dedb5e into main Aug 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pending-release PR queued for the next release build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adaptive pixelisations (Delaunay, KNNBarycentric) crash in FitImaging; ConstantSplit broken on RectangularUniform

2 participants