Beispiel #1
0
    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
Beispiel #2
0
    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
Beispiel #3
0
    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
Beispiel #4
0
    def mst_invariant_differential(self,
                                   kwargs_lens,
                                   radius,
                                   center_x=None,
                                   center_y=None,
                                   model_list_bool=None,
                                   num_points=10):
        """
        Average of the radial stretch differential in radial direction, divided by the radial stretch factor.

        .. math::
            \\xi = \\frac{\\partial \\lambda_{\\rm rad}}{\\partial r} \\frac{1}{\\lambda_{\\rm rad}}

        This quantity is invariant under the MST.
        The specific definition is provided by Birrer 2021. Equivalent (proportional) definitions are provided by e.g.
        Kochanek 2020, Sonnenfeld 2018.

        :param kwargs_lens: lens model keyword argument list
        :param radius: radius from the center where to compute the MST invariant differential
        :param center_x: center position
        :param center_y: center position
        :param model_list_bool: indicate which part of the model to consider
        :param num_points: number of estimates around the radius
        :return: xi
        """
        center_x, center_y = analysis_util.profile_center(
            kwargs_lens, center_x, center_y)
        x, y = util.points_on_circle(radius, num_points)
        ext = LensModelExtensions(lensModel=self._lens_model)
        lambda_rad, lambda_tan, orientation_angle, dlambda_tan_dtan, dlambda_tan_drad, dlambda_rad_drad, dlambda_rad_dtan, dphi_tan_dtan, dphi_tan_drad, dphi_rad_drad, dphi_rad_dtan = ext.radial_tangential_differentials(
            x, y, kwargs_lens, center_x=center_x, center_y=center_y)
        xi = np.mean(dlambda_rad_drad / lambda_rad)
        return xi
Beispiel #5
0
    def effective_einstein_radius(self, kwargs_lens, center_x=None, center_y=None, model_bool_list=None, grid_num=200,
                                  grid_spacing=0.05, get_precision=False, verbose=True):
        """
        computes the radius with mean convergence=1

        :param kwargs_lens: list of lens model keyword arguments
        :param spacing: number of annular bins to compute the convergence (resolution of the Einstein radius estimate)
        :param get_precision: If `True`, return the precision of estimated Einstein radius
        :return: estimate of the Einstein radius
        """
        center_x, center_y = analysis_util.profile_center(kwargs_lens, center_x, center_y)

        x_grid, y_grid = util.make_grid(numPix=grid_num, deltapix=grid_spacing)
        x_grid += center_x
        y_grid += center_y
        kappa = self._lens_model.kappa(x_grid, y_grid, kwargs_lens, k=model_bool_list)
        if self._lens_model.lens_model_list[0] in ['INTERPOL', 'INTERPOL_SCALED']:
            center_x = x_grid[kappa == np.max(kappa)][0]
            center_y = y_grid[kappa == np.max(kappa)][0]
        #kappa = util.array2image(kappa)
        r_array = np.linspace(0, grid_num*grid_spacing/2., grid_num*2)
        for r in r_array:
            mask = np.array(1 - mask_util.mask_center_2d(center_x, center_y, r, x_grid, y_grid))
            sum_mask = np.sum(mask)
            if sum_mask > 0:
                kappa_mean = np.sum(kappa*mask)/np.sum(mask)
                if kappa_mean < 1:
                    if get_precision:
                        return r, r_array[1] - r_array[0]
                    else:
                        return r
        if verbose:
            Warning("No Einstein radius computed for the following model!", kwargs_lens)
        return np.nan
