Commit d11303337da842bf84a741ca82bff8d1645690d6

Authored by sanchez
1 parent 70701752

use the new ctbutterfly + some doc (need more)

pyext/ctools/analysisutils.py
@@ -21,9 +21,10 @@ @@ -21,9 +21,10 @@
21 import ctools as ct 21 import ctools as ct
22 import gammalib as gl 22 import gammalib as gl
23 from math import sqrt,log10,floor 23 from math import sqrt,log10,floor
24 -import sys 24 +import sys,string
25 25
26 class base(object): 26 class base(object):
  27 + '''This class is used to defined the colors of the print'''
27 def __init__(self): 28 def __init__(self):
28 self.classname = self.__class__.__name__ 29 self.classname = self.__class__.__name__
29 self.errorcolor = "\033[31m"#red 30 self.errorcolor = "\033[31m"#red
@@ -35,6 +36,7 @@ class base(object): @@ -35,6 +36,7 @@ class base(object):
35 self.basemembers = ["classname","errorcolor","infocolor","warningcolor","successcolor","endcolor","prependfunction"] 36 self.basemembers = ["classname","errorcolor","infocolor","warningcolor","successcolor","endcolor","prependfunction"]
36 37
37 def error(self,message, functionname = ""): 38 def error(self,message, functionname = ""):
  39 + '''Print the error message'''
38 printstring = "" 40 printstring = ""
39 if functionname == "": 41 if functionname == "":
40 printstring = "\n"+self.errorcolor+"*** Error ["+self.classname+"]: "+message+" ***\n"+self.endcolor 42 printstring = "\n"+self.errorcolor+"*** Error ["+self.classname+"]: "+message+" ***\n"+self.endcolor
@@ -43,6 +45,7 @@ class base(object): @@ -43,6 +45,7 @@ class base(object):
43 sys.exit(printstring) 45 sys.exit(printstring)
44 46
45 def info(self,message,newline=True): 47 def info(self,message,newline=True):
  48 + '''Print the information message'''
46 printstring = self.infocolor+"["+self.classname+"]: "+message+self.endcolor 49 printstring = self.infocolor+"["+self.classname+"]: "+message+self.endcolor
47 if newline: 50 if newline:
48 print(printstring) 51 print(printstring)
@@ -50,7 +53,8 @@ class base(object): @@ -50,7 +53,8 @@ class base(object):
50 print(self.infocolor+message+self.endcolor) 53 print(self.infocolor+message+self.endcolor)
51 sys.stdout.flush() 54 sys.stdout.flush()
52 55
53 - def warning(self,message,functionname = ""): 56 + def warning(self,message,functionname = ""):*
  57 + '''Print the warning message'''
54 printstring = "" 58 printstring = ""
55 if functionname == "": 59 if functionname == "":
56 printstring = self.warningcolor+"["+self.classname+"] Warning: "+message+self.endcolor 60 printstring = self.warningcolor+"["+self.classname+"] Warning: "+message+self.endcolor
@@ -59,19 +63,21 @@ class base(object): @@ -59,19 +63,21 @@ class base(object):
59 print(printstring) 63 print(printstring)
60 64
61 def success(self,message): 65 def success(self,message):
  66 + '''Print the success message'''
62 printstring = self.successcolor+"["+self.classname+"]: "+message+self.endcolor 67 printstring = self.successcolor+"["+self.classname+"]: "+message+self.endcolor
63 print(printstring) 68 print(printstring)
64 69
65 def progress(self,message="."): 70 def progress(self,message="."):
  71 + '''Print the progess message'''
66 string = self.infocolor+message+self.endcolor 72 string = self.infocolor+message+self.endcolor
67 print(string) 73 print(string)
68 74
69 -  
70 -class ResultsSorage(dict,base): 75 +class ResultsStorage(dict,base):
71 """class to store the results in the good format""" 76 """class to store the results in the good format"""
72 def __init__(self,*arg,**kw): 77 def __init__(self,*arg,**kw):
73 - super(ResultsSorage, self).__init__(*arg, **kw) 78 + super(ResultsStorage, self).__init__(*arg, **kw)
74 base.__init__(self) 79 base.__init__(self)
  80 + # Can store the differential flux, upper limit, time, energy and so one
75 self["dnde"] = {} 81 self["dnde"] = {}
76 self["ulim_dnde"] = [] 82 self["ulim_dnde"] = []
77 self["time"] = {} 83 self["time"] = {}
@@ -79,26 +85,31 @@ class ResultsSorage(dict,base): @@ -79,26 +85,31 @@ class ResultsSorage(dict,base):
79 self["TS"] = [] 85 self["TS"] = []
80 self["Iflux"] = {} 86 self["Iflux"] = {}
81 87
  88 + #store the time : Min, Max and units of the variable
82 self["time"]["tmin_value"] = [] 89 self["time"]["tmin_value"] = []
83 self["time"]["tmax_value"] = [] 90 self["time"]["tmax_value"] = []
84 self["time"]["unit"] = "sec" 91 self["time"]["unit"] = "sec"
85 92
  93 + #store the energy : Value min,max (ed_* and eu_*) and units of the variable
