obslist.py

Mayer Michael, 10/31/2014 11:32 AM

Download (10.1 KB)

 
1
from gammalib import *
2
from ctools import *
3
import os
4
import sys
5
import pyfits
6

    
7
def fits_header(fname,*args,**kwargs):
8
    hdu = 1
9
    for name,value in kwargs.items():
10
        if name == "hdu":
11
            hdu = value                  
12
    fdata = pyfits.open(fname)  
13
    arr = []
14
    for arg in args:
15
        if isinstance(arg,str):   
16
            if arg in fdata[hdu].header:     
17
                arr.append(fdata[hdu].header[arg])
18
            else:
19
                arr.append(float('NaN'))
20
                print fname+": Argument",arg,"not found in fits header (append NaN to array)"
21
                
22
        elif isinstance(arg,list):
23
            for argi in arg:
24
                if argi in fdata[hdu].header:     
25
                    arr.append(fdata[hdu].header[argi])
26
                else:
27
                    arr.append(float('NaN'))
28
                    print fname+": Argument",argi,"not found in fits header (append NaN to array)"
29
        else:
30
            print "Wrong argument type in function fits_header(fname,*args,**kwargs): encountered argument",type(arg)
31
            
32
    fdata.close()
33
    if len(arr)==1:
34
        return arr[0]
35
    else:
36
        return arr
37
    
38
def get_column_from_table(filename, column=0):
39
  result = []
40
  file = open(filename)
41
  for line in file.readlines():
42
    if len(line) <= 1:
43
      continue
44
    if line[0] == '#':
45
      continue
46
    if len(line.split()) > column:
47
      result.append(line.split()[column])
48
    else:
49
      result.append('')
50
  file.close()
51
  return result
52

    
53
class base(object):
54
    def __init__(self):
55
        self.classname = self.__class__.__name__
56
        self.errorcolor = "\033[31m"#red
57
        self.infocolor = "\033[34m"#blue
58
        self.warningcolor = "\033[33m"#yellow
59
        self.successcolor = "\033[32m"#green
60
        self.endcolor = "\033[0m"#reset
61
        
62
    def error(self,message, functionname = ""):
63
        printstring = ""
64
        if functionname == "":
65
            printstring = "\n"+self.errorcolor+"*** Error ["+self.classname+"]: "+message+" ***\n"+self.endcolor
66
        else:
67
            printstring = "\n"+self.errorcolor+"*** Error ["+self.classname+"::"+functionname+"]: "+message+" ***\n"+self.endcolor
68
        sys.exit(printstring)
69
    
70
    def info(self,message,newline=True):
71
        printstring = self.infocolor+"["+self.classname+"]: "+message+self.endcolor     
72
        if newline:
73
            print printstring
74
        else:
75
            print self.infocolor+message+self.endcolor,
76
            sys.stdout.flush()  
77
        
78
    def warning(self,message,functionname = ""):
79
        printstring = ""
80
        if functionname == "":
81
            printstring = self.warningcolor+"["+self.classname+"] Warning: "+message+self.endcolor
82
        else:
83
            printstring = self.warningcolor+"["+self.classname+"::"+functionname+"] Warning: "+message+self.endcolor
84
        print printstring
85
    def success(self,message):
86
        printstring = self.successcolor+"["+self.classname+"]: "+message+self.endcolor
87
        print printstring
88

    
89
class hess_obslist(base):
90

    
91
    def __init__(self,runlist):
92
        super(hess_obslist,self).__init__()
93
        self.runlist = []
94
        if isinstance(runlist,str):  
95
            self.runlistfile = os.path.abspath(runlist)
96
            if not os.path.isfile(self.runlistfile):
97
                self.error("Runlistfile "+self.runlistfile+" does not exist",sys._getframe().f_code.co_name)            
98
            self.runlist = get_column_from_table(self.runlistfile,0)  
99
        elif isinstance(runlist,list):
100
            self.runlist = runlist
101
        else:
