24 from cscripts
import obsutils
25 from cscripts
import ioutils
26 from cscripts
import mputils
34 Generates pull distributions for a model
42 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv)
54 Extend ctools.csobservation getstate method to include some members
62 state = {
'base' : ctools.csobservation.__getstate__(self),
71 Extend ctools.csobservation setstate method to include some members
78 ctools.csobservation.__setstate__(self, state[
'base'])
79 self.
_fits = state[
'fits']
89 Get parameters from parfile
92 if self.obs().is_empty():
93 self.obs(self._get_observations())
98 self._setup_observations(self.obs())
101 self._set_obs_statistic(gammalib.toupper(self[
'statistic'].string()))
104 enumbins = self[
'enumbins'].integer()
107 if gammalib.toupper(self[
'onsrc'].string()) !=
'NONE':
112 self[
'npix'].integer()
114 self[
'coordsys'].string()
115 self[
'proj'].string()
118 if self.obs().
models().is_empty():
119 self.obs().
models(self[
'inmodel'].filename())
122 self[
'ntrials'].integer()
123 self[
'edisp'].boolean()
124 self[
'seed'].integer()
125 self[
'chatter'].integer()
128 self[
'profile'].boolean()
131 if self._read_ahead():
132 self[
'outfile'].filename()
135 self._log_parameters(gammalib.TERSE)
145 Generate summary string for observation
149 obs : `~gammalib.GCTAObservation`
158 if obs.classname() ==
'GCTAOnOffObservation':
159 emin = obs.on_spec().ebounds().emin().TeV()
160 emax = obs.on_spec().ebounds().emax().TeV()
163 emin = obs.events().ebounds().emin().TeV()
164 emax = obs.events().ebounds().emax().TeV()
165 binned = (obs.events().classname() ==
'GCTAEventCube')
170 events = obs.nobserved()
174 text =
'%d events, %.3f-%.3f TeV, %s' % (events, emin, emax, mode)
176 text =
'%.3f-%.3f TeV, %s' % (emin, emax, mode)
183 Compute the pull for a single trial
188 Random number generator seed
193 Dictionary of results
196 self._log_header2(gammalib.NORMAL,
'Trial %d' %
197 (seed-self[
'seed'].integer()+1))
201 nbins = self[
'enumbins'].integer()
202 onsrc = self[
'onsrc'].string()
203 edisp = self[
'edisp'].boolean()
204 statistic = self[
'statistic'].string()
213 if gammalib.toupper(onsrc) !=
'NONE':
214 onrad = self[
'onrad'].real()
215 emin = self[
'emin'].real()
216 emax = self[
'emax'].real()
227 emin = self[
'emin'].real()
228 emax = self[
'emax'].real()
229 binsz = self[
'binsz'].real()
230 npix = self[
'npix'].integer()
231 proj = self[
'proj'].string()
232 coordsys = self[
'coordsys'].string()
235 obs = obsutils.sim(self.obs(),
236 emin=emin, emax=emax, nbins=nbins,
237 onsrc=onsrc, onrad=onrad,
238 addbounds=
True, seed=seed,
239 binsz=binsz, npix=npix, proj=proj, coord=coordsys,
240 edisp=edisp, nthreads=1, log=
False,
241 debug=self._logDebug(), chatter=self[
'chatter'].integer())
246 nevents += run.nobserved()
249 self._log_header3(gammalib.NORMAL,
'Simulation')
250 for run
in self.obs():
251 self._log_value(gammalib.NORMAL,
'Input observation %s' % run.id(),
254 self._log_value(gammalib.NORMAL,
'Output observation %s' % run.id(),
256 self._log_value(gammalib.NORMAL,
'Number of simulated events', nevents)
259 if self[
'profile'].boolean():
260 models = self.obs().
models()
262 like = ctools.cterror(obs)
263 like[
'srcname'] = model.name()
264 like[
'edisp'] = edisp
265 like[
'statistic'] = statistic
267 like[
'debug'] = self._logDebug()
268 like[
'chatter'] = self[
'chatter'].integer()
271 like = ctools.ctlike(obs)
272 like[
'edisp'] = edisp
273 like[
'statistic'] = statistic
275 like[
'debug'] = self._logDebug()
276 like[
'chatter'] = self[
'chatter'].integer()
280 logL = like.opt().value()
281 npred = like.obs().npred()
282 models = like.obs().
models()
285 self._log_header3(gammalib.NORMAL,
'Pulls')
296 colnames = [
'LogL',
'Sim_Events',
'Npred_Events']
297 values = {
'LogL': logL,
'Sim_Events': nevents,
'Npred_Events': npred}
298 for i
in range(models.size()):
300 for k
in range(model.size()):
307 name = model.name() +
'_' + par.name()
312 col_par_error = name+
'_error'
313 col_par_pull = name+
'_pull'
316 colnames.append(col_par)
317 colnames.append(col_par_error)
318 colnames.append(col_par_pull)
323 fitted_value = par.value()
324 real_value = self.obs().
models()[i][k].value()
327 pull = (fitted_value - real_value) / error
332 values[col_par] = fitted_value
333 values[col_par_error] = error
334 values[col_par_pull] = pull
337 value =
'%.4f (%e +/- %e)' % (pull, fitted_value, error)
338 self._log_value(gammalib.NORMAL, name, value)
341 result = {
'colnames': colnames,
'values': values}
348 Create FITS file from results
352 results : list of dict
353 List of result dictionaries
357 for colname
in results[0][
'colnames']:
358 if colname !=
'LogL' and colname !=
'Sim_Events' and \
359 colname !=
'Npred_Events':
360 headers.append(colname)
364 logl = gammalib.GFitsTableDoubleCol(
'LOGL', nrows)
365 nevents = gammalib.GFitsTableDoubleCol(
'NEVENTS', nrows)
366 npred = gammalib.GFitsTableDoubleCol(
'NPRED', nrows)
368 nevents.unit(
'counts')
371 for header
in headers:
372 name = gammalib.toupper(header)
373 column = gammalib.GFitsTableDoubleCol(name, nrows)
375 columns.append(column)
378 for i, result
in enumerate(results):
379 logl[i] = result[
'values'][
'LogL']
380 nevents[i] = result[
'values'][
'Sim_Events']
381 npred[i] = result[
'values'][
'Npred_Events']
382 for k, column
in enumerate(columns):
383 column[i] = result[
'values'][headers[k]]
386 table = gammalib.GFitsBinTable(nrows)
387 table.extname(
'PULL_DISTRIBUTION')
390 table.card(
'INSTRUME',
'CTA',
'Name of Instrument')
391 table.card(
'TELESCOP',
'CTA',
'Name of Telescope')
397 if gammalib.toupper(self[
'onsrc'].string()) !=
'NONE':
398 onrad = self[
'onrad'].real()
401 if self[
'enumbins'].integer() > 0:
402 npix = self[
'npix'].integer()
403 binsz = self[
'binsz'].real()
404 coordsys = self[
'coordsys'].string()
405 proj = self[
'proj'].string()
413 table.card(
'NPULLS', self[
'ntrials'].integer(),
'Number of pulls')
414 table.card(
'SEED', self[
'seed'].integer(),
'Seed value for pulls')
415 table.card(
'ONSRC', self[
'onsrc'].string(),
'Name of On surce for On/Off analysis')
416 table.card(
'ONRAD', onrad,
'[deg] Radius of On region')
417 table.card(
'ENUMBINS', self[
'enumbins'].integer(),
'Number of energy bins')
418 table.card(
'NPIX', npix,
'Number of pixels for binned analysis')
419 table.card(
'BINSZ', binsz,
'Pixel size for binned analysis')
420 table.card(
'COORDSYS', coordsys,
'Coordinate system for binned analysis')
421 table.card(
'PROJ', proj,
'Projection for binned analysis')
422 table.card(
'STAT', self[
'statistic'].string(),
'Optimization statistic')
423 table.card(
'EDISP', self[
'edisp'].boolean(),
'Use energy dispersion?')
424 table.card(
'PROFILE', self[
'profile'].boolean(),
'Use likelihood profile method for errors?')
428 table.append(nevents)
430 for column
in columns:
434 self.
_fits = gammalib.GFits()
435 self._fits.append(table)
450 self._log_observations(gammalib.NORMAL, self.obs(),
'Input observation')
453 self._log_header1(gammalib.TERSE,
'Generate pull distribution')
456 ntrials = self[
'ntrials'].integer()
459 seed = self[
'seed'].integer()
466 args = [(self,
'_trial', i + seed)
for i
in range(ntrials)]
467 poolresults = mputils.process(self.
_nthreads, mputils.mpfunc, args)
470 for i
in range(ntrials):
475 results.append(poolresults[i][0])
476 self._log_string(gammalib.TERSE, poolresults[i][1][
'log'],
False)
482 result = self.
_trial(i + seed)
485 results.append(result)
499 models : `~gammalib.GModels`
513 self._log_header1(gammalib.TERSE,
'Save pull distribution')
516 if self.
_fits !=
None:
519 outfile = self[
'outfile'].filename()
522 self._log_value(gammalib.NORMAL,
'Pull distribution file', outfile.url())
525 self._fits.saveto(outfile, self[
'clobber'].boolean())
532 Return pull distribution FITS file
535 FITS file containing pull distribution
544 if __name__ ==
'__main__':