Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions autoarray/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@
from .mask.derive.grid_2d import DeriveGrid2D
from .mask.mask_1d import Mask1D
from .mask.mask_2d import Mask2D
from .operators.convolver import Convolver
from .operators.convolver import Convolver
from .operators.transformer import TransformerDFT
from .operators.transformer import TransformerNUFFT
from .operators.over_sampling.decorator import over_sample
Expand Down
37 changes: 10 additions & 27 deletions autoarray/dataset/imaging/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from autoarray.dataset.grids import GridsDataset
from autoarray.dataset.imaging.w_tilde import WTildeImaging
from autoarray.structures.arrays.uniform_2d import Array2D
from autoarray.operators.convolver import Convolver
from autoarray.structures.arrays.kernel_2d import Kernel2D
from autoarray.mask.mask_2d import Mask2D
from autoarray import type as ty
Expand All @@ -30,7 +29,7 @@ def __init__(
noise_covariance_matrix: Optional[np.ndarray] = None,
over_sample_size_lp: Union[int, Array2D] = 4,
over_sample_size_pixelization: Union[int, Array2D] = 4,
pad_for_convolver: bool = False,
pad_for_psf: bool = False,
use_normalized_psf: Optional[bool] = True,
check_noise_map: bool = True,
):
Expand Down Expand Up @@ -77,7 +76,7 @@ def __init__(
over_sample_size_pixelization
How over sampling is performed for the grid which is associated with a pixelization, which is therefore
passed into the calculations performed in the `inversion` module.
pad_for_convolver
pad_for_psf
The PSF convolution may extend beyond the edges of the image mask, which can lead to edge effects in the
convolved image. If `True`, the image and noise-map are padded to ensure the PSF convolution does not
extend beyond the edge of the image.
Expand All @@ -90,9 +89,9 @@ def __init__(

self.unmasked = None

self.pad_for_convolver = pad_for_convolver
self.pad_for_psf = pad_for_psf

if pad_for_convolver and psf is not None:
if pad_for_psf and psf is not None:
try:
data.mask.derive_mask.blurring_from(
kernel_shape_native=psf.shape_native
Expand Down Expand Up @@ -167,6 +166,9 @@ def __init__(

self.psf = psf

if psf.mask.shape[0] % 2 == 0 or psf.mask.shape[1] % 2 == 0:
raise exc.KernelException("Kernel2D Kernel2D must be odd")
Copy link
Collaborator

Choose a reason for hiding this comment

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

I have seen this before but never really understood, why do you want the PSF kernel to be odd?

Copy link
Owner Author

Choose a reason for hiding this comment

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

For real space convolution, even x even kernels can induce a half pixel shift depending on where you centre it. This meant that things like the lens model centres had a half pixel shift, in the end, I think.

Alternatively, you could sample the "peak" of the even x even PSF in the central 4 pixels, which means you don't fully sample its shape where it matters most.

This may not matter for an FFT? And certainly wont matter once we do PSF over sampling?

Its definitely a hack I am happy to see removed.


@cached_property
def grids(self):
return GridsDataset(
Expand All @@ -176,25 +178,6 @@ def grids(self):
psf=self.psf,
)

@cached_property
def convolver(self):
"""
Returns a `Convolver` from a mask and 2D PSF kernel.

The `Convolver` stores in memory the array indexing between the mask and PSF, enabling efficient 2D PSF
convolution of images and matrices used for linear algebra calculations (see `operators.convolver`).

This uses lazy allocation such that the calculation is only performed when the convolver is used, ensuring
efficient set up of the `Imaging` class.

Returns
-------
Convolver
The convolver given the masked imaging data's mask and PSF.
"""

return Convolver(mask=self.mask, kernel=Kernel2D(values=self.psf._array, mask=self.psf.mask, header=self.psf.header))

@cached_property
def w_tilde(self):
"""
Expand Down Expand Up @@ -370,7 +353,7 @@ def apply_mask(self, mask: Mask2D) -> "Imaging":
noise_covariance_matrix=noise_covariance_matrix,
over_sample_size_lp=over_sample_size_lp,
over_sample_size_pixelization=over_sample_size_pixelization,
pad_for_convolver=True,
pad_for_psf=True,
)

dataset.unmasked = unmasked_dataset
Expand Down Expand Up @@ -463,7 +446,7 @@ def apply_noise_scaling(
noise_covariance_matrix=self.noise_covariance_matrix,
over_sample_size_lp=self.over_sample_size_lp,
over_sample_size_pixelization=self.over_sample_size_pixelization,
pad_for_convolver=False,
pad_for_psf=False,
check_noise_map=False,
)

Expand Down Expand Up @@ -511,7 +494,7 @@ def apply_over_sampling(
over_sample_size_lp=over_sample_size_lp or self.over_sample_size_lp,
over_sample_size_pixelization=over_sample_size_pixelization
or self.over_sample_size_pixelization,
pad_for_convolver=False,
pad_for_psf=False,
check_noise_map=False,
)

Expand Down
2 changes: 1 addition & 1 deletion autoarray/dataset/interferometer/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,5 +276,5 @@ def output_to_fits(
)

@property
def convolver(self):
def psf(self):
return None
2 changes: 1 addition & 1 deletion autoarray/dataset/preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ def background_noise_map_via_edges_from(image, no_edges):
def psf_with_odd_dimensions_from(psf):
"""
If the PSF kernel has one or two even-sized dimensions, return a PSF object where the kernel has odd-sized
dimensions (odd-sized dimensions are required by a *Convolver*).
dimensions (odd-sized dimensions are required for 2D convolution).

Kernels are rescaled using the scikit-image routine rescale, which performs rescaling via an interpolation
routine. This may lead to loss of accuracy in the PSF kernel and it is advised that users, where possible,
Expand Down
7 changes: 0 additions & 7 deletions autoarray/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,6 @@ def make_blurring_grid_2d_7x7():
return aa.Grid2D.from_mask(mask=make_blurring_mask_2d_7x7())


# CONVOLVERS #


def make_convolver_7x7():
return aa.Convolver(mask=make_mask_2d_7x7(), kernel=make_psf_3x3())


def make_image_7x7():
return aa.Array2D.ones(shape_native=(7, 7), pixel_scales=(1.0, 1.0))

Expand Down
21 changes: 9 additions & 12 deletions autoarray/geometry/geometry_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ def convert_pixel_scales_2d(pixel_scales: ty.PixelScales) -> Tuple[float, float]

return pixel_scales


@numba_util.jit()
def central_pixel_coordinates_2d_numba_from(
shape_native: Tuple[int, int],
Expand All @@ -205,6 +206,7 @@ def central_pixel_coordinates_2d_numba_from(
"""
return (float(shape_native[0] - 1) / 2, float(shape_native[1] - 1) / 2)


@numba_util.jit()
def central_scaled_coordinate_2d_numba_from(
shape_native: Tuple[int, int],
Expand Down Expand Up @@ -305,6 +307,7 @@ def central_scaled_coordinate_2d_from(

return (y_pixel, x_pixel)


def pixel_coordinates_2d_from(
scaled_coordinates_2d: Tuple[float, float],
shape_native: Tuple[int, int],
Expand Down Expand Up @@ -589,9 +592,9 @@ def grid_pixel_centres_2d_slim_from(
centres_scaled = np.array(centres_scaled)
pixel_scales = np.array(pixel_scales)
sign = np.array([-1.0, 1.0])
return (
(sign * grid_scaled_2d_slim / pixel_scales) + centres_scaled + 0.5
).astype(int)
return ((sign * grid_scaled_2d_slim / pixel_scales) + centres_scaled + 0.5).astype(
int
)


def grid_pixel_indexes_2d_slim_from(
Expand Down Expand Up @@ -647,9 +650,7 @@ def grid_pixel_indexes_2d_slim_from(
)

return (
(grid_pixels_2d_slim * np.array([shape_native[1], 1]))
.sum(axis=1)
.astype(int)
(grid_pixels_2d_slim * np.array([shape_native[1], 1])).sum(axis=1).astype(int)
)


Expand Down Expand Up @@ -698,9 +699,7 @@ def grid_scaled_2d_slim_from(
centres_scaled = np.array(centres_scaled)
pixel_scales = np.array(pixel_scales)
sign = np.array([-1, 1])
return (
(grid_pixels_2d_slim - centres_scaled - 0.5) * pixel_scales * sign
)
return (grid_pixels_2d_slim - centres_scaled - 0.5) * pixel_scales * sign


def grid_pixel_centres_2d_from(
Expand Down Expand Up @@ -750,9 +749,7 @@ def grid_pixel_centres_2d_from(
centres_scaled = np.array(centres_scaled)
pixel_scales = np.array(pixel_scales)
sign = np.array([-1.0, 1.0])
return (
(sign * grid_scaled_2d / pixel_scales) + centres_scaled + 0.5
).astype(int)
return ((sign * grid_scaled_2d / pixel_scales) + centres_scaled + 0.5).astype(int)


def extent_symmetric_from(
Expand Down
6 changes: 3 additions & 3 deletions autoarray/inversion/inversion/dataset_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ def __init__(
data,
noise_map,
grids=None,
convolver=None,
psf=None,
transformer=None,
w_tilde=None,
noise_covariance_matrix=None,
Expand Down Expand Up @@ -41,7 +41,7 @@ def __init__(
border_relocator
The border relocator, which relocates coordinates outside the border of the source-plane data grid to its
edge.
convolver
psf
Perform 2D convolution of the imaigng data's PSF when computing the operated mapping matrix.
transformer
Performs a Fourier transform of the image-data from real-space to visibilities when computing the
Expand All @@ -59,7 +59,7 @@ def __init__(
self.data = data
self.noise_map = noise_map
self.grids = grids
self.convolver = convolver
self.psf = psf
self.transformer = transformer
self.w_tilde = w_tilde
self.noise_covariance_matrix = noise_covariance_matrix
Expand Down
3 changes: 1 addition & 2 deletions autoarray/inversion/inversion/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,7 @@ def inversion_interferometer_from(
dataset
The dataset (e.g. `Interferometer`) whose data is reconstructed via the `Inversion`.
w_tilde
Object which uses the `Imaging` dataset's PSF / `Convolver` operateor to perform the `Inversion` using the
w-tilde formalism.
Object which uses the `Imaging` dataset's PSF to perform the `Inversion` using the w-tilde formalism.
linear_obj_list
The list of linear objects (e.g. analytic functions, a mapper with a pixelized grid) which reconstruct the
input dataset's data and whose values are solved for via the inversion.
Expand Down
15 changes: 7 additions & 8 deletions autoarray/inversion/inversion/imaging/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ def __init__(
of the linear object parameters that best reconstruct the dataset to be solved, via linear matrix algebra.

This object contains matrices and vectors which perform an inversion for fits to an `Imaging` dataset. This
includes operations which use a PSF / `Convolver` in order to incorporate blurring into the solved for
linear object pixels.
includes operations which use a PSF in order to incorporate blurring into the solved for linear object pixels.

The inversion may be regularized, whereby the parameters of the linear objects used to reconstruct the data
are smoothed with one another such that their solved for values conform to certain properties (e.g. smoothness
Expand Down Expand Up @@ -76,8 +75,8 @@ def __init__(
)

@property
def convolver(self):
return self.dataset.convolver
def psf(self):
return self.dataset.psf

@property
def operated_mapping_matrix_list(self) -> List[np.ndarray]:
Expand All @@ -88,15 +87,15 @@ def operated_mapping_matrix_list(self) -> List[np.ndarray]:
This is used to construct the simultaneous linear equations which reconstruct the data.

This property returns the a list of each linear object's blurred mapping matrix, which is computed by
blurring each linear object's `mapping_matrix` property with the `Convolver` operator.
blurring each linear object's `mapping_matrix` property with the `psf` operator.

A linear object may have a `operated_mapping_matrix_override` property, which bypasses the `mapping_matrix`
computation and convolution operator and is directly placed in the `operated_mapping_matrix_list`.
"""

return [
(
self.convolver.convolve_mapping_matrix(
self.psf.convolve_mapping_matrix(
mapping_matrix=linear_obj.mapping_matrix
)
if linear_obj.operated_mapping_matrix_override is None
Expand Down Expand Up @@ -139,7 +138,7 @@ def linear_func_operated_mapping_matrix_dict(self) -> Dict:
if linear_func.operated_mapping_matrix_override is not None:
operated_mapping_matrix = linear_func.operated_mapping_matrix_override
else:
operated_mapping_matrix = self.convolver.convolve_mapping_matrix(
operated_mapping_matrix = self.psf.convolve_mapping_matrix(
mapping_matrix=linear_func.mapping_matrix
)

Expand Down Expand Up @@ -221,7 +220,7 @@ def mapper_operated_mapping_matrix_dict(self) -> Dict:
mapper_operated_mapping_matrix_dict = {}

for mapper in self.cls_list_from(cls=AbstractMapper):
operated_mapping_matrix = self.convolver.convolve_mapping_matrix(
operated_mapping_matrix = self.psf.convolve_mapping_matrix(
mapping_matrix=mapper.mapping_matrix
)

Expand Down
10 changes: 4 additions & 6 deletions autoarray/inversion/inversion/imaging/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,8 @@ def __init__(

Parameters
----------
noise_map
The noise-map of the observed imaging data which values are solved for.
convolver
The convolver which performs a 2D convolution on the mapping matrix with the imaging data's PSF.
dataset
The dataset containing the image data, noise-map and psf which is fitted by the inversion.
linear_obj_list
The linear objects used to reconstruct the data's observed values. If multiple linear objects are passed
the simultaneous linear equations are combined and solved simultaneously.
Expand Down Expand Up @@ -80,7 +78,7 @@ def _data_vector_mapper(self) -> np.ndarray:
mapper = mapper_list[i]
param_range = mapper_param_range_list[i]

operated_mapping_matrix = self.convolver.convolve_mapping_matrix(
operated_mapping_matrix = self.psf.convolve_mapping_matrix(
mapping_matrix=mapper.mapping_matrix
)

Expand Down Expand Up @@ -142,7 +140,7 @@ def _curvature_matrix_mapper_diag(self) -> Optional[np.ndarray]:
mapper_i = mapper_list[i]
mapper_param_range_i = mapper_param_range_list[i]

operated_mapping_matrix = self.convolver.convolve_mapping_matrix(
operated_mapping_matrix = self.psf.convolve_mapping_matrix(
mapping_matrix=mapper_i.mapping_matrix
)

Expand Down
13 changes: 5 additions & 8 deletions autoarray/inversion/inversion/imaging/w_tilde.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,8 @@ def __init__(

Parameters
----------
noise_map
The noise-map of the observed imaging data which values are solved for.
convolver
The convolver used to perform 2D convolution of the imaigng data's PSF when computing the operated
mapping matrix.
dataset
The dataset containing the image data, noise-map and psf which is fitted by the inversion.
w_tilde
An object containing matrices that construct the linear equations via the w-tilde formalism which bypasses
the mapping matrix.
Expand Down Expand Up @@ -76,7 +73,7 @@ def w_tilde_data(self):
return inversion_imaging_util.w_tilde_data_imaging_from(
image_native=np.array(self.data.native),
noise_map_native=np.array(self.noise_map.native),
kernel_native=np.array(self.convolver.kernel.native),
kernel_native=np.array(self.psf.kernel.native),
native_index_for_slim_index=self.data.mask.derive_indexes.native_for_slim,
)

Expand Down Expand Up @@ -528,8 +525,8 @@ def mapped_reconstructed_data_dict(self) -> Dict[LinearObj, Array2D]:
values=mapped_reconstructed_image, mask=self.mask
)

mapped_reconstructed_image = self.convolver.convolve_image_no_blurring(
image=mapped_reconstructed_image
mapped_reconstructed_image = self.psf.convolve_image_no_blurring(
image=mapped_reconstructed_image, mask=self.mask
)

else:
Expand Down
2 changes: 1 addition & 1 deletion autoarray/inversion/linear_obj/linear_obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def pixel_signals_from(self, signal_scale) -> np.ndarray:
def operated_mapping_matrix_override(self) -> Optional[np.ndarray]:
"""
An `Inversion` takes the `mapping_matrix` of each linear object and combines it with the data's operators
(e.g. a `Convolver` for `Imaging` data) to compute the `operated_mapping_matrix`.
(e.g. a PSF for `Imaging` data) to compute the `operated_mapping_matrix`.

If this property is overwritten this operation is not performed, with the `operated_mapping_matrix` output
by this property automatically used instead.
Expand Down
Loading
Loading