Ejemplo n.º 1
0
    def test_radial_profile(self):
        Rs = 1.
        kwargs_light = [{'Rs': Rs, 'amp': 1., 'center_x': 0, 'center_y': 0}]
        kwargs_options = {'light_model_list': ['HERNQUIST']}
        lightModel = LightModel(**kwargs_options)
        profile = LightProfileAnalysis(light_model=lightModel)
        r_list = np.linspace(start=0.01, stop=10, num=10)
        I_r = profile.radial_light_profile(r_list,
                                           kwargs_light,
                                           center_x=None,
                                           center_y=None,
                                           model_bool_list=None)
        I_r_true = lightModel.surface_brightness(r_list, 0, kwargs_light)
        npt.assert_almost_equal(I_r, I_r_true, decimal=5)

        # test off-center
        Rs = 1.
        kwargs_light = [{'Rs': Rs, 'amp': 1., 'center_x': 1., 'center_y': 0}]
        kwargs_options = {'light_model_list': ['HERNQUIST']}
        lightModel = LightModel(**kwargs_options)
        profile = LightProfileAnalysis(light_model=lightModel)
        r_list = np.linspace(start=0.01, stop=10, num=10)
        I_r = profile.radial_light_profile(r_list,
                                           kwargs_light,
                                           center_x=None,
                                           center_y=None,
                                           model_bool_list=None)
        I_r_true = lightModel.surface_brightness(r_list + 1, 0, kwargs_light)
        npt.assert_almost_equal(I_r, I_r_true, decimal=5)
Ejemplo n.º 2
0
    def test_merge_low_high_res(self):
        subpixel_x, subpixel_y = self._adaptive_grid._high_res_coordinates
        x, y = self._adaptive_grid._x_low_res, self._adaptive_grid._x_low_res
        model = LightModel(light_model_list=['GAUSSIAN'])
        kwargs_light = [{
            'center_x': 0,
            'center_y': 0,
            'sigma_x': 1,
            'sigma_y': 1,
            'amp': 1
        }]
        subgrid_values = model.surface_brightness(subpixel_x, subpixel_y,
                                                  kwargs_light)
        image1d = model.surface_brightness(x, y, kwargs_light)

        image_added = self._adaptive_grid._merge_low_high_res(
            image1d, subgrid_values)
        added_array = util.image2array(image_added)
        supersampled_values = self._adaptive_grid._average_subgrid(
            subgrid_values)
        assert added_array[util.image2array(
            self._supersampling_indexes)] == supersampled_values

        image_high_res = self._adaptive_grid._high_res_image(subgrid_values)
        assert len(image_high_res) == self.nx * self._supersampling_factor
Ejemplo n.º 3
0
class TestLightModel(object):
    """
    tests the source model routines
    """

    def setup(self):
        self.light_model_list = ['GAUSSIAN', 'MULTI_GAUSSIAN', 'SERSIC', 'SERSIC_ELLIPSE', 'DOUBLE_SERSIC',
                                 'CORE_SERSIC', 'DOUBLE_CORE_SERSIC', 'BULDGE_DISK', 'SHAPELETS', 'HERNQUIST',
                                 'HERNQUIST_ELLIPSE', 'PJAFFE', 'PJAFFE_ELLIPSE', 'UNIFORM', 'NONE'
                                 ]
        self.kwargs = [
            {'amp': 1., 'sigma_x': 1, 'sigma_y': 1., 'center_x': 0, 'center_y': 0},  # 'GAUSSIAN'
            {'amp': [1., 2], 'sigma': [1, 3], 'center_x': 0, 'center_y': 0},  # 'MULTI_GAUSSIAN'
            {'I0_sersic': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'center_x': 0, 'center_y': 0},  # 'SERSIC'
            {'I0_sersic': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'q': 0.8, 'phi_G': 0.5, 'center_x': 0, 'center_y': 0},  # 'SERSIC_ELLIPSE'
            {'I0_sersic': 1, 'R_sersic': 0.5, 'n_sersic': 1, 'q': 0.8, 'phi_G': 0.5, 'center_x': 0, 'center_y': 0,
             'I0_2': 1, 'R_2': 0.05, 'n_2': 2, 'phi_G_2': 0, 'q_2': 1},  # 'DOUBLE_SERSIC'
            {'I0_sersic': 1, 'R_sersic': 0.5, 'Re': 0.1, 'gamma': 2., 'n_sersic': 1, 'q': 0.8, 'phi_G': 0.5, 'center_x': 0, 'center_y': 0},
            # 'CORE_SERSIC'
            {'I0_sersic': 1, 'R_sersic': 0.5, 'Re': 0.1, 'gamma': 2., 'n_sersic': 1, 'q': 0.8, 'phi_G': 0.5,
             'center_x': 0, 'center_y': 0, 'I0_2': 1, 'R_2': 0.05, 'n_2': 2, 'phi_G_2': 0, 'q_2': 1},
            # 'DOUBLE_CORE_SERSIC'
            {'I0_b': 1, 'R_b': 0.1, 'phi_G_b': 0, 'q_b': 1, 'I0_d': 2, 'R_d': 1, 'phi_G_d': 0.5, 'q_d': 0.7, 'center_x': 0, 'center_y': 0},  # BULDGE_DISK
            {'amp': [1, 1, 1], 'beta': 0.5, 'n_max': 1, 'center_x': 0, 'center_y': 0},  # 'SHAPELETS'
            {'sigma0': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0},  # 'HERNQUIST'
            {'sigma0': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'q': 0.8, 'phi_G': 0},  # 'HERNQUIST_ELLIPSE'
            {'sigma0': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0},  # 'PJAFFE'
            {'sigma0': 1, 'Ra': 1, 'Rs': 0.5, 'center_x': 0, 'center_y': 0, 'q': 0.8, 'phi_G': 0},  # 'PJAFFE_ELLIPSE'
            {'mean': 1},  # 'UNIFORM'
            {}]# 'NONE'

        self.LightModel = LightModel(light_model_list=self.light_model_list)

    def test_init(self):
        model_list = ['CORE_SERSIC', 'DOUBLE_CORE_SERSIC', 'BULDGE_DISK', 'SHAPELETS', 'UNIFORM']
        lightModel = LightModel(light_model_list=model_list)
        assert len(lightModel.profile_type_list) == len(model_list)

    def test_surface_brightness(self):
        output = self.LightModel.surface_brightness(x=1, y=1, kwargs_list=self.kwargs)
        npt.assert_almost_equal(output, 2.544428612985992, decimal=6)

    def test_surface_brightness_array(self):
        output = self.LightModel.surface_brightness(x=[1], y=[1], kwargs_list=self.kwargs)
        npt.assert_almost_equal(output[0], 2.544428612985992, decimal=6)

    def test_functions_split(self):
        output = self.LightModel.functions_split(x=1., y=1., kwargs_list=self.kwargs)
        assert output[0][0] == 0.058549831524319168

    def test_re_normalize_flux(self):
        kwargs_out = self.LightModel.re_normalize_flux(kwargs_list=self.kwargs, norm_factor=2)
        assert kwargs_out[0]['amp'] == 2 * self.kwargs[0]['amp']
Ejemplo n.º 4
0
    def test_multi_gaussian_decomposition_ellipse(self):
        Rs = 1.
        kwargs_light = [{'Rs': Rs, 'amp': 1., 'center_x': 0, 'center_y': 0}]
        kwargs_options = {'light_model_list': ['HERNQUIST']}
        lightModel = LightModel(**kwargs_options)
        profile = LightProfileAnalysis(light_model=lightModel)

        kwargs_mge = profile.multi_gaussian_decomposition_ellipse(
            kwargs_light,
            grid_spacing=0.01,
            grid_num=100,
            model_bool_list=None,
            n_comp=20,
            center_x=None,
            center_y=None)
        mge = MultiGaussianEllipse()
        r_array = np.logspace(start=-2, stop=0.5, num=10)
        flux = mge.function(r_array, 0, **kwargs_mge)
        flux_true = lightModel.surface_brightness(r_array, 0, kwargs_light)
        npt.assert_almost_equal(flux / flux_true, 1, decimal=2)

        # elliptic

        Rs = 1.
        kwargs_light = [{
            'Rs': Rs,
            'amp': 1.,
            'e1': 0.1,
            'e2': 0,
            'center_x': 0,
            'center_y': 0
        }]
        kwargs_options = {'light_model_list': ['HERNQUIST_ELLIPSE']}
        lightModel = LightModel(**kwargs_options)
        profile = LightProfileAnalysis(light_model=lightModel)

        kwargs_mge = profile.multi_gaussian_decomposition_ellipse(
            kwargs_light,
            grid_spacing=0.1,
            grid_num=400,
            model_bool_list=None,
            n_comp=20,
            center_x=None,
            center_y=None)

        print(kwargs_mge['e1'])
        mge = MultiGaussianEllipse()
        r_array = np.logspace(start=-2, stop=0.5, num=10)
        flux = mge.function(r_array, 0, **kwargs_mge)
        flux_true = lightModel.surface_brightness(r_array, 0, kwargs_light)

        npt.assert_almost_equal(flux / flux_true, 1, decimal=1)