86 self["ener"]["value"] = [] 94 self["ener"]["value"] = []
87 self["ener"]["ed_value"] = [] 95 self["ener"]["ed_value"] = []
88 self["ener"]["eu_value"] = [] 96 self["ener"]["eu_value"] = []
89 self["ener"]["unit"] = "MeV" 97 self["ener"]["unit"] = "MeV"
90 98
  99 + #store the differential flux : Value min,max (ed_* and eu_*) and units of the variable
91 self["dnde"]["value"] = [] 100 self["dnde"]["value"] = []
92 self["dnde"]["ed_value"] = [] 101 self["dnde"]["ed_value"] = []
93 self["dnde"]["eu_value"] = [] 102 self["dnde"]["eu_value"] = []
94 self["dnde"]["unit"] = "ph/cm2/s/MeV" 103 self["dnde"]["unit"] = "ph/cm2/s/MeV"
95 104
  105 + #store the integral flux : Value min,max (ed_* and eu_*) and units of the variable
96 self["Iflux"]["value"] = [] 106 self["Iflux"]["value"] = []
97 self["Iflux"]["ed_value"] = [] 107 self["Iflux"]["ed_value"] = []
98 self["Iflux"]["eu_value"] = [] 108 self["Iflux"]["eu_value"] = []
99 self["Iflux"]["unit"] = "ph/cm2/s" 109 self["Iflux"]["unit"] = "ph/cm2/s"
100 110
101 def Print(self): 111 def Print(self):
  112 + """ Print the value stored in the class"""
102 self.success("Results are :") 113 self.success("Results are :")
103 for k in self.iterkeys(): 114 for k in self.iterkeys():
104 self.info("Key name : "+k) 115 self.info("Key name : "+k)
@@ -110,12 +121,17 @@ class ResultsSorage(dict,base): @@ -110,12 +121,17 @@ class ResultsSorage(dict,base):
110 print() 121 print()
111 122
112 class Analyser(base): 123 class Analyser(base):
  124 + '''Class to run the analysis of the data. Currently the parameters are hard coded but this will change once
  125 + the method to feed the class will be defined
  126 + The classe can work with GObservation as input (simulation) or fits files (simulation+real data)'''
113 def __init__(self): 127 def __init__(self):
114 super(Analyser,self).__init__() 128 super(Analyser,self).__init__()
115 self.info("Creating "+self.classname+" object") 129 self.info("Creating "+self.classname+" object")
  130 + #Observation and ctlike object
116 self.m_obs = None 131 self.m_obs = None
117 self.like = None 132 self.like = None
118 133
  134 + #parameters
119 self.m_ebinalg = "LOG" 135 self.m_ebinalg = "LOG"
120 self.m_eunit = "TeV" 136 self.m_eunit = "TeV"
121 self.m_enumbins = 10#nbins 137 self.m_enumbins = 10#nbins
@@ -126,6 +142,8 @@ class Analyser(base): @@ -126,6 +142,8 @@ class Analyser(base):
126 self.m_edisp = False 142 self.m_edisp = False
127 self.m_stat = "POISSON"#stat 143 self.m_stat = "POISSON"#stat
128 144
  145 + # booleans to ensure that input files and parameters have been defined
  146 + # set to false at the begining and turn to true while a file/parameter is defined.
129 self.m_source_set = False 147 self.m_source_set = False
130 self.m_files_set = False 148 self.m_files_set = False
131 self.m_time_set = False 149 self.m_time_set = False
@@ -135,6 +153,7 @@ class Analyser(base): @@ -135,6 +153,7 @@ class Analyser(base):
135 self.m_xml_set = False 153 self.m_xml_set = False
136 154
137 def set_xml(self,xml): 155 def set_xml(self,xml):
  156 + '''Set the model XML file'''
138 self.m_xml = xml 157 self.m_xml = xml
139 ind = xml.find(".xml") 158 ind = xml.find(".xml")
140 if not ind==-1: 159 if not ind==-1:
@@ -142,6 +161,7 @@ class Analyser(base): @@ -142,6 +161,7 @@ class Analyser(base):
142 self.m_xml_set = True 161 self.m_xml_set = True
143 162
144 def set_roi(self,roi): 163 def set_roi(self,roi):
  164 + '''Set the ROI parameter and compute the number of pixel, bin size of the map'''
145 self.m_roi = float(roi) 165 self.m_roi = float(roi)
146 self.m_nxpix = int(self.m_roi*100) #nxpix 166 self.m_nxpix = int(self.m_roi*100) #nxpix
147 self.m_nypix = int(self.m_roi*100) #nypix 167 self.m_nypix = int(self.m_roi*100) #nypix
@@ -149,23 +169,45 @@ class Analyser(base): @@ -149,23 +169,45 @@ class Analyser(base):
149 self.m_roi_set = True 169 self.m_roi_set = True
150 170
151 def set_irfs(self,caldb,irf): 171 def set_irfs(self,caldb,irf):
  172 + '''Set the IRFs definition'''
152 self.m_caldb = caldb 173 self.m_caldb = caldb
153 self.m_irf = irf 174 self.m_irf = irf
154 self.m_irfs_set = True 175 self.m_irfs_set = True
155 176
156 def set_Fitsfiles(self,evtfile,tag="CTA_analysis"): 177 def set_Fitsfiles(self,evtfile,tag="CTA_analysis"):
  178 + '''Set the input and output fits files'''
