From 92e200bdd54270ff8dddca342f58a96b159c7e8a Mon Sep 17 00:00:00 2001
From: "P.-A. Loizeau" <p.-a.loizeau@gsi.de>
Date: Fri, 26 Mar 2021 15:56:00 +0100
Subject: [PATCH] [mCBM] Improve spill detection in T0 monitor to make it
 compatible with MQ operation

- Add threshold for non pulser digis in both algo, Task and device
- Make interval for spill threshold checks configurable in both algo, Task and device
- Spill detection only when both threshold passed
- Add Monitor macro for mCBM 2021 using this functionality
---
 MQ/monitor/CbmDeviceMonitorT0.cxx             |  12 +-
 MQ/monitor/CbmDeviceMonitorT0.h               |   2 +
 MQ/monitor/runMonitorT0.cxx                   |   8 +-
 .../monitor/CbmMcbm2018MonitorAlgoT0.cxx      |  33 +++--
 .../monitor/CbmMcbm2018MonitorAlgoT0.h        |  24 +++-
 .../monitor/CbmMcbm2018MonitorTaskT0.cxx      |   4 +
 .../monitor/CbmMcbm2018MonitorTaskT0.h        |   8 ++
 macro/beamtime/mcbm2021/MonitorT0.C           | 121 ++++++++++++++++++
 8 files changed, 190 insertions(+), 22 deletions(-)
 create mode 100644 macro/beamtime/mcbm2021/MonitorT0.C

diff --git a/MQ/monitor/CbmDeviceMonitorT0.cxx b/MQ/monitor/CbmDeviceMonitorT0.cxx
index 4b951f6452..fc83b46eaa 100644
--- a/MQ/monitor/CbmDeviceMonitorT0.cxx
+++ b/MQ/monitor/CbmDeviceMonitorT0.cxx
@@ -6,7 +6,6 @@
  */
 
 #include "CbmDeviceMonitorT0.h"
-#include "CbmMQDefs.h"
 
 #include "CbmFlesCanvasTools.h"
 #include "CbmMcbm2018MonitorAlgoT0.h"
@@ -49,7 +48,9 @@ CbmDeviceMonitorT0::CbmDeviceMonitorT0()
   , fuHistoryHistoSize {3600}
   , fuMinTotPulser {185}
   , fuMaxTotPulser {195}
-  , fuOffSpillCountLimit {1000}
+  , fuOffSpillCountLimit {25}
+  , fuOffSpillCountLimitNonPulser {10}
+  , fdSpillCheckInterval {0.0128}
   , fvuChanMap {0, 1, 2, 3, 4, 5, 6, 7}
   , fuPublishFreqTs {100}
   , fdMinPublishTime {0.5}
