Commit f7d12c2c2d5607ca5b3aa92b5254e8400f441af9

Authored by Jürgen Knödlseder
1 parent 65300dd7

Use Huilier's theorem to compute the spherical excess in the solidangle() method.

The former trigonometric method led to different results on different platforms due to numerical imprecisions. We now use Huilier's theorem to be less sensitive to numerical problems. The polygon is decomposed in two triangles for this purpose.
Showing 1 changed file with 78 additions and 9 deletions
src/sky/GWcs.cpp
... ... @@ -56,7 +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 +#define G_SOLIDANGLE_OPTION 2 // 1=sin/cos, 2=tan, 3=vectors
60 60  
61 61 /* __ Debug definitions __________________________________________________ */
62 62 //#define G_DIR2XY_DEBUG // Debug dir2xy
... ... @@ -457,7 +457,7 @@ double GWcs::solidangle(const GSkyPixel& pixel) const
457 457 GSkyDir dir4 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()+0.5));
458 458  
459 459 // Compile option 1: Use triginometric function
460   - #if defined(G_USE_TRIGO_FOR_SOLIDANGLE)
  460 + #if G_SOLIDANGLE_OPTION == 1
461 461  
462 462 // Initialise solid angle
463 463 double solidangle = 0.0;
... ... @@ -486,9 +486,9 @@ double GWcs::solidangle(const GSkyPixel& pixel) const
486 486 double cos_a34 = std::cos(a34);
487 487  
488 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));
  489 + double angle2 = gammalib::acos((cos_a34-cos_a24*cos_a23)/(sin_a24*sin_a23));
  490 + double angle3 = gammalib::acos((cos_a24-cos_a34*cos_a23)/(sin_a34*sin_a23));
  491 + double angle4 = gammalib::acos((cos_a23-cos_a24*cos_a34)/(sin_a24*sin_a34));
492 492  
493 493 // Compute excess area to determine solid angle
494 494 solidangle = (angle2 + angle3 + angle4) - gammalib::pi;
... ... @@ -513,9 +513,9 @@ double GWcs::solidangle(const GSkyPixel& pixel) const
513 513 double cos_a24 = std::cos(a24);
514 514  
515 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));
  516 + double angle1 = gammalib::acos((cos_a24-cos_a12*cos_a14)/(sin_a12*sin_a14));
  517 + double angle2 = gammalib::acos((cos_a14-cos_a12*cos_a24)/(sin_a12*sin_a24));
  518 + double angle4 = gammalib::acos((cos_a12-cos_a14*cos_a24)/(sin_a14*sin_a24));
519 519  
520 520 // Compute excess area to determine solid angle
521 521 solidangle = (angle1 + angle2 + angle4) - gammalib::pi;
... ... @@ -554,7 +554,76 @@ double GWcs::solidangle(const GSkyPixel& pixel) const
554 554  
555 555 } // endif: we had a polynom
556 556  
557   - // Compile option 2: Use vectors
  557 + // Compile option 2: Use Huilier's theorem
  558 + #elif G_SOLIDANGLE_OPTION == 2
  559 +
  560 + // Initialise solid angle
  561 + double solidangle = 0.0;
  562 +
  563 + // Compute angular distances between pixel corners
  564 + double a12 = dir1.dist(dir2);
  565 + double a14 = dir1.dist(dir4);
  566 + double a23 = dir2.dist(dir3);
  567 + double a34 = dir3.dist(dir4);
  568 +
  569 + // Special case: a12 or a14 is zero, then pixel is a triangle composed
  570 + // of [2,3,4]
  571 + if (a12 <= 0.0 || a14 <= 0.0) {
  572 +
  573 + // Compute diagonals
  574 + double a24 = dir2.dist(dir4);
  575 +
  576 + // Triangle [2,3,4]
  577 + double s = 0.5 * (a23 + a34 + a24);
  578 + solidangle = std::atan(std::sqrt(std::tan(0.5*s) *
  579 + std::tan(0.5*(s-a23)) *
  580 + std::tan(0.5*(s-a34)) *
  581 + std::tan(0.5*(s-a24))));
  582 +
  583 + }
  584 +
  585 + // Special case: a23 or a 34 is zero, then pixel is a triangle composed
  586 + // of [1,2,4]
  587 + else if (a23 <= 0.0 || a34 <= 0.0) {
  588 +
  589 + // Compute diagonals
  590 + double a24 = dir2.dist(dir4);
  591 +
  592 + // Triangle [1,2,4]
  593 + double s = 0.5 * (a12 + a24 + a14);
  594 + solidangle = std::atan(std::sqrt(std::tan(0.5*s) *
  595 + std::tan(0.5*(s-a12)) *
  596 + std::tan(0.5*(s-a24)) *
  597 + std::tan(0.5*(s-a14))));
  598 +
  599 + }
  600 +
  601 + // Otherwise we have a polygon
  602 + else {
  603 +
  604 + // Compute diagonal
  605 + double a24 = dir2.dist(dir4);
  606 +
  607 + // Triangle 1 [1,2,4]
  608 + double s1 = 0.5 * (a12 + a24 + a14);
  609 + double excess1 = std::atan(std::sqrt(std::tan(0.5*s1) *
  610 + std::tan(0.5*(s1-a12)) *
  611 + std::tan(0.5*(s1-a24)) *
  612 + std::tan(0.5*(s1-a14))));
  613 +
  614 + // Triangle 2 [2,3,4]
  615 + double s2 = 0.5 * (a23 + a34 + a24);
  616 + double excess2 = std::atan(std::sqrt(std::tan(0.5*s2) *
  617 + std::tan(0.5*(s2-a23)) *
  618 + std::tan(0.5*(s2-a34)) *
  619 + std::tan(0.5*(s2-a24))));
  620 +
  621 + // Determine solid angle
  622 + solidangle = 4.0 * (excess1 + excess2);
  623 +
  624 + } // endif: we had a polynom
  625 +
  626 + // Compile option 3: Use vectors
558 627 #else
559 628  
560 629 // Get vectors to pixel corners
... ...