Commit a276a1d31ef988c8a1bcd6603b4e81474fd7a8fa
1 parent
abc02a45
Implement COMPTEL background model computation (#3557)
Showing
6 changed files
with
547 additions
and
3 deletions
ChangeLog
| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | |
| 6 | 6 | Store DRB, DRG and DRX as GCOMDri in GCOMObservation (#3560) |
| 7 | 7 | Implement COMPTEL response for diffuse models (#3558) |
| 8 | + Implement COMPTEL background model computation (#3557) | |
| 8 | 9 | Fix reading of scaled FITS columns, remove GFitsTableCol::scale() method (#3553) |
| 9 | 10 | Add gammalib::compare() function (#3552) |
| 10 | 11 | Add DRI constructor to GCOMObservation class | ... | ... |
NEWS
| ... | ... | @@ -77,6 +77,7 @@ The following methods have been added: |
| 77 | 77 | - GCOMObservation::drgname() |
| 78 | 78 | - GCOMObservation::drxname() |
| 79 | 79 | - GCOMObservation::response(GCOMResponse&) |
| 80 | +- GCOMObservation::compute_drb() | |
| 80 | 81 | - GCOMDri::tof_correction() |
| 81 | 82 | - GCOMDri::num_superpackets() |
| 82 | 83 | - GCOMDri::num_used_superpackets() |
| ... | ... | @@ -280,8 +281,8 @@ spatial model gradients (#3203). |
| 280 | 281 | Store DRB, DRG and DRX as instances of GCOMDri instead of GSkyMap in GCOMObservation |
| 281 | 282 | (#3560). |
| 282 | 283 | |
| 283 | -Remove internal response caching since caching is handled by the base class response | |
| 284 | -computation methods (#2973). | |
| 284 | +Added GCOMObservation::compute_drb() method to compute background models for COMPTEL. | |
| 285 | +So far the PHINOR and BGDLIXA background methods were implemented (#3557). | |
| 285 | 286 | |
| 286 | 287 | Added method to set COMPTEL response using GCOMResponse instance. |
| 287 | 288 | |
| ... | ... | @@ -301,6 +302,9 @@ Added methods to access DRI filenames in GCOMObservation. |
| 301 | 302 | |
| 302 | 303 | Implemented vectorised response computation in GCOMResponse::irf_ptsrc() method (#3501). |
| 303 | 304 | |
| 305 | +Remove internal response caching since caching is handled by the base class response | |
| 306 | +computation methods (#2973). | |
| 307 | + | |
| 304 | 308 | |
| 305 | 309 | 22. INTEGRAL/SPI interface |
| 306 | 310 | -------------------------- | ... | ... |
doc/source/admin/release_history/2.0.rst
| ... | ... | @@ -33,6 +33,8 @@ Improvements |
| 33 | 33 | |
| 34 | 34 | * [`3558 <https://cta-redmine.irap.omp.eu/issues/3558>`_] - |
| 35 | 35 | Implement COMPTEL response for diffuse models |
| 36 | +* [`3557 <https://cta-redmine.irap.omp.eu/issues/3557>`_] - | |
| 37 | + Implement COMPTEL background model computation | |
| 36 | 38 | * [`3552 <https://cta-redmine.irap.omp.eu/issues/3552>`_] - |
| 37 | 39 | Add ``gammalib::compare()`` function |
| 38 | 40 | * Add DRI constructor to ``GCOMObservation`` class | ... | ... |
inst/com/include/GCOMObservation.hpp
| ... | ... | @@ -131,6 +131,12 @@ public: |
| 131 | 131 | void drbname(const GFilename& drbname); |
| 132 | 132 | void drgname(const GFilename& drgname); |
| 133 | 133 | void drxname(const GFilename& drxname); |
| 134 | + void compute_drb(const std::string& method, | |
| 135 | + const GCOMDri& drm, | |
| 136 | + const int& nrunav = 3, | |
| 137 | + const int& navgr = 3, | |
| 138 | + const int& nincl = 13, | |
| 139 | + const int& nexcl = 0); | |
| 134 | 140 | |
| 135 | 141 | protected: |
| 136 | 142 | // Protected methods |
| ... | ... | @@ -144,6 +150,19 @@ protected: |
| 144 | 150 | bool check_dri(const GCOMDri& map) const; |
| 145 | 151 | void read_attributes(const GFitsHDU* hdu); |
| 146 | 152 | void write_attributes(GFitsHDU* hdu) const; |
| 153 | + void compute_drb_phinor(const GCOMDri& drm); | |
| 154 | + void compute_drb_bgdlixa(const GCOMDri& drm, | |
| 155 | + const int& nrunav = 3, | |
| 156 | + const int& navgr = 3, | |
| 157 | + const int& nincl = 13, | |
| 158 | + const int& nexcl = 0); | |
| 159 | + void get_bgdlixa_phibar_indices(const int& iphibar, | |
| 160 | + const int& nincl, | |
| 161 | + const int& nexcl, | |
| 162 | + int* isel1, | |
| 163 | + int* iex1, | |
| 164 | + int* iex2, | |
| 165 | + int* isel2) const; | |
| 147 | 166 | |
| 148 | 167 | // Protected members |
| 149 | 168 | std::string m_instrument; //!< Instrument name | ... | ... |
inst/com/pyext/GCOMObservation.i
| ... | ... | @@ -99,6 +99,12 @@ public: |
| 99 | 99 | void drbname(const GFilename& drbname); |
| 100 | 100 | void drgname(const GFilename& drgname); |
| 101 | 101 | void drxname(const GFilename& drxname); |
| 102 | + void compute_drb(const std::string& method, | |
| 103 | + const GCOMDri& drm, | |
| 104 | + const int& nrunav = 3, | |
| 105 | + const int& navgr = 3, | |
| 106 | + const int& nincl = 13, | |
| 107 | + const int& nexcl = 0); | |
| 102 | 108 | }; |
| 103 | 109 | |
| 104 | 110 | ... | ... |
inst/com/src/GCOMObservation.cpp
| ... | ... | @@ -57,7 +57,9 @@ const GObservationRegistry g_obs_com_registry(&g_obs_com_seed); |
| 57 | 57 | #define G_LOAD_DRB "GCOMObservation::load_drb(GFilename&)" |
| 58 | 58 | #define G_LOAD_DRG "GCOMObservation::load_drg(GFilename&)" |
| 59 | 59 | #define G_DRM "GCOMObservation::drm(GModels&)" |
| 60 | -#define G_ADD_DRM "GCOMObservation::add_drm(GSkyModel&)" | |
| 60 | +#define G_COMPUTE_DRB "GCOMObservation::compute_drb(std::string&, GCOMDri&, "\ | |
| 61 | + "int&, int&, int&, int&" | |
| 62 | +#define G_COMPUTE_DRB_PHINOR "GCOMObservation::compute_drb_phinor(GCOMDri&)" | |
| 61 | 63 | |
| 62 | 64 | /* __ Macros _____________________________________________________________ */ |
| 63 | 65 | |
| ... | ... | @@ -731,6 +733,45 @@ GCOMDri GCOMObservation::drm(const GModels& models) const |
| 731 | 733 | |
| 732 | 734 | |
| 733 | 735 | /***********************************************************************//** |
| 736 | + * @brief Compute DRB cube | |
| 737 | + * | |
| 738 | + * @param[in] method Background method (PHINOR or BGDLIXA). | |
| 739 | + * @param[in] drm DRM cube. | |
| 740 | + * @param[in] nrunav BGDLIXA: number of bins used for running average. | |
| 741 | + * @param[in] navgr BGDLIXA: number of bins used for averaging. | |
| 742 | + * @param[in] nincl BGDLIXA: number of Phibar layers to include. | |
| 743 | + * @param[in] nexcl BGDLIXA: number of Phibar layers to exclude. | |
| 744 | + * | |
| 745 | + * Computes a COMPTEL DRB cube using either the PHINOR or BGDLIXA method. | |
| 746 | + * See the protected methods compute_drb_phinor() and compute_drb_bgdlixa() | |
| 747 | + * for more information. | |
| 748 | + ***************************************************************************/ | |
| 749 | +void GCOMObservation::compute_drb(const std::string& method, | |
| 750 | + const GCOMDri& drm, | |
| 751 | + const int& nrunav, | |
| 752 | + const int& navgr, | |
| 753 | + const int& nincl, | |
| 754 | + const int& nexcl) | |
| 755 | +{ | |
| 756 | + // Branch to relevant method based on specified background method | |
| 757 | + if (method == "PHINOR") { | |
| 758 | + compute_drb_phinor(drm); | |
| 759 | + } | |
| 760 | + else if (method == "BGDLIXA") { | |
| 761 | + compute_drb_bgdlixa(drm, nrunav, navgr, nincl, nexcl); | |
| 762 | + } | |
| 763 | + else { | |
| 764 | + std::string msg = "Unknown background method \""+method+"\". " | |
| 765 | + "Specify either \"PHINOR\" or \"BGDLIXA\"."; | |
| 766 | + throw GException::invalid_argument(G_COMPUTE_DRB, msg); | |
| 767 | + } | |
| 768 | + | |
| 769 | + // Return | |
| 770 | + return; | |
| 771 | +} | |
| 772 | + | |
| 773 | + | |
| 774 | +/***********************************************************************//** | |
| 734 | 775 | * @brief Print observation information |
| 735 | 776 | * |
| 736 | 777 | * @param[in] chatter Chattiness. |
| ... | ... | @@ -1135,3 +1176,474 @@ void GCOMObservation::write_attributes(GFitsHDU* hdu) const |
| 1135 | 1176 | // Return |
| 1136 | 1177 | return; |
| 1137 | 1178 | } |
| 1179 | + | |
| 1180 | + | |
| 1181 | +/***********************************************************************//** | |
| 1182 | + * @brief Compute DRB cube using PHINOR method | |
| 1183 | + * | |
| 1184 | + * @param[in] drm DRM cube. | |
| 1185 | + * | |
| 1186 | + * @exception GException::invalid_value | |
| 1187 | + * Observation does not contain an event cube | |
| 1188 | + * @exception GException::invalid_argument | |
| 1189 | + * DRM cube is incompatible with DRE | |
| 1190 | + ***************************************************************************/ | |
| 1191 | +void GCOMObservation::compute_drb_phinor(const GCOMDri& drm) | |
| 1192 | +{ | |
| 1193 | + // Extract COMPTEL event cube | |
| 1194 | + const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(this->events()); | |
| 1195 | + if (cube == NULL) { | |
| 1196 | + std::string msg = "Observation \""+this->name()+"\" ("+this->id()+") " | |
| 1197 | + "does not contain a COMPTEL event cube. Please " | |
| 1198 | + "specify a COMPTEL observation containing and event " | |
| 1199 | + "cube."; | |
| 1200 | + throw GException::invalid_value(G_COMPUTE_DRB_PHINOR, msg); | |
| 1201 | + } | |
| 1202 | + | |
| 1203 | + // Check DRM | |
| 1204 | + if (!check_dri(drm)) { | |
| 1205 | + std::string msg = "Specified DRM cube is incompatible with DRE. Please " | |
| 1206 | + "specify a DRM with a data-space definition that is " | |
| 1207 | + "identical to that of the DRE."; | |
| 1208 | + throw GException::invalid_argument(G_COMPUTE_DRB_PHINOR, msg); | |
| 1209 | + } | |
| 1210 | + | |
| 1211 | + // Initialise DRB by cloning DRG | |
| 1212 | + m_drb = m_drg; | |
| 1213 | + | |
| 1214 | + // Get DRI sky maps | |
| 1215 | + const GSkyMap& map_dre = cube->dre().map(); | |
| 1216 | + const GSkyMap& map_drm = drm.map(); | |
| 1217 | + const GSkyMap& map_drg = m_drg.map(); | |
| 1218 | + GSkyMap& map_drb = const_cast<GSkyMap&>(m_drb.map()); | |
| 1219 | + | |
| 1220 | + // Get data space dimensions | |
| 1221 | + int npix = m_drg.map().npix(); | |
| 1222 | + int nphibar = m_drg.nphibar(); | |
| 1223 | + | |
| 1224 | + // Phibar normalise DRB | |
| 1225 | + for (int iphibar = 0; iphibar < nphibar; ++iphibar) { | |
| 1226 | + double sum_dre = 0.0; | |
| 1227 | + double sum_drm = 0.0; | |
| 1228 | + double sum_drg = 0.0; | |
| 1229 | + for (int ipix = 0; ipix < npix; ++ipix) { | |
| 1230 | + sum_dre += map_dre(ipix, iphibar); | |
| 1231 | + sum_drm += map_drm(ipix, iphibar); | |
| 1232 | + sum_drg += map_drg(ipix, iphibar); | |
| 1233 | + } | |
| 1234 | + if (sum_drg > 0.0) { | |
| 1235 | + double norm = (sum_dre - sum_drm) / sum_drg; | |
| 1236 | + for (int ipix = 0; ipix < npix; ++ipix) { | |
| 1237 | + map_drb(ipix, iphibar) *= norm; | |
| 1238 | + } | |
| 1239 | + } | |
| 1240 | + else { | |
| 1241 | + for (int ipix = 0; ipix < npix; ++ipix) { | |
| 1242 | + map_drb(ipix, iphibar) = 0.0; | |
| 1243 | + } | |
| 1244 | + } | |
| 1245 | + } | |
| 1246 | + | |
| 1247 | + // Return | |
| 1248 | + return; | |
| 1249 | +} | |
| 1250 | + | |
| 1251 | + | |
| 1252 | +/***********************************************************************//** | |
| 1253 | + * @brief Compute DRB cube using BGDLIXA method | |
| 1254 | + * | |
| 1255 | + * @param[in] drm DRM cube. | |
| 1256 | + * @param[in] nrunav Number of bins used for running average. | |
| 1257 | + * @param[in] navgr Number of bins used for averaging. | |
| 1258 | + * @param[in] nincl Number of Phibar layers to include. | |
| 1259 | + * @param[in] nexcl Number of Phibar layers to exclude. | |
| 1260 | + * | |
| 1261 | + * @exception GException::invalid_value | |
| 1262 | + * Observation does not contain an event cube | |
| 1263 | + * @exception GException::invalid_argument | |
| 1264 | + * DRM cube is incompatible with DRE | |
| 1265 | + * | |
| 1266 | + * Computes a DRB cube using the BGDLIXA method that is documented in Rob | |
| 1267 | + * van Dijk's PhD thesis. The revelant equations from the thesis that are | |
| 1268 | + * implemented here are 3.12, 3.12 and 3.14. | |
| 1269 | + ***************************************************************************/ | |
| 1270 | +void GCOMObservation::compute_drb_bgdlixa(const GCOMDri& drm, | |
| 1271 | + const int& nrunav, | |
| 1272 | + const int& navgr, | |
| 1273 | + const int& nincl, | |
| 1274 | + const int& nexcl) | |
| 1275 | +{ | |
| 1276 | + // Extract COMPTEL event cube | |
| 1277 | + const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(this->events()); | |
| 1278 | + if (cube == NULL) { | |
| 1279 | + std::string msg = "Observation \""+this->name()+"\" ("+this->id()+") " | |
| 1280 | + "does not contain a COMPTEL event cube. Please " | |
| 1281 | + "specify a COMPTEL observation containing and event " | |
| 1282 | + "cube."; | |
| 1283 | + throw GException::invalid_value(G_COMPUTE_DRB_PHINOR, msg); | |
| 1284 | + } | |
| 1285 | + | |
| 1286 | + // Check DRM | |
| 1287 | + if (!check_dri(drm)) { | |
| 1288 | + std::string msg = "Specified DRM cube is incompatible with DRE. Please " | |
| 1289 | + "specify a DRM with a data-space definition that is " | |
| 1290 | + "identical to that of the DRE."; | |
| 1291 | + throw GException::invalid_argument(G_COMPUTE_DRB_PHINOR, msg); | |
| 1292 | + } | |
| 1293 | + | |
| 1294 | + // Initialise DRB and scratch DRI by cloning DRG | |
| 1295 | + m_drb = m_drg; | |
| 1296 | + GCOMDri dri = m_drg; | |
| 1297 | + | |
| 1298 | + // Get references to relevant sky maps | |
| 1299 | + const GSkyMap& map_dre = cube->dre().map(); | |
| 1300 | + const GSkyMap& map_drm = drm.map(); | |
| 1301 | + const GSkyMap& map_drg = m_drg.map(); | |
| 1302 | + GSkyMap& map_drb = const_cast<GSkyMap&>(m_drb.map()); | |
| 1303 | + GSkyMap& map_dri = const_cast<GSkyMap&>(dri.map()); | |
| 1304 | + | |
| 1305 | + // Get data space dimensions | |
| 1306 | + int nchi = m_drg.nchi(); | |
| 1307 | + int npsi = m_drg.npsi(); | |
| 1308 | + int nphibar = m_drg.nphibar(); | |
| 1309 | + int npix = nchi * npsi; | |
| 1310 | + int nsize = npix * nphibar; | |
| 1311 | + | |
| 1312 | + // Precompute half running average lengths | |
| 1313 | + int navgr2 = int(navgr/2); | |
| 1314 | + int nexcl2 = int(nexcl/2); | |
| 1315 | + int nincl2 = int(nincl/2); | |
| 1316 | + | |
| 1317 | + // Initialise DRB and scratch DRI | |
| 1318 | + for (int iphibar = 0; iphibar < nphibar; ++iphibar) { | |
| 1319 | + for (int ipix = 0; ipix < npix; ++ipix) { | |
| 1320 | + map_drb(ipix, iphibar) = 0.0; | |
| 1321 | + map_dri(ipix, iphibar) = 0.0; | |
| 1322 | + } | |
| 1323 | + } | |
| 1324 | + | |
| 1325 | + // Phibar normalise DRB (Equation 3.12 in Rob van Dijk's PhD thesis). | |
| 1326 | + for (int iphibar = 0; iphibar < nphibar; ++iphibar) { | |
| 1327 | + double sum_dre = 0.0; | |
| 1328 | + double sum_drm = 0.0; | |
| 1329 | + double sum_drg = 0.0; | |
| 1330 | + for (int ipix = 0; ipix < npix; ++ipix) { | |
| 1331 | + sum_dre += map_dre(ipix, iphibar); | |
| 1332 | + sum_drm += map_drm(ipix, iphibar); | |
| 1333 | + sum_drg += map_drg(ipix, iphibar); | |
| 1334 | + } | |
| 1335 | + if (sum_drg > 0.0) { | |
| 1336 | + double norm = (sum_dre - sum_drm) / sum_drg; | |
| 1337 | + for (int ipix = 0; ipix < npix; ++ipix) { | |
| 1338 | + map_dri(ipix, iphibar) = map_drg(ipix, iphibar) * norm; | |
| 1339 | + } | |
| 1340 | + } | |
| 1341 | + } | |
| 1342 | + | |
| 1343 | + // Do 3D running average of DRE and Phibar normalised DRG (Equation 3.13 | |
| 1344 | + // in Rob van Dijk's PhD thesis). The result is a Phibar normalised DRG | |
| 1345 | + // that is normalised over the 3D region to the DRE. The 3D region is all | |
| 1346 | + // Phibar layers and [-nrunav,+nrunav] Chi/Psi pixels around the pixel of | |
| 1347 | + // consideration. | |
| 1348 | + if (nrunav >= 1) { | |
| 1349 | + | |
| 1350 | + // Loop over Chi pixels | |
| 1351 | + for (int ichi = 0; ichi < nchi; ++ichi) { | |
| 1352 | + | |
| 1353 | + // Compute running average window in Chi | |
| 1354 | + int kchi_min = ichi - nrunav; | |
| 1355 | + int kchi_max = ichi + nrunav; | |
| 1356 | + if (kchi_min < 0) { | |
| 1357 | + kchi_min = 0; | |
| 1358 | + } | |
| 1359 | + if (kchi_max >= nchi) { | |
| 1360 | + kchi_max = nchi - 1; | |
| 1361 | + } | |
| 1362 | + | |
| 1363 | + // Loop over Psi pixels | |
| 1364 | + for (int ipsi = 0; ipsi < npsi; ++ipsi) { | |
| 1365 | + | |
| 1366 | + // Compute running average window in Psi | |
| 1367 | + int kpsi_min = ipsi - nrunav; | |
| 1368 | + int kpsi_max = ipsi + nrunav; | |
| 1369 | + if (kpsi_min < 0) { | |
| 1370 | + kpsi_min = 0; | |
| 1371 | + } | |
| 1372 | + if (kpsi_max >= npsi) { | |
| 1373 | + kpsi_max = npsi - 1; | |
| 1374 | + } | |
| 1375 | + | |
| 1376 | + // Initialise sums | |
| 1377 | + double sum_dre = 0.0; | |
| 1378 | + double sum_drm = 0.0; | |
| 1379 | + double sum_dri = 0.0; | |
| 1380 | + | |
| 1381 | + // Compute running average | |
| 1382 | + for (int kchi = kchi_min; kchi <= kchi_max; ++kchi) { | |
| 1383 | + for (int kpsi = kpsi_min; kpsi <= kpsi_max; ++kpsi) { | |
| 1384 | + int kpix = kchi + kpsi * nchi; | |
| 1385 | + for (int kphibar = 0; kphibar < nphibar; ++kphibar) { | |
| 1386 | + if (map_drg(kpix, kphibar) != 0.0) { | |
| 1387 | + sum_dre += map_dre(kpix, kphibar); | |
| 1388 | + sum_drm += map_drm(kpix, kphibar); | |
| 1389 | + sum_dri += map_dri(kpix, kphibar); | |
| 1390 | + } | |
| 1391 | + } | |
| 1392 | + } | |
| 1393 | + } | |
| 1394 | + | |
| 1395 | + // Renormalise scratch array | |
| 1396 | + if (sum_dri != 0.0) { | |
| 1397 | + int ipix = ichi + ipsi * nchi; | |
| 1398 | + double norm = (sum_dre - sum_drm) / sum_dri; | |
| 1399 | + for (int iphibar = 0; iphibar < nphibar; ++iphibar) { | |
| 1400 | + map_dri(ipix, iphibar) *= norm; | |
| 1401 | + } | |
| 1402 | + } | |
| 1403 | + | |
| 1404 | + } // endfor: looped over Phi | |
| 1405 | + | |
| 1406 | + } // endfor: looped over Chi | |
| 1407 | + | |
| 1408 | + } // endif: running averaging was requested | |
| 1409 | + | |
| 1410 | + // First part of Equation (3.14) in Rob van Dijk's PhD thesis. | |
| 1411 | + // (DRB = B^0C_L / sum B^0C_L). The DRB is pre-computed by adjusting the | |
| 1412 | + // scratch DRI over nincl Phibar layers. | |
| 1413 | + int ksel1 = 0; | |
| 1414 | + int kex1 = 0; | |
| 1415 | + int kex2 = 0; | |
| 1416 | + int ksel2 = 0; | |
| 1417 | + for (int iphibar = 0; iphibar < nphibar; ++iphibar) { | |
| 1418 | + | |
| 1419 | + // Get Phibar index range for sums | |
| 1420 | + get_bgdlixa_phibar_indices(iphibar, nincl, nexcl, | |
| 1421 | + &ksel1, &kex1, &kex2, &ksel2); | |
| 1422 | + | |
| 1423 | + // Loop over Chi/Psi pixels | |
| 1424 | + for (int ipix = 0; ipix < npix; ++ipix) { | |
| 1425 | + | |
| 1426 | + // Initialise DRB value | |
| 1427 | + map_drb(ipix, iphibar) = 0.0; | |
| 1428 | + | |
| 1429 | + // Continue only if scratch DRI is non-zero | |
| 1430 | + if (map_dri(ipix, iphibar) != 0.0) { | |
| 1431 | + | |
| 1432 | + // Initialise sum | |
| 1433 | + double sum_dri = 0.0; | |
| 1434 | + | |
| 1435 | + // Take sum over [ksel1, kex1] | |
| 1436 | + if (kex1 >= 0) { | |
| 1437 | + for (int kphibar = ksel1; kphibar <= kex1; ++kphibar) { | |
| 1438 | + sum_dri += map_dri(ipix, kphibar); | |
| 1439 | + } | |
| 1440 | + } | |
| 1441 | + | |
| 1442 | + // Take sum over [kxe2, ksel2] | |
| 1443 | + if (kex2 < nphibar) { | |
| 1444 | + for (int kphibar = kex2; kphibar <= ksel2; ++kphibar) { | |
| 1445 | + sum_dri += map_dri(ipix, kphibar); | |
| 1446 | + } | |
| 1447 | + } | |
| 1448 | + | |
| 1449 | + // If sum is not zero then set DRB | |
| 1450 | + if (sum_dri != 0.0) { | |
| 1451 | + map_drb(ipix, iphibar) = map_dri(ipix, iphibar) / sum_dri; | |
| 1452 | + } | |
| 1453 | + | |
| 1454 | + } // endif: scratch DRI was non-zero | |
| 1455 | + | |
| 1456 | + } // endfor: looped over Chi/Psi pixels | |
| 1457 | + | |
| 1458 | + } // endfor: looped over Phibar | |
| 1459 | + | |
| 1460 | + // Second part of Equation (3.14) in Rob van Dijk's PhD thesis that | |
| 1461 | + // corresponds to G * [E / G]^s that will be stored in scratch DRI. | |
| 1462 | + // | |
| 1463 | + // NOTES: | |
| 1464 | + // - we replaced DRE by DRE-DRM in the nominator of the running | |
| 1465 | + // average since and source component should of course be | |
| 1466 | + // subtracted | |
| 1467 | + // - we implemented an alternative running average computation where | |
| 1468 | + // the ratio between the DRE and DRG sums is taken. This avoids | |
| 1469 | + // the divergence of the ratio at the edge of the DRG. | |
| 1470 | + for (int ichi = 0; ichi < nchi; ++ichi) { | |
| 1471 | + | |
| 1472 | + // Compute running average window in Chi | |
| 1473 | + int kchi_min = ichi - navgr2; | |
| 1474 | + int kchi_max = ichi + navgr2; | |
| 1475 | + if (kchi_min < 0) { | |
| 1476 | + kchi_min = 0; | |
| 1477 | + } | |
| 1478 | + if (kchi_max >= nchi) { | |
| 1479 | + kchi_max = nchi - 1; | |
| 1480 | + } | |
| 1481 | + | |
| 1482 | + // Loop over Psi pixels | |
| 1483 | + for (int ipsi = 0; ipsi < npsi; ++ipsi) { | |
| 1484 | + | |
| 1485 | + // Compute running average window in Psi | |
| 1486 | + int kpsi_min = ipsi - navgr2; | |
| 1487 | + int kpsi_max = ipsi + navgr2; | |
| 1488 | + if (kpsi_min < 0) { | |
| 1489 | + kpsi_min = 0; | |
| 1490 | + } | |
| 1491 | + if (kpsi_max >= npsi) { | |
| 1492 | + kpsi_max = npsi - 1; | |
| 1493 | + } | |
| 1494 | + | |
| 1495 | + // Loop over Phibar layers | |
| 1496 | + for (int iphibar = 0; iphibar < nphibar; ++iphibar) { | |
| 1497 | + | |
| 1498 | + // Initialise sums | |
| 1499 | + double sum_dre = 0.0; | |
| 1500 | + double sum_drm = 0.0; | |
| 1501 | + double sum_drg = 0.0; | |
| 1502 | + | |
| 1503 | + // Compute running average | |
| 1504 | + for (int kchi = kchi_min; kchi <= kchi_max; ++kchi) { | |
| 1505 | + for (int kpsi = kpsi_min; kpsi <= kpsi_max; ++kpsi) { | |
| 1506 | + int kpix = kchi + kpsi * nchi; | |
| 1507 | + sum_dre += map_dre(kpix, iphibar); | |
| 1508 | + sum_drm += map_drm(kpix, iphibar); | |
| 1509 | + sum_drg += map_drg(kpix, iphibar); | |
| 1510 | + } | |
| 1511 | + } | |
| 1512 | + | |
| 1513 | + // Multiply average by DRG and store it in scratch DRI | |
| 1514 | + int ipix = ichi + ipsi * nchi; | |
| 1515 | + if (sum_drg > 0.0) { | |
| 1516 | + double norm = (sum_dre - sum_drm) / sum_drg; | |
| 1517 | + map_dri(ipix, iphibar) = map_drg(ipix, iphibar) * norm; | |
| 1518 | + } | |
| 1519 | + else { | |
| 1520 | + map_dri(ipix, iphibar) = 0.0; | |
| 1521 | + } | |
| 1522 | + | |
| 1523 | + } // endfor: looped over Phibar layers | |
| 1524 | + | |
| 1525 | + } // endfor: looped over Psi pixels | |
| 1526 | + | |
| 1527 | + } // endfor: looped over Chi pixels | |
| 1528 | + | |
| 1529 | + // Third part of Equation (3.14) in Rob van Dijk's PhD thesis that sums | |
| 1530 | + // G * [E / G]^s over a subset of Phibar layers (the first parenthesis) | |
| 1531 | + // and multplies with B^0C_L / sum B^0C_L | |
| 1532 | + for (int iphibar = 0; iphibar < nphibar; ++iphibar) { | |
| 1533 | + | |
| 1534 | + // Get Phibar index range for sums | |
| 1535 | + get_bgdlixa_phibar_indices(iphibar, nincl, nexcl, | |
| 1536 | + &ksel1, &kex1, &kex2, &ksel2); | |
| 1537 | + | |
| 1538 | + // Loop over Chi/Psi pixels | |
| 1539 | + for (int ipix = 0; ipix < npix; ++ipix) { | |
| 1540 | + | |
| 1541 | + // If DRB is not empty then correct it | |
| 1542 | + if (map_drb(ipix, iphibar) != 0.0) { | |
| 1543 | + | |
| 1544 | + // Initialise DRI sum | |
| 1545 | + double sum_dri = 0.0; | |
| 1546 | + | |
| 1547 | + // Take sum over [ksel1, kex1] | |
| 1548 | + if (kex1 >= 0) { | |
| 1549 | + for (int kphibar = ksel1; kphibar <= kex1; ++kphibar) { | |
| 1550 | + sum_dri += map_dri(ipix, kphibar); | |
| 1551 | + } | |
| 1552 | + } | |
| 1553 | + | |
| 1554 | + // Take sum over [kxe2, ksel2] | |
| 1555 | + if (kex2 < nphibar) { | |
| 1556 | + for (int kphibar = kex2; kphibar <= ksel2; ++kphibar) { | |
| 1557 | + sum_dri += map_dri(ipix, kphibar); | |
| 1558 | + } | |
| 1559 | + } | |
| 1560 | + | |
| 1561 | + // Correct DRB | |
| 1562 | + map_drb(ipix, iphibar) *= sum_dri; | |
| 1563 | + | |
| 1564 | + } // endif: DRB was not empty | |
| 1565 | + | |
| 1566 | + } // endfor: looped over Chi/Psi pixels | |
| 1567 | + | |
| 1568 | + } // endfor: looped over Phibar | |
| 1569 | + | |
| 1570 | + // Return | |
| 1571 | + return; | |
| 1572 | +} | |
| 1573 | + | |
| 1574 | + | |
| 1575 | +/***********************************************************************//** | |
| 1576 | + * @brief Compute Phibar index range for BGDLIXA background method | |
| 1577 | + * | |
| 1578 | + * @param[in] iphibar Phibar layer index. | |
| 1579 | + * @param[in] nincl Number of Phibar layers to include. | |
| 1580 | + * @param[in] nexcl Number of Phibar layers to exclude. | |
| 1581 | + * @param[out] isel1 Start index for first sum. | |
| 1582 | + * @param[out] iex1 Stop index for first sum. | |
| 1583 | + * @param[out] iex2 Start index for second sum. | |
| 1584 | + * @param[out] isel2 Stop index for second sum. | |
| 1585 | + * | |
| 1586 | + * This method is a helper method for the BGDLIXA background method. It | |
| 1587 | + * computes the Phibar index range for the third step of the background | |
| 1588 | + * model computation. The third step corresponds to Equation (3.14) in Rob | |
| 1589 | + * van Dijk's PhD thesis. | |
| 1590 | + * | |
| 1591 | + * The Phibar sum will be taken over the index ranges [isel1, iex1] and | |
| 1592 | + * [ixe2, isel2]. | |
| 1593 | + ***************************************************************************/ | |
| 1594 | +void GCOMObservation::get_bgdlixa_phibar_indices(const int& iphibar, | |
| 1595 | + const int& nincl, | |
| 1596 | + const int& nexcl, | |
| 1597 | + int* isel1, | |
| 1598 | + int* iex1, | |
| 1599 | + int* iex2, | |
| 1600 | + int* isel2) const | |
| 1601 | +{ | |
| 1602 | + // Get number of Phibar layers | |
| 1603 | + int nphibar = m_drg.nphibar(); | |
| 1604 | + int imax = nphibar - 1; | |
| 1605 | + | |
| 1606 | + // Precompute half running average lengths | |
| 1607 | + int nexcl2 = int(nexcl/2); | |
| 1608 | + int nincl2 = int(nincl/2); | |
| 1609 | + | |
| 1610 | + // Compute Phibar index range without respecting boundaries | |
| 1611 | + *iex1 = iphibar - nexcl2 - 1; | |
| 1612 | + *iex2 = iphibar + nexcl2 + 1; | |
| 1613 | + *isel1 = iphibar - nincl2; | |
| 1614 | + *isel2 = iphibar + nincl2; | |
| 1615 | + | |
| 1616 | + // If no Phibar layers are to be excluded then make sure that the | |
| 1617 | + // Phibar layer range is continuous | |
| 1618 | + if (nexcl == 0) { | |
| 1619 | + (*iex2)--; | |
| 1620 | + } | |
| 1621 | + | |
| 1622 | + // Make sure that start index of first sum and stop index of second | |
| 1623 | + // some are within the validity range | |
| 1624 | + if (*isel1 < 0) { | |
| 1625 | + *isel1 = 0; | |
| 1626 | + } | |
| 1627 | + if (*isel2 > imax) { | |
| 1628 | + *isel2 = imax; | |
| 1629 | + } | |
| 1630 | + | |
| 1631 | + // Make sure that the sums use always ncincl Phibar layers, also near | |
| 1632 | + // the edges | |
| 1633 | + if (*isel1 == 0) { | |
| 1634 | + *isel2 = nincl - 1; | |
| 1635 | + if (nincl > imax) { | |
| 1636 | + *isel2 = imax; | |
| 1637 | + } | |
| 1638 | + | |
| 1639 | + } | |
| 1640 | + if (*isel2 == imax) { | |
| 1641 | + *isel1 = nphibar - nincl; | |
| 1642 | + if (*isel1 < 0) { | |
| 1643 | + *isel1 = 0; | |
| 1644 | + } | |
| 1645 | + } | |
| 1646 | + | |
| 1647 | + // Return | |
| 1648 | + return; | |
| 1649 | +} | ... | ... |