Commit e6d15df1b5ae55579f053c455c267011a3857f2a

Authored by Jürgen Knödlseder
1 parent b8b92464

Support Python container slicing (#2128)

ChangeLog
1 -2017-06-22 1 +2017-07-22
2 2
3 * Version 1.4.0 released 3 * Version 1.4.0 released
4 ========================= 4 =========================
1 New Features and Important Changes in GammaLib 1.4.0 1 New Features and Important Changes in GammaLib 1.4.0
2 2
3 -22 June 2017 3 +22 July 2017
4 4
5 5
6 1. Introduction 6 1. Introduction
@@ -21,7 +21,13 @@ The following classes have been renamed: @@ -21,7 +21,13 @@ The following classes have been renamed:
21 - n.a. 21 - n.a.
22 22
23 The following methods have been added: 23 The following methods have been added:
24 -- n.a. 24 +- GSkyRegion::type(std::string&)
  25 +- GSkyRegion::name(std::string&)
  26 +- GSkyRegion::solidangle(std::string&)
  27 +- GOptimizerPars::append(GOptimizerPar&)
  28 +- GLATEventList::append(GLATEventAtom&)
  29 +- GLATEventList::reserve(int&)
  30 +- GLATEventList::remove(int&,int&)
25 31
26 The following methods have been removed: 32 The following methods have been removed:
27 - n.a. 33 - n.a.
@@ -78,12 +84,13 @@ None @@ -78,12 +84,13 @@ None
78 84
79 11. Optimization module 85 11. Optimization module
80 ----------------------- 86 -----------------------
81 -None 87 +Add GOptimizerPars::append() method to allow appending of parameters to the
  88 +container.
82 89
83 90
84 12. Sky module 91 12. Sky module
85 -------------- 92 --------------
86 -None 93 +Add methods to set the name, type and solid angle of a sky region.
87 94
88 95
89 13. Support module 96 13. Support module
@@ -118,7 +125,7 @@ None @@ -118,7 +125,7 @@ None
118 125
119 19. Fermi-LAT interface 126 19. Fermi-LAT interface
120 ---------------------- 127 ----------------------
121 -None 128 +Add append(), remove() and reserve() methods to GLATEventList class.
122 129
123 130
124 20. CTA interface 131 20. CTA interface
include/GOptimizerPars.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * GOptimizerPars.hpp - Optimizer parameter container class * 2 * GOptimizerPars.hpp - Optimizer parameter container class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2009-2015 by Juergen Knoedlseder * 4 + * copyright (C) 2009-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -75,6 +75,7 @@ public: @@ -75,6 +75,7 @@ public:
75 int nfree(void) const; 75 int nfree(void) const;
76 GOptimizerPar* set(const int& index, const GOptimizerPar& par); 76 GOptimizerPar* set(const int& index, const GOptimizerPar& par);
77 GOptimizerPar* set(const std::string& name, const GOptimizerPar& par); 77 GOptimizerPar* set(const std::string& name, const GOptimizerPar& par);
  78 + GOptimizerPar* append(const GOptimizerPar& par);
78 void attach(GOptimizerPar* par); 79 void attach(GOptimizerPar* par);
79 void attach(const int& index, GOptimizerPar* par); 80 void attach(const int& index, GOptimizerPar* par);
80 void attach(const std::string& name, GOptimizerPar* par); 81 void attach(const std::string& name, GOptimizerPar* par);
include/GSkyRegion.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * GSkyRegion.hpp - Abstract virtual sky region base class * 2 * GSkyRegion.hpp - Abstract virtual sky region base class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2013-2014 by Pierrick Martin * 4 + * copyright (C) 2013-2017 by Pierrick Martin *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -80,6 +80,9 @@ public: @@ -80,6 +80,9 @@ public:
80 const std::string& type(void) const; 80 const std::string& type(void) const;
81 const std::string& name(void) const; 81 const std::string& name(void) const;
82 const double& solidangle(void) const; 82 const double& solidangle(void) const;
  83 + void type(const std::string& type);
  84 + void name(const std::string& name);
  85 + void solidangle(const double& solidangle);
83 86
84 protected: 87 protected:
85 // Protected methods 88 // Protected methods
@@ -109,6 +112,21 @@ const std::string& GSkyRegion::name(void) const @@ -109,6 +112,21 @@ const std::string& GSkyRegion::name(void) const
109 112
110 113
111 /***********************************************************************//** 114 /***********************************************************************//**
  115 + * @brief Set region name
  116 + *
  117 + * @param[in] name Region name.
  118 + *
  119 + * Sets the region name.
  120 + ***************************************************************************/
  121 +inline
  122 +void GSkyRegion::name(const std::string& name)
  123 +{
  124 + m_name = name;
  125 + return;
  126 +}
  127 +
  128 +
  129 +/***********************************************************************//**
112 * @brief Return region type 130 * @brief Return region type
113 * 131 *
114 * @return Region type 132 * @return Region type
@@ -123,16 +141,46 @@ const std::string& GSkyRegion::type(void) const @@ -123,16 +141,46 @@ const std::string& GSkyRegion::type(void) const
123 141
124 142
125 /***********************************************************************//** 143 /***********************************************************************//**
126 - * @brief Return solid angle 144 + * @brief Set region type
  145 + *
  146 + * @param[in] type Region type.
  147 + *
  148 + * Sets the region type.
  149 + ***************************************************************************/
  150 +inline
  151 +void GSkyRegion::type(const std::string& type)
  152 +{
  153 + m_type = type;
  154 + return;
  155 +}
  156 +
  157 +
  158 +/***********************************************************************//**
  159 + * @brief Return solid angle of region
127 * 160 *
128 - * @return Solid angle 161 + * @return Solid angle of region.
129 * 162 *
130 - * Returns the solid angle subtended by the region (in steradian). 163 + * Returns the solid angle subtended by the region (in steradians).
131 ***************************************************************************/ 164 ***************************************************************************/
132 inline 165 inline
133 const double& GSkyRegion::solidangle(void) const 166 const double& GSkyRegion::solidangle(void) const
134 { 167 {
135 return (m_solid); 168 return (m_solid);
136 } 169 }
137 - 170 +
  171 +
  172 +/***********************************************************************//**
  173 + * @brief Set solid angle of region
  174 + *
  175 + * @param[in] solidangle Solid angle of region (in steradians).
  176 + *
  177 + * Sets the solid angle subtended by the region (in steradians).
  178 + ***************************************************************************/
  179 +inline
  180 +void GSkyRegion::solidangle(const double& solidangle)
  181 +{
  182 + m_solid = solidangle;
  183 + return;
  184 +}
  185 +
138 #endif /* GSKYREGION_HPP */ 186 #endif /* GSKYREGION_HPP */
inst/cta/pyext/GCTAEventList.i
@@ -90,19 +90,64 @@ public: @@ -90,19 +90,64 @@ public:
90 * @brief GCTAEventList class extension 90 * @brief GCTAEventList class extension
91 ***************************************************************************/ 91 ***************************************************************************/
92 %extend GCTAEventList { 92 %extend GCTAEventList {
93 - GCTAEventList copy() {  
94 - return (*self);  
95 - }  
96 - GCTAEventAtom* __getitem__(int index) {  
97 - if (index >= 0 && index < self->size()) 93 + GCTAEventAtom* __getitem__(const int& index) {
  94 + // Counting from start, e.g. [2]
  95 + if (index >= 0 && index < self->size()) {
98 return (*self)[index]; 96 return (*self)[index];
99 - else  
100 - throw GException::out_of_range("__getitem__(int)", index, self->size()); 97 + }
  98 + // Counting from end, e.g. [-1]
  99 + else if (index < 0 && self->size()+index >= 0) {
  100 + return (*self)[self->size()+index];
  101 + }
  102 + else {
  103 + throw GException::out_of_range("__getitem__(int)", "Event index",
  104 + index, self->size());
  105 + }
  106 + }
  107 + GCTAEventList* __getitem__(PyObject *param) {
  108 + if (PySlice_Check(param)) {
  109 + Py_ssize_t start = 0;
  110 + Py_ssize_t stop = 0;
  111 + Py_ssize_t step = 0;
  112 + Py_ssize_t len = self->size();
  113 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  114 + GCTAEventList* list = new GCTAEventList;
  115 + if (step > 0) {
  116 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  117 + list->append(*(*self)[i]);
  118 + }
  119 + }
  120 + else {
  121 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  122 + list->append(*(*self)[i]);
  123 + }
  124 + }
  125 + return list;
  126 + }
  127 + else {
  128 + throw GException::invalid_argument("__getitem__(PyObject)",
  129 + "Invalid slice indices");
  130 + }
  131 + }
  132 + else {
  133 + throw GException::invalid_argument("__getitem__(PyObject)","");
  134 + }
101 } 135 }
102 - void __setitem__(int index, const GCTAEventAtom& val) {  
103 - if (index>=0 && index < self->size())  
104 - *((*self)[index]) = val;  
105 - else  
106 - throw GException::out_of_range("__setitem__(int)", index, self->size()); 136 + void __setitem__(const int& index, const GCTAEventAtom& event) {
  137 + // Counting from start, e.g. [2]
  138 + if (index >= 0 && index < self->size()) {
  139 + *(*self)[index] = event;
  140 + }
  141 + // Counting from end, e.g. [-1]
  142 + else if (index < 0 && self->size()+index >= 0) {
  143 + *(*self)[self->size()+index] = event;
  144 + }
  145 + else {
  146 + throw GException::out_of_range("__setitem__(int)", "Event index",
  147 + index, self->size());
  148 + }
  149 + }
  150 + GCTAEventList copy() {
  151 + return (*self);
107 } 152 }
108 }; 153 };
inst/cta/test/test_CTA.py
@@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
20 import os 20 import os
21 import gammalib 21 import gammalib
22 import math 22 import math
  23 +import test_support
23 24
24 25
25 # ================================== # 26 # ================================== #
@@ -27,12 +28,12 @@ import math @@ -27,12 +28,12 @@ import math
27 # ================================== # 28 # ================================== #
28 class Test(gammalib.GPythonTestSuite): 29 class Test(gammalib.GPythonTestSuite):
29 """ 30 """
30 - Test class for GammaLib CTA module. 31 + Test class for GammaLib CTA module
31 """ 32 """
32 # Constructor 33 # Constructor
33 def __init__(self): 34 def __init__(self):
34 """ 35 """
35 - Constructor. 36 + Constructor
36 """ 37 """
37 # Call base class constructor 38 # Call base class constructor
38 gammalib.GPythonTestSuite.__init__(self) 39 gammalib.GPythonTestSuite.__init__(self)
@@ -44,28 +45,58 @@ class Test(gammalib.GPythonTestSuite): @@ -44,28 +45,58 @@ class Test(gammalib.GPythonTestSuite):
44 # Return 45 # Return
45 return 46 return
46 47
47 - # Set test functions  
48 - def set(self): 48 + # Setup GCTAEventList container
  49 + def _setup_eventlist(self):
49 """ 50 """
50 - Set all test functions. 51 + Setup GCTAEventList container
  52 +
  53 + Returns
  54 + -------
  55 + list : `~gammalib.GCTAEventList`
  56 + GCTAEventList container
51 """ 57 """
52 - # Set test name  
53 - self.name('CTA') 58 + # Setup event list container
  59 + list = gammalib.GCTAEventList()
  60 + atom = gammalib.GCTAEventAtom()
  61 + for i in range(10):
  62 + atom.energy().MeV(float(i))
  63 + list.append(atom)
  64 +
  65 + # Return event list container
  66 + return list
  67 +
  68 + # Test GCTAEventList class access operators
  69 + def _test_eventlist_access(self):
  70 + """
  71 + Test GCTAEventList class observation access
  72 + """
  73 + # Setup event list container
  74 + list = self._setup_eventlist()
54 75
55 - # Append tests  
56 - self.append(self.test_aeff, 'Test CTA effective area classes')  
57 - self.append(self.test_psf, 'Test CTA PSF classes')  
58 - self.append(self.test_edisp, 'Test CTA energy dispersion classes')  
59 - self.append(self.test_response, 'Test CTA response classes')  
60 - self.append(self.test_onoff, 'Test CTA On/Off analysis') 76 + # Perform event list access tests
  77 + test_support._energy_container_access_index(self, list)
  78 +
  79 + # Return
  80 + return
  81 +
  82 + # Test GCTAEventList class slicing
  83 + def _test_eventlist_slicing(self):
  84 + """
  85 + Test GCTAEventList class slicing
  86 + """
  87 + # Setup event list container
  88 + list = self._setup_eventlist()
  89 +
  90 + # Perform slicing tests
  91 + test_support._energy_container_slicing(self, list)
61 92
62 # Return 93 # Return
63 return 94 return
64 95
65 # Test effective area response 96 # Test effective area response
66 - def test_aeff(self): 97 + def _test_aeff(self):
67 """ 98 """
68 - Test GCTAAeff classes. 99 + Test GCTAAeff classes
69 """ 100 """
70 # Test GCTAAeff2D file constructor 101 # Test GCTAAeff2D file constructor
71 filename = self._caldb + '/prod1_gauss.fits' 102 filename = self._caldb + '/prod1_gauss.fits'
@@ -119,9 +150,9 @@ class Test(gammalib.GPythonTestSuite): @@ -119,9 +150,9 @@ class Test(gammalib.GPythonTestSuite):
119 return 150 return
120 151
121 # Test point spread function response 152 # Test point spread function response
122 - def test_psf(self): 153 + def _test_psf(self):
123 """ 154 """
124 - Test GCTAPsf classes. 155 + Test GCTAPsf classes
125 """ 156 """
126 # Test GCTAPsf2D file constructor 157 # Test GCTAPsf2D file constructor
127 filename = self._caldb + '/prod1_gauss.fits' 158 filename = self._caldb + '/prod1_gauss.fits'
@@ -175,9 +206,9 @@ class Test(gammalib.GPythonTestSuite): @@ -175,9 +206,9 @@ class Test(gammalib.GPythonTestSuite):
175 return 206 return
176 207
177 # Test energy dispersion 208 # Test energy dispersion
178 - def test_edisp(self): 209 + def _test_edisp(self):
179 """ 210 """
180 - Test GCTAEdisp classes. 211 + Test GCTAEdisp classes
181 """ 212 """
182 # Test GCTAEdispRmf file constructor 213 # Test GCTAEdispRmf file constructor
183 filename = self._caldb + '/dc1/rmf.fits' 214 filename = self._caldb + '/dc1/rmf.fits'
@@ -222,7 +253,7 @@ class Test(gammalib.GPythonTestSuite): @@ -222,7 +253,7 @@ class Test(gammalib.GPythonTestSuite):
222 # 0.5, 0.005) 253 # 0.5, 0.005)
223 254
224 # Test response 255 # Test response
225 - def test_response(self): 256 + def _test_response(self):
226 """ 257 """
227 Test response classes 258 Test response classes
228 """ 259 """
@@ -234,9 +265,9 @@ class Test(gammalib.GPythonTestSuite): @@ -234,9 +265,9 @@ class Test(gammalib.GPythonTestSuite):
234 return 265 return
235 266
236 # Test On/Off analysis 267 # Test On/Off analysis
237 - def test_onoff(self): 268 + def _test_onoff(self):
238 """ 269 """
239 - Test On/Off analysis. 270 + Test On/Off analysis
240 """ 271 """
241 # Create On region 272 # Create On region
242 crab = gammalib.GSkyDir() 273 crab = gammalib.GSkyDir()
@@ -271,9 +302,6 @@ class Test(gammalib.GPythonTestSuite): @@ -271,9 +302,6 @@ class Test(gammalib.GPythonTestSuite):
271 lm = gammalib.GOptimizerLM() 302 lm = gammalib.GOptimizerLM()
272 outobs.optimize(lm) 303 outobs.optimize(lm)
273 outobs.errors(lm) 304 outobs.errors(lm)
274 - #print(lm)  
275 - #print(outobs)  
276 - #print(outobs.models())  
277 305
278 # Test On/Off model fitting results 306 # Test On/Off model fitting results
279 sky = outobs.models()['Crab'] 307 sky = outobs.models()['Crab']
@@ -307,3 +335,23 @@ class Test(gammalib.GPythonTestSuite): @@ -307,3 +335,23 @@ class Test(gammalib.GPythonTestSuite):
307 335
308 # Return 336 # Return
309 return 337 return
  338 +
  339 + # Set test functions
  340 + def set(self):
  341 + """
  342 + Set all test functions.
  343 + """
  344 + # Set test name
  345 + self.name('CTA')
  346 +
  347 + # Append tests
  348 + self.append(self._test_eventlist_access, 'Test GCTAEventList event access')
  349 + self.append(self._test_eventlist_slicing, 'Test GCTAEventList slicing')
  350 + self.append(self._test_aeff, 'Test CTA effective area classes')
  351 + self.append(self._test_psf, 'Test CTA PSF classes')
  352 + self.append(self._test_edisp, 'Test CTA energy dispersion classes')
  353 + self.append(self._test_response, 'Test CTA response classes')
  354 + self.append(self._test_onoff, 'Test CTA On/Off analysis')
  355 +
  356 + # Return
  357 + return
inst/lat/include/GLATEventList.hpp
@@ -61,7 +61,7 @@ public: @@ -61,7 +61,7 @@ public:
61 virtual ~GLATEventList(void); 61 virtual ~GLATEventList(void);
62 62
63 // Operators 63 // Operators
64 - virtual GLATEventList& operator= (const GLATEventList& list); 64 + virtual GLATEventList& operator=(const GLATEventList& list);
65 virtual GLATEventAtom* operator[](const int& index); 65 virtual GLATEventAtom* operator[](const int& index);
66 virtual const GLATEventAtom* operator[](const int& index) const; 66 virtual const GLATEventAtom* operator[](const int& index) const;
67 67
@@ -81,6 +81,9 @@ public: @@ -81,6 +81,9 @@ public:
81 virtual std::string print(const GChatter& chatter = NORMAL) const; 81 virtual std::string print(const GChatter& chatter = NORMAL) const;
82 82
83 // Other methods 83 // Other methods
  84 + void append(const GLATEventAtom& event);
  85 + void reserve(const int& number);
  86 + void remove(const int& index, const int& number = 1);
