Commit a448964cd5bb31bd5ef515cadb62ca5f0d9df91d

Authored by Jürgen Knödlseder
1 parent 08e0327b

Add logL and event statistics to pull distribution output file.

Showing 1 changed file with 311 additions and 305 deletions
scripts/cspull.py
... ... @@ -30,332 +30,338 @@ import math
30 30 # cspull class #
31 31 # ============ #
32 32 class cspull(GApplication):
33   - """
34   - This class implements the pull distribution generation script. It derives
35   - from the GammaLib::GApplication class which provides support for parameter
36   - files, command line arguments, and logging. In that way the Python
37   - script behaves just as a regular ctool.
38   - """
39   - def __init__(self, *argv):
40   - """
41   - Constructor.
42   - """
43   - # Set name
44   - self.name = "cspull"
45   - self.version = "0.2.0"
46   -
47   - # Initialise some members
48   - self.obs = None
49   - self.model = None
50   - self.m_srcmdl = None
51   -
52   - # Make sure that parfile exists
53   - file = self.parfile()
  33 + """
  34 + This class implements the pull distribution generation script. It derives
  35 + from the GammaLib::GApplication class which provides support for parameter
  36 + files, command line arguments, and logging. In that way the Python
  37 + script behaves just as a regular ctool.
  38 + """
  39 + def __init__(self, *argv):
  40 + """
  41 + Constructor.
  42 + """
  43 + # Set name
  44 + self.name = "cspull"
  45 + self.version = "0.2.0"
  46 +
  47 + # Initialise some members
  48 + self.obs = None
  49 + self.model = None
  50 + self.m_srcmdl = None
  51 +
  52 + # Make sure that parfile exists
  53 + file = self.parfile()
54 54  
55   - # Initialise application
56   - if len(argv) == 0:
57   - GApplication.__init__(self, self.name, self.version)
58   - elif len(argv) ==1:
59   - GApplication.__init__(self, self.name, self.version, *argv)
60   - else:
61   - raise TypeError("Invalid number of arguments given.")
  55 + # Initialise application
  56 + if len(argv) == 0:
  57 + GApplication.__init__(self, self.name, self.version)
  58 + elif len(argv) ==1:
  59 + GApplication.__init__(self, self.name, self.version, *argv)
  60 + else:
  61 + raise TypeError("Invalid number of arguments given.")
62 62  
63   - # Set logger properties
64   - self.log_header()
65   - self.log.date(True)
  63 + # Set logger properties
  64 + self.log_header()
  65 + self.log.date(True)
66 66  
67   - # Return
68   - return
69   -
70   - def __del__(self):
71   - """
72   - Destructor.
73   - """
74   - # Write separator into logger
75   - if self.logTerse():
76   - self.log("\n")
77   -
78   - # Return
79   - return
  67 + # Return
  68 + return
  69 +
  70 + def __del__(self):
  71 + """
  72 + Destructor.
  73 + """
  74 + # Write separator into logger
  75 + if self.logTerse():
  76 + self.log("\n")
  77 +
  78 + # Return
  79 + return
