class TestLightModel(object): """ tests the source model routines """ def setup(self): self.light_model_list = ['GAUSSIAN', 'MULTI_GAUSSIAN', 'SERSIC', 'SERSIC_ELLIPSE', 'DOUBLE_SERSIC', 'CORE_SERSIC', 'DOUBLE_CORE_SERSIC', 'BULDGE_DISK', 'SHAPELETS', 'HERNQUIST', 'HERNQUIST_ELLIPSE', 'PJAFFE', 'PJAFFE_ELLIPSE', 'UNIFORM', 'NONE' ] self.kwargs = [ {'amp': 1., 'sigma_x': 1, 'sigma_y': 1., 'center_x': 0, 'center_y': 0}, # 'GAUSSIAN' {'amp': [1., 2], 'sigma': [1, 3], 'center_x': 0, 'center_y': 0}, # 'MULTI_GAUSSIAN' {'I0_sersic': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'center_x': 0, 'center_y': 0}, # 'SERSIC' {'I0_sersic': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'q': 0.8, 'phi_G': 0.5, 'center_x': 0, 'center_y': 0}, # 'SERSIC_ELLIPSE' {'I0_sersic': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'q': 0.8, 'phi_G': 0.5, 'center_x': 0, 'center_y': 0, 'I0_2': 1, 'R_2': 0.05, 'n_2': 2, 'phi_G_2': 0, 'q_2': 1}, # 'DOUBLE_SERSIC' {'I0_sersic': 1, 'R_sersic': 0.5, 'Re': 0.1, 'gamma': 2., 'n_sersic': 1, 'q': 0.8, 'phi_G': 0.5, 'center_x': 0, 'center_y': 0}, # 'CORE_SERSIC' {'I0_sersic': 1, 'R_sersic': 0.5, 'Re': 0.1, 'gamma': 2., 'n_sersic': 1, 'q': 0.8, 'phi_G': 0.5, 'center_x': 0, 'center_y': 0, 'I0_2': 1, 'R_2': 0.05, 'n_2': 2, 'phi_G_2': 0, 'q_2': 1}, # 'DOUBLE_CORE_SERSIC' {'I0_b': 1, 'R_b': 0.1, 'phi_G_b': 0, 'q_b': 1, 'I0_d': 2, 'R_d': 1, 'phi_G_d': 0.5, 'q_d': 0.7, 'center_x': 0, 'center_y': 0}, # BULDGE_DISK {'amp': [1, 1, 1], 'beta': 0.5, 'n_max': 1, 'center_x': 0, 'center_y': 0}, # 'SHAPELETS' {'sigma0': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0}, # 'HERNQUIST' {'sigma0': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'q': 0.8, 'phi_G': 0}, # 'HERNQUIST_ELLIPSE' {'sigma0': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0}, # 'PJAFFE' {'sigma0': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'q': 0.8, 'phi_G': 0}, # 'PJAFFE_ELLIPSE' {'mean': 1}, # 'UNIFORM' {}]# 'NONE' self.LightModel = LightModel(light_model_list=self.light_model_list) def test_init(self): model_list = ['CORE_SERSIC', 'DOUBLE_CORE_SERSIC', 'BULDGE_DISK', 'SHAPELETS', 'UNIFORM'] lightModel = LightModel(light_model_list=model_list) assert len(lightModel.profile_type_list) == len(model_list) def test_surface_brightness(self): output = self.LightModel.surface_brightness(x=1, y=1, kwargs_list=self.kwargs) npt.assert_almost_equal(output, 2.544428612985992, decimal=6) def test_surface_brightness_array(self): output = self.LightModel.surface_brightness(x=[1], y=[1], kwargs_list=self.kwargs) npt.assert_almost_equal(output[0], 2.544428612985992, decimal=6) def test_functions_split(self): output = self.LightModel.functions_split(x=1., y=1., kwargs_list=self.kwargs) assert output[0][0] == 0.058549831524319168 def test_re_normalize_flux(self): kwargs_out = self.LightModel.re_normalize_flux(kwargs_list=self.kwargs, norm_factor=2) assert kwargs_out[0]['amp'] == 2 * self.kwargs[0]['amp']
def test_raise(self): with self.assertRaises(ValueError): lighModel = LightModel(light_model_list=['WRONG']) with self.assertRaises(ValueError): lighModel = LightModel(light_model_list=['UNIFORM']) lighModel.light_3d(r=1, kwargs_list=[{'amp': 1}]) with self.assertRaises(ValueError): lighModel = LightModel(light_model_list=['UNIFORM']) lighModel.profile_type_list = ['WRONG'] lighModel.functions_split(x=0, y=0, kwargs_list=[{}]) with self.assertRaises(ValueError): lighModel = LightModel(light_model_list=['UNIFORM']) lighModel.profile_type_list = ['WRONG'] lighModel.num_param_linear(kwargs_list=[{}]) with self.assertRaises(ValueError): lighModel = LightModel(light_model_list=['UNIFORM']) lighModel.profile_type_list = ['WRONG'] lighModel.update_linear(param=[1], i=0, kwargs_list=[{}]) with self.assertRaises(ValueError): lighModel = LightModel(light_model_list=['UNIFORM']) lighModel.profile_type_list = ['WRONG'] lighModel.total_flux(kwargs_list=[{}])
class TestLightModel(object): """ tests the source model routines """ def setup(self): self.light_model_list = [ 'GAUSSIAN', 'MULTI_GAUSSIAN', 'SERSIC', 'SERSIC_ELLIPSE', 'CORE_SERSIC', 'SHAPELETS', 'HERNQUIST', 'HERNQUIST_ELLIPSE', 'PJAFFE', 'PJAFFE_ELLIPSE', 'UNIFORM', 'POWER_LAW', 'NIE', 'INTERPOL', 'SHAPELETS_POLAR_EXP', 'ELLIPSOID' ] phi_G, q = 0.5, 0.8 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) self.kwargs = [ { 'amp': 1., 'sigma': 1., 'center_x': 0, 'center_y': 0 }, # 'GAUSSIAN' { 'amp': [1., 2], 'sigma': [1, 3], 'center_x': 0, 'center_y': 0 }, # 'MULTI_GAUSSIAN' { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'center_x': 0, 'center_y': 0 }, # 'SERSIC' { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'e1': e1, 'e2': e2, 'center_x': 0, 'center_y': 0 }, # 'SERSIC_ELLIPSE' { 'amp': 1, 'R_sersic': 0.5, 'Rb': 0.1, 'gamma': 2., 'n_sersic': 1, 'e1': e1, 'e2': e2, 'center_x': 0, 'center_y': 0 }, # 'CORE_SERSIC' { 'amp': [1, 1, 1], 'beta': 0.5, 'n_max': 1, 'center_x': 0, 'center_y': 0 }, # 'SHAPELETS' { 'amp': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0 }, # 'HERNQUIST' { 'amp': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'e1': e1, 'e2': e2 }, # 'HERNQUIST_ELLIPSE' { 'amp': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0 }, # 'PJAFFE' { 'amp': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'e1': e1, 'e2': e2 }, # 'PJAFFE_ELLIPSE' { 'amp': 1 }, # 'UNIFORM' { 'amp': 1., 'gamma': 2., 'e1': e1, 'e2': e2, 'center_x': 0, 'center_y': 0 }, # 'POWER_LAW' { 'amp': .001, 'e1': 0, 'e2': 1., 'center_x': 0, 'center_y': 0, 's_scale': 1. }, # 'NIE' { 'image': np.zeros((20, 5)), 'scale': 1, 'phi_G': 0, 'center_x': 0, 'center_y': 0 }, { 'amp': [1], 'n_max': 0, 'beta': 1, 'center_x': 0, 'center_y': 0 }, { 'amp': 1, 'radius': 1., 'e1': 0, 'e2': 0.1, 'center_x': 0, 'center_y': 0 } # 'ELLIPSOID' ] self.LightModel = LightModel(light_model_list=self.light_model_list) def test_init(self): model_list = [ 'CORE_SERSIC', 'SHAPELETS', 'SHAPELETS_POLAR', 'SHAPELETS_POLAR_EXP', 'UNIFORM', 'CHAMELEON', 'DOUBLE_CHAMELEON', 'TRIPLE_CHAMELEON' ] lightModel = LightModel(light_model_list=model_list) assert len(lightModel.profile_type_list) == len(model_list) def test_surface_brightness(self): output = self.LightModel.surface_brightness(x=1., y=1., kwargs_list=self.kwargs) npt.assert_almost_equal(output, 2.5886852663397137, decimal=6) def test_surface_brightness_array(self): output = self.LightModel.surface_brightness(x=[1], y=[1], kwargs_list=self.kwargs) npt.assert_almost_equal(output[0], 2.5886852663397137, decimal=6) def test_functions_split(self): output = self.LightModel.functions_split(x=1., y=1., kwargs_list=self.kwargs) npt.assert_almost_equal(output[0][0], 0.058549831524319168, decimal=6) def test_param_name_list(self): param_name_list = self.LightModel.param_name_list assert len(self.light_model_list) == len(param_name_list) def test_num_param_linear(self): num = self.LightModel.num_param_linear(self.kwargs, list_return=False) assert num == 19 num_list = self.LightModel.num_param_linear(self.kwargs, list_return=True) assert num_list[0] == 1 def test_update_linear(self): response, n = self.LightModel.functions_split(1, 1, self.kwargs) param = np.ones(n) * 2 kwargs_out, i = self.LightModel.update_linear(param, i=0, kwargs_list=self.kwargs) assert i == n assert kwargs_out[0]['amp'] == 2 def test_total_flux(self): light_model_list = [ 'SERSIC', 'SERSIC_ELLIPSE', 'INTERPOL', 'GAUSSIAN', 'GAUSSIAN_ELLIPSE', 'MULTI_GAUSSIAN', 'MULTI_GAUSSIAN_ELLIPSE' ] kwargs_list = [ { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'center_x': 0, 'center_y': 0 }, # 'SERSIC' { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'e1': 0.1, 'e2': 0, 'center_x': 0, 'center_y': 0 }, # 'SERSIC_ELLIPSE' { 'image': np.ones((20, 5)), 'scale': 1, 'phi_G': 0, 'center_x': 0, 'center_y': 0 }, # 'INTERPOL' { 'amp': 2, 'sigma': 2, 'center_x': 0, 'center_y': 0 }, # 'GAUSSIAN' { 'amp': 2, 'sigma': 2, 'e1': 0.1, 'e2': 0, 'center_x': 0, 'center_y': 0 }, # 'GAUSSIAN_ELLIPSE' { 'amp': [1, 1], 'sigma': [2, 1], 'center_x': 0, 'center_y': 0 }, # 'MULTI_GAUSSIAN' { 'amp': [1, 1], 'sigma': [2, 1], 'e1': 0.1, 'e2': 0, 'center_x': 0, 'center_y': 0 } # 'MULTI_GAUSSIAN_ELLIPSE' ] lightModel = LightModel(light_model_list=light_model_list) total_flux_list = lightModel.total_flux(kwargs_list) assert total_flux_list[2] == 100 assert total_flux_list[3] == 2 assert total_flux_list[4] == 2 assert total_flux_list[5] == 2 assert total_flux_list[6] == 2 total_flux_list = lightModel.total_flux(kwargs_list, norm=True) assert total_flux_list[2] == 100 assert total_flux_list[3] == 1 assert total_flux_list[4] == 1 assert total_flux_list[5] == 2 assert total_flux_list[6] == 2 def test_delete_interpol_caches(self): x, y = util.make_grid(numPix=20, deltapix=1.) gauss = Gaussian() flux = gauss.function(x, y, amp=1., center_x=0., center_y=0., sigma=1.) image = util.array2image(flux) light_model_list = ['INTERPOL', 'INTERPOL'] kwargs_list = [{ 'image': image, 'scale': 1, 'phi_G': 0, 'center_x': 0, 'center_y': 0 }, { 'image': image, 'scale': 1, 'phi_G': 0, 'center_x': 0, 'center_y': 0 }] lightModel = LightModel(light_model_list=light_model_list) output = lightModel.surface_brightness(x, y, kwargs_list) for func in lightModel.func_list: assert hasattr(func, '_image_interp') lightModel.delete_interpol_caches() for func in lightModel.func_list: assert not hasattr(func, '_image_interp') def test_check_positive_flux_profile(self): ligthModel = LightModel(light_model_list=['GAUSSIAN']) kwargs_list = [{'amp': 0, 'sigma': 1}] bool = ligthModel.check_positive_flux_profile(kwargs_list) assert bool kwargs_list = [{'amp': -1, 'sigma': 1}] bool = ligthModel.check_positive_flux_profile(kwargs_list) assert not bool
class TestLightModel(object): """ tests the source model routines """ def setup(self): self.light_model_list = [ 'GAUSSIAN', 'MULTI_GAUSSIAN', 'SERSIC', 'SERSIC_ELLIPSE', 'CORE_SERSIC', 'SHAPELETS', 'HERNQUIST', 'HERNQUIST_ELLIPSE', 'PJAFFE', 'PJAFFE_ELLIPSE', 'UNIFORM', 'POWER_LAW', 'NIE', 'INTERPOL', 'SHAPELETS_POLAR_EXP' ] phi_G, q = 0.5, 0.8 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) self.kwargs = [ { 'amp': 1., 'sigma_x': 1, 'sigma_y': 1., 'center_x': 0, 'center_y': 0 }, # 'GAUSSIAN' { 'amp': [1., 2], 'sigma': [1, 3], 'center_x': 0, 'center_y': 0 }, # 'MULTI_GAUSSIAN' { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'center_x': 0, 'center_y': 0 }, # 'SERSIC' { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'e1': e1, 'e2': e2, 'center_x': 0, 'center_y': 0 }, # 'SERSIC_ELLIPSE' { 'amp': 1, 'R_sersic': 0.5, 'Re': 0.1, 'gamma': 2., 'n_sersic': 1, 'e1': e1, 'e2': e2, 'center_x': 0, 'center_y': 0 }, # 'CORE_SERSIC' { 'amp': [1, 1, 1], 'beta': 0.5, 'n_max': 1, 'center_x': 0, 'center_y': 0 }, # 'SHAPELETS' { 'amp': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0 }, # 'HERNQUIST' { 'amp': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'e1': e1, 'e2': e2 }, # 'HERNQUIST_ELLIPSE' { 'amp': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0 }, # 'PJAFFE' { 'amp': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'e1': e1, 'e2': e2 }, # 'PJAFFE_ELLIPSE' { 'amp': 1 }, # 'UNIFORM' { 'amp': 1., 'gamma': 2., 'e1': e1, 'e2': e2, 'center_x': 0, 'center_y': 0 }, # 'POWER_LAW' { 'amp': .001, 'e1': 0, 'e2': 1., 'center_x': 0, 'center_y': 0, 's_scale': 1. }, # 'NIE' { 'image': np.zeros((10, 10)), 'scale': 1, 'phi_G': 0, 'center_x': 0, 'center_y': 0 }, { 'amp': [1], 'n_max': 0, 'beta': 1, 'center_x': 0, 'center_y': 0 } ] self.LightModel = LightModel(light_model_list=self.light_model_list) def test_init(self): model_list = [ 'CORE_SERSIC', 'SHAPELETS', 'SHAPELETS_POLAR', 'SHAPELETS_POLAR_EXP', 'UNIFORM', 'CHAMELEON', 'DOUBLE_CHAMELEON', 'TRIPLE_CHAMELEON' ] lightModel = LightModel(light_model_list=model_list) assert len(lightModel.profile_type_list) == len(model_list) def test_surface_brightness(self): output = self.LightModel.surface_brightness(x=1, y=1, kwargs_list=self.kwargs) npt.assert_almost_equal(output, 3.7065728131855824, decimal=6) def test_surface_brightness_array(self): output = self.LightModel.surface_brightness(x=[1], y=[1], kwargs_list=self.kwargs) npt.assert_almost_equal(output[0], 3.7065728131855824, decimal=6) def test_functions_split(self): output = self.LightModel.functions_split(x=1., y=1., kwargs_list=self.kwargs) npt.assert_almost_equal(output[0][0], 0.058549831524319168, decimal=6) def test_re_normalize_flux(self): kwargs_out = self.LightModel.re_normalize_flux(kwargs_list=self.kwargs, norm_factor=2) assert kwargs_out[0]['amp'] == 2 * self.kwargs[0]['amp'] def test_param_name_list(self): param_name_list = self.LightModel.param_name_list() assert len(self.light_model_list) == len(param_name_list) def test_num_param_linear(self): num = self.LightModel.num_param_linear(self.kwargs, list_return=False) assert num == 18 num_list = self.LightModel.num_param_linear(self.kwargs, list_return=True) assert num_list[0] == 1 def test_update_linear(self): response, n = self.LightModel.functions_split(1, 1, self.kwargs) param = np.ones(n) * 2 kwargs_out, i = self.LightModel.update_linear(param, i=0, kwargs_list=self.kwargs) assert i == n assert kwargs_out[0]['amp'] == 2 def test_total_flux(self): light_model_list = [ 'SERSIC', 'SERSIC_ELLIPSE', 'INTERPOL', 'GAUSSIAN', 'GAUSSIAN_ELLIPSE', 'MULTI_GAUSSIAN', 'MULTI_GAUSSIAN_ELLIPSE' ] kwargs_list = [ { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'center_x': 0, 'center_y': 0 }, # 'SERSIC' { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'e1': 0.1, 'e2': 0, 'center_x': 0, 'center_y': 0 }, # 'SERSIC_ELLIPSE' { 'image': np.ones((10, 10)), 'scale': 1, 'phi_G': 0, 'center_x': 0, 'center_y': 0 }, # 'INTERPOL' { 'amp': 2, 'sigma_x': 2, 'sigma_y': 1, 'center_x': 0, 'center_y': 0 }, # 'GAUSSIAN' { 'amp': 2, 'sigma': 2, 'e1': 0.1, 'e2': 0, 'center_x': 0, 'center_y': 0 }, # 'GAUSSIAN_ELLIPSE' { 'amp': [1, 1], 'sigma': [2, 1], 'center_x': 0, 'center_y': 0 }, # 'MULTI_GAUSSIAN' { 'amp': [1, 1], 'sigma': [2, 1], 'e1': 0.1, 'e2': 0, 'center_x': 0, 'center_y': 0 } # 'MULTI_GAUSSIAN_ELLIPSE' ] lightModel = LightModel(light_model_list=light_model_list) total_flux_list = lightModel.total_flux(kwargs_list) assert total_flux_list[2] == 100 assert total_flux_list[3] == 2 assert total_flux_list[4] == 2 assert total_flux_list[5] == 2 assert total_flux_list[6] == 2 total_flux_list = lightModel.total_flux(kwargs_list, norm=True) assert total_flux_list[2] == 100 assert total_flux_list[3] == 1 assert total_flux_list[4] == 1 assert total_flux_list[5] == 2 assert total_flux_list[6] == 2
class LensAnalysis(object): """ class to compute flux ratio anomalies, inherited from standard MakeImage """ def __init__(self, kwargs_model): self.LensLightModel = LightModel( kwargs_model.get('lens_light_model_list', [])) self.SourceModel = LightModel( kwargs_model.get('source_light_model_list', [])) self.LensModel = LensModel( lens_model_list=kwargs_model.get('lens_model_list', []), z_source=kwargs_model.get('z_source', None), redshift_list=kwargs_model.get('redshift_list', None), multi_plane=kwargs_model.get('multi_plane', False)) self._lensModelExtensions = LensModelExtensions(self.LensModel) self.PointSource = PointSource(point_source_type_list=kwargs_model.get( 'point_source_model_list', [])) self.kwargs_model = kwargs_model self.NumLensModel = NumericLens( lens_model_list=kwargs_model.get('lens_model_list', [])) def fermat_potential(self, kwargs_lens, kwargs_ps): ra_pos, dec_pos = self.PointSource.image_position( kwargs_ps, kwargs_lens) ra_pos = ra_pos[0] dec_pos = dec_pos[0] ra_source, dec_source = self.LensModel.ray_shooting( ra_pos, dec_pos, kwargs_lens) ra_source = np.mean(ra_source) dec_source = np.mean(dec_source) fermat_pot = self.LensModel.fermat_potential(ra_pos, dec_pos, ra_source, dec_source, kwargs_lens) return fermat_pot def ellipticity_lens_light(self, kwargs_lens_light, center_x=0, center_y=0, model_bool_list=None, deltaPix=None, numPix=None): """ make sure that the window covers all the light, otherwise the moments may give to low answers. :param kwargs_lens_light: :param center_x: :param center_y: :param model_bool_list: :param deltaPix: :param numPix: :return: """ if model_bool_list is None: model_bool_list = [True] * len(kwargs_lens_light) if numPix is None: numPix = 100 if deltaPix is None: deltaPix = 0.05 x_grid, y_grid = util.make_grid(numPix=numPix, deltapix=deltaPix) x_grid += center_x y_grid += center_y I_xy = self._lens_light_internal(x_grid, y_grid, kwargs_lens_light, model_bool_list=model_bool_list) e1, e2 = analysis_util.ellipticities(I_xy, x_grid, y_grid) return e1, e2 def half_light_radius_lens(self, kwargs_lens_light, center_x=0, center_y=0, model_bool_list=None, deltaPix=None, numPix=None): """ computes numerically the half-light-radius of the deflector light and the total photon flux :param kwargs_lens_light: :return: """ if model_bool_list is None: model_bool_list = [True] * len(kwargs_lens_light) if numPix is None: numPix = 1000 if deltaPix is None: deltaPix = 0.05 x_grid, y_grid = util.make_grid(numPix=numPix, deltapix=deltaPix) x_grid += center_x y_grid += center_y lens_light = self._lens_light_internal(x_grid, y_grid, kwargs_lens_light, model_bool_list=model_bool_list) R_h = analysis_util.half_light_radius(lens_light, x_grid, y_grid, center_x, center_y) return R_h def half_light_radius_source(self, kwargs_source, center_x=0, center_y=0, deltaPix=None, numPix=None): """ computes numerically the half-light-radius of the deflector light and the total photon flux :param kwargs_source: :return: """ if numPix is None: numPix = 1000 if deltaPix is None: deltaPix = 0.005 x_grid, y_grid = util.make_grid(numPix=numPix, deltapix=deltaPix) x_grid += center_x y_grid += center_y source_light = self.SourceModel.surface_brightness( x_grid, y_grid, kwargs_source) R_h = analysis_util.half_light_radius(source_light, x_grid, y_grid, center_x=center_x, center_y=center_y) return R_h def _lens_light_internal(self, x_grid, y_grid, kwargs_lens_light, model_bool_list=None): """ evaluates only part of the light profiles :param x_grid: :param y_grid: :param kwargs_lens_light: :return: """ if model_bool_list is None: model_bool_list = [True] * len(kwargs_lens_light) lens_light = np.zeros_like(x_grid) for i, bool in enumerate(model_bool_list): if bool is True: lens_light_i = self.LensLightModel.surface_brightness( x_grid, y_grid, kwargs_lens_light, k=i) lens_light += lens_light_i return lens_light def multi_gaussian_lens_light(self, kwargs_lens_light, model_bool_list=None, e1=0, e2=0, n_comp=20, deltaPix=None, numPix=None): """ multi-gaussian decomposition of the lens light profile (in 1-dimension) :param kwargs_lens_light: :param n_comp: :return: """ if 'center_x' in kwargs_lens_light[0]: center_x = kwargs_lens_light[0]['center_x'] center_y = kwargs_lens_light[0]['center_y'] else: center_x, center_y = 0, 0 r_h = self.half_light_radius_lens(kwargs_lens_light, center_x=center_x, center_y=center_y, model_bool_list=model_bool_list, deltaPix=deltaPix, numPix=numPix) r_array = np.logspace(-3, 2, 200) * r_h * 2 x_coords, y_coords = param_util.transform_e1e2(r_array, np.zeros_like(r_array), e1=-e1, e2=-e2) x_coords += center_x y_coords += center_y #r_array = np.logspace(-2, 1, 50) * r_h flux_r = self._lens_light_internal(x_coords, y_coords, kwargs_lens_light, model_bool_list=model_bool_list) amplitudes, sigmas, norm = mge.mge_1d(r_array, flux_r, N=n_comp) return amplitudes, sigmas, center_x, center_y def multi_gaussian_lens(self, kwargs_lens, model_bool_list=None, e1=0, e2=0, n_comp=20): """ multi-gaussian lens model in convergence space :param kwargs_lens: :param n_comp: :return: """ if 'center_x' in kwargs_lens[0]: center_x = kwargs_lens[0]['center_x'] center_y = kwargs_lens[0]['center_y'] else: raise ValueError('no keyword center_x defined!') theta_E = self._lensModelExtensions.effective_einstein_radius( kwargs_lens) r_array = np.logspace(-4, 2, 200) * theta_E x_coords, y_coords = param_util.transform_e1e2(r_array, np.zeros_like(r_array), e1=-e1, e2=-e2) x_coords += center_x y_coords += center_y #r_array = np.logspace(-2, 1, 50) * theta_E if model_bool_list is None: model_bool_list = [True] * len(kwargs_lens) kappa_s = np.zeros_like(r_array) for i in range(len(kwargs_lens)): if model_bool_list[i] is True: kappa_s += self.LensModel.kappa(x_coords, y_coords, kwargs_lens, k=i) amplitudes, sigmas, norm = mge.mge_1d(r_array, kappa_s, N=n_comp) return amplitudes, sigmas, center_x, center_y def flux_components(self, kwargs_light, n_grid=400, delta_grid=0.01, deltaPix=0.05, type="lens"): """ computes the total flux in each component of the model :param kwargs_light: :param n_grid: :param delta_grid: :return: """ flux_list = [] R_h_list = [] x_grid, y_grid = util.make_grid(numPix=n_grid, deltapix=delta_grid) kwargs_copy = copy.deepcopy(kwargs_light) for k, kwargs in enumerate(kwargs_light): if 'center_x' in kwargs_copy[k]: kwargs_copy[k]['center_x'] = 0 kwargs_copy[k]['center_y'] = 0 if type == 'lens': light = self.LensLightModel.surface_brightness(x_grid, y_grid, kwargs_copy, k=k) elif type == 'source': light = self.SourceModel.surface_brightness(x_grid, y_grid, kwargs_copy, k=k) else: raise ValueError("type %s not supported!" % type) flux = np.sum(light) * delta_grid**2 / deltaPix**2 R_h = analysis_util.half_light_radius(light, x_grid, y_grid) flux_list.append(flux) R_h_list.append(R_h) return flux_list, R_h_list def error_map_source(self, kwargs_source, x_grid, y_grid, cov_param): """ variance of the linear source reconstruction in the source plane coordinates, computed by the diagonal elements of the covariance matrix of the source reconstruction as a sum of the errors of the basis set. :param kwargs_source: keyword arguments of source model :param x_grid: x-axis of positions to compute error map :param y_grid: y-axis of positions to compute error map :param cov_param: covariance matrix of liner inversion parameters :return: diagonal covariance errors at the positions (x_grid, y_grid) """ error_map = np.zeros_like(x_grid) basis_functions, n_source = self.SourceModel.functions_split( x_grid, y_grid, kwargs_source) basis_functions = np.array(basis_functions) if cov_param is not None: for i in range(len(error_map)): error_map[i] = basis_functions[:, i].T.dot( cov_param[:n_source, :n_source]).dot(basis_functions[:, i]) return error_map def light2mass_mge(self, kwargs_lens_light, model_bool_list=None, elliptical=False, numPix=100, deltaPix=0.05): # estimate center if 'center_x' in kwargs_lens_light[0]: center_x, center_y = kwargs_lens_light[0][ 'center_x'], kwargs_lens_light[0]['center_y'] else: center_x, center_y = 0, 0 # estimate half-light radius r_h = self.half_light_radius_lens(kwargs_lens_light, center_x=center_x, center_y=center_y, model_bool_list=model_bool_list, numPix=numPix, deltaPix=deltaPix) # estimate ellipticity at half-light radius if elliptical is True: e1, e2 = self.ellipticity_lens_light( kwargs_lens_light, center_x=center_x, center_y=center_y, model_bool_list=model_bool_list, deltaPix=deltaPix * 2, numPix=numPix) else: e1, e2 = 0, 0 # MGE around major axis amplitudes, sigmas, center_x, center_y = self.multi_gaussian_lens_light( kwargs_lens_light, model_bool_list=model_bool_list, e1=e1, e2=e2, n_comp=20) kwargs_mge = { 'amp': amplitudes, 'sigma': sigmas, 'center_x': center_x, 'center_y': center_y } if elliptical: kwargs_mge['e1'] = e1 kwargs_mge['e2'] = e2 # rotate axes and add ellipticity to model kwargs return kwargs_mge @staticmethod def light2mass_interpol(lens_light_model_list, kwargs_lens_light, numPix=100, deltaPix=0.05, subgrid_res=5, center_x=0, center_y=0): """ takes a lens light model and turns it numerically in a lens model (with all lensmodel quantities computed on a grid). Then provides an interpolated grid for the quantities. :param kwargs_lens_light: lens light keyword argument list :param numPix: number of pixels per axis for the return interpolation :param deltaPix: interpolation/pixel size :param center_x: center of the grid :param center_y: center of the grid :param subgrid: subgrid for the numerical integrals :return: """ # make sugrid x_grid_sub, y_grid_sub = util.make_grid(numPix=numPix * 5, deltapix=deltaPix, subgrid_res=subgrid_res) import lenstronomy.Util.mask as mask_util mask = mask_util.mask_sphere(x_grid_sub, y_grid_sub, center_x, center_y, r=1) x_grid, y_grid = util.make_grid(numPix=numPix, deltapix=deltaPix) # compute light on the subgrid lightModel = LightModel(light_model_list=lens_light_model_list) flux = lightModel.surface_brightness(x_grid_sub, y_grid_sub, kwargs_lens_light) flux_norm = np.sum(flux[mask == 1]) / np.sum(mask) flux /= flux_norm from lenstronomy.LensModel.numerical_profile_integrals import ConvergenceIntegrals integral = ConvergenceIntegrals() # compute lensing quantities with subgrid convergence_sub = flux f_x_sub, f_y_sub = integral.deflection_from_kappa(convergence_sub, x_grid_sub, y_grid_sub, deltaPix=deltaPix / float(subgrid_res)) f_sub = integral.potential_from_kappa(convergence_sub, x_grid_sub, y_grid_sub, deltaPix=deltaPix / float(subgrid_res)) # interpolation function on lensing quantities x_axes_sub, y_axes_sub = util.get_axes(x_grid_sub, y_grid_sub) from lenstronomy.LensModel.Profiles.interpol import Interpol_func interp_func = Interpol_func() interp_func.do_interp(x_axes_sub, y_axes_sub, f_sub, f_x_sub, f_y_sub) # compute lensing quantities on sparser grid x_axes, y_axes = util.get_axes(x_grid, y_grid) f_ = interp_func.function(x_grid, y_grid) f_x, f_y = interp_func.derivatives(x_grid, y_grid) # numerical differentials for second order differentials from lenstronomy.LensModel.numeric_lens_differentials import NumericLens lens_differential = NumericLens(lens_model_list=['INTERPOL']) kwargs = [{ 'grid_interp_x': x_axes_sub, 'grid_interp_y': y_axes_sub, 'f_': f_sub, 'f_x': f_x_sub, 'f_y': f_y_sub }] f_xx, f_xy, f_yx, f_yy = lens_differential.hessian( x_grid, y_grid, kwargs) kwargs_interpol = { 'grid_interp_x': x_axes, 'grid_interp_y': y_axes, 'f_': util.array2image(f_), 'f_x': util.array2image(f_x), 'f_y': util.array2image(f_y), 'f_xx': util.array2image(f_xx), 'f_xy': util.array2image(f_xy), 'f_yy': util.array2image(f_yy) } return kwargs_interpol def mass_fraction_within_radius(self, kwargs_lens, center_x, center_y, theta_E, numPix=100): """ computes the mean convergence of all the different lens model components within a spherical aperture :param kwargs_lens: lens model keyword argument list :param center_x: center of the aperture :param center_y: center of the aperture :param theta_E: radius of aperture :return: list of average convergences for all the model components """ x_grid, y_grid = util.make_grid(numPix=numPix, deltapix=2. * theta_E / numPix) x_grid += center_x y_grid += center_y mask = mask_util.mask_sphere(x_grid, y_grid, center_x, center_y, theta_E) kappa_list = [] for i in range(len(kwargs_lens)): kappa = self.LensModel.kappa(x_grid, y_grid, kwargs_lens, k=i) kappa_mean = np.sum(kappa * mask) / np.sum(mask) kappa_list.append(kappa_mean) return kappa_list
class TestLightModel(object): """ tests the source model routines """ def setup(self): self.light_model_list = [ 'GAUSSIAN', 'MULTI_GAUSSIAN', 'SERSIC', 'SERSIC_ELLIPSE', 'CORE_SERSIC', 'SHAPELETS', 'HERNQUIST', 'HERNQUIST_ELLIPSE', 'PJAFFE', 'PJAFFE_ELLIPSE', 'UNIFORM', 'POWER_LAW', 'NIE' ] phi_G, q = 0.5, 0.8 e1, e2 = param_util.phi_q2_ellipticity(phi_G, q) self.kwargs = [ { 'amp': 1., 'sigma_x': 1, 'sigma_y': 1., 'center_x': 0, 'center_y': 0 }, # 'GAUSSIAN' { 'amp': [1., 2], 'sigma': [1, 3], 'center_x': 0, 'center_y': 0 }, # 'MULTI_GAUSSIAN' { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'center_x': 0, 'center_y': 0 }, # 'SERSIC' { 'amp': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'e1': e1, 'e2': e2, 'center_x': 0, 'center_y': 0 }, # 'SERSIC_ELLIPSE' { 'amp': 1, 'R_sersic': 0.5, 'Re': 0.1, 'gamma': 2., 'n_sersic': 1, 'e1': e1, 'e2': e2, 'center_x': 0, 'center_y': 0 }, # 'CORE_SERSIC' { 'amp': [1, 1, 1], 'beta': 0.5, 'n_max': 1, 'center_x': 0, 'center_y': 0 }, # 'SHAPELETS' { 'amp': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0 }, # 'HERNQUIST' { 'amp': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'e1': e1, 'e2': e2 }, # 'HERNQUIST_ELLIPSE' { 'amp': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0 }, # 'PJAFFE' { 'amp': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'e1': e1, 'e2': e2 }, # 'PJAFFE_ELLIPSE' { 'amp': 1 }, # 'UNIFORM' { 'amp': 1., 'gamma': 2., 'e1': e1, 'e2': e2, 'center_x': 0, 'center_y': 0 }, # 'POWER_LAW' { 'amp': .001, 'e1': 0, 'e2': 1., 'center_x': 0, 'center_y': 0, 's_scale': 1. }, # 'NIE' ] self.LightModel = LightModel(light_model_list=self.light_model_list) def test_init(self): model_list = [ 'CORE_SERSIC', 'SHAPELETS', 'UNIFORM', 'CHAMELEON', 'DOUBLE_CHAMELEON' ] lightModel = LightModel(light_model_list=model_list) assert len(lightModel.profile_type_list) == len(model_list) def test_surface_brightness(self): output = self.LightModel.surface_brightness(x=1, y=1, kwargs_list=self.kwargs) npt.assert_almost_equal(output, 3.512593731652167, decimal=6) def test_surface_brightness_array(self): output = self.LightModel.surface_brightness(x=[1], y=[1], kwargs_list=self.kwargs) npt.assert_almost_equal(output[0], 3.512593731652167, decimal=6) def test_functions_split(self): output = self.LightModel.functions_split(x=1., y=1., kwargs_list=self.kwargs) npt.assert_almost_equal(output[0][0], 0.058549831524319168, decimal=6) def test_re_normalize_flux(self): kwargs_out = self.LightModel.re_normalize_flux(kwargs_list=self.kwargs, norm_factor=2) assert kwargs_out[0]['amp'] == 2 * self.kwargs[0]['amp'] def test_param_name_list(self): param_name_list = self.LightModel.param_name_list() assert len(self.light_model_list) == len(param_name_list) def test_update_linear(self): response, n = self.LightModel.functions_split(1, 1, self.kwargs) param = np.ones(n) * 2 kwargs_out, i = self.LightModel.update_linear(param, i=0, kwargs_list=self.kwargs) assert i == n assert kwargs_out[0]['amp'] == 2
class LensAnalysis(object): """ class to compute flux ratio anomalies, inherited from standard MakeImage """ def __init__(self, kwargs_model): self.LensLightModel = LightModel(kwargs_model.get('lens_light_model_list', ['NONE'])) self.SourceModel = LightModel(kwargs_model.get('source_light_model_list', ['NONE'])) self.LensModel = LensModelExtensions(lens_model_list=kwargs_model['lens_model_list']) self.PointSource = PointSource(point_source_type_list=kwargs_model.get('point_source_model_list', ['NONE'])) self.kwargs_model = kwargs_model self.NumLensModel = NumericLens(lens_model_list=kwargs_model['lens_model_list']) self.gaussian = Gaussian() def fermat_potential(self, kwargs_lens, kwargs_ps): ra_pos, dec_pos = self.PointSource.image_position(kwargs_ps, kwargs_lens) ra_pos = ra_pos[0] dec_pos = dec_pos[0] ra_source, dec_source = self.LensModel.ray_shooting(ra_pos, dec_pos, kwargs_lens) ra_source = np.mean(ra_source) dec_source = np.mean(dec_source) fermat_pot = self.LensModel.fermat_potential(ra_pos, dec_pos, ra_source, dec_source, kwargs_lens) return fermat_pot def half_light_radius_lens(self, kwargs_lens_light, deltaPix=None, numPix=None): """ computes numerically the half-light-radius of the deflector light and the total photon flux :param kwargs_lens_light: :return: """ if numPix is None: numPix = 1000 if deltaPix is None: deltaPix = 0.05 x_grid, y_grid = util.make_grid(numPix=numPix, deltapix=deltaPix) lens_light = self._lens_light_internal(x_grid, y_grid, kwargs_lens_light) R_h = analysis_util.half_light_radius(lens_light, x_grid, y_grid) return R_h def half_light_radius_source(self, kwargs_source, deltaPix=None, numPix=None): """ computes numerically the half-light-radius of the deflector light and the total photon flux :param kwargs_lens_light: :return: """ if numPix is None: numPix = 1000 if deltaPix is None: deltaPix = 0.005 x_grid, y_grid = util.make_grid(numPix=numPix, deltapix=deltaPix) source_light = self.SourceModel.surface_brightness(x_grid, y_grid, kwargs_source) R_h = analysis_util.half_light_radius(source_light, x_grid, y_grid, center_x=kwargs_source[0]['center_x'], center_y=kwargs_source[0]['center_y']) return R_h def _lens_light_internal(self, x_grid, y_grid, kwargs_lens_light): """ :param x_grid: :param y_grid: :param kwargs_lens_light: :return: """ kwargs_lens_light_copy = copy.deepcopy(kwargs_lens_light) lens_light_model_internal_bool = self.kwargs_model.get('light_model_deflector_bool', [True] * len(kwargs_lens_light)) lens_light = np.zeros_like(x_grid) for i, bool in enumerate(lens_light_model_internal_bool): if bool is True: kwargs_lens_light_copy[i]['center_x'] = 0 kwargs_lens_light_copy[i]['center_y'] = 0 lens_light_i = self.LensLightModel.surface_brightness(x_grid, y_grid, kwargs_lens_light_copy, k=i) lens_light += lens_light_i return lens_light def multi_gaussian_lens_light(self, kwargs_lens_light, n_comp=20): """ multi-gaussian decomposition of the lens light profile (in 1-dimension) :param kwargs_lens_light: :param n_comp: :return: """ r_h = self.half_light_radius_lens(kwargs_lens_light) r_array = np.logspace(-3, 2, 200) * r_h * 2 #r_array = np.logspace(-2, 1, 50) * r_h flux_r = self._lens_light_internal(r_array, np.zeros_like(r_array), kwargs_lens_light) amplitudes, sigmas, norm = mge.mge_1d(r_array, flux_r, N=n_comp) return amplitudes, sigmas def multi_gaussian_lens(self, kwargs_lens, n_comp=20): """ multi-gaussian lens model in convergence space :param kwargs_lens: :param n_comp: :return: """ kwargs_lens_copy = copy.deepcopy(kwargs_lens) if 'center_x' in kwargs_lens_copy[0]: center_x = kwargs_lens_copy[0]['center_x'] center_y = kwargs_lens_copy[0]['center_y'] else: raise ValueError('no keyword center_x defined!') theta_E = self.LensModel.effective_einstein_radius(kwargs_lens) r_array = np.logspace(-4, 2, 200) * theta_E #r_array = np.logspace(-2, 1, 50) * theta_E lens_model_internal_bool = self.kwargs_model.get('lens_model_internal_bool', [True] * len(kwargs_lens)) kappa_s = np.zeros_like(r_array) for i in range(len(kwargs_lens_copy)): if lens_model_internal_bool[i]: if 'center_x' in kwargs_lens_copy[0]: kwargs_lens_copy[i]['center_x'] -= center_x kwargs_lens_copy[i]['center_y'] -= center_y kappa_s += self.LensModel.kappa(r_array, np.zeros_like(r_array), kwargs_lens_copy, k=i) amplitudes, sigmas, norm = mge.mge_1d(r_array, kappa_s, N=n_comp) return amplitudes, sigmas, center_x, center_y def flux_components(self, kwargs_light, n_grid=400, delta_grid=0.01, deltaPix=0.05, type="lens"): """ computes the total flux in each component of the model :param kwargs_light: :param n_grid: :param delta_grid: :return: """ flux_list = [] R_h_list = [] x_grid, y_grid = util.make_grid(numPix=n_grid, deltapix=delta_grid) kwargs_copy = copy.deepcopy(kwargs_light) for k, kwargs in enumerate(kwargs_light): if 'center_x' in kwargs_copy[k]: kwargs_copy[k]['center_x'] = 0 kwargs_copy[k]['center_y'] = 0 if type == 'lens': light = self.LensLightModel.surface_brightness(x_grid, y_grid, kwargs_copy, k=k) elif type == 'source': light = self.SourceModel.surface_brightness(x_grid, y_grid, kwargs_copy, k=k) else: raise ValueError("type %s not supported!" % type) flux = np.sum(light)*delta_grid**2/ deltaPix**2 R_h = analysis_util.half_light_radius(light, x_grid, y_grid) flux_list.append(flux) R_h_list.append(R_h) return flux_list, R_h_list @staticmethod def buldge_disk_ratio(kwargs_buldge_disk): """ computes the buldge-to-disk ratio of the :param kwargs_buldge_disk: kwargs of the buldge2disk function :return: """ kwargs_bd = copy.deepcopy(kwargs_buldge_disk) kwargs_bd['center_x'] = 0 kwargs_bd['center_y'] = 0 deltaPix = 0.05 numPix = 200 x_grid, y_grid = util.make_grid(numPix, deltaPix) from lenstronomy.LightModel.Profiles.sersic import BuldgeDisk bd_class = BuldgeDisk() light_grid = bd_class.function(x_grid, y_grid, **kwargs_bd) light_tot = np.sum(light_grid) kwargs_bd['I0_d'] = 0 light_grid = bd_class.function(x_grid, y_grid, **kwargs_bd) light_buldge = np.sum(light_grid) return light_tot, light_buldge def error_map_source(self, kwargs_source, x_grid, y_grid, cov_param): """ variance of the linear source reconstruction in the source plane coordinates, computed by the diagonal elements of the covariance matrix of the source reconstruction as a sum of the errors of the basis set. :param kwargs_source: keyword arguments of source model :param x_grid: x-axis of positions to compute error map :param y_grid: y-axis of positions to compute error map :param cov_param: covariance matrix of liner inversion parameters :return: diagonal covariance errors at the positions (x_grid, y_grid) """ error_map = np.zeros_like(x_grid) basis_functions, n_source = self.SourceModel.functions_split(x_grid, y_grid, kwargs_source) basis_functions = np.array(basis_functions) if cov_param is not None: for i in range(len(error_map)): error_map[i] = basis_functions[:, i].T.dot(cov_param[:n_source, :n_source]).dot(basis_functions[:, i]) return error_map
def test_raise(self): with self.assertRaises(ValueError): # try to set decomposition scale to higher than maximal value starlets = SLIT_Starlets(force_no_pysap=True) # define a test image with gaussian components num_pix = 50 x, y = util.make_grid(num_pix, 1) # build a non-trivial positive image from sum of gaussians gaussian = Gaussian() gaussian1 = gaussian.function(x, y, amp=100, sigma=1, center_x=-7, center_y=-7) gaussian2 = gaussian.function(x, y, amp=500, sigma=3, center_x=-3, center_y=-3) gaussian3 = gaussian.function(x, y, amp=2000, sigma=5, center_x=+5, center_y=+5) test_image = util.array2image(gaussian1 + gaussian2 + gaussian3) n_scales = 100 _ = starlets.decomposition_2d(test_image, n_scales) with self.assertRaises(ValueError): # try to set decomposition scale to negative value starlets = SLIT_Starlets(force_no_pysap=True) # define a test image with gaussian components num_pix = 50 x, y = util.make_grid(num_pix, 1) # build a non-trivial positive image from sum of gaussians gaussian = Gaussian() gaussian1 = gaussian.function(x, y, amp=100, sigma=1, center_x=-7, center_y=-7) gaussian2 = gaussian.function(x, y, amp=500, sigma=3, center_x=-3, center_y=-3) gaussian3 = gaussian.function(x, y, amp=2000, sigma=5, center_x=+5, center_y=+5) test_image = util.array2image(gaussian1 + gaussian2 + gaussian3) n_scales = -1 _ = starlets.decomposition_2d(test_image, n_scales) with self.assertRaises(ValueError): # function_split is not supported/defined for pixel-based profiles light_model = LightModel(['SLIT_STARLETS']) num_pix = 20 x, y = util.make_grid(num_pix, 1) kwargs_list = [{ 'amp': np.ones((3, num_pix, num_pix)), 'n_scales': 3, 'n_pixels': 20**2, 'center_x': 0, 'center_y': 0, 'scale': 1 }] _ = light_model.functions_split(x, y, kwargs_list) with self.assertRaises(ValueError): # provided a wrong shape for starlet coefficients starlet_class = SLIT_Starlets() num_pix = 20 x, y = util.make_grid(num_pix, 1) coeffs_wrong = np.ones((3, num_pix**2)) kwargs_list = { 'amp': coeffs_wrong, 'n_scales': 3, 'n_pixels': 20**2, 'center_x': 0, 'center_y': 0, 'scale': 1 } _ = starlet_class.function(x, y, **kwargs_list) image_wrong = np.ones((1, num_pix, num_pix)) _ = starlet_class.decomposition(image_wrong, 3) with self.assertRaises(ValueError): # provided a wrong shape for image to be decomposed starlet_class = SLIT_Starlets() num_pix = 20 image_wrong = np.ones((2, num_pix, num_pix)) _ = starlet_class.decomposition(image_wrong, 3)