Commit 302c8f9374e0991ba075dc0f716f9ed4e7df7b3a

Authored by Jürgen Knödlseder
2 parents d2abdb17 7d2423aa

Merge branch 'issue_1017' into issue_1017_jk

Conflicts:
	src/sky/GWcs.cpp
ChangeLog
... ... @@ -23,6 +23,7 @@
23 23 Put likelihood computation in GObservation class
24 24 Add broken power law spectral model
25 25 Add Gaussian spectral model
  26 + Implement exact sky map pixel solid angle computation
26 27 Rename the following classes:
27 28 - GWcs => GSkyProjection
28 29 - GWcslib => GWcs
... ...
1   -New Features and Important Changes in GammaLib 00-08-00
  1 +vNew Features and Important Changes in GammaLib 00-08-00
2 2  
3 3 Author(s) : Juergen Knoedlseder
4 4  
... ... @@ -560,7 +560,12 @@ The GSkyPixel class now supports 1D and 2D pixelisations, allowing
560 560 a more generic usage of the class. Integer and double precision
561 561 values can be assigned from and to GSkyPixel for 1D pixelisations.
562 562  
563   -The GWcsAIT class has been added for Aitoff-Hammer projections.
  563 +The GWcsAIT class has been added for Aitoff projections.
  564 +
  565 +The solid angle of sky map pixels are now computed using the spherical
  566 +excess. This provides accurate solid angles even in case that the
  567 +pixels are highly distorted, for example at the poles of the Aitoff
  568 +projections.
564 569  
565 570  
566 571 13. Support module
... ...
src/sky/GWcs.cpp
... ... @@ -56,6 +56,7 @@
56 56  
57 57 /* __ Coding definitions _________________________________________________ */
58 58 //#define G_LIN_MATINV_FORCE_PC // Force PC usage
  59 +#define G_USE_TRIGO_FOR_SOLIDANGLE // Use trigonometric functions
59 60  
60 61 /* __ Debug definitions __________________________________________________ */
61 62 //#define G_DIR2XY_DEBUG // Debug dir2xy
... ... @@ -425,7 +426,27 @@ void GWcs::write(GFitsHDU& hdu) const
425 426 *
426 427 * @param[in] pixel Pixel index (x,y)
427 428 *
428   -TODO:: UPDATE THIS DOCSTRING (+link to wikipedia)
  429 + * Estimates solid angles of pixels using the Girard equation for excess
  430 + * area - see: http://mathworld.wolfram.com/SphericalPolygon.html
  431 + *
  432 + *
  433 + * Below, the definiton of the pixel cornes and sides are shown as used
  434 + * within the code.
  435 + *
  436 + * a12
  437 + * 1---------2
  438 + * |\ /|
  439 + * | \a13 / |
  440 + * | \ / |
  441 + * | \ / |
  442 + * a14| X |a23
  443 + * | / \ |
  444 + * | / \ |
  445 + * | /a24 \ |
  446 + * |/ \|
  447 + * 4---------3
  448 + * a34
  449 + *
429 450 ***************************************************************************/
430 451 double GWcs::solidangle(const GSkyPixel& pixel) const
431 452 {
... ... @@ -435,47 +456,128 @@ double GWcs::solidangle(const GSkyPixel& pixel) const
435 456 GSkyDir dir3 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()+0.5));
436 457 GSkyDir dir4 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()+0.5));
437 458  
  459 + // Compile option 1: Use triginometric function
  460 + #if defined(G_USE_TRIGO_FOR_SOLIDANGLE)
  461 +
  462 + // Initialise solid angle
  463 + double solidangle = 0.0;
  464 +