157 self.m_evtfile = "event_selected_"+tag+".fits" 179 self.m_evtfile = "event_selected_"+tag+".fits"
158 self.m_raw_evt = evtfile 180 self.m_raw_evt = evtfile
159 self.m_cntfile = "countmap_"+tag+".fits" 181 self.m_cntfile = "countmap_"+tag+".fits"
160 self.m_files_set = True 182 self.m_files_set = True
161 183
162 def set_source(self,name,ra,dec): 184 def set_source(self,name,ra,dec):
  185 + '''Set the source name and the RA/DEC position of the source'''
163 self.m_ra = ra 186 self.m_ra = ra
164 self.m_dec = dec 187 self.m_dec = dec
165 self.m_name = name 188 self.m_name = name
166 self.m_source_set = True 189 self.m_source_set = True
167 190
  191 + def set_time_boundary(self,tmin,tmax):
  192 + """Set the start and stop time of the observation"""
  193 + self.m_tmin = float(tmin)
  194 + self.m_tmax = float(tmax)
  195 + self.m_time_set = True
  196 +
  197 + def set_energy_boundary(self,emin,emax):
  198 + """Set the energy bounds of the observation"""
  199 + self.m_emin = emin
  200 + self.m_emax = emax
  201 + ebounds = gl.GEbounds(gl.GEnergy(emin, self.m_eunit), \
  202 + gl.GEnergy(emax, self.m_eunit))
  203 +
  204 + if self.m_obs:
  205 + for obs in self.m_obs:
  206 + obs.events().ebounds(ebounds)
  207 + self.m_energy_set = True
  208 +
168 def validate(self): 209 def validate(self):
  210 + '''Check is all the parameters has been set'''
169 if not self.m_time_set : 211 if not self.m_time_set :
170 self.error("Time range of the observations not set") 212 self.error("Time range of the observations not set")
171 213
@@ -188,6 +230,7 @@ class Analyser(base): @@ -188,6 +230,7 @@ class Analyser(base):
188 self.error("XML files for the sky model not set") 230 self.error("XML files for the sky model not set")
189 231
190 def copy(self,analyse,tag="CTA_analysis_copy"): 232 def copy(self,analyse,tag="CTA_analysis_copy"):
  233 + '''Make a copy of the class'''
191 self.set_xml(analyse.m_xml) 234 self.set_xml(analyse.m_xml)
192 self.set_irfs(analyse.m_caldb,analyse.m_irf) 235 self.set_irfs(analyse.m_caldb,analyse.m_irf)
193 self.set_roi(analyse.m_roi) 236 self.set_roi(analyse.m_roi)
@@ -198,35 +241,20 @@ class Analyser(base): @@ -198,35 +241,20 @@ class Analyser(base):
198 241
199 242
200 def set_obs(self,obs): 243 def set_obs(self,obs):
201 - self.m_obs = obs #set the GObservation container 244 + '''set the GObservation container'''
  245 + self.m_obs = obs
202 246
203 - def set_time_boundary(self,tmin,tmax):  
204 - """Set the start and stop time of the observation"""  
205 - self.m_tmin = float(tmin)  
206 - self.m_tmax = float(tmax)  
207 - self.m_time_set = True  
208 -  
209 - def set_energy_boundary(self,emin,emax):  
210 - """Set the energy bounds of the observation"""  
211 - self.m_emin = emin  
212 - self.m_emax = emax  
213 - ebounds = gl.GEbounds(gl.GEnergy(emin, self.m_eunit), \  
214 - gl.GEnergy(emax, self.m_eunit))  
215 -  
216 - if self.m_obs:  
217 - for obs in self.m_obs:  
218 - obs.events().ebounds(ebounds)  
219 - self.m_energy_set = True  
220 -  
221 def ctselect(self): 247 def ctselect(self):
222 - # ctselect application and set parameters 248 + '''ctselect application and set parameters'''
223 self.info("Running ctselect to cut on events") 249 self.info("Running ctselect to cut on events")
224 - self.validate() 250 + self.validate()# check the parameters
  251 +
225 if self.m_obs: 252 if self.m_obs:
226 filter = ct.ctselect(self.m_obs) 253 filter = ct.ctselect(self.m_obs)
227 else: 254 else:
228 filter = ct.ctselect() 255 filter = ct.ctselect()
229 256
  257 + #set the parameters for running the tool
230 filter["infile"] = self.m_raw_evt 258 filter["infile"] = self.m_raw_evt
231 filter["outfile"] = self.m_evtfile 259 filter["outfile"] = self.m_evtfile
232 filter["usepnt"].boolean(self.m_usepnt) # Use pointing for map centre 260 filter["usepnt"].boolean(self.m_usepnt) # Use pointing for map centre
@@ -241,6 +269,7 @@ class Analyser(base): @@ -241,6 +269,7 @@ class Analyser(base):
241 filter.logFileOpen() 269 filter.logFileOpen()
242 270
243 filter.run() 271 filter.run()
  272 + # if no Gobservation have been defined, then save the fits file.
