Commit bc5cda86b1fbf8e2a77361ab2d98b229cca5a0b8

Authored by Jürgen Knödlseder
1 parent 30832424

Implement specific response cache for CTA stacked analysis (#3316)

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)
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 [![Build Status](https://cta-jenkins.irap.omp.eu/buildStatus/icon?job=gammalib-integrate-os)](https://cta-jenkins.irap.omp.eu/job/gammalib-integrate-os/) 5 [![Build Status](https://cta-jenkins.irap.omp.eu/buildStatus/icon?job=gammalib-integrate-os)](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&amp; obsEng) const @@ -443,6 +445,188 @@ GEbounds GCTAResponseCube::ebounds(const GEnergy&amp; 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&amp; rsp) @@ -658,6 +844,10 @@ void GCTAResponseCube::copy_members(const GCTAResponseCube&amp; 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 }