From 4c3db6a61698d42d69cad6bcfe15360c0971cf64 Mon Sep 17 00:00:00 2001
From: Volker Friese <v.friese@gsi.de>
Date: Mon, 30 Jan 2023 19:18:18 +0000
Subject: [PATCH] Introduce common scheme of masking inactive channels in the
 simulation. Refs #2708.

---
 core/base/CbmDigitize.h              | 22 +++++++++--
 core/base/CbmDigitizeBase.cxx        | 24 ++++++++++++
 core/base/CbmDigitizeBase.h          | 37 ++++++++++++++----
 sim/detectors/sts/CbmStsDigitize.cxx | 56 +++++++++++++++++++++++++++-
 sim/detectors/sts/CbmStsDigitize.h   | 33 +++++++++++++++-
 5 files changed, 160 insertions(+), 12 deletions(-)

diff --git a/core/base/CbmDigitize.h b/core/base/CbmDigitize.h
index 78a137ee69..286180bd27 100644
--- a/core/base/CbmDigitize.h
+++ b/core/base/CbmDigitize.h
@@ -24,6 +24,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <sstream>
 #include <string>
 #include <utility>
@@ -227,9 +228,11 @@ public:
      **/
   void SendData(Double_t time, Digi* digi, CbmMatch* match = nullptr)
   {
-    std::unique_ptr<Digi> tmpDigi(digi);
-    std::unique_ptr<CbmMatch> tmpMatch(match);
-    fDaqBuffer.insert(make_pair(time, std::make_pair(std::move(tmpDigi), std::move(tmpMatch))));
+    if (IsChannelActive(*digi)) {
+      std::unique_ptr<Digi> tmpDigi(digi);
+      std::unique_ptr<CbmMatch> tmpMatch(match);
+      fDaqBuffer.insert(make_pair(time, std::make_pair(std::move(tmpDigi), std::move(tmpMatch))));
+    }
   }
   // --------------------------------------------------------------------------
 
@@ -330,6 +333,19 @@ private:
   // --------------------------------------------------------------------------
 
 
+  // --------------------------------------------------------------------------
+  /** @brief Test if the channel of a digi object is set active
+   ** @param digi object
+   ** @return .true. if the respective channel is active
+   **/
+  bool IsChannelActive(const Digi& digi)
+  {
+    if (fInactiveChannels.count(digi.GetAddress())) return false;
+    return true;
+  }
+  // --------------------------------------------------------------------------
+
+
   ClassDef(CbmDigitize, 1);
 };
 
diff --git a/core/base/CbmDigitizeBase.cxx b/core/base/CbmDigitizeBase.cxx
index 66ef864c96..0d56f13c0f 100644
--- a/core/base/CbmDigitizeBase.cxx
+++ b/core/base/CbmDigitizeBase.cxx
@@ -16,6 +16,7 @@
 #include <TGenericClassInfo.h>  // for TGenericClassInfo
 
 #include <cassert>  // for assert
+#include <cstdio>
 
 // -----   Default constructor   --------------------------------------------
 CbmDigitizeBase::CbmDigitizeBase()
@@ -75,4 +76,27 @@ void CbmDigitizeBase::GetEventInfo()
 // --------------------------------------------------------------------------
 
 
+// -----   Read list of inactive channels   ---------------------------------
+std::pair<size_t, bool> CbmDigitizeBase::ReadInactiveChannels()
+{
+
+  if (fInactiveChannelFileName.IsNull()) return std::make_pair(0, true);
+
+  FILE* channelFile = fopen(fInactiveChannelFileName.Data(), "r");
+  if (channelFile == nullptr) return std::make_pair(0, false);
+
+  size_t nLines    = 0;
+  uint32_t channel = 0;
+  while (fscanf(channelFile, "%u", &channel) == 1) {
+    fInactiveChannels.insert(channel);
+    nLines++;
+  }
+  bool success = feof(channelFile);
+
+  fclose(channelFile);
+  return std::make_pair(nLines, success);
+}
+// --------------------------------------------------------------------------
+
+
 ClassImp(CbmDigitizeBase)
diff --git a/core/base/CbmDigitizeBase.h b/core/base/CbmDigitizeBase.h
index 2b960bb81e..a2bca30e46 100644
--- a/core/base/CbmDigitizeBase.h
+++ b/core/base/CbmDigitizeBase.h
@@ -17,9 +17,12 @@
 #include <Rtypes.h>      // for THashConsistencyHolder, ClassDef
 #include <RtypesCore.h>  // for Bool_t, Double_t, Int_t, kTRUE, ULong64_t
 
+#include <set>
 #include <string>  // for string
+
 class CbmTimeSlice;
 
