Commit 523323c92ca0e3e723116d51564677176a3a2ff4

Authored by Jürgen Knödlseder
2 parents a446d51c add41cca

Merge branch '1828-quality-of-iact-cscripts' into integration

# Conflicts:
#	cscripts/csiactcopy.py
#	cscripts/csiactdata.py
cscripts/Makefile.am
@@ -152,7 +152,8 @@ testdata = $(top_srcdir)/test/data/crab.xml \ @@ -152,7 +152,8 @@ testdata = $(top_srcdir)/test/data/crab.xml \
152 $(top_srcdir)/test/data/models_spectral.xml \ 152 $(top_srcdir)/test/data/models_spectral.xml \
153 $(top_srcdir)/test/data/model_filefunction.txt \ 153 $(top_srcdir)/test/data/model_filefunction.txt \
154 $(top_srcdir)/test/data/model_map.fits.gz \ 154 $(top_srcdir)/test/data/model_map.fits.gz \
155 - $(top_srcdir)/test/data/model_mapcube.fits.gz 155 + $(top_srcdir)/test/data/model_mapcube.fits.gz \
  156 + $(top_srcdir)/test/data/iact_runlist.dat
156 157
157 # Test data to be distributed in $(pyexecdir)/cscripts/tests/data/iactdata 158 # Test data to be distributed in $(pyexecdir)/cscripts/tests/data/iactdata
158 testiactdata = $(top_srcdir)/test/data/iactdata/hdu-index.fits.gz \ 159 testiactdata = $(top_srcdir)/test/data/iactdata/hdu-index.fits.gz \
cscripts/csiactcopy.py
@@ -91,7 +91,18 @@ class csiactcopy(ctools.cscript): @@ -91,7 +91,18 @@ class csiactcopy(ctools.cscript):
91 def _copy(self, source, clobber): 91 def _copy(self, source, clobber):
92 """ 92 """
93 Copy file to outpath 93 Copy file to outpath
  94 +
  95 + Parameters
  96 + ----------
  97 + source : string
  98 + Path of file to be copied
  99 +
  100 + Returns
  101 + -------
  102 + filesize : float
  103 + Size of the file that was copied
94 """ 104 """
  105 +
95 # Get file destination 106 # Get file destination
96 destination = os.path.join(self._outpath, 107 destination = os.path.join(self._outpath,
97 os.path.relpath(source, self._remote_base)) 108 os.path.relpath(source, self._remote_base))
@@ -147,10 +158,21 @@ class csiactcopy(ctools.cscript): @@ -147,10 +158,21 @@ class csiactcopy(ctools.cscript):
147 def _merge(self, localfits, remotefits, hduname, clobber): 158 def _merge(self, localfits, remotefits, hduname, clobber):
148 """ 159 """
149 Merge remote and local fits files 160 Merge remote and local fits files
150 -  
151 If the local fits file is not present, a new one is created. 161 If the local fits file is not present, a new one is created.
  162 +
  163 + Parameters
  164 + ----------
  165 + localfits : string
  166 + Path of local index FITS file
  167 + remotefits : string
  168 + Path of remote index FITS file
  169 + hduname : string
  170 + Name of HDU extension to be merged
  171 + clobber : bool
  172 + Flag if remote content should overwrite local content
152 """ 173 """
153 - # ... 174 +
  175 + # Logging
154 if self._logTerse(): 176 if self._logTerse():
155 self._log_value('Local file', localfits) 177 self._log_value('Local file', localfits)
156 self._log_value('Remote file', remotefits) 178 self._log_value('Remote file', remotefits)
@@ -214,7 +236,7 @@ class csiactcopy(ctools.cscript): @@ -214,7 +236,7 @@ class csiactcopy(ctools.cscript):
214 tmp_hdu = remote[hduname] 236 tmp_hdu = remote[hduname]
215 237
216 # Get old size of remote HDU 238 # Get old size of remote HDU
217 - size = remote_hdu.size() 239 + size = remote_hdu.nrows()
218 240
219 # Extend remote HDU 241 # Extend remote HDU
220 remote_hdu.append_rows(tmp_hdu.nrows()) 242 remote_hdu.append_rows(tmp_hdu.nrows())
@@ -229,8 +251,8 @@ class csiactcopy(ctools.cscript): @@ -229,8 +251,8 @@ class csiactcopy(ctools.cscript):
229 robs_col = remote_hdu['OBS_ID'] 251 robs_col = remote_hdu['OBS_ID']
230 for obs_id in robs_col: 252 for obs_id in robs_col:
231 remote_obs.append(obs_id) 253 remote_obs.append(obs_id)
232 -  
233 - # Dump the number of remote and local entries 254 +
  255 + # Log entries of index files
234 if self._logTerse(): 256 if self._logTerse():
235 self._log_value('Remote entries', len(remote_obs)) 257 self._log_value('Remote entries', len(remote_obs))
236 self._log_value('Local entries', len(local_obs)) 258 self._log_value('Local entries', len(local_obs))
@@ -250,12 +272,18 @@ class csiactcopy(ctools.cscript): @@ -250,12 +272,18 @@ class csiactcopy(ctools.cscript):
250 272
251 # Remove local obs_id entries 273 # Remove local obs_id entries
252 table_has_obsid = True 274 table_has_obsid = True
  275 +
  276 + # Loop over obs ids and overwrite with remote content
253 while table_has_obsid: 277 while table_has_obsid:
  278 +
  279 + # First remove old rows
254 for i in range(local_hdu.nrows()): 280 for i in range(local_hdu.nrows()):
255 if remote_obs_id == local_hdu['OBS_ID'][i]: 281 if remote_obs_id == local_hdu['OBS_ID'][i]:
256 local_hdu.remove_rows(i,1) 282 local_hdu.remove_rows(i,1)
257 removed_rows += 1 283 removed_rows += 1
258 break 284 break
  285 +
  286 + # Replace with remote content
259 table_has_obsid = False 287 table_has_obsid = False
260 for i in range(local_hdu.nrows()): 288 for i in range(local_hdu.nrows()):
261 if remote_obs_id == local_hdu['OBS_ID'][i]: 289 if remote_obs_id == local_hdu['OBS_ID'][i]:
@@ -290,8 +318,8 @@ class csiactcopy(ctools.cscript): @@ -290,8 +318,8 @@ class csiactcopy(ctools.cscript):
290 318
291 # Add remote HDUs 319 # Add remote HDUs
292 local_hdu.insert_rows(old_local_rows, remote_hdu.nrows()) 320 local_hdu.insert_rows(old_local_rows, remote_hdu.nrows())
293 -  
294 - # Dump ... 321 +
  322 + # Log actions
295 if self._logTerse(): 323 if self._logTerse():
296 if clobber: 324 if clobber:
297 what = 'Removed local rows' 325 what = 'Removed local rows'
@@ -344,6 +372,8 @@ class csiactcopy(ctools.cscript): @@ -344,6 +372,8 @@ class csiactcopy(ctools.cscript):
344 # Check if runlist file is available 372 # Check if runlist file is available
345 if self._runlist.exists(): 373 if self._runlist.exists():
346 runfile = open(self._runlist.url()) 374 runfile = open(self._runlist.url())
  375 +
  376 + # Read runlist
347 for line in runfile.readlines(): 377 for line in runfile.readlines():
348 if len(line) == 0: 378 if len(line) == 0:
349 continue 379 continue
@@ -351,6 +381,8 @@ class csiactcopy(ctools.cscript): @@ -351,6 +381,8 @@ class csiactcopy(ctools.cscript):
351 continue 381 continue
352 if len(line.split()) > 0: 382 if len(line.split()) > 0:
353 self._runs.append(int(line.split()[0])) 383 self._runs.append(int(line.split()[0]))
  384 +
  385 + # Close runlist file
