Commit efb7eaae22c3d28829648e143c7e029b8956c0f3
1 parent
d726da04
Refactor cscaldb script and add unit test.
Showing
7 changed files
with
244 additions
and
76 deletions
cscripts/Makefile.am
| ... | ... | @@ -9,6 +9,9 @@ pythonscripts = __init__.py \ |
| 9 | 9 | csfindobs.py csiactcopy.py csiactdata.py csiactobs.py \ |
| 10 | 10 | obsutils.py |
| 11 | 11 | |
| 12 | +# Parfiles to be distributed in $(prefix)/syspfiles | |
| 13 | +parfiles = cscaldb.par | |
| 14 | + | |
| 12 | 15 | # Scripts for which symbolic links will be created in bindir |
| 13 | 16 | linkscripts = cspull cssens cstsdist cscaldb csresmap \ |
| 14 | 17 | csobsdef csspec cslightcrv csobsinfo \ |
| ... | ... | @@ -16,12 +19,14 @@ linkscripts = cspull cssens cstsdist cscaldb csresmap \ |
| 16 | 19 | csobs2caldb \ |
| 17 | 20 | csfindobs csiactcopy csiactdata csiactobs |
| 18 | 21 | |
| 19 | -# Distribute scripts | |
| 22 | +# Distribute scripts and parfiles | |
| 20 | 23 | EXTRA_DIST = $(binscripts) $(pythonscripts) |
| 21 | 24 | binscriptsdir = $(bindir) |
| 22 | 25 | binscripts_DATA = $(binscripts) |
| 23 | 26 | pythonscriptsdir = $(pyexecdir)/cscripts |
| 24 | 27 | pythonscripts_DATA = $(pythonscripts) |
| 28 | +pfilesdir = $(prefix)/syspfiles | |
| 29 | +pfiles_DATA = $(parfiles) | |
| 25 | 30 | |
| 26 | 31 | # Add hook rule to create symbolic links for cscripts |
| 27 | 32 | install-data-hook: | ... | ... |
cscripts/cscaldb.par
0 → 100644
| 1 | +############################################################################# | |
| 2 | +# # | |
| 3 | +# CTA Science Analysis Tools # | |
| 4 | +# # | |
| 5 | +# ------------------------------------------------------------------------- # | |
| 6 | +# # | |
| 7 | +# File: cscaldb.par # | |
| 8 | +# Version: 1.1.0 # | |
| 9 | +# # | |
| 10 | +# Author: Jurgen Knodlseder # | |
| 11 | +# Jurgen.Knodlseder@irap.omp.eu # | |
| 12 | +# IRAP # | |
| 13 | +# # | |
| 14 | +# Purpose: Parameter file for the cscaldb script # | |
| 15 | +# # | |
| 16 | +############################################################################# | |
| 17 | +# | |
| 18 | +# Standard parameters | |
| 19 | +#==================== | |
| 20 | +chatter, i, h, 2,0,4, "Chattiness of output" | |
| 21 | +clobber, b, h, yes,,, "Overwrite existing output files with new output files?" | |
| 22 | +debug, b, h, no,,, "Debugging mode activated" | |
| 23 | +mode, s, h, "ql",,, "Mode of automatic parameters" | |
| 24 | +logfile, f, h, "cscaldb.log",,, "Log filename" | ... | ... |
cscripts/cscaldb.py
| ... | ... | @@ -2,7 +2,7 @@ |
| 2 | 2 | # ========================================================================== |
| 3 | 3 | # This script dumps all available calibrations into the console. |
| 4 | 4 | # |
| 5 | -# Copyright (C) 2014-2015 Juergen Knoedlseder | |
| 5 | +# Copyright (C) 2014-2016 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 |
| ... | ... | @@ -25,32 +25,28 @@ import glob |
| 25 | 25 | import os |
| 26 | 26 | |
| 27 | 27 | |
| 28 | -# ============ # | |
| 29 | -# cspull class # | |
| 30 | -# ============ # | |
| 28 | +# ============= # | |
| 29 | +# cscaldb class # | |
| 30 | +# ============= # | |
| 31 | 31 | class cscaldb(ctools.cscript): |
| 32 | 32 | """ |
| 33 | - This class dumps the content of the ctools calibration database. | |
| 34 | - It derives from the ctools.cscript class which provides support for | |
| 35 | - parameter files, command line arguments, and logging. In that way | |
| 36 | - the Python script behaves just as a regular ctool. | |
| 33 | + The cscaldb class logs the content of the ctools calibration database | |
| 34 | + into the log file. Optionally, if the "debug" parameter is set to "yes" | |
| 35 | + the calibration database is also logged into the console. | |
| 37 | 36 | """ |
| 38 | 37 | def __init__(self, *argv): |
| 39 | 38 | """ |
| 40 | 39 | Constructor. |
| 41 | 40 | """ |
| 42 | 41 | # Set name |
| 43 | - self.name = "cscaldb" | |
| 44 | - self.version = "1.0.0" | |
| 45 | - | |
| 46 | - # Make sure that parfile exists | |
| 47 | - file = self.parfile() | |
| 42 | + self._name = "cscaldb" | |
| 43 | + self._version = "1.0.0" | |
| 48 | 44 | |
| 49 | 45 | # Initialise application |
| 50 | 46 | if len(argv) == 0: |
| 51 | - ctools.cscript.__init__(self, self.name, self.version) | |
| 47 | + ctools.cscript.__init__(self, self._name, self._version) | |
| 52 | 48 | elif len(argv) ==1: |
| 53 | - ctools.cscript.__init__(self, self.name, self.version, *argv) | |
| 49 | + ctools.cscript.__init__(self, self._name, self._version, *argv) | |
| 54 | 50 | else: |
| 55 | 51 | raise TypeError("Invalid number of arguments given.") |
| 56 | 52 | |
| ... | ... | @@ -68,34 +64,97 @@ class cscaldb(ctools.cscript): |
| 68 | 64 | # Return |
| 69 | 65 | return |
| 70 | 66 | |
| 71 | - def parfile(self): | |
| 67 | + def _get_parameters(self): | |
| 72 | 68 | """ |
| 73 | - Check if parfile exists. If parfile does not exist then create a | |
| 74 | - default parfile. This kluge avoids shipping the cscript with a parfile. | |
| 69 | + Get parameters from parfile. | |
| 75 | 70 | """ |
| 76 | - # Set parfile name | |
| 77 | - parfile = self.name+".par" | |
| 71 | + # Return | |
| 72 | + return | |
| 78 | 73 | |
| 79 | - try: | |
| 80 | - pars = gammalib.GApplicationPars(parfile) | |
| 81 | - except: | |
| 82 | - # Signal if parfile was not found | |
| 83 | - sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n") | |
| 74 | + def _get_missions(self, caldb): | |
| 75 | + """ | |
| 76 | + Extract mission names from a calibration database. | |
| 84 | 77 | |
| 85 | - # Create default parfile | |
| 86 | - pars = gammalib.GApplicationPars() | |
| 87 | - pars.append_standard() | |
| 88 | - pars.save(parfile) | |
| 78 | + Args: | |
| 79 | + caldb: Calibration database. | |
| 89 | 80 | |
| 90 | - # Return | |
| 91 | - return | |
| 81 | + Returns: | |
| 82 | + A list of mission names. | |
| 83 | + """ | |
| 84 | + # Initialise mission list | |
| 85 | + missions = [] | |
| 86 | + | |
| 87 | + # Extract missions | |
| 88 | + paths = glob.glob(caldb.rootdir()+"/data/*") | |
| 89 | + paths.sort() | |
| 90 | + for path in paths: | |
| 91 | + missions.append(os.path.basename(path)) | |
| 92 | 92 | |
| 93 | - def get_parameters(self): | |
| 93 | + # Sort missions | |
| 94 | + missions.sort() | |
| 95 | + | |
| 96 | + # Return missions | |
| 97 | + return missions | |
| 98 | + | |
| 99 | + def _get_instruments(self, caldb, mission): | |
| 94 | 100 | """ |
| 95 | - Get parameters from parfile. | |
| 101 | + Extract instrument names from a calibration database. | |
| 102 | + | |
| 103 | + Args: | |
| 104 | + caldb: Calibration database. | |
| 105 | + mission: Mission name. | |
| 106 | + | |
| 107 | + Returns: | |
| 108 | + A list of instrument names. | |
| 96 | 109 | """ |
| 97 | - # Return | |
| 98 | - return | |
| 110 | + # Initialise instrument list | |
| 111 | + instruments = [] | |
| 112 | + | |
| 113 | + # Extract instruments | |
| 114 | + paths = glob.glob(caldb.rootdir()+"/data/"+mission+"/*") | |
| 115 | + paths.sort() | |
| 116 | + for path in paths: | |
| 117 | + instruments.append(os.path.basename(path)) | |
| 118 | + | |
| 119 | + # Sort instruments | |
| 120 | + instruments.sort() | |
| 121 | + | |
| 122 | + # Return instruments | |
| 123 | + return instruments | |
| 124 | + | |
| 125 | + def _get_response_names(self, calibrations): | |
| 126 | + """ | |
| 127 | + Extract response names from a calibrations FITS table and return | |
| 128 | + them in form of a list. | |
| 129 | + | |
| 130 | + Args: | |
| 131 | + calibrations: FITS table containing the calibrations. | |
| 132 | + | |
| 133 | + Returns: | |
| 134 | + A list of response names. | |
| 135 | + """ | |
| 136 | + # Initialise response name list | |
| 137 | + names = [] | |
| 138 | + | |
| 139 | + # Extract response names from calibrations and append them to the | |
| 140 | + # response name list | |
| 141 | + nrows = calibrations.length() | |
| 142 | + ncols = calibrations.number() | |
| 143 | + for row in range(nrows): | |
| 144 | + for col in range(ncols): | |
| 145 | + cal = calibrations.string(row, col) | |
| 146 | + istart = cal.find("NAME(") | |
| 147 | + if istart != -1: | |
| 148 | + istop = cal.find(")") | |
| 149 | + name = cal[5:istop] | |
| 150 | + if names.count(name) == 0: | |
| 151 | + names.append(name) | |
| 152 | + | |
| 153 | + # Sort response names | |
| 154 | + names.sort() | |
| 155 | + | |
| 156 | + # Return response names | |
| 157 | + return names | |
| 99 | 158 | |
| 100 | 159 | def execute(self): |
| 101 | 160 | """ |
| ... | ... | @@ -116,23 +175,18 @@ class cscaldb(ctools.cscript): |
| 116 | 175 | self.log.cout(True) |
| 117 | 176 | |
| 118 | 177 | # Get parameters |
| 119 | - self.get_parameters() | |
| 178 | + self._get_parameters() | |
| 120 | 179 | |
| 121 | 180 | # Write input parameters into logger |
| 122 | 181 | if self.logTerse(): |
| 123 | 182 | self.log_parameters() |
| 124 | 183 | self.log("\n") |
| 125 | 184 | |
| 126 | - # Get the calibration database path | |
| 185 | + # Get the calibration database | |
| 127 | 186 | caldb = gammalib.GCaldb() |
| 128 | 187 | |
| 129 | - # Gather missions | |
| 130 | - missions = [] | |
| 131 | - paths = glob.glob(caldb.rootdir()+"/data/*") | |
| 132 | - paths.sort() | |
| 133 | - for path in paths: | |
| 134 | - head, tail = os.path.split(path) | |
| 135 | - missions.append(tail) | |
| 188 | + # Extract mission names from the calibration database | |
| 189 | + missions = self._get_missions(caldb) | |
| 136 | 190 | |
| 137 | 191 | # Loop over missions |
| 138 | 192 | for mission in missions: |
| ... | ... | @@ -146,41 +200,26 @@ class cscaldb(ctools.cscript): |
| 146 | 200 | self.log("\n") |
| 147 | 201 | self.log.header1("Mission: "+mission) |
| 148 | 202 | |
| 149 | - # Gather instruments | |
| 150 | - instruments = [] | |
| 151 | - paths = glob.glob(caldb.rootdir()+"/data/"+mission+"/*") | |
| 152 | - paths.sort() | |
| 153 | - for path in paths: | |
| 154 | - head, tail = os.path.split(path) | |
| 155 | - instruments.append(tail) | |
| 203 | + # Extract instruments | |
| 204 | + instruments = self._get_instruments(caldb, mission) | |
| 156 | 205 | |
| 157 | 206 | # Loop over instruments |
| 158 | 207 | for instrument in instruments: |
| 159 | 208 | |
| 160 | 209 | # Write mission into logger |
| 161 | 210 | if self.logTerse(): |
| 162 | - self.log.header3("Response functions in database \""+instrument+"\"") | |
| 211 | + self.log.header3("Response functions in database \""+ | |
| 212 | + instrument+"\"") | |
| 163 | 213 | |
| 164 | - # Open calibration index file | |
| 165 | - cifname = caldb.rootdir()+"/data/"+mission+"/"+instrument+"/caldb.indx" | |
| 166 | - fits = gammalib.GFits(cifname) | |
| 167 | - cif = fits["CIF"] | |
| 168 | - cals = cif["CAL_CBD"] | |
| 214 | + # Open calibration index file and retrieve calibrations | |
| 215 | + filename = "/data/"+mission+"/"+instrument+"/caldb.indx" | |
| 216 | + cifname = caldb.rootdir() + filename | |
| 217 | + fits = gammalib.GFits(cifname) | |
| 218 | + cif = fits["CIF"] | |
| 219 | + cals = cif["CAL_CBD"] | |
| 169 | 220 | |
| 170 | 221 | # Extract response names |
| 171 | - names = [] | |
| 172 | - nrows = cals.length() | |
| 173 | - ncols = cals.number() | |
| 174 | - for row in range(nrows): | |
| 175 | - for col in range(ncols): | |
| 176 | - cal = cals.string(row, col) | |
| 177 | - istart = cal.find("NAME(") | |
| 178 | - if istart != -1: | |
| 179 | - istop = cal.find(")") | |
| 180 | - name = cal[5:istop] | |
| 181 | - if names.count(name) == 0: | |
| 182 | - names.append(name) | |
| 183 | - names.sort() | |
| 222 | + names = self._get_response_names(cals) | |
| 184 | 223 | |
| 185 | 224 | # Print response name |
| 186 | 225 | if self.logTerse(): |
| ... | ... | @@ -197,7 +236,7 @@ class cscaldb(ctools.cscript): |
| 197 | 236 | # ======================== # |
| 198 | 237 | if __name__ == '__main__': |
| 199 | 238 | """ |
| 200 | - Dumps calibration database into log file. | |
| 239 | + Logs calibration database into the log file. | |
| 201 | 240 | """ |
| 202 | 241 | # Create instance of application |
| 203 | 242 | app = cscaldb(sys.argv) | ... | ... |
pyext/Makefile.am
| 1 | 1 | ############################################################################# |
| 2 | 2 | # Makefile for ctools Python extension module # |
| 3 | 3 | # ------------------------------------------------------------------------- # |
| 4 | -# Copyright (C) 2011-2015 Juergen Knoedlseder # | |
| 4 | +# Copyright (C) 2011-2016 Juergen Knoedlseder # | |
| 5 | 5 | # ------------------------------------------------------------------------- # |
| 6 | 6 | # # |
| 7 | 7 | # This program is free software: you can redistribute it and/or modify # |
| ... | ... | @@ -46,6 +46,7 @@ testscripts = ctools/tests/__init__.py \ |
| 46 | 46 | ../test/test_ctbutterfly.py \ |
| 47 | 47 | ../test/test_ctulimit.py \ |
| 48 | 48 | ../test/test_cterror.py \ |
| 49 | + ../test/test_cscaldb.py \ | |
| 49 | 50 | ../test/test_pipelines.py |
| 50 | 51 | testdata = ../test/data/crab.xml \ |
| 51 | 52 | ../test/data/crab_events.fits.gz \ | ... | ... |
test/test_cscaldb.py
0 → 100755
| 1 | +#! /usr/bin/env python | |
| 2 | +# ========================================================================== | |
| 3 | +# This scripts performs unit tests for the cscaldb script. | |
| 4 | +# | |
| 5 | +# Copyright (C) 2016 Juergen Knoedlseder | |
| 6 | +# | |
| 7 | +# This program is free software: you can redistribute it and/or modify | |
| 8 | +# it under the terms of the GNU General Public License as published by | |
| 9 | +# the Free Software Foundation, either version 3 of the License, or | |
| 10 | +# (at your option) any later version. | |
| 11 | +# | |
| 12 | +# This program is distributed in the hope that it will be useful, | |
| 13 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 | +# GNU General Public License for more details. | |
| 16 | +# | |
| 17 | +# You should have received a copy of the GNU General Public License | |
| 18 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 19 | +# | |
| 20 | +# ========================================================================== | |
| 21 | +import gammalib | |
| 22 | +import cscripts | |
| 23 | + | |
| 24 | + | |
| 25 | +# ============================= # | |
| 26 | +# Test class for cscaldb script # | |
| 27 | +# ============================= # | |
| 28 | +class Test(gammalib.GPythonTestSuite): | |
| 29 | + """ | |
| 30 | + Test class for cscaldb script. | |
| 31 | + """ | |
| 32 | + # Constructor | |
| 33 | + def __init__(self): | |
| 34 | + """ | |
| 35 | + Constructor. | |
| 36 | + """ | |
| 37 | + # Call base class constructor | |
| 38 | + gammalib.GPythonTestSuite.__init__(self) | |
| 39 | + | |
| 40 | + # Return | |
| 41 | + return | |
| 42 | + | |
| 43 | + # Set test functions | |
| 44 | + def set(self): | |
| 45 | + """ | |
| 46 | + Set all test functions. | |
| 47 | + """ | |
| 48 | + # Set test name | |
| 49 | + self.name("cscaldb") | |
| 50 | + | |
| 51 | + # Append tests | |
| 52 | + self.append(self._test_functional, "Test cscaldb functionality") | |
| 53 | + | |
| 54 | + # Return | |
| 55 | + return | |
| 56 | + | |
| 57 | + # Test cscaldb functionality | |
| 58 | + def _test_functional(self): | |
| 59 | + """ | |
| 60 | + Test cscaldb functionality. | |
| 61 | + """ | |
| 62 | + # Set-up cscaldb | |
| 63 | + caldb = cscripts.cscaldb() | |
| 64 | + | |
| 65 | + # Run script | |
| 66 | + self.test_try("Run cscaldb") | |
| 67 | + try: | |
| 68 | + caldb.run() | |
| 69 | + self.test_try_success() | |
| 70 | + except: | |
| 71 | + msg = "Exception occured in cscaldb." | |
| 72 | + self.test_try_failure(msg) | |
| 73 | + | |
| 74 | + # Return | |
| 75 | + return | ... | ... |
test/test_cscripts.sh.in
| ... | ... | @@ -47,11 +47,30 @@ export CALDB=$PWD/caldb |
| 47 | 47 | rm -rf $PFILES |
| 48 | 48 | mkdir -p $PFILES |
| 49 | 49 | cp -r ../src/*/*.par pfiles/ |
| 50 | +cp -r ../cscripts/*.par pfiles/ | |
| 50 | 51 | rm -rf $CALDB |
| 51 | 52 | mkdir -p $CALDB |
| 52 | 53 | |
| 53 | 54 | |
| 54 | 55 | # |
| 56 | +# Test cscaldb | |
| 57 | +# ============ | |
| 58 | +$ECHO -n "Test cscaldb: " | |
| 59 | +chmod +x @abs_top_srcdir@/cscripts/cscaldb.py | |
| 60 | +@PYTHON_COVERAGE@@abs_top_srcdir@/cscripts/cscaldb.py \ | |
| 61 | + chatter=4 > cscaldb.log | |
| 62 | +$ECHO -n "." | |
| 63 | +if [ -s "cscaldb.log" ] | |
| 64 | +then | |
| 65 | + $ECHO -n "." | |
| 66 | +else | |
| 67 | + $ECHO " cscaldb.log file is not valid" | |
| 68 | + exit 1 | |
| 69 | +fi | |
| 70 | +$ECHO " ok" | |
| 71 | + | |
| 72 | + | |
| 73 | +# | |
| 55 | 74 | # Test csobs2caldb |
| 56 | 75 | # ================ |
| 57 | 76 | $ECHO -n "Test csobs2caldb: " | ... | ... |
test/test_python.py
| ... | ... | @@ -37,6 +37,7 @@ import test_ctcubemask |
| 37 | 37 | import test_ctbutterfly |
| 38 | 38 | import test_ctulimit |
| 39 | 39 | import test_cterror |
| 40 | +import test_cscaldb | |
| 40 | 41 | import test_pipelines |
| 41 | 42 | |
| 42 | 43 | |
| ... | ... | @@ -65,6 +66,7 @@ def test(installed=False): |
| 65 | 66 | suite_ctbutterfly = test_ctbutterfly.Test() |
| 66 | 67 | suite_ctulimit = test_ctulimit.Test() |
| 67 | 68 | suite_cterror = test_cterror.Test() |
| 69 | + suite_cscaldb = test_cscaldb.Test() | |
| 68 | 70 | suite_pipelines = test_pipelines.Test() |
| 69 | 71 | |
| 70 | 72 | # Setup unit tests |
| ... | ... | @@ -82,6 +84,7 @@ def test(installed=False): |
| 82 | 84 | suite_ctbutterfly.set() |
| 83 | 85 | suite_ctulimit.set() |
| 84 | 86 | suite_cterror.set() |
| 87 | + suite_cscaldb.set() | |
| 85 | 88 | suite_pipelines.set() |
| 86 | 89 | |
| 87 | 90 | # Append tests to container |
| ... | ... | @@ -99,6 +102,7 @@ def test(installed=False): |
| 99 | 102 | suites.append(suite_ctbutterfly) |
| 100 | 103 | suites.append(suite_ctulimit) |
| 101 | 104 | suites.append(suite_cterror) |
| 105 | + suites.append(suite_cscaldb) | |
| 102 | 106 | suites.append(suite_pipelines) |
| 103 | 107 | |
| 104 | 108 | # If we have an installed version then create a temporary |
| ... | ... | @@ -113,11 +117,11 @@ def test(installed=False): |
| 113 | 117 | # Get test directory |
| 114 | 118 | import inspect |
| 115 | 119 | testdir = inspect.getfile(ctools.tests) |
| 116 | - head, tail = os.path.split(testdir) | |
| 120 | + dirname = os.path.dirname(testdir) | |
| 117 | 121 | |
| 118 | 122 | # Copy over test data and irf |
| 119 | - os.system("cp -r %s %s" % (head+"/data", "data")) | |
| 120 | - os.system("cp -r %s %s" % (head+"/irf", "irf")) | |
| 123 | + os.system("cp -r %s %s" % (dirname+"/data", "data")) | |
| 124 | + os.system("cp -r %s %s" % (dirname+"/irf", "irf")) | |
| 121 | 125 | |
| 122 | 126 | # Set PFILES environment variable |
| 123 | 127 | try: |
| ... | ... | @@ -129,6 +133,7 @@ def test(installed=False): |
| 129 | 133 | # Copy over pfiles |
| 130 | 134 | if not installed: |
| 131 | 135 | os.system("cp -r ../src/*/*.par pfiles/") |
| 136 | + os.system("cp -r ../cscripts/*.par pfiles/") | |
| 132 | 137 | else: |
| 133 | 138 | os.system("cp -r %s/syspfiles/*.par pfiles/" % (os.environ['CTOOLS'])) |
| 134 | 139 | ... | ... |