Commit d47bd257a83c088d35b94d226ae05ae99d9ead0b
1 parent
8321269e
Replace trapezoid rule for energy integration of background template by numerica…
…l integration in ctskymap (#1975)
Showing
4 changed files
with
69 additions
and
32 deletions
ChangeLog
| 1 | -2017-03-18 | |
| 1 | +2017-03-21 | |
| 2 | 2 | |
| 3 | 3 | * Version 1.3.0 released |
| 4 | 4 | ======================== |
| 5 | 5 | |
| 6 | - Take into account RoI in ctskymap (#1975) | |
| 6 | + Take into account RoI in ctskymap and use numerical integration for IRF (#1975) | |
| 7 | 7 | Set local language to english (#1370) |
| 8 | 8 | Enhance logfile output of csroot2caldb script |
| 9 | 9 | Set default deadc value to 0.98 (CTA has <2% deadtime) | ... | ... |
NEWS
| 1 | 1 | New Features and Important Changes in ctools 1.3.0.dev1 |
| 2 | 2 | |
| 3 | -18 March 2017 | |
| 3 | +21 March 2017 | |
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | Introduction |
| ... | ... | @@ -53,7 +53,10 @@ None |
| 53 | 53 | ctskymap - CTA sky mapping |
| 54 | 54 | -------------------------- |
| 55 | 55 | Any RoI is now taken into account in ctskymap so that if IRF background |
| 56 | -subtraction is requested the counts and background maps are coherent | |
| 56 | +subtraction is requested the counts and background maps are coherent. In | |
| 57 | +addition, the energy integration over the background template is now done | |
| 58 | +numerically so that strong variations in the background rate, such as | |
| 59 | +those occuring close to the threshold, are correctly taken into account | |
| 57 | 60 | (#1975). |
| 58 | 61 | |
| 59 | 62 | ... | ... |
src/ctskymap/ctskymap.cpp
| ... | ... | @@ -30,7 +30,6 @@ |
| 30 | 30 | #endif |
| 31 | 31 | #include <cstdio> |
| 32 | 32 | #include "ctskymap.hpp" |
| 33 | -#include "GTools.hpp" | |
| 34 | 33 | |
| 35 | 34 | /* __ Method name definitions ____________________________________________ */ |
| 36 | 35 | #define G_INIT_MAP "ctskymap::init_map(GCTAObservation* obs)" |
| ... | ... | @@ -584,7 +583,8 @@ void ctskymap::map_background(GCTAObservation* obs) |
| 584 | 583 | * No background template available in instrument response function. |
| 585 | 584 | * |
| 586 | 585 | * Estimates the background in the sky map using the IRF template for a given |
| 587 | - * observation and adds this estimate to the background sky map. | |
| 586 | + * observation and adds this estimate to the background sky map. The IRF | |
| 587 | + * template is integrated numerically in energy. | |
| 588 | 588 | ***************************************************************************/ |
| 589 | 589 | void ctskymap::map_background_irf(GCTAObservation* obs) |
| 590 | 590 | { |
| ... | ... | @@ -612,24 +612,16 @@ void ctskymap::map_background_irf(GCTAObservation* obs) |
| 612 | 612 | throw GException::invalid_value(G_BKG_SUBTRACT_IRF, msg); |
| 613 | 613 | } |
| 614 | 614 | |
| 615 | - // Setup energy range covered by data | |
| 616 | - GEnergy emin; | |
| 617 | - GEnergy emax; | |
| 618 | - GEbounds ebds; | |
| 619 | - emin.TeV(m_emin); | |
| 620 | - emax.TeV(m_emax); | |
| 621 | - | |
| 622 | - // Determine number of energy nodes, 20 per decade, at least 10 bins | |
| 623 | - int nebin = int((emax.log10TeV() - emin.log10TeV()) * 20.0); | |
| 624 | - if (nebin < 10) { | |
| 625 | - nebin = 10; | |
| 626 | - } | |
| 615 | + // Compute natural logarithm of energy range in MeV | |
| 616 | + double lnEmin = std::log(m_emin * 1.0e6); | |
| 617 | + double lnEmax = std::log(m_emax * 1.0e6); | |
| 627 | 618 | |
| 628 | 619 | // Extract region of interest from observation |
| 629 | 620 | GCTARoi roi = obs->roi(); |
| 630 | 621 | |
| 631 | - // Setup energy nodes for computation | |
| 632 | - GEnergies energies(nebin, emin, emax); // More complicated nbins later | |
| 622 | + // Initialise statistics | |
| 623 | + int calls = 0; | |
| 624 | + double total = 0.0; | |
| 633 | 625 | |
| 634 | 626 | // Loop over all background map pixels |
| 635 | 627 | for (int i = 0; i < m_bkgmap.npix(); ++i) { |
| ... | ... | @@ -646,28 +638,57 @@ void ctskymap::map_background_irf(GCTAObservation* obs) |
| 646 | 638 | continue; |
| 647 | 639 | } |
| 648 | 640 | |
| 649 | - // Compute background value for each energy node | |
| 650 | - std::vector<double> values(energies.size(), 0.0); | |
| 651 | - for (int k = 0; k < energies.size(); ++k) { | |
| 652 | - values[k] = (*bkg)(energies[k].log10TeV(), instdir.detx(), | |
| 653 | - instdir.dety()); | |
| 654 | - } | |
| 641 | + // Setup integration function | |
| 642 | + ctskymap::irf_kern integrand(bkg, &instdir); | |
| 643 | + GIntegral integral(&integrand); | |
| 655 | 644 | |
| 656 | - // Integrate background values according to Trapezoid rule | |
| 657 | - double value = 0; | |
| 658 | - for (int k = 1; k < energies.size(); ++k) { | |
| 659 | - value += 0.5 * (values[k] + values[k-1]) * | |
| 660 | - (energies[k].MeV() - energies[k-1].MeV()); | |
| 661 | - } | |
| 645 | + // Set precision (has been carefully adjusted using a test simulation | |
| 646 | + // over the energy range 20 GeV - 120 TeV) | |
| 647 | + integral.eps(1.0e-7); | |
| 662 | 648 | |
| 649 | + // Do Romberg integration | |
| 650 | + double value = integral.romberg(lnEmin, lnEmax); | |
| 651 | + | |
| 652 | + // Update number of background function calls | |
| 653 | + calls += integral.calls(); | |
| 654 | + | |
| 663 | 655 | // Multiply background rate with livetime and solid angle |
| 664 | 656 | value *= obs->livetime() * m_bkgmap.solidangle(i); |
| 665 | 657 | |
| 666 | 658 | // Add number of background events to background map |
| 667 | 659 | m_bkgmap(i,0) += value; |
| 668 | 660 | |
| 661 | + // Update total number of background events | |
| 662 | + total += value; | |
| 663 | + | |
| 669 | 664 | } // endfor: looped over background map pixels |
| 665 | + | |
| 666 | + // Log background subtraction results | |
| 667 | + log_value(NORMAL, "Events in background", int(total+0.5)); | |
| 668 | + log_value(NORMAL, "Background evaluations", calls); | |
| 670 | 669 | |
| 671 | 670 | // Return |
| 672 | 671 | return; |
| 673 | 672 | } |
| 673 | + | |
| 674 | + | |
| 675 | +/***********************************************************************//** | |
| 676 | + * @brief Estimates the background in sky map based on IRF template | |
| 677 | + * | |
| 678 | + * @param[in] lnE Natural logarithm of energy in MeV. | |
| 679 | + ***************************************************************************/ | |
| 680 | +double ctskymap::irf_kern::eval(const double& lnE) | |
| 681 | +{ | |
| 682 | + // Get log10 of energy in TeV | |
| 683 | + double logE = lnE * gammalib::inv_ln10 - 6; | |
| 684 | + | |
| 685 | + // Get function value | |
| 686 | + double value = (*m_bgd)(logE, m_dir->detx(), m_dir->dety()); | |
| 687 | + | |
| 688 | + // Correct for variable substitution | |
| 689 | + value *= std::exp(lnE); | |
| 690 | + | |
| 691 | + // Return value | |
| 692 | + return value; | |
| 693 | +} | |
| 694 | + | ... | ... |
src/ctskymap/ctskymap.hpp
| ... | ... | @@ -73,6 +73,19 @@ protected: |
| 73 | 73 | void map_background(GCTAObservation* obs); |
| 74 | 74 | void map_background_irf(GCTAObservation* obs); |
| 75 | 75 | |
| 76 | + // Background integration kernel | |
| 77 | + class irf_kern : public GFunction { | |
| 78 | + public: | |
| 79 | + irf_kern(const GCTABackground* bgd, | |
| 80 | + const GCTAInstDir* dir) : | |
| 81 | + m_bgd(bgd), | |
| 82 | + m_dir(dir) { } | |
| 83 | + double eval(const double& lnE); | |
| 84 | + protected: | |
| 85 | + const GCTABackground* m_bgd; //!< Pointer to background | |
| 86 | + const GCTAInstDir* m_dir; //!< Pointer to instrument direction | |
| 87 | + }; | |
| 88 | + | |
| 76 | 89 | // User parameters |
| 77 | 90 | GFilename m_outmap; //!< Output file name |
| 78 | 91 | double m_emin; //!< Minimum energy (TeV) | ... | ... |