Commit f54cd3020f284c6d6262c9fa3e05ff72faaa04cc
1 parent
92d74e59
Adjust the interface for On/Off observations
Showing
4 changed files
with
423 additions
and
495 deletions
inst/cta/include/GCTAOnOffObservation.hpp
| @@ -40,20 +40,33 @@ | @@ -40,20 +40,33 @@ | ||
| 40 | class GModels; | 40 | class GModels; |
| 41 | class GOptimizerPars; | 41 | class GOptimizerPars; |
| 42 | class GCTAObservation; | 42 | class GCTAObservation; |
| 43 | +class GBounds; | ||
| 43 | 44 | ||
| 44 | 45 | ||
| 45 | /***********************************************************************//** | 46 | /***********************************************************************//** |
| 46 | * @class GCTAOnOffObservation | 47 | * @class GCTAOnOffObservation |
| 47 | * | 48 | * |
| 48 | * @brief CTA On/Off observation class | 49 | * @brief CTA On/Off observation class |
| 50 | + * | ||
| 51 | + * This class defines a CTA On/Off observation. An On/Off observation is | ||
| 52 | + * defined by two spectra, one for an On region including the source of | ||
| 53 | + * interest, and one for an Off region including only background. The | ||
| 54 | + * response of an On/Off observation is given by the Auxiliary Response File | ||
| 55 | + * (ARF) and the Redistribution Matrix File (RMF). | ||
| 56 | + * | ||
| 57 | + * The class uses GPha objects to store the On and Off spectra, and GArf and | ||
| 58 | + * GRmf objects to store the response information. | ||
| 49 | ***************************************************************************/ | 59 | ***************************************************************************/ |
| 50 | class GCTAOnOffObservation : public GObservation { | 60 | class GCTAOnOffObservation : public GObservation { |
| 51 | 61 | ||
| 52 | public: | 62 | public: |
| 53 | // Constructors and destructors | 63 | // Constructors and destructors |
| 54 | GCTAOnOffObservation(void); | 64 | GCTAOnOffObservation(void); |
| 55 | - GCTAOnOffObservation(const GEbounds& ereco, const GSkyRegions& on, | ||
| 56 | - const GSkyRegions& off); | 65 | + GCTAOnOffObservation(const GCTAObservation& obs, |
| 66 | + const GEbounds& etrue, | ||
| 67 | + const GEbounds& ereco, | ||
| 68 | + const GSkyRegions& on, | ||
| 69 | + const GSkyRegions& off); | ||
| 57 | GCTAOnOffObservation(const GCTAOnOffObservation& obs); | 70 | GCTAOnOffObservation(const GCTAOnOffObservation& obs); |
| 58 | virtual ~GCTAOnOffObservation(void); | 71 | virtual ~GCTAOnOffObservation(void); |
| 59 | 72 | ||
| @@ -82,28 +95,28 @@ public: | @@ -82,28 +95,28 @@ public: | ||
| 82 | virtual int nobserved(void) const; | 95 | virtual int nobserved(void) const; |
| 83 | 96 | ||
| 84 | // Other methods | 97 | // Other methods |
| 85 | - void instrument(const std::string& instrument); | ||
| 86 | - void on_regions(const GSkyRegions& regions); | ||
| 87 | - void off_regions(const GSkyRegions& regions); | ||
| 88 | - const GPha& on_spec(void) const; | ||
| 89 | - const GPha& off_spec(void) const; | ||
| 90 | - const GArf& arf(void) const; | ||
| 91 | - const GRmf& rmf(void) const; | ||
| 92 | - void fill(const GCTAObservation& obs); | ||
| 93 | - void compute_response(const GCTAObservation& obs, | ||
| 94 | - const GEbounds& etrue); | 98 | + void instrument(const std::string& instrument); |
| 99 | + void on_regions(const GSkyRegions& regions); | ||
| 100 | + void off_regions(const GSkyRegions& regions); | ||
| 101 | + const GSkyRegions& on_regions(void) const; | ||
| 102 | + const GSkyRegions& off_regions(void) const; | ||
| 103 | + const GPha& on_spec(void) const; | ||
| 104 | + const GPha& off_spec(void) const; | ||
| 105 | + const GArf& arf(void) const; | ||
| 106 | + const GRmf& rmf(void) const; | ||
| 95 | 107 | ||
| 96 | protected: | 108 | protected: |
| 97 | // Protected methods | 109 | // Protected methods |
| 98 | void init_members(void); | 110 | void init_members(void); |
| 99 | void copy_members(const GCTAOnOffObservation& obs); | 111 | void copy_members(const GCTAOnOffObservation& obs); |
| 100 | void free_members(void); | 112 | void free_members(void); |
| 101 | - void compute_alpha(const GCTAObservation& obs); | 113 | + void set(const GCTAObservation& obs); |
| 102 | void compute_arf(const GCTAObservation& obs); | 114 | void compute_arf(const GCTAObservation& obs); |
| 103 | void compute_bgd(const GCTAObservation& obs); | 115 | void compute_bgd(const GCTAObservation& obs); |
| 104 | - void compute_rmf(const GCTAObservation& obs, const GEbounds& etrue); | ||
| 105 | - double model_on(const GModels& models, int ibin, GVector* mod_grad) const; | ||
| 106 | - double model_off(const GModels& models, int ibin, GVector* mod_grad) const; | 116 | + void compute_alpha(const GCTAObservation& obs); |
| 117 | + void compute_rmf(const GCTAObservation& obs); | ||
| 118 | + double N_gamma(const GModels& models, const int& ibin, GVector* grad) const; | ||
| 119 | + double N_bgd(const GModels& models, const int& ibin, GVector* grad) const; | ||
| 107 | 120 | ||
| 108 | // Protected data members | 121 | // Protected data members |
| 109 | std::string m_instrument; //!< Instrument name | 122 | std::string m_instrument; //!< Instrument name |
| @@ -228,9 +241,33 @@ void GCTAOnOffObservation::off_regions(const GSkyRegions& regions) | @@ -228,9 +241,33 @@ void GCTAOnOffObservation::off_regions(const GSkyRegions& regions) | ||
| 228 | 241 | ||
| 229 | 242 | ||
| 230 | /***********************************************************************//** | 243 | /***********************************************************************//** |
| 231 | - * @brief Return ON spectrum | 244 | + * @brief Return On regions |
| 245 | + * | ||
| 246 | + * @return On regions. | ||
| 247 | + ***************************************************************************/ | ||
| 248 | +inline | ||
| 249 | +const GSkyRegions& GCTAOnOffObservation::on_regions(void) const | ||
| 250 | +{ | ||
| 251 | + return (m_on_regions); | ||
| 252 | +} | ||
| 253 | + | ||
| 254 | + | ||
| 255 | +/***********************************************************************//** | ||
| 256 | + * @brief Return Off regions | ||
| 257 | + * | ||
| 258 | + * @return Off regions. | ||
| 259 | + ***************************************************************************/ | ||
| 260 | +inline | ||
| 261 | +const GSkyRegions& GCTAOnOffObservation::off_regions(void) const | ||
| 262 | +{ | ||
| 263 | + return (m_off_regions); | ||
| 264 | +} | ||
| 265 | + | ||
| 266 | + | ||
| 267 | +/***********************************************************************//** | ||
| 268 | + * @brief Return On spectrum | ||
| 232 | * | 269 | * |
| 233 | - * @return ON spectrum. | 270 | + * @return On spectrum. |
| 234 | ***************************************************************************/ | 271 | ***************************************************************************/ |
| 235 | inline | 272 | inline |
| 236 | const GPha& GCTAOnOffObservation::on_spec(void) const | 273 | const GPha& GCTAOnOffObservation::on_spec(void) const |
| @@ -240,9 +277,9 @@ const GPha& GCTAOnOffObservation::on_spec(void) const | @@ -240,9 +277,9 @@ const GPha& GCTAOnOffObservation::on_spec(void) const | ||
| 240 | 277 | ||
| 241 | 278 | ||
| 242 | /***********************************************************************//** | 279 | /***********************************************************************//** |
| 243 | - * @brief Return OFF spectrum | 280 | + * @brief Return Off spectrum |
| 244 | * | 281 | * |
| 245 | - * @return OFF spectrum. | 282 | + * @return Off spectrum. |
| 246 | ***************************************************************************/ | 283 | ***************************************************************************/ |
| 247 | inline | 284 | inline |
| 248 | const GPha& GCTAOnOffObservation::off_spec(void) const | 285 | const GPha& GCTAOnOffObservation::off_spec(void) const |
inst/cta/pyext/GCTAOnOffObservation.i
| @@ -63,8 +63,11 @@ class GCTAOnOffObservation : public GObservation { | @@ -63,8 +63,11 @@ class GCTAOnOffObservation : public GObservation { | ||
| 63 | public: | 63 | public: |
| 64 | // Constructors and destructors | 64 | // Constructors and destructors |
| 65 | GCTAOnOffObservation(void); | 65 | GCTAOnOffObservation(void); |
| 66 | - GCTAOnOffObservation(const GEbounds& ereco, const GSkyRegions& on, | ||
| 67 | - const GSkyRegions& off); | 66 | + GCTAOnOffObservation(const GCTAObservation& obs, |
| 67 | + const GEbounds& etrue, | ||
| 68 | + const GEbounds& ereco, | ||
| 69 | + const GSkyRegions& on, | ||
| 70 | + const GSkyRegions& off); | ||
| 68 | GCTAOnOffObservation(const GCTAOnOffObservation& obs); | 71 | GCTAOnOffObservation(const GCTAOnOffObservation& obs); |
| 69 | virtual ~GCTAOnOffObservation(void); | 72 | virtual ~GCTAOnOffObservation(void); |
| 70 | 73 | ||
| @@ -89,16 +92,15 @@ public: | @@ -89,16 +92,15 @@ public: | ||
| 89 | virtual int nobserved(void) const; | 92 | virtual int nobserved(void) const; |
| 90 | 93 | ||
| 91 | // Other methods | 94 | // Other methods |
| 92 | - void instrument(const std::string& instrument); | ||
| 93 | - void on_regions(const GSkyRegions& regions); | ||
| 94 | - void off_regions(const GSkyRegions& regions); | ||
| 95 | - const GPha& on_spec(void) const; | ||
| 96 | - const GPha& off_spec(void) const; | ||
| 97 | - const GArf& arf(void) const; | ||
| 98 | - const GRmf& rmf(void) const; | ||
| 99 | - void fill(const GCTAObservation& obs); | ||
| 100 | - void compute_response(const GCTAObservation& obs, | ||
| 101 | - const GEbounds& etrue); | 95 | + void instrument(const std::string& instrument); |
| 96 | + void on_regions(const GSkyRegions& regions); | ||
| 97 | + void off_regions(const GSkyRegions& regions); | ||
| 98 | + const GSkyRegions& on_regions(void) const; | ||
| 99 | + const GSkyRegions& off_regions(void) const; | ||
| 100 | + const GPha& on_spec(void) const; | ||
| 101 | + const GPha& off_spec(void) const; | ||
| 102 | + const GArf& arf(void) const; | ||
| 103 | + const GRmf& rmf(void) const; | ||
| 102 | }; | 104 | }; |
| 103 | 105 | ||
| 104 | 106 |
inst/cta/src/GCTAOnOffObservation.cpp
| @@ -55,16 +55,15 @@ const GObservationRegistry g_onoff_obs_cta_registry(&g_onoff_obs_cta_seed); | @@ -55,16 +55,15 @@ const GObservationRegistry g_onoff_obs_cta_registry(&g_onoff_obs_cta_seed); | ||
| 55 | #define G_RESPONSE_GET "GCTAOnOffObservation::response()" | 55 | #define G_RESPONSE_GET "GCTAOnOffObservation::response()" |
| 56 | #define G_WRITE "GCTAOnOffObservation::write(GXmlElement&)" | 56 | #define G_WRITE "GCTAOnOffObservation::write(GXmlElement&)" |
| 57 | #define G_READ "GCTAOnOffObservation::read(GXmlElement&)" | 57 | #define G_READ "GCTAOnOffObservation::read(GXmlElement&)" |
| 58 | -#define G_FILL "GCTAOnOffObservation::fill(GCTAObservation&)" | ||
| 59 | -#define G_COMPUTE_ALPHA "GCTAOnOffObservation::compute_alpha("\ | ||
| 60 | - "GCTAObservation&)" | ||
| 61 | -#define G_COMPUTE_ARF "GCTAOnOffObservation::compute_arf(GCTAObservation&)" | ||
| 62 | -#define G_COMPUTE_BGD "GCTAOnOffObservation::compute_bgd(GCTAObservation&)" | ||
| 63 | -#define G_COMPUTE_RMF "GCTAOnOffObservation::compute_rmf(GCTAObservation&,"\ | ||
| 64 | - " GEbounds&)" | ||
| 65 | #define G_LIKELIHOOD "GCTAOnOffObservation::likelihood(GModels&, "\ | 58 | #define G_LIKELIHOOD "GCTAOnOffObservation::likelihood(GModels&, "\ |
| 66 | "GOptimizerPars&, GMatrixSparse&, "\ | 59 | "GOptimizerPars&, GMatrixSparse&, "\ |
| 67 | "GVector&, double&, double&)" | 60 | "GVector&, double&, double&)" |
| 61 | +#define G_SET "GCTAOnOffObservation::set(GCTAObservation&)" | ||
| 62 | +#define G_COMPUTE_ARF "GCTAOnOffObservation::compute_arf(GCTAObservation&)" | ||
| 63 | +#define G_COMPUTE_BGD "GCTAOnOffObservation::compute_bgd(GCTAObservation&)" | ||
| 64 | +#define G_COMPUTE_ALPHA "GCTAOnOffObservation::compute_alpha("\ | ||
| 65 | + "GCTAObservation&)" | ||
| 66 | +#define G_COMPUTE_RMF "GCTAOnOffObservation::compute_rmf(GCTAObservation&)" | ||
| 68 | 67 | ||
| 69 | /* __ Constants __________________________________________________________ */ | 68 | /* __ Constants __________________________________________________________ */ |
| 70 | const double minmod = 1.0e-100; //!< Minimum model value | 69 | const double minmod = 1.0e-100; //!< Minimum model value |
| @@ -86,6 +85,8 @@ const double minerr = 1.0e-100; //!< Minimum statistical error | @@ -86,6 +85,8 @@ const double minerr = 1.0e-100; //!< Minimum statistical error | ||
| 86 | 85 | ||
| 87 | /***********************************************************************//** | 86 | /***********************************************************************//** |
| 88 | * @brief Void constructor | 87 | * @brief Void constructor |
| 88 | + * | ||
| 89 | + * Constructs empty On/Off observation. | ||
| 89 | ***************************************************************************/ | 90 | ***************************************************************************/ |
| 90 | GCTAOnOffObservation::GCTAOnOffObservation(void) | 91 | GCTAOnOffObservation::GCTAOnOffObservation(void) |
| 91 | { | 92 | { |
| @@ -100,7 +101,7 @@ GCTAOnOffObservation::GCTAOnOffObservation(void) | @@ -100,7 +101,7 @@ GCTAOnOffObservation::GCTAOnOffObservation(void) | ||
| 100 | /***********************************************************************//** | 101 | /***********************************************************************//** |
| 101 | * @brief Copy constructor | 102 | * @brief Copy constructor |
| 102 | * | 103 | * |
| 103 | - * @param[in] obs CTA On/Off observation. | 104 | + * @param[in] obs On/Off observation. |
| 104 | ***************************************************************************/ | 105 | ***************************************************************************/ |
| 105 | GCTAOnOffObservation::GCTAOnOffObservation(const GCTAOnOffObservation& obs) | 106 | GCTAOnOffObservation::GCTAOnOffObservation(const GCTAOnOffObservation& obs) |
| 106 | { | 107 | { |
| @@ -116,15 +117,25 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GCTAOnOffObservation& obs) | @@ -116,15 +117,25 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GCTAOnOffObservation& obs) | ||
| 116 | 117 | ||
| 117 | 118 | ||
| 118 | /***********************************************************************//** | 119 | /***********************************************************************//** |
| 119 | - * @brief Parameter constructor | 120 | + * @brief CTA observation constructor |
| 120 | * | 121 | * |
| 121 | - * @param[in] ereco Reconstructed energy bins. | 122 | + * @param[in] obs CTA observation. |
| 123 | + * @param[in] etrue True energy boundaries. | ||
| 124 | + * @param[in] ereco Reconstructed energy boundaries. | ||
| 122 | * @param[in] on On regions. | 125 | * @param[in] on On regions. |
| 123 | * @param[in] off Off regions. | 126 | * @param[in] off Off regions. |
| 127 | + * | ||
| 128 | + * Constructs On/Off observation a CTA observation by filling the On and Off | ||
| 129 | + * spectra and computing the Auxiliary Response File (ARF) and Redistribution | ||
| 130 | + * Matrix File (RMF). The method requires the specification of the true and | ||
| 131 | + * reconstructed energy boundaries, as well as the definition of On and Off | ||
| 132 | + * regions. | ||
| 124 | ***************************************************************************/ | 133 | ***************************************************************************/ |
| 125 | -GCTAOnOffObservation::GCTAOnOffObservation(const GEbounds& ereco, | ||
| 126 | - const GSkyRegions& on, | ||
| 127 | - const GSkyRegions& off) | 134 | +GCTAOnOffObservation::GCTAOnOffObservation(const GCTAObservation& obs, |
| 135 | + const GEbounds& etrue, | ||
| 136 | + const GEbounds& ereco, | ||
| 137 | + const GSkyRegions& on, | ||
| 138 | + const GSkyRegions& off) | ||
| 128 | { | 139 | { |
| 129 | // Initialise private | 140 | // Initialise private |
| 130 | init_members(); | 141 | init_members(); |
| @@ -133,10 +144,17 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GEbounds& ereco, | @@ -133,10 +144,17 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GEbounds& ereco, | ||
| 133 | m_on_spec = GPha(ereco); | 144 | m_on_spec = GPha(ereco); |
| 134 | m_off_spec = GPha(ereco); | 145 | m_off_spec = GPha(ereco); |
| 135 | 146 | ||
| 147 | + // Initialise response information | ||
| 148 | + m_arf = GArf(ereco); | ||
| 149 | + m_rmf = GRmf(etrue, ereco); | ||
| 150 | + | ||
| 136 | // Store regions | 151 | // Store regions |
| 137 | m_on_regions = on; | 152 | m_on_regions = on; |
| 138 | m_off_regions = off; | 153 | m_off_regions = off; |
| 139 | 154 | ||
| 155 | + // Set On/Off observation from CTA observation | ||
| 156 | + set(obs); | ||
| 157 | + | ||
| 140 | // Return | 158 | // Return |
| 141 | return; | 159 | return; |
| 142 | } | 160 | } |
| @@ -164,10 +182,10 @@ GCTAOnOffObservation::~GCTAOnOffObservation(void) | @@ -164,10 +182,10 @@ GCTAOnOffObservation::~GCTAOnOffObservation(void) | ||
| 164 | /***********************************************************************//** | 182 | /***********************************************************************//** |
| 165 | * @brief Assignment operator | 183 | * @brief Assignment operator |
| 166 | * | 184 | * |
| 167 | - * @param[in] obs CTA On/Off observation. | ||
| 168 | - * @return CTA On/Off observation. | 185 | + * @param[in] obs On/Off observation. |
| 186 | + * @return On/Off observation. | ||
| 169 | * | 187 | * |
| 170 | - * Assigns one CTA On/Off observation to another On/Off observation object. | 188 | + * Assigns one On/Off observation to another On/Off observation object. |
| 171 | ***************************************************************************/ | 189 | ***************************************************************************/ |
| 172 | GCTAOnOffObservation& GCTAOnOffObservation::operator=(const GCTAOnOffObservation& obs) | 190 | GCTAOnOffObservation& GCTAOnOffObservation::operator=(const GCTAOnOffObservation& obs) |
| 173 | { | 191 | { |
| @@ -237,7 +255,7 @@ GCTAOnOffObservation* GCTAOnOffObservation::clone(void) const | @@ -237,7 +255,7 @@ GCTAOnOffObservation* GCTAOnOffObservation::clone(void) const | ||
| 237 | * @exception GException::invalid_argument | 255 | * @exception GException::invalid_argument |
| 238 | * Invalid response class specified. | 256 | * Invalid response class specified. |
| 239 | * | 257 | * |
| 240 | - * Sets the response function for the observation. | 258 | + * Sets the response function for the On/Off observation. |
| 241 | ***************************************************************************/ | 259 | ***************************************************************************/ |
| 242 | void GCTAOnOffObservation::response(const GResponse& rsp) | 260 | void GCTAOnOffObservation::response(const GResponse& rsp) |
| 243 | { | 261 | { |
| @@ -291,17 +309,12 @@ const GCTAResponse* GCTAOnOffObservation::response(void) const | @@ -291,17 +309,12 @@ const GCTAResponse* GCTAOnOffObservation::response(void) const | ||
| 291 | 309 | ||
| 292 | 310 | ||
| 293 | /***********************************************************************//** | 311 | /***********************************************************************//** |
| 294 | - * @brief Read ON/OFFobservation from an xml element | 312 | + * @brief Read On/Off observation from an XML element |
| 295 | * | 313 | * |
| 296 | * @param[in] xml XML element. | 314 | * @param[in] xml XML element. |
| 297 | * | 315 | * |
| 298 | - * @exception GException::xml_invalid_parnum | ||
| 299 | - * Invalid number of parameters found in XML element. | ||
| 300 | - * @exception GException::xml_invalid_parnames | ||
| 301 | - * Invalid parameter names found in XML element. | ||
| 302 | - * | ||
| 303 | - * Reads information for a CTA On/Off observation from an XML element. | ||
| 304 | - * The expected format of the XML element is | 316 | + * Reads information for an On/Off observation from an XML element. The |
| 317 | + * expected format of the XML element is | ||
| 305 | * | 318 | * |
| 306 | * <observation name="..." id="..." instrument="..."> | 319 | * <observation name="..." id="..." instrument="..."> |
| 307 | * <parameter name="Pha_on" file="..."/> | 320 | * <parameter name="Pha_on" file="..."/> |
| @@ -321,109 +334,21 @@ void GCTAOnOffObservation::read(const GXmlElement& xml) | @@ -321,109 +334,21 @@ void GCTAOnOffObservation::read(const GXmlElement& xml) | ||
| 321 | // Extract instrument name | 334 | // Extract instrument name |
| 322 | m_instrument = xml.attribute("instrument"); | 335 | m_instrument = xml.attribute("instrument"); |
| 323 | 336 | ||
| 324 | - // Determine number of parameter nodes in XML element | ||
| 325 | - int npars = xml.elements("parameter"); | ||
| 326 | - | ||
| 327 | - // Verify that XML element has exactly 6 parameters | ||
| 328 | - if (xml.elements() != 6 || npars != 6) { | ||
| 329 | - throw GException::xml_invalid_parnum(G_READ, xml, | ||
| 330 | - "CTA observation requires exactly 6 parameters."); | ||
| 331 | - } | ||
| 332 | - | ||
| 333 | - // Extract parameters | ||
| 334 | - int npar[] = {0, 0, 0, 0, 0, 0}; | ||
| 335 | - for (int i = 0; i < npars; ++i) { | ||
| 336 | - | ||
| 337 | - // Get parameter element | ||
| 338 | - const GXmlElement* par = xml.element("parameter", i); | ||
| 339 | - | ||
| 340 | - // Handle Pha_on | ||
| 341 | - if (par->attribute("name") == "Pha_on") { | ||
| 342 | - | ||
| 343 | - // Read pha_on file name | ||
| 344 | - std::string filename = par->attribute("file"); | ||
| 345 | - | ||
| 346 | - // Load pha_on | ||
| 347 | - m_on_spec.load(filename); | ||
| 348 | - | ||
| 349 | - // Increment parameter counter | ||
| 350 | - npar[0]++; | ||
| 351 | - } | ||
| 352 | - | ||
| 353 | - // Handle Pha_off | ||
| 354 | - else if (par->attribute("name") == "Pha_off") { | ||
| 355 | - | ||
| 356 | - // Read countsmap file name | ||
| 357 | - std::string filename = par->attribute("file"); | ||
| 358 | - | ||
| 359 | - // Load pha_off | ||
| 360 | - m_off_spec.load(filename); | ||
| 361 | - | ||
| 362 | - // Increment parameter counter | ||
| 363 | - npar[1]++; | ||
| 364 | - } | ||
| 365 | - | ||
| 366 | - // Handle on regions | ||
| 367 | - else if(par->attribute("name") == "Regions_on") { | ||
| 368 | - | ||
| 369 | - // Get filename | ||
| 370 | - std::string filename = par->attribute("file"); | ||
| 371 | - | ||
| 372 | - // Load on regions | ||
| 373 | - m_on_regions.load(filename); | ||
| 374 | - | ||
| 375 | - // Increase number of parameters | ||
| 376 | - npar[2]++; | ||
| 377 | - } | ||
| 378 | - | ||
| 379 | - // Handle off regions | ||
| 380 | - else if(par->attribute("name") == "Regions_off") { | ||
| 381 | - | ||
| 382 | - // Get filename | ||
| 383 | - std::string filename = par->attribute("file"); | ||
| 384 | - | ||
| 385 | - // load off regions | ||
| 386 | - m_on_regions.load(filename); | ||
| 387 | - | ||
| 388 | - // Increase number of parameters | ||
| 389 | - npar[3]++; | ||
| 390 | - } | ||
| 391 | - | ||
| 392 | - // Handle Arf | ||
| 393 | - else if(par->attribute("name") == "Arf") { | ||
| 394 | - | ||
| 395 | - // Get filename | ||
| 396 | - std::string filename = par->attribute("file"); | ||
| 397 | - | ||
| 398 | - // Load arf | ||
| 399 | - m_arf.load(filename); | ||
| 400 | - | ||
| 401 | - // Increase number of parameters | ||
| 402 | - npar[4]++; | ||
| 403 | - } | ||
| 404 | - | ||
| 405 | - // Handle Rmf | ||
| 406 | - else if(par->attribute("name") == "Rmf") { | ||
| 407 | - | ||
| 408 | - // Get filename | ||
| 409 | - std::string filename = par->attribute("file"); | ||
| 410 | - | ||
| 411 | - // Load Rmf | ||
| 412 | - m_rmf.load(filename); | ||
| 413 | - | ||
| 414 | - // Increase number of parameters | ||
| 415 | - npar[5]++; | ||
| 416 | - } | ||
| 417 | - | ||
| 418 | - } // endfor: looped over all parameters | ||
| 419 | - | ||
| 420 | - // Verify that all parameters were found | ||
| 421 | - if (npar[0] != 1 || npar[1] != 1 || npar[2] != 1 || | ||
| 422 | - npar[3] != 1 || npar[4] != 1 || npar[5] != 1) { | ||
| 423 | - throw GException::xml_invalid_parnames(G_READ, xml, | ||
| 424 | - "Require \"Pha_on\" or \"Pha_off\" and \"Regions_on\"" | ||
| 425 | - ", \"Regions_off\",\"Arf\" and \"Rmf\" parameters."); | ||
| 426 | - } | 337 | + // Get parameters |
| 338 | + std::string pha_on = gammalib::xml_get_attr(G_READ, xml, "Pha_on", "file"); | ||
| 339 | + std::string pha_off = gammalib::xml_get_attr(G_READ, xml, "Pha_off", "file"); | ||
| 340 | + std::string reg_on = gammalib::xml_get_attr(G_READ, xml, "Regions_on", "file"); | ||
| 341 | + std::string reg_off = gammalib::xml_get_attr(G_READ, xml, "Regions_off", "file"); | ||
| 342 | + std::string arf = gammalib::xml_get_attr(G_READ, xml, "Arf", "file"); | ||
| 343 | + std::string rmf = gammalib::xml_get_attr(G_READ, xml, "Rmf", "file"); | ||
| 344 | + | ||
| 345 | + // Load files | ||
| 346 | + m_on_spec.load(pha_on); | ||
| 347 | + m_off_spec.load(pha_off); | ||
| 348 | + m_on_regions.load(reg_on); | ||
| 349 | + m_off_regions.load(reg_off); | ||
| 350 | + m_arf.load(arf); | ||
| 351 | + m_rmf.load(rmf); | ||
| 427 | 352 | ||
| 428 | // Return | 353 | // Return |
| 429 | return; | 354 | return; |
| @@ -435,12 +360,7 @@ void GCTAOnOffObservation::read(const GXmlElement& xml) | @@ -435,12 +360,7 @@ void GCTAOnOffObservation::read(const GXmlElement& xml) | ||
| 435 | * | 360 | * |
| 436 | * @param[in] xml XML element. | 361 | * @param[in] xml XML element. |
| 437 | * | 362 | * |
| 438 | - * @exception GException::xml_invalid_parnum | ||
| 439 | - * Invalid number of parameters found in XML element. | ||
| 440 | - * @exception GException::xml_invalid_parnames | ||
| 441 | - * Invalid parameter names found in XML element. | ||
| 442 | - * | ||
| 443 | - * Writes information for a CTA On/Off observation into an XML element. The | 363 | + * Writes information for an On/Off observation into an XML element. The |
| 444 | * expected format of the XML element is | 364 | * expected format of the XML element is |
| 445 | * | 365 | * |
| 446 | * <observation name="..." id="..." instrument="..."> | 366 | * <observation name="..." id="..." instrument="..."> |
| @@ -452,150 +372,36 @@ void GCTAOnOffObservation::read(const GXmlElement& xml) | @@ -452,150 +372,36 @@ void GCTAOnOffObservation::read(const GXmlElement& xml) | ||
| 452 | * <parameter name="Rmf" file="..."/> | 372 | * <parameter name="Rmf" file="..."/> |
| 453 | * </observation> | 373 | * </observation> |
| 454 | * | 374 | * |
| 375 | + * The actual files described in the XML elements are not written. | ||
| 455 | ***************************************************************************/ | 376 | ***************************************************************************/ |
| 456 | void GCTAOnOffObservation::write(GXmlElement& xml) const | 377 | void GCTAOnOffObservation::write(GXmlElement& xml) const |
| 457 | { | 378 | { |
| 458 | - // If XML element has 0 nodes then append 6 parameter nodes | ||
| 459 | - if (xml.elements() == 0) { | ||
| 460 | - xml.append(GXmlElement("parameter name=\"Pha_on\"")); | ||
| 461 | - xml.append(GXmlElement("parameter name=\"Pha_off\"")); | ||
| 462 | - xml.append(GXmlElement("parameter name=\"Regions_on\"")); | ||
| 463 | - xml.append(GXmlElement("parameter name=\"Regions_off\"")); | ||
| 464 | - xml.append(GXmlElement("parameter name=\"Arf\"")); | ||
| 465 | - xml.append(GXmlElement("parameter name=\"Rmf\"")); | ||
| 466 | - } | ||
| 467 | - | ||
| 468 | - // Verify that XML element has exactly 4 parameters | ||
| 469 | - if (xml.elements() != 6 || xml.elements("parameter") != 6) { | ||
| 470 | - throw GException::xml_invalid_parnum(G_WRITE, xml, | ||
| 471 | - "CTAOnOffObservation requires exactly 6 parameters."); | ||
| 472 | - } | 379 | + // Allocate XML element pointer |
| 380 | + GXmlElement* par; | ||
| 473 | 381 | ||
| 474 | - // Set or update parameter attributes | ||
| 475 | - int npar[] = {0, 0, 0, 0, 0, 0}; | ||
| 476 | - for (int i = 0; i < 6; ++i) { | 382 | + // Set Pha_on parameter |
| 383 | + par = gammalib::xml_need_par(G_WRITE, xml, "Pha_on"); | ||
| 384 | + par->attribute("file", m_on_spec.filename()); | ||
| 477 | 385 | ||
| 478 | - // Get parameter element | ||
| 479 | - GXmlElement* par = xml.element("parameter", i); | ||
| 480 | - | ||
| 481 | - // Handle on counts | ||
| 482 | - if (par->attribute("name") == "Pha_on") { | ||
| 483 | - par->attribute("file", m_on_spec.filename()); | ||
| 484 | - npar[0]++; | ||
| 485 | - } | ||
| 486 | - | ||
| 487 | - // Handle off counts | ||
| 488 | - else if (par->attribute("name") == "Pha_off") { | ||
| 489 | - par->attribute("file", m_off_spec.filename()); | ||
| 490 | - npar[1]++; | ||
| 491 | - } | ||
| 492 | - | ||
| 493 | - // Handle on regions | ||
| 494 | - else if (par->attribute("name") == "Regions_on") { | ||
| 495 | - par->attribute("file", m_on_regions.filename()); | ||
| 496 | - npar[2]++; | ||
| 497 | - } | 386 | + // Set Pha_off parameter |
| 387 | + par = gammalib::xml_need_par(G_WRITE, xml, "Pha_off"); | ||
| 388 | + par->attribute("file", m_off_spec.filename()); | ||
| 498 | 389 | ||
| 499 | - // Handle off regions | ||
| 500 | - else if (par->attribute("name") == "Regions_off") { | ||
| 501 | - par->attribute("file", m_off_regions.filename()); | ||
| 502 | - npar[3]++; | ||
| 503 | - } | 390 | + // Set Regions_on parameter |
| 391 | + par = gammalib::xml_need_par(G_WRITE, xml, "Regions_on"); | ||
| 392 | + par->attribute("file", m_on_regions.filename()); | ||
| 504 | 393 | ||
| 505 | - // Handle effective area | ||
| 506 | - else if (par->attribute("name") == "Arf") { | ||
| 507 | - par->attribute("file", m_arf.filename()); | ||
| 508 | - npar[4]++; | ||
| 509 | - } | 394 | + // Set Regions_off parameter |
| 395 | + par = gammalib::xml_need_par(G_WRITE, xml, "Regions_off"); | ||
| 396 | + par->attribute("file", m_off_regions.filename()); | ||
| 510 | 397 | ||
| 511 | - // Handle energy resolution | ||
| 512 | - else if (par->attribute("name") == "Rmf") { | ||
| 513 | - par->attribute("file", m_rmf.filename()); | ||
| 514 | - npar[5]++; | ||
| 515 | - } | ||
| 516 | - } | 398 | + // Set Arf parameter |
| 399 | + par = gammalib::xml_need_par(G_WRITE, xml, "Arf"); | ||
| 400 | + par->attribute("file", m_arf.filename()); | ||
| 517 | 401 | ||
| 518 | - // Verify that all required parameters are present | ||
| 519 | - if (npar[0] != 1 || npar[1] != 1 || npar[2] != 1 || | ||
| 520 | - npar[3] != 1 || npar[4] != 1 || npar[5] != 1) { | ||
| 521 | - throw GException::xml_invalid_parnames(G_WRITE, xml, | ||
| 522 | - "Require \"Pha_on\" or \"Pha_off\" and \"Regions_on\"," | ||
| 523 | - " \"Regions_off\", \"Arf\", and \"Rmf\" parameters."); | ||
| 524 | - } | ||
| 525 | - | ||
| 526 | - // Return | ||
| 527 | - return; | ||
| 528 | -} | ||
| 529 | - | ||
| 530 | - | ||
| 531 | -/***********************************************************************//** | ||
| 532 | - * @brief Fill events in the On and Off spectra | ||
| 533 | - * | ||
| 534 | - * @param[in] obs CTA observation. | ||
| 535 | - * | ||
| 536 | - * @exception GException::invalid_value | ||
| 537 | - * No CTA event list found in CTA observation. | ||
| 538 | - * | ||
| 539 | - * Fills events from an observation into the On and Off spectra and cumulates | ||
| 540 | - * their livetime. This method adds to any existing content in the On and | ||
| 541 | - * Off spectra. | ||
| 542 | - ***************************************************************************/ | ||
| 543 | -void GCTAOnOffObservation::fill(const GCTAObservation& obs) | ||
| 544 | -{ | ||
| 545 | - // Get CTA event list pointer | ||
| 546 | - const GCTAEventList* events = dynamic_cast<const GCTAEventList*>(obs.events()); | ||
| 547 | - if (events == NULL) { | ||
| 548 | - std::string msg = "No event list found in CTA observation \""+ | ||
| 549 | - obs.name()+"\" (ID="+obs.id()+"). ON/OFF observation " | ||
| 550 | - "can only be filled from event list."; | ||
| 551 | - throw GException::invalid_value(G_FILL, msg); | ||
| 552 | - } | ||
| 553 | - | ||
| 554 | - // Loop over all events | ||
| 555 | - for (int i = 0; i < events->size(); ++i) { | ||
| 556 | - | ||
| 557 | - // Get measured event direction | ||
| 558 | - const GCTAEventAtom* atom = (*events)[i]; | ||
| 559 | - GSkyDir dir = atom->dir().dir(); | ||
| 560 | - | ||
| 561 | - // Fill in spectrum according to region containment | ||
| 562 | - if (m_on_regions.contains(dir)) { | ||
| 563 | - m_on_spec.fill(atom->energy()); | ||
| 564 | - } | ||
| 565 | - if (m_off_regions.contains(dir)) { | ||
| 566 | - m_off_spec.fill(atom->energy()); | ||
| 567 | - } | ||
| 568 | - | ||
| 569 | - } // endfor: looped over all events | ||
| 570 | - | ||
| 571 | - // Store the livetime as exposures of the spectra | ||
| 572 | - m_on_spec.exposure(obs.livetime()); | ||
| 573 | - m_off_spec.exposure(obs.livetime()); | ||
| 574 | - | ||
| 575 | - // Store the ontime, livetime and deadtime correction in the observation | ||
| 576 | - m_ontime = obs.ontime(); | ||
| 577 | - m_livetime = obs.livetime(); | ||
| 578 | - m_deadc = obs.deadc(); | ||
| 579 | - | ||
| 580 | - // Return | ||
| 581 | - return; | ||
| 582 | -} | ||
| 583 | - | ||
| 584 | - | ||
| 585 | -/***********************************************************************//** | ||
| 586 | - * @brief Compute response for On/Off observation | ||
| 587 | - * | ||
| 588 | - * @param[in] obs CTA observation. | ||
| 589 | - * @param[in] etrue True energy boundaries. | ||
| 590 | - ***************************************************************************/ | ||
| 591 | -void GCTAOnOffObservation::compute_response(const GCTAObservation& obs, | ||
| 592 | - const GEbounds& etrue) | ||
| 593 | -{ | ||
| 594 | - // Compute response components | ||
| 595 | - compute_arf(obs); | ||
| 596 | - compute_bgd(obs); | ||
| 597 | - compute_rmf(obs, etrue); | ||
| 598 | - compute_alpha(obs); | 402 | + // Set Rmf parameter |
| 403 | + par = gammalib::xml_need_par(G_WRITE, xml, "Rmf"); | ||
| 404 | + par->attribute("file", m_rmf.filename()); | ||
| 599 | 405 | ||
| 600 | // Return | 406 | // Return |
| 601 | return; | 407 | return; |
| @@ -622,8 +428,8 @@ void GCTAOnOffObservation::compute_response(const GCTAObservation& obs, | @@ -622,8 +428,8 @@ void GCTAOnOffObservation::compute_response(const GCTAObservation& obs, | ||
| 622 | * \f$N_{\gamma}\f$ and background events \f$N_{\rm bgd}\f$ are | 428 | * \f$N_{\gamma}\f$ and background events \f$N_{\rm bgd}\f$ are |
| 623 | * computed from the spectral models of the relevant components in the | 429 | * computed from the spectral models of the relevant components in the |
| 624 | * model container (spatial and temporal components are ignored so far). | 430 | * model container (spatial and temporal components are ignored so far). |
| 625 | - * See the model_on() and model_off() methods for details about the | ||
| 626 | - * model computations. | 431 | + * See the N_gamma() and N_bgd() methods for details about the model |
| 432 | + * computations. | ||
| 627 | * | 433 | * |
| 628 | * The log-likelihood is given by | 434 | * The log-likelihood is given by |
| 629 | * | 435 | * |
| @@ -758,8 +564,8 @@ double GCTAOnOffObservation::likelihood(const GModels& models, | @@ -758,8 +564,8 @@ double GCTAOnOffObservation::likelihood(const GModels& models, | ||
| 758 | 564 | ||
| 759 | // Get number of gamma and background events (and corresponding | 565 | // Get number of gamma and background events (and corresponding |
| 760 | // spectral model gradients) | 566 | // spectral model gradients) |
| 761 | - double ngam = model_on(models, i, &sky_grad); | ||
| 762 | - double nbgd = model_off(models, i, &bgd_grad); | 567 | + double ngam = N_gamma(models, i, &sky_grad); |
| 568 | + double nbgd = N_bgd(models, i, &bgd_grad); | ||
| 763 | 569 | ||
| 764 | // Skip bin if model is too small (avoids -Inf or NaN gradients) | 570 | // Skip bin if model is too small (avoids -Inf or NaN gradients) |
| 765 | double nonpred = ngam + alpha[i] * nbgd; | 571 | double nonpred = ngam + alpha[i] * nbgd; |
| @@ -1028,119 +834,62 @@ void GCTAOnOffObservation::free_members(void) | @@ -1028,119 +834,62 @@ void GCTAOnOffObservation::free_members(void) | ||
| 1028 | 834 | ||
| 1029 | 835 | ||
| 1030 | /***********************************************************************//** | 836 | /***********************************************************************//** |
| 1031 | - * @brief Compute vector of alpha parameters | 837 | + * @brief Set On/Off observation from a CTA observation |
| 1032 | * | 838 | * |
| 1033 | * @param[in] obs CTA observation. | 839 | * @param[in] obs CTA observation. |
| 1034 | * | 840 | * |
| 1035 | * @exception GException::invalid_value | 841 | * @exception GException::invalid_value |
| 1036 | - * No CTA response found in CTA observation. | ||
| 1037 | - * | ||
| 1038 | - * Compute the alpha parameters for all energy bins. The alpha parameter | ||
| 1039 | - * gives the ratio between the On and Off region background acceptance | ||
| 1040 | - * multiplied by the ratio between On and Off region solid angles. | 842 | + * No CTA event list found in CTA observation. |
| 1041 | * | 843 | * |
| 1042 | - * @todo Implement for general sky regions, not only circles | ||
| 1043 | - * @todo Integrate over the sky region instead of taking the values at the | ||
| 1044 | - * sky region centre | 844 | + * Sets an On/Off observation from a CTA observation by filling the events |
| 845 | + * that fall in the On and Off regions into the PHA spectra and by computing | ||
| 846 | + * the corresponding ARF and RMF response functions. | ||
| 1045 | ***************************************************************************/ | 847 | ***************************************************************************/ |
| 1046 | -void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs) | 848 | +void GCTAOnOffObservation::set(const GCTAObservation& obs) |
| 1047 | { | 849 | { |
| 1048 | - // Get energy boundaries from On spectrum | ||
| 1049 | - GEbounds ereco = m_on_spec.ebounds(); | ||
| 1050 | - | ||
| 1051 | - // Continue only if there are spectral bins | ||
| 1052 | - int nreco = ereco.size(); | ||
| 1053 | - if (nreco > 0) { | 850 | + // Get CTA event list pointer |
| 851 | + const GCTAEventList* events = dynamic_cast<const GCTAEventList*>(obs.events()); | ||
| 852 | + if (events == NULL) { | ||
| 853 | + std::string msg = "No event list found in CTA observation \""+ | ||
| 854 | + obs.name()+"\" (ID="+obs.id()+"). ON/OFF observation " | ||
| 855 | + "can only be filled from event list."; | ||
| 856 | + throw GException::invalid_value(G_SET, msg); | ||
| 857 | + } | ||
| 1054 | 858 | ||
| 1055 | - // Initialise On/Off exposure ratios | ||
| 1056 | - std::vector<double> alpha(nreco, 0.0); | ||
| 1057 | - | ||
| 1058 | - // Get CTA response pointer. Throw an exception if no response is found | ||
| 1059 | - const GCTAResponseIrf* response = | ||
| 1060 | - dynamic_cast<const GCTAResponseIrf*>(obs.response()); | ||
| 1061 | - if (response == NULL) { | ||
| 1062 | - std::string msg = "Response in CTA observation \""+obs.name()+"\" " | ||
| 1063 | - "(ID="+obs.id()+") is not of the GCTAResponseIrf " | ||
| 1064 | - "type."; | ||
| 1065 | - throw GException::invalid_value(G_COMPUTE_ALPHA, msg); | ||
| 1066 | - } | ||
| 1067 | - | ||
| 1068 | - // Get CTA observation pointing direction, zenith, and azimuth | ||
| 1069 | - GCTAPointing obspnt = obs.pointing(); | ||
| 1070 | - GSkyDir obsdir = obspnt.dir(); | 859 | + // Loop over all events |
| 860 | + for (int i = 0; i < events->size(); ++i) { | ||
| 1071 | 861 | ||
| 1072 | - // Loop over reconstructed energies | ||
| 1073 | - for (int i = 0; i < nreco; ++i) { | 862 | + // Get measured event direction |
| 863 | + const GCTAEventAtom* atom = (*events)[i]; | ||
| 864 | + GSkyDir dir = atom->dir().dir(); | ||
| 865 | + | ||
| 866 | + // Fill in spectrum according to region containment | ||
| 867 | + if (m_on_regions.contains(dir)) { | ||
| 868 | + m_on_spec.fill(atom->energy()); | ||
| 869 | + } | ||
| 870 | + if (m_off_regions.contains(dir)) { | ||
| 871 | + m_off_spec.fill(atom->energy()); | ||
| 872 | + } | ||
| 1074 | 873 | ||
| 1075 | - // Get mean log10 energy in TeV of bin | ||
| 1076 | - double logEreco = ereco.elogmean(i).log10TeV(); | ||
| 1077 | - | ||
| 1078 | - // Initialise effective area totals | ||
| 1079 | - double aon(0.0); | ||
| 1080 | - double aoff(0.0); | ||
| 1081 | - | ||
| 1082 | - // Loop over ON sky regions | ||
| 1083 | - for (int m = 0; m < m_on_regions.size(); ++m) { | ||
| 1084 | - | ||
| 1085 | - // If region is of type GSkyRegionCircle | ||
| 1086 | - const GSkyRegionCircle* skyreg = | ||
| 1087 | - dynamic_cast<const GSkyRegionCircle*>(m_on_regions[m]); | ||
| 1088 | - if (skyreg != NULL) { | ||
| 1089 | - | ||
| 1090 | - // Get centre of circular region | ||
| 1091 | - GSkyDir centreg = skyreg->centre(); | ||
| 1092 | - | ||
| 1093 | - // Compute instrument direction from region centre | ||
| 1094 | - GCTAInstDir instdir(obspnt.instdir(centreg)); | 874 | + } // endfor: looped over all events |
| 1095 | 875 | ||
| 1096 | - // Add up acceptance | ||
| 1097 | - aon += (*response->background())(logEreco, | ||
| 1098 | - instdir.detx(), | ||
| 1099 | - instdir.dety()) * | ||
| 1100 | - skyreg->solidangle(); | ||
| 1101 | - | ||
| 1102 | - } // endif: sky region is of type GSkyRegionCircle | ||
| 1103 | - | ||
| 1104 | - } // Looped over ON regions | ||
| 1105 | - | ||
| 1106 | - // Loop over OFF sky regions | ||
| 1107 | - for (int m = 0; m < m_off_regions.size(); ++m) { | ||
| 1108 | - | ||
| 1109 | - // If region is of type GSkyRegionCircle | ||
| 1110 | - const GSkyRegionCircle* skyreg = | ||
| 1111 | - dynamic_cast<const GSkyRegionCircle*>(m_off_regions[m]); | ||
| 1112 | - if (skyreg != NULL) { | ||
| 1113 | - | ||
| 1114 | - // Get centre of circular region | ||
| 1115 | - GSkyDir centreg = skyreg->centre(); | ||
| 1116 | - | ||
| 1117 | - // Compute instrument direction from region centre | ||
| 1118 | - GCTAInstDir instdir(obspnt.instdir(centreg)); | 876 | + // Store the livetime as exposures of the spectra |
| 877 | + m_on_spec.exposure(obs.livetime()); | ||
| 878 | + m_off_spec.exposure(obs.livetime()); | ||
| 1119 | 879 | ||
| 1120 | - // Add up acceptance | ||
| 1121 | - aoff += (*response->background())(logEreco, | ||
| 1122 | - instdir.detx(), | ||
| 1123 | - instdir.dety()) * | ||
| 1124 | - skyreg->solidangle(); | ||
| 1125 | - | ||
| 1126 | - } // endif: sky region is of type GSkyRegionCircle | ||
| 1127 | - | ||
| 1128 | - } // endfor: looped over OFF regions | ||
| 1129 | - | ||
| 1130 | - // Compute alpha for this energy bin | ||
| 1131 | - if (aoff > 0.0) { | ||
| 1132 | - alpha[i] = aon/aoff; | ||
| 1133 | - } | ||
| 1134 | - | ||
| 1135 | - } // endfor: looped over reconstructed energies | 880 | + // Store the ontime, livetime and deadtime correction in the observation |
| 881 | + m_ontime = obs.ontime(); | ||
| 882 | + m_livetime = obs.livetime(); | ||
| 883 | + m_deadc = obs.deadc(); | ||
| 1136 | 884 | ||
| 1137 | - // Append alpha vector to ARF | ||
| 1138 | - m_arf.append("ALPHA", alpha); | 885 | + // Compute response components |
| 886 | + compute_arf(obs); | ||
| 887 | + compute_bgd(obs); | ||
| 888 | + compute_alpha(obs); | ||
| 889 | + compute_rmf(obs); | ||
| 1139 | 890 | ||
| 1140 | - } // endif: there were energy bins | ||
| 1141 | - | ||
| 1142 | - // Return | ||
| 1143 | - return; | 891 | + // Return |
| 892 | + return; | ||
| 1144 | } | 893 | } |
| 1145 | 894 | ||
| 1146 | 895 | ||
| @@ -1158,11 +907,11 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs) | @@ -1158,11 +907,11 @@ void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs) | ||
| 1158 | ***************************************************************************/ | 907 | ***************************************************************************/ |
| 1159 | void GCTAOnOffObservation::compute_arf(const GCTAObservation& obs) | 908 | void GCTAOnOffObservation::compute_arf(const GCTAObservation& obs) |
| 1160 | { | 909 | { |
| 1161 | - // Get energy boundaries from on spectrum | ||
| 1162 | - GEbounds ereco = m_on_spec.ebounds(); | ||
| 1163 | - | ||
| 1164 | - // Continue only if there are spectral bins | ||
| 1165 | - int nreco = ereco.size(); | 910 | + // Get reconstructed energy boundaries from on ARF |
| 911 | + GEbounds ereco = m_arf.ebounds(); | ||
| 912 | + int nreco = ereco.size(); | ||
| 913 | + | ||
| 914 | + // Continue only if there are ARF bins | ||
| 1166 | if (nreco > 0) { | 915 | if (nreco > 0) { |
| 1167 | 916 | ||
| 1168 | // Get CTA response pointer. Throw an exception if no response is found | 917 | // Get CTA response pointer. Throw an exception if no response is found |
| @@ -1181,9 +930,6 @@ void GCTAOnOffObservation::compute_arf(const GCTAObservation& obs) | @@ -1181,9 +930,6 @@ void GCTAOnOffObservation::compute_arf(const GCTAObservation& obs) | ||
| 1181 | double zenith = obspnt.zenith(); | 930 | double zenith = obspnt.zenith(); |
| 1182 | double azimuth = obspnt.azimuth(); | 931 | double azimuth = obspnt.azimuth(); |
| 1183 | 932 | ||
| 1184 | - // Initialize ARF | ||
| 1185 | - m_arf = GArf(ereco); | ||
| 1186 | - | ||
| 1187 | // Loop over reconstructed energies | 933 | // Loop over reconstructed energies |
| 1188 | for (int i = 0; i < nreco; ++i) { | 934 | for (int i = 0; i < nreco; ++i) { |
| 1189 | 935 | ||
| @@ -1202,11 +948,11 @@ void GCTAOnOffObservation::compute_arf(const GCTAObservation& obs) | @@ -1202,11 +948,11 @@ void GCTAOnOffObservation::compute_arf(const GCTAObservation& obs) | ||
| 1202 | if (skyreg != NULL) { | 948 | if (skyreg != NULL) { |
| 1203 | 949 | ||
| 1204 | // Get centre of circular region | 950 | // Get centre of circular region |
| 1205 | - GSkyDir centreg(skyreg->centre()); | 951 | + GSkyDir centre(skyreg->centre()); |
| 1206 | 952 | ||
| 1207 | // Compute position of region centre in instrument coordinates | 953 | // Compute position of region centre in instrument coordinates |
| 1208 | - double theta = obsdir.dist(centreg); | ||
| 1209 | - double phi = obsdir.posang(centreg); | 954 | + double theta = obsdir.dist(centre); |
| 955 | + double phi = obsdir.posang(centre); | ||
| 1210 | 956 | ||
| 1211 | // Add up effective area | 957 | // Add up effective area |
| 1212 | m_arf[i] += response->aeff(theta, | 958 | m_arf[i] += response->aeff(theta, |
| @@ -1229,33 +975,35 @@ void GCTAOnOffObservation::compute_arf(const GCTAObservation& obs) | @@ -1229,33 +975,35 @@ void GCTAOnOffObservation::compute_arf(const GCTAObservation& obs) | ||
| 1229 | 975 | ||
| 1230 | 976 | ||
| 1231 | /***********************************************************************//** | 977 | /***********************************************************************//** |
| 1232 | - * @brief Compute background rate in Off observations | 978 | + * @brief Compute background rate in Off region |
| 1233 | * | 979 | * |
| 1234 | * @param[in] obs CTA observation. | 980 | * @param[in] obs CTA observation. |
| 1235 | * | 981 | * |
| 1236 | * @exception GException::invalid_argument | 982 | * @exception GException::invalid_argument |
| 1237 | - * Specified observation does not contain relevant response or | ||
| 1238 | - * background information | 983 | + * Observation does not contain relevant response or background |
| 984 | + * information | ||
| 985 | + * | ||
| 986 | + * Compute the background rate in units of events/s/MeV in all Off regions | ||
| 987 | + * and stores the background rate as additional column with name | ||
| 988 | + * "BACKGROUND" in the Auxiliary Response File (ARF). | ||
| 1239 | * | 989 | * |
| 1240 | * @todo Should implement integration of background model over region. | 990 | * @todo Should implement integration of background model over region. |
| 1241 | * @todo Allow general region, not only circles. | 991 | * @todo Allow general region, not only circles. |
| 1242 | ***************************************************************************/ | 992 | ***************************************************************************/ |
| 1243 | void GCTAOnOffObservation::compute_bgd(const GCTAObservation& obs) | 993 | void GCTAOnOffObservation::compute_bgd(const GCTAObservation& obs) |
| 1244 | { | 994 | { |
| 1245 | - // Get energy boundaries from on spectrum | ||
| 1246 | - GEbounds ereco = m_on_spec.ebounds(); | 995 | + // Get reconstructed energy boundaries from on ARF |
| 996 | + GEbounds ereco = m_arf.ebounds(); | ||
| 997 | + int nreco = ereco.size(); | ||
| 1247 | 998 | ||
| 1248 | - // Continue only if there are spectral bins | ||
| 1249 | - int nreco = ereco.size(); | 999 | + // Continue only if there are ARF bins |
| 1250 | if (nreco > 0) { | 1000 | if (nreco > 0) { |
| 1251 | 1001 | ||
| 1252 | - // Initialise background rayes | 1002 | + // Initialise background rates to zero |
| 1253 | std::vector<double> background(nreco, 0.0); | 1003 | std::vector<double> background(nreco, 0.0); |
| 1254 | 1004 | ||
| 1255 | - // Get CTA observation pointing direction, zenith, and azimuth | ||
| 1256 | - GCTAPointing obspnt(obs.pointing()); | ||
| 1257 | - double zenith = obspnt.zenith(); | ||
| 1258 | - double azimuth = obspnt.azimuth(); | 1005 | + // Get CTA observation pointing direction |
| 1006 | + GCTAPointing obspnt = obs.pointing(); | ||
| 1259 | 1007 | ||
| 1260 | // Get pointer on CTA IRF response | 1008 | // Get pointer on CTA IRF response |
| 1261 | const GCTAResponseIrf* rsp = | 1009 | const GCTAResponseIrf* rsp = |
| @@ -1266,7 +1014,7 @@ void GCTAOnOffObservation::compute_bgd(const GCTAObservation& obs) | @@ -1266,7 +1014,7 @@ void GCTAOnOffObservation::compute_bgd(const GCTAObservation& obs) | ||
| 1266 | throw GException::invalid_argument(G_COMPUTE_BGD, msg); | 1014 | throw GException::invalid_argument(G_COMPUTE_BGD, msg); |
| 1267 | } | 1015 | } |
| 1268 | 1016 | ||
| 1269 | - // Retrieve pointer to CTA background | 1017 | + // Get pointer to CTA background |
| 1270 | const GCTABackground* bgd = rsp->background(); | 1018 | const GCTABackground* bgd = rsp->background(); |
| 1271 | if (bgd == NULL) { | 1019 | if (bgd == NULL) { |
| 1272 | std::string msg = "Specified observation contains no " | 1020 | std::string msg = "Specified observation contains no " |
| @@ -1280,24 +1028,24 @@ void GCTAOnOffObservation::compute_bgd(const GCTAObservation& obs) | @@ -1280,24 +1028,24 @@ void GCTAOnOffObservation::compute_bgd(const GCTAObservation& obs) | ||
| 1280 | // Get region centre direction, fall through if region is not | 1028 | // Get region centre direction, fall through if region is not |
| 1281 | // of type GSkyRegionCircle | 1029 | // of type GSkyRegionCircle |
| 1282 | const GSkyRegionCircle* skyreg = | 1030 | const GSkyRegionCircle* skyreg = |
| 1283 | - dynamic_cast<const GSkyRegionCircle*>(m_off_regions[m]); | 1031 | + dynamic_cast<const GSkyRegionCircle*>(m_off_regions[m]); |
| 1284 | if (skyreg == NULL) { | 1032 | if (skyreg == NULL) { |
| 1285 | continue; | 1033 | continue; |
| 1286 | } | 1034 | } |
| 1287 | 1035 | ||
| 1288 | // Get centre of circular region | 1036 | // Get centre of circular region |
| 1289 | - GSkyDir centreg = skyreg->centre(); | 1037 | + GSkyDir centre = skyreg->centre(); |
| 1290 | 1038 | ||
| 1291 | - // Set direction to centre of the region in instrument coordinates | ||
| 1292 | - GCTAInstDir offdir = obspnt.instdir(centreg); | 1039 | + // Get instrument direction of region centre |
| 1040 | + GCTAInstDir offdir = obspnt.instdir(centre); | ||
| 1293 | 1041 | ||
| 1294 | // Loop over energy bins | 1042 | // Loop over energy bins |
| 1295 | for (int i = 0; i < nreco; ++i) { | 1043 | for (int i = 0; i < nreco; ++i) { |
| 1296 | 1044 | ||
| 1297 | - // Get log energy bin mean | 1045 | + // Get log10(E/TeV) of mean reconstructed bin energy |
| 1298 | double logEreco = m_on_spec.ebounds().elogmean(i).log10TeV(); | 1046 | double logEreco = m_on_spec.ebounds().elogmean(i).log10TeV(); |
| 1299 | 1047 | ||
| 1300 | - // Get rate in events/s/MeV | 1048 | + // Get background rate in events/s/MeV |
| 1301 | background[i] += (*bgd)(logEreco, | 1049 | background[i] += (*bgd)(logEreco, |
| 1302 | offdir.detx(), | 1050 | offdir.detx(), |
| 1303 | offdir.dety()) * skyreg->solidangle(); | 1051 | offdir.dety()) * skyreg->solidangle(); |
| @@ -1317,27 +1065,146 @@ void GCTAOnOffObservation::compute_bgd(const GCTAObservation& obs) | @@ -1317,27 +1065,146 @@ void GCTAOnOffObservation::compute_bgd(const GCTAObservation& obs) | ||
| 1317 | 1065 | ||
| 1318 | 1066 | ||
| 1319 | /***********************************************************************//** | 1067 | /***********************************************************************//** |
| 1068 | + * @brief Compute vector of alpha parameters | ||
| 1069 | + * | ||
| 1070 | + * @param[in] obs CTA observation. | ||
| 1071 | + * | ||
| 1072 | + * @exception GException::invalid_value | ||
| 1073 | + * No CTA response found in CTA observation. | ||
| 1074 | + * | ||
| 1075 | + * Compute the alpha parameters for all energy bins. The alpha parameter | ||
| 1076 | + * gives the ratio between the On and Off region background acceptance | ||
| 1077 | + * multiplied by the ratio between On and Off region solid angles. | ||
| 1078 | + * | ||
| 1079 | + * @todo Implement for general sky regions, not only circles | ||
| 1080 | + * @todo Integrate over the sky region instead of taking the values at the | ||
| 1081 | + * sky region centre | ||
| 1082 | + ***************************************************************************/ | ||
| 1083 | +void GCTAOnOffObservation::compute_alpha(const GCTAObservation& obs) | ||
| 1084 | +{ | ||
| 1085 | + // Get reconstructed energy boundaries from on ARF | ||
| 1086 | + GEbounds ereco = m_arf.ebounds(); | ||
| 1087 | + int nreco = ereco.size(); | ||
| 1088 | + | ||
| 1089 | + // Continue only if there are ARF bins | ||
| 1090 | + if (nreco > 0) { | ||
| 1091 | + | ||
| 1092 | + // Initialise On/Off exposure ratios | ||
| 1093 | + std::vector<double> alpha(nreco, 0.0); | ||
| 1094 | + | ||
| 1095 | + // Get CTA response pointer. Throw an exception if no response is found | ||
| 1096 | + const GCTAResponseIrf* response = | ||
| 1097 | + dynamic_cast<const GCTAResponseIrf*>(obs.response()); | ||
| 1098 | + if (response == NULL) { | ||
| 1099 | + std::string msg = "Response in CTA observation \""+obs.name()+"\" " | ||
| 1100 | + "(ID="+obs.id()+") is not of the GCTAResponseIrf " | ||
| 1101 | + "type."; | ||
| 1102 | + throw GException::invalid_value(G_COMPUTE_ALPHA, msg); | ||
| 1103 | + } | ||
| 1104 | + | ||
| 1105 | + // Get CTA observation pointing direction, zenith, and azimuth | ||
| 1106 | + GCTAPointing obspnt = obs.pointing(); | ||
| 1107 | + GSkyDir obsdir = obspnt.dir(); | ||
| 1108 | + | ||
| 1109 | + // Loop over reconstructed energies | ||
| 1110 | + for (int i = 0; i < nreco; ++i) { | ||
| 1111 | + | ||
| 1112 | + // Get mean log10 energy in TeV of bin | ||
| 1113 | + double logEreco = ereco.elogmean(i).log10TeV(); | ||
| 1114 | + | ||
| 1115 | + // Initialise effective area totals | ||
| 1116 | + double aon(0.0); | ||
| 1117 | + double aoff(0.0); | ||
| 1118 | + | ||
| 1119 | + // Loop over ON sky regions | ||
| 1120 | + for (int m = 0; m < m_on_regions.size(); ++m) { | ||
| 1121 | + | ||
| 1122 | + // If region is of type GSkyRegionCircle | ||
| 1123 | + const GSkyRegionCircle* skyreg = | ||
| 1124 | + dynamic_cast<const GSkyRegionCircle*>(m_on_regions[m]); | ||
| 1125 | + if (skyreg != NULL) { | ||
| 1126 | + | ||
| 1127 | + // Get centre of circular region | ||
| 1128 | + GSkyDir centreg = skyreg->centre(); | ||
| 1129 | + | ||
| 1130 | + // Compute instrument direction from region centre | ||
| 1131 | + GCTAInstDir instdir(obspnt.instdir(centreg)); | ||
| 1132 | + | ||
| 1133 | + // Add up acceptance | ||
| 1134 | + aon += (*response->background())(logEreco, | ||
| 1135 | + instdir.detx(), | ||
| 1136 | + instdir.dety()) * | ||
| 1137 | + skyreg->solidangle(); | ||
| 1138 | + | ||
| 1139 | + } // endif: sky region is of type GSkyRegionCircle | ||
| 1140 | + | ||
| 1141 | + } // Looped over ON regions | ||
| 1142 | + | ||
| 1143 | + // Loop over OFF sky regions | ||
| 1144 | + for (int m = 0; m < m_off_regions.size(); ++m) { | ||
| 1145 | + | ||
| 1146 | + // If region is of type GSkyRegionCircle | ||
| 1147 | + const GSkyRegionCircle* skyreg = | ||
| 1148 | + dynamic_cast<const GSkyRegionCircle*>(m_off_regions[m]); | ||
| 1149 | + if (skyreg != NULL) { | ||
| 1150 | + | ||
| 1151 | + // Get centre of circular region | ||
| 1152 | + GSkyDir centreg = skyreg->centre(); | ||
| 1153 | + | ||
| 1154 | + // Compute instrument direction from region centre | ||
| 1155 | + GCTAInstDir instdir(obspnt.instdir(centreg)); | ||
| 1156 | + | ||
| 1157 | + // Add up acceptance | ||
| 1158 | + aoff += (*response->background())(logEreco, | ||
| 1159 | + instdir.detx(), | ||
| 1160 | + instdir.dety()) * | ||
| 1161 | + skyreg->solidangle(); | ||
| 1162 | + | ||
| 1163 | + } // endif: sky region is of type GSkyRegionCircle | ||
| 1164 | + | ||
| 1165 | + } // endfor: looped over OFF regions | ||
| 1166 | + | ||
| 1167 | + // Compute alpha for this energy bin | ||
| 1168 | + if (aoff > 0.0) { | ||
| 1169 | + alpha[i] = aon/aoff; | ||
| 1170 | + } | ||
| 1171 | + | ||
| 1172 | + } // endfor: looped over reconstructed energies | ||
| 1173 | + | ||
| 1174 | + // Append alpha vector to ARF | ||
| 1175 | + m_arf.append("ALPHA", alpha); | ||
| 1176 | + | ||
| 1177 | + } // endif: there were energy bins | ||
| 1178 | + | ||
| 1179 | + // Return | ||
| 1180 | + return; | ||
| 1181 | +} | ||
| 1182 | + | ||
| 1183 | + | ||
| 1184 | +/***********************************************************************//** | ||
| 1320 | * @brief Compute RMF of On/Off observation | 1185 | * @brief Compute RMF of On/Off observation |
| 1321 | * | 1186 | * |
| 1322 | * @param[in] obs CTA observation. | 1187 | * @param[in] obs CTA observation. |
| 1323 | - * @param[in] etrue True energy boundaries. | ||
| 1324 | * | 1188 | * |
| 1325 | * @exception GException::invalid_value | 1189 | * @exception GException::invalid_value |
| 1326 | * Observation does not contain IRF response | 1190 | * Observation does not contain IRF response |
| 1327 | * | 1191 | * |
| 1192 | + * Compute the energy redistribution matrix for an On/Off observation. The | ||
| 1193 | + * method requires that the RMF energy axes have been defined before. | ||
| 1194 | + * | ||
| 1328 | * @todo Check if we really should use reconstructed energy in the Aeff | 1195 | * @todo Check if we really should use reconstructed energy in the Aeff |
| 1329 | * access. | 1196 | * access. |
| 1330 | * @todo Generalise to any kind of sky region | 1197 | * @todo Generalise to any kind of sky region |
| 1331 | ***************************************************************************/ | 1198 | ***************************************************************************/ |
| 1332 | -void GCTAOnOffObservation::compute_rmf(const GCTAObservation& obs, | ||
| 1333 | - const GEbounds& etrue) | 1199 | +void GCTAOnOffObservation::compute_rmf(const GCTAObservation& obs) |
| 1334 | { | 1200 | { |
| 1335 | - // Get reconstructed energy boundaries from on spectrum | ||
| 1336 | - GEbounds ereco = m_on_spec.ebounds(); | ||
| 1337 | - | ||
| 1338 | - // Continue only if there are spectral bins | ||
| 1339 | - int ntrue = etrue.size(); | ||
| 1340 | - int nreco = ereco.size(); | 1201 | + // Get true and reconstructed energy boundaries from RMF |
| 1202 | + GEbounds etrue = m_rmf.etrue(); | ||
| 1203 | + GEbounds ereco = m_rmf.emeasured(); | ||
| 1204 | + int ntrue = etrue.size(); | ||
| 1205 | + int nreco = ereco.size(); | ||
| 1206 | + | ||
| 1207 | + // Continue only if there are RMF bins | ||
| 1341 | if (ntrue > 0 && nreco > 0) { | 1208 | if (ntrue > 0 && nreco > 0) { |
| 1342 | 1209 | ||
| 1343 | // Get CTA response pointer | 1210 | // Get CTA response pointer |
| @@ -1356,9 +1223,6 @@ void GCTAOnOffObservation::compute_rmf(const GCTAObservation& obs, | @@ -1356,9 +1223,6 @@ void GCTAOnOffObservation::compute_rmf(const GCTAObservation& obs, | ||
| 1356 | double zenith = obspnt.zenith(); | 1223 | double zenith = obspnt.zenith(); |
| 1357 | double azimuth = obspnt.azimuth(); | 1224 | double azimuth = obspnt.azimuth(); |
| 1358 | 1225 | ||
| 1359 | - // Initialize RMF | ||
| 1360 | - m_rmf = GRmf(etrue, ereco); | ||
| 1361 | - | ||
| 1362 | // Loop over reconstructed energy | 1226 | // Loop over reconstructed energy |
| 1363 | for (int ireco = 0; ireco < nreco; ++ireco) { | 1227 | for (int ireco = 0; ireco < nreco; ++ireco) { |
| 1364 | 1228 | ||
| @@ -1367,6 +1231,9 @@ void GCTAOnOffObservation::compute_rmf(const GCTAObservation& obs, | @@ -1367,6 +1231,9 @@ void GCTAOnOffObservation::compute_rmf(const GCTAObservation& obs, | ||
| 1367 | 1231 | ||
| 1368 | // Loop over true energy | 1232 | // Loop over true energy |
| 1369 | for (int itrue = 0; itrue < ntrue; ++itrue) { | 1233 | for (int itrue = 0; itrue < ntrue; ++itrue) { |
| 1234 | + | ||
| 1235 | + // Initialise RMF element | ||
| 1236 | + m_rmf(itrue, ireco) = 0.0; | ||
| 1370 | 1237 | ||
| 1371 | // Compute true energy and initialise weight for this bin | 1238 | // Compute true energy and initialise weight for this bin |
| 1372 | double logEtrue = etrue.elogmean(itrue).log10TeV(); | 1239 | double logEtrue = etrue.elogmean(itrue).log10TeV(); |
| @@ -1424,33 +1291,46 @@ void GCTAOnOffObservation::compute_rmf(const GCTAObservation& obs, | @@ -1424,33 +1291,46 @@ void GCTAOnOffObservation::compute_rmf(const GCTAObservation& obs, | ||
| 1424 | 1291 | ||
| 1425 | 1292 | ||
| 1426 | /*********************************************************************** | 1293 | /*********************************************************************** |
| 1427 | - * @brief Evaluate model for sky contribution and fill model gradients | 1294 | + * @brief Compute \f$N_{\gamma}\f$ value and model parameter gradients |
| 1428 | * | 1295 | * |
| 1429 | * @param[in] models Model container. | 1296 | * @param[in] models Model container. |
| 1430 | - * @param[in,out] ibin Energy bin number. | ||
| 1431 | - * @param[in,out] mod_grad Model gradient array. | 1297 | + * @param[in] ibin Energy bin number. |
| 1298 | + * @param[in,out] grad Model gradient vector. | ||
| 1432 | * | 1299 | * |
| 1433 | - * Computes the number of expected gamma-ray events in an On region for a | ||
| 1434 | - * given energy bin, and returns it. Also computes the gradients of the | ||
| 1435 | - * sky model spectral components. The method assumes that | ||
| 1436 | - * parameters are stored in the order spatial-spectral-temporal. | 1300 | + * Returns the predicted number of source events \f$N_{\gamma}\f$ |
| 1301 | + * in the On regions for a given energy bin. The method computes also | ||
| 1302 | + * | ||
| 1303 | + * \f[ | ||
| 1304 | + * \left( \frac{\partial N_{\gamma}}{\partial p_{\rm sky}} \right) | ||
| 1305 | + * \f] | ||
| 1306 | + * | ||
| 1307 | + * which are the gradients in the predicted number of source events with | ||
| 1308 | + * respect to all model parameters. | ||
| 1309 | + * | ||
| 1310 | + * The method assumes that parameters are stored in the order | ||
| 1311 | + * spatial-spectral-temporal. | ||
| 1437 | * | 1312 | * |
| 1438 | * @todo I think this method only works for point sources. What happens | 1313 | * @todo I think this method only works for point sources. What happens |
| 1439 | * for an extended source? | 1314 | * for an extended source? |
| 1440 | ***********************************************************************/ | 1315 | ***********************************************************************/ |
| 1441 | -double GCTAOnOffObservation::model_on(const GModels& models, | ||
| 1442 | - int ibin, | ||
| 1443 | - GVector* mod_grad) const | 1316 | +double GCTAOnOffObservation::N_gamma(const GModels& models, |
| 1317 | + const int& ibin, | ||
| 1318 | + GVector* grad) const | ||
| 1444 | { | 1319 | { |
| 1445 | // Get total number of model parameters | 1320 | // Get total number of model parameters |
| 1446 | int npars = models.npars(); | 1321 | int npars = models.npars(); |
| 1447 | - | ||
| 1448 | - // Initialize variables (vector has 0.0 values) | 1322 | + |
| 1323 | + // Initialize results | ||
| 1449 | double value = 0.0; | 1324 | double value = 0.0; |
| 1450 | - int ipar = 0; | 1325 | + for (int i = 0; i < npars; ++i) { |
| 1326 | + (*grad)[i] = 0.0; | ||
| 1327 | + } | ||
| 1451 | 1328 | ||
| 1452 | // Continue only if bin number is in range and there are model parameters | 1329 | // Continue only if bin number is in range and there are model parameters |
| 1453 | - if ((ibin < m_on_spec.size()) && (npars > 0)) { | 1330 | + if ((ibin >= 0) && (ibin < m_on_spec.size()) && (npars > 0)) { |
| 1331 | + | ||
| 1332 | + // Initialise parameter index | ||
| 1333 | + int ipar = 0; | ||
| 1454 | 1334 | ||
| 1455 | // Get energy bin bounds | 1335 | // Get energy bin bounds |
| 1456 | const GEnergy emin = m_on_spec.ebounds().emin(ibin); | 1336 | const GEnergy emin = m_on_spec.ebounds().emin(ibin); |
| @@ -1460,8 +1340,8 @@ double GCTAOnOffObservation::model_on(const GModels& models, | @@ -1460,8 +1340,8 @@ double GCTAOnOffObservation::model_on(const GModels& models, | ||
| 1460 | 1340 | ||
| 1461 | // Compute normalisation factors | 1341 | // Compute normalisation factors |
| 1462 | double exposure = m_on_spec.exposure(); | 1342 | double exposure = m_on_spec.exposure(); |
| 1463 | - double norm_flux = m_arf[ibin] * exposure; | ||
| 1464 | - double norm_grad = norm_flux * ewidth; | 1343 | + double norm_flux = m_arf[ibin] * exposure; // cm2 s |
| 1344 | + double norm_grad = norm_flux * ewidth; // cm2 s MeV | ||
| 1465 | 1345 | ||
| 1466 | // Loop over models | 1346 | // Loop over models |
| 1467 | for (int j = 0; j < models.size(); ++j) { | 1347 | for (int j = 0; j < models.size(); ++j) { |
| @@ -1500,7 +1380,7 @@ double GCTAOnOffObservation::model_on(const GModels& models, | @@ -1500,7 +1380,7 @@ double GCTAOnOffObservation::model_on(const GModels& models, | ||
| 1500 | // computing the flux over the energy bin in ph/cm2/s | 1380 | // computing the flux over the energy bin in ph/cm2/s |
| 1501 | // and multiplying this flux by the effective area (cm2) | 1381 | // and multiplying this flux by the effective area (cm2) |
| 1502 | // and the livetime (s) | 1382 | // and the livetime (s) |
| 1503 | - value += spectral->flux(emin,emax) * norm_flux; | 1383 | + value += spectral->flux(emin, emax) * norm_flux; |
| 1504 | 1384 | ||
| 1505 | // Determine the model gradients at the current energy | 1385 | // Determine the model gradients at the current energy |
| 1506 | spectral->eval_gradients(emean); | 1386 | spectral->eval_gradients(emean); |
| @@ -1509,7 +1389,7 @@ double GCTAOnOffObservation::model_on(const GModels& models, | @@ -1509,7 +1389,7 @@ double GCTAOnOffObservation::model_on(const GModels& models, | ||
| 1509 | for (int k = 0; k < spectral->size(); ++k, ++ipar) { | 1389 | for (int k = 0; k < spectral->size(); ++k, ++ipar) { |
| 1510 | GModelPar& par = (*spectral)[k]; | 1390 | GModelPar& par = (*spectral)[k]; |
| 1511 | if (par.is_free() && ipar < npars) { | 1391 | if (par.is_free() && ipar < npars) { |
| 1512 | - (*mod_grad)[ipar] = par.factor_gradient() * norm_grad; | 1392 | + (*grad)[ipar] = par.factor_gradient() * norm_grad; |
| 1513 | } | 1393 | } |
| 1514 | } | 1394 | } |
| 1515 | 1395 | ||
| @@ -1531,47 +1411,58 @@ double GCTAOnOffObservation::model_on(const GModels& models, | @@ -1531,47 +1411,58 @@ double GCTAOnOffObservation::model_on(const GModels& models, | ||
| 1531 | 1411 | ||
| 1532 | 1412 | ||
| 1533 | /*********************************************************************** | 1413 | /*********************************************************************** |
| 1534 | - * @brief Evaluate model for bgd contribution and fill model gradients | 1414 | + * @brief Compute \f$N_{\rm bgd}\f$ value and model parameter gradients |
| 1535 | * | 1415 | * |
| 1536 | * @param[in] models Model container. | 1416 | * @param[in] models Model container. |
| 1537 | - * @param[in,out] ibin Energy bin number. | ||
| 1538 | - * @param[in,out] mod_grad Model gradient array. | ||
| 1539 | - * @return Number of expected background events. | 1417 | + * @param[in] ibin Energy bin index. |
| 1418 | + * @param[in,out] grad Model gradient vector. | ||
| 1419 | + * @return Predicted number of background events in Off regions. | ||
| 1540 | * | 1420 | * |
| 1541 | - * Returns the number of expected background events in the Off spectrum | ||
| 1542 | - * for a given energy bin. The method computes also the gradients of the | ||
| 1543 | - * background model spectral components. | 1421 | + * Returns the predicted number of background events \f$N_{\rm bgd}\f$ |
| 1422 | + * in the Off regions for a given energy bin. The method computes also | ||
| 1423 | + * | ||
| 1424 | + * \f[ | ||
| 1425 | + * \left( \frac{\partial N_{\rm bgd}}{\partial p_{\rm bgd}} \right) | ||
| 1426 | + * \f] | ||
| 1427 | + * | ||
| 1428 | + * which are the gradients in the predicted number of background events | ||
| 1429 | + * with respect to all model parameters. | ||
| 1544 | * | 1430 | * |
| 1545 | * The method assumes that the model parameters are stored in the order | 1431 | * The method assumes that the model parameters are stored in the order |
| 1546 | - * spatial-spectral-temporal. | 1432 | + * spectral-temporal. |
| 1547 | * | 1433 | * |
| 1548 | * @todo So far only handles the GCTAModelIrfBackground background model; | 1434 | * @todo So far only handles the GCTAModelIrfBackground background model; |
| 1549 | * Should be more generic, but there is maybe for the moment no | 1435 | * Should be more generic, but there is maybe for the moment no |
| 1550 | * other choice than implementing something for all possible | 1436 | * other choice than implementing something for all possible |
| 1551 | * background models; that's not very satisfactory ... | 1437 | * background models; that's not very satisfactory ... |
| 1552 | ***********************************************************************/ | 1438 | ***********************************************************************/ |
| 1553 | -double GCTAOnOffObservation::model_off(const GModels& models, | ||
| 1554 | - int ibin, | ||
| 1555 | - GVector* mod_grad) const | 1439 | +double GCTAOnOffObservation::N_bgd(const GModels& models, |
| 1440 | + const int& ibin, | ||
| 1441 | + GVector* grad) const | ||
| 1556 | { | 1442 | { |
| 1557 | // Get total number of model parameters | 1443 | // Get total number of model parameters |
| 1558 | int npars = models.npars(); | 1444 | int npars = models.npars(); |
| 1559 | 1445 | ||
| 1560 | - // Initialize variables | ||
| 1561 | - double value = 0.0; | ||
| 1562 | - int ipar = 0; | ||
| 1563 | - | ||
| 1564 | - // Continue only if bin number is in range and if there are parameters | ||
| 1565 | - if ((ibin < m_off_spec.size()) && (npars > 0)) { | 1446 | + // Initialize results |
| 1447 | + double value = 0.0; | ||
| 1448 | + for (int i = 0; i < npars; ++i) { | ||
| 1449 | + (*grad)[i] = 0.0; | ||
| 1450 | + } | ||
| 1451 | + | ||
| 1452 | + // Continue only if bin number is valid and if there are model parameters | ||
| 1453 | + if ((ibin >= 0) && (ibin < m_off_spec.size()) && (npars > 0)) { | ||
| 1566 | 1454 | ||
| 1567 | - // Get reference to background rates | 1455 | + // Initialise parameter index |
| 1456 | + int ipar = 0; | ||
| 1457 | + | ||
| 1458 | + // Get reference to background rates (events/MeV/s) | ||
| 1568 | const std::vector<double>& background = m_arf["BACKGROUND"]; | 1459 | const std::vector<double>& background = m_arf["BACKGROUND"]; |
| 1569 | 1460 | ||
| 1570 | // Get energy bin mean and width | 1461 | // Get energy bin mean and width |
| 1571 | const GEnergy emean = m_off_spec.ebounds().elogmean(ibin); | 1462 | const GEnergy emean = m_off_spec.ebounds().elogmean(ibin); |
| 1572 | const double ewidth = m_off_spec.ebounds().ewidth(ibin).MeV(); | 1463 | const double ewidth = m_off_spec.ebounds().ewidth(ibin).MeV(); |
| 1573 | 1464 | ||
| 1574 | - // Compute normalisation factor | 1465 | + // Compute normalisation factor (events) |
| 1575 | double exposure = m_off_spec.exposure(); | 1466 | double exposure = m_off_spec.exposure(); |
| 1576 | double norm = background[ibin] * exposure * ewidth; | 1467 | double norm = background[ibin] * exposure * ewidth; |
| 1577 | 1468 | ||
| @@ -1591,7 +1482,7 @@ double GCTAOnOffObservation::model_off(const GModels& models, | @@ -1591,7 +1482,7 @@ double GCTAOnOffObservation::model_off(const GModels& models, | ||
| 1591 | continue; | 1482 | continue; |
| 1592 | } | 1483 | } |
| 1593 | 1484 | ||
| 1594 | - // Fall through if model is not a IRF background component | 1485 | + // Fall through if model is not an IRF background component |
| 1595 | const GCTAModelIrfBackground* bgd = | 1486 | const GCTAModelIrfBackground* bgd = |
| 1596 | dynamic_cast<const GCTAModelIrfBackground*>(mptr); | 1487 | dynamic_cast<const GCTAModelIrfBackground*>(mptr); |
| 1597 | if (bgd == NULL) { | 1488 | if (bgd == NULL) { |
| @@ -1604,16 +1495,17 @@ double GCTAOnOffObservation::model_off(const GModels& models, | @@ -1604,16 +1495,17 @@ double GCTAOnOffObservation::model_off(const GModels& models, | ||
| 1604 | if (spectral != NULL) { | 1495 | if (spectral != NULL) { |
| 1605 | 1496 | ||
| 1606 | // Determine the number of background events in model by | 1497 | // Determine the number of background events in model by |
| 1607 | - // computing the rate at the energy bin in events/s/MeV and | ||
| 1608 | - // by multiplying the rate with the off livetime (s), the | ||
| 1609 | - // energy bin width (MeV) and the spectral normalisation | 1498 | + // computing the model normalization at the mean bin energy bin |
| 1499 | + // and multiplying the normalisation with the number of | ||
| 1500 | + // background events | ||
| 1610 | value += spectral->eval_gradients(emean) * norm; | 1501 | value += spectral->eval_gradients(emean) * norm; |
| 1611 | 1502 | ||
| 1612 | - // Loop over spectral model parameters | 1503 | + // Compute the parameter gradients for all spectral model |
| 1504 | + // parameters | ||
| 1613 | for (int k = 0; k < spectral->size(); ++k, ++ipar) { | 1505 | for (int k = 0; k < spectral->size(); ++k, ++ipar) { |
| 1614 | - GModelPar& par=(*spectral)[k]; | 1506 | + GModelPar& par = (*spectral)[k]; |
| 1615 | if (par.is_free() && ipar < npars) { | 1507 | if (par.is_free() && ipar < npars) { |
| 1616 | - (*mod_grad)[ipar] = par.factor_gradient() * norm; | 1508 | + (*grad)[ipar] += par.factor_gradient() * norm; |
| 1617 | } | 1509 | } |
| 1618 | } | 1510 | } |
| 1619 | 1511 |
inst/cta/test/test_CTA.py
| @@ -265,15 +265,12 @@ class Test(gammalib.GPythonTestSuite): | @@ -265,15 +265,12 @@ class Test(gammalib.GPythonTestSuite): | ||
| 265 | ereco = gammalib.GEbounds(10, gammalib.GEnergy(0.1, 'TeV'), | 265 | ereco = gammalib.GEbounds(10, gammalib.GEnergy(0.1, 'TeV'), |
| 266 | gammalib.GEnergy(10.0, 'TeV')) | 266 | gammalib.GEnergy(10.0, 'TeV')) |
| 267 | 267 | ||
| 268 | - # Create On/Off observations by filling all events found in | ||
| 269 | - # the observation container and computing the response | 268 | + # Create On/Off observations from CTA observations |
| 270 | filename = self.caldb + '/../data/irf_unbinned.xml' | 269 | filename = self.caldb + '/../data/irf_unbinned.xml' |
| 271 | inobs = gammalib.GObservations(filename) | 270 | inobs = gammalib.GObservations(filename) |
| 272 | outobs = gammalib.GObservations() | 271 | outobs = gammalib.GObservations() |
| 273 | for run in inobs: | 272 | for run in inobs: |
| 274 | - onoff = gammalib.GCTAOnOffObservation(ereco, on, off) | ||
| 275 | - onoff.fill(run) | ||
| 276 | - onoff.compute_response(run, etrue) | 273 | + onoff = gammalib.GCTAOnOffObservation(run, etrue, ereco, on, off) |
| 277 | outobs.append(onoff) | 274 | outobs.append(onoff) |
| 278 | 275 | ||
| 279 | # Load model container and attach it to the observations | 276 | # Load model container and attach it to the observations |