Commit 4fdb5ce125d6f7e365771e3f5d791158051abc55

Authored by Jürgen Knödlseder
1 parent b030e64d

Revise cstsdist parameters (#1567)

The cstsdist parameter interface is now much simpler, requiring on input either an unbinned, binned or stacked observation. If an observation definition XML file is provided it is assumed that the file only contains event lists.
ChangeLog
... ... @@ -26,6 +26,7 @@
26 26 Add "NODES" method to csspec to support non-CTA analysis (#1927)
27 27 Use t-type parameters for all "tmin" and "tmax" parameters (#1864)
28 28 Set OBS_ID in ctobssim (#1836)
  29 + Revise cstsdist parameters (#1567)
29 30 Add ctbutterfly::butterfly() method (#1512)
30 31  
31 32  
... ...
... ... @@ -319,8 +319,14 @@ The script now derives from the csobservation base class. A "statistic"
319 319 parameter was added to allow setting the optimizer statistic for the Test
320 320 Statistic distribution generation (#2237).
321 321  
322   -Use t-type parameters for "tmin" and "tmax" to all specifying times in various
323   -formats (#1864).
  322 +The parameter interface was considerably revised, in particular the following
  323 +parameters were removed: "ra", "dec", "rad", "coordsys", "proj", "emin",
  324 +"emax", "enumbins", "tmin", "tmax", "npix" and "binsz". The "inobs" parameter
  325 +is now always queried. The script now reads in an observation or an observation
  326 +container and derives the TS distribution for a source based on that observation
  327 +container. So far the script supports unbinned, binned and stacked observations.
  328 +If an observation definition XML file is specified the script assumes that all
  329 +observations are event lists (#1567).
324 330  
325 331  
326 332 cstsmapmerge - Merge Test Statistic maps
... ...
cscripts/cstsdist.par
... ... @@ -16,7 +16,7 @@
16 16 #
17 17 # Input and output parameters
18 18 #============================
19   -inobs, f, h, NONE,,, "Input event list, counts cube, or observation definition XML file"
  19 +inobs, f, a, events.fits,,, "Input event list, counts cube, or observation definition XML file"
20 20 inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model definition XML file"
21 21 srcname, s, a, Crab,,, "Source name"
22 22 expcube, f, a, NONE,,, "Input exposure cube file"
... ... @@ -33,18 +33,6 @@ outfile, f, a, ts.dat,,, "Output Test Statistic distribution file"
33 33 # Script parameters
34 34 #==================
35 35 ntrials, i, a, 10,,, "Number of trials"
36   -ra, r, a, 83.63,0,360, "RA of pointing (degrees)"
37   -dec, r, a, 22.01,-90,90, "Dec of pointing (degrees)"
38   -rad, r, h, 5.0,0,180, "Radius of ROI (degrees)"
39   -coordsys, s, a, CEL,CEL|GAL,, "Coordinate system (CEL - celestial, GAL - galactic)"
40   -proj, s, a, TAN,AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN,, "Projection method"
41   -emin, r, a, 0.1,,, "Lower energy limit (TeV)"
42   -emax, r, a, 100.0,,, "Upper energy limit (TeV)"
43   -enumbins, i, a, 0,,, "Number of energy bins (0=unbinned)"
44   -tmin, t, a, 2020-01-01T00:00:00,,, "Start time (UTC string, JD, MJD or MET in seconds)"
45   -tmax, t, a, 2020-01-01T00:30:00,,, "Stop time (UTC string, JD, MJD or MET in seconds)"
46   -npix, i, a, 200,,, "Number of pixels for binned"
47   -binsz, r, a, 0.05,,, "Pixel size for binned (degrees/pixel)"
48 36 statistic, s, h, DEFAULT,DEFAULT|CSTAT|WSTAT|CHI2,, "Optimization statistic"
49 37  
50 38 #
... ...
cscripts/cstsdist.py
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # Generates the TS distribution for a particular model
4 4 #
5   -# Copyright (C) 2011-2017 Juergen Knoedlseder
  5 +# Copyright (C) 2011-2018 Juergen Knoedlseder
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -37,7 +37,7 @@ class cstsdist(ctools.csobservation):
37 37 # Constructor
38 38 def __init__(self, *argv):
39 39 """
40   - Constructor.
  40 + Constructor
41 41 """
42 42 # Initialise application by calling the appropriate class constructor
43 43 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv)
... ... @@ -45,6 +45,7 @@ class cstsdist(ctools.csobservation):
45 45 # Initialise some members
46 46 self._srcname = ''
47 47 self._log_clients = False
  48 + self._model = None
48 49  
49 50 # Return
50 51 return
... ... @@ -65,13 +66,6 @@ class cstsdist(ctools.csobservation):
65 66 # Get source name
66 67 self._srcname = self['srcname'].string()
67 68  
68   - # Query parameters for binned if requested
69   - if self['enumbins'].integer() != 0:
70   - self['npix'].integer()
71   - self['binsz'].real()
72   - self['coordsys'].string()
73   - self['proj'].string()
74   -
75 69 # Set models if we have none
76 70 if self.obs().models().size() == 0:
77 71 self.obs().models(self['inmodel'].filename())
... ... @@ -79,15 +73,73 @@ class cstsdist(ctools.csobservation):
79 73 # Query parameters
80 74 self['edisp'].boolean()
81 75 self['ntrials'].integer()
82   - self['outfile'].filename()
  76 +
83 77 self['debug'].boolean()
84 78  
  79 + # Read ahead output parameters
  80 + #if self._read_ahead():
  81 + # self['outfile'].filename()
  82 + self['outfile'].filename()
  83 +
85 84 # Write input parameters into logger
86 85 self._log_parameters(gammalib.TERSE)
87 86  
88 87 # Return
89 88 return
90 89  
  90 + def _sim(self, seed):
  91 + """
  92 + Return a simulated observation container
  93 +
  94 + Parameters
  95 + ----------
  96 + seed : int
  97 + Random number generator seed
  98 +
  99 + Returns
  100 + -------
  101 + sim : `~gammalib.GObservations`
  102 + Simulated observation container
  103 + """
  104 + # If observation is a counts cube then simulate events from the counts
  105 + # cube model ...
  106 + if self.obs().size() == 1 and self.obs()[0].eventtype() == 'CountsCube':
  107 +
  108 + # If no counts cube model exists then compute it now
  109 + if self._model == None:
  110 + model = ctools.ctmodel(self.obs())
  111 + model['debug'] = self['debug'].boolean()
  112 + model['chatter'] = self['chatter'].integer()
  113 + model.run()
  114 + self._model = model.cube().copy() # Save copy for persistence
  115 +
  116 + # Allocate random number generator
  117 + ran = gammalib.GRan()
  118 +
  119 + # Get copy of model map
  120 + counts = self._model.counts().copy()
  121 +
  122 + # Randomize counts
  123 + for i in range(counts.npix()):
  124 + counts[i] = ran.poisson(counts[i])
  125 +
  126 + # Copy observations
  127 + sim = self.obs().copy()
  128 +
  129 + # Set counts map
  130 + sim[0].events().counts(counts)
  131 +
  132 + # ... otherwise simuate events from the observation container (works
  133 + # only for event lists
  134 + else:
  135 + sim = obsutils.sim(self.obs(),
  136 + seed = seed,
  137 + log = self._log_clients,
  138 + debug = self['debug'].boolean())
  139 +
  140 + # Return simulated observation
  141 + return sim
  142 +
91 143 def _trial(self, seed):
92 144 """
93 145 Create the TS for a single trial
... ... @@ -105,29 +157,8 @@ class cstsdist(ctools.csobservation):
105 157 # Write header
106 158 self._log_header2(gammalib.EXPLICIT, 'Trial %d' % (seed+1))
107 159  
108   - # Set default binned parameters
109   - coordsys = 'CEL'
110   - proj = 'TAN'
111   - npix = 0
112   - binsz = 0.0
113   -
114   - # If binned analysis is requested the read the binned parameters
115   - if self['enumbins'].integer() != 0:
116   - npix = self['npix'].integer()
117   - binsz = self['binsz'].real()
118   - coordsys = self['coordsys'].string()
119   - proj = self['proj'].string()
120   -
121 160 # Simulate events
122   - sim = obsutils.sim(self.obs(),
123   - nbins = self['enumbins'].integer(),
124   - seed = seed,
125   - proj = proj,
126   - coord = coordsys,
127   - binsz = binsz,
128   - npix = npix,
129   - log = self._log_clients,
130   - debug = self['debug'].boolean())
  161 + sim = self._sim(seed)
131 162  
132 163 # Determine number of events in simulation
133 164 nevents = 0.0
... ... @@ -160,7 +191,7 @@ class cstsdist(ctools.csobservation):
160 191 for model in models:
161 192 self._log_value(gammalib.EXPLICIT, 'Model', model.name())
162 193 for par in model:
163   - self._log_string(gammalib.EXPLICIT, str(par)+'\n')
  194 + self._log_string(gammalib.EXPLICIT, str(par))
164 195 elif self._logNormal():
165 196 name = 'Trial %d' % seed
166 197 value = 'TS=%.3f Prefactor=%e +/- %e' % \
... ...
doc/source/users/reference_manual/cstsdist.rst
... ... @@ -15,9 +15,6 @@ sets. The Test Statistics is defined as twice the log-likelihood difference
15 15 that is obtained when fitting simulated data with and without a given
16 16 source model component.
17 17  
18   -This script either performs an unbinned or a binned simulation, stacked
19   -analysis is not yet supported.
20   -
21 18 cstsdist will create an ASCII file in comma-separated value (CSV) format,
22 19 containing one row per TS computation. The first row is a header row providing
23 20 the column names. The following rows give the TS value, the log-likelihood
... ... @@ -26,13 +23,18 @@ fitted events, as well as the values and errors for all fitted parameters.
26 23  
27 24 From the output file, TS distribution plots can be generated using for
28 25 example the ``show_ts_distribution.py`` script in the examples folder. The
29   -script require matplotlib for plotting.
  26 +script requires matplotlib for plotting.
  27 +
  28 +.. warning::
  29 + This script does not work for On/Off observations. If an observation
  30 + definition XML file is specified the script assumes that all observations
  31 + are event lists.
30 32  
31 33  
32 34 General parameters
33 35 ------------------
34 36  
35   -``(inobs = NONE) [file]``
  37 +``inobs [file]``
36 38 Input event list, counts cube or observation definition XML file.
37 39  
38 40 ``inmodel [file]``
... ... @@ -72,42 +74,6 @@ General parameters
72 74 ``ntrials [integer]``
73 75 Number of Monte Carlo samples.
74 76  
75   -``ra [real]``
76   - Right Ascension of CTA pointing (J2000, in degrees).
77   -
78   -``dec [real]``
79   - Declination of CTA pointing (J2000, in degrees).
80   -
81   -``(rad = 5.0) [real]``
82   - ROI radius (in degrees).
83   -
84   -``coordsys <CEL|GAL> [string]``
85   - Coordinate system (CEL - celestial, GAL - galactic).
86   -
87   -``proj <AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN> [string]``
88   - Projection method.
89   -
90   -``emin [real]``
91   - Lower energy limit (in TeV).
92   -
93   -``emax [real]``
94   - Upper energy limit (in TeV).
95   -
96   -``enumbins [integer]``
97   - Number of energy bins (0=unbinned).
98   -
99   -``tmin [time]``
100   - Start time (UTC string, JD, MJD or MET in seconds).
101   -
102   -``tmax [time]``
103   - Stop time (UTC string, JD, MJD or MET in seconds).
104   -
105   -``npix [integer]``
106   - Number of pixels for binned analysis.
107   -
108   -``binsz [real]``
109   - Pixel size for binned analysis.
110   -
111 77 ``(statistic = DEFAULT) <DEFAULT|CSTAT|WSTAT|CHI2> [string]``
112 78 Optimization statistic. ``DEFAULT`` uses the default statistic for all
113 79 observations, which is ``CSTAT`` or the statistic specified in the
... ...
src/Makefile.am
... ... @@ -100,7 +100,7 @@ help-install:
100 100 echo "$(INSTALL_DATA) $$file $(DESTDIR)$(datadir)/help/$$helpname" ; \
101 101 $(INSTALL_DATA) "$$file" $(DESTDIR)$(datadir)/help/"$$helpname" ; \
102 102 sed -i.bak -e 's/``//g' -e 's/`//g' -e 's/:ref://g' -e 's/:doc://g' \
103   - -e 's/.. note::/Note/g' -e '1d' \
  103 + -e 's/.. note::/Note/g' -e 's/.. warning::/Warning/g' -e '1d' \
104 104 $(DESTDIR)$(datadir)/help/"$$helpname" ; \
105 105 rm -rf $(DESTDIR)$(datadir)/help/"$$helpname".bak ; \
106 106 done
... ...
test/test_cstsdist.py
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # This scripts performs unit tests for the cstsdist script.
4 4 #
5   -# Copyright (C) 2016-2017 Juergen Knoedlseder
  5 +# Copyright (C) 2016-2018 Juergen Knoedlseder
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -42,6 +42,10 @@ class Test(test):
42 42 # Call base class constructor
43 43 test.__init__(self)
44 44  
  45 + # Set members
  46 + self._stacked_inobs = self._datadir + '/obs_stacked.xml'
  47 + self._stacked_model = self._datadir + '/crab_bkgcube.xml'
  48 +
45 49 # Return
46 50 return
47 51  
... ... @@ -55,7 +59,12 @@ class Test(test):
55 59  
56 60 # Append tests
57 61 self.append(self._test_cmd, 'Test cstsdist on command line')
58   - self.append(self._test_python, 'Test cstsdist from Python')
  62 + self.append(self._test_python_unbinned,
  63 + 'Test cstsdist from Python in unbinned mode')
  64 + self.append(self._test_python_binned,
  65 + 'Test cstsdist from Python in binned mode')
  66 + self.append(self._test_python_stacked,
  67 + 'Test cstsdist from Python in stacked mode')
59 68  
60 69 # Return
61 70 return
... ... @@ -69,12 +78,10 @@ class Test(test):
69 78 cstsdist = self._script('cstsdist')
70 79  
71 80 # Setup cstsdist command
72   - cmd = cstsdist+' inmodel="'+self._model+'"'+ \
73   - ' srcname="Crab"'+ \
  81 + cmd = cstsdist+' inobs="'+self._events+'"'+ \
  82 + ' inmodel="'+self._model+'" srcname="Crab"'+ \
74 83 ' caldb="'+self._caldb+'" irf="'+self._irf+'"'+ \
75   - ' ntrials=1 ra=83.63 dec=22.01 emin=0.1 emax=100.0'+ \
76   - ' enumbins=0 tmin=0.0 tmax=1800.0 rad=5.0 npix=200 npix=200'+ \
77   - ' binsz=0.05'+ \
  84 + ' ntrials=2 '+ \
78 85 ' outfile="cstsdist_cmd1.dat"'+ \
79 86 ' logfile="cstsdist_cmd1.log" chatter=2'
80 87  
... ... @@ -90,14 +97,12 @@ class Test(test):
90 97 self._check_result_file('cstsdist_cmd1.dat')
91 98  
92 99 # Setup cstsdist command
93   - cmd = cstsdist+' inmodel="model_that_does_not_exist.xml"'+ \
94   - ' srcname="Crab"'+ \
  100 + cmd = cstsdist+' inobs="event_file_that_does_not_exist.xml"'+ \
  101 + ' inmodel="'+self._model+'" srcname="Crab"'+ \
95 102 ' caldb="'+self._caldb+'" irf="'+self._irf+'"'+ \
96   - ' ntrials=1 ra=83.63 dec=22.01 emin=0.1 emax=100.0'+ \
97   - ' enumbins=0 tmin=0.0 tmax=1800.0 rad=5.0 npix=200 npix=200'+ \
98   - ' binsz=0.05'+ \
  103 + ' ntrials=1 '+ \
99 104 ' outfile="cstsdist_cmd2.dat"'+ \
100   - ' logfile="cstsdist_cmd2.log" debug=yes chatter=2'
  105 + ' logfile="cstsdist_cmd2.log" chatter=2'
101 106  
102 107 # Check if execution failed
103 108 self.test_assert(self._execute(cmd) != 0,
... ... @@ -110,25 +115,18 @@ class Test(test):
110 115 return
111 116  
112 117 # Test cstsdist from Python
113   - def _test_python(self):
  118 + def _test_python_unbinned(self):
114 119 """
115 120 Test cstsdist from Python
116 121 """
117   - # Set-up cstsdist
  122 + # Set-up cstsdist for event list
118 123 tsdist = cscripts.cstsdist()
  124 + tsdist['inobs'] = self._events
119 125 tsdist['inmodel'] = self._model
120 126 tsdist['srcname'] = 'Crab'
121 127 tsdist['caldb'] = self._caldb
122 128 tsdist['irf'] = self._irf
123   - tsdist['ntrials'] = 1
124   - tsdist['ra'] = 83.63
125   - tsdist['dec'] = 22.01
126   - tsdist['emin'] = 0.1
127   - tsdist['emax'] = 100.0
128   - tsdist['enumbins'] = 0
129   - tsdist['tmin'] = 0.0
130   - tsdist['tmax'] = 1800.0
131   - tsdist['rad'] = 5.0
  129 + tsdist['ntrials'] = 2
132 130 tsdist['outfile'] = 'cstsdist_py1.dat'
133 131 tsdist['logfile'] = 'cstsdist_py1.log'
134 132 tsdist['chatter'] = 3
... ... @@ -144,8 +142,61 @@ class Test(test):
144 142 # Return
145 143 return
146 144  
  145 + def _test_python_binned(self):
  146 + """
  147 + Test cstsdist from Python
  148 + """
  149 + # Set-up cstsdist for counts cube
  150 + tsdist = cscripts.cstsdist()
  151 + tsdist['inobs'] = self._cntcube
  152 + tsdist['inmodel'] = self._model
  153 + tsdist['srcname'] = 'Crab'
  154 + tsdist['expcube'] = 'NONE'
  155 + tsdist['psfcube'] = 'NONE'
  156 + tsdist['bkgcube'] = 'NONE'
  157 + tsdist['caldb'] = self._caldb
  158 + tsdist['irf'] = self._irf
  159 + tsdist['ntrials'] = 2
  160 + tsdist['outfile'] = 'cstsdist_py2.dat'
  161 + tsdist['logfile'] = 'cstsdist_py2.log'
  162 + tsdist['chatter'] = 4
  163 +
  164 + # Run cstsdist script
  165 + tsdist.logFileOpen() # Make sure we get a log file
  166 + tsdist.execute()
  167 +
  168 + # Check pull distribution file
  169 + self._check_result_file('cstsdist_py2.dat')
  170 +
  171 + # Return
  172 + return
  173 +
  174 + def _test_python_stacked(self):
  175 + """
  176 + Test cstsdist from Python
  177 + """
  178 + # Set-up cstsdist for stacked cube
  179 + tsdist = cscripts.cstsdist()
  180 + tsdist['inobs'] = self._stacked_inobs
  181 + tsdist['inmodel'] = self._stacked_model
  182 + tsdist['srcname'] = 'Crab'
  183 + tsdist['ntrials'] = 2
  184 + tsdist['outfile'] = 'cstsdist_py3.dat'
  185 + tsdist['logfile'] = 'cstsdist_py3.log'
  186 + tsdist['chatter'] = 4
  187 +
  188 + # Run cstsdist script
  189 + tsdist.logFileOpen() # Make sure we get a log file
  190 + tsdist.execute()
  191 +
  192 + # Check pull distribution file
  193 + self._check_result_file('cstsdist_py3.dat')
  194 +
  195 + # Return
  196 + return
  197 +
147 198 # Check result file
148   - def _check_result_file(self, filename, ncols=9):
  199 + def _check_result_file(self, filename, nrows=3, ncols=9):
149 200 """
150 201 Check result file
151 202  
... ... @@ -153,6 +204,8 @@ class Test(test):
153 204 ----------
154 205 filename : str
155 206 Name of result file
  207 + nrows : int, optional
  208 + Required number of rows
156 209 ncols : int, optional
157 210 Required number of columns
158 211 """
... ... @@ -160,7 +213,7 @@ class Test(test):
160 213 results = gammalib.GCsv(filename, ',')
161 214  
162 215 # Check dimensions
163   - self.test_value(results.nrows(), 2, 'Check rows in TS file')
  216 + self.test_value(results.nrows(), nrows, 'Check rows in TS file')
164 217 self.test_value(results.ncols(), ncols, 'Check columns in TS file')
165 218  
166 219 # Return
... ...