def make_psf(configuration): # The psf parameters in terms of the input parameters. To simulate the different pixel size # we set the sigma of the psf to be a multiple (according to the ratio input) # of the actual sigma in data pixel units. # This should correspond, when ratio>1 to the case when the PSF's resolution is bigger # than the image. If the ratio is 1 than they have the same pixel size. psf_sigma = configuration.psf_sigma * configuration.resolution_ratio psf_amplitude = configuration.psf_amplitude psf_position = configuration.psf_position # We model the PSF as a gaussian as well. Note we are using the psf_sigma variable, # that is the one which is scaled through the ration. In other terms, we are working in # units of Data Pixels to simulate the conditions of the bug, when the ratio != 1. psf, psf_x, psf_y = symmetric_gaussian_image(amplitude=psf_amplitude, sigma=psf_sigma, position=psf_position, n_bins=configuration.psf_size) # Normalize PSF norm_psf = psf / psf.sum() cdelt = DATA_PIXEL_SIZE / configuration.resolution_ratio psf_wcs = WcsStub([cdelt, cdelt]) # Create a Sherpa PSF model object using the psf arrays sherpa_kernel = DataIMG('kernel_data', psf_x, psf_y, norm_psf, shape=(configuration.psf_size, configuration.psf_size), sky=psf_wcs ) psf_model = PSFModel('psf_model', kernel=sherpa_kernel) psf_model.norm = 1 psf_model.origin = (psf_position + 1, psf_position + 1) return psf, psf_model
def make_data(data_class): """Create a test data object of the given class. Using a string means it is easier to support the various PHA "types" - eg basic, grouping, grouping+quality. """ x0 = np.asarray([1, 3, 7, 12]) y = np.asarray([2, 3, 4, 5]) if data_class == "1d": return Data1D('x1', x0, y) if data_class == "1dint": return Data1DInt('xint1', x0, np.asarray([3, 5, 8, 15]), y) chans = np.arange(1, 5) if data_class == "pha": return DataPHA('pha', chans, y) # We want to provide PHA tests that check out the grouping and # quality handling (but it is not worth trying all different # variants), so we have "grp" for grouping and no quality [*], and # "qual" for grouping and quality. # # [*] by which I mean we have not called ignore_bad, not that # there is no quality array. # grp = np.asarray([1, -1, 1, 1]) qual = np.asarray([0, 0, 2, 0]) pha = DataPHA('pha', chans, y, grouping=grp, quality=qual) if data_class == "grp": return pha if data_class == "qual": pha.ignore_bad() return pha x0 = np.asarray([1, 2, 3] * 2) x1 = np.asarray([1, 1, 1, 2, 2, 2]) y = np.asarray([2, 3, 4, 5, 6, 7]) if data_class == "2d": return Data2D('x2', x0, x1, y, shape=(2, 3)) if data_class == "2dint": return Data2DInt('xint2', x0, x1, x0 + 1, x1 + 1, y, shape=(2, 3)) if data_class == "img": return DataIMG('img', x0, x1, y, shape=(2, 3)) if data_class == "imgint": return DataIMGInt('imgi', x0, x1, x0 + 1, x1 + 1, y, shape=(2, 3)) assert False
def make_image(configuration): source_position = configuration.source_position # The convolution of two gaussians is a gaussian with a stddev which is the sum # of those convolved, so we model the image as a Gaussian itself. image_sigma = sqrt(configuration.source_sigma ** 2 + configuration.psf_sigma ** 2) image_amplitude = configuration.source_amplitude * configuration.psf_amplitude image, image_x, image_y = symmetric_gaussian_image(amplitude=image_amplitude, sigma=image_sigma, position=source_position, n_bins=configuration.image_size) data_image = DataIMG("image", image_x, image_y, image, shape=(configuration.image_size, configuration.image_size), sky=WcsStub([DATA_PIXEL_SIZE, DATA_PIXEL_SIZE]) ) return data_image
def get_kernel(self, data, subkernel=True): indep, dep, kshape, lo, hi = self._get_kernel_data(data, subkernel) # Use kernel data set WCS if available eqpos = getattr(self.kernel, 'eqpos', None) sky = getattr(self.kernel, 'sky', None) # If kernel is a model, use WCS from data if available if callable(self.kernel): eqpos = getattr(data, 'eqpos', None) sky = getattr(data, 'sky', None) dataset = None ndim = len(kshape) if ndim == 1: dataset = Data1D('kernel', indep[0], dep) elif ndim == 2: # Edit WCS to reflect the subkernel extraction in # physical coordinates. if (subkernel and sky is not None and lo is not None and hi is not None): if (WCS is not None): sky = WCS(sky.name, sky.type, sky.crval, sky.crpix - lo, sky.cdelt, sky.crota, sky.epoch, sky.equinox) # FIXME: Support for WCS only (non-Chandra) coordinate # transformations? dataset = DataIMG('kernel', indep[0], indep[1], dep, kshape[::-1], sky=sky, eqpos=eqpos) else: raise PSFErr('ndim') return dataset
def make_test_image(): """A simple image Note that normally you'd have logical axes of 1:31, 1:21 here and then a WCS, but I've decided to number the axes differently (in physical units) as there is no requirement that the logical units are 1:nx/ny. """ x1, x0 = np.mgrid[3830:3850, 4245:4275] # What is the ordering of shape? At the moment going for # NumPy style (ny, nx), but there is no credible documentation # (any documentation was added to describe the behavior we # have now). # shape = x0.shape x0 = x0.flatten() x1 = x1.flatten() y = np.ones(x0.size) return DataIMG('d', x0, x1, y, shape=shape)