Source code for astrowisp.fake_image.piecewise_psf

"""Declares the PiecewisePSF base class for piecewise PSF functions."""

from bisect import bisect

from astrowisp.psf_base import PSFBase

[docs] def get_piece_index(boundaries, coordinate): """ Return the index of the piece along one axis containing the given coord. Args: boundaries: The offsets relative to the PSF center where different PSF pieces meet along the direction in which we are trying to locate the piece index. coordinate: The coordinate we are trying to find the piece index of. Returns: ind: The index along the selected coordinate of the piece containing x. """ if coordinate == boundaries[-1]: return len(boundaries) - 2 return bisect(boundaries, coordinate) - 1
[docs] class PiecewisePSF(PSFBase): """Base clas for PSFs defined on a grid of pieces."""
[docs] def __init__(self, boundaries, pieces): """ Define a PSF with the given boundaries. Args: boundaries: Dictionary with keys `x` and `y` giving the offsets relative to the center of the horizontal piece boundaries. The PSF is zero left of the first or right of the last x boundary as wall as below the first and above the last y boundary. pieces: The pieces making up the PSF should be a class inherited from PSFPiece. Returns: None """ self._boundaries = boundaries self._pieces = pieces super().__init__()
[docs] def get_left_range(self): """Return how far the PSF extends to the left of center.""" return -self._boundaries['x'][0]
[docs] def get_right_range(self): """Return how far the PSF extends to the right of center.""" return self._boundaries['x'][-1]
[docs] def get_down_range(self): """Return how far the PSF extends downward of center.""" return -self._boundaries['y'][0]
[docs] def get_up_range(self): """Return how far the PSF extends upward of center.""" return self._boundaries['y'][-1]
#(x, y) is a reasonable way to specify the coordinates of an offset vector. #pylint: disable=invalid-name
[docs] def __call__(self, x, y): """See the documentation of PSFBase.__call__.""" if( x < self._boundaries['x'][0] or x > self._boundaries['x'][-1] or y < self._boundaries['y'][0] or y > self._boundaries['y'][-1] ): return 0.0 return self._pieces[ get_piece_index(self._boundaries['y'], y) ][ get_piece_index(self._boundaries['x'], x) ](x, y)
#pylint: enable=invalid-name
[docs] def integrate(self, left, bottom, width, height): """See documentation of PSFBase.integrate.""" result = 0.0 if width < 0: sign = -1 left = left + width width = abs(width) else: sign = 1 if height < 0: sign *= -1 bottom = bottom + height height = abs(height) for y_piece in range( max(0, get_piece_index(self._boundaries['y'], bottom)), min(get_piece_index(self._boundaries['y'], bottom + height) + 1, len(self._boundaries['y']) - 1) ): y_min = max(self._boundaries['y'][y_piece], bottom) y_max = min(height + bottom, self._boundaries['y'][y_piece + 1]) for x_piece in range( max(0, get_piece_index(self._boundaries['x'], left)), min(get_piece_index(self._boundaries['x'], left + width) + 1, len(self._boundaries['x']) - 1) ): piece = self._pieces[y_piece][x_piece] x_min = max(self._boundaries['x'][x_piece], left) x_max = min(width + left, self._boundaries['x'][x_piece + 1]) result += piece.integrate(x_min, y_min, x_max - x_min, y_max - y_min) return sign * result