244 if not(self.m_obs): 273 if not(self.m_obs):
245 filter.save() 274 filter.save()
246 275
@@ -251,14 +280,17 @@ class Analyser(base): @@ -251,14 +280,17 @@ class Analyser(base):
251 self.m_obs = filter.obs().copy() 280 self.m_obs = filter.obs().copy()
252 281
253 def ctbin(self,log=False,debug=False): 282 def ctbin(self,log=False,debug=False):
254 - # ctbin application and set parameters  
255 - self.validate() 283 + '''ctbin application and set parameters'''
256 self.info("Running ctbin to create count map") 284 self.info("Running ctbin to create count map")
  285 + self.validate()# check the parameters
  286 +
257 if self.m_obs: 287 if self.m_obs:
258 bin = ct.ctbin(self.m_obs) 288 bin = ct.ctbin(self.m_obs)
259 else: 289 else:
260 bin = ct.ctbin() 290 bin = ct.ctbin()
261 bin["evfile"] = self.m_evtfile 291 bin["evfile"] = self.m_evtfile
  292 +
  293 + #set the parameters for running the tool
262 bin["outfile"] = self.m_cntfile 294 bin["outfile"] = self.m_cntfile
263 bin["ebinalg"].string(self.m_ebinalg) 295 bin["ebinalg"].string(self.m_ebinalg)
264 bin["emin"].real(self.m_emin) 296 bin["emin"].real(self.m_emin)
@@ -290,14 +322,17 @@ class Analyser(base): @@ -290,14 +322,17 @@ class Analyser(base):
290 self.m_obs = bin.obs().copy() 322 self.m_obs = bin.obs().copy()
291 323
292 def create_fit(self,log=False,debug=False): 324 def create_fit(self,log=False,debug=False):
293 - self.validate() 325 + '''Create the like object from ctlike'''
294 # create ctlike instance with given parameters 326 # create ctlike instance with given parameters
295 self.info("Fitting Data using ctlike") 327 self.info("Fitting Data using ctlike")
  328 + self.validate()
  329 +
  330 + #set the parameters of the tools
296 if self.m_obs: 331 if self.m_obs:
297 self.like = ct.ctlike(self.m_obs) 332 self.like = ct.ctlike(self.m_obs)
298 else: 333 else:
299 self.like = ct.ctlike() 334 self.like = ct.ctlike()
300 - if self.m_binned: 335 + if self.m_binned#binned or unbinned analysis
301 self.like["infile"] = self.m_cntfile 336 self.like["infile"] = self.m_cntfile
302 else: 337 else:
303 self.like["infile"] = self.m_evtfile 338 self.like["infile"] = self.m_evtfile
@@ -312,10 +347,50 @@ class Analyser(base): @@ -312,10 +347,50 @@ class Analyser(base):
312 # Optionally open the log file 347 # Optionally open the log file
313 if log: 348 if log:
314 self.like.logFileOpen() 349 self.like.logFileOpen()
  350 +
315 # Optionally switch-on debugging model 351 # Optionally switch-on debugging model
316 if debug: 352 if debug:
317 self.like["debug"].boolean(True) 353 self.like["debug"].boolean(True)
318 354
  355 + def compute_butterfly(self,name,log=False,debug=False):
  356 + '''create ctlike instance with given parameters'''
  357 + self.info("Computing the data with ctbutterfly")
  358 + self.validate()
  359 +
  360 + if self.m_obs:
  361 + butterfly = ct.ctbutterfly(self.m_obs)
  362 + else:#parameters of the tools
  363 + butterfly = ct.ctbutterfly()
  364 + butterfly["infile"] = self.m_evtfile
  365 + butterfly['srcname'] = name
  366 + butterfly["emin"].real(self.m_emin)
  367 + butterfly["emax"].real(self.m_emax)
  368 + butterfly["caldb"].string(self.m_caldb)
  369 + butterfly["irf"].string(self.m_irf)
  370 + butterfly["srcmdl"] = self.m_xml
  371 + filename = name+"_butterfly.txt"
  372 + butterfly["outfile"] = filename
  373 +
  374 + # Optionally open the log file
  375 + if log:
  376 + butterfly.logFileOpen()
  377 + # Optionally switch-on debugging model
  378 + if debug:
  379 + butterfly["debug"].boolean(True)
  380 +
  381 + butterfly.run() #Compute the butterfly
  382 + butterfly.save() # save the txt files
  383 +
  384 + #Store the results in the Storage class
  385 + self.m_butterfly = ResultsStorage()
  386 + data = open(filename,'r').readlines()
  387 + for line in data:
  388 + words = string.split(line)
  389 + self.m_butterfly["ener"]["value"].append(float(words[0]))
  390 + self.m_butterfly["dnde"]["value"].append(float(words[1]))
  391 + self.m_butterfly["dnde"]["ed_value"].append(float(words[1]) - float(words[2]))
  392 + self.m_butterfly["dnde"]["eu_value"].append(float(words[1]) + float(words[2]))
  393 +
319 def fit(self,log=False,debug=False): 394 def fit(self,log=False,debug=False):
320 self.validate() 395 self.validate()
321 if not(self.like): 396 if not(self.like):
@@ -329,81 +404,82 @@ class Analyser(base): @@ -329,81 +404,82 @@ class Analyser(base):
329 self.success("Fit performed") 404 self.success("Fit performed")
330 405
331 def PrintResults(self,srcname = ""): 406 def PrintResults(self,srcname = ""):
  407 + ''' Print results of the fit '''
