analysisutils.py

classes to run ctools - Sanchez David, 07/22/2014 04:27 PM

Download (12.7 KB)

 
1
# ==========================================================================
2
# This script provides a number of functions that are useful for handling
3
# CTA observations.
4
#
5
# Copyright (C) 2011-2014 David Sanchez Michael Mayer Rolf Buehler Juergen Knoedlseder
6
#
7
# This program is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
#
20
# ==========================================================================
21
import ctools as ct
22
import gammalib as gl
23
from math import log10,floor
24
import sys
25

    
26
class base(object):
27
    def __init__(self):
28
        self.classname = self.__class__.__name__
29
        self.errorcolor = "\033[31m"#red
30
        self.infocolor = "\033[34m"#blue
31
        self.warningcolor = "\033[33m"#yellow
32
        self.successcolor = "\033[32m"#green
33
        self.endcolor = "\033[0m"#reset
34
        self.prependfunction = True
35
        self.basemembers = ["classname","errorcolor","infocolor","warningcolor","successcolor","endcolor","prependfunction"]
36
        
37
    def error(self,message, functionname = ""):
38
        printstring = ""
39
        if functionname == "":
40
            printstring = "\n"+self.errorcolor+"*** Error ["+self.classname+"]: "+message+" ***\n"+self.endcolor
41
        else:
42
            printstring = "\n"+self.errorcolor+"*** Error ["+self.classname+"::"+functionname+"]: "+message+" ***\n"+self.endcolor
43
        sys.exit(printstring)
44
    
45
    def info(self,message,newline=True):
46
        printstring = self.infocolor+"["+self.classname+"]: "+message+self.endcolor     
47
        if newline:
48
            print printstring
49
        else:
50
            print self.infocolor+message+self.endcolor,
51
            sys.stdout.flush()  
52
        
53
    def warning(self,message,functionname = ""):
54
        printstring = ""
55
        if functionname == "":
56
            printstring = self.warningcolor+"["+self.classname+"] Warning: "+message+self.endcolor
57
        else:
58
            printstring = self.warningcolor+"["+self.classname+"::"+functionname+"] Warning: "+message+self.endcolor
59
        print printstring
60
        
61
    def success(self,message):
62
        printstring = self.successcolor+"["+self.classname+"]: "+message+self.endcolor
63
        print printstring
64
        
65
    def progress(self,message="."):
66
        string = self.infocolor+message+self.endcolor
67
        print string
68
        
69
        
70
class ResultsSorage(dict,base):
71
    """class to store the results in the good format"""
72
    def __init__(self,*arg,**kw):
73
        super(ResultsSorage, self).__init__(*arg, **kw)
74
        base.__init__(self)
75
        self["dnde"]      = []
76
        self["eu_dnde"]   = []
77
        self["ed_dnde"]   = []
78
        self["ulim_dnde"] = []
79
        self["ener"]      = []
80
        self["eu_ener"]   = []
81
        self["ed_ener"]   = []
82
        self["TS"]        = []
83
        self["Iflux"]     = []
84
        self["e_Iflux"]   = []
85
        
86
    def Print(self):
87
        self.info("Results are :")
88
        for k in self.iterkeys():
89
            print "\t",k,"\t",self[k]
90
        
91
        
92
class Analyser(base):
93
    def __init__(self):
94
        super(Analyser,self).__init__()
95
        self.info("Creating "+self.classname+" object")
96
        self.m_obs = None
97
        self.like  = None
98
        
99
        self.m_evtfile  = "events_selected.fits"        
100
        self.m_raw_evt  = "events.fits"
101
        self.m_cntfile  = "cntmap.fits"
102
        self.m_ebinalg  = "LOG"
103
        self.m_eunit    = "TeV"
104
        self.m_ra       = 83.63
105
        self.m_dec      = 22.01
106
        self.m_roi      = 2.
107
        self.m_tmin     = 0.
108
        self.m_tmax     = 0.
109
        self.m_emin     = 0.1#emin
110
        self.m_emax     = 10.#emax
111
        self.m_enumbins = 10#nbins
112
        self.m_usepnt   = True # Use pointing for map centre
113
        self.m_nxpix    = 200#npix
114
        self.m_nypix    = 200#npix
115
        self.m_binsz    = 0.05#binsz
116
        self.m_coordsys = "GAL"#coord
117
        self.m_proj     = "TAN"#proj
118
        self.m_binned   = False
119
        
120
        self.m_stat     = "POISSON"#stat
121
        self.m_caldb    = "dummy"
122
        self.m_irf      = "cta_dummy_irf"
123
        self.m_edisp    = False
124
        self.m_xml      = "$PWD/crab.xml"
125
        self.m_xml_out  = "$PWD/crab_results.xml"
126

    
127

    
128
    def set_obs(self,obs):
