From 5d33f01e15de8595f2fa68f50cbbf98d14738952 Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Mon, 27 Nov 2023 12:58:16 +0100
Subject: [PATCH] QA: A possibility of running on CbmEvents is introduced; CA:
 Timeslice reading is improved in order to fit the event-base mode

---
 core/qa/CMakeLists.txt           |  1 +
 core/qa/CbmQaTask.cxx            | 33 ++++++++++++--
 core/qa/CbmQaTask.h              | 38 ++++++++++++----
 reco/L1/CbmCaMCModule.cxx        | 70 +++++++++++++++--------------
 reco/L1/CbmCaMCModule.h          | 14 +++---
 reco/L1/CbmCaTimeSliceReader.cxx | 19 +++++---
 reco/L1/CbmCaTimeSliceReader.h   | 77 +++++++++++---------------------
 reco/L1/CbmL1DetectorID.h        | 19 +++++---
 reco/L1/qa/CbmCaOutputQa.cxx     |  4 +-
 9 files changed, 158 insertions(+), 117 deletions(-)

diff --git a/core/qa/CMakeLists.txt b/core/qa/CMakeLists.txt
index 7d53054828..93567ed590 100644
--- a/core/qa/CMakeLists.txt
+++ b/core/qa/CMakeLists.txt
@@ -38,6 +38,7 @@ set(PUBLIC_DEPENDENCIES
   )
 
 set(PRIVATE_DEPENDENCIES
+  CbmData
   external::yaml-cpp
   )
 
diff --git a/core/qa/CbmQaTask.cxx b/core/qa/CbmQaTask.cxx
index a33bac9603..58a6ffc7fc 100644
--- a/core/qa/CbmQaTask.cxx
+++ b/core/qa/CbmQaTask.cxx
@@ -15,6 +15,7 @@
 #include "FairRunAna.h"
 #include "TAxis.h"
 #include "TCanvas.h"
+#include "TClonesArray.h"
 #include "TF1.h"
 #include "TPad.h"
 #include "TPaveText.h"
@@ -39,9 +40,21 @@ CbmQaTask::CbmQaTask(const char* name, int verbose, bool isMCUsed)
 //
 void CbmQaTask::Exec(Option_t* /*option*/)
 {
-  fNofEvents.SetVal(fNofEvents.GetVal() + 1);
-  this->InitTimeSlice();
-  this->FillHistograms();
+  if (fpBrEvents) {
+    int nEvents = fpBrEvents->GetEntriesFast();
+    for (int iEvt = 0; iEvt < nEvents; ++iEvt) {
+      fpCurrentEvent = static_cast<CbmEvent*>(fpBrEvents->At(iEvt));
+      this->InitTimeSlice();
+      this->FillHistograms();
+      fNofEvents.SetVal(fNofEvents.GetVal() + 1);
+    }
+    fpCurrentEvent = nullptr;
+  }
+  else {
+    this->InitTimeSlice();
+    this->FillHistograms();
+    fNofEvents.SetVal(fNofEvents.GetVal() + 1);
+  }
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -86,6 +99,20 @@ InitStatus CbmQaTask::Init()
   LOG_IF(info, fVerbose > 1) << fName << ": initializing histograms";
   res = std::max(res, InitHistograms());
 
+  // ----- Initialize event branch
+  if (!fbProcessFullTs) {
+    fpBrEvents = dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("CbmEvent"));
+    if (fpBrEvents) {
+      LOG_IF(info, fVerbose > 1) << fName << ": the routine will run on events";
+    }
+    else {
+      LOG_IF(info, fVerbose > 1) << fName << ": the routine will run on TS, the CbmEvent branch is undefined";
+    }
+  }
+  else {
+    LOG_IF(info, fVerbose > 1) << fName << ": the routine will run on TS, the CbmEvent branch is disabled with flag";
+  }
+
   fNofEvents.SetVal(0);
 
   return res;
diff --git a/core/qa/CbmQaTask.h b/core/qa/CbmQaTask.h
index e7ae74d906..1c04db3f81 100644
--- a/core/qa/CbmQaTask.h
+++ b/core/qa/CbmQaTask.h
@@ -10,6 +10,7 @@
 
 #pragma once
 
