Commit 4c2771c1b62396df74ba0c6137e2b7e60aaa5f85

Authored by Florent Forest
1 parent cdd1386a

Added inv_ln10, bisection searches for MC, computation of cumulated probability for each true energy

include/GMath.hpp
... ... @@ -51,6 +51,7 @@ namespace gammalib {
51 51 const double sqrt_onehalf = std::sqrt(1.0/2.0);
52 52 const double sqrt_pihalf = std::sqrt(pihalf);
53 53 const double sqrt_two = std::sqrt(2.0);
  54 + const double inv_ln10 = 1.0/ln10;
54 55 }
55 56  
56 57 /* __ Prototypes _________________________________________________________ */
... ...
inst/cta/include/GCTAEdisp2D.hpp
... ... @@ -103,10 +103,18 @@ private:
103 103 void update(const double& logEobs,
104 104 const double& logEsrc,
105 105 const double& theta) const;
  106 + void update_cumul(const double& logEsrc,
  107 + const double& theta = 0.0,
  108 + const double& phi = 0.0,
  109 + const double& zenith = 0.0,
  110 + const double& azimuth = 0.0) const;
106 111  
107 112 // Members
108 113 std::string m_filename; //!< Name of Edisp response file
109 114 GCTAResponseTable m_edisp; //!< Edisp response table
  115 + mutable double m_logEsrc;
  116 + mutable double m_theta;
  117 + mutable std::vector<std::pair<double, double> > m_cumul;
110 118 };
111 119  
112 120  
... ...
inst/cta/include/GCTAEdispRmf.hpp
... ... @@ -100,11 +100,10 @@ private:
100 100 void set_cache(void) const;
101 101 void set_mc_cache(void) const;
102 102 void update(const double& arg1, const double& arg2) const;
103   - void update_cumul(const double& logEsrc,
104   - const double& theta = 0.0,
105   - const double& phi = 0.0,
106   - const double& zenith = 0.0,
107   - const double& azimuth = 0.0) const;
  103 + void compute_cumul(const double& theta = 0.0,
  104 + const double& phi = 0.0,
  105 + const double& zenith = 0.0,
  106 + const double& azimuth = 0.0) const;
108 107  
109 108 // Members
110 109 std::string m_filename; //!< Name of response file
... ... @@ -128,9 +127,11 @@ private:
128 127 // Monte Carlo cache
129 128 mutable std::vector<int> m_mc_measured_start;
130 129 mutable std::vector<GVector> m_mc_measured_cdf;
131   - mutable double m_logEsrc;
  130 + mutable bool m_cdf_computed;
132 131 mutable double m_theta;
133   - mutable std::vector<std::pair<double, double> > m_cumul;
  132 +
  133 + mutable std::vector<std::vector<std::pair<double, double> > > m_cumul;
  134 +
