Commit eb131e63aa1cdc9f2b451e5f2da95f4af7adfc49

Authored by Jürgen Knödlseder
2 parents 76e21e25 6f4762d7

Merge branch '1039-allow-energy-thresholds-via-IRF-and-XML' into integration

ChangeLog
1   -2014-10-31 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
  1 +2014-11-07 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 2  
3 3 * Version 0.9.0 released
4 4 ========================
... ... @@ -34,6 +34,7 @@
34 34 Introduce class codes to avoid dynamic type casting
35 35 Remove error computation from optimization
36 36 Add GOptimize::errors() method for error computation
  37 + Add support for user and save CTA energy thresholds
37 38 Several bug corrections
38 39  
39 40  
... ...
... ... @@ -2,7 +2,7 @@ New Features and Important Changes in GammaLib 00-09-00
2 2  
3 3 Author(s) : Juergen Knoedlseder
4 4  
5   -31 October 2014
  5 +7 November 2014
6 6  
7 7  
8 8 1. Introduction
... ... @@ -307,6 +307,11 @@ Events are now only loaded when needed into GCTAObservation. This reduces memory
307 307 the usage. The method dispose_events() has been added to explicitely allow the
308 308 disposal of the events.
309 309  
  310 +Support for user provided energy thresholds and save energy thresholds has been
  311 +implemented. Save energy thresholds will be extracted from the LO_THRES and
  312 +HI_THRES keywords if they are present in the effective area response FITS
  313 +file. The user may supply energy thresholds in the XML file.
  314 +
310 315  
311 316 21. COMPTEL interface
312 317 ---------------------
... ...
inst/cta/include/GCTAObservation.hpp
... ... @@ -120,6 +120,8 @@ public:
120 120 void eventfile(const std::string& filename);
121 121 const std::string& eventfile(void) const;
122 122 void dispose_events(void);
  123 + const double& lo_user_thres(void) const;
  124 + const double& hi_user_thres(void) const;
123 125  
124 126 protected:
125 127 // Protected methods
... ... @@ -131,17 +133,19 @@ protected:
131 133 void set_event_type(void);
132 134  
133 135 // Protected members
134   - std::string m_instrument; //!< Instrument name
135   - std::string m_eventfile; //!< Event filename
136   - std::string m_eventtype; //!< Event type (for XML file)
137   - GCTAResponse* m_response; //!< Pointer to instrument response functions
138   - GCTAPointing m_pointing; //!< Pointing direction
139   - int m_obs_id; //!< Observation ID
140   - double m_ontime; //!< Ontime (seconds)
141   - double m_livetime; //!< Livetime (seconds)
142   - double m_deadc; //!< Deadtime correction (livetime/ontime)
143   - double m_ra_obj; //!< Right Ascension of object (degrees)
144   - double m_dec_obj; //!< Declination of object (degrees)
  136 + std::string m_instrument; //!< Instrument name
  137 + std::string m_eventfile; //!< Event filename
  138 + std::string m_eventtype; //!< Event type (for XML file)
  139 + GCTAResponse* m_response; //!< Pointer to instrument response functions
  140 + GCTAPointing m_pointing; //!< Pointing direction
  141 + int m_obs_id; //!< Observation ID
  142 + double m_ontime; //!< Ontime (seconds)
  143 + double m_livetime; //!< Livetime (seconds)
  144 + double m_deadc; //!< Deadtime correction (livetime/ontime)
  145 + double m_ra_obj; //!< Right Ascension of object (degrees)
  146 + double m_dec_obj; //!< Declination of object (degrees)
  147 + double m_lo_user_thres; //!< User defined lower energy threshold
  148 + double m_hi_user_thres; //!< User defined upper energy boundary
