Commit a35f9317adc1b83917b16433b4aaa3bd2f60114a

Authored by Jürgen Knödlseder
1 parent 49530689

Enhance ctools code coverage (#1828)

ChangeLog
1 -2016-08-06 1 +2016-08-12
2 2
3 * Version 1.2.0 released 3 * Version 1.2.0 released
4 ======================== 4 ========================
5 5
  6 + Remove ctselect::time_reference() method
6 Add ctool and cscript pars() methods (#1838) 7 Add ctool and cscript pars() methods (#1838)
7 Fix ctbin::save() bug for empty observation container (#1835) 8 Fix ctbin::save() bug for empty observation container (#1835)
8 Fix exception when calling ctools clear() methods (#1835) 9 Fix exception when calling ctools clear() methods (#1835)
1 New Features and Important Changes in ctools 1.2.0 1 New Features and Important Changes in ctools 1.2.0
2 2
3 -6 August 2016 3 +12 August 2016
4 4
5 5
6 Introduction 6 Introduction
@@ -38,6 +38,9 @@ ctselect - CTA event selection @@ -38,6 +38,9 @@ ctselect - CTA event selection
38 The clear() method now calls GApplication::clear() to conserve the properties 38 The clear() method now calls GApplication::clear() to conserve the properties
39 of the tool (#1835). 39 of the tool (#1835).
40 40
  41 +The time_reference() method has been removed since the method is part of the
  42 +ctool base class, and exposed in Python as _time_reference().
  43 +
41 44
42 ctbin - CTA event binning 45 ctbin - CTA event binning
43 ------------------------- 46 -------------------------
README.md
1 ctools information 1 ctools information
2 ================== 2 ==================
3 -* Version: 1.2.0.dev1 (6 August 2016) 3 +* Version: 1.2.0.dev1 (12 August 2016)
4 * Author: Juergen Knoedlseder (jurgen.knodlseder@irap.omp.eu) 4 * Author: Juergen Knoedlseder (jurgen.knodlseder@irap.omp.eu)
5 * GammaLib dependency: 1.2.0.dev1 5 * GammaLib dependency: 1.2.0.dev1
6 6
pyext/Makefile.am
@@ -64,6 +64,7 @@ testscripts = ctools/tests/__init__.py \ @@ -64,6 +64,7 @@ testscripts = ctools/tests/__init__.py \
64 testdata = $(top_srcdir)/test/data/crab.xml \ 64 testdata = $(top_srcdir)/test/data/crab.xml \
65 $(top_srcdir)/test/data/crab_events.fits.gz \ 65 $(top_srcdir)/test/data/crab_events.fits.gz \
66 $(top_srcdir)/test/data/crab_cntmap.fits.gz \ 66 $(top_srcdir)/test/data/crab_cntmap.fits.gz \
  67 + $(top_srcdir)/test/data/invalid_event_list.fits.gz \
67 $(top_srcdir)/test/data/exclusion.reg 68 $(top_srcdir)/test/data/exclusion.reg
68 69
69 # Install test scripts and test data. Note that we don't need to prepend 70 # Install test scripts and test data. Note that we don't need to prepend
pyext/ctselect.i
@@ -44,11 +44,10 @@ public: @@ -44,11 +44,10 @@ public:
44 virtual ~ctselect(void); 44 virtual ~ctselect(void);
45 45
46 // Methods 46 // Methods
47 - void clear(void);  
48 - void run(void);  
49 - void save(void);  
50 - const GObservations& obs(void) const;  
51 - const GTimeReference& time_reference(void) const; 47 + void clear(void);
  48 + void run(void);
  49 + void save(void);
  50 + const GObservations& obs(void) const;
52 }; 51 };
53 52
54 53
src/ctbkgcube/ctbkgcube.cpp
@@ -246,20 +246,12 @@ void ctbkgcube::run(void) @@ -246,20 +246,12 @@ void ctbkgcube::run(void)
246 // Flag removal 246 // Flag removal
247 bool remove = true; 247 bool remove = true;
248 248
249 - // Do we have a CTA, HESS, MAGIC or VERITAS specific model?  
250 - if (m_bkgmdl[i]->is_valid("CTA", "") ||  
251 - m_bkgmdl[i]->is_valid("HESS", "") ||  
252 - m_bkgmdl[i]->is_valid("MAGIC", "") ||  
253 - m_bkgmdl[i]->is_valid("VERITAS", "")) {  
254 -  
255 - // Do we have a background model?  
256 - if (dynamic_cast<GModelData*>(m_bkgmdl[i]) != NULL) {  
257 -  
258 - // ... then keep model  
259 - remove = false;  
260 -  
261 - } // endif: had a background model  
262 - } // endif: had a CTA, HESS, MAGIC or VERITAS model 249 + // If we have a data space model with "GCTA" classname then we
  250 + // have a CTA background model and we want to keep the model
  251 + if ((dynamic_cast<GModelData*>(m_bkgmdl[i]) != NULL) &&
  252 + (m_bkgmdl[i]->classname().substr(0,4) == "GCTA")) {
  253 + remove = false;
  254 + }
263 255
264 // Log model removal or keeping 256 // Log model removal or keeping
265 std::string what = (remove) ? "Remove model" : "Keep model"; 257 std::string what = (remove) ? "Remove model" : "Keep model";
src/ctselect/ctselect.cpp
@@ -291,8 +291,8 @@ void ctselect::run(void) @@ -291,8 +291,8 @@ void ctselect::run(void)
291 // If we have an input file then check it 291 // If we have an input file then check it
292 if (!m_infiles[i].empty()) { 292 if (!m_infiles[i].empty()) {
293 std::string message = check_infile(m_infiles[i], m_evtname[i]); 293 std::string message = check_infile(m_infiles[i], m_evtname[i]);
294 - if (message.length() > 0) {  
295 - throw GException::app_error(G_RUN, message); 294 + if (!message.empty()) {
  295 + throw GException::invalid_value(G_RUN, message);
296 } 296 }
297 } 297 }
298 298
@@ -322,8 +322,8 @@ void ctselect::run(void) @@ -322,8 +322,8 @@ void ctselect::run(void)
322 // If we have a temporary file then check it 322 // If we have a temporary file then check it
323 if (!filename.empty()) { 323 if (!filename.empty()) {
324 std::string message = check_infile(filename, m_evtname[i]); 324 std::string message = check_infile(filename, m_evtname[i]);
325 - if (message.length() > 0) {  
326 - throw GException::app_error(G_RUN, message); 325 + if (!message.empty()) {
  326 + throw GException::invalid_value(G_RUN, message);
327 } 327 }
328 } 328 }
329 329
@@ -611,8 +611,9 @@ void ctselect::select_events(GCTAObservation* obs, @@ -611,8 +611,9 @@ void ctselect::select_events(GCTAObservation* obs,
611 // Write header into logger 611 // Write header into logger
612 log_header3(NORMAL, "Events selection"); 612 log_header3(NORMAL, "Events selection");
613 613
614 - // Initialise selection string 614 + // Initialise selection and addition strings
615 std::string selection; 615 std::string selection;
  616 + std::string add;
616 617
617 // Initialise selection flags 618 // Initialise selection flags
618 bool remove_all = false; 619 bool remove_all = false;
@@ -679,6 +680,7 @@ void ctselect::select_events(GCTAObservation* obs, @@ -679,6 +680,7 @@ void ctselect::select_events(GCTAObservation* obs,
679 sprintf(cmin, "%.8f", tmin); 680 sprintf(cmin, "%.8f", tmin);
680 sprintf(cmax, "%.8f", tmax); 681 sprintf(cmax, "%.8f", tmax);
681 selection = "TIME >= "+std::string(cmin)+" && TIME <= "+std::string(cmax); 682 selection = "TIME >= "+std::string(cmin)+" && TIME <= "+std::string(cmax);
  683 + add = " && ";
682 log_value(NORMAL, "Time range", 684 log_value(NORMAL, "Time range",
683 gammalib::str(tmin)+" - "+gammalib::str(tmax)+" s"); 685 gammalib::str(tmin)+" - "+gammalib::str(tmax)+" s");
684 686
@@ -687,11 +689,6 @@ void ctselect::select_events(GCTAObservation* obs, @@ -687,11 +689,6 @@ void ctselect::select_events(GCTAObservation* obs,
687 // Make energy selection 689 // Make energy selection
688 if (m_select_energy) { 690 if (m_select_energy) {
689 691
690 - // If we have aready a selection than add an "&&" operator  
691 - if (selection.length() > 0) {  
692 - selection += " && ";  
693 - }  
694 -  
695 // Log the requested energy selection 692 // Log the requested energy selection
696 if (logNormal()) { 693 if (logNormal()) {
697 log << gammalib::parformat("Selected energy range"); 694 log << gammalib::parformat("Selected energy range");
@@ -725,43 +722,40 @@ void ctselect::select_events(GCTAObservation* obs, @@ -725,43 +722,40 @@ void ctselect::select_events(GCTAObservation* obs,
725 char cmax[80]; 722 char cmax[80];
726 sprintf(cmin, "%.8f", emin); 723 sprintf(cmin, "%.8f", emin);
727 sprintf(cmax, "%.8f", emax); 724 sprintf(cmax, "%.8f", emax);
728 - selection += "ENERGY >= "+std::string(cmin)+" && ENERGY <= "+  
729 - std::string(cmax); 725 + selection += add + "ENERGY >= " + std::string(cmin)+
  726 + " && ENERGY <= " + std::string(cmax);
  727 + add = " && ";
730 } 728 }
731 } 729 }
732 else if (emin > 0.0) { 730 else if (emin > 0.0) {
733 char cmin[80]; 731 char cmin[80];
734 sprintf(cmin, "%.8f", emin); 732 sprintf(cmin, "%.8f", emin);
735 - selection += "ENERGY >= "+std::string(cmin); 733 + selection += add + "ENERGY >= " + std::string(cmin);
  734 + add = " && ";
736 } 735 }
737 else if (emax > 0.0) { 736 else if (emax > 0.0) {
738 char cmax[80]; 737 char cmax[80];
739 sprintf(cmax, "%.8f", emax); 738 sprintf(cmax, "%.8f", emax);
740 - selection += "ENERGY <= "+std::string(cmax); 739 + selection += add + "ENERGY <= " + std::string(cmax);
  740 + add = " && ";
741 } 741 }
742 else { 742 else {
743 - log << "None" << std::endl;  
744 remove_all = true; 743 remove_all = true;
745 } 744 }
746 745
747 } // endif: made energy selection 746 } // endif: made energy selection
748 747
749 - // Make ROI selection 748 + // Make RoI selection
750 if (m_select_roi) { 749 if (m_select_roi) {
751 750
752 - // If we have aready a selection than add an "&&" operator  
753 - if (selection.length() > 0) {  
754 - selection += " && ";  
755 - }  
756 -  
757 - // Log the requested ROI 751 + // Log the requested RoI
758 log_value(NORMAL, "Requested RoI", 752 log_value(NORMAL, "Requested RoI",
759 "Centre(RA,DEC)=("+gammalib::str(ra)+", "+ 753 "Centre(RA,DEC)=("+gammalib::str(ra)+", "+
760 gammalib::str(dec)+") deg, Radius="+gammalib::str(m_rad)+ 754 gammalib::str(dec)+") deg, Radius="+gammalib::str(m_rad)+
761 " deg"); 755 " deg");
762 756
763 - // If we have already an ROI then make sure that the selected  
764 - // ROI overlaps with the existing ROI 757 + // If we have already an RoI then make sure that the selected
  758 + // ROI overlaps with the existing RoI
765 double roi_radius = list->roi().radius(); 759 double roi_radius = list->roi().radius();
766 if (roi_radius > 0.0) { 760 if (roi_radius > 0.0) {
767 GSkyDir roi_centre = list->roi().centre().dir(); 761 GSkyDir roi_centre = list->roi().centre().dir();
@@ -777,7 +771,7 @@ void ctselect::select_events(GCTAObservation* obs, @@ -777,7 +771,7 @@ void ctselect::select_events(GCTAObservation* obs,
777 } 771 }
778 } 772 }
779 773
780 - // Log the selected ROI 774 + // Log the selected RoI
781 if (logNormal()) { 775 if (logNormal()) {
782 log << gammalib::parformat("Selected RoI"); 776 log << gammalib::parformat("Selected RoI");
783 if (rad <= 0.0) { 777 if (rad <= 0.0) {
@@ -790,29 +784,25 @@ void ctselect::select_events(GCTAObservation* obs, @@ -790,29 +784,25 @@ void ctselect::select_events(GCTAObservation* obs,
790 } 784 }
791 } 785 }
792 786
793 - // Format ROI selection 787 + // Format RoI selection
794 char cra[80]; 788 char cra[80];
795 char cdec[80]; 789 char cdec[80];
796 char crad[80]; 790 char crad[80];
797 sprintf(cra, "%.6f", ra); 791 sprintf(cra, "%.6f", ra);
798 sprintf(cdec, "%.6f", dec); 792 sprintf(cdec, "%.6f", dec);
799 sprintf(crad, "%.6f", rad); 793 sprintf(crad, "%.6f", rad);
800 - selection += "ANGSEP("+std::string(cra)+"," +  
801 - std::string(cdec)+",RA,DEC) <= " +  
802 - std::string(crad); 794 + selection += add + "ANGSEP("+std::string(cra)+"," +
  795 + std::string(cdec)+",RA,DEC) <= " +
  796 + std::string(crad);
  797 + add = " && ";
803 798
804 } // endif: made ROI selection 799 } // endif: made ROI selection
805 800
806 // Make an expression selection 801 // Make an expression selection
807 if (select_expr) { 802 if (select_expr) {
808 803
809 - // If we have aready a selection than add an "&&" operator  
810 - if (selection.length() > 0) {  
811 - selection += " && ";  
812 - }  
813 -  
814 // Append the expression 804 // Append the expression
815 - selection += "("+gammalib::strip_whitespace(m_expr)+")"; 805 + selection += add + "("+gammalib::strip_whitespace(m_expr)+")";
816 806
817 } // endif: made expression selection 807 } // endif: made expression selection
818 808
@@ -875,11 +865,10 @@ void ctselect::select_events(GCTAObservation* obs, @@ -875,11 +865,10 @@ void ctselect::select_events(GCTAObservation* obs,
875 GCTAInstDir instdir; 865 GCTAInstDir instdir;
876 instdir.dir().radec_deg(ra, dec); 866 instdir.dir().radec_deg(ra, dec);
877 list->roi(GCTARoi(instdir, rad)); 867 list->roi(GCTARoi(instdir, rad));
878 - } // endif: Roi selection was performed 868 + }
879 869
  870 + // ... otherwise restore old RoI information if it existed
880 else if (old_roi.is_valid()) { 871 else if (old_roi.is_valid()) {
881 - // Restore old RoI information in case no selection was performed  
882 - // and RoI was existing before  
883 list->roi(old_roi); 872 list->roi(old_roi);
884 } 873 }
885 874
@@ -891,11 +880,10 @@ void ctselect::select_events(GCTAObservation* obs, @@ -891,11 +880,10 @@ void ctselect::select_events(GCTAObservation* obs,
891 GEbounds ebounds; 880 GEbounds ebounds;
892 ebounds.append(GEnergy(emin, "TeV"), GEnergy(emax, "TeV")); 881 ebounds.append(GEnergy(emin, "TeV"), GEnergy(emax, "TeV"));
893 list->ebounds(ebounds); 882 list->ebounds(ebounds);
894 - } //endif: energy selection was performed 883 + }
895 884
  885 + // ... otherwise restore old Ebounds if they existed
896 else if (old_ebounds.size() > 0) { 886 else if (old_ebounds.size() > 0) {
897 - // Restore old Ebounds in case no energy selection was performed  
898 - // and observation already had valid Ebounds  
899 list->ebounds(old_ebounds); 887 list->ebounds(old_ebounds);
900 } 888 }
901 889
@@ -1342,65 +1330,60 @@ void ctselect::save_event_list(const GCTAObservation* obs, @@ -1342,65 +1330,60 @@ void ctselect::save_event_list(const GCTAObservation* obs,
1342 const std::string& gtiname, 1330 const std::string& gtiname,
1343 const std::string& outfile) const 1331 const std::string& outfile) const
1344 { 1332 {
1345 - // Save only if observation is valid  
1346 - if (obs != NULL) {  
1347 -  
1348 - // Save only if we have an event list  
1349 - if (obs->eventtype() == "EventList") {  
1350 -  
1351 - // Set output FITS file event extension names  
1352 - GFilename outname(outfile);  
1353 - std::string outevt = evtname;  
1354 - std::string outgti = gtiname;  
1355 - if (outname.has_extname()) {  
1356 - std::vector<std::string> extnames =  
1357 - gammalib::split(outname.extname(), ";");  
1358 - if (extnames.size() > 0) {  
1359 - std::string extname = gammalib::strip_whitespace(extnames[0]);  
1360 - if (!extname.empty()) {  
1361 - outevt = extname;  
1362 - }  
1363 - }  
1364 - if (extnames.size() > 1) {  
1365 - std::string extname = gammalib::strip_whitespace(extnames[1]);  
1366 - if (!extname.empty()) {  
1367 - outgti = extname;  
1368 - } 1333 + // Save only if we have an event list
  1334 + if (obs->eventtype() == "EventList") {
  1335 +
  1336 + // Set output FITS file event extension names
  1337 + GFilename outname(outfile);
  1338 + std::string outevt = evtname;
  1339 + std::string outgti = gtiname;
  1340 + if (outname.has_extname()) {
  1341 + std::vector<std::string> extnames =
  1342 + gammalib::split(outname.extname(), ";");
  1343 + if (extnames.size() > 0) {
  1344 + std::string extname = gammalib::strip_whitespace(extnames[0]);
  1345 + if (!extname.empty()) {
  1346 + outevt = extname;
1369 } 1347 }
1370 } 1348 }
1371 -  
1372 - // Create output FITS file  
1373 - GFits outfits;  
1374 -  
1375 - // Write observation into FITS file  
1376 - obs->write(outfits, outevt, outgti);  
1377 -  
1378 - // Copy all extensions other than evtname and gtiname extensions  
1379 - // from the input to the output event list. The evtname and  
1380 - // gtiname extensions are written by the save method, all others  
1381 - // that may eventually be present have to be copied over  
1382 - // explicitly.  
1383 - GFits infits(infile);  
1384 - for (int extno = 1; extno < infits.size(); ++extno) {  
1385 - GFitsHDU* hdu = infits.at(extno);  
1386 - if (hdu->extname() != evtname &&  
1387 - hdu->extname() != gtiname &&  
1388 - hdu->extname() != outevt &&  
1389 - hdu->extname() != outgti) {  
1390 - outfits.append(*hdu); 1349 + if (extnames.size() > 1) {
  1350 + std::string extname = gammalib::strip_whitespace(extnames[1]);
  1351 + if (!extname.empty()) {
  1352 + outgti = extname;
1391 } 1353 }
1392 } 1354 }
  1355 + }
1393 1356
1394 - // Close input file  
1395 - infits.close(); 1357 + // Create output FITS file
  1358 + GFits outfits;
  1359 +
  1360 + // Write observation into FITS file
  1361 + obs->write(outfits, outevt, outgti);
  1362 +
  1363 + // Copy all extensions other than evtname and gtiname extensions
  1364 + // from the input to the output event list. The evtname and
  1365 + // gtiname extensions are written by the save method, all others
  1366 + // that may eventually be present have to be copied over
  1367 + // explicitly.
  1368 + GFits infits(infile);
  1369 + for (int extno = 1; extno < infits.size(); ++extno) {
  1370 + GFitsHDU* hdu = infits.at(extno);
  1371 + if (hdu->extname() != evtname &&
  1372 + hdu->extname() != gtiname &&
  1373 + hdu->extname() != outevt &&
  1374 + hdu->extname() != outgti) {
  1375 + outfits.append(*hdu);
  1376 + }
  1377 + }
1396 1378
1397 - // Save file to disk and close it (we need both operations)  
1398 - outfits.saveto(outname.url(), clobber());  
1399 - outfits.close(); 1379 + // Close input file
  1380 + infits.close();
1400 1381
1401 - } // endif: observation was unbinned 1382 + // Save file to disk and close it (we need both operations)
  1383 + outfits.saveto(outname.url(), clobber());
  1384 + outfits.close();
1402 1385
1403 - } // endif: observation was valid 1386 + } // endif: observation was unbinned
1404 1387
1405 // Return 1388 // Return
1406 return; 1389 return;
src/ctselect/ctselect.hpp
@@ -62,7 +62,6 @@ public: @@ -62,7 +62,6 @@ public:
62 void run(void); 62 void run(void);
63 void save(void); 63 void save(void);
64 const GObservations& obs(void) const; 64 const GObservations& obs(void) const;
65 - const GTimeReference& time_reference(void) const;  
66 65
67 protected: 66 protected:
68 // Protected methods 67 // Protected methods
@@ -128,16 +127,4 @@ const GObservations&amp; ctselect::obs(void) const @@ -128,16 +127,4 @@ const GObservations&amp; ctselect::obs(void) const
128 return m_obs; 127 return m_obs;
129 } 128 }
130 129
131 -  
132 -/***********************************************************************//**  
133 - * @brief Return CTA time reference  
134 - *  
135 - * @return CTA time reference  
136 - ***************************************************************************/  
137 -inline  
138 -const GTimeReference& ctselect::time_reference(void) const  
139 -{  
140 - return m_cta_ref;  
141 -}  
142 -  
143 #endif /* CTSELECT_HPP */ 130 #endif /* CTSELECT_HPP */
src/cttsmap/cttsmap.cpp
@@ -234,7 +234,7 @@ void cttsmap::run(void) @@ -234,7 +234,7 @@ void cttsmap::run(void)
234 234
235 // Initialise optimizer 235 // Initialise optimizer
236 GOptimizerLM* opt = (logExplicit()) ? new GOptimizerLM(&log) 236 GOptimizerLM* opt = (logExplicit()) ? new GOptimizerLM(&log)
237 - : new GOptimizerLM(); 237 + : new GOptimizerLM();
238 238
239 // Store initial models 239 // Store initial models
240 GModels models_orig = m_obs.models(); 240 GModels models_orig = m_obs.models();
@@ -246,15 +246,15 @@ void cttsmap::run(void) @@ -246,15 +246,15 @@ void cttsmap::run(void)
246 models.remove(m_srcname); 246 models.remove(m_srcname);
247 247
248 // Get likelihood of null hypothesis if not given before 248 // Get likelihood of null hypothesis if not given before
249 - if (m_logL0 == 0.0) { 249 + if (m_logL0 == 0.0) {
250 250
251 // Write header 251 // Write header
252 log_header1(TERSE, "Compute NULL Hypothesis for TS computation"); 252 log_header1(TERSE, "Compute NULL Hypothesis for TS computation");
253 253
254 - // Compute likelihood without the test source  
255 - m_obs.models(models);  
256 - m_obs.optimize(*opt);  
257 - m_logL0 = -(opt->value()); 254 + // Compute likelihood without the test source
  255 + m_obs.models(models);
  256 + m_obs.optimize(*opt);
  257 + m_logL0 = -(opt->value());
258 258
259 } 259 }
260 260
@@ -272,11 +272,9 @@ void cttsmap::run(void) @@ -272,11 +272,9 @@ void cttsmap::run(void)
272 " at "+bincentre.print()); 272 " at "+bincentre.print());
273 273
274 // Add test source at current bin position 274 // Add test source at current bin position
275 - if (m_testsource != NULL) {  
276 - (*m_testsource)["RA"].value(bincentre.ra_deg());  
277 - (*m_testsource)["DEC"].value(bincentre.dec_deg());  
278 - models.append(*m_testsource);  
279 - } 275 + (*m_testsource)["RA"].value(bincentre.ra_deg());
  276 + (*m_testsource)["DEC"].value(bincentre.dec_deg());
  277 + models.append(*m_testsource);
280 278
281 // Assign models to observations 279 // Assign models to observations
282 m_obs.models(models); 280 m_obs.models(models);
@@ -292,16 +290,11 @@ void cttsmap::run(void) @@ -292,16 +290,11 @@ void cttsmap::run(void)
292 290
293 // Log information 291 // Log information
294 if (logExplicit()) { 292 if (logExplicit()) {
295 - log << " TS value ....: ";  
296 - log << ts << std::endl; 293 + log_value(EXPLICIT, "TS value", ts);
297 } 294 }
298 - else if (logTerse()) {  
299 - log << "TS for bin number ";  
300 - log << i;  
301 - log << " at ";  
302 - log << bincentre.print();  
303 - log << ": ";  
304 - log << ts << std::endl; 295 + else if (logNormal()) {
  296 + log_value(NORMAL, "TS value (bin "+gammalib::str(i)+")",
  297 + gammalib::str(ts)+" ("+bincentre.print()+")");
305 } 298 }
306 299
307 // Get test source model instance 300 // Get test source model instance
@@ -312,11 +305,9 @@ void cttsmap::run(void) @@ -312,11 +305,9 @@ void cttsmap::run(void)
312 m_tsmap(i) = ts; 305 m_tsmap(i) = ts;
313 306
314 // Extract fitted test source parameters 307 // Extract fitted test source parameters
315 - if (m_testsource != NULL) {  
316 - for (int j = 0; j < m_mapnames.size(); ++j) {  
317 - m_maps[j](i) = (*testsource)[m_mapnames[j]].value();  
318 - }  
319 - } 308 + for (int j = 0; j < m_mapnames.size(); ++j) {
  309 + m_maps[j](i) = (*testsource)[m_mapnames[j]].value();
  310 + }
320 311
321 // Set status of bin to true 312 // Set status of bin to true
322 m_statusmap(i) = 1.0; 313 m_statusmap(i) = 1.0;
@@ -479,7 +470,8 @@ void cttsmap::copy_members(const cttsmap&amp; app) @@ -479,7 +470,8 @@ void cttsmap::copy_members(const cttsmap&amp; app)
479 m_statusmap = app.m_statusmap; 470 m_statusmap = app.m_statusmap;
480 471
481 // Clone protected members 472 // Clone protected members
482 - m_testsource = (app.m_testsource != NULL) ? app.m_testsource->clone() : NULL; 473 + m_testsource = (app.m_testsource != NULL) ? app.m_testsource->clone()
  474 + : NULL;
483 475
484 // Return 476 // Return
485 return; 477 return;
@@ -491,6 +483,12 @@ void cttsmap::copy_members(const cttsmap&amp; app) @@ -491,6 +483,12 @@ void cttsmap::copy_members(const cttsmap&amp; app)
491 ***************************************************************************/ 483 ***************************************************************************/
492 void cttsmap::free_members(void) 484 void cttsmap::free_members(void)
493 { 485 {
  486 + // Free test source
  487 + if (m_testsource != NULL) {
  488 + delete m_testsource;
  489 + m_testsource = NULL;
  490 + }
  491 +
494 // Return 492 // Return
495 return; 493 return;
496 } 494 }
@@ -519,26 +517,24 @@ void cttsmap::get_parameters(void) @@ -519,26 +517,24 @@ void cttsmap::get_parameters(void)
519 // Get name of test source 517 // Get name of test source
520 m_srcname = (*this)["srcname"].string(); 518 m_srcname = (*this)["srcname"].string();
521 519
522 - // Get Model and store it as protected member 520 + // Get model and store it as protected member. Note that the clone
  521 + // method will never return a NULL pointer, hence we do not need
  522 + // to check the pointer.
523 m_testsource = m_obs.models()[m_srcname]->clone(); 523 m_testsource = m_obs.models()[m_srcname]->clone();
524 524
525 // Check if model has RA and DEC parameters which are necessary to 525 // Check if model has RA and DEC parameters which are necessary to
526 // continue 526 // continue
527 - if (m_testsource != NULL) {  
528 - if (!m_testsource->has_par("RA") || !m_testsource->has_par("DEC")) {  
529 - std::string msg = "Source \""+m_srcname+"\" has no \"RA\" and "  
530 - "\"DEC\" parameters. Only sources with \"RA\" "  
531 - " and \"DEC\" parameters can be used as test "  
532 - "sources.";  
533 - throw GException::invalid_value(G_GET_PARAMETERS, msg);  
534 - } 527 + if (!m_testsource->has_par("RA") || !m_testsource->has_par("DEC")) {
  528 + std::string msg = "Source \""+m_srcname+"\" has no \"RA\" and "
  529 + "\"DEC\" parameters. Only sources with \"RA\" "
  530 + "and \"DEC\" parameters can be used as test "
  531 + "sources.";
  532 + throw GException::invalid_value(G_GET_PARAMETERS, msg);
535 } 533 }
536 534
537 // Fix the spatial parameters of the test source 535 // Fix the spatial parameters of the test source
538 - if (m_testsource != NULL) {  
539 - (*m_testsource)["RA"].fix();  
540 - (*m_testsource)["DEC"].fix();  
541 - } 536 + (*m_testsource)["RA"].fix();
  537 + (*m_testsource)["DEC"].fix();
542 538
543 // Create sky map based on task parameters 539 // Create sky map based on task parameters
544 GSkyMap map = create_map(m_obs); 540 GSkyMap map = create_map(m_obs);
@@ -583,32 +579,27 @@ void cttsmap::init_maps(const GSkyMap&amp; map) @@ -583,32 +579,27 @@ void cttsmap::init_maps(const GSkyMap&amp; map)
583 m_tsmap = GSkyMap(map); 579 m_tsmap = GSkyMap(map);
584 580
585 // Initialise map information 581 // Initialise map information
586 - m_statusmap.clear();  
587 -  
588 - // Create status map  
589 - m_statusmap = GSkyMap(map);  
590 -  
591 - // Initialise maps of free parameters  
592 - if (m_testsource != NULL) { 582 + m_statusmap.clear();
593 583
594 - // Loop over all model parameters  
595 - for (int i = 0; i < m_testsource->size(); i++) {  
596 -  
597 - // Skip fixed parameters  
598 - if ((*m_testsource)[i].is_fixed()) {  
599 - continue;  
600 - } 584 + // Create status map
  585 + m_statusmap = GSkyMap(map);
601 586
602 - // Add sky map for free parameters. Note that push_back will  
603 - // create a copy.  
604 - m_maps.push_back(map); 587 + // Loop over all model parameters
  588 + for (int i = 0; i < m_testsource->size(); i++) {
  589 +
  590 + // Skip fixed parameters
  591 + if ((*m_testsource)[i].is_fixed()) {
  592 + continue;
  593 + }
605 594
606 - // Store parameter name  
607 - m_mapnames.push_back((*m_testsource)[i].name());  
608 -  
609 - } // endfor: looped over all model parameters 595 + // Add sky map for free parameters. Note that push_back will
  596 + // create a copy.
  597 + m_maps.push_back(map);
610 598
611 - } // endif: test source was valid 599 + // Store parameter name
  600 + m_mapnames.push_back((*m_testsource)[i].name());
  601 +
  602 + } // endfor: looped over all model parameters
612 603
613 // Return 604 // Return
614 return; 605 return;
src/ctulimit/ctulimit.cpp
@@ -618,10 +618,10 @@ void ctulimit::ulimit_bisection(const double&amp; min, const double&amp; max) @@ -618,10 +618,10 @@ void ctulimit::ulimit_bisection(const double&amp; min, const double&amp; max)
618 618
619 // Change boundaries for further iteration 619 // Change boundaries for further iteration
620 if (eval_mid > 0.0) { 620 if (eval_mid > 0.0) {
621 - wrk_max = mid; 621 + wrk_max = mid; // logL too large, new range = [wrk_min, mid]
622 } 622 }
623 - else if (eval_mid < 0.0) {  
624 - wrk_min = mid; 623 + else {
  624 + wrk_min = mid; // logL too small, new range = [mid, wrk_max]
625 } 625 }
626 626
627 // Increment counter 627 // Increment counter
@@ -672,7 +672,7 @@ double ctulimit::evaluate(const double&amp; value) @@ -672,7 +672,7 @@ double ctulimit::evaluate(const double&amp; value)
672 else { 672 else {
673 std::string msg = "Value of parameter \""+m_model_par->name()+"\" " 673 std::string msg = "Value of parameter \""+m_model_par->name()+"\" "
674 "outside of validity range requested. To omit " 674 "outside of validity range requested. To omit "
675 - "this error please enlarge the parameter range " 675 + "this error please enlarge the parameter range "
676 "in the model XML file."; 676 "in the model XML file.";
677 throw GException::invalid_value(G_EVALUATE, msg); 677 throw GException::invalid_value(G_EVALUATE, msg);
678 } 678 }
test/data/invalid_event_list.fits.gz 0 → 100644
No preview for this file type
test/test_ctselect.py
@@ -39,6 +39,9 @@ class Test(test): @@ -39,6 +39,9 @@ class Test(test):
39 # Call base class constructor 39 # Call base class constructor
40 test.__init__(self) 40 test.__init__(self)
41 41
  42 + # Set test data
  43 + self._invalid_events = self._datadir + '/invalid_event_list.fits'
  44 +
42 # Return 45 # Return
43 return 46 return
44 47
@@ -104,7 +107,7 @@ class Test(test): @@ -104,7 +107,7 @@ class Test(test):
104 """ 107 """
105 Test ctselect from Python 108 Test ctselect from Python
106 """ 109 """
107 - # Allocate ctselect 110 + # Allocate empty ctselect tool
108 select = ctools.ctselect() 111 select = ctools.ctselect()
109 112
110 # Check that empty ctselect tool holds an empty observation 113 # Check that empty ctselect tool holds an empty observation
@@ -122,7 +125,6 @@ class Test(test): @@ -122,7 +125,6 @@ class Test(test):
122 select.clear() 125 select.clear()
123 126
124 # Now set ctselect parameters 127 # Now set ctselect parameters
125 - select = ctools.ctselect()  
126 select['inobs'] = self._events 128 select['inobs'] = self._events
127 select['ra'] = 83.63 129 select['ra'] = 83.63
128 select['dec'] = 22.01 130 select['dec'] = 22.01
@@ -130,7 +132,7 @@ class Test(test): @@ -130,7 +132,7 @@ class Test(test):
130 select['tmin'] = 0 132 select['tmin'] = 0
131 select['tmax'] = 1800 133 select['tmax'] = 1800
132 select['emin'] = 0.1 134 select['emin'] = 0.1
133 - select['emax'] = 100 135 + select['emax'] = 100.0
134 select['outobs'] = 'ctselect_py1.fits' 136 select['outobs'] = 'ctselect_py1.fits'
135 select['logfile'] = 'ctselect_py1.log' 137 select['logfile'] = 'ctselect_py1.log'
136 select['chatter'] = 2 138 select['chatter'] = 2
@@ -166,7 +168,6 @@ class Test(test): @@ -166,7 +168,6 @@ class Test(test):
166 168
167 # Check result file 169 # Check result file
168 self._check_result_file('ctselect_py2.fits') 170 self._check_result_file('ctselect_py2.fits')
169 - print('Step3')  
170 171
171 # Execute again the copy of ctselect tool again, now using the pointing 172 # Execute again the copy of ctselect tool again, now using the pointing
172 # information in the input observation 173 # information in the input observation
@@ -186,19 +187,75 @@ class Test(test): @@ -186,19 +187,75 @@ class Test(test):
186 # Check that cleared ctselect tool holds no observations and events 187 # Check that cleared ctselect tool holds no observations and events
187 self._check_obs(cpy_select.obs(), nobs=0) 188 self._check_obs(cpy_select.obs(), nobs=0)
188 189
  190 + # Get mixed observation container
  191 + obs = self._obs_mixed()
  192 +
  193 + # Now setup ctselect tool from observation container. We make an
  194 + # event selection that will result in zero events in the file.
  195 + select = ctools.ctselect(obs)
  196 + select['ra'] = 83.63
  197 + select['dec'] = 22.01
  198 + select['rad'] = 3.0
  199 + select['tmin'] = 0
  200 + select['tmax'] = 1800
  201 + select['emin'] = 120.0
  202 + select['emax'] = 130.0
  203 + select['expr'] = 'DETX == 0'
  204 + select['outobs'] = 'ctselect_py4.fits'
  205 + select['logfile'] = 'ctselect_py4.log'
  206 + select['chatter'] = 3
  207 +
  208 + # Execute tool
  209 + select.logFileOpen() # Needed to get a new log file
  210 + select.execute()
  211 +
  212 + # Check result file
  213 + self._check_result_file('ctselect_py4.fits', nevents=0)
  214 +
  215 + # Setup ctselect tool for an invalid event file
  216 + select = ctools.ctselect()
  217 + select['inobs'] = self._invalid_events
  218 + select['ra'] = 83.63
  219 + select['dec'] = 22.01
  220 + select['rad'] = 3
  221 + select['tmin'] = 0
  222 + select['tmax'] = 1800
  223 + select['emin'] = 0.1
  224 + select['emax'] = 100.0
  225 + select['outobs'] = 'ctselect_py5.fits'
  226 + select['logfile'] = 'ctselect_py5.log'
  227 + select['chatter'] = 3
  228 +
  229 + # Execute tool
  230 + select.logFileOpen() # Needed to get a new log file
  231 + self.test_try('Test invalid event file')
  232 + try:
  233 + select.execute()
  234 + self.test_try_failure('Exception not thrown')
  235 + except ValueError:
  236 + self.test_try_success()
  237 +
  238 +
189 # Return 239 # Return
190 return 240 return
191 241
192 # Check result file 242 # Check result file
193 - def _check_result_file(self, filename): 243 + def _check_result_file(self, filename, nevents=6127):
194 """ 244 """
195 Check result file 245 Check result file
  246 +
  247 + Parameters
  248 + ----------
  249 + filename : str
  250 + Event list file name
  251 + nevents : int, optional
  252 + Expected number of events
196 """ 253 """
197 # Open result file 254 # Open result file
198 events = gammalib.GCTAEventList(filename) 255 events = gammalib.GCTAEventList(filename)
199 256
200 # Check event list 257 # Check event list
201 - self._check_events(events, nevents=6127) 258 + self._check_events(events, nevents=nevents)
202 259
203 # Return 260 # Return
204 return 261 return
test/test_cttsmap.py
1 #! /usr/bin/env python 1 #! /usr/bin/env python
2 # ========================================================================== 2 # ==========================================================================
3 -# This scripts performs unit tests for the cttsmap tool. 3 +# This scripts performs unit tests for the cttsmap tool
4 # 4 #
5 # Copyright (C) 2014-2016 Juergen Knoedlseder 5 # Copyright (C) 2014-2016 Juergen Knoedlseder
6 # 6 #
@@ -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
@@ -105,14 +106,31 @@ class Test(test): @@ -105,14 +106,31 @@ class Test(test):
105 """ 106 """
106 Test cttsmap from Python 107 Test cttsmap from Python
107 """ 108 """
108 - # Set-up cttsmap 109 + # Allocate empty cttsmap tool
109 tsmap = ctools.cttsmap() 110 tsmap = ctools.cttsmap()
  111 +
  112 + # Check that empty cttsmap tool holds an empty observation and an
  113 + # empty TS map
  114 + self._check_obs(tsmap.obs(), nobs=0)
  115 + self._check_ts_map(tsmap.tsmap(), nx=0, ny=0)
  116 +
  117 + # Check that saving does not nothing
  118 + tsmap['outmap'] = 'cttsmap_py0.fits'
  119 + tsmap['logfile'] = 'cttsmap_py0.log'
  120 + tsmap.logFileOpen()
  121 + tsmap.save()
  122 + self.test_assert(not os.path.isfile('cttsmap_py0.fits'),
  123 + 'Check that no TS map has been created')
  124 +
  125 + # Check that clearing does not lead to an exception or segfault
  126 + tsmap.clear()
  127 +
  128 + # Now set cttsmap parameters
110 tsmap['inobs'] = self._events 129 tsmap['inobs'] = self._events
111 tsmap['inmodel'] = self._model 130 tsmap['inmodel'] = self._model
112 tsmap['srcname'] = 'Crab' 131 tsmap['srcname'] = 'Crab'
113 tsmap['caldb'] = self._caldb 132 tsmap['caldb'] = self._caldb
114 tsmap['irf'] = self._irf 133 tsmap['irf'] = self._irf
115 - tsmap['outmap'] = 'cttsmap_py1.fits'  
116 tsmap['nxpix'] = 3 134 tsmap['nxpix'] = 3
117 tsmap['nypix'] = 3 135 tsmap['nypix'] = 3
118 tsmap['binsz'] = 0.02 136 tsmap['binsz'] = 0.02
@@ -120,6 +138,7 @@ class Test(test): @@ -120,6 +138,7 @@ class Test(test):
120 tsmap['proj'] = 'CAR' 138 tsmap['proj'] = 'CAR'
121 tsmap['xref'] = 83.63 139 tsmap['xref'] = 83.63
122 tsmap['yref'] = 22.01 140 tsmap['yref'] = 22.01
  141 + tsmap['outmap'] = 'cttsmap_py1.fits'
123 tsmap['logfile'] = 'cttsmap_py1.log' 142 tsmap['logfile'] = 'cttsmap_py1.log'
124 tsmap['chatter'] = 2 143 tsmap['chatter'] = 2
125 144
@@ -131,32 +150,116 @@ class Test(test): @@ -131,32 +150,116 @@ class Test(test):
131 # Check result file 150 # Check result file
132 self._check_result_file('cttsmap_py1.fits') 151 self._check_result_file('cttsmap_py1.fits')
133 152
  153 + # Copy cttsmap tool
  154 + cpy_tsmap = tsmap.copy()
  155 +
  156 + # Check observation container and TS map of copy
  157 + self._check_obs(cpy_tsmap.obs())
  158 + self._check_ts_map(cpy_tsmap.tsmap())
  159 +
  160 + # Execute copy of cttsmap tool again, now with a higher chatter
  161 + # level than before
  162 + cpy_tsmap['binmin'] = 0
  163 + cpy_tsmap['binmax'] = 1
  164 + cpy_tsmap['outmap'] = 'cttsmap_py2.fits'
  165 + cpy_tsmap['logfile'] = 'cttsmap_py2.log'
  166 + cpy_tsmap['chatter'] = 3
  167 + cpy_tsmap['publish'] = True
  168 + cpy_tsmap.logFileOpen() # Needed to get a new log file
  169 + cpy_tsmap.execute()
  170 +
  171 + # Check result file
  172 + self._check_result_file('cttsmap_py2.fits')
  173 +
  174 + # Now clear copy of cttsmap tool
  175 + cpy_tsmap.clear()
  176 +
  177 + # Check that the cleared copy has also cleared the observation
  178 + # container and TS map
  179 + self._check_obs(cpy_tsmap.obs(), nobs=0)
  180 + self._check_ts_map(cpy_tsmap.tsmap(), nx=0, ny=0)
  181 +
134 # Return 182 # Return
135 return 183 return
136 184
137 # Check result file 185 # Check result file
138 - def _check_result_file(self, filename): 186 + def _check_result_file(self, filename, nx=3, ny=3):
139 """ 187 """
140 Check result file 188 Check result file
  189 +
  190 + Parameters
  191 + ----------
  192 + filename : str
  193 + TS map file name
  194 + nx : int, optional
  195 + Number of X pixels
  196 + ny : int, optional
  197 + Number of Y pixels
141 """ 198 """
142 # Open result file 199 # Open result file
143 fits = gammalib.GFits(filename) 200 fits = gammalib.GFits(filename)
144 201
145 # Get HDUs 202 # Get HDUs
146 - ts = fits['Primary']  
147 - prefactor = fits['Prefactor']  
148 - index = fits['Index'] 203 + ts = fits['Primary']
  204 + pre = fits['Prefactor']
  205 + index = fits['Index']
149 206
150 # Check dimensions 207 # Check dimensions
151 - self.test_value(ts.naxis(), 2, 'Check for 2 dimensions')  
152 - self.test_value(ts.naxes(0), 3, 'Check for 3 pixels in X')  
153 - self.test_value(ts.naxes(1), 3, 'Check for 3 pixels in Y')  
154 - self.test_value(prefactor.naxis(), 2, 'Check for 2 dimensions')  
155 - self.test_value(prefactor.naxes(0), 3, 'Check for 3 pixels in X')  
156 - self.test_value(prefactor.naxes(1), 3, 'Check for 3 pixels in Y')  
157 - self.test_value(index.naxis(), 2, 'Check for 2 dimensions')  
158 - self.test_value(index.naxes(0), 3, 'Check for 3 pixels in X')  
159 - self.test_value(index.naxes(1), 3, 'Check for 3 pixels in Y') 208 + self.test_value(ts.naxis(), 2, 'Check for TS map dimensions')
  209 + self.test_value(ts.naxes(0), nx, 'Check for TS map pixels in X')
  210 + self.test_value(ts.naxes(1), ny, 'Check for TS map pixels in Y')
  211 + self.test_value(pre.naxis(), 2, 'Check for Prefactor map dimensions')
  212 + self.test_value(pre.naxes(0), nx, 'Check for Prefactor map pixels in X')
  213 + self.test_value(pre.naxes(1), ny, 'Check for Prefactor map pixels in Y')
  214 + self.test_value(index.naxis(), 2, 'Check for Index map dimensions')
  215 + self.test_value(index.naxes(0), nx, 'Check for Index map pixels in X')
  216 + self.test_value(index.naxes(1), ny, 'Check for Index map pixels in Y')
  217 +
  218 + # Return
  219 + return
  220 +
  221 + # Check observation
  222 + def _check_obs(self, obs, nobs=1):
  223 + """
  224 + Check observation
  225 +
  226 + Parameters
  227 + ----------
  228 + obs : `~gammalib.GObservations`
  229 + Models
  230 + nobs : int, optional
  231 + Expected number of observations
  232 + """
  233 + # Check number of observations
  234 + self.test_value(obs.size(), nobs, 'Check number of observations')
  235 +
  236 + # Return
  237 + return
  238 +
  239 + # Check TS map
  240 + def _check_ts_map(self, tsmap, nx=3, ny=3):
  241 + """
  242 + Check TS map
  243 +
  244 + Parameters
  245 + ----------
  246 + tsmap : `~gammalib.GSkyMap`
  247 + TS map
  248 + nx : int, optional
  249 + Number of X pixels
  250 + ny : int, optional
  251 + Number of Y pixels
  252 + """
  253 + # Determine number of maps
  254 + if nx > 0 and ny > 0:
  255 + nmaps = 1
  256 + else:
  257 + nmaps = 0
  258 +
  259 + # Check dimensions
  260 + self.test_value(tsmap.nmaps(), nmaps, 'Check number of maps')
  261 + self.test_value(tsmap.nx(), nx, 'Check for number of X pixels')
  262 + self.test_value(tsmap.ny(), ny, 'Check for number of Y pixels')
160 263
161 # Return 264 # Return
162 return 265 return
test/test_ctulimit.py
@@ -118,7 +118,6 @@ class Test(test): @@ -118,7 +118,6 @@ class Test(test):
118 ulimit.clear() 118 ulimit.clear()
119 119
120 # Now set ctulimit parameters 120 # Now set ctulimit parameters
121 - ulimit = ctools.ctulimit()  
122 ulimit['inobs'] = self._events 121 ulimit['inobs'] = self._events
123 ulimit['inmodel'] = self._model 122 ulimit['inmodel'] = self._model
124 ulimit['srcname'] = 'Crab' 123 ulimit['srcname'] = 'Crab'
@@ -140,6 +139,13 @@ class Test(test): @@ -140,6 +139,13 @@ class Test(test):
140 self.test_value(ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16, 139 self.test_value(ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16,
141 'Check upper limit on energy flux') 140 'Check upper limit on energy flux')
142 141
  142 + # Check obs() method
  143 + self.test_value(ulimit.obs().size(), 1,
  144 + 'Check number of observations in container')
  145 +
  146 + # Check opt() method
  147 + self.test_value(ulimit.opt().status(), 0, 'Check optimizer status')
  148 +
143 # Copy ctulimit tool 149 # Copy ctulimit tool
144 cpy_ulimit = ulimit.copy() 150 cpy_ulimit = ulimit.copy()
145 151
@@ -166,6 +172,9 @@ class Test(test): @@ -166,6 +172,9 @@ class Test(test):
166 self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16, 172 self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16,
167 'Check upper limit on energy flux') 173 'Check upper limit on energy flux')
168 174
  175 + # Save copy of observation container for later
  176 + obs = cpy_ulimit.obs().copy()
  177 +
169 # Now clear copy of ctulimit tool 178 # Now clear copy of ctulimit tool
170 cpy_ulimit.clear() 179 cpy_ulimit.clear()
171 180
@@ -177,6 +186,52 @@ class Test(test): @@ -177,6 +186,52 @@ class Test(test):
177 self.test_value(cpy_ulimit.eflux_ulimit(), 0.0, 1.0e-16, 186 self.test_value(cpy_ulimit.eflux_ulimit(), 0.0, 1.0e-16,
178 'Check upper limit on energy flux') 187 'Check upper limit on energy flux')
179 188
  189 + # Now set ctulimit tool using the observation container from last
  190 + # time. This should avoid the necessity to recompute the maximum
  191 + # likelihood
  192 + ulimit = ctools.ctulimit(obs)
  193 + #ulimit['inobs'] = self._events
  194 + #ulimit['inmodel'] = self._model
  195 + ulimit['srcname'] = 'Crab'
  196 + #ulimit['caldb'] = self._caldb
  197 + #ulimit['irf'] = self._irf
  198 + ulimit['logfile'] = 'ctulimit_py3.log'
  199 + ulimit['chatter'] = 4
  200 +
  201 + # Execute ctulimit tool
  202 + ulimit.logFileOpen() # Needed to get a new log file
  203 + ulimit.execute()
  204 +
  205 + # Check results
  206 + self.test_value(ulimit.diff_ulimit(), 8.86803e-18, 1.0e-23,
  207 + 'Check differential upper limit')
  208 + self.test_value(ulimit.flux_ulimit(), 6.10509e-12, 1.0e-17,
  209 + 'ulimit upper limit on photon flux')
  210 + self.test_value(ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16,
  211 + 'Check upper limit on energy flux')
  212 +
  213 + # Test invalid model name
  214 + self.test_try('Test invalid model name')
  215 + try:
  216 + ulimit['srcname'] = 'Weihnachtsstern'
  217 + ulimit['logfile'] = 'ctulimit_py4.log'
  218 + ulimit.logFileOpen()
  219 + ulimit.execute()
  220 + self.test_try_failure('Exception not thrown')
  221 + except ValueError:
  222 + self.test_try_success()
  223 +
  224 + # Test specification of background model
  225 + ulimit['srcname'] = 'Background'
  226 + ulimit['logfile'] = 'ctulimit_py5.log'
  227 + ulimit.logFileOpen()
  228 + self.test_try('Test invalid model name')
  229 + try:
  230 + ulimit.execute()
  231 + self.test_try_failure('Exception not thrown')
  232 + except ValueError:
  233 + self.test_try_success()
  234 +
180 # Return 235 # Return
181 return 236 return
182 237