332 self.info("Results of the Fit") 408 self.info("Results of the Fit")
333 for m in self.like.obs().models(): 409 for m in self.like.obs().models():
334 if srcname == m.name() or srcname=="": 410 if srcname == m.name() or srcname=="":
335 print("Model : "+m.name()) 411 print("Model : "+m.name())
336 print(m) 412 print(m)
337 413
338 - def GetSrcResuls(self,Res,srcname,E0=None,factor = 1e6,tmin=None,tmax=None):  
339 - """function to get and store the results of a fit""" 414 + def GetSrcResuls(self,Res,srcname,E0=None,factor = 1e6):
  415 + """function to get and store the results of a fit. Store the results in the Storage class element"""
340 results = self.GetSrcParams(srcname) 416 results = self.GetSrcParams(srcname)
341 417
342 - if 1:  
343 - # #Time  
344 - # if (tmin is not None) or (tmax is not None) :  
345 - # Res["time"]["tmin_value"].append(tmin)  
346 - # Res["time"]["tmax_value"].append(tmax)  
347 - # Res["time"]["unit"] = "sec"  
348 - # else:  
349 - Res["time"]["tmin_value"].append(self.m_tmin)  
350 - Res["time"]["tmax_value"].append(self.m_tmax)  
351 - Res["time"]["unit"] = "sec"  
352 -  
353 - #Energy  
354 - if (E0 is not None): 418 + #Store the time
  419 + Res["time"]["tmin_value"].append(self.m_tmin)
  420 + Res["time"]["tmax_value"].append(self.m_tmax)
  421 + Res["time"]["unit"] = "sec"
  422 +
  423 + #Store the energy
  424 + if (E0 is not None):#if a 'pivot' energy is given
355 Res["ener"]["value"].append(E0*factor) 425 Res["ener"]["value"].append(E0*factor)
356 Res["ener"]["ed_value"].append((E0-self.m_emin)*factor) 426 Res["ener"]["ed_value"].append((E0-self.m_emin)*factor)
357 Res["ener"]["eu_value"].append((self.m_emax-E0)*factor) 427 Res["ener"]["eu_value"].append((self.m_emax-E0)*factor)
358 Res["ener"]["unit"] = "MeV" 428 Res["ener"]["unit"] = "MeV"
359 - else: 429 + else:#if not, the geometric mean energy is used
360 Res["ener"]["value"].append(sqrt(self.m_emin*self.m_emax)) 430 Res["ener"]["value"].append(sqrt(self.m_emin*self.m_emax))
361 Res["ener"]["ed_value"].append(-self.m_emin+sqrt(self.m_emin*self.m_emax)) 431 Res["ener"]["ed_value"].append(-self.m_emin+sqrt(self.m_emin*self.m_emax))
362 Res["ener"]["eu_value"].append(self.m_emax-sqrt(self.m_emin*self.m_emax)) 432 Res["ener"]["eu_value"].append(self.m_emax-sqrt(self.m_emin*self.m_emax))
363 Res["ener"]["unit"] = self.m_eunit 433 Res["ener"]["unit"] = self.m_eunit
364 434
  435 + #save the flux values
365 Res["Iflux"]["value"].append(results["flux"]) 436 Res["Iflux"]["value"].append(results["flux"])
366 Res["Iflux"]["eu_value"].append(results["eflux"]) 437 Res["Iflux"]["eu_value"].append(results["eflux"])
367 Res["Iflux"]["ed_value"].append(results["eflux"]) 438 Res["Iflux"]["ed_value"].append(results["eflux"])
368 - # Res["Iflux"]["unit"] = "unit"  
369 439
370 - m = self.GetModel(srcname)  
371 - Res["dnde"]["value"].append(m.spectral()[0].value())  
372 - Res["dnde"]["eu_value"].append(m.spectral()[0].error())  
373 - Res["dnde"]["ed_value"].append(m.spectral()[0].error()) 440 + #save the differential flux in a src model independent maner
  441 + srcmodel = self.GetModel(srcname)
  442 + Res["dnde"]["value"].append(srcmodel.spectral()[0].value())
  443 + Res["dnde"]["eu_value"].append(srcmodel.spectral()[0].error())
  444 + Res["dnde"]["ed_value"].append(srcmodel.spectral()[0].error())
374 445
375 - Res["TS"].append(100) 446 + Res["TS"].append(100) ## TODO use the real TS value
376 447
377 - UL = UpperLimitComputer(self,srcname) 448 + UL = UpperLimitComputer(self,srcname) #Compute the UL. To be updated
378 UL.run() 449 UL.run()
379 Res["ulim_dnde"].append(0) 450 Res["ulim_dnde"].append(0)
380 - # del UL 451 +
381 return Res 452 return Res
382 453
383 def GetSrcParams(self,srcname): 454 def GetSrcParams(self,srcname):
  455 + '''Retrive the source parameters from the like object and store it in a dictonnary'''
384 results = {} 456 results = {}
385 found = False 457 found = False
386 m = self.GetModel(srcname) 458 m = self.GetModel(srcname)
  459 +
  460 + #get the integral flux
