Commit 1fbf6770fd946562fb0d6cb6fc56a0b9ffb6595c

Authored by Jürgen Knödlseder
1 parent 22933023

Add D1 and D2 module statistics

ChangeLog
1   -2021-12-01
  1 +2021-12-02
2 2  
3 3 * Version 2.0.0 released
4 4 ========================
5 5  
6   - Add GCOMSelection::fpmtflag() method (#3917)
  6 + Add GCOMSelection::fpmtflag(), GCOMSelection::use_d1() and
  7 + GCOMSelection::use_d2() methods (#3917)
7 8 Add GCOMModelDRBPhibarBins class (#3913)
8 9 Compute spectral model gradients for negative factor values
9 10 Add likelihood fit event selection hook (#3912)
... ...
... ... @@ -114,6 +114,8 @@ The following methods have been added:
114 114 - GCOMSelection::phase_curve()
115 115 - GCOMSelection::phases()
116 116 - GCOMSelection::fpmtflag()
  117 +- GCOMSelection::use_d1()
  118 +- GCOMSelection::use_d2()
117 119 - gammalib::tmpnam()
118 120 - gammalib::compare()
119 121 - gammalib::xml_check_parnum()
... ... @@ -389,6 +391,11 @@ spatial model gradients (#3203).
389 391  
390 392 22. COMPTEL interface
391 393 ---------------------
  394 +Added GCOMSelection::use_d1() and GCOMSelection::use_d2() methods to control the usage
  395 +of D1 and D2 modules. The control logic was implemented in GCOMDri and header keywords
  396 +with per module information are now written into the DRE FITS files. A D1 and D2
  397 +module usage string is also written into DRE and DRG files (#3917).
  398 +
392 399 Added GCOMSelection::fpmtflag() methods to select the method how D2 modules with
393 400 failed PMTs will be handled. If the flag is set to 0, D2 modules with failed PMTs
394 401 will be discarded, if set to 1 modules with failed PMT will be included, and if set
... ...
README.md
1 1 GammaLib information
2 2 ====================
3   -* Version: 2.0.0.dev (1 December 2021)
  3 +* Version: 2.0.0.dev (2 December 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 (30 November 2021)
4   -=======================================
  3 +GammaLib 2.0 release (2 December 2021)
  4 +======================================
5 5  
6 6 Overview
7 7 --------
... ... @@ -37,6 +37,8 @@ Bug fixes
37 37 Improvements
38 38 ------------
39 39  
  40 +* [`3917 <https://cta-redmine.irap.omp.eu/issues/3913>`_] -
  41 + Add ``GCOMSelection::fpmtflag()``, ``GCOMSelection::use_d1()`` and ``GCOMSelection::use_d2()`` methods
40 42 * [`3913 <https://cta-redmine.irap.omp.eu/issues/3913>`_] -
41 43 Add ``GCOMModelDRBPhibarBins`` class
42 44 * [`3912 <https://cta-redmine.irap.omp.eu/issues/3912>`_] -
... ...
inst/com/include/GCOMSelection.hpp
... ... @@ -97,6 +97,10 @@ public:
97 97 void vetoflag_max(const int& vetoflag_max);
98 98 const int& fpmtflag(void) const;
99 99 void fpmtflag(const int& fpmtflag);
  100 + const bool& use_d1(const int& id1) const;
  101 + void use_d1(const int& id1, const bool& use);
  102 + const bool& use_d2(const int& id2) const;
  103 + void use_d2(const int& id2, const bool& use);
100 104 const GModelTemporalPhaseCurve& phase_curve(void) const;
101 105 void phase_curve(const GModelTemporalPhaseCurve& phase_curve);
102 106 const GPhases& phases(void) const;
... ... @@ -128,6 +132,8 @@ protected:
128 132 int m_fpmtflag; //!< D2 PMT failures
129 133 //!< (0: exclude modules, 1: include modules,
130 134 //!< 2: use FPM information)
  135 + bool m_use_d1[7]; //!< D1 module usage
  136 + bool m_use_d2[14]; //!< D2 module usage
131 137 GModelTemporalPhaseCurve m_phase_curve; //!< Phase curve for phase selection
132 138 GPhases m_phases; //!< Phases for phase selection
133 139  
... ... @@ -154,6 +160,8 @@ protected:
154 160 mutable int m_num_d1module_off; //!< Number of events excluded since D1 module off
155 161 mutable int m_num_d2module_off; //!< Number of events excluded since D2 module off
156 162 mutable int m_num_fpmt; //!< Number of events excluded due to failed PMT
  163 + mutable int m_num_d1[7]; //!< Number of events per D1 module
  164 + mutable int m_num_d2[14]; //!< Number of events per D2 module
157 165 };
158 166  
159 167  
... ...
inst/com/pyext/GCOMSelection.i
... ... @@ -80,6 +80,10 @@ public:
80 80 void vetoflag_max(const int& vetoflag_max);
81 81 const int& fpmtflag(void) const;
82 82 void fpmtflag(const int& fpmtflag);
  83 + const bool& use_d1(const int& id1) const;
  84 + void use_d1(const int& id1, const bool& use);
  85 + const bool& use_d2(const int& id2) const;
  86 + void use_d2(const int& id2, const bool& use);
83 87 const GModelTemporalPhaseCurve& phase_curve(void) const;
84 88 void phase_curve(const GModelTemporalPhaseCurve& phase_curve);
85 89 const GPhases& phases(void) const;
... ...
inst/com/src/GCOMDri.cpp
... ... @@ -1309,12 +1309,33 @@ void GCOMDri::write_attributes(GFitsHDU* hdu) const
1309 1309 }
1310 1310  
1311 1311 // If there was an event seletion then write selection set. Otherwise write
1312   - // handling of D2 PMT failures.
  1312 + // handling D1 and D2 module usage and handling mode of D2 PMT failures.
1313 1313 if (m_has_selection) {
1314 1314 m_selection.write(*hdu);
1315 1315 }
1316 1316 else {
  1317 +
  1318 + // Write D2 PMT failure handling flag
1317 1319 hdu->card("D2FPMT", m_selection.fpmtflag(), "D2 PMT failure handling");
  1320 +
  1321 + // Write D1 module usage
  1322 + std::string d1use = "0000000";
  1323 + for (int i = 0; i < 7; ++i) {
  1324 + if (m_selection.use_d1(i)) {
  1325 + d1use[i] = '1';
  1326 + }
  1327 + }
  1328 + hdu->card("D1USE", d1use, "D1 module usage");
  1329 +
  1330 + // Write D2 module usage
  1331 + std::string d2use = "00000000000000";
  1332 + for (int i = 0; i < 14; ++i) {
  1333 + if (m_selection.use_d2(i)) {
  1334 + d2use[i] = '1';
  1335 + }
  1336 + }
  1337 + hdu->card("D2USE", d2use, "D2 module usage");
  1338 +
1318 1339 }
1319 1340  
1320 1341 // If there was a valid Earth horizon cut then write it
... ... @@ -1407,6 +1428,11 @@ double GCOMDri::compute_geometry(const int&amp; tjd,
1407 1428 // Loop over all D2 modules
1408 1429 for (int id2 = 0; id2 < 14; ++id2) {
1409 1430  
  1431 + // Skip if coresponding modules should not be used
  1432 + if (!select.use_d1(id1) || !select.use_d2(id2)) {
  1433 + continue;
  1434 + }
  1435 +
1410 1436 // Get D2 module status
1411 1437 int d2status = status.d2status(tjd, id2+1);
1412 1438  
... ...
inst/com/src/GCOMSelection.cpp
... ... @@ -37,6 +37,10 @@
37 37  
38 38 /* __ Method name definitions ____________________________________________ */
39 39 #define G_FPMTFLAG "GCOMSelection::fpmtflag(int&)"
  40 +#define G_USE_D1_GET "GCOMSelection::use_d1(int&)"
  41 +#define G_USE_D1_SET "GCOMSelection::use_d1(int&, bool&)"
  42 +#define G_USE_D2_GET "GCOMSelection::use_d2(int&)"
  43 +#define G_USE_D2_SET "GCOMSelection::use_d2(int&, bool&)"
40 44  
41 45 /* __ Macros _____________________________________________________________ */
42 46  
... ... @@ -190,6 +194,12 @@ void GCOMSelection::init_statistics(void) const
190 194 m_num_d1module_off = 0;
191 195 m_num_d2module_off = 0;
192 196 m_num_fpmt = 0;
  197 + for (int i = 0; i < 7; ++i) {
  198 + m_num_d1[i] = 0;
  199 + }
  200 + for (int i = 0; i < 14; ++i) {
  201 + m_num_d2[i] = 0;
  202 + }
193 203  
194 204 // Return
195 205 return;
... ... @@ -304,9 +314,19 @@ bool GCOMSelection::use_event(const GCOMEventAtom&amp; event) const
304 314 int d1status = status.d1status(tjd, id1);
305 315 int d2status = status.d2status(tjd, id2);
306 316  
  317 + // Exclude event if the coresponding modules should not be used
  318 + if (!m_use_d1[id1-1]) {
  319 + m_num_d1module_off++;
  320 + use = false;
  321 + }
  322 + else if (!m_use_d2[id2-1]) {
  323 + m_num_d2module_off++;
  324 + use = false;
  325 + }
  326 +
307 327 // Exclude event if the corresponding modules are signalled
308 328 // as off
309   - if (d1status != 1) {
  329 + else if (d1status != 1) {
310 330 m_num_d1module_off++;
311 331 use = false;
312 332 }
... ... @@ -319,16 +339,18 @@ bool GCOMSelection::use_event(const GCOMEventAtom&amp; event) const
319 339 // failure flag
320 340 else if (d2status > 1) {
321 341  
322   - // If failure flag = 0 then reject event
  342 + // If failure flag = 0 then reject event and signal that the
  343 + // module was off
323 344 if (m_fpmtflag == 0) {
324   - m_num_fpmt++;
  345 + m_num_d2module_off++;
325 346 use = false;
326 347 }
327 348  
328 349 // ... otherwise if failure flag = 2 and the module has a
329 350 // valid exclusion circle then reject event if it is
330 351 // within the exclusion circle; if the module has no
331   - // exclusion region then reject the entire module.
  352 + // exclusion region then reject the entire module and
  353 + // signal that it was off.
332 354 else if (m_fpmtflag == 2) {
333 355 double r = gammalib::com_exd2r(id2);
334 356 if (r >= 0.1) {
... ... @@ -342,7 +364,7 @@ bool GCOMSelection::use_event(const GCOMEventAtom&amp; event) const
342 364 }
343 365 }
344 366 else {
345   - m_num_fpmt++;
  367 + m_num_d2module_off++;
346 368 use = false;
347 369 }
348 370 }
... ... @@ -353,7 +375,16 @@ bool GCOMSelection::use_event(const GCOMEventAtom&amp; event) const
353 375  
354 376 // Update acceptance and rejection statistics
355 377 if (use) {
  378 +
  379 + // Extract module IDs from MODCOM
  380 + int id2 = (event.modcom()-1)/7 + 1; // [1-14]
  381 + int id1 = event.modcom() - (id2-1) * 7; // [1-7]
  382 +
  383 + // Update statistics
356 384 m_num_events_used++;
  385 + m_num_d1[id1-1]++;
  386 + m_num_d2[id2-1]++;
  387 +
357 388 }
358 389 else {
359 390 m_num_events_rejected++;
... ... @@ -395,6 +426,96 @@ void GCOMSelection::fpmtflag(const int&amp; fpmtflag)
395 426  
396 427  
397 428 /***********************************************************************//**
  429 + * @brief Return D1 module usage flag
  430 + *
  431 + * @param[in] id1 D1 module identifier [0,...,6].
  432 + * @return True if D1 module @p id1 should be used.
  433 + ***************************************************************************/
  434 +const bool& GCOMSelection::use_d1(const int& id1) const
  435 +{
  436 + // Check module validity range
  437 + if (id1 < 0 or id1 > 6) {
  438 + std::string msg = "Invalid D1 module identifier "+gammalib::str(id1)+
  439 + " specified. The D1 module identifier needs to be "
  440 + "comprised within 0 and 6.";
  441 + throw GException::invalid_argument(G_USE_D1_GET, msg);
  442 + }
  443 +
  444 + // Return usage flag
  445 + return (m_use_d1[id1]);
  446 +}
  447 +
  448 +
  449 +/***********************************************************************//**
  450 + * @brief Set D1 module usage flag
  451 + *
  452 + * @param[in] id1 D1 module identifier [0,...,6].
  453 + * @param[in] use D1 module usage.
  454 + ***************************************************************************/
  455 +void GCOMSelection::use_d1(const int& id1, const bool& use)
  456 +{
  457 + // Check module validity range
  458 + if (id1 < 0 or id1 > 6) {
  459 + std::string msg = "Invalid D1 module identifier "+gammalib::str(id1)+
  460 + " specified. The D1 module identifier needs to be "
  461 + "comprised within 0 and 6.";
  462 + throw GException::invalid_argument(G_USE_D1_SET, msg);
  463 + }
  464 +
  465 + // Set usage flag
  466 + m_use_d1[id1] = use;
  467 +
  468 + // Return
  469 + return;
  470 +}
  471 +
  472 +
  473 +/***********************************************************************//**
  474 + * @brief Return D2 module usage flag
  475 + *
  476 + * @param[in] id2 D2 module identifier [0,...,13].
  477 + * @return True if D2 module @p id2 should be used.
  478 + ***************************************************************************/
  479 +const bool& GCOMSelection::use_d2(const int& id2) const
  480 +{
  481 + // Check module validity range
  482 + if (id2 < 0 or id2 > 13) {
  483 + std::string msg = "Invalid D2 module identifier "+gammalib::str(id2)+
  484 + " specified. The D2 module identifier needs to be "
  485 + "comprised within 0 and 13.";
  486 + throw GException::invalid_argument(G_USE_D2_GET, msg);
  487 + }
  488 +
  489 + // Return usage flag
  490 + return (m_use_d2[id2]);
  491 +}
  492 +
  493 +
  494 +/***********************************************************************//**
  495 + * @brief Set D2 module usage flag
  496 + *
  497 + * @param[in] id2 D2 module identifier [0,...,13].
  498 + * @param[in] use D2 module usage.
  499 + ***************************************************************************/
  500 +void GCOMSelection::use_d2(const int& id2, const bool& use)
  501 +{
  502 + // Check module validity range
  503 + if (id2 < 0 or id2 > 13) {
  504 + std::string msg = "Invalid D2 module identifier "+gammalib::str(id2)+
  505 + " specified. The D2 module identifier needs to be "
  506 + "comprised within 0 and 13.";
  507 + throw GException::invalid_argument(G_USE_D2_SET, msg);
  508 + }
  509 +
  510 + // Set usage flag
  511 + m_use_d2[id2] = use;
  512 +
  513 + // Return
  514 + return;
  515 +}
  516 +
  517 +
  518 +/***********************************************************************//**
398 519 * @brief Read selection set from FITS HDU keywords
399 520 *
400 521 * @param[in] hdu FITS HDU.
... ... @@ -425,7 +546,6 @@ void GCOMSelection::read(const GFitsHDU&amp; hdu)
425 546 m_psd_max = hdu.real("PSDMAX");
426 547 }
427 548  
428   -
429 549 // Read Earth horizon angle - Phibar selection
430 550 if (hdu.has_card("ZETMIN") && hdu.has_card("ZETMAX")) {
431 551 m_zeta_min = hdu.real("ZETMIN");
... ... @@ -449,6 +569,26 @@ void GCOMSelection::read(const GFitsHDU&amp; hdu)
449 569 m_fpmtflag = hdu.integer("D2FPMT");
450 570 }
451 571  
  572 + // Read D1 module usage flag
  573 + if (hdu.has_card("D1USE")) {
  574 + std::string use = gammalib::strip_whitespace(hdu.string("D1USE"));
  575 + if (use.length() == 7) {
  576 + for (int i = 0; i < 7; ++i) {
  577 + m_use_d1[i] = (use[i] == '1');
  578 + }
  579 + }
  580 + }
  581 +
  582 + // Read D2 module usage flag
  583 + if (hdu.has_card("D2USE")) {
  584 + std::string use = gammalib::strip_whitespace(hdu.string("D2USE"));
  585 + if (use.length() == 14) {
  586 + for (int i = 0; i < 14; ++i) {
  587 + m_use_d2[i] = (use[i] == '1');
  588 + }
  589 + }
  590 + }
  591 +
452 592 // Read selection statistics
453 593 if (hdu.has_card("NEVCHK")) {
454 594 m_num_events_checked = hdu.integer("NEVCHK");
... ... @@ -490,6 +630,18 @@ void GCOMSelection::read(const GFitsHDU&amp; hdu)
490 630 if (hdu.has_card("NNOSCT")) {
491 631 m_num_no_scatter = hdu.integer("NNOSCT");
492 632 }
  633 + for (int i = 0; i < 7; ++i) {
  634 + std::string key = "ND1-"+gammalib::str(i+1,"%2.2d");
  635 + if (hdu.has_card(key)) {
  636 + m_num_d1[i] = hdu.integer(key);
  637 + }
  638 + }
  639 + for (int i = 0; i < 14; ++i) {
  640 + std::string key = "ND2-"+gammalib::str(i+1,"%2.2d");
  641 + if (hdu.has_card(key)) {
  642 + m_num_d2[i] = hdu.integer(key);
  643 + }
  644 + }
493 645 if (hdu.has_card("ND1OFF")) {
494 646 m_num_d1module_off = hdu.integer("ND1OFF");
495 647 }
... ... @@ -543,6 +695,24 @@ void GCOMSelection::write(GFitsHDU&amp; hdu) const
543 695 // Write D2 PMT failure handling flag
544 696 hdu.card("D2FPMT", m_fpmtflag, "D2 PMT failure handling");
545 697  
  698 + // Write D1 module usage
  699 + std::string d1use = "0000000";
  700 + for (int i = 0; i < 7; ++i) {
  701 + if (m_use_d1[i]) {
  702 + d1use[i] = '1';
  703 + }
  704 + }
  705 + hdu.card("D1USE", d1use, "D1 module usage");
  706 +
  707 + // Write D2 module usage
  708 + std::string d2use = "00000000000000";
  709 + for (int i = 0; i < 14; ++i) {
  710 + if (m_use_d2[i]) {
  711 + d2use[i] = '1';
  712 + }
  713 + }
  714 + hdu.card("D2USE", d2use, "D2 module usage");
  715 +
546 716 // Write selection statistics
547 717 hdu.card("NEVCHK", m_num_events_checked, "Number of checked events");
548 718 hdu.card("NEVUSE", m_num_events_used, "Number of used events");
... ... @@ -563,6 +733,16 @@ void GCOMSelection::write(GFitsHDU&amp; hdu) const
563 733 hdu.card("NVFLHI", m_num_vetoflag_max, "Number of events > VFLMAX");
564 734 hdu.card("NNOSCT", m_num_no_scatter, "Number of events w/o scatter angle");
565 735 hdu.card("NINVMT", m_num_invalid_modcom, "Number of events with invalid minitelescope");
  736 + for (int i = 0; i < 7; ++i) {
  737 + std::string key = "ND1-"+gammalib::str(i+1,"%2.2d");
  738 + std::string com = "Number of events in D1 module "+gammalib::str(i+1);
  739 + hdu.card(key, m_num_d1[i], com);
  740 + }
  741 + for (int i = 0; i < 14; ++i) {
  742 + std::string key = "ND2-"+gammalib::str(i+1,"%2.2d");
  743 + std::string com = "Number of events in D2 module "+gammalib::str(i+1);
  744 + hdu.card(key, m_num_d2[i], com);
  745 + }
566 746 hdu.card("ND1OFF", m_num_d1module_off, "Number of events with D1 module off");
567 747 hdu.card("ND2OFF", m_num_d2module_off, "Number of events with D2 module off");
568 748 hdu.card("ND2FPM", m_num_fpmt, "Number of events excluded due to failed PMTs");
... ... @@ -646,6 +826,30 @@ std::string GCOMSelection::print(const GChatter&amp; chatter) const
646 826 result.append(gammalib::str(m_vetoflag_max)+"] < ");
647 827 result.append(gammalib::str(m_num_vetoflag_max));
648 828  
  829 + // Append D1 module usage
  830 + for (int i = 0; i < 7; ++i) {
  831 + result.append("\n"+gammalib::parformat("D1 module "+gammalib::str(i+1)));
  832 + result.append(gammalib::str(m_num_d1[i]));
  833 + if (m_use_d1[i]) {
  834 + result.append(" [use]");
  835 + }
  836 + else {
  837 + result.append(" [don't use]");
  838 + }
  839 + }
  840 +
  841 + // Append D2 module usage
  842 + for (int i = 0; i < 14; ++i) {
  843 + result.append("\n"+gammalib::parformat("D2 module "+gammalib::str(i+1)));
  844 + result.append(gammalib::str(m_num_d2[i]));
  845 + if (m_use_d2[i]) {
  846 + result.append(" [use]");
  847 + }
  848 + else {
  849 + result.append(" [don't use]");
  850 + }
  851 + }
  852 +
649 853 // Append D1 module off
650 854 result.append("\n"+gammalib::parformat("D1 modules off"));
651 855 result.append(gammalib::str(m_num_d1module_off));
... ... @@ -707,6 +911,12 @@ void GCOMSelection::init_members(void)
707 911 m_fpmtflag = 0; //!< D2 PMT failure flag
708 912 m_phase_curve.clear();
709 913 m_phases.clear();
  914 + for (int i = 0; i < 7; ++i) {
  915 + m_use_d1[i] = true;
  916 + }
  917 + for (int i = 0; i < 14; ++i) {
  918 + m_use_d2[i] = true;
  919 + }
710 920  
711 921 // Initialise statistics
712 922 init_statistics();
... ... @@ -741,6 +951,12 @@ void GCOMSelection::copy_members(const GCOMSelection&amp; select)
741 951 m_fpmtflag = select.m_fpmtflag;
742 952 m_phase_curve = select.m_phase_curve;
743 953 m_phases = select.m_phases;
  954 + for (int i = 0; i < 7; ++i) {
  955 + m_use_d1[i] = select.m_use_d1[i];
  956 + }
  957 + for (int i = 0; i < 14; ++i) {
  958 + m_use_d2[i] = select.m_use_d2[i];
  959 + }
744 960  
745 961 // Copy statistics
746 962 m_num_events_checked = select.m_num_events_checked;
... ... @@ -766,6 +982,14 @@ void GCOMSelection::copy_members(const GCOMSelection&amp; select)
766 982 m_num_d2module_off = select.m_num_d2module_off;
767 983 m_num_fpmt = select.m_num_fpmt;
768 984  
  985 + // Copy module usage
  986 + for (int i = 0; i < 7; ++i) {
  987 + m_num_d1[i] = select.m_num_d1[i];
  988 + }
  989 + for (int i = 0; i < 14; ++i) {
  990 + m_num_d2[i] = select.m_num_d2[i];
  991 + }
  992 +
769 993 // Return
770 994 return;
771 995 }
... ...