def test_create_solver_class(self): from slitronomy.Optimization.solver_source import SparseSolverSource source_model_class = LightModel(['SLIT_STARLETS']) lens_light_model_class = LightModel([]) point_source_class = PointSource(point_source_type_list=[]) source_numerics_class = NumericsSubFrame(self.imageModel.Data, self.imageModel.PSF, supersampling_factor=2) solver_class = class_util.create_solver_class( self.imageModel.Data, self.imageModel.PSF, self.imageModel.ImageNumerics, source_numerics_class, self.imageModel.LensModel, source_model_class, lens_light_model_class, point_source_class, self.imageModel._extinction, self.kwargs_sparse_solver) assert isinstance(solver_class, SparseSolverSource) from slitronomy.Optimization.solver_source_lens import SparseSolverSourceLens source_model_class = LightModel(['SLIT_STARLETS']) lens_light_model_class = LightModel(['SLIT_STARLETS']) point_source_class = PointSource(point_source_type_list=[]) source_numerics_class = NumericsSubFrame(self.imageModel.Data, self.imageModel.PSF, supersampling_factor=2) solver_class = class_util.create_solver_class( self.imageModel.Data, self.imageModel.PSF, self.imageModel.ImageNumerics, source_numerics_class, self.imageModel.LensModel, source_model_class, lens_light_model_class, point_source_class, self.imageModel._extinction, self.kwargs_sparse_solver) assert isinstance(solver_class, SparseSolverSourceLens)
def __init__(self, data_class, psf_class, lens_model_class=None, source_model_class=None, lens_light_model_class=None, point_source_class=None, extinction_class=None, kwargs_numerics=None): """ :param data_class: instance of ImageData() or PixelGrid() class :param psf_class: instance of PSF() class :param lens_model_class: instance of LensModel() class :param source_model_class: instance of LightModel() class describing the source parameters :param lens_light_model_class: instance of LightModel() class describing the lens light parameters :param point_source_class: instance of PointSource() class describing the point sources :param kwargs_numerics: keyword argument with various numeric description (see ImageNumerics class for options) """ self.type = 'single-band' self.PSF = psf_class self.Data = data_class self.PSF.set_pixel_size(self.Data.pixel_width) if kwargs_numerics is None: kwargs_numerics = {} self.ImageNumerics = NumericsSubFrame(pixel_grid=self.Data, psf=self.PSF, **kwargs_numerics) if lens_model_class is None: lens_model_class = LensModel(lens_model_list=[]) self.LensModel = lens_model_class if point_source_class is None: point_source_class = PointSource(point_source_type_list=[]) self.PointSource = point_source_class self.PointSource.update_lens_model(lens_model_class=lens_model_class) x_center, y_center = self.Data.center self.PointSource.update_search_window( search_window=np.max(self.Data.width), x_center=x_center, y_center=y_center, min_distance=self.Data.pixel_width, only_from_unspecified=True) self._psf_error_map = self.PSF.psf_error_map_bool if source_model_class is None: source_model_class = LightModel(light_model_list=[]) self.SourceModel = source_model_class if lens_light_model_class is None: lens_light_model_class = LightModel(light_model_list=[]) self.LensLightModel = lens_light_model_class self.source_mapping = Image2SourceMapping( lensModel=lens_model_class, sourceModel=source_model_class) self.num_bands = 1 self._kwargs_numerics = kwargs_numerics if extinction_class is None: extinction_class = DifferentialExtinction(optical_depth_model=[]) self._extinction = extinction_class
def setup(self): self.num_pix = 20 # cutout pixel size delta_pix = 0.2 background_rms = 0.05 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=self.num_pix, deltapix=delta_pix, subgrid_res=1, inverse=False, left_lower=False) # imaging data class kwargs_data = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': np.zeros((self.num_pix, self.num_pix)), 'background_rms': background_rms, 'noise_map': background_rms * np.ones( (self.num_pix, self.num_pix)), } data_class = ImageData(**kwargs_data) # lens mass class lens_model_class = LensModel(['SPEP']) self.kwargs_lens = [{ 'theta_E': 1, 'gamma': 2, 'center_x': 0, 'center_y': 0, 'e1': -0.05, 'e2': 0.05 }] # source light class source_model_class = LightModel(['SLIT_STARLETS']) self.kwargs_source = [{ 'coeffs': 0, 'n_scales': 3, 'n_pixels': self.num_pix**2 }] # define numerics classes image_numerics_class = NumericsSubFrame(pixel_grid=data_class, psf=PSF(psf_type='NONE')) source_numerics_class = NumericsSubFrame(pixel_grid=data_class, psf=PSF(psf_type='NONE'), supersampling_factor=1) # init sparse solver self.solver = SparseSolverSource(data_class, lens_model_class, image_numerics_class, source_numerics_class, source_model_class, num_iter_source=10) # init the tracker self.tracker_alone = SolverTracker(self.solver, verbose=True)
def test_raise(self): with self.assertRaises(ValueError): num_pix = 10 data = ImageData(np.zeros((num_pix, num_pix))) lens_model = LensModel(['SPEP']) image_grid_class = NumericsSubFrame(data, PSF('NONE')).grid_class source_grid_class = NumericsSubFrame(data, PSF('NONE')).grid_class lensing_op = LensingOperator(lens_model, image_grid_class, source_grid_class, num_pix, source_interpolation='sth')
def update_psf(self, psf_class): """ update the instance of the class with a new instance of PSF() with a potentially different point spread function :param psf_class: :return: no return. Class is updated. """ self.PSF = psf_class self.PSF.set_pixel_size(self.Data.pixel_width) self.ImageNumerics = NumericsSubFrame(pixel_grid=self.Data, psf=self.PSF, **self._kwargs_numerics)
def __init__(self, *args, **kwargs): super(TestRaise, self).__init__(*args, **kwargs) self.num_pix = 49 # cutout pixel size self.subgrid_res_source = 1 self.num_pix_source = self.num_pix * self.subgrid_res_source delta_pix = 0.24 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=self.num_pix, deltapix=delta_pix, subgrid_res=1, inverse=False, left_lower=False) image_data = np.random.rand(self.num_pix, self.num_pix) self.kwargs_data = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': image_data, 'background_rms': 0.01, 'noise_map': 0.01 * np.ones_like(image_data), } self.data = ImageData(**self.kwargs_data) self.lens_model_class = LensModel(['SPEP']) self.kwargs_lens = [{ 'theta_E': 1, 'gamma': 2, 'center_x': 0, 'center_y': 0, 'e1': -0.05, 'e2': 0.05 }] self.source_model_class = LightModel(['SLIT_STARLETS']) self.lens_light_model_class = LightModel(['SLIT_STARLETS']) self.kwargs_source = [{'n_scales': 4}] self.kwargs_lens_light = [{'n_scales': 4}] psf = PSF(psf_type='NONE') self.numerics = NumericsSubFrame(pixel_grid=self.data, psf=psf) self.source_numerics = NumericsSubFrame( pixel_grid=self.data, psf=psf, supersampling_factor=self.subgrid_res_source) self.solver_source_lens = SparseSolverSourceLens( self.data, self.lens_model_class, self.numerics, self.source_numerics, self.source_model_class, self.lens_light_model_class, num_iter_source=1, num_iter_lens=1, num_iter_weights=1)
def setup(self): self.num_pix = 25 # cutout pixel size self.subgrid_res_source = 2 delta_pix = 0.32 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=self.num_pix, deltapix=delta_pix, subgrid_res=1, inverse=False, left_lower=False) kwargs_data = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': np.zeros((self.num_pix, self.num_pix)) } data_class = ImageData(**kwargs_data) numerics_image = NumericsSubFrame(data_class, PSF('NONE')) numerics_source = NumericsSubFrame( data_class, PSF('NONE'), supersampling_factor=self.subgrid_res_source) self.source_plane = SizeablePlaneGrid(numerics_source.grid_class, verbose=True) # create a mask mimicking the real case of lensing operation lens_model_class = LensModel(['SIE']) kwargs_lens = [{ 'theta_E': 1.5, 'center_x': 0, 'center_y': 0, 'e1': 0.1, 'e2': 0.1 }] lensing_op = LensingOperator(lens_model_class, numerics_image.grid_class, numerics_source.grid_class, self.num_pix, self.subgrid_res_source) lensing_op.update_mapping(kwargs_lens) unit_image = np.ones((self.num_pix, self.num_pix)) mask_image = np.zeros((self.num_pix, self.num_pix)) mask_image[2:-2, 2:-2] = 1 # some binary image that mask out borders self.unit_image_mapped = lensing_op.image2source_2d(unit_image, no_flux_norm=False) self.mask_mapped = lensing_op.image2source_2d(mask_image)
def __init__(self, *args, **kwargs): super(TestRaise, self).__init__(*args, **kwargs) self.num_pix = 10 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=self.num_pix, deltapix=0.5, subgrid_res=1, inverse=False, left_lower=False) kwargs_data_nonsquare = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': np.zeros( (self.num_pix, self.num_pix + 10)), # non-square image } kwargs_data = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': np.zeros( (self.num_pix, self.num_pix)), # non-square image } self.data_nonsquare = ImageData(**kwargs_data_nonsquare) self.data = ImageData(**kwargs_data) psf = PSF('NONE') self.numerics = NumericsSubFrame(self.data, psf) lens_model = LensModel(['SPEP']) self.source_model_class = LightModel(['SLIT_STARLETS']) self.lens_light_model_class = LightModel(['SLIT_STARLETS']) # get grid classes image_grid_class = self.numerics.grid_class source_numerics = NumericsSubFrame(self.data, psf, supersampling_factor=1) source_grid_class = source_numerics.grid_class self.lensing_op = LensingOperator(lens_model, image_grid_class, source_grid_class, self.num_pix) self.model_op = ModelOperators(self.data, self.lensing_op, self.numerics) self.model_op.add_lens_light(self.lens_light_model_class) self.model_op_nolens = ModelOperators(self.data, self.lensing_op, self.numerics)
def setup(self): self.num_pix = 25 # cutout pixel size self.delta_pix = 0.24 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=self.num_pix, deltapix=self.delta_pix, subgrid_res=1, inverse=False, left_lower=False) kwargs_data = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': np.zeros((self.num_pix, self.num_pix)) } numerics = NumericsSubFrame(ImageData(**kwargs_data), PSF('NONE')) self.plane_grid = PlaneGrid(numerics.grid_class)
def test_source_plane_coordinates(self): lensing_op = LensingOperator(self.lens_model, self.image_grid_class, self.source_grid_class_default, self.num_pix) theta_x, theta_y = lensing_op.source_plane_coordinates assert theta_x.size == self.num_pix**2 assert theta_y.size == self.num_pix**2 subgrid_res = 2 source_grid_class = NumericsSubFrame( self.data, self.psf, supersampling_factor=subgrid_res).grid_class lensing_op = LensingOperator(self.lens_model, self.image_grid_class, source_grid_class, self.num_pix) theta_x, theta_y = lensing_op.source_plane_coordinates assert theta_x.size == self.num_pix**2 * subgrid_res**2 assert theta_y.size == self.num_pix**2 * subgrid_res**2
def test_raise(self): with self.assertRaises(ValueError): # test rectangular size num_pix_x = 25 num_pix_y = 30 delta_pix = 0.24 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=num_pix_x, deltapix=delta_pix, subgrid_res=1, inverse=False, left_lower=False) kwargs_data = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': np.zeros((num_pix_x, num_pix_y)) } numerics = NumericsSubFrame(ImageData(**kwargs_data), PSF('NONE')) plane_grid = PlaneGrid(numerics.grid_class)
def _setup_pixelbased_source_numerics(self, kwargs_numerics, kwargs_pixelbased): """ Check if model requirement are compatible with support pixel-based solver, and creates a new numerics class specifically for source plane. :param kwargs_numerics: keyword argument with various numeric description (see ImageNumerics class for options) :param kwargs_pixelbased: keyword argument with various settings related to the pixel-based solver (see SLITronomy documentation) """ # check that the required convolution type is compatible with pixel-based modelling (in current implementation) psf_type = self.PSF.psf_type supersampling_convolution = kwargs_numerics.get( 'supersampling_convolution', False) supersampling_factor = kwargs_numerics.get('supersampling_factor', 1) compute_mode = kwargs_numerics.get('compute_mode', 'regular') if psf_type not in ['PIXEL', 'NONE']: raise ValueError( "Only convolution using a pixelated kernel is supported for pixel-based modelling" ) if compute_mode != 'regular': raise ValueError( "Only regular coordinate grid is supported for pixel-based modelling" ) if (supersampling_convolution is True and supersampling_factor > 1): raise ValueError( "Only non-supersampled convolution is supported for pixel-based modelling" ) # setup the source numerics with a (possibily) different supersampling resolution supersampling_factor_source = kwargs_pixelbased.pop( 'supersampling_factor_source', 1) kwargs_numerics_source = kwargs_numerics.copy() kwargs_numerics_source[ 'supersampling_factor'] = supersampling_factor_source kwargs_numerics_source['compute_mode'] = 'regular' source_numerics_class = NumericsSubFrame(pixel_grid=self.Data, psf=self.PSF, **kwargs_numerics_source) return source_numerics_class
def setup(self): # data specifics sigma_bkg = .05 # background noise per pixel exp_time = 100 # exposure time (arbitrary units, flux per pixel is in units #photons/exp_time unit) self.num_pix = 100 # cutout pixel size delta_pix = 0.05 # pixel size in arcsec (area per pixel = delta_pix**2) fwhm = 0.5 # full width half max of PSF # supersampling factor for source plane self.subgrid_res_source = 1 self.num_pix_source = self.num_pix * self.subgrid_res_source # wavelets scales for lens and source self.n_scales_source = 4 self.n_scales_lens = 3 # prepare data simulation kwargs_data = sim_util.data_configure_simple(self.num_pix, delta_pix, exp_time, sigma_bkg, inverse=True) data_class = ImageData(**kwargs_data) # generate sa pixelated gaussian PSF kernel kwargs_psf = { 'psf_type': 'GAUSSIAN', 'fwhm': fwhm, 'truncation': 5, 'pixel_size': delta_pix } psf_class = PSF(**kwargs_psf) kernel = psf_class.kernel_point_source kwargs_psf = { 'psf_type': 'PIXEL', 'kernel_point_source': kernel, 'psf_error_map': np.ones_like(kernel) * 0.001 } psf_class = PSF(**kwargs_psf) # 'EXERNAL_SHEAR': external shear kwargs_shear = { 'gamma1': 0.01, 'gamma2': 0.01 } # gamma_ext: shear strength, psi_ext: shear angel (in radian) phi, q = 0.2, 0.8 e1, e2 = param_util.phi_q2_ellipticity(phi, q) kwargs_spemd = { 'theta_E': 1., 'gamma': 1.8, 'center_x': 0, 'center_y': 0, 'e1': e1, 'e2': e2 } lens_model_list = ['SPEP', 'SHEAR'] self.kwargs_lens = [kwargs_spemd, kwargs_shear] self.lens_model_class = LensModel(lens_model_list=lens_model_list) # list of light profiles (for lens and source) # 'SERSIC': spherical Sersic profile kwargs_sersic = { 'amp': 1., 'R_sersic': 0.1, 'n_sersic': 2, 'center_x': 0, 'center_y': 0 } # 'SERSIC_ELLIPSE': elliptical Sersic profile phi, q = 0.2, 0.9 e1, e2 = param_util.phi_q2_ellipticity(phi, q) kwargs_sersic_ellipse = { 'amp': 1., 'R_sersic': .6, 'n_sersic': 7, 'center_x': 0, 'center_y': 0, 'e1': e1, 'e2': e2 } 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) # list of lens light profiles point_source_class = PointSource(['LENSED_POSITION']) lens_eq_solver = LensEquationSolver(lensModel=self.lens_model_class) ra_image, dec_image = lens_eq_solver.image_position_from_source( sourcePos_x=kwargs_source[0]['center_x'], sourcePos_y=kwargs_source[0]['center_y'], kwargs_lens=self.kwargs_lens) point_amp = np.ones_like(ra_image) kwargs_ps = [{ 'ra_image': ra_image, 'dec_image': dec_image, 'point_amp': point_amp }] # simulate data kwargs_numerics = {'supersampling_factor': 1} imageModel = ImageModel(data_class, psf_class, self.lens_model_class, source_model_class, lens_light_model_class, point_source_class, kwargs_numerics=kwargs_numerics) self.image_sim = sim_util.simulate_simple(imageModel, self.kwargs_lens, kwargs_source, kwargs_lens_light, kwargs_ps) data_class.update_data(self.image_sim) # retrieve the point source data only (for initial guess for source+PS solver) self.ps_sim = imageModel.image(self.kwargs_lens, kwargs_source, kwargs_lens_light, kwargs_ps, source_add=False, lens_light_add=False, point_source_add=True) # define some mask self.likelihood_mask = np.zeros((self.num_pix, self.num_pix)) self.likelihood_mask[5:-5, 5:-5] = 1 # get a numerics classes numerics = NumericsSubFrame(pixel_grid=data_class, psf=psf_class) source_numerics = NumericsSubFrame( pixel_grid=data_class, psf=psf_class, supersampling_factor=self.subgrid_res_source) self.num_iter_source = 20 self.num_iter_lens = 10 self.num_iter_global = 7 self.num_iter_weights = 2 # source grid offsets self.kwargs_special = { 'delta_x_source_grid': 0, 'delta_y_source_grid': 0, } # init the solvers # SOLVER SOURCE, with analysis formulation self.source_model_class = LightModel(['SLIT_STARLETS']) self.kwargs_source = [{'n_scales': self.n_scales_source}] self.solver_source_ana = SparseSolverSource( data_class, self.lens_model_class, numerics, source_numerics, self.source_model_class, source_interpolation='bilinear', minimal_source_plane=False, use_mask_for_minimal_source_plane=True, min_num_pix_source=20, sparsity_prior_norm=1, force_positivity=True, formulation='analysis', verbose=False, show_steps=False, min_threshold=5, threshold_increment_high_freq=1, threshold_decrease_type='exponential', num_iter_source=self.num_iter_source, num_iter_weights=self.num_iter_weights) self.solver_source_ana.set_likelihood_mask(self.likelihood_mask) # SOLVER SOURCE + LENS, with synthesis formulation self.lens_light_model_class = LightModel(['SLIT_STARLETS']) self.kwargs_lens_light = [{'n_scales': self.n_scales_lens}] self.solver_lens_syn = SparseSolverSourceLens( data_class, self.lens_model_class, numerics, source_numerics, self.source_model_class, self.lens_light_model_class, source_interpolation='bilinear', minimal_source_plane=False, use_mask_for_minimal_source_plane=True, min_num_pix_source=20, sparsity_prior_norm=1, force_positivity=True, formulation='synthesis', verbose=False, show_steps=False, min_threshold=3, threshold_increment_high_freq=1, threshold_decrease_type='linear', num_iter_global=self.num_iter_global, num_iter_source=self.num_iter_source, num_iter_lens=self.num_iter_lens, num_iter_weights=self.num_iter_weights) self.solver_lens_syn.set_likelihood_mask(self.likelihood_mask)
class ImageModel(object): """ this class uses functions of lens_model and source_model to make a lensed image """ def __init__(self, data_class, psf_class, lens_model_class=None, source_model_class=None, lens_light_model_class=None, point_source_class=None, extinction_class=None, kwargs_numerics=None, kwargs_pixelbased=None): """ :param data_class: instance of ImageData() or PixelGrid() class :param psf_class: instance of PSF() class :param lens_model_class: instance of LensModel() class :param source_model_class: instance of LightModel() class describing the source parameters :param lens_light_model_class: instance of LightModel() class describing the lens light parameters :param point_source_class: instance of PointSource() class describing the point sources :param kwargs_numerics: keyword arguments with various numeric description (see ImageNumerics class for options) :param kwargs_pixelbased: keyword arguments with various settings related to the pixel-based solver (see SLITronomy documentation) """ self.type = 'single-band' self.num_bands = 1 self.PSF = psf_class self.Data = data_class self.PSF.set_pixel_size(self.Data.pixel_width) if kwargs_numerics is None: kwargs_numerics = {} self.ImageNumerics = NumericsSubFrame(pixel_grid=self.Data, psf=self.PSF, **kwargs_numerics) if lens_model_class is None: lens_model_class = LensModel(lens_model_list=[]) self.LensModel = lens_model_class if point_source_class is None: point_source_class = PointSource(point_source_type_list=[]) self.PointSource = point_source_class self.PointSource.update_lens_model(lens_model_class=lens_model_class) x_center, y_center = self.Data.center self.PointSource.update_search_window( search_window=np.max(self.Data.width), x_center=x_center, y_center=y_center, min_distance=self.Data.pixel_width, only_from_unspecified=True) self._psf_error_map = self.PSF.psf_error_map_bool if source_model_class is None: source_model_class = LightModel(light_model_list=[]) self.SourceModel = source_model_class if lens_light_model_class is None: lens_light_model_class = LightModel(light_model_list=[]) self.LensLightModel = lens_light_model_class self._kwargs_numerics = kwargs_numerics if extinction_class is None: extinction_class = DifferentialExtinction(optical_depth_model=[]) self._extinction = extinction_class if kwargs_pixelbased is None: kwargs_pixelbased = {} else: kwargs_pixelbased = kwargs_pixelbased.copy() self._pixelbased_bool = self._detect_pixelbased_models() if self._pixelbased_bool is True: from slitronomy.Util.class_util import create_solver_class # requirement on SLITronomy is exclusively here self.SourceNumerics = self._setup_pixelbased_source_numerics( kwargs_numerics, kwargs_pixelbased) self.PixelSolver = create_solver_class( self.Data, self.PSF, self.ImageNumerics, self.SourceNumerics, self.LensModel, self.SourceModel, self.LensLightModel, self.PointSource, self._extinction, kwargs_pixelbased) self.source_mapping = None # handled with pixelated operator else: self.source_mapping = Image2SourceMapping( lensModel=lens_model_class, sourceModel=source_model_class) def reset_point_source_cache(self, cache=True): """ deletes all the cache in the point source class and saves it from then on :param cache: boolean, if True, saves the next occuring point source positions in the cache :return: None """ self.PointSource.delete_lens_model_cache() self.PointSource.set_save_cache(cache) def update_psf(self, psf_class): """ update the instance of the class with a new instance of PSF() with a potentially different point spread function :param psf_class: :return: no return. Class is updated. """ self.PSF = psf_class self.PSF.set_pixel_size(self.Data.pixel_width) self.ImageNumerics = NumericsSubFrame(pixel_grid=self.Data, psf=self.PSF, **self._kwargs_numerics) def source_surface_brightness(self, kwargs_source, kwargs_lens=None, kwargs_extinction=None, kwargs_special=None, unconvolved=False, de_lensed=False, k=None, update_pixelbased_mapping=True): """ computes the source surface brightness distribution :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles :param kwargs_extinction: list of keyword arguments of extinction model :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing) :param de_lensed: if True: returns the un-lensed source surface brightness profile, otherwise the lensed. :param k: integer, if set, will only return the model of the specific index :return: 2d array of surface brightness pixels """ if len(self.SourceModel.profile_type_list) == 0: return np.zeros(self.Data.num_pixel_axes) if self._pixelbased_bool is True: return self._source_surface_brightness_pixelbased( kwargs_source, kwargs_lens=kwargs_lens, kwargs_extinction=kwargs_extinction, kwargs_special=kwargs_special, unconvolved=unconvolved, de_lensed=de_lensed, k=k, update_mapping=update_pixelbased_mapping) else: return self._source_surface_brightness_analytical( kwargs_source, kwargs_lens=kwargs_lens, kwargs_extinction=kwargs_extinction, kwargs_special=kwargs_special, unconvolved=unconvolved, de_lensed=de_lensed, k=k) def _source_surface_brightness_analytical(self, kwargs_source, kwargs_lens=None, kwargs_extinction=None, kwargs_special=None, unconvolved=False, de_lensed=False, k=None): """ computes the source surface brightness distribution :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles :param kwargs_extinction: list of keyword arguments of extinction model :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing) :param de_lensed: if True: returns the un-lensed source surface brightness profile, otherwise the lensed. :param k: integer, if set, will only return the model of the specific index :return: 2d array of surface brightness pixels """ ra_grid, dec_grid = self.ImageNumerics.coordinates_evaluate if de_lensed is True: source_light = self.SourceModel.surface_brightness(ra_grid, dec_grid, kwargs_source, k=k) else: source_light = self.source_mapping.image_flux_joint(ra_grid, dec_grid, kwargs_lens, kwargs_source, k=k) source_light *= self._extinction.extinction( ra_grid, dec_grid, kwargs_extinction=kwargs_extinction, kwargs_special=kwargs_special) source_light_final = self.ImageNumerics.re_size_convolve( source_light, unconvolved=unconvolved) return source_light_final def _source_surface_brightness_pixelbased(self, kwargs_source, kwargs_lens=None, kwargs_extinction=None, kwargs_special=None, unconvolved=False, de_lensed=False, k=None, update_mapping=True): """ computes the source surface brightness distribution, using pixel-based solver for light profiles (from SLITronomy) :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles :param kwargs_extinction: list of keyword arguments of extinction model :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing) :param de_lensed: if True: returns the un-lensed source surface brightness profile, otherwise the lensed. :param k: integer, if set, will only return the model of the specific index :param update_mapping: if False, prevent the pixelated lensing mapping to be updated (saves computation time if previously computed). :return: 2d array of surface brightness pixels """ ra_grid, dec_grid = self.SourceNumerics.coordinates_evaluate source_light = self.SourceModel.surface_brightness(ra_grid, dec_grid, kwargs_source, k=k) if de_lensed is True: source_light = self.SourceNumerics.re_size_convolve( source_light, unconvolved=unconvolved) else: source_mapping = self.PixelSolver.lensingOperator source_light = source_mapping.source2image( source_light, kwargs_lens=kwargs_lens, kwargs_special=kwargs_special, update_mapping=update_mapping, original_source_grid=True) source_light = self.ImageNumerics.re_size_convolve( source_light, unconvolved=unconvolved) # undo flux normalization performed by re_size_convolve (already handled in SLITronomy) source_light_final = source_light / self.Data.pixel_width**2 return source_light_final def lens_surface_brightness(self, kwargs_lens_light, unconvolved=False, k=None): """ computes the lens surface brightness distribution :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles :param unconvolved: if True, returns unconvolved surface brightness (perfect seeing), otherwise convolved with PSF kernel :return: 2d array of surface brightness pixels """ if self._pixelbased_bool is True: if unconvolved is True: raise ValueError( "Lens light pixel-based modelling does not perform deconvolution" ) return self._lens_surface_brightness_pixelbased(kwargs_lens_light, k=k) else: return self._lens_surface_brightness_analytical( kwargs_lens_light, unconvolved=unconvolved, k=k) def _lens_surface_brightness_analytical(self, kwargs_lens_light, unconvolved=False, k=None): """ computes the lens surface brightness distribution :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles :param unconvolved: if True, returns unconvolved surface brightness (perfect seeing), otherwise convolved with PSF kernel :return: 2d array of surface brightness pixels """ ra_grid, dec_grid = self.ImageNumerics.coordinates_evaluate lens_light = self.LensLightModel.surface_brightness(ra_grid, dec_grid, kwargs_lens_light, k=k) lens_light_final = self.ImageNumerics.re_size_convolve( lens_light, unconvolved=unconvolved) return lens_light_final def _lens_surface_brightness_pixelbased(self, kwargs_lens_light, k=None): """ computes the lens surface brightness distribution , using pixel-based solver for light profiles (from SLITronomy) Important: SLITronomy does not solve for deconvolved lens light, hence the returned map is convolved with the PSF. :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles :return: 2d array of surface brightness pixels """ ra_grid, dec_grid = self.ImageNumerics.coordinates_evaluate lens_light = self.LensLightModel.surface_brightness(ra_grid, dec_grid, kwargs_lens_light, k=k) lens_light_final = util.array2image(lens_light) return lens_light_final def point_source(self, kwargs_ps, kwargs_lens=None, kwargs_special=None, unconvolved=False, k=None): """ computes the point source positions and paints PSF convolutions on them :param kwargs_ps: :param k: :return: """ point_source_image = np.zeros((self.Data.num_pixel_axes)) if unconvolved or self.PointSource is None: return point_source_image ra_pos, dec_pos, amp = self.PointSource.point_source_list( kwargs_ps, kwargs_lens=kwargs_lens, k=k) ra_pos, dec_pos = self._displace_astrometry( ra_pos, dec_pos, kwargs_special=kwargs_special) point_source_image += self.ImageNumerics.point_source_rendering( ra_pos, dec_pos, amp) return point_source_image def image(self, kwargs_lens=None, kwargs_source=None, kwargs_lens_light=None, kwargs_ps=None, kwargs_extinction=None, kwargs_special=None, unconvolved=False, source_add=True, lens_light_add=True, point_source_add=True): """ make an image with a realisation of linear parameter values "param" :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles :param kwargs_ps: keyword arguments corresponding to "other" parameters, such as external shear and point source image positions :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing) :param source_add: if True, compute source, otherwise without :param lens_light_add: if True, compute lens light, otherwise without :param point_source_add: if True, add point sources, otherwise without :return: 2d array of surface brightness pixels of the simulation """ model = np.zeros((self.Data.num_pixel_axes)) if source_add is True: model += self.source_surface_brightness( kwargs_source, kwargs_lens, kwargs_extinction=kwargs_extinction, kwargs_special=kwargs_special, unconvolved=unconvolved) if lens_light_add is True: model += self.lens_surface_brightness(kwargs_lens_light, unconvolved=unconvolved) if point_source_add is True: model += self.point_source(kwargs_ps, kwargs_lens, kwargs_special=kwargs_special, unconvolved=unconvolved) return model def extinction_map(self, kwargs_extinction=None, kwargs_special=None): """ differential extinction per pixel :param kwargs_extinction: list of keyword arguments corresponding to the optical depth models tau, such that extinction is exp(-tau) :param kwargs_special: keyword arguments, additional parameter to the extinction :return: 2d array of size of the image """ ra_grid, dec_grid = self.ImageNumerics.coordinates_evaluate extinction = self._extinction.extinction( ra_grid, dec_grid, kwargs_extinction=kwargs_extinction, kwargs_special=kwargs_special) extinction_array = np.ones_like(ra_grid) * extinction extinction = self.ImageNumerics.re_size_convolve(extinction_array, unconvolved=True) return extinction def _displace_astrometry(self, x_pos, y_pos, kwargs_special=None): """ displaces point sources by shifts specified in kwargs_special :param x_pos: list of point source positions according to point source model list :param y_pos: list of point source positions according to point source model list :param kwargs_special: keyword arguments, can contain 'delta_x_image' and 'delta_y_image' The list is defined in order of the image positions :return: shifted image positions in same format as input """ if kwargs_special is not None: if 'delta_x_image' in kwargs_special: delta_x, delta_y = kwargs_special[ 'delta_x_image'], kwargs_special['delta_y_image'] delta_x_new = np.zeros(len(x_pos)) delta_x_new[0:len(delta_x)] = delta_x[:] delta_y_new = np.zeros(len(y_pos)) delta_y_new[0:len(delta_y)] = delta_y x_pos = x_pos + delta_x_new y_pos = y_pos + delta_y_new return x_pos, y_pos def _detect_pixelbased_models(self): """ Returns True if light profiles specific to pixel-based modelling are present in source model list. Otherwise returns False. Currently, pixel-based light profiles are: 'SLIT_STARLETS', 'SLIT_STARLETS_GEN2'. """ source_model_list = self.SourceModel.profile_type_list if 'SLIT_STARLETS' in source_model_list or 'SLIT_STARLETS_GEN2' in source_model_list: if len(source_model_list) > 1: raise ValueError( "'SLIT_STARLETS' or 'SLIT_STARLETS_GEN2' must be the only source model list for pixel-based modelling" ) return True return False def _setup_pixelbased_source_numerics(self, kwargs_numerics, kwargs_pixelbased): """ Check if model requirement are compatible with support pixel-based solver, and creates a new numerics class specifically for source plane. :param kwargs_numerics: keyword argument with various numeric description (see ImageNumerics class for options) :param kwargs_pixelbased: keyword argument with various settings related to the pixel-based solver (see SLITronomy documentation) """ # check that the required convolution type is compatible with pixel-based modelling (in current implementation) psf_type = self.PSF.psf_type supersampling_convolution = kwargs_numerics.get( 'supersampling_convolution', False) supersampling_factor = kwargs_numerics.get('supersampling_factor', 1) compute_mode = kwargs_numerics.get('compute_mode', 'regular') if psf_type not in ['PIXEL', 'NONE']: raise ValueError( "Only convolution using a pixelated kernel is supported for pixel-based modelling" ) if compute_mode != 'regular': raise ValueError( "Only regular coordinate grid is supported for pixel-based modelling" ) if (supersampling_convolution is True and supersampling_factor > 1): raise ValueError( "Only non-supersampled convolution is supported for pixel-based modelling" ) # setup the source numerics with a (possibily) different supersampling resolution supersampling_factor_source = kwargs_pixelbased.pop( 'supersampling_factor_source', 1) kwargs_numerics_source = kwargs_numerics.copy() kwargs_numerics_source[ 'supersampling_factor'] = supersampling_factor_source kwargs_numerics_source['compute_mode'] = 'regular' source_numerics_class = NumericsSubFrame(pixel_grid=self.Data, psf=self.PSF, **kwargs_numerics_source) return source_numerics_class
def __init__(self, data_class, psf_class, lens_model_class=None, source_model_class=None, lens_light_model_class=None, point_source_class=None, extinction_class=None, kwargs_numerics=None, kwargs_pixelbased=None): """ :param data_class: instance of ImageData() or PixelGrid() class :param psf_class: instance of PSF() class :param lens_model_class: instance of LensModel() class :param source_model_class: instance of LightModel() class describing the source parameters :param lens_light_model_class: instance of LightModel() class describing the lens light parameters :param point_source_class: instance of PointSource() class describing the point sources :param kwargs_numerics: keyword arguments with various numeric description (see ImageNumerics class for options) :param kwargs_pixelbased: keyword arguments with various settings related to the pixel-based solver (see SLITronomy documentation) """ self.type = 'single-band' self.num_bands = 1 self.PSF = psf_class self.Data = data_class self.PSF.set_pixel_size(self.Data.pixel_width) if kwargs_numerics is None: kwargs_numerics = {} self.ImageNumerics = NumericsSubFrame(pixel_grid=self.Data, psf=self.PSF, **kwargs_numerics) if lens_model_class is None: lens_model_class = LensModel(lens_model_list=[]) self.LensModel = lens_model_class if point_source_class is None: point_source_class = PointSource(point_source_type_list=[]) self.PointSource = point_source_class self.PointSource.update_lens_model(lens_model_class=lens_model_class) x_center, y_center = self.Data.center self.PointSource.update_search_window( search_window=np.max(self.Data.width), x_center=x_center, y_center=y_center, min_distance=self.Data.pixel_width, only_from_unspecified=True) self._psf_error_map = self.PSF.psf_error_map_bool if source_model_class is None: source_model_class = LightModel(light_model_list=[]) self.SourceModel = source_model_class if lens_light_model_class is None: lens_light_model_class = LightModel(light_model_list=[]) self.LensLightModel = lens_light_model_class self._kwargs_numerics = kwargs_numerics if extinction_class is None: extinction_class = DifferentialExtinction(optical_depth_model=[]) self._extinction = extinction_class if kwargs_pixelbased is None: kwargs_pixelbased = {} else: kwargs_pixelbased = kwargs_pixelbased.copy() self._pixelbased_bool = self._detect_pixelbased_models() if self._pixelbased_bool is True: from slitronomy.Util.class_util import create_solver_class # requirement on SLITronomy is exclusively here self.SourceNumerics = self._setup_pixelbased_source_numerics( kwargs_numerics, kwargs_pixelbased) self.PixelSolver = create_solver_class( self.Data, self.PSF, self.ImageNumerics, self.SourceNumerics, self.LensModel, self.SourceModel, self.LensLightModel, self.PointSource, self._extinction, kwargs_pixelbased) self.source_mapping = None # handled with pixelated operator else: self.source_mapping = Image2SourceMapping( lensModel=lens_model_class, sourceModel=source_model_class)
def test_raise(self): with self.assertRaises(ValueError): source_model_class = LightModel(['SERSIC']) # not supported lens_light_model_class = LightModel(['SLIT_STARLETS']) point_source_class = PointSource(point_source_type_list=[]) source_numerics_class = NumericsSubFrame(self.imageModel.Data, self.imageModel.PSF, supersampling_factor=2) solver_class = class_util.create_solver_class( self.imageModel.Data, self.imageModel.PSF, self.imageModel.ImageNumerics, source_numerics_class, self.imageModel.LensModel, source_model_class, lens_light_model_class, point_source_class, self.imageModel._extinction, self.kwargs_sparse_solver) with self.assertRaises(ValueError): source_model_class = LightModel(['SLIT_STARLETS']) lens_light_model_class = LightModel(['SERSIC']) # not supported point_source_class = PointSource(point_source_type_list=[]) source_numerics_class = NumericsSubFrame(self.imageModel.Data, self.imageModel.PSF, supersampling_factor=2) solver_class = class_util.create_solver_class( self.imageModel.Data, self.imageModel.PSF, self.imageModel.ImageNumerics, source_numerics_class, self.imageModel.LensModel, source_model_class, lens_light_model_class, point_source_class, self.imageModel._extinction, self.kwargs_sparse_solver) with self.assertRaises(ValueError): source_model_class = LightModel(['SLIT_STARLETS', 'SLIT_STARLETS']) # not supported lens_light_model_class = LightModel(['SLIT_STARLETS' ]) # not supported point_source_class = PointSource(point_source_type_list=[]) source_numerics_class = NumericsSubFrame(self.imageModel.Data, self.imageModel.PSF, supersampling_factor=2) solver_class = class_util.create_solver_class( self.imageModel.Data, self.imageModel.PSF, self.imageModel.ImageNumerics, source_numerics_class, self.imageModel.LensModel, source_model_class, lens_light_model_class, point_source_class, self.imageModel._extinction, self.kwargs_sparse_solver) with self.assertRaises(ValueError): source_model_class = LightModel(['SLIT_STARLETS']) lens_light_model_class = LightModel( ['SLIT_STARLETS', 'SLIT_STARLETS']) # not supported point_source_class = PointSource(point_source_type_list=[]) source_numerics_class = NumericsSubFrame(self.imageModel.Data, self.imageModel.PSF, supersampling_factor=2) solver_class = class_util.create_solver_class( self.imageModel.Data, self.imageModel.PSF, self.imageModel.ImageNumerics, source_numerics_class, self.imageModel.LensModel, source_model_class, lens_light_model_class, point_source_class, self.imageModel._extinction, self.kwargs_sparse_solver) with self.assertRaises(ValueError): source_model_class = LightModel([]) # not supported lens_light_model_class = LightModel(['SLIT_STARLETS']) point_source_class = PointSource(point_source_type_list=[]) source_numerics_class = NumericsSubFrame(self.imageModel.Data, self.imageModel.PSF, supersampling_factor=2) solver_class = class_util.create_solver_class( self.imageModel.Data, self.imageModel.PSF, self.imageModel.ImageNumerics, source_numerics_class, self.imageModel.LensModel, source_model_class, lens_light_model_class, point_source_class, self.imageModel._extinction, self.kwargs_sparse_solver) with self.assertRaises(NotImplementedError): # ask for source + point sources: no more supported temporarily source_model_class = LightModel(['SLIT_STARLETS']) lens_light_model_class = LightModel([]) point_source_class = PointSource( point_source_type_list=['SOURCE_POSITION']) source_numerics_class = NumericsSubFrame(self.imageModel.Data, self.imageModel.PSF, supersampling_factor=2) solver_class = class_util.create_solver_class( self.imageModel.Data, self.imageModel.PSF, self.imageModel.ImageNumerics, source_numerics_class, self.imageModel.LensModel, source_model_class, lens_light_model_class, point_source_class, self.imageModel._extinction, self.kwargs_sparse_solver) with self.assertRaises(NotImplementedError): # ask for source + lens light + point sources: not supported source_model_class = LightModel(['SLIT_STARLETS']) lens_light_model_class = LightModel(['SLIT_STARLETS']) point_source_class = PointSource( point_source_type_list=['SOURCE_POSITION']) source_numerics_class = NumericsSubFrame(self.imageModel.Data, self.imageModel.PSF, supersampling_factor=2) solver_class = class_util.create_solver_class( self.imageModel.Data, self.imageModel.PSF, self.imageModel.ImageNumerics, source_numerics_class, self.imageModel.LensModel, source_model_class, lens_light_model_class, point_source_class, self.imageModel._extinction, self.kwargs_sparse_solver)
def setup(self): self.num_pix = 49 # cutout pixel size self.subgrid_res_source = 2 self.num_pix_source = self.num_pix * self.subgrid_res_source self.background_rms = 0.05 self.noise_map = self.background_rms * np.ones( (self.num_pix, self.num_pix)) delta_pix = 0.24 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=self.num_pix, deltapix=delta_pix, subgrid_res=1, inverse=False, left_lower=False) self.image_data = np.random.rand(self.num_pix, self.num_pix) kwargs_data = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': self.image_data, 'background_rms': self.background_rms, 'noise_map': self.noise_map, } data = ImageData(**kwargs_data) gaussian_func = Gaussian() x, y = l_util.make_grid(41, 1) gaussian = gaussian_func.function(x, y, amp=1, sigma=0.02, center_x=0, center_y=0) self.psf_kernel = gaussian / gaussian.sum() lens_model = LensModel(['SPEP']) self.kwargs_lens = [{ 'theta_E': 1, 'gamma': 2, 'center_x': 0, 'center_y': 0, 'e1': -0.05, 'e2': 0.05 }] # wavelets scales for lens and source self.n_scales_source = 4 self.n_scales_lens = 3 # list of source light profiles self.source_model = LightModel(['SLIT_STARLETS']) self.kwargs_source = [{'n_scales': self.n_scales_source}] # list of lens light profiles self.lens_light_model = LightModel(['SLIT_STARLETS']) self.kwargs_lens_light = [{'n_scales': self.n_scales_lens}] # get grid classes image_grid_class = NumericsSubFrame(data, PSF('NONE')).grid_class source_grid_class = NumericsSubFrame( data, PSF('NONE'), supersampling_factor=self.subgrid_res_source).grid_class # get a lensing operator self.lensing_op = LensingOperator(lens_model, image_grid_class, source_grid_class, self.num_pix) self.noise_class = NoiseLevels( data, subgrid_res_source=self.subgrid_res_source, include_regridding_error=False) self.noise_class_regrid = NoiseLevels( data, subgrid_res_source=self.subgrid_res_source, include_regridding_error=True)
def test_supersampling_simple(): """ :return: """ from lenstronomy.Data.psf import PSF from lenstronomy.SimulationAPI.data_api import DataAPI detector_pixel_scale = 0.04 numpix = 64 supersampling_factor = 2 # generate a Gaussian image x, y = util.make_grid(numPix=numpix * supersampling_factor, deltapix=detector_pixel_scale / supersampling_factor) from lenstronomy.LightModel.Profiles.gaussian import Gaussian gaussian = Gaussian() image_1d = gaussian.function(x, y, amp=1, sigma=0.1) image = util.array2image(image_1d) # generate psf kernal supersampled kernel_super = kernel_util.kernel_gaussian( kernel_numPix=21 * supersampling_factor + 1, deltaPix=detector_pixel_scale / supersampling_factor, fwhm=0.2) psf_parameters = { 'psf_type': 'PIXEL', 'kernel_point_source': kernel_super, 'point_source_supersampling_factor': supersampling_factor } kwargs_detector = { 'pixel_scale': detector_pixel_scale, 'ccd_gain': 2.5, 'read_noise': 4.0, 'magnitude_zero_point': 25.0, 'exposure_time': 5400.0, 'sky_brightness': 22, 'num_exposures': 1, 'background_noise': None } kwargs_numerics = { 'supersampling_factor': 2, 'supersampling_convolution': True, 'point_source_supersampling_factor': 2, 'supersampling_kernel_size': 21 } psf_model = PSF(**psf_parameters) data_class = DataAPI(numpix=numpix, **kwargs_detector).data_class from lenstronomy.ImSim.Numerics.numerics_subframe import NumericsSubFrame image_numerics = NumericsSubFrame(pixel_grid=data_class, psf=psf_model, **kwargs_numerics) conv_class = image_numerics.convolution_class conv_flat = conv_class.convolution2d(image) print(np.shape(conv_flat), 'shape of output') # psf_helper = lenstronomy_utils.PSFHelper(data_class, psf_model, kwargs_numerics) # Convolve with lenstronomy and with scipy # helper_image = psf_helper.psf_model(image) from scipy import signal scipy_image = signal.fftconvolve(image, kernel_super, mode='same') from lenstronomy.Util import image_util image_scipy_resized = image_util.re_size(scipy_image, supersampling_factor) image_unconvolved = image_util.re_size(image, supersampling_factor) # Compare the outputs # low res convolution as comparison kwargs_numerics_low_res = { 'supersampling_factor': 2, 'supersampling_convolution': False, 'point_source_supersampling_factor': 2, } image_numerics_low_res = NumericsSubFrame(pixel_grid=data_class, psf=psf_model, **kwargs_numerics_low_res) conv_class_low_res = image_numerics_low_res.convolution_class conv_flat_low_res = conv_class_low_res.convolution2d(image_unconvolved) #import matplotlib.pyplot as plt #plt.matshow(image_scipy_resized - image_unconvolved) #plt.colorbar() #plt.show() #plt.matshow(image_scipy_resized - conv_flat) #plt.colorbar() #plt.show() #plt.matshow(image_scipy_resized - conv_flat_low_res) #plt.colorbar() #plt.show() np.testing.assert_almost_equal(conv_flat, image_scipy_resized)
def setup(self): self.num_pix = 20 # cutout pixel size delta_pix = 0.2 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=self.num_pix, deltapix=delta_pix, subgrid_res=1, inverse=False, left_lower=False) # imaging data class gaussian = Gaussian() x, y = l_util.make_grid(self.num_pix, 1) gaussian1 = gaussian.function(x, y, amp=5, sigma=1, center_x=-7, center_y=-7) gaussian2 = gaussian.function(x, y, amp=20, sigma=2, center_x=-3, center_y=-3) gaussian3 = gaussian.function(x, y, amp=60, sigma=4, center_x=+5, center_y=+5) image_data = util.array2image(gaussian1 + gaussian2 + gaussian3) background_rms = 0.1 image_data += background_rms * np.random.randn(self.num_pix, self.num_pix) kwargs_data = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': image_data, 'background_rms': background_rms, 'noise_map': background_rms * np.ones_like(image_data), } data_class = ImageData(**kwargs_data) # lens mass class lens_model_class = LensModel(['SPEP']) self.kwargs_lens = [{ 'theta_E': 1, 'gamma': 2, 'center_x': 0, 'center_y': 0, 'e1': -0.05, 'e2': 0.05 }] # source light class source_model_class = LightModel(['SLIT_STARLETS']) self.kwargs_source = [{ 'coeffs': 0, 'n_scales': 3, 'n_pixels': self.num_pix**2 }] # define numerics classes image_numerics_class = NumericsSubFrame(pixel_grid=data_class, psf=PSF(psf_type='NONE')) source_numerics_class = NumericsSubFrame(pixel_grid=data_class, psf=PSF(psf_type='NONE'), supersampling_factor=1) # init sparse solver self.solver = SparseSolverSource(data_class, lens_model_class, image_numerics_class, source_numerics_class, source_model_class, num_iter_source=10) # init the plotter self.plotter = SolverPlotter(self.solver, show_now=False)
class ImageModel(object): """ this class uses functions of lens_model and source_model to make a lensed image """ def __init__(self, data_class, psf_class, lens_model_class=None, source_model_class=None, lens_light_model_class=None, point_source_class=None, extinction_class=None, kwargs_numerics={}): """ :param data_class: instance of ImageData() or PixelGrid() class :param psf_class: instance of PSF() class :param lens_model_class: instance of LensModel() class :param source_model_class: instance of LightModel() class describing the source parameters :param lens_light_model_class: instance of LightModel() class describing the lens light parameters :param point_source_class: instance of PointSource() class describing the point sources :param kwargs_numerics: keyword argument with various numeric description (see ImageNumerics class for options) """ self.type = 'single-band' self.PSF = psf_class self.Data = data_class self.PSF.set_pixel_size(self.Data.pixel_width) self.ImageNumerics = NumericsSubFrame(pixel_grid=self.Data, psf=self.PSF, **kwargs_numerics) if lens_model_class is None: lens_model_class = LensModel(lens_model_list=[]) self.LensModel = lens_model_class if point_source_class is None: point_source_class = PointSource(point_source_type_list=[]) self.PointSource = point_source_class self.PointSource.update_lens_model(lens_model_class=lens_model_class) x_center, y_center = self.Data.center self.PointSource.update_search_window( search_window=np.max(self.Data.width), x_center=x_center, y_center=y_center, min_distance=self.Data.pixel_width) self._psf_error_map = self.PSF.psf_error_map_bool if source_model_class is None: source_model_class = LightModel(light_model_list=[]) self.SourceModel = source_model_class if lens_light_model_class is None: lens_light_model_class = LightModel(light_model_list=[]) self.LensLightModel = lens_light_model_class self.source_mapping = Image2SourceMapping( lensModel=lens_model_class, sourceModel=source_model_class) self.num_bands = 1 self._kwargs_numerics = kwargs_numerics if extinction_class is None: extinction_class = DifferentialExtinction(optical_depth_model=[]) self._extinction = extinction_class def reset_point_source_cache(self, bool=True): """ deletes all the cache in the point source class and saves it from then on :param bool: boolean, if True, saves the next occuring point source positions in the cache :return: None """ self.PointSource.delete_lens_model_cache() self.PointSource.set_save_cache(bool) def update_psf(self, psf_class): """ update the instance of the class with a new instance of PSF() with a potentially different point spread function :param psf_class: :return: no return. Class is updated. """ self.PSF = psf_class self.PSF.set_pixel_size(self.Data.pixel_width) self.ImageNumerics = NumericsSubFrame(pixel_grid=self.Data, psf=self.PSF, **self._kwargs_numerics) def source_surface_brightness(self, kwargs_source, kwargs_lens=None, kwargs_extinction=None, kwargs_special=None, unconvolved=False, de_lensed=False, k=None): """ computes the source surface brightness distribution :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles :param kwargs_extinction: list of keyword arguments of extinction model :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing) :param de_lensed: if True: returns the un-lensed source surface brightness profile, otherwise the lensed. :param k: integer, if set, will only return the model of the specific index :return: 1d array of surface brightness pixels """ if len(self.SourceModel.profile_type_list) == 0: return np.zeros((self.Data.num_pixel_axes)) ra_grid, dec_grid = self.ImageNumerics.coordinates_evaluate if de_lensed is True: source_light = self.SourceModel.surface_brightness(ra_grid, dec_grid, kwargs_source, k=k) else: source_light = self.source_mapping.image_flux_joint(ra_grid, dec_grid, kwargs_lens, kwargs_source, k=k) source_light *= self._extinction.extinction( ra_grid, dec_grid, kwargs_extinction=kwargs_extinction, kwargs_special=kwargs_special) source_light_final = self.ImageNumerics.re_size_convolve( source_light, unconvolved=unconvolved) return source_light_final def lens_surface_brightness(self, kwargs_lens_light, unconvolved=False, k=None): """ computes the lens surface brightness distribution :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles :param unconvolved: if True, returns unconvolved surface brightness (perfect seeing), otherwise convolved with PSF kernel :return: 1d array of surface brightness pixels """ ra_grid, dec_grid = self.ImageNumerics.coordinates_evaluate lens_light = self.LensLightModel.surface_brightness(ra_grid, dec_grid, kwargs_lens_light, k=k) lens_light_final = self.ImageNumerics.re_size_convolve( lens_light, unconvolved=unconvolved) return lens_light_final def point_source(self, kwargs_ps, kwargs_lens=None, kwargs_special=None, unconvolved=False, k=None): """ computes the point source positions and paints PSF convolutions on them :param kwargs_ps: :param k: :return: """ point_source_image = np.zeros((self.Data.num_pixel_axes)) if unconvolved or self.PointSource is None: return point_source_image ra_pos, dec_pos, amp, n_points = self.PointSource.linear_response_set( kwargs_ps, kwargs_lens, with_amp=True, k=k) for i in range(n_points): point_source_image += self.ImageNumerics.point_source_rendering( ra_pos[i], dec_pos[i], amp[i]) return point_source_image def image(self, kwargs_lens=None, kwargs_source=None, kwargs_lens_light=None, kwargs_ps=None, kwargs_extinction=None, kwargs_special=None, unconvolved=False, source_add=True, lens_light_add=True, point_source_add=True): """ make an image with a realisation of linear parameter values "param" :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles :param kwargs_ps: keyword arguments corresponding to "other" parameters, such as external shear and point source image positions :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing) :param source_add: if True, compute source, otherwise without :param lens_light_add: if True, compute lens light, otherwise without :param point_source_add: if True, add point sources, otherwise without :return: 1d array of surface brightness pixels of the simulation """ model = np.zeros((self.Data.num_pixel_axes)) if source_add is True: model += self.source_surface_brightness( kwargs_source, kwargs_lens, kwargs_extinction=kwargs_extinction, kwargs_special=kwargs_special, unconvolved=unconvolved) if lens_light_add is True: model += self.lens_surface_brightness(kwargs_lens_light, unconvolved=unconvolved) if point_source_add is True: model += self.point_source(kwargs_ps, kwargs_lens, kwargs_special=kwargs_special, unconvolved=unconvolved) return model def extinction_map(self, kwargs_extinction=None, kwargs_special=None): """ differential extinction per pixel :param kwargs_extinction: list of keyword arguments corresponding to the optical depth models tau, such that extinction is exp(-tau) :param kwargs_special: keyword arguments, additional parameter to the extinction :return: 2d array of size of the image """ ra_grid, dec_grid = self.ImageNumerics.coordinates_evaluate extinction = self._extinction.extinction( ra_grid, dec_grid, kwargs_extinction=kwargs_extinction, kwargs_special=kwargs_special) extinction_array = np.ones_like(ra_grid) * extinction extinction = self.ImageNumerics.re_size_convolve(extinction_array, unconvolved=True) return extinction
def setup(self): self.num_pix = 49 # cutout pixel size self.subgrid_res_source = 2 self.num_pix_source = self.num_pix * self.subgrid_res_source delta_pix = 0.24 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=self.num_pix, deltapix=delta_pix, subgrid_res=1, inverse=False, left_lower=False) self.image_data = np.random.rand(self.num_pix, self.num_pix) kwargs_data = { 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': self.image_data, } data = ImageData(**kwargs_data) lens_model = LensModel(['SPEP']) kwargs_lens = [{ 'theta_E': 1, 'gamma': 2, 'center_x': 0, 'center_y': 0, 'e1': -0.05, 'e2': 0.05 }] # PSF kernel_pixel = np.zeros((self.num_pix, self.num_pix)) kernel_pixel[int(self.num_pix / 2), int(self.num_pix / 2)] = 1 # just a dirac here kwargs_psf = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_pixel} psf = PSF(**kwargs_psf) # wavelets scales for lens and source self.n_scales_source = 4 self.n_scales_lens = 3 # list of source light profiles source_model = LightModel(['SLIT_STARLETS']) self.kwargs_source = [{'n_scales': self.n_scales_source}] # list of lens light profiles lens_light_model = LightModel(['SLIT_STARLETS']) self.kwargs_lens_light = [{'n_scales': self.n_scales_lens}] # define some mask likelihood_mask = np.ones((self.num_pix, self.num_pix)) # get grid classes self.numerics = NumericsSubFrame(data, psf) image_grid_class = self.numerics.grid_class source_numerics = NumericsSubFrame( data, psf, supersampling_factor=self.subgrid_res_source) source_grid_class = source_numerics.grid_class # get a lensing operator self.lensing_op = LensingOperator(lens_model, image_grid_class, source_grid_class, self.num_pix) self.lensing_op.update_mapping(kwargs_lens) self.model_op = ModelOperators(data, self.lensing_op, self.numerics) self.model_op._set_likelihood_mask(likelihood_mask) self.model_op.add_source_light(source_model) self.model_op.add_lens_light(lens_light_model) self.model_op_nolens = ModelOperators(data, self.lensing_op, self.numerics) self.model_op_nolens._set_likelihood_mask(likelihood_mask) self.model_op_nolens.add_source_light(source_model) # define some test images in direct space self.X_s = np.random.rand(self.num_pix_source, self.num_pix_source) # source light self.X_l = np.random.rand(self.num_pix, self.num_pix) # lens light # define some test images in wavelets space self.alpha_s = np.random.rand(self.n_scales_source, self.num_pix_source, self.num_pix_source) # source light self.alpha_l = np.random.rand(self.n_scales_lens, self.num_pix, self.num_pix) # lens light
def setup(self): self.num_pix = 25 # cutout pixel size delta_pix = 0.24 _, _, ra_at_xy_0, dec_at_xy_0, _, _, Mpix2coord, _ \ = l_util.make_grid_with_coordtransform(numPix=self.num_pix, deltapix=delta_pix, subgrid_res=1, inverse=False, left_lower=False) kwargs_data = { #'background_rms': background_rms, #'exposure_time': np.ones((self.num_pix, self.num_pix)) * exp_time, # individual exposure time/weight per pixel 'ra_at_xy_0': ra_at_xy_0, 'dec_at_xy_0': dec_at_xy_0, 'transform_pix2angle': Mpix2coord, 'image_data': np.zeros((self.num_pix, self.num_pix)) } self.data = ImageData(**kwargs_data) self.lens_model = LensModel(['SPEP']) self.kwargs_lens = [{ 'theta_E': 1, 'gamma': 2, 'center_x': 0, 'center_y': 0, 'e1': -0.05, 'e2': 0.05 }] self.kwargs_lens_null = [{ 'theta_E': 0, 'gamma': 2, 'center_x': 0, 'center_y': 0, 'e1': 0, 'e2': 0 }] # PSF specification kwargs_psf = {'psf_type': 'NONE'} self.psf = PSF(**kwargs_psf) # list of source light profiles source_model_list = ['SERSIC_ELLIPSE'] kwargs_sersic_ellipse_source = { 'amp': 2000, 'R_sersic': 0.6, 'n_sersic': 1, 'e1': 0.1, 'e2': 0.1, 'center_x': 0.3, 'center_y': 0.3 } kwargs_source = [kwargs_sersic_ellipse_source] source_model = LightModel(light_model_list=source_model_list) # list of lens light profiles lens_light_model_list = [] kwargs_lens_light = [{}] lens_light_model = LightModel(light_model_list=lens_light_model_list) kwargs_numerics = { 'supersampling_factor': 1, 'supersampling_convolution': False } self.image_model = ImageModel(self.data, self.psf, self.lens_model, source_model, lens_light_model, point_source_class=None, kwargs_numerics=kwargs_numerics) self.image_grid_class = self.image_model.ImageNumerics.grid_class self.source_grid_class_default = NumericsSubFrame(self.data, self.psf).grid_class # create simulated image image_sim_no_noise = self.image_model.image(self.kwargs_lens, kwargs_source, kwargs_lens_light) self.source_light_lensed = image_sim_no_noise self.data.update_data(image_sim_no_noise) # source only, in source plane, on same grid as data self.source_light_delensed = self.image_model.source_surface_brightness( kwargs_source, unconvolved=False, de_lensed=True) # define some auto mask for tests self.likelihood_mask = np.zeros_like(self.source_light_lensed) self.likelihood_mask[self.source_light_lensed > 0.1 * self.source_light_lensed.max()] = 1