Skip to content

Commit d68d5a0

Browse files
authored
Merge pull request #171 from Jammy2211/revert-167-feature/unit_tests
Revert "Feature/unit tests"
2 parents 5de1760 + 869a8e1 commit d68d5a0

File tree

99 files changed

+4745
-1494
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+4745
-1494
lines changed

autoarray/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from . import fixtures
55
from . import mock as m
66
from .numba_util import profile_func
7+
from .preloads import Preloads
78
from .dataset import preprocess
89
from .dataset.abstract.dataset import AbstractDataset
910
from .dataset.abstract.w_tilde import AbstractWTilde
@@ -54,6 +55,8 @@
5455
from .mask.derive.grid_2d import DeriveGrid2D
5556
from .mask.mask_1d import Mask1D
5657
from .mask.mask_2d import Mask2D
58+
from .operators.convolver import Convolver
59+
from .operators.convolver import Convolver
5760
from .operators.transformer import TransformerDFT
5861
from .operators.transformer import TransformerNUFFT
5962
from .operators.over_sampling.decorator import over_sample

autoarray/abstract_ndarray.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
from abc import ABC
66
from abc import abstractmethod
7-
import jax.numpy as jnp
7+
import numpy as np
88

99
from autoconf.fitsable import output_to_fits
1010

11-
from autoarray.numpy_wrapper import register_pytree_node, Array
11+
from autoarray.numpy_wrapper import numpy as npw, register_pytree_node, Array
1212

1313
from typing import TYPE_CHECKING
1414

@@ -83,7 +83,7 @@ def __init__(self, array):
8383

8484
def invert(self):
8585
new = self.copy()
86-
new._array = jnp.invert(new._array)
86+
new._array = np.invert(new._array)
8787
return new
8888

8989
@classmethod
@@ -105,7 +105,7 @@ def instance_flatten(cls, instance):
105105
@staticmethod
106106
def flip_hdu_for_ds9(values):
107107
if conf.instance["general"]["fits"]["flip_for_ds9"]:
108-
return jnp.flipud(values)
108+
return np.flipud(values)
109109
return values
110110

111111
@classmethod
@@ -114,11 +114,11 @@ def instance_unflatten(cls, aux_data, children):
114114
Unflatten a tuple of attributes (i.e. a pytree) into an instance of an autoarray class
115115
"""
116116
instance = cls.__new__(cls)
117-
for key, value in zip(aux_data, children):
117+
for key, value in zip(aux_data, children[1:]):
118118
setattr(instance, key, value)
119119
return instance
120120

121-
def with_new_array(self, array: jnp.ndarray) -> "AbstractNDArray":
121+
def with_new_array(self, array: np.ndarray) -> "AbstractNDArray":
122122
"""
123123
Copy this object but give it a new array.
124124
@@ -165,7 +165,7 @@ def __iter__(self):
165165

166166
@to_new_array
167167
def sqrt(self):
168-
return jnp.sqrt(self._array)
168+
return np.sqrt(self._array)
169169

170170
@property
171171
def array(self):
@@ -331,13 +331,13 @@ def __getitem__(self, item):
331331
result = self._array[item]
332332
if isinstance(item, slice):
333333
result = self.with_new_array(result)
334-
if isinstance(result, jnp.ndarray):
334+
if isinstance(result, np.ndarray):
335335
result = self.with_new_array(result)
336336
return result
337337

338338
def __setitem__(self, key, value):
339-
if isinstance(key, (jnp.ndarray, AbstractNDArray, Array)):
340-
self._array = jnp.where(key, value, self._array)
339+
if isinstance(key, (np.ndarray, AbstractNDArray, Array)):
340+
self._array = npw.where(key, value, self._array)
341341
else:
342342
self._array[key] = value
343343

autoarray/config/general.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ pixelization:
1616
voronoi_nn_max_interpolation_neighbors: 300
1717
structures:
1818
native_binned_only: false # If True, data structures are only stored in their native and binned format. This is used to reduce memory usage in autocti.
19+
test:
20+
preloads_check_threshold: 1.0 # If the figure of merit of a fit with and without preloads is greater than this threshold, the check preload test fails and an exception raised for a model-fit.
21+

autoarray/config/grids.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
radial_minimum:
2+
function_name:
3+
class_name: 1.0e-08

