Commit 6e9d8a89bf29b084dc464feb792f8ef4bb0f548a
1 parent
5b6ed6bf
Add flux() methods.
The flux() methods return the correct flux in a pixel considering that a bilinear interpolation is performed in the map. Flux is defined as intensity times solid angle. This works so far only properly for WCS projections. For HealPix maps, only the pixel intensity times the solid angle is returned.
Showing
3 changed files
with
208 additions
and
7 deletions
include/GSkymap.hpp
| ... | ... | @@ -133,6 +133,8 @@ public: |
| 133 | 133 | int pix2inx(const GSkyPixel& pixel) const; |
| 134 | 134 | int dir2inx(const GSkyDir& dir) const; |
| 135 | 135 | GSkyPixel dir2pix(const GSkyDir& dir) const; |
| 136 | + double flux(const int& index, const int& map = 0) const; | |
| 137 | + double flux(const GSkyPixel& pixel, const int& map = 0) const; | |
| 136 | 138 | double solidangle(const int& index) const; |
| 137 | 139 | double solidangle(const GSkyPixel& pixel) const; |
| 138 | 140 | bool contains(const GSkyDir& dir) const; |
| ... | ... | @@ -164,6 +166,8 @@ private: |
| 164 | 166 | void alloc_wcs(const GFitsImage& image); |
| 165 | 167 | GFitsBinTable* create_healpix_hdu(void) const; |
| 166 | 168 | GFitsImageDouble* create_wcs_hdu(void) const; |
| 169 | + double solidangle(const GSkyDir& dir1, const GSkyDir& dir2, | |
| 170 | + const GSkyDir& dir3, const GSkyDir& dir4) const; | |
| 167 | 171 | |
| 168 | 172 | // Private data area |
| 169 | 173 | int m_num_pixels; //!< Number of pixels (used for pixel allocation) | ... | ... |
pyext/GSkymap.i
| ... | ... | @@ -128,12 +128,15 @@ public: |
| 128 | 128 | virtual ~GSkymap(void); |
| 129 | 129 | |
| 130 | 130 | // Operators |
| 131 | - GSkymap& operator+=(const GSkymap& map); | |
| 132 | - GSkymap& operator+=(const double& value); | |
| 133 | - GSkymap& operator-=(const GSkymap& map); | |
| 134 | - GSkymap& operator-=(const double& value); | |
| 135 | - GSkymap& operator*=(const GSkymap& map); | |
| 136 | - GSkymap& operator*=(const double& factor); | |
| 131 | + GSkymap& operator+=(const GSkymap& map); | |
| 132 | + GSkymap& operator+=(const double& value); | |
| 133 | + GSkymap& operator-=(const GSkymap& map); | |
| 134 | + GSkymap& operator-=(const double& value); | |
| 135 | + GSkymap& operator*=(const GSkymap& map); | |
| 136 | + GSkymap& operator*=(const double& factor); | |
| 137 | + double& operator()(const int& index, const int& map = 0); | |
| 138 | + double& operator()(const GSkyPixel& pixel, const int& map = 0); | |
| 139 | + double operator()(const GSkyDir& dir, const int& map = 0) const; | |
| 137 | 140 | |
| 138 | 141 | // Methods |
| 139 | 142 | void clear(void); |
| ... | ... | @@ -150,6 +153,8 @@ public: |
| 150 | 153 | int pix2inx(const GSkyPixel& pixel) const; |
| 151 | 154 | int dir2inx(const GSkyDir& dir) const; |
| 152 | 155 | GSkyPixel dir2pix(const GSkyDir& dir) const; |
| 156 | + double flux(const int& index, const int& map = 0) const; | |
| 157 | + double flux(const GSkyPixel& pixel, const int& map = 0) const; | |
| 153 | 158 | double solidangle(const int& index) const; |
| 154 | 159 | double solidangle(const GSkyPixel& pixel) const; |
| 155 | 160 | bool contains(const GSkyDir& dir) const; | ... | ... |
src/sky/GSkymap.cpp
| ... | ... | @@ -56,6 +56,8 @@ |
| 56 | 56 | #define G_PIX2DIR "GSkymap::pix2dir(GSkyPixel&)" |
| 57 | 57 | #define G_DIR2INX "GSkymap::dir2inx(GSkyDir&)" |
| 58 | 58 | #define G_DIR2PIX "GSkymap::dir2pix(GSkyDir&)" |
| 59 | +#define G_FLUX1 "GSkymap::flux(int&)" | |
| 60 | +#define G_FLUX2 "GSkymap::flux(GSkyPixel&)" | |
| 59 | 61 | #define G_SOLIDANGLE1 "GSkymap::solidangle(int&)" |
| 60 | 62 | #define G_SOLIDANGLE2 "GSkymap::solidangle(GSkyPixel&)" |
| 61 | 63 | #define G_EXTRACT "GSkymap::extract(int&, int&)" |
| ... | ... | @@ -1207,6 +1209,106 @@ GSkyPixel GSkymap::dir2pix(const GSkyDir& dir) const |
| 1207 | 1209 | |
| 1208 | 1210 | |
| 1209 | 1211 | /***********************************************************************//** |
| 1212 | + * @brief Returns flux in pixel | |
| 1213 | + * | |
| 1214 | + * @param[in] index Pixel index [0,...,npix()-1]. | |
| 1215 | + * @param[in] map Map index [0,...,nmaps()-1]. | |
| 1216 | + * @return Flux in pixel. | |
| 1217 | + * | |
| 1218 | + * @exception GException::invalid_value | |
| 1219 | + * No valid sky projection found. | |
| 1220 | + * | |
| 1221 | + * Returns the flux in the pixel with the specified @p index. | |
| 1222 | + ***************************************************************************/ | |
| 1223 | +double GSkymap::flux(const int& index, const int& map) const | |
| 1224 | +{ | |
| 1225 | + // Throw error if WCS is not valid | |
| 1226 | + if (m_proj == NULL) { | |
| 1227 | + std::string msg = "Sky projection has not been defined."; | |
| 1228 | + throw GException::invalid_value(G_FLUX1, msg); | |
| 1229 | + } | |
| 1230 | + | |
| 1231 | + // Determine flux from pixel index. | |
| 1232 | + double flux = this->flux(inx2pix(index), map); | |
| 1233 | + | |
| 1234 | + // Return flux | |
| 1235 | + return flux; | |
| 1236 | +} | |
| 1237 | + | |
| 1238 | + | |
| 1239 | +/***********************************************************************//** | |
| 1240 | + * @brief Returns flux in pixel | |
| 1241 | + * | |
| 1242 | + * @param[in] pixel Sky map pixel. | |
| 1243 | + * @param[in] map Map index [0,...,nmaps()-1]. | |
| 1244 | + * @return Flux in pixel. | |
| 1245 | + * | |
| 1246 | + * @exception GException::invalid_value | |
| 1247 | + * No valid sky projection found. | |
| 1248 | + * | |
| 1249 | + * Returns the flux in the specified sky map @p pixel. | |
| 1250 | + * | |
| 1251 | + * @todo Implement flux computation for HealPix map. | |
| 1252 | + ***************************************************************************/ | |
| 1253 | +double GSkymap::flux(const GSkyPixel& pixel, const int& map) const | |
| 1254 | +{ | |
| 1255 | + // Throw error if WCS is not valid | |
| 1256 | + if (m_proj == NULL) { | |
| 1257 | + std::string msg = "Sky projection has not been defined."; | |
| 1258 | + throw GException::invalid_value(G_FLUX2, msg); | |
| 1259 | + } | |
| 1260 | + | |
| 1261 | + // Initialise flux | |
| 1262 | + double flux = 0.0; | |
| 1263 | + | |
| 1264 | + // Perform flux computation for HealPix map | |
| 1265 | + if (m_proj->size() == 1) { | |
| 1266 | + | |
| 1267 | + // This does a simple flux computation that is using just the pixel | |
| 1268 | + // centre. This is incorrect for interpolated maps. | |
| 1269 | + // TODO: Implement flux computation that takes care of interpolated | |
| 1270 | + // maps | |
| 1271 | + flux = this->operator()(pixel, map) * solidangle(pixel); | |
| 1272 | + | |
| 1273 | + } // endif: we had a HealPix map | |
| 1274 | + | |
| 1275 | + // ... otherwise perform flux computation for WCS map | |
| 1276 | + else { | |
| 1277 | + | |
| 1278 | + // Compute flux | |
| 1279 | + flux = this->operator()(pix2dir(GSkyPixel(pixel.x()-0.25, | |
| 1280 | + pixel.y()-0.25)), map) * | |
| 1281 | + solidangle(pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()-0.5)), | |
| 1282 | + pix2dir(GSkyPixel(pixel.x(), pixel.y()-0.5)), | |
| 1283 | + pix2dir(GSkyPixel(pixel.x(), pixel.y())), | |
| 1284 | + pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()))) + | |
| 1285 | + this->operator()(pix2dir(GSkyPixel(pixel.x()+0.25, | |
| 1286 | + pixel.y()-0.25)), map) * | |
| 1287 | + solidangle(pix2dir(GSkyPixel(pixel.x(), pixel.y()-0.5)), | |
| 1288 | + pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()-0.5)), | |
| 1289 | + pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y())), | |
| 1290 | + pix2dir(GSkyPixel(pixel.x(), pixel.y()))) + | |
| 1291 | + this->operator()(pix2dir(GSkyPixel(pixel.x()+0.25, | |
| 1292 | + pixel.y()+0.25)), map) * | |
| 1293 | + solidangle(pix2dir(GSkyPixel(pixel.x(), pixel.y())), | |
| 1294 | + pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y())), | |
| 1295 | + pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()+0.5)), | |
| 1296 | + pix2dir(GSkyPixel(pixel.x(), pixel.y()+0.5))) + | |
| 1297 | + this->operator()(pix2dir(GSkyPixel(pixel.x()-0.25, | |
| 1298 | + pixel.y()+0.25)), map) * | |
| 1299 | + solidangle(pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y())), | |
| 1300 | + pix2dir(GSkyPixel(pixel.x(), pixel.y())), | |
| 1301 | + pix2dir(GSkyPixel(pixel.x(), pixel.y()+0.5)), | |
| 1302 | + pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()+0.5))); | |
| 1303 | + | |
| 1304 | + } // endelse: we had a WCS map | |
| 1305 | + | |
| 1306 | + // Return flux | |
| 1307 | + return flux; | |
| 1308 | +} | |
| 1309 | + | |
| 1310 | + | |
| 1311 | +/***********************************************************************//** | |
| 1210 | 1312 | * @brief Returns solid angle of pixel |
| 1211 | 1313 | * |
| 1212 | 1314 | * @param[in] index Pixel index [0,...,npix()-1]. |
| ... | ... | @@ -1226,7 +1328,7 @@ double GSkymap::solidangle(const int& index) const |
| 1226 | 1328 | } |
| 1227 | 1329 | |
| 1228 | 1330 | // Determine solid angle from pixel index. |
| 1229 | - double solidangle = m_proj->solidangle(inx2pix(index)); | |
| 1331 | + double solidangle = this->solidangle(inx2pix(index)); | |
| 1230 | 1332 | |
| 1231 | 1333 | // Return solid angle |
| 1232 | 1334 | return solidangle; |
| ... | ... | @@ -2262,6 +2364,96 @@ GFitsImageDouble* GSkymap::create_wcs_hdu(void) const |
| 2262 | 2364 | } |
| 2263 | 2365 | |
| 2264 | 2366 | |
| 2367 | +/***********************************************************************//** | |
| 2368 | + * @brief Compute solid angle subtended by 4 sky directions | |
| 2369 | + * | |
| 2370 | + * @param[in] dir1 First sky direction. | |
| 2371 | + * @param[in] dir2 Second sky direction. | |
| 2372 | + * @param[in] dir3 Third sky direction. | |
| 2373 | + * @param[in] dir4 Forth sky direction. | |
| 2374 | + * @return Solid angle (steradians). | |
| 2375 | + * | |
| 2376 | + * Estimate the solid angle subtended by 4 sky directions using Huilier's | |
| 2377 | + * theroem. | |
| 2378 | + * | |
| 2379 | + * Below, the definiton of the pixel cornes and sides are shown as used | |
| 2380 | + * within the code. | |
| 2381 | + * | |
| 2382 | + * a12 | |
| 2383 | + * 1---------2 | |
| 2384 | + * |\ /| | |
| 2385 | + * | \a13 / | | |
| 2386 | + * | \ / | | |
| 2387 | + * | \ / | | |
| 2388 | + * a14| X |a23 | |
| 2389 | + * | / \ | | |
| 2390 | + * | / \ | | |
| 2391 | + * | /a24 \ | | |
| 2392 | + * |/ \| | |
| 2393 | + * 4---------3 | |
| 2394 | + * a34 | |
| 2395 | + * | |
| 2396 | + ***************************************************************************/ | |
| 2397 | +double GSkymap::solidangle(const GSkyDir& dir1, const GSkyDir& dir2, | |
| 2398 | + const GSkyDir& dir3, const GSkyDir& dir4) const | |
| 2399 | +{ | |
| 2400 | + // Initialise solid angle | |
| 2401 | + double solidangle = 0.0; | |
| 2402 | + | |
| 2403 | + // Compute angular distances between pixel corners | |
| 2404 | + double a12 = dir1.dist(dir2); | |
| 2405 | + double a14 = dir1.dist(dir4); | |
| 2406 | + double a23 = dir2.dist(dir3); | |
| 2407 | + double a24 = dir2.dist(dir4); | |
| 2408 | + double a34 = dir3.dist(dir4); | |
| 2409 | + | |
| 2410 | + // Special case: a12 or a14 is zero, then pixel is a triangle composed | |
| 2411 | + // of [2,3,4] | |
| 2412 | + if (a12 <= 0.0 || a14 <= 0.0) { | |
| 2413 | + double s = 0.5 * (a23 + a34 + a24); | |
| 2414 | + solidangle = 4.0 * std::atan(std::sqrt(std::tan(0.5*s) * | |
| 2415 | + std::tan(0.5*(s-a23)) * | |
| 2416 | + std::tan(0.5*(s-a34)) * | |
| 2417 | + std::tan(0.5*(s-a24)))); | |
| 2418 | + } | |
| 2419 | + | |
| 2420 | + // Special case: a23 or a 34 is zero, then pixel is a triangle composed | |
| 2421 | + // of [1,2,4] | |
| 2422 | + else if (a23 <= 0.0 || a34 <= 0.0) { | |
| 2423 | + double s = 0.5 * (a12 + a24 + a14); | |
| 2424 | + solidangle = 4.0 * std::atan(std::sqrt(std::tan(0.5*s) * | |
| 2425 | + std::tan(0.5*(s-a12)) * | |
| 2426 | + std::tan(0.5*(s-a24)) * | |
| 2427 | + std::tan(0.5*(s-a14)))); | |
| 2428 | + } | |
| 2429 | + | |
| 2430 | + // Otherwise we have a polygon | |
| 2431 | + else { | |
| 2432 | + | |
| 2433 | + // Triangle 1 [1,2,4] | |
| 2434 | + double s1 = 0.5 * (a12 + a24 + a14); | |
| 2435 | + double excess1 = std::atan(std::sqrt(std::tan(0.5*s1) * | |
| 2436 | + std::tan(0.5*(s1-a12)) * | |
| 2437 | + std::tan(0.5*(s1-a24)) * | |
| 2438 | + std::tan(0.5*(s1-a14)))); | |
| 2439 | + | |
| 2440 | + // Triangle 2 [2,3,4] | |
| 2441 | + double s2 = 0.5 * (a23 + a34 + a24); | |
| 2442 | + double excess2 = std::atan(std::sqrt(std::tan(0.5*s2) * | |
| 2443 | + std::tan(0.5*(s2-a23)) * | |
| 2444 | + std::tan(0.5*(s2-a34)) * | |
| 2445 | + std::tan(0.5*(s2-a24)))); | |
| 2446 | + | |
| 2447 | + // Determine solid angle | |
| 2448 | + solidangle = 4.0 * (excess1 + excess2); | |
| 2449 | + | |
| 2450 | + } // endif: we had a polynom | |
| 2451 | + | |
| 2452 | + // Return solid angle | |
| 2453 | + return solidangle; | |
| 2454 | +} | |
| 2455 | + | |
| 2456 | + | |
| 2265 | 2457 | /*========================================================================== |
| 2266 | 2458 | = = |
| 2267 | 2459 | = Friends = | ... | ... |