diff --git a/ChangeLog b/ChangeLog index a2d81f0..e1a353b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017-06-22 +2017-07-22 * Version 1.4.0 released ========================= diff --git a/NEWS b/NEWS index d41925d..f9a66f1 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ New Features and Important Changes in GammaLib 1.4.0 -22 June 2017 +22 July 2017 1. Introduction @@ -21,7 +21,13 @@ The following classes have been renamed: - n.a. The following methods have been added: -- n.a. +- GSkyRegion::type(std::string&) +- GSkyRegion::name(std::string&) +- GSkyRegion::solidangle(std::string&) +- GOptimizerPars::append(GOptimizerPar&) +- GLATEventList::append(GLATEventAtom&) +- GLATEventList::reserve(int&) +- GLATEventList::remove(int&,int&) The following methods have been removed: - n.a. @@ -78,12 +84,13 @@ None 11. Optimization module ----------------------- -None +Add GOptimizerPars::append() method to allow appending of parameters to the +container. 12. Sky module -------------- -None +Add methods to set the name, type and solid angle of a sky region. 13. Support module @@ -118,7 +125,7 @@ None 19. Fermi-LAT interface ---------------------- -None +Add append(), remove() and reserve() methods to GLATEventList class. 20. CTA interface diff --git a/include/GOptimizerPars.hpp b/include/GOptimizerPars.hpp index a7336c3..c06afee 100644 --- a/include/GOptimizerPars.hpp +++ b/include/GOptimizerPars.hpp @@ -1,7 +1,7 @@ /*************************************************************************** * GOptimizerPars.hpp - Optimizer parameter container class * * ----------------------------------------------------------------------- * - * copyright (C) 2009-2015 by Juergen Knoedlseder * + * copyright (C) 2009-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -75,6 +75,7 @@ public: int nfree(void) const; GOptimizerPar* set(const int& index, const GOptimizerPar& par); GOptimizerPar* set(const std::string& name, const GOptimizerPar& par); + GOptimizerPar* append(const GOptimizerPar& par); void attach(GOptimizerPar* par); void attach(const int& index, GOptimizerPar* par); void attach(const std::string& name, GOptimizerPar* par); diff --git a/include/GSkyRegion.hpp b/include/GSkyRegion.hpp index 652f91d..4867cd7 100644 --- a/include/GSkyRegion.hpp +++ b/include/GSkyRegion.hpp @@ -1,7 +1,7 @@ /*************************************************************************** * GSkyRegion.hpp - Abstract virtual sky region base class * * ----------------------------------------------------------------------- * - * copyright (C) 2013-2014 by Pierrick Martin * + * copyright (C) 2013-2017 by Pierrick Martin * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -80,6 +80,9 @@ public: const std::string& type(void) const; const std::string& name(void) const; const double& solidangle(void) const; + void type(const std::string& type); + void name(const std::string& name); + void solidangle(const double& solidangle); protected: // Protected methods @@ -109,6 +112,21 @@ const std::string& GSkyRegion::name(void) const /***********************************************************************//** + * @brief Set region name + * + * @param[in] name Region name. + * + * Sets the region name. + ***************************************************************************/ +inline +void GSkyRegion::name(const std::string& name) +{ + m_name = name; + return; +} + + +/***********************************************************************//** * @brief Return region type * * @return Region type @@ -123,16 +141,46 @@ const std::string& GSkyRegion::type(void) const /***********************************************************************//** - * @brief Return solid angle + * @brief Set region type + * + * @param[in] type Region type. + * + * Sets the region type. + ***************************************************************************/ +inline +void GSkyRegion::type(const std::string& type) +{ + m_type = type; + return; +} + + +/***********************************************************************//** + * @brief Return solid angle of region * - * @return Solid angle + * @return Solid angle of region. * - * Returns the solid angle subtended by the region (in steradian). + * Returns the solid angle subtended by the region (in steradians). ***************************************************************************/ inline const double& GSkyRegion::solidangle(void) const { return (m_solid); } - + + +/***********************************************************************//** + * @brief Set solid angle of region + * + * @param[in] solidangle Solid angle of region (in steradians). + * + * Sets the solid angle subtended by the region (in steradians). + ***************************************************************************/ +inline +void GSkyRegion::solidangle(const double& solidangle) +{ + m_solid = solidangle; + return; +} + #endif /* GSKYREGION_HPP */ diff --git a/inst/cta/pyext/GCTAEventList.i b/inst/cta/pyext/GCTAEventList.i index cb8e864..c77f7bf 100644 --- a/inst/cta/pyext/GCTAEventList.i +++ b/inst/cta/pyext/GCTAEventList.i @@ -90,19 +90,64 @@ public: * @brief GCTAEventList class extension ***************************************************************************/ %extend GCTAEventList { - GCTAEventList copy() { - return (*self); - } - GCTAEventAtom* __getitem__(int index) { - if (index >= 0 && index < self->size()) + GCTAEventAtom* __getitem__(const int& index) { + // Counting from start, e.g. [2] + if (index >= 0 && index < self->size()) { return (*self)[index]; - else - throw GException::out_of_range("__getitem__(int)", index, self->size()); + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; + } + else { + throw GException::out_of_range("__getitem__(int)", "Event index", + index, self->size()); + } + } + GCTAEventList* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GCTAEventList* list = new GCTAEventList; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + list->append(*(*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + list->append(*(*self)[i]); + } + } + return list; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } } - void __setitem__(int index, const GCTAEventAtom& val) { - if (index>=0 && index < self->size()) - *((*self)[index]) = val; - else - throw GException::out_of_range("__setitem__(int)", index, self->size()); + void __setitem__(const int& index, const GCTAEventAtom& event) { + // Counting from start, e.g. [2] + if (index >= 0 && index < self->size()) { + *(*self)[index] = event; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + *(*self)[self->size()+index] = event; + } + else { + throw GException::out_of_range("__setitem__(int)", "Event index", + index, self->size()); + } + } + GCTAEventList copy() { + return (*self); } }; diff --git a/inst/cta/test/test_CTA.py b/inst/cta/test/test_CTA.py index 21deb4e..2d7ae4a 100755 --- a/inst/cta/test/test_CTA.py +++ b/inst/cta/test/test_CTA.py @@ -20,6 +20,7 @@ import os import gammalib import math +import test_support # ================================== # @@ -27,12 +28,12 @@ import math # ================================== # class Test(gammalib.GPythonTestSuite): """ - Test class for GammaLib CTA module. + Test class for GammaLib CTA module """ # Constructor def __init__(self): """ - Constructor. + Constructor """ # Call base class constructor gammalib.GPythonTestSuite.__init__(self) @@ -44,28 +45,58 @@ class Test(gammalib.GPythonTestSuite): # Return return - # Set test functions - def set(self): + # Setup GCTAEventList container + def _setup_eventlist(self): """ - Set all test functions. + Setup GCTAEventList container + + Returns + ------- + list : `~gammalib.GCTAEventList` + GCTAEventList container """ - # Set test name - self.name('CTA') + # Setup event list container + list = gammalib.GCTAEventList() + atom = gammalib.GCTAEventAtom() + for i in range(10): + atom.energy().MeV(float(i)) + list.append(atom) + + # Return event list container + return list + + # Test GCTAEventList class access operators + def _test_eventlist_access(self): + """ + Test GCTAEventList class observation access + """ + # Setup event list container + list = self._setup_eventlist() - # Append tests - self.append(self.test_aeff, 'Test CTA effective area classes') - self.append(self.test_psf, 'Test CTA PSF classes') - self.append(self.test_edisp, 'Test CTA energy dispersion classes') - self.append(self.test_response, 'Test CTA response classes') - self.append(self.test_onoff, 'Test CTA On/Off analysis') + # Perform event list access tests + test_support._energy_container_access_index(self, list) + + # Return + return + + # Test GCTAEventList class slicing + def _test_eventlist_slicing(self): + """ + Test GCTAEventList class slicing + """ + # Setup event list container + list = self._setup_eventlist() + + # Perform slicing tests + test_support._energy_container_slicing(self, list) # Return return # Test effective area response - def test_aeff(self): + def _test_aeff(self): """ - Test GCTAAeff classes. + Test GCTAAeff classes """ # Test GCTAAeff2D file constructor filename = self._caldb + '/prod1_gauss.fits' @@ -119,9 +150,9 @@ class Test(gammalib.GPythonTestSuite): return # Test point spread function response - def test_psf(self): + def _test_psf(self): """ - Test GCTAPsf classes. + Test GCTAPsf classes """ # Test GCTAPsf2D file constructor filename = self._caldb + '/prod1_gauss.fits' @@ -175,9 +206,9 @@ class Test(gammalib.GPythonTestSuite): return # Test energy dispersion - def test_edisp(self): + def _test_edisp(self): """ - Test GCTAEdisp classes. + Test GCTAEdisp classes """ # Test GCTAEdispRmf file constructor filename = self._caldb + '/dc1/rmf.fits' @@ -222,7 +253,7 @@ class Test(gammalib.GPythonTestSuite): # 0.5, 0.005) # Test response - def test_response(self): + def _test_response(self): """ Test response classes """ @@ -234,9 +265,9 @@ class Test(gammalib.GPythonTestSuite): return # Test On/Off analysis - def test_onoff(self): + def _test_onoff(self): """ - Test On/Off analysis. + Test On/Off analysis """ # Create On region crab = gammalib.GSkyDir() @@ -271,9 +302,6 @@ class Test(gammalib.GPythonTestSuite): lm = gammalib.GOptimizerLM() outobs.optimize(lm) outobs.errors(lm) - #print(lm) - #print(outobs) - #print(outobs.models()) # Test On/Off model fitting results sky = outobs.models()['Crab'] @@ -307,3 +335,23 @@ class Test(gammalib.GPythonTestSuite): # Return return + + # Set test functions + def set(self): + """ + Set all test functions. + """ + # Set test name + self.name('CTA') + + # Append tests + self.append(self._test_eventlist_access, 'Test GCTAEventList event access') + self.append(self._test_eventlist_slicing, 'Test GCTAEventList slicing') + self.append(self._test_aeff, 'Test CTA effective area classes') + self.append(self._test_psf, 'Test CTA PSF classes') + self.append(self._test_edisp, 'Test CTA energy dispersion classes') + self.append(self._test_response, 'Test CTA response classes') + self.append(self._test_onoff, 'Test CTA On/Off analysis') + + # Return + return diff --git a/inst/lat/include/GLATEventList.hpp b/inst/lat/include/GLATEventList.hpp index 6ee0f62..ce2c446 100644 --- a/inst/lat/include/GLATEventList.hpp +++ b/inst/lat/include/GLATEventList.hpp @@ -61,7 +61,7 @@ public: virtual ~GLATEventList(void); // Operators - virtual GLATEventList& operator= (const GLATEventList& list); + virtual GLATEventList& operator=(const GLATEventList& list); virtual GLATEventAtom* operator[](const int& index); virtual const GLATEventAtom* operator[](const int& index) const; @@ -81,6 +81,9 @@ public: virtual std::string print(const GChatter& chatter = NORMAL) const; // Other methods + void append(const GLATEventAtom& event); + void reserve(const int& number); + void remove(const int& index, const int& number = 1); protected: // Protected methods @@ -93,13 +96,13 @@ protected: void read_ds_keys(const GFitsHDU& hdu); // Protected members - GLATRoi m_roi; //!< Region of interest - std::vector m_events; //!< Events - std::vector m_difrsp_label; //!< Diffuse response model labels - std::vector m_ds_type; //!< Data selection types - std::vector m_ds_unit; //!< Data selection units - std::vector m_ds_value; //!< Data selection values - std::vector m_ds_reference; //!< Data selection references + GLATRoi m_roi; //!< Region of interest + std::vector m_events; //!< Events + std::vector m_difrsp_label; //!< Diffuse response model labels + std::vector m_ds_type; //!< Data selection types + std::vector m_ds_unit; //!< Data selection units + std::vector m_ds_value; //!< Data selection values + std::vector m_ds_reference; //!< Data selection references }; @@ -150,4 +153,19 @@ const GLATRoi& GLATEventList::roi(void) const return m_roi; } + +/***********************************************************************//** + * @brief Reserves space for events + * + * @param[in] number Number of events. + * + * Reserves space for number events in the event list. + ***************************************************************************/ +inline +void GLATEventList::reserve(const int& number) +{ + m_events.reserve(number); + return; +} + #endif /* GLATEVENTLIST_HPP */ diff --git a/inst/lat/pyext/GLATEventList.i b/inst/lat/pyext/GLATEventList.i index 2769026..7b919f4 100644 --- a/inst/lat/pyext/GLATEventList.i +++ b/inst/lat/pyext/GLATEventList.i @@ -1,7 +1,7 @@ /*************************************************************************** * GLATEventList.i - Fermi/LAT event list class * * ----------------------------------------------------------------------- * - * copyright (C) 2012-2016 by Juergen Knoedlseder * + * copyright (C) 2012-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -56,6 +56,11 @@ public: virtual int number(void) const; virtual void roi(const GRoi& roi); virtual const GLATRoi& roi(void) const; + + // Other methods + void append(const GLATEventAtom& event); + void reserve(const int& number); + void remove(const int& index, const int& number = 1); }; @@ -63,25 +68,64 @@ public: * @brief GLATEventList class extension ***************************************************************************/ %extend GLATEventList { - GLATEventList copy() { - return (*self); - } GLATEventAtom* __getitem__(const int& index) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { - return ((*self)[index]); + return (*self)[index]; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; } else { throw GException::out_of_range("__getitem__(int)", "Event index", index, self->size()); } } - void __setitem__(const int& index, const GLATEventAtom& value) { - if (index>=0 && index < self->size()) { - *((*self)[index]) = value; + GLATEventList* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GLATEventList* list = new GLATEventList; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + list->append(*(*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + list->append(*(*self)[i]); + } + } + return list; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } + } + void __setitem__(const int& index, const GLATEventAtom& event) { + // Counting from start, e.g. [2] + if (index >= 0 && index < self->size()) { + *(*self)[index] = event; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + *(*self)[self->size()+index] = event; } else { throw GException::out_of_range("__setitem__(int)", "Event index", index, self->size()); } } + GLATEventList copy() { + return (*self); + } }; diff --git a/inst/lat/src/GLATEventList.cpp b/inst/lat/src/GLATEventList.cpp index fb16e9d..e1c0b55 100644 --- a/inst/lat/src/GLATEventList.cpp +++ b/inst/lat/src/GLATEventList.cpp @@ -384,9 +384,56 @@ void GLATEventList::roi(const GRoi& roi) /***********************************************************************//** + * @brief Append event to event list + * + * @param[in] event Event. + * + * Appends an event to the end of the event list. + ***************************************************************************/ +void GLATEventList::append(const GLATEventAtom& event) +{ + // Append event + m_events.push_back(event); + + // Return + return; +} + + +/***********************************************************************//** + * @brief Remove events from event list + * + * @param[in] index Index from which on events should be removed. + * @param[in] number Number of event to remove (default: 1). + * + * Removes events from the event list. This method does nothing if @p index + * points beyond the event list. The method does also gently accept + * @p number arguments where @p index + @p number reach beyond the event + * list. In that case, all events from event @p index on will be removed. + ***************************************************************************/ +void GLATEventList::remove(const int& index, const int& number) +{ + // Continue only if index is valid + if (index < size()) { + + // Determine number of elements to remove + int n_remove = (index + number > size()) ? size() - index : number; + + // Remove events + m_events.erase(m_events.begin() + index, + m_events.begin() + index + n_remove); + + } // endif: index was valid + + // Return + return; +} + + +/***********************************************************************//** * @brief Print event list information * - * @param[in] chatter Chattiness (defaults to NORMAL). + * @param[in] chatter Chattiness. * @return String containing event list information. ***************************************************************************/ std::string GLATEventList::print(const GChatter& chatter) const diff --git a/inst/lat/test/test_LAT.py b/inst/lat/test/test_LAT.py index b5b23c6..7ffa9cf 100755 --- a/inst/lat/test/test_LAT.py +++ b/inst/lat/test/test_LAT.py @@ -1,7 +1,7 @@ # ========================================================================== # This module performs unit tests for the GammaLib LAT module. # -# Copyright (C) 2012-2015 Juergen Knoedlseder +# Copyright (C) 2012-2017 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 @@ -18,6 +18,7 @@ # # ========================================================================== import gammalib +import test_support # ================================== # @@ -25,12 +26,12 @@ import gammalib # ================================== # class Test(gammalib.GPythonTestSuite): """ - Test class for GammaLib LAT module. + Test class for GammaLib LAT module """ # Constructor def __init__(self): """ - Constructor. + Constructor """ # Call base class constructor gammalib.GPythonTestSuite.__init__(self) @@ -38,24 +39,65 @@ class Test(gammalib.GPythonTestSuite): # Return return - # Set test functions - def set(self): + # Setup GLATEventList container + def _setup_eventlist(self): """ - Set all test functions. + Setup GLATEventList container + + Returns + ------- + list : `~gammalib.GLATEventList` + GLATEventList container """ - # Set test name - self.name("LAT") + # Setup event list container + list = gammalib.GLATEventList() + atom = gammalib.GLATEventAtom() + for i in range(10): + atom.energy().MeV(float(i)) + list.append(atom) - # Append tests - self.append(self.test, "LAT dummy test") + # Return event list container + return list + + # Test GLATEventList class access operators + def _test_eventlist_access(self): + """ + Test GLATEventList class observation access + """ + # Setup event list container + list = self._setup_eventlist() + + # Perform event list access tests + test_support._energy_container_access_index(self, list) + + # Return + return + + # Test GLATEventList class slicing + def _test_eventlist_slicing(self): + """ + Test GLATEventList class slicing + """ + # Setup event list container + list = self._setup_eventlist() + + # Perform slicing tests + test_support._energy_container_slicing(self, list) # Return return - # Test function - def test(self): + # Set test functions + def set(self): """ - Test function. + Set all test functions. """ + # Set test name + self.name('LAT') + + # Append tests + self.append(self._test_eventlist_access, 'Test GLATEventList event access') + self.append(self._test_eventlist_slicing, 'Test GLATEventList slicing') + # Return return diff --git a/pyext/GFits.i b/pyext/GFits.i index 9d75886..ece9135 100644 --- a/pyext/GFits.i +++ b/pyext/GFits.i @@ -1,7 +1,7 @@ /*************************************************************************** * GFits.i - FITS file class * * ----------------------------------------------------------------------- * - * copyright (C) 2008-2016 by Juergen Knoedlseder * + * copyright (C) 2008-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -100,9 +100,14 @@ public: ***************************************************************************/ %extend GFits { GFitsHDU* __getitem__(const int& extno) { + // Counting from start, e.g. [2] if (extno >= 0 && extno < self->size()) { return (*self)[extno]; } + // Counting from end, e.g. [-1] + else if (extno < 0 && self->size()+extno >= 0) { + return (*self)[self->size()+extno]; + } else { throw GException::out_of_range("__getitem__(int)", "Extension number", @@ -112,10 +117,43 @@ public: GFitsHDU* __getitem__(const std::string& extname) { return (*self)[extname]; } + GFits* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GFits* fits = new GFits; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + fits->append(*(*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + fits->append(*(*self)[i]); + } + } + return fits; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } + } void __setitem__(const int& extno, const GFitsHDU& hdu) { + // Counting from start, e.g. [2] if (extno >= 0 && extno < self->size()) { self->set(extno, hdu); - return; + } + // Counting from end, e.g. [-1] + else if (extno < 0 && self->size()+extno >= 0) { + self->set(self->size()+extno, hdu); } else { throw GException::out_of_range("__setitem__(int)", diff --git a/pyext/GFitsHeader.i b/pyext/GFitsHeader.i index 1752560..8ec041c 100644 --- a/pyext/GFitsHeader.i +++ b/pyext/GFitsHeader.i @@ -1,7 +1,7 @@ /*************************************************************************** - * GFitsHeader.i - FITS header cards container class * + * GFitsHeader.i - FITS header cards container class * * ----------------------------------------------------------------------- * - * copyright (C) 2008-2015 by Juergen Knoedlseder * + * copyright (C) 2008-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -29,15 +29,13 @@ #include "GTools.hpp" %} -//%include stl.i - /***********************************************************************//** * @class GFitsHeader * * @brief Interface for FITS header class ***************************************************************************/ -class GFitsHeader : public GBase { +class GFitsHeader : public GContainer { public: // Constructors and destructors GFitsHeader(void); @@ -77,9 +75,14 @@ public: ***************************************************************************/ %extend GFitsHeader { GFitsHeaderCard& __getitem__(const int& cardno) { + // Counting from start, e.g. [2] if (cardno >= 0 && cardno < self->size()) { return (*self)[cardno]; } + // Counting from end, e.g. [-1] + else if (cardno < 0 && self->size()+cardno >= 0) { + return (*self)[self->size()+cardno]; + } else { throw GException::out_of_range("__getitem__(int)", "Header card number", @@ -89,10 +92,43 @@ public: GFitsHeaderCard& __getitem__(const std::string& keyname) { return (*self)[keyname]; } + GFitsHeader* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GFitsHeader* header = new GFitsHeader; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + header->append((*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + header->append((*self)[i]); + } + } + return header; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } + } void __setitem__(const int& cardno, const GFitsHeaderCard& card) { + // Counting from start, e.g. [2] if (cardno >= 0 && cardno < self->size()) { (*self)[cardno] = card; - return; + } + // Counting from end, e.g. [-1] + else if (cardno < 0 && self->size()+cardno >= 0) { + (*self)[self->size()+cardno] = card; } else { throw GException::out_of_range("__setitem__(int)", diff --git a/pyext/GNodeArray.i b/pyext/GNodeArray.i index a38ce46..ac1c921 100644 --- a/pyext/GNodeArray.i +++ b/pyext/GNodeArray.i @@ -86,17 +86,55 @@ public: ***************************************************************************/ %extend GNodeArray { double __getitem__(const int& index) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { return (*self)[index]; } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; + } else { throw GException::out_of_range("__getitem__(int)", index, self->size()); } } + GNodeArray* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GNodeArray* nodes = new GNodeArray; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + nodes->append((*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + nodes->append((*self)[i]); + } + } + return nodes; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } + } void __setitem__(const int& index, const double& val) { - if (index>=0 && index < self->size()) { + // Counting from start, e.g. [2] + if (index >= 0 && index < self->size()) { (*self)[index] = val; - return; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + (*self)[self->size()+index] = val; } else { throw GException::out_of_range("__setitem__(int)", index, self->size()); diff --git a/pyext/GOptimizerPars.i b/pyext/GOptimizerPars.i index 10d3099..ed2f7d4 100644 --- a/pyext/GOptimizerPars.i +++ b/pyext/GOptimizerPars.i @@ -1,7 +1,7 @@ /*************************************************************************** * GOptimizerPars.i - Optimizer parameter container class * * ----------------------------------------------------------------------- * - * copyright (C) 2009-2015 by Juergen Knoedlseder * + * copyright (C) 2009-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -52,6 +52,7 @@ public: int nfree(void) const; GOptimizerPar* set(const int& index, const GOptimizerPar& par); GOptimizerPar* set(const std::string& name, const GOptimizerPar& par); + GOptimizerPar* append(const GOptimizerPar& par); void attach(GOptimizerPar *par); void attach(const int& index, GOptimizerPar* par); void attach(const std::string& name, GOptimizerPar* par); @@ -70,9 +71,14 @@ public: ***************************************************************************/ %extend GOptimizerPars { GOptimizerPar* __getitem__(const int& index) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { return (*self)[index]; } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; + } else { throw GException::out_of_range("__getitem__(int)", "Parameter index", index, self->size()); @@ -81,10 +87,43 @@ public: GOptimizerPar* __getitem__(const std::string& name) { return (*self)[name]; } + GOptimizerPars* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GOptimizerPars* pars = new GOptimizerPars; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + pars->attach((*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + pars->attach((*self)[i]); + } + } + return pars; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } + } void __setitem__(const int& index, GOptimizerPar* par) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { self->attach(index, par); - return; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + self->attach(self->size()+index, par); } else { throw GException::out_of_range("__setitem__(int)", "Parameter index", diff --git a/pyext/GSkyRegion.i b/pyext/GSkyRegion.i index e854f7f..2f34496 100644 --- a/pyext/GSkyRegion.i +++ b/pyext/GSkyRegion.i @@ -1,7 +1,7 @@ /*************************************************************************** * GSkyRegion.i - Sky region class * * ----------------------------------------------------------------------- * - * copyright (C) 2013-2015 by Michael Mayer * + * copyright (C) 2013-2017 by Michael Mayer * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -55,6 +55,9 @@ public: const std::string& type(void) const; const std::string& name(void) const; const double& solidangle(void) const; + void type(const std::string& type); + void name(const std::string& name); + void solidangle(const double& solidangle); }; diff --git a/pyext/GSkyRegions.i b/pyext/GSkyRegions.i index efbb521..4723a3c 100644 --- a/pyext/GSkyRegions.i +++ b/pyext/GSkyRegions.i @@ -1,7 +1,7 @@ /*************************************************************************** * GSkyRegions.i - Sky region container class * * ----------------------------------------------------------------------- * - * copyright (C) 2013-2016 by Pierrick Martin * + * copyright (C) 2013-2017 by Pierrick Martin * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -67,17 +67,55 @@ public: ***************************************************************************/ %extend GSkyRegions { GSkyRegion* __getitem__(const int& index) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { return (*self)[index]; } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; + } else { throw GException::out_of_range("__getitem__(int)", index, self->size()); } } + GSkyRegions* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GSkyRegions* regions = new GSkyRegions; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + regions->append(*(*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + regions->append(*(*self)[i]); + } + } + return regions; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } + } void __setitem__(const int& index, const GSkyRegion& val) { - if (index>=0 && index < self->size()) { + // Counting from start, e.g. [2] + if (index >= 0 && index < self->size()) { self->set(index, val); - return; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + self->set(self->size()+index, val); } else { throw GException::out_of_range("__setitem__(int)", index, self->size()); diff --git a/pyext/GTestSuites.i b/pyext/GTestSuites.i index 524eecf..8a1e360 100644 --- a/pyext/GTestSuites.i +++ b/pyext/GTestSuites.i @@ -1,7 +1,7 @@ /*************************************************************************** * GTestSuites.i - Test suite container class * * ----------------------------------------------------------------------- * - * copyright (C) 2012-2016 Jean-Baptiste Cayrou * + * copyright (C) 2012-2017 Jean-Baptiste Cayrou * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -73,17 +73,55 @@ public: ***************************************************************************/ %extend GTestSuites { GTestSuite* __getitem__(const int& index) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { return (*self)[index]; } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; + } else { throw GException::out_of_range("__getitem__(int)", index, self->size()); } } + GTestSuites* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GTestSuites* tests = new GTestSuites(self->name()); + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + tests->append(*(*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + tests->append(*(*self)[i]); + } + } + return tests; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } + } void __setitem__(const int& index, const GTestSuite& suite) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { self->set(index, suite); - return; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + self->set(self->size()+index, suite); } else { throw GException::out_of_range("__setitem__(int)", index, self->size()); diff --git a/pyext/GXml.i b/pyext/GXml.i index 3bc6707..1c1046e 100644 --- a/pyext/GXml.i +++ b/pyext/GXml.i @@ -1,7 +1,7 @@ /*************************************************************************** * GXml.i - XML class * * ----------------------------------------------------------------------- * - * copyright (C) 2010-2016 by Juergen Knoedlseder * + * copyright (C) 2010-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -74,27 +74,60 @@ public: ***************************************************************************/ %extend GXml { GXmlNode* __getitem__(const int& index) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { return (*self)[index]; } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; + } else { - throw GException::out_of_range("__getitem__(int)", index, - 0, self->size()-1); + throw GException::out_of_range("__getitem__(int)", index, self->size()); + } + } + GXml* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GXml* xml = new GXml; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + xml->append(*(*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + xml->append(*(*self)[i]); + } + } + return xml; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); } } void __setitem__(const int& index, const GXmlNode& node) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { self->set(index, node); - return; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + self->set(self->size()+index, node); } else { - throw GException::out_of_range("__setitem__(int)", index, - 0, self->size()-1); + throw GException::out_of_range("__setitem__(int)", index, self->size()); } } - int __len__() { - return (self->size()); - } GXml copy() { return (*self); } diff --git a/pyext/GXmlElement.i b/pyext/GXmlElement.i index ecd914d..76a0b6d 100644 --- a/pyext/GXmlElement.i +++ b/pyext/GXmlElement.i @@ -1,7 +1,7 @@ /*************************************************************************** * GXmlElement.i - XML element node class definition * * ----------------------------------------------------------------------- * - * copyright (C) 2010-2016 by Juergen Knoedlseder * + * copyright (C) 2010-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -61,6 +61,61 @@ public: * @brief GXmlElement class extension ***************************************************************************/ %extend GXmlElement { + GXmlNode* __getitem__(const int& index) { + // Counting from start, e.g. [2] + if (index >= 0 && index < self->size()) { + return (*self)[index]; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; + } + else { + throw GException::out_of_range("__getitem__(int)", index, self->size()); + } + } + void __setitem__(const int& index, const GXmlNode& node) { + // Counting from start, e.g. [2] + if (index >= 0 && index < self->size()) { + self->set(index, node); + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + self->set(self->size()+index, node); + } + else { + throw GException::out_of_range("__setitem__(int)", index, self->size()); + } + } + GXmlElement* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GXmlElement* element = new GXmlElement; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + element->append(*(*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + element->append(*(*self)[i]); + } + } + return element; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } + } GXmlElement copy() { return (*self); } diff --git a/pyext/GXmlNode.i b/pyext/GXmlNode.i index ac259f1..e065636 100644 --- a/pyext/GXmlNode.i +++ b/pyext/GXmlNode.i @@ -1,7 +1,7 @@ /*************************************************************************** * GXmlNode.i - Abstract XML node base class * * ----------------------------------------------------------------------- * - * copyright (C) 2010-2016 by Juergen Knoedlseder * + * copyright (C) 2010-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -36,7 +36,7 @@ * * @brief Abstract XML node base class ***************************************************************************/ -class GXmlNode : public GBase { +class GXmlNode : public GContainer { public: // Constructors and destructors GXmlNode(void); @@ -89,25 +89,29 @@ public: return gammalib::tochar(self->print(NORMAL, 0)); } GXmlNode* __getitem__(const int& index) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { return (*self)[index]; } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; + } else { - throw GException::out_of_range("__getitem__(int)", index, - 0, self->size()-1); + throw GException::out_of_range("__getitem__(int)", index, self->size()); } } void __setitem__(const int& index, const GXmlNode& node) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { self->set(index, node); - return; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + self->set(self->size()+index, node); } else { - throw GException::out_of_range("__setitem__(int)", index, - 0, self->size()-1); + throw GException::out_of_range("__setitem__(int)", index, self->size()); } } - int __len__() { - return (self->size()); - } }; diff --git a/src/opt/GOptimizerPar.cpp b/src/opt/GOptimizerPar.cpp index 71332de..a370c16 100644 --- a/src/opt/GOptimizerPar.cpp +++ b/src/opt/GOptimizerPar.cpp @@ -1,7 +1,7 @@ /*************************************************************************** * GOptimizerPar.cpp - Optimizer parameter class * * ----------------------------------------------------------------------- * - * copyright (C) 2013-2015 by Juergen Knoedlseder * + * copyright (C) 2013-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -700,8 +700,8 @@ std::string GOptimizerPar::print(const GChatter& chatter) const void GOptimizerPar::init_members(void) { // Initialise members - m_name = ""; - m_unit = ""; + m_name.clear(); + m_unit.clear(); m_factor_value = 0.0; m_factor_error = 0.0; m_factor_gradient = 0.0; diff --git a/src/opt/GOptimizerPars.cpp b/src/opt/GOptimizerPars.cpp index c8ff29c..9371b07 100644 --- a/src/opt/GOptimizerPars.cpp +++ b/src/opt/GOptimizerPars.cpp @@ -1,7 +1,7 @@ /*************************************************************************** * GOptimizerPars.cpp - Optimizer parameter container class * * ----------------------------------------------------------------------- * - * copyright (C) 2009-2013 by Juergen Knoedlseder * + * copyright (C) 2009-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -392,6 +392,30 @@ GOptimizerPar* GOptimizerPars::set(const std::string& name, const GOptimizerPar& /***********************************************************************//** + * @brief Append parameter to container + * + * @param[in] par Parameter reference. + * @return Pointer to appended parameter. + * + * Appends a parameter to the container. The method stores a copy of the + * parameter in the container, hence the client may delete the parameter + * after the method is called. + ***************************************************************************/ +GOptimizerPar* GOptimizerPars::append(const GOptimizerPar& par) +{ + // Clone parameter + GOptimizerPar* ptr = par.clone(); + + // Inserts deep copy of parameter + m_alloc.push_back(true); + m_pars.push_back(ptr); + + // Return parameter pointer + return ptr; +} + + +/***********************************************************************//** * @brief Attach parameter to container * * @param[in] par Parameter pointer. @@ -680,6 +704,7 @@ std::string GOptimizerPars::print(const GChatter& chatter) const // Append parameters for (int i = 0; i < size(); ++i) { +std::cout << i << " " << m_pars[i] << std::endl; result.append("\n"+m_pars[i]->print(chatter)); } diff --git a/test/test_GFits.py b/test/test_GFits.py index e3d701a..342d345 100755 --- a/test/test_GFits.py +++ b/test/test_GFits.py @@ -27,11 +27,12 @@ import gammalib # =================================== # class Test(gammalib.GPythonTestSuite): """ - Test class for GammaLib FITS module. + Test class for GammaLib FITS module """ + # Constructor def __init__(self): """ - Constructor. + Constructor """ # Call base class constructor gammalib.GPythonTestSuite.__init__(self) @@ -39,25 +40,236 @@ class Test(gammalib.GPythonTestSuite): # Return return - def set(self): + # Setup GFits container + def _setup_fits(self): + """ + Setup GFits container + + Returns + ------- + fits : `~gammalib.GFits` + GFits container """ - Set all test functions. + # Setup GFits container + fits = gammalib.GFits() + image = gammalib.GFitsImageDouble() + for i in range(10): + image.extname('%s' % i) + fits.append(image) + + # Return GFits container + return fits + + # Setup GFitsHeader container + def _setup_header(self): """ - # Set test name - self.name("fits") + Setup GFitsHeader container - # Append tests - self.append(self.test_fits, "Test GFits class") - self.append(self.test_fits_image, "Test GFitsImage class") - self.append(self.test_fits_table, "Test GFitsTable class") - self.append(self.test_fits_table_columns, "Test GFitsTableCol classes") + Returns + ------- + header : `~gammalib.GFitsHeader` + GFitsHeader container + """ + # Setup GFitsHeader container + header = gammalib.GFitsHeader() + card = gammalib.GFitsHeaderCard() + for i in range(10): + card.keyname('%s' % i) + header.append(card) + + # Return GFitsHeader container + return header + + # Test GFits class access operators + def _test_fits_access(self): + """ + Test GFits class parameter access + """ + # Setup GFits container and element + fits = self._setup_fits() + image = gammalib.GFitsImageDouble() + + # Loop over all elements using the container iterator and count the + # number of iterations + niter = 0 + for hdu in fits: + self.test_value(hdu.extname(), '%s' % niter) + niter += 1 + + # Check that looping was successful + self.test_value(fits.size(), 10, 'Check container size') + self.test_value(niter, 10, 'Check container iterator') + + # Test access from start + self.test_value(fits[3].extname(), '3') + + # Check access from end + self.test_value(fits[-2].extname(), '8') + + # Check parameter setting by index from start + image.extname('98') + fits[3] = image + self.test_value(fits[3].extname(), '98') + + # Check parameter setting by index from end + image.extname('99') + fits[-2] = image + self.test_value(fits[-2].extname(), '99') + + # Return + return + + # Test GFits class slicing + def _test_fits_slicing(self): + """ + Test GFits class slicing + """ + # Setup XML container + fits = self._setup_fits() + + # Test fits[start:end] + self.test_value(len(fits[3:5]), 2) + self.test_value(fits[3:5][0].extname(), '3') + self.test_value(fits[3:5][1].extname(), '4') + + # Test fits[start:] + self.test_value(len(fits[7:]), 3) + self.test_value(fits[7:][0].extname(), '7') + self.test_value(fits[7:][1].extname(), '8') + self.test_value(fits[7:][2].extname(), '9') + + # Test fits[:end] + self.test_value(len(fits[:2]), 2) + self.test_value(fits[:2][0].extname(), '0') + self.test_value(fits[:2][1].extname(), '1') + + # Test fits[:] + self.test_value(len(fits[:]), 10) + for i in range(10): + self.test_value(fits[:][i].extname(), '%s' % i) + + # Test fits[start:end:step] + self.test_value(len(fits[3:7:2]), 2) + self.test_value(fits[3:7:2][0].extname(), '3') + self.test_value(fits[3:7:2][1].extname(), '5') + + # Test fits[start:end:step] + self.test_value(len(fits[6:3:-2]), 2) + self.test_value(fits[6:3:-2][0].extname(), '6') + self.test_value(fits[6:3:-2][1].extname(), '4') + + # Test fits[-start:] + self.test_value(len(fits[-2:]), 2) + self.test_value(fits[-2:][0].extname(), '8') + self.test_value(fits[-2:][1].extname(), '9') + + # Test fits[:-end] + self.test_value(len(fits[:-7]), 3) + self.test_value(fits[:-7][0].extname(), '0') + self.test_value(fits[:-7][1].extname(), '1') + self.test_value(fits[:-7][2].extname(), '2') + + # Return + return + + # Test GFitsHeader class access operators + def _test_header_access(self): + """ + Test GFitsHeader class parameter access + """ + # Setup FITS header + header = self._setup_header() + + # Loop over all elements using the container iterator and count the + # number of iterations + niter = 0 + for card in header: + self.test_value(card.keyname(), '%s' % niter) + niter += 1 + + # Check that looping was successful + self.test_value(header.size(), 10, 'Check container size') + self.test_value(niter, 10, 'Check container iterator') + + # Test access from start + self.test_value(header[3].keyname(), '3') + + # Check access from end + self.test_value(header[-2].keyname(), '8') + + # Setup header card + card = gammalib.GFitsHeaderCard() + + # Check parameter setting by index from start + card.keyname('98') + header[3] = card + self.test_value(header[3].keyname(), '98') + + # Check parameter setting by index from end + card.keyname('99') + header[-2] = card + self.test_value(header[-2].keyname(), '99') # Return return - def test_fits(self): + # Test GFitsHeader class slicing + def _test_header_slicing(self): + """ + Test GFitsHeader class slicing """ - Test GFile class interface. + # Setup FITS header + header = self._setup_header() + + # Test header[start:end] + self.test_value(len(header[3:5]), 2) + self.test_value(header[3:5][0].keyname(), '3') + self.test_value(header[3:5][1].keyname(), '4') + + # Test header[start:] + self.test_value(len(header[7:]), 3) + self.test_value(header[7:][0].keyname(), '7') + self.test_value(header[7:][1].keyname(), '8') + self.test_value(header[7:][2].keyname(), '9') + + # Test header[:end] + self.test_value(len(header[:2]), 2) + self.test_value(header[:2][0].keyname(), '0') + self.test_value(header[:2][1].keyname(), '1') + + # Test header[:] + self.test_value(len(header[:]), 10) + for i in range(10): + self.test_value(header[:][i].keyname(), '%s' % i) + + # Test header[start:end:step] + self.test_value(len(header[3:7:2]), 2) + self.test_value(header[3:7:2][0].keyname(), '3') + self.test_value(header[3:7:2][1].keyname(), '5') + + # Test header[start:end:step] + self.test_value(len(header[6:3:-2]), 2) + self.test_value(header[6:3:-2][0].keyname(), '6') + self.test_value(header[6:3:-2][1].keyname(), '4') + + # Test header[-start:] + self.test_value(len(header[-2:]), 2) + self.test_value(header[-2:][0].keyname(), '8') + self.test_value(header[-2:][1].keyname(), '9') + + # Test header[:-end] + self.test_value(len(header[:-7]), 3) + self.test_value(header[:-7][0].keyname(), '0') + self.test_value(header[:-7][1].keyname(), '1') + self.test_value(header[:-7][2].keyname(), '2') + + # Return + return + + # Test GFile class interface + def _test_fits(self): + """ + Test GFile class interface """ # Get test data directory datadir = os.environ['TEST_DATA'] + '/' @@ -66,33 +278,33 @@ class Test(gammalib.GPythonTestSuite): file = gammalib.GFilename(datadir+'file.fits') # Test loading of FITS file - self.test_try("Test GFits file load constructor") + self.test_try('Test GFits file load constructor') try: fits = gammalib.GFits(file) self.test_try_success() except: - self.test_try_failure("Unable to load FITS file.") + self.test_try_failure('Unable to load FITS file.') # Test creation of FITS file - self.test_try("Test GFits file creation constructor") + self.test_try('Test GFits file creation constructor') try: - fits = gammalib.GFits("test_file.fits", True) + fits = gammalib.GFits('test_file.fits', True) self.test_try_success() except: - self.test_try_failure("Unable to create FITS file.") + self.test_try_failure('Unable to create FITS file.') # Open FITS file fits = gammalib.GFits(file) - self.test_value(fits["EVENTS"].nrows(), 1231, "Check number of rows") + self.test_value(fits['EVENTS'].nrows(), 1231, 'Check number of rows') # Open FITS file with event selection - fits = gammalib.GFits(file+"[EVENTS][ENERGY>1.0]") - self.test_value(fits["EVENTS"].nrows(), 152, "Check number of rows") + fits = gammalib.GFits(file+'[EVENTS][ENERGY>1.0]') + self.test_value(fits['EVENTS'].nrows(), 152, 'Check number of rows') # Open FITS file with non-existing extension name - self.test_try("Test non-existing extension name") + self.test_try('Test non-existing extension name') try: - fits = gammalib.GFits(file+"[DUMMY][ENERGY>1.0]") + fits = gammalib.GFits(file+'[DUMMY][ENERGY>1.0]') self.test_try_failure() except: self.test_try_success() @@ -100,13 +312,14 @@ class Test(gammalib.GPythonTestSuite): # Return return - def test_fits_image(self): + # Test GFitsImage class interface + def _test_fits_image(self): """ - Test GFitsImage class interface. + Test GFitsImage class interface """ # Set test file names - file1 = gammalib.GFilename("test_python_fits_image_v1.fits") - file2 = gammalib.GFilename("test_python_fits_image_v2.fits") + file1 = gammalib.GFilename('test_python_fits_image_v1.fits') + file2 = gammalib.GFilename('test_python_fits_image_v2.fits') # Remove test files file1.remove() @@ -138,15 +351,15 @@ class Test(gammalib.GPythonTestSuite): img7[x, y] = x + y * nx img8[x, y] = x + y * nx img9[x, y] = x + y * nx - img1.extname("Byte") - img2.extname("Double") - img3.extname("Float") - img4.extname("Long") - img5.extname("LongLong") - img6.extname("SByte") - img7.extname("Short") - img8.extname("ULong") - img9.extname("UShort") + img1.extname('Byte') + img2.extname('Double') + img3.extname('Float') + img4.extname('Long') + img5.extname('LongLong') + img6.extname('SByte') + img7.extname('Short') + img8.extname('ULong') + img9.extname('UShort') # Test image types by checking the bitpix values self.test_value(img1.bitpix(), 8) @@ -172,9 +385,9 @@ class Test(gammalib.GPythonTestSuite): # Set header keywords img_byte = fits.image(0) - img_byte.card("test", "test-value", "this is for testing") - img_byte.card("real", 3.1415, "a real value") - img_byte.card("int", 41, "an integer value") + img_byte.card('test', 'test-value', 'this is for testing') + img_byte.card('real', 3.1415, 'a real value') + img_byte.card('int', 41, 'an integer value') # Save FITS file fits.save() @@ -198,7 +411,7 @@ class Test(gammalib.GPythonTestSuite): # Get double precision image, take square root of pixel and save in # another file - img_double = fits.image("Double") + img_double = fits.image('Double') for x in range(nx): for y in range(ny): img_double[x, y] = math.sqrt(img_double[x, y]) @@ -232,13 +445,14 @@ class Test(gammalib.GPythonTestSuite): # Return return - def test_fits_table(self): + # Test GFitsTable class interface + def _test_fits_table(self): """ - Test GFitsTable class interface. + Test GFitsTable class interface """ # Set test file names - file1 = gammalib.GFilename("test_python_fits_table_v1.fits") - file2 = gammalib.GFilename("test_python_fits_table_v2.fits") + file1 = gammalib.GFilename('test_python_fits_table_v1.fits') + file2 = gammalib.GFilename('test_python_fits_table_v2.fits') # Remove test files file1.remove() @@ -249,17 +463,17 @@ class Test(gammalib.GPythonTestSuite): # Create table columns nrows = 10 - col1 = gammalib.GFitsTableBitCol("BIT", nrows) - col2 = gammalib.GFitsTableBoolCol("BOOLEAN", nrows) - col3 = gammalib.GFitsTableByteCol("BYTE", nrows) - col4 = gammalib.GFitsTableDoubleCol("DOUBLE", nrows) - col5 = gammalib.GFitsTableFloatCol("FLOAT", nrows) - col6 = gammalib.GFitsTableLongCol("LONG", nrows) - col7 = gammalib.GFitsTableLongLongCol("LONGLONG", nrows) - col8 = gammalib.GFitsTableShortCol("SHORT", nrows) - col9 = gammalib.GFitsTableStringCol("STRING", nrows, 20) - col10 = gammalib.GFitsTableULongCol("ULONG", nrows) - col11 = gammalib.GFitsTableUShortCol("USHORT", nrows) + col1 = gammalib.GFitsTableBitCol('BIT', nrows) + col2 = gammalib.GFitsTableBoolCol('BOOLEAN', nrows) + col3 = gammalib.GFitsTableByteCol('BYTE', nrows) + col4 = gammalib.GFitsTableDoubleCol('DOUBLE', nrows) + col5 = gammalib.GFitsTableFloatCol('FLOAT', nrows) + col6 = gammalib.GFitsTableLongCol('LONG', nrows) + col7 = gammalib.GFitsTableLongLongCol('LONGLONG', nrows) + col8 = gammalib.GFitsTableShortCol('SHORT', nrows) + col9 = gammalib.GFitsTableStringCol('STRING', nrows, 20) + col10 = gammalib.GFitsTableULongCol('ULONG', nrows) + col11 = gammalib.GFitsTableUShortCol('USHORT', nrows) for i in range(nrows): #col1[i] = i % 2 # Old swig version #col2[i] = i % 2 # Old swig version @@ -288,7 +502,7 @@ class Test(gammalib.GPythonTestSuite): tbl_ascii.append(col9) tbl_ascii.append(col10) tbl_ascii.append(col11) - tbl_ascii.extname("ASCII table") + tbl_ascii.extname('ASCII table') fits.append(tbl_ascii) # Set binary table @@ -304,7 +518,7 @@ class Test(gammalib.GPythonTestSuite): tbl_bin.append(col9) tbl_bin.append(col10) tbl_bin.append(col11) - tbl_bin.extname("Binary table") + tbl_bin.extname('Binary table') fits.append(tbl_bin) # Save FITS file @@ -316,36 +530,37 @@ class Test(gammalib.GPythonTestSuite): # Return return - def test_fits_table_columns(self): + # Test FITS table columns + def _test_fits_table_columns(self): """ Test FITS table columns """ # Create table columns nrows = 10 - col1 = gammalib.GFitsTableBitCol("BIT", nrows) - col2 = gammalib.GFitsTableBoolCol("BOOLEAN", nrows) - col3 = gammalib.GFitsTableByteCol("BYTE", nrows) - col4 = gammalib.GFitsTableDoubleCol("DOUBLE", nrows) - col5 = gammalib.GFitsTableFloatCol("FLOAT", nrows) - col6 = gammalib.GFitsTableLongCol("LONG", nrows) - col7 = gammalib.GFitsTableLongLongCol("LONGLONG", nrows) - col8 = gammalib.GFitsTableShortCol("SHORT", nrows) - col9 = gammalib.GFitsTableStringCol("STRING", nrows, 20) - col10 = gammalib.GFitsTableULongCol("ULONG", nrows) - col11 = gammalib.GFitsTableUShortCol("USHORT", nrows) + col1 = gammalib.GFitsTableBitCol('BIT', nrows) + col2 = gammalib.GFitsTableBoolCol('BOOLEAN', nrows) + col3 = gammalib.GFitsTableByteCol('BYTE', nrows) + col4 = gammalib.GFitsTableDoubleCol('DOUBLE', nrows) + col5 = gammalib.GFitsTableFloatCol('FLOAT', nrows) + col6 = gammalib.GFitsTableLongCol('LONG', nrows) + col7 = gammalib.GFitsTableLongLongCol('LONGLONG', nrows) + col8 = gammalib.GFitsTableShortCol('SHORT', nrows) + col9 = gammalib.GFitsTableStringCol('STRING', nrows, 20) + col10 = gammalib.GFitsTableULongCol('ULONG', nrows) + col11 = gammalib.GFitsTableUShortCol('USHORT', nrows) # Test number of rows - self.test_value(col1.nrows(), nrows, "Check number of rows in Bit column") - self.test_value(col2.nrows(), nrows, "Check number of rows in Boolean column") - self.test_value(col3.nrows(), nrows, "Check number of rows in Byte column") - self.test_value(col4.nrows(), nrows, "Check number of rows in Double column") - self.test_value(col5.nrows(), nrows, "Check number of rows in Float column") - self.test_value(col6.nrows(), nrows, "Check number of rows in Long column") - self.test_value(col7.nrows(), nrows, "Check number of rows in LongLong column") - self.test_value(col8.nrows(), nrows, "Check number of rows in Short column") - self.test_value(col9.nrows(), nrows, "Check number of rows in String column") - self.test_value(col10.nrows(), nrows, "Check number of rows in ULong column") - self.test_value(col11.nrows(), nrows, "Check number of rows in UShort column") + self.test_value(col1.nrows(), nrows, 'Check number of rows in Bit column') + self.test_value(col2.nrows(), nrows, 'Check number of rows in Boolean column') + self.test_value(col3.nrows(), nrows, 'Check number of rows in Byte column') + self.test_value(col4.nrows(), nrows, 'Check number of rows in Double column') + self.test_value(col5.nrows(), nrows, 'Check number of rows in Float column') + self.test_value(col6.nrows(), nrows, 'Check number of rows in Long column') + self.test_value(col7.nrows(), nrows, 'Check number of rows in LongLong column') + self.test_value(col8.nrows(), nrows, 'Check number of rows in Short column') + self.test_value(col9.nrows(), nrows, 'Check number of rows in String column') + self.test_value(col10.nrows(), nrows, 'Check number of rows in ULong column') + self.test_value(col11.nrows(), nrows, 'Check number of rows in UShort column') # Test iterators for row in col1: @@ -373,28 +588,48 @@ class Test(gammalib.GPythonTestSuite): # Test setting and retrieving of values col1[5] = True - self.test_assert(col1[5], "Check Bit column setting and retrieving") + self.test_assert(col1[5], 'Check Bit column setting and retrieving') col2[5] = True - self.test_assert(col2[5], "Check Boolean column setting and retrieving") + self.test_assert(col2[5], 'Check Boolean column setting and retrieving') col3[5] = 5 - self.test_value(col3[5], 5, "Check Byte column setting and retrieving") + self.test_value(col3[5], 5, 'Check Byte column setting and retrieving') col4[5] = 3.14 - self.test_value(col4[5], 3.14, 1.0e-6, "Check Double column setting and retrieving") + self.test_value(col4[5], 3.14, 1.0e-6, 'Check Double column setting and retrieving') col5[5] = 3.14 - self.test_value(col5[5], 3.14, 1.0e-6, "Check Float column setting and retrieving") + self.test_value(col5[5], 3.14, 1.0e-6, 'Check Float column setting and retrieving') col6[5] = 314 - self.test_value(col6[5], 314, "Check Long column setting and retrieving") + self.test_value(col6[5], 314, 'Check Long column setting and retrieving') col7[5] = 314 - self.test_value(col7[5], 314, "Check LongLong column setting and retrieving") + self.test_value(col7[5], 314, 'Check LongLong column setting and retrieving') col8[5] = 314 - self.test_value(col8[5], 314, "Check Short column setting and retrieving") - col9[5] = "Hallo" - self.test_assert(col9[5] == "Hallo", "Check String column setting and retrieving") + self.test_value(col8[5], 314, 'Check Short column setting and retrieving') + col9[5] = 'Hallo' + self.test_assert(col9[5] == 'Hallo', 'Check String column setting and retrieving') col10[5] = 314 - self.test_value(col10[5], 314, "Check ULong column setting and retrieving") + self.test_value(col10[5], 314, 'Check ULong column setting and retrieving') col11[5] = 314 - self.test_value(col11[5], 314, "Check UShort column setting and retrieving") + self.test_value(col11[5], 314, 'Check UShort column setting and retrieving') + + # Return + return + + # Set test functions + def set(self): + """ + Set all test functions + """ + # Set test name + self.name('fits') + + # Append tests + self.append(self._test_fits, 'Test GFits') + self.append(self._test_fits_access, 'Test GFits parameter access') + self.append(self._test_fits_slicing, 'Test GFits slicing') + self.append(self._test_header_access, 'Test GFitsHeader parameter access') + self.append(self._test_header_slicing, 'Test GFitsHeader slicing') + self.append(self._test_fits_image, 'Test GFitsImage') + self.append(self._test_fits_table, 'Test GFitsTable') + self.append(self._test_fits_table_columns, 'Test GFitsTableCol') # Return return - diff --git a/test/test_GObservation.py b/test/test_GObservation.py index a749d28..1354e6b 100755 --- a/test/test_GObservation.py +++ b/test/test_GObservation.py @@ -649,24 +649,8 @@ class Test(gammalib.GPythonTestSuite): # Setup photons container photons = self._setup_photons() - # Loop over all elements using the container iterator and count the - # number of iterations - nphotons = 0 - reference = 0.0 - for photon in photons: - self.test_value(photon.energy().MeV(), reference) - nphotons += 1 - reference += 1.0 - - # Check that looping was successful - self.test_value(photons.size(), 10, 'Check container size') - self.test_value(nphotons, 10, 'Check container iterator') - - # Test access from start - self.test_value(photons[3].energy().MeV(), 3.0) - - # Check access from end - self.test_value(photons[-2].energy().MeV(), 8.0) + # Perform photons access tests + test_support._energy_container_access_index(self, photons) # Return return @@ -679,47 +663,8 @@ class Test(gammalib.GPythonTestSuite): # Setup photons container photons = self._setup_photons() - # Test photons[start:end] - self.test_value(len(photons[3:5]), 2) - self.test_value(photons[3:5][0].energy().MeV(), 3.0) - self.test_value(photons[3:5][1].energy().MeV(), 4.0) - - # Test photons[start:] - self.test_value(len(photons[7:]), 3) - self.test_value(photons[7:][0].energy().MeV(), 7.0) - self.test_value(photons[7:][1].energy().MeV(), 8.0) - self.test_value(photons[7:][2].energy().MeV(), 9.0) - - # Test photons[:end] - self.test_value(len(photons[:2]), 2) - self.test_value(photons[:2][0].energy().MeV(), 0.0) - self.test_value(photons[:2][1].energy().MeV(), 1.0) - - # Test photons[:] - self.test_value(len(photons[:]), 10) - for i in range(10): - self.test_value(photons[:][i].energy().MeV(), float(i)) - - # Test photons[start:end:step] - self.test_value(len(photons[3:7:2]), 2) - self.test_value(photons[3:7:2][0].energy().MeV(), 3.0) - self.test_value(photons[3:7:2][1].energy().MeV(), 5.0) - - # Test photons[start:end:step] - self.test_value(len(photons[6:3:-2]), 2) - self.test_value(photons[6:3:-2][0].energy().MeV(), 6.0) - self.test_value(photons[6:3:-2][1].energy().MeV(), 4.0) - - # Test photons[-start:] - self.test_value(len(photons[-2:]), 2) - self.test_value(photons[-2:][0].energy().MeV(), 8.0) - self.test_value(photons[-2:][1].energy().MeV(), 9.0) - - # Test photons[:-end] - self.test_value(len(photons[:-7]), 3) - self.test_value(photons[:-7][0].energy().MeV(), 0.0) - self.test_value(photons[:-7][1].energy().MeV(), 1.0) - self.test_value(photons[:-7][2].energy().MeV(), 2.0) + # Perform slicing tests + test_support._energy_container_slicing(self, photons) # Return return @@ -736,16 +681,6 @@ class Test(gammalib.GPythonTestSuite): # Perform observation access tests test_support._container_access_index(self, obs) - # Check observation setting by index from start - run.id('98') - obs[3] = run - self.test_value(obs[3].id(), '98') - - # Check observation setting by index from end - run.id('99') - obs[-2] = run - self.test_value(obs[-2].id(), '99') - # Return return diff --git a/test/test_GOptimizer.py b/test/test_GOptimizer.py index 0e3f599..e53d191 100755 --- a/test/test_GOptimizer.py +++ b/test/test_GOptimizer.py @@ -1,7 +1,7 @@ # ========================================================================== # This module performs unit tests for the GammaLib optimizer module. # -# Copyright (C) 2012-2015 Juergen Knoedlseder +# Copyright (C) 2012-2017 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 @@ -18,6 +18,7 @@ # # ========================================================================== import gammalib +import test_support # ======================================== # @@ -38,24 +39,76 @@ class Test(gammalib.GPythonTestSuite): # Return return - # Set test functions - def set(self): + # Setup GOptimizerPars container + def _setup_pars(self): """ - Set all test functions. + Setup GOptimizerPars container + + Returns + ------- + pars : `~gammalib.GOptimizerPars` + GOptimizerPars container """ - # Set test name - self.name("opt") + # Setup GOptimizerPars container + pars = gammalib.GOptimizerPars() + par = gammalib.GOptimizerPar() + for i in range(10): + par.name('%s' % i) + pars.append(par) - # Append tests - self.append(self.test, "Optimizer module dummy test") + # Return GOptimizerPars container + return pars + + # Test GOptimizerPars class access operators + def _test_pars_access(self): + """ + Test GOptimizerPars class parameter access + """ + # Setup GOptimizerPars container and parameter + pars = self._setup_pars() + par = gammalib.GOptimizerPar() + + # Perform GOptimizerPars access tests + test_support._container_access_index(self, pars) + + # Check parameter setting by index from start + par.name('98') + pars[3] = par + self.test_value(pars[3].name(), '98') + + # Check parameter setting by index from end + par.name('99') + pars[-2] = par + self.test_value(pars[-2].name(), '99') + + # Return + return + + # Test GOptimizerPars class slicing + def _test_pars_slicing(self): + """ + Test GOptimizerPars class slicing + """ + # Setup GOptimizerPars container + pars = self._setup_pars() + + # Perform slicing tests + test_support._container_slicing(self, pars) # Return return - # Test function - def test(self): + # Set test functions + def set(self): """ - Test function. + Set all test functions. """ + # Set test name + self.name('opt') + + # Append tests + self.append(self._test_pars_access, "Test GOptimizerPars parameter access") + self.append(self._test_pars_slicing, "Test GOptimizerPars slicing") + # Return return diff --git a/test/test_GSky.py b/test/test_GSky.py index bde4433..df02032 100755 --- a/test/test_GSky.py +++ b/test/test_GSky.py @@ -20,12 +20,13 @@ import os import math import gammalib +import test_support # =========== # # Text parser # # =========== # -def loadtxt(filename): +def _loadtxt(filename): """ Parse text file with columns of floats. @@ -63,40 +64,33 @@ class Test(gammalib.GPythonTestSuite): # Return return - def set(self): - """ - Set all test functions. + # Setup GSkyRegions container + def _setup_regions(self): """ - # Set test name - self.name("sky") + Setup GSkyRegions container - # Append tests - self.append(self.test_methods, "Test sky map methods") - self.append(self.test_friend_methods, "Test sky map friend methods") - self.append(self.test_operators, "Test sky map operators") - self.append(self.test_skymap_healpix, "Test HEALPix map") - self.append(self.test_skymap_ait, "Test AIT projection map") - self.append(self.test_skymap_azp, "Test AZP projection map") - self.append(self.test_skymap_car, "Test CAR projection map") - self.append(self.test_skymap_gls, "Test GLS projection map") - self.append(self.test_skymap_mer, "Test MER projection map") - self.append(self.test_skymap_mol, "Test MOL projection map") - self.append(self.test_skymap_sfl, "Test SFL projection map") - self.append(self.test_skymap_sin, "Test SIN projection map") - self.append(self.test_skymap_stg, "Test STG projection map") - self.append(self.test_skymap_tan, "Test TAN projection map") - self.append(self.test_fk5_to_galactic, "Test FK5 to Galactic coordinate conversion") + Returns + ------- + regions : `~gammalib.GSkyRegions` + Sky regions container + """ + # Setup regions container + regions = gammalib.GSkyRegions() + circle = gammalib.GSkyRegionCircle() + for i in range(10): + circle.name('%s' % i) + regions.append(circle) - # Return - return + # Return regions container + return regions # Test sky map methods - def test_methods(self): + def _test_methods(self): """ Test the sky map methods. """ # Setup sky maps - map = gammalib.GSkyMap("CAR", "CEL", 83.63, 22.01, -3.7, 2.6, 10, 8, 12) + map = gammalib.GSkyMap('CAR', 'CEL', 83.63, 22.01, -3.7, 2.6, 10, 8, 12) # Set sky map shape map.shape(3,4) @@ -126,7 +120,7 @@ class Test(gammalib.GPythonTestSuite): return # Test sky map friend methods - def test_friend_methods(self): + def _test_friend_methods(self): """ Test the sky map friend methods """ @@ -154,12 +148,12 @@ class Test(gammalib.GPythonTestSuite): return # Test sky map operators - def test_operators(self): + def _test_operators(self): """ Test the sky map operators. """ # Setup sky maps - map = gammalib.GSkyMap("CAR", "CEL", 83.6331, 22.0145, -3.7, 2.6, 2, 2) + map = gammalib.GSkyMap('CAR', 'CEL', 83.6331, 22.0145, -3.7, 2.6, 2, 2) map[0] = 1.0 map[1] = 2.0 map[2] = 3.0 @@ -218,7 +212,7 @@ class Test(gammalib.GPythonTestSuite): return # Generic skymap pixel transformation test - def test_skymap_pixels(self, pixels, map): + def _test_skymap_pixels(self, pixels, map): """ Control coordinate and pixel transformation methods. """ @@ -226,9 +220,9 @@ class Test(gammalib.GPythonTestSuite): for i in range(pixels.npix()): dir = pixels.inx2dir(i) inx = pixels.dir2inx(dir) - msg = map + " inx2dir/dir2inx check for pixel " + str(i) - err = map + " GSkyMap trouble with pixel " + str(i) + " (" + str(inx) + \ - "), RA=" + str(dir.ra() * 180 / math.pi) + ", Dec=" + str(dir.dec() * 180 / math.pi) + msg = map + ' inx2dir/dir2inx check for pixel ' + str(i) + err = map + ' GSkyMap trouble with pixel ' + str(i) + ' (' + str(inx) + \ + '), RA=' + str(dir.ra() * 180 / math.pi) + ', Dec=' + str(dir.dec() * 180 / math.pi) self.test_assert(i == inx, msg, err) # Control SkyDir coordinate transformation for all pixels @@ -240,21 +234,21 @@ class Test(gammalib.GPythonTestSuite): if (dra >= 5.0): dra -= 2.0 * math.pi ddec = abs(dir.dec() - dir_new.dec()) - msg = map + " dir check for pixel " + str(i) - err = map + " GSkyMap trouble with pixel " + str(i) + " (" + str(dra) + \ - "," + str(ddec) + ")" + msg = map + ' dir check for pixel ' + str(i) + err = map + ' GSkyMap trouble with pixel ' + str(i) + ' (' + str(dra) + \ + ',' + str(ddec) + ')' self.test_assert(not (dra > 1.0e-9 or ddec > 1.0e-9), msg, err) # Return return # Generic skymap projection test - def test_skymap_proj(self, proj): + def _test_skymap_proj(self, proj): """ Test skymap projection. """ # Set filename - file = "test_python_skymap_" + proj + ".fits" + file = 'test_python_skymap_' + proj + '.fits' # Remove test files try: @@ -263,26 +257,26 @@ class Test(gammalib.GPythonTestSuite): pass # Create skymap - pixels = gammalib.GSkyMap(proj, "CEL", 83.6331, 22.0145, -3.7, 2.6, 5, 5, 20) + pixels = gammalib.GSkyMap(proj, 'CEL', 83.6331, 22.0145, -3.7, 2.6, 5, 5, 20) for map in range(pixels.nmaps()): for i in range(pixels.npix()): pixels[i, map] = i + map * pixels.npix() pixels.save(file) # Test coordinate and pixel transformations - self.test_skymap_pixels(pixels, proj) + self._test_skymap_pixels(pixels, proj) # Return return # Test HEALPix projection - def test_skymap_healpix(self): + def _test_skymap_healpix(self): """ Test HEALPix interface. """ # Set filenames - file1 = "test_python_skymap_hpx_v1.fits" - file2 = "test_python_skymap_hpx_v2.fits" + file1 = 'test_python_skymap_hpx_v1.fits' + file2 = 'test_python_skymap_hpx_v2.fits' # Remove test files try: @@ -292,7 +286,7 @@ class Test(gammalib.GPythonTestSuite): pass # Create HEALPix skymap - pixels = gammalib.GSkyMap("GAL", 2, "RING", 2) + pixels = gammalib.GSkyMap('GAL', 2, 'RING', 2) for i in range(pixels.npix()): pixels[i] = i + 1.0 pixels[i, 1] = i + 1.0 + 1000.0 @@ -302,7 +296,7 @@ class Test(gammalib.GPythonTestSuite): pixels = gammalib.GSkyMap(file1) # Control coordinate and pixel transformations - self.test_skymap_pixels(pixels, "HEALPix") + self._test_skymap_pixels(pixels, 'HEALPix') # Save HEALPix skymap twice. The second saving should fail. try: @@ -311,7 +305,7 @@ class Test(gammalib.GPythonTestSuite): except RuntimeError: pass else: - raise RuntimeError("*** TEST ERROR: FITS file overwritten!") + raise RuntimeError('*** TEST ERROR: FITS file overwritten!') pixels.save(file2, True) # Load again HEALPix skymap @@ -321,117 +315,117 @@ class Test(gammalib.GPythonTestSuite): return # Test AIT projection - def test_skymap_ait(self): + def _test_skymap_ait(self): """ Test AIT projection. """ # Execute generic test - self.test_skymap_proj("AIT") + self._test_skymap_proj('AIT') # Return return # Test AZP projection - def test_skymap_azp(self): + def _test_skymap_azp(self): """ Test AZP projection. """ # Execute generic test - self.test_skymap_proj("AZP") + self._test_skymap_proj('AZP') # Return return # Test CAR projection - def test_skymap_car(self): + def _test_skymap_car(self): """ Test CAR projection. """ # Execute generic test - self.test_skymap_proj("CAR") + self._test_skymap_proj('CAR') # Return return # Test GLS projection - def test_skymap_gls(self): + def _test_skymap_gls(self): """ Test GLS projection. """ # Execute generic test - self.test_skymap_proj("GLS") + self._test_skymap_proj('GLS') # Return return # Test MER projection - def test_skymap_mer(self): + def _test_skymap_mer(self): """ Test MER projection. """ # Execute generic test - self.test_skymap_proj("MER") + self._test_skymap_proj('MER') # Return return # Test MOL projection - def test_skymap_mol(self): + def _test_skymap_mol(self): """ Test MOL projection. """ # Execute generic test - self.test_skymap_proj("MOL") + self._test_skymap_proj('MOL') # Return return # Test SIN projection - def test_skymap_sin(self): + def _test_skymap_sin(self): """ Test SIN projection. """ # Execute generic test - self.test_skymap_proj("SIN") + self._test_skymap_proj('SIN') # Return return # Test SFL projection - def test_skymap_sfl(self): + def _test_skymap_sfl(self): """ Test SFL projection. """ # Execute generic test - self.test_skymap_proj("SFL") + self._test_skymap_proj('SFL') # Return return # Test STG projection - def test_skymap_stg(self): + def _test_skymap_stg(self): """ Test STG projection. """ # Execute generic test - self.test_skymap_proj("STG") + self._test_skymap_proj('STG') # Return return # Test TAN projection - def test_skymap_tan(self): + def _test_skymap_tan(self): """ Test TAN projection. """ # Execute generic test - self.test_skymap_proj("TAN") + self._test_skymap_proj('TAN') # Return return # FK5 J2000 to Galactic coordinate tranformations - def test_fk5_to_galactic(self): + def _test_fk5_to_galactic(self): """ Test precision of FK5 J2000 to Galactic coordinate tranformations against pyast (http://dsberry.github.com/starlink/pyast.html) @@ -446,8 +440,8 @@ class Test(gammalib.GPythonTestSuite): # Set parameters fk5_filename = datadir + 'initial_coords.txt' galactic_filename = datadir + 'fk5_to_galactic.txt' - fk5_coordinates = loadtxt(fk5_filename) - galactic_coordinates = loadtxt(galactic_filename) + fk5_coordinates = _loadtxt(fk5_filename) + galactic_coordinates = _loadtxt(galactic_filename) coordinates = zip(fk5_coordinates, galactic_coordinates) max_dist = 0 @@ -483,3 +477,70 @@ class Test(gammalib.GPythonTestSuite): # Return return + + # Test GSkyRegions class access operators + def _test_regions_access(self): + """ + Test GSkyRegions class observation access + """ + # Setup regions container + regions = self._setup_regions() + circle = gammalib.GSkyRegionCircle() + + # Perform regions access tests + test_support._container_access_index(self, regions) + + # Check regions setting by index from start + circle.name('98') + regions[3] = circle + self.test_value(regions[3].name(), '98') + + # Check observation setting by index from end + circle.name('99') + regions[-2] = circle + self.test_value(regions[-2].name(), '99') + + # Return + return + + # Test GSkyRegions class slicing + def _test_regions_slicing(self): + """ + Test GSkyRegions class slicing + """ + # Setup regions container + regions = self._setup_regions() + + # Perform slicing tests + test_support._container_slicing(self, regions) + + # Return + return + + def set(self): + """ + Set all test functions. + """ + # Set test name + self.name("sky") + + # Append tests + self.append(self._test_methods, "Test sky map methods") + self.append(self._test_friend_methods, "Test sky map friend methods") + self.append(self._test_operators, "Test sky map operators") + self.append(self._test_skymap_healpix, "Test HEALPix map") + self.append(self._test_skymap_ait, "Test AIT projection map") + self.append(self._test_skymap_azp, "Test AZP projection map") + self.append(self._test_skymap_car, "Test CAR projection map") + self.append(self._test_skymap_gls, "Test GLS projection map") + self.append(self._test_skymap_mer, "Test MER projection map") + self.append(self._test_skymap_mol, "Test MOL projection map") + self.append(self._test_skymap_sfl, "Test SFL projection map") + self.append(self._test_skymap_sin, "Test SIN projection map") + self.append(self._test_skymap_stg, "Test STG projection map") + self.append(self._test_skymap_tan, "Test TAN projection map") + self.append(self._test_regions_access, "Test GSkyRegions region access") + self.append(self._test_regions_slicing, "Test GSkyRegions slicing") + + # Return + return diff --git a/test/test_GSupport.py b/test/test_GSupport.py index a64cd0e..64c0e1c 100755 --- a/test/test_GSupport.py +++ b/test/test_GSupport.py @@ -1,7 +1,7 @@ # ========================================================================== # This module performs unit tests for the GammaLib support module. # -# Copyright (C) 2012-2016 Juergen Knoedlseder +# Copyright (C) 2012-2017 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 @@ -39,26 +39,26 @@ class Test(gammalib.GPythonTestSuite): # Return return - # Set all test functions - def set(self): - """ - Set all test functions. + # Setup GNodeArray container + def _setup_nodes(self): """ - # Set test name - self.name('support') + Setup GNodeArray - # Append tests - self.append(self.test_node_array, 'Test GNodeArray') - self.append(self.test_url_file, 'Test GUrlFile') - self.append(self.test_url_string, 'Test GUrlString') - self.append(self.test_filename, 'Test GFilename') - self.append(self.test_csv, 'Test GCsv') + Returns + ------- + nodes : `~gammalib.GNodeArray` + Node array + """ + # Setup time container + nodes = gammalib.GNodeArray() + for i in range(10): + nodes.append(float(i)) - # Return - return + # Return GNodeArray + return nodes # Test GNodeArray class - def test_node_array(self): + def _test_node_array(self): """ Test GNodeArray class. """ @@ -91,8 +91,91 @@ class Test(gammalib.GPythonTestSuite): # Return return + # Test GNodeArray access + def _test_node_array_access(self): + """ + Test GNodeArray access + """ + # Setup nodes container + nodes = self._setup_nodes() + + # Loop over all elements using the container iterator and count the + # number of iterations + nnodes = 0 + reference = 0.0 + for node in nodes: + self.test_value(node, reference) + nnodes += 1 + reference += 1.0 + + # Check that looping was successful + self.test_value(nodes.size(), 10, 'Check container size') + self.test_value(nnodes, 10, 'Check container iterator') + + # Test access from start + self.test_value(nodes[3], 3.0) + + # Check access from end + self.test_value(nodes[-2], 8.0) + + # Return + return + + # Test GNodeArray slicing + def _test_node_array_slicing(self): + """ + Test GNodeArray slicing + """ + # Setup nodes container + nodes = self._setup_nodes() + + # Test nodes[start:end] + self.test_value(len(nodes[3:5]), 2) + self.test_value(nodes[3:5][0], 3.0) + self.test_value(nodes[3:5][1], 4.0) + + # Test nodes[start:] + self.test_value(len(nodes[7:]), 3) + self.test_value(nodes[7:][0], 7.0) + self.test_value(nodes[7:][1], 8.0) + self.test_value(nodes[7:][2], 9.0) + + # Test nodes[:end] + self.test_value(len(nodes[:2]), 2) + self.test_value(nodes[:2][0], 0.0) + self.test_value(nodes[:2][1], 1.0) + + # Test nodes[:] + self.test_value(len(nodes[:]), 10) + for i in range(10): + self.test_value(nodes[:][i], float(i)) + + # Test nodes[start:end:step] + self.test_value(len(nodes[3:7:2]), 2) + self.test_value(nodes[3:7:2][0], 3.0) + self.test_value(nodes[3:7:2][1], 5.0) + + # Test nodes[start:end:step] + self.test_value(len(nodes[6:3:-2]), 2) + self.test_value(nodes[6:3:-2][0], 6.0) + self.test_value(nodes[6:3:-2][1], 4.0) + + # Test nodes[-start:] + self.test_value(len(nodes[-2:]), 2) + self.test_value(nodes[-2:][0], 8.0) + self.test_value(nodes[-2:][1], 9.0) + + # Test nodes[:-end] + self.test_value(len(nodes[:-7]), 3) + self.test_value(nodes[:-7][0], 0.0) + self.test_value(nodes[:-7][1], 1.0) + self.test_value(nodes[:-7][2], 2.0) + + # Return + return + # Test GUrlFile class - def test_url_file(self): + def _test_url_file(self): """ Test GUrlFile class. """ @@ -113,7 +196,7 @@ class Test(gammalib.GPythonTestSuite): return # Test GUrlString class - def test_url_string(self): + def _test_url_string(self): """ Test GUrlString class. """ @@ -133,7 +216,7 @@ class Test(gammalib.GPythonTestSuite): return # Test GFilename class - def test_filename(self): + def _test_filename(self): """ Test GFilename class. """ @@ -158,7 +241,7 @@ class Test(gammalib.GPythonTestSuite): return # Test GCsv class - def test_csv(self): + def _test_csv(self): """ Test GCsv class. """ @@ -195,3 +278,24 @@ class Test(gammalib.GPythonTestSuite): # Return return + + # Set all test functions + def set(self): + """ + Set all test functions. + """ + # Set test name + self.name('support') + + # Append tests + self.append(self._test_node_array, 'Test GNodeArray') + self.append(self._test_node_array_access, 'Test GNodeArray node access') + self.append(self._test_node_array_slicing, 'Test GNodeArray slicing') + self.append(self._test_url_file, 'Test GUrlFile') + self.append(self._test_url_string, 'Test GUrlString') + self.append(self._test_filename, 'Test GFilename') + self.append(self._test_csv, 'Test GCsv') + + # Return + return + diff --git a/test/test_GTest.py b/test/test_GTest.py index f1b68f2..79fc61f 100755 --- a/test/test_GTest.py +++ b/test/test_GTest.py @@ -1,7 +1,7 @@ # ========================================================================== # This module performs unit tests for the GammaLib test module. # -# Copyright (C) 2012-2015 Juergen Knoedlseder +# Copyright (C) 2012-2017 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 @@ -18,6 +18,7 @@ # # ========================================================================== import gammalib +import test_support # =================================== # @@ -25,12 +26,12 @@ import gammalib # =================================== # class Test(gammalib.GPythonTestSuite): """ - Test class for GammaLib test module. + Test class for GammaLib test module """ # Constructor def __init__(self): """ - Constructor. + Constructor """ # Call base class constructor gammalib.GPythonTestSuite.__init__(self) @@ -38,24 +39,76 @@ class Test(gammalib.GPythonTestSuite): # Return return - # Set test functions - def set(self): + # Setup test suite container + def _setup_suites(self): """ - Set all test functions. + Setup test suite container + + Returns + ------- + suites : `~gammalib.GTestSuites` + Test suite container """ - # Set test name - self.name("test") + # Setup test suite container + suites = gammalib.GTestSuites() + suite = gammalib.GPythonTestSuite() + for i in range(10): + suite.name('%s' % i) + suites.append(suite) - # Append tests - self.append(self.test, "Test module dummy test") + # Return test suite container + return suites + + # Test GTestSuites class access operators + def _test_suites_access(self): + """ + Test GTestSuites class parameter access + """ + # Setup test suite container and test suite + suites = self._setup_suites() + suite = gammalib.GPythonTestSuite() + + # Perform GTestSuites access tests + test_support._container_access_index(self, suites) + + # Check parameter setting by index from start + suite.name('98') + suites[3] = suite + self.test_value(suites[3].name(), '98') + + # Check parameter setting by index from end + suite.name('99') + suites[-2] = suite + self.test_value(suites[-2].name(), '99') + + # Return + return + + # Test GTestSuites class slicing + def _test_suites_slicing(self): + """ + Test GTestSuites class slicing + """ + # Setup test suite container + suites = self._setup_suites() + + # Perform slicing tests + test_support._container_slicing(self, suites) # Return return - # Test function - def test(self): + # Set test functions + def set(self): """ - Test function. + Set all test functions. """ + # Set test name + self.name('test') + + # Append tests + self.append(self._test_suites_access, 'Test GTestSuites parameter access') + self.append(self._test_suites_slicing, 'Test GTestSuites slicing') + # Return return diff --git a/test/test_GXml.py b/test/test_GXml.py index 24522ea..f5c5741 100755 --- a/test/test_GXml.py +++ b/test/test_GXml.py @@ -1,7 +1,7 @@ # ========================================================================== # This module performs unit tests for the GammaLib xml module. # -# Copyright (C) 2012-2015 Juergen Knoedlseder +# Copyright (C) 2012-2017 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 @@ -18,6 +18,7 @@ # # ========================================================================== import gammalib +import test_support # ================================== # @@ -25,7 +26,7 @@ import gammalib # ================================== # class Test(gammalib.GPythonTestSuite): """ - Test class for GammaLib xml module. + Test class for GammaLib xml module """ # Constructor def __init__(self): @@ -38,24 +39,137 @@ class Test(gammalib.GPythonTestSuite): # Return return - # Set test functions - def set(self): + # Setup GXml container + def _setup_xml(self): """ - Set all test functions. + Setup GXml container + + Returns + ------- + xml : `~gammalib.GXml` + GXml container """ - # Set test name - self.name("xml") + # Setup XML container + xml = gammalib.GXml() + element = gammalib.GXmlElement() + for i in range(10): + element.name('%s' % i) + xml.append(element) - # Append tests - self.append(self.test, "XML module dummy test") + # Return XML container + return xml + + # Setup GXmlElement container + def _setup_elements(self): + """ + Setup GXmlElement container + + Returns + ------- + elements : `~gammalib.GXmlElement` + GXml container + """ + # Setup GXmlElement container + elements = gammalib.GXmlElement() + element = gammalib.GXmlElement() + for i in range(10): + element.name('%s' % i) + elements.append(element) + + # Return GXmlElement container + return elements + + # Test GXml class access operators + def _test_xml_access(self): + """ + Test GXml class parameter access + """ + # Setup XML container and element + xml = self._setup_xml() + element = gammalib.GXmlElement() + + # Perform GXml access tests + test_support._container_access_index(self, xml) + + # Check parameter setting by index from start + element.name('98') + xml[3] = element + self.test_value(xml[3].name(), '98') + + # Check parameter setting by index from end + element.name('99') + xml[-2] = element + self.test_value(xml[-2].name(), '99') + + # Return + return + + # Test GXml class slicing + def _test_xml_slicing(self): + """ + Test GXml class slicing + """ + # Setup XML container + xml = self._setup_xml() + + # Perform slicing tests + test_support._container_slicing(self, xml) # Return return - # Test function - def test(self): + # Test GXmlElement class access operators + def _test_elements_access(self): """ - Test function. + Test GXmlElement class parameter access """ + # Setup GXmlElement container and element + elements = self._setup_elements() + element = gammalib.GXmlElement() + + # Perform GXmlElement access tests + test_support._container_access_index(self, elements) + + # Check parameter setting by index from start + element.name('98') + elements[3] = element + self.test_value(elements[3].name(), '98') + + # Check parameter setting by index from end + element.name('99') + elements[-2] = element + self.test_value(elements[-2].name(), '99') + + # Return + return + + # Test GXmlElement class slicing + def _test_elements_slicing(self): + """ + Test GXmlElement class slicing + """ + # Setup GXmlElement container + elements = self._setup_elements() + + # Perform slicing tests + test_support._container_slicing(self, elements) + + # Return + return + + # Set test functions + def set(self): + """ + Set all test functions. + """ + # Set test name + self.name('xml') + + # Append tests + self.append(self._test_xml_access, 'Test GXml parameter access') + self.append(self._test_xml_slicing, 'Test GXml slicing') + self.append(self._test_elements_access, 'Test GXmlElement parameter access') + self.append(self._test_elements_slicing, 'Test GXmlElement slicing') + # Return return diff --git a/test/test_support.py b/test/test_support.py index f281fe4..826a63b 100755 --- a/test/test_support.py +++ b/test/test_support.py @@ -50,6 +50,69 @@ def _container_access_index(testsuite, container): # Check access from end testsuite.test_value(container[-2].name(), '8') + # Clone first element + #element = container[0].copy() + + # Check setting by index from start + #element.name('98') + #container[3] = element + #self.test_value(container[3].name(), '98') + + # Check setting by index from end + #element.name('99') + #container[-2] = element + #self.test_value(container[-2].name(), '99') + + # Return + return + + +# ===================================== # +# Test energy container access by index # +# ===================================== # +def _energy_container_access_index(testsuite, container): + """ + Test energy container access by index + + Parameters + ---------- + testsuite : `~gammalib.GPythonTestSuite` + Test suite class + container : `~gammalib.GContainer` + Container class + """ + # Loop over all elements using the container iterator and count the number + # of iterations + niter = 0 + reference = 0.0 + for element in container: + testsuite.test_value(element.energy().MeV(), reference) + niter += 1 + reference += 1.0 + + # Check that looping was successful + testsuite.test_value(container.size(), 10, 'Check container size') + testsuite.test_value(niter, 10, 'Check container iterator') + + # Test access from start + testsuite.test_value(container[3].energy().MeV(), 3.0) + + # Check access from end + testsuite.test_value(container[-2].energy().MeV(), 8.0) + + # Clone first element + element = container[0].copy() + + # Check setting by index from start + element.energy().MeV(98.0) + container[3] = element + testsuite.test_value(container[3].energy().MeV(), 98.0) + + # Check setting setting by index from end + element.energy().MeV(99.0) + container[-2] = element + testsuite.test_value(container[-2].energy().MeV(), 99.0) + # Return return @@ -112,3 +175,63 @@ def _container_slicing(testsuite, container): # Return return + + +# ============================= # +# Test energy container slicing # +# ============================= # +def _energy_container_slicing(testsuite, container): + """ + Test energy container slicing + + Parameters + ---------- + testsuite : `~gammalib.GPythonTestSuite` + Test suite class + container : `~gammalib.GContainer` + Container class + """ + # Test container[start:end] + testsuite.test_value(len(container[3:5]), 2) + testsuite.test_value(container[3:5][0].energy().MeV(), 3.0) + testsuite.test_value(container[3:5][1].energy().MeV(), 4.0) + + # Test container[start:] + testsuite.test_value(len(container[7:]), 3) + testsuite.test_value(container[7:][0].energy().MeV(), 7.0) + testsuite.test_value(container[7:][1].energy().MeV(), 8.0) + testsuite.test_value(container[7:][2].energy().MeV(), 9.0) + + # Test container[:end] + testsuite.test_value(len(container[:2]), 2) + testsuite.test_value(container[:2][0].energy().MeV(), 0.0) + testsuite.test_value(container[:2][1].energy().MeV(), 1.0) + + # Test container[:] + testsuite.test_value(len(container[:]), 10) + for i in range(10): + testsuite.test_value(container[:][i].energy().MeV(), float(i)) + + # Test container[start:end:step] + testsuite.test_value(len(container[3:7:2]), 2) + testsuite.test_value(container[3:7:2][0].energy().MeV(), 3.0) + testsuite.test_value(container[3:7:2][1].energy().MeV(), 5.0) + + # Test container[start:end:step] + testsuite.test_value(len(container[6:3:-2]), 2) + testsuite.test_value(container[6:3:-2][0].energy().MeV(), 6.0) + testsuite.test_value(container[6:3:-2][1].energy().MeV(), 4.0) + + # Test container[-start:] + testsuite.test_value(len(container[-2:]), 2) + testsuite.test_value(container[-2:][0].energy().MeV(), 8.0) + testsuite.test_value(container[-2:][1].energy().MeV(), 9.0) + + # Test container[:-end] + testsuite.test_value(len(container[:-7]), 3) + testsuite.test_value(container[:-7][0].energy().MeV(), 0.0) + testsuite.test_value(container[:-7][1].energy().MeV(), 1.0) + testsuite.test_value(container[:-7][2].energy().MeV(), 2.0) + + # Return + return