class TestAdaptiveGrid(object): def setup(self): deltaPix = 1. transform_pix2angle = np.array([[1, 0], [0, 1]]) * deltaPix ra_at_xy_0, dec_at_xy_0 = -5, -5 nx, ny = 11, 11 self._supersampling_factor = 4 supersampling_indexes = np.zeros((nx, ny)) supersampling_indexes = np.array(supersampling_indexes, dtype=bool) supersampling_indexes[5, 5] = True self._supersampling_indexes = supersampling_indexes self.nx, self.ny = nx, ny self._adaptive_grid = AdaptiveGrid(nx, ny, transform_pix2angle, ra_at_xy_0, dec_at_xy_0, supersampling_indexes, self._supersampling_factor) def test_coordinates_evaluate(self): x_grid, y_grid = self._adaptive_grid.coordinates_evaluate print(np.shape(x_grid), 'test shape') assert len(x_grid) == self._supersampling_factor**2 + self.nx * self.ny - 1 def test_subpixel_coordinates(self): subpixel_x, subpixel_y = self._adaptive_grid._high_res_coordinates assert len(subpixel_x) == 4**2 assert subpixel_x[0] == -0.375 assert subpixel_y[0] == -0.375 assert subpixel_y[3] == -0.375 assert subpixel_x[3] == 0.375 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 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': 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 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
def setup(self): deltaPix = 1. transform_pix2angle = np.array([[1, 0], [0, 1]]) * deltaPix ra_at_xy_0, dec_at_xy_0 = -5, -5 nx, ny = 11, 11 self._supersampling_factor = 4 supersampling_indexes = np.zeros((nx, ny)) supersampling_indexes = np.array(supersampling_indexes, dtype=bool) supersampling_indexes[5, 5] = True self._supersampling_indexes = supersampling_indexes self.nx, self.ny = nx, ny self._adaptive_grid = AdaptiveGrid(nx, ny, transform_pix2angle, ra_at_xy_0, dec_at_xy_0, supersampling_indexes, self._supersampling_factor)
def __init__(self, nx, ny, transform_pix2angle, ra_at_xy_0, dec_at_xy_0, flux_evaluate_indexes, compute_indexes, supersampled_indexes, supersampling_factor, supersampling_kernel_size, kernel_super): self._grid = AdaptiveGrid(nx, ny, transform_pix2angle, ra_at_xy_0, dec_at_xy_0, supersampled_indexes, supersampling_factor, flux_evaluate_indexes) 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)
class AdaptiveNumerics(object): """ this class manages and computes a surface brightness convolved image in an adaptive approach. The strategie applied are: 1.1 surface brightness computation only where significant flux is expected 1.2 super sampled surface brightness only in regimes of high spacial variability in the surface brightness and at high contrast 2.1 convolution only applied where flux is present (avoid convolving a lot of zeros) 2.2 simplified Multi-Gaussian convolution in regimes of low contrast 2.3 (super-) sampled PSF convolution only at high contrast of highly variable sources the class performs the convolution with two different input arrays, one with low resolution and one on a subpart with high resolution """ def __init__(self, nx, ny, transform_pix2angle, ra_at_xy_0, dec_at_xy_0, flux_evaluate_indexes, compute_indexes, supersampled_indexes, supersampling_factor, supersampling_kernel_size, kernel_super): self._grid = AdaptiveGrid(nx, ny, transform_pix2angle, ra_at_xy_0, dec_at_xy_0, supersampled_indexes, supersampling_factor, flux_evaluate_indexes) 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) def re_size_convolve(self, flux_array): """ :param flux_array: 1d array, flux values corresponding to coordinates_evaluate :param array_low_res_partial: regular sampled surface brightness, 1d array :return: convolved image on regular pixel grid, 2d array """ # add supersampled region to lower resolution on image_low_res, image_high_res_partial = self._grid.flux_array2image_low_high( flux_array) # convolve low res grid and high res grid image_conv = self._conv.re_size_convolve(image_low_res, image_high_res_partial) return image_conv @property def coordinates_evaluate(self): """ :return: 1d array of all coordinates being evaluated to perform the image computation """ return self._grid.coordinates_evaluate
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
def __init__(self, pixel_grid, psf, supersampling_factor=1, compute_mode='regular', supersampling_convolution=True, supersampling_kernel_size=5, flux_evaluate_indexes=None, supersampled_indexes=None, compute_indexes=None): """ :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. """ # if no super sampling, turn the supersampling convolution off if supersampling_factor == 1: supersampling_convolution = False 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 compute_mode == 'adaptive' and supersampling_convolution is True and supersampling_factor > 1: kernel_super = psf.subgrid_point_source_kernel( 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': pass #self._conv = RegularConvolution(supersampling_factor=supersampling_factor, # supersampling_kernel_size=supersampling_kernel_size) else: raise ValueError( 'compute_mode %s not valid! Chose either regular or adaptive.' % compute_mode)