def psf_configure(self, psf_type="GAUSSIAN", fwhm=1, kernelsize=11, deltaPix=1, truncate=6, kernel=None): """ :param psf_type: :param fwhm: :param pixel_grid: :return: """ # psf_type: 'NONE', 'gaussian', 'pixel' # 'pixel': kernel, kernel_large # 'gaussian': 'sigma', 'truncate' if psf_type == 'GAUSSIAN': sigma = util.fwhm2sigma(fwhm) sigma_axis = sigma x_grid, y_grid = util.make_grid(kernelsize, deltaPix) kernel_large = self.gaussian.function(x_grid, y_grid, amp=1., sigma_x=sigma_axis, sigma_y=sigma_axis, center_x=0, center_y=0) kernel_large /= np.sum(kernel_large) kernel_large = util.array2image(kernel_large) kernel_pixel = kernel_util.pixel_kernel(kernel_large) kwargs_psf = {'psf_type': psf_type, 'fwhm': fwhm, 'truncation': truncate*fwhm, 'kernel_point_source': kernel_large, 'kernel_pixel': kernel_pixel, 'pixel_size': deltaPix} elif psf_type == 'PIXEL': kernel_large = copy.deepcopy(kernel) kernel_large = kernel_util.cut_psf(kernel_large, psf_size=kernelsize) kernel_small = copy.deepcopy(kernel) kernel_small = kernel_util.cut_psf(kernel_small, psf_size=kernelsize) kwargs_psf = {'psf_type': "PIXEL", 'kernel_pixel': kernel_small, 'kernel_point_source': kernel_large} elif psf_type == 'NONE': kwargs_psf = {'psf_type': 'NONE'} else: raise ValueError("psf type %s not supported!" % psf_type) psf_class = PSF(kwargs_psf) return psf_class
def update_psf(self, kwargs_psf, kwargs_lens, kwargs_source, kwargs_lens_light, kwargs_ps, factor=1, symmetry=1): """ :param kwargs_data: :param kwargs_psf: :param kwargs_options: :param kwargs_lens: :param kwargs_source: :param kwargs_lens_light: :param kwargs_ps: :return: """ psf_class = PSF(kwargs_psf) self._image_model_class.update_psf(psf_class) self._image_model_class.update_numerics(self._kwargs_numerics) kernel_old = psf_class.kernel_point_source kernel_small = psf_class.kernel_pixel kernel_size = len(kernel_old) kernelsize_small = len(kernel_small) kwargs_numerics_psf = copy.deepcopy(self._kwargs_numerics) kwargs_numerics_psf['psf_error_map'] = False self._image_model_class.update_numerics(kwargs_numerics_psf) image_single_point_source_list = self.image_single_point_source(self._image_model_class, kwargs_lens, kwargs_source, kwargs_lens_light, kwargs_ps) ra_image, dec_image, 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) mask = self._image_model_class.ImageNumerics.mask x_grid, y_grid = self._image_model_class.Data.coordinates deltaPix = self._image_model_class.Data.deltaPix #fwhm = self._image_model_class.PSF.psf_fwhm(kwargs_psf, deltaPix) radius = kwargs_psf.get("block_neighbour", 0.) / 2. mask_point_source_list = self.mask_point_sources(ra_image, dec_image, x_grid, y_grid, radius) point_source_list = self.cutout_psf(x_, y_, image_single_point_source_list, kernel_size, mask, mask_point_source_list, kernel_old, symmetry=symmetry) kernel_old_array = np.zeros((symmetry, kernel_size, kernel_size)) for i in range(symmetry): kernel_old_array[i, :, :] = kernel_old kernel_new, error_map = self.combine_psf(point_source_list, kernel_old_array, sigma_bkg=self._image_model_class.Data.background_rms, factor=factor) kernel_new_small = copy.deepcopy(kernel_new) kernel_new_small = kernel_util.pixel_kernel(kernel_new_small, subgrid_res=3) kernel_new_small = kernel_util.cut_psf(kernel_new_small, psf_size=kernelsize_small) kernel_new = kernel_util.cut_psf(kernel_new, psf_size=kernel_size) kwargs_psf_new = copy.deepcopy(kwargs_psf) if not self._kwargs_numerics.get('psf_keep_small', False): kwargs_psf_new['kernel_pixel'] = kernel_new_small kwargs_psf_new['kernel_point_source'] = kernel_new self._image_model_class.update_psf(PSF(kwargs_psf_new)) self._image_model_class.update_numerics(self._kwargs_numerics) logL_after = self._image_model_class.likelihood_data_given_model(kwargs_lens, kwargs_source, kwargs_lens_light, kwargs_ps) if not self._kwargs_numerics.get('psf_keep_error_map', False): kwargs_psf_new['psf_error_map'] = error_map return kwargs_psf_new, logL_after
def subgrid_point_source_kernel(self, subgrid_res): """ :return: """ if hasattr(self, '_kernel_point_source_subsampled' ) and self._point_source_subsampling_factor == subgrid_res: pass else: kernel = kernel_util.subgrid_kernel(self.kernel_point_source, subgrid_res, odd=True, num_iter=5) n = len(self.kernel_point_source) n_new = n * subgrid_res if n_new % 2 == 0: n_new -= 1 if hasattr(self, '_kernel_point_source_subsampled'): print( "Warning: subsampled point source kernel overwritten due to different subsampling size requested." ) self._kernel_point_source_subsampled = kernel_util.cut_psf( kernel, psf_size=n_new) self._point_source_subsampling_factor = subgrid_res return self._kernel_point_source_subsampled
def subgrid_point_source_kernel(self, subgrid_res): """ :return: """ if hasattr(self, '_kernel_point_source_subsampled') and self._point_source_subsampling_factor == subgrid_res: pass else: if self.psf_type == 'GAUSSIAN': kernel_numPix = self._truncation / self._pixel_size * subgrid_res kernel_numPix = int(round(kernel_numPix)) if kernel_numPix % 2 == 0: kernel_numPix += 1 self._kernel_point_source_subsampled = kernel_util.kernel_gaussian(kernel_numPix, self._pixel_size/subgrid_res, self._fwhm) elif self.psf_type == 'PIXEL': kernel = kernel_util.subgrid_kernel(self.kernel_point_source, subgrid_res, odd=True, num_iter=5) n = len(self.kernel_point_source) n_new = n * subgrid_res if n_new % 2 == 0: n_new -= 1 if hasattr(self, '_kernel_point_source_subsampled'): print("Warning: subsampled point source kernel overwritten due to different subsampling size requested.") self._kernel_point_source_subsampled = kernel_util.cut_psf(kernel, psf_size=n_new) self._point_source_subsampling_factor = subgrid_res return self._kernel_point_source_subsampled
def subgrid_pixel_kernel(self, subgrid_res): """ :return: """ if hasattr(self, '_kernel_pixel_subsampled' ) and self._pixel_subsampling_factor == subgrid_res: pass elif hasattr(self, '_kernel_point_source_subsampled'): # if the subsampling scale matches the one from the point source - take it! if self._point_source_subsampling_factor == subgrid_res: self._kernel_pixel_subsampled = self._kernel_point_source_subsampled self._pixel_subsampling_factor = self._point_source_subsampling_factor else: kernel = kernel_util.subgrid_kernel(self.kernel_point_source, subgrid_res, odd=True, num_iter=5) n = len(self.kernel_pixel) n_new = n * subgrid_res if n_new % 2 == 0: n_new -= 1 self._kernel_pixel_subsampled = kernel_util.cut_psf(kernel, psf_size=n_new) self._pixel_subsampling_factor = subgrid_res return self._kernel_pixel_subsampled
def instantiate_PSF_kwargs(psf_type, pixel_scale, seeing, kernel_size, which_psf_maps): """Instantiate PSF kwargs by reading in template PSF maps Parameters ---------- psf_config : dict copy of the PSF config pixel_scale : float pixel scale in arcsec/pix Returns ------- dict dict with lenstronomy psf kwargs """ if psf_type == 'PIXEL': psf_kwargs = [] psf_id_list = which_psf_maps random_psf_id = psf_id_list[np.random.randint(len(psf_id_list))] psf_path = resource_filename('baobab.in_data', 'psf_maps/psf_{:d}.fits'.format(random_psf_id)) psf_map = pyfits.getdata(psf_path) kernel_cut = kernel_util.cut_psf(psf_map, kernel_size) psf_kwargs = {'psf_type': 'PIXEL', 'pixel_size': pixel_scale, 'kernel_point_source': kernel_cut} return psf_kwargs elif psf_type == 'GAUSSIAN': psf_kwargs = {'psf_type': 'GAUSSIAN', 'fwhm': seeing, 'pixel_size': pixel_scale} return psf_kwargs else: return {'psf_type': 'NONE'}
def pixel_kernel(self, num_pix=None): """ access pixelated kernel :param num_pix: size of returned kernel (odd number per axis). If None, return the original kernel. :return: pixel kernel centered """ if num_pix is not None: return kernel_util.cut_psf(self._kernel, num_pix) return self._kernel
def update_psf(self, kwargs_psf, kwargs_params, stacking_method='median', psf_symmetry=1, psf_iter_factor=1., block_center_neighbour=0, error_map_radius=None): """ :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 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) :return: kwargs_psf_new, logL_after, error_map """ psf_class = PSF(**kwargs_psf) self._image_model_class.update_psf(psf_class) kernel_old = psf_class.kernel_point_source kernel_size = len(kernel_old) kwargs_psf_copy = copy.deepcopy(kwargs_psf) kwargs_psf_new = {'psf_type': 'PIXEL', 'kernel_point_source': kwargs_psf_copy['kernel_point_source']} 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)) image_single_point_source_list = self.image_single_point_source(self._image_model_class, kwargs_params) kwargs_ps = kwargs_params.get('kwargs_ps', None) kwargs_lens = kwargs_params.get('kwargs_lens', None) ra_image, dec_image, 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) psf_kernel_list, star_cutout_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, amp, x_, y_, error_map_radius=error_map_radius) kwargs_psf_new['kernel_point_source'] = kernel_new kwargs_psf_new['point_source_supersampling_factor'] = 1 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
def kernel_point_source_supersampled(self, supersampling_factor, updata_cache=True): """ generates (if not already available) a supersampled PSF with ood numbers of pixels centered :param supersampling_factor: int >=1, supersampling factor relative to pixel resolution :param updata_cache: boolean, if True, updates the cached supersampling PSF if generated. Attention, this will overwrite a previously used supersampled PSF if the resolution is changing. :return: super-sampled PSF as 2d numpy array """ if hasattr( self, '_kernel_point_source_supersampled' ) and self._point_source_supersampling_factor == supersampling_factor: kernel_point_source_supersampled = self._kernel_point_source_supersampled else: if self.psf_type == 'GAUSSIAN': kernel_numPix = self._truncation / self._pixel_size * supersampling_factor kernel_numPix = int(round(kernel_numPix)) if kernel_numPix > 10000: raise ValueError( 'The pixelized Gaussian kernel has a grid of %s pixels with a truncation at ' '%s times the sigma of the Gaussian, exceeding the limit allowed.' % (kernel_numPix, self._truncation)) if kernel_numPix % 2 == 0: kernel_numPix += 1 kernel_point_source_supersampled = kernel_util.kernel_gaussian( kernel_numPix, self._pixel_size / supersampling_factor, self._fwhm) elif self.psf_type == 'PIXEL': kernel = kernel_util.subgrid_kernel(self.kernel_point_source, supersampling_factor, odd=True, num_iter=5) n = len(self.kernel_point_source) n_new = n * supersampling_factor if n_new % 2 == 0: n_new -= 1 if hasattr(self, '_kernel_point_source_supersampled'): warnings.warn( "Super-sampled point source kernel over-written due to different subsampling" " size requested.", Warning) kernel_point_source_supersampled = kernel_util.cut_psf( kernel, psf_size=n_new) elif self.psf_type == 'NONE': kernel_point_source_supersampled = self._kernel_point_source else: raise ValueError('psf_type %s not valid!' % self.psf_type) if updata_cache is True: self._kernel_point_source_supersampled = kernel_point_source_supersampled self._point_source_supersampling_factor = supersampling_factor return kernel_point_source_supersampled
def instantiate_PSF_models(psf_config, pixel_scale): """Instantiate PSF models by reading in template PSF maps Parameters ---------- psf_config : dict copy of the PSF config pixel_scale : float pixel scale in arcsec/pix Returns ------- list list of lenstronomy PSF instances """ if psf_config['type'] == 'PIXEL': psf_models = [] if psf_config['which_psf_maps'] is None: # Instantiate PSF with all available PSF maps #FIXME: equate psf_id with psf_i since seed number is meaningless psf_id_list = [ 101, 102, 103, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 118 ] else: psf_id_list = [psf_config['which_psf_maps']] for psf_i, psf_id in enumerate(psf_id_list): psf_path = resource_filename( 'baobab.in_data', 'psf_maps/psf_{:d}.fits'.format(psf_id)) psf_map = pyfits.getdata(psf_path) kernel_cut = kernel_util.cut_psf(psf_map, psf_config['kernel_size']) kwargs_psf = { 'psf_type': 'PIXEL', 'pixel_size': pixel_scale, 'kernel_point_source': kernel_cut } psf_models.append(PSF(**kwargs_psf)) return psf_models elif psf_config['type'] == 'GAUSSIAN': kwargs_psf = { 'psf_type': 'GAUSSIAN', 'fwhm': psf_config['PSF_FWHM'], 'pixel_size': pixel_scale } psf_model = PSF(**kwargs_psf) return [psf_model] else: psf_model = PSF(psf_type='NONE') return [psf_model]
def _subgrid_kernel(self, subgrid_res): """ :return: """ if not hasattr(self, '_subgrid_kernel_out'): kernel = kernel_util.subgrid_kernel(self.kernel_point_source, subgrid_res, odd=True) n = len(self._kernel_pixel) n_new = n * subgrid_res if n_new % 2 == 0: n_new -= 1 self._subgrid_kernel_out = kernel_util.cut_psf(kernel, psf_size=n_new) return self._subgrid_kernel_out
def psf_configure_simple(psf_type="GAUSSIAN", fwhm=1, kernelsize=11, deltaPix=1, truncate=6, kernel=None): """ this routine generates keyword arguments to initialize a PSF() class in lenstronomy. Have a look at the PSF class documentation to see the full possibilities. :param psf_type: string, type of PSF model :param fwhm: Full width at half maximum of PSF (if GAUSSIAN psf) :param kernelsize: size in pixel of kernel (use odd numbers), only applicable for PIXEL kernels :param deltaPix: pixel size in angular units (only needed for GAUSSIAN kernel :param truncate: how many sigmas out is the truncation happening :param kernel: 2d numpy arra centered PSF (odd number per axis) :return: keyword arguments """ if psf_type == 'GAUSSIAN': sigma = util.fwhm2sigma(fwhm) sigma_axis = sigma gaussian = Gaussian() x_grid, y_grid = util.make_grid(kernelsize, deltaPix) kernel_large = gaussian.function(x_grid, y_grid, amp=1., sigma_x=sigma_axis, sigma_y=sigma_axis, center_x=0, center_y=0) kernel_large /= np.sum(kernel_large) kernel_large = util.array2image(kernel_large) kernel_pixel = kernel_util.pixel_kernel(kernel_large) kwargs_psf = { 'psf_type': psf_type, 'fwhm': fwhm, 'truncation': truncate * fwhm, 'kernel_point_source': kernel_large, 'kernel_pixel': kernel_pixel, 'pixel_size': deltaPix } elif psf_type == 'PIXEL': kernel_large = copy.deepcopy(kernel) kernel_large = kernel_util.cut_psf(kernel_large, psf_size=kernelsize) kwargs_psf = {'psf_type': "PIXEL", 'kernel_point_source': kernel_large} elif psf_type == 'NONE': kwargs_psf = {'psf_type': 'NONE'} else: raise ValueError("psf type %s not supported!" % psf_type) return kwargs_psf
def _supersampling_cut_kernel(kernel_super, convolution_kernel_size, supersampling_factor): """ :param kernel_super: super-sampled kernel :param convolution_kernel_size: size of convolution kernel in units of regular pixels (odd) :param supersampling_factor: super-sampling factor of convolution kernel :return: cut out kernel in super-sampling size """ if convolution_kernel_size is not None: size = convolution_kernel_size * supersampling_factor if size % 2 == 0: size += 1 kernel_cut = kernel_util.cut_psf(kernel_super, size) return kernel_cut else: return kernel_super
def kernel_point_source_supersampled(self, supersampling_factor, updata_cache=True): """ :return: """ if hasattr( self, '_kernel_point_source_supersampled' ) and self._point_source_supersampling_factor == supersampling_factor: kernel_point_source_supersampled = self._kernel_point_source_supersampled else: if self.psf_type == 'GAUSSIAN': kernel_numPix = self._truncation / self._pixel_size * supersampling_factor kernel_numPix = int(round(kernel_numPix)) if kernel_numPix % 2 == 0: kernel_numPix += 1 kernel_point_source_supersampled = kernel_util.kernel_gaussian( kernel_numPix, self._pixel_size / supersampling_factor, self._fwhm) elif self.psf_type == 'PIXEL': kernel = kernel_util.subgrid_kernel(self.kernel_point_source, supersampling_factor, odd=True, num_iter=5) n = len(self.kernel_point_source) n_new = n * supersampling_factor if n_new % 2 == 0: n_new -= 1 if hasattr(self, '_kernel_point_source_supersampled'): warnings.warn( "Super-sampled point source kernel over-written due to different subsampling" " size requested.", Warning) kernel_point_source_supersampled = kernel_util.cut_psf( kernel, psf_size=n_new) elif self.psf_type == 'NONE': kernel_point_source_supersampled = self._kernel_point_source else: raise ValueError('psf_type %s not valid!' % self.psf_type) if updata_cache is True: self._kernel_point_source_supersampled = kernel_point_source_supersampled self._point_source_supersampling_factor = supersampling_factor return kernel_point_source_supersampled
def update_psf(self, kwargs_psf, kwargs_params, stacking_method='median', psf_symmetry=1, psf_iter_factor=1., block_center_neighbour=0): """ :param kwargs_data: :param kwargs_psf: :param kwargs_options: :param kwargs_lens: :param kwargs_source: :param kwargs_lens_light: :param kwargs_ps: :return: """ psf_class = PSF(**kwargs_psf) self._image_model_class.update_psf(psf_class) kernel_old = psf_class.kernel_point_source kernel_size = len(kernel_old) #kwargs_numerics_psf['psf_error_map'] = False kwargs_psf_copy = copy.deepcopy(kwargs_psf) kwargs_psf_new = {'psf_type': 'PIXEL', 'kernel_point_source': kwargs_psf_copy['kernel_point_source']} 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)) image_single_point_source_list = self.image_single_point_source(self._image_model_class, kwargs_params) kwargs_ps = kwargs_params.get('kwargs_ps', None) kwargs_lens = kwargs_params.get('kwargs_lens', None) ra_image, dec_image, 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) point_source_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, error_map = self.combine_psf(point_source_list, kernel_old, sigma_bkg=self._image_model_class.Data.background_rms, factor=psf_iter_factor, stacking_option=stacking_method, symmetry=psf_symmetry) kernel_new = kernel_util.cut_psf(kernel_new, psf_size=kernel_size) kwargs_psf_new['kernel_point_source'] = kernel_new kwargs_psf_new['point_source_supersampling_factor'] = 1 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
def setup(self): # we define a model consisting of a singe Sersric profile from lenstronomy.LightModel.light_model import LightModel light_model_list = ['SERSIC_ELLIPSE'] self.lightModel = LightModel(light_model_list=light_model_list) self.kwargs_light = [ {'amp': 100, 'R_sersic': 0.5, 'n_sersic': 3, 'e1': 0, 'e2': 0, 'center_x': 0.02, 'center_y': 0}] # we define a pixel grid and a higher resolution super sampling factor self._supersampling_factor = 5 numPix = 61 # cutout pixel size deltaPix = 0.05 # pixel size in arcsec (area per pixel = deltaPix**2) x, y, ra_at_xy_0, dec_at_xy_0, x_at_radec_0, y_at_radec_0, Mpix2coord, Mcoord2pix = util.make_grid_with_coordtransform( numPix=numPix, deltapix=deltaPix, subgrid_res=1, left_lower=False, inverse=False) flux = self.lightModel.surface_brightness(x, y, kwargs_list=self.kwargs_light) flux = util.array2image(flux) flux_max = np.max(flux) conv_pixels_partial = np.zeros((numPix, numPix), dtype=bool) conv_pixels_partial[flux >= flux_max / 20] = True self._conv_pixels_partial = conv_pixels_partial # high resolution ray-tracing and high resolution convolution, the full calculation self.kwargs_numerics_true = {'supersampling_factor': self._supersampling_factor, # super sampling factor of (partial) high resolution ray-tracing 'compute_mode': 'regular', # 'regular' or 'adaptive' 'supersampling_convolution': True, # bool, if True, performs the supersampled convolution (either on regular or adaptive grid) 'supersampling_kernel_size': None, # size of the higher resolution kernel region (can be smaller than the original kernel). None leads to use the full size 'flux_evaluate_indexes': None, # bool mask, if None, it will evaluate all (sub) pixels 'supersampled_indexes': None, # bool mask of pixels to be computed in supersampled grid (only for adaptive mode) 'compute_indexes': None, # bool mask of pixels to be computed the PSF response (flux being added to). Only used for adaptive mode and can be set =likelihood mask. 'point_source_supersampling_factor': 1, # int, supersampling factor when rendering a point source (not used in this script) } # high resolution convolution on a smaller PSF with low resolution convolution on the edges of the PSF and high resolution ray tracing self.kwargs_numerics_high_res_narrow = {'supersampling_factor': self._supersampling_factor, 'compute_mode': 'regular', 'supersampling_convolution': True, 'supersampling_kernel_size': 5, } # low resolution convolution based on high resolution ray-tracing grid self.kwargs_numerics_low_conv_high_grid = {'supersampling_factor': self._supersampling_factor, 'compute_mode': 'regular', 'supersampling_convolution': False, # does not matter for supersampling_factor=1 'supersampling_kernel_size': None, # does not matter for supersampling_factor=1 } # low resolution convolution with a subset of pixels with high resolution ray-tracing self.kwargs_numerics_low_conv_high_adaptive = {'supersampling_factor': self._supersampling_factor, 'compute_mode': 'adaptive', 'supersampling_convolution': False, # does not matter for supersampling_factor=1 'supersampling_kernel_size': None, # does not matter for supersampling_factor=1 'supersampled_indexes': self._conv_pixels_partial, 'convolution_kernel_size': 9, } # low resolution convolution with a subset of pixels with high resolution ray-tracing and high resoluton convolution on smaller kernel size self.kwargs_numerics_high_adaptive = {'supersampling_factor': self._supersampling_factor, 'compute_mode': 'adaptive', 'supersampling_convolution': True, # does not matter for supersampling_factor=1 'supersampling_kernel_size': 5, # does not matter for supersampling_factor=1 'supersampled_indexes': self._conv_pixels_partial, 'convolution_kernel_size': 9, } # low resolution convolution and low resolution ray tracing, the simplest calculation self.kwargs_numerics_low_res = {'supersampling_factor': 1, 'compute_mode': 'regular', 'supersampling_convolution': False, # does not matter for supersampling_factor=1 'supersampling_kernel_size': None, # does not matter for supersampling_factor=1 'convolution_kernel_size': 9, } flux_evaluate_indexes = np.zeros((numPix, numPix), dtype=bool) flux_evaluate_indexes[flux >= flux_max / 1000] = True # low resolution convolution on subframe self.kwargs_numerics_partial = {'supersampling_factor': 1, 'compute_mode': 'regular', 'supersampling_convolution': False, # does not matter for supersampling_factor=1 'supersampling_kernel_size': None, # does not matter for supersampling_factor=1 'flux_evaluate_indexes': flux_evaluate_indexes, 'convolution_kernel_size': 9 } # import PSF file kernel_super = kernel_util.kernel_gaussian(kernel_numPix=11 * self._supersampling_factor, deltaPix=deltaPix / self._supersampling_factor, fwhm=0.1) kernel_size = 9 kernel_super = kernel_util.cut_psf(psf_data=kernel_super, psf_size=kernel_size * self._supersampling_factor) # make instance of the PixelGrid class from lenstronomy.Data.pixel_grid import PixelGrid kwargs_grid = {'nx': numPix, 'ny': numPix, 'transform_pix2angle': Mpix2coord, 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0} self.pixel_grid = PixelGrid(**kwargs_grid) # make instance of the PSF class from lenstronomy.Data.psf import PSF kwargs_psf = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_super, 'point_source_supersampling_factor': self._supersampling_factor} self.psf_class = PSF(**kwargs_psf) # without convolution image_model_true = ImageModel(self.pixel_grid, self.psf_class, lens_light_model_class=self.lightModel, kwargs_numerics=self.kwargs_numerics_true) self.image_true = image_model_true.image(kwargs_lens_light=self.kwargs_light)
def pick_psf(self, ra=None, dec=None, r_cut=15, pixel_size=None, kernel_size=None, pick=True): """ select psf :param x: x coordinate. :param y: y coordinate. :param r_cut: radius size of the psf. :param deltaPix: pixel size of the psf. :param kernel_size: kernel size of the psf. :return: kwargs_psf """ if ra is not None: x_psf, y_psf = self.radec2detector(ra, dec) image_psf = self.cut_image_psf(x_psf, y_psf, r_cut) else: data_process = dxhDataProcess(fov_image=self.image, target_pos=[0, 0], pos_type='pixel', zp=0) if self.interaction & pick: psfyn = input( 'Hint: do you want to pick up the PSF youself? (y/n): ') if psfyn == 'y': print(( 'Please only pick 1 psf, otherwise only the 1st will be chosen' )) data_process.find_PSF(radius=r_cut, user_option=True) image_psf = data_process.PSF_list[0] elif psfyn == 'n': data_process.find_PSF(radius=r_cut, user_option=False) image_psf = data_process.PSF_list[0] else: raise ValueError("Please input 'y' or 'n' !") else: data_process.find_PSF(radius=r_cut, user_option=False) image_psf = data_process.PSF_list[0] if kernel_size is None: kernel_size = np.shape(image_psf)[0] image_psf_cut = kernel_util.cut_psf( image_psf, psf_size=kernel_size) #why using kernel ? if pixel_size is None: pixel_size = self.deltaPix else: pixel_size = pixel_size kwargs_psf = { 'psf_type': 'PIXEL', 'kernel_point_source': image_psf_cut, 'pixel_size': pixel_size } self.psf = image_psf_cut # TODO adding simulated psf return kwargs_psf
def test_cut_psf(): image = np.ones((7, 7)) psf_cut = kernel_util.cut_psf(image, 5) assert len(psf_cut) == 5
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
ID, fr)) # agn_stdd = pyfits.getdata('./allscience/{0}_{1}_stdd.fits'.format(ID,fr)) stdd = 4 #Measurement from empty retion, 0.016*0.08**2/0.13**2/np.sqrt(8) agn_stdd = (abs(agn_image / exp_time) + stdd**2)**0.5 print("The fitting image:") plt.imshow(agn_image, norm=LogNorm(), origin='lower') plt.savefig('./zoutput/{0}_agn.png'.format(ID)) if pltshow == 0: plt.close() else: plt.show() print("The adopted PSF:") psf = kernel_util.cut_psf(psf, psf_size=kernel_size) plt.imshow(psf, norm=LogNorm(), origin='lower') plt.savefig('./zoutput/{0}_psf.png'.format(ID)) if pltshow == 0: plt.close() else: plt.show() from mask_objects import mask_obj _, _, deblend_sources = mask_obj(agn_image, snr=snratio, npixels=numberpixels, return_deblend=True) print("deblend image to find the ID for the Objects for the mask:")