80 80  
81   - def parfile(self):
82   - """
83   - Check if parfile exists. If parfile does not exist then create a
84   - default parfile. This kluge avoids shipping the cscript with a parfile.
85   - """
86   - # Set parfile name
87   - parfile = self.name+".par"
88   -
89   - try:
90   - pars = GApplicationPars(parfile)
91   - except:
92   - # Signal if parfile was not found
93   - sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n")
94   -
95   - # Create default parfile
96   - pars = GApplicationPars()
97   - pars.append(GApplicationPar("srcmdl","f","a","$GAMMALIB/share/models/crab.xml","","","Source model"))
98   - pars.append(GApplicationPar("outfile","f","a","pull.dat","","","Output file name"))
99   - pars.append(GApplicationPar("ntrials","i","a","10","","","Number of trials"))
100   - pars.append(GApplicationPar("caldb","s","h","","","","Calibration database"))
101   - pars.append(GApplicationPar("irf","s","a","cta_dummy_irf","","","Instrument response function"))
102   - pars.append(GApplicationPar("ra","r","a","83.6331","0","360","RA of pointing (deg)"))
103   - pars.append(GApplicationPar("dec","r","a","22.0145","-90","90","Dec of pointing (deg)"))
104   - pars.append(GApplicationPar("emin","r","a","0.1","0.0","","Lower energy limit (TeV)"))
105   - pars.append(GApplicationPar("emax","r","a","100.0","0.0","","Upper energy limit (TeV)"))
106   - pars.append(GApplicationPar("enumbins","i","a","0","","","Number of energy bins (0=unbinned)"))
107   - pars.append(GApplicationPar("duration","r","a","180000.0","","","Effective exposure time (s)"))
108   - pars.append(GApplicationPar("deadc","r","h","0.95","","","Deadtime correction factor"))
109   - pars.append(GApplicationPar("rad","r","h","5.0","","","Radius of ROI (deg)"))
110   - pars.append(GApplicationPar("npix","i","h","200","","","Number of pixels for binned"))
111   - pars.append(GApplicationPar("binsz","r","h","0.05","","","Pixel size for binned (deg/pixel)"))
112   - pars.append_standard()
113   - pars.save(parfile)
114   -
115   - # Return
116   - return
117   -
118   - def get_parameters(self):
119   - """
120   - Get parameters from parfile and setup the observation.
121   - """
122   - # Get parameters
123   - if self.model == None:
124   - self.m_srcmdl = self["srcmdl"].filename()
125   - self.m_outfile = self["outfile"].filename()
126   - self.m_ntrials = self["ntrials"].integer()
127   - self.m_caldb = self["caldb"].string()
128   - self.m_irf = self["irf"].string()
129   - self.m_ra = self["ra"].real()
130   - self.m_dec = self["dec"].real()
131   - self.m_emin = self["emin"].real()
132   - self.m_emax = self["emax"].real()
133   - self.m_enumbins = self["enumbins"].integer()
134   - self.m_duration = self["duration"].real()
135   - self.m_deadc = self["deadc"].real()
136   - self.m_rad = self["rad"].real()
137   - self.m_npix = self["npix"].integer()
138   - self.m_binsz = self["binsz"].real()
  81 + def parfile(self):
  82 + """
  83 + Check if parfile exists. If parfile does not exist then create a
  84 + default parfile. This kluge avoids shipping the cscript with a parfile.
  85 + """
  86 + # Set parfile name
  87 + parfile = self.name+".par"
  88 +
  89 + try:
  90 + pars = GApplicationPars(parfile)
  91 + except:
  92 + # Signal if parfile was not found
  93 + sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n")
  94 +
  95 + # Create default parfile
  96 + pars = GApplicationPars()
  97 + pars.append(GApplicationPar("srcmdl","f","a","$GAMMALIB/share/models/crab.xml","","","Source model"))
  98 + pars.append(GApplicationPar("outfile","f","a","pull.dat","","","Output file name"))
  99 + pars.append(GApplicationPar("ntrials","i","a","10","","","Number of trials"))
  100 + pars.append(GApplicationPar("caldb","s","h","","","","Calibration database"))
  101 + pars.append(GApplicationPar("irf","s","a","cta_dummy_irf","","","Instrument response function"))
  102 + pars.append(GApplicationPar("ra","r","a","83.6331","0","360","RA of pointing (deg)"))
  103 + pars.append(GApplicationPar("dec","r","a","22.0145","-90","90","Dec of pointing (deg)"))
  104 + pars.append(GApplicationPar("emin","r","a","0.1","0.0","","Lower energy limit (TeV)"))
  105 + pars.append(GApplicationPar("emax","r","a","100.0","0.0","","Upper energy limit (TeV)"))
  106 + pars.append(GApplicationPar("enumbins","i","a","0","","","Number of energy bins (0=unbinned)"))
  107 + pars.append(GApplicationPar("duration","r","a","180000.0","","","Effective exposure time (s)"))
  108 + pars.append(GApplicationPar("deadc","r","h","0.95","","","Deadtime correction factor"))
  109 + pars.append(GApplicationPar("rad","r","h","5.0","","","Radius of ROI (deg)"))
  110 + pars.append(GApplicationPar("npix","i","h","200","","","Number of pixels for binned"))
  111 + pars.append(GApplicationPar("binsz","r","h","0.05","","","Pixel size for binned (deg/pixel)"))
  112 + pars.append_standard()
  113 + pars.save(parfile)
  114 +
  115 + # Return
  116 + return
  117 +
  118 + def get_parameters(self):
  119 + """
  120 + Get parameters from parfile and setup the observation.
  121 + """
  122 + # Get parameters
  123 + if self.model == None:
  124 + self.m_srcmdl = self["srcmdl"].filename()
  125 + self.m_outfile = self["outfile"].filename()
  126 + self.m_ntrials = self["ntrials"].integer()
  127 + self.m_caldb = self["caldb"].string()
  128 + self.m_irf = self["irf"].string()
  129 + self.m_ra = self["ra"].real()
  130 + self.m_dec = self["dec"].real()
  131 + self.m_emin = self["emin"].real()
  132 + self.m_emax = self["emax"].real()
  133 + self.m_enumbins = self["enumbins"].integer()
  134 + self.m_duration = self["duration"].real()
  135 + self.m_deadc = self["deadc"].real()
  136 + self.m_rad = self["rad"].real()
  137 + self.m_npix = self["npix"].integer()
  138 + self.m_binsz = self["binsz"].real()
