Commit 0eeff30e13dc9647d62bcb69d3e84fdca8b936fe

Authored by Jürgen Knödlseder
2 parents 70c82fc3 ee25e9a8

Merge branch 'devel' into pull-request-1982-add-phase-info-ctphase

# Conflicts:
#	src/Makefile.am
Showing 73 changed files with 2785 additions and 1366 deletions
.gitignore
... ... @@ -71,6 +71,8 @@ src/ctcubemask/ctcubemask
71 71 src/ctbutterfly/ctbutterfly
72 72 src/ctulimit/ctulimit
73 73 src/cterror/cterror
  74 +src/ctprob/ctprob
  75 +src/ctphase/ctphase
74 76 test/pfiles/
75 77 test/caldb/
76 78 test/prod3
... ...
... ... @@ -2,6 +2,7 @@ Johan Bregeon (johan.bregeon@lupm.in2p3.fr)
2 2 Rolf Buehler (rolf.buehler@desy.de)
3 3 Jean-Baptiste Cayrou (cayrou@etud.insa-toulouse.fr)
4 4 Christoph Deil (Christoph.Deil@mpi-hd.mpg.de)
  5 +Leonardo Di Venere (leonardo.divenere@ba.infn.it)
5 6 Florent Forest (florent.forest@isae.fr)
6 7 Lucie Gerard (lgerard@wgs18.zeuthen.desy.de)
7 8 Maria Haupt (maria.haupt@desy.de)
... ...
ChangeLog
1   -2017-04-05
  1 +2017-04-11