354 runfile.close() 386 runfile.close()
355 387
356 # Logging 388 # Logging
@@ -428,8 +460,8 @@ class csiactcopy(ctools.cscript): @@ -428,8 +460,8 @@ class csiactcopy(ctools.cscript):
428 # Initialise flag if SIZE column is present 460 # Initialise flag if SIZE column is present
429 has_size = table.contains('SIZE') 461 has_size = table.contains('SIZE')
430 462
  463 + # Initialise file size
431 if has_size: 464 if has_size:
432 - # Initialise file size  
433 cp_size = 0 465 cp_size = 0
434 466
435 # Initialise remote observation IDs 467 # Initialise remote observation IDs
@@ -439,6 +471,8 @@ class csiactcopy(ctools.cscript): @@ -439,6 +471,8 @@ class csiactcopy(ctools.cscript):
439 471
440 # Log runs that are not available remotely 472 # Log runs that are not available remotely
441 for run in self._runs: 473 for run in self._runs:
  474 +
  475 + # Check for run not in remote data store
442 if not run in remote_ids: 476 if not run in remote_ids:
443 if self._logNormal(): 477 if self._logNormal():
444 self._log('Skip observation '+str(run)+': ') 478 self._log('Skip observation '+str(run)+': ')
@@ -529,16 +563,22 @@ class csiactcopy(ctools.cscript): @@ -529,16 +563,22 @@ class csiactcopy(ctools.cscript):
529 self._log('\n') 563 self._log('\n')
530 self._log.header1('Copying files') 564 self._log.header1('Copying files')
531 565
532 - # intialise counter 566 + # Intialise counter
533 k = 0 567 k = 0
534 568
535 - # initialise values for logging 569 + # Initialise values for logging
536 last_fraction = 0.0 570 last_fraction = 0.0
537 fraction_increment = 20.0 571 fraction_increment = 20.0
  572 +
  573 + # Use 10% step increase
538 if self._logNormal(): 574 if self._logNormal():
539 fraction_increment = 10.0 575 fraction_increment = 10.0
  576 +
  577 + # Use 5% step increase
540 if self._logTerse(): 578 if self._logTerse():
541 fraction_increment = 5.0 579 fraction_increment = 5.0
  580 +
  581 + # Use 2% step increase
542 if self._logExplicit(): 582 if self._logExplicit():
543 fraction_increment = 2.0 583 fraction_increment = 2.0
544 584
@@ -552,6 +592,8 @@ class csiactcopy(ctools.cscript): @@ -552,6 +592,8 @@ class csiactcopy(ctools.cscript):
552 # Log progress 592 # Log progress
553 fraction = float(k) / float(len(files)) * 100.0 593 fraction = float(k) / float(len(files)) * 100.0
554 while fraction > last_fraction: 594 while fraction > last_fraction:
  595 +
  596 + # Print status of copying procedure
555 if self._logNormal() and not self._logVerbose(): 597 if self._logNormal() and not self._logVerbose():
556 self._log_value('Status', '%d %%' % int(last_fraction)) 598 self._log_value('Status', '%d %%' % int(last_fraction))
557 last_fraction += fraction_increment 599 last_fraction += fraction_increment
@@ -565,7 +607,7 @@ class csiactcopy(ctools.cscript): @@ -565,7 +607,7 @@ class csiactcopy(ctools.cscript):
565 total_size += filesize 607 total_size += filesize
566 n_copied += 1 608 n_copied += 1
567 609
568 - # Increment counter 610 + # Increment file counter
569 k += 1 611 k += 1
570 612
571 # Logging 613 # Logging
@@ -573,14 +615,17 @@ class csiactcopy(ctools.cscript): @@ -573,14 +615,17 @@ class csiactcopy(ctools.cscript):
573 self._log.parformat('Status') 615 self._log.parformat('Status')
574 self._log('Finished') 616 self._log('Finished')
575 self._log('\n') 617 self._log('\n')
  618 +
  619 + # Logging about index files
576 if self._logTerse(): 620 if self._logTerse():
577 self._log('\n') 621 self._log('\n')
578 self._log.header1('Updating index files') 622 self._log.header1('Updating index files')
579 623
580 - # Build local index file names 624 + # Build local hdu index file name
581 local_hdu = os.path.join(self._outpath, 625 local_hdu = os.path.join(self._outpath,
582 os.path.relpath(remote_hdu, 626 os.path.relpath(remote_hdu,
583 self._remote_base)) 627 self._remote_base))
  628 + # Build local obs index file name
584 local_obs = os.path.join(self._outpath, 629 local_obs = os.path.join(self._outpath,
585 os.path.relpath(remote_obs, 630 os.path.relpath(remote_obs,
586 self._remote_base)) 631 self._remote_base))
@@ -596,6 +641,7 @@ class csiactcopy(ctools.cscript): @@ -596,6 +641,7 @@ class csiactcopy(ctools.cscript):
596 # Merge remote index files with local files 641 # Merge remote index files with local files
597 self._merge(local_hdu, remote_hdu, 'HDU_INDEX', self._clobber()) 642 self._merge(local_hdu, remote_hdu, 'HDU_INDEX', self._clobber())
598 643
  644 + # Logging
599 if self._logTerse(): 645 if self._logTerse():
600 self._log('\n') 646 self._log('\n')
601 self._log.header3('OBS index') 647 self._log.header3('OBS index')
@@ -607,7 +653,8 @@ class csiactcopy(ctools.cscript): @@ -607,7 +653,8 @@ class csiactcopy(ctools.cscript):
607 # If all files were copied, just copy index files too 653 # If all files were copied, just copy index files too
608 self._copy(remote_hdu, self._clobber()) 654 self._copy(remote_hdu, self._clobber())
609 self._copy(remote_obs, self._clobber()) 655 self._copy(remote_obs, self._clobber())
610 - 656 +
  657 + # Logging
611 if self._logTerse(): 658 if self._logTerse():
612 self._log('\n') 659 self._log('\n')
613 self._log.header3('Master index file') 660 self._log.header3('Master index file')
cscripts/csiactdata.py
@@ -95,6 +95,12 @@ class csiactdata(ctools.cscript): @@ -95,6 +95,12 @@ class csiactdata(ctools.cscript):
95 def _log_configuration(self, config): 95 def _log_configuration(self, config):
96 """ 96 """
97 Log configuration 97 Log configuration
  98 +
  99 + Parameters
  100 + ----------
  101 + config : dict
  102 + Dictionary containing data configuration
  103 +
98 """ 104 """
99 # Log only if the level is at least "Terse" 105 # Log only if the level is at least "Terse"
100 if self._logTerse(): 106 if self._logTerse():
@@ -107,6 +113,8 @@ class csiactdata(ctools.cscript): @@ -107,6 +113,8 @@ class csiactdata(ctools.cscript):
107 113
108 # Print additional information 114 # Print additional information
109 for key in config: 115 for key in config:
  116 +
  117 + # Skip keys that were treated above
