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 3 * Version 1.2.0 released
4 4 ========================
5 5  
  6 + Remove ctselect::time_reference() method
6 7 Add ctool and cscript pars() methods (#1838)
7 8 Fix ctbin::save() bug for empty observation container (#1835)
8 9 Fix exception when calling ctools clear() methods (#1835)
... ...
1 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 6 Introduction
... ... @@ -38,6 +38,9 @@ ctselect - CTA event selection
38 38 The clear() method now calls GApplication::clear() to conserve the properties
39 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 45 ctbin - CTA event binning
43 46 -------------------------
... ...
README.md
1 1 ctools information
2 2 ==================
3   -* Version: 1.2.0.dev1 (6 August 2016)
  3 +* Version: 1.2.0.dev1 (12 August 2016)
4 4 * Author: Juergen Knoedlseder (jurgen.knodlseder@irap.omp.eu)
5 5 * GammaLib dependency: 1.2.0.dev1
6 6  
... ...
pyext/Makefile.am
... ... @@ -64,6 +64,7 @@ testscripts = ctools/tests/__init__.py \
64 64 testdata = $(top_srcdir)/test/data/crab.xml \
65 65 $(top_srcdir)/test/data/crab_events.fits.gz \
66 66 $(top_srcdir)/test/data/crab_cntmap.fits.gz \
  67 + $(top_srcdir)/test/data/invalid_event_list.fits.gz \
67 68 $(top_srcdir)/test/data/exclusion.reg
68 69  
69 70 # Install test scripts and test data. Note that we don't need to prepend
... ...
pyext/ctselect.i
... ... @@ -44,11 +44,10 @@ public:
44 44 virtual ~ctselect(void);
45 45  
46 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 246 // Flag removal
247 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 256 // Log model removal or keeping
265 257 std::string what = (remove) ? "Remove model" : "Keep model";
... ...
src/ctselect/ctselect.cpp
... ... @@ -291,8 +291,8 @@ void ctselect::run(void)
291 291 // If we have an input file then check it
292 292 if (!m_infiles[i].empty()) {
293 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 322 // If we have a temporary file then check it
323 323 if (!filename.empty()) {
324 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 611 // Write header into logger
612 612 log_header3(NORMAL, "Events selection");
613 613  
614   - // Initialise selection string
  614 + // Initialise selection and addition strings
615 615 std::string selection;
  616 + std::string add;
616 617  
617 618 // Initialise selection flags
618 619 bool remove_all = false;
... ... @@ -679,6 +680,7 @@ void ctselect::select_events(GCTAObservation* obs,
679 680 sprintf(cmin, "%.8f", tmin);
680 681 sprintf(cmax, "%.8f", tmax);
681 682 selection = "TIME >= "+std::string(cmin)+" && TIME <= "+std::string(cmax);
  683 + add = " && ";
682 684 log_value(NORMAL, "Time range",
683 685 gammalib::str(tmin)+" - "+gammalib::str(tmax)+" s");
684 686  
... ... @@ -687,11 +689,6 @@ void ctselect::select_events(GCTAObservation* obs,
687 689 // Make energy selection
688 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 692 // Log the requested energy selection
696 693 if (logNormal()) {
697 694 log << gammalib::parformat("Selected energy range");
... ... @@ -725,43 +722,40 @@ void ctselect::select_events(GCTAObservation* obs,
725 722 char cmax[80];
726 723 sprintf(cmin, "%.8f", emin);
727 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 730 else if (emin > 0.0) {
733 731 char cmin[80];
734 732 sprintf(cmin, "%.8f", emin);
735   - selection += "ENERGY >= "+std::string(cmin);
  733 + selection += add + "ENERGY >= " + std::string(cmin);
  734 + add = " && ";
736 735 }
737 736 else if (emax > 0.0) {
738 737 char cmax[80];
739 738 sprintf(cmax, "%.8f", emax);
740   - selection += "ENERGY <= "+std::string(cmax);
  739 + selection += add + "ENERGY <= " + std::string(cmax);
  740 + add = " && ";
741 741 }
742 742 else {
743   - log << "None" << std::endl;
744 743 remove_all = true;
745 744 }
746 745  
747 746 } // endif: made energy selection
748 747  
749   - // Make ROI selection
  748 + // Make RoI selection
750 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 752 log_value(NORMAL, "Requested RoI",
759 753 "Centre(RA,DEC)=("+gammalib::str(ra)+", "+
760 754 gammalib::str(dec)+") deg, Radius="+gammalib::str(m_rad)+
761 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 759 double roi_radius = list->roi().radius();
766 760 if (roi_radius > 0.0) {
767 761 GSkyDir roi_centre = list->roi().centre().dir();
... ... @@ -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 775 if (logNormal()) {
782 776 log << gammalib::parformat("Selected RoI");
783 777 if (rad <= 0.0) {
... ... @@ -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 788 char cra[80];
795 789 char cdec[80];
796 790 char crad[80];
797 791 sprintf(cra, "%.6f", ra);
798 792 sprintf(cdec, "%.6f", dec);
799 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 799 } // endif: made ROI selection
805 800  
806 801 // Make an expression selection
807 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 804 // Append the expression
815   - selection += "("+gammalib::strip_whitespace(m_expr)+")";
  805 + selection += add + "("+gammalib::strip_whitespace(m_expr)+")";
816 806  
817 807 } // endif: made expression selection
818 808  
... ... @@ -875,11 +865,10 @@ void ctselect::select_events(GCTAObservation* obs,
875 865 GCTAInstDir instdir;
876 866 instdir.dir().radec_deg(ra, dec);
877 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 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 872 list->roi(old_roi);
884 873 }
885 874  
... ... @@ -891,11 +880,10 @@ void ctselect::select_events(GCTAObservation* obs,
891 880 GEbounds ebounds;
892 881 ebounds.append(GEnergy(emin, "TeV"), GEnergy(emax, "TeV"));
893 882 list->ebounds(ebounds);
894   - } //endif: energy selection was performed
  883 + }
895 884  
  885 + // ... otherwise restore old Ebounds if they existed
896 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 887 list->ebounds(old_ebounds);
900 888 }
901 889  
... ... @@ -1342,65 +1330,60 @@ void ctselect::save_event_list(const GCTAObservation* obs,
1342 1330 const std::string& gtiname,
1343 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 1388 // Return
1406 1389 return;
... ...
src/ctselect/ctselect.hpp
... ... @@ -62,7 +62,6 @@ public:
62 62 void run(void);
63 63 void save(void);
64 64 const GObservations& obs(void) const;
65   - const GTimeReference& time_reference(void) const;
66 65  
67 66 protected:
68 67 // Protected methods
... ... @@ -128,16 +127,4 @@ const GObservations&amp; ctselect::obs(void) const
128 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 130 #endif /* CTSELECT_HPP */
... ...
src/cttsmap/cttsmap.cpp
... ... @@ -234,7 +234,7 @@ void cttsmap::run(void)
234 234  
235 235 // Initialise optimizer
236 236 GOptimizerLM* opt = (logExplicit()) ? new GOptimizerLM(&log)
237   - : new GOptimizerLM();
  237 + : new GOptimizerLM();
238 238  
239 239 // Store initial models
240 240 GModels models_orig = m_obs.models();
... ... @@ -246,15 +246,15 @@ void cttsmap::run(void)
246 246 models.remove(m_srcname);
247 247  
248 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 251 // Write header
252 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 272 " at "+bincentre.print());
273 273  
274 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 279 // Assign models to observations
282 280 m_obs.models(models);
... ... @@ -292,16 +290,11 @@ void cttsmap::run(void)
292 290  
293 291 // Log information
294 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 300 // Get test source model instance
... ... @@ -312,11 +305,9 @@ void cttsmap::run(void)
312 305 m_tsmap(i) = ts;
313 306  
314 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 312 // Set status of bin to true
322 313 m_statusmap(i) = 1.0;
... ... @@ -479,7 +470,8 @@ void cttsmap::copy_members(const cttsmap&amp; app)
479 470 m_statusmap = app.m_statusmap;
480 471  
481 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 476 // Return
485 477 return;
... ... @@ -491,6 +483,12 @@ void cttsmap::copy_members(const cttsmap&amp; app)
491 483 ***************************************************************************/
492 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 492 // Return
495 493 return;
496 494 }
... ... @@ -519,26 +517,24 @@ void cttsmap::get_parameters(void)
519 517 // Get name of test source
520 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 523 m_testsource = m_obs.models()[m_srcname]->clone();
524 524  
525 525 // Check if model has RA and DEC parameters which are necessary to
526 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 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 539 // Create sky map based on task parameters
544 540 GSkyMap map = create_map(m_obs);
... ... @@ -583,32 +579,27 @@ void cttsmap::init_maps(const GSkyMap&amp; map)
583 579 m_tsmap = GSkyMap(map);
584 580  
585 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 604 // Return
614 605 return;
... ...
src/ctulimit/ctulimit.cpp
... ... @@ -618,10 +618,10 @@ void ctulimit::ulimit_bisection(const double&amp; min, const double&amp; max)
618 618  
619 619 // Change boundaries for further iteration
620 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 627 // Increment counter
... ... @@ -672,7 +672,7 @@ double ctulimit::evaluate(const double&amp; value)
672 672 else {
673 673 std::string msg = "Value of parameter \""+m_model_par->name()+"\" "
674 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 676 "in the model XML file.";
677 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 39 # Call base class constructor
40 40 test.__init__(self)
41 41  
  42 + # Set test data
  43 + self._invalid_events = self._datadir + '/invalid_event_list.fits'
  44 +
42 45 # Return
43 46 return
44 47  
... ... @@ -104,7 +107,7 @@ class Test(test):
104 107 """
105 108 Test ctselect from Python
106 109 """
107   - # Allocate ctselect
  110 + # Allocate empty ctselect tool
108 111 select = ctools.ctselect()
109 112  
110 113 # Check that empty ctselect tool holds an empty observation
... ... @@ -122,7 +125,6 @@ class Test(test):
122 125 select.clear()
123 126  
124 127 # Now set ctselect parameters
125   - select = ctools.ctselect()
126 128 select['inobs'] = self._events
127 129 select['ra'] = 83.63
128 130 select['dec'] = 22.01
... ... @@ -130,7 +132,7 @@ class Test(test):
130 132 select['tmin'] = 0
131 133 select['tmax'] = 1800
132 134 select['emin'] = 0.1
133   - select['emax'] = 100
  135 + select['emax'] = 100.0
134 136 select['outobs'] = 'ctselect_py1.fits'
135 137 select['logfile'] = 'ctselect_py1.log'
136 138 select['chatter'] = 2
... ... @@ -166,7 +168,6 @@ class Test(test):
166 168  
167 169 # Check result file
168 170 self._check_result_file('ctselect_py2.fits')
169   - print('Step3')
170 171  
171 172 # Execute again the copy of ctselect tool again, now using the pointing
172 173 # information in the input observation
... ... @@ -186,19 +187,75 @@ class Test(test):
186 187 # Check that cleared ctselect tool holds no observations and events
187 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 239 # Return
190 240 return
191 241  
192 242 # Check result file
193   - def _check_result_file(self, filename):
  243 + def _check_result_file(self, filename, nevents=6127):
194 244 """
195 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 254 # Open result file
198 255 events = gammalib.GCTAEventList(filename)
199 256  
200 257 # Check event list
201   - self._check_events(events, nevents=6127)
  258 + self._check_events(events, nevents=nevents)
202 259  
203 260 # Return
204 261 return
... ...
test/test_cttsmap.py
1 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 5 # Copyright (C) 2014-2016 Juergen Knoedlseder
6 6 #
... ... @@ -18,6 +18,7 @@
18 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19 #
20 20 # ==========================================================================
  21 +import os
21 22 import gammalib
22 23 import ctools
23 24 from testing import test
... ... @@ -105,14 +106,31 @@ class Test(test):
105 106 """
106 107 Test cttsmap from Python
107 108 """
108   - # Set-up cttsmap
  109 + # Allocate empty cttsmap tool
109 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 129 tsmap['inobs'] = self._events
111 130 tsmap['inmodel'] = self._model
112 131 tsmap['srcname'] = 'Crab'
113 132 tsmap['caldb'] = self._caldb
114 133 tsmap['irf'] = self._irf
115   - tsmap['outmap'] = 'cttsmap_py1.fits'
116 134 tsmap['nxpix'] = 3
117 135 tsmap['nypix'] = 3
118 136 tsmap['binsz'] = 0.02
... ... @@ -120,6 +138,7 @@ class Test(test):
120 138 tsmap['proj'] = 'CAR'
121 139 tsmap['xref'] = 83.63
122 140 tsmap['yref'] = 22.01
  141 + tsmap['outmap'] = 'cttsmap_py1.fits'
123 142 tsmap['logfile'] = 'cttsmap_py1.log'
124 143 tsmap['chatter'] = 2
125 144  
... ... @@ -131,32 +150,116 @@ class Test(test):
131 150 # Check result file
132 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 182 # Return
135 183 return
136 184  
137 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 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 199 # Open result file
143 200 fits = gammalib.GFits(filename)
144 201  
145 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 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 264 # Return
162 265 return
... ...
test/test_ctulimit.py
... ... @@ -118,7 +118,6 @@ class Test(test):
118 118 ulimit.clear()
119 119  
120 120 # Now set ctulimit parameters
121   - ulimit = ctools.ctulimit()
122 121 ulimit['inobs'] = self._events
123 122 ulimit['inmodel'] = self._model
124 123 ulimit['srcname'] = 'Crab'
... ... @@ -140,6 +139,13 @@ class Test(test):
140 139 self.test_value(ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16,
141 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 149 # Copy ctulimit tool
144 150 cpy_ulimit = ulimit.copy()
145 151  
... ... @@ -166,6 +172,9 @@ class Test(test):
166 172 self.test_value(cpy_ulimit.eflux_ulimit(), 2.75669e-11, 1.0e-16,
167 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 178 # Now clear copy of ctulimit tool
170 179 cpy_ulimit.clear()
171 180  
... ... @@ -177,6 +186,52 @@ class Test(test):
177 186 self.test_value(cpy_ulimit.eflux_ulimit(), 0.0, 1.0e-16,
178 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 235 # Return
181 236 return
182 237  
... ...