autogalaxy.OverSampler#
- class OverSampler[source]#
Bases:
objectOver samples grid calculations using a uniform sub-grid.
When a 2D grid of (y,x) coordinates is input into a function, the result is evaluated at every coordinate on the grid. When the grid is paired to a 2D image (e.g. an Array2D) the solution needs to approximate the 2D integral of that function in each pixel. Over sample objects define how this over-sampling is performed.
This object inputs a uniform sub-grid, where every image-pixel is split into a uniform grid of sub-pixels. The function is evaluated at every sub-pixel, and the final value in each pixel is computed by summing the contribution from all sub-pixels.
This is the simplest over-sampling method, but may not provide precise solutions for functions that vary significantly within a pixel. To achieve precision in these pixels a high sub_size is required, which can be computationally expensive as it is applied to every pixel.
Example
If the mask’s sub_size is > 1, the grid is defined as a sub-grid where each entry corresponds to the (y,x) coordinates at the centre of each sub-pixel of an unmasked pixel. The Grid2D is therefore stored as an ndarray of shape [total_unmasked_coordinates*sub_size**2, 2]
The sub-grid indexes are ordered such that pixels begin from the first (top-left) sub-pixel in the first unmasked pixel. Indexes then go over the sub-pixels in each unmasked pixel, for every unmasked pixel. Therefore, the sub-grid is an ndarray of shape [total_unmasked_coordinates*(sub_grid_shape)**2, 2].
For example:
grid[9, 1] - using a 2x2 sub-grid, gives the 3rd unmasked pixel’s 2nd sub-pixel x-coordinate.
grid[9, 1] - using a 3x3 sub-grid, gives the 2nd unmasked pixel’s 1st sub-pixel x-coordinate.
grid[27, 0] - using a 3x3 sub-grid, gives the 4th unmasked pixel’s 1st sub-pixel y-coordinate.
Below is a visual illustration of a sub grid. Indexing of each sub-pixel goes from the top-left corner. In contrast to the grid above, our illustration below restricts the mask to just 2 pixels, to keep the illustration brief.
x x x x x x x x x x x x x x x x x x x x This is an example mask.Mask2D, where: x x x x x x x x x x x x x x x x x x x x x = `True` (Pixel is masked and excluded from lens) x x x x O O x x x x O = `False` (Pixel is not masked and included in lens) x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
Our grid with a sub-size looks like it did before:
pixel_scales = 1.0" <--- -ve x +ve --> x x x x x x x x x x ^ x x x x x x x x x x I x x x x x x x x x x I y x x x x x x x x x x x +ve grid[0] = [0.5, -1.5] x x x x 0 1 x x x x y grid[1] = [0.5, -0.5] x x x x x x x x x x -ve x x x x x x x x x x I x x x x x x x x x x I x x x x x x x x x x \/ x x x x x x x x x x
However, if the sub-size is 2, we go to each unmasked pixel and allocate sub-pixel coordinates for it. For example, for pixel 0, if sub_size=2, we use a 2x2 sub-grid:
Pixel 0 - (2x2): y x grid[0] = [0.66, -1.66] I0I1I grid[1] = [0.66, -1.33] I2I3I grid[2] = [0.33, -1.66] grid[3] = [0.33, -1.33]
If we used a sub_size of 3, for the pixel we we would create a 3x3 sub-grid:
y x grid[0] = [0.75, -0.75] grid[1] = [0.75, -0.5] grid[2] = [0.75, -0.25] I0I1I2I grid[3] = [0.5, -0.75] I3I4I5I grid[4] = [0.5, -0.5] I6I7I8I grid[5] = [0.5, -0.25] grid[6] = [0.25, -0.75] grid[7] = [0.25, -0.5] grid[8] = [0.25, -0.25]
All sub-pixels in masked pixels have values (0.0, 0.0).
__Adaptive Oversampling__
By default, the sub-grid is the same size in every pixel (e.g. the value of sub_size is an integer that defines the size of the sub-grid for every pixel).
However, the sub_size can also be input as an Array2D, with varying integer values for each pixel. This is called adaptive over-sampling and is used to adapt the over-sampling to the bright regions of the data, saving computational time.
__Pixelization__
For pixelizations performed in the inversion module, over sampling is equally important. Now, the over sampling maps multiple data sub-pixels to pixels in the pixelization, where mappings are performed fractionally based on the sub-grid sizes.
The over sampling class has functions dedicated to mapping between the sub-grid and pixel-grid, for example slim_for_sub_slim.
The class OverSampling is used for the high level API, whereby this is where users input their preferred over-sampling configuration. This class, OverSampler, contains the functionality which actually performs the over-sampling calculations, but is hidden from the user.
- Parameters:
Methods
Convenience method to access the binned-up array in its 1D representation, which is a Grid2D stored as an
ndarrayof shape [total_unmasked_pixels, 2].Attributes
Derives a 1D
ndarraywhich maps every subgridded 1Dslimindex of theMask2Dto its non-subgridded 1Dslimindex.Returns True if the sub_size is uniform across all pixels in the mask.
The area of every sub-pixel in the mask.
A property that is only computed once per instance and then replaces itself with an ordinary attribute.
- property sub_is_uniform: bool#
Returns True if the sub_size is uniform across all pixels in the mask.
- property sub_pixel_areas: ndarray#
The area of every sub-pixel in the mask.
- binned_array_2d_from(array, xp=<module 'numpy' from '/home/docs/checkouts/readthedocs.org/user_builds/pyautogalaxy/envs/latest/lib/python3.11/site-packages/numpy/__init__.py'>)[source]#
Convenience method to access the binned-up array in its 1D representation, which is a Grid2D stored as an
ndarrayof shape [total_unmasked_pixels, 2].The binning up process converts a array from (y,x) values where each value is a coordinate on the sub-array to (y,x) values where each coordinate is at the centre of its mask (e.g. a array with a sub_size of 1). This is performed by taking the mean of all (y,x) values in each sub pixel.
If the array is stored in 1D it is return as is. If it is stored in 2D, it must first be mapped from 2D to 1D.
In PyAutoCTI all Array2D objects are used in their native representation without sub-gridding. Significant memory can be saved by only store this format, thus the native_binned_only config override can force this behaviour. It is recommended users do not use this option to avoid unexpected behaviour.
Old docstring:
For a sub-grid, every unmasked pixel of its 2D mask with shape (total_y_pixels, total_x_pixels) is divided into a finer uniform grid of shape (total_y_pixels*sub_size, total_x_pixels*sub_size). This routine computes the (y,x) scaled coordinates a the centre of every sub-pixel defined by this 2D mask array.
The sub-grid is returned on an array of shape (total_unmasked_pixels*sub_size**2, 2). y coordinates are stored in the 0 index of the second dimension, x coordinates in the 1 index. Masked coordinates are therefore removed and not included in the slimmed grid.
Grid2D are defined from the top-left corner, where the first unmasked sub-pixel corresponds to index 0. Sub-pixels that are part of the same mask array pixel are indexed next to one another, such that the second sub-pixel in the first pixel has index 1, its next sub-pixel has index 2, and so forth.
- property slim_for_sub_slim: ndarray#
Derives a 1D
ndarraywhich maps every subgridded 1Dslimindex of theMask2Dto its non-subgridded 1Dslimindex.For example, for the following
Mask2Dforsub_size=1:- ::
- [[True, True, True, True]
[True, False, False, True], [True, False, True, True], [True, True, True, True]]
This has three unmasked (
Falsevalues) which have theslimindexes:- ::
[0, 1, 2]
The array
slim_for_sub_slimis therefore:- ::
[0, 1, 2]
For a
Mask2Dwithsub_size=2each unmaskedFalseentry is split into a sub-pixel of size 2x2. Therefore the arrayslim_for_sub_slimbecomes:- ::
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]
Examples
import autoarray as aa mask_2d = aa.Mask2D( mask=[[True, True, True, True] [True, False, False, True], [True, False, True, True], [True, True, True, True]] pixel_scales=1.0, ) derive_indexes_2d = aa.DeriveIndexes2D(mask=mask_2d) print(derive_indexes_2d.slim_for_sub_slim)
- uniform_over_sampled#
A property that is only computed once per instance and then replaces itself with an ordinary attribute. Deleting the attribute resets the property.
Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76