+#include "CbmEvent.h"
 #include "CbmQaIO.h"
 #include "CbmQaTable.h"
 #include "FairTask.h"
@@ -35,6 +36,9 @@
 
 #include <yaml-cpp/yaml.h>
 
+class CbmEvent;
+class TClonesArray;
+
 /// Class CbmQaTask is to be inherited with a particular QA-task. It provides mechanisms for storage and management
 /// of QA canvases and histograms management
 class CbmQaTask : public FairTask, public CbmQaIO {
@@ -45,24 +49,37 @@ class CbmQaTask : public FairTask, public CbmQaIO {
   /// \param  isMCUsed Flag: true - MC information is used, false - only reconstructed data QA is processed
   CbmQaTask(const char* name, int verbose, bool isMCUsed);
 
-  /// Default constructor
+  /// @brief Default constructor
   CbmQaTask() = delete;  // TODO: Let's see, what can happen, if one deletes default constructor
 
-  /// Destructor
+  /// @brief Destructor
   virtual ~CbmQaTask() = default;
 
-  // Copy and move semantics
+  /// @brief Copy constructor
   CbmQaTask(const CbmQaTask&) = delete;
-  CbmQaTask(CbmQaTask&&)      = delete;
+
+  /// @brief Move constructor
+  CbmQaTask(CbmQaTask&&) = delete;
+
+  /// @brief Copy assignment operator
   CbmQaTask& operator=(const CbmQaTask&) = delete;
+
+  /// @brief Move assignment operator
   CbmQaTask& operator=(CbmQaTask&&) = delete;
 
   /// @brief Gets name of the setup
   const std::string& GetSetupName() const { return fsSetupName; }
 
-  /// Returns flag, whether MC information is used or not in the task
+  /// @brief Returns flag, whether MC information is used or not in the task
   bool IsMCUsed() const { return fbUseMC; }
 
+  /// @brief Sets events suppression flag
+  ///
+  /// By default the QA task runs on the reconstructed events (CbmEvent objects), if the tree of the objects is
+  /// presented in the input. This flag disables the events-based routine, so the QA is executed over the whole
+  /// Time-slice.
+  void SetProcessFullTs(bool bProcessFullTs) { fbProcessFullTs = bProcessFullTs; }
+
   /// FairTask: Task initialization in the beginning of the run
   InitStatus Init() override;
 
@@ -138,15 +155,20 @@ class CbmQaTask : public FairTask, public CbmQaIO {
   /// @brief Puts setup title on the canvas
   void PutSetupNameOnPad(double xMin, double yMin, double xMax, double yMax);
 
+  /// @brief Gets pointer to current event
+  CbmEvent* GetCurrentEvent() { return fpCurrentEvent; }
+
  private:
   /// @brief De-initializes this task
   void DeInitBase();
 
-  bool fbUseMC = false;  ///< Flag, if MC is used
-
+  TClonesArray* fpBrEvents = nullptr;  ///< Pointer to CbmEvent branch
+  CbmEvent* fpCurrentEvent = nullptr;  ///< Pointer to the current event
   std::string fsSetupName = "";  ///< Name of the setup (to draw on the canvases)
-
   TParameter<int> fNofEvents{"nEvents", 0};  ///< Number of processed events
+  bool fbUseMC         = false;              ///< Flag, if MC is used
+  bool fbProcessFullTs = false;              ///< If true, routine runs on the full TS even if the CbmEvent branch is in
+
 
   ClassDefOverride(CbmQaTask, 0);
 };
diff --git a/reco/L1/CbmCaMCModule.cxx b/reco/L1/CbmCaMCModule.cxx
index cfe5ed794a..70ad4f3730 100644
--- a/reco/L1/CbmCaMCModule.cxx
+++ b/reco/L1/CbmCaMCModule.cxx
@@ -80,11 +80,6 @@ try {
   auto mcManager = dynamic_cast<CbmMCDataManager*>(fairManager->GetObject("MCDataManager"));
   assert(mcManager);
 
-  if (!fbLegacyEventMode) {
-    fpTimeSlice   = dynamic_cast<CbmTimeSlice*>(fairManager->GetObject("TimeSlice."));
-    fpMCEventList = dynamic_cast<CbmMCEventList*>(fairManager->GetObject("MCEventList."));
-  }
-
   fpMCEventHeader = mcManager->GetObject("MCEventHeader.");
   fpMCTracks      = mcManager->InitBranch("MCTrack");
 
@@ -147,21 +142,33 @@ catch (const std::logic_error& error) {
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void MCModule::InitEvent(CbmEvent* /*pEvent*/)
+void MCModule::InitEvent(CbmEvent* pEvent)
 {
   // Fill a set of file and event indexes
   fFileEventIDs.clear();
-  if (fbLegacyEventMode) {
-    int iFile  = FairRunAna::Instance()->GetEventHeader()->GetInputFileId();
-    int iEvent = FairRunAna::Instance()->GetEventHeader()->GetMCEntryNumber();
-    fFileEventIDs.insert({iFile, iEvent});
+  fBestMcFile  = -1;
+  fBestMcEvent = -1;
+  if (pEvent) {
+    CbmMatch* pEvtMatch = pEvent->GetMatch();
+    assert(pEvtMatch);
+    int nLinks = pEvtMatch->GetNofLinks();
+    LOG(info) << "DEBUG: nof linked mc events " << nLinks << " of total " << fpMCEventList->GetNofEvents();
+    for (int iLink = 0; iLink < nLinks; ++iLink) {
+      const auto& link = pEvtMatch->GetLink(iLink);
+      fFileEventIDs.emplace(link.GetFile(), link.GetEntry());
+    }
+    if (nLinks > 1) {
+      const auto& bestLink = pEvtMatch->GetMatchedLink();
+      fBestMcFile          = bestLink.GetFile();
+      fBestMcEvent         = bestLink.GetEntry();
+    }
   }
   else {
     int nEvents = fpMCEventList->GetNofEvents();
     for (int iE = 0; iE < nEvents; ++iE) {
       int iFile  = fpMCEventList->GetFileIdByIndex(iE);
       int iEvent = fpMCEventList->GetEventIdByIndex(iE);
-      fFileEventIDs.insert({iFile, iEvent});
+      fFileEventIDs.emplace(iFile, iEvent);
     }
   }
 
@@ -203,6 +210,11 @@ void MCModule::InitTrackInfo()
     // Cut on max number of points on station
     isRec &= aTrk.GetMaxNofPointsOnStation() <= 3;
 
+    // Suppress MC tracks from complementary MC events
+    if (fBestMcFile >= 0 && (aTrk.GetFileId() != fBestMcFile || aTrk.GetEventId() != fBestMcEvent)) {
+      isRec = false;
+    }
+
     bool isAdd = isRec;  // is track additional
 
     // Cut on number of stations
@@ -345,10 +357,10 @@ void MCModule::CheckInit() const
   }
 
   // Check event list
-  if (!fbLegacyEventMode && !fpMCEventList) {
+  if (!fpMCEventList) {
     throw std::logic_error("MC event list was not found");
   }
-  if (!fbLegacyEventMode && !fpTimeSlice) {
+  if (!fpTimeSlice) {
     throw std::logic_error("Time slice was not found");
   }
 
@@ -380,6 +392,10 @@ void MCModule::CheckInit() const
 template<>
 void MCModule::ReadMCPointsForDetector<ca::EDetectorID::kTof>()
 {
+  if (!fvbUseDet[ca::EDetectorID::kTof]) {
+    return;
+  }
+
   auto* pBrHitMatches = fvpBrHitMatches[ca::EDetectorID::kTof];
   auto* pBrPoints     = fvpBrPoints[ca::EDetectorID::kTof];
 
@@ -497,21 +513,11 @@ void MCModule::ReadMCPoints()
   }
 
   // ----- Read MC points in MVD, STS, MuCh, TRD and TOF
-  if (fvbUseDet[ca::EDetectorID::kMvd]) {
-    this->ReadMCPointsForDetector<ca::EDetectorID::kMvd>();
-  }
-  if (fvbUseDet[ca::EDetectorID::kSts]) {
-    this->ReadMCPointsForDetector<ca::EDetectorID::kSts>();
-  }
-  if (fvbUseDet[ca::EDetectorID::kMuch]) {
-    this->ReadMCPointsForDetector<ca::EDetectorID::kMuch>();
-  }
-  if (fvbUseDet[ca::EDetectorID::kTrd]) {
-    this->ReadMCPointsForDetector<ca::EDetectorID::kTrd>();
-  }
-  if (fvbUseDet[ca::EDetectorID::kTof]) {
-    this->ReadMCPointsForDetector<ca::EDetectorID::kTof>();
-  }
+  ReadMCPointsForDetector<ca::EDetectorID::kMvd>();
+  ReadMCPointsForDetector<ca::EDetectorID::kSts>();
+  ReadMCPointsForDetector<ca::EDetectorID::kMuch>();
+  ReadMCPointsForDetector<ca::EDetectorID::kTrd>();
+  ReadMCPointsForDetector<ca::EDetectorID::kTof>();
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -520,15 +526,13 @@ void MCModule::ReadMCTracks()
 {
   // ----- Total number of tracks
   int nTracksTot = 0;
-  for (const auto& key : fFileEventIDs) {
-    nTracksTot += fpMCTracks->Size(key.first, key.second);  /// iFile, iEvent
+  for (const auto& [iFile, iEvent] : fFileEventIDs) {
+    nTracksTot += fpMCTracks->Size(iFile, iEvent);  /// iFile, iEvent
   }
   fpMCData->ReserveNofTracks(nTracksTot);
 
   // ----- Loop over MC events
-  for (const auto& key : fFileEventIDs) {
-    int iFile       = key.first;
-    int iEvent      = key.second;
+  for (const auto& [iFile, iEvent] : fFileEventIDs) {
     auto pEvtHeader = dynamic_cast<FairMCEventHeader*>(fpMCEventHeader->Get(iFile, iEvent));
     if (!pEvtHeader) {
       LOG(fatal) << "cbm::ca::MCModule: event header is not found for file " << iFile << " and event " << iEvent;
diff --git a/reco/L1/CbmCaMCModule.h b/reco/L1/CbmCaMCModule.h
index 26765dbdb7..6ed20f34f3 100644
--- a/reco/L1/CbmCaMCModule.h
+++ b/reco/L1/CbmCaMCModule.h
@@ -131,12 +131,6 @@ namespace cbm::ca
     /// @note Should be called before this->Init()
     void SetDetector(ca::EDetectorID detID, bool flag) { fvbUseDet[detID] = flag; }
 
-    /// @brief Sets legacy event mode:
-    /// @param flag Flag:
-    ///              - true:  runs on events base,
-    ///              - false: runs on time-slice base
-    void SetLegacyEventMode(bool flag) { fbLegacyEventMode = flag; }
-
     /// @brief Registers MC data object
     /// @param mcData  Instance of MC data
     void RegisterMCData(tools::MCData& mcData) { fpMCData = &mcData; }
@@ -229,7 +223,6 @@ namespace cbm::ca
 
     // ------ Flags
     DetIdArr_t<bool> fvbUseDet = {{false}};  ///< Flag: is detector subsystem used
-    bool fbLegacyEventMode     = false;      ///< if tracking uses events instead of time-slices (back compatibility)
     int fVerbose               = 1;          ///< Verbosity level
     int fPerformanceMode       = -1;         ///< Mode of performance
 
@@ -247,6 +240,9 @@ namespace cbm::ca
 
     // Matching information
     std::set<std::pair<int, int>> fFileEventIDs;  ///< Set of file and event indexes: first - iFile, second - iEvent
+    int fBestMcFile  = -1;                        ///< Index of bestly matched MC file
+    int fBestMcEvent = -1;                        ///< Index of bestly matched MC event
+
 
     // ----- Internal MC data
     tools::MCData* fpMCData = nullptr;  ///< MC information (hits and tracks) instance
@@ -256,7 +252,6 @@ namespace cbm::ca
     ca::Vector<CbmL1HitId>* fpvHitIds        = nullptr;  ///< Pointer to hit index container
     ca::Vector<CbmL1HitDebugInfo>* fpvQaHits = nullptr;  ///< Pointer to QA hit container
 
-
     /// @brief Pointer to array of first hit indexes in the detector subsystem
     ///
     /// This array must be initialized in the run initialization function.
@@ -491,6 +486,9 @@ namespace cbm::ca
   template<ca::EDetectorID DetID>
   void MCModule::ReadMCPointsForDetector()
   {
+    if (!fvbUseDet[DetID]) {
+      return;
+    }
     for (const auto& [iFile, iEvent] : fFileEventIDs) {
       int nPointsEvent = fvpBrPoints[DetID]->Size(iFile, iEvent);
       for (int iP = 0; iP < nPointsEvent; ++iP) {
diff --git a/reco/L1/CbmCaTimeSliceReader.cxx b/reco/L1/CbmCaTimeSliceReader.cxx
index 1e2d83e23e..d5e8d35e4c 100644
--- a/reco/L1/CbmCaTimeSliceReader.cxx
+++ b/reco/L1/CbmCaTimeSliceReader.cxx
@@ -186,8 +186,9 @@ catch (const std::logic_error& error) {
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void TimeSliceReader::InitTimeSlice()
+void TimeSliceReader::ReadEvent(CbmEvent* pEvent)
 {
+  fpEvent = pEvent;
   this->ReadHits();
   this->ReadRecoTracks();
 }
@@ -203,13 +204,15 @@ void TimeSliceReader::ReadRecoTracks()
   }
 
   assert(fpBrRecoTracks);
-  int nTracks = fpBrRecoTracks->GetEntriesFast();
-  fpvTracks->reset(nTracks);
+  int nTracks = 0;
   switch (fTrackingMode) {
     case ECbmCaTrackingMode::kSTS:
+      nTracks = fpEvent ? fpEvent->GetNofData(ECbmDataType::kStsTrack) : fpBrRecoTracks->GetEntriesFast();
+      fpvTracks->reset(nTracks);
       // Fill tracks from StsTrack branch
       for (int iT = 0; iT < nTracks; ++iT) {
-        auto* pInputTrack = static_cast<CbmStsTrack*>(fpBrRecoTracks->At(iT));
+        int iText         = fpEvent ? fpEvent->GetIndex(ECbmDataType::kStsTrack, iT) : iT;
+        auto* pInputTrack = static_cast<CbmStsTrack*>(fpBrRecoTracks->At(iText));
         auto& track       = (*fpvTracks)[iT];
 
         track.Set(cbm::L1Util::ConvertTrackParam(*pInputTrack->GetParamFirst()));
@@ -238,10 +241,12 @@ void TimeSliceReader::ReadRecoTracks()
       break;
 
     case ECbmCaTrackingMode::kMCBM:
-      //LOG(fatal) << "Sorry, mCBM mode has not been implemented yet. Stay tuned :)";
       // Fill tracks from GlobalTrack branch
+      nTracks = fpEvent ? fpEvent->GetNofData(ECbmDataType::kGlobalTrack) : fpBrRecoTracks->GetEntriesFast();
+      fpvTracks->reset(nTracks);
       for (int iT = 0; iT < nTracks; ++iT) {
-        auto* pInputTrack = static_cast<CbmGlobalTrack*>(fpBrRecoTracks->At(iT));
+        int iText         = fpEvent ? fpEvent->GetIndex(ECbmDataType::kGlobalTrack, iT) : iT;
+        auto* pInputTrack = static_cast<CbmGlobalTrack*>(fpBrRecoTracks->At(iText));
         auto& track       = (*fpvTracks)[iT];
         track.Set(cbm::L1Util::ConvertTrackParam(*pInputTrack->GetParamFirst()));
         track.TLast   = cbm::L1Util::ConvertTrackParam(*pInputTrack->GetParamLast());
@@ -355,7 +360,7 @@ void TimeSliceReader::ReadHits()
   // TODO: Address case with CbmEvent != nullptr
   for (int iDet = 0; iDet < static_cast<int>(ca::EDetectorID::kEND); ++iDet) {
     if (fvbUseDet[iDet]) {
-      fvNofHitsTotal[iDet] = fvpBrHits[iDet]->GetEntriesFast();
+      fvNofHitsTotal[iDet] = fpEvent ? fpEvent->GetNofData(kCbmHitType[iDet]) : fvpBrHits[iDet]->GetEntriesFast();
     }
   }
 
diff --git a/reco/L1/CbmCaTimeSliceReader.h b/reco/L1/CbmCaTimeSliceReader.h
index 6a211addbe..1a1a0b51c4 100644
--- a/reco/L1/CbmCaTimeSliceReader.h
+++ b/reco/L1/CbmCaTimeSliceReader.h
@@ -7,13 +7,13 @@
 /// @since  24.02.2023
 /// @author Sergei Zharko <s.zharko@gsi.de>
 
-#ifndef CbmCaTimeSliceReader_h
-#define CbmCaTimeSliceReader_h 1
+#pragma once
 
 #include "CaConstants.h"
 #include "CaToolsHitRecord.h"
 #include "CaVector.h"
 #include "CbmCaMCModule.h"
+#include "CbmEvent.h"
 #include "CbmL1.h"  // TMP: for CbmL1HitStore
 #include "CbmL1DetectorID.h"
 #include "CbmL1Hit.h"
@@ -31,7 +31,6 @@
 #include "CbmTrdTrackingInterface.h"
 #include "TClonesArray.h"
 
-
 class CbmTimeSlice;
 namespace cbm::algo::ca
 {
@@ -41,7 +40,6 @@ namespace cbm::algo::ca
 
 namespace cbm::ca
 {
-
   /// @brief A reader of time slice for CA tracker
   ///
   /// The class reads reconstructed hits and reconstructed tracks (optionally) and fills the CA tracking internal
@@ -93,9 +91,10 @@ namespace cbm::ca
     bool InitRun();
 
     /// @brief Reads time slice
+    /// @param pEvent  A pointer to CbmEvent
     ///
     /// Reads hits and tracks (optionally) from time slice
-    void InitTimeSlice();
+    void ReadEvent(CbmEvent* pEvent = nullptr);
 
     /// @brief Registers hit debug info container
     /// @param vQaHits  Reference to Qa hit container
@@ -131,7 +130,6 @@ namespace cbm::ca
     /// @param  mode Tracking mode (from ECbmTrackingMode)
     void SetTrackingMode(ECbmCaTrackingMode mode) { fTrackingMode = mode; }
 
-
    private:
     /// @brief Check class initialization
     /// @note The function throws std::logic_error, if initialization is incomplete
@@ -164,6 +162,7 @@ namespace cbm::ca
 
     // Input data branches
     CbmTimeSlice* fpBrTimeSlice         = nullptr;      ///< Pointer to the TS object
+    CbmEvent* fpEvent                   = nullptr;      ///< Pointer to the event object
     DetIdArr_t<TClonesArray*> fvpBrHits = {{nullptr}};  ///< Input branch for hits
 
     // Branches for reconstructed tracks. The input at the moment (as for 27.02.2023) depends on the selected
@@ -211,6 +210,8 @@ namespace cbm::ca
 template<ca::EDetectorID DetID>
 int cbm::ca::TimeSliceReader::ReadHitsForDetector()
 {
+  using Hit_t = HitTypes_t::at<DetID>;
+
   if (!fvbUseDet[DetID]) {
     return 0;
   }  // Detector is entirelly not used
@@ -221,51 +222,27 @@ int cbm::ca::TimeSliceReader::ReadHitsForDetector()
 
   fFirstHitKey = fNofHitKeys;
 
-  for (int iHext = 0; iHext < nHitsTot; ++iHext) {
+  for (int iH = 0; iH < nHitsTot; ++iH) {
+    int iHext = fpEvent ? fpEvent->GetIndex(kCbmHitType[DetID], iH) : iH;
     tools::HitRecord hitRecord;
 
-    CbmPixelHit* pPixelHit = nullptr;  // Pointer to hit object
-    int iStGeom            = -1;       // Geometry station number
+    auto* pHit  = static_cast<Hit_t*>(fvpBrHits[DetID]->At(iHext));
+    int iStGeom = pDetInterface->GetTrackingStationIndex(pHit);
 
     // Fill out detector specific data
-    if constexpr (ca::EDetectorID::kMvd == DetID) {
-      CbmMvdHit* pMvdHit = static_cast<CbmMvdHit*>(fvpBrHits[DetID]->At(iHext));
-      pPixelHit          = static_cast<CbmPixelHit*>(pMvdHit);
-      iStGeom            = pDetInterface->GetTrackingStationIndex(pMvdHit);
-    }
-    else if constexpr (ca::EDetectorID::kSts == DetID) {
-      CbmStsHit* pStsHit = static_cast<CbmStsHit*>(fvpBrHits[DetID]->At(iHext));
-      pPixelHit          = static_cast<CbmPixelHit*>(pStsHit);
-      iStGeom            = pDetInterface->GetTrackingStationIndex(pStsHit->GetAddress());
-      hitRecord.fStripF  = fFirstHitKey + pStsHit->GetFrontClusterId();
-      hitRecord.fStripB  = fFirstHitKey + pStsHit->GetBackClusterId();
-    }
-    else if constexpr (ca::EDetectorID::kMuch == DetID) {
-      CbmMuchPixelHit* pMuchHit = static_cast<CbmMuchPixelHit*>(fvpBrHits[DetID]->At(iHext));
-      pPixelHit                 = static_cast<CbmPixelHit*>(pMuchHit);
-      iStGeom                   = pDetInterface->GetTrackingStationIndex(pMuchHit->GetAddress());
-    }
-    else if constexpr (ca::EDetectorID::kTrd == DetID) {
-      CbmTrdHit* pTrdHit = static_cast<CbmTrdHit*>(fvpBrHits[DetID]->At(iHext));
-      pPixelHit          = static_cast<CbmPixelHit*>(pTrdHit);
-      iStGeom            = pDetInterface->GetTrackingStationIndex(pTrdHit->GetAddress());
+    if constexpr (ca::EDetectorID::kSts == DetID) {
+      hitRecord.fStripF = fFirstHitKey + pHit->GetFrontClusterId();
+      hitRecord.fStripB = fFirstHitKey + pHit->GetBackClusterId();
     }
     else if constexpr (ca::EDetectorID::kTof == DetID) {
-      CbmTofHit* pTofHit = static_cast<CbmTofHit*>(fvpBrHits[DetID]->At(iHext));
-      pPixelHit          = static_cast<CbmPixelHit*>(pTofHit);
-      // NOTE: In TOF we can take station index only from hit, because the function needs information on x and z
-      //       of the hit in case of "beam_mcbm_2021_07_surveyed" (missingHits flag = true).
-      // TODO: Investigate this case or apply the hack to the TOF level
-      iStGeom = pDetInterface->GetTrackingStationIndex(pTofHit);
-
       // *** Additional cuts for TOF ***
       // Skip Bmon hits
-      if (5 == CbmTofAddress::GetSmType(pTofHit->GetAddress())) {
+      if (5 == CbmTofAddress::GetSmType(pHit->GetAddress())) {
         continue;
       }
 
       // FIXME: Figure it out, if this cut is still needed (introduced a year ago for mCBM)
-      if (ECbmCaTrackingMode::kMCBM == fTrackingMode && pTofHit->GetZ() > 400) {
+      if (ECbmCaTrackingMode::kMCBM == fTrackingMode && pHit->GetZ() > 400) {
         continue;
       }
     }
@@ -277,19 +254,19 @@ int cbm::ca::TimeSliceReader::ReadHitsForDetector()
 
     // Fill out data common for all the detectors
     hitRecord.fStaId = iStActive;
-    hitRecord.fX     = pPixelHit->GetX();
-    hitRecord.fY     = pPixelHit->GetY();
-    hitRecord.fZ     = pPixelHit->GetZ();
-    hitRecord.fDx2   = pPixelHit->GetDx() * pPixelHit->GetDx();
-    hitRecord.fDy2   = pPixelHit->GetDy() * pPixelHit->GetDy();
-    hitRecord.fDxy   = pPixelHit->GetDxy();
-    hitRecord.fT     = pPixelHit->GetTime();
-    hitRecord.fDt2   = pPixelHit->GetTimeError() * pPixelHit->GetTimeError();
+    hitRecord.fX     = pHit->GetX();
+    hitRecord.fY     = pHit->GetY();
+    hitRecord.fZ     = pHit->GetZ();
+    hitRecord.fDx2   = pHit->GetDx() * pHit->GetDx();
+    hitRecord.fDy2   = pHit->GetDy() * pHit->GetDy();
+    hitRecord.fDxy   = pHit->GetDxy();
+    hitRecord.fT     = pHit->GetTime();
+    hitRecord.fDt2   = pHit->GetTimeError() * pHit->GetTimeError();
 
-    std::tie(hitRecord.fRangeX, hitRecord.fRangeY, hitRecord.fRangeT) = pDetInterface->GetHitRanges(*pPixelHit);
+    std::tie(hitRecord.fRangeX, hitRecord.fRangeY, hitRecord.fRangeT) = pDetInterface->GetHitRanges(*pHit);
 
     hitRecord.fDet        = static_cast<int>(DetID);
-    hitRecord.fDataStream = (static_cast<int64_t>(hitRecord.fDet) << 60) | pPixelHit->GetAddress();
+    hitRecord.fDataStream = (static_cast<int64_t>(hitRecord.fDet) << 60) | pHit->GetAddress();
     hitRecord.fExtId      = iHext;
 
     // Update number of hit keys
@@ -318,5 +295,3 @@ int cbm::ca::TimeSliceReader::ReadHitsForDetector()
 
   return nHitsStored;
 }
-
-#endif  // CbmCaTimeSliceReader_h
diff --git a/reco/L1/CbmL1DetectorID.h b/reco/L1/CbmL1DetectorID.h
index 4d1b66358d..2fc2733ac7 100644
--- a/reco/L1/CbmL1DetectorID.h
+++ b/reco/L1/CbmL1DetectorID.h
@@ -7,11 +7,11 @@
 /// @author S.Zharko
 /// @since  01.12.2022
 
-#ifndef CbmL1DetectorID_h
-#define CbmL1DetectorID_h 1
+#pragma once
 
 #include "CaConstants.h"
 #include "CaEnumArray.h"
+#include "CbmDefs.h"
 
 #include <string>
 
@@ -92,6 +92,18 @@ namespace cbm::ca
   /// @brief Name of point branches for each detector
   constexpr DetIdArr_t<const char*> kDetPointBrName = {{"MvdPoint", "StsPoint", "MuchPoint", "TrdPoint", "TofPoint"}};
 
+  /// @brief Data type of hits (for CbmEvent)
+  /* clang-format off */
+  constexpr DetIdArr_t<ECbmDataType> kCbmHitType = 
+  {{
+    ECbmDataType::kMvdHit, 
+    ECbmDataType::kStsHit, 
+    ECbmDataType::kMuchPixelHit, 
+    ECbmDataType::kTrdHit, 
+    ECbmDataType::kTofHit
+  }};
+  /* clang-format on */
+
   /// @brief Name
 
   /// @brief Types of MC point objects for each detector
@@ -108,6 +120,3 @@ enum class ECbmCaTrackingMode
   kSTS,  ///< Local tracking in CBM (STS + MVD), results stored to the StsTrack branch
   kMCBM  ///< Global tracking in mCBM (STS, MuCh, TRD, TOF), results stored to GlobalTrack branch
 };
-
-
-#endif  // CbmL1DetectorID_h
diff --git a/reco/L1/qa/CbmCaOutputQa.cxx b/reco/L1/qa/CbmCaOutputQa.cxx
index 7dc3590589..d99cac0f81 100644
--- a/reco/L1/qa/CbmCaOutputQa.cxx
+++ b/reco/L1/qa/CbmCaOutputQa.cxx
@@ -934,7 +934,7 @@ InitStatus OutputQa::InitTimeSlice()
 
 
   // Read reconstructed input
-  fpTSReader->InitTimeSlice();
+  fpTSReader->ReadEvent(this->GetCurrentEvent());
   nHits       = fvHits.size();
   nRecoTracks = fvRecoTracks.size();
 
@@ -944,7 +944,7 @@ InitStatus OutputQa::InitTimeSlice()
   // Match tracks and points
   // Read MC tracks and points
   if (IsMCUsed()) {
-    fpMCModule->InitEvent(nullptr);
+    fpMCModule->InitEvent(this->GetCurrentEvent());
     nMCPoints = fMCData.GetNofPoints();
     nMCTracks = fMCData.GetNofTracks();
     fpMCModule->MatchRecoAndMC();
-- 
GitLab