Commit bc5cda86b1fbf8e2a77361ab2d98b229cca5a0b8
1 parent
30832424
Implement specific response cache for CTA stacked analysis (#3316)
Showing
7 changed files
with
230 additions
and
23 deletions
ChangeLog
| 1 | -2020-08-07 | |
| 1 | +2020-08-08 | |
| 2 | 2 | |
| 3 | 3 | * Bug fix version 1.7.1 released |
| 4 | 4 | ================================ |
| 5 | 5 | |
| 6 | + Implement specific response cache for CTA stacked analysis (#3316) | |
| 6 | 7 | Speed up model definition XML file writing (#3308) |
| 7 | - Switch off response cache for stacked CTA analysis (#3305) | |
| 8 | 8 | Fix automatic type casting in Python interface (#3295) |
| 9 | 9 | Make parameter file reading and writing thread safe (#3287) |
| 10 | 10 | Add quotes to sky region names (#3280) | ... | ... |
NEWS
| 1 | 1 | New Features and Important Changes in GammaLib 1.7.1 |
| 2 | 2 | |
| 3 | -7 August 2020 | |
| 3 | +8 August 2020 | |
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | 1. Introduction |
| ... | ... | @@ -144,8 +144,10 @@ None |
| 144 | 144 | |
| 145 | 145 | 20. CTA interface |
| 146 | 146 | ----------------- |
| 147 | -The response cache was switched off for CTA stacked analysis since it used up | |
| 148 | -too much memory in case that many sources needed to be cached (#3305). | |
| 147 | +A specific response cache was implemented for the stacked analysis that reduces | |
| 148 | +the memory requirements by at least a factor of 6. Instead of using the std::map | |
| 149 | +cache, the full data-space is cached, avoiding the need for any bookkeeping | |
| 150 | +(#3316). | |
| 149 | 151 | |
| 150 | 152 | |
| 151 | 153 | 21. COMPTEL interface | ... | ... |
README.md
doc/source/admin/release_history/1.7.1.rst
| 1 | 1 | .. _1.7.1: |
| 2 | 2 | |
| 3 | -GammaLib 1.7.1 release (7 August 2020) | |
| 3 | +GammaLib 1.7.1 release (8 August 2020) | |
| 4 | 4 | ====================================== |
| 5 | 5 | |
| 6 | 6 | Overview |
| ... | ... | @@ -10,10 +10,10 @@ GammaLib 1.7.1 is a bug fix release for GammaLib release 1.7. |
| 10 | 10 | |
| 11 | 11 | The following bugs were fixed: |
| 12 | 12 | |
| 13 | +* [`3316 <https://cta-redmine.irap.omp.eu/issues/3316>`_] - | |
| 14 | + Implement specific response cache for CTA stacked analysis | |
| 13 | 15 | * [`3308 <https://cta-redmine.irap.omp.eu/issues/3308>`_] - |
| 14 | 16 | Speed up model definition XML file writing |
| 15 | -* [`3305 <https://cta-redmine.irap.omp.eu/issues/3305>`_] - | |
| 16 | - Switch off response cache for stacked CTA analysis | |
| 17 | 17 | * [`3295 <https://cta-redmine.irap.omp.eu/issues/3295>`_] - |
| 18 | 18 | Fix automatic type casting in Python interface |
| 19 | 19 | * [`3287 <https://cta-redmine.irap.omp.eu/issues/3287>`_] - | ... | ... |
inst/cta/include/GCTAResponseCube.hpp
| ... | ... | @@ -30,6 +30,7 @@ |
| 30 | 30 | /* __ Includes ___________________________________________________________ */ |
| 31 | 31 | #include <string> |
| 32 | 32 | #include <vector> |
| 33 | +#include "GNdarray.hpp" | |
| 33 | 34 | #include "GCTAResponse.hpp" |
| 34 | 35 | #include "GCTACubeExposure.hpp" |
| 35 | 36 | #include "GCTACubePsf.hpp" |
| ... | ... | @@ -97,6 +98,11 @@ public: |
| 97 | 98 | virtual void write(GXmlElement& xml) const; |
| 98 | 99 | virtual std::string print(const GChatter& chatter = NORMAL) const; |
| 99 | 100 | |
| 101 | + // Overloaded virtual base class methods | |
| 102 | + virtual double irf_spatial(const GEvent& event, | |
| 103 | + const GSource& source, | |
| 104 | + const GObservation& obs) const; | |
| 105 | + | |
| 100 | 106 | // Other Methods |
| 101 | 107 | const GCTACubeExposure& exposure(void) const; |
| 102 | 108 | void exposure(const GCTACubeExposure& exposure); |
| ... | ... | @@ -147,6 +153,10 @@ private: |
| 147 | 153 | GCTACubeEdisp m_edisp; //!< Energy dispersion cube |
| 148 | 154 | mutable bool m_apply_edisp; //!< Apply energy dispersion |
| 149 | 155 | mutable bool m_has_edisp; //!< Flag to indicate if energy |
| 156 | + | |
| 157 | + // Kludge: cube response cache | |
| 158 | + mutable std::vector<std::string> m_cache_names; //!< Model names | |
| 159 | + mutable std::vector<GNdarray> m_cache_values; //!< Cached values | |
| 150 | 160 | }; |
| 151 | 161 | |
| 152 | 162 | ... | ... |
inst/cta/pyext/GCTAResponseCube.i
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * GCTAResponseCube.i - CTA cube analysis response function class * |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2014-2018 by Juergen Knoedlseder * | |
| 4 | + * copyright (C) 2014-2020 by Juergen Knoedlseder * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -68,6 +68,11 @@ public: |
| 68 | 68 | virtual void read(const GXmlElement& xml); |
| 69 | 69 | virtual void write(GXmlElement& xml) const; |
| 70 | 70 | |
| 71 | + // Overloaded virtual base class methods | |
| 72 | + virtual double irf_spatial(const GEvent& event, | |
| 73 | + const GSource& source, | |
| 74 | + const GObservation& obs) const; | |
| 75 | + | |
| 71 | 76 | // Other Methods |
| 72 | 77 | const GCTACubeExposure& exposure(void) const; |
| 73 | 78 | void exposure(const GCTACubeExposure& exposure); | ... | ... |
inst/cta/src/GCTAResponseCube.cpp
| ... | ... | @@ -31,17 +31,6 @@ |
| 31 | 31 | #include <cmath> |
| 32 | 32 | #include <string> |
| 33 | 33 | #include "GTools.hpp" |
| 34 | -#include "GCTAResponseCube.hpp" | |
| 35 | -#include "GCTAResponse_helpers.hpp" | |
| 36 | -#include "GCTAInstDir.hpp" | |
| 37 | -#include "GCTAEventBin.hpp" | |
| 38 | -#include "GCTASupport.hpp" | |
| 39 | -#include "GModelSpatialPointSource.hpp" | |
| 40 | -#include "GModelSpatialRadial.hpp" | |
| 41 | -#include "GModelSpatialRadialShell.hpp" | |
| 42 | -#include "GModelSpatialElliptical.hpp" | |
| 43 | -#include "GModelSpatialComposite.hpp" | |
| 44 | -#include "GModelSpatialDiffuse.hpp" | |
| 45 | 34 | #include "GPhoton.hpp" |
| 46 | 35 | #include "GSource.hpp" |
| 47 | 36 | #include "GEvent.hpp" |
| ... | ... | @@ -50,6 +39,19 @@ |
| 50 | 39 | #include "GTime.hpp" |
| 51 | 40 | #include "GIntegral.hpp" |
| 52 | 41 | #include "GObservation.hpp" |
| 42 | +#include "GModelSpatialPointSource.hpp" | |
| 43 | +#include "GModelSpatialRadial.hpp" | |
| 44 | +#include "GModelSpatialRadialShell.hpp" | |
| 45 | +#include "GModelSpatialElliptical.hpp" | |
| 46 | +#include "GModelSpatialComposite.hpp" | |
| 47 | +#include "GModelSpatialDiffuse.hpp" | |
| 48 | +#include "GCTAResponseCube.hpp" | |
| 49 | +#include "GCTAResponse_helpers.hpp" | |
| 50 | +#include "GCTAInstDir.hpp" | |
| 51 | +#include "GCTAEventBin.hpp" | |
| 52 | +#include "GCTASupport.hpp" | |
| 53 | +#include "GCTAEventCube.hpp" // Kludge | |
| 54 | +#include "GCTAEventBin.hpp" // Kludge | |
| 53 | 55 | |
| 54 | 56 | /* __ Method name definitions ____________________________________________ */ |
| 55 | 57 | #define G_IRF "GCTAResponseCube::irf(GEvent&, GPhoton& GObservation&)" |
| ... | ... | @@ -443,6 +445,188 @@ GEbounds GCTAResponseCube::ebounds(const GEnergy& obsEng) const |
| 443 | 445 | |
| 444 | 446 | |
| 445 | 447 | /***********************************************************************//** |
| 448 | + * @brief Return instrument response integrated over the spatial model | |
| 449 | + * | |
| 450 | + * @param[in] event Event. | |
| 451 | + * @param[in] source Source. | |
| 452 | + * @param[in] obs Observation. | |
| 453 | + * @return Instrument response to a spatial model. | |
| 454 | + * | |
| 455 | + * Returns the instrument response for a given event, source and observation | |
| 456 | + * integrated over the spatial model component. The method computes | |
| 457 | + * | |
| 458 | + * \f[ | |
| 459 | + * {\tt irf}(p', E', t') = \int_p M_{\rm S}(p | E, t) \, | |
| 460 | + * R(p', E', t' | p, E, t) \, d\,p | |
| 461 | + * \f] | |
| 462 | + * | |
| 463 | + * where | |
| 464 | + * * \f$M_{\rm S}(p | E, t)\f$ is the spatial model component, | |
| 465 | + * * \f$R(p', E', t' | p, E, t)\f$ is the Instrument Response Function (IRF), | |
| 466 | + * * \f$p'\f$ is the measured instrument direction, | |
| 467 | + * * \f$E'\f$ is the measured or reconstructed energy, | |
| 468 | + * * \f$t'\f$ is the measured arrival time, | |
| 469 | + * * \f$p\f$ is the true photon arrival direction, | |
| 470 | + * * \f$E\f$ is the true photon energy, and | |
| 471 | + * * \f$t\f$ is the true trigger time. | |
| 472 | + * | |
| 473 | + * The integration is done over all relevant true sky directions \f$p\f$. | |
| 474 | + * | |
| 475 | + * Depending on the type of the source model the method branches to the | |
| 476 | + * following methods to perform the actual computations | |
| 477 | + * | |
| 478 | + * irf_ptsrc() - for the handling of a point source | |
| 479 | + * irf_radial() - for radial models | |
| 480 | + * irf_elliptical() - for elliptical models | |
| 481 | + * irf_diffuse() - for diffuse models | |
| 482 | + * irf_composite() - for composite models | |
| 483 | + * | |
| 484 | + * The method implements a caching mechanism for spatial models that have all | |
| 485 | + * parameters fixed. For those models the instrument response for a given | |
| 486 | + * event and observation is only computed once and then stored in an internal | |
| 487 | + * cache from which it is fetched back in case that the method is called | |
| 488 | + * again for the same event and observation. | |
| 489 | + ***************************************************************************/ | |
| 490 | +double GCTAResponseCube::irf_spatial(const GEvent& event, | |
| 491 | + const GSource& source, | |
| 492 | + const GObservation& obs) const | |
| 493 | +{ | |
| 494 | + // Initialise IRF value | |
| 495 | + double irf = 0.0; | |
| 496 | + | |
| 497 | + // Set IRF value attributes | |
| 498 | + std::string name = obs.id() + "::" + source.name(); | |
| 499 | + const GInstDir& dir = event.dir(); | |
| 500 | + const GEnergy& ereco = event.energy(); | |
| 501 | + const GEnergy& etrue = source.energy(); | |
| 502 | + | |
| 503 | + // Signal if spatial model has free parameters | |
| 504 | + bool has_free_pars = source.model()->has_free_pars(); | |
| 505 | + | |
| 506 | + // Kludge: the IRF response cache should be used, the model has no | |
| 507 | + // free parameters and there is no energy dispersion | |
| 508 | + if (m_use_irf_cache && !has_free_pars && !use_edisp()) { | |
| 509 | + | |
| 510 | + // Build unique cache name | |
| 511 | + std::string name = obs.id() + "::" + source.name(); | |
| 512 | + | |
| 513 | + // Get index in cache, returns -1 if name is not found in cache | |
| 514 | + int index = -1; | |
| 515 | + for (int i = 0; i < m_cache_names.size(); ++i) { | |
| 516 | + if (m_cache_names[i] == name) { | |
| 517 | + index = i; | |
| 518 | + break; | |
| 519 | + } | |
| 520 | + } | |
| 521 | + | |
| 522 | + // If index was not found then allocate a new cache map | |
| 523 | + if (index == -1) { | |
| 524 | + | |
| 525 | + // Get pointer to event cube | |
| 526 | + const GCTAEventCube* cube = | |
| 527 | + static_cast<const GCTAEventCube*>(obs.events()); | |
| 528 | + | |
| 529 | + // Allocate cache | |
| 530 | + GNdarray cache(cube->nx()*cube->ny(), cube->ebins()); | |
| 531 | + | |
| 532 | + // Initialise all cache values with -1 (not set) | |
| 533 | + for (int i = 0; i < cache.size(); ++i) { | |
| 534 | + cache(i) = -1.0; | |
| 535 | + } | |
| 536 | + | |
| 537 | + // Insert cache | |
| 538 | + m_cache_names.push_back(name); | |
| 539 | + m_cache_values.push_back(cache); | |
| 540 | + | |
| 541 | + // Set index | |
| 542 | + index = m_cache_names.size()-1; | |
| 543 | + | |
| 544 | + } // endif: allocated new cache | |
| 545 | + | |
| 546 | + // Get reference to CTA event bin | |
| 547 | + const GCTAEventBin& bin = static_cast<const GCTAEventBin&>(event); | |
| 548 | + | |
| 549 | + // Get cache value | |
| 550 | + irf = m_cache_values[index](bin.ipix(), bin.ieng()); | |
| 551 | + | |
| 552 | + // If cache value is not valid then copute IRF | |
| 553 | + if (irf < 0.0) { | |
| 554 | + | |
| 555 | + // Compute IRF for spatial model | |
| 556 | + switch (source.model()->code()) { | |
| 557 | + case GMODEL_SPATIAL_POINT_SOURCE: | |
| 558 | + irf = irf_ptsrc(event, source, obs); | |
| 559 | + break; | |
| 560 | + case GMODEL_SPATIAL_RADIAL: | |
| 561 | + irf = irf_radial(event, source, obs); | |
| 562 | + break; | |
| 563 | + case GMODEL_SPATIAL_ELLIPTICAL: | |
| 564 | + irf = irf_elliptical(event, source, obs); | |
| 565 | + break; | |
| 566 | + case GMODEL_SPATIAL_DIFFUSE: | |
| 567 | + irf = irf_diffuse(event, source, obs); | |
| 568 | + break; | |
| 569 | + case GMODEL_SPATIAL_COMPOSITE: | |
| 570 | + irf = irf_composite(event, source, obs); | |
| 571 | + break; | |
| 572 | + default: | |
| 573 | + break; | |
| 574 | + } | |
| 575 | + | |
| 576 | + // Set cache value | |
| 577 | + m_cache_values[index](bin.ipix(), bin.ieng()) = irf; | |
| 578 | + | |
| 579 | + } // endif: computed IRF | |
| 580 | + | |
| 581 | + } // endif: kludge | |
| 582 | + | |
| 583 | + // ... otherwise use release 1.7 response cache | |
| 584 | + else { | |
| 585 | + | |
| 586 | + // If the spatial model component has free parameters, or the response | |
| 587 | + // cache should not be used, or the cache does not contain the requested | |
| 588 | + // IRF value then compute the IRF value for the spatial model. | |
| 589 | + if (has_free_pars || | |
| 590 | + !m_use_irf_cache || | |
| 591 | + !m_irf_cache.contains(name, dir, ereco, etrue, &irf)) { | |
| 592 | + | |
| 593 | + // Compute IRF for spatial model | |
| 594 | + switch (source.model()->code()) { | |
| 595 | + case GMODEL_SPATIAL_POINT_SOURCE: | |
| 596 | + irf = irf_ptsrc(event, source, obs); | |
| 597 | + break; | |
| 598 | + case GMODEL_SPATIAL_RADIAL: | |
| 599 | + irf = irf_radial(event, source, obs); | |
| 600 | + break; | |
| 601 | + case GMODEL_SPATIAL_ELLIPTICAL: | |
| 602 | + irf = irf_elliptical(event, source, obs); | |
| 603 | + break; | |
| 604 | + case GMODEL_SPATIAL_DIFFUSE: | |
| 605 | + irf = irf_diffuse(event, source, obs); | |
| 606 | + break; | |
| 607 | + case GMODEL_SPATIAL_COMPOSITE: | |
| 608 | + irf = irf_composite(event, source, obs); | |
| 609 | + break; | |
| 610 | + default: | |
| 611 | + break; | |
| 612 | + } | |
| 613 | + | |
| 614 | + } // endif: computed spatial model | |
| 615 | + | |
| 616 | + // If the spatial model has no free parameters and the response cache | |
| 617 | + // should be used then put the IRF value in the response cache. | |
| 618 | + if (!has_free_pars && m_use_irf_cache) { | |
| 619 | + m_irf_cache.set(name, dir, ereco, etrue, irf); | |
| 620 | + } | |
| 621 | + | |
| 622 | + } // endelse: used release 1.7 response cache | |
| 623 | + | |
| 624 | + // Return IRF value | |
| 625 | + return irf; | |
| 626 | +} | |
| 627 | + | |
| 628 | + | |
| 629 | +/***********************************************************************//** | |
| 446 | 630 | * @brief Read response information from XML element |
| 447 | 631 | * |
| 448 | 632 | * @param[in] xml XML element. |
| ... | ... | @@ -635,8 +819,10 @@ void GCTAResponseCube::init_members(void) |
| 635 | 819 | m_background.clear(); |
| 636 | 820 | m_apply_edisp = false; |
| 637 | 821 | m_has_edisp = false; |
| 638 | - m_use_irf_cache = false; //!< Current response cache uses too | |
| 639 | - m_use_nroi_cache = false; //!< much memory (#3305) | |
| 822 | + | |
| 823 | + // Kludge: Initialise cube response cache | |
| 824 | + m_cache_names.clear(); | |
| 825 | + m_cache_values.clear(); | |
| 640 | 826 | |
| 641 | 827 | // Return |
| 642 | 828 | return; |
| ... | ... | @@ -658,6 +844,10 @@ void GCTAResponseCube::copy_members(const GCTAResponseCube& rsp) |
| 658 | 844 | m_apply_edisp = rsp.m_apply_edisp; |
| 659 | 845 | m_has_edisp = rsp.m_has_edisp; |
| 660 | 846 | |
| 847 | + // Kludge: Copy cube response cache | |
| 848 | + m_cache_names = rsp.m_cache_names; | |
| 849 | + m_cache_values = rsp.m_cache_values; | |
| 850 | + | |
| 661 | 851 | // Return |
| 662 | 852 | return; |
| 663 | 853 | } | ... | ... |