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 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)
... ...
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
1 1 GammaLib information
2 2 ====================
3   -* Version: 1.7.1 (7 August 2020)
  3 +* Version: 1.7.1 (8 August 2020)
4 4  
5 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 .. _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&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 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&amp; 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 }
... ...