Commit f3da83abb4d8a0f71f8d34925446084a3cfb1dc7
1 parent
285fb246
Enhance precision of GCTAEdisp2D::compute_ebounds_src
Showing
4 changed files
with
285 additions
and
146 deletions
ChangeLog
| 1 | -2017-03-24 | |
| 1 | +2017-03-27 | |
| 2 | 2 | |
| 3 | 3 | * Version 1.3.0 released |
| 4 | 4 | ========================= |
| 5 | 5 | |
| 6 | + Enhance precision of GCTAEdisp2D::compute_ebounds_src | |
| 6 | 7 | Add conversion methods between GEbounds and GEnergies (#1977) |
| 7 | 8 | Add GModelSpectralSmoothBrokenPlaw class (#1948) |
| 8 | 9 | Implement lazy loading of energy dispersion in GCTAEdisp2D (#1940) | ... | ... |
NEWS
| 1 | 1 | New Features and Important Changes in GammaLib 1.3.0.dev1 |
| 2 | 2 | |
| 3 | -24 March 2017 | |
| 3 | +27 March 2017 | |
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | 1. Introduction |
| ... | ... | @@ -154,6 +154,12 @@ Lazy loading of the energy dispersion in GCTAEdisp2D has been implemented by |
| 154 | 154 | adding a fetch() method to the class. Now the energy dispersion is only loaded |
| 155 | 155 | when needed, for example for function evaluation or Monte Carlo sampling (#1940). |
| 156 | 156 | |
| 157 | +The GCTAEdisp2D::compute_ebounds_src method now loops over the migration to | |
| 158 | +enhance the precision in the true energy boundaries that are returned by this | |
| 159 | +method. In addition, the validity range of the table is now stored in members | |
| 160 | +of the class, and a non-zero energy dispersion is only returned for valid | |
| 161 | +elements of the response table. | |
| 162 | + | |
| 157 | 163 | |
| 158 | 164 | 21. COMPTEL interface |
| 159 | 165 | --------------------- | ... | ... |
inst/cta/include/GCTAEdisp2D.hpp
| ... | ... | @@ -119,7 +119,10 @@ private: |
| 119 | 119 | const double& phi = 0.0, |
| 120 | 120 | const double& zenith = 0.0, |
| 121 | 121 | const double& azimuth = 0.0) const; |
| 122 | + void set_indices(void); | |
| 123 | + void set_boundaries(void); | |
| 122 | 124 | void set_max_edisp(void) const; |
| 125 | + void normalize_table(void); | |
| 123 | 126 | |
| 124 | 127 | // Protected classes |
| 125 | 128 | class edisp_kern : public GFunction { |
| ... | ... | @@ -138,13 +141,19 @@ private: |
| 138 | 141 | }; |
| 139 | 142 | |
| 140 | 143 | // Members |
| 141 | - mutable GFilename m_filename; //!< Name of Edisp response file | |
| 142 | - GCTAResponseTable m_edisp; //!< Edisp response table | |
| 143 | - mutable bool m_fetched; //!< Signals that Edisp has been fetched | |
| 144 | - int m_inx_etrue; //!< True energy index | |
| 145 | - int m_inx_migra; //!< Migration index | |
| 146 | - int m_inx_theta; //!< Theta index | |
| 147 | - int m_inx_matrix; //!< Matrix | |
| 144 | + mutable GFilename m_filename; //!< Name of Edisp response file | |
| 145 | + GCTAResponseTable m_edisp; //!< Edisp response table | |
| 146 | + mutable bool m_fetched; //!< Signals that Edisp has been fetched | |
| 147 | + int m_inx_etrue; //!< True energy index | |
| 148 | + int m_inx_migra; //!< Migration index | |
| 149 | + int m_inx_theta; //!< Theta index | |
| 150 | + int m_inx_matrix; //!< Matrix | |
| 151 | + double m_logEsrc_min; //!< Minimum logE (log10(E/TeV)) | |
| 152 | + double m_logEsrc_max; //!< Maximum logE (log10(E/TeV)) | |
| 153 | + double m_migra_min; //!< Minimum migration | |
| 154 | + double m_migra_max; //!< Maximum migration | |
| 155 | + double m_theta_min; //!< Minimum theta (radians) | |
| 156 | + double m_theta_max; //!< Maximum theta (radians) | |
| 148 | 157 | |
| 149 | 158 | // Computation cache |
| 150 | 159 | mutable bool m_ebounds_obs_computed; |
| ... | ... | @@ -198,17 +207,4 @@ const GCTAResponseTable& GCTAEdisp2D::table(void) const |
| 198 | 207 | return (m_edisp); |
| 199 | 208 | } |
| 200 | 209 | |
| 201 | - | |
| 202 | -/***********************************************************************//** | |
| 203 | - * @brief Set response table | |
| 204 | - * | |
| 205 | - * @param[in] table Response table. | |
| 206 | - ***************************************************************************/ | |
| 207 | -inline | |
| 208 | -void GCTAEdisp2D::table(const GCTAResponseTable& table) | |
| 209 | -{ | |
| 210 | - m_edisp = table; | |
| 211 | - return; | |
| 212 | -} | |
| 213 | - | |
| 214 | 210 | #endif /* GCTAEDISP2D_HPP */ | ... | ... |
inst/cta/src/GCTAEdisp2D.cpp
| ... | ... | @@ -198,22 +198,33 @@ double GCTAEdisp2D::operator()(const double& logEobs, |
| 198 | 198 | // Initalize edisp |
| 199 | 199 | double edisp = 0.0; |
| 200 | 200 | |
| 201 | - // Compute Eobs/Esrc | |
| 202 | - double EobsOverEsrc = std::exp((logEobs-logEsrc) * gammalib::ln10); | |
| 201 | + // Continue only if logEsrc and theta are in validity range | |
| 202 | + if ((logEsrc >= m_logEsrc_min) && (logEsrc <= m_logEsrc_max) && | |
| 203 | + (theta >= m_theta_min) && (theta <= m_theta_max)) { | |
| 203 | 204 | |
| 204 | - // Setup argument vector | |
| 205 | - double arg[3]; | |
| 206 | - arg[m_inx_etrue] = logEsrc; | |
| 207 | - arg[m_inx_migra] = EobsOverEsrc; | |
| 208 | - arg[m_inx_theta] = theta; | |
| 205 | + // Compute Eobs/Esrc | |
| 206 | + double EobsOverEsrc = std::exp((logEobs-logEsrc) * gammalib::ln10); | |
| 209 | 207 | |
| 210 | - // Compute edisp | |
| 211 | - edisp = m_edisp(m_inx_matrix, arg[0], arg[1], arg[2]); | |
| 208 | + // Continue only if migration is in validity range | |
| 209 | + if ((EobsOverEsrc >= m_migra_min) && (EobsOverEsrc <= m_migra_max)) { | |
| 212 | 210 | |
| 213 | - // Make sure that energy dispersion is non-negative | |
| 214 | - if (edisp < 0.0) { | |
| 215 | - edisp = 0.0; | |
| 216 | - } | |
| 211 | + // Setup argument vector | |
| 212 | + double arg[3]; | |
| 213 | + arg[m_inx_etrue] = logEsrc; | |
| 214 | + arg[m_inx_migra] = EobsOverEsrc; | |
| 215 | + arg[m_inx_theta] = theta; | |
| 216 | + | |
| 217 | + // Compute edisp | |
| 218 | + edisp = m_edisp(m_inx_matrix, arg[0], arg[1], arg[2]); | |
| 219 | + | |
| 220 | + // Make sure that energy dispersion is non-negative | |
| 221 | + if (edisp < 0.0) { | |
| 222 | + edisp = 0.0; | |
| 223 | + } | |
| 224 | + | |
| 225 | + } // endif: migration was in valid range | |
| 226 | + | |
| 227 | + } // endif: true energy and offset angle was in valid range | |
| 217 | 228 | |
| 218 | 229 | // Return |
| 219 | 230 | return edisp; |
| ... | ... | @@ -260,6 +271,41 @@ GCTAEdisp2D* GCTAEdisp2D::clone(void) const |
| 260 | 271 | |
| 261 | 272 | |
| 262 | 273 | /***********************************************************************//** |
| 274 | + * @brief Assign response table | |
| 275 | + * | |
| 276 | + * @param[in] table Response table. | |
| 277 | + * | |
| 278 | + * Assigns the response table for an energy dispersion. | |
| 279 | + ***************************************************************************/ | |
| 280 | +void GCTAEdisp2D::table(const GCTAResponseTable& table) | |
| 281 | +{ | |
| 282 | + // Assign response table | |
| 283 | + m_edisp = table; | |
| 284 | + | |
| 285 | + // Set indices | |
| 286 | + set_indices(); | |
| 287 | + | |
| 288 | + // Set true energy axis to logarithmic scale | |
| 289 | + m_edisp.axis_log10(m_inx_etrue); | |
| 290 | + | |
| 291 | + // Set offset angle axis to radians | |
| 292 | + m_edisp.axis_radians(m_inx_theta); | |
| 293 | + | |
| 294 | + // Normalize energy dispersion table | |
| 295 | + normalize_table(); | |
| 296 | + | |
| 297 | + // Set maximum energy dispersion value | |
| 298 | + set_max_edisp(); | |
| 299 | + | |
| 300 | + // Set table boundaries | |
| 301 | + set_boundaries(); | |
| 302 | + | |
| 303 | + // Return | |
| 304 | + return; | |
| 305 | +} | |
| 306 | + | |
| 307 | + | |
| 308 | +/***********************************************************************//** | |
| 263 | 309 | * @brief Read energy dispersion from FITS table |
| 264 | 310 | * |
| 265 | 311 | * @param[in] table FITS table. |
| ... | ... | @@ -291,12 +337,6 @@ void GCTAEdisp2D::read(const GFitsTable& table) |
| 291 | 337 | // Read energy dispersion table |
| 292 | 338 | m_edisp.read(table); |
| 293 | 339 | |
| 294 | - // Get mandatory indices (throw exception if not found) | |
| 295 | - m_inx_etrue = m_edisp.axis("ETRUE"); | |
| 296 | - m_inx_migra = m_edisp.axis("MIGRA"); | |
| 297 | - m_inx_theta = m_edisp.axis("THETA"); | |
| 298 | - m_inx_matrix = m_edisp.table("MATRIX"); | |
| 299 | - | |
| 300 | 340 | // Throw an exception if the table is not two-dimensional |
| 301 | 341 | if (m_edisp.axes() != 3) { |
| 302 | 342 | std::string msg = "Expected three-dimensional energy dispersion " |
| ... | ... | @@ -307,94 +347,24 @@ void GCTAEdisp2D::read(const GFitsTable& table) |
| 307 | 347 | throw GException::invalid_value(G_READ, msg); |
| 308 | 348 | } |
| 309 | 349 | |
| 350 | + // Set table indices | |
| 351 | + set_indices(); | |
| 352 | + | |
| 310 | 353 | // Set true energy axis to logarithmic scale |
| 311 | 354 | m_edisp.axis_log10(m_inx_etrue); |
| 312 | 355 | |
| 313 | 356 | // Set offset angle axis to radians |
| 314 | 357 | m_edisp.axis_radians(m_inx_theta); |
| 315 | 358 | |
| 316 | - // Get axes dimensions | |
| 317 | - int etrue_size = m_edisp.axis_bins(m_inx_etrue); | |
| 318 | - int migra_size = m_edisp.axis_bins(m_inx_migra); | |
| 319 | - int theta_size = m_edisp.axis_bins(m_inx_theta); | |
| 320 | - | |
| 321 | - // Now normalize the migration matrix vectors. We do this by integrating | |
| 322 | - // for each true energy and offset angle the measured energy. We perform | |
| 323 | - // here two passes as the ebounds_obs() method depends on the content of | |
| 324 | - // the matrix, and by having two passes we are sure that we get a | |
| 325 | - // consistent energy interval. | |
| 326 | - for (int pass = 0; pass < 2; ++pass) { | |
| 327 | - | |
| 328 | - // Initialise sums | |
| 329 | - std::vector<double> sums; | |
| 330 | - sums.reserve(theta_size*etrue_size); | |
| 331 | - | |
| 332 | - // Loop over offset angle. | |
| 333 | - for (int i_theta = 0; i_theta < theta_size; ++i_theta) { | |
| 334 | - | |
| 335 | - // Get offset angle (in radians) | |
| 336 | - double theta = 0.5 * (m_edisp.axis_lo(m_inx_theta,i_theta) + | |
| 337 | - m_edisp.axis_hi(m_inx_theta,i_theta)) * | |
| 338 | - gammalib::deg2rad; | |
| 339 | - | |
| 340 | - // Loop over true photon energy | |
| 341 | - for (int i_etrue = 0; i_etrue < etrue_size; ++i_etrue) { | |
| 342 | - | |
| 343 | - // Get energy | |
| 344 | - double emin = std::log10(m_edisp.axis_lo(m_inx_etrue,i_etrue)); | |
| 345 | - double emax = std::log10(m_edisp.axis_hi(m_inx_etrue,i_etrue)); | |
| 346 | - double logEsrc = 0.5*(emin+emax); | |
| 347 | - | |
| 348 | - // Initialise integration | |
| 349 | - double sum = 0.0; | |
| 350 | - | |
| 351 | - // Get integration boundaries | |
| 352 | - GEbounds ebounds = ebounds_obs(logEsrc, theta); | |
| 353 | - | |
| 354 | - // Loop over all energy intervals | |
| 355 | - for (int i = 0; i < ebounds.size(); ++i) { | |
| 356 | - | |
| 357 | - // Get energy boundaries | |
| 358 | - emin = ebounds.emin(i).log10TeV(); | |
| 359 | - emax = ebounds.emax(i).log10TeV(); | |
| 360 | - | |
| 361 | - // Setup integration function | |
| 362 | - edisp_kern integrand(this, logEsrc, theta); | |
| 363 | - GIntegral integral(&integrand); | |
| 364 | - | |
| 365 | - // Set integration precision | |
| 366 | - integral.eps(1.0e-6); | |
| 367 | - | |
| 368 | - // Do Romberg integration | |
| 369 | - sum += integral.romberg(emin, emax); | |
| 370 | - | |
| 371 | - } // endfor: looped over energy intervals | |
| 372 | - | |
| 373 | - // Store sum | |
| 374 | - sums.push_back(sum); | |
| 375 | - | |
| 376 | - } // endfor: looped over Etrue | |
| 377 | - | |
| 378 | - } // endfor: looped over theta | |
| 379 | - | |
| 380 | - // Normalize vectors of migration matrix for all etrue and theta. | |
| 381 | - for (int i_theta = 0, inx = 0; i_theta < theta_size; ++i_theta) { | |
| 382 | - for (int i_etrue = 0; i_etrue < etrue_size; ++i_etrue, ++inx) { | |
| 383 | - double sum = sums[inx]; | |
| 384 | - if (sum > 0.0) { | |
| 385 | - int offset = i_etrue + (i_theta*migra_size) * etrue_size; | |
| 386 | - for (int k = 0, i = offset; k < migra_size; ++k, i += etrue_size) { | |
| 387 | - m_edisp(m_inx_matrix,i) /= sum; | |
| 388 | - } | |
| 389 | - } | |
| 390 | - } | |
| 391 | - } | |
| 392 | - | |
| 393 | - } // endfor: made 2 passes | |
| 359 | + // Normalize energy dispersion table | |
| 360 | + normalize_table(); | |
| 394 | 361 | |
| 395 | 362 | // Set maximum energy dispersion value |
| 396 | 363 | set_max_edisp(); |
| 397 | 364 | |
| 365 | + // Set table boundaries | |
| 366 | + set_boundaries(); | |
| 367 | + | |
| 398 | 368 | // Return |
| 399 | 369 | return; |
| 400 | 370 | } |
| ... | ... | @@ -857,11 +827,17 @@ void GCTAEdisp2D::init_members(void) |
| 857 | 827 | // Initialise members |
| 858 | 828 | m_filename.clear(); |
| 859 | 829 | m_edisp.clear(); |
| 860 | - m_fetched = false; | |
| 861 | - m_inx_etrue = 0; | |
| 862 | - m_inx_migra = 1; | |
| 863 | - m_inx_theta = 2; | |
| 864 | - m_inx_matrix = 0; | |
| 830 | + m_fetched = false; | |
| 831 | + m_inx_etrue = 0; | |
| 832 | + m_inx_migra = 1; | |
| 833 | + m_inx_theta = 2; | |
| 834 | + m_inx_matrix = 0; | |
| 835 | + m_logEsrc_min = 0.0; | |
| 836 | + m_logEsrc_max = 0.0; | |
| 837 | + m_migra_min = 0.0; | |
| 838 | + m_migra_max = 0.0; | |
| 839 | + m_theta_min = 0.0; | |
| 840 | + m_theta_max = 0.0; | |
| 865 | 841 | |
| 866 | 842 | // Initialise computation cache |
| 867 | 843 | m_ebounds_obs_computed = false; |
| ... | ... | @@ -889,13 +865,19 @@ void GCTAEdisp2D::init_members(void) |
| 889 | 865 | void GCTAEdisp2D::copy_members(const GCTAEdisp2D& edisp) |
| 890 | 866 | { |
| 891 | 867 | // Copy members |
| 892 | - m_filename = edisp.m_filename; | |
| 893 | - m_edisp = edisp.m_edisp; | |
| 894 | - m_fetched = edisp.m_fetched; | |
| 895 | - m_inx_etrue = edisp.m_inx_etrue; | |
| 896 | - m_inx_migra = edisp.m_inx_migra; | |
| 897 | - m_inx_theta = edisp.m_inx_theta; | |
| 898 | - m_inx_matrix = edisp.m_inx_matrix; | |
| 868 | + m_filename = edisp.m_filename; | |
| 869 | + m_edisp = edisp.m_edisp; | |
| 870 | + m_fetched = edisp.m_fetched; | |
| 871 | + m_inx_etrue = edisp.m_inx_etrue; | |
| 872 | + m_inx_migra = edisp.m_inx_migra; | |
| 873 | + m_inx_theta = edisp.m_inx_theta; | |
| 874 | + m_inx_matrix = edisp.m_inx_matrix; | |
| 875 | + m_logEsrc_min = edisp.m_logEsrc_min; | |
| 876 | + m_logEsrc_max = edisp.m_logEsrc_max; | |
| 877 | + m_migra_min = edisp.m_migra_min; | |
| 878 | + m_migra_max = edisp.m_migra_max; | |
| 879 | + m_theta_min = edisp.m_theta_min; | |
| 880 | + m_theta_max = edisp.m_theta_max; | |
| 899 | 881 | |
| 900 | 882 | // Copy computation cache |
| 901 | 883 | m_ebounds_obs_computed = edisp.m_ebounds_obs_computed; |
| ... | ... | @@ -1063,7 +1045,8 @@ void GCTAEdisp2D::compute_ebounds_src(const double& theta, |
| 1063 | 1045 | const double eps = 1.0e-12; |
| 1064 | 1046 | |
| 1065 | 1047 | // Determine number of true energy bins |
| 1066 | - int n_bins = m_edisp.axis_bins(m_inx_etrue); | |
| 1048 | + int n_bins = m_edisp.axis_bins(m_inx_etrue); | |
| 1049 | + int n_migras = m_edisp.axis_bins(m_inx_migra); | |
| 1067 | 1050 | |
| 1068 | 1051 | // Loop over Eobs |
| 1069 | 1052 | for (int iobs = 0; iobs < n_bins; ++iobs) { |
| ... | ... | @@ -1080,40 +1063,54 @@ void GCTAEdisp2D::compute_ebounds_src(const double& theta, |
| 1080 | 1063 | bool maxFound = false; |
| 1081 | 1064 | |
| 1082 | 1065 | // Find minimum boundary |
| 1083 | - for (int isrc = 0; isrc < n_bins; ++isrc) { | |
| 1066 | + for (int imigra = 0; imigra < n_migras; ++imigra) { | |
| 1084 | 1067 | |
| 1085 | - // Set Esrc | |
| 1086 | - double Esrc = std::sqrt(m_edisp.axis_hi(m_inx_etrue,isrc) * | |
| 1087 | - m_edisp.axis_lo(m_inx_etrue,isrc)); | |
| 1088 | - double logEsrc = std::log10(Esrc); | |
| 1068 | + // Get mean migra | |
| 1069 | + double migra = 0.5 * (m_edisp.axis_lo(m_inx_migra,imigra) + | |
| 1070 | + m_edisp.axis_lo(m_inx_migra,imigra)); | |
| 1071 | + | |
| 1072 | + // Fall through if migration is zero | |
| 1073 | + if (migra == 0.0) { | |
| 1074 | + continue; | |
| 1075 | + } | |
| 1076 | + | |
| 1077 | + // Compute log10 of true energy | |
| 1078 | + double logEsrc = logEobs - std::log10(migra); | |
| 1089 | 1079 | |
| 1090 | 1080 | // Get matrix term |
| 1091 | 1081 | double edisp = operator()(logEobs, logEsrc, theta); |
| 1092 | 1082 | |
| 1093 | 1083 | // Find first non-negligible matrix term |
| 1094 | 1084 | if (edisp >= eps) { |
| 1095 | - minFound = true; | |
| 1096 | - logEsrcMin = logEsrc; | |
| 1085 | + maxFound = true; | |
| 1086 | + logEsrcMax = logEsrc; | |
| 1097 | 1087 | break; |
| 1098 | 1088 | } |
| 1099 | 1089 | |
| 1100 | 1090 | } // endfor: find minimum boundary |
| 1101 | 1091 | |
| 1102 | 1092 | // Find maximum boundary |
| 1103 | - for (int isrc = n_bins-1; isrc >= 0; isrc--) { | |
| 1093 | + for (int imigra = n_migras-1; imigra >= 0; imigra--) { | |
| 1094 | + | |
| 1095 | + // Get mean migra | |
| 1096 | + double migra = 0.5 * (m_edisp.axis_lo(m_inx_migra,imigra) + | |
| 1097 | + m_edisp.axis_lo(m_inx_migra,imigra)); | |
| 1098 | + | |
| 1099 | + // Fall through if migration is zero | |
| 1100 | + if (migra == 0.0) { | |
| 1101 | + continue; | |
| 1102 | + } | |
| 1104 | 1103 | |
| 1105 | - // Set Esrc | |
| 1106 | - double Esrc = std::sqrt(m_edisp.axis_hi(m_inx_etrue,isrc) * | |
| 1107 | - m_edisp.axis_lo(m_inx_etrue,isrc)); | |
| 1108 | - double logEsrc = std::log10(Esrc); | |
| 1104 | + // Compute log10 of true energy | |
| 1105 | + double logEsrc = logEobs - std::log10(migra); | |
| 1109 | 1106 | |
| 1110 | 1107 | // Get matrix term |
| 1111 | 1108 | double edisp = operator()(logEobs, logEsrc, theta); |
| 1112 | 1109 | |
| 1113 | 1110 | // Find first non-negligible matrix term |
| 1114 | 1111 | if (edisp >= eps) { |
| 1115 | - maxFound = true; | |
| 1116 | - logEsrcMax = logEsrc; | |
| 1112 | + minFound = true; | |
| 1113 | + logEsrcMin = logEsrc; | |
| 1117 | 1114 | break; |
| 1118 | 1115 | } |
| 1119 | 1116 | |
| ... | ... | @@ -1143,6 +1140,56 @@ void GCTAEdisp2D::compute_ebounds_src(const double& theta, |
| 1143 | 1140 | |
| 1144 | 1141 | |
| 1145 | 1142 | /***********************************************************************//** |
| 1143 | + * @brief Set table indices | |
| 1144 | + * | |
| 1145 | + * Sets the data members m_inx_etrue, m_inx_migra, m_inx_theta, and | |
| 1146 | + * m_inx_matrix. | |
| 1147 | + ***************************************************************************/ | |
| 1148 | +void GCTAEdisp2D::set_indices(void) | |
| 1149 | +{ | |
| 1150 | + // Get mandatory indices (throw exception if not found) | |
| 1151 | + m_inx_etrue = m_edisp.axis("ETRUE"); | |
| 1152 | + m_inx_migra = m_edisp.axis("MIGRA"); | |
| 1153 | + m_inx_theta = m_edisp.axis("THETA"); | |
| 1154 | + m_inx_matrix = m_edisp.table("MATRIX"); | |
| 1155 | + | |
| 1156 | + // Return | |
| 1157 | + return; | |
| 1158 | +} | |
| 1159 | + | |
| 1160 | + | |
| 1161 | +/***********************************************************************//** | |
| 1162 | + * @brief Set energy dispersion boundaries | |
| 1163 | + * | |
| 1164 | + * Sets the data members m_logEsrc_min, m_logEsrc_max, m_migra_min, | |
| 1165 | + * m_migra_max, m_theta_min and m_theta_max that define the validity range | |
| 1166 | + * of the energy dispersion. | |
| 1167 | + ***************************************************************************/ | |
| 1168 | +void GCTAEdisp2D::set_boundaries(void) | |
| 1169 | +{ | |
| 1170 | + // Get number of bins | |
| 1171 | + int netrue = m_edisp.axis_bins(m_inx_etrue); | |
| 1172 | + int nmigra = m_edisp.axis_bins(m_inx_migra); | |
| 1173 | + int ntheta = m_edisp.axis_bins(m_inx_theta); | |
| 1174 | + | |
| 1175 | + // Compute minimum and maximum logEsrc boundaries | |
| 1176 | + m_logEsrc_min = std::log10(m_edisp.axis_lo(m_inx_etrue, 0)); | |
| 1177 | + m_logEsrc_max = std::log10(m_edisp.axis_hi(m_inx_etrue, netrue-1)); | |
| 1178 | + | |
| 1179 | + // Compute minimum and maximum migration boundaries | |
| 1180 | + m_migra_min = m_edisp.axis_lo(m_inx_migra, 0); | |
| 1181 | + m_migra_max = m_edisp.axis_hi(m_inx_migra, nmigra-1); | |
| 1182 | + | |
| 1183 | + // Compute minimum and maximum theta boundaries | |
| 1184 | + m_theta_min = m_edisp.axis_lo(m_inx_theta, 0) * gammalib::deg2rad; | |
| 1185 | + m_theta_max = m_edisp.axis_hi(m_inx_theta, ntheta-1) * gammalib::deg2rad; | |
| 1186 | + | |
| 1187 | + // Return | |
| 1188 | + return; | |
| 1189 | +} | |
| 1190 | + | |
| 1191 | + | |
| 1192 | +/***********************************************************************//** | |
| 1146 | 1193 | * @brief Set maximum energy dispersion value |
| 1147 | 1194 | ***************************************************************************/ |
| 1148 | 1195 | void GCTAEdisp2D::set_max_edisp(void) const |
| ... | ... | @@ -1164,6 +1211,95 @@ void GCTAEdisp2D::set_max_edisp(void) const |
| 1164 | 1211 | |
| 1165 | 1212 | |
| 1166 | 1213 | /***********************************************************************//** |
| 1214 | + * @brief Normalize energy dispersion table | |
| 1215 | + ***************************************************************************/ | |
| 1216 | +void GCTAEdisp2D::normalize_table(void) | |
| 1217 | +{ | |
| 1218 | + // Get axes dimensions | |
| 1219 | + int etrue_size = m_edisp.axis_bins(m_inx_etrue); | |
| 1220 | + int migra_size = m_edisp.axis_bins(m_inx_migra); | |
| 1221 | + int theta_size = m_edisp.axis_bins(m_inx_theta); | |
| 1222 | + | |
| 1223 | + // Now normalize the migration matrix vectors. We do this by integrating | |
| 1224 | + // for each true energy and offset angle the measured energy. We perform | |
| 1225 | + // here two passes as the ebounds_obs() method depends on the content of | |
| 1226 | + // the matrix, and by having two passes we are sure that we get a | |
| 1227 | + // consistent energy interval. | |
| 1228 | + for (int pass = 0; pass < 2; ++pass) { | |
| 1229 | + | |
| 1230 | + // Initialise sums | |
| 1231 | + std::vector<double> sums; | |
| 1232 | + sums.reserve(theta_size*etrue_size); | |
| 1233 | + | |
| 1234 | + // Loop over offset angle. | |
| 1235 | + for (int i_theta = 0; i_theta < theta_size; ++i_theta) { | |
| 1236 | + | |
| 1237 | + // Get offset angle (in radians) | |
| 1238 | + double theta = 0.5 * (m_edisp.axis_lo(m_inx_theta,i_theta) + | |
| 1239 | + m_edisp.axis_hi(m_inx_theta,i_theta)) * | |
| 1240 | + gammalib::deg2rad; | |
| 1241 | + | |
| 1242 | + // Loop over true photon energy | |
| 1243 | + for (int i_etrue = 0; i_etrue < etrue_size; ++i_etrue) { | |
| 1244 | + | |
| 1245 | + // Get energy | |
| 1246 | + double emin = std::log10(m_edisp.axis_lo(m_inx_etrue,i_etrue)); | |
| 1247 | + double emax = std::log10(m_edisp.axis_hi(m_inx_etrue,i_etrue)); | |
| 1248 | + double logEsrc = 0.5*(emin+emax); | |
| 1249 | + | |
| 1250 | + // Initialise integration | |
| 1251 | + double sum = 0.0; | |
| 1252 | + | |
| 1253 | + // Get integration boundaries | |
| 1254 | + GEbounds ebounds = ebounds_obs(logEsrc, theta); | |
| 1255 | + | |
| 1256 | + // Loop over all energy intervals | |
| 1257 | + for (int i = 0; i < ebounds.size(); ++i) { | |
| 1258 | + | |
| 1259 | + // Get energy boundaries | |
| 1260 | + emin = ebounds.emin(i).log10TeV(); | |
| 1261 | + emax = ebounds.emax(i).log10TeV(); | |
| 1262 | + | |
| 1263 | + // Setup integration function | |
| 1264 | + edisp_kern integrand(this, logEsrc, theta); | |
| 1265 | + GIntegral integral(&integrand); | |
| 1266 | + | |
| 1267 | + // Set integration precision | |
| 1268 | + integral.eps(1.0e-6); | |
| 1269 | + | |
| 1270 | + // Do Romberg integration | |
| 1271 | + sum += integral.romberg(emin, emax); | |
| 1272 | + | |
| 1273 | + } // endfor: looped over energy intervals | |
| 1274 | + | |
| 1275 | + // Store sum | |
| 1276 | + sums.push_back(sum); | |
| 1277 | + | |
| 1278 | + } // endfor: looped over Etrue | |
| 1279 | + | |
| 1280 | + } // endfor: looped over theta | |
| 1281 | + | |
| 1282 | + // Normalize vectors of migration matrix for all etrue and theta. | |
| 1283 | + for (int i_theta = 0, inx = 0; i_theta < theta_size; ++i_theta) { | |
| 1284 | + for (int i_etrue = 0; i_etrue < etrue_size; ++i_etrue, ++inx) { | |
| 1285 | + double sum = sums[inx]; | |
| 1286 | + if (sum > 0.0) { | |
| 1287 | + int offset = i_etrue + (i_theta*migra_size) * etrue_size; | |
| 1288 | + for (int k = 0, i = offset; k < migra_size; ++k, i += etrue_size) { | |
| 1289 | + m_edisp(m_inx_matrix,i) /= sum; | |
| 1290 | + } | |
| 1291 | + } | |
| 1292 | + } | |
| 1293 | + } | |
| 1294 | + | |
| 1295 | + } // endfor: made 2 passes | |
| 1296 | + | |
| 1297 | + // Return | |
| 1298 | + return; | |
| 1299 | +} | |
| 1300 | + | |
| 1301 | + | |
| 1302 | +/***********************************************************************//** | |
| 1167 | 1303 | * @brief Integration kernel for edisp_kern() class |
| 1168 | 1304 | * |
| 1169 | 1305 | * @param[in] x Function value. | ... | ... |