387 results["flux"] = m.spectral().flux(gl.GEnergy(self.m_emin,self.m_eunit),gl.GEnergy(self.m_emax,self.m_eunit)) 461 results["flux"] = m.spectral().flux(gl.GEnergy(self.m_emin,self.m_eunit),gl.GEnergy(self.m_emax,self.m_eunit))
388 results["eflux"] = m.spectral().eflux(gl.GEnergy(self.m_emin,self.m_eunit),gl.GEnergy(self.m_emax,self.m_eunit)) 462 results["eflux"] = m.spectral().eflux(gl.GEnergy(self.m_emin,self.m_eunit),gl.GEnergy(self.m_emax,self.m_eunit))
  463 +
  464 + # Get free parameters
389 for par in m.spectral(): 465 for par in m.spectral():
390 if par.is_free(): 466 if par.is_free():
391 results[par.name()] = par.value() 467 results[par.name()] = par.value()
392 results["e"+par.name()] = par.error() 468 results["e"+par.name()] = par.error()
393 - 469 +
394 return results 470 return results
395 - 471 +
396 def GetModel(self,srcname): 472 def GetModel(self,srcname):
  473 + ''' Get the spectral parameters of the sources stored in the like object'''
397 found = False 474 found = False
398 for m in self.like.obs().models(): 475 for m in self.like.obs().models():
399 if m.name() == srcname: 476 if m.name() == srcname:
400 return m 477 return m
401 self.error("source "+srcname+" not in the source list") 478 self.error("source "+srcname+" not in the source list")
402 -  
403 479
404 def MakeEbin(analyse,nbins,srcname,binned = False): 480 def MakeEbin(analyse,nbins,srcname,binned = False):
405 #Store the results 481 #Store the results
406 - Res = ResultsSorage() 482 + Res = ResultsStorage()
407 483
408 #check the source name, exit is the srcname is false 484 #check the source name, exit is the srcname is false
409 analyse.GetModel(srcname) 485 analyse.GetModel(srcname)
@@ -454,7 +530,7 @@ def MakeEbin(analyse,nbins,srcname,binned = False): @@ -454,7 +530,7 @@ def MakeEbin(analyse,nbins,srcname,binned = False):
454 530
455 def MakeLC(analyse,nbins,srcname,binned = False): 531 def MakeLC(analyse,nbins,srcname,binned = False):
456 #Store the results 532 #Store the results
457 - Res = ResultsSorage() 533 + Res = ResultsStorage()
458 534
459 #check the source name, exit is the srcname is false 535 #check the source name, exit is the srcname is false
460 analyse.GetModel(srcname) 536 analyse.GetModel(srcname)
@@ -493,10 +569,11 @@ def MakeLC(analyse,nbins,srcname,binned = False): @@ -493,10 +569,11 @@ def MakeLC(analyse,nbins,srcname,binned = False):
493 return Res 569 return Res
494 570
495 class UpperLimitComputer(base): 571 class UpperLimitComputer(base):
  572 + '''This class compute the ul and will be removed'''
496 def __init__(self,analyser,srcname,parname = "Prefactor"): 573 def __init__(self,analyser,srcname,parname = "Prefactor"):
497 super(UpperLimitComputer,self).__init__() 574 super(UpperLimitComputer,self).__init__()
498 self.info("Creating "+self.classname+" object") 575 self.info("Creating "+self.classname+" object")
499 - # self.like = analyser.like.copy() 576 +
500 obs = analyser.like.obs().copy() 577 obs = analyser.like.obs().copy()
501 self.like = ct.ctlike(obs) 578 self.like = ct.ctlike(obs)
502 self.succes = False 579 self.succes = False
pyext/ctools/plotutils.py
@@ -56,7 +56,7 @@ class SpectralBase(object): @@ -56,7 +56,7 @@ class SpectralBase(object):
56 def __init__(self,sed=True,sed_factor=1.): 56 def __init__(self,sed=True,sed_factor=1.):
57 self.m_sed_factor = sed_factor 57 self.m_sed_factor = sed_factor
58 self.m_sed = sed 58 self.m_sed = sed
59 - 59 +
60 def _convertSED(self,tab,energy): 60 def _convertSED(self,tab,energy):
61 """convert the a table storing dN/dE in sed with right units""" 61 """convert the a table storing dN/dE in sed with right units"""
62 62
@@ -68,6 +68,26 @@ class SpectralBase(object): @@ -68,6 +68,26 @@ class SpectralBase(object):
68 tab[i] *= energy[i]**2*self.m_sed_factor 68 tab[i] *= energy[i]**2*self.m_sed_factor
69 return tab 69 return tab
70 70
  71 + def _convertE(self,energy,unit,newunit):
  72 + """convert the a energy which has units 'unit' to "newunit'"""
  73 + factor = 1
  74 + if unit == "MeV" and newunit == "GeV" :
  75 + factor = 1e-3
  76 + if unit == "MeV" and newunit == "TeV" :
  77 + factor = 1e-6
  78 + if unit == "GeV" and newunit == "TeV" :
  79 + factor = 1e-3
  80 + if unit == "GeV" and newunit == "MeV" :
  81 + factor = 1e3
  82 + if unit == "TeV" and newunit == "GeV" :
  83 + factor = 1e3
  84 + if unit == "TeV" and newunit == "MeV" :
  85 + factor = 1e6
  86 + for i in xrange(len(energy)):
  87 + energy[i] *= factor
  88 + return energy
  89 +
  90 +
