def __init__(self, multi_band_list, kwargs_model, model, error_map, cov_param, param, kwargs_params, likelihood_mask_list=None, band_index=0, arrow_size=0.02, cmap_string="gist_heat"): self.bandmodel = SingleBandMultiModel( multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index) self._kwargs_special_partial = kwargs_params.get( 'kwargs_special', None) kwarks_lens_partial, kwargs_source_partial, kwargs_lens_light_partial, kwargs_ps_partial, self._kwargs_extinction_partial = self.bandmodel.select_kwargs( **kwargs_params) self._kwargs_lens_partial, self._kwargs_source_partial, self._kwargs_lens_light_partial, self._kwargs_ps_partial = self.bandmodel.update_linear_kwargs( param, kwarks_lens_partial, kwargs_source_partial, kwargs_lens_light_partial, kwargs_ps_partial) self._norm_residuals = self.bandmodel.reduced_residuals( model, error_map=error_map) self._reduced_x2 = self.bandmodel.reduced_chi2(model, error_map=error_map) print("reduced chi^2 of data ", band_index, "= ", self._reduced_x2) self._model = model self._cov_param = cov_param self._param = param self._lensModel = self.bandmodel.LensModel self._lensModelExt = LensModelExtensions(self._lensModel) log_model = np.log10(model) log_model[np.isnan(log_model)] = -5 self._v_min_default = max(np.min(log_model), -5) self._v_max_default = min(np.max(log_model), 10) self._coords = self.bandmodel.Data self._data = self._coords.data self._deltaPix = self._coords.pixel_width self._frame_size = np.max(self._coords.width) x_grid, y_grid = self._coords.pixel_coordinates self._x_grid = util.image2array(x_grid) self._y_grid = util.image2array(y_grid) if isinstance(cmap_string, str): cmap = plt.get_cmap(cmap_string) else: cmap = cmap_string cmap.set_bad(color='k', alpha=1.) cmap.set_under('k') self._cmap = cmap self._arrow_size = arrow_size
def _likelihood(self, args): """ routine to compute X2 given variable parameters for a MCMC/PSO chainF """ #generate image and computes likelihood multi_band_list = self.update_multi_band(args) image_model = SingleBandMultiModel(multi_band_list, self._kwargs_model, likelihood_mask_list=self._likelihood_mask_list, band_index=self._band_index) logL = image_model.likelihood_data_given_model(source_marg=self._source_marg, **self._kwargs_params) return logL
def __init__(self, multi_band_list, kwargs_model, model, error_map, cov_param, param, kwargs_params, image_likelihood_mask_list=None, band_index=0, verbose=True): """ :param multi_band_list: list of imaging data configuration [[kwargs_data, kwargs_psf, kwargs_numerics], [...]] :param kwargs_model: model keyword argument list for the full multi-band modeling :param model: 2d numpy array of modeled image for the specified band :param error_map: 2d numpy array of size of the image, additional error in the pixels coming from PSF uncertainties :param cov_param: covariance matrix of the linear inversion :param param: 1d numpy array of the linear coefficients of this imaging band :param kwargs_params: keyword argument of keyword argument lists of the different model components selected for the imaging band, NOT including linear amplitudes (not required as being overwritten by the param list) :param image_likelihood_mask_list: list of 2d numpy arrays of likelihood masks (for all bands) :param band_index: integer of the band to be considered in this class :param verbose: if True (default), prints the reduced chi2 value for the current band. """ self._bandmodel = SingleBandMultiModel( multi_band_list, kwargs_model, likelihood_mask_list=image_likelihood_mask_list, band_index=band_index) self._kwargs_special_partial = kwargs_params.get( 'kwargs_special', None) kwarks_lens_partial, kwargs_source_partial, kwargs_lens_light_partial, kwargs_ps_partial, self._kwargs_extinction_partial = self._bandmodel.select_kwargs( **kwargs_params) self._kwargs_lens_partial, self._kwargs_source_partial, self._kwargs_lens_light_partial, self._kwargs_ps_partial = self._bandmodel.update_linear_kwargs( param, kwarks_lens_partial, kwargs_source_partial, kwargs_lens_light_partial, kwargs_ps_partial) # this is an (out-commented) example of how to re-create the model in this band # model_new = self.bandmodel.image(self._kwargs_lens_partial, self._kwargs_source_partial, self._kwargs_lens_light_partial, self._kwargs_ps_partial, self._kwargs_special_partial, self._kwargs_extinction_partial) self._norm_residuals = self._bandmodel.reduced_residuals( model, error_map=error_map) self._reduced_x2 = self._bandmodel.reduced_chi2(model, error_map=error_map) if verbose: print("reduced chi^2 of data ", band_index, "= ", self._reduced_x2) self._model = model self._cov_param = cov_param self._param = param self._error_map = error_map
def psf_iteration(self, compute_bands=None, **kwargs_psf_iter): """ iterative PSF reconstruction :param compute_bands: bool list, if multiple bands, this process can be limited to a subset of bands :param kwargs_psf_iter: keyword arguments as used or available in PSFIteration.update_iterative() definition :return: 0, updated PSF is stored in self.multi_band_list """ kwargs_model = self._updateManager.kwargs_model kwargs_likelihood = self._updateManager.kwargs_likelihood likelihood_mask_list = kwargs_likelihood.get('image_likelihood_mask_list', None) kwargs_pixelbased = kwargs_likelihood.get('kwargs_pixelbased', None) kwargs_temp = self.best_fit(bijective=False) if compute_bands is None: compute_bands = [True] * len(self.multi_band_list) for band_index in range(len(self.multi_band_list)): if compute_bands[band_index] is True: kwargs_psf = self.multi_band_list[band_index][1] image_model = SingleBandMultiModel(self.multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index, kwargs_pixelbased=kwargs_pixelbased) psf_iter = PsfFitting(image_model_class=image_model) kwargs_psf = psf_iter.update_iterative(kwargs_psf, kwargs_params=kwargs_temp, **kwargs_psf_iter) self.multi_band_list[band_index][1] = kwargs_psf return 0
def create_im_sim(multi_band_list, multi_band_type, kwargs_model, bands_compute=None, image_likelihood_mask_list=None, band_index=0, kwargs_pixelbased=None): """ :param multi_band_list: list of [[kwargs_data, kwargs_psf, kwargs_numerics], [], ..] :param multi_band_type: string, option when having multiple imaging data sets modelled simultaneously. Options are: - 'multi-linear': linear amplitudes are inferred on single data set - 'linear-joint': linear amplitudes ae jointly inferred - 'single-band': single band :param kwargs_model: model keyword arguments :param bands_compute: (optional), bool list to indicate which band to be included in the modeling :param image_likelihood_mask_list: list of image likelihood mask (same size as image_data with 1 indicating being evaluated and 0 being left out) :param band_index: integer, index of the imaging band to model (only applied when using 'single-band' as option) :param kwargs_pixelbased: keyword arguments with various settings related to the pixel-based solver (see SLITronomy documentation) :return: MultiBand class instance """ if multi_band_type == 'multi-linear': from lenstronomy.ImSim.MultiBand.multi_linear import MultiLinear multiband = MultiLinear(multi_band_list, kwargs_model, compute_bool=bands_compute, likelihood_mask_list=image_likelihood_mask_list) elif multi_band_type == 'joint-linear': from lenstronomy.ImSim.MultiBand.joint_linear import JointLinear multiband = JointLinear(multi_band_list, kwargs_model, compute_bool=bands_compute, likelihood_mask_list=image_likelihood_mask_list) elif multi_band_type == 'single-band': from lenstronomy.ImSim.MultiBand.single_band_multi_model import SingleBandMultiModel multiband = SingleBandMultiModel(multi_band_list, kwargs_model, likelihood_mask_list=image_likelihood_mask_list, band_index=band_index, kwargs_pixelbased=kwargs_pixelbased) else: raise ValueError("type %s is not supported!" % multi_band_type) return multiband
def __init__(self, multi_band_list, kwargs_model, likelihood_mask_list=None, compute_bool=None, kwargs_pixelbased=None, linear_solver=True): """ :param multi_band_list: list of imaging band configurations [[kwargs_data, kwargs_psf, kwargs_numerics],[...], ...] :param kwargs_model: model option keyword arguments :param likelihood_mask_list: list of likelihood masks (booleans with size of the individual images) :param compute_bool: (optional), bool list to indicate which band to be included in the modeling :param linear_solver: bool, if True (default) fixes the linear amplitude parameters 'amp' (avoid sampling) such that they get overwritten by the linear solver solution. """ self.type = 'multi-linear' imageModel_list = [] if linear_solver is False and len(multi_band_list) > 1: raise ValueError( 'Multi-linear mode with more than one band does not support "linear_solver" = False.' ) for band_index in range(len(multi_band_list)): imageModel = SingleBandMultiModel( multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index, kwargs_pixelbased=kwargs_pixelbased, linear_solver=linear_solver) imageModel_list.append(imageModel) super(MultiLinear, self).__init__(imageModel_list, compute_bool=compute_bool)
def create_im_sim(multi_band_list, multi_band_type, kwargs_model, bands_compute=None, likelihood_mask_list=None, band_index=0): """ :param multi_band_type: string, option when having multiple imaging data sets modelled simultaneously. Options are: - 'multi-linear': linear amplitudes are inferred on single data set - 'linear-joint': linear amplitudes ae jointly inferred - 'single-band': single band :return: MultiBand class instance """ if multi_band_type == 'multi-linear': from lenstronomy.ImSim.MultiBand.multi_linear import MultiLinear multiband = MultiLinear(multi_band_list, kwargs_model, compute_bool=bands_compute, likelihood_mask_list=likelihood_mask_list) elif multi_band_type == 'joint-linear': from lenstronomy.ImSim.MultiBand.joint_linear import JointLinear multiband = JointLinear(multi_band_list, kwargs_model, compute_bool=bands_compute, likelihood_mask_list=likelihood_mask_list) elif multi_band_type == 'single-band': from lenstronomy.ImSim.MultiBand.single_band_multi_model import SingleBandMultiModel multiband = SingleBandMultiModel(multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index) else: raise ValueError("type %s is not supported!" % multi_band_type) return multiband
def __init__(self, multi_band_list, kwargs_model, likelihood_mask_list=None, compute_bool=None): self.type = 'multi-linear' imageModel_list = [] for band_index in range(len(multi_band_list)): imageModel = SingleBandMultiModel(multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index) imageModel_list.append(imageModel) super(MultiLinear, self).__init__(imageModel_list, compute_bool=compute_bool)
def psf_iteration(self, num_iter=10, no_break=True, stacking_method='median', block_center_neighbour=0, keep_psf_error_map=True, psf_symmetry=1, psf_iter_factor=1, error_map_radius=None, verbose=True, compute_bands=None): """ iterative PSF reconstruction :param num_iter: number of iterations in the process :param no_break: bool, if False will break the process as soon as one step lead to a wors reconstruction then the previous step :param stacking_method: string, 'median' and 'mean' supported :param block_center_neighbour: radius of neighbouring point source to be blocked in the reconstruction :param keep_psf_error_map: bool, whether or not to keep the previous psf_error_map :param psf_symmetry: int, number of invariant rotations in the reconstructed PSF :param psf_iter_factor: factor of new estimated PSF relative to the old one PSF_updated = (1-psf_iter_factor) * PSF_old + psf_iter_factor*PSF_new :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) :param verbose: bool, print statements :param compute_bands: bool list, if multiple bands, this process can be limited to a subset of bands :return: 0, updated PSF is stored in self.multi_band_list """ kwargs_model = self._updateManager.kwargs_model kwargs_likelihood = self._updateManager.kwargs_likelihood likelihood_mask_list = kwargs_likelihood.get( 'image_likelihood_mask_list', None) kwargs_pixelbased = kwargs_likelihood.get('kwargs_pixelbased', None) kwargs_temp = self.best_fit(bijective=False) if compute_bands is None: compute_bands = [True] * len(self.multi_band_list) for band_index in range(len(self.multi_band_list)): if compute_bands[band_index] is True: kwargs_psf = self.multi_band_list[band_index][1] image_model = SingleBandMultiModel( self.multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index, kwargs_pixelbased=kwargs_pixelbased) psf_iter = PsfFitting(image_model_class=image_model) kwargs_psf = psf_iter.update_iterative( kwargs_psf, kwargs_params=kwargs_temp, num_iter=num_iter, no_break=no_break, stacking_method=stacking_method, block_center_neighbour=block_center_neighbour, keep_psf_error_map=keep_psf_error_map, psf_symmetry=psf_symmetry, psf_iter_factor=psf_iter_factor, error_map_radius=error_map_radius, verbose=verbose) self.multi_band_list[band_index][1] = kwargs_psf return 0
def __init__(self, multi_band_list, kwargs_model, likelihood_mask_list=None, compute_bool=None, kwargs_pixelbased=None): """ :param multi_band_list: list of imaging band configurations [[kwargs_data, kwargs_psf, kwargs_numerics],[...], ...] :param kwargs_model: model option keyword arguments :param likelihood_mask_list: list of likelihood masks (booleans with size of the individual images :param compute_bool: (optinal), bool list to indicate which band to be included in the modeling """ self.type = 'multi-linear' imageModel_list = [] for band_index in range(len(multi_band_list)): imageModel = SingleBandMultiModel( multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index, kwargs_pixelbased=kwargs_pixelbased) imageModel_list.append(imageModel) super(MultiLinear, self).__init__(imageModel_list, compute_bool=compute_bool)
def psf_iteration(self, num_iter=10, no_break=True, stacking_method='median', block_center_neighbour=0, keep_psf_error_map=True, psf_symmetry=1, psf_iter_factor=1, verbose=True, compute_bands=None): """ iterative PSF reconstruction :param num_iter: number of iterations in the process :param no_break: bool, if False will break the process as soon as one step lead to a wors reconstruction then the previous step :param stacking_method: string, 'median' and 'mean' supported :param block_center_neighbour: radius of neighbouring point source to be blocked in the reconstruction :param keep_psf_error_map: bool, whether or not to keep the previous psf_error_map :param psf_symmetry: int, number of invariant rotations in the reconstructed PSF :param psf_iter_factor: factor of new estimated PSF relative to the old one PSF_updated = (1-psf_iter_factor) * PSF_old + psf_iter_factor*PSF_new :param verbose: bool, print statements :param compute_bands: bool list, if multiple bands, this process can be limited to a subset of bands :return: 0, updated PSF is stored in self.mult_iband_list """ kwargs_model = self._updateManager.kwargs_model kwargs_likelihood = self._updateManager.kwargs_likelihood likelihood_mask_list = kwargs_likelihood.get('image_likelihood_mask_list', None) param_class = self._param_class lens_updated = param_class.update_lens_scaling(self._cosmo_temp, self._lens_temp) source_updated = param_class.image2source_plane(self._source_temp, lens_updated) if compute_bands is None: compute_bands = [True] * len(self.multi_band_list) for band_index in range(len(self.multi_band_list)): if compute_bands[band_index] is True: kwargs_psf = self.multi_band_list[band_index][1] image_model = SingleBandMultiModel(self.multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index) psf_iter = PsfFitting(image_model_class=image_model) kwargs_psf = psf_iter.update_iterative(kwargs_psf, lens_updated, source_updated, self._lens_light_temp, self._ps_temp, num_iter=num_iter, no_break=no_break, stacking_method=stacking_method, block_center_neighbour=block_center_neighbour, keep_psf_error_map=keep_psf_error_map, psf_symmetry=psf_symmetry, psf_iter_factor=psf_iter_factor, verbose=verbose) self.multi_band_list[band_index][1] = kwargs_psf return 0
def create_im_sim(multi_band_list, multi_band_type, kwargs_model, bands_compute=None, likelihood_mask_list=None, band_index=0): """ :param multi_band_type: string, option when having multiple imaging data sets modelled simultaneously. Options are: - 'multi-band': linear amplitudes are inferred on single data set - 'multi-exposure': linear amplitudes ae jointly inferred - 'multi-frame': multiple frames (as single exposures with disjoint lens model :return: MultiBand class instance """ if multi_band_type == 'multi-linear': multiband = MultiLinear(multi_band_list, kwargs_model, compute_bool=bands_compute, likelihood_mask_list=likelihood_mask_list) elif multi_band_type == 'joint-linear': multiband = JointLinear(multi_band_list, kwargs_model, compute_bool=bands_compute, likelihood_mask_list=likelihood_mask_list) elif multi_band_type == 'single-band': multiband = SingleBandMultiModel(multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index) else: raise ValueError("type %s is not supported!" % multi_band_type) return multiband
class ModelBand(object): """ class to plot a single band given the full modeling results This class has it's specific role when the linear inference is performed on the joint band level and/or when only a subset of model components get used for this specific band in the modeling. """ def __init__(self, multi_band_list, kwargs_model, model, error_map, cov_param, param, kwargs_params, image_likelihood_mask_list=None, band_index=0, verbose=True): """ :param multi_band_list: list of imaging data configuration [[kwargs_data, kwargs_psf, kwargs_numerics], [...]] :param kwargs_model: model keyword argument list for the full multi-band modeling :param model: 2d numpy array of modeled image for the specified band :param error_map: 2d numpy array of size of the image, additional error in the pixels coming from PSF uncertainties :param cov_param: covariance matrix of the linear inversion :param param: 1d numpy array of the linear coefficients of this imaging band :param kwargs_params: keyword argument of keyword argument lists of the different model components selected for the imaging band, NOT including linear amplitudes (not required as being overwritten by the param list) :param image_likelihood_mask_list: list of 2d numpy arrays of likelihood masks (for all bands) :param band_index: integer of the band to be considered in this class :param verbose: if True (default), prints the reduced chi2 value for the current band. """ self._bandmodel = SingleBandMultiModel( multi_band_list, kwargs_model, likelihood_mask_list=image_likelihood_mask_list, band_index=band_index) self._kwargs_special_partial = kwargs_params.get( 'kwargs_special', None) kwarks_lens_partial, kwargs_source_partial, kwargs_lens_light_partial, kwargs_ps_partial, self._kwargs_extinction_partial = self._bandmodel.select_kwargs( **kwargs_params) self._kwargs_lens_partial, self._kwargs_source_partial, self._kwargs_lens_light_partial, self._kwargs_ps_partial = self._bandmodel.update_linear_kwargs( param, kwarks_lens_partial, kwargs_source_partial, kwargs_lens_light_partial, kwargs_ps_partial) # this is an (out-commented) example of how to re-create the model in this band # model_new = self.bandmodel.image(self._kwargs_lens_partial, self._kwargs_source_partial, self._kwargs_lens_light_partial, self._kwargs_ps_partial, self._kwargs_special_partial, self._kwargs_extinction_partial) self._norm_residuals = self._bandmodel.reduced_residuals( model, error_map=error_map) self._reduced_x2 = self._bandmodel.reduced_chi2(model, error_map=error_map) if verbose: print("reduced chi^2 of data ", band_index, "= ", self._reduced_x2) self._model = model self._cov_param = cov_param self._param = param self._error_map = error_map @property def model(self): """ :return: model, 2d numpy array """ return self._model @property def norm_residuals(self): """ :return: normalized residuals, 2d numpy array """ return self._norm_residuals @property def image_model_class(self): """ ImageModel() class instance of the single band with only the model components applied to this band :return: SingleBandMultiModel() instance, which inherits the ImageModel instance """ return self._bandmodel @property def kwargs_model(self): """ :return: keyword argument of keyword argument lists of the different model components selected for the imaging band, including linear amplitudes. These format matches the image_model_class() return """ kwargs_return = { 'kwargs_lens': self._kwargs_lens_partial, 'kwargs_source': self._kwargs_source_partial, 'kwargs_lens_light': self._kwargs_lens_light_partial, 'kwargs_ps': self._kwargs_ps_partial, 'kwargs_special': self._kwargs_special_partial, 'kwargs_extinction': self._kwargs_extinction_partial } return kwargs_return
class ModelBandPlot(object): """ class to plot a single band given the modeling results """ def __init__(self, multi_band_list, kwargs_model, model, error_map, cov_param, param, kwargs_params, likelihood_mask_list=None, band_index=0, arrow_size=0.02, cmap_string="gist_heat"): self.bandmodel = SingleBandMultiModel( multi_band_list, kwargs_model, likelihood_mask_list=likelihood_mask_list, band_index=band_index) self._kwargs_special_partial = kwargs_params.get( 'kwargs_special', None) kwarks_lens_partial, kwargs_source_partial, kwargs_lens_light_partial, kwargs_ps_partial, self._kwargs_extinction_partial = self.bandmodel.select_kwargs( **kwargs_params) self._kwargs_lens_partial, self._kwargs_source_partial, self._kwargs_lens_light_partial, self._kwargs_ps_partial = self.bandmodel.update_linear_kwargs( param, kwarks_lens_partial, kwargs_source_partial, kwargs_lens_light_partial, kwargs_ps_partial) self._norm_residuals = self.bandmodel.reduced_residuals( model, error_map=error_map) self._reduced_x2 = self.bandmodel.reduced_chi2(model, error_map=error_map) print("reduced chi^2 of data ", band_index, "= ", self._reduced_x2) self._model = model self._cov_param = cov_param self._param = param self._lensModel = self.bandmodel.LensModel self._lensModelExt = LensModelExtensions(self._lensModel) log_model = np.log10(model) log_model[np.isnan(log_model)] = -5 self._v_min_default = max(np.min(log_model), -5) self._v_max_default = min(np.max(log_model), 10) self._coords = self.bandmodel.Data self._data = self._coords.data self._deltaPix = self._coords.pixel_width self._frame_size = np.max(self._coords.width) x_grid, y_grid = self._coords.pixel_coordinates self._x_grid = util.image2array(x_grid) self._y_grid = util.image2array(y_grid) if isinstance(cmap_string, str): cmap = plt.get_cmap(cmap_string) else: cmap = cmap_string cmap.set_bad(color='k', alpha=1.) cmap.set_under('k') self._cmap = cmap self._arrow_size = arrow_size def _critical_curves(self): if not hasattr(self, '_ra_crit_list') or not hasattr( self, '_dec_crit_list'): self._ra_crit_list, self._dec_crit_list = self._lensModelExt.critical_curve_tiling( self._kwargs_lens_partial, compute_window=self._frame_size, start_scale=self._deltaPix / 5., max_order=10) return self._ra_crit_list, self._dec_crit_list def _caustics(self): if not hasattr(self, '_ra_caustic_list') or not hasattr( self, '_dec_caustic_list'): ra_crit_list, dec_crit_list = self._critical_curves() self._ra_caustic_list, self._dec_caustic_list = self._lensModel.ray_shooting( ra_crit_list, dec_crit_list, self._kwargs_lens_partial) return self._ra_caustic_list, self._dec_caustic_list def data_plot(self, ax, v_min=None, v_max=None, text='Observed', font_size=15, colorbar_label=r'log$_{10}$ flux', **kwargs): """ :param ax: :return: """ if v_min is None: v_min = self._v_min_default if v_max is None: v_max = self._v_max_default im = ax.matshow(np.log10(self._data), origin='lower', extent=[0, self._frame_size, 0, self._frame_size], cmap=self._cmap, vmin=v_min, vmax=v_max) # , vmin=0, vmax=2 ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) plot_util.scale_bar(ax, self._frame_size, dist=1, text='1"', font_size=font_size) plot_util.text_description(ax, self._frame_size, text=text, color="w", backgroundcolor='k', font_size=font_size) if 'no_arrow' not in kwargs or not kwargs['no_arrow']: plot_util.coordinate_arrows(ax, self._frame_size, self._coords, color='w', arrow_size=self._arrow_size, font_size=font_size) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax, orientation='vertical') cb.set_label(colorbar_label, fontsize=font_size) return ax def model_plot(self, ax, v_min=None, v_max=None, image_names=False, colorbar_label=r'log$_{10}$ flux', font_size=15, text='Reconstructed', **kwargs): """ :param ax: :param model: :param v_min: :param v_max: :return: """ if v_min is None: v_min = self._v_min_default if v_max is None: v_max = self._v_max_default im = ax.matshow(np.log10(self._model), origin='lower', vmin=v_min, vmax=v_max, extent=[0, self._frame_size, 0, self._frame_size], cmap=self._cmap) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) plot_util.scale_bar(ax, self._frame_size, dist=1, text='1"', font_size=font_size) plot_util.text_description(ax, self._frame_size, text=text, color="w", backgroundcolor='k', font_size=font_size) if 'no_arrow' not in kwargs or not kwargs['no_arrow']: plot_util.coordinate_arrows(ax, self._frame_size, self._coords, color='w', arrow_size=self._arrow_size, font_size=font_size) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(colorbar_label, fontsize=font_size) #plot_line_set(ax, self._coords, self._ra_caustic_list, self._dec_caustic_list, color='b') #plot_line_set(ax, self._coords, self._ra_crit_list, self._dec_crit_list, color='r') if image_names is True: ra_image, dec_image = self.bandmodel.PointSource.image_position( self._kwargs_ps_partial, self._kwargs_lens_partial) plot_util.image_position_plot(ax, self._coords, ra_image, dec_image) #source_position_plot(ax, self._coords, self._kwargs_source) def convergence_plot(self, ax, text='Convergence', v_min=None, v_max=None, font_size=15, colorbar_label=r'$\log_{10}\ \kappa$', **kwargs): """ :param x_grid: :param y_grid: :param kwargs_lens: :param kwargs_else: :return: """ if not 'cmap' in kwargs: kwargs['cmap'] = self._cmap kappa_result = util.array2image( self._lensModel.kappa(self._x_grid, self._y_grid, self._kwargs_lens_partial)) im = ax.matshow(np.log10(kappa_result), origin='lower', extent=[0, self._frame_size, 0, self._frame_size], cmap=kwargs['cmap'], vmin=v_min, vmax=v_max) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) plot_util.scale_bar(ax, self._frame_size, dist=1, text='1"', color='w', font_size=font_size) if 'no_arrow' not in kwargs or not kwargs['no_arrow']: plot_util.coordinate_arrows(ax, self._frame_size, self._coords, color='w', arrow_size=self._arrow_size, font_size=font_size) plot_util.text_description(ax, self._frame_size, text=text, color="w", backgroundcolor='k', flipped=False, font_size=font_size) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(colorbar_label, fontsize=font_size) return ax def normalized_residual_plot( self, ax, v_min=-6, v_max=6, font_size=15, text="Normalized Residuals", colorbar_label=r'(f${}_{\rm model}$ - f${}_{\rm data}$)/$\sigma$', no_arrow=False, **kwargs): """ :param ax: :param v_min: :param v_max: :param kwargs: kwargs to send to matplotlib.pyplot.matshow() :return: """ if not 'cmap' in kwargs: kwargs['cmap'] = 'bwr' im = ax.matshow(self._norm_residuals, vmin=v_min, vmax=v_max, extent=[0, self._frame_size, 0, self._frame_size], origin='lower', **kwargs) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) plot_util.scale_bar(ax, self._frame_size, dist=1, text='1"', color='k', font_size=font_size) plot_util.text_description(ax, self._frame_size, text=text, color="k", backgroundcolor='w', font_size=font_size) if not no_arrow: plot_util.coordinate_arrows(ax, self._frame_size, self._coords, color='w', arrow_size=self._arrow_size, font_size=font_size) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(colorbar_label, fontsize=font_size) return ax def absolute_residual_plot(self, ax, v_min=-1, v_max=1, font_size=15, text="Residuals", colorbar_label=r'(f$_{model}$-f$_{data}$)'): """ :param ax: :param residuals: :return: """ im = ax.matshow(self._model - self._data, vmin=v_min, vmax=v_max, extent=[0, self._frame_size, 0, self._frame_size], cmap='bwr', origin='lower') ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) plot_util.scale_bar(ax, self._frame_size, dist=1, text='1"', color='k', font_size=font_size) plot_util.text_description(ax, self._frame_size, text=text, color="k", backgroundcolor='w', font_size=font_size) plot_util.coordinate_arrows(ax, self._frame_size, self._coords, font_size=font_size, color='k', arrow_size=self._arrow_size) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(colorbar_label, fontsize=font_size) return ax def source(self, numPix, deltaPix, center=None, image_orientation=True): """ :param numPix: number of pixels per axes :param deltaPix: pixel size :param image_orientation: bool, if True, uses frame in orientation of the image, otherwise in RA-DEC coordinates :return: 2d surface brightness grid of the reconstructed source and Coordinates() instance of source grid """ if image_orientation is True: Mpix2coord = self._coords.transform_pix2angle * deltaPix / self._deltaPix x_grid_source, y_grid_source = util.make_grid_transformed( numPix, Mpix2Angle=Mpix2coord) ra_at_xy_0, dec_at_xy_0 = x_grid_source[0], y_grid_source[0] else: x_grid_source, y_grid_source, ra_at_xy_0, dec_at_xy_0, x_at_radec_0, y_at_radec_0, Mpix2coord, Mcoord2pix = util.make_grid_with_coordtransform( numPix, deltaPix) center_x = 0 center_y = 0 if center is not None: center_x, center_y = center[0], center[1] elif len(self._kwargs_source_partial) > 0: center_x = self._kwargs_source_partial[0]['center_x'] center_y = self._kwargs_source_partial[0]['center_y'] x_grid_source += center_x y_grid_source += center_y coords_source = Coordinates(transform_pix2angle=Mpix2coord, ra_at_xy_0=ra_at_xy_0 + center_x, dec_at_xy_0=dec_at_xy_0 + center_y) source = self.bandmodel.SourceModel.surface_brightness( x_grid_source, y_grid_source, self._kwargs_source_partial) source = util.array2image(source) * deltaPix**2 return source, coords_source def source_plot(self, ax, numPix, deltaPix_source, center=None, v_min=None, v_max=None, with_caustics=False, caustic_color='yellow', font_size=15, plot_scale='log', scale_size=0.1, text="Reconstructed source", colorbar_label=r'log$_{10}$ flux', point_source_position=True, **kwargs): """ :param ax: :param numPix: :param deltaPix_source: :param center: [center_x, center_y], if specified, uses this as the center :param v_min: :param v_max: :param with_caustics: :param caustic_color: :param font_size: :param plot_scale: string, log or linear, scale of surface brightness plot :param kwargs: :return: """ if v_min is None: v_min = self._v_min_default if v_max is None: v_max = self._v_max_default d_s = numPix * deltaPix_source source, coords_source = self.source(numPix, deltaPix_source, center=center) if plot_scale == 'log': source[source < 10**(v_min)] = 10**( v_min) # to remove weird shadow in plot source_scale = np.log10(source) elif plot_scale == 'linear': source_scale = source else: raise ValueError( 'variable plot_scale needs to be "log" or "linear", not %s.' % plot_scale) im = ax.matshow(source_scale, origin='lower', extent=[0, d_s, 0, d_s], cmap=self._cmap, vmin=v_min, vmax=v_max) # source ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(colorbar_label, fontsize=font_size) if with_caustics is True: ra_caustic_list, dec_caustic_list = self._caustics() plot_util.plot_line_set(ax, coords_source, ra_caustic_list, dec_caustic_list, color=caustic_color) plot_util.scale_bar(ax, d_s, dist=scale_size, text='{:.1f}"'.format(scale_size), color='w', flipped=False, font_size=font_size) if 'no_arrow' not in kwargs or not kwargs['no_arrow']: plot_util.coordinate_arrows(ax, self._frame_size, self._coords, color='w', arrow_size=self._arrow_size, font_size=font_size) plot_util.text_description(ax, d_s, text=text, color="w", backgroundcolor='k', flipped=False, font_size=font_size) if point_source_position is True: ra_source, dec_source = self.bandmodel.PointSource.source_position( self._kwargs_ps_partial, self._kwargs_lens_partial) plot_util.source_position_plot(ax, coords_source, ra_source, dec_source) return ax def error_map_source_plot(self, ax, numPix, deltaPix_source, v_min=None, v_max=None, with_caustics=False, font_size=15, point_source_position=True): x_grid_source, y_grid_source = util.make_grid_transformed( numPix, self._coords.transform_pix2angle * deltaPix_source / self._deltaPix) x_center = self._kwargs_source_partial[0]['center_x'] y_center = self._kwargs_source_partial[0]['center_y'] x_grid_source += x_center y_grid_source += y_center coords_source = Coordinates(self._coords.transform_pix2angle * deltaPix_source / self._deltaPix, ra_at_xy_0=x_grid_source[0], dec_at_xy_0=y_grid_source[0]) error_map_source = self.bandmodel.error_map_source( self._kwargs_source_partial, x_grid_source, y_grid_source, self._cov_param) error_map_source = util.array2image(error_map_source) d_s = numPix * deltaPix_source im = ax.matshow(error_map_source, origin='lower', extent=[0, d_s, 0, d_s], cmap=self._cmap, vmin=v_min, vmax=v_max) # source ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(r'error variance', fontsize=font_size) if with_caustics: ra_caustic_list, dec_caustic_list = self._caustics() plot_util.plot_line_set(ax, coords_source, ra_caustic_list, dec_caustic_list, color='b') plot_util.scale_bar(ax, d_s, dist=0.1, text='0.1"', color='w', flipped=False, font_size=font_size) plot_util.coordinate_arrows(ax, d_s, coords_source, arrow_size=self._arrow_size, color='w', font_size=font_size) plot_util.text_description(ax, d_s, text="Error map in source", color="w", backgroundcolor='k', flipped=False, font_size=font_size) if point_source_position is True: ra_source, dec_source = self.bandmodel.PointSource.source_position( self._kwargs_ps_partial, self._kwargs_lens_partial) plot_util.source_position_plot(ax, coords_source, ra_source, dec_source) return ax def magnification_plot(self, ax, v_min=-10, v_max=10, image_name_list=None, font_size=15, no_arrow=False, text="Magnification model", colorbar_label=r"$\det\ (\mathsf{A}^{-1})$", **kwargs): """ :param ax: matplotib axis instance :param v_min: minimum range of plotting :param v_max: maximum range of plotting :param kwargs: kwargs to send to matplotlib.pyplot.matshow() :return: """ if not 'cmap' in kwargs: kwargs['cmap'] = self._cmap if not 'alpha' in kwargs: kwargs['alpha'] = 0.5 mag_result = util.array2image( self._lensModel.magnification(self._x_grid, self._y_grid, self._kwargs_lens_partial)) im = ax.matshow(mag_result, origin='lower', extent=[0, self._frame_size, 0, self._frame_size], vmin=v_min, vmax=v_max, **kwargs) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) plot_util.scale_bar(ax, self._frame_size, dist=1, text='1"', color='k', font_size=font_size) if not no_arrow: plot_util.coordinate_arrows(ax, self._frame_size, self._coords, color='k', arrow_size=self._arrow_size, font_size=font_size) plot_util.text_description(ax, self._frame_size, text=text, color="k", backgroundcolor='w', font_size=font_size) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(colorbar_label, fontsize=font_size) ra_image, dec_image = self.bandmodel.PointSource.image_position( self._kwargs_ps_partial, self._kwargs_lens_partial) plot_util.image_position_plot(ax, self._coords, ra_image, dec_image, color='k', image_name_list=image_name_list) return ax def deflection_plot(self, ax, v_min=None, v_max=None, axis=0, with_caustics=False, image_name_list=None, text="Deflection model", font_size=15, colorbar_label=r'arcsec'): """ :param kwargs_lens: :param kwargs_else: :return: """ alpha1, alpha2 = self._lensModel.alpha(self._x_grid, self._y_grid, self._kwargs_lens_partial) alpha1 = util.array2image(alpha1) alpha2 = util.array2image(alpha2) if axis == 0: alpha = alpha1 else: alpha = alpha2 im = ax.matshow(alpha, origin='lower', extent=[0, self._frame_size, 0, self._frame_size], vmin=v_min, vmax=v_max, cmap=self._cmap, alpha=0.5) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) plot_util.scale_bar(ax, self._frame_size, dist=1, text='1"', color='k', font_size=font_size) plot_util.coordinate_arrows(ax, self._frame_size, self._coords, color='k', arrow_size=self._arrow_size, font_size=font_size) plot_util.text_description(ax, self._frame_size, text=text, color="k", backgroundcolor='w', font_size=font_size) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(colorbar_label, fontsize=font_size) if with_caustics is True: ra_crit_list, dec_crit_list = self._critical_curves() ra_caustic_list, dec_caustic_list = self._caustics() plot_util.plot_line_set(ax, self._coords, ra_caustic_list, dec_caustic_list, color='b') plot_util.plot_line_set(ax, self._coords, ra_crit_list, dec_crit_list, color='r') ra_image, dec_image = self.bandmodel.PointSource.image_position( self._kwargs_ps_partial, self._kwargs_lens_partial) plot_util.image_position_plot(ax, self._coords, ra_image, dec_image, image_name_list=image_name_list) return ax def decomposition_plot(self, ax, text='Reconstructed', v_min=None, v_max=None, unconvolved=False, point_source_add=False, font_size=15, source_add=False, lens_light_add=False, **kwargs): """ :param ax: :param text: :param v_min: :param v_max: :param unconvolved: :param point_source_add: :param source_add: :param lens_light_add: :param kwargs: kwargs to send matplotlib.pyplot.matshow() :return: """ model = self.bandmodel.image(self._kwargs_lens_partial, self._kwargs_source_partial, self._kwargs_lens_light_partial, self._kwargs_ps_partial, unconvolved=unconvolved, source_add=source_add, lens_light_add=lens_light_add, point_source_add=point_source_add) if v_min is None: v_min = self._v_min_default if v_max is None: v_max = self._v_max_default if not 'cmap' in kwargs: kwargs['cmap'] = self._cmap im = ax.matshow(np.log10(model), origin='lower', vmin=v_min, vmax=v_max, extent=[0, self._frame_size, 0, self._frame_size], **kwargs) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) plot_util.scale_bar(ax, self._frame_size, dist=1, text='1"', font_size=font_size) plot_util.text_description(ax, self._frame_size, text=text, color="w", backgroundcolor='k') plot_util.coordinate_arrows(ax, self._frame_size, self._coords, arrow_size=self._arrow_size, font_size=font_size) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(r'log$_{10}$ flux', fontsize=font_size) return ax def subtract_from_data_plot(self, ax, text='Subtracted', v_min=None, v_max=None, point_source_add=False, source_add=False, lens_light_add=False, font_size=15): model = self.bandmodel.image(self._kwargs_lens_partial, self._kwargs_source_partial, self._kwargs_lens_light_partial, self._kwargs_ps_partial, unconvolved=False, source_add=source_add, lens_light_add=lens_light_add, point_source_add=point_source_add) if v_min is None: v_min = self._v_min_default if v_max is None: v_max = self._v_max_default im = ax.matshow(np.log10(self._data - model), origin='lower', vmin=v_min, vmax=v_max, extent=[0, self._frame_size, 0, self._frame_size], cmap=self._cmap) ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) ax.autoscale(False) plot_util.scale_bar(ax, self._frame_size, dist=1, text='1"', font_size=font_size) plot_util.text_description(ax, self._frame_size, text=text, color="w", backgroundcolor='k', font_size=font_size) plot_util.coordinate_arrows(ax, self._frame_size, self._coords, arrow_size=self._arrow_size, font_size=font_size) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = plt.colorbar(im, cax=cax) cb.set_label(r'log$_{10}$ flux', fontsize=font_size) return ax def plot_main(self, with_caustics=False): """ print the main plots together in a joint frame :return: """ f, axes = plt.subplots(2, 3, figsize=(16, 8)) self.data_plot(ax=axes[0, 0]) self.model_plot(ax=axes[0, 1], image_names=True) self.normalized_residual_plot(ax=axes[0, 2], v_min=-6, v_max=6) self.source_plot(ax=axes[1, 0], deltaPix_source=0.01, numPix=100, with_caustics=with_caustics) self.convergence_plot(ax=axes[1, 1], v_max=1) self.magnification_plot(ax=axes[1, 2]) f.tight_layout() f.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0., hspace=0.05) return f, axes def plot_separate(self): """ plot the different model components separately :return: """ f, axes = plt.subplots(2, 3, figsize=(16, 8)) self.decomposition_plot(ax=axes[0, 0], text='Lens light', lens_light_add=True, unconvolved=True) self.decomposition_plot(ax=axes[1, 0], text='Lens light convolved', lens_light_add=True) self.decomposition_plot(ax=axes[0, 1], text='Source light', source_add=True, unconvolved=True) self.decomposition_plot(ax=axes[1, 1], text='Source light convolved', source_add=True) self.decomposition_plot(ax=axes[0, 2], text='All components', source_add=True, lens_light_add=True, unconvolved=True) self.decomposition_plot(ax=axes[1, 2], text='All components convolved', source_add=True, lens_light_add=True, point_source_add=True) f.tight_layout() f.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0., hspace=0.05) return f, axes def plot_subtract_from_data_all(self): """ subtract model components from data :return: """ f, axes = plt.subplots(2, 3, figsize=(16, 8)) self.subtract_from_data_plot(ax=axes[0, 0], text='Data') self.subtract_from_data_plot(ax=axes[0, 1], text='Data - Point Source', point_source_add=True) self.subtract_from_data_plot(ax=axes[0, 2], text='Data - Lens Light', lens_light_add=True) self.subtract_from_data_plot(ax=axes[1, 0], text='Data - Source Light', source_add=True) self.subtract_from_data_plot(ax=axes[1, 1], text='Data - Source Light - Point Source', source_add=True, point_source_add=True) self.subtract_from_data_plot(ax=axes[1, 2], text='Data - Lens Light - Point Source', lens_light_add=True, point_source_add=True) f.tight_layout() f.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0., hspace=0.05) return f, axes def plot_extinction_map(self, ax, v_min=None, v_max=None, **kwargs): """ :param ax: :param v_min: :param v_max: :return: """ model = self.bandmodel.extinction_map(self._kwargs_extinction_partial, self._kwargs_special_partial) if v_min is None: v_min = 0 if v_max is None: v_max = 1 im = ax.matshow(model, origin='lower', vmin=v_min, vmax=v_max, extent=[0, self._frame_size, 0, self._frame_size], **kwargs) return ax
def setup(self): # data specifics sigma_bkg = 0.05 # background noise per pixel exp_time = 100 # exposure time (arbitrary units, flux per pixel is in units #photons/exp_time unit) numPix = 10 # cutout pixel size deltaPix = 0.1 # pixel size in arcsec (area per pixel = deltaPix**2) fwhm = 0.5 # full width half max of PSF # PSF specification kwargs_data = simulation_util.data_configure_simple( numPix, deltaPix, exp_time, sigma_bkg) data_class = ImageData(**kwargs_data) kwargs_psf = { 'psf_type': 'GAUSSIAN', 'fwhm': fwhm, 'pixel_size': deltaPix } psf_class = PSF(**kwargs_psf) kwargs_spemd = { 'theta_E': 1., 'gamma': 1.8, 'center_x': 0, 'center_y': 0, 'e1': 0.1, 'e2': 0.1 } lens_model_list = ['SPEP'] kwargs_lens = [kwargs_spemd] lens_model_class = LensModel(lens_model_list=lens_model_list) kwargs_sersic = { 'amp': 1., 'R_sersic': 0.1, 'n_sersic': 2, 'center_x': 0, 'center_y': 0 } # 'SERSIC_ELLIPSE': elliptical Sersic profile kwargs_sersic_ellipse = { 'amp': 1., 'R_sersic': .6, 'n_sersic': 3, 'center_x': 0, 'center_y': 0, 'e1': 0.1, 'e2': 0.1 } lens_light_model_list = ['SERSIC'] kwargs_lens_light = [kwargs_sersic] lens_light_model_class = LightModel( light_model_list=lens_light_model_list) source_model_list = ['SERSIC_ELLIPSE'] kwargs_source = [kwargs_sersic_ellipse] source_model_class = LightModel(light_model_list=source_model_list) # Point Source point_source_model_list = ['UNLENSED'] kwargs_ps = [{ 'ra_image': [0.4], 'dec_image': [-0.2], 'point_amp': [2] }] point_source_class = PointSource( point_source_type_list=point_source_model_list) kwargs_numerics = { 'supersampling_factor': 1, 'supersampling_convolution': False, 'compute_mode': 'regular' } imageModel = ImageModel(data_class, psf_class, lens_model_class, source_model_class, lens_light_model_class, point_source_class=point_source_class, kwargs_numerics=kwargs_numerics) image_sim = simulation_util.simulate_simple(imageModel, kwargs_lens, kwargs_source, kwargs_lens_light, kwargs_ps) data_class.update_data(image_sim) kwargs_data['image_data'] = image_sim self.multi_band_list = [[kwargs_data, kwargs_psf, kwargs_numerics]] self.kwargs_model = { 'lens_model_list': lens_model_list, 'source_light_model_list': source_model_list, 'lens_light_model_list': lens_light_model_list, 'point_source_model_list': point_source_model_list, 'fixed_magnification_list': [False], 'index_lens_model_list': [[0]], 'index_lens_light_model_list': [[0]], 'index_source_light_model_list': [[0]], 'index_point_source_model_list': [[0]], } self.kwargs_params = { 'kwargs_lens': kwargs_lens, 'kwargs_source': kwargs_source, 'kwargs_lens_light': kwargs_lens_light, 'kwargs_ps': kwargs_ps } self.single_band = SingleBandMultiModel( multi_band_list=self.multi_band_list, kwargs_model=self.kwargs_model, linear_solver=True) self.single_band_no_linear = SingleBandMultiModel( multi_band_list=self.multi_band_list, kwargs_model=self.kwargs_model, linear_solver=False)