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,6 +71,8 @@ src/ctcubemask/ctcubemask
71 src/ctbutterfly/ctbutterfly 71 src/ctbutterfly/ctbutterfly
72 src/ctulimit/ctulimit 72 src/ctulimit/ctulimit
73 src/cterror/cterror 73 src/cterror/cterror
  74 +src/ctprob/ctprob
  75 +src/ctphase/ctphase
74 test/pfiles/ 76 test/pfiles/
75 test/caldb/ 77 test/caldb/
76 test/prod3 78 test/prod3
@@ -2,6 +2,7 @@ Johan Bregeon (johan.bregeon@lupm.in2p3.fr) @@ -2,6 +2,7 @@ Johan Bregeon (johan.bregeon@lupm.in2p3.fr)
2 Rolf Buehler (rolf.buehler@desy.de) 2 Rolf Buehler (rolf.buehler@desy.de)
3 Jean-Baptiste Cayrou (cayrou@etud.insa-toulouse.fr) 3 Jean-Baptiste Cayrou (cayrou@etud.insa-toulouse.fr)
4 Christoph Deil (Christoph.Deil@mpi-hd.mpg.de) 4 Christoph Deil (Christoph.Deil@mpi-hd.mpg.de)
  5 +Leonardo Di Venere (leonardo.divenere@ba.infn.it)