+
 /** @class CbmDigitizeBase
  ** @brief Abstract base class for CBM digitisation tasks
  ** @author Volker Friese <v.friese@gsi.de>
@@ -152,6 +155,15 @@ public:
   void SetEventMode(Bool_t choice = kTRUE) { fEventMode = choice; }
 
 
+  /** @brief Set the file containing the list of inactive channels
+   ** @param fileName   Name of file
+   **
+   ** Channels are identified by their CbmAddress. The file must contain a list of addresses,
+   ** one per line. Comments after the address are allowed if separated by a blank.
+   **/
+  void SetInactiveChannelFile(const char* fileName) { fInactiveChannelFileName = fileName; }
+
+
   /** @brief Set production of inter-event noise
      ** @param Choice If kTRUE, the digitizer will produce noise
      **/
@@ -159,13 +171,24 @@ public:
 
 
 protected:
-  Bool_t fEventMode;           /// Flag for event-by-event mode
-  Bool_t fProduceNoise;        /// Flag for production of inter-event noise
-  Bool_t fCreateMatches;       /// Flag for creation of links to MC
-  Int_t fCurrentInput;         /// Number of current input
-  Int_t fCurrentEvent;         /// Number of current MC event
-  Int_t fCurrentMCEntry;       /// Number of current MC entry
-  Double_t fCurrentEventTime;  /// Time of current MC event [ns]
+  Bool_t fEventMode;                          /// Flag for event-by-event mode
+  Bool_t fProduceNoise;                       /// Flag for production of inter-event noise
+  Bool_t fCreateMatches;                      /// Flag for creation of links to MC
+  Int_t fCurrentInput;                        /// Number of current input
+  Int_t fCurrentEvent;                        /// Number of current MC event
+  Int_t fCurrentMCEntry;                      /// Number of current MC entry
+  Double_t fCurrentEventTime;                 /// Time of current MC event [ns]
+  TString fInactiveChannelFileName     = "";  /// Name of file with inactive channels
+  std::set<uint32_t> fInactiveChannels = {};  /// Set of inactive channels, indicated by CbmAddress
+
+  /** @brief Read the list of inactive channels from file
+   ** @param fileName   File name
+   ** @return Number of channels read from file, success of file reading
+   **
+   ** Reading from the file will stop when a read error occurs. In that case, or when the file
+   ** could not be opened at all, the success flag will be .false.
+   **/
+  virtual std::pair<size_t, bool> ReadInactiveChannels();
 
 
 private:
diff --git a/sim/detectors/sts/CbmStsDigitize.cxx b/sim/detectors/sts/CbmStsDigitize.cxx
index 5571246d0c..7778459d33 100644
--- a/sim/detectors/sts/CbmStsDigitize.cxx
+++ b/sim/detectors/sts/CbmStsDigitize.cxx
@@ -17,6 +17,7 @@
 #include <iomanip>
 #include <iostream>
 #include <sstream>
+#include <tuple>
 
 // Includes from ROOT
 #include "TClonesArray.h"