110 if key in ['name','hduindx','obsindx']: 118 if key in ['name','hduindx','obsindx']:
111 continue 119 continue
112 self._log_value(key, config[key]) 120 self._log_value(key, config[key])
cscripts/csiactobs.py
@@ -47,9 +47,10 @@ class csiactobs(ctools.cscript): @@ -47,9 +47,10 @@ class csiactobs(ctools.cscript):
47 """ 47 """
48 # Set name and version 48 # Set name and version
49 self._name = 'csiactobs' 49 self._name = 'csiactobs'
50 - self._version = '1.1.0' 50 + self._version = '1.2.0'
51 51
52 # Initialise some members 52 # Initialise some members
  53 + self._obs = gammalib.GObservations()
53 self._ebounds = gammalib.GEbounds() 54 self._ebounds = gammalib.GEbounds()
54 self._datapath = os.getenv('VHEFITS','') 55 self._datapath = os.getenv('VHEFITS','')
55 self._inmodels = gammalib.GModels() 56 self._inmodels = gammalib.GModels()
@@ -59,8 +60,8 @@ class csiactobs(ctools.cscript): @@ -59,8 +60,8 @@ class csiactobs(ctools.cscript):
59 self._runlist = [] 60 self._runlist = []
60 self._runlistfile = gammalib.GFilename() 61 self._runlistfile = gammalib.GFilename()
61 self._bkgpars = 0 62 self._bkgpars = 0
62 - self._outmodel = gammalib.GFilename()  
63 - self._outobs = gammalib.GFilename() 63 + #self._outmodel = gammalib.GFilename()
  64 + #self._outobs = gammalib.GFilename()
64 self._master_indx = '' 65 self._master_indx = ''
65 self._use_bkg_scale = False 66 self._use_bkg_scale = False
66 self._ev_hiera = [''] 67 self._ev_hiera = ['']
@@ -80,8 +81,7 @@ class csiactobs(ctools.cscript): @@ -80,8 +81,7 @@ class csiactobs(ctools.cscript):
80 self._subdir = '' 81 self._subdir = ''
81 self._debug = False 82 self._debug = False
82 83
83 - # Initialise application by calling the appropriate class  
84 - # constructor. 84 + # Initialise application by calling the appropriate class constructor
85 self._init_cscript(argv) 85 self._init_cscript(argv)
86 86
87 # Return 87 # Return
@@ -91,7 +91,7 @@ class csiactobs(ctools.cscript): @@ -91,7 +91,7 @@ class csiactobs(ctools.cscript):
91 # Private methods 91 # Private methods
92 def _get_parameters(self): 92 def _get_parameters(self):
93 """ 93 """
94 - Get parameters from parfile and setup the observation. 94 + Get parameters from parfile and setup the observation
95 """ 95 """
96 # Set data path 96 # Set data path
97 if self._datapath == '': 97 if self._datapath == '':
@@ -105,7 +105,7 @@ class csiactobs(ctools.cscript): @@ -105,7 +105,7 @@ class csiactobs(ctools.cscript):
105 self._datapath = gammalib.expand_env(self._datapath) 105 self._datapath = gammalib.expand_env(self._datapath)
106 106
107 # Read FITS production 107 # Read FITS production
108 - self._prodname = self['prodname'].string() 108 + self._prodname = self['prodname'].string()
109 109
110 # Read runlist file if list not already filled 110 # Read runlist file if list not already filled
111 if len(self._runlist) == 0: 111 if len(self._runlist) == 0:
@@ -125,13 +125,12 @@ class csiactobs(ctools.cscript): @@ -125,13 +125,12 @@ class csiactobs(ctools.cscript):
125 runfile.close() 125 runfile.close()
126 126
127 # Read number of background parameters 127 # Read number of background parameters
128 - self._bkgpars = self['bkgpars'].integer()  
129 -  
130 - # Output model file  
131 - self._outmodel = self['outmodel'].filename()  
132 -  
133 - # Observation outfile  
134 - self._outobs = self['outobs'].filename() 128 + self._bkgpars = self['bkgpars'].integer()
  129 +
  130 + # Query ahead output parameters
  131 + if self._read_ahead():
  132 + self['outmodel'].filename()
  133 + self['outobs'].filename()
135 134
136 # Master index file name 135 # Master index file name
137 self._master_indx = self['master_indx'].string() 136 self._master_indx = self['master_indx'].string()
@@ -174,27 +173,45 @@ class csiactobs(ctools.cscript): @@ -174,27 +173,45 @@ class csiactobs(ctools.cscript):
174 173
175 # Get HDUs 174 # Get HDUs
176 for config in configs: 175 for config in configs:
  176 +
  177 + # Check if prodname is present
177 if self._prodname == config['name']: 178 if self._prodname == config['name']:
178 self._hdu_index = str(os.path.join(self._datapath, config['hduindx'])) 179 self._hdu_index = str(os.path.join(self._datapath, config['hduindx']))
179 self._obs_index = str(os.path.join(self._datapath, config['obsindx'])) 180 self._obs_index = str(os.path.join(self._datapath, config['obsindx']))
  181 +
  182 + # Leave loop if index file names were found
180 break 183 break
181 184
182 - # Check HDUs 185 + # Check index files
183 if self._hdu_index == '' or self._obs_index == '': 186 if self._hdu_index == '' or self._obs_index == '':
184 raise RuntimeError('*** ERROR: FITS data store "'+self._prodname+'" not available. Run csiactdata to get a list of available storage names') 187 raise RuntimeError('*** ERROR: FITS data store "'+self._prodname+'" not available. Run csiactdata to get a list of available storage names')
  188 +
  189 + # Check HDU names
185 filename = gammalib.GFilename(self._hdu_index+'[HDU_INDEX]') 190 filename = gammalib.GFilename(self._hdu_index+'[HDU_INDEX]')
186 if not filename.is_fits(): 191 if not filename.is_fits():
187 raise RuntimeError('*** ERROR: HDU index file "'+self._hdu_index+'[HDU_INDEX]" for FITS data store "'+self._prodname+'" not available. Check your master index file or run csiactdata to get a list of available storage names.') 192 raise RuntimeError('*** ERROR: HDU index file "'+self._hdu_index+'[HDU_INDEX]" for FITS data store "'+self._prodname+'" not available. Check your master index file or run csiactdata to get a list of available storage names.')
188 193
189 # Check for existence of 'BKG_SCALE' in the observation index file if required 194 # Check for existence of 'BKG_SCALE' in the observation index file if required
190 if self._use_bkg_scale: 195 if self._use_bkg_scale:
  196 +
  197 + # Create filename
191 filename = gammalib.GFilename(self._obs_index+'[OBS_INDEX]') 198 filename = gammalib.GFilename(self._obs_index+'[OBS_INDEX]')
  199 +
  200 + # Check if it is a FITS file
192 if filename.is_fits(): 201 if filename.is_fits():
  202 +
  203 + # Open FITS file
193 fits = gammalib.GFits(self._obs_index) 204 fits = gammalib.GFits(self._obs_index)
  205 +
  206 + # Check if column "BKG_SCALE" is found and signal its possible usage
194 if not fits['OBS_INDEX'].contains('BKG_SCALE'): 207 if not fits['OBS_INDEX'].contains('BKG_SCALE'):
195 self._use_bkg_scale = False 208 self._use_bkg_scale = False
  209 +
  210 + # Close FITS file
196 fits.close() 211 fits.close()
  212 +
197 else: 213 else:
  214 + # Signal that there is no background scale
