def __init__(self, kernel_super, supersampling_factor, conv_supersample_pixels, supersampling_kernel_size=None, compute_pixels=None, nopython=True, cache=True, parallel=False): """ :param kernel_super: convolution kernel in units of super sampled pixels provided, odd length per axis :param supersampling_factor: factor of supersampling relative to pixel grid :param conv_supersample_pixels: bool array same size as data, pixels to be convolved and their light to be blurred :param supersampling_kernel_size: number of pixels (in units of the image pixels) that are convolved with the supersampled kernel :param compute_pixels: bool array of size of image, these pixels (if True) will get blurred light from other pixels :param nopython: bool, numba jit setting to use python or compiled. :param cache: bool, numba jit setting to use cache :param parallel: bool, numba jit setting to use parallel mode """ kernel = kernel_util.degrade_kernel(kernel_super, degrading_factor=supersampling_factor) self._low_res_conv = PixelKernelConvolution(kernel, convolution_type='fft') if supersampling_kernel_size is None: supersampling_kernel_size = len(kernel) n_cut_super = supersampling_kernel_size * supersampling_factor if n_cut_super % 2 == 0: n_cut_super += 1 #kernel_super_cut = image_util.cut_edges(kernel_super, n_cut_super) #kernel_cut = kernel_util.degrade_kernel(kernel_super_cut, degrading_factor=supersampling_factor) kernel_super_cut = image_util.cut_edges(kernel_super, n_cut_super) kernel_cut = kernel_util.degrade_kernel(kernel_super_cut, degrading_factor=supersampling_factor) self._low_res_partial = NumbaConvolution(kernel_cut, conv_supersample_pixels, compute_pixels=compute_pixels, nopython=nopython, cache=cache, parallel=parallel, memory_raise=True) self._hig_res_partial = SubgridNumbaConvolution(kernel_super_cut, supersampling_factor, conv_supersample_pixels, compute_pixels=compute_pixels, nopython=nopython, cache=cache, parallel=parallel)#, kernel_size=len(kernel_cut)) self._supersampling_factor = supersampling_factor
def test_degrade_kernel(): subgrid_res = 2 x_grid, y_gird = Util.make_grid(19, 1., 1) sigma = 1.5 flux = gaussian.function(x_grid, y_gird, amp=1, sigma=sigma) kernel_super = Util.array2image(flux)/np.sum(flux) kernel_degraded = kernel_util.degrade_kernel(kernel_super, degrading_factor=subgrid_res) npt.assert_almost_equal(np.sum(kernel_degraded), 1, decimal=8) kernel_degraded = kernel_util.degrade_kernel(kernel_super, degrading_factor=3) npt.assert_almost_equal(np.sum(kernel_degraded), 1, decimal=8) kernel_degraded = kernel_util.degrade_kernel(kernel_super, degrading_factor=1) npt.assert_almost_equal(np.sum(kernel_degraded), 1, decimal=8)
def __init__(self, psf_type='NONE', fwhm=None, truncation=5, pixel_size=None, kernel_point_source=None, psf_error_map=None, point_source_supersampling_factor=1, kernel_point_source_init=None): """ :param psf_type: string, type of PSF: options are 'NONE', 'PIXEL', 'GAUSSIAN' :param fwhm: float, full width at half maximum, only required for 'GAUSSIAN' model :param truncation: float, Gaussian truncation (in units of sigma), only required for 'GAUSSIAN' model :param pixel_size: width of pixel (required for Gaussian model, not required when using in combination with ImageModel modules) :param kernel_point_source: 2d numpy array, odd length, centered PSF of a point source (if not normalized, will be normalized) :param psf_error_map: uncertainty in the PSF model per pixel (size of data, not super-sampled). 2d numpy array. Size can be larger or smaller than the pixel-sized PSF model and if so, will be matched. This error will be added to the pixel error around the position of point sources as follows: sigma^2_i += 'psf_error_map'_j * (point_source_flux_i)**2 :param point_source_supersampling_factor: int, supersampling factor of kernel_point_source :param kernel_point_source_init: memory of an initial point source kernel that gets passed through the psf iteration """ self.psf_type = psf_type self._pixel_size = pixel_size self.kernel_point_source_init = kernel_point_source_init if self.psf_type == 'GAUSSIAN': if fwhm is None: raise ValueError('fwhm must be set for GAUSSIAN psf type!') self._fwhm = fwhm self._sigma_gaussian = util.fwhm2sigma(self._fwhm) self._truncation = truncation self._point_source_supersampling_factor = 0 elif self.psf_type == 'PIXEL': if kernel_point_source is None: raise ValueError('kernel_point_source needs to be specified for PIXEL PSF type!') if len(kernel_point_source) % 2 == 0: raise ValueError('kernel needs to have odd axis number, not ', np.shape(kernel_point_source)) if point_source_supersampling_factor > 1: self._kernel_point_source_supersampled = kernel_point_source self._point_source_supersampling_factor = point_source_supersampling_factor kernel_point_source = kernel_util.degrade_kernel(self._kernel_point_source_supersampled, self._point_source_supersampling_factor) self._kernel_point_source = kernel_point_source / np.sum(kernel_point_source) elif self.psf_type == 'NONE': self._kernel_point_source = np.zeros((3, 3)) self._kernel_point_source[1, 1] = 1 else: raise ValueError("psf_type %s not supported!" % self.psf_type) if psf_error_map is not None: n_kernel = len(self.kernel_point_source) self._psf_error_map = kernel_util.match_kernel_size(psf_error_map, n_kernel) if self.psf_type == 'PIXEL' and point_source_supersampling_factor > 1: if len(psf_error_map) == len(self._kernel_point_source_supersampled): Warning('psf_error_map has the same size as the super-sampled kernel. Make sure the units in the' 'psf_error_map are on the down-sampled pixel scale.') self.psf_error_map_bool = True else: self.psf_error_map_bool = False
def test_degrade_kernel(): x_grid, y_gird = Util.make_grid(19 * 5, 1., 1) sigma = 1.5 amp = 2 flux = gaussian.function(x_grid, y_gird, amp=2, sigma=sigma) kernel_super = Util.array2image(flux) / np.sum(flux) * amp for degrading_factor in range(7): kernel_degraded = kernel_util.degrade_kernel( kernel_super, degrading_factor=degrading_factor + 1) npt.assert_almost_equal(np.sum(kernel_degraded), amp, decimal=8)
def error_map_estimate_new(self, psf_kernel, psf_kernel_list, ra_image, dec_image, point_amp, supersampling_factor, error_map_radius=None): """ relative uncertainty in the psf model (in quadrature) per pixel based on residuals achieved in the image :param psf_kernel: PSF kernel (super-sampled) :param psf_kernel_list: list of individual best PSF kernel estimates :param ra_image: image positions in angles :param dec_image: image positions in angles :param point_amp: image amplitude :param supersampling_factor: super-sampling factor :param error_map_radius: radius (in angle) to cut the error map :return: psf error map such that square of the uncertainty gets boosted by error_map * (psf * amp)**2 """ kernel_low = kernel_util.degrade_kernel(psf_kernel, supersampling_factor) error_map_list = np.zeros( (len(psf_kernel_list), len(kernel_low), len(kernel_low))) x_pos, y_pos = self._image_model_class.Data.map_coord2pix( ra_image, dec_image) for i, psf_kernel_i in enumerate(psf_kernel_list): kernel_low_i = kernel_util.degrade_kernel(psf_kernel_i, supersampling_factor) x, y, amp_i = x_pos[i], y_pos[i], point_amp[i] x_int = int(round(x)) y_int = int(round(y)) C_D_cutout = kernel_util.cutout_source( x_int, y_int, self._image_model_class.Data.C_D, len(kernel_low_i), shift=False) residuals_i = np.abs(kernel_low - kernel_low_i) residuals_i -= np.sqrt(C_D_cutout) / amp_i residuals_i[residuals_i < 0] = 0 error_map_list[i, :, :] = residuals_i**2 error_map = np.median(error_map_list, axis=0) error_map[kernel_low > 0] /= kernel_low[kernel_low > 0]**2 error_map = np.nan_to_num(error_map) error_map[error_map > 1] = 1 # cap on error to be the same # mask the error map outside a certain radius (can avoid double counting of errors when map is overlapping if error_map_radius is not None: pixel_scale = self._image_model_class.Data.pixel_width x_grid, y_grid = util.make_grid(numPix=len(error_map), deltapix=pixel_scale) mask = mask_util.mask_azimuthal(x_grid, y_grid, center_x=0, center_y=0, r=error_map_radius) error_map *= util.array2image(mask) return error_map