def test_kernel_subsampled(self): deltaPix = 0.05 # pixel size of image numPix = 40 # number of pixels per axis subsampling_res = 3 # subsampling scale factor (in each dimension) fwhm = 0.3 # FWHM of the PSF kernel fwhm_object = 0.2 # FWHM of the Gaussian source to be convolved # create Gaussian/Pixelized kernels # first we create the sub-sampled kernel kernel_point_source_subsampled = kernel_util.kernel_gaussian(kernel_numPix=11*subsampling_res, deltaPix=deltaPix/subsampling_res, fwhm=fwhm) # to have the same consistent kernel, we re-size (average over the sub-sampled pixels) the sub-sampled kernel kernel_point_source = image_util.re_size(kernel_point_source_subsampled, subsampling_res) # here we create the two PSF() classes kwargs_pixel_subsampled = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_point_source_subsampled, 'point_source_supersampling_factor': subsampling_res} psf_pixel_subsampled = PSF(**kwargs_pixel_subsampled) psf_pixel_subsampled.kernel_point_source_supersampled(supersampling_factor=subsampling_res+1) kernel_point_source /= np.sum(kernel_point_source) kwargs_pixel = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_point_source} psf_pixel = PSF(**kwargs_pixel) kernel_point_source = psf_pixel.kernel_point_source kernel_super = psf_pixel.kernel_point_source_supersampled(supersampling_factor=3) npt.assert_almost_equal(np.sum(kernel_point_source), np.sum(kernel_super), decimal=8) npt.assert_almost_equal(np.sum(kernel_point_source), 1, decimal=8) deltaPix = 0.05 # pixel size of image numPix = 40 # number of pixels per axis subsampling_res = 4 # subsampling scale factor (in each dimension) fwhm = 0.3 # FWHM of the PSF kernel fwhm_object = 0.2 # FWHM of the Gaussian source to be convolved # create Gaussian/Pixelized kernels # first we create the sub-sampled kernel kernel_point_source_subsampled = kernel_util.kernel_gaussian(kernel_numPix=11 * subsampling_res + 1, deltaPix=deltaPix / subsampling_res, fwhm=fwhm) kwargs_pixel_subsampled = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_point_source_subsampled, 'point_source_supersampling_factor': subsampling_res} psf_pixel_subsampled = PSF(**kwargs_pixel_subsampled) kernel_point_source /= np.sum(kernel_point_source) kwargs_pixel = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_point_source} psf_pixel = PSF(**kwargs_pixel) kernel_point_source = psf_pixel.kernel_point_source kernel_point_source_new = psf_pixel_subsampled.kernel_point_source npt.assert_almost_equal(np.sum(kernel_point_source), np.sum(kernel_point_source_new), decimal=8) npt.assert_almost_equal(np.sum(kernel_point_source), 1, decimal=8) psf_none = PSF(psf_type='NONE') kernel_super = psf_none.kernel_point_source_supersampled(supersampling_factor=5) npt.assert_almost_equal(kernel_super, psf_none.kernel_point_source, decimal=9)
def test_raise(self): psf = PSF(psf_type='PIXEL', kernel_point_source=np.ones((3, 3))) psf.psf_type = 'WRONG' with self.assertRaises(ValueError): PSF(psf_type='GAUSSIAN') with self.assertRaises(ValueError): PSF(psf_type='PIXEL') with self.assertRaises(ValueError): PSF(psf_type='PIXEL', kernel_point_source=np.ones((2, 2))) with self.assertRaises(ValueError): PSF(psf_type='WRONG') with self.assertRaises(ValueError): PSF(psf_type='PIXEL', kernel_point_source=np.ones((3, 3)), psf_error_map=np.ones((5, 5))) psf.kernel_point_source_supersampled(supersampling_factor=3) with self.assertRaises(ValueError): psf = PSF(psf_type='PIXEL', kernel_point_source=np.ones((3, 3))) psf.psf_type = 'WRONG' psf.kernel_point_source_supersampled(supersampling_factor=3) with self.assertRaises(ValueError): psf = PSF(psf_type='GAUSSIAN', fwhm=100, pixel_size=0.0001) psf.kernel_point_source_supersampled(supersampling_factor=3) with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("always") # Trigger a warning. kernel_point_source_subsampled = np.ones((9, 9)) subsampling_res = 3 kwargs_pixel_subsampled = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_point_source_subsampled, 'point_source_supersampling_factor': subsampling_res} psf_pixel_subsampled = PSF(**kwargs_pixel_subsampled) psf_pixel_subsampled.kernel_point_source_supersampled(supersampling_factor=subsampling_res + 4) # Verify some things assert 1 == 1
def test_kernel_point_source(self): kernel_gaussian = self.psf_gaussian.kernel_point_source kernel_pixel = self.psf_pixel.kernel_point_source assert len(kernel_gaussian) == 21 assert len(kernel_pixel) == 21 kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': 0.2, 'truncation': 3, 'pixel_size': 0.05} psf_class = PSF(**kwargs_psf) kernel_point_source = psf_class.kernel_point_source assert len(kernel_point_source) == 13 kernel_super = psf_class.kernel_point_source_supersampled(supersampling_factor=3) assert np.sum(kernel_point_source) == np.sum(kernel_super) assert np.sum(kernel_point_source) == 1
def update_psf(self, kwargs_psf, kwargs_params, stacking_method='median', psf_symmetry=1, psf_iter_factor=.2, block_center_neighbour=0, error_map_radius=None, block_center_neighbour_error_map=None, new_procedure=True): """ :param kwargs_psf: keyword arguments to construct the PSF() class :param kwargs_params: keyword arguments of the parameters of the model components (e.g. 'kwargs_lens' etc) :param stacking_method: 'median', 'mean'; the different estimates of the PSF are stacked and combined together. The choices are: 'mean': mean of pixel values as the estimator (not robust to outliers) 'median': median of pixel values as the estimator (outlier rejection robust but needs >2 point sources in the data :param psf_symmetry: number of rotational invariant symmetries in the estimated PSF. =1 mean no additional symmetries. =4 means 90 deg symmetry. This is enforced by a rotatioanl stack according to the symmetry specified. These additional imposed symmetries can help stabelize the PSF estimate when there are limited constraints/number of point sources in the image. :param psf_iter_factor: factor in (0, 1] of ratio of old vs new PSF in the update in the iteration. :param block_center_neighbour: angle, radius of neighbouring point sources around their centers the estimates is ignored. Default is zero, meaning a not optimal subtraction of the neighbouring point sources might contaminate the estimate. :param block_center_neighbour_error_map: angle, radius of neighbouring point sources around their centers the estimates of the ERROR MAP is ignored. If None, then the value of block_center_neighbour is used (recommended) :param error_map_radius: float, radius (in arc seconds) of the outermost error in the PSF estimate (e.g. to avoid double counting of overlapping PSF errors), if None, all of the pixels are considered (unless blocked through other means) :param new_procedure: boolean, uses post lenstronomy 1.9.2 procedure which is more optimal for super-sampled PSF's :return: kwargs_psf_new, logL_after, error_map """ if block_center_neighbour_error_map is None: block_center_neighbour_error_map = block_center_neighbour psf_class = PSF(**kwargs_psf) kwargs_psf_copy = copy.deepcopy(kwargs_psf) point_source_supersampling_factor = kwargs_psf_copy.get( 'point_source_supersampling_factor', 1) kwargs_psf_new = { 'psf_type': 'PIXEL', 'kernel_point_source': kwargs_psf_copy['kernel_point_source'], 'point_source_supersampling_factor': point_source_supersampling_factor, 'psf_error_map': kwargs_psf_copy.get('psf_error_map', None) } # if 'psf_error_map' in kwargs_psf_copy: # kwargs_psf_new['psf_error_map'] = kwargs_psf_copy['psf_error_map'] / 10 self._image_model_class.update_psf(PSF(**kwargs_psf_new)) model, error_map_image, cov_param, param = self._image_model_class.image_linear_solve( **kwargs_params) kwargs_ps = kwargs_params.get('kwargs_ps', None) kwargs_lens = kwargs_params.get('kwargs_lens', None) ra_image, dec_image, point_amp = self._image_model_class.PointSource.point_source_list( kwargs_ps, kwargs_lens) x_, y_ = self._image_model_class.Data.map_coord2pix( ra_image, dec_image) kernel_old = psf_class.kernel_point_source kernel_size = len(kernel_old) if not new_procedure: image_single_point_source_list = self.image_single_point_source( self._image_model_class, kwargs_params) star_cutout_list = self.point_like_source_cutouts( x_pos=x_, y_pos=y_, image_list=image_single_point_source_list, cutout_size=kernel_size) psf_kernel_list = self.cutout_psf( ra_image, dec_image, x_, y_, image_single_point_source_list, kernel_size, kernel_old, block_center_neighbour=block_center_neighbour) kernel_new = self.combine_psf(psf_kernel_list, kernel_old, factor=psf_iter_factor, stacking_option=stacking_method, symmetry=psf_symmetry) kernel_new = kernel_util.cut_psf(kernel_new, psf_size=kernel_size) error_map = self.error_map_estimate( kernel_new, star_cutout_list, point_amp, x_, y_, error_map_radius=error_map_radius, block_center_neighbour=block_center_neighbour_error_map) if point_source_supersampling_factor > 1: # The current version of using a super-sampled PSF in the iterative reconstruction is to first # constrain a down-sampled version and then in a second step perform a super-sampling of it. This is not # optimal and should be changed in the future that the corrections of the super-sampled version is done # rather than constraining a totally new PSF first kernel_new = kernel_util.subgrid_kernel( kernel_new, subgrid_res=point_source_supersampling_factor, odd=True, num_iter=10) # chop edges n_kernel = len(kwargs_psf['kernel_point_source']) kernel_new = kernel_util.cut_psf(kernel_new, psf_size=n_kernel) else: kernel_old_high_res = psf_class.kernel_point_source_supersampled( supersampling_factor=point_source_supersampling_factor) kernel_size_high = len(kernel_old_high_res) data = self._image_model_class.Data.data residuals = data - model psf_kernel_list = self.psf_estimate_individual( ra_image, dec_image, point_amp, residuals, cutout_size=kernel_size, kernel_guess=kernel_old_high_res, supersampling_factor=point_source_supersampling_factor, block_center_neighbour=block_center_neighbour) kernel_new = self.combine_psf(psf_kernel_list, kernel_old_high_res, factor=psf_iter_factor, stacking_option=stacking_method, symmetry=psf_symmetry) kernel_new = kernel_util.cut_psf(kernel_new, psf_size=kernel_size_high) # resize kernel for error_map estimate # kernel_new_low = kernel_util.degrade_kernel(kernel_new, point_source_supersampling_factor) # compute error map on pixel level error_map = self.error_map_estimate_new( kernel_new, psf_kernel_list, ra_image, dec_image, point_amp, point_source_supersampling_factor, error_map_radius=error_map_radius) kwargs_psf_new['kernel_point_source'] = kernel_new # if 'psf_error_map' in kwargs_psf_new: # kwargs_psf_new['psf_error_map'] *= 10 self._image_model_class.update_psf(PSF(**kwargs_psf_new)) logL_after = self._image_model_class.likelihood_data_given_model( **kwargs_params) return kwargs_psf_new, logL_after, error_map