Commit 960f7ce661878ccb757d86102937c9758ea1983c

Authored by Jürgen Knödlseder
2 parents b8e06a5e 35e553ce

Merge branch 'integration' into devel

cscripts/csiactobs.py
@@ -85,6 +85,10 @@ class csiactobs(ctools.cscript): @@ -85,6 +85,10 @@ class csiactobs(ctools.cscript):
85 # Initialise application by calling the appropriate class constructor 85 # Initialise application by calling the appropriate class constructor
86 self._init_cscript(argv) 86 self._init_cscript(argv)
87 87
  88 + # Append an observation list to XML instance
  89 + self._xml.append(gammalib.GXmlElement('observation_list title="observation list"'))
  90 + self._xml_obslist = self._xml.element('observation_list', 0)
  91 +
88 # Return 92 # Return
89 return 93 return
90 94
@@ -559,12 +563,7 @@ class csiactobs(ctools.cscript): @@ -559,12 +563,7 @@ class csiactobs(ctools.cscript):
559 563
560 # Clear models 564 # Clear models
561 self._models.clear() 565 self._models.clear()
562 -  
563 - # Clear XML file and append an observation list  
564 - self._xml.clear()  
565 - self._xml.append(gammalib.GXmlElement('observation_list title="observation list"'))  
566 - lib = self._xml.element('observation_list', 0)  
567 - 566 +
568 # Log output 567 # Log output
569 msg = 'Looping over %d runs' % len(self._runlist) 568 msg = 'Looping over %d runs' % len(self._runlist)
570 self._log_header1(gammalib.TERSE, msg) 569 self._log_header1(gammalib.TERSE, msg)
@@ -713,7 +712,7 @@ class csiactobs(ctools.cscript): @@ -713,7 +712,7 @@ class csiactobs(ctools.cscript):
713 run_emax.TeV())) 712 run_emax.TeV()))
714 713
715 # Append observation to XML and set attributes 714 # Append observation to XML and set attributes
716 - obs = lib.append('observation') 715 + obs = self._xml_obslist.append('observation')
717 obs.attribute('name', object_name) 716 obs.attribute('name', object_name)
718 obs.attribute('id', str(obs_id)) 717 obs.attribute('id', str(obs_id))
719 obs.attribute('instrument', telescope) 718 obs.attribute('instrument', telescope)
@@ -768,7 +767,7 @@ class csiactobs(ctools.cscript): @@ -768,7 +767,7 @@ class csiactobs(ctools.cscript):
768 self._write_summary() 767 self._write_summary()
769 768
770 # Write warning in no observation could be used from runlist 769 # Write warning in no observation could be used from runlist
771 - if lib.size() == 0: 770 + if self._xml_obslist.size() == 0:
772 self._log_string(gammalib.NORMAL, 'WARNING: No observation was ' 771 self._log_string(gammalib.NORMAL, 'WARNING: No observation was '
773 'appended from specified runlist') 772 'appended from specified runlist')
774 773
cscripts/cstsmapmerge.py
@@ -30,17 +30,17 @@ import ctools @@ -30,17 +30,17 @@ import ctools
30 # ================== # 30 # ================== #
31 class cstsmapmerge(ctools.cscript): 31 class cstsmapmerge(ctools.cscript):
32 """ 32 """
33 - Merge Test Statistic maps 33 + Merge Test Statistic maps.
34 """ 34 """
35 35
36 # Constructor 36 # Constructor
37 def __init__(self, *argv): 37 def __init__(self, *argv):
38 """ 38 """
39 - Constructor 39 + Constructor.
40 """ 40 """
41 # Set name 41 # Set name
42 self._name = 'cstsmapmerge' 42 self._name = 'cstsmapmerge'
43 - self._version = '1.2.0' 43 + self._version = '1.1.0'
44 44
45 # Initialise class members 45 # Initialise class members
46 self._files = None 46 self._files = None
@@ -64,7 +64,7 @@ class cstsmapmerge(ctools.cscript): @@ -64,7 +64,7 @@ class cstsmapmerge(ctools.cscript):
64 # Private methods 64 # Private methods
65 def _get_parameters(self): 65 def _get_parameters(self):
66 """ 66 """
67 - Get parameters from parfile 67 + Get parameters from parfile.
68 """ 68 """
69 # Get input maps string 69 # Get input maps string
70 inmaps = self['inmaps'].string() 70 inmaps = self['inmaps'].string()
@@ -118,7 +118,7 @@ class cstsmapmerge(ctools.cscript): @@ -118,7 +118,7 @@ class cstsmapmerge(ctools.cscript):
118 if self._read_ahead(): 118 if self._read_ahead():
119 self['outmap'].filename() 119 self['outmap'].filename()
120 120
121 - # Write input parameters into logger 121 + # Write input parameters into logger
122 self._log_parameters(gammalib.TERSE) 122 self._log_parameters(gammalib.TERSE)
123 123
124 # Return 124 # Return
@@ -126,12 +126,7 @@ class cstsmapmerge(ctools.cscript): @@ -126,12 +126,7 @@ class cstsmapmerge(ctools.cscript):
126 126
127 def _init_ts_map(self, fitsfile): 127 def _init_ts_map(self, fitsfile):
128 """ 128 """
129 - Initialise Test Statistic map  
130 -  
131 - Parameters  
132 - ----------  
133 - fitsfile : str  
134 - FITS file to be merged 129 + Initialise Test Statistic map.
135 """ 130 """
136 # Set filename 131 # Set filename
137 self._in_filename = fitsfile 132 self._in_filename = fitsfile
@@ -169,12 +164,10 @@ class cstsmapmerge(ctools.cscript): @@ -169,12 +164,10 @@ class cstsmapmerge(ctools.cscript):
169 164
170 def _merge_ts_map(self, fitsfile): 165 def _merge_ts_map(self, fitsfile):
171 """ 166 """
172 - Merge TS map from FITS file into output TS map 167 + Merge TS map from FITS file into output TS map.
173 168
174 - Parameters  
175 - ----------  
176 - fitsfile : str  
177 - FITS file to be merged 169 + Args:
  170 + fitsfile: FITS file to be merged.
