diff --git a/pyext/ctlikelihood.i b/pyext/ctlikelihood.i index 67fec04..8bdff40 100644 --- a/pyext/ctlikelihood.i +++ b/pyext/ctlikelihood.i @@ -26,9 +26,44 @@ %{ /* Put headers and other declarations here that are needed for compilation */ +#define SWIG #include "ctlikelihood.hpp" + + +/***********************************************************************//** + * @class cslikelihood + * + * @brief cslikelihood base class + * + * This class is a non-abstract C++ implementation of the ctlikelihood base + * class. It serves as Python base class since Python does not know about + * abstract classes. + ***************************************************************************/ +class cslikelihood : public ctlikelihood { +public: + // Constructors and destructors + cslikelihood(const std::string& name, const std::string& version) : + ctlikelihood(name, version) {} + cslikelihood(const std::string& name, const std::string& version, + const GObservations& obs) : + ctlikelihood(name, version, obs) {} + cslikelihood(const std::string& name, const std::string& version, + int argc, char* argv[]) : + ctlikelihood(name, version, argc, argv){} + cslikelihood(const cslikelihood& app) : ctlikelihood(app) {} + virtual ~cslikelihood(void) {} + + // Dummy methods (implementation makes this class non-abstract) + virtual void clear(void) {} + virtual void run(void) {} + virtual void save(void) {} +}; %} +// Include (int ARGC, char **ARGV) typemap to allow passing command line +// arguments to GApplication constructor +%include "argcargv.i" + /***********************************************************************//** * @class ctlikelihood @@ -54,11 +89,65 @@ public: // Methods const GOptimizer* opt(void) const; + + // Make methods private in Python by prepending an underscore + %rename(_evaluate) evaluate; + + // Protected methods + double evaluate(GModelPar& par, const double& value); +}; + + +/***********************************************************************//** + * @class cslikelihood + * + * @brief Base class for likelihood scripts + * + * This is the base class from which likelihood scripts should derive. + ***************************************************************************/ +class cslikelihood : public ctlikelihood { +public: + // Constructors and destructors + cslikelihood(const std::string& name, const std::string& version); + cslikelihood(const std::string& name, const std::string& version, + const GObservations& obs); + cslikelihood(const std::string& name, const std::string& version, + int ARGC, char **ARGV); + cslikelihood(const cslikelihood& app); + virtual ~cslikelihood(void); + + // Methods + virtual void clear(void); + virtual void run(void); + virtual void save(void); }; /***********************************************************************//** - * @brief Likelihood tool Python extensions + * @brief Likelihood tool base class C++ extensions ***************************************************************************/ %extend ctlikelihood { } + + +/***********************************************************************//** + * @brief Likelihood tool base class Python extensions + ***************************************************************************/ +%pythoncode %{ + +# Initialise application by calling the appropriate base class constructor. +# The function supports either an observation container, or an argument +# list or no argument as "argv" parameter. The function also writes the +# header in the log file and switches the date on for logging. +def _init_cslikelihood(self, argv): + if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations): + cslikelihood.__init__(self, self._name, self._version, argv[0]) + elif len(argv) > 0: + cslikelihood.__init__(self, self._name, self._version, *argv) + else: + cslikelihood.__init__(self, self._name, self._version) + # Set logger properties + self._log_header() + self._log.date(True) +cslikelihood._init_cslikelihood = _init_cslikelihood +%} diff --git a/pyext/ctobservation.i b/pyext/ctobservation.i index e36832b..5791958 100644 --- a/pyext/ctobservation.i +++ b/pyext/ctobservation.i @@ -26,14 +26,49 @@ %{ /* Put headers and other declarations here that are needed for compilation */ +#define SWIG #include "ctobservation.hpp" + + +/***********************************************************************//** + * @class csobservation + * + * @brief csobservation base class + * + * This class is a non-abstract C++ implementation of the ctobservation base + * class. It serves as Python base class since Python does not know about + * abstract classes. + ***************************************************************************/ +class csobservation : public ctobservation { +public: + // Constructors and destructors + csobservation(const std::string& name, const std::string& version) : + ctobservation(name, version) {} + csobservation(const std::string& name, const std::string& version, + const GObservations& obs) : + ctobservation(name, version, obs) {} + csobservation(const std::string& name, const std::string& version, + int argc, char* argv[]) : + ctobservation(name, version, argc, argv){} + csobservation(const csobservation& app) : ctobservation(app) {} + virtual ~csobservation(void) {} + + // Dummy methods (implementation makes this class non-abstract) + virtual void clear(void) {} + virtual void run(void) {} + virtual void save(void) {} +}; %} +// Include (int ARGC, char **ARGV) typemap to allow passing command line +// arguments to GApplication constructor +%include "argcargv.i" + /***********************************************************************//** * @class ctobservation * - * @brief Base class for likelihood tools + * @brief Base class for observation tools ***************************************************************************/ class ctobservation : public ctool { @@ -43,7 +78,7 @@ public: ctobservation(const std::string& name, const std::string& version, const GObservations& obs); ctobservation(const std::string& name, const std::string& version, - int argc, char* argv[]); + int ARGC, char **ARGV); ctobservation(const ctobservation& app); virtual ~ctobservation(void); @@ -66,6 +101,31 @@ public: /***********************************************************************//** + * @class csobservation + * + * @brief Base class for observation scripts + * + * This is the base class from which observation scripts should derive. + ***************************************************************************/ +class csobservation : public ctobservation { +public: + // Constructors and destructors + csobservation(const std::string& name, const std::string& version); + csobservation(const std::string& name, const std::string& version, + const GObservations& obs); + csobservation(const std::string& name, const std::string& version, + int ARGC, char **ARGV); + csobservation(const csobservation& app); + virtual ~csobservation(void); + + // Methods + virtual void clear(void); + virtual void run(void); + virtual void save(void); +}; + + +/***********************************************************************//** * @brief Observation tool base class C++ extensions ***************************************************************************/ %extend ctobservation { @@ -76,6 +136,24 @@ public: * @brief Observation tool base class Python extensions ***************************************************************************/ %pythoncode %{ + +# Initialise application by calling the appropriate base class constructor. +# The function supports either an observation container, or an argument +# list or no argument as "argv" parameter. The function also writes the +# header in the log file and switches the date on for logging. +def _init_csobservation(self, argv): + if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations): + csobservation.__init__(self, self._name, self._version, argv[0]) + elif len(argv) > 0: + csobservation.__init__(self, self._name, self._version, *argv) + else: + csobservation.__init__(self, self._name, self._version) + # Set logger properties + self._log_header() + self._log.date(True) +csobservation._init_csobservation = _init_csobservation + +# Define an iterator over all observations def _unbinned_observations(self): obs = self._first_unbinned_observation() while obs != None: diff --git a/pyext/ctool.i b/pyext/ctool.i index 78b9386..076dc42 100644 --- a/pyext/ctool.i +++ b/pyext/ctool.i @@ -86,12 +86,12 @@ public: %rename(_time_reference) time_reference; %rename(_get_observations) get_observations; %rename(_setup_observations) setup_observations; + %rename(_setup_models) setup_models; %rename(_create_ebounds) create_ebounds; %rename(_create_map) create_map; %rename(_create_cube) create_cube; %rename(_create_cta_obs) create_cta_obs; %rename(_require_inobs) require_inobs; - %rename(_require_inobs_nolist) require_inobs_nolist; %rename(_require_inobs_nocube) require_inobs_nocube; %rename(_log_observations) log_observations; %rename(_log_models) log_models; @@ -128,9 +128,11 @@ public: // Protected methods that check user parameters void require_inobs(const std::string& method); - void require_inobs_nolist(const std::string& method); void require_inobs_nocube(const std::string& method); + // Protected methods that extract user parameters + GCTARoi get_roi(void); + // Protected methods for logging void log_observations(const GChatter& chatter, const GObservations& obs, @@ -139,9 +141,6 @@ public: const GModels& models, const std::string& what = "Model"); - // Protected methods that extract user parameters - GCTARoi get_roi(void); - // Protected support methods void set_response(GObservations& obs); std::vector set_edisp(GObservations& obs, const bool& edisp) const; diff --git a/src/ctulimit/ctulimit.par b/src/ctulimit/ctulimit.par index dff2582..f891c7e 100644 --- a/src/ctulimit/ctulimit.par +++ b/src/ctulimit/ctulimit.par @@ -38,7 +38,7 @@ eref, r, h, 1.0,,, "Reference energy for differential limit (TeV)" emin, r, h, 1.0,,, "Minimum energy for integral flux limit (TeV)" emax, r, h, 100.0,,, "Maximum energy for integral flux limit (TeV)" tol, r, h, 1e-5,,, "Computation tolerance" -max_iter, i, h, 50,,, "Maximum number of iterations" +max_iter, i, h, 50,1,1000, "Maximum number of iterations" # # Standard parameters diff --git a/src/support/ctlikelihood.hpp b/src/support/ctlikelihood.hpp index 1463472..de450eb 100644 --- a/src/support/ctlikelihood.hpp +++ b/src/support/ctlikelihood.hpp @@ -61,15 +61,20 @@ public: // Methods const GOptimizer* opt(void) const; +#ifndef SWIG +protected: +#endif + // Protected methods in C++, public in SWIG interface + double evaluate(GModelPar& par, const double& value); + protected: // Protected methods void init_members(void); void copy_members(const ctlikelihood& app); void free_members(void); - double evaluate(GModelPar& par, const double& value); // Protected members - GOptimizerLM m_opt; //!< Optimizer + GOptimizerLM m_opt; //!< Optimizer }; diff --git a/src/support/ctobservation.hpp b/src/support/ctobservation.hpp index 908c3c1..7d5f9b2 100644 --- a/src/support/ctobservation.hpp +++ b/src/support/ctobservation.hpp @@ -64,9 +64,7 @@ public: // Methods const GObservations& obs(void) const; -#ifdef SWIG -public: -#else +#ifndef SWIG protected: #endif // Iterator methods and members diff --git a/src/support/ctool.cpp b/src/support/ctool.cpp index 1de9fc7..9d2566e 100644 --- a/src/support/ctool.cpp +++ b/src/support/ctool.cpp @@ -549,10 +549,10 @@ GEbounds ctool::create_ebounds(void) file.close(); std::string msg = "No extension with name \"EBOUNDS\" or" " \"ENERGYBINS\" found in FITS file" - " \""+ebinfile+"\".\n" - "An \"EBOUNDS\" or \"ENERGYBINS\" extension" - " is required if the parameter \"ebinalg\"" - " is set to \"FILE\"."; + " \""+ebinfile+"\". An \"EBOUNDS\" or " + "\"ENERGYBINS\" extension is required if " + "the parameter \"ebinalg\" is set to " + "\"FILE\"."; throw GException::invalid_value(G_CREATE_EBOUNDS, msg); } } @@ -788,6 +788,9 @@ GCTAObservation ctool::create_cta_obs(void) * * Throw an exception if the "inobs" parameter is either "NONE" or an empty * string. + * + * @todo This method is only used by csobsinfo, csresmap and csspec. We + * should try to get rid of it ***************************************************************************/ void ctool::require_inobs(const std::string& method) { @@ -810,63 +813,13 @@ void ctool::require_inobs(const std::string& method) /***********************************************************************//** - * @brief Throws exception if inobs parameter is an event list - * - * @param[in] method Method name. - * - * Throw an exception if the inobs parameter is an event list. - ***************************************************************************/ -void ctool::require_inobs_nolist(const std::string& method) -{ - // Get inobs filename - GFilename filename = (*this)["inobs"].filename(); - - // Continue only if we have a FITS file - if (filename.is_fits()) { - - // Signal no list - bool is_list = false; - - // Try loading file as counts cube. If this is successful then - // throw an exception - try { - - // Load list from file - GCTAEventList list(filename); - - // If we're still alive then signal that we have a list - is_list = true; - - } - - // Catch any exceptions - catch (...) { - ; - } - - // If we have an event list then throw an exception - if (is_list) { - std::string msg = "An event list has been specified for the " - "\"inobs\" parameter, yet no event list " - "can be specified as input observation." - " Instead, specify a counts cube or an " - "observation definition file."; - throw GException::invalid_value(method, msg); - } - - } // endif: we had a FITS file - - // Return - return; -} - - -/***********************************************************************//** * @brief Throws exception if inobs parameter is a counts cube * * @param[in] method Method name. * * Throw an exception if the inobs parameter is a counts cube. + * + * @todo This method is only used by ctobssim. We should try to get rid of it ***************************************************************************/ void ctool::require_inobs_nocube(const std::string& method) { @@ -1542,6 +1495,9 @@ GSkyDir ctool::get_mean_pointing(const GObservations& obs) * @brief Get current resident set size (physical memory use) in Bytes * * @return Physical memory use in Bytes. + * + * @todo This method is currently not used and can be removed if we do not + * use it ***************************************************************************/ size_t ctool::get_current_rss(void) { diff --git a/test/test_cscript.py b/test/test_cscript.py new file mode 100755 index 0000000..17f7d19 --- /dev/null +++ b/test/test_cscript.py @@ -0,0 +1,383 @@ +#! /usr/bin/env python +# ========================================================================== +# This scripts performs unit tests for the cspull script. +# +# Copyright (C) 2016 Juergen Knoedlseder +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# ========================================================================== +import gammalib +import ctools +from testing import test + + +# ================== # +# cscript_test class # +# ================== # +class cscript_test(ctools.cscript): + """ + Test class for the cscript base class + """ + # Constructor + def __init__(self, *argv): + """ + Constructor + """ + # Set name + self._name = 'cscript_test' + self._version = '1.2.0' + + # Initialise observation container from constructor arguments + self._obs, argv = self._set_input_obs(argv) + + # Initialise application by calling the appropriate class constructor + self._init_cscript(argv) + + # Return + return + + # Check is_valid_filename() method + def _check_is_valid_filename(self, filename): + return self._is_valid_filename(gammalib.GFilename(filename)) + + # Check setup_observations() method + def _check_setup_observations(self, filename, list=True, cube=True): + self.pars()['inobs'].value(filename) + obs = gammalib.GObservations() + self._setup_observations(obs, True, list, cube) + return + + # Check setup_models() method + def _check_setup_models(self): + obs = gammalib.GObservations() + self._setup_models(obs) + return + + # Check create_ebounds() method + def _check_create_ebounds(self, filename): + self.pars()['ebinfile'].value(filename) + return self._create_ebounds() + + # Check require_inobs() method + def _check_require_inobs(self, filename): + self.pars()['inobs'].value(filename) + self._require_inobs('_check_require_inobs') + return + + # Check get_roi() method + def _check_get_roi(self): + return self._get_roi() + + # Check restore_edisp() method + def _check_restore_edisp(self): + obs = gammalib.GObservations() + edisp = [True, True] + self._restore_edisp(obs, edisp) + return + + # Check set_obs_bounds() method + def _check_set_obs_bounds(self): + obs = gammalib.GObservations() + list = gammalib.GCTAEventList() + cta = gammalib.GCTAObservation() + cta.events(list) + obs.append(cta) + self._set_obs_bounds(obs) + return obs.copy() + + # Check get_mean_pointing() method + def _check_get_mean_pointing(self): + obs = gammalib.GObservations() + return self._get_mean_pointing(obs) + + +# ======================== # +# ctobservation_test class # +# ======================== # +class ctobservation_test(ctools.csobservation): + """ + Test class for the ctobservation base class + """ + # Constructor + def __init__(self, *argv): + """ + Constructor + """ + # Set name + self._name = 'ctobservation_test' + self._version = '1.2.0' + + # Initialise application by calling the appropriate class constructor + self._init_csobservation(argv) + + # Return + return + + +# ======================= # +# ctlikelihood_test class # +# ======================= # +class ctlikelihood_test(ctools.cslikelihood): + """ + Test class for the ctlikelihood base class + """ + # Constructor + def __init__(self, *argv): + """ + Constructor + """ + # Set name + self._name = 'ctlikelihood_test' + self._version = '1.2.0' + + # Initialise application by calling the appropriate class constructor + self._init_cslikelihood(argv) + + # Return + return + + # Check evaluate() method + def _check_evaluate(self, value): + par = gammalib.GModelPar() + par.value(2.0) + par.range(1.0, 3.0) + return self._evaluate(par, value) + + +# ============================ # +# Test class for base classes # +# ============================ # +class Test(test): + """ + Test class for base classes + """ + # Constructor + def __init__(self): + """ + Constructor + """ + # Call base class constructor + test.__init__(self) + + # Create parameter file for cscript_test application + pars = gammalib.GApplicationPars() + pars.append(gammalib.GApplicationPar('inobs','f','h','NONE','','','')) + pars.append(gammalib.GApplicationPar('inmodel','f','h','NONE','','','')) + pars.append(gammalib.GApplicationPar('ebinalg','s','h','FILE','','','')) + pars.append(gammalib.GApplicationPar('ebinfile','f','h','NONE','','','')) + pars.append(gammalib.GApplicationPar('ra','r','h','NONE','','','')) + pars.append(gammalib.GApplicationPar('dec','r','h','NONE','','','')) + pars.append(gammalib.GApplicationPar('rad','r','h','1.0','','','')) + pars.append(gammalib.GApplicationPar('emin','r','h','1.0','','','')) + pars.append(gammalib.GApplicationPar('emax','r','h','10.0','','','')) + pars.append_standard() + pars.save('cscript_test.par') + + # Create parameter file for ctobservation_test.par application + pars = gammalib.GApplicationPars() + pars.append_standard() + pars.save('ctobservation_test.par') + + # Create parameter file for ctlikelihood_test application + pars = gammalib.GApplicationPars() + pars.append_standard() + pars.save('ctlikelihood_test.par') + + # Create energy boundaries file + ebounds = gammalib.GEbounds(1, gammalib.GEnergy(1.0,'TeV'), + gammalib.GEnergy(10.0,'TeV')) + ebounds.save('test_ebinfile_ebounds.fits[EBOUNDS]', True) + ebounds.save('test_ebinfile_energybins.fits[ENERGYBINS]', True) + ebounds.save('test_ebinfile_energies.fits[ENERGIES]', True) + + # Return + return + + # Set test functions + def set(self): + """ + Set all test functions + """ + # Set test name + self.name('cscript') + + # Append tests + self.append(self._test_cscript, 'Test cscript base class') + self.append(self._test_ctobservation, 'Test ctobservation base class') + self.append(self._test_ctlikelihood, 'Test ctlikelihood base class') + + # Return + return + + # Test cscript base class + def _test_cscript(self): + """ + Test cscript base class + """ + # Allocate empty + empty = cscript_test() + + # Test is_valid_filename() method + self.test_assert(empty._check_is_valid_filename(self._model), + 'Check model definiton XML file') + self.test_assert(not empty._check_is_valid_filename(''), + 'Check empty filename') + self.test_assert(not empty._check_is_valid_filename('NONE'), + 'Check "NONE" filename') + + # Test setup_observations() for invalid file name + self.test_try('Check setup_observations() for "NONE"') + try: + empty._check_setup_observations('NONE') + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + + # Test setup_observations() for unacceptable event list + self.test_try('Check setup_observations() for unacceptable event list') + try: + empty._check_setup_observations(self._events, list=False) + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + + # Test setup_observations() for unacceptable counts cube + self.test_try('Check setup_observations() for unacceptable counts cube') + try: + empty._check_setup_observations(self._cntcube, cube=False) + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + + # Test setup_models() for invalid model definition file name + self.test_try('Check setup_models() for invalid model definition file name') + try: + empty._check_setup_models() + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + + # Test create_ebounds() method for "EBOUNDS" extension + ebounds = empty._check_create_ebounds('test_ebinfile_ebounds.fits') + self.test_value(ebounds.size(), 1, 'Check number of energy boundaries') + self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy') + self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy') + + # Test create_ebounds() method for "ENERGYBINS" extension + ebounds = empty._check_create_ebounds('test_ebinfile_energybins.fits') + self.test_value(ebounds.size(), 1, 'Check number of energy boundaries') + self.test_value(ebounds.emin().TeV(), 1.0, 'Check minimum energy') + self.test_value(ebounds.emax().TeV(), 10.0, 'Check maximum energy') + + # Test create_ebounds() method for invalid extension + self.test_try('Check create_ebounds() method for invalid extension') + try: + empty._check_create_ebounds('test_ebinfile_energies.fits') + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + + # Test require_inobs() method for invalid file name + self.test_try('Check require_inobs() method for invalid file name') + try: + empty._check_require_inobs('NONE') + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + + # Test get_roi() method + roi = empty._check_get_roi() + self.test_assert(not roi.is_valid(), 'Check get_roi() method') + + # Test restore_edisp() method for invalid vector size + #self.test_try('Check restore_edisp() method for invalid vector size') + #try: + # empty._check_restore_edisp() + # self.test_try_failure('Exception not thrown') + #except ValueError: + # self.test_try_success() + # + # NOTE: This code does not work because of a missing list to + # integer vector conversion. + + # Test set_obs_bounds() method + obs = empty._check_set_obs_bounds() + self.test_value(obs.size(), 1, 'Check number of observations') + self.test_value(obs[0].events().ebounds().size(), 1, + 'Check number of energy boundaries') + self.test_value(obs[0].events().ebounds().emin().TeV(), 1.0, + 'Check minimum energy') + self.test_value(obs[0].events().ebounds().emax().TeV(), 10.0, + 'Check maximum energy') + self.test_value(obs[0].events().roi().radius(), 1.0, + 'Check RoI radius') + + # Test get_mean_pointing() method for empty observation container + self.test_try('Check get_mean_pointing() method for empty observation ' + 'container') + try: + empty._check_get_mean_pointing() + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + + # Return + return + + # Test ctobservation base class + def _test_ctobservation(self): + """ + Test ctobservation base class + """ + # Allocate empty + empty = ctobservation_test() + + # Test first_unbinned_observation() method + self.test_assert(empty._first_unbinned_observation() is None, + 'Check first_unbinned_observation() method') + + # Test next_unbinned_observation() method + self.test_assert(empty._next_unbinned_observation() is None, + 'Check next_unbinned_observation() method') + + # Return + return + + # Test ctlikelihood base class + def _test_ctlikelihood(self): + """ + Test ctlikelihood base class + """ + # Allocate empty + empty = ctlikelihood_test() + + # Test evaluate() method for minimum value violation + self.test_try('Check evaluate() for minimum value violation') + try: + empty._check_evaluate(0.0) + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + + # Test evaluate() method for maximum value violation + self.test_try('Check evaluate() for maximum value violation') + try: + empty._check_evaluate(4.0) + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + + # Return + return diff --git a/test/test_ctskymap.py b/test/test_ctskymap.py index 25fd9e4..4c584a2 100755 --- a/test/test_ctskymap.py +++ b/test/test_ctskymap.py @@ -181,10 +181,10 @@ class Test(test): skymap['nxpix'] = 200 skymap['nypix'] = 200 skymap['binsz'] = 0.02 - skymap['coordsys'] = 'CEL' + skymap['coordsys'] = 'GAL' skymap['proj'] = 'CAR' - skymap['xref'] = 83.63 - skymap['yref'] = 22.01 + skymap['xref'] = 184.5575 + skymap['yref'] = -5.7844 skymap['outmap'] = 'ctskymap_py3.fits' skymap['logfile'] = 'ctskymap_py3.log' skymap['chatter'] = 4 diff --git a/test/test_ctulimit.py b/test/test_ctulimit.py index 9219c0f..73a0b66 100755 --- a/test/test_ctulimit.py +++ b/test/test_ctulimit.py @@ -111,6 +111,7 @@ class Test(test): 'Check upper limit on energy flux') # Check that saving does not nothing + ulimit['logfile'] = 'ctulimit_py0.log' ulimit.logFileOpen() ulimit.save() @@ -157,13 +158,6 @@ class Test(test): self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16, 'Check upper limit on energy flux') - # Execute copy of ctulimit tool again, now with a higher chatter - # level than before - cpy_ulimit['logfile'] = 'ctulimit_py2.log' - cpy_ulimit['chatter'] = 3 - cpy_ulimit.logFileOpen() # Needed to get a new log file - cpy_ulimit.execute() - # Check results self.test_value(cpy_ulimit.diff_ulimit(), 8.86803e-18, 1.0e-21, 'Check differential upper limit') @@ -172,9 +166,6 @@ class Test(test): self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16, 'Check upper limit on energy flux') - # Save copy of observation container for later - obs = cpy_ulimit.obs().copy() - # Now clear copy of ctulimit tool cpy_ulimit.clear() @@ -186,13 +177,21 @@ class Test(test): self.test_value(cpy_ulimit.eflux_ulimit(), 0.0, 1.0e-16, 'Check upper limit on energy flux') - # Now set ctulimit tool using the observation container from last - # time. This should avoid the necessity to recompute the maximum - # likelihood - ulimit = ctools.ctulimit(obs) + # Run ctlike to get an initial log-likelihood solution + like = ctools.ctlike() + like['inobs'] = self._events + like['inmodel'] = self._model + like['caldb'] = self._caldb + like['irf'] = self._irf + like.run() + + # Now set ctulimit tool using the observation container from the + # previous run. This should avoid the necessity to recompute the + # maximum likelihood + ulimit = ctools.ctulimit(like.obs()) ulimit['srcname'] = 'Crab' - ulimit['logfile'] = 'ctulimit_py3.log' - ulimit['chatter'] = 4 + ulimit['logfile'] = 'ctulimit_py2.log' + ulimit['chatter'] = 3 # Execute ctulimit tool ulimit.logFileOpen() # Needed to get a new log file @@ -207,11 +206,11 @@ class Test(test): 'Check upper limit on energy flux') # Test invalid model name + ulimit['srcname'] = 'Weihnachtsstern' + ulimit['logfile'] = 'ctulimit_py3.log' + ulimit.logFileOpen() self.test_try('Test invalid model name') try: - ulimit['srcname'] = 'Weihnachtsstern' - ulimit['logfile'] = 'ctulimit_py4.log' - ulimit.logFileOpen() ulimit.execute() self.test_try_failure('Exception not thrown') except ValueError: @@ -219,7 +218,7 @@ class Test(test): # Test specification of background model ulimit['srcname'] = 'Background' - ulimit['logfile'] = 'ctulimit_py5.log' + ulimit['logfile'] = 'ctulimit_py4.log' ulimit.logFileOpen() self.test_try('Test invalid model name') try: @@ -228,6 +227,18 @@ class Test(test): except ValueError: self.test_try_success() + # Test run with too few iterations + ulimit['srcname'] = 'Crab' + ulimit['max_iter'] = 1 + ulimit['logfile'] = 'ctulimit_py5.log' + ulimit.logFileOpen() + self.test_try('Test ctulimit with too few iterations') + try: + ulimit.execute() + self.test_try_failure('Exception not thrown') + except ValueError: + self.test_try_success() + # Return return diff --git a/test/test_python_cscripts.py b/test/test_python_cscripts.py index 541dd22..82efb66 100755 --- a/test/test_python_cscripts.py +++ b/test/test_python_cscripts.py @@ -23,6 +23,7 @@ import sys import gammalib import cscripts sys.path.append(os.path.dirname(os.path.abspath(__file__))) +import test_cscript import test_cscaldb import test_csfindobs import test_csinfo @@ -105,65 +106,25 @@ def test(installed=False, debug=False): os.system('cp -r %s/syspfiles/*.par pfiles/' % (os.environ['CTOOLS'])) os.system('chmod u+w pfiles/*') - # Allocate test suite container - suites = gammalib.GTestSuites('cscripts unit testing') - - # Allocate test suites - suite_cscaldb = test_cscaldb.Test() - suite_csinfo = test_csinfo.Test() - suite_cslightcrv = test_cslightcrv.Test() - suite_csmodelinfo = test_csmodelinfo.Test() - suite_csmodelmerge = test_csmodelmerge.Test() - suite_csobs2caldb = test_csobs2caldb.Test() - suite_csobsdef = test_csobsdef.Test() - suite_csobsinfo = test_csobsinfo.Test() - suite_cspull = test_cspull.Test() - suite_csresmap = test_csresmap.Test() - suite_csroot2caldb = test_csroot2caldb.Test() - suite_cssens = test_cssens.Test() - suite_csspec = test_csspec.Test() - suite_cstsdist = test_cstsdist.Test() - suite_cstsmapmerge = test_cstsmapmerge.Test() - suite_cstsmapsplit = test_cstsmapsplit.Test() - suite_csworkflow = test_csworkflow.Test() - - # Setup unit tests - suite_cscaldb.set() - suite_csinfo.set() - suite_cslightcrv.set() - suite_csmodelinfo.set() - suite_csmodelmerge.set() - suite_csobs2caldb.set() - suite_csobsdef.set() - suite_csobsinfo.set() - suite_cspull.set() - suite_csresmap.set() - suite_csroot2caldb.set() - suite_cssens.set() - suite_csspec.set() - suite_cstsdist.set() - suite_cstsmapmerge.set() - suite_cstsmapsplit.set() - suite_csworkflow.set() - - # Append tests to container - suites.append(suite_cscaldb) - suites.append(suite_csinfo) - suites.append(suite_cslightcrv) - suites.append(suite_csmodelinfo) - suites.append(suite_csmodelmerge) - suites.append(suite_csobs2caldb) - suites.append(suite_csobsdef) - suites.append(suite_csobsinfo) - suites.append(suite_cspull) - suites.append(suite_csresmap) - suites.append(suite_csroot2caldb) - suites.append(suite_cssens) - suites.append(suite_csspec) - suites.append(suite_cstsdist) - suites.append(suite_cstsmapmerge) - suites.append(suite_cstsmapsplit) - suites.append(suite_csworkflow) + # Define list of test suites + tests = [test_cscript.Test(), + test_cscaldb.Test(), + test_csinfo.Test(), + test_cslightcrv.Test(), + test_csmodelinfo.Test(), + test_csmodelmerge.Test(), + test_csobs2caldb.Test(), + test_csobsdef.Test(), + test_csobsinfo.Test(), + test_cspull.Test(), + test_csresmap.Test(), + test_csroot2caldb.Test(), + test_cssens.Test(), + test_csspec.Test(), + test_cstsdist.Test(), + test_cstsmapmerge.Test(), + test_cstsmapsplit.Test(), + test_csworkflow.Test()] # Append tests for Python 2.6+ (the IACT cscripts depend on the json # module which is only available since Python 2.6+) @@ -178,23 +139,19 @@ def test(installed=False, debug=False): # impact the environment variable in the parent shell. del os.environ['VHEFITS'] - # Allocate test suites - suite_csfindobs = test_csfindobs.Test() - suite_csiactcopy = test_csiactcopy.Test() - suite_csiactdata = test_csiactdata.Test() - suite_csiactobs = test_csiactobs.Test() - - # Setup unit tests - suite_csfindobs.set() - suite_csiactcopy.set() - suite_csiactdata.set() - suite_csiactobs.set() - - # Append tests to container - suites.append(suite_csfindobs) - suites.append(suite_csiactcopy) - suites.append(suite_csiactdata) - suites.append(suite_csiactobs) + # Append IACT script tests to list of test suites + tests.extend([test_csfindobs.Test(), + test_csiactcopy.Test(), + test_csiactdata.Test(), + test_csiactobs.Test()]) + + # Allocate test suite container + suites = gammalib.GTestSuites('cscripts unit testing') + + # Set test suites and append them to suite container + for suite in tests: + suite.set() + suites.append(suite) # Run test suite success = suites.run() diff --git a/test/test_python_ctools.py b/test/test_python_ctools.py index 14372eb..37ecbf9 100755 --- a/test/test_python_ctools.py +++ b/test/test_python_ctools.py @@ -99,65 +99,32 @@ def test(installed=False): os.system('cp -r %s/syspfiles/*.par pfiles/' % (os.environ['CTOOLS'])) os.system('chmod u+w pfiles/*') + # Define list of test suites + tests = [test_ctobssim.Test(), + test_ctselect.Test(), + test_ctbin.Test(), + test_ctlike.Test(), + test_cttsmap.Test(), + test_ctmodel.Test(), + test_ctskymap.Test(), + test_ctexpcube.Test(), + test_ctpsfcube.Test(), + test_ctedispcube.Test(), + test_ctbkgcube.Test(), + test_ctmapcube.Test(), + test_ctcubemask.Test(), + test_ctbutterfly.Test(), + test_ctulimit.Test(), + test_cterror.Test(), + test_pipelines.Test()] + # Allocate test suite container suites = gammalib.GTestSuites('ctools unit testing') - # Allocate test suites and append them to the container - suite_ctobssim = test_ctobssim.Test() - suite_ctselect = test_ctselect.Test() - suite_ctbin = test_ctbin.Test() - suite_ctlike = test_ctlike.Test() - suite_cttsmap = test_cttsmap.Test() - suite_ctmodel = test_ctmodel.Test() - suite_ctskymap = test_ctskymap.Test() - suite_ctexpcube = test_ctexpcube.Test() - suite_ctpsfcube = test_ctpsfcube.Test() - suite_ctedispcube = test_ctedispcube.Test() - suite_ctbkgcube = test_ctbkgcube.Test() - suite_ctmapcube = test_ctmapcube.Test() - suite_ctcubemask = test_ctcubemask.Test() - suite_ctbutterfly = test_ctbutterfly.Test() - suite_ctulimit = test_ctulimit.Test() - suite_cterror = test_cterror.Test() - suite_pipelines = test_pipelines.Test() - - # Setup unit tests - suite_ctobssim.set() - suite_ctselect.set() - suite_ctbin.set() - suite_ctlike.set() - suite_cttsmap.set() - suite_ctmodel.set() - suite_ctskymap.set() - suite_ctexpcube.set() - suite_ctpsfcube.set() - suite_ctedispcube.set() - suite_ctbkgcube.set() - suite_ctmapcube.set() - suite_ctcubemask.set() - suite_ctbutterfly.set() - suite_ctulimit.set() - suite_cterror.set() - suite_pipelines.set() - - # Append tests to container - suites.append(suite_ctobssim) - suites.append(suite_ctselect) - suites.append(suite_ctbin) - suites.append(suite_ctlike) - suites.append(suite_cttsmap) - suites.append(suite_ctmodel) - suites.append(suite_ctskymap) - suites.append(suite_ctexpcube) - suites.append(suite_ctpsfcube) - suites.append(suite_ctedispcube) - suites.append(suite_ctbkgcube) - suites.append(suite_ctmapcube) - suites.append(suite_ctcubemask) - suites.append(suite_ctbutterfly) - suites.append(suite_ctulimit) - suites.append(suite_cterror) - suites.append(suite_pipelines) + # Set test suites and append them to suite container + for suite in tests: + suite.set() + suites.append(suite) # Run test suite success = suites.run()