Commit 59b21f3fadc47764816b56d9437a8e4c01076ac3

Authored by Josh Cardenzana
1 parent 7c04755b

Updated RING subtraction in ctskymap (#2207)

Updated help text in ctskymap.rst
Added parameter in ctskymap to allow computing ring alphas run-by-run or as an average over all runs
Implemented run averaged computation of ring alpha parameters.
Added caching of pixel directions to prevent numerous calls to 'GSkyMap::inx2dir()'.
Removed 'm_cnts' variable, using m_skymap instead to store individual run counts when doing "RING" subtraction.
doc/source/users/reference_manual/ctskymap.rst
... ... @@ -74,9 +74,30 @@ General parameters
74 74 ``yref [real]``
75 75 Declination / Galactic latitude of image centre (J2000, in degrees).
76 76  
  77 +
  78 +Background subtraction configuration parameters
  79 +-----------------------------------------------
  80 +
77 81 ``bkgsubtract <NONE|IRF|RING> [string]``
78 82 Background subtraction method.
79 83  
  84 +``roiradius [real]``
  85 + Region of interest radius for RING subtraction (in degrees).
  86 +
  87 +``inradius [real]``
  88 + Inner ring radius for RING subtraction (in degrees).
  89 +
  90 +``outradius [real]``
  91 + Outer ring radius for RING subtraction (in degrees).
  92 +
  93 +``(regfile = NONE) [file]``
  94 + Exclusion region file as either a FITS map or DS9 region file.
  95 +
  96 +``(runavgalpha = yes) [boolean]``
  97 + Specifies whether or not to compute the run averaged alpha for RING
  98 + subtraction. Setting to 'no' will result in computing the alpha parameter
  99 + for each individual run (which can take a very long time).
  100 +
80 101  
81 102 Standard parameters
82 103 -------------------
... ...
src/ctskymap/ctskymap.cpp
... ... @@ -242,9 +242,14 @@ void ctskymap::run(void)
242 242  
243 243 } // endfor: looped over observations
244 244  
245   - // Compute the significance map
246   - map_significance();
  245 + if (m_bkgsubtract != "NONE") {
  246 + // Compute the significance map
  247 + map_significance();
247 248  
  249 + // Subtract background map from counts map
  250 + m_skymap -= m_bkgmap;
  251 + }
  252 +
248 253 // Optionally publish sky map
249 254 if (m_publish) {
250 255 publish();
... ... @@ -367,7 +372,6 @@ void ctskymap::init_members(void)
367 372 m_roiradius = 0.0;
368 373 m_inradius = 0.0;
369 374 m_outradius = 0.0;
370   - m_cnts = std::vector<int>(0);
371 375  
372 376 // Return
373 377 return;
... ... @@ -397,7 +401,6 @@ void ctskymap::copy_members(const ctskymap&amp; app)
397 401 m_roiradius = app.m_roiradius;
398 402 m_inradius = app.m_inradius;
399 403 m_outradius = app.m_outradius;
400   - m_cnts = app.m_cnts;
401 404  
402 405 // Return
403 406 return;
... ... @@ -456,14 +459,15 @@ void ctskymap::get_parameters(void)
456 459 m_roiradius = (*this)["roiradius"].real();
457 460 m_inradius = (*this)["inradius"].real();
458 461 m_outradius = (*this)["outradius"].real();
  462 + m_runavgalpha = (*this)["runavgalpha"].boolean();
459 463  
460   - // Make sure the values are reasonable
  464 + // Make sure that (roiradius < inradius < outradius)
461 465 if (m_roiradius > m_inradius) {
462 466 std::string err("'roiradius' must be smaller than inner ring radius");
463   - throw GException::invalid_value(err);
  467 + throw GException::invalid_value("ctskymap::get_parameter()",err);
464 468 } else if (m_inradius > m_outradius) {
465 469 std::string err("Inner ring radius must be smaller than outer ring radius");
466   - throw GException::invalid_value(err);
  470 + throw GException::invalid_value("ctskymap::get_parameter()",err);
467 471 } // endif: Ring radius checks
468 472 }
469 473 }
... ... @@ -477,16 +481,21 @@ void ctskymap::get_parameters(void)
477 481 // Setup the exclusions map
478 482 map_exclusions((*this)["regfile"].filename());
479 483  
480   - // If doing a ring background subtraction, generate an alpha map
481   - if (m_bkgsubtract == "RING") {
482   - m_cnts = std::vector<int>(m_bkgmap.npix(), 0);
483   - }
484   -
485   - // Cache the pixel solid angles
  484 + // Cache the pixel areas
