analysisutils.py
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 |
|