198 self._use_bkg_scale = False 215 self._use_bkg_scale = False
199 216
200 # Create base data directory from hdu index file location 217 # Create base data directory from hdu index file location
@@ -209,33 +226,37 @@ class csiactobs(ctools.cscript): @@ -209,33 +226,37 @@ class csiactobs(ctools.cscript):
209 # Return 226 # Return
210 return 227 return
211 228
212 - def runlist(self, runlist):  
213 - """  
214 - Set observation list 229 + def _background_spectrum(self, prefactor, index, emin = 0.01, emax = 100.0):
215 """ 230 """
  231 + Create a background spectrum model dependent on user parameters
216 232
217 - # Check if convertable to a python list  
218 - try:  
219 -  
220 - # Store a copy of input argument  
221 - self._runlist = list(runlist)  
222 -  
223 - except:  
224 -  
225 - # raise error if wrong type detected  
226 - raise RuntimeError('Argument of csiactobs.runlist() must be of type "list"') 233 + Parameters
  234 + ----------
  235 + prefactor : float
  236 + Prefactor parameter of spectral model
  237 + index : float
  238 + Index parameter of spectral model
  239 + emin : float
  240 + Minimum energy (in case a spectral node function is required)
  241 + emax : float
  242 + Maximum energy (in case a spectral node function is required)
227 243
228 - # Return  
229 - return  
230 -  
231 - def _background_spectrum(self, run, prefactor, index, emin = 0.01, emax = 100.0): 244 + Returns
  245 + -------
  246 + spec : `~gammalib.GModelSpectral()`
  247 + Spectral model for the background shape
  248 + """
232 249
233 # Handle constant spectral model 250 # Handle constant spectral model
234 if index == 0.0 and self._bkgpars <= 1: 251 if index == 0.0 and self._bkgpars <= 1:
235 spec = gammalib.GModelSpectralConst() 252 spec = gammalib.GModelSpectralConst()
  253 +
  254 + # Set parameter range
236 spec['Normalization'].min(prefactor / self._bkg_range_factor) 255 spec['Normalization'].min(prefactor / self._bkg_range_factor)
237 spec['Normalization'].max(prefactor * self._bkg_range_factor) 256 spec['Normalization'].max(prefactor * self._bkg_range_factor)
238 spec['Normalization'].value(prefactor) 257 spec['Normalization'].value(prefactor)
  258 +
  259 + # Freeze or release normalisation parameter
239 if self._bkgpars == 0: 260 if self._bkgpars == 0:
240 spec['Normalization'].fix() 261 spec['Normalization'].fix()
241 else: 262 else:
@@ -245,8 +266,10 @@ class csiactobs(ctools.cscript): @@ -245,8 +266,10 @@ class csiactobs(ctools.cscript):
245 266
246 # Create power law model 267 # Create power law model
247 if self._bkgpars <= 2: 268 if self._bkgpars <= 2:
248 - e = gammalib.GEnergy(1.0,'TeV')  
249 - spec = gammalib.GModelSpectralPlaw(prefactor, index, e) 269 +
  270 + # Set Power Law model with arbitrary pivot energy
  271 + pivot = gammalib.GEnergy(1.0,'TeV')
  272 + spec = gammalib.GModelSpectralPlaw(prefactor, index, pivot)
250 273
251 # Set parameter ranges 274 # Set parameter ranges
252 spec[0].min(prefactor / self._bkg_range_factor) 275 spec[0].min(prefactor / self._bkg_range_factor)
@@ -269,19 +292,31 @@ class csiactobs(ctools.cscript): @@ -269,19 +292,31 @@ class csiactobs(ctools.cscript):
269 else: 292 else:
270 293
271 # Create reference powerlaw 294 # Create reference powerlaw
272 - plaw = gammalib.GModelSpectralPlaw(prefactor, index, gammalib.GEnergy(1.0,'TeV')) 295 + pivot = gammalib.GEnergy(1.0,'TeV')
  296 + plaw = gammalib.GModelSpectralPlaw(prefactor, index, pivot)
273 297
274 # Create spectral model and energy values 298 # Create spectral model and energy values
275 spec = gammalib.GModelSpectralNodes() 299 spec = gammalib.GModelSpectralNodes()
  300 +
  301 + # Create logarithmic energy nodes
276 bounds = gammalib.GEbounds(self._bkgpars,gammalib.GEnergy(emin,'TeV'),gammalib.GEnergy(emax,'TeV'), True) 302 bounds = gammalib.GEbounds(self._bkgpars,gammalib.GEnergy(emin,'TeV'),gammalib.GEnergy(emax,'TeV'), True)
  303 +
  304 + # Loop over bounds and set intensity value
277 for i in range(bounds.size()): 305 for i in range(bounds.size()):
278 energy = bounds.elogmean(i) 306 energy = bounds.elogmean(i)
279 - value = plaw.eval(energy, gammalib.GTime()) 307 + value = plaw.eval(energy)
  308 +
  309 + # Append energy, value - tuple to node function
280 spec.append(energy, value) 310 spec.append(energy, value)
  311 +
  312 + # Loop over parameters
281 for par in spec: 313 for par in spec:
282 314
  315 + # Fix energy nodes
283 if 'Energy' in par.name(): 316 if 'Energy' in par.name():
284 par.fix() 317 par.fix()
  318 +
  319 + # Release intensity nodes
285 elif 'Intensity' in par.name(): 320 elif 'Intensity' in par.name():
286 value = par.value() 321 value = par.value()
287 par.scale(value) 322 par.scale(value)
@@ -292,13 +327,36 @@ class csiactobs(ctools.cscript): @@ -292,13 +327,36 @@ class csiactobs(ctools.cscript):
292 return spec 327 return spec
293 328
294 def _iact_background(self, telescope, obs_id, bkg_scale, bkgtype, emin=0.01, emax=100): 329 def _iact_background(self, telescope, obs_id, bkg_scale, bkgtype, emin=0.01, emax=100):
  330 + """
  331 + Create an IACT background model
  332 +
  333 + Parameters
  334 + ----------
  335 + telescope : string
  336 + Name of telescope
  337 + obs_id : string
  338 + Observation ID
  339 + bkg_scale : float
  340 + Background scaling factor
  341 + bkgtype : string
  342 + Type of background (irf,aeff, or gauss)
295 343
  344 + Returns
  345 + -------
  346 + model : `~gammalib.GModelData()`
  347 + Background model for IACT observation
  348 + """
  349 +
296 # handle IrfBackground 350 # handle IrfBackground
297 if bkgtype == 'irf': 351 if bkgtype == 'irf':
  352 +
  353 + # Set parameters to have a constant spectral model
298 prefactor = 1.0 354 prefactor = 1.0
299 index = 0.0 355 index = 0.0
300 prefactor *= bkg_scale 356 prefactor *= bkg_scale
301 - spec = self._background_spectrum(obs_id, prefactor, index, emin, emax) 357 +
  358 + # Create background spectrum
  359 + spec = self._background_spectrum(prefactor, index, emin, emax)
302 360
303 # Create background model instance 361 # Create background model instance
304 bck = gammalib.GCTAModelIrfBackground(spec) 362 bck = gammalib.GCTAModelIrfBackground(spec)
@@ -306,7 +364,7 @@ class csiactobs(ctools.cscript): @@ -306,7 +364,7 @@ class csiactobs(ctools.cscript):
306 # Set AeffBackground 364 # Set AeffBackground
307 elif bkgtype == 'aeff': 365 elif bkgtype == 'aeff':
308 prefactor = bkg_scale * self._bkg_aeff_norm 366 prefactor = bkg_scale * self._bkg_aeff_norm
309 - spec = self._background_spectrum(obs_id, prefactor, self._bkg_aeff_index, emin, emax) 367 + spec = self._background_spectrum(prefactor, self._bkg_aeff_index, emin, emax)
310 368
311 # Create background model instance 369 # Create background model instance
312 bck = gammalib.GCTAModelAeffBackground(spec) 370 bck = gammalib.GCTAModelAeffBackground(spec)
@@ -314,12 +372,14 @@ class csiactobs(ctools.cscript): @@ -314,12 +372,14 @@ class csiactobs(ctools.cscript):
314 # Set Gaussian Background 372 # Set Gaussian Background
315 elif bkgtype == 'gauss': 373 elif bkgtype == 'gauss':
316 prefactor = bkg_scale * self._bkg_gauss_norm 374 prefactor = bkg_scale * self._bkg_gauss_norm
317 - spec = self._background_spectrum(obs_id, prefactor, self._bkg_gauss_index, emin, emax) 375 +
  376 + # Create background spectrum
  377 + spec = self._background_spectrum(prefactor, self._bkg_gauss_index, emin, emax)
