Commit bb9410c7c406e17d9246fc02016e65b46518d4a8

Authored by Josh Cardenzana
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.
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
... ... @@ -61,6 +61,7 @@ namespace std {
61 61 %include "ctlike.i"
62 62 %include "ctmodel.i"
63 63 %include "ctselect.i"
  64 +%include "ctphase.i"
64 65 %include "ctskymap.i"
65 66 %include "ctexpcube.i"
66 67 %include "ctpsfcube.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&amp; 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&amp; 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, &quot;phased_events.fits&quot;,,, &quot;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,,, &quot;Publish event list on VO Hub?&quot;
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(),
... ...