Commit 65300dd7c766fdfd5fa44e962f4074d60f731d6e

Authored by Jürgen Knödlseder
2 parents 3c035092 9c75e11c

Merge branch 'issue_1017_jk' into integration

Conflicts:
	ChangeLog
ChangeLog
@@ -24,6 +24,7 @@ @@ -24,6 +24,7 @@
24 Add broken power law spectral model 24 Add broken power law spectral model
25 Add Gaussian spectral model 25 Add Gaussian spectral model
26 Update parameter files if necessary 26 Update parameter files if necessary
  27 + Implement exact sky map pixel solid angle computation
27 Rename the following classes: 28 Rename the following classes:
28 - GWcs => GSkyProjection 29 - GWcs => GSkyProjection
29 - GWcslib => GWcs 30 - 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 Author(s) : Juergen Knoedlseder 3 Author(s) : Juergen Knoedlseder
4 4
@@ -565,7 +565,12 @@ The GSkyPixel class now supports 1D and 2D pixelisations, allowing @@ -565,7 +565,12 @@ The GSkyPixel class now supports 1D and 2D pixelisations, allowing
565 a more generic usage of the class. Integer and double precision 565 a more generic usage of the class. Integer and double precision
566 values can be assigned from and to GSkyPixel for 1D pixelisations. 566 values can be assigned from and to GSkyPixel for 1D pixelisations.
567 567
568 -The GWcsAIT class has been added for Aitoff-Hammer projections. 568 +The GWcsAIT class has been added for Aitoff projections.
  569 +
  570 +The solid angle of sky map pixels are now computed using the spherical
  571 +excess. This provides accurate solid angles even in case that the
  572 +pixels are highly distorted, for example at the poles of the Aitoff
  573 +projections.