318 radial = gammalib.GCTAModelRadialGauss(self._bkg_gauss_sigma) 378 radial = gammalib.GCTAModelRadialGauss(self._bkg_gauss_sigma)
319 bck = gammalib.GCTAModelRadialAcceptance(radial, spec) 379 bck = gammalib.GCTAModelRadialAcceptance(radial, spec)
320 380
321 else: 381 else:
322 - msg = 'Background type "'+self._bkgtype+'" unsupported' 382 + msg = 'Background type "'+bkgtype+'" unsupported'
323 raise RuntimeError(msg) 383 raise RuntimeError(msg)
324 384
325 # Copy model 385 # Copy model
@@ -383,6 +443,7 @@ class csiactobs(ctools.cscript): @@ -383,6 +443,7 @@ class csiactobs(ctools.cscript):
383 eventfile = aefffile = psffile = edispfile = bkgfile = '' 443 eventfile = aefffile = psffile = edispfile = bkgfile = ''
384 eventhdu = aeffhdu = '' 444 eventhdu = aeffhdu = ''
385 445
  446 + # Initialise types and formats
386 types = [] 447 types = []
387 formats = [] 448 formats = []
388 for i in range(hduindx_hdu.nrows()): 449 for i in range(hduindx_hdu.nrows()):
@@ -402,7 +463,11 @@ class csiactobs(ctools.cscript): @@ -402,7 +463,11 @@ class csiactobs(ctools.cscript):
402 hduindx_hdu['FILE_NAME'][index]) 463 hduindx_hdu['FILE_NAME'][index])
403 eventhdu = hduindx_hdu['HDU_NAME'][index] 464 eventhdu = hduindx_hdu['HDU_NAME'][index]
404 eventfile += '['+eventhdu+']' 465 eventfile += '['+eventhdu+']'
  466 +
  467 + # Check if psf file is available
405 if not gammalib.GFilename(eventfile).is_fits(): 468 if not gammalib.GFilename(eventfile).is_fits():
  469 +
  470 + # Print warning that observation will be skipped since no events are present
406 if self._logTerse(): 471 if self._logTerse():
407 self._log('Skipping observation '+str(obs_id)+ 472 self._log('Skipping observation '+str(obs_id)+
408 ': eventfile "'+eventfile+'" not found\n') 473 ': eventfile "'+eventfile+'" not found\n')
@@ -421,7 +486,11 @@ class csiactobs(ctools.cscript): @@ -421,7 +486,11 @@ class csiactobs(ctools.cscript):
421 hduindx_hdu['FILE_NAME'][index]) 486 hduindx_hdu['FILE_NAME'][index])
422 aeffhdu = hduindx_hdu['HDU_NAME'][index] 487 aeffhdu = hduindx_hdu['HDU_NAME'][index]
423 aefffile += '['+aeffhdu+']' 488 aefffile += '['+aeffhdu+']'
  489 +
  490 + # Check if psf file is available
424 if not gammalib.GFilename(aefffile).is_fits(): 491 if not gammalib.GFilename(aefffile).is_fits():
  492 +
  493 + # Print warning that observation will be skipped since no effective area is present
425 if self._logTerse(): 494 if self._logTerse():
426 self._log('Skipping observation '+str(obs_id)+ 495 self._log('Skipping observation '+str(obs_id)+
427 ': effective area "'+aefffile+'" not found\n') 496 ': effective area "'+aefffile+'" not found\n')
@@ -439,7 +508,11 @@ class csiactobs(ctools.cscript): @@ -439,7 +508,11 @@ class csiactobs(ctools.cscript):
439 hduindx_hdu['FILE_DIR'][index], 508 hduindx_hdu['FILE_DIR'][index],
440 hduindx_hdu['FILE_NAME'][index]) 509 hduindx_hdu['FILE_NAME'][index])
441 psffile += '['+hduindx_hdu['HDU_NAME'][index]+']' 510 psffile += '['+hduindx_hdu['HDU_NAME'][index]+']'
  511 +
  512 + # Check if psf file is available
442 if not gammalib.GFilename(psffile).is_fits(): 513 if not gammalib.GFilename(psffile).is_fits():
  514 +
  515 + # Print warning that observation will be skipped since no PSF is present
443 if self._logTerse(): 516 if self._logTerse():
444 self._log('Skipping observation '+str(obs_id)+ 517 self._log('Skipping observation '+str(obs_id)+
445 ': point spread function "'+psffile+ 518 ': point spread function "'+psffile+
@@ -458,7 +531,11 @@ class csiactobs(ctools.cscript): @@ -458,7 +531,11 @@ class csiactobs(ctools.cscript):
458 hduindx_hdu['FILE_DIR'][index], 531 hduindx_hdu['FILE_DIR'][index],
459 hduindx_hdu['FILE_NAME'][index]) 532 hduindx_hdu['FILE_NAME'][index])
460 edispfile += '['+hduindx_hdu['HDU_NAME'][index]+']' 533 edispfile += '['+hduindx_hdu['HDU_NAME'][index]+']'
  534 +
  535 + # Check if edisp file is available
461 if not gammalib.GFilename(edispfile).is_fits(): 536 if not gammalib.GFilename(edispfile).is_fits():
  537 +
  538 + # Print warning that edisp cannot be used for this observation
