Commit 997ffff511b58a071bdf5d64ab3bd5608d813719
1 parent
b1668ffb
Allow specifying of input sky map in ctskymap (#2311)
Showing
11 changed files
with
519 additions
and
300 deletions
ChangeLog
| 1 | -2018-02-10 | 1 | +2018-02-13 |
| 2 | 2 | ||
| 3 | * Version 1.6.0 released | 3 | * Version 1.6.0 released |
| 4 | ======================== | 4 | ======================== |
| 5 | 5 | ||
| 6 | + Allow specifying of input sky map in ctskymap (#2311) | ||
| 6 | Accelerate IRF and RING background methods in ctskymap (#2309) | 7 | Accelerate IRF and RING background methods in ctskymap (#2309) |
| 7 | 8 | ||
| 8 | 9 |
NEWS
| 1 | New Features and Important Changes in ctools 1.6.0 | 1 | New Features and Important Changes in ctools 1.6.0 |
| 2 | 2 | ||
| 3 | -10 February 2018 | 3 | +13 February 2018 |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | Introduction | 6 | Introduction |
| @@ -106,7 +106,22 @@ None | @@ -106,7 +106,22 @@ None | ||
| 106 | 106 | ||
| 107 | ctskymap - CTA sky mapping | 107 | ctskymap - CTA sky mapping |
| 108 | -------------------------- | 108 | -------------------------- |
| 109 | -Accelerate the IRF and RING background methods (#2309). | 109 | +Add the "inmap", "iterations" and "threshold" parameters. The hidden |
| 110 | +"inmap" parameter allows specifying a sky map file containing a "COUNTS" | ||
| 111 | +and "ACCEPTANCE" extension which avoids looping over event lists in an | ||
| 112 | +observation container. The "iterations" parameter allows the iterative | ||
| 113 | +determination of an exclusion map from the resulting significance map for | ||
| 114 | +the RING background method. The exclusion map will flag all pixels with | ||
| 115 | +significances above the "threshold" value so that they will be excluded | ||
| 116 | +in the subsequent RING background determination. Since this will impact | ||
| 117 | +the pixel significances, the procedure needs to be repeated a couple of | ||
| 118 | +times to stabilise (#2311). | ||
| 119 | + | ||
| 120 | +Accelerate the IRF and RING background methods. For the RING background | ||
| 121 | +method the computation is either performed using a FFT or using a direct | ||
| 122 | +computation. The FFT computation is faster, but assumed Euclidian | ||
| 123 | +distances for the sky map grid, the direct computation is slower, but | ||
| 124 | +accurately computes the distances between sky map pixels (#2309). | ||
| 110 | 125 | ||
| 111 | 126 | ||
| 112 | cttsmap - Generation of Test Statistic map | 127 | cttsmap - Generation of Test Statistic map |
doc/source/admin/release_history/1.6.rst
| @@ -22,6 +22,8 @@ Bug fixes | @@ -22,6 +22,8 @@ Bug fixes | ||
| 22 | Improvements | 22 | Improvements |
| 23 | ------------ | 23 | ------------ |
| 24 | 24 | ||
| 25 | +* [`2311 <https://cta-redmine.irap.omp.eu/issues/2311>`_] - | ||
| 26 | + Allow specifying of input skymap to :ref:`ctskymap` tool | ||
| 25 | * [`2309 <https://cta-redmine.irap.omp.eu/issues/2309>`_] - | 27 | * [`2309 <https://cta-redmine.irap.omp.eu/issues/2309>`_] - |
| 26 | Accelerate `IRF` and `RING` background methods in :ref:`ctskymap` | 28 | Accelerate `IRF` and `RING` background methods in :ref:`ctskymap` |
| 27 | 29 |
doc/source/users/reference_manual/ctskymap.rst
| @@ -41,6 +41,11 @@ General parameters | @@ -41,6 +41,11 @@ General parameters | ||
| 41 | Instrument response function (only required for IRF background subtraction | 41 | Instrument response function (only required for IRF background subtraction |
| 42 | if no response information is provided by ``inobs``). | 42 | if no response information is provided by ``inobs``). |
| 43 | 43 | ||
| 44 | +``(inmap = NONE) [file]`` | ||
| 45 | + Input sky map file containing a ``COUNTS`` and an ``ACCEPTANCE`` extension. | ||
| 46 | + Such extensions are produce by a previous run of the :ref:`ctskymap` tool with | ||
| 47 | + the ``IRF`` or ``RING`` background method. | ||
| 48 | + | ||
| 44 | ``outmap [file]`` | 49 | ``outmap [file]`` |
| 45 | Output sky map file. | 50 | Output sky map file. |
| 46 | 51 | ||
| @@ -90,6 +95,19 @@ Background subtraction configuration parameters | @@ -90,6 +95,19 @@ Background subtraction configuration parameters | ||
| 90 | ``outradius [real]`` | 95 | ``outradius [real]`` |
| 91 | Outer background ring radius for ``RING`` subtraction (in degrees). | 96 | Outer background ring radius for ``RING`` subtraction (in degrees). |
| 92 | 97 | ||
| 98 | +``iterations [integer]`` | ||
| 99 | + Number of iterations for the automatic computation of exclusion regions. | ||
| 100 | + Sky map pixels with detection significance above the value specified by the | ||
| 101 | + ``threshold`` parameter will be defined as exclusion regions, and the ``RING`` | ||
| 102 | + background will be recomputed based on these exclusion regions. Since this | ||
| 103 | + will likely change the significance of the pixels, the procedure can be | ||
| 104 | + iteratively repeated, and the ``iterations`` parameter specifies how often | ||
| 105 | + the procedure should be repeated. | ||
| 106 | + | ||
| 107 | +``threshold [real]`` | ||
| 108 | + Significance threshold above which pixels should be excluded for the | ||
| 109 | + background computation in the ``RING`` background method. | ||
| 110 | + | ||
| 93 | ``(inexclusion = NONE) [file]`` | 111 | ``(inexclusion = NONE) [file]`` |
| 94 | Exclusion region file as either a FITS map or DS9 region file. | 112 | Exclusion region file as either a FITS map or DS9 region file. |
| 95 | 113 |
pyext/ctobservation.i
| @@ -94,6 +94,7 @@ public: | @@ -94,6 +94,7 @@ public: | ||
| 94 | // Make methods private in Python by prepending an underscore | 94 | // Make methods private in Python by prepending an underscore |
| 95 | %rename(_first_unbinned_observation) first_unbinned_observation; | 95 | %rename(_first_unbinned_observation) first_unbinned_observation; |
| 96 | %rename(_next_unbinned_observation) next_unbinned_observation; | 96 | %rename(_next_unbinned_observation) next_unbinned_observation; |
| 97 | + %rename(_read_ogip_keywords) read_ogip_keywords; | ||
| 97 | %rename(_write_ogip_keywords) write_ogip_keywords; | 98 | %rename(_write_ogip_keywords) write_ogip_keywords; |
| 98 | %rename(_set_obs_statistic) set_obs_statistic; | 99 | %rename(_set_obs_statistic) set_obs_statistic; |
| 99 | %rename(_save_events_fits) save_events_fits; | 100 | %rename(_save_events_fits) save_events_fits; |
src/ctskymap/ctskymap.cpp
| @@ -35,6 +35,8 @@ | @@ -35,6 +35,8 @@ | ||
| 35 | #define G_GET_PARAMETERS "ctskymap::get_parameter()" | 35 | #define G_GET_PARAMETERS "ctskymap::get_parameter()" |
| 36 | #define G_MAP_EVENTS "ctskymap::map_events(GCTAObservation*)" | 36 | #define G_MAP_EVENTS "ctskymap::map_events(GCTAObservation*)" |
| 37 | #define G_MAP_BACKGROUND_IRF "ctskymap::map_background_irf(GCTAObservation*)" | 37 | #define G_MAP_BACKGROUND_IRF "ctskymap::map_background_irf(GCTAObservation*)" |
| 38 | +#define G_RING_BOUNDING_BOX "ctskymap::ring_bounding_box(int&, int&, int&, "\ | ||
| 39 | + "int&, int&)" | ||
| 38 | #define G_RING_KERNEL "ctskymap::ring_kernel(double&, double&)" | 40 | #define G_RING_KERNEL "ctskymap::ring_kernel(double&, double&)" |
| 39 | 41 | ||
| 40 | /* __ Debug definitions __________________________________________________ */ | 42 | /* __ Debug definitions __________________________________________________ */ |
| @@ -223,58 +225,14 @@ void ctskymap::run(void) | @@ -223,58 +225,14 @@ void ctskymap::run(void) | ||
| 223 | // Setup maps | 225 | // Setup maps |
| 224 | setup_maps(); | 226 | setup_maps(); |
| 225 | 227 | ||
| 226 | - // Write input observation container into logger | ||
| 227 | - log_observations(NORMAL, m_obs, "Input observation"); | ||
| 228 | - | ||
| 229 | - // Write header into logger | ||
| 230 | - log_header1(TERSE, gammalib::number("Find unbinned observation", | ||
| 231 | - m_obs.size())); | ||
| 232 | - | ||
| 233 | - // Find all unbinned CTA observations in m_obs | ||
| 234 | - std::vector<GCTAObservation*> obs_list(0); | ||
| 235 | - for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL; | ||
| 236 | - obs = next_unbinned_observation()) { | ||
| 237 | - | ||
| 238 | - // Push observation into list | ||
| 239 | - obs_list.push_back(obs); | ||
| 240 | - | ||
| 241 | - // Write message | ||
| 242 | - std::string msg = " Including unbinned "+obs->instrument()+ | ||
| 243 | - " observation"; | ||
| 244 | - log_string(NORMAL, msg); | 228 | + // If no input map exists then fill counts and acceptance maps from |
| 229 | + // observation container | ||
| 230 | + if (!m_has_inmap) { | ||
| 231 | + fill_maps(); | ||
| 245 | } | 232 | } |
| 246 | 233 | ||
| 247 | - // Write header into logger | ||
| 248 | - log_header1(TERSE, gammalib::number("Map observation", m_obs.size())); | ||
| 249 | - | ||
| 250 | - // Loop over all unbinned CTA observations in the container | ||
| 251 | - #pragma omp parallel for | ||
| 252 | - for (int i = 0; i < obs_list.size(); ++i) { | ||
| 253 | - | ||
| 254 | - // Get pointer to observation | ||
| 255 | - GCTAObservation* obs = obs_list[i]; | ||
| 256 | - | ||
| 257 | - // Map events into sky map | ||
| 258 | - map_events(obs); | ||
| 259 | - | ||
| 260 | - // Compute background sky map (only if m_bkgsubtract != "NONE") | ||
| 261 | - map_background(obs); | ||
| 262 | - | ||
| 263 | - // Dispose events to free memory | ||
| 264 | - obs->dispose_events(); | ||
| 265 | - | ||
| 266 | - } // endfor: looped over observations | ||
| 267 | - | ||
| 268 | - // If background subtraction is selected then compute significance map | ||
| 269 | - if (m_bkgsubtract != "NONE") { | ||
| 270 | - | ||
| 271 | - // Compute the significance map | ||
| 272 | - map_significance(); | ||
| 273 | - | ||
| 274 | - // Subtract background map from counts map | ||
| 275 | - m_skymap -= m_bkgmap; | ||
| 276 | - | ||
| 277 | - } // endif: background subtraction is selected | 234 | + // Compute maps |
| 235 | + compute_maps(); | ||
| 278 | 236 | ||
| 279 | // Optionally publish sky map | 237 | // Optionally publish sky map |
| 280 | if (m_publish) { | 238 | if (m_publish) { |
| @@ -289,8 +247,8 @@ void ctskymap::run(void) | @@ -289,8 +247,8 @@ void ctskymap::run(void) | ||
| 289 | /***********************************************************************//** | 247 | /***********************************************************************//** |
| 290 | * @brief Save sky map | 248 | * @brief Save sky map |
| 291 | * | 249 | * |
| 292 | - * Saves the sky map into a FITS file. The FITS file name is specified by the | ||
| 293 | - * @p outname parameter. | 250 | + * Saves the sky map into a FITS file. The FITS file name is specified by |
| 251 | + * the @p outname parameter. | ||
| 294 | ***************************************************************************/ | 252 | ***************************************************************************/ |
| 295 | void ctskymap::save(void) | 253 | void ctskymap::save(void) |
| 296 | { | 254 | { |
| @@ -307,39 +265,31 @@ void ctskymap::save(void) | @@ -307,39 +265,31 @@ void ctskymap::save(void) | ||
| 307 | GFits fits; | 265 | GFits fits; |
| 308 | 266 | ||
| 309 | // Write sky map into FITS file | 267 | // Write sky map into FITS file |
| 310 | - GFitsHDU* hdu = m_skymap.write(fits); | 268 | + write_map(fits, m_skymap, "SKYMAP"); |
| 311 | 269 | ||
| 312 | - // Write keywords into sky map extension | ||
| 313 | - write_ogip_keywords(hdu); | ||
| 314 | - write_hdu_keywords(hdu); | ||
| 315 | - | ||
| 316 | - // If background subtraction is requested then write background map | ||
| 317 | - // and significance map to FITS file | 270 | + // If background subtraction is requested then write the background map, |
| 271 | + // the significance map, the counts map and the acceptance map to the | ||
| 272 | + // FITS file | ||
| 318 | if (m_bkgsubtract != "NONE") { | 273 | if (m_bkgsubtract != "NONE") { |
| 319 | 274 | ||
| 320 | // Write background map into FITS file | 275 | // Write background map into FITS file |
| 321 | - hdu = m_bkgmap.write(fits); | ||
| 322 | - | ||
| 323 | - // Set background map extension name | ||
| 324 | - if (hdu != NULL) { | ||
| 325 | - hdu->extname("BACKGROUND"); | ||
| 326 | - } | 276 | + write_map(fits, m_bkgmap, "BACKGROUND"); |
| 327 | 277 | ||
| 328 | - // Write keywords into background extension | ||
| 329 | - write_ogip_keywords(hdu); | ||
| 330 | - write_hdu_keywords(hdu); | ||
| 331 | 278 | ||
| 332 | // Write significance map into FITS file | 279 | // Write significance map into FITS file |
| 333 | - hdu = m_sigmap.write(fits); | 280 | + write_map(fits, m_sigmap, "SIGNIFICANCE"); |
| 334 | 281 | ||
| 335 | - // Set significance map extension name | ||
| 336 | - if (hdu != NULL) { | ||
| 337 | - hdu->extname("SIGNIFICANCE"); | ||
| 338 | - } | 282 | + // Write counts map into FITS file |
| 283 | + write_map(fits, m_counts, "COUNTS"); | ||
| 339 | 284 | ||
| 340 | - // Write keywords into significance extension | ||
| 341 | - write_ogip_keywords(hdu); | ||
| 342 | - write_hdu_keywords(hdu); | 285 | + // Write acceptance map into FITS file |
| 286 | + write_map(fits, m_acceptance, "ACCEPTANCE"); | ||
| 287 | + | ||
| 288 | + // If RING background subtraction is requested then write also | ||
| 289 | + // the exclusion map to the FITS file | ||
| 290 | + if (m_bkgsubtract == "RING") { | ||
| 291 | + write_map(fits, m_exclmap, "EXCLUSION"); | ||
| 292 | + } | ||
| 343 | 293 | ||
| 344 | } // endif: background subtraction was requested | 294 | } // endif: background subtraction was requested |
| 345 | 295 | ||
| @@ -401,21 +351,25 @@ void ctskymap::init_members(void) | @@ -401,21 +351,25 @@ void ctskymap::init_members(void) | ||
| 401 | // Initialise User parameters | 351 | // Initialise User parameters |
| 402 | m_outmap.clear(); | 352 | m_outmap.clear(); |
| 403 | m_inexclusion.clear(); | 353 | m_inexclusion.clear(); |
| 404 | - m_binsz = 0.0; | ||
| 405 | m_emin = 0.0; | 354 | m_emin = 0.0; |
| 406 | m_emax = 0.0; | 355 | m_emax = 0.0; |
| 407 | m_bkgsubtract = "NONE"; | 356 | m_bkgsubtract = "NONE"; |
| 408 | m_roiradius = 0.0; | 357 | m_roiradius = 0.0; |
| 409 | m_inradius = 0.0; | 358 | m_inradius = 0.0; |
| 410 | m_outradius = 0.0; | 359 | m_outradius = 0.0; |
| 360 | + m_iterations = 0; | ||
| 361 | + m_threshold = 5.0; | ||
| 411 | m_usefft = true; | 362 | m_usefft = true; |
| 412 | m_publish = false; | 363 | m_publish = false; |
| 413 | m_chatter = static_cast<GChatter>(2); | 364 | m_chatter = static_cast<GChatter>(2); |
| 414 | 365 | ||
| 415 | // Initialise members | 366 | // Initialise members |
| 367 | + m_has_inmap = false; | ||
| 416 | m_skymap.clear(); | 368 | m_skymap.clear(); |
| 417 | m_bkgmap.clear(); | 369 | m_bkgmap.clear(); |
| 418 | m_sigmap.clear(); | 370 | m_sigmap.clear(); |
| 371 | + m_counts.clear(); | ||
| 372 | + m_acceptance.clear(); | ||
| 419 | m_exclmap.clear(); | 373 | m_exclmap.clear(); |
| 420 | 374 | ||
| 421 | // Initialise cache | 375 | // Initialise cache |
| @@ -440,22 +394,26 @@ void ctskymap::copy_members(const ctskymap& app) | @@ -440,22 +394,26 @@ void ctskymap::copy_members(const ctskymap& app) | ||
| 440 | // Copy User parameters | 394 | // Copy User parameters |
| 441 | m_outmap = app.m_outmap; | 395 | m_outmap = app.m_outmap; |
| 442 | m_inexclusion = app.m_inexclusion; | 396 | m_inexclusion = app.m_inexclusion; |
| 443 | - m_binsz = app.m_binsz; | ||
| 444 | m_emin = app.m_emin; | 397 | m_emin = app.m_emin; |
| 445 | m_emax = app.m_emax; | 398 | m_emax = app.m_emax; |
| 446 | m_bkgsubtract = app.m_bkgsubtract; | 399 | m_bkgsubtract = app.m_bkgsubtract; |
| 447 | m_roiradius = app.m_roiradius; | 400 | m_roiradius = app.m_roiradius; |
| 448 | m_inradius = app.m_inradius; | 401 | m_inradius = app.m_inradius; |
| 449 | m_outradius = app.m_outradius; | 402 | m_outradius = app.m_outradius; |
| 403 | + m_iterations = app.m_iterations; | ||
| 404 | + m_threshold = app.m_threshold; | ||
| 450 | m_usefft = app.m_usefft; | 405 | m_usefft = app.m_usefft; |
| 451 | m_publish = app.m_publish; | 406 | m_publish = app.m_publish; |
| 452 | m_chatter = app.m_chatter; | 407 | m_chatter = app.m_chatter; |
| 453 | 408 | ||
| 454 | // Copy members | 409 | // Copy members |
| 455 | - m_skymap = app.m_skymap; | ||
| 456 | - m_bkgmap = app.m_bkgmap; | ||
| 457 | - m_sigmap = app.m_sigmap; | ||
| 458 | - m_exclmap = app.m_exclmap; | 410 | + m_has_inmap = app.m_has_inmap; |
| 411 | + m_skymap = app.m_skymap; | ||
| 412 | + m_bkgmap = app.m_bkgmap; | ||
| 413 | + m_sigmap = app.m_sigmap; | ||
| 414 | + m_counts = app.m_counts; | ||
| 415 | + m_acceptance = app.m_acceptance; | ||
| 416 | + m_exclmap = app.m_exclmap; | ||
| 459 | 417 | ||
| 460 | // Copy cache | 418 | // Copy cache |
| 461 | m_solidangle = app.m_solidangle; | 419 | m_solidangle = app.m_solidangle; |
| @@ -490,17 +448,61 @@ void ctskymap::free_members(void) | @@ -490,17 +448,61 @@ void ctskymap::free_members(void) | ||
| 490 | ***************************************************************************/ | 448 | ***************************************************************************/ |
| 491 | void ctskymap::get_parameters(void) | 449 | void ctskymap::get_parameters(void) |
| 492 | { | 450 | { |
| 493 | - // Setup observations from "inobs" parameter. Do not request response | ||
| 494 | - // information and do not accept counts cubes. | ||
| 495 | - setup_observations(m_obs, false, true, false); | 451 | + // So far we have no valid input map |
| 452 | + m_has_inmap = false; | ||
| 453 | + | ||
| 454 | + // If an input map was specified then extract try loading the COUNTS | ||
| 455 | + // and ACCEPTANCE extensions from that file | ||
| 456 | + GFilename inmap = (*this)["inmap"].filename(); | ||
| 457 | + if (inmap != "NONE") { | ||
| 458 | + GFits fits(inmap); | ||
| 459 | + if (fits.contains("COUNTS") && fits.contains("ACCEPTANCE")) { | ||
| 460 | + | ||
| 461 | + // Get HDUs | ||
| 462 | + GFitsHDU &counts = *fits["COUNTS"]; | ||
| 463 | + GFitsHDU &acceptance = *fits["ACCEPTANCE"]; | ||
| 496 | 464 | ||
| 497 | - // Create sky map. Note that the method reads the relevant User parameters. | ||
| 498 | - m_skymap = create_map(m_obs); | 465 | + // Read counts and acceptance map |
| 466 | + m_counts.read(counts); | ||
| 467 | + m_acceptance.read(acceptance); | ||
| 499 | 468 | ||
| 500 | - // Get further parameters | ||
| 501 | - m_binsz = (*this)["binsz"].real(); | ||
| 502 | - m_emin = (*this)["emin"].real(); | ||
| 503 | - m_emax = (*this)["emax"].real(); | 469 | + // Extract OGIP parameters |
| 470 | + read_ogip_keywords(&counts); | ||
| 471 | + | ||
| 472 | + // Extract energy range | ||
| 473 | + m_emin = (counts.has_card("E_MIN")) ? counts.real("E_MIN") : 0.0; | ||
| 474 | + m_emax = (counts.has_card("E_MAX")) ? counts.real("E_MAX") : 0.0; | ||
| 475 | + | ||
| 476 | + // Signal availability of sky map | ||
| 477 | + m_has_inmap = true; | ||
| 478 | + } | ||
| 479 | + else { | ||
| 480 | + std::string msg = "Input sky map \""+inmap.url()+"\" does not " | ||
| 481 | + "contain \"COUNTS\" and \"ACCEPTANCE\" " | ||
| 482 | + "extensions."; | ||
| 483 | + throw GException::invalid_value(G_GET_PARAMETERS, msg); | ||
| 484 | + } | ||
| 485 | + fits.close(); | ||
| 486 | + } | ||
| 487 | + | ||
| 488 | + // If no valid input map exists then request observations | ||
| 489 | + if (!m_has_inmap) { | ||
| 490 | + | ||
| 491 | + // Setup observations from "inobs" parameter. Do not request response | ||
| 492 | + // information and do not accept counts cubes. | ||
| 493 | + setup_observations(m_obs, false, true, false); | ||
| 494 | + | ||
| 495 | + // Create counts and acceptance maps from the User parameters | ||
| 496 | + m_counts = create_map(m_obs); | ||
| 497 | + m_acceptance = m_counts; | ||
| 498 | + | ||
| 499 | + // Get further parameters | ||
| 500 | + m_emin = (*this)["emin"].real(); | ||
| 501 | + m_emax = (*this)["emax"].real(); | ||
| 502 | + | ||
| 503 | + } // endif: no valid input map existed | ||
| 504 | + | ||
| 505 | + // Get background method | ||
| 504 | m_bkgsubtract = (*this)["bkgsubtract"].string(); | 506 | m_bkgsubtract = (*this)["bkgsubtract"].string(); |
| 505 | 507 | ||
| 506 | // Get RING background parameters | 508 | // Get RING background parameters |
| @@ -510,16 +512,20 @@ void ctskymap::get_parameters(void) | @@ -510,16 +512,20 @@ void ctskymap::get_parameters(void) | ||
| 510 | m_roiradius = (*this)["roiradius"].real(); | 512 | m_roiradius = (*this)["roiradius"].real(); |
| 511 | m_inradius = (*this)["inradius"].real(); | 513 | m_inradius = (*this)["inradius"].real(); |
| 512 | m_outradius = (*this)["outradius"].real(); | 514 | m_outradius = (*this)["outradius"].real(); |
| 515 | + m_iterations = (*this)["iterations"].integer(); | ||
| 516 | + if (m_iterations > 0) { | ||
| 517 | + m_threshold = (*this)["threshold"].real(); | ||
| 518 | + } | ||
| 513 | m_inexclusion = (*this)["inexclusion"].filename(); | 519 | m_inexclusion = (*this)["inexclusion"].filename(); |
| 514 | m_usefft = (*this)["usefft"].boolean(); | 520 | m_usefft = (*this)["usefft"].boolean(); |
| 515 | 521 | ||
| 516 | // Make sure that (roiradius < inradius < outradius) | 522 | // Make sure that (roiradius < inradius < outradius) |
| 517 | if (m_roiradius > m_inradius) { | 523 | if (m_roiradius > m_inradius) { |
| 518 | - std::string msg("'roiradius' must be smaller than 'inradius'"); | 524 | + std::string msg("\"roiradius\" must be smaller than \"inradius\""); |
| 519 | throw GException::invalid_value(G_GET_PARAMETERS, msg); | 525 | throw GException::invalid_value(G_GET_PARAMETERS, msg); |
| 520 | } | 526 | } |
| 521 | else if (m_inradius > m_outradius) { | 527 | else if (m_inradius > m_outradius) { |
| 522 | - std::string msg("'inradius' must be smaller than 'outradius'"); | 528 | + std::string msg("\"inradius\" must be smaller than \"outradius\""); |
| 523 | throw GException::invalid_value(G_GET_PARAMETERS, msg); | 529 | throw GException::invalid_value(G_GET_PARAMETERS, msg); |
| 524 | } | 530 | } |
| 525 | 531 | ||
| @@ -527,7 +533,7 @@ void ctskymap::get_parameters(void) | @@ -527,7 +533,7 @@ void ctskymap::get_parameters(void) | ||
| 527 | 533 | ||
| 528 | // If background subtraction is requested then make sure that the CTA | 534 | // If background subtraction is requested then make sure that the CTA |
| 529 | // observations in the observation container have response information | 535 | // observations in the observation container have response information |
| 530 | - if (m_bkgsubtract != "NONE") { | 536 | + if (m_bkgsubtract != "NONE" && !m_has_inmap) { |
| 531 | set_response(m_obs); | 537 | set_response(m_obs); |
| 532 | } | 538 | } |
| 533 | 539 | ||
| @@ -563,19 +569,15 @@ void ctskymap::setup_maps(void) | @@ -563,19 +569,15 @@ void ctskymap::setup_maps(void) | ||
| 563 | // is requested | 569 | // is requested |
| 564 | if (m_bkgsubtract != "NONE") { | 570 | if (m_bkgsubtract != "NONE") { |
| 565 | 571 | ||
| 566 | - // Create background and significance maps | ||
| 567 | - m_bkgmap = create_map(m_obs); | ||
| 568 | - m_sigmap = create_map(m_obs); | ||
| 569 | - | ||
| 570 | // Setup the exclusions map | 572 | // Setup the exclusions map |
| 571 | - map_exclusions(m_inexclusion); | 573 | + setup_exclusion_map(m_inexclusion); |
| 572 | 574 | ||
| 573 | // Cache the pixel solid angles and sky directions | 575 | // Cache the pixel solid angles and sky directions |
| 574 | - m_solidangle.reserve(m_bkgmap.npix()); | ||
| 575 | - m_dirs.reserve(m_bkgmap.npix()); | ||
| 576 | - for (int i = 0; i < m_bkgmap.npix(); ++i) { | ||
| 577 | - m_solidangle.push_back(m_bkgmap.solidangle(i)); | ||
| 578 | - m_dirs.push_back(m_bkgmap.inx2dir(i)); | 576 | + m_solidangle.reserve(m_counts.npix()); |
| 577 | + m_dirs.reserve(m_counts.npix()); | ||
| 578 | + for (int i = 0; i < m_counts.npix(); ++i) { | ||
| 579 | + m_solidangle.push_back(m_counts.solidangle(i)); | ||
| 580 | + m_dirs.push_back(m_counts.inx2dir(i)); | ||
| 579 | } | 581 | } |
| 580 | 582 | ||
| 581 | } // endif: background subtraction selected | 583 | } // endif: background subtraction selected |
| @@ -601,10 +603,10 @@ void ctskymap::setup_maps(void) | @@ -601,10 +603,10 @@ void ctskymap::setup_maps(void) | ||
| 601 | * background estimation. Pixels with values different from 0 will be | 603 | * background estimation. Pixels with values different from 0 will be |
| 602 | * excluded. | 604 | * excluded. |
| 603 | ***************************************************************************/ | 605 | ***************************************************************************/ |
| 604 | -void ctskymap::map_exclusions(const GFilename& filename) | 606 | +void ctskymap::setup_exclusion_map(const GFilename& filename) |
| 605 | { | 607 | { |
| 606 | // Create exlusion map | 608 | // Create exlusion map |
| 607 | - m_exclmap = create_map(m_obs); | 609 | + m_exclmap = m_counts; |
| 608 | 610 | ||
| 609 | // Set all pixels to 0 (no pixel excluded) | 611 | // Set all pixels to 0 (no pixel excluded) |
| 610 | m_exclmap = 0.0; | 612 | m_exclmap = 0.0; |
| @@ -614,10 +616,10 @@ void ctskymap::map_exclusions(const GFilename& filename) | @@ -614,10 +616,10 @@ void ctskymap::map_exclusions(const GFilename& filename) | ||
| 614 | 616 | ||
| 615 | // Fill the exclusions based on the regions supplied | 617 | // Fill the exclusions based on the regions supplied |
| 616 | if (filename.is_fits()) { | 618 | if (filename.is_fits()) { |
| 617 | - map_exclusions_fits(filename); | 619 | + setup_exclusion_map_fits(filename); |
| 618 | } | 620 | } |
| 619 | else { | 621 | else { |
| 620 | - map_exclusions_region(filename); | 622 | + setup_exclusion_map_region(filename); |
| 621 | } | 623 | } |
| 622 | 624 | ||
| 623 | } // endif: filename was valid | 625 | } // endif: filename was valid |
| @@ -635,7 +637,7 @@ void ctskymap::map_exclusions(const GFilename& filename) | @@ -635,7 +637,7 @@ void ctskymap::map_exclusions(const GFilename& filename) | ||
| 635 | * Sets all exclusion map pixels to 1 that correspond to non-zero pixels in | 637 | * Sets all exclusion map pixels to 1 that correspond to non-zero pixels in |
| 636 | * the exclusion sky map FITS file. | 638 | * the exclusion sky map FITS file. |
| 637 | ***************************************************************************/ | 639 | ***************************************************************************/ |
| 638 | -void ctskymap::map_exclusions_fits(const GFilename& filename) | 640 | +void ctskymap::setup_exclusion_map_fits(const GFilename& filename) |
| 639 | { | 641 | { |
| 640 | // Load the fits image | 642 | // Load the fits image |
| 641 | GSkyMap inmap(filename); | 643 | GSkyMap inmap(filename); |
| @@ -669,7 +671,7 @@ void ctskymap::map_exclusions_fits(const GFilename& filename) | @@ -669,7 +671,7 @@ void ctskymap::map_exclusions_fits(const GFilename& filename) | ||
| 669 | * Sets all exclusion map pixels to 1 that are contained in any of the DS9 | 671 | * Sets all exclusion map pixels to 1 that are contained in any of the DS9 |
| 670 | * regions. | 672 | * regions. |
| 671 | ***************************************************************************/ | 673 | ***************************************************************************/ |
| 672 | -void ctskymap::map_exclusions_region(const GFilename& filename) | 674 | +void ctskymap::setup_exclusion_map_region(const GFilename& filename) |
| 673 | { | 675 | { |
| 674 | // Load the exclusion regions | 676 | // Load the exclusion regions |
| 675 | GSkyRegions regions(filename); | 677 | GSkyRegions regions(filename); |
| @@ -693,16 +695,75 @@ void ctskymap::map_exclusions_region(const GFilename& filename) | @@ -693,16 +695,75 @@ void ctskymap::map_exclusions_region(const GFilename& filename) | ||
| 693 | 695 | ||
| 694 | 696 | ||
| 695 | /***********************************************************************//** | 697 | /***********************************************************************//** |
| 696 | - * @brief Map events into a sky map | 698 | + * @brief Fill maps from observation container |
| 699 | + * | ||
| 700 | + * Fill counts and optionally acceptance maps from data in the observation | ||
| 701 | + * container. | ||
| 702 | + ***************************************************************************/ | ||
| 703 | +void ctskymap::fill_maps(void) | ||
| 704 | +{ | ||
| 705 | + // Write input observation container into logger | ||
| 706 | + log_observations(NORMAL, m_obs, "Input observation"); | ||
| 707 | + | ||
| 708 | + // Write header into logger | ||
| 709 | + log_header1(TERSE, gammalib::number("Find unbinned observation", | ||
| 710 | + m_obs.size())); | ||
| 711 | + | ||
| 712 | + // Find all unbinned CTA observations in m_obs | ||
| 713 | + std::vector<GCTAObservation*> obs_list(0); | ||
| 714 | + for (GCTAObservation* obs = first_unbinned_observation(); obs != NULL; | ||
| 715 | + obs = next_unbinned_observation()) { | ||
| 716 | + | ||
| 717 | + // Push observation into list | ||
| 718 | + obs_list.push_back(obs); | ||
| 719 | + | ||
| 720 | + // Write message | ||
| 721 | + std::string msg = " Including unbinned "+obs->instrument()+ | ||
| 722 | + " observation"; | ||
| 723 | + log_string(NORMAL, msg); | ||
| 724 | + } | ||
| 725 | + | ||
| 726 | + // Write header into logger | ||
| 727 | + log_header1(TERSE, gammalib::number("Fill map from observation", | ||
| 728 | + m_obs.size())); | ||
| 729 | + | ||
| 730 | + // Loop over all unbinned CTA observations in the container | ||
| 731 | + #pragma omp parallel for | ||
| 732 | + for (int i = 0; i < obs_list.size(); ++i) { | ||
| 733 | + | ||
| 734 | + // Get pointer to observation | ||
| 735 | + GCTAObservation* obs = obs_list[i]; | ||
| 736 | + | ||
| 737 | + // Fill events into counts map | ||
| 738 | + fill_maps_counts(obs); | ||
| 739 | + | ||
| 740 | + // Optionally compute acceptance sky map | ||
| 741 | + if (m_bkgsubtract != "NONE") { | ||
| 742 | + fill_maps_acceptance(obs); | ||
| 743 | + } | ||
| 744 | + | ||
| 745 | + // Dispose events to free memory | ||
| 746 | + obs->dispose_events(); | ||
| 747 | + | ||
| 748 | + } // endfor: looped over observations | ||
| 749 | + | ||
| 750 | + // Return | ||
| 751 | + return; | ||
| 752 | +} | ||
| 753 | + | ||
| 754 | + | ||
| 755 | +/***********************************************************************//** | ||
| 756 | + * @brief Fill events into counts map | ||
| 697 | * | 757 | * |
| 698 | * @param[in] obs CTA observation. | 758 | * @param[in] obs CTA observation. |
| 699 | * | 759 | * |
| 700 | * @exception GException::no_list | 760 | * @exception GException::no_list |
| 701 | * No event list found in observation. | 761 | * No event list found in observation. |
| 702 | * | 762 | * |
| 703 | - * This method maps the events found in a CTA events list into a sky map. | 763 | + * Fills the events found in a CTA events list into a sky map. The method |
| 764 | + * adds the events to the m_counts member. | ||
| 704 | ***************************************************************************/ | 765 | ***************************************************************************/ |
| 705 | -void ctskymap::map_events(GCTAObservation* obs) | 766 | +void ctskymap::fill_maps_counts(GCTAObservation* obs) |
| 706 | { | 767 | { |
| 707 | // Get non-const pointer on a CTA event list | 768 | // Get non-const pointer on a CTA event list |
| 708 | GCTAEventList* events = dynamic_cast<GCTAEventList*> | 769 | GCTAEventList* events = dynamic_cast<GCTAEventList*> |
| @@ -745,11 +806,11 @@ void ctskymap::map_events(GCTAObservation* obs) | @@ -745,11 +806,11 @@ void ctskymap::map_events(GCTAObservation* obs) | ||
| 745 | // Determine sky pixel | 806 | // Determine sky pixel |
| 746 | GCTAInstDir* inst = (GCTAInstDir*)&(event->dir()); | 807 | GCTAInstDir* inst = (GCTAInstDir*)&(event->dir()); |
| 747 | GSkyDir dir = inst->dir(); | 808 | GSkyDir dir = inst->dir(); |
| 748 | - GSkyPixel pixel = m_skymap.dir2pix(dir); | 809 | + GSkyPixel pixel = m_counts.dir2pix(dir); |
| 749 | 810 | ||
| 750 | // Skip if pixel is out of range | 811 | // Skip if pixel is out of range |
| 751 | - if (pixel.x() < -0.5 || pixel.x() > (m_skymap.nx() - 0.5) || | ||
| 752 | - pixel.y() < -0.5 || pixel.y() > (m_skymap.ny() - 0.5)) { | 812 | + if (pixel.x() < -0.5 || pixel.x() > (m_counts.nx() - 0.5) || |
| 813 | + pixel.y() < -0.5 || pixel.y() > (m_counts.ny() - 0.5)) { | ||
| 753 | num_outside_map++; | 814 | num_outside_map++; |
| 754 | continue; | 815 | continue; |
| 755 | } | 816 | } |
| @@ -762,7 +823,7 @@ void ctskymap::map_events(GCTAObservation* obs) | @@ -762,7 +823,7 @@ void ctskymap::map_events(GCTAObservation* obs) | ||
| 762 | 823 | ||
| 763 | // Fill event in skymap | 824 | // Fill event in skymap |
| 764 | #pragma omp critical(ctskymap_map_events) | 825 | #pragma omp critical(ctskymap_map_events) |
| 765 | - m_skymap(pixel) += 1.0; | 826 | + m_counts(pixel) += 1.0; |
| 766 | num_in_map++; | 827 | num_in_map++; |
| 767 | 828 | ||
| 768 | } // endfor: looped over all events | 829 | } // endfor: looped over all events |
| @@ -779,7 +840,7 @@ void ctskymap::map_events(GCTAObservation* obs) | @@ -779,7 +840,7 @@ void ctskymap::map_events(GCTAObservation* obs) | ||
| 779 | 840 | ||
| 780 | // Write sky map into header | 841 | // Write sky map into header |
| 781 | log_header1(EXPLICIT, "Sky map"); | 842 | log_header1(EXPLICIT, "Sky map"); |
| 782 | - log_string(EXPLICIT, m_skymap.print(m_chatter)); | 843 | + log_string(EXPLICIT, m_counts.print(m_chatter)); |
| 783 | } | 844 | } |
| 784 | 845 | ||
| 785 | // Return | 846 | // Return |
| @@ -788,36 +849,7 @@ void ctskymap::map_events(GCTAObservation* obs) | @@ -788,36 +849,7 @@ void ctskymap::map_events(GCTAObservation* obs) | ||
| 788 | 849 | ||
| 789 | 850 | ||
| 790 | /***********************************************************************//** | 851 | /***********************************************************************//** |
| 791 | - * @brief Estimates the background in sky map for observation | ||
| 792 | - * | ||
| 793 | - * @param[in] obs CTA observation. | ||
| 794 | - * | ||
| 795 | - * Estimates the background in the sky map for a given observation and adds | ||
| 796 | - * this estimate to the background sky map. The background estimation method | ||
| 797 | - * is specified by the "bkgsubtract" parameter which can take the following | ||
| 798 | - * values: | ||
| 799 | - * | ||
| 800 | - * NONE - No background estimation | ||
| 801 | - * IRF - Background estimation based on IRF template | ||
| 802 | - * RING - Ring background estimation | ||
| 803 | - ***************************************************************************/ | ||
| 804 | -void ctskymap::map_background(GCTAObservation* obs) | ||
| 805 | -{ | ||
| 806 | - // Dispatch to appropriate background estimation method | ||
| 807 | - if (m_bkgsubtract == "IRF") { | ||
| 808 | - map_background_irf(obs); | ||
| 809 | - } | ||
| 810 | - else if (m_bkgsubtract == "RING") { | ||
| 811 | - map_background_irf(obs); | ||
| 812 | - } | ||
| 813 | - | ||
| 814 | - // Return | ||
| 815 | - return; | ||
| 816 | -} | ||
| 817 | - | ||
| 818 | - | ||
| 819 | -/***********************************************************************//** | ||
| 820 | - * @brief Estimates the background in sky map based on IRF template | 852 | + * @brief Compute background acceptance sky map based on IRF template |
| 821 | * | 853 | * |
| 822 | * @param[in] obs CTA observation. | 854 | * @param[in] obs CTA observation. |
| 823 | * | 855 | * |
| @@ -825,11 +857,10 @@ void ctskymap::map_background(GCTAObservation* obs) | @@ -825,11 +857,10 @@ void ctskymap::map_background(GCTAObservation* obs) | ||
| 825 | * No response information available for observation. | 857 | * No response information available for observation. |
| 826 | * No background template available in instrument response function. | 858 | * No background template available in instrument response function. |
| 827 | * | 859 | * |
| 828 | - * Estimates the background in the sky map using the IRF template for a given | ||
| 829 | - * observation and adds this estimate to the background sky map. The IRF | ||
| 830 | - * template is integrated numerically in energy. | 860 | + * Computes a background acceptance sky map using the IRF template for a |
| 861 | + * given observation and adds the estimate to the acceptance sky map. | ||
| 831 | ***************************************************************************/ | 862 | ***************************************************************************/ |
| 832 | -void ctskymap::map_background_irf(GCTAObservation* obs) | 863 | +void ctskymap::fill_maps_acceptance(GCTAObservation* obs) |
| 833 | { | 864 | { |
| 834 | // Get IRF response | 865 | // Get IRF response |
| 835 | const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*> | 866 | const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*> |
| @@ -874,8 +905,8 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | @@ -874,8 +905,8 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | ||
| 874 | // Initialise statistics | 905 | // Initialise statistics |
| 875 | double total = 0.0; | 906 | double total = 0.0; |
| 876 | 907 | ||
| 877 | - // Loop over all background map pixels | ||
| 878 | - for (int i = 0; i < m_bkgmap.npix(); ++i) { | 908 | + // Loop over all acceptance map pixels |
| 909 | + for (int i = 0; i < m_acceptance.npix(); ++i) { | ||
| 879 | 910 | ||
| 880 | // Get sky direction of pixel | 911 | // Get sky direction of pixel |
| 881 | GSkyDir& skydir = m_dirs[i]; | 912 | GSkyDir& skydir = m_dirs[i]; |
| @@ -894,16 +925,16 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | @@ -894,16 +925,16 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | ||
| 894 | // Multiply background rate with livetime and solid angle | 925 | // Multiply background rate with livetime and solid angle |
| 895 | value *= exposure * m_solidangle[i]; | 926 | value *= exposure * m_solidangle[i]; |
| 896 | 927 | ||
| 897 | - // Add number of background events to background map | ||
| 898 | - #pragma omp critical(ctskymap_map_background_irf) | ||
| 899 | - m_bkgmap(i) += value; | 928 | + // Add number of background events to acceptance map |
| 929 | + #pragma omp critical(ctskymap_map_acceptance) | ||
| 930 | + m_acceptance(i) += value; | ||
| 900 | 931 | ||
| 901 | // Update total number of background events | 932 | // Update total number of background events |
| 902 | total += value; | 933 | total += value; |
| 903 | 934 | ||
| 904 | - } // endfor: looped over background map pixels | 935 | + } // endfor: looped over acceptance map pixels |
| 905 | 936 | ||
| 906 | - // Log background subtraction results | 937 | + // Log acceptance results |
| 907 | #pragma omp critical(ctskymap_map_events) | 938 | #pragma omp critical(ctskymap_map_events) |
| 908 | { | 939 | { |
| 909 | log_value(NORMAL, "Events in background", int(total+0.5)); | 940 | log_value(NORMAL, "Events in background", int(total+0.5)); |
| @@ -915,14 +946,24 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | @@ -915,14 +946,24 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | ||
| 915 | 946 | ||
| 916 | 947 | ||
| 917 | /***********************************************************************//** | 948 | /***********************************************************************//** |
| 918 | - * @brief Compute the pixel significance if background subtraction is | ||
| 919 | - * requested | 949 | + * @brief Compute sky map, background map and significance map |
| 950 | + * | ||
| 951 | + * Computes the sky map, background map and significance map. The following | ||
| 952 | + * background subtraction methods are supported: | ||
| 953 | + * | ||
| 954 | + * NONE | ||
| 955 | + * ==== | ||
| 920 | * | 956 | * |
| 921 | - * Computes the pixel significance if a background subtraction method is | ||
| 922 | - * specified. | 957 | + * The sky map is simply the binned counts map, no background and |
| 958 | + * significance maps are computed. | ||
| 923 | * | 959 | * |
| 924 | - * For the @c IRF method Poisson statistic (in the Gaussian limit) is | ||
| 925 | - * assumed, and the significance \f$\sigma_i\f$ is computed using | 960 | + * IRF |
| 961 | + * === | ||
| 962 | + * | ||
| 963 | + * The background map is the acceptance map, and this background map is | ||
| 964 | + * subtracted from the counts map and assigned to the sky map. The | ||
| 965 | + * significance \f$\sigma_i\f$ is computed assuming Poisson statistic in | ||
| 966 | + * the Gaussian limit, using | ||
| 926 | * | 967 | * |
| 927 | * \f[\sigma_i = \frac{N_i - B_i}{\sqrt{N_i}}\f] | 968 | * \f[\sigma_i = \frac{N_i - B_i}{\sqrt{N_i}}\f] |
| 928 | * | 969 | * |
| @@ -930,6 +971,9 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | @@ -930,6 +971,9 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | ||
| 930 | * \f$N_i\f$ is the number of observed counts and | 971 | * \f$N_i\f$ is the number of observed counts and |
| 931 | * \f$B_i\f$ is the estimated number of background counts. | 972 | * \f$B_i\f$ is the estimated number of background counts. |
| 932 | * | 973 | * |
| 974 | + * RING | ||
| 975 | + * ==== | ||
| 976 | + * | ||
| 933 | * For the @c RING method the Li & Ma significance is computed for each | 977 | * For the @c RING method the Li & Ma significance is computed for each |
| 934 | * pixel, using the @c roiradius, @c inradius and @c outradius parameters | 978 | * pixel, using the @c roiradius, @c inradius and @c outradius parameters |
| 935 | * to specify the radius of the On region and the Off background ring, | 979 | * to specify the radius of the On region and the Off background ring, |
| @@ -941,21 +985,59 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | @@ -941,21 +985,59 @@ void ctskymap::map_background_irf(GCTAObservation* obs) | ||
| 941 | * map. Use FFT if the sky map is close to a cartesian grid, and use the | 985 | * map. Use FFT if the sky map is close to a cartesian grid, and use the |
| 942 | * direct method if the sky map shows important distortions. | 986 | * direct method if the sky map shows important distortions. |
| 943 | ***************************************************************************/ | 987 | ***************************************************************************/ |
| 944 | -void ctskymap::map_significance(void) | 988 | +void ctskymap::compute_maps(void) |
| 945 | { | 989 | { |
| 946 | - // Compute significance from "RING" method (Li & Ma eq. 17) | ||
| 947 | - if (m_bkgsubtract == "RING") { | 990 | + // Write header into logger |
| 991 | + log_header1(TERSE, "Compute maps"); | ||
| 992 | + | ||
| 993 | + // If no background subtraction is requested then simply assign the | ||
| 994 | + // counts map to the skymap | ||
| 995 | + if (m_bkgsubtract == "NONE") { | ||
| 996 | + m_skymap = m_counts; | ||
| 997 | + } | ||
| 998 | + | ||
| 999 | + // else if IRF background is selected then use the acceptance as background | ||
| 1000 | + else if (m_bkgsubtract == "IRF") { | ||
| 1001 | + m_skymap = m_counts - m_acceptance; | ||
| 1002 | + m_bkgmap = m_acceptance; | ||
| 1003 | + m_sigmap = (m_counts - m_acceptance) / sqrt(m_counts); | ||
| 1004 | + } | ||
| 1005 | + | ||
| 1006 | + // else if RING background is selected then compute the On | ||
| 1007 | + else if (m_bkgsubtract == "RING") { | ||
| 1008 | + | ||
| 1009 | + // Compute initial RING background | ||
| 948 | if (m_usefft) { | 1010 | if (m_usefft) { |
| 949 | - map_significance_ring_fft(); | 1011 | + compute_maps_ring_fft(); |
| 950 | } | 1012 | } |
| 951 | else { | 1013 | else { |
| 952 | - map_significance_ring_direct(); | 1014 | + compute_maps_ring_direct(); |
| 953 | } | 1015 | } |
| 954 | - } | ||
| 955 | 1016 | ||
| 956 | - // Compute significance using Poisson statistics in the Gaussian limit | ||
| 957 | - else { | ||
| 958 | - m_sigmap = (m_skymap - m_bkgmap) / sqrt(m_skymap); | 1017 | + // Store copy of exclusion regions |
| 1018 | + GSkyMap exclmap = m_exclmap; | ||
| 1019 | + | ||
| 1020 | + // Iterative computation of exclusion regions | ||
| 1021 | + for (int iter = 0; iter < m_iterations; ++iter) { | ||
| 1022 | + | ||
| 1023 | + // Set exclusion region from significance map | ||
| 1024 | + m_exclmap = exclmap; | ||
| 1025 | + for (int i = 0; i < m_exclmap.npix(); ++i) { | ||
| 1026 | + if (m_sigmap(i) > m_threshold) { | ||
| 1027 | + m_exclmap(i) = 1.0; | ||
| 1028 | + } | ||
| 1029 | + } | ||
| 1030 | + | ||
| 1031 | + // Re-compute RING background | ||
| 1032 | + if (m_usefft) { | ||
| 1033 | + compute_maps_ring_fft(); | ||
| 1034 | + } | ||
| 1035 | + else { | ||
| 1036 | + compute_maps_ring_direct(); | ||
| 1037 | + } | ||
| 1038 | + | ||
| 1039 | + } // endfor: looped over iterations | ||
| 1040 | + | ||
| 959 | } | 1041 | } |
| 960 | 1042 | ||
| 961 | // Return | 1043 | // Return |
| @@ -964,77 +1046,79 @@ void ctskymap::map_significance(void) | @@ -964,77 +1046,79 @@ void ctskymap::map_significance(void) | ||
| 964 | 1046 | ||
| 965 | 1047 | ||
| 966 | /***********************************************************************//** | 1048 | /***********************************************************************//** |
| 967 | - * @brief Compute the pixel significance for RING background | 1049 | + * @brief Compute the maps for RING background using a FFT |
| 968 | * | 1050 | * |
| 969 | * Computes the Li & Ma significance for each sky map pixel and replaces | 1051 | * Computes the Li & Ma significance for each sky map pixel and replaces |
| 970 | * the sky and background maps by the On- and Off-count maps. The computation | 1052 | * the sky and background maps by the On- and Off-count maps. The computation |
| 971 | - * is done by computing the exact distances between pixels in the sky map. | 1053 | + * is done using a FFT. |
| 972 | ***************************************************************************/ | 1054 | ***************************************************************************/ |
| 973 | -void ctskymap::map_significance_ring_direct(void) | 1055 | +void ctskymap::compute_maps_ring_fft(void) |
| 974 | { | 1056 | { |
| 975 | // Log message about what is being done | 1057 | // Log message about what is being done |
| 976 | - log_header1(NORMAL, "Computing ring background map (direct method)"); | ||
| 977 | - log_value(NORMAL, "Total pixels to process", m_skymap.npix()); | 1058 | + log_header3(NORMAL, "Computing ring background map (FFT method)"); |
| 978 | 1059 | ||
| 979 | - // Initialise On- and Off-count maps | ||
| 980 | - GSkyMap onmap = m_skymap; | ||
| 981 | - GSkyMap offmap = m_skymap; | ||
| 982 | - onmap = 0.0; | ||
| 983 | - offmap = 0.0; | 1060 | + // Initialise maps |
| 1061 | + m_skymap = m_counts; | ||
| 1062 | + m_bkgmap = m_counts; | ||
| 1063 | + m_sigmap = m_counts; | ||
| 1064 | + m_skymap = 0.0; | ||
| 1065 | + m_bkgmap = 0.0; | ||
| 1066 | + m_sigmap = 0.0; | ||
| 984 | 1067 | ||
| 985 | // Initialise statistics | 1068 | // Initialise statistics |
| 986 | int num_bad_alpha = 0; | 1069 | int num_bad_alpha = 0; |
| 987 | 1070 | ||
| 988 | - // Set progress logging frequency. By default the user is updated on the | ||
| 989 | - // progress when another 10% of pixels is processed, however, if there | ||
| 990 | - // are many pixels the user is updated each 100000 pixels. | ||
| 991 | - int n_logpix = m_skymap.npix() / 10; | ||
| 992 | - if (n_logpix > 100000) { | ||
| 993 | - n_logpix = 100000; | 1071 | + // Set-up sky and acceptance maps with excluded pixels according to the |
| 1072 | + // exclusion map | ||
| 1073 | + GSkyMap excl_counts = m_counts; | ||
| 1074 | + GSkyMap excl_acceptance = m_acceptance; | ||
| 1075 | + for (int i = 0; i < m_counts.npix(); ++i) { | ||
| 1076 | + if (m_exclmap(i) != 0.0) { | ||
| 1077 | + excl_counts(i) = 0.0; | ||
| 1078 | + excl_acceptance(i) = 0.0; | ||
| 1079 | + } | ||
| 994 | } | 1080 | } |
| 995 | 1081 | ||
| 996 | - // Loop over sky map pixels | ||
| 997 | - #pragma omp parallel for | ||
| 998 | - for (int i = 0; i < m_skymap.npix(); ++i) { | 1082 | + // Convolve maps for On-region and Off-region |
| 1083 | + GSkyMap on_counts = ring_convolve(m_counts, 0.0, m_roiradius); | ||
| 1084 | + GSkyMap on_alpha = ring_convolve(m_acceptance, 0.0, m_roiradius); | ||
| 1085 | + GSkyMap off_counts = ring_convolve(excl_counts, m_inradius, m_outradius); | ||
| 1086 | + GSkyMap off_alpha = ring_convolve(excl_acceptance, m_inradius, m_outradius); | ||
| 999 | 1087 | ||
| 1000 | - // Initialise the on/off counts and alpha for this bin | ||
| 1001 | - double n_on = 0.0; | ||
| 1002 | - double n_off = 0.0; | ||
| 1003 | - double alpha = 0.0; | 1088 | + // Compute maps by loop over sky map pixels |
| 1089 | + for (int i = 0; i < m_sigmap.npix(); ++i) { | ||
| 1004 | 1090 | ||
| 1005 | - // Update user about progress (only if there are more than 10000 pixels) | ||
| 1006 | - if (i % n_logpix == 0 && n_logpix > 10000) { | ||
| 1007 | - #pragma omp critical(ctskymap_map_significance_ring) | ||
| 1008 | - log_value(NORMAL, "Pixels remaining", m_skymap.npix()-i); | 1091 | + // Get On-counts, Off-counts and alpha value for this bin |
| 1092 | + double n_on = on_counts(i); | ||
| 1093 | + double n_off = off_counts(i); | ||
| 1094 | + double alpha; | ||
| 1095 | + if (off_alpha(i) == 0.0) { | ||
| 1096 | + alpha = 0.0; | ||
| 1097 | + n_on = 0.0; | ||
| 1098 | + n_off = 0.0; | ||
| 1099 | + } | ||
| 1100 | + else { | ||
| 1101 | + alpha = on_alpha(i) / off_alpha(i); | ||
| 1009 | } | 1102 | } |
| 1010 | - | ||
| 1011 | - // Compute the alpha and counts for this bin | ||
| 1012 | - compute_ring_values(i, m_skymap, m_bkgmap, n_on, n_off, alpha); | ||
| 1013 | 1103 | ||
| 1014 | // Store the On and alpha-weighted Off-counts | 1104 | // Store the On and alpha-weighted Off-counts |
| 1015 | - onmap(i) = n_on; | ||
| 1016 | - offmap(i) = alpha * n_off; | 1105 | + m_bkgmap(i) = alpha * n_off; |
| 1106 | + m_skymap(i) = n_on - m_bkgmap(i); | ||
| 1017 | 1107 | ||
| 1018 | // If alpha is zero then increment the bad alpha counter | 1108 | // If alpha is zero then increment the bad alpha counter |
| 1019 | if (alpha == 0.0) { | 1109 | if (alpha == 0.0) { |
| 1020 | num_bad_alpha++; | 1110 | num_bad_alpha++; |
| 1021 | - #pragma omp critical(ctskymap_map_significance_ring) | ||
| 1022 | - m_sigmap(i) = 0.0; | ||
| 1023 | } | 1111 | } |
| 1024 | 1112 | ||
| 1025 | - // ... otherwise store the results | 1113 | + // ... otherwise compute and store the results |
| 1026 | else { | 1114 | else { |
| 1027 | - | ||
| 1028 | - // Compute and store significance (Li & Ma eq. 17) | ||
| 1029 | - double sigma = sigma_li_ma(n_on, n_off, alpha); | ||
| 1030 | - #pragma omp critical(ctskymap_map_significance_ring) | ||
| 1031 | - m_sigmap(i) = sigma; | ||
| 1032 | - | ||
| 1033 | - } // endelse: alpha was non-zero | 1115 | + m_sigmap(i) = sigma_li_ma(n_on, n_off, alpha); |
| 1116 | + } | ||
| 1034 | 1117 | ||
| 1035 | } // endfor: looped over all pixels | 1118 | } // endfor: looped over all pixels |
| 1036 | 1119 | ||
| 1037 | // Log the number of bad-alpha bins | 1120 | // Log the number of bad-alpha bins |
| 1121 | + log_value(NORMAL, "Total number of pixels", m_sigmap.npix()); | ||
| 1038 | log_value(NORMAL, "Pixels with alpha=0", num_bad_alpha); | 1122 | log_value(NORMAL, "Pixels with alpha=0", num_bad_alpha); |
| 1039 | 1123 | ||
| 1040 | // Now take the square root. Since some bins can be negative, first | 1124 | // Now take the square root. Since some bins can be negative, first |
| @@ -1042,11 +1126,6 @@ void ctskymap::map_significance_ring_direct(void) | @@ -1042,11 +1126,6 @@ void ctskymap::map_significance_ring_direct(void) | ||
| 1042 | // each bin by its sign to preserve the +/- significance. | 1126 | // each bin by its sign to preserve the +/- significance. |
| 1043 | m_sigmap = sign(m_sigmap) * sqrt(abs(m_sigmap)); | 1127 | m_sigmap = sign(m_sigmap) * sqrt(abs(m_sigmap)); |
| 1044 | 1128 | ||
| 1045 | - // Terminate by storing the on-counts map as sky map and the off-counts | ||
| 1046 | - // map as background map | ||
| 1047 | - m_skymap = onmap; | ||
| 1048 | - m_bkgmap = offmap; | ||
| 1049 | - | ||
| 1050 | // Return | 1129 | // Return |
| 1051 | return; | 1130 | return; |
| 1052 | } | 1131 | } |
| @@ -1057,68 +1136,75 @@ void ctskymap::map_significance_ring_direct(void) | @@ -1057,68 +1136,75 @@ void ctskymap::map_significance_ring_direct(void) | ||
| 1057 | * | 1136 | * |
| 1058 | * Computes the Li & Ma significance for each sky map pixel and replaces | 1137 | * Computes the Li & Ma significance for each sky map pixel and replaces |
| 1059 | * the sky and background maps by the On- and Off-count maps. The computation | 1138 | * the sky and background maps by the On- and Off-count maps. The computation |
| 1060 | - * is done using a FFT. | 1139 | + * is done by computing the exact distances between pixels in the sky map. |
| 1061 | ***************************************************************************/ | 1140 | ***************************************************************************/ |
| 1062 | -void ctskymap::map_significance_ring_fft(void) | 1141 | +void ctskymap::compute_maps_ring_direct(void) |
| 1063 | { | 1142 | { |
| 1064 | // Log message about what is being done | 1143 | // Log message about what is being done |
| 1065 | - log_header1(NORMAL, "Computing ring background map (FFT method)"); | 1144 | + log_header3(NORMAL, "Computing ring background map (direct method)"); |
| 1145 | + log_value(NORMAL, "Total pixels to process", m_counts.npix()); | ||
| 1146 | + | ||
| 1147 | + // Initialise maps | ||
| 1148 | + m_skymap = m_counts; | ||
| 1149 | + m_bkgmap = m_counts; | ||
| 1150 | + m_sigmap = m_counts; | ||
| 1151 | + m_skymap = 0.0; | ||
| 1152 | + m_bkgmap = 0.0; | ||
| 1153 | + m_sigmap = 0.0; | ||
| 1066 | 1154 | ||
| 1067 | // Initialise statistics | 1155 | // Initialise statistics |
| 1068 | int num_bad_alpha = 0; | 1156 | int num_bad_alpha = 0; |
| 1069 | 1157 | ||
| 1070 | - // Set-up sky and acceptance maps with excluded pixels according to the | ||
| 1071 | - // exclusion map | ||
| 1072 | - GSkyMap skymap = m_skymap; | ||
| 1073 | - GSkyMap acceptance = m_bkgmap; | ||
| 1074 | - for (int i = 0; i < m_skymap.npix(); ++i) { | ||
| 1075 | - if (m_exclmap(i) != 0.0) { | ||
| 1076 | - skymap(i) = 0.0; | ||
| 1077 | - acceptance(i) = 0.0; | ||
| 1078 | - } | 1158 | + // Set progress logging frequency. By default the user is updated on the |
| 1159 | + // progress when another 10% of pixels is processed, however, if there | ||
| 1160 | + // are many pixels the user is updated each 100000 pixels. | ||
| 1161 | + int n_logpix = m_counts.npix() / 10; | ||
| 1162 | + if (n_logpix > 100000) { | ||
| 1163 | + n_logpix = 100000; | ||
| 1079 | } | 1164 | } |
| 1080 | 1165 | ||
| 1081 | - // Convolve maps for On-region and Off-region | ||
| 1082 | - GSkyMap on_counts = ring_convolve(skymap, 0.0, m_roiradius); | ||
| 1083 | - GSkyMap on_alpha = ring_convolve(acceptance, 0.0, m_roiradius); | ||
| 1084 | - GSkyMap off_counts = ring_convolve(skymap, m_inradius, m_outradius); | ||
| 1085 | - GSkyMap off_alpha = ring_convolve(acceptance, m_inradius, m_outradius); | 1166 | + // Compute maps by loop over sky map pixels |
| 1167 | + #pragma omp parallel for | ||
| 1168 | + for (int i = 0; i < m_sigmap.npix(); ++i) { | ||
| 1086 | 1169 | ||
| 1087 | - // Loop over sky map pixels | ||
| 1088 | - for (int i = 0; i < m_skymap.npix(); ++i) { | 1170 | + // Initialise the on/off counts and alpha for this bin |
| 1171 | + double n_on = 0.0; | ||
| 1172 | + double n_off = 0.0; | ||
| 1173 | + double alpha = 0.0; | ||
| 1089 | 1174 | ||
| 1090 | - // Get On-counts, Off-counts and alpha value for this bin | ||
| 1091 | - double n_on = on_counts(i); | ||
| 1092 | - double n_off = off_counts(i); | ||
| 1093 | - double alpha; | ||
| 1094 | - if (off_alpha(i) == 0.0) { | ||
| 1095 | - alpha = 0.0; | ||
| 1096 | - n_on = 0.0; | ||
| 1097 | - n_off = 0.0; | ||
| 1098 | - } | ||
| 1099 | - else { | ||
| 1100 | - alpha = on_alpha(i) / off_alpha(i); | 1175 | + // Update user about progress (only if there are more than 10000 pixels) |
| 1176 | + if (i % n_logpix == 0 && n_logpix > 10000) { | ||
| 1177 | + #pragma omp critical(ctskymap_map_significance_ring) | ||
| 1178 | + log_value(NORMAL, "Pixels remaining", m_sigmap.npix()-i); | ||
| 1101 | } | 1179 | } |
| 1102 | 1180 | ||
| 1181 | + // Compute the alpha and counts for this bin | ||
| 1182 | + compute_ring_values(i, m_counts, m_acceptance, n_on, n_off, alpha); | ||
| 1183 | + | ||
| 1103 | // Store the On and alpha-weighted Off-counts | 1184 | // Store the On and alpha-weighted Off-counts |
| 1104 | - on_counts(i) = n_on; | ||
| 1105 | - off_counts(i) = alpha * n_off; | 1185 | + m_bkgmap(i) = alpha * n_off; |
| 1186 | + m_skymap(i) = n_on - m_bkgmap(i); | ||
| 1106 | 1187 | ||
| 1107 | // If alpha is zero then increment the bad alpha counter | 1188 | // If alpha is zero then increment the bad alpha counter |
| 1108 | if (alpha == 0.0) { | 1189 | if (alpha == 0.0) { |
| 1109 | - m_sigmap(i) = 0.0; | ||
| 1110 | num_bad_alpha++; | 1190 | num_bad_alpha++; |
| 1191 | + #pragma omp critical(ctskymap_compute_maps_ring_direct) | ||
| 1192 | + m_sigmap(i) = 0.0; | ||
| 1111 | } | 1193 | } |
| 1112 | 1194 | ||
| 1113 | - // ... otherwise compute and store the results | 1195 | + // ... otherwise store the results |
| 1114 | else { | 1196 | else { |
| 1115 | - m_sigmap(i) = sigma_li_ma(n_on, n_off, alpha); | ||
| 1116 | - } | 1197 | + |
| 1198 | + // Compute and store significance (Li & Ma eq. 17) | ||
| 1199 | + double sigma = sigma_li_ma(n_on, n_off, alpha); | ||
| 1200 | + #pragma omp critical(ctskymap_compute_maps_ring_direct) | ||
| 1201 | + m_sigmap(i) = sigma; | ||
| 1202 | + | ||
| 1203 | + } // endelse: alpha was non-zero | ||
| 1117 | 1204 | ||
| 1118 | } // endfor: looped over all pixels | 1205 | } // endfor: looped over all pixels |
| 1119 | 1206 | ||
| 1120 | // Log the number of bad-alpha bins | 1207 | // Log the number of bad-alpha bins |
| 1121 | - log_value(NORMAL, "Total number of pixels", m_skymap.npix()); | ||
| 1122 | log_value(NORMAL, "Pixels with alpha=0", num_bad_alpha); | 1208 | log_value(NORMAL, "Pixels with alpha=0", num_bad_alpha); |
| 1123 | 1209 | ||
| 1124 | // Now take the square root. Since some bins can be negative, first | 1210 | // Now take the square root. Since some bins can be negative, first |
| @@ -1126,11 +1212,6 @@ void ctskymap::map_significance_ring_fft(void) | @@ -1126,11 +1212,6 @@ void ctskymap::map_significance_ring_fft(void) | ||
| 1126 | // each bin by its sign to preserve the +/- significance. | 1212 | // each bin by its sign to preserve the +/- significance. |
| 1127 | m_sigmap = sign(m_sigmap) * sqrt(abs(m_sigmap)); | 1213 | m_sigmap = sign(m_sigmap) * sqrt(abs(m_sigmap)); |
| 1128 | 1214 | ||
| 1129 | - // Terminate by storing the on-counts map as sky map and the off-counts | ||
| 1130 | - // map as background map | ||
| 1131 | - m_skymap = on_counts; | ||
| 1132 | - m_bkgmap = off_counts; | ||
| 1133 | - | ||
| 1134 | // Return | 1215 | // Return |
| 1135 | return; | 1216 | return; |
| 1136 | } | 1217 | } |
| @@ -1281,21 +1362,33 @@ void ctskymap::ring_bounding_box(const int& ipixel, int& ix1, int& ix2, | @@ -1281,21 +1362,33 @@ void ctskymap::ring_bounding_box(const int& ipixel, int& ix1, int& ix2, | ||
| 1281 | int& iy1, int& iy2) const | 1362 | int& iy1, int& iy2) const |
| 1282 | { | 1363 | { |
| 1283 | // Get number of pixels in x and y direction | 1364 | // Get number of pixels in x and y direction |
| 1284 | - int nx = m_skymap.nx(); | ||
| 1285 | - int ny = m_skymap.ny(); | 1365 | + int nx = m_counts.nx(); |
| 1366 | + int ny = m_counts.ny(); | ||
| 1286 | 1367 | ||
| 1287 | // Get x and y index of pixel to consider | 1368 | // Get x and y index of pixel to consider |
| 1288 | int ix0 = ipixel % nx; | 1369 | int ix0 = ipixel % nx; |
| 1289 | int iy0 = ipixel / nx; | 1370 | int iy0 = ipixel / nx; |
| 1290 | 1371 | ||
| 1372 | + // Get pointer on WCS projection | ||
| 1373 | + const GWcs* wcs = dynamic_cast<const GWcs*>(m_counts.projection()); | ||
| 1374 | + if (wcs == NULL) { | ||
| 1375 | + std::string msg = "Sky map is not a WCS projection. Method is only " | ||
| 1376 | + "valid for WCS projections."; | ||
| 1377 | + throw GException::invalid_value(G_RING_BOUNDING_BOX, msg); | ||
| 1378 | + } | ||
| 1379 | + | ||
| 1380 | + // Get X and Y step size | ||
| 1381 | + double dx_binsz = wcs->cdelt(0); | ||
| 1382 | + double dy_binsz = wcs->cdelt(1); | ||
| 1383 | + | ||
| 1291 | // Compute pixel increment in x-direction | 1384 | // Compute pixel increment in x-direction |
| 1292 | double dx = 0.0; | 1385 | double dx = 0.0; |
| 1293 | int ix = (ix0 > 0) ? ix0 - 1 : ix0 + 1; | 1386 | int ix = (ix0 > 0) ? ix0 - 1 : ix0 + 1; |
| 1294 | if (ix < nx) { | 1387 | if (ix < nx) { |
| 1295 | dx = m_dirs[ipixel].dist_deg(m_dirs[ix+iy0*nx]); | 1388 | dx = m_dirs[ipixel].dist_deg(m_dirs[ix+iy0*nx]); |
| 1296 | } | 1389 | } |
| 1297 | - if (dx < m_binsz) { | ||
| 1298 | - dx = m_binsz; | 1390 | + if (dx < dx_binsz) { |
| 1391 | + dx = dx_binsz; | ||
| 1299 | } | 1392 | } |
| 1300 | 1393 | ||
| 1301 | // Compute pixel increment in y-direction | 1394 | // Compute pixel increment in y-direction |
| @@ -1304,8 +1397,8 @@ void ctskymap::ring_bounding_box(const int& ipixel, int& ix1, int& ix2, | @@ -1304,8 +1397,8 @@ void ctskymap::ring_bounding_box(const int& ipixel, int& ix1, int& ix2, | ||
| 1304 | if (iy < ny) { | 1397 | if (iy < ny) { |
| 1305 | dx = m_dirs[ipixel].dist_deg(m_dirs[ix0+iy*nx]); | 1398 | dx = m_dirs[ipixel].dist_deg(m_dirs[ix0+iy*nx]); |
| 1306 | } | 1399 | } |
| 1307 | - if (dy < m_binsz) { | ||
| 1308 | - dy = m_binsz; | 1400 | + if (dy < dy_binsz) { |
| 1401 | + dy = dy_binsz; | ||
| 1309 | } | 1402 | } |
| 1310 | 1403 | ||
| 1311 | // Compute bounding box half size in x and y. The outer radius is | 1404 | // Compute bounding box half size in x and y. The outer radius is |
| @@ -1410,7 +1503,7 @@ GSkyMap ctskymap::ring_convolve(const GSkyMap& map, const double& rmin, | @@ -1410,7 +1503,7 @@ GSkyMap ctskymap::ring_convolve(const GSkyMap& map, const double& rmin, | ||
| 1410 | GNdarray ctskymap::ring_kernel(const double& rmin, const double& rmax) const | 1503 | GNdarray ctskymap::ring_kernel(const double& rmin, const double& rmax) const |
| 1411 | { | 1504 | { |
| 1412 | // Get pointer on WCS projection | 1505 | // Get pointer on WCS projection |
| 1413 | - const GWcs* wcs = dynamic_cast<const GWcs*>(m_skymap.projection()); | 1506 | + const GWcs* wcs = dynamic_cast<const GWcs*>(m_counts.projection()); |
| 1414 | if (wcs == NULL) { | 1507 | if (wcs == NULL) { |
| 1415 | std::string msg = "Sky map is not a WCS projection. Method is only " | 1508 | std::string msg = "Sky map is not a WCS projection. Method is only " |
| 1416 | "valid for WCS projections."; | 1509 | "valid for WCS projections."; |
| @@ -1422,24 +1515,24 @@ GNdarray ctskymap::ring_kernel(const double& rmin, const double& rmax) const | @@ -1422,24 +1515,24 @@ GNdarray ctskymap::ring_kernel(const double& rmin, const double& rmax) const | ||
| 1422 | double dy = wcs->cdelt(1); | 1515 | double dy = wcs->cdelt(1); |
| 1423 | 1516 | ||
| 1424 | // Initialise kernel | 1517 | // Initialise kernel |
| 1425 | - GNdarray kern(m_skymap.nx(), m_skymap.ny()); | 1518 | + GNdarray kern(m_counts.nx(), m_counts.ny()); |
| 1426 | 1519 | ||
| 1427 | // Fill kernel | 1520 | // Fill kernel |
| 1428 | - for (int ix1 = 0, ix2 = m_skymap.nx(); ix1 < m_skymap.nx(); ++ix1, --ix2) { | 1521 | + for (int ix1 = 0, ix2 = m_counts.nx(); ix1 < m_counts.nx(); ++ix1, --ix2) { |
| 1429 | double x = ix1 * dx; | 1522 | double x = ix1 * dx; |
| 1430 | double xqs = x * x; | 1523 | double xqs = x * x; |
| 1431 | - for (int iy1 = 0, iy2 = m_skymap.ny(); iy1 < m_skymap.ny(); ++iy1, --iy2) { | 1524 | + for (int iy1 = 0, iy2 = m_counts.ny(); iy1 < m_counts.ny(); ++iy1, --iy2) { |
| 1432 | double y = iy1 * dy; | 1525 | double y = iy1 * dy; |
| 1433 | double r = std::sqrt(xqs + y*y); | 1526 | double r = std::sqrt(xqs + y*y); |
| 1434 | if ((r >= rmin) && (r <= rmax)) { | 1527 | if ((r >= rmin) && (r <= rmax)) { |
| 1435 | kern(ix1,iy1) += 1.0; | 1528 | kern(ix1,iy1) += 1.0; |
| 1436 | - if (ix2 < m_skymap.nx()) { | 1529 | + if (ix2 < m_counts.nx()) { |
| 1437 | kern(ix2,iy1) += 1.0; | 1530 | kern(ix2,iy1) += 1.0; |
| 1438 | } | 1531 | } |
| 1439 | - if (iy2 < m_skymap.ny()) { | 1532 | + if (iy2 < m_counts.ny()) { |
| 1440 | kern(ix1,iy2) += 1.0; | 1533 | kern(ix1,iy2) += 1.0; |
| 1441 | } | 1534 | } |
| 1442 | - if ((ix2 < m_skymap.nx()) && (iy2 < m_skymap.ny())) { | 1535 | + if ((ix2 < m_counts.nx()) && (iy2 < m_counts.ny())) { |
| 1443 | kern(ix2,iy2) += 1.0; | 1536 | kern(ix2,iy2) += 1.0; |
| 1444 | } | 1537 | } |
| 1445 | } | 1538 | } |
| @@ -1486,6 +1579,34 @@ double ctskymap::sigma_li_ma(const double& n_on, | @@ -1486,6 +1579,34 @@ double ctskymap::sigma_li_ma(const double& n_on, | ||
| 1486 | 1579 | ||
| 1487 | 1580 | ||
| 1488 | /***********************************************************************//** | 1581 | /***********************************************************************//** |
| 1582 | + * @brief Write sky map into FITS file | ||
| 1583 | + * | ||
| 1584 | + * @param[in,out] fits FITS file. | ||
| 1585 | + * @param[in] map Sky map. | ||
| 1586 | + * @param[in] extname Extension name. | ||
| 1587 | + * | ||
| 1588 | + * Write one sky map with the extension name and keywords into the FITS file. | ||
| 1589 | + ***************************************************************************/ | ||
| 1590 | +void ctskymap::write_map(GFits& fits, const GSkyMap& map, const std::string& extname) const | ||
| 1591 | +{ | ||
| 1592 | + // Write map into FITS file | ||
| 1593 | + GFitsHDU* hdu = map.write(fits); | ||
| 1594 | + | ||
| 1595 | + // Set map extension name | ||
| 1596 | + if (hdu != NULL) { | ||
| 1597 | + hdu->extname(extname); | ||
| 1598 | + } | ||
| 1599 | + | ||
| 1600 | + // Write keywords into map extension | ||
| 1601 | + write_ogip_keywords(hdu); | ||
| 1602 | + write_hdu_keywords(hdu); | ||
| 1603 | + | ||
| 1604 | + // Return | ||
| 1605 | + return; | ||
| 1606 | +} | ||
| 1607 | + | ||
| 1608 | + | ||
| 1609 | +/***********************************************************************//** | ||
| 1489 | * @brief Write keywords in FITS HDU | 1610 | * @brief Write keywords in FITS HDU |
| 1490 | * | 1611 | * |
| 1491 | * @param[in,out] hdu Pointer to FITS HDU. | 1612 | * @param[in,out] hdu Pointer to FITS HDU. |
| @@ -1505,9 +1626,13 @@ void ctskymap::write_hdu_keywords(GFitsHDU* hdu) const | @@ -1505,9 +1626,13 @@ void ctskymap::write_hdu_keywords(GFitsHDU* hdu) const | ||
| 1505 | 1626 | ||
| 1506 | // Write RING background keywords | 1627 | // Write RING background keywords |
| 1507 | if (m_bkgsubtract == "RING") { | 1628 | if (m_bkgsubtract == "RING") { |
| 1508 | - hdu->card("ROIRAD", m_roiradius, "[deg] Source region radius"); | ||
| 1509 | - hdu->card("INRAD", m_inradius, "[deg] Inner background ring radius"); | ||
| 1510 | - hdu->card("OUTRAD", m_outradius, "[deg] Outer background ring radius"); | 1629 | + hdu->card("USEFFT", m_usefft, "Use FFT for RING background"); |
| 1630 | + hdu->card("ROIRAD", m_roiradius, "[deg] Source region radius"); | ||
| 1631 | + hdu->card("INRAD", m_inradius, "[deg] Inner background ring radius"); | ||
| 1632 | + hdu->card("OUTRAD", m_outradius, "[deg] Outer background ring radius"); | ||
| 1633 | + hdu->card("ITER", m_iterations, "Exclusion map iterations"); | ||
| 1634 | + hdu->card("THRES", m_threshold, "Exclusion map threshold"); | ||
| 1635 | + hdu->card("EXCLMAP", m_inexclusion.url(), "Exclusion map name"); | ||
| 1511 | } | 1636 | } |
| 1512 | 1637 | ||
| 1513 | } // endif: pointer was valid | 1638 | } // endif: pointer was valid |
src/ctskymap/ctskymap.hpp
| @@ -69,15 +69,15 @@ protected: | @@ -69,15 +69,15 @@ protected: | ||
| 69 | void free_members(void); | 69 | void free_members(void); |
| 70 | void get_parameters(void); | 70 | void get_parameters(void); |
| 71 | void setup_maps(void); | 71 | void setup_maps(void); |
| 72 | - void map_exclusions(const GFilename& filename); | ||
| 73 | - void map_exclusions_fits(const GFilename& filename); | ||
| 74 | - void map_exclusions_region(const GFilename& filename); | ||
| 75 | - void map_events(GCTAObservation* obs); | ||
| 76 | - void map_background(GCTAObservation* obs); | ||
| 77 | - void map_background_irf(GCTAObservation* obs); | ||
| 78 | - void map_significance(void); | ||
| 79 | - void map_significance_ring_direct(void); | ||
| 80 | - void map_significance_ring_fft(void); | 72 | + void setup_exclusion_map(const GFilename& filename); |
| 73 | + void setup_exclusion_map_fits(const GFilename& filename); | ||
| 74 | + void setup_exclusion_map_region(const GFilename& filename); | ||
| 75 | + void fill_maps(void); | ||
| 76 | + void fill_maps_counts(GCTAObservation* obs); | ||
| 77 | + void fill_maps_acceptance(GCTAObservation* obs); | ||
| 78 | + void compute_maps(void); | ||
| 79 | + void compute_maps_ring_fft(void); | ||
| 80 | + void compute_maps_ring_direct(void); | ||
| 81 | void compute_ring_values(const int& ipixel, | 81 | void compute_ring_values(const int& ipixel, |
| 82 | const GSkyMap& counts, | 82 | const GSkyMap& counts, |
| 83 | const GSkyMap& background, | 83 | const GSkyMap& background, |
| @@ -92,26 +92,33 @@ protected: | @@ -92,26 +92,33 @@ protected: | ||
| 92 | double sigma_li_ma(const double& n_on, | 92 | double sigma_li_ma(const double& n_on, |
| 93 | const double& n_off, | 93 | const double& n_off, |
| 94 | const double& alpha) const; | 94 | const double& alpha) const; |
| 95 | + void write_map(GFits& fits, | ||
| 96 | + const GSkyMap& map, | ||
| 97 | + const std::string& extname) const; | ||
| 95 | void write_hdu_keywords(GFitsHDU* hdu) const; | 98 | void write_hdu_keywords(GFitsHDU* hdu) const; |
| 96 | 99 | ||
| 97 | // User parameters | 100 | // User parameters |
| 98 | GFilename m_outmap; //!< Output file name | 101 | GFilename m_outmap; //!< Output file name |
| 99 | GFilename m_inexclusion; //!< Exclusion map file name | 102 | GFilename m_inexclusion; //!< Exclusion map file name |
| 100 | - double m_binsz; //!< Sky map binsize | ||
| 101 | double m_emin; //!< Minimum energy (TeV) | 103 | double m_emin; //!< Minimum energy (TeV) |
| 102 | double m_emax; //!< Maximum energy (TeV) | 104 | double m_emax; //!< Maximum energy (TeV) |
| 103 | std::string m_bkgsubtract; //!< Background subtraction method | 105 | std::string m_bkgsubtract; //!< Background subtraction method |
| 104 | double m_roiradius; //!< Region of interest radius for RING bkg. | 106 | double m_roiradius; //!< Region of interest radius for RING bkg. |
| 105 | double m_inradius; //!< Inner ring radius for RING background | 107 | double m_inradius; //!< Inner ring radius for RING background |
| 106 | double m_outradius; //!< Outer ring radius for RING background | 108 | double m_outradius; //!< Outer ring radius for RING background |
| 109 | + int m_iterations; //!< Number of iterations for RING background | ||
| 110 | + double m_threshold; //!< Threshold for RING background | ||
| 107 | bool m_usefft; //!< Use FFT for RING background | 111 | bool m_usefft; //!< Use FFT for RING background |
| 108 | bool m_publish; //!< Publish sky map? | 112 | bool m_publish; //!< Publish sky map? |
| 109 | GChatter m_chatter; //!< Chattiness | 113 | GChatter m_chatter; //!< Chattiness |
| 110 | 114 | ||
| 111 | // Protected members | 115 | // Protected members |
| 116 | + bool m_has_inmap; //!< Has valid input map | ||
| 112 | GSkyMap m_skymap; //!< Sky map | 117 | GSkyMap m_skymap; //!< Sky map |
| 113 | GSkyMap m_bkgmap; //!< Background map | 118 | GSkyMap m_bkgmap; //!< Background map |
| 114 | GSkyMap m_sigmap; //!< Significance map | 119 | GSkyMap m_sigmap; //!< Significance map |
| 120 | + GSkyMap m_counts; //!< Counts map | ||
| 121 | + GSkyMap m_acceptance; //!< Acceptance map | ||
| 115 | GSkyMap m_exclmap; //!< Exclusion map for RING background | 122 | GSkyMap m_exclmap; //!< Exclusion map for RING background |
| 116 | 123 | ||
| 117 | // Caching variables to prevent multiple computations of the same thing | 124 | // Caching variables to prevent multiple computations of the same thing |
src/ctskymap/ctskymap.par
| @@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
| 19 | inobs, f, a, events.fits,,, "Input event list or observation definition XML file" | 19 | inobs, f, a, events.fits,,, "Input event list or observation definition XML file" |
| 20 | caldb, s, a, prod2,,, "Calibration database" | 20 | caldb, s, a, prod2,,, "Calibration database" |
| 21 | irf, s, a, South_0.5h,,, "Instrument response function" | 21 | irf, s, a, South_0.5h,,, "Instrument response function" |
| 22 | +inmap, f, h, NONE,,, "Input skymap file" | ||
| 22 | outmap, f, a, skymap.fits,,, "Output skymap file" | 23 | outmap, f, a, skymap.fits,,, "Output skymap file" |
| 23 | 24 | ||
| 24 | # | 25 | # |
| @@ -46,8 +47,10 @@ bkgsubtract, s, a, NONE, NONE|IRF|RING,, "Background subtraction method" | @@ -46,8 +47,10 @@ bkgsubtract, s, a, NONE, NONE|IRF|RING,, "Background subtraction method" | ||
| 46 | roiradius, r, a, 0.2,,, "Source region radius for estimating on-counts (degrees)" | 47 | roiradius, r, a, 0.2,,, "Source region radius for estimating on-counts (degrees)" |
| 47 | inradius, r, a, 0.6,,, "Inner background ring radius (degrees)" | 48 | inradius, r, a, 0.6,,, "Inner background ring radius (degrees)" |
| 48 | outradius, r, a, 0.8,,, "Outer background ring radius (degrees)" | 49 | outradius, r, a, 0.8,,, "Outer background ring radius (degrees)" |
| 50 | +iterations, i, a, 0,0,100, "Number of iterations for exclusion regions computation" | ||
| 51 | +threshold, r, a, 5.0,,, "Significance threshold for exclusion regions computation" | ||
| 49 | inexclusion, f, h, NONE,,, "Exclusion map or DS9 region file name" | 52 | inexclusion, f, h, NONE,,, "Exclusion map or DS9 region file name" |
| 50 | -usefft, b, h, yes,,, "Use FFT for ring computation?" | 53 | +usefft, b, h, yes,,, "Use FFT for ring computation?" |
| 51 | 54 | ||
| 52 | # | 55 | # |
| 53 | # Standard parameters | 56 | # Standard parameters |
src/support/ctobservation.cpp
| @@ -319,6 +319,48 @@ const GCTAObservation* ctobservation::next_unbinned_observation(void) const | @@ -319,6 +319,48 @@ const GCTAObservation* ctobservation::next_unbinned_observation(void) const | ||
| 319 | 319 | ||
| 320 | 320 | ||
| 321 | /***********************************************************************//** | 321 | /***********************************************************************//** |
| 322 | + * @brief Read OGIP keywords from FITS HDU | ||
| 323 | + * | ||
| 324 | + * @param[in,out] hdu Pointer to FITS HDU. | ||
| 325 | + * | ||
| 326 | + * Read OGIP keywords from FITS HDU. | ||
| 327 | + ***************************************************************************/ | ||
| 328 | +void ctobservation::read_ogip_keywords(GFitsHDU* hdu) const | ||
| 329 | +{ | ||
| 330 | + // Continue only if pointer is valid | ||
| 331 | + if (hdu != NULL) { | ||
| 332 | + | ||
| 333 | + // Get observation information | ||
| 334 | + m_ogip_telescope = (hdu->has_card("TELESCOP")) ? hdu->string("TELESCOP") : ""; | ||
| 335 | + | ||
| 336 | + // Get observation time information | ||
| 337 | + std::string date_obs = (hdu->has_card("DATE-OBS")) ? hdu->string("DATE-OBS") : ""; | ||
| 338 | + std::string time_obs = (hdu->has_card("TIME-OBS")) ? hdu->string("TIME-OBS") : ""; | ||
| 339 | + std::string date_end = (hdu->has_card("DATE-END")) ? hdu->string("DATE-END") : ""; | ||
| 340 | + std::string time_end = (hdu->has_card("TIME-END")) ? hdu->string("TIME-END") : ""; | ||
| 341 | + m_ogip_telapse = (hdu->has_card("TELAPSE")) ? hdu->real("TELAPSE") : 0.0; | ||
| 342 | + m_ogip_ontime = (hdu->has_card("ONTIME")) ? hdu->real("ONTIME") : 0.0; | ||
| 343 | + m_ogip_livetime = (hdu->has_card("LIVETIME")) ? hdu->real("LIVETIME") : 0.0; | ||
| 344 | + m_ogip_exposure = (hdu->has_card("EXPOSURE")) ? hdu->real("EXPOSURE") : 0.0; | ||
| 345 | + | ||
| 346 | + // Get OGIP start and stop time | ||
| 347 | + std::string tstart = date_obs + "T" + time_obs; | ||
| 348 | + std::string tstop = date_end + "T" + time_end; | ||
| 349 | + if (tstart != "T") { | ||
| 350 | + m_ogip_tstart.utc(tstart); | ||
| 351 | + } | ||
| 352 | + if (tstop != "T") { | ||
| 353 | + m_ogip_tstop.utc(tstop); | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + } // endif: pointer was valid | ||
| 357 | + | ||
| 358 | + // Return | ||
| 359 | + return; | ||
| 360 | +} | ||
| 361 | + | ||
| 362 | + | ||
| 363 | +/***********************************************************************//** | ||
| 322 | * @brief Write OGIP keywords in FITS HDU | 364 | * @brief Write OGIP keywords in FITS HDU |
| 323 | * | 365 | * |
| 324 | * @param[in,out] hdu Pointer to FITS HDU. | 366 | * @param[in,out] hdu Pointer to FITS HDU. |
src/support/ctobservation.hpp
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * ctobservation - Base class for observation tools * | 2 | * ctobservation - Base class for observation tools * |
| 3 | * ----------------------------------------------------------------------- * | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2016-2017 by Juergen Knoedlseder * | 4 | + * copyright (C) 2016-2018 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 * |
| @@ -73,6 +73,7 @@ protected: | @@ -73,6 +73,7 @@ protected: | ||
| 73 | GCTAObservation* next_unbinned_observation(void); | 73 | GCTAObservation* next_unbinned_observation(void); |
| 74 | const GCTAObservation* first_unbinned_observation(void) const; | 74 | const GCTAObservation* first_unbinned_observation(void) const; |
| 75 | const GCTAObservation* next_unbinned_observation(void) const; | 75 | const GCTAObservation* next_unbinned_observation(void) const; |
| 76 | + void read_ogip_keywords(GFitsHDU* hdu) const; | ||
| 76 | void write_ogip_keywords(GFitsHDU* hdu) const; | 77 | void write_ogip_keywords(GFitsHDU* hdu) const; |
| 77 | void set_obs_statistic(const std::string& statistic); | 78 | void set_obs_statistic(const std::string& statistic); |
| 78 | void save_events_fits(void); | 79 | void save_events_fits(void); |
src/support/ctool.cpp
| @@ -650,7 +650,11 @@ GEbounds ctool::create_ebounds(void) | @@ -650,7 +650,11 @@ GEbounds ctool::create_ebounds(void) | ||
| 650 | ***************************************************************************/ | 650 | ***************************************************************************/ |
| 651 | GSkyMap ctool::create_map(const GObservations& obs) | 651 | GSkyMap ctool::create_map(const GObservations& obs) |
| 652 | { | 652 | { |
| 653 | - // Read task parameters | 653 | + // Read coordinate system and projection |
| 654 | + std::string coordsys = (*this)["coordsys"].string(); | ||
| 655 | + std::string proj = (*this)["proj"].string(); | ||
| 656 | + | ||
| 657 | + // Read sky map reference | ||
| 654 | double xref = 0.0; | 658 | double xref = 0.0; |
| 655 | double yref = 0.0; | 659 | double yref = 0.0; |
| 656 | bool usepnt = (*this)["usepnt"].boolean(); | 660 | bool usepnt = (*this)["usepnt"].boolean(); |
| @@ -658,11 +662,11 @@ GSkyMap ctool::create_map(const GObservations& obs) | @@ -658,11 +662,11 @@ GSkyMap ctool::create_map(const GObservations& obs) | ||
| 658 | xref = (*this)["xref"].real(); | 662 | xref = (*this)["xref"].real(); |
| 659 | yref = (*this)["yref"].real(); | 663 | yref = (*this)["yref"].real(); |
| 660 | } | 664 | } |
| 661 | - std::string proj = (*this)["proj"].string(); | ||
| 662 | - std::string coordsys = (*this)["coordsys"].string(); | ||
| 663 | - double binsz = (*this)["binsz"].real(); | ||
| 664 | - int nxpix = (*this)["nxpix"].integer(); | ||
| 665 | - int nypix = (*this)["nypix"].integer(); | 665 | + |
| 666 | + // Read sky map pixel size and number of bins | ||
| 667 | + double binsz = (*this)["binsz"].real(); | ||
| 668 | + int nxpix = (*this)["nxpix"].integer(); | ||
| 669 | + int nypix = (*this)["nypix"].integer(); | ||
| 666 | 670 | ||
| 667 | // If requested, get pointing from observations | 671 | // If requested, get pointing from observations |
| 668 | if (usepnt) { | 672 | if (usepnt) { |