145 149  
146 150 // Special protected member for GCTAModelCubeBackground friend
147 151 std::string m_bgdfile; //!< Background filename
... ... @@ -387,4 +391,30 @@ const std::string&amp; GCTAObservation::eventfile(void) const
387 391 return m_eventfile;
388 392 }
389 393  
  394 +
  395 +/***********************************************************************//**
  396 + * @brief Return user low energy threshold
  397 + *
  398 + * @return User low energy threshold.
  399 + ***************************************************************************/
  400 +inline
  401 +const double& GCTAObservation::lo_user_thres(void) const
  402 +{
  403 + return m_lo_user_thres;
  404 +}
  405 +
  406 +/***********************************************************************//**
  407 + * @brief Return user high energy threshold
  408 + *
  409 + * @return User high energy threshold.
  410 + ***************************************************************************/
  411 +inline
  412 +const double& GCTAObservation::hi_user_thres(void) const
  413 +{
  414 + return m_hi_user_thres;
  415 +}
  416 +
  417 +
  418 +
  419 +
390 420 #endif /* GCTAOBSERVATION_HPP */
... ...
inst/cta/include/GCTAResponse.hpp
... ... @@ -93,6 +93,7 @@ protected:
93 93 const GObservation& obs) const;
94 94 const GCTAInstDir& retrieve_dir(const std::string& origin,
95 95 const GEvent& event) const;
  96 +
96 97 };
97 98  
98 99 #endif /* GCTARESPONSE_HPP */
... ...
inst/cta/include/GCTAResponseIrf.hpp
... ... @@ -127,6 +127,8 @@ public:
127 127 void edisp(GCTAEdisp* edisp);
128 128 const GCTABackground* background(void) const;
129 129 void background(GCTABackground* background);
  130 + const double& lo_save_thres(void) const;
  131 + const double& hi_save_thres(void) const;
130 132  
131 133 // Low-level response methods
132 134 double aeff(const double& theta,
... ... @@ -177,6 +179,8 @@ private:
177 179 GCTAEdisp* m_edisp; //!< Energy dispersion
178 180 GCTABackground* m_background; //!< Energy dispersion
179 181 mutable bool m_apply_edisp; //!< Apply energy dispersion
  182 + double m_lo_save_thres; //!< Save low energy threshold
  183 + double m_hi_save_thres; //!< Save high energy threshold
180 184  
181 185 // XML response filename
182 186 std::string m_xml_caldb; //!< Calibration database string in XML file
... ... @@ -398,4 +402,26 @@ void GCTAResponseIrf::background(GCTABackground* background)
398 402 return;
399 403 }
400 404  
  405 +/***********************************************************************//**
  406 + * @brief Return low energy threshold from IRF
  407 + *
  408 + * @return Low energy threshold from IRF.
  409 + ***************************************************************************/
  410 +inline
  411 +const double& GCTAResponseIrf::lo_save_thres(void) const
  412 +{
  413 + return m_lo_save_thres;
  414 +}
  415 +
  416 +/***********************************************************************//**
  417 + * @brief Return high energy threshold from IRF
  418 + *
  419 + * @return High energy threshold from IRF.
  420 + ***************************************************************************/
  421 +inline
  422 +const double& GCTAResponseIrf::hi_save_thres(void) const
  423 +{
  424 + return m_hi_save_thres;
  425 +}
  426 +
401 427 #endif /* GCTARESPONSEIRF_HPP */
... ...
inst/cta/pyext/GCTAObservation.i
... ... @@ -93,6 +93,8 @@ public:
93 93 void eventfile(const std::string& filename);
94 94 const std::string& eventfile(void) const;
95 95 void dispose_events(void);
  96 + const double& lo_user_thres(void) const;
  97 + const double& hi_user_thres(void) const;
96 98 };
97 99  
98 100  
... ...
inst/cta/src/GCTAObservation.cpp
... ... @@ -638,7 +638,10 @@ GEbounds GCTAObservation::ebounds(void) const
638 638 * ...
639 639 * </observation>
640 640 *
641   - * for a binned observation.
  641 + * for a binned observation. Optional user energy thresholds can be
  642 + * specified by adding the emin and emax attributes:
  643 + *
  644 + * <observation name="..." id="..." instrument="..." emin="..." emax="...">