129
        self.m_obs = obs #set the GObservation container
130

    
131
    def set_energy_boundary(self,emin,emax):
132
        self.m_emin = emin
133
        self.m_emax = emax
134
        ebounds = gl.GEbounds(gl.GEnergy(emin, self.m_eunit), \
135
                                gl.GEnergy(emax, self.m_eunit))
136

    
137
        if self.m_obs:
138
            for obs in self.m_obs:
139
                obs.events().ebounds(ebounds)
140
        
141
    def ctselect(self):
142
        # ctselect application and set parameters
143
        self.info("Running ctselect to cut on events")
144
        if self.m_obs:
145
            filter = ct.ctselect(self.m_obs)
146
        else:
147
            filter = ct.ctselect()
148
        
149
        filter["infile"] = self.m_raw_evt               
150
        filter["outfile"] = self.m_evtfile  
151
        filter["usepnt"].boolean(self.m_usepnt) # Use pointing for map centre
152
        filter["ra"]  = self.m_ra
153
        filter["dec"]  = self.m_dec
154
        filter["rad"]  = self.m_roi
155
        filter["tmin"] = self.m_tmin
156
        filter["tmax"] = self.m_tmax
157
        filter["emin"].real(self.m_emin)
158
        filter["emax"].real(self.m_emax)
159
        filter["expr"] = ""
160
        filter.logFileOpen()
161

    
162
        filter.run()
163
        if not(self.m_obs):
164
            filter.save()
165

    
166
        if self.m_obs:
167
            # Make a deep copy of the observation that will be returned
168
            # (the ctbin object will go out of scope one the function is
169
            # left)
170
            self.m_obs = filter.obs().copy()
171
        
172
    def ctbin(self,log=False,debug=False):
173
        # ctbin application and set parameters
174
        self.info("Running ctbin to create count map")
175
        if self.m_obs:
176
            bin = ct.ctbin(self.m_obs)
177
        else:
178
            bin = ct.ctbin()
179
            bin["evfile"] = self.m_evtfile
180
        bin["outfile"] = self.m_cntfile
181
        bin["ebinalg"].string(self.m_ebinalg)
182
        bin["emin"].real(self.m_emin)
183
        bin["emax"].real(self.m_emax)
184
        Nbdecade = log10(self.m_emax)-log10(self.m_emin)#Compute the number of decade
185
        bin["enumbins"].integer(int(self.m_enumbins*Nbdecade))
186
        bin["usepnt"].boolean(self.m_usepnt) # Use pointing for map centre
187
        bin["nxpix"].integer(self.m_nxpix)
188
        bin["nypix"].integer(self.m_nypix)
189
        bin["binsz"].real(self.m_binsz)
190
        bin["coordsys"].string(self.m_coordsys)
191
        bin["proj"].string(self.m_proj)
192
        
193
        # Optionally open the log file
194
        if log:
195
            bin.logFileOpen()
196

    
197
        # Optionally switch-on debugging model
198
        if debug:
199
            bin["debug"].boolean(True)
200

    
201
        # Run ctbin application. This will loop over all observations in
202
        # the container and bin the events in counts maps
203
        bin.excute()
204
        if self.m_obs:
205
            # Make a deep copy of the observation that will be returned
206
            # (the ctbin object will go out of scope one the function is
207
            # left)
208
            self.m_obs = bin.obs().copy()
209
            
210
    def create_fit(self,log=False,debug=False):
211
        # create ctlike instance with given parameters
212
        self.info("Fitting Data using ctlike")
213
        if self.m_obs:
214
            self.like = ct.ctlike(self.m_obs)
215
        else:
216
            self.like = ct.ctlike()
217
            if self.m_binned:
218
                self.like["infile"] = self.m_cntfile
219
            else:
220
                self.like["infile"] = self.m_evtfile
221
                
222
            self.like["stat"].string(self.m_stat)
223
            self.like["caldb"].string(self.m_caldb)
224
            self.like["irf"].string(self.m_irf)
225
            self.like["srcmdl"] = self.m_xml 
226
        self.like["edisp"].boolean(self.m_edisp)
227
        self.like["outmdl"] = self.m_xml_out
228

    
229
        # Optionally open the log file
230
        if log:
231
            self.like.logFileOpen()
232
        # Optionally switch-on debugging model
233
        if debug:
234
            self.like["debug"].boolean(True)
235
            
236
    def fit(self,log=False,debug=False):
237
        if not(self.like):
238
            self.warning("ctlike object not created, creating now")
239
            self.create_fit(log,debug)
240

    
241
        # Run ctlike application.
242
        self.like.run()
243
        # Save the results in XML
244
        self.like.save()
245
        self.success("Fit performed")
246
        
247
    def PrintResults(self,srcname = ""):