134 135 };
135 136  
136 137  
... ...
inst/cta/src/GCTAEdisp2D.cpp
... ... @@ -77,6 +77,7 @@ GCTAEdisp2D::GCTAEdisp2D(void) : GCTAEdisp()
77 77 ***************************************************************************/
78 78 GCTAEdisp2D::GCTAEdisp2D(const std::string& filename) : GCTAEdisp()
79 79 {
  80 +
80 81 // Initialise class members
81 82 init_members();
82 83  
... ... @@ -182,8 +183,6 @@ double GCTAEdisp2D::operator()(const double&amp; logEobs,
182 183 double EobsOverEsrc = std::exp((logEobs-logEsrc) * gammalib::ln10);
183 184  
184 185 // Compute edisp
185   - //edisp = m_edisp(0, logEsrc, std::exp((logEobs-logEsrc)*std::log(10.0)),
186   - // theta);
187 186 edisp = m_edisp(0, logEsrc, EobsOverEsrc, theta);
188 187  
189 188 // Return
... ... @@ -237,6 +236,7 @@ GCTAEdisp2D* GCTAEdisp2D::clone(void) const
237 236 ***************************************************************************/
238 237 void GCTAEdisp2D::load(const std::string& filename)
239 238 {
  239 +
240 240 // Open FITS file
241 241 GFits fits(filename);
242 242  
... ... @@ -269,6 +269,7 @@ void GCTAEdisp2D::load(const std::string&amp; filename)
269 269 ***************************************************************************/
270 270 void GCTAEdisp2D::read(const GFits& fits)
271 271 {
  272 +
272 273 // Clear response table
273 274 m_edisp.clear();
274 275  
... ... @@ -310,10 +311,10 @@ void GCTAEdisp2D::read(const GFits&amp; fits)
310 311 if (sum != 0.0) {
311 312 for (int i_migra = 0, i = offset; i_migra < migra_size;
312 313 ++i_migra, i += etrue_size) {
313   - m_edisp(0, i) /= (sum / gammalib::ln10);
  314 + m_edisp(0, i) *= (gammalib::ln10 / sum);
314 315 }
315 316 }
316   -
  317 +
317 318 } // endfor: looped over theta
318 319 } // endfor: looped over Etrue
319 320  
... ... @@ -391,66 +392,32 @@ GEnergy GCTAEdisp2D::mc(GRan&amp; ran,
391 392 const double& zenith,
392 393 const double& azimuth) const
393 394 {
394   - // Vector representing cumulative probability distribution
395   - std::vector<std::pair<double, double> > cumul;
396   -
397   - // Initialize cumulative probability
398   - double sum = 0.0;
399   -
400   - // Loop over EobsOverEsrc
401   - // TODO: We should precompute the cumulative distributions for all
402   - // tabluated Esrc values and put them in a Monte Carlo cache.
403   - // It's probably sufficient to select the nearest vector and
404   - // use it to draw energies. Otherwise this method will be
405   - // very slow as it computes the individual vectors for each
406   - // call.
407   - for (int i = 0; i < m_edisp.axis(1); ++i) {
408   -
409   - // Stop if we have reached the maximum
410   - if (sum == 1.0) {
411   - break;
412   - }
413   -
414   - // Compute delta(Eobs/Etrue) and Eobs/Etrue values
415   - double delta = m_edisp.axis_hi(1, i) -
416   - m_edisp.axis_lo(1, i);
417   - double EobsOverEsrc = 0.5 * (m_edisp.axis_hi(1, i) +
418   - m_edisp.axis_lo(1, i));
419   -
420   - // Compute cumulative probability
421   - double add = m_edisp(0, logEsrc, EobsOverEsrc, theta) *
422   - delta / EobsOverEsrc / gammalib::ln10;
423   -
424   - // Limit cumulative probability to 1
425   - sum += add;
426   - if (sum > 1.0) {
427   - sum = 1.0;
428   - }
429 395  
430   - // Create pair containing EobsOverEsrc and cumulated probability
431   - std::pair<double, double> pair(EobsOverEsrc, sum);
432   -
433   - // Add to vector
434   - cumul.push_back(pair);
435   -
436   - } // endfor: looped over EobsOverEsrc
  396 + // Update cumul
  397 + update_cumul(logEsrc, theta, phi, zenith, azimuth);
437 398  
438 399 // Draw random number between 0 and 1 from uniform distribution
439 400 double p = ran.uniform();
440 401  
441   - // Find right index
442   - // TODO: This can lead to index = m_edisp.axis(1) on axit, which
443   - // leads to an array indexing problem in the interpolation.
444   - // Also, a bisection search would be more efficient.
445   - int index = 0;
446   - while(index < m_edisp.axis(1) - 2 && cumul[index+1].second < p) {
447   - index++;
448   - } // index found
  402 + // Find right index with bisection search
  403 + int low = 0;
  404 + int high = m_cumul.size();
  405 + while ((high-low) > 1) {
  406 + int mid = (low+high) / 2;
  407 + if (p < m_cumul[mid].second) {
  408 + high = mid;
  409 + }
  410 + else if (m_cumul[mid].second <= p) {
  411 + low = mid;
  412 + }
  413 + }
  414 + // Index found
  415 + int index = low;
449 416  
450 417 // Interpolate EobsOverEsrc value
451   - double result = (cumul[index+1].second - p)*cumul[index].first
452   - + (p - cumul[index].second)*cumul[index+1].first;
453   - result /= (cumul[index+1].second - cumul[index].second);
  418 + double result = (m_cumul[index+1].second - p)*m_cumul[index].first
  419 + + (p - m_cumul[index].second)*m_cumul[index+1].first;
  420 + result /= (m_cumul[index+1].second - m_cumul[index].second);
454 421  
455 422 // Final result
456 423 double logEnergy = std::log10(result) + logEsrc;
... ... @@ -520,7 +487,7 @@ GEbounds GCTAEdisp2D::ebounds_obs(const double&amp; logEsrc,
520 487 }
521 488  
522 489 } // endfor: looped over EobsOverEsrc
523   -
  490 +
524 491 // If energy dispersion has never become negligible until end of loop,
525 492 // reset logEobsMax
526 493 if (!maxFound) {
... ... @@ -566,7 +533,7 @@ GEbounds GCTAEdisp2D::ebounds_src(const double&amp; logEobs,
566 533 double logEsrcMax = 30.0;
567 534 bool minFound = false;
568 535 bool maxFound = false;
569   -
  536 +
570 537 // Find boundaries
571 538 for (int i = 0; i < m_edisp.axis(0); ++i) {
572 539  
... ... @@ -580,7 +547,7 @@ GEbounds GCTAEdisp2D::ebounds_src(const double&amp; logEobs,
580 547 minFound = true;
581 548 logEsrcMin = logEsrc;
582 549 }
583   -
  550 +
584 551 // Find last non-negligible matrix term
585 552 else if (minFound && !maxFound &&
586 553 m_edisp(0, logEsrc, EobsOverEsrc, theta) < eps) {
... ... @@ -593,15 +560,15 @@ GEbounds GCTAEdisp2D::ebounds_src(const double&amp; logEobs,
593 560 m_edisp(0, logEsrc, EobsOverEsrc, theta) >= eps) {
594 561 maxFound = false;
595 562 }
596   -
  563 +
597 564 } // endfor: looped over true energy
598   -
  565 +
599 566 // If energy dispersion has never become negligible until end of loop,
600 567 // reset logEobsMax
601 568 if (!maxFound) {
602 569 logEsrcMax = 30.0;
603 570 }
604   -
  571 +
605 572 // Compute energy boundaries
606 573 GEnergy emin;
607 574 GEnergy emax;
... ... @@ -671,6 +638,11 @@ void GCTAEdisp2D::init_members(void)
671 638 m_filename.clear();
672 639 m_edisp.clear();
673 640  
  641 + // Initialise Monte Carlo cache
  642 + m_logEsrc = -30.0;
  643 + m_theta = 0.0;
  644 + m_cumul.clear();
  645 +
674 646 // Return
675 647 return;
676 648 }
... ... @@ -700,3 +672,55 @@ void GCTAEdisp2D::free_members(void)
700 672 // Return
701 673 return;
702 674 }
  675 +
  676 +/***********************************************************************//**
  677 + * @brief Update cumulative probability
  678 + *
  679 + * TODO : vector of vectors for each Esrc and select nearest vector in mc
  680 + *
  681 + ***************************************************************************/
  682 +void GCTAEdisp2D::update_cumul(const double& logEsrc,
  683 + const double& theta,
  684 + const double& phi,
  685 + const double& zenith,
  686 + const double& azimuth) const
  687 +{
  688 +
  689 + if (logEsrc != m_logEsrc || theta != m_theta) {
  690 +
  691 + m_cumul.clear();
  692 +
  693 + m_logEsrc = logEsrc;
  694 + m_theta = theta;
  695 +
  696 + // Initialize cumulative probability
  697 + double sum = 0.0;
  698 +
  699 + for (int i = 0; i < m_edisp.axis(1); ++i) {
  700 +
  701 + // Compute delta(Eobs/Etrue) and Eobs/Etrue values
  702 + double delta = m_edisp.axis_hi(1, i) -
  703 + m_edisp.axis_lo(1, i);
  704 + double EobsOverEsrc = 0.5 * (m_edisp.axis_hi(1, i) +
  705 + m_edisp.axis_lo(1, i));
  706 +
  707 + // Compute cumulative probability
  708 + double add = m_edisp(0, logEsrc, EobsOverEsrc, theta) *
  709 + delta / EobsOverEsrc * gammalib::inv_ln10;
  710 +
  711 + // Add to sum (and keep sum lower or equal to 1)
  712 + sum = sum+add >= 1.0 ? 1.0 : sum+add;
  713 +
  714 + // Create pair containing EobsOverEsrc and cumulated probability
  715 + std::pair<double, double> pair(EobsOverEsrc, sum);
  716 + std::cout << "Eobs/Esrc = " << EobsOverEsrc << ", sum = " << sum << std::endl;
  717 +
  718 + // Add to vector
  719 + m_cumul.push_back(pair);
  720 +
  721 + } // endfor: looped over EobsOverEsrc
  722 + }
  723 +
  724 + // Return
  725 + return;
  726 +}
... ...
inst/cta/src/GCTAEdispPerfTable.cpp
... ... @@ -190,7 +190,7 @@ double GCTAEdispPerfTable::operator()(const double&amp; logEobs,
190 190 // Compute energy dispersion value
191 191 double delta = logEobs - logEsrc;
192 192 double edisp = m_par_scale * std::exp(m_par_width * delta * delta);
193   -
  193 +
194 194 // Return energy dispersion
195 195 return edisp;
196 196 }
... ... @@ -249,8 +249,6 @@ GCTAEdispPerfTable* GCTAEdispPerfTable::clone(void) const
249 249 ***************************************************************************/
250 250 void GCTAEdispPerfTable::load(const std::string& filename)
251 251 {
252   - // Set conversion factor from RMS(ln(Eest/Etrue)) to RMS(log10(Eest/Etrue))
253   - const double conv = 0.434294481903;
254 252  
255 253 // Clear arrays
256 254 m_logE.clear();
... ... @@ -292,7 +290,7 @@ void GCTAEdispPerfTable::load(const std::string&amp; filename)
292 290  
293 291 // Push elements in node array and vector
294 292 m_logE.append(gammalib::todouble(elements[0]));
295   - m_sigma.push_back(gammalib::todouble(elements[4]) * conv);
  293 + m_sigma.push_back(gammalib::todouble(elements[4]) * gammalib::inv_ln10);
296 294  
297 295 } // endwhile: looped over lines
298 296  
... ...
inst/cta/src/GCTAEdispRmf.cpp
... ... @@ -40,8 +40,8 @@
40 40 /* __ Macros _____________________________________________________________ */
41 41  
42 42 /* __ Coding definitions _________________________________________________ */
43   -#define G_OLD_MC_CODE
44   -#define G_MC_REJECTION
  43 +//#define G_OLD_MC_CODE
  44 +//#define G_MC_REJECTION
45 45  
46 46 /* __ Debug definitions __________________________________________________ */
47 47  
... ... @@ -333,7 +333,7 @@ GEnergy GCTAEdispRmf::mc(GRan&amp; ran,
333 333 ftest = ran.uniform() * fmax;
334 334 }
335 335 energy.log10TeV(e);
336   -
  336 +
337 337 #else
338 338 // Determine measured energy index from Monte-Carlo cache
339 339 int imeasured = ran.cdf(m_mc_measured_cdf[itrue]) + offset;
... ... @@ -348,7 +348,7 @@ GEnergy GCTAEdispRmf::mc(GRan&amp; ran,
348 348 // Set interval
349 349 energy.log10TeV(e);
350 350 #endif
351   -
  351 +
352 352 } // endif: offset was valid
353 353  
354 354 } // endif: there was redistribution information
... ... @@ -365,26 +365,46 @@ GEnergy GCTAEdispRmf::mc(GRan&amp; ran,
365 365 const double& azimuth) const
366 366 {
367 367  
368   - // Update cumul
369   - update_cumul(logEsrc, theta, phi, zenith, azimuth);
  368 + // Compute cumulative probability
  369 + compute_cumul(theta, phi, zenith, azimuth);
  370 +
  371 + // Find right logEsrc index with bisection search
  372 + int low = 0;
  373 + int high = m_rmf.ntrue();
  374 + while ((high-low) > 1) {
  375 + int mid = (low+high) / 2;
  376 + if (logEsrc < m_rmf.etrue().elogmean(mid).log10TeV()) {
  377 + high = mid;
  378 + }
  379 + else {
  380 + low = mid;
  381 + }
  382 + }
  383 + // Index found
  384 + int isrc = low;
370 385  
371 386 // Draw random number between 0 and 1 from uniform distribution
372 387 double p = ran.uniform();
373 388  
374   - // Find right index
375   - // TODO: This can lead to index = m_edisp.axis(1) on exit, which
376   - // leads to an array indexing problem in the interpolation.
377   - // Also, a bisection search would be more efficient.
378   - int index = 0;
379   - while(index < m_cumul.size() - 2 && m_cumul[index+1].second < p) {
380   - index++;
381   - } // index found
  389 + // Find right index with bisection search
  390 + low = 0;
  391 + high = m_cumul[isrc].size();
  392 + while ((high-low) > 1) {
  393 + int mid = (low+high) / 2;
  394 + if (p < m_cumul[isrc][mid].second) {
  395 + high = mid;
  396 + }
  397 + else if (m_cumul[isrc][mid].second <= p) {
  398 + low = mid;
  399 + }
  400 + }
  401 + // Index found
  402 + int index = low;
382 403  
383 404 // Interpolate Eobs value
384   - double Eobs = (m_cumul[index+1].second - p)*m_cumul[index].first
385   - + (p - m_cumul[index].second)*m_cumul[index+1].first;
386   - Eobs /= (m_cumul[index+1].second - m_cumul[index].second);
387   -
  405 + double Eobs = (m_cumul[isrc][index+1].second - p)*m_cumul[isrc][index].first
  406 + + (p - m_cumul[isrc][index].second)*m_cumul[isrc][index+1].first;
  407 + Eobs /= (m_cumul[isrc][index+1].second - m_cumul[isrc][index].second);
388 408  
389 409 // Set energy
390 410 GEnergy energy;
... ... @@ -524,8 +544,8 @@ void GCTAEdispRmf::init_members(void)
524 544 // Initialise Monte Carlo cache
525 545 m_mc_measured_start.clear();
526 546 m_mc_measured_cdf.clear();
527   - m_logEsrc = -30.0;
528   - m_theta = 0.0;
  547 + m_cdf_computed = false;
  548 + m_theta = 0.0;
529 549 m_cumul.clear();
530 550  
531 551 // Return
... ... @@ -562,9 +582,9 @@ void GCTAEdispRmf::copy_members(const GCTAEdispRmf&amp; edisp)
562 582 // Copy Monte Carlo cache
563 583 m_mc_measured_start = edisp.m_mc_measured_start;
564 584 m_mc_measured_cdf = edisp.m_mc_measured_cdf;
565   - m_logEsrc = edisp.m_logEsrc;
566 585 m_theta = edisp.m_theta;
567 586 m_cumul = edisp.m_cumul;
  587 + m_cdf_computed = edisp.m_cdf_computed;
568 588  
569 589 // Return
570 590 return;
... ... @@ -770,19 +790,29 @@ void GCTAEdispRmf::update(const double&amp; etrue, const double&amp; emeasured) const
770 790  
771 791  
772 792 /***********************************************************************//**
773   - * @brief Update cumulative probability
  793 + * @brief Compute cumulative probability
774 794 *
775 795 ***************************************************************************/
776   -void GCTAEdispRmf::update_cumul(const double& logEsrc,
777   - const double& theta,
778   - const double& phi,
779   - const double& zenith,
780   - const double& azimuth) const
  796 +void GCTAEdispRmf::compute_cumul(const double& theta,
  797 + const double& phi,
  798 + const double& zenith,
  799 + const double& azimuth) const
781 800 {
782   - if (logEsrc != m_logEsrc || theta != m_theta) {
  801 + // TODO ? compute also for each theta ??
  802 +
  803 + if (!m_cdf_computed) {
783 804  
784   - m_logEsrc = logEsrc;
785   - m_theta = theta;
  805 + m_cumul.clear();
  806 +
  807 + //m_theta = theta;
  808 + m_cdf_computed = true;
  809 +
  810 + // Loop over Esrc
  811 + for (int isrc = 0; isrc < m_rmf.ntrue(); ++isrc) {
  812 +
  813 + m_cumul.push_back(std::vector<std::pair<double, double> >());
  814 +
  815 + double logEsrc = m_rmf.etrue().elogmean(isrc).log10TeV();
786 816  
787 817 // Initialize cumulative probability
788 818 double sum = 0.0;
... ... @@ -802,21 +832,22 @@ void GCTAEdispRmf::update_cumul(const double&amp; logEsrc,
802 832 double Eobs = Eobsmin+i*deltaEobs/n;
803 833  
804 834 // Compute cumulative probability
805   - double add = GCTAEdispRmf::operator()(logEsrc, std::log10(Eobs), theta) * deltaEobs / n / Eobs / std::log(10.0);
  835 + double add = GCTAEdispRmf::operator()(logEsrc, std::log10(Eobs), theta) * deltaEobs / (n * Eobs * gammalib::ln10);
806 836  
807   - //sum = sum+add/n >= 1.0 ? 1.0 : sum+add/n;
  837 + // Add to sum (and keep sum lower or equal to 1)
808 838 sum = sum+add >= 1.0 ? 1.0 : sum+add;
809 839  
810 840 // Create pair containing Eobs and cumulative probability
811 841 std::pair<double, double> pair(Eobs, sum);
812 842  
813 843 // Add to vector
814   - m_cumul.push_back(pair);
  844 + m_cumul[isrc].push_back(pair);
815 845 }
816 846  
817 847 }
818 848 }
819 849  
  850 + }
820 851 // Return
821 852 return;
822 853 }
... ...
inst/cta/test/example_sim_edisp.py
... ... @@ -140,6 +140,7 @@ if __name__ == &#39;__main__&#39;:
140 140 # Load edisp
141 141 edisp = gammalib.GCTAEdispRmf("./caldb/dc1/rmf.fits")
142 142 #edisp = gammalib.GCTAEdispPerfTable("./caldb/cta_dummy_irf.dat")
  143 + # NE MARCHE PAS /!\
143 144 #edisp = gammalib.GCTAEdisp2D("./caldb/edisp_matrix.fits")
144 145  
145 146 # Simulate Edisp
... ...