autoarray/dataset/imaging/dataset.py

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from autoarray.dataset.grids import GridsDataset
1010
from autoarray.dataset.imaging.w_tilde import WTildeImaging
1111
from autoarray.structures.arrays.uniform_2d import Array2D
12+
from autoarray.operators.convolver import Convolver
1213
from autoarray.structures.arrays.kernel_2d import Kernel2D
1314
from autoarray.mask.mask_2d import Mask2D
1415
from autoarray import type as ty
@@ -29,7 +30,7 @@ def __init__(
2930
noise_covariance_matrix: Optional[np.ndarray] = None,
3031
over_sample_size_lp: Union[int, Array2D] = 4,
3132
over_sample_size_pixelization: Union[int, Array2D] = 4,
32-
pad_for_psf: bool = False,
33+
pad_for_convolver: bool = False,
3334
use_normalized_psf: Optional[bool] = True,
3435
check_noise_map: bool = True,
3536
):
@@ -76,7 +77,7 @@ def __init__(
7677
over_sample_size_pixelization
7778
How over sampling is performed for the grid which is associated with a pixelization, which is therefore
7879
passed into the calculations performed in the `inversion` module.
79-
pad_for_psf
80+
pad_for_convolver
8081
The PSF convolution may extend beyond the edges of the image mask, which can lead to edge effects in the
8182
convolved image. If `True`, the image and noise-map are padded to ensure the PSF convolution does not
8283
extend beyond the edge of the image.
@@ -89,9 +90,9 @@ def __init__(
8990

9091
self.unmasked = None
9192

92-
self.pad_for_psf = pad_for_psf
93+
self.pad_for_convolver = pad_for_convolver
9394

94-
if pad_for_psf and psf is not None:
95+
if pad_for_convolver and psf is not None:
9596
try:
9697
data.mask.derive_mask.blurring_from(
9798
kernel_shape_native=psf.shape_native
@@ -161,15 +162,11 @@ def __init__(
161162

162163
if psf is not None and use_normalized_psf:
163164
psf = Kernel2D.no_mask(
164-
values=psf.native._array, pixel_scales=psf.pixel_scales, normalize=True
165+
values=psf.native, pixel_scales=psf.pixel_scales, normalize=True
165166
)
166167

167168
self.psf = psf
168169

169-
if psf is not None:
170-
if psf.mask.shape[0] % 2 == 0 or psf.mask.shape[1] % 2 == 0:
171-
raise exc.KernelException("Kernel2D Kernel2D must be odd")
172-
173170
@cached_property
174171
def grids(self):
175172
return GridsDataset(
@@ -179,6 +176,25 @@ def grids(self):
179176
psf=self.psf,
180177
)
181178

179+
@cached_property
180+
def convolver(self):
181+
"""
182+
Returns a `Convolver` from a mask and 2D PSF kernel.
183+
184+
The `Convolver` stores in memory the array indexing between the mask and PSF, enabling efficient 2D PSF
185+
convolution of images and matrices used for linear algebra calculations (see `operators.convolver`).
186+
187+
This uses lazy allocation such that the calculation is only performed when the convolver is used, ensuring
188+
efficient set up of the `Imaging` class.
189+
190+
Returns
191+
-------
192+
Convolver
193+
The convolver given the masked imaging data's mask and PSF.
194+
"""
195+
196+
return Convolver(mask=self.mask, kernel=self.psf)
197+
182198
@cached_property
183199
def w_tilde(self):
184200
"""
@@ -204,9 +220,9 @@ def w_tilde(self):
204220
indexes,
205221
lengths,
206222
) = inversion_imaging_util.w_tilde_curvature_preload_imaging_from(
207-
noise_map_native=np.array(self.noise_map.native.array).astype("float64"),
208-
kernel_native=np.array(self.psf.native.array).astype("float64"),
209-
native_index_for_slim_index=np.array(self.mask.derive_indexes.native_for_slim).astype("int"),
223+
noise_map_native=np.array(self.noise_map.native),
224+
kernel_native=np.array(self.psf.native),
225+
native_index_for_slim_index=self.mask.derive_indexes.native_for_slim,
210226
)
211227

212228
return WTildeImaging(
@@ -354,7 +370,7 @@ def apply_mask(self, mask: Mask2D) -> "Imaging":
354370
noise_covariance_matrix=noise_covariance_matrix,
355371
over_sample_size_lp=over_sample_size_lp,
356372
over_sample_size_pixelization=over_sample_size_pixelization,
357-
pad_for_psf=True,
373+
pad_for_convolver=True,
358374
)
359375

360376
dataset.unmasked = unmasked_dataset
@@ -409,20 +425,20 @@ def apply_noise_scaling(
409425
"""
410426

411427
if signal_to_noise_value is None:
412-
noise_map = np.array(self.noise_map.native.array)
413-
noise_map[mask.array == False] = noise_value
428+
noise_map = self.noise_map.native
429+
noise_map[mask == False] = noise_value
414430
else:
415431
noise_map = np.where(
416432
mask == False,
417-
np.median(self.data.native.array[mask.derive_mask.edge == False])
433+
np.median(self.data.native[mask.derive_mask.edge == False])
418434
/ signal_to_noise_value,
419-
self.noise_map.native.array,
435+
self.noise_map.native,
420436
)
421437

422438
if should_zero_data:
423-
data = np.where(np.invert(mask.array), 0.0, self.data.native.array)
439+
data = np.where(np.invert(mask), 0.0, self.data.native)
424440
else:
425-
data = self.data.native.array
441+
data = self.data.native
426442

427443
data_unmasked = Array2D.no_mask(
428444
values=data,
@@ -447,7 +463,7 @@ def apply_noise_scaling(
447463
noise_covariance_matrix=self.noise_covariance_matrix,
448464
over_sample_size_lp=self.over_sample_size_lp,
449465
over_sample_size_pixelization=self.over_sample_size_pixelization,
450-
pad_for_psf=False,
466+
pad_for_convolver=False,
451467
check_noise_map=False,
452468
)
453469

@@ -495,7 +511,7 @@ def apply_over_sampling(
495511
over_sample_size_lp=over_sample_size_lp or self.over_sample_size_lp,
496512
over_sample_size_pixelization=over_sample_size_pixelization
497513
or self.over_sample_size_pixelization,
498-
pad_for_psf=False,
514+
pad_for_convolver=False,
499515
check_noise_map=False,
500516
)
501517

autoarray/dataset/interferometer/dataset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,5 +276,5 @@ def output_to_fits(
276276
)
277277

278278
@property
279-
def psf(self):
279+
def convolver(self):
280280
return None

autoarray/dataset/preprocess.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,15 +263,15 @@ def edges_from(image, no_edges):
263263
edges = []
264264

265265
for edge_no in range(no_edges):
266-
top_edge = image.native.array[edge_no, edge_no : image.shape_native[1] - edge_no]
267-
bottom_edge = image.native.array[
266+
top_edge = image.native[edge_no, edge_no : image.shape_native[1] - edge_no]
267+
bottom_edge = image.native[
268268
image.shape_native[0] - 1 - edge_no,
269269
edge_no : image.shape_native[1] - edge_no,
270270
]
271-
left_edge = image.native.array[
271+
left_edge = image.native[
272272
edge_no + 1 : image.shape_native[0] - 1 - edge_no, edge_no
273273
]
274-
right_edge = image.native.array[
274+
right_edge = image.native[
275275
edge_no + 1 : image.shape_native[0] - 1 - edge_no,
276276
image.shape_native[1] - 1 - edge_no,
277277
]
@@ -328,7 +328,7 @@ def background_noise_map_via_edges_from(image, no_edges):
328328
def psf_with_odd_dimensions_from(psf):
329329
"""
330330
If the PSF kernel has one or two even-sized dimensions, return a PSF object where the kernel has odd-sized
331-
dimensions (odd-sized dimensions are required for 2D convolution).
331+
dimensions (odd-sized dimensions are required by a *Convolver*).
332332
333333
Kernels are rescaled using the scikit-image routine rescale, which performs rescaling via an interpolation
334334
routine. This may lead to loss of accuracy in the PSF kernel and it is advised that users, where possible,
@@ -517,8 +517,8 @@ def noise_map_with_signal_to_noise_limit_from(
517517
noise_map_limit = np.where(
518518
(signal_to_noise_map.native > signal_to_noise_limit)
519519
& (noise_limit_mask == False),
520-
np.abs(data.native.array) / signal_to_noise_limit,
521-
noise_map.native.array,
520+
np.abs(data.native) / signal_to_noise_limit,
521+
noise_map.native,
522522
)
523523

524524
mask = Mask2D.all_false(

autoarray/exc.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,17 @@ class PlottingException(Exception):
106106
pass
107107

108108

109+
class PreloadsException(Exception):
110+
"""
111+
Raises exceptions associated with the `preloads.py` module and `Preloads` class.
112+
113+
For example if the preloaded quantities lead to a change in figure of merit of a fit compared to a fit without
114+
preloading.
115+
"""
116+
117+
pass
118+
119+
109120
class ProfilingException(Exception):
110121
"""
111122
Raises exceptions associated with in-built profiling tools (e.g. the `profile_func` decorator).

0 commit comments

Comments
 (0)