Commit b5c6b9a469fa3cb19a42605dbdfe72516c7b100f
1 parent
f18179e5
Normalize migration matrix upon loading by performing a numerical integration of…
… the energy dispersion access operator(). By this method we assure that the matrix is properly normalized, including the effects of numerical interpolation.
Showing
2 changed files
with
115 additions
and
38 deletions
inst/cta/include/GCTAEdisp2D.hpp
| ... | ... | @@ -31,6 +31,7 @@ |
| 31 | 31 | #include <string> |
| 32 | 32 | #include "GCTAEdisp.hpp" |
| 33 | 33 | #include "GCTAResponseTable.hpp" |
| 34 | +#include "GFunction.hpp" | |
| 34 | 35 | |
| 35 | 36 | /* __ Forward declarations _______________________________________________ */ |
| 36 | 37 | class GRan; |
| ... | ... | @@ -112,6 +113,22 @@ private: |
| 112 | 113 | const double& azimuth = 0.0) const; |
| 113 | 114 | void set_max_edisp(void) const; |
| 114 | 115 | |
| 116 | + // Protected classes | |
| 117 | + class edisp_kern : public GFunction { | |
| 118 | + public: | |
| 119 | + edisp_kern(const GCTAEdisp2D* parent, | |
| 120 | + const double& logEsrc, | |
| 121 | + const double& theta) : | |
| 122 | + m_parent(parent), | |
| 123 | + m_logEsrc(logEsrc), | |
| 124 | + m_theta(theta) { } | |
| 125 | + double eval(const double& x); | |
| 126 | + protected: | |
| 127 | + const GCTAEdisp2D* m_parent; //!< Pointer to parent class | |
| 128 | + const double& m_logEsrc; //!< True photon energy | |
| 129 | + const double& m_theta; //!< Offset angle | |
| 130 | + }; | |
| 131 | + | |
| 115 | 132 | // Members |
| 116 | 133 | std::string m_filename; //!< Name of Edisp response file |
| 117 | 134 | GCTAResponseTable m_edisp; //!< Edisp response table | ... | ... |
inst/cta/src/GCTAEdisp2D.cpp
| ... | ... | @@ -32,6 +32,7 @@ |
| 32 | 32 | #include <vector> |
| 33 | 33 | #include "GTools.hpp" |
| 34 | 34 | #include "GMath.hpp" |
| 35 | +#include "GIntegral.hpp" | |
| 35 | 36 | #include "GFits.hpp" |
| 36 | 37 | #include "GFitsTable.hpp" |
| 37 | 38 | #include "GFitsBinTable.hpp" |
| ... | ... | @@ -278,50 +279,78 @@ void GCTAEdisp2D::read(const GFits& fits) |
| 278 | 279 | // Read energy dispersion table |
| 279 | 280 | m_edisp.read(table); |
| 280 | 281 | |
| 282 | + // Set true energy axis to logarithmic scale | |
| 283 | + m_edisp.axis_log10(0); | |
| 284 | + | |
| 285 | + // Set offset angle axis to radians | |
| 286 | + m_edisp.axis_radians(2); | |
| 287 | + | |
| 281 | 288 | // Get axes dimensions |
| 282 | 289 | int etrue_size = m_edisp.axis(0); |
| 283 | 290 | int migra_size = m_edisp.axis(1); |
| 284 | 291 | int theta_size = m_edisp.axis(2); |
| 285 | 292 | |
| 286 | - // Normalize vectors of migration matrix for all etrue and theta | |
| 287 | - for (int i_etrue = 0; i_etrue < etrue_size; ++i_etrue) { | |
| 288 | - for (int i_theta = 0; i_theta < theta_size; ++i_theta) { | |
| 293 | + // Normalize vectors of migration matrix for all etrue and theta. | |
| 294 | + // Loop over offset angle. | |
| 295 | + for (int i_theta = 0; i_theta < theta_size; ++i_theta) { | |
| 289 | 296 | |
| 290 | - // Initialise sum and offset | |
| 291 | - double sum = 0.0; | |
| 292 | - int offset = i_etrue + (i_theta*migra_size) * etrue_size; | |
| 297 | + // Get offset angle (in radians) | |
| 298 | + double theta = 0.5 * (m_edisp.axis_lo(2,i_theta) + | |
| 299 | + m_edisp.axis_hi(2,i_theta)) * gammalib::deg2rad; | |
| 293 | 300 | |
| 294 | - // Compute sum | |
| 295 | - for (int i_migra = 0, i = offset; i_migra < migra_size; | |
| 296 | - ++i_migra, i += etrue_size) { | |
| 301 | + // Loop over true photon energy | |
| 302 | + for (int i_etrue = 0; i_etrue < etrue_size; ++i_etrue) { | |
| 297 | 303 | |
| 298 | - // Compute delta(Eobs/Etrue) and Eobs/Etrue | |
| 299 | - double delta = m_edisp.axis_hi(1, i_migra) - | |
| 300 | - m_edisp.axis_lo(1, i_migra); | |
| 301 | - double EobsOverEsrc = 0.5 * (m_edisp.axis_hi(1, i_migra) + | |
| 302 | - m_edisp.axis_lo(1, i_migra)); | |
| 304 | + // Get energy | |
| 305 | + double emin = std::log10(m_edisp.axis_lo(0,i_etrue)); | |
| 306 | + double emax = std::log10(m_edisp.axis_hi(0,i_etrue)); | |
| 307 | + double logEsrc = 0.5*(emin+emax); | |
| 303 | 308 | |
| 304 | - // Add dispersion matrix element to sum | |
| 305 | - sum += m_edisp(0, i) * delta / EobsOverEsrc; | |
| 309 | + // Now loop twice as ebounds_obs() actually depends on the | |
| 310 | + // value of the edisp matrix, hence we want to be sure that | |
| 311 | + // we integrate over the same range that is later used for | |
| 312 | + // the energy dispersion handling. | |
| 313 | + for (int iter = 0; iter < 2; ++iter) { | |
| 306 | 314 | |
| 307 | - } | |
| 315 | + // Get integration boundaries | |
| 316 | + GEbounds ebounds = ebounds_obs(logEsrc, theta); | |
| 308 | 317 | |
| 309 | - // Normalise by sum/log(10.0) | |
| 310 | - if (sum != 0.0) { | |
| 311 | - for (int i_migra = 0, i = offset; i_migra < migra_size; | |
| 312 | - ++i_migra, i += etrue_size) { | |
| 313 | - m_edisp(0, i) *= (gammalib::ln10 / sum); | |
| 314 | - } | |
| 315 | - } | |
| 318 | + // Initialise integration | |
| 319 | + double sum = 0.0; | |
| 316 | 320 | |
| 317 | - } // endfor: looped over theta | |
| 318 | - } // endfor: looped over Etrue | |
| 321 | + // Loop over all energy intervals | |
| 322 | + for (int i = 0; i < ebounds.size(); ++i) { | |
| 319 | 323 | |
| 320 | - // Set true energy axis to logarithmic scale | |
| 321 | - m_edisp.axis_log10(0); | |
| 324 | + // Get energy boundaries | |
| 325 | + emin = ebounds.emin(i).log10TeV(); | |
| 326 | + emax = ebounds.emax(i).log10TeV(); | |
| 322 | 327 | |
| 323 | - // Set offset angle axis to radians | |
| 324 | - m_edisp.axis_radians(2); | |
| 328 | + // Setup integration function | |
| 329 | + edisp_kern integrand(this, logEsrc, theta); | |
| 330 | + GIntegral integral(&integrand); | |
| 331 | + | |
| 332 | + // Set integration precision | |
| 333 | + integral.eps(1.0e-6); | |
| 334 | + | |
| 335 | + // Do Romberg integration | |
| 336 | + sum += integral.romberg(emin, emax); | |
| 337 | +//std::cout << theta << " " << logEsrc << " " << sum; | |
| 338 | +//std::cout << " e=[" << emin << "," << emax << "]" << std::endl; | |
| 339 | + | |
| 340 | + } // endfor: looped over all energy intervals | |
| 341 | + | |
| 342 | + // If sum is positive then renormalize vector | |
| 343 | + if (sum > 0.0) { | |
| 344 | + int offset = i_etrue + (i_theta*migra_size) * etrue_size; | |
| 345 | + for (int k = 0, i = offset; k < migra_size; ++k, i += etrue_size) { | |
| 346 | + m_edisp(0,i) /= sum; | |
| 347 | + } | |
| 348 | + } | |
| 349 | + | |
| 350 | + } // endfor: did two iterations | |
| 351 | + | |
| 352 | + } // endfor: looped over Etrue | |
| 353 | + } // endfor: looped over theta | |
| 325 | 354 | |
| 326 | 355 | // Set maximum energy dispersion value |
| 327 | 356 | set_max_edisp(); |
| ... | ... | @@ -678,14 +707,14 @@ void GCTAEdisp2D::compute_ebounds_obs(const double& theta, |
| 678 | 707 | m_ebounds_obs.clear(); |
| 679 | 708 | |
| 680 | 709 | // Set epsilon |
| 681 | - const double eps = 1.0e-06; | |
| 710 | + const double eps = 1.0e-12; | |
| 682 | 711 | |
| 683 | 712 | // Loop over Esrc |
| 684 | 713 | for (int isrc = 0; isrc < m_edisp.axis(0); ++isrc) { |
| 685 | 714 | |
| 686 | 715 | // Set Esrc |
| 687 | - double Esrc = 0.5 * (m_edisp.axis_hi(0, isrc) + | |
| 688 | - m_edisp.axis_lo(0, isrc)); | |
| 716 | + double Esrc = std::sqrt(m_edisp.axis_hi(0, isrc) * | |
| 717 | + m_edisp.axis_lo(0, isrc)); | |
| 689 | 718 | double logEsrc = std::log10(Esrc); |
| 690 | 719 | |
| 691 | 720 | // Initialise results |
| ... | ... | @@ -762,13 +791,14 @@ void GCTAEdisp2D::compute_ebounds_src(const double& theta, |
| 762 | 791 | m_ebounds_src.clear(); |
| 763 | 792 | |
| 764 | 793 | // Set epsilon |
| 765 | - const double eps = 1.0e-06; | |
| 794 | + const double eps = 1.0e-12; | |
| 766 | 795 | |
| 767 | 796 | // Loop over Eobs |
| 768 | 797 | for (int iobs = 0; iobs < m_edisp.axis(0); ++iobs) { |
| 769 | 798 | |
| 770 | - double Eobs = 0.5 * (m_edisp.axis_hi(0, iobs) + | |
| 771 | - m_edisp.axis_lo(0, iobs)); | |
| 799 | + // Set Eobs | |
| 800 | + double Eobs = std::sqrt(m_edisp.axis_hi(0, iobs) * | |
| 801 | + m_edisp.axis_lo(0, iobs)); | |
| 772 | 802 | double logEobs = std::log10(Eobs); |
| 773 | 803 | |
| 774 | 804 | // Initialise results |
| ... | ... | @@ -780,8 +810,9 @@ void GCTAEdisp2D::compute_ebounds_src(const double& theta, |
| 780 | 810 | // Find boundaries, loop over Esrc |
| 781 | 811 | for (int isrc = 0; isrc < m_edisp.axis(0); ++isrc) { |
| 782 | 812 | |
| 783 | - double Esrc = 0.5 * (m_edisp.axis_hi(0, isrc) + | |
| 784 | - m_edisp.axis_lo(0, isrc)); | |
| 813 | + // Set Esrc | |
| 814 | + double Esrc = std::sqrt(m_edisp.axis_hi(0, isrc) * | |
| 815 | + m_edisp.axis_lo(0, isrc)); | |
| 785 | 816 | double logEsrc = std::log10(Esrc); |
| 786 | 817 | |
| 787 | 818 | // Find first non-negligible matrix term |
| ... | ... | @@ -846,3 +877,32 @@ void GCTAEdisp2D::set_max_edisp(void) const |
| 846 | 877 | // Return |
| 847 | 878 | return; |
| 848 | 879 | } |
| 880 | + | |
| 881 | + | |
| 882 | +/***********************************************************************//** | |
| 883 | + * @brief Integration kernel for edisp_kern() class | |
| 884 | + * | |
| 885 | + * @param[in] x Function value. | |
| 886 | + * | |
| 887 | + * This method implements the integration kernel needed for the edisp_kern() | |
| 888 | + * class. | |
| 889 | + ***************************************************************************/ | |
| 890 | +double GCTAEdisp2D::edisp_kern::eval(const double& x) | |
| 891 | +{ | |
| 892 | + // Get function value | |
| 893 | + double value = m_parent->operator()(x, m_logEsrc, m_theta); | |
| 894 | + | |
| 895 | + // Compile option: Check for NaN | |
| 896 | + #if defined(G_NAN_CHECK) | |
| 897 | + if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { | |
| 898 | + std::cout << "*** ERROR: GCTAEdisp2D::edisp_kern::eval"; | |
| 899 | + std::cout << "(x=" << x << "): "; | |
| 900 | + std::cout << " NaN/Inf encountered"; | |
| 901 | + std::cout << " (value=" << value; | |
| 902 | + std::cout << ")" << std::endl; | |
| 903 | + } | |
| 904 | + #endif | |
| 905 | + | |
| 906 | + // Return value | |
| 907 | + return value; | |
| 908 | +} | ... | ... |