Commit 00269f87230ad10b1603bd6fed52bb2ce6d39226

Authored by Jürgen Knödlseder
1 parent 6857ea15

Implement vectorised response computation for COMPTEL (#3501)

ChangeLog
1   -2021-01-14
  1 +2021-01-15
2 2  
3 3 * Version 2.0.0 released
4 4 ========================
5 5  
  6 + Implement vectorised response computation for COMPTEL (#3501)
6 7 Fix response cache removal for vector cache (#3499)
7 8 Add GModelAssociation and GModelAssociations classes (#3469)
8 9 Add GSkyMap::correlate() method (#3461)
... ...
1 1 New Features and Important Changes in GammaLib 2.0.0
2 2  
3   -14 January 2021
  3 +15 January 2021
4 4  
5 5  
6 6 1. Introduction
... ... @@ -232,7 +232,7 @@ spatial model gradients (#3203).
232 232  
233 233 21. COMPTEL interface
234 234 ---------------------
235   -None
  235 +Implement vectorised response computation in GCOMResponse::irf_ptsrc() method (#3501).
236 236  
237 237  
238 238 22. INTEGRAL/SPI interface
... ...
README.md
1 1 GammaLib information
2 2 ====================
3   -* Version: 2.0.0.dev (14 January 2021)
  3 +* Version: 2.0.0.dev (15 January 2021)
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/2.0.rst
1 1 .. _2.0:
2 2  
3   -GammaLib 2.0 release (14 January 2021)
  3 +GammaLib 2.0 release (15 January 2021)
4 4 ======================================
5 5  
6 6 Overview
... ... @@ -27,6 +27,8 @@ Bug fixes
27 27 Improvements
28 28 ------------
29 29  
  30 +* [`3501 <https://cta-redmine.irap.omp.eu/issues/3501>`_] -
  31 + Implement vectorised response computation for COMPTEL
30 32 * [`3333 <https://cta-redmine.irap.omp.eu/issues/3333>`_] -
31 33 Integrate analytical gradients for energy dispersion computation
32 34 * [`3324 <https://cta-redmine.irap.omp.eu/issues/3324>`_] -
... ...
inst/com/include/GCOMResponse.hpp
1 1 /***************************************************************************
2 2 * GCOMResponse.hpp - COMPTEL Response class *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2012-2020 by Juergen Knoedlseder *
  4 + * copyright (C) 2012-2021 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -101,8 +101,6 @@ private:
101 101 void init_members(void);
102 102 void copy_members(const GCOMResponse& rsp);
103 103 void free_members(void);
104   - GVector irf_drm(const GModelSky& model,
105   - const GObservation& obs) const;
106 104  
107 105 // Overloaded virtual base class methods
108 106 virtual GVector irf_ptsrc(const GModelSky& model,
... ...
inst/com/src/GCOMResponse.cpp
1 1 /***************************************************************************
2 2 * GCOMResponse.cpp - COMPTEL Response class *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2012-2020 by Juergen Knoedlseder *
  4 + * copyright (C) 2012-2021 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -47,6 +47,7 @@
47 47 #include "GModelSpectralConst.hpp"
48 48 #include "GCOMResponse.hpp"
49 49 #include "GCOMObservation.hpp"
  50 +#include "GCOMEventCube.hpp"
50 51 #include "GCOMEventBin.hpp"
51 52 #include "GCOMInstDir.hpp"
52 53  
... ... @@ -57,7 +58,8 @@
57 58 #define G_NROI "GCOMResponse::nroi(GModelSky&, GEnergy&, GTime&, "\
58 59 "GObservation&)"
59 60 #define G_EBOUNDS "GCOMResponse::ebounds(GEnergy&)"
60   -#define G_IRF_DRM "GCOMResponse::irf_drm(GModelSky&, GObservation&)"
  61 +#define G_IRF_PTSRC "GCOMResponse::irf_ptsrc(GModelSky&, GObservation&, "\
  62 + "GMatrix*)"
61 63 #define G_IRF_RADIAL "GCOMResponse::irf_radial(GModelSky&, GObservation&, "\
62 64 "GMatrix*)"
63 65 #define G_IRF_ELLIPTICAL "GCOMResponse::irf_elliptical(GModelSky&, "\
... ... @@ -841,122 +843,155 @@ void GCOMResponse::free_members(void)
841 843  
842 844  
843 845 /***********************************************************************//**
844   - * @brief Return instrument response vector
  846 + * @brief Return instrument response to point source
845 847 *
846 848 * @param[in] model Sky model.
847 849 * @param[in] obs Observation.
848   - * @return Instrument response vector.
  850 + * @param[out] gradients Gradients matrix.
  851 + * @return Instrument response to point source for all events in
  852 + * observation.
849 853 *
850   - * @exception GException::invalid_argument
851   - * Invalid observation or event type specified.
852   - * @exception GException::feature_not_implemented
853   - * Computation for specified spatial model not implemented.
  854 + * Returns the instrument response to a point source for all events in the
  855 + * observations.
854 856 *
855   - * Returns the instrument response to a sky model for all events in a given
856   - * observation. The computation of the response is handled by the
857   - * GCOMObservation::drm() method that also will update the cube in case that
858   - * any of the parameters changes.
  857 + * @p gradients is an optional matrix where the number of rows corresponds
  858 + * to the number of events in the observation and the number of columns
  859 + * corresponds to the number of spatial model parameters. ince for point
  860 + * sources no gradients are computed, the method does not alter the
  861 + * content of @p gradients.
859 862 ***************************************************************************/
860   -GVector GCOMResponse::irf_drm(const GModelSky& model,
861   - const GObservation& obs) const
  863 +GVector GCOMResponse::irf_ptsrc(const GModelSky& model,
  864 + const GObservation& obs,
  865 + GMatrix* gradients) const
862 866 {
863   - // Get number of events
864   - int nevents = obs.events()->size();
  867 + // Extract COMPTEL observation
  868 + const GCOMObservation* obs_ptr = dynamic_cast<const GCOMObservation*>(&obs);
  869 + if (obs_ptr == NULL) {
  870 + std::string cls = std::string(typeid(&obs).name());
  871 + std::string msg = "Observation of type \""+cls+"\" is not a COMPTEL "
  872 + "observations. Please specify a COMPTEL observation "
  873 + "as argument.";
  874 + throw GException::invalid_argument(G_IRF_PTSRC, msg);
  875 + }
  876 +
  877 + // Extract COMPTEL event cube
  878 + const GCOMEventCube* cube = dynamic_cast<const GCOMEventCube*>(obs_ptr->events());
  879 + if (cube == NULL) {
  880 + std::string msg = "Observation \""+obs.name()+"\" ("+obs.id()+") does "
  881 + "not contain a COMPTEL event cube. Please specify "
  882 + "a COMPTEL observation containing and event cube.";
  883 + throw GException::invalid_argument(G_IRF_PTSRC, msg);
  884 + }
  885 +
  886 + // Get number of Chi/Psi pixels, Phibar layers and event bins
  887 + int npix = cube->naxis(0) * cube->naxis(1);
  888 + int nphibar = cube->naxis(2);
  889 + int nevents = cube->size();
865 890  
866 891 // Initialise result
867 892 GVector irfs(nevents);
868 893  
869   - // Get pointer to COMPTEL observation
870   - const GCOMObservation* comobs = dynamic_cast<const GCOMObservation*>(&obs);
871   - if (comobs == NULL) {
872   - std::string cls = std::string(typeid(&obs).name());
873   - std::string msg = "Observation of type \""+cls+"\" is not a "
874   - "COMPTEL observation. Please specify a COMPTEL "
875   - "observation as argument.";
876   - throw GException::invalid_argument(G_IRF_DRM, msg);
877   - }
  894 + // Get point source direction
  895 + GSkyDir srcDir =
  896 + static_cast<const GModelSpatialPointSource*>(model.spatial())->dir();
878 897  
879   - // Get reference to DRM
880   - const GCOMDri& drm = comobs->drm(model);
  898 + // Get IAQ normalisation (cm2): DRX (cm2 s) * DEADC / ONTIME (s)
  899 + double iaq_norm = obs_ptr->drx()(srcDir) * obs_ptr->deadc() /
  900 + obs_ptr->ontime();
881 901  
882   - // Extract model values from DRM cache
883   - for (int k = 0; k < nevents; ++k) {
884   - irfs[k] = drm[k];
885   - }
  902 + // Get pointer to DRG pixels
  903 + const double* drg = obs_ptr->drg().pixels();
886 904  
887   - // Return
888   - return irfs;
889   -}
  905 + // Loop over Chi and Psi
  906 + for (int ipix = 0; ipix < npix; ++ipix) {
890 907  
  908 + // Get pointer to event bin
  909 + const GCOMEventBin* bin = (*cube)[ipix];
891 910  
892   -/***********************************************************************//**
893   - * @brief Return instrument response to point source sky model
894   - *
895   - * @param[in] model Sky model.
896   - * @param[in] obs Observation.
897   - * @param[in] gradients Gradients matrix.
898   - * @return Instrument response to point source sky model.
899   - *
900   - * Returns the instrument response to a point source sky model for all
901   - * events.
902   - ***************************************************************************/
903   -GVector GCOMResponse::irf_ptsrc(const GModelSky& model,
904   - const GObservation& obs,
905   - GMatrix* gradients) const
906   -{
907   - // Get number of events
908   - int nevents = obs.events()->size();
  911 + // Get reference to instrument direction
  912 + const GCOMInstDir& obsDir = bin->dir();
909 913  
910   - // Initialise result
911   - GVector irfs(nevents);
  914 + // Get reference to Phigeo sky direction
  915 + const GSkyDir& phigeoDir = obsDir.dir();
912 916  
913   - // Check if spatial model has free parameters
914   - bool has_free_pars = model.spatial()->has_free_pars();
  917 + // Compute angle between true photon arrival direction and scatter
  918 + // direction (Chi,Psi)
  919 + double phigeo = srcDir.dist_deg(phigeoDir);
915 920  
916   - // If model has free parameters then compute IRF value for all events
917   - if (has_free_pars) {
918   -
919   - // Get point source direction
920   - GSkyDir srcDir =
921   - static_cast<const GModelSpatialPointSource*>(model.spatial())->dir();
922   -
923   - // Loop over events
924   - for (int k = 0; k < nevents; ++k) {
  921 + // Compute interpolation factors
  922 + double phirat = phigeo / m_phigeo_bin_size; // 0.5 at bin centre
  923 + int iphigeo = int(phirat); // index into which Phigeo falls
  924 + double eps = phirat - iphigeo - 0.5; // 0.0 at bin centre [-0.5, 0.5[
925 925  
926   - // Get reference to event
927   - const GEvent& event = *((*obs.events())[k]);
  926 + // If Phigeo is in range then compute the IRF value for all
  927 + // Phibar layers
  928 + if (iphigeo < m_phigeo_bins) {
928 929  
929   - // Get source energy and time (no dispersion)
930   - GEnergy srcEng = event.energy();
931   - GTime srcTime = event.time();
  930 + // Loop over Phibar
  931 + for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
932 932  
933   - // Setup photon
934   - GPhoton photon(srcDir, srcEng, srcTime);
  933 + // Get IAQ index
  934 + int i = iphibar * m_phigeo_bins + iphigeo;
935 935  
936   - // Get IRF value
937   - irfs[k] = this->irf(event, photon, obs);
  936 + // Initialise IAQ
  937 + double iaq = 0.0;
938 938  
939   - } // endfor: looped over events
  939 + // Compute IAQ
  940 + if (eps < 0.0) { // interpolate towards left
  941 + if (iphigeo > 0) {
  942 + iaq = (1.0 + eps) * m_iaq[i] - eps * m_iaq[i-1];
  943 + }
  944 + else {
  945 + iaq = (1.0 - eps) * m_iaq[i] + eps * m_iaq[i+1];
  946 + }
  947 + }
  948 + else { // interpolate towards right
  949 + if (iphigeo < m_phigeo_bins-1) {
  950 + iaq = (1.0 - eps) * m_iaq[i] + eps * m_iaq[i+1];
  951 + }
  952 + else {
  953 + iaq = (1.0 + eps) * m_iaq[i] - eps * m_iaq[i-1];
  954 + }
  955 + }
940 956  
941   - } // endif: model had free parameters
  957 + // Continue only if IAQ is positive
  958 + if (iaq > 0.0) {
942 959  
943   - // ... otherwise extract model from DRM cache
944   - else {
945   - irfs = irf_drm(model, obs);
946   - }
  960 + // Get DRI index
  961 + int idri = ipix + iphibar * npix;
947 962  
948   - // Return IRF value
  963 + // Compute IRF value
  964 + double irf = iaq * drg[idri] * iaq_norm;
  965 +
  966 + // Make sure that IRF is positive
  967 + if (irf < 0.0) {
  968 + irf = 0.0;
  969 + }
  970 +
  971 + // Store IRF value
  972 + irfs[idri] = irf;
  973 +
  974 + } // endif: IAQ was positive
  975 +
  976 + } // endfor: looped over Phibar
  977 +
  978 + } // endif: Phigeo was in valid range
  979 +
  980 + } // endfor: looped over Chi and Psi
  981 +
  982 + // Return IRF vector
949 983 return irfs;
950 984 }
951 985  
952 986  
953 987 /***********************************************************************//**
954   - * @brief Return instrument response to radial source sky model
  988 + * @brief Return instrument response to radial source
955 989 *
956 990 * @param[in] model Sky model.
957 991 * @param[in] obs Observation.
958   - * @param[in] gradients Gradients matrix.
959   - * @return Instrument response to radial source sky model.
  992 + * @param[out] gradients Gradients matrix.
  993 + * @return Instrument response to radial source for all events in
  994 + * observation.
960 995 *
961 996 * @todo Implement method.
962 997 ***************************************************************************/
... ... @@ -982,12 +1017,13 @@ GVector GCOMResponse::irf_radial(const GModelSky&amp; model,
982 1017  
983 1018  
984 1019 /***********************************************************************//**
985   - * @brief Return instrument response to elliptical source sky model
  1020 + * @brief Return instrument response to elliptical source
986 1021 *
987 1022 * @param[in] model Sky model.
988 1023 * @param[in] obs Observation.
989   - * @param[in] gradients Gradients matrix.
990   - * @return Instrument response to elliptical source sky model.
  1024 + * @param[out] gradients Gradients matrix.
  1025 + * @return Instrument response to elliptical source for all events in
  1026 + * observation.
991 1027 *
992 1028 * @todo Implement method.
993 1029 ***************************************************************************/
... ... @@ -1013,12 +1049,13 @@ GVector GCOMResponse::irf_elliptical(const GModelSky&amp; model,
1013 1049  
1014 1050  
1015 1051 /***********************************************************************//**
1016   - * @brief Return instrument response to diffuse source sky model
  1052 + * @brief Return instrument response to diffuse source
1017 1053 *
1018 1054 * @param[in] model Sky model.
1019 1055 * @param[in] obs Observation.
1020   - * @param[in] gradients Gradients matrix.
1021   - * @return Instrument response to diffuse source sky model.
  1056 + * @param[out] gradients Gradients matrix.
  1057 + * @return Instrument response to diffuse source for all events in
  1058 + * observation.
1022 1059 *
1023 1060 * @todo Implement method.
1024 1061 ***************************************************************************/
... ...
inst/cta/src/GCTAResponseCube.cpp
... ... @@ -1618,9 +1618,9 @@ double GCTAResponseCube::irf_diffuse(const GEvent&amp; event,
1618 1618 *
1619 1619 * Returns the instrument response to a specified radial source.
1620 1620 *
1621   - * @p gradients is an optional sparse matrix where the number of rows
1622   - * corresponds to the number of events in the observation and the number
1623   - * of columns corresponds to the number of spatial model parameters.
  1621 + * @p gradients is an optional matrix where the number of rows corresponds
  1622 + * to the number of events in the observation and the number of columns
  1623 + * corresponds to the number of spatial model parameters.
1624 1624 ***************************************************************************/
1625 1625 GVector GCTAResponseCube::irf_radial(const GModelSky& model,
1626 1626 const GObservation& obs,
... ...