Beispiel #6
0
    def profile_slope(self,
                      kwargs_lens,
                      radius,
                      center_x=None,
                      center_y=None,
                      model_list_bool=None,
                      num_points=10):
        """
        computes the logarithmic power-law slope of a profile. ATTENTION: this is not an observable!

        :param kwargs_lens: lens model keyword argument list
        :param radius: radius from the center where to compute the logarithmic slope (angular units
        :param model_list_bool: bool list, indicate which part of the model to consider
        :param num_points: number of estimates around the Einstein radius
        :return: logarithmic power-law slope
        """
        center_x, center_y = analysis_util.profile_center(
            kwargs_lens, center_x, center_y)
        x, y = util.points_on_circle(radius, num_points)
        dr = 0.01
        x_dr, y_dr = util.points_on_circle(radius + dr, num_points)

        alpha_E_x_i, alpha_E_y_i = self._lens_model.alpha(center_x + x,
                                                          center_y + y,
                                                          kwargs_lens,
                                                          k=model_list_bool)
        alpha_E_r = np.sqrt(alpha_E_x_i**2 + alpha_E_y_i**2)
        alpha_E_dr_x_i, alpha_E_dr_y_i = self._lens_model.alpha(
            center_x + x_dr, center_y + y_dr, kwargs_lens, k=model_list_bool)
        alpha_E_dr = np.sqrt(alpha_E_dr_x_i**2 + alpha_E_dr_y_i**2)
        slope = np.mean(
            np.log(alpha_E_dr / alpha_E_r) / np.log((radius + dr) / radius))
        gamma = -slope + 2
        return gamma
Beispiel #7
0
    def effective_einstein_radius(self,
                                  kwargs_lens,
                                  center_x=None,
                                  center_y=None,
                                  model_bool_list=None,
                                  grid_num=200,
                                  grid_spacing=0.05,
                                  get_precision=False,
                                  verbose=True):
        """
        computes the radius with mean convergence=1

        :param kwargs_lens: list of lens model keyword arguments
        :param center_x: position of the center (if not set, is attempting to find it from the parameters kwargs_lens)
        :param center_y: position of the center (if not set, is attempting to find it from the parameters kwargs_lens)
        :param model_bool_list: list of booleans indicating the addition (=True) of a model component in computing the
         Einstein radius
        :param grid_num: integer, number of grid points to numerically evaluate the convergence and estimate the
         Einstein radius
        :param grid_spacing: spacing in angular units of the grid
        :param get_precision: If `True`, return the precision of estimated Einstein radius
        :param verbose: boolean, if True prints warning if indication of insufficient result
        :return: estimate of the Einstein radius
        """
        center_x, center_y = analysis_util.profile_center(
            kwargs_lens, center_x, center_y)

        x_grid, y_grid = util.make_grid(numPix=grid_num, deltapix=grid_spacing)
        x_grid += center_x
        y_grid += center_y
        kappa = self._lens_model.kappa(x_grid,
                                       y_grid,
                                       kwargs_lens,
                                       k=model_bool_list)
        if self._lens_model.lens_model_list[0] in [
                'INTERPOL', 'INTERPOL_SCALED'
        ]:
            center_x = x_grid[kappa == np.max(kappa)][0]
            center_y = y_grid[kappa == np.max(kappa)][0]
        #kappa = util.array2image(kappa)
        r_array = np.linspace(0, grid_num * grid_spacing / 2., grid_num * 2)
        for r in r_array:
            mask = np.array(1 - mask_util.mask_center_2d(
                center_x, center_y, r, x_grid, y_grid))
            sum_mask = np.sum(mask)
            if sum_mask > 0:
                kappa_mean = np.sum(kappa * mask) / np.sum(mask)
                if kappa_mean < 1:
                    if get_precision:
                        return r, r_array[1] - r_array[0]
                    else:
                        return r
        if verbose:
            Warning("No Einstein radius computed for the following model!",
                    kwargs_lens)
        return np.nan
Beispiel #8
0
    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
Beispiel #9
0
    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
Beispiel #10
0
    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
Beispiel #11
0
 def test_raise(self):
     with self.assertRaises(ValueError):
         kwargs_list = [{}]
         analysis_util.profile_center(kwargs_list=kwargs_list)
Beispiel #12
0
 def test_profile_center(self):
     kwargs_list = [{'center_x': 1, 'center_y': 0}]
     center_x, center_y = analysis_util.profile_center(
         kwargs_list=kwargs_list)
     assert center_x == 1
     assert center_y == 0