Ejemplo n.º 5
0
    def test_derivatives(self):
        kwargs_arc = {
            'tangential_stretch': 3,
            #'radial_stretch': 1.,
            'curvature': 0.8,
            'direction': 0,
            'center_x': 0,
            'center_y': 0
        }

        kwargs_arc_sis = {
            'tangential_stretch': 3,
            'radial_stretch': 1.,
            'curvature': 0.8,
            'direction': 0,
            'center_x': 0,
            'center_y': 0
        }
        x, y = util.make_grid(numPix=100, deltapix=0.01)
        f_x_sis, f_y_sis = self.arc_sis.derivatives(x, y, **kwargs_arc_sis)
        beta_x_sis = x - f_x_sis
        beta_y_sis = y - f_y_sis
        f_x_const, f_y_const = self.arc_const.derivatives(x, y, **kwargs_arc)
        beta_x_const = x - f_x_const
        beta_y_const = y - f_y_const

        from lenstronomy.LightModel.light_model import LightModel
        gauss = LightModel(['GAUSSIAN'])
        kwargs_source = [{
            'amp': 1,
            'sigma': 0.05,
            'center_x': 0,
            'center_y': 0
        }]
        flux_sis = gauss.surface_brightness(beta_x_sis, beta_y_sis,
                                            kwargs_source)
        flux_const = gauss.surface_brightness(beta_x_const, beta_y_const,
                                              kwargs_source)

        npt.assert_almost_equal((flux_const - flux_sis) / np.max(flux_const),
                                0,
                                decimal=2)

        # check for stability outside the defined bounds of curvature
        f_x_const, f_y_const = self.arc_const.derivatives(x=0,
                                                          y=1000,
                                                          **kwargs_arc)
        npt.assert_almost_equal(f_x_const, 0)
        npt.assert_almost_equal(f_y_const, 0)
Ejemplo n.º 6
0
    def setup(self):
        lightModel = LightModel(light_model_list=['GAUSSIAN'])
        self.delta_pix = 1
        self.num_pix = 10
        self.num_pix_kernel = 7
        x, y = util.make_grid(numPix=self.num_pix_kernel, deltapix=self.delta_pix)
        kwargs_kernel = [{'amp': 1, 'sigma': 3, 'center_x': 0, 'center_y': 0}]
        kernel = lightModel.surface_brightness(x, y, kwargs_kernel)
        self.kernel = util.array2image(kernel)
        self.kernel /= np.sum(self.kernel)

        x, y = util.make_grid(numPix=self.num_pix, deltapix=self.delta_pix)
        kwargs = [{'amp': 1, 'sigma': 2, 'center_x': 0, 'center_y': 0}]
        flux = lightModel.surface_brightness(x, y, kwargs)
        self.model = util.array2image(flux)
Ejemplo n.º 7
0
    def source_flux_rh(self, kwargs_result, deltaPix_s, numPix):
        """
        A function to calculate flux, half light radius of the given modeling result.
        :param kwargs_results: modeling result
        :param deltaPix: pixel scale in the source plane
        :param numPix: pixel numbers in the source plane
        :return: flux (cts/s) and R_e (") in the source plane
        """
        imageModel = class_creator.create_im_sim(
            self.multi_band_list,
            multi_band_type='single-band',
            kwargs_model=self.kwargs_model,
            bands_compute=[True],
            band_index=0)
        kwargs_source = kwargs_result['kwargs_source']
        _, _, _, _ = imageModel.image_linear_solve(inv_bool=True,
                                                   **kwargs_result)

        x_center = kwargs_source[0]['center_x']
        y_center = kwargs_source[0]['center_y']
        x_grid_source, y_grid_source = util.make_grid(numPix=numPix,
                                                      deltapix=deltaPix_s)
        x_grid_source += x_center
        y_grid_source += y_center
        source_light_model = self.kwargs_model['source_light_model_list']
        lightModel = LightModel(light_model_list=source_light_model)
        flux = lightModel.surface_brightness(x_grid_source, y_grid_source,
                                             kwargs_source) * deltaPix_s**2
        rh = half_light_radius(flux, x_grid_source, y_grid_source, x_center,
                               y_center)
        return flux, rh
Ejemplo n.º 8
0
 def test_flux_array2image_low_high(self):
     x, y = self._adaptive_grid.coordinates_evaluate
     model = LightModel(light_model_list=['GAUSSIAN'])
     kwargs_light = [{'center_x': 0, 'center_y': 0, 'sigma': 1, 'amp': 1}]
     flux_values = model.surface_brightness(x, y, kwargs_light)
     image_low_res, image_high_res = self._adaptive_grid.flux_array2image_low_high(flux_values)
     assert len(image_high_res) == self.nx * self._supersampling_factor
Ejemplo n.º 9
0
 def test_average_subgrid(self):
     subpixel_x, subpixel_y = self._adaptive_grid._high_res_coordinates
     model = LightModel(light_model_list=['GAUSSIAN'])
     kwargs_light = [{'center_x': 0, 'center_y': 0, 'sigma': 1, 'amp': 1}]
     subgrid_values = model.surface_brightness(subpixel_x, subpixel_y, kwargs_light)
     supersampled_values = self._adaptive_grid._average_subgrid(subgrid_values)
     assert len(supersampled_values) == 1
Ejemplo n.º 10
0
    def test_delete_interpol_caches(self):
        x, y = util.make_grid(numPix=20, deltapix=1.)
        gauss = Gaussian()
        flux = gauss.function(x, y, amp=1., center_x=0., center_y=0., sigma=1.)
        image = util.array2image(flux)

        light_model_list = ['INTERPOL', 'INTERPOL']
        kwargs_list = [{
            'image': image,
            'scale': 1,
            'phi_G': 0,
            'center_x': 0,
            'center_y': 0
        }, {
            'image': image,
            'scale': 1,
            'phi_G': 0,
            'center_x': 0,
            'center_y': 0
        }]
        lightModel = LightModel(light_model_list=light_model_list)
        output = lightModel.surface_brightness(x, y, kwargs_list)
        for func in lightModel.func_list:
            assert hasattr(func, '_image_interp')
        lightModel.delete_interpol_caches()
        for func in lightModel.func_list:
            assert not hasattr(func, '_image_interp')
    def test_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)
Ejemplo n.º 12
0
 def setup(self):
     lightModel = LightModel(light_model_list=['GAUSSIAN'])
     self.delta_pix = 1
     x, y = util.make_grid(10, deltapix=self.delta_pix)
     kwargs = [{'amp': 1, 'sigma': 2, 'center_x': 0, 'center_y': 0}]
     flux = lightModel.surface_brightness(x, y, kwargs)
     self.model = util.array2image(flux)
Ejemplo n.º 13
0
    def test_spt_mapping(self):

        e1, e2 = 0.1, -0.2

        kwargs_arc_sis_mst = {
            'tangential_stretch': 3,
            'radial_stretch': 1.2,
            'curvature': 0.8,
            'direction': 0,
            'center_x': 0,
            'center_y': 0
        }

        # inverse reduced shear transform as SPT
        kwargs_arc_spt = copy.deepcopy(kwargs_arc_sis_mst)
        kwargs_arc_spt['gamma1'] = -e1
        kwargs_arc_spt['gamma2'] = -e2

        x, y = util.make_grid(numPix=100, deltapix=0.01)
        f_x_sis, f_y_sis = self._curve_regular.derivatives(
            x, y, **kwargs_arc_sis_mst)
        beta_x_sis = x - f_x_sis
        beta_y_sis = y - f_y_sis
        f_x_spt, f_y_spt = self._curve_spt.derivatives(x, y, **kwargs_arc_spt)
        beta_x_spt = x - f_x_spt
        beta_y_spt = y - f_y_spt

        from lenstronomy.LightModel.light_model import LightModel
        gauss = LightModel(['GAUSSIAN_ELLIPSE'])
        kwargs_source = [{
            'amp': 1,
            'sigma': 0.05,
            'center_x': 0,
            'center_y': 0,
            'e1': 0,
            'e2': 0
        }]
        kwargs_source_spt = copy.deepcopy(kwargs_source)
        kwargs_source_spt[0]['e1'] = e1
        kwargs_source_spt[0]['e2'] = e2
        flux_sis = gauss.surface_brightness(beta_x_sis, beta_y_sis,
                                            kwargs_source)
        flux_spt = gauss.surface_brightness(beta_x_spt, beta_y_spt,
                                            kwargs_source_spt)
        npt.assert_almost_equal(flux_sis, flux_spt)
Ejemplo n.º 14
0
    def setup(self):
        self.supersampling_factor = 3
        lightModel = LightModel(light_model_list=['GAUSSIAN'])
        self.delta_pix = 1.
        x, y = util.make_grid(20, deltapix=self.delta_pix)
        x_sub, y_sub = util.make_grid(20*self.supersampling_factor, deltapix=self.delta_pix/self.supersampling_factor)
        kwargs = [{'amp': 1, 'sigma': 2, 'center_x': 0, 'center_y': 0}]
        flux = lightModel.surface_brightness(x, y, kwargs)
        self.model = util.array2image(flux)
        flux_sub = lightModel.surface_brightness(x_sub, y_sub, kwargs)
        self.model_sub = util.array2image(flux_sub)

        x, y = util.make_grid(5, deltapix=self.delta_pix)
        kwargs_kernel = [{'amp': 1, 'sigma': 1, 'center_x': 0, 'center_y': 0}]
        kernel = lightModel.surface_brightness(x, y, kwargs_kernel)
        self.kernel = util.array2image(kernel) / np.sum(kernel)

        x_sub, y_sub = util.make_grid(5*self.supersampling_factor, deltapix=self.delta_pix/self.supersampling_factor)
        kernel_sub = lightModel.surface_brightness(x_sub, y_sub, kwargs_kernel)
        self.kernel_sub = util.array2image(kernel_sub) / np.sum(kernel_sub)
    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)
