Commit ad1eef9b740f43214c89821ede9761995eb9b7f8

Authored by Jürgen Knödlseder
1 parent e00d5dd4

Add ctool::setup_observations() method to setup an observation container by comp…

…lementing missing information from user parameters.
pyext/ctool.i
... ... @@ -87,6 +87,7 @@ public:
87 87 %rename(_read_ahead) read_ahead() const;
88 88 %rename(_time_reference) time_reference() const;
89 89 %rename(_get_observations) get_observations(const bool& get_response = true);
  90 + %rename(_setup_observations) setup_observations(GObservations& obs);
90 91 %rename(_create_ebounds) create_ebounds();
91 92 %rename(_create_map) create_map(const GObservations& obs);
92 93 %rename(_create_cube) create_cube(const GObservations& obs);
... ... @@ -105,6 +106,7 @@ public:
105 106 const bool& read_ahead(void) const;
106 107 const GTimeReference& time_reference(void) const;
107 108 GObservations get_observations(const bool& get_response = true);
  109 + void setup_observations(GObservations& obs);
108 110  
109 111 // Protected methods that create objects from user parameters
110 112 GEbounds create_ebounds(void);
... ... @@ -170,14 +172,15 @@ public:
170 172  
171 173 # Initialise observation container from constructor arguments. In case that
172 174 # an observation container is provided as argument, this container will be
173   -# used to initialise the class.
  175 +# used to initialise the class. The function returns a tuple containing the
  176 +# observation container and the eventually reduced argument list.
174 177 def _set_input_obs(self, argv):
175 178 if len(argv) > 0 and isinstance(argv[0],gammalib.GObservations):
176 179 obs = argv[0]
177 180 argv = argv[1:]
178 181 else:
179 182 obs = gammalib.GObservations()
180   - return obs
  183 + return (obs, argv)
181 184 cscript._set_input_obs = _set_input_obs
182 185  
183 186 # Initialise application by calling the appropriate class constructor.
... ...
src/support/ctool.cpp
... ... @@ -49,6 +49,7 @@
49 49  
50 50  
51 51 /* __ Method name definitions ____________________________________________ */
  52 +#define G_SETUP_OBSERVATION "ctool::setup_observations(GObservations&)"
