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,7 +56,7 @@
56 56
57 /* __ Coding definitions _________________________________________________ */ 57 /* __ Coding definitions _________________________________________________ */
58 //#define G_LIN_MATINV_FORCE_PC // Force PC usage 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 /* __ Debug definitions __________________________________________________ */ 61 /* __ Debug definitions __________________________________________________ */
62 //#define G_DIR2XY_DEBUG // Debug dir2xy 62 //#define G_DIR2XY_DEBUG // Debug dir2xy
@@ -457,7 +457,7 @@ double GWcs::solidangle(const GSkyPixel& pixel) const @@ -457,7 +457,7 @@ double GWcs::solidangle(const GSkyPixel& pixel) const
457 GSkyDir dir4 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()+0.5)); 457 GSkyDir dir4 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()+0.5));
458 458
459 // Compile option 1: Use triginometric function 459 // Compile option 1: Use triginometric function
460 - #if defined(G_USE_TRIGO_FOR_SOLIDANGLE) 460 + #if G_SOLIDANGLE_OPTION == 1
461 461
462 // Initialise solid angle 462 // Initialise solid angle
463 double solidangle = 0.0; 463 double solidangle = 0.0;
@@ -486,9 +486,9 @@ double GWcs::solidangle(const GSkyPixel& pixel) const @@ -486,9 +486,9 @@ double GWcs::solidangle(const GSkyPixel& pixel) const
486 double cos_a34 = std::cos(a34); 486 double cos_a34 = std::cos(a34);
487 487
488 // Compute angles 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 // Compute excess area to determine solid angle 493 // Compute excess area to determine solid angle
494 solidangle = (angle2 + angle3 + angle4) - gammalib::pi; 494 solidangle = (angle2 + angle3 + angle4) - gammalib::pi;
@@ -513,9 +513,9 @@ double GWcs::solidangle(const GSkyPixel& pixel) const @@ -513,9 +513,9 @@ double GWcs::solidangle(const GSkyPixel& pixel) const
513 double cos_a24 = std::cos(a24); 513 double cos_a24 = std::cos(a24);
514 514
515 // Compute angles 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 // Compute excess area to determine solid angle 520 // Compute excess area to determine solid angle
521 solidangle = (angle1 + angle2 + angle4) - gammalib::pi; 521 solidangle = (angle1 + angle2 + angle4) - gammalib::pi;
@@ -554,7 +554,76 @@ double GWcs::solidangle(const GSkyPixel& pixel) const @@ -554,7 +554,76 @@ double GWcs::solidangle(const GSkyPixel& pixel) const
554 554
555 } // endif: we had a polynom 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 #else 627 #else
559 628
560 // Get vectors to pixel corners 629 // Get vectors to pixel corners