462 if self._logTerse(): 539 if self._logTerse():
463 self._log('Warning: observation '+str(obs_id)+ 540 self._log('Warning: observation '+str(obs_id)+
464 ' has no energy dispersion "'+edispfile+ 541 ' has no energy dispersion "'+edispfile+
@@ -480,17 +557,22 @@ class csiactobs(ctools.cscript): @@ -480,17 +557,22 @@ class csiactobs(ctools.cscript):
480 bkgfile += '['+hduindx_hdu['HDU_NAME'][index]+']' 557 bkgfile += '['+hduindx_hdu['HDU_NAME'][index]+']'
481 if 'irf' in bkg_mod_hierarchy and not gammalib.GFilename(bkgfile).is_fits(): 558 if 'irf' in bkg_mod_hierarchy and not gammalib.GFilename(bkgfile).is_fits():
482 bkg_mod_hierarchy.remove('irf') 559 bkg_mod_hierarchy.remove('irf')
  560 +
  561 + # Throw warning if IRF background cannot be used
483 if self._logTerse(): 562 if self._logTerse():
484 self._log('Warning: observation '+str(obs_id)+ 563 self._log('Warning: observation '+str(obs_id)+
485 ' has no background information (file="'+ 564 ' has no background information (file="'+
486 bkgfile+'"). IRF background cannot be used\n') 565 bkgfile+'"). IRF background cannot be used\n')
487 bkgfile = '' 566 bkgfile = ''
488 if len(bkg_mod_hierarchy) == 0: 567 if len(bkg_mod_hierarchy) == 0:
  568 +
  569 + # Skip observation if no background can be used
489 if self._logTerse(): 570 if self._logTerse():
490 self._log('Skipping observation '+str(obs_id)+ 571 self._log('Skipping observation '+str(obs_id)+
491 ': No background can be used\n') 572 ': No background can be used\n')
492 continue 573 continue
493 else: 574 else:
  575 + # Log if we fall back to next background approach
494 if self._logTerse(): 576 if self._logTerse():
495 self._log('Observation '+str(obs_id)+ 577 self._log('Observation '+str(obs_id)+
496 ': Falling back to background "'+ 578 ': Falling back to background "'+
@@ -499,15 +581,21 @@ class csiactobs(ctools.cscript): @@ -499,15 +581,21 @@ class csiactobs(ctools.cscript):
499 # Close hdu index file 581 # Close hdu index file
500 hduindx.close() 582 hduindx.close()
501 583
502 - # Handle background scale information if available 584 + # Initialise background scale
503 bkg_scale = 1.0 585 bkg_scale = 1.0
  586 +
  587 + # Check if background scale should be used
504 if self._use_bkg_scale: 588 if self._use_bkg_scale:
  589 +
  590 + # Read background scale from fits file
505 obsindx = gammalib.GFits(self._obs_index+'[OBS_INDEX]'+obs_selection) 591 obsindx = gammalib.GFits(self._obs_index+'[OBS_INDEX]'+obs_selection)
506 bkg_scale = obsindx['OBS_INDEX']['BKG_SCALE'][0] 592 bkg_scale = obsindx['OBS_INDEX']['BKG_SCALE'][0]
507 obsindx.close() 593 obsindx.close()
508 594
509 - # Open fits file to determine the observation name 595 + # Open event FITS file
510 fits = gammalib.GFits(eventfile) 596 fits = gammalib.GFits(eventfile)
  597 +
  598 + # Get object and telescope strings from event hdu
511 events = fits[eventhdu] 599 events = fits[eventhdu]
512 object_name = events.string('OBJECT') 600 object_name = events.string('OBJECT')
513 telescope = events.string('TELESCOP') 601 telescope = events.string('TELESCOP')
@@ -550,6 +638,7 @@ class csiactobs(ctools.cscript): @@ -550,6 +638,7 @@ class csiactobs(ctools.cscript):
550 self._log('Adding observation '+str(obs_id)+ 638 self._log('Adding observation '+str(obs_id)+
551 ' ("'+object_name+'")\n') 639 ' ("'+object_name+'")\n')
552 640
  641 + # log more details
553 if self._logExplicit(): 642 if self._logExplicit():
554 self._log(' Event file: '+eventfile+'\n') 643 self._log(' Event file: '+eventfile+'\n')
555 self._log(' Effective area: '+aefffile+'\n') 644 self._log(' Effective area: '+aefffile+'\n')
@@ -615,10 +704,13 @@ class csiactobs(ctools.cscript): @@ -615,10 +704,13 @@ class csiactobs(ctools.cscript):
615 self._log('\n') 704 self._log('\n')
616 705
617 else: 706 else:
  707 + # Print warning if no observation could be be used from runlist
618 self._log.header2('WARNING: No observation from given runlist available') 708 self._log.header2('WARNING: No observation from given runlist available')
619 709
620 # Append models provided by 'inmodels' if necessary 710 # Append models provided by 'inmodels' if necessary
621 - if not self._inmodels == None: 711 + if self._inmodels.size() > 0:
  712 +
  713 + # Logging
622 if self._logTerse(): 714 if self._logTerse():
623 self._log('\n') 715 self._log('\n')
624 self._log.header1('Appending models') 716 self._log.header1('Appending models')
@@ -650,17 +742,64 @@ class csiactobs(ctools.cscript): @@ -650,17 +742,64 @@ class csiactobs(ctools.cscript):
650 742
651 def save(self): 743 def save(self):
652 """ 744 """
653 - Save model definition XML file 745 + Save observation definition and model definition XML file
654 """ 746 """
655 - # Save observation XML file  
656 - self._xml.save(self._outobs) 747 + # Write header
  748 + if self._logTerse():
  749 + self._log('\n')
  750 + self._log.header1('Save XML files')
  751 +
  752 + # Get filenames
  753 + outobs = self['outobs'].filename()
  754 + outmodel = self['outmodel'].filename()
  755 +
  756 + # Log file name
  757 + if self._logTerse():
  758 + self._log(gammalib.parformat('Obs. definition XML file'))
  759 + self._log(outobs.url())
  760 + self._log('\n')
  761 +
  762 + # Save observation definition XML file
  763 + self._xml.save(outobs.url())
  764 +
  765 + # Log file name
  766 + if self._logTerse():
  767 + self._log(gammalib.parformat('Model definiton XML file'))
  768 + self._log(outmodel.url())
  769 + self._log('\n')
657 770
658 # Save model XML file 771 # Save model XML file
659 - self._models.save(self._outmodel) 772 + self._models.save(outmodel.url())
660 773
661 # Return 774 # Return
662 return 775 return
663 776
  777 + def runlist(self, runlist):
  778 + """
  779 + Set runlist
  780 +
  781 + Parameters
  782 + ----------
  783 + runlist : list
  784 + List of observation IDs
  785 +
  786 + Raises
  787 + ------
  788 + RuntimeError
  789 + Input runlist is not a Python list
  790 + """
  791 + # If the runlist is convertable to a Python list then store the
  792 + # runlist in the class
  793 + try:
  794 + self._runlist = list(runlist)
  795 +
  796 + # ... otherwise raise an exception
  797 + except:
  798 + raise RuntimeError('Argument is not a Python list')
  799 +
  800 + # Return
  801 + return
  802 +
664 def ebounds(self): 803 def ebounds(self):
665 """ 804 """
666 Return runlist energy boundaries 805 Return runlist energy boundaries
@@ -670,20 +809,20 @@ class csiactobs(ctools.cscript): @@ -670,20 +809,20 @@ class csiactobs(ctools.cscript):
670 809
671 def obs(self): 810 def obs(self):
672 """ 811 """
673 - Returns GObservations object 812 + Return observations container
674 """ 813 """
675 - # Initialise observations  
676 - obs = gammalib.GObservations() 814 + # Clear observations
  815 + self._obs.clear()
677 816
678 # Read observations if XML is filled 817 # Read observations if XML is filled
679 if self._xml.size(): 818 if self._xml.size():
680 - obs.read(self._xml) 819 + self._obs.read(self._xml)
681 820
682 # Assign models 821 # Assign models
683 - obs.models(self._models) 822 + self._obs.models(self._models)
684 823
685 # Return observations 824 # Return observations
686 - return obs 825 + return self._obs
687 826
688 827
689 # ======================== # 828 # ======================== #
pyext/ctool.i
@@ -198,7 +198,7 @@ cscript._init_cscript = _init_cscript @@ -198,7 +198,7 @@ cscript._init_cscript = _init_cscript
198 198
199 # Log the value of a parameter 199 # Log the value of a parameter
200 def _log_value(self, name, value): 200 def _log_value(self, name, value):
201 - self._log.parformat(name) 201 + self._log.parformat(str(name))
202 self._log(str(value)) 202 self._log(str(value))
203 self._log('\n') 203 self._log('\n')
204 cscript._log_value = _log_value 204 cscript._log_value = _log_value
test/data/iact_runlist.dat 0 → 100644
  1 +0
test/data/iactdata/master.json
@@ -3,7 +3,14 @@ @@ -3,7 +3,14 @@
3 { 3 {
4 "name": "unit-test", 4 "name": "unit-test",
5 "obsindx": "obs-index.fits.gz", 5 "obsindx": "obs-index.fits.gz",
6 - "hduindx": "hdu-index.fits.gz" 6 + "hduindx": "hdu-index.fits.gz",
  7 + "comment": "this is a comment"
  8 + },
  9 + {
  10 + "name": "unit-test-that-doesnt-exist",
  11 + "obsindx": "badfile.fits.gz",
  12 + "hduindx": "unavailable_file.fits.gz",
  13 + "comment": "this is a comment"
7 } 14 }
8 ] 15 ]
9 } 16 }
test/test_csiactdata.py
1 #! /usr/bin/env python 1 #! /usr/bin/env python
2 # ========================================================================== 2 # ==========================================================================
3 -# This scripts performs unit tests for the csiactdata script. 3 +# This scripts performs unit tests for the csiactdata script
4 # 4 #
5 # Copyright (C) 2016 Juergen Knoedlseder 5 # Copyright (C) 2016 Juergen Knoedlseder
6 # 6 #
@@ -108,6 +108,13 @@ class Test(test): @@ -108,6 +108,13 @@ class Test(test):
108 # Run csiactdata script and save run list 108 # Run csiactdata script and save run list
109 iactdata.logFileOpen() # Make sure we get a log file 109 iactdata.logFileOpen() # Make sure we get a log file
110 iactdata.run() 110 iactdata.run()
  111 +
  112 + # Get available configs
  113 + names = iactdata.names()
  114 +
  115 + # Check if there is at least one config available
  116 + self.test_assert(len(names) > 0,
  117 + 'Check successful execution from Python')
