Commit f62663d556430ab75786cd600ecece1fc3299ca9
1 parent
67894a21
Use column names instead of hard-wired indices in GCTAAeff2D (#1656).
Showing
2 changed files
with
118 additions
and
67 deletions
inst/cta/include/GCTAAeff2D.hpp
| ... | ... | @@ -87,8 +87,12 @@ private: |
| 87 | 87 | void free_members(void); |
| 88 | 88 | |
| 89 | 89 | // Members |
| 90 | - std::string m_filename; //!< Name of Aeff response file | |
| 91 | - GCTAResponseTable m_aeff; //!< Aeff response table | |
| 90 | + std::string m_filename; //!< Name of Aeff response file | |
| 91 | + GCTAResponseTable m_aeff; //!< Aeff response table | |
| 92 | + int m_inx_energy; //!< Energy index | |
| 93 | + int m_inx_theta; //!< Theta index | |
| 94 | + int m_inx_aeff; //!< Effective area (true energy) | |
| 95 | + int m_inx_aeff_reco; //!< Effective area (reconstructed energy) | |
| 92 | 96 | }; |
| 93 | 97 | |
| 94 | 98 | ... | ... |
inst/cta/src/GCTAAeff2D.cpp
| 1 | 1 | /*************************************************************************** |
| 2 | - * GCTAAeff2D.cpp - CTA 2D effective area class * | |
| 2 | + * GCTAAeff2D.cpp - CTA 2D effective area class * | |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2012-2015 by Juergen Knoedlseder * | |
| 4 | + * copyright (C) 2012-2016 by Juergen Knoedlseder * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -56,6 +56,8 @@ |
| 56 | 56 | |
| 57 | 57 | /***********************************************************************//** |
| 58 | 58 | * @brief Void constructor |
| 59 | + * | |
| 60 | + * Constructs empty effective area. | |
| 59 | 61 | ***************************************************************************/ |
| 60 | 62 | GCTAAeff2D::GCTAAeff2D(void) : GCTAAeff() |
| 61 | 63 | { |
| ... | ... | @@ -91,6 +93,8 @@ GCTAAeff2D::GCTAAeff2D(const std::string& filename) : GCTAAeff() |
| 91 | 93 | * @brief Copy constructor |
| 92 | 94 | * |
| 93 | 95 | * @param[in] aeff Effective area. |
| 96 | + * | |
| 97 | + * Constructs effective area by copying from another effective area. | |
| 94 | 98 | ***************************************************************************/ |
| 95 | 99 | GCTAAeff2D::GCTAAeff2D(const GCTAAeff2D& aeff) : GCTAAeff(aeff) |
| 96 | 100 | { |
| ... | ... | @@ -107,6 +111,8 @@ GCTAAeff2D::GCTAAeff2D(const GCTAAeff2D& aeff) : GCTAAeff(aeff) |
| 107 | 111 | |
| 108 | 112 | /***********************************************************************//** |
| 109 | 113 | * @brief Destructor |
| 114 | + * | |
| 115 | + * Destructs effective area. | |
| 110 | 116 | ***************************************************************************/ |
| 111 | 117 | GCTAAeff2D::~GCTAAeff2D(void) |
| 112 | 118 | { |
| ... | ... | @@ -129,8 +135,10 @@ GCTAAeff2D::~GCTAAeff2D(void) |
| 129 | 135 | * |
| 130 | 136 | * @param[in] aeff Effective area. |
| 131 | 137 | * @return Effective area. |
| 138 | + * | |
| 139 | + * Assigns effective area. | |
| 132 | 140 | ***************************************************************************/ |
| 133 | -GCTAAeff2D& GCTAAeff2D::operator= (const GCTAAeff2D& aeff) | |
| 141 | +GCTAAeff2D& GCTAAeff2D::operator=(const GCTAAeff2D& aeff) | |
| 134 | 142 | { |
| 135 | 143 | // Execute only if object is not identical |
| 136 | 144 | if (this != &aeff) { |
| ... | ... | @@ -158,14 +166,15 @@ GCTAAeff2D& GCTAAeff2D::operator= (const GCTAAeff2D& aeff) |
| 158 | 166 | * @brief Return effective area in units of cm2 |
| 159 | 167 | * |
| 160 | 168 | * @param[in] logE Log10 of the true photon energy (TeV). |
| 161 | - * @param[in] theta Offset angle in camera system (rad). Defaults to 0.0. | |
| 162 | - * @param[in] phi Azimuth angle in camera system (rad). Not used in this method. | |
| 163 | - * @param[in] zenith Zenith angle in Earth system (rad). Not used in this method. | |
| 164 | - * @param[in] azimuth Azimuth angle in Earth system (rad). Not used in this method. | |
| 165 | - * @param[in] etrue Use true energy (true/false). Defaults to true. | |
| 169 | + * @param[in] theta Offset angle in camera system (rad) (default: 0.0). | |
| 170 | + * @param[in] phi Azimuth angle in camera system (rad). | |
| 171 | + * @param[in] zenith Zenith angle in Earth system (rad). | |
| 172 | + * @param[in] azimuth Azimuth angle in Earth system (rad). | |
| 173 | + * @param[in] etrue Use true energy (default: true). | |
| 174 | + * @return Effective area in cm2. | |
| 166 | 175 | * |
| 167 | 176 | * Returns the effective area in units of cm2 for a given energy and |
| 168 | - * offset angle. The effective area is bi-linearily interpolated in the | |
| 177 | + * offset angle. The effective area is bi-linearly interpolated in the | |
| 169 | 178 | * log10(energy) - offset angle plane. The method assures that the effective |
| 170 | 179 | * area value never becomes negative. |
| 171 | 180 | * |
| ... | ... | @@ -182,10 +191,11 @@ double GCTAAeff2D::operator()(const double& logE, |
| 182 | 191 | const bool& etrue) const |
| 183 | 192 | { |
| 184 | 193 | // Set parameter index |
| 185 | - int index = (etrue) ? 0 : 1; | |
| 194 | + int index = (etrue) ? m_inx_aeff : m_inx_aeff_reco; | |
| 186 | 195 | |
| 187 | 196 | // Get effective area value in cm2 |
| 188 | - double aeff = m_aeff(index, logE, theta); | |
| 197 | + double aeff = (m_inx_energy == 0) ? m_aeff(index, logE, theta) : | |
| 198 | + m_aeff(index, theta, logE); | |
| 189 | 199 | |
| 190 | 200 | // Make sure that effective area is not negative |
| 191 | 201 | if (aeff < 0.0) { |
| ... | ... | @@ -204,13 +214,13 @@ double GCTAAeff2D::operator()(const double& logE, |
| 204 | 214 | ==========================================================================*/ |
| 205 | 215 | |
| 206 | 216 | /***********************************************************************//** |
| 207 | - * @brief Clear instance | |
| 217 | + * @brief Clear effective area. | |
| 208 | 218 | * |
| 209 | - * This method properly resets the object to an initial state. | |
| 219 | + * Clears effective area. | |
| 210 | 220 | ***************************************************************************/ |
| 211 | 221 | void GCTAAeff2D::clear(void) |
| 212 | 222 | { |
| 213 | - // Free class members (base and derived classes, derived class first) | |
| 223 | + // Free class members | |
| 214 | 224 | free_members(); |
| 215 | 225 | this->GCTAAeff::free_members(); |
| 216 | 226 | |
| ... | ... | @@ -224,9 +234,11 @@ void GCTAAeff2D::clear(void) |
| 224 | 234 | |
| 225 | 235 | |
| 226 | 236 | /***********************************************************************//** |
| 227 | - * @brief Clone instance | |
| 237 | + * @brief Clone effective area | |
| 238 | + * | |
| 239 | + * @return Deep copy of effective area. | |
| 228 | 240 | * |
| 229 | - * @return Deep copy of effective area instance. | |
| 241 | + * Returns a pointer to a deep copy of the effective area. | |
| 230 | 242 | ***************************************************************************/ |
| 231 | 243 | GCTAAeff2D* GCTAAeff2D::clone(void) const |
| 232 | 244 | { |
| ... | ... | @@ -240,12 +252,26 @@ GCTAAeff2D* GCTAAeff2D::clone(void) const |
| 240 | 252 | * @param[in] table FITS table. |
| 241 | 253 | * |
| 242 | 254 | * @exception GException::invalid_value |
| 243 | - * FITS file format differs from expectation. | |
| 255 | + * Response table is not two-dimensional. | |
| 256 | + * | |
| 257 | + * Reads the effective area form the FITS @p table. The following column | |
| 258 | + * names are mandatory: | |
| 244 | 259 | * |
| 245 | - * Reads the effective area form the FITS @p table. | |
| 260 | + * ENERG_LO - Energy lower bin boundaries | |
| 261 | + * ENERG_HI - Energy upper bin boundaries | |
| 262 | + * THETA_LO - Offset angle lower bin boundaries | |
| 263 | + * THETA_HI - Offset angle upper bin boundaries | |
| 264 | + * EFFAREA - Effective area | |
| 246 | 265 | * |
| 247 | - * The data are stored in m_aeff which is of type GCTAResponseTable. The | |
| 248 | - * energy axis will be set to log10, the offset angle axis to radians. | |
| 266 | + * In addition, the following column names are optional: | |
| 267 | + * | |
| 268 | + * EFFAREA_RECO - Effective area as function of reconstructed energy | |
| 269 | + * | |
| 270 | + * The data are stored in the m_aeff member. The energy axis will be set to | |
| 271 | + * log10, the offset angle axis to radians. | |
| 272 | + * | |
| 273 | + * @todo Analyse the unit of the parameter axis to determine the conversion | |
| 274 | + * factor for the effective areas. For the moment they are hard wired. | |
| 249 | 275 | ***************************************************************************/ |
| 250 | 276 | void GCTAAeff2D::read(const GFitsTable& table) |
| 251 | 277 | { |
| ... | ... | @@ -255,31 +281,34 @@ void GCTAAeff2D::read(const GFitsTable& table) |
| 255 | 281 | // Read effective area table |
| 256 | 282 | m_aeff.read(table); |
| 257 | 283 | |
| 258 | - // Check that axis names comply to format | |
| 259 | - if (m_aeff.axis_lo_name(0) != "ENERG_LO" || | |
| 260 | - m_aeff.axis_hi_name(0) != "ENERG_HI") { | |
| 261 | - std::string msg = "Effective area response table does not contain" | |
| 262 | - " \"ENERG_LO\" and \"ENERG_HI\" columns as the" | |
| 263 | - " first axis."; | |
| 264 | - throw GException::invalid_value(G_READ, msg); | |
| 265 | - } | |
| 266 | - if (m_aeff.axis_lo_name(1) != "THETA_LO" || | |
| 267 | - m_aeff.axis_hi_name(1) != "THETA_HI") { | |
| 268 | - std::string msg = "Effective area response table does not contain" | |
| 269 | - " \"THETA_LO\" and \"THETA_HI\" columns as the" | |
| 270 | - " second axis."; | |
| 284 | + // Get mandatory indices (throw exception if not found) | |
| 285 | + m_inx_energy = m_aeff.axis("ENERG"); | |
| 286 | + m_inx_theta = m_aeff.axis("THETA"); | |
| 287 | + m_inx_aeff = m_aeff.table("EFFAREA"); | |
| 288 | + | |
| 289 | + // Get optional index (use "EFFAREA" if "EFFAREA_RECO" does not exist) | |
| 290 | + m_inx_aeff_reco = (m_aeff.has_table("EFFAREA_RECO")) ? | |
| 291 | + m_aeff.table("EFFAREA_RECO") : m_inx_aeff; | |
| 292 | + | |
| 293 | + // Throw an exception if the table is not two-dimensional | |
| 294 | + if (m_aeff.axes() != 2) { | |
| 295 | + std::string msg = "Expected two-dimensional effective area response " | |
| 296 | + "table but found "+gammalib::str(m_aeff.axes())+ | |
| 297 | + " dimensions. Please specify a two-dimensional " | |
| 298 | + "effective area."; | |
| 271 | 299 | throw GException::invalid_value(G_READ, msg); |
| 272 | 300 | } |
| 273 | 301 | |
| 274 | 302 | // Set energy axis to logarithmic scale |
| 275 | - m_aeff.axis_log10(0); | |
| 303 | + m_aeff.axis_log10(m_inx_energy); | |
| 276 | 304 | |
| 277 | 305 | // Set offset angle axis to radians |
| 278 | - m_aeff.axis_radians(1); | |
| 306 | + m_aeff.axis_radians(m_inx_theta); | |
| 279 | 307 | |
| 280 | 308 | // Convert effective areas from m2 to cm2 |
| 281 | - m_aeff.scale(0, 1.0e4); | |
| 282 | - m_aeff.scale(1, 1.0e4); | |
| 309 | + for (int i = 0; i < m_aeff.tables(); ++i) { | |
| 310 | + m_aeff.scale(i, 1.0e4); | |
| 311 | + } | |
| 283 | 312 | |
| 284 | 313 | // Return |
| 285 | 314 | return; |
| ... | ... | @@ -291,7 +320,7 @@ void GCTAAeff2D::read(const GFitsTable& table) |
| 291 | 320 | * |
| 292 | 321 | * @param[in] table FITS binary table. |
| 293 | 322 | * |
| 294 | - * Writes effective area into the FITS binary @p table. | |
| 323 | + * Writes effective area into a FITS binary @p table. | |
| 295 | 324 | * |
| 296 | 325 | * @todo Add keywords. |
| 297 | 326 | ***************************************************************************/ |
| ... | ... | @@ -301,8 +330,9 @@ void GCTAAeff2D::write(GFitsBinTable& table) const |
| 301 | 330 | GCTAResponseTable aeff(m_aeff); |
| 302 | 331 | |
| 303 | 332 | // Convert area from cm2 to m2 |
| 304 | - aeff.scale(0, 1.0e-4); | |
| 305 | - aeff.scale(1, 1.0e-4); | |
| 333 | + for (int i = 0; i < aeff.tables(); ++i) { | |
| 334 | + aeff.scale(i, 1.0e-4); | |
| 335 | + } | |
| 306 | 336 | |
| 307 | 337 | // Write response table |
| 308 | 338 | aeff.write(table); |
| ... | ... | @@ -384,44 +414,51 @@ void GCTAAeff2D::save(const std::string& filename, const bool& clobber) const |
| 384 | 414 | |
| 385 | 415 | |
| 386 | 416 | /***********************************************************************//** |
| 387 | - * @brief Return maximum effective area at a given energy | |
| 417 | + * @brief Return maximum effective area at a given energy in cm2 | |
| 388 | 418 | * |
| 389 | 419 | * @param[in] logE Log10 of the true photon energy (TeV). |
| 390 | - * @param[in] zenith Zenith angle in Earth system (rad). Not used in this method. | |
| 391 | - * @param[in] azimuth Azimuth angle in Earth system (rad). Not used in this method. | |
| 392 | - * @param[in] etrue Use true energy (true/false). Not used. | |
| 420 | + * @param[in] zenith Zenith angle in Earth system (rad). | |
| 421 | + * @param[in] azimuth Azimuth angle in Earth system (rad). | |
| 422 | + * @param[in] etrue Use true energy (default: true). | |
| 393 | 423 | * @return Maximum effective area (cm2). |
| 424 | + * | |
| 425 | + * Returns the maximum effective area for a given energy, zenith and azimuth | |
| 426 | + * angle in units of cm2. | |
| 394 | 427 | ***************************************************************************/ |
| 395 | 428 | double GCTAAeff2D::max(const double& logE, |
| 396 | 429 | const double& zenith, |
| 397 | 430 | const double& azimuth, |
| 398 | 431 | const bool& etrue) const |
| 399 | 432 | { |
| 400 | - // Set parameter index | |
| 401 | - int index = (etrue) ? 0 : 1; | |
| 402 | - | |
| 403 | - // Get number of theta bins | |
| 404 | - int n_theta = m_aeff.axis(1); | |
| 405 | - | |
| 406 | 433 | // Initialise maximum effective area |
| 407 | 434 | double max_aeff = 0.0; |
| 408 | 435 | |
| 409 | - // Compute stepsize | |
| 410 | - double theta_step = m_aeff.axis_hi(1, n_theta - 1) / (double(n_theta) - 1.0); | |
| 436 | + // Set parameter index | |
| 437 | + int index = (etrue) ? m_inx_aeff : m_inx_aeff_reco; | |
| 438 | + | |
| 439 | + // Get number of theta bins | |
| 440 | + int n_theta = m_aeff.axis_bins(m_inx_theta); | |
| 411 | 441 | |
| 412 | 442 | // Loop over theta values |
| 413 | 443 | for (int i = 0; i < n_theta; ++i) { |
| 414 | 444 | |
| 415 | - // Compute theta | |
| 416 | - double theta = i * theta_step; | |
| 445 | + // Compute lower and upper theta bin values | |
| 446 | + double theta_lo = m_aeff.axis_lo(m_inx_theta, i); | |
| 447 | + double theta_hi = m_aeff.axis_hi(m_inx_theta, i); | |
| 417 | 448 | |
| 418 | 449 | // Get effective area value in cm2 |
| 419 | - double aeff = m_aeff(index, logE, theta); | |
| 450 | + double aeff_lo = (m_inx_energy == 0) ? m_aeff(index, logE, theta_lo) : | |
| 451 | + m_aeff(index, theta_lo, logE); | |
| 452 | + double aeff_hi = (m_inx_energy == 0) ? m_aeff(index, logE, theta_hi) : | |
| 453 | + m_aeff(index, theta_hi, logE); | |
| 420 | 454 | |
| 421 | 455 | // Update maximum effective area if larger than current maximum |
| 422 | 456 | // effective area |
| 423 | - if (aeff > max_aeff) { | |
| 424 | - max_aeff = aeff; | |
| 457 | + if (aeff_lo > max_aeff) { | |
| 458 | + max_aeff = aeff_lo; | |
| 459 | + } | |
| 460 | + if (aeff_hi > max_aeff) { | |
| 461 | + max_aeff = aeff_hi; | |
| 425 | 462 | } |
| 426 | 463 | |
| 427 | 464 | } // endfor: loop over theta values |
| ... | ... | @@ -446,12 +483,14 @@ std::string GCTAAeff2D::print(const GChatter& chatter) const |
| 446 | 483 | if (chatter != SILENT) { |
| 447 | 484 | |
| 448 | 485 | // Compute energy boundaries in TeV |
| 449 | - double emin = m_aeff.axis_lo(0,0); | |
| 450 | - double emax = m_aeff.axis_hi(0,m_aeff.axis(0)-1); | |
| 486 | + double emin = m_aeff.axis_lo(m_inx_energy,0); | |
| 487 | + double emax = m_aeff.axis_hi(m_inx_energy, | |
| 488 | + m_aeff.axis_bins(m_inx_energy)-1); | |
| 451 | 489 | |
| 452 | 490 | // Compute offset angle boundaries in deg |
| 453 | - double omin = m_aeff.axis_lo(1,0); | |
| 454 | - double omax = m_aeff.axis_hi(1,m_aeff.axis(1)-1); | |
| 491 | + double omin = m_aeff.axis_lo(m_inx_theta,0); | |
| 492 | + double omax = m_aeff.axis_hi(m_inx_theta, | |
| 493 | + m_aeff.axis_bins(m_inx_theta)-1); | |
| 455 | 494 | |
| 456 | 495 | // Append header |
| 457 | 496 | result.append("=== GCTAAeff2D ==="); |
| ... | ... | @@ -459,9 +498,9 @@ std::string GCTAAeff2D::print(const GChatter& chatter) const |
| 459 | 498 | // Append information |
| 460 | 499 | result.append("\n"+gammalib::parformat("Filename")+m_filename); |
| 461 | 500 | result.append("\n"+gammalib::parformat("Number of energy bins") + |
| 462 | - gammalib::str(m_aeff.axis(0))); | |
| 501 | + gammalib::str(m_aeff.axis_bins(m_inx_energy))); | |
| 463 | 502 | result.append("\n"+gammalib::parformat("Number of offset bins") + |
| 464 | - gammalib::str(m_aeff.axis(1))); | |
| 503 | + gammalib::str(m_aeff.axis_bins(m_inx_theta))); | |
| 465 | 504 | result.append("\n"+gammalib::parformat("Log10(Energy) range")); |
| 466 | 505 | result.append(gammalib::str(emin)+" - "+gammalib::str(emax)+" TeV"); |
| 467 | 506 | result.append("\n"+gammalib::parformat("Offset angle range")); |
| ... | ... | @@ -488,6 +527,10 @@ void GCTAAeff2D::init_members(void) |
| 488 | 527 | // Initialise members |
| 489 | 528 | m_filename.clear(); |
| 490 | 529 | m_aeff.clear(); |
| 530 | + m_inx_energy = 0; | |
| 531 | + m_inx_theta = 1; | |
| 532 | + m_inx_aeff = 0; | |
| 533 | + m_inx_aeff_reco = 1; | |
| 491 | 534 | |
| 492 | 535 | // Return |
| 493 | 536 | return; |
| ... | ... | @@ -502,8 +545,12 @@ void GCTAAeff2D::init_members(void) |
| 502 | 545 | void GCTAAeff2D::copy_members(const GCTAAeff2D& aeff) |
| 503 | 546 | { |
| 504 | 547 | // Copy members |
| 505 | - m_filename = aeff.m_filename; | |
| 506 | - m_aeff = aeff.m_aeff; | |
| 548 | + m_filename = aeff.m_filename; | |
| 549 | + m_aeff = aeff.m_aeff; | |
| 550 | + m_inx_energy = aeff.m_inx_energy; | |
| 551 | + m_inx_theta = aeff.m_inx_theta; | |
| 552 | + m_inx_aeff = aeff.m_inx_aeff; | |
| 553 | + m_inx_aeff_reco = aeff.m_inx_aeff_reco; | |
| 507 | 554 | |
| 508 | 555 | // Return |
| 509 | 556 | return; | ... | ... |