def setup(self):
     self.numPix = 10
     kwargs_data = {'image_data': np.zeros((self.numPix, self.numPix))}
     self.Data = Data(kwargs_data)
     kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': 1}
     self.PSF = PSF(kwargs_psf)
     kwargs_numerics = {'subgrid_res': 2, 'psf_subgrid': True}
     self.ImageNumerics = ImageNumerics(self.Data, self.PSF, **kwargs_numerics)
Пример #2
0
    def update_numerics(self, kwargs_numerics):
        """
        update numerical options

        :param kwargs_numerics:
        :return:
        """
        self._psf_error_map = kwargs_numerics.get('psf_error_map', False)
        self.ImageNumerics = ImageNumerics(data=self.Data, psf=self.PSF, kwargs_numerics=kwargs_numerics)
Пример #3
0
 def __init__(self,
              data_class,
              psf_class=None,
              lens_model_class=None,
              source_model_class=None,
              lens_light_model_class=None,
              point_source_class=None,
              kwargs_numerics={}):
     """
     :param data_class: instance of Data() class
     :param psf_class: instance of PSF() class
     :param lens_model_class: instance of LensModel() class
     :param source_model_class: instance of LightModel() class describing the source parameters
     :param lens_light_model_class: instance of LightModel() class describing the lens light parameters
     :param point_source_class: instance of PointSource() class describing the point sources
     :param kwargs_numerics: keyword argument with various numeric description (see ImageNumerics class for options)
     """
     self.type = 'single-band'
     self.PSF = psf_class
     self.Data = data_class
     self.ImageNumerics = ImageNumerics(pixel_grid=self.Data,
                                        psf=self.PSF,
                                        **kwargs_numerics)
     if lens_model_class is None:
         lens_model_class = LensModel(lens_model_list=[])
     self.LensModel = lens_model_class
     self.PointSource = point_source_class
     self._error_map_bool_list = None
     if self.PointSource is not None:
         self.PointSource.update_lens_model(
             lens_model_class=lens_model_class)
         x_center, y_center = self.Data.center
         self.PointSource.update_search_window(
             search_window=np.max(self.Data.width),
             x_center=x_center,
             y_center=y_center,
             min_distance=self.Data.pixel_width)
         if self.PSF.psf_error_map is not None:
             self._psf_error_map = True
             self._error_map_bool_list = kwargs_numerics.get(
                 'error_map_bool_list',
                 [True] * len(self.PointSource.point_source_type_list))
         else:
             self._psf_error_map = False
     else:
         self._psf_error_map = False
     if source_model_class is None:
         source_model_class = LightModel(light_model_list=[])
     self.SourceModel = source_model_class
     if lens_light_model_class is None:
         lens_light_model_class = LightModel(light_model_list=[])
     self.LensLightModel = lens_light_model_class
     self.source_mapping = Image2SourceMapping(
         lensModel=lens_model_class, sourceModel=source_model_class)
     self.num_bands = 1
    def test_point_source_rendering(self):
        numPix = 20
        deltaPix = 0.05
        ra_at_xy_0 = 0
        dec_at_xy_0 = 0
        kwargs_data = {'image_data': np.zeros((numPix, numPix))}
        data = Data(kwargs_data)
        kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': 1., 'point_source_subgrid': 1}
        psf = PSF(kwargs_psf)
        kwargs_numerics = {'subgrid_res': 2, 'psf_subgrid': True}
        imageNumerics = ImageNumerics(data, psf, **kwargs_numerics)
        ra_pos = np.array([10, 7])
        dec_pos = np.array([6, 7])
        amp = np.array([10, 10])
        image = imageNumerics.point_source_rendering_old(ra_pos, dec_pos, amp)
        image_subgrid = imageNumerics.point_source_rendering(ra_pos, dec_pos, amp)
        npt.assert_almost_equal(image[10, 7], image_subgrid[10, 7], decimal=8)

        kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': 2., 'point_source_subgrid': 3}
        psf = PSF(kwargs_psf)
        kwargs_numerics = {'subgrid_res': 1, 'psf_subgrid': True}
        imageNumerics = ImageNumerics(data, psf, **kwargs_numerics)
        ra_pos = np.array([7.1, 14])
        dec_pos = np.array([7, 7.32])
        amp = np.array([10, 10])
        image = imageNumerics.point_source_rendering(ra_pos, dec_pos, amp)
        image_subgrid = imageNumerics.point_source_rendering(ra_pos, dec_pos, amp)
        image_sum = np.sum(image)
        image_subgrid_sum = np.sum(image_subgrid)
        npt.assert_almost_equal(image_sum/image_subgrid_sum, 1, decimal=5)

        assert image[7, 14] <= image_subgrid[7, 14]
        npt.assert_almost_equal(image[0, 0], image_subgrid[0, 0], decimal=8)
