Source code for astrowisp.fake_image.piecewise_bicubic_psf

"""Defines the PiecewiseBicubicPSF class."""

import scipy.linalg
import numpy

from astrowisp.fake_image.piecewise_psf import PiecewisePSF
from astrowisp.fake_image.bipolynomial_psf_piece import BipolynomialPSFPiece

[docs] class PiecewiseBicubicPSF(PiecewisePSF): """ A piecewise PSF class where the PSF over each piece is a bi-cubic function. """ #Could not think of a reasonable way to split this function or decrease the #number of local variables without losing readability. #pylint: disable=too-many-locals
[docs] @staticmethod def _create_piece(boundaries, psf_parameters): """ Return a BicubicPSFPiece satisfying the given constraints. Args: The same as the arguments of __init__ Returns: psf_piece: A BicubicPSFPiece instance with parameters as specified by `psf_parameters`. """ matrix = numpy.empty((16, 16)) row_offset = 0 for vert_index in range(2): #y is a reasonable name for position vector y-component. #pylint: disable=invalid-name y = boundaries['y'][vert_index] #pylint: enable=invalid-name for horz_index in range(2): #y is a reasonable name for position vector y-component. #pylint: disable=invalid-name x = boundaries['x'][horz_index] #pylint: enable=invalid-name y_term = 1.0 column = 0 for y_pow in range(4): x_term = 1.0 for x_pow in range(4): if x == 0: dx_term = (1.0 if x_pow == 1 else 0.0) else: dx_term = x_pow * x_term / x if y == 0: dy_term = (1.0 if y_pow == 1 else 0.0) else: dy_term = y_pow * y_term / y matrix[row_offset, column] = x_term * y_term matrix[row_offset + 4, column] = dx_term * y_term matrix[row_offset + 8, column] = x_term * dy_term matrix[row_offset + 12, column] = dx_term * dy_term column += 1 x_term *= x y_term *= y row_offset += 1 rhs = numpy.empty(16) rhs[0 : 4] = psf_parameters['values'].flatten() rhs[4 : 8] = psf_parameters['d_dx'].flatten() rhs[8 : 12] = psf_parameters['d_dy'].flatten() rhs[12 : 16] = psf_parameters['d2_dxdy'].flatten() coefficients = scipy.linalg.solve(matrix, rhs) return BipolynomialPSFPiece(coefficients.reshape((4, 4)))
#pylint: enable=too-many-locals
[docs] def __init__(self, boundaries, psf_parameters): """ Initialize a PiecewiseBicubicPSF with the given shape. Args: boundaries: Dictionary (keys ``x`` and ``y``) listing the cell horizontal/vertical boundaries. psf_parameters: A dictionary of 2x2 structures with keys: * values: The values of the piece bi-cubic polynomial af the intersections of the horizontal & vertical ``boundaries``. * d_dx: The x derivatives of the piece bi-cubic polynomial af the intersections of the horizontal & vertical ``boundaries``. * d_dy: The y derivatives of the piece bi-cubic polynomial af the intersections of the horizontal & vertical ``boundaries``. * d2_dxdy: The x,y cross-derivatives of the piece bi-cubic polynomial af the intersections of the horizontal & vertical ``boundaries``. Returns: None """ pieces = [] for cell_y_index in range(len(boundaries['y']) - 1): pieces.append([]) for cell_x_index in range(len(boundaries['x']) - 1): pieces[-1].append( self._create_piece( boundaries={ 'x': boundaries['x'][cell_x_index : cell_x_index + 2], 'y': boundaries['y'][cell_y_index : cell_y_index + 2] }, psf_parameters={ 'values': psf_parameters['values'][ cell_y_index : cell_y_index + 2, cell_x_index : cell_x_index + 2 ], 'd_dx': psf_parameters['d_dx'][ cell_y_index : cell_y_index + 2, cell_x_index : cell_x_index + 2 ], 'd_dy': psf_parameters['d_dy'][ cell_y_index : cell_y_index + 2, cell_x_index : cell_x_index + 2 ], 'd2_dxdy': psf_parameters['d2_dxdy'][ cell_y_index : cell_y_index + 2, cell_x_index : cell_x_index + 2 ] } ) ) super().__init__(boundaries, pieces)