102
            self.error("Given runlist is neither list nor file",sys._getframe().f_code.co_name)
103
        self.obs = GObservations()
104
        self.emin = 0.1
105
        self.emax = 100
106
        self.runlist_emin = 1e3
107
        self.runlist_emax = 1e-3       
108
        self.run_FoV = 2.5
109
        self.datapath = os.environ["HDATA_PATH"]
110
        self.bgpath = os.environ["HBG_PATH"]
111
        self.verbose = True
112
        self.nodes = 1
113
        self.alt_bounds = [0,20,23,27,30,33,37,40,44,49,53,58,64,72,90]
114
        self.az_bounds = [-180,-90,90,180]
115
    
116
    def _eventsfile(self,runnr):
117
        return self.datapath+"/events/events_"+runnr+".fits"
118
    def _psffile(self,runnr):
119
        return self.datapath+"/psf/psf_"+runnr+".fits"
120
    def _Aefffile(self,runnr):
121
        return self.datapath+"/Aeff/Aeff_"+runnr+".fits"
122
    
123
    def _select(self,evlist,emin,emax):
124

    
125
        [ra,dec] = fits_header(evlist,"RA_PNT","DEC_PNT")
126
        
127
        expr = evlist+"[EVENTS][ENERGY >= "+str(emin)+" && ENERGY <= "+str(emax)+" && ANGSEP("+str(ra)+","+str(dec)+",RA,DEC) <= "+str(self.run_FoV)+"]"
128
        fits = GFits(expr)
129
        fits[1].card("NDSKEYS",3,"")
130
        fits[1].card("DSTYP1","TIME","")
131
        fits[1].card("DSUNI1",'s',"")
132
        fits[1].card("DSVAL1","TABLE","")
133
        fits[1].card("DSREF1",":GTI","")
134
        fits[1].card("DSTYP2","POS(RA,DEC)","")
135
        fits[1].card("DSUNI2",'deg',"")
136
        fits[1].card("DSVAL2","CIRCLE("+str(ra)+","+str(dec)+","+str(self.run_FoV)+")","")
137
        fits[1].card("DSTYP3","ENERGY","")
138
        fits[1].card("DSUNI3",'TeV',"")
139
        fits[1].card("DSVAL3",str(emin)+":"+str(emax),"")
140
         
141
        obs = GCTAObservation("HESS")
142
        obs.read(fits)
143
        return obs
144

    
145

    
146
    def _findbins(self,alt,az):
147
        altbin=-1
148
        azbin = -1
149
        for i in range(len(self.alt_bounds)-1):
150
            if alt >= self.alt_bounds[i] and alt <= self.alt_bounds[i+1]:
151
                altbin=i
152
                break
153
        if az < -90 or az > 90:
154
            azbin = 1
155
        else:
156
            azbin = 0
157
        return altbin,azbin
158
    
159
    def hess_inst_background(self,run,emin=0.1,emax=80):
160
        spec = 0  
161
        if self.nodes <= 1:
162
            spec = GModelSpectralConst()
163
            spec["Value"].min(0.1)
164
            spec["Value"].max(10)
165
            if self.nodes <1:
166
                spec["Value"].fix()
167
            else:
168
                spec["Value"].free()
169
        elif self.nodes == 2:
170
            e= GEnergy(1.0,"TeV")
171
            spec = GModelSpectralPlaw(1.0,0.0,e)  
172
            spec[0].free()
173
            spec[0].min(0.01)
174
            spec[0].max(10.0)
175
            spec[0].scale(1.0)
176
            spec[1].free()
177
            spec[1].min(-2.0)
178
            spec[1].max(2.0)
179
            spec[1].scale(1.0)
180
        else:
181
            spec = GModelSpectralNodes()
182
            bounds = GEbounds(self.nodes,GEnergy(emin,"TeV"),GEnergy(emax,"TeV"),True)
183
            for i in range(bounds.size()):      
184
                spec.append(bounds.elogmean(i),1.0) 
185
                for par in spec:
