Commit f7d12c2c2d5607ca5b3aa92b5254e8400f441af9
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 | ... | ... |