Skip to content

Commit

Permalink
remove OverSamplingDataset
Browse files Browse the repository at this point in the history
  • Loading branch information
Jammy2211 committed Dec 20, 2024
1 parent 78bf573 commit be571b5
Show file tree
Hide file tree
Showing 24 changed files with 242 additions and 206 deletions.
1 change: 0 additions & 1 deletion autoarray/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from .dataset.interferometer.dataset import Interferometer
from .dataset.interferometer.simulator import SimulatorInterferometer
from .dataset.interferometer.w_tilde import WTildeInterferometer
from .dataset.over_sampling import OverSamplingDataset
from .dataset.dataset_model import DatasetModel
from .fit.fit_dataset import AbstractFit
from .fit.fit_dataset import FitDataset
Expand Down
63 changes: 54 additions & 9 deletions autoarray/dataset/abstract/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
import warnings
from typing import Optional, Union

from autoarray.dataset.over_sampling import OverSamplingDataset
from autoconf import cached_property

from autoarray.dataset.grids import GridsDataset

from autoarray import exc
from autoarray.mask.mask_1d import Mask1D
from autoarray.mask.mask_2d import Mask2D
from autoarray.structures.abstract_structure import Structure
from autoarray.structures.arrays.uniform_2d import Array2D
from autoconf import cached_property

from autoarray.operators.over_sampling import over_sample_util


logger = logging.getLogger(__name__)
Expand All @@ -24,7 +26,8 @@ def __init__(
data: Structure,
noise_map: Structure,
noise_covariance_matrix: Optional[np.ndarray] = None,
over_sampling: Optional[OverSamplingDataset] = OverSamplingDataset(),
over_sample_size_lp: Union[int, Array2D] = 4,
over_sample_size_pixelization: Union[int, Array2D] = 4,
):
"""
An abstract dataset, containing the image data, noise-map, PSF and associated quantities for calculations
Expand All @@ -45,6 +48,32 @@ def __init__(
over sampling calculations built in which approximate the 2D line integral of these calculations within a
pixel. This is explained in more detail in the `GridsDataset` class.
**Over Sampling**
If a grid is uniform and the centre of each point on the grid is the centre of a 2D pixel, evaluating
the value of a function on the grid requires a 2D line integral to compute it precisely. This can be
computationally expensive and difficult to implement.
Over sampling is a numerical technique where the function is evaluated on a sub-grid within each grid pixel
which is higher resolution than the grid itself. This approximates more closely the value of the function
within a 2D line intergral of the values in the square pixel that the grid is centred.
For example, in PyAutoGalaxy and PyAutoLens the light profiles and galaxies are evaluated in order to determine
how much light falls in each pixel. This uses over sampling and therefore a higher resolution grid than the
image data to ensure the calculation is accurate.
This class controls how over sampling is performed for 2 different types of grids:
- `lp`: A grids of (y,x) coordinates which aligns with the centre of every image pixel of the image data
and is used to evaluate light profiles for model-fititng.
- `pixelization`: A grid of (y,x) coordinates which again align with the centre of every image pixel of
the image data. This grid is used specifically for pixelizations computed via the `inversion` module, which
can benefit from using different oversampling schemes than the normal grid.
Different calculations typically benefit from different over sampling, which this class enables
the customization of.
Parameters
----------
data
Expand All @@ -56,10 +85,13 @@ def __init__(
noise_covariance_matrix
A noise-map covariance matrix representing the covariance between noise in every `data` value, which
can be used via a bespoke fit to account for correlated noise in the data.
over_sampling
The over sampling schemes which divide the grids into sub grids of smaller pixels within their host image
pixels when using the grid to evaluate a function (e.g. images) to better approximate the 2D line integral
This class controls over sampling for all the different grids (e.g. `grid`, `grids.pixelization).
over_sample_size_lp
The over sampling scheme size, which divides the grid into a sub grid of smaller pixels when computing
values (e.g. images) from the grid to approximate the 2D line integral of the amount of light that falls
into each pixel.
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.
"""