186
                    if "Energy" in par.name():
187
                        par.fix()
188
                    elif "Intensity" in par.name():
189
                        par.min(0.01)
190
                        par.max(10.0)
191
        bck = GCTAModelIrfBackground(spec)
192
        bck.ids(run)
193
        bck.instruments("HESS")
194
        bck.name("bck_"+run)  
195
        bck.tscalc(False)
196
        return bck  
197
                
198

    
199
    def erange(self,emin,emax):
200
        if emin>=emax:
201
            self.error("Energy range ["+str(emin)+";"+str(emax)+"] not valid",sys._getframe().f_code.co_name)
202
        self.emin = emin
203
        self.emax = emax
204
        
205
    def check_run(self,runnr):
206
        if not os.path.exists(self._eventsfile(runnr)):
207
            return False
208
        if not os.path.exists(self._psffile(runnr)):
209
            return False
210
        if not os.path.exists(self._Aefffile(runnr)):
211
            return False
212
        return True
213
    
214
    def load(self):
215
        self.obs.clear()
216
        models = GModels()
217
        if self.verbose:
218
            self.info("Loading "+str(len(self.runlist))+" H.E.S.S. runs...")    
219
  
220
        for run in self.runlist: 
221
            if not self.check_run(run):
222
                if self.verbose:
223
                    self.warning("Run "+run+" does not exist")
224
                continue 
225
            evlist = self._eventsfile(run)       
226
            [alt,az,ntels] = fits_header(evlist,"ALT_PNT","AZ_PNT","N_TELS")
227
            if alt == 0.0 or az == 0.0 or ntels<=2 or ntels>5:
228
                if self.verbose:
229
                    self.warning("Run "+run+" not valid (Alt="+str(alt)+", Az="+str(az)+", Ntels="+str(ntels)+")")
230
                continue
231
            altbin,azbin = self._findbins(alt, az)
232
            bgfile = self.bgpath+"/hist_alt"+str(altbin)+"_az"+str(azbin)+".fits"                      
233
            if not os.path.exists(bgfile):
234
                if self.verbose:
235
                    self.warning("Run "+run+" has no corresponding off run (run will be skipped, Altbin="+str(altbin)+", Azbin="+str(azbin)+")")
236
                continue
237
            runemax = fits_header(self._Aefffile(run),"HI_THRES")
238
            runemin = fits_header(bgfile,"E_THRES")
239

    
240
            minenergy=0
241
            maxenergy=0
242
            if self.emin < runemin:
243
                minenergy=runemin
244
            else:
245
                minenergy=self.emin
246
            
247
            if self.emax > runemax:
248
                maxenergy = runemax
249
            else:
250
                maxenergy = self.emax
251
            
252
            if maxenergy <= minenergy:
253
                if self.verbose:
254
                    self.warning("Run "+run+ " has no event after selection")
255
                continue
256

    
257
            if minenergy<= self.runlist_emin:
258
                self.runlist_emin = minenergy
259
            if maxenergy >=self.runlist_emax:
260
                self.runlist_emax=maxenergy
261

    
262
            response = GCTAResponseIrf()
263
            response.load_psf(self._psffile(run))
264
            response.load_aeff(self._Aefffile(run))
265
            response.load_background(bgfile)
266
 
267
            sel_hess_obs = self._select(evlist,minenergy,maxenergy)
268
            sel_hess_obs.response(response)
269
            sel_hess_obs.id(run)
270
 
271
            self.obs.append(sel_hess_obs)
272
            bck = self.hess_inst_background(run,minenergy,maxenergy)
273
            models.append(bck)
274

    
275
        self.obs.models(models) 
276
        
277
        if self.verbose and self.obs.size()>0:
278
            self.success("... loaded "+str(self.obs.size())+ " H.E.S.S. runs (Energy range: "+str("%.2f" % self.runlist_emin)+" - "+ str("%.2f" % self.runlist_emax)+" TeV)")
279
        elif self.verbose:
280
            self.warning("no run has been loaded")