569 574
570 575
571 13. Support module 576 13. Support module
inst/com/test/test_COM.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 * test_COM.cpp - test COM classes * 2 * test_COM.cpp - test COM classes *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2012-2013 by Juergen Knoedlseder * 4 + * copyright (C) 2012-2014 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -580,7 +580,7 @@ void TestGCOMOptimize::test_binned_optimizer(void) @@ -580,7 +580,7 @@ void TestGCOMOptimize::test_binned_optimizer(void)
580 47, 0, 580 47, 0,
581 29.9617, 0.377506, 581 29.9617, 0.377506,
582 49, 0, 582 49, 0,
583 - 27.9993, 0.372603}; 583 + 27.9992, 0.372603};
584 test_try("Perform LM optimization"); 584 test_try("Perform LM optimization");
585 try { 585 try {
586 GOptimizerLM opt; 586 GOptimizerLM opt;
inst/cta/test/test_CTA.cpp
1 /*************************************************************************** 1 /***************************************************************************
2 * test_CTA.cpp - Test CTA classes * 2 * test_CTA.cpp - Test CTA classes *
3 * ----------------------------------------------------------------------- * 3 * ----------------------------------------------------------------------- *
4 - * copyright (C) 2010-2013 by Juergen Knoedlseder * 4 + * copyright (C) 2010-2014 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- * 5 * ----------------------------------------------------------------------- *
6 * * 6 * *
7 * This program is free software: you can redistribute it and/or modify * 7 * This program is free software: you can redistribute it and/or modify *
@@ -335,7 +335,8 @@ void TestGCTAResponse::test_response_irf_diffuse(void) @@ -335,7 +335,8 @@ void TestGCTAResponse::test_response_irf_diffuse(void)
335 { 335 {
336 // Set reference value 336 // Set reference value
337 //double ref = 13803.800313356; 337 //double ref = 13803.800313356;
338 - const double ref = 13803.5186374; 338 + //const double ref = 13803.5186374;
  339 + const double ref = 13796.8200974; // After GWcs::solidangle improvement
339 340
340 // Set parameters 341 // Set parameters
341 double src_ra = 201.3651; 342 double src_ra = 201.3651;
@@ -412,7 +413,8 @@ void TestGCTAResponse::test_response_npred_diffuse(void) @@ -412,7 +413,8 @@ void TestGCTAResponse::test_response_npred_diffuse(void)
412 { 413 {
413 // Set reference value 414 // Set reference value
414 //double ref = 11212.26274; // npred_spec precision of 1e-6 415 //double ref = 11212.26274; // npred_spec precision of 1e-6
415 - const double ref = 11212.437464; // npred_spec precision of 1e-5 416 + //const double ref = 11212.437464; // npred_spec precision of 1e-5
  417 + const double ref = 11206.8536502; // After GWcs::solidangle improvement
416 418
417 // Set parameters 419 // Set parameters
418 double src_ra = 201.3651; 420 double src_ra = 201.3651;
@@ -766,10 +768,10 @@ void TestGCTAOptimize::test_binned_optimizer(void) @@ -766,10 +768,10 @@ void TestGCTAOptimize::test_binned_optimizer(void)
766 double fit_results[] = {83.6331, 0, 768 double fit_results[] = {83.6331, 0,
767 22.0145, 0, 769 22.0145, 0,
768 5.616410411e-16, 1.904730785e-17, 770 5.616410411e-16, 1.904730785e-17,
769 - -2.481781246, -0.02580905077, 771 + -2.47925, -0.02580905077,
770 300000, 0, 772 300000, 0,
771 1, 0, 773 1, 0,
772 - 2.933677595, 0.06639644824, 774 + 2.93353, 0.06639644824,
773 6.550723074e-05, 1.945714239e-06, 775 6.550723074e-05, 1.945714239e-06,
774 -1.833781187, -0.0160819, 776 -1.833781187, -0.0160819,
775 1000000, 0, 777 1000000, 0,
src/sky/GWcs.cpp
@@ -56,6 +56,7 @@ @@ -56,6 +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 60
60 /* __ Debug definitions __________________________________________________ */ 61 /* __ Debug definitions __________________________________________________ */
61 //#define G_DIR2XY_DEBUG // Debug dir2xy 62 //#define G_DIR2XY_DEBUG // Debug dir2xy
@@ -425,34 +426,158 @@ void GWcs::write(GFitsHDU& hdu) const @@ -425,34 +426,158 @@ void GWcs::write(GFitsHDU& hdu) const
425 * 426 *
426 * @param[in] pixel Pixel index (x,y) 427 * @param[in] pixel Pixel index (x,y)
427 * 428 *
428 - * Estimate solid angles of pixel by computing the coordinates in the 4 pixel  
429 - * corners. The surface is computed using a cartesian approximation:  
430 - * a  
431 - * 1-----5-----2 a+b  
432 - * / | h \ where A = h ---  
433 - * 4-------6-------3 2  
434 - * b  
435 - * This is a brute force technique that works sufficiently well for non-  
436 - * rotated sky maps. Something more intelligent should be implemented in  
437 - * the future. 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 + *
438 ***************************************************************************/ 450 ***************************************************************************/
439 double GWcs::solidangle(const GSkyPixel& pixel) const 451 double GWcs::solidangle(const GSkyPixel& pixel) const
440 { 452 {
441 - // Get the sky directions of the 6 points 453 + // Get the sky directions of the 4 points
442 GSkyDir dir1 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()-0.5)); 454 GSkyDir dir1 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()-0.5));
443 GSkyDir dir2 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()-0.5)); 455 GSkyDir dir2 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()-0.5));
444 GSkyDir dir3 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()+0.5)); 456 GSkyDir dir3 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()+0.5));
445 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));
446 - GSkyDir dir5 = pix2dir(GSkyPixel(pixel.x(), pixel.y()-0.5));  
447 - GSkyDir dir6 = pix2dir(GSkyPixel(pixel.x(), pixel.y()+0.5));  
448 458
449 - // Compute distances between sky directions  
450 - double a = dir1.dist(dir2);  
451 - double b = dir3.dist(dir4);  
452 - double h = dir5.dist(dir6); 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 +
  465 + // Compute angular distances between pixel corners
  466 + double a12 = dir1.dist(dir2);
  467 + double a14 = dir1.dist(dir4);
  468 + double a23 = dir2.dist(dir3);
  469 + double a34 = dir3.dist(dir4);
  470 +
  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) {
453 474
454 - // Compute solid angle  
455 - double solidangle = 0.5*(h*(a+b)); 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
456 581
457 // Return solid angle 582 // Return solid angle
458 return solidangle; 583 return solidangle;