self.data = data
Expand Down Expand Up @@ -93,15 +125,28 @@ def __init__(

self.noise_map = noise_map

self.over_sampling = over_sampling
self.over_sample_size_lp = (
over_sample_util.over_sample_size_convert_to_array_2d_from(
over_sample_size=over_sample_size_lp, mask=self.mask
)
)
self.over_sample_size_pixelization = (
over_sample_util.over_sample_size_convert_to_array_2d_from(
over_sample_size=over_sample_size_pixelization, mask=self.mask
)
)

@property
def grid(self):
return self.grids.lp

@cached_property
def grids(self):
return GridsDataset(mask=self.data.mask, over_sampling=self.over_sampling)
return GridsDataset(
mask=self.data.mask,
over_sample_size_lp=self.over_sample_size_lp,
over_sample_size_pixelization=self.over_sample_size_pixelization,
)

@property
def shape_native(self):
Expand Down
25 changes: 17 additions & 8 deletions autoarray/dataset/grids.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Optional, Union

from autoarray.dataset.over_sampling import OverSamplingDataset
from autoarray.mask.mask_2d import Mask2D
from autoarray.structures.arrays.uniform_2d import Array2D
from autoarray.structures.arrays.kernel_2d import Kernel2D
from autoarray.structures.grids.uniform_1d import Grid1D
from autoarray.structures.grids.uniform_2d import Grid2D
Expand All @@ -14,7 +14,8 @@ class GridsDataset:
def __init__(
self,
mask: Mask2D,
over_sampling: OverSamplingDataset,
over_sample_size_lp: Union[int, Array2D],
over_sample_size_pixelization: Union[int, Array2D],
psf: Optional[Kernel2D] = None,
):
"""
Expand Down Expand Up @@ -43,12 +44,20 @@ def __init__(
Parameters
----------
mask
over_sampling
over_sample_size_lp
The over sampling scheme size, which divides the grid into a sub grid of smaller pixels when computing
values (e.g. images) from the grid to approximate the 2D line integral of the amount of light that falls
into each pixel.
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.
psf
The Point Spread Function kernel of the image which accounts for diffraction due to the telescope optics
via 2D convolution.
"""
self.mask = mask
self.over_sampling = over_sampling
self.over_sample_size_lp = over_sample_size_lp
self.over_sample_size_pixelization = over_sample_size_pixelization
self.psf = psf

@cached_property
Expand All @@ -66,7 +75,7 @@ def lp(self) -> Union[Grid1D, Grid2D]:
"""
return Grid2D.from_mask(
mask=self.mask,
over_sample_size=self.over_sampling.lp,
over_sample_size=self.over_sample_size_lp,
)

@cached_property
Expand All @@ -87,7 +96,7 @@ def pixelization(self) -> Grid2D:
"""
return Grid2D.from_mask(
mask=self.mask,
over_sample_size=self.over_sampling.pixelization,
over_sample_size=self.over_sample_size_pixelization,
)

@cached_property
Expand Down Expand Up @@ -117,7 +126,7 @@ def blurring(self) -> Optional[Grid2D]:
@cached_property
def border_relocator(self) -> BorderRelocator:
return BorderRelocator(
mask=self.mask, sub_size=self.pixelization.over_sample_size
mask=self.mask, sub_size=self.over_sample_size_pixelization
)


Expand Down
77 changes: 47 additions & 30 deletions autoarray/dataset/imaging/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from autoarray.dataset.abstract.dataset import AbstractDataset
from autoarray.dataset.grids import GridsDataset
from autoarray.dataset.imaging.w_tilde import WTildeImaging
from autoarray.dataset.over_sampling import OverSamplingDataset
from autoarray.structures.arrays.uniform_2d import Array2D
from autoarray.operators.convolver import Convolver
from autoarray.structures.arrays.kernel_2d import Kernel2D
Expand All @@ -28,7 +27,8 @@ def __init__(
noise_map: Optional[Array2D] = None,
psf: Optional[Kernel2D] = None,
noise_covariance_matrix: Optional[np.ndarray] = None,
over_sampling: Optional[OverSamplingDataset] = OverSamplingDataset(),
over_sample_size_lp: Union[int, Array2D] = 4,
over_sample_size_pixelization: Union[int, Array2D] = 4,
pad_for_convolver: bool = False,
use_normalized_psf: Optional[bool] = True,
check_noise_map: bool = True,
Expand Down Expand Up @@ -69,10 +69,13 @@ def __init__(
noise_covariance_matrix
A noise-map covariance matrix representing the covariance between noise in every `data` value, which
can be used via a bespoke fit to account for correlated noise in the data.
over_sampling
The over sampling schemes which divide the grids into sub grids of smaller pixels within their host image
pixels when using the grid to evaluate a function (e.g. images) to better approximate the 2D line integral
This class controls over sampling for all the different grids (e.g. `grid`, `grids.pixelization).
over_sample_size_lp
The over sampling scheme size, which divides the grid into a sub grid of smaller pixels when computing
values (e.g. images) from the grid to approximate the 2D line integral of the amount of light that falls
into each pixel.
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
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
Expand Down Expand Up @@ -114,7 +117,8 @@ def __init__(
data=data,
noise_map=noise_map,
noise_covariance_matrix=noise_covariance_matrix,
over_sampling=over_sampling,
over_sample_size_lp=over_sample_size_lp,
over_sample_size_pixelization=over_sample_size_pixelization,
)

self.use_normalized_psf = use_normalized_psf
Expand Down Expand Up @@ -143,7 +147,10 @@ def __init__(
@cached_property
def grids(self):
return GridsDataset(
mask=self.data.mask, over_sampling=self.over_sampling, psf=self.psf
mask=self.data.mask,
over_sample_size_lp=self.over_sample_size_lp,
over_sample_size_pixelization=self.over_sample_size_pixelization,
psf=self.psf,
)

@cached_property
Expand Down Expand Up @@ -214,7 +221,8 @@ def from_fits(
psf_hdu: int = 0,
noise_covariance_matrix: Optional[np.ndarray] = None,
check_noise_map: bool = True,
over_sampling: Optional[OverSamplingDataset] = OverSamplingDataset(),
over_sample_size_lp: Union[int, Array2D] = 4,
over_sample_size_pixelization: Union[int, Array2D] = 4,
) -> "Imaging":
"""
Load an imaging dataset from multiple .fits file.
Expand Down Expand Up @@ -253,10 +261,13 @@ def from_fits(
A noise-map covariance matrix representing the covariance between noise in every `data` value.
check_noise_map
If True, the noise-map is checked to ensure all values are above zero.
over_sampling
The over sampling schemes which divide the grids into sub grids of smaller pixels within their host image
pixels when using the grid to evaluate a function (e.g. images) to better approximate the 2D line integral
This class controls over sampling for all the different grids (e.g. `grid`, `grids.pixelization).
over_sample_size_lp
The over sampling scheme size, which divides the grid into a sub grid of smaller pixels when computing
values (e.g. images) from the grid to approximate the 2D line integral of the amount of light that falls
into each pixel.
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.
"""

data = Array2D.from_fits(
Expand Down Expand Up @@ -284,7 +295,8 @@ def from_fits(
psf=psf,
noise_covariance_matrix=noise_covariance_matrix,
check_noise_map=check_noise_map,
over_sampling=over_sampling,
over_sample_size_lp=over_sample_size_lp,
over_sample_size_pixelization=over_sample_size_pixelization,
)

def apply_mask(self, mask: Mask2D) -> "Imaging":
Expand Down Expand Up @@ -323,12 +335,18 @@ def apply_mask(self, mask: Mask2D) -> "Imaging":
else:
noise_covariance_matrix = None

over_sample_size_lp = Array2D(values=self.over_sample_size_lp.native, mask=mask)
over_sample_size_pixelization = Array2D(
values=self.over_sample_size_pixelization.native, mask=mask
)

dataset = Imaging(
data=data,
noise_map=noise_map,
psf=self.psf,
noise_covariance_matrix=noise_covariance_matrix,
over_sampling=self.over_sampling,
over_sample_size_lp=over_sample_size_lp,
over_sample_size_pixelization=over_sample_size_pixelization,
pad_for_convolver=True,
)

Expand Down Expand Up @@ -416,7 +434,8 @@ def apply_noise_scaling(
noise_map=noise_map,
psf=self.psf,
noise_covariance_matrix=self.noise_covariance_matrix,
over_sampling=self.over_sampling,
over_sample_size_lp=self.over_sample_size_lp,
over_sample_size_pixelization=self.over_sample_size_pixelization,
pad_for_convolver=False,
check_noise_map=False,
)
Expand All @@ -429,7 +448,8 @@ def apply_noise_scaling(

def apply_over_sampling(
self,
over_sampling: Optional[OverSamplingDataset] = OverSamplingDataset(),
over_sample_size_lp: Union[int, Array2D] = None,
over_sample_size_pixelization: Union[int, Array2D] = None,
) -> "AbstractDataset":
"""
Apply new over sampling objects to the grid and grid pixelization of the dataset.
Expand All @@ -449,25 +469,22 @@ def apply_over_sampling(
Parameters
----------
over_sampling
The over sampling schemes which divide the grids into sub grids of smaller pixels within their host image
pixels when using the grid to evaluate a function (e.g. images) to better approximate the 2D line integral
This class controls over sampling for all the different grids (e.g. `grid`, `grids.pixelization).
over_sample_size_lp
The over sampling scheme size, which divides the grid into a sub grid of smaller pixels when computing
values (e.g. images) from the grid to approximate the 2D line integral of the amount of light that falls
into each pixel.
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.
"""

uniform = over_sampling.lp or self.over_sampling.lp
pixelization = over_sampling.pixelization or self.over_sampling.pixelization

over_sampling = OverSamplingDataset(
lp=uniform,
pixelization=pixelization,
)

return Imaging(
data=self.data,
noise_map=self.noise_map,
psf=self.psf,
over_sampling=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,
check_noise_map=False,
)
Expand Down
12 changes: 10 additions & 2 deletions autoarray/dataset/imaging/simulator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import numpy as np
from typing import Optional, Union

from autoarray.dataset.imaging.dataset import Imaging
from autoarray.structures.arrays.uniform_2d import Array2D
Expand Down Expand Up @@ -98,7 +99,9 @@ def __init__(
self.noise_if_add_noise_false = noise_if_add_noise_false
self.noise_seed = noise_seed

def via_image_from(self, image: Array2D) -> Imaging:
def via_image_from(
self, image: Array2D, over_sample_size: Optional[Union[int, np.ndarray]] = None
) -> Imaging:
"""
Simulate an `Imaging` dataset from an input image.
Expand Down Expand Up @@ -163,6 +166,11 @@ def via_image_from(self, image: Array2D) -> Imaging:

image = Array2D(values=image, mask=mask)

return Imaging(
dataset = Imaging(
data=image, psf=self.psf, noise_map=noise_map, check_noise_map=False
)

if over_sample_size is not None:
dataset = dataset.apply_over_sampling(over_sample_size_lp=over_sample_size)

return dataset
Loading

0 comments on commit be571b5

Please sign in to comment.