2 2  
3 3 * Version 1.3.0 released
4 4 ========================
5 5  
  6 + Add ctprob tool (#1991)
  7 + ctlike stores covariance matrix in either CSV or FITS format (#1863)
  8 + Use correct ROOT histograms in csroot2caldb
  9 + Implement regression scheme in cssens and remove num_avg parameter (#1989)
  10 + Implement Gaussian error propagation in ctbutterfly (#1862)
6 11 Copy cscripts into bin directory instead of creating a symbolic links (#1987)
7 12 If code originates from Git, always compile the Python bindings (#1985)
8 13 Raise exception instead of exiting with return code in Python tests (#1983)
... ...
1 1 New Features and Important Changes in ctools 1.3.0.dev1
2 2  
3   -5 April 2017
  3 +11 April 2017
4 4  
5 5  
6 6 Introduction
... ... @@ -57,7 +57,10 @@ None
57 57  
58 58 ctlike - Maximum likelihood fitting
59 59 -----------------------------------
60   -None
  60 +The tool now stores the covariance matrix in either FITS or CSV format,
  61 +depending on the file type specified in the file name. For file names
  62 +terminating with ".fits" or ".fit" a FITS file will be written, otherwise
  63 +a CSV file will be written (#1863).
61 64  
62 65  
63 66 cttsmap - Generation of Test Statistic map
... ... @@ -113,7 +116,11 @@ None
113 116  
114 117 ctbutterfly - Generate butterfly diagrams
115 118 -----------------------------------------
116   -None
  119 +The tool now uses Gaussian error propagation as the standard method for the
  120 +computation of the butterfly diagram. The envelope method that existed before
  121 +is still available for power law spectral models as an option. The "method"
  122 +parameter has been added to allow the selection of the computation method
  123 +(#1862).
117 124  
118 125  
119 126 ctulimit - Compute upper limit
... ... @@ -126,6 +133,15 @@ cterror - Likelihood profile error computation
126 133 None
127 134  
128 135  
  136 +ctprob - Event probability computation
  137 +--------------------------------------
  138 +The ctprob tool has been added that computates for each event the probability
  139 +that the event originates from a given model component. The tool takes on input
  140 +either an event list or an observation definition XML file. It appends to each
  141 +event list a column for each model component that will contain the probability
  142 +that the event originates from that component (#1991).
  143 +
  144 +
129 145 cscripts
130 146 --------
131 147 The csebins script has been added that generates an energy boundaries
... ... @@ -133,6 +149,15 @@ extension that can be used for a stacked analysis. The energy boundaries
133 149 are set as function of the variation in the effective area and background
134 150 rates of the Instrument Response Function (#1976).
135 151  
  152 +A regression scheme now replaces the averaging scheme in cssens as this
  153 +allows more accurately the prediction of the flux value at the threshold
  154 +Test Statistic. The num_avg parameter has been removed (#1989).
  155 +
  156 +The names of some ROOT histograms has been changed in the Monte Carlo data
  157 +and the "EffectiveAreaEtrue_offaxis" needed to be changed to
  158 +"EffectiveAreaEtrueNoTheta2cut_offaxis" and "EffectiveAreaEtrue" to
  159 +"EffectiveAreaEtrueNoTheta2cut" in csroot2caldb.
  160 +
136 161  
137 162 Examples
138 163 --------
... ...
cscripts/csroot2caldb.py
... ... @@ -536,7 +536,8 @@ class csroot2caldb(ctools.cscript):
536 536 Translate ROOT to CALDB effective area extension
537 537  
538 538 The following ROOT histograms are used:
539   - - EffectiveAreaEtrue_offaxis -> EFFAREA
  539 + - EffectiveAreaEtrueNoTheta2cut_offaxis -> EFFAREA
  540 + - EffectiveAreaEtrueNoTheta2cut (for normalization)
540 541  
541 542 Parameters
542 543 ----------
... ... @@ -551,13 +552,13 @@ class csroot2caldb(ctools.cscript):
551 552 self._log_header1(gammalib.TERSE, 'Generate effective area extension')
552 553  
553 554 # Get relevant ROOT histograms
554   - etrue = tfile.Get('EffectiveAreaEtrue_offaxis')
  555 + etrue = tfile.Get('EffectiveAreaEtrueNoTheta2cut_offaxis')
555 556  
556 557 # If requested then normalize the 2D histogram on the on-axis 1D
557 558 # histogram. This assures that the 2D histogram has the same on-axis
558 559 # effective area dependence as the 1D histogram.
559 560 if self['norm1d'].boolean():
560   - etrue_1D = tfile.Get('EffectiveAreaEtrue')
  561 + etrue_1D = tfile.Get('EffectiveAreaEtrueNoTheta2cut')
561 562 self._renorm_onaxis(etrue, etrue_1D)
562 563  
563 564 # If requested then rebin the effective area Etrue histogram. This
... ...
cscripts/cssens.par
... ... @@ -20,7 +20,7 @@ inobs, f, h, NONE,,, "Input event list, counts cube, or observation definition
20 20 inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model definition XML file"
21 21 srcname, s, a, Crab,,, "Source name"
22 22 caldb, s, a, prod2,,, "Calibration database"
23   -irf, s, a, South_0.5h,,, "Instrument response function"
  23 +irf, s, a, South_50h,,, "Instrument response function"
24 24 edisp, b, h, no,,, "Apply energy dispersion?"
25 25 deadc, r, h, 0.98,0,1, "Deadtime correction factor"
26 26 outfile, f, h, sensitivity.dat,,, "Output sensitivity ASCII file"
... ... @@ -31,16 +31,15 @@ outfile, f, h, sensitivity.dat,,, "Output sensitivity ASCII file"
31 31 offset, r, h, 0.0,,, "Source offset angle (deg)"
32 32 duration, r, a, 180000.0,,, "Effective exposure time (s)"
33 33 rad, r, a, 5.0,,, "Radius of ROI (deg)"
34   -emin, r, a, 0.020,,, "Lower energy limit (TeV)"
35   -emax, r, a, 200.0,,, "Upper energy limit (TeV)"
36   -bins, i, a, 21,,, "Number of energy bins for differential sensitivity computation"
  34 +emin, r, a, 0.03163,,, "Lower energy limit (TeV)"
  35 +emax, r, a, 125.8925,,, "Upper energy limit (TeV)"
  36 +bins, i, a, 18,,, "Number of energy bins for differential sensitivity computation"
37 37 enumbins, i, h, 0,,, "Number of energy bins for binned analysis (0=unbinned)"
38 38 npix, i, h, 200,,, "Number of pixels for binned analysis"
39 39 binsz, r, h, 0.05,,, "Pixel size for binned analysis (deg/pixel)"
40 40 type, s, h, Differential,Differential|Integral,, "Sensitivity type"
41 41 sigma, r, h, 5.0,,, "Significance threshold (Gaussian sigma)"
42 42 max_iter, i, h, 50,,, "Maximum number of iterations"
43   -num_avg, i, h, 3,,, "Number of iterations for sliding average"
44 43  
45 44 #
46 45 # Standard parameters
... ... @@ -49,6 +48,6 @@ chatter, i, h, 2,0,4, "Chattiness of output"
49 48 clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
50 49 debug, b, h, no,,, "Debugging mode activated"
51 50 mode, s, h, ql,,, "Mode of automatic parameters"
52   -logfile, f, h, cspull.log,,, "Log filename"
  51 +logfile, f, h, cssens.log,,, "Log filename"
53 52  
54 53  
... ...
cscripts/cssens.py
1 1 #! /usr/bin/env python
2 2 # ==========================================================================
3   -# Computes the array sensitivity using a test source
  3 +# Computes the array sensitivity using the Test Statistic for a test source
4 4 #
5   -# Copyright (C) 2011-2016 Juergen Knoedlseder
  5 +# Copyright (C) 2011-2017 Juergen Knoedlseder
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -40,7 +40,7 @@ class cssens(ctools.cscript):
40 40 and the flux level is determined that leads to a particular significance.
41 41  
42 42 The significance is determined using the Test Statistic, defined as twice
43   - the likelihood difference between fitting with and without the test source.
  43 + the likelihood difference between fitting with and without the test source.
44 44 """
45 45  
46 46 # Constructor
... ... @@ -50,31 +50,20 @@ class cssens(ctools.cscript):
50 50 """
51 51 # Set name
52 52 self._name = 'cssens'
53   - self._version = '1.2.0'
  53 + self._version = '1.3.0'
54 54  
55 55 # Initialise class members
56   - self._obs = gammalib.GObservations()
57 56 self._ebounds = gammalib.GEbounds()
58 57 self._obs_ebounds = []
59 58 self._srcname = ''
60   - self._outfile = gammalib.GFilename()
61 59 self._ra = None
62 60 self._dec = None
63   - self._edisp = False
64   - self._emin = 0.020
65   - self._emax = 200.0
66   - self._bins = 21
67   - self._enumbins = 0
68   - self._npix = 200
69   - self._binsz = 0.05
70   - self._type = 'Differential'
71   - self._ts_thres = 25.0
72   - self._max_iter = 50
73   - self._num_avg = 3
74 61 self._log_clients = False
75   -
76   - # Initialise application by calling the appropriate base class
77   - # constructor
  62 +
  63 + # Initialise observation container from constructor arguments
  64 + self._obs, argv = self._set_input_obs(argv)
  65 +
  66 + # Initialise application by calling the appropriate class constructor
78 67 self._init_cscript(argv)
79 68  
80 69 # Return
... ... @@ -87,8 +76,8 @@ class cssens(ctools.cscript):
87 76 Get user parameters from parfile
88 77 """
89 78 # Set observation if not done before
90   - if self._obs == None or self._obs.size() == 0:
91   - self._obs = self._set_obs()
  79 + if self._obs.size() == 0:
  80 + self._obs = self._set_obs(self['emin'].real(), self['emax'].real())
92 81  
93 82 # Set models if we have none
94 83 if self._obs.models().size() == 0:
... ... @@ -98,31 +87,28 @@ class cssens(ctools.cscript):
98 87 self._srcname = self['srcname'].string()
99 88  
100 89 # Read further parameters
101   - self._outfile = self['outfile'].filename()
102   - self._emin = self['emin'].real()
103   - self._emax = self['emax'].real()
104   - self._bins = self['bins'].integer()
105   -
106   - # Read parameters for binned if requested
107   - self._enumbins = self['enumbins'].integer()
108   - if not self._enumbins == 0:
109   - self._npix = self['npix'].integer()
110   - self._binsz = self['binsz'].real()
111   -
112   - # Read remaining parameters
113   - self._edisp = self['edisp'].boolean()
114   - self._ts_thres = self['sigma'].real() * self['sigma'].real()
115   - self._max_iter = self['max_iter'].integer()
116   - self._num_avg = self['num_avg'].integer()
117   - self._type = self['type'].string()
118   -
119   - # Query remaining parameters
  90 + emin = self['emin'].real()
  91 + emax = self['emax'].real()
  92 + bins = self['bins'].integer()
  93 +
  94 + # Query parameters for binned if requested
  95 + enumbins = self['enumbins'].integer()
  96 + if not enumbins == 0:
  97 + self['npix'].integer()
  98 + self['binsz'].real()
  99 +
  100 + # Query input parameters
  101 + self['sigma'].real()
  102 + self['max_iter'].integer()
  103 + self['type'].string()
  104 + self['outfile'].filename()
  105 + self['edisp'].boolean()
120 106 self['debug'].boolean()
121 107  
122 108 # Derive some parameters
123   - self._ebounds = gammalib.GEbounds(self._bins,
124   - gammalib.GEnergy(self._emin, 'TeV'),
125   - gammalib.GEnergy(self._emax, 'TeV'))
  109 + self._ebounds = gammalib.GEbounds(bins,
  110 + gammalib.GEnergy(emin, 'TeV'),
  111 + gammalib.GEnergy(emax, 'TeV'))
126 112  
127 113 # Write input parameters into logger
128 114 self._log_parameters(gammalib.TERSE)
... ... @@ -130,20 +116,20 @@ class cssens(ctools.cscript):
130 116 # Return
131 117 return
132 118  
133   - def _set_obs(self, lpnt=0.0, bpnt=0.0, emin=0.1, emax=100.0):
  119 + def _set_obs(self, emin, emax, lpnt=0.0, bpnt=0.0):
134 120 """
135 121 Set an observation container
136 122  
137 123 Parameters
138 124 ----------
  125 + emin : float
  126 + Minimum energy (TeV)
  127 + emax : float
  128 + Maximum energy (TeV)
139 129 lpnt : float, optional
140 130 Galactic longitude of pointing (deg)
141 131 bpnt : float, optional
142 132 Galactic latitude of pointing (deg)
143   - emin : float, optional
144   - Minimum energy (TeV)
145   - emax : float, optional
146   - Maximum energy (TeV)
147 133  
148 134 Returns
149 135 -------
... ... @@ -205,23 +191,23 @@ class cssens(ctools.cscript):
205 191  
206 192 # Get energy boundaries of the observation
207 193 obs_ebounds = self._obs_ebounds[i]
208   -
  194 +
209 195 # Get minimum and maximum energy of the observation
210 196 obs_emin = obs_ebounds.emin()
211 197 obs_emax = obs_ebounds.emax()
212   -
  198 +
213 199 # If [emin,emax] is fully contained in the observation energy range
214 200 # the use [emin,emax] as energy boundaries
215 201 if obs_emin <= emin and obs_emax >= emax:
216 202 ebounds = gammalib.GEbounds(emin, emax)
217   -
  203 +
218 204 # ... otherwise, if [emin,emax] is completely outside the
219 205 # observation energy range then set the energy boundaries to the
220 206 # zero-width interval [0,0]
221 207 elif emax < obs_emin or emin > obs_emax:
222 208 e0 = gammalib.GEnergy(0.0, 'TeV')
223 209 ebounds = gammalib.GEbounds(e0, e0)
224   -
  210 +
225 211 # ... otherwise, if [emin,emax] overlaps partially with the
226 212 # observation energy range then set the energy boundaries to the
227 213 # overlapping part
... ... @@ -229,10 +215,10 @@ class cssens(ctools.cscript):
229 215 # Set overlapping energy range
230 216 set_emin = max(emin, obs_emin)
231 217 set_emax = min(emax, obs_emax)
232   -
  218 +
233 219 # Set energy boundaries
234 220 ebounds = gammalib.GEbounds(set_emin, set_emax)
235   -
  221 +
236 222 # Set the energy boundaries as the boundaries of the observation
237 223 obs.events().ebounds(ebounds)
238 224  
... ... @@ -286,13 +272,27 @@ class cssens(ctools.cscript):
286 272 # Set TeV->erg conversion factor
287 273 tev2erg = 1.6021764
288 274  
  275 + # Set parameters
  276 + ts_thres = self['sigma'].real() * self['sigma'].real()
  277 + max_iter = self['max_iter'].integer()
  278 + enumbins = self['enumbins'].integer()
  279 + if not enumbins == 0:
  280 + npix = self['npix'].integer()
  281 + binsz = self['binsz'].real()
  282 + else:
  283 + npix = 200
  284 + binsz = 0.05
  285 +
  286 + # Set flux ratio precision required for convergence to 5%
  287 + ratio_precision = 0.05
  288 +
289 289 # Set energy boundaries
290 290 self._set_obs_ebounds(emin, emax)
291 291  
292   - # Determine energy boundaries from first observation in the container
293   - loge = math.log10(math.sqrt(emin.TeV()*emax.TeV()))
294   - e_mean = math.pow(10.0, loge)
295   - erg_mean = e_mean * tev2erg
  292 + # Determine mean energy for energy boundary
  293 + e_mean = math.sqrt(emin.TeV()*emax.TeV())
  294 + loge = math.log10(e_mean)
  295 + erg_mean = e_mean * tev2erg
296 296  
297 297 # Compute Crab unit. This is the factor with which the Prefactor needs
298 298 # to be multiplied to get 1 Crab.
... ... @@ -300,20 +300,27 @@ class cssens(ctools.cscript):
300 300 src_flux = test_model[self._srcname].spectral().flux(emin, emax)
301 301 crab_unit = crab_flux/src_flux
302 302  
303   - # Write header and some introductory information into logger
  303 + # Initialise regression coefficient
  304 + regcoeff = 0.0
  305 +
  306 + # Write header for energy bin
  307 + self._log_string(gammalib.TERSE, '')
304 308 self._log_header2(gammalib.TERSE, 'Energies: '+str(emin)+' - '+str(emax))
  309 +
  310 + # Write initial parameters
  311 + self._log_header3(gammalib.TERSE, 'Initial parameters')
305 312 self._log_value(gammalib.TERSE, 'Crab flux', str(crab_flux)+' ph/cm2/s')
306   - self._log_value(gammalib.TERSE, 'Source model flux', str(src_flux)+
307   - ' ph/cm2/s')
  313 + self._log_value(gammalib.TERSE, 'Source model flux', str(src_flux)+' ph/cm2/s')
308 314 self._log_value(gammalib.TERSE, 'Crab unit factor', crab_unit)
309 315  
310 316 # Initialise loop
311   - crab_flux_value = []
312   - photon_flux_value = []
313   - energy_flux_value = []
314   - sensitivity_value = []
315   - iterations = 0
316   - test_crab_flux = 0.1 # Initial test flux in Crab units (100 mCrab)
  317 + results = []
  318 + iterations = 0
  319 + test_crab_flux = 0.1 # Initial test flux in Crab units (100 mCrab)
  320 +
  321 + # Write header for iterations for terse chatter level
  322 + if self._logTerse():
  323 + self._log_header3(gammalib.TERSE, 'Iterations')
317 324  
318 325 # Loop until we break
319 326 while True:
... ... @@ -335,11 +342,11 @@ class cssens(ctools.cscript):
335 342  
336 343 # Simulate events for the models. "sim" holds an observation
337 344 # container with observations containing the simulated events.
338   - sim = obsutils.sim(self._obs, nbins=self._enumbins, seed=iterations,
339   - binsz=self._binsz, npix=self._npix,
  345 + sim = obsutils.sim(self._obs, nbins=enumbins, seed=iterations,
  346 + binsz=binsz, npix=npix,
340 347 log=self._log_clients,
341 348 debug=self['debug'].boolean(),
342   - edisp=self._edisp)
  349 + edisp=self['edisp'].boolean())
343 350  
344 351 # Determine number of events in simulation by summing the events
345 352 # over all observations in the observation container
... ... @@ -354,7 +361,7 @@ class cssens(ctools.cscript):
354 361 # Fit test source to the simulated events in the observation
355 362 # container
356 363 fit = ctools.ctlike(sim)
357   - fit['edisp'] = edisp=self._edisp
  364 + fit['edisp'] = self['edisp'].boolean()
358 365 fit['debug'] = self['debug'].boolean()
359 366 fit['chatter'] = self['chatter'].integer()
360 367 fit.run()
... ... @@ -383,29 +390,24 @@ class cssens(ctools.cscript):
383 390 # Assess quality based on a comparison between Npred and Nevents
384 391 quality = npred - nevents
385 392  
386   - # Write test source fit results into logger
387   - self._log_header3(gammalib.EXPLICIT, 'Test source model fit')
388   - self._log_value(gammalib.EXPLICIT, 'Test statistics', ts)
389   - self._log_value(gammalib.EXPLICIT, 'log likelihood', logL)
390   - self._log_value(gammalib.EXPLICIT, 'Number of predicted events', quality)
391   - self._log_value(gammalib.EXPLICIT, 'Fit quality', npred)
392   - for model in models:
393   - self._log_value(gammalib.EXPLICIT, 'Model', model.name())
394   - for par in model:
395   - self._log_string(gammalib.EXPLICIT, str(par))
396   -
397   - # If TS was non-positive then increase the test flux and start
398   - # over
  393 + # Write fit results into logger
  394 + name = 'Iteration %d' % iterations
  395 + value = ('TS=%10.4f Sim=%9.4f mCrab Fit=%9.4f mCrab '
  396 + 'Sens=%e erg/cm2/s' %
  397 + (ts, test_crab_flux*1000.0, crab_flux*1000.0, sensitivity))
  398 + self._log_value(gammalib.TERSE, name, value)
  399 +
  400 + # If TS was non-positive then increase the test flux and start over
399 401 if ts <= 0.0:
400 402  
401 403 # If the number of iterations was exceeded then stop
402   - if (iterations >= self._max_iter):
  404 + if (iterations >= max_iter):
403 405 self._log_string(gammalib.TERSE,
404   - ' Test ended after %d iterations.' % self._max_iter)
  406 + ' Test ended after %d iterations.' % max_iter)
405 407 break
406 408  
407   - # Increase test flux by a factor of 2
408   - test_crab_flux = test_crab_flux * 2.0
  409 + # Increase test flux
  410 + test_crab_flux *= 3.0
409 411  
410 412 # Signal start we start over
411 413 self._log_string(gammalib.EXPLICIT,
... ... @@ -414,95 +416,64 @@ class cssens(ctools.cscript):
414 416 # ... and start over
415 417 continue
416 418  
417   - # Compute flux correction factor based on average TS. We
418   - # assume here that the significance is proportional to the source
419   - # flux, and that the significance scales as the square root of
420   - # the Test Statistic
421   - correct = math.sqrt(self._ts_thres/ts)
  419 + # Append result entry to result list
  420 + result = {'ts': ts, 'crab_flux': crab_flux,
  421 + 'photon_flux': photon_flux,
  422 + 'energy_flux': energy_flux}
  423 + results.append(result)
  424 +
  425 + # Predict Crab flux at threshold TS using a linear regression of
  426 + # the log(TS) and log(crab_flux) values that have so far been
  427 + # computed. If not enough results are available than use a simple
  428 + # TS scaling relation.
  429 + if len(results) > 1:
  430 + pred_crab_flux, regcoeff = self._predict_flux(results, ts_thres)
  431 + correct = pred_crab_flux / crab_flux
  432 + else:
  433 + correct = math.sqrt(ts_thres/ts)
422 434  
423 435 # Compute extrapolated fluxes based on the flux correction factor
424 436 crab_flux = correct * crab_flux
425 437 photon_flux = correct * photon_flux
426 438 energy_flux = correct * energy_flux
427 439 sensitivity = correct * sensitivity
428   - crab_flux_value.append(crab_flux)
429   - photon_flux_value.append(photon_flux)
430   - energy_flux_value.append(energy_flux)
431   - sensitivity_value.append(sensitivity)
432   -
433   - # Write fit results
434   - if self._logExplicit():
435   - self._log_value(gammalib.EXPLICIT, 'Photon flux',
436   - str(photon_flux)+' ph/cm2/s')
437   - self._log_value(gammalib.EXPLICIT, 'Energy flux',
438   - str(energy_flux)+' erg/cm2/s')
439   - self._log_value(gammalib.EXPLICIT, 'Crab flux',
440   - str(crab_flux*1000.0)+' mCrab')
441   - self._log_value(gammalib.EXPLICIT, 'Differential sensitivity',
442   - str(sensitivity)+' erg/cm2/s')
443   - for model in models:
444   - self._log_value(gammalib.EXPLICIT, 'Model', model.name())
445   - for par in model:
446   - self._log_string(gammalib.EXPLICIT, str(par))
447   - elif self._logTerse():
448   - name = 'Iteration %d' % iterations
449   - value = ('TS=%.4f corr=%e %e ph/cm2/s = %e erg/cm2/s = %.2f '
450   - 'mCrab = %e erg/cm2/s' % (ts, correct, photon_flux,
451   - energy_flux, crab_flux*1000.0, sensitivity))
452   - self._log_value(gammalib.TERSE, name, value)
453   -
454   - # Compute sliding average of extrapolated fitted prefactor,
455   - # photon and energy flux. This damps out fluctuations and
456   - # improves convergence.
457   - crab_flux = 0.0
458   - photon_flux = 0.0
459   - energy_flux = 0.0
460   - sensitivity = 0.0
461   - num = 0.0
462   - for k in range(self._num_avg):
463   - inx = len(crab_flux_value) - k - 1
464   - if inx >= 0:
465   - crab_flux += crab_flux_value[inx]
466   - photon_flux += photon_flux_value[inx]
467   - energy_flux += energy_flux_value[inx]
468   - sensitivity += sensitivity_value[inx]
469   - num += 1.0
470   - crab_flux /= num
471   - photon_flux /= num
472   - energy_flux /= num
473   - sensitivity /= num
474   -
475   - # Compare average flux to last average
476   - if iterations > self._num_avg:
  440 +
  441 + # If we have at least 3 results then check if the flux determination
  442 + # at the TS threshold has converged
  443 + if len(results) > 3:
477 444 if test_crab_flux > 0:
  445 +
  446 + # Compute fractional change in the Crab flux between two
  447 + # iterations
478 448 ratio = crab_flux/test_crab_flux
479 449  
480   - # We have 2 convergence criteria:
481   - # 1. The average flux does not change
482   - # 2. The flux correction factor is small
483   - if ratio >= 0.99 and ratio <= 1.01 and \
484   - correct >= 0.9 and correct <= 1.1:
485   - if self._logTerse():
486   - self._log(' Converged ('+str(ratio)+')\n')
  450 + # If fractional change is smaller than the required position
  451 + # the iterations are stopped
  452 + if ratio > 1.0-ratio_precision and \
  453 + ratio < 1.0+ratio_precision:
  454 + value = ('TS=%10.4f Sim=%9.4f mCrab '
  455 + ' Sens=%e erg/cm2/s' %
  456 + (ts, crab_flux*1000.0, sensitivity))
  457 + self._log_value(gammalib.TERSE, 'Converged result', value)
  458 + self._log_value(gammalib.TERSE, 'Converged flux ratio', ratio)
  459 + self._log_value(gammalib.TERSE, 'Regression coefficient',
  460 + regcoeff)
487 461 break
488 462 else:
489   - if self._logTerse():
490   - self._log(' Flux is zero.\n')
  463 + self._log_value(gammalib.TERSE, 'Not converged', 'Flux is zero')
491 464 break
492 465  
493   - # Use average for next iteration
  466 + # Set test flux for next iteration
494 467 test_crab_flux = crab_flux
495 468  
496 469 # Exit loop if number of trials exhausted
497   - if (iterations >= self._max_iter):
498   - if self._logTerse():
499   - self._log(' Test ended after '+str(self._max_iter)+
500   - ' iterations.\n')
  470 + if (iterations >= max_iter):
  471 + self._log_string(gammalib.TERSE,
  472 + ' Test ended after %d iterations.' % max_iter)
501 473 break
502 474  
503 475 # Write fit results into logger
504 476 self._log_header3(gammalib.TERSE, 'Fit results')
505   - self._log_value(gammalib.TERSE, 'Test statistics', ts)
506 477 self._log_value(gammalib.TERSE, 'Photon flux',
507 478 str(photon_flux)+' ph/cm2/s')
508 479 self._log_value(gammalib.TERSE, 'Energy flux',
... ... @@ -523,16 +494,84 @@ class cssens(ctools.cscript):
523 494 # Restore energy boundaries of observation container
524 495 for i, obs in enumerate(self._obs):
525 496 obs.events().ebounds(self._obs_ebounds[i])
526   -
  497 +
527 498 # Store result
528 499 result = {'loge': loge, 'emin': emin.TeV(), 'emax': emax.TeV(), \
529 500 'crab_flux': crab_flux, 'photon_flux': photon_flux, \
530 501 'energy_flux': energy_flux, \
531   - 'sensitivity': sensitivity}
  502 + 'sensitivity': sensitivity, 'regcoeff': regcoeff, \
  503 + 'nevents': nevents, 'npred': npred}
532 504  
533 505 # Return result
534 506 return result
535 507  
  508 + def _predict_flux(self, results, ts):
  509 + """
  510 + Predict Crab flux for a given TS value
  511 +
  512 + The Crab flux at a given Test Statistic value is predicted by doing a
  513 + linear regression of the log(TS) and log(crab_flux) values in a results
  514 + list.
  515 +
  516 + See https://en.wikipedia.org/wiki/Simple_linear_regression
  517 +
  518 + Parameters
  519 + ----------
  520 + results : list of dict
  521 + List of results
  522 + ts : float
  523 + Test Statistic value
  524 +
  525 + Returns
  526 + -------
  527 + crab_flux_prediction, regcoeff : tuple of float
  528 + Predicted Crab flux and regression coefficient
  529 + """
  530 + # Compute means and regression coefficient
  531 + mean_x = 0.0
  532 + mean_y = 0.0
  533 + mean_xy = 0.0
  534 + mean_xx = 0.0
  535 + mean_yy = 0.0
  536 + for result in results:
  537 + x = math.log(float(result['ts']))
  538 + y = math.log(float(result['crab_flux']))
  539 + mean_x += x
  540 + mean_y += y
  541 + mean_xy += x * y
  542 + mean_xx += x * x
  543 + mean_yy += y * y
  544 + norm = 1.0 / float(len(results))
  545 + mean_x *= norm
  546 + mean_y *= norm
  547 + mean_xy *= norm
  548 + mean_xx *= norm
  549 + mean_yy *= norm
  550 + rxy = (mean_xy - mean_x * mean_y) / \
  551 + math.sqrt((mean_xx - mean_x*mean_x) *
  552 + (mean_yy - mean_y*mean_y))
  553 + regcoeff = rxy*rxy
  554 +
  555 + # Compute regression line slope
  556 + beta_nom = 0.0
  557 + beta_denom = 0.0
  558 + for result in results:
  559 + x = math.log(float(result['ts']))
  560 + y = math.log(float(result['crab_flux']))
  561 + beta_nom += (x - mean_x) * (y - mean_y)
  562 + beta_denom += (x - mean_x) * (x - mean_x)
  563 + beta = beta_nom / beta_denom
  564 +
  565 + # Compute regression line offset
  566 + alpha = mean_y - beta * mean_x
  567 +
  568 + # Predict Crab flux at TS threshold
  569 + log_ts_thres = math.log(ts)
  570 + crab_flux_prediction = math.exp(alpha + beta * log_ts_thres)
  571 +
  572 + # Return
  573 + return (crab_flux_prediction, regcoeff)
  574 +
536 575  
537 576 # Public methods
538 577 def run(self):
... ... @@ -545,15 +584,16 @@ class cssens(ctools.cscript):
545 584  
546 585 # Get parameters
547 586 self._get_parameters()
548   -
  587 +
549 588 # Loop over observations and store a deep copy of the energy
550 589 # boundaries for later use
551 590 for obs in self._obs:
552 591 self._obs_ebounds.append(obs.events().ebounds().copy())
553   -
  592 +
554 593 # Initialise script
555 594 colnames = ['loge', 'emin', 'emax', 'crab_flux', 'photon_flux',
556   - 'energy_flux', 'sensitivity']
  595 + 'energy_flux', 'sensitivity', 'regcoeff', 'nevents',
  596 + 'npred']
557 597 results = []
558 598  
559 599 # Set test source model for this observation
... ... @@ -566,30 +606,35 @@ class cssens(ctools.cscript):
566 606 # Write models into logger
567 607 self._log_models(gammalib.NORMAL, models, 'Model')
568 608  
  609 + # Get sensitivity type
  610 + sensitivity_type = self['type'].string()
  611 +
569 612 # Write header
570 613 self._log_header1(gammalib.TERSE, 'Sensitivity determination')
571   - self._log_value(gammalib.TERSE, 'Type', str(self._type))
  614 + self._log_value(gammalib.TERSE, 'Type', sensitivity_type)
572 615  
573 616 # Loop over energy bins
574 617 for ieng in range(self._ebounds.size()):
575 618  
576 619 # Set energies
577   - if self._type == 'Differential':
  620 + if sensitivity_type == 'Differential':
578 621 emin = self._ebounds.emin(ieng)
579 622 emax = self._ebounds.emax(ieng)
580   - elif self._type == 'Integral':
  623 + elif sensitivity_type == 'Integral':
581 624 emin = self._ebounds.emin(ieng)
582 625 emax = self._ebounds.emax()
583 626 else:
584 627 msg = ('Invalid sensitivity type "%s" encountered. Either '
585   - 'specify "Differential" or "Integral".' % self._type)
  628 + 'specify "Differential" or "Integral".' %
  629 + sensitivity_type)
586 630 raise RuntimeError(msg)
587 631  
588 632 # Determine sensitivity
589 633 result = self._get_sensitivity(emin, emax, models)
590 634  
591 635 # Write out trial result
592   - ioutils.write_csv_row(self._outfile.url(), ieng, colnames, result)
  636 + ioutils.write_csv_row(self['outfile'].filename().url(), ieng,
  637 + colnames, result)
593 638  
594 639 # Append results
595 640 results.append(result)
... ...
doc/source/users/reference_manual/cssens.rst
... ... @@ -100,9 +100,6 @@ General parameters
100 100 ``(max_iter = 50) [integer]``
101 101 Maximum number of iterations.
102 102  
103   -``(num_avg = 3) [integer]``
104   - Number of iterations for sliding average.
105   -
106 103  
107 104 Standard parameters
108 105 -------------------
... ...
doc/source/users/reference_manual/ctbutterfly.rst
... ... @@ -3,21 +3,25 @@
3 3 ctbutterfly
4 4 ===========
5 5  
6   -Computes butterfly diagram for a power law model.
  6 +Computes butterfly diagram for a given spectral model.
7 7  
8 8  
9 9 Synopsis
10 10 --------
11 11  
12   -This tool calculates a butterfly diagram for a specific source with power law
13   -spectral model. The butterfly diagram is the envelope of all power law models
14   -that are within a given confidence limit compatible with the data. By default
15   -a confidence level of 68% is used, but the level can be adjusted using the
16   -hidden ``confidence`` parameter. ctbutterfly computes this envelope by
17   -evaluating for each energy the minimum and maximum intensity of all power law
18   -models that fall within the error ellipse of the prefactor and index parameters.
19   -The error ellipse is derived from the covariance matrix of a maximum likelihood
20   -fit.
  12 +This tool calculates a butterfly diagram for a specific source according to
  13 +its spectral model. The butterfly diagram is the envelope of all spectral
  14 +models that are within a given confidence limit compatible with the data.
  15 +The default method used for the calculation is Gaussian error propagation
  16 +using the covariance matrix from a maximum likelihood fit. By default a
  17 +confidence level of 68% is used, but the level can be adjusted using the
  18 +hidden ``confidence`` parameter. For power law models, an alternative
  19 +calculation method can be specified by setting the hidden parameter
  20 +``method=ENVELOPE``. By using this method, the envelope is computed by
  21 +evaluating for each energy the minimum and maximum intensity of all power
  22 +law models that fall within the error ellipse of the prefactor and index
  23 +parameters. The error ellipse is derived from the covariance matrix of a
  24 +maximum likelihood fit.
21 25  
22 26 ctbutterfly assumes that the input model (parameter ``inmodel``) has been
23 27 adjusted using :doc:`ctlike` to the data, but if this is not the case you
... ... @@ -68,11 +72,14 @@ General parameters
68 72  
69 73 ``outfile [file]``
70 74 Output butterfly ASCII file name.
71   -
  75 +
72 76 ``(fit = no) [boolean]``
73 77 Performs maximum likelihood fitting of input model ignoring any provided
74 78 covariance matrix.
75   -
  79 +
  80 +``(method = "GAUSSIAN") <GAUSSIAN|ENVELOPE> [string]``
  81 + Computation method.
  82 +
76 83 ``(confidence = 0.68) [real]``
77 84 Confidence level for error computation.
78 85  
... ...
doc/source/users/reference_manual/ctlike.rst
... ... @@ -48,13 +48,13 @@ the spatial model parameters can be kept fixed during that computation
48 48 ctlike generates an output model XML file that contains the values of the
49 49 best fitting model parameters. For all free parameters, an ``error`` attribute
50 50 is added that provides the statistical uncertainty in the parameter estimate.
51   -In addition, the entire output of the covariance matrix to a separate FITS file
52   -can be queried (parameter ``outcovmat``). The parameter order given in the file
53   -corresponds to the arrangement of the covariance matrix entries. If computation
54   -of the Test Statistics has been requested for a model component, a ``ts``
55   -attribute providing the Test Statistics value is added. The output model can be
56   -used as an input model for other ctools.
  51 +If computation of the Test Statistics has been requested for a model component,
  52 +a ``ts`` attribute providing the Test Statistics value is added. The output model
  53 +can be used as an input model for other ctools.
57 54  
  55 +In addition, the covariance matrix can be saved into a file by specifying a
  56 +file name for the ``outcovmat`` parameter. If the file name ends with ``.fits``
  57 +or ``.fit`` a FITS file is written, otherwise a CSV file is written.
58 58  
59 59  
60 60 General parameters
... ... @@ -89,7 +89,7 @@ General parameters
89 89 the maximum likelihood fit.
90 90  
91 91 ``(outcovmat = NONE) [string]``
92   - Output FITS file to store covariance matrix.
  92 + Output FITS or CSV file to store covariance matrix.
93 93  
94 94 ``(stat = POISSON) [string]``
95 95 Fitting statistics (POISSON or GAUSSIAN; only affects binned analysis).
... ...
doc/source/users/reference_manual/ctprob.rst 0 → 100644
  1 +.. _ctprob:
  2 +
  3 +ctprob
  4 +========
  5 +
  6 +Compute event probability for a given model.
  7 +
  8 +
  9 +Synopsis
  10 +--------
  11 +
  12 +This tool takes an event list file (or an XML observation definition file) and
  13 +a model as input and computes for each event the probability that it originates
  14 +from a specific model component. The probability is computed by by evaluating
  15 +the differential event probability for a given model and normalizing these
  16 +probabilities so that the sum of the probabilities for all model components is
  17 +unity for each event.
  18 +
  19 +The tool appends for each model component a single precision column to the event
  20 +list that contains the event probabilities. The name of the column is build from
  21 +the model name prefixed with ``PROB_``.
  22 +
  23 +
  24 +General parameters
  25 +------------------
  26 +
  27 +``inobs [file]``
  28 + Input event list or observation definition XML file
  29 +
  30 +``outobs [file]``
  31 + Output event list or observation definition XML file.
  32 +
  33 +``(prefix = "prob_") [string]``
  34 + Prefix for output event lists in observation definition file.
  35 +
  36 +``inmodel [string]``
  37 + Input model definition XML file.
  38 +
  39 +``caldb [string]``
  40 + Calibration database.
  41 +
  42 +``irf [string]``
  43 + Instrument response function.
  44 +
  45 +``(edisp = no) [boolean]``
  46 + Applies energy dispersion to response computation.
  47 +
  48 +
  49 +Standard parameters
  50 +-------------------
  51 +
  52 +``(publish = no) [boolean]``
  53 + Specifies whether the event list(s) should be published on VO Hub.
  54 +
  55 +``(chatter = 2) [integer]``
  56 + Verbosity of the executable:
  57 + chatter = 0: no information will be logged
  58 +
  59 + chatter = 1: only errors will be logged
  60 +
  61 + chatter = 2: errors and actions will be logged
  62 +
  63 + chatter = 3: report about the task execution
  64 +
  65 + chatter = 4: detailed report about the task execution
  66 +
  67 +``(clobber = yes) [boolean]``
  68 + Specifies whether existing output files should be overwritten.
  69 +
  70 +``(debug = no) [boolean]``
  71 + Enables debug mode. In debug mode the executable will dump any log file output to the console.
  72 +
  73 +``(mode = ql) [string]``
  74 + Mode of automatic parameters (default is "ql", i.e. "query and learn").
  75 +
  76 +``(logfile = ctprob.log) [string]``
  77 + Name of log file.
  78 +
  79 +
  80 +Related tools or scripts
  81 +------------------------
  82 +
  83 +:doc:`ctphase`
  84 +:doc:`csphasecrv`
  85 +
... ...
doc/source/users/reference_manual/index.rst
... ... @@ -27,6 +27,7 @@ ctools
27 27 ctmodel --- Computes model counts cube <ctmodel>
28 28 ctobssim --- Simulate observations <ctobssim>
29 29 ctpsfcube --- Generates point spread function cube <ctpsfcube>
  30 + ctprob --- Computes event probability for a given model <ctprob>
30 31 ctselect --- Selects event data <ctselect>
31 32 ctskymap --- Generates sky map <ctskymap>
32 33 cttsmap --- Generates Test Statistic map <cttsmap>
... ...
pyext/Makefile.am
... ... @@ -59,6 +59,7 @@ testscripts = ctools/tests/__init__.py \
59 59 $(top_srcdir)/test/test_ctbutterfly.py \
60 60 $(top_srcdir)/test/test_ctulimit.py \
61 61 $(top_srcdir)/test/test_cterror.py \
  62 + $(top_srcdir)/test/test_ctprob.py \
62 63 $(top_srcdir)/test/test_pipelines.py
63 64  
64 65 # Test data to be distributed in $(pyexecdir)/ctools/tests/data
... ...
pyext/ctool.i
1 1 /***************************************************************************
2 2 * ctool - ctool base class *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2014-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2014-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -105,6 +105,8 @@ public:
105 105 %rename(_insert_energy_boundaries) insert_energy_boundaries;
106 106 %rename(_cube_layer_usage) cube_layer_usage;
107 107 %rename(_is_valid_filename) is_valid_filename;
  108 + %rename(_get_gtiname) get_gtiname;
  109 + %rename(_save_event_list) save_event_list;
108 110 %rename(_warn_too_few_energies) warn_too_few_energies;
109 111 %rename(_warn_xml_suffix) warn_xml_suffix;
110 112  
... ... @@ -147,6 +149,13 @@ public:
147 149 std::vector<bool> cube_layer_usage(const GEbounds& cube_ebounds,
148 150 const GEbounds& list_ebounds) const;
149 151 bool is_valid_filename(const GFilename& filename) const;
  152 + std::string get_gtiname(const std::string& filename,
  153 + const std::string& evtname) const;
  154 + void save_event_list(const GCTAObservation* obs,
  155 + const std::string& infile,
  156 + const std::string& evtname,
  157 + const std::string& gtiname,
  158 + const std::string& outfile) const;
150 159  
151 160 // Protected warning strings
152 161 std::string warn_too_few_energies(const GEnergies& energies) const;
... ...
pyext/ctools/tools.i
... ... @@ -73,6 +73,7 @@ namespace std {
73 73 %include "ctbutterfly.i"
74 74 %include "ctulimit.i"
75 75 %include "cterror.i"
  76 +%include "ctprob.i"
76 77  
77 78 /* __ Test function ______________________________________________________ */
78 79 %pythoncode %{
... ...
pyext/ctphase.i
1 1 /***************************************************************************
2 2 * ctphase - Append phase information to CTA events file *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2017 by Leonardo Di Venere *
  4 + * copyright (C) 2017 by Joshua Cardenzana *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -21,7 +21,7 @@
21 21 /**
22 22 * @file ctphase.i
23 23 * @brief Append phase information to CTA events file
24   - * @author Leonardo Di Venere
  24 + * @author Joshua Cardenzana
25 25 */
26 26 %{
27 27 /* Put headers and other declarations here that are needed for compilation */
... ...
pyext/ctprob.i 0 → 100644
  1 +/***************************************************************************
  2 + * ctprob - Computes probability for a given model *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2012-2016 by Leonardo Di Venere *
  5 + * ----------------------------------------------------------------------- *
  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 +/**
  22 + * @file ctprob.i
  23 + * @brief Computes probability for a given model
  24 + * @author Leonardo Di Venere
  25 + */
  26 +%{
  27 +/* Put headers and other declarations here that are needed for compilation */
  28 +#include "ctprob.hpp"
  29 +%}
  30 +
  31 +
  32 +/***********************************************************************//**
  33 + * @class ctprob
  34 + *
  35 + * @brief Data selection tool
  36 + ***************************************************************************/
  37 +class ctprob : public ctobservation {
  38 +public:
  39 + // Constructors and destructors
  40 + ctprob(void);
  41 + explicit ctprob(const GObservations& obs);
  42 + ctprob(int argc, char *argv[]);
  43 + ctprob(const ctprob& app);
  44 + virtual ~ctprob(void);
  45 +
  46 + // Methods
  47 + void clear(void);
  48 + void run(void);
  49 + void save(void);
  50 + void publish(const std::string& name = "");
  51 +};
  52 +
  53 +
  54 +/***********************************************************************//**
  55 + * @brief Data selection tool Python extension
  56 + ***************************************************************************/
  57 +%extend ctprob {
  58 + ctprob copy() {
  59 + return (*self);
  60 + }
  61 +}
... ...
src/Makefile.am
1 1 #############################################################################
2 2 # Makefile.am for ctools module #
3 3 # ------------------------------------------------------------------------- #
4   -# Copyright (C) 2016 Juergen Knoedlseder #
  4 +# Copyright (C) 2016-2017 Juergen Knoedlseder #
5 5 # ------------------------------------------------------------------------- #
6 6 # #
7 7 # This program is free software: you can redistribute it and/or modify #
... ... @@ -41,7 +41,8 @@ SUBDIRS = support \
41 41 ctbutterfly \
42 42 ctulimit \
43 43 cterror \
44   - ctphase
  44 + ctphase \
  45 + ctprob
45 46  
46 47 # Scripts to be distributed
47 48 scripts = ctools-setup \
... ... @@ -70,7 +71,8 @@ libctools_la_LIBADD = support/libsupport.la \
70 71 ctbutterfly/libctbutterfly.la \
71 72 ctulimit/libctulimit.la \
72 73 cterror/libcterror.la \
73   - ctphase/libctphase.la
  74 + ctphase/libctphase.la \
  75 + ctprob/libctprob.la
74 76  
75 77 libctools_la_LDFLAGS = -version-info $(CTOOLS_LT_VERSION) @OPENMP_LIB_LDFLAGS@
76 78  
... ...
src/ctbin/ctbin.cpp
... ... @@ -55,7 +55,7 @@
55 55 *
56 56 * Constructs an empty event binning tool.
57 57 ***************************************************************************/
58   -ctbin::ctbin(void) : ctobservation(CTBIN_NAME, CTBIN_VERSION)
  58 +ctbin::ctbin(void) : ctobservation(CTBIN_NAME, VERSION)
59 59 {
60 60 // Initialise members
61 61 init_members();
... ... @@ -73,7 +73,7 @@ ctbin::ctbin(void) : ctobservation(CTBIN_NAME, CTBIN_VERSION)
73 73 * Constructs event binning tool from an observation container.
74 74 ***************************************************************************/
75 75 ctbin::ctbin(const GObservations& obs) :
76   - ctobservation(CTBIN_NAME, CTBIN_VERSION, obs)
  76 + ctobservation(CTBIN_NAME, VERSION, obs)
77 77 {
78 78 // Initialise members
79 79 init_members();
... ... @@ -94,7 +94,7 @@ ctbin::ctbin(const GObservations&amp; obs) :
94 94 * parameter setting.
95 95 ***************************************************************************/
96 96 ctbin::ctbin(int argc, char *argv[]) :
97   - ctobservation(CTBIN_NAME, CTBIN_VERSION, argc, argv)
  97 + ctobservation(CTBIN_NAME, VERSION, argc, argv)
98 98 {
99 99 // Initialise members
100 100 init_members();
... ...
src/ctbin/ctbin.hpp
... ... @@ -31,8 +31,7 @@
31 31 #include "ctobservation.hpp"
32 32  
33 33 /* __Definitions _________________________________________________________ */
34   -#define CTBIN_NAME "ctbin"
35   -#define CTBIN_VERSION "1.2.0"
  34 +#define CTBIN_NAME "ctbin"
36 35  
37 36  
38 37 /***********************************************************************//**
... ...
src/ctbkgcube/ctbkgcube.cpp
... ... @@ -50,7 +50,7 @@
50 50 /***********************************************************************//**
51 51 * @brief Void constructor
52 52 ***************************************************************************/
53   -ctbkgcube::ctbkgcube(void) : ctobservation(CTBKGCUBE_NAME, CTBKGCUBE_VERSION)
  53 +ctbkgcube::ctbkgcube(void) : ctobservation(CTBKGCUBE_NAME, VERSION)
54 54 {
55 55 // Initialise members
56 56 init_members();
... ... @@ -69,7 +69,7 @@ ctbkgcube::ctbkgcube(void) : ctobservation(CTBKGCUBE_NAME, CTBKGCUBE_VERSION)
69 69 * observations container.
70 70 ***************************************************************************/
71 71 ctbkgcube::ctbkgcube(const GObservations& obs) :
72   - ctobservation(CTBKGCUBE_NAME, CTBKGCUBE_VERSION, obs)
  72 + ctobservation(CTBKGCUBE_NAME, VERSION, obs)
73 73 {
74 74 // Initialise members
75 75 init_members();
... ... @@ -87,7 +87,7 @@ ctbkgcube::ctbkgcube(const GObservations&amp; obs) :
87 87 * @param[in] argv Array of command line arguments.
88 88 ***************************************************************************/
89 89 ctbkgcube::ctbkgcube(int argc, char *argv[]) :
90   - ctobservation(CTBKGCUBE_NAME, CTBKGCUBE_VERSION, argc, argv)
  90 + ctobservation(CTBKGCUBE_NAME, VERSION, argc, argv)
91 91 {
92 92 // Initialise members
93 93 init_members();
... ...
src/ctbkgcube/ctbkgcube.hpp
... ... @@ -33,8 +33,7 @@
33 33 #include "ctobservation.hpp"
34 34  
35 35 /* __Definitions _________________________________________________________ */
36   -#define CTBKGCUBE_NAME "ctbkgcube"
37   -#define CTBKGCUBE_VERSION "1.1.0"
  36 +#define CTBKGCUBE_NAME "ctbkgcube"
38 37  
39 38  
40 39 /***********************************************************************//**
... ...
src/ctbutterfly/ctbutterfly.cpp
1 1 /***************************************************************************
2 2 * ctbutterfly - butterfly calculation tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2014-2016 by Michael Mayer *
  4 + * copyright (C) 2014-2017 by Michael Mayer *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -52,7 +52,7 @@
52 52 /***********************************************************************//**
53 53 * @brief Void constructor
54 54 ***************************************************************************/
55   -ctbutterfly::ctbutterfly(void) : ctlikelihood(CTBUTTERFLY_NAME, CTBUTTERFLY_VERSION)
  55 +ctbutterfly::ctbutterfly(void) : ctlikelihood(CTBUTTERFLY_NAME, VERSION)
56 56 {
57 57 // Initialise members
58 58 init_members();
... ... @@ -71,7 +71,7 @@ ctbutterfly::ctbutterfly(void) : ctlikelihood(CTBUTTERFLY_NAME, CTBUTTERFLY_VERS
71 71 * observations container.
72 72 ***************************************************************************/
73 73 ctbutterfly::ctbutterfly(const GObservations& obs) :
74   - ctlikelihood(CTBUTTERFLY_NAME, CTBUTTERFLY_VERSION, obs)
  74 + ctlikelihood(CTBUTTERFLY_NAME, VERSION, obs)
75 75 {
76 76 // Initialise members
77 77 init_members();
... ... @@ -89,7 +89,7 @@ ctbutterfly::ctbutterfly(const GObservations&amp; obs) :
89 89 * @param[in] argv Array of command line arguments.
90 90 ***************************************************************************/
91 91 ctbutterfly::ctbutterfly(int argc, char *argv[]) :
92   - ctlikelihood(CTBUTTERFLY_NAME, CTBUTTERFLY_VERSION, argc, argv)
  92 + ctlikelihood(CTBUTTERFLY_NAME, VERSION, argc, argv)
93 93 {
94 94 // Initialise members
95 95 init_members();
... ... @@ -243,11 +243,14 @@ void ctbutterfly::run(void)
243 243 m_obs.optimize(m_opt);
244 244 m_obs.errors(m_opt);
245 245  
246   - // Get covariance matrix by inverting the curvature matrix. Note that
247   - // the curvature matrix is for the unscaled parameters, hence we have
248   - // to scale them before we can proceed.
  246 + // Get covariance matrix.
249 247 GObservations::likelihood likelihood = m_obs.function();
250   - m_covariance = likelihood.curvature()->invert();
  248 + if (m_method == "GAUSSIAN") {
  249 + m_covariance = likelihood.curvature()->invert();
  250 + }
  251 + else {
  252 + m_covariance = likelihood.covariance();
  253 + }
251 254  
252 255 // Write optimizer, optimised model and covariance matrix into logger
253 256 log_string(NORMAL, m_opt.print(m_chatter));
... ... @@ -271,157 +274,26 @@ void ctbutterfly::run(void)
271 274 GObservations::likelihood likelihood = m_obs.function();
272 275 likelihood.eval(pars);
273 276  
274   - // Get covariance matrix by inverting the curvature matrix. Note that
275   - // the curvature matrix is for the unscaled parameters, hence we have
276   - // to scale them before we can proceed.
277   - m_covariance = likelihood.curvature()->invert();
  277 + // Get covariance matrix.
  278 + if (m_method == "GAUSSIAN") {
  279 + m_covariance = likelihood.curvature()->invert();
  280 + }
  281 + else {
  282 + m_covariance = likelihood.covariance();
  283 + }
278 284  
279 285 // Write covariance matrix into logger
280 286 log_string(EXPLICIT, m_covariance.print(m_chatter));
281 287  
282 288 } // endif: covariance computation needed
283 289  
284   - // Write header into logger
285   - log_header1(TERSE, "Prepare butterfly computation");
286   -
287   - // Find parameter indices. We do this by the memory location of the
288   - // model parameters.
289   - GModelSky* skymodel = dynamic_cast<GModelSky*>(models[m_srcname]);
290   - GModelPar* par_prefactor = &(*skymodel)["Prefactor"];
291   - GModelPar* par_index = &(*skymodel)["Index"];
292   - int inx_prefactor = -1;
293   - int inx_index = -1;
294   - for (int i = 0; i < models.npars(); ++i) {
295   - if (models.pars()[i] == par_prefactor) {
296   - inx_prefactor = i;
297   - }
298   - if (models.pars()[i] == par_index) {
299   - inx_index = i;
300   - }
  290 + // Compute butterfly depending on selected method
  291 + if (m_method == "GAUSSIAN") {
  292 + gaussian_error_propagation(models);
  293 + }
  294 + else {
  295 + ellipsoid_boundary(models);
301 296 }
302   -
303   - // Store model values and scales
304   - double prefactor_mean = (*skymodel)["Prefactor"].value();
305   - double index_mean = (*skymodel)["Index"].value();
306   - double pivot_mean = (*skymodel)["PivotEnergy"].value();
307   - double prefactor_scale = (*skymodel)["Prefactor"].scale();
308   - double index_scale = (*skymodel)["Index"].scale();
309   - GEnergy pivot(pivot_mean, "MeV");
310   -
311   - // Write parameter indices into logger
312   - log_value(NORMAL, "Prefactor", gammalib::str(prefactor_mean)+
313   - " ph/cm2/s/MeV ("+gammalib::str(inx_prefactor)+")");
314   - log_value(NORMAL, "Index", gammalib::str(index_mean)+
315   - " ("+gammalib::str(inx_index)+")");
316   - log_value(NORMAL, "Pivot energy", pivot.print());
317   -
318   - // Extract covariance elements
319   - double cov_pp = m_covariance(inx_prefactor,inx_prefactor);
320   - double cov_pg = m_covariance(inx_prefactor,inx_index);
321   - double cov_gg = m_covariance(inx_index,inx_index);
322   -
323   - // Compute eigenvectors and eigenvalues
324   - double lambda1;
325   - double lambda2;
326   - GVector vector1(2);
327   - GVector vector2(2);
328   - eigenvectors(cov_pp, cov_pg, cov_pg, cov_gg,
329   - &lambda1, &lambda2, &vector1, &vector2);
330   -
331   - // Write eigenvectors and eigenvalues into logger
332   - log_value(NORMAL, "Eigenvalue 1", lambda1);
333   - log_value(NORMAL, "Eigenvalue 2", lambda2);
334   - log_value(NORMAL, "Eigenvector 1", vector1.print());
335   - log_value(NORMAL, "Eigenvector 2", vector2.print());
336   -
337   - // Confidence scaling
338   - double sigma = gammalib::erfinv(m_confidence) * gammalib::sqrt_two;
339   - double scale = (sigma*sigma);
340   -
341   - // Write confidence level information into logger
342   - log_value(NORMAL, "Confidence level", m_confidence);
343   - log_value(NORMAL, "Corresponding scaling", scale);
344   -
345   - // Compute minor and major axes of error ellipse
346   - double major = scale*std::sqrt(lambda1);
347   - double minor = scale*std::sqrt(lambda2);
348   -
349   - // Write header into logger
350   - log_header1(TERSE, "Generate butterfly");
351   -
352   - // Initialise result arrays
353   - m_energies.assign(m_ebounds.size(), 0.0);
354   - m_intensities.assign(m_ebounds.size(), 0.0);
355   - m_min_intensities.assign(m_ebounds.size(), 1e30);
356   - m_max_intensities.assign(m_ebounds.size(), 0.0);
357   -
358   - // Walk around the error ellipse
359   - int nt = 360;
360   - double dt = gammalib::twopi/double(nt);
361   - double t = 0.0;
362   - for (int i = 0; i < nt; ++i, t += dt) {
363   -
364   - // Pre-compute sin and cosine
365   - double sin_t = std::sin(t);
366   - double cos_t = std::cos(t);
367   -
368   - // Compute prefactor and index
369   - double prefactor = (major * cos_t * vector1[0] +
370   - minor * sin_t * vector2[0]) * prefactor_scale +
371   - prefactor_mean;
372   - double index = (major * cos_t * vector1[1] +
373   - minor * sin_t * vector2[1]) * index_scale +
374   - index_mean;
375   -
376   - // Write prefactor and index into logger
377   - log_value(EXPLICIT, "Angle "+gammalib::str(t*gammalib::rad2deg),
378   - gammalib::str(prefactor)+" ph/cm2/s/MeV; "+
379   - gammalib::str(index));
380   -
381   - // Setup power law model
382   - GModelSpectralPlaw plaw(prefactor, index, pivot);
383   -
384   - // Evaluate power law at each energy and extract minimum and
385   - // maximum intensity
386   - for (int k = 0; k < m_ebounds.size(); ++k) {
387   -
388   - // Get the energy of current bin
389   - GTime time;
390   - GEnergy energy = m_ebounds.elogmean(k);
391   -
392   - // Evaluate power law
393   - double intensity = plaw.eval(energy, time);
394   -
395   - // Get extremes
396   - if (intensity < m_min_intensities[k]) {
397   - m_min_intensities[k] = intensity;
398   - }
399   - if (intensity > m_max_intensities[k]) {
400   - m_max_intensities[k] = intensity;
401   - }
402   -
403   - } // endfor: looped over all energies
404   -
405   - } // endfor: looped over all angles
406   -
407   - // Setup power law model for mean prefactor and index
408   - GModelSpectralPlaw plaw(prefactor_mean, index_mean, pivot);
409   -
410   - // Compute energy and intensity vectors for mean power law
411   - for (int k = 0; k < m_ebounds.size(); ++k) {
412   -
413   - // Get the energy of current bin
414   - GTime time;
415   - GEnergy energy = m_ebounds.elogmean(k);
416   -
417   - // Evaluate power law
418   - double intensity = plaw.eval(energy, time);
419   -
420   - // Store results
421   - m_energies[k] = energy.MeV();
422   - m_intensities[k] = intensity;
423   -
424   - } // endfor: looped over energies
425 297  
426 298 // Write header into logger
427 299 log_header1(TERSE, "Results");
... ... @@ -431,11 +303,11 @@ void ctbutterfly::run(void)
431 303  
432 304 // Write results into logger
433 305 log_value(NORMAL, "Intensity at "+gammalib::str(m_energies[k])+" MeV",
434   - gammalib::str(m_intensities[k])+" ("+
435   - gammalib::str(m_min_intensities[k])+", "+
436   - gammalib::str(m_max_intensities[k])+") ph/cm2/s/MeV");
  306 + gammalib::str(m_intensities[k])+" ("+
  307 + gammalib::str(m_min_intensities[k])+", "+
  308 + gammalib::str(m_max_intensities[k])+") ph/cm2/s/MeV");
437 309  
438   - } // endfor: looped over energies
  310 + } //endfor: loop over energy bin
439 311  
440 312 // Restore energy dispersion flag for all CTA observations
441 313 for (int i = 0; i < m_obs.size(); ++i) {
... ... @@ -504,6 +376,7 @@ void ctbutterfly::init_members(void)
504 376 {
505 377 // Initialise members
506 378 m_srcname.clear();
  379 + m_method.clear();
507 380 m_confidence = 0.68;
508 381 m_max_iter = 50;
509 382 m_apply_edisp = false;
... ... @@ -537,6 +410,7 @@ void ctbutterfly::copy_members(const ctbutterfly&amp; app)
537 410 {
538 411 // Copy attributes
539 412 m_srcname = app.m_srcname;
  413 + m_method = app.m_method;
540 414 m_confidence = app.m_confidence;
541 415 m_max_iter = app.m_max_iter;
542 416 m_apply_edisp = app.m_apply_edisp;
... ... @@ -544,7 +418,7 @@ void ctbutterfly::copy_members(const ctbutterfly&amp; app)
544 418 m_chatter = app.m_chatter;
545 419 m_ebounds = app.m_ebounds;
546 420 m_outfile = app.m_outfile;
547   -
  421 +
548 422 // Copy protected members
549 423 m_covariance = app.m_covariance;
550 424 m_energies = app.m_energies;
... ... @@ -583,16 +457,13 @@ void ctbutterfly::get_parameters(void)
583 457 {
584 458 // Setup observations from "inobs" parameter
585 459 setup_observations(m_obs);
586   -
  460 +
587 461 // Setup models from "inmodel" parameter
588 462 setup_models(m_obs, (*this)["srcname"].string());
589 463  
590 464 // Get name of test source
591 465 m_srcname = (*this)["srcname"].string();
592 466  
593   - // Check model name and type
594   - check_model();
595   -
596 467 // Create energy boundaries from user parameters
597 468 m_ebounds = create_ebounds();
598 469  
... ... @@ -600,18 +471,22 @@ void ctbutterfly::get_parameters(void)
600 471 std::string matrixfilename = (*this)["matrix"].filename();
601 472 if (matrixfilename != "NONE") {
602 473 std::string msg = "Loading of matrix from file not implemented yet. "
603   - "Use filename = \"NONE\" to induce a recomputation of "
604   - "the matrix internally.";
  474 + "Use filename = \"NONE\" to induce a recomputation of "
  475 + "the matrix internally.";
605 476 throw GException::feature_not_implemented(G_GET_PARAMETERS, msg);
606 477 // m_covariance.load(matrixfilename);
607 478 }
608 479  
609 480 // Get remaining parameters
610 481 m_apply_edisp = (*this)["edisp"].boolean();
  482 + m_method = (*this)["method"].string();
611 483 m_confidence = (*this)["confidence"].real();
612 484 m_fit = (*this)["fit"].boolean();
613 485 m_chatter = static_cast<GChatter>((*this)["chatter"].integer());
614 486  
  487 + // Check model name and type
  488 + check_model();
  489 +
615 490 // Optionally read ahead parameters so that they get correctly
616 491 // dumped into the log file
617 492 if (read_ahead()) {
... ... @@ -627,6 +502,279 @@ void ctbutterfly::get_parameters(void)
627 502  
628 503  
629 504 /***********************************************************************//**
  505 + * @brief Compute butterfly using the ellipsoid boundary method
  506 + ***************************************************************************/
  507 +void ctbutterfly::ellipsoid_boundary(GModels& models)
  508 +{
  509 + // Write header into logger
  510 + log_header1(TERSE, "Prepare butterfly computation");
  511 +
  512 + // Find parameter indices. We do this by the memory location of the
  513 + // model parameters.
  514 + GModelSky* skymodel = dynamic_cast<GModelSky*>(models[m_srcname]);
  515 + GModelPar* par_prefactor = &(*skymodel)["Prefactor"];
  516 + GModelPar* par_index = &(*skymodel)["Index"];
  517 + int inx_prefactor = -1;
  518 + int inx_index = -1;
  519 + for (int i = 0; i < models.npars(); ++i) {
  520 + if (models.pars()[i] == par_prefactor) {
  521 + inx_prefactor = i;
  522 + }
  523 + if (models.pars()[i] == par_index) {
  524 + inx_index = i;
  525 + }
  526 + }
  527 +
  528 + // Store model values
  529 + double prefactor_mean = (*skymodel)["Prefactor"].value();
  530 + double index_mean = (*skymodel)["Index"].value();
  531 + double pivot_mean = (*skymodel)["PivotEnergy"].value();
  532 + double prefactor_scale = (*skymodel)["Prefactor"].scale();
  533 + double index_scale = (*skymodel)["Index"].scale();
  534 + GEnergy pivot(pivot_mean, "MeV");
  535 +
  536 + // Write parameter indices into logger
  537 + log_value(NORMAL, "Prefactor", gammalib::str(prefactor_mean)+
  538 + " ph/cm2/s/MeV ("+
  539 + gammalib::str(inx_prefactor)+")");
  540 + log_value(NORMAL, "Index", gammalib::str(index_mean)+
  541 + " ("+gammalib::str(inx_index)+")");
  542 + log_value(NORMAL, "Pivot energy", pivot.print());
  543 +
  544 + // Extract covariance elements
  545 + double cov_pp = m_covariance(inx_prefactor,inx_prefactor);
  546 + double cov_pg = m_covariance(inx_prefactor,inx_index);
  547 + double cov_gg = m_covariance(inx_index,inx_index);
  548 +
  549 + // Compute eigenvectors and eigenvalues
  550 + double lambda1;
  551 + double lambda2;
  552 + GVector vector1(2);
  553 + GVector vector2(2);
  554 + eigenvectors(cov_pp, cov_pg, cov_pg, cov_gg,
  555 + &lambda1, &lambda2, &vector1, &vector2);
  556 +
  557 + // Write eigenvectors and eigenvalues into logger
  558 + log_value(NORMAL, "Eigenvalue 1", lambda1);
  559 + log_value(NORMAL, "Eigenvalue 2", lambda2);
  560 + log_value(NORMAL, "Eigenvector 1", vector1.print());
  561 + log_value(NORMAL, "Eigenvector 2", vector2.print());
  562 +
  563 + // Confidence scaling, calculated from a Chi-Sqr.
  564 + // distribution with 2 dof
  565 + double scale = std::sqrt( -2. * std::log(1.-m_confidence) );
  566 +
  567 + // Write confidence level information into logger
  568 + log_value(NORMAL, "Confidence level", m_confidence);
  569 + log_value(NORMAL, "Corresponding scaling", scale);
  570 +
  571 + // Compute minor and major axes of error ellipse
  572 + double major = scale*std::sqrt(lambda1);
  573 + double minor = scale*std::sqrt(lambda2);
  574 +
  575 + // Write header into logger
  576 + log_header1(TERSE, "Generate butterfly");
  577 +
  578 + // Initialise result arrays
  579 + m_energies.assign(m_ebounds.size(), 0.0);
  580 + m_intensities.assign(m_ebounds.size(), 0.0);
  581 + m_min_intensities.assign(m_ebounds.size(), 1e30);
  582 + m_max_intensities.assign(m_ebounds.size(), 0.0);
  583 +
  584 + // Walk around the error ellipse
  585 + int nt = 360;
  586 + double dt = gammalib::twopi/double(nt);
  587 + double t = 0.0;
  588 + for (int i = 0; i < nt; ++i, t += dt) {
  589 +
  590 + // Pre-compute sin and cosine
  591 + double sin_t = std::sin(t);
  592 + double cos_t = std::cos(t);
  593 +
  594 + // Compute prefactor and index
  595 + double prefactor = (major * cos_t * vector1[0] +
  596 + minor * sin_t * vector2[0]) * prefactor_scale +
  597 + prefactor_mean;
  598 + double index = (major * cos_t * vector1[1] +
  599 + minor * sin_t * vector2[1]) * index_scale +
  600 + index_mean;
  601 +
  602 + // Write prefactor and index into logger
  603 + log_value(EXPLICIT, "Angle "+gammalib::str(t*gammalib::rad2deg),
  604 + gammalib::str(prefactor)+" ph/cm2/s/MeV; "+
  605 + gammalib::str(index));
  606 +
  607 + // Setup power law model
  608 + GModelSpectralPlaw plaw(prefactor, index, pivot);
  609 +
  610 + // Evaluate power law at each energy and extract minimum and
  611 + // maximum intensity
  612 + for (int k = 0; k < m_ebounds.size(); ++k) {
  613 +
  614 + // Get the energy of current bin
  615 + GTime time;
  616 + GEnergy energy = m_ebounds.elogmean(k);
  617 +
  618 + // Evaluate power law
  619 + double intensity = plaw.eval(energy, time);
  620 +
  621 + // Get extremes
  622 + if (intensity < m_min_intensities[k]) {
  623 + m_min_intensities[k] = intensity;
  624 + }
  625 + if (intensity > m_max_intensities[k]) {
  626 + m_max_intensities[k] = intensity;
  627 + }
  628 +
  629 + } // endfor: looped over all energies
  630 +
  631 + } // endfor: looped over all angles
  632 +
  633 + // Setup power law model for mean prefactor and index
  634 + GModelSpectralPlaw plaw(prefactor_mean, index_mean, pivot);
  635 +
  636 + // Compute energy and intensity vectors for mean power law
  637 + for (int k = 0; k < m_ebounds.size(); ++k) {
  638 +
  639 + // Get the energy of current bin
  640 + GTime time;
  641 + GEnergy energy = m_ebounds.elogmean(k);
  642 +
  643 + // Evaluate power law
  644 + double intensity = plaw.eval(energy, time);
  645 +
  646 + // Store results
  647 + m_energies[k] = energy.MeV();
  648 + m_intensities[k] = intensity;
  649 +
  650 + } // endfor: looped over energies
  651 +
  652 + // Return
  653 + return;
  654 +}
  655 +
  656 +
  657 +/***********************************************************************//**
  658 + * @brief Compute butterfly using Gaussian error propagation
  659 + *
  660 + * Computes the butterfly diagram using Gaussian error propagation. This
  661 + * works for any kind of model.
  662 + ***************************************************************************/
  663 +void ctbutterfly::gaussian_error_propagation(GModels& models)
  664 +{
  665 + // Write header into logger
  666 + log_header1(TERSE, "Prepare butterfly computation");
  667 +
  668 + // Confidence scaling
  669 + double scale = gammalib::erfinv(m_confidence) * gammalib::sqrt_two;
  670 +
  671 + // Write confidence level information into logger
  672 + log_value(NORMAL, "Confidence level", m_confidence);
  673 + log_value(NORMAL, "Corresponding scaling", scale);
  674 +
  675 + // Write header into logger
  676 + log_header1(TERSE, "Generate butterfly");
  677 +
  678 + // Initialise result arrays
  679 + m_energies.clear();
  680 + m_intensities.clear();
  681 + m_min_intensities.clear();
  682 + m_max_intensities.clear();
  683 +
  684 + // Initialise dummy time to evaluate spectral model
  685 + GTime time = GTime();
  686 +
  687 + // Initialise vector of gradients
  688 + GVector grad = GVector(m_obs.models().npars());
  689 +
  690 + // Loop over energy bins
  691 + for (int i = 0; i < m_ebounds.size(); ++i) {
  692 +
  693 + // Initialise number of gradients
  694 + int num_gradient = 0;
  695 +
  696 + // Get the mean logarithmic energy of current bin
  697 + GEnergy energy = m_ebounds.elogmean(i);
  698 +
  699 + // Initialise model flux value
  700 + double model_flux = 0.0;
  701 +
  702 + // Loop over models
  703 + for (int j = 0; j < models.size(); ++j) {
  704 +
  705 + // Check wether model is a skymodel
  706 + GModelSky* skymodel = dynamic_cast<GModelSky*>(models[j]);
  707 +
  708 + // Yes ...
  709 + if (skymodel != NULL) {
  710 +
  711 + // Set flux value of source of interest, evaluate gradients
  712 + if (skymodel->name() == m_srcname) {
  713 +
  714 + // Get spectral component of model
  715 + GModelSpectral *spectral = skymodel->spectral();
  716 +
  717 + // Get model flux
  718 + model_flux = spectral->eval(energy, time, true);
  719 +
  720 + // Loop over all model parameters
  721 + for (int k = 0; k < skymodel->size(); ++k) {
  722 +
  723 + // Set gradient if we deal with spectral component
  724 + bool parIsSpectral = false;
  725 + for (int l = 0; l < spectral->size(); ++l) {
  726 + if ((&((*spectral)[l])) == (&((*skymodel)[k]))) {
  727 + grad[num_gradient] = (*spectral)[l].gradient();
  728 + num_gradient++;
  729 + parIsSpectral = true;
  730 + break;
  731 + }
  732 + } // endfor: looped over spectral parameters
  733 +
  734 + // If parameter is spatial or temporal, count up
  735 + if (!parIsSpectral) {
  736 + num_gradient++;
  737 + }
  738 +
  739 + } // endfor: looped over all model parameters
  740 +
  741 + } // endif: model was source of interest
  742 + else {
  743 + num_gradient += skymodel->size();
  744 + }
  745 +
  746 + } // endif: model was sky model
  747 +
  748 + // Skip other models (e.g. GModelData instances)
  749 + else {
  750 + num_gradient += models[j]->size();
  751 + }
  752 +
  753 + } // endfor: Looped over models
  754 +
  755 + // Multiply covariance to the gradient vector
  756 + GVector vector = m_covariance * grad;
  757 +
  758 + // Get the error from the scalar product
  759 + double error = std::sqrt(grad * vector);
  760 +
  761 + // Multiply with confidence scaling
  762 + error *= scale;
  763 +
  764 + // Store flux, value and energy for saving
  765 + m_intensities.push_back(model_flux);
  766 + m_energies.push_back(energy.MeV());
  767 + m_min_intensities.push_back(model_flux-error);
  768 + m_max_intensities.push_back(model_flux+error);
  769 +
  770 + } // endfor: Looped over energy bins
  771 +
  772 + // Return
  773 + return;
  774 +}
  775 +
  776 +
  777 +/***********************************************************************//**
630 778 * @brief Check if sky model is valid
631 779 *
632 780 * @exception GException::invalid_value
... ... @@ -645,17 +793,22 @@ void ctbutterfly::check_model(void)
645 793 GModelSky* model = dynamic_cast<GModelSky*>(models[m_srcname]);
646 794 if (model == NULL) {
647 795 std::string msg = "Source \""+m_srcname+"\" is not a sky model. "
648   - "Please specify the name of a sky model for "
649   - "butterfly computation.";
  796 + "Please specify the name of a sky model for "
  797 + "butterfly computation.";
650 798 throw GException::invalid_value(G_CHECK_MODEL, msg);
651 799 }
652 800  
653   - // Check that the spectral model is a power law
654   - if (model->spectral()->type() != "PowerLaw") {
655   - std::string msg = "\""+model->spectral()->type()+"\" cannot be "
656   - "used as spectral model for an butterfly "
657   - "computation. Please specify a power law model.";
658   - throw GException::invalid_value(G_CHECK_MODEL, msg);
  801 + // Check that the spectral model is a power law for the "ENVELOPE"
  802 + // method
  803 + if (m_method == "ENVELOPE") {
  804 + if (model->spectral()->type() != "PowerLaw") {
  805 + std::string msg = "\""+model->spectral()->type()+"\" cannot be "
  806 + "used as spectral model for an butterfly "
  807 + "computation with method=ENVELOPE. Please "
  808 + "specify a power law model or switch to "
  809 + "method=GAUSSIAN.";
  810 + throw GException::invalid_value(G_CHECK_MODEL, msg);
  811 + }
659 812 }
660 813  
661 814 } // endif: source model existed
... ... @@ -663,8 +816,8 @@ void ctbutterfly::check_model(void)
663 816 // Otherwise throw an exception
664 817 else {
665 818 std::string msg = "Source \""+m_srcname+"\" not found in model "
666   - "container. Please add a source with that name "
667   - "or check for possible typos.";
  819 + "container. Please add a source with that name "
  820 + "or check for possible typos.";
668 821 throw GException::invalid_value(G_CHECK_MODEL, msg);
669 822 }
670 823  
... ... @@ -689,13 +842,13 @@ void ctbutterfly::check_model(void)
689 842 * http://www.math.harvard.edu/archive/21b_fall_04/exhibits/2dmatrices/index.html
690 843 ***************************************************************************/
691 844 void ctbutterfly::eigenvectors(const double& a,
692   - const double& b,
693   - const double& c,
694   - const double& d,
695   - double* lambda1,
696   - double* lambda2,
697   - GVector* vector1,
698   - GVector* vector2)
  845 + const double& b,
  846 + const double& c,
  847 + const double& d,
  848 + double* lambda1,
  849 + double* lambda2,
  850 + GVector* vector1,
  851 + GVector* vector2)
699 852 {
700 853 // Compute trace and determinant
701 854 double trace = a + d;
... ... @@ -730,7 +883,7 @@ void ctbutterfly::eigenvectors(const double&amp; a,
730 883 // Normalize eigenvectors
731 884 *vector1 /= norm(*vector1);
732 885 *vector2 /= norm(*vector2);
733   -
  886 +
734 887 // Return
735 888 return;
736 889 }
... ...
src/ctbutterfly/ctbutterfly.hpp
1 1 /***************************************************************************
2 2 * ctbutterfly - butterfly calculation tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2014-2016 by Michael Mayer *
  4 + * copyright (C) 2014-2017 by Michael Mayer *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -33,8 +33,7 @@
33 33 #include "ctlikelihood.hpp"
34 34  
35 35 /* __Definitions _________________________________________________________ */
36   -#define CTBUTTERFLY_NAME "ctbutterfly"
37   -#define CTBUTTERFLY_VERSION "1.1.0"
  36 +#define CTBUTTERFLY_NAME "ctbutterfly"
38 37  
39 38  
40 39 /***********************************************************************//**
... ... @@ -77,6 +76,10 @@ protected:
77 76 void copy_members(const ctbutterfly& app);
78 77 void free_members(void);
79 78 void get_parameters(void);
  79 + void gaussian_error_propagation(GModels& models);
  80 + void ellipsoid_boundary(GModels& models);
  81 +
  82 +
80 83 void check_model(void);
81 84 void eigenvectors(const double& a,
82 85 const double& b,
... ... @@ -89,6 +92,7 @@ protected:
89 92  
90 93 // User parameters
91 94 std::string m_srcname; //!< Name of source to compute butterfly
  95 + std::string m_method; //!< Computation method
92 96 double m_confidence; //!< Confidence level
93 97 int m_max_iter; //!< Maximum number of iterations
94 98 bool m_apply_edisp; //!< Apply energy dispersion?
... ...
src/ctbutterfly/ctbutterfly.par
... ... @@ -27,6 +27,7 @@ caldb, s, a, &quot;prod2&quot;,,, &quot;Calibration database&quot;
27 27 irf, s, a, "South_0.5h",,, "Instrument response function"
28 28 edisp, b, h, no,,, "Apply energy dispersion?"
29 29 outfile, f, a, "butterfly.txt",,, "Output ASCII file"
  30 +method, s, h, GAUSSIAN, GAUSSIAN|ENVELOPE,,"Butterfly computation method"
30 31  
31 32 #
32 33 # Butterfly parameters
... ...
src/ctcubemask/ctcubemask.cpp
... ... @@ -51,7 +51,7 @@
51 51 /***********************************************************************//**
52 52 * @brief Void constructor
53 53 ***************************************************************************/
54   -ctcubemask::ctcubemask(void) : ctobservation(CTCUBEMASK_NAME, CTCUBEMASK_VERSION)
  54 +ctcubemask::ctcubemask(void) : ctobservation(CTCUBEMASK_NAME, VERSION)
55 55 {
56 56 // Initialise members
57 57 init_members();
... ... @@ -70,7 +70,7 @@ ctcubemask::ctcubemask(void) : ctobservation(CTCUBEMASK_NAME, CTCUBEMASK_VERSION
70 70 * an observation container.
71 71 ***************************************************************************/
72 72 ctcubemask::ctcubemask(const GObservations& obs) :
73   - ctobservation(CTCUBEMASK_NAME, CTCUBEMASK_VERSION, obs)
  73 + ctobservation(CTCUBEMASK_NAME, VERSION, obs)
74 74 {
75 75 // Initialise members
76 76 init_members();
... ... @@ -89,7 +89,7 @@ ctcubemask::ctcubemask(const GObservations&amp; obs) :
89 89 * @param[in] argv Array of command line arguments.
90 90 ***************************************************************************/
91 91 ctcubemask::ctcubemask(int argc, char *argv[]) :
92   - ctobservation(CTCUBEMASK_NAME, CTCUBEMASK_VERSION, argc, argv)
  92 + ctobservation(CTCUBEMASK_NAME, VERSION, argc, argv)
93 93 {
94 94 // Initialise members
95 95 init_members();
... ...
src/ctcubemask/ctcubemask.hpp
... ... @@ -35,8 +35,7 @@
35 35 #include "ctobservation.hpp"
36 36  
37 37 /* __Definitions _________________________________________________________ */
38   -#define CTCUBEMASK_NAME "ctcubemask"
39   -#define CTCUBEMASK_VERSION "1.2.0"
  38 +#define CTCUBEMASK_NAME "ctcubemask"
40 39  
41 40  
42 41 /***********************************************************************//**
... ...
src/ctedispcube/ctedispcube.cpp
... ... @@ -52,7 +52,7 @@
52 52 *
53 53 * Constructs an empty energy dispersion tool.
54 54 ***************************************************************************/
55   -ctedispcube::ctedispcube(void) : ctobservation(CTEDISPCUBE_NAME, CTEDISPCUBE_VERSION)
  55 +ctedispcube::ctedispcube(void) : ctobservation(CTEDISPCUBE_NAME, VERSION)
56 56 {
57 57 // Initialise members
58 58 init_members();
... ... @@ -71,7 +71,7 @@ ctedispcube::ctedispcube(void) : ctobservation(CTEDISPCUBE_NAME, CTEDISPCUBE_VER
71 71 * in an observation container @p obs.
72 72 ***************************************************************************/
73 73 ctedispcube::ctedispcube(const GObservations& obs) :
74   - ctobservation(CTEDISPCUBE_NAME, CTEDISPCUBE_VERSION, obs)
  74 + ctobservation(CTEDISPCUBE_NAME, VERSION, obs)
75 75 {
76 76 // Initialise members
77 77 init_members();
... ... @@ -92,7 +92,7 @@ ctedispcube::ctedispcube(const GObservations&amp; obs) :
92 92 * on the command line.
93 93 ***************************************************************************/
94 94 ctedispcube::ctedispcube(int argc, char *argv[]) :
95   - ctobservation(CTEDISPCUBE_NAME, CTEDISPCUBE_VERSION, argc, argv)
  95 + ctobservation(CTEDISPCUBE_NAME, VERSION, argc, argv)
96 96 {
97 97 // Initialise members
98 98 init_members();
... ...
src/ctedispcube/ctedispcube.hpp
... ... @@ -33,8 +33,7 @@
33 33 #include "ctobservation.hpp"
34 34  
35 35 /* __Definitions _________________________________________________________ */
36   -#define CTEDISPCUBE_NAME "ctedispcube"
37   -#define CTEDISPCUBE_VERSION "1.1.0"
  36 +#define CTEDISPCUBE_NAME "ctedispcube"
38 37  
39 38  
40 39 /***********************************************************************//**
... ...
src/cterror/cterror.cpp
... ... @@ -52,7 +52,7 @@
52 52 *
53 53 * Constructs an empty cterror tool.
54 54 ***************************************************************************/
55   -cterror::cterror(void) : ctlikelihood(CTERROR_NAME, CTERROR_VERSION)
  55 +cterror::cterror(void) : ctlikelihood(CTERROR_NAME, VERSION)
56 56 {
57 57 // Initialise members
58 58 init_members();
... ... @@ -70,7 +70,7 @@ cterror::cterror(void) : ctlikelihood(CTERROR_NAME, CTERROR_VERSION)
70 70 * Constructs cterror tool from an observations container.
71 71 ***************************************************************************/
72 72 cterror::cterror(const GObservations& obs) :
73   - ctlikelihood(CTERROR_NAME, CTERROR_VERSION, obs)
  73 + ctlikelihood(CTERROR_NAME, VERSION, obs)
74 74 {
75 75 // Initialise members
76 76 init_members();
... ... @@ -90,7 +90,7 @@ cterror::cterror(const GObservations&amp; obs) :
90 90 * parameters that are provided as command line arguments.
91 91 ***************************************************************************/
92 92 cterror::cterror(int argc, char *argv[]) :
93   - ctlikelihood(CTERROR_NAME, CTERROR_VERSION, argc, argv)
  93 + ctlikelihood(CTERROR_NAME, VERSION, argc, argv)
94 94 {
95 95 // Initialise members
96 96 init_members();
... ...
src/cterror/cterror.hpp
... ... @@ -31,8 +31,7 @@
31 31 #include "ctlikelihood.hpp"
32 32  
33 33 /* __Definitions _________________________________________________________ */
34   -#define CTERROR_NAME "cterror"
35   -#define CTERROR_VERSION "1.2.0"
  34 +#define CTERROR_NAME "cterror"
36 35  
37 36  
38 37 /***********************************************************************//**
... ...
src/ctexpcube/ctexpcube.cpp
... ... @@ -50,7 +50,7 @@
50 50 /***********************************************************************//**
51 51 * @brief Void constructor
52 52 ***************************************************************************/
53   -ctexpcube::ctexpcube(void) : ctobservation(CTEXPCUBE_NAME, CTEXPCUBE_VERSION)
  53 +ctexpcube::ctexpcube(void) : ctobservation(CTEXPCUBE_NAME, VERSION)
54 54 {
55 55 // Initialise members
56 56 init_members();
... ... @@ -69,7 +69,7 @@ ctexpcube::ctexpcube(void) : ctobservation(CTEXPCUBE_NAME, CTEXPCUBE_VERSION)
69 69 * observations container.
70 70 ***************************************************************************/
71 71 ctexpcube::ctexpcube(const GObservations& obs) :
72   - ctobservation(CTEXPCUBE_NAME, CTEXPCUBE_VERSION, obs)
  72 + ctobservation(CTEXPCUBE_NAME, VERSION, obs)
73 73 {
74 74 // Initialise members
75 75 init_members();
... ... @@ -87,7 +87,7 @@ ctexpcube::ctexpcube(const GObservations&amp; obs) :
87 87 * @param[in] argv Array of command line arguments.
88 88 ***************************************************************************/
89 89 ctexpcube::ctexpcube(int argc, char *argv[]) :
90   - ctobservation(CTEXPCUBE_NAME, CTEXPCUBE_VERSION, argc, argv)
  90 + ctobservation(CTEXPCUBE_NAME, VERSION, argc, argv)
91 91 {
92 92 // Initialise members
93 93 init_members();
... ...
src/ctexpcube/ctexpcube.hpp
... ... @@ -33,8 +33,7 @@
33 33 #include "ctobservation.hpp"
34 34  
35 35 /* __Definitions _________________________________________________________ */
36   -#define CTEXPCUBE_NAME "ctexpcube"
37   -#define CTEXPCUBE_VERSION "1.1.0"
  36 +#define CTEXPCUBE_NAME "ctexpcube"
38 37  
39 38  
40 39 /***********************************************************************//**
... ...
src/ctlike/ctlike.cpp
1 1 /***************************************************************************
2 2 * ctlike - Maximum likelihood fitting tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2010-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2010-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -48,7 +48,7 @@
48 48 /***********************************************************************//**
49 49 * @brief Void constructor
50 50 ***************************************************************************/
51   -ctlike::ctlike(void) : ctlikelihood(CTLIKE_NAME, CTLIKE_VERSION)
  51 +ctlike::ctlike(void) : ctlikelihood(CTLIKE_NAME, VERSION)
52 52 {
53 53 // Initialise members
54 54 init_members();
... ... @@ -66,7 +66,7 @@ ctlike::ctlike(void) : ctlikelihood(CTLIKE_NAME, CTLIKE_VERSION)
66 66 * Constructs ctlike tool from an observations container.
67 67 ***************************************************************************/
68 68 ctlike::ctlike(const GObservations& obs) :
69   - ctlikelihood(CTLIKE_NAME, CTLIKE_VERSION, obs)
  69 + ctlikelihood(CTLIKE_NAME, VERSION, obs)
70 70 {
71 71 // Initialise members
72 72 init_members();
... ... @@ -86,7 +86,7 @@ ctlike::ctlike(const GObservations&amp; obs) :
86 86 * that are provided as command line arguments.
87 87 ***************************************************************************/
88 88 ctlike::ctlike(int argc, char *argv[]) :
89   - ctlikelihood(CTLIKE_NAME, CTLIKE_VERSION, argc, argv)
  89 + ctlikelihood(CTLIKE_NAME, VERSION, argc, argv)
90 90 {
91 91 // Initialise members
92 92 init_members();
... ... @@ -321,8 +321,13 @@ void ctlike::run(void)
321 321 /***********************************************************************//**
322 322 * @brief Save results
323 323 *
324   - * This method saves the fit results into a XML file and a FITS file. If
325   - * the filename parameters are "NONE", the files are not saved.
  324 + * This method saves the fit results and the covariance matrix. The fit
  325 + * results are written into a XML file while the covariance matrix is written
  326 + * into either a FITS or a CSV file, depending on the file type extension
  327 + * (an extension of `.fits` or `.fit` produce a FITS file, any other
  328 + * extension produces a CSV file).
  329 + *
  330 + * If the filenames are `NONE` no information is saved.
326 331 ***************************************************************************/
327 332 void ctlike::save(void)
328 333 {
... ...
src/ctlike/ctlike.hpp
1 1 /***************************************************************************
2 2 * ctlike - Maximum likelihood fitting tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2010-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2010-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -31,8 +31,7 @@
31 31 #include "ctlikelihood.hpp"
32 32  
33 33 /* __Definitions _________________________________________________________ */
34   -#define CTLIKE_NAME "ctlike"
35   -#define CTLIKE_VERSION "1.2.0"
  34 +#define CTLIKE_NAME "ctlike"
36 35  
37 36  
38 37 /***********************************************************************//**
... ... @@ -68,17 +67,17 @@ protected:
68 67 double reoptimize_lm(void);
69 68  
70 69 // User parameters
71   - bool m_refit; //!< Refitting
72   - GFilename m_outmodel; //!< Source model output XML file name
73   - GFilename m_outcovmat; //!< Covariance matrix output FITS file name
74   - bool m_apply_edisp; //!< Apply energy dispersion?
75   - bool m_fix_spat_for_ts; //!< Fix spatial parameters for TS computation?
76   - GChatter m_chatter; //!< Chattiness
  70 + bool m_refit; //!< Refitting
  71 + GFilename m_outmodel; //!< Source model output XML file name
  72 + GFilename m_outcovmat; //!< Covariance matrix output file name
  73 + bool m_apply_edisp; //!< Apply energy dispersion?
  74 + bool m_fix_spat_for_ts; //!< Fix spatial parameters for TS computation?
  75 + GChatter m_chatter; //!< Chattiness
77 76  
78 77 // Members
79   - int m_max_iter; //!< Maximum number of iterations
80   - int m_max_stall; //!< Maximum number of stalls
81   - double m_logL; //!< Maximum log likelihood
  78 + int m_max_iter; //!< Maximum number of iterations
  79 + int m_max_stall; //!< Maximum number of stalls
  80 + double m_logL; //!< Maximum log likelihood
82 81 };
83 82  
84 83 #endif /* CTLIKE_HPP */
... ...
src/ctmapcube/ctmapcube.cpp
... ... @@ -50,7 +50,7 @@
50 50 /***********************************************************************//**
51 51 * @brief Void constructor
52 52 ***************************************************************************/
53   -ctmapcube::ctmapcube(void) : ctool(CTMAPCUBE_NAME, CTMAPCUBE_VERSION)
  53 +ctmapcube::ctmapcube(void) : ctool(CTMAPCUBE_NAME, VERSION)
54 54 {
55 55 // Initialise members
56 56 init_members();
... ... @@ -67,7 +67,7 @@ ctmapcube::ctmapcube(void) : ctool(CTMAPCUBE_NAME, CTMAPCUBE_VERSION)
67 67 * @param[in] argv Array of command line arguments.
68 68 ***************************************************************************/
69 69 ctmapcube::ctmapcube(int argc, char *argv[]) :
70   - ctool(CTMAPCUBE_NAME, CTMAPCUBE_VERSION, argc, argv)
  70 + ctool(CTMAPCUBE_NAME, VERSION, argc, argv)
71 71 {
72 72 // Initialise members
73 73 init_members();
... ...
src/ctmapcube/ctmapcube.hpp
... ... @@ -33,8 +33,7 @@
33 33 #include "ctool.hpp"
34 34  
35 35 /* __Definitions _________________________________________________________ */
36   -#define CTMAPCUBE_NAME "ctmapcube"
37   -#define CTMAPCUBE_VERSION "1.3.0"
  36 +#define CTMAPCUBE_NAME "ctmapcube"
38 37  
39 38  
40 39 /***********************************************************************//**
... ...
src/ctmodel/ctmodel.cpp
... ... @@ -53,7 +53,7 @@ const GEnergy g_energy_margin(1.0e-12, &quot;TeV&quot;);
53 53 /***********************************************************************//**
54 54 * @brief Void constructor
55 55 ***************************************************************************/
56   -ctmodel::ctmodel(void) : ctobservation(CTMODEL_NAME, CTMODEL_VERSION)
  56 +ctmodel::ctmodel(void) : ctobservation(CTMODEL_NAME, VERSION)
57 57 {
58 58 // Initialise members
59 59 init_members();
... ... @@ -72,7 +72,7 @@ ctmodel::ctmodel(void) : ctobservation(CTMODEL_NAME, CTMODEL_VERSION)
72 72 * observations container.
73 73 ***************************************************************************/
74 74 ctmodel::ctmodel(const GObservations& obs) :
75   - ctobservation(CTMODEL_NAME, CTMODEL_VERSION, obs)
  75 + ctobservation(CTMODEL_NAME, VERSION, obs)
76 76 {
77 77 // Initialise members
78 78 init_members();
... ... @@ -90,7 +90,7 @@ ctmodel::ctmodel(const GObservations&amp; obs) :
90 90 * @param[in] argv Array of command line arguments.
91 91 ***************************************************************************/
92 92 ctmodel::ctmodel(int argc, char *argv[]) :
93   - ctobservation(CTMODEL_NAME, CTMODEL_VERSION, argc, argv)
  93 + ctobservation(CTMODEL_NAME, VERSION, argc, argv)
94 94 {
95 95 // Initialise members
96 96 init_members();
... ...
src/ctmodel/ctmodel.hpp
... ... @@ -33,8 +33,7 @@
33 33 #include "ctobservation.hpp"
34 34  
35 35 /* __Definitions _________________________________________________________ */
36   -#define CTMODEL_NAME "ctmodel"
37   -#define CTMODEL_VERSION "1.1.0"
  36 +#define CTMODEL_NAME "ctmodel"
38 37  
39 38  
40 39 /***********************************************************************//**
... ...
src/ctobssim/ctobssim.cpp
... ... @@ -67,7 +67,7 @@ const double g_roi_margin = 0.5; //!&lt; Simulation radius margin (degrees)
67 67 *
68 68 * Constructs an empty ctobssim tool.
69 69 ***************************************************************************/
70   -ctobssim::ctobssim(void) : ctobservation(CTOBSSIM_NAME, CTOBSSIM_VERSION)
  70 +ctobssim::ctobssim(void) : ctobservation(CTOBSSIM_NAME, VERSION)
71 71 {
72 72 // Initialise members
73 73 init_members();
... ... @@ -85,7 +85,7 @@ ctobssim::ctobssim(void) : ctobservation(CTOBSSIM_NAME, CTOBSSIM_VERSION)
85 85 * Constructs ctobssim tool from an observation container.
86 86 ***************************************************************************/
87 87 ctobssim::ctobssim(const GObservations& obs) :
88   - ctobservation(CTOBSSIM_NAME, CTOBSSIM_VERSION, obs)
  88 + ctobservation(CTOBSSIM_NAME, VERSION, obs)
89 89 {
90 90 // Initialise members
91 91 init_members();
... ... @@ -105,7 +105,7 @@ ctobssim::ctobssim(const GObservations&amp; obs) :
105 105 * setting.
106 106 ***************************************************************************/
107 107 ctobssim::ctobssim(int argc, char *argv[]) :
108   - ctobservation(CTOBSSIM_NAME, CTOBSSIM_VERSION, argc, argv)
  108 + ctobservation(CTOBSSIM_NAME, VERSION, argc, argv)
109 109 {
110 110 // Initialise members
111 111 init_members();
... ... @@ -1471,7 +1471,8 @@ void ctobssim::simulate_background(GCTAObservation* obs,
1471 1471  
1472 1472 // Debug code: signal that we step into the response MC method
1473 1473 #if defined(G_BACKGROUND_DEBUG)
1474   - std::cout << "ctobssim::simulate_background: model->mc in" << std::endl;
  1474 + std::cout << "ctobssim::simulate_background: model->mc in"
  1475 + << std::endl;
1475 1476 #endif
1476 1477  
1477 1478 // Get simulated CTA event list. Note that this method
... ... @@ -1481,7 +1482,8 @@ void ctobssim::simulate_background(GCTAObservation* obs,
1481 1482  
1482 1483 // Debug code: signal that we came back
1483 1484 #if defined(G_BACKGROUND_DEBUG)
1484   - std::cout << "ctobssim::simulate_background: model->mc out" << std::endl;
  1485 + std::cout << "ctobssim::simulate_background: model->mc out"
  1486 + << std::endl;
1485 1487 #endif
1486 1488  
1487 1489 // Continue only if we got a CTA event list
... ...
src/ctobssim/ctobssim.hpp
... ... @@ -33,8 +33,7 @@
33 33 #include "ctobservation.hpp"
34 34  
35 35 /* __Definitions _________________________________________________________ */
36   -#define CTOBSSIM_NAME "ctobssim"
37   -#define CTOBSSIM_VERSION "1.2.0"
  36 +#define CTOBSSIM_NAME "ctobssim"
38 37  
39 38  
40 39 /***********************************************************************//**
... ...
src/ctphase/Makefile.am
1 1 #############################################################################
2 2 # Makefile.am for ctphase tool #
3 3 # ------------------------------------------------------------------------- #
4   -# Copyright (C) 2017 Leonardo Di Venere #
  4 +# Copyright (C) 2017 Joshua Cardenzana #
5 5 # ------------------------------------------------------------------------- #
6 6 # #
7 7 # This program is free software: you can redistribute it and/or modify #
... ...
src/ctphase/ctphase.cpp
1 1 /***************************************************************************
2 2 * ctphase - Append phase information to CTA events file *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2017 by Leonardo Di Venere *
  4 + * copyright (C) 2017 by Joshua Cardenzana *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -21,7 +21,7 @@
21 21 /**
22 22 * @file ctphase.cpp
23 23 * @brief Append phase information to CTA events file
24   - * @author Leonardo Di Venere
  24 + * @author Joshua Cardenzana
25 25 */
26 26  
27 27 /* __ Includes ___________________________________________________________ */
... ... @@ -33,15 +33,12 @@
33 33 #include "GTools.hpp"
34 34  
35 35 /* __ Method name definitions ____________________________________________ */
36   -#define G_RUN "ctphase::run()"
37   -#define G_PHASE_EVENTS "ctphase::phase_events(GCTAObservation*, "\
38   - "std::string&, std::string&, std::string&)"
39   -#define G_SET_EBOUNDS "ctphase::set_ebounds(GCTAObservation*, GEbounds&)"
  36 +#define G_GET_PARAMETERS "ctphase::get_parameters()"
  37 +#define G_PHASE_EVENTS "ctphase::phase_events(GCTAObservation*)"
40 38  
41 39 /* __ Debug definitions __________________________________________________ */
42 40  
43 41 /* __ Coding definitions _________________________________________________ */
44   -//#define G_USE_MKSTEMP //!< Use mkstemp for temporary filename
45 42  
46 43  
47 44 /*==========================================================================
... ... @@ -53,7 +50,7 @@
53 50 /***********************************************************************//**
54 51 * @brief Void constructor
55 52 ***************************************************************************/
56   -ctphase::ctphase(void) : ctobservation(CTPHASE_NAME, CTPHASE_VERSION)
  53 +ctphase::ctphase(void) : ctobservation(CTPHASE_NAME, VERSION)
57 54 {
58 55 // Initialise members
59 56 init_members();
... ... @@ -72,7 +69,7 @@ ctphase::ctphase(void) : ctobservation(CTPHASE_NAME, CTPHASE_VERSION)
72 69 * provided in an observation container.
73 70 ***************************************************************************/
74 71 ctphase::ctphase(const GObservations& obs) :
75   - ctobservation(CTPHASE_NAME, CTPHASE_VERSION, obs)
  72 + ctobservation(CTPHASE_NAME, VERSION, obs)
76 73 {
77 74 // Initialise members
78 75 init_members();
... ... @@ -91,7 +88,7 @@ ctphase::ctphase(const GObservations&amp; obs) :
91 88 * @param[in] argv Array of command line arguments.
92 89 ***************************************************************************/
93 90 ctphase::ctphase(int argc, char *argv[]) :
94   - ctobservation(CTPHASE_NAME, CTPHASE_VERSION, argc, argv)
  91 + ctobservation(CTPHASE_NAME, VERSION, argc, argv)
95 92 {
96 93 // Initialise members
97 94 init_members();
... ... @@ -203,10 +200,11 @@ void ctphase::clear(void)
203 200  
204 201  
205 202 /***********************************************************************//**
206   - * @brief Append phase information to event data
  203 + * @brief Runs the ctprob tool
207 204 *
208 205 * This method reads in the application parameters and loops over all
209   - * observations that were found to append phase information to the data.
  206 + * unbinned observations to compute the phase information for each event
  207 + * based on an input model.
210 208 ***************************************************************************/
211 209 void ctphase::run(void)
212 210 {
... ... @@ -222,118 +220,22 @@ void ctphase::run(void)
222 220 log_observations(NORMAL, m_obs, "Input observation");
223 221  
224 222 // Write header into logger
225   - log_header1(TERSE, "Appending phase informaiton");
  223 + log_header1(TERSE, "Compute event phase");
226 224  
227 225 // Initialise counters
228 226 int n_observations = 0;
229 227  
230   - // Loop over all observation in the container
231   - for (int i = 0; i < m_obs.size(); ++i) {
232   -
233   - // Write header for the current observation
234   - log_header3(TERSE, get_obs_header(m_obs[i]));
235   -
236   - // Initialise event input and output filenames and the event
237   - // and GTI extension names
238   - m_infiles.push_back("");
239   - m_evtname.push_back(gammalib::extname_cta_events);
240   - m_gtiname.push_back(gammalib::extname_gti);
241   -
242   - // Get CTA observation
243   - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
244   -
245   - // Skip observation if it's not CTA
246   - if (obs == NULL) {
247   - std::string msg = " Skipping "+m_obs[i]->instrument()+
248   - " observation";
249   - log_string(NORMAL, msg);
250   - continue;
251   - }
252   -
253   - // Skip observation if we have a binned observation
254   - if (obs->eventtype() == "CountsCube") {
255   - std::string msg = " Skipping binned "+m_obs[i]->instrument()+
256   - " observation";
257   - log_string(NORMAL, msg);
258   - continue;
259   - }
  228 + // Loop over all unbinned CTA observations in the container
  229 + for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL;
  230 + obs = next_unbinned_observation()) {
260 231  
261 232 // Increment counter
262 233 n_observations++;
263 234  
264   - // Save event file name (for possible saving)
265   - m_infiles[i] = obs->eventfile();
266   -
267   - // Extract event and GTI extension names from input FITS file
268   - GFilename fname(m_infiles[i]);
269   - if (fname.has_extname()) {
270   - m_evtname[i] = fname.extname();
271   - }
272   - m_gtiname[i] = get_gtiname(fname.url(), m_evtname[i]);
273   -
274   - // Write input file information into logger
275   - log_value(NORMAL, "Input filename", m_infiles[i]);
276   - log_value(NORMAL, "Event extension name", m_evtname[i]);
277   - log_value(NORMAL, "GTI extension name", m_gtiname[i]);
278   -
279   - // Fall through in case that the event file is empty
280   - if (obs->events()->size() == 0) {
281   - log_string(NORMAL, " Warning: No events in event file \""+
282   - m_infiles[i]+"\". Event phasing skipped.");
283   - continue;
284   - }
  235 + // Compute event phase
  236 + phase_events(obs);
285 237  
286   - // If we have an input file then check it
287   - if (!m_infiles[i].empty()) {
288   - std::string message = check_infile(m_infiles[i], m_evtname[i]);
289   - if (!message.empty()) {
290   - throw GException::invalid_value(G_RUN, message);
291   - }
292   - }
293   -
294   - // Get temporary file name
295   - #if G_USE_MKSTEMP
296   - char tpl[] = "ctphaseXXXXXX";
297   - int fileid = mkstemp(tpl);
298   - std::string filename(tpl);
299   - #else
300   - std::string filename = std::tmpnam(NULL);
301   - #endif
302   -
303   - // Save observation in temporary file. We add here the events and
304   - // GTI extension name so that the GCTAObservation::save method can
305   - // use this information for writing the proper extension names into
306   - // the temporary file
307   - obs->save(filename+"["+m_evtname[i]+";"+ m_gtiname[i]+"]", true);
308   -
309   - // Log saved FITS file.
310   - if (logExplicit()) {
311   - GFits tmpfile(filename);
312   - log.header3("FITS file content of temporary file");
313   - log << tmpfile << std::endl;
314   - tmpfile.close();
315   - }
316   -
317   - // If we have a temporary file then check it
318   - if (!filename.empty()) {
319   - std::string message = check_infile(filename, m_evtname[i]);
320   - if (!message.empty()) {
321   - throw GException::invalid_value(G_RUN, message);
322   - }
323   - }
324   -
325   - // Load observation from temporary file and compute phase
326   - phase_events(obs, filename, m_evtname[i], m_gtiname[i]);
327   -
328   - // Close temporary file
329   - #if G_USE_MKSTEMP
330   - close(fileid);
331   - #endif
332   -
333   - // Remove temporary file
334   - std::remove(filename.c_str());
335   -
336   - } // endfor: looped over all observations
  238 + } // endfor: looped over observations
337 239  
338 240 // If more than a single observation has been handled then make sure that
339 241 // an XML file will be used for storage
... ... @@ -380,12 +282,12 @@ void ctphase::save(void)
380 282  
381 283 // Case A: Save event file(s) and XML metadata information
382 284 if (m_use_xml) {
383   - save_xml();
  285 + save_events_xml();
384 286 }
385 287  
386 288 // Case B: Save event file as FITS file
387 289 else {
388   - save_fits();
  290 + save_events_fits();
389 291 }
390 292  
391 293 // Return
... ... @@ -459,15 +361,10 @@ void ctphase::publish(const std::string&amp; name)
459 361 void ctphase::init_members(void)
460 362 {
461 363 // Initialise parameters
462   - m_outobs.clear();
463   - m_prefix.clear();
464   - m_phase.clear();
465 364 m_chatter = static_cast<GChatter>(2);
466 365  
467 366 // Initialise protected members
468   - m_infiles.clear();
469   - m_evtname.clear();
470   - m_gtiname.clear();
  367 + m_phase.clear();
471 368  
472 369 // Return
473 370 return;
... ... @@ -482,15 +379,10 @@ void ctphase::init_members(void)
482 379 void ctphase::copy_members(const ctphase& app)
483 380 {
484 381 // Copy parameters
485   - m_outobs = app.m_outobs;
486   - m_prefix = app.m_prefix;
487   - m_chatter = app.m_chatter;
  382 + m_chatter = app.m_chatter;
488 383  
489 384 // Copy protected members
490   - m_infiles = app.m_infiles;
491   - m_evtname = app.m_evtname;
492   - m_gtiname = app.m_gtiname;
493   - m_phase = app.m_phase;
  385 + m_phase = app.m_phase;
494 386  
495 387 // Return
496 388 return;
... ... @@ -502,8 +394,6 @@ void ctphase::copy_members(const ctphase&amp; app)
502 394 ***************************************************************************/
503 395 void ctphase::free_members(void)
504 396 {
505   - m_phase.clear();
506   -
507 397 // Return
508 398 return;
509 399 }
... ... @@ -526,381 +416,81 @@ void ctphase::get_parameters(void)
526 416 // information and do not accept counts cubes.
527 417 setup_observations(m_obs, false, true, false);
528 418  
529   - // Check whether a model XML file and source name were supplied
530   - if (!((*this)["inmodel"].filename().file().empty()) &&
531   - !((*this)["source"].string().empty())) {
532   -
533   - // Get the information from an xml file
534   - read_phase_info_from_xml();
535   - }
536   -
537   - // Check for sanity of frequency and phase information
538   - else if ((*this)["p0"].is_valid() &&
539   - (*this)["mjd"].is_valid() &&
540   - (*this)["f0"].is_valid()&&
541   - (*this)["f1"].is_valid()&&
542   - (*this)["f2"].is_valid()) {
543   -
544   - // The following creates an XML object responsible for initializing
545   - // 'm_phase'. This was done as the default values for the parameters in
546   - // 'GModelTemporalPhaseCurve' are such that the ranges are predefined.
547   - // Initializing 'm_phase' from an XML object circumvents this restriction.
548   -
549   - GXmlElement norm;
550   - norm.name("parameter");
551   - norm.attribute("name", "Normalization");
552   - norm.attribute("value", "1");
553   - norm.attribute("min", "0");
554   - norm.attribute("max", "1000");
555   -
556   - GXmlElement mjd;
557   - mjd.name("parameter");
558   - mjd.attribute("name", "MJD");
559   - mjd.attribute("value", (*this)["mjd"].value());
560   - mjd.attribute("min", (*this)["mjd"].min());
561   - mjd.attribute("max", (*this)["mjd"].max());
562   -
563   - GXmlElement p0;
564   - p0.name("parameter");
565   - p0.attribute("name", "Phase");
566   - p0.attribute("value", (*this)["p0"].value());
567   - p0.attribute("min", (*this)["p0"].min());
568   - p0.attribute("max", (*this)["p0"].max());
569   -
570   - GXmlElement f0;
571   - f0.name("parameter");
572   - f0.attribute("name", "F0");
573   - f0.attribute("value", (*this)["f0"].value());
574   - f0.attribute("min", (*this)["f0"].min());
575   - f0.attribute("max", (*this)["f0"].max());
576   -
577   - GXmlElement f1;
578   - f1.name("parameter");
579   - f1.attribute("name", "F1");
580   - f1.attribute("value", (*this)["f1"].value());
581   - f1.attribute("min", (*this)["f1"].min());
582   - f1.attribute("max", (*this)["f1"].max());
583   -
584   - GXmlElement f2;
585   - f2.name("parameter");
586   - f2.attribute("name", "F2");
587   - f2.attribute("value", (*this)["f2"].value());
588   - f2.attribute("min", (*this)["f2"].min());
589   - f2.attribute("max", (*this)["f2"].max());
590   -
591   - GXmlElement info;
592   - info.append(norm);
593   - info.append(mjd);
594   - info.append(p0);
595   - info.append(f0);
596   - info.append(f1);
597   - info.append(f2);
598   -
599   - info.attribute("file","");
600   -
601   - m_phase = GModelTemporalPhaseCurve();
602   - m_phase.read(info);
603   - }
604   - else {
605   - GException::invalid_value("ctphase::get_parameters()",
606   - "Invalid parameter value for p0, mjd, f0, f1, or f2.");
607   - }
608   -
609   - // Get other User parameters
610   - m_chatter = static_cast<GChatter>((*this)["chatter"].integer());
611   -
612   - // Optionally read ahead parameters so that they get correctly
613   - // dumped into the log file
614   - if (read_ahead()) {
615   - m_outobs = (*this)["outobs"].filename();
616   - m_prefix = (*this)["prefix"].string();
617   - }
618   -
619   - // Write parameters into logger
620   - log_parameters(TERSE);
621   -
622   - // Return
623   - return;
624   -}
625   -
626   -/*************************************************************************
627   - * @brief Read phase information from XML file
628   - *
629   - * @exception GException::par_error
630   - * Source does not have a temporal component with phase information.
631   - ***************************************************************************/
632   -void ctphase::read_phase_info_from_xml(void)
633   -{
634   - // Load the models from the xml file
635   - GModels in_models((*this)["inmodel"].filename());
636   -
637   - // Get the temporal component of this source
638   - std::string src_name = (*this)["source"].string();
639   - GModelSky* model = dynamic_cast<GModelSky*>(in_models[src_name]);
640   - GModelTemporalPhaseCurve* temporal_model = dynamic_cast<GModelTemporalPhaseCurve*>(model->temporal());
641   -
642   - // Make sure the model has a temporal component with phase info
643   - if (temporal_model != NULL) {
644   -
645   - // Copy the phase model
646   - m_phase = GModelTemporalPhaseCurve(*temporal_model);
647   -
648   - } else {
649   - // Throw an error as there is no temporal component for this source
650   - throw GException::par_error("ctphase::get_parameters(void)",
651   - "source",
652   - "\"" + src_name + "\" source model " +
653   - "does not have a temporal component with "+
654   - "phase information!");
655   - }
656   -}
657   -
658   -
659   -/***********************************************************************//**
660   - * @brief Define phase for events
661   - *
662   - * @param[in,out] obs CTA observation.
663   - * @param[in] filename File name.
664   - * @param[in] evtname Event extension name.
665   - * @param[in] gtiname GTI extension name.
666   - *
667   - * @exception GException::invalid_value
668   - * No events extension found in FITS file.
669   - *
670   - * Append phase information to events from a FITS file by adding a "PHASE"
671   - * column to the FITS file.
672   - ***************************************************************************/
673   -void ctphase::phase_events(GCTAObservation* obs,
674   - const std::string& filename,
675   - const std::string& evtname,
676   - const std::string& gtiname)
677   -{
678   - // Get CTA event list pointer
679   - GCTAEventList* list =
680   - static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events()));
681   -
682   - GCTAEventAtom* event = (*list)[0];
683   -
684   - // Print a warning into the log file if there are some precision concerns
685   - double dt = std::abs(event->time() - m_phase.mjd());
686   - if (((m_phase.f1() * dt) > 1.0e8) ||
687   - (m_phase.f2() * dt * dt) > 1.0e8) {
688   - log_string(NORMAL,"*** WARNING ***");
689   - log_string(NORMAL," Values supplied for reference MJD and/or f1 and/or f2");
690   - log_string(NORMAL," are large and may result in numerical precision issues.");
691   - log_string(NORMAL," Consider using an ephemeris derived from a date closer");
692   - log_string(NORMAL," to the data being analyzed.");
693   - log_value(NORMAL, " Observation ID", obs->obs_id());
694   - log_value(NORMAL, " Reference MJD", m_phase.mjd().mjd());
695   - log_value(NORMAL, " First event MJD", event->time().mjd());
696   - log_string(NORMAL,"*** WARNING ***");
697   - }
698   -
699   - for (int evnt=0; evnt<list->size(); evnt++) {
700   - // Get the next event
701   - event = (*list)[evnt];
702   -
703   - // Get the event time
704   - GTime time = event->time();
705   -
706   - // Set the event phase
707   - event->phase(m_phase.phase(time));
708   - }
709   -
710   - // Make sure the file knows to save the phase information
711   - if (!list->has_phase()) {
712   - list->has_phase(true);
713   - }
714   -
715   - // Return
716   - return;
717   -}
718   -
719   -
720   -/***********************************************************************//**
721   - * @brief Check input filename
722   - *
723   - * @param[in] filename File name.
724   - * @param[in] evtname Event extension name.
725   - *
726   - * This method checks if the input FITS file is correct.
727   - ***************************************************************************/
728   -std::string ctphase::check_infile(const std::string& filename,
729   - const std::string& evtname) const
730   -{
731   - // Initialise message string
732   - std::string message = "";
733   -
734   - // Open FITS file
735   - GFits fits(filename);
736   -
737   - // Check for existence of events extensions
738   - if (!fits.contains(evtname)) {
739   - message = "No \""+evtname+"\" extension found in input file \""+
740   - filename + "\".";
741   - }
742   -
743   - // ... otherwise check column names
744   - else {
  419 + // If a model definition XML file is provided the
  420 + GFilename inmodel = (*this)["inmodel"].filename();
  421 + if (is_valid_filename(inmodel)) {
745 422  
746   - // Get pointer to FITS table
747   - GFitsTable* table = fits.table(evtname);
  423 + // Load the models from the XML file
  424 + GModels models(inmodel);
748 425  
749   - // Initialise list of missing columns
750   - std::vector<std::string> missing;
  426 + // Get the source component
  427 + std::string source = (*this)["source"].string();
751 428  
752   - // Check for existence of TIME column
753   - if (!table->contains("TIME")) {
754   - missing.push_back("TIME");
  429 + // Throw an exception if source is not found in the model container
  430 + if (!models.contains(source)) {
  431 + std::string msg = "Source model \""+source+"\" not found in model "
  432 + "definition XML file \""+inmodel.url()+"\".";
  433 + throw GException::invalid_value(G_GET_PARAMETERS, msg);
755 434 }
756 435  
757   - // Check for existence of ENERGY column
758   - if (!table->contains("ENERGY")) {
759   - missing.push_back("ENERGY");
760   - }
  436 + // Get pointer to source model
  437 + GModelSky* sky = dynamic_cast<GModelSky*>(models[source]);
761 438  
762   - // Check for existence of RA column
763   - if (!table->contains("RA")) {
764   - missing.push_back("RA");
  439 + // Throw an exception if model is not a sky model
  440 + if (sky == NULL) {
  441 + std::string msg = "Source model \""+source+"\" is not a sky model.";
  442 + throw GException::invalid_value(G_GET_PARAMETERS, msg);
765 443 }
766 444  
767   - // Check for existence of DEC column
768   - if (!table->contains("DEC")) {
769   - missing.push_back("DEC");
770   - }
  445 + // Get pointer to temporal phase curve
  446 + GModelTemporalPhaseCurve* phasecurve =
  447 + dynamic_cast<GModelTemporalPhaseCurve*>(sky->temporal());
771 448  
772   - // Set error message for missing columns
773   - if (!missing.empty()) {
774   - message = "The following columns are missing in the "
775   - "\""+evtname+"\" extension of input file \""+
776   - filename + "\": ";
777   - for (int i = 0; i < missing.size(); ++i) {
778   - message += "\"" + missing[i] + "\"";
779   - if (i < missing.size()-1) {
780   - message += ", ";
781   - }
782   - }
  449 + // Throw an exception if model has not a temporal phase curve
  450 + // component
  451 + if (phasecurve == NULL) {
  452 + std::string msg = "Source model \""+source+"\" does not have a "
  453 + "temporal component with phase information.";
  454 + throw GException::invalid_value(G_GET_PARAMETERS, msg);
783 455 }
784 456  
785   - } // endelse: checked column names
786   -
787   - // Return
788   - return message;
789   -}
790   -
791   -
792   -/***********************************************************************//**
793   - * @brief Set output file name.
794   - *
795   - * @param[in] filename Input file name.
796   - *
797   - * Converts an input file name into an output filename by prepending the
798   - * prefix stored in the member m_prefix to the input file name. Any path as
799   - * well as extension will be stripped from the input file name. Also a
800   - * trailing ".gz" will be stripped as one cannot write into gzipped files.
801   - ***************************************************************************/
802   -std::string ctphase::set_outfile_name(const std::string& filename) const
803   -{
804   - // Create filename
805   - GFilename fname(filename);
806   -
807   - // Split input filename without any extensions into path elements
808   - std::vector<std::string> elements = gammalib::split(fname.url(), "/");
809   -
810   - // The last path element is the filename
811   - std::string outname = m_prefix + elements[elements.size()-1];
812   -
813   - // Strip any ".gz"
814   - outname = gammalib::strip_chars(outname, ".gz");
815   -
816   - // Return output filename
817   - return outname;
818   -}
819   -
820   -
821   -/***********************************************************************//**
822   - * @brief Get Good Time Intervals extension name
823   - *
824   - * @param[in] filename Input file name.
825   - * @param[in] evtname Events extension name.
826   - *
827   - * Extracts the Good Time Intervals extension name from the event file. We
828   - * do this by loading the events and accessing the Good Time Intervals
829   - * extension name using the GCTAEventList::gtiname() method. If the file name
830   - * is empty, the method returns `GTI`.
831   - ***************************************************************************/
832   -std::string ctphase::get_gtiname(const std::string& filename,
833   - const std::string& evtname) const
834   -{
835   - // Initialise GTI name
836   - std::string gtiname = gammalib::extname_gti;
837   -
838   - // Continue only if the filename is not empty
839   - if (!filename.empty()) {
  457 + // Set phase curve
  458 + m_phase = GModelTemporalPhaseCurve(*phasecurve);
840 459  
841   - // Load events
842   - GCTAEventList events(filename+"["+evtname+"]");
  460 + } // endif: model definition XML file provided
843 461  
844   - // Get GTI name
845   - gtiname = events.gtiname();
846   -
847   - } // endif: filename was not empty
848   -
849   - // Return GTI name
850   - return (gtiname);
851   -}
852   -
853   -
854   -/***********************************************************************//**
855   - * @brief Save event list in FITS format.
856   - *
857   - * Save the event list as a FITS file. The file name of the FITS file is
858   - * specified by the "outobs" parameter.
859   - ***************************************************************************/
860   -void ctphase::save_fits(void)
861   -{
862   - // Save only if there are observations
863   - if (m_obs.size() > 0) {
864   -
865   - // Get output filename
866   - m_outobs = (*this)["outobs"].filename();
867   -
868   - // Get CTA observation from observation container
869   - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]);
870   -
871   - // Save only if it's a CTA observation
872   - if (obs != NULL) {
873   -
874   - // Save only if file name is non-empty
875   - if (m_infiles[0].length() > 0) {
  462 + // Otherwise read phase curve information from the parameter files
  463 + else {
876 464  
877   - // Create file name object
878   - GFilename fname(m_outobs);
  465 + // Read phase curve user parameters
  466 + GFilename phasecurve = (*this)["phasecurve"].filename();
  467 + double mjd_value = (*this)["mjd"].real();
  468 + double phase = (*this)["phase"].real();
  469 + double f0 = (*this)["f0"].real();
  470 + double f1 = (*this)["f1"].real();
  471 + double f2 = (*this)["f2"].real();
879 472  
880   - // Extract filename and event extension name
881   - std::string outfile = fname.url();
  473 + // Set reference time
  474 + GTime mjd;
  475 + mjd.mjd(mjd_value);
882 476  
883   - // Append event extension name. We handle here the possibility
884   - // to write the events into a different extension.
885   - if (fname.has_extname()) {
886   - outfile += "["+fname.extname()+"]";
887   - }
888   - else {
889   - outfile += "["+m_evtname[0]+"]";
890   - }
  477 + // Set phase curve
  478 + m_phase = GModelTemporalPhaseCurve(phasecurve, mjd, phase, f0, f1, f2);
891 479  
892   - // Log filename
893   - log_value(NORMAL, "Event list file", outfile);
  480 + } // endelse: read phase curve information from User parameters
894 481  
895   - // Save event list
896   - save_event_list(obs, m_infiles[0], m_evtname[0], m_gtiname[0],
897   - outfile);
898   -
899   - } // endif: filename was non empty
  482 + // Get other User parameters
  483 + m_chatter = static_cast<GChatter>((*this)["chatter"].integer());
900 484  
901   - } // endif: observation was CTA observation
  485 + // Optionally read ahead parameters so that they get correctly
  486 + // dumped into the log file
  487 + if (read_ahead()) {
  488 + (*this)["outobs"].filename();
  489 + (*this)["prefix"].string();
  490 + }
902 491  
903   - } // endif: there were observations
  492 + // Write parameters into logger
  493 + log_parameters(TERSE);
904 494  
905 495 // Return
906 496 return;
... ... @@ -908,169 +498,68 @@ void ctphase::save_fits(void)
908 498  
909 499  
910 500 /***********************************************************************//**
911   - * @brief Save event list(s) in XML format.
  501 + * @brief Compute event phase for an observation
912 502 *
913   - * Save the event list(s) into FITS files and write the file path information
914   - * into a XML file. The filename of the XML file is specified by the outfile
915   - * parameter, the filename(s) of the event lists are built by prepending a
916   - * prefix to the input event list filenames. Any path present in the input
917   - * filename will be stripped, i.e. the event list(s) will be written in the
918   - * local working directory (unless a path is specified in the prefix).
  503 + * @param[in,out] obs CTA observation.
  504 + *
  505 + * @exception GException::invalid_value
  506 + * No events extension found in FITS file.
  507 + *
  508 + * Append phase information to events from a FITS file by adding a "PHASE"
  509 + * column to the FITS file.
919 510 ***************************************************************************/
920   -void ctphase::save_xml(void)
  511 +void ctphase::phase_events(GCTAObservation* obs)
921 512 {
922   - // Get output filename and prefix
923   - m_outobs = (*this)["outobs"].filename();
924   - m_prefix = (*this)["prefix"].string();
925   -
926   - // Issue warning if output filename has no .xml suffix
927   - log_string(TERSE, warn_xml_suffix(m_outobs));
928   -
929   - // Loop over all observation in the container
930   - for (int i = 0; i < m_obs.size(); ++i) {
931   -
932   - // Get CTA observation
933   - GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
934   -
935   - // Skip observations that are no CTA observations
936   - if (obs == NULL) {
937   - continue;
938   - }
  513 + // Write header into logger
  514 + log_header3(NORMAL, "Compute event phases");
  515 +
  516 + // Make sure that the observation holds a CTA event list. If this
  517 + // is not the case then throw an exception.
  518 + GCTAEventList* events = dynamic_cast<GCTAEventList*>(const_cast<GEvents*>
  519 + (obs->events()));
  520 + if (events == NULL) {
  521 + std::string msg = "CTA Observation does not contain an event list. An "
  522 + "event list is needed to compute the event phases.";
  523 + throw GException::invalid_value(G_PHASE_EVENTS, msg);
  524 + }
939 525  
940   - // Skip observations that have empty names
941   - if (m_infiles[i].length() == 0) {
942   - continue;
  526 + // Continue only if there are events
  527 + if (events->size() > 0) {
  528 +
  529 + // Print a warning into the log file if there are some precision concerns
  530 + GCTAEventAtom* event = (*events)[0];
  531 + double dt = std::abs(event->time() - m_phase.mjd());
  532 + if (((m_phase.f1() * dt) > 1.0e8) ||
  533 + (m_phase.f2() * dt * dt) > 1.0e8) {
  534 + log_string(NORMAL,"*** WARNING ***");
  535 + log_string(NORMAL," Values supplied for reference MJD and/or f1 and/or f2");
  536 + log_string(NORMAL," are large and may result in numerical precision issues.");
  537 + log_string(NORMAL," Consider using an ephemeris derived from a date closer");
  538 + log_string(NORMAL," to the data being analyzed.");
  539 + log_value(NORMAL, " Observation ID", obs->obs_id());
  540 + log_value(NORMAL, " Reference MJD", m_phase.mjd().mjd());
  541 + log_value(NORMAL, " First event MJD", event->time().mjd());
  542 + log_string(NORMAL,"*** WARNING ***");
943 543 }
944 544  
945   - // Set event output file name
946   - std::string outfile = set_outfile_name(m_infiles[i]);
947   -
948   - // Append event extension name
949   - outfile += "["+m_evtname[i]+"]";
950   -
951   - // Log filename
952   - log_value(NORMAL, "Event list file", outfile);
953   -
954   - // Store output file name in observation
955   - obs->eventfile(outfile);
956   -
957   - // Save event list
958   - save_event_list(obs, m_infiles[i], m_evtname[i], m_gtiname[i],
959   - outfile);
960   -
961   - } // endfor: looped over observations
962   -
963   - // Write observation definition XML file name into logger
964   - log_value(NORMAL, "Obs. definition file", m_outobs);
965   -
966   - // Save observations in XML file
967   - m_obs.save(m_outobs);
968   -
969   - // Return
970   - return;
971   -}
972   -
  545 + // Compute the phase for all events
  546 + for (int i = 0; i < events->size(); ++i) {
973 547  
974   -/***********************************************************************//**
975   - * @brief Save event list into FITS file
976   - *
977   - * @param[in] obs Pointer to CTA observation.
978   - * @param[in] infile Input file name.
979   - * @param[in] evtname Event extension name.
980   - * @param[in] gtiname GTI extension name.
981   - * @param[in] outfile Output file name.
982   - *
983   - * Saves an event list and the corresponding Good Time Intervals into a FITS
984   - * file and copy all others extensions from the input file to the output
985   - * file.
986   - *
987   - * If an extension name is specified in the @p outfile argument, the events
988   - * and eventually also the Good Time Intervals will be extracted from the
989   - * argument and used for writing the events. The format is
990   - *
991   - * <filename>[<event extension name;GTI extension name>]
992   - *
993   - * where <filename> needs to be replaced by the name of the FITS file,
994   - * and <event extension name;GTI extension name> by the name of the events
995   - * and Good Time Intervals extensions. For example
996   - *
997   - * myfits.fits[EVENTS1;GTI1]
998   - *
999   - * will write the updated events into the "EVENTS1" extension and the
1000   - * Good Time Intervals into the "GTI1" extension of the "myfits.fits" FITS
1001   - * file. If the Good Time Intervals extension name is skipped, e.g.
1002   - *
1003   - * myfits.fits[EVENTS1]
1004   - *
1005   - * the original extension name for the Good Time Intervals will be kept.
1006   - * Analogously, only the Good Time Intervals extension name can be changed
1007   - * by specifying
1008   - *
1009   - * myfits.fits[;GTI1]
1010   - *
1011   - * In none of the cases will the original events and Good Time Intervals be
1012   - * copied over to the output file.
1013   - ***************************************************************************/
1014   -void ctphase::save_event_list(const GCTAObservation* obs,
1015   - const std::string& infile,
1016   - const std::string& evtname,
1017   - const std::string& gtiname,
1018   - const std::string& outfile) const
1019   -{
1020   - // Save only if we have an event list
1021   - if (obs->eventtype() == "EventList") {
1022   -
1023   - // Set output FITS file event extension names
1024   - GFilename outname(outfile);
1025   - std::string outevt = evtname;
1026   - std::string outgti = gtiname;
1027   - if (outname.has_extname()) {
1028   - std::vector<std::string> extnames =
1029   - gammalib::split(outname.extname(), ";");
1030   - if (extnames.size() > 0) {
1031   - std::string extname = gammalib::strip_whitespace(extnames[0]);
1032   - if (!extname.empty()) {
1033   - outevt = extname;
1034   - }
1035   - }
1036   - if (extnames.size() > 1) {
1037   - std::string extname = gammalib::strip_whitespace(extnames[1]);
1038   - if (!extname.empty()) {
1039   - outgti = extname;
1040   - }
1041   - }
1042   - }
  548 + // Get pointer to the event
  549 + GCTAEventAtom* event = (*events)[i];
1043 550  
1044   - // Create output FITS file
1045   - GFits outfits;
1046   -
1047   - // Write observation into FITS file
1048   - obs->write(outfits, outevt, outgti);
1049   -
1050   - // Copy all extensions other than evtname and gtiname extensions
1051   - // from the input to the output event list. The evtname and
1052   - // gtiname extensions are written by the save method, all others
1053   - // that may eventually be present have to be copied over
1054   - // explicitly.
1055   - GFits infits(infile);
1056   - for (int extno = 1; extno < infits.size(); ++extno) {
1057   - GFitsHDU* hdu = infits.at(extno);
1058   - if (hdu->extname() != evtname &&
1059   - hdu->extname() != gtiname &&
1060   - hdu->extname() != outevt &&
1061   - hdu->extname() != outgti) {
1062   - outfits.append(*hdu);
1063   - }
1064   - }
1065   -
1066   - // Close input file
1067   - infits.close();
  551 + // Get the event time
  552 + GTime time = event->time();
  553 +
  554 + // Set the event phase
  555 + event->phase(m_phase.phase(time));
1068 556  
1069   - // Save file to disk and close it (we need both operations)
1070   - outfits.saveto(outname.url(), clobber());
1071   - outfits.close();
  557 + } // endfor: looped over events
1072 558  
1073   - } // endif: observation was unbinned
  559 + } // endif: there were events
  560 +
  561 + // Signal that phase information is available
  562 + events->has_phase(true);
1074 563  
1075 564 // Return
1076 565 return;
... ...
src/ctphase/ctphase.hpp
1 1 /***************************************************************************
2 2 * ctphase - Append phase information to CTA events file *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2017 by Leonardo Di Venere *
  4 + * copyright (C) 2017 by Joshua Cardenzana *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -21,7 +21,7 @@
21 21 /**
22 22 * @file ctphase.hpp
23 23 * @brief Append phase information to CTA events file
24   - * @author Leonardo Di Venere
  24 + * @author Joshua Cardenzana
25 25 */
26 26  
27 27 #ifndef CTPHASE_HPP
... ... @@ -35,8 +35,7 @@
35 35 #include "ctobservation.hpp"
36 36  
37 37 /* __Definitions _________________________________________________________ */
38   -#define CTPHASE_NAME "ctphase"
39   -#define CTPHASE_VERSION "0.0.1"
  38 +#define CTPHASE_NAME "ctphase"
40 39  
41 40  
42 41 /***********************************************************************//**
... ... @@ -65,38 +64,17 @@ public:
65 64  
66 65 protected:
67 66 // Protected methods
68   - void init_members(void);
69   - void copy_members(const ctphase& app);
70   - void free_members(void);
71   - void get_parameters(void);
72   - void read_phase_info_from_xml(void);
73   - void phase_events(GCTAObservation* obs,
74   - const std::string& filename,
75   - const std::string& evtname,
76   - const std::string& gtiname);
77   - std::string check_infile(const std::string& filename,
78   - const std::string& evtname) const;
79   - std::string set_outfile_name(const std::string& filename) const;
80   - std::string get_gtiname(const std::string& filename,
81   - const std::string& evtname) const;
82   - void save_fits(void);
83   - void save_xml(void);
84   - void save_event_list(const GCTAObservation* obs,
85   - const std::string& infile,
86   - const std::string& evtname,
87   - const std::string& gtiname,
88   - const std::string& outfile) const;
  67 + void init_members(void);
  68 + void copy_members(const ctphase& app);
  69 + void free_members(void);
  70 + void get_parameters(void);
  71 + void phase_events(GCTAObservation* obs);
89 72  
90 73 // User parameters
91   - std::string m_outobs; //!< Output event list or XML file
92   - std::string m_prefix; //!< Prefix for multiple event lists
93   - GModelTemporalPhaseCurve m_phase; //!< Phase information object
94   - GChatter m_chatter; //!< Chattiness
  74 + GChatter m_chatter; //!< Chattiness
95 75  
96 76 // Protected members
97   - std::vector<std::string> m_infiles; //!< Input event filenames
98   - std::vector<std::string> m_evtname; //!< Event extension names
99   - std::vector<std::string> m_gtiname; //!< GTI extension names
  77 + GModelTemporalPhaseCurve m_phase; //!< Phase curve model
100 78 };
101 79  
102 80  
... ...
src/ctphase/ctphase.par
... ... @@ -5,11 +5,10 @@
5 5 # ------------------------------------------------------------------------- #
6 6 # #
7 7 # File: ctphase.par #
8   -# Version: 0.0.1 #
9 8 # #
10   -# Author: Leonardo Di Venere #
11   -# leonardo.divenere@ba.infn.it #
12   -# INFN #
  9 +# Author: Joshua Cardenzana #
  10 +# jcardenzana@irap.omp.eu #
  11 +# IRAP #
13 12 # #
14 13 # Purpose: Parameter file for the ctphase application #
15 14 # #
... ... @@ -17,20 +16,21 @@
17 16 #
18 17 # General parameters
19 18 #===================
20   -inobs, f, a,events.fits,,, "Input event list or observation definition XML file"
21   -outobs, f, a,phased_events.fits,,, "Output event list or observation definition XML file"
22   -prefix, s, h, "phased_",,, "Prefix for event lists in observation definition XML file"
23   -inmodel, f, h, ,,, "Model file defining the phase information"
24   -source, s, h, ,,, "Source in model file to use for phase information"
  19 +inobs, f, a, "events.fits",,, "Input event list or observation definition XML file"
  20 +outobs, f, a, "phased_events.fits",,, "Output event list or observation definition XML file"
  21 +prefix, s, h, "phased_",,, "Prefix for event lists in observation definition XML file"
  22 +inmodel, f, a, "$CTOOLS/share/models/crab.xml",,, "Model file defining the phase information"
  23 +source, s, a, "Crab",,, "Source in model file to use for phase information"
25 24  
26 25 #
27 26 # Phase information parameters
28 27 #=====================
29   -mjd, r, a, 51544.5,,, "Reference MJD for phase information"
30   -p0, r, a, 0.0,0.0,1.0, "Phase at reference MJD"
31   -f0, r, a, 1,,, "Frequency at reference MJD [Hz]"
32   -f1, r, a, 0.0,,, "First freq. derivative at reference MJD [s^-1]"
33   -f2, r, a, 0.0,,, "Second freq. derivative at reference MJD [s^-2]"
  28 +phasecurve, f, a, phase.fits,,, "Phase curve FITS file"
  29 +mjd, r, a, 51544.5,,, "Reference MJD for phase information"
  30 +phase, r, a, 0.0,0.0,1.0, "Phase at reference MJD"
  31 +f0, r, a, 1.0,,, "Frequency at reference MJD (Hz)"
  32 +f1, r, a, 0.1,,, "First freq. derivative at reference MJD (s^-1)"
  33 +f2, r, a, 0.01,,, "Second freq. derivative at reference MJD (s^-2)"
34 34  
35 35 #
36 36 # Standard parameters
... ...
src/ctphase/main.cpp
1 1 /***************************************************************************
2 2 * ctphase - Append phase information to CTA events file *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2017 by Leonardo Di Venere *
  4 + * copyright (C) 2017 by Joshua Cardenzana *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -21,7 +21,7 @@
21 21 /**
22 22 * @file ctphase/main.cpp
23 23 * @brief Append phase information to CTA events file
24   - * @author Leonardo Di Venere
  24 + * @author Joshua Cardenzana
25 25 */
26 26  
27 27 /* __ Includes ___________________________________________________________ */
... ...
src/ctprob/Makefile.am 0 → 100644
  1 +#############################################################################
  2 +# Makefile.am for ctprob tool #
  3 +# ------------------------------------------------------------------------- #
  4 +# Copyright (C) 2017 Leonardo Di Venere #
  5 +# ------------------------------------------------------------------------- #
  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 +
  22 +# Set include directories
  23 +INCLUDES = -I$(top_srcdir)/src/support
  24 +
  25 +# Program name
  26 +bin_PROGRAMS = ctprob
  27 +
  28 +# Sources
  29 +sources = ctprob.cpp ctprob.hpp
  30 +
  31 +# Libtool library
  32 +noinst_LTLIBRARIES = libctprob.la
  33 +libctprob_la_SOURCES = $(sources)
  34 +libctprob_la_LDFLAGS = @OPENMP_LIB_LDFLAGS@
  35 +
  36 +# Program definition
  37 +ctprob_SOURCES = main.cpp
  38 +ctprob_LDFLAGS = $(LIB_LINK_OPTION) @LDFLAGS@
  39 +ctprob_CPPFLAGS = @CPPFLAGS@
  40 +ctprob_LDADD = libctprob.la $(top_builddir)/src/support/libsupport.la
  41 +
  42 +# Parameter files
  43 +pfilesdir = $(prefix)/syspfiles
  44 +pfiles_DATA = $(srcdir)/ctprob.par
  45 +
  46 +# Extra files to be distributed in the tar file
  47 +EXTRA_DIST = $(pfiles_DATA)
... ...
src/ctprob/ctprob.cpp 0 → 100644
  1 +/***************************************************************************
  2 + * ctprob - Computes event probability for a given model *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2017 by Leonardo Di Venere *
  5 + * ----------------------------------------------------------------------- *
  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 +/**
  22 + * @file ctprob.cpp
  23 + * @brief Computes event probability for a given model
  24 + * @author Leonardo Di Venere
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#endif
  31 +#include <cstdlib>
  32 +#include "ctprob.hpp"
  33 +#include "GTools.hpp"
  34 +
  35 +/* __ Method name definitions ____________________________________________ */
  36 +#define G_GET_OBS "ctprob::get_obs()"
  37 +#define G_EVALUATE_PROB "ctprob::evaluate_probability(GCTAObservation*)"
  38 +
  39 +/* __ Debug definitions __________________________________________________ */
  40 +
  41 +/* __ Coding definitions _________________________________________________ */
  42 +
  43 +
  44 +/*==========================================================================
  45 + = =
  46 + = Constructors/destructors =
  47 + = =
  48 + ==========================================================================*/
  49 +
  50 +/***********************************************************************//**
  51 + * @brief Void constructor
  52 + ***************************************************************************/
  53 +ctprob::ctprob(void) : ctobservation(CTPROB_NAME, VERSION)
  54 +{
  55 + // Initialise members
  56 + init_members();
  57 +
  58 + // Return
  59 + return;
  60 +}
  61 +
  62 +
  63 +/***********************************************************************//**
  64 + * @brief Observations constructor
  65 + *
  66 + * param[in] obs Observation container.
  67 + *
  68 + * Creates an instance of the class that is initialised using the information
  69 + * provided in an observation container.
  70 + ***************************************************************************/
  71 +ctprob::ctprob(const GObservations& obs) :
  72 + ctobservation(CTPROB_NAME, VERSION, obs)
  73 +{
  74 + // Initialise members
  75 + init_members();
  76 +
  77 + // Return
  78 + return;
  79 +}
  80 +
  81 +
  82 +
  83 +
  84 +/***********************************************************************//**
  85 + * @brief Command line constructor
  86 + *
  87 + * @param[in] argc Number of arguments in command line.
  88 + * @param[in] argv Array of command line arguments.
  89 + ***************************************************************************/
  90 +ctprob::ctprob(int argc, char *argv[]) :
  91 + ctobservation(CTPROB_NAME, VERSION, argc, argv)
  92 +{
  93 + // Initialise members
  94 + init_members();
  95 +
  96 + // Return
  97 + return;
  98 +}
  99 +
  100 +
  101 +/***********************************************************************//**
  102 + * @brief Copy constructor
  103 + *
  104 + * @param[in] app Application.
  105 + ***************************************************************************/
  106 +ctprob::ctprob(const ctprob& app) : ctobservation(app)
  107 +{
  108 + // Initialise members
  109 + init_members();
  110 +
  111 + // Copy members
  112 + copy_members(app);
  113 +
  114 + // Return
  115 + return;
  116 +}
  117 +
  118 +
  119 +/***********************************************************************//**
  120 + * @brief Destructor
  121 + ***************************************************************************/
  122 +ctprob::~ctprob(void)
  123 +{
  124 + // Free members
  125 + free_members();
  126 +
  127 + // Return
  128 + return;
  129 +}
  130 +
  131 +
  132 +/*==========================================================================
  133 + = =
  134 + = Operators =
  135 + = =
  136 + ==========================================================================*/
  137 +
  138 +/***********************************************************************//**
  139 + * @brief Assignment operator
  140 + *
  141 + * @param[in] app Application.
  142 + * @return Application.
  143 + ***************************************************************************/
  144 +ctprob& ctprob::operator=(const ctprob& app)
  145 +{
  146 + // Execute only if object is not identical
  147 + if (this != &app) {
  148 +
  149 + // Copy base class members
  150 + this->ctobservation::operator=(app);
  151 +
  152 + // Free members
  153 + free_members();
  154 +
  155 + // Initialise members
  156 + init_members();
  157 +
  158 + // Copy members
  159 + copy_members(app);
  160 +
  161 + } // endif: object was not identical
  162 +
  163 + // Return this object
  164 + return *this;
  165 +}
  166 +
  167 +
  168 +/*==========================================================================
  169 + = =
  170 + = Public methods =
  171 + = =
  172 + ==========================================================================*/
  173 +
  174 +/***********************************************************************//**
  175 + * @brief Clear ctprob tool
  176 + *
  177 + * Clears ctprob tool.
  178 + ***************************************************************************/
  179 +void ctprob::clear(void)
  180 +{
  181 + // Free members
  182 + free_members();
  183 + this->ctobservation::free_members();
  184 + this->ctool::free_members();
  185 +
  186 + // Clear base class (needed to conserve tool name and version)
  187 + this->GApplication::clear();
  188 +
  189 + // Initialise members
  190 + this->ctool::init_members();
  191 + this->ctobservation::init_members();
  192 + init_members();
  193 +
  194 + // Write header into logger
  195 + log_header();
  196 +
  197 + // Return
  198 + return;
  199 +}
  200 +
  201 +
  202 +/***********************************************************************//**
  203 + * @brief Runs the ctprob tool
  204 + *
  205 + * This method reads in the application parameters and loops over all
  206 + * unbinned observations to compute the probability for each event that it
  207 + * comes from one of the model components.
  208 + ***************************************************************************/
  209 +void ctprob::run(void)
  210 +{
  211 + // Switch screen logging on in debug mode
  212 + if (logDebug()) {
  213 + log.cout(true);
  214 + }
  215 +
  216 + // Get parameters
  217 + get_parameters();
  218 +
  219 + // Set energy dispersion flags of all CTA observations and save old
  220 + // values in save_edisp vector
  221 + std::vector<bool> save_edisp = set_edisp(m_obs, m_apply_edisp);
  222 +
  223 + // Write input observation container into logger
  224 + log_observations(NORMAL, m_obs, "Input observation");
  225 +
  226 + // Write header into logger
  227 + log_header1(TERSE, "Compute event probabilities");
  228 +
  229 + // Initialise counters
  230 + int n_observations = 0;
  231 +
  232 + // Loop over all unbinned CTA observations in the container
  233 + for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL;
  234 + obs = next_unbinned_observation()) {
  235 +
  236 + // Increment counter
  237 + n_observations++;
  238 +
  239 + // Evaluate event probabilities
  240 + evaluate_probability(obs);
  241 +
  242 + } // endfor: looped over observations
  243 +
  244 + // If more than a single observation has been handled then make sure that
  245 + // an XML file will be used for storage
  246 + if (n_observations > 1) {
  247 + m_use_xml = true;
  248 + }
  249 +
  250 + // Write observation(s) into logger
  251 + log_observations(NORMAL, m_obs, "Output observation");
  252 +
  253 + // Restore energy dispersion flags of all CTA observations
  254 + restore_edisp(m_obs, save_edisp);
  255 +
  256 + // Optionally publish event list(s)
  257 + if ((*this)["publish"].boolean()) {
  258 + publish();
  259 + }
  260 +
  261 + // Return
  262 + return;
  263 +}
  264 +
  265 +
  266 +/***********************************************************************//**
  267 + * @brief Save the selected event list(s)
  268 + *
  269 + * This method saves the selected event list(s) into FITS file(s). There are
  270 + * two modes, depending on the m_use_xml flag.
  271 + *
  272 + * If m_use_xml is true, all selected event list(s) will be saved into FITS
  273 + * files, where the output filenames are constructued from the input
  274 + * filenames by prepending the m_prefix string to name. Any path information
  275 + * will be stripped form the input name, hence event files will be written
  276 + * into the local working directory (unless some path information is present
  277 + * in the prefix). In addition, an XML file will be created that gathers
  278 + * the filename information for the selected event list(s). If an XML file
  279 + * was present on input, all metadata information will be copied from this
  280 + * input file.
  281 + *
  282 + * If m_use_xml is false, the selected event list will be saved into a FITS
  283 + * file.
  284 + ***************************************************************************/
  285 +void ctprob::save(void)
  286 +{
  287 + // Write header into logger
  288 + log_header1(TERSE, gammalib::number("Save event list", m_obs.size()));
  289 +
  290 + // Case A: Save event file(s) and XML metadata information
  291 + if (m_use_xml) {
  292 + save_xml();
  293 + }
  294 +
  295 + // Case B: Save event file as FITS file
  296 + else {
  297 + save_fits();
  298 + }
  299 +
  300 + // Return
  301 + return;
  302 +}
  303 +
  304 +
  305 +/***********************************************************************//**
  306 + * @brief Publish event lists
  307 + *
  308 + * @param[in] name Event list name.
  309 + ***************************************************************************/
  310 +void ctprob::publish(const std::string& name)
  311 +{
  312 + // Write header into logger
  313 + log_header1(TERSE, gammalib::number("Publish event list", m_obs.size()));
  314 +
  315 + // Loop over all observation in the container
  316 + for (int i = 0; i < m_obs.size(); ++i) {
  317 +
  318 + // Get CTA observation
  319 + GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
  320 +
  321 + // Handle only CTA observations
  322 + if (obs != NULL) {
  323 +
  324 + // Continue only if there is an event list
  325 + if (obs->events()->size() != 0) {
  326 +
  327 + // Set default name if user name is empty
  328 + std::string user_name(name);
  329 + if (user_name.empty()) {
  330 + user_name = CTPROB_NAME;
  331 + }
  332 +
  333 + // If there are several event lists then add an index
  334 + if (m_use_xml) {
  335 + user_name += gammalib::str(i);
  336 + }
  337 +
  338 + // Write event list name into logger
  339 + log_value(NORMAL, "Event list name", user_name);
  340 +
  341 + // Write events into in-memory FITS file
  342 + GFits fits;
  343 + obs->write(fits);
  344 +
  345 + // Publish
  346 + fits.publish(gammalib::extname_cta_events, user_name);
  347 +
  348 + } // endif: there were events
  349 +
  350 + } // endif: observation was a CTA observation
  351 +
  352 + } // endfor: looped over observations
  353 +
  354 + // Return
  355 + return;
  356 +}
  357 +
  358 +
  359 +/*==========================================================================
  360 + = =
  361 + = Private methods =
  362 + = =
  363 + ==========================================================================*/
  364 +
  365 +/***********************************************************************//**
  366 + * @brief Initialise class members
  367 + ***************************************************************************/
  368 +void ctprob::init_members(void)
  369 +{
  370 + // Initialise parameters
  371 + m_outobs.clear();
  372 + m_prefix.clear();
  373 + m_chatter = static_cast<GChatter>(2);
  374 +
  375 + // Initialise protected members
  376 + m_infiles.clear();
  377 + m_evtname.clear();
  378 + m_gtiname.clear();
  379 +
  380 + // Return
  381 + return;
  382 +}
  383 +
  384 +
  385 +/***********************************************************************//**
  386 + * @brief Copy class members
  387 + *
  388 + * @param[in] app Application.
  389 + ***************************************************************************/
  390 +void ctprob::copy_members(const ctprob& app)
  391 +{
  392 + // Copy parameters
  393 + m_outobs = app.m_outobs;
  394 + m_prefix = app.m_prefix;
  395 + m_chatter = app.m_chatter;
  396 +
  397 + // Copy protected members
  398 + m_infiles = app.m_infiles;
  399 + m_evtname = app.m_evtname;
  400 + m_gtiname = app.m_gtiname;
  401 +
  402 + // Return
  403 + return;
  404 +}
  405 +
  406 +
  407 +/***********************************************************************//**
  408 + * @brief Delete class members
  409 + ***************************************************************************/
  410 +void ctprob::free_members(void)
  411 +{
  412 + // Return
  413 + return;
  414 +}
  415 +
  416 +
  417 +/***********************************************************************//**
  418 + * @brief Get application parameters
  419 + *
  420 + * Get all user parameters from parameter file or (if required) by querying
  421 + * the user. Times are assumed to be in the native CTA MJD format.
  422 + *
  423 + * This method also loads observations if no observations are yet allocated.
  424 + * Observations are either loaded from a single CTA even list, or from a
  425 + * XML file using the metadata information that is stored in that file.
  426 + ***************************************************************************/
  427 +void ctprob::get_parameters(void)
  428 +{
  429 + // Setup observations from "inobs" parameter. Do not request response
  430 + // information and do not accept counts cubes.
  431 + if (m_obs.size() == 0) {
  432 + get_obs();
  433 + }
  434 + // ... otherwise add response information and energy boundaries in case
  435 + // that they are missing
  436 + else {
  437 + setup_observations(m_obs);
  438 + }
  439 +
  440 + // Read model definition file if required
  441 + if (m_obs.models().size() == 0) {
  442 +
  443 + // Get model filename
  444 + std::string inmodel = (*this)["inmodel"].filename();
  445 +
  446 + // Load models from file
  447 + m_obs.models(inmodel);
  448 +
  449 + } // endif: there were no models
  450 +
  451 + // Get energy dispersion flag parameters
  452 + m_apply_edisp = (*this)["edisp"].boolean();
  453 +
  454 +
  455 + // Get remaining parameters
  456 + m_publish = (*this)["publish"].boolean();
  457 + m_chatter = static_cast<GChatter>((*this)["chatter"].integer());
  458 +
  459 + // Optionally read ahead parameters so that they get correctly
  460 + // dumped into the log file
  461 + if (read_ahead()) {
  462 + m_outobs = (*this)["outobs"].filename();
  463 + m_prefix = (*this)["prefix"].string();
  464 + }
  465 +
  466 + // Write parameters into logger
  467 + log_parameters(TERSE);
  468 +
  469 + // Return
  470 + return;
  471 +}
  472 +
  473 +
  474 +/***********************************************************************//**
  475 + * @brief Get observation container
  476 + *
  477 + * @exception GException::invalid_value
  478 + * Invalid FITS file.
  479 + *
  480 + * Get an observation container according to the user parameters. The method
  481 + * supports loading of a individual FITS file or an observation definition
  482 + * file in XML format.
  483 + ***************************************************************************/
  484 +void ctprob::get_obs(void)
  485 +{
  486 + // Get the filename from the input parameters
  487 + std::string filename = (*this)["inobs"].filename();
  488 +
  489 + // If no observation definition file throw an exception
  490 + if (!is_valid_filename(filename)) {
  491 + throw GException::invalid_value(G_GET_OBS, "Input event list is not valid.");
  492 + } // endif: filename was not valid
  493 +
  494 + // ... otherwise we have a file name
  495 + else {
  496 +
  497 + // If file is a FITS file then create an empty CTA observation
  498 + // and load file into observation
  499 + if (GFilename(filename).is_fits()) {
  500 +
  501 + // Allocate empty CTA observation
  502 + GCTAObservation cta;
  503 +
  504 + // Load data
  505 + cta.load(filename);
  506 +
  507 + // Set response
  508 + set_obs_response(&cta);
  509 +
  510 + // Append observation to container
  511 + m_obs.append(cta);
  512 +
  513 + // Signal that no XML file should be used for storage
  514 + m_use_xml = false;
  515 +
  516 + }
  517 +
  518 + // ... otherwise load file into observation container
  519 + else {
  520 +
  521 + // Load observations from XML file
  522 + m_obs.load(filename);
  523 +
  524 + // For all observations that have no response, set the response
  525 + // from the task parameters
  526 + set_response(m_obs);
  527 +
  528 + // Set observation boundary parameters (emin, emax, rad)
  529 + set_obs_bounds(m_obs);
  530 +
  531 + // Signal that XML file should be used for storage
  532 + m_use_xml = true;
  533 +
  534 + } // endelse: file was an XML file
  535 +
  536 + }
  537 +
  538 + // Return
  539 + return;
  540 +
  541 +}
  542 +
  543 +
  544 +
  545 +/***********************************************************************//**
  546 + * @brief Evaluate probability for events
  547 + *
  548 + * @param[in,out] obs CTA observation.
  549 + *
  550 + * @exception GException::invalid_value
  551 + * Observation does not contain an event list.
  552 + *
  553 + * Computes for all events the probability that an event arises from a
  554 + * specific model component. The computation is done by by evaluating the
  555 + * differential event probability for a given model and normalizing these
  556 + * probabilities so that the sum of the probabilities for all model
  557 + * components is unity for each event.
  558 + *
  559 + * The method appends for each model component a single precision column to
  560 + * the event list that contains the event probabilities. The name of the
  561 + * column is build from the model name prefixed with `PROB_`.
  562 + ***************************************************************************/
  563 +void ctprob::evaluate_probability(GCTAObservation* obs)
  564 +{
  565 + // Write header into logger
  566 + log_header3(NORMAL, "Evaluate events probabilities");
  567 +
  568 + // Make sure that the observation holds a CTA event list. If this
  569 + // is not the case then throw an exception.
  570 + GCTAEventList* events = dynamic_cast<GCTAEventList*>(const_cast<GEvents*>
  571 + (obs->events()));
  572 + if (events == NULL) {
  573 + std::string msg = "CTA Observation does not contain an event list. An "
  574 + "event list is needed to compute the event "
  575 + "probabilities.";
  576 + throw GException::invalid_value(G_EVALUATE_PROB, msg);
  577 + }
  578 +
  579 + // Continue only if there are model components
  580 + int nmodels = m_obs.models().size();
  581 + if (nmodels > 0) {
  582 +
  583 + // Allocate single precision FITS table columns for all model components
  584 + std::vector<GFitsTableFloatCol*> columns;
  585 + for (int k = 0; k < nmodels; ++k) {
  586 + const std::string colname = "PROB_" + m_obs.models()[k] ->name();
  587 + GFitsTableFloatCol* col =
  588 + new GFitsTableFloatCol(colname, events->size());
  589 + columns.push_back(col);
  590 + }
  591 +
  592 + // Loop over all events in the event list
  593 + for (int i = 0; i < events->size(); ++i) {
  594 +
  595 + // Initialise total probability
  596 + double total = 0.0;
  597 +
  598 + // Get point to event
  599 + const GEvent* event = (*events)[i];
  600 +
  601 + // Initialise probability vector
  602 + std::vector<double> probabilities(nmodels, 0.0);
  603 +
  604 + // Loop over models
  605 + for (int k = 0; k < nmodels; ++k) {
  606 + double value = m_obs.models()[k]->eval(*event, *obs);
  607 + probabilities[k] = value;
  608 + total += value;
  609 + }
  610 +
  611 + // Normalize probabilities to unity
  612 + if (total > 0.0) {
  613 + for (int k = 0; k < nmodels; ++k) {
  614 + probabilities[k] /= total;
  615 + }
  616 + }
  617 +
  618 + // Store probabilities in FITS columns
  619 + for (int k = 0; k < nmodels; ++k) {
  620 + (*(columns[k]))(i) = probabilities[k];
  621 + }
  622 +
  623 + } // endfor: looped over all events
  624 +
  625 + // Append columns to event list
  626 + for (int k = 0; k < nmodels; ++k) {
  627 + events->append_column(*columns[k]);
  628 + }
  629 +
  630 + } // endif: there were model components
  631 +
  632 + // Return
  633 + return;
  634 +}
  635 +
  636 +
  637 +/***********************************************************************//**
  638 + * @brief Set output file name.
  639 + *
  640 + * @param[in] filename Input file name.
  641 + *
  642 + * Converts an input file name into an output filename by prepending the
  643 + * prefix stored in the member m_prefix to the input file name. Any path as
  644 + * well as extension will be stripped from the input file name. Also a
  645 + * trailing ".gz" will be stripped as one cannot write into gzipped files.
  646 + ***************************************************************************/
  647 +std::string ctprob::set_outfile_name(const std::string& filename) const
  648 +{
  649 + // Create filename
  650 + GFilename fname(filename);
  651 +
  652 + // Split input filename without any extensions into path elements
  653 + std::vector<std::string> elements = gammalib::split(fname.url(), "/");
  654 +
  655 + // The last path element is the filename
  656 + std::string outname = m_prefix + elements[elements.size()-1];
  657 +
  658 + // Strip any ".gz"
  659 + outname = gammalib::strip_chars(outname, ".gz");
  660 +
  661 + // Return output filename
  662 + return outname;
  663 +}
  664 +
  665 +
  666 +/***********************************************************************//**
  667 + * @brief Save event list in FITS format.
  668 + *
  669 + * Save the event list as a FITS file. The file name of the FITS file is
  670 + * specified by the `outobs` parameter.
  671 + ***************************************************************************/
  672 +void ctprob::save_fits(void)
  673 +{
  674 + // Save only if there are observations
  675 + if (m_obs.size() > 0) {
  676 +
  677 + // Get output filename
  678 + m_outobs = (*this)["outobs"].filename();
  679 +
  680 + // Loop over all unbinned CTA observations in the container
  681 + for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL;
  682 + obs = next_unbinned_observation()) {
  683 +
  684 + // Get input file name and default extension names
  685 + std::string infile = obs->eventfile();
  686 + std::string evtname = gammalib::extname_cta_events;
  687 + std::string gtiname = gammalib::extname_gti;
  688 +
  689 + // Create file name object
  690 + GFilename fname(m_outobs);
  691 +
  692 + // Extract filename and event extension name
  693 + std::string outfile = fname.url();
  694 +
  695 + // Append event extension name. We handle here the possibility
  696 + // to write the events into a different extension.
  697 + if (fname.has_extname()) {
  698 + outfile += "["+fname.extname()+"]";
  699 + }
  700 + else {
  701 + outfile += "["+gammalib::extname_cta_events+"]";
  702 + }
  703 +
  704 + // Log filename
  705 + log_value(NORMAL, "Event list file", outfile);
  706 +
  707 + // Save event list
  708 + save_event_list(obs, infile, evtname, gtiname, outfile);
  709 +
  710 + // Exit the loop (if this method is called we should only
  711 + // have a single unbinned observation in the observation
  712 + // container
  713 + break;
  714 +
  715 + } // endfor: looped over all unbinned observations
  716 +
  717 + } // endif: there were observations
  718 +
  719 + // Return
  720 + return;
  721 +}
  722 +
  723 +
  724 +/***********************************************************************//**
  725 + * @brief Save event list(s) in XML format.
  726 + *
  727 + * Save the event list(s) into FITS files and write the file path information
  728 + * into a XML file. The filename of the XML file is specified by the `outobs`
  729 + * parameter, the filename(s) of the event lists are built by prepending a
  730 + * prefix to the input event list filenames. Any path present in the input
  731 + * filename will be stripped, i.e. the event list(s) will be written in the
  732 + * local working directory (unless a path is specified in the prefix).
  733 + ***************************************************************************/
  734 +void ctprob::save_xml(void)
  735 +{
  736 + // Get output filename and prefix
  737 + m_outobs = (*this)["outobs"].filename();
  738 + m_prefix = (*this)["prefix"].string();
  739 +
  740 + // Issue warning if output filename has no .xml suffix
  741 + log_string(TERSE, warn_xml_suffix(m_outobs));
  742 +
  743 + // Loop over all unbinned CTA observations in the container
  744 + for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL;
  745 + obs = next_unbinned_observation()) {
  746 +
  747 + // Get input file name and default extension names
  748 + std::string infile = obs->eventfile();
  749 + std::string evtname = gammalib::extname_cta_events;
  750 + std::string gtiname = gammalib::extname_gti;
  751 +
  752 + // Extract event and GTI extension names from input FITS file
  753 + GFilename fname(infile);
  754 + if (fname.has_extname()) {
  755 + evtname = fname.extname();
  756 + }
  757 + gtiname = get_gtiname(fname.url(), evtname);
  758 +
  759 + // Set event output file name
  760 + std::string outfile = set_outfile_name(infile);
  761 +
  762 + // Append event extension name
  763 + outfile += "["+evtname+"]";
  764 +
  765 + // Log filename
  766 + log_value(NORMAL, "Event list file", outfile);
  767 +
  768 + // Store output file name in observation
  769 + obs->eventfile(outfile);
  770 +
  771 + // Save event list
  772 + save_event_list(obs, infile, evtname, gtiname, outfile);
  773 +
  774 + } // endfor: looped over observations
  775 +
  776 + // Write observation definition XML file name into logger
  777 + log_value(NORMAL, "Obs. definition file", m_outobs);
  778 +
  779 + // Save observations in XML file
  780 + m_obs.save(m_outobs);
  781 +
  782 + // Return
  783 + return;
  784 +}
... ...
src/ctprob/ctprob.hpp 0 → 100644
  1 +/***************************************************************************
  2 + * ctprob - Computes event probability for a given model *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2017 by Leonardo Di Venere *
  5 + * ----------------------------------------------------------------------- *
  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 +/**
  22 + * @file ctprob.hpp
  23 + * @brief Computes event probability for a given model
  24 + * @author Leonardo Di Venere
  25 + */
  26 +
  27 +#ifndef CTPROB_HPP
  28 +#define CTPROB_HPP
  29 +
  30 +/* __ Includes ___________________________________________________________ */
  31 +#include <vector>
  32 +#include <string>
  33 +#include "GammaLib.hpp"
  34 +#include "GCTALib.hpp"
  35 +#include "ctobservation.hpp"
  36 +
  37 +/* __Definitions _________________________________________________________ */
  38 +#define CTPROB_NAME "ctprob"
  39 +
  40 +
  41 +/***********************************************************************//**
  42 + * @class ctprob
  43 + *
  44 + * @brief Data selection tool
  45 + ***************************************************************************/
  46 +class ctprob : public ctobservation {
  47 +
  48 +public:
  49 + // Constructors and destructors
  50 + ctprob(void);
  51 + explicit ctprob(const GObservations& obs);
  52 + ctprob(int argc, char *argv[]);
  53 + ctprob(const ctprob& app);
  54 + virtual ~ctprob(void);
  55 +
  56 + // Operators
  57 + ctprob& operator=(const ctprob& app);
  58 +
  59 + // Methods
  60 + void clear(void);
  61 + void run(void);
  62 + void save(void);
  63 + void publish(const std::string& name = "");
  64 +
  65 +protected:
  66 + // Protected methods
  67 + void init_members(void);
  68 + void copy_members(const ctprob& app);
  69 + void free_members(void);
  70 + void get_parameters(void);
  71 + void get_obs(void);
  72 + void evaluate_probability(GCTAObservation* obs);
  73 + std::string set_outfile_name(const std::string& filename) const;
  74 + void save_fits(void);
  75 + void save_xml(void);
  76 +
  77 + // User parameters
  78 + std::string m_outobs; //!< Output event list or XML file
  79 + std::string m_prefix; //!< Prefix for multiple event lists
  80 + bool m_apply_edisp; //!< Apply energy dispersion?
  81 + bool m_publish; //!< Publish event list?
  82 + GChatter m_chatter; //!< Chattiness
  83 +
  84 + // Protected members
  85 + std::vector<std::string> m_infiles; //!< Input event filenames
  86 + std::vector<std::string> m_evtname; //!< Event extension names
  87 + std::vector<std::string> m_gtiname; //!< GTI extension names
  88 +};
  89 +
  90 +#endif /* CTPROB_HPP */
... ...
src/ctprob/ctprob.par 0 → 100644
  1 +#############################################################################
  2 +# #
  3 +# CTA Science Analysis Tools #
  4 +# #
  5 +# ------------------------------------------------------------------------- #
  6 +# #
  7 +# File: ctprob.par #
  8 +# #
  9 +# Author: Leonardo Di Venere #
  10 +# leonardo.divenere@ba.infn.it #
  11 +# INFN #
  12 +# #
  13 +# Purpose: Parameter file for the ctprob application #
  14 +# #
  15 +#############################################################################
  16 +#
  17 +# General parameters
  18 +#===================
  19 +inobs, f, a, "events.fits",,, "Input event list or observation definition XML file"
  20 +outobs, f, a, "prob_events.fits",,, "Output event list or observation definition XML file"
  21 +prefix, s, h, "prob_",,, "Prefix for event lists in observation definition XML file"
  22 +inmodel, f, a, "$CTOOLS/share/models/crab.xml",,, "Input model definition XML file"
  23 +caldb, s, a, "prod2",,, "Calibration database"
  24 +irf, s, a, "South_0.5h",,, "Instrument response function"
  25 +edisp, b, h, no,,, "Apply energy dispersion?"
  26 +
  27 +#
  28 +# Standard parameters
  29 +#====================
  30 +publish, b, h, no,,, "Publish event list on VO Hub?"
  31 +chatter, i, h, 2,0,4, "Chattiness of output"
  32 +clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
  33 +debug, b, h, no,,, "Debugging mode activated"
  34 +mode, s, h, "ql",,, "Mode of automatic parameters"
  35 +logfile, f, h, "ctprob.log",,, "Log filename"
... ...
src/ctprob/main.cpp 0 → 100644
  1 +/***************************************************************************
  2 + * ctprob - Computes event probability for a given model *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2017 by Leonardo Di Venere *
  5 + * ----------------------------------------------------------------------- *
  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 +/**
  22 + * @file main.cpp
  23 + * @brief Computes event probability for a given model
  24 + * @author Leonardo Di Venere
  25 + */
  26 +
  27 +/* __ Includes ___________________________________________________________ */
  28 +#ifdef HAVE_CONFIG_H
  29 +#include <config.h>
  30 +#endif
  31 +#include "support.hpp"
  32 +#include "ctprob.hpp"
  33 +
  34 +
  35 +/***********************************************************************//**
  36 + * @brief Main entry point of application
  37 + *
  38 + * @param[in] argc Number of command line arguments.
  39 + * @param[in] argv Command line arguments.
  40 + *
  41 + * This is the main entry point of the ctprob application. It allocates a
  42 + * ctprob object and executes the application. Any exceptions that occur
  43 + * will be catched and corresponding error messages written in the
  44 + * application logger and into the standard output.
  45 + ***************************************************************************/
  46 +int main (int argc, char *argv[])
  47 +{
  48 + // Initialise return code
  49 + int rc = 1;
  50 +
  51 + // Initialise pointer on application
  52 + ctprob* application = NULL;
  53 +
  54 + // Execute application
  55 + try {
  56 +
  57 + // Create instance of application
  58 + application = new ctprob(argc, argv);
  59 +
  60 + // Execute ctool
  61 + rc = execute_ctool(application);
  62 +
  63 + }
  64 +
  65 + catch (std::exception &e) {
  66 +
  67 + // Report exception
  68 + report_ctool_failure("ctprob", e.what());
  69 +
  70 + }
  71 +
  72 + // Delete application
  73 + delete application;
  74 +
  75 + // Return
  76 + return rc;
  77 +}
... ...
src/ctpsfcube/ctpsfcube.cpp
... ... @@ -49,7 +49,7 @@
49 49 /***********************************************************************//**
50 50 * @brief Void constructor
51 51 ***************************************************************************/
52   -ctpsfcube::ctpsfcube(void) : ctobservation(CTPSFCUBE_NAME, CTPSFCUBE_VERSION)
  52 +ctpsfcube::ctpsfcube(void) : ctobservation(CTPSFCUBE_NAME, VERSION)
53 53 {
54 54 // Initialise members
55 55 init_members();
... ... @@ -68,7 +68,7 @@ ctpsfcube::ctpsfcube(void) : ctobservation(CTPSFCUBE_NAME, CTPSFCUBE_VERSION)
68 68 * observations container.
69 69 ***************************************************************************/
70 70 ctpsfcube::ctpsfcube(const GObservations& obs) :
71   - ctobservation(CTPSFCUBE_NAME, CTPSFCUBE_VERSION, obs)
  71 + ctobservation(CTPSFCUBE_NAME, VERSION, obs)
72 72 {
73 73 // Initialise members
74 74 init_members();
... ... @@ -86,7 +86,7 @@ ctpsfcube::ctpsfcube(const GObservations&amp; obs) :
86 86 * @param[in] argv Array of command line arguments.
87 87 ***************************************************************************/
88 88 ctpsfcube::ctpsfcube(int argc, char *argv[]) :
89   - ctobservation(CTPSFCUBE_NAME, CTPSFCUBE_VERSION, argc, argv)
  89 + ctobservation(CTPSFCUBE_NAME, VERSION, argc, argv)
90 90 {
91 91 // Initialise members
92 92 init_members();
... ...
src/ctpsfcube/ctpsfcube.hpp
... ... @@ -33,8 +33,7 @@
33 33 #include "ctobservation.hpp"
34 34  
35 35 /* __Definitions _________________________________________________________ */
36   -#define CTPSFCUBE_NAME "ctpsfcube"
37   -#define CTPSFCUBE_VERSION "1.1.0"
  36 +#define CTPSFCUBE_NAME "ctpsfcube"
38 37  
39 38  
40 39 /***********************************************************************//**
... ...
src/ctselect/ctselect.cpp
... ... @@ -53,7 +53,7 @@
53 53 /***********************************************************************//**
54 54 * @brief Void constructor
55 55 ***************************************************************************/
56   -ctselect::ctselect(void) : ctobservation(CTSELECT_NAME, CTSELECT_VERSION)
  56 +ctselect::ctselect(void) : ctobservation(CTSELECT_NAME, VERSION)
57 57 {
58 58 // Initialise members
59 59 init_members();
... ... @@ -72,7 +72,7 @@ ctselect::ctselect(void) : ctobservation(CTSELECT_NAME, CTSELECT_VERSION)
72 72 * provided in an observation container.
73 73 ***************************************************************************/
74 74 ctselect::ctselect(const GObservations& obs) :
75   - ctobservation(CTSELECT_NAME, CTSELECT_VERSION, obs)
  75 + ctobservation(CTSELECT_NAME, VERSION, obs)
76 76 {
77 77 // Initialise members
78 78 init_members();
... ... @@ -91,7 +91,7 @@ ctselect::ctselect(const GObservations&amp; obs) :
91 91 * @param[in] argv Array of command line arguments.
92 92 ***************************************************************************/
93 93 ctselect::ctselect(int argc, char *argv[]) :
94   - ctobservation(CTSELECT_NAME, CTSELECT_VERSION, argc, argv)
  94 + ctobservation(CTSELECT_NAME, VERSION, argc, argv)
95 95 {
96 96 // Initialise members
97 97 init_members();
... ... @@ -1175,39 +1175,6 @@ std::string ctselect::set_outfile_name(const std::string&amp; filename) const
1175 1175  
1176 1176  
1177 1177 /***********************************************************************//**
1178   - * @brief Get Good Time Intervals extension name
1179   - *
1180   - * @param[in] filename Input file name.
1181   - * @param[in] evtname Events extension name.
1182   - *
1183   - * Extracts the Good Time Intervals extension name from the event file. We
1184   - * do this by loading the events and accessing the Good Time Intervals
1185   - * extension name using the GCTAEventList::gtiname() method. If the file name
1186   - * is empty, the method returns `GTI`.
1187   - ***************************************************************************/
1188   -std::string ctselect::get_gtiname(const std::string& filename,
1189   - const std::string& evtname) const
1190   -{
1191   - // Initialise GTI name
1192   - std::string gtiname = gammalib::extname_gti;
1193   -
1194   - // Continue only if the filename is not empty
1195   - if (!filename.empty()) {
1196   -
1197   - // Load events
1198   - GCTAEventList events(filename+"["+evtname+"]");
1199   -
1200   - // Get GTI name
1201   - gtiname = events.gtiname();
1202   -
1203   - }
1204   -
1205   - // Return GTI name
1206   - return (gtiname);
1207   -}
1208   -
1209   -
1210   -/***********************************************************************//**
1211 1178 * @brief Save event list in FITS format.
1212 1179 *
1213 1180 * Save the event list as a FITS file. The file name of the FITS file is
... ... @@ -1325,109 +1292,3 @@ void ctselect::save_xml(void)
1325 1292 // Return
1326 1293 return;
1327 1294 }
1328   -
1329   -
1330   -/***********************************************************************//**
1331   - * @brief Save event list into FITS file
1332   - *
1333   - * @param[in] obs Pointer to CTA observation.
1334   - * @param[in] infile Input file name.
1335   - * @param[in] evtname Event extension name.
1336   - * @param[in] gtiname GTI extension name.
1337   - * @param[in] outfile Output file name.
1338   - *
1339   - * Saves an event list and the corresponding Good Time Intervals into a FITS
1340   - * file and copy all others extensions from the input file to the output
1341   - * file.
1342   - *
1343   - * If an extension name is specified in the @p outfile argument, the events
1344   - * and eventually also the Good Time Intervals will be extracted from the
1345   - * argument and used for writing the events. The format is
1346   - *
1347   - * <filename>[<event extension name;GTI extension name>]
1348   - *
1349   - * where <filename> needs to be replaced by the name of the FITS file,
1350   - * and <event extension name;GTI extension name> by the name of the events
1351   - * and Good Time Intervals extensions. For example
1352   - *
1353   - * myfits.fits[EVENTS1;GTI1]
1354   - *
1355   - * will write the selected events into the "EVENTS1" extension and the
1356   - * Good Time Intervals into the "GTI1" extension of the "myfits.fits" FITS
1357   - * file. If the Good Time Intervals extension name is skipped, e.g.
1358   - *
1359   - * myfits.fits[EVENTS1]
1360   - *
1361   - * the original extension name for the Good Time Intervals will be kept.
1362   - * Analogously, only the Good Time Intervals extension name can be changed
1363   - * by specifying
1364   - *
1365   - * myfits.fits[;GTI1]
1366   - *
1367   - * In none of the cases will the original events and Good Time Intervals be
1368   - * copied over to the output file.
1369   - ***************************************************************************/
1370   -void ctselect::save_event_list(const GCTAObservation* obs,
1371   - const std::string& infile,
1372   - const std::string& evtname,
1373   - const std::string& gtiname,
1374   - const std::string& outfile) const
1375   -{
1376   - // Save only if we have an event list
1377   - if (obs->eventtype() == "EventList") {
1378   -
1379   - // Set output FITS file event extension names
1380   - GFilename outname(outfile);
1381   - std::string outevt = evtname;
1382   - std::string outgti = gtiname;
1383   - if (outname.has_extname()) {
1384   - std::vector<std::string> extnames =
1385   - gammalib::split(outname.extname(), ";");
1386   - if (extnames.size() > 0) {
1387   - std::string extname = gammalib::strip_whitespace(extnames[0]);
1388   - if (!extname.empty()) {
1389   - outevt = extname;
1390   - }
1391   - }
1392   - if (extnames.size() > 1) {
1393   - std::string extname = gammalib::strip_whitespace(extnames[1]);
1394   - if (!extname.empty()) {
1395   - outgti = extname;
1396   - }
1397   - }
1398   - }
1399   -
1400   - // Create output FITS file
1401   - GFits outfits;
1402   -
1403   - // Write observation into FITS file
1404   - obs->write(outfits, outevt, outgti);
1405   -
1406   - // Copy all extensions other than evtname and gtiname extensions
1407   - // from the input to the output event list. The evtname and
1408   - // gtiname extensions are written by the save method, all others
1409   - // that may eventually be present have to be copied over
1410   - // explicitly.
1411   - GFits infits(infile);
1412   - for (int extno = 1; extno < infits.size(); ++extno) {
1413   - GFitsHDU* hdu = infits.at(extno);
1414   - if (hdu->extname() != evtname &&
1415   - hdu->extname() != gtiname &&
1416   - hdu->extname() != outevt &&
1417   - hdu->extname() != outgti) {
1418   - outfits.append(*hdu);
1419   - }
1420   - }
1421   -
1422   - // Close input file
1423   - infits.close();
1424   -
1425   - // Save file to disk and close it (we need both operations)
1426   - outfits.saveto(outname.url(), clobber());
1427   - outfits.close();
1428   -
1429   - } // endif: observation was unbinned
1430   -
1431   - // Return
1432   - return;
1433   -}
... ...
src/ctselect/ctselect.hpp
1 1 /***************************************************************************
2 2 * ctselect - Data selection tool *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2010-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2010-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -35,8 +35,7 @@
35 35 #include "ctobservation.hpp"
36 36  
37 37 /* __Definitions _________________________________________________________ */
38   -#define CTSELECT_NAME "ctselect"
39   -#define CTSELECT_VERSION "1.2.0"
  38 +#define CTSELECT_NAME "ctselect"
40 39  
41 40  
42 41 /***********************************************************************//**
... ... @@ -78,15 +77,8 @@ protected:
78 77 std::string check_infile(const std::string& filename,
79 78 const std::string& evtname) const;
80 79 std::string set_outfile_name(const std::string& filename) const;
81   - std::string get_gtiname(const std::string& filename,
82   - const std::string& evtname) const;
83 80 void save_fits(void);
84 81 void save_xml(void);
85   - void save_event_list(const GCTAObservation* obs,
86   - const std::string& infile,
87   - const std::string& evtname,
88   - const std::string& gtiname,
89   - const std::string& outfile) const;
90 82  
91 83 // User parameters
92 84 std::string m_outobs; //!< Output event list or XML file
... ...
src/ctskymap/ctskymap.cpp
... ... @@ -52,7 +52,7 @@
52 52 *
53 53 * Constructs an empty sky mapping tool.
54 54 ***************************************************************************/
55   -ctskymap::ctskymap(void) : ctobservation(CTSKYMAP_NAME, CTSKYMAP_VERSION)
  55 +ctskymap::ctskymap(void) : ctobservation(CTSKYMAP_NAME, VERSION)
56 56 {
57 57 // Initialise members
58 58 init_members();
... ... @@ -70,7 +70,7 @@ ctskymap::ctskymap(void) : ctobservation(CTSKYMAP_NAME, CTSKYMAP_VERSION)
70 70 * Constructs sky mapping tool from an observation container.
71 71 ***************************************************************************/
72 72 ctskymap::ctskymap(const GObservations& obs) :
73   - ctobservation(CTSKYMAP_NAME, CTSKYMAP_VERSION, obs)
  73 + ctobservation(CTSKYMAP_NAME, VERSION, obs)
74 74 {
75 75 // Initialise members
76 76 init_members();
... ... @@ -91,7 +91,7 @@ ctskymap::ctskymap(const GObservations&amp; obs) :
91 91 * parameter setting.
92 92 ***************************************************************************/
93 93 ctskymap::ctskymap(int argc, char *argv[]) :
94   - ctobservation(CTSKYMAP_NAME, CTSKYMAP_VERSION, argc, argv)
  94 + ctobservation(CTSKYMAP_NAME, VERSION, argc, argv)
95 95 {
96 96 // Initialise members
97 97 init_members();
... ...
src/ctskymap/ctskymap.hpp
... ... @@ -32,8 +32,7 @@
32 32 #include "ctobservation.hpp"
33 33  
34 34 /* __Definitions _________________________________________________________ */
35   -#define CTSKYMAP_NAME "ctskymap"
36   -#define CTSKYMAP_VERSION "1.3.0"
  35 +#define CTSKYMAP_NAME "ctskymap"
37 36  
38 37  
39 38 /***********************************************************************//**
... ...
src/cttsmap/cttsmap.cpp
... ... @@ -51,7 +51,7 @@
51 51 *
52 52 * Constructs an empty cttsmap tool.
53 53 ***************************************************************************/
54   -cttsmap::cttsmap(void) : ctlikelihood(CTTSMAP_NAME, CTTSMAP_VERSION)
  54 +cttsmap::cttsmap(void) : ctlikelihood(CTTSMAP_NAME, VERSION)
55 55 {
56 56 // Initialise members
57 57 init_members();
... ... @@ -69,7 +69,7 @@ cttsmap::cttsmap(void) : ctlikelihood(CTTSMAP_NAME, CTTSMAP_VERSION)
69 69 * Constructs cttsmap tool from an observations container.
70 70 ***************************************************************************/
71 71 cttsmap::cttsmap(const GObservations& obs) :
72   - ctlikelihood(CTTSMAP_NAME, CTTSMAP_VERSION, obs)
  72 + ctlikelihood(CTTSMAP_NAME, VERSION, obs)
73 73 {
74 74 // Initialise members
75 75 init_members();
... ... @@ -89,7 +89,7 @@ cttsmap::cttsmap(const GObservations&amp; obs) :
89 89 * that are provided as command line arguments.
90 90 ***************************************************************************/
91 91 cttsmap::cttsmap(int argc, char *argv[]) :
92   - ctlikelihood(CTTSMAP_NAME, CTTSMAP_VERSION, argc, argv)
  92 + ctlikelihood(CTTSMAP_NAME, VERSION, argc, argv)
93 93 {
94 94 // Initialise members
95 95 init_members();
... ...
src/cttsmap/cttsmap.hpp
... ... @@ -31,8 +31,7 @@
31 31 #include "ctlikelihood.hpp"
32 32  
33 33 /* __Definitions _________________________________________________________ */
34   -#define CTTSMAP_NAME "cttsmap"
35   -#define CTTSMAP_VERSION "1.2.0"
  34 +#define CTTSMAP_NAME "cttsmap"
36 35  
37 36  
38 37 /***********************************************************************//**
... ...
src/ctulimit/ctulimit.cpp
... ... @@ -53,7 +53,7 @@
53 53 *
54 54 * Constructs an empty ctulimit tool.
55 55 ***************************************************************************/
56   -ctulimit::ctulimit(void) : ctlikelihood(CTULIMIT_NAME, CTULIMIT_VERSION)
  56 +ctulimit::ctulimit(void) : ctlikelihood(CTULIMIT_NAME, VERSION)
57 57 {
58 58 // Initialise members
59 59 init_members();
... ... @@ -71,7 +71,7 @@ ctulimit::ctulimit(void) : ctlikelihood(CTULIMIT_NAME, CTULIMIT_VERSION)
71 71 * Constructs ctulimit tool from an observations container.
72 72 ***************************************************************************/
73 73 ctulimit::ctulimit(const GObservations& obs) :
74   - ctlikelihood(CTULIMIT_NAME, CTULIMIT_VERSION, obs)
  74 + ctlikelihood(CTULIMIT_NAME, VERSION, obs)
75 75 {
76 76 // Initialise members
77 77 init_members();
... ... @@ -92,7 +92,7 @@ ctulimit::ctulimit(const GObservations&amp; obs) :
92 92 * parameters that are provided as command line arguments.
93 93 ***************************************************************************/
94 94 ctulimit::ctulimit(int argc, char *argv[]) :
95   - ctlikelihood(CTULIMIT_NAME, CTULIMIT_VERSION, argc, argv)
  95 + ctlikelihood(CTULIMIT_NAME, VERSION, argc, argv)
96 96 {
97 97 // Initialise members
98 98 init_members();
... ...
src/ctulimit/ctulimit.hpp
... ... @@ -31,8 +31,7 @@
31 31 #include "ctlikelihood.hpp"
32 32  
33 33 /* __Definitions _________________________________________________________ */
34   -#define CTULIMIT_NAME "ctulimit"
35   -#define CTULIMIT_VERSION "1.2.0"
  34 +#define CTULIMIT_NAME "ctulimit"
36 35  
37 36  
38 37 /***********************************************************************//**
... ...
src/support/ctobservation.cpp
1 1 /***************************************************************************
2 2 * ctobservation - Base class for observation tools *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2016-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -326,3 +326,123 @@ const GCTAObservation* ctobservation::next_unbinned_observation(void) const
326 326 // Return next CTA observation
327 327 return obs;
328 328 }
  329 +
  330 +
  331 +/***********************************************************************//**
  332 + * @brief Save event list in FITS format.
  333 + *
  334 + * Save the event list as a FITS file. The file name of the FITS file is
  335 + * specified by the `outobs` parameter.
  336 + ***************************************************************************/
  337 +void ctobservation::save_events_fits(void)
  338 +{
  339 + // Save only if there are observations
  340 + if (m_obs.size() > 0) {
  341 +
  342 + // Get output filename
  343 + std::string outobs = (*this)["outobs"].filename();
  344 +
  345 + // Loop over all unbinned CTA observations in the container
  346 + for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL;
  347 + obs = next_unbinned_observation()) {
  348 +
  349 + // Get input file name and default extension names
  350 + std::string infile = obs->eventfile();
  351 + std::string evtname = gammalib::extname_cta_events;
  352 + std::string gtiname = gammalib::extname_gti;
  353 +
  354 + // Create file name object
  355 + GFilename fname(outobs);
  356 +
  357 + // Extract filename and event extension name
  358 + std::string outfile = fname.url();
  359 +
  360 + // Append event extension name. We handle here the possibility
  361 + // to write the events into a different extension.
  362 + if (fname.has_extname()) {
  363 + outfile += "["+fname.extname()+"]";
  364 + }
  365 + else {
  366 + outfile += "["+gammalib::extname_cta_events+"]";
  367 + }
  368 +
  369 + // Log filename
  370 + log_value(NORMAL, "Event list file", outfile);
  371 +
  372 + // Save event list
  373 + save_event_list(obs, infile, evtname, gtiname, outfile);
  374 +
  375 + // Exit the loop (if this method is called we should only
  376 + // have a single unbinned observation in the observation
  377 + // container
  378 + break;
  379 +
  380 + } // endfor: looped over all unbinned observations
  381 +
  382 + } // endif: there were observations
  383 +
  384 + // Return
  385 + return;
  386 +}
  387 +
  388 +
  389 +/***********************************************************************//**
  390 + * @brief Save event list(s) in XML format.
  391 + *
  392 + * Save the event list(s) into FITS files and write the file path information
  393 + * into a XML file. The filename of the XML file is specified by the `outobs`
  394 + * parameter, the filename(s) of the event lists are built by prepending a
  395 + * prefix to the input event list filenames. Any path present in the input
  396 + * filename will be stripped, i.e. the event list(s) will be written in the
  397 + * local working directory (unless a path is specified in the prefix).
  398 + ***************************************************************************/
  399 +void ctobservation::save_events_xml(void)
  400 +{
  401 + // Get output filename and prefix
  402 + std::string outobs = (*this)["outobs"].filename();
  403 +
  404 + // Issue warning if output filename has no .xml suffix
  405 + log_string(TERSE, warn_xml_suffix(outobs));
  406 +
  407 + // Loop over all unbinned CTA observations in the container
  408 + for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL;
  409 + obs = next_unbinned_observation()) {
  410 +
  411 + // Get input file name and default extension names
  412 + std::string infile = obs->eventfile();
  413 + std::string evtname = gammalib::extname_cta_events;
  414 + std::string gtiname = gammalib::extname_gti;
  415 +
  416 + // Extract event and GTI extension names from input FITS file
  417 + GFilename fname(infile);
  418 + if (fname.has_extname()) {
  419 + evtname = fname.extname();
  420 + }
  421 + gtiname = get_gtiname(fname.url(), evtname);
  422 +
  423 + // Set event output file name
  424 + std::string outfile = set_outfile_name(infile);
  425 +
  426 + // Append event extension name
  427 + outfile += "["+evtname+"]";
  428 +
  429 + // Log filename
  430 + log_value(NORMAL, "Event list file", outfile);
  431 +
  432 + // Store output file name in observation
  433 + obs->eventfile(outfile);
  434 +
  435 + // Save event list
  436 + save_event_list(obs, infile, evtname, gtiname, outfile);
  437 +
  438 + } // endfor: looped over observations
  439 +
  440 + // Write observation definition XML file name into logger
  441 + log_value(NORMAL, "Obs. definition file", outobs);
  442 +
  443 + // Save observations in XML file
  444 + m_obs.save(outobs);
  445 +
  446 + // Return
  447 + return;
  448 +}
... ...
src/support/ctobservation.hpp
1 1 /***************************************************************************
2 2 * ctobservation - Base class for observation tools *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2016-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -78,6 +78,8 @@ protected:
78 78 void init_members(void);
79 79 void copy_members(const ctobservation& app);
80 80 void free_members(void);
  81 + void save_events_fits(void);
  82 + void save_events_xml(void);
81 83  
82 84 // Protected members
83 85 GObservations m_obs; //!< Observation container
... ...
src/support/ctool.cpp
... ... @@ -1028,6 +1028,41 @@ GCTARoi ctool::get_roi(void)
1028 1028  
1029 1029  
1030 1030 /***********************************************************************//**
  1031 + * @brief Set output file name.
  1032 + *
  1033 + * @param[in] filename Input file name.
  1034 + *
  1035 + * Required user parameters:
  1036 + * prefix
  1037 + *
  1038 + * Converts an input file name into an output filename by prepending the
  1039 + * prefix specified by the `prefix` parameter to the input file name. Any
  1040 + * path as well as extension will be stripped from the input file name. Also
  1041 + * a trailing `.gz` will be stripped as one cannot write into gzipped files.
  1042 + ***************************************************************************/
  1043 +std::string ctool::set_outfile_name(const std::string& filename)
  1044 +{
  1045 + // Get prefix User parameter
  1046 + std::string prefix = (*this)["prefix"].string();
  1047 +
  1048 + // Create filename
  1049 + GFilename fname(filename);
  1050 +
  1051 + // Split input filename without any extensions into path elements
  1052 + std::vector<std::string> elements = gammalib::split(fname.url(), "/");
  1053 +
  1054 + // The last path element is the filename
  1055 + std::string outname = prefix + elements[elements.size()-1];
  1056 +
  1057 + // Strip any ".gz"
  1058 + outname = gammalib::strip_chars(outname, ".gz");
  1059 +
  1060 + // Return output filename
  1061 + return outname;
  1062 +}
  1063 +
  1064 +
  1065 +/***********************************************************************//**
1031 1066 * @brief Set response for all CTA observations in container
1032 1067 *
1033 1068 * @param[in,out] obs Observation container
... ... @@ -1730,6 +1765,145 @@ std::vector&lt;bool&gt; ctool::cube_layer_usage(const GEbounds&amp; cube_ebounds,
1730 1765  
1731 1766  
1732 1767 /***********************************************************************//**
  1768 + * @brief Save event list into FITS file
  1769 + *
  1770 + * @param[in] obs Pointer to CTA observation.
  1771 + * @param[in] infile Input file name.
  1772 + * @param[in] evtname Event extension name.
  1773 + * @param[in] gtiname GTI extension name.
  1774 + * @param[in] outfile Output file name.
  1775 + *
  1776 + * Saves an event list and the corresponding Good Time Intervals into a FITS
  1777 + * file and copy all others extensions from the input file to the output
  1778 + * file.
  1779 + *
  1780 + * If an extension name is specified in the @p outfile argument, the events
  1781 + * and eventually also the Good Time Intervals will be extracted from the
  1782 + * argument and used for writing the events. The format is
  1783 + *
  1784 + * <filename>[<event extension name;GTI extension name>]
  1785 + *
  1786 + * where <filename> needs to be replaced by the name of the FITS file,
  1787 + * and <event extension name;GTI extension name> by the name of the events
  1788 + * and Good Time Intervals extensions. For example
  1789 + *
  1790 + * myfits.fits[EVENTS1;GTI1]
  1791 + *
  1792 + * will write the selected events into the `EVENTS1` extension and the
  1793 + * Good Time Intervals into the `GTI1` extension of the `myfits.fits` FITS
  1794 + * file. If the Good Time Intervals extension name is skipped, e.g.
  1795 + *
  1796 + * myfits.fits[EVENTS1]
  1797 + *
  1798 + * the original extension name for the Good Time Intervals will be kept.
  1799 + * Analogously, only the Good Time Intervals extension name can be changed
  1800 + * by specifying
  1801 + *
  1802 + * myfits.fits[;GTI1]
  1803 + *
  1804 + * In none of the cases will the original events and Good Time Intervals be
  1805 + * copied over to the output file.
  1806 + ***************************************************************************/
  1807 +void ctool::save_event_list(const GCTAObservation* obs,
  1808 + const std::string& infile,
  1809 + const std::string& evtname,
  1810 + const std::string& gtiname,
  1811 + const std::string& outfile) const
  1812 +{
  1813 + // Save only if we have an event list
  1814 + if (obs->eventtype() == "EventList") {
  1815 +
  1816 + // Set output FITS file event extension names
  1817 + GFilename outname(outfile);
  1818 + std::string outevt = evtname;
  1819 + std::string outgti = gtiname;
  1820 + if (outname.has_extname()) {
  1821 + std::vector<std::string> extnames =
  1822 + gammalib::split(outname.extname(), ";");
  1823 + if (extnames.size() > 0) {
  1824 + std::string extname = gammalib::strip_whitespace(extnames[0]);
  1825 + if (!extname.empty()) {
  1826 + outevt = extname;
  1827 + }
  1828 + }
  1829 + if (extnames.size() > 1) {
  1830 + std::string extname = gammalib::strip_whitespace(extnames[1]);
  1831 + if (!extname.empty()) {
  1832 + outgti = extname;
  1833 + }
  1834 + }
  1835 + }
  1836 +
  1837 + // Create output FITS file
  1838 + GFits outfits;
  1839 +
  1840 + // Write observation into FITS file
  1841 + obs->write(outfits, outevt, outgti);
  1842 +
  1843 + // Copy all extensions other than evtname and gtiname extensions
  1844 + // from the input to the output event list. The evtname and
  1845 + // gtiname extensions are written by the save method, all others
  1846 + // that may eventually be present have to be copied over
  1847 + // explicitly.
  1848 + GFits infits(infile);
  1849 + for (int extno = 1; extno < infits.size(); ++extno) {
  1850 + GFitsHDU* hdu = infits.at(extno);
  1851 + if (hdu->extname() != evtname &&
  1852 + hdu->extname() != gtiname &&
  1853 + hdu->extname() != outevt &&
  1854 + hdu->extname() != outgti) {
  1855 + outfits.append(*hdu);
  1856 + }
  1857 + }
  1858 +
  1859 + // Close input file
  1860 + infits.close();
  1861 +
  1862 + // Save file to disk and close it (we need both operations)
  1863 + outfits.saveto(outname.url(), clobber());
  1864 + outfits.close();
  1865 +
  1866 + } // endif: observation was unbinned
  1867 +
  1868 + // Return
  1869 + return;
  1870 +}
  1871 +
  1872 +
  1873 +/***********************************************************************//**
  1874 + * @brief Get Good Time Intervals extension name
  1875 + *
  1876 + * @param[in] filename Input file name.
  1877 + * @param[in] evtname Events extension name.
  1878 + *
  1879 + * Extracts the Good Time Intervals extension name from the event file. We
  1880 + * do this by loading the events and accessing the Good Time Intervals
  1881 + * extension name using the GCTAEventList::gtiname() method. If the file name
  1882 + * is empty, the method returns `GTI`.
  1883 + ***************************************************************************/
  1884 +std::string ctool::get_gtiname(const std::string& filename,
  1885 + const std::string& evtname) const
  1886 +{
  1887 + // Initialise GTI name
  1888 + std::string gtiname = gammalib::extname_gti;
  1889 +
  1890 + // Continue only if the filename is not empty
  1891 + if (!filename.empty()) {
  1892 +
  1893 + // Load events
  1894 + GCTAEventList events(filename+"["+evtname+"]");
  1895 +
  1896 + // Get GTI name
  1897 + gtiname = events.gtiname();
  1898 +
  1899 + }
  1900 +
  1901 + // Return GTI name
  1902 + return (gtiname);
  1903 +}
  1904 +
  1905 +
  1906 +/***********************************************************************//**
1733 1907 * @brief Set warning string if there are too few energies
1734 1908 *
1735 1909 * @param[in] energies Energies.
... ...
src/support/ctool.hpp
1 1 /***************************************************************************
2 2 * ctool - ctool base class *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2014-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2014-2017 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -104,6 +104,7 @@ protected:
104 104  
105 105 // Protected methods that extract user parameters
106 106 GCTARoi get_roi(void);
  107 + std::string set_outfile_name(const std::string& filename);
107 108  
108 109 // Protected support methods
109 110 void set_response(GObservations& obs);
... ... @@ -121,6 +122,13 @@ protected:
121 122 std::vector<bool> cube_layer_usage(const GEbounds& cube_ebounds,
122 123 const GEbounds& list_ebounds) const;
123 124 bool is_valid_filename(const GFilename& filename) const;
  125 + std::string get_gtiname(const std::string& filename,
  126 + const std::string& evtname) const;
  127 + void save_event_list(const GCTAObservation* obs,
  128 + const std::string& infile,
  129 + const std::string& evtname,
  130 + const std::string& gtiname,
  131 + const std::string& outfile) const;
124 132  
125 133 // Protected warning strings
126 134 std::string warn_too_few_energies(const GEnergies& energies) const;
... ...
test/data/irf.root
No preview for this file type
test/data/model_temporal_phasecurve.fits 0 → 100644
No preview for this file type
test/data/model_temporal_phasecurve.xml 0 → 100644
  1 +<?xml version="1.0" standalone="no"?>
  2 +<source_library title="source library">
  3 + <source name="Crab" type="PointSource">
  4 + <spectrum type="PowerLaw">
  5 + <parameter name="Prefactor" scale="1e-16" value="5.7" min="1e-07" max="1000.0" free="1"/>
  6 + <parameter name="Index" scale="-1" value="2.48" min="0.0" max="+5.0" free="1"/>
  7 + <parameter name="PivotEnergy" scale="1e6" value="0.3" min="0.01" max="1000.0" free="0"/>
  8 + </spectrum>
  9 + <spatialModel type="PointSource">
  10 + <parameter free="0" max="360" min="-360" name="RA" scale="1" value="83.6331" />
  11 + <parameter free="0" max="90" min="-90" name="DEC" scale="1" value="22.0145" />
  12 + </spatialModel>
  13 + <temporal type="PhaseCurve" file="model_temporal_phasecurve.fits">
  14 + <parameter name="Normalization" scale="1" value="1.0" min="0.0" max="1000.0" free="0"/>
  15 + <parameter name="MJD" scale="1" value="51544.5" min="0.0" max="100000.0" free="0"/>
  16 + <parameter name="Phase" scale="1" value="0.0" min="0.0" max="1.0" free="0"/>
  17 + <parameter name="F0" scale="1" value="1.0" min="0.0" max="1000.0" free="0"/>
  18 + <parameter name="F1" scale="1" value="0.1" min="0.0" max="1000.0" free="0"/>
  19 + <parameter name="F2" scale="1" value="0.01" min="0.0" max="1000.0" free="0"/>
  20 + </temporal>
  21 + </source>
  22 +</source_library>
... ...
test/test_cssens.py
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # This scripts performs unit tests for the cssens script
4 4 #
5   -# Copyright (C) 2016 Juergen Knoedlseder
  5 +# Copyright (C) 2016-2017 Juergen Knoedlseder
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -168,7 +168,7 @@ class Test(test):
168 168 # Check dimensions
169 169 self.test_value(results.nrows(), 2,
170 170 'Check number of rows in sensitivity file')
171   - self.test_value(results.ncols(), 7,
  171 + self.test_value(results.ncols(), 10,
172 172 'Check number of columns in sensitivity file')
173 173  
174 174 # Return
... ...
test/test_ctbutterfly.py
... ... @@ -168,6 +168,9 @@ class Test(test):
168 168 cpy_butterfly['outfile'] = 'ctbutterfly_py3.dat'
169 169 cpy_butterfly['logfile'] = 'ctbutterfly_py3.log'
170 170 cpy_butterfly['chatter'] = 4
  171 +
  172 + # Execute ctbutterfly tool
  173 + cpy_butterfly.logFileOpen() # Make sure we get a log file
171 174 cpy_butterfly.execute()
172 175  
173 176 # Check result file
... ...
test/test_ctphase.py
1 1 #! /usr/bin/env python
2 2 # ==========================================================================
3   -# This scripts performs unit tests for the ctselect tool.
  3 +# This scripts performs unit tests for the ctphase tool.
4 4 #
5   -# Copyright (C) 2014-2016 Juergen Knoedlseder
  5 +# Copyright (C) 2017 by Joshua Cardenzana
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -40,6 +40,8 @@ class Test(test):
40 40 test.__init__(self)
41 41  
42 42 # Set test data
  43 + self._model_file = self._datadir + '/model_temporal_phasecurve.xml'
  44 + self._phase_file = self._datadir + '/model_temporal_phasecurve.fits'
43 45 self._invalid_events = self._datadir + '/invalid_event_list.fits'
44 46  
45 47 # Return
... ... @@ -70,10 +72,9 @@ class Test(test):
70 72  
71 73 # Setup ctphase command
72 74 cmd = ctphase+' inobs="'+self._events+'"'+ \
73   - ' outobs="ctphase_cmd1.fits"'+ \
74   - ' p0=0.1 mjd=51544.5'+ \
75   - ' f0=0.1 f1=0. f2=0.'+ \
76   - ' logfile="ctphase_cmd1.log" chatter=1'
  75 + ' outobs="ctphase_cmd1.fits"'+ \
  76 + ' inmodel="'+self._model_file+'" source="Crab"'+ \
  77 + ' logfile="ctphase_cmd1.log" chatter=1'
77 78  
78 79 # Check if execution of wrong command fails
79 80 self.test_assert(self._execute('command_that_does_not_exist') != 0,
... ... @@ -88,10 +89,9 @@ class Test(test):
88 89  
89 90 # Setup ctphase command
90 91 cmd = ctphase+' inobs="event_file_that_does_not_exist.fits"'+ \
91   - ' outobs="ctphase_cmd2.fits"'+ \
92   - ' p0=0.1 mjd=51544.5'+ \
93   - ' f0=0.1 f1=0. f2=0.'+ \
94   - ' logfile="ctphase_cmd2.log" chatter=1'
  92 + ' outobs="ctphase_cmd2.fits"'+ \
  93 + ' inmodel="'+self._model_file+'" source="Crab"'+ \
  94 + ' logfile="ctphase_cmd2.log" chatter=1'
95 95  
96 96 # Check if execution failed
97 97 self.test_assert(self._execute(cmd) != 0,
... ... @@ -124,6 +124,8 @@ class Test(test):
124 124 self._check_obs(phase.obs(), nobs=0)
125 125  
126 126 # Check that saving does nothing
  127 + phase['inmodel'] = self._model_file
  128 + phase['source'] = 'Crab'
127 129 phase['outobs'] = 'ctphase_py0.fits'
128 130 phase['logfile'] = 'ctphase_py0.log'
129 131 phase.logFileOpen()
... ... @@ -136,11 +138,8 @@ class Test(test):
136 138  
137 139 # Now set ctphase parameters
138 140 phase['inobs'] = self._events
139   - phase['p0'] = 0.
140   - phase['mjd'] = 51544.5
141   - phase['f0'] = 1.
142   - phase['f1'] = 0.0
143   - phase['f2'] = 0.
  141 + phase['inmodel'] = self._model_file
  142 + phase['source'] = 'Crab'
144 143 phase['outobs'] = 'ctphase_py1.fits'
145 144 phase['logfile'] = 'ctphase_py1.log'
146 145 phase['chatter'] = 2
... ... @@ -151,34 +150,50 @@ class Test(test):
151 150 phase.save()
152 151  
153 152 # Check result file
154   - self._check_result_file('ctphase_py1.fits', nevents=6141)
  153 + self._check_result_file('ctphase_py1.fits')
  154 +
  155 + # Now run ctphase tool without a model file
  156 + phase['inmodel'] = 'NONE'
  157 + phase['source'] = 'NONE'
  158 + phase['phasecurve'] = self._phase_file
  159 + phase['mjd'] = 51544.5
  160 + phase['phase'] = 0.0
  161 + phase['f0'] = 1.0
  162 + phase['f1'] = 0.1
  163 + phase['f2'] = 0.01
  164 + phase['outobs'] = 'ctphase_py2.fits'
  165 + phase['logfile'] = 'ctphase_py2.log'
  166 + phase['chatter'] = 3
  167 +
  168 + # Execute ctphase tool
  169 + phase.logFileOpen() # Make sure we get a log file
  170 + phase.execute()
  171 +
  172 + # Check result file
  173 + self._check_result_file('ctphase_py2.fits')
155 174  
156 175 # Copy ctphase tool
157 176 cpy_phase = phase.copy()
158 177  
159   - # Execute copy of ctphase tool again, now with a negative value
160   - # of initial phase to test for invalid parameter value
161   - self.test_try('Test invalid parameter value')
162   - try:
163   - cpy_phase['mjd'] = 51544.5
164   - cpy_phase['f0'] = 1.
165   - cpy_phase['f1'] = 0.2
166   - cpy_phase['f2'] = 0.
167   - cpy_phase['outobs'] = 'ctphase_py2.fits'
168   - cpy_phase['logfile'] = 'ctphase_py2.log'
169   - cpy_phase['chatter'] = 3
170   - cpy_phase['publish'] = True
171   - cpy_phase.logFileOpen() # Needed to get a new log file
172   - cpy_phase['p0'] = -0.5
173   - cpy_phase.execute()
174   - self.test_try_failure('Exception not thrown')
175   - except ValueError:
176   - self.test_try_success()
  178 + # Clear phase tool
  179 + phase.clear()
  180 +
  181 + # Execute copy
  182 + cpy_phase['outobs'] = 'ctphase_py3.fits'
  183 + cpy_phase['logfile'] = 'ctphase_py3.log'
  184 + cpy_phase['chatter'] = 4
  185 + cpy_phase['publish'] = True
  186 + cpy_phase.logFileOpen() # Needed to get a new log file
  187 + cpy_phase.execute()
177 188  
  189 + # Check result file
  190 + self._check_result_file('ctphase_py3.fits')
  191 +
  192 + # Return
178 193 return
179 194  
180 195 # Check result file
181   - def _check_result_file(self, filename, nevents=591, dec=22.01, rad=3.0):
  196 + def _check_result_file(self, filename, nevents=6141):
182 197 """
183 198 Check result file
184 199  
... ... @@ -188,14 +203,10 @@ class Test(test):
188 203 Event list file name
189 204 nevents : int, optional
190 205 Expected number of events
191   - dec : float, optional
192   - Expected Declination (deg)
193   - rad : float, optional
194   - Expected radius (deg)
195 206 """
196 207 # Open result file
197   - events = gammalib.GCTAEventList(filename)
198   - phases = [ events[i].phase() for i in range(events.size())]
  208 + events = gammalib.GCTAEventList(filename)
  209 + phases = [events[i].phase() for i in range(events.size())]
199 210 test_result = int(sum(phases)>0)
200 211 self.test_value(test_result, 1, 'Check number of events')
201 212  
... ... @@ -213,8 +224,6 @@ class Test(test):
213 224 Models
214 225 nobs : int, optional
215 226 Expected number of observations
216   - nevents : int, optional
217   - Expected number of events
218 227 """
219 228 # Check number of observations
220 229 self.test_value(obs.size(), nobs, 'Check number of observations')
... ...
test/test_ctprob.py 0 → 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# This scripts performs unit tests for the ctprob tool.
  4 +#
  5 +# Copyright (C) 2017 by Leonardo Di Venere
  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 os
  22 +import gammalib
  23 +import ctools
  24 +from testing import test
  25 +
  26 +
  27 +# ============================ #
  28 +# Test class for ctprob tool #
  29 +# ============================ #
  30 +class Test(test):
  31 + """
  32 + Test class for ctprob tool
  33 + """
  34 + # Constructor
  35 + def __init__(self):
  36 + """
  37 + Constructor
  38 + """
  39 + # Call base class constructor
  40 + test.__init__(self)
  41 +
  42 + # Set test data
  43 + self._invalid_events = self._datadir + '/invalid_event_list.fits'
  44 +
  45 + # Return
  46 + return
  47 +
  48 + # Set test functions
  49 + def set(self):
  50 + """
  51 + Set all test functions
  52 + """
  53 + # Set test name
  54 + self.name('ctprob')
  55 +
  56 + # Append tests
  57 + self.append(self._test_cmd, 'Test ctprob on command line')
  58 + self.append(self._test_python, 'Test ctprob from Python')
  59 +
  60 + # Return
  61 + return
  62 +
  63 + # Test ctprob on command line
  64 + def _test_cmd(self):
  65 + """
  66 + Test ctprob on the command line
  67 + """
  68 + # Set tool name
  69 + ctprob = self._tool('ctprob')
  70 +
  71 + # Setup ctprob command
  72 + cmd = ctprob+' inobs="'+self._events+'"'+ \
  73 + ' outobs="ctprob_cmd1.fits"'+ \
  74 + ' inmodel='+self._model+ \
  75 + ' caldb='+self._caldb+' irf='+self._irf+ \
  76 + ' edisp=no'+ \
  77 + ' logfile="ctprob_cmd1.log" chatter=1'
  78 +
  79 + # Check if execution was successful
  80 + self.test_assert(self._execute(cmd) == 0,
  81 + 'Check successful execution from command line')
  82 +
  83 + # Check result file
  84 + self._check_result_file('ctprob_cmd1.fits')
  85 +
  86 + # Setup ctprob command
  87 + cmd = ctprob+' inobs="event_file_that_does_not_exist.fits"'+ \
  88 + ' outobs="ctprob_cmd2.fits"'+ \
  89 + ' inmodel='+self._model+ \
  90 + ' caldb='+self._caldb+' irf='+self._irf+ \
  91 + ' edisp=no'+ \
  92 + ' logfile="ctprob_cmd2.log" chatter=1'
  93 +
  94 + # Check if execution failed
  95 + self.test_assert(self._execute(cmd) != 0,
  96 + 'Check invalid input file when executed from command line')
  97 +
  98 + # Setup ctprob --help option
  99 + cmd = ctprob+' --help'
  100 +
  101 + # Check if execution was successful in case that the CTOOLS
  102 + # environment variable was set or failed otherwise
  103 + if 'CTOOLS' in os.environ:
  104 + self.test_value(self._execute(cmd), 0,
  105 + 'Check successful execution with --help option')
  106 + else:
  107 + self.test_assert(self._execute(cmd) != 0,
  108 + 'Check execution failure with --help option')
  109 +
  110 + # Return
  111 + return
  112 +
  113 + # Test ctprob from Python
  114 + def _test_python(self):
  115 + """
  116 + Test ctprob from Python
  117 + """
  118 + # Allocate empty ctprob tool
  119 + prob = ctools.ctprob()
  120 +
  121 + # Check that empty ctprob tool holds an empty observation
  122 + self._check_obs(prob.obs(), nobs=0)
  123 +
  124 + # Check that saving does nothing
  125 + prob['outobs'] = 'ctprob_py0.fits'
  126 + prob['logfile'] = 'ctprob_py0.log'
  127 + prob.logFileOpen()
  128 + prob.save()
  129 + self.test_assert(not os.path.isfile('ctprob_py0.fits'),
  130 + 'Check that no event list has been created')
  131 +
  132 + # Check that clearing does not lead to an exception or segfault
  133 + prob.clear()
  134 +
  135 + # Now set ctprob parameters
  136 + prob['inobs'] = self._events
  137 + prob['outobs'] = 'ctprob_py1.fits'
  138 + prob['inmodel'] = self._model
  139 + prob['caldb'] = self._caldb
  140 + prob['irf'] = self._irf
  141 + prob['edisp'] = False
  142 + prob['logfile'] = 'ctprob_py1.log'
  143 + prob['chatter'] = 2
  144 +
  145 + # Run ctprob tool
  146 + prob.logFileOpen() # Make sure we get a log file
  147 + prob.run()
  148 + prob.save()
  149 +
  150 + # Check result file
  151 + self._check_result_file('ctprob_py1.fits')
  152 +
  153 + # Setup ctprob tool for an invalid event file
  154 + prob = ctools.ctprob()
  155 + prob['inobs'] = self._invalid_events
  156 + prob['outobs'] = 'ctprob_py2.fits'
  157 + prob['inmodel'] = self._model
  158 + prob['caldb'] = self._caldb
  159 + prob['irf'] = self._irf
  160 + prob['edisp'] = False
  161 + prob['logfile'] = 'ctprob_py2.log'
  162 + prob['chatter'] = 3
  163 +
  164 + # Execute tool
  165 + prob.logFileOpen() # Needed to get a new log file
  166 + self.test_try('Test invalid event file')
  167 + try:
  168 + prob.execute()
  169 + self.test_try_failure('Exception not thrown')
  170 + except RuntimeError:
  171 + self.test_try_success()
  172 +
  173 + # Setup ctprob with a list of observations and test prefix
  174 + prob = ctools.ctprob()
  175 + prob['inobs'] = self._datadir + '/obs_unbinned.xml'
  176 + prob['prefix'] = 'ctprob_py3_'
  177 + prob['outobs'] = 'ctprob_py3_obs.xml'
  178 + prob['inmodel'] = self._model
  179 + prob['caldb'] = self._caldb
  180 + prob['irf'] = self._irf
  181 + prob['edisp'] = True
  182 + prob['logfile'] = 'ctprob_py3.log'
  183 + prob['chatter'] = 4
  184 +
  185 + # Run ctprob tool
  186 + prob.logFileOpen() # Make sure we get a log file
  187 + prob.execute()
  188 +
  189 + # Check result file
  190 + self._check_result_file('ctprob_py3_crab_events.fits')
  191 +
  192 + # Return
  193 + return
  194 +
  195 + # Check result file
  196 + def _check_result_file(self, filename, nevents=6141):
  197 + """
  198 + Check result file
  199 +
  200 + Parameters
  201 + ----------
  202 + filename : str
  203 + Event list file name
  204 + nevents : int, optional
  205 + Expected number of events
  206 + """
  207 + # Open result file
  208 + events = gammalib.GCTAEventList(filename)
  209 +
  210 + # Check event list
  211 + self._check_events(events, nevents=nevents)
  212 +
  213 + # Check that probability columns exist
  214 + colname1 = 'PROB_Background'
  215 + colname2 = 'PROB_Crab'
  216 + self._check_column(filename, colname1)
  217 + self._check_column(filename, colname2)
  218 +
  219 + # Check that the probability values are correctly normalized
  220 + self._check_normalization(filename, [colname1,colname2])
  221 +
  222 + # Return
  223 + return
  224 +
  225 + # Check observation and event list
  226 + def _check_obs(self, obs, nobs=1, nevents=6141):
  227 + """
  228 + Check observation and event list
  229 +
  230 + Parameters
  231 + ----------
  232 + obs : `~gammalib.GObservations`
  233 + Models
  234 + nobs : int, optional
  235 + Expected number of observations
  236 + nevents : int, optional
  237 + Expected number of events
  238 + """
  239 + # Check number of observations
  240 + self.test_value(obs.size(), nobs, 'Check number of observations')
  241 +
  242 + # If there is an observation then check the event list of the first
  243 + # one
  244 + if obs.size() > 0:
  245 + self._check_events(obs[0].events(), nevents=nevents)
  246 +
  247 + # Return
  248 + return
  249 +
  250 + # Check events
  251 + def _check_events(self, events, nevents=6141):
  252 + """
  253 + Check event list
  254 +
  255 + Parameters
  256 + ----------
  257 + events : `~gammalib.GCTAEventList`
  258 + Event list
  259 + nevents : int, optional
  260 + Expected number of events
  261 + """
  262 + # Check event list
  263 + self.test_value(events.size(), nevents, 'Check number of events')
  264 +
  265 + # Return
  266 + return
  267 +
  268 +
  269 + def _check_column(self, filename, colname):
  270 + """
  271 + Check that column colname exists.
  272 +
  273 + Parameters
  274 + ----------
  275 + filename : str
  276 + Event list file name
  277 + colname : str
  278 + Name of the column to check
  279 + """
  280 + # Check that column exists
  281 + gfits = gammalib.GFits(filename)
  282 + gtable = gfits[1]
  283 + check = int(gtable.contains(colname))
  284 + self.test_value(check, 1, 'Check column '+colname)
  285 +
  286 + # Return
  287 + return
  288 +
  289 +
  290 + def _check_normalization(self, filename, colnames):
  291 + """
  292 + Check that the probability values in columns identified by colnames are
  293 + correctly normalized.
  294 +
  295 + Parameters
  296 + ----------
  297 + filename : str
  298 + Event list file name
  299 + colnames : list
  300 + Names of the columns to check
  301 + """
  302 + # Check that the probability values are correctly normalized
  303 +
  304 + # Open fits table
  305 + gfits = gammalib.GFits(filename)
  306 + gtable = gfits[1]
  307 + ncols = gtable.ncols()
  308 + nevt = gtable.nrows()
  309 + srcs = []
  310 +
  311 + # Loop over colnames
  312 + for colname in colnames:
  313 +
  314 + # Get the correct column corresponding to colname from the table
  315 + for icol in range(ncols):
  316 + gcol = gtable[icol]
  317 + if gcol.name()==colname:
  318 + break
  319 +
  320 + # Read and save column content
  321 + src1 = []
  322 + for ievt in range(nevt):
  323 + src1.append(gcol[ievt])
  324 + srcs.extend(src1)
  325 +
  326 + # Compute sum
  327 + tot = sum(srcs)
  328 + self.test_value(int(tot+0.5), nevt, 'Check that probability columns '
  329 + 'are normalized')
  330 +
  331 + # Return
  332 + return
  333 +
... ...
test/test_python_ctools.py
... ... @@ -40,6 +40,7 @@ import test_ctcubemask
40 40 import test_ctbutterfly
41 41 import test_ctulimit
42 42 import test_cterror
  43 +import test_ctprob
43 44 import test_pipelines
44 45  
45 46  
... ... @@ -118,6 +119,7 @@ def test(installed=False):
118 119 test_ctbutterfly.Test(),
119 120 test_ctulimit.Test(),
120 121 test_cterror.Test(),
  122 + test_ctprob.Test(),
121 123 test_pipelines.Test()]
122 124  
123 125 # Allocate test suite container
... ...