71 BLUE="#337EF5" 91 BLUE="#337EF5"
72 GREY='grey' 92 GREY='grey'
73 GREEN = '#21851D' 93 GREEN = '#21851D'
@@ -103,6 +123,7 @@ class residuals(analysisutils.base,options,SpectralBase): @@ -103,6 +123,7 @@ class residuals(analysisutils.base,options,SpectralBase):
103 Energy_list = {"MeV":1,"GeV":1e-3,"TeV":1e-6} #TODO 123 Energy_list = {"MeV":1,"GeV":1e-3,"TeV":1e-6} #TODO
104 for i in range(self.Npt): 124 for i in range(self.Npt):
105 if self.m_point_info["TS"][i] >= self.tslim: 125 if self.m_point_info["TS"][i] >= self.tslim:
  126 + #TODO remove the like
106 th_val.append(self.spectrum.eval(gl.GEnergy(self.m_point_info["ener"]["value"][i],self.m_point_info["ener"]["unit"]),gl.GTime(0))) 127 th_val.append(self.spectrum.eval(gl.GEnergy(self.m_point_info["ener"]["value"][i],self.m_point_info["ener"]["unit"]),gl.GTime(0)))
107 index.append(i) 128 index.append(i)
108 else: 129 else:
@@ -139,7 +160,7 @@ class ulimgraph(analysisutils.base,options,SpectralBase): @@ -139,7 +160,7 @@ class ulimgraph(analysisutils.base,options,SpectralBase):
139 self.Npt = len(self.m_point_info["dnde"]["value"]) 160 self.Npt = len(self.m_point_info["dnde"]["value"])
140 161
141 def _plt_points(self): 162 def _plt_points(self):
142 - results = analysisutils.ResultsSorage() 163 + results = analysisutils.ResultsStorage()
143 164
144 Energy_list = {"MeV":1,"GeV":1e-3,"TeV":1e-6} #TODO 165 Energy_list = {"MeV":1,"GeV":1e-3,"TeV":1e-6} #TODO
145 for i in range(self.Npt): 166 for i in range(self.Npt):
@@ -232,22 +253,19 @@ class SpectrumPlotter(analysisutils.base,SpectralBase): @@ -232,22 +253,19 @@ class SpectrumPlotter(analysisutils.base,SpectralBase):
232 if data points are provided, only change applied is energy unit convertion to match the butterfly one 253 if data points are provided, only change applied is energy unit convertion to match the butterfly one
233 (i.e. no dN/dE to SED conversion). 254 (i.e. no dN/dE to SED conversion).
234 It is currently assumed that the unit is MeV for the energy of the data point. this will be change 255 It is currently assumed that the unit is MeV for the energy of the data point. this will be change
235 - once the I/O container format will be defined."""  
236 - def __init__(self,srcname,like,datapoint,emin=0.1,emax=100,energy = "TeV",SED = True ,npt = 50): 256 + once the I/O container format will be defined.
  257 + like is used to compute the residual. if like = None, no residual will be computed TODO
  258 + butterfly is a results Storage object read from the file produced by ctbutterfly
  259 + datapoint is the results Storage object for the datapoints."""
  260 + def __init__(self,srcname,like, butterfly,datapoint,emin=0.1,emax=100,energy = "TeV",SED = True):
237 super(SpectrumPlotter,self).__init__() 261 super(SpectrumPlotter,self).__init__()
  262 + self.m_ebound = [emin,emax]
  263 + self.m_name = srcname
  264 + self.m_butterfly = butterfly
  265 + self.m_spectral = like.obs().models()[srcname].spectral()
  266 + self.m_but = []
  267 + self.m_enebut = []
238 268
239 - self.m_ebound = [emin,emax]  
240 - self.m_name = srcname  
241 - self.m_like = like  
242 - self.m_spectral = like.obs().models()[srcname].spectral()  
243 - self.m_energy = []  
244 - self.m_flux = []  
245 - self.m_error = []  
246 - self.m_but = []  
247 - self.m_enebut = []  
248 - self.m_npt = npt  
249 - self.m_covar = gl.GMatrix(1,1)  
250 - self.covar()  
251 #~ this part take care of the style : SED or differential flux 269 #~ this part take care of the style : SED or differential flux
252 #~ in the case of SED, the y-unit is erg/cm2/s 270 #~ in the case of SED, the y-unit is erg/cm2/s
253 self.m_sed = SED 271 self.m_sed = SED
@@ -260,6 +278,7 @@ class SpectrumPlotter(analysisutils.base,SpectralBase): @@ -260,6 +278,7 @@ class SpectrumPlotter(analysisutils.base,SpectralBase):
260 self.points = ulimgraph(datapoint,self.m_sed,gl.MeV2erg,energy) 278 self.points = ulimgraph(datapoint,self.m_sed,gl.MeV2erg,energy)
261 self.residuals = residuals(self.m_spectral,datapoint,self.m_sed,gl.MeV2erg,energy) 279 self.residuals = residuals(self.m_spectral,datapoint,self.m_sed,gl.MeV2erg,energy)
262 280
  281 +
