def test_mge_1d_sersic(self): n_comp = 30 r_sersic = 1. n_sersic = 3.7 I0_sersic = 1. rs = np.logspace(-2., 1., 50) * r_sersic ss = self.sersic.function(rs, np.zeros_like(rs), amp=I0_sersic, n_sersic=n_sersic, R_sersic=r_sersic) amplitudes, sigmas, norm = mge.mge_1d(rs, ss, N=n_comp) ss_mge = self.multiGaussian.function(rs, np.zeros_like(rs), amp=amplitudes, sigma=sigmas) #print((ss - ss_mge)/ss) for i in range(10, len(ss) - 10): #print(rs[i]) npt.assert_almost_equal((ss_mge[i] - ss[i]) / ss[i], 0, decimal=1) amplitudes, sigmas, norm = mge.mge_1d(rs, np.zeros_like(rs), N=n_comp) assert amplitudes[0] == 0 amplitudes, sigmas, norm = mge.mge_1d(rs, np.zeros_like(rs), N=0) assert amplitudes[0] == 0
def test_mge_light_and_mass(self): # anisotropy profile anisotropy_type = 'OsipkovMerritt' r_ani = 2. kwargs_anisotropy = {'r_ani': r_ani} # anisotropy radius [arcsec] # aperture as slit aperture_type = 'slit' length = 3.8 width = 0.9 kwargs_aperture = {'length': length, 'width': width, 'center_ra': 0, 'center_dec': 0, 'angle': 0} psf_fwhm = 0.7 # Gaussian FWHM psf kwargs_cosmo = {'D_d': 1000, 'D_s': 1500, 'D_ds': 800} # light profile light_profile_list = ['HERNQUIST'] r_eff = 1.8 kwargs_light = [{'Rs': r_eff, 'amp': 1.}] # effective half light radius (2d projected) in arcsec # mass profile mass_profile_list = ['SPP'] theta_E = 1.2 gamma = 2. kwargs_profile = [{'theta_E': theta_E, 'gamma': gamma}] # Einstein radius (arcsec) and power-law slope # mge of light profile lightModel = LightModel(light_profile_list) r_array = np.logspace(-2, 2, 200) * r_eff * 2 flux_r = lightModel.surface_brightness(r_array, 0, kwargs_light) amps, sigmas, norm = mge.mge_1d(r_array, flux_r, N=20) light_profile_list_mge = ['MULTI_GAUSSIAN'] kwargs_light_mge = [{'amp': amps, 'sigma': sigmas}] # mge of lens profile lensModel = LensModel(mass_profile_list) r_array = np.logspace(-2, 2, 200) kappa_r = lensModel.kappa(r_array, 0, kwargs_profile) amps, sigmas, norm = mge.mge_1d(r_array, kappa_r, N=20) mass_profile_list_mge = ['MULTI_GAUSSIAN_KAPPA'] kwargs_profile_mge = [{'amp': amps, 'sigma': sigmas}] galkin = Galkin(mass_profile_list, light_profile_list, aperture_type=aperture_type, anisotropy_model=anisotropy_type, fwhm=psf_fwhm, kwargs_cosmo=kwargs_cosmo) sigma_v = galkin.vel_disp(kwargs_profile, kwargs_light, kwargs_anisotropy, kwargs_aperture) galkin = Galkin(mass_profile_list_mge, light_profile_list_mge, aperture_type=aperture_type, anisotropy_model=anisotropy_type, fwhm=psf_fwhm, kwargs_cosmo=kwargs_cosmo) sigma_v2 = galkin.vel_disp(kwargs_profile_mge, kwargs_light_mge, kwargs_anisotropy, kwargs_aperture) print(sigma_v, sigma_v2, 'sigma_v Galkin, sigma_v MGEn') print((sigma_v/sigma_v2)**2) npt.assert_almost_equal((sigma_v-sigma_v2)/sigma_v2, 0, decimal=2)
def test_hernquist_deprojection(self): hernquist = Hernquist() n_comp = 20 sigma0 = 1 r_eff = 1.5 rs = np.logspace(-2., 1., 50) * r_eff * 0.5 ss = hernquist.function(rs, np.zeros_like(rs), sigma0, Rs=r_eff) amplitudes, sigmas, norm = mge.mge_1d(rs, ss, N=n_comp) amplitudes_3d, sigmas_3d = mge.de_projection_3d(amplitudes, sigmas) ss_3d_mge = self.multiGaussian.function(rs, np.zeros_like(rs), amp=amplitudes_3d, sigma=sigmas_3d) ss_3d_mulit = self.multiGaussian.light_3d(rs, amp=amplitudes, sigma=sigmas) for i in range(10, len(ss_3d_mge)): npt.assert_almost_equal((ss_3d_mge[i] - ss_3d_mulit[i]) / (ss_3d_mulit[i] + ss_3d_mge[i]), 0, decimal=1) ss_3d = hernquist.light_3d(rs, sigma0, Rs=r_eff) for i in range(10, len(ss_3d) - 10): npt.assert_almost_equal( (ss_3d_mge[i] - ss_3d[i]) / (ss_3d[i] + ss_3d_mge[i]), 0, decimal=1)
def test_nfw_sersic(self): kwargs_lens_nfw = {'alpha_Rs': 1.4129647849966354, 'Rs': 7.0991113634274736} kwargs_lens_sersic = {'k_eff': 0.24100561407593576, 'n_sersic': 1.8058507329346063, 'R_sersic': 1.0371803141813705} from lenstronomy.LensModel.Profiles.nfw import NFW from lenstronomy.LensModel.Profiles.sersic import Sersic nfw = NFW() sersic = Sersic() theta_E = 1.5 n_comp = 10 rs = np.logspace(-2., 1., 100) * theta_E f_xx_nfw, f_xy_nfw, f_yx_nfw, f_yy_nfw = nfw.hessian(rs, 0, **kwargs_lens_nfw) f_xx_s, f_xy_s, f_yx_s, f_yy_s = sersic.hessian(rs, 0, **kwargs_lens_sersic) kappa = 1 / 2. * (f_xx_nfw + f_xx_s + f_yy_nfw + f_yy_s) amplitudes, sigmas, norm = mge.mge_1d(rs, kappa, N=n_comp) kappa_mge = self.multiGaussian.function(rs, np.zeros_like(rs), amp=amplitudes, sigma=sigmas) from lenstronomy.LensModel.Profiles.multi_gaussian_kappa import MultiGaussianKappa mge_kappa = MultiGaussianKappa() f_xx_mge, f_xy_mge, f_yx_mge, f_yy_mge = mge_kappa.hessian(rs, np.zeros_like(rs), amp=amplitudes, sigma=sigmas) for i in range(0, 80): npt.assert_almost_equal(kappa_mge[i], 1. / 2 * (f_xx_mge[i] + f_yy_mge[i]), decimal=1) npt.assert_almost_equal((kappa[i] - kappa_mge[i]) / kappa[i], 0, decimal=1) f_nfw = nfw.function(theta_E, 0, **kwargs_lens_nfw) f_s = sersic.function(theta_E, 0, **kwargs_lens_sersic) f_mge = mge_kappa.function(theta_E, 0, sigma=sigmas, amp=amplitudes) npt.assert_almost_equal(f_mge / (f_nfw + f_s), 1, decimal=2)
def test_sersic_vs_hernquist_kinematics(self): """ attention: this test only works for Sersic indices > \approx 2! Lower n_sersic will result in different predictions with the Hernquist assumptions replacing the correct Light model! :return: """ # anisotropy profile anisotropy_type = 'OsipkovMerritt' r_ani = 2. kwargs_anisotropy = {'r_ani': r_ani} # anisotropy radius [arcsec] # aperture as slit aperture_type = 'slit' length = 3.8 width = 0.9 kwargs_aperture = {'length': length, 'width': width, 'center_ra': 0, 'center_dec': 0, 'angle': 0} psf_fwhm = 0.7 # Gaussian FWHM psf kwargs_cosmo = {'D_d': 1000, 'D_s': 1500, 'D_ds': 800} # light profile light_profile_list = ['SERSIC'] r_sersic = .3 n_sersic = 2.8 kwargs_light = [{'amp': 1., 'R_sersic': r_sersic, 'n_sersic': n_sersic}] # effective half light radius (2d projected) in arcsec # mass profile mass_profile_list = ['SPP'] theta_E = 1.2 gamma = 2. kwargs_profile = [{'theta_E': theta_E, 'gamma': gamma}] # Einstein radius (arcsec) and power-law slope # Hernquist fit to Sersic profile lens_analysis = LensAnalysis({'lens_light_model_list': ['SERSIC'], 'lens_model_list': []}) r_eff = lens_analysis.half_light_radius_lens(kwargs_light, deltaPix=0.1, numPix=100) print(r_eff) light_profile_list_hernquist = ['HERNQUIST'] kwargs_light_hernquist = [{'Rs': r_eff*0.551, 'amp': 1.}] # mge of light profile lightModel = LightModel(light_profile_list) r_array = np.logspace(-3, 2, 100) * r_eff * 2 print(r_sersic/r_eff, 'r_sersic/r_eff') flux_r = lightModel.surface_brightness(r_array, 0, kwargs_light) amps, sigmas, norm = mge.mge_1d(r_array, flux_r, N=20) light_profile_list_mge = ['MULTI_GAUSSIAN'] kwargs_light_mge = [{'amp': amps, 'sigma': sigmas}] print(amps, sigmas, 'amp', 'sigma') galkin = Galkin(mass_profile_list, light_profile_list_hernquist, aperture_type=aperture_type, anisotropy_model=anisotropy_type, fwhm=psf_fwhm, kwargs_cosmo=kwargs_cosmo) sigma_v = galkin.vel_disp(kwargs_profile, kwargs_light_hernquist, kwargs_anisotropy, kwargs_aperture) galkin = Galkin(mass_profile_list, light_profile_list_mge, aperture_type=aperture_type, anisotropy_model=anisotropy_type, fwhm=psf_fwhm, kwargs_cosmo=kwargs_cosmo) sigma_v2 = galkin.vel_disp(kwargs_profile, kwargs_light_mge, kwargs_anisotropy, kwargs_aperture) print(sigma_v, sigma_v2, 'sigma_v Galkin, sigma_v MGEn') print((sigma_v/sigma_v2)**2) npt.assert_almost_equal((sigma_v-sigma_v2)/sigma_v2, 0, decimal=1)
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 test_spemd(self): from lenstronomy.LensModel.Profiles.spep import SPEP from lenstronomy.LensModel.Profiles.multi_gaussian_kappa import MultiGaussianKappa spep = SPEP() mge_kappa = MultiGaussianKappa() n_comp = 8 theta_E = 1.41 kwargs = {'theta_E': theta_E, 'e1': 0, 'e2': 0, 'gamma': 1.61} rs = np.logspace(-2., 1., 100) * theta_E f_xx, f_yy, f_xy = spep.hessian(rs, 0, **kwargs) kappa = 1 / 2. * (f_xx + f_yy) amplitudes, sigmas, norm = mge.mge_1d(rs, kappa, N=n_comp) kappa_mge = self.multiGaussian.function(rs, np.zeros_like(rs), amp=amplitudes, sigma=sigmas) f_xx_mge, f_yy_mge, f_xy_mge = mge_kappa.hessian(rs, np.zeros_like(rs), amp=amplitudes, sigma=sigmas) for i in range(0, 80): npt.assert_almost_equal(kappa_mge[i], 1. / 2 * (f_xx_mge[i] + f_yy_mge[i]), decimal=1) npt.assert_almost_equal((kappa[i] - kappa_mge[i]) / kappa[i], 0, decimal=1) f_ = spep.function(theta_E, 0, **kwargs) f_mge = mge_kappa.function(theta_E, 0, sigma=sigmas, amp=amplitudes) npt.assert_almost_equal(f_mge / f_, 1, decimal=2)
def test_mge_sersic_n_sersic(self): n_comp = 20 r_sersic = 1.5 n_sersic = .5 I0_sersic = 1. rs = np.logspace(-2., 1., 50) * r_sersic ss = self.sersic.function(rs, np.zeros_like(rs), amp=I0_sersic, n_sersic=n_sersic, R_sersic=r_sersic) amplitudes, sigmas, norm = mge.mge_1d(rs, ss, N=n_comp) ss_mge = self.multiGaussian.function(rs, np.zeros_like(rs), amp=amplitudes, sigma=sigmas) for i in range(10, len(ss) - 10): npt.assert_almost_equal((ss_mge[i] - ss[i]) / (ss[i] + ss_mge[i]), 0, decimal=1) n_comp = 20 r_sersic = 1.5 n_sersic = 3.5 I0_sersic = 1. rs = np.logspace(-2., 1., 50) * r_sersic ss = self.sersic.function(rs, np.zeros_like(rs), amp=I0_sersic, n_sersic=n_sersic, R_sersic=r_sersic) amplitudes, sigmas, norm = mge.mge_1d(rs, ss, N=n_comp) ss_mge = self.multiGaussian.function(rs, np.zeros_like(rs), amp=amplitudes, sigma=sigmas) for i in range(10, len(ss) - 10): npt.assert_almost_equal((ss_mge[i] - ss[i]) / (ss[i] + ss_mge[i]), 0, decimal=1)
def test_hernquist(self): hernquist = Hernquist() n_comp = 20 sigma0 = 1 r_eff = 1.5 rs = np.logspace(-2., 1., 50) * r_eff * 0.5 ss = hernquist.function(rs, np.zeros_like(rs), sigma0, Rs=r_eff) amplitudes, sigmas, norm = mge.mge_1d(rs, ss, N=n_comp) ss_mge = self.multiGaussian.function(rs, np.zeros_like(rs), amp=amplitudes, sigma=sigmas) for i in range(10, len(ss)-10): npt.assert_almost_equal((ss_mge[i]-ss[i])/(ss[i]+ss_mge[i]), 0, decimal=2)
def test_example(self): n_comp = 10 rs = np.array([0.01589126, 0.01703967, 0.01827108, 0.01959148, 0.0210073 , 0.02252544, 0.02415329, 0.02589879, 0.02777042, 0.02977731, 0.03192923, 0.03423667, 0.03671086, 0.03936385, 0.04220857, 0.04525886, 0.0485296 , 0.0520367 , 0.05579724, 0.05982956, 0.06415327, 0.06878945, 0.07376067, 0.07909115, 0.08480685, 0.09093561, 0.09750727, 0.10455385, 0.11210966, 0.12021152, 0.12889887, 0.13821403, 0.14820238, 0.15891255, 0.17039672, 0.18271082, 0.19591482, 0.21007304, 0.22525444, 0.24153295, 0.25898787, 0.2777042 , 0.29777311, 0.31929235, 0.34236672, 0.36710861, 0.39363853, 0.42208569, 0.45258865, 0.48529597, 0.52036697, 0.55797244, 0.59829556, 0.64153272, 0.6878945 , 0.73760673, 0.79091152, 0.8480685 , 0.90935605, 0.97507269, 1.04553848, 1.12109664, 1.20211518, 1.28898871, 1.38214034, 1.48202378, 1.58912553, 1.70396721, 1.82710819, 1.95914822, 2.10073042, 2.25254437, 2.4153295 , 2.58987865, 2.77704199, 2.9777311 , 3.19292345, 3.42366716, 3.67108607, 3.93638527, 4.22085689, 4.5258865 , 4.85295974, 5.20366966, 5.57972441, 5.98295559, 6.41532717, 6.87894505, 7.37606729, 7.90911519, 8.48068497, 9.09356051, 9.75072687, 10.45538481, 11.21096643, 12.02115183, 12.88988708, 13.82140341, 14.82023784, 15.89125526]) kappa = np.array([ 12.13776067, 11.60484966, 11.09533396, 10.60818686, 10.14242668, 9.69711473, 9.27135349, 8.86428482, 8.47508818, 8.10297905, 7.7472073 , 7.40705574, 7.08183863, 6.77090034, 6.47361399, 6.18938022, 5.917626 , 5.65780342, 5.40938864, 5.1718808 , 4.94480104, 4.72769151, 4.52011448, 4.3216514 , 4.13190214, 3.9504841 , 3.77703149, 3.61119459, 3.45263901, 3.30104507, 3.1561071 , 3.01753287, 2.88504297, 2.75837025, 2.63725931, 2.52146595, 2.41075668, 2.30490829, 2.20370736, 2.10694982, 2.01444058, 1.92599312, 1.84142909, 1.76057799, 1.6832768 , 1.60936965, 1.53870751, 1.47114792, 1.40655465, 1.34479745, 1.28575181, 1.22929867, 1.17532421, 1.12371958, 1.07438074, 1.02720821, 0.98210687, 0.93898578, 0.897758 , 0.85834039, 0.82065349, 0.78462129, 0.75017114, 0.71723359, 0.68574222, 0.65563353, 0.62684681, 0.59932403, 0.57300967, 0.5478507 , 0.52379638, 0.5007982 , 0.47880979, 0.45778683, 0.43768691, 0.41846951, 0.40009589, 0.38252899, 0.3657334 , 0.34967525, 0.33432216, 0.31964317, 0.30560868, 0.29219041, 0.27936129, 0.26709545, 0.25536817, 0.24415579, 0.23343571, 0.22318631, 0.21338694, 0.20401782, 0.19506006, 0.18649562, 0.17830721, 0.17047832, 0.16299318, 0.15583668, 0.14899441, 0.14245255]) amplitudes, sigmas, norm = mge.mge_1d(rs, kappa, N=n_comp)
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, center_x=None, center_y=None, model_bool_list=None, n_comp=20): """ multi-gaussian lens model in convergence space :param kwargs_lens: :param n_comp: :return: """ center_x, center_y = analysis_util.profile_center(kwargs_lens, center_x, center_y) theta_E = self.effective_einstein_radius(kwargs_lens) r_array = np.logspace(-4, 2, 200) * theta_E kappa_s = self.radial_lens_profile(r_array, kwargs_lens, center_x=center_x, center_y=center_y, model_bool_list=model_bool_list) amplitudes, sigmas, norm = mge.mge_1d(r_array, kappa_s, N=n_comp) return amplitudes, sigmas, center_x, center_y
def mge_kernel(kernel, order=5): """ azimutal Multi-Gaussian expansion of a pixelized kernel :param kernel: 2d numpy array :return: """ # radial average n = len(kernel) center = (n - 1) / 2. psf_r = image_util.radial_profile(kernel, center=[center, center]) # MGE of radial average n_r = len(psf_r) r_array = np.linspace(start=0., stop=n_r - 1, num=n_r) amps, sigmas, norm = mge.mge_1d(r_array, psf_r, N=order, linspace=True) return amps, sigmas, norm
def multi_gaussian_decomposition(self, kwargs_light, model_bool_list=None, n_comp=20, center_x=None, center_y=None, r_h=None, grid_spacing=0.02, grid_num=200): """ multi-gaussian decomposition of the lens light profile (in 1-dimension) :param kwargs_light: keyword argument list of profiles :param center_x: center of profile, if None takes it from the first profile in kwargs_light :param center_y: center of profile, if None takes it from the first profile in kwargs_light :param model_bool_list: list of booleans to select subsets of the profile :param grid_spacing: grid spacing over which the moments are computed for the half-light radius :param grid_num: grid size over which the moments are computed :param n_comp: maximum number of Gaussian's in the MGE :param r_h: float, half light radius to be used for MGE (optional, otherwise using a numerical grid) :return: amplitudes, sigmas, center_x, center_y """ center_x, center_y = analysis_util.profile_center( kwargs_light, center_x, center_y) if r_h is None: r_h = self.half_light_radius(kwargs_light, center_x=center_x, center_y=center_y, model_bool_list=model_bool_list, grid_spacing=grid_spacing, grid_num=grid_num) r_array = np.logspace(-3, 2, 200) * r_h * 2 flux_r = self.radial_light_profile(r_array, kwargs_light, center_x=center_x, center_y=center_y, 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_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 test_mge_light_and_mass(self): # anisotropy profile anisotropy_model = 'OM' r_ani = 2. kwargs_anisotropy = {'r_ani': r_ani} # anisotropy radius [arcsec] # aperture as slit aperture_type = 'slit' length = 3.8 width = 0.9 kwargs_aperture = { 'length': length, 'width': width, 'center_ra': 0, 'center_dec': 0, 'angle': 0, 'aperture_type': aperture_type } psf_fwhm = 0.7 # Gaussian FWHM psf kwargs_cosmo = {'d_d': 1000, 'd_s': 1500, 'd_ds': 800} # light profile light_profile_list = ['HERNQUIST'] r_eff = 1.8 kwargs_light = [{ 'Rs': r_eff, 'amp': 1. }] # effective half light radius (2d projected) in arcsec # mass profile mass_profile_list = ['SPP'] theta_E = 1.2 gamma = 2. kwargs_profile = [{ 'theta_E': theta_E, 'gamma': gamma }] # Einstein radius (arcsec) and power-law slope # mge of light profile lightModel = LightModel(light_profile_list) r_array = np.logspace(-2, 2, 200) * r_eff * 2 flux_r = lightModel.surface_brightness(r_array, 0, kwargs_light) amps, sigmas, norm = mge.mge_1d(r_array, flux_r, N=20) light_profile_list_mge = ['MULTI_GAUSSIAN'] kwargs_light_mge = [{'amp': amps, 'sigma': sigmas}] # mge of lens profile lensModel = LensModel(mass_profile_list) r_array = np.logspace(-2, 2, 200) kappa_r = lensModel.kappa(r_array, 0, kwargs_profile) amps, sigmas, norm = mge.mge_1d(r_array, kappa_r, N=20) mass_profile_list_mge = ['MULTI_GAUSSIAN_KAPPA'] kwargs_profile_mge = [{'amp': amps, 'sigma': sigmas}] kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': psf_fwhm} kwargs_model = { 'mass_profile_list': mass_profile_list, 'light_profile_list': light_profile_list, 'anisotropy_model': anisotropy_model } kwargs_numerics = { 'interpol_grid_num': 100, 'log_integration': True, 'max_integrate': 100, 'min_integrate': 0.01 } galkin = Galkin(kwargs_model=kwargs_model, kwargs_psf=kwargs_psf, kwargs_cosmo=kwargs_cosmo, kwargs_aperture=kwargs_aperture, kwargs_numerics=kwargs_numerics) sigma_v = galkin.dispersion(kwargs_profile, kwargs_light, kwargs_anisotropy) kwargs_model_mge = { 'mass_profile_list': mass_profile_list_mge, 'light_profile_list': light_profile_list_mge, 'anisotropy_model': anisotropy_model } galkin = Galkin(kwargs_model=kwargs_model_mge, kwargs_psf=kwargs_psf, kwargs_cosmo=kwargs_cosmo, kwargs_aperture=kwargs_aperture, kwargs_numerics=kwargs_numerics) sigma_v2 = galkin.dispersion(kwargs_profile_mge, kwargs_light_mge, kwargs_anisotropy) print(sigma_v, sigma_v2, 'sigma_v Galkin, sigma_v MGEn') print((sigma_v / sigma_v2)**2) npt.assert_almost_equal((sigma_v - sigma_v2) / sigma_v2, 0, decimal=2)
def kinematic_profiles(self, kwargs_lens, kwargs_lens_light, r_eff, MGE_light=False, MGE_mass=False, lens_model_kinematics_bool=None, light_model_kinematics_bool=None, Hernquist_approx=False): """ translates the lenstronomy lens and mass profiles into a (sub) set of profiles that are compatible with the GalKin module to compute the kinematics thereof. :param kwargs_lens: lens model parameters :param kwargs_lens_light: lens light parameters :param r_eff: a rough estimate of the half light radius of the lens light in case of computing the MGE of the light profile :param MGE_light: bool, if true performs the MGE for the light distribution :param MGE_mass: bool, if true performs the MGE for the mass distribution :param lens_model_kinematics_bool: bool list of length of the lens model. Only takes a subset of all the models as part of the kinematics computation (can be used to ignore substructure, shear etc that do not describe the main deflector potential :param light_model_kinematics_bool: bool list of length of the light model. Only takes a subset of all the models as part of the kinematics computation (can be used to ignore light components that do not describe the main deflector :param Hernquist_approx: bool, if True, uses a Hernquist light profile matched to the half light radius of the deflector light profile to compute the kinematics :return: mass_profile_list, kwargs_profile, light_profile_list, kwargs_light """ mass_profile_list = [] kwargs_profile = [] if lens_model_kinematics_bool is None: lens_model_kinematics_bool = [True] * len(kwargs_lens) for i, lens_model in enumerate(self.kwargs_options['lens_model_list']): if lens_model_kinematics_bool[i] is True: mass_profile_list.append(lens_model) if lens_model in ['INTERPOL', 'INTERPOL_SCLAED']: center_x, center_y = self._lensModelExt.lens_center( kwargs_lens, k=i) kwargs_lens_i = copy.deepcopy(kwargs_lens[i]) kwargs_lens_i['grid_interp_x'] -= center_x kwargs_lens_i['grid_interp_y'] -= center_y else: kwargs_lens_i = { k: v for k, v in kwargs_lens[i].items() if not k in ['center_x', 'center_y'] } kwargs_profile.append(kwargs_lens_i) if MGE_mass is True: lensModel = LensModel(lens_model_list=mass_profile_list) massModel = LensModelExtensions(lensModel) theta_E = massModel.effective_einstein_radius(kwargs_profile) r_array = np.logspace(-4, 2, 200) * theta_E mass_r = lensModel.kappa(r_array, np.zeros_like(r_array), kwargs_profile) amps, sigmas, norm = mge.mge_1d(r_array, mass_r, N=20) mass_profile_list = ['MULTI_GAUSSIAN_KAPPA'] kwargs_profile = [{'amp': amps, 'sigma': sigmas}] light_profile_list = [] kwargs_light = [] if light_model_kinematics_bool is None: light_model_kinematics_bool = [True] * len(kwargs_lens_light) for i, light_model in enumerate( self.kwargs_options['lens_light_model_list']): if light_model_kinematics_bool[i]: light_profile_list.append(light_model) kwargs_lens_light_i = { k: v for k, v in kwargs_lens_light[i].items() if not k in ['center_x', 'center_y'] } if 'e1' in kwargs_lens_light_i: kwargs_lens_light_i['e1'] = 0 kwargs_lens_light_i['e2'] = 0 kwargs_light.append(kwargs_lens_light_i) if Hernquist_approx is True: light_profile_list = ['HERNQUIST'] kwargs_light = [{'Rs': r_eff, 'amp': 1.}] else: if MGE_light is True: lightModel = LightModel(light_profile_list) r_array = np.logspace(-3, 2, 200) * r_eff * 2 flux_r = lightModel.surface_brightness(r_array, 0, kwargs_light) amps, sigmas, norm = mge.mge_1d(r_array, flux_r, N=20) light_profile_list = ['MULTI_GAUSSIAN'] kwargs_light = [{'amp': amps, 'sigma': sigmas}] return mass_profile_list, kwargs_profile, light_profile_list, kwargs_light
def kinematic_lens_profiles(self, kwargs_lens, MGE_fit=False, model_kinematics_bool=None, theta_E=None, gamma=None, kwargs_mge=None, analytic_kinematics=False): """ translates the lenstronomy lens and mass profiles into a (sub) set of profiles that are compatible with the GalKin module to compute the kinematics thereof. The requirement is that the profiles are centered at (0, 0) and that for all profile types there exists a 3d de-projected analytical representation. :param kwargs_lens: lens model parameters :param MGE_fit: bool, if true performs the MGE for the mass distribution :param model_kinematics_bool: bool list of length of the lens model. Only takes a subset of all the models as part of the kinematics computation (can be used to ignore substructure, shear etc that do not describe the main deflector potential :param theta_E: (optional float) estimate of the Einstein radius. If present, does not numerically compute this quantity in this routine numerically :param gamma: local power-law slope at the Einstein radius (optional) :param kwargs_mge: keyword arguments that go into the MGE decomposition routine :param analytic_kinematics: bool, if True, solves the Jeans equation analytically for the power-law mass profile with Hernquist light profile :return: mass_profile_list, keyword argument list """ if analytic_kinematics is True: if gamma is None or theta_E is None: raise ValueError( 'power-law slope and Einstein radius must be set to allow for analytic kinematics to ' 'be computed!') return None, {'theta_E': theta_E, 'gamma': gamma} mass_profile_list = [] kwargs_profile = [] if model_kinematics_bool is None: model_kinematics_bool = [True] * len(kwargs_lens) for i, lens_model in enumerate(self._lens_model_list): if model_kinematics_bool[i] is True: mass_profile_list.append(lens_model) if lens_model in ['INTERPOL', 'INTERPOL_SCLAED']: center_x_i, center_y_i = self._lensMassProfile.convergence_peak( kwargs_lens, model_bool_list=i, grid_num=200, grid_spacing=0.01, center_x_init=0, center_y_init=0) kwargs_lens_i = copy.deepcopy(kwargs_lens[i]) kwargs_lens_i['grid_interp_x'] -= center_x_i kwargs_lens_i['grid_interp_y'] -= center_y_i else: kwargs_lens_i = { k: v for k, v in kwargs_lens[i].items() if not k in ['center_x', 'center_y'] } kwargs_profile.append(kwargs_lens_i) if MGE_fit is True: if kwargs_mge is None: raise ValueError('kwargs_mge needs to be specified!') if theta_E is None: raise ValueError( 'rough estimate of the Einstein radius needs to be provided to compute the MGE!' ) r_array = np.logspace(-4, 2, 200) * theta_E if self._lens_model_list[0] in ['INTERPOL', 'INTERPOL_SCLAED']: center_x, center_y = self._lensMassProfile.convergence_peak( kwargs_lens, model_bool_list=model_kinematics_bool, grid_num=200, grid_spacing=0.01, center_x_init=0, center_y_init=0) else: center_x, center_y = None, None mass_r = self._lensMassProfile.radial_lens_profile( r_array, kwargs_lens, center_x=center_x, center_y=center_y, model_bool_list=model_kinematics_bool) amps, sigmas, norm = mge.mge_1d(r_array, mass_r, N=kwargs_mge.get('n_comp', 20)) mass_profile_list = ['MULTI_GAUSSIAN_KAPPA'] kwargs_profile = [{'amp': amps, 'sigma': sigmas}] return mass_profile_list, kwargs_profile
def velocity_dispersion_numerical(self, kwargs_lens, kwargs_lens_light, kwargs_anisotropy, kwargs_aperture, psf_fwhm, aperture_type, anisotropy_model, r_eff=None, kwargs_numerics={}, MGE_light=False, MGE_mass=False, lens_model_kinematics_bool=None, light_model_kinematics_bool=None, Hernquist_approx=False): """ Computes the LOS velocity dispersion of the deflector galaxy with arbitrary combinations of light and mass models. For a detailed description, visit the description of the Galkin() class. Additionaly to executing the Galkin routine, it has an optional Multi-Gaussian-Expansion decomposition of lens and light models that do not have a three-dimensional distribution built in, such as Sersic profiles etc. The center of all the lens and lens light models that are part of the kinematic estimate must be centered on the same point. :param kwargs_lens: lens model parameters :param kwargs_lens_light: lens light parameters :param kwargs_anisotropy: anisotropy parameters (see Galkin module) :param kwargs_aperture: aperture parameters (see Galkin module) :param psf_fwhm: full width at half maximum of the seeing (Gaussian form) :param aperture_type: type of aperture (see Galkin module :param anisotropy_model: stellar anisotropy model (see Galkin module) :param r_eff: a rough estimate of the half light radius of the lens light in case of computing the MGE of the light profile :param kwargs_numerics: keyword arguments that contain numerical options (see Galkin module) :param MGE_light: bool, if true performs the MGE for the light distribution :param MGE_mass: bool, if true performs the MGE for the mass distribution :param lens_model_kinematics_bool: bool list of length of the lens model. Only takes a subset of all the models as part of the kinematics computation (can be used to ignore substructure, shear etc that do not describe the main deflector potential :param light_model_kinematics_bool: bool list of length of the light model. Only takes a subset of all the models as part of the kinematics computation (can be used to ignore light components that do not describe the main deflector :return: LOS velocity dispersion [km/s] """ kwargs_cosmo = { 'D_d': self.lensCosmo.D_d, 'D_s': self.lensCosmo.D_s, 'D_ds': self.lensCosmo.D_ds } mass_profile_list = [] kwargs_profile = [] if lens_model_kinematics_bool is None: lens_model_kinematics_bool = [True] * len(kwargs_lens) for i, lens_model in enumerate(self.kwargs_options['lens_model_list']): if lens_model_kinematics_bool[i] is True: mass_profile_list.append(lens_model) if lens_model in ['INTERPOL', 'INTERPOL_SCLAED']: center_x, center_y = self._lensModelExt.lens_center( kwargs_lens, k=i) kwargs_lens_i = copy.deepcopy(kwargs_lens[i]) kwargs_lens_i['grid_interp_x'] -= center_x kwargs_lens_i['grid_interp_y'] -= center_y else: kwargs_lens_i = { k: v for k, v in kwargs_lens[i].items() if not k in ['center_x', 'center_y'] } kwargs_profile.append(kwargs_lens_i) if MGE_mass is True: lensModel = LensModel(lens_model_list=mass_profile_list) massModel = LensModelExtensions(lensModel) theta_E = massModel.effective_einstein_radius(kwargs_profile) r_array = np.logspace(-4, 2, 200) * theta_E mass_r = lensModel.kappa(r_array, np.zeros_like(r_array), kwargs_profile) amps, sigmas, norm = mge.mge_1d(r_array, mass_r, N=20) mass_profile_list = ['MULTI_GAUSSIAN_KAPPA'] kwargs_profile = [{'amp': amps, 'sigma': sigmas}] light_profile_list = [] kwargs_light = [] if light_model_kinematics_bool is None: light_model_kinematics_bool = [True] * len(kwargs_lens_light) for i, light_model in enumerate( self.kwargs_options['lens_light_model_list']): if light_model_kinematics_bool[i]: light_profile_list.append(light_model) kwargs_lens_light_i = { k: v for k, v in kwargs_lens_light[i].items() if not k in ['center_x', 'center_y'] } if 'q' in kwargs_lens_light_i: kwargs_lens_light_i['q'] = 1 kwargs_light.append(kwargs_lens_light_i) if r_eff is None: lensAnalysis = LensAnalysis( {'lens_light_model_list': light_profile_list}) r_eff = lensAnalysis.half_light_radius_lens( kwargs_light, model_bool_list=light_model_kinematics_bool) if Hernquist_approx is True: light_profile_list = ['HERNQUIST'] kwargs_light = [{'Rs': r_eff, 'amp': 1.}] else: if MGE_light is True: lightModel = LightModel(light_profile_list) r_array = np.logspace(-3, 2, 200) * r_eff * 2 flux_r = lightModel.surface_brightness(r_array, 0, kwargs_light) amps, sigmas, norm = mge.mge_1d(r_array, flux_r, N=20) light_profile_list = ['MULTI_GAUSSIAN'] kwargs_light = [{'amp': amps, 'sigma': sigmas}] galkin = Galkin(mass_profile_list, light_profile_list, aperture_type=aperture_type, anisotropy_model=anisotropy_model, fwhm=psf_fwhm, kwargs_cosmo=kwargs_cosmo, **kwargs_numerics) sigma2 = galkin.vel_disp(kwargs_profile, kwargs_light, kwargs_anisotropy, kwargs_aperture) return sigma2
def velocity_disperson_numerical(self, kwargs_lens, kwargs_lens_light, kwargs_anisotropy, kwargs_aperture, psf_fwhm, aperture_type, anisotropy_model, r_eff=1., kwargs_numerics={}, MGE_light=False, MGE_mass=False): """ :param kwargs_lens: :param kwargs_lens_light: :param kwargs_anisotropy: :param kwargs_aperature: :return: """ kwargs_cosmo = { 'D_d': self.lensCosmo.D_d, 'D_s': self.lensCosmo.D_s, 'D_ds': self.lensCosmo.D_ds } mass_profile_list = [] kwargs_profile = [] lens_model_internal_bool = self.kwargs_options.get( 'lens_model_deflector_bool', [True] * len(kwargs_lens)) for i, lens_model in enumerate(self.kwargs_options['lens_model_list']): if lens_model_internal_bool[i]: mass_profile_list.append(lens_model) kwargs_lens_i = { k: v for k, v in kwargs_lens[i].items() if not k in ['center_x', 'center_y'] } kwargs_profile.append(kwargs_lens_i) if MGE_mass is True: massModel = LensModelExtensions(lens_model_list=mass_profile_list) theta_E = massModel.effective_einstein_radius(kwargs_lens) r_array = np.logspace(-4, 2, 200) * theta_E mass_r = massModel.kappa(r_array, 0, kwargs_profile) amps, sigmas, norm = mge.mge_1d(r_array, mass_r, N=20) mass_profile_list = ['MULTI_GAUSSIAN_KAPPA'] kwargs_profile = [{'amp': amps, 'sigma': sigmas}] light_profile_list = [] kwargs_light = [] lens_light_model_internal_bool = self.kwargs_options.get( 'light_model_deflector_bool', [True] * len(kwargs_lens_light)) for i, light_model in enumerate( self.kwargs_options['lens_light_model_list']): if lens_light_model_internal_bool[i]: light_profile_list.append(light_model) kwargs_Lens_light_i = { k: v for k, v in kwargs_lens_light[i].items() if not k in ['center_x', 'center_y'] } if 'q' in kwargs_Lens_light_i: kwargs_Lens_light_i['q'] = 1 kwargs_light.append(kwargs_Lens_light_i) if MGE_light is True: lightModel = LightModel(light_profile_list) r_array = np.logspace(-3, 2, 200) * r_eff * 2 flux_r = lightModel.surface_brightness(r_array, 0, kwargs_light) amps, sigmas, norm = mge.mge_1d(r_array, flux_r, N=20) light_profile_list = ['MULTI_GAUSSIAN'] kwargs_light = [{'amp': amps, 'sigma': sigmas}] galkin = Galkin(mass_profile_list, light_profile_list, aperture_type=aperture_type, anisotropy_model=anisotropy_model, fwhm=psf_fwhm, kwargs_cosmo=kwargs_cosmo, kwargs_numerics=kwargs_numerics) sigma_v = galkin.vel_disp(kwargs_profile, kwargs_light, kwargs_anisotropy, kwargs_aperture, r_eff=r_eff) return sigma_v
def test_mge_power_law_lens(self): """ compare power-law profiles analytical vs. numerical :return: """ # anisotropy profile anisotropy_type = 'OsipkovMerritt' r_ani = 2. kwargs_anisotropy = {'r_ani': r_ani} # anisotropy radius [arcsec] # aperture as slit aperture_type = 'slit' length = 3.8 width = 0.9 kwargs_aperture = { 'length': length, 'width': width, 'center_ra': 0, 'center_dec': 0, 'angle': 0, 'aperture_type': aperture_type } psf_fwhm = 0.7 # Gaussian FWHM psf kwargs_cosmo = {'D_d': 1000, 'D_s': 1500, 'D_ds': 800} # light profile light_profile_list = ['HERNQUIST'] r_eff = 1.8 kwargs_light = [{ 'Rs': r_eff, 'amp': 1. }] # effective half light radius (2d projected) in arcsec # mass profile mass_profile_list = ['SPP'] theta_E = 1.2 gamma = 2. kwargs_profile = [{ 'theta_E': theta_E, 'gamma': gamma }] # Einstein radius (arcsec) and power-law slope # mge of lens profile lensModel = LensModel(mass_profile_list) r_array = np.logspace(-2, 1, 100) * theta_E kappa_r = lensModel.kappa(r_array, 0, kwargs_profile) amps, sigmas, norm = mge.mge_1d(r_array, kappa_r, N=20) mass_profile_list_mge = ['MULTI_GAUSSIAN_KAPPA'] kwargs_profile_mge = [{'amp': amps, 'sigma': sigmas}] kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': psf_fwhm} galkin = Galkin(mass_profile_list, light_profile_list, anisotropy_model=anisotropy_type, kwargs_psf=kwargs_psf, kwargs_cosmo=kwargs_cosmo, kwargs_aperture=kwargs_aperture) sigma_v = galkin.vel_disp(kwargs_profile, kwargs_light, kwargs_anisotropy) galkin = Galkin(mass_profile_list_mge, light_profile_list, anisotropy_model=anisotropy_type, kwargs_psf=kwargs_psf, kwargs_cosmo=kwargs_cosmo, kwargs_aperture=kwargs_aperture) sigma_v2 = galkin.vel_disp(kwargs_profile_mge, kwargs_light, kwargs_anisotropy) print(sigma_v, sigma_v2, 'sigma_v Galkin, sigma_v MGEn') print((sigma_v / sigma_v2)**2) npt.assert_almost_equal((sigma_v - sigma_v2) / sigma_v2, 0, decimal=2)