Commit d3d2a2fd1be5c29906269a22cee3915570d54d23
1 parent
1bcfc0f8
Correct stacked response computation.
The BACKRESP column in Arf has originally not been updated when stacking On/Off observations and the background scaling factor has not been computed correctly. This has been fixed now.
Showing
2 changed files
with
69 additions
and
83 deletions
inst/cta/include/GCTAOnOffObservation.hpp
| @@ -118,7 +118,6 @@ protected: | @@ -118,7 +118,6 @@ protected: | ||
| 118 | void init_members(void); | 118 | void init_members(void); |
| 119 | void copy_members(const GCTAOnOffObservation& obs); | 119 | void copy_members(const GCTAOnOffObservation& obs); |
| 120 | void free_members(void); | 120 | void free_members(void); |
| 121 | - void set_logetrue(void); | ||
| 122 | void set_exposure(void); | 121 | void set_exposure(void); |
| 123 | void check_consistency(const std::string& method) const; | 122 | void check_consistency(const std::string& method) const; |
| 124 | void set(const GCTAObservation& obs, | 123 | void set(const GCTAObservation& obs, |
| @@ -183,7 +182,6 @@ protected: | @@ -183,7 +182,6 @@ protected: | ||
| 183 | GPha m_off_spec; //!< Off counts spectrum | 182 | GPha m_off_spec; //!< Off counts spectrum |
| 184 | GArf m_arf; //!< Auxiliary Response Function vector | 183 | GArf m_arf; //!< Auxiliary Response Function vector |
| 185 | GRmf m_rmf; //!< Redistribution matrix | 184 | GRmf m_rmf; //!< Redistribution matrix |
| 186 | - GNodeArray m_logetrue; //!< Node array of log10 true energies in TeV | ||
| 187 | }; | 185 | }; |
| 188 | 186 | ||
| 189 | 187 |
inst/cta/src/GCTAOnOffObservation.cpp
| @@ -165,9 +165,6 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GPha& pha_on, | @@ -165,9 +165,6 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GPha& pha_on, | ||
| 165 | m_arf = arf; | 165 | m_arf = arf; |
| 166 | m_rmf = rmf; | 166 | m_rmf = rmf; |
| 167 | 167 | ||
| 168 | - // Set log true energy node array | ||
| 169 | - set_logetrue(); | ||
| 170 | - | ||
| 171 | // Set the ontime, livetime and deadtime correction | 168 | // Set the ontime, livetime and deadtime correction |
| 172 | set_exposure(); | 169 | set_exposure(); |
| 173 | 170 | ||
| @@ -244,8 +241,12 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GCTAObservation& obs, | @@ -244,8 +241,12 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GCTAObservation& obs, | ||
| 244 | * | 241 | * |
| 245 | * \f[ | 242 | * \f[ |
| 246 | * \alpha(E_{\rm reco}) = \frac{\sum_i \alpha_i(E_{\rm reco}) | 243 | * \alpha(E_{\rm reco}) = \frac{\sum_i \alpha_i(E_{\rm reco}) |
| 247 | - * N^{\rm off}_i(E_{\rm reco})} | ||
| 248 | - * {\sum_i N^{\rm off}_i(E_{\rm reco})} | 244 | + * B_i(E_{\rm reco}) \tau_i} |
| 245 | + * {\sum_i B_i(E_{\rm reco}) \tau_i} | ||
| 246 | + * \f] | ||
| 247 | + * | ||
| 248 | + * \f[ | ||
| 249 | + * B(E_{\rm reco}) = \frac{\sum_i B_i(E_{\rm reco}) \tau_i}{\sum_i \tau_i} | ||
| 249 | * \f] | 250 | * \f] |
| 250 | * | 251 | * |
| 251 | * \f[ | 252 | * \f[ |
| @@ -265,6 +266,7 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GCTAObservation& obs, | @@ -265,6 +266,7 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GCTAObservation& obs, | ||
| 265 | * \f$i\f$, | 266 | * \f$i\f$, |
| 266 | * \f$\alpha_i(E_{\rm reco})\f$ is the background scaling of observation | 267 | * \f$\alpha_i(E_{\rm reco})\f$ is the background scaling of observation |
| 267 | * \f$i\f$, | 268 | * \f$i\f$, |
| 269 | + * \f$B_i(E_{\rm reco})\f$ is the background rate for observation \f$i\f$, | ||
| 268 | * \f$ARF_i(E_{\rm true})\f$ is the Auxiliary Response File of observation | 270 | * \f$ARF_i(E_{\rm true})\f$ is the Auxiliary Response File of observation |
| 269 | * \f$i\f$, | 271 | * \f$i\f$, |
| 270 | * \f$RMF_i(E_{\rm true}, E_{\rm reco})\f$ is the Redistribution Matrix File | 272 | * \f$RMF_i(E_{\rm true}, E_{\rm reco})\f$ is the Redistribution Matrix File |
| @@ -311,6 +313,23 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GObservations& obs) : | @@ -311,6 +313,23 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GObservations& obs) : | ||
| 311 | m_livetime = onoff->livetime(); | 313 | m_livetime = onoff->livetime(); |
| 312 | exposure = onoff->on_spec().exposure(); | 314 | exposure = onoff->on_spec().exposure(); |
| 313 | 315 | ||
| 316 | + // Compute number of background events/MeV from BACKRESP column | ||
| 317 | + // and store result intermediately into Arf BACKRESP column | ||
| 318 | + std::vector<double>& backresp = m_arf["BACKRESP"]; | ||
| 319 | + for (int i = 0; i < backresp.size(); ++i) { | ||
| 320 | + backresp[i] *= onoff->on_spec().exposure(); | ||
| 321 | + } | ||
| 322 | + | ||
| 323 | + // Compute background scaling factor contribution | ||
| 324 | + for (int i = 0; i < m_on_spec.size(); ++i) { | ||
| 325 | + GEnergy emean = m_on_spec.ebounds().elogmean(i); | ||
| 326 | + double background = onoff->arf()("BACKRESP", emean); | ||
| 327 | + double exposure = onoff->on_spec().exposure(); | ||
| 328 | + double alpha = onoff->on_spec().backscal(i); | ||
| 329 | + double scale = alpha * background * exposure; | ||
| 330 | + m_on_spec.backscal(i,scale); | ||
| 331 | + } | ||
| 332 | + | ||
| 314 | // Compute RMF contribution | 333 | // Compute RMF contribution |
| 315 | for (int itrue = 0; itrue < m_rmf.ntrue(); ++itrue) { | 334 | for (int itrue = 0; itrue < m_rmf.ntrue(); ++itrue) { |
| 316 | double arf = m_arf[itrue]; | 335 | double arf = m_arf[itrue]; |
| @@ -355,29 +374,31 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GObservations& obs) : | @@ -355,29 +374,31 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GObservations& obs) : | ||
| 355 | throw GException::invalid_value(G_CONSTRUCTOR2, msg); | 374 | throw GException::invalid_value(G_CONSTRUCTOR2, msg); |
| 356 | } | 375 | } |
| 357 | 376 | ||
| 358 | - // Compute background scaling factor | ||
| 359 | - for (int i = 0; i < m_on_spec.size(); ++i) { | ||
| 360 | - | ||
| 361 | - // Compute background scaling factor for spectral bin | ||
| 362 | - double n1 = m_off_spec[i]; // Counts from Off | ||
| 363 | - double n2 = onoff->off_spec()[i]; // Counts from Off | ||
| 364 | - double a1 = m_on_spec.backscal(i); // Alpha from On | ||
| 365 | - double a2 = onoff->on_spec().backscal(i); // Alpha from On | ||
| 366 | - double n = n1 + n2; | ||
| 367 | - double a = (n > 0.0) ? (a1 * n1 + a2 * n2)/n : 1.0; | ||
| 368 | - | ||
| 369 | - // Set background scaling factor of On Spectrum | ||
| 370 | - m_on_spec.backscal(i,a); | ||
| 371 | - | ||
| 372 | - } // endfor: computed background scaling factors | ||
| 373 | - | ||
| 374 | // Add On and Off spectrum | 377 | // Add On and Off spectrum |
| 375 | m_on_spec += onoff->on_spec(); | 378 | m_on_spec += onoff->on_spec(); |
| 376 | m_off_spec += onoff->off_spec(); | 379 | m_off_spec += onoff->off_spec(); |
| 377 | 380 | ||
| 381 | + // Compute background scaling factor contribution | ||
| 382 | + for (int i = 0; i < m_on_spec.size(); ++i) { | ||
| 383 | + GEnergy emean = m_on_spec.ebounds().elogmean(i); | ||
| 384 | + double background = onoff->arf()("BACKRESP", emean); | ||
| 385 | + double exposure = onoff->on_spec().exposure(); | ||
| 386 | + double alpha = onoff->on_spec().backscal(i); | ||
| 387 | + double scale = m_on_spec.backscal(i) + | ||
| 388 | + alpha * background * exposure; | ||
| 389 | + m_on_spec.backscal(i,scale); | ||
| 390 | + } | ||
| 391 | + | ||
| 378 | // Add ARF | 392 | // Add ARF |
| 379 | m_arf += onoff->arf() * onoff->on_spec().exposure(); | 393 | m_arf += onoff->arf() * onoff->on_spec().exposure(); |
| 380 | 394 | ||
| 395 | + // Add number of background events/MeV from BACKRESP column | ||
| 396 | + const std::vector<double>& src = onoff->arf()["BACKRESP"]; | ||
| 397 | + std::vector<double>& dst = m_arf["BACKRESP"]; | ||
| 398 | + for (int i = 0; i < dst.size(); ++i) { | ||
| 399 | + dst[i] += src[i] * onoff->on_spec().exposure(); | ||
| 400 | + } | ||
| 401 | + | ||
| 381 | // Add RMF | 402 | // Add RMF |
| 382 | for (int itrue = 0; itrue < m_arf.size(); ++itrue) { | 403 | for (int itrue = 0; itrue < m_arf.size(); ++itrue) { |
| 383 | double arf = onoff->arf()[itrue] * onoff->on_spec().exposure(); | 404 | double arf = onoff->arf()[itrue] * onoff->on_spec().exposure(); |
| @@ -397,6 +418,19 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GObservations& obs) : | @@ -397,6 +418,19 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GObservations& obs) : | ||
| 397 | 418 | ||
| 398 | } // endfor: looped over observations | 419 | } // endfor: looped over observations |
| 399 | 420 | ||
| 421 | + // Compute stacked background scaling factor | ||
| 422 | + for (int i = 0; i < m_on_spec.size(); ++i) { | ||
| 423 | + GEnergy emean = m_on_spec.ebounds().elogmean(i); | ||
| 424 | + double norm = m_arf("BACKRESP", emean); | ||
| 425 | + if (norm > 0.0) { | ||
| 426 | + double scale = m_on_spec.backscal(i) / norm; | ||
| 427 | + m_on_spec.backscal(i,scale); | ||
| 428 | + } | ||
| 429 | + else { | ||
| 430 | + m_on_spec.backscal(i,0.0); | ||
| 431 | + } | ||
| 432 | + } | ||
| 433 | + | ||
| 400 | // Compute RMF | 434 | // Compute RMF |
| 401 | for (int itrue = 0; itrue < m_arf.size(); ++itrue) { | 435 | for (int itrue = 0; itrue < m_arf.size(); ++itrue) { |
| 402 | double arf = m_arf[itrue]; | 436 | double arf = m_arf[itrue]; |
| @@ -407,8 +441,18 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GObservations& obs) : | @@ -407,8 +441,18 @@ GCTAOnOffObservation::GCTAOnOffObservation(const GObservations& obs) : | ||
| 407 | 441 | ||
| 408 | // Compute ARF | 442 | // Compute ARF |
| 409 | if (exposure > 0.0) { | 443 | if (exposure > 0.0) { |
| 444 | + | ||
| 445 | + // Normalise Arf | ||
| 410 | m_arf /= exposure; | 446 | m_arf /= exposure; |
| 411 | - } | 447 | + |
| 448 | + // Compute background events/MeV/sec and store them in BACKRESP | ||
| 449 | + // column | ||
| 450 | + std::vector<double>& backresp = m_arf["BACKRESP"]; | ||
| 451 | + for (int i = 0; i < backresp.size(); ++i) { | ||
| 452 | + backresp[i] /= exposure; | ||
| 453 | + } | ||
| 454 | + | ||
| 455 | + } // endif: total exposure was positive | ||
| 412 | 456 | ||
| 413 | // Return | 457 | // Return |
| 414 | return; | 458 | return; |
| @@ -639,9 +683,6 @@ void GCTAOnOffObservation::read(const GXmlElement& xml) | @@ -639,9 +683,6 @@ void GCTAOnOffObservation::read(const GXmlElement& xml) | ||
| 639 | m_arf.load(arf); | 683 | m_arf.load(arf); |
| 640 | m_rmf.load(rmf); | 684 | m_rmf.load(rmf); |
| 641 | 685 | ||
| 642 | - // Set log true energy node array | ||
| 643 | - set_logetrue(); | ||
| 644 | - | ||
| 645 | // Set the ontime, livetime and deadtime correction | 686 | // Set the ontime, livetime and deadtime correction |
| 646 | set_exposure(); | 687 | set_exposure(); |
| 647 | 688 | ||
| @@ -809,7 +850,6 @@ void GCTAOnOffObservation::init_members(void) | @@ -809,7 +850,6 @@ void GCTAOnOffObservation::init_members(void) | ||
| 809 | m_off_spec.clear(); | 850 | m_off_spec.clear(); |
| 810 | m_arf.clear(); | 851 | m_arf.clear(); |
| 811 | m_rmf.clear(); | 852 | m_rmf.clear(); |
| 812 | - m_logetrue.clear(); | ||
| 813 | 853 | ||
| 814 | // Return | 854 | // Return |
| 815 | return; | 855 | return; |
| @@ -832,7 +872,6 @@ void GCTAOnOffObservation::copy_members(const GCTAOnOffObservation& obs) | @@ -832,7 +872,6 @@ void GCTAOnOffObservation::copy_members(const GCTAOnOffObservation& obs) | ||
| 832 | m_off_spec = obs.m_off_spec; | 872 | m_off_spec = obs.m_off_spec; |
| 833 | m_arf = obs.m_arf; | 873 | m_arf = obs.m_arf; |
| 834 | m_rmf = obs.m_rmf; | 874 | m_rmf = obs.m_rmf; |
| 835 | - m_logetrue = obs.m_logetrue; | ||
| 836 | 875 | ||
| 837 | // Clone members | 876 | // Clone members |
| 838 | m_response = (obs.m_response != NULL) ? obs.m_response->clone() : NULL; | 877 | m_response = (obs.m_response != NULL) ? obs.m_response->clone() : NULL; |
| @@ -854,39 +893,6 @@ void GCTAOnOffObservation::free_members(void) | @@ -854,39 +893,6 @@ void GCTAOnOffObservation::free_members(void) | ||
| 854 | 893 | ||
| 855 | 894 | ||
| 856 | /***********************************************************************//** | 895 | /***********************************************************************//** |
| 857 | - * @brief Set true energy node array | ||
| 858 | - ***************************************************************************/ | ||
| 859 | -void GCTAOnOffObservation::set_logetrue(void) | ||
| 860 | -{ | ||
| 861 | - // Clear node array | ||
| 862 | - m_logetrue.clear(); | ||
| 863 | - | ||
| 864 | - // Continue only if there are true energies in Arf | ||
| 865 | - int netrue = m_arf.size(); | ||
| 866 | - if (netrue > 0) { | ||
| 867 | - | ||
| 868 | - // Reserve space in node array | ||
| 869 | - m_logetrue.reserve(netrue); | ||
| 870 | - | ||
| 871 | - // Append all log mean energies to node array | ||
| 872 | - for (int i = 0; i < netrue; ++i) { | ||
| 873 | - | ||
| 874 | - // Get log mean of true energy in TeV | ||
| 875 | - double logE = m_arf.ebounds().elogmean(i).log10TeV(); | ||
| 876 | - | ||
| 877 | - // Append energy to node array | ||
| 878 | - m_logetrue.append(logE); | ||
| 879 | - | ||
| 880 | - } // endfor: appended log mean energies | ||
| 881 | - | ||
| 882 | - } // endif: there were true energies in Arf | ||
| 883 | - | ||
| 884 | - // Return | ||
| 885 | - return; | ||
| 886 | -} | ||
| 887 | - | ||
| 888 | - | ||
| 889 | -/***********************************************************************//** | ||
| 890 | * @brief Set ontime, livetime and deadtime correction factor | 896 | * @brief Set ontime, livetime and deadtime correction factor |
| 891 | ***************************************************************************/ | 897 | ***************************************************************************/ |
| 892 | void GCTAOnOffObservation::set_exposure(void) | 898 | void GCTAOnOffObservation::set_exposure(void) |
| @@ -1007,9 +1013,6 @@ void GCTAOnOffObservation::set(const GCTAObservation& obs, | @@ -1007,9 +1013,6 @@ void GCTAOnOffObservation::set(const GCTAObservation& obs, | ||
| 1007 | compute_alpha(obs, reg_on, reg_off); | 1013 | compute_alpha(obs, reg_on, reg_off); |
| 1008 | compute_rmf(obs, reg_on); | 1014 | compute_rmf(obs, reg_on); |
| 1009 | 1015 | ||
| 1010 | - // Set log true energy node array | ||
| 1011 | - set_logetrue(); | ||
| 1012 | - | ||
| 1013 | // Return | 1016 | // Return |
| 1014 | return; | 1017 | return; |
| 1015 | } | 1018 | } |
| @@ -1659,28 +1662,13 @@ double GCTAOnOffObservation::N_bgd(const GModels& models, | @@ -1659,28 +1662,13 @@ double GCTAOnOffObservation::N_bgd(const GModels& models, | ||
| 1659 | // Initialise parameter index | 1662 | // Initialise parameter index |
| 1660 | int ipar = 0; | 1663 | int ipar = 0; |
| 1661 | 1664 | ||
| 1662 | - // Get reference to background response (events/MeV/s) | ||
| 1663 | - const std::vector<double>& backresp = m_arf["BACKRESP"]; | ||
| 1664 | - | ||
| 1665 | // Get reconstructed energy bin mean and width | 1665 | // Get reconstructed energy bin mean and width |
| 1666 | GEnergy emean = m_on_spec.ebounds().elogmean(ibin); | 1666 | GEnergy emean = m_on_spec.ebounds().elogmean(ibin); |
| 1667 | double ewidth = m_on_spec.ebounds().ewidth(ibin).MeV(); | 1667 | double ewidth = m_on_spec.ebounds().ewidth(ibin).MeV(); |
| 1668 | 1668 | ||
| 1669 | - // Perform log-log interpolation of background rate at reconstructed | ||
| 1670 | - // energy | ||
| 1671 | - m_logetrue.set_value(emean.log10TeV()); | ||
| 1672 | - double wgt_left = m_logetrue.wgt_left(); | ||
| 1673 | - double wgt_right = m_logetrue.wgt_right(); | ||
| 1674 | - double bkg_left = backresp[m_logetrue.inx_left()]; | ||
| 1675 | - double bkg_right = backresp[m_logetrue.inx_right()]; | ||
| 1676 | - double background = 0.0; | ||
| 1677 | - if (bkg_left > 0.0 && bkg_right > 0.0) { | ||
| 1678 | - background = std::exp(wgt_left * std::log(bkg_left) + | ||
| 1679 | - wgt_right * std::log(bkg_right)); | ||
| 1680 | - } | ||
| 1681 | - if (background < 0.0) { | ||
| 1682 | - background = 0.0; | ||
| 1683 | - } | 1669 | + // Perform log-log interpolation of background rate (events/MeV/s) |
| 1670 | + // at reconstructed energy | ||
| 1671 | + double background = m_arf("BACKRESP", emean); | ||
| 1684 | 1672 | ||
| 1685 | // Compute normalisation factor (events) | 1673 | // Compute normalisation factor (events) |
| 1686 | double exposure = m_on_spec.exposure(); | 1674 | double exposure = m_on_spec.exposure(); |