Commit 76afa729ffd96927d239cf699dce53d4fa17b95e

Authored by Jürgen Knödlseder
1 parent ce48d505

Enhance ctools unit tests

src/ctbkgcube/ctbkgcube.cpp
@@ -488,6 +488,12 @@ void ctbkgcube::get_parameters(void) @@ -488,6 +488,12 @@ void ctbkgcube::get_parameters(void)
488 488
489 } // endif: there was no observation in the container 489 } // endif: there was no observation in the container
490 490
  491 + // ... otherwise add response information and energy boundaries in case
  492 + // that they are missing
  493 + else {
  494 + setup_observations(m_obs);
  495 + }
  496 +
491 // Get the incube filename 497 // Get the incube filename
492 std::string incube = (*this)["incube"].filename(); 498 std::string incube = (*this)["incube"].filename();
493 499
src/ctbutterfly/ctbutterfly.cpp
@@ -573,9 +573,8 @@ void ctbutterfly::free_members(void) @@ -573,9 +573,8 @@ void ctbutterfly::free_members(void)
573 /***********************************************************************//** 573 /***********************************************************************//**
574 * @brief Get application parameters 574 * @brief Get application parameters
575 * 575 *
576 - * @exception GException::invalid_value  
577 - * Test source not found or no RA/DEC parameters found for test  
578 - * source. 576 + * @exception GException::feature_not_implemented
  577 + * Loading of covariance matrix is not yet implemented.
579 * 578 *
580 * Get all task parameters from parameter file or (if required) by querying 579 * Get all task parameters from parameter file or (if required) by querying
581 * the user. Most parameters are only required if no observation exists so 580 * the user. Most parameters are only required if no observation exists so
@@ -597,6 +596,11 @@ void ctbutterfly::get_parameters(void) @@ -597,6 +596,11 @@ void ctbutterfly::get_parameters(void)
597 596
598 } // endif: there was no observation in the container 597 } // endif: there was no observation in the container
599 598
  599 + // ... otherwise add response information and energy boundaries in case
  600 + // that they are missing
  601 + else {
  602 + setup_observations(m_obs);
  603 + }
600 604
601 // If there is are no models associated with the observations then 605 // If there is are no models associated with the observations then
602 // load now the model definition 606 // load now the model definition
src/ctcubemask/ctcubemask.cpp
@@ -301,7 +301,7 @@ void ctcubemask::save(void) @@ -301,7 +301,7 @@ void ctcubemask::save(void)
301 // Get counts cube filename 301 // Get counts cube filename
302 m_outcube = (*this)["outcube"].filename(); 302 m_outcube = (*this)["outcube"].filename();
303 303
304 - // Case A: Save event file(s) and XML metadata information 304 + // Case A: Save counts cube(s) and XML metadata information
305 if (m_use_xml) { 305 if (m_use_xml) {
306 306
307 // Get prefix 307 // Get prefix
@@ -311,7 +311,7 @@ void ctcubemask::save(void) @@ -311,7 +311,7 @@ void ctcubemask::save(void)
311 save_xml(); 311 save_xml();
312 } 312 }
313 313
314 - // Case B: Save event file as FITS file 314 + // Case B: Save counts cube as FITS file
315 else { 315 else {
316 save_fits(); 316 save_fits();
317 } 317 }
@@ -404,9 +404,9 @@ void ctcubemask::init_members(void) @@ -404,9 +404,9 @@ void ctcubemask::init_members(void)
404 void ctcubemask::copy_members(const ctcubemask& app) 404 void ctcubemask::copy_members(const ctcubemask& app)
405 { 405 {
406 // Copy parameters 406 // Copy parameters
407 - m_regfile = app.m_regfile; 407 + m_regfile = app.m_regfile;
408 m_outcube = app.m_outcube; 408 m_outcube = app.m_outcube;
409 - m_prefix = app.m_prefix; 409 + m_prefix = app.m_prefix;
410 m_usepnt = app.m_usepnt; 410 m_usepnt = app.m_usepnt;
411 m_ra = app.m_ra; 411 m_ra = app.m_ra;
412 m_dec = app.m_dec; 412 m_dec = app.m_dec;
@@ -471,7 +471,7 @@ void ctcubemask::get_parameters(void) @@ -471,7 +471,7 @@ void ctcubemask::get_parameters(void)
471 } // endif: there was no observation in the container 471 } // endif: there was no observation in the container
472 472
473 // Get parameters 473 // Get parameters
474 - m_regfile = (*this)["regfile"].filename(); 474 + m_regfile = (*this)["regfile"].filename();
475 m_usepnt = (*this)["usepnt"].boolean(); 475 m_usepnt = (*this)["usepnt"].boolean();
476 if (!m_usepnt) { 476 if (!m_usepnt) {
477 477
@@ -725,18 +725,23 @@ std::string ctcubemask::set_outfile_name(const std::string& filename) const @@ -725,18 +725,23 @@ std::string ctcubemask::set_outfile_name(const std::string& filename) const
725 ***************************************************************************/ 725 ***************************************************************************/
726 void ctcubemask::save_fits(void) 726 void ctcubemask::save_fits(void)
727 { 727 {
728 - // Save only if filename is non-empty  
729 - if (!m_outcube.is_empty()) { 728 + // Save only if filename is non-empty and if there are observations
  729 + if (!m_outcube.is_empty() && m_obs.size() > 0) {
730 730
731 // Get CTA observation from observation container 731 // Get CTA observation from observation container
732 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]); 732 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]);
733 733
734 - // Log counts cube file name  
735 - log_value(NORMAL, "Counts cube file", m_outcube.url()); 734 + // Handle only CTA observations
  735 + if (obs != NULL) {
  736 +
  737 + // Log counts cube file name
  738 + log_value(NORMAL, "Counts cube file", m_outcube.url());
736 739
737 - // Save event list  
738 - save_counts_map(obs, m_outcube); 740 + // Save counts cube
  741 + obs->save(m_outcube, clobber());
739 742
  743 + } // endif: observation was a CTA observation
  744 +