486 485 m_solidangle = std::vector<double>(m_bkgmap.npix(), 0.0);
  486 + m_dirs.reserve(m_bkgmap.npix());
487 487 for (int i=0; i<m_bkgmap.npix(); i++) {
488 488 m_solidangle[i] = m_bkgmap.solidangle(i);
  489 + m_dirs.push_back(m_bkgmap.inx2dir(i));
  490 + }
  491 +
  492 + // If doing a ring background subtraction, generate an alpha map and
  493 + // make sure to cache the counts for each observation
  494 + if (m_bkgsubtract == "RING") {
  495 + m_alphamap = create_map(m_obs);
  496 + m_onmap = create_map(m_obs);
489 497 }
  498 +
490 499 }
491 500  
492 501 // Write parameters into logger
... ... @@ -568,11 +577,6 @@ void ctskymap::map_events(GCTAObservation* obs)
568 577 // Fill event in skymap
569 578 m_skymap(pixel, 0) += 1.0;
570 579 num_in_map++;
571   -
572   - // If doing the RING subtraction, keep tabs on counts from this obs
573   - if (m_bkgsubtract == "RING") {
574   - m_cnts[m_skymap.pix2inx(pixel)] += 1.0;
575   - }
576 580  
577 581 } // endfor: looped over all events
578 582  
... ... @@ -699,7 +703,7 @@ void ctskymap::map_background_irf(GCTAObservation* obs)
699 703 calls += integral.calls();
700 704  
701 705 // Multiply background rate with livetime and solid angle
702   - value *= obs->livetime() * m_bkgmap.solidangle(i);
  706 + value *= obs->livetime() * m_solidangle[i];
703 707  
704 708 // Add number of background events to background map
705 709 m_bkgmap(i,0) += value;
... ... @@ -769,16 +773,16 @@ void ctskymap::map_background_ring(GCTAObservation* obs)
769 773 double total = 0.0;
770 774 double exposure = obs->livetime() ;
771 775  
772   - // Cached background IRF sensitivities
773   - std::vector<double> sens(m_cnts.size(), 0.0);
774   - std::vector<bool> obsoverlap(m_cnts.size(), false);
  776 + // Create map for caching background IRF sensitivities
  777 + GSkyMap sens = create_map(m_obs);
  778 +
  779 + std::vector<int> bin_indx(0);
775 780  
776   - // Cache the IRF sensitivities
777 781 // Loop over all map pixels
778 782 for (int i = 0; i < m_bkgmap.npix(); ++i) {
779 783  
780 784 // Get sky direction of pixel
781   - GSkyDir skydir = m_bkgmap.inx2dir(i);
  785 + GSkyDir& skydir = m_dirs[i];
782 786  
783 787 // Convert sky direction in instrument direction
784 788 GCTAInstDir instdir = obs->pointing().instdir(skydir);
... ... @@ -789,13 +793,8 @@ void ctskymap::map_background_ring(GCTAObservation* obs)
789 793 continue;
790 794 }
791 795  
792   - // Notify that this bin overlaps the observation
793   - obsoverlap[i] = true;
794   -
795   - // If bin is excluded in the exclusion, skip it
796   - if (m_exclmap(i) == 0.0) {
797   - continue;
798   - }
  796 + // Add this bin to the list of bins overlapping the skymap
  797 + bin_indx.push_back( i );
799 798  
800 799 // Setup integration function
801 800 ctskymap::irf_kern integrand(bkg, &instdir);
... ... @@ -807,83 +806,57 @@ void ctskymap::map_background_ring(GCTAObservation* obs)
807 806  
808 807 // Do Romberg integration to get the sensitivity (note: this assumes the
809 808 // background IRF is a good approximation for the radial sensitivity)
810   - sens[i] = integral.romberg(lnEmin, lnEmax);
  809 + sens(i,0) = integral.romberg(lnEmin, lnEmax) *
  810 + m_solidangle[i] * obs->livetime();