438 465 // Compute angular distances between pixel corners
439 466 double a12 = dir1.dist(dir2);
440   - double a13 = dir1.dist(dir3);
441 467 double a14 = dir1.dist(dir4);
442 468 double a23 = dir2.dist(dir3);
443   - double a24 = dir2.dist(dir4);
444 469 double a34 = dir3.dist(dir4);
445 470  
446   - // Angle 1
447   - double a = a13;
448   - double b = a34;
449   - double c = a14;
450   - double angle1 = std::acos((std::cos(a) - std::cos(b)*std::cos(c))/(std::sin(b)*std::sin(c)));
451   -
452   - // Angle 2
453   - a = a24;
454   - b = a23;
455   - c = a34;
456   - double angle2 = std::acos((std::cos(a) - std::cos(b)*std::cos(c))/(std::sin(b)*std::sin(c)));
457   -
458   - // Angle 3
459   - a = a13;
460   - b = a12;
461   - c = a23;
462   - double angle3 = std::acos((std::cos(a) - std::cos(b)*std::cos(c))/(std::sin(b)*std::sin(c)));
463   -
464   - // Angle 4
465   - a = a24;
466   - b = a14;
467   - c = a12;
468   - double angle4 = std::acos((std::cos(a) - std::cos(b)*std::cos(c))/(std::sin(b)*std::sin(c)));
469   -
470   - /*
471   - std::cout << angle1 << " ";
472   - std::cout << angle2 << " ";
473   - std::cout << angle3 << " ";
474   - std::cout << angle4 << " " << std::endl;
475   - */
476   -
477   - // http://mathworld.wolfram.com/SphericalPolygon.html
478   - double solidangle = (angle1 + angle2 + angle3 + angle4) - (2.0 * gammalib::pi);
  471 + // Special case: a12 or a14 is zero, then pixel is a triangle composed
  472 + // of [2,3,4]
  473 + if (a12 <= 0.0 || a14 <= 0.0) {
  474 +
  475 + // Compute diagonals
  476 + double a24 = dir2.dist(dir4);
  477 +
  478 + // Compute sines
  479 + double sin_a23 = std::sin(a23);
  480 + double sin_a24 = std::sin(a24);
  481 + double sin_a34 = std::sin(a34);
  482 +
  483 + // Compute cosines
  484 + double cos_a23 = std::cos(a23);
  485 + double cos_a24 = std::cos(a24);
  486 + double cos_a34 = std::cos(a34);
  487 +
  488 + // Compute angles
  489 + double angle2 = std::acos((cos_a34-cos_a24*cos_a23)/(sin_a24*sin_a23));
  490 + double angle3 = std::acos((cos_a24-cos_a34*cos_a23)/(sin_a34*sin_a23));
  491 + double angle4 = std::acos((cos_a23-cos_a24*cos_a34)/(sin_a24*sin_a34));
  492 +
  493 + // Compute excess area to determine solid angle
  494 + solidangle = (angle2 + angle3 + angle4) - gammalib::pi;
  495 +
  496 + }
  497 +
  498 + // Special case: a23 or a 34 is zero, then pixel is a triangle composed
  499 + // of [1,2,4]
  500 + else if (a23 <= 0.0 || a34 <= 0.0) {
  501 +
  502 + // Compute diagonals
  503 + double a24 = dir2.dist(dir4);
  504 +
  505 + // Compute sines
  506 + double sin_a12 = std::sin(a12);
  507 + double sin_a14 = std::sin(a14);
  508 + double sin_a24 = std::sin(a24);
  509 +
  510 + // Compute cosines
  511 + double cos_a12 = std::cos(a12);
  512 + double cos_a14 = std::cos(a14);
  513 + double cos_a24 = std::cos(a24);
  514 +
  515 + // Compute angles
  516 + double angle1 = std::acos((cos_a24-cos_a12*cos_a14)/(sin_a12*sin_a14));
  517 + double angle2 = std::acos((cos_a14-cos_a12*cos_a24)/(sin_a12*sin_a24));
  518 + double angle4 = std::acos((cos_a12-cos_a14*cos_a24)/(sin_a14*sin_a24));
  519 +
  520 + // Compute excess area to determine solid angle
  521 + solidangle = (angle1 + angle2 + angle4) - gammalib::pi;
  522 +
  523 + }
  524 +
  525 + // Otherwise we have a polygon
  526 + else {
  527 +
  528 + // Compute diagonals
  529 + double a13 = dir1.dist(dir3);
  530 + double a24 = dir2.dist(dir4);
  531 +
  532 + // Compute sines
  533 + double sin_a12 = std::sin(a12);
  534 + double sin_a14 = std::sin(a14);
  535 + double sin_a23 = std::sin(a23);
  536 + double sin_a34 = std::sin(a34);
  537 +
  538 + // Compute cosines
  539 + double cos_a12 = std::cos(a12);
  540 + double cos_a13 = std::cos(a13);
  541 + double cos_a14 = std::cos(a14);
  542 + double cos_a23 = std::cos(a23);
  543 + double cos_a24 = std::cos(a24);
  544 + double cos_a34 = std::cos(a34);
  545 +
  546 + // Compute angles
  547 + double angle1 = std::acos((cos_a13-cos_a34*cos_a14)/(sin_a34*sin_a14));
  548 + double angle2 = std::acos((cos_a24-cos_a23*cos_a34)/(sin_a23*sin_a34));
  549 + double angle3 = std::acos((cos_a13-cos_a12*cos_a23)/(sin_a12*sin_a23));
  550 + double angle4 = std::acos((cos_a24-cos_a14*cos_a12)/(sin_a14*sin_a12));
  551 +
  552 + // Use Girard equation for excess area to determine solid angle
  553 + solidangle = (angle1 + angle2 + angle3 + angle4) - gammalib::twopi;
  554 +
  555 + } // endif: we had a polynom
  556 +
  557 + // Compile option 2: Use vectors
  558 + #else
  559 +
  560 + // Get vectors to pixel corners
  561 + GVector vec1 = dir1.celvector();
  562 + GVector vec2 = dir2.celvector();
  563 + GVector vec3 = dir3.celvector();
  564 + GVector vec4 = dir4.celvector();
  565 +
  566 + // Compute inner angles of pixel corners
  567 + double angle1 = gammalib::acos(cross(vec2, (cross(vec1, vec2))) *
  568 + cross(vec2, (cross(vec3, vec2))));
  569 + double angle2 = gammalib::acos(cross(vec3, (cross(vec2, vec3))) *
  570 + cross(vec3, (cross(vec4, vec3))));
  571 + double angle3 = gammalib::acos(cross(vec4, (cross(vec3, vec4))) *
  572 + cross(vec4, (cross(vec1, vec4))));
  573 + double angle4 = gammalib::acos(cross(vec1, (cross(vec4, vec1))) *
  574 + cross(vec1, (cross(vec2, vec1))));
  575 +
  576 + // Use Girard equation for excess area to determine solid angle
  577 + double solidangle = gammalib::deg2rad * gammalib::deg2rad +
  578 + (angle1 + angle2 + angle3 + angle4) -
  579 + gammalib::twopi;
  580 + #endif
479 581  
480 582 // Return solid angle
481 583 return solidangle;
... ...