Commit 2de0afeaceefb29da9e9278278bf496bf361c0c0

Authored by Jürgen Knödlseder
1 parent b58507bd

Replace ASCII output files by FITS files in cssens (#1707)

ChangeLog
1   -2021-05-07
  1 +2021-05-11
2 2  
3 3 * Version 2.0.0 released
4 4 ========================
... ... @@ -17,6 +17,7 @@
17 17 Replace std::tmpnam() by gammalib::tmpnam() function in ctselect (#3324)
18 18 Remove implicit conversion warnings (#3324)
19 19 Add support of rectangular On/Off regions (#3248)
  20 + Replace ASCII output files by FITS files (#1707)
20 21  
21 22  
22 23 2021-04-28
... ...
1 1 New Features and Important Changes in ctools 2.0.0
2 2  
3   -7 May 2021
  3 +11 May 2021
4 4  
5 5  
6 6 Introduction
... ... @@ -286,6 +286,8 @@ The test source position is now used as pointing direction, eventually offset
286 286 in galactic latitude by a number of degrees specified using the "offset"
287 287 parameter (#3555).
288 288  
  289 +The ASCII output file was replaced by a FITS file (#1707).
  290 +
289 291  
290 292 csspec - Generates Spectral Energy Distribution
291 293 -----------------------------------------------
... ... @@ -358,7 +360,7 @@ regions (#3248).
358 360  
359 361 Examples
360 362 --------
361   -None
  363 +The show_sensitivity.py was adapted to deal also with FITS output files (#1707).
362 364  
363 365  
364 366 caldb
... ...
README.md
1 1 ctools information
2 2 ==================
3   -* Version: 2.0.0.dev (7 May 2021)
  3 +* Version: 2.0.0.dev (11 May 2021)
4 4 * GammaLib dependency: 2.0.0.dev
5 5  
6 6 [![Build Status](https://cta-jenkins.irap.omp.eu/buildStatus/icon?job=ctools-integrate-os)](https://cta-jenkins.irap.omp.eu/job/ctools-integrate-os/)
... ...
cscripts/csphasecrv.py
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # Generates spectra as a function of phase
4 4 #
5   -# Copyright (C) 2017-2019 Rolf Buehler
  5 +# Copyright (C) 2017-2021 Rolf Buehler
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -88,12 +88,12 @@ class csphasecrv(ctools.csobservation):
88 88 state = {'base' : ctools.csobservation.__getstate__(self),
89 89 'srcname' : self._srcname,
90 90 'phbins' : self._phbins,
91   - 'stacked' : self._stacked,
92 91 'onoff' : self._onoff,
  92 + 'stacked' : self._stacked,
93 93 'fits' : self._fits,
  94 + 'fitmodels' : self._fitmodels,
94 95 'nthreads' : self._nthreads,
95   - 'excl_reg_map' : self._excl_reg_map,
96   - 'fitmodels' : self._fitmodels}
  96 + 'excl_reg_map' : self._excl_reg_map}
97 97  
98 98 # Return pickled dictionary
99 99 return state
... ... @@ -110,12 +110,12 @@ class csphasecrv(ctools.csobservation):
110 110 ctools.csobservation.__setstate__(self, state['base'])
111 111 self._srcname = state['srcname']
112 112 self._phbins = state['phbins']
113   - self._stacked = state['stacked']
114 113 self._onoff = state['onoff']
  114 + self._stacked = state['stacked']
115 115 self._fits = state['fits']
  116 + self._fitmodels = state['fitmodels']
116 117 self._nthreads = state['nthreads']
117 118 self._excl_reg_map = state['excl_reg_map']
118   - self._fitmodels = state['fitmodels']
119 119  
120 120 # Return
121 121 return
... ... @@ -291,7 +291,7 @@ class csphasecrv(ctools.csobservation):
291 291 'phmax': phmax,
292 292 'pars': pars,
293 293 'values': {}}
294   -
  294 +
295 295 # Store fit results
296 296 phname = str(phmin)+'-'+str(phmax)
297 297  
... ... @@ -310,14 +310,14 @@ class csphasecrv(ctools.csobservation):
310 310  
311 311 # Append result to list of dictionaries
312 312 results.append(result)
313   -
  313 +
314 314 # Create FITS table from results
315 315 table = self._create_fits_table(results)
316 316  
317 317 # Create FITS file and append FITS table to FITS file
318 318 self._fits = gammalib.GFits()
319 319 self._fits.append(table)
320   -
  320 +
321 321 # Return
322 322 return
323 323  
... ... @@ -339,7 +339,7 @@ class csphasecrv(ctools.csobservation):
339 339  
340 340 # Save to fits
341 341 self._fits.saveto(outfile, self._clobber())
342   -
  342 +
343 343 # Return
344 344 return
345 345  
... ... @@ -368,25 +368,33 @@ class csphasecrv(ctools.csobservation):
368 368 # Log file name
369 369 name = 'Phase [%s] file' % phname
370 370 self._log_value(gammalib.NORMAL, name, outfile)
371   -
  371 +
372 372 # Return
373 373 return
374 374  
375   - def _phase_bin(self,phbin):
  375 + def _phase_bin(self, phbin):
  376 + """
  377 + Analyse one phase bin
  378 +
  379 + Parameters
  380 + ----------
  381 + phbin : list of float
  382 + Phase bin limits
  383 + """
376 384  
377 385 # Write time bin into header
378 386 self._log_header2(gammalib.TERSE, 'PHASE %f - %f' %
379 387 (phbin[0], phbin[1]))
380 388  
381 389 # Select events
382   - select = ctools.ctselect(self.obs().copy())
  390 + select = ctools.ctselect(self.obs())
383 391 select['emin'] = self['emin'].real()
384 392 select['emax'] = self['emax'].real()
385 393 select['tmin'] = 'UNDEFINED'
386 394 select['tmax'] = 'UNDEFINED'
387   - select['rad'] = 'UNDEFINED'
388   - select['ra'] = 'UNDEFINED'
389   - select['dec'] = 'UNDEFINED'
  395 + select['rad'] = 'UNDEFINED'
  396 + select['ra'] = 'UNDEFINED'
  397 + select['dec'] = 'UNDEFINED'
390 398 select['expr'] = 'PHASE>' + str(phbin[0]) + ' && PHASE<' + str(phbin[1])
391 399 select.run()
392 400  
... ... @@ -457,13 +465,13 @@ class csphasecrv(ctools.csobservation):
457 465 # Switch screen logging on in debug mode
458 466 if self._logDebug():
459 467 self._log.cout(True)
460   -
  468 +
461 469 # Get parameters
462 470 self._get_parameters()
463 471  
464 472 # Write observation into logger
465 473 self._log_observations(gammalib.NORMAL, self.obs(), 'Observation')
466   -
  474 +
467 475 # Dictionary to save phase fitted models
468 476 self._fitmodels = {}
469 477  
... ... @@ -507,7 +515,7 @@ class csphasecrv(ctools.csobservation):
507 515  
508 516 # Save results to XML files (one per phase bin)
509 517 self._save_xml()
510   -
  518 +
511 519 # Return
512 520 return
513 521  
... ... @@ -569,7 +577,7 @@ class csphasecrv(ctools.csobservation):
569 577 # Return
570 578 return self._excl_reg_map
571 579  
572   -
  580 +
573 581 # ======================== #
574 582 # Main routine entry point #
575 583 # ======================== #
... ...
cscripts/cssens.par
... ... @@ -23,7 +23,7 @@ caldb, s, a, prod2,,, &quot;Calibration database&quot;
23 23 irf, s, a, South_50h,,, "Instrument response function"
24 24 edisp, b, h, no,,, "Apply energy dispersion?"
25 25 deadc, r, h, 0.98,0,1, "Deadtime correction factor"
26   -outfile, f, h, sensitivity.dat,,, "Output sensitivity ASCII file"
  26 +outfile, f, a, sensitivity.fits,,, "Output sensitivity FITS file"
27 27  
28 28 #
29 29 # Script parameters
... ... @@ -51,5 +51,3 @@ clobber, b, h, yes,,, &quot;Overwrite existing output files with new output files?&quot;
51 51 debug, b, h, no,,, "Activate debugging mode?"
52 52 mode, s, h, ql,,, "Mode of automatic parameters"
53 53 logfile, f, h, cssens.log,,, "Log filename"
54   -
55   -
... ...
cscripts/cssens.py
... ... @@ -54,6 +54,7 @@ class cssens(ctools.csobservation):
54 54 # Initialise class members
55 55 self._ebounds = gammalib.GEbounds()
56 56 self._obs_ebounds = []
  57 + self._fits = None
57 58 self._srcname = ''
58 59 self._ra = None
59 60 self._dec = None
... ... @@ -78,6 +79,7 @@ class cssens(ctools.csobservation):
78 79 state = {'base' : ctools.csobservation.__getstate__(self),
79 80 'ebounds' : self._ebounds,
80 81 'obs_ebounds' : self._obs_ebounds,
  82 + 'fits' : self._fits,
81 83 'srcname' : self._srcname,
82 84 'ra' : self._ra,
83 85 'dec' : self._dec,
... ... @@ -100,6 +102,7 @@ class cssens(ctools.csobservation):
100 102 ctools.csobservation.__setstate__(self, state['base'])
101 103 self._ebounds = state['ebounds']
102 104 self._obs_ebounds = state['obs_ebounds']
  105 + self._fits = state['fits']
103 106 self._srcname = state['srcname']
104 107 self._ra = state['ra']
105 108 self._dec = state['dec']
... ... @@ -145,7 +148,6 @@ class cssens(ctools.csobservation):
145 148 self['sigma'].real()
146 149 self['max_iter'].integer()
147 150 self['type'].string()
148   - self['outfile'].filename()
149 151 self['edisp'].boolean()
150 152 self['debug'].boolean()
151 153  
... ... @@ -154,6 +156,10 @@ class cssens(ctools.csobservation):
154 156 gammalib.GEnergy(emin, 'TeV'),
155 157 gammalib.GEnergy(emax, 'TeV'))
156 158  
  159 + # Read ahead output parameters
  160 + if self._read_ahead():
  161 + self['outfile'].filename()
  162 +
157 163 # Write input parameters into logger
158 164 self._log_parameters(gammalib.TERSE)
159 165  
... ... @@ -690,6 +696,88 @@ class cssens(ctools.csobservation):
690 696 # Return results
691 697 return result
692 698  
  699 + def _create_fits(self, results):
  700 + """
  701 + Create FITS file from results
  702 +
  703 + Parameters
  704 + ----------
  705 + results : list of dict
  706 + List of result dictionaries
  707 + """
  708 + # Create FITS table columns
  709 + nrows = len(results)
  710 + e_mean = gammalib.GFitsTableDoubleCol('E_MEAN', nrows)
  711 + e_min = gammalib.GFitsTableDoubleCol('E_MIN', nrows)
  712 + e_max = gammalib.GFitsTableDoubleCol('E_MAX', nrows)
  713 + flux_crab = gammalib.GFitsTableDoubleCol('FLUX_CRAB', nrows)
  714 + flux_photon = gammalib.GFitsTableDoubleCol('FLUX_PHOTON', nrows)
  715 + flux_energy = gammalib.GFitsTableDoubleCol('FLUX_ENERGY', nrows)
  716 + sensitivity = gammalib.GFitsTableDoubleCol('SENSITIVITY', nrows)
  717 + regcoeff = gammalib.GFitsTableDoubleCol('REGRESSION_COEFF', nrows)
  718 + nevents = gammalib.GFitsTableDoubleCol('NEVENTS', nrows)
  719 + npred = gammalib.GFitsTableDoubleCol('NPRED', nrows)
  720 + e_mean.unit('TeV')
  721 + e_min.unit('TeV')
  722 + e_max.unit('TeV')
  723 + flux_crab.unit('')
  724 + flux_photon.unit('ph/cm2/s')
  725 + flux_energy.unit('erg/cm2/s')
  726 + sensitivity.unit('erg/cm2/s')
  727 + regcoeff.unit('')
  728 + nevents.unit('counts')
  729 + npred.unit('counts')
  730 +
  731 + # Fill FITS table columns
  732 + for i, result in enumerate(results):
  733 + e_mean[i] = math.pow(10.0, result['loge'])
  734 + e_min[i] = result['emin']
  735 + e_max[i] = result['emax']
  736 + flux_crab[i] = result['crab_flux']
  737 + flux_photon[i] = result['photon_flux']
  738 + flux_energy[i] = result['energy_flux']
  739 + sensitivity[i] = result['sensitivity']
  740 + regcoeff[i] = result['regcoeff']
  741 + nevents[i] = result['nevents']
  742 + npred[i] = result['npred']
  743 +
  744 + # Initialise FITS Table with extension "SENSITIVITY"
  745 + table = gammalib.GFitsBinTable(nrows)
  746 + table.extname('SENSITIVITY')
  747 +
  748 + # Add keywors for compatibility with gammalib.GMWLSpectrum
  749 + table.card('INSTRUME', 'CTA', 'Name of Instrument')
  750 + table.card('TELESCOP', 'CTA', 'Name of Telescope')
  751 +
  752 + # Stamp header
  753 + self._stamp(table)
  754 +
  755 + # Add script keywords
  756 + table.card('OBJECT', self._srcname, 'Source for which sensitivity was estimated')
  757 + table.card('TYPE', self['type'].string(), 'Sensitivity type')
  758 + table.card('SIGMA', self['sigma'].real(), '[sigma] Sensitivity threshold')
  759 + table.card('MAX_ITER', self['max_iter'].integer(), 'Maximum number of iterations')
  760 + table.card('STAT', self['statistic'].string(), 'Optimization statistic')
  761 +
  762 + # Append filled columns to fits table
  763 + table.append(e_mean)
  764 + table.append(e_min)
  765 + table.append(e_max)
  766 + table.append(flux_crab)
  767 + table.append(flux_photon)
  768 + table.append(flux_energy)
  769 + table.append(sensitivity)
  770 + table.append(regcoeff)
  771 + table.append(nevents)
  772 + table.append(npred)
  773 +
  774 + # Create the FITS file now
  775 + self._fits = gammalib.GFits()
  776 + self._fits.append(table)
  777 +
  778 + # Return
  779 + return
  780 +
693 781  
694 782 # Public methods
695 783 def run(self):
... ... @@ -708,10 +796,7 @@ class cssens(ctools.csobservation):
708 796 for obs in self.obs():
709 797 self._obs_ebounds.append(obs.events().ebounds().copy())
710 798  
711   - # Initialise script
712   - colnames = ['loge', 'emin', 'emax', 'crab_flux', 'photon_flux',
713   - 'energy_flux', 'sensitivity', 'regcoeff', 'nevents',
714   - 'npred']
  799 + # Initialise results
715 800 results = []
716 801  
717 802 # Set test source model for this observation
... ... @@ -745,20 +830,50 @@ class cssens(ctools.csobservation):
745 830 else:
746 831 for ieng in range(self._ebounds.size()):
747 832  
748   - #Run analysis in energy bin
  833 + # Run analysis in energy bin
749 834 result = self._e_bin(ieng)
750 835  
751 836 # Append results
752 837 results.append(result)
753 838  
754   - # Write out trial result
755   - for ieng, result in enumerate(results):
756   - ioutils.write_csv_row(self['outfile'].filename().url(), ieng,
757   - colnames, result)
  839 + # Create FITS file
  840 + self._create_fits(results)
758 841  
759 842 # Return
760 843 return
761 844  
  845 + def save(self):
  846 + """
  847 + Save sensitivity FITS file
  848 + """
  849 + # Write header
  850 + self._log_header1(gammalib.TERSE, 'Save sensitivity curve')
  851 +
  852 + # Continue only if FITS file is valid
  853 + if self._fits != None:
  854 +
  855 + # Get outmap parameter
  856 + outfile = self['outfile'].filename()
  857 +
  858 + # Log file name
  859 + self._log_value(gammalib.NORMAL, 'Sensitivity file', outfile.url())
  860 +
  861 + # Save sensitivity
  862 + self._fits.saveto(outfile, self['clobber'].boolean())
  863 +
  864 + # Return
  865 + return
  866 +
  867 + def sensitivity(self):
  868 + """
  869 + Return sensitivity FITS file
  870 +
  871 + Returns:
  872 + FITS file containing sensitivity curve
  873 + """
  874 + # Return
  875 + return self._fits
  876 +
762 877  
763 878 # ======================== #
764 879 # Main routine entry point #
... ...
doc/source/admin/release_history/2.0.rst
1 1 .. _2.0:
2 2  
3   -ctools 2.0 release (7 May 2021)
4   -===============================
  3 +ctools 2.0 release (11 May 2021)
  4 +================================
5 5  
6 6 Overview
7 7 --------
... ... @@ -44,6 +44,8 @@ Improvements
44 44 Replace ``std::tmpnam()`` by ``gammalib::tmpnam()`` function in :ref:`ctselect`
45 45 * [`3324 <https://cta-redmine.irap.omp.eu/issues/3324>`_] -
46 46 Remove implicit conversion warnings
  47 +* [`1707 <https://cta-redmine.irap.omp.eu/issues/1707>`_] -
  48 + Replace ASCII output files by FITS files
47 49  
48 50  
49 51 New features
... ...
doc/source/users/reference_manual/cssens.rst
... ... @@ -42,17 +42,11 @@ bin/threshold will be performed in parallel over as many processes as the number
42 42 CPUs available on your machine. The maximum number of parallel processes can be set
43 43 by the user through the ``nthreads`` hidden parameter.
44 44  
45   -:ref:`cssens` will generate an ASCII file in comma-separated value (CSV) format
46   -containing the sensitivity as function of energy. The first row is a header row
47   -providing the column names. The following rows provide the mean logarithmic
48   -energy and the boundaries of the energy bin for which the sensitivity was
49   -computed. They also provide the flux within the energy bin in Crab units, in
50   -photons (ph/cm2/s) and in energy (erg/cm2/s). Finally, the sensitivity is given
51   -as the test source spectrum evaluated at the mean logarithmic energy multiplied
52   -by the energy squared (erg/cm2/s).
  45 +:ref:`cssens` will generate a FITS file with a single extension that contains a
  46 +binary table with the sensitivity as function of energy.
53 47  
54   -The sensitivity can be displayed using the ``show_sensitivity.py`` script in the
55   -example folder. Matplotlib is required to execute the script.
  48 +The sensitivity FITS file can be displayed using the ``show_sensitivity.py`` script
  49 +in the example folder. Matplotlib is required to execute the script.
56 50  
57 51  
58 52 General parameters
... ... @@ -81,7 +75,7 @@ General parameters
81 75 Average deadtime correction factor.
82 76  
83 77 ``outfile [file]``
84   - ASCII file containing the sensitivity values.
  78 + Output sensitivity FITS file.
85 79  
86 80 ``(offset = 0.0) [real]``
87 81 Offset angle of source in field of view (in degrees).
... ...
examples/show_sensitivity.py
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # Display differential sensitivity plot generated by cssens
4 4 #
5   -# Copyright (C) 2015-2020 Juergen Knoedlseder
  5 +# Copyright (C) 2015-2021 Juergen Knoedlseder
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -36,6 +36,29 @@ import cscripts
36 36 # ===================== #
37 37 def read_sensitivity(filename):
38 38 """
  39 + Read sensitivity information
  40 +
  41 + Parameters
  42 + ----------
  43 + filename : str
  44 + Name of FITS or CSV file
  45 + """
  46 + # Read sensitivity information dependent on file type
  47 + fname = gammalib.GFilename(filename)
  48 + if fname.is_fits():
  49 + sensitivity = read_sensitivity_fits(filename)
  50 + else:
  51 + sensitivity = read_sensitivity_csv(filename)
  52 +
  53 + # Return sensitivity
  54 + return sensitivity
  55 +
  56 +
  57 +# =================================== #
  58 +# Read sensitivity data from CSV file #
  59 +# =================================== #
  60 +def read_sensitivity_csv(filename):
  61 + """
39 62 Read sensitivity information from CSV file
40 63  
41 64 Parameters
... ... @@ -94,6 +117,61 @@ def read_sensitivity(filename):
94 117 return sensitivity
95 118  
96 119  
  120 +# ==================================== #
  121 +# Read sensitivity data from FITS file #
  122 +# ==================================== #
  123 +def read_sensitivity_fits(filename):
  124 + """
  125 + Read sensitivity information from FITS file
  126 +
  127 + Parameters
  128 + ----------
  129 + filename : str
  130 + Name of CSV file
  131 +
  132 + Returns
  133 + -------
  134 + sensitivity : dict
  135 + Dictionary with sensitivity information
  136 + """
  137 + # Open FITS file
  138 + fits = gammalib.GFits(filename)
  139 +
  140 + # Get sensitivity table
  141 + table = fits.table('SENSITIVITY')
  142 +
  143 + # Get relevant columns
  144 + c_e_mean = table['E_MEAN']
  145 + c_e_min = table['E_MIN']
  146 + c_e_max = table['E_MAX']
  147 + c_sensitivity = table['SENSITIVITY']
  148 +
  149 + # Get mode
  150 + mode = table.card('TYPE').string()
  151 +
  152 + # Initialise vectors
  153 + energies = []
  154 + sensitivities = []
  155 +
  156 + # Fill vectors
  157 + nrows = table.nrows()
  158 + for row in range(nrows):
  159 + if mode == 'Differential':
  160 + energies.append(c_e_mean[row])
  161 + else:
  162 + energies.append(c_e_min[row])
  163 + sensitivities.append(c_sensitivity[row])
  164 +
  165 +
  166 + # Set dictionary
  167 + sensitivity = {'mode' : mode,
  168 + 'energy' : energies,
  169 + 'sensitivity' : sensitivities}
  170 +
  171 + # Return
  172 + return sensitivity
  173 +
  174 +
97 175 # ===================== #
98 176 # Plot sensitivity data #
99 177 # ===================== #
... ...
test/test_csphasecrv.py
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # This scripts performs unit tests for the csphasecrv script.
4 4 #
5   -# Copyright (C) 2017-2020 Juergen Knoedlseder
  5 +# Copyright (C) 2017-2021 Juergen Knoedlseder
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -33,7 +33,7 @@ class Test(test):
33 33 This test class makes unit tests for the csphasecrv script by using it
34 34 from the command line and from Python.
35 35 """
36   -
  36 +
37 37 # Constructor
38 38 def __init__(self):
39 39 """
... ... @@ -280,7 +280,7 @@ class Test(test):
280 280 pcrv['phbinalg'] = 'LIN'
281 281 pcrv['phbins'] = 2
282 282 pcrv['method'] = '3D'
283   - pcrv['enumbins'] = 0
  283 + pcrv['enumbins'] = 0 # Unbinned analysis
284 284 pcrv['emin'] = 1.0
285 285 pcrv['emax'] = 100.0
286 286 pcrv['outfile'] = 'csphasecrv_py6.fits'
... ... @@ -378,6 +378,6 @@ class Test(test):
378 378  
379 379 # Close FITS file
380 380 fits.close()
381   -
  381 +
382 382 # Return
383 383 return
... ...
test/test_cssens.py
... ... @@ -2,7 +2,7 @@
2 2 # ==========================================================================
3 3 # This scripts performs unit tests for the cssens script
4 4 #
5   -# Copyright (C) 2016-2018 Juergen Knoedlseder
  5 +# Copyright (C) 2016-2021 Juergen Knoedlseder
6 6 #
7 7 # This program is free software: you can redistribute it and/or modify
8 8 # it under the terms of the GNU General Public License as published by
... ... @@ -77,7 +77,7 @@ class Test(test):
77 77 ' srcname="Crab"'+ \
78 78 ' caldb="'+self._caldb+'" irf="'+self._irf+'"'+ \
79 79 ' duration=180.0 rad=3.0 emin=1.0 emax=10.0 bins=1'+ \
80   - ' outfile="cssens_cmd1.dat"'+ \
  80 + ' outfile="cssens_cmd1.fits"'+ \
81 81 ' logfile="cssens_cmd1.log" chatter=1'
82 82  
83 83 # Check if execution was successful
... ... @@ -85,14 +85,14 @@ class Test(test):
85 85 'Check successful execution from command line')
86 86  
87 87 # Check result file
88   - self._check_result_file('cssens_cmd1.dat')
  88 + self._check_result_file('cssens_cmd1.dat', 1)
89 89  
90 90 # Setup cssens command
91 91 cmd = cssens+' inmodel="model_that_does_not_exist.xml"'+ \
92 92 ' srcname="Crab"'+ \
93 93 ' caldb="'+self._caldb+'" irf="'+self._irf+'"'+ \
94 94 ' duration=180.0 rad=3.0 emin=1.0 emax=10.0 bins=1'+ \
95   - ' outfile="cssens_cmd2.dat"'+ \
  95 + ' outfile="cssens_cmd2.fits"'+ \
96 96 ' logfile="cssens_cmd2.log" debug=yes chatter=2'
97 97  
98 98 # Check if execution failed
... ... @@ -118,12 +118,12 @@ class Test(test):
118 118 sens['srcname'] = 'Crab'
119 119 sens['caldb'] = self._caldb
120 120 sens['irf'] = self._irf
121   - sens['outfile'] = 'cssens_py1.dat'
122 121 sens['duration'] = 180.0
123 122 sens['rad'] = 3.0
124 123 sens['emin'] = 1.0
125 124 sens['emax'] = 10.0
126 125 sens['bins'] = 2
  126 + sens['outfile'] = 'cssens_py1.fits'
127 127 sens['logfile'] = 'cssens_py1.log'
128 128 sens['chatter'] = 4
129 129  
... ... @@ -132,8 +132,8 @@ class Test(test):
132 132 sens.run()
133 133 sens.save()
134 134  
135   - # Check pull distribution file
136   - self._check_result_file('cssens_py1.dat',nrows=3)
  135 + # Check sensitivity file
  136 + self._check_result_file('cssens_py1.fits', 2)
137 137  
138 138 # Set-up cssens for integral sensitivity computation without
139 139 # multiprocessing
... ... @@ -143,13 +143,13 @@ class Test(test):
143 143 sens['srcname'] = 'Crab'
144 144 sens['caldb'] = self._caldb
145 145 sens['irf'] = self._irf
146   - sens['outfile'] = 'cssens_py2.dat'
147 146 sens['duration'] = 180.0
148 147 sens['rad'] = 3.0
149 148 sens['emin'] = 1.0
150 149 sens['emax'] = 10.0
151 150 sens['bins'] = 1
152 151 sens['type'] = 'Integral'
  152 + sens['outfile'] = 'cssens_py2.fits'
153 153 sens['logfile'] = 'cssens_py2.log'
154 154 sens['chatter'] = 4
155 155 sens['nthreads'] = 1
... ... @@ -157,8 +157,8 @@ class Test(test):
157 157 # Execute cssens script
158 158 sens.execute()
159 159  
160   - # Check pull distribution file
161   - self._check_result_file('cssens_py2.dat')
  160 + # Check sensitivity file
  161 + self._check_result_file('cssens_py2.fits', 1)
162 162  
163 163 # Return
164 164 return
... ... @@ -178,12 +178,12 @@ class Test(test):
178 178 sens['srcname'] = 'Crab'
179 179 sens['caldb'] = self._caldb
180 180 sens['irf'] = self._irf
181   - sens['outfile'] = 'cssens_py1_pickle.dat'
182 181 sens['duration'] = 180.0
183 182 sens['rad'] = 3.0
184 183 sens['emin'] = 1.0
185 184 sens['emax'] = 10.0
186 185 sens['bins'] = 2
  186 + sens['outfile'] = 'cssens_py1_pickle.fits'
187 187 sens['logfile'] = 'cssens_py1_pickle.log'
188 188 sens['chatter'] = 4
189 189  
... ... @@ -196,23 +196,24 @@ class Test(test):
196 196 obj.save()
197 197  
198 198 # Check result file
199   - self._check_result_file('cssens_py1_pickle.dat',nrows=3)
  199 + self._check_result_file('cssens_py1_pickle.fits', 2)
200 200  
201 201 # Return
202 202 return
203 203  
204 204 # Check result file
205   - def _check_result_file(self, filename, nrows=2):
  205 + def _check_result_file(self, filename, nrows):
206 206 """
207 207 Check result file
208 208 """
209   - # Open result file as CSV file
210   - results = gammalib.GCsv(filename, ',')
  209 + # Open result file as FITS file
  210 + fits = gammalib.GFits(filename)
  211 + table = fits.table('SENSITIVITY')
211 212  
212 213 # Check dimensions
213   - self.test_value(results.nrows(), nrows,
  214 + self.test_value(table.nrows(), nrows,
214 215 'Check number of rows in sensitivity file')
215   - self.test_value(results.ncols(), 10,
  216 + self.test_value(table.ncols(), 10,
216 217 'Check number of columns in sensitivity file')
217 218  
218 219 # Return
... ...