811 811  
812 812 // Update number of background function calls
813 813 calls += integral.calls();
814 814  
815 815 } // endfor: Loop for caching bkg IRF sensitivity
816 816  
817   - // Define the regions necessary to do the pixel checks
818   - GSkyRegionCircle roi_reg(0.0, 0.0, m_roiradius);
819   - GSkyRegionCircle inner_reg(0.0, 0.0, m_inradius);
820   - GSkyRegionCircle outer_reg(0.0, 0.0, m_outradius);
  817 + // Loop over all map pixels that fall in this observation
  818 + for (int i = 0; i < bin_indx.size(); ++i) {
821 819  
822   -log_string(NORMAL, "LOOPING ON BKG IRF DONE");
823   -log_string(NORMAL, "LOOPING ON EVENTS!");
824   - // Loop over all map pixels
825   - for (int i = 0; i < m_bkgmap.npix(); ++i) {
  820 + // Get this bin
  821 + int ibin = bin_indx[i];
826 822  
827   - log_value(NORMAL, "PIXEL #", i);
  823 + // If averaging parameters over all positions, then update intermediate
  824 + // values to be used in the full computation later
  825 + if (m_runavgalpha) {
828 826  
829   - if (!obsoverlap[i]) {
830   - continue;
  827 + // Store the sensitivity for this bin
  828 + m_alphamap(ibin,0) += sens(ibin,0);
  829 +
  830 + // Store the counts in this bin
  831 + m_onmap(ibin,0) += m_skymap(ibin,0);
831 832 }
832 833  
833   - // Update the region positions
834   - roi_reg.centre(skydir);
835   - inner_reg.centre(skydir);
836   - outer_reg.centre(skydir);
837   -
838   - // Loop again over every pixel in the observation to compute Non/Noff
839   - int n_on(0), n_off(0);
840   - double alpha_on(0.0), alpha_off(0.0);
841   - for (int j = 0; j < m_bkgmap.npix(); ++j) {
842   -
843   - // Check if the observation overlaps this pixel
844   - if (!obsoverlap[j]) {
845   - continue;
846   - }
847   -
848   - // Get sky direction of pixel
849   - skydir = m_bkgmap.inx2dir(i);
850   -
851   - // Check if pixel is inside source region
852   - if (roi_reg.contains(skydir)) {
853   - // Update n_on
854   - n_on += m_cnts[j];
855   -
856   - // Update alpha_on
857   - alpha_on += m_solidangle[j] * sens[j];
858   - }
859   -
860   - // Otherwise check if it is in the background region
861   - else if ((m_exclmap(j) == 1.0) &&
862   - !inner_reg.contains(skydir) &&
863   - outer_reg.contains(skydir)) {
864   - // Update n_off
865   - n_off += m_cnts[j];
866   -
867   - // Update alpha_off
868   - alpha_off += m_solidangle[j] * sens[j];
869   - }
870   -
871   - } // endfor: sub-loop over pixels
872   -
873   - // Compute the likelihood for this bin
874   - double alpha = alpha_on / alpha_off;
875   - m_sigmap(i,0) += std::log(1);
876   -
877   - // Update the predicted background counts
878   - m_bkgmap(i,0) = n_on - (alpha * n_off);
  834 + // Otherwise we need to re-loop on each observation to compute the
  835 + // alpha weighted value of Noff for this run
  836 + else {
  837 +
  838 + // Compute the on, off and alpha parameters
  839 + double n_on(0);
  840 + double n_off(0);
  841 + double alpha(0);
  842 + compute_ring_values(m_skymap, sens, m_dirs[ibin],
  843 + n_on, n_off, alpha);
  844 +
  845 + // Update intermediate computation of significance
  846 + m_sigmap( ibin, 0 ) +=
  847 + n_on * std::log((1.0+alpha) * n_on / alpha / (n_on+n_off)) +
  848 + n_off * std::log((1.0+alpha) * n_off / (n_on+n_off));
  849 +
  850 + // Update the predicted background counts and alpha parameters
  851 + m_alphamap( ibin, 0 ) += alpha;
  852 + m_bkgmap( ibin,0 ) += alpha * n_off;
  853 + m_onmap( ibin, 0 ) += n_on;
  854 + }
879 855  
880 856 } // endfor: looped over background map pixels
881 857  
882   - // Zero out the alpha map to prepare it for the next observation
883   - std::vector<int>::iterator iter;
884   - for (iter=m_cnts.begin(); iter!=m_cnts.end(); ++iter) {
885   - (*iter) = 0;
886   - }
  858 + // Zero out the counts map to prepare it for the next observation
  859 + m_skymap = 0.0;
887 860  
888 861 // Return
889 862 return;
... ... @@ -900,30 +873,131 @@ log_string(NORMAL, &quot;LOOPING ON EVENTS!&quot;);
900 873 ***************************************************************************/
901 874 void ctskymap::map_significance(void)
902 875 {
903   - // Check if no background subtraction is requested
904   - if (m_bkgsubtract == "NONE") {
905   - return;
906   - }
  876 + // Compute significance from "RING" method (Li & Ma eq. 17)
  877 + if (m_bkgsubtract == "RING") {
  878 +
  879 + // Check if we're averaging the alpha parameter over all runs
  880 + if (m_runavgalpha) {
  881 +
  882 + // Log message about what is being done
  883 + log_header2(NORMAL, "Computing run averaged RBM map");
  884 + log_value(NORMAL, "Total pixels to process", m_onmap.npix());
  885 +
  886 + // Loop through each bin in the on-counts map
  887 + for (int i = 0; i < m_onmap.npix(); ++i) {
  888 +
  889 + // Get bin coordinate
  890 + GSkyDir& skydir = m_dirs[i];
  891 +
  892 + // Compute the alpha and lambda for this bin
  893 + double n_on(0), n_off(0), alpha(0.0);
  894 + compute_ring_values(m_onmap, m_alphamap, skydir,
  895 + n_on, n_off, alpha);
  896 +
  897 + // If alpha is reasonable, then store the results
  898 + if (alpha > 0.0) {
  899 + // Save the on-counts
  900 + m_skymap(i,0) = n_on;
  901 +
  902 + // Save the significance and off-counts
  903 + m_bkgmap(i,0) = alpha * n_off;
  904 + m_sigmap(i,0) =
  905 + n_on * std::log((1.0+alpha) * n_on / alpha / (n_on+n_off)) +
  906 + n_off * std::log((1.0+alpha) * n_off / (n_on+n_off));
  907 + }
  908 + } // endfor: Loop over all pixels
  909 + }
  910 +
  911 + // Otherwise most of the intensive calculations were done at the
  912 + // observation level.
  913 + else {
  914 + // m_onmap is the integral on-counts map, so update m_skymap
  915 + m_skymap = m_onmap;
907 916  
908   - // If background subtract was required then compute significance map..
  917 + } // endif: m_runavgalpha
909 918  
910   - // ... from "RING" method (Li & Ma eq. 17)
911   - else if (m_bkgsubtract == "RING") {
912 919 // Multiply the significance map by '-2'
913 920 m_sigmap *= -2.0;
914 921  
915   - // Now the square root
916   - m_sigmap = sqrt(m_sigmap);
917   - }
  922 + // Now take the square root
  923 + m_sigmap = sign(m_sigmap) * sqrt( abs(m_sigmap) );
  924 + }
918 925  
919 926 // ... using Poisson statistics in the Gaussian limit
920 927 else {
921 928 // Compute significance map
922 929 m_sigmap = (m_skymap - m_bkgmap) / sqrt(m_skymap);
  930 +
923 931 } // endif: background subtraction was requested
924 932  
925   - // Subtract background map from counts map
926   - m_skymap -= m_bkgmap;
  933 +}
  934 +
  935 +
  936 +/***********************************************************************//**
  937 + * @brief Computes Non, Noff and alpha for a counts map and sensitivity map
  938 + *
  939 + * @param[in] counts Counts map
  940 + * @param[in] sensitivity Sensitivity map
  941 + * @param[in] position Position of the ring & roi centers
  942 + * @param[out] non Returned estimate of ON counts
  943 + * @param[out] noff Returned estimate of OFF counts
  944 + * @param[out] alpha Returned estimate of alpha
  945 + *
  946 + * This method computes the Non counts Noff values at a given position. It
  947 + * also computes the alpha parameter from the passed sensitivity map.
  948 + ***************************************************************************/
  949 +void ctskymap::compute_ring_values(const GSkyMap& counts,
  950 + const GSkyMap& sensitivity,
  951 + const GSkyDir& position,
  952 + double& non, double& noff, double& alpha)
  953 +{
  954 + // Reset non and noff
  955 + non = 0.0;
  956 + noff = 0.0;
  957 + double alpha_on(0.0);
  958 + double alpha_off(0.0);
  959 +
  960 + // Define the regions necessary to do the pixel checks
  961 + GSkyRegionCircle roi_reg(position, m_roiradius);
  962 + GSkyRegionCircle inner_reg(position, m_inradius);
  963 + GSkyRegionCircle outer_reg(position, m_outradius);
  964 +
  965 + // Loop over every pixel in the observation to compute Non, Noff
  966 + for (int j = 0; j < counts.npix(); ++j) {
  967 +
  968 + // Get the index and sky direction of this pixel
  969 + GSkyDir& skydir = m_dirs[j];
  970 +
  971 + // Check if it is in the background region
  972 + if ((m_exclmap(j,0) == 1.0) &&
  973 + outer_reg.contains(skydir) &&
  974 + !inner_reg.contains(skydir)) {
  975 + // Update n_off
  976 + noff += counts(j,0);
  977 +
  978 + // Update alpha_off
  979 + alpha_off += sensitivity(j,0);
  980 + }
  981 +
  982 + // Check if pixel is inside source region
  983 + else if (roi_reg.contains(skydir)) {
  984 + // Update n_on for significance computation
  985 + non += counts(j,0);
  986 +
  987 + // Update alpha_on
  988 + alpha_on += sensitivity(j,0);
  989 +
  990 + } // endif: source and background region check
  991 +
  992 + } // endfor: sub-loop over pixels
  993 +
  994 + // Compute alpha
  995 + if (alpha_off == 0) {
  996 + alpha = 0.0;
  997 + } else {
  998 + alpha = alpha_on / alpha_off;
  999 + }
  1000 + return;
927 1001 }
928 1002  
929 1003  
... ... @@ -934,7 +1008,7 @@ void ctskymap::map_significance(void)
934 1008 ***************************************************************************/
935 1009 void ctskymap::map_exclusions(const GFilename& filename)
936 1010 {
937   - // Otherwise, create the map and set all pixels to 1
  1011 + // Create the exlusion map and set all pixels to 1
938 1012 m_exclmap = create_map(m_obs);
939 1013 m_exclmap = 1.0;
940 1014  
... ...
src/ctskymap/ctskymap.hpp
... ... @@ -76,6 +76,10 @@ protected:
76 76 void map_exclusions(const GFilename& filename);
77 77 void map_exclusions_reg(const GFilename& filename);
78 78 void map_exclusions_fits(const GFilename& filename);
  79 + void compute_ring_values(const GSkyMap& counts,
  80 + const GSkyMap& sensitivity,
  81 + const GSkyDir& position,
  82 + double& non, double& noff, double& alpha);
79 83  
80 84 // Background integration kernel
81 85 class irf_kern : public GFunction {
... ... @@ -97,19 +101,24 @@ protected:
97 101 std::string m_bkgsubtract; //!< Background subtraction method
98 102 bool m_publish; //!< Publish sky map?
99 103 GChatter m_chatter; //!< Chattiness
  104 +
  105 + // Parameters for configuring the RING background subtraction
100 106 double m_roiradius; //!< Region of interest radius
101 107 double m_inradius; //!< Inner ring radius
102 108 double m_outradius; //!< Outer ring radius
103   -
  109 + bool m_runavgalpha; //!< Determines how alpha is computed
  110 +
104 111 // Protected members
105 112 GSkyMap m_skymap; //!< Sky map
106 113 GSkyMap m_bkgmap; //!< Background map
107 114 GSkyMap m_sigmap; //!< Significance map
108   - GSkyMap m_exclmap; //!< Exclusion map (if doing "RING" bkg subtraction)
  115 + GSkyMap m_exclmap; //!< Exclusion map (if "RING" bkg subtraction)
  116 + GSkyMap m_alphamap; //!< Alpha map values (if "RING" subtraction)
  117 + GSkyMap m_onmap; //!< On counts map (if "RING" subtraction)
109 118  
110 119 // Caching variables to prevent multiple computations of the same thing
111   - std::vector<int> m_cnts; //!< Current observation counts (for "RING")
112   - std::vector<double> m_solidangle; //!< Cached pixel solid angles
  120 + std::vector<double> m_solidangle; //!< Cached pixel solid angles
  121 + std::vector<GSkyDir> m_dirs; //!< Cached pixel directions
113 122 };
114 123  
115 124  
... ...
src/ctskymap/ctskymap.par
... ... @@ -43,10 +43,11 @@ yref, r, a, 22.01,-90,90, &quot;Second coordinate of image center in degrees (DEC
43 43 # Background subtraction parameters
44 44 #==================================
45 45 bkgsubtract, s, a, NONE, NONE|IRF|RING,, "Background subtraction method"
46   -roiradius, r, a, 0.0,,, "Region of interest radius"
47   -inradius, r, a, 0.6,,, "Inner ring radius"
48   -outradius, r, a, 0.8,,, "Outer ring radius"
  46 +roiradius, r, a, 0.0,,, "Region of interest radius (degrees)"
  47 +inradius, r, a, 0.6,,, "Inner ring radius (degrees)"
  48 +outradius, r, a, 0.8,,, "Outer ring radius (degrees)"
49 49 regfile, f, h, NONE,,, "Exclusion regions definition file"
  50 +runavgalpha, b, h, yes,,, "Compute alpha as average over runs"
50 51  
51 52 #
52 53 # Standard parameters
... ...