Commit a446d51c322c4d28f11244e435f3655a81bb3d26

Authored by Jürgen Knödlseder
1 parent a266b565

Improve commenting of cscripts (#1828)

cscripts/csfindobs.py
... ... @@ -225,15 +225,12 @@ class csfindobs(ctools.cscript):
225 225  
226 226 # Write the number of observations into the logger
227 227 if self._logTerse():
228   - self._log(gammalib.parformat('Observations'))
229   - self._log(len(self._runs))
230   - self._log('\n')
  228 + self._log_value('Observations', len(self._runs))
231 229  
232 230 # Write the observation identifiers into the logger
233 231 if self._logNormal() and len(self._runs) > 0:
234 232 for i, run in enumerate(self._runs):
235   - self._log(gammalib.parformat('Observation %d' % (i+1)))
236   - self._log(str(run)+'\n')
  233 + self._log_value('Observation %d' % (i+1), run)
237 234  
238 235 # Close FITS file
239 236 fits.close()
... ...
cscripts/csiactcopy.py
... ... @@ -101,20 +101,12 @@ class csiactcopy(ctools.cscript):
101 101  
102 102 # Logging
103 103 if self._logVerbose():
104   - self._log('\n')
105   - self._log.header3('Copy file')
106   - self._log.parformat('Source')
107   - self._log(str(source))
108   - self._log('\n')
109   - self._log.parformat('Destination')
110   - self._log(str(destination))
111   - self._log('\n')
112   - self._log.parformat('Already exists')
113   - self._log(str(os.path.isfile(destination)))
114   - self._log('\n')
115   - self._log.parformat('Overwrite')
116   - self._log(str(clobber))
117 104 self._log('\n')
  105 + self._log.header3('Copy file')
  106 + self._log_value('Source', source)
  107 + self._log_value('Destination', destination)
  108 + self._log_value('Already exists', str(os.path.isfile(destination)))
  109 + self._log_value('Overwrite', clobber)
118 110 self._log.parformat('Copying')
119 111  
120 112 # Flag if file destination is already available
... ... @@ -158,24 +150,17 @@ class csiactcopy(ctools.cscript):
158 150  
159 151 If the local fits file is not present, a new one is created.
160 152 """
161   -
  153 + # ...
162 154 if self._logTerse():
163   - self._log.parformat('Local file')
164   - self._log(str(localfits))
165   - self._log('\n')
166   - self._log.parformat('Remote file')
167   - self._log(str(remotefits))
168   - self._log('\n')
169   - self._log.parformat('HDU name')
170   - self._log(str(hduname))
171   - self._log('\n')
172   - self._log.parformat('Conflict preference')
  155 + self._log_value('Local file', localfits)
  156 + self._log_value('Remote file', remotefits)
  157 + self._log_value('HDU name', hduname)
173 158 if clobber:
174   - self._log('Remote')
  159 + preference = 'Remote'
175 160 else:
176   - self._log('Local')
177   - self._log('\n')
178   -
  161 + preference = 'Local'
  162 + self._log_value('Conflict preference', preference)
  163 +
179 164 # Check if local fits file is available
180 165 if os.path.isfile(localfits):
181 166 local = gammalib.GFits(str(localfits))
... ... @@ -244,15 +229,12 @@ class csiactcopy(ctools.cscript):
244 229 robs_col = remote_hdu['OBS_ID']
245 230 for obs_id in robs_col:
246 231 remote_obs.append(obs_id)
247   -
  232 +
  233 + # Dump the number of remote and local entries
248 234 if self._logTerse():
249   - self._log.parformat('Remote entries')
250   - self._log(str(len(remote_obs)))
251   - self._log('\n')
252   - self._log.parformat('Local entries')
253   - self._log(str(len(local_obs)))
254   - self._log('\n')
255   -
  235 + self._log_value('Remote entries', len(remote_obs))
  236 + self._log_value('Local entries', len(local_obs))
  237 +
256 238 # initialise counter for logging
257 239 removed_rows = 0
258 240  
... ... @@ -306,16 +288,16 @@ class csiactcopy(ctools.cscript):
306 288 # Store number of local rows
307 289 old_local_rows = local_hdu.nrows()
308 290  
309   - # Add rmeote HDUs
  291 + # Add remote HDUs
310 292 local_hdu.insert_rows(old_local_rows, remote_hdu.nrows())
311   -
  293 +
  294 + # Dump ...
312 295 if self._logTerse():
313 296 if clobber:
314   - self._log.parformat('Removed local rows')
  297 + what = 'Removed local rows'
315 298 else:
316   - self._log.parformat('Skipped remote rows')
317   - self._log(str(removed_rows))
318   - self._log('\n')
  299 + what = 'Skipped remote rows'
  300 + self._log_value(what, removed_rows)
319 301  
320 302 # Loop over columns
321 303 for i in range(local_hdu.ncols()):
... ... @@ -338,7 +320,7 @@ class csiactcopy(ctools.cscript):
338 320 # Public methods
339 321 def run(self):
340 322 """
341   - Run the script.
  323 + Run the script
342 324 """
343 325 # Switch screen logging on in debug mode
344 326 if self._logDebug():
... ... @@ -373,9 +355,7 @@ class csiactcopy(ctools.cscript):
373 355  
374 356 # Logging
375 357 if self._logTerse():
376   - self._log.parformat('Number of observations')
377   - self._log(str(len(self._runs)))
378   - self._log('\n')
  358 + self._log_value('Number of observations', len(self._runs))
379 359  
380 360 # Copy all data if runlist file is 'NONE'
381 361 elif self._runlist == 'NONE':
... ... @@ -438,13 +418,9 @@ class csiactcopy(ctools.cscript):
438 418 # Log information
439 419 if self._logTerse():
440 420 self._log.header3('Remote config "'+self._prodname+'"')
441   - self._log.parformat('HDU index')
442   - self._log(str(remote_hdu))
443   - self._log('\n')
444   - self._log.parformat('Observation index')
445   - self._log(str(remote_obs))
446   - self._log('\n')
447   -
  421 + self._log_value('HDU index', remote_hdu)
  422 + self._log_value('Observation index', remote_obs)
  423 +
448 424 # Open remote HDU index file
449 425 fits = gammalib.GFits(str(remote_hdu))
450 426 table = fits['HDU_INDEX']
... ... @@ -519,19 +495,16 @@ class csiactcopy(ctools.cscript):
519 495 if self._logTerse():
520 496 self._log('\n')
521 497 self._log.header2('File information')
522   - self._log.parformat('Number of files')
523   - self._log(str(len(files)))
524   - self._log('\n')
  498 + self._log_value('Number of files', len(files))
525 499 if has_size:
526   - self._log.parformat('Size')
527   - self._log('%.2f'%(float(cp_size)*1e-6)+' MB')
528   - self._log('\n')
  500 + size = float(cp_size) * 1.0e-6
  501 + self._log_value('Size', '%.2f MB' % size)
529 502 if self._logVerbose():
530 503 self._log('\n')
531 504 self._log.header3('File names')
532 505 for filename in files:
533 506 self._log(str(filename)+'\n')
534   -
  507 +
535 508 # Close HDU index file
536 509 fits.close()
537 510  
... ... @@ -569,7 +542,7 @@ class csiactcopy(ctools.cscript):
569 542 if self._logExplicit():
570 543 fraction_increment = 2.0
571 544  
572   - # initialise logging properties
  545 + # Initialise logging properties
573 546 n_copied = 0
574 547 total_size = 0.0
575 548  
... ... @@ -580,14 +553,14 @@ class csiactcopy(ctools.cscript):
580 553 fraction = float(k) / float(len(files)) * 100.0
581 554 while fraction > last_fraction:
582 555 if self._logNormal() and not self._logVerbose():
583   - self._log.parformat('Status')
584   - self._log(str(int(last_fraction))+'%')
585   - self._log('\n')
  556 + self._log_value('Status', '%d %%' % int(last_fraction))
586 557 last_fraction += fraction_increment
587 558  
588 559 # Copy file
589 560 filesize = self._copy(filename, self._clobber())
590   -
  561 +
  562 + # If the filesize is positive then increment the number of copied
  563 + # files and add the size to the total copied filesize
591 564 if filesize > 0.0:
592 565 total_size += filesize
593 566 n_copied += 1
... ... @@ -708,31 +681,23 @@ class csiactcopy(ctools.cscript):
708 681 if self._logNormal():
709 682 self._log('\n')
710 683 self._log.header1('Summary')
711   - self._log.parformat('Data files found')
712   - self._log(str(len(files)))
713   - self._log('\n')
714   - self._log.parformat('Data files copied')
715   - self._log(str(n_copied))
716   - self._log('\n')
717   - self._log.parformat('Size')
718   - self._log('%.2f'%(float(total_size)*1e-6)+' MB')
719   - self._log('\n')
720   - self._log.parformat('Local configs')
721   - self._log(str(len(newconfigs)))
722   - self._log('\n')
  684 + self._log_value('Data files found', len(files))
  685 + self._log_value('Data files copied', n_copied)
  686 + self._log_value('Size', '%.2f MB' % (float(total_size)*1.0e-6))
  687 + self._log_value('Local configs', len(newconfigs))
723 688 if self._logTerse():
724 689 self._log('\n')
725 690 self._log.header3('Content of master index')
726 691 for config in newconfigs:
727 692 self._log(str(config['name']))
728 693 self._log('\n')
729   -
  694 +
730 695 # Return
731 696 return
732 697  
733 698 def execute(self):
734 699 """
735   - Execute the script.
  700 + Execute the script
736 701 """
737 702 # Open logfile
738 703 self.logFileOpen()
... ...
cscripts/csiactdata.py
... ... @@ -96,26 +96,20 @@ class csiactdata(ctools.cscript):
96 96 """
97 97 Log configuration
98 98 """
99   - # Log information
  99 + # Log only if the level is at least "Terse"
100 100 if self._logTerse():
  101 +
  102 + # Log configuration information
101 103 self._log.header3(str(config['name']))
102   - self._log.parformat('Name')
103   - self._log(str(config['name']))
104   - self._log('\n')
105   - self._log.parformat('Observation index')
106   - self._log(str(config['obsindx']))
107   - self._log('\n')
108   - self._log.parformat('HDU index')
109   - self._log(str(config['hduindx']))
110   - self._log('\n')
111   -
  104 + self._log_value('Name', config['name'])
  105 + self._log_value('Observation index', config['obsindx'])
  106 + self._log_value('HDU index', config['hduindx'])
  107 +
112 108 # Print additional information
113 109 for key in config:
114 110 if key in ['name','hduindx','obsindx']:
115 111 continue
116   - self._log.parformat(str(key))
117   - self._log(str(config[key]))
118   - self._log('\n')
  112 + self._log_value(key, config[key])
119 113  
120 114 # Return
121 115 return
... ...
cscripts/csinfo.py
... ... @@ -21,8 +21,9 @@
21 21 import sys
22 22 import os
23 23  
24   -# Copied and edited a bit from the `doc/source/users/reference_manual/index.rst`
25   -# file. The list there and here needs to be manually updated and kept in sync.
  24 +# List of available ctools. The list was copied from
  25 +# `doc/source/users/reference_manual/index.rst`
  26 +# and needs to be manually updated and kept in sync
26 27 CTOOL_LIST = """
27 28 ctbin Generates counts cube
28 29 ctbkgcube Generates background cube
... ... @@ -41,6 +42,10 @@ CTOOL_LIST = """
41 42 cttsmap Generates Test Statistics map
42 43 ctulimit Calculates upper limit
43 44 """
  45 +
  46 +# List of available cscripts. The list was copied from
  47 +# `doc/source/users/reference_manual/index.rst`
  48 +# and needs to be manually updated and kept in sync
44 49 CSCRIPT_LIST = """
45 50 cscaldb Lists available instrument response functions
46 51 cslightcrv Computes lightcurve
... ... @@ -57,6 +62,7 @@ CSCRIPT_LIST = """
57 62 cstsmapsplit Creates commands to split the Test Statistic map computations
58 63 cstsmapmerge Merges slices from Test Statistic map computations\n
59 64 csobs2caldb Creates a caldb entry from an input observation
  65 + csroot2caldb Creates a caldb entry from a ROOT performance file
60 66 csiactdata Shows information about IACT data available on the user machine
61 67 csiactobs Generates observation definition file for IACT data from observation IDs
62 68 csfindobs Generates a list of IACT observation IDs
... ... @@ -92,23 +98,6 @@ def get_command_output(cmd):
92 98 return getoutput(cmd)
93 99  
94 100  
95   -# ===================================== #
96   -# Workaround for print without linefeed #
97   -# ===================================== #
98   -def log(text, end='\n'):
99   - """
100   - Print text to console
101   -
102   - Workaround to have an `end=''` option on old Pythons:
103   - http://stackoverflow.com/a/493399/498873
104   - """
105   - # Print without linefeed
106   - sys.stdout.write(text + end)
107   -
108   - # Return
109   - return
110   -
111   -
112 101 # ====================== #
113 102 # Print list information #
114 103 # ====================== #
... ... @@ -135,66 +124,61 @@ def csinfo_setup_check():
135 124 """
136 125 Print check information
137 126 """
138   - # Initialise success flags
139   - all_ok = True
140   - gammalib_environ = False
141   - ctools_environ = False
142   - gammalib_python = False
143   - ctools_python = False
144   - cscripts_python = False
145   -
146 127 # Print header
147 128 print('\nGammalib / ctools setup check:\n')
148 129  
149   - # Check if GAMMALIB is set
150   - log(' GAMMALIB environment variable ... ', end='')
151   - try:
152   - gammalib_env = os.environ['GAMMALIB']
  130 + # Check if the "GAMMALIB" environment variable is set
  131 + sys.stdout.write(' GAMMALIB environment variable ... ')
  132 + if 'GAMMALIB' in os.environ:
153 133 print('ok')
154   - except KeyError:
155   - print('NOT OK')
156   - all_ok = False
157 134 gammalib_environ = True
  135 + else:
  136 + print('NOT OK')
  137 + gammalib_environ = False
158 138  
159   - # Check if CTOOLS is set
160   - log(' CTOOLS environment variable ... ', end='')
161   - try:
162   - ctools_env = os.environ['CTOOLS']
  139 + # Check if the "CTOOLS" environment variable is set
  140 + sys.stdout.write(' CTOOLS environment variable ... ')
  141 + if 'CTOOLS' in os.environ:
163 142 print('ok')
164   - except KeyError:
165   - print('NOT_OK')
166   - all_ok = False
167 143 ctools_environ = True
  144 + else:
  145 + print('NOT OK')
  146 + ctools_environ = False
  147 +
168 148  
169 149 # Check if gammalib Python module import works
170   - log(' gammalib Python import .......... ', end='')
  150 + sys.stdout.write(' gammalib Python import .......... ')
171 151 try:
172 152 import gammalib
173 153 print('ok')
  154 + gammalib_python = True
174 155 except:
175 156 print('NOT OK')
176   - all_ok = False
177   - gammalib_python = True
  157 + gammalib_python = False
178 158  
179 159 # Check if ctools Python module import works
180   - log(' ctools Python import .......... ', end='')
  160 + sys.stdout.write(' ctools Python import .......... ')
181 161 try:
182 162 import ctools
183 163 print('ok')
  164 + ctools_python = True
184 165 except:
185 166 print('NOT OK')
186   - all_ok = False
187   - ctools_python = True
  167 + ctools_python = False
188 168  
189 169 # Check if cscripts Python module import works
190   - log(' cscripts Python import .......... ', end='')
  170 + sys.stdout.write(' cscripts Python import .......... ')
191 171 try:
192 172 import cscripts
193 173 print('ok')
  174 + cscripts_python = True
194 175 except:
195 176 print('NOT OK')
196   - all_ok = False
197   - cscripts_python = True
  177 + cscripts_python = False
  178 +
  179 + # Set flag that everything is okay
  180 + all_ok = gammalib_environ and ctools_environ and gammalib_python and \
  181 + ctools_python and cscripts_python
198 182  
199 183 # Signal if everything is okay, or notify about the problems that have
200 184 # been encountered
... ... @@ -202,11 +186,11 @@ def csinfo_setup_check():
202 186 print('\n ===> Your Gammalib / ctools setup is OK.')
203 187 else:
204 188 print('\n ===> WARNING: Your Gammalib / ctools setup is NOT OK!\n')
205   - if gammalib_environ:
  189 + if not gammalib_environ:
206 190 print(' - Have you set the GAMMALIB environment variable?')
207   - if ctools_environ:
  191 + if not ctools_environ:
208 192 print(' - Have you set the CTOOLS environment variable?')
209   - if gammalib_python or ctools_python or cscripts_python:
  193 + if not gammalib_python or not ctools_python or not cscripts_python:
210 194 print(' - Did you source gammalib-init.sh?')
211 195 print(' - Did you source ctools-init.sh ?')
212 196 print(' - Are you using the correct Python ?')
... ... @@ -257,10 +241,8 @@ def csinfo_setup_info():
257 241 gammalib_env = os.environ.get('GAMMALIB', 'Not found')
258 242 ctools_env = os.environ.get('CTOOLS', 'Not found')
259 243  
260   - # Print header
  244 + # Print setup information
261 245 print('\nGammalib / ctools setup info:\n')
262   -
263   - # Print package versions
264 246 print(' Gammalib version ................ %s' % gammalib_version)
265 247 print(' ctools version ................ %s' % ctools_version)
266 248 print(' cscripts version ................ %s' % cscripts_version)
... ... @@ -306,7 +288,7 @@ def get_pkg_config_info(info, library):
306 288 out = get_command_output(cmd)
307 289  
308 290 # If the command returns 'was not found' then pkg-config is not
309   - # avaailable
  291 + # available
310 292 if 'not found' in out:
311 293 out = 'Not available'
312 294  
... ... @@ -340,8 +322,8 @@ def csinfo(argv):
340 322 """
341 323 Print information about Gammalib and ctools to the console
342 324 """
343   - # If there are no command line arguments then print help and exit
344   - # with success
  325 + # If there are no command line arguments then print help and exit with
  326 + # success
345 327 if len(argv) <= 1:
346 328 csinfo_print_help()
347 329 sys.exit(0)
... ...
cscripts/cslightcrv.py
... ... @@ -21,6 +21,7 @@
21 21 import sys
22 22 import gammalib
23 23 import ctools
  24 +from cscripts import obsutils
24 25  
25 26  
26 27 # ================ #
... ... @@ -82,10 +83,6 @@ class cslightcrv(ctools.cscript):
82 83 # Initialise script by calling the appropriate class constructor.
83 84 self._init_cscript(argv)
84 85  
85   - # Set logger properties
86   - self._log_header()
87   - self._log.date(True)
88   -
89 86 # Return
90 87 return
91 88  
... ... @@ -162,20 +159,26 @@ class cslightcrv(ctools.cscript):
162 159 # Initialise Good Time Intervals
163 160 gti = gammalib.GGti()
164 161  
165   - # Get algorithm to use for defining the time intervals
  162 + # Get algorithm to use for defining the time intervals. Possible
  163 + # values are "FILE", "LIN" and "GTI". This is enforced at
  164 + # parameter file level, hence no checking is needed.
166 165 algorithm = self['tbinalg'].string()
167 166  
168   - # Handle a FITS or a ASCII file for time bin definition
  167 + # If the algorithm is "FILE" then handle a FITS or an ASCII file for
  168 + # the time bin definition
169 169 if algorithm == 'FILE':
170 170  
171 171 # Get the filename
172 172 filename = self['tbinfile'].filename()
173 173  
174   - # If the file a FITS file then load GTIs
  174 + # If the file a FITS file then load GTIs directly
175 175 if filename.is_fits():
176 176 gti.load(filename)
177 177  
178   - # ... otherwise load file as CSV ASCII file
  178 + # ... otherwise load file the ASCII file as CSV file and construct
  179 + # the GTIs from the rows of the CSV file. It is expected that the
  180 + # CSV file has two columns containing the "START" and "STOP"
  181 + # values of the time bins. No header row is expected.
179 182 csv = gammalib.GCsv(filename)
180 183 for i in range(csv.nrows()):
181 184 tmin = gammalib.GTime()
... ... @@ -184,7 +187,8 @@ class cslightcrv(ctools.cscript):
184 187 tmax.mjd(csv.real(i,1))
185 188 gti.append(tmin,tmax)
186 189  
187   - # Handle linear time binning
  190 + # If the algorithm is "LIN" then use a linear time binning, defined by
  191 + # the "tmin", "tmax" and "tbins" user parameters
188 192 elif algorithm == 'LIN':
189 193  
190 194 # Get start and stop time and number of time bins
... ... @@ -192,7 +196,7 @@ class cslightcrv(ctools.cscript):
192 196 time_max = self['tmax'].real()
193 197 nbins = self['tbins'].integer()
194 198  
195   - # Compute time step and setup time intervals
  199 + # Compute time step and setup the GTIs
196 200 time_step = (time_max - time_min) / float(nbins)
197 201 for i in range(nbins):
198 202 tmin = gammalib.GTime()
... ... @@ -201,7 +205,8 @@ class cslightcrv(ctools.cscript):
201 205 tmax.mjd(time_min + (i+1)*time_step)
202 206 gti.append(tmin,tmax)
203 207  
204   - # Handle usage of observation GTIs
  208 + # If the algorithm is "GTI" then extract the GTIs from the observations
  209 + # in the container and use them for the light curve time binning
205 210 elif algorithm == 'GTI':
206 211  
207 212 # Append the GTIs of all observations
... ... @@ -210,11 +215,6 @@ class cslightcrv(ctools.cscript):
210 215 gti.append(obs.events().gti().tstart(i),
211 216 obs.events().gti().tstop(i))
212 217  
213   - # ... otherwise raise an exception (this should never occur)
214   - else:
215   - raise AttributeError('Paramter tbinalg="'+algorithm+'" unknown. '
216   - 'Must be one of "FILE", "LIN" or "GTI".')
217   -
218 218 # Return Good Time Intervals
219 219 return gti
220 220  
... ... @@ -227,7 +227,7 @@ class cslightcrv(ctools.cscript):
227 227 names : list of str
228 228 List of free parameter names.
229 229 """
230   - # Initialise list of free parameter names
  230 + # Initialise empty list of free parameter names
231 231 names = []
232 232  
233 233 # Collect list of free parameter names
... ... @@ -304,7 +304,7 @@ class cslightcrv(ctools.cscript):
304 304 table = gammalib.GFitsBinTable(nrows)
305 305 table.extname('LIGHTCURVE')
306 306  
307   - # Append time columns
  307 + # Append time columns "MJD" and "e_MJD"
308 308 mjd = gammalib.GFitsTableDoubleCol('MJD', nrows)
309 309 e_mjd = gammalib.GFitsTableDoubleCol('e_MJD', nrows)
310 310 mjd.unit('days')
... ... @@ -330,13 +330,13 @@ class cslightcrv(ctools.cscript):
330 330 table.append(col)
331 331 table.append(e_col)
332 332  
333   - # Append Test Statistic column
  333 + # Append Test Statistic column "TS"
334 334 ts = gammalib.GFitsTableDoubleCol('TS', nrows)
335 335 for i, result in enumerate(results):
336 336 ts[i] = result['ts']
337 337 table.append(ts)
338 338  
339   - # Append upper limit column
  339 + # Append upper limit column "UpperLimit"
340 340 ulimit = gammalib.GFitsTableDoubleCol('UpperLimit', nrows)
341 341 ulimit.unit('ph/cm2/s')
342 342 for i, result in enumerate(results):
... ... @@ -375,7 +375,7 @@ class cslightcrv(ctools.cscript):
375 375 ulimit['srcname'] = self._srcname
376 376 ulimit['eref'] = 1.0
377 377  
378   - # Try to run upper limit and catch exceptions
  378 + # Try to run upper limit and catch any exceptions
379 379 try:
380 380 ulimit.run()
381 381 ulimit_value = ulimit.flux_ulimit()
... ... @@ -423,111 +423,36 @@ class cslightcrv(ctools.cscript):
423 423  
424 424 # Header
425 425 if self._logExplicit():
426   - self._log.header3('Creating exposure cube')
427   -
428   - # Create exposure cube
429   - expcube = ctools.ctexpcube(obs)
430   - expcube['incube'] = 'NONE'
431   - expcube['usepnt'] = False
432   - expcube['ebinalg'] = 'LOG'
433   - expcube['xref'] = self['xref'].real()
434   - expcube['yref'] = self['yref'].real()
435   - expcube['binsz'] = self['binsz'].real()
436   - expcube['nxpix'] = self['nxpix'].integer()
437   - expcube['nypix'] = self['nypix'].integer()
438   - expcube['enumbins'] = self['enumbins'].integer()
439   - expcube['emin'] = self['emin'].real()
440   - expcube['emax'] = self['emax'].real()
441   - expcube['coordsys'] = self['coordsys'].string()
442   - expcube['proj'] = self['proj'].string()
443   - expcube.run()
444   -
445   - # Header
446   - if self._logExplicit():
447   - self._log.header3('Creating point spread function cube')
448   -
449   - # Compute spatial binning for point spread function and
450   - # energy dispersion cubes
451   - binsz = 10.0 * self['binsz'].real()
452   - nxpix = min(self['nxpix'].integer() // 10, 2) # Make sure result is int
453   - nypix = min(self['nypix'].integer() // 10, 2) # Make sure result is int
454   -
455   - # Create point spread function cube
456   - psfcube = ctools.ctpsfcube(obs)
457   - psfcube['incube'] = 'NONE'
458   - psfcube['usepnt'] = False
459   - psfcube['ebinalg'] = 'LOG'
460   - psfcube['xref'] = self['xref'].real()
461   - psfcube['yref'] = self['yref'].real()
462   - psfcube['binsz'] = binsz
463   - psfcube['nxpix'] = nxpix
464   - psfcube['nypix'] = nypix
465   - psfcube['enumbins'] = self['enumbins'].integer()
466   - psfcube['emin'] = self['emin'].real()
467   - psfcube['emax'] = self['emax'].real()
468   - psfcube['coordsys'] = self['coordsys'].string()
469   - psfcube['proj'] = self['proj'].string()
470   - psfcube.run()
471   -
472   - # Check if we need to include energy dispersion
473   - if self['edisp'].boolean():
474   -
475   - # Header
476   - if self._logExplicit():
477   - self._log.header3('Creating energy dispersion cube')
478   -
479   - # Create energy dispersion cube
480   - edispcube = ctools.ctedispcube(obs)
481   - edispcube['incube'] = 'NONE'
482   - edispcube['usepnt'] = False
483   - edispcube['ebinalg'] = 'LOG'
484   - edispcube['xref'] = self['xref'].real()
485   - edispcube['yref'] = self['yref'].real()
486   - edispcube['binsz'] = binsz
487   - edispcube['nxpix'] = nxpix
488   - edispcube['nypix'] = nypix
489   - edispcube['enumbins'] = self['enumbins'].integer()
490   - edispcube['emin'] = self['emin'].real()
491   - edispcube['emax'] = self['emax'].real()
492   - edispcube['coordsys'] = self['coordsys'].string()
493   - edispcube['proj'] = self['proj'].string()
494   - edispcube.run()
495   -
496   - # Header
497   - if self._logExplicit():
498   - self._log.header3('Creating background cube')
499   -
500   - # Create background cube
501   - bkgcube = ctools.ctbkgcube(obs)
502   - bkgcube['incube'] = 'NONE'
503   - bkgcube['usepnt'] = False
504   - bkgcube['ebinalg'] = 'LOG'
505   - bkgcube['xref'] = self['xref'].real()
506   - bkgcube['yref'] = self['yref'].real()
507   - bkgcube['binsz'] = self['binsz'].real()
508   - bkgcube['nxpix'] = self['nxpix'].integer()
509   - bkgcube['nypix'] = self['nypix'].integer()
510   - bkgcube['enumbins'] = self['enumbins'].integer()
511   - bkgcube['emin'] = self['emin'].real()
512   - bkgcube['emax'] = self['emax'].real()
513   - bkgcube['coordsys'] = self['coordsys'].string()
514   - bkgcube['proj'] = self['proj'].string()
515   - bkgcube.run()
  426 + self._log.header3('Creating stacked response')
  427 +
  428 + # Get stacked response
  429 + response = obsutils.get_stacked_response(obs,
  430 + self['xref'].real(),
  431 + self['yref'].real(),
  432 + binsz=self['binsz'].real(),
  433 + nxpix=self['nxpix'].integer(),
  434 + nypix=self['nypix'].integer(),
  435 + emin=self['emin'].real(),
  436 + emax=self['emax'].real(),
  437 + enumbins=self['enumbins'].integer(),
  438 + edisp=self['edisp'].boolean(),
  439 + coordsys=self['coordsys'].string(),
  440 + proj=self['proj'].string())
516 441  
517 442 # Retrieve a new oberservation container
518 443 new_obs = cntcube.obs().copy()
519 444  
520   - # Get new models
521   - models = bkgcube.models()
522   -
523 445 # Set stacked response
524 446 if self['edisp'].boolean():
525   - new_obs[0].response(expcube.expcube(), psfcube.psfcube(),
526   - edispcube.edispcube(), bkgcube.bkgcube())
  447 + new_obs[0].response(response['expcube'], response['psfcube'],
  448 + response['edispcube'], response['bkgcube'])
527 449 else:
528   - new_obs[0].response(expcube.expcube(), psfcube.psfcube(),
529   - bkgcube.bkgcube())
  450 + new_obs[0].response(response['expcube'], response['psfcube'],
  451 + response['bkgcube'])
530 452  
  453 + # Get new models
  454 + models = response['models']
  455 +
531 456 # Fix background models if required
532 457 if self['fix_bkg'].boolean():
533 458 for model in models:
... ... @@ -636,8 +561,8 @@ class cslightcrv(ctools.cscript):
636 561  
637 562 # Signal skipping of bin
638 563 if self._logTerse():
639   - self._log(gammalib.parformat('Warning'))
640   - self._log('No event in this time bin, skip bin.\n')
  564 + self._log_value('Warning', 'No event in this time bin, '
  565 + 'skip bin.')
641 566  
642 567 # Set all results to 0
643 568 for par in pars:
... ... @@ -678,19 +603,12 @@ class cslightcrv(ctools.cscript):
678 603 value = source.spectral()[par].value()
679 604 error = source.spectral()[par].error()
680 605 unit = source.spectral()[par].unit()
681   - self._log(gammalib.parformat(par))
682   - self._log(str(value))
683   - self._log(' +/- ')
684   - self._log(str(error))
685   - self._log(' ')
686   - self._log(unit)
687   - self._log('\n')
  606 + self._log_value(par, str(value)+' +/- '+str(error)+' '+unit)
688 607 if result['ulimit'] > 0.0:
689   - self._log(gammalib.parformat('Upper flux limit'))
690   - self._log(str(result['ulimit'])+' ph/cm2/s\n')
  608 + self._log_value('Upper flux limit', str(result['ulimit'])+
  609 + ' ph/cm2/s')
691 610 if self['calc_ts'].boolean():
692   - self._log(gammalib.parformat('Test Statistic'))
693   - self._log(str(result['ts'])+'\n')
  611 + self._log_value('Test Statistic', result['ts'])
694 612  
695 613 # Create FITS table from results
696 614 table = self._create_fits_table(results)
... ... @@ -738,9 +656,7 @@ class cslightcrv(ctools.cscript):
738 656  
739 657 # Log file name
740 658 if self._logTerse():
741   - self._log(gammalib.parformat('Light curve file'))
742   - self._log(outfile.url())
743   - self._log('\n')
  659 + self._log_value('Light curve file', outfile.url())
744 660  
745 661 # Save spectrum
746 662 self._fits.saveto(outfile, self._clobber())
... ... @@ -750,7 +666,7 @@ class cslightcrv(ctools.cscript):
750 666  
751 667 def lightcurve(self):
752 668 """
753   - Return light curve FITS file.
  669 + Return light curve FITS file
754 670  
755 671 Returns
756 672 -------
... ...
cscripts/csmodelinfo.py
... ... @@ -28,7 +28,7 @@ import ctools
28 28 # ================= #
29 29 class csmodelinfo(ctools.cscript):
30 30 """
31   - Shows the content of a model container.
  31 + Shows the content of a model container
32 32  
33 33 The script is useful to show, e.g., the number of sources in a model
34 34 container, the background models, free and fixed parameters etc.
... ... @@ -39,29 +39,16 @@ class csmodelinfo(ctools.cscript):
39 39 # Constructor
40 40 def __init__(self, *argv):
41 41 """
42   - Constructor.
  42 + Constructor
43 43 """
44 44 # Set name
45   - self._name = "csmodelinfo"
46   - self._version = "1.1.0"
  45 + self._name = 'csmodelinfo'
  46 + self._version = '1.2.0'
47 47  
48 48 # Initialise class members
49   - self._models = gammalib.GModels()
50   - self._ds9file = gammalib.GFilename("NONE")
51   - self._pnt_type = ""
52   - self._pnt_mark_size = 12
53   - self._show_labels = True
54   - self._width = 2
55   - self._fontfamily = "helvetica"
56   - self._fontsize = 12
57   - self._fontweight = "normal"
58   - self._fontslant = "roman"
59   - self._show_ext_type = True
60   - self._free_color = "green"
61   - self._fixed_color = "magenta"
62   -
63   - # Initialise application by calling the appropriate class
64   - # constructor.
  49 + self._models = gammalib.GModels()
  50 +
  51 + # Initialise application by calling the appropriate class constructor
65 52 self._init_cscript(argv)
66 53  
67 54 # Return
... ... @@ -71,57 +58,83 @@ class csmodelinfo(ctools.cscript):
71 58 # Private methods
72 59 def _get_parameters(self):
73 60 """
74   - Get parameters from parfile and setup the observation.
  61 + Get parameters from parfile and setup the observation
75 62 """
76 63 # Get models
77   - self._models = gammalib.GModels(self["inmodel"].filename())
  64 + self._models = gammalib.GModels(self['inmodel'].filename())
78 65  
79   - # Get hidden parameters for region file
80   - self._pnt_type = self["pnt_type"].string()
81   - self._pnt_mark_size = self["pnt_mark_size"].integer()
82   - self._show_labels = self["show_labels"].boolean()
83   - self._width = self["width"].integer()
84   - self._fontfamily = self["fontfamily"].string()
85   - self._fontsize = self["fontsize"].integer()
86   - self._fontweight = self["fontweight"].string()
87   - self._fontslant = self["fontslant"].string()
88   - self._show_ext_type = self["show_ext_type"].boolean()
89   - self._free_color = self["free_color"].string()
90   - self._fixed_color = self["fixed_color"].string()
91   -
92   - # Read ahead DS9 filename
  66 + # Query hidden parameters for region file
  67 + self['pnt_type'].string()
  68 + self['pnt_mark_size'].integer()
  69 + self['show_labels'].boolean()
  70 + self['width'].integer()
  71 + self['fontfamily'].string()
  72 + self['fontsize'].integer()
  73 + self['fontweight'].string()
  74 + self['fontslant'].string()
  75 + self['show_ext_type'].boolean()
  76 + self['free_color'].string()
  77 + self['fixed_color'].string()
  78 +
  79 + # Query ahead DS9 filename
93 80 if self._read_ahead():
94   - self._ds9file = self["ds9file"].filename()
  81 + self["ds9file"].filename()
95 82  
96 83 # Write input parameters into logger
97 84 if self._logTerse():
98 85 self._log_parameters()
99   - self._log("\n")
  86 + self._log('\n')
100 87  
101 88 # Return
102 89 return
103 90  
  91 + def _ds9attributes(self, model):
  92 + """
  93 + Returns attributes for DS9 string
  94 + Parameters
  95 + ----------
  96 + model : `~gammalib.GModel`
  97 + Model
  98 +
  99 + Returns
  100 + -------
  101 + attributes : str
  102 + DS9 attribute string
  103 + """
  104 + # Determine region color. A model where all parameters are fixed will
  105 + # get the color defined by "fixed_color", a model with at least one
  106 + # free parameter will get the color defined by "free_color".
  107 + color = self['fixed_color'].string()
  108 + for par in model:
  109 + if par.is_free():
  110 + color = self['free_color'].string()
  111 + break
  112 +
  113 + # Set DS9 attributes
  114 + attributes = (' color=%s width=%d font=%s %d %s %s' %
  115 + (color, self['width'].integer(),
  116 + self['fontfamily'].string(), self['fontsize'].integer(),
  117 + self['fontweight'].string(), self['fontslant'].string()))
  118 +
  119 + # Return attributes
  120 + return attributes
  121 +
104 122 def _model2ds9string(self, model):
105 123 """
106   - Converts model into a DS9 region string.
  124 + Converts model into a DS9 region string
107 125  
108   - Args:
109   - model: Model.
  126 + Parameters
  127 + ----------
  128 + model : `~gammalib.GModel`
  129 + Model
110 130  
111   - Returns:
112   - DS9 region string.
  131 + Returns
  132 + -------
  133 + ds9string : str
  134 + DS9 region string
113 135 """
114 136 # Initialise DS9 region string
115   - ds9string = ""
116   -
117   - # Determine region color. The color will change between a model
118   - # where all parameters are fixed and a model with at least one
119   - # free parameter.
120   - color = self._fixed_color
121   - for par in model:
122   - if par.is_free():
123   - color = self._free_color
124   - break
  137 + ds9string = ''
125 138  
126 139 # Retrieve model sky direction. The model is skipped in case that
127 140 # it does not provide a sky direction.
... ... @@ -129,8 +142,9 @@ class csmodelinfo(ctools.cscript):
129 142 try:
130 143 modelpos = model.spatial().dir()
131 144 except AttributeError:
132   - self._log("Skip source \""+model.name()+"\" since no "
133   - "sky direction is associated with that model.\n")
  145 + msg = ('Skip model "%s" since it has no sky direction.\n' %
  146 + model.name())
  147 + self._log(msg)
134 148 is_valid = False
135 149  
136 150 # Continue only if sky direction was found
... ... @@ -141,16 +155,16 @@ class csmodelinfo(ctools.cscript):
141 155 modelname = model.name()
142 156  
143 157 # Handle point source
144   - if modeltype == "PointSource":
  158 + if modeltype == 'PointSource':
145 159  
146   - # Append point to DS9 string
147   - ds9string += "point("
148   - ds9string += str(modelpos.ra_deg())
149   - ds9string += ","
150   - ds9string += str(modelpos.dec_deg())
151   - ds9string += ") # "
152   - ds9string += "point="+self._pnt_type+" "
153   - ds9string += str(self._pnt_mark_size)+" "
  160 + # Append point with Right Ascension and Declination to the DS9
  161 + # string. The type of the point is specified by the "pnt_type"
  162 + # parameter, the size of the point by the "pnt_mark_size"
  163 + # parameter
  164 + ds9string += ('point(%.6f,%.6f) # point=%s %d' %
  165 + (modelpos.ra_deg(), modelpos.dec_deg(),
  166 + self['pnt_type'].string(),
  167 + self['pnt_mark_size'].integer()))
154 168  
155 169 # Handle extended sources
156 170 elif modeltype == "ExtendedSource":
... ... @@ -160,89 +174,74 @@ class csmodelinfo(ctools.cscript):
160 174 classname = spatial.classname()
161 175  
162 176 # Handle radial sources
163   - if "Radial" in classname:
  177 + if 'Radial' in classname:
164 178  
165 179 # Retrieve short name of model class (e.g. "Gauss"
166 180 # or "Disk)
167   - shorttype = classname.split("Radial")[-1]
  181 + shorttype = classname.split('Radial')[-1]
168 182  
169 183 # Handle Disk and Shell model
170   - if (classname == "GModelSpatialRadialDisk" or
171   - classname == "GModelSpatialRadialShell"):
  184 + if (classname == 'GModelSpatialRadialDisk' or
  185 + classname == 'GModelSpatialRadialShell'):
172 186 size = spatial.radius()
173 187  
174 188 # Handle Gauss Model
175   - elif classname == "GModelSpatialRadialGauss":
  189 + elif classname == 'GModelSpatialRadialGauss':
176 190 size = spatial.sigma()
177 191  
178 192 # Skip if source is unknown
179 193 else:
180   - self._log("Skip source \""+model.name()+"\""
181   - " since the radial model \""+classname+
182   - "\" is unkown.\n")
  194 + msg = ('Skip model "%s" since the radial model "%s" '
  195 + 'is unknown.\n' % (model.name(), classname))
  196 + self._log(msg)
183 197 is_valid = False
184 198  
185 199 # Append circle to DS9 string
186 200 if is_valid:
187   - ds9string += "circle("
188   - ds9string += str(modelpos.ra_deg())
189   - ds9string += ","
190   - ds9string += str(modelpos.dec_deg())
191   - ds9string += ","
192   - ds9string += str(size*3600.)+"\") # "
193   -
  201 + ds9string += ('circle(%.6f,%.6f,%.6f) #' %
  202 + (modelpos.ra_deg(), modelpos.dec_deg(),
  203 + size*3600.0))
  204 +
194 205 # Handle elliptical sources
195   - elif "Elliptical" in classname:
  206 + elif 'Elliptical' in classname:
196 207  
197 208 # Retrieve short name and source size
198   - shorttype = classname.split("Elliptical")[-1]
  209 + shorttype = classname.split('Elliptical')[-1]
199 210 size1 = spatial.semimajor()
200 211 size2 = spatial.semiminor()
201 212 angle = spatial.posangle()
202 213  
203 214 # Append ellipse to DS9 string
204   - ds9string += "ellipse("
205   - ds9string += str(modelpos.ra_deg())
206   - ds9string += ","
207   - ds9string += str(modelpos.dec_deg())
208   - ds9string += ","
209   - ds9string += str(size1*3600.)+"\""
210   - ds9string += ","
211   - ds9string += str(size2*3600.)+"\""
212   - ds9string += ","
213   - ds9string += str(angle+90.0)+") # "
  215 + ds9string += ('ellipse(%.6f,%.6f,%.6f,%.6f,%.6f) #' %
  216 + (modelpos.ra_deg(), modelpos.dec_deg(),
  217 + size1*3600.0, size2*3600.0, angle+90.0))
214 218  
215 219 # Skip if source is neither radial nor elliptical
216 220 else:
217   - self._log("Skip source \""+model.name()+"\" "
218   - "since the model \""+classname+"\" is "
219   - "neither a point source, a radial source, "
220   - "nor a elliptical source.\n")
  221 + msg = ('Skip model "%s" since the model "%s" is neither '
  222 + 'a point source, a radial source, nor an elliptical '
  223 + 'source.\n' % (model.name(), classname))
  224 + self._log(msg)
221 225 is_valid = False
222 226  
223 227 # Add short model type to modelname
224   - if self._show_ext_type:
225   - modelname +=" ("+shorttype+")"
  228 + if self['show_ext_type'].boolean():
  229 + modelname +=' ('+shorttype+')'
226 230  
227 231 # Add DS9 attributes
228 232 if is_valid:
229   - ds9string += "color="+color+" "
230   - ds9string += "width="+str(self._width)+" "
231   - ds9string += "font=\""+self._fontfamily+" "
232   - ds9string += str(self._fontsize)+" "
233   - ds9string += self._fontweight+" "
234   - ds9string += self._fontslant+"\""
235   - if self._show_labels:
236   - ds9string += " text={"+modelname+"}"
  233 + ds9string += self._ds9attributes(model)
  234 + if self['show_labels'].boolean():
  235 + ds9string += ' text={'+modelname+'}'
237 236  
238 237 # Return string
239 238 return ds9string
240   -
  239 +
241 240  
242 241 # Public methods
243 242 def run(self):
244 243 """
245   - Run the script.
  244 + Run the script
246 245 """
247 246 # Switch screen logging on in debug mode
248 247 if self._logDebug():
... ... @@ -253,11 +252,11 @@ class csmodelinfo(ctools.cscript):
253 252  
254 253 # Optionally log models
255 254 if self._logVerbose():
256   - self._log("\n")
257   - self._log.header1("Models")
258   - self._log("\n")
  255 + self._log('\n')
  256 + self._log.header1('Models')
  257 + self._log('\n')
259 258 self._log(str(self._models))
260   - self._log("\n")
  259 + self._log('\n')
261 260  
262 261 # Initialise output values
263 262 types = {}
... ... @@ -295,7 +294,7 @@ class csmodelinfo(ctools.cscript):
295 294 ts[model.name()] = model.ts()
296 295  
297 296 # Skymodel?
298   - skymodel = (model.classname() == "GModelSky")
  297 + skymodel = (model.classname() == 'GModelSky')
299 298 if skymodel:
300 299 free_src_pars[model.name()] = []
301 300  
... ... @@ -340,140 +339,110 @@ class csmodelinfo(ctools.cscript):
340 339 if self._logTerse():
341 340  
342 341 # Log summary
343   - self._log("\n")
344   - self._log.header1("Summary")
  342 + self._log('\n')
  343 + self._log.header1('Summary')
345 344  
346 345 # Log instruments
347   - self._log.header3("Instrument specific models")
  346 + self._log.header3('Instrument specific models')
348 347 for inst, n_inst in instruments.items():
349   - if inst == "":
350   - inst = "All"
351   - self._log.parformat(inst)
352   - self._log(str(n_inst))
353   - self._log("\n")
  348 + if inst == '':
  349 + inst = 'All'
  350 + self._log_value(inst, n_inst)
354 351  
355 352 # Log model types
356   - self._log.header3("Model types")
  353 + self._log.header3('Model types')
357 354 for modeltype, n_types in types.items():
358   - self._log.parformat(modeltype)
359   - self._log(str(n_types))
360   - self._log("\n")
  355 + self._log_value(modeltype, n_types)
361 356  
362 357 # Log model parameter information
363   - self._log("\n")
364   - self._log.header1("Parameter information")
365   - self._log.parformat("All parameters")
366   - self._log(str(n_par_total))
367   - self._log("\n")
368   - self._log.parformat("Fixed parameters")
369   - self._log(str(n_par_fixed))
370   - self._log("\n")
371   - self._log.parformat("Free parameters (total)")
372   - self._log(str(n_par_free))
373   - self._log("\n")
374   - self._log.parformat("Free background parameters")
375   - self._log(str(n_par_free_bkg))
376   - self._log("\n")
377   - self._log.parformat("Free source parameters")
378   - self._log(str(n_par_free_src))
379   - self._log("\n")
  358 + self._log('\n')
  359 + self._log.header1('Parameter information')
  360 + self._log_value('All parameters', n_par_total)
  361 + self._log_value('Fixed parameters', n_par_fixed)
  362 + self._log_value('Free parameters (total)', n_par_free)
  363 + self._log_value('Free background parameters', n_par_free_bkg)
  364 + self._log_value('Free source parameters', n_par_free_src)
380 365 if n_par_free_spec > 0:
381   - self._log.parformat("Free spectral parameters")
382   - self._log(str(n_par_free_spec))
383   - self._log("\n")
  366 + self._log_value('Free spectral parameters', n_par_free_spec)
384 367 if n_par_free_spat > 0:
385   - self._log.parformat("Free spatial parameters")
386   - self._log(str(n_par_free_spat))
387   - self._log("\n")
  368 + self._log_value('Free spatial parameters', n_par_free_spat)
388 369 if n_par_free_temp > 0:
389   - self._log.parformat("Free temporal parameters")
390   - self._log(str(n_par_free_temp))
391   - self._log("\n")
392   - self._log.parformat("Parameters at limit")
393   - self._log(str(n_par_at_limit))
394   - self._log("\n")
  370 + self._log_value('Free temporal parameters', n_par_free_temp)
  371 + self._log_value('Parameters at limit', n_par_at_limit)
395 372  
396 373 # Log parameters at limit (if any)
397 374 if n_par_at_limit > 0:
398   - self._log.header3("Parameters at limit")
  375 + self._log.header3('Parameters at limit')
399 376 for source, parameter in pars_at_limit.items():
400 377 if len(parameter):
401 378 for par in parameter:
402   - self._log.parformat(source)
403   - self._log(par)
404   - self._log("\n")
  379 + self._log_value(source, par)
405 380  
406 381 # Optionally log free parameters
407 382 if self._logExplicit() and len(free_src_pars):
408   - self._log("\n")
409   - self._log.header2("Free source parameters")
  383 + self._log('\n')
  384 + self._log.header2('Free source parameters')
410 385 for source, parameter in free_src_pars.items():
411 386 if len(parameter):
412 387 self._log.header3(source)
413 388 for par in parameter:
414 389 self._log(str(par))
415   - self._log("\n")
416   - self._log("\n")
  390 + self._log('\n')
  391 + self._log('\n')
417 392  
418 393 # Log TS values if available
419 394 if len(ts):
420   - self._log.header3("Test statistics")
421   - for source,tsvalue in ts.items():
422   - self._log.parformat(source)
423   - self._log("%.2f"%tsvalue)
424   - self._log("\n")
  395 + self._log.header3('Test statistics')
  396 + for source, tsvalue in ts.items():
  397 + self._log_value(source, tsvalue)
425 398  
426 399 # Return
427 400 return
428 401  
429 402 def save(self):
430 403 """
431   - Save models to ds9 region file if required
  404 + Save models to ds9 region file
432 405 """
433   -
434   - # Get output filename in case it was not read ahead
435   - self._ds9file = self["ds9file"].filename()
  406 + # Get output filename
  407 + ds9file = self['ds9file'].filename()
436 408  
437 409 # Check if DS9 file is valid
438   - if self._ds9file != "NONE":
  410 + if ds9file != '' and ds9file != 'NONE':
439 411  
440 412 # Write header
441 413 if self._logTerse():
442   - self._log("\n")
443   - self._log.header1("Save models in DS9 file")
  414 + self._log('\n')
  415 + self._log.header1('Save models in DS9 file')
444 416  
445 417 # Log filename
446 418 if self._logTerse():
447   - self._log(gammalib.parformat("DS9 filename"))
448   - self._log(self._ds9file.url())
449   - self._log("\n")
  419 + self._log_value('DS9 filename', ds9file.url())
450 420  
451 421 # Open file
452   - f = open(self._ds9file.url(),"w")
  422 + f = open(ds9file.url(), 'w')
453 423  
454 424 # Write coordinate system
455   - f.write("fk5\n")
  425 + f.write('fk5\n')
456 426  
457 427 # Loop over models
458 428 for model in self._models:
459 429  
460 430 # Continue only if point source or extended source model
461   - if (model.type() == "PointSource" or
462   - model.type() == "ExtendedSource"):
  431 + if (model.type() == 'PointSource' or
  432 + model.type() == 'ExtendedSource'):
463 433 line = self._model2ds9string(model)
464 434 if len(line):
465   - f.write(line+"\n")
  435 + f.write(line+'\n')
466 436  
467 437 # Logging for diffuse components
468   - elif model.type() == "DiffuseSource":
469   - self._log("Skipping diffuse model \""+model.name()+
470   - "\"\n")
  438 + elif model.type() == 'DiffuseSource':
  439 + self._log('Skipping diffuse model "'+model.name()+'".\n')
471 440  
472 441 # Logging for background components
473 442 else:
474 443 if self._logExplicit():
475   - self._log("Skipping background model \""+
476   - model.name()+"\"\n")
  444 + self._log('Skipping background model "'+model.name()+
  445 + '".\n')
477 446  
478 447 # Close file
479 448 f.close()
... ... @@ -483,7 +452,7 @@ class csmodelinfo(ctools.cscript):
483 452  
484 453 def execute(self):
485 454 """
486   - Execute the script.
  455 + Execute the script
487 456 """
488 457 # Open logfile
489 458 self.logFileOpen()
... ...
cscripts/csmodelmerge.py
... ... @@ -43,7 +43,7 @@ class csmodelmerge(ctools.cscript):
43 43 """
44 44 # Set name
45 45 self._name = 'csmodelmerge'
46   - self._version = '1.1.0'
  46 + self._version = '1.2.0'
47 47  
48 48 # Initialise class members
49 49 self._files = None
... ... @@ -146,23 +146,19 @@ class csmodelmerge(ctools.cscript):
146 146 if self._logTerse():
147 147 nmodels = models.size()
148 148 if nmodels == 0:
149   - self._log(gammalib.parformat('Add no model from file'))
  149 + name = 'Add no model from file'
150 150 elif nmodels == 1:
151   - self._log(gammalib.parformat('Add 1 model from file'))
  151 + name = 'Add 1 model from file'
152 152 else:
153   - self._log(gammalib.parformat('Add %d models from file' %
154   - nmodels))
155   - self._log(f)
156   - self._log('\n')
  153 + name = 'Add %d models from file' % nmodels
  154 + self._log_value(name, f)
157 155  
158 156 # Extend model container by adding all models in the model file
159 157 self._models.extend(models)
160 158  
161 159 # Log total number of models
162 160 if self._logTerse():
163   - self._log(gammalib.parformat('Models after merging'))
164   - self._log(self._models.size())
165   - self._log('\n')
  161 + self._log_value('Models after merging', self._models.size())
166 162  
167 163 # Return
168 164 return
... ... @@ -189,9 +185,7 @@ class csmodelmerge(ctools.cscript):
189 185  
190 186 # Log filename
191 187 if self._logTerse():
192   - self._log(gammalib.parformat('Model definition XML file'))
193   - self._log(outmodel.url())
194   - self._log('\n')
  188 + self._log_value('Model definition XML file', outmodel.url())
195 189  
196 190 # Save models
197 191 self._models.save(outmodel)
... ...
cscripts/csobs2caldb.py
... ... @@ -156,19 +156,11 @@ class csobs2caldb(ctools.cscript):
156 156  
157 157 # Log filenames
158 158 if self._logNormal():
159   - self._log.header3("IRF input files")
160   - self._log(gammalib.parformat("Effective area"))
161   - self._log(fname_aeff.url())
162   - self._log("\n")
163   - self._log(gammalib.parformat("Point spread function"))
164   - self._log(fname_psf.url())
165   - self._log("\n")
166   - self._log(gammalib.parformat("Energy dispersion"))
167   - self._log(fname_edisp.url())
168   - self._log("\n")
169   - self._log(gammalib.parformat("Background rate"))
170   - self._log(fname_bkg.url())
171   - self._log("\n")
  159 + self._log.header3('IRF input files')
  160 + self._log_value('Effective area', fname_aeff.url())
  161 + self._log_value('Point spread function', fname_psf.url())
  162 + self._log_value('Energy dispersion', fname_edisp.url())
  163 + self._log_value('Background rate', fname_bkg.url())
172 164  
173 165 # Open FITS files of response components
174 166 fits_aeff = gammalib.GFits(fname_aeff)
... ... @@ -336,18 +328,13 @@ class csobs2caldb(ctools.cscript):
336 328  
337 329 # Log resulting FITS table
338 330 if self._logNormal():
339   - self._log(gammalib.parformat("Calibration directory"))
340   - self._log(self._cal_dir)
341   - self._log("\n")
342   - self._log(gammalib.parformat("Base directory"))
343   - self._log(self._base_dir)
344   - self._log("\n")
  331 + self._log_value('Calibration directory', self._cal_dir)
  332 + self._log_value('Base directory', self._base_dir)
345 333 if not os.path.isdir(self._rsp_dir):
346   - self._log(gammalib.parformat("IRF directory"))
  334 + name = 'IRF directory'
347 335 else:
348   - self._log(gammalib.parformat("IRF directory (existing)"))
349   - self._log(self._rsp_dir)
350   - self._log("\n")
  336 + name = 'IRF directory (existing)'
  337 + self._log_value(name, self._rsp_dir)
351 338  
352 339 # Create IRF directory is it does not yet exist
353 340 if not os.path.isdir(self._rsp_dir):
... ... @@ -400,12 +387,8 @@ class csobs2caldb(ctools.cscript):
400 387  
401 388 # Write filenames into logger
402 389 if self._logNormal():
403   - self._log(gammalib.parformat('CALDB index file'))
404   - self._log(self._caldb_inx.filename().url())
405   - self._log('\n')
406   - self._log(gammalib.parformat('Response file'))
407   - self._log(filename)
408   - self._log('\n')
  390 + self._log_value('CALDB index file', self._caldb_inx.filename().url())
  391 + self._log_value('Response file', filename)
409 392  
410 393 # Save caldb index file
411 394 self._caldb_inx.save(self._clobber())
... ...
cscripts/csobsdef.py
... ... @@ -75,7 +75,7 @@ class csobsdef(ctools.cscript):
75 75 # Constructor
76 76 def __init__(self, *argv):
77 77 """
78   - Constructor.
  78 + Constructor
79 79  
80 80 Parameters
81 81 ----------
... ... @@ -85,7 +85,7 @@ class csobsdef(ctools.cscript):
85 85 """
86 86 # Set name and version
87 87 self._name = 'csobsdef'
88   - self._version = '1.1.0'
  88 + self._version = '1.2.0'
89 89  
90 90 # Initialise class members
91 91 self._obs = gammalib.GObservations()
... ... @@ -103,7 +103,7 @@ class csobsdef(ctools.cscript):
103 103 # Private methods
104 104 def _get_parameters(self):
105 105 """
106   - Get parameters from parfile.
  106 + Get parameters from parfile
107 107 """
108 108 # Query input filename if necessary
109 109 if self._pntdef.size() == 0:
... ... @@ -123,7 +123,7 @@ class csobsdef(ctools.cscript):
123 123  
124 124 def _set_response(self, obs, caldb, irf):
125 125 """
126   - Set response for an observation.
  126 + Set response for an observation
127 127  
128 128 The method creates an XML element so that that the response XML
129 129 writer will write the database and response name into the
... ... @@ -151,7 +151,7 @@ class csobsdef(ctools.cscript):
151 151 # Public methods
152 152 def run(self):
153 153 """
154   - Run the script.
  154 + Run the script
155 155  
156 156 Raises
157 157 ------
... ... @@ -315,9 +315,9 @@ class csobsdef(ctools.cscript):
315 315 self._log(str(obs))
316 316 self._log('\n')
317 317 elif self._logTerse():
318   - self._log(gammalib.parformat(obs.instrument()+' observation'))
319   - self._log('Name="'+obs.name()+'" ')
320   - self._log('ID="'+obs.id()+'"\n')
  318 + name = obs.instrument()+' observation'
  319 + value = 'Name="%s" ID="%s"' % (obs.name(), obs.id())
  320 + self._log_value(name, value)
321 321  
322 322 # Append observation
323 323 self._obs.append(obs)
... ... @@ -342,9 +342,7 @@ class csobsdef(ctools.cscript):
342 342  
343 343 # Log filename
344 344 if self._logTerse():
345   - self._log(gammalib.parformat('Observation XML file'))
346   - self._log(outobs.url())
347   - self._log('\n')
  345 + self._log_value('Observation XML file', outobs.url())
348 346  
349 347 # Save observation definition XML file
350 348 self._obs.save(outobs)
... ... @@ -354,7 +352,7 @@ class csobsdef(ctools.cscript):
354 352  
355 353 def execute(self):
356 354 """
357   - Execute the script.
  355 + Execute the script
358 356 """
359 357 # Open logfile
360 358 self.logFileOpen()
... ... @@ -373,7 +371,7 @@ class csobsdef(ctools.cscript):
373 371  
374 372 def pntdef(self, csv):
375 373 """
376   - Set pointing definition from a CSV table.
  374 + Set pointing definition from a CSV table
377 375  
378 376 Parameters
379 377 ----------
... ...
cscripts/csobsinfo.py
... ... @@ -38,7 +38,7 @@ class csobsinfo(ctools.cscript):
38 38 """
39 39 # Set name
40 40 self._name = 'csobsinfo'
41   - self._version = '1.1.0'
  41 + self._version = '1.2.0'
42 42  
43 43 # Initialise class members
44 44 self._obj_dir = None
... ... @@ -181,20 +181,14 @@ class csobsinfo(ctools.cscript):
181 181 n_eventbins += obs.events().size()
182 182 n_obs_binned += 1
183 183 if self._logTerse():
184   - self._log.parformat('Binned')
185   - self._log('yes\n')
186   - self._log.parformat('Number of bins')
187   - self._log(str(obs.events().size()))
188   - self._log('\n')
  184 + self._log_value('Binned', 'yes')
  185 + self._log_value('Number of bins', obs.events().size())
189 186 else:
190 187 n_events += obs.events().size()
191 188 n_obs_unbinned += 1
192 189 if self._logTerse():
193   - self._log.parformat('Binned')
194   - self._log('no\n')
195   - self._log.parformat('Number of events')
196   - self._log(str(obs.events().size()))
197   - self._log('\n')
  190 + self._log_value('Binned', 'no')
  191 + self._log_value('Number of events', obs.events().size())
198 192  
199 193 # Retrieve zenith and azimuth and store for later use
200 194 zenith = obs.pointing().zenith()
... ... @@ -232,39 +226,19 @@ class csobsinfo(ctools.cscript):
232 226 self._log(str(obs_gti.tstop().mjd()))
233 227 self._log('\n')
234 228  
235   - # Log ontime
236   - self._log.parformat('Ontime')
237   - self._log(str(obs.ontime()))
238   - self._log(' s\n')
239   -
240   - # Log livetime
241   - self._log.parformat('Livetime')
242   - self._log(str(obs.livetime()))
243   - self._log(' s\n')
244   -
245   - # Log dead time fraction
246   - self._log.parformat('Deadtime fraction (%)')
247   - self._log('%.3f' % (deadfrac))
248   - self._log('\n')
249   -
250   - # Log pointing direction
251   - self._log.parformat('Pointing')
252   - self._log(str(pnt_dir))
253   - self._log('\n')
254   -
  229 + # Log observation information
  230 + self._log_value('Ontime', '%.3f s' % obs.ontime())
  231 + self._log_value('Livetime', '%.3f s' % obs.livetime())
  232 + self._log_value('Deadtime fraction', '%.3f %%' % deadfrac)
  233 + self._log_value('Pointing', pnt_dir)
  234 +
255 235 # Optionally log offset with respect to target direction
256 236 if self._compute_offset:
257   - self._log.parformat('Offset from target')
258   - self._log('%.2f' % (offset))
259   - self._log(' deg\n')
260   -
261   - # Log Zenith and Azimuth if required
262   - self._log.parformat('Zenith angle')
263   - self._log('%.2f' % (zenith))
264   - self._log(' deg\n')
265   - self._log.parformat('Azimuth angle')
266   - self._log('%.2f' % (azimuth))
267   - self._log(' deg\n')
  237 + self._log_value('Offset from target', '%.2f deg' % offset)
  238 +
  239 + # Log Zenith and Azimuth angles
  240 + self._log_value('Zenith angle', '%.2f deg' % zenith)
  241 + self._log_value('Azimuth angle', '%.2f deg' % azimuth)
268 242  
269 243 # Log summary
270 244 if self._logTerse():
... ... @@ -275,36 +249,26 @@ class csobsinfo(ctools.cscript):
275 249  
276 250 # Log general summary
277 251 self._log.header3('Observations')
278   - self._log.parformat('Unbinned observations')
279   - self._log(str(n_obs_unbinned))
280   - self._log('\n')
281   - self._log.parformat('Binned observations')
282   - self._log(str(n_obs_binned))
283   - self._log('\n')
  252 + self._log_value('Unbinned observations', n_obs_unbinned)
  253 + self._log_value('Binned observations', n_obs_binned)
  254 + self._log_value('Binned observations', n_obs_binned)
284 255 self._log.header3('Events')
285   - self._log.parformat('Number of events')
286   - self._log(str(n_events))
287   - self._log('\n')
288   - self._log.parformat('Number of bins')
289   - self._log(str(n_eventbins))
290   - self._log('\n')
  256 + self._log_value('Number of events', n_events)
  257 + self._log_value('Number of bins', n_eventbins)
291 258  
292 259 # Log pointing summary
293 260 self._log.header3('Pointings')
294 261  
295 262 # Log mean offset if possible
296 263 if self._compute_offset:
297   - self._log.parformat('Mean offset angle')
298   - self._log('%.2f' % (sum(self._offsets)/len(self._offsets)))
299   - self._log(' deg\n')
  264 + self._log_value('Mean offset angle', '%.2f deg' %
  265 + (sum(self._offsets)/len(self._offsets)))
300 266  
301 267 # Log mean azimuth and zenith angle
302   - self._log.parformat('Mean zenith angle')
303   - self._log('%.2f' % (sum(self._zeniths)/len(self._zeniths)))
304   - self._log(' deg\n')
305   - self._log.parformat('Mean azimuth angle')
306   - self._log('%.2f' % (sum(self._azimuths)/len(self._azimuths)))
307   - self._log(' deg\n')
  268 + self._log_value('Mean zenith angle', '%.2f deg' %
  269 + (sum(self._zeniths)/len(self._zeniths)))
  270 + self._log_value('Mean azimuth angle', '%.2f deg' %
  271 + (sum(self._azimuths)/len(self._azimuths)))
308 272  
309 273 # Optionally log names of observations. Note that the set class
310 274 # is used to extract all different observation names from the
... ... @@ -313,44 +277,34 @@ class csobsinfo(ctools.cscript):
313 277 if self._logExplicit() and sys.version_info >= (2,4):
314 278 obs_set = set(obs_names)
315 279 for name in obs_set:
316   - self._log.parformat('"'+name+'"')
317   - self._log(str(obs_names.count(name)))
318   - self._log('\n')
  280 + self._log_value('"'+name+'"', obs_names.count(name))
319 281 self._log('\n')
320   -
321   - # Log energy range
322   - self._log.header3('Energy range')
323   - self._log.parformat('Minimum energy')
324   - if self._ebounds.size() == 0:
325   - self._log('undefined')
326   - else:
327   - self._log(str(self._ebounds.emin()))
328   - self._log('\n')
329   - self._log.parformat('Maximum energy')
  282 +
  283 + # Get energy boundary information
330 284 if self._ebounds.size() == 0:
331   - self._log('undefined')
  285 + min_value = 'undefined'
  286 + max_value = 'undefined'
332 287 else:
333   - self._log(str(self._ebounds.emax()))
334   - self._log('\n')
335   -
  288 + min_value = str(self._ebounds.emin())
  289 + max_value = str(self._ebounds.emax())
  290 +
  291 + # Log energy range
  292 + self._log.header3('Energy range')
  293 + self._log_value('Minimum energy', min_value)
  294 + self._log_value('Maximum energy', max_value)
  295 +
336 296 # Log time range
337 297 self._log.header3('Time range')
338   - self._log.parformat('Start (MJD)')
339   - self._log(str(self._gti.tstart().mjd()))
340   - self._log('\n')
341   - self._log.parformat('Stop (MJD)')
342   - self._log(str(self._gti.tstop().mjd()))
343   - self._log('\n')
344   -
345   - # Log ontime and livetime in different units
346   - self._log.parformat('Total ontime')
347   - self._log('%.2f s = %.2f min = %.2f h' %
348   - (ontime, ontime/60., ontime/3600.))
349   - self._log('\n')
350   - self._log.parformat('Total livetime')
351   - self._log('%.2f s = %.2f min = %.2f h' %
352   - (livetime, livetime/60.0, livetime/3600.))
353   - self._log('\n')
  298 + self._log_value('Start (MJD)', self._gti.tstart().mjd())
  299 + self._log_value('Stop (MJD)', self._gti.tstop().mjd())
  300 +
  301 + # Log ontime and livetime in different units
  302 + on_time = '%.2f s = %.2f min = %.2f h' % \
  303 + (ontime, ontime/60., ontime/3600.)
  304 + live_time = '%.2f s = %.2f min = %.2f h' % \
  305 + (livetime, livetime/60., livetime/3600.)
  306 + self._log_value('Total ontime', on_time)
  307 + self._log_value('Total livetime', live_time)
354 308  
355 309 # Return
356 310 return
... ... @@ -377,9 +331,7 @@ class csobsinfo(ctools.cscript):
377 331  
378 332 # Log filename
379 333 if self._logTerse():
380   - self._log(gammalib.parformat('DS9 filename'))
381   - self._log(ds9file.url())
382   - self._log('\n')
  334 + self._log_value('DS9 filename', ds9file.url())
383 335  
384 336 # Open file
385 337 f = open(ds9file.url(),'w')
... ... @@ -436,7 +388,7 @@ class csobsinfo(ctools.cscript):
436 388  
437 389 def execute(self):
438 390 """
439   - Execute the script.
  391 + Execute the script
440 392 """
441 393 # Open logfile
442 394 self.logFileOpen()
... ...
cscripts/cspull.py
... ... @@ -214,16 +214,12 @@ class cspull(ctools.cscript):
214 214 if self._logNormal():
215 215 self._log.header3('Simulation')
216 216 for run in self._obs:
217   - self._log.parformat('Input observation %s' % (run.id()))
218   - self._log(self._obs_string(run))
219   - self._log('\n')
  217 + self._log_value('Input observation %s' % run.id(),
  218 + self._obs_string(run))
220 219 for run in obs:
221   - self._log.parformat('Output observation %s' % (run.id()))
222   - self._log(self._obs_string(run))
223   - self._log('\n')
224   - self._log.parformat('Number of simulated events')
225   - self._log(nevents)
226   - self._log('\n')
  220 + self._log_value('Output observation %s' % run.id(),
  221 + self._obs_string(run))
  222 + self._log_value('Number of simulated events', nevents)
227 223  
228 224 # Fit model
229 225 if self['profile'].boolean():
... ... @@ -291,13 +287,8 @@ class cspull(ctools.cscript):
291 287  
292 288 # Write result
293 289 if self._logNormal():
294   - self._log.parformat(name)
295   - self._log(pull)
296   - self._log(' (')
297   - self._log(fitted_value)
298   - self._log(' +/- ')
299   - self._log(error)
300   - self._log(')\n')
  290 + value = '%.4f (%e +/- %e)' % (pull, fitted_value, error)
  291 + self._log_value(name, value)
301 292  
302 293 # Bundle together results
303 294 result = {'colnames': colnames, 'values': values}
... ...
cscripts/csresmap.py
... ... @@ -290,9 +290,7 @@ class csresmap(ctools.cscript):
290 290  
291 291 # Log file name
292 292 if self._logTerse():
293   - self._log(gammalib.parformat('Residual map file'))
294   - self._log(outmap.url())
295   - self._log('\n')
  293 + self._log_value('Residual map file', outmap.url())
296 294  
297 295 # Save residual map
298 296 self._resmap.save(outmap, self['clobber'].boolean())
... ... @@ -325,9 +323,7 @@ class csresmap(ctools.cscript):
325 323  
326 324 # Log map name
327 325 if self._logTerse():
328   - self._log(gammalib.parformat('Residual map name'))
329   - self._log(user_name)
330   - self._log('\n')
  326 + self._log_value('Residual map name', user_name)
331 327  
332 328 # Publish map
333 329 self._resmap.publish(user_name)
... ...
cscripts/cssens.py
... ... @@ -306,15 +306,9 @@ class cssens(ctools.cscript):
306 306 if self._logTerse():
307 307 self._log('\n')
308 308 self._log.header2('Energies: '+str(emin)+' - '+str(emax))
309   - self._log.parformat('Crab flux')
310   - self._log(crab_flux)
311   - self._log(' ph/cm2/s\n')
312   - self._log.parformat('Source model flux')
313   - self._log(src_flux)
314   - self._log(' ph/cm2/s\n')
315   - self._log.parformat('Crab unit factor')
316   - self._log(crab_unit)
317   - self._log('\n')
  309 + self._log_value('Crab flux', str(crab_flux)+' ph/cm2/s')
  310 + self._log_value('Source model flux', str(src_flux)+' ph/cm2/s')
  311 + self._log_value('Crab unit factor', crab_unit)
318 312  
319 313 # Initialise loop
320 314 crab_flux_value = []
... ... @@ -358,9 +352,7 @@ class cssens(ctools.cscript):
358 352 # Write simulation results
359 353 if self._logExplicit():
360 354 self._log.header3('Simulation')
361   - self._log.parformat('Number of simulated events')
362   - self._log(nevents)
363   - self._log('\n')
  355 + self._log_value('Number of simulated events', nevents)
364 356  
365 357 # Fit test source
366 358 fit = ctools.ctlike(sim)
... ... @@ -391,22 +383,12 @@ class cssens(ctools.cscript):
391 383 # Write test source fit results
392 384 if self._logExplicit():
393 385 self._log.header3('Test source model fit')
394   - self._log.parformat('Test statistics')
395   - self._log(ts)
396   - self._log('\n')
397   - self._log.parformat('log likelihood')
398   - self._log(logL)
399   - self._log('\n')
400   - self._log.parformat('Number of predicted events')
401   - self._log(npred)
402   - self._log('\n')
403   - self._log.parformat('Fit quality')
404   - self._log(quality)
405   - self._log('\n')
  386 + self._log_value('Test statistics', ts)
  387 + self._log_value('log likelihood', logL)
  388 + self._log_value('Number of predicted events', quality)
  389 + self._log_value('Fit quality', npred)
406 390 for model in models:
407   - self._log.parformat('Model')
408   - self._log(model.name())
409   - self._log('\n')
  391 + self._log_value('Model', model.name())
410 392 for par in model:
411 393 self._log(str(par)+'\n')
412 394  
... ... @@ -447,40 +429,21 @@ class cssens(ctools.cscript):
447 429  
448 430 # Write fit results
449 431 if self._logExplicit():
450   - self._log.parformat('Photon flux')
451   - self._log(photon_flux)
452   - self._log(' ph/cm2/s\n')
453   - self._log.parformat('Energy flux')
454   - self._log(energy_flux)
455   - self._log(' erg/cm2/s\n')
456   - self._log.parformat('Crab flux')
457   - self._log(crab_flux*1000.0)
458   - self._log(' mCrab\n')
459   - self._log.parformat('Differential sensitivity')
460   - self._log(sensitivity)
461   - self._log(' erg/cm2/s\n')
  432 + self._log_value('Photon flux', str(photon_flux)+' ph/cm2/s')
  433 + self._log_value('Energy flux', str(energy_flux)+' erg/cm2/s')
  434 + self._log_value('Crab flux', str(crab_flux*1000.0)+' mCrab')
  435 + self._log_value('Differential sensitivity', str(sensitivity)+
  436 + ' erg/cm2/s')
462 437 for model in models:
463   - self._log.parformat('Model')
464   - self._log(model.name())
465   - self._log('\n')
  438 + self._log_value('Model', model.name())
466 439 for par in model:
467 440 self._log(str(par)+'\n')
468 441 elif self._logTerse():
469   - self._log.parformat('Iteration %d' % iterations)
470   - self._log('TS=')
471   - self._log(ts)
472   - self._log(' ')
473   - self._log('corr=')
474   - self._log(correct)
475   - self._log(' ')
476   - self._log(photon_flux)
477   - self._log(' ph/cm2/s = ')
478   - self._log(energy_flux)
479   - self._log(' erg/cm2/s = ')
480   - self._log(crab_flux*1000.0)
481   - self._log(' mCrab = ')
482   - self._log(sensitivity)
483   - self._log(' erg/cm2/s\n')
  442 + name = 'Iteration %d' % iterations
  443 + value = ('TS=%.4f corr=%e %e ph/cm2/s = %e erg/cm2/s = %.2f '
  444 + 'mCrab = %e erg/cm2/s' % (ts, correct, photon_flux,
  445 + energy_flux, crab_flux*1000.0, sensitivity))
  446 + self._log_value(name, value)
484 447  
485 448 # Compute sliding average of extrapolated fitted prefactor,
486 449 # photon and energy flux. This damps out fluctuations and
... ... @@ -534,35 +497,17 @@ class cssens(ctools.cscript):
534 497 # Write fit results
535 498 if self._logTerse():
536 499 self._log.header3('Fit results')
537   - self._log.parformat('Test statistics')
538   - self._log(ts)
539   - self._log('\n')
540   - self._log.parformat('Photon flux')
541   - self._log(photon_flux)
542   - self._log(' ph/cm2/s\n')
543   - self._log.parformat('Energy flux')
544   - self._log(energy_flux)
545   - self._log(' erg/cm2/s\n')
546   - self._log.parformat('Crab flux')
547   - self._log(crab_flux*1000.0)
548   - self._log(' mCrab\n')
549   - self._log.parformat('Differential sensitivity')
550   - self._log(sensitivity)
551   - self._log(' erg/cm2/s\n')
552   - self._log.parformat('Number of simulated events')
553   - self._log(nevents)
554   - self._log('\n')
  500 + self._log_value('Test statistics', ts)
  501 + self._log_value('Photon flux', str(photon_flux)+' ph/cm2/s')
  502 + self._log_value('Energy flux', str(energy_flux)+' erg/cm2/s')
  503 + self._log_value('Crab flux', str(crab_flux*1000.0)+' mCrab')
  504 + self._log_value('Differential sensitivity', str(sensitivity)+' erg/cm2/s')
  505 + self._log_value('Number of simulated events', nevents)
555 506 self._log.header3('Test source model fitting')
556   - self._log.parformat('log likelihood')
557   - self._log(logL)
558   - self._log('\n')
559   - self._log.parformat('Number of predicted events')
560   - self._log(npred)
561   - self._log('\n')
  507 + self._log_value('log likelihood', logL)
  508 + self._log_value('Number of predicted events', npred)
562 509 for model in models:
563   - self._log.parformat('Model')
564   - self._log(model.name())
565   - self._log('\n')
  510 + self._log_value('Model', model.name())
566 511 for par in model:
567 512 self._log(str(par)+'\n')
568 513  
... ...
cscripts/csspec.py
... ... @@ -214,17 +214,13 @@ class csspec(ctools.cscript):
214 214 self._log.header1("Spectral binning")
215 215 if self._binned_mode:
216 216 cube_ebounds = self._obs[0].events().ebounds()
217   - self._log.parformat("Counts cube energy range")
218   - self._log(str(cube_ebounds.emin()))
219   - self._log(" - ")
220   - self._log(str(cube_ebounds.emax()))
221   - self._log("\n")
  217 + value = '%s - %s' % (str(cube_ebounds.emin()),
  218 + str(cube_ebounds.emax()))
  219 + self._log_value('Counts cube energy range', value)
222 220 for i in range(self._ebounds.size()):
223   - self._log.parformat("Bin "+str(i+1))
224   - self._log(str(self._ebounds.emin(i)))
225   - self._log(" - ")
226   - self._log(str(self._ebounds.emax(i)))
227   - self._log("\n")
  221 + value = '%s - %s' % (str(self._ebounds.emin(i)),
  222 + str(self._ebounds.emax(i)))
  223 + self._log_value('Bin %d' % (i+1), value)
228 224  
229 225 # Write observation into logger
230 226 if self._logTerse():
... ...
cscripts/cstsdist.py
... ... @@ -160,9 +160,7 @@ class cstsdist(ctools.cscript):
160 160 # Write simulation results
161 161 if self._logExplicit():
162 162 self._log.header3('Simulation')
163   - self._log.parformat('Number of simulated events')
164   - self._log(nevents)
165   - self._log('\n')
  163 + self._log_value('Number of simulated events', nevents)
166 164  
167 165 # Fit model
168 166 fit = ctools.ctlike(sim)
... ... @@ -180,30 +178,18 @@ class cstsdist(ctools.cscript):
180 178 # Write fit results, either explicit or normal
181 179 if self._logExplicit():
182 180 self._log.header3('Test source model fit')
183   - self._log.parformat('Test statistics')
184   - self._log(ts)
185   - self._log('\n')
186   - self._log.parformat('log likelihood')
187   - self._log(logL)
188   - self._log('\n')
189   - self._log.parformat('Number of predicted events')
190   - self._log(npred)
191   - self._log('\n')
  181 + self._log_value('Test statistics', ts)
  182 + self._log_value('log likelihood', logL)
  183 + self._log_value('Number of predicted events', npred)
192 184 for model in models:
193   - self._log.parformat('Model')
194   - self._log(model.name())
195   - self._log('\n')
  185 + self._log_value('Model', model.name())
196 186 for par in model:
197 187 self._log(str(par)+'\n')
198 188 elif self._logNormal():
199   - self._log.parformat('Trial '+str(seed))
200   - self._log('TS=')
201   - self._log(ts)
202   - self._log(' Prefactor=')
203   - self._log(model['Prefactor'].value())
204   - self._log('+/-')
205   - self._log(model['Prefactor'].error())
206   - self._log('\n')
  189 + name = 'Trial %d' % seed
  190 + value = 'TS=%.3f Prefactor=%e +/- %e' % \
  191 + (ts, model['Prefactor'].value(), model['Prefactor'].error())
  192 + self._log_value(name, value)
207 193  
208 194 # Initialise results
209 195 colnames = []
... ...
cscripts/cstsmapmerge.py
... ... @@ -293,9 +293,8 @@ class cstsmapmerge(ctools.cscript):
293 293 # Skip file if it's not a FITS file
294 294 if not gammalib.GFilename(fitsfile).is_fits():
295 295 if self._logExplicit():
296   - self._log(gammalib.parformat('Skip file'))
297   - self._log(fitsfile)
298   - self._log(' (not a FITS file)\n')
  296 + self._log_value('Skip file',
  297 + '%s (not a FITS file)' % fitsfile)
299 298 continue
300 299  
301 300 # Open FITS file
... ... @@ -317,9 +316,8 @@ class cstsmapmerge(ctools.cscript):
317 316 else:
318 317 fits.close()
319 318 if self._logExplicit():
320   - self._log(gammalib.parformat('Skip file'))
321   - self._log(fitsfile)
322   - self._log(' (no "STATUS MAP" extension)\n')
  319 + self._log_value('Skip file',
  320 + '%s (no "STATUS MAP" extension)' % fitsfile)
323 321 continue
324 322  
325 323 # Signal if no suitable file was found
... ... @@ -349,10 +347,9 @@ class cstsmapmerge(ctools.cscript):
349 347 # Skip if file is not FITS
350 348 if not gammalib.GFilename(fitsfile).is_fits():
351 349 if self._logExplicit():
352   - self._log(gammalib.parformat('Skip file'))
353   - self._log(fitsfile)
354   - self._log(' (not a FITS file)\n')
355   - continue
  350 + self._log_value('Skip file',
  351 + '%s (not a FITS file)' % fitsfile)
  352 + continue
356 353  
357 354 # Open FITS file
358 355 fits = gammalib.GFits(fitsfile)
... ... @@ -361,9 +358,9 @@ class cstsmapmerge(ctools.cscript):
361 358 if not fits.contains('STATUS MAP'):
362 359 fits.close()
363 360 if self._logExplicit():
364   - self._log(gammalib.parformat('Skip file'))
365   - self._log(fitsfile)
366   - self._log(' (no "STATUS MAP" extension)\n')
  361 + self._log_value('Skip file',
  362 + '%s (no "STATUS MAP" extension)' %
  363 + fitsfile)
367 364 continue
368 365  
369 366 # Close FITS file
... ... @@ -400,9 +397,7 @@ class cstsmapmerge(ctools.cscript):
400 397  
401 398 # Log filename
402 399 if self._logTerse():
403   - self._log(gammalib.parformat('TS map file'))
404   - self._log(outmap.url())
405   - self._log('\n')
  400 + self._log_value('TS map file', outmap.url())
406 401  
407 402 # Create FITS file
408 403 fits = gammalib.GFits()
... ... @@ -438,9 +433,7 @@ class cstsmapmerge(ctools.cscript):
438 433 for filename in self._merged_files:
439 434 os.remove(filename)
440 435 if self._logTerse():
441   - self._log(gammalib.parformat('Deleted input file'))
442   - self._log(filename)
443   - self._log('\n')
  436 + self._log_value('Deleted input file', filename)
444 437  
445 438 # Return
446 439 return
... ...
cscripts/cstsmapsplit.py
... ... @@ -46,7 +46,7 @@ class cstsmapsplit(ctools.cscript):
46 46  
47 47 # Set name and version
48 48 self._name = 'cstsmapsplit'
49   - self._version = '1.1.0'
  49 + self._version = '1.2.0'
50 50  
51 51 # Set data members
52 52 self._outmap = gammalib.GFilename()
... ... @@ -99,8 +99,7 @@ class cstsmapsplit(ctools.cscript):
99 99  
100 100 # Return
101 101 return
102   -
103   -
  102 +
104 103 def _compute_null_hypothesis(self):
105 104 """
106 105 Compute null hypothesis
... ... @@ -136,11 +135,11 @@ class cstsmapsplit(ctools.cscript):
136 135 return -(opt.value())
137 136  
138 137  
  138 + # Public methods
139 139 def run(self):
140 140 """
141 141 Run the script
142 142 """
143   -
144 143 # Switch screen logging on in debug mode
145 144 if self._logDebug():
146 145 self._log.cout(True)
... ... @@ -172,13 +171,9 @@ class cstsmapsplit(ctools.cscript):
172 171  
173 172 # Write likelihood into logger
174 173 if self._logTerse():
175   - self._log(gammalib.parformat('Source removed'))
176   - self._log(self._srcname)
177   - self._log('\n')
178   - self._log(gammalib.parformat('Log-likelihood'))
179   - self._log(repr(logL0))
180   - self._log('\n')
181   -
  174 + self._log_value('Source removed', self._srcname)
  175 + self._log_value('Log-likelihood', repr(logL0))
  176 +
182 177 # Get parameters of TS map ctool
183 178 pars = gammalib.GApplicationPars('cttsmap.par')
184 179  
... ... @@ -196,9 +191,7 @@ class cstsmapsplit(ctools.cscript):
196 191 if self._logTerse():
197 192 self._log('\n')
198 193 self._log.header1('Create commands')
199   - self._log(gammalib.parformat('Number of cttsmap calls'))
200   - self._log(str(njobs))
201   - self._log('\n')
  194 + self._log_value('Number of cttsmap calls', njobs)
202 195  
203 196 # Loop over TS map parameters
204 197 for par in pars:
... ... @@ -262,12 +255,10 @@ class cstsmapsplit(ctools.cscript):
262 255 # Return
263 256 return
264 257  
265   -
266 258 def execute(self):
267 259 """
268 260 Execute the script
269 261 """
270   -
271 262 # Run the script
272 263 self.run()
273 264  
... ... @@ -277,12 +268,10 @@ class cstsmapsplit(ctools.cscript):
277 268 # Return
278 269 return
279 270  
280   -
281 271 def save(self):
282 272 """
283 273 Save commands to ASCII file
284 274 """
285   -
286 275 # Open file
287 276 f = open(self._outfile.url(), 'w')
288 277  
... ...
cscripts/csworkflow.py
... ... @@ -53,7 +53,7 @@ class csworkflow(ctools.cscript):
53 53 """
54 54 # Set name and version
55 55 self._name = 'csworkflow'
56   - self._version = '1.0.0'
  56 + self._version = '1.2.0'
57 57  
58 58 # Set members
59 59 self._workflow = gammalib.GXml()
... ... @@ -168,12 +168,9 @@ class csworkflow(ctools.cscript):
168 168  
169 169 # Log information about actors
170 170 if self._logNormal():
171   - self._log.parformat('Actor "'+name+'"')
172   - self._log(tool)
173   - self._log('\n')
  171 + self._log_value('Actor "%s"' % name, tool)
174 172 if num_inputs == 0:
175   - self._log.parformat(' Predecessor')
176   - self._log('none\n')
  173 + self._log_value(' Predecessor', 'none')
177 174 else:
178 175 if num_inputs == 1:
179 176 self._log.parformat(' Predecessor')
... ... @@ -203,16 +200,15 @@ class csworkflow(ctools.cscript):
203 200  
204 201 # Log execution start
205 202 if self._logNormal():
206   - self._log.parformat('Execute actor')
207   - self._log('"'+actor['name']+'"\n')
  203 + self._log_value('Execute actor', '"%s"' % actor['name'])
208 204  
209 205 # Execute actor
210 206 self._execute_actor(actor)
211 207  
212 208 # Log execution finish
213 209 if self._logNormal():
214   - self._log.parformat('Finished actor execution')
215   - self._log('"'+actor['name']+'"\n')
  210 + self._log_value('Finished actor execution',
  211 + '"%s"' % actor['name'])
216 212  
217 213 # Set actor status to finished
218 214 actor['status'] = 'finished'
... ... @@ -247,21 +243,15 @@ class csworkflow(ctools.cscript):
247 243 if self._logNormal():
248 244 pars = actor['input_parameters']
249 245 for par in pars:
250   - self._log.parformat(' Input parameter')
251   - self._log(par['name'])
252   - self._log('=')
253   - self._log(self._get_parameter_value(par))
254   - self._log('\n')
  246 + self._log_value(' Input parameter', '%s=%s' %
  247 + (par['name'], self._get_parameter_value(par)))
255 248  
256 249 # Log output parameters
257 250 if self._logNormal():
258 251 pars = actor['output_parameters']
259 252 for par in pars:
260   - self._log.parformat(' Output parameter')
261   - self._log(par['name'])
262   - self._log('=')
263   - self._log(self._get_parameter_value(par))
264   - self._log('\n')
  253 + self._log_value(' Output parameter', '%s=%s' %
  254 + (par['name'], self._get_parameter_value(par)))
265 255  
266 256 # Set actor tool
267 257 if 'tool' in actor:
... ... @@ -342,7 +332,7 @@ class csworkflow(ctools.cscript):
342 332 # Public methods
343 333 def run(self):
344 334 """
345   - Run the script.
  335 + Run the script
346 336 """
347 337 # Switch screen logging on in debug mode
348 338 if self._logDebug():
... ... @@ -368,7 +358,7 @@ class csworkflow(ctools.cscript):
368 358  
369 359 def execute(self):
370 360 """
371   - Execute the script.
  361 + Execute the script
372 362 """
373 363 # Open logfile
374 364 self.logFileOpen()
... ...
pyext/ctool.i
... ... @@ -183,17 +183,23 @@ def _set_input_obs(self, argv):
183 183 return (obs, argv)
184 184 cscript._set_input_obs = _set_input_obs
185 185  
186   -# Initialise application by calling the appropriate class constructor.
  186 +# Initialise application by calling the appropriate class constructor
187 187 def _init_cscript(self, argv):
188 188 if len(argv) == 0:
189 189 cscript.__init__(self, self._name, self._version)
190 190 elif len(argv) == 1:
191 191 cscript.__init__(self, self._name, self._version, *argv)
192 192 else:
193   - raise TypeError("Invalid number of arguments given.")
  193 + raise TypeError('Invalid number of arguments given.')
194 194 # Set logger properties
195 195 self._log_header()
196 196 self._log.date(True)
197 197 cscript._init_cscript = _init_cscript
198 198  
  199 +# Log the value of a parameter
  200 +def _log_value(self, name, value):
  201 + self._log.parformat(name)
  202 + self._log(str(value))
  203 + self._log('\n')
  204 +cscript._log_value = _log_value
199 205 %}
... ...
test/test_csmodelinfo.py
... ... @@ -74,7 +74,7 @@ class Test(test):
74 74  
75 75 # Setup csmodelinfo command
76 76 cmd = csmodelinfo+' inmodel="'+self._models_spec+'"'+ \
77   - ' ds9file="model_cmd1.reg"'+ \
  77 + ' ds9file="csmodelinfo_cmd1.reg"'+ \
78 78 ' logfile="csmodelinfo_cmd1.log" chatter=1'
79 79  
80 80 # Check if execution of wrong command fails
... ... @@ -86,11 +86,11 @@ class Test(test):
86 86 'Check successful execution from command line')
87 87  
88 88 # Check region file
89   - self._check_ds9_file('model_cmd1.reg')
  89 + self._check_ds9_file('csmodelinfo_cmd1.reg')
90 90  
91 91 # Setup csmodelinfo command
92 92 cmd = csmodelinfo+' inmodel="model_that_does_not_exist.xml"'+ \
93   - ' ds9file="model_cmd2.reg"'+ \
  93 + ' ds9file="csmodelinfo_cmd2.reg"'+ \
94 94 ' logfile="csmodelinfo_cmd2.log"'
95 95  
96 96 # Check if execution failed
... ...