@@ -74,6 +75,8 @@ void CbmDeviceMonitorT0::InitTask() try {
   fuMinTotPulser            = fConfig->GetValue<uint32_t>("PulsTotMin");
   fuMaxTotPulser            = fConfig->GetValue<uint32_t>("PulsTotMax");
   fuOffSpillCountLimit      = fConfig->GetValue<uint32_t>("SpillThr");
+  fuOffSpillCountLimitNonPulser = fConfig->GetValue<uint32_t>("SpillThrNonPuls");
+  fdSpillCheckInterval      = fConfig->GetValue<double>("SpillCheckInt");
   std::string sChanMap      = fConfig->GetValue<std::string>("ChanMap");
   fuPublishFreqTs           = fConfig->GetValue<uint32_t>("PubFreqTs");
   fdMinPublishTime          = fConfig->GetValue<double_t>("PubTimeMin");
@@ -130,8 +133,7 @@ void CbmDeviceMonitorT0::InitTask() try {
   InitContainers();
 } catch (InitTaskError& e) {
   LOG(error) << e.what();
-  // Wrapper defined in CbmMQDefs.h to support different FairMQ versions
-  cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
+  ChangeState(fair::mq::Transition::ErrorFound);
 }
 
 bool CbmDeviceMonitorT0::IsChannelNameAllowed(std::string channelName) {
@@ -200,6 +202,8 @@ Bool_t CbmDeviceMonitorT0::InitContainers() {
   fMonitorAlgo->SetHistoryHistoSize(fuHistoryHistoSize);
   fMonitorAlgo->SetPulserTotLimits(fuMinTotPulser, fuMaxTotPulser);
   fMonitorAlgo->SetSpillThreshold(fuOffSpillCountLimit);
+  fMonitorAlgo->SetSpillThresholdNonPulser(fuOffSpillCountLimitNonPulser);
+  fMonitorAlgo->SetSpillCheckInterval(fdSpillCheckInterval);
   fMonitorAlgo->SetChannelMap(fvuChanMap[0], fvuChanMap[1], fvuChanMap[2], fvuChanMap[3], fvuChanMap[4], fvuChanMap[5],
                               fvuChanMap[6], fvuChanMap[7]);
 
diff --git a/MQ/monitor/CbmDeviceMonitorT0.h b/MQ/monitor/CbmDeviceMonitorT0.h
index 2c24b424d0..886fc067df 100644
--- a/MQ/monitor/CbmDeviceMonitorT0.h
+++ b/MQ/monitor/CbmDeviceMonitorT0.h
@@ -50,6 +50,8 @@ private:
   uint32_t fuMinTotPulser;
   uint32_t fuMaxTotPulser;
   uint32_t fuOffSpillCountLimit;
+  uint32_t fuOffSpillCountLimitNonPulser;
+  double   fdSpillCheckInterval;
   std::vector<uint32_t> fvuChanMap;
   uint32_t fuPublishFreqTs;
   double_t fdMinPublishTime;
diff --git a/MQ/monitor/runMonitorT0.cxx b/MQ/monitor/runMonitorT0.cxx
index e53c761b07..5f82ce8c93 100644
--- a/MQ/monitor/runMonitorT0.cxx
+++ b/MQ/monitor/runMonitorT0.cxx
@@ -21,8 +21,14 @@ void addCustomOptions(bpo::options_description& options) {
                         bpo::value<uint32_t>()->default_value(195),
                         "Maximal TOT for pulser cut");
   options.add_options()("SpillThr",
-                        bpo::value<uint32_t>()->default_value(1000),
+                        bpo::value<uint32_t>()->default_value(25),
                         "Hits Nb Thr for spill detection");
+  options.add_options()("SpillThrNonPuls",
+                        bpo::value<uint32_t>()->default_value(10),
+                        "Non pulser Hits Nb Thr for spill detection");
+  options.add_options()("SpillCheckInt",
+                        bpo::value<double>()->default_value(0.128),
+                        "Interval in seconds between count checks for spill detection");
   options.add_options()("ChanMap", bpo::value<std::string>()->default_value("0,1,2,3,4,5,6,7"),
                         "Set T0 channel map e.g. 0,1,2,3,4,5,6,7");
   options.add_options()("PubFreqTs",
diff --git a/fles/mcbm2018/monitor/CbmMcbm2018MonitorAlgoT0.cxx b/fles/mcbm2018/monitor/CbmMcbm2018MonitorAlgoT0.cxx
index b4cd936ffa..8d6fc39cad 100644
--- a/fles/mcbm2018/monitor/CbmMcbm2018MonitorAlgoT0.cxx
+++ b/fles/mcbm2018/monitor/CbmMcbm2018MonitorAlgoT0.cxx
@@ -306,22 +306,30 @@ Bool_t CbmMcbm2018MonitorAlgoT0::ProcessMs(const fles::Timeslice& ts,
   /// Spill Detection
   if (0 == fuCurrDpbIdx) {
     /// Check only every second
-    if (1.0 < fdMsTime - fdLastSecondTime) {
+    if (fdSpillCheckInterval < fdMsTime - fdLastInterTime) {
       /// Spill Off detection
-      if (fbSpillOn && fuCountsLastSecond < fuOffSpillCountLimit) {
+      if (fbSpillOn && fuCountsLastInter < fuOffSpillCountLimit
+          && fuNonPulserCountsLastInter < fuOffSpillCountLimitNonPulser) {
         fbSpillOn = kFALSE;
         fuCurrentSpillIdx++;
         fuCurrentSpillPlot = (fuCurrentSpillPlot + 1) % kuNbSpillPlots;
         fdStartTimeSpill   = fdMsTime;
         fvhDpbMapSpill[fuCurrentSpillPlot]->Reset();
         fvhChannelMapSpill[fuCurrentSpillPlot]->Reset();
-      }  // if( fbSpillOn && fuCountsLastSecond < fuOffSpillCountLimit )
-      else if (fuOffSpillCountLimit < fuCountsLastSecond)
+      }  // if( fbSpillOn && fuCountsLastInter < fuOffSpillCountLimit && same for non pulser)
+      else if (fuOffSpillCountLimit < fuCountsLastInter)
         fbSpillOn = kTRUE;
 
-      fuCountsLastSecond = 0;
-      fdLastSecondTime   = fdMsTime;
-    }  // if( 1 < fdMsTime - fdLastSecondTime )
+      LOG(debug) << Form( "%6llu %6.4f %9u %9u %2d",
+                         fulCurrentTsIdx, fdMsTime - fdLastInterTime,
+                         fuCountsLastInter,
+                         fuNonPulserCountsLastInter,
+                         fuCurrentSpillIdx);
+
+      fuCountsLastInter = 0;
+      fuNonPulserCountsLastInter = 0;
+      fdLastInterTime   = fdMsTime;
+    }  // if( fdSpillCheckInterval < fdMsTime - fdLastInterTime )
   }    // if( 0 == fuCurrDpbIdx )
 
   /// Save start time of first valid MS )
@@ -379,7 +387,7 @@ Bool_t CbmMcbm2018MonitorAlgoT0::ProcessMs(const fles::Timeslice& ts,
         }  // if( getGdpbHitIs24b() )
         else {
           /// Spill detection
-          fuCountsLastSecond++;
+          fuCountsLastInter++;
 
           fhErrorFractEvo->Fill(fdMsTime - fdStartTime, 0.0);
           fhLostEvtFractEvo->Fill(fdMsTime - fdStartTime, 0.0);
@@ -396,6 +404,8 @@ Bool_t CbmMcbm2018MonitorAlgoT0::ProcessMs(const fles::Timeslice& ts,
           /// Do not fill the pulser hits to keep counts low for channel 0
           UInt_t uTot = mess.getGdpbHit32Tot();
           if (uTot < fuMinTotPulser || fuMaxTotPulser < uTot) {
+            fuNonPulserCountsLastInter++;
+
             fhDpbMap->Fill(fuCurrDpbIdx);
             fhChannelMap->Fill(uChannelT0);
             fhChanHitMap->Fill(fuDiamChanMap[uChannelT0]);
@@ -1248,7 +1258,7 @@ Bool_t CbmMcbm2018MonitorAlgoT0::CreateHistograms() {
     fcSpillCounts->cd(1 + uSpill);
     gPad->SetGridx();
     gPad->SetGridy();
-    //      gPad->SetLogy();
+    gPad->SetLogy();
     //      fvhChannelMapSpill[ uSpill ]->SetStats( kTRUE );
     fvhChannelMapSpill[uSpill]->Draw();
     gPad->Update();
@@ -1393,8 +1403,6 @@ Bool_t CbmMcbm2018MonitorAlgoT0::ResetHistograms(Bool_t bResetTime) {
     fvhEvtLostFractPerMsEvoChan[uChan]->Reset();
   }  // for( UInt_t uChan = 0; uChan < kuNbChanDiamond; ++uChan )
 
-  fuCurrentSpillIdx  = 0;
-  fuCurrentSpillPlot = 0;
   fhDpbMap->Reset();
   fhChannelMap->Reset();
   fhHitMapEvo->Reset();
@@ -1424,6 +1432,9 @@ Bool_t CbmMcbm2018MonitorAlgoT0::ResetHistograms(Bool_t bResetTime) {
   if (kTRUE == bResetTime) {
     /// Also reset the Start time for the evolution plots!
     fdStartTime = -1.0;
+
+    fuCurrentSpillIdx  = 0;
+    fuCurrentSpillPlot = 0;
   }  // if( kTRUE == bResetTime )
 
   return kTRUE;
diff --git a/fles/mcbm2018/monitor/CbmMcbm2018MonitorAlgoT0.h b/fles/mcbm2018/monitor/CbmMcbm2018MonitorAlgoT0.h
index 1a5bb4aa94..a450a80c6f 100644
--- a/fles/mcbm2018/monitor/CbmMcbm2018MonitorAlgoT0.h
+++ b/fles/mcbm2018/monitor/CbmMcbm2018MonitorAlgoT0.h
@@ -72,6 +72,12 @@ public:
   inline void SetSpillThreshold(UInt_t uCntLimit) {
     fuOffSpillCountLimit = uCntLimit;
   }
+  inline void SetSpillThresholdNonPulser(UInt_t uCntLimit) {
+    fuOffSpillCountLimitNonPulser = uCntLimit;
+  }
+  inline void SetSpillCheckInterval(Double_t dIntervalSec) {
+    fdSpillCheckInterval = dIntervalSec;
+  }
   inline void SetChannelMap(UInt_t uChan0,
                             UInt_t uChan1,
                             UInt_t uChan2,
@@ -115,6 +121,8 @@ private:
   UInt_t fuMinTotPulser       = 90;
   UInt_t fuMaxTotPulser       = 100;
   UInt_t fuOffSpillCountLimit = 200;
+  UInt_t fuOffSpillCountLimitNonPulser = 80;
+  Double_t fdSpillCheckInterval = 1.0;
 
   /// Constants
   static const Int_t kiMaxNbFlibLinks   = 32;
@@ -169,6 +177,16 @@ private:
   std::vector<gdpbv100::FullMessage> fvmHitsInMs =
     {};  //! All hits (time in bins, TOT in bins, asic, channel) in last MS, sorted with "<" operator
 
+  /// Spill detection
+  Bool_t fbSpillOn                  = kTRUE;
+  UInt_t fuCurrentSpillIdx          = 0;
+  UInt_t fuCurrentSpillPlot         = 0;
+  Double_t fdStartTimeSpill         = -1.0;
+  Double_t fdLastInterTime          = -1.0;
+  UInt_t fuCountsLastInter          = 0;
+  UInt_t fuNonPulserCountsLastInter = 0;
+
+
   /// Histograms related variables
   UInt_t fuHistoryHistoSize =
     3600; /** Size in seconds of the evolution histograms **/
@@ -205,12 +223,6 @@ private:
   std::vector<TH2*> fvhEvtLostFractPerMsEvoChan =
     std::vector<TH2*>(kuNbChanDiamond, nullptr);
   /// Channels map
-  Bool_t fbSpillOn                   = kTRUE;
-  UInt_t fuCurrentSpillIdx           = 0;
-  UInt_t fuCurrentSpillPlot          = 0;
-  Double_t fdStartTimeSpill          = -1.0;
-  Double_t fdLastSecondTime          = -1.0;
-  UInt_t fuCountsLastSecond          = 0;
   static const UInt_t kuNbSpillPlots = 5;
   //      UInt_t  kuDiamChanMap[ kuNbChanDiamond ] = { 2, 3, 4, 5, 0, 1, 6, 7 }; //! Map from electronics channel to Diamond strip
   UInt_t fuDiamChanMap[kuNbChanDiamond] =
diff --git a/fles/mcbm2018/monitor/CbmMcbm2018MonitorTaskT0.cxx b/fles/mcbm2018/monitor/CbmMcbm2018MonitorTaskT0.cxx
index 8f08a21cf8..0674c524b2 100644
--- a/fles/mcbm2018/monitor/CbmMcbm2018MonitorTaskT0.cxx
+++ b/fles/mcbm2018/monitor/CbmMcbm2018MonitorTaskT0.cxx
@@ -41,6 +41,8 @@ CbmMcbm2018MonitorTaskT0::CbmMcbm2018MonitorTaskT0()
   , fuMinTotPulser(90)
   , fuMaxTotPulser(100)
   , fuOffSpillCountLimit(200)
+  , fuOffSpillCountLimitNonPulser(80)
+  , fdSpillCheckInterval(1.0)
   , fulTsCounter(0)
   , fMonitorAlgo(nullptr) {
   fMonitorAlgo = new CbmMcbm2018MonitorAlgoT0();
@@ -105,6 +107,8 @@ Bool_t CbmMcbm2018MonitorTaskT0::InitContainers() {
   fMonitorAlgo->SetHistoryHistoSize(fuHistoryHistoSize);
   fMonitorAlgo->SetPulserTotLimits(fuMinTotPulser, fuMaxTotPulser);
   fMonitorAlgo->SetSpillThreshold(fuOffSpillCountLimit);
+  fMonitorAlgo->SetSpillThresholdNonPulser(fuOffSpillCountLimitNonPulser);
+  fMonitorAlgo->SetSpillCheckInterval(fdSpillCheckInterval);
 
   /// Histos creation, obtain pointer on them and add them to the HTTP server
   /// Trigger histo creation on all associated algos
diff --git a/fles/mcbm2018/monitor/CbmMcbm2018MonitorTaskT0.h b/fles/mcbm2018/monitor/CbmMcbm2018MonitorTaskT0.h
index 962d86e53f..7452056384 100644
--- a/fles/mcbm2018/monitor/CbmMcbm2018MonitorTaskT0.h
+++ b/fles/mcbm2018/monitor/CbmMcbm2018MonitorTaskT0.h
@@ -55,6 +55,12 @@ public:
   inline void SetSpillThreshold(UInt_t uCntLimit) {
     fuOffSpillCountLimit = uCntLimit;
   }
+  inline void SetSpillThresholdNonPulser(UInt_t uCntLimit) {
+    fuOffSpillCountLimitNonPulser = uCntLimit;
+  }
+  inline void SetSpillCheckInterval(Double_t dIntervalSec) {
+    fdSpillCheckInterval = dIntervalSec;
+  }
   void SetChannelMap(UInt_t uChan0,
                      UInt_t uChan1,
                      UInt_t uChan2,
@@ -77,6 +83,8 @@ private:
   UInt_t fuMinTotPulser;
   UInt_t fuMaxTotPulser;
   UInt_t fuOffSpillCountLimit;
+  UInt_t fuOffSpillCountLimitNonPulser;
+  Double_t fdSpillCheckInterval;
 
   /// Statistics & first TS rejection
   uint64_t fulTsCounter;
diff --git a/macro/beamtime/mcbm2021/MonitorT0.C b/macro/beamtime/mcbm2021/MonitorT0.C
new file mode 100644
index 0000000000..88a19cafaf
--- /dev/null
+++ b/macro/beamtime/mcbm2021/MonitorT0.C
@@ -0,0 +1,121 @@
+/** @file MCBM DATA unpacking
+ ** @author Florian Uhlig <f.uhlig@gsi.de>
+ ** @date 20.06.2016
+ ** Modified by P.-A. Loizeau
+ ** @date 30.01.2019
+ ** ROOT macro to read tsa files which have been produced with the new data transport
+ ** Convert data into cbmroot format.
+ ** Uses CbmMcbm2018Source as source task.
+ */
+// In order to call later Finish, we make this global
+FairRunOnline* run = NULL;
+
+void MonitorT0(TString inFile           = "",
+               TString sHostname        = "cbmflesnode8:5558;cbmflesnode9:5559",
+               Int_t iServerHttpPort    = 8080,
+               Int_t iServerRefreshRate = 100,
+               UInt_t uRunId            = 0,
+               UInt_t nrEvents          = 0) {
+  TString srcDir = gSystem->Getenv("VMCWORKDIR");
+
+  // --- Specify number of events to be produced.
+  // --- -1 means run until the end of the input file.
+  Int_t nEvents = -1;
+  // --- Specify output file name (this is just an example)
+  TString runId   = TString::Format("%u", uRunId);
+  TString parFile = "data/moni_t0_params_" + runId + ".root";
+
+  // --- Set log output levels
+  FairLogger::GetLogger();
+  gLogger->SetLogScreenLevel("INFO");
+  //gLogger->SetLogScreenLevel("DEBUG");
+  gLogger->SetLogVerbosityLevel("MEDIUM");
+
+  // --- Define parameter files
+  TList* parFileList = new TList();
+  TString paramDir   = srcDir + "/macro/beamtime/mcbm2021/";
+
+  TString paramFileTof       = paramDir + "mT0Par.par";
+  TObjString* parTofFileName = new TObjString(paramFileTof);
+  parFileList->Add(parTofFileName);
+
+  // --- Set debug level
+  gDebug = 0;
+
+  std::cout << std::endl;
+
+  // ========================================================================
+  // ========================================================================
+  std::cout << std::endl;
+  std::cout << ">>> MonitorT0: Initialising..." << std::endl;
+  CbmMcbm2018MonitorTaskT0* monitor_t0 = new CbmMcbm2018MonitorTaskT0();
+
+  monitor_t0->SetIgnoreOverlapMs();
+  monitor_t0->SetHistoryHistoSize(1800);
+  if (0 < uRunId)
+    monitor_t0->SetHistoFilename(
+      Form("data/HistosMonitorT0_%03u.root", uRunId));
+  monitor_t0->SetPulserTotLimits(180, 210);  // for runs  >  86
+
+  // --- Source task
+  CbmMcbm2018Source* source = new CbmMcbm2018Source();
+
+  if ("" != inFile) {
+    source->SetFileName(inFile);
+  }  // if( "" != inFile )
+  else {
+    source->SetHostName(sHostname);
+  }  // else of if( "" != inFile )
+
+  // Use kHodo since there is no entry for T0 in the enum yet
+  source->AddUnpacker(monitor_t0, 0x90, ECbmModuleId::kHodo);  //gDPB T0
+
+  source->SetSubscriberHwm(1000);
+
+  // --- Run
+  run = new FairRunOnline(source);
+  run->ActivateHttpServer(iServerRefreshRate,
+                          iServerHttpPort);  // refresh each 100 events
+  /// To avoid the server sucking all Histos from gROOT when no output file is used
+  /// ===> Need to explicitely add the canvases to the server in the task!
+  run->GetHttpServer()->GetSniffer()->SetScanGlobalDir(kFALSE);
+  run->SetAutoFinish(kFALSE);
+
+
+  // -----   Runtime database   ---------------------------------------------
+  FairRuntimeDb* rtdb       = run->GetRuntimeDb();
+  FairParAsciiFileIo* parIn = new FairParAsciiFileIo();
+  parIn->open(parFileList, "in");
+  rtdb->setFirstInput(parIn);
+
+  run->Init();
+
+  // --- Start run
+  TStopwatch timer;
+  timer.Start();
+  std::cout << ">>> MonitorT0: Starting run..." << std::endl;
+  if (0 == nrEvents) {
+    run->Run(nEvents, 0);  // run until end of input file
+  } else {
+    run->Run(0, nrEvents);  // process  2000 Events
+  }
+  run->Finish();
+
+  timer.Stop();
+
+  std::cout << "Processed " << std::dec << source->GetTsCount() << " timeslices"
+            << std::endl;
+
+  // --- End-of-run info
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+  std::cout << std::endl << std::endl;
+  std::cout << ">>> MonitorT0: Macro finished successfully." << std::endl;
+  std::cout << ">>> MonitorT0: Real time " << rtime << " s, CPU time " << ctime
+            << " s" << std::endl;
+  std::cout << std::endl;
+
+  /// --- Screen output for automatic tests
+  std::cout << " Test passed" << std::endl;
+  std::cout << " All ok " << std::endl;
+}
-- 
GitLab