139 139  
140   - # Set some fixed parameters
141   - self.m_log = False # Logging in client tools
142   - self.m_debug = False # Debugging in client tools
143   -
144   - # Setup observation
145   - self.obs = self.set_obs(ra=self.m_ra, dec=self.m_dec, \
146   - emin=self.m_emin, emax=self.m_emax)
147   -
148   - # Load source model
149   - if self.m_srcmdl != None:
150   - self.model = GModels(self.m_srcmdl)
151   -
152   - # Append source model to observation
153   - self.obs.models(self.model)
  140 + # Set some fixed parameters
  141 + self.m_log = False # Logging in client tools
  142 + self.m_debug = False # Debugging in client tools
  143 +
  144 + # Setup observation
  145 + self.obs = self.set_obs(ra=self.m_ra, dec=self.m_dec, \
  146 + emin=self.m_emin, emax=self.m_emax)
  147 +
  148 + # Load source model
  149 + if self.m_srcmdl != None:
  150 + self.model = GModels(self.m_srcmdl)
  151 +
  152 + # Append source model to observation
  153 + self.obs.models(self.model)
154 154  
155   - # Return
156   - return
157   -
158   - def models(self, models):
159   - """
160   - Set model.
161   - """
162   - # Copy models
163   - self.model = models.copy()
164   -
165   - # Return
166   - return
167   -
168   - def execute(self):
169   - """
170   - Execute the script.
171   - """
172   - # Run the script
173   - self.run()
174   -
175   - # Return
176   - return
  155 + # Return
  156 + return
  157 +
  158 + def models(self, models):
  159 + """
  160 + Set model.
  161 + """
  162 + # Copy models
  163 + self.model = models.copy()
  164 +
  165 + # Return
  166 + return
  167 +
  168 + def execute(self):
  169 + """
  170 + Execute the script.
  171 + """
  172 + # Run the script
  173 + self.run()
  174 +
  175 + # Return
  176 + return
177 177  
178   - def run(self):
179   - """
180   - Run the script.
181   - """
182   - # Switch screen logging on in debug mode
183   - if self.logDebug():
184   - self.log.cout(True)
  178 + def run(self):
  179 + """
  180 + Run the script.
  181 + """
  182 + # Switch screen logging on in debug mode
  183 + if self.logDebug():
  184 + self.log.cout(True)
185 185  
186   - # Get parameters
187   - self.get_parameters()
188   -
189   - # Write input parameters into logger
190   - if self.logTerse():
191   - self.log_parameters()
192   - self.log("\n")
193   -
194   - # Write observation into logger
195   - if self.logTerse():
196   - self.log("\n")
197   - self.log.header1("Observation")
198   - self.log(str(self.obs))
199   - self.log("\n")
  186 + # Get parameters
  187 + self.get_parameters()
  188 +
  189 + # Write input parameters into logger
  190 + if self.logTerse():
  191 + self.log_parameters()
  192 + self.log("\n")
  193 +
  194 + # Write observation into logger
  195 + if self.logTerse():
  196 + self.log("\n")
  197 + self.log.header1("Observation")
  198 + self.log(str(self.obs))
  199 + self.log("\n")
200 200  
201   - # Write header
202   - if self.logTerse():
203   - self.log("\n")
204   - self.log.header1("Generate pull distribution")
  201 + # Write header
  202 + if self.logTerse():
  203 + self.log("\n")
  204 + self.log.header1("Generate pull distribution")
