Commit 69a208a2a73af0909bd4c162cca48f3bf252559b
1 parent
91bf6a00
Implement 8-wedge integration formula for WCS pixels
Showing
1 changed file
with
90 additions
and
56 deletions
src/sky/GSkymap.cpp
| ... | ... | @@ -29,6 +29,7 @@ |
| 29 | 29 | #include <config.h> |
| 30 | 30 | #endif |
| 31 | 31 | #include "GException.hpp" |
| 32 | +#include "GMath.hpp" | |
| 32 | 33 | #include "GTools.hpp" |
| 33 | 34 | #include "GSkymap.hpp" |
| 34 | 35 | #include "GHealpix.hpp" |
| ... | ... | @@ -851,13 +852,26 @@ double GSkymap::operator()(const GSkyDir& dir, const int& map) const |
| 851 | 852 | double x_size = std::abs(m_num_x * static_cast<GWcs*>(m_proj)->cdelt(0)); |
| 852 | 853 | bool x_wrap = (x_size > 359.99); |
| 853 | 854 | |
| 855 | + // Get pixel index that is to the left-top of the actual | |
| 856 | + // pixel. We take care of the special case of negative pixel | |
| 857 | + // indices which arise if we are in the first column or | |
| 858 | + // first row of the map. | |
| 859 | + int inx_x = int(pixel.x()); | |
| 860 | + int inx_y = int(pixel.y()); | |
| 861 | + if (pixel.x() < 0.0) { | |
| 862 | + inx_x--; | |
| 863 | + } | |
| 864 | + if (pixel.y() < 0.0) { | |
| 865 | + inx_y--; | |
| 866 | + } | |
| 867 | + | |
| 854 | 868 | // Set left and right indices for interpolation. The left |
| 855 | - // index needs to non-negative and the right index needs | |
| 869 | + // index needs to be non-negative and the right index needs | |
| 856 | 870 | // to be not larger that the number of pixels. We treat |
| 857 | 871 | // here also the special case of wrap around in the x |
| 858 | 872 | // axis that may occur if we have an allsky map. |
| 859 | - int inx_x_left = int(pixel.x()); | |
| 860 | - int inx_y_left = int(pixel.y()); | |
| 873 | + int inx_x_left = inx_x; | |
| 874 | + int inx_y_left = inx_y; | |
| 861 | 875 | int inx_x_right = inx_x_left + 1; |
| 862 | 876 | int inx_y_right = inx_y_left + 1; |
| 863 | 877 | if (inx_x_left < 0) { |
| ... | ... | @@ -865,7 +879,7 @@ double GSkymap::operator()(const GSkyDir& dir, const int& map) const |
| 865 | 879 | inx_x_left += m_num_x; |
| 866 | 880 | } |
| 867 | 881 | else { |
| 868 | - inx_x_left = 0; | |
| 882 | + inx_x_left = 0; | |
| 869 | 883 | } |
| 870 | 884 | } |
| 871 | 885 | if (inx_x_right >= m_num_x) { |
| ... | ... | @@ -877,16 +891,16 @@ double GSkymap::operator()(const GSkyDir& dir, const int& map) const |
| 877 | 891 | } |
| 878 | 892 | } |
| 879 | 893 | if (inx_y_left < 0) { |
| 880 | - inx_y_left = 0; | |
| 894 | + inx_y_left = 0; | |
| 881 | 895 | } |
| 882 | 896 | if (inx_y_right >= m_num_y) { |
| 883 | 897 | inx_y_right = m_num_y - 1; |
| 884 | 898 | } |
| 885 | 899 | |
| 886 | 900 | // Set weighting factors for interpolation |
| 887 | - double wgt_x_right = (pixel.x() - int(pixel.x())); | |
| 901 | + double wgt_x_right = (pixel.x() - inx_x); | |
| 888 | 902 | double wgt_x_left = 1.0 - wgt_x_right; |
| 889 | - double wgt_y_right = (pixel.y() - int(pixel.y())); | |
| 903 | + double wgt_y_right = (pixel.y() - inx_y); | |
| 890 | 904 | double wgt_y_left = 1.0 - wgt_y_right; |
| 891 | 905 | |
| 892 | 906 | // Compute skymap pixel indices for bi-linear interpolation |
| ... | ... | @@ -1266,15 +1280,14 @@ double GSkymap::flux(const int& index, const int& map) const |
| 1266 | 1280 | * |
| 1267 | 1281 | * Returns the flux in the specified sky map @p pixel. The flux is computed |
| 1268 | 1282 | * by integrating the intensity over the solid angle subtended by the pixel. |
| 1283 | + * Integration is done by dividing the pixel into wedges, computing the | |
| 1284 | + * intensitites at the cornes of each wedge, averaging these intensities, | |
| 1285 | + * and multiplying it with the solid angle of each wedge. This provides an | |
| 1286 | + * approximation of the true pixel flux which is accurate to better than | |
| 1287 | + * about 5%. | |
| 1269 | 1288 | * |
| 1270 | - * For a HealPix pixelisation, the pixel is divided into 12 wedges and the | |
| 1271 | - * flux is integrated in each wedge by computing the average of the corner | |
| 1272 | - * intensities multiplied by the solid angle of the wedge. This leads to a | |
| 1273 | - * precision of the order of 1-3% in the flux computation. | |
| 1274 | - * | |
| 1275 | - * For a WCS pixelisation, the pixel is divided into 4 quadrants and the flux | |
| 1276 | - * is computed in each quandrant by multiplying the intensity in the centre | |
| 1277 | - * of the quadrant with the solid angle of the quadrant. | |
| 1289 | + * For a HealPix pixelisation, the pixel is divided into 12 wedges. For a | |
| 1290 | + * WCS pixelisation, the pixel is divided into 8 wedges. | |
| 1278 | 1291 | ***************************************************************************/ |
| 1279 | 1292 | double GSkymap::flux(const GSkyPixel& pixel, const int& map) const |
| 1280 | 1293 | { |
| ... | ... | @@ -1319,29 +1332,29 @@ double GSkymap::flux(const GSkyPixel& pixel, const int& map) const |
| 1319 | 1332 | double i12 = this->operator()(boundaries[11]); |
| 1320 | 1333 | |
| 1321 | 1334 | // Compute fluxes in wedges |
| 1322 | - double flux1 = (i0 + i1 + i2) / 3.0 * | |
| 1335 | + double flux1 = gammalib::onethird * (i0 + i1 + i2) * | |
| 1323 | 1336 | solidangle(centre, boundaries[0], boundaries[4]); |
| 1324 | - double flux2 = (i0 + i2 + i3) / 3.0 * | |
| 1337 | + double flux2 = gammalib::onethird * (i0 + i2 + i3) * | |
| 1325 | 1338 | solidangle(centre, boundaries[4], boundaries[8]); |
| 1326 | - double flux3 = (i0 + i3 + i4) / 3.0 * | |
| 1339 | + double flux3 = gammalib::onethird * (i0 + i3 + i4) * | |
| 1327 | 1340 | solidangle(centre, boundaries[8], boundaries[1]); |
| 1328 | - double flux4 = (i0 + i4 + i5) / 3.0 * | |
| 1341 | + double flux4 = gammalib::onethird * (i0 + i4 + i5) * | |
| 1329 | 1342 | solidangle(centre, boundaries[1], boundaries[5]); |
| 1330 | - double flux5 = (i0 + i5 + i6) / 3.0 * | |
| 1343 | + double flux5 = gammalib::onethird * (i0 + i5 + i6) * | |
| 1331 | 1344 | solidangle(centre, boundaries[5], boundaries[9]); |
| 1332 | - double flux6 = (i0 + i6 + i7) / 3.0 * | |
| 1345 | + double flux6 = gammalib::onethird * (i0 + i6 + i7) * | |
| 1333 | 1346 | solidangle(centre, boundaries[9], boundaries[2]); |
| 1334 | - double flux7 = (i0 + i7 + i8) / 3.0 * | |
| 1347 | + double flux7 = gammalib::onethird * (i0 + i7 + i8) * | |
| 1335 | 1348 | solidangle(centre, boundaries[2], boundaries[6]); |
| 1336 | - double flux8 = (i0 + i8 + i9) / 3.0 * | |
| 1349 | + double flux8 = gammalib::onethird * (i0 + i8 + i9) * | |
| 1337 | 1350 | solidangle(centre, boundaries[6], boundaries[10]); |
| 1338 | - double flux9 = (i0 + i9 + i10) / 3.0 * | |
| 1351 | + double flux9 = gammalib::onethird * (i0 + i9 + i10) * | |
| 1339 | 1352 | solidangle(centre, boundaries[10], boundaries[3]); |
| 1340 | - double flux10 = (i0 + i10 + i11) / 3.0 * | |
| 1353 | + double flux10 = gammalib::onethird * (i0 + i10 + i11) * | |
| 1341 | 1354 | solidangle(centre, boundaries[3], boundaries[7]); |
| 1342 | - double flux11 = (i0 + i11 + i12) / 3.0 * | |
| 1355 | + double flux11 = gammalib::onethird * (i0 + i11 + i12) * | |
| 1343 | 1356 | solidangle(centre, boundaries[7], boundaries[11]); |
| 1344 | - double flux12 = (i0 + i12 + i1) / 3.0 * | |
| 1357 | + double flux12 = gammalib::onethird * (i0 + i12 + i1) * | |
| 1345 | 1358 | solidangle(centre, boundaries[11], boundaries[0]); |
| 1346 | 1359 | |
| 1347 | 1360 | // Sum up fluxes |
| ... | ... | @@ -1352,36 +1365,57 @@ double GSkymap::flux(const GSkyPixel& pixel, const int& map) const |
| 1352 | 1365 | } // endif: we had a HealPix map |
| 1353 | 1366 | |
| 1354 | 1367 | // ... otherwise perform flux computation for WCS map. The pixel is |
| 1355 | - // divided into 4 quadrants and the flux is computed in each quandrant | |
| 1356 | - // by multiplying the intensity in the centre of the quadrant with the | |
| 1357 | - // solid angle of the quadrant. | |
| 1368 | + // divided into 8 wedges and the flux is integrated in each wedge by | |
| 1369 | + // computing the average of the corner intensities multiplied by the | |
| 1370 | + // solid angle of the wedge. This leads to a precision of the order | |
| 1371 | + // of <1% in the flux computation. | |
| 1358 | 1372 | else { |
| 1359 | 1373 | |
| 1360 | - // Compute flux | |
| 1361 | - flux = this->operator()(pix2dir(GSkyPixel(pixel.x()-0.25, | |
| 1362 | - pixel.y()-0.25)), map) * | |
| 1363 | - solidangle(pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()-0.5)), | |
| 1364 | - pix2dir(GSkyPixel(pixel.x(), pixel.y()-0.5)), | |
| 1365 | - pix2dir(GSkyPixel(pixel.x(), pixel.y())), | |
| 1366 | - pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()))) + | |
| 1367 | - this->operator()(pix2dir(GSkyPixel(pixel.x()+0.25, | |
| 1368 | - pixel.y()-0.25)), map) * | |
| 1369 | - solidangle(pix2dir(GSkyPixel(pixel.x(), pixel.y()-0.5)), | |
| 1370 | - pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()-0.5)), | |
| 1371 | - pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y())), | |
| 1372 | - pix2dir(GSkyPixel(pixel.x(), pixel.y()))) + | |
| 1373 | - this->operator()(pix2dir(GSkyPixel(pixel.x()+0.25, | |
| 1374 | - pixel.y()+0.25)), map) * | |
| 1375 | - solidangle(pix2dir(GSkyPixel(pixel.x(), pixel.y())), | |
| 1376 | - pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y())), | |
| 1377 | - pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()+0.5)), | |
| 1378 | - pix2dir(GSkyPixel(pixel.x(), pixel.y()+0.5))) + | |
| 1379 | - this->operator()(pix2dir(GSkyPixel(pixel.x()-0.25, | |
| 1380 | - pixel.y()+0.25)), map) * | |
| 1381 | - solidangle(pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y())), | |
| 1382 | - pix2dir(GSkyPixel(pixel.x(), pixel.y())), | |
| 1383 | - pix2dir(GSkyPixel(pixel.x(), pixel.y()+0.5)), | |
| 1384 | - pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()+0.5))); | |
| 1374 | + // Get centre | |
| 1375 | + GSkyDir centre = pix2dir(pixel); | |
| 1376 | + | |
| 1377 | + // Get boundaries | |
| 1378 | + GSkyDir boundary1 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()-0.5)); | |
| 1379 | + GSkyDir boundary2 = pix2dir(GSkyPixel(pixel.x(), pixel.y()-0.5)); | |
| 1380 | + GSkyDir boundary3 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()-0.5)); | |
| 1381 | + GSkyDir boundary4 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y())); | |
| 1382 | + GSkyDir boundary5 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()+0.5)); | |
| 1383 | + GSkyDir boundary6 = pix2dir(GSkyPixel(pixel.x(), pixel.y()+0.5)); | |
| 1384 | + GSkyDir boundary7 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()+0.5)); | |
| 1385 | + GSkyDir boundary8 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y())); | |
| 1386 | + | |
| 1387 | + // Compute intensities | |
| 1388 | + double i0 = this->operator()(centre); | |
| 1389 | + double i1 = this->operator()(boundary1); | |
| 1390 | + double i2 = this->operator()(boundary2); | |
| 1391 | + double i3 = this->operator()(boundary3); | |
| 1392 | + double i4 = this->operator()(boundary4); | |
| 1393 | + double i5 = this->operator()(boundary5); | |
| 1394 | + double i6 = this->operator()(boundary6); | |
| 1395 | + double i7 = this->operator()(boundary7); | |
| 1396 | + double i8 = this->operator()(boundary8); | |
| 1397 | + | |
| 1398 | + // Compute fluxes | |
| 1399 | + double flux1 = gammalib::onethird * (i1 + i2 + i0) * | |
| 1400 | + solidangle(boundary1, boundary2, centre); | |
| 1401 | + double flux2 = gammalib::onethird * (i2 + i3 + i0) * | |
| 1402 | + solidangle(boundary2, boundary3, centre); | |
| 1403 | + double flux3 = gammalib::onethird * (i3 + i4 + i0) * | |
| 1404 | + solidangle(boundary3, boundary4, centre); | |
| 1405 | + double flux4 = gammalib::onethird * (i4 + i5 + i0) * | |
| 1406 | + solidangle(boundary4, boundary5, centre); | |
| 1407 | + double flux5 = gammalib::onethird * (i5 + i6 + i0) * | |
| 1408 | + solidangle(boundary5, boundary6, centre); | |
| 1409 | + double flux6 = gammalib::onethird * (i6 + i7 + i0) * | |
| 1410 | + solidangle(boundary6, boundary7, centre); | |
| 1411 | + double flux7 = gammalib::onethird * (i7 + i8 + i0) * | |
| 1412 | + solidangle(boundary7, boundary8, centre); | |
| 1413 | + double flux8 = gammalib::onethird * (i8 + i1 + i0) * | |
| 1414 | + solidangle(boundary8, boundary1, centre); | |
| 1415 | + | |
| 1416 | + // Sum up fluxes | |
| 1417 | + flux = (flux1 + flux2 + flux3 + flux4 + | |
| 1418 | + flux5 + flux6 + flux7 + flux8); | |
| 1385 | 1419 | |
| 1386 | 1420 | } // endelse: we had a WCS map |
| 1387 | 1421 | |
| ... | ... | @@ -2602,7 +2636,7 @@ double GSkymap::solidangle(const GSkyDir& dir1, const GSkyDir& dir2, |
| 2602 | 2636 | std::tan(0.5*(s-a12)) * |
| 2603 | 2637 | std::tan(0.5*(s-a23)) * |
| 2604 | 2638 | std::tan(0.5*(s-a13)))); |
| 2605 | - | |
| 2639 | + | |
| 2606 | 2640 | // Return solid angle |
| 2607 | 2641 | return solidangle; |
| 2608 | 2642 | } | ... | ... |