111 118
112 # Return 119 # Return
113 return 120 return
test/test_csiactobs.py
1 #! /usr/bin/env python 1 #! /usr/bin/env python
2 # ========================================================================== 2 # ==========================================================================
3 -# This scripts performs unit tests for the csiactobs script. 3 +# This scripts performs unit tests for the csiactobs script
4 # 4 #
5 # Copyright (C) 2016 Juergen Knoedlseder 5 # Copyright (C) 2016 Juergen Knoedlseder
6 # 6 #
@@ -44,6 +44,7 @@ class Test(test): @@ -44,6 +44,7 @@ class Test(test):
44 44
45 # Set data members 45 # Set data members
46 self._datapath = self._datadir + '/iactdata' 46 self._datapath = self._datadir + '/iactdata'
  47 + self._runlist = self._datadir + '/iact_runlist.dat'
47 48
48 # Return 49 # Return
49 return 50 return
@@ -74,10 +75,10 @@ class Test(test): @@ -74,10 +75,10 @@ class Test(test):
74 # Setup csiactobs command 75 # Setup csiactobs command
75 cmd = csiactobs+' datapath="'+self._datapath+'"'+ \ 76 cmd = csiactobs+' datapath="'+self._datapath+'"'+ \
76 ' prodname="unit-test"'+ \ 77 ' prodname="unit-test"'+ \
77 - ' infile="runlist_cmd1.dat"'+ \ 78 + ' infile="'+self._runlist+'"'+ \
78 ' bkgpars=1'+\ 79 ' bkgpars=1'+\
79 - ' outobs="obs_iactobs_cmd1.xml"'+ \  
80 - ' outmodel="bgd_iactobs_cmd1.xml"'+ \ 80 + ' outobs="csiactobs_obs_cmd1.xml"'+ \
  81 + ' outmodel="csiactobs_bgd_cmd1.xml"'+ \
81 ' logfile="csiactobs_cmd1.log" chatter=1' 82 ' logfile="csiactobs_cmd1.log" chatter=1'
82 83
83 # Check if execution of wrong command fails 84 # Check if execution of wrong command fails
@@ -89,23 +90,36 @@ class Test(test): @@ -89,23 +90,36 @@ class Test(test):
89 'Check successful execution from command line') 90 'Check successful execution from command line')
90 91
91 # Check observation definition XML file 92 # Check observation definition XML file
92 - self._check_obsdef('obs_iactobs_cmd1.xml') 93 + self._check_obsdef('csiactobs_obs_cmd1.xml')
93 94
94 # Check model definition XML file 95 # Check model definition XML file
95 - self._check_moddef('bgd_iactobs_cmd1.xml') 96 + self._check_moddef('csiactobs_bgd_cmd1.xml')
96 97
97 # Setup csiactobs command 98 # Setup csiactobs command
98 cmd = csiactobs+' datapath="data_path_that_does_not_exist"'+ \ 99 cmd = csiactobs+' datapath="data_path_that_does_not_exist"'+ \
99 ' prodname="unit-test"'+ \ 100 ' prodname="unit-test"'+ \
100 - ' infile="runlist_cmd1.dat"'+ \ 101 + ' infile="'+self._runlist+'"'+ \
101 ' bkgpars=1'+\ 102 ' bkgpars=1'+\
102 - ' outobs="obs_iactobs_cmd2.xml"'+ \  
103 - ' outmodel="bgd_iactobs_cmd2.xml"'+ \ 103 + ' outobs="csiactobs_obs_cmd2.xml"'+ \
  104 + ' outmodel="csiactobs_bgd_cmd2.xml"'+ \
104 ' logfile="csiactobs_cmd2.log" chatter=1' 105 ' logfile="csiactobs_cmd2.log" chatter=1'
105 106
106 # Check if execution failed 107 # Check if execution failed
107 self.test_assert(self._execute(cmd) != 0, 108 self.test_assert(self._execute(cmd) != 0,
108 - 'Check invalid input file when executed from command line') 109 + 'Check invalid input datapath when executed from command line')
  110 +
  111 + # Setup csiactobs command
  112 + cmd = csiactobs+' datapath="'+self._datapath+'"'+ \
  113 + ' prodname="unit-test-doesnt-exist"'+ \
  114 + ' infile="'+self._runlist+'"'+ \
  115 + ' bkgpars=1'+\
  116 + ' outobs="csiactobs_obs_cmd3.xml"'+ \
  117 + ' outmodel="csiactobs_bgd_cmd3.xml"'+ \
  118 + ' logfile="csiactobs_cmd3.log" chatter=1'
  119 +
  120 + # Check if execution failed
  121 + self.test_assert(self._execute(cmd) != 0,
  122 + 'Check invalid input prodname when executed from command line')
109 123
110 # Return 124 # Return
111 return 125 return
@@ -119,10 +133,10 @@ class Test(test): @@ -119,10 +133,10 @@ class Test(test):
119 iactobs = cscripts.csiactobs() 133 iactobs = cscripts.csiactobs()
120 iactobs['datapath'] = self._datapath 134 iactobs['datapath'] = self._datapath
121 iactobs['prodname'] = 'unit-test' 135 iactobs['prodname'] = 'unit-test'
122 - iactobs['infile'] = 'runlist_py1.dat' 136 + iactobs['infile'] = self._runlist
123 iactobs['bkgpars'] = 1 137 iactobs['bkgpars'] = 1
124 - iactobs['outobs'] = 'obs_iactobs_py1.xml'  
125 - iactobs['outmodel'] = 'bgd_iactobs_py1.xml' 138 + iactobs['outobs'] = 'csiactobs_obs_py1.xml'
  139 + iactobs['outmodel'] = 'csiactobs_bgd_py1.xml'