Ejemplo n.º 16
0
    def setup(self):
        lightModel = LightModel(light_model_list=['GAUSSIAN'])
        self.supersampling_factor = 3
        self.delta_pix = 1
        self.num_pix = 10
        self.num_pix_kernel = 7
        x, y = util.make_grid(numPix=self.num_pix_kernel, deltapix=self.delta_pix)
        kwargs_kernel = [{'amp': 1, 'sigma': 3, 'center_x': 0, 'center_y': 0}]
        kernel = lightModel.surface_brightness(x, y, kwargs_kernel)
        self.kernel = util.array2image(kernel)
        self.kernel /= np.sum(self.kernel)

        x_sub, y_sub = util.make_grid(numPix=self.num_pix_kernel, deltapix=self.delta_pix, subgrid_res=self.supersampling_factor)
        kernel_super = lightModel.surface_brightness(x_sub, y_sub, kwargs_kernel)
        self.kernel_super = util.array2image(kernel_super)
        self.kernel_super /= np.sum(self.kernel_super)

        x_sub, y_sub = util.make_grid(numPix=self.num_pix, deltapix=self.delta_pix, subgrid_res=self.supersampling_factor)
        kwargs = [{'amp': 1, 'sigma': 2, 'center_x': 0, 'center_y': 0}]
        flux = lightModel.surface_brightness(x_sub, y_sub, kwargs)
        self.model_super = util.array2image(flux)
        self.model = image_util.re_size(self.model_super, factor=self.supersampling_factor)
