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 | * Bug fix version 1.7.1 released | 3 | * Bug fix version 1.7.1 released |
| 4 | ================================ | 4 | ================================ |
| 5 | 5 | ||
| 6 | + Implement specific response cache for CTA stacked analysis (#3316) | ||
| 6 | Speed up model definition XML file writing (#3308) | 7 | Speed up model definition XML file writing (#3308) |
| 7 | - Switch off response cache for stacked CTA analysis (#3305) | ||
| 8 | Fix automatic type casting in Python interface (#3295) | 8 | Fix automatic type casting in Python interface (#3295) |
| 9 | Make parameter file reading and writing thread safe (#3287) | 9 | Make parameter file reading and writing thread safe (#3287) |
| 10 | Add quotes to sky region names (#3280) | 10 | Add quotes to sky region names (#3280) |
NEWS
| 1 | New Features and Important Changes in GammaLib 1.7.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 | 1. Introduction | 6 | 1. Introduction |
| @@ -144,8 +144,10 @@ None | @@ -144,8 +144,10 @@ None | ||
| 144 | 144 | ||
| 145 | 20. CTA interface | 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 | 21. COMPTEL interface | 153 | 21. COMPTEL interface |
README.md
| 1 | GammaLib information | 1 | GammaLib information |
| 2 | ==================== | 2 | ==================== |
| 3 | -* Version: 1.7.1 (7 August 2020) | 3 | +* Version: 1.7.1 (8 August 2020) |
| 4 | 4 | ||
| 5 | [](https://cta-jenkins.irap.omp.eu/job/gammalib-integrate-os/) | 5 | [](https://cta-jenkins.irap.omp.eu/job/gammalib-integrate-os/) |
| 6 | 6 |
doc/source/admin/release_history/1.7.1.rst
| 1 | .. _1.7.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 | Overview | 6 | Overview |
| @@ -10,10 +10,10 @@ GammaLib 1.7.1 is a bug fix release for GammaLib release 1.7. | @@ -10,10 +10,10 @@ GammaLib 1.7.1 is a bug fix release for GammaLib release 1.7. | ||
| 10 | 10 | ||
| 11 | The following bugs were fixed: | 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 | * [`3308 <https://cta-redmine.irap.omp.eu/issues/3308>`_] - | 15 | * [`3308 <https://cta-redmine.irap.omp.eu/issues/3308>`_] - |
| 14 | Speed up model definition XML file writing | 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 | * [`3295 <https://cta-redmine.irap.omp.eu/issues/3295>`_] - | 17 | * [`3295 <https://cta-redmine.irap.omp.eu/issues/3295>`_] - |
| 18 | Fix automatic type casting in Python interface | 18 | Fix automatic type casting in Python interface |
| 19 | * [`3287 <https://cta-redmine.irap.omp.eu/issues/3287>`_] - | 19 | * [`3287 <https://cta-redmine.irap.omp.eu/issues/3287>`_] - |
inst/cta/include/GCTAResponseCube.hpp
| @@ -30,6 +30,7 @@ | @@ -30,6 +30,7 @@ | ||
| 30 | /* __ Includes ___________________________________________________________ */ | 30 | /* __ Includes ___________________________________________________________ */ |
| 31 | #include <string> | 31 | #include <string> |
| 32 | #include <vector> | 32 | #include <vector> |
| 33 | +#include "GNdarray.hpp" | ||
| 33 | #include "GCTAResponse.hpp" | 34 | #include "GCTAResponse.hpp" |
| 34 | #include "GCTACubeExposure.hpp" | 35 | #include "GCTACubeExposure.hpp" |
| 35 | #include "GCTACubePsf.hpp" | 36 | #include "GCTACubePsf.hpp" |
| @@ -97,6 +98,11 @@ public: | @@ -97,6 +98,11 @@ public: | ||
| 97 | virtual void write(GXmlElement& xml) const; | 98 | virtual void write(GXmlElement& xml) const; |
| 98 | virtual std::string print(const GChatter& chatter = NORMAL) const; | 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 | // Other Methods | 106 | // Other Methods |
| 101 | const GCTACubeExposure& exposure(void) const; | 107 | const GCTACubeExposure& exposure(void) const; |
| 102 | void exposure(const GCTACubeExposure& exposure); | 108 | void exposure(const GCTACubeExposure& exposure); |
| @@ -147,6 +153,10 @@ private: | @@ -147,6 +153,10 @@ private: | ||
| 147 | GCTACubeEdisp m_edisp; //!< Energy dispersion cube | 153 | GCTACubeEdisp m_edisp; //!< Energy dispersion cube |
| 148 | mutable bool m_apply_edisp; //!< Apply energy dispersion | 154 | mutable bool m_apply_edisp; //!< Apply energy dispersion |
| 149 | mutable bool m_has_edisp; //!< Flag to indicate if energy | 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 | * GCTAResponseCube.i - CTA cube analysis response function class * | 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 | * 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 * |
| @@ -68,6 +68,11 @@ public: | @@ -68,6 +68,11 @@ public: | ||
| 68 | virtual void read(const GXmlElement& xml); | 68 | virtual void read(const GXmlElement& xml); |
| 69 | virtual void write(GXmlElement& xml) const; | 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 | // Other Methods | 76 | // Other Methods |
| 72 | const GCTACubeExposure& exposure(void) const; | 77 | const GCTACubeExposure& exposure(void) const; |
| 73 | void exposure(const GCTACubeExposure& exposure); | 78 | void exposure(const GCTACubeExposure& exposure); |
inst/cta/src/GCTAResponseCube.cpp
| @@ -31,17 +31,6 @@ | @@ -31,17 +31,6 @@ | ||
| 31 | #include <cmath> | 31 | #include <cmath> |
| 32 | #include <string> | 32 | #include <string> |
| 33 | #include "GTools.hpp" | 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 | #include "GPhoton.hpp" | 34 | #include "GPhoton.hpp" |
| 46 | #include "GSource.hpp" | 35 | #include "GSource.hpp" |
| 47 | #include "GEvent.hpp" | 36 | #include "GEvent.hpp" |
| @@ -50,6 +39,19 @@ | @@ -50,6 +39,19 @@ | ||
| 50 | #include "GTime.hpp" | 39 | #include "GTime.hpp" |
| 51 | #include "GIntegral.hpp" | 40 | #include "GIntegral.hpp" |
| 52 | #include "GObservation.hpp" | 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 | /* __ Method name definitions ____________________________________________ */ | 56 | /* __ Method name definitions ____________________________________________ */ |
| 55 | #define G_IRF "GCTAResponseCube::irf(GEvent&, GPhoton& GObservation&)" | 57 | #define G_IRF "GCTAResponseCube::irf(GEvent&, GPhoton& GObservation&)" |
| @@ -443,6 +445,188 @@ GEbounds GCTAResponseCube::ebounds(const GEnergy& obsEng) const | @@ -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 | * @brief Read response information from XML element | 630 | * @brief Read response information from XML element |
| 447 | * | 631 | * |
| 448 | * @param[in] xml XML element. | 632 | * @param[in] xml XML element. |
| @@ -635,8 +819,10 @@ void GCTAResponseCube::init_members(void) | @@ -635,8 +819,10 @@ void GCTAResponseCube::init_members(void) | ||
| 635 | m_background.clear(); | 819 | m_background.clear(); |
| 636 | m_apply_edisp = false; | 820 | m_apply_edisp = false; |
| 637 | m_has_edisp = false; | 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 | // Return | 827 | // Return |
| 642 | return; | 828 | return; |
| @@ -658,6 +844,10 @@ void GCTAResponseCube::copy_members(const GCTAResponseCube& rsp) | @@ -658,6 +844,10 @@ void GCTAResponseCube::copy_members(const GCTAResponseCube& rsp) | ||
| 658 | m_apply_edisp = rsp.m_apply_edisp; | 844 | m_apply_edisp = rsp.m_apply_edisp; |
| 659 | m_has_edisp = rsp.m_has_edisp; | 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 | // Return | 851 | // Return |
| 662 | return; | 852 | return; |
| 663 | } | 853 | } |