178 """ 171 """
179 # Open FITS file 172 # Open FITS file
180 fits = gammalib.GFits(fitsfile) 173 fits = gammalib.GFits(fitsfile)
@@ -204,23 +197,23 @@ class cstsmapmerge(ctools.cscript): @@ -204,23 +197,23 @@ class cstsmapmerge(ctools.cscript):
204 197
205 # Compare size of maps 198 # Compare size of maps
206 if not len(add_maps) == len(self._maps): 199 if not len(add_maps) == len(self._maps):
207 - msg = ('Cannot merge map "%s" into map "%s" since the number of '  
208 - 'parameters between both maps is different.' %  
209 - (fitsfile, self._in_filename)) 200 + msg = 'Cannot merge map "'+fitsfile+'" into map "'+\
  201 + self._in_filename+'" since the number of parameters ' +\
  202 + 'between both maps is different.'
210 raise RuntimeError(msg) 203 raise RuntimeError(msg)
211 204
212 # Loop over bins 205 # Loop over bins
213 for i in range(self._tsmap.npix()): 206 for i in range(self._tsmap.npix()):
214 207
215 # Consider only bins that have been computed 208 # Consider only bins that have been computed
216 - if add_statusmap[i] > 0.5: 209 + if add_statusmap[i] > -0.5:
217 210
218 # Raise exception if this bin has already been computed 211 # Raise exception if this bin has already been computed
219 - if self._statusmap[i] > 0.5 and not self._overwrite:  
220 - msg = ('Attempt to merge bin which apparently has already '  
221 - 'been merged. File "%s" contains already merged '  
222 - 'bins. Set hidden parameter "overwrite=yes" to '  
223 - 'avoid this error.' % fitsfile) 212 + if self._statusmap[i] > -0.5 and not self._overwrite:
  213 + msg = 'Attempt to merge bin which apparently has '+\
  214 + 'already been merged. File "'+fitsfile+'" '+\
  215 + 'contains already merged bins. Set hidden '+\
  216 + 'parameter "overwrite=yes" to avoid this error.'
224 raise RuntimeError(msg) 217 raise RuntimeError(msg)
225 218
226 # Copy TS values 219 # Copy TS values
@@ -238,17 +231,13 @@ class cstsmapmerge(ctools.cscript): @@ -238,17 +231,13 @@ class cstsmapmerge(ctools.cscript):
238 231
239 def _get_number_of_ts_pixels(self, fitsfile): 232 def _get_number_of_ts_pixels(self, fitsfile):
240 """ 233 """
241 - Return number of pixels with TS values 234 + Return number of pixels with TS values.
242 235
243 - Parameters  
244 - ----------  
245 - fitsfile : str  
246 - FITS file to be merged 236 + Args:
  237 + fitsfile: FITS file to be merged.
247 238
248 - Returns  
249 - -------  
250 - counts : int  
251 - Number of pixels for which TS has been computed 239 + Returns:
  240 + Number of pixels for which TS has been computed.
252 """ 241 """
253 # Get status map for this file 242 # Get status map for this file
254 status = gammalib.GSkyMap(fitsfile+'[STATUS MAP]') 243 status = gammalib.GSkyMap(fitsfile+'[STATUS MAP]')
@@ -256,7 +245,7 @@ class cstsmapmerge(ctools.cscript): @@ -256,7 +245,7 @@ class cstsmapmerge(ctools.cscript):
256 # Count number of pixels with TS status set 245 # Count number of pixels with TS status set
257 count = 0 246 count = 0
258 for pix in status: 247 for pix in status:
259 - if pix > 0.5: 248 + if pix > -0.5:
260 count += 1 249 count += 1
261 250
262 # Return number of pixels 251 # Return number of pixels
@@ -266,7 +255,7 @@ class cstsmapmerge(ctools.cscript): @@ -266,7 +255,7 @@ class cstsmapmerge(ctools.cscript):
266 # Public methods 255 # Public methods
267 def run(self): 256 def run(self):
268 """ 257 """
269 - Run the script 258 + Run the script.
270 """ 259 """
271 # Switch screen logging on in debug mode 260 # Switch screen logging on in debug mode
272 if self._logDebug(): 261 if self._logDebug():
@@ -276,9 +265,7 @@ class cstsmapmerge(ctools.cscript): @@ -276,9 +265,7 @@ class cstsmapmerge(ctools.cscript):
276 self._get_parameters() 265 self._get_parameters()
277 266
278 # Write header into logger 267 # Write header into logger
279 - if self._logTerse():  
280 - self._log('\n')  
281 - self._log.header1('Merge TS maps') 268 + self._log_header1(gammalib.TERSE, 'Merge TS maps')
282 269
283 # Initialise file to start with 270 # Initialise file to start with
284 file0 = '' 271 file0 = ''
@@ -290,8 +277,11 @@ class cstsmapmerge(ctools.cscript): @@ -290,8 +277,11 @@ class cstsmapmerge(ctools.cscript):
290 277
291 # Skip file if it's not a FITS file 278 # Skip file if it's not a FITS file
292 if not gammalib.GFilename(fitsfile).is_fits(): 279 if not gammalib.GFilename(fitsfile).is_fits():
293 - self._log_value(gammalib.EXPLICIT, 'Skip file',  
294 - '%s (not a FITS file)' % fitsfile) 280 +
  281 + # Log message
  282 + self._log_value(gammalib.EXPLICIT, 'Skip file', fitsfile +' (not a FITS file)')
  283 +
  284 + # Continue