84 87
85 protected: 88 protected:
86 // Protected methods 89 // Protected methods
@@ -93,13 +96,13 @@ protected: @@ -93,13 +96,13 @@ protected:
93 void read_ds_keys(const GFitsHDU& hdu); 96 void read_ds_keys(const GFitsHDU& hdu);
94 97
95 // Protected members 98 // Protected members
96 - GLATRoi m_roi; //!< Region of interest  
97 - std::vector<GLATEventAtom> m_events; //!< Events  
98 - std::vector<std::string> m_difrsp_label; //!< Diffuse response model labels  
99 - std::vector<std::string> m_ds_type; //!< Data selection types  
100 - std::vector<std::string> m_ds_unit; //!< Data selection units  
101 - std::vector<std::string> m_ds_value; //!< Data selection values  
102 - std::vector<std::string> m_ds_reference; //!< Data selection references 99 + GLATRoi m_roi; //!< Region of interest
  100 + std::vector<GLATEventAtom> m_events; //!< Events
  101 + std::vector<std::string> m_difrsp_label; //!< Diffuse response model labels
  102 + std::vector<std::string> m_ds_type; //!< Data selection types
  103 + std::vector<std::string> m_ds_unit; //!< Data selection units
  104 + std::vector<std::string> m_ds_value; //!< Data selection values
  105 + std::vector<std::string> m_ds_reference; //!< Data selection references
103 }; 106 };
104 107
105 108
@@ -150,4 +153,19 @@ const GLATRoi&amp; GLATEventList::roi(void) const @@ -150,4 +153,19 @@ const GLATRoi&amp; GLATEventList::roi(void) const
150 return m_roi; 153 return m_roi;
151 } 154 }
152 155
  156 +
  157 +/***********************************************************************//**
  158 + * @brief Reserves space for events
  159 + *
  160 + * @param[in] number Number of events.
  161 + *
  162 + * Reserves space for number events in the event list.
  163 + ***************************************************************************/
  164 +inline
  165 +void GLATEventList::reserve(const int& number)
  166 +{
  167 + m_events.reserve(number);
  168 + return;
  169 +}
  170 +
153 #endif /* GLATEVENTLIST_HPP */ 171 #endif /* GLATEVENTLIST_HPP */
inst/lat/pyext/GLATEventList.i
1 /*************************************************************************** 1 /***************************************************************************
2 * GLATEventList.i - Fermi/LAT event list class * 2 * GLATEventList.i - Fermi/LAT event list class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2012-2016 by Juergen Knoedlseder * 4 + * copyright (C) 2012-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -56,6 +56,11 @@ public: @@ -56,6 +56,11 @@ public:
56 virtual int number(void) const; 56 virtual int number(void) const;
57 virtual void roi(const GRoi& roi); 57 virtual void roi(const GRoi& roi);
58 virtual const GLATRoi& roi(void) const; 58 virtual const GLATRoi& roi(void) const;
  59 +
  60 + // Other methods
  61 + void append(const GLATEventAtom& event);
  62 + void reserve(const int& number);
  63 + void remove(const int& index, const int& number = 1);
59 }; 64 };
60 65
61 66
@@ -63,25 +68,64 @@ public: @@ -63,25 +68,64 @@ public:
63 * @brief GLATEventList class extension 68 * @brief GLATEventList class extension
64 ***************************************************************************/ 69 ***************************************************************************/
65 %extend GLATEventList { 70 %extend GLATEventList {
66 - GLATEventList copy() {  
67 - return (*self);  
68 - }  
69 GLATEventAtom* __getitem__(const int& index) { 71 GLATEventAtom* __getitem__(const int& index) {
  72 + // Counting from start, e.g. [2]
70 if (index >= 0 && index < self->size()) { 73 if (index >= 0 && index < self->size()) {
71 - return ((*self)[index]); 74 + return (*self)[index];
  75 + }
  76 + // Counting from end, e.g. [-1]
  77 + else if (index < 0 && self->size()+index >= 0) {
  78 + return (*self)[self->size()+index];
72 } 79 }
73 else { 80 else {
74 throw GException::out_of_range("__getitem__(int)", "Event index", 81 throw GException::out_of_range("__getitem__(int)", "Event index",
75 index, self->size()); 82 index, self->size());
76 } 83 }
77 } 84 }
78 - void __setitem__(const int& index, const GLATEventAtom& value) {  
79 - if (index>=0 && index < self->size()) {  
80 - *((*self)[index]) = value; 85 + GLATEventList* __getitem__(PyObject *param) {
  86 + if (PySlice_Check(param)) {
  87 + Py_ssize_t start = 0;
  88 + Py_ssize_t stop = 0;
  89 + Py_ssize_t step = 0;
  90 + Py_ssize_t len = self->size();
  91 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  92 + GLATEventList* list = new GLATEventList;
  93 + if (step > 0) {
  94 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  95 + list->append(*(*self)[i]);
  96 + }
  97 + }
  98 + else {
  99 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  100 + list->append(*(*self)[i]);
  101 + }
  102 + }
  103 + return list;
  104 + }
  105 + else {
  106 + throw GException::invalid_argument("__getitem__(PyObject)",
  107 + "Invalid slice indices");
  108 + }
  109 + }
  110 + else {
  111 + throw GException::invalid_argument("__getitem__(PyObject)","");
  112 + }
  113 + }
  114 + void __setitem__(const int& index, const GLATEventAtom& event) {
  115 + // Counting from start, e.g. [2]
  116 + if (index >= 0 && index < self->size()) {
  117 + *(*self)[index] = event;
  118 + }
  119 + // Counting from end, e.g. [-1]
  120 + else if (index < 0 && self->size()+index >= 0) {
  121 + *(*self)[self->size()+index] = event;
81 } 122 }
82 else { 123 else {
83 throw GException::out_of_range("__setitem__(int)", "Event index", 124 throw GException::out_of_range("__setitem__(int)", "Event index",
84 index, self->size()); 125 index, self->size());
85 } 126 }
86 } 127 }
  128 + GLATEventList copy() {
  129 + return (*self);
  130 + }
87 }; 131 };
inst/lat/src/GLATEventList.cpp
@@ -384,9 +384,56 @@ void GLATEventList::roi(const GRoi&amp; roi) @@ -384,9 +384,56 @@ void GLATEventList::roi(const GRoi&amp; roi)
384 384
385 385
386 /***********************************************************************//** 386 /***********************************************************************//**
  387 + * @brief Append event to event list
  388 + *
  389 + * @param[in] event Event.
  390 + *
  391 + * Appends an event to the end of the event list.
  392 + ***************************************************************************/
  393 +void GLATEventList::append(const GLATEventAtom& event)
  394 +{
  395 + // Append event
  396 + m_events.push_back(event);
  397 +
  398 + // Return
  399 + return;
  400 +}
  401 +
  402 +
  403 +/***********************************************************************//**
  404 + * @brief Remove events from event list
  405 + *
  406 + * @param[in] index Index from which on events should be removed.
  407 + * @param[in] number Number of event to remove (default: 1).
  408 + *
  409 + * Removes events from the event list. This method does nothing if @p index
  410 + * points beyond the event list. The method does also gently accept
  411 + * @p number arguments where @p index + @p number reach beyond the event
  412 + * list. In that case, all events from event @p index on will be removed.
  413 + ***************************************************************************/
  414 +void GLATEventList::remove(const int& index, const int& number)
  415 +{
  416 + // Continue only if index is valid
  417 + if (index < size()) {
  418 +
  419 + // Determine number of elements to remove
  420 + int n_remove = (index + number > size()) ? size() - index : number;
  421 +
  422 + // Remove events
  423 + m_events.erase(m_events.begin() + index,
  424 + m_events.begin() + index + n_remove);
  425 +
  426 + } // endif: index was valid
  427 +
  428 + // Return
  429 + return;
  430 +}
  431 +
  432 +
  433 +/***********************************************************************//**
387 * @brief Print event list information 434 * @brief Print event list information
388 * 435 *
389 - * @param[in] chatter Chattiness (defaults to NORMAL). 436 + * @param[in] chatter Chattiness.
390 * @return String containing event list information. 437 * @return String containing event list information.
391 ***************************************************************************/ 438 ***************************************************************************/
392 std::string GLATEventList::print(const GChatter& chatter) const 439 std::string GLATEventList::print(const GChatter& chatter) const
inst/lat/test/test_LAT.py
1 # ========================================================================== 1 # ==========================================================================
2 # This module performs unit tests for the GammaLib LAT module. 2 # This module performs unit tests for the GammaLib LAT module.
3 # 3 #
4 -# Copyright (C) 2012-2015 Juergen Knoedlseder 4 +# Copyright (C) 2012-2017 Juergen Knoedlseder
5 # 5 #
6 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by 7 # it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 # 18 #
19 # ========================================================================== 19 # ==========================================================================
20 import gammalib 20 import gammalib
  21 +import test_support
21 22
22 23
23 # ================================== # 24 # ================================== #
@@ -25,12 +26,12 @@ import gammalib @@ -25,12 +26,12 @@ import gammalib
25 # ================================== # 26 # ================================== #
26 class Test(gammalib.GPythonTestSuite): 27 class Test(gammalib.GPythonTestSuite):
27 """ 28 """
28 - Test class for GammaLib LAT module. 29 + Test class for GammaLib LAT module
29 """ 30 """
30 # Constructor 31 # Constructor
31 def __init__(self): 32 def __init__(self):
32 """ 33 """
33 - Constructor. 34 + Constructor
34 """ 35 """
35 # Call base class constructor 36 # Call base class constructor
36 gammalib.GPythonTestSuite.__init__(self) 37 gammalib.GPythonTestSuite.__init__(self)
@@ -38,24 +39,65 @@ class Test(gammalib.GPythonTestSuite): @@ -38,24 +39,65 @@ class Test(gammalib.GPythonTestSuite):
38 # Return 39 # Return
39 return 40 return
40 41
41 - # Set test functions  
42 - def set(self): 42 + # Setup GLATEventList container
  43 + def _setup_eventlist(self):
43 """ 44 """
44 - Set all test functions. 45 + Setup GLATEventList container
  46 +
  47 + Returns
  48 + -------
  49 + list : `~gammalib.GLATEventList`
  50 + GLATEventList container
45 """ 51 """
46 - # Set test name  
47 - self.name("LAT") 52 + # Setup event list container
  53 + list = gammalib.GLATEventList()
  54 + atom = gammalib.GLATEventAtom()
  55 + for i in range(10):
  56 + atom.energy().MeV(float(i))
  57 + list.append(atom)
48 58
49 - # Append tests  
50 - self.append(self.test, "LAT dummy test") 59 + # Return event list container
  60 + return list
  61 +
  62 + # Test GLATEventList class access operators
  63 + def _test_eventlist_access(self):
  64 + """
  65 + Test GLATEventList class observation access
  66 + """
  67 + # Setup event list container
  68 + list = self._setup_eventlist()
  69 +
  70 + # Perform event list access tests
  71 + test_support._energy_container_access_index(self, list)
  72 +
  73 + # Return
  74 + return
  75 +
  76 + # Test GLATEventList class slicing
  77 + def _test_eventlist_slicing(self):
  78 + """
  79 + Test GLATEventList class slicing
  80 + """
  81 + # Setup event list container
  82 + list = self._setup_eventlist()
  83 +
  84 + # Perform slicing tests
  85 + test_support._energy_container_slicing(self, list)
51 86
52 # Return 87 # Return
53 return 88 return
54 89
55 - # Test function  
56 - def test(self): 90 + # Set test functions
  91 + def set(self):
57 """ 92 """
58 - Test function. 93 + Set all test functions.
59 """ 94 """
  95 + # Set test name
  96 + self.name('LAT')
  97 +
  98 + # Append tests
  99 + self.append(self._test_eventlist_access, 'Test GLATEventList event access')
  100 + self.append(self._test_eventlist_slicing, 'Test GLATEventList slicing')
  101 +
