Skip to content

feat: oversampled PSF convolution core API (convolve_over_sample_size)#355

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/psf-oversample-core
Jul 8, 2026
Merged

feat: oversampled PSF convolution core API (convolve_over_sample_size)#355
Jammy2211 merged 1 commit into
mainfrom
feature/psf-oversample-core

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Oversampled PSF convolution, phase 2a (core API) of the feature designed and approved in #353: Convolver gains convolve_over_sample_size, so PSF blurring can run at an integer multiple of the image resolution (the PSF supplied at that fine resolution) and bin back down by the mean of each sub-block — improving blurring accuracy for modeling. The implementation reuses the existing convolution machinery verbatim on an upscaled mask, plus a cached permutation between autoarray's per-pixel sub-block ordering and the fine mask's row-major slim ordering. Behaviour at the default convolve_over_sample_size=1 is unchanged.

Tracks #354. Design note + brute-force numerical ground truth: PyAutoMind/feature/autoarray/ (oversampling_design.md, oversampling_ground_truth.py).

API Changes

All changes are additive; convolve_over_sample_size=1 (default) leaves every existing code path untouched.

  • Convolver(convolve_over_sample_size: int = 1) — kernel supplied at the fine resolution when > 1; new kernel_shape_image_resolution property; convolution methods expect over-sampled (sub-block ordered) inputs when > 1 and raise KernelException on binned input; optional mask= keyword on the image-convolution methods; the oversampled JAX path always uses the FFT formalism.
  • Imaging(convolve_over_sample_size_lp=1, convolve_over_sample_size_pixelization=1) — with loud guards: matching over_sample_size_* must be uniform and equal when > 1; differing lp/pixelization sizes raise; incompatible with sparse_operator. from_fits gains the two sizes + psf_pixel_scales; apply_mask/apply_over_sampling pass through.
  • GridsDataset.blurring — footprint from the kernel's image-resolution shape, evaluated at the fine resolution when oversampled.
  • over_sample decorator — keyword-only binned: bool = True; False returns sub-block-ordered values.
  • New utils: mask_2d_upscaled_from, sub_slim_to_fine_slim_from; ConvolverState gains an optional explicit blurring_mask.

See full details below.

Test Plan

  • 13 new unit tests: s=2 output pinned to the phase-1 brute-force ground truth to ≤1e-12; s=1 scene parity; permutation bijection/round-trip; delta-kernel mapping-matrix identity; all validation guards.
  • Full suites against this branch: PyAutoArray 857 passed, PyAutoGalaxy 933 passed, PyAutoLens 331 passed.

Validation checklist (--auto run — plan was not pre-approved in-session)

Full API Changes (for automation & release notes)

Added

  • Convolver(convolve_over_sample_size: int = 1) — over sample size of the PSF; size 2 = PSF at 2× the image resolution (kernel pixel scales = image pixel scales / size, validated at state construction).
  • Convolver.kernel_shape_image_resolution — the kernel footprint in image-resolution pixels (drives the blurring-mask derivation).
  • Convolver.convolved_image_from(..., mask=None) / convolved_image_via_real_space_np_from(..., mask=None) — optional keyword; required when oversampled and no precomputed state exists (over-sampled inputs carry no mask). Keyword-only in practice; all downstream call sites verified keyword-based.
  • ConvolverState(..., blurring_mask=None) — explicit blurring-mask override; the FFT frame is sized to retain an explicit blurring region.
  • Imaging(convolve_over_sample_size_lp: int = 1, convolve_over_sample_size_pixelization: int = 1) — plumbed through from_fits (+ psf_pixel_scales), apply_mask, apply_over_sampling; psf_setup_state=True precomputes the fine state.
  • over_sample decorator: keyword-only binned: bool = True.
  • over_sample_util.mask_2d_upscaled_from(mask_2d, over_sample_size).
  • over_sample_util.sub_slim_to_fine_slim_from(mask_2d, over_sample_size).

Changed-Behaviour (only when convolve_over_sample_size > 1)

  • Convolution methods take over-sampled (sub-block ordered) inputs and return image-resolution outputs.
  • GridsDataset.blurring is built at the fine resolution with the image-resolution footprint.

Guards (raise loudly)

  • Non-int / < 1 convolve_over_sample_size*TypeError / KernelException/DatasetException.
  • over_sample_size_* not uniform-and-equal when oversampled → DatasetException.
  • Differing lp/pixelization convolve sizes → DatasetException (single PSF kernel).
  • sparse_operator (ctor or apply_sparse_operator) with an oversampled PSF → DatasetException.
  • Binned input, kernel/pixel-scale mismatch, missing mask+state → KernelException.

Deferred (per approved phasing)

  • Inversion wiring (phase 2b): an oversampled Convolver raises if handed a binned mapping matrix, so pixelized fits cannot silently mis-run.
  • PyAutoGalaxy operate/image.py consumer switch (phase 2c); workspace examples (phase 3); docs (phase 4).

Migration

  • No migration; existing code is unaffected. To opt in: supply the PSF at s× the image resolution and pass convolve_over_sample_size_lp=s with over_sample_size_lp=s.

🤖 Generated with Claude Code

#354)

Implements phase 2a of the approved design (PyAutoMind
feature/autoarray/oversampling_design.md, approved in #353):

- mask_2d_upscaled_from + sub_slim_to_fine_slim_from utils: fine mask at
  pixel_scales/s and the permutation between per-pixel sub-block ordering
  and the fine mask's row-major slim ordering.
- Convolver(convolve_over_sample_size=s): fine-resolution kernel semantics,
  fine ConvolverState (with explicit blurring-mask override sized into the
  FFT frame), oversampled scatter -> existing convolve -> s x s mean bin in
  all convolution methods (numpy real-space + JAX FFT), loud validation of
  kernel pixel scales and binned-input misuse. s=1 paths are untouched.
- Imaging/GridsDataset: convolve_over_sample_size_lp / _pixelization ints
  (default 1), equality rule vs over_sample_size_*, adaptive/differing/
  sparse-operator guards, blurring grid evaluated at the fine resolution,
  psf_setup_state fine-state precompute, from_fits psf_pixel_scales,
  apply_mask/apply_over_sampling pass-through.
- over_sample decorator: keyword-only binned=True pass-through; binned=False
  returns sub-block-ordered values (the oversampled Convolver input format).
- Tests pinned to the phase-1 brute-force ground truth: s=2 reference values
  to 1e-12, s=1 parity, permutation bijection, delta-kernel mapping-matrix
  identity, all guards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 8, 2026 15:30
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label Jul 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

2 participants