295 continue 285 continue
296 286
297 # Open FITS file 287 # Open FITS file
@@ -299,29 +289,40 @@ class cstsmapmerge(ctools.cscript): @@ -299,29 +289,40 @@ class cstsmapmerge(ctools.cscript):
299 289
300 # If file contains a status map then use it 290 # If file contains a status map then use it
301 if fits.contains('STATUS MAP'): 291 if fits.contains('STATUS MAP'):
  292 +
  293 + # Close FITS file
302 fits.close() 294 fits.close()
  295 +
  296 + # Set filename to initial filename
303 file0 = fitsfile 297 file0 = fitsfile
304 - if self._logTerse():  
305 - self._log(gammalib.parformat('Initial TS map file'))  
306 - self._log(fitsfile)  
307 - count = self._get_number_of_ts_pixels(fitsfile)  
308 - self._log(' (%d TS pixels computed)' % count)  
309 - self._log('\n') 298 +
  299 + # Log message
  300 + pix_info = ' (%d TS pixels computed)' % self._get_number_of_ts_pixels(fitsfile)
  301 + self._log_value(gammalib.TERSE, 'Initial TS map file', fitsfile + pix_info)
  302 +
  303 + # Leave loop
310 break 304 break
311 305
312 # ... otherwise signal that file is useless 306 # ... otherwise signal that file is useless
313 else: 307 else:
314 - fits.close()  
315 - self._log_value(gammalib.EXPLICIT, 'Skip file',  
316 - '%s (no "STATUS MAP" extension)' % fitsfile) 308 +
  309 + # Close fits file
  310 + fits.close()
  311 +
  312 + # Info message
  313 + self._log_value(gammalib.EXPLICIT, 'Skip file', fitsfile +' (no "STATUS MAP" extension)')
  314 +
  315 + # Continue
317 continue 316 continue
318 317
319 # Signal if no suitable file was found 318 # Signal if no suitable file was found
320 if file0 == '': 319 if file0 == '':
321 - if self._logTerse():  
322 - self._log('None of the provided files seems to be a sliced '  
323 - 'TS map file (none has a "STATUS MAP" extension).\n')  
324 - 320 + msg = 'None of the provided files seems to be a sliced ' + \
  321 + 'TS map file (none has a "STATUS MAP" ' + \
  322 + 'extension)'
  323 + raise RuntimeError(msg)
  324 +
  325 +
325 # ... otherwise merge files 326 # ... otherwise merge files
326 else: 327 else:
327 328
@@ -342,9 +343,8 @@ class cstsmapmerge(ctools.cscript): @@ -342,9 +343,8 @@ class cstsmapmerge(ctools.cscript):
342 343
343 # Skip if file is not FITS 344 # Skip if file is not FITS
344 if not gammalib.GFilename(fitsfile).is_fits(): 345 if not gammalib.GFilename(fitsfile).is_fits():
345 - self._log_value(gammalib.EXPLICIT, 'Skip file',  
346 - '%s (not a FITS file)' % fitsfile)  
347 - continue 346 + self._log_value(gammalib.EXPLICIT, 'Skip file', fitsfile +' (not a FITS file)')
  347 + continue
348 348
349 # Open FITS file 349 # Open FITS file
350 fits = gammalib.GFits(fitsfile) 350 fits = gammalib.GFits(fitsfile)
@@ -352,20 +352,15 @@ class cstsmapmerge(ctools.cscript): @@ -352,20 +352,15 @@ class cstsmapmerge(ctools.cscript):
352 # Skip if file does not contain status map 352 # Skip if file does not contain status map
353 if not fits.contains('STATUS MAP'): 353 if not fits.contains('STATUS MAP'):
354 fits.close() 354 fits.close()
355 - self._log_value(gammalib.EXPLICIT, 'Skip file',  
356 - '%s (no "STATUS MAP" extension)' % fitsfile) 355 + self._log_value(gammalib.EXPLICIT, 'Skip file', fitsfile +' (no "STATUS MAP" extension)')
357 continue 356 continue
358 357
359 # Close FITS file 358 # Close FITS file
360 fits.close() 359 fits.close()
361 360
362 # Logging 361 # Logging
363 - if self._logTerse():  
364 - self._log(gammalib.parformat('Merge TS map file'))  
365 - self._log(fitsfile)  
366 - count = self._get_number_of_ts_pixels(fitsfile)  
367 - self._log(' (%d TS pixels computed)' % count)  
368 - self._log('\n') 362 + pix_info = ' (%d TS pixels computed)' % self._get_number_of_ts_pixels(fitsfile)
  363 + self._log_value(gammalib.TERSE, 'Merge TS map file', fitsfile + pix_info)