126 iactobs['logfile'] = 'csiactobs_py1.log' 140 iactobs['logfile'] = 'csiactobs_py1.log'
127 iactobs['chatter'] = 2 141 iactobs['chatter'] = 2
128 142
@@ -132,10 +146,88 @@ class Test(test): @@ -132,10 +146,88 @@ class Test(test):
132 iactobs.save() 146 iactobs.save()
133 147
134 # Check observation definition XML file 148 # Check observation definition XML file
135 - self._check_obsdef('obs_iactobs_py1.xml') 149 + self._check_obsdef('csiactobs_obs_py1.xml')
136 150
137 # Check model definition XML file 151 # Check model definition XML file
138 - self._check_moddef('bgd_iactobs_py1.xml') 152 + self._check_moddef('csiactobs_bgd_py1.xml')
  153 +
  154 + # Create test runlist
  155 + runlist = ['0']
  156 +
  157 + # Set-up csiactobs using a runlist with 2 background parameters
  158 + iactobs = cscripts.csiactobs()
  159 + iactobs['datapath'] = self._datapath
  160 + iactobs['prodname'] = 'unit-test'
  161 + iactobs['bkgpars'] = 2
  162 + iactobs['outobs'] = 'csiactobs_obs_py2.xml'
  163 + iactobs['outmodel'] = 'csiactobs_bgd_py2.xml'
  164 + iactobs['logfile'] = 'csiactobs_py2.log'
  165 + iactobs['chatter'] = 3
  166 + iactobs.runlist(runlist)
  167 +
  168 + # Run csiactobs script and save run list
  169 + iactobs.logFileOpen() # Make sure we get a log file
  170 + iactobs.run()
  171 + iactobs.save()
  172 +
  173 + # Test return functions
  174 + self.test_value(iactobs.obs().size(), 1,
  175 + 'Check number of observations in container')
  176 + self.test_value(iactobs.ebounds().size(), 0,
  177 + 'Check number of energy boundaries')
  178 +
  179 + # Check observation definition XML file
  180 + self._check_obsdef('csiactobs_obs_py2.xml')
  181 +
  182 + # Check model definition XML file
  183 + self._check_moddef('csiactobs_bgd_py2.xml')
  184 +
  185 + # Set-up csiactobs with a large number of free parameters and "aeff"
  186 + # background
  187 + iactobs = cscripts.csiactobs()
  188 + iactobs['datapath'] = self._datapath
  189 + iactobs['prodname'] = 'unit-test'
  190 + iactobs['infile'] = self._runlist
  191 + iactobs['bkgpars'] = 8
  192 + iactobs['bkg_mod_hiera'] = 'aeff'
  193 + iactobs['outobs'] = 'csiactobs_obs_py3.xml'
  194 + iactobs['outmodel'] = 'csiactobs_bgd_py3.xml'
  195 + iactobs['logfile'] = 'csiactobs_py3.log'
  196 + iactobs['chatter'] = 4
  197 +
  198 + # Execute csiactobs script
  199 + iactobs.execute()
  200 +
  201 + # Check observation definition XML file
  202 + self._check_obsdef('csiactobs_obs_py3.xml')
  203 +
  204 + # Check model definition XML file
  205 + self._check_moddef('csiactobs_bgd_py3.xml')
  206 +
  207 + # Set-up csiactobs with a "gauss" background and "inmodel" parameter
  208 + iactobs = cscripts.csiactobs()
  209 + iactobs['datapath'] = self._datapath
  210 + iactobs['inmodel'] = self._model
  211 + iactobs['prodname'] = 'unit-test'
  212 + iactobs['infile'] = self._runlist
  213 + iactobs['bkgpars'] = 1
  214 + iactobs['bkg_mod_hiera'] = 'gauss'
  215 + iactobs['outobs'] = 'NONE'
  216 + iactobs['outmodel'] = 'NONE'
  217 + iactobs['logfile'] = 'csiactobs_py4.log'
  218 + iactobs['chatter'] = 4
  219 +
  220 + # Run csiactobs script
  221 + iactobs.logFileOpen() # Make sure we get a log file
  222 + iactobs.run()
  223 +
  224 + # Check number of observations
  225 + self.test_value(iactobs.obs().size(), 1,
  226 + 'Check number of observations in container')
  227 +
  228 + # Check number of models
  229 + self.test_value(iactobs.obs().models().size(), 3,
  230 + 'Check number of models in container')
139 231
140 # Return 232 # Return
141 return 233 return
@@ -154,34 +246,26 @@ class Test(test): @@ -154,34 +246,26 @@ class Test(test):
154 # Check number of observations 246 # Check number of observations
155 self.test_value(obs.size(), 1, 247 self.test_value(obs.size(), 1,
156 'Check for single observation in XML file') 248 'Check for single observation in XML file')
157 - self.test_assert(obs[0].eventfile().file() == 'events.fits.gz',  
158 - 'Check event file name')  
159 - self.test_assert(obs[0].eventfile().extname() == 'EVENTS',  
160 - 'Check event extension name')  
161 - self.test_assert(rsp.aeff().filename().file() ==  
162 - 'irf_file.fits.gz',  
163 - 'Check effective area name')  
164 - self.test_assert(rsp.aeff().filename().extname() ==  
165 - 'EFFECTIVE AREA',  
166 - 'Check effective area extension name')  
167 - self.test_assert(rsp.psf().filename().file() ==  
168 - 'irf_file.fits.gz',  
169 - 'Check point spread function name')  
170 - self.test_assert(rsp.psf().filename().extname() ==  
171 - 'POINT SPREAD FUNCTION',  
172 - 'Check point spread function extension name')  
173 - self.test_assert(rsp.edisp().filename().file() ==  
174 - 'irf_file.fits.gz',  
175 - 'Check energy dispersion name')  
176 - self.test_assert(rsp.edisp().filename().extname() ==  
177 - 'ENERGY DISPERSION',  
178 - 'Check energy dispersion extension name')  
179 - self.test_assert(rsp.background().filename().file() ==  
180 - 'irf_file.fits.gz',  
181 - 'Check background name')  
182 - self.test_assert(rsp.background().filename().extname() ==  
183 - 'BACKGROUND',  
184 - 'Check background extension name') 249 + self.test_value(obs[0].eventfile().file(), 'events.fits.gz',
  250 + 'Check event file name')
  251 + self.test_value(obs[0].eventfile().extname(), 'EVENTS',
  252 + 'Check event extension name')
  253 + self.test_value(rsp.aeff().filename().file(), 'irf_file.fits.gz',
  254 + 'Check effective area file name')
  255 + self.test_value(rsp.aeff().filename().extname(), 'EFFECTIVE AREA',
  256 + 'Check effective area extension name')
  257 + self.test_value(rsp.psf().filename().file(), 'irf_file.fits.gz',
  258 + 'Check point spread function file name')
  259 + self.test_value(rsp.psf().filename().extname(), 'POINT SPREAD FUNCTION',
  260 + 'Check point spread function extension name')
  261 + self.test_value(rsp.edisp().filename().file(), 'irf_file.fits.gz',
  262 + 'Check energy dispersion file name')
  263 + self.test_value(rsp.edisp().filename().extname(), 'ENERGY DISPERSION',
  264 + 'Check energy dispersion extension name')
  265 + self.test_value(rsp.background().filename().file(), 'irf_file.fits.gz',
  266 + 'Check background file name')
  267 + self.test_value(rsp.background().filename().extname(), 'BACKGROUND',
  268 + 'Check background extension name')
185 269
186 # Return 270 # Return
187 return 271 return