Repository navigation
feat: Convolver convolve_over_sample_size + Imaging plumbing (phase 2a) #354
Description
Activity
Phase 2a implemented — parking for ship sign-off
The core API is implemented, committed locally on
feature/psf-oversample-core(PyAutoArray, commit4eceda06, not pushed), and fully verified. Per the supervised--autocontract the commit/push/PR step is the gated action, so this is the batched sign-off question.Verification
Leg Result Tests (shipped repo) PyAutoArray 857 passed, 0 failed (includes 13 new tests) Tests (downstream, API kwarg added) PyAutoGalaxy 933 passed, PyAutoLens 331 passed against the branch via worktree PYTHONPATH Ground truth s=2 reference values reproduced to ≤1e-12 through both the raw Convolver and the full Imaging.apply_maskflow; s=1 parity exactReview Surface: 9 files, +1363/−277, python-sourceflag. Verdict: CLEAN — additive API, all four scoping guards fire in tests,apply_maskstate-rebuild edge fixed during implementationSmoke Not run (change is additive behind convolve_over_sample_size=1defaults; can run the curated subsets before push on request)Heart YELLOW (same chronic reason set as this morning: stale workspace validation, 55 stale parked scripts, assistant pin, no install verification, old PRs). No reason set was acknowledged at this launch, so an unattended ship is not permitted regardless API Changes (drafted PR section)
Convolvergainsconvolve_over_sample_size: int = 1(kernel supplied at the fine resolution when >1),kernel_shape_image_resolutionproperty.convolved_image_from/convolved_image_via_real_space_np_fromgain an optional keywordmask=(needed because over-sampled inputs don't carry the mask; all existing call sites pass keywords, verified in PyAutoGalaxy/PyAutoLens). When s>1, convolution methods expect over-sampled (sub-block ordered) inputs and raiseKernelExceptionon binned input; the JAX oversampled path always uses the FFT formalism.ConvolverStategains an optionalblurring_maskoverride; FFT frame is sized to keep an explicit blurring region.Imaginggainsconvolve_over_sample_size_lp/convolve_over_sample_size_pixelization(int, default 1) with guards: over_sample_size must be uniform and equal when >1; differing lp/pixelization sizes raise (single kernel);sparse_operator+ oversampled pixelization raises;apply_sparse_operatorraises on an oversampled PSF.from_fitsgains the two sizes +psf_pixel_scales.apply_mask/apply_over_samplingpass through.GridsDataset.blurringuses the kernel's image-resolution footprint and evaluates at the fine resolution when oversampled.over_sampledecorator gains keyword-onlybinned: bool = True;binned=Falsereturns sub-block-ordered values.- New utils:
mask_2d_upscaled_from,sub_slim_to_fine_slim_from. - Not in this PR (per the approved phasing): inversion wiring (2b — an s>1 Convolver currently raises loudly if an inversion hands it a binned mapping matrix), PyAutoGalaxy
operate/image.pyconsumer switch (2c, also blocked by the kaplinghat PyAutoGalaxy claim), workspace examples (3), docs (4).
⏸ The question
Approve pushing this commit and opening the pending-release PR on PyAutoLabs/PyAutoArray?
- "Ship it" → push
feature/psf-oversample-core, open the PR with the body above (pending-release, library-first gate), file phase 2b's prompt for issue, update Mind state. - "Run smoke first" → run the curated workspace smoke subsets against the branch, append results here, then ship if clean.
- Amendments → reply with changes; they're applied before push.
Also note: the Heart YELLOW reasons above are the same chronic set you acknowledged for
profiling-polish-designtoday — if you want that acknowledgement to cover this task too, say so and it's recorded inactive.md(it never carries over implicitly).Task
psf-oversample-coreparkedawaiting-inputin PyAutoMind/active.md; the worktree holds the local commit.🤖 Generated with Claude Code
🚢 Shipped (human-approved at the sign-off checkpoint): PR #355 (
pending-release, branchfeature/psf-oversample-core).Workspace impact: none for existing scripts — the API is additive behind
convolve_over_sample_size=1defaults, and PyAutoGalaxy (933) / PyAutoLens (331) suites pass against the branch unchanged. No migration follow-up needed; new workspace demos arrive in phase 3 after 2b/2c per the approved phasing.Next in the series: phase 2b (inversion wiring) is filed as its own issue and starts once this PR merges. Phase 2c (PyAutoGalaxy consumer) was queued behind the
kaplinghat-sidm-cored-nfwPyAutoGalaxy claim, which has since been released — it now waits only on this merge.Merge and issue-close stay human acts — happy to do both on your word.
🤖 Generated with Claude Code
- added a commit that references this issue
on Jul 8, 2026 ✅ Merged as PR #355 (squash). Phase 2a complete —
convolve_over_sample_sizecore API is on main. Phase 2b (inversion wiring) continues in #356.🤖 Generated with Claude Code
- added a commit that references this issue
on Jul 8, 2026
Overview
Phase 2a of oversampled PSF convolution: the PyAutoArray core API. Implements the design approved in #353 (
PyAutoMind/feature/autoarray/oversampling_design.md) verbatim —Convolver.convolve_over_sample_size, the fine-mask machinery,Imagingplumbing and the adaptive guards, with unit tests pinned to the phase-1 numerical ground truth. Behaviour atconvolve_over_sample_size=1is byte-identical to today.Run mode:
--autoat effective levelsupervised(plan-to-issue, ship sign-off parks with a batched question). Phase split: 2a (this issue) → 2b inversion wiring → 2c PyAutoGalaxy consumer (queued, blocked by an unrelated PyAutoGalaxy worktree claim) → phases 3–4 (workspace, docs).Plan
mask_2d_upscaled_from(mask, s)and the cached permutation between autoarray's per-pixel sub-block ordering and the fine mask's row-major slim ordering.Convolverwithconvolve_over_sample_size: int = 1: fine-resolution kernel semantics, fineConvolverStatefromstate_from, oversampled scatter → existing convolve → s×s mean bin → slim in all four convolution methods, loud shape/pixel-scale validation.Imaging/GridsDatasetwithconvolve_over_sample_size_lp/convolve_over_sample_size_pixelization(int, default 1), the equality rule vsover_sample_size_*, blurring grid atover_sample_size=s,psf_setup_statefine state, ctor/from_fits/apply_*pass-through,sparse_operator+ adaptive guards.binned: bool = Truepass-through to theover_sampledecorator (autoarray side only).Detailed implementation plan
Affected Repositories
Branch Survey
Suggested branch:
feature/psf-oversample-coreWorktree root:
~/Code/PyAutoLabs-wt/psf-oversample-core/Implementation Steps
autoarray/mask/mask_2d_util.py:mask_2d_upscaled_from(mask_2d, over_sample_size)(each unmasked pixel → s×s unmasked block, pixel scale ps/s, same origin); permutation buildersub_slim_to_fine_slim_from(mask, s)mapping per-pixel sub-block slim indices to fine-mask row-major slim indices (and its inverse). Unit tests: round-trip permutation, upscaled-mask geometry, s=1 identity.autoarray/operators/convolver.py: when built for s>1, construct from(kernel_fine, mask_fine); cachesub_slim_to_fine_slim, the blurring-region permutation, and bin/reshape indices alongside the existing FFT precomputes.convolve_over_sample_size: int = 1ctor param (validate plain int ≥ 1, TypeError otherwise);state_from(mask)derives the fine mask when s>1 and checkskernel.pixel_scales ≈ mask.pixel_scales / s(KernelException on mismatch);convolved_image_from,convolved_mapping_matrix_fromand both_via_real_space_*variants accept over-sampled slim inputs when s>1 (lengthn_unmasked·s², sub-block order), raise on binned-length input, return image-resolution slim via mean bin-down. s=1 paths untouched.autoarray/dataset/imaging/dataset.py+dataset/grids.py: new ctor ints (default 1) stored + passed throughfrom_fits/apply_mask/apply_over_sampling; equality rule (s>1 requires matchingover_sample_size_*uniform int equal to it, DatasetException otherwise, checked viaOverSampler.sub_is_uniform); blurring grid getsover_sample_size=swhen s>1;psf_setup_statebuilds the fine state; raise ifsparse_operator is not Noneandconvolve_over_sample_size_pixelization > 1.autoarray/operators/over_sampling/decorator.py:binned: bool = Truekwarg;binned=Falsereturns sub-gridded values in sub-block order (the s>1 Convolver input format). No callers change in this PR.test_autoarray/: mirror the ground-truth scene (11×11, ps=1, r=3.5 circular mask, Gaussian source σ=1.2 @ (0.3,−0.4), Gaussian PSF σ=0.8, kernel radius 2.0"): s=1 parity vs existing path; s=2 == design §7 reference values (sum 2.796562184524787, slim0 3.726289901353439e-02, slim17 2.025075336159483e-01, slim36 1.090767109119494e-02); guard raises; decorator binned=False ordering.Key Files
autoarray/operators/convolver.py— ConvolverState + Convolver (design §§1–2)autoarray/mask/mask_2d_util.py— upscale + permutation utilsautoarray/dataset/imaging/dataset.py,autoarray/dataset/grids.py— plumbing + guards (design §3, §6)autoarray/operators/over_sampling/decorator.py—binnedkwarg (design §5)PyAutoMind/feature/autoarray/oversampling_design.md— the approved design (do not re-design)PyAutoMind/feature/autoarray/oversampling_ground_truth.py— reference numbersAcceptance
## API Changesfor phases 2b/2c/3.Original Prompt
Click to expand starting prompt
See
PyAutoMind/issued/oversampling_phase_2a_convolver_dataset.md(phase 2a split ofoversampling_phase_2_core_api.md, itself phase 2 ofoversampling.md; design approved in #353).