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
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
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
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