Commit de55878739b8fadd68a729e63820d2b9f58c40d4
1 parent
d44e87a4
Updated ctskymap with RING bkg subtraction (#2207)
Removed 'runavgalpha' option, since computing the run-by-run significance is a non trivial thing and the difference in the residual counts map is negligible. Added special handling in the significance computation when Non=0 to avoid NaN's.
Showing
5 changed files
with
72 additions
and
110 deletions
doc/source/users/reference_manual/ctskymap.rst
| ... | ... | @@ -82,7 +82,7 @@ Background subtraction configuration parameters |
| 82 | 82 | Background subtraction method. |
| 83 | 83 | |
| 84 | 84 | ``roiradius [real]`` |
| 85 | - Region of interest radius for RING subtraction (in degrees). | |
| 85 | + Source region radius for estimating on-counts (in degrees). | |
| 86 | 86 | |
| 87 | 87 | ``inradius [real]`` |
| 88 | 88 | Inner ring radius for RING subtraction (in degrees). |
| ... | ... | @@ -93,11 +93,6 @@ Background subtraction configuration parameters |
| 93 | 93 | ``(regfile = NONE) [file]`` |
| 94 | 94 | Exclusion region file as either a FITS map or DS9 region file. |
| 95 | 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 | - | |
| 101 | 96 | |
| 102 | 97 | Standard parameters |
| 103 | 98 | ------------------- | ... | ... |
src/ctskymap/ctskymap.cpp
| ... | ... | @@ -475,7 +475,6 @@ void ctskymap::get_parameters(void) |
| 475 | 475 | m_roiradius = (*this)["roiradius"].real(); |
| 476 | 476 | m_inradius = (*this)["inradius"].real(); |
| 477 | 477 | m_outradius = (*this)["outradius"].real(); |
| 478 | - m_runavgalpha = (*this)["runavgalpha"].boolean(); | |
| 479 | 478 | |
| 480 | 479 | // Make sure that (roiradius < inradius < outradius) |
| 481 | 480 | if (m_roiradius > m_inradius) { |
| ... | ... | @@ -498,10 +497,10 @@ void ctskymap::get_parameters(void) |
| 498 | 497 | map_exclusions((*this)["regfile"].filename()); |
| 499 | 498 | |
| 500 | 499 | // Cache the pixel areas |
| 501 | - m_solidangle = std::vector<double>(m_bkgmap.npix(), 0.0); | |
| 500 | + m_solidangle.reserve(m_bkgmap.npix()); | |
| 502 | 501 | m_dirs.reserve(m_bkgmap.npix()); |
| 503 | 502 | for (int i=0; i<m_bkgmap.npix(); i++) { |
| 504 | - m_solidangle[i] = m_bkgmap.solidangle(i); | |
| 503 | + m_solidangle.push_back(m_bkgmap.solidangle(i)); | |
| 505 | 504 | m_dirs.push_back(m_bkgmap.inx2dir(i)); |
| 506 | 505 | } |
| 507 | 506 | |
| ... | ... | @@ -789,11 +788,6 @@ void ctskymap::map_background_ring(GCTAObservation* obs) |
| 789 | 788 | double total = 0.0; |
| 790 | 789 | double exposure = obs->livetime() ; |
| 791 | 790 | |
| 792 | - // Create map for caching background IRF sensitivities | |
| 793 | - GSkyMap sens = create_map(m_obs); | |
| 794 | - | |
| 795 | - std::vector<int> bin_indx(0); | |
| 796 | - | |
| 797 | 791 | // Loop over all map pixels |
| 798 | 792 | for (int i = 0; i < m_bkgmap.npix(); ++i) { |
| 799 | 793 | |
| ... | ... | @@ -809,9 +803,6 @@ void ctskymap::map_background_ring(GCTAObservation* obs) |
| 809 | 803 | continue; |
| 810 | 804 | } |
| 811 | 805 | |
| 812 | - // Add this bin to the list of bins overlapping the skymap | |
| 813 | - bin_indx.push_back( i ); | |
| 814 | - | |
| 815 | 806 | // Setup integration function |
| 816 | 807 | ctskymap::irf_kern integrand(bkg, &instdir); |
| 817 | 808 | GIntegral integral(&integrand); |
| ... | ... | @@ -822,53 +813,17 @@ void ctskymap::map_background_ring(GCTAObservation* obs) |
| 822 | 813 | |
| 823 | 814 | // Do Romberg integration to get the sensitivity (note: this assumes the |
| 824 | 815 | // background IRF is a good approximation for the radial sensitivity) |
| 825 | - sens(i,0) = integral.romberg(lnEmin, lnEmax) * | |
| 826 | - m_solidangle[i] * obs->livetime(); | |
| 816 | + m_alphamap(i,0) += integral.romberg(lnEmin, lnEmax) * | |
| 817 | + m_solidangle[i] * obs->livetime(); | |
| 827 | 818 | |
| 819 | + // Store the counts in this bin | |
| 820 | + m_onmap(i,0) += m_skymap(i,0); | |
| 821 | + | |
| 828 | 822 | // Update number of background function calls |
| 829 | 823 | calls += integral.calls(); |
| 830 | 824 | |
| 831 | 825 | } // endfor: Loop for caching bkg IRF sensitivity |
| 832 | 826 | |
| 833 | - // Loop over all map pixels that fall in this observation | |
| 834 | - for (int i = 0; i < bin_indx.size(); ++i) { | |
| 835 | - | |
| 836 | - // Get this bin | |
| 837 | - int ibin = bin_indx[i]; | |
| 838 | - | |
| 839 | - // If averaging parameters over all positions, then update intermediate | |
| 840 | - // values to be used in the full computation later | |
| 841 | - if (m_runavgalpha) { | |
| 842 | - | |
| 843 | - // Store the sensitivity for this bin | |
| 844 | - m_alphamap(ibin,0) += sens(ibin,0); | |
| 845 | - | |
| 846 | - // Store the counts in this bin | |
| 847 | - m_onmap(ibin,0) += m_skymap(ibin,0); | |
| 848 | - } | |
| 849 | - | |
| 850 | - // Otherwise we need to re-loop on each observation to compute the | |
| 851 | - // alpha weighted value of Noff for this run | |
| 852 | - else { | |
| 853 | - | |
| 854 | - // Compute the on, off and alpha parameters | |
| 855 | - double n_on(0.0), n_off(0.0), alpha(0.0); | |
| 856 | - compute_ring_values(m_skymap, sens, m_dirs[ibin], | |
| 857 | - n_on, n_off, alpha); | |
| 858 | - | |
| 859 | - // Update intermediate computation of significance | |
| 860 | - m_sigmap( ibin, 0 ) += | |
| 861 | - n_on * std::log((1.0+alpha) * n_on / alpha / (n_on+n_off)) + | |
| 862 | - n_off * std::log((1.0+alpha) * n_off / (n_on+n_off)); | |
| 863 | - | |
| 864 | - // Update the predicted background counts and alpha parameters | |
| 865 | - m_alphamap( ibin, 0 ) += alpha; | |
| 866 | - m_bkgmap( ibin,0 ) += alpha * n_off; | |
| 867 | - m_onmap( ibin, 0 ) += n_on; | |
| 868 | - } | |
| 869 | - | |
| 870 | - } // endfor: looped over background map pixels | |
| 871 | - | |
| 872 | 827 | // Zero out the counts map to prepare it for the next observation |
| 873 | 828 | m_skymap = 0.0; |
| 874 | 829 | |
| ... | ... | @@ -876,6 +831,7 @@ void ctskymap::map_background_ring(GCTAObservation* obs) |
| 876 | 831 | return; |
| 877 | 832 | } |
| 878 | 833 | |
| 834 | + | |
| 879 | 835 | /***********************************************************************//** |
| 880 | 836 | * @brief Write keywords in FITS HDU |
| 881 | 837 | * |
| ... | ... | @@ -914,63 +870,69 @@ void ctskymap::map_significance(void) |
| 914 | 870 | // Compute significance from "RING" method (Li & Ma eq. 17) |
| 915 | 871 | if (m_bkgsubtract == "RING") { |
| 916 | 872 | |
| 917 | - // Check if we're averaging the alpha parameter over all runs | |
| 918 | - if (m_runavgalpha) { | |
| 873 | + // Log message about what is being done | |
| 874 | + log_header1(NORMAL, "Computing RBM map"); | |
| 875 | + log_value(NORMAL, "Total pixels to process", m_onmap.npix()); | |
| 919 | 876 | |
| 920 | - // Log message about what is being done | |
| 921 | - log_header1(NORMAL, "Computing run averaged RBM map"); | |
| 922 | - log_value(NORMAL, "Total pixels to process", m_onmap.npix()); | |
| 877 | + // Store the number of bins with an inappropriate alpha parameter | |
| 878 | + int num_bad_alpha(0); | |
| 879 | + // Loop through each bin in the on-counts map | |
| 880 | + for (int i = 0; i < m_onmap.npix(); ++i) { | |
| 923 | 881 | |
| 924 | - // Loop through each bin in the on-counts map | |
| 925 | - for (int i = 0; i < m_onmap.npix(); ++i) { | |
| 882 | + // Reset the on/off counts and alpha for this bin | |
| 883 | + double n_on(0), n_off(0), alpha(0.0); | |
| 926 | 884 | |
| 927 | - // Since this can take a long time, keep the user updated on | |
| 928 | - // the progress when another 10% of pixels is processed | |
| 929 | - if (i%(m_onmap.npix()/10)==0) { | |
| 930 | - log_value(NORMAL, "Pixels remaining", m_onmap.npix()-i); | |
| 931 | - } | |
| 885 | + // Since this can take a long time, keep the user updated on | |
| 886 | + // the progress when another 10% of pixels is processed | |
| 887 | + if (i%(m_onmap.npix()/10)==0) { | |
| 888 | + log_value(NORMAL, "Pixels remaining", m_onmap.npix()-i); | |
| 889 | + } | |
| 932 | 890 | |
| 933 | - // Get bin coordinate | |
| 934 | - GSkyDir& skydir = m_dirs[i]; | |
| 935 | - | |
| 936 | - // Compute the alpha and lambda for this bin | |
| 937 | - double n_on(0), n_off(0), alpha(0.0); | |
| 938 | - compute_ring_values(m_onmap, m_alphamap, skydir, | |
| 939 | - n_on, n_off, alpha); | |
| 940 | - | |
| 941 | - // If alpha is reasonable, then store the results | |
| 942 | - if (alpha > 0.0) { | |
| 943 | - // Save the on-counts | |
| 944 | - m_skymap(i,0) = n_on; | |
| 945 | - | |
| 946 | - // Save the significance and off-counts | |
| 947 | - m_bkgmap(i,0) = alpha * n_off; | |
| 948 | - m_sigmap(i,0) = | |
| 949 | - n_on * std::log((1.0+alpha) * n_on / alpha / (n_on+n_off)) + | |
| 950 | - n_off * std::log((1.0+alpha) * n_off / (n_on+n_off)); | |
| 951 | - } | |
| 952 | - } // endfor: Loop over all pixels | |
| 953 | - } | |
| 891 | + // Get bin coordinates | |
| 892 | + GSkyDir& skydir = m_dirs[i]; | |
| 954 | 893 | |
| 955 | - // Otherwise most of the intensive calculations were done at the | |
| 956 | - // observation level. | |
| 957 | - else { | |
| 958 | - // m_onmap is the integral on-counts map, so update m_skymap | |
| 959 | - m_skymap = m_onmap; | |
| 894 | + // Compute the alpha and counts for this bin | |
| 895 | + compute_ring_values(m_onmap, m_alphamap, skydir, | |
| 896 | + n_on, n_off, alpha); | |
| 960 | 897 | |
| 961 | - } // endif: m_runavgalpha | |
| 898 | + // If alpha is reasonable, then store the results | |
| 899 | + if (alpha == 0.0) { | |
| 900 | + // Increment the bad alpha counter | |
| 901 | + num_bad_alpha++; | |
| 902 | + } | |
| 903 | + | |
| 904 | + else { | |
| 905 | + // Save the on-counts and alpha-weighted off-counts | |
| 906 | + m_skymap(i,0) = n_on; | |
| 907 | + m_bkgmap(i,0) = alpha * n_off; | |
| 908 | + | |
| 909 | + // Compute significance | |
| 910 | + if (n_on == 0.0) { | |
| 911 | + | |
| 912 | + // The significance computation reduces to the following form | |
| 913 | + m_sigmap(i,0) = -2.0 * n_off * std::log(1.0+alpha); | |
| 914 | + | |
| 915 | + } else { | |
| 916 | + // Save the significance | |
| 917 | + m_sigmap(i,0) = (n_on < (alpha*n_off) ? -2.0:2.0 ) * | |
| 918 | + (n_on * std::log((1.0+alpha) * n_on / (alpha * (n_on+n_off))) + | |
| 919 | + n_off * std::log((1.0+alpha) * n_off / (n_on+n_off))); | |
| 920 | + } | |
| 921 | + } | |
| 922 | + } // endfor: Loop over all pixels | |
| 962 | 923 | |
| 963 | - // Multiply the significance map by '2', as per Li & Ma (1983) Eq. 17 | |
| 964 | - m_sigmap *= 2.0; | |
| 924 | + // Log the number of bad-alpha bins | |
| 925 | + log_value(NORMAL, "Bins with bad alpha", num_bad_alpha); | |
| 965 | 926 | |
| 966 | 927 | // Now take the square root. Since some bins can be negative, first take |
| 967 | 928 | // the absolute value of the map, square root that, then multiply each |
| 968 | 929 | // bin by its sign to preserve the +/- significance. |
| 969 | - m_sigmap = sign(m_skymap - m_bkgmap) * sqrt( abs(m_sigmap) ); | |
| 930 | + m_sigmap = sign(m_sigmap) * sqrt( abs(m_sigmap) ); | |
| 970 | 931 | } |
| 971 | 932 | |
| 972 | - // ... using Poisson statistics in the Gaussian limit | |
| 933 | + // Compute significance using Poisson statistics in the Gaussian limit | |
| 973 | 934 | else { |
| 935 | + | |
| 974 | 936 | // Compute significance map |
| 975 | 937 | m_sigmap = (m_skymap - m_bkgmap) / sqrt(m_skymap); |
| 976 | 938 | |
| ... | ... | @@ -1018,6 +980,7 @@ void ctskymap::compute_ring_values(const GSkyMap& counts, |
| 1018 | 980 | if ((m_exclmap(j,0) == 1.0) && |
| 1019 | 981 | outer_reg.contains(skydir) && |
| 1020 | 982 | !inner_reg.contains(skydir)) { |
| 983 | + | |
| 1021 | 984 | // Update n_off |
| 1022 | 985 | noff += counts(j,0); |
| 1023 | 986 | |
| ... | ... | @@ -1027,6 +990,7 @@ void ctskymap::compute_ring_values(const GSkyMap& counts, |
| 1027 | 990 | |
| 1028 | 991 | // Check if pixel is inside source region |
| 1029 | 992 | else if (roi_reg.contains(skydir)) { |
| 993 | + | |
| 1030 | 994 | // Update n_on for significance computation |
| 1031 | 995 | non += counts(j,0); |
| 1032 | 996 | |
| ... | ... | @@ -1038,8 +1002,13 @@ void ctskymap::compute_ring_values(const GSkyMap& counts, |
| 1038 | 1002 | } // endfor: sub-loop over pixels |
| 1039 | 1003 | |
| 1040 | 1004 | // Compute alpha |
| 1041 | - if (alpha_off == 0) { | |
| 1005 | + if (alpha_off == 0.0) { | |
| 1006 | + // The off region does not have any sensitivity or there are no events | |
| 1007 | + // in either the on region or the off region | |
| 1042 | 1008 | alpha = 0.0; |
| 1009 | + non = 0.0; | |
| 1010 | + noff = 0.0; | |
| 1011 | + | |
| 1043 | 1012 | } else { |
| 1044 | 1013 | alpha = alpha_on / alpha_off; |
| 1045 | 1014 | } |
| ... | ... | @@ -1092,6 +1061,7 @@ void ctskymap::map_exclusions_fits(const GFilename& filename) |
| 1092 | 1061 | |
| 1093 | 1062 | // Check this sky position in the fits map |
| 1094 | 1063 | if (inmap.contains(dir) && (inmap(inmap.dir2inx(dir)) == 0.0)) { |
| 1064 | + | |
| 1095 | 1065 | // Set the pixel to 0 |
| 1096 | 1066 | m_exclmap(i) = 0.0; |
| 1097 | 1067 | |
| ... | ... | @@ -1111,10 +1081,10 @@ void ctskymap::map_exclusions_reg(const GFilename& filename) |
| 1111 | 1081 | GSkyRegions regions(filename); |
| 1112 | 1082 | |
| 1113 | 1083 | // Loop through the individual pixels in the exclusion map |
| 1114 | - GSkyDir dir; | |
| 1115 | 1084 | for (int i=0; i<m_exclmap.npix(); i++) { |
| 1085 | + | |
| 1116 | 1086 | // Get the pixel position |
| 1117 | - dir = m_exclmap.pix2dir(i); | |
| 1087 | + GSkyDir dir = m_exclmap.pix2dir(i); | |
| 1118 | 1088 | |
| 1119 | 1089 | // Check if GSkyDir overlaps with the regions |
| 1120 | 1090 | if (regions.contains(dir)) { | ... | ... |
src/ctskymap/ctskymap.hpp
| ... | ... | @@ -74,8 +74,8 @@ protected: |
| 74 | 74 | void map_background_ring(GCTAObservation* obs); |
| 75 | 75 | void map_significance(void); |
| 76 | 76 | void map_exclusions(const GFilename& filename); |
| 77 | - void map_exclusions_reg(const GFilename& filename); | |
| 78 | 77 | void map_exclusions_fits(const GFilename& filename); |
| 78 | + void map_exclusions_reg(const GFilename& filename); | |
| 79 | 79 | void compute_ring_values(const GSkyMap& counts, |
| 80 | 80 | const GSkyMap& sensitivity, |
| 81 | 81 | const GSkyDir& position, |
| ... | ... | @@ -107,7 +107,6 @@ protected: |
| 107 | 107 | double m_roiradius; //!< Region of interest radius |
| 108 | 108 | double m_inradius; //!< Inner ring radius |
| 109 | 109 | double m_outradius; //!< Outer ring radius |
| 110 | - bool m_runavgalpha; //!< Determines how alpha is computed | |
| 111 | 110 | |
| 112 | 111 | // Protected members |
| 113 | 112 | GSkyMap m_skymap; //!< Sky map | ... | ... |
src/ctskymap/ctskymap.par
| ... | ... | @@ -43,11 +43,10 @@ yref, r, a, 22.01,-90,90, "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 (degrees)" | |
| 46 | +roiradius, r, a, 0.0,,, "Source region radius for estimating on-counts (degrees)" | |
| 47 | 47 | inradius, r, a, 0.6,,, "Inner ring radius (degrees)" |
| 48 | 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" | |
| 51 | 50 | |
| 52 | 51 | # |
| 53 | 52 | # Standard parameters | ... | ... |
test/test_ctskymap.py
| ... | ... | @@ -261,8 +261,7 @@ class Test(test): |
| 261 | 261 | skymap['roiradius'] = 0.1 |
| 262 | 262 | skymap['inradius'] = 0.6 |
| 263 | 263 | skymap['outradius'] = 0.8 |
| 264 | - skymap['regfile'] = 'NONE' | |
| 265 | - skymap['runavgalpha'] = True | |
| 264 | + skymap['regfile'] = 'NONE' | |
| 266 | 265 | |
| 267 | 266 | # Execute tool |
| 268 | 267 | skymap.logFileOpen() # Needed to get a new log file | ... | ... |