248
        self.info("Results of the Fit")
249
        for m in self.like.obs().models():
250
            if srcname == m.name() or srcname=="":
251
                print "Model : "+m.name()
252
                print m
253
                
254
    def GetSrcResuls(self,Res,srcname,E0=1,factor = 1e6):
255

    
256
        results = self.GetSrcParams(srcname)
257

    
258
        Res["ener"].append(E0*factor)
259
        Res["ed_ener"].append((E0-self.m_emin)*factor)
260
        Res["eu_ener"].append((self.m_emax-E0)*factor)
261

    
262
        Res["Iflux"].append(results["flux"])
263
        Res["e_Iflux"].append(results["eflux"])
264

    
265
        m = self.GetModel(srcname)
266
        Res["dnde"].append(m.spectral().eval(gl.GEnergy(E0,self.m_eunit),gl.GTime(0)))
267
        m.spectral().eval_gradients(gl.GEnergy(E0,self.m_eunit),gl.GTime(0))
268
        # Assume that par 0 is the norm
269
        Res["eu_dnde"].append(m.spectral()[0].factor_gradient())
270
        Res["ed_dnde"].append(m.spectral()[0].factor_gradient())
271
        
272
        Res["TS"].append(100)
273
        # Res["TS"].append(self.like.obs().models()[srcname].ts())
274
        Res["ulim_dnde"].append(Res["dnde"][-1])
275
        return Res
276

    
277
    def GetSrcParams(self,srcname):
278
        results = {}
279
        found = False
280
        m = self.GetModel(srcname)
281
        results["flux"] = m.spectral().flux(gl.GEnergy(self.m_emin,self.m_eunit),gl.GEnergy(self.m_emax,self.m_eunit))
282
        results["eflux"] = m.spectral().eflux(gl.GEnergy(self.m_emin,self.m_eunit),gl.GEnergy(self.m_emax,self.m_eunit))
283
        for par in m.spectral():
284
            if par.is_free():
285
                results[par.name()] = par.value()
286
                results["e"+par.name()] = par.error()
287
            
288
        return results
289
        
290
    def GetModel(self,srcname):
291
        found = False
292
        for m in self.like.obs().models():
293
            if m.name() == srcname:
294
                return m
295
        self.error("source "+srcname+" not in the source list")
296
            
297
    
298
def MakeEbin(analyse,nbins,srcname,binned = False):
299
    #Store the results
300
    Res = ResultsSorage()
301
    
302
    #check the source name, exit is the srcname is false
303
    analyse.GetModel(srcname)
304
    
305
    #compute the conversion factor to have energy in MeV
306
    Energy_list = {"MeV":1,"GeV":1e3,"TeV":1e6} #TODO
307
    factor = Energy_list[analyse.m_eunit]
308
    
309
    for i in xrange(nbins):
310
        obs_copy = analyse.like.obs().copy()
311
        emin = pow(10,log10(analyse.m_emin) + (log10(analyse.m_emax)-log10(analyse.m_emin))/(nbins)*i)
312
        emax = pow(10,log10(analyse.m_emin) + (log10(analyse.m_emax)-log10(analyse.m_emin))/(nbins)*(i+1))
313
        E0 = pow(10, (log10(emin) + log10(emax)) / 2)
314
        print "Making energy bin between %2.1e"%(emin)+analyse.m_eunit+" and %2.1e"%(emax)+analyse.m_eunit
315

    
316
        # change the PivotEnergy to E0, froze all spectral parameters but the prefactor
317
        # m = obs_copy.models()[srcname]
318
        # for par in m.spectral():
319
            # if par.name() == "PivotEnergy":
320
                # par.value(E0*factor)
321
            # if not(par.name() == "Prefactor") and par.is_free(): # assume that all model have a prefactor
322
                # par.fix()
323
            # if par.name() == "Prefactor":
324
                # Set the norm to a better guess
325
                # new_val = m.spectral().eval(gl.GEnergy(E0,analyse.m_eunit),gl.GTime(0))
326
                # m.spectral()["Prefactor"].value(new_val)
327
                            
328
        ana_bin = Analyser()
329

    
330
        #copy the obs object
331
        ana_bin.set_obs(obs_copy)
332

    
333
        # Set energy boundaries
334
        ana_bin.set_energy_boundary(emin,emax)
335
        ana_bin.ctselect()
336

    
337
        # if binned:
338
            # ana_bin.ctbin()
339

    
340
        # Create the fit object
341
        ana_bin.create_fit(log=False,debug=False)
342
        
343
        # Run ctlike application.
344
        ana_bin.like.run()
345

    
346
        #Retrive the results in the good format
347
        Res = ana_bin.GetSrcResuls(Res,srcname,E0,factor)
348
        
349
        del ana_bin
350
    return Res
351