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 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&amp; 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&amp; 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&amp; GCTAAeff2D::operator= (const GCTAAeff2D&amp; 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&amp; 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&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 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&amp; 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&amp; 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&amp; 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&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 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&amp; 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&amp; 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;
... ...