#!/usr/bin/env python class srcList: #arguments are: #sources (string, filename of LAT source list fits file in catalog format) #ft1 (string, filename of event file for which the xml will be used, only used to extract ROI info) #out (string, name of output xml file, defaults to mymodel.xml) def __init__(self,sources,ft1,out='mymodel.xml',allSky=False): if not fileCheck(sources): #check that file exists print "Error: %s not found." %sources return if fileCheck(out): print 'Warning: %s already exists, file will be overwritten if you proceed with makeModel.' %out self.srcs=sources self.out=out if allSky: self.roi=0.0,0.0,360. else: self.roi=getPos(ft1) #define a quick print function to make sure everything looks irght def Print(self): print 'Source list file: ',self.srcs print 'Output file name: ',self.out print 'Selecting %s degrees around (ra,dec)=(%s,%s)' %(self.roi[2],self.ra,self.dec) #make the xml file #arguments are: #GDfile (str) -- optional, location and name of Galactic diffuse model to use #GDname (str) -- optional, name of Galactic diffuse component to use in xml model #ISOfile (str) -- optional, location and name of Isotropic diffuse template to use #ISOname (str) -- optional, name of Isotropic diffuse component to use in xml model #normsOnly (bool) -- optional, flag to only set normalizations parameters free #extDir (str) -- optional, directory with extended source templates #radLim (float) -- optional, radius in degrees from center of ROI beyond which source parameters are fixed #maxRad (float) -- optional, absolute maximum radius beyond which sources are fixed, this may be necessary when doing binned analysis and a variable source beyond radLim would be set free but this source is beyond the boundaries of the square region used for the binned likelihood #ExtraRad (float) -- optional, radius beyond ROI radius in event file out to which sources will be included with fixed parameters, defaul tof 10 is good for analyses starting around 100 MeV, but for higher energy fits this can be decreased #sigFree (float) -- optional, significance below which source parameters are fixed, even if within radLim #varFree (float) -- optional, variability index above which source parameters are free, if beyond radLim and/or below sigFree only the normalization parameter is set free, currently not implemented for building from xml catalog #psForce (bool) -- optional, flag to force extended sources to be point sources #makeRegion (bool) -- optional, flag to also generate ds9 region file #GIndexFree (bool) -- optional, the Galactic diffuse is given a power-law spectral shape but the by default the index is frozen, setting this flag to True allows that to be free for additional freedom in diffuse fit #ApplyEDisp (boo) -- optional, flag to apply energy dispersion to free sources (except diffuse backgrounds) default is False. def makeModel(self,GDfile="$(FERMI_DIR)/refdata/fermi/galdiffuse/gll_iem_v06.fits",GDname='gll_iem_v06',ISOfile="$(FERMI_DIR)/refdata/fermi/galdiffuse/iso_P8R2_SOURCE_V6_v06.txt",ISOname='iso_P8R2_SOURCE_V6_v06',normsOnly=False,extDir='',radLim=-1,maxRad=None,ExtraRad=10,sigFree=5,varFree=True,psForce=False,makeRegion=True,GIndexFree=False,ApplyEDisp=False,wd='',oldNames=False): self.radLim=(self.roi[2] if radLim<=0 else radLim) self.maxRad=(self.radLim if maxRad==None else maxRad) if self.maxRad=sL.roi[2] or dist>=sL.maxRad: if dist>=sL.roi[2] or dist>=sL.maxRad or fixAll: Sources[sname]['free']=False specOut.setAttribute('apply_edisp','false')#source is fixed, so never apply edisp for p in specPars: specOut.appendChild(parameter_element("0","%s"%str(p.getAttribute('name')),"%s"%str(p.getAttribute('max')),"%s"%str(p.getAttribute('min')),"%s"%str(p.getAttribute('scale')),"%s"%str(p.getAttribute('value')))) elif dist>sL.radLim: if sL.var and varIdx>=72.44: Sources[sname]['free']=True specOut.setAttribute('apply_edisp',ed) for p in specPars: FreeFlag=("1" if p.getAttribute('name')==spec[0].getAttribute('normPar') else "0") specOut.appendChild(parameter_element("%s"%FreeFlag,"%s"%str(p.getAttribute('name')),"%s"%str(p.getAttribute('max')),"%s"%str(p.getAttribute('min')),"%s"%str(p.getAttribute('scale')),"%s"%str(p.getAttribute('value')))) else: Sources[sname]['free']=False specOut.setAttribute('apply_edisp','false') for p in specPars: specOut.appendChild(parameter_element("0","%s"%str(p.getAttribute('name')),"%s"%str(p.getAttribute('max')),"%s"%str(p.getAttribute('min')),"%s"%str(p.getAttribute('scale')),"%s"%str(p.getAttribute('value')))) elif float(src.getAttribute('TS_value'))>=sL.sig: Sources[sname]['free']=True specOut.setAttribute('apply_edisp',ed) for p in specPars: freeFlag=("1" if p.getAttribute('name')==spec[0].getAttribute('normPar') or (not sL.nO and p.getAttribute('free')=="1") else "0") #if str(p.getAttribute('name')) in normNames or (not sL.nO and str(p.getAttribute('name')) in freePars): specOut.appendChild(parameter_element("%s"%freeFlag,"%s"%str(p.getAttribute('name')),"%s"%str(p.getAttribute('max')),"%s"%str(p.getAttribute('min')),"%s"%str(p.getAttribute('scale')),"%s"%str(p.getAttribute('value')))) #else: #specOut.appendChild(parameter_element("0","%s"%str(p.getAttribute('name')),"%s"%str(p.getAttribute('max')),"%s"%str(p.getAttribute('min')),"%s"%str(p.getAttribute('scale')),"%s"%str(p.getAttribute('value')))) else: if sL.var and varIdx>=72.44: Sources[sname]['free']=True specOut.setAttribute('apply_edisp',ed) for p in specPars: FreeFlag=("1" if p.getAttribute('name')==spec[0].getAttribute('normPar') else "0") specOut.appendChild(parameter_element("%s"%FreeFlag,"%s"%str(p.getAttribute('name')),"%s"%str(p.getAttribute('max')),"%s"%str(p.getAttribute('min')),"%s"%str(p.getAttribute('scale')),"%s"%str(p.getAttribute('value')))) else: Sources[sname]['free']=False specOut.setAttribute('apply_edisp','false') for p in specPars: specOut.appendChild(parameter_element("0","%s"%str(p.getAttribute('name')),"%s"%str(p.getAttribute('max')),"%s"%str(p.getAttribute('min')),"%s"%str(p.getAttribute('scale')),"%s"%str(p.getAttribute('value')))) if Ext: spatial=src.getElementsByTagName('spatialModel') spatialOut.setAttribute('type','SpatialMap') spatialOut.setAttribute('map_based_integral','true') efile=sL.extD+spatial[0].getAttribute('file') spatialOut.setAttribute('file',efile) srcOut.setAttribute('type','DiffuseSource') extSrcNum+=1 print 'Extended source %s in ROI, make sure %s is the correct path to the extended template.'%(sname,efile) else: spatialOut.setAttribute('type','SkyDirFunction') spatialOut.appendChild(parameter_element("0","RA","360.0","-360.0","1.0","%.4f"%srcRA)) spatialOut.appendChild(parameter_element("0","DEC","360.0","-360.0","1.0","%.4f"%srcDEC)) srcOut.setAttribute('type','PointSource') ptSrcNum+=1 srcOut.appendChild(specOut) srcOut.appendChild(spatialOut) outputXml.documentElement.appendChild(srcOut) gal=outputXml.createElement('source') gal.setAttribute('name',GDn) gal.setAttribute('type','DiffuseSource') galspec=outputXml.createElement('spectrum') galspec.setAttribute('type','PowerLaw') galspec.setAttribute('apply_edisp','false') galspec.appendChild(parameter_element("1","Prefactor","10","0","1","1")) if sL.GIF: galspec.appendChild(parameter_element("1","Index","1","-1","1","0")) else: galspec.appendChild(parameter_element("0","Index","1","-1","1","0")) galspec.appendChild(parameter_element("0","Scale","1e6","2e1","1","100")) galspatial=outputXml.createElement('spatialModel') galspatial.setAttribute('type','MapCubeFunction') galspatial.setAttribute('file',GD) galspatial.appendChild(parameter_element("0","Normalization","1e3","1e-3","1","1")) gal.appendChild(galspec) gal.appendChild(galspatial) outputXml.documentElement.appendChild(gal) iso=outputXml.createElement('source') iso.setAttribute('name',ISOn) iso.setAttribute('type','DiffuseSource') isospec=outputXml.createElement('spectrum') isospec.setAttribute('type','FileFunction') isospec.setAttribute('file',ISO) isospec.setAttribute('apply_edisp','false') isospec.appendChild(parameter_element("1","Normalization","10","0.01","1","1")) isospatial=outputXml.createElement('spatialModel') isospatial.setAttribute('type','ConstantValue') isospatial.appendChild(parameter_element("0","Value","10","0","1","1")) iso.appendChild(isospec) iso.appendChild(isospatial) outputXml.documentElement.appendChild(iso) xmlStr=outputXml.toprettyxml(' ').splitlines(True) outStr=filter(lambda xmlStr: len(xmlStr) and not xmlStr.isspace(),xmlStr) outfile=open(sL.out,'w') outfile.write(''.join(outStr)) outfile.close() if not sL.psF: print 'Added %i point sources and %i extended sources'%(ptSrcNum,extSrcNum) if extSrcNum>0: print 'If using unbinned likelihood you will need to rerun gtdiffrsp for the extended sources or rerun the makeModel function with optional argument psForce=True' else: print 'Added %i point sources, note that any extended sources in ROI were modeled as point sources becaue psForce option was set to True'%ptSrcNum if sL.reg: BuildRegion(sL,Sources) return #function to cycle through the source list and add point source entries def addSrcsFITS(sL,GD,GDn,ISO,ISOn,oldNames): model=open(sL.out,'w') #open file in write mode, overwrites other files of same name file=pyfits.open(sL.srcs) #open source list file and access necessary fields, requires LAT source catalog definitions and names #mask=file[1].data.field('Signif_Avg')>=sL.sig #data=file[1].data[mask] data=file['LAT_Point_Source_Catalog'].data extendedinfo=file['ExtendedSources'].data extName=extendedinfo.field('Source_Name') extFile=extendedinfo.field('Spatial_Filename') name=data.field('Source_Name') Sigvals=data.field('Signif_Avg') VarIdx=data.field('Variability_Index') EName=data.field('Extended_Source_Name') ra=data.field('RAJ2000') dec=data.field('DEJ2000') flux=data.field('Flux_Density') pivot=data.field('Pivot_Energy') index=data.field('Spectral_Index') cutoff=data.field('Cutoff') expIndex=data.field('Exp_Index') spectype=data.field('SpectrumType') beta=data.field('Beta') model.write('\n') model.write('\n') model.write('\n\n') step=(sL.roi[2]+sL.ER)/5. #divide ROI radius plus ExtraRadius degrees into 5 steps for ordering of sources i=1 radii=[] ptSrcNum=0 extSrcNum=0 Sources={}#dictionary for sources, useful for creating region file later. while i<6: if i*step<=sL.roi[2]+sL.ER: radii+=[step*i] else: radii+=[sL.roi[2]+sL.ER] #just in case of rounding errors i+=1 for x in radii: if x==sL.roi[2]+sL.ER: model.write('\n\n' %(x-step,x)) else: model.write('\n\n' %(x-step,x)) for n,f,i,r,d,p,c,t,b,TS,ei,vi,En in zip(name,flux,index,ra,dec,pivot,cutoff,spectype,beta,Sigvals,expIndex,VarIdx,EName): E=(True if n[-1]=='e' else False) dist=angsep(sL.roi[0],sL.roi[1],r,d) #check that source is within ROI radius + 10 degress of ROI center if r==sL.roi[0] and d==sL.roi[1]: dist=0.0 if (dist=x-step) or (x==sL.roi[2]+10. and dist==x): if E and not sL.psF: Sources[En]={'ra':r,'dec':d,'stype':t,'E':E} extSrcNum+=1 Name='\n' %(dist,En) else: if E:#even if forcing all to point sources, use extended name Sources[En]={'ra':r,'dec':d,'stype':t,'E':E} Name='\n' %(dist,En) else: Sources[n]={'ra':r,'dec':d,'stype':t,'E':E} if oldNames: srcname='_' for N in n.split(' '): srcname+=N Name='\n' %(dist,srcname) else: Name='\n' %(dist,n) ptSrcNum+=1 if t=='PowerLaw': fixAll=(True if n=='3FGL J0534.5+2201i' or En in ['Cygnus Cocoon','Vela X','MSH 15-52','gamma Cygni'] else False) spec,free=PLspec(sL,f,i,p,dist,TS,vi,fixAll) elif t=='PowerLaw2':#no value for flux from 100 MeV to 100 GeV in fits file if i!=1.:#so calculate it by integrating PowerLaw spectral model F=f*p**i/(-i+1.)*(1.e5**(-i+1.)-1.e2**(-i+1.)) else: F=f*p*log(1.e3) spec,free=PL2spec(sL,F,i,dist,TS,vi) #spec,free=PL2spec(sL,f100,i,dist,TS,vi) elif t=='LogParabola': spec,free=LPspec(sL,f,i,p,b,dist,TS,vi) else: spec,free=COspec(sL,f,i,p,c,ei,dist,TS,vi) if E: Sources[En]['free']=free else: Sources[n]['free']=free if E and not sL.psF: #need to fix this efile=None for EXTNAME,EXTFILE in zip(extName,extFile): if En==EXTNAME: efile=sL.extD+EXTFILE if efile==None: print 'could not find a match for',En,'in the list:' print extName efile='' skydir='\t\n'%(efile) print 'Extended source %s in ROI, make sure %s is the correct path to the extended template.'%(En,efile) skydir+='\t\t\n' skydir+='\t\n' else: skydir='\t\n' skydir+='\t\t\n' %r skydir+='\t\t\n' %d skydir+='\t\n' skydir+='' (src,)=(Name+spec+skydir,) ptsrc=pS(src).getElementsByTagName('source')[0] ptsrc.writexml(model) model.write('\n') file.close() #close file if not sL.psF: print 'Added %i point sources and %i extended sources'%(ptSrcNum,extSrcNum) if extSrcNum>0: print 'If using unbinned likelihood you will need to rerun gtdiffrsp for the extended sources or rerun the makeModel function with optional argument psForce=True' else: print 'Added %i point sources, note that any extended sources in ROI were modeled as point sources becaue psForce option was set to True'%ptSrcNum #add galactic diffuse with PL spectrum, fix index to zero for general use, those who want it to be free can unfreeze parameter manually model.write('\n\n') Name='\n\n' %GDn spec='\t\n' spec+='\t\t\n' if sL.GIF: spec+='\t\t\n' else: spec+='\t\t\n' spec+='\t\t\n' spec+='\t\n' skydir='\t\n' %GD skydir+='\t\t\n' skydir+='\t\n' skydir+='' (src,)=(Name+spec+skydir,) galdiff=pS(src).getElementsByTagName('source')[0] galdiff.writexml(model) model.write('\n') Name='\n' %ISOn spec='\t\n' %ISO spec+='\t\t\n' spec+='\t\n' skydir='\t\n' skydir+='\t\t\n' skydir+='\t\n' skydir+='' (src,)=(Name+spec+skydir,) iso=pS(src).getElementsByTagName('source')[0] iso.writexml(model) model.write('\n') model.close() if sL.reg: BuildRegion(sL,Sources) return def BuildRegion(sL,Sources): myreg=open(sL.regFile,'w')#note that this will overwrite previous region files of the same name myreg.write('# Region File format: DS9 version ?')#I don't actually know, but I think it's one of the later ones, need to verify myreg.write('\n# Created by make3FGLxml.py') myreg.write('\nglobal font="roman 10 normal" move =0') for k in Sources.keys(): src=Sources[k] #get color based on if the source is free or not color=('green' if src['free'] else 'magenta') if src['E']:#if the source is extended, always have the point be a "big" box myreg.write('\nJ2000;point(%.3f,%.3f) # point = box 18 color = %s text={%s}'%(src['ra'],src['dec'],color,k)) else:#if the source is a point source, choose the point type based on spectral model ptype=('cross' if src['stype']=='PLSuperExpCutoff' else 'diamond' if src['stype']=='LogParabola' else 'circle') myreg.write('\nJ2000;point(%.3f,%.3f) # point = %s 15 color = %s text={%s}'%(src['ra'],src['dec'],ptype,color,k)) myreg.close() return def PLspec(sL,f,i,p,dist,TS,vi,fixAll): fscale=int(floor(log10(f))) if (dist>sL.roi[2] or fixAll) or (dist>sL.maxRad) or (dist>sL.radLim and (vi<72.44 or not sL.var)) or (TSsL.roi[2] or fixAll: #if beyond ROI, shouldn't attempt to fit parameters if fixAll: spec+='\t\n' else: spec+='\t\n' spec+='\t\t\n' %(fscale,f/10**fscale) spec+='\t\t\n' %i free=False elif(dist>sL.radLim): if dist>sL.maxRad: spec+='\t\n'%sL.radLim spec+='\t\t\n' %(fscale,f/10**fscale) free=False elif vi<72.44 or not sL.var: spec+='\t\n'%sL.radLim spec+='\t\t\n' %(fscale,f/10**fscale) free=False else: spec+='\t\n'%(sL.radLim,vi) free=True spec+='\t\t\n' %(fscale,f/10**fscale) spec+='\t\t\n' %i elif(TSsL.roi[2] or (dist>sL.maxRad) or (dist>sL.radLim and (vi<72.44 or not sL.var)) or (TSsL.roi[2]): #if beyond ROI, shouldn't attempt to fit parameters spec+='\t\n' spec+='\t\t\n'%(fscale,F/10**fscale) spec+='\t\t\n' %i free=False elif(dist>sL.radLim): if dist>sL.maxRad: spec+='\t\n'%sL.radLim spec+='\t\t\n'%(fscale,F/10**fscale) free=False elif vi<72.44 or not sL.var: spec+='\t\n'%sL.radLim spec+='\t\t\n'%(fscale,F/10**fscale) free=False else: spec+='\t\n'%(sL.radLim,vi) spec+='\t\t\n'%(fscale,F/10**fscale) free=True spec+='\t\t\n' %i elif(TSsL.roi[2] or (dist>sL.maxRad) or (dist>sL.radLim and (vi<72.44 or not sL.var)) or (TS=0 else 2.)#some pulsars with index1 < 0 assuming standard convention, means rising counts spectrum at low E, odd if(dist>sL.roi[2]): #if beyond ROI, shouldn't attempt to fit parameters spec+='\t\n' free=False spec+='\t\t\n' %(fscale,f/10**fscale) spec+='\t\t\n' %i if c<=1e5: spec+='\t\t\n'%c else: spec+='\t\t\n'%(2.*c,c) elif(dist>sL.radLim): if dist>sL.maxRad: spec+='\t\n'%sL.radLim spec+='\t\t\n' %(fscale,f/10**fscale) free=False elif vi<72.44 or not sL.var: spec+='\t\n'%sL.radLim spec+='\t\t\n' %(fscale,f/10**fscale) free=False else: spec+='\t\n'%(sL.radLim,vi) spec+='\t\t\n' %(fscale,f/10**fscale) free=True spec+='\t\t\n' %i if c<=1e5: spec+='\t\t\n'%c else: spec+='\t\t\n'%(2.*c,c) elif(TSsL.roi[2] or (dist>sL.maxRad) or (dist>sL.radLim and (vi<72.44 or not sL.var)) or (TSsL.roi[2]): #if beyond ROI, shouldn't attempt to fit parameters spec+='\t\n' spec+='\t\t\n' %(fscale,f/10**fscale) spec+='\t\t\n' %i spec+='\t\t\n'%b free=False elif(dist>sL.radLim): if dist>sL.maxRad: spec+='\t\n'%sL.radLim spec+='\t\t\n' %(fscale,f/10**fscale) free=False elif vi<72.44 or not sL.var: spec+='\t\n'%sL.radLim spec+='\t\t\n' %(fscale,f/10**fscale) free=False else: spec+='\t\n'%(sL.radLim,vi) spec+='\t\t\n' %(fscale,f/10**fscale) free=True spec+='\t\t\n' %i spec+='\t\t\n'%b elif(TS