Ejemplo n.º 17
0
    def test_multi_gaussian_decomposition(self):
        Rs = 1.
        kwargs_light = [{'Rs': Rs, 'amp': 1., 'center_x': 0, 'center_y': 0}]
        kwargs_options = {'light_model_list': ['HERNQUIST']}
        lightModel = LightModel(**kwargs_options)
        profile = LightProfileAnalysis(light_model=lightModel)

        amplitudes, sigmas, center_x, center_y = profile.multi_gaussian_decomposition(kwargs_light, grid_spacing=0.01, grid_num=100, model_bool_list=None, n_comp=20,
                                                                                      center_x=None, center_y=None)
        mge = MultiGaussian()
        r_array = np.logspace(start=-2, stop=0.5, num=10)
        print(r_array, 'test r_array')
        flux = mge.function(r_array, 0, amp=amplitudes, sigma=sigmas, center_x=center_x, center_y=center_y)
        flux_true = lightModel.surface_brightness(r_array, 0, kwargs_light)
        npt.assert_almost_equal(flux / flux_true, 1, decimal=2)

        # test off-center

        Rs = 1.
        offset = 1.
        kwargs_light = [{'Rs': Rs, 'amp': 1., 'center_x': offset, 'center_y': 0}]
        kwargs_options = {'light_model_list': ['HERNQUIST']}
        lightModel = LightModel(**kwargs_options)
        profile = LightProfileAnalysis(light_model=lightModel)

        amplitudes, sigmas, center_x, center_y = profile.multi_gaussian_decomposition(kwargs_light, grid_spacing=0.01,
                                                                                      grid_num=100, model_bool_list=None,
                                                                                      n_comp=20,
                                                                                      center_x=None, center_y=None)
        assert center_x == offset
        assert center_y == 0
        mge = MultiGaussian()
        r_array = np.logspace(start=-2, stop=0.5, num=10)
        print(r_array, 'test r_array')
        flux = mge.function(r_array, 0, amp=amplitudes, sigma=sigmas, center_x=center_x, center_y=center_y)
        flux_true = lightModel.surface_brightness(r_array, 0, kwargs_light)
        npt.assert_almost_equal(flux / flux_true, 1, decimal=2)

        """
Ejemplo n.º 18
0
 def source_plane(self, kwargs_options, kwargs_source, numPix, deltaPix):
     """
     source plane simulation
     :param kwargs_options:
     :param kwargs_source:
     :param numPix:
     :param deltaPix:
     :return:
     """
     x, y = util.make_grid(numPix, deltaPix)
     sourceModel = LightModel(kwargs_options.get('source_light_model_list', ['NONE']))
     image1d = sourceModel.surface_brightness(x, y, kwargs_source)
     image2d = util.array2image(image1d)
     return image2d
Ejemplo n.º 19
0
class DifferentialExtinction(object):
    """
    class to compute an extinction (for a specific band/wavelength). This class uses the functionality available in
    the LightModel module to describe an optical depth tau_ext to compute the extinction on the sky/image.
    """
    def __init__(self, optical_depth_model=None, tau0_index=0):
        """

        :param optical_depth_model: list of strings naming the profiles (same convention as LightModel module)
         describing the optical depth of the extinction
        """
        if optical_depth_model is None:
            optical_depth_model = []
        self._profile = LightModel(light_model_list=optical_depth_model)
        if len(optical_depth_model) == 0:
            self._compute_bool = False
        else:
            self._compute_bool = True
        self._tau0_index = tau0_index

    @property
    def compute_bool(self):
        """
        :return: True when a differential extinction is set, False otherwise 
        """
        return self._compute_bool

    def extinction(self, x, y, kwargs_extinction=None, kwargs_special=None):
        """

        :param x: coordinate in image plane of flux intensity
        :param y: coordinate in image plane of flux intensity
        :param kwargs_extinction: keyword argument list matching the extinction profile
        :param kwargs_special: keyword arguments hosting special parameters, here required 'tau0_list'
        :return: extinction corrected flux
        """
        if self._compute_bool is False or kwargs_extinction is None:
            return 1
        tau = self._profile.surface_brightness(x,
                                               y,
                                               kwargs_list=kwargs_extinction)
        tau0_list = kwargs_special.get('tau0_list', None)
        if tau0_list is not None:
            tau0 = tau0_list[self._tau0_index]
        else:
            tau0 = 1
        return np.exp(-tau0 * tau)
Ejemplo n.º 20
0
    def test_light2mass_conversion(self):
        numPix = 100
        deltaPix = 0.05

        lightModel = LightModel(light_model_list=['SERSIC_ELLIPSE', 'SERSIC'])
        kwargs_lens_light = [{
            'R_sersic': 0.5,
            'n_sersic': 4,
            'amp': 2,
            'e1': 0,
            'e2': 0.05
        }, {
            'R_sersic': 1.5,
            'n_sersic': 1,
            'amp': 2
        }]

        kwargs_interpol = light2mass.light2mass_interpol(
            lens_light_model_list=['SERSIC_ELLIPSE', 'SERSIC'],
            kwargs_lens_light=kwargs_lens_light,
            numPix=numPix,
            deltaPix=deltaPix,
            subgrid_res=1)
        from lenstronomy.LensModel.lens_model import LensModel
        lensModel = LensModel(lens_model_list=['INTERPOL_SCALED'])
        kwargs_lens = [kwargs_interpol]
        import lenstronomy.Util.util as util
        x_grid, y_grid = util.make_grid(numPix, deltapix=deltaPix)
        kappa = lensModel.kappa(x_grid, y_grid, kwargs=kwargs_lens)
        kappa = util.array2image(kappa)
        kappa /= np.mean(kappa)
        flux = lightModel.surface_brightness(x_grid, y_grid, kwargs_lens_light)
        flux = util.array2image(flux)
        flux /= np.mean(flux)
        # import matplotlib.pyplot as plt
        # plt.matshow(flux-kappa)
        # plt.colorbar()
        # plt.show()
        delta_kappa = (kappa - flux) / flux
        max_delta = np.max(np.abs(delta_kappa))
        assert max_delta < 1
        # assert max_diff < 0.01
        npt.assert_almost_equal(flux[0, 0], kappa[0, 0], decimal=2)
Ejemplo n.º 21
0
    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
Ejemplo n.º 22
0
class TestLightModel(object):
    """
    tests the source model routines
    """
    def setup(self):
        self.light_model_list = [
            'GAUSSIAN', 'MULTI_GAUSSIAN', 'SERSIC', 'SERSIC_ELLIPSE',
            'CORE_SERSIC', 'SHAPELETS', 'HERNQUIST', 'HERNQUIST_ELLIPSE',
            'PJAFFE', 'PJAFFE_ELLIPSE', 'UNIFORM', 'POWER_LAW', 'NIE',
            'INTERPOL', 'SHAPELETS_POLAR_EXP', 'ELLIPSOID'
        ]
        phi_G, q = 0.5, 0.8
        e1, e2 = param_util.phi_q2_ellipticity(phi_G, q)
        self.kwargs = [
            {
                'amp': 1.,
                'sigma': 1.,
                'center_x': 0,
                'center_y': 0
            },  # 'GAUSSIAN'
            {
                'amp': [1., 2],
                'sigma': [1, 3],
                'center_x': 0,
                'center_y': 0
            },  # 'MULTI_GAUSSIAN'
            {
                'amp': 1,
                'R_sersic': 0.5,
                'n_sersic': 1,
                'center_x': 0,
                'center_y': 0
            },  # 'SERSIC'
            {
                'amp': 1,
                'R_sersic': 0.5,
                'n_sersic': 1,
                'e1': e1,
                'e2': e2,
                'center_x': 0,
                'center_y': 0
            },  # 'SERSIC_ELLIPSE'
            {
                'amp': 1,
                'R_sersic': 0.5,
                'Rb': 0.1,
                'gamma': 2.,
                'n_sersic': 1,
                'e1': e1,
                'e2': e2,
                'center_x': 0,
                'center_y': 0
            },
            # 'CORE_SERSIC'
            {
                'amp': [1, 1, 1],
                'beta': 0.5,
                'n_max': 1,
                'center_x': 0,
                'center_y': 0
            },  # 'SHAPELETS'
            {
                'amp': 1,
                'Rs': 0.5,
                'center_x': 0,
                'center_y': 0
            },  # 'HERNQUIST'
            {
                'amp': 1,
                'Rs': 0.5,
                'center_x': 0,
                'center_y': 0,
                'e1': e1,
                'e2': e2
            },  # 'HERNQUIST_ELLIPSE'
            {
                'amp': 1,
                'Ra': 1,
                'Rs': 0.5,
                'center_x': 0,
                'center_y': 0
            },  # 'PJAFFE'
            {
                'amp': 1,
                'Ra': 1,
                'Rs': 0.5,
                'center_x': 0,
                'center_y': 0,
                'e1': e1,
                'e2': e2
            },  # 'PJAFFE_ELLIPSE'
            {
                'amp': 1
            },  # 'UNIFORM'
            {
                'amp': 1.,
                'gamma': 2.,
                'e1': e1,
                'e2': e2,
                'center_x': 0,
                'center_y': 0
            },  # 'POWER_LAW'
            {
                'amp': .001,
                'e1': 0,
                'e2': 1.,
                'center_x': 0,
                'center_y': 0,
                's_scale': 1.
            },  # 'NIE'
            {
                'image': np.zeros((20, 5)),
                'scale': 1,
                'phi_G': 0,
                'center_x': 0,
                'center_y': 0
            },
            {
                'amp': [1],
                'n_max': 0,
                'beta': 1,
                'center_x': 0,
                'center_y': 0
            },
            {
                'amp': 1,
                'radius': 1.,
                'e1': 0,
                'e2': 0.1,
                'center_x': 0,
                'center_y': 0
            }  # 'ELLIPSOID'
        ]

        self.LightModel = LightModel(light_model_list=self.light_model_list)

    def test_init(self):
        model_list = [
            'CORE_SERSIC', 'SHAPELETS', 'SHAPELETS_POLAR',
            'SHAPELETS_POLAR_EXP', 'UNIFORM', 'CHAMELEON', 'DOUBLE_CHAMELEON',
            'TRIPLE_CHAMELEON'
        ]
        lightModel = LightModel(light_model_list=model_list)
        assert len(lightModel.profile_type_list) == len(model_list)

    def test_surface_brightness(self):
        output = self.LightModel.surface_brightness(x=1.,
                                                    y=1.,
                                                    kwargs_list=self.kwargs)
        npt.assert_almost_equal(output, 2.5886852663397137, decimal=6)

    def test_surface_brightness_array(self):
        output = self.LightModel.surface_brightness(x=[1],
                                                    y=[1],
                                                    kwargs_list=self.kwargs)
        npt.assert_almost_equal(output[0], 2.5886852663397137, decimal=6)

    def test_functions_split(self):
        output = self.LightModel.functions_split(x=1.,
                                                 y=1.,
                                                 kwargs_list=self.kwargs)
        npt.assert_almost_equal(output[0][0], 0.058549831524319168, decimal=6)

    def test_param_name_list(self):
        param_name_list = self.LightModel.param_name_list
        assert len(self.light_model_list) == len(param_name_list)

    def test_num_param_linear(self):
        num = self.LightModel.num_param_linear(self.kwargs, list_return=False)
        assert num == 19

        num_list = self.LightModel.num_param_linear(self.kwargs,
                                                    list_return=True)
        assert num_list[0] == 1

    def test_update_linear(self):
        response, n = self.LightModel.functions_split(1, 1, self.kwargs)
        param = np.ones(n) * 2
        kwargs_out, i = self.LightModel.update_linear(param,
                                                      i=0,
                                                      kwargs_list=self.kwargs)
        assert i == n
        assert kwargs_out[0]['amp'] == 2

    def test_total_flux(self):
        light_model_list = [
            'SERSIC', 'SERSIC_ELLIPSE', 'INTERPOL', 'GAUSSIAN',
            'GAUSSIAN_ELLIPSE', 'MULTI_GAUSSIAN', 'MULTI_GAUSSIAN_ELLIPSE'
        ]
        kwargs_list = [
            {
                'amp': 1,
                'R_sersic': 0.5,
                'n_sersic': 1,
                'center_x': 0,
                'center_y': 0
            },  # 'SERSIC'
            {
                'amp': 1,
                'R_sersic': 0.5,
                'n_sersic': 1,
                'e1': 0.1,
                'e2': 0,
                'center_x': 0,
                'center_y': 0
            },  # 'SERSIC_ELLIPSE'
            {
                'image': np.ones((20, 5)),
                'scale': 1,
                'phi_G': 0,
                'center_x': 0,
                'center_y': 0
            },  # 'INTERPOL'
            {
                'amp': 2,
                'sigma': 2,
                'center_x': 0,
                'center_y': 0
            },  # 'GAUSSIAN'
            {
                'amp': 2,
                'sigma': 2,
                'e1': 0.1,
                'e2': 0,
                'center_x': 0,
                'center_y': 0
            },  # 'GAUSSIAN_ELLIPSE'
            {
                'amp': [1, 1],
                'sigma': [2, 1],
                'center_x': 0,
                'center_y': 0
            },  # 'MULTI_GAUSSIAN'
            {
                'amp': [1, 1],
                'sigma': [2, 1],
                'e1': 0.1,
                'e2': 0,
                'center_x': 0,
                'center_y': 0
            }  # 'MULTI_GAUSSIAN_ELLIPSE'
        ]
        lightModel = LightModel(light_model_list=light_model_list)
        total_flux_list = lightModel.total_flux(kwargs_list)
        assert total_flux_list[2] == 100
        assert total_flux_list[3] == 2
        assert total_flux_list[4] == 2
        assert total_flux_list[5] == 2
        assert total_flux_list[6] == 2

        total_flux_list = lightModel.total_flux(kwargs_list, norm=True)
        assert total_flux_list[2] == 100
        assert total_flux_list[3] == 1
        assert total_flux_list[4] == 1
        assert total_flux_list[5] == 2
        assert total_flux_list[6] == 2

    def test_delete_interpol_caches(self):
        x, y = util.make_grid(numPix=20, deltapix=1.)
        gauss = Gaussian()
        flux = gauss.function(x, y, amp=1., center_x=0., center_y=0., sigma=1.)
        image = util.array2image(flux)

        light_model_list = ['INTERPOL', 'INTERPOL']
        kwargs_list = [{
            'image': image,
            'scale': 1,
            'phi_G': 0,
            'center_x': 0,
            'center_y': 0
        }, {
            'image': image,
            'scale': 1,
            'phi_G': 0,
            'center_x': 0,
            'center_y': 0
        }]
        lightModel = LightModel(light_model_list=light_model_list)
        output = lightModel.surface_brightness(x, y, kwargs_list)
        for func in lightModel.func_list:
            assert hasattr(func, '_image_interp')
        lightModel.delete_interpol_caches()
        for func in lightModel.func_list:
            assert not hasattr(func, '_image_interp')

    def test_check_positive_flux_profile(self):
        ligthModel = LightModel(light_model_list=['GAUSSIAN'])
        kwargs_list = [{'amp': 0, 'sigma': 1}]
        bool = ligthModel.check_positive_flux_profile(kwargs_list)
        assert bool

        kwargs_list = [{'amp': -1, 'sigma': 1}]
        bool = ligthModel.check_positive_flux_profile(kwargs_list)
        assert not bool
Ejemplo n.º 23
0
class LightProfile(object):
    """
    class to deal with the light distribution
    """
    def __init__(self, profile_list=['HERNQUIST'], kwargs_numerics={}):
        """

        :param profile_list:
        """
        self.light_model = LightModel(light_model_list=profile_list,
                                      smoothing=0.000001)
        self._interp_grid_num = kwargs_numerics.get('interpol_grid_num', 1000)
        self._max_interpolate = kwargs_numerics.get('max_integrate', 100)
        self._min_interpolate = kwargs_numerics.get('min_integrate', 0.001)

    def light_3d(self, r, kwargs_list):
        """

        :param kwargs_list:
        :return:
        """
        light_3d = self.light_model.light_3d(r, kwargs_list)
        return light_3d

    def light_3d_interp(self, r, kwargs_list, new_compute=False):
        """

        :param kwargs_list:
        :return:
        """
        if not hasattr(self, '_f_light_3d') or new_compute is True:
            r_array = np.logspace(np.log10(self._min_interpolate),
                                  np.log10(self._max_interpolate),
                                  self._interp_grid_num)
            light_3d_array = self.light_model.light_3d(r_array, kwargs_list)
            light_3d_array[light_3d_array < 10**(-100)] = 10**(-100)
            f = interp1d(np.log(r_array),
                         np.log(light_3d_array),
                         fill_value="extrapolate")
            self._f_light_3d = f
        return np.exp(self._f_light_3d(np.log(r)))

    def light_2d(self, R, kwargs_list):
        """

        :param R:
        :param kwargs_list:
        :return:
        """
        kwargs_list_copy = copy.deepcopy(kwargs_list)
        kwargs_list_new = []
        for kwargs in kwargs_list_copy:
            if 'e1' in kwargs:
                kwargs['e1'] = 0
            if 'e2' in kwargs:
                kwargs['e2'] = 0
            kwargs_list_new.append({
                k: v
                for k, v in kwargs.items()
                if not k in ['center_x', 'center_y']
            })
        return self.light_model.surface_brightness(R, 0, kwargs_list_new)

    def draw_light_2d_linear(self,
                             kwargs_list,
                             n=1,
                             new_compute=False,
                             r_eff=1.):
        """
        constructs the CDF and draws from it random realizations of projected radii R
        :param kwargs_list:
        :return:
        """
        if not hasattr(self, '_light_cdf') or new_compute is True:
            r_array = np.linspace(self._min_interpolate, self._max_interpolate,
                                  self._interp_grid_num)
            cum_sum = np.zeros_like(r_array)
            sum = 0
            for i, r in enumerate(r_array):
                if i == 0:
                    cum_sum[i] = 0
                else:
                    sum += self.light_2d(r, kwargs_list) * r
                    cum_sum[i] = copy.deepcopy(sum)
            cum_sum_norm = cum_sum / cum_sum[-1]
            f = interp1d(cum_sum_norm, r_array)
            self._light_cdf = f
        cdf_draw = np.random.uniform(0., 1, n)
        r_draw = self._light_cdf(cdf_draw)
        return r_draw

    def draw_light_2d(self, kwargs_list, n=1, new_compute=False):
        """
        constructs the CDF and draws from it random realizations of projected radii R
        :param kwargs_list:
        :return:
        """
        if not hasattr(self, '_light_cdf_log') or new_compute is True:
            r_array = np.logspace(np.log10(self._min_interpolate),
                                  np.log10(self._max_interpolate),
                                  self._interp_grid_num)
            cum_sum = np.zeros_like(r_array)
            sum = 0
            for i, r in enumerate(r_array):
                if i == 0:
                    cum_sum[i] = 0
                else:
                    sum += self.light_2d(r, kwargs_list) * r * r
                    cum_sum[i] = copy.deepcopy(sum)
            cum_sum_norm = cum_sum / cum_sum[-1]
            f = interp1d(cum_sum_norm, np.log(r_array))
            self._light_cdf_log = f
        cdf_draw = np.random.uniform(0., 1, n)
        r_log_draw = self._light_cdf_log(cdf_draw)
        return np.exp(r_log_draw)
Ejemplo n.º 24
0
class LightProfile(object):
    """
    class to deal with the light distribution for GalKin

    In particular, this class allows for:
     - (faster) interpolated calculation for a given profile (for a range that the Jeans equation is computed)
     - drawing 3d and 2d distributions from a given (spherical) profile
       (within bounds where the Jeans equation is expected to be accurate)
     - 2d projected profiles within the 3d integration range (truncated)

    """
    def __init__(self, profile_list, interpol_grid_num=2000, max_interpolate=1000, min_interpolate=0.001,
                 max_draw=None):
        """

        :param profile_list: list of light profiles for LightModel module (must support light_3d() functionalities)
        :param interpol_grid_num: int; number of interpolation steps (logarithmically between min and max value)
        :param max_interpolate: float; maximum interpolation of 3d light profile
        :param min_interpolate: float; minimum interpolate (and also drawing of light profile)
        :param max_draw: float; (optional) if set, draws up to this radius, else uses max_interpolate value
        """

        self.light_model = LightModel(light_model_list=profile_list)
        self._interp_grid_num = interpol_grid_num
        self._max_interpolate = max_interpolate
        self._min_interpolate = min_interpolate
        if max_draw is None:
            max_draw = max_interpolate
        self._max_draw = max_draw

    def light_3d(self, r, kwargs_list):
        """
        three-dimensional light profile

        :param r: 3d radius
        :param kwargs_list: list of keyword arguments of light profiles (see LightModule)
        :return: flux per 3d volume at radius r
        """
        light_3d = self.light_model.light_3d(r, kwargs_list)
        return light_3d

    def light_3d_interp(self, r, kwargs_list, new_compute=False):
        """
        interpolated three-dimensional light profile within bounds [min_interpolate, max_interpolate]
        in logarithmic units with interpol_grid_num numbers of interpolation steps

        :param r: 3d radius
        :param kwargs_list: list of keyword arguments of light profiles (see LightModule)
        :param new_compute: boolean, if True, re-computes the interpolation
         (becomes valid with updated kwargs_list argument)
        :return: flux per 3d volume at radius r
        """
        if not hasattr(self, '_f_light_3d') or new_compute is True:
            r_array = np.logspace(np.log10(self._min_interpolate), np.log10(self._max_interpolate), self._interp_grid_num)
            light_3d_array = self.light_model.light_3d(r_array, kwargs_list)
            light_3d_array[light_3d_array < 10 ** (-1000)] = 10 ** (-1000)
            f = interp1d(np.log(r_array), np.log(light_3d_array), fill_value=(np.log(light_3d_array[0]), -1000),
                         bounds_error=False)  # "extrapolate"
            self._f_light_3d = f
        return np.exp(self._f_light_3d(np.log(r)))

    def light_2d(self, R, kwargs_list):
        """
        projected light profile (integrated to infinity in the projected axis)

        :param R: projected 2d radius
        :param kwargs_list: list of keyword arguments of light profiles (see LightModule)
        :return: projected surface brightness
        """
        kwargs_light_circularized = self._circularize_kwargs(kwargs_list)
        return self.light_model.surface_brightness(R, 0, kwargs_light_circularized)

    def _circularize_kwargs(self, kwargs_list):
        """

        :param kwargs_list: list of keyword arguments of light profiles (see LightModule)
        :return: circularized arguments
        """
        # TODO make sure averaging is done azimuthally
        if not hasattr(self, '_kwargs_light_circularized'):
            kwargs_list_copy = copy.deepcopy(kwargs_list)
            kwargs_list_new = []
            for kwargs in kwargs_list_copy:
                if 'e1' in kwargs:
                    kwargs['e1'] = 0
                if 'e2' in kwargs:
                    kwargs['e2'] = 0
                kwargs_list_new.append({k: v for k, v in kwargs.items() if not k in ['center_x', 'center_y']})
            self._kwargs_light_circularized = kwargs_list_new
        return self._kwargs_light_circularized

    def _light_2d_finite_single(self, R, kwargs_list):
        """
        projected light profile (integrated to FINITE 3d boundaries from the max_interpolate)
        for a single float number of R

        :param R: projected 2d radius (between min_interpolate and max_interpolate)
        :param kwargs_list: list of keyword arguments of light profiles (see LightModule)
        :return: projected surface brightness
        """

        # here we perform a logarithmic integral
        stop = np.log10(np.maximum(np.sqrt(self._max_interpolate**2 - R**2), self._min_interpolate + 0.00001))
        x = np.logspace(start=np.log10(self._min_interpolate), stop=stop, num=self._interp_grid_num)
        r_array = np.sqrt(x**2 + R**2)
        flux_r = self.light_3d(r_array, kwargs_list)
        dlog_r = (np.log10(x[2]) - np.log10(x[1])) * np.log(10)
        flux_r *= dlog_r * x

        # linear integral
        #x = np.linspace(start=self._min_interpolate, stop=np.sqrt(self._max_interpolate ** 2 - R ** 2),
        #                num=self._interp_grid_num)
        #r_array = np.sqrt(x ** 2 + R ** 2)
        #dr = x[1] - x[0]
        #flux_r = self.light_3d(r_array + dr / 2, kwargs_circ)
        #dr = x[1] - x[0]
        #flux_r *= dr

        flux_R = np.sum(flux_r)
        # perform finite integral

        #out = integrate.quad(lambda x: self.light_3d(np.sqrt(R ** 2 + x ** 2), kwargs_circ), self._min_interpolate,
        #                     np.sqrt(self._max_interpolate**2 - R**2))
        #print(out_1, out, 'test')
        #flux_R = out[0]
        return flux_R * 2  # integral in both directions

    def light_2d_finite(self, R, kwargs_list):
        """
        projected light profile (integrated to FINITE 3d boundaries from the max_interpolate)

        :param R: projected 2d radius (between min_interpolate and max_interpolate
        :param kwargs_list: list of keyword arguments of light profiles (see LightModule)
        :return: projected surface brightness
        """

        kwargs_circ = self._circularize_kwargs(kwargs_list)
        n = len(np.atleast_1d(R))
        if n <= 1:
            return self._light_2d_finite_single(R, kwargs_circ)
        else:
            light_2d = np.zeros(n)
            for i, R_i in enumerate(R):
                light_2d[i] = self._light_2d_finite_single(R_i, kwargs_circ)
            return light_2d

    def draw_light_2d_linear(self, kwargs_list, n=1, new_compute=False):
        """
        constructs the CDF and draws from it random realizations of projected radii R
        The interpolation of the CDF is done in linear projected radius space

        :param kwargs_list: list of keyword arguments of light profiles (see LightModule)
        :param n: int; number of draws
        :param new_compute: boolean, if True, re-computes the interpolation
         (becomes valid with updated kwargs_list argument)
        :return: draw of projected radius for the given light profile distribution
        """
        if not hasattr(self, '_light_cdf') or new_compute is True:
            r_array = np.linspace(self._min_interpolate, self._max_draw, self._interp_grid_num)
            cum_sum = np.zeros_like(r_array)
            sum = 0
            for i, r in enumerate(r_array):
                if i == 0:
                    cum_sum[i] = 0
                else:
                    sum += self.light_2d(r, kwargs_list) * r
                    cum_sum[i] = copy.deepcopy(sum)
            cum_sum_norm = cum_sum/cum_sum[-1]
            f = interp1d(cum_sum_norm, r_array)
            self._light_cdf = f
        cdf_draw = np.random.uniform(0., 1, n)
        r_draw = self._light_cdf(cdf_draw)
        return r_draw

    def draw_light_2d(self, kwargs_list, n=1, new_compute=False):
        """
        constructs the CDF and draws from it random realizations of projected radii R
        CDF is constructed in logarithmic projected radius spacing

        :param kwargs_list: light model keyword argument list
        :param n: int, number of draws per functino call
        :param new_compute: re-computes the interpolated CDF
        :return: realization of projected radius following the distribution of the light model
        """
        if not hasattr(self, '_light_cdf_log') or new_compute is True:
            r_array = np.logspace(np.log10(self._min_interpolate), np.log10(self._max_draw), self._interp_grid_num)
            cum_sum = np.zeros_like(r_array)
            sum = 0
            for i, r in enumerate(r_array):
                if i == 0:
                    cum_sum[i] = 0
                else:
                    sum += self.light_2d(r, kwargs_list) * r * r
                    cum_sum[i] = copy.deepcopy(sum)
            cum_sum_norm = cum_sum/cum_sum[-1]
            f = interp1d(cum_sum_norm, np.log(r_array))
            self._light_cdf_log = f
        cdf_draw = np.random.uniform(0., 1, n)
        r_log_draw = self._light_cdf_log(cdf_draw)
        return np.exp(r_log_draw)

    def draw_light_3d(self, kwargs_list, n=1, new_compute=False):
        """
        constructs the CDF and draws from it random realizations of 3D radii r

        :param kwargs_list: light model keyword argument list
        :param n: int, number of draws per function call
        :param new_compute: re-computes the interpolated CDF
        :return: realization of projected radius following the distribution of the light model
        """
        if not hasattr(self, '_light_3d_cdf_log') or new_compute is True:
            r_array = np.logspace(np.log10(self._min_interpolate), np.log10(self._max_draw), self._interp_grid_num)
            dlog_r = np.log10(r_array[1]) - np.log10(r_array[0])
            r_array_int = np.logspace(np.log10(self._min_interpolate) + dlog_r / 2, np.log10(self._max_draw) + dlog_r / 2, self._interp_grid_num)
            cum_sum = np.zeros_like(r_array)
            sum = 0
            for i, r in enumerate(r_array_int[:-1]):
                #if i == 0:
                #    cum_sum[i] = 0
                #else:
                    sum += self.light_3d(r, kwargs_list) * r**2 * (r_array[i+1] - r_array[i])# * r
                    cum_sum[i+1] = copy.deepcopy(sum)
            cum_sum_norm = cum_sum/cum_sum[-1]
            f = interp1d(cum_sum_norm, np.log(r_array))
            self._light_3d_cdf_log = f
        cdf_draw = np.random.uniform(0., 1, n)
        r_log_draw = self._light_3d_cdf_log(cdf_draw)
        return np.exp(r_log_draw)

    def delete_cache(self):
        """
        deletes cached interpolation function of the CDF for a specific light profile

        :return: None
        """
        if hasattr(self, '_light_cdf_log'):
            del self._light_cdf_log
        if hasattr(self, '_light_cdf'):
            del self._light_cdf
        if hasattr(self, '_f_light_3d'):
            del self._f_light_3d
        if hasattr(self, '_kwargs_light_circularized'):
            del self._kwargs_light_circularized
Ejemplo n.º 25
0
    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
Ejemplo n.º 26
0
class TestLightModel(object):
    """
    tests the source model routines
    """
    def setup(self):
        self.light_model_list = [
            'GAUSSIAN', 'MULTI_GAUSSIAN', 'SERSIC', 'SERSIC_ELLIPSE',
            'CORE_SERSIC', 'SHAPELETS', 'HERNQUIST', 'HERNQUIST_ELLIPSE',
            'PJAFFE', 'PJAFFE_ELLIPSE', 'UNIFORM', 'POWER_LAW', 'NIE',
            'INTERPOL', 'SHAPELETS_POLAR_EXP'
        ]
        phi_G, q = 0.5, 0.8
        e1, e2 = param_util.phi_q2_ellipticity(phi_G, q)
        self.kwargs = [
            {
                'amp': 1.,
                'sigma_x': 1,
                'sigma_y': 1.,
                'center_x': 0,
                'center_y': 0
            },  # 'GAUSSIAN'
            {
                'amp': [1., 2],
                'sigma': [1, 3],
                'center_x': 0,
                'center_y': 0
            },  # 'MULTI_GAUSSIAN'
            {
                'amp': 1,
                'R_sersic': 0.5,
                'n_sersic': 1,
                'center_x': 0,
                'center_y': 0
            },  # 'SERSIC'
            {
                'amp': 1,
                'R_sersic': 0.5,
                'n_sersic': 1,
                'e1': e1,
                'e2': e2,
                'center_x': 0,
                'center_y': 0
            },  # 'SERSIC_ELLIPSE'
            {
                'amp': 1,
                'R_sersic': 0.5,
                'Re': 0.1,
                'gamma': 2.,
                'n_sersic': 1,
                'e1': e1,
                'e2': e2,
                'center_x': 0,
                'center_y': 0
            },
            # 'CORE_SERSIC'
            {
                'amp': [1, 1, 1],
                'beta': 0.5,
                'n_max': 1,
                'center_x': 0,
                'center_y': 0
            },  # 'SHAPELETS'
            {
                'amp': 1,
                'Rs': 0.5,
                'center_x': 0,
                'center_y': 0
            },  # 'HERNQUIST'
            {
                'amp': 1,
                'Rs': 0.5,
                'center_x': 0,
                'center_y': 0,
                'e1': e1,
                'e2': e2
            },  # 'HERNQUIST_ELLIPSE'
            {
                'amp': 1,
                'Ra': 1,
                'Rs': 0.5,
                'center_x': 0,
                'center_y': 0
            },  # 'PJAFFE'
            {
                'amp': 1,
                'Ra': 1,
                'Rs': 0.5,
                'center_x': 0,
                'center_y': 0,
                'e1': e1,
                'e2': e2
            },  # 'PJAFFE_ELLIPSE'
            {
                'amp': 1
            },  # 'UNIFORM'
            {
                'amp': 1.,
                'gamma': 2.,
                'e1': e1,
                'e2': e2,
                'center_x': 0,
                'center_y': 0
            },  # 'POWER_LAW'
            {
                'amp': .001,
                'e1': 0,
                'e2': 1.,
                'center_x': 0,
                'center_y': 0,
                's_scale': 1.
            },  # 'NIE'
            {
                'image': np.zeros((10, 10)),
                'scale': 1,
                'phi_G': 0,
                'center_x': 0,
                'center_y': 0
            },
            {
                'amp': [1],
                'n_max': 0,
                'beta': 1,
                'center_x': 0,
                'center_y': 0
            }
        ]

        self.LightModel = LightModel(light_model_list=self.light_model_list)

    def test_init(self):
        model_list = [
            'CORE_SERSIC', 'SHAPELETS', 'SHAPELETS_POLAR',
            'SHAPELETS_POLAR_EXP', 'UNIFORM', 'CHAMELEON', 'DOUBLE_CHAMELEON',
            'TRIPLE_CHAMELEON'
        ]
        lightModel = LightModel(light_model_list=model_list)
        assert len(lightModel.profile_type_list) == len(model_list)

    def test_surface_brightness(self):
        output = self.LightModel.surface_brightness(x=1,
                                                    y=1,
                                                    kwargs_list=self.kwargs)
        npt.assert_almost_equal(output, 3.7065728131855824, decimal=6)

    def test_surface_brightness_array(self):
        output = self.LightModel.surface_brightness(x=[1],
                                                    y=[1],
                                                    kwargs_list=self.kwargs)
        npt.assert_almost_equal(output[0], 3.7065728131855824, decimal=6)

    def test_functions_split(self):
        output = self.LightModel.functions_split(x=1.,
                                                 y=1.,
                                                 kwargs_list=self.kwargs)
        npt.assert_almost_equal(output[0][0], 0.058549831524319168, decimal=6)

    def test_re_normalize_flux(self):
        kwargs_out = self.LightModel.re_normalize_flux(kwargs_list=self.kwargs,
                                                       norm_factor=2)
        assert kwargs_out[0]['amp'] == 2 * self.kwargs[0]['amp']

    def test_param_name_list(self):
        param_name_list = self.LightModel.param_name_list()
        assert len(self.light_model_list) == len(param_name_list)

    def test_num_param_linear(self):
        num = self.LightModel.num_param_linear(self.kwargs, list_return=False)
        assert num == 18

        num_list = self.LightModel.num_param_linear(self.kwargs,
                                                    list_return=True)
        assert num_list[0] == 1

    def test_update_linear(self):
        response, n = self.LightModel.functions_split(1, 1, self.kwargs)
        param = np.ones(n) * 2
        kwargs_out, i = self.LightModel.update_linear(param,
                                                      i=0,
                                                      kwargs_list=self.kwargs)
        assert i == n
        assert kwargs_out[0]['amp'] == 2

    def test_total_flux(self):
        light_model_list = [
            'SERSIC', 'SERSIC_ELLIPSE', 'INTERPOL', 'GAUSSIAN',
            'GAUSSIAN_ELLIPSE', 'MULTI_GAUSSIAN', 'MULTI_GAUSSIAN_ELLIPSE'
        ]
        kwargs_list = [
            {
                'amp': 1,
                'R_sersic': 0.5,
                'n_sersic': 1,
                'center_x': 0,
                'center_y': 0
            },  # 'SERSIC'
            {
                'amp': 1,
                'R_sersic': 0.5,
                'n_sersic': 1,
                'e1': 0.1,
                'e2': 0,
                'center_x': 0,
                'center_y': 0
            },  # 'SERSIC_ELLIPSE'
            {
                'image': np.ones((10, 10)),
                'scale': 1,
                'phi_G': 0,
                'center_x': 0,
                'center_y': 0
            },  # 'INTERPOL'
            {
                'amp': 2,
                'sigma_x': 2,
                'sigma_y': 1,
                'center_x': 0,
                'center_y': 0
            },  # 'GAUSSIAN'
            {
                'amp': 2,
                'sigma': 2,
                'e1': 0.1,
                'e2': 0,
                'center_x': 0,
                'center_y': 0
            },  # 'GAUSSIAN_ELLIPSE'
            {
                'amp': [1, 1],
                'sigma': [2, 1],
                'center_x': 0,
                'center_y': 0
            },  # 'MULTI_GAUSSIAN'
            {
                'amp': [1, 1],
                'sigma': [2, 1],
                'e1': 0.1,
                'e2': 0,
                'center_x': 0,
                'center_y': 0
            }  # 'MULTI_GAUSSIAN_ELLIPSE'
        ]
        lightModel = LightModel(light_model_list=light_model_list)
        total_flux_list = lightModel.total_flux(kwargs_list)
        assert total_flux_list[2] == 100
        assert total_flux_list[3] == 2
        assert total_flux_list[4] == 2
        assert total_flux_list[5] == 2
        assert total_flux_list[6] == 2

        total_flux_list = lightModel.total_flux(kwargs_list, norm=True)
        assert total_flux_list[2] == 100
        assert total_flux_list[3] == 1
        assert total_flux_list[4] == 1
        assert total_flux_list[5] == 2
        assert total_flux_list[6] == 2
Ejemplo n.º 27
0
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 test_magnification_finite_adaptive(self):
        lens_model_list = ['EPL', 'SHEAR']
        z_source = 1.5
        kwargs_lens = [{
            'theta_E': 1.,
            'gamma': 2.,
            'e1': 0.02,
            'e2': -0.09,
            'center_x': 0,
            'center_y': 0
        }, {
            'gamma1': 0.01,
            'gamma2': 0.03
        }]

        lensmodel = LensModel(lens_model_list)
        extension = LensModelExtensions(lensmodel)
        solver = LensEquationSolver(lensmodel)
        source_x, source_y = 0.07, 0.03
        x_image, y_image = solver.findBrightImage(source_x, source_y,
                                                  kwargs_lens)

        source_fwhm_parsec = 40.

        pc_per_arcsec = 1000 / self.cosmo.arcsec_per_kpc_proper(z_source).value
        source_sigma = source_fwhm_parsec / pc_per_arcsec / 2.355

        grid_size = auto_raytracing_grid_size(source_fwhm_parsec)
        grid_resolution = auto_raytracing_grid_resolution(source_fwhm_parsec)
        # make this even higher resolution to show convergence
        grid_number = int(2 * grid_size / grid_resolution)
        window_size = 2 * grid_size

        mag_square_grid = extension.magnification_finite(
            x_image,
            y_image,
            kwargs_lens,
            source_sigma=source_sigma,
            grid_number=grid_number,
            window_size=window_size)
        flux_ratios_square_grid = mag_square_grid / max(mag_square_grid)

        mag_adaptive_grid = extension.magnification_finite_adaptive(
            x_image,
            y_image,
            source_x,
            source_y,
            kwargs_lens,
            source_fwhm_parsec,
            z_source,
            cosmo=self.cosmo)
        flux_ratios_adaptive_grid = mag_adaptive_grid / max(mag_adaptive_grid)

        mag_adaptive_grid_fixed_aperture_size = extension.magnification_finite_adaptive(
            x_image,
            y_image,
            source_x,
            source_y,
            kwargs_lens,
            source_fwhm_parsec,
            z_source,
            cosmo=self.cosmo,
            fixed_aperture_size=True,
            grid_radius_arcsec=0.2)
        flux_ratios_fixed_aperture_size = mag_adaptive_grid_fixed_aperture_size / max(
            mag_adaptive_grid_fixed_aperture_size)

        mag_adaptive_grid_2 = extension.magnification_finite_adaptive(
            x_image,
            y_image,
            source_x,
            source_y,
            kwargs_lens,
            source_fwhm_parsec,
            z_source,
            cosmo=self.cosmo,
            axis_ratio=0)

        flux_ratios_adaptive_grid_2 = mag_adaptive_grid_2 / max(
            mag_adaptive_grid_2)

        # tests the default cosmology
        _ = extension.magnification_finite_adaptive(x_image,
                                                    y_image,
                                                    source_x,
                                                    source_y,
                                                    kwargs_lens,
                                                    source_fwhm_parsec,
                                                    z_source,
                                                    cosmo=None,
                                                    tol=0.0001)

        # test smallest eigenvalue
        _ = extension.magnification_finite_adaptive(
            x_image,
            y_image,
            source_x,
            source_y,
            kwargs_lens,
            source_fwhm_parsec,
            z_source,
            cosmo=None,
            tol=0.0001,
            use_largest_eigenvalue=False)

        # tests the r_max > sqrt(2) * grid_radius stop criterion
        _ = extension.magnification_finite_adaptive(x_image,
                                                    y_image,
                                                    source_x,
                                                    source_y,
                                                    kwargs_lens,
                                                    source_fwhm_parsec,
                                                    z_source,
                                                    cosmo=None,
                                                    tol=0.0001,
                                                    step_size=1000)

        mag_point_source = abs(
            lensmodel.magnification(x_image, y_image, kwargs_lens))

        quarter_precent_precision = [0.0025] * 4
        npt.assert_array_less(
            flux_ratios_square_grid / flux_ratios_adaptive_grid - 1,
            quarter_precent_precision)
        npt.assert_array_less(
            flux_ratios_fixed_aperture_size / flux_ratios_adaptive_grid - 1,
            quarter_precent_precision)
        npt.assert_array_less(
            flux_ratios_square_grid / flux_ratios_adaptive_grid_2 - 1,
            quarter_precent_precision)
        half_percent_precision = [0.005] * 4
        npt.assert_array_less(mag_square_grid / mag_adaptive_grid - 1,
                              half_percent_precision)
        npt.assert_array_less(mag_square_grid / mag_adaptive_grid_2 - 1,
                              half_percent_precision)
        npt.assert_array_less(mag_adaptive_grid / mag_point_source - 1,
                              half_percent_precision)

        flux_array = np.array([0., 0.])
        grid_x = np.array([0., source_sigma])
        grid_y = np.array([0., 0.])
        grid_r = np.hypot(grid_x, grid_y)

        # test that the double gaussian profile has 2x the flux when dx, dy = 0
        magnification_double_gaussian = extension.magnification_finite_adaptive(
            x_image,
            y_image,
            source_x,
            source_y,
            kwargs_lens,
            source_fwhm_parsec,
            z_source,
            cosmo=self.cosmo,
            source_light_model='DOUBLE_GAUSSIAN',
            dx=0.,
            dy=0.,
            amp_scale=1.,
            size_scale=1.)
        npt.assert_almost_equal(magnification_double_gaussian,
                                2 * mag_adaptive_grid)

        grid_radius = 0.3
        npix = 400
        _x = _y = np.linspace(-grid_radius, grid_radius, npix)
        resolution = 2 * grid_radius / npix
        xx, yy = np.meshgrid(_x, _y)
        for i in range(0, 4):
            beta_x, beta_y = lensmodel.ray_shooting(x_image[i] + xx.ravel(),
                                                    y_image[i] + yy.ravel(),
                                                    kwargs_lens)
            source_light_model = LightModel(['GAUSSIAN'] * 2)
            amp_scale, dx, dy, size_scale = 0.2, 0.005, -0.005, 1.
            kwargs_source = [{
                'amp': 1.,
                'center_x': source_x,
                'center_y': source_y,
                'sigma': source_sigma
            }, {
                'amp': amp_scale,
                'center_x': source_x + dx,
                'center_y': source_y + dy,
                'sigma': source_sigma * size_scale
            }]
            sb = source_light_model.surface_brightness(beta_x, beta_y,
                                                       kwargs_source)
            magnification_double_gaussian_reference = np.sum(
                sb) * resolution**2
            magnification_double_gaussian = extension.magnification_finite_adaptive(
                [x_image[i]], [y_image[i]],
                source_x,
                source_y,
                kwargs_lens,
                source_fwhm_parsec,
                z_source,
                cosmo=self.cosmo,
                source_light_model='DOUBLE_GAUSSIAN',
                dx=dx,
                dy=dy,
                amp_scale=amp_scale,
                size_scale=size_scale,
                grid_resolution=resolution,
                grid_radius_arcsec=grid_radius,
                axis_ratio=1.)
            npt.assert_almost_equal(
                magnification_double_gaussian /
                magnification_double_gaussian_reference, 1., 3)

        source_model = LightModel(['GAUSSIAN'])
        kwargs_source = [{
            'amp': 1.,
            'center_x': source_x,
            'center_y': source_y,
            'sigma': source_sigma
        }]

        r_min = 0.
        r_max = source_sigma * 0.9
        flux_array = extension._magnification_adaptive_iteration(
            flux_array, x_image[0], y_image[0], grid_x, grid_y, grid_r, r_min,
            r_max, lensmodel, kwargs_lens, source_model, kwargs_source)
        bx, by = lensmodel.ray_shooting(x_image[0], y_image[0], kwargs_lens)
        sb_true = source_model.surface_brightness(bx, by, kwargs_source)
        npt.assert_equal(True, flux_array[0] == sb_true)
        npt.assert_equal(True, flux_array[1] == 0.)

        r_min = source_sigma * 0.9
        r_max = 2 * source_sigma

        flux_array = extension._magnification_adaptive_iteration(
            flux_array, x_image[0], y_image[0], grid_x, grid_y, grid_r, r_min,
            r_max, lensmodel, kwargs_lens, source_model, kwargs_source)
        bx, by = lensmodel.ray_shooting(x_image[0] + source_sigma, y_image[0],
                                        kwargs_lens)
        sb_true = source_model.surface_brightness(bx, by, kwargs_source)
        npt.assert_equal(True, flux_array[1] == sb_true)
Ejemplo n.º 29
0
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_res: subgrid for the numerical integrals
    :return:
    """
    # make super-sampled grid
    x_grid_sub, y_grid_sub = util.make_grid(numPix=numPix * 5,
                                            deltapix=deltaPix,
                                            subgrid_res=subgrid_res)
    import lenstronomy.Util.mask_util 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 import convergence_integrals as integral

    # compute lensing quantities with subgrid
    convergence_sub = util.array2image(flux)
    f_x_sub, f_y_sub = integral.deflection_from_kappa_grid(
        convergence_sub, grid_spacing=deltaPix / float(subgrid_res))
    f_sub = integral.potential_from_kappa_grid(convergence_sub,
                                               grid_spacing=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
    interp_func = Interpol()
    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.lens_model import LensModel
    lens_model = LensModel(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_model.hessian(x_grid,
                                                y_grid,
                                                kwargs,
                                                diff=0.00001)
    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
Ejemplo n.º 30
0
class TestNumerics(object):

    def setup(self):

        # we define a model consisting of a singe Sersric profile
        from lenstronomy.LightModel.light_model import LightModel
        light_model_list = ['SERSIC_ELLIPSE']
        self.lightModel = LightModel(light_model_list=light_model_list)
        self.kwargs_light = [
            {'amp': 100, 'R_sersic': 0.5, 'n_sersic': 3, 'e1': 0, 'e2': 0, 'center_x': 0.02, 'center_y': 0}]

        # we define a pixel grid and a higher resolution super sampling factor
        self._supersampling_factor = 5
        numPix = 61  # cutout pixel size
        deltaPix = 0.05  # pixel size in arcsec (area per pixel = deltaPix**2)
        x, y, ra_at_xy_0, dec_at_xy_0, x_at_radec_0, y_at_radec_0, Mpix2coord, Mcoord2pix = util.make_grid_with_coordtransform(
            numPix=numPix, deltapix=deltaPix, subgrid_res=1, left_lower=False, inverse=False)
        flux = self.lightModel.surface_brightness(x, y, kwargs_list=self.kwargs_light)
        flux = util.array2image(flux)
        flux_max = np.max(flux)
        conv_pixels_partial = np.zeros((numPix, numPix), dtype=bool)
        conv_pixels_partial[flux >= flux_max / 20] = True
        self._conv_pixels_partial = conv_pixels_partial

        # high resolution ray-tracing and high resolution convolution, the full calculation
        self.kwargs_numerics_true = {'supersampling_factor': self._supersampling_factor,
                                # super sampling factor of (partial) high resolution ray-tracing
                                'compute_mode': 'regular',  # 'regular' or 'adaptive'
                                'supersampling_convolution': True,
                                # bool, if True, performs the supersampled convolution (either on regular or adaptive grid)
                                'supersampling_kernel_size': None,
                                # size of the higher resolution kernel region (can be smaller than the original kernel). None leads to use the full size
                                'flux_evaluate_indexes': None,  # bool mask, if None, it will evaluate all (sub) pixels
                                'supersampled_indexes': None,
                                # bool mask of pixels to be computed in supersampled grid (only for adaptive mode)
                                'compute_indexes': None,
                                # bool mask of pixels to be computed the PSF response (flux being added to). Only used for adaptive mode and can be set =likelihood mask.
                                'point_source_supersampling_factor': 1,
                                # int, supersampling factor when rendering a point source (not used in this script)
                                }

        # high resolution convolution on a smaller PSF with low resolution convolution on the edges of the PSF and high resolution ray tracing
        self.kwargs_numerics_high_res_narrow = {'supersampling_factor': self._supersampling_factor,
                                           'compute_mode': 'regular',
                                           'supersampling_convolution': True,
                                           'supersampling_kernel_size': 5,
                                           }

        # low resolution convolution based on high resolution ray-tracing grid
        self.kwargs_numerics_low_conv_high_grid = {'supersampling_factor': self._supersampling_factor,
                                              'compute_mode': 'regular',
                                              'supersampling_convolution': False,
                                              # does not matter for supersampling_factor=1
                                              'supersampling_kernel_size': None,
                                              # does not matter for supersampling_factor=1
                                              }

        # low resolution convolution with a subset of pixels with high resolution ray-tracing
        self.kwargs_numerics_low_conv_high_adaptive = {'supersampling_factor': self._supersampling_factor,
                                                  'compute_mode': 'adaptive',
                                                  'supersampling_convolution': False,
                                                  # does not matter for supersampling_factor=1
                                                  'supersampling_kernel_size': None,
                                                  # does not matter for supersampling_factor=1
                                                  'supersampled_indexes': self._conv_pixels_partial,
                                                       'convolution_kernel_size': 9,
                                                  }

        # low resolution convolution with a subset of pixels with high resolution ray-tracing and high resoluton convolution on smaller kernel size
        self.kwargs_numerics_high_adaptive = {'supersampling_factor': self._supersampling_factor,
                                         'compute_mode': 'adaptive',
                                         'supersampling_convolution': True,
                                         # does not matter for supersampling_factor=1
                                         'supersampling_kernel_size': 5,  # does not matter for supersampling_factor=1
                                         'supersampled_indexes': self._conv_pixels_partial,
                                              'convolution_kernel_size': 9,
                                         }

        # low resolution convolution and low resolution ray tracing, the simplest calculation
        self.kwargs_numerics_low_res = {'supersampling_factor': 1,
                                   'compute_mode': 'regular',
                                   'supersampling_convolution': False,  # does not matter for supersampling_factor=1
                                   'supersampling_kernel_size': None,  # does not matter for supersampling_factor=1
                                        'convolution_kernel_size': 9,
                                   }

        flux_evaluate_indexes = np.zeros((numPix, numPix), dtype=bool)
        flux_evaluate_indexes[flux >= flux_max / 1000] = True
        # low resolution convolution on subframe
        self.kwargs_numerics_partial = {'supersampling_factor': 1,
                                        'compute_mode': 'regular',
                                        'supersampling_convolution': False,
                                        # does not matter for supersampling_factor=1
                                        'supersampling_kernel_size': None,  # does not matter for supersampling_factor=1
                                        'flux_evaluate_indexes': flux_evaluate_indexes,
                                        'convolution_kernel_size': 9
                                        }


        # import PSF file
        kernel_super = kernel_util.kernel_gaussian(kernel_numPix=11 * self._supersampling_factor,
                                                                     deltaPix=deltaPix / self._supersampling_factor, fwhm=0.1)


        kernel_size = 9
        kernel_super = kernel_util.cut_psf(psf_data=kernel_super, psf_size=kernel_size * self._supersampling_factor)

        # make instance of the PixelGrid class
        from lenstronomy.Data.pixel_grid import PixelGrid
        kwargs_grid = {'nx': numPix, 'ny': numPix, 'transform_pix2angle': Mpix2coord, 'ra_at_xy_0': ra_at_xy_0,
                       'dec_at_xy_0': dec_at_xy_0}
        self.pixel_grid = PixelGrid(**kwargs_grid)

        # make instance of the PSF class
        from lenstronomy.Data.psf import PSF
        kwargs_psf = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_super,
                      'point_source_supersampling_factor': self._supersampling_factor}
        self.psf_class = PSF(**kwargs_psf)



        # without convolution
        image_model_true = ImageModel(self.pixel_grid, self.psf_class, lens_light_model_class=self.lightModel,
                                      kwargs_numerics=self.kwargs_numerics_true)
        self.image_true = image_model_true.image(kwargs_lens_light=self.kwargs_light)

    def test_full(self):
        image_model_true = ImageModel(self.pixel_grid, self.psf_class, lens_light_model_class=self.lightModel,
                                      kwargs_numerics=self.kwargs_numerics_true)
        image_unconvolved = image_model_true.image(kwargs_lens_light=self.kwargs_light, unconvolved=True)
        npt.assert_almost_equal(np.sum(self.image_true) / np.sum(image_unconvolved), 1, decimal=2)

    def test_high_res_narrow(self):
        image_model = ImageModel(self.pixel_grid, self.psf_class, lens_light_model_class=self.lightModel,
                                      kwargs_numerics=self.kwargs_numerics_high_res_narrow)
        image_conv = image_model.image(kwargs_lens_light=self.kwargs_light, unconvolved=False)
        npt.assert_almost_equal((self.image_true - image_conv) / self.image_true, 0, decimal=2)

    def test_low_conv_high_grid(self):
        image_model = ImageModel(self.pixel_grid, self.psf_class, lens_light_model_class=self.lightModel,
                                      kwargs_numerics=self.kwargs_numerics_low_conv_high_grid)
        image_conv = image_model.image(kwargs_lens_light=self.kwargs_light, unconvolved=False)
        npt.assert_almost_equal((self.image_true - image_conv) / self.image_true, 0, decimal=1)

    def test_low_conv_high_adaptive(self):
        image_model = ImageModel(self.pixel_grid, self.psf_class, lens_light_model_class=self.lightModel,
                                      kwargs_numerics=self.kwargs_numerics_low_conv_high_adaptive)
        image_conv = image_model.image(kwargs_lens_light=self.kwargs_light, unconvolved=False)
        npt.assert_almost_equal((self.image_true - image_conv) / self.image_true, 0, decimal=1)

    def test_high_adaptive(self):
        image_model = ImageModel(self.pixel_grid, self.psf_class, lens_light_model_class=self.lightModel,
                                      kwargs_numerics=self.kwargs_numerics_high_adaptive)
        image_conv = image_model.image(kwargs_lens_light=self.kwargs_light, unconvolved=False)
        npt.assert_almost_equal((self.image_true - image_conv) / self.image_true, 0, decimal=1)

    def test_low_res(self):
        image_model = ImageModel(self.pixel_grid, self.psf_class, lens_light_model_class=self.lightModel,
                                      kwargs_numerics=self.kwargs_numerics_low_res)
        image_conv = image_model.image(kwargs_lens_light=self.kwargs_light, unconvolved=False)
        npt.assert_almost_equal((self.image_true - image_conv) / self.image_true, 0, decimal=1)

    def test_sub_frame(self):
        image_model = ImageModel(self.pixel_grid, self.psf_class, lens_light_model_class=self.lightModel,
                                 kwargs_numerics=self.kwargs_numerics_partial)
        image_conv = image_model.image(kwargs_lens_light=self.kwargs_light, unconvolved=False)
        delta = (self.image_true - image_conv) / self.image_true
        npt.assert_almost_equal(delta[self._conv_pixels_partial], 0, decimal=1)