52 53 #define G_GET_MEAN_POINTING "ctool::get_mean_pointing(GObservations&)"
53 54 #define G_CREATE_EBOUNDS "ctool::create_ebounds()"
54 55 #define G_PROVIDE_HELP "ctool::provide_help()"
... ... @@ -378,7 +379,98 @@ GObservations ctool::get_observations(const bool& get_response)
378 379  
379 380 // Return observation container
380 381 return obs;
  382 +}
  383 +
  384 +
  385 +/***********************************************************************//**
  386 + * @brief Setup observation container
  387 + *
  388 + * @param[in] obs Observation container
  389 + *
  390 + * @exception GException::invalid_value
  391 + * Invalid "inobs" parameter encountered.
  392 + *
  393 + * Setup an observation container by appending all required information that
  394 + * is missing using user parameters.
  395 + *
  396 + * If the observation container @p obs is empty, the method will extract the
  397 + * filename from the "inobs" parameter, and if the filename is neither empty
  398 + * nor "NONE", will load the observation container from the specified file.
  399 + * If the file is a FITS file, and dependent on the information that is found
  400 + * in the FITS file, the method will append a single CTA observation to the
  401 + * observation container, containing either an event list or a counts cube.
  402 + * Otherwise, the method assumes that the file is an observation definition
  403 + * XML file and will load that file into the observation container.
  404 + *
  405 + * If the filename is empty or "NONE", the method will throw an exception.
  406 + *
  407 + * The method will then setup the response for all CTA observations in the
  408 + * container (see the set_response() method for more information).
  409 + *
  410 + * The method will furthermore setup the observation boundaries for all CTA
  411 + * observations in the container that contain event lists (see the
  412 + * set_obs_bounds() method for more information).
  413 + ***************************************************************************/
  414 +void ctool::setup_observations(GObservations& obs)
  415 +{
  416 + // Load observations if there are none in the container
  417 + if (obs.size() == 0) {
  418 +
  419 + // Get the filename from the "inobs" parameter
  420 + GFilename filename((*this)["inobs"].filename());
  421 +
  422 + // Load observation container from file if the filename is neither
  423 + // "NONE" nor empty ...
  424 + if ((gammalib::toupper(filename.url()) != "NONE") &&
  425 + !filename.is_empty()) {
  426 +
  427 + // If file does not exist then throw an exceptions
  428 + if (!filename.exists()) {
  429 + std::string msg = "The \"inobs\" parameter \""+filename+
  430 + "\" specifies a file that does not "
  431 + "exist. Please specify a valid event "
  432 + "list, counts cube or observation "
  433 + "definition XML file.";
  434 + throw GException::invalid_value(G_SETUP_OBSERVATION, msg);
  435 + }
  436 +
  437 + // If the file is a FITS file then load it into a CTA
  438 + // observation and append that observation to the container ...
  439 + else if (filename.is_fits()) {
  440 + GCTAObservation cta(filename);
  441 + obs.append(cta);
  442 + }
  443 +
  444 + // ... otherwise it is assumed that the file is an observation
  445 + // definition XML file and the file is loaded into the
  446 + // observation container
  447 + else {
  448 + obs.load(filename);
  449 + }
  450 +
  451 + }
  452 +
  453 + // ... otherwise, if the filename is "NONE" or empty then throw
  454 + // an exception.
  455 + else {
  456 + std::string msg = "The \"inobs\" parameter \""+filename+
  457 + "\" is not a valid filename. Please specify "
  458 + "a valid event list, counts cube or "
  459 + "observation definition XML file.";
  460 + throw GException::invalid_value(G_SETUP_OBSERVATION, msg);
  461 + }
  462 +
  463 + } // endif: there were no observations in the container
  464 +
  465 + // Setup the response for all CTA observations in the observation
  466 + // container
  467 + set_response(obs);
381 468  
  469 + // Setup boundaries for all CTA observations containing event lists
  470 + set_obs_bounds(obs);
  471 +
  472 + // Return
  473 + return;
382 474 }
383 475  
384 476  
... ... @@ -595,15 +687,16 @@ GCTAEventCube ctool::create_cube(const GObservations& obs)
595 687 * method furthermore sets the ontime, livetime and deadtime correction
596 688 * factor.
597 689 *
598   - * The following parameters are read:
599   - * ra - Right Ascension of pointing and RoI centre (deg)
600   - * dec - Declination of pointing and RoI centre (deg)
601   - * rad - Radius of RoI (deg)
602   - * deadc - Deadtime correction factor
603   - * tmin - Start time
604   - * tmax - Stop time
605   - * emin - Minimum energy (TeV)
606   - * emax - Maximum energy (TeV)
  690 + * The following parameters are read
  691 + *
  692 + * ra: Right Ascension of pointing and RoI centre (deg)
  693 + * dec: Declination of pointing and RoI centre (deg)
  694 + * rad: Radius of RoI (deg)
  695 + * deadc: Deadtime correction factor
  696 + * tmin: Start time
  697 + * tmax: Stop time
  698 + * emin: Minimum energy (TeV)
  699 + * emax: Maximum energy (TeV)