Пример #5
0
class TestImageNumerics(object):
    def setup(self):
        self.numPix = 10
        kwargs_data = {'image_data': np.zeros((self.numPix, self.numPix))}
        self.Data = Data(kwargs_data)
        kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': 1}
        self.PSF = PSF(kwargs_psf)
        kwargs_numerics = {'subgrid_res': 2, 'psf_subgrid': True}
        self.ImageNumerics = ImageNumerics(self.Data, self.PSF,
                                           kwargs_numerics)

    def test_psf_cutout(self):
        idex_mask = np.zeros((5, 5))
        idex_mask[3, 2] = 1
        idex_mask[1, 1] = 1
        image_data = np.zeros((5, 5))
        image_data[1, 1] = 1
        kwargs_data = {'image_data': image_data}
        data = Data(kwargs_data)
        kwargs_numerics = {'idex_mask': idex_mask}
        imageNumerics = ImageNumerics(data,
                                      self.PSF,
                                      kwargs_numerics=kwargs_numerics)
        cut_data = imageNumerics._cutout_psf(image_data, subgrid_res=1)
        print(cut_data)
        assert cut_data[0, 0] == 1
        assert cut_data[2, 1] == 0
        nx, ny = np.shape(cut_data)
        assert nx == 3
        assert ny == 2

        idex_mask = np.ones((5, 5))
        kwargs_data = {'image_data': image_data}
        data = Data(kwargs_data)
        kwargs_numerics = {'idex_mask': idex_mask}
        imageNumerics = ImageNumerics(data,
                                      self.PSF,
                                      kwargs_numerics=kwargs_numerics)
        cut_data = imageNumerics._cutout_psf(image_data, subgrid_res=1)
        assert cut_data[1, 1] == 1

    def test_idex_subgrid(self):
        idex_mask = np.zeros(self.numPix**2)
        n = 8
        nx, ny = int(np.sqrt(len(idex_mask))), int(np.sqrt(len(idex_mask)))
        idex_mask[n] = 1
        subgrid_res = 2
        idex_mask_subgrid = self.ImageNumerics._subgrid_idex(
            idex_mask, subgrid_res, nx, ny)
        assert idex_mask_subgrid[(n + 1) * subgrid_res - 1] == 1
        assert idex_mask_subgrid[(n + 1) * subgrid_res - 2] == 1
        print(type(nx * subgrid_res + (n + 1) * subgrid_res - 1))
        print(type((n + 1) * subgrid_res - 2))
        assert idex_mask_subgrid[nx * subgrid_res + (n + 1) * subgrid_res -
                                 1] == 1
Пример #6
0
 def __init__(self,
              data_class,
              psf_class=None,
              lens_model_class=None,
              source_model_class=None,
              lens_light_model_class=None,
              point_source_class=None,
              kwargs_numerics={}):
     """
     :param data_class: instance of Data() class
     :param psf_class: instance of PSF() class
     :param lens_model_class: instance of LensModel() class
     :param source_model_class: instance of LightModel() class describing the source parameters
     :param lens_light_model_class: instance of LightModel() class describing the lens light parameters
     :param point_source_class: instance of PointSource() class describing the point sources
     :param kwargs_numerics: keyword argument with various numerics description (see ImageNumerics class for options)
     """
     self.PSF = psf_class
     self.Data = data_class
     self.ImageNumerics = ImageNumerics(data=self.Data,
                                        psf=self.PSF,
                                        **kwargs_numerics)
     self.LensModel = lens_model_class
     self.PointSource = point_source_class
     self._error_map_bool_list = None
     if self.PointSource is not None:
         self.PointSource.update_lens_model(
             lens_model_class=lens_model_class)
         if self.PSF.psf_error_map is not None:
             self._psf_error_map = True
             self._error_map_bool_list = kwargs_numerics.get(
                 'error_map_bool_list',
                 [True] * len(self.PointSource._point_source_type_list))
         else:
             self._psf_error_map = False
     else:
         self._psf_error_map = False
     self.SourceModel = source_model_class
     self.LensLightModel = lens_light_model_class
     self.num_bands = 1
    def test_psf_cutout(self):
        idex_mask = np.zeros((5, 5))
        idex_mask[3, 2] = 1
        idex_mask[1, 1] = 1
        image_data = np.zeros((5, 5))
        image_data[1, 1] = 1
        kwargs_data = {'image_data': image_data}
        data = Data(kwargs_data)
        kwargs_numerics = {'idex_mask': idex_mask}
        imageNumerics = ImageNumerics(data, self.PSF, **kwargs_numerics)
        cut_data = imageNumerics._cutout_psf(image_data, subgrid_res=1)
        print(cut_data)
        assert cut_data[0, 0] == 1
        assert cut_data[2, 1] == 0
        nx, ny = np.shape(cut_data)
        assert nx == 3
        assert ny == 2

        idex_mask = np.ones((5, 5))
        kwargs_data = {'image_data': image_data}
        data = Data(kwargs_data)
        kwargs_numerics = {'idex_mask': idex_mask}
        imageNumerics = ImageNumerics(data, self.PSF, **kwargs_numerics)
        cut_data = imageNumerics._cutout_psf(image_data, subgrid_res=1)
        assert cut_data[1, 1] == 1
Пример #8
0
    def __init__(self, data_class, psf_class=None, lens_model_class=None, source_model_class=None, lens_light_model_class=None, point_source_class=None, kwargs_numerics={}):
        """


        :param kwargs_options: keywords of the modelling choices
        'subgrid_res': integer, sub-grid ray-tracing resolution
        'psf_subgrid': bool, if True, performs the convolution on the subgrid resolution
        (higher accuracy for higher computational cost)
        :param kwargs_data: keywords of the data, see Data() class for further information
        :param kwargs_psf: keywords of the PSF convolution, see PSF() class for further information
        """
        self.PSF = psf_class
        self.Data = data_class
        self._psf_error_map = kwargs_numerics.get('psf_error_map', False)
        self.kwargs_numerics = kwargs_numerics
        self.ImageNumerics = ImageNumerics(data=self.Data, psf=self.PSF, kwargs_numerics=kwargs_numerics)
        self.LensModel = lens_model_class
        self.PointSource = point_source_class
        if self.PointSource is not None:
            self.PointSource.update_lens_model(lens_model_class=lens_model_class)
        self.SourceModel = source_model_class
        self.LensLightModel = lens_light_model_class
Пример #9
0
class ImageModel(object):
    """
    this class uses functions of lens_model and source_model to make a lensed image
    """
    def __init__(self,
                 data_class,
                 psf_class=None,
                 lens_model_class=None,
                 source_model_class=None,
                 lens_light_model_class=None,
                 point_source_class=None,
                 kwargs_numerics={}):
        """
        :param data_class: instance of Data() class
        :param psf_class: instance of PSF() class
        :param lens_model_class: instance of LensModel() class
        :param source_model_class: instance of LightModel() class describing the source parameters
        :param lens_light_model_class: instance of LightModel() class describing the lens light parameters
        :param point_source_class: instance of PointSource() class describing the point sources
        :param kwargs_numerics: keyword argument with various numerics description (see ImageNumerics class for options)
        """
        self.PSF = psf_class
        self.Data = data_class
        self.ImageNumerics = ImageNumerics(data=self.Data,
                                           psf=self.PSF,
                                           **kwargs_numerics)
        self.LensModel = lens_model_class
        self.PointSource = point_source_class
        self._error_map_bool_list = None
        if self.PointSource is not None:
            self.PointSource.update_lens_model(
                lens_model_class=lens_model_class)
            if self.PSF.psf_error_map is not None:
                self._psf_error_map = True
                self._error_map_bool_list = kwargs_numerics.get(
                    'error_map_bool_list',
                    [True] * len(self.PointSource._point_source_type_list))
            else:
                self._psf_error_map = False
        else:
            self._psf_error_map = False
        self.SourceModel = source_model_class
        self.LensLightModel = lens_light_model_class
        self.num_bands = 1

    def reset_point_source_cache(self):
        """
        deletes all the cache in the point source class and saves it from then on

        :return:
        """
        if self.PointSource is not None:
            self.PointSource.delete_lens_model_cach()
            self.PointSource.set_save_cache(True)

    def update_data(self, data_class):
        """

        :param data_class: instance of Data() class
        :return: no return. Class is updated.
        """
        self.Data = data_class
        self.ImageNumerics._Data = data_class

    def update_psf(self, psf_class):
        """

        update the instance of the class with a new instance of PSF() with a potentially different point spread function

        :param psf_class:
        :return: no return. Class is updated.
        """
        self.PSF = psf_class
        self.ImageNumerics._PSF = psf_class

    def update_numerics(self, kwargs_numerics):
        """

        update numerical options

        :param kwargs_numerics:
        :return: no return. Class is updated.
        """
        self._psf_error_map = kwargs_numerics.get('psf_error_map', False)
        self.ImageNumerics = ImageNumerics(data=self.Data,
                                           psf=self.PSF,
                                           **kwargs_numerics)

    def source_surface_brightness(self,
                                  kwargs_source,
                                  kwargs_lens=None,
                                  unconvolved=False,
                                  de_lensed=False,
                                  k=None):
        """

        computes the source surface brightness distribution

        :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles
        :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles
        :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing)
        :param de_lensed: if True: returns the un-lensed source surface brightness profile, otherwise the lensed.
        :return: 1d array of surface brightness pixels
        """
        if self.SourceModel is None:
            return np.zeros_like(self.Data.data)
        if de_lensed is True or self.LensModel is None:
            x_source, y_source = self.ImageNumerics.ra_grid_ray_shooting, self.ImageNumerics.dec_grid_ray_shooting
        else:
            x_source, y_source = self.LensModel.ray_shooting(
                self.ImageNumerics.ra_grid_ray_shooting,
                self.ImageNumerics.dec_grid_ray_shooting, kwargs_lens)
        source_light = self.SourceModel.surface_brightness(x_source,
                                                           y_source,
                                                           kwargs_source,
                                                           k=k)
        source_light_final = self.ImageNumerics.re_size_convolve(
            source_light, unconvolved=unconvolved)
        return source_light_final

    def lens_surface_brightness(self,
                                kwargs_lens_light,
                                unconvolved=False,
                                k=None):
        """

        computes the lens surface brightness distribution

        :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles
        :param unconvolved: if True, returns unconvolved surface brightness (perfect seeing), otherwise convolved with PSF kernel
        :return: 1d array of surface brightness pixels
        """
        if self.LensLightModel is None:
            return np.zeros_like(self.Data.data)
        lens_light = self.LensLightModel.surface_brightness(
            self.ImageNumerics.ra_grid_ray_shooting,
            self.ImageNumerics.dec_grid_ray_shooting,
            kwargs_lens_light,
            k=k)
        lens_light_final = self.ImageNumerics.re_size_convolve(
            lens_light, unconvolved=unconvolved)
        return lens_light_final

    def point_source(self,
                     kwargs_ps,
                     kwargs_lens=None,
                     unconvolved=False,
                     k=None):
        """

        computes the point source positions and paints PSF convolutions on them

        :param kwargs_ps:
        :param k:
        :return:
        """
        point_source_image = np.zeros_like(self.Data.data)
        if unconvolved or self.PointSource is None:
            return point_source_image
        ra_pos, dec_pos, amp, n_points = self.PointSource.linear_response_set(
            kwargs_ps, kwargs_lens, with_amp=True, k=k)
        for i in range(n_points):
            point_source_image += self.ImageNumerics.point_source_rendering(
                ra_pos[i], dec_pos[i], amp[i])
        return point_source_image

    def image_linear_solve(self,
                           kwargs_lens=None,
                           kwargs_source=None,
                           kwargs_lens_light=None,
                           kwargs_ps=None,
                           inv_bool=False):
        """

        computes the image (lens and source surface brightness with a given lens model).
        The linear parameters are computed with a weighted linear least square optimization (i.e. flux normalization of the brightness profiles)

        :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles
        :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles
        :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles
        :param kwargs_ps: keyword arguments corresponding to "other" parameters, such as external shear and point source image positions
        :param inv_bool: if True, invert the full linear solver Matrix Ax = y for the purpose of the covariance matrix.
        :return: 1d array of surface brightness pixels of the optimal solution of the linear parameters to match the data
        """
        if not self.LensModel is None:
            x_source, y_source = self.LensModel.ray_shooting(
                self.ImageNumerics.ra_grid_ray_shooting,
                self.ImageNumerics.dec_grid_ray_shooting, kwargs_lens)
        else:
            x_source, y_source = self.ImageNumerics.ra_grid_ray_shooting, self.ImageNumerics.dec_grid_ray_shooting

        A = self._response_matrix(self.ImageNumerics.ra_grid_ray_shooting,
                                  self.ImageNumerics.dec_grid_ray_shooting,
                                  x_source, y_source, kwargs_lens,
                                  kwargs_source, kwargs_lens_light, kwargs_ps,
                                  self.ImageNumerics.mask)
        error_map = self.error_map(kwargs_lens, kwargs_ps)
        error_map_1d = self.ImageNumerics.image2array(error_map)
        d = self.ImageNumerics.image2array(self.Data.data *
                                           self.ImageNumerics.mask)
        param, cov_param, wls_model = de_lens.get_param_WLS(
            A.T,
            1 / (self.ImageNumerics.C_D_response + error_map_1d),
            d,
            inv_bool=inv_bool)
        _, _, _, _ = self._update_linear_kwargs(param, kwargs_lens,
                                                kwargs_source,
                                                kwargs_lens_light, kwargs_ps)
        model = self.ImageNumerics.array2image(wls_model)
        return model, error_map, cov_param, param

    def image(self,
              kwargs_lens=None,
              kwargs_source=None,
              kwargs_lens_light=None,
              kwargs_ps=None,
              unconvolved=False,
              source_add=True,
              lens_light_add=True,
              point_source_add=True):
        """

        make a image with a realisation of linear parameter values "param"

        :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles
        :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles
        :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles
        :param kwargs_ps: keyword arguments corresponding to "other" parameters, such as external shear and point source image positions
        :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing)
        :param source_add: if True, compute source, otherwise without
        :param lens_light_add: if True, compute lens light, otherwise without
        :param point_source_add: if True, add point sources, otherwise without
        :return: 1d array of surface brightness pixels of the simulation
        """
        if source_add:
            source_light = self.source_surface_brightness(
                kwargs_source, kwargs_lens, unconvolved=unconvolved)
        else:
            source_light = np.zeros_like(self.Data.data)
        if lens_light_add:
            lens_light = self.lens_surface_brightness(kwargs_lens_light,
                                                      unconvolved=unconvolved)
        else:
            lens_light = np.zeros_like(self.Data.data)
        if point_source_add:
            point_source = self.point_source(kwargs_ps,
                                             kwargs_lens,
                                             unconvolved=unconvolved)
        else:
            point_source = np.zeros_like(self.Data.data)
        model = (source_light + lens_light +
                 point_source) * self.ImageNumerics.mask
        return model

    def error_map(self, kwargs_lens, kwargs_ps):
        """

        :param kwargs_lens:
        :param kwargs_ps:
        :return:
        """
        error_map = np.zeros_like(self.Data.data)
        if self._psf_error_map is True:
            for k, bool in enumerate(self._error_map_bool_list):
                if bool is True:
                    ra_pos, dec_pos, amp, n_points = self.PointSource.linear_response_set(
                        kwargs_ps, kwargs_lens, k=k)
                    for i in range(0, n_points):
                        error_map_add = self.ImageNumerics.psf_error_map(
                            ra_pos[i], dec_pos[i], amp[i])
                        error_map += error_map_add
        return error_map

    def point_sources_list(self, kwargs_ps, kwargs_lens, k=None):
        """

        :param kwargs_ps:
        :return: list of images containing only single point sources
        """
        point_list = []
        if self.PointSource is None:
            return point_list
        ra_array, dec_array, amp_array = self.PointSource.point_source_list(
            kwargs_ps, kwargs_lens, k=k)
        for i in range(len(ra_array)):
            point_source = self.ImageNumerics.point_source_rendering(
                [ra_array[i]], [dec_array[i]], [amp_array[i]])
            point_list.append(point_source)
        return point_list

    def image_positions(self, kwargs_ps, kwargs_lens):
        """
        lens equation solver for image positions given lens model and source position (only for image positions within
        the data frame).

        :param kwargs_lens: keyword arguments of lens models (as list)
        :param sourcePos_x: source position in relative arc sec
        :param sourcePos_y: source position in relative arc sec
        :return: x_coords, y_coords of image positions
        """
        if self.PointSource is None:
            return [], []
        x_mins, y_mins = self.PointSource.image_position(
            kwargs_ps, kwargs_lens)
        return x_mins, y_mins

    def likelihood_data_given_model(self,
                                    kwargs_lens,
                                    kwargs_source,
                                    kwargs_lens_light,
                                    kwargs_ps,
                                    source_marg=False,
                                    compute_bool=None):
        """

        computes the likelihood of the data given a model
        This is specified with the non-linear parameters and a linear inversion and prior marginalisation.

        :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles
        :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles
        :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles
        :param kwargs_ps: keyword arguments corresponding to "other" parameters, such as external shear and point source image positions
        :return: log likelihood (natural logarithm)
        """
        # generate image
        im_sim, model_error, cov_matrix, param = self.image_linear_solve(
            kwargs_lens,
            kwargs_source,
            kwargs_lens_light,
            kwargs_ps,
            inv_bool=source_marg)
        # compute X^2
        logL = self.Data.log_likelihood(im_sim, self.ImageNumerics.mask,
                                        model_error)
        if cov_matrix is not None and source_marg:
            marg_const = de_lens.marginalisation_const(cov_matrix)
            #if marg_const + logL > 0:
            #logL = np.log(np.exp(logL) + np.exp(marg_const))
            logL += marg_const
        return logL

    def reduced_residuals(self, model, error_map=0):
        """

        :param model:
        :return:
        """
        mask = self.ImageNumerics.mask
        residual = (model - self.Data.data) / np.sqrt(self.Data.C_D +
                                                      np.abs(error_map)) * mask
        return residual

    def reduced_chi2(self, model, error_map=0):
        """
        returns reduced chi2
        :param model:
        :param error_map:
        :return:
        """
        chi2 = self.reduced_residuals(model, error_map)
        return np.sum(chi2**2) / self.numData_evaluate()

    def numData_evaluate(self, compute_bool=None):
        """
        number of data points to be used in the linear solver
        :return:
        """
        return self.ImageNumerics.numData_evaluate

    def fermat_potential(self, kwargs_lens, kwargs_ps):
        """

        :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles
        :param kwargs_else: keyword arguments corresponding to "other" parameters, such as external shear and point source image positions
        :return: time delay in arcsec**2 without geometry term (second part of Eqn 1 in Suyu et al. 2013) as a list
        """

        ra_pos_list, dec_pos_list = self.PointSource.image_position(
            kwargs_ps, kwargs_lens)
        ra_source_list, dec_source_list = self.PointSource.source_position(
            kwargs_ps, kwargs_lens)
        phi_fermat = []
        for i in range(len(ra_pos_list)):
            phi_fermat_i = self.LensModel.fermat_potential(
                ra_pos_list[i], dec_pos_list[i], ra_source_list[i],
                dec_source_list[i], kwargs_lens)
            phi_fermat.append(phi_fermat_i)
        return phi_fermat

    def _response_matrix(self,
                         x_grid,
                         y_grid,
                         x_source,
                         y_source,
                         kwargs_lens,
                         kwargs_source,
                         kwargs_lens_light,
                         kwargs_ps,
                         mask,
                         unconvolved=False):
        """

        return linear response Matrix

        :param x_grid:
        :param y_grid:
        :param x_source:
        :param y_source:
        :param kwargs_lens:
        :param kwargs_source:
        :param kwargs_lens_light:
        :param kwargs_ps:
        :param mask:
        :param unconvolved:
        :return:
        """
        if not self.SourceModel is None:
            source_light_response, n_source = self.SourceModel.functions_split(
                x_source, y_source, kwargs_source)
        else:
            source_light_response, n_source = [], 0
        if not self.LensLightModel is None:
            lens_light_response, n_lens_light = self.LensLightModel.functions_split(
                x_grid, y_grid, kwargs_lens_light)
        else:
            lens_light_response, n_lens_light = [], 0
        if not self.PointSource is None:
            ra_pos, dec_pos, amp, n_points = self.PointSource.linear_response_set(
                kwargs_ps, kwargs_lens, with_amp=False)
        else:
            ra_pos, dec_pos, amp, n_points = [], [], [], 0
        num_param = n_points + n_lens_light + n_source

        num_response = self.ImageNumerics.num_response
        A = np.zeros((num_param, num_response))
        n = 0
        # response of sersic source profile
        for i in range(0, n_source):
            image = source_light_response[i]
            image = self.ImageNumerics.re_size_convolve(
                image, unconvolved=unconvolved)
            A[n, :] = self.ImageNumerics.image2array(image)
            n += 1
        # response of lens light profile
        for i in range(0, n_lens_light):
            image = lens_light_response[i]
            image = self.ImageNumerics.re_size_convolve(
                image, unconvolved=unconvolved)
            A[n, :] = self.ImageNumerics.image2array(image)
            n += 1
        # response of point sources
        for i in range(0, n_points):
            image = self.ImageNumerics.point_source_rendering(
                ra_pos[i], dec_pos[i], amp[i])
            A[n, :] = self.ImageNumerics.image2array(image)
            n += 1
        A = self._add_mask(A, mask)
        return A

    def _add_mask(self, A, mask):
        """

        :param A: 2d matrix n*len(mask)
        :param mask: 1d vector of 1 or zeros
        :return: column wise multiplication of A*mask
        """
        return A[:] * self.ImageNumerics.image2array(mask)

    def _update_linear_kwargs(self, param, kwargs_lens, kwargs_source,
                              kwargs_lens_light, kwargs_ps):
        """

        links linear parameters to kwargs arguments

        :param param: linear parameter vector corresponding to the response matrix
        :return: updated list of kwargs with linear parameter values
        """
        i = 0
        if not self.SourceModel is None:
            kwargs_source, i = self.SourceModel.update_linear(
                param, i, kwargs_list=kwargs_source)
        if not self.LensLightModel is None:
            kwargs_lens_light, i = self.LensLightModel.update_linear(
                param, i, kwargs_list=kwargs_lens_light)
        if not self.PointSource is None:
            kwargs_ps, i = self.PointSource.update_linear(
                param, i, kwargs_ps, kwargs_lens)
        return kwargs_lens, kwargs_source, kwargs_lens_light, kwargs_ps
class TestImageNumerics(object):

    def setup(self):
        self.numPix = 10
        kwargs_data = {'image_data': np.zeros((self.numPix, self.numPix))}
        self.Data = Data(kwargs_data)
        kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': 1}
        self.PSF = PSF(kwargs_psf)
        kwargs_numerics = {'subgrid_res': 2, 'psf_subgrid': True}
        self.ImageNumerics = ImageNumerics(self.Data, self.PSF, **kwargs_numerics)

    def test_psf_cutout(self):
        idex_mask = np.zeros((5, 5))
        idex_mask[3, 2] = 1
        idex_mask[1, 1] = 1
        image_data = np.zeros((5, 5))
        image_data[1, 1] = 1
        kwargs_data = {'image_data': image_data}
        data = Data(kwargs_data)
        kwargs_numerics = {'idex_mask': idex_mask}
        imageNumerics = ImageNumerics(data, self.PSF, **kwargs_numerics)
        cut_data = imageNumerics._cutout_psf(image_data, subgrid_res=1)
        print(cut_data)
        assert cut_data[0, 0] == 1
        assert cut_data[2, 1] == 0
        nx, ny = np.shape(cut_data)
        assert nx == 3
        assert ny == 2

        idex_mask = np.ones((5, 5))
        kwargs_data = {'image_data': image_data}
        data = Data(kwargs_data)
        kwargs_numerics = {'idex_mask': idex_mask}
        imageNumerics = ImageNumerics(data, self.PSF, **kwargs_numerics)
        cut_data = imageNumerics._cutout_psf(image_data, subgrid_res=1)
        assert cut_data[1, 1] == 1

    def test_idex_subgrid(self):
        idex_mask = np.zeros(self.numPix**2)
        n = 8
        nx, ny = int(np.sqrt(len(idex_mask))), int(np.sqrt(len(idex_mask)))
        idex_mask[n] = 1
        subgrid_res = 2
        idex_mask_subgrid = self.ImageNumerics._subgrid_idex(idex_mask, subgrid_res, nx, ny)
        assert idex_mask_subgrid[(n + 1) * subgrid_res - 1] == 1
        assert idex_mask_subgrid[(n + 1) * subgrid_res - 2] == 1
        print(type(nx * subgrid_res + (n + 1) * subgrid_res - 1))
        print(type((n + 1) * subgrid_res - 2))
        assert idex_mask_subgrid[nx * subgrid_res + (n + 1) * subgrid_res - 1] == 1

    def test_point_source_rendering(self):
        numPix = 20
        deltaPix = 0.05
        ra_at_xy_0 = 0
        dec_at_xy_0 = 0
        kwargs_data = {'image_data': np.zeros((numPix, numPix))}
        data = Data(kwargs_data)
        kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': 1., 'point_source_subgrid': 1}
        psf = PSF(kwargs_psf)
        kwargs_numerics = {'subgrid_res': 2, 'psf_subgrid': True}
        imageNumerics = ImageNumerics(data, psf, **kwargs_numerics)
        ra_pos = np.array([10, 7])
        dec_pos = np.array([6, 7])
        amp = np.array([10, 10])
        image = imageNumerics.point_source_rendering_old(ra_pos, dec_pos, amp)
        image_subgrid = imageNumerics.point_source_rendering(ra_pos, dec_pos, amp)
        npt.assert_almost_equal(image[10, 7], image_subgrid[10, 7], decimal=8)

        kwargs_psf = {'psf_type': 'GAUSSIAN', 'fwhm': 2., 'point_source_subgrid': 3}
        psf = PSF(kwargs_psf)
        kwargs_numerics = {'subgrid_res': 1, 'psf_subgrid': True}
        imageNumerics = ImageNumerics(data, psf, **kwargs_numerics)
        ra_pos = np.array([7.1, 14])
        dec_pos = np.array([7, 7.32])
        amp = np.array([10, 10])
        image = imageNumerics.point_source_rendering(ra_pos, dec_pos, amp)
        image_subgrid = imageNumerics.point_source_rendering(ra_pos, dec_pos, amp)
        image_sum = np.sum(image)
        image_subgrid_sum = np.sum(image_subgrid)
        npt.assert_almost_equal(image_sum/image_subgrid_sum, 1, decimal=5)

        assert image[7, 14] <= image_subgrid[7, 14]
        npt.assert_almost_equal(image[0, 0], image_subgrid[0, 0], decimal=8)
Пример #11
0
class ImageModel(object):
    """
    this class uses functions of lens_model and source_model to make a lensed image
    """
    def __init__(self,
                 data_class,
                 psf_class=None,
                 lens_model_class=None,
                 source_model_class=None,
                 lens_light_model_class=None,
                 point_source_class=None,
                 kwargs_numerics={}):
        """
        :param data_class: instance of Data() class
        :param psf_class: instance of PSF() class
        :param lens_model_class: instance of LensModel() class
        :param source_model_class: instance of LightModel() class describing the source parameters
        :param lens_light_model_class: instance of LightModel() class describing the lens light parameters
        :param point_source_class: instance of PointSource() class describing the point sources
        :param kwargs_numerics: keyword argument with various numeric description (see ImageNumerics class for options)
        """
        self.type = 'single-band'
        self.PSF = psf_class
        self.Data = data_class
        self.ImageNumerics = ImageNumerics(pixel_grid=self.Data,
                                           psf=self.PSF,
                                           **kwargs_numerics)
        if lens_model_class is None:
            lens_model_class = LensModel(lens_model_list=[])
        self.LensModel = lens_model_class
        self.PointSource = point_source_class
        self._error_map_bool_list = None
        if self.PointSource is not None:
            self.PointSource.update_lens_model(
                lens_model_class=lens_model_class)
            x_center, y_center = self.Data.center
            self.PointSource.update_search_window(
                search_window=np.max(self.Data.width),
                x_center=x_center,
                y_center=y_center,
                min_distance=self.Data.pixel_width)
            if self.PSF.psf_error_map is not None:
                self._psf_error_map = True
                self._error_map_bool_list = kwargs_numerics.get(
                    'error_map_bool_list',
                    [True] * len(self.PointSource.point_source_type_list))
            else:
                self._psf_error_map = False
        else:
            self._psf_error_map = False
        if source_model_class is None:
            source_model_class = LightModel(light_model_list=[])
        self.SourceModel = source_model_class
        if lens_light_model_class is None:
            lens_light_model_class = LightModel(light_model_list=[])
        self.LensLightModel = lens_light_model_class
        self.source_mapping = Image2SourceMapping(
            lensModel=lens_model_class, sourceModel=source_model_class)
        self.num_bands = 1

    def reset_point_source_cache(self, bool=True):
        """
        deletes all the cache in the point source class and saves it from then on

        :return:
        """
        if self.PointSource is not None:
            self.PointSource.delete_lens_model_cach()
            self.PointSource.set_save_cache(bool)

    def update_psf(self, psf_class):
        """

        update the instance of the class with a new instance of PSF() with a potentially different point spread function

        :param psf_class:
        :return: no return. Class is updated.
        """
        self.PSF = psf_class
        self.ImageNumerics._PSF = psf_class

    def source_surface_brightness(self,
                                  kwargs_source,
                                  kwargs_lens=None,
                                  unconvolved=False,
                                  de_lensed=False,
                                  k=None):
        """

        computes the source surface brightness distribution

        :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles
        :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles
        :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing)
        :param de_lensed: if True: returns the un-lensed source surface brightness profile, otherwise the lensed.
        :return: 1d array of surface brightness pixels
        """
        if len(self.SourceModel.profile_type_list) == 0:
            return np.zeros_like(self.Data.data)
        ra_grid, dec_grid = self.ImageNumerics.coordinates_evaluate
        if de_lensed is True:
            source_light = self.SourceModel.surface_brightness(ra_grid,
                                                               dec_grid,
                                                               kwargs_source,
                                                               k=k)
        else:
            source_light = self.source_mapping.image_flux_joint(ra_grid,
                                                                dec_grid,
                                                                kwargs_lens,
                                                                kwargs_source,
                                                                k=k)
        source_light_final = self.ImageNumerics.re_size_convolve(
            source_light, unconvolved=unconvolved)
        return source_light_final

    def lens_surface_brightness(self,
                                kwargs_lens_light,
                                unconvolved=False,
                                k=None):
        """

        computes the lens surface brightness distribution

        :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles
        :param unconvolved: if True, returns unconvolved surface brightness (perfect seeing), otherwise convolved with PSF kernel
        :return: 1d array of surface brightness pixels
        """
        if self.LensLightModel is None:
            return np.zeros_like(self.Data.data)
        ra_grid, dec_grid = self.ImageNumerics.coordinates_evaluate
        lens_light = self.LensLightModel.surface_brightness(ra_grid,
                                                            dec_grid,
                                                            kwargs_lens_light,
                                                            k=k)
        lens_light_final = self.ImageNumerics.re_size_convolve(
            lens_light, unconvolved=unconvolved)
        return lens_light_final

    def point_source(self,
                     kwargs_ps,
                     kwargs_lens=None,
                     unconvolved=False,
                     k=None):
        """

        computes the point source positions and paints PSF convolutions on them

        :param kwargs_ps:
        :param k:
        :return:
        """
        point_source_image = np.zeros_like(self.Data.data)
        if unconvolved or self.PointSource is None:
            return point_source_image
        ra_pos, dec_pos, amp, n_points = self.PointSource.linear_response_set(
            kwargs_ps, kwargs_lens, with_amp=True, k=k)
        for i in range(n_points):
            point_source_image += self.ImageNumerics.point_source_rendering(
                ra_pos[i], dec_pos[i], amp[i])
        return point_source_image

    def image(self,
              kwargs_lens=None,
              kwargs_source=None,
              kwargs_lens_light=None,
              kwargs_ps=None,
              unconvolved=False,
              source_add=True,
              lens_light_add=True,
              point_source_add=True):
        """

        make a image with a realisation of linear parameter values "param"

        :param kwargs_lens: list of keyword arguments corresponding to the superposition of different lens profiles
        :param kwargs_source: list of keyword arguments corresponding to the superposition of different source light profiles
        :param kwargs_lens_light: list of keyword arguments corresponding to different lens light surface brightness profiles
        :param kwargs_ps: keyword arguments corresponding to "other" parameters, such as external shear and point source image positions
        :param unconvolved: if True: returns the unconvolved light distribution (prefect seeing)
        :param source_add: if True, compute source, otherwise without
        :param lens_light_add: if True, compute lens light, otherwise without
        :param point_source_add: if True, add point sources, otherwise without
        :return: 1d array of surface brightness pixels of the simulation
        """
        if source_add:
            source_light = self.source_surface_brightness(
                kwargs_source, kwargs_lens, unconvolved=unconvolved)
        else:
            source_light = np.zeros_like(self.Data.data)
        if lens_light_add:
            lens_light = self.lens_surface_brightness(kwargs_lens_light,
                                                      unconvolved=unconvolved)
        else:
            lens_light = np.zeros_like(self.Data.data)
        if point_source_add:
            point_source = self.point_source(kwargs_ps,
                                             kwargs_lens,
                                             unconvolved=unconvolved)
        else:
            point_source = np.zeros_like(self.Data.data)
        model = (source_light + lens_light + point_source)
        return model

    def error_map(self, kwargs_lens, kwargs_ps):
        """

        :param kwargs_lens:
        :param kwargs_ps:
        :return:
        """
        error_map = np.zeros_like(self.Data.data)
        if self._psf_error_map is True:
            for k, bool in enumerate(self._error_map_bool_list):
                if bool is True:
                    ra_pos, dec_pos, amp, n_points = self.PointSource.linear_response_set(
                        kwargs_ps, kwargs_lens, k=k)
                    for i in range(0, n_points):
                        error_map_add = self.ImageNumerics.psf_error_map(
                            ra_pos[i], dec_pos[i], amp[i], self.Data.data)
                        error_map += error_map_add
        return error_map