Commit c4afb3f9a203456cab9afaf435680bc4e5dcf0ff
1 parent
8f76e1ff
Implement HealPix support and rejection method for Monte Carlo simulations.
Showing
2 changed files
with
149 additions
and
7 deletions
include/GModelSpatialDiffuseCube.hpp
| @@ -119,6 +119,7 @@ protected: | @@ -119,6 +119,7 @@ protected: | ||
| 119 | GNodeArray m_logE; //!< Log10(energy) values of the maps | 119 | GNodeArray m_logE; //!< Log10(energy) values of the maps |
| 120 | GEbounds m_ebounds; //!< Energy bounds of the maps | 120 | GEbounds m_ebounds; //!< Energy bounds of the maps |
| 121 | std::vector<double> m_mc_cache; //!< Monte Carlo cache | 121 | std::vector<double> m_mc_cache; //!< Monte Carlo cache |
| 122 | + std::vector<double> m_mc_max; //!< Maximum values for MC | ||
| 122 | GModelSpectralNodes m_mc_spectrum; //!< Map cube spectrum | 123 | GModelSpectralNodes m_mc_spectrum; //!< Map cube spectrum |
| 123 | GSkyDir m_mc_cone_dir; //!< Monte Carlo simulation cone centre | 124 | GSkyDir m_mc_cone_dir; //!< Monte Carlo simulation cone centre |
| 124 | double m_mc_cone_rad; //!< Monte Carlo simulation cone radius | 125 | double m_mc_cone_rad; //!< Monte Carlo simulation cone radius |
src/model/GModelSpatialDiffuseCube.cpp
| @@ -31,6 +31,7 @@ | @@ -31,6 +31,7 @@ | ||
| 31 | #include "GException.hpp" | 31 | #include "GException.hpp" |
| 32 | #include "GTools.hpp" | 32 | #include "GTools.hpp" |
| 33 | #include "GMath.hpp" | 33 | #include "GMath.hpp" |
| 34 | +#include "GHealpix.hpp" | ||
| 34 | #include "GModelSpatialDiffuseCube.hpp" | 35 | #include "GModelSpatialDiffuseCube.hpp" |
| 35 | #include "GModelSpatialRegistry.hpp" | 36 | #include "GModelSpatialRegistry.hpp" |
| 36 | #include "GFitsTable.hpp" | 37 | #include "GFitsTable.hpp" |
| @@ -454,16 +455,90 @@ GSkyDir GModelSpatialDiffuseCube::mc(const GEnergy& energy, | @@ -454,16 +455,90 @@ GSkyDir GModelSpatialDiffuseCube::mc(const GEnergy& energy, | ||
| 454 | low = mid; | 455 | low = mid; |
| 455 | } | 456 | } |
| 456 | } | 457 | } |
| 458 | + int index = low - offset; | ||
| 457 | 459 | ||
| 458 | // Convert sky map index to sky map pixel | 460 | // Convert sky map index to sky map pixel |
| 459 | - GSkyPixel pixel = m_cube.inx2pix(low-offset); | 461 | + GSkyPixel pixel = m_cube.inx2pix(index); |
| 460 | 462 | ||
| 461 | - // Randomize pixel | ||
| 462 | - pixel.x(pixel.x() + ran.uniform() - 0.5); | ||
| 463 | - pixel.y(pixel.y() + ran.uniform() - 0.5); | 463 | + // If we have a 2D pixel then randomize pixel values and convert them |
| 464 | + // into a sky direction | ||
| 465 | + if (pixel.is_2D()) { | ||
| 464 | 466 | ||
| 465 | - // Get sky direction | ||
| 466 | - dir = m_cube.pix2dir(pixel); | 467 | + // Use a rejection method to find a sky direction |
| 468 | + while (true) { | ||
| 469 | + | ||
| 470 | + // Draw random sky pixel | ||
| 471 | + GSkyPixel test(pixel.x() + ran.uniform() - 0.5, | ||
| 472 | + pixel.y() + ran.uniform() - 0.5); | ||
| 473 | + | ||
| 474 | + // Derive sky direction | ||
| 475 | + dir = m_cube.pix2dir(test); | ||
| 476 | + | ||
| 477 | + // Get map value at that sky direction | ||
| 478 | + double value = m_cube(dir); | ||
| 479 | + | ||
| 480 | + // Get uniform random number up to the maximum | ||
| 481 | + double uniform = ran.uniform() * m_mc_max[low]; | ||
| 482 | + | ||
| 483 | + // Exit loop if we're not larger than the map value | ||
| 484 | + if (uniform <= value) { | ||
| 485 | + break; | ||
| 486 | + } | ||
| 487 | + | ||
| 488 | + } // endwhile: rejection method | ||
| 489 | + | ||
| 490 | + } // endif: had a 2D pixel | ||
| 491 | + | ||
| 492 | + // ... otherwise convert pixel into sky direction and randomize | ||
| 493 | + // position. We use a while loop to randomize the position within a | ||
| 494 | + // circle that enclosed the pixel and retain only directions that | ||
| 495 | + // result in the same pixel index and that are compatible with the | ||
| 496 | + // density distribution. | ||
| 497 | + else { | ||
| 498 | + | ||
| 499 | + // Get pointer on HealPix projection | ||
| 500 | + const GHealpix* healpix = | ||
| 501 | + static_cast<const GHealpix*>(m_cube.projection()); | ||
| 502 | + | ||
| 503 | + // Get enclosing radius | ||
| 504 | + double radius = healpix->max_pixrad(); | ||
| 505 | + | ||
| 506 | + // Initialize pixel centre | ||
| 507 | + dir = m_cube.pix2dir(pixel); | ||
| 508 | + | ||
| 509 | + // Get randomized pixel | ||
| 510 | + GSkyDir randomized_dir; | ||
| 511 | + double cosrad = std::cos(radius); | ||
| 512 | + while (true) { | ||
| 513 | + | ||
| 514 | + // Get randomized sky direction | ||
| 515 | + randomized_dir = dir; | ||
| 516 | + double theta = std::acos(1.0 - ran.uniform() * (1.0 - cosrad)) * gammalib::rad2deg; | ||
| 517 | + double phi = 360.0 * ran.uniform(); | ||
| 518 | + randomized_dir.rotate_deg(phi, theta); | ||
| 519 | + | ||
| 520 | + // Skip if we are not in the actual pixel | ||
| 521 | + if (m_cube.dir2inx(randomized_dir) != index) { | ||
| 522 | + continue; | ||
| 523 | + } | ||
| 524 | + | ||
| 525 | + // Get map value at that sky direction | ||
| 526 | + double value = m_cube(randomized_dir); | ||
| 527 | + | ||
| 528 | + // Get uniform random number up to the maximum | ||
| 529 | + double uniform = ran.uniform() * m_mc_max[low]; | ||
| 530 | + | ||
| 531 | + // Exit loop if we're not larger than the map value | ||
| 532 | + if (uniform <= value) { | ||
| 533 | + break; | ||
| 534 | + } | ||
| 535 | + | ||
| 536 | + } // endwhile | ||
| 537 | + | ||
| 538 | + // Store randomize sky position | ||
| 539 | + dir = randomized_dir; | ||
| 540 | + | ||
| 541 | + } // endelse: we had a HealPix map | ||
| 467 | 542 | ||
| 468 | } // endif: there were pixels in sky map | 543 | } // endif: there were pixels in sky map |
| 469 | 544 | ||
| @@ -787,6 +862,7 @@ void GModelSpatialDiffuseCube::set_mc_cone(const GSkyDir& centre, | @@ -787,6 +862,7 @@ void GModelSpatialDiffuseCube::set_mc_cone(const GSkyDir& centre, | ||
| 787 | { | 862 | { |
| 788 | // Initialise cache | 863 | // Initialise cache |
| 789 | m_mc_cache.clear(); | 864 | m_mc_cache.clear(); |
| 865 | + m_mc_max.clear(); | ||
| 790 | m_mc_spectrum.clear(); | 866 | m_mc_spectrum.clear(); |
| 791 | 867 | ||
| 792 | // Fetch cube | 868 | // Fetch cube |
| @@ -801,6 +877,7 @@ void GModelSpatialDiffuseCube::set_mc_cone(const GSkyDir& centre, | @@ -801,6 +877,7 @@ void GModelSpatialDiffuseCube::set_mc_cone(const GSkyDir& centre, | ||
| 801 | 877 | ||
| 802 | // Reserve space for all pixels in cache | 878 | // Reserve space for all pixels in cache |
| 803 | m_mc_cache.reserve((npix+1)*nmaps); | 879 | m_mc_cache.reserve((npix+1)*nmaps); |
| 880 | + m_mc_max.reserve(npix*nmaps); | ||
| 804 | 881 | ||
| 805 | // Loop over all maps | 882 | // Loop over all maps |
| 806 | for (int i = 0; i < nmaps; ++i) { | 883 | for (int i = 0; i < nmaps; ++i) { |
| @@ -833,7 +910,7 @@ void GModelSpatialDiffuseCube::set_mc_cone(const GSkyDir& centre, | @@ -833,7 +910,7 @@ void GModelSpatialDiffuseCube::set_mc_cone(const GSkyDir& centre, | ||
| 833 | // simulated event is contained in the simulation cone. | 910 | // simulated event is contained in the simulation cone. |
| 834 | double distance = centre.dist_deg(m_cube.pix2dir(k)); | 911 | double distance = centre.dist_deg(m_cube.pix2dir(k)); |
| 835 | if (distance <= radius+pixel_radius) { | 912 | if (distance <= radius+pixel_radius) { |
| 836 | - double flux = m_cube(k,i) * m_cube.solidangle(k); | 913 | + double flux = m_cube.flux(k,i); |
| 837 | if (flux > 0.0) { | 914 | if (flux > 0.0) { |
| 838 | total_flux += flux; | 915 | total_flux += flux; |
| 839 | } | 916 | } |
| @@ -866,6 +943,68 @@ void GModelSpatialDiffuseCube::set_mc_cone(const GSkyDir& centre, | @@ -866,6 +943,68 @@ void GModelSpatialDiffuseCube::set_mc_cone(const GSkyDir& centre, | ||
| 866 | 943 | ||
| 867 | } | 944 | } |
| 868 | 945 | ||
| 946 | + // Do we have a HealPix map? | ||
| 947 | + if (m_cube.projection()->code() == "HPX") { | ||
| 948 | + | ||
| 949 | + // Get pointer on HealPix projection | ||
| 950 | + const GHealpix* healpix = | ||
| 951 | + static_cast<const GHealpix*>(m_cube.projection()); | ||
| 952 | + | ||
| 953 | + // Compute maximum value that may occur from bilinear | ||
| 954 | + // interpolation within this pixel and push this value on the | ||
| 955 | + // stack. We do this by checking values of all neighbours. | ||
| 956 | + for (int k = 0; k < npix; ++k) { | ||
| 957 | + | ||
| 958 | + // Get neighbours | ||
| 959 | + std::vector<int> neighbours = healpix->neighbours(k); | ||
| 960 | + | ||
| 961 | + // Loop over neighbours | ||
| 962 | + double max = m_cube(k,i); | ||
| 963 | + for (int j = 0; j < neighbours.size(); ++j) { | ||
| 964 | + if (neighbours[j] != -1) { | ||
| 965 | + double value = m_cube(neighbours[j],i); | ||
| 966 | + if (value > max) { | ||
| 967 | + max = value; | ||
| 968 | + } | ||
| 969 | + } | ||
| 970 | + } | ||
| 971 | + | ||
| 972 | + // Store maximum | ||
| 973 | + m_mc_max.push_back(max); | ||
| 974 | + | ||
| 975 | + } // endfor: looped over pixels | ||
| 976 | + | ||
| 977 | + } // endif: Healpix projection | ||
| 978 | + | ||
| 979 | + // ... no, then we have a WCS map | ||
| 980 | + else { | ||
| 981 | + | ||
| 982 | + // Compute maximum value that may occur from bilinear | ||
| 983 | + // interpolation within this pixel and push this value on the | ||
| 984 | + // stack. We do this by checking the map values at the corners | ||
| 985 | + // and the centre of each edge. | ||
| 986 | + for (int k = 0; k < npix; ++k) { | ||
| 987 | + GSkyPixel pixel = m_cube.inx2pix(k); | ||
| 988 | + double max = m_cube(pixel,i); | ||
| 989 | + for (int ix = -1; ix < 2; ++ix) { | ||
| 990 | + for (int iy = -1; iy < 2; ++iy) { | ||
| 991 | + if (ix != 0 || iy != 0) { | ||
| 992 | + GSkyPixel edge(pixel.x()+ix*0.5, pixel.y()+iy*0.5); | ||
| 993 | + if (m_cube.contains(edge)) { | ||
| 994 | + GSkyDir dir = m_cube.pix2dir(edge); | ||
| 995 | + double value = m_cube(dir,i); | ||
| 996 | + if (value > max) { | ||
| 997 | + max = value; | ||
| 998 | + } | ||
| 999 | + } | ||
| 1000 | + } | ||
| 1001 | + } | ||
| 1002 | + } | ||
| 1003 | + m_mc_max.push_back(max); | ||
| 1004 | + } | ||
| 1005 | + | ||
| 1006 | + } // endelse: computed maximum pixel value | ||
| 1007 | + | ||
| 869 | } // endfor: looped over all maps | 1008 | } // endfor: looped over all maps |
| 870 | 1009 | ||
| 871 | // Dump cache values for debugging | 1010 | // Dump cache values for debugging |
| @@ -1000,6 +1139,7 @@ void GModelSpatialDiffuseCube::init_members(void) | @@ -1000,6 +1139,7 @@ void GModelSpatialDiffuseCube::init_members(void) | ||
| 1000 | 1139 | ||
| 1001 | // Initialise MC cache | 1140 | // Initialise MC cache |
| 1002 | m_mc_cache.clear(); | 1141 | m_mc_cache.clear(); |
| 1142 | + m_mc_max.clear(); | ||
| 1003 | m_mc_spectrum.clear(); | 1143 | m_mc_spectrum.clear(); |
| 1004 | m_mc_cone_dir.clear(); | 1144 | m_mc_cone_dir.clear(); |
| 1005 | m_mc_cone_rad = 0.0; | 1145 | m_mc_cone_rad = 0.0; |
| @@ -1026,6 +1166,7 @@ void GModelSpatialDiffuseCube::copy_members(const GModelSpatialDiffuseCube& mode | @@ -1026,6 +1166,7 @@ void GModelSpatialDiffuseCube::copy_members(const GModelSpatialDiffuseCube& mode | ||
| 1026 | 1166 | ||
| 1027 | // Copy MC cache | 1167 | // Copy MC cache |
| 1028 | m_mc_cache = model.m_mc_cache; | 1168 | m_mc_cache = model.m_mc_cache; |
| 1169 | + m_mc_max = model.m_mc_max; | ||
| 1029 | m_mc_spectrum = model.m_mc_spectrum; | 1170 | m_mc_spectrum = model.m_mc_spectrum; |
| 1030 | m_mc_cone_dir = model.m_mc_cone_dir; | 1171 | m_mc_cone_dir = model.m_mc_cone_dir; |
| 1031 | m_mc_cone_rad = model.m_mc_cone_rad; | 1172 | m_mc_cone_rad = model.m_mc_cone_rad; |