60 # Return 102 # Return
61 return 103 return
pyext/GFits.i
1 /*************************************************************************** 1 /***************************************************************************
2 * GFits.i - FITS file class * 2 * GFits.i - FITS file class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2008-2016 by Juergen Knoedlseder * 4 + * copyright (C) 2008-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -100,9 +100,14 @@ public: @@ -100,9 +100,14 @@ public:
100 ***************************************************************************/ 100 ***************************************************************************/
101 %extend GFits { 101 %extend GFits {
102 GFitsHDU* __getitem__(const int& extno) { 102 GFitsHDU* __getitem__(const int& extno) {
  103 + // Counting from start, e.g. [2]
103 if (extno >= 0 && extno < self->size()) { 104 if (extno >= 0 && extno < self->size()) {
104 return (*self)[extno]; 105 return (*self)[extno];
105 } 106 }
  107 + // Counting from end, e.g. [-1]
  108 + else if (extno < 0 && self->size()+extno >= 0) {
  109 + return (*self)[self->size()+extno];
  110 + }
106 else { 111 else {
107 throw GException::out_of_range("__getitem__(int)", 112 throw GException::out_of_range("__getitem__(int)",
108 "Extension number", 113 "Extension number",
@@ -112,10 +117,43 @@ public: @@ -112,10 +117,43 @@ public:
112 GFitsHDU* __getitem__(const std::string& extname) { 117 GFitsHDU* __getitem__(const std::string& extname) {
113 return (*self)[extname]; 118 return (*self)[extname];
114 } 119 }
  120 + GFits* __getitem__(PyObject *param) {
  121 + if (PySlice_Check(param)) {
  122 + Py_ssize_t start = 0;
  123 + Py_ssize_t stop = 0;
  124 + Py_ssize_t step = 0;
  125 + Py_ssize_t len = self->size();
  126 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  127 + GFits* fits = new GFits;
  128 + if (step > 0) {
  129 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  130 + fits->append(*(*self)[i]);
  131 + }
  132 + }
  133 + else {
  134 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  135 + fits->append(*(*self)[i]);
  136 + }
  137 + }
  138 + return fits;
  139 + }
  140 + else {
  141 + throw GException::invalid_argument("__getitem__(PyObject)",
  142 + "Invalid slice indices");
  143 + }
  144 + }
  145 + else {
  146 + throw GException::invalid_argument("__getitem__(PyObject)","");
  147 + }
  148 + }
115 void __setitem__(const int& extno, const GFitsHDU& hdu) { 149 void __setitem__(const int& extno, const GFitsHDU& hdu) {
  150 + // Counting from start, e.g. [2]
116 if (extno >= 0 && extno < self->size()) { 151 if (extno >= 0 && extno < self->size()) {
117 self->set(extno, hdu); 152 self->set(extno, hdu);
118 - return; 153 + }
  154 + // Counting from end, e.g. [-1]
  155 + else if (extno < 0 && self->size()+extno >= 0) {
  156 + self->set(self->size()+extno, hdu);
119 } 157 }
120 else { 158 else {
121 throw GException::out_of_range("__setitem__(int)", 159 throw GException::out_of_range("__setitem__(int)",
pyext/GFitsHeader.i
1 /*************************************************************************** 1 /***************************************************************************
2 - * GFitsHeader.i - FITS header cards container class * 2 + * GFitsHeader.i - FITS header cards container class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2008-2015 by Juergen Knoedlseder * 4 + * copyright (C) 2008-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -29,15 +29,13 @@ @@ -29,15 +29,13 @@
29 #include "GTools.hpp" 29 #include "GTools.hpp"
30 %} 30 %}
31 31
32 -//%include stl.i  
33 -  
34 32
35 /***********************************************************************//** 33 /***********************************************************************//**
36 * @class GFitsHeader 34 * @class GFitsHeader
37 * 35 *
38 * @brief Interface for FITS header class 36 * @brief Interface for FITS header class
39 ***************************************************************************/ 37 ***************************************************************************/
40 -class GFitsHeader : public GBase { 38 +class GFitsHeader : public GContainer {
41 public: 39 public:
42 // Constructors and destructors 40 // Constructors and destructors
43 GFitsHeader(void); 41 GFitsHeader(void);
@@ -77,9 +75,14 @@ public: @@ -77,9 +75,14 @@ public:
77 ***************************************************************************/ 75 ***************************************************************************/
78 %extend GFitsHeader { 76 %extend GFitsHeader {
79 GFitsHeaderCard& __getitem__(const int& cardno) { 77 GFitsHeaderCard& __getitem__(const int& cardno) {
  78 + // Counting from start, e.g. [2]
80 if (cardno >= 0 && cardno < self->size()) { 79 if (cardno >= 0 && cardno < self->size()) {
81 return (*self)[cardno]; 80 return (*self)[cardno];
82 } 81 }
  82 + // Counting from end, e.g. [-1]
  83 + else if (cardno < 0 && self->size()+cardno >= 0) {
  84 + return (*self)[self->size()+cardno];
  85 + }
83 else { 86 else {
84 throw GException::out_of_range("__getitem__(int)", 87 throw GException::out_of_range("__getitem__(int)",
85 "Header card number", 88 "Header card number",
@@ -89,10 +92,43 @@ public: @@ -89,10 +92,43 @@ public:
89 GFitsHeaderCard& __getitem__(const std::string& keyname) { 92 GFitsHeaderCard& __getitem__(const std::string& keyname) {
90 return (*self)[keyname]; 93 return (*self)[keyname];
91 } 94 }
  95 + GFitsHeader* __getitem__(PyObject *param) {
  96 + if (PySlice_Check(param)) {
  97 + Py_ssize_t start = 0;
  98 + Py_ssize_t stop = 0;
  99 + Py_ssize_t step = 0;
  100 + Py_ssize_t len = self->size();
  101 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  102 + GFitsHeader* header = new GFitsHeader;
  103 + if (step > 0) {
  104 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  105 + header->append((*self)[i]);
  106 + }
  107 + }
  108 + else {
  109 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  110 + header->append((*self)[i]);
  111 + }
  112 + }
  113 + return header;
  114 + }
  115 + else {
  116 + throw GException::invalid_argument("__getitem__(PyObject)",
  117 + "Invalid slice indices");
  118 + }
  119 + }
  120 + else {
  121 + throw GException::invalid_argument("__getitem__(PyObject)","");
  122 + }
  123 + }
92 void __setitem__(const int& cardno, const GFitsHeaderCard& card) { 124 void __setitem__(const int& cardno, const GFitsHeaderCard& card) {
  125 + // Counting from start, e.g. [2]
93 if (cardno >= 0 && cardno < self->size()) { 126 if (cardno >= 0 && cardno < self->size()) {
94 (*self)[cardno] = card; 127 (*self)[cardno] = card;
95 - return; 128 + }
  129 + // Counting from end, e.g. [-1]
  130 + else if (cardno < 0 && self->size()+cardno >= 0) {
  131 + (*self)[self->size()+cardno] = card;
96 } 132 }
97 else { 133 else {
98 throw GException::out_of_range("__setitem__(int)", 134 throw GException::out_of_range("__setitem__(int)",
pyext/GNodeArray.i
@@ -86,17 +86,55 @@ public: @@ -86,17 +86,55 @@ public:
86 ***************************************************************************/ 86 ***************************************************************************/
87 %extend GNodeArray { 87 %extend GNodeArray {
88 double __getitem__(const int& index) { 88 double __getitem__(const int& index) {
  89 + // Counting from start, e.g. [2]
89 if (index >= 0 && index < self->size()) { 90 if (index >= 0 && index < self->size()) {
90 return (*self)[index]; 91 return (*self)[index];
91 } 92 }
  93 + // Counting from end, e.g. [-1]
  94 + else if (index < 0 && self->size()+index >= 0) {
  95 + return (*self)[self->size()+index];
  96 + }
92 else { 97 else {
93 throw GException::out_of_range("__getitem__(int)", index, self->size()); 98 throw GException::out_of_range("__getitem__(int)", index, self->size());
94 } 99 }
95 } 100 }
  101 + GNodeArray* __getitem__(PyObject *param) {
  102 + if (PySlice_Check(param)) {
  103 + Py_ssize_t start = 0;
  104 + Py_ssize_t stop = 0;
  105 + Py_ssize_t step = 0;
  106 + Py_ssize_t len = self->size();
  107 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  108 + GNodeArray* nodes = new GNodeArray;
  109 + if (step > 0) {
  110 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  111 + nodes->append((*self)[i]);
  112 + }
  113 + }
  114 + else {
  115 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  116 + nodes->append((*self)[i]);
  117 + }
  118 + }
  119 + return nodes;
  120 + }
  121 + else {
  122 + throw GException::invalid_argument("__getitem__(PyObject)",
  123 + "Invalid slice indices");
  124 + }
  125 + }
  126 + else {
  127 + throw GException::invalid_argument("__getitem__(PyObject)","");
  128 + }
  129 + }
96 void __setitem__(const int& index, const double& val) { 130 void __setitem__(const int& index, const double& val) {
97 - if (index>=0 && index < self->size()) { 131 + // Counting from start, e.g. [2]
  132 + if (index >= 0 && index < self->size()) {
98 (*self)[index] = val; 133 (*self)[index] = val;
99 - return; 134 + }
  135 + // Counting from end, e.g. [-1]
  136 + else if (index < 0 && self->size()+index >= 0) {
  137 + (*self)[self->size()+index] = val;
100 } 138 }
101 else { 139 else {
102 throw GException::out_of_range("__setitem__(int)", index, self->size()); 140 throw GException::out_of_range("__setitem__(int)", index, self->size());
pyext/GOptimizerPars.i
1 /*************************************************************************** 1 /***************************************************************************
2 * GOptimizerPars.i - Optimizer parameter container class * 2 * GOptimizerPars.i - Optimizer parameter container class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2009-2015 by Juergen Knoedlseder * 4 + * copyright (C) 2009-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -52,6 +52,7 @@ public: @@ -52,6 +52,7 @@ public:
52 int nfree(void) const; 52 int nfree(void) const;
53 GOptimizerPar* set(const int& index, const GOptimizerPar& par); 53 GOptimizerPar* set(const int& index, const GOptimizerPar& par);
54 GOptimizerPar* set(const std::string& name, const GOptimizerPar& par); 54 GOptimizerPar* set(const std::string& name, const GOptimizerPar& par);
  55 + GOptimizerPar* append(const GOptimizerPar& par);
55 void attach(GOptimizerPar *par); 56 void attach(GOptimizerPar *par);
56 void attach(const int& index, GOptimizerPar* par); 57 void attach(const int& index, GOptimizerPar* par);
57 void attach(const std::string& name, GOptimizerPar* par); 58 void attach(const std::string& name, GOptimizerPar* par);
@@ -70,9 +71,14 @@ public: @@ -70,9 +71,14 @@ public:
70 ***************************************************************************/ 71 ***************************************************************************/
71 %extend GOptimizerPars { 72 %extend GOptimizerPars {
72 GOptimizerPar* __getitem__(const int& index) { 73 GOptimizerPar* __getitem__(const int& index) {
  74 + // Counting from start, e.g. [2]
73 if (index >= 0 && index < self->size()) { 75 if (index >= 0 && index < self->size()) {
74 return (*self)[index]; 76 return (*self)[index];
75 } 77 }
  78 + // Counting from end, e.g. [-1]
  79 + else if (index < 0 && self->size()+index >= 0) {
  80 + return (*self)[self->size()+index];
  81 + }
76 else { 82 else {
77 throw GException::out_of_range("__getitem__(int)", "Parameter index", 83 throw GException::out_of_range("__getitem__(int)", "Parameter index",
78 index, self->size()); 84 index, self->size());
@@ -81,10 +87,43 @@ public: @@ -81,10 +87,43 @@ public:
81 GOptimizerPar* __getitem__(const std::string& name) { 87 GOptimizerPar* __getitem__(const std::string& name) {
82 return (*self)[name]; 88 return (*self)[name];
83 } 89 }
  90 + GOptimizerPars* __getitem__(PyObject *param) {
  91 + if (PySlice_Check(param)) {
  92 + Py_ssize_t start = 0;
  93 + Py_ssize_t stop = 0;
  94 + Py_ssize_t step = 0;
  95 + Py_ssize_t len = self->size();
  96 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  97 + GOptimizerPars* pars = new GOptimizerPars;
  98 + if (step > 0) {
  99 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  100 + pars->attach((*self)[i]);
  101 + }
  102 + }
  103 + else {
  104 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  105 + pars->attach((*self)[i]);
  106 + }
  107 + }
  108 + return pars;
  109 + }
  110 + else {
  111 + throw GException::invalid_argument("__getitem__(PyObject)",
  112 + "Invalid slice indices");
  113 + }
  114 + }
  115 + else {
  116 + throw GException::invalid_argument("__getitem__(PyObject)","");
  117 + }
  118 + }
84 void __setitem__(const int& index, GOptimizerPar* par) { 119 void __setitem__(const int& index, GOptimizerPar* par) {
  120 + // Counting from start, e.g. [2]
85 if (index >= 0 && index < self->size()) { 121 if (index >= 0 && index < self->size()) {
86 self->attach(index, par); 122 self->attach(index, par);
87 - return; 123 + }
  124 + // Counting from end, e.g. [-1]
  125 + else if (index < 0 && self->size()+index >= 0) {
  126 + self->attach(self->size()+index, par);
88 } 127 }
89 else { 128 else {
90 throw GException::out_of_range("__setitem__(int)", "Parameter index", 129 throw GException::out_of_range("__setitem__(int)", "Parameter index",
pyext/GSkyRegion.i
1 /*************************************************************************** 1 /***************************************************************************
2 * GSkyRegion.i - Sky region class * 2 * GSkyRegion.i - Sky region class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2013-2015 by Michael Mayer * 4 + * copyright (C) 2013-2017 by Michael Mayer *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -55,6 +55,9 @@ public: @@ -55,6 +55,9 @@ public:
55 const std::string& type(void) const; 55 const std::string& type(void) const;
56 const std::string& name(void) const; 56 const std::string& name(void) const;
57 const double& solidangle(void) const; 57 const double& solidangle(void) const;
  58 + void type(const std::string& type);
  59 + void name(const std::string& name);
  60 + void solidangle(const double& solidangle);
58 }; 61 };
59 62
60 63
pyext/GSkyRegions.i
1 /*************************************************************************** 1 /***************************************************************************
2 * GSkyRegions.i - Sky region container class * 2 * GSkyRegions.i - Sky region container class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2013-2016 by Pierrick Martin * 4 + * copyright (C) 2013-2017 by Pierrick Martin *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -67,17 +67,55 @@ public: @@ -67,17 +67,55 @@ public:
67 ***************************************************************************/ 67 ***************************************************************************/
68 %extend GSkyRegions { 68 %extend GSkyRegions {
69 GSkyRegion* __getitem__(const int& index) { 69 GSkyRegion* __getitem__(const int& index) {
  70 + // Counting from start, e.g. [2]
70 if (index >= 0 && index < self->size()) { 71 if (index >= 0 && index < self->size()) {
71 return (*self)[index]; 72 return (*self)[index];
72 } 73 }
  74 + // Counting from end, e.g. [-1]
  75 + else if (index < 0 && self->size()+index >= 0) {
  76 + return (*self)[self->size()+index];
  77 + }
73 else { 78 else {
74 throw GException::out_of_range("__getitem__(int)", index, self->size()); 79 throw GException::out_of_range("__getitem__(int)", index, self->size());
75 } 80 }
76 } 81 }
  82 + GSkyRegions* __getitem__(PyObject *param) {
  83 + if (PySlice_Check(param)) {
  84 + Py_ssize_t start = 0;
  85 + Py_ssize_t stop = 0;
  86 + Py_ssize_t step = 0;
  87 + Py_ssize_t len = self->size();
  88 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  89 + GSkyRegions* regions = new GSkyRegions;
  90 + if (step > 0) {
  91 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  92 + regions->append(*(*self)[i]);
  93 + }
  94 + }
  95 + else {
  96 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  97 + regions->append(*(*self)[i]);
  98 + }
  99 + }
  100 + return regions;
  101 + }
  102 + else {
  103 + throw GException::invalid_argument("__getitem__(PyObject)",
  104 + "Invalid slice indices");
  105 + }
  106 + }
  107 + else {
  108 + throw GException::invalid_argument("__getitem__(PyObject)","");
  109 + }
  110 + }
77 void __setitem__(const int& index, const GSkyRegion& val) { 111 void __setitem__(const int& index, const GSkyRegion& val) {
78 - if (index>=0 && index < self->size()) { 112 + // Counting from start, e.g. [2]
  113 + if (index >= 0 && index < self->size()) {
79 self->set(index, val); 114 self->set(index, val);
80 - return; 115 + }
  116 + // Counting from end, e.g. [-1]
  117 + else if (index < 0 && self->size()+index >= 0) {
  118 + self->set(self->size()+index, val);
81 } 119 }
82 else { 120 else {
83 throw GException::out_of_range("__setitem__(int)", index, self->size()); 121 throw GException::out_of_range("__setitem__(int)", index, self->size());
pyext/GTestSuites.i
1 /*************************************************************************** 1 /***************************************************************************
2 * GTestSuites.i - Test suite container class * 2 * GTestSuites.i - Test suite container class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2012-2016 Jean-Baptiste Cayrou * 4 + * copyright (C) 2012-2017 Jean-Baptiste Cayrou *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -73,17 +73,55 @@ public: @@ -73,17 +73,55 @@ public:
73 ***************************************************************************/ 73 ***************************************************************************/
74 %extend GTestSuites { 74 %extend GTestSuites {
75 GTestSuite* __getitem__(const int& index) { 75 GTestSuite* __getitem__(const int& index) {
  76 + // Counting from start, e.g. [2]
76 if (index >= 0 && index < self->size()) { 77 if (index >= 0 && index < self->size()) {
77 return (*self)[index]; 78 return (*self)[index];
78 } 79 }
  80 + // Counting from end, e.g. [-1]
  81 + else if (index < 0 && self->size()+index >= 0) {
  82 + return (*self)[self->size()+index];
  83 + }
79 else { 84 else {
80 throw GException::out_of_range("__getitem__(int)", index, self->size()); 85 throw GException::out_of_range("__getitem__(int)", index, self->size());
81 } 86 }
82 } 87 }
  88 + GTestSuites* __getitem__(PyObject *param) {
  89 + if (PySlice_Check(param)) {
  90 + Py_ssize_t start = 0;
  91 + Py_ssize_t stop = 0;
  92 + Py_ssize_t step = 0;
  93 + Py_ssize_t len = self->size();
  94 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  95 + GTestSuites* tests = new GTestSuites(self->name());
  96 + if (step > 0) {
  97 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  98 + tests->append(*(*self)[i]);
  99 + }
  100 + }
  101 + else {
  102 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  103 + tests->append(*(*self)[i]);
  104 + }
  105 + }
  106 + return tests;
  107 + }
  108 + else {
  109 + throw GException::invalid_argument("__getitem__(PyObject)",
  110 + "Invalid slice indices");
  111 + }
  112 + }
  113 + else {
  114 + throw GException::invalid_argument("__getitem__(PyObject)","");
  115 + }
  116 + }
83 void __setitem__(const int& index, const GTestSuite& suite) { 117 void __setitem__(const int& index, const GTestSuite& suite) {
  118 + // Counting from start, e.g. [2]
84 if (index >= 0 && index < self->size()) { 119 if (index >= 0 && index < self->size()) {
85 self->set(index, suite); 120 self->set(index, suite);
86 - return; 121 + }
  122 + // Counting from end, e.g. [-1]
  123 + else if (index < 0 && self->size()+index >= 0) {
  124 + self->set(self->size()+index, suite);
87 } 125 }
88 else { 126 else {
89 throw GException::out_of_range("__setitem__(int)", index, self->size()); 127 throw GException::out_of_range("__setitem__(int)", index, self->size());
pyext/GXml.i
1 /*************************************************************************** 1 /***************************************************************************
2 * GXml.i - XML class * 2 * GXml.i - XML class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2010-2016 by Juergen Knoedlseder * 4 + * copyright (C) 2010-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -74,27 +74,60 @@ public: @@ -74,27 +74,60 @@ public:
74 ***************************************************************************/ 74 ***************************************************************************/
75 %extend GXml { 75 %extend GXml {
76 GXmlNode* __getitem__(const int& index) { 76 GXmlNode* __getitem__(const int& index) {
  77 + // Counting from start, e.g. [2]
77 if (index >= 0 && index < self->size()) { 78 if (index >= 0 && index < self->size()) {
78 return (*self)[index]; 79 return (*self)[index];
79 } 80 }
  81 + // Counting from end, e.g. [-1]
  82 + else if (index < 0 && self->size()+index >= 0) {
  83 + return (*self)[self->size()+index];
  84 + }
80 else { 85 else {
81 - throw GException::out_of_range("__getitem__(int)", index,  
82 - 0, self->size()-1); 86 + throw GException::out_of_range("__getitem__(int)", index, self->size());
  87 + }
  88 + }
  89 + GXml* __getitem__(PyObject *param) {
  90 + if (PySlice_Check(param)) {
  91 + Py_ssize_t start = 0;
  92 + Py_ssize_t stop = 0;
  93 + Py_ssize_t step = 0;
  94 + Py_ssize_t len = self->size();
  95 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  96 + GXml* xml = new GXml;
  97 + if (step > 0) {
  98 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  99 + xml->append(*(*self)[i]);
  100 + }
  101 + }
  102 + else {
  103 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  104 + xml->append(*(*self)[i]);
  105 + }
  106 + }
  107 + return xml;
  108 + }
  109 + else {
  110 + throw GException::invalid_argument("__getitem__(PyObject)",
  111 + "Invalid slice indices");
  112 + }
  113 + }
  114 + else {
  115 + throw GException::invalid_argument("__getitem__(PyObject)","");
83 } 116 }
84 } 117 }
85 void __setitem__(const int& index, const GXmlNode& node) { 118 void __setitem__(const int& index, const GXmlNode& node) {
  119 + // Counting from start, e.g. [2]
86 if (index >= 0 && index < self->size()) { 120 if (index >= 0 && index < self->size()) {
87 self->set(index, node); 121 self->set(index, node);
88 - return; 122 + }
  123 + // Counting from end, e.g. [-1]
  124 + else if (index < 0 && self->size()+index >= 0) {
  125 + self->set(self->size()+index, node);
89 } 126 }
90 else { 127 else {
91 - throw GException::out_of_range("__setitem__(int)", index,  
92 - 0, self->size()-1); 128 + throw GException::out_of_range("__setitem__(int)", index, self->size());
93 } 129 }
94 } 130 }
95 - int __len__() {  
96 - return (self->size());  
97 - }  
98 GXml copy() { 131 GXml copy() {
99 return (*self); 132 return (*self);
100 } 133 }
pyext/GXmlElement.i
1 /*************************************************************************** 1 /***************************************************************************
2 * GXmlElement.i - XML element node class definition * 2 * GXmlElement.i - XML element node class definition *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2010-2016 by Juergen Knoedlseder * 4 + * copyright (C) 2010-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -61,6 +61,61 @@ public: @@ -61,6 +61,61 @@ public:
61 * @brief GXmlElement class extension 61 * @brief GXmlElement class extension
62 ***************************************************************************/ 62 ***************************************************************************/
63 %extend GXmlElement { 63 %extend GXmlElement {
  64 + GXmlNode* __getitem__(const int& index) {
  65 + // Counting from start, e.g. [2]
  66 + if (index >= 0 && index < self->size()) {
  67 + return (*self)[index];
  68 + }
  69 + // Counting from end, e.g. [-1]
  70 + else if (index < 0 && self->size()+index >= 0) {
  71 + return (*self)[self->size()+index];
  72 + }
  73 + else {
  74 + throw GException::out_of_range("__getitem__(int)", index, self->size());
  75 + }
  76 + }
  77 + void __setitem__(const int& index, const GXmlNode& node) {
  78 + // Counting from start, e.g. [2]
  79 + if (index >= 0 && index < self->size()) {
  80 + self->set(index, node);
  81 + }
  82 + // Counting from end, e.g. [-1]
  83 + else if (index < 0 && self->size()+index >= 0) {
  84 + self->set(self->size()+index, node);
  85 + }
  86 + else {
  87 + throw GException::out_of_range("__setitem__(int)", index, self->size());
  88 + }
  89 + }
  90 + GXmlElement* __getitem__(PyObject *param) {
  91 + if (PySlice_Check(param)) {
  92 + Py_ssize_t start = 0;
  93 + Py_ssize_t stop = 0;
  94 + Py_ssize_t step = 0;
  95 + Py_ssize_t len = self->size();
  96 + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) {
  97 + GXmlElement* element = new GXmlElement;
  98 + if (step > 0) {
  99 + for (int i = (int)start; i < (int)stop; i += (int)step) {
  100 + element->append(*(*self)[i]);
  101 + }
  102 + }
  103 + else {
  104 + for (int i = (int)start; i > (int)stop; i += (int)step) {
  105 + element->append(*(*self)[i]);
  106 + }
  107 + }
  108 + return element;
  109 + }
  110 + else {
  111 + throw GException::invalid_argument("__getitem__(PyObject)",
  112 + "Invalid slice indices");
  113 + }
  114 + }
  115 + else {
  116 + throw GException::invalid_argument("__getitem__(PyObject)","");
  117 + }
  118 + }
64 GXmlElement copy() { 119 GXmlElement copy() {
65 return (*self); 120 return (*self);
66 } 121 }
pyext/GXmlNode.i
1 /*************************************************************************** 1 /***************************************************************************
2 * GXmlNode.i - Abstract XML node base class * 2 * GXmlNode.i - Abstract XML node base class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2010-2016 by Juergen Knoedlseder * 4 + * copyright (C) 2010-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -36,7 +36,7 @@ @@ -36,7 +36,7 @@
36 * 36 *
37 * @brief Abstract XML node base class 37 * @brief Abstract XML node base class
38 ***************************************************************************/ 38 ***************************************************************************/
39 -class GXmlNode : public GBase { 39 +class GXmlNode : public GContainer {
40 public: 40 public:
41 // Constructors and destructors 41 // Constructors and destructors
42 GXmlNode(void); 42 GXmlNode(void);
@@ -89,25 +89,29 @@ public: @@ -89,25 +89,29 @@ public:
89 return gammalib::tochar(self->print(NORMAL, 0)); 89 return gammalib::tochar(self->print(NORMAL, 0));
90 } 90 }
91 GXmlNode* __getitem__(const int& index) { 91 GXmlNode* __getitem__(const int& index) {
  92 + // Counting from start, e.g. [2]
92 if (index >= 0 && index < self->size()) { 93 if (index >= 0 && index < self->size()) {
93 return (*self)[index]; 94 return (*self)[index];
94 } 95 }
  96 + // Counting from end, e.g. [-1]
  97 + else if (index < 0 && self->size()+index >= 0) {
  98 + return (*self)[self->size()+index];
  99 + }
95 else { 100 else {
96 - throw GException::out_of_range("__getitem__(int)", index,  
97 - 0, self->size()-1); 101 + throw GException::out_of_range("__getitem__(int)", index, self->size());
98 } 102 }
99 } 103 }
100 void __setitem__(const int& index, const GXmlNode& node) { 104 void __setitem__(const int& index, const GXmlNode& node) {
  105 + // Counting from start, e.g. [2]
101 if (index >= 0 && index < self->size()) { 106 if (index >= 0 && index < self->size()) {
102 self->set(index, node); 107 self->set(index, node);
103 - return; 108 + }
  109 + // Counting from end, e.g. [-1]
  110 + else if (index < 0 && self->size()+index >= 0) {
  111 + self->set(self->size()+index, node);
104 } 112 }
105 else { 113 else {
106 - throw GException::out_of_range("__setitem__(int)", index,  
107 - 0, self->size()-1); 114 + throw GException::out_of_range("__setitem__(int)", index, self->size());
108 } 115 }
109 } 116 }
110 - int __len__() {  
111 - return (self->size());  
112 - }  
113 }; 117 };
src/opt/GOptimizerPar.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 * GOptimizerPar.cpp - Optimizer parameter class * 2 * GOptimizerPar.cpp - Optimizer parameter class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2013-2015 by Juergen Knoedlseder * 4 + * copyright (C) 2013-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -700,8 +700,8 @@ std::string GOptimizerPar::print(const GChatter&amp; chatter) const @@ -700,8 +700,8 @@ std::string GOptimizerPar::print(const GChatter&amp; chatter) const
700 void GOptimizerPar::init_members(void) 700 void GOptimizerPar::init_members(void)
701 { 701 {
702 // Initialise members 702 // Initialise members
703 - m_name = "";  
704 - m_unit = ""; 703 + m_name.clear();
  704 + m_unit.clear();
705 m_factor_value = 0.0; 705 m_factor_value = 0.0;
706 m_factor_error = 0.0; 706 m_factor_error = 0.0;
707 m_factor_gradient = 0.0; 707 m_factor_gradient = 0.0;
src/opt/GOptimizerPars.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 * GOptimizerPars.cpp - Optimizer parameter container class * 2 * GOptimizerPars.cpp - Optimizer parameter container class *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2009-2013 by Juergen Knoedlseder * 4 + * copyright (C) 2009-2017 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -392,6 +392,30 @@ GOptimizerPar* GOptimizerPars::set(const std::string&amp; name, const GOptimizerPar&amp; @@ -392,6 +392,30 @@ GOptimizerPar* GOptimizerPars::set(const std::string&amp; name, const GOptimizerPar&amp;
392 392
393 393
394 /***********************************************************************//** 394 /***********************************************************************//**
  395 + * @brief Append parameter to container
  396 + *
  397 + * @param[in] par Parameter reference.
  398 + * @return Pointer to appended parameter.
  399 + *
  400 + * Appends a parameter to the container. The method stores a copy of the
  401 + * parameter in the container, hence the client may delete the parameter
  402 + * after the method is called.
  403 + ***************************************************************************/
  404 +GOptimizerPar* GOptimizerPars::append(const GOptimizerPar& par)
  405 +{
  406 + // Clone parameter
  407 + GOptimizerPar* ptr = par.clone();
  408 +
  409 + // Inserts deep copy of parameter
  410 + m_alloc.push_back(true);
  411 + m_pars.push_back(ptr);
  412 +
  413 + // Return parameter pointer
  414 + return ptr;
  415 +}
  416 +
  417 +
  418 +/***********************************************************************//**
395 * @brief Attach parameter to container 419 * @brief Attach parameter to container
396 * 420 *
397 * @param[in] par Parameter pointer. 421 * @param[in] par Parameter pointer.
@@ -680,6 +704,7 @@ std::string GOptimizerPars::print(const GChatter&amp; chatter) const @@ -680,6 +704,7 @@ std::string GOptimizerPars::print(const GChatter&amp; chatter) const
680 704
681 // Append parameters 705 // Append parameters
682 for (int i = 0; i < size(); ++i) { 706 for (int i = 0; i < size(); ++i) {
  707 +std::cout << i << " " << m_pars[i] << std::endl;
683 result.append("\n"+m_pars[i]->print(chatter)); 708 result.append("\n"+m_pars[i]->print(chatter));
684 } 709 }
685 710
test/test_GFits.py
@@ -27,11 +27,12 @@ import gammalib @@ -27,11 +27,12 @@ import gammalib
27 # =================================== # 27 # =================================== #
28 class Test(gammalib.GPythonTestSuite): 28 class Test(gammalib.GPythonTestSuite):
29 """ 29 """
30 - Test class for GammaLib FITS module. 30 + Test class for GammaLib FITS module
31 """ 31 """
  32 + # Constructor
32 def __init__(self): 33 def __init__(self):
33 """ 34 """
34 - Constructor. 35 + Constructor
35 """ 36 """
36 # Call base class constructor 37 # Call base class constructor
37 gammalib.GPythonTestSuite.__init__(self) 38 gammalib.GPythonTestSuite.__init__(self)
@@ -39,25 +40,236 @@ class Test(gammalib.GPythonTestSuite): @@ -39,25 +40,236 @@ class Test(gammalib.GPythonTestSuite):
39 # Return 40 # Return
40 return 41 return
41 42
42 - def set(self): 43 + # Setup GFits container
  44 + def _setup_fits(self):
  45 + """
  46 + Setup GFits container
  47 +
  48 + Returns
  49 + -------
  50 + fits : `~gammalib.GFits`
  51 + GFits container
43 """ 52 """
44 - Set all test functions. 53 + # Setup GFits container
  54 + fits = gammalib.GFits()
  55 + image = gammalib.GFitsImageDouble()
  56 + for i in range(10):
  57 + image.extname('%s' % i)
  58 + fits.append(image)
  59 +
  60 + # Return GFits container
  61 + return fits
  62 +
  63 + # Setup GFitsHeader container
  64 + def _setup_header(self):
45 """ 65 """
46 - # Set test name  
47 - self.name("fits") 66 + Setup GFitsHeader container
48 67
49 - # Append tests  
50 - self.append(self.test_fits, "Test GFits class")  
51 - self.append(self.test_fits_image, "Test GFitsImage class")  
52 - self.append(self.test_fits_table, "Test GFitsTable class")  
53 - self.append(self.test_fits_table_columns, "Test GFitsTableCol classes") 68 + Returns
  69 + -------
  70 + header : `~gammalib.GFitsHeader`
  71 + GFitsHeader container
  72 + """
  73 + # Setup GFitsHeader container
  74 + header = gammalib.GFitsHeader()
  75 + card = gammalib.GFitsHeaderCard()
  76 + for i in range(10):
  77 + card.keyname('%s' % i)
  78 + header.append(card)
  79 +
  80 + # Return GFitsHeader container
  81 + return header
  82 +
  83 + # Test GFits class access operators
  84 + def _test_fits_access(self):
  85 + """
  86 + Test GFits class parameter access
  87 + """
  88 + # Setup GFits container and element
  89 + fits = self._setup_fits()
  90 + image = gammalib.GFitsImageDouble()
  91 +
  92 + # Loop over all elements using the container iterator and count the
  93 + # number of iterations
  94 + niter = 0
  95 + for hdu in fits:
  96 + self.test_value(hdu.extname(), '%s' % niter)
  97 + niter += 1
  98 +
  99 + # Check that looping was successful
  100 + self.test_value(fits.size(), 10, 'Check container size')
  101 + self.test_value(niter, 10, 'Check container iterator')
  102 +
  103 + # Test access from start
  104 + self.test_value(fits[3].extname(), '3')
  105 +
  106 + # Check access from end
  107 + self.test_value(fits[-2].extname(), '8')
  108 +
  109 + # Check parameter setting by index from start
  110 + image.extname('98')
  111 + fits[3] = image
  112 + self.test_value(fits[3].extname(), '98')
  113 +
  114 + # Check parameter setting by index from end
  115 + image.extname('99')
  116 + fits[-2] = image
  117 + self.test_value(fits[-2].extname(), '99')
  118 +
  119 + # Return
  120 + return
  121 +
  122 + # Test GFits class slicing
  123 + def _test_fits_slicing(self):
  124 + """
  125 + Test GFits class slicing
  126 + """
  127 + # Setup XML container
  128 + fits = self._setup_fits()
  129 +
  130 + # Test fits[start:end]
  131 + self.test_value(len(fits[3:5]), 2)
  132 + self.test_value(fits[3:5][0].extname(), '3')
  133 + self.test_value(fits[3:5][1].extname(), '4')
  134 +
  135 + # Test fits[start:]
  136 + self.test_value(len(fits[7:]), 3)
  137 + self.test_value(fits[7:][0].extname(), '7')
  138 + self.test_value(fits[7:][1].extname(), '8')
  139 + self.test_value(fits[7:][2].extname(), '9')
  140 +
  141 + # Test fits[:end]
  142 + self.test_value(len(fits[:2]), 2)
  143 + self.test_value(fits[:2][0].extname(), '0')
  144 + self.test_value(fits[:2][1].extname(), '1')
  145 +
  146 + # Test fits[:]
  147 + self.test_value(len(fits[:]), 10)
  148 + for i in range(10):
  149 + self.test_value(fits[:][i].extname(), '%s' % i)
  150 +
  151 + # Test fits[start:end:step]
  152 + self.test_value(len(fits[3:7:2]), 2)
  153 + self.test_value(fits[3:7:2][0].extname(), '3')
  154 + self.test_value(fits[3:7:2][1].extname(), '5')
  155 +
  156 + # Test fits[start:end:step]
  157 + self.test_value(len(fits[6:3:-2]), 2)
  158 + self.test_value(fits[6:3:-2][0].extname(), '6')
  159 + self.test_value(fits[6:3:-2][1].extname(), '4')
  160 +
  161 + # Test fits[-start:]
  162 + self.test_value(len(fits[-2:]), 2)
  163 + self.test_value(fits[-2:][0].extname(), '8')
  164 + self.test_value(fits[-2:][1].extname(), '9')
  165 +
  166 + # Test fits[:-end]
  167 + self.test_value(len(fits[:-7]), 3)
  168 + self.test_value(fits[:-7][0].extname(), '0')
  169 + self.test_value(fits[:-7][1].extname(), '1')
  170 + self.test_value(fits[:-7][2].extname(), '2')
  171 +
  172 + # Return
  173 + return
  174 +
  175 + # Test GFitsHeader class access operators
  176 + def _test_header_access(self):
  177 + """
  178 + Test GFitsHeader class parameter access
  179 + """
  180 + # Setup FITS header
  181 + header = self._setup_header()
  182 +
  183 + # Loop over all elements using the container iterator and count the
  184 + # number of iterations
  185 + niter = 0
  186 + for card in header:
  187 + self.test_value(card.keyname(), '%s' % niter)
  188 + niter += 1
  189 +
  190 + # Check that looping was successful
  191 + self.test_value(header.size(), 10, 'Check container size')
  192 + self.test_value(niter, 10, 'Check container iterator')
  193 +
  194 + # Test access from start
  195 + self.test_value(header[3].keyname(), '3')
  196 +
  197 + # Check access from end
  198 + self.test_value(header[-2].keyname(), '8')
  199 +
  200 + # Setup header card
  201 + card = gammalib.GFitsHeaderCard()
  202 +
  203 + # Check parameter setting by index from start
  204 + card.keyname('98')
  205 + header[3] = card
  206 + self.test_value(header[3].keyname(), '98')
  207 +
  208 + # Check parameter setting by index from end
  209 + card.keyname('99')
  210 + header[-2] = card
  211 + self.test_value(header[-2].keyname(), '99')
54 212
55 # Return 213 # Return
56 return 214 return
57 215
58 - def test_fits(self): 216 + # Test GFitsHeader class slicing
  217 + def _test_header_slicing(self):
  218 + """
  219 + Test GFitsHeader class slicing
59 """ 220 """
60 - Test GFile class interface. 221 + # Setup FITS header
  222 + header = self._setup_header()
  223 +
  224 + # Test header[start:end]
  225 + self.test_value(len(header[3:5]), 2)
  226 + self.test_value(header[3:5][0].keyname(), '3')
  227 + self.test_value(header[3:5][1].keyname(), '4')
  228 +
  229 + # Test header[start:]
  230 + self.test_value(len(header[7:]), 3)
  231 + self.test_value(header[7:][0].keyname(), '7')
  232 + self.test_value(header[7:][1].keyname(), '8')
  233 + self.test_value(header[7:][2].keyname(), '9')
  234 +
  235 + # Test header[:end]
  236 + self.test_value(len(header[:2]), 2)
  237 + self.test_value(header[:2][0].keyname(), '0')
  238 + self.test_value(header[:2][1].keyname(), '1')
  239 +
  240 + # Test header[:]
  241 + self.test_value(len(header[:]), 10)
  242 + for i in range(10):
  243 + self.test_value(header[:][i].keyname(), '%s' % i)
  244 +
  245 + # Test header[start:end:step]
  246 + self.test_value(len(header[3:7:2]), 2)
  247 + self.test_value(header[3:7:2][0].keyname(), '3')
  248 + self.test_value(header[3:7:2][1].keyname(), '5')
  249 +
  250 + # Test header[start:end:step]
  251 + self.test_value(len(header[6:3:-2]), 2)
  252 + self.test_value(header[6:3:-2][0].keyname(), '6')
  253 + self.test_value(header[6:3:-2][1].keyname(), '4')
  254 +
  255 + # Test header[-start:]
  256 + self.test_value(len(header[-2:]), 2)
  257 + self.test_value(header[-2:][0].keyname(), '8')
  258 + self.test_value(header[-2:][1].keyname(), '9')
  259 +
  260 + # Test header[:-end]
  261 + self.test_value(len(header[:-7]), 3)
  262 + self.test_value(header[:-7][0].keyname(), '0')
  263 + self.test_value(header[:-7][1].keyname(), '1')
  264 + self.test_value(header[:-7][2].keyname(), '2')
  265 +
  266 + # Return
  267 + return
  268 +
  269 + # Test GFile class interface
  270 + def _test_fits(self):
  271 + """
  272 + Test GFile class interface
61 """ 273 """
62 # Get test data directory 274 # Get test data directory
63 datadir = os.environ['TEST_DATA'] + '/' 275 datadir = os.environ['TEST_DATA'] + '/'
@@ -66,33 +278,33 @@ class Test(gammalib.GPythonTestSuite): @@ -66,33 +278,33 @@ class Test(gammalib.GPythonTestSuite):
66 file = gammalib.GFilename(datadir+'file.fits') 278 file = gammalib.GFilename(datadir+'file.fits')
67 279
68 # Test loading of FITS file 280 # Test loading of FITS file
69 - self.test_try("Test GFits file load constructor") 281 + self.test_try('Test GFits file load constructor')
70 try: 282 try:
71 fits = gammalib.GFits(file) 283 fits = gammalib.GFits(file)
72 self.test_try_success() 284 self.test_try_success()
73 except: 285 except:
74 - self.test_try_failure("Unable to load FITS file.") 286 + self.test_try_failure('Unable to load FITS file.')
75 287
76 # Test creation of FITS file 288 # Test creation of FITS file
77 - self.test_try("Test GFits file creation constructor") 289 + self.test_try('Test GFits file creation constructor')
78 try: 290 try:
79 - fits = gammalib.GFits("test_file.fits", True) 291 + fits = gammalib.GFits('test_file.fits', True)
80 self.test_try_success() 292 self.test_try_success()
81 except: 293 except:
82 - self.test_try_failure("Unable to create FITS file.") 294 + self.test_try_failure('Unable to create FITS file.')
83 295
84 # Open FITS file 296 # Open FITS file
85 fits = gammalib.GFits(file) 297 fits = gammalib.GFits(file)
86 - self.test_value(fits["EVENTS"].nrows(), 1231, "Check number of rows") 298 + self.test_value(fits['EVENTS'].nrows(), 1231, 'Check number of rows')
87 299
88 # Open FITS file with event selection 300 # Open FITS file with event selection
89 - fits = gammalib.GFits(file+"[EVENTS][ENERGY>1.0]")  
90 - self.test_value(fits["EVENTS"].nrows(), 152, "Check number of rows") 301 + fits = gammalib.GFits(file+'[EVENTS][ENERGY>1.0]')
  302 + self.test_value(fits['EVENTS'].nrows(), 152, 'Check number of rows')
91 303
92 # Open FITS file with non-existing extension name 304 # Open FITS file with non-existing extension name
93 - self.test_try("Test non-existing extension name") 305 + self.test_try('Test non-existing extension name')
94 try: 306 try:
95 - fits = gammalib.GFits(file+"[DUMMY][ENERGY>1.0]") 307 + fits = gammalib.GFits(file+'[DUMMY][ENERGY>1.0]')
96 self.test_try_failure() 308 self.test_try_failure()
97 except: 309 except:
98 self.test_try_success() 310 self.test_try_success()
@@ -100,13 +312,14 @@ class Test(gammalib.GPythonTestSuite): @@ -100,13 +312,14 @@ class Test(gammalib.GPythonTestSuite):
100 # Return 312 # Return
101 return 313 return
102 314
103 - def test_fits_image(self): 315 + # Test GFitsImage class interface
  316 + def _test_fits_image(self):
104 """ 317 """
105 - Test GFitsImage class interface. 318 + Test GFitsImage class interface
106 """ 319 """
107 # Set test file names 320 # Set test file names
108 - file1 = gammalib.GFilename("test_python_fits_image_v1.fits")  
109 - file2 = gammalib.GFilename("test_python_fits_image_v2.fits") 321 + file1 = gammalib.GFilename('test_python_fits_image_v1.fits')
  322 + file2 = gammalib.GFilename('test_python_fits_image_v2.fits')
110 323
111 # Remove test files 324 # Remove test files
112 file1.remove() 325 file1.remove()
@@ -138,15 +351,15 @@ class Test(gammalib.GPythonTestSuite): @@ -138,15 +351,15 @@ class Test(gammalib.GPythonTestSuite):
138 img7[x, y] = x + y * nx 351 img7[x, y] = x + y * nx
139 img8[x, y] = x + y * nx 352 img8[x, y] = x + y * nx
140 img9[x, y] = x + y * nx 353 img9[x, y] = x + y * nx
141 - img1.extname("Byte")  
142 - img2.extname("Double")  
143 - img3.extname("Float")  
144 - img4.extname("Long")  
145 - img5.extname("LongLong")  
146 - img6.extname("SByte")  
147 - img7.extname("Short")  
148 - img8.extname("ULong")  
149 - img9.extname("UShort") 354 + img1.extname('Byte')
  355 + img2.extname('Double')
  356 + img3.extname('Float')
  357 + img4.extname('Long')
  358 + img5.extname('LongLong')
  359 + img6.extname('SByte')
  360 + img7.extname('Short')
  361 + img8.extname('ULong')
  362 + img9.extname('UShort')
150 363
151 # Test image types by checking the bitpix values 364 # Test image types by checking the bitpix values
152 self.test_value(img1.bitpix(), 8) 365 self.test_value(img1.bitpix(), 8)
@@ -172,9 +385,9 @@ class Test(gammalib.GPythonTestSuite): @@ -172,9 +385,9 @@ class Test(gammalib.GPythonTestSuite):
172 385
173 # Set header keywords 386 # Set header keywords
174 img_byte = fits.image(0) 387 img_byte = fits.image(0)
175 - img_byte.card("test", "test-value", "this is for testing")  
176 - img_byte.card("real", 3.1415, "a real value")  
177 - img_byte.card("int", 41, "an integer value") 388 + img_byte.card('test', 'test-value', 'this is for testing')
  389 + img_byte.card('real', 3.1415, 'a real value')
  390 + img_byte.card('int', 41, 'an integer value')
178 391
179 # Save FITS file 392 # Save FITS file
180 fits.save() 393 fits.save()
@@ -198,7 +411,7 @@ class Test(gammalib.GPythonTestSuite): @@ -198,7 +411,7 @@ class Test(gammalib.GPythonTestSuite):
198 411
199 # Get double precision image, take square root of pixel and save in 412 # Get double precision image, take square root of pixel and save in
200 # another file 413 # another file
201 - img_double = fits.image("Double") 414 + img_double = fits.image('Double')
202 for x in range(nx): 415 for x in range(nx):
203 for y in range(ny): 416 for y in range(ny):
204 img_double[x, y] = math.sqrt(img_double[x, y]) 417 img_double[x, y] = math.sqrt(img_double[x, y])
@@ -232,13 +445,14 @@ class Test(gammalib.GPythonTestSuite): @@ -232,13 +445,14 @@ class Test(gammalib.GPythonTestSuite):
232 # Return 445 # Return
233 return 446 return
234 447
235 - def test_fits_table(self): 448 + # Test GFitsTable class interface
  449 + def _test_fits_table(self):
236 """ 450 """
237 - Test GFitsTable class interface. 451 + Test GFitsTable class interface
238 """ 452 """
239 # Set test file names 453 # Set test file names
240 - file1 = gammalib.GFilename("test_python_fits_table_v1.fits")  
241 - file2 = gammalib.GFilename("test_python_fits_table_v2.fits") 454 + file1 = gammalib.GFilename('test_python_fits_table_v1.fits')
  455 + file2 = gammalib.GFilename('test_python_fits_table_v2.fits')
242 456
243 # Remove test files 457 # Remove test files
244 file1.remove() 458 file1.remove()
@@ -249,17 +463,17 @@ class Test(gammalib.GPythonTestSuite): @@ -249,17 +463,17 @@ class Test(gammalib.GPythonTestSuite):
249 463
250 # Create table columns 464 # Create table columns
251 nrows = 10 465 nrows = 10
252 - col1 = gammalib.GFitsTableBitCol("BIT", nrows)  
253 - col2 = gammalib.GFitsTableBoolCol("BOOLEAN", nrows)  
254 - col3 = gammalib.GFitsTableByteCol("BYTE", nrows)  
255 - col4 = gammalib.GFitsTableDoubleCol("DOUBLE", nrows)  
256 - col5 = gammalib.GFitsTableFloatCol("FLOAT", nrows)  
257 - col6 = gammalib.GFitsTableLongCol("LONG", nrows)  
258 - col7 = gammalib.GFitsTableLongLongCol("LONGLONG", nrows)  
259 - col8 = gammalib.GFitsTableShortCol("SHORT", nrows)  
260 - col9 = gammalib.GFitsTableStringCol("STRING", nrows, 20)  
261 - col10 = gammalib.GFitsTableULongCol("ULONG", nrows)  
262 - col11 = gammalib.GFitsTableUShortCol("USHORT", nrows) 466 + col1 = gammalib.GFitsTableBitCol('BIT', nrows)
  467 + col2 = gammalib.GFitsTableBoolCol('BOOLEAN', nrows)
  468 + col3 = gammalib.GFitsTableByteCol('BYTE', nrows)
  469 + col4 = gammalib.GFitsTableDoubleCol('DOUBLE', nrows)
  470 + col5 = gammalib.GFitsTableFloatCol('FLOAT', nrows)
  471 + col6 = gammalib.GFitsTableLongCol('LONG', nrows)
  472 + col7 = gammalib.GFitsTableLongLongCol('LONGLONG', nrows)
  473 + col8 = gammalib.GFitsTableShortCol('SHORT', nrows)
  474 + col9 = gammalib.GFitsTableStringCol('STRING', nrows, 20)
  475 + col10 = gammalib.GFitsTableULongCol('ULONG', nrows)
  476 + col11 = gammalib.GFitsTableUShortCol('USHORT', nrows)
263 for i in range(nrows): 477 for i in range(nrows):
264 #col1[i] = i % 2 # Old swig version 478 #col1[i] = i % 2 # Old swig version
265 #col2[i] = i % 2 # Old swig version 479 #col2[i] = i % 2 # Old swig version
@@ -288,7 +502,7 @@ class Test(gammalib.GPythonTestSuite): @@ -288,7 +502,7 @@ class Test(gammalib.GPythonTestSuite):
288 tbl_ascii.append(col9) 502 tbl_ascii.append(col9)
289 tbl_ascii.append(col10) 503 tbl_ascii.append(col10)
290 tbl_ascii.append(col11) 504 tbl_ascii.append(col11)
291 - tbl_ascii.extname("ASCII table") 505 + tbl_ascii.extname('ASCII table')
292 fits.append(tbl_ascii) 506 fits.append(tbl_ascii)
293 507
294 # Set binary table 508 # Set binary table
@@ -304,7 +518,7 @@ class Test(gammalib.GPythonTestSuite): @@ -304,7 +518,7 @@ class Test(gammalib.GPythonTestSuite):
304 tbl_bin.append(col9) 518 tbl_bin.append(col9)
305 tbl_bin.append(col10) 519 tbl_bin.append(col10)
306 tbl_bin.append(col11) 520 tbl_bin.append(col11)
307 - tbl_bin.extname("Binary table") 521 + tbl_bin.extname('Binary table')
308 fits.append(tbl_bin) 522 fits.append(tbl_bin)
309 523
310 # Save FITS file 524 # Save FITS file
@@ -316,36 +530,37 @@ class Test(gammalib.GPythonTestSuite): @@ -316,36 +530,37 @@ class Test(gammalib.GPythonTestSuite):
316 # Return 530 # Return
317 return 531 return
318 532
319 - def test_fits_table_columns(self): 533 + # Test FITS table columns
  534 + def _test_fits_table_columns(self):
320 """ 535 """
321 Test FITS table columns 536 Test FITS table columns
322 """ 537 """
323 # Create table columns 538 # Create table columns
324 nrows = 10 539 nrows = 10
325 - col1 = gammalib.GFitsTableBitCol("BIT", nrows)  
326 - col2 = gammalib.GFitsTableBoolCol("BOOLEAN", nrows)  
327 - col3 = gammalib.GFitsTableByteCol("BYTE", nrows)  
328 - col4 = gammalib.GFitsTableDoubleCol("DOUBLE", nrows)  
329 - col5 = gammalib.GFitsTableFloatCol("FLOAT", nrows)  
330 - col6 = gammalib.GFitsTableLongCol("LONG", nrows)  
331 - col7 = gammalib.GFitsTableLongLongCol("LONGLONG", nrows)  
332 - col8 = gammalib.GFitsTableShortCol("SHORT", nrows)  
333 - col9 = gammalib.GFitsTableStringCol("STRING", nrows, 20)  
334 - col10 = gammalib.GFitsTableULongCol("ULONG", nrows)  
335 - col11 = gammalib.GFitsTableUShortCol("USHORT", nrows) 540 + col1 = gammalib.GFitsTableBitCol('BIT', nrows)
  541 + col2 = gammalib.GFitsTableBoolCol('BOOLEAN', nrows)
  542 + col3 = gammalib.GFitsTableByteCol('BYTE', nrows)
  543 + col4 = gammalib.GFitsTableDoubleCol('DOUBLE', nrows)
  544 + col5 = gammalib.GFitsTableFloatCol('FLOAT', nrows)
  545 + col6 = gammalib.GFitsTableLongCol('LONG', nrows)
  546 + col7 = gammalib.GFitsTableLongLongCol('LONGLONG', nrows)
  547 + col8 = gammalib.GFitsTableShortCol('SHORT', nrows)
  548 + col9 = gammalib.GFitsTableStringCol('STRING', nrows, 20)
  549 + col10 = gammalib.GFitsTableULongCol('ULONG', nrows)
  550 + col11 = gammalib.GFitsTableUShortCol('USHORT', nrows)
336 551
337 # Test number of rows 552 # Test number of rows
338 - self.test_value(col1.nrows(), nrows, "Check number of rows in Bit column")  
339 - self.test_value(col2.nrows(), nrows, "Check number of rows in Boolean column")  
340 - self.test_value(col3.nrows(), nrows, "Check number of rows in Byte column")  
341 - self.test_value(col4.nrows(), nrows, "Check number of rows in Double column")  
342 - self.test_value(col5.nrows(), nrows, "Check number of rows in Float column")  
343 - self.test_value(col6.nrows(), nrows, "Check number of rows in Long column")  
344 - self.test_value(col7.nrows(), nrows, "Check number of rows in LongLong column")  
345 - self.test_value(col8.nrows(), nrows, "Check number of rows in Short column")  
346 - self.test_value(col9.nrows(), nrows, "Check number of rows in String column")  
347 - self.test_value(col10.nrows(), nrows, "Check number of rows in ULong column")  
348 - self.test_value(col11.nrows(), nrows, "Check number of rows in UShort column") 553 + self.test_value(col1.nrows(), nrows, 'Check number of rows in Bit column')
  554 + self.test_value(col2.nrows(), nrows, 'Check number of rows in Boolean column')
  555 + self.test_value(col3.nrows(), nrows, 'Check number of rows in Byte column')
  556 + self.test_value(col4.nrows(), nrows, 'Check number of rows in Double column')
  557 + self.test_value(col5.nrows(), nrows, 'Check number of rows in Float column')
  558 + self.test_value(col6.nrows(), nrows, 'Check number of rows in Long column')
  559 + self.test_value(col7.nrows(), nrows, 'Check number of rows in LongLong column')
  560 + self.test_value(col8.nrows(), nrows, 'Check number of rows in Short column')
  561 + self.test_value(col9.nrows(), nrows, 'Check number of rows in String column')
  562 + self.test_value(col10.nrows(), nrows, 'Check number of rows in ULong column')
  563 + self.test_value(col11.nrows(), nrows, 'Check number of rows in UShort column')
349 564
350 # Test iterators 565 # Test iterators
351 for row in col1: 566 for row in col1:
@@ -373,28 +588,48 @@ class Test(gammalib.GPythonTestSuite): @@ -373,28 +588,48 @@ class Test(gammalib.GPythonTestSuite):
373 588
374 # Test setting and retrieving of values 589 # Test setting and retrieving of values
375 col1[5] = True 590 col1[5] = True
376 - self.test_assert(col1[5], "Check Bit column setting and retrieving") 591 + self.test_assert(col1[5], 'Check Bit column setting and retrieving')
377 col2[5] = True 592 col2[5] = True
378 - self.test_assert(col2[5], "Check Boolean column setting and retrieving") 593 + self.test_assert(col2[5], 'Check Boolean column setting and retrieving')
379 col3[5] = 5 594 col3[5] = 5
380 - self.test_value(col3[5], 5, "Check Byte column setting and retrieving") 595 + self.test_value(col3[5], 5, 'Check Byte column setting and retrieving')
381 col4[5] = 3.14 596 col4[5] = 3.14
382 - self.test_value(col4[5], 3.14, 1.0e-6, "Check Double column setting and retrieving") 597 + self.test_value(col4[5], 3.14, 1.0e-6, 'Check Double column setting and retrieving')
383 col5[5] = 3.14 598 col5[5] = 3.14
384 - self.test_value(col5[5], 3.14, 1.0e-6, "Check Float column setting and retrieving") 599 + self.test_value(col5[5], 3.14, 1.0e-6, 'Check Float column setting and retrieving')
385 col6[5] = 314 600 col6[5] = 314
386 - self.test_value(col6[5], 314, "Check Long column setting and retrieving") 601 + self.test_value(col6[5], 314, 'Check Long column setting and retrieving')
387 col7[5] = 314 602 col7[5] = 314
388 - self.test_value(col7[5], 314, "Check LongLong column setting and retrieving") 603 + self.test_value(col7[5], 314, 'Check LongLong column setting and retrieving')
389 col8[5] = 314 604 col8[5] = 314
390 - self.test_value(col8[5], 314, "Check Short column setting and retrieving")  
391 - col9[5] = "Hallo"  
392 - self.test_assert(col9[5] == "Hallo", "Check String column setting and retrieving") 605 + self.test_value(col8[5], 314, 'Check Short column setting and retrieving')
  606 + col9[5] = 'Hallo'
  607 + self.test_assert(col9[5] == 'Hallo', 'Check String column setting and retrieving')
393 col10[5] = 314 608 col10[5] = 314
394 - self.test_value(col10[5], 314, "Check ULong column setting and retrieving") 609 + self.test_value(col10[5], 314, 'Check ULong column setting and retrieving')
395 col11[5] = 314 610 col11[5] = 314
396 - self.test_value(col11[5], 314, "Check UShort column setting and retrieving") 611 + self.test_value(col11[5], 314, 'Check UShort column setting and retrieving')
  612 +
  613 + # Return
  614 + return
  615 +
  616 + # Set test functions
  617 + def set(self):
  618 + """
  619 + Set all test functions
  620 + """
  621 + # Set test name
  622 + self.name('fits')
  623 +
  624 + # Append tests
  625 + self.append(self._test_fits, 'Test GFits')
  626 + self.append(self._test_fits_access, 'Test GFits parameter access')
  627 + self.append(self._test_fits_slicing, 'Test GFits slicing')
  628 + self.append(self._test_header_access, 'Test GFitsHeader parameter access')
  629 + self.append(self._test_header_slicing, 'Test GFitsHeader slicing')
  630 + self.append(self._test_fits_image, 'Test GFitsImage')
  631 + self.append(self._test_fits_table, 'Test GFitsTable')
  632 + self.append(self._test_fits_table_columns, 'Test GFitsTableCol')
397 633
398 # Return 634 # Return
399 return 635 return
400 -  
test/test_GObservation.py
@@ -649,24 +649,8 @@ class Test(gammalib.GPythonTestSuite): @@ -649,24 +649,8 @@ class Test(gammalib.GPythonTestSuite):
649 # Setup photons container 649 # Setup photons container
650 photons = self._setup_photons() 650 photons = self._setup_photons()
651 651
652 - # Loop over all elements using the container iterator and count the  
653 - # number of iterations  
654 - nphotons = 0  
655 - reference = 0.0  
656 - for photon in photons:  
657 - self.test_value(photon.energy().MeV(), reference)  
658 - nphotons += 1  
659 - reference += 1.0  
660 -  
661 - # Check that looping was successful  
662 - self.test_value(photons.size(), 10, 'Check container size')  
663 - self.test_value(nphotons, 10, 'Check container iterator')  
664 -  
665 - # Test access from start  
666 - self.test_value(photons[3].energy().MeV(), 3.0)  
667 -  
668 - # Check access from end  
669 - self.test_value(photons[-2].energy().MeV(), 8.0) 652 + # Perform photons access tests
  653 + test_support._energy_container_access_index(self, photons)
670 654
671 # Return 655 # Return
672 return 656 return
@@ -679,47 +663,8 @@ class Test(gammalib.GPythonTestSuite): @@ -679,47 +663,8 @@ class Test(gammalib.GPythonTestSuite):
679 # Setup photons container 663 # Setup photons container
680 photons = self._setup_photons() 664 photons = self._setup_photons()
681 665
682 - # Test photons[start:end]  
683 - self.test_value(len(photons[3:5]), 2)  
684 - self.test_value(photons[3:5][0].energy().MeV(), 3.0)  
685 - self.test_value(photons[3:5][1].energy().MeV(), 4.0)  
686 -  
687 - # Test photons[start:]  
688 - self.test_value(len(photons[7:]), 3)  
689 - self.test_value(photons[7:][0].energy().MeV(), 7.0)  
690 - self.test_value(photons[7:][1].energy().MeV(), 8.0)  
691 - self.test_value(photons[7:][2].energy().MeV(), 9.0)  
692 -  
693 - # Test photons[:end]  
694 - self.test_value(len(photons[:2]), 2)  
695 - self.test_value(photons[:2][0].energy().MeV(), 0.0)  
696 - self.test_value(photons[:2][1].energy().MeV(), 1.0)  
697 -  
698 - # Test photons[:]  
699 - self.test_value(len(photons[:]), 10)  
700 - for i in range(10):  
701 - self.test_value(photons[:][i].energy().MeV(), float(i))  
702 -  
703 - # Test photons[start:end:step]  
704 - self.test_value(len(photons[3:7:2]), 2)  
705 - self.test_value(photons[3:7:2][0].energy().MeV(), 3.0)  
706 - self.test_value(photons[3:7:2][1].energy().MeV(), 5.0)  
707 -  
708 - # Test photons[start:end:step]  
709 - self.test_value(len(photons[6:3:-2]), 2)  
710 - self.test_value(photons[6:3:-2][0].energy().MeV(), 6.0)  
711 - self.test_value(photons[6:3:-2][1].energy().MeV(), 4.0)  
712 -  
713 - # Test photons[-start:]  
714 - self.test_value(len(photons[-2:]), 2)  
715 - self.test_value(photons[-2:][0].energy().MeV(), 8.0)  
716 - self.test_value(photons[-2:][1].energy().MeV(), 9.0)  
717 -  
718 - # Test photons[:-end]  
719 - self.test_value(len(photons[:-7]), 3)  
720 - self.test_value(photons[:-7][0].energy().MeV(), 0.0)  
721 - self.test_value(photons[:-7][1].energy().MeV(), 1.0)  
722 - self.test_value(photons[:-7][2].energy().MeV(), 2.0) 666 + # Perform slicing tests
  667 + test_support._energy_container_slicing(self, photons)
723 668
724 # Return 669 # Return
725 return 670 return
@@ -736,16 +681,6 @@ class Test(gammalib.GPythonTestSuite): @@ -736,16 +681,6 @@ class Test(gammalib.GPythonTestSuite):
736 # Perform observation access tests 681 # Perform observation access tests
737 test_support._container_access_index(self, obs) 682 test_support._container_access_index(self, obs)
738 683
739 - # Check observation setting by index from start  
740 - run.id('98')  
741 - obs[3] = run  
742 - self.test_value(obs[3].id(), '98')  
743 -  
744 - # Check observation setting by index from end  
745 - run.id('99')  
746 - obs[-2] = run  
747 - self.test_value(obs[-2].id(), '99')  
748 -  
749 # Return 684 # Return
750 return 685 return
751 686
test/test_GOptimizer.py
1 # ========================================================================== 1 # ==========================================================================
2 # This module performs unit tests for the GammaLib optimizer module. 2 # This module performs unit tests for the GammaLib optimizer module.
3 # 3 #
4 -# Copyright (C) 2012-2015 Juergen Knoedlseder 4 +# Copyright (C) 2012-2017 Juergen Knoedlseder
5 # 5 #
6 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by 7 # it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 # 18 #
19 # ========================================================================== 19 # ==========================================================================
20 import gammalib 20 import gammalib
  21 +import test_support
21 22
22 23
23 # ======================================== # 24 # ======================================== #
@@ -38,24 +39,76 @@ class Test(gammalib.GPythonTestSuite): @@ -38,24 +39,76 @@ class Test(gammalib.GPythonTestSuite):
38 # Return 39 # Return
39 return 40 return
40 41
41 - # Set test functions  
42 - def set(self): 42 + # Setup GOptimizerPars container
  43 + def _setup_pars(self):
43 """ 44 """
44 - Set all test functions. 45 + Setup GOptimizerPars container
  46 +
  47 + Returns
  48 + -------
  49 + pars : `~gammalib.GOptimizerPars`
  50 + GOptimizerPars container
45 """ 51 """
46 - # Set test name  
47 - self.name("opt") 52 + # Setup GOptimizerPars container
  53 + pars = gammalib.GOptimizerPars()
  54 + par = gammalib.GOptimizerPar()
  55 + for i in range(10):
  56 + par.name('%s' % i)
  57 + pars.append(par)
48 58
49 - # Append tests  
50 - self.append(self.test, "Optimizer module dummy test") 59 + # Return GOptimizerPars container
  60 + return pars
  61 +
  62 + # Test GOptimizerPars class access operators
  63 + def _test_pars_access(self):
  64 + """
  65 + Test GOptimizerPars class parameter access
  66 + """
  67 + # Setup GOptimizerPars container and parameter
  68 + pars = self._setup_pars()
  69 + par = gammalib.GOptimizerPar()
  70 +
  71 + # Perform GOptimizerPars access tests
  72 + test_support._container_access_index(self, pars)
  73 +
  74 + # Check parameter setting by index from start
  75 + par.name('98')
  76 + pars[3] = par
  77 + self.test_value(pars[3].name(), '98')
  78 +
  79 + # Check parameter setting by index from end
  80 + par.name('99')
  81 + pars[-2] = par
  82 + self.test_value(pars[-2].name(), '99')
  83 +
  84 + # Return
  85 + return
  86 +
  87 + # Test GOptimizerPars class slicing
  88 + def _test_pars_slicing(self):
  89 + """
  90 + Test GOptimizerPars class slicing
  91 + """
  92 + # Setup GOptimizerPars container
  93 + pars = self._setup_pars()
  94 +
  95 + # Perform slicing tests
  96 + test_support._container_slicing(self, pars)
51 97
52 # Return 98 # Return
53 return 99 return
54 100
55 - # Test function  
56 - def test(self): 101 + # Set test functions
  102 + def set(self):
57 """ 103 """
58 - Test function. 104 + Set all test functions.
59 """ 105 """
  106 + # Set test name
  107 + self.name('opt')
  108 +
  109 + # Append tests
  110 + self.append(self._test_pars_access, "Test GOptimizerPars parameter access")
  111 + self.append(self._test_pars_slicing, "Test GOptimizerPars slicing")
  112 +
60 # Return 113 # Return
61 return 114 return
test/test_GSky.py
@@ -20,12 +20,13 @@ @@ -20,12 +20,13 @@
20 import os 20 import os
21 import math 21 import math
22 import gammalib 22 import gammalib
  23 +import test_support
23 24
24 25
25 # =========== # 26 # =========== #
26 # Text parser # 27 # Text parser #
27 # =========== # 28 # =========== #
28 -def loadtxt(filename): 29 +def _loadtxt(filename):
29 """ 30 """
30 Parse text file with columns of floats. 31 Parse text file with columns of floats.
31 32
@@ -63,40 +64,33 @@ class Test(gammalib.GPythonTestSuite): @@ -63,40 +64,33 @@ class Test(gammalib.GPythonTestSuite):
63 # Return 64 # Return
64 return 65 return
65 66
66 - def set(self):  
67 - """  
68 - Set all test functions. 67 + # Setup GSkyRegions container
  68 + def _setup_regions(self):
69 """ 69 """
70 - # Set test name  
71 - self.name("sky") 70 + Setup GSkyRegions container
72 71
73 - # Append tests  
74 - self.append(self.test_methods, "Test sky map methods")  
75 - self.append(self.test_friend_methods, "Test sky map friend methods")  
76 - self.append(self.test_operators, "Test sky map operators")  
77 - self.append(self.test_skymap_healpix, "Test HEALPix map")  
78 - self.append(self.test_skymap_ait, "Test AIT projection map")  
79 - self.append(self.test_skymap_azp, "Test AZP projection map")  
80 - self.append(self.test_skymap_car, "Test CAR projection map")  
81 - self.append(self.test_skymap_gls, "Test GLS projection map")  
82 - self.append(self.test_skymap_mer, "Test MER projection map")  
83 - self.append(self.test_skymap_mol, "Test MOL projection map")  
84 - self.append(self.test_skymap_sfl, "Test SFL projection map")  
85 - self.append(self.test_skymap_sin, "Test SIN projection map")  
86 - self.append(self.test_skymap_stg, "Test STG projection map")  
87 - self.append(self.test_skymap_tan, "Test TAN projection map")  
88 - self.append(self.test_fk5_to_galactic, "Test FK5 to Galactic coordinate conversion") 72 + Returns
  73 + -------
  74 + regions : `~gammalib.GSkyRegions`
  75 + Sky regions container
  76 + """
  77 + # Setup regions container
  78 + regions = gammalib.GSkyRegions()
  79 + circle = gammalib.GSkyRegionCircle()
  80 + for i in range(10):
  81 + circle.name('%s' % i)
  82 + regions.append(circle)
89 83
90 - # Return  
91 - return 84 + # Return regions container
  85 + return regions
92 86
93 # Test sky map methods 87 # Test sky map methods
94 - def test_methods(self): 88 + def _test_methods(self):
95 """ 89 """
96 Test the sky map methods. 90 Test the sky map methods.
97 """ 91 """
98 # Setup sky maps 92 # Setup sky maps
99 - map = gammalib.GSkyMap("CAR", "CEL", 83.63, 22.01, -3.7, 2.6, 10, 8, 12) 93 + map = gammalib.GSkyMap('CAR', 'CEL', 83.63, 22.01, -3.7, 2.6, 10, 8, 12)
100 94
101 # Set sky map shape 95 # Set sky map shape
102 map.shape(3,4) 96 map.shape(3,4)
@@ -126,7 +120,7 @@ class Test(gammalib.GPythonTestSuite): @@ -126,7 +120,7 @@ class Test(gammalib.GPythonTestSuite):
126 return 120 return
127 121
128 # Test sky map friend methods 122 # Test sky map friend methods
129 - def test_friend_methods(self): 123 + def _test_friend_methods(self):
130 """ 124 """
131 Test the sky map friend methods 125 Test the sky map friend methods
132 """ 126 """
@@ -154,12 +148,12 @@ class Test(gammalib.GPythonTestSuite): @@ -154,12 +148,12 @@ class Test(gammalib.GPythonTestSuite):
154 return 148 return
155 149
156 # Test sky map operators 150 # Test sky map operators
157 - def test_operators(self): 151 + def _test_operators(self):
158 """ 152 """
159 Test the sky map operators. 153 Test the sky map operators.
160 """ 154 """
161 # Setup sky maps 155 # Setup sky maps
162 - map = gammalib.GSkyMap("CAR", "CEL", 83.6331, 22.0145, -3.7, 2.6, 2, 2) 156 + map = gammalib.GSkyMap('CAR', 'CEL', 83.6331, 22.0145, -3.7, 2.6, 2, 2)
163 map[0] = 1.0 157 map[0] = 1.0
164 map[1] = 2.0 158 map[1] = 2.0
165 map[2] = 3.0 159 map[2] = 3.0
@@ -218,7 +212,7 @@ class Test(gammalib.GPythonTestSuite): @@ -218,7 +212,7 @@ class Test(gammalib.GPythonTestSuite):
218 return 212 return
219 213
220 # Generic skymap pixel transformation test 214 # Generic skymap pixel transformation test
221 - def test_skymap_pixels(self, pixels, map): 215 + def _test_skymap_pixels(self, pixels, map):
222 """ 216 """
223 Control coordinate and pixel transformation methods. 217 Control coordinate and pixel transformation methods.
224 """ 218 """
@@ -226,9 +220,9 @@ class Test(gammalib.GPythonTestSuite): @@ -226,9 +220,9 @@ class Test(gammalib.GPythonTestSuite):
226 for i in range(pixels.npix()): 220 for i in range(pixels.npix()):
227 dir = pixels.inx2dir(i) 221 dir = pixels.inx2dir(i)
228 inx = pixels.dir2inx(dir) 222 inx = pixels.dir2inx(dir)
229 - msg = map + " inx2dir/dir2inx check for pixel " + str(i)  
230 - err = map + " GSkyMap trouble with pixel " + str(i) + " (" + str(inx) + \  
231 - "), RA=" + str(dir.ra() * 180 / math.pi) + ", Dec=" + str(dir.dec() * 180 / math.pi) 223 + msg = map + ' inx2dir/dir2inx check for pixel ' + str(i)
  224 + err = map + ' GSkyMap trouble with pixel ' + str(i) + ' (' + str(inx) + \
  225 + '), RA=' + str(dir.ra() * 180 / math.pi) + ', Dec=' + str(dir.dec() * 180 / math.pi)
232 self.test_assert(i == inx, msg, err) 226 self.test_assert(i == inx, msg, err)
233 227
234 # Control SkyDir coordinate transformation for all pixels 228 # Control SkyDir coordinate transformation for all pixels
@@ -240,21 +234,21 @@ class Test(gammalib.GPythonTestSuite): @@ -240,21 +234,21 @@ class Test(gammalib.GPythonTestSuite):
240 if (dra >= 5.0): 234 if (dra >= 5.0):
241 dra -= 2.0 * math.pi 235 dra -= 2.0 * math.pi
242 ddec = abs(dir.dec() - dir_new.dec()) 236 ddec = abs(dir.dec() - dir_new.dec())
243 - msg = map + " dir check for pixel " + str(i)  
244 - err = map + " GSkyMap trouble with pixel " + str(i) + " (" + str(dra) + \  
245 - "," + str(ddec) + ")" 237 + msg = map + ' dir check for pixel ' + str(i)
  238 + err = map + ' GSkyMap trouble with pixel ' + str(i) + ' (' + str(dra) + \
  239 + ',' + str(ddec) + ')'
246 self.test_assert(not (dra > 1.0e-9 or ddec > 1.0e-9), msg, err) 240 self.test_assert(not (dra > 1.0e-9 or ddec > 1.0e-9), msg, err)
247 241
248 # Return 242 # Return
249 return 243 return
250 244
251 # Generic skymap projection test 245 # Generic skymap projection test
252 - def test_skymap_proj(self, proj): 246 + def _test_skymap_proj(self, proj):
253 """ 247 """
254 Test skymap projection. 248 Test skymap projection.
255 """ 249 """
256 # Set filename 250 # Set filename
257 - file = "test_python_skymap_" + proj + ".fits" 251 + file = 'test_python_skymap_' + proj + '.fits'
258 252
259 # Remove test files 253 # Remove test files
260 try: 254 try:
@@ -263,26 +257,26 @@ class Test(gammalib.GPythonTestSuite): @@ -263,26 +257,26 @@ class Test(gammalib.GPythonTestSuite):
263 pass 257 pass
264 258
265 # Create skymap 259 # Create skymap
266 - pixels = gammalib.GSkyMap(proj, "CEL", 83.6331, 22.0145, -3.7, 2.6, 5, 5, 20) 260 + pixels = gammalib.GSkyMap(proj, 'CEL', 83.6331, 22.0145, -3.7, 2.6, 5, 5, 20)
267 for map in range(pixels.nmaps()): 261 for map in range(pixels.nmaps()):
268 for i in range(pixels.npix()): 262 for i in range(pixels.npix()):
269 pixels[i, map] = i + map * pixels.npix() 263 pixels[i, map] = i + map * pixels.npix()
270 pixels.save(file) 264 pixels.save(file)
271 265
272 # Test coordinate and pixel transformations 266 # Test coordinate and pixel transformations
273 - self.test_skymap_pixels(pixels, proj) 267 + self._test_skymap_pixels(pixels, proj)
274 268
275 # Return 269 # Return
276 return 270 return
277 271
278 # Test HEALPix projection 272 # Test HEALPix projection
279 - def test_skymap_healpix(self): 273 + def _test_skymap_healpix(self):
280 """ 274 """
281 Test HEALPix interface. 275 Test HEALPix interface.
282 """ 276 """
283 # Set filenames 277 # Set filenames
284 - file1 = "test_python_skymap_hpx_v1.fits"  
285 - file2 = "test_python_skymap_hpx_v2.fits" 278 + file1 = 'test_python_skymap_hpx_v1.fits'
  279 + file2 = 'test_python_skymap_hpx_v2.fits'
286 280
287 # Remove test files 281 # Remove test files
288 try: 282 try:
@@ -292,7 +286,7 @@ class Test(gammalib.GPythonTestSuite): @@ -292,7 +286,7 @@ class Test(gammalib.GPythonTestSuite):
292 pass 286 pass
293 287
294 # Create HEALPix skymap 288 # Create HEALPix skymap
295 - pixels = gammalib.GSkyMap("GAL", 2, "RING", 2) 289 + pixels = gammalib.GSkyMap('GAL', 2, 'RING', 2)
296 for i in range(pixels.npix()): 290 for i in range(pixels.npix()):
297 pixels[i] = i + 1.0 291 pixels[i] = i + 1.0
298 pixels[i, 1] = i + 1.0 + 1000.0 292 pixels[i, 1] = i + 1.0 + 1000.0
@@ -302,7 +296,7 @@ class Test(gammalib.GPythonTestSuite): @@ -302,7 +296,7 @@ class Test(gammalib.GPythonTestSuite):
302 pixels = gammalib.GSkyMap(file1) 296 pixels = gammalib.GSkyMap(file1)
303 297
304 # Control coordinate and pixel transformations 298 # Control coordinate and pixel transformations
305 - self.test_skymap_pixels(pixels, "HEALPix") 299 + self._test_skymap_pixels(pixels, 'HEALPix')
306 300
307 # Save HEALPix skymap twice. The second saving should fail. 301 # Save HEALPix skymap twice. The second saving should fail.
308 try: 302 try:
@@ -311,7 +305,7 @@ class Test(gammalib.GPythonTestSuite): @@ -311,7 +305,7 @@ class Test(gammalib.GPythonTestSuite):
311 except RuntimeError: 305 except RuntimeError:
312 pass 306 pass
313 else: 307 else:
314 - raise RuntimeError("*** TEST ERROR: FITS file overwritten!") 308 + raise RuntimeError('*** TEST ERROR: FITS file overwritten!')
315 pixels.save(file2, True) 309 pixels.save(file2, True)
316 310
317 # Load again HEALPix skymap 311 # Load again HEALPix skymap
@@ -321,117 +315,117 @@ class Test(gammalib.GPythonTestSuite): @@ -321,117 +315,117 @@ class Test(gammalib.GPythonTestSuite):
321 return 315 return
322 316
323 # Test AIT projection 317 # Test AIT projection
324 - def test_skymap_ait(self): 318 + def _test_skymap_ait(self):
325 """ 319 """
326 Test AIT projection. 320 Test AIT projection.
327 """ 321 """
328 # Execute generic test 322 # Execute generic test
329 - self.test_skymap_proj("AIT") 323 + self._test_skymap_proj('AIT')
330 324
331 # Return 325 # Return
332 return 326 return
333 327
334 # Test AZP projection 328 # Test AZP projection
335 - def test_skymap_azp(self): 329 + def _test_skymap_azp(self):
336 """ 330 """
337 Test AZP projection. 331 Test AZP projection.
338 """ 332 """
339 # Execute generic test 333 # Execute generic test
340 - self.test_skymap_proj("AZP") 334 + self._test_skymap_proj('AZP')
341 335
342 # Return 336 # Return
343 return 337 return
344 338
345 # Test CAR projection 339 # Test CAR projection
346 - def test_skymap_car(self): 340 + def _test_skymap_car(self):
347 """ 341 """
348 Test CAR projection. 342 Test CAR projection.
349 """ 343 """
350 # Execute generic test 344 # Execute generic test
351 - self.test_skymap_proj("CAR") 345 + self._test_skymap_proj('CAR')
352 346
353 # Return 347 # Return
354 return 348 return
355 349
356 # Test GLS projection 350 # Test GLS projection
357 - def test_skymap_gls(self): 351 + def _test_skymap_gls(self):
358 """ 352 """
359 Test GLS projection. 353 Test GLS projection.
360 """ 354 """
361 # Execute generic test 355 # Execute generic test
362 - self.test_skymap_proj("GLS") 356 + self._test_skymap_proj('GLS')
363 357
364 # Return 358 # Return
365 return 359 return
366 360
367 # Test MER projection 361 # Test MER projection
368 - def test_skymap_mer(self): 362 + def _test_skymap_mer(self):
369 """ 363 """
370 Test MER projection. 364 Test MER projection.
371 """ 365 """
372 # Execute generic test 366 # Execute generic test
373 - self.test_skymap_proj("MER") 367 + self._test_skymap_proj('MER')
374 368
375 # Return 369 # Return
376 return 370 return
377 371
378 # Test MOL projection 372 # Test MOL projection
379 - def test_skymap_mol(self): 373 + def _test_skymap_mol(self):
380 """ 374 """
381 Test MOL projection. 375 Test MOL projection.
382 """ 376 """
383 # Execute generic test 377 # Execute generic test
384 - self.test_skymap_proj("MOL") 378 + self._test_skymap_proj('MOL')
385 379
386 # Return 380 # Return
387 return 381 return
388 382
389 # Test SIN projection 383 # Test SIN projection
390 - def test_skymap_sin(self): 384 + def _test_skymap_sin(self):
391 """ 385 """
392 Test SIN projection. 386 Test SIN projection.
393 """ 387 """
394 # Execute generic test 388 # Execute generic test
395 - self.test_skymap_proj("SIN") 389 + self._test_skymap_proj('SIN')
396 390
397 # Return 391 # Return
398 return 392 return
399 393
400 # Test SFL projection 394 # Test SFL projection
401 - def test_skymap_sfl(self): 395 + def _test_skymap_sfl(self):
402 """ 396 """
403 Test SFL projection. 397 Test SFL projection.
404 """ 398 """
405 # Execute generic test 399 # Execute generic test
406 - self.test_skymap_proj("SFL") 400 + self._test_skymap_proj('SFL')
407 401
408 # Return 402 # Return
409 return 403 return
410 404
411 # Test STG projection 405 # Test STG projection
412 - def test_skymap_stg(self): 406 + def _test_skymap_stg(self):
413 """ 407 """
414 Test STG projection. 408 Test STG projection.
415 """ 409 """
416 # Execute generic test 410 # Execute generic test
417 - self.test_skymap_proj("STG") 411 + self._test_skymap_proj('STG')
418 412
419 # Return 413 # Return
420 return 414 return
421 415
422 # Test TAN projection 416 # Test TAN projection
423 - def test_skymap_tan(self): 417 + def _test_skymap_tan(self):
424 """ 418 """
425 Test TAN projection. 419 Test TAN projection.
426 """ 420 """
427 # Execute generic test 421 # Execute generic test
428 - self.test_skymap_proj("TAN") 422 + self._test_skymap_proj('TAN')
429 423
430 # Return 424 # Return
431 return 425 return
432 426
433 # FK5 J2000 to Galactic coordinate tranformations 427 # FK5 J2000 to Galactic coordinate tranformations
434 - def test_fk5_to_galactic(self): 428 + def _test_fk5_to_galactic(self):
435 """ 429 """
436 Test precision of FK5 J2000 to Galactic coordinate tranformations 430 Test precision of FK5 J2000 to Galactic coordinate tranformations
437 against pyast (http://dsberry.github.com/starlink/pyast.html) 431 against pyast (http://dsberry.github.com/starlink/pyast.html)
@@ -446,8 +440,8 @@ class Test(gammalib.GPythonTestSuite): @@ -446,8 +440,8 @@ class Test(gammalib.GPythonTestSuite):
446 # Set parameters 440 # Set parameters
447 fk5_filename = datadir + 'initial_coords.txt' 441 fk5_filename = datadir + 'initial_coords.txt'
448 galactic_filename = datadir + 'fk5_to_galactic.txt' 442 galactic_filename = datadir + 'fk5_to_galactic.txt'
449 - fk5_coordinates = loadtxt(fk5_filename)  
450 - galactic_coordinates = loadtxt(galactic_filename) 443 + fk5_coordinates = _loadtxt(fk5_filename)
  444 + galactic_coordinates = _loadtxt(galactic_filename)
451 coordinates = zip(fk5_coordinates, galactic_coordinates) 445 coordinates = zip(fk5_coordinates, galactic_coordinates)
452 max_dist = 0 446 max_dist = 0
453 447
@@ -483,3 +477,70 @@ class Test(gammalib.GPythonTestSuite): @@ -483,3 +477,70 @@ class Test(gammalib.GPythonTestSuite):
483 477
484 # Return 478 # Return
485 return 479 return
  480 +
  481 + # Test GSkyRegions class access operators
  482 + def _test_regions_access(self):
  483 + """
  484 + Test GSkyRegions class observation access
  485 + """
  486 + # Setup regions container
  487 + regions = self._setup_regions()
  488 + circle = gammalib.GSkyRegionCircle()
  489 +
  490 + # Perform regions access tests
  491 + test_support._container_access_index(self, regions)
  492 +
  493 + # Check regions setting by index from start
  494 + circle.name('98')
  495 + regions[3] = circle
  496 + self.test_value(regions[3].name(), '98')
  497 +
  498 + # Check observation setting by index from end
  499 + circle.name('99')
  500 + regions[-2] = circle
  501 + self.test_value(regions[-2].name(), '99')
  502 +
  503 + # Return
  504 + return
  505 +
  506 + # Test GSkyRegions class slicing
  507 + def _test_regions_slicing(self):
  508 + """
  509 + Test GSkyRegions class slicing
  510 + """
  511 + # Setup regions container
  512 + regions = self._setup_regions()
  513 +
  514 + # Perform slicing tests
  515 + test_support._container_slicing(self, regions)
  516 +
  517 + # Return
  518 + return
  519 +
  520 + def set(self):
  521 + """
  522 + Set all test functions.
  523 + """
  524 + # Set test name
  525 + self.name("sky")
  526 +
  527 + # Append tests
  528 + self.append(self._test_methods, "Test sky map methods")
  529 + self.append(self._test_friend_methods, "Test sky map friend methods")
  530 + self.append(self._test_operators, "Test sky map operators")
  531 + self.append(self._test_skymap_healpix, "Test HEALPix map")
  532 + self.append(self._test_skymap_ait, "Test AIT projection map")
  533 + self.append(self._test_skymap_azp, "Test AZP projection map")
  534 + self.append(self._test_skymap_car, "Test CAR projection map")
  535 + self.append(self._test_skymap_gls, "Test GLS projection map")
  536 + self.append(self._test_skymap_mer, "Test MER projection map")
  537 + self.append(self._test_skymap_mol, "Test MOL projection map")
  538 + self.append(self._test_skymap_sfl, "Test SFL projection map")
  539 + self.append(self._test_skymap_sin, "Test SIN projection map")
  540 + self.append(self._test_skymap_stg, "Test STG projection map")
  541 + self.append(self._test_skymap_tan, "Test TAN projection map")
  542 + self.append(self._test_regions_access, "Test GSkyRegions region access")
  543 + self.append(self._test_regions_slicing, "Test GSkyRegions slicing")
  544 +
  545 + # Return
  546 + return
test/test_GSupport.py
1 # ========================================================================== 1 # ==========================================================================
2 # This module performs unit tests for the GammaLib support module. 2 # This module performs unit tests for the GammaLib support module.
3 # 3 #
4 -# Copyright (C) 2012-2016 Juergen Knoedlseder 4 +# Copyright (C) 2012-2017 Juergen Knoedlseder
5 # 5 #
6 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by 7 # it under the terms of the GNU General Public License as published by
@@ -39,26 +39,26 @@ class Test(gammalib.GPythonTestSuite): @@ -39,26 +39,26 @@ class Test(gammalib.GPythonTestSuite):
39 # Return 39 # Return
40 return 40 return
41 41
42 - # Set all test functions  
43 - def set(self):  
44 - """  
45 - Set all test functions. 42 + # Setup GNodeArray container
  43 + def _setup_nodes(self):
46 """ 44 """
47 - # Set test name  
48 - self.name('support') 45 + Setup GNodeArray
49 46
50 - # Append tests  
51 - self.append(self.test_node_array, 'Test GNodeArray')  
52 - self.append(self.test_url_file, 'Test GUrlFile')  
53 - self.append(self.test_url_string, 'Test GUrlString')  
54 - self.append(self.test_filename, 'Test GFilename')  
55 - self.append(self.test_csv, 'Test GCsv') 47 + Returns
  48 + -------
  49 + nodes : `~gammalib.GNodeArray`
  50 + Node array
  51 + """
  52 + # Setup time container
  53 + nodes = gammalib.GNodeArray()
  54 + for i in range(10):
  55 + nodes.append(float(i))
56 56
57 - # Return  
58 - return 57 + # Return GNodeArray
  58 + return nodes
59 59
60 # Test GNodeArray class 60 # Test GNodeArray class
61 - def test_node_array(self): 61 + def _test_node_array(self):
62 """ 62 """
63 Test GNodeArray class. 63 Test GNodeArray class.
64 """ 64 """
@@ -91,8 +91,91 @@ class Test(gammalib.GPythonTestSuite): @@ -91,8 +91,91 @@ class Test(gammalib.GPythonTestSuite):
91 # Return 91 # Return
92 return 92 return
93 93
  94 + # Test GNodeArray access
  95 + def _test_node_array_access(self):
  96 + """
  97 + Test GNodeArray access
  98 + """
  99 + # Setup nodes container
  100 + nodes = self._setup_nodes()
  101 +
  102 + # Loop over all elements using the container iterator and count the
  103 + # number of iterations
  104 + nnodes = 0
  105 + reference = 0.0
  106 + for node in nodes:
  107 + self.test_value(node, reference)
  108 + nnodes += 1
  109 + reference += 1.0
  110 +
  111 + # Check that looping was successful
  112 + self.test_value(nodes.size(), 10, 'Check container size')
  113 + self.test_value(nnodes, 10, 'Check container iterator')
  114 +
  115 + # Test access from start
  116 + self.test_value(nodes[3], 3.0)
  117 +
  118 + # Check access from end
  119 + self.test_value(nodes[-2], 8.0)
  120 +
  121 + # Return
  122 + return
  123 +
  124 + # Test GNodeArray slicing
  125 + def _test_node_array_slicing(self):
  126 + """
  127 + Test GNodeArray slicing
  128 + """
  129 + # Setup nodes container
  130 + nodes = self._setup_nodes()
  131 +
  132 + # Test nodes[start:end]
  133 + self.test_value(len(nodes[3:5]), 2)
  134 + self.test_value(nodes[3:5][0], 3.0)
  135 + self.test_value(nodes[3:5][1], 4.0)
  136 +
  137 + # Test nodes[start:]
  138 + self.test_value(len(nodes[7:]), 3)
  139 + self.test_value(nodes[7:][0], 7.0)
  140 + self.test_value(nodes[7:][1], 8.0)
  141 + self.test_value(nodes[7:][2], 9.0)
  142 +
  143 + # Test nodes[:end]
  144 + self.test_value(len(nodes[:2]), 2)
  145 + self.test_value(nodes[:2][0], 0.0)
  146 + self.test_value(nodes[:2][1], 1.0)
  147 +
  148 + # Test nodes[:]
  149 + self.test_value(len(nodes[:]), 10)
  150 + for i in range(10):
  151 + self.test_value(nodes[:][i], float(i))
  152 +
  153 + # Test nodes[start:end:step]
  154 + self.test_value(len(nodes[3:7:2]), 2)
  155 + self.test_value(nodes[3:7:2][0], 3.0)
  156 + self.test_value(nodes[3:7:2][1], 5.0)
  157 +
  158 + # Test nodes[start:end:step]
  159 + self.test_value(len(nodes[6:3:-2]), 2)
  160 + self.test_value(nodes[6:3:-2][0], 6.0)
  161 + self.test_value(nodes[6:3:-2][1], 4.0)
  162 +
  163 + # Test nodes[-start:]
  164 + self.test_value(len(nodes[-2:]), 2)
  165 + self.test_value(nodes[-2:][0], 8.0)
  166 + self.test_value(nodes[-2:][1], 9.0)
  167 +
  168 + # Test nodes[:-end]
  169 + self.test_value(len(nodes[:-7]), 3)
  170 + self.test_value(nodes[:-7][0], 0.0)
  171 + self.test_value(nodes[:-7][1], 1.0)
  172 + self.test_value(nodes[:-7][2], 2.0)
  173 +
  174 + # Return
  175 + return
  176 +
94 # Test GUrlFile class 177 # Test GUrlFile class
95 - def test_url_file(self): 178 + def _test_url_file(self):
96 """ 179 """
97 Test GUrlFile class. 180 Test GUrlFile class.
98 """ 181 """
@@ -113,7 +196,7 @@ class Test(gammalib.GPythonTestSuite): @@ -113,7 +196,7 @@ class Test(gammalib.GPythonTestSuite):
113 return 196 return
114 197
115 # Test GUrlString class 198 # Test GUrlString class
116 - def test_url_string(self): 199 + def _test_url_string(self):
117 """ 200 """
118 Test GUrlString class. 201 Test GUrlString class.
119 """ 202 """
@@ -133,7 +216,7 @@ class Test(gammalib.GPythonTestSuite): @@ -133,7 +216,7 @@ class Test(gammalib.GPythonTestSuite):
133 return 216 return
134 217
135 # Test GFilename class 218 # Test GFilename class
136 - def test_filename(self): 219 + def _test_filename(self):
137 """ 220 """
138 Test GFilename class. 221 Test GFilename class.
139 """ 222 """
@@ -158,7 +241,7 @@ class Test(gammalib.GPythonTestSuite): @@ -158,7 +241,7 @@ class Test(gammalib.GPythonTestSuite):
158 return 241 return
159 242
160 # Test GCsv class 243 # Test GCsv class
161 - def test_csv(self): 244 + def _test_csv(self):
162 """ 245 """
163 Test GCsv class. 246 Test GCsv class.
164 """ 247 """
@@ -195,3 +278,24 @@ class Test(gammalib.GPythonTestSuite): @@ -195,3 +278,24 @@ class Test(gammalib.GPythonTestSuite):
195 278
196 # Return 279 # Return
197 return 280 return
  281 +
  282 + # Set all test functions
  283 + def set(self):
  284 + """
  285 + Set all test functions.
  286 + """
  287 + # Set test name
  288 + self.name('support')
  289 +
  290 + # Append tests
  291 + self.append(self._test_node_array, 'Test GNodeArray')
  292 + self.append(self._test_node_array_access, 'Test GNodeArray node access')
  293 + self.append(self._test_node_array_slicing, 'Test GNodeArray slicing')
  294 + self.append(self._test_url_file, 'Test GUrlFile')
  295 + self.append(self._test_url_string, 'Test GUrlString')
  296 + self.append(self._test_filename, 'Test GFilename')
  297 + self.append(self._test_csv, 'Test GCsv')
  298 +
  299 + # Return
  300 + return
  301 +
test/test_GTest.py
1 # ========================================================================== 1 # ==========================================================================
2 # This module performs unit tests for the GammaLib test module. 2 # This module performs unit tests for the GammaLib test module.
3 # 3 #
4 -# Copyright (C) 2012-2015 Juergen Knoedlseder 4 +# Copyright (C) 2012-2017 Juergen Knoedlseder
5 # 5 #
6 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by 7 # it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 # 18 #
19 # ========================================================================== 19 # ==========================================================================
20 import gammalib 20 import gammalib
  21 +import test_support
21 22
22 23
23 # =================================== # 24 # =================================== #
@@ -25,12 +26,12 @@ import gammalib @@ -25,12 +26,12 @@ import gammalib
25 # =================================== # 26 # =================================== #
26 class Test(gammalib.GPythonTestSuite): 27 class Test(gammalib.GPythonTestSuite):
27 """ 28 """
28 - Test class for GammaLib test module. 29 + Test class for GammaLib test module
29 """ 30 """
30 # Constructor 31 # Constructor
31 def __init__(self): 32 def __init__(self):
32 """ 33 """
33 - Constructor. 34 + Constructor
34 """ 35 """
35 # Call base class constructor 36 # Call base class constructor
36 gammalib.GPythonTestSuite.__init__(self) 37 gammalib.GPythonTestSuite.__init__(self)
@@ -38,24 +39,76 @@ class Test(gammalib.GPythonTestSuite): @@ -38,24 +39,76 @@ class Test(gammalib.GPythonTestSuite):
38 # Return 39 # Return
39 return 40 return
40 41
41 - # Set test functions  
42 - def set(self): 42 + # Setup test suite container
  43 + def _setup_suites(self):
43 """ 44 """
44 - Set all test functions. 45 + Setup test suite container
  46 +
  47 + Returns
  48 + -------
  49 + suites : `~gammalib.GTestSuites`
  50 + Test suite container
45 """ 51 """
46 - # Set test name  
47 - self.name("test") 52 + # Setup test suite container
  53 + suites = gammalib.GTestSuites()
  54 + suite = gammalib.GPythonTestSuite()
  55 + for i in range(10):
  56 + suite.name('%s' % i)
  57 + suites.append(suite)
48 58
49 - # Append tests  
50 - self.append(self.test, "Test module dummy test") 59 + # Return test suite container
  60 + return suites
  61 +
  62 + # Test GTestSuites class access operators
  63 + def _test_suites_access(self):
  64 + """
  65 + Test GTestSuites class parameter access
  66 + """
  67 + # Setup test suite container and test suite
  68 + suites = self._setup_suites()
  69 + suite = gammalib.GPythonTestSuite()
  70 +
  71 + # Perform GTestSuites access tests
  72 + test_support._container_access_index(self, suites)
  73 +
  74 + # Check parameter setting by index from start
  75 + suite.name('98')
  76 + suites[3] = suite
  77 + self.test_value(suites[3].name(), '98')
  78 +
  79 + # Check parameter setting by index from end
  80 + suite.name('99')
  81 + suites[-2] = suite
  82 + self.test_value(suites[-2].name(), '99')
  83 +
  84 + # Return
  85 + return
  86 +
  87 + # Test GTestSuites class slicing
  88 + def _test_suites_slicing(self):
  89 + """
  90 + Test GTestSuites class slicing
  91 + """
  92 + # Setup test suite container
  93 + suites = self._setup_suites()
  94 +
  95 + # Perform slicing tests
  96 + test_support._container_slicing(self, suites)
51 97
52 # Return 98 # Return
53 return 99 return
54 100
55 - # Test function  
56 - def test(self): 101 + # Set test functions
  102 + def set(self):
57 """ 103 """
58 - Test function. 104 + Set all test functions.
59 """ 105 """
  106 + # Set test name
  107 + self.name('test')
  108 +
  109 + # Append tests
  110 + self.append(self._test_suites_access, 'Test GTestSuites parameter access')
  111 + self.append(self._test_suites_slicing, 'Test GTestSuites slicing')
  112 +
60 # Return 113 # Return
61 return 114 return
test/test_GXml.py
1 # ========================================================================== 1 # ==========================================================================
2 # This module performs unit tests for the GammaLib xml module. 2 # This module performs unit tests for the GammaLib xml module.
3 # 3 #
4 -# Copyright (C) 2012-2015 Juergen Knoedlseder 4 +# Copyright (C) 2012-2017 Juergen Knoedlseder
5 # 5 #
6 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by 7 # it under the terms of the GNU General Public License as published by
@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 # 18 #
19 # ========================================================================== 19 # ==========================================================================
20 import gammalib 20 import gammalib
  21 +import test_support
21 22
22 23
23 # ================================== # 24 # ================================== #
@@ -25,7 +26,7 @@ import gammalib @@ -25,7 +26,7 @@ import gammalib
25 # ================================== # 26 # ================================== #
26 class Test(gammalib.GPythonTestSuite): 27 class Test(gammalib.GPythonTestSuite):
27 """ 28 """
28 - Test class for GammaLib xml module. 29 + Test class for GammaLib xml module
29 """ 30 """
30 # Constructor 31 # Constructor
31 def __init__(self): 32 def __init__(self):
@@ -38,24 +39,137 @@ class Test(gammalib.GPythonTestSuite): @@ -38,24 +39,137 @@ class Test(gammalib.GPythonTestSuite):
38 # Return 39 # Return
39 return 40 return
40 41
41 - # Set test functions  
42 - def set(self): 42 + # Setup GXml container
  43 + def _setup_xml(self):
43 """ 44 """
44 - Set all test functions. 45 + Setup GXml container
  46 +
  47 + Returns
  48 + -------
  49 + xml : `~gammalib.GXml`
  50 + GXml container
45 """ 51 """
46 - # Set test name  
47 - self.name("xml") 52 + # Setup XML container
  53 + xml = gammalib.GXml()
  54 + element = gammalib.GXmlElement()
  55 + for i in range(10):
  56 + element.name('%s' % i)
  57 + xml.append(element)
48 58
49 - # Append tests  
50 - self.append(self.test, "XML module dummy test") 59 + # Return XML container
  60 + return xml
  61 +
  62 + # Setup GXmlElement container
  63 + def _setup_elements(self):
  64 + """
  65 + Setup GXmlElement container
  66 +
  67 + Returns
  68 + -------
  69 + elements : `~gammalib.GXmlElement`
  70 + GXml container
  71 + """
  72 + # Setup GXmlElement container
  73 + elements = gammalib.GXmlElement()
  74 + element = gammalib.GXmlElement()
  75 + for i in range(10):
  76 + element.name('%s' % i)
  77 + elements.append(element)
  78 +
  79 + # Return GXmlElement container
  80 + return elements
  81 +
  82 + # Test GXml class access operators
  83 + def _test_xml_access(self):
  84 + """
  85 + Test GXml class parameter access
  86 + """
  87 + # Setup XML container and element
  88 + xml = self._setup_xml()
  89 + element = gammalib.GXmlElement()
  90 +
  91 + # Perform GXml access tests
  92 + test_support._container_access_index(self, xml)
  93 +
  94 + # Check parameter setting by index from start
  95 + element.name('98')
  96 + xml[3] = element
  97 + self.test_value(xml[3].name(), '98')
  98 +
  99 + # Check parameter setting by index from end
  100 + element.name('99')
  101 + xml[-2] = element
  102 + self.test_value(xml[-2].name(), '99')
  103 +
  104 + # Return
  105 + return
  106 +
  107 + # Test GXml class slicing
  108 + def _test_xml_slicing(self):
  109 + """
  110 + Test GXml class slicing
  111 + """
  112 + # Setup XML container
  113 + xml = self._setup_xml()
  114 +
  115 + # Perform slicing tests
  116 + test_support._container_slicing(self, xml)
51 117
52 # Return 118 # Return
53 return 119 return
54 120
55 - # Test function  
56 - def test(self): 121 + # Test GXmlElement class access operators
  122 + def _test_elements_access(self):
57 """ 123 """
58 - Test function. 124 + Test GXmlElement class parameter access
59 """ 125 """
  126 + # Setup GXmlElement container and element
  127 + elements = self._setup_elements()
  128 + element = gammalib.GXmlElement()
  129 +
  130 + # Perform GXmlElement access tests
  131 + test_support._container_access_index(self, elements)
  132 +
  133 + # Check parameter setting by index from start
  134 + element.name('98')
  135 + elements[3] = element
  136 + self.test_value(elements[3].name(), '98')
  137 +
  138 + # Check parameter setting by index from end
  139 + element.name('99')
  140 + elements[-2] = element
  141 + self.test_value(elements[-2].name(), '99')
  142 +
  143 + # Return
  144 + return
  145 +
  146 + # Test GXmlElement class slicing
  147 + def _test_elements_slicing(self):
  148 + """
  149 + Test GXmlElement class slicing
  150 + """
  151 + # Setup GXmlElement container
  152 + elements = self._setup_elements()
  153 +
  154 + # Perform slicing tests
  155 + test_support._container_slicing(self, elements)
  156 +
  157 + # Return
  158 + return
  159 +
  160 + # Set test functions
  161 + def set(self):
  162 + """
  163 + Set all test functions.
  164 + """
  165 + # Set test name
  166 + self.name('xml')
  167 +
  168 + # Append tests
  169 + self.append(self._test_xml_access, 'Test GXml parameter access')
  170 + self.append(self._test_xml_slicing, 'Test GXml slicing')
  171 + self.append(self._test_elements_access, 'Test GXmlElement parameter access')
  172 + self.append(self._test_elements_slicing, 'Test GXmlElement slicing')
  173 +
60 # Return 174 # Return
61 return 175 return
test/test_support.py
@@ -50,6 +50,69 @@ def _container_access_index(testsuite, container): @@ -50,6 +50,69 @@ def _container_access_index(testsuite, container):
50 # Check access from end 50 # Check access from end
51 testsuite.test_value(container[-2].name(), '8') 51 testsuite.test_value(container[-2].name(), '8')
52 52
  53 + # Clone first element
  54 + #element = container[0].copy()
  55 +
  56 + # Check setting by index from start
  57 + #element.name('98')
  58 + #container[3] = element
  59 + #self.test_value(container[3].name(), '98')
  60 +
  61 + # Check setting by index from end
  62 + #element.name('99')
  63 + #container[-2] = element
  64 + #self.test_value(container[-2].name(), '99')
  65 +
  66 + # Return
  67 + return
  68 +
  69 +
  70 +# ===================================== #
  71 +# Test energy container access by index #
  72 +# ===================================== #
  73 +def _energy_container_access_index(testsuite, container):
  74 + """
  75 + Test energy container access by index
  76 +
  77 + Parameters
  78 + ----------
  79 + testsuite : `~gammalib.GPythonTestSuite`
  80 + Test suite class
  81 + container : `~gammalib.GContainer`
  82 + Container class
  83 + """
  84 + # Loop over all elements using the container iterator and count the number
  85 + # of iterations
  86 + niter = 0
  87 + reference = 0.0
  88 + for element in container:
  89 + testsuite.test_value(element.energy().MeV(), reference)
  90 + niter += 1
  91 + reference += 1.0
  92 +
  93 + # Check that looping was successful
  94 + testsuite.test_value(container.size(), 10, 'Check container size')
  95 + testsuite.test_value(niter, 10, 'Check container iterator')
  96 +
  97 + # Test access from start
  98 + testsuite.test_value(container[3].energy().MeV(), 3.0)
  99 +
  100 + # Check access from end
  101 + testsuite.test_value(container[-2].energy().MeV(), 8.0)
  102 +
  103 + # Clone first element
  104 + element = container[0].copy()
  105 +
  106 + # Check setting by index from start
  107 + element.energy().MeV(98.0)
  108 + container[3] = element
  109 + testsuite.test_value(container[3].energy().MeV(), 98.0)
  110 +
  111 + # Check setting setting by index from end
  112 + element.energy().MeV(99.0)
  113 + container[-2] = element
  114 + testsuite.test_value(container[-2].energy().MeV(), 99.0)
  115 +
53 # Return 116 # Return
54 return 117 return
55 118
@@ -112,3 +175,63 @@ def _container_slicing(testsuite, container): @@ -112,3 +175,63 @@ def _container_slicing(testsuite, container):
112 175
113 # Return 176 # Return
114 return 177 return
  178 +
  179 +
  180 +# ============================= #
  181 +# Test energy container slicing #
  182 +# ============================= #
  183 +def _energy_container_slicing(testsuite, container):
  184 + """
  185 + Test energy container slicing
  186 +
  187 + Parameters
  188 + ----------
  189 + testsuite : `~gammalib.GPythonTestSuite`
  190 + Test suite class
  191 + container : `~gammalib.GContainer`
  192 + Container class
  193 + """
  194 + # Test container[start:end]
  195 + testsuite.test_value(len(container[3:5]), 2)
  196 + testsuite.test_value(container[3:5][0].energy().MeV(), 3.0)
  197 + testsuite.test_value(container[3:5][1].energy().MeV(), 4.0)
  198 +
  199 + # Test container[start:]
  200 + testsuite.test_value(len(container[7:]), 3)
  201 + testsuite.test_value(container[7:][0].energy().MeV(), 7.0)
  202 + testsuite.test_value(container[7:][1].energy().MeV(), 8.0)
  203 + testsuite.test_value(container[7:][2].energy().MeV(), 9.0)
  204 +
  205 + # Test container[:end]
  206 + testsuite.test_value(len(container[:2]), 2)
  207 + testsuite.test_value(container[:2][0].energy().MeV(), 0.0)
  208 + testsuite.test_value(container[:2][1].energy().MeV(), 1.0)
  209 +
  210 + # Test container[:]
  211 + testsuite.test_value(len(container[:]), 10)
  212 + for i in range(10):
  213 + testsuite.test_value(container[:][i].energy().MeV(), float(i))
  214 +
  215 + # Test container[start:end:step]
  216 + testsuite.test_value(len(container[3:7:2]), 2)
  217 + testsuite.test_value(container[3:7:2][0].energy().MeV(), 3.0)
  218 + testsuite.test_value(container[3:7:2][1].energy().MeV(), 5.0)
  219 +
  220 + # Test container[start:end:step]
  221 + testsuite.test_value(len(container[6:3:-2]), 2)
  222 + testsuite.test_value(container[6:3:-2][0].energy().MeV(), 6.0)
  223 + testsuite.test_value(container[6:3:-2][1].energy().MeV(), 4.0)
  224 +
  225 + # Test container[-start:]
  226 + testsuite.test_value(len(container[-2:]), 2)
  227 + testsuite.test_value(container[-2:][0].energy().MeV(), 8.0)
  228 + testsuite.test_value(container[-2:][1].energy().MeV(), 9.0)
  229 +
  230 + # Test container[:-end]
  231 + testsuite.test_value(len(container[:-7]), 3)
  232 + testsuite.test_value(container[:-7][0].energy().MeV(), 0.0)
  233 + testsuite.test_value(container[:-7][1].energy().MeV(), 1.0)
  234 + testsuite.test_value(container[:-7][2].energy().MeV(), 2.0)
  235 +
  236 + # Return
  237 + return