Commit bb9410c7c406e17d9246fc02016e65b46518d4a8
1 parent
1aa1a2c6
Updated test cases for ctphase (#1982)
Added a python wrapper file for ctphase. Added tests of the python wrapper for ctphase (and made sure they pass). Added unit information to the '.par' file.
Showing
9 changed files
with
379 additions
and
110 deletions
pyext/Makefile.am
| ... | ... | @@ -44,6 +44,7 @@ testscripts = ctools/tests/__init__.py \ |
| 44 | 44 | $(top_srcdir)/test/test_python_ctools.py \ |
| 45 | 45 | $(top_srcdir)/test/test_ctobssim.py \ |
| 46 | 46 | $(top_srcdir)/test/test_ctselect.py \ |
| 47 | + $(top_srcdir)/test/test_ctphase.py \ | |
| 47 | 48 | $(top_srcdir)/test/test_ctbin.py \ |
| 48 | 49 | $(top_srcdir)/test/test_ctlike.py \ |
| 49 | 50 | $(top_srcdir)/test/test_cttsmap.py \ | ... | ... |
pyext/ctools/tools.i
pyext/ctphase.i
0 → 100644
| 1 | +/*************************************************************************** | |
| 2 | + * ctphase - Append phase information to CTA events file * | |
| 3 | + * ----------------------------------------------------------------------- * | |
| 4 | + * copyright (C) 2017 by Leonardo Di Venere * | |
| 5 | + * ----------------------------------------------------------------------- * | |
| 6 | + * * | |
| 7 | + * This program is free software: you can redistribute it and/or modify * | |
| 8 | + * it under the terms of the GNU General Public License as published by * | |
| 9 | + * the Free Software Foundation, either version 3 of the License, or * | |
| 10 | + * (at your option) any later version. * | |
| 11 | + * * | |
| 12 | + * This program is distributed in the hope that it will be useful, * | |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
| 15 | + * GNU General Public License for more details. * | |
| 16 | + * * | |
| 17 | + * You should have received a copy of the GNU General Public License * | |
| 18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * | |
| 19 | + * * | |
| 20 | + ***************************************************************************/ | |
| 21 | +/** | |
| 22 | + * @file ctphase.i | |
| 23 | + * @brief Append phase information to CTA events file | |
| 24 | + * @author Leonardo Di Venere | |
| 25 | + */ | |
| 26 | +%{ | |
| 27 | +/* Put headers and other declarations here that are needed for compilation */ | |
| 28 | +#include "ctphase.hpp" | |
| 29 | +%} | |
| 30 | + | |
| 31 | + | |
| 32 | +/***********************************************************************//** | |
| 33 | + * @class ctphase | |
| 34 | + * | |
| 35 | + * @brief Data selection tool | |
| 36 | + ***************************************************************************/ | |
| 37 | +class ctphase : public ctobservation { | |
| 38 | +public: | |
| 39 | + // Constructors and destructors | |
| 40 | + ctphase(void); | |
| 41 | + explicit ctphase(const GObservations& obs); | |
| 42 | + ctphase(int argc, char *argv[]); | |
| 43 | + ctphase(const ctphase& app); | |
| 44 | + virtual ~ctphase(void); | |
| 45 | + | |
| 46 | + // Methods | |
| 47 | + void clear(void); | |
| 48 | + void run(void); | |
| 49 | + void save(void); | |
| 50 | + void publish(const std::string& name = ""); | |
| 51 | +}; | |
| 52 | + | |
| 53 | + | |
| 54 | +/***********************************************************************//** | |
| 55 | + * @brief Data selection tool Python extension | |
| 56 | + ***************************************************************************/ | |
| 57 | +%extend ctphase { | |
| 58 | + ctphase copy() { | |
| 59 | + return (*self); | |
| 60 | + } | |
| 61 | +} | ... | ... |
src/ctphase/ctphase.cpp
| 1 | 1 | /*************************************************************************** |
| 2 | - * ctphase - Data selection tool * | |
| 2 | + * ctphase - Append phase information to CTA events file * | |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2010-2017 by Juergen Knoedlseder * | |
| 4 | + * copyright (C) 2017 by Leonardo Di Venere * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -20,8 +20,8 @@ |
| 20 | 20 | ***************************************************************************/ |
| 21 | 21 | /** |
| 22 | 22 | * @file ctphase.cpp |
| 23 | - * @brief Data selection tool definition | |
| 24 | - * @author Juergen Knoedlseder | |
| 23 | + * @brief Append phase information to CTA events file | |
| 24 | + * @author Leonardo Di Venere | |
| 25 | 25 | */ |
| 26 | 26 | |
| 27 | 27 | /* __ Includes ___________________________________________________________ */ |
| ... | ... | @@ -34,7 +34,7 @@ |
| 34 | 34 | |
| 35 | 35 | /* __ Method name definitions ____________________________________________ */ |
| 36 | 36 | #define G_RUN "ctphase::run()" |
| 37 | -#define G_SELECT_EVENTS "ctphase::select_events(GCTAObservation*, "\ | |
| 37 | +#define G_PHASE_EVENTS "ctphase::phase_events(GCTAObservation*, "\ | |
| 38 | 38 | "std::string&, std::string&, std::string&)" |
| 39 | 39 | #define G_SET_EBOUNDS "ctphase::set_ebounds(GCTAObservation*, GEbounds&)" |
| 40 | 40 | |
| ... | ... | @@ -203,14 +203,10 @@ void ctphase::clear(void) |
| 203 | 203 | |
| 204 | 204 | |
| 205 | 205 | /***********************************************************************//** |
| 206 | - * @brief Select event data | |
| 206 | + * @brief Append phase information to event data | |
| 207 | 207 | * |
| 208 | 208 | * This method reads in the application parameters and loops over all |
| 209 | - * observations that were found to perform an event selection. Event | |
| 210 | - * selection is done by writing each observation to a temporary file and | |
| 211 | - * re-opening the temporary file using the cfitsio event filter syntax. | |
| 212 | - * The temporary file is deleted after this action so that no disk overflow | |
| 213 | - * will occur. | |
| 209 | + * observations that were found to append phase information to the data. | |
| 214 | 210 | ***************************************************************************/ |
| 215 | 211 | void ctphase::run(void) |
| 216 | 212 | { |
| ... | ... | @@ -226,7 +222,7 @@ void ctphase::run(void) |
| 226 | 222 | log_observations(NORMAL, m_obs, "Input observation"); |
| 227 | 223 | |
| 228 | 224 | // Write header into logger |
| 229 | - log_header1(TERSE, "Event selection"); | |
| 225 | + log_header1(TERSE, "Appending phase informaiton"); | |
| 230 | 226 | |
| 231 | 227 | // Initialise counters |
| 232 | 228 | int n_observations = 0; |
| ... | ... | @@ -283,7 +279,7 @@ void ctphase::run(void) |
| 283 | 279 | // Fall through in case that the event file is empty |
| 284 | 280 | if (obs->events()->size() == 0) { |
| 285 | 281 | log_string(NORMAL, " Warning: No events in event file \""+ |
| 286 | - m_infiles[i]+"\". Event selection skipped."); | |
| 282 | + m_infiles[i]+"\". Event phasing skipped."); | |
| 287 | 283 | continue; |
| 288 | 284 | } |
| 289 | 285 | |
| ... | ... | @@ -326,7 +322,7 @@ void ctphase::run(void) |
| 326 | 322 | } |
| 327 | 323 | } |
| 328 | 324 | |
| 329 | - // Load observation from temporary file, including event selection | |
| 325 | + // Load observation from temporary file and compute phase | |
| 330 | 326 | phase_events(obs, filename, m_evtname[i], m_gtiname[i]); |
| 331 | 327 | |
| 332 | 328 | // Close temporary file |
| ... | ... | @@ -359,22 +355,22 @@ void ctphase::run(void) |
| 359 | 355 | |
| 360 | 356 | |
| 361 | 357 | /***********************************************************************//** |
| 362 | - * @brief Save the selected event list(s) | |
| 358 | + * @brief Save the output event list(s) | |
| 363 | 359 | * |
| 364 | - * This method saves the selected event list(s) into FITS file(s). There are | |
| 360 | + * This method saves the updated event list(s) into FITS file(s). There are | |
| 365 | 361 | * two modes, depending on the m_use_xml flag. |
| 366 | 362 | * |
| 367 | - * If m_use_xml is true, all selected event list(s) will be saved into FITS | |
| 363 | + * If m_use_xml is true, all output event list(s) will be saved into FITS | |
| 368 | 364 | * files, where the output filenames are constructued from the input |
| 369 | 365 | * filenames by prepending the m_prefix string to name. Any path information |
| 370 | 366 | * will be stripped form the input name, hence event files will be written |
| 371 | 367 | * into the local working directory (unless some path information is present |
| 372 | 368 | * in the prefix). In addition, an XML file will be created that gathers |
| 373 | - * the filename information for the selected event list(s). If an XML file | |
| 369 | + * the filename information for the output event list(s). If an XML file | |
| 374 | 370 | * was present on input, all metadata information will be copied from this |
| 375 | 371 | * input file. |
| 376 | 372 | * |
| 377 | - * If m_use_xml is false, the selected event list will be saved into a FITS | |
| 373 | + * If m_use_xml is false, the output event list will be saved into a FITS | |
| 378 | 374 | * file. |
| 379 | 375 | ***************************************************************************/ |
| 380 | 376 | void ctphase::save(void) |
| ... | ... | @@ -506,6 +502,8 @@ void ctphase::copy_members(const ctphase& app) |
| 506 | 502 | ***************************************************************************/ |
| 507 | 503 | void ctphase::free_members(void) |
| 508 | 504 | { |
| 505 | + m_phase.clear(); | |
| 506 | + | |
| 509 | 507 | // Return |
| 510 | 508 | return; |
| 511 | 509 | } |
| ... | ... | @@ -528,19 +526,70 @@ void ctphase::get_parameters(void) |
| 528 | 526 | // information and do not accept counts cubes. |
| 529 | 527 | setup_observations(m_obs, false, true, false); |
| 530 | 528 | |
| 531 | - // Check for sanity of energy selection parameters | |
| 529 | + // Check for sanity of frequency and phase information | |
| 532 | 530 | if ((*this)["p0"].is_valid() && |
| 533 | 531 | (*this)["mjd"].is_valid() && |
| 534 | 532 | (*this)["f0"].is_valid()) { |
| 535 | 533 | |
| 536 | - m_phase = GModelTemporalPhaseCurve(); | |
| 537 | - m_phase.norm(1.0); | |
| 538 | - m_phase.mjd((*this)["mjd"].real()); | |
| 539 | - m_phase.phase((*this)["p0"].real()); | |
| 540 | - m_phase.f0((*this)["f0"].real()); | |
| 541 | - m_phase.f1((*this)["f1"].real()); | |
| 542 | - m_phase.f2((*this)["f2"].real()); | |
| 534 | + // The following creates an XML object responsible for initializing | |
| 535 | + // 'm_phase'. This was done as the default values for the parameters in | |
| 536 | + // 'GModelTemporalPhaseCurve' are such that the ranges are predefined. | |
| 537 | + // Initializing 'm_phase' from an XML object circumvents this restriction. | |
| 538 | + | |
| 539 | + GXmlElement norm; | |
| 540 | + norm.name("parameter"); | |
| 541 | + norm.attribute("name", "Normalization"); | |
| 542 | + norm.attribute("value", "1"); | |
| 543 | + norm.attribute("min", "0"); | |
| 544 | + norm.attribute("max", "1000"); | |
| 545 | + | |
| 546 | + GXmlElement mjd; | |
| 547 | + mjd.name("parameter"); | |
| 548 | + mjd.attribute("name", "MJD"); | |
| 549 | + mjd.attribute("value", (*this)["mjd"].value()); | |
| 550 | + mjd.attribute("min", (*this)["mjd"].min()); | |
| 551 | + mjd.attribute("max", (*this)["mjd"].max()); | |
| 552 | + | |
| 553 | + GXmlElement p0; | |
| 554 | + p0.name("parameter"); | |
| 555 | + p0.attribute("name", "Phase"); | |
| 556 | + p0.attribute("value", (*this)["p0"].value()); | |
| 557 | + p0.attribute("min", (*this)["p0"].min()); | |
| 558 | + p0.attribute("max", (*this)["p0"].max()); | |
| 559 | + | |
| 560 | + GXmlElement f0; | |
| 561 | + f0.name("parameter"); | |
| 562 | + f0.attribute("name", "F0"); | |
| 563 | + f0.attribute("value", (*this)["f0"].value()); | |
| 564 | + f0.attribute("min", (*this)["f0"].min()); | |
| 565 | + f0.attribute("max", (*this)["f0"].max()); | |
| 566 | + | |
| 567 | + GXmlElement f1; | |
| 568 | + f1.name("parameter"); | |
| 569 | + f1.attribute("name", "F1"); | |
| 570 | + f1.attribute("value", (*this)["f1"].value()); | |
| 571 | + f1.attribute("min", (*this)["f1"].min()); | |
| 572 | + f1.attribute("max", (*this)["f1"].max()); | |
| 573 | + | |
| 574 | + GXmlElement f2; | |
| 575 | + f2.name("parameter"); | |
| 576 | + f2.attribute("name", "F2"); | |
| 577 | + f2.attribute("value", (*this)["f2"].value()); | |
| 578 | + f2.attribute("min", (*this)["f2"].min()); | |
| 579 | + f2.attribute("max", (*this)["f2"].max()); | |
| 543 | 580 | |
| 581 | + GXmlElement info; | |
| 582 | + info.append(norm); | |
| 583 | + info.append(mjd); | |
| 584 | + info.append(p0); | |
| 585 | + info.append(f0); | |
| 586 | + info.append(f1); | |
| 587 | + info.append(f2); | |
| 588 | + | |
| 589 | + info.attribute("file",""); | |
| 590 | + | |
| 591 | + m_phase = GModelTemporalPhaseCurve(); | |
| 592 | + m_phase.read(info); | |
| 544 | 593 | } |
| 545 | 594 | else { |
| 546 | 595 | GException::invalid_value("ctphase::get_parameters()", |
| ... | ... | @@ -576,12 +625,8 @@ void ctphase::get_parameters(void) |
| 576 | 625 | * @exception GException::invalid_value |
| 577 | 626 | * No events extension found in FITS file. |
| 578 | 627 | * |
| 579 | - * Select events from a FITS file by making use of the selection possibility | |
| 580 | - * of the cfitsio library on loading a file. A selection string is created | |
| 581 | - * from the specified criteria that is appended to the filename so that | |
| 582 | - * cfitsio will automatically filter the event data. This selection string | |
| 583 | - * is then applied when opening the FITS file. The event list in the current | |
| 584 | - * observation is replaced by selected event list read from the FITS file. | |
| 628 | + * Append phase information to events from a FITS file by adding a "PHASE" | |
| 629 | + * column to the FITS file. | |
| 585 | 630 | ***************************************************************************/ |
| 586 | 631 | void ctphase::phase_events(GCTAObservation* obs, |
| 587 | 632 | const std::string& filename, |
| ... | ... | @@ -591,13 +636,6 @@ void ctphase::phase_events(GCTAObservation* obs, |
| 591 | 636 | // Write header into logger |
| 592 | 637 | log_header3(NORMAL, "Events phasing"); |
| 593 | 638 | |
| 594 | - // Initialise selection and addition strings | |
| 595 | - std::string selection; | |
| 596 | - std::string add; | |
| 597 | - | |
| 598 | - // Initialise selection flags | |
| 599 | - bool remove_all = false; | |
| 600 | - | |
| 601 | 639 | // Get CTA event list pointer |
| 602 | 640 | GCTAEventList* list = |
| 603 | 641 | static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events())); |
| ... | ... | @@ -617,62 +655,7 @@ void ctphase::phase_events(GCTAObservation* obs, |
| 617 | 655 | if (!list->has_phase()) { |
| 618 | 656 | list->has_phase(true); |
| 619 | 657 | } |
| 620 | -/* | |
| 621 | - // Save GTI for later usage | |
| 622 | - GGti gti = list->gti(); | |
| 623 | - | |
| 624 | - // Build input filename including selection expression | |
| 625 | - std::string expression = filename; | |
| 626 | 658 | |
| 627 | - // Dump FITS filename including selection expression | |
| 628 | - log_value(NORMAL, "FITS filename", expression); | |
| 629 | - | |
| 630 | - // Open FITS file | |
| 631 | - GFits file(expression); | |
| 632 | - | |
| 633 | - // Log selected FITS file | |
| 634 | - log_header3(EXPLICIT, "FITS file content after selection"); | |
| 635 | - log_string(EXPLICIT, file.print(m_chatter)); | |
| 636 | - | |
| 637 | - // Check if we have an events HDU | |
| 638 | - if (!file.contains(evtname)) { | |
| 639 | - std::string msg = "No events extension \""+evtname+"\" found in " | |
| 640 | - "FITS file. The expression \""+expression+"\" " | |
| 641 | - "was used to open the FITS file."; | |
| 642 | - throw GException::invalid_value(G_SELECT_EVENTS, msg); | |
| 643 | - } | |
| 644 | - | |
| 645 | - // Determine number of events in the events HDU. If removal of all events | |
| 646 | - // has been requested then set the number of events to zero. | |
| 647 | - int nevents = (remove_all) ? 0 : file.table(evtname)->nrows(); | |
| 648 | - | |
| 649 | - // If the selected event list is empty then append an empty event list | |
| 650 | - // to the observation | |
| 651 | - if (nevents < 1) { | |
| 652 | - | |
| 653 | - // Create empty event list | |
| 654 | - GCTAEventList eventlist; | |
| 655 | - | |
| 656 | - // Append list to observation | |
| 657 | - obs->events(eventlist); | |
| 658 | - | |
| 659 | - } | |
| 660 | - | |
| 661 | - // ... otherwise load the data from the temporary file | |
| 662 | - else { | |
| 663 | - obs->read(file); | |
| 664 | - } | |
| 665 | - | |
| 666 | - // Get CTA event list pointer | |
| 667 | - list = static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events())); | |
| 668 | - | |
| 669 | - // Make sure that events are fetched since the temporary file will be | |
| 670 | - // closed later | |
| 671 | - list->fetch(); | |
| 672 | - | |
| 673 | - // Set event list GTI (in any case as any event list has a GTI) | |
| 674 | - list->gti(gti); | |
| 675 | -*/ | |
| 676 | 659 | // Return |
| 677 | 660 | return; |
| 678 | 661 | } |
| ... | ... | @@ -687,7 +670,7 @@ void ctphase::phase_events(GCTAObservation* obs, |
| 687 | 670 | * This method checks if the input FITS file is correct. |
| 688 | 671 | ***************************************************************************/ |
| 689 | 672 | std::string ctphase::check_infile(const std::string& filename, |
| 690 | - const std::string& evtname) const | |
| 673 | + const std::string& evtname) const | |
| 691 | 674 | { |
| 692 | 675 | // Initialise message string |
| 693 | 676 | std::string message = ""; |
| ... | ... | @@ -805,7 +788,7 @@ std::string ctphase::get_gtiname(const std::string& filename, |
| 805 | 788 | // Get GTI name |
| 806 | 789 | gtiname = events.gtiname(); |
| 807 | 790 | |
| 808 | - } | |
| 791 | + } // endif: filename was not empty | |
| 809 | 792 | |
| 810 | 793 | // Return GTI name |
| 811 | 794 | return (gtiname); |
| ... | ... | @@ -957,7 +940,7 @@ void ctphase::save_xml(void) |
| 957 | 940 | * |
| 958 | 941 | * myfits.fits[EVENTS1;GTI1] |
| 959 | 942 | * |
| 960 | - * will write the selected events into the "EVENTS1" extension and the | |
| 943 | + * will write the updated events into the "EVENTS1" extension and the | |
| 961 | 944 | * Good Time Intervals into the "GTI1" extension of the "myfits.fits" FITS |
| 962 | 945 | * file. If the Good Time Intervals extension name is skipped, e.g. |
| 963 | 946 | * | ... | ... |
src/ctphase/ctphase.hpp
| 1 | 1 | /*************************************************************************** |
| 2 | - * ctphase - Data selection tool * | |
| 2 | + * ctphase - Append phase information to CTA events file * | |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | 4 | * copyright (C) 2017 by Leonardo Di Venere * |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| ... | ... | @@ -20,8 +20,8 @@ |
| 20 | 20 | ***************************************************************************/ |
| 21 | 21 | /** |
| 22 | 22 | * @file ctphase.hpp |
| 23 | - * @brief Data selection tool definition | |
| 24 | - * @author Juergen Knoedlseder | |
| 23 | + * @brief Append phase information to CTA events file | |
| 24 | + * @author Leonardo Di Venere | |
| 25 | 25 | */ |
| 26 | 26 | |
| 27 | 27 | #ifndef CTPHASE_HPP |
| ... | ... | @@ -63,8 +63,6 @@ public: |
| 63 | 63 | void save(void); |
| 64 | 64 | void publish(const std::string& name = ""); |
| 65 | 65 | |
| 66 | - // TODO: Add Methods for updating model parameters | |
| 67 | - | |
| 68 | 66 | protected: |
| 69 | 67 | // Protected methods |
| 70 | 68 | void init_members(void); | ... | ... |
src/ctphase/ctphase.par
| ... | ... | @@ -22,12 +22,12 @@ outobs, f, a, "phased_events.fits",,, "Output event list or observation definiti |
| 22 | 22 | prefix, s, h, "phased_",,, "Prefix for event lists in observation definition XML file" |
| 23 | 23 | |
| 24 | 24 | # |
| 25 | -# Selection parameters | |
| 25 | +# Phase information parameters | |
| 26 | 26 | #===================== |
| 27 | 27 | mjd, r, a, 52400,,, "Reference MJD for phase information" |
| 28 | -f0, r, a, 1,,, "Frequency at reference MJD" | |
| 29 | -f1, r, a, 0,,, "First freq. derivative at reference MJD" | |
| 30 | -f2, r, a, 0,,, "Second freq. derivative at reference MJD" | |
| 28 | +f0, r, a, 1,,, "Frequency at reference MJD [Hz]" | |
| 29 | +f1, r, a, -0.2,,, "First freq. derivative at reference MJD [s^-1]" | |
| 30 | +f2, r, a, 0,,, "Second freq. derivative at reference MJD [s^-2]" | |
| 31 | 31 | p0, r, a, 0.1,0.0,1.0, "Phase at reference MJD" |
| 32 | 32 | |
| 33 | 33 | # |
| ... | ... | @@ -37,5 +37,5 @@ publish, b, h, no,,, "Publish event list on VO Hub?" |
| 37 | 37 | chatter, i, h, 2,0,4, "Chattiness of output" |
| 38 | 38 | clobber, b, h, yes,,, "Overwrite existing output files with new output files?" |
| 39 | 39 | debug, b, h, no,,, "Debugging mode activated" |
| 40 | -mode, s, h, "h",,, "Mode of automatic parameters" | |
| 40 | +mode, s, h, "ql",,, "Mode of automatic parameters" | |
| 41 | 41 | logfile, f, h, "ctphase.log",,, "Log filename" | ... | ... |
src/ctphase/main.cpp
| 1 | 1 | /*************************************************************************** |
| 2 | - * ctphase - Append phase information to CTA events file * | |
| 2 | + * ctphase - Append phase information to CTA events file * | |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2017 by Leonardo Di Venere * | |
| 4 | + * copyright (C) 2017 by Leonardo Di Venere * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * | ... | ... |
test/test_ctphase.py
0 → 100644
| 1 | +#! /usr/bin/env python | |
| 2 | +# ========================================================================== | |
| 3 | +# This scripts performs unit tests for the ctselect tool. | |
| 4 | +# | |
| 5 | +# Copyright (C) 2014-2016 Juergen Knoedlseder | |
| 6 | +# | |
| 7 | +# This program is free software: you can redistribute it and/or modify | |
| 8 | +# it under the terms of the GNU General Public License as published by | |
| 9 | +# the Free Software Foundation, either version 3 of the License, or | |
| 10 | +# (at your option) any later version. | |
| 11 | +# | |
| 12 | +# This program is distributed in the hope that it will be useful, | |
| 13 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 | +# GNU General Public License for more details. | |
| 16 | +# | |
| 17 | +# You should have received a copy of the GNU General Public License | |
| 18 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 19 | +# | |
| 20 | +# ========================================================================== | |
| 21 | +import os | |
| 22 | +import gammalib | |
| 23 | +import ctools | |
| 24 | +from testing import test | |
| 25 | + | |
| 26 | + | |
| 27 | +# ============================ # | |
| 28 | +# Test class for ctselect tool # | |
| 29 | +# ============================ # | |
| 30 | +class Test(test): | |
| 31 | + """ | |
| 32 | + Test class for ctselect tool | |
| 33 | + """ | |
| 34 | + # Constructor | |
| 35 | + def __init__(self): | |
| 36 | + """ | |
| 37 | + Constructor | |
| 38 | + """ | |
| 39 | + # Call base class constructor | |
| 40 | + test.__init__(self) | |
| 41 | + | |
| 42 | + # Set test data | |
| 43 | + self._invalid_events = self._datadir + '/invalid_event_list.fits' | |
| 44 | + | |
| 45 | + # Return | |
| 46 | + return | |
| 47 | + | |
| 48 | + # Set test functions | |
| 49 | + def set(self): | |
| 50 | + """ | |
| 51 | + Set all test functions | |
| 52 | + """ | |
| 53 | + # Set test name | |
| 54 | + self.name('ctphase') | |
| 55 | + | |
| 56 | + # Append tests | |
| 57 | + self.append(self._test_cmd, 'Test ctphase on command line') | |
| 58 | + self.append(self._test_python, 'Test ctphase from Python') | |
| 59 | + | |
| 60 | + # Return | |
| 61 | + return | |
| 62 | + | |
| 63 | + # Test ctphase on command line | |
| 64 | + def _test_cmd(self): | |
| 65 | + """ | |
| 66 | + Test ctphase on the command line | |
| 67 | + """ | |
| 68 | + # Set tool name | |
| 69 | + ctphase = self._tool('ctphase') | |
| 70 | + | |
| 71 | + # Setup ctphase command | |
| 72 | + cmd = ctphase+' inobs="'+self._events+'"'+ \ | |
| 73 | + ' outobs="ctphase_cmd1.fits"'+ \ | |
| 74 | + ' p0=0.1 mjd=52400'+ \ | |
| 75 | + ' f0=0.1 f1=0. f2=0.'+ \ | |
| 76 | + ' logfile="ctphase_cmd1.log" chatter=1' | |
| 77 | + | |
| 78 | + # Check if execution of wrong command fails | |
| 79 | + self.test_assert(self._execute('command_that_does_not_exist') != 0, | |
| 80 | + 'Self test of test script') | |
| 81 | + | |
| 82 | + # Check if execution was successful | |
| 83 | + self.test_assert(self._execute(cmd) == 0, | |
| 84 | + 'Check successful execution from command line') | |
| 85 | + | |
| 86 | + # Check result file | |
| 87 | + self._check_result_file('ctphase_cmd1.fits') | |
| 88 | + | |
| 89 | + # Setup ctphase command | |
| 90 | + cmd = ctphase+' inobs="event_file_that_does_not_exist.fits"'+ \ | |
| 91 | + ' outobs="ctphase_cmd2.fits"'+ \ | |
| 92 | + ' p0=0.1 mjd=52400'+ \ | |
| 93 | + ' f0=0.1 f1=0. f2=0.'+ \ | |
| 94 | + ' logfile="ctphase_cmd2.log" chatter=1' | |
| 95 | + | |
| 96 | + # Check if execution failed | |
| 97 | + self.test_assert(self._execute(cmd) != 0, | |
| 98 | + 'Check invalid input file when executed from command line') | |
| 99 | + | |
| 100 | + # Setup ctphase --help option | |
| 101 | + cmd = ctphase+' --help' | |
| 102 | + | |
| 103 | + # Check if execution was successful in case that the CTOOLS | |
| 104 | + # environment variable was set or failed otherwise | |
| 105 | + if 'CTOOLS' in os.environ: | |
| 106 | + self.test_value(self._execute(cmd), 0, | |
| 107 | + 'Check successful execution with --help option') | |
| 108 | + else: | |
| 109 | + self.test_assert(self._execute(cmd) != 0, | |
| 110 | + 'Check execution failure with --help option') | |
| 111 | + | |
| 112 | + # Return | |
| 113 | + return | |
| 114 | + | |
| 115 | + # Test ctphase from Python | |
| 116 | + def _test_python(self): | |
| 117 | + """ | |
| 118 | + Test ctphase from Python | |
| 119 | + """ | |
| 120 | + # Allocate empty ctphase tool | |
| 121 | + phase = ctools.ctphase() | |
| 122 | + | |
| 123 | + # Check that empty ctphase tool holds an empty observation | |
| 124 | + self._check_obs(phase.obs(), nobs=0) | |
| 125 | + | |
| 126 | + # Check that saving does nothing | |
| 127 | + phase['outobs'] = 'ctphase_py0.fits' | |
| 128 | + phase['logfile'] = 'ctphase_py0.log' | |
| 129 | + phase.logFileOpen() | |
| 130 | + phase.save() | |
| 131 | + self.test_assert(not os.path.isfile('ctphase_py0.fits'), | |
| 132 | + 'Check that no event list has been created') | |
| 133 | + | |
| 134 | + # Check that clearing does not lead to an exception or segfault | |
| 135 | + phase.clear() | |
| 136 | + | |
| 137 | + # Now set ctphase parameters | |
| 138 | + phase['inobs'] = self._events | |
| 139 | + phase['p0'] = 0. | |
| 140 | + phase['mjd'] = 52400 | |
| 141 | + phase['f0'] = 1. | |
| 142 | + phase['f1'] = -0.2 | |
| 143 | + phase['f2'] = 0. | |
| 144 | + phase['outobs'] = 'ctphase_py1.fits' | |
| 145 | + phase['logfile'] = 'ctphase_py1.log' | |
| 146 | + phase['chatter'] = 2 | |
| 147 | + | |
| 148 | + # Run ctphase tool | |
| 149 | + phase.logFileOpen() # Make sure we get a log file | |
| 150 | + phase.run() | |
| 151 | + phase.save() | |
| 152 | + | |
| 153 | + # Check result file | |
| 154 | + self._check_result_file('ctphase_py1.fits', nevents=6141) | |
| 155 | + | |
| 156 | + # Copy ctphase tool | |
| 157 | + cpy_phase = phase.copy() | |
| 158 | + | |
| 159 | + # Execute copy of ctphase tool again, now with a negative value | |
| 160 | + # of initial phase to test for invalid parameter value | |
| 161 | + try: | |
| 162 | + self.test_try('Test invalid parameter value') | |
| 163 | + cpy_phase['p0'] = -0.5 | |
| 164 | + cpy_phase['mjd'] = 52400 | |
| 165 | + cpy_phase['f0'] = 1. | |
| 166 | + cpy_phase['f1'] = -0.2 | |
| 167 | + cpy_phase['f2'] = 0. | |
| 168 | + cpy_phase['outobs'] = 'ctphase_py2.fits' | |
| 169 | + cpy_phase['logfile'] = 'ctphase_py2.log' | |
| 170 | + cpy_phase['chatter'] = 3 | |
| 171 | + cpy_phase['publish'] = True | |
| 172 | + cpy_phase.logFileOpen() # Needed to get a new log file | |
| 173 | + cpy_phase.execute() | |
| 174 | + self.test_try_failure('Exception not thrown') | |
| 175 | + except ValueError: | |
| 176 | + self.test_try_success() | |
| 177 | + | |
| 178 | + return | |
| 179 | + | |
| 180 | + # Check result file | |
| 181 | + def _check_result_file(self, filename, nevents=591, dec=22.01, rad=3.0): | |
| 182 | + """ | |
| 183 | + Check result file | |
| 184 | + | |
| 185 | + Parameters | |
| 186 | + ---------- | |
| 187 | + filename : str | |
| 188 | + Event list file name | |
| 189 | + nevents : int, optional | |
| 190 | + Expected number of events | |
| 191 | + dec : float, optional | |
| 192 | + Expected Declination (deg) | |
| 193 | + rad : float, optional | |
| 194 | + Expected radius (deg) | |
| 195 | + """ | |
| 196 | + # Open result file | |
| 197 | + events = gammalib.GCTAEventList(filename) | |
| 198 | + phases = [ events[i].phase() for i in range(events.size())] | |
| 199 | + test_result = int(sum(phases)>0) | |
| 200 | + self.test_value(test_result, 1, 'Check number of events') | |
| 201 | + | |
| 202 | + # Return | |
| 203 | + return | |
| 204 | + | |
| 205 | + # Check observation and event list | |
| 206 | + def _check_obs(self, obs, nobs=1): | |
| 207 | + """ | |
| 208 | + Check observation and event list | |
| 209 | + | |
| 210 | + Parameters | |
| 211 | + ---------- | |
| 212 | + obs : `~gammalib.GObservations` | |
| 213 | + Models | |
| 214 | + nobs : int, optional | |
| 215 | + Expected number of observations | |
| 216 | + nevents : int, optional | |
| 217 | + Expected number of events | |
| 218 | + """ | |
| 219 | + # Check number of observations | |
| 220 | + self.test_value(obs.size(), nobs, 'Check number of observations') | |
| 221 | + | |
| 222 | + # Return | |
| 223 | + return | ... | ... |
test/test_python_ctools.py
| ... | ... | @@ -25,6 +25,7 @@ import os |
| 25 | 25 | sys.path.append(os.path.dirname(os.path.abspath(__file__))) |
| 26 | 26 | import test_ctobssim |
| 27 | 27 | import test_ctselect |
| 28 | +import test_ctphase | |
| 28 | 29 | import test_ctbin |
| 29 | 30 | import test_ctlike |
| 30 | 31 | import test_cttsmap |
| ... | ... | @@ -102,6 +103,7 @@ def test(installed=False): |
| 102 | 103 | # Define list of test suites |
| 103 | 104 | tests = [test_ctobssim.Test(), |
| 104 | 105 | test_ctselect.Test(), |
| 106 | + test_ctphase.Test(), | |
| 105 | 107 | test_ctbin.Test(), |
| 106 | 108 | test_ctlike.Test(), |
| 107 | 109 | test_cttsmap.Test(), | ... | ... |