Commit 6e9d8a89bf29b084dc464feb792f8ef4bb0f548a

Authored by Jürgen Knödlseder
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.
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&amp; 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&amp; 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 =
... ...