Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/over sampling refactor #159

Merged
merged 28 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bf1f2b8
all over samplers dont support None
Jammy2211 Dec 14, 2024
3ef3d60
remove Grid2D Iterate and sort bugs
Jammy2211 Dec 14, 2024
177bfda
mid way through big refactor removing a lor of ocer sampoling nonsens…
Jammy2211 Dec 15, 2024
b209f3e
fix over sample util tests and rename
Jammy2211 Dec 15, 2024
cdda058
structure tests pass
Jammy2211 Dec 15, 2024
a5ddad2
fix dataset tests
Jammy2211 Dec 15, 2024
eabb866
most tests fixed
Jammy2211 Dec 15, 2024
9ebe6f8
all tests pass
Jammy2211 Dec 15, 2024
d4a8ef3
black
Jammy2211 Dec 15, 2024
3e0f442
horrible refactor nearly done
Jammy2211 Dec 15, 2024
215baab
remove config nonsense
Jammy2211 Dec 15, 2024
73d6700
uniform -> lp
Jammy2211 Dec 15, 2024
1fab29e
border relocator refactor
Jammy2211 Dec 16, 2024
305f50e
simplify grid over sampled API
Jammy2211 Dec 16, 2024
4f7251e
simplify API
Jammy2211 Dec 16, 2024
9aff29b
noise scaling hacks
Jammy2211 Dec 16, 2024
6f01e62
fix
Jammy2211 Dec 16, 2024
3806cb7
undo changes
Jammy2211 Dec 16, 2024
64ec5e0
Merge branch 'main' into feature/over_sampling_refactor
Jammy2211 Dec 18, 2024
ad35938
remove Grid2DIRregularUniform
Jammy2211 Dec 18, 2024
ac082a3
Merge branch 'main' into feature/over_sampling_refactor
Jammy2211 Dec 18, 2024
62b688f
remove point Hilbert funciton
Jammy2211 Dec 19, 2024
78bf573
added apply_over_sampling to Grid2D
Jammy2211 Dec 19, 2024
be571b5
remove OverSamplingDataset
Jammy2211 Dec 20, 2024
1d20dda
fix bug
Jammy2211 Dec 20, 2024
b4548cc
dataset changes
Jammy2211 Jan 13, 2025
18ca6ef
docstring
Jammy2211 Jan 14, 2025
a3c1454
final clean up
Jammy2211 Jan 15, 2025
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
9 changes: 1 addition & 8 deletions 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 Expand Up @@ -69,14 +68,8 @@
from .structures.arrays.irregular import ArrayIrregular
from .structures.grids.uniform_1d import Grid1D
from .structures.grids.uniform_2d import Grid2D
from .operators.over_sampling.decorator import perform_over_sampling_from
from .operators.over_sampling.grid_oversampled import Grid2DOverSampled
from .operators.over_sampling.uniform import OverSamplingUniform
from .operators.over_sampling.iterate import OverSamplingIterate
from .operators.over_sampling.uniform import OverSamplerUniform
from .operators.over_sampling.iterate import OverSamplerIterate
from .operators.over_sampling.over_sampler import OverSampler
from .structures.grids.irregular_2d import Grid2DIrregular
from .structures.grids.irregular_2d import Grid2DIrregularUniform
from .structures.mesh.rectangular_2d import Mesh2DRectangular
from .structures.mesh.voronoi_2d import Mesh2DVoronoi
from .structures.mesh.delaunay_2d import Mesh2DDelaunay
Expand Down
5 changes: 2 additions & 3 deletions autoarray/config/visualize/plots.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ dataset: # Settings for plots of all datasets
data: false # Plot the individual data of every dataset?
noise_map: false # Plot the individual noise-map of every dataset?
signal_to_noise_map: false # Plot the individual signal-to-noise-map of every dataset?
over_sampling: false # Plot the over-sampling sub-size, used to evaluate light profiles, of every dataset?
over_sampling_non_uniform: false # Plot the over-sampling sub-size, used to evaluate non uniform grids, of every dataset?
over_sampling_pixelization: false # Plot the over-sampling sub-size, used to evaluate pixelizations, of every dataset?
over_sample_size_lp: false # Plot the over-sampling size, used to evaluate light profiles, of every dataset?
over_sample_size_pixelization: false # Plot the over-sampling size, used to evaluate pixelizations, of every dataset?
imaging: # Settings for plots of imaging datasets (e.g. ImagingPlotter)
psf: false
fit: # Settings for plots of all fits (e.g. FitImagingPlotter, FitInterferometerPlotter).
Expand Down
77 changes: 67 additions & 10 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.uniform
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 Expand Up @@ -161,4 +206,16 @@ def trimmed_after_convolution_from(self, kernel_shape) -> "AbstractDataset":
kernel_shape=kernel_shape
)