205 205  
206   - # Loop over trials
207   - for seed in range(self.m_ntrials):
208   -
209   - # Make a trial
210   - result = self.trial(seed)
211   -
212   - # Write out result immediately
213   - if seed == 0:
214   - file = open(self.m_outfile, 'w')
215   - writer = csv.DictWriter(file, result['colnames'])
216   - writer.writerow(dict((_,_) for _ in result['colnames']))
217   - else:
218   - file = open(self.m_outfile, 'a')
219   - writer = csv.DictWriter(file, result['colnames'])
220   - writer.writerow(result['values'])
221   - file.close()
222   -
223   - # Return
224   - return
225   -
226   - def set_obs(self, ra=83.6331, dec=22.0145, emin=0.1, emax=100.0):
227   - """
228   - Returns an observation container with a single CTA observation.
229   -
230   - Keywords:
231   - ra - Right Ascension of pointing [deg] (default: 83.6331)
232   - dec - Declination of pointing [deg] (default: 22.0145)
233   - emin - Minimum energy [TeV] (default: 0.1)
234   - emax - Maximum energy [TeV] (default: 100.0)
235   - """
236   - # Allocate observation container
237   - obs = GObservations()
238   -
239   - # Set single pointing
240   - pntdir = GSkyDir()
241   - pntdir.radec_deg(ra, dec)
242   -
243   - # Create CTA observation
244   - run = obsutils.set(pntdir, caldb=self.m_caldb, irf=self.m_irf, \
245   - duration=self.m_duration, deadc=self.m_deadc, \
  206 + # Loop over trials
  207 + for seed in range(self.m_ntrials):
  208 +
  209 + # Make a trial
  210 + result = self.trial(seed)
  211 +
  212 + # Write out result immediately
  213 + if seed == 0:
  214 + file = open(self.m_outfile, 'w')
  215 + writer = csv.DictWriter(file, result['colnames'])
  216 + writer.writerow(dict((_,_) for _ in result['colnames']))
  217 + else:
  218 + file = open(self.m_outfile, 'a')
  219 + writer = csv.DictWriter(file, result['colnames'])
  220 + writer.writerow(result['values'])
  221 + file.close()
  222 +
  223 + # Return
  224 + return
  225 +
  226 + def set_obs(self, ra=83.6331, dec=22.0145, emin=0.1, emax=100.0):
  227 + """
  228 + Returns an observation container with a single CTA observation.
  229 +
  230 + Keywords:
  231 + ra - Right Ascension of pointing [deg] (default: 83.6331)
  232 + dec - Declination of pointing [deg] (default: 22.0145)
  233 + emin - Minimum energy [TeV] (default: 0.1)
  234 + emax - Maximum energy [TeV] (default: 100.0)
  235 + """
  236 + # Allocate observation container
  237 + obs = GObservations()
  238 +
  239 + # Set single pointing
  240 + pntdir = GSkyDir()
  241 + pntdir.radec_deg(ra, dec)
  242 +
  243 + # Create CTA observation
  244 + run = obsutils.set(pntdir, caldb=self.m_caldb, irf=self.m_irf, \
  245 + duration=self.m_duration, deadc=self.m_deadc, \
246 246 emin=emin, emax=emax, rad=self.m_rad)
247   -
248   - # Append observation to container
249   - obs.append(run)
250   -
251   - # Return observation container
252   - return obs
253   -
254   - def trial(self, seed):
255   - """
256   - Create the pull for a single trial.
257   -
258   - Parameters:
259   - seed - Random number generator seed
260   - """
261   - # Write header
262   - if self.logExplicit():
263   - self.log.header2("Trial "+str(seed+1))
  247 +
  248 + # Append observation to container
  249 + obs.append(run)
  250 +
  251 + # Return observation container
  252 + return obs
  253 +
  254 + def trial(self, seed):
  255 + """
  256 + Create the pull for a single trial.
  257 +
  258 + Parameters:
  259 + seed - Random number generator seed
  260 + """
  261 + # Write header
  262 + if self.logExplicit():
  263 + self.log.header2("Trial "+str(seed+1))
264 264  
265   - # Simulate events
266   - obs = obsutils.sim(self.obs, \
267   - nbins=self.m_enumbins, \
268   - seed=seed, \
269   - binsz=self.m_binsz, \
270   - npix=self.m_npix, \
271   - log=self.m_log, debug=self.m_debug)
  265 + # Simulate events
  266 + obs = obsutils.sim(self.obs, \
  267 + nbins=self.m_enumbins, \
  268 + seed=seed, \
  269 + binsz=self.m_binsz, \
  270 + npix=self.m_npix, \
  271 + log=self.m_log, debug=self.m_debug)
272 272  
273   - # Determine number of events in simulation
274   - nevents = 0.0
275   - for run in obs:
276   - nevents += run.events().number()
  273 + # Determine number of events in simulation
  274 + nevents = 0.0
  275 + for run in obs:
  276 + nevents += run.events().number()
277 277  
278   - # Write simulation results
279   - if self.logExplicit():
280   - self.log.header3("Simulation")
281   - self.log.parformat("Number of simulated events")
282   - self.log(nevents)
283   - self.log("\n")
  278 + # Write simulation results
  279 + if self.logExplicit():
  280 + self.log.header3("Simulation")
  281 + self.log.parformat("Number of simulated events")
  282 + self.log(nevents)
  283 + self.log("\n")
284 284  
285   - # Fit model
286   - like = obsutils.fit(obs, log=self.m_log, debug=self.m_debug)
  285 + # Fit model
  286 + like = obsutils.fit(obs, log=self.m_log, debug=self.m_debug)
287 287  
288   - # Store results
289   - logL = like.opt().value()
290   - npred = like.obs().npred()
291   - models = like.obs().models()
  288 + # Store results
  289 + logL = like.opt().value()
  290 + npred = like.obs().npred()
  291 + models = like.obs().models()
292 292  
293   - # Write result header
294   - if self.logExplicit():
295   - self.log.header3("Pulls")
296   -
297   - # Gather results
298   - colnames = []
299   - values = {}
300   - for i in range(models.size()):
301   - model = models[i]
302   - model_name = model.name()
303   - for k in range(model.size()):
304   - par = model[k]
305   - if par.is_free():
306   -
307   - # Set parameter name
308   - name = model_name+"_"+par.name()
309   -
310   - # Append parameter, Pull_parameter and Unc_parameter
311   - colnames.append(name)
312   - colnames.append("Pull_"+name)
313   - colnames.append("Unc_"+name)
314   -
315   - # Compute pull
316   - fitted_value = par.value()
317   - real_value = self.model[i][k].value()
318   - error = par.error()
319   - if error != 0.0:
320   - pull = (fitted_value - real_value) / error
321   - else:
322   - pull = 99.0
323   -
324   - # Store results
325   - values[name] = fitted_value
326   - values["Pull_"+name] = pull
327   - values["Unc_"+name] = error
  293 + # Write result header
  294 + if self.logExplicit():
  295 + self.log.header3("Pulls")
  296 +
  297 + # Gather results
  298 + colnames = []
  299 + values = {}
  300 + colnames.append("LogL")
  301 + colnames.append("Sim_Events")
  302 + colnames.append("Npred_Events")
  303 + values["LogL"] = logL
  304 + values["Sim_Events"] = nevents
  305 + values["Npred_Events"] = npred
  306 + for i in range(models.size()):
  307 + model = models[i]
  308 + model_name = model.name()
  309 + for k in range(model.size()):
  310 + par = model[k]
  311 + if par.is_free():
  312 +
  313 + # Set parameter name
  314 + name = model_name+"_"+par.name()
  315 +
  316 + # Append parameter, Pull_parameter and Unc_parameter
  317 + colnames.append(name)
  318 + colnames.append("Pull_"+name)
  319 + colnames.append("Unc_"+name)
  320 +
  321 + # Compute pull
  322 + fitted_value = par.value()
  323 + real_value = self.model[i][k].value()
  324 + error = par.error()
  325 + if error != 0.0:
  326 + pull = (fitted_value - real_value) / error
  327 + else:
  328 + pull = 99.0
  329 +
  330 + # Store results
  331 + values[name] = fitted_value
  332 + values["Pull_"+name] = pull
  333 + values["Unc_"+name] = error
328 334  
329   - # Write result
330   - if self.logExplicit():
331   - self.log.parformat(name)
332   - self.log(pull)
333   - self.log(" (")
334   - self.log(fitted_value)
335   - self.log(" +/- ")
336   - self.log(error)
337   - self.log(")\n")
338   -
339   - # Bundle together results
340   - result = {'colnames': colnames, 'values': values}
341   -
342   - # Return
343   - return result
  335 + # Write result
  336 + if self.logExplicit():
  337 + self.log.parformat(name)
  338 + self.log(pull)
  339 + self.log(" (")
  340 + self.log(fitted_value)
  341 + self.log(" +/- ")
  342 + self.log(error)
  343 + self.log(")\n")
  344 +
  345 + # Bundle together results
  346 + result = {'colnames': colnames, 'values': values}
  347 +
  348 + # Return
  349 + return result
344 350  
345 351  
346 352 # ======================== #
347 353 # Main routine entry point #
348 354 # ======================== #
349 355 if __name__ == '__main__':
350   - """
351   - Generates pull distribution for a source model.
352   - """
353   - # Create instance of application
354   - app = cspull(sys.argv)
355   -
356   - # Open logfile
357   - app.logFileOpen()
358   -
359   - # Execute application
360   - app.execute()
361   -
362 356 \ No newline at end of file
  357 + """
  358 + Generates pull distribution for a source model.
  359 + """
  360 + # Create instance of application
  361 + app = cspull(sys.argv)
  362 +
  363 + # Open logfile
  364 + app.logFileOpen()
  365 +
  366 + # Execute application
  367 + app.execute()
  368 +
363 369 \ No newline at end of file
... ...