Source code for lenstronomy.Analysis.light_profile

import copy
import numpy as np
import lenstronomy.Util.util as util
import lenstronomy.Util.analysis_util as analysis_util
import lenstronomy.Util.multi_gauss_expansion as mge

__all__ = ['LightProfileAnalysis']


[docs]class LightProfileAnalysis(object): """ class with analysis routines to compute derived properties of the lens model """ def __init__(self, light_model): """ :param light_model: LightModel instance """ self._light_model = light_model
[docs] def ellipticity(self, kwargs_light, grid_spacing, grid_num, center_x=None, center_y=None, model_bool_list=None): """ make sure that the window covers all the light, otherwise the moments may give a too low answers. :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 :param grid_num: grid size over which the moments are computed :return: eccentricities e1, e2 """ center_x, center_y = analysis_util.profile_center(kwargs_light, center_x, center_y) if model_bool_list is None: model_bool_list = [True] * len(kwargs_light) x_grid, y_grid = util.make_grid(numPix=grid_num, deltapix=grid_spacing) x_grid += center_x y_grid += center_y I_xy = self._light_model.surface_brightness(x_grid, y_grid, kwargs_light, k=model_bool_list) e1, e2 = analysis_util.ellipticities(I_xy, x_grid-center_x, y_grid-center_y) return e1, e2
[docs] def half_light_radius(self, kwargs_light, grid_spacing, grid_num, center_x=None, center_y=None, model_bool_list=None): """ computes numerically the half-light-radius of the deflector light and the total photon flux :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 :param grid_num: grid size over which the moments are computed :return: half-light radius """ center_x, center_y = analysis_util.profile_center(kwargs_light, center_x, center_y) if model_bool_list is None: model_bool_list = [True] * len(kwargs_light) x_grid, y_grid = util.make_grid(numPix=grid_num, deltapix=grid_spacing) x_grid += center_x y_grid += center_y lens_light = self._light_model.surface_brightness(x_grid, y_grid, kwargs_light, k=model_bool_list) R_h = analysis_util.half_light_radius(lens_light, x_grid, y_grid, center_x, center_y) return R_h
[docs] def radial_light_profile(self, r_list, kwargs_light, center_x=None, center_y=None, model_bool_list=None): """ :param r_list: list of radii to compute the spherically averaged lens light profile :param center_x: center of the profile :param center_y: center of the profile :param kwargs_light: lens light parameter keyword argument list :param model_bool_list: bool list or None, indicating which profiles to sum over :return: flux amplitudes at r_list radii spherically averaged """ center_x, center_y = analysis_util.profile_center(kwargs_light, center_x, center_y) f_list = [] for r in r_list: x, y = util.points_on_circle(r, num_points=20) f_r = self._light_model.surface_brightness(x + center_x, y + center_y, kwargs_list=kwargs_light, k=model_bool_list) f_list.append(np.average(f_r)) return f_list
[docs] def multi_gaussian_decomposition(self, kwargs_light, grid_spacing=0.01, grid_num=100, model_bool_list=None, n_comp=20, center_x=None, center_y=None): """ 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 :param grid_num: grid size over which the moments are computed :param n_comp: maximum number of Gaussian's in the MGE :return: amplitudes, sigmas, center_x, center_y """ center_x, center_y = analysis_util.profile_center(kwargs_light, center_x, center_y) 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
[docs] def multi_gaussian_decomposition_ellipse(self, kwargs_light, model_bool_list=None, center_x=None, center_y=None, grid_num=100, grid_spacing=0.05, n_comp=20): """ MGE with ellipticity estimate. Attention: numerical grid settings for ellipticity estimate and radial MGE may not necessarily be the same! :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 :param grid_num: grid size over which the moments are computed :param n_comp: maximum number of Gaussians in the MGE :return: keyword arguments of the elliptical multi Gaussian profile in lenstronomy conventions """ # estimate center center_x, center_y = analysis_util.profile_center(kwargs_light, center_x, center_y) e1, e2 = self.ellipticity(kwargs_light, center_x=center_x, center_y=center_y, model_bool_list=model_bool_list, grid_spacing=grid_spacing * 2, grid_num=grid_num) # MGE around major axis amplitudes, sigmas, center_x, center_y = self.multi_gaussian_decomposition(kwargs_light, model_bool_list=model_bool_list, n_comp=n_comp, grid_spacing=grid_spacing, grid_num=grid_num, center_x=center_x, center_y=center_y) kwargs_mge = {'amp': amplitudes, 'sigma': sigmas, 'center_x': center_x, 'center_y': center_y} kwargs_mge['e1'] = e1 kwargs_mge['e2'] = e2 return kwargs_mge
[docs] def flux_components(self, kwargs_light, grid_num=400, grid_spacing=0.01): """ computes the total flux in each component of the model :param kwargs_light: :param grid_num: :param grid_spacing: :return: """ flux_list = [] R_h_list = [] x_grid, y_grid = util.make_grid(numPix=grid_num, deltapix=grid_spacing) 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 light = self._light_model.surface_brightness(x_grid, y_grid, kwargs_copy, k=k) flux = np.sum(light) * grid_spacing ** 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