Skip to content

Commit dec03e8

Browse files
Jammy2211Jammy2211claude
authored
feat: k x s coupling call sites (#362 phase 2) (#486)
OperateImage._binned_for_convolution applies the partial pre-bin after evaluation in the three blurred-image variants (no-op when sizes equal s); the linear light profile override does the same; convolved_padded_image_2d_from now inherits the input grid's (possibly adaptive) evaluation sizes on the padded frame, padded with s in the border, so simulation composes with adaptive evaluation too. Co-authored-by: Jammy2211 <JNightingale2211@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 6fd900a commit dec03e8

2 files changed

Lines changed: 70 additions & 6 deletions

File tree

autogalaxy/operate/image.py

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,26 @@ def has(self, cls) -> bool:
6767
"""
6868
raise NotImplementedError
6969

70+
@staticmethod
71+
def _binned_for_convolution(values, grid, psf, xp=np):
72+
"""
73+
Partially bin values evaluated on ``grid``'s over-sampled coordinates (per-pixel
74+
sizes k_i * s) down to the uniform s the oversampled Convolver requires — the
75+
k x s coupling. A no-op when the grid's sizes already equal s.
76+
"""
77+
from autoarray.operators.over_sampling.over_sample_util import (
78+
binned_to_convolve_size_from,
79+
)
80+
81+
values = values.array if hasattr(values, "array") else values
82+
83+
return binned_to_convolve_size_from(
84+
values=values,
85+
sub_size=np.array(grid.over_sample_size),
86+
convolve_over_sample_size=psf.convolve_over_sample_size,
87+
xp=xp,
88+
)
89+
7090
@staticmethod
7191
def _psf_evaluation_grids_from(grid, blurring_grid, psf):
7292
"""
@@ -163,8 +183,12 @@ def blurred_image_2d_from(
163183

164184
if convolution_mask is not None:
165185
blurred_image_2d = psf.convolved_image_from(
166-
image=image_2d_not_operated,
167-
blurring_image=blurring_image_2d_not_operated,
186+
image=self._binned_for_convolution(
187+
image_2d_not_operated, grid, psf, xp=xp
188+
),
189+
blurring_image=self._binned_for_convolution(
190+
blurring_image_2d_not_operated, blurring_grid, psf, xp=xp
191+
),
168192
mask=convolution_mask,
169193
xp=xp,
170194
)
@@ -247,14 +271,32 @@ def convolved_padded_image_2d_from(self, grid, psf: aa.Convolver, xp=np):
247271
origin=grid.origin,
248272
)
249273

250-
padded_grid = aa.Grid2D.from_mask(mask=padded_mask, over_sample_size=s)
274+
# The padded grid inherits the input grid's (possibly adaptive, k x s
275+
# coupled) evaluation sizes, padded with s in the border region.
276+
pad_width = (
277+
(padded_shape[0] - grid.mask.shape_native[0]) // 2,
278+
(padded_shape[1] - grid.mask.shape_native[1]) // 2,
279+
)
280+
over_sample_size = np.pad(
281+
np.array(grid.over_sample_size.native),
282+
pad_width,
283+
mode="constant",
284+
constant_values=s,
285+
)
286+
over_sample_size[over_sample_size == 0] = s
287+
288+
padded_grid = aa.Grid2D.from_mask(
289+
mask=padded_mask, over_sample_size=over_sample_size
290+
)
251291

252292
image_over_sampled = self.image_2d_from(
253293
grid=padded_grid.over_sampled, xp=xp, operated_only=False
254294
)
255295

256296
convolved = psf.convolved_image_from(
257-
image=image_over_sampled,
297+
image=self._binned_for_convolution(
298+
image_over_sampled, padded_grid, psf, xp=xp
299+
),
258300
blurring_image=None,
259301
mask=padded_mask,
260302
xp=xp,
@@ -416,8 +458,12 @@ def blurred_image_2d_list_from(
416458

417459
if convolution_mask is not None:
418460
blurred_image_2d = psf.convolved_image_from(
419-
image=image_2d_not_operated,
420-
blurring_image=blurring_image_2d_not_operated,
461+
image=self._binned_for_convolution(
462+
image_2d_not_operated, grid, psf
463+
),
464+
blurring_image=self._binned_for_convolution(
465+
blurring_image_2d_not_operated, blurring_grid, psf
466+
),
421467
mask=convolution_mask,
422468
)
423469
else:
@@ -584,6 +630,14 @@ def galaxy_blurred_image_2d_dict_from(
584630
galaxy_key
585631
]
586632

633+
if convolution_mask is not None:
634+
image_2d_not_operated = self._binned_for_convolution(
635+
image_2d_not_operated, grid, psf, xp=xp
636+
)
637+
blurring_image_2d_not_operated = self._binned_for_convolution(
638+
blurring_image_2d_not_operated, blurring_grid, psf, xp=xp
639+
)
640+
587641
blurred_image_2d = psf.convolved_image_from(
588642
image=image_2d_not_operated,
589643
blurring_image=blurring_image_2d_not_operated,

autogalaxy/profiles/light/linear/abstract.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,13 +355,23 @@ def operated_mapping_matrix_override(self) -> Optional[np.ndarray]:
355355

356356
blurred_image_2d_list = []
357357

358+
from autogalaxy.operate.image import OperateImage
359+
358360
for pixel, light_profile in enumerate(self.light_profile_list):
359361
image_2d = light_profile.image_2d_from(grid=evaluation_grid, xp=self._xp)
360362

361363
blurring_image_2d = light_profile.image_2d_from(
362364
grid=evaluation_blurring_grid, xp=self._xp
363365
)
364366

367+
if convolution_mask is not None:
368+
image_2d = OperateImage._binned_for_convolution(
369+
image_2d, self.grid, self.psf, xp=self._xp
370+
)
371+
blurring_image_2d = OperateImage._binned_for_convolution(
372+
blurring_image_2d, self.blurring_grid, self.psf, xp=self._xp
373+
)
374+
365375
blurred_image_2d = self.psf.convolved_image_from(
366376
image=image_2d,
367377
blurring_image=blurring_image_2d,

0 commit comments

Comments
 (0)