dataset.over_sample_size_lp = (
dataset.over_sample_size_lp.trimmed_after_convolution_from(
kernel_shape=kernel_shape
)
)

dataset.over_sample_size_pixelization = (
dataset.over_sample_size_pixelization.trimmed_after_convolution_from(
kernel_shape=kernel_shape
)
)

return dataset
84 changes: 21 additions & 63 deletions autoarray/dataset/grids.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
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

from autoarray.operators.over_sampling.uniform import OverSamplingUniform
from autoarray.inversion.pixelization.border_relocator import BorderRelocator
from autoconf import cached_property

Expand All @@ -15,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 All @@ -28,11 +28,6 @@ def __init__(
which is used for most normal calculations (e.g. evaluating the amount of light that falls in an pixel
from a light profile).

- `non_uniform`: A grid of (y,x) coordinates which aligns with the centre of every image pixel of the image
data, but where their values are going to be deflected to become non-uniform such that the adaptive over
sampling scheme used for the main grid does not apply. This is used to compute over sampled light profiles of
lensed sources in PyAutoLens.

- `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.
Expand All @@ -49,16 +44,24 @@ 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
def uniform(self) -> Union[Grid1D, Grid2D]:
def lp(self) -> Union[Grid1D, Grid2D]:
"""
Returns the grid of (y,x) Cartesian coordinates at the centre of every pixel in the masked data, which is used
to perform most normal calculations (e.g. evaluating the amount of light that falls in an pixel from a light
Expand All @@ -70,38 +73,9 @@ def uniform(self) -> Union[Grid1D, Grid2D]:
-------
The (y,x) coordinates of every pixel in the data.
"""

return Grid2D.from_mask(
mask=self.mask,
over_sampling=self.over_sampling.uniform,
)

@cached_property
def non_uniform(self) -> Optional[Union[Grid1D, Grid2D]]:
"""
Returns the grid of (y,x) Cartesian coordinates at the centre of every pixel in the masked data, but
with a different over sampling scheme designed for

where
their values are going to be deflected to become non-uniform such that the adaptive over sampling scheme used
for the main grid does not apply.

This is used to compute over sampled light profiles of lensed sources in PyAutoLens.


This grid is computed based on the mask, in particular its pixel-scale and sub-grid size.

Returns
-------
The (y,x) coordinates of every pixel in the data.
"""

if self.over_sampling.non_uniform is None:
return None

return Grid2D.from_mask(
mask=self.mask,
over_sampling=self.over_sampling.non_uniform,
over_sample_size=self.over_sample_size_lp,
)

@cached_property
Expand All @@ -120,15 +94,9 @@ def pixelization(self) -> Grid2D:
-------
The (y,x) coordinates of every pixel in the data, used for pixelization / inversion calculations.
"""

over_sampling = self.over_sampling.pixelization

if over_sampling is None:
over_sampling = OverSamplingUniform(sub_size=4)

return Grid2D.from_mask(
mask=self.mask,
over_sampling=over_sampling,
over_sample_size=self.over_sample_size_pixelization,
)

@cached_property
Expand All @@ -151,36 +119,26 @@ def blurring(self) -> Optional[Grid2D]:
if self.psf is None:
return None

return self.uniform.blurring_grid_via_kernel_shape_from(
return self.lp.blurring_grid_via_kernel_shape_from(
kernel_shape_native=self.psf.shape_native,
)

@cached_property
def over_sampler_non_uniform(self):
return self.non_uniform.over_sampling.over_sampler_from(mask=self.mask)

@cached_property
def over_sampler_pixelization(self):
return self.pixelization.over_sampling.over_sampler_from(mask=self.mask)

@cached_property
def border_relocator(self) -> BorderRelocator:
return BorderRelocator(
mask=self.mask, sub_size=self.pixelization.over_sampling.sub_size
mask=self.mask, sub_size=self.over_sample_size_pixelization
)


class GridsInterface:
def __init__(
self,
uniform=None,
non_uniform=None,
lp=None,
pixelization=None,
blurring=None,
border_relocator=None,
):
self.uniform = uniform
self.non_uniform = non_uniform
self.lp = lp
self.pixelization = pixelization
self.blurring = blurring
self.border_relocator = border_relocator
Loading
Loading