Commit fc6ba477b38271ab9529a3dabdfc6a9f482136c7

Authored by Jürgen Knödlseder
1 parent ae65ce02

Use bounding box for efficient ring background determination (#2309)

src/ctskymap/ctskymap.cpp
@@ -397,9 +397,10 @@ void ctskymap::publish(const std::string& name) @@ -397,9 +397,10 @@ void ctskymap::publish(const std::string& name)
397 ***************************************************************************/ 397 ***************************************************************************/
398 void ctskymap::init_members(void) 398 void ctskymap::init_members(void)
399 { 399 {
400 - // Initialise members 400 + // Initialise User parameters
401 m_outmap.clear(); 401 m_outmap.clear();
402 m_inexclusion.clear(); 402 m_inexclusion.clear();
  403 + m_binsz = 0.0;
403 m_emin = 0.0; 404 m_emin = 0.0;
404 m_emax = 0.0; 405 m_emax = 0.0;
405 m_bkgsubtract = "NONE"; 406 m_bkgsubtract = "NONE";
@@ -409,7 +410,7 @@ void ctskymap::init_members(void) @@ -409,7 +410,7 @@ void ctskymap::init_members(void)
409 m_publish = false; 410 m_publish = false;
410 m_chatter = static_cast<GChatter>(2); 411 m_chatter = static_cast<GChatter>(2);
411 412
412 - // Initialise maps 413 + // Initialise members
413 m_skymap.clear(); 414 m_skymap.clear();
414 m_bkgmap.clear(); 415 m_bkgmap.clear();
415 m_sigmap.clear(); 416 m_sigmap.clear();
@@ -418,6 +419,9 @@ void ctskymap::init_members(void) @@ -418,6 +419,9 @@ void ctskymap::init_members(void)
418 // Initialise cache 419 // Initialise cache
419 m_solidangle.clear(); 420 m_solidangle.clear();
420 m_dirs.clear(); 421 m_dirs.clear();
  422 + m_cos_roiradius = 1.0;
  423 + m_cos_inradius = 1.0;
  424 + m_cos_outradius = 1.0;
421 425
422 // Return 426 // Return
423 return; 427 return;
@@ -431,9 +435,10 @@ void ctskymap::init_members(void) @@ -431,9 +435,10 @@ void ctskymap::init_members(void)
431 ***************************************************************************/ 435 ***************************************************************************/
432 void ctskymap::copy_members(const ctskymap& app) 436 void ctskymap::copy_members(const ctskymap& app)
433 { 437 {
434 - // Copy members 438 + // Copy User parameters
435 m_outmap = app.m_outmap; 439 m_outmap = app.m_outmap;
436 m_inexclusion = app.m_inexclusion; 440 m_inexclusion = app.m_inexclusion;
  441 + m_binsz = app.m_binsz;
437 m_emin = app.m_emin; 442 m_emin = app.m_emin;
438 m_emax = app.m_emax; 443 m_emax = app.m_emax;
439 m_bkgsubtract = app.m_bkgsubtract; 444 m_bkgsubtract = app.m_bkgsubtract;
@@ -443,15 +448,18 @@ void ctskymap::copy_members(const ctskymap&amp; app) @@ -443,15 +448,18 @@ void ctskymap::copy_members(const ctskymap&amp; app)
443 m_publish = app.m_publish; 448 m_publish = app.m_publish;
444 m_chatter = app.m_chatter; 449 m_chatter = app.m_chatter;
445 450
446 - // Copy maps  
447 - m_skymap = app.m_skymap;  
448 - m_bkgmap = app.m_bkgmap;  
449 - m_sigmap = app.m_sigmap;  
450 - m_exclmap = app.m_exclmap; 451 + // Copy members
  452 + m_skymap = app.m_skymap;
  453 + m_bkgmap = app.m_bkgmap;
  454 + m_sigmap = app.m_sigmap;
  455 + m_exclmap = app.m_exclmap;
451 456
452 // Copy cache 457 // Copy cache
453 - m_solidangle = app.m_solidangle;  
454 - m_dirs = app.m_dirs; 458 + m_solidangle = app.m_solidangle;
  459 + m_dirs = app.m_dirs;
  460 + m_cos_roiradius = app.m_cos_roiradius;
  461 + m_cos_inradius = app.m_cos_inradius;
  462 + m_cos_outradius = app.m_cos_outradius;
455 463
456 // Return 464 // Return
457 return; 465 return;
@@ -487,6 +495,7 @@ void ctskymap::get_parameters(void) @@ -487,6 +495,7 @@ void ctskymap::get_parameters(void)
487 m_skymap = create_map(m_obs); 495 m_skymap = create_map(m_obs);
488 496
489 // Get further parameters 497 // Get further parameters
  498 + m_binsz = (*this)["binsz"].real();
490 m_emin = (*this)["emin"].real(); 499 m_emin = (*this)["emin"].real();
491 m_emax = (*this)["emax"].real(); 500 m_emax = (*this)["emax"].real();
492 m_bkgsubtract = (*this)["bkgsubtract"].string(); 501 m_bkgsubtract = (*this)["bkgsubtract"].string();
@@ -567,6 +576,13 @@ void ctskymap::setup_maps(void) @@ -567,6 +576,13 @@ void ctskymap::setup_maps(void)
567 576
568 } // endif: background subtraction selected 577 } // endif: background subtraction selected
569 578
  579 + // Compute cosine of ring radii for RING background method
  580 + if (m_bkgsubtract == "RING") {
  581 + m_cos_roiradius = std::cos(m_roiradius * gammalib::deg2rad);
  582 + m_cos_inradius = std::cos(m_inradius * gammalib::deg2rad);
  583 + m_cos_outradius = std::cos(m_outradius * gammalib::deg2rad);
  584 + }
  585 +
570 // Return 586 // Return
571 return; 587 return;
572 } 588 }
@@ -964,11 +980,8 @@ void ctskymap::map_significance_ring(void) @@ -964,11 +980,8 @@ void ctskymap::map_significance_ring(void)
964 log_value(NORMAL, "Pixels remaining", m_skymap.npix()-i); 980 log_value(NORMAL, "Pixels remaining", m_skymap.npix()-i);
965 } 981 }
966 982
967 - // Get bin coordinates  
968 - GSkyDir& skydir = m_dirs[i];  
969 -  
970 // Compute the alpha and counts for this bin 983 // Compute the alpha and counts for this bin
971 - compute_ring_values(m_skymap, m_bkgmap, skydir, n_on, n_off, alpha); 984 + compute_ring_values(i, m_skymap, m_bkgmap, n_on, n_off, alpha);
972 985
973 // Store the On and alpha-weighted Off-counts 986 // Store the On and alpha-weighted Off-counts
974 onmap(i) = n_on; 987 onmap(i) = n_on;
@@ -1020,74 +1033,107 @@ void ctskymap::map_significance_ring(void) @@ -1020,74 +1033,107 @@ void ctskymap::map_significance_ring(void)
1020 /***********************************************************************//** 1033 /***********************************************************************//**
1021 * @brief Computes Non, Noff and alpha for a counts map and sensitivity map 1034 * @brief Computes Non, Noff and alpha for a counts map and sensitivity map
1022 * 1035 *
1023 - * @param[in] counts Counts map  
1024 - * @param[in] background Background map  
1025 - * @param[in] position Position of the ring & roi centers  
1026 - * @param[out] non Returned estimate of ON counts  
1027 - * @param[out] noff Returned estimate of OFF counts  
1028 - * @param[out] alpha Returned estimate of alpha 1036 + * @param[in] ipixel Sky map pixel to consider.
  1037 + * @param[in] counts Counts map.
  1038 + * @param[in] background Background map.
  1039 + * @param[out] non Returned estimate of On-counts.
  1040 + * @param[out] noff Returned estimate of Off-counts.
  1041 + * @param[out] alpha Returned estimate of alpha.
1029 * 1042 *
1030 - * This method computes the Non counts Noff values at a given position. It  
1031 - * also computes the alpha parameter from the passed sensitivity map. 1043 + * Computes the On- and Off-counts values at a given position from in counts
  1044 + * map and the alpha parameter from the background map.
  1045 + *
  1046 + * To speed-up the computations the method considers only the pixels within
  1047 + * a bounding box that comprises the outer background ring radius. The method
  1048 + * considers wrapping around of pixel indices in the Right Ascension /
  1049 + * Galactic longitude direction.
  1050 + *
  1051 + * If the alpha of the ring region is zero the values of @p non, @p noff,
  1052 + * and @p alpha will be set to zero.
1032 ***************************************************************************/ 1053 ***************************************************************************/
1033 -void ctskymap::compute_ring_values(const GSkyMap& counts, 1054 +void ctskymap::compute_ring_values(const int& ipixel,
  1055 + const GSkyMap& counts,
1034 const GSkyMap& background, 1056 const GSkyMap& background,
1035 - const GSkyDir& position,  
1036 double& non, 1057 double& non,
1037 double& noff, 1058 double& noff,
1038 double& alpha) 1059 double& alpha)
1039 { 1060 {
1040 - // Reset Non and Noff  
1041 - non = 0.0;  
1042 - noff = 0.0; 1061 + // Initialise return values (non, noff and alpha)
  1062 + non = 0.0;
  1063 + noff = 0.0;
  1064 + alpha = 0.0;
1043 1065
1044 // Initialise On and Off alpha 1066 // Initialise On and Off alpha
1045 double alpha_on = 0.0; 1067 double alpha_on = 0.0;
1046 double alpha_off = 0.0; 1068 double alpha_off = 0.0;
1047 1069
1048 - // Compute cosine of radii. We use the cosine of the radius here to  
1049 - // mimimize as much as possible the trigonometric computations. Note that  
1050 - // the cosine of an angle is maximal for an angle of zero. This explains  
1051 - // later why we chose ">=" to test whether an angle is smaller than a  
1052 - // given radius.  
1053 - double cos_roiradius = std::cos(m_roiradius * gammalib::deg2rad);  
1054 - double cos_inradius = std::cos(m_inradius * gammalib::deg2rad);  
1055 - double cos_outradius = std::cos(m_outradius * gammalib::deg2rad); 1070 + // Get sky direction of pixel
  1071 + GSkyDir& position = m_dirs[ipixel];
  1072 +
  1073 + // Get pixel bounding box
  1074 + int ix_start;
  1075 + int ix_stop;
  1076 + int iy_start;
  1077 + int iy_stop;
  1078 + ring_bounding_box(ipixel, ix_start, ix_stop, iy_start, iy_stop);
1056 1079
1057 - // Loop over every pixel in the observation to compute Non, Noff  
1058 - for (int j = 0; j < counts.npix(); ++j) { 1080 + // Get number of x pixels in sky map
  1081 + int nx = counts.nx();
1059 1082
1060 - // Get the index and sky direction of this pixel  
1061 - GSkyDir& skydir = m_dirs[j]; 1083 + // Loop over x pixels of bounding box
  1084 + for (int ix_nowrap = ix_start; ix_nowrap < ix_stop; ++ix_nowrap) {
1062 1085
1063 - // Only consider pixels within the outer radius of the background region  
1064 - if (position.cos_dist(skydir) >= cos_outradius) { 1086 + // Compute x pixel index by wrapping the pixel index into the
  1087 + // interval [0,nx[
  1088 + int ix = ix_nowrap;
  1089 + if (ix < 0) {
  1090 + ix += nx;
  1091 + }
  1092 + else if (ix >= nx) {
  1093 + ix -= nx;
  1094 + }
1065 1095
1066 - // Check if pixel is inside the background region  
1067 - if ((m_exclmap(j) == 0.0) && position.cos_dist(skydir) < cos_inradius) { 1096 + // Initialise pixel index
  1097 + int i = ix + iy_start * nx;
1068 1098
1069 - // Update n_off  
1070 - noff += counts(j); 1099 + // Loop over y pixels of bounding box
  1100 + for (int iy = iy_start; iy < iy_stop; ++iy, i += nx) {
1071 1101
1072 - // Update alpha_off  
1073 - alpha_off += background(j); 1102 + // Get the index and sky direction of this pixel
  1103 + GSkyDir& skydir = m_dirs[i];
1074 1104
1075 - } 1105 + // Only consider pixels within the outer radius of the background
  1106 + // region
  1107 + if (position.cos_dist(skydir) >= m_cos_outradius) {
  1108 +
  1109 + // Check if pixel is inside the background region
  1110 + if ((m_exclmap(i) == 0.0) &&
  1111 + (position.cos_dist(skydir) < m_cos_inradius)) {
  1112 +
  1113 + // Update n_off
  1114 + noff += counts(i);
  1115 +
  1116 + // Update alpha_off
  1117 + alpha_off += background(i);
1076 1118
1077 - // ... otherwise check if pixel is inside source region  
1078 - else if (position.cos_dist(skydir) >= cos_roiradius) { 1119 + }
1079 1120
1080 - // Update n_on for significance computation  
1081 - non += counts(j); 1121 + // ... otherwise check if pixel is inside source region
  1122 + else if (position.cos_dist(skydir) >= m_cos_roiradius) {
1082 1123
1083 - // Update alpha_on  
1084 - alpha_on += background(j); 1124 + // Update n_on
  1125 + non += counts(i);
1085 1126
1086 - } // endif: source and background region check 1127 + // Update alpha_on
  1128 + alpha_on += background(i);
1087 1129
1088 - } // endif: pixel is within outer radius of background region 1130 + } // endif: source and background region check
1089 1131
1090 - } // endfor: looped over pixels 1132 + } // endif: pixel is within outer radius of background region
  1133 +
  1134 + } // endfor: looped over y pixels
  1135 +
  1136 + } // endfor: looped over x pixels
1091 1137
1092 // Compute alpha. If the off region does not have any sensitivity then 1138 // Compute alpha. If the off region does not have any sensitivity then
1093 // set Non = Noff = 0 1139 // set Non = Noff = 0
@@ -1106,6 +1152,95 @@ void ctskymap::compute_ring_values(const GSkyMap&amp; counts, @@ -1106,6 +1152,95 @@ void ctskymap::compute_ring_values(const GSkyMap&amp; counts,
1106 1152
1107 1153
1108 /***********************************************************************//** 1154 /***********************************************************************//**
  1155 + * @brief Computes bounding box for RING background computation
  1156 + *
  1157 + * @param[in] ipixel Sky map pixel to consider.
  1158 + * @param[out] ix1 Index of first pixel in x.
  1159 + * @param[out] ix2 Index after last pixel in x.
  1160 + * @param[out] iy1 Index of first pixel in y.
  1161 + * @param[out] iy2 Index after last pixel in y.
  1162 + *
  1163 + * Computes the bounding box that contained the background ring for a
  1164 + * specific pixel for the RING background method.
  1165 + *
  1166 + * The method determines the local pixel scale for the requested pixel and
  1167 + * draws a bounding box with 1.5 times the outer background ring radius
  1168 + * around the pixel. In the x direction the pixel indices are unconstrained,
  1169 + * and the client has to assure that the pixel value is comprised within
  1170 + * the validity range (this is required to handle the longitude wrap around).
  1171 + * In the y direction the pixel indices are constrained to [0,ny], where
  1172 + * ny is the number of y pixels in the sky map.
  1173 + ***************************************************************************/
  1174 +void ctskymap::ring_bounding_box(const int& ipixel, int& ix1, int& ix2,
  1175 + int& iy1, int& iy2)
  1176 +{
  1177 + // Get number of pixels in x and y direction
  1178 + int nx = m_skymap.nx();
  1179 + int ny = m_skymap.ny();
  1180 +
  1181 + // Get x and y index of pixel to consider
  1182 + int ix0 = ipixel % nx;
  1183 + int iy0 = ipixel / nx;
  1184 +
  1185 + // Compute pixel increment in x-direction
  1186 + double dx = 0.0;
  1187 + int ix = (ix0 > 0) ? ix0 - 1 : ix0 + 1;
  1188 + if (ix < nx) {
  1189 + dx = m_dirs[ipixel].dist_deg(m_dirs[ix+iy0*nx]);
  1190 + }
  1191 + if (dx < m_binsz) {
  1192 + dx = m_binsz;
  1193 + }
  1194 +
  1195 + // Compute pixel increment in y-direction
  1196 + double dy = 0.0;
  1197 + int iy = (iy0 > 0) ? iy0 - 1 : iy0 + 1;
  1198 + if (iy < ny) {
  1199 + dx = m_dirs[ipixel].dist_deg(m_dirs[ix0+iy*nx]);
  1200 + }
  1201 + if (dy < m_binsz) {
  1202 + dy = m_binsz;
  1203 + }
  1204 +
  1205 + // Compute bounding box half size in x and y. The outer radius is
  1206 + // multiplied by 1.5 to have some margin in case of map distortions
  1207 + int nx_bbox = int(1.5 * m_outradius / dx);
  1208 + int ny_bbox = int(1.5 * m_outradius / dy);
  1209 +
  1210 + // Compute index range for x. We allow that indices are smaller than 0
  1211 + // or equal or larger than nx to handle wrap around, which needs to be
  1212 + // done in the client method.
  1213 + if (2*nx_bbox < nx) {
  1214 + ix1 = ix0 - nx_bbox;
  1215 + ix2 = ix0 + nx_bbox;
  1216 + }
  1217 + else {
  1218 + ix1 = 0;
  1219 + ix2 = nx;
  1220 + }
  1221 +
  1222 + // Compute index range for y. The index range is restricted to [0,ny].
  1223 + if (2*ny_bbox < ny) {
  1224 + iy1 = iy0 - ny_bbox;
  1225 + iy2 = iy0 + ny_bbox;
  1226 + if (iy1 < 0) {
  1227 + iy1 = 0;
  1228 + }
  1229 + if (iy2 > ny) {
  1230 + iy2 = ny;
  1231 + }
  1232 + }
  1233 + else {
  1234 + iy1 = 0;
  1235 + iy2 = ny;
  1236 + }
  1237 +
  1238 + // Return
  1239 + return;
  1240 +}
  1241 +
  1242 +
  1243 +/***********************************************************************//**
1109 * @brief Write keywords in FITS HDU 1244 * @brief Write keywords in FITS HDU
1110 * 1245 *
1111 * @param[in,out] hdu Pointer to FITS HDU. 1246 * @param[in,out] hdu Pointer to FITS HDU.
src/ctskymap/ctskymap.hpp
1 /*************************************************************************** 1 /***************************************************************************
2 * ctskymap - Sky mapping tool * 2 * ctskymap - Sky mapping tool *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2010-2017 by Juergen Knoedlseder * 4 + * copyright (C) 2010-2018 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -77,15 +77,20 @@ protected: @@ -77,15 +77,20 @@ protected:
77 void map_background_irf(GCTAObservation* obs); 77 void map_background_irf(GCTAObservation* obs);
78 void map_significance(void); 78 void map_significance(void);
79 void map_significance_ring(void); 79 void map_significance_ring(void);
80 - void compute_ring_values(const GSkyMap& counts, 80 + void compute_ring_values(const int& ipixel,
  81 + const GSkyMap& counts,
81 const GSkyMap& background, 82 const GSkyMap& background,
82 - const GSkyDir& position,  
83 - double& non, double& noff, double& alpha); 83 + double& non,
  84 + double& noff,
  85 + double& alpha);
  86 + void ring_bounding_box(const int& ipixel, int& ix1, int& ix2,
  87 + int& iy1, int& iy2);
84 void write_hdu_keywords(GFitsHDU* hdu) const; 88 void write_hdu_keywords(GFitsHDU* hdu) const;
85 89
86 // User parameters 90 // User parameters
87 GFilename m_outmap; //!< Output file name 91 GFilename m_outmap; //!< Output file name
88 GFilename m_inexclusion; //!< Exclusion map file name 92 GFilename m_inexclusion; //!< Exclusion map file name
  93 + double m_binsz; //!< Sky map binsize
89 double m_emin; //!< Minimum energy (TeV) 94 double m_emin; //!< Minimum energy (TeV)
90 double m_emax; //!< Maximum energy (TeV) 95 double m_emax; //!< Maximum energy (TeV)
91 std::string m_bkgsubtract; //!< Background subtraction method 96 std::string m_bkgsubtract; //!< Background subtraction method
@@ -102,8 +107,11 @@ protected: @@ -102,8 +107,11 @@ protected:
102 GSkyMap m_exclmap; //!< Exclusion map for RING background 107 GSkyMap m_exclmap; //!< Exclusion map for RING background
103 108
104 // Caching variables to prevent multiple computations of the same thing 109 // Caching variables to prevent multiple computations of the same thing
105 - std::vector<double> m_solidangle; //!< Cached pixel solid angles  
106 - std::vector<GSkyDir> m_dirs; //!< Cached pixel directions 110 + std::vector<double> m_solidangle; //!< Cached pixel solid angles
  111 + std::vector<GSkyDir> m_dirs; //!< Cached pixel directions
  112 + double m_cos_roiradius; //!< Cosine of RoI radius
  113 + double m_cos_inradius; //!< Cosine of inner ring radius
  114 + double m_cos_outradius; //!< Cosine of outer ring radius
107 }; 115 };
108 116
109 117