642 645 *
643 646 * The method does no load the events into memory but stores the file name
644 647 * of the event file. The events are only loaded when required. This reduces
... ... @@ -653,6 +656,14 @@ void GCTAObservation::read(const GXmlElement&amp; xml)
653 656 // Extract instrument name
654 657 m_instrument = xml.attribute("instrument");
655 658  
  659 + // Read in user defined energy boundaries of this observation
  660 + if (xml.attribute("emin") != "") {
  661 + m_lo_user_thres = gammalib::todouble(xml.attribute("emin"));
  662 + }
  663 + if (xml.attribute("emax") != "") {
  664 + m_hi_user_thres = gammalib::todouble(xml.attribute("emax"));
  665 + }
  666 +
656 667 // Determine number of parameter nodes in XML element
657 668 int npars = xml.elements("parameter");
658 669  
... ... @@ -793,7 +804,12 @@ void GCTAObservation::read(const GXmlElement&amp; xml)
793 804 * ...
794 805 * </observation>
795 806 *
796   - * for a binned observation.
  807 + * for a binned observation. If user energy threshold are defined (i.e.
  808 + * threshold values are >0) the additional emin and emax attributes will
  809 + * be written to the file:
  810 + *
  811 + * <observation name="..." id="..." instrument="..." emin="..." emax="...">
  812 + *
797 813 ***************************************************************************/
798 814 void GCTAObservation::write(GXmlElement& xml) const
799 815 {
... ... @@ -813,6 +829,14 @@ void GCTAObservation::write(GXmlElement&amp; xml) const
813 829 throw GException::invalid_value(G_WRITE, msg);
814 830 }
815 831  
  832 + // Add user energy threshold attributes (if set)
  833 + if (m_lo_user_thres > 0.0) {
  834 + xml.attribute("emin", gammalib::str(m_lo_user_thres));
  835 + }
  836 + if (m_hi_user_thres > 0.0) {
  837 + xml.attribute("emax", gammalib::str(m_hi_user_thres));
  838 + }
  839 +