@@ -152,6 +153,9 @@ void CbmStsDigitize::CreateDigi(Int_t address, UShort_t channel, Long64_t time,
 {
   assert(time >= 0);
 
+  // No action if the channel is marked inactive
+  if (!IsChannelActiveSts(address, channel)) return;
+
   // Update times of first and last digi
   fTimeDigiFirst = fNofDigis ? TMath::Min(fTimeDigiFirst, Double_t(time)) : time;
   fTimeDigiLast  = TMath::Max(fTimeDigiLast, Double_t(time));
@@ -334,6 +338,21 @@ InitStatus CbmStsDigitize::Init()
   // --- Initialise parameters
   InitParams();
 
+  // --- Read list of inactive channels
+  if (!fInactiveChannelFileName.IsNull()) {
+    LOG(info) << GetName() << ": Reading inactive channels from " << fInactiveChannelFileName;
+    auto result = ReadInactiveChannels();
+    if (!result.second) {
+      LOG(error) << GetName() << ": Error in reading from file! Task will be inactive.";
+      return kFATAL;
+    }
+    LOG(info) << GetName() << ": " << std::get<0>(result) << " lines read from file";
+  }
+  size_t nChanInactive = 0;
+  for (auto& entry : fInactiveChannelsSts)
+    nChanInactive += entry.second.size();
+  LOG(info) << GetName() << ": " << nChanInactive << " channels set inactive";
+
   // Instantiate modules
   UInt_t nModules = InitModules();
   LOG(info) << GetName() << ": Created " << nModules << " modules";
@@ -342,7 +361,6 @@ InitStatus CbmStsDigitize::Init()
   UInt_t nSensors = InitSensors();
   LOG(info) << GetName() << ": Created " << nSensors << " sensors";
 
-
   // --- Get FairRootManager instance
   FairRootManager* ioman = FairRootManager::Instance();
   assert(ioman);
@@ -355,6 +373,7 @@ InitStatus CbmStsDigitize::Init()
   fTracks = (TClonesArray*) ioman->GetObject("MCTrack");
   assert(fTracks);
 
+  // --- Register the output branches
   RegisterOutput();
 
   // --- Screen output
@@ -594,6 +613,17 @@ void CbmStsDigitize::InitSetup()
 // -------------------------------------------------------------------------
 
 
+// -----   Check for channel being active   --------------------------------
+bool CbmStsDigitize::IsChannelActiveSts(Int_t address, UShort_t channel)
+{
+  auto it = fInactiveChannelsSts.find(address);
+  if (it == fInactiveChannelsSts.end()) return true;
+  if (it->second.count(channel)) return false;
+  return true;
+}
+// -------------------------------------------------------------------------
+
+
 // -----   Process the analogue buffers of all modules   -------------------
 void CbmStsDigitize::ProcessAnalogBuffers(Double_t readoutTime)
 {
@@ -668,6 +698,30 @@ void CbmStsDigitize::ProcessPoint(const CbmStsPoint* point, Double_t eventTime,
 // -------------------------------------------------------------------------
 
 
+// -----  Read list of inactive channels from file   -----------------------
+std::pair<size_t, bool> CbmStsDigitize::ReadInactiveChannels()
+{
+
+  if (fInactiveChannelFileName.IsNull()) return std::make_pair(0, true);
+
+  FILE* channelFile = fopen(fInactiveChannelFileName.Data(), "r");
+  if (channelFile == nullptr) return std::make_pair(0, false);
+
+  size_t nLines    = 0;
+  uint32_t address = 0;
+  uint16_t channel = 0;
+  while (fscanf(channelFile, "%u %hu", &address, &channel) == 2) {
+    fInactiveChannelsSts[address].insert(channel);
+    nLines++;
+  }
+  bool success = feof(channelFile);
+
+  fclose(channelFile);
+  return std::make_pair(nLines, success);
+}
+// -------------------------------------------------------------------------
+
+
 // -----   Private method ReInit   -----------------------------------------
 InitStatus CbmStsDigitize::ReInit()
 {
diff --git a/sim/detectors/sts/CbmStsDigitize.h b/sim/detectors/sts/CbmStsDigitize.h
index 5679ac6cac..a2a104486d 100644
--- a/sim/detectors/sts/CbmStsDigitize.h
+++ b/sim/detectors/sts/CbmStsDigitize.h
@@ -288,7 +288,7 @@ private:
   Int_t fNofDigis      = 0;  ///< Number of created digis in Exec
 
   // --- Run counters
-  Int_t fNofEvents           = 0;   ///< Total number of procesed events
+  Int_t fNofEvents           = 0;   ///< Total number of processed events
   Double_t fNofPointsProcTot = 0;   ///< Total number of processed points
   Double_t fNofPointsIgnoTot = 0;   ///< Total number of ignored points
   Double_t fNofSignalsFTot   = 0;   ///< Number of signals on front side
@@ -297,6 +297,11 @@ private:
   Double_t fNofNoiseTot      = 0;   ///< Total number of noise digis
   Double_t fTimeTot          = 0.;  ///< Total execution time
 
+  // --- List of inactive channels
+  // --- We do not use the base class here since STS channels are identified not only by
+  // --- CbmAddress like in all other detectors, but by address plus channel number.
+  std::map<Int_t, std::set<UShort_t>> fInactiveChannelsSts = {};
+
 
   /** @brief Number of signals in the analogue buffers
    ** @value nSignals  Sum of number of signals in all modules
@@ -335,6 +340,17 @@ private:
   UInt_t InitSensors();
 
 
+  /** @brief Test if the channel of a digi object is set active
+   ** @param address CbmStdAddress of module
+   ** @param channel Channel number in module
+   ** @return .true. if the respective channel is active
+   **
+   ** We do not use the base class method IsChannelActive(), because unlike for the other detector systems,
+   ** an STS channel is not identified by the address only, but by address plus channel number.
+   **/
+  bool IsChannelActiveSts(Int_t address, UShort_t channel);
+
+
   /** Process the analog buffers of all modules
    ** @param readoutTime  Time of readout [ns]
    **/
@@ -352,6 +368,21 @@ private:
   void ProcessPoint(const CbmStsPoint* point, Double_t eventTime, const CbmLink& link);
 
 
+  /** @brief Read the list of inactive channels from file
+   ** @param fileName   File name
+   ** @return Number of channels read from file, success of file reading
+   **
+   ** This re-implements the respective method from the base class by reading not only the address,
+   ** but also the channel number from file. The file must contain one line for each channel
+   ** containing the module address and the channel number, separated by a blank. Comments can
+   ** follow after the channel number, if separated by a blank.
+   **
+   ** Reading from the file will stop when a read error occurs. In that case, or when the file
+   ** could not be opened at all, the success flag will be .false.
+   **/
+  std::pair<size_t, bool> ReadInactiveChannels();
+
+
   /** @brief Reset event counters **/
   void ResetCounters();
 
-- 
GitLab