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 24 Add broken power law spectral model
25 25 Add Gaussian spectral model
26 26 Update parameter files if necessary
  27 + Implement exact sky map pixel solid angle computation
27 28 Rename the following classes:
28 29 - GWcs => GSkyProjection
29 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 3 Author(s) : Juergen Knoedlseder
4 4  
... ... @@ -565,7 +565,12 @@ The GSkyPixel class now supports 1D and 2D pixelisations, allowing
565 565 a more generic usage of the class. Integer and double precision
566 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 576 13. Support module
... ...
inst/com/test/test_COM.cpp
1 1 /***************************************************************************
2 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 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -580,7 +580,7 @@ void TestGCOMOptimize::test_binned_optimizer(void)
580 580 47, 0,
581 581 29.9617, 0.377506,
582 582 49, 0,
583   - 27.9993, 0.372603};
  583 + 27.9992, 0.372603};
584 584 test_try("Perform LM optimization");
585 585 try {
586 586 GOptimizerLM opt;
... ...
inst/cta/test/test_CTA.cpp
1 1 /***************************************************************************
2 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 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 335 {
336 336 // Set reference value
337 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 341 // Set parameters
341 342 double src_ra = 201.3651;
... ... @@ -412,7 +413,8 @@ void TestGCTAResponse::test_response_npred_diffuse(void)
412 413 {
413 414 // Set reference value
414 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 419 // Set parameters
418 420 double src_ra = 201.3651;
... ... @@ -766,10 +768,10 @@ void TestGCTAOptimize::test_binned_optimizer(void)
766 768 double fit_results[] = {83.6331, 0,
767 769 22.0145, 0,
768 770 5.616410411e-16, 1.904730785e-17,
769   - -2.481781246, -0.02580905077,
  771 + -2.47925, -0.02580905077,
770 772 300000, 0,
771 773 1, 0,
772   - 2.933677595, 0.06639644824,
  774 + 2.93353, 0.06639644824,
773 775 6.550723074e-05, 1.945714239e-06,
774 776 -1.833781187, -0.0160819,
775 777 1000000, 0,
... ...
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,34 +426,158 @@ void GWcs::write(GFitsHDU& hdu) const
425 426 *
426 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 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 454 GSkyDir dir1 = pix2dir(GSkyPixel(pixel.x()-0.5, pixel.y()-0.5));
443 455 GSkyDir dir2 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()-0.5));
444 456 GSkyDir dir3 = pix2dir(GSkyPixel(pixel.x()+0.5, pixel.y()+0.5));
445 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 582 // Return solid angle
458 583 return solidangle;
... ...