5 Florent Forest (florent.forest@isae.fr) 6 Florent Forest (florent.forest@isae.fr)
6 Lucie Gerard (lgerard@wgs18.zeuthen.desy.de) 7 Lucie Gerard (lgerard@wgs18.zeuthen.desy.de)
7 Maria Haupt (maria.haupt@desy.de) 8 Maria Haupt (maria.haupt@desy.de)
ChangeLog
1 -2017-04-05 1 +2017-04-11
2 2
3 * Version 1.3.0 released 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 Copy cscripts into bin directory instead of creating a symbolic links (#1987) 11 Copy cscripts into bin directory instead of creating a symbolic links (#1987)
7 If code originates from Git, always compile the Python bindings (#1985) 12 If code originates from Git, always compile the Python bindings (#1985)
8 Raise exception instead of exiting with return code in Python tests (#1983) 13 Raise exception instead of exiting with return code in Python tests (#1983)
1 New Features and Important Changes in ctools 1.3.0.dev1 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 Introduction 6 Introduction
@@ -57,7 +57,10 @@ None @@ -57,7 +57,10 @@ None
57 57
58 ctlike - Maximum likelihood fitting 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 cttsmap - Generation of Test Statistic map 66 cttsmap - Generation of Test Statistic map
@@ -113,7 +116,11 @@ None @@ -113,7 +116,11 @@ None
113 116
114 ctbutterfly - Generate butterfly diagrams 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 ctulimit - Compute upper limit 126 ctulimit - Compute upper limit
@@ -126,6 +133,15 @@ cterror - Likelihood profile error computation @@ -126,6 +133,15 @@ cterror - Likelihood profile error computation
126 None 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 cscripts 145 cscripts
130 -------- 146 --------
131 The csebins script has been added that generates an energy boundaries 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,6 +149,15 @@ extension that can be used for a stacked analysis. The energy boundaries
133 are set as function of the variation in the effective area and background 149 are set as function of the variation in the effective area and background
134 rates of the Instrument Response Function (#1976). 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 Examples 162 Examples
138 -------- 163 --------
cscripts/csroot2caldb.py
@@ -536,7 +536,8 @@ class csroot2caldb(ctools.cscript): @@ -536,7 +536,8 @@ class csroot2caldb(ctools.cscript):
536 Translate ROOT to CALDB effective area extension 536 Translate ROOT to CALDB effective area extension
537 537
538 The following ROOT histograms are used: 538 The following ROOT histograms are used:
539 - - EffectiveAreaEtrue_offaxis -> EFFAREA 539 + - EffectiveAreaEtrueNoTheta2cut_offaxis -> EFFAREA
  540 + - EffectiveAreaEtrueNoTheta2cut (for normalization)
540 541
541 Parameters 542 Parameters
542 ---------- 543 ----------
@@ -551,13 +552,13 @@ class csroot2caldb(ctools.cscript): @@ -551,13 +552,13 @@ class csroot2caldb(ctools.cscript):
551 self._log_header1(gammalib.TERSE, 'Generate effective area extension') 552 self._log_header1(gammalib.TERSE, 'Generate effective area extension')
552 553
553 # Get relevant ROOT histograms 554 # Get relevant ROOT histograms
554 - etrue = tfile.Get('EffectiveAreaEtrue_offaxis') 555 + etrue = tfile.Get('EffectiveAreaEtrueNoTheta2cut_offaxis')
555 556
556 # If requested then normalize the 2D histogram on the on-axis 1D 557 # If requested then normalize the 2D histogram on the on-axis 1D
557 # histogram. This assures that the 2D histogram has the same on-axis 558 # histogram. This assures that the 2D histogram has the same on-axis
558 # effective area dependence as the 1D histogram. 559 # effective area dependence as the 1D histogram.
559 if self['norm1d'].boolean(): 560 if self['norm1d'].boolean():
560 - etrue_1D = tfile.Get('EffectiveAreaEtrue') 561 + etrue_1D = tfile.Get('EffectiveAreaEtrueNoTheta2cut')
561 self._renorm_onaxis(etrue, etrue_1D) 562 self._renorm_onaxis(etrue, etrue_1D)
562 563
563 # If requested then rebin the effective area Etrue histogram. This 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,7 +20,7 @@ inobs, f, h, NONE,,, "Input event list, counts cube, or observation definition
20 inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model definition XML file" 20 inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model definition XML file"
21 srcname, s, a, Crab,,, "Source name" 21 srcname, s, a, Crab,,, "Source name"
22 caldb, s, a, prod2,,, "Calibration database" 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 edisp, b, h, no,,, "Apply energy dispersion?" 24 edisp, b, h, no,,, "Apply energy dispersion?"
25 deadc, r, h, 0.98,0,1, "Deadtime correction factor" 25 deadc, r, h, 0.98,0,1, "Deadtime correction factor"
26 outfile, f, h, sensitivity.dat,,, "Output sensitivity ASCII file" 26 outfile, f, h, sensitivity.dat,,, "Output sensitivity ASCII file"
@@ -31,16 +31,15 @@ outfile, f, h, sensitivity.dat,,, "Output sensitivity ASCII file" @@ -31,16 +31,15 @@ outfile, f, h, sensitivity.dat,,, "Output sensitivity ASCII file"
31 offset, r, h, 0.0,,, "Source offset angle (deg)" 31 offset, r, h, 0.0,,, "Source offset angle (deg)"
32 duration, r, a, 180000.0,,, "Effective exposure time (s)" 32 duration, r, a, 180000.0,,, "Effective exposure time (s)"
33 rad, r, a, 5.0,,, "Radius of ROI (deg)" 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 enumbins, i, h, 0,,, "Number of energy bins for binned analysis (0=unbinned)" 37 enumbins, i, h, 0,,, "Number of energy bins for binned analysis (0=unbinned)"
38 npix, i, h, 200,,, "Number of pixels for binned analysis" 38 npix, i, h, 200,,, "Number of pixels for binned analysis"
39 binsz, r, h, 0.05,,, "Pixel size for binned analysis (deg/pixel)" 39 binsz, r, h, 0.05,,, "Pixel size for binned analysis (deg/pixel)"
40 type, s, h, Differential,Differential|Integral,, "Sensitivity type" 40 type, s, h, Differential,Differential|Integral,, "Sensitivity type"
41 sigma, r, h, 5.0,,, "Significance threshold (Gaussian sigma)" 41 sigma, r, h, 5.0,,, "Significance threshold (Gaussian sigma)"
42 max_iter, i, h, 50,,, "Maximum number of iterations" 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 # Standard parameters 45 # Standard parameters
@@ -49,6 +48,6 @@ chatter, i, h, 2,0,4, "Chattiness of output" @@ -49,6 +48,6 @@ chatter, i, h, 2,0,4, "Chattiness of output"
49 clobber, b, h, yes,,, "Overwrite existing output files with new output files?" 48 clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
50 debug, b, h, no,,, "Debugging mode activated" 49 debug, b, h, no,,, "Debugging mode activated"
51 mode, s, h, ql,,, "Mode of automatic parameters" 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 #! /usr/bin/env python 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 # This program is free software: you can redistribute it and/or modify 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 8 # it under the terms of the GNU General Public License as published by
@@ -40,7 +40,7 @@ class cssens(ctools.cscript): @@ -40,7 +40,7 @@ class cssens(ctools.cscript):
40 and the flux level is determined that leads to a particular significance. 40 and the flux level is determined that leads to a particular significance.
41 41
42 The significance is determined using the Test Statistic, defined as twice 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 # Constructor 46 # Constructor
@@ -50,31 +50,20 @@ class cssens(ctools.cscript): @@ -50,31 +50,20 @@ class cssens(ctools.cscript):
50 """ 50 """
51 # Set name 51 # Set name
52 self._name = 'cssens' 52 self._name = 'cssens'
53 - self._version = '1.2.0' 53 + self._version = '1.3.0'
54 54
55 # Initialise class members 55 # Initialise class members
56 - self._obs = gammalib.GObservations()  
57 self._ebounds = gammalib.GEbounds() 56 self._ebounds = gammalib.GEbounds()
58 self._obs_ebounds = [] 57 self._obs_ebounds = []
59 self._srcname = '' 58 self._srcname = ''
60 - self._outfile = gammalib.GFilename()  
61 self._ra = None 59 self._ra = None
62 self._dec = None 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 self._log_clients = False 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 self._init_cscript(argv) 67 self._init_cscript(argv)
79 68
80 # Return 69 # Return
@@ -87,8 +76,8 @@ class cssens(ctools.cscript): @@ -87,8 +76,8 @@ class cssens(ctools.cscript):
87 Get user parameters from parfile 76 Get user parameters from parfile
88 """ 77 """
89 # Set observation if not done before 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 # Set models if we have none 82 # Set models if we have none
94 if self._obs.models().size() == 0: 83 if self._obs.models().size() == 0:
@@ -98,31 +87,28 @@ class cssens(ctools.cscript): @@ -98,31 +87,28 @@ class cssens(ctools.cscript):
98 self._srcname = self['srcname'].string() 87 self._srcname = self['srcname'].string()
99 88
100 # Read further parameters 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 self['debug'].boolean() 106 self['debug'].boolean()
121 107
122 # Derive some parameters 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 # Write input parameters into logger 113 # Write input parameters into logger
128 self._log_parameters(gammalib.TERSE) 114 self._log_parameters(gammalib.TERSE)
@@ -130,20 +116,20 @@ class cssens(ctools.cscript): @@ -130,20 +116,20 @@ class cssens(ctools.cscript):
130 # Return 116 # Return
131 return 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 Set an observation container 121 Set an observation container
136 122
137 Parameters 123 Parameters
138 ---------- 124 ----------
  125 + emin : float
  126 + Minimum energy (TeV)
  127 + emax : float
  128 + Maximum energy (TeV)
139 lpnt : float, optional 129 lpnt : float, optional
140 Galactic longitude of pointing (deg) 130 Galactic longitude of pointing (deg)
141 bpnt : float, optional 131 bpnt : float, optional
142 Galactic latitude of pointing (deg) 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 Returns 134 Returns
149 ------- 135 -------
@@ -205,23 +191,23 @@ class cssens(ctools.cscript): @@ -205,23 +191,23 @@ class cssens(ctools.cscript):
205 191
206 # Get energy boundaries of the observation 192 # Get energy boundaries of the observation
207 obs_ebounds = self._obs_ebounds[i] 193 obs_ebounds = self._obs_ebounds[i]
208 - 194 +
209 # Get minimum and maximum energy of the observation 195 # Get minimum and maximum energy of the observation
210 obs_emin = obs_ebounds.emin() 196 obs_emin = obs_ebounds.emin()
211 obs_emax = obs_ebounds.emax() 197 obs_emax = obs_ebounds.emax()
212 - 198 +
213 # If [emin,emax] is fully contained in the observation energy range 199 # If [emin,emax] is fully contained in the observation energy range
214 # the use [emin,emax] as energy boundaries 200 # the use [emin,emax] as energy boundaries
215 if obs_emin <= emin and obs_emax >= emax: 201 if obs_emin <= emin and obs_emax >= emax:
216 ebounds = gammalib.GEbounds(emin, emax) 202 ebounds = gammalib.GEbounds(emin, emax)
217 - 203 +
218 # ... otherwise, if [emin,emax] is completely outside the 204 # ... otherwise, if [emin,emax] is completely outside the
219 # observation energy range then set the energy boundaries to the 205 # observation energy range then set the energy boundaries to the
220 # zero-width interval [0,0] 206 # zero-width interval [0,0]
221 elif emax < obs_emin or emin > obs_emax: 207 elif emax < obs_emin or emin > obs_emax:
222 e0 = gammalib.GEnergy(0.0, 'TeV') 208 e0 = gammalib.GEnergy(0.0, 'TeV')
223 ebounds = gammalib.GEbounds(e0, e0) 209 ebounds = gammalib.GEbounds(e0, e0)
224 - 210 +
225 # ... otherwise, if [emin,emax] overlaps partially with the 211 # ... otherwise, if [emin,emax] overlaps partially with the
226 # observation energy range then set the energy boundaries to the 212 # observation energy range then set the energy boundaries to the
227 # overlapping part 213 # overlapping part
@@ -229,10 +215,10 @@ class cssens(ctools.cscript): @@ -229,10 +215,10 @@ class cssens(ctools.cscript):
229 # Set overlapping energy range 215 # Set overlapping energy range
230 set_emin = max(emin, obs_emin) 216 set_emin = max(emin, obs_emin)
231 set_emax = min(emax, obs_emax) 217 set_emax = min(emax, obs_emax)
232 - 218 +
233 # Set energy boundaries 219 # Set energy boundaries
234 ebounds = gammalib.GEbounds(set_emin, set_emax) 220 ebounds = gammalib.GEbounds(set_emin, set_emax)
235 - 221 +
236 # Set the energy boundaries as the boundaries of the observation 222 # Set the energy boundaries as the boundaries of the observation
237 obs.events().ebounds(ebounds) 223 obs.events().ebounds(ebounds)
238 224
@@ -286,13 +272,27 @@ class cssens(ctools.cscript): @@ -286,13 +272,27 @@ class cssens(ctools.cscript):
286 # Set TeV->erg conversion factor 272 # Set TeV->erg conversion factor
287 tev2erg = 1.6021764 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 # Set energy boundaries 289 # Set energy boundaries
290 self._set_obs_ebounds(emin, emax) 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 # Compute Crab unit. This is the factor with which the Prefactor needs 297 # Compute Crab unit. This is the factor with which the Prefactor needs
298 # to be multiplied to get 1 Crab. 298 # to be multiplied to get 1 Crab.
@@ -300,20 +300,27 @@ class cssens(ctools.cscript): @@ -300,20 +300,27 @@ class cssens(ctools.cscript):
300 src_flux = test_model[self._srcname].spectral().flux(emin, emax) 300 src_flux = test_model[self._srcname].spectral().flux(emin, emax)
301 crab_unit = crab_flux/src_flux 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 self._log_header2(gammalib.TERSE, 'Energies: '+str(emin)+' - '+str(emax)) 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 self._log_value(gammalib.TERSE, 'Crab flux', str(crab_flux)+' ph/cm2/s') 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 self._log_value(gammalib.TERSE, 'Crab unit factor', crab_unit) 314 self._log_value(gammalib.TERSE, 'Crab unit factor', crab_unit)
309 315
310 # Initialise loop 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 # Loop until we break 325 # Loop until we break
319 while True: 326 while True:
@@ -335,11 +342,11 @@ class cssens(ctools.cscript): @@ -335,11 +342,11 @@ class cssens(ctools.cscript):
335 342
336 # Simulate events for the models. "sim" holds an observation 343 # Simulate events for the models. "sim" holds an observation
337 # container with observations containing the simulated events. 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 log=self._log_clients, 347 log=self._log_clients,
341 debug=self['debug'].boolean(), 348 debug=self['debug'].boolean(),
342 - edisp=self._edisp) 349 + edisp=self['edisp'].boolean())
343 350
344 # Determine number of events in simulation by summing the events 351 # Determine number of events in simulation by summing the events
345 # over all observations in the observation container 352 # over all observations in the observation container
@@ -354,7 +361,7 @@ class cssens(ctools.cscript): @@ -354,7 +361,7 @@ class cssens(ctools.cscript):
354 # Fit test source to the simulated events in the observation 361 # Fit test source to the simulated events in the observation
355 # container 362 # container
356 fit = ctools.ctlike(sim) 363 fit = ctools.ctlike(sim)
357 - fit['edisp'] = edisp=self._edisp 364 + fit['edisp'] = self['edisp'].boolean()
358 fit['debug'] = self['debug'].boolean() 365 fit['debug'] = self['debug'].boolean()
359 fit['chatter'] = self['chatter'].integer() 366 fit['chatter'] = self['chatter'].integer()
360 fit.run() 367 fit.run()
@@ -383,29 +390,24 @@ class cssens(ctools.cscript): @@ -383,29 +390,24 @@ class cssens(ctools.cscript):
383 # Assess quality based on a comparison between Npred and Nevents 390 # Assess quality based on a comparison between Npred and Nevents
384 quality = npred - nevents 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 if ts <= 0.0: 401 if ts <= 0.0:
400 402
401 # If the number of iterations was exceeded then stop 403 # If the number of iterations was exceeded then stop
402 - if (iterations >= self._max_iter): 404 + if (iterations >= max_iter):
403 self._log_string(gammalib.TERSE, 405 self._log_string(gammalib.TERSE,
404 - ' Test ended after %d iterations.' % self._max_iter) 406 + ' Test ended after %d iterations.' % max_iter)
405 break 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 # Signal start we start over 412 # Signal start we start over
411 self._log_string(gammalib.EXPLICIT, 413 self._log_string(gammalib.EXPLICIT,
@@ -414,95 +416,64 @@ class cssens(ctools.cscript): @@ -414,95 +416,64 @@ class cssens(ctools.cscript):
414 # ... and start over 416 # ... and start over
415 continue 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 # Compute extrapolated fluxes based on the flux correction factor 435 # Compute extrapolated fluxes based on the flux correction factor
424 crab_flux = correct * crab_flux 436 crab_flux = correct * crab_flux
425 photon_flux = correct * photon_flux 437 photon_flux = correct * photon_flux
426 energy_flux = correct * energy_flux 438 energy_flux = correct * energy_flux
427 sensitivity = correct * sensitivity 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 if test_crab_flux > 0: 444 if test_crab_flux > 0:
  445 +
  446 + # Compute fractional change in the Crab flux between two
  447 + # iterations
478 ratio = crab_flux/test_crab_flux 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 break 461 break
488 else: 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 break 464 break
492 465
493 - # Use average for next iteration 466 + # Set test flux for next iteration
494 test_crab_flux = crab_flux 467 test_crab_flux = crab_flux
495 468
496 # Exit loop if number of trials exhausted 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 break 473 break
502 474
503 # Write fit results into logger 475 # Write fit results into logger
504 self._log_header3(gammalib.TERSE, 'Fit results') 476 self._log_header3(gammalib.TERSE, 'Fit results')
505 - self._log_value(gammalib.TERSE, 'Test statistics', ts)  
506 self._log_value(gammalib.TERSE, 'Photon flux', 477 self._log_value(gammalib.TERSE, 'Photon flux',
507 str(photon_flux)+' ph/cm2/s') 478 str(photon_flux)+' ph/cm2/s')
508 self._log_value(gammalib.TERSE, 'Energy flux', 479 self._log_value(gammalib.TERSE, 'Energy flux',
@@ -523,16 +494,84 @@ class cssens(ctools.cscript): @@ -523,16 +494,84 @@ class cssens(ctools.cscript):
523 # Restore energy boundaries of observation container 494 # Restore energy boundaries of observation container
524 for i, obs in enumerate(self._obs): 495 for i, obs in enumerate(self._obs):
525 obs.events().ebounds(self._obs_ebounds[i]) 496 obs.events().ebounds(self._obs_ebounds[i])
526 - 497 +
527 # Store result 498 # Store result
528 result = {'loge': loge, 'emin': emin.TeV(), 'emax': emax.TeV(), \ 499 result = {'loge': loge, 'emin': emin.TeV(), 'emax': emax.TeV(), \
529 'crab_flux': crab_flux, 'photon_flux': photon_flux, \ 500 'crab_flux': crab_flux, 'photon_flux': photon_flux, \
530 'energy_flux': energy_flux, \ 501 'energy_flux': energy_flux, \
531 - 'sensitivity': sensitivity} 502 + 'sensitivity': sensitivity, 'regcoeff': regcoeff, \
  503 + 'nevents': nevents, 'npred': npred}
532 504
533 # Return result 505 # Return result
534 return result 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 # Public methods 576 # Public methods
538 def run(self): 577 def run(self):
@@ -545,15 +584,16 @@ class cssens(ctools.cscript): @@ -545,15 +584,16 @@ class cssens(ctools.cscript):
545 584
546 # Get parameters 585 # Get parameters
547 self._get_parameters() 586 self._get_parameters()
548 - 587 +
549 # Loop over observations and store a deep copy of the energy 588 # Loop over observations and store a deep copy of the energy
550 # boundaries for later use 589 # boundaries for later use
551 for obs in self._obs: 590 for obs in self._obs:
552 self._obs_ebounds.append(obs.events().ebounds().copy()) 591 self._obs_ebounds.append(obs.events().ebounds().copy())
553 - 592 +
554 # Initialise script 593 # Initialise script
555 colnames = ['loge', 'emin', 'emax', 'crab_flux', 'photon_flux', 594 colnames = ['loge', 'emin', 'emax', 'crab_flux', 'photon_flux',
556 - 'energy_flux', 'sensitivity'] 595 + 'energy_flux', 'sensitivity', 'regcoeff', 'nevents',
  596 + 'npred']
557 results = [] 597 results = []
558 598
559 # Set test source model for this observation 599 # Set test source model for this observation
@@ -566,30 +606,35 @@ class cssens(ctools.cscript): @@ -566,30 +606,35 @@ class cssens(ctools.cscript):
566 # Write models into logger 606 # Write models into logger
567 self._log_models(gammalib.NORMAL, models, 'Model') 607 self._log_models(gammalib.NORMAL, models, 'Model')
568 608
  609 + # Get sensitivity type
  610 + sensitivity_type = self['type'].string()
  611 +
569 # Write header 612 # Write header
570 self._log_header1(gammalib.TERSE, 'Sensitivity determination') 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 # Loop over energy bins 616 # Loop over energy bins
574 for ieng in range(self._ebounds.size()): 617 for ieng in range(self._ebounds.size()):
575 618
576 # Set energies 619 # Set energies
577 - if self._type == 'Differential': 620 + if sensitivity_type == 'Differential':
578 emin = self._ebounds.emin(ieng) 621 emin = self._ebounds.emin(ieng)
579 emax = self._ebounds.emax(ieng) 622 emax = self._ebounds.emax(ieng)
580 - elif self._type == 'Integral': 623 + elif sensitivity_type == 'Integral':
581 emin = self._ebounds.emin(ieng) 624 emin = self._ebounds.emin(ieng)
582 emax = self._ebounds.emax() 625 emax = self._ebounds.emax()
583 else: 626 else:
584 msg = ('Invalid sensitivity type "%s" encountered. Either ' 627 msg = ('Invalid sensitivity type "%s" encountered. Either '
585 - 'specify "Differential" or "Integral".' % self._type) 628 + 'specify "Differential" or "Integral".' %
  629 + sensitivity_type)
586 raise RuntimeError(msg) 630 raise RuntimeError(msg)
587 631
588 # Determine sensitivity 632 # Determine sensitivity
589 result = self._get_sensitivity(emin, emax, models) 633 result = self._get_sensitivity(emin, emax, models)
590 634
591 # Write out trial result 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 # Append results 639 # Append results
595 results.append(result) 640 results.append(result)
doc/source/users/reference_manual/cssens.rst
@@ -100,9 +100,6 @@ General parameters @@ -100,9 +100,6 @@ General parameters
100 ``(max_iter = 50) [integer]`` 100 ``(max_iter = 50) [integer]``
101 Maximum number of iterations. 101 Maximum number of iterations.
102 102
103 -``(num_avg = 3) [integer]``  
104 - Number of iterations for sliding average.  
105 -  
106 103
107 Standard parameters 104 Standard parameters
108 ------------------- 105 -------------------
doc/source/users/reference_manual/ctbutterfly.rst
@@ -3,21 +3,25 @@ @@ -3,21 +3,25 @@
3 ctbutterfly 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 Synopsis 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 ctbutterfly assumes that the input model (parameter ``inmodel``) has been 26 ctbutterfly assumes that the input model (parameter ``inmodel``) has been
23 adjusted using :doc:`ctlike` to the data, but if this is not the case you 27 adjusted using :doc:`ctlike` to the data, but if this is not the case you
@@ -68,11 +72,14 @@ General parameters @@ -68,11 +72,14 @@ General parameters
68 72
69 ``outfile [file]`` 73 ``outfile [file]``
70 Output butterfly ASCII file name. 74 Output butterfly ASCII file name.
71 - 75 +
72 ``(fit = no) [boolean]`` 76 ``(fit = no) [boolean]``
73 Performs maximum likelihood fitting of input model ignoring any provided 77 Performs maximum likelihood fitting of input model ignoring any provided
74 covariance matrix. 78 covariance matrix.
75 - 79 +
  80 +``(method = "GAUSSIAN") <GAUSSIAN|ENVELOPE> [string]``
  81 + Computation method.
  82 +
76 ``(confidence = 0.68) [real]`` 83 ``(confidence = 0.68) [real]``
77 Confidence level for error computation. 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,13 +48,13 @@ the spatial model parameters can be kept fixed during that computation
48 ctlike generates an output model XML file that contains the values of the 48 ctlike generates an output model XML file that contains the values of the
49 best fitting model parameters. For all free parameters, an ``error`` attribute 49 best fitting model parameters. For all free parameters, an ``error`` attribute
50 is added that provides the statistical uncertainty in the parameter estimate. 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 General parameters 60 General parameters
@@ -89,7 +89,7 @@ General parameters @@ -89,7 +89,7 @@ General parameters
89 the maximum likelihood fit. 89 the maximum likelihood fit.
90 90
91 ``(outcovmat = NONE) [string]`` 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 ``(stat = POISSON) [string]`` 94 ``(stat = POISSON) [string]``
95 Fitting statistics (POISSON or GAUSSIAN; only affects binned analysis). 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,6 +27,7 @@ ctools
27 ctmodel --- Computes model counts cube <ctmodel> 27 ctmodel --- Computes model counts cube <ctmodel>
28 ctobssim --- Simulate observations <ctobssim> 28 ctobssim --- Simulate observations <ctobssim>
29 ctpsfcube --- Generates point spread function cube <ctpsfcube> 29 ctpsfcube --- Generates point spread function cube <ctpsfcube>
  30 + ctprob --- Computes event probability for a given model <ctprob>
30 ctselect --- Selects event data <ctselect> 31 ctselect --- Selects event data <ctselect>
31 ctskymap --- Generates sky map <ctskymap> 32 ctskymap --- Generates sky map <ctskymap>
32 cttsmap --- Generates Test Statistic map <cttsmap> 33 cttsmap --- Generates Test Statistic map <cttsmap>
pyext/Makefile.am
@@ -59,6 +59,7 @@ testscripts = ctools/tests/__init__.py \ @@ -59,6 +59,7 @@ testscripts = ctools/tests/__init__.py \
59 $(top_srcdir)/test/test_ctbutterfly.py \ 59 $(top_srcdir)/test/test_ctbutterfly.py \
60 $(top_srcdir)/test/test_ctulimit.py \ 60 $(top_srcdir)/test/test_ctulimit.py \
61 $(top_srcdir)/test/test_cterror.py \ 61 $(top_srcdir)/test/test_cterror.py \
  62 + $(top_srcdir)/test/test_ctprob.py \
62 $(top_srcdir)/test/test_pipelines.py 63 $(top_srcdir)/test/test_pipelines.py
63 64
64 # Test data to be distributed in $(pyexecdir)/ctools/tests/data 65 # Test data to be distributed in $(pyexecdir)/ctools/tests/data
pyext/ctool.i
1 /*************************************************************************** 1 /***************************************************************************
2 * ctool - ctool base class * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -105,6 +105,8 @@ public: @@ -105,6 +105,8 @@ public:
105 %rename(_insert_energy_boundaries) insert_energy_boundaries; 105 %rename(_insert_energy_boundaries) insert_energy_boundaries;
106 %rename(_cube_layer_usage) cube_layer_usage; 106 %rename(_cube_layer_usage) cube_layer_usage;
107 %rename(_is_valid_filename) is_valid_filename; 107 %rename(_is_valid_filename) is_valid_filename;
  108 + %rename(_get_gtiname) get_gtiname;
  109 + %rename(_save_event_list) save_event_list;
108 %rename(_warn_too_few_energies) warn_too_few_energies; 110 %rename(_warn_too_few_energies) warn_too_few_energies;
109 %rename(_warn_xml_suffix) warn_xml_suffix; 111 %rename(_warn_xml_suffix) warn_xml_suffix;
110 112
@@ -147,6 +149,13 @@ public: @@ -147,6 +149,13 @@ public:
147 std::vector<bool> cube_layer_usage(const GEbounds& cube_ebounds, 149 std::vector<bool> cube_layer_usage(const GEbounds& cube_ebounds,
148 const GEbounds& list_ebounds) const; 150 const GEbounds& list_ebounds) const;
149 bool is_valid_filename(const GFilename& filename) const; 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 // Protected warning strings 160 // Protected warning strings
152 std::string warn_too_few_energies(const GEnergies& energies) const; 161 std::string warn_too_few_energies(const GEnergies& energies) const;
pyext/ctools/tools.i
@@ -73,6 +73,7 @@ namespace std { @@ -73,6 +73,7 @@ namespace std {
73 %include "ctbutterfly.i" 73 %include "ctbutterfly.i"
74 %include "ctulimit.i" 74 %include "ctulimit.i"
75 %include "cterror.i" 75 %include "cterror.i"
  76 +%include "ctprob.i"
76 77
77 /* __ Test function ______________________________________________________ */ 78 /* __ Test function ______________________________________________________ */
78 %pythoncode %{ 79 %pythoncode %{
pyext/ctphase.i
1 /*************************************************************************** 1 /***************************************************************************
2 * ctphase - Append phase information to CTA events file * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 /** 21 /**
22 * @file ctphase.i 22 * @file ctphase.i
23 * @brief Append phase information to CTA events file 23 * @brief Append phase information to CTA events file
24 - * @author Leonardo Di Venere 24 + * @author Joshua Cardenzana
25 */ 25 */
26 %{ 26 %{
27 /* Put headers and other declarations here that are needed for compilation */ 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 # Makefile.am for ctools module # 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 # This program is free software: you can redistribute it and/or modify # 7 # This program is free software: you can redistribute it and/or modify #
@@ -41,7 +41,8 @@ SUBDIRS = support \ @@ -41,7 +41,8 @@ SUBDIRS = support \
41 ctbutterfly \ 41 ctbutterfly \
42 ctulimit \ 42 ctulimit \
43 cterror \ 43 cterror \
44 - ctphase 44 + ctphase \
  45 + ctprob
45 46
46 # Scripts to be distributed 47 # Scripts to be distributed
47 scripts = ctools-setup \ 48 scripts = ctools-setup \
@@ -70,7 +71,8 @@ libctools_la_LIBADD = support/libsupport.la \ @@ -70,7 +71,8 @@ libctools_la_LIBADD = support/libsupport.la \
70 ctbutterfly/libctbutterfly.la \ 71 ctbutterfly/libctbutterfly.la \
71 ctulimit/libctulimit.la \ 72 ctulimit/libctulimit.la \
72 cterror/libcterror.la \ 73 cterror/libcterror.la \
73 - ctphase/libctphase.la 74 + ctphase/libctphase.la \
  75 + ctprob/libctprob.la
74 76
75 libctools_la_LDFLAGS = -version-info $(CTOOLS_LT_VERSION) @OPENMP_LIB_LDFLAGS@ 77 libctools_la_LDFLAGS = -version-info $(CTOOLS_LT_VERSION) @OPENMP_LIB_LDFLAGS@
76 78
src/ctbin/ctbin.cpp
@@ -55,7 +55,7 @@ @@ -55,7 +55,7 @@
55 * 55 *
56 * Constructs an empty event binning tool. 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 // Initialise members 60 // Initialise members
61 init_members(); 61 init_members();
@@ -73,7 +73,7 @@ ctbin::ctbin(void) : ctobservation(CTBIN_NAME, CTBIN_VERSION) @@ -73,7 +73,7 @@ ctbin::ctbin(void) : ctobservation(CTBIN_NAME, CTBIN_VERSION)
73 * Constructs event binning tool from an observation container. 73 * Constructs event binning tool from an observation container.
74 ***************************************************************************/ 74 ***************************************************************************/
75 ctbin::ctbin(const GObservations& obs) : 75 ctbin::ctbin(const GObservations& obs) :
76 - ctobservation(CTBIN_NAME, CTBIN_VERSION, obs) 76 + ctobservation(CTBIN_NAME, VERSION, obs)
77 { 77 {
78 // Initialise members 78 // Initialise members
79 init_members(); 79 init_members();
@@ -94,7 +94,7 @@ ctbin::ctbin(const GObservations&amp; obs) : @@ -94,7 +94,7 @@ ctbin::ctbin(const GObservations&amp; obs) :
94 * parameter setting. 94 * parameter setting.
95 ***************************************************************************/ 95 ***************************************************************************/
96 ctbin::ctbin(int argc, char *argv[]) : 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 // Initialise members 99 // Initialise members
100 init_members(); 100 init_members();
src/ctbin/ctbin.hpp
@@ -31,8 +31,7 @@ @@ -31,8 +31,7 @@
31 #include "ctobservation.hpp" 31 #include "ctobservation.hpp"
32 32
33 /* __Definitions _________________________________________________________ */ 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,7 +50,7 @@
50 /***********************************************************************//** 50 /***********************************************************************//**
51 * @brief Void constructor 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 // Initialise members 55 // Initialise members
56 init_members(); 56 init_members();
@@ -69,7 +69,7 @@ ctbkgcube::ctbkgcube(void) : ctobservation(CTBKGCUBE_NAME, CTBKGCUBE_VERSION) @@ -69,7 +69,7 @@ ctbkgcube::ctbkgcube(void) : ctobservation(CTBKGCUBE_NAME, CTBKGCUBE_VERSION)
69 * observations container. 69 * observations container.
70 ***************************************************************************/ 70 ***************************************************************************/
71 ctbkgcube::ctbkgcube(const GObservations& obs) : 71 ctbkgcube::ctbkgcube(const GObservations& obs) :
72 - ctobservation(CTBKGCUBE_NAME, CTBKGCUBE_VERSION, obs) 72 + ctobservation(CTBKGCUBE_NAME, VERSION, obs)
73 { 73 {
74 // Initialise members 74 // Initialise members
75 init_members(); 75 init_members();
@@ -87,7 +87,7 @@ ctbkgcube::ctbkgcube(const GObservations&amp; obs) : @@ -87,7 +87,7 @@ ctbkgcube::ctbkgcube(const GObservations&amp; obs) :
87 * @param[in] argv Array of command line arguments. 87 * @param[in] argv Array of command line arguments.
88 ***************************************************************************/ 88 ***************************************************************************/
89 ctbkgcube::ctbkgcube(int argc, char *argv[]) : 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 // Initialise members 92 // Initialise members
93 init_members(); 93 init_members();
src/ctbkgcube/ctbkgcube.hpp
@@ -33,8 +33,7 @@ @@ -33,8 +33,7 @@
33 #include "ctobservation.hpp" 33 #include "ctobservation.hpp"
34 34
35 /* __Definitions _________________________________________________________ */ 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 * ctbutterfly - butterfly calculation tool * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -52,7 +52,7 @@ @@ -52,7 +52,7 @@
52 /***********************************************************************//** 52 /***********************************************************************//**
53 * @brief Void constructor 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 // Initialise members 57 // Initialise members
58 init_members(); 58 init_members();
@@ -71,7 +71,7 @@ ctbutterfly::ctbutterfly(void) : ctlikelihood(CTBUTTERFLY_NAME, CTBUTTERFLY_VERS @@ -71,7 +71,7 @@ ctbutterfly::ctbutterfly(void) : ctlikelihood(CTBUTTERFLY_NAME, CTBUTTERFLY_VERS
71 * observations container. 71 * observations container.
72 ***************************************************************************/ 72 ***************************************************************************/
73 ctbutterfly::ctbutterfly(const GObservations& obs) : 73 ctbutterfly::ctbutterfly(const GObservations& obs) :
74 - ctlikelihood(CTBUTTERFLY_NAME, CTBUTTERFLY_VERSION, obs) 74 + ctlikelihood(CTBUTTERFLY_NAME, VERSION, obs)
75 { 75 {
76 // Initialise members 76 // Initialise members
77 init_members(); 77 init_members();
@@ -89,7 +89,7 @@ ctbutterfly::ctbutterfly(const GObservations&amp; obs) : @@ -89,7 +89,7 @@ ctbutterfly::ctbutterfly(const GObservations&amp; obs) :
89 * @param[in] argv Array of command line arguments. 89 * @param[in] argv Array of command line arguments.
90 ***************************************************************************/ 90 ***************************************************************************/
91 ctbutterfly::ctbutterfly(int argc, char *argv[]) : 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 // Initialise members 94 // Initialise members
95 init_members(); 95 init_members();
@@ -243,11 +243,14 @@ void ctbutterfly::run(void) @@ -243,11 +243,14 @@ void ctbutterfly::run(void)
243 m_obs.optimize(m_opt); 243 m_obs.optimize(m_opt);
244 m_obs.errors(m_opt); 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 GObservations::likelihood likelihood = m_obs.function(); 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 // Write optimizer, optimised model and covariance matrix into logger 255 // Write optimizer, optimised model and covariance matrix into logger
253 log_string(NORMAL, m_opt.print(m_chatter)); 256 log_string(NORMAL, m_opt.print(m_chatter));
@@ -271,157 +274,26 @@ void ctbutterfly::run(void) @@ -271,157 +274,26 @@ void ctbutterfly::run(void)
271 GObservations::likelihood likelihood = m_obs.function(); 274 GObservations::likelihood likelihood = m_obs.function();
272 likelihood.eval(pars); 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 // Write covariance matrix into logger 285 // Write covariance matrix into logger
280 log_string(EXPLICIT, m_covariance.print(m_chatter)); 286 log_string(EXPLICIT, m_covariance.print(m_chatter));
281 287
282 } // endif: covariance computation needed 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 // Write header into logger 298 // Write header into logger
427 log_header1(TERSE, "Results"); 299 log_header1(TERSE, "Results");
@@ -431,11 +303,11 @@ void ctbutterfly::run(void) @@ -431,11 +303,11 @@ void ctbutterfly::run(void)
431 303
432 // Write results into logger 304 // Write results into logger
433 log_value(NORMAL, "Intensity at "+gammalib::str(m_energies[k])+" MeV", 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 // Restore energy dispersion flag for all CTA observations 312 // Restore energy dispersion flag for all CTA observations
441 for (int i = 0; i < m_obs.size(); ++i) { 313 for (int i = 0; i < m_obs.size(); ++i) {
@@ -504,6 +376,7 @@ void ctbutterfly::init_members(void) @@ -504,6 +376,7 @@ void ctbutterfly::init_members(void)
504 { 376 {
505 // Initialise members 377 // Initialise members
506 m_srcname.clear(); 378 m_srcname.clear();
  379 + m_method.clear();
507 m_confidence = 0.68; 380 m_confidence = 0.68;
508 m_max_iter = 50; 381 m_max_iter = 50;
509 m_apply_edisp = false; 382 m_apply_edisp = false;
@@ -537,6 +410,7 @@ void ctbutterfly::copy_members(const ctbutterfly&amp; app) @@ -537,6 +410,7 @@ void ctbutterfly::copy_members(const ctbutterfly&amp; app)
537 { 410 {
538 // Copy attributes 411 // Copy attributes
539 m_srcname = app.m_srcname; 412 m_srcname = app.m_srcname;
  413 + m_method = app.m_method;
540 m_confidence = app.m_confidence; 414 m_confidence = app.m_confidence;
541 m_max_iter = app.m_max_iter; 415 m_max_iter = app.m_max_iter;
542 m_apply_edisp = app.m_apply_edisp; 416 m_apply_edisp = app.m_apply_edisp;
@@ -544,7 +418,7 @@ void ctbutterfly::copy_members(const ctbutterfly&amp; app) @@ -544,7 +418,7 @@ void ctbutterfly::copy_members(const ctbutterfly&amp; app)
544 m_chatter = app.m_chatter; 418 m_chatter = app.m_chatter;
545 m_ebounds = app.m_ebounds; 419 m_ebounds = app.m_ebounds;
546 m_outfile = app.m_outfile; 420 m_outfile = app.m_outfile;
547 - 421 +
548 // Copy protected members 422 // Copy protected members
549 m_covariance = app.m_covariance; 423 m_covariance = app.m_covariance;
550 m_energies = app.m_energies; 424 m_energies = app.m_energies;
@@ -583,16 +457,13 @@ void ctbutterfly::get_parameters(void) @@ -583,16 +457,13 @@ void ctbutterfly::get_parameters(void)
583 { 457 {
584 // Setup observations from "inobs" parameter 458 // Setup observations from "inobs" parameter
585 setup_observations(m_obs); 459 setup_observations(m_obs);
586 - 460 +
587 // Setup models from "inmodel" parameter 461 // Setup models from "inmodel" parameter
588 setup_models(m_obs, (*this)["srcname"].string()); 462 setup_models(m_obs, (*this)["srcname"].string());
589 463
590 // Get name of test source 464 // Get name of test source
591 m_srcname = (*this)["srcname"].string(); 465 m_srcname = (*this)["srcname"].string();
592 466
593 - // Check model name and type  
594 - check_model();  
595 -  
596 // Create energy boundaries from user parameters 467 // Create energy boundaries from user parameters
597 m_ebounds = create_ebounds(); 468 m_ebounds = create_ebounds();
598 469
@@ -600,18 +471,22 @@ void ctbutterfly::get_parameters(void) @@ -600,18 +471,22 @@ void ctbutterfly::get_parameters(void)
600 std::string matrixfilename = (*this)["matrix"].filename(); 471 std::string matrixfilename = (*this)["matrix"].filename();
601 if (matrixfilename != "NONE") { 472 if (matrixfilename != "NONE") {
602 std::string msg = "Loading of matrix from file not implemented yet. " 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 throw GException::feature_not_implemented(G_GET_PARAMETERS, msg); 476 throw GException::feature_not_implemented(G_GET_PARAMETERS, msg);
606 // m_covariance.load(matrixfilename); 477 // m_covariance.load(matrixfilename);
607 } 478 }
608 479
609 // Get remaining parameters 480 // Get remaining parameters
610 m_apply_edisp = (*this)["edisp"].boolean(); 481 m_apply_edisp = (*this)["edisp"].boolean();
  482 + m_method = (*this)["method"].string();
611 m_confidence = (*this)["confidence"].real(); 483 m_confidence = (*this)["confidence"].real();
612 m_fit = (*this)["fit"].boolean(); 484 m_fit = (*this)["fit"].boolean();
613 m_chatter = static_cast<GChatter>((*this)["chatter"].integer()); 485 m_chatter = static_cast<GChatter>((*this)["chatter"].integer());
614 486
  487 + // Check model name and type
  488 + check_model();
  489 +
615 // Optionally read ahead parameters so that they get correctly 490 // Optionally read ahead parameters so that they get correctly
616 // dumped into the log file 491 // dumped into the log file
617 if (read_ahead()) { 492 if (read_ahead()) {
@@ -627,6 +502,279 @@ void ctbutterfly::get_parameters(void) @@ -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 * @brief Check if sky model is valid 778 * @brief Check if sky model is valid
631 * 779 *
632 * @exception GException::invalid_value 780 * @exception GException::invalid_value
@@ -645,17 +793,22 @@ void ctbutterfly::check_model(void) @@ -645,17 +793,22 @@ void ctbutterfly::check_model(void)
645 GModelSky* model = dynamic_cast<GModelSky*>(models[m_srcname]); 793 GModelSky* model = dynamic_cast<GModelSky*>(models[m_srcname]);
646 if (model == NULL) { 794 if (model == NULL) {
647 std::string msg = "Source \""+m_srcname+"\" is not a sky model. " 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 throw GException::invalid_value(G_CHECK_MODEL, msg); 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 } // endif: source model existed 814 } // endif: source model existed
@@ -663,8 +816,8 @@ void ctbutterfly::check_model(void) @@ -663,8 +816,8 @@ void ctbutterfly::check_model(void)
663 // Otherwise throw an exception 816 // Otherwise throw an exception
664 else { 817 else {
665 std::string msg = "Source \""+m_srcname+"\" not found in model " 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 throw GException::invalid_value(G_CHECK_MODEL, msg); 821 throw GException::invalid_value(G_CHECK_MODEL, msg);
669 } 822 }
670 823
@@ -689,13 +842,13 @@ void ctbutterfly::check_model(void) @@ -689,13 +842,13 @@ void ctbutterfly::check_model(void)
689 * http://www.math.harvard.edu/archive/21b_fall_04/exhibits/2dmatrices/index.html 842 * http://www.math.harvard.edu/archive/21b_fall_04/exhibits/2dmatrices/index.html
690 ***************************************************************************/ 843 ***************************************************************************/
691 void ctbutterfly::eigenvectors(const double& a, 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 // Compute trace and determinant 853 // Compute trace and determinant
701 double trace = a + d; 854 double trace = a + d;
@@ -730,7 +883,7 @@ void ctbutterfly::eigenvectors(const double&amp; a, @@ -730,7 +883,7 @@ void ctbutterfly::eigenvectors(const double&amp; a,
730 // Normalize eigenvectors 883 // Normalize eigenvectors
731 *vector1 /= norm(*vector1); 884 *vector1 /= norm(*vector1);
732 *vector2 /= norm(*vector2); 885 *vector2 /= norm(*vector2);
733 - 886 +
734 // Return 887 // Return
735 return; 888 return;
736 } 889 }
src/ctbutterfly/ctbutterfly.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * ctbutterfly - butterfly calculation tool * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -33,8 +33,7 @@ @@ -33,8 +33,7 @@
33 #include "ctlikelihood.hpp" 33 #include "ctlikelihood.hpp"
34 34
35 /* __Definitions _________________________________________________________ */ 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,6 +76,10 @@ protected:
77 void copy_members(const ctbutterfly& app); 76 void copy_members(const ctbutterfly& app);
78 void free_members(void); 77 void free_members(void);
79 void get_parameters(void); 78 void get_parameters(void);
  79 + void gaussian_error_propagation(GModels& models);
  80 + void ellipsoid_boundary(GModels& models);
  81 +
  82 +
80 void check_model(void); 83 void check_model(void);
81 void eigenvectors(const double& a, 84 void eigenvectors(const double& a,
82 const double& b, 85 const double& b,
@@ -89,6 +92,7 @@ protected: @@ -89,6 +92,7 @@ protected:
89 92
90 // User parameters 93 // User parameters
91 std::string m_srcname; //!< Name of source to compute butterfly 94 std::string m_srcname; //!< Name of source to compute butterfly
  95 + std::string m_method; //!< Computation method
92 double m_confidence; //!< Confidence level 96 double m_confidence; //!< Confidence level
93 int m_max_iter; //!< Maximum number of iterations 97 int m_max_iter; //!< Maximum number of iterations
94 bool m_apply_edisp; //!< Apply energy dispersion? 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,6 +27,7 @@ caldb, s, a, &quot;prod2&quot;,,, &quot;Calibration database&quot;
27 irf, s, a, "South_0.5h",,, "Instrument response function" 27 irf, s, a, "South_0.5h",,, "Instrument response function"
28 edisp, b, h, no,,, "Apply energy dispersion?" 28 edisp, b, h, no,,, "Apply energy dispersion?"
29 outfile, f, a, "butterfly.txt",,, "Output ASCII file" 29 outfile, f, a, "butterfly.txt",,, "Output ASCII file"
  30 +method, s, h, GAUSSIAN, GAUSSIAN|ENVELOPE,,"Butterfly computation method"
30 31
31 # 32 #
32 # Butterfly parameters 33 # Butterfly parameters
src/ctcubemask/ctcubemask.cpp
@@ -51,7 +51,7 @@ @@ -51,7 +51,7 @@
51 /***********************************************************************//** 51 /***********************************************************************//**
52 * @brief Void constructor 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 // Initialise members 56 // Initialise members
57 init_members(); 57 init_members();
@@ -70,7 +70,7 @@ ctcubemask::ctcubemask(void) : ctobservation(CTCUBEMASK_NAME, CTCUBEMASK_VERSION @@ -70,7 +70,7 @@ ctcubemask::ctcubemask(void) : ctobservation(CTCUBEMASK_NAME, CTCUBEMASK_VERSION
70 * an observation container. 70 * an observation container.
71 ***************************************************************************/ 71 ***************************************************************************/
72 ctcubemask::ctcubemask(const GObservations& obs) : 72 ctcubemask::ctcubemask(const GObservations& obs) :
73 - ctobservation(CTCUBEMASK_NAME, CTCUBEMASK_VERSION, obs) 73 + ctobservation(CTCUBEMASK_NAME, VERSION, obs)
74 { 74 {
75 // Initialise members 75 // Initialise members
76 init_members(); 76 init_members();
@@ -89,7 +89,7 @@ ctcubemask::ctcubemask(const GObservations&amp; obs) : @@ -89,7 +89,7 @@ ctcubemask::ctcubemask(const GObservations&amp; obs) :
89 * @param[in] argv Array of command line arguments. 89 * @param[in] argv Array of command line arguments.
90 ***************************************************************************/ 90 ***************************************************************************/
91 ctcubemask::ctcubemask(int argc, char *argv[]) : 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 // Initialise members 94 // Initialise members
95 init_members(); 95 init_members();
src/ctcubemask/ctcubemask.hpp
@@ -35,8 +35,7 @@ @@ -35,8 +35,7 @@
35 #include "ctobservation.hpp" 35 #include "ctobservation.hpp"
36 36
37 /* __Definitions _________________________________________________________ */ 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,7 +52,7 @@
52 * 52 *
53 * Constructs an empty energy dispersion tool. 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 // Initialise members 57 // Initialise members
58 init_members(); 58 init_members();
@@ -71,7 +71,7 @@ ctedispcube::ctedispcube(void) : ctobservation(CTEDISPCUBE_NAME, CTEDISPCUBE_VER @@ -71,7 +71,7 @@ ctedispcube::ctedispcube(void) : ctobservation(CTEDISPCUBE_NAME, CTEDISPCUBE_VER
71 * in an observation container @p obs. 71 * in an observation container @p obs.
72 ***************************************************************************/ 72 ***************************************************************************/
73 ctedispcube::ctedispcube(const GObservations& obs) : 73 ctedispcube::ctedispcube(const GObservations& obs) :
74 - ctobservation(CTEDISPCUBE_NAME, CTEDISPCUBE_VERSION, obs) 74 + ctobservation(CTEDISPCUBE_NAME, VERSION, obs)
75 { 75 {
76 // Initialise members 76 // Initialise members
77 init_members(); 77 init_members();
@@ -92,7 +92,7 @@ ctedispcube::ctedispcube(const GObservations&amp; obs) : @@ -92,7 +92,7 @@ ctedispcube::ctedispcube(const GObservations&amp; obs) :
92 * on the command line. 92 * on the command line.
93 ***************************************************************************/ 93 ***************************************************************************/
94 ctedispcube::ctedispcube(int argc, char *argv[]) : 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 // Initialise members 97 // Initialise members
98 init_members(); 98 init_members();
src/ctedispcube/ctedispcube.hpp
@@ -33,8 +33,7 @@ @@ -33,8 +33,7 @@
33 #include "ctobservation.hpp" 33 #include "ctobservation.hpp"
34 34
35 /* __Definitions _________________________________________________________ */ 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,7 +52,7 @@
52 * 52 *
53 * Constructs an empty cterror tool. 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 // Initialise members 57 // Initialise members
58 init_members(); 58 init_members();
@@ -70,7 +70,7 @@ cterror::cterror(void) : ctlikelihood(CTERROR_NAME, CTERROR_VERSION) @@ -70,7 +70,7 @@ cterror::cterror(void) : ctlikelihood(CTERROR_NAME, CTERROR_VERSION)
70 * Constructs cterror tool from an observations container. 70 * Constructs cterror tool from an observations container.
71 ***************************************************************************/ 71 ***************************************************************************/
72 cterror::cterror(const GObservations& obs) : 72 cterror::cterror(const GObservations& obs) :
73 - ctlikelihood(CTERROR_NAME, CTERROR_VERSION, obs) 73 + ctlikelihood(CTERROR_NAME, VERSION, obs)
74 { 74 {
75 // Initialise members 75 // Initialise members
76 init_members(); 76 init_members();
@@ -90,7 +90,7 @@ cterror::cterror(const GObservations&amp; obs) : @@ -90,7 +90,7 @@ cterror::cterror(const GObservations&amp; obs) :
90 * parameters that are provided as command line arguments. 90 * parameters that are provided as command line arguments.
91 ***************************************************************************/ 91 ***************************************************************************/
92 cterror::cterror(int argc, char *argv[]) : 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 // Initialise members 95 // Initialise members
96 init_members(); 96 init_members();
src/cterror/cterror.hpp
@@ -31,8 +31,7 @@ @@ -31,8 +31,7 @@
31 #include "ctlikelihood.hpp" 31 #include "ctlikelihood.hpp"
32 32
33 /* __Definitions _________________________________________________________ */ 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,7 +50,7 @@
50 /***********************************************************************//** 50 /***********************************************************************//**
51 * @brief Void constructor 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 // Initialise members 55 // Initialise members
56 init_members(); 56 init_members();
@@ -69,7 +69,7 @@ ctexpcube::ctexpcube(void) : ctobservation(CTEXPCUBE_NAME, CTEXPCUBE_VERSION) @@ -69,7 +69,7 @@ ctexpcube::ctexpcube(void) : ctobservation(CTEXPCUBE_NAME, CTEXPCUBE_VERSION)
69 * observations container. 69 * observations container.
70 ***************************************************************************/ 70 ***************************************************************************/
71 ctexpcube::ctexpcube(const GObservations& obs) : 71 ctexpcube::ctexpcube(const GObservations& obs) :
72 - ctobservation(CTEXPCUBE_NAME, CTEXPCUBE_VERSION, obs) 72 + ctobservation(CTEXPCUBE_NAME, VERSION, obs)
73 { 73 {
74 // Initialise members 74 // Initialise members
75 init_members(); 75 init_members();
@@ -87,7 +87,7 @@ ctexpcube::ctexpcube(const GObservations&amp; obs) : @@ -87,7 +87,7 @@ ctexpcube::ctexpcube(const GObservations&amp; obs) :
87 * @param[in] argv Array of command line arguments. 87 * @param[in] argv Array of command line arguments.
88 ***************************************************************************/ 88 ***************************************************************************/
89 ctexpcube::ctexpcube(int argc, char *argv[]) : 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 // Initialise members 92 // Initialise members
93 init_members(); 93 init_members();
src/ctexpcube/ctexpcube.hpp
@@ -33,8 +33,7 @@ @@ -33,8 +33,7 @@
33 #include "ctobservation.hpp" 33 #include "ctobservation.hpp"
34 34
35 /* __Definitions _________________________________________________________ */ 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 * ctlike - Maximum likelihood fitting tool * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -48,7 +48,7 @@ @@ -48,7 +48,7 @@
48 /***********************************************************************//** 48 /***********************************************************************//**
49 * @brief Void constructor 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 // Initialise members 53 // Initialise members
54 init_members(); 54 init_members();
@@ -66,7 +66,7 @@ ctlike::ctlike(void) : ctlikelihood(CTLIKE_NAME, CTLIKE_VERSION) @@ -66,7 +66,7 @@ ctlike::ctlike(void) : ctlikelihood(CTLIKE_NAME, CTLIKE_VERSION)
66 * Constructs ctlike tool from an observations container. 66 * Constructs ctlike tool from an observations container.
67 ***************************************************************************/ 67 ***************************************************************************/
68 ctlike::ctlike(const GObservations& obs) : 68 ctlike::ctlike(const GObservations& obs) :
69 - ctlikelihood(CTLIKE_NAME, CTLIKE_VERSION, obs) 69 + ctlikelihood(CTLIKE_NAME, VERSION, obs)
70 { 70 {
71 // Initialise members 71 // Initialise members
72 init_members(); 72 init_members();
@@ -86,7 +86,7 @@ ctlike::ctlike(const GObservations&amp; obs) : @@ -86,7 +86,7 @@ ctlike::ctlike(const GObservations&amp; obs) :
86 * that are provided as command line arguments. 86 * that are provided as command line arguments.
87 ***************************************************************************/ 87 ***************************************************************************/
88 ctlike::ctlike(int argc, char *argv[]) : 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 // Initialise members 91 // Initialise members
92 init_members(); 92 init_members();
@@ -321,8 +321,13 @@ void ctlike::run(void) @@ -321,8 +321,13 @@ void ctlike::run(void)
321 /***********************************************************************//** 321 /***********************************************************************//**
322 * @brief Save results 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 void ctlike::save(void) 332 void ctlike::save(void)
328 { 333 {
src/ctlike/ctlike.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * ctlike - Maximum likelihood fitting tool * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -31,8 +31,7 @@ @@ -31,8 +31,7 @@
31 #include "ctlikelihood.hpp" 31 #include "ctlikelihood.hpp"
32 32
33 /* __Definitions _________________________________________________________ */ 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,17 +67,17 @@ protected:
68 double reoptimize_lm(void); 67 double reoptimize_lm(void);
69 68
70 // User parameters 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 // Members 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 #endif /* CTLIKE_HPP */ 83 #endif /* CTLIKE_HPP */
src/ctmapcube/ctmapcube.cpp
@@ -50,7 +50,7 @@ @@ -50,7 +50,7 @@
50 /***********************************************************************//** 50 /***********************************************************************//**
51 * @brief Void constructor 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 // Initialise members 55 // Initialise members
56 init_members(); 56 init_members();
@@ -67,7 +67,7 @@ ctmapcube::ctmapcube(void) : ctool(CTMAPCUBE_NAME, CTMAPCUBE_VERSION) @@ -67,7 +67,7 @@ ctmapcube::ctmapcube(void) : ctool(CTMAPCUBE_NAME, CTMAPCUBE_VERSION)
67 * @param[in] argv Array of command line arguments. 67 * @param[in] argv Array of command line arguments.
68 ***************************************************************************/ 68 ***************************************************************************/
69 ctmapcube::ctmapcube(int argc, char *argv[]) : 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 // Initialise members 72 // Initialise members
73 init_members(); 73 init_members();
src/ctmapcube/ctmapcube.hpp
@@ -33,8 +33,7 @@ @@ -33,8 +33,7 @@
33 #include "ctool.hpp" 33 #include "ctool.hpp"
34 34
35 /* __Definitions _________________________________________________________ */ 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,7 +53,7 @@ const GEnergy g_energy_margin(1.0e-12, &quot;TeV&quot;);
53 /***********************************************************************//** 53 /***********************************************************************//**
54 * @brief Void constructor 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 // Initialise members 58 // Initialise members
59 init_members(); 59 init_members();
@@ -72,7 +72,7 @@ ctmodel::ctmodel(void) : ctobservation(CTMODEL_NAME, CTMODEL_VERSION) @@ -72,7 +72,7 @@ ctmodel::ctmodel(void) : ctobservation(CTMODEL_NAME, CTMODEL_VERSION)
72 * observations container. 72 * observations container.
73 ***************************************************************************/ 73 ***************************************************************************/
74 ctmodel::ctmodel(const GObservations& obs) : 74 ctmodel::ctmodel(const GObservations& obs) :
75 - ctobservation(CTMODEL_NAME, CTMODEL_VERSION, obs) 75 + ctobservation(CTMODEL_NAME, VERSION, obs)
76 { 76 {
77 // Initialise members 77 // Initialise members
78 init_members(); 78 init_members();
@@ -90,7 +90,7 @@ ctmodel::ctmodel(const GObservations&amp; obs) : @@ -90,7 +90,7 @@ ctmodel::ctmodel(const GObservations&amp; obs) :
90 * @param[in] argv Array of command line arguments. 90 * @param[in] argv Array of command line arguments.
91 ***************************************************************************/ 91 ***************************************************************************/
92 ctmodel::ctmodel(int argc, char *argv[]) : 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 // Initialise members 95 // Initialise members
96 init_members(); 96 init_members();
src/ctmodel/ctmodel.hpp
@@ -33,8 +33,7 @@ @@ -33,8 +33,7 @@
33 #include "ctobservation.hpp" 33 #include "ctobservation.hpp"
34 34
35 /* __Definitions _________________________________________________________ */ 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,7 +67,7 @@ const double g_roi_margin = 0.5; //!&lt; Simulation radius margin (degrees)
67 * 67 *
68 * Constructs an empty ctobssim tool. 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 // Initialise members 72 // Initialise members
73 init_members(); 73 init_members();
@@ -85,7 +85,7 @@ ctobssim::ctobssim(void) : ctobservation(CTOBSSIM_NAME, CTOBSSIM_VERSION) @@ -85,7 +85,7 @@ ctobssim::ctobssim(void) : ctobservation(CTOBSSIM_NAME, CTOBSSIM_VERSION)
85 * Constructs ctobssim tool from an observation container. 85 * Constructs ctobssim tool from an observation container.
86 ***************************************************************************/ 86 ***************************************************************************/
87 ctobssim::ctobssim(const GObservations& obs) : 87 ctobssim::ctobssim(const GObservations& obs) :
88 - ctobservation(CTOBSSIM_NAME, CTOBSSIM_VERSION, obs) 88 + ctobservation(CTOBSSIM_NAME, VERSION, obs)
89 { 89 {
90 // Initialise members 90 // Initialise members
91 init_members(); 91 init_members();
@@ -105,7 +105,7 @@ ctobssim::ctobssim(const GObservations&amp; obs) : @@ -105,7 +105,7 @@ ctobssim::ctobssim(const GObservations&amp; obs) :
105 * setting. 105 * setting.
106 ***************************************************************************/ 106 ***************************************************************************/
107 ctobssim::ctobssim(int argc, char *argv[]) : 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 // Initialise members 110 // Initialise members
111 init_members(); 111 init_members();
@@ -1471,7 +1471,8 @@ void ctobssim::simulate_background(GCTAObservation* obs, @@ -1471,7 +1471,8 @@ void ctobssim::simulate_background(GCTAObservation* obs,
1471 1471
1472 // Debug code: signal that we step into the response MC method 1472 // Debug code: signal that we step into the response MC method
1473 #if defined(G_BACKGROUND_DEBUG) 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 #endif 1476 #endif
1476 1477
1477 // Get simulated CTA event list. Note that this method 1478 // Get simulated CTA event list. Note that this method
@@ -1481,7 +1482,8 @@ void ctobssim::simulate_background(GCTAObservation* obs, @@ -1481,7 +1482,8 @@ void ctobssim::simulate_background(GCTAObservation* obs,
1481 1482
1482 // Debug code: signal that we came back 1483 // Debug code: signal that we came back
1483 #if defined(G_BACKGROUND_DEBUG) 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 #endif 1487 #endif
1486 1488
1487 // Continue only if we got a CTA event list 1489 // Continue only if we got a CTA event list
src/ctobssim/ctobssim.hpp
@@ -33,8 +33,7 @@ @@ -33,8 +33,7 @@
33 #include "ctobservation.hpp" 33 #include "ctobservation.hpp"
34 34
35 /* __Definitions _________________________________________________________ */ 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 # Makefile.am for ctphase tool # 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 # This program is free software: you can redistribute it and/or modify # 7 # This program is free software: you can redistribute it and/or modify #
src/ctphase/ctphase.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 * ctphase - Append phase information to CTA events file * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 /** 21 /**
22 * @file ctphase.cpp 22 * @file ctphase.cpp
23 * @brief Append phase information to CTA events file 23 * @brief Append phase information to CTA events file
24 - * @author Leonardo Di Venere 24 + * @author Joshua Cardenzana
25 */ 25 */
26 26
27 /* __ Includes ___________________________________________________________ */ 27 /* __ Includes ___________________________________________________________ */
@@ -33,15 +33,12 @@ @@ -33,15 +33,12 @@
33 #include "GTools.hpp" 33 #include "GTools.hpp"
34 34
35 /* __ Method name definitions ____________________________________________ */ 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 /* __ Debug definitions __________________________________________________ */ 39 /* __ Debug definitions __________________________________________________ */
42 40
43 /* __ Coding definitions _________________________________________________ */ 41 /* __ Coding definitions _________________________________________________ */
44 -//#define G_USE_MKSTEMP //!< Use mkstemp for temporary filename  
45 42
46 43
47 /*========================================================================== 44 /*==========================================================================
@@ -53,7 +50,7 @@ @@ -53,7 +50,7 @@
53 /***********************************************************************//** 50 /***********************************************************************//**
54 * @brief Void constructor 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 // Initialise members 55 // Initialise members
59 init_members(); 56 init_members();
@@ -72,7 +69,7 @@ ctphase::ctphase(void) : ctobservation(CTPHASE_NAME, CTPHASE_VERSION) @@ -72,7 +69,7 @@ ctphase::ctphase(void) : ctobservation(CTPHASE_NAME, CTPHASE_VERSION)
72 * provided in an observation container. 69 * provided in an observation container.
73 ***************************************************************************/ 70 ***************************************************************************/
74 ctphase::ctphase(const GObservations& obs) : 71 ctphase::ctphase(const GObservations& obs) :
75 - ctobservation(CTPHASE_NAME, CTPHASE_VERSION, obs) 72 + ctobservation(CTPHASE_NAME, VERSION, obs)
76 { 73 {
77 // Initialise members 74 // Initialise members
78 init_members(); 75 init_members();
@@ -91,7 +88,7 @@ ctphase::ctphase(const GObservations&amp; obs) : @@ -91,7 +88,7 @@ ctphase::ctphase(const GObservations&amp; obs) :
91 * @param[in] argv Array of command line arguments. 88 * @param[in] argv Array of command line arguments.
92 ***************************************************************************/ 89 ***************************************************************************/
93 ctphase::ctphase(int argc, char *argv[]) : 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 // Initialise members 93 // Initialise members
97 init_members(); 94 init_members();
@@ -203,10 +200,11 @@ void ctphase::clear(void) @@ -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 * This method reads in the application parameters and loops over all 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 void ctphase::run(void) 209 void ctphase::run(void)
212 { 210 {
@@ -222,118 +220,22 @@ void ctphase::run(void) @@ -222,118 +220,22 @@ void ctphase::run(void)
222 log_observations(NORMAL, m_obs, "Input observation"); 220 log_observations(NORMAL, m_obs, "Input observation");
223 221
224 // Write header into logger 222 // Write header into logger
225 - log_header1(TERSE, "Appending phase informaiton"); 223 + log_header1(TERSE, "Compute event phase");
226 224
227 // Initialise counters 225 // Initialise counters
228 int n_observations = 0; 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 // Increment counter 232 // Increment counter
262 n_observations++; 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 // If more than a single observation has been handled then make sure that 240 // If more than a single observation has been handled then make sure that
339 // an XML file will be used for storage 241 // an XML file will be used for storage
@@ -380,12 +282,12 @@ void ctphase::save(void) @@ -380,12 +282,12 @@ void ctphase::save(void)
380 282
381 // Case A: Save event file(s) and XML metadata information 283 // Case A: Save event file(s) and XML metadata information
382 if (m_use_xml) { 284 if (m_use_xml) {
383 - save_xml(); 285 + save_events_xml();
384 } 286 }
385 287
386 // Case B: Save event file as FITS file 288 // Case B: Save event file as FITS file
387 else { 289 else {
388 - save_fits(); 290 + save_events_fits();
389 } 291 }
390 292
391 // Return 293 // Return
@@ -459,15 +361,10 @@ void ctphase::publish(const std::string&amp; name) @@ -459,15 +361,10 @@ void ctphase::publish(const std::string&amp; name)
459 void ctphase::init_members(void) 361 void ctphase::init_members(void)
460 { 362 {
461 // Initialise parameters 363 // Initialise parameters
462 - m_outobs.clear();  
463 - m_prefix.clear();  
464 - m_phase.clear();  
465 m_chatter = static_cast<GChatter>(2); 364 m_chatter = static_cast<GChatter>(2);
466 365
467 // Initialise protected members 366 // Initialise protected members
468 - m_infiles.clear();  
469 - m_evtname.clear();  
470 - m_gtiname.clear(); 367 + m_phase.clear();
471 368
472 // Return 369 // Return
473 return; 370 return;
@@ -482,15 +379,10 @@ void ctphase::init_members(void) @@ -482,15 +379,10 @@ void ctphase::init_members(void)
482 void ctphase::copy_members(const ctphase& app) 379 void ctphase::copy_members(const ctphase& app)
483 { 380 {
484 // Copy parameters 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 // Copy protected members 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 // Return 387 // Return
496 return; 388 return;
@@ -502,8 +394,6 @@ void ctphase::copy_members(const ctphase&amp; app) @@ -502,8 +394,6 @@ void ctphase::copy_members(const ctphase&amp; app)
502 ***************************************************************************/ 394 ***************************************************************************/
503 void ctphase::free_members(void) 395 void ctphase::free_members(void)
504 { 396 {
505 - m_phase.clear();  
506 -  
507 // Return 397 // Return
508 return; 398 return;
509 } 399 }
@@ -526,381 +416,81 @@ void ctphase::get_parameters(void) @@ -526,381 +416,81 @@ void ctphase::get_parameters(void)
526 // information and do not accept counts cubes. 416 // information and do not accept counts cubes.
527 setup_observations(m_obs, false, true, false); 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 // Return 495 // Return
906 return; 496 return;
@@ -908,169 +498,68 @@ void ctphase::save_fits(void) @@ -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 // Return 564 // Return
1076 return; 565 return;
src/ctphase/ctphase.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * ctphase - Append phase information to CTA events file * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 /** 21 /**
22 * @file ctphase.hpp 22 * @file ctphase.hpp
23 * @brief Append phase information to CTA events file 23 * @brief Append phase information to CTA events file
24 - * @author Leonardo Di Venere 24 + * @author Joshua Cardenzana
25 */ 25 */
26 26
27 #ifndef CTPHASE_HPP 27 #ifndef CTPHASE_HPP
@@ -35,8 +35,7 @@ @@ -35,8 +35,7 @@
35 #include "ctobservation.hpp" 35 #include "ctobservation.hpp"
36 36
37 /* __Definitions _________________________________________________________ */ 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,38 +64,17 @@ public:
65 64
66 protected: 65 protected:
67 // Protected methods 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 // User parameters 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 // Protected members 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,11 +5,10 @@
5 # ------------------------------------------------------------------------- # 5 # ------------------------------------------------------------------------- #
6 # # 6 # #
7 # File: ctphase.par # 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 # Purpose: Parameter file for the ctphase application # 13 # Purpose: Parameter file for the ctphase application #
15 # # 14 # #
@@ -17,20 +16,21 @@ @@ -17,20 +16,21 @@
17 # 16 #
18 # General parameters 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 # Phase information parameters 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 # Standard parameters 36 # Standard parameters
src/ctphase/main.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 * ctphase - Append phase information to CTA events file * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 /** 21 /**
22 * @file ctphase/main.cpp 22 * @file ctphase/main.cpp
23 * @brief Append phase information to CTA events file 23 * @brief Append phase information to CTA events file
24 - * @author Leonardo Di Venere 24 + * @author Joshua Cardenzana
25 */ 25 */
26 26
27 /* __ Includes ___________________________________________________________ */ 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,7 +49,7 @@
49 /***********************************************************************//** 49 /***********************************************************************//**
50 * @brief Void constructor 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 // Initialise members 54 // Initialise members
55 init_members(); 55 init_members();
@@ -68,7 +68,7 @@ ctpsfcube::ctpsfcube(void) : ctobservation(CTPSFCUBE_NAME, CTPSFCUBE_VERSION) @@ -68,7 +68,7 @@ ctpsfcube::ctpsfcube(void) : ctobservation(CTPSFCUBE_NAME, CTPSFCUBE_VERSION)
68 * observations container. 68 * observations container.
69 ***************************************************************************/ 69 ***************************************************************************/
70 ctpsfcube::ctpsfcube(const GObservations& obs) : 70 ctpsfcube::ctpsfcube(const GObservations& obs) :
71 - ctobservation(CTPSFCUBE_NAME, CTPSFCUBE_VERSION, obs) 71 + ctobservation(CTPSFCUBE_NAME, VERSION, obs)
72 { 72 {
73 // Initialise members 73 // Initialise members
74 init_members(); 74 init_members();
@@ -86,7 +86,7 @@ ctpsfcube::ctpsfcube(const GObservations&amp; obs) : @@ -86,7 +86,7 @@ ctpsfcube::ctpsfcube(const GObservations&amp; obs) :
86 * @param[in] argv Array of command line arguments. 86 * @param[in] argv Array of command line arguments.
87 ***************************************************************************/ 87 ***************************************************************************/
88 ctpsfcube::ctpsfcube(int argc, char *argv[]) : 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 // Initialise members 91 // Initialise members
92 init_members(); 92 init_members();
src/ctpsfcube/ctpsfcube.hpp
@@ -33,8 +33,7 @@ @@ -33,8 +33,7 @@
33 #include "ctobservation.hpp" 33 #include "ctobservation.hpp"
34 34
35 /* __Definitions _________________________________________________________ */ 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,7 +53,7 @@
53 /***********************************************************************//** 53 /***********************************************************************//**
54 * @brief Void constructor 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 // Initialise members 58 // Initialise members
59 init_members(); 59 init_members();
@@ -72,7 +72,7 @@ ctselect::ctselect(void) : ctobservation(CTSELECT_NAME, CTSELECT_VERSION) @@ -72,7 +72,7 @@ ctselect::ctselect(void) : ctobservation(CTSELECT_NAME, CTSELECT_VERSION)
72 * provided in an observation container. 72 * provided in an observation container.
73 ***************************************************************************/ 73 ***************************************************************************/
74 ctselect::ctselect(const GObservations& obs) : 74 ctselect::ctselect(const GObservations& obs) :
75 - ctobservation(CTSELECT_NAME, CTSELECT_VERSION, obs) 75 + ctobservation(CTSELECT_NAME, VERSION, obs)
76 { 76 {
77 // Initialise members 77 // Initialise members
78 init_members(); 78 init_members();
@@ -91,7 +91,7 @@ ctselect::ctselect(const GObservations&amp; obs) : @@ -91,7 +91,7 @@ ctselect::ctselect(const GObservations&amp; obs) :
91 * @param[in] argv Array of command line arguments. 91 * @param[in] argv Array of command line arguments.
92 ***************************************************************************/ 92 ***************************************************************************/
93 ctselect::ctselect(int argc, char *argv[]) : 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 // Initialise members 96 // Initialise members
97 init_members(); 97 init_members();
@@ -1175,39 +1175,6 @@ std::string ctselect::set_outfile_name(const std::string&amp; filename) const @@ -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 * @brief Save event list in FITS format. 1178 * @brief Save event list in FITS format.
1212 * 1179 *
1213 * Save the event list as a FITS file. The file name of the FITS file is 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,109 +1292,3 @@ void ctselect::save_xml(void)
1325 // Return 1292 // Return
1326 return; 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 * ctselect - Data selection tool * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -35,8 +35,7 @@ @@ -35,8 +35,7 @@
35 #include "ctobservation.hpp" 35 #include "ctobservation.hpp"
36 36
37 /* __Definitions _________________________________________________________ */ 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,15 +77,8 @@ protected:
78 std::string check_infile(const std::string& filename, 77 std::string check_infile(const std::string& filename,
79 const std::string& evtname) const; 78 const std::string& evtname) const;
80 std::string set_outfile_name(const std::string& filename) const; 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 void save_fits(void); 80 void save_fits(void);
84 void save_xml(void); 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 // User parameters 83 // User parameters
92 std::string m_outobs; //!< Output event list or XML file 84 std::string m_outobs; //!< Output event list or XML file
src/ctskymap/ctskymap.cpp
@@ -52,7 +52,7 @@ @@ -52,7 +52,7 @@
52 * 52 *
53 * Constructs an empty sky mapping tool. 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 // Initialise members 57 // Initialise members
58 init_members(); 58 init_members();
@@ -70,7 +70,7 @@ ctskymap::ctskymap(void) : ctobservation(CTSKYMAP_NAME, CTSKYMAP_VERSION) @@ -70,7 +70,7 @@ ctskymap::ctskymap(void) : ctobservation(CTSKYMAP_NAME, CTSKYMAP_VERSION)
70 * Constructs sky mapping tool from an observation container. 70 * Constructs sky mapping tool from an observation container.
71 ***************************************************************************/ 71 ***************************************************************************/
72 ctskymap::ctskymap(const GObservations& obs) : 72 ctskymap::ctskymap(const GObservations& obs) :
73 - ctobservation(CTSKYMAP_NAME, CTSKYMAP_VERSION, obs) 73 + ctobservation(CTSKYMAP_NAME, VERSION, obs)
74 { 74 {
75 // Initialise members 75 // Initialise members
76 init_members(); 76 init_members();
@@ -91,7 +91,7 @@ ctskymap::ctskymap(const GObservations&amp; obs) : @@ -91,7 +91,7 @@ ctskymap::ctskymap(const GObservations&amp; obs) :
91 * parameter setting. 91 * parameter setting.
92 ***************************************************************************/ 92 ***************************************************************************/
93 ctskymap::ctskymap(int argc, char *argv[]) : 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 // Initialise members 96 // Initialise members
97 init_members(); 97 init_members();
src/ctskymap/ctskymap.hpp
@@ -32,8 +32,7 @@ @@ -32,8 +32,7 @@
32 #include "ctobservation.hpp" 32 #include "ctobservation.hpp"
33 33
34 /* __Definitions _________________________________________________________ */ 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,7 +51,7 @@
51 * 51 *
52 * Constructs an empty cttsmap tool. 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 // Initialise members 56 // Initialise members
57 init_members(); 57 init_members();
@@ -69,7 +69,7 @@ cttsmap::cttsmap(void) : ctlikelihood(CTTSMAP_NAME, CTTSMAP_VERSION) @@ -69,7 +69,7 @@ cttsmap::cttsmap(void) : ctlikelihood(CTTSMAP_NAME, CTTSMAP_VERSION)
69 * Constructs cttsmap tool from an observations container. 69 * Constructs cttsmap tool from an observations container.
70 ***************************************************************************/ 70 ***************************************************************************/
71 cttsmap::cttsmap(const GObservations& obs) : 71 cttsmap::cttsmap(const GObservations& obs) :
72 - ctlikelihood(CTTSMAP_NAME, CTTSMAP_VERSION, obs) 72 + ctlikelihood(CTTSMAP_NAME, VERSION, obs)
73 { 73 {
74 // Initialise members 74 // Initialise members
75 init_members(); 75 init_members();
@@ -89,7 +89,7 @@ cttsmap::cttsmap(const GObservations&amp; obs) : @@ -89,7 +89,7 @@ cttsmap::cttsmap(const GObservations&amp; obs) :
89 * that are provided as command line arguments. 89 * that are provided as command line arguments.
90 ***************************************************************************/ 90 ***************************************************************************/
91 cttsmap::cttsmap(int argc, char *argv[]) : 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 // Initialise members 94 // Initialise members
95 init_members(); 95 init_members();
src/cttsmap/cttsmap.hpp
@@ -31,8 +31,7 @@ @@ -31,8 +31,7 @@
31 #include "ctlikelihood.hpp" 31 #include "ctlikelihood.hpp"
32 32
33 /* __Definitions _________________________________________________________ */ 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,7 +53,7 @@
53 * 53 *
54 * Constructs an empty ctulimit tool. 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 // Initialise members 58 // Initialise members
59 init_members(); 59 init_members();
@@ -71,7 +71,7 @@ ctulimit::ctulimit(void) : ctlikelihood(CTULIMIT_NAME, CTULIMIT_VERSION) @@ -71,7 +71,7 @@ ctulimit::ctulimit(void) : ctlikelihood(CTULIMIT_NAME, CTULIMIT_VERSION)
71 * Constructs ctulimit tool from an observations container. 71 * Constructs ctulimit tool from an observations container.
72 ***************************************************************************/ 72 ***************************************************************************/
73 ctulimit::ctulimit(const GObservations& obs) : 73 ctulimit::ctulimit(const GObservations& obs) :
74 - ctlikelihood(CTULIMIT_NAME, CTULIMIT_VERSION, obs) 74 + ctlikelihood(CTULIMIT_NAME, VERSION, obs)
75 { 75 {
76 // Initialise members 76 // Initialise members
77 init_members(); 77 init_members();
@@ -92,7 +92,7 @@ ctulimit::ctulimit(const GObservations&amp; obs) : @@ -92,7 +92,7 @@ ctulimit::ctulimit(const GObservations&amp; obs) :
92 * parameters that are provided as command line arguments. 92 * parameters that are provided as command line arguments.
93 ***************************************************************************/ 93 ***************************************************************************/
94 ctulimit::ctulimit(int argc, char *argv[]) : 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 // Initialise members 97 // Initialise members
98 init_members(); 98 init_members();
src/ctulimit/ctulimit.hpp
@@ -31,8 +31,7 @@ @@ -31,8 +31,7 @@
31 #include "ctlikelihood.hpp" 31 #include "ctlikelihood.hpp"
32 32
33 /* __Definitions _________________________________________________________ */ 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 * ctobservation - Base class for observation tools * 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 * This program is free software: you can redistribute it and/or modify * 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,3 +326,123 @@ const GCTAObservation* ctobservation::next_unbinned_observation(void) const
326 // Return next CTA observation 326 // Return next CTA observation
327 return obs; 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 * ctobservation - Base class for observation tools * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -78,6 +78,8 @@ protected: @@ -78,6 +78,8 @@ protected:
78 void init_members(void); 78 void init_members(void);
79 void copy_members(const ctobservation& app); 79 void copy_members(const ctobservation& app);
80 void free_members(void); 80 void free_members(void);
  81 + void save_events_fits(void);
  82 + void save_events_xml(void);
81 83
82 // Protected members 84 // Protected members
83 GObservations m_obs; //!< Observation container 85 GObservations m_obs; //!< Observation container
src/support/ctool.cpp
@@ -1028,6 +1028,41 @@ GCTARoi ctool::get_roi(void) @@ -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 * @brief Set response for all CTA observations in container 1066 * @brief Set response for all CTA observations in container
1032 * 1067 *
1033 * @param[in,out] obs Observation container 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,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 * @brief Set warning string if there are too few energies 1907 * @brief Set warning string if there are too few energies
1734 * 1908 *
1735 * @param[in] energies Energies. 1909 * @param[in] energies Energies.
src/support/ctool.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * ctool - ctool base class * 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -104,6 +104,7 @@ protected: @@ -104,6 +104,7 @@ protected:
104 104
105 // Protected methods that extract user parameters 105 // Protected methods that extract user parameters
106 GCTARoi get_roi(void); 106 GCTARoi get_roi(void);
  107 + std::string set_outfile_name(const std::string& filename);
107 108
108 // Protected support methods 109 // Protected support methods
109 void set_response(GObservations& obs); 110 void set_response(GObservations& obs);
@@ -121,6 +122,13 @@ protected: @@ -121,6 +122,13 @@ protected:
121 std::vector<bool> cube_layer_usage(const GEbounds& cube_ebounds, 122 std::vector<bool> cube_layer_usage(const GEbounds& cube_ebounds,
122 const GEbounds& list_ebounds) const; 123 const GEbounds& list_ebounds) const;
123 bool is_valid_filename(const GFilename& filename) const; 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 // Protected warning strings 133 // Protected warning strings
126 std::string warn_too_few_energies(const GEnergies& energies) const; 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,7 +2,7 @@
2 # ========================================================================== 2 # ==========================================================================
3 # This scripts performs unit tests for the cssens script 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 # This program is free software: you can redistribute it and/or modify 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 8 # it under the terms of the GNU General Public License as published by
@@ -168,7 +168,7 @@ class Test(test): @@ -168,7 +168,7 @@ class Test(test):
168 # Check dimensions 168 # Check dimensions
169 self.test_value(results.nrows(), 2, 169 self.test_value(results.nrows(), 2,
170 'Check number of rows in sensitivity file') 170 'Check number of rows in sensitivity file')
171 - self.test_value(results.ncols(), 7, 171 + self.test_value(results.ncols(), 10,
172 'Check number of columns in sensitivity file') 172 'Check number of columns in sensitivity file')
173 173
174 # Return 174 # Return
test/test_ctbutterfly.py
@@ -168,6 +168,9 @@ class Test(test): @@ -168,6 +168,9 @@ class Test(test):
168 cpy_butterfly['outfile'] = 'ctbutterfly_py3.dat' 168 cpy_butterfly['outfile'] = 'ctbutterfly_py3.dat'
169 cpy_butterfly['logfile'] = 'ctbutterfly_py3.log' 169 cpy_butterfly['logfile'] = 'ctbutterfly_py3.log'
170 cpy_butterfly['chatter'] = 4 170 cpy_butterfly['chatter'] = 4
  171 +
  172 + # Execute ctbutterfly tool
  173 + cpy_butterfly.logFileOpen() # Make sure we get a log file
171 cpy_butterfly.execute() 174 cpy_butterfly.execute()
172 175
173 # Check result file 176 # Check result file
test/test_ctphase.py
1 #! /usr/bin/env python 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 # This program is free software: you can redistribute it and/or modify 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 8 # it under the terms of the GNU General Public License as published by
@@ -40,6 +40,8 @@ class Test(test): @@ -40,6 +40,8 @@ class Test(test):
40 test.__init__(self) 40 test.__init__(self)
41 41
42 # Set test data 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 self._invalid_events = self._datadir + '/invalid_event_list.fits' 45 self._invalid_events = self._datadir + '/invalid_event_list.fits'
44 46
45 # Return 47 # Return
@@ -70,10 +72,9 @@ class Test(test): @@ -70,10 +72,9 @@ class Test(test):
70 72
71 # Setup ctphase command 73 # Setup ctphase command
72 cmd = ctphase+' inobs="'+self._events+'"'+ \ 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 # Check if execution of wrong command fails 79 # Check if execution of wrong command fails
79 self.test_assert(self._execute('command_that_does_not_exist') != 0, 80 self.test_assert(self._execute('command_that_does_not_exist') != 0,
@@ -88,10 +89,9 @@ class Test(test): @@ -88,10 +89,9 @@ class Test(test):
88 89
89 # Setup ctphase command 90 # Setup ctphase command
90 cmd = ctphase+' inobs="event_file_that_does_not_exist.fits"'+ \ 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 # Check if execution failed 96 # Check if execution failed
97 self.test_assert(self._execute(cmd) != 0, 97 self.test_assert(self._execute(cmd) != 0,
@@ -124,6 +124,8 @@ class Test(test): @@ -124,6 +124,8 @@ class Test(test):
124 self._check_obs(phase.obs(), nobs=0) 124 self._check_obs(phase.obs(), nobs=0)
125 125
126 # Check that saving does nothing 126 # Check that saving does nothing
  127 + phase['inmodel'] = self._model_file
  128 + phase['source'] = 'Crab'
127 phase['outobs'] = 'ctphase_py0.fits' 129 phase['outobs'] = 'ctphase_py0.fits'
128 phase['logfile'] = 'ctphase_py0.log' 130 phase['logfile'] = 'ctphase_py0.log'
129 phase.logFileOpen() 131 phase.logFileOpen()
@@ -136,11 +138,8 @@ class Test(test): @@ -136,11 +138,8 @@ class Test(test):
136 138
137 # Now set ctphase parameters 139 # Now set ctphase parameters
138 phase['inobs'] = self._events 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 phase['outobs'] = 'ctphase_py1.fits' 143 phase['outobs'] = 'ctphase_py1.fits'
145 phase['logfile'] = 'ctphase_py1.log' 144 phase['logfile'] = 'ctphase_py1.log'
146 phase['chatter'] = 2 145 phase['chatter'] = 2
@@ -151,34 +150,50 @@ class Test(test): @@ -151,34 +150,50 @@ class Test(test):
151 phase.save() 150 phase.save()
152 151
153 # Check result file 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 # Copy ctphase tool 175 # Copy ctphase tool
157 cpy_phase = phase.copy() 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 return 193 return
179 194
180 # Check result file 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 Check result file 198 Check result file
184 199
@@ -188,14 +203,10 @@ class Test(test): @@ -188,14 +203,10 @@ class Test(test):
188 Event list file name 203 Event list file name
189 nevents : int, optional 204 nevents : int, optional
190 Expected number of events 205 Expected number of events
191 - dec : float, optional  
192 - Expected Declination (deg)  
193 - rad : float, optional  
194 - Expected radius (deg)  
195 """ 206 """
196 # Open result file 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 test_result = int(sum(phases)>0) 210 test_result = int(sum(phases)>0)
200 self.test_value(test_result, 1, 'Check number of events') 211 self.test_value(test_result, 1, 'Check number of events')
201 212
@@ -213,8 +224,6 @@ class Test(test): @@ -213,8 +224,6 @@ class Test(test):
213 Models 224 Models
214 nobs : int, optional 225 nobs : int, optional
215 Expected number of observations 226 Expected number of observations
216 - nevents : int, optional  
217 - Expected number of events  
218 """ 227 """
219 # Check number of observations 228 # Check number of observations
220 self.test_value(obs.size(), nobs, 'Check number of observations') 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,6 +40,7 @@ import test_ctcubemask
40 import test_ctbutterfly 40 import test_ctbutterfly
41 import test_ctulimit 41 import test_ctulimit
42 import test_cterror 42 import test_cterror
  43 +import test_ctprob
43 import test_pipelines 44 import test_pipelines
44 45
45 46
@@ -118,6 +119,7 @@ def test(installed=False): @@ -118,6 +119,7 @@ def test(installed=False):
118 test_ctbutterfly.Test(), 119 test_ctbutterfly.Test(),
119 test_ctulimit.Test(), 120 test_ctulimit.Test(),
120 test_cterror.Test(), 121 test_cterror.Test(),
  122 + test_ctprob.Test(),
121 test_pipelines.Test()] 123 test_pipelines.Test()]
122 124
123 # Allocate test suite container 125 # Allocate test suite container