369 364
370 # Merge TS map 365 # Merge TS map
371 self._merge_ts_map(fitsfile) 366 self._merge_ts_map(fitsfile)
@@ -378,16 +373,11 @@ class cstsmapmerge(ctools.cscript): @@ -378,16 +373,11 @@ class cstsmapmerge(ctools.cscript):
378 373
379 def save(self): 374 def save(self):
380 """ 375 """
381 - Save TS map and remove slices if requested 376 + Save TS map and remove slices if requested.
382 """ 377 """
383 - # Write header  
384 - self._log_header1(gammalib.TERSE, 'Save TS map')  
385 378
386 # Get output filename in case it was not read ahead 379 # Get output filename in case it was not read ahead
387 outmap = self['outmap'].filename() 380 outmap = self['outmap'].filename()
388 -  
389 - # Log filename  
390 - self._log_value(gammalib.TERSE, 'TS map file', outmap.url())  
391 381
392 # Create FITS file 382 # Create FITS file
393 fits = gammalib.GFits() 383 fits = gammalib.GFits()
@@ -403,33 +393,65 @@ class cstsmapmerge(ctools.cscript): @@ -403,33 +393,65 @@ class cstsmapmerge(ctools.cscript):
403 for i in range(len(self._mapnames)): 393 for i in range(len(self._mapnames)):
404 fits[i+1].extname(self._mapnames[i]) 394 fits[i+1].extname(self._mapnames[i])
405 395
  396 + # Treat status map separately
  397 + self._statusmap.write(fits)
  398 + fits[fits.size()-1].extname('STATUS MAP')
  399 +
406 # Check if map is fully done 400 # Check if map is fully done
407 - done = True 401 + bins_merged = 0
408 for pix in self._statusmap: 402 for pix in self._statusmap:
409 - if pix < 0.5:  
410 - done = False  
411 - break 403 + if pix > -0.5:
  404 + bins_merged += 1
  405 +
  406 + # Set boolean if map is fully done
  407 + done = (bins_merged == self._tsmap.npix())
412 408
413 - # Write status map if we are not done yet 409 + # Log summary header
  410 + self._log_header2(gammalib.TERSE, 'Merging Summary')
  411 +
  412 + # Write computing status if we are not done yet
414 if not done: 413 if not done:
415 - self._statusmap.write(fits)  
416 - fits[fits.size()-1].extname('STATUS MAP') 414 +
  415 + # Log bins that were computed and those that were missing
  416 + self._log_value(gammalib.TERSE, 'TS map bins', self._tsmap.npix())
  417 + self._log_value(gammalib.TERSE, 'Bins computed and merged', bins_merged )
  418 + self._log_value(gammalib.TERSE, 'Bins missing', self._tsmap.npix() - bins_merged)
  419 +
  420 + else:
  421 +
  422 + # Write success message
  423 + self._log_string(gammalib.TERSE, 'TS map was fully computed and successfully merged')
  424 +
  425 + # Write header
  426 + self._log_header1(gammalib.TERSE, 'Save TS map')
  427 +
  428 + # Log filename
  429 + self._log_value(gammalib.TERSE, 'TS map file', outmap.url())
417 430
418 # Save FITS file 431 # Save FITS file
419 - fits.saveto(outmap, self._clobber()) 432 + fits.saveto(outmap, self._clobber())
420 433
421 - # Delete TS input maps if requested  
422 - if self._delete: 434 + # Delete TS input maps if requested and map is fully done
  435 + if self._delete and done:
  436 +
  437 + # Log header
  438 + self._log_header2(gammalib.TERSE, 'Delete slices TS map files')
  439 +
  440 + # Loop over sliced files
423 for filename in self._merged_files: 441 for filename in self._merged_files:
  442 +
  443 + # Remove file
424 os.remove(filename) 444 os.remove(filename)
425 - self._log_value(gammalib.TERSE, 'Deleted input file', filename) 445 +
  446 + # Log message about file
  447 + self._log_value(gammalib.TERSE,'Deleted input file', filename)
426 448
427 # Return 449 # Return
428 return 450 return
429 451
430 def execute(self): 452 def execute(self):
431 """ 453 """
432 - Execute the script 454 + Execute the script.
433 """ 455 """
434 # Open logfile 456 # Open logfile
435 self.logFileOpen() 457 self.logFileOpen()
cscripts/cstsmapsplit.par
@@ -27,6 +27,7 @@ bkgcube, f, a, NONE,,, &quot;Input background cube file (only needed for stacke @@ -27,6 +27,7 @@ bkgcube, f, a, NONE,,, &quot;Input background cube file (only needed for stacke
27 caldb, s, a, prod2,,, "Calibration database" 27 caldb, s, a, prod2,,, "Calibration database"
28 irf, s, a, South_0.5h,,, "Instrument response function" 28 irf, s, a, South_0.5h,,, "Instrument response function"
29 edisp, b, h, no,,, "Apply energy dispersion?" 29 edisp, b, h, no,,, "Apply energy dispersion?"
  30 +errors, b, h, no,,, "Compute/store parameter errors?"
30 outmap, f, a, tsmap.fits,,, "Output Test Statistic map file" 31 outmap, f, a, tsmap.fits,,, "Output Test Statistic map file"
31 bins_per_job, i, a, 5,,, "Number of TS map bins per task" 32 bins_per_job, i, a, 5,,, "Number of TS map bins per task"
32 compute_null, b, a, yes,,,"Compute null hypothesis first?" 33 compute_null, b, a, yes,,,"Compute null hypothesis first?"
doc/source/users/reference_manual/cttsmap.rst
@@ -21,7 +21,10 @@ Gaussian sigma). @@ -21,7 +21,10 @@ Gaussian sigma).
21 21
22 cttsmap generates a FITS file comprising a sky map of TS values followed by 22 cttsmap generates a FITS file comprising a sky map of TS values followed by
23 one extension per free parameter that contains sky maps of the fitted 23 one extension per free parameter that contains sky maps of the fitted
24 -parameter values. 24 +parameter values. To save computation time, the errors are not computed by
  25 +default. Specifying the hidden parameter ``errors=yes`` will switch on the
  26 +error computation. Accordingly, for each free parameter, the errors are also
  27 +stored in a separate sky map.