816 840 // If XML element has 0 nodes then add the required parameter nodes
817 841 if (xml.elements() == 0) {
818 842 std::string text = "parameter name=\""+m_eventtype+"\"";
... ... @@ -1033,6 +1057,7 @@ void GCTAObservation::load(const std::string&amp; cntcube,
1033 1057 ***************************************************************************/
1034 1058 void GCTAObservation::save(const std::string& filename, const bool& clobber) const
1035 1059 {
  1060 +
1036 1061 // Create FITS file
1037 1062 GFits fits;
1038 1063  
... ... @@ -1173,6 +1198,28 @@ std::string GCTAObservation::print(const GChatter&amp; chatter) const
1173 1198 result.append("\n"+gammalib::parformat("Deadtime correction"));
1174 1199 result.append(gammalib::str(m_deadc));
1175 1200  
  1201 + // Append user energy threshold information
  1202 + result.append("\n"+gammalib::parformat("User energy range"));
  1203 + if (m_lo_user_thres > 0.0 && m_hi_user_thres) {
  1204 + result.append(gammalib::str(m_lo_user_thres));
  1205 + result.append(" - ");
  1206 + result.append(gammalib::str(m_hi_user_thres));
  1207 + result.append(" TeV");
  1208 + }
  1209 + else if (m_lo_user_thres > 0.0) {
  1210 + result.append("> ");
  1211 + result.append(gammalib::str(m_lo_user_thres));
  1212 + result.append(" TeV");
  1213 + }
  1214 + else if (m_hi_user_thres > 0.0) {
  1215 + result.append("< ");
  1216 + result.append(gammalib::str(m_hi_user_thres));
  1217 + result.append(" TeV");
  1218 + }
  1219 + else {
  1220 + result.append("undefined");
  1221 + }
  1222 +
1176 1223 // Append detailed information
1177 1224 GChatter reduced_chatter = gammalib::reduce(chatter);
1178 1225 if (reduced_chatter > SILENT) {
... ... @@ -1221,12 +1268,14 @@ void GCTAObservation::init_members(void)
1221 1268 m_bgdfile.clear();
1222 1269 m_response = NULL;
1223 1270 m_pointing.clear();
1224   - m_obs_id = 0;
1225   - m_ontime = 0.0;
1226   - m_livetime = 0.0;
1227   - m_deadc = 0.0;
1228   - m_ra_obj = 0.0;
1229   - m_dec_obj = 0.0;
  1271 + m_obs_id = 0;
  1272 + m_ontime = 0.0;
  1273 + m_livetime = 0.0;
  1274 + m_deadc = 0.0;
  1275 + m_ra_obj = 0.0;
  1276 + m_dec_obj = 0.0;
  1277 + m_lo_user_thres = 0.0;
  1278 + m_hi_user_thres = 0.0;
1230 1279  
1231 1280 // Return
1232 1281 return;
... ... @@ -1241,17 +1290,19 @@ void GCTAObservation::init_members(void)
1241 1290 void GCTAObservation::copy_members(const GCTAObservation& obs)
1242 1291 {
1243 1292 // Copy members
1244   - m_instrument = obs.m_instrument;
1245   - m_eventfile = obs.m_eventfile;
1246   - m_eventtype = obs.m_eventtype;
1247   - m_bgdfile = obs.m_bgdfile;
1248   - m_pointing = obs.m_pointing;
1249   - m_obs_id = obs.m_obs_id;
1250   - m_ontime = obs.m_ontime;
1251   - m_livetime = obs.m_livetime;
1252   - m_deadc = obs.m_deadc;
1253   - m_ra_obj = obs.m_ra_obj;
1254   - m_dec_obj = obs.m_dec_obj;
  1293 + m_instrument = obs.m_instrument;
  1294 + m_eventfile = obs.m_eventfile;
  1295 + m_eventtype = obs.m_eventtype;
  1296 + m_bgdfile = obs.m_bgdfile;
  1297 + m_pointing = obs.m_pointing;
  1298 + m_obs_id = obs.m_obs_id;
  1299 + m_ontime = obs.m_ontime;
  1300 + m_livetime = obs.m_livetime;
  1301 + m_deadc = obs.m_deadc;
  1302 + m_ra_obj = obs.m_ra_obj;
  1303 + m_dec_obj = obs.m_dec_obj;
  1304 + m_lo_user_thres = obs.m_lo_user_thres;
  1305 + m_hi_user_thres = obs.m_hi_user_thres;
1255 1306  
1256 1307 // Clone members
1257 1308 m_response = (obs.m_response != NULL) ? obs.m_response->clone() : NULL;
... ...
inst/cta/src/GCTAResponseIrf.cpp
... ... @@ -948,15 +948,47 @@ void GCTAResponseIrf::load_aeff(const std::string&amp; filename)
948 948 // If file contains an "EFFECTIVE AREA" extension then load it
949 949 // as CTA response table
950 950 if (file.contains("EFFECTIVE AREA")) {
  951 +
  952 + // Get HDU
  953 + const GFitsHDU* hdu = file.at("EFFECTIVE AREA");
  954 +
  955 + // Read save energy thresholds if available
  956 + if (hdu->has_card("LO_THRES")) {
  957 + m_lo_save_thres = hdu->real("LO_THRES");
  958 + }
  959 + if (hdu->has_card("HI_THRES")) {
  960 + m_hi_save_thres = hdu->real("HI_THRES");
  961 + }
  962 +
  963 + // Close file
951 964 file.close();
  965 +
  966 + // Allocate Aeff from file
952 967 m_aeff = new GCTAAeff2D(filename);
  968 +
953 969 }
954 970  
955 971 // ... else if file contains a "SPECRESP" extension then load it
956 972 // as ARF
957 973 else if (file.contains("SPECRESP")) {
  974 +
  975 + // Get HDU
  976 + const GFitsHDU* hdu = file.at("SPECRESP");
  977 +
  978 + // Read save energy thresholds if available
  979 + if (hdu->has_card("LO_THRES")) {
  980 + m_lo_save_thres = hdu->real("LO_THRES");
  981 + }
  982 + if (hdu->has_card("LO_THRES")) {
  983 + m_hi_save_thres = hdu->real("HI_THRES");
  984 + }
  985 +
  986 + // Close file
958 987 file.close();
  988 +
  989 + // Allocate Aeff from file
959 990 m_aeff = new GCTAAeffArf(filename);
  991 +
960 992 }
961 993  
962 994 }
... ... @@ -1221,6 +1253,28 @@ std::string GCTAResponseIrf::print(const GChatter&amp; chatter) const
1221 1253 }
1222 1254 }
1223 1255  
  1256 + // Append save energy threshold information
  1257 + result.append("\n"+gammalib::parformat("Save energy range"));
  1258 + if (m_lo_save_thres > 0.0 && m_hi_save_thres) {
  1259 + result.append(gammalib::str(m_lo_save_thres));
  1260 + result.append(" - ");
  1261 + result.append(gammalib::str(m_hi_save_thres));
  1262 + result.append(" TeV");
  1263 + }
  1264 + else if (m_lo_save_thres > 0.0) {
  1265 + result.append("> ");
  1266 + result.append(gammalib::str(m_lo_save_thres));
  1267 + result.append(" TeV");
  1268 + }
  1269 + else if (m_hi_save_thres > 0.0) {
  1270 + result.append("< ");
  1271 + result.append(gammalib::str(m_hi_save_thres));
  1272 + result.append(" TeV");
  1273 + }
  1274 + else {
  1275 + result.append("undefined");
  1276 + }
  1277 +
1224 1278 // Append calibration database
1225 1279 result.append("\n"+m_caldb.print(chatter));
1226 1280  
... ... @@ -2905,11 +2959,13 @@ void GCTAResponseIrf::init_members(void)
2905 2959 // Initialise members
2906 2960 m_caldb.clear();
2907 2961 m_rspname.clear();
2908   - m_aeff = NULL;
2909   - m_psf = NULL;
2910   - m_edisp = NULL;
2911   - m_background = NULL;
2912   - m_apply_edisp = false; //!< Switched off by default
  2962 + m_aeff = NULL;
  2963 + m_psf = NULL;
  2964 + m_edisp = NULL;
  2965 + m_background = NULL;
  2966 + m_apply_edisp = false; //!< Switched off by default
  2967 + m_lo_save_thres = 0.0;
  2968 + m_hi_save_thres = 0.0;
2913 2969  
2914 2970 // XML response filenames
2915 2971 m_xml_caldb.clear();
... ... @@ -2938,9 +2994,11 @@ void GCTAResponseIrf::init_members(void)
2938 2994 void GCTAResponseIrf::copy_members(const GCTAResponseIrf& rsp)
2939 2995 {
2940 2996 // Copy members
2941   - m_caldb = rsp.m_caldb;
2942   - m_rspname = rsp.m_rspname;
2943   - m_apply_edisp = rsp.m_apply_edisp;
  2997 + m_caldb = rsp.m_caldb;
  2998 + m_rspname = rsp.m_rspname;
  2999 + m_apply_edisp = rsp.m_apply_edisp;
  3000 + m_lo_save_thres = rsp.m_lo_save_thres;
  3001 + m_hi_save_thres = rsp.m_hi_save_thres;
2944 3002  
2945 3003 // Copy response filenames
2946 3004 m_xml_caldb = rsp.m_xml_caldb;
... ...
src/obs/GObservations.cpp
... ... @@ -646,7 +646,7 @@ void GObservations::write(GXml&amp; xml) const
646 646  
647 647 // Write all observations into library
648 648 for (int i = 0; i < size(); ++i) {
649   -
  649 +
650 650 // Initialise pointer on observation
651 651 GXmlElement* obs = NULL;
652 652  
... ... @@ -670,7 +670,7 @@ void GObservations::write(GXml&amp; xml) const
670 670 obs->attribute("id", m_obs[i]->id());
671 671 obs->attribute("instrument", m_obs[i]->instrument());
672 672 }
673   -
  673 +
674 674 // Write now observation
675 675 m_obs[i]->write(*obs);
676 676  
... ...