263 def _validateUnits(self): 282 def _validateUnits(self):
264 Energy_list = {"MeV":1,"GeV":1e3,"TeV":1e6} 283 Energy_list = {"MeV":1,"GeV":1e3,"TeV":1e6}
265 if not(Energy_list.has_key(self.eunit)): 284 if not(Energy_list.has_key(self.eunit)):
@@ -269,74 +288,24 @@ class SpectrumPlotter(analysisutils.base,SpectralBase): @@ -269,74 +288,24 @@ class SpectrumPlotter(analysisutils.base,SpectralBase):
269 if self.m_sed: 288 if self.m_sed:
270 self.m_sed_factor = gl.MeV2erg*Energy_list[self.eunit]**2 289 self.m_sed_factor = gl.MeV2erg*Energy_list[self.eunit]**2
271 290
272 - def covar(self):  
273 - # Get covariance matrix if fit has converged  
274 - try:  
275 - fullcovar = self.m_like.obs().function().curvature().invert()  
276 - except:  
277 - self.warning("Covariance matrix not determined successfully")  
278 - return  
279 - #~ get the matrix element of the source of interest  
280 - #~ 1) get the right element indices  
281 - idx = 0  
282 - par_index_map = []  
283 - for m in self.m_like.obs().models() :  
284 - if m.name()!= self.m_name:  
285 - idx += m.size()  
286 - continue  
287 - idx += m.spatial().size()  
288 - for par in m.spectral():  
289 - if par.is_free():  
290 - par_index_map.append(idx)  
291 - idx += 1  
292 -  
293 - #~ 2) get the elemets and store them in a matrix  
294 - self.m_covar = gl.GMatrix(len(par_index_map),len(par_index_map))  
295 - i = 0  
296 - for xpar in par_index_map:  
297 - j = 0  
298 - for ypar in par_index_map:  
299 - self.m_covar[i,j] = fullcovar[xpar,ypar]  
300 - j += 1  
301 - i += 1  
302 - self.success("Covariance Matrix succesfuly computed")  
303 -  
304 def _makespectrum(self): 291 def _makespectrum(self):
305 - for i in xrange(self.m_npt):  
306 - #Compute the energy  
307 - lene = log10(self.m_ebound[0])+log10(self.m_ebound[1])*i/(self.m_npt-1)  
308 - self.m_energy.append(pow(10,lene))  
309 - #Compute the flux  
310 - self.m_flux.append(self.m_spectral.eval(gl.GEnergy(pow(10,lene),self.eunit),gl.GTime(0)))  
311 -  
312 - #Compute the gradients  
313 - if self.m_covar.size() != 1:  
314 - self.m_spectral.eval_gradients(gl.GEnergy(pow(10,lene), self.eunit),gl.GTime(0))  
315 - #store them into a GVector  
316 - Derivative = gl.GVector(self.m_covar.size()/2)  
317 - j = 0  
318 - for par in self.m_spectral:  
319 - if par.is_free():  
320 - Derivative[j] = par.factor_gradient()  
321 - j += 1  
322 - #~ computed the error  
323 - self.m_error.append(sqrt(Derivative * (self.m_covar*Derivative)))  
324 -  
325 - #~ convert the flux in sed if asked  
326 - self.m_flux = self._convertSED(self.m_flux,self.m_energy)  
327 - if self.m_covar.size() != 1:  
328 - self.m_error = self._convertSED(self.m_error,self.m_energy)  
329 - self._makebutterfly() # make the butterfly  
330 - self.success("Spectrum computed")  
331 - 292 + #convert the flux in sed if asked
  293 + self.m_energy = self._convertE(self.m_butterfly['ener']["value"],"MeV","TeV") #gtbutterfly gives MeV
  294 + self.m_flux = self._convertSED(self.m_butterfly['dnde']["value"],self.m_butterfly['ener']["value"])
  295 + self.m_error_d = self._convertSED(self.m_butterfly['dnde']["ed_value"],self.m_butterfly['ener']["value"])
  296 + self.m_error_u = self._convertSED(self.m_butterfly['dnde']["eu_value"],self.m_butterfly['ener']["value"])
  297 + self._makebutterfly() # make the butterfly
  298 +
  299 + self.success("Butterfly ready to be plotted")
  300 +#
332 def _makebutterfly(self): 301 def _makebutterfly(self):
333 - """make the butterfly by appending element in a table"""  
334 - for i in xrange(self.m_npt):  
335 - self.m_but.append(self.m_flux[i]+self.m_error[i]) 302 + """make the butterfly by reading the result and making a closed table"""
  303 + for i in xrange(len(self.m_energy)):
  304 + self.m_but.append(self.m_error_u[i])
336 self.m_enebut.append(self.m_energy[i]) 305 self.m_enebut.append(self.m_energy[i])
337 - for i in xrange(self.m_npt):  
338 - idx = self.m_npt-i-1  
339 - self.m_but.append(self.m_flux[idx]-self.m_error[idx]) 306 + for i in xrange(len(self.m_energy)):
  307 + idx = len(self.m_energy)-i-1
  308 + self.m_but.append(self.m_error_d[idx])
340 self.m_enebut.append(self.m_energy[idx]) 309 self.m_enebut.append(self.m_energy[idx])
341 self.m_but.append(self.m_but[0]) 310 self.m_but.append(self.m_but[0])
342 self.m_enebut.append(self.m_enebut[0]) 311 self.m_enebut.append(self.m_enebut[0])