25 28
26 29
27 General parameters 30 General parameters
@@ -56,6 +59,9 @@ General parameters @@ -56,6 +59,9 @@ General parameters
56 59
57 ``outmap [file]`` 60 ``outmap [file]``
58 Output Test Statistic map file. 61 Output Test Statistic map file.
  62 +
  63 +``(errors = no) [boolean]``
  64 + Compute and store parameter errors?
59 65
60 ``(usepnt = no) [boolean]`` 66 ``(usepnt = no) [boolean]``
61 Use CTA pointing direction for map centre instead of xref/yref parameters? 67 Use CTA pointing direction for map centre instead of xref/yref parameters?
src/cttsmap/cttsmap.cpp
@@ -173,9 +173,7 @@ cttsmap&amp; cttsmap::operator=(const cttsmap&amp; app) @@ -173,9 +173,7 @@ cttsmap&amp; cttsmap::operator=(const cttsmap&amp; app)
173 ==========================================================================*/ 173 ==========================================================================*/
174 174
175 /***********************************************************************//** 175 /***********************************************************************//**
176 - * @brief Clear cttsmap tool  
177 - *  
178 - * Clears cttsmap tool. 176 + * @brief Clear instance
179 ***************************************************************************/ 177 ***************************************************************************/
180 void cttsmap::clear(void) 178 void cttsmap::clear(void)
181 { 179 {
@@ -194,9 +192,6 @@ void cttsmap::clear(void) @@ -194,9 +192,6 @@ void cttsmap::clear(void)
194 this->ctlikelihood::init_members(); 192 this->ctlikelihood::init_members();
195 init_members(); 193 init_members();
196 194
197 - // Write header into logger  
198 - log_header();  
199 -  
200 // Return 195 // Return
201 return; 196 return;
202 } 197 }
@@ -290,6 +285,14 @@ void cttsmap::run(void) @@ -290,6 +285,14 @@ void cttsmap::run(void)
290 // Optimize observation container 285 // Optimize observation container
291 m_obs.optimize(m_opt); 286 m_obs.optimize(m_opt);
292 287
  288 + // Compute errors if necessary
  289 + if (m_errors) {
  290 + m_obs.errors(m_opt);
  291 + }
  292 +
  293 + // Get status of optimization
  294 + int status = m_opt.status();
  295 +
293 // Retrieve the Likelihood value 296 // Retrieve the Likelihood value
294 double logL1 = -(m_opt.value()); 297 double logL1 = -(m_opt.value());
295 298
@@ -314,11 +317,27 @@ void cttsmap::run(void) @@ -314,11 +317,27 @@ void cttsmap::run(void)
314 317
315 // Extract fitted test source parameters 318 // Extract fitted test source parameters
316 for (int j = 0; j < m_mapnames.size(); ++j) { 319 for (int j = 0; j < m_mapnames.size(); ++j) {
317 - m_maps[j](i) = (*testsource)[m_mapnames[j]].value();  
318 - }  
319 320
320 - // Set status of bin to true  
321 - m_statusmap(i) = 1.0; 321 + // If map name start with "e_" then set the parameter error ...
  322 + if (m_mapnames[j].substr(0,2) == "e_") {
  323 +
  324 + // Get parameter name by removing the error prefix
  325 + std::string parname = m_mapnames[j].substr(2, m_mapnames[j].size());
  326 +
  327 + // Get parameter error
  328 + m_maps[j](i) = (*testsource)[parname].error();
  329 +
  330 + }
  331 +
  332 + // ... otherwise set the parameter value
  333 + else {
  334 + m_maps[j](i) = (*testsource)[m_mapnames[j]].value();
  335 + }
  336 +
  337 + } // endfor: looped over all maps
  338 +
  339 + // Set Fit status of the bin
  340 + m_statusmap(i) = status;
322 341
323 // Remove model from container 342 // Remove model from container
324 models.remove(m_srcname); 343 models.remove(m_srcname);
@@ -371,11 +390,9 @@ void cttsmap::save(void) @@ -371,11 +390,9 @@ void cttsmap::save(void)
371 fits[i+1]->extname(m_mapnames[i]); 390 fits[i+1]->extname(m_mapnames[i]);
372 } 391 }
373 392
374 - // Add computation log if not all bins are computed  
375 - if (m_binmin != -1 || m_binmax != -1) {  
376 - m_statusmap.write(fits);  
377 - fits[m_mapnames.size()+1]->extname("STATUS MAP");  
378 - } 393 + // Write Fit status map
  394 + m_statusmap.write(fits);
  395 + fits[fits.size()-1]->extname("STATUS MAP");