740 } 745 }
741 746
742 // Return 747 // Return
@@ -745,30 +750,20 @@ void ctcubemask::save_fits(void) @@ -745,30 +750,20 @@ void ctcubemask::save_fits(void)
745 750
746 751
747 /***********************************************************************//** 752 /***********************************************************************//**
748 - * @brief Save counts map(s) in XML format. 753 + * @brief Save counts cube(s) in XML format.
749 * 754 *
750 - * Save the counts map(s) into FITS files and write the file path information  
751 - * into a XML file. The filename of the XML file is specified by the  
752 - * m_outfile member, the filename(s) of the counts map(s) are built by 755 + * Save the counts cube(s) into FITS files and write the file path
  756 + * information into an XML file. The filename of the XML file is specified by
  757 + * the m_outfile member, the filename(s) of the counts cube(s) are built by
753 * prepending the prefix given by the m_prefix member to the input counts 758 * prepending the prefix given by the m_prefix member to the input counts
754 - * map(s) filenames. Any path present in the input filename will be stripped,  
755 - * i.e. the counts map(s) will be written in the local working directory  
756 - * (unless a path is specified in the m_prefix member). 759 + * cube(s) filenames. Any path present in the input filename will be
  760 + * stripped, i.e. the counts cube(s) will be written in the local working
  761 + * directory (unless a path is specified in the m_prefix member).
757 ***************************************************************************/ 762 ***************************************************************************/
758 void ctcubemask::save_xml(void) 763 void ctcubemask::save_xml(void)
759 { 764 {
760 // Issue warning if output filename has no .xml suffix 765 // Issue warning if output filename has no .xml suffix
761 - std::string suffix = gammalib::tolower(m_outcube.url().substr(  
762 - m_outcube.length()-4,4));  
763 - if (suffix != ".xml") {  
764 - std::string msg = "\nWARNING: Name of observation definition output "  
765 - "file \""+m_outcube+"\" does not terminate with\n"  
766 - " \".xml\". This is not an error, but may "  
767 - "be misleading. It is recommended to use the\n"  
768 - " suffix \".xml\" for observation definition "  
769 - "files.";  
770 - log_string(TERSE, msg);  
771 - } 766 + log_string(TERSE, warn_xml_suffix(m_outcube.url()));
772 767
773 // Loop over all observation in the container 768 // Loop over all observation in the container
774 for (int i = 0; i < m_obs.size(); ++i) { 769 for (int i = 0; i < m_obs.size(); ++i) {
@@ -788,8 +783,8 @@ void ctcubemask::save_xml(void) @@ -788,8 +783,8 @@ void ctcubemask::save_xml(void)
788 // Log counts cube file name 783 // Log counts cube file name
789 log_value(NORMAL, "Counts cube file", outfile); 784 log_value(NORMAL, "Counts cube file", outfile);
790 785
791 - // Save event list  
792 - save_counts_map(obs, outfile); 786 + // Save counts cube
  787 + obs->save(outfile, clobber());
793 788
794 } // endif: observation was a CTA observations 789 } // endif: observation was a CTA observations
795 790
@@ -801,30 +796,3 @@ void ctcubemask::save_xml(void) @@ -801,30 +796,3 @@ void ctcubemask::save_xml(void)
801 // Return 796 // Return
802 return; 797 return;
803 } 798 }
804 -  
805 -  
806 -  
807 -/***********************************************************************//**  
808 - * @brief Save a single counts map into a FITS file  
809 - *  
810 - * @param[in] obs Pointer to CTA observation.  
811 - * @param[in] outfile Output file name.  
812 - *  
813 - * This method saves a single counts map into a FITS file. The method does  
814 - * nothing if the observation pointer is not valid.  
815 - ***************************************************************************/  
816 -void ctcubemask::save_counts_map(const GCTAObservation* obs,  
817 - const std::string& outfile) const  
818 -{  
819 - // Save only if observation is valid  
820 - if (obs != NULL) {  
821 -  
822 - // Save observation into FITS file  
823 - obs->save(outfile, clobber());  
824 -  
825 - } // endif: observation was valid  
826 -  
827 - // Return  
828 - return;  
829 -}  
830 -  
src/ctcubemask/ctcubemask.hpp
@@ -36,7 +36,7 @@ @@ -36,7 +36,7 @@
36 36
37 /* __Definitions _________________________________________________________ */ 37 /* __Definitions _________________________________________________________ */
38 #define CTCUBEMASK_NAME "ctcubemask" 38 #define CTCUBEMASK_NAME "ctcubemask"
39 -#define CTCUBEMASK_VERSION "1.1.0" 39 +#define CTCUBEMASK_VERSION "1.2.0"
40 40
41 41
42 /***********************************************************************//** 42 /***********************************************************************//**
@@ -75,8 +75,6 @@ protected: @@ -75,8 +75,6 @@ protected:
75 std::string set_outfile_name(const std::string& filename) const; 75 std::string set_outfile_name(const std::string& filename) const;
76 void save_fits(void); 76 void save_fits(void);
77 void save_xml(void); 77 void save_xml(void);
78 - void save_counts_map(const GCTAObservation* obs,  
79 - const std::string& outfile) const;  
80 78
81 // User parameters 79 // User parameters
82 GFilename m_regfile; //!< ds9 region file 80 GFilename m_regfile; //!< ds9 region file
src/ctedispcube/ctedispcube.cpp
@@ -361,6 +361,12 @@ void ctedispcube::get_parameters(void) @@ -361,6 +361,12 @@ void ctedispcube::get_parameters(void)
361 361
362 } // endif: there was no observation in the container 362 } // endif: there was no observation in the container
363 363
  364 + // ... otherwise add response information and energy boundaries in case
  365 + // that they are missing
  366 + else {
  367 + setup_observations(m_obs);
  368 + }
  369 +
364 // Get the incube filename 370 // Get the incube filename
365 std::string incube = (*this)["incube"].filename(); 371 std::string incube = (*this)["incube"].filename();
366 372
src/cterror/cterror.cpp
@@ -475,6 +475,11 @@ void cterror::get_parameters(void) @@ -475,6 +475,11 @@ void cterror::get_parameters(void)
475 475
476 } // endif: there was no observation in the container 476 } // endif: there was no observation in the container
477 477
  478 + // ... otherwise add response information and energy boundaries in case
  479 + // that they are missing
  480 + else {
  481 + setup_observations(m_obs);
  482 + }
478 483
479 // If there are no models associated with the observations then 484 // If there are no models associated with the observations then
480 // load now the model definition 485 // load now the model definition
src/ctexpcube/ctexpcube.cpp
@@ -386,6 +386,12 @@ void ctexpcube::get_parameters(void) @@ -386,6 +386,12 @@ void ctexpcube::get_parameters(void)
386 386
387 } // endif: there was no observation in the container 387 } // endif: there was no observation in the container
388 388
  389 + // ... otherwise add response information and energy boundaries in case
  390 + // that they are missing
  391 + else {
  392 + setup_observations(m_obs);
  393 + }
  394 +
389 // Get the incube filename 395 // Get the incube filename
390 std::string incube = (*this)["incube"].filename(); 396 std::string incube = (*this)["incube"].filename();
391 397
src/ctlike/ctlike.cpp
@@ -373,6 +373,12 @@ void ctlike::get_parameters(void) @@ -373,6 +373,12 @@ void ctlike::get_parameters(void)
373 373
374 } // endif: there was no observation in the container 374 } // endif: there was no observation in the container
375 375
  376 + // ... otherwise add response information and energy boundaries in case
  377 + // that they are missing
  378 + else {
  379 + setup_observations(m_obs);
  380 + }
  381 +
376 // If only single observation is used, read statistics parameter 382 // If only single observation is used, read statistics parameter
377 if (!m_use_xml) { 383 if (!m_use_xml) {
378 384
src/ctmodel/ctmodel.cpp
@@ -456,6 +456,12 @@ void ctmodel::get_parameters(void) @@ -456,6 +456,12 @@ void ctmodel::get_parameters(void)
456 get_obs(); 456 get_obs();
457 } 457 }
458 458
  459 + // ... otherwise add response information and energy boundaries in case
  460 + // that they are missing
  461 + else {
  462 + setup_observations(m_obs);
  463 + }
  464 +
459 // If we have now excactly one CTA observation (but no cube has yet been 465 // If we have now excactly one CTA observation (but no cube has yet been
460 // appended to the observation) then check whether this observation 466 // appended to the observation) then check whether this observation
461 // is a binned observation, and if yes, extract the counts cube for 467 // is a binned observation, and if yes, extract the counts cube for
src/ctobssim/ctobssim.cpp
@@ -561,9 +561,10 @@ void ctobssim::get_parameters(void) @@ -561,9 +561,10 @@ void ctobssim::get_parameters(void)
561 561
562 } 562 }
563 563
564 - // ... otherwise make sure that observation boundaries are set 564 + // ... otherwise add response information and energy boundaries in case
  565 + // that they are missing
565 else { 566 else {
566 - set_obs_bounds(m_obs); 567 + setup_observations(m_obs);
567 } 568 }
568 569
569 // Read model definition file if required 570 // Read model definition file if required
src/ctpsfcube/ctpsfcube.cpp
@@ -346,6 +346,12 @@ void ctpsfcube::get_parameters(void) @@ -346,6 +346,12 @@ void ctpsfcube::get_parameters(void)
346 346
347 } // endif: there was no observation in the container 347 } // endif: there was no observation in the container
348 348
  349 + // ... otherwise add response information and energy boundaries in case
  350 + // that they are missing
  351 + else {
  352 + setup_observations(m_obs);
  353 + }
  354 +
349 // Get the incube filename 355 // Get the incube filename
350 std::string incube = (*this)["incube"].filename(); 356 std::string incube = (*this)["incube"].filename();
351 357
src/cttsmap/cttsmap.cpp
@@ -523,6 +523,12 @@ void cttsmap::get_parameters(void) @@ -523,6 +523,12 @@ void cttsmap::get_parameters(void)
523 523
524 } // endif: there was no observation in the container 524 } // endif: there was no observation in the container
525 525
  526 + // ... otherwise add response information and energy boundaries in case
  527 + // that they are missing
  528 + else {
  529 + setup_observations(m_obs);
  530 + }
  531 +
526 // If there is are no models associated with the observations then 532 // If there is are no models associated with the observations then
527 // load now the model definition 533 // load now the model definition
528 if (m_obs.models().size() == 0) { 534 if (m_obs.models().size() == 0) {
src/ctulimit/ctulimit.cpp
@@ -481,6 +481,11 @@ void ctulimit::get_parameters(void) @@ -481,6 +481,11 @@ void ctulimit::get_parameters(void)
481 481
482 } // endif: there was no observation in the container 482 } // endif: there was no observation in the container
483 483
  484 + // ... otherwise add response information and energy boundaries in case
  485 + // that they are missing
  486 + else {
  487 + setup_observations(m_obs);
  488 + }
484 489
485 // If there is are no models associated with the observations then 490 // If there is are no models associated with the observations then
486 // load now the model definition 491 // load now the model definition
src/support/ctool.cpp
@@ -1646,7 +1646,7 @@ std::string ctool::warn_xml_suffix(const GFilename&amp; filename) const @@ -1646,7 +1646,7 @@ std::string ctool::warn_xml_suffix(const GFilename&amp; filename) const
1646 1646
1647 // Warn if there are not enough energy bins 1647 // Warn if there are not enough energy bins
1648 if (suffix != ".xml") { 1648 if (suffix != ".xml") {
1649 - warning.append("\nWARNING: Name of observation definition output file " 1649 + warning.append("WARNING: Name of observation definition output file "
1650 "\""+filename+"\" does not terminate with \".xml\"." 1650 "\""+filename+"\" does not terminate with \".xml\"."
1651 "\n This is not an error, but may be misleading. " 1651 "\n This is not an error, but may be misleading. "
1652 "It is recommended to use the suffix" 1652 "It is recommended to use the suffix"
test/test_ctbin.py
@@ -194,15 +194,9 @@ class Test(test): @@ -194,15 +194,9 @@ class Test(test):
194 self.test_value(bin.cube().size(), 0, 194 self.test_value(bin.cube().size(), 0,
195 'Check that empty ctbin has an empty counts cube') 195 'Check that empty ctbin has an empty counts cube')
196 196
197 - # Prepare observation container for stacked analysis  
198 - cta = gammalib.GCTAObservation(self._events)  
199 - obs = gammalib.GObservations()  
200 - cta.id('0001')  
201 - obs.append(cta)  
202 - cta.id('0002')  
203 - obs.append(cta)  
204 - cta.id('0003')  
205 - obs.append(cta) 197 + # Prepare observation container for stacking of events into a
  198 + # single counts cube
  199 + obs = self._obs_events()
206 200
207 # Set-up ctbin using an observation container 201 # Set-up ctbin using an observation container
208 bin = ctools.ctbin(obs) 202 bin = ctools.ctbin(obs)
test/test_ctbkgcube.py
@@ -213,18 +213,8 @@ class Test(test): @@ -213,18 +213,8 @@ class Test(test):
213 self._check_cube(cpy_bkgcube.bkgcube(), nenergies=0) 213 self._check_cube(cpy_bkgcube.bkgcube(), nenergies=0)
214 self._check_models(cpy_bkgcube.models(), nmodels=0) 214 self._check_models(cpy_bkgcube.models(), nmodels=0)
215 215
216 - # Prepare observation container  
217 - obs1 = gammalib.GCTAObservation(self._events)  
218 - obs2 = gammalib.GCTAObservation(self._cntcube)  
219 - obs3 = gammalib.GLATObservation()  
220 - obs1.id('0001')  
221 - obs2.id('0002')  
222 - obs3.id('0001')  
223 - obs3.events(gammalib.GLATEventList())  
224 - obs = gammalib.GObservations()  
225 - obs.append(obs1)  
226 - obs.append(obs2)  
227 - obs.append(obs3) 216 + # Get mixel observation container
  217 + obs = self._obs_mixed()
228 obs.models(gammalib.GModels(self._model)) 218 obs.models(gammalib.GModels(self._model))
229 219
230 # Set-up ctbkgcube from observation container 220 # Set-up ctbkgcube from observation container
test/test_ctcubemask.py
@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # 19 #
20 # ========================================================================== 20 # ==========================================================================
  21 +import os
21 import gammalib 22 import gammalib
22 import ctools 23 import ctools
23 from testing import test 24 from testing import test
@@ -106,8 +107,24 @@ class Test(test): @@ -106,8 +107,24 @@ class Test(test):
106 """ 107 """
107 Test ctcubemask from Python 108 Test ctcubemask from Python
108 """ 109 """
109 - # Set-up ctcubemask 110 + # Allocate ctcubemask
110 mask = ctools.ctcubemask() 111 mask = ctools.ctcubemask()
  112 +
  113 + # Check that empty ctcubemask tool holds an empty observation
  114 + self._check_obs(mask.obs(), nobs=0)
  115 +
  116 + # Check that saving saves an empty counts cube
  117 + mask['outcube'] = 'ctcubemask_py0.fits'
  118 + mask['logfile'] = 'ctcubemask_py0.log'
  119 + mask.logFileOpen()
  120 + mask.save()
  121 + self.test_assert(not os.path.isfile('ctcubemask_py0.fits'),
  122 + 'Check that no counts cube has been created')
  123 +
  124 + # Check that clearing does not lead to an exception or segfault
  125 + mask.clear()
  126 +
  127 + # Now set ctcubemask parameters
111 mask['inobs'] = self._cntcube 128 mask['inobs'] = self._cntcube
112 mask['regfile'] = self._exclusion 129 mask['regfile'] = self._exclusion
113 mask['ra'] = 83.63 130 mask['ra'] = 83.63
@@ -127,14 +144,15 @@ class Test(test): @@ -127,14 +144,15 @@ class Test(test):
127 # Check result file 144 # Check result file
128 self._check_result_file('ctcubemask_py1.fits') 145 self._check_result_file('ctcubemask_py1.fits')
129 146
130 - # Set-up ctcubemask without exclusion regions 147 + # Set-up ctcubemask without exclusion regions but tighter energy
  148 + # selection
131 mask = ctools.ctcubemask() 149 mask = ctools.ctcubemask()
132 mask['inobs'] = self._cntcube 150 mask['inobs'] = self._cntcube
133 mask['regfile'] = 'NONE' 151 mask['regfile'] = 'NONE'
134 mask['ra'] = 83.63 152 mask['ra'] = 83.63
135 mask['dec'] = 22.01 153 mask['dec'] = 22.01
136 mask['rad'] = 3.0 154 mask['rad'] = 3.0
137 - mask['emin'] = 0.1 155 + mask['emin'] = 1.0
138 mask['emax'] = 100.0 156 mask['emax'] = 100.0
139 mask['outcube'] = 'ctcubemask_py2.fits' 157 mask['outcube'] = 'ctcubemask_py2.fits'
140 mask['logfile'] = 'ctcubemask_py2.log' 158 mask['logfile'] = 'ctcubemask_py2.log'
@@ -146,22 +164,54 @@ class Test(test): @@ -146,22 +164,54 @@ class Test(test):
146 mask.execute() 164 mask.execute()
147 165
148 # Check result file 166 # Check result file
149 - self._check_result_file('ctcubemask_py2.fits', events=5542) 167 + self._check_result_file('ctcubemask_py2.fits', events=573)
  168 +
  169 + # Copy ctcubemask tool
  170 + cpy_mask = mask.copy()
150 171
151 - # Copy ctcubemask tool and execute copy  
152 - cpy_mask = mask 172 + # Check that ctcubemask tool holds one observation
  173 + self._check_obs(cpy_mask.obs())
  174 +
  175 + # Execute copy of ctcubemask tool again, now with a higher chatter
  176 + # level than before
153 cpy_mask['outcube'] = 'ctcubemask_py3.fits' 177 cpy_mask['outcube'] = 'ctcubemask_py3.fits'
154 cpy_mask['logfile'] = 'ctcubemask_py3.log' 178 cpy_mask['logfile'] = 'ctcubemask_py3.log'
155 - cpy_mask['chatter'] = 4 179 + cpy_mask['chatter'] = 4
156 cpy_mask.execute() 180 cpy_mask.execute()
157 181
158 # Check result file 182 # Check result file
159 - self._check_result_file('ctcubemask_py3.fits', events=5542) 183 + self._check_result_file('ctcubemask_py3.fits', events=573)
160 184
161 # Clear ctcubemask tool 185 # Clear ctcubemask tool
162 - mask.clear() 186 + cpy_mask.clear()
163 187
164 - # TODO: Do some test after clearing 188 + # Check that empty ctcubemask tool holds an empty observation
  189 + self._check_obs(cpy_mask.obs(), nobs=0)
  190 +
  191 + # Prepare observation container
  192 + obs = self._obs_mixed()
  193 + obs.models(gammalib.GModels(self._model))
  194 +
  195 + # Set-up ctcubemask from observation container, don't perform any
  196 + # energy selection
  197 + mask = ctools.ctcubemask(obs)
  198 + mask['regfile'] = 'NONE'
  199 + mask['ra'] = 83.63
  200 + mask['dec'] = 22.01
  201 + mask['rad'] = 3.0
  202 + mask['emin'] = 'NONE'
  203 + mask['emax'] = 'NONE'
  204 + mask['outcube'] = 'ctcubemask_py4.xml'
  205 + mask['logfile'] = 'ctcubemask_py4.log'
  206 + mask['chatter'] = 3
  207 + mask['debug'] = True
  208 +
  209 + # Execute ctcubemask tool
  210 + mask.logFileOpen() # Make sure we get a log file
  211 + mask.execute()
  212 +
  213 + # Check result file
  214 + self._check_result_file('filtered_crab_cntmap.fits', events=5542)
165 215
166 # Return 216 # Return
167 return 217 return
@@ -180,3 +230,21 @@ class Test(test): @@ -180,3 +230,21 @@ class Test(test):
180 230
181 # Return 231 # Return
182 return 232 return
  233 +
  234 + # Check observation container
  235 + def _check_obs(self, obs, nobs=1):
  236 + """
  237 + Check observation container
  238 +
  239 + Parameters
  240 + ----------
  241 + obs : `~gammalib.GObservations`
  242 + Observation container
  243 + nobs : int, optional
  244 + Expected number of observations
  245 + """
  246 + # Check size of observation container
  247 + self.test_value(obs.size(), nobs, 'Check size of observation container')
  248 +
  249 + # Return
  250 + return
test/test_ctedispcube.py
@@ -185,6 +185,38 @@ class Test(test): @@ -185,6 +185,38 @@ class Test(test):
185 # cube 185 # cube
186 self._check_cube(cpy_edispcube.edispcube(), nenergies=0, nmigras=0) 186 self._check_cube(cpy_edispcube.edispcube(), nenergies=0, nmigras=0)
187 187
  188 + # Get mixed observation container
  189 + obs = self._obs_mixed()
  190 +
  191 + # Set-up ctedispcube from observation container
  192 + edispcube = ctools.ctedispcube(obs)
  193 + edispcube['incube'] = 'NONE'
  194 + edispcube['caldb'] = self._caldb
  195 + edispcube['irf'] = self._irf
  196 + edispcube['ebinalg'] = 'LOG'
  197 + edispcube['emin'] = 0.1
  198 + edispcube['emax'] = 100.0
  199 + edispcube['enumbins'] = 20
  200 + edispcube['nxpix'] = 10
  201 + edispcube['nypix'] = 10
  202 + edispcube['binsz'] = 0.4
  203 + edispcube['coordsys'] = 'CEL'
  204 + edispcube['proj'] = 'CAR'
  205 + edispcube['xref'] = 83.63
  206 + edispcube['yref'] = 22.01
  207 + edispcube['migramax'] = 2.0
  208 + edispcube['migrabins'] = 10
  209 + edispcube['outcube'] = 'ctedispcube_py3.fits'
  210 + edispcube['logfile'] = 'ctedispcube_py3.log'
  211 + edispcube['chatter'] = 4
  212 +
  213 + # Execute ctedispcube tool
  214 + edispcube.logFileOpen() # Make sure we get a log file
  215 + edispcube.execute()
  216 +
  217 + # Check result file
  218 + self._check_result_file('ctedispcube_py3.fits')
  219 +
188 # Return 220 # Return
189 return 221 return
190 222
test/test_ctexpcube.py
@@ -181,6 +181,36 @@ class Test(test): @@ -181,6 +181,36 @@ class Test(test):
181 # Check that the cleared copy has also cleared the exposure cube 181 # Check that the cleared copy has also cleared the exposure cube
182 self._check_cube(cpy_expcube.expcube(), nenergies=0) 182 self._check_cube(cpy_expcube.expcube(), nenergies=0)
183 183
  184 + # Get mixed observation container
  185 + obs = self._obs_mixed()
  186 +
  187 + # Set-up ctexpcube from observation container
  188 + expcube = ctools.ctexpcube(obs)
  189 + expcube['incube'] = 'NONE'
  190 + expcube['caldb'] = self._caldb
  191 + expcube['irf'] = self._irf
  192 + expcube['ebinalg'] = 'LOG'
  193 + expcube['emin'] = 0.1
  194 + expcube['emax'] = 100.0
  195 + expcube['enumbins'] = 20
  196 + expcube['nxpix'] = 200
  197 + expcube['nypix'] = 200
  198 + expcube['binsz'] = 0.02
  199 + expcube['coordsys'] = 'CEL'
  200 + expcube['proj'] = 'CAR'
  201 + expcube['xref'] = 83.63
  202 + expcube['yref'] = 22.01
  203 + expcube['logfile'] = 'ctexpcube_py3.log'
  204 + expcube['outcube'] = 'ctexpcube_py3.fits'
  205 + expcube['chatter'] = 4
  206 +
  207 + # Execute ctexpcube tool
  208 + expcube.logFileOpen() # Needed to get a new log file
  209 + expcube.execute()
  210 +
  211 + # Check result file
  212 + self._check_result_file('ctexpcube_py3.fits')
  213 +
184 # Return 214 # Return
185 return 215 return
186 216
test/test_ctpsfcube.py
@@ -131,7 +131,6 @@ class Test(test): @@ -131,7 +131,6 @@ class Test(test):
131 # Now set ctpsfcube parameters 131 # Now set ctpsfcube parameters
132 psfcube['inobs'] = self._events 132 psfcube['inobs'] = self._events
133 psfcube['incube'] = 'NONE' 133 psfcube['incube'] = 'NONE'
134 - psfcube['outcube'] = 'ctpsfcube_py1.fits'  
135 psfcube['caldb'] = self._caldb 134 psfcube['caldb'] = self._caldb
136 psfcube['irf'] = self._irf 135 psfcube['irf'] = self._irf
137 psfcube['ebinalg'] = 'LOG' 136 psfcube['ebinalg'] = 'LOG'
@@ -147,6 +146,7 @@ class Test(test): @@ -147,6 +146,7 @@ class Test(test):
147 psfcube['yref'] = 22.01 146 psfcube['yref'] = 22.01
148 psfcube['amax'] = 0.3 147 psfcube['amax'] = 0.3
149 psfcube['anumbins'] = 10 148 psfcube['anumbins'] = 10
  149 + psfcube['outcube'] = 'ctpsfcube_py1.fits'
150 psfcube['logfile'] = 'ctpsfcube_py1.log' 150 psfcube['logfile'] = 'ctpsfcube_py1.log'
151 psfcube['chatter'] = 2 151 psfcube['chatter'] = 2
152 152
@@ -184,6 +184,38 @@ class Test(test): @@ -184,6 +184,38 @@ class Test(test):
184 # Check that the cleared copy has also cleared the PSF cube 184 # Check that the cleared copy has also cleared the PSF cube
185 self._check_cube(cpy_psfcube.psfcube(), nenergies=0) 185 self._check_cube(cpy_psfcube.psfcube(), nenergies=0)
186 186
  187 + # Get mixed observation container
  188 + obs = self._obs_mixed()
  189 +
  190 + # Set-up ctpsfcube from observation container
  191 + psfcube = ctools.ctpsfcube(obs)
  192 + psfcube['incube'] = 'NONE'
  193 + psfcube['caldb'] = self._caldb
  194 + psfcube['irf'] = self._irf
  195 + psfcube['ebinalg'] = 'LOG'
  196 + psfcube['emin'] = 0.1
  197 + psfcube['emax'] = 100
  198 + psfcube['enumbins'] = 20
  199 + psfcube['nxpix'] = 10
  200 + psfcube['nypix'] = 10
  201 + psfcube['binsz'] = 0.4
  202 + psfcube['coordsys'] = 'CEL'
  203 + psfcube['proj'] = 'CAR'
  204 + psfcube['xref'] = 83.63
  205 + psfcube['yref'] = 22.01
  206 + psfcube['amax'] = 0.3
  207 + psfcube['anumbins'] = 10
  208 + psfcube['outcube'] = 'ctpsfcube_py3.fits'
  209 + psfcube['logfile'] = 'ctpsfcube_py3.log'
  210 + psfcube['chatter'] = 4
  211 +
  212 + # Execute ctpsfcube tool
  213 + psfcube.logFileOpen() # Make sure we get a log file
  214 + psfcube.execute()
  215 +
  216 + # Check result file
  217 + self._check_result_file('ctpsfcube_py3.fits')
  218 +
187 # Return 219 # Return
188 return 220 return
189 221
test/testing.py.in
@@ -97,3 +97,70 @@ class test(gammalib.GPythonTestSuite): @@ -97,3 +97,70 @@ class test(gammalib.GPythonTestSuite):
97 97
98 # Return return code 98 # Return return code
99 return rc 99 return rc
  100 +
  101 + # Return observation container with 3 identical event lists
  102 + def _obs_events(self):
  103 + """
  104 + Return observation container with 3 identical event lists
  105 +
  106 + Returns
  107 + -------
  108 + obs : `~gammalib.gammalib.GObservations`
  109 + Observations container
  110 + """
  111 + # Load CTA event list
  112 + cta = gammalib.GCTAObservation(self._events)
  113 +
  114 + # Allocate observation container
  115 + obs = gammalib.GObservations()
  116 +
  117 + # Append CTA observation with ID "0001"
  118 + cta.id('0001')
  119 + obs.append(cta)
  120 +
  121 + # Append CTA observation with ID "0002"
  122 + cta.id('0002')
  123 + obs.append(cta)
  124 +
  125 + # Append CTA observation with ID "0003"
  126 + cta.id('0003')
  127 + obs.append(cta)
  128 +
  129 + # Return observation container
  130 + return obs
  131 +
  132 + # Return observation container with event list, counts cube and LAT
  133 + # observation
  134 + def _obs_mixed(self):
  135 + """
  136 + Return observation container with event list, counts cube and LAT
  137 + observation
  138 +
  139 + Returns
  140 + -------
  141 + obs : `~gammalib.gammalib.GObservations`
  142 + Observations container
  143 + """
  144 + # Load CTA event list
  145 + obs1 = gammalib.GCTAObservation(self._events)
  146 + obs1.id('0001')
  147 +
  148 + # Load CTA counts cube
  149 + obs2 = gammalib.GCTAObservation(self._cntcube)
  150 + obs2.id('0002')
  151 +
  152 + # Create empty LAT observation
  153 + obs3 = gammalib.GLATObservation()
  154 + obs3.id('0001')
  155 + obs3.events(gammalib.GLATEventList())
  156 +
  157 + # Allocate observation container
  158 + obs = gammalib.GObservations()
  159 +
  160 + # Append observations to container
  161 + obs.append(obs1)
  162 + obs.append(obs2)
  163 + obs.append(obs3)
  164 +
  165 + # Return observation container
  166 + return obs