Commit 640e93f42ca416c210985765b098239e4b2c8930
1 parent
bd7183cb
Remove diffuse model caching for stacked analysis (#2722)
Showing
5 changed files
with
154 additions
and
44 deletions
ChangeLog
| 1 | -2018-11-09 | |
| 1 | +2018-11-12 | |
| 2 | 2 | |
| 3 | 3 | * Version 1.6.0 released |
| 4 | 4 | ======================== |
| 5 | 5 | |
| 6 | + Remove diffuse response cube caching (#2722) | |
| 6 | 7 | Revise GCTAEdispCube::operator() interface and disable stacked response |
| 7 | 8 | cutting in true energy (#2721) |
| 8 | 9 | Rename GCTAResponseIrf::lo_save_thres() and GCTAResponseIrf::hi_save_thres() | ... | ... |
NEWS
| 1 | 1 | New Features and Important Changes in GammaLib 1.6.0 |
| 2 | 2 | |
| 3 | -9 November 2018 | |
| 3 | +12 November 2018 | |
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | 1. Introduction |
| ... | ... | @@ -21,7 +21,8 @@ The following classes have been added: |
| 21 | 21 | - GCTAModelSpatialRegistry |
| 22 | 22 | |
| 23 | 23 | The following classes have been removed: |
| 24 | -- none | |
| 24 | +- GCTACubeSourceDiffuse | |
| 25 | +- GCTACubeSourcePoint | |
| 25 | 26 | |
| 26 | 27 | The following classes have been renamed: |
| 27 | 28 | - none |
| ... | ... | @@ -314,6 +315,10 @@ None |
| 314 | 315 | |
| 315 | 316 | 20. CTA interface |
| 316 | 317 | ----------------- |
| 318 | +The classes GCTACubeSourcePoint and GCTACubeSourceDiffuse were removed since | |
| 319 | +the response caching is now performed at the GCTAResponse level, hence no | |
| 320 | +dedicated response cache classes are needed anymore (#2722). | |
| 321 | + | |
| 317 | 322 | The arguments of the GCTACubeEdisp::operator() were changed from, passing |
| 318 | 323 | now reconstructed and true energy objects, followed by a true sky direction. |
| 319 | 324 | This is more consistent with the GCTAEdisp interface. The stacked response | ... | ... |
inst/cta/Makefile.am
| ... | ... | @@ -70,8 +70,6 @@ sources = src/GCTASupport.cpp \ |
| 70 | 70 | src/GCTACubePsf.cpp \ |
| 71 | 71 | src/GCTACubeEdisp.cpp \ |
| 72 | 72 | src/GCTACubeSource.cpp \ |
| 73 | - src/GCTACubeSourcePoint.cpp \ | |
| 74 | - src/GCTACubeSourceDiffuse.cpp \ | |
| 75 | 73 | src/GCTAInstDir.cpp \ |
| 76 | 74 | src/GCTARoi.cpp \ |
| 77 | 75 | src/GCTAPointing.cpp \ |
| ... | ... | @@ -129,8 +127,6 @@ pkginclude_HEADERS = include/GCTATypemaps.hpp \ |
| 129 | 127 | include/GCTACubeEdisp.hpp \ |
| 130 | 128 | include/GCTACubeBackground.hpp \ |
| 131 | 129 | include/GCTACubeSource.hpp \ |
| 132 | - include/GCTACubeSourcePoint.hpp \ | |
| 133 | - include/GCTACubeSourceDiffuse.hpp \ | |
| 134 | 130 | include/GCTAModelBackground.hpp \ |
| 135 | 131 | include/GCTAModelSpatial.hpp \ |
| 136 | 132 | include/GCTAModelSpatialGradient.hpp \ | ... | ... |
inst/cta/include/GCTAResponseCube.hpp
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * GCTAResponseCube.hpp - CTA cube analysis response function class * |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2014-2016 by Juergen Knoedlseder * | |
| 4 | + * copyright (C) 2014-2018 by Juergen Knoedlseder * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -124,6 +124,10 @@ private: |
| 124 | 124 | const GSkyDir& obsDir, |
| 125 | 125 | const GEnergy& srcEng, |
| 126 | 126 | const GTime& srcTime) const; |
| 127 | + double psf_diffuse(const GModelSpatial* model, | |
| 128 | + const GSkyDir& obsDir, | |
| 129 | + const GEnergy& srcEng, | |
| 130 | + const GTime& srcTime) const; | |
| 127 | 131 | double irf_ptsrc(const GEvent& event, |
| 128 | 132 | const GSource& source, |
| 129 | 133 | const GObservation& obs) const; | ... | ... |
inst/cta/src/GCTAResponseCube.cpp
| ... | ... | @@ -33,7 +33,6 @@ |
| 33 | 33 | #include "GTools.hpp" |
| 34 | 34 | #include "GCTAResponseCube.hpp" |
| 35 | 35 | #include "GCTAResponse_helpers.hpp" |
| 36 | -#include "GCTACubeSourceDiffuse.hpp" | |
| 37 | 36 | #include "GCTAInstDir.hpp" |
| 38 | 37 | #include "GCTAEventBin.hpp" |
| 39 | 38 | #include "GCTASupport.hpp" |
| ... | ... | @@ -1089,6 +1088,89 @@ double GCTAResponseCube::psf_elliptical(const GModelSpatialElliptical* model, |
| 1089 | 1088 | |
| 1090 | 1089 | |
| 1091 | 1090 | /***********************************************************************//** |
| 1091 | + * @brief Integrate PSF over diffuse model | |
| 1092 | + * | |
| 1093 | + * @param[in] model Diffuse spatial model. | |
| 1094 | + * @param[in] obsDir Observed event direction. | |
| 1095 | + * @param[in] srcEng True photon energy. | |
| 1096 | + * @param[in] srcTime True photon arrival time. | |
| 1097 | + * | |
| 1098 | + * Computes the integral | |
| 1099 | + * | |
| 1100 | + * \f[ | |
| 1101 | + * \int_0^{\delta_{\rm max}} | |
| 1102 | + * {\rm PSF}(\delta) \times | |
| 1103 | + * \int_0^{2\pi} {\rm Map}(\delta, \phi) \sin \delta | |
| 1104 | + * {\rm d}\phi {\rm d}\delta | |
| 1105 | + * \f] | |
| 1106 | + * | |
| 1107 | + * where \f${\rm Map}(\delta, \phi)\f$ is the diffuse map in the coordinate | |
| 1108 | + * system of the point spread function, defined by the angle \f$\delta\f$ | |
| 1109 | + * between the true and the measured photon direction and the azimuth angle | |
| 1110 | + * \f$\phi\f$ around the measured photon direction. | |
| 1111 | + * \f${\rm PSF}(\delta)\f$ is the azimuthally symmetric point spread | |
| 1112 | + * function. | |
| 1113 | + ***************************************************************************/ | |
| 1114 | +double GCTAResponseCube::psf_diffuse(const GModelSpatial* model, | |
| 1115 | + const GSkyDir& obsDir, | |
| 1116 | + const GEnergy& srcEng, | |
| 1117 | + const GTime& srcTime) const | |
| 1118 | +{ | |
| 1119 | + // Set minimum and maximum number of iterations for Romberg integration. | |
| 1120 | + // These values have been determined after careful testing, see | |
| 1121 | + // https://cta-redmine.irap.omp.eu/issues/2458 | |
| 1122 | + static const int min_iter_delta = 5; | |
| 1123 | + static const int min_iter_phi = 5; | |
| 1124 | + static const int max_iter_delta = 8; | |
| 1125 | + static const int max_iter_phi = 8; | |
| 1126 | + | |
| 1127 | + // Initialise PSF | |
| 1128 | + double psf = 0.0; | |
| 1129 | + | |
| 1130 | + // Compute rotation matrix to convert from PSF centred coordinate system | |
| 1131 | + // spanned by delta and phi into the reference frame of the observed | |
| 1132 | + // arrival direction given in Right Ascension and Declination. | |
| 1133 | + GMatrix ry; | |
| 1134 | + GMatrix rz; | |
| 1135 | + ry.eulery(obsDir.dec_deg() - 90.0); | |
| 1136 | + rz.eulerz(-obsDir.ra_deg()); | |
| 1137 | + GMatrix rot = (ry * rz).transpose(); | |
| 1138 | + | |
| 1139 | + // Get offset angle integration interval in radians | |
| 1140 | + double delta_min = 0.0; | |
| 1141 | + double delta_max = 1.1 * this->psf().delta_max(); | |
| 1142 | + | |
| 1143 | + // Get resolution of spatial model | |
| 1144 | + double resolution = gammalib::resolution(model); | |
| 1145 | + | |
| 1146 | + | |
| 1147 | + // Setup integration kernel. We take here the observed photon arrival | |
| 1148 | + // direction as the true photon arrival direction because the PSF does | |
| 1149 | + // not vary significantly over a small region. | |
| 1150 | + cta_psf_diffuse_kern_delta integrand(this, model, &rot, | |
| 1151 | + obsDir, srcEng, srcTime, | |
| 1152 | + min_iter_phi, max_iter_phi, | |
| 1153 | + resolution); | |
| 1154 | + | |
| 1155 | + // Set number of radial integration iterations | |
| 1156 | + int iter = gammalib::iter_rho(delta_max, resolution, | |
| 1157 | + min_iter_delta, max_iter_delta); | |
| 1158 | + | |
| 1159 | + // Setup integration | |
| 1160 | + GIntegral integral(&integrand); | |
| 1161 | + | |
| 1162 | + // Set fixed number of iterations | |
| 1163 | + integral.fixed_iter(iter); | |
| 1164 | + | |
| 1165 | + // Integrate over PSF delta angle | |
| 1166 | + psf = integral.romberg(delta_min, delta_max); | |
| 1167 | + | |
| 1168 | + // Return PSF | |
| 1169 | + return psf; | |
| 1170 | +} | |
| 1171 | + | |
| 1172 | + | |
| 1173 | +/***********************************************************************//** | |
| 1092 | 1174 | * @brief Return instrument response to point source |
| 1093 | 1175 | * |
| 1094 | 1176 | * @param[in] event Observed event. |
| ... | ... | @@ -1319,7 +1401,8 @@ double GCTAResponseCube::irf_elliptical(const GEvent& event, |
| 1319 | 1401 | GEnergy srcEng = source.energy(); |
| 1320 | 1402 | |
| 1321 | 1403 | // Get pointer to elliptical model |
| 1322 | - const GModelSpatialElliptical* model = static_cast<const GModelSpatialElliptical*>(source.model()); | |
| 1404 | + const GModelSpatialElliptical* model = | |
| 1405 | + static_cast<const GModelSpatialElliptical*>(source.model()); | |
| 1323 | 1406 | |
| 1324 | 1407 | // Compute angle between model centre and measured photon direction and |
| 1325 | 1408 | // position angle (radians) |
| ... | ... | @@ -1415,46 +1498,67 @@ double GCTAResponseCube::irf_diffuse(const GEvent& event, |
| 1415 | 1498 | } |
| 1416 | 1499 | const GCTAEventBin* bin = static_cast<const GCTAEventBin*>(&event); |
| 1417 | 1500 | |
| 1418 | - // Get pointer to source cache. We first search the cache for a model | |
| 1419 | - // with the source name. If no model was found we initialise a new | |
| 1420 | - // cache entry for that model. Otherwise, we simply return the actual | |
| 1421 | - // cache entry. | |
| 1422 | - GCTACubeSourceDiffuse* cache(NULL); | |
| 1423 | - int index = cache_index(source.name()); | |
| 1424 | - if (index == -1) { | |
| 1501 | + // Get event attribute references | |
| 1502 | + const GSkyDir& obsDir = bin->dir().dir(); | |
| 1503 | + const GEnergy& obsEng = bin->energy(); | |
| 1504 | + const GTime& obsTime = bin->time(); | |
| 1425 | 1505 | |
| 1426 | - // No cache entry was found, thus allocate and initialise a new one | |
| 1427 | - cache = new GCTACubeSourceDiffuse; | |
| 1428 | - cache->set(source.name(), *source.model(), obs); | |
| 1429 | - m_cache.push_back(cache); | |
| 1506 | + // Get energy of source model | |
| 1507 | + GEnergy srcEng = source.energy(); | |
| 1430 | 1508 | |
| 1431 | - } // endif: no cache entry was found | |
| 1432 | - else { | |
| 1509 | + // Get pointer to elliptical model | |
| 1510 | + const GModelSpatialDiffuse* model = | |
| 1511 | + static_cast<const GModelSpatialDiffuse*>(source.model()); | |
| 1433 | 1512 | |
| 1434 | - // Check that the cache entry is of the expected type | |
| 1435 | - if (m_cache[index]->code() != GCTA_CUBE_SOURCE_DIFFUSE) { | |
| 1436 | - std::string msg = "Cached model \""+source.name()+"\" is not " | |
| 1437 | - "an extended source model. This method only " | |
| 1438 | - "applies to extended source models."; | |
| 1439 | - throw GException::invalid_value(G_IRF_DIFFUSE, msg); | |
| 1440 | - } | |
| 1441 | - cache = static_cast<GCTACubeSourceDiffuse*>(m_cache[index]); | |
| 1513 | + // Get pointer on CTA response cube | |
| 1514 | + //const GCTAResponseCube* rsp = gammalib::cta_rsp_cube(G_IRF_DIFFUSE, obs); | |
| 1442 | 1515 | |
| 1443 | - } // endelse: there was a cache entry for this model | |
| 1516 | + // Get livetime (in seconds) and deadtime correction factor | |
| 1517 | + double livetime = exposure().livetime(); | |
| 1518 | + double deadc = exposure().deadc(); | |
| 1444 | 1519 | |
| 1445 | - // If energy dispersion is available then compute IRF using the true | |
| 1446 | - // photon energy and multiply in the energy dispersion ... | |
| 1447 | - if (use_edisp()) { | |
| 1448 | - irf = cache->irf(bin->ipix(), source.energy()); | |
| 1449 | - if (irf > 0.0) { | |
| 1450 | - irf *= edisp()(bin->energy(), source.energy(), bin->dir().dir()); | |
| 1451 | - } | |
| 1452 | - } | |
| 1520 | + // Get Psf radius (in degrees) | |
| 1521 | + double delta_max = psf().delta_max() * gammalib::rad2deg; | |
| 1453 | 1522 | |
| 1454 | - // ... otherwise compute the IRF at the observed energy | |
| 1455 | - else { | |
| 1456 | - irf = cache->irf(bin->ipix(), bin->ieng()); | |
| 1457 | - } | |
| 1523 | + // Continue only if livetime is >0 and model contains reconstructed | |
| 1524 | + // sky direction | |
| 1525 | + if (livetime > 0.0 && model->contains(obsDir, delta_max)) { | |
| 1526 | + | |
| 1527 | + // Get exposure | |
| 1528 | + // | |
| 1529 | + // The current code assumes that the exposure at the observed and | |
| 1530 | + // true event direction does not vary significantly. In other words, | |
| 1531 | + // the code assumes that the exposure is constant over the size of | |
| 1532 | + // the PSF. | |
| 1533 | + irf = exposure()(obsDir, srcEng); | |
| 1534 | + | |
| 1535 | + // Continue only if exposure is positive | |
| 1536 | + if (irf > 0.0) { | |
| 1537 | + | |
| 1538 | + // Recover effective area from exposure | |
| 1539 | + irf /= livetime; | |
| 1540 | + | |
| 1541 | + // Compute product of PSF and diffuse map, integrated over the | |
| 1542 | + // relevant PSF area. We assume no energy dispersion and thus | |
| 1543 | + // compute the product using the observed energy. | |
| 1544 | + irf *= psf_diffuse(model, obsDir, srcEng, obsTime); | |
| 1545 | + | |
| 1546 | + // Multiply-in energy dispersion | |
| 1547 | + // | |
| 1548 | + // The current code assumes that the energy dispersion at the | |
| 1549 | + // observed and true event direction does not vary | |
| 1550 | + // significantly. In other words, the code assumes that the | |
| 1551 | + // energy dispersion is constant over the size of the PSF. | |
| 1552 | + if (use_edisp() && irf > 0.0) { | |
| 1553 | + irf *= edisp()(bin->energy(), srcEng, obsDir); | |
| 1554 | + } | |
| 1555 | + | |
| 1556 | + // Apply deadtime correction | |
| 1557 | + irf *= exposure().deadc(); | |
| 1558 | + | |
| 1559 | + } // endif: exposure was positive | |
| 1560 | + | |
| 1561 | + } // endif: livetime was positive | |
| 1458 | 1562 | |
| 1459 | 1563 | // Compile option: Check for NaN/Inf |
| 1460 | 1564 | #if defined(G_NAN_CHECK) | ... | ... |