379 396
380 // Save FITS file 397 // Save FITS file
381 fits.saveto(m_outmap, clobber()); 398 fits.saveto(m_outmap, clobber());
@@ -437,6 +454,7 @@ void cttsmap::init_members(void) @@ -437,6 +454,7 @@ void cttsmap::init_members(void)
437 m_outmap.clear(); 454 m_outmap.clear();
438 m_apply_edisp = false; 455 m_apply_edisp = false;
439 m_publish = false; 456 m_publish = false;
  457 + m_errors = false;
440 458
441 // Initialise protected members 459 // Initialise protected members
442 m_binmin = -1; 460 m_binmin = -1;
@@ -465,6 +483,7 @@ void cttsmap::copy_members(const cttsmap&amp; app) @@ -465,6 +483,7 @@ void cttsmap::copy_members(const cttsmap&amp; app)
465 m_outmap = app.m_outmap; 483 m_outmap = app.m_outmap;
466 m_apply_edisp = app.m_apply_edisp; 484 m_apply_edisp = app.m_apply_edisp;
467 m_publish = app.m_publish; 485 m_publish = app.m_publish;
  486 + m_errors = app.m_errors;
468 487
469 // Copy protected members 488 // Copy protected members
470 m_binmin = app.m_binmin; 489 m_binmin = app.m_binmin;
@@ -516,7 +535,7 @@ void cttsmap::get_parameters(void) @@ -516,7 +535,7 @@ void cttsmap::get_parameters(void)
516 { 535 {
517 // Setup observations from "inobs" parameter 536 // Setup observations from "inobs" parameter
518 setup_observations(m_obs); 537 setup_observations(m_obs);
519 - 538 +
520 // Setup models from "inmodel" parameter 539 // Setup models from "inmodel" parameter
521 setup_models(m_obs, (*this)["srcname"].string()); 540 setup_models(m_obs, (*this)["srcname"].string());
522 541
@@ -545,6 +564,9 @@ void cttsmap::get_parameters(void) @@ -545,6 +564,9 @@ void cttsmap::get_parameters(void)
545 // Create sky map based on task parameters 564 // Create sky map based on task parameters
546 GSkyMap map = create_map(m_obs); 565 GSkyMap map = create_map(m_obs);
547 566
  567 + // Check if errors should be computed
  568 + m_errors = (*this)["errors"].boolean();
  569 +
548 // Initialise maps from user parameters 570 // Initialise maps from user parameters
549 init_maps(map); 571 init_maps(map);
550 572
@@ -585,14 +607,17 @@ void cttsmap::init_maps(const GSkyMap&amp; map) @@ -585,14 +607,17 @@ void cttsmap::init_maps(const GSkyMap&amp; map)
585 m_tsmap = GSkyMap(map); 607 m_tsmap = GSkyMap(map);
586 608
587 // Initialise map information 609 // Initialise map information
588 - m_statusmap.clear(); 610 + m_statusmap.clear();
  611 +
  612 + // Create status map and progress map
  613 + m_statusmap = GSkyMap(map);
589 614
590 - // Create status map  
591 - m_statusmap = GSkyMap(map); 615 + // Set status map to invalid value -1 to signal that bin wasn't computed yet
  616 + m_statusmap = -1.0;
592 617
593 // Loop over all model parameters 618 // Loop over all model parameters
594 for (int i = 0; i < m_testsource->size(); i++) { 619 for (int i = 0; i < m_testsource->size(); i++) {
595 - 620 +
596 // Skip fixed parameters 621 // Skip fixed parameters
597 if ((*m_testsource)[i].is_fixed()) { 622 if ((*m_testsource)[i].is_fixed()) {
598 continue; 623 continue;
@@ -604,7 +629,18 @@ void cttsmap::init_maps(const GSkyMap&amp; map) @@ -604,7 +629,18 @@ void cttsmap::init_maps(const GSkyMap&amp; map)
604 629
605 // Store parameter name 630 // Store parameter name
606 m_mapnames.push_back((*m_testsource)[i].name()); 631 m_mapnames.push_back((*m_testsource)[i].name());
607 - 632 +
  633 + // Add parameter errors if requested
  634 + if (m_errors) {
  635 +
  636 + // Add sky map for fit error of the free parameter
  637 + m_maps.push_back(map);
  638 +
  639 + // Store name of parameter error
  640 + m_mapnames.push_back("e_" + (*m_testsource)[i].name());
  641 +
  642 + } // endif: error calculation was requested
  643 +
608 } // endfor: looped over all model parameters 644 } // endfor: looped over all model parameters
609 645
610 // Return 646 // Return
src/cttsmap/cttsmap.hpp
@@ -82,19 +82,20 @@ protected: @@ -82,19 +82,20 @@ protected:
82 void init_maps(const GSkyMap& map); 82 void init_maps(const GSkyMap& map);
83 83
84 // User parameters 84 // User parameters
85 - std::string m_srcname; //!< Name of source which is moved around  
86 - GFilename m_outmap; //!< Output TS map file name  
87 - bool m_apply_edisp; //!< Apply energy dispersion?  
88 - bool m_publish; //!< Publish TS map? 85 + std::string m_srcname; //!< Name of source which is moved around
  86 + GFilename m_outmap; //!< Output TS map file name
  87 + bool m_apply_edisp; //!< Apply energy dispersion?
  88 + bool m_publish; //!< Publish TS map?
  89 + bool m_errors; //!< Compute and store parameter errors?
89 90
90 // Parameters to control speed and job splitting 91 // Parameters to control speed and job splitting
91 - int m_binmin; //!< Map bin number from which computation should start  
92 - int m_binmax; //!< Map bin number where map computation should end  
93 - double m_logL0; //!< Likelihood value of null hypothesis 92 + int m_binmin; //!< Map bin number from which computation should start
  93 + int m_binmax; //!< Map bin number where map computation should end
  94 + double m_logL0; //!< Likelihood value of null hypothesis
94 95
95 // Protected members 96 // Protected members
96 GSkyMap m_tsmap; //!< TS map 97 GSkyMap m_tsmap; //!< TS map
97 - GSkyMap m_statusmap; //!< Map of computed bins 98 + GSkyMap m_statusmap; //!< Map of optimizer fit status
98 std::vector<std::string> m_mapnames; //!< Names of free parameters 99 std::vector<std::string> m_mapnames; //!< Names of free parameters
99 std::vector<GSkyMap> m_maps; //!< Sky maps for each free parameter 100 std::vector<GSkyMap> m_maps; //!< Sky maps for each free parameter
100 GModel* m_testsource; //!< Pointer to test source for TS computation 101 GModel* m_testsource; //!< Pointer to test source for TS computation
src/cttsmap/cttsmap.par
@@ -5,11 +5,11 @@ @@ -5,11 +5,11 @@
5 # ------------------------------------------------------------------------- # 5 # ------------------------------------------------------------------------- #
6 # # 6 # #
7 # File: cttsmap.par # 7 # File: cttsmap.par #
8 -# Version: 1.1.0 # 8 +# Version: 1.2.0 #
9 # # 9 # #
10 # Author: Michael Mayer # 10 # Author: Michael Mayer #
11 -# michael.mayer@desy.de #  
12 -# DESY # 11 +# michael.mayer@physik.hu-berlin.de #
  12 +# HU Berlin #
13 # # 13 # #
14 # Purpose: Parameter file for the cttsmap application # 14 # Purpose: Parameter file for the cttsmap application #
15 # # 15 # #
@@ -30,6 +30,11 @@ edisp, b, h, no,,, &quot;Apply energy dispersion?&quot; @@ -30,6 +30,11 @@ edisp, b, h, no,,, &quot;Apply energy dispersion?&quot;
30 outmap, f, a, "tsmap.fits",,, "Output Test Statistic map file" 30 outmap, f, a, "tsmap.fits",,, "Output Test Statistic map file"
31 31
32 # 32 #
  33 +# TS map computation parameters
  34 +#==============================
  35 +errors, b, h, no,,, "Compute and store parameter errors?"
  36 +
  37 +#
33 # Spatial binning parameters 38 # Spatial binning parameters
34 #=========================== 39 #===========================
35 usepnt, b, h, no,,, "Use pointing instead of xref/yref parameters?" 40 usepnt, b, h, no,,, "Use pointing instead of xref/yref parameters?"
@@ -43,7 +48,7 @@ proj, s, a, &quot;CAR&quot;, AIT|AZP|CAR|MER|MOL|STG|TAN,, &quot;Projection method&quot; @@ -43,7 +48,7 @@ proj, s, a, &quot;CAR&quot;, AIT|AZP|CAR|MER|MOL|STG|TAN,, &quot;Projection method&quot;
43 48
44 # 49 #
45 # Parameters for splitting and speed purpose 50 # Parameters for splitting and speed purpose
46 -#=========================== 51 +#===========================================
47 binmin, i, h, -1,,, "First bin to compute" 52 binmin, i, h, -1,,, "First bin to compute"
48 binmax, i, h, -1,,, "Last bin to compute" 53 binmax, i, h, -1,,, "Last bin to compute"
49 logL0, r, h, 0.0,,, "LogLikelihood value of null hypothesis" 54 logL0, r, h, 0.0,,, "LogLikelihood value of null hypothesis"
test/data/tsmap_0.fits
No preview for this file type
test/data/tsmap_1.fits
No preview for this file type
test/test_csiactobs.py
@@ -148,7 +148,7 @@ class Test(test): @@ -148,7 +148,7 @@ class Test(test):
148 148
149 # Check empty observation definition XML file 149 # Check empty observation definition XML file
150 self._check_obsdef('csiactobs_obs_py0.xml', 0) 150 self._check_obsdef('csiactobs_obs_py0.xml', 0)
151 - 151 +
152 # Check empty model definition XML file 152 # Check empty model definition XML file
153 self._check_moddef('csiactobs_bgd_py0.xml', 0) 153 self._check_moddef('csiactobs_bgd_py0.xml', 0)
154 154
test/test_cstsmapmerge.py
@@ -98,7 +98,7 @@ class Test(test): @@ -98,7 +98,7 @@ class Test(test):
98 # Check if execution failed 98 # Check if execution failed
99 self.test_assert(self._execute(cmd) != 0, 99 self.test_assert(self._execute(cmd) != 0,
100 'Check invalid input file when executed from command line') 100 'Check invalid input file when executed from command line')
101 - 101 +
102 # Return 102 # Return
103 return 103 return
104 104
@@ -160,10 +160,10 @@ class Test(test): @@ -160,10 +160,10 @@ class Test(test):
160 160
161 # Check merged TS map 161 # Check merged TS map
162 self._check_result_file('cstsmapmerge_py4.fits') 162 self._check_result_file('cstsmapmerge_py4.fits')
163 -  
164 - # Set-up space-separated cstsmapmerge with invalid files 163 +
  164 + # Set-up cstsmapmerge with incomplete file list
165 merge = cscripts.cstsmapmerge() 165 merge = cscripts.cstsmapmerge()
166 - merge['inmaps'] = self._events+' '+self._model 166 + merge['inmaps'] = self._map0 + ' ' + self._events
167 merge['outmap'] = 'cstsmapmerge_py5.fits' 167 merge['outmap'] = 'cstsmapmerge_py5.fits'
168 merge['logfile'] = 'cstsmapmerge_py5.log' 168 merge['logfile'] = 'cstsmapmerge_py5.log'
169 merge['chatter'] = 4 169 merge['chatter'] = 4
@@ -172,13 +172,13 @@ class Test(test): @@ -172,13 +172,13 @@ class Test(test):
172 merge.execute() 172 merge.execute()
173 173
174 # Check merged TS map 174 # Check merged TS map
175 - #self._check_result_file('cstsmapmerge_py5.fits') 175 + self._check_result_file('cstsmapmerge_py5.fits', False)
176 176
177 # Return 177 # Return
178 return 178 return
179 179
180 # Check result file 180 # Check result file
181 - def _check_result_file(self, filename): 181 + def _check_result_file(self, filename, test_complete = True):
182 """ 182 """
183 Check result file 183 Check result file
184 """ 184 """
@@ -189,6 +189,7 @@ class Test(test): @@ -189,6 +189,7 @@ class Test(test):
189 ts = fits['Primary'] 189 ts = fits['Primary']
190 prefactor = fits['Prefactor'] 190 prefactor = fits['Prefactor']
191 index = fits['Index'] 191 index = fits['Index']
  192 + status = fits['STATUS MAP']
192 193
193 # Check dimensions 194 # Check dimensions
194 self.test_value(ts.naxis(), 2, 'Check for 2 dimensions') 195 self.test_value(ts.naxis(), 2, 'Check for 2 dimensions')
@@ -200,6 +201,23 @@ class Test(test): @@ -200,6 +201,23 @@ class Test(test):
200 self.test_value(index.naxis(), 2, 'Check for 2 dimensions') 201 self.test_value(index.naxis(), 2, 'Check for 2 dimensions')
201 self.test_value(index.naxes(0), 2, 'Check for 2 pixels in X') 202 self.test_value(index.naxes(0), 2, 'Check for 2 pixels in X')
202 self.test_value(index.naxes(1), 1, 'Check for 1 pixel in Y') 203 self.test_value(index.naxes(1), 1, 'Check for 1 pixel in Y')
  204 + self.test_value(status.naxis(), 2, 'Check for 2 dimensions')
  205 + self.test_value(status.naxes(0), 2, 'Check for 2 pixels in X')
  206 + self.test_value(status.naxes(1), 1, 'Check for 1 pixel in Y')
  207 +
  208 + # Initialise flag if map is complete
  209 + done = True
  210 +
  211 + # Loop over status sky map
  212 + for pix in status:
  213 +
  214 + # Check if pix is larger than threshold
  215 + if pix < -0.5:
  216 + done = False
  217 + break
  218 +
  219 + # Test for completeness of merged map
  220 + self.test_assert(done == test_complete, 'Test if map was merged completely')
203 221
204 # Return 222 # Return
205 return 223 return
test/test_cttsmap.py
@@ -98,6 +98,23 @@ class Test(test): @@ -98,6 +98,23 @@ class Test(test):
98 self.test_assert(self._execute(cmd) != 0, 98 self.test_assert(self._execute(cmd) != 0,
99 'Check invalid input file when executed from command line') 99 'Check invalid input file when executed from command line')
100 100
  101 + # Setup cttsmap command
  102 + cmd = cttsmap+' inobs="'+self._events+'"'+ \
  103 + ' inmodel="'+self._model+'" srcname="Crab"'+ \
  104 + ' caldb="'+self._caldb+'" irf="'+self._irf+'"'+ \
  105 + ' errors=yes'+ \
  106 + ' outmap="cttsmap_cmd3.fits"'+ \
  107 + ' nxpix=3 nypix=3 binsz=0.02'+ \
  108 + ' coordsys="CEL" proj="CAR" xref=83.63 yref=22.01'+ \
  109 + ' logfile="cttsmap_cmd3.log" chatter=1'
  110 +
  111 + # Check if execution was successful
  112 + self.test_assert(self._execute(cmd) == 0,
  113 + 'Check successful execution from command line')
  114 +
  115 + # Check result file
  116 + self._check_result_file('cttsmap_cmd3.fits')
  117 +
101 # Setup cttsmap --help option 118 # Setup cttsmap --help option
102 cmd = cttsmap+' --help' 119 cmd = cttsmap+' --help'
103 120
@@ -267,7 +284,7 @@ class Test(test): @@ -267,7 +284,7 @@ class Test(test):
267 nmaps = 1 284 nmaps = 1
268 else: 285 else:
269 nmaps = 0 286 nmaps = 0
270 - 287 +
271 # Check dimensions 288 # Check dimensions
272 self.test_value(tsmap.nmaps(), nmaps, 'Check number of maps') 289 self.test_value(tsmap.nmaps(), nmaps, 'Check number of maps')
273 self.test_value(tsmap.nx(), nx, 'Check for number of X pixels') 290 self.test_value(tsmap.nx(), nx, 'Check for number of X pixels')