def _make_tsmap_fast(self, prefix, **kwargs): """ Make a TS map from a GTAnalysis instance. This is a simplified implementation optimized for speed that only fits for the source normalization (all background components are kept fixed). The spectral/spatial characteristics of the test source can be defined with the src_dict argument. By default this method will generate a TS map for a point source with an index=2.0 power-law spectrum. Parameters ---------- model : dict or `~fermipy.roi_model.Source` Dictionary or Source object defining the properties of the test source that will be used in the scan. """ loglevel = kwargs.get('loglevel', self.loglevel) src_dict = copy.deepcopy(kwargs.setdefault('model', {})) src_dict = {} if src_dict is None else src_dict multithread = kwargs.setdefault('multithread', False) threshold = kwargs.setdefault('threshold', 1E-2) max_kernel_radius = kwargs.get('max_kernel_radius') loge_bounds = kwargs.setdefault('loge_bounds', None) use_pylike = kwargs.setdefault('use_pylike', True) if loge_bounds: if len(loge_bounds) != 2: raise Exception('Wrong size of loge_bounds array.') loge_bounds[0] = (loge_bounds[0] if loge_bounds[0] is not None else self.log_energies[0]) loge_bounds[1] = (loge_bounds[1] if loge_bounds[1] is not None else self.log_energies[-1]) else: loge_bounds = [self.log_energies[0], self.log_energies[-1]] # Put the test source at the pixel closest to the ROI center xpix, ypix = (np.round((self.npix - 1.0) / 2.), np.round((self.npix - 1.0) / 2.)) cpix = np.array([xpix, ypix]) map_geom = self._geom.to_image() frame = coordsys_to_frame(map_geom.coordsys) skydir = SkyCoord(*map_geom.pix_to_coord((cpix[0], cpix[1])), frame=frame, unit='deg') skydir = skydir.transform_to('icrs') src_dict['ra'] = skydir.ra.deg src_dict['dec'] = skydir.dec.deg src_dict.setdefault('SpatialModel', 'PointSource') src_dict.setdefault('SpatialWidth', 0.3) src_dict.setdefault('Index', 2.0) src_dict.setdefault('Prefactor', 1E-13) counts = [] bkg = [] model = [] c0_map = [] eslices = [] enumbins = [] model_npred = 0 for c in self.components: imin = utils.val_to_edge(c.log_energies, loge_bounds[0])[0] imax = utils.val_to_edge(c.log_energies, loge_bounds[1])[0] eslice = slice(imin, imax) bm = c.model_counts_map(exclude=kwargs['exclude']).data.astype('float')[ eslice, ...] cm = c.counts_map().data.astype('float')[eslice, ...] bkg += [bm] counts += [cm] c0_map += [cash(cm, bm)] eslices += [eslice] enumbins += [cm.shape[0]] self.add_source('tsmap_testsource', src_dict, free=True, init_source=False, use_single_psf=True, use_pylike=use_pylike, loglevel=logging.DEBUG) src = self.roi['tsmap_testsource'] # self.logger.info(str(src_dict)) modelname = utils.create_model_name(src) for c, eslice in zip(self.components, eslices): mm = c.model_counts_map('tsmap_testsource').data.astype('float')[ eslice, ...] model_npred += np.sum(mm) model += [mm] self.delete_source('tsmap_testsource', loglevel=logging.DEBUG) for i, mm in enumerate(model): dpix = 3 for j in range(mm.shape[0]): ix, iy = np.unravel_index( np.argmax(mm[j, ...]), mm[j, ...].shape) mx = mm[j, ix, :] > mm[j, ix, iy] * threshold my = mm[j, :, iy] > mm[j, ix, iy] * threshold dpix = max(dpix, np.round(np.sum(mx) / 2.)) dpix = max(dpix, np.round(np.sum(my) / 2.)) if max_kernel_radius is not None and \ dpix > int(max_kernel_radius / self.components[i].binsz): dpix = int(max_kernel_radius / self.components[i].binsz) xslice = slice(max(int(xpix - dpix), 0), min(int(xpix + dpix + 1), self.npix)) model[i] = model[i][:, xslice, xslice] ts_values = np.zeros((self.npix, self.npix)) amp_values = np.zeros((self.npix, self.npix)) wrap = functools.partial(_ts_value_newton, counts=counts, bkg=bkg, model=model, C_0_map=c0_map) if kwargs['map_skydir'] is not None: map_offset = wcs_utils.skydir_to_pix(kwargs['map_skydir'], map_geom.wcs) map_delta = 0.5 * kwargs['map_size'] / self.components[0].binsz xmin = max(int(np.ceil(map_offset[1] - map_delta)), 0) xmax = min(int(np.floor(map_offset[1] + map_delta)) + 1, self.npix) ymin = max(int(np.ceil(map_offset[0] - map_delta)), 0) ymax = min(int(np.floor(map_offset[0] + map_delta)) + 1, self.npix) xslice = slice(xmin, xmax) yslice = slice(ymin, ymax) xyrange = [range(xmin, xmax), range(ymin, ymax)] wcs = map_geom.wcs.deepcopy() npix = (ymax - ymin, xmax - xmin) crpix = (map_geom._crpix[0] - ymin, map_geom._crpix[1] - xmin) wcs.wcs.crpix[0] -= ymin wcs.wcs.crpix[1] -= xmin # FIXME: We should implement this with a proper cutout method map_geom = WcsGeom(wcs, npix, crpix=crpix) else: xyrange = [range(self.npix), range(self.npix)] xslice = slice(0, self.npix) yslice = slice(0, self.npix) positions = [] for i, j in itertools.product(xyrange[0], xyrange[1]): p = [[k // 2, i, j] for k in enumbins] positions += [p] self.logger.log(loglevel, 'Fitting test source.') if multithread: pool = Pool() results = pool.map(wrap, positions) pool.close() pool.join() else: results = map(wrap, positions) for i, r in enumerate(results): ix = positions[i][0][1] iy = positions[i][0][2] ts_values[ix, iy] = r[0] amp_values[ix, iy] = r[1] ts_values = ts_values[xslice, yslice] amp_values = amp_values[xslice, yslice] ts_map = WcsNDMap(map_geom, ts_values) sqrt_ts_map = WcsNDMap(map_geom, ts_values**0.5) npred_map = WcsNDMap(map_geom, amp_values * model_npred) amp_map = WcsNDMap(map_geom, amp_values * src.get_norm()) o = {'name': utils.join_strings([prefix, modelname]), 'src_dict': copy.deepcopy(src_dict), 'file': None, 'ts': ts_map, 'sqrt_ts': sqrt_ts_map, 'npred': npred_map, 'amplitude': amp_map, 'loglike': -self.like(), 'config': kwargs } return o
def _make_tsmap_fast(self, prefix, **kwargs): """ Make a TS map from a GTAnalysis instance. This is a simplified implementation optimized for speed that only fits for the source normalization (all background components are kept fixed). The spectral/spatial characteristics of the test source can be defined with the src_dict argument. By default this method will generate a TS map for a point source with an index=2.0 power-law spectrum. Parameters ---------- model : dict or `~fermipy.roi_model.Source` Dictionary or Source object defining the properties of the test source that will be used in the scan. """ loglevel = kwargs.get('loglevel', self.loglevel) src_dict = copy.deepcopy(kwargs.setdefault('model', {})) src_dict = {} if src_dict is None else src_dict multithread = kwargs.setdefault('multithread', False) threshold = kwargs.setdefault('threshold', 1E-2) max_kernel_radius = kwargs.get('max_kernel_radius') loge_bounds = kwargs.setdefault('loge_bounds', None) use_pylike = kwargs.setdefault('use_pylike', True) if loge_bounds: if len(loge_bounds) != 2: raise Exception('Wrong size of loge_bounds array.') loge_bounds[0] = (loge_bounds[0] if loge_bounds[0] is not None else self.log_energies[0]) loge_bounds[1] = (loge_bounds[1] if loge_bounds[1] is not None else self.log_energies[-1]) else: loge_bounds = [self.log_energies[0], self.log_energies[-1]] # Put the test source at the pixel closest to the ROI center xpix, ypix = (np.round( (self.npix - 1.0) / 2.), np.round((self.npix - 1.0) / 2.)) cpix = np.array([xpix, ypix]) map_geom = self._geom.to_image() frame = coordsys_to_frame(map_geom.coordsys) skydir = SkyCoord(*map_geom.pix_to_coord((cpix[0], cpix[1])), frame=frame, unit='deg') skydir = skydir.transform_to('icrs') src_dict['ra'] = skydir.ra.deg src_dict['dec'] = skydir.dec.deg src_dict.setdefault('SpatialModel', 'PointSource') src_dict.setdefault('SpatialWidth', 0.3) src_dict.setdefault('Index', 2.0) src_dict.setdefault('Prefactor', 1E-13) counts = [] bkg = [] model = [] c0_map = [] eslices = [] enumbins = [] model_npred = 0 for c in self.components: imin = utils.val_to_edge(c.log_energies, loge_bounds[0])[0] imax = utils.val_to_edge(c.log_energies, loge_bounds[1])[0] eslice = slice(imin, imax) bm = c.model_counts_map( exclude=kwargs['exclude']).data.astype('float')[eslice, ...] cm = c.counts_map().data.astype('float')[eslice, ...] bkg += [bm] counts += [cm] c0_map += [cash(cm, bm)] eslices += [eslice] enumbins += [cm.shape[0]] self.add_source('tsmap_testsource', src_dict, free=True, init_source=False, use_single_psf=True, use_pylike=use_pylike, loglevel=logging.DEBUG) src = self.roi['tsmap_testsource'] # self.logger.info(str(src_dict)) modelname = utils.create_model_name(src) for c, eslice in zip(self.components, eslices): mm = c.model_counts_map('tsmap_testsource').data.astype('float')[ eslice, ...] model_npred += np.sum(mm) model += [mm] self.delete_source('tsmap_testsource', loglevel=logging.DEBUG) for i, mm in enumerate(model): dpix = 3 for j in range(mm.shape[0]): ix, iy = np.unravel_index(np.argmax(mm[j, ...]), mm[j, ...].shape) mx = mm[j, ix, :] > mm[j, ix, iy] * threshold my = mm[j, :, iy] > mm[j, ix, iy] * threshold dpix = max(dpix, np.round(np.sum(mx) / 2.)) dpix = max(dpix, np.round(np.sum(my) / 2.)) if max_kernel_radius is not None and \ dpix > int(max_kernel_radius / self.components[i].binsz): dpix = int(max_kernel_radius / self.components[i].binsz) xslice = slice(max(int(xpix - dpix), 0), min(int(xpix + dpix + 1), self.npix)) model[i] = model[i][:, xslice, xslice] ts_values = np.zeros((self.npix, self.npix)) amp_values = np.zeros((self.npix, self.npix)) wrap = functools.partial(_ts_value_newton, counts=counts, bkg=bkg, model=model, C_0_map=c0_map) if kwargs['map_skydir'] is not None: map_offset = wcs_utils.skydir_to_pix(kwargs['map_skydir'], map_geom.wcs) map_delta = 0.5 * kwargs['map_size'] / self.components[0].binsz xmin = max(int(np.ceil(map_offset[1] - map_delta)), 0) xmax = min(int(np.floor(map_offset[1] + map_delta)) + 1, self.npix) ymin = max(int(np.ceil(map_offset[0] - map_delta)), 0) ymax = min(int(np.floor(map_offset[0] + map_delta)) + 1, self.npix) xslice = slice(xmin, xmax) yslice = slice(ymin, ymax) xyrange = [range(xmin, xmax), range(ymin, ymax)] wcs = map_geom.wcs.deepcopy() npix = (ymax - ymin, xmax - xmin) crpix = (map_geom._crpix[0] - ymin, map_geom._crpix[1] - xmin) wcs.wcs.crpix[0] -= ymin wcs.wcs.crpix[1] -= xmin # FIXME: We should implement this with a proper cutout method map_geom = WcsGeom(wcs, npix, crpix=crpix) else: xyrange = [range(self.npix), range(self.npix)] xslice = slice(0, self.npix) yslice = slice(0, self.npix) positions = [] for i, j in itertools.product(xyrange[0], xyrange[1]): p = [[k // 2, i, j] for k in enumbins] positions += [p] self.logger.log(loglevel, 'Fitting test source.') if multithread: pool = Pool() results = pool.map(wrap, positions) pool.close() pool.join() else: results = map(wrap, positions) for i, r in enumerate(results): ix = positions[i][0][1] iy = positions[i][0][2] ts_values[ix, iy] = r[0] amp_values[ix, iy] = r[1] ts_values = ts_values[xslice, yslice] amp_values = amp_values[xslice, yslice] ts_map = WcsNDMap(map_geom, ts_values) sqrt_ts_map = WcsNDMap(map_geom, ts_values**0.5) npred_map = WcsNDMap(map_geom, amp_values * model_npred) amp_map = WcsNDMap(map_geom, amp_values * src.get_norm()) o = { 'name': utils.join_strings([prefix, modelname]), 'src_dict': copy.deepcopy(src_dict), 'file': None, 'ts': ts_map, 'sqrt_ts': sqrt_ts_map, 'npred': npred_map, 'amplitude': amp_map, 'loglike': -self.like(), 'config': kwargs } return o
def _make_tsmap_fast(self, prefix, **kwargs): """ Make a TS map from a GTAnalysis instance. This is a simplified implementation optimized for speed that only fits for the source normalization (all background components are kept fixed). The spectral/spatial characteristics of the test source can be defined with the src_dict argument. By default this method will generate a TS map for a point source with an index=2.0 power-law spectrum. Parameters ---------- model : dict or `~fermipy.roi_model.Source` Dictionary or Source object defining the properties of the test source that will be used in the scan. """ src_dict = copy.deepcopy(kwargs.setdefault('model', {})) src_dict = {} if src_dict is None else src_dict multithread = kwargs.setdefault('multithread', False) threshold = kwargs.setdefault('threshold', 1E-2) max_kernel_radius = kwargs.get('max_kernel_radius') loge_bounds = kwargs.setdefault('loge_bounds', None) if loge_bounds is not None: if len(loge_bounds) == 0: loge_bounds = [None, None] elif len(loge_bounds) == 1: loge_bounds += [None] loge_bounds[0] = (loge_bounds[0] if loge_bounds[0] is not None else self.log_energies[0]) loge_bounds[1] = (loge_bounds[1] if loge_bounds[1] is not None else self.log_energies[-1]) else: loge_bounds = [self.log_energies[0], self.log_energies[-1]] # Put the test source at the pixel closest to the ROI center xpix, ypix = (np.round((self.npix - 1.0) / 2.), np.round((self.npix - 1.0) / 2.)) cpix = np.array([xpix, ypix]) skywcs = self._skywcs skydir = wcs_utils.pix_to_skydir(cpix[0], cpix[1], skywcs) src_dict['ra'] = skydir.ra.deg src_dict['dec'] = skydir.dec.deg src_dict.setdefault('SpatialModel', 'PointSource') src_dict.setdefault('SpatialWidth', 0.3) src_dict.setdefault('Index', 2.0) src_dict.setdefault('Prefactor', 1E-13) counts = [] bkg = [] model = [] c0_map = [] eslices = [] enumbins = [] model_npred = 0 for c in self.components: imin = utils.val_to_edge(c.log_energies, loge_bounds[0])[0] imax = utils.val_to_edge(c.log_energies, loge_bounds[1])[0] eslice = slice(imin, imax) bm = c.model_counts_map(exclude=kwargs['exclude']).counts.astype('float')[ eslice, ...] cm = c.counts_map().counts.astype('float')[eslice, ...] bkg += [bm] counts += [cm] c0_map += [cash(cm, bm)] eslices += [eslice] enumbins += [cm.shape[0]] self.add_source('tsmap_testsource', src_dict, free=True, init_source=False) src = self.roi['tsmap_testsource'] # self.logger.info(str(src_dict)) modelname = utils.create_model_name(src) for c, eslice in zip(self.components, eslices): mm = c.model_counts_map('tsmap_testsource').counts.astype('float')[ eslice, ...] model_npred += np.sum(mm) model += [mm] self.delete_source('tsmap_testsource') for i, mm in enumerate(model): dpix = 3 for j in range(mm.shape[0]): ix, iy = np.unravel_index( np.argmax(mm[j, ...]), mm[j, ...].shape) mx = mm[j, ix, :] > mm[j, ix, iy] * threshold my = mm[j, :, iy] > mm[j, ix, iy] * threshold dpix = max(dpix, np.round(np.sum(mx) / 2.)) dpix = max(dpix, np.round(np.sum(my) / 2.)) if max_kernel_radius is not None and \ dpix > int(max_kernel_radius / self.components[i].binsz): dpix = int(max_kernel_radius / self.components[i].binsz) xslice = slice(max(int(xpix - dpix), 0), min(int(xpix + dpix + 1), self.npix)) model[i] = model[i][:, xslice, xslice] ts_values = np.zeros((self.npix, self.npix)) amp_values = np.zeros((self.npix, self.npix)) wrap = functools.partial(_ts_value_newton, counts=counts, bkg=bkg, model=model, C_0_map=c0_map) if kwargs['map_skydir'] is not None: map_offset = wcs_utils.skydir_to_pix(kwargs['map_skydir'], self._skywcs) map_delta = 0.5 * kwargs['map_size'] / self.components[0].binsz xmin = max(int(np.ceil(map_offset[1] - map_delta)), 0) xmax = min(int(np.floor(map_offset[1] + map_delta)) + 1, self.npix) ymin = max(int(np.ceil(map_offset[0] - map_delta)), 0) ymax = min(int(np.floor(map_offset[0] + map_delta)) + 1, self.npix) xslice = slice(xmin, xmax) yslice = slice(ymin, ymax) xyrange = [range(xmin, xmax), range(ymin, ymax)] map_wcs = skywcs.deepcopy() map_wcs.wcs.crpix[0] -= ymin map_wcs.wcs.crpix[1] -= xmin else: xyrange = [range(self.npix), range(self.npix)] map_wcs = skywcs xslice = slice(0, self.npix) yslice = slice(0, self.npix) positions = [] for i, j in itertools.product(xyrange[0], xyrange[1]): p = [[k // 2, i, j] for k in enumbins] positions += [p] if multithread: pool = Pool() results = pool.map(wrap, positions) pool.close() pool.join() else: results = map(wrap, positions) for i, r in enumerate(results): ix = positions[i][0][1] iy = positions[i][0][2] ts_values[ix, iy] = r[0] amp_values[ix, iy] = r[1] ts_values = ts_values[xslice, yslice] amp_values = amp_values[xslice, yslice] ts_map = Map(ts_values, map_wcs) sqrt_ts_map = Map(ts_values**0.5, map_wcs) npred_map = Map(amp_values * model_npred, map_wcs) amp_map = Map(amp_values * src.get_norm(), map_wcs) o = {'name': utils.join_strings([prefix, modelname]), 'src_dict': copy.deepcopy(src_dict), 'file': None, 'ts': ts_map, 'sqrt_ts': sqrt_ts_map, 'npred': npred_map, 'amplitude': amp_map, 'config': kwargs } fits_file = utils.format_filename(self.config['fileio']['workdir'], 'tsmap.fits', prefix=[prefix, modelname]) if kwargs['write_fits']: fits_utils.write_maps(ts_map, {'SQRT_TS_MAP': sqrt_ts_map, 'NPRED_MAP': npred_map, 'N_MAP': amp_map}, fits_file) o['file'] = os.path.basename(fits_file) if kwargs['write_npy']: np.save(os.path.splitext(fits_file)[0] + '.npy', o) return o