diff --git a/cscripts/csfindobs.py b/cscripts/csfindobs.py index 966233f..d11d4a5 100755 --- a/cscripts/csfindobs.py +++ b/cscripts/csfindobs.py @@ -225,15 +225,12 @@ class csfindobs(ctools.cscript): # Write the number of observations into the logger if self._logTerse(): - self._log(gammalib.parformat('Observations')) - self._log(len(self._runs)) - self._log('\n') + self._log_value('Observations', len(self._runs)) # Write the observation identifiers into the logger if self._logNormal() and len(self._runs) > 0: for i, run in enumerate(self._runs): - self._log(gammalib.parformat('Observation %d' % (i+1))) - self._log(str(run)+'\n') + self._log_value('Observation %d' % (i+1), run) # Close FITS file fits.close() diff --git a/cscripts/csiactcopy.py b/cscripts/csiactcopy.py index b763d93..8abf1ce 100755 --- a/cscripts/csiactcopy.py +++ b/cscripts/csiactcopy.py @@ -101,20 +101,12 @@ class csiactcopy(ctools.cscript): # Logging if self._logVerbose(): - self._log('\n') - self._log.header3('Copy file') - self._log.parformat('Source') - self._log(str(source)) - self._log('\n') - self._log.parformat('Destination') - self._log(str(destination)) - self._log('\n') - self._log.parformat('Already exists') - self._log(str(os.path.isfile(destination))) - self._log('\n') - self._log.parformat('Overwrite') - self._log(str(clobber)) self._log('\n') + self._log.header3('Copy file') + self._log_value('Source', source) + self._log_value('Destination', destination) + self._log_value('Already exists', str(os.path.isfile(destination))) + self._log_value('Overwrite', clobber) self._log.parformat('Copying') # Flag if file destination is already available @@ -158,24 +150,17 @@ class csiactcopy(ctools.cscript): If the local fits file is not present, a new one is created. """ - + # ... if self._logTerse(): - self._log.parformat('Local file') - self._log(str(localfits)) - self._log('\n') - self._log.parformat('Remote file') - self._log(str(remotefits)) - self._log('\n') - self._log.parformat('HDU name') - self._log(str(hduname)) - self._log('\n') - self._log.parformat('Conflict preference') + self._log_value('Local file', localfits) + self._log_value('Remote file', remotefits) + self._log_value('HDU name', hduname) if clobber: - self._log('Remote') + preference = 'Remote' else: - self._log('Local') - self._log('\n') - + preference = 'Local' + self._log_value('Conflict preference', preference) + # Check if local fits file is available if os.path.isfile(localfits): local = gammalib.GFits(str(localfits)) @@ -244,15 +229,12 @@ class csiactcopy(ctools.cscript): robs_col = remote_hdu['OBS_ID'] for obs_id in robs_col: remote_obs.append(obs_id) - + + # Dump the number of remote and local entries if self._logTerse(): - self._log.parformat('Remote entries') - self._log(str(len(remote_obs))) - self._log('\n') - self._log.parformat('Local entries') - self._log(str(len(local_obs))) - self._log('\n') - + self._log_value('Remote entries', len(remote_obs)) + self._log_value('Local entries', len(local_obs)) + # initialise counter for logging removed_rows = 0 @@ -306,16 +288,16 @@ class csiactcopy(ctools.cscript): # Store number of local rows old_local_rows = local_hdu.nrows() - # Add rmeote HDUs + # Add remote HDUs local_hdu.insert_rows(old_local_rows, remote_hdu.nrows()) - + + # Dump ... if self._logTerse(): if clobber: - self._log.parformat('Removed local rows') + what = 'Removed local rows' else: - self._log.parformat('Skipped remote rows') - self._log(str(removed_rows)) - self._log('\n') + what = 'Skipped remote rows' + self._log_value(what, removed_rows) # Loop over columns for i in range(local_hdu.ncols()): @@ -338,7 +320,7 @@ class csiactcopy(ctools.cscript): # Public methods def run(self): """ - Run the script. + Run the script """ # Switch screen logging on in debug mode if self._logDebug(): @@ -373,9 +355,7 @@ class csiactcopy(ctools.cscript): # Logging if self._logTerse(): - self._log.parformat('Number of observations') - self._log(str(len(self._runs))) - self._log('\n') + self._log_value('Number of observations', len(self._runs)) # Copy all data if runlist file is 'NONE' elif self._runlist == 'NONE': @@ -438,13 +418,9 @@ class csiactcopy(ctools.cscript): # Log information if self._logTerse(): self._log.header3('Remote config "'+self._prodname+'"') - self._log.parformat('HDU index') - self._log(str(remote_hdu)) - self._log('\n') - self._log.parformat('Observation index') - self._log(str(remote_obs)) - self._log('\n') - + self._log_value('HDU index', remote_hdu) + self._log_value('Observation index', remote_obs) + # Open remote HDU index file fits = gammalib.GFits(str(remote_hdu)) table = fits['HDU_INDEX'] @@ -519,19 +495,16 @@ class csiactcopy(ctools.cscript): if self._logTerse(): self._log('\n') self._log.header2('File information') - self._log.parformat('Number of files') - self._log(str(len(files))) - self._log('\n') + self._log_value('Number of files', len(files)) if has_size: - self._log.parformat('Size') - self._log('%.2f'%(float(cp_size)*1e-6)+' MB') - self._log('\n') + size = float(cp_size) * 1.0e-6 + self._log_value('Size', '%.2f MB' % size) if self._logVerbose(): self._log('\n') self._log.header3('File names') for filename in files: self._log(str(filename)+'\n') - + # Close HDU index file fits.close() @@ -569,7 +542,7 @@ class csiactcopy(ctools.cscript): if self._logExplicit(): fraction_increment = 2.0 - # initialise logging properties + # Initialise logging properties n_copied = 0 total_size = 0.0 @@ -580,14 +553,14 @@ class csiactcopy(ctools.cscript): fraction = float(k) / float(len(files)) * 100.0 while fraction > last_fraction: if self._logNormal() and not self._logVerbose(): - self._log.parformat('Status') - self._log(str(int(last_fraction))+'%') - self._log('\n') + self._log_value('Status', '%d %%' % int(last_fraction)) last_fraction += fraction_increment # Copy file filesize = self._copy(filename, self._clobber()) - + + # If the filesize is positive then increment the number of copied + # files and add the size to the total copied filesize if filesize > 0.0: total_size += filesize n_copied += 1 @@ -708,31 +681,23 @@ class csiactcopy(ctools.cscript): if self._logNormal(): self._log('\n') self._log.header1('Summary') - self._log.parformat('Data files found') - self._log(str(len(files))) - self._log('\n') - self._log.parformat('Data files copied') - self._log(str(n_copied)) - self._log('\n') - self._log.parformat('Size') - self._log('%.2f'%(float(total_size)*1e-6)+' MB') - self._log('\n') - self._log.parformat('Local configs') - self._log(str(len(newconfigs))) - self._log('\n') + self._log_value('Data files found', len(files)) + self._log_value('Data files copied', n_copied) + self._log_value('Size', '%.2f MB' % (float(total_size)*1.0e-6)) + self._log_value('Local configs', len(newconfigs)) if self._logTerse(): self._log('\n') self._log.header3('Content of master index') for config in newconfigs: self._log(str(config['name'])) self._log('\n') - + # Return return def execute(self): """ - Execute the script. + Execute the script """ # Open logfile self.logFileOpen() diff --git a/cscripts/csiactdata.py b/cscripts/csiactdata.py index 266ca6e..61c6fa3 100755 --- a/cscripts/csiactdata.py +++ b/cscripts/csiactdata.py @@ -96,26 +96,20 @@ class csiactdata(ctools.cscript): """ Log configuration """ - # Log information + # Log only if the level is at least "Terse" if self._logTerse(): + + # Log configuration information self._log.header3(str(config['name'])) - self._log.parformat('Name') - self._log(str(config['name'])) - self._log('\n') - self._log.parformat('Observation index') - self._log(str(config['obsindx'])) - self._log('\n') - self._log.parformat('HDU index') - self._log(str(config['hduindx'])) - self._log('\n') - + self._log_value('Name', config['name']) + self._log_value('Observation index', config['obsindx']) + self._log_value('HDU index', config['hduindx']) + # Print additional information for key in config: if key in ['name','hduindx','obsindx']: continue - self._log.parformat(str(key)) - self._log(str(config[key])) - self._log('\n') + self._log_value(key, config[key]) # Return return diff --git a/cscripts/csinfo.py b/cscripts/csinfo.py index f9a51f5..ff73255 100755 --- a/cscripts/csinfo.py +++ b/cscripts/csinfo.py @@ -21,8 +21,9 @@ import sys import os -# Copied and edited a bit from the `doc/source/users/reference_manual/index.rst` -# file. The list there and here needs to be manually updated and kept in sync. +# List of available ctools. The list was copied from +# `doc/source/users/reference_manual/index.rst` +# and needs to be manually updated and kept in sync CTOOL_LIST = """ ctbin Generates counts cube ctbkgcube Generates background cube @@ -41,6 +42,10 @@ CTOOL_LIST = """ cttsmap Generates Test Statistics map ctulimit Calculates upper limit """ + +# List of available cscripts. The list was copied from +# `doc/source/users/reference_manual/index.rst` +# and needs to be manually updated and kept in sync CSCRIPT_LIST = """ cscaldb Lists available instrument response functions cslightcrv Computes lightcurve @@ -57,6 +62,7 @@ CSCRIPT_LIST = """ cstsmapsplit Creates commands to split the Test Statistic map computations cstsmapmerge Merges slices from Test Statistic map computations\n csobs2caldb Creates a caldb entry from an input observation + csroot2caldb Creates a caldb entry from a ROOT performance file csiactdata Shows information about IACT data available on the user machine csiactobs Generates observation definition file for IACT data from observation IDs csfindobs Generates a list of IACT observation IDs @@ -92,23 +98,6 @@ def get_command_output(cmd): return getoutput(cmd) -# ===================================== # -# Workaround for print without linefeed # -# ===================================== # -def log(text, end='\n'): - """ - Print text to console - - Workaround to have an `end=''` option on old Pythons: - http://stackoverflow.com/a/493399/498873 - """ - # Print without linefeed - sys.stdout.write(text + end) - - # Return - return - - # ====================== # # Print list information # # ====================== # @@ -135,66 +124,61 @@ def csinfo_setup_check(): """ Print check information """ - # Initialise success flags - all_ok = True - gammalib_environ = False - ctools_environ = False - gammalib_python = False - ctools_python = False - cscripts_python = False - # Print header print('\nGammalib / ctools setup check:\n') - # Check if GAMMALIB is set - log(' GAMMALIB environment variable ... ', end='') - try: - gammalib_env = os.environ['GAMMALIB'] + # Check if the "GAMMALIB" environment variable is set + sys.stdout.write(' GAMMALIB environment variable ... ') + if 'GAMMALIB' in os.environ: print('ok') - except KeyError: - print('NOT OK') - all_ok = False gammalib_environ = True + else: + print('NOT OK') + gammalib_environ = False - # Check if CTOOLS is set - log(' CTOOLS environment variable ... ', end='') - try: - ctools_env = os.environ['CTOOLS'] + # Check if the "CTOOLS" environment variable is set + sys.stdout.write(' CTOOLS environment variable ... ') + if 'CTOOLS' in os.environ: print('ok') - except KeyError: - print('NOT_OK') - all_ok = False ctools_environ = True + else: + print('NOT OK') + ctools_environ = False + # Check if gammalib Python module import works - log(' gammalib Python import .......... ', end='') + sys.stdout.write(' gammalib Python import .......... ') try: import gammalib print('ok') + gammalib_python = True except: print('NOT OK') - all_ok = False - gammalib_python = True + gammalib_python = False # Check if ctools Python module import works - log(' ctools Python import .......... ', end='') + sys.stdout.write(' ctools Python import .......... ') try: import ctools print('ok') + ctools_python = True except: print('NOT OK') - all_ok = False - ctools_python = True + ctools_python = False # Check if cscripts Python module import works - log(' cscripts Python import .......... ', end='') + sys.stdout.write(' cscripts Python import .......... ') try: import cscripts print('ok') + cscripts_python = True except: print('NOT OK') - all_ok = False - cscripts_python = True + cscripts_python = False + + # Set flag that everything is okay + all_ok = gammalib_environ and ctools_environ and gammalib_python and \ + ctools_python and cscripts_python # Signal if everything is okay, or notify about the problems that have # been encountered @@ -202,11 +186,11 @@ def csinfo_setup_check(): print('\n ===> Your Gammalib / ctools setup is OK.') else: print('\n ===> WARNING: Your Gammalib / ctools setup is NOT OK!\n') - if gammalib_environ: + if not gammalib_environ: print(' - Have you set the GAMMALIB environment variable?') - if ctools_environ: + if not ctools_environ: print(' - Have you set the CTOOLS environment variable?') - if gammalib_python or ctools_python or cscripts_python: + if not gammalib_python or not ctools_python or not cscripts_python: print(' - Did you source gammalib-init.sh?') print(' - Did you source ctools-init.sh ?') print(' - Are you using the correct Python ?') @@ -257,10 +241,8 @@ def csinfo_setup_info(): gammalib_env = os.environ.get('GAMMALIB', 'Not found') ctools_env = os.environ.get('CTOOLS', 'Not found') - # Print header + # Print setup information print('\nGammalib / ctools setup info:\n') - - # Print package versions print(' Gammalib version ................ %s' % gammalib_version) print(' ctools version ................ %s' % ctools_version) print(' cscripts version ................ %s' % cscripts_version) @@ -306,7 +288,7 @@ def get_pkg_config_info(info, library): out = get_command_output(cmd) # If the command returns 'was not found' then pkg-config is not - # avaailable + # available if 'not found' in out: out = 'Not available' @@ -340,8 +322,8 @@ def csinfo(argv): """ Print information about Gammalib and ctools to the console """ - # If there are no command line arguments then print help and exit - # with success + # If there are no command line arguments then print help and exit with + # success if len(argv) <= 1: csinfo_print_help() sys.exit(0) diff --git a/cscripts/cslightcrv.py b/cscripts/cslightcrv.py index 54cdf5d..f2e56d1 100755 --- a/cscripts/cslightcrv.py +++ b/cscripts/cslightcrv.py @@ -21,6 +21,7 @@ import sys import gammalib import ctools +from cscripts import obsutils # ================ # @@ -82,10 +83,6 @@ class cslightcrv(ctools.cscript): # Initialise script by calling the appropriate class constructor. self._init_cscript(argv) - # Set logger properties - self._log_header() - self._log.date(True) - # Return return @@ -162,20 +159,26 @@ class cslightcrv(ctools.cscript): # Initialise Good Time Intervals gti = gammalib.GGti() - # Get algorithm to use for defining the time intervals + # Get algorithm to use for defining the time intervals. Possible + # values are "FILE", "LIN" and "GTI". This is enforced at + # parameter file level, hence no checking is needed. algorithm = self['tbinalg'].string() - # Handle a FITS or a ASCII file for time bin definition + # If the algorithm is "FILE" then handle a FITS or an ASCII file for + # the time bin definition if algorithm == 'FILE': # Get the filename filename = self['tbinfile'].filename() - # If the file a FITS file then load GTIs + # If the file a FITS file then load GTIs directly if filename.is_fits(): gti.load(filename) - # ... otherwise load file as CSV ASCII file + # ... otherwise load file the ASCII file as CSV file and construct + # the GTIs from the rows of the CSV file. It is expected that the + # CSV file has two columns containing the "START" and "STOP" + # values of the time bins. No header row is expected. csv = gammalib.GCsv(filename) for i in range(csv.nrows()): tmin = gammalib.GTime() @@ -184,7 +187,8 @@ class cslightcrv(ctools.cscript): tmax.mjd(csv.real(i,1)) gti.append(tmin,tmax) - # Handle linear time binning + # If the algorithm is "LIN" then use a linear time binning, defined by + # the "tmin", "tmax" and "tbins" user parameters elif algorithm == 'LIN': # Get start and stop time and number of time bins @@ -192,7 +196,7 @@ class cslightcrv(ctools.cscript): time_max = self['tmax'].real() nbins = self['tbins'].integer() - # Compute time step and setup time intervals + # Compute time step and setup the GTIs time_step = (time_max - time_min) / float(nbins) for i in range(nbins): tmin = gammalib.GTime() @@ -201,7 +205,8 @@ class cslightcrv(ctools.cscript): tmax.mjd(time_min + (i+1)*time_step) gti.append(tmin,tmax) - # Handle usage of observation GTIs + # If the algorithm is "GTI" then extract the GTIs from the observations + # in the container and use them for the light curve time binning elif algorithm == 'GTI': # Append the GTIs of all observations @@ -210,11 +215,6 @@ class cslightcrv(ctools.cscript): gti.append(obs.events().gti().tstart(i), obs.events().gti().tstop(i)) - # ... otherwise raise an exception (this should never occur) - else: - raise AttributeError('Paramter tbinalg="'+algorithm+'" unknown. ' - 'Must be one of "FILE", "LIN" or "GTI".') - # Return Good Time Intervals return gti @@ -227,7 +227,7 @@ class cslightcrv(ctools.cscript): names : list of str List of free parameter names. """ - # Initialise list of free parameter names + # Initialise empty list of free parameter names names = [] # Collect list of free parameter names @@ -304,7 +304,7 @@ class cslightcrv(ctools.cscript): table = gammalib.GFitsBinTable(nrows) table.extname('LIGHTCURVE') - # Append time columns + # Append time columns "MJD" and "e_MJD" mjd = gammalib.GFitsTableDoubleCol('MJD', nrows) e_mjd = gammalib.GFitsTableDoubleCol('e_MJD', nrows) mjd.unit('days') @@ -330,13 +330,13 @@ class cslightcrv(ctools.cscript): table.append(col) table.append(e_col) - # Append Test Statistic column + # Append Test Statistic column "TS" ts = gammalib.GFitsTableDoubleCol('TS', nrows) for i, result in enumerate(results): ts[i] = result['ts'] table.append(ts) - # Append upper limit column + # Append upper limit column "UpperLimit" ulimit = gammalib.GFitsTableDoubleCol('UpperLimit', nrows) ulimit.unit('ph/cm2/s') for i, result in enumerate(results): @@ -375,7 +375,7 @@ class cslightcrv(ctools.cscript): ulimit['srcname'] = self._srcname ulimit['eref'] = 1.0 - # Try to run upper limit and catch exceptions + # Try to run upper limit and catch any exceptions try: ulimit.run() ulimit_value = ulimit.flux_ulimit() @@ -423,111 +423,36 @@ class cslightcrv(ctools.cscript): # Header if self._logExplicit(): - self._log.header3('Creating exposure cube') - - # Create exposure cube - expcube = ctools.ctexpcube(obs) - expcube['incube'] = 'NONE' - expcube['usepnt'] = False - expcube['ebinalg'] = 'LOG' - expcube['xref'] = self['xref'].real() - expcube['yref'] = self['yref'].real() - expcube['binsz'] = self['binsz'].real() - expcube['nxpix'] = self['nxpix'].integer() - expcube['nypix'] = self['nypix'].integer() - expcube['enumbins'] = self['enumbins'].integer() - expcube['emin'] = self['emin'].real() - expcube['emax'] = self['emax'].real() - expcube['coordsys'] = self['coordsys'].string() - expcube['proj'] = self['proj'].string() - expcube.run() - - # Header - if self._logExplicit(): - self._log.header3('Creating point spread function cube') - - # Compute spatial binning for point spread function and - # energy dispersion cubes - binsz = 10.0 * self['binsz'].real() - nxpix = min(self['nxpix'].integer() // 10, 2) # Make sure result is int - nypix = min(self['nypix'].integer() // 10, 2) # Make sure result is int - - # Create point spread function cube - psfcube = ctools.ctpsfcube(obs) - psfcube['incube'] = 'NONE' - psfcube['usepnt'] = False - psfcube['ebinalg'] = 'LOG' - psfcube['xref'] = self['xref'].real() - psfcube['yref'] = self['yref'].real() - psfcube['binsz'] = binsz - psfcube['nxpix'] = nxpix - psfcube['nypix'] = nypix - psfcube['enumbins'] = self['enumbins'].integer() - psfcube['emin'] = self['emin'].real() - psfcube['emax'] = self['emax'].real() - psfcube['coordsys'] = self['coordsys'].string() - psfcube['proj'] = self['proj'].string() - psfcube.run() - - # Check if we need to include energy dispersion - if self['edisp'].boolean(): - - # Header - if self._logExplicit(): - self._log.header3('Creating energy dispersion cube') - - # Create energy dispersion cube - edispcube = ctools.ctedispcube(obs) - edispcube['incube'] = 'NONE' - edispcube['usepnt'] = False - edispcube['ebinalg'] = 'LOG' - edispcube['xref'] = self['xref'].real() - edispcube['yref'] = self['yref'].real() - edispcube['binsz'] = binsz - edispcube['nxpix'] = nxpix - edispcube['nypix'] = nypix - edispcube['enumbins'] = self['enumbins'].integer() - edispcube['emin'] = self['emin'].real() - edispcube['emax'] = self['emax'].real() - edispcube['coordsys'] = self['coordsys'].string() - edispcube['proj'] = self['proj'].string() - edispcube.run() - - # Header - if self._logExplicit(): - self._log.header3('Creating background cube') - - # Create background cube - bkgcube = ctools.ctbkgcube(obs) - bkgcube['incube'] = 'NONE' - bkgcube['usepnt'] = False - bkgcube['ebinalg'] = 'LOG' - bkgcube['xref'] = self['xref'].real() - bkgcube['yref'] = self['yref'].real() - bkgcube['binsz'] = self['binsz'].real() - bkgcube['nxpix'] = self['nxpix'].integer() - bkgcube['nypix'] = self['nypix'].integer() - bkgcube['enumbins'] = self['enumbins'].integer() - bkgcube['emin'] = self['emin'].real() - bkgcube['emax'] = self['emax'].real() - bkgcube['coordsys'] = self['coordsys'].string() - bkgcube['proj'] = self['proj'].string() - bkgcube.run() + self._log.header3('Creating stacked response') + + # Get stacked response + response = obsutils.get_stacked_response(obs, + self['xref'].real(), + self['yref'].real(), + binsz=self['binsz'].real(), + nxpix=self['nxpix'].integer(), + nypix=self['nypix'].integer(), + emin=self['emin'].real(), + emax=self['emax'].real(), + enumbins=self['enumbins'].integer(), + edisp=self['edisp'].boolean(), + coordsys=self['coordsys'].string(), + proj=self['proj'].string()) # Retrieve a new oberservation container new_obs = cntcube.obs().copy() - # Get new models - models = bkgcube.models() - # Set stacked response if self['edisp'].boolean(): - new_obs[0].response(expcube.expcube(), psfcube.psfcube(), - edispcube.edispcube(), bkgcube.bkgcube()) + new_obs[0].response(response['expcube'], response['psfcube'], + response['edispcube'], response['bkgcube']) else: - new_obs[0].response(expcube.expcube(), psfcube.psfcube(), - bkgcube.bkgcube()) + new_obs[0].response(response['expcube'], response['psfcube'], + response['bkgcube']) + # Get new models + models = response['models'] + # Fix background models if required if self['fix_bkg'].boolean(): for model in models: @@ -636,8 +561,8 @@ class cslightcrv(ctools.cscript): # Signal skipping of bin if self._logTerse(): - self._log(gammalib.parformat('Warning')) - self._log('No event in this time bin, skip bin.\n') + self._log_value('Warning', 'No event in this time bin, ' + 'skip bin.') # Set all results to 0 for par in pars: @@ -678,19 +603,12 @@ class cslightcrv(ctools.cscript): value = source.spectral()[par].value() error = source.spectral()[par].error() unit = source.spectral()[par].unit() - self._log(gammalib.parformat(par)) - self._log(str(value)) - self._log(' +/- ') - self._log(str(error)) - self._log(' ') - self._log(unit) - self._log('\n') + self._log_value(par, str(value)+' +/- '+str(error)+' '+unit) if result['ulimit'] > 0.0: - self._log(gammalib.parformat('Upper flux limit')) - self._log(str(result['ulimit'])+' ph/cm2/s\n') + self._log_value('Upper flux limit', str(result['ulimit'])+ + ' ph/cm2/s') if self['calc_ts'].boolean(): - self._log(gammalib.parformat('Test Statistic')) - self._log(str(result['ts'])+'\n') + self._log_value('Test Statistic', result['ts']) # Create FITS table from results table = self._create_fits_table(results) @@ -738,9 +656,7 @@ class cslightcrv(ctools.cscript): # Log file name if self._logTerse(): - self._log(gammalib.parformat('Light curve file')) - self._log(outfile.url()) - self._log('\n') + self._log_value('Light curve file', outfile.url()) # Save spectrum self._fits.saveto(outfile, self._clobber()) @@ -750,7 +666,7 @@ class cslightcrv(ctools.cscript): def lightcurve(self): """ - Return light curve FITS file. + Return light curve FITS file Returns ------- diff --git a/cscripts/csmodelinfo.py b/cscripts/csmodelinfo.py index fd913fa..6becbf6 100755 --- a/cscripts/csmodelinfo.py +++ b/cscripts/csmodelinfo.py @@ -28,7 +28,7 @@ import ctools # ================= # class csmodelinfo(ctools.cscript): """ - Shows the content of a model container. + Shows the content of a model container The script is useful to show, e.g., the number of sources in a model container, the background models, free and fixed parameters etc. @@ -39,29 +39,16 @@ class csmodelinfo(ctools.cscript): # Constructor def __init__(self, *argv): """ - Constructor. + Constructor """ # Set name - self._name = "csmodelinfo" - self._version = "1.1.0" + self._name = 'csmodelinfo' + self._version = '1.2.0' # Initialise class members - self._models = gammalib.GModels() - self._ds9file = gammalib.GFilename("NONE") - self._pnt_type = "" - self._pnt_mark_size = 12 - self._show_labels = True - self._width = 2 - self._fontfamily = "helvetica" - self._fontsize = 12 - self._fontweight = "normal" - self._fontslant = "roman" - self._show_ext_type = True - self._free_color = "green" - self._fixed_color = "magenta" - - # Initialise application by calling the appropriate class - # constructor. + self._models = gammalib.GModels() + + # Initialise application by calling the appropriate class constructor self._init_cscript(argv) # Return @@ -71,57 +58,83 @@ class csmodelinfo(ctools.cscript): # Private methods def _get_parameters(self): """ - Get parameters from parfile and setup the observation. + Get parameters from parfile and setup the observation """ # Get models - self._models = gammalib.GModels(self["inmodel"].filename()) + self._models = gammalib.GModels(self['inmodel'].filename()) - # Get hidden parameters for region file - self._pnt_type = self["pnt_type"].string() - self._pnt_mark_size = self["pnt_mark_size"].integer() - self._show_labels = self["show_labels"].boolean() - self._width = self["width"].integer() - self._fontfamily = self["fontfamily"].string() - self._fontsize = self["fontsize"].integer() - self._fontweight = self["fontweight"].string() - self._fontslant = self["fontslant"].string() - self._show_ext_type = self["show_ext_type"].boolean() - self._free_color = self["free_color"].string() - self._fixed_color = self["fixed_color"].string() - - # Read ahead DS9 filename + # Query hidden parameters for region file + self['pnt_type'].string() + self['pnt_mark_size'].integer() + self['show_labels'].boolean() + self['width'].integer() + self['fontfamily'].string() + self['fontsize'].integer() + self['fontweight'].string() + self['fontslant'].string() + self['show_ext_type'].boolean() + self['free_color'].string() + self['fixed_color'].string() + + # Query ahead DS9 filename if self._read_ahead(): - self._ds9file = self["ds9file"].filename() + self["ds9file"].filename() # Write input parameters into logger if self._logTerse(): self._log_parameters() - self._log("\n") + self._log('\n') # Return return + def _ds9attributes(self, model): + """ + Returns attributes for DS9 string + Parameters + ---------- + model : `~gammalib.GModel` + Model + + Returns + ------- + attributes : str + DS9 attribute string + """ + # Determine region color. A model where all parameters are fixed will + # get the color defined by "fixed_color", a model with at least one + # free parameter will get the color defined by "free_color". + color = self['fixed_color'].string() + for par in model: + if par.is_free(): + color = self['free_color'].string() + break + + # Set DS9 attributes + attributes = (' color=%s width=%d font=%s %d %s %s' % + (color, self['width'].integer(), + self['fontfamily'].string(), self['fontsize'].integer(), + self['fontweight'].string(), self['fontslant'].string())) + + # Return attributes + return attributes + def _model2ds9string(self, model): """ - Converts model into a DS9 region string. + Converts model into a DS9 region string - Args: - model: Model. + Parameters + ---------- + model : `~gammalib.GModel` + Model - Returns: - DS9 region string. + Returns + ------- + ds9string : str + DS9 region string """ # Initialise DS9 region string - ds9string = "" - - # Determine region color. The color will change between a model - # where all parameters are fixed and a model with at least one - # free parameter. - color = self._fixed_color - for par in model: - if par.is_free(): - color = self._free_color - break + ds9string = '' # Retrieve model sky direction. The model is skipped in case that # it does not provide a sky direction. @@ -129,8 +142,9 @@ class csmodelinfo(ctools.cscript): try: modelpos = model.spatial().dir() except AttributeError: - self._log("Skip source \""+model.name()+"\" since no " - "sky direction is associated with that model.\n") + msg = ('Skip model "%s" since it has no sky direction.\n' % + model.name()) + self._log(msg) is_valid = False # Continue only if sky direction was found @@ -141,16 +155,16 @@ class csmodelinfo(ctools.cscript): modelname = model.name() # Handle point source - if modeltype == "PointSource": + if modeltype == 'PointSource': - # Append point to DS9 string - ds9string += "point(" - ds9string += str(modelpos.ra_deg()) - ds9string += "," - ds9string += str(modelpos.dec_deg()) - ds9string += ") # " - ds9string += "point="+self._pnt_type+" " - ds9string += str(self._pnt_mark_size)+" " + # Append point with Right Ascension and Declination to the DS9 + # string. The type of the point is specified by the "pnt_type" + # parameter, the size of the point by the "pnt_mark_size" + # parameter + ds9string += ('point(%.6f,%.6f) # point=%s %d' % + (modelpos.ra_deg(), modelpos.dec_deg(), + self['pnt_type'].string(), + self['pnt_mark_size'].integer())) # Handle extended sources elif modeltype == "ExtendedSource": @@ -160,89 +174,74 @@ class csmodelinfo(ctools.cscript): classname = spatial.classname() # Handle radial sources - if "Radial" in classname: + if 'Radial' in classname: # Retrieve short name of model class (e.g. "Gauss" # or "Disk) - shorttype = classname.split("Radial")[-1] + shorttype = classname.split('Radial')[-1] # Handle Disk and Shell model - if (classname == "GModelSpatialRadialDisk" or - classname == "GModelSpatialRadialShell"): + if (classname == 'GModelSpatialRadialDisk' or + classname == 'GModelSpatialRadialShell'): size = spatial.radius() # Handle Gauss Model - elif classname == "GModelSpatialRadialGauss": + elif classname == 'GModelSpatialRadialGauss': size = spatial.sigma() # Skip if source is unknown else: - self._log("Skip source \""+model.name()+"\"" - " since the radial model \""+classname+ - "\" is unkown.\n") + msg = ('Skip model "%s" since the radial model "%s" ' + 'is unknown.\n' % (model.name(), classname)) + self._log(msg) is_valid = False # Append circle to DS9 string if is_valid: - ds9string += "circle(" - ds9string += str(modelpos.ra_deg()) - ds9string += "," - ds9string += str(modelpos.dec_deg()) - ds9string += "," - ds9string += str(size*3600.)+"\") # " - + ds9string += ('circle(%.6f,%.6f,%.6f) #' % + (modelpos.ra_deg(), modelpos.dec_deg(), + size*3600.0)) + # Handle elliptical sources - elif "Elliptical" in classname: + elif 'Elliptical' in classname: # Retrieve short name and source size - shorttype = classname.split("Elliptical")[-1] + shorttype = classname.split('Elliptical')[-1] size1 = spatial.semimajor() size2 = spatial.semiminor() angle = spatial.posangle() # Append ellipse to DS9 string - ds9string += "ellipse(" - ds9string += str(modelpos.ra_deg()) - ds9string += "," - ds9string += str(modelpos.dec_deg()) - ds9string += "," - ds9string += str(size1*3600.)+"\"" - ds9string += "," - ds9string += str(size2*3600.)+"\"" - ds9string += "," - ds9string += str(angle+90.0)+") # " + ds9string += ('ellipse(%.6f,%.6f,%.6f,%.6f,%.6f) #' % + (modelpos.ra_deg(), modelpos.dec_deg(), + size1*3600.0, size2*3600.0, angle+90.0)) # Skip if source is neither radial nor elliptical else: - self._log("Skip source \""+model.name()+"\" " - "since the model \""+classname+"\" is " - "neither a point source, a radial source, " - "nor a elliptical source.\n") + msg = ('Skip model "%s" since the model "%s" is neither ' + 'a point source, a radial source, nor an elliptical ' + 'source.\n' % (model.name(), classname)) + self._log(msg) is_valid = False # Add short model type to modelname - if self._show_ext_type: - modelname +=" ("+shorttype+")" + if self['show_ext_type'].boolean(): + modelname +=' ('+shorttype+')' # Add DS9 attributes if is_valid: - ds9string += "color="+color+" " - ds9string += "width="+str(self._width)+" " - ds9string += "font=\""+self._fontfamily+" " - ds9string += str(self._fontsize)+" " - ds9string += self._fontweight+" " - ds9string += self._fontslant+"\"" - if self._show_labels: - ds9string += " text={"+modelname+"}" + ds9string += self._ds9attributes(model) + if self['show_labels'].boolean(): + ds9string += ' text={'+modelname+'}' # Return string return ds9string - + # Public methods def run(self): """ - Run the script. + Run the script """ # Switch screen logging on in debug mode if self._logDebug(): @@ -253,11 +252,11 @@ class csmodelinfo(ctools.cscript): # Optionally log models if self._logVerbose(): - self._log("\n") - self._log.header1("Models") - self._log("\n") + self._log('\n') + self._log.header1('Models') + self._log('\n') self._log(str(self._models)) - self._log("\n") + self._log('\n') # Initialise output values types = {} @@ -295,7 +294,7 @@ class csmodelinfo(ctools.cscript): ts[model.name()] = model.ts() # Skymodel? - skymodel = (model.classname() == "GModelSky") + skymodel = (model.classname() == 'GModelSky') if skymodel: free_src_pars[model.name()] = [] @@ -340,140 +339,110 @@ class csmodelinfo(ctools.cscript): if self._logTerse(): # Log summary - self._log("\n") - self._log.header1("Summary") + self._log('\n') + self._log.header1('Summary') # Log instruments - self._log.header3("Instrument specific models") + self._log.header3('Instrument specific models') for inst, n_inst in instruments.items(): - if inst == "": - inst = "All" - self._log.parformat(inst) - self._log(str(n_inst)) - self._log("\n") + if inst == '': + inst = 'All' + self._log_value(inst, n_inst) # Log model types - self._log.header3("Model types") + self._log.header3('Model types') for modeltype, n_types in types.items(): - self._log.parformat(modeltype) - self._log(str(n_types)) - self._log("\n") + self._log_value(modeltype, n_types) # Log model parameter information - self._log("\n") - self._log.header1("Parameter information") - self._log.parformat("All parameters") - self._log(str(n_par_total)) - self._log("\n") - self._log.parformat("Fixed parameters") - self._log(str(n_par_fixed)) - self._log("\n") - self._log.parformat("Free parameters (total)") - self._log(str(n_par_free)) - self._log("\n") - self._log.parformat("Free background parameters") - self._log(str(n_par_free_bkg)) - self._log("\n") - self._log.parformat("Free source parameters") - self._log(str(n_par_free_src)) - self._log("\n") + self._log('\n') + self._log.header1('Parameter information') + self._log_value('All parameters', n_par_total) + self._log_value('Fixed parameters', n_par_fixed) + self._log_value('Free parameters (total)', n_par_free) + self._log_value('Free background parameters', n_par_free_bkg) + self._log_value('Free source parameters', n_par_free_src) if n_par_free_spec > 0: - self._log.parformat("Free spectral parameters") - self._log(str(n_par_free_spec)) - self._log("\n") + self._log_value('Free spectral parameters', n_par_free_spec) if n_par_free_spat > 0: - self._log.parformat("Free spatial parameters") - self._log(str(n_par_free_spat)) - self._log("\n") + self._log_value('Free spatial parameters', n_par_free_spat) if n_par_free_temp > 0: - self._log.parformat("Free temporal parameters") - self._log(str(n_par_free_temp)) - self._log("\n") - self._log.parformat("Parameters at limit") - self._log(str(n_par_at_limit)) - self._log("\n") + self._log_value('Free temporal parameters', n_par_free_temp) + self._log_value('Parameters at limit', n_par_at_limit) # Log parameters at limit (if any) if n_par_at_limit > 0: - self._log.header3("Parameters at limit") + self._log.header3('Parameters at limit') for source, parameter in pars_at_limit.items(): if len(parameter): for par in parameter: - self._log.parformat(source) - self._log(par) - self._log("\n") + self._log_value(source, par) # Optionally log free parameters if self._logExplicit() and len(free_src_pars): - self._log("\n") - self._log.header2("Free source parameters") + self._log('\n') + self._log.header2('Free source parameters') for source, parameter in free_src_pars.items(): if len(parameter): self._log.header3(source) for par in parameter: self._log(str(par)) - self._log("\n") - self._log("\n") + self._log('\n') + self._log('\n') # Log TS values if available if len(ts): - self._log.header3("Test statistics") - for source,tsvalue in ts.items(): - self._log.parformat(source) - self._log("%.2f"%tsvalue) - self._log("\n") + self._log.header3('Test statistics') + for source, tsvalue in ts.items(): + self._log_value(source, tsvalue) # Return return def save(self): """ - Save models to ds9 region file if required + Save models to ds9 region file """ - - # Get output filename in case it was not read ahead - self._ds9file = self["ds9file"].filename() + # Get output filename + ds9file = self['ds9file'].filename() # Check if DS9 file is valid - if self._ds9file != "NONE": + if ds9file != '' and ds9file != 'NONE': # Write header if self._logTerse(): - self._log("\n") - self._log.header1("Save models in DS9 file") + self._log('\n') + self._log.header1('Save models in DS9 file') # Log filename if self._logTerse(): - self._log(gammalib.parformat("DS9 filename")) - self._log(self._ds9file.url()) - self._log("\n") + self._log_value('DS9 filename', ds9file.url()) # Open file - f = open(self._ds9file.url(),"w") + f = open(ds9file.url(), 'w') # Write coordinate system - f.write("fk5\n") + f.write('fk5\n') # Loop over models for model in self._models: # Continue only if point source or extended source model - if (model.type() == "PointSource" or - model.type() == "ExtendedSource"): + if (model.type() == 'PointSource' or + model.type() == 'ExtendedSource'): line = self._model2ds9string(model) if len(line): - f.write(line+"\n") + f.write(line+'\n') # Logging for diffuse components - elif model.type() == "DiffuseSource": - self._log("Skipping diffuse model \""+model.name()+ - "\"\n") + elif model.type() == 'DiffuseSource': + self._log('Skipping diffuse model "'+model.name()+'".\n') # Logging for background components else: if self._logExplicit(): - self._log("Skipping background model \""+ - model.name()+"\"\n") + self._log('Skipping background model "'+model.name()+ + '".\n') # Close file f.close() @@ -483,7 +452,7 @@ class csmodelinfo(ctools.cscript): def execute(self): """ - Execute the script. + Execute the script """ # Open logfile self.logFileOpen() diff --git a/cscripts/csmodelmerge.py b/cscripts/csmodelmerge.py index 0e461dd..e345ee1 100755 --- a/cscripts/csmodelmerge.py +++ b/cscripts/csmodelmerge.py @@ -43,7 +43,7 @@ class csmodelmerge(ctools.cscript): """ # Set name self._name = 'csmodelmerge' - self._version = '1.1.0' + self._version = '1.2.0' # Initialise class members self._files = None @@ -146,23 +146,19 @@ class csmodelmerge(ctools.cscript): if self._logTerse(): nmodels = models.size() if nmodels == 0: - self._log(gammalib.parformat('Add no model from file')) + name = 'Add no model from file' elif nmodels == 1: - self._log(gammalib.parformat('Add 1 model from file')) + name = 'Add 1 model from file' else: - self._log(gammalib.parformat('Add %d models from file' % - nmodels)) - self._log(f) - self._log('\n') + name = 'Add %d models from file' % nmodels + self._log_value(name, f) # Extend model container by adding all models in the model file self._models.extend(models) # Log total number of models if self._logTerse(): - self._log(gammalib.parformat('Models after merging')) - self._log(self._models.size()) - self._log('\n') + self._log_value('Models after merging', self._models.size()) # Return return @@ -189,9 +185,7 @@ class csmodelmerge(ctools.cscript): # Log filename if self._logTerse(): - self._log(gammalib.parformat('Model definition XML file')) - self._log(outmodel.url()) - self._log('\n') + self._log_value('Model definition XML file', outmodel.url()) # Save models self._models.save(outmodel) diff --git a/cscripts/csobs2caldb.py b/cscripts/csobs2caldb.py index 0e25649..3405b4b 100755 --- a/cscripts/csobs2caldb.py +++ b/cscripts/csobs2caldb.py @@ -156,19 +156,11 @@ class csobs2caldb(ctools.cscript): # Log filenames if self._logNormal(): - self._log.header3("IRF input files") - self._log(gammalib.parformat("Effective area")) - self._log(fname_aeff.url()) - self._log("\n") - self._log(gammalib.parformat("Point spread function")) - self._log(fname_psf.url()) - self._log("\n") - self._log(gammalib.parformat("Energy dispersion")) - self._log(fname_edisp.url()) - self._log("\n") - self._log(gammalib.parformat("Background rate")) - self._log(fname_bkg.url()) - self._log("\n") + self._log.header3('IRF input files') + self._log_value('Effective area', fname_aeff.url()) + self._log_value('Point spread function', fname_psf.url()) + self._log_value('Energy dispersion', fname_edisp.url()) + self._log_value('Background rate', fname_bkg.url()) # Open FITS files of response components fits_aeff = gammalib.GFits(fname_aeff) @@ -336,18 +328,13 @@ class csobs2caldb(ctools.cscript): # Log resulting FITS table if self._logNormal(): - self._log(gammalib.parformat("Calibration directory")) - self._log(self._cal_dir) - self._log("\n") - self._log(gammalib.parformat("Base directory")) - self._log(self._base_dir) - self._log("\n") + self._log_value('Calibration directory', self._cal_dir) + self._log_value('Base directory', self._base_dir) if not os.path.isdir(self._rsp_dir): - self._log(gammalib.parformat("IRF directory")) + name = 'IRF directory' else: - self._log(gammalib.parformat("IRF directory (existing)")) - self._log(self._rsp_dir) - self._log("\n") + name = 'IRF directory (existing)' + self._log_value(name, self._rsp_dir) # Create IRF directory is it does not yet exist if not os.path.isdir(self._rsp_dir): @@ -400,12 +387,8 @@ class csobs2caldb(ctools.cscript): # Write filenames into logger if self._logNormal(): - self._log(gammalib.parformat('CALDB index file')) - self._log(self._caldb_inx.filename().url()) - self._log('\n') - self._log(gammalib.parformat('Response file')) - self._log(filename) - self._log('\n') + self._log_value('CALDB index file', self._caldb_inx.filename().url()) + self._log_value('Response file', filename) # Save caldb index file self._caldb_inx.save(self._clobber()) diff --git a/cscripts/csobsdef.py b/cscripts/csobsdef.py index fc584c9..ea5d87e 100755 --- a/cscripts/csobsdef.py +++ b/cscripts/csobsdef.py @@ -75,7 +75,7 @@ class csobsdef(ctools.cscript): # Constructor def __init__(self, *argv): """ - Constructor. + Constructor Parameters ---------- @@ -85,7 +85,7 @@ class csobsdef(ctools.cscript): """ # Set name and version self._name = 'csobsdef' - self._version = '1.1.0' + self._version = '1.2.0' # Initialise class members self._obs = gammalib.GObservations() @@ -103,7 +103,7 @@ class csobsdef(ctools.cscript): # Private methods def _get_parameters(self): """ - Get parameters from parfile. + Get parameters from parfile """ # Query input filename if necessary if self._pntdef.size() == 0: @@ -123,7 +123,7 @@ class csobsdef(ctools.cscript): def _set_response(self, obs, caldb, irf): """ - Set response for an observation. + Set response for an observation The method creates an XML element so that that the response XML writer will write the database and response name into the @@ -151,7 +151,7 @@ class csobsdef(ctools.cscript): # Public methods def run(self): """ - Run the script. + Run the script Raises ------ @@ -315,9 +315,9 @@ class csobsdef(ctools.cscript): self._log(str(obs)) self._log('\n') elif self._logTerse(): - self._log(gammalib.parformat(obs.instrument()+' observation')) - self._log('Name="'+obs.name()+'" ') - self._log('ID="'+obs.id()+'"\n') + name = obs.instrument()+' observation' + value = 'Name="%s" ID="%s"' % (obs.name(), obs.id()) + self._log_value(name, value) # Append observation self._obs.append(obs) @@ -342,9 +342,7 @@ class csobsdef(ctools.cscript): # Log filename if self._logTerse(): - self._log(gammalib.parformat('Observation XML file')) - self._log(outobs.url()) - self._log('\n') + self._log_value('Observation XML file', outobs.url()) # Save observation definition XML file self._obs.save(outobs) @@ -354,7 +352,7 @@ class csobsdef(ctools.cscript): def execute(self): """ - Execute the script. + Execute the script """ # Open logfile self.logFileOpen() @@ -373,7 +371,7 @@ class csobsdef(ctools.cscript): def pntdef(self, csv): """ - Set pointing definition from a CSV table. + Set pointing definition from a CSV table Parameters ---------- diff --git a/cscripts/csobsinfo.py b/cscripts/csobsinfo.py index 2ba529f..0ab4a78 100755 --- a/cscripts/csobsinfo.py +++ b/cscripts/csobsinfo.py @@ -38,7 +38,7 @@ class csobsinfo(ctools.cscript): """ # Set name self._name = 'csobsinfo' - self._version = '1.1.0' + self._version = '1.2.0' # Initialise class members self._obj_dir = None @@ -181,20 +181,14 @@ class csobsinfo(ctools.cscript): n_eventbins += obs.events().size() n_obs_binned += 1 if self._logTerse(): - self._log.parformat('Binned') - self._log('yes\n') - self._log.parformat('Number of bins') - self._log(str(obs.events().size())) - self._log('\n') + self._log_value('Binned', 'yes') + self._log_value('Number of bins', obs.events().size()) else: n_events += obs.events().size() n_obs_unbinned += 1 if self._logTerse(): - self._log.parformat('Binned') - self._log('no\n') - self._log.parformat('Number of events') - self._log(str(obs.events().size())) - self._log('\n') + self._log_value('Binned', 'no') + self._log_value('Number of events', obs.events().size()) # Retrieve zenith and azimuth and store for later use zenith = obs.pointing().zenith() @@ -232,39 +226,19 @@ class csobsinfo(ctools.cscript): self._log(str(obs_gti.tstop().mjd())) self._log('\n') - # Log ontime - self._log.parformat('Ontime') - self._log(str(obs.ontime())) - self._log(' s\n') - - # Log livetime - self._log.parformat('Livetime') - self._log(str(obs.livetime())) - self._log(' s\n') - - # Log dead time fraction - self._log.parformat('Deadtime fraction (%)') - self._log('%.3f' % (deadfrac)) - self._log('\n') - - # Log pointing direction - self._log.parformat('Pointing') - self._log(str(pnt_dir)) - self._log('\n') - + # Log observation information + self._log_value('Ontime', '%.3f s' % obs.ontime()) + self._log_value('Livetime', '%.3f s' % obs.livetime()) + self._log_value('Deadtime fraction', '%.3f %%' % deadfrac) + self._log_value('Pointing', pnt_dir) + # Optionally log offset with respect to target direction if self._compute_offset: - self._log.parformat('Offset from target') - self._log('%.2f' % (offset)) - self._log(' deg\n') - - # Log Zenith and Azimuth if required - self._log.parformat('Zenith angle') - self._log('%.2f' % (zenith)) - self._log(' deg\n') - self._log.parformat('Azimuth angle') - self._log('%.2f' % (azimuth)) - self._log(' deg\n') + self._log_value('Offset from target', '%.2f deg' % offset) + + # Log Zenith and Azimuth angles + self._log_value('Zenith angle', '%.2f deg' % zenith) + self._log_value('Azimuth angle', '%.2f deg' % azimuth) # Log summary if self._logTerse(): @@ -275,36 +249,26 @@ class csobsinfo(ctools.cscript): # Log general summary self._log.header3('Observations') - self._log.parformat('Unbinned observations') - self._log(str(n_obs_unbinned)) - self._log('\n') - self._log.parformat('Binned observations') - self._log(str(n_obs_binned)) - self._log('\n') + self._log_value('Unbinned observations', n_obs_unbinned) + self._log_value('Binned observations', n_obs_binned) + self._log_value('Binned observations', n_obs_binned) self._log.header3('Events') - self._log.parformat('Number of events') - self._log(str(n_events)) - self._log('\n') - self._log.parformat('Number of bins') - self._log(str(n_eventbins)) - self._log('\n') + self._log_value('Number of events', n_events) + self._log_value('Number of bins', n_eventbins) # Log pointing summary self._log.header3('Pointings') # Log mean offset if possible if self._compute_offset: - self._log.parformat('Mean offset angle') - self._log('%.2f' % (sum(self._offsets)/len(self._offsets))) - self._log(' deg\n') + self._log_value('Mean offset angle', '%.2f deg' % + (sum(self._offsets)/len(self._offsets))) # Log mean azimuth and zenith angle - self._log.parformat('Mean zenith angle') - self._log('%.2f' % (sum(self._zeniths)/len(self._zeniths))) - self._log(' deg\n') - self._log.parformat('Mean azimuth angle') - self._log('%.2f' % (sum(self._azimuths)/len(self._azimuths))) - self._log(' deg\n') + self._log_value('Mean zenith angle', '%.2f deg' % + (sum(self._zeniths)/len(self._zeniths))) + self._log_value('Mean azimuth angle', '%.2f deg' % + (sum(self._azimuths)/len(self._azimuths))) # Optionally log names of observations. Note that the set class # is used to extract all different observation names from the @@ -313,44 +277,34 @@ class csobsinfo(ctools.cscript): if self._logExplicit() and sys.version_info >= (2,4): obs_set = set(obs_names) for name in obs_set: - self._log.parformat('"'+name+'"') - self._log(str(obs_names.count(name))) - self._log('\n') + self._log_value('"'+name+'"', obs_names.count(name)) self._log('\n') - - # Log energy range - self._log.header3('Energy range') - self._log.parformat('Minimum energy') - if self._ebounds.size() == 0: - self._log('undefined') - else: - self._log(str(self._ebounds.emin())) - self._log('\n') - self._log.parformat('Maximum energy') + + # Get energy boundary information if self._ebounds.size() == 0: - self._log('undefined') + min_value = 'undefined' + max_value = 'undefined' else: - self._log(str(self._ebounds.emax())) - self._log('\n') - + min_value = str(self._ebounds.emin()) + max_value = str(self._ebounds.emax()) + + # Log energy range + self._log.header3('Energy range') + self._log_value('Minimum energy', min_value) + self._log_value('Maximum energy', max_value) + # Log time range self._log.header3('Time range') - self._log.parformat('Start (MJD)') - self._log(str(self._gti.tstart().mjd())) - self._log('\n') - self._log.parformat('Stop (MJD)') - self._log(str(self._gti.tstop().mjd())) - self._log('\n') - - # Log ontime and livetime in different units - self._log.parformat('Total ontime') - self._log('%.2f s = %.2f min = %.2f h' % - (ontime, ontime/60., ontime/3600.)) - self._log('\n') - self._log.parformat('Total livetime') - self._log('%.2f s = %.2f min = %.2f h' % - (livetime, livetime/60.0, livetime/3600.)) - self._log('\n') + self._log_value('Start (MJD)', self._gti.tstart().mjd()) + self._log_value('Stop (MJD)', self._gti.tstop().mjd()) + + # Log ontime and livetime in different units + on_time = '%.2f s = %.2f min = %.2f h' % \ + (ontime, ontime/60., ontime/3600.) + live_time = '%.2f s = %.2f min = %.2f h' % \ + (livetime, livetime/60., livetime/3600.) + self._log_value('Total ontime', on_time) + self._log_value('Total livetime', live_time) # Return return @@ -377,9 +331,7 @@ class csobsinfo(ctools.cscript): # Log filename if self._logTerse(): - self._log(gammalib.parformat('DS9 filename')) - self._log(ds9file.url()) - self._log('\n') + self._log_value('DS9 filename', ds9file.url()) # Open file f = open(ds9file.url(),'w') @@ -436,7 +388,7 @@ class csobsinfo(ctools.cscript): def execute(self): """ - Execute the script. + Execute the script """ # Open logfile self.logFileOpen() diff --git a/cscripts/cspull.py b/cscripts/cspull.py index 54ed2f3..e178d0f 100755 --- a/cscripts/cspull.py +++ b/cscripts/cspull.py @@ -214,16 +214,12 @@ class cspull(ctools.cscript): if self._logNormal(): self._log.header3('Simulation') for run in self._obs: - self._log.parformat('Input observation %s' % (run.id())) - self._log(self._obs_string(run)) - self._log('\n') + self._log_value('Input observation %s' % run.id(), + self._obs_string(run)) for run in obs: - self._log.parformat('Output observation %s' % (run.id())) - self._log(self._obs_string(run)) - self._log('\n') - self._log.parformat('Number of simulated events') - self._log(nevents) - self._log('\n') + self._log_value('Output observation %s' % run.id(), + self._obs_string(run)) + self._log_value('Number of simulated events', nevents) # Fit model if self['profile'].boolean(): @@ -291,13 +287,8 @@ class cspull(ctools.cscript): # Write result if self._logNormal(): - self._log.parformat(name) - self._log(pull) - self._log(' (') - self._log(fitted_value) - self._log(' +/- ') - self._log(error) - self._log(')\n') + value = '%.4f (%e +/- %e)' % (pull, fitted_value, error) + self._log_value(name, value) # Bundle together results result = {'colnames': colnames, 'values': values} diff --git a/cscripts/csresmap.py b/cscripts/csresmap.py index afa163c..9946b24 100755 --- a/cscripts/csresmap.py +++ b/cscripts/csresmap.py @@ -290,9 +290,7 @@ class csresmap(ctools.cscript): # Log file name if self._logTerse(): - self._log(gammalib.parformat('Residual map file')) - self._log(outmap.url()) - self._log('\n') + self._log_value('Residual map file', outmap.url()) # Save residual map self._resmap.save(outmap, self['clobber'].boolean()) @@ -325,9 +323,7 @@ class csresmap(ctools.cscript): # Log map name if self._logTerse(): - self._log(gammalib.parformat('Residual map name')) - self._log(user_name) - self._log('\n') + self._log_value('Residual map name', user_name) # Publish map self._resmap.publish(user_name) diff --git a/cscripts/cssens.py b/cscripts/cssens.py index 1d6cdf7..f653c63 100755 --- a/cscripts/cssens.py +++ b/cscripts/cssens.py @@ -306,15 +306,9 @@ class cssens(ctools.cscript): if self._logTerse(): self._log('\n') self._log.header2('Energies: '+str(emin)+' - '+str(emax)) - self._log.parformat('Crab flux') - self._log(crab_flux) - self._log(' ph/cm2/s\n') - self._log.parformat('Source model flux') - self._log(src_flux) - self._log(' ph/cm2/s\n') - self._log.parformat('Crab unit factor') - self._log(crab_unit) - self._log('\n') + self._log_value('Crab flux', str(crab_flux)+' ph/cm2/s') + self._log_value('Source model flux', str(src_flux)+' ph/cm2/s') + self._log_value('Crab unit factor', crab_unit) # Initialise loop crab_flux_value = [] @@ -358,9 +352,7 @@ class cssens(ctools.cscript): # Write simulation results if self._logExplicit(): self._log.header3('Simulation') - self._log.parformat('Number of simulated events') - self._log(nevents) - self._log('\n') + self._log_value('Number of simulated events', nevents) # Fit test source fit = ctools.ctlike(sim) @@ -391,22 +383,12 @@ class cssens(ctools.cscript): # Write test source fit results if self._logExplicit(): self._log.header3('Test source model fit') - self._log.parformat('Test statistics') - self._log(ts) - self._log('\n') - self._log.parformat('log likelihood') - self._log(logL) - self._log('\n') - self._log.parformat('Number of predicted events') - self._log(npred) - self._log('\n') - self._log.parformat('Fit quality') - self._log(quality) - self._log('\n') + self._log_value('Test statistics', ts) + self._log_value('log likelihood', logL) + self._log_value('Number of predicted events', quality) + self._log_value('Fit quality', npred) for model in models: - self._log.parformat('Model') - self._log(model.name()) - self._log('\n') + self._log_value('Model', model.name()) for par in model: self._log(str(par)+'\n') @@ -447,40 +429,21 @@ class cssens(ctools.cscript): # Write fit results if self._logExplicit(): - self._log.parformat('Photon flux') - self._log(photon_flux) - self._log(' ph/cm2/s\n') - self._log.parformat('Energy flux') - self._log(energy_flux) - self._log(' erg/cm2/s\n') - self._log.parformat('Crab flux') - self._log(crab_flux*1000.0) - self._log(' mCrab\n') - self._log.parformat('Differential sensitivity') - self._log(sensitivity) - self._log(' erg/cm2/s\n') + self._log_value('Photon flux', str(photon_flux)+' ph/cm2/s') + self._log_value('Energy flux', str(energy_flux)+' erg/cm2/s') + self._log_value('Crab flux', str(crab_flux*1000.0)+' mCrab') + self._log_value('Differential sensitivity', str(sensitivity)+ + ' erg/cm2/s') for model in models: - self._log.parformat('Model') - self._log(model.name()) - self._log('\n') + self._log_value('Model', model.name()) for par in model: self._log(str(par)+'\n') elif self._logTerse(): - self._log.parformat('Iteration %d' % iterations) - self._log('TS=') - self._log(ts) - self._log(' ') - self._log('corr=') - self._log(correct) - self._log(' ') - self._log(photon_flux) - self._log(' ph/cm2/s = ') - self._log(energy_flux) - self._log(' erg/cm2/s = ') - self._log(crab_flux*1000.0) - self._log(' mCrab = ') - self._log(sensitivity) - self._log(' erg/cm2/s\n') + name = 'Iteration %d' % iterations + value = ('TS=%.4f corr=%e %e ph/cm2/s = %e erg/cm2/s = %.2f ' + 'mCrab = %e erg/cm2/s' % (ts, correct, photon_flux, + energy_flux, crab_flux*1000.0, sensitivity)) + self._log_value(name, value) # Compute sliding average of extrapolated fitted prefactor, # photon and energy flux. This damps out fluctuations and @@ -534,35 +497,17 @@ class cssens(ctools.cscript): # Write fit results if self._logTerse(): self._log.header3('Fit results') - self._log.parformat('Test statistics') - self._log(ts) - self._log('\n') - self._log.parformat('Photon flux') - self._log(photon_flux) - self._log(' ph/cm2/s\n') - self._log.parformat('Energy flux') - self._log(energy_flux) - self._log(' erg/cm2/s\n') - self._log.parformat('Crab flux') - self._log(crab_flux*1000.0) - self._log(' mCrab\n') - self._log.parformat('Differential sensitivity') - self._log(sensitivity) - self._log(' erg/cm2/s\n') - self._log.parformat('Number of simulated events') - self._log(nevents) - self._log('\n') + self._log_value('Test statistics', ts) + self._log_value('Photon flux', str(photon_flux)+' ph/cm2/s') + self._log_value('Energy flux', str(energy_flux)+' erg/cm2/s') + self._log_value('Crab flux', str(crab_flux*1000.0)+' mCrab') + self._log_value('Differential sensitivity', str(sensitivity)+' erg/cm2/s') + self._log_value('Number of simulated events', nevents) self._log.header3('Test source model fitting') - self._log.parformat('log likelihood') - self._log(logL) - self._log('\n') - self._log.parformat('Number of predicted events') - self._log(npred) - self._log('\n') + self._log_value('log likelihood', logL) + self._log_value('Number of predicted events', npred) for model in models: - self._log.parformat('Model') - self._log(model.name()) - self._log('\n') + self._log_value('Model', model.name()) for par in model: self._log(str(par)+'\n') diff --git a/cscripts/csspec.py b/cscripts/csspec.py index 285444f..02c60bb 100755 --- a/cscripts/csspec.py +++ b/cscripts/csspec.py @@ -214,17 +214,13 @@ class csspec(ctools.cscript): self._log.header1("Spectral binning") if self._binned_mode: cube_ebounds = self._obs[0].events().ebounds() - self._log.parformat("Counts cube energy range") - self._log(str(cube_ebounds.emin())) - self._log(" - ") - self._log(str(cube_ebounds.emax())) - self._log("\n") + value = '%s - %s' % (str(cube_ebounds.emin()), + str(cube_ebounds.emax())) + self._log_value('Counts cube energy range', value) for i in range(self._ebounds.size()): - self._log.parformat("Bin "+str(i+1)) - self._log(str(self._ebounds.emin(i))) - self._log(" - ") - self._log(str(self._ebounds.emax(i))) - self._log("\n") + value = '%s - %s' % (str(self._ebounds.emin(i)), + str(self._ebounds.emax(i))) + self._log_value('Bin %d' % (i+1), value) # Write observation into logger if self._logTerse(): diff --git a/cscripts/cstsdist.py b/cscripts/cstsdist.py index 8ead84b..b52bd9d 100755 --- a/cscripts/cstsdist.py +++ b/cscripts/cstsdist.py @@ -160,9 +160,7 @@ class cstsdist(ctools.cscript): # Write simulation results if self._logExplicit(): self._log.header3('Simulation') - self._log.parformat('Number of simulated events') - self._log(nevents) - self._log('\n') + self._log_value('Number of simulated events', nevents) # Fit model fit = ctools.ctlike(sim) @@ -180,30 +178,18 @@ class cstsdist(ctools.cscript): # Write fit results, either explicit or normal if self._logExplicit(): self._log.header3('Test source model fit') - self._log.parformat('Test statistics') - self._log(ts) - self._log('\n') - self._log.parformat('log likelihood') - self._log(logL) - self._log('\n') - self._log.parformat('Number of predicted events') - self._log(npred) - self._log('\n') + self._log_value('Test statistics', ts) + self._log_value('log likelihood', logL) + self._log_value('Number of predicted events', npred) for model in models: - self._log.parformat('Model') - self._log(model.name()) - self._log('\n') + self._log_value('Model', model.name()) for par in model: self._log(str(par)+'\n') elif self._logNormal(): - self._log.parformat('Trial '+str(seed)) - self._log('TS=') - self._log(ts) - self._log(' Prefactor=') - self._log(model['Prefactor'].value()) - self._log('+/-') - self._log(model['Prefactor'].error()) - self._log('\n') + name = 'Trial %d' % seed + value = 'TS=%.3f Prefactor=%e +/- %e' % \ + (ts, model['Prefactor'].value(), model['Prefactor'].error()) + self._log_value(name, value) # Initialise results colnames = [] diff --git a/cscripts/cstsmapmerge.py b/cscripts/cstsmapmerge.py index 6c27d26..1d50b58 100755 --- a/cscripts/cstsmapmerge.py +++ b/cscripts/cstsmapmerge.py @@ -293,9 +293,8 @@ class cstsmapmerge(ctools.cscript): # Skip file if it's not a FITS file if not gammalib.GFilename(fitsfile).is_fits(): if self._logExplicit(): - self._log(gammalib.parformat('Skip file')) - self._log(fitsfile) - self._log(' (not a FITS file)\n') + self._log_value('Skip file', + '%s (not a FITS file)' % fitsfile) continue # Open FITS file @@ -317,9 +316,8 @@ class cstsmapmerge(ctools.cscript): else: fits.close() if self._logExplicit(): - self._log(gammalib.parformat('Skip file')) - self._log(fitsfile) - self._log(' (no "STATUS MAP" extension)\n') + self._log_value('Skip file', + '%s (no "STATUS MAP" extension)' % fitsfile) continue # Signal if no suitable file was found @@ -349,10 +347,9 @@ class cstsmapmerge(ctools.cscript): # Skip if file is not FITS if not gammalib.GFilename(fitsfile).is_fits(): if self._logExplicit(): - self._log(gammalib.parformat('Skip file')) - self._log(fitsfile) - self._log(' (not a FITS file)\n') - continue + self._log_value('Skip file', + '%s (not a FITS file)' % fitsfile) + continue # Open FITS file fits = gammalib.GFits(fitsfile) @@ -361,9 +358,9 @@ class cstsmapmerge(ctools.cscript): if not fits.contains('STATUS MAP'): fits.close() if self._logExplicit(): - self._log(gammalib.parformat('Skip file')) - self._log(fitsfile) - self._log(' (no "STATUS MAP" extension)\n') + self._log_value('Skip file', + '%s (no "STATUS MAP" extension)' % + fitsfile) continue # Close FITS file @@ -400,9 +397,7 @@ class cstsmapmerge(ctools.cscript): # Log filename if self._logTerse(): - self._log(gammalib.parformat('TS map file')) - self._log(outmap.url()) - self._log('\n') + self._log_value('TS map file', outmap.url()) # Create FITS file fits = gammalib.GFits() @@ -438,9 +433,7 @@ class cstsmapmerge(ctools.cscript): for filename in self._merged_files: os.remove(filename) if self._logTerse(): - self._log(gammalib.parformat('Deleted input file')) - self._log(filename) - self._log('\n') + self._log_value('Deleted input file', filename) # Return return diff --git a/cscripts/cstsmapsplit.py b/cscripts/cstsmapsplit.py index 29f255e..9eaa33e 100755 --- a/cscripts/cstsmapsplit.py +++ b/cscripts/cstsmapsplit.py @@ -46,7 +46,7 @@ class cstsmapsplit(ctools.cscript): # Set name and version self._name = 'cstsmapsplit' - self._version = '1.1.0' + self._version = '1.2.0' # Set data members self._outmap = gammalib.GFilename() @@ -99,8 +99,7 @@ class cstsmapsplit(ctools.cscript): # Return return - - + def _compute_null_hypothesis(self): """ Compute null hypothesis @@ -136,11 +135,11 @@ class cstsmapsplit(ctools.cscript): return -(opt.value()) + # Public methods def run(self): """ Run the script """ - # Switch screen logging on in debug mode if self._logDebug(): self._log.cout(True) @@ -172,13 +171,9 @@ class cstsmapsplit(ctools.cscript): # Write likelihood into logger if self._logTerse(): - self._log(gammalib.parformat('Source removed')) - self._log(self._srcname) - self._log('\n') - self._log(gammalib.parformat('Log-likelihood')) - self._log(repr(logL0)) - self._log('\n') - + self._log_value('Source removed', self._srcname) + self._log_value('Log-likelihood', repr(logL0)) + # Get parameters of TS map ctool pars = gammalib.GApplicationPars('cttsmap.par') @@ -196,9 +191,7 @@ class cstsmapsplit(ctools.cscript): if self._logTerse(): self._log('\n') self._log.header1('Create commands') - self._log(gammalib.parformat('Number of cttsmap calls')) - self._log(str(njobs)) - self._log('\n') + self._log_value('Number of cttsmap calls', njobs) # Loop over TS map parameters for par in pars: @@ -262,12 +255,10 @@ class cstsmapsplit(ctools.cscript): # Return return - def execute(self): """ Execute the script """ - # Run the script self.run() @@ -277,12 +268,10 @@ class cstsmapsplit(ctools.cscript): # Return return - def save(self): """ Save commands to ASCII file """ - # Open file f = open(self._outfile.url(), 'w') diff --git a/cscripts/csworkflow.py b/cscripts/csworkflow.py index 498a90c..b1e3fd7 100755 --- a/cscripts/csworkflow.py +++ b/cscripts/csworkflow.py @@ -53,7 +53,7 @@ class csworkflow(ctools.cscript): """ # Set name and version self._name = 'csworkflow' - self._version = '1.0.0' + self._version = '1.2.0' # Set members self._workflow = gammalib.GXml() @@ -168,12 +168,9 @@ class csworkflow(ctools.cscript): # Log information about actors if self._logNormal(): - self._log.parformat('Actor "'+name+'"') - self._log(tool) - self._log('\n') + self._log_value('Actor "%s"' % name, tool) if num_inputs == 0: - self._log.parformat(' Predecessor') - self._log('none\n') + self._log_value(' Predecessor', 'none') else: if num_inputs == 1: self._log.parformat(' Predecessor') @@ -203,16 +200,15 @@ class csworkflow(ctools.cscript): # Log execution start if self._logNormal(): - self._log.parformat('Execute actor') - self._log('"'+actor['name']+'"\n') + self._log_value('Execute actor', '"%s"' % actor['name']) # Execute actor self._execute_actor(actor) # Log execution finish if self._logNormal(): - self._log.parformat('Finished actor execution') - self._log('"'+actor['name']+'"\n') + self._log_value('Finished actor execution', + '"%s"' % actor['name']) # Set actor status to finished actor['status'] = 'finished' @@ -247,21 +243,15 @@ class csworkflow(ctools.cscript): if self._logNormal(): pars = actor['input_parameters'] for par in pars: - self._log.parformat(' Input parameter') - self._log(par['name']) - self._log('=') - self._log(self._get_parameter_value(par)) - self._log('\n') + self._log_value(' Input parameter', '%s=%s' % + (par['name'], self._get_parameter_value(par))) # Log output parameters if self._logNormal(): pars = actor['output_parameters'] for par in pars: - self._log.parformat(' Output parameter') - self._log(par['name']) - self._log('=') - self._log(self._get_parameter_value(par)) - self._log('\n') + self._log_value(' Output parameter', '%s=%s' % + (par['name'], self._get_parameter_value(par))) # Set actor tool if 'tool' in actor: @@ -342,7 +332,7 @@ class csworkflow(ctools.cscript): # Public methods def run(self): """ - Run the script. + Run the script """ # Switch screen logging on in debug mode if self._logDebug(): @@ -368,7 +358,7 @@ class csworkflow(ctools.cscript): def execute(self): """ - Execute the script. + Execute the script """ # Open logfile self.logFileOpen() diff --git a/pyext/ctool.i b/pyext/ctool.i index d16b956..5aec3a7 100644 --- a/pyext/ctool.i +++ b/pyext/ctool.i @@ -183,17 +183,23 @@ def _set_input_obs(self, argv): return (obs, argv) cscript._set_input_obs = _set_input_obs -# Initialise application by calling the appropriate class constructor. +# Initialise application by calling the appropriate class constructor def _init_cscript(self, argv): if len(argv) == 0: cscript.__init__(self, self._name, self._version) elif len(argv) == 1: cscript.__init__(self, self._name, self._version, *argv) else: - raise TypeError("Invalid number of arguments given.") + raise TypeError('Invalid number of arguments given.') # Set logger properties self._log_header() self._log.date(True) cscript._init_cscript = _init_cscript +# Log the value of a parameter +def _log_value(self, name, value): + self._log.parformat(name) + self._log(str(value)) + self._log('\n') +cscript._log_value = _log_value %} diff --git a/test/test_csmodelinfo.py b/test/test_csmodelinfo.py index a8cff35..b41186f 100755 --- a/test/test_csmodelinfo.py +++ b/test/test_csmodelinfo.py @@ -74,7 +74,7 @@ class Test(test): # Setup csmodelinfo command cmd = csmodelinfo+' inmodel="'+self._models_spec+'"'+ \ - ' ds9file="model_cmd1.reg"'+ \ + ' ds9file="csmodelinfo_cmd1.reg"'+ \ ' logfile="csmodelinfo_cmd1.log" chatter=1' # Check if execution of wrong command fails @@ -86,11 +86,11 @@ class Test(test): 'Check successful execution from command line') # Check region file - self._check_ds9_file('model_cmd1.reg') + self._check_ds9_file('csmodelinfo_cmd1.reg') # Setup csmodelinfo command cmd = csmodelinfo+' inmodel="model_that_does_not_exist.xml"'+ \ - ' ds9file="model_cmd2.reg"'+ \ + ' ds9file="csmodelinfo_cmd2.reg"'+ \ ' logfile="csmodelinfo_cmd2.log"' # Check if execution failed