Skip to content

fix: resolve the Delaunay zeroed edge ring against the mapper's grid, not pixels #526

Closed

Description

@Jammy2211

Overview

Delaunay(pixels, zeroed_pixels) inflates self.pixels by zeroed_pixels and derives the zeroed edge-ring indices from that inflated count. Every autolens_workspace feature script and the Euclid pipeline pass the appended grid length as pixels, so mesh.pixels overstates the mapper's real parameter count by the ring size. For a single mapper the error cancels inside zeroed_ids_to_keep (the ring is still zeroed, which is why nothing ever failed); with two or more pixelized mappers the first mapper's ring stays live and interior vertices are zeroed instead. The same inflated pixels plus the index-array zeroed_pixels property also break to_dict round-trips (a Delaunay fit reloaded from tracer.json crashes). Full history in PyAutoMind/draft/bug/euclid/delaunay_edge_ring_never_zeroed.md.

Plan

  • Make the zeroed ring a property of the mapper's actual source-plane mesh grid: always its last zeroed_pixels vertices, whatever pixels says.
  • Stop inflating Delaunay.pixels; store the count the caller passed and the zeroed count as plain ints so the mesh round-trips through to_dict.
  • Route zeroed_ids_to_keep through mapper.params and a new mapper.zeroed_pixels, and cover the one- and two-mapper cases with tests.
  • Then fix the call sites to the correct form (pixels=<interior count>) in autolens_workspace and the Euclid pipeline, with a Euclid unit test on the mesh construction.
Detailed implementation plan

Affected Repositories

  • PyAutoArray (primary)
  • euclid_strong_lens_modeling_pipeline
  • autolens_workspace

Branch Survey

Repository Current Branch Dirty?
./PyAutoArray main clean
./euclid_strong_lens_modeling_pipeline main clean
./autolens_workspace main clean

Suggested branch: claude/delaunay-edge-ring-zeroed-8l4u1z on all three repos (the workspace and Euclid CI check the library chain out at the same-named branch).

Implementation Steps

  1. autoarray/inversion/mesh/mesh/abstract.py — add AbstractMesh.zeroed_pixels_from(pixels) returning the mesh's own zeroed_pixels index array (empty if the mesh has none).
  2. autoarray/inversion/mesh/mesh/delaunay.py — __init__ stores self.pixels = int(pixels) and self.zeroed_pixels = int(zeroed_pixels); override zeroed_pixels_from(pixels) to np.arange(pixels - zeroed_pixels, pixels); rewrite the docstring (pixels documents the interior count, the ring is the last zeroed_pixels vertices of the grid actually handed to the mapper).
  3. autoarray/inversion/mappers/abstract.py — add Mapper.zeroed_pixels = self.mesh.zeroed_pixels_from(pixels=self.params).
  4. autoarray/inversion/inversion/abstract.py — zeroed_ids_to_keep uses m.params for block sizes and m.zeroed_pixels for local ids; docstring updated.
  5. Tests: test_autoarray/inversion/mesh/mesh/test_delaunay.py (ring indices vs grid length, to_dict round-trip) and test_autoarray/inversion/inversion/test_abstract.py (zeroed_ids_to_keep with Delaunay mappers: one mapper under both call forms, two mappers).
  6. euclid_strong_lens_modeling_pipeline — scripts/initial_lens_model.py, both sites in scripts/full_model.py, hpc/diagnostics/jax_fork_control.py pass the interior count; a test in tests/ builds the mesh as the script does and asserts the ring indices are the appended points.
  7. autolens_workspace — the 20 pixels=image_plane_mesh_grid.shape[0] sites under scripts/ pass the image-mesh pixel count; prose updated; notebooks regenerated.

Key Files

  • autoarray/inversion/mesh/mesh/delaunay.py — the constructor and ring semantics
  • autoarray/inversion/inversion/abstract.py — zeroed_ids_to_keep, the only consumer of the ring
  • autoarray/inversion/mappers/abstract.py — params is the real parameter count

Follow-ups (not in this task)

  • autolens_workspace_test/scripts/multi_dataset/dataset_model_parity_delaunay.py and autolens_workspace_developer/jax_profiling/*/delaunay.py still pass the appended length; harmless after step 4, tidy separately.

Original Prompt

Click to expand starting prompt

See PyAutoMind/draft/bug/euclid/delaunay_edge_ring_never_zeroed.md (finding, provenance and the 2026-09-05 history audit).

Activity

  1. Jammy2211 commented on Sep 5, 2026

    @Jammy2211
    CollaboratorAuthor

    Library PR Created — workspace legs open behind the library-first gate

    API-change summary. Delaunay.pixels is no longer inflated by zeroed_pixels (it is the interior count as passed; total_pixels adds the ring); Delaunay.zeroed_pixels is the int count and the indices come from zeroed_pixels_from(pixels); new AbstractMesh.zeroed_pixels_from and Mapper.zeroed_pixels; zeroed_ids_to_keep sizes blocks by mapper.params. Both call forms in the wild zero the same vertices; two-mapper inversions are now correct; the mesh round-trips through to_dict.

    Verified. autoarray 1369 passed / 62 skipped; Euclid fast suite 74 passed against the branch; workspace imaging and multi-galaxy Delaunay scripts run end-to-end under the smoke profile.

    Next: /prm merges library-first, then the two workspace PRs. Follow-ups outside this task: autolens_workspace_test/scripts/multi_dataset/dataset_model_parity_delaunay.py and autolens_workspace_developer/jax_profiling/*/delaunay.py still pass the appended length (harmless after #527).


    Generated by Claude Code

  2. Jammy2211 commented on Sep 5, 2026

    @Jammy2211
    CollaboratorAuthor

    Shipped

    Summary. The over-count cancelled for a single mapper, so no archived single-source result changes; two-mapper inversions now zero every ring correctly and a Delaunay fit reloads from tracer.json. History of how the fix landed only in the SLaM and test-workspace scripts is in the completion record PyAutoMind/complete/2026/09/delaunay-edge-ring-zeroed.md.

    Pending release. PyAutoArray#527 carries pending-release; the workspace and Euclid changes need no new API and run against any autoarray.

    Follow-ups (not filed). autolens_workspace_test/scripts/multi_dataset/dataset_model_parity_delaunay.py and autolens_workspace_developer/jax_profiling/*/delaunay.py still pass the appended length — harmless now, tidy when next touched.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions