Ejemplo n.º 1
0
    def test_update_psf(self):
        fwhm = 0.3
        sigma = util.fwhm2sigma(fwhm)
        x_grid, y_grid = util.make_grid(numPix=31, deltapix=0.05)
        from lenstronomy.LightModel.Profiles.gaussian import Gaussian
        gaussian = Gaussian()
        kernel_point_source = gaussian.function(x_grid,
                                                y_grid,
                                                amp=1.,
                                                sigma_x=sigma,
                                                sigma_y=sigma,
                                                center_x=0,
                                                center_y=0)
        kernel_point_source /= np.sum(kernel_point_source)
        kernel_point_source = util.array2image(kernel_point_source)
        kwargs_psf = {
            'psf_type': 'PIXEL',
            'kernel_point_source': kernel_point_source
        }

        kwargs_psf_return, improved_bool = self.psf_fitting.update_psf(
            kwargs_psf,
            self.kwargs_lens,
            self.kwargs_source,
            self.kwargs_lens_light,
            self.kwargs_ps,
            factor=0.1,
            symmetry=1)
        assert improved_bool
        kernel_new = kwargs_psf_return['kernel_point_source']
        kernel_true = self.kwargs_psf['kernel_point_source']
        kernel_old = kwargs_psf['kernel_point_source']
        diff_old = np.sum((kernel_old - kernel_true)**2)
        diff_new = np.sum((kernel_new - kernel_true)**2)
        assert diff_old > diff_new
Ejemplo n.º 2
0
    def test_update_iterative(self):
        fwhm = 0.5
        sigma = util.fwhm2sigma(fwhm)
        x_grid, y_grid = util.make_grid(numPix=31, deltapix=0.05)
        from lenstronomy.LightModel.Profiles.gaussian import Gaussian
        gaussian = Gaussian()
        kernel_point_source = gaussian.function(x_grid, y_grid, amp=1., sigma_x=sigma, sigma_y=sigma,
                                              center_x=0, center_y=0)
        kernel_point_source /= np.sum(kernel_point_source)
        kernel_point_source = util.array2image(kernel_point_source)
        kwargs_psf = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_point_source}
        kwargs_psf_iter = {'stacking_method': 'median'}
        kwargs_psf_new = self.psf_fitting.update_iterative(kwargs_psf, self.kwargs_lens, self.kwargs_source,
                                                                       self.kwargs_lens_light, self.kwargs_ps,
                                                           **kwargs_psf_iter)
        kernel_new = kwargs_psf_new['kernel_point_source']
        kernel_true = self.kwargs_psf['kernel_point_source']
        kernel_old = kwargs_psf['kernel_point_source']
        diff_old = np.sum((kernel_old - kernel_true) ** 2)
        diff_new = np.sum((kernel_new - kernel_true) ** 2)
        assert diff_old > diff_new
        assert diff_new < 0.01

        kwargs_psf_new = self.psf_fitting.update_iterative(kwargs_psf, self.kwargs_lens, self.kwargs_source,
                                                           self.kwargs_lens_light, self.kwargs_ps, num_iter=3,
                                                           no_break=True)
        kernel_new = kwargs_psf_new['kernel_point_source']
        kernel_true = self.kwargs_psf['kernel_point_source']
        kernel_old = kwargs_psf['kernel_point_source']
        diff_old = np.sum((kernel_old - kernel_true) ** 2)
        diff_new = np.sum((kernel_new - kernel_true) ** 2)
        assert diff_old > diff_new
        assert diff_new < 0.01
Ejemplo n.º 3
0
    def test_update_psf(self):
        fwhm = 0.5
        sigma = util.fwhm2sigma(fwhm)
        x_grid, y_grid = util.make_grid(numPix=31, deltapix=0.05)
        from lenstronomy.LightModel.Profiles.gaussian import Gaussian
        gaussian = Gaussian()
        kernel_point_source = gaussian.function(x_grid,
                                                y_grid,
                                                amp=1.,
                                                sigma=sigma,
                                                center_x=0,
                                                center_y=0)
        kernel_point_source /= np.sum(kernel_point_source)
        kernel_point_source = util.array2image(kernel_point_source)
        kwargs_psf = {
            'psf_type': 'PIXEL',
            'kernel_point_source': kernel_point_source
        }

        kwargs_psf_iter = {'stacking_method': 'median'}
        #mag = np.ones_like(x_pos)

        kwargs_psf_return, improved_bool, error_map = self.psf_fitting.update_psf(
            kwargs_psf, self.kwargs_params, **kwargs_psf_iter)
        assert improved_bool
        kernel_new = kwargs_psf_return['kernel_point_source']
        kernel_true = self.kwargs_psf['kernel_point_source']
        kernel_old = kwargs_psf['kernel_point_source']
        diff_old = np.sum((kernel_old - kernel_true)**2)
        diff_new = np.sum((kernel_new - kernel_true)**2)
        assert diff_old > diff_new
Ejemplo n.º 4
0
    def psf_configure(self, psf_type="GAUSSIAN", fwhm=1, kernelsize=11, deltaPix=1, truncate=6, kernel=None):
        """

        :param psf_type:
        :param fwhm:
        :param pixel_grid:
        :return:
        """
        # psf_type: 'NONE', 'gaussian', 'pixel'
        # 'pixel': kernel, kernel_large
        # 'gaussian': 'sigma', 'truncate'
        if psf_type == 'GAUSSIAN':
            sigma = util.fwhm2sigma(fwhm)
            sigma_axis = sigma
            x_grid, y_grid = util.make_grid(kernelsize, deltaPix)
            kernel_large = self.gaussian.function(x_grid, y_grid, amp=1., sigma_x=sigma_axis, sigma_y=sigma_axis, center_x=0, center_y=0)
            kernel_large /= np.sum(kernel_large)
            kernel_large = util.array2image(kernel_large)
            kernel_pixel = kernel_util.pixel_kernel(kernel_large)
            kwargs_psf = {'psf_type': psf_type, 'fwhm': fwhm, 'truncation': truncate*fwhm, 'kernel_point_source': kernel_large, 'kernel_pixel': kernel_pixel, 'pixel_size': deltaPix}
        elif psf_type == 'PIXEL':
            kernel_large = copy.deepcopy(kernel)
            kernel_large = kernel_util.cut_psf(kernel_large, psf_size=kernelsize)
            kernel_small = copy.deepcopy(kernel)
            kernel_small = kernel_util.cut_psf(kernel_small, psf_size=kernelsize)
            kwargs_psf = {'psf_type': "PIXEL", 'kernel_pixel': kernel_small, 'kernel_point_source': kernel_large}
        elif psf_type == 'NONE':
            kwargs_psf = {'psf_type': 'NONE'}
        else:
            raise ValueError("psf type %s not supported!" % psf_type)
        psf_class = PSF(kwargs_psf)
        return psf_class
Ejemplo n.º 5
0
    def test_update_iterative(self):
        fwhm = 0.5
        sigma = util.fwhm2sigma(fwhm)
        x_grid, y_grid = util.make_grid(numPix=31, deltapix=0.05)
        from lenstronomy.LightModel.Profiles.gaussian import Gaussian
        gaussian = Gaussian()
        kernel_point_source = gaussian.function(x_grid,
                                                y_grid,
                                                amp=1.,
                                                sigma=sigma,
                                                center_x=0,
                                                center_y=0)
        kernel_point_source /= np.sum(kernel_point_source)
        kernel_point_source = util.array2image(kernel_point_source)
        kwargs_psf = {
            'psf_type': 'PIXEL',
            'kernel_point_source': kernel_point_source,
            'kernel_point_source_init': kernel_point_source
        }
        kwargs_psf_iter = {
            'stacking_method': 'median',
            'psf_symmetry': 2,
            'psf_iter_factor': 0.2,
            'block_center_neighbour': 0.1,
            'error_map_radius': 0.5,
            'new_procedure': False,
            'no_break': False,
            'verbose': True,
            'keep_psf_error_map': False
        }

        kwargs_params = copy.deepcopy(self.kwargs_params)
        kwargs_ps = kwargs_params['kwargs_ps']
        del kwargs_ps[0]['source_amp']
        print(kwargs_params['kwargs_ps'])
        kwargs_psf_new = self.psf_fitting.update_iterative(
            kwargs_psf, kwargs_params, **kwargs_psf_iter)
        kernel_new = kwargs_psf_new['kernel_point_source']
        kernel_true = self.kwargs_psf['kernel_point_source']
        kernel_old = kwargs_psf['kernel_point_source']
        diff_old = np.sum((kernel_old - kernel_true)**2)
        diff_new = np.sum((kernel_new - kernel_true)**2)
        assert diff_old > diff_new
        assert diff_new < 0.01
        assert 'psf_error_map' in kwargs_psf_new

        kwargs_psf_new = self.psf_fitting.update_iterative(
            kwargs_psf,
            kwargs_params,
            num_iter=3,
            no_break=True,
            keep_psf_error_map=True)
        kernel_new = kwargs_psf_new['kernel_point_source']
        kernel_true = self.kwargs_psf['kernel_point_source']
        kernel_old = kwargs_psf['kernel_point_source']
        diff_old = np.sum((kernel_old - kernel_true)**2)
        diff_new = np.sum((kernel_new - kernel_true)**2)
        assert diff_old > diff_new
        assert diff_new < 0.01
Ejemplo n.º 6
0
    def __init__(self, kernel, truncation=4):
        """

        :param kernel: 2d kernel
        :param truncation: sigma scaling of kernel truncation
        """
        fwhm = kernel_util.fwhm_kernel(kernel)
        self._sigma = util.fwhm2sigma(fwhm)
        self._truncation = truncation
Ejemplo n.º 7
0
def kernel_gaussian(kernel_numPix, deltaPix, fwhm):
    sigma = util.fwhm2sigma(fwhm)
    #if kernel_numPix % 2 == 0:
    #    kernel_numPix += 1
    x_grid, y_grid = util.make_grid(kernel_numPix, deltaPix)
    gaussian = Gaussian()
    kernel = gaussian.function(x_grid, y_grid, amp=1., sigma=sigma, center_x=0, center_y=0)
    kernel /= np.sum(kernel)
    kernel = util.array2image(kernel)
    return kernel
Ejemplo n.º 8
0
    def __init__(self, psf_type='NONE', fwhm=None, truncation=5, pixel_size=None, kernel_point_source=None,
                 psf_error_map=None, point_source_supersampling_factor=1, kernel_point_source_init=None):
        """

        :param psf_type: string, type of PSF: options are 'NONE', 'PIXEL', 'GAUSSIAN'
        :param fwhm: float, full width at half maximum, only required for 'GAUSSIAN' model
        :param truncation: float, Gaussian truncation (in units of sigma), only required for 'GAUSSIAN' model
        :param pixel_size: width of pixel (required for Gaussian model, not required when using in combination with ImageModel modules)
        :param kernel_point_source: 2d numpy array, odd length, centered PSF of a point source
         (if not normalized, will be normalized)
        :param psf_error_map: uncertainty in the PSF model per pixel (size of data, not super-sampled). 2d numpy array.
        Size can be larger or smaller than the pixel-sized PSF model and if so, will be matched.
        This error will be added to the pixel error around the position of point sources as follows:
        sigma^2_i += 'psf_error_map'_j * (point_source_flux_i)**2
        :param point_source_supersampling_factor: int, supersampling factor of kernel_point_source
        :param kernel_point_source_init: memory of an initial point source kernel that gets passed through the psf iteration
        """
        self.psf_type = psf_type
        self._pixel_size = pixel_size
        self.kernel_point_source_init = kernel_point_source_init
        if self.psf_type == 'GAUSSIAN':
            if fwhm is None:
                raise ValueError('fwhm must be set for GAUSSIAN psf type!')
            self._fwhm = fwhm
            self._sigma_gaussian = util.fwhm2sigma(self._fwhm)
            self._truncation = truncation
            self._point_source_supersampling_factor = 0
        elif self.psf_type == 'PIXEL':
            if kernel_point_source is None:
                raise ValueError('kernel_point_source needs to be specified for PIXEL PSF type!')
            if len(kernel_point_source) % 2 == 0:
                raise ValueError('kernel needs to have odd axis number, not ', np.shape(kernel_point_source))
            if point_source_supersampling_factor > 1:
                self._kernel_point_source_supersampled = kernel_point_source
                self._point_source_supersampling_factor = point_source_supersampling_factor
                kernel_point_source = kernel_util.degrade_kernel(self._kernel_point_source_supersampled, self._point_source_supersampling_factor)
            self._kernel_point_source = kernel_point_source / np.sum(kernel_point_source)

        elif self.psf_type == 'NONE':
            self._kernel_point_source = np.zeros((3, 3))
            self._kernel_point_source[1, 1] = 1
        else:
            raise ValueError("psf_type %s not supported!" % self.psf_type)
        if psf_error_map is not None:
            n_kernel = len(self.kernel_point_source)
            self._psf_error_map = kernel_util.match_kernel_size(psf_error_map, n_kernel)
            if self.psf_type == 'PIXEL' and point_source_supersampling_factor > 1:
                if len(psf_error_map) == len(self._kernel_point_source_supersampled):
                    Warning('psf_error_map has the same size as the super-sampled kernel. Make sure the units in the'
                            'psf_error_map are on the down-sampled pixel scale.')
            self.psf_error_map_bool = True
        else:
            self.psf_error_map_bool = False
Ejemplo n.º 9
0
def psf_configure_simple(psf_type="GAUSSIAN",
                         fwhm=1,
                         kernelsize=11,
                         deltaPix=1,
                         truncate=6,
                         kernel=None):
    """
    this routine generates keyword arguments to initialize a PSF() class in lenstronomy. Have a look at the PSF class
    documentation to see the full possibilities.

    :param psf_type: string, type of PSF model
    :param fwhm: Full width at half maximum of PSF (if GAUSSIAN psf)
    :param kernelsize: size in pixel of kernel (use odd numbers), only applicable for PIXEL kernels
    :param deltaPix: pixel size in angular units (only needed for GAUSSIAN kernel
    :param truncate: how many sigmas out is the truncation happening
    :param kernel: 2d numpy arra centered PSF (odd number per axis)
    :return: keyword arguments
    """

    if psf_type == 'GAUSSIAN':
        sigma = util.fwhm2sigma(fwhm)
        sigma_axis = sigma
        gaussian = Gaussian()
        x_grid, y_grid = util.make_grid(kernelsize, deltaPix)
        kernel_large = gaussian.function(x_grid,
                                         y_grid,
                                         amp=1.,
                                         sigma_x=sigma_axis,
                                         sigma_y=sigma_axis,
                                         center_x=0,
                                         center_y=0)
        kernel_large /= np.sum(kernel_large)
        kernel_large = util.array2image(kernel_large)
        kernel_pixel = kernel_util.pixel_kernel(kernel_large)
        kwargs_psf = {
            'psf_type': psf_type,
            'fwhm': fwhm,
            'truncation': truncate * fwhm,
            'kernel_point_source': kernel_large,
            'kernel_pixel': kernel_pixel,
            'pixel_size': deltaPix
        }
    elif psf_type == 'PIXEL':
        kernel_large = copy.deepcopy(kernel)
        kernel_large = kernel_util.cut_psf(kernel_large, psf_size=kernelsize)
        kwargs_psf = {'psf_type': "PIXEL", 'kernel_point_source': kernel_large}
    elif psf_type == 'NONE':
        kwargs_psf = {'psf_type': 'NONE'}
    else:
        raise ValueError("psf type %s not supported!" % psf_type)
    return kwargs_psf
Ejemplo n.º 10
0
    def __init__(self, kwargs_psf):
        self.psf_type = kwargs_psf.get('psf_type', 'NONE')
        if self.psf_type == 'GAUSSIAN':
            self._fwhm = kwargs_psf['fwhm']
            self._sigma_gaussian = util.fwhm2sigma(self._fwhm)
            self._truncation = kwargs_psf.get('truncation', 5 * self._fwhm)
            if 'pixel_size' in kwargs_psf:
                self._pixel_size = kwargs_psf['pixel_size']
        elif self.psf_type == 'PIXEL':
            if 'kernel_point_source_subsampled' in kwargs_psf:
                self._kernel_point_source_subsampled = kwargs_psf[
                    'kernel_point_source_subsampled']
                n_high = len(self._kernel_point_source_subsampled)
                self._point_source_subsampling_factor = kwargs_psf[
                    'point_source_subsampling_factor']
                numPix = int(n_high / self._point_source_subsampling_factor)
                self._kernel_point_source = util.averaging(
                    self._kernel_point_source_subsampled,
                    numGrid=n_high,
                    numPix=numPix)
            else:
                self._kernel_point_source = kwargs_psf['kernel_point_source']
            if 'kernel_pixel_subsampled' in kwargs_psf:
                self._kernel_pixel_subsampled = kwargs_psf[
                    'kernel_pixel_subsampled']
                n_high = len(self._kernel_point_source_subsampled)
                self._pixel_subsampling_factor = kwargs_psf[
                    'pixel_subsampling_factor']
                numPix = int(n_high / self._pixel_subsampling_factor)
                self._kernel_pixel = util.averaging(
                    self._kernel_pixel_subsampled,
                    numGrid=n_high,
                    numPix=numPix)
            else:
                if 'kernel_pixel' in kwargs_psf:
                    self._kernel_pixel = kwargs_psf['kernel_pixel']
                else:
                    self._kernel_pixel = kernel_util.pixel_kernel(
                        self._kernel_point_source, subgrid_res=1)

        elif self.psf_type == 'NONE':
            self._kernel_point_source = np.zeros((3, 3))
            self._kernel_point_source[1, 1] = 1
        else:
            raise ValueError("psf_type %s not supported!" % self.psf_type)
        if 'psf_error_map' in kwargs_psf:
            self._psf_error_map = kwargs_psf['psf_error_map']
            if len(self._psf_error_map) != len(self._kernel_point_source):
                raise ValueError(
                    'psf_error_map must have same size as kernel_point_source!'
                )
Ejemplo n.º 11
0
 def __init__(self, kwargs_psf):
     self.psf_type = kwargs_psf.get('psf_type', 'NONE')
     if self.psf_type == 'GAUSSIAN':
         self._fwhm = kwargs_psf['fwhm']
         self._sigma_gaussian = util.fwhm2sigma(self._fwhm)
         self._truncation = kwargs_psf.get('truncation', 5 * self._fwhm)
         if 'pixel_size' in kwargs_psf:
             self._pixel_size = kwargs_psf['pixel_size']
     elif self.psf_type == 'PIXEL':
         self._kernel_point_source = kwargs_psf['kernel_point_source']
         if 'kernel_pixel' in kwargs_psf:
             self._kernel_pixel = kwargs_psf['kernel_pixel']
         else:
             self._kernel_pixel = kernel_util.pixel_kernel(self._kernel_point_source, subgrid_res=7)
     elif self.psf_type == 'NONE':
         self._kernel_point_source = np.zeros((3, 3))
     else:
         raise ValueError("psf_type %s not supported!" % self.psf_type)
     if 'psf_error_map' in kwargs_psf:
         self._psf_error_map = kwargs_psf['psf_error_map']
Ejemplo n.º 12
0
    def setup(self):

        # data specifics
        sigma_bkg = 0.01  # background noise per pixel
        exp_time = 100  # exposure time (arbitrary units, flux per pixel is in units #photons/exp_time unit)
        numPix = 100  # cutout pixel size
        deltaPix = 0.05  # pixel size in arcsec (area per pixel = deltaPix**2)
        fwhm = 0.3  # full width half max of PSF

        # PSF specification

        kwargs_data = sim_util.data_configure_simple(numPix, deltaPix, exp_time, sigma_bkg)
        data_class = Data(kwargs_data)
        sigma = util.fwhm2sigma(fwhm)
        x_grid, y_grid = util.make_grid(numPix=31, deltapix=0.05)
        from lenstronomy.LightModel.Profiles.gaussian import Gaussian
        gaussian = Gaussian()
        kernel_point_source = gaussian.function(x_grid, y_grid, amp=1., sigma_x=sigma, sigma_y=sigma,
                                                center_x=0, center_y=0)
        kernel_point_source /= np.sum(kernel_point_source)
        kernel_point_source = util.array2image(kernel_point_source)
        self.kwargs_psf = {'psf_type': 'PIXEL', 'kernel_point_source': kernel_point_source}

        psf_class = PSF(kwargs_psf=self.kwargs_psf)

        # 'EXERNAL_SHEAR': external shear
        kwargs_shear = {'e1': 0.01, 'e2': 0.01}  # gamma_ext: shear strength, psi_ext: shear angel (in radian)
        phi, q = 0.2, 0.8
        e1, e2 = param_util.phi_q2_ellipticity(phi, q)
        kwargs_spemd = {'theta_E': 1., 'gamma': 1.8, 'center_x': 0, 'center_y': 0, 'e1': e1, 'e2': e2}

        lens_model_list = ['SPEP', 'SHEAR']
        self.kwargs_lens = [kwargs_spemd, kwargs_shear]
        lens_model_class = LensModel(lens_model_list=lens_model_list)
        # list of light profiles (for lens and source)
        # 'SERSIC': spherical Sersic profile
        kwargs_sersic = {'amp': 1., 'R_sersic': 0.1, 'n_sersic': 2, 'center_x': 0, 'center_y': 0}
        # 'SERSIC_ELLIPSE': elliptical Sersic profile
        phi, q = 0.2, 0.9
        e1, e2 = param_util.phi_q2_ellipticity(phi, q)
        kwargs_sersic_ellipse = {'amp': 1., 'R_sersic': .6, 'n_sersic': 7, 'center_x': 0, 'center_y': 0,
                                 'e1': e1, 'e2': e2}

        lens_light_model_list = ['SERSIC']
        self.kwargs_lens_light = [kwargs_sersic]
        lens_light_model_class = LightModel(light_model_list=lens_light_model_list)
        source_model_list = ['SERSIC_ELLIPSE']
        self.kwargs_source = [kwargs_sersic_ellipse]
        source_model_class = LightModel(light_model_list=source_model_list)
        self.kwargs_ps = [{'ra_source': 0.0, 'dec_source': 0.0,
                           'source_amp': 10.}]  # quasar point source position in the source plane and intrinsic brightness
        point_source_class = PointSource(point_source_type_list=['SOURCE_POSITION'], fixed_magnification_list=[True])
        kwargs_numerics = {'subgrid_res': 3, 'psf_subgrid': True}
        imageModel = ImageModel(data_class, psf_class, lens_model_class, source_model_class,
                                     lens_light_model_class,
                                     point_source_class, kwargs_numerics=kwargs_numerics)
        image_sim = sim_util.simulate_simple(imageModel, self.kwargs_lens, self.kwargs_source,
                                         self.kwargs_lens_light, self.kwargs_ps)
        data_class.update_data(image_sim)
        self.imageModel = ImageModel(data_class, psf_class, lens_model_class, source_model_class,
                                lens_light_model_class,
                                point_source_class, kwargs_numerics=kwargs_numerics)

        self.psf_fitting = PsfFitting(self.imageModel)
Ejemplo n.º 13
0
def test_fwhm2sigma():
    fwhm = 0.5
    sigma = util.fwhm2sigma(fwhm)
    assert sigma == fwhm / (2 * np.sqrt(2 * np.log(2)))
Ejemplo n.º 14
0
    def __init__(self,
                 pixel_grid,
                 psf,
                 supersampling_factor=1,
                 compute_mode='regular',
                 supersampling_convolution=False,
                 supersampling_kernel_size=5,
                 flux_evaluate_indexes=None,
                 supersampled_indexes=None,
                 compute_indexes=None,
                 point_source_supersampling_factor=1,
                 convolution_kernel_size=None,
                 convolution_type='fft_static',
                 truncation=4):
        """

        :param pixel_grid: PixelGrid() class instance
        :param psf: PSF() class instance
        :param compute_mode: options are: 'regular', 'adaptive'
        :param supersampling_factor: int, factor of higher resolution sub-pixel sampling of surface brightness
        :param supersampling_convolution: bool, if True, performs (part of) the convolution on the super-sampled
        grid/pixels
        :param supersampling_kernel_size: int (odd number), size (in regular pixel units) of the super-sampled
        convolution
        :param flux_evaluate_indexes: boolean 2d array of size of image (or None, then initiated as gird of True's).
        Pixels indicated with True will be used to perform the surface brightness computation (and possible lensing
        ray-shooting). Pixels marked as False will be assigned a flux value of zero (or ignored in the adaptive
        convolution)
        :param supersampled_indexes: 2d boolean array (only used in mode='adaptive') of pixels to be supersampled (in
        surface brightness and if supersampling_convolution=True also in convolution)
        :param compute_indexes: 2d boolean array (only used in mode='adaptive'), marks pixel that the resonse after
        convolution is computed (all others =0). This can be set to likelihood_mask in the Likelihood module for
        consistency.
        :param point_source_supersampling_factor: super-sampling resolution of the point source placing
        :param convolution_kernel_size: int, odd number, size of convolution kernel. If None, takes size of point_source_kernel
        :param convolution_type: string, 'fft', 'grid', 'fft_static' mode of 2d convolution
        """
        if compute_mode not in ['regular', 'adaptive']:
            raise ValueError(
                'compute_mode specified as %s not valid. Options are "adaptive", "regular"'
            )
        # if no super sampling, turn the supersampling convolution off
        self._psf_type = psf.psf_type
        if not isinstance(supersampling_factor, int):
            raise TypeError(
                'supersampling_factor needs to be an integer! Current type is %s'
                % type(supersampling_factor))
        if supersampling_factor == 1:
            supersampling_convolution = False
        self._pixel_width = pixel_grid.pixel_width
        nx, ny = pixel_grid.num_pixel_axes
        transform_pix2angle = pixel_grid.transform_pix2angle
        ra_at_xy_0, dec_at_xy_0 = pixel_grid.radec_at_xy_0
        if supersampled_indexes is None:
            supersampled_indexes = np.zeros((nx, ny), dtype=bool)
        if compute_mode == 'adaptive':  # or (compute_mode == 'regular' and supersampling_convolution is False and supersampling_factor > 1):
            self._grid = AdaptiveGrid(nx, ny, transform_pix2angle, ra_at_xy_0,
                                      dec_at_xy_0, supersampled_indexes,
                                      supersampling_factor,
                                      flux_evaluate_indexes)
        else:
            self._grid = RegularGrid(nx, ny, transform_pix2angle, ra_at_xy_0,
                                     dec_at_xy_0, supersampling_factor,
                                     flux_evaluate_indexes)
        if self._psf_type == 'PIXEL':
            if compute_mode == 'adaptive' and supersampling_convolution is True:
                from lenstronomy.ImSim.Numerics.adaptive_numerics import AdaptiveConvolution
                kernel_super = psf.kernel_point_source_supersampled(
                    supersampling_factor)
                kernel_super = self._supersampling_cut_kernel(
                    kernel_super, convolution_kernel_size,
                    supersampling_factor)
                self._conv = AdaptiveConvolution(
                    kernel_super,
                    supersampling_factor,
                    conv_supersample_pixels=supersampled_indexes,
                    supersampling_kernel_size=supersampling_kernel_size,
                    compute_pixels=compute_indexes,
                    nopython=True,
                    cache=True,
                    parallel=False)

            elif compute_mode == 'regular' and supersampling_convolution is True:
                kernel_super = psf.kernel_point_source_supersampled(
                    supersampling_factor)
                if convolution_kernel_size is not None:
                    kernel_super = psf.kernel_point_source_supersampled(
                        supersampling_factor)
                    kernel_super = self._supersampling_cut_kernel(
                        kernel_super, convolution_kernel_size,
                        supersampling_factor)
                self._conv = SubgridKernelConvolution(
                    kernel_super,
                    supersampling_factor,
                    supersampling_kernel_size=supersampling_kernel_size,
                    convolution_type=convolution_type)
            else:
                kernel = psf.kernel_point_source
                kernel = self._supersampling_cut_kernel(
                    kernel, convolution_kernel_size, supersampling_factor=1)
                self._conv = PixelKernelConvolution(
                    kernel, convolution_type=convolution_type)

        elif self._psf_type == 'GAUSSIAN':
            pixel_scale = pixel_grid.pixel_width
            fwhm = psf.fwhm  # FWHM  in units of angle
            sigma = util.fwhm2sigma(fwhm)
            sigma_list = [sigma]
            fraction_list = [1]
            self._conv = MultiGaussianConvolution(sigma_list,
                                                  fraction_list,
                                                  pixel_scale,
                                                  supersampling_factor,
                                                  supersampling_convolution,
                                                  truncation=truncation)
        elif self._psf_type == 'NONE':
            self._conv = None
        else:
            raise ValueError(
                'psf_type %s not valid! Chose either NONE, GAUSSIAN or PIXEL.'
                % self._psf_type)
        super(Numerics, self).__init__(
            pixel_grid=pixel_grid,
            supersampling_factor=point_source_supersampling_factor,
            psf=psf)
        if supersampling_convolution is True:
            self._high_res_return = True
        else:
            self._high_res_return = False
Ejemplo n.º 15
0
    def magnification_finite_adaptive(self,
                                      x_image,
                                      y_image,
                                      source_x,
                                      source_y,
                                      kwargs_lens,
                                      source_fwhm_parsec,
                                      z_source,
                                      cosmo=None,
                                      grid_resolution=None,
                                      grid_radius_arcsec=None,
                                      axis_ratio=0.5,
                                      tol=0.001,
                                      step_size=0.05,
                                      use_largest_eigenvalue=True):
        """
        This method computes image magnifications with a finite-size background source assuming a Gaussian
        source light profile. It can be much faster that magnification_finite for lens models with many
        deflectors and a relatively compact source. This is because most pixels in a rectangular window around a lensed
        image of a compact source will contain zero flux, and therefore don't contribute to the image brightness.

        Rather than ray tracing through a rectangular grid, this routine accelerates the computation of image
        magnifications with finite-size sources by ray tracing through an elliptical aperture oriented such that
        it resembles the surface brightness of the lensed image itself. The aperture size is initially quite small,
        and increases in size until the flux inside of it (and hence the magnification) converges. The orientation of
        the elliptical aperture is computed from the magnification tensor at the image coordinate.

        If for whatever reason you prefer a circular aperture to the elliptical approximation using the hessian eigenvectors,
        you can just set axis_ratio = 1.

        To use the eigenvalues of the hessian matrix to estimate the optimum axis ratio, set axis_ratio = 0.

        The default settings for the grid resolution and ray tracing window size work well for sources with fwhm between
        0.5 - 100 pc.

        :param x_image: a list or array of x coordinates [units arcsec]
        :param y_image: a list or array of y coordinates [units arcsec]
        :param kwargs_lens: keyword arguments for the lens model
        :param source_fwhm_parsec: the size of the background source [units parsec]
        :param z_source: the source redshift
        :param cosmo: (optional) an instance of astropy.cosmology; if not specified, a default cosmology will be used
        :param grid_resolution: the grid resolution in units arcsec/pixel; if not specified, an appropriate value will
        be estimated from the source size
        :param grid_radius_arcsec: (optional) the size of the ray tracing region in arcsec; if not specified, an appropriate value
        will be estimated from the source size
        :param axis_ratio: the axis ratio of the ellipse used for ray tracing; if axis_ratio = 0, then the eigenvalues
        the hessian matrix will be used to estimate an appropriate axis ratio. Be warned: if the image is highly
        magnified it will tend to curve out of the resulting ellipse
        :param tol: tolerance for convergence in the magnification
        :param step_size: sets the increment for the successively larger ray tracing windows
        :param use_largest_eigenvalue: bool; if True, then the major axis of the ray tracing ellipse region
        will be aligned with the eigenvector corresponding to the largest eigenvalue of the hessian matrix
        :return: an array of image magnifications
        """

        if cosmo is None:
            cosmo = self._lensModel.cosmo

        if grid_radius_arcsec is None:
            grid_radius_arcsec = auto_raytracing_grid_size(source_fwhm_parsec)
        if grid_resolution is None:
            grid_resolution = auto_raytracing_grid_resolution(
                source_fwhm_parsec)

        pc_per_arcsec = 1000 / cosmo.arcsec_per_kpc_proper(z_source).value
        source_fwhm_arcsec = source_fwhm_parsec / pc_per_arcsec
        source_sigma_arcsec = fwhm2sigma(source_fwhm_arcsec)
        kwargs_source = [{
            'amp': 1.,
            'center_x': source_x,
            'center_y': source_y,
            'sigma': source_sigma_arcsec
        }]
        source_model = LightModel(['GAUSSIAN'])

        npix = int(2 * grid_radius_arcsec / grid_resolution)
        _grid_x = np.linspace(-grid_radius_arcsec, grid_radius_arcsec, npix)
        _grid_y = np.linspace(-grid_radius_arcsec, grid_radius_arcsec, npix)

        magnifications = []
        minimum_magnification = 1e-4
        grid_x_0, grid_y_0 = np.meshgrid(_grid_x, _grid_y)
        grid_x_0, grid_y_0 = grid_x_0.ravel(), grid_y_0.ravel()

        for xi, yi in zip(x_image, y_image):

            w1, w2, v11, v12, v21, v22 = self.hessian_eigenvectors(
                xi, yi, kwargs_lens)
            _v = [np.array([v11, v12]), np.array([v21, v22])]
            _w = [abs(w1), abs(w2)]
            if use_largest_eigenvalue:
                idx = int(np.argmax(_w))
            else:
                idx = int(np.argmin(_w))
            v = _v[idx]

            rotation_angle = np.arctan(v[1] / v[0]) - np.pi / 2
            grid_x, grid_y = util.rotate(grid_x_0, grid_y_0, rotation_angle)

            if axis_ratio == 0:
                sort = np.argsort(_w)
                q = _w[sort[0]] / _w[sort[1]]
                grid_r = np.hypot(grid_x, grid_y / q).ravel()
            else:
                grid_r = np.hypot(grid_x, grid_y / axis_ratio).ravel()

            flux_array = np.zeros_like(grid_x_0)
            step = step_size * grid_radius_arcsec
            r_min = 0
            r_max = step
            magnification_current = 0.

            while True:

                flux_array = self._magnification_adaptive_iteration(
                    flux_array, xi, yi, grid_x_0, grid_y_0, grid_r, r_min,
                    r_max, self._lensModel, kwargs_lens, source_model,
                    kwargs_source)
                new_magnification = np.sum(flux_array) * grid_resolution**2
                diff = abs(new_magnification -
                           magnification_current) / new_magnification

                # the sqrt(2) will allow this algorithm to fill up the entire square window
                if r_max > np.sqrt(2) * grid_radius_arcsec:
                    break
                elif diff < tol and new_magnification > minimum_magnification:
                    break
                else:
                    r_min += step
                    r_max += step
                    magnification_current = new_magnification

            magnifications.append(new_magnification)

        return np.array(magnifications)
def setup_mag_finite(cosmo, lens_model, grid_radius_arcsec, grid_resolution, source_fwhm_parsec, source_light_model, z_source,
                     source_x, source_y, dx, dy, amp_scale, size_scale):

    """
    Sets up the ray tracing grid and source light model for magnification_finite_adaptive and
    plot_quasar_images routines
    :param cosmo: (optional) an instance of astropy.cosmology; if not specified, a default cosmology will be used
    :param lens_model: an instance of LensModel
    :param grid_radius_arcsec: (optional) the size of the ray tracing region in arcsec; if not specified, an appropriate value
    will be estimated from the source size
    :param grid_resolution: the grid resolution in units arcsec/pixel; if not specified, an appropriate value will
    be estimated from the source size
    :param source_fwhm_parsec: the size of the background source [units parsec]
    :param source_light_model: the model for background source light; currently implemented are 'SINGLE_GAUSSIAN' and
    'DOUBLE_GAUSSIAN'.
    :param z_source: source redshift
    :param source_x: source x position [arcsec]
    :param source_y: source y position [arcsec]
    :param dx: used with source model 'DOUBLE_GAUSSIAN', the offset of the second source light profile from the first
    [arcsec]
    :param dy: used with source model 'DOUBLE_GAUSSIAN', the offset of the second source light profile from the first
    [arcsec]
    :param amp_scale: used with source model 'DOUBLE_GAUSSIAN', the peak brightness of the second source light profile
    relative to the first
    :param size_scale: used with source model 'DOUBLE_GAUSSIAN', the size of the second source light profile relative
    to the first
    :return: x coordinate grid, y coordinate grid, source light model, and keywords for the source light model
    """
    if cosmo is None:
        cosmo = lens_model.cosmo

    if grid_radius_arcsec is None:
        grid_radius_arcsec = auto_raytracing_grid_size(source_fwhm_parsec)
    if grid_resolution is None:
        grid_resolution = auto_raytracing_grid_resolution(source_fwhm_parsec)

    pc_per_arcsec = 1000 / cosmo.arcsec_per_kpc_proper(z_source).value
    source_fwhm_arcsec = source_fwhm_parsec / pc_per_arcsec
    source_sigma_arcsec = fwhm2sigma(source_fwhm_arcsec)

    if source_light_model == 'SINGLE_GAUSSIAN':
        kwargs_source = [{'amp': 1., 'center_x': source_x, 'center_y': source_y, 'sigma': source_sigma_arcsec}]
        source_model = LightModel(['GAUSSIAN'])
    elif source_light_model == 'DOUBLE_GAUSSIAN':
        amp_1 = 1.
        kwargs_source_1 = [{'amp': amp_1, 'center_x': source_x, 'center_y': source_y, 'sigma': source_sigma_arcsec}]
        # c = amp / (2 * np.pi * sigma**2)
        amp_2 = amp_1 * amp_scale * size_scale ** 2
        kwargs_source_2 = [{'amp': amp_2, 'center_x': source_x + dx, 'center_y': source_y + dy,
                            'sigma': source_sigma_arcsec * size_scale}]
        kwargs_source = kwargs_source_1 + kwargs_source_2
        source_model = LightModel(['GAUSSIAN'] * 2)
    else:
        raise Exception('source light model must be specified, currently implemented models are  SINGLE_GAUSSIAN '
                        'and DOUBLE_GAUSSIAN')

    npix = int(2 * grid_radius_arcsec / grid_resolution)
    _grid_x = np.linspace(-grid_radius_arcsec, grid_radius_arcsec, npix)
    _grid_y = np.linspace(-grid_radius_arcsec, grid_radius_arcsec, npix)
    grid_x_0, grid_y_0 = np.meshgrid(_grid_x, _grid_y)

    return grid_x_0, grid_y_0, source_model, kwargs_source, grid_resolution, grid_radius_arcsec