Commit f62663d556430ab75786cd600ecece1fc3299ca9

Authored by Jürgen Knödlseder
1 parent 67894a21

Use column names instead of hard-wired indices in GCTAAeff2D (#1656).

inst/cta/include/GCTAAeff2D.hpp
@@ -87,8 +87,12 @@ private: @@ -87,8 +87,12 @@ private:
87 void free_members(void); 87 void free_members(void);
88 88
89 // Members 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 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -56,6 +56,8 @@ @@ -56,6 +56,8 @@
56 56
57 /***********************************************************************//** 57 /***********************************************************************//**
58 * @brief Void constructor 58 * @brief Void constructor
  59 + *
  60 + * Constructs empty effective area.
59 ***************************************************************************/ 61 ***************************************************************************/
60 GCTAAeff2D::GCTAAeff2D(void) : GCTAAeff() 62 GCTAAeff2D::GCTAAeff2D(void) : GCTAAeff()
61 { 63 {
@@ -91,6 +93,8 @@ GCTAAeff2D::GCTAAeff2D(const std::string&amp; filename) : GCTAAeff() @@ -91,6 +93,8 @@ GCTAAeff2D::GCTAAeff2D(const std::string&amp; filename) : GCTAAeff()
91 * @brief Copy constructor 93 * @brief Copy constructor
92 * 94 *
93 * @param[in] aeff Effective area. 95 * @param[in] aeff Effective area.
  96 + *
  97 + * Constructs effective area by copying from another effective area.
94 ***************************************************************************/ 98 ***************************************************************************/
95 GCTAAeff2D::GCTAAeff2D(const GCTAAeff2D& aeff) : GCTAAeff(aeff) 99 GCTAAeff2D::GCTAAeff2D(const GCTAAeff2D& aeff) : GCTAAeff(aeff)
96 { 100 {
@@ -107,6 +111,8 @@ GCTAAeff2D::GCTAAeff2D(const GCTAAeff2D&amp; aeff) : GCTAAeff(aeff) @@ -107,6 +111,8 @@ GCTAAeff2D::GCTAAeff2D(const GCTAAeff2D&amp; aeff) : GCTAAeff(aeff)
107 111
108 /***********************************************************************//** 112 /***********************************************************************//**
109 * @brief Destructor 113 * @brief Destructor
  114 + *
  115 + * Destructs effective area.
110 ***************************************************************************/ 116 ***************************************************************************/
111 GCTAAeff2D::~GCTAAeff2D(void) 117 GCTAAeff2D::~GCTAAeff2D(void)
112 { 118 {
@@ -129,8 +135,10 @@ GCTAAeff2D::~GCTAAeff2D(void) @@ -129,8 +135,10 @@ GCTAAeff2D::~GCTAAeff2D(void)
129 * 135 *
130 * @param[in] aeff Effective area. 136 * @param[in] aeff Effective area.
131 * @return Effective area. 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 // Execute only if object is not identical 143 // Execute only if object is not identical
136 if (this != &aeff) { 144 if (this != &aeff) {
@@ -158,14 +166,15 @@ GCTAAeff2D&amp; GCTAAeff2D::operator= (const GCTAAeff2D&amp; aeff) @@ -158,14 +166,15 @@ GCTAAeff2D&amp; GCTAAeff2D::operator= (const GCTAAeff2D&amp; aeff)
158 * @brief Return effective area in units of cm2 166 * @brief Return effective area in units of cm2
159 * 167 *
160 * @param[in] logE Log10 of the true photon energy (TeV). 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 * Returns the effective area in units of cm2 for a given energy and 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 * log10(energy) - offset angle plane. The method assures that the effective 178 * log10(energy) - offset angle plane. The method assures that the effective
170 * area value never becomes negative. 179 * area value never becomes negative.
171 * 180 *
@@ -182,10 +191,11 @@ double GCTAAeff2D::operator()(const double&amp; logE, @@ -182,10 +191,11 @@ double GCTAAeff2D::operator()(const double&amp; logE,
182 const bool& etrue) const 191 const bool& etrue) const
183 { 192 {
184 // Set parameter index 193 // Set parameter index
185 - int index = (etrue) ? 0 : 1; 194 + int index = (etrue) ? m_inx_aeff : m_inx_aeff_reco;
186 195
187 // Get effective area value in cm2 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 // Make sure that effective area is not negative 200 // Make sure that effective area is not negative
191 if (aeff < 0.0) { 201 if (aeff < 0.0) {
@@ -204,13 +214,13 @@ double GCTAAeff2D::operator()(const double&amp; logE, @@ -204,13 +214,13 @@ double GCTAAeff2D::operator()(const double&amp; 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 void GCTAAeff2D::clear(void) 221 void GCTAAeff2D::clear(void)
212 { 222 {
213 - // Free class members (base and derived classes, derived class first) 223 + // Free class members
214 free_members(); 224 free_members();
215 this->GCTAAeff::free_members(); 225 this->GCTAAeff::free_members();
216 226
@@ -224,9 +234,11 @@ void GCTAAeff2D::clear(void) @@ -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 GCTAAeff2D* GCTAAeff2D::clone(void) const 243 GCTAAeff2D* GCTAAeff2D::clone(void) const
232 { 244 {
@@ -240,12 +252,26 @@ GCTAAeff2D* GCTAAeff2D::clone(void) const @@ -240,12 +252,26 @@ GCTAAeff2D* GCTAAeff2D::clone(void) const
240 * @param[in] table FITS table. 252 * @param[in] table FITS table.
241 * 253 *
242 * @exception GException::invalid_value 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 void GCTAAeff2D::read(const GFitsTable& table) 276 void GCTAAeff2D::read(const GFitsTable& table)
251 { 277 {
@@ -255,31 +281,34 @@ void GCTAAeff2D::read(const GFitsTable&amp; table) @@ -255,31 +281,34 @@ void GCTAAeff2D::read(const GFitsTable&amp; table)
255 // Read effective area table 281 // Read effective area table
256 m_aeff.read(table); 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 throw GException::invalid_value(G_READ, msg); 299 throw GException::invalid_value(G_READ, msg);
272 } 300 }
273 301
274 // Set energy axis to logarithmic scale 302 // Set energy axis to logarithmic scale
275 - m_aeff.axis_log10(0); 303 + m_aeff.axis_log10(m_inx_energy);
276 304
277 // Set offset angle axis to radians 305 // Set offset angle axis to radians
278 - m_aeff.axis_radians(1); 306 + m_aeff.axis_radians(m_inx_theta);
279 307
280 // Convert effective areas from m2 to cm2 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 // Return 313 // Return
285 return; 314 return;
@@ -291,7 +320,7 @@ void GCTAAeff2D::read(const GFitsTable&amp; table) @@ -291,7 +320,7 @@ void GCTAAeff2D::read(const GFitsTable&amp; table)
291 * 320 *
292 * @param[in] table FITS binary table. 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 * @todo Add keywords. 325 * @todo Add keywords.
297 ***************************************************************************/ 326 ***************************************************************************/
@@ -301,8 +330,9 @@ void GCTAAeff2D::write(GFitsBinTable&amp; table) const @@ -301,8 +330,9 @@ void GCTAAeff2D::write(GFitsBinTable&amp; table) const
301 GCTAResponseTable aeff(m_aeff); 330 GCTAResponseTable aeff(m_aeff);
302 331
303 // Convert area from cm2 to m2 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 // Write response table 337 // Write response table
308 aeff.write(table); 338 aeff.write(table);
@@ -384,44 +414,51 @@ void GCTAAeff2D::save(const std::string&amp; filename, const bool&amp; clobber) const @@ -384,44 +414,51 @@ void GCTAAeff2D::save(const std::string&amp; filename, const bool&amp; 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 * @param[in] logE Log10 of the true photon energy (TeV). 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 * @return Maximum effective area (cm2). 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 double GCTAAeff2D::max(const double& logE, 428 double GCTAAeff2D::max(const double& logE,
396 const double& zenith, 429 const double& zenith,
397 const double& azimuth, 430 const double& azimuth,
398 const bool& etrue) const 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 // Initialise maximum effective area 433 // Initialise maximum effective area
407 double max_aeff = 0.0; 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 // Loop over theta values 442 // Loop over theta values
413 for (int i = 0; i < n_theta; ++i) { 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 // Get effective area value in cm2 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 // Update maximum effective area if larger than current maximum 455 // Update maximum effective area if larger than current maximum
422 // effective area 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 } // endfor: loop over theta values 464 } // endfor: loop over theta values
@@ -446,12 +483,14 @@ std::string GCTAAeff2D::print(const GChatter&amp; chatter) const @@ -446,12 +483,14 @@ std::string GCTAAeff2D::print(const GChatter&amp; chatter) const
446 if (chatter != SILENT) { 483 if (chatter != SILENT) {
447 484
448 // Compute energy boundaries in TeV 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 // Compute offset angle boundaries in deg 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 // Append header 495 // Append header
457 result.append("=== GCTAAeff2D ==="); 496 result.append("=== GCTAAeff2D ===");
@@ -459,9 +498,9 @@ std::string GCTAAeff2D::print(const GChatter&amp; chatter) const @@ -459,9 +498,9 @@ std::string GCTAAeff2D::print(const GChatter&amp; chatter) const
459 // Append information 498 // Append information
460 result.append("\n"+gammalib::parformat("Filename")+m_filename); 499 result.append("\n"+gammalib::parformat("Filename")+m_filename);
461 result.append("\n"+gammalib::parformat("Number of energy bins") + 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 result.append("\n"+gammalib::parformat("Number of offset bins") + 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 result.append("\n"+gammalib::parformat("Log10(Energy) range")); 504 result.append("\n"+gammalib::parformat("Log10(Energy) range"));
466 result.append(gammalib::str(emin)+" - "+gammalib::str(emax)+" TeV"); 505 result.append(gammalib::str(emin)+" - "+gammalib::str(emax)+" TeV");
467 result.append("\n"+gammalib::parformat("Offset angle range")); 506 result.append("\n"+gammalib::parformat("Offset angle range"));
@@ -488,6 +527,10 @@ void GCTAAeff2D::init_members(void) @@ -488,6 +527,10 @@ void GCTAAeff2D::init_members(void)
488 // Initialise members 527 // Initialise members
489 m_filename.clear(); 528 m_filename.clear();
490 m_aeff.clear(); 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 // Return 535 // Return
493 return; 536 return;
@@ -502,8 +545,12 @@ void GCTAAeff2D::init_members(void) @@ -502,8 +545,12 @@ void GCTAAeff2D::init_members(void)
502 void GCTAAeff2D::copy_members(const GCTAAeff2D& aeff) 545 void GCTAAeff2D::copy_members(const GCTAAeff2D& aeff)
503 { 546 {
504 // Copy members 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 // Return 555 // Return
509 return; 556 return;