def _make_ltcube(self): """ Generate the livetime cube.""" #TODO -- unify weighted livetime import sys self.quiet = False self.ltcube = self.ltcube or self._make_default_name(prefix='lt') roi_info = self.dss.roi_info() if hasattr(self.dss, 'roi_info') else None if (roi_info is None) or (roi_info[2] > 90): # full sky ltcube roi_dir = skymaps.SkyDir(0, 0) exp_radius = 180 else: roi_dir = skymaps.SkyDir(roi_info[0], roi_info[1]) exp_radius = roi_info[2] + self.livetime_buffer if self.zenith_cut is None: self.zenith_cut = get_default('ZENITH_ANGLE', None) print 'Warning: using default zenith_cut, {}'.format( self.zenith_cut) # raise DataManException('zenith cut not specified') zenithcut = self.zenith_cut.get_bounds()[1] if not self.quiet: if exp_radius == 180: print 'Constructing all-sky livetime cube' else: print( 'Constructing livetime cube about RA,Dec = ({0:0.3f},{1:0.3f}) with a radius of {2:0.3f} deg.' .format(roi_dir.ra(), roi_dir.dec(), exp_radius)) for i in xrange(1 + self.use_weighted_livetime): #print('on iteration {0}'.format(i)) sys.stdout.flush() lt = skymaps.LivetimeCube(cone_angle=exp_radius, dir=roi_dir, zcut=np.cos(np.radians(zenithcut)), pixelsize=self.livetime_pixelsize, quiet=self.quiet, weighted=i) for hf in self.ft2files: if not self.quiet: print('checking FT2 file {0}...'.format(hf)), lt_gti = skymaps.Gti(hf, 'SC_DATA') if not ((lt_gti.maxValue() < self.gti.minValue()) or (lt_gti.minValue() > self.gti.maxValue())): lt.load(hf, self.gti) if not self.quiet: print 'loaded' else: if not self.quiet: print 'not in Gti range' # write out ltcube extension = 'WEIGHTED_EXPOSURE' if i else 'EXPOSURE' lt.write(self.ltcube, extension, not bool(i)) if self.dss is not None: self.dss.write(self.ltcube, header_key=0) # write some info to livetime file f = pyfits.open(self.ltcube) f[0]._header['RADIUS'] = exp_radius f[0]._header['PIXSIZE'] = self.livetime_pixelsize f.writeto(self.ltcube, overwrite=True) f.close()
def test(): assoc = SourceAssociation() #3C 454.3 pos, error = skymaps.SkyDir(343.495, 16.149), .016 / 2.45 * 1.51 associations = assoc.id(pos, [error, error, 0], name='3C 454.3') print(associations)
def load_sources(self, roi_index, rings=1, tsmin=[0, 25, 100]): """ load sources from the roi and its neighbors in the pickle file found in modeldir roi_index : integer HEALPix index of the ROI rings : integer number of rings of concentric pixels to search for (fixed) sources to add Special value: if -1, do not add any sources at all tsmin : array minimun TS to accept sources in """ self.pickle_file = os.path.join(self.config.modeldir, 'pickle.zip') if not os.path.exists(self.pickle_file): raise Exception('Expected file "pickle.zip" not found in %s' % config.configdir) if hasattr(roi_index, '__len__'): roi_index = skymaps.Band(12).dir(skymaps.SkyDir(*roi_index)) self.index = roi_index self.roi_dir = skymaps.Band(12).dir(roi_index) self.name = 'HP12_%04d' % roi_index self._z = zipfile.ZipFile(os.path.expandvars(self.pickle_file)) global_only = rings == -1 self.load_sources_from_healpix((roi_index, 0), global_only=global_only) if global_only: return for neighbor_index in neighbors(roi_index, rings=rings): self.load_sources_from_healpix(neighbor_index, neighbors=True)
def __init__(self, healpix_index=None, pos=None, radius=5, radius_factor=0.5): """ parameters --------- healpix_index : [None | int ] pos : [None | tuple of float] radius : float radius_factor : float Factor to apply to define the ROI size for extraction of data to fit. This is needed to allow enough size to perform the convolution using a square grid """ if healpix_index is not None: self.index = healpix_index self.pos = skymaps.Band(12).dir(self.index) self.radius=radius self.name = 'HP12_%04d' % self.index elif pos is not None: self.index=None self.pos=skymaps.SkyDir(*pos[:2]) self.radius = pos[2]*radius_factor if len(pos)>2 else radius self.name = 'ROI(%.3f,%.3f, %.1f)' % ( self.pos.ra(),self.pos.dec(), self.radius) else: # no explicit index or position self.name = None pass
def fill_empty_bands(bpd, bands): dummy = skymaps.SkyDir(0, 0) for bin_center in (bands[:-1] * bands[1:])**0.5: ph_f = pointlike.Photon(dummy, bin_center, 2.5e8, 0) ph_b = pointlike.Photon(dummy, bin_center, 2.5e8, 1) bpd.addBand(ph_f) bpd.addBand(ph_b)
def make_associations(self): """ run the standard association logic Only apply to "good" sources """ srcid = associate.SrcId() assoc = {} print 'Note: making bzcat first if second' for name, s in self.df.iterrows(): has_ellipse = not np.isnan(s['r95']) if has_ellipse: try: adict = srcid(name, skymaps.SkyDir(s['ra'], s['dec']), s['r95'] / 2.6) except Exception, msg: print 'Failed association for source %s: %s' % (name, msg) adict = None has_ellipse = adict is not None if has_ellipse: cats = adict['cat'] probs = adict['prob'] i=1 if len(cats)>1 and \ cats[1]=='bzcat' and probs[1]>0.8\ or cats[0]=='cgrabs' else 0 assoc[name] = ad = dict( acat=adict['cat'][i] if has_ellipse else None, aname=adict['name'][i] if has_ellipse else None, adelta_ts=adict['deltats'][i] if has_ellipse else None, aprob=adict['prob'][i] if has_ellipse else 0., adict=adict if has_ellipse else None, )
def plot_spectra(self, ax=None, glat=0, glon=(0, 2, -2, 30, -30, 90, -90), erange=None, title=None, label=None): """ show spectral for give glat, various glon values """ from matplotlib import pylab as plt if not self.loaded: self.load() ee = np.logspace(1.5, 6, 101) if erange is None else erange if ax is None: fig, ax = plt.subplots(1, 1, figsize=(5, 5)) else: fig = ax.figure for x in glon: sd = skymaps.SkyDir(glat, x, skymaps.SkyDir.GALACTIC) ax.loglog(ee, map(lambda e: e**2 * self(sd, e), ee), label='b=%.0f' % x if label is None else label) # if hasattr(self, 'energies'): # et = self.energies # ax.loglog(et, map(lambda e: e**2*self(sd,e), et), '--') ax.grid() if len(glon) > 1: ax.legend(loc='lower left', prop=dict(size=10)) plt.setp( ax, xlabel=r'$\mathrm{Energy\ [MeV]}$', ylabel=r'$\mathrm{E^2\ df/dE\ [Mev\ cm^{-2}\ s^{-1}\ sr^{-1}]}$') ax.set_title('Galactic diffuse at l=%.0f' % glat if title is None else title, size=12) return fig
def roi(self, *pars, **kwargs): """ return an object based on the selector, with attributes for creating roi analysis: list of ROIBand objects list of models: point sources and diffuse pars, kwargs : pass to the selector """ roi_kw = kwargs.pop('roi_kw', dict()) # allow parameter to be a name or a direction sel = pars[0] source_name = None if type(sel) == types.IntType: index = int(sel) # needs to be int if int type elif type(sel) == skymaps.SkyDir: index = self.skymodel.hpindex(sel) elif type(sel) == types.StringType: index = self.skymodel.hpindex( self.skymodel.find_source(sel).skydir) source_name = sel elif type(sel) == tuple and len( sel) == 2: # interpret a tuple of length 2 as (ra,dec) index = self.skymodel.hpindex(skymaps.SkyDir(*sel)) else: raise Exception('factory argument "%s" not recognized.' % sel) ## preselect the given source after setting up the ROI ## (not implemented here) # src_sel = self.selector(index, **kwargs) class ROIdef(object): def __init__(self, **kwargs): self.__dict__.update(kwargs) def __str__(self): return 'ROIdef for %s' % self.name skydir = src_sel.skydir() global_sources, extended_sources = self._diffuse_sources(src_sel) if isinstance(self.dataset, dataman.DataSet): bandsel = BandSelector(self.data_manager, self.psf, self.exposure, skydir) bands = bandsel(minROI=self.analysis_kw['minROI'], maxROI=self.analysis_kw['maxROI'], emin=self.analysis_kw['emin'], emax=self.analysis_kw['emax']) else: bands = self.dataset(self.psf, self.exposure, skydir) ## setup galactic diffuse correction and/or counts to pass into ROI generation #if self.galactic_correction is not None: # # look up the diffuse correction factors for this ROI, by name # self.exposure.dcorr = self.dcorr.ix[src_sel.name()].values return ROIdef(name=src_sel.name(), roi_dir=skydir, bands=bands, global_sources=global_sources, extended_sources=extended_sources, point_sources=self._local_sources(src_sel), exposure=self.exposure, **roi_kw)
def associate_catalog(self, catalog, **kwargs): """Cross-correlate a Fermi catalog with a given counterpart catalog Arguments: catalog: string, path to a LAT catalog for which to perform associations Keyword Arguments: cpt_class[None]: string or [strings], Counterpart class(es) to use for associations. Can be a single name or a list. If None, use all availabile classes. name[None]: string, key under which to save association information in self.sources. If None, don't save. unique[False]: bool, if True, compute probabilities for unique associations (one counterpart per LAT source) trap_mask[False]: bool, if True, use a trapezoidal mask for computing local counterpart densities. This is only included to get the same numbers as gtsrcid, no reason to use it in general. elliptical_errors[True]: bool, if True, use the full elliptical error paraemeters, otherwise use a circle with radius equal to the semi-major axis of the ellipse. Provided for compatibility with older versions of gtsrcid, no reason to use it otherwise. accept_in_r95[False]: bool, if True, accept sources within r95 as associations, regardless of formal probability Return: a dictionary with keys=names, values=dicts returned by id() """ #Read in Fermi catalog kw = dict(cpt_class=None, unique=True, trap_mask=False, elliptical_errors=True, accept_in_r95=False) for k, v in kw.items(): kw[k] = kwargs.pop(k, v) if kwargs: raise SrcidError( '\n'.join(['Unrecognized kwargs for method "id":'] + ["\t%s" % k for k in kwargs.keys()] + [''])) _cat = pf.open(catalog) dat = _cat['LAT_POINT_SOURCE_CATALOG'].data names = dat.Source_Name if 'Source_Name' in dat.names else dat.NickName try: ras, decs = dat.RA.astype('float'), dat.DEC.astype('float') except AttributeError: ras, decs = dat.RAJ2000.astype('float'), dat.DEJ2000.astype( 'float') if kw.pop('elliptical_errors'): maj_axes, min_axes = dat.Conf_95_SemiMajor / conv95, dat.Conf_95_SemiMinor / conv95 angles = dat.Conf_95_PosAng else: maj_axes = min_axes = angles = dat.Conf_95_SemiMajor / conv95 return dict(((name, self.id(skymaps.SkyDir(ra, dec), (a, b, ang), **kw)) for name, ra, dec, a, b, ang in zip( names, ras, decs, maj_axes, min_axes, angles)))
def fill_empty_bands(bpd, bands): dummy = skymaps.SkyDir(0, 0) if self.psf_event_types: event_types = [4, 8, 16, 32] else: event_types = [0, 1] for bin_center in (bands[:-1] * bands[1:])**0.5: for et in event_types: ph = skymaps.Photon(dummy, bin_center, 2.5e8, et) bpd.addBand(ph)
def __init__(self,class_module,catalog_dir,verbosity = 1): self.names,lons,lats= self.init(class_module,catalog_dir,verbosity = verbosity) radii = self.get_radii() self.source_mask_radius = max(radii)*3 self.mask = self._make_selection() self.sources = np.array([ExtendedSource(self,name,skymaps.SkyDir(lon,lat,self.coords),radius) for name,lon,lat,radius in zip(self.names,lons,lats,radii)])[self.mask] if self.coords == skymaps.SkyDir.GALACTIC: self.ras = np.array([source.skydir.ra() for source in self.sources]) self.decs = np.array([source.skydir.dec() for source in self.sources]) else: self.ras,self.decs = lons[self.mask],lats[self.mask]
def __init__(self,class_module,catalog_dir,verbosity=1): self.names,lons,lats = self.init(class_module,catalog_dir,verbosity=verbosity) self.mask = self._make_selection() self.sources = np.array([CatalogSource(self,name,skymaps.SkyDir(lon,lat,self.coords)) for name,lon,lat in zip(self.names,lons,lats)])[self.mask] if self.coords == skymaps.SkyDir.GALACTIC: self.ras = np.array([source.skydir.ra() for source in self.sources]) self.decs = np.array([source.skydir.dec() for source in self.sources]) else: self.ras,self.decs = lons[self.mask],lats[self.mask] self._get_foms() self.names = [s.name for s in self.sources] #replace so in order of sources
def id_list(self,r,class_list = None,trap_mask=False,unique = False): """Perform associations on a recarray of sources. r: a recarray with columns name,ra,dec,a,b,ang class_list: list of counterpart classes return: dict with key = name, value = return from id(SkyDir(ra,dec),(a,b,ang))""" associations = {} for s in r: associations[s.name] = self.id(skymaps.SkyDir(s.ra,s.dec),(s.a,s.b,s.ang), cpt_class = class_list,name = s.name, trap_mask=trap_mask,unique = False) return associations
def __init__(self,class_module,catalog_dir,verbosity = 1): self.names,lons,lats = self.init(class_module,catalog_dir,verbosity = verbosity) errors = self.get_position_errors() self.source_mask_radius = 3*max(errors) self.mask = self._make_selection() self.sources = np.array([GammaRaySource(self,name,skymaps.SkyDir(lon,lat,self.coords),error) for name,lon,lat,error in zip(self.names,lons,lats,errors)])[self.mask] #Save ras and decs for use in select_circle. MUCH faster than using the SkyDirs. if self.coords == skymaps.SkyDir.GALACTIC: self.ras = np.array([source.skydir.ra() for source in self.sources]) self.decs = np.array([source.skydir.dec() for source in self.sources]) else: self.ras,self.decs = lons[self.mask],lats[self.mask]
def get_livetime(self, pixelsize=1.0, weighted=False, clobber=True): gti = self.gti if self.ltcube is not None and os.path.exists(self.ltcube): try: lt = skymaps.LivetimeCube(self.ltcube, weighted=weighted) if not self.quiet: print 'loaded LivetimeCube %s ' % self.ltcube return lt except RuntimeError: if not self.quiet: ext = 'WEIGHTED_EXPOSURE' if weighted else 'EXPOSURE' print( 'no extension %s in file %s: will generate it from the ft2files' % (ext, self.ltcube)) elif not self.quiet: print 'LivetimeCube file %s does not exist: will generate it from the ft2 files' % self.ltcube if self.roi_dir is None: # no roi specified: use full sky self.roi_dir = skymaps.SkyDir(0, 0) self.exp_radius = 180 lt = skymaps.LivetimeCube(cone_angle=self.exp_radius, dir=self.roi_dir, zcut=math.cos(math.radians(self.zenithcut)), pixelsize=pixelsize, quiet=self.quiet, weighted=weighted) for hf in self.ft2files: if not self.quiet: print 'loading FT2 file %s' % hf, lt_gti = skymaps.Gti(hf, 'SC_DATA') if not ((lt_gti.maxValue() < self.gti.minValue()) or (lt_gti.minValue() > self.gti.maxValue())): lt.load(hf, gti) # write out ltcube if requested if self.ltcube is not None: extension = 'WEIGHTED_EXPOSURE' if weighted else 'EXPOSURE' lt.write(self.ltcube, extension, clobber) return lt
def loadsrclist(self,fname,srcs): self.srcs = [] self.src_names = [] self.src_redshifts = [] self.src_ra_deg = [] self.src_dec_deg = [] self.src_radec = [] if not fname is None: src_names = np.genfromtxt(fname,unpack=True,dtype=None) else: src_names = np.array(srcs.split(',')) if src_names.ndim == 0: src_names = src_names.reshape(1) cat = Catalog.get() for name in src_names: src = cat.get_source_by_name(name) name = src['Source_Name'] ra = src['RAJ2000'] dec = src['DEJ2000'] print 'Loading ', name self._photon_data._srcs.append(src) sd = skymaps.SkyDir(ra,dec) self.srcs.append(sd) self.src_names.append(name) self.src_ra_deg.append(ra) self.src_dec_deg.append(dec) self.src_radec.append((np.radians(ra),np.radians(dec))) self.src_redshifts.append(0.)
def load_photons(self, ft1file): hdulist = pyfits.open(ft1file) evhdu = hdulist['EVENTS'] if self.config['max_events'] is not None: table = evhdu.data[0:self.config['max_events']] else: table = evhdu.data msk = table.field('ZENITH_ANGLE') < self.config['zmax'] if not self.config['event_class_id'] is None: event_class = bitarray_to_int(table.field('EVENT_CLASS'), True) msk &= (event_class & ((0x1) << int(self.config['event_class_id'])) > 0) if not self.config['event_type_id'] is None: event_type = bitarray_to_int(table.field('EVENT_TYPE'), True) msk &= (event_type & ((0x1) << int(self.config['event_type_id'])) > 0) table = table[msk] if self.config['erange'] is not None: erange = [float(t) for t in self.config['erange'].split('/')] msk = ((np.log10(table.field('ENERGY')) > erange[0]) & (np.log10(table.field('ENERGY')) < erange[1])) table = table[msk] if self.config['conversion_type'] is not None: if self.config['conversion_type'] == 'front': msk = table.field('CONVERSION_TYPE') == 0 else: msk = table.field('CONVERSION_TYPE') == 1 table = table[msk] if self.config['phase_selection'] is not None: msk = table.field('PULSE_PHASE') < 0 phases = self.config['phase_selection'].split(',') for p in phases: (plo, phi) = p.split('/') msk |= ((table.field('PULSE_PHASE') > float(plo)) & (table.field('PULSE_PHASE') < float(phi))) table = table[msk] nevent = len(table) print 'Loading ', ft1file, ' nevent: ', nevent pd = self._photon_data for isrc, (src_ra, src_dec) in enumerate(zip(self.src_ra_deg, self.src_dec_deg)): vsrc = Vector3D.createLatLon(np.radians(src_dec), np.radians(src_ra)) msk = ((table.field('DEC') > (src_dec - self.config['max_dist'])) & (table.field('DEC') < (src_dec + self.config['max_dist']))) table_src = table[msk] vra = np.array(table_src.field('RA'), dtype=float) vdec = np.array(table_src.field('DEC'), dtype=float) vptz_ra = np.array(table_src.field('PtRaz'), dtype=float) vptz_dec = np.array(table_src.field('PtDecz'), dtype=float) dth = separation_angle(self.src_radec[isrc][0], self.src_radec[isrc][1], np.radians(vra), np.radians(vdec)) print 'Applying distance max' msk = dth < np.radians(self.config['max_dist']) table_src = table_src[msk] vra = vra[msk] vdec = vdec[msk] vptz_ra = vptz_ra[msk] vptz_dec = vptz_dec[msk] veq = Vector3D.createLatLon(np.radians(vdec), np.radians(vra)) eptz = Vector3D.createLatLon(np.radians(vptz_dec), np.radians(vptz_ra)) # True incidenge angle from source src_theta = vsrc.separation(eptz) print 'Getting projected direction' vp = veq.project2d(vsrc) vx = np.degrees(vp.theta() * np.sin(vp.phi())) vy = -np.degrees(vp.theta() * np.cos(vp.phi())) vptz = eptz.project2d(vsrc) vp2 = copy.deepcopy(vp) vp2.rotatez(-vptz.phi()) print 'Getting projected direction2' vx2 = np.degrees(vp2.theta() * np.sin(vp2.phi())) vy2 = -np.degrees(vp2.theta() * np.cos(vp2.phi())) # import matplotlib.pyplot as plt # print vp.theta()[:10] # print vp2.theta()[:10] # print np.sqrt(vx**2+vy**2)[:10] # print np.sqrt(vx2**2+vy2**2)[:10] # plt.figure() # plt.plot(vx2,vy2,marker='o',linestyle='None') # plt.gca().set_xlim(-80,80) # plt.gca().set_ylim(-80,80) # plt.figure() # plt.plot(vx,vy,marker='o',linestyle='None') # plt.show() # vx2 = np.degrees(vp.theta()*np.sin(vp.phi())) # vy2 = -np.degrees(vp.theta()*np.cos(vp.phi())) src_index = np.zeros(len(table_src), dtype=int) src_index[:] = isrc src_phase = np.zeros(len(table_src)) if 'PULSE_PHASE' in evhdu.columns.names: src_phase = table_src.field('PULSE_PHASE') psf_core = np.zeros(len(table_src)) if 'CTBCORE' in evhdu.columns.names: psf_core = list(table_src.field('CTBCORE')) event_type = np.zeros(len(table_src), dtype='int') if 'EVENT_TYPE' in evhdu.columns.names: event_type = bitarray_to_int(table_src.field('EVENT_TYPE'), True) event_class = bitarray_to_int(table_src.field('EVENT_CLASS'), True) pd.append('psfcore', psf_core) pd.append('time', table_src.field('TIME')) pd.append('ra', table_src.field('RA')) pd.append('dec', table_src.field('DEC')) pd.append('delta_ra', vx) pd.append('delta_dec', vy) pd.append('delta_phi', vx2) pd.append('delta_theta', vy2) pd.append('energy', np.log10(table_src.field('ENERGY'))) pd.append('dtheta', dth[msk]) pd.append('event_class', event_class) pd.append('event_type', event_type) pd.append('conversion_type', table_src.field('CONVERSION_TYPE').astype('int')) pd.append('src_index', src_index) pd.append('phase', src_phase) pd.append('cth', np.cos(src_theta)) # pd.append('cth',np.cos(np.radians(table_src.field('THETA')))) # costheta2 = np.cos(src_theta) # costheta = np.cos(np.radians(table_src.field('THETA'))) if self._phist is not None: import skymaps cthv = [] for k in range(len(table_src)): sd = skymaps.SkyDir(src_ra, src_dec) pi = self._phist(table_src.field('TIME')[k]) cth = np.cos(pi.zAxis().difference(sd)) print k, pd['energy'][k], cth, np.cos( theta3[k]), costheta[k] cthv.append(cth) pd.append('cth', cthv) print 'Finished' # print 'Loaded ', len(self.dtheta), ' events' hdulist.close()
def pyskyfun(u): return skyfun(skymaps.SkyDir(skymaps.Hep3Vector(u[0],u[1],u[2])))