Skip to content

Commit ea21935

Browse files
Jammy2211Jammy2211
authored andcommitted
extend preload making function
1 parent 51401b0 commit ea21935

File tree

10 files changed

+62
-186
lines changed

10 files changed

+62
-186
lines changed

autoarray/dataset/imaging/simulator.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,7 @@ def via_image_from(
179179
if over_sample_size is not None:
180180

181181
dataset = dataset.apply_over_sampling(
182-
over_sample_size_lp=over_sample_size.native,
183-
disable_fft_pad=True
182+
over_sample_size_lp=over_sample_size.native, disable_fft_pad=True
184183
)
185184

186185
return dataset

autoarray/inversion/inversion/abstract.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from autoarray.dataset.interferometer.dataset import Interferometer
1212
from autoarray.inversion.inversion.dataset_interface import DatasetInterface
1313
from autoarray.inversion.linear_obj.linear_obj import LinearObj
14+
from autoarray.inversion.linear_obj.func_list import AbstractLinearObjFuncList
1415
from autoarray.inversion.pixelization.mappers.abstract import AbstractMapper
1516
from autoarray.inversion.regularization.abstract import AbstractRegularization
1617
from autoarray.inversion.inversion.settings import SettingsInversion
@@ -416,11 +417,18 @@ def reconstruction(self) -> np.ndarray:
416417
"""
417418
if self.settings.use_positive_only_solver:
418419

419-
if self.preloads.source_pixel_zeroed_indices is not None:
420+
if (
421+
self.preloads.source_pixel_zeroed_indices is not None
422+
and self.settings.force_edge_pixels_to_zeros
423+
):
420424

421425
# ids of values which are not zeroed and therefore kept in soluiton, which is computed in preloads.
422426
ids_to_keep = self.preloads.source_pixel_zeroed_indices_to_keep
423427

428+
total_linear_light_profiles = self.cls_list_from(
429+
cls=AbstractLinearObjFuncList
430+
)
431+
424432
# Use advanced indexing to select rows/columns
425433
data_vector = self.data_vector[ids_to_keep]
426434
curvature_reg_matrix = self.curvature_reg_matrix[ids_to_keep][

autoarray/inversion/inversion/imaging/mapping.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def _data_vector_mapper(self) -> np.ndarray:
6262
"""
6363

6464
if not self.has(cls=AbstractMapper):
65-
return None
65+
return
6666

6767
data_vector = np.zeros(self.total_params)
6868

autoarray/inversion/pixelization/mesh/mesh_util.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,9 @@ def rectangular_edges_from(shape_native, pixel_scales):
352352
return jnp.stack(edges_list, axis=0)
353353

354354

355-
def rectangular_edge_pixel_list_from(shape_native: Tuple[int, int]) -> List[int]:
355+
def rectangular_edge_pixel_list_from(
356+
shape_native: Tuple[int, int], total_linear_light_profiles: int = 0
357+
) -> List[int]:
356358
"""
357359
Returns a list of the 1D indices of all pixels on the edge of a rectangular pixelization,
358360
based on its 2D shape.
@@ -381,7 +383,9 @@ def rectangular_edge_pixel_list_from(shape_native: Tuple[int, int]) -> List[int]
381383
right = (np.arange(1, rows - 1) + 1) * cols - 1
382384

383385
# Concatenate all edge indices
384-
edge_pixel_indices = np.concatenate([top, left, right, bottom])
386+
edge_pixel_indices = total_linear_light_profiles + np.concatenate(
387+
[top, left, right, bottom]
388+
)
385389

386390
# Sort and return
387391
return np.sort(edge_pixel_indices).tolist()

autoarray/operators/over_sampling/over_sample_util.py

Lines changed: 36 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -167,190 +167,60 @@ def sub_size_radial_bins_from(
167167
return sub_size_list[bin_indices]
168168

169169

170-
from autoarray.geometry import geometry_util
171-
172-
173170
def grid_2d_slim_over_sampled_via_mask_from(
174171
mask_2d: np.ndarray,
175172
pixel_scales: ty.PixelScales,
176173
sub_size: np.ndarray,
177174
origin: Tuple[float, float] = (0.0, 0.0),
178175
) -> np.ndarray:
179176
"""
180-
For a sub-grid, every unmasked pixel of its 2D mask with shape (total_y_pixels, total_x_pixels) is divided into
181-
a finer uniform grid of shape (total_y_pixels*sub_size, total_x_pixels*sub_size). This routine computes the (y,x)
182-
scaled coordinates at the centre of every sub-pixel defined by this 2D mask array.
177+
Compute a sub-sampled 2D grid of coordinates for every unmasked pixel,
178+
skipping pixels where sub_size == 0 (to avoid divide-by-zero).
179+
"""
183180

184-
The sub-grid is returned on an array of shape (total_unmasked_pixels*sub_size**2, 2). y coordinates are
185-
stored in the 0 index of the second dimension, x coordinates in the 1 index. Masked coordinates are therefore
186-
removed and not included in the slimmed grid.
181+
H, W = mask_2d.shape
182+
sy, sx = pixel_scales
183+
oy, ox = origin
187184

188-
Grid2D are defined from the top-left corner, where the first unmasked sub-pixel corresponds to index 0.
189-
Sub-pixels that are part of the same mask array pixel are indexed next to one another, such that the second
190-
sub-pixel in the first pixel has index 1, its next sub-pixel has index 2, and so forth.
185+
# 1) Find unmasked pixel indices in row-major order
186+
rows, cols = np.nonzero(~mask_2d)
187+
Npix = rows.size
191188

192-
Parameters
193-
----------
194-
mask_2d
195-
A 2D array of bools, where `False` values are unmasked and therefore included as part of the calculated
196-
sub-grid.
197-
pixel_scales
198-
The (y,x) scaled units to pixel units conversion factor of the 2D mask array.
199-
sub_size
200-
The size of the sub-grid that each pixel of the 2D mask array is divided into.
201-
origin
202-
The (y,x) origin of the 2D array, which the sub-grid is shifted around.
189+
if Npix == 0:
190+
return np.empty((0, 2), dtype=float)
203191

204-
Returns
205-
-------
206-
ndarray
207-
A slimmed sub grid of (y,x) scaled coordinates at the centre of every pixel unmasked pixel on the 2D mask
208-
array. The sub grid array has dimensions (total_unmasked_pixels*sub_size**2, 2).
192+
# 2) Broadcast or validate sub_size array
193+
sub_arr = np.asarray(sub_size)
194+
sub_arr = np.full(Npix, sub_arr, dtype=int) if sub_arr.size == 1 else sub_arr
209195

210-
Examples
211-
--------
212-
mask = np.array([[True, False, True],
213-
[False, False, False]
214-
[True, False, True]])
215-
grid_slim = grid_2d_slim_over_sampled_via_mask_from(mask=mask, pixel_scales=(0.5, 0.5), sub_size=1, origin=(0.0, 0.0))
216-
"""
196+
# 3) Mask out any pixels with invalid sub_size <= 0
197+
valid_mask = sub_arr > 0
198+
rows, cols, sub_arr = rows[valid_mask], cols[valid_mask], sub_arr[valid_mask]
217199

218-
pixels_in_mask = (np.size(mask_2d) - np.sum(mask_2d)).astype(int)
200+
if sub_arr.size == 0:
201+
return np.empty((0, 2), dtype=float)
219202

220-
if isinstance(sub_size, int):
221-
sub_size = np.full(fill_value=sub_size, shape=pixels_in_mask)
203+
# 4) Compute pixel centers
204+
cy = (H - 1) / 2.0
205+
cx = (W - 1) / 2.0
206+
y_pix = (cy - rows) * sy + oy
207+
x_pix = (cols - cx) * sx + ox
222208

223-
total_sub_pixels = np.sum(sub_size**2)
209+
# 5) For each valid pixel, generate its sub-pixel coords
210+
coords_list = []
211+
for i, s in enumerate(sub_arr):
212+
dy = sy / s
213+
dx = sx / s
224214

225-
grid_slim = np.zeros(shape=(total_sub_pixels, 2))
215+
y_off = np.linspace(+sy / 2 - dy / 2, -sy / 2 + dy / 2, s)
216+
x_off = np.linspace(-sx / 2 + dx / 2, +sx / 2 - dx / 2, s)
226217

227-
centres_scaled = geometry_util.central_scaled_coordinate_2d_from(
228-
shape_native=mask_2d.shape, pixel_scales=pixel_scales, origin=origin
229-
)
218+
y_sub, x_sub = np.meshgrid(y_off, x_off, indexing="ij")
219+
220+
coords = np.stack([y_pix[i] + y_sub.ravel(), x_pix[i] + x_sub.ravel()], axis=1)
221+
coords_list.append(coords)
230222

231-
index = 0
232-
sub_index = 0
233-
234-
for y in range(mask_2d.shape[0]):
235-
for x in range(mask_2d.shape[1]):
236-
if not mask_2d[y, x]:
237-
sub = sub_size[index]
238-
239-
y_sub_half = pixel_scales[0] / 2
240-
y_sub_step = pixel_scales[0] / (sub)
241-
242-
x_sub_half = pixel_scales[1] / 2
243-
x_sub_step = pixel_scales[1] / (sub)
244-
245-
y_scaled = (y - centres_scaled[0]) * pixel_scales[0]
246-
x_scaled = (x - centres_scaled[1]) * pixel_scales[1]
247-
248-
for y1 in range(sub):
249-
for x1 in range(sub):
250-
grid_slim[sub_index, 0] = -(
251-
y_scaled - y_sub_half + y1 * y_sub_step + (y_sub_step / 2.0)
252-
)
253-
grid_slim[sub_index, 1] = (
254-
x_scaled - x_sub_half + x1 * x_sub_step + (x_sub_step / 2.0)
255-
)
256-
sub_index += 1
257-
258-
index += 1
259-
260-
return grid_slim
261-
262-
263-
#
264-
265-
# def grid_2d_slim_over_sampled_via_mask_from(
266-
# mask_2d: np.ndarray,
267-
# pixel_scales: ty.PixelScales,
268-
# sub_size: np.ndarray,
269-
# origin: Tuple[float, float] = (0.0, 0.0),
270-
# ) -> np.ndarray:
271-
# """
272-
# For a sub-grid, every unmasked pixel of its 2D mask with shape (total_y_pixels, total_x_pixels) is divided into
273-
# a finer uniform grid of shape (total_y_pixels*sub_size, total_x_pixels*sub_size). This routine computes the (y,x)
274-
# scaled coordinates at the centre of every sub-pixel defined by this 2D mask array.
275-
#
276-
# The sub-grid is returned on an array of shape (total_unmasked_pixels*sub_size**2, 2). y coordinates are
277-
# stored in the 0 index of the second dimension, x coordinates in the 1 index. Masked coordinates are therefore
278-
# removed and not included in the slimmed grid.
279-
#
280-
# Grid2D are defined from the top-left corner, where the first unmasked sub-pixel corresponds to index 0.
281-
# Sub-pixels that are part of the same mask array pixel are indexed next to one another, such that the second
282-
# sub-pixel in the first pixel has index 1, its next sub-pixel has index 2, and so forth.
283-
#
284-
# Parameters
285-
# ----------
286-
# mask_2d
287-
# A 2D array of bools, where `False` values are unmasked and therefore included as part of the calculated
288-
# sub-grid.
289-
# pixel_scales
290-
# The (y,x) scaled units to pixel units conversion factor of the 2D mask array.
291-
# sub_size
292-
# The size of the sub-grid that each pixel of the 2D mask array is divided into.
293-
# origin
294-
# The (y,x) origin of the 2D array, which the sub-grid is shifted around.
295-
#
296-
# Returns
297-
# -------
298-
# ndarray
299-
# A slimmed sub grid of (y,x) scaled coordinates at the centre of every pixel unmasked pixel on the 2D mask
300-
# array. The sub grid array has dimensions (total_unmasked_pixels*sub_size**2, 2).
301-
#
302-
# Examples
303-
# --------
304-
# mask = np.array([[True, False, True],
305-
# [False, False, False]
306-
# [True, False, True]])
307-
# grid_slim = grid_2d_slim_over_sampled_via_mask_from(mask=mask, pixel_scales=(0.5, 0.5), sub_size=1, origin=(0.0, 0.0))
308-
# """
309-
#
310-
# H, W = mask_2d.shape
311-
# sy, sx = pixel_scales
312-
# oy, ox = origin
313-
#
314-
# # 1) Find unmasked pixel indices in row-major order
315-
# rows, cols = np.nonzero(~mask_2d)
316-
# Npix = rows.size
317-
#
318-
# # 2) Broadcast or validate sub_size array
319-
# sub_arr = np.asarray(sub_size)
320-
# sub_arr = np.full(Npix, sub_arr, dtype=int) if sub_arr.size == 1 else sub_arr
321-
#
322-
# # 3) Compute pixel centers (y ↑ up, x → right)
323-
# cy = (H - 1) / 2.0
324-
# cx = (W - 1) / 2.0
325-
# y_pix = (cy - rows) * sy + oy
326-
# x_pix = (cols - cx) * sx + ox
327-
#
328-
# # 4) For each pixel, generate its sub-pixel coords and collect
329-
# coords_list = []
330-
# for i in range(Npix):
331-
# s = sub_arr[i]
332-
# dy = sy / s
333-
# dx = sx / s
334-
#
335-
# # y offsets: from top (+sy/2 - dy/2) down to bottom (-sy/2 + dy/2)
336-
# y_off = np.linspace(+sy/2 - dy/2, -sy/2 + dy/2, s)
337-
# # x offsets: left to right
338-
# x_off = np.linspace(-sx/2 + dx/2, +sx/2 - dx/2, s)
339-
#
340-
# # build subgrid
341-
# y_sub, x_sub = np.meshgrid(y_off, x_off, indexing="ij")
342-
# y_sub = y_sub.ravel()
343-
# x_sub = x_sub.ravel()
344-
#
345-
# # center + offsets
346-
# y_center = y_pix[i]
347-
# x_center = x_pix[i]
348-
# coords = np.stack([y_center + y_sub, x_center + x_sub], axis=1)
349-
#
350-
# coords_list.append(coords)
351-
#
352-
# # 5) Concatenate all sub-pixel blocks in row-major pixel order
353-
# return np.vstack(coords_list)
223+
return np.vstack(coords_list)
354224

355225

356226
def over_sample_size_via_radial_bins_from(

autoarray/plot/mat_plot/two_d.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def __init__(
6565
serial_overscan_plot: Optional[w2d.SerialOverscanPlot] = None,
6666
use_log10: bool = False,
6767
plot_mask: bool = True,
68+
quick_update: bool = False,
6869
):
6970
"""
7071
Visualizes 2D data structures (e.g an `Array2D`, `Grid2D`, `VectorField`, etc.) using Matplotlib.
@@ -227,6 +228,7 @@ def __init__(
227228
self.plot_mask = plot_mask
228229

229230
self.is_for_subplot = False
231+
self.quick_update = quick_update
230232

231233
def plot_array(
232234
self,

autoarray/plot/wrap/base/output.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ def to_figure(
157157
overwrite=True,
158158
)
159159

160-
def subplot_to_figure(self, auto_filename: Optional[str] = None):
160+
def subplot_to_figure(
161+
self, auto_filename: Optional[str] = None, also_show: bool = False
162+
):
161163
"""
162164
Output a subplot figure, either as an image on the screen or to the hard-disk as a png or fits file.
163165
@@ -184,6 +186,9 @@ def subplot_to_figure(self, auto_filename: Optional[str] = None):
184186
elif format == "png" or format == "pdf":
185187
self.savefig(filename, output_path, format)
186188

189+
if also_show:
190+
plt.show()
191+
187192
def to_figure_output_mode(self, filename: str):
188193
global COUNT
189194

test_autoarray/config/general.yaml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,6 @@ numba:
1919
nopython: true
2020
parallel: false
2121
use_numba: true
22-
output:
23-
backup_every_update: 10
24-
grid_results_interval: 100
25-
log_every_update: 50
26-
log_file: output.log
27-
log_level: INFO
28-
model_results_decimal_places: 3
29-
model_results_every_update: 100
30-
remove_files: false
3122
pixelization:
3223
voronoi_nn_max_interpolation_neighbors: 300
3324
profiling:

test_autoarray/dataset/imaging/test_dataset.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ def make_test_data_path():
3333
return test_data_path
3434

3535

36-
3736
def test__noise_covariance_input__noise_map_uses_diag():
3837
image = aa.Array2D.ones(shape_native=(3, 3), pixel_scales=1.0)
3938
noise_covariance_matrix = np.ones(shape=(9, 9))

test_autoarray/structures/arrays/test_kernel_2d.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,4 @@ def test__convolve_imaged_from__via_fft__sizes_not_precomputed__compare_numerica
527527
image=masked_image, blurring_image=blurring_image
528528
)
529529

530-
assert blurred_fft.native.array[13, 13] == pytest.approx(
531-
228.5, rel=1e-6, abs=1e-6
532-
)
530+
assert blurred_fft.native.array[13, 13] == pytest.approx(228.5, rel=1e-6, abs=1e-6)

0 commit comments

Comments
 (0)