607 700 ***************************************************************************/
608 701 GCTAObservation ctool::create_cta_obs(void)
609 702 {
... ... @@ -804,12 +897,9 @@ void ctool::require_inobs_nocube(const std::string& method)
804 897 *
805 898 * @param[in,out] obs Observation container
806 899 *
807   - * Set the response for a CTA observations in the container that so far have
808   - * no response using the "caldb" and "irf" task parameters.
809   - *
810   - * The following parameters are read:
811   - * caldb - Calibration database
812   - * irf - Instrument response function
  900 + * Set the response for all CTA observations in the container that so far
  901 + * have no response information available. See the set_obs_response()
  902 + * method for more information about the user parameters that are read.
813 903 ***************************************************************************/
814 904 void ctool::set_response(GObservations& obs)
815 905 {
... ... @@ -841,69 +931,83 @@ void ctool::set_response(GObservations& obs)
841 931 *
842 932 * @param[in,out] obs CTA observation
843 933 *
844   - * Set the response for a CTA observation. If the CTA observation contains
  934 + * Set the response for one CTA observation. If the CTA observation contains
845 935 * a counts cube the method first attempts to set the response information
846   - * using the @a expcube and @a psfcube user parameters. If this is not
847   - * successful (for example because the parameters do not exist or their
848   - * value is NONE or blank), the method will set the response information
849   - * from the @a caldb and @a irf user parameters.
  936 + * using the following user parameters
  937 + *
  938 + * expcube: Exposure cube file
  939 + * psfcube: Point spread function cube file
  940 + * edispcube: Energy dispersion cube file (optional)
  941 + * bkgcube: Background cube file
  942 + *
  943 + * If none of the @p expcube, @p psfcube and @p bkgcube parameters is
  944 + * "NONE" or empty, the method will allocate a stacked response for the
  945 + * observation. In case that an energy dispersion cube is provided using
  946 + * the @p edispcube parameter, this energy dispersion cube is also loaded
  947 + * and attached to the stacked response function.
  948 + *
  949 + * In case that any of the @p expcube, @p psfcube and @p bkgcube parameters
  950 + * is "NONE" or empty, the method will assume that a IRF response should
  951 + * be used, and will attempty to set the response information using the
  952 + * following user parameters
  953 + *
  954 + * caldb: Calibration database
  955 + * irf: Instrument response function
850 956 *
851   - * The following parameters are read:
852   - * expcube - Exposure cube file (optional)
853   - * psfcube - PSF cube file (optional)
854   - * caldb - Calibration database (optional)
855   - * irf - Instrument response function (optional)
856 957 ***************************************************************************/
857 958 void ctool::set_obs_response(GCTAObservation* obs)
858 959 {
859 960 // Initialise response flag
860 961 bool has_response = false;
861 962  
862   - // If the observation contains a counts cube, then first check whether
863   - // the expcube and psfcube parameters exist and are not NONE
  963 + // If the observation contains a counts cube, then check whether
  964 + // response information for a stacked analysis is provided, and if so,
  965 + // set that response information for the CTA observation
864 966 if (dynamic_cast<const GCTAEventCube*>(obs->events()) != NULL) {
865 967 if (has_par("expcube") && has_par("psfcube") &&
866 968 has_par("edispcube") && has_par("bkgcube")) {
867 969  
868 970 // Get filenames
869   - std::string expcube = (*this)["expcube"].filename();
870   - std::string psfcube = (*this)["psfcube"].filename();
871   - std::string edispcube = (*this)["edispcube"].filename();
872   - std::string bkgcube = (*this)["bkgcube"].filename();
873   -
874   - // Extract response information if available
875   - if ((expcube != "NONE") && (psfcube != "NONE") &&
876   - (bkgcube != "NONE") &&
877   - (gammalib::strip_whitespace(expcube) != "") &&
878   - (gammalib::strip_whitespace(psfcube) != "") &&
879   - (gammalib::strip_whitespace(bkgcube) != "")) {
  971 + GFilename expcube((*this)["expcube"].filename());
  972 + GFilename psfcube((*this)["psfcube"].filename());
  973 + GFilename edispcube((*this)["edispcube"].filename());
  974 + GFilename bkgcube((*this)["bkgcube"].filename());
  975 +
  976 + // Extract stacked response information if available
  977 + if ((gammalib::toupper(expcube.url()) != "NONE") &&
  978 + (gammalib::toupper(psfcube.url()) != "NONE") &&
  979 + (gammalib::toupper(bkgcube.url()) != "NONE") &&
  980 + !expcube.is_empty() &&
  981 + !psfcube.is_empty() &&
  982 + !bkgcube.is_empty()) {
880 983  
881 984 // Get exposure, PSF and background cubes
882 985 GCTACubeExposure exposure(expcube);
883 986 GCTACubePsf psf(psfcube);
884 987 GCTACubeBackground background(bkgcube);
885 988  
886   - // Optionally load energy dispersion cube
887   - if ((edispcube != "NONE") &&
888   - (gammalib::strip_whitespace(edispcube) != "")) {
  989 + // If an energy dispersion cube is available, get also
  990 + // this cube, and set all information as stacked response
  991 + // for this CTA observation
  992 + if ((gammalib::toupper(edispcube.url()) != "NONE") &&
  993 + !edispcube.is_empty()) {
889 994 GCTACubeEdisp edisp(edispcube);
890 995 obs->response(exposure, psf, edisp, background);
891 996 }
892 997 else {
893   - // Set reponse
894 998 obs->response(exposure, psf, background);
895 999 }
896 1000  
897   - // Signal response availability
  1001 + // Signal that response is available
898 1002 has_response = true;
899 1003  
900 1004 } // endif: filenames were available
901 1005  
902   - } // endif: expcube and psfcube parameters exist
  1006 + } // endif: expcube, psfcube and bkdcube parameters valid
903 1007 } // endif: observation contains a counts cube
904 1008  
905   - // If we have not yet response information then get it now
906   - // from the caldb and irf parameters
  1009 + // If we have not yet response information then get it now from the
  1010 + // caldb and irf user parameters
907 1011 if (!has_response) {
908 1012  
909 1013 // Load response information
... ... @@ -938,59 +1042,70 @@ void ctool::set_obs_response(GCTAObservation* obs)
938 1042  
939 1043  
940 1044 /***********************************************************************//**
941   - * @brief Set observation boundaries
  1045 + * @brief Set observation boundaries for all CTA observations
942 1046 *
943 1047 * @param[in,out] obs Observation container
  1048 + *
  1049 + * Sets the observation boundaries for all CTA observations in the container
  1050 + * that contain event lists. If the energy boundaries of an event list are
  1051 + * empty, the method gets the
  1052 + *
  1053 + * emin: Minimum energy (TeV)
  1054 + * emax: Maximum energy (TeV)
  1055 + *
  1056 + * user parameters and sets a single energy boundary element @p [emin,emax].
  1057 + *
  1058 + * If the RoI radius of the event list is invalid, the method gets the
  1059 + *
  1060 + * rad: Region of Interest radius (deg)
  1061 + *
  1062 + * user parameter to set the radius of the RoI, and uses the CTA pointing
  1063 + * direction to set the centre of the RoI.
944 1064 ***************************************************************************/
945 1065 void ctool::set_obs_bounds(GObservations& obs)
946 1066 {
947   - // Setup response for all observations
  1067 + // Loop over all observations in the container
948 1068 for (int i = 0; i < obs.size(); ++i) {
949 1069  
950   - // Is this observation a CTA observation?
  1070 + // Get pointer to CTA observation
951 1071 GCTAObservation* cta = dynamic_cast<GCTAObservation*>(obs[i]);
952 1072  
953   - // Continue only if observation is CTA and has events
954   - if ((cta != NULL) && (cta->has_events())) {
955   -
956   - // Get pointer on event list
957   - GCTAEventList* list = const_cast<GCTAEventList*>(dynamic_cast<const GCTAEventList*>(cta->events()));
958   -
959   - // Continue only if it's valid
960   - if (list != NULL) {
961   -
962   - // If there are no energy boundaries then read the user
963   - // parameters and add them
964   - if (list->ebounds().is_empty()) {
965   -
966   - // If there are "emin" and "emax" parameters then use
967   - // them
968   - if (has_par("emin") && has_par("emax")) {
969   - double emin = (*this)["emin"].real();
970   - double emax = (*this)["emax"].real();
971   - GEbounds ebounds(GEnergy(emin, "TeV"),
972   - GEnergy(emax, "TeV"));
973   - list->ebounds(ebounds);
974   - }
975   -
976   - }
  1073 + // Fall through if observation is not a CTA observation or if it
  1074 + // does not contain events
  1075 + if ((cta == NULL) || (!cta->has_events())) {
  1076 + continue;
  1077 + }
977 1078  
978   - // If there is no ROI then read the user parameters and add
979   - // them
980   - if (list->roi().radius() == 0) {
981   -
982   - // If there is a "rad" parameter then use it
983   - if (has_par("rad")) {
984   - double rad = (*this)["rad"].real();
985   - GCTARoi roi(GCTAInstDir(cta->pointing().dir()), rad);
986   - list->roi(roi);
987   - }
  1079 + // Get pointer on CTA event list
  1080 + GCTAEventList* list = const_cast<GCTAEventList*>
  1081 + (dynamic_cast<const GCTAEventList*>(cta->events()));
988 1082  
989   - }
  1083 + // Fall through if CTA observation does not contain an event list
  1084 + if (list == NULL) {
  1085 + continue;
  1086 + }
990 1087  
991   - } // endif: list was valid
  1088 + // If there are no energy boundaries then read the "emin" and "emax"
  1089 + // user parameters and add them
  1090 + if (list->ebounds().is_empty()) {
  1091 + if (has_par("emin") && has_par("emax")) {
  1092 + double emin((*this)["emin"].real());
  1093 + double emax((*this)["emax"].real());
  1094 + GEbounds ebounds(GEnergy(emin, "TeV"),
  1095 + GEnergy(emax, "TeV"));
  1096 + list->ebounds(ebounds);
  1097 + }
  1098 + }
992 1099  
993   - } // endif: observation was CTA
  1100 + // If there is no RoI then read the "rad" user parameters and use
  1101 + // the pointing direction to set the RoI
  1102 + if (list->roi().radius() == 0) {
  1103 + if (has_par("rad")) {
  1104 + double rad = (*this)["rad"].real();
  1105 + GCTARoi roi(GCTAInstDir(cta->pointing().dir()), rad);
  1106 + list->roi(roi);
  1107 + }
  1108 + }
994 1109  
995 1110 } // endfor: looped over observations
996 1111  
... ...
src/support/ctool.hpp
... ... @@ -72,6 +72,7 @@ protected:
72 72 const bool& read_ahead(void) const;
73 73 const GTimeReference& time_reference(void) const;
74 74 GObservations get_observations(const bool& get_response = true);
  75 + void setup_observations(GObservations& obs);
75 76  
76 77 // Protected methods that create objects from user parameters
77 78 GEbounds create_ebounds(void);
... ...