diff --git a/core/qa/CbmQaCmpDrawer.cxx b/core/qa/CbmQaCmpDrawer.cxx
index 84ef5bc25b80c547b79e812f32e6fe6c31548b5a..ed2b2305db77f7a965137be7ee3b3d1765862d69 100644
--- a/core/qa/CbmQaCmpDrawer.cxx
+++ b/core/qa/CbmQaCmpDrawer.cxx
@@ -18,4 +18,3 @@ template class CbmQaCmpDrawer<TH1F>;
 template class CbmQaCmpDrawer<TProfile>;
 template class CbmQaCmpDrawer<TH2F>;
 template class CbmQaCmpDrawer<TProfile2D>;
-
diff --git a/macro/mcbm/mcbm_qa.C b/macro/mcbm/mcbm_qa.C
index 363d9c0059d99f2c3d18b8cdb34cceedb5111523..2d4d45fd99a7148c8910f03cded9b10348475f6d 100644
--- a/macro/mcbm/mcbm_qa.C
+++ b/macro/mcbm/mcbm_qa.C
@@ -244,7 +244,7 @@ void mcbm_qa(Int_t nEvents = 0, TString dataset = "data/mcbm_beam_2020_03_test",
   pCaOutputQa->SetMcbmTrackingMode();
   pCaOutputQa->ReadParameters(caParFile.Data());
   pCaOutputQa->SetUseSts(bUseSts);
-  //pCaOutputQa->SetUseMuch(bUseMuch);
+  pCaOutputQa->SetUseMuch(bUseMuch);
   pCaOutputQa->SetUseTrd(bUseTrd);
   pCaOutputQa->SetUseTof(bUseTof);
   run->AddTask(pCaOutputQa);
diff --git a/reco/L1/CMakeLists.txt b/reco/L1/CMakeLists.txt
index 53086f8c772ac6acef3623a216fd2b7294c177fa..469c472599a677bccae98991fa0b832735459aa0 100644
--- a/reco/L1/CMakeLists.txt
+++ b/reco/L1/CMakeLists.txt
@@ -38,7 +38,7 @@ set(SRCS
   OffLineInterface/CbmL1StsTrackFinder.cxx
   OffLineInterface/CbmL1GlobalTrackFinder.cxx
   OffLineInterface/CbmL1GlobalFindTracksEvents.cxx
-
+  L1Algo/utils/CaAlgoRandom.cxx
   L1Algo/L1Algo.cxx
   L1Algo/L1TrackPar.cxx
   L1Algo/L1CaTrackFinder.cxx
@@ -115,6 +115,7 @@ set(HEADERS
   L1Algo/L1Undef.h
   catools/CaToolsWindowFinder.h
   catools/CaToolsLinkKey.h
+  catools/CaToolsHitRecord.h
   qa/CbmCaInputQaBase.h
 )
 
diff --git a/reco/L1/CbmCaMCModule.cxx b/reco/L1/CbmCaMCModule.cxx
index 2263509a63b89985b74b0d7d53927c0dbe542e80..db1e8fc942f59fd4df8f048f8c97f1e3020f2b02 100644
--- a/reco/L1/CbmCaMCModule.cxx
+++ b/reco/L1/CbmCaMCModule.cxx
@@ -1,4 +1,4 @@
-/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
    SPDX-License-Identifier: GPL-3.0-only
    Authors: Sergei Zharko [committer] */
 
@@ -19,7 +19,6 @@
 #include "CbmMCTrack.h"
 #include "CbmStsHit.h"
 #include "CbmTimeSlice.h"
-
 #include "FairEventHeader.h"
 #include "FairMCEventHeader.h"
 #include "FairRootManager.h"
@@ -42,6 +41,8 @@
 // *********************************
 
 using cbm::ca::MCModule;
+using L1Constants::clrs::kCL;   // clear log
+using L1Constants::clrs::kRDb;  // red bold log
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
@@ -63,60 +64,43 @@ try {
   fpMCEventHeader = mcManager->GetObject("MCEventHeader.");
   fpMCTracks      = mcManager->InitBranch("MCTrack");
 
-  fpMvdPoints  = nullptr;
-  fpStsPoints  = nullptr;
-  fpMuchPoints = nullptr;
-  fpTrdPoints  = nullptr;
-  fpTofPoints  = nullptr;
-
-  fpMvdHitMatches  = nullptr;
-  fpStsHitMatches  = nullptr;
-  fpMuchHitMatches = nullptr;
-  fpTrdHitMatches  = nullptr;
-  fpTofHitMatches  = nullptr;
+  fvpBrPoints.fill(nullptr);
+  fvpBrHitMatches.fill(nullptr);
 
   fpStsClusterMatches = nullptr;
   fpStsHits           = nullptr;
 
   fFileEventIDs.clear();
 
-  if (fbUseMvd) {
-    LOG(info) << "CA MC Module: initializing branches for MVD";
-    fpMvdPoints     = mcManager->InitBranch("MvdPoint");
-    fpMvdHitMatches = dynamic_cast<TClonesArray*>(fairManager->GetObject("MvdHitMatch"));
-  }
+  auto InitPointBranch = [&](const char* brName, L1DetectorID detID) {
+    if (fvbUseDet[detID]) { fvpBrPoints[detID] = mcManager->InitBranch(brName); }
+  };
 
-  if (fbUseSts) {
-    LOG(info) << "CA MC Module: initializing branches for STS";
-    fpStsPoints         = mcManager->InitBranch("StsPoint");
-    fpStsHitMatches     = dynamic_cast<TClonesArray*>(fairManager->GetObject("StsHitMatch"));
-    fpStsClusterMatches = dynamic_cast<TClonesArray*>(fairManager->GetObject("StsClusterMatch"));
-    fpStsHits           = dynamic_cast<TClonesArray*>(fairManager->GetObject("StsHit"));
-  }
+  auto InitMatchesBranch = [&](const char* brName, L1DetectorID detID) {
+    if (fvbUseDet[detID]) { fvpBrHitMatches[detID] = dynamic_cast<TClonesArray*>(fairManager->GetObject(brName)); }
+  };
 
-  if (fbUseMuch) {
-    LOG(info) << "CA MC Module: initializing branches for MuCh";
-    fpMuchPoints     = mcManager->InitBranch("MuchPoint");
-    fpMuchHitMatches = dynamic_cast<TClonesArray*>(fairManager->GetObject("MuchPixelHitMatch"));
-  }
+  InitPointBranch("MvdPoint", L1DetectorID::kMvd);
+  InitPointBranch("StsPoint", L1DetectorID::kSts);
+  InitPointBranch("MuchPoint", L1DetectorID::kMuch);
+  InitPointBranch("TrdPoint", L1DetectorID::kTrd);
+  InitPointBranch("TofPoint", L1DetectorID::kTof);
 
-  if (fbUseTrd) {
-    LOG(info) << "CA MC Module: initializing branches for TRD";
-    fpTrdPoints     = mcManager->InitBranch("TrdPoint");
-    fpTrdHitMatches = dynamic_cast<TClonesArray*>(fairManager->GetObject("TrdHitMatch"));
-  }
+  InitMatchesBranch("MvdHitMatch", L1DetectorID::kMvd);
+  InitMatchesBranch("StsHitMatch", L1DetectorID::kSts);
+  InitMatchesBranch("MuchPixelHitMatch", L1DetectorID::kMuch);
+  InitMatchesBranch("TrdHitMatch", L1DetectorID::kTrd);
+  InitMatchesBranch("TofHitMatch", L1DetectorID::kTof);
 
-  if (fbUseTof) {
-    LOG(info) << "CA MC Module: initializing branches for TOF";
-    fpTofPoints     = mcManager->InitBranch("TofPoint");
-    fpTofHitMatches = dynamic_cast<TClonesArray*>(fairManager->GetObject("TofHitMatch"));
+  if (fvbUseDet[L1DetectorID::kSts]) {
+    fpStsClusterMatches = dynamic_cast<TClonesArray*>(fairManager->GetObject("StsClusterMatch"));
+    fpStsHits           = dynamic_cast<TClonesArray*>(fairManager->GetObject("StsHit"));
   }
 
   // Check initialization
   this->CheckInit();
 
   LOG(info) << "CA MC Module: initializing CA tracking Monte-Carlo module... \033[1;32mDone!\033[0m";
-
   return true;
 }
 catch (const std::logic_error& error) {
@@ -217,7 +201,11 @@ void MCModule::Finish() {}
 //
 void MCModule::MatchRecoAndMC()
 {
-  this->MatchPointsAndHits();
+  this->MatchPointsAndHits<L1DetectorID::kMvd>();
+  this->MatchPointsAndHits<L1DetectorID::kSts>();
+  this->MatchPointsAndHits<L1DetectorID::kMuch>();
+  this->MatchPointsAndHits<L1DetectorID::kTrd>();
+  this->MatchPointsAndHits<L1DetectorID::kTof>();
   this->MatchRecoAndMCTracks();
   this->InitTrackInfo();
 }
@@ -229,13 +217,10 @@ template<>
 int MCModule::MatchHitWithMc<L1DetectorID::kMvd>(int iHitExt) const
 {
   int iPoint = -1;
-  if (fpMvdHitMatches) {
-    const auto* hitMatch = dynamic_cast<CbmMatch*>(fpMvdHitMatches->At(iHitExt));
-    assert(hitMatch);
-    if (hitMatch->GetNofLinks() > 0
-        && hitMatch->GetLink(0).GetIndex() < fpMCData->GetNofPointsUsed(L1DetectorID::kMvd)) {
-      iPoint = hitMatch->GetLink(0).GetIndex();
-    }
+  const auto* hitMatch = dynamic_cast<CbmMatch*>(fvpBrHitMatches[L1DetectorID::kMvd]->At(iHitExt));
+  assert(hitMatch);
+  if (hitMatch->GetNofLinks() > 0 && hitMatch->GetLink(0).GetIndex() < fpMCData->GetNofPointsUsed(L1DetectorID::kMvd)) {
+    iPoint = hitMatch->GetLink(0).GetIndex();
   }
   return iPoint;
 }
@@ -302,7 +287,7 @@ template<>
 int MCModule::MatchHitWithMc<L1DetectorID::kMuch>(int iHitExt) const
 {
   int iPoint               = -1;
-  const auto* hitMatchMuch = dynamic_cast<CbmMatch*>(fpMuchHitMatches->At(iHitExt));
+  const auto* hitMatchMuch = dynamic_cast<CbmMatch*>(fvpBrHitMatches[L1DetectorID::kMuch]->At(iHitExt));
   if (hitMatchMuch) {
     for (int iLink = 0; iLink < hitMatchMuch->GetNofLinks(); ++iLink) {
       if (hitMatchMuch->GetLink(iLink).GetIndex() < fpMCData->GetNofPointsUsed(L1DetectorID::kMuch)) {
@@ -327,7 +312,7 @@ template<>
 int MCModule::MatchHitWithMc<L1DetectorID::kTrd>(int iHitExt) const
 {
   int iPoint           = -1;
-  const auto* hitMatch = dynamic_cast<const CbmMatch*>(fpTrdHitMatches->At(iHitExt));
+  const auto* hitMatch = dynamic_cast<const CbmMatch*>(fvpBrHitMatches[L1DetectorID::kTrd]->At(iHitExt));
   if (hitMatch) {
     int iMC = -1;
     if (hitMatch->GetNofLinks() > 0) {
@@ -351,8 +336,9 @@ int MCModule::MatchHitWithMc<L1DetectorID::kTrd>(int iHitExt) const
 template<>
 int MCModule::MatchHitWithMc<L1DetectorID::kTof>(int iHitExt) const
 {
+  // TODO: SZh 23.05.2023: Use TOF interactions class
   int iPoint           = -1;
-  const auto* hitMatch = dynamic_cast<const CbmMatch*>(fpTofHitMatches->At(iHitExt));
+  const auto* hitMatch = dynamic_cast<const CbmMatch*>(fvpBrHitMatches[L1DetectorID::kTof]->At(iHitExt));
   if (hitMatch) {
     for (int iLink = 0; iLink < hitMatch->GetNofLinks(); ++iLink) {
       int iMc    = hitMatch->GetLink(iLink).GetIndex();
@@ -360,7 +346,7 @@ int MCModule::MatchHitWithMc<L1DetectorID::kTof>(int iHitExt) const
       int iEvent = hitMatch->GetLink(iLink).GetEntry();
       if (iMc < 0) return iPoint;
 
-      assert(iMc >= 0 && iMc < fpTofPoints->Size(iFile, iEvent));
+      assert(iMc >= 0 && iMc < fvpBrPoints[L1DetectorID::kTof]->Size(iFile, iEvent));
       int iPointPrelim = fpMCData->FindInternalPointIndex(L1DetectorID::kTof, iMc, iEvent, iFile);
       if (iPointPrelim == -1) { continue; }
       iPoint = iPointPrelim;
@@ -369,54 +355,7 @@ int MCModule::MatchHitWithMc<L1DetectorID::kTof>(int iHitExt) const
   return iPoint;
 }
 
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void MCModule::MatchPointsAndHits()
-{
-  // Clear point indexes of each hit
-  // NOTE: at the moment only the best point is stored to the hit, but we keep the possibility for keeping many
-  //       points for possible future module extension.
-  for (auto& hit : (*fpvQaHits)) {
-    hit.mcPointIds.clear();
-  }
 
-  // Match hit with point for different detectors
-  auto DoMatch = [&](int iH, int iP) constexpr
-  {
-    if (iP > -1) {
-      auto& hit = (*fpvQaHits)[iH];
-      hit.mcPointIds.push_back_no_warning(iP);
-      fpMCData->GetPoint(iP).AddHitID(iH);
-    }
-  };
-
-  int iH = 0;
-  if (fbUseMvd) {
-    for (iH = (*fpvFstHitId)[int(L1DetectorID::kMvd)]; iH < (*fpvFstHitId)[int(L1DetectorID::kMvd) + 1]; ++iH) {
-      DoMatch(iH, MatchHitWithMc<L1DetectorID::kMvd>((*fpvQaHits)[iH].ExtIndex));
-    }
-  }
-  if (fbUseSts) {
-    for (iH = (*fpvFstHitId)[int(L1DetectorID::kSts)]; iH < (*fpvFstHitId)[int(L1DetectorID::kSts) + 1]; ++iH) {
-      DoMatch(iH, MatchHitWithMc<L1DetectorID::kSts>((*fpvQaHits)[iH].ExtIndex));
-    }
-  }
-  if (fbUseSts) {
-    for (iH = (*fpvFstHitId)[int(L1DetectorID::kMuch)]; iH < (*fpvFstHitId)[int(L1DetectorID::kMuch) + 1]; ++iH) {
-      DoMatch(iH, MatchHitWithMc<L1DetectorID::kMuch>((*fpvQaHits)[iH].ExtIndex));
-    }
-  }
-  if (fbUseTrd) {
-    for (iH = (*fpvFstHitId)[int(L1DetectorID::kTrd)]; iH < (*fpvFstHitId)[int(L1DetectorID::kTrd) + 1]; ++iH) {
-      DoMatch(iH, MatchHitWithMc<L1DetectorID::kTrd>((*fpvQaHits)[iH].ExtIndex));
-    }
-  }
-  if (fbUseTof) {
-    for (iH = (*fpvFstHitId)[int(L1DetectorID::kTof)]; iH < (*fpvFstHitId)[int(L1DetectorID::kTof) + 1]; ++iH) {
-      DoMatch(iH, MatchHitWithMc<L1DetectorID::kTof>((*fpvQaHits)[iH].ExtIndex));
-    }
-  }
-}
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
@@ -429,14 +368,15 @@ void MCModule::MatchRecoAndMCTracks()
     auto& mNofHitsVsMCTrkID = trkRe.hitMap;
     //mNofHitsVsMCTrkID.clear();
     for (int iH : trkRe.Hits) {
-      for (int iP : (*fpvQaHits)[iH].mcPointIds) {
-        assert(iP > -1);  // Should never be triggered
+      int iP = (*fpvQaHits)[iH].GetMCPointIndex();
+      L1_SHOW(iP);
+      if (iP > -1) {
         int iTmc = fpMCData->GetPoint(iP).GetTrackId();
         if (mNofHitsVsMCTrkID.find(iTmc) == mNofHitsVsMCTrkID.end()) { mNofHitsVsMCTrkID[iTmc] = 1; }
         else {
           mNofHitsVsMCTrkID[iTmc] += 1;
         }
-      }  // loop over global point ids stored for hit: end
+      }
     }    // loop over hit ids stored for a reconstructed track: end
 
 
@@ -473,25 +413,6 @@ void MCModule::MatchRecoAndMCTracks()
   }  // loop over reconstructed tracks: end
 }
 
-
-// ***********************
-// **     Accessors     **
-// ***********************
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void MCModule::SetDetector(L1DetectorID detID, bool flag)
-{
-  switch (detID) {
-    case L1DetectorID::kMvd: fbUseMvd = flag; break;
-    case L1DetectorID::kSts: fbUseSts = flag; break;
-    case L1DetectorID::kMuch: fbUseMuch = flag; break;
-    case L1DetectorID::kTrd: fbUseTrd = flag; break;
-    case L1DetectorID::kTof: fbUseTof = flag; break;
-    case L1DetectorID::kEND: break;
-  }
-}
-
 // *******************************
 // **     Utility functions     **
 // *******************************
@@ -521,43 +442,26 @@ void MCModule::CheckInit() const
   if (!fpMCEventHeader) { throw std::logic_error("MC event header is unavailable"); }
 
   // Check detectors initialization
-  if (fbUseMvd) {
-    if (!fpMvdPoints) { throw std::logic_error("MC points unavailable for MVD"); }
-    if (!fpMvdHitMatches) { throw std::logic_error("Hit matches unavailable for MVD"); }
+  for (int iD = 0; iD < static_cast<int>(L1DetectorID::kEND); ++iD) {
+    if (fvbUseDet[iD]) {
+      if (!fvpBrPoints[iD]) { throw std::logic_error(Form("MC points are unavailable for %s", kDetName[iD])); }
+      if (!fvpBrHitMatches[iD]) { throw std::logic_error(Form("Hit matches are unavailable for %s", kDetName[iD])); }
+    }
   }
 
-  if (fbUseSts) {
-    if (!fpStsPoints) { throw std::logic_error("MC points unavailable for STS"); }
-    if (!fpStsHitMatches) { throw std::logic_error("Hit matches unavailable for STS"); }
+  if (fvbUseDet[L1DetectorID::kSts]) {
     if (!fpStsClusterMatches) { throw std::logic_error("Cluster matches unavailable for STS"); }
     if (!fpStsHits) { throw std::logic_error("Hits unavailable for STS"); }
   }
-
-  if (fbUseMuch) {
-    if (!fpMuchPoints) { throw std::logic_error("MC points unavailable for MuCh"); }
-    if (!fpMuchHitMatches) { throw std::logic_error("Hit matches unavailable for MuCh"); }
-  }
-
-  if (fbUseTrd) {
-    if (!fpTrdPoints) { throw std::logic_error("MC points unavailable for TRD"); }
-    if (!fpTrdHitMatches) { throw std::logic_error("Hit matches unavailable for TRD"); }
-  }
-
-  if (fbUseTof) {
-    if (!fpTofPoints) { throw std::logic_error("MC points unavailable for TOF"); }
-    if (!fpTofHitMatches) { throw std::logic_error("Hit matches unavailable for TOF"); }
-  }
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<>
-void MCModule::ReadMCPointsForDetector<L1DetectorID::kTof>(CbmMCDataArray* pPoints)
+void MCModule::ReadMCPointsForDetector<L1DetectorID::kTof>()
 {
-  for (const auto& key : fFileEventIDs) {
-    int iFile  = key.first;
-    int iEvent = key.second;
-
+  auto* pPoints = fvpBrPoints[L1DetectorID::kTof];
+  for (const auto& [iFile, iEvent] : fFileEventIDs) {
     // Prepare TODO
     int nTofStationsGeo = fpParameters->GetNstationsGeometry(L1DetectorID::kTof);
     std::vector<std::vector<int>> vTofPointToTrack(nTofStationsGeo);      // TODO
@@ -573,7 +477,7 @@ void MCModule::ReadMCPointsForDetector<L1DetectorID::kTof>(CbmMCDataArray* pPoin
     // Check whether a particular TOF point is matched to a hit
     auto* pTofHits = dynamic_cast<TClonesArray*>(FairRootManager::Instance()->GetObject("TofHit"));
     for (int iHit = 0; iHit < pTofHits->GetEntriesFast(); ++iHit) {
-      auto* pHitMatch = L1_DYNAMIC_CAST<CbmMatch*>(fpTofHitMatches->At(iHit));
+      auto* pHitMatch = L1_DYNAMIC_CAST<CbmMatch*>(fvpBrHitMatches[L1DetectorID::kTof]->At(iHit));
       LOG_IF(fatal, !pHitMatch) << "CA MC Module: hit match was not found for TOF hit " << iHit;
       for (int iLink = 0; iLink < pHitMatch->GetNofLinks(); ++iLink) {
         const auto& link = pHitMatch->GetLink(iLink);
@@ -627,14 +531,10 @@ void MCModule::ReadMCPointsForDetector<L1DetectorID::kTof>(CbmMCDataArray* pPoin
       if (iStActive < 0) { continue; }
       for (int iTrk = 0; iTrk < (int) vTofPointToTrack[iStLocGeo].size(); ++iTrk) {
         if (vTofPointToTrack[iStLocGeo][iTrk] < 0) { continue; }
-        ::ca::tools::MCPoint aPoint;
-        if (FillMCPoint<L1DetectorID::kTof>(vTofPointToTrack[iStLocGeo][iTrk], iEvent, iFile, aPoint)) {
-          aPoint.SetStationId(iStActive);
-          int iExtGlob = fpMCData->GetPointGlobExtIndex(L1DetectorID::kTof, vTofPointToTrack[iStLocGeo][iTrk]);
-          aPoint.SetExternalId(iExtGlob);
-          int iPInt = fpMCData->GetNofPoints();  // assign an index of point in internal container
-          if (aPoint.GetTrackId() > -1) { fpMCData->GetTrack(aPoint.GetTrackId()).AddPointIndex(iPInt); }
-          fpMCData->AddPoint(aPoint);
+        auto oPoint = FillMCPoint<L1DetectorID::kTof>(vTofPointToTrack[iStLocGeo][iTrk], iEvent, iFile);
+        if (oPoint) {
+          oPoint->SetStationId(iStActive);
+          fpMCData->AddPoint(*oPoint);
         }
       }  // loop over tracks: end
     }    // loop over geometry stations: end
@@ -648,34 +548,20 @@ void MCModule::ReadMCPoints()
   int nPointsEstimated = 5 * fpMCData->GetNofTracks() * fpParameters->GetNstationsActive();
   fpMCData->ReserveNofPoints(nPointsEstimated);
 
-  int nPointsMvd  = 0;
-  int nPointsSts  = 0;
-  int nPointsMuch = 0;
-  int nPointsTrd  = 0;
-  int nPointsTof  = 0;
-  for (const auto& key : fFileEventIDs) {
-    int iFile  = key.first;
-    int iEvent = key.second;
-
-    if (fbUseMvd) { nPointsMvd += fpMvdPoints->Size(iFile, iEvent); }
-    if (fbUseSts) { nPointsSts += fpStsPoints->Size(iFile, iEvent); }
-    if (fbUseMuch) { nPointsMuch += fpMuchPoints->Size(iFile, iEvent); }
-    if (fbUseTrd) { nPointsTrd += fpTrdPoints->Size(iFile, iEvent); }
-    if (fbUseTof) { nPointsTof += fpTofPoints->Size(iFile, iEvent); }
+  CbmCaDetIdArr_t<int> vNofPointsDet = {0};
+  for (const auto& [iFile, iEvent] : fFileEventIDs) {
+    for (int iD = 0; iD < static_cast<int>(vNofPointsDet.size()); ++iD) {
+      if (fvbUseDet[iD]) { vNofPointsDet[iD] = fvpBrPoints[iD]->Size(iFile, iEvent); }
+      fpMCData->SetNofPointsOrig(static_cast<L1DetectorID>(iD), vNofPointsDet[iD]);
+    }
   }
 
-  fpMCData->SetNofPointsOrig(L1DetectorID::kMvd, nPointsMvd);
-  fpMCData->SetNofPointsOrig(L1DetectorID::kSts, nPointsSts);
-  fpMCData->SetNofPointsOrig(L1DetectorID::kMuch, nPointsMuch);
-  fpMCData->SetNofPointsOrig(L1DetectorID::kTrd, nPointsTrd);
-  fpMCData->SetNofPointsOrig(L1DetectorID::kTof, nPointsTof);
-
   // ----- Read MC points in MVD, STS, MuCh, TRD and TOF
-  if (fbUseMvd) { this->ReadMCPointsForDetector<L1DetectorID::kMvd>(fpMvdPoints); }
-  if (fbUseSts) { this->ReadMCPointsForDetector<L1DetectorID::kSts>(fpStsPoints); }
-  if (fbUseMuch) { this->ReadMCPointsForDetector<L1DetectorID::kMuch>(fpMuchPoints); }
-  if (fbUseTrd) { this->ReadMCPointsForDetector<L1DetectorID::kTrd>(fpTrdPoints); }
-  if (fbUseTof) { this->ReadMCPointsForDetector<L1DetectorID::kTof>(fpTofPoints); }
+  if (fvbUseDet[L1DetectorID::kMvd]) { this->ReadMCPointsForDetector<L1DetectorID::kMvd>(); }
+  if (fvbUseDet[L1DetectorID::kSts]) { this->ReadMCPointsForDetector<L1DetectorID::kSts>(); }
+  if (fvbUseDet[L1DetectorID::kMuch]) { this->ReadMCPointsForDetector<L1DetectorID::kMuch>(); }
+  if (fvbUseDet[L1DetectorID::kTrd]) { this->ReadMCPointsForDetector<L1DetectorID::kTrd>(); }
+  if (fvbUseDet[L1DetectorID::kTof]) { this->ReadMCPointsForDetector<L1DetectorID::kTof>(); }
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
diff --git a/reco/L1/CbmCaMCModule.h b/reco/L1/CbmCaMCModule.h
index 95e5ecf16735fb19389169469e2d6fdc81948352..e1f2b90296fc06f8cb9c8f782f2717e008eb2536 100644
--- a/reco/L1/CbmCaMCModule.h
+++ b/reco/L1/CbmCaMCModule.h
@@ -29,6 +29,7 @@
 #include "TDatabasePDG.h"
 
 #include <numeric>
+#include <optional>
 #include <string>
 #include <string_view>
 #include <type_traits>
@@ -52,6 +53,8 @@ namespace cbm::ca
   /// @brief Class CbmCaPerformance is an interface to communicate between
   ///
   class MCModule {
+
+
   public:
     /// @brief Constructor
     /// @param verbosity  Verbosity level
@@ -73,17 +76,13 @@ namespace cbm::ca
     /// @brief Move assignment operator
     MCModule& operator=(MCModule&&) = delete;
 
-    /// @brief Creates hits from MC points
-    ///
-    /// This function creates hits from MC points in selected tracking stations and re-fills hit arrays.
-    void CreateHitsFromPoints() {}
-
-    /// @brief Sets hit parameters from the matched MC point
-    void AdjustHitsToPoints();
 
     /// @brief Defines performance action in the end of the run
     void Finish();
 
+    /// @brief Gets a pointer to MC data object
+    const ::ca::tools::MCData* GetMCData() const { return fpMCData; }
+
     /// @brief Defines performance action in the beginning of each event or time slice
     /// @note This function should be called before hits initialization
     /// @param  pEvent Pointer to a current CbmEvent
@@ -93,6 +92,16 @@ namespace cbm::ca
     /// @return Success flag
     bool InitRun();
 
+    /// @brief Matches hit with MC point
+    /// @tparam  DetId Detector ID
+    /// @param   iHitExt  External index of hit
+    /// @return           MC-point index in fvMCPoints array
+    ///
+    /// This method finds a match for a given hit or matches for hits clusters (in case of STS), finds the best
+    /// link in the match and returns the corresponding global ID of the MC points.
+    template<L1DetectorID DetId>
+    int MatchHitWithMc(int iHitExt) const;
+
     /// @brief Match reconstructed and MC data
     ///
     /// Runs matching of hits with points and reconstructed tracks with MC ones. Reconstructed tracks are updated with
@@ -115,7 +124,7 @@ namespace cbm::ca
     /// @param  detID  Id of detector
     /// @param  flag   Flag: true - detector is used
     /// @note Should be called before this->Init()
-    void SetDetector(L1DetectorID detID, bool flag);
+    void SetDetector(L1DetectorID detID, bool flag) { fvbUseDet[detID] = flag; }
 
     /// @brief Sets legacy event mode:
     /// @param flag Flag:
@@ -123,26 +132,6 @@ namespace cbm::ca
     ///              - false: runs on time-slice base
     void SetLegacyEventMode(bool flag) { fbLegacyEventMode = flag; }
 
-    /// @brief Creates hits from MC points for a particular detector and station
-    /// @param detID   DetectorID
-    /// @param iStLoc  Local index of station, provided by geometry
-    /// @param du      Error u-coordinate [cm]
-    /// @param dv      Error v-coordinate [cm]
-    /// @param dt      Error of time [ns]
-    /// @param ifSmear Flag:
-    ///                 - true:  MC point quantities are smeared along the error by gaussian,
-    ///                 - false: Precise point quantities are used
-    ///void SetHitsFromPoints(L1DetectorID detID, int iStLoc, double du, double dv, double dt, bool ifSmear) {}
-
-    /// @brief  Adjusts existing reconstructed hits to MC points for a particular detector and station
-    /// @param detID   DetectorID
-    /// @param iStLoc  Local index of station, provided by geometry
-    /// @param ifSmear Flag:
-    ///                 - true:  MC point quantities are smeared along the error by gaussian,
-    ///                 - false: Precise point quantities are used
-    ///void SetHitsFromPoints(L1DetectorID detID, int iStLoc, bool ifSmear) {}
-
-
     /// @brief Registers MC data object
     /// @param mcData  Instance of MC data
     void RegisterMCData(::ca::tools::MCData& mcData) { fpMCData = &mcData; }
@@ -175,20 +164,11 @@ namespace cbm::ca
     /// consecutive stations containing a hit or point and number of stations and points with hits.
     void InitTrackInfo();
 
-
-    /// @brief Matches hit with MC point
-    /// @tparam  DetId Detector ID
-    /// @param   iHitExt  External index of hit
-    /// @return           MC-point index in fvMCPoints array
-    ///
-    /// This method finds a match for a given hit or matches for hits clusters (in case of STS), finds the best
-    /// link in the match and returns the corresponding global ID of the MC points.
-    template<L1DetectorID DetId>
-    int MatchHitWithMc(int iHitExt) const;
-
-    /// @brief Match MC points and reconstructed hits
+    /// @brief  Match sets of MC points and reconstructed hits for a given detector
+    /// @tparam  DetID  Index of the detector
     ///
     /// Writes indexes of MC points to each hit and indexes of hits to each MC point.
+    template<L1DetectorID DetID>
     void MatchPointsAndHits();
 
     /// @brief Matches reconstructed tracks with MC tracks
@@ -209,7 +189,7 @@ namespace cbm::ca
 
     /// @brief Reads MC points in particular detector
     template<L1DetectorID DetID>
-    void ReadMCPointsForDetector(CbmMCDataArray* pPoints);
+    void ReadMCPointsForDetector();
 
     /// @brief Fills a single detector-specific MC point
     /// @tparam     DetID      Detector subsystem ID
@@ -220,42 +200,23 @@ namespace cbm::ca
     /// @return true   Point is correct and is to be saved to the MCData object
     /// @return false  Point is incorrect and will be ignored
     template<L1DetectorID DetID>
-    bool FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::tools::MCPoint& point);
-
-    std::shared_ptr<L1Parameters> fpParameters = nullptr;  ///< Pointer to tracking parameters object
+    std::optional<::ca::tools::MCPoint> FillMCPoint(int iExtId, int iEvent, int iFile);
 
     // ------ Flags
-    bool fbUseMvd  = false;  ///< is MVD used
-    bool fbUseSts  = false;  ///< is STS used
-    bool fbUseMuch = false;  ///< is MuCh used
-    bool fbUseTrd  = false;  ///< is TRD used
-    bool fbUseTof  = false;  ///< is TOF used
-
-    bool fbLegacyEventMode = false;  ///< if tracking uses events instead of time-slices (back compatibility)
-    int fVerbose           = 0;      ///< Verbosity level
-    int fPerformanceMode   = -1;     ///< Mode of performance
+    CbmCaDetIdArr_t<bool> fvbUseDet = {{false}};  ///< Flag: is detector subsystem used
+    bool fbLegacyEventMode          = false;  ///< if tracking uses events instead of time-slices (back compatibility)
+    int fVerbose                    = 0;      ///< Verbosity level
+    int fPerformanceMode            = -1;     ///< Mode of performance
 
+    std::shared_ptr<L1Parameters> fpParameters = nullptr;  ///< Pointer to tracking parameters object
     // ------ Input data branches
-    const CbmTimeSlice* fpTimeSlice = nullptr;  ///< Current time slice
-
-    // Mc-event
+    const CbmTimeSlice* fpTimeSlice  = nullptr;  ///< Current time slice
     CbmMCEventList* fpMCEventList    = nullptr;  ///< MC event list
     CbmMCDataObject* fpMCEventHeader = nullptr;  ///< MC event header
     CbmMCDataArray* fpMCTracks       = nullptr;  ///< MC tracks input
 
-    // Mc-points
-    CbmMCDataArray* fpMvdPoints  = nullptr;  ///< MVD MC-points input container
-    CbmMCDataArray* fpStsPoints  = nullptr;  ///< STS MC-points input container
-    CbmMCDataArray* fpMuchPoints = nullptr;  ///< MuCh MC-points input container
-    CbmMCDataArray* fpTrdPoints  = nullptr;  ///< TRD MC-points input container
-    CbmMCDataArray* fpTofPoints  = nullptr;  ///< TOF MC-points input container
-
-    // Matches
-    TClonesArray* fpMvdHitMatches  = nullptr;  ///< Array of MVD hit matches
-    TClonesArray* fpStsHitMatches  = nullptr;  ///< Array of STS hit matches
-    TClonesArray* fpMuchHitMatches = nullptr;  ///< Array of MuCh hit matches
-    TClonesArray* fpTrdHitMatches  = nullptr;  ///< Array of TRD hit matches
-    TClonesArray* fpTofHitMatches  = nullptr;  ///< Array of TOF hit matches
+    CbmCaDetIdArr_t<CbmMCDataArray*> fvpBrPoints   = {{nullptr}};  ///< Array of points vs. detector
+    CbmCaDetIdArr_t<TClonesArray*> fvpBrHitMatches = {{nullptr}};  ///< Array of hit match branches vs. detector
 
     TClonesArray* fpStsHits           = nullptr;  ///< Array of STS hits (currently needed for matching)
     TClonesArray* fpStsClusterMatches = nullptr;  ///< Array of STS cluster matches
@@ -263,14 +224,15 @@ namespace cbm::ca
     // Matching information
     std::set<std::pair<int, int>> fFileEventIDs;  ///< Set of file and event indexes: first - iFile, second - iEvent
 
-    // MC data
+    // ----- Internal MC data
     ::ca::tools::MCData* fpMCData = nullptr;  ///< MC information (hits and tracks) instance
 
-    // Reconstructed data
+    // ----- Internal reconstructed data
     L1Vector<CbmL1Track>* fpvRecoTracks    = nullptr;  ///< Pointer to reconstructed track container
     L1Vector<CbmL1HitId>* fpvHitIds        = nullptr;  ///< Pointer to hit index container
     L1Vector<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.
@@ -286,8 +248,10 @@ namespace cbm::ca
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<L1DetectorID DetID>
-bool cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::tools::MCPoint& point)
+std::optional<::ca::tools::MCPoint> cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile)
 {
+  auto oPoint = std::make_optional<::ca::tools::MCPoint>();
+
   // ----- Get positions, momenta, time and track ID
   TVector3 posIn;             // Position at entrance to station [cm]
   TVector3 posOut;            // Position at exist of station [cm]
@@ -295,13 +259,15 @@ bool cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::too
   TVector3 momOut;            // 3-momentum at exit of station [GeV/c]
   double time = undef::kD;    // Time of MC point (after beginning of the event) [ns]
   int iTmcExt = undef::kI32;  // Track ID in the external container
-  // MVD
+
+  auto* pBrPoints = fvpBrPoints[DetID];
+
   if constexpr (L1DetectorID::kMvd == DetID) {
-    auto* pExtPoint = dynamic_cast<CbmMvdPoint*>(fpMvdPoints->Get(iFile, iEvent, iExtId));
+    auto* pExtPoint = dynamic_cast<CbmMvdPoint*>(pBrPoints->Get(iFile, iEvent, iExtId));
     if (!pExtPoint) {
       LOG(warn) << "CbmCaMCModule: MVD MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
                 << ", iFile = " << iFile << " does not exist";
-      return false;
+      return std::nullopt;
     }
     pExtPoint->Position(posIn);
     pExtPoint->PositionOut(posOut);
@@ -312,11 +278,11 @@ bool cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::too
   }
   // STS
   else if constexpr (L1DetectorID::kSts == DetID) {
-    auto* pExtPoint = dynamic_cast<CbmStsPoint*>(fpStsPoints->Get(iFile, iEvent, iExtId));
+    auto* pExtPoint = dynamic_cast<CbmStsPoint*>(pBrPoints->Get(iFile, iEvent, iExtId));
     if (!pExtPoint) {
       LOG(warn) << "CbmCaMCModule: STS MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
                 << ", iFile = " << iFile << " does not exist";
-      return false;
+      return std::nullopt;
     }
     pExtPoint->Position(posIn);
     pExtPoint->PositionOut(posOut);
@@ -327,11 +293,11 @@ bool cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::too
   }
   // MuCh
   else if constexpr (L1DetectorID::kMuch == DetID) {
-    auto* pExtPoint = dynamic_cast<CbmMuchPoint*>(fpMuchPoints->Get(iFile, iEvent, iExtId));
+    auto* pExtPoint = dynamic_cast<CbmMuchPoint*>(pBrPoints->Get(iFile, iEvent, iExtId));
     if (!pExtPoint) {
       LOG(warn) << "CbmCaMCModule: MuCh MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
                 << ", iFile = " << iFile << " does not exist";
-      return false;
+      return std::nullopt;
     }
     pExtPoint->Position(posIn);
     pExtPoint->PositionOut(posOut);
@@ -342,11 +308,11 @@ bool cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::too
   }
   // TRD
   else if constexpr (L1DetectorID::kTrd == DetID) {
-    auto* pExtPoint = dynamic_cast<CbmTrdPoint*>(fpTrdPoints->Get(iFile, iEvent, iExtId));
+    auto* pExtPoint = dynamic_cast<CbmTrdPoint*>(pBrPoints->Get(iFile, iEvent, iExtId));
     if (!pExtPoint) {
       LOG(warn) << "CbmCaMCModule: TRD MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
                 << ", iFile = " << iFile << " does not exist";
-      return false;
+      return std::nullopt;
     }
     pExtPoint->Position(posIn);
     pExtPoint->PositionOut(posOut);
@@ -357,11 +323,11 @@ bool cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::too
   }
   // TOF
   else if constexpr (L1DetectorID::kTof == DetID) {
-    auto* pExtPoint = dynamic_cast<CbmTofPoint*>(fpTofPoints->Get(iFile, iEvent, iExtId));
+    auto* pExtPoint = dynamic_cast<CbmTofPoint*>(pBrPoints->Get(iFile, iEvent, iExtId));
     if (!pExtPoint) {
       LOG(warn) << "CbmCaMCModule: TOF MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
                 << ", iFile = " << iFile << " does not exist";
-      return false;
+      return std::nullopt;
     }
     pExtPoint->Position(posIn);
     pExtPoint->Position(posOut);
@@ -373,7 +339,7 @@ bool cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::too
   if (iTmcExt < 0) {
     LOG(warn) << "CbmCaMCModule: For MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
               << ", iFile = " << iFile << " MC track is undefined (has ID = " << iTmcExt << ')';
-    return false;
+    return std::nullopt;
   }
   TVector3 posMid = 0.5 * (posIn + posOut);
   TVector3 momMid = 0.5 * (momIn + momOut);
@@ -421,79 +387,91 @@ bool cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::too
       LOG(warn) << "CbmCaMCModule: MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
                 << ", iFile = " << iFile << " and det id " << int(DetID) << " fell out of the TS duration [" << startT
                 << ", " << endT << "] with measured time = " << time << " [ns]";
-      return false;
+      return std::nullopt;
     }
   }
 
   // ----- Fill MC point
-  point.SetExternalId(iExtId);
-  point.SetEventId(iEvent);
-  point.SetFileId(iFile);
-  point.SetTime(time);
-  point.SetX(posMid.X());
-  point.SetY(posMid.Y());
-  point.SetZ(posMid.Z());
-  point.SetXIn(posIn.X());
-  point.SetYIn(posIn.Y());
-  point.SetZIn(posIn.Z());
-  point.SetXOut(posOut.X());
-  point.SetYOut(posOut.Y());
-  point.SetZOut(posOut.Z());
-  point.SetPx(momMid.X());
-  point.SetPy(momMid.Y());
-  point.SetPz(momMid.Z());
-  point.SetPxIn(momIn.X());
-  point.SetPyIn(momIn.Y());
-  point.SetPzIn(momIn.Z());
-  point.SetPxOut(momOut.X());
-  point.SetPyOut(momOut.Y());
-  point.SetPzOut(momOut.Z());
-
+  oPoint->SetExternalId(fpMCData->GetPointGlobExtIndex(DetID, iExtId));
+  oPoint->SetEventId(iEvent);
+  oPoint->SetFileId(iFile);
+  oPoint->SetTime(time);
+  oPoint->SetX(posMid.X());
+  oPoint->SetY(posMid.Y());
+  oPoint->SetZ(posMid.Z());
+  oPoint->SetXIn(posIn.X());
+  oPoint->SetYIn(posIn.Y());
+  oPoint->SetZIn(posIn.Z());
+  oPoint->SetXOut(posOut.X());
+  oPoint->SetYOut(posOut.Y());
+  oPoint->SetZOut(posOut.Z());
+  oPoint->SetPx(momMid.X());
+  oPoint->SetPy(momMid.Y());
+  oPoint->SetPz(momMid.Z());
+  oPoint->SetPxIn(momIn.X());
+  oPoint->SetPyIn(momIn.Y());
+  oPoint->SetPzIn(momIn.Z());
+  oPoint->SetPxOut(momOut.X());
+  oPoint->SetPyOut(momOut.Y());
+  oPoint->SetPzOut(momOut.Z());
+
+  // Select current number of points as a local id of points
+  oPoint->SetId(fpMCData->GetNofPoints());
+
+  // Match MC track and point to each other
   int iTmcInt = fpMCData->FindInternalTrackIndex(iTmcExt, iEvent, iFile);
 
-  point.SetId(fpMCData->GetNofPoints());  // select current number of points as a local id of points
-  point.SetTrackId(iTmcInt);
-  point.SetStationId(stationID);
-  point.SetDetectorId(DetID);
+  oPoint->SetTrackId(iTmcInt);
+  if (iTmcInt > -1) { fpMCData->GetTrack(iTmcInt).AddPointIndex(oPoint->GetId()); }
+
+  oPoint->SetStationId(stationID);
+  oPoint->SetDetectorId(DetID);
 
   auto* pExtTrk = L1_DYNAMIC_CAST<CbmMCTrack*>(fpMCTracks->Get(iFile, iEvent, iTmcExt));
   if (!pExtTrk) {
     LOG(warn) << "CbmCaMCModule: MC track with iTmcExt = " << iTmcExt << ", iEvent = " << iEvent
               << ", iFile = " << iFile << " MC track is undefined (nullptr)";
-    return false;
+    return std::nullopt;
   }
-  point.SetPdgCode(pExtTrk->GetPdgCode());
-  point.SetMotherId(pExtTrk->GetMotherId());
+  oPoint->SetPdgCode(pExtTrk->GetPdgCode());
+  oPoint->SetMotherId(pExtTrk->GetMotherId());
 
-  auto* pPdgDB = TDatabasePDG::Instance()->GetParticle(point.GetPdgCode());
-  point.SetMass(pPdgDB ? pPdgDB->Mass() : 0.);  /// TODO: Set from track
-  point.SetCharge(pPdgDB ? pPdgDB->Charge() / 3. : 0.);
+  auto* pPdgDB = TDatabasePDG::Instance()->GetParticle(oPoint->GetPdgCode());
+  oPoint->SetMass(pPdgDB ? pPdgDB->Mass() : 0.);  /// TODO: Set from track
+  oPoint->SetCharge(pPdgDB ? pPdgDB->Charge() / 3. : 0.);
 
-  return true;
+  return oPoint;
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
-// NOTE: template is used, because another template function FillMCPoint is used inside
+//
 template<L1DetectorID DetID>
-void cbm::ca::MCModule::ReadMCPointsForDetector(CbmMCDataArray* pPoints)
+void cbm::ca::MCModule::MatchPointsAndHits()
 {
-  if constexpr (L1DetectorID::kTof != DetID) {
-    for (const auto& key : fFileEventIDs) {
-      int iFile        = key.first;
-      int iEvent       = key.second;
-      int nPointsEvent = pPoints->Size(iFile, iEvent);
-      for (int iP = 0; iP < nPointsEvent; ++iP) {
-        ::ca::tools::MCPoint aPoint;
-        if (FillMCPoint<DetID>(iP, iEvent, iFile, aPoint)) {
-          aPoint.SetExternalId(fpMCData->GetPointGlobExtIndex(DetID, iP));
-          int iPInt = fpMCData->GetNofPoints();  // assign an index of point in internal container
-          if (aPoint.GetTrackId() > -1) { fpMCData->GetTrack(aPoint.GetTrackId()).AddPointIndex(iPInt); }
-          fpMCData->AddPoint(aPoint);
-        }
-      }  // iP: end
-    }    // key: end
+  if (!fvbUseDet[DetID]) { return; }
+
+  for (int iH = (*fpvFstHitId)[static_cast<int>(DetID)]; iH < (*fpvFstHitId)[static_cast<int>(DetID) + 1]; ++iH) {
+    auto& hit = (*fpvQaHits)[iH];
+    int iP    = MatchHitWithMc<DetID>(hit.ExtIndex);
+    if (iP > -1) {
+      hit.SetMCPointIndex(iP);
+      fpMCData->GetPoint(iP).AddHitID(iH);
+    }
   }
 }
+// ---------------------------------------------------------------------------------------------------------------------
+// NOTE: template is used, because another template function FillMCPoint is used inside
+template<L1DetectorID DetID>
+void cbm::ca::MCModule::ReadMCPointsForDetector()
+{
+  for (const auto& [iFile, iEvent] : fFileEventIDs) {
+    int nPointsEvent = fvpBrPoints[DetID]->Size(iFile, iEvent);
+    for (int iP = 0; iP < nPointsEvent; ++iP) {
+      std::optional<::ca::tools::MCPoint> oPoint = FillMCPoint<DetID>(iP, iEvent, iFile);
+      if (oPoint) { fpMCData->AddPoint(*oPoint); }
+    }  // iP: end
+  }    // key: end
+}
 
 
 #endif  // CbmCaMCModule_h
diff --git a/reco/L1/CbmCaMCModule.h.orig b/reco/L1/CbmCaMCModule.h.orig
new file mode 100644
index 0000000000000000000000000000000000000000..ebe5bbe25f7c0288b8c5f4ce10ffefeadc2a4266
--- /dev/null
+++ b/reco/L1/CbmCaMCModule.h.orig
@@ -0,0 +1,503 @@
+/* Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// @file   CbmCaMCModule.h
+/// @brief  CA Tracking performance interface for CBM (header)
+/// @since  23.09.2022
+/// @author S.Zharko <s.zharko@gsi.de>
+
+#ifndef CbmCaMCModule_h
+#define CbmCaMCModule_h 1
+
+#include "CbmL1DetectorID.h"
+#include "CbmL1Hit.h"
+#include "CbmL1Track.h"
+#include "CbmLink.h"
+#include "CbmMCDataArray.h"
+#include "CbmMCEventList.h"
+#include "CbmMCTrack.h"
+#include "CbmMatch.h"
+#include "CbmMuchPoint.h"
+#include "CbmMvdPoint.h"
+#include "CbmStsPoint.h"
+#include "CbmTimeSlice.h"
+#include "CbmTofPoint.h"
+#include "CbmTrdPoint.h"
+
+#include "TClonesArray.h"
+#include "TDatabasePDG.h"
+
+#include <numeric>
+#include <string>
+#include <string_view>
+#include <type_traits>
+
+#include "CaToolsMCData.h"
+#include "CaToolsMCPoint.h"
+#include "L1Constants.h"
+#include "L1InputData.h"
+#include "L1Parameters.h"
+#include "L1Undef.h"
+
+class CbmEvent;
+class CbmMCDataObject;
+class CbmL1HitDebugInfo;
+class CbmL1Track;
+
+enum class L1DetectorID;
+
+namespace cbm::ca
+{
+<<<<<<< HEAD
+  /// @brief Class CbmCaPerformance is an interface to communicate between
+=======
+  /// Class CbmCaPerformance is an interface to communicate between
+>>>>>>> CA: QA updates
+  ///
+  class MCModule {
+  public:
+    /// @brief Constructor
+    /// @param verbosity  Verbosity level
+    /// @param perfMode   Performance mode (defines cut on number of consecutive stations with hit or point)
+    MCModule(int verb = 0, int perfMode = 3) : fVerbose(verb), fPerformanceMode(perfMode) {}
+
+    /// @brief Destructor
+    ~MCModule() = default;
+
+    /// @brief Copy constructor
+    MCModule(const MCModule&) = delete;
+
+    /// @brief Move constructor
+    MCModule(MCModule&&) = delete;
+
+    /// @brief Copy assignment operator
+    MCModule& operator=(const MCModule&) = delete;
+
+    /// @brief Move assignment operator
+    MCModule& operator=(MCModule&&) = delete;
+
+    /// @brief Creates hits from MC points
+    ///
+    /// This function creates hits from MC points in selected tracking stations and re-fills hit arrays.
+    void CreateHitsFromPoints() {}
+
+    /// @brief Sets hit parameters from the matched MC point
+    void AdjustHitsToPoints();
+
+    /// @brief Defines performance action in the end of the run
+    void Finish();
+
+    /// @brief Defines performance action in the beginning of each event or time slice
+    /// @note This function should be called before hits initialization
+    /// @param  pEvent Pointer to a current CbmEvent
+    void InitEvent(CbmEvent* pEvent);
+
+    /// @brief Defines action on the module in the beginning of the run
+    /// @return Success flag
+    bool InitRun();
+
+    /// @brief Match reconstructed and MC data
+    ///
+    /// Runs matching of hits with points and reconstructed tracks with MC ones. Reconstructed tracks are updated with
+    /// true information.
+    void MatchRecoAndMC();
+
+    /// @brief Processes event
+    ///
+    /// Fills histograms and tables, should be called after the tracking done
+    void ProcessEvent(CbmEvent* pEvent);
+
+    /// @brief Sets first hit indexes container in different detectors
+    /// @param source Array of indexes
+    void RegisterFirstHitIndexes(const std::array<int, L1Constants::size::kMaxNdetectors + 1>& source)
+    {
+      fpvFstHitId = &source;
+    }
+
+    /// @brief Sets used detector subsystems
+    /// @param  detID  Id of detector
+    /// @param  flag   Flag: true - detector is used
+    /// @note Should be called before this->Init()
+    void SetDetector(L1DetectorID detID, bool 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 Creates hits from MC points for a particular detector and station
+    /// @param detID   DetectorID
+    /// @param iStLoc  Local index of station, provided by geometry
+    /// @param du      Error u-coordinate [cm]
+    /// @param dv      Error v-coordinate [cm]
+    /// @param dt      Error of time [ns]
+    /// @param ifSmear Flag:
+    ///                 - true:  MC point quantities are smeared along the error by gaussian,
+    ///                 - false: Precise point quantities are used
+    ///void SetHitsFromPoints(L1DetectorID detID, int iStLoc, double du, double dv, double dt, bool ifSmear) {}
+
+    /// @brief  Adjusts existing reconstructed hits to MC points for a particular detector and station
+    /// @param detID   DetectorID
+    /// @param iStLoc  Local index of station, provided by geometry
+    /// @param ifSmear Flag:
+    ///                 - true:  MC point quantities are smeared along the error by gaussian,
+    ///                 - false: Precise point quantities are used
+    ///void SetHitsFromPoints(L1DetectorID detID, int iStLoc, bool ifSmear) {}
+
+
+    /// @brief Registers MC data object
+    /// @param mcData  Instance of MC data
+    void RegisterMCData(::ca::tools::MCData& mcData) { fpMCData = &mcData; }
+
+    /// @brief Registers reconstructed track container
+    /// @param vRecoTrack Reference to reconstructed track container
+    void RegisterRecoTrackContainer(L1Vector<CbmL1Track>& vRecoTracks) { fpvRecoTracks = &vRecoTracks; }
+
+    /// @brief Registers hit index container
+    /// @param vHitIds  Reference to hit index container
+    void RegisterHitIndexContainer(L1Vector<CbmL1HitId>& vHitIds) { fpvHitIds = &vHitIds; }
+
+    /// @brief Registers CA parameters object
+    /// @param pParameters  A shared pointer to the parameters object
+    void RegisterParameters(std::shared_ptr<L1Parameters>& pParameters) { fpParameters = pParameters; }
+
+    /// @brief Registers debug hit container
+    /// @param vQaHits  Reference to debug hit container
+    void RegisterQaHitContainer(L1Vector<CbmL1HitDebugInfo>& vQaHits) { fpvQaHits = &vQaHits; }
+
+  private:
+    /// @brief Check class initialization
+    /// @note The function throws std::logic_error, if initialization is incomplete
+    void CheckInit() const;
+
+    /// @brief  Initializes MC track
+    ///
+    /// Initializes information about arrangement of points and hits of MC tracks within stations and the status
+    /// of track ability to be reconstructed, calculates max number of points and hits on a station, number of
+    /// consecutive stations containing a hit or point and number of stations and points with hits.
+    void InitTrackInfo();
+
+
+    /// @brief Matches hit with MC point
+    /// @tparam  DetId Detector ID
+    /// @param   iHitExt  External index of hit
+    /// @return           MC-point index in fvMCPoints array
+    ///
+    /// This method finds a match for a given hit or matches for hits clusters (in case of STS), finds the best
+    /// link in the match and returns the corresponding global ID of the MC points.
+    template<L1DetectorID DetId>
+    int MatchHitWithMc(int iHitExt) const;
+
+    /// @brief Match MC points and reconstructed hits
+    ///
+    /// Writes indexes of MC points to each hit and indexes of hits to each MC point.
+    void MatchPointsAndHits();
+
+    /// @brief Matches reconstructed tracks with MC tracks
+    ///
+    /// In the procedure, the maps of associated MC track indexes to corresponding number of hits are filled out and the
+    /// max purity is calculated for each reconstructed track in the TS/event. If the value of purity for a given MC track
+    /// is larger then a threshold, the corresponding track index is saved to the reconstructed track object, in the same
+    /// time the index of the reconstructed track object is saved to this MC track object. If purity for the MC track does
+    /// not pass the threshold, its index will not be accounted as a matched track, and the index of reconstructed track
+    /// will be added as an index of "touched" track.
+    void MatchRecoAndMCTracks();
+
+    /// @brief Reads MC tracks from external trees and saves them to MCDataObject
+    void ReadMCTracks();
+
+    /// @brief Reads MC points from external trees and saves them to MCDataObject
+    void ReadMCPoints();
+
+    /// @brief Reads MC points in particular detector
+    template<L1DetectorID DetID>
+    void ReadMCPointsForDetector(CbmMCDataArray* pPoints);
+
+    /// @brief Fills a single detector-specific MC point
+    /// @tparam     DetID      Detector subsystem ID
+    /// @param[in]  iExtId     Index of point in the external points container
+    /// @param[in]  iEvent     EventID of point in the external points container
+    /// @param[in]  iFile      FileID of point int the external points container
+    /// @param[out] intMCPoint Reference to the internal tracking MC point object (ca::tools::MCData)
+    /// @return true   Point is correct and is to be saved to the MCData object
+    /// @return false  Point is incorrect and will be ignored
+    template<L1DetectorID DetID>
+    bool FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::tools::MCPoint& point);
+
+    std::shared_ptr<L1Parameters> fpParameters = nullptr;  ///< Pointer to tracking parameters object
+
+    // ------ Flags
+    bool fbUseMvd  = false;  ///< is MVD used
+    bool fbUseSts  = false;  ///< is STS used
+    bool fbUseMuch = false;  ///< is MuCh used
+    bool fbUseTrd  = false;  ///< is TRD used
+    bool fbUseTof  = false;  ///< is TOF used
+
+    bool fbLegacyEventMode = false;  ///< if tracking uses events instead of time-slices (back compatibility)
+    int fVerbose           = 0;      ///< Verbosity level
+    int fPerformanceMode   = -1;     ///< Mode of performance
+
+    // ------ Input data branches
+    const CbmTimeSlice* fpTimeSlice = nullptr;  ///< Current time slice
+
+    // Mc-event
+    CbmMCEventList* fpMCEventList    = nullptr;  ///< MC event list
+    CbmMCDataObject* fpMCEventHeader = nullptr;  ///< MC event header
+    CbmMCDataArray* fpMCTracks       = nullptr;  ///< MC tracks input
+
+    // Mc-points
+    CbmMCDataArray* fpMvdPoints  = nullptr;  ///< MVD MC-points input container
+    CbmMCDataArray* fpStsPoints  = nullptr;  ///< STS MC-points input container
+    CbmMCDataArray* fpMuchPoints = nullptr;  ///< MuCh MC-points input container
+    CbmMCDataArray* fpTrdPoints  = nullptr;  ///< TRD MC-points input container
+    CbmMCDataArray* fpTofPoints  = nullptr;  ///< TOF MC-points input container
+
+    // Matches
+    TClonesArray* fpMvdHitMatches  = nullptr;  ///< Array of MVD hit matches
+    TClonesArray* fpStsHitMatches  = nullptr;  ///< Array of STS hit matches
+    TClonesArray* fpMuchHitMatches = nullptr;  ///< Array of MuCh hit matches
+    TClonesArray* fpTrdHitMatches  = nullptr;  ///< Array of TRD hit matches
+    TClonesArray* fpTofHitMatches  = nullptr;  ///< Array of TOF hit matches
+
+    TClonesArray* fpStsHits           = nullptr;  ///< Array of STS hits (currently needed for matching)
+    TClonesArray* fpStsClusterMatches = nullptr;  ///< Array of STS cluster matches
+
+    // Matching information
+    std::set<std::pair<int, int>> fFileEventIDs;  ///< Set of file and event indexes: first - iFile, second - iEvent
+
+    // MC data
+    ::ca::tools::MCData* fpMCData = nullptr;  ///< MC information (hits and tracks) instance
+
+    // Reconstructed data
+    L1Vector<CbmL1Track>* fpvRecoTracks    = nullptr;  ///< Pointer to reconstructed track container
+    L1Vector<CbmL1HitId>* fpvHitIds        = nullptr;  ///< Pointer to hit index container
+    L1Vector<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.
+    const std::array<int, L1Constants::size::kMaxNdetectors + 1>* fpvFstHitId = nullptr;
+  };
+}  // namespace cbm::ca
+
+
+// **********************************************
+// **     Template function implementation     **
+// **********************************************
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+template<L1DetectorID DetID>
+bool cbm::ca::MCModule::FillMCPoint(int iExtId, int iEvent, int iFile, ::ca::tools::MCPoint& point)
+{
+  // ----- Get positions, momenta, time and track ID
+  TVector3 posIn;             // Position at entrance to station [cm]
+  TVector3 posOut;            // Position at exist of station [cm]
+  TVector3 momIn;             // 3-momentum at entrance to station [GeV/c]
+  TVector3 momOut;            // 3-momentum at exit of station [GeV/c]
+  double time = undef::kD;    // Time of MC point (after beginning of the event) [ns]
+  int iTmcExt = undef::kI32;  // Track ID in the external container
+  // MVD
+  if constexpr (L1DetectorID::kMvd == DetID) {
+    auto* pExtPoint = dynamic_cast<CbmMvdPoint*>(fpMvdPoints->Get(iFile, iEvent, iExtId));
+    if (!pExtPoint) {
+      LOG(warn) << "CbmCaMCModule: MVD MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
+                << ", iFile = " << iFile << " does not exist";
+      return false;
+    }
+    pExtPoint->Position(posIn);
+    pExtPoint->PositionOut(posOut);
+    pExtPoint->Momentum(momIn);
+    pExtPoint->MomentumOut(momOut);
+    time    = pExtPoint->GetTime();
+    iTmcExt = pExtPoint->GetTrackID();
+  }
+  // STS
+  else if constexpr (L1DetectorID::kSts == DetID) {
+    auto* pExtPoint = dynamic_cast<CbmStsPoint*>(fpStsPoints->Get(iFile, iEvent, iExtId));
+    if (!pExtPoint) {
+      LOG(warn) << "CbmCaMCModule: STS MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
+                << ", iFile = " << iFile << " does not exist";
+      return false;
+    }
+    pExtPoint->Position(posIn);
+    pExtPoint->PositionOut(posOut);
+    pExtPoint->Momentum(momIn);
+    pExtPoint->MomentumOut(momOut);
+    time    = pExtPoint->GetTime();
+    iTmcExt = pExtPoint->GetTrackID();
+  }
+  // MuCh
+  else if constexpr (L1DetectorID::kMuch == DetID) {
+    auto* pExtPoint = dynamic_cast<CbmMuchPoint*>(fpMuchPoints->Get(iFile, iEvent, iExtId));
+    if (!pExtPoint) {
+      LOG(warn) << "CbmCaMCModule: MuCh MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
+                << ", iFile = " << iFile << " does not exist";
+      return false;
+    }
+    pExtPoint->Position(posIn);
+    pExtPoint->PositionOut(posOut);
+    pExtPoint->Momentum(momIn);
+    pExtPoint->Momentum(momOut);
+    time    = pExtPoint->GetTime();
+    iTmcExt = pExtPoint->GetTrackID();
+  }
+  // TRD
+  else if constexpr (L1DetectorID::kTrd == DetID) {
+    auto* pExtPoint = dynamic_cast<CbmTrdPoint*>(fpTrdPoints->Get(iFile, iEvent, iExtId));
+    if (!pExtPoint) {
+      LOG(warn) << "CbmCaMCModule: TRD MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
+                << ", iFile = " << iFile << " does not exist";
+      return false;
+    }
+    pExtPoint->Position(posIn);
+    pExtPoint->PositionOut(posOut);
+    pExtPoint->Momentum(momIn);
+    pExtPoint->MomentumOut(momOut);
+    time    = pExtPoint->GetTime();
+    iTmcExt = pExtPoint->GetTrackID();
+  }
+  // TOF
+  else if constexpr (L1DetectorID::kTof == DetID) {
+    auto* pExtPoint = dynamic_cast<CbmTofPoint*>(fpTofPoints->Get(iFile, iEvent, iExtId));
+    if (!pExtPoint) {
+      LOG(warn) << "CbmCaMCModule: TOF MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
+                << ", iFile = " << iFile << " does not exist";
+      return false;
+    }
+    pExtPoint->Position(posIn);
+    pExtPoint->Position(posOut);
+    pExtPoint->Momentum(momIn);
+    pExtPoint->Momentum(momOut);
+    time    = pExtPoint->GetTime();
+    iTmcExt = pExtPoint->GetTrackID();
+  }
+  if (iTmcExt < 0) {
+    LOG(warn) << "CbmCaMCModule: For MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
+              << ", iFile = " << iFile << " MC track is undefined (has ID = " << iTmcExt << ')';
+    return false;
+  }
+  TVector3 posMid = 0.5 * (posIn + posOut);
+  TVector3 momMid = 0.5 * (momIn + momOut);
+
+  // // ----- Get station index
+  int stationID    = undef::kI32;  // Index of station in the array of active tracking stations
+  int nStationsGeo = fpParameters->GetNstationsGeometry(DetID);
+  // MVD, STS TODO: Try to extend for MuCh and TRD
+  if constexpr (L1DetectorID::kMvd == DetID || L1DetectorID::kSts == DetID) {
+    // Determine active station global index
+    double bestDist = 1.e+20;
+    for (int iStLocGeo = 0; iStLocGeo < nStationsGeo; ++iStLocGeo) {
+      int iStActive = fpParameters->GetStationIndexActive(iStLocGeo, DetID);
+      if (iStActive < 0) { continue; }
+      const L1Station& station = fpParameters->GetStation(iStActive);
+      double dist              = posIn.Z() - station.fZ[0];
+      if (fabs(dist) < fabs(bestDist)) {
+        bestDist  = dist;
+        stationID = iStActive;
+      }
+    }
+  }
+  // MuCh, TRD
+  else if constexpr (L1DetectorID::kMuch == DetID || L1DetectorID::kTrd == DetID) {
+    // Offset for MuCh - 2.5 cm, for TRD - 20. cm. TODO: Where did these values came from?
+    double offset = (L1DetectorID::kMuch == DetID) ? 2.5 : 20.;
+    for (int iStLocGeo = 0; iStLocGeo < nStationsGeo; ++iStLocGeo) {
+      int iStActive = fpParameters->GetStationIndexActive(iStLocGeo, DetID);
+      if (iStActive < 0) { continue; }
+      const L1Station& station = fpParameters->GetStation(iStActive);
+      if (posMid.Z() > station.fZ[0] - offset) { stationID = iStActive; }
+    }
+  }
+
+  // Update point time with event time
+  time += fpMCEventList->GetEventTime(iEvent, iFile);
+
+  // ----- Reject MC points falling out of the time slice
+  // STS, MuCh, TRD, TOF
+  if constexpr (DetID != L1DetectorID::kMvd) {
+    double startT = fpTimeSlice->GetStartTime();
+    double endT   = fpTimeSlice->GetEndTime();
+
+    if ((startT > 0. && time < startT) || (endT > 0. && time > endT)) {
+      LOG(warn) << "CbmCaMCModule: MC point with iExtId = " << iExtId << ", iEvent = " << iEvent
+                << ", iFile = " << iFile << " and det id " << int(DetID) << " fell out of the TS duration [" << startT
+                << ", " << endT << "] with measured time = " << time << " [ns]";
+      return false;
+    }
+  }
+
+  // ----- Fill MC point
+  point.SetExternalId(iExtId);
+  point.SetEventId(iEvent);
+  point.SetFileId(iFile);
+  point.SetTime(time);
+  point.SetX(posMid.X());
+  point.SetY(posMid.Y());
+  point.SetZ(posMid.Z());
+  point.SetXIn(posIn.X());
+  point.SetYIn(posIn.Y());
+  point.SetZIn(posIn.Z());
+  point.SetXOut(posOut.X());
+  point.SetYOut(posOut.Y());
+  point.SetZOut(posOut.Z());
+  point.SetPx(momMid.X());
+  point.SetPy(momMid.Y());
+  point.SetPz(momMid.Z());
+  point.SetPxIn(momIn.X());
+  point.SetPyIn(momIn.Y());
+  point.SetPzIn(momIn.Z());
+  point.SetPxOut(momOut.X());
+  point.SetPyOut(momOut.Y());
+  point.SetPzOut(momOut.Z());
+
+  int iTmcInt = fpMCData->FindInternalTrackIndex(iTmcExt, iEvent, iFile);
+
+  point.SetId(fpMCData->GetNofPoints());  // select current number of points as a local id of points
+  point.SetTrackId(iTmcInt);
+  point.SetStationId(stationID);
+  point.SetDetectorId(DetID);
+
+  auto* pExtTrk = L1_DYNAMIC_CAST<CbmMCTrack*>(fpMCTracks->Get(iFile, iEvent, iTmcExt));
+  if (!pExtTrk) {
+    LOG(warn) << "CbmCaMCModule: MC track with iTmcExt = " << iTmcExt << ", iEvent = " << iEvent
+              << ", iFile = " << iFile << " MC track is undefined (nullptr)";
+    return false;
+  }
+  point.SetPdgCode(pExtTrk->GetPdgCode());
+  point.SetMotherId(pExtTrk->GetMotherId());
+
+  auto* pPdgDB = TDatabasePDG::Instance()->GetParticle(point.GetPdgCode());
+  point.SetMass(pPdgDB ? pPdgDB->Mass() : 0.);  /// TODO: Set from track
+  point.SetCharge(pPdgDB ? pPdgDB->Charge() / 3. : 0.);
+
+  return true;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+// NOTE: template is used, because another template function FillMCPoint is used inside
+template<L1DetectorID DetID>
+void cbm::ca::MCModule::ReadMCPointsForDetector(CbmMCDataArray* pPoints)
+{
+  if constexpr (L1DetectorID::kTof != DetID) {
+    for (const auto& key : fFileEventIDs) {
+      int iFile        = key.first;
+      int iEvent       = key.second;
+      int nPointsEvent = pPoints->Size(iFile, iEvent);
+      for (int iP = 0; iP < nPointsEvent; ++iP) {
+        ::ca::tools::MCPoint aPoint;
+        if (FillMCPoint<DetID>(iP, iEvent, iFile, aPoint)) {
+          aPoint.SetExternalId(fpMCData->GetPointGlobExtIndex(DetID, iP));
+          int iPInt = fpMCData->GetNofPoints();  // assign an index of point in internal container
+          if (aPoint.GetTrackId() > -1) { fpMCData->GetTrack(aPoint.GetTrackId()).AddPointIndex(iPInt); }
+          fpMCData->AddPoint(aPoint);
+        }
+      }  // iP: end
+    }    // key: end
+  }
+}
+
+
+#endif  // CbmCaMCModule_h
diff --git a/reco/L1/CbmCaTimeSliceReader.cxx b/reco/L1/CbmCaTimeSliceReader.cxx
index 85e0ec20d3b1de721cfedfac9d8e1c97269b983c..bb96dcf479cc181a213a0a8d2d4614853aeca1c7 100644
--- a/reco/L1/CbmCaTimeSliceReader.cxx
+++ b/reco/L1/CbmCaTimeSliceReader.cxx
@@ -19,21 +19,19 @@
 #include "FairRootManager.h"
 #include "Logger.h"
 
+#include <algorithm>
 #include <numeric>
 
 #include "L1Constants.h"
 #include "L1InputData.h"
 #include "L1Parameters.h"
 
+using ca::tools::HitRecord;
 using cbm::ca::TimeSliceReader;
 using L1Constants::clrs::kCL;   // clear log
 using L1Constants::clrs::kGNb;  // green bold log
 using L1Constants::clrs::kRDb;  // red bold log
 
-// ---------------------------------------------------------------------------------------------------------------------
-//
-TimeSliceReader::TimeSliceReader(ECbmTrackingMode mode) : fTrackingMode(mode) {}
-
 // ---------------------------------------------------------------------------------------------------------------------
 //
 void TimeSliceReader::Clear()
@@ -45,11 +43,7 @@ void TimeSliceReader::Clear()
   fpBrTimeSlice = nullptr;
   fpParameters  = nullptr;
 
-  fpBrMvdHits  = nullptr;
-  fpBrStsHits  = nullptr;
-  fpBrMuchHits = nullptr;
-  fpBrTrdHits  = nullptr;
-  fpBrTofHits  = nullptr;
+  fvpBrHits.fill(nullptr);
 
   fpBrRecoTracks = nullptr;
   fpBrStsTracks  = nullptr;
@@ -80,17 +74,17 @@ void TimeSliceReader::CheckInit() const
 
   if (!fpBrTimeSlice) { throw std::logic_error("Time slice branch is unavailable"); }
 
-  if (fvbUseDet[L1DetectorID::kMvd] && !fpBrMvdHits) { throw std::logic_error("MVD hits branch is unavailable"); }
-  if (fvbUseDet[L1DetectorID::kSts] && !fpBrStsHits) { throw std::logic_error("STS hits branch is unavailable"); }
-  if (fvbUseDet[L1DetectorID::kMuch] && !fpBrMuchHits) { throw std::logic_error("MuCh hits branch is unavailable"); }
-  if (fvbUseDet[L1DetectorID::kTrd] && !fpBrTrdHits) { throw std::logic_error("TRD hits branch is unavailable"); }
-  if (fvbUseDet[L1DetectorID::kTof] && !fpBrTofHits) { throw std::logic_error("TOF hits branch is unavailable"); }
+  for (int iDet = 0; iDet < static_cast<int>(L1DetectorID::kEND); ++iDet) {
+    if (fvbUseDet[iDet] && !fvpBrHits[iDet]) {
+      throw std::logic_error(std::string(kDetName[iDet]) + " hits branch is not found");
+    }
+  }
 
   if (fpvTracks) {
-    if (ECbmTrackingMode::kSTS == fTrackingMode) {
+    if (ECbmCaTrackingMode::kSTS == fTrackingMode) {
       if (!fpBrRecoTracks) { throw std::logic_error("StsTrack branch is unavailable"); }
     }
-    else if (ECbmTrackingMode::kMCBM == fTrackingMode) {
+    else if (ECbmCaTrackingMode::kMCBM == fTrackingMode) {
       if (!fpBrRecoTracks) { throw std::logic_error("GlobalTrack branch is unavailable"); }
       if (fvbUseDet[L1DetectorID::kSts] && !fpBrStsTracks) { throw std::logic_error("StsTrack branch is not found"); }
       if (fvbUseDet[L1DetectorID::kMuch] && !fpBrMuchTracks) {
@@ -109,11 +103,11 @@ try {
   LOG(info) << "TimeSliceReader: initializing run ... ";
 
   // Init tracking detector interfaces
-  fpMvdInterface  = CbmMvdTrackingInterface::Instance();
-  fpStsInterface  = CbmStsTrackingInterface::Instance();
-  fpMuchInterface = CbmMuchTrackingInterface::Instance();
-  fpTrdInterface  = CbmTrdTrackingInterface::Instance();
-  fpTofInterface  = CbmTofTrackingInterface::Instance();
+  fvpDetInterface[L1DetectorID::kMvd]  = CbmMvdTrackingInterface::Instance();
+  fvpDetInterface[L1DetectorID::kSts]  = CbmStsTrackingInterface::Instance();
+  fvpDetInterface[L1DetectorID::kMuch] = CbmMuchTrackingInterface::Instance();
+  fvpDetInterface[L1DetectorID::kTrd]  = CbmTrdTrackingInterface::Instance();
+  fvpDetInterface[L1DetectorID::kTof]  = CbmTofTrackingInterface::Instance();
 
   // ** Init data branches **
 
@@ -122,22 +116,25 @@ try {
 
   fpBrTimeSlice = dynamic_cast<CbmTimeSlice*>(pFairManager->GetObject("TimeSlice."));
 
-  // Init hit branches
-  if (fvbUseDet[L1DetectorID::kMvd]) { fpBrMvdHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MvdHit")); }
-  if (fvbUseDet[L1DetectorID::kSts]) { fpBrStsHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsHit")); }
-  if (fvbUseDet[L1DetectorID::kMuch]) {
-    fpBrMuchHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("MuchPixelHit"));
-  }
-  if (fvbUseDet[L1DetectorID::kTrd]) { fpBrTrdHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TrdHit")); }
-  if (fvbUseDet[L1DetectorID::kTof]) { fpBrTofHits = dynamic_cast<TClonesArray*>(pFairManager->GetObject("TofHit")); }
+  // Init branches
+  auto InitHitBranch = [&](L1DetectorID detID, const char* branchName) {
+    if (fvbUseDet[detID]) { fvpBrHits[detID] = dynamic_cast<TClonesArray*>(pFairManager->GetObject(branchName)); }
+  };
+
+  InitHitBranch(L1DetectorID::kMvd, "MvdHit");
+  InitHitBranch(L1DetectorID::kSts, "StsHit");
+  InitHitBranch(L1DetectorID::kMuch, "MuchPixelHit");
+  InitHitBranch(L1DetectorID::kTrd, "TrdHit");
+  InitHitBranch(L1DetectorID::kTof, "TofHit");
 
   // Init track branches
+
   if (fpvTracks) {
     switch (fTrackingMode) {
-      case ECbmTrackingMode::kSTS:
+      case ECbmCaTrackingMode::kSTS:
         fpBrRecoTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsTrack"));
         break;
-      case ECbmTrackingMode::kMCBM:
+      case ECbmCaTrackingMode::kMCBM:
         fpBrRecoTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("GlobalTrack"));
         if (fvbUseDet[L1DetectorID::kSts]) {
           fpBrStsTracks = dynamic_cast<TClonesArray*>(pFairManager->GetObject("StsTrack"));
@@ -188,7 +185,7 @@ void TimeSliceReader::ReadRecoTracks()
   int nTracks = fpBrRecoTracks->GetEntriesFast();
   fpvTracks->reset(nTracks);
   switch (fTrackingMode) {
-    case ECbmTrackingMode::kSTS:
+    case ECbmCaTrackingMode::kSTS:
       // Fill tracks from StsTrack branch
       for (int iT = 0; iT < nTracks; ++iT) {
         auto* pInputTrack = static_cast<CbmStsTrack*>(fpBrRecoTracks->At(iT));
@@ -207,18 +204,18 @@ void TimeSliceReader::ReadRecoTracks()
         track.Hits.reserve(pInputTrack->GetNofHits());
         for (int iH = 0; iH < pInputTrack->GetNofMvdHits(); ++iH) {
           int iHext = pInputTrack->GetMvdHitIndex(iH);
-          int iHint = vHitMvdIds[iHext];
+          int iHint = fvvHitExtToIntIndexMap[L1DetectorID::kMvd][iHext];
           track.Hits.push_back(iHint);
         }  // iH
         for (int iH = 0; iH < pInputTrack->GetNofStsHits(); ++iH) {
           int iHext = pInputTrack->GetStsHitIndex(iH);
-          int iHint = vHitStsIds[iHext];
+          int iHint = fvvHitExtToIntIndexMap[L1DetectorID::kSts][iHext];
           track.Hits.push_back(iHint);
         }  // iH
       }    // iT
       break;
 
-    case ECbmTrackingMode::kMCBM:
+    case ECbmCaTrackingMode::kMCBM:
       //LOG(fatal) << "Sorry, mCBM mode has not been implemented yet. Stay tuned :)";
       // Fill tracks from GlobalTrack branch
       for (int iT = 0; iT < nTracks; ++iT) {
@@ -238,13 +235,13 @@ void TimeSliceReader::ReadRecoTracks()
             if (fvbUseDet[L1DetectorID::kMvd]) {
               for (int iH = 0; iH < pStsTrack->GetNofMvdHits(); ++iH) {
                 int iHext = pStsTrack->GetMvdHitIndex(iH);
-                int iHint = vHitMvdIds[iHext];
+                int iHint = fvvHitExtToIntIndexMap[L1DetectorID::kMvd][iHext];
                 track.Hits.push_back(iHint);
               }
             }
             for (int iH = 0; iH < pStsTrack->GetNofStsHits(); ++iH) {
               int iHext = pStsTrack->GetStsHitIndex(iH);
-              int iHint = vHitStsIds[iHext];
+              int iHint = fvvHitExtToIntIndexMap[L1DetectorID::kSts][iHext];
               track.Hits.push_back(iHint);
             }
           }
@@ -257,7 +254,7 @@ void TimeSliceReader::ReadRecoTracks()
             auto* pMuchTrack = static_cast<CbmMuchTrack*>(fpBrMuchTracks->At(iMuchTrkId));
             for (int iH = 0; iH < pMuchTrack->GetNofHits(); ++iH) {
               int iHext = pMuchTrack->GetHitIndex(iH);
-              int iHint = vHitMuchIds[iHext];
+              int iHint = fvvHitExtToIntIndexMap[L1DetectorID::kMuch][iHext];
               track.Hits.push_back(iHint);
             }
           }
@@ -270,7 +267,7 @@ void TimeSliceReader::ReadRecoTracks()
             const auto* pTrdTrack = static_cast<const CbmTrdTrack*>(fpBrTrdTracks->At(iTrdTrkId));
             for (int iH = 0; iH < pTrdTrack->GetNofHits(); ++iH) {
               int iHext = pTrdTrack->GetHitIndex(iH);
-              int iHint = vHitTrdIds[iHext];
+              int iHint = fvvHitExtToIntIndexMap[L1DetectorID::kTrd][iHext];
               track.Hits.push_back(iHint);
             }  // iH
           }
@@ -283,7 +280,7 @@ void TimeSliceReader::ReadRecoTracks()
             const auto* pTofTrack = static_cast<const CbmTofTrack*>(fpBrTofTracks->At(iTofTrkId));
             for (int iH = 0; iH < pTofTrack->GetNofHits(); ++iH) {
               int iHext = pTofTrack->GetHitIndex(iH);
-              int iHint = vHitTofIds[iHext];
+              int iHint = fvvHitExtToIntIndexMap[L1DetectorID::kTof][iHext];
               track.Hits.push_back(iHint);
             }  // iH
           }    // if iTofTrkId > -1
@@ -303,42 +300,28 @@ void TimeSliceReader::RegisterIODataManager(std::shared_ptr<L1IODataManager>& pI
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-template<>
-void TimeSliceReader::SortQaHits<true>()
+void TimeSliceReader::SortQaHits()
 {
   int nStationsActive = fpParameters->GetNstationsActive();
   L1Vector<CbmL1HitDebugInfo> vNewHits(fpvQaHits->size());
-  std::vector<int> vHitFirstIndexes(nStationsActive + 1, 0);
+  std::vector<int> vHitFstIndexes(nStationsActive + 1, 0);
   std::vector<int> vNofHitsStored(nStationsActive, 0);
 
   // Count number of hits in each station (NOTE: we could use here boarders from the IO data manager, but we would keep
   // these two procedures independent)
-  for (const auto& hit : (*fpvQaHits)) {
-    ++vHitFirstIndexes[hit.GetStationId() + 1];
-  }
-
+  std::for_each(fpvQaHits->begin(), fpvQaHits->end(), [&](const auto& h) { ++vHitFstIndexes[h.GetStationId() + 1]; });
   for (int iSt = 0; iSt < nStationsActive; ++iSt) {
-    vHitFirstIndexes[iSt + 1] += vHitFirstIndexes[iSt];
+    vHitFstIndexes[iSt + 1] += vHitFstIndexes[iSt];
   }
 
   for (const auto& hit : (*fpvQaHits)) {
-    int iSt                                                   = hit.GetStationId();
-    vNewHits[vHitFirstIndexes[iSt] + (vNofHitsStored[iSt]++)] = hit;
+    int iSt                                                 = hit.GetStationId();
+    vNewHits[vHitFstIndexes[iSt] + (vNofHitsStored[iSt]++)] = hit;
   }
 
   std::swap(vNewHits, (*fpvQaHits));
 }
 
-// ---------------------------------------------------------------------------------------------------------------------
-//
-template<>
-void TimeSliceReader::SortQaHits<false>()
-{
-  std::sort(fpvQaHits->begin(), fpvQaHits->end(), [](const CbmL1HitDebugInfo& a, const CbmL1HitDebugInfo& b) {
-    return (a.iStation < b.iStation) || (a.iStation == b.iStation) && (a.y < b.y);
-  });
-}
-
 // ---------------------------------------------------------------------------------------------------------------------
 //
 void TimeSliceReader::ReadHits()
@@ -347,11 +330,10 @@ void TimeSliceReader::ReadHits()
   fNofHitKeys  = 0;
   fFirstHitKey = 0;
 
-  if (fvbUseDet[L1DetectorID::kMvd]) { fvNofHitsTotal[L1DetectorID::kMvd] = fpBrMvdHits->GetEntriesFast(); }
-  if (fvbUseDet[L1DetectorID::kSts]) { fvNofHitsTotal[L1DetectorID::kSts] = fpBrStsHits->GetEntriesFast(); }
-  if (fvbUseDet[L1DetectorID::kMuch]) { fvNofHitsTotal[L1DetectorID::kMuch] = fpBrMuchHits->GetEntriesFast(); }
-  if (fvbUseDet[L1DetectorID::kTrd]) { fvNofHitsTotal[L1DetectorID::kTrd] = fpBrTrdHits->GetEntriesFast(); }
-  if (fvbUseDet[L1DetectorID::kTof]) { fvNofHitsTotal[L1DetectorID::kTof] = fpBrTofHits->GetEntriesFast(); }
+  // TODO: Address case with CbmEvent != nullptr
+  for (int iDet = 0; iDet < static_cast<int>(L1DetectorID::kEND); ++iDet) {
+    if (fvbUseDet[iDet]) { fvNofHitsTotal[iDet] = fvpBrHits[iDet]->GetEntriesFast(); }
+  }
 
   int nHitsTot = std::accumulate(fvNofHitsTotal.begin(), fvNofHitsTotal.end(), 0);
 
@@ -364,29 +346,16 @@ void TimeSliceReader::ReadHits()
     fpvQaHits->clear();
     fpvQaHits->reserve(nHitsTot);
   }
-  if (fpIODataManager) {
-    fpIODataManager->ResetInputData();
-    fpIODataManager->ReserveNhits(nHitsTot);
-  }
+  if (fpIODataManager) { fpIODataManager->ResetInputData(nHitsTot); }
 
   std::fill(fvHitFirstIndexDet.begin(), fvHitFirstIndexDet.end(), 0);
 
   // Read hits for different detectors
-  if (fvbUseDet[L1DetectorID::kMvd]) {
-    fvNofHitsUsed[L1DetectorID::kMvd] = ReadHitsForDetector<L1DetectorID::kMvd>(fpBrMvdHits);
-  }
-  if (fvbUseDet[L1DetectorID::kSts]) {
-    fvNofHitsUsed[L1DetectorID::kSts] = ReadHitsForDetector<L1DetectorID::kSts>(fpBrStsHits);
-  }
-  if (fvbUseDet[L1DetectorID::kMuch]) {
-    fvNofHitsUsed[L1DetectorID::kMuch] = ReadHitsForDetector<L1DetectorID::kMuch>(fpBrMuchHits);
-  }
-  if (fvbUseDet[L1DetectorID::kTrd]) {
-    fvNofHitsUsed[L1DetectorID::kTrd] = ReadHitsForDetector<L1DetectorID::kTrd>(fpBrTrdHits);
-  }
-  if (fvbUseDet[L1DetectorID::kTof]) {
-    fvNofHitsUsed[L1DetectorID::kTof] = ReadHitsForDetector<L1DetectorID::kTof>(fpBrTofHits);
-  }
+  fvNofHitsUsed[L1DetectorID::kMvd]  = ReadHitsForDetector<L1DetectorID::kMvd>();
+  fvNofHitsUsed[L1DetectorID::kSts]  = ReadHitsForDetector<L1DetectorID::kSts>();
+  fvNofHitsUsed[L1DetectorID::kMuch] = ReadHitsForDetector<L1DetectorID::kMuch>();
+  fvNofHitsUsed[L1DetectorID::kTrd]  = ReadHitsForDetector<L1DetectorID::kTrd>();
+  fvNofHitsUsed[L1DetectorID::kTof]  = ReadHitsForDetector<L1DetectorID::kTof>();
 
   // Save first hit index for different detector subsystems
   for (uint32_t iDet = 0; iDet < fvNofHitsUsed.size(); ++iDet) {
@@ -399,26 +368,18 @@ void TimeSliceReader::ReadHits()
   if (fpIODataManager) { fpIODataManager->SetNhitKeys(fNofHitKeys); }
 
   // Sort debug hits
-  if (fpvQaHits) { this->SortQaHits<true>(); }  // false - old sort, true - new backet sort
+  if (fpvQaHits) { this->SortQaHits(); }
 
   // Update maps of ext->int hit indexes
   // NOTE: fvpHitIds must be initialized, if we want to read tracks from the file
   if (fpvHitIds) {
-    auto UpdateHitIndexMap = [&](L1Vector<int> & vIds, L1DetectorID detID) constexpr
-    {
-      if (fvbUseDet[detID]) {
-        vIds.reset(fvNofHitsTotal[detID]);
-        for (int iH = fvHitFirstIndexDet[int(detID)]; iH < fvHitFirstIndexDet[int(detID) + 1]; ++iH) {
-          vIds[(*fpvQaHits)[iH].ExtIndex] = iH;
-        }
-      }
-    };
+    auto ResetIndexMap = [&, idx = 0](auto& v) mutable { v.reset(fvNofHitsTotal[idx++]); };
+    std::for_each(fvvHitExtToIntIndexMap.begin(), fvvHitExtToIntIndexMap.end(), ResetIndexMap);
 
-    UpdateHitIndexMap(vHitMvdIds, L1DetectorID::kMvd);
-    UpdateHitIndexMap(vHitStsIds, L1DetectorID::kSts);
-    UpdateHitIndexMap(vHitMuchIds, L1DetectorID::kMuch);
-    UpdateHitIndexMap(vHitTrdIds, L1DetectorID::kTrd);
-    UpdateHitIndexMap(vHitTofIds, L1DetectorID::kTof);
+    for (int iH = 0; iH < fNofHits; ++iH) {
+      const auto& hit                               = (*fpvQaHits)[iH];
+      fvvHitExtToIntIndexMap[hit.Det][hit.ExtIndex] = iH;
+    }
   }
 }
 
@@ -448,17 +409,17 @@ void TimeSliceReader::StoreHitRecord(const HitRecord& hitRecord)
 
   // Save debug information
   if (fpvQaHits) {
-    CbmL1HitDebugInfo hitDbg;
-    hitDbg.Det      = hitRecord.fDet;
-    hitDbg.ExtIndex = hitRecord.fExtId;
-    hitDbg.IntIndex = static_cast<int>(fpvQaHits->size());
-    hitDbg.iStation = hitRecord.fStaId;
-    hitDbg.x        = hitRecord.fX;
-    hitDbg.y        = hitRecord.fY;
-    hitDbg.dx       = hitRecord.fDx;
-    hitDbg.dy       = hitRecord.fDy;
-    hitDbg.dxy      = hitRecord.fDxy;
-    hitDbg.time     = hitRecord.fT;
-    fpvQaHits->push_back(hitDbg);
+    CbmL1HitDebugInfo aHitQa;
+    aHitQa.Det      = hitRecord.fDet;
+    aHitQa.ExtIndex = hitRecord.fExtId;
+    aHitQa.IntIndex = static_cast<int>(fpvQaHits->size());
+    aHitQa.iStation = hitRecord.fStaId;
+    aHitQa.x        = hitRecord.fX;
+    aHitQa.y        = hitRecord.fY;
+    aHitQa.dx       = hitRecord.fDx;
+    aHitQa.dy       = hitRecord.fDy;
+    aHitQa.dxy      = hitRecord.fDxy;
+    aHitQa.time     = hitRecord.fT;
+    fpvQaHits->push_back(aHitQa);
   }
 }
diff --git a/reco/L1/CbmCaTimeSliceReader.h b/reco/L1/CbmCaTimeSliceReader.h
index 1b9e60dd05fc69b666c191301ecd081fe96d72c8..7cab89abfe338c071b108291cf683ba39cffeaba 100644
--- a/reco/L1/CbmCaTimeSliceReader.h
+++ b/reco/L1/CbmCaTimeSliceReader.h
@@ -10,6 +10,7 @@
 #ifndef CbmCaTimeSliceReader_h
 #define CbmCaTimeSliceReader_h 1
 
+#include "CbmCaMCModule.h"
 #include "CbmL1.h"  // TMP: for CbmL1HitStore
 #include "CbmL1DetectorID.h"
 #include "CbmL1Hit.h"
@@ -28,6 +29,7 @@
 
 #include "TClonesArray.h"
 
+#include "CaToolsHitRecord.h"
 #include "L1Constants.h"
 #include "L1Vector.h"
 
@@ -38,39 +40,19 @@ class L1Parameters;
 
 namespace cbm::ca
 {
+  using ::ca::tools::HitRecord;
+
+
   /// @brief A reader of time slice for CA tracker
   ///
   /// The class reads reconstructed hits and reconstructed tracks (optionally) and fills the CA tracking internal
   /// data structures.
   ///
   class TimeSliceReader {
-    /// @brief A structure to store hits information from different detectors in a uniform manner
-    ///
-    struct HitRecord {
-      double fX           = 0.;  ///< x component of hit position [cm]
-      double fY           = 0.;  ///< y component of hit position [cm]
-      double fDx          = 0.;  ///< error of x component of hit position [cm]
-      double fDy          = 0.;  ///< error of y component of hit position [cm]
-      double fDxy         = 0.;  ///< correlation between x and y components [cm]
-      double fU           = 0.;  ///< hit position in direction of front strips [cm]
-      double fV           = 0.;  ///< hit position in direction of back strips [cm]
-      double fDu          = 0.;  ///< hit position error in direction of front strips [cm]
-      double fDv          = 0.;  ///< hit position error in direction of back strips [cm]
-      double fZ           = 0.;  ///< z component of hit position [cm]
-      double fT           = 0.;  ///< time of hit [ns]
-      double fDt          = 0.;  ///< time error of hit [ns]
-      int64_t fDataStream = -1;  ///< Global index of detector module
-      int fExtId          = -1;  ///< external index of hit
-      int fStaId          = -1;  ///< index of active tracking station
-      int fStripF         = -1;  ///< index of front strip
-      int fStripB         = -1;  ///< index of back strip
-      int fDet            = -1;  ///< detector ID
-    };
-
   public:
     /// @brief Constructor from parameters
     /// @param mode  Tracking mode
-    TimeSliceReader(ECbmTrackingMode mode);
+    TimeSliceReader() = default;
 
     /// @brief Destructor
     ~TimeSliceReader() = default;
@@ -90,10 +72,6 @@ namespace cbm::ca
     /// @brief Clears class content
     void Clear();
 
-    /// @brief Check class initialization
-    /// @note The function throws std::logic_error, if initialization is incomplete
-    void CheckInit() const;
-
     /// @brief Gets reference to container of first hit indexes in a detector subsystem
     /// @return Ref. to the container
     const auto& GetHitFirstIndexDet() const { return fvHitFirstIndexDet; }
@@ -106,6 +84,9 @@ namespace cbm::ca
       return fvHitFirstIndexDet[int(iDet) + 1] - fvHitFirstIndexDet[int(iDet)];
     }
 
+    /// @brief Gets CBM tracking mode
+    ECbmCaTrackingMode GetTrackingMode() const { return fTrackingMode; }
+
     /// @brief Run initializer function
     /// @return Success flag
     ///
@@ -117,12 +98,6 @@ namespace cbm::ca
     /// Reads hits and tracks (optionally) from time slice
     void InitTimeSlice();
 
-    /// @brief Reads hits
-    void ReadHits();
-
-    /// @brief Reads reconstructed tracks
-    void ReadRecoTracks();
-
     /// @brief Registers hit debug info container
     /// @param vQaHits  Reference to Qa hit container
     /// @note If no container is registered, all related routines are omitted
@@ -153,17 +128,30 @@ namespace cbm::ca
     /// @note Should be called before this->Init()
     void SetDetector(L1DetectorID detID, bool flag = true) { fvbUseDet[detID] = flag; }
 
+    /// @brief  Sets the tracking mode
+    /// @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
+    void CheckInit() const;
+
+    /// @brief Reads hits
+    void ReadHits();
+
+    /// @brief Reads reconstructed tracks
+    void ReadRecoTracks();
+
     /// @brief Reads hits for a given detector subsystem
     /// @tparam Detector ID
-    /// @param  pBrHits  Pointer to input hit branch
     /// @return  Number of stored hits
     /// @note The function modifies fNofHitKey and fFirstHitKey counters
     template<L1DetectorID DetID>
-    int ReadHitsForDetector(const TClonesArray* pBrHits);
+    int ReadHitsForDetector();
 
     /// @brief Sorts QA hit objects by stations
-    template<bool IsNewSortingApproach>
     void SortQaHits();
 
     /// @brief Saves hit to data structures
@@ -172,27 +160,14 @@ namespace cbm::ca
     /// Stores recorded hit information into registered hit containers
     void StoreHitRecord(const HitRecord& hitRecord);
 
-
     bool fbReadTracks = true;   ///< flag to read reconstructed tracks from reco.root
 
-
-    // Pointers to the tracking detector interfaces
-    CbmTrackingDetectorInterfaceBase* fpMvdInterface  = nullptr;
-    CbmTrackingDetectorInterfaceBase* fpStsInterface  = nullptr;
-    CbmTrackingDetectorInterfaceBase* fpMuchInterface = nullptr;
-    CbmTrackingDetectorInterfaceBase* fpTrdInterface  = nullptr;
-    CbmTrackingDetectorInterfaceBase* fpTofInterface  = nullptr;
+    /// @brief Pointers to the tracking detector interfaces for each subsystem
+    CbmCaDetIdArr_t<const CbmTrackingDetectorInterfaceBase*> fvpDetInterface = {{nullptr}};
 
     // Input data branches
-    CbmTimeSlice* fpBrTimeSlice = nullptr;  ///< Pointer to the TS object
-
-    TClonesArray* fpBrMvdHits  = nullptr;  ///< Input branch for MVD hits ("MvdHit")
-    TClonesArray* fpBrStsHits  = nullptr;  ///< Input branch for STS hits ("StsHit")
-    TClonesArray* fpBrMuchHits = nullptr;  ///< Input branch for MuCh hits ("MuchPixelHit")
-    TClonesArray* fpBrTrdHits  = nullptr;  ///< Input branch for TRD hits ("TrdHit")
-    TClonesArray* fpBrTofHits  = nullptr;  ///< Input branch for TOF hits ("TofHit")
-
-    CbmCaDetIdArr_t<TClonesArray*> fvpBrHits = {nullptr};  ///< Input branch for hits
+    CbmTimeSlice* fpBrTimeSlice              = nullptr;      ///< Pointer to the TS object
+    CbmCaDetIdArr_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
     // tracking mode. For simulations in CBM, the CA tracking is used only in STS + MVD detectors. In this case
@@ -211,27 +186,21 @@ namespace cbm::ca
     std::shared_ptr<L1IODataManager> fpIODataManager = nullptr;  ///< Pointer to input data manager
     std::shared_ptr<L1Parameters> fpParameters       = nullptr;  ///< Pointer to tracking parameters object
 
-
     // Maps of hit indexes: ext -> int
-    L1Vector<int> vHitMvdIds {"CbmCaTimeSliceReader::vHitMvdIds"};
-    L1Vector<int> vHitStsIds {"CbmCaTimeSliceReader::vHitStsIds"};
-    L1Vector<int> vHitMuchIds {"CbmCaTimeSliceReader::vHitMuchIds"};
-    L1Vector<int> vHitTrdIds {"CbmCaTimeSliceReader::vHitTrdIds"};
-    L1Vector<int> vHitTofIds {"CbmCaTimeSliceReader::vHitTofIds"};
+    CbmCaDetIdArr_t<L1Vector<int>> fvvHitExtToIntIndexMap;  ///< Hit index map ext -> int
 
-    CbmCaDetIdArr_t<int> fvNofHitsTotal = {0};      ///< Total hit number in detector
-    CbmCaDetIdArr_t<int> fvNofHitsUsed  = {0};      ///< Number of used hits in detector
-    CbmCaDetIdArr_t<bool> fvbUseDet     = {false};  ///< Flag: is detector subsystem used
+    CbmCaDetIdArr_t<int> fvNofHitsTotal = {{0}};      ///< Total hit number in detector
+    CbmCaDetIdArr_t<int> fvNofHitsUsed  = {{0}};      ///< Number of used hits in detector
+    CbmCaDetIdArr_t<bool> fvbUseDet     = {{false}};  ///< Flag: is detector subsystem used
 
-    // Additional
-    ECbmTrackingMode fTrackingMode;  ///< Tracking mode
+    ECbmCaTrackingMode fTrackingMode = ECbmCaTrackingMode::kSTS;  ///< Tracking mode
 
     // Variables for storing cache
     int fNofHits     = 0;  ///< Stored number of hits
     int fNofHitKeys  = 0;  ///< Recorded number of hit keys
     int fFirstHitKey = 0;  ///< First index of hit key for the detector subsystem
 
-    std::array<int, L1Constants::size::kMaxNdetectors + 1> fvHitFirstIndexDet = {0};  ///< First hit index in detector
+    std::array<int, L1Constants::size::kMaxNdetectors + 1> fvHitFirstIndexDet = {{0}};  ///< First hit index in detector
   };
 }  // namespace cbm::ca
 
@@ -243,78 +212,61 @@ namespace cbm::ca
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<L1DetectorID DetID>
-int cbm::ca::TimeSliceReader::ReadHitsForDetector(const TClonesArray* pBrHits)
+int cbm::ca::TimeSliceReader::ReadHitsForDetector()
 {
-  int nHitsTot    = pBrHits->GetEntriesFast();  // total number of hits stored in a branch
-  int nHitsStored = 0;                          // number of hits stored
+  if (!fvbUseDet[DetID]) { return 0; }  // Detector is entirelly not used
+
+  const auto* pDetInterface = fvpDetInterface[DetID];
+  int nHitsTot              = fvpBrHits[DetID]->GetEntriesFast();  // total number of hits provided by hit finder
+  int nHitsStored           = 0;                                   // number of hits used in tracking
 
   fFirstHitKey = fNofHitKeys;
 
   for (int iHext = 0; iHext < nHitsTot; ++iHext) {
-    HitRecord hitRecord;  // Record of hits information
+    HitRecord hitRecord;
 
     CbmPixelHit* pPixelHit = nullptr;  // Pointer to hit object
-    float phiF             = 0.;       // Stereo angle of front strips
-    float phiB             = 0.;       // Stereo angle of back strips
     int iStGeom            = -1;       // Geometry station number
 
     // Fill out detector specific data
     if constexpr (L1DetectorID::kMvd == DetID) {
-      CbmMvdHit* pMvdHit = static_cast<CbmMvdHit*>(pBrHits->At(iHext));
-      iStGeom            = fpMvdInterface->GetTrackingStationIndex(pMvdHit->GetStationNr());
-      phiF               = fpMvdInterface->GetStripsStereoAngleFront(iStGeom);
-      phiB               = fpMvdInterface->GetStripsStereoAngleBack(iStGeom);
+      CbmMvdHit* pMvdHit = static_cast<CbmMvdHit*>(fvpBrHits[DetID]->At(iHext));
       pPixelHit          = static_cast<CbmPixelHit*>(pMvdHit);
-      hitRecord.fDu      = pMvdHit->GetDx();
-      hitRecord.fDv      = pMvdHit->GetDy();
+      iStGeom            = pDetInterface->GetTrackingStationIndex(pMvdHit->GetStationNr());
     }
     else if constexpr (L1DetectorID::kSts == DetID) {
-      CbmStsHit* pStsHit = static_cast<CbmStsHit*>(pBrHits->At(iHext));
-      iStGeom            = fpStsInterface->GetTrackingStationIndex(pStsHit->GetAddress());
-      phiF               = fpStsInterface->GetStripsStereoAngleFront(iStGeom);
-      phiB               = fpStsInterface->GetStripsStereoAngleBack(iStGeom);
+      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();
       hitRecord.fDu      = pStsHit->GetDu();
       hitRecord.fDv      = pStsHit->GetDv();
     }
     else if constexpr (L1DetectorID::kMuch == DetID) {
-      CbmMuchPixelHit* pMuchHit = static_cast<CbmMuchPixelHit*>(pBrHits->At(iHext));
-      iStGeom                   = fpMuchInterface->GetTrackingStationIndex(pMuchHit->GetAddress());
-      phiF                      = fpMuchInterface->GetStripsStereoAngleFront(iStGeom);
-      phiB                      = fpMuchInterface->GetStripsStereoAngleBack(iStGeom);
+      CbmMuchPixelHit* pMuchHit = static_cast<CbmMuchPixelHit*>(fvpBrHits[DetID]->At(iHext));
       pPixelHit                 = static_cast<CbmPixelHit*>(pMuchHit);
-      hitRecord.fDu             = pMuchHit->GetDx();
-      hitRecord.fDv             = pMuchHit->GetDy();
+      iStGeom                   = pDetInterface->GetTrackingStationIndex(pMuchHit->GetAddress());
     }
     else if constexpr (L1DetectorID::kTrd == DetID) {
-      CbmTrdHit* pTrdHit = static_cast<CbmTrdHit*>(pBrHits->At(iHext));
-      iStGeom            = fpTrdInterface->GetTrackingStationIndex(pTrdHit->GetAddress());
-      phiF               = fpTrdInterface->GetStripsStereoAngleFront(iStGeom);
-      phiB               = fpTrdInterface->GetStripsStereoAngleBack(iStGeom);
+      CbmTrdHit* pTrdHit = static_cast<CbmTrdHit*>(fvpBrHits[DetID]->At(iHext));
       pPixelHit          = static_cast<CbmPixelHit*>(pTrdHit);
-      hitRecord.fDu      = pTrdHit->GetDx();
-      hitRecord.fDv      = pTrdHit->GetDy();
+      iStGeom            = pDetInterface->GetTrackingStationIndex(pTrdHit->GetAddress());
     }
     else if constexpr (L1DetectorID::kTof == DetID) {
-      CbmTofHit* pTofHit = static_cast<CbmTofHit*>(pBrHits->At(iHext));
+      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       = fpTofInterface->GetTrackingStationIndex(pTofHit);
-      phiF          = fpTofInterface->GetStripsStereoAngleFront(iStGeom);
-      phiB          = fpTofInterface->GetStripsStereoAngleBack(iStGeom);
-      pPixelHit     = static_cast<CbmPixelHit*>(pTofHit);
-      hitRecord.fDu = pTofHit->GetDx();
-      hitRecord.fDv = pTofHit->GetDy();
+      iStGeom = pDetInterface->GetTrackingStationIndex(pTofHit);
 
       // *** Additional cuts for TOF ***
       // Skip T0 hits
       if (5 == CbmTofAddress::GetSmType(pTofHit->GetAddress())) { continue; }
 
       // FIXME: Figure it out, if this cut is still needed (introduced a year ago for mCBM)
-      if (ECbmTrackingMode::kMCBM == fTrackingMode && pTofHit->GetZ() > 400) { continue; }
+      if (ECbmCaTrackingMode::kMCBM == fTrackingMode && pTofHit->GetZ() > 400) { continue; }
     }
 
     int iStActive = fpParameters->GetStationIndexActive(iStGeom, DetID);
@@ -332,6 +284,8 @@ int cbm::ca::TimeSliceReader::ReadHitsForDetector(const TClonesArray* pBrHits)
     hitRecord.fDt         = pPixelHit->GetTimeError();
     hitRecord.fDet        = static_cast<int>(DetID);
     hitRecord.fDataStream = (static_cast<int64_t>(hitRecord.fDet) << 60) | pPixelHit->GetAddress();
+    float phiF            = pDetInterface->GetStripsStereoAngleFront(iStGeom);
+    float phiB            = pDetInterface->GetStripsStereoAngleBack(iStGeom);
     hitRecord.fU          = hitRecord.fX * cos(phiF) + hitRecord.fY * sin(phiF);
     hitRecord.fV          = hitRecord.fX * cos(phiB) + hitRecord.fY * sin(phiB);
     hitRecord.fExtId      = iHext;
@@ -342,6 +296,8 @@ int cbm::ca::TimeSliceReader::ReadHitsForDetector(const TClonesArray* pBrHits)
       if (fNofHitKeys <= hitRecord.fStripB) { fNofHitKeys += hitRecord.fStripB; }
     }
     else {
+      hitRecord.fDu     = hitRecord.fDx;
+      hitRecord.fDv     = hitRecord.fDy;
       hitRecord.fStripF = fFirstHitKey + iHext;
       hitRecord.fStripB = hitRecord.fStripF;
       if (fNofHitKeys <= hitRecord.fStripF) { fNofHitKeys += hitRecord.fStripF; }
@@ -351,8 +307,8 @@ int cbm::ca::TimeSliceReader::ReadHitsForDetector(const TClonesArray* pBrHits)
     this->StoreHitRecord(hitRecord);
     ++nHitsStored;
   }  // iH
+
   return nHitsStored;
 }
 
-
 #endif  // CbmCaTimeSliceReader_h
diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx
index d2469ffd5e2e5a7c126b9e92f16ad7d122292fda..0cc4dba49d07b25b681566e4cc0fd4d7f36ab490 100644
--- a/reco/L1/CbmL1.cxx
+++ b/reco/L1/CbmL1.cxx
@@ -1,6 +1,6 @@
 /* Copyright (C) 2006-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Ivan Kisel, Sergey Gorbunov [committer], Valentina Akishina, Igor Kulakov, Maksym Zyzak */
+   Authors: Ivan Kisel, Sergey Gorbunov [committer], Valentina Akishina, Igor Kulakov, Maksym Zyzak, Sergei Zharko */
 
 /*
  *====================================================================
@@ -1138,8 +1138,9 @@ void CbmL1::IdealTrackFinder()
     for (unsigned int iH = 0; iH < MC.Hits.size(); iH++) {
       const int hitI               = MC.Hits[iH];
       const CbmL1HitDebugInfo& hit = fvHitDebugInfo[hitI];
-
-      const int iStation = fvMCPoints[hit.mcPointIds[0]].iStation;
+      const int iP                 = hit.GetMCPointIndex();
+      assert(iP >= 0);
+      const int iStation = fvMCPoints[iP].iStation;
 
       if (iStation >= 0) hitIndices[iStation] = hitI;
     }
diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h
index 85608d727df3f472967998948eb93713a2009a6b..8d663caccc1343ac81a18ef01f1f5fec3472bd26 100644
--- a/reco/L1/CbmL1.h
+++ b/reco/L1/CbmL1.h
@@ -381,6 +381,9 @@ private:
   // ** Reconstruction Performance **
   // ********************************
 
+  /// @brief  Sets random seed to CA internal random generator
+  /// @param  seed  Random seed
+  void SetRandomSeed(unsigned int seed) { fInitManager.SetRandomSeed(seed); }
 
   /// Matches reconstructed and MC tracks
   /// \note Should be called before Performances
diff --git a/reco/L1/CbmL1DetectorID.h b/reco/L1/CbmL1DetectorID.h
index 1ec1ae7eb2da97b2dd9bb7f2fd6c1665d271fffd..d4435388cc21589f74802c741838c0c5edf2b829 100644
--- a/reco/L1/CbmL1DetectorID.h
+++ b/reco/L1/CbmL1DetectorID.h
@@ -10,12 +10,15 @@
 #ifndef CbmL1DetectorID_h
 #define CbmL1DetectorID_h 1
 
+#include <string>
+
 #include "L1EArray.h"
 
 /// Enumeration for the detector subsystems used in L1 tracking
 /// It is important for the subsystems to be specified in the actual order. The order is used
 /// for the L1Station array filling.
 /// Note: L1DetectorID has a forward declaration in L1InitManager.h and L1BaseStationInfo.h
+/// TODO: Probably, we need to move everything into a single CbmCaConst.h header
 enum class L1DetectorID
 {
   kMvd,
@@ -31,9 +34,15 @@ enum class L1DetectorID
 template<typename T>
 using CbmCaDetIdArr_t = L1EArray<L1DetectorID, T>;
 
+namespace cbm::ca
+{
+  /// @brief Name of detector subsystems
+  constexpr CbmCaDetIdArr_t<const char*> kDetName = {{"MVD", "STS", "MuCh", "TRD", "TOF"}};
+
+}  // namespace cbm::ca
 
 /// @brief Enumeration for different tracking running modes
-enum class ECbmTrackingMode
+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
diff --git a/reco/L1/CbmL1Hit.h b/reco/L1/CbmL1Hit.h
index 3c5c66caf91ebd9da4569273dbe1f7e2a9ec3d99..92b76f8770f3458d57cb2c7a111c84f007639396 100644
--- a/reco/L1/CbmL1Hit.h
+++ b/reco/L1/CbmL1Hit.h
@@ -49,7 +49,7 @@ public:
 ///
 class CbmL1HitDebugInfo {  // TODO: SZh 21.09.2022: Replace instances of this class with L1Hit
 public:
-  /// Gets detector type
+  /// @brief Gets detector type
   /// 0 - MVD
   /// 1 - STS
   /// 2 - MuCh
@@ -58,29 +58,31 @@ public:
   // TODO: SZh 02.03.2023: Replace det. ID with L1DetectorID
   int GetDetectorType() const { return Det; }
 
-  /// Gets distance from z-axis [cm]
-  float GetR() const { return std::sqrt(x * x + y * y); }
+  /// @brief Gets distance from z-axis [cm]
+  double GetR() const { return std::sqrt(x * x + y * y); }
 
-  /// Gets index of the hit in the external container
+  /// @brief Gets index of the hit in the external container
   int GetExternalHitId() const { return ExtIndex; }
 
-  /// Gets MC point index container
-  const auto& GetMCPointIndexes() const { return mcPointIds; }
+  /// @brief Gets index of matched MC point
+  int GetMCPointIndex() const { return fPointID; }
 
-  /// Gets index of matched MC point
-  int GetMCPointIndex() const { return mcPointIds.size() ? mcPointIds[0] : -1; }
-
-  /// Gets global index of active tracking station
+  /// @brief Gets global index of active tracking station
   int GetStationId() const { return iStation; }
 
-  /// Gets time measurement [ns]
-  float GetT() const { return time; }
+  /// @brief Gets time measurement [ns]
+  double GetT() const { return time; }
+
+  /// @brief Gets x component of position [cm]
+  double GetX() const { return x; }
+
+  /// @brief Gets y component of position [cm]
+  double GetY() const { return y; }
 
-  /// Gets x component of position [cm]
-  float GetX() const { return x; }
+  /// @brief Sets index of matched MC point
+  /// @param pointID  Internal index of MC point
+  void SetMCPointIndex(int pointID) { fPointID = pointID; }
 
-  /// Gets y component of position [cm]
-  float GetY() const { return y; }
 
   /// @brief String representation of the object
   /// @param verbose  Verbosity level
@@ -102,7 +104,7 @@ public:
       if (verbose > 0) {
         msg << setw(14) << setfill(' ') << "dx [cm]" << ' ';
         msg << setw(14) << setfill(' ') << "dy [cm]" << ' ';
-        msg << setw(14) << setfill(' ') << "dxy [cm]" << ' ';
+        msg << setw(14) << setfill(' ') << "dxy [cm2]" << ' ';
         msg << setw(14) << setfill(' ') << "dt [ns]" << ' ';
       }
     }
@@ -129,6 +131,7 @@ public:
   int ExtIndex;                                                ///< index of hit in the external branch
   int IntIndex;                                                ///< index of hit in the internal array
   int iStation;                                                ///< index of station in active stations array
+  int Det;                                                     ///< detector subsystem ID
   double x;                                                    ///< x coordinate of position [cm]
   double y;                                                    ///< y coordinate of position [cm]
   double time;                                                 ///< hit time [ns]
@@ -136,8 +139,7 @@ public:
   double dy;                                                   ///< y coordinate error [cm]
   double dt;                                                   ///< time error [ns]
   double dxy;                                                  ///< covariance between x and y [cm2]
-  int Det;                                                     ///< detector subsystem ID
-  L1Vector<int> mcPointIds {"CbmL1HitDebugInfo::mcPointIds"};  ///< indices of CbmL1MCPoint in L1->fvMCPoints array
+  int fPointID = -1;                                           ///< index of matched MC point
 };
 
 #endif
diff --git a/reco/L1/CbmL1Performance.cxx b/reco/L1/CbmL1Performance.cxx
index 38dca67a4bacdfd37d772efbd6a43d7e4cad051e..2fce9259f9db132b1f6dfc5e9b082d3f84776c86 100644
--- a/reco/L1/CbmL1Performance.cxx
+++ b/reco/L1/CbmL1Performance.cxx
@@ -101,27 +101,23 @@ void CbmL1::TrackMatch()
     map<int, int>& hitmap = prtra->hitMap;  // how many hits from each mcTrack belong to current recoTrack
     map<int, int> hitmapChain;
     for (vector<int>::iterator ih = (prtra->Hits).begin(); ih != (prtra->Hits).end(); ++ih) {
-
-      const int nMCPoints = fvHitDebugInfo[*ih].mcPointIds.size();
-      for (int iP = 0; iP < nMCPoints; iP++) {
-        int iMC = fvHitDebugInfo[*ih].mcPointIds[iP];
-
-        //     cout<<iMC<<" iMC"<<endl;
-        int ID      = -1;
-        int chainID = -1;
-        if (iMC >= 0) {
-          ID      = fvMCPoints[iMC].ID;
-          chainID = fvMCTracks[ID].chainID;
-        }
-        if (hitmap.find(ID) == hitmap.end()) hitmap[ID] = 1;
-        else {
-          hitmap[ID] += 1;
-        }
-        if (hitmapChain.find(chainID) == hitmapChain.end()) hitmapChain[chainID] = 1;
-        else {
-          hitmapChain[chainID] += 1;
-        }
-      }  // for iPoint
+      int iMC = fvHitDebugInfo[*ih].GetMCPointIndex();
+
+      //     cout<<iMC<<" iMC"<<endl;
+      int ID      = -1;
+      int chainID = -1;
+      if (iMC >= 0) {
+        ID      = fvMCPoints[iMC].ID;
+        chainID = fvMCTracks[ID].chainID;
+      }
+      if (hitmap.find(ID) == hitmap.end()) hitmap[ID] = 1;
+      else {
+        hitmap[ID] += 1;
+      }
+      if (hitmapChain.find(chainID) == hitmapChain.end()) hitmapChain[chainID] = 1;
+      else {
+        hitmapChain[chainID] += 1;
+      }
     }    // for iHit
 
     // RTrack <-> MCTrack identification
diff --git a/reco/L1/CbmL1ReadEvent.cxx b/reco/L1/CbmL1ReadEvent.cxx
index a87bd4748b8bd3874637031be5310a1013bea397..400efdeb0e6403826da9967973597253c1c82b25 100644
--- a/reco/L1/CbmL1ReadEvent.cxx
+++ b/reco/L1/CbmL1ReadEvent.cxx
@@ -1145,9 +1145,7 @@ void CbmL1::ReadEvent(CbmEvent* event)
   fvExternalHits.reserve(nHits);
   fvHitDebugInfo.reserve(nHits);
   fvHitPointIndexes.reserve(nHits);
-
-  fpIODataManager->ResetInputData();
-  fpIODataManager->ReserveNhits(nHits);
+  fpIODataManager->ResetInputData(nHits);
   fpIODataManager->SetNhitKeys(NStrips);
 
   // ----- Fill
@@ -1461,13 +1459,8 @@ bool CbmL1::ReadMCPoint(CbmL1MCPoint* MC, int iPoint, int file, int event, int i
 void CbmL1::HitMatch()
 {
   // Clear contents
-  for (auto& hit : fvHitDebugInfo) {
-    hit.mcPointIds.clear();
-  }
-
-  for (auto& point : fvMCPoints) {
-    point.hitIds.clear();
-  }
+  std::for_each(fvHitDebugInfo.begin(), fvHitDebugInfo.end(), [&](auto& hit) { hit.SetMCPointIndex(-1); });
+  std::for_each(fvMCPoints.begin(), fvMCPoints.end(), [&](auto& point) { point.hitIds.clear(); });
 
   // Fill new contents
   const int NHits = fvHitDebugInfo.size();
@@ -1475,7 +1468,7 @@ void CbmL1::HitMatch()
     CbmL1HitDebugInfo& hit = fvHitDebugInfo[iH];
     int iP                 = fvHitPointIndexes[iH];
     if (iP >= 0) {
-      hit.mcPointIds.push_back_no_warning(iP);
+      hit.SetMCPointIndex(iP);
       fvMCPoints[iP].hitIds.push_back_no_warning(iH);
     }
   }
diff --git a/reco/L1/L1Algo/L1IODataManager.cxx b/reco/L1/L1Algo/L1IODataManager.cxx
index a76fad40bbde38b9338e4ff2882177a2e1619521..37913828d6ff099049c8188bfbac8c61c09d75cc 100644
--- a/reco/L1/L1Algo/L1IODataManager.cxx
+++ b/reco/L1/L1Algo/L1IODataManager.cxx
@@ -75,13 +75,14 @@ void L1IODataManager::ReadInputData(const std::string& fileName)
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void L1IODataManager::ResetInputData() noexcept
+void L1IODataManager::ResetInputData(L1HitIndex_t nHits) noexcept
 {
   L1InputData tmp;
   fInputData.Swap(tmp);
   fLastStreamId = -1;
-  fInputData.fStreamStartIndices.reserve(2000);
+  fInputData.fStreamStartIndices.reserve(2000);  // TODO: What are these numbers? Please, put them into L1Constants.h
   fInputData.fStreamStopIndices.reserve(2000);
+  fInputData.fHits.reserve(nHits);
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
diff --git a/reco/L1/L1Algo/L1IODataManager.h b/reco/L1/L1Algo/L1IODataManager.h
index 49bcf6fa58008247f15ede4034cc394748f17e57..b7902481d6b81077285cf27457398ffd47f466de 100644
--- a/reco/L1/L1Algo/L1IODataManager.h
+++ b/reco/L1/L1Algo/L1IODataManager.h
@@ -57,8 +57,9 @@ public:
   /// \note   If one does not call this method, the underlying vector of hits will be filled with the time penalty
   void ReserveNhits(L1HitIndex_t nHits) { fInputData.fHits.reserve(nHits); }
 
-  /// Resets the input data block
-  void ResetInputData() noexcept;
+  /// @brief  Resets the input data block
+  /// @param  nHits  Number of hits to reserve
+  void ResetInputData(L1HitIndex_t nHits = 0) noexcept;
 
   /// Pushes back a hit
   /// \param  hit  An L1Hit object
diff --git a/reco/L1/L1Algo/L1InitManager.h b/reco/L1/L1Algo/L1InitManager.h
index 9a2f76cae719c6b4aa6e6d2de7e740d677a98da0..e85cc484ab3d252f128e7c6f6e659ec9c65ccafe 100644
--- a/reco/L1/L1Algo/L1InitManager.h
+++ b/reco/L1/L1Algo/L1InitManager.h
@@ -225,6 +225,11 @@ public:
   /// \param  filename  Name of the output L1 parameters configuration
   void SetOutputConfigName(const std::string& filename) { fConfigOutputName = filename; }
 
+  /// @brief Sets pseudo-random numbers generator seed
+  /// @param seed  Seed value
+  /// @note  The default seed is 0
+  void SetRandomSeed(unsigned int seed) { fParameters.fRandomSeed = seed; }
+
   /// Sets target position
   /// \param  x  Position X component [cm]
   /// \param  y  Position Y component [cm]
diff --git a/reco/L1/L1Algo/L1Parameters.cxx b/reco/L1/L1Algo/L1Parameters.cxx
index 443b6660e6765e7c6c14dc2e322949a0de87e254..396c09b151a59ec9466bb4defa63510a353b853b 100644
--- a/reco/L1/L1Algo/L1Parameters.cxx
+++ b/reco/L1/L1Algo/L1Parameters.cxx
@@ -232,6 +232,7 @@ std::string L1Parameters::ToString(int verbosity, int indentLevel) const
   aStream << indent << indentChar << "Max number of threads:              " << L1Constants::size::kMaxNthreads << '\n';
   aStream << indent << indentChar << "Max number of triplets:             " << L1Constants::size::kMaxNtriplets << '\n';
   aStream << indent << kCLb << "RUNTIME CONSTANTS:\n" << kCL;
+  aStream << indent << indentChar << "Random seed:                        " << fRandomSeed << '\n';
   aStream << indent << indentChar << "Max number of doublets per singlet: " << fMaxDoubletsPerSinglet << '\n';
   aStream << indent << indentChar << "Max number of triplets per doublet: " << fMaxTripletPerDoublets << '\n';
   aStream << indent << indentChar << "Tracking level:                     " << fTrackingLevel << '\n';
diff --git a/reco/L1/L1Algo/L1Parameters.h b/reco/L1/L1Algo/L1Parameters.h
index bfe7ba29142d5da28b9a899771d436a77c8b8f7d..03c235f250053cd887c93cc1800ba6f1932fb5ab 100644
--- a/reco/L1/L1Algo/L1Parameters.h
+++ b/reco/L1/L1Algo/L1Parameters.h
@@ -71,12 +71,21 @@ public:
   /// String representation of the class contents
   std::string ToString(int verbosity = 0, int indentLevel = 0) const;
 
+  // TODO: SZh 15.05.2023: Setters should be removed from the class, since parameters
+  //                       can be initialized only via L1InitManager.
   /// Sets upper-bound cut on max number of doublets per one singlet
   void SetMaxDoubletsPerSinglet(unsigned int value) { fMaxDoubletsPerSinglet = value; }
 
   /// Sets upper-bound cut on max number of triplets per one doublet
   void SetMaxTripletPerDoublets(unsigned int value) { fMaxTripletPerDoublets = value; }
 
+  /// @brief  Gets first active station index within detector subsystem
+  /// @param  detectorID  Detector ID
+  int GetFirstActiveStationIndex(L1DetectorID detectorID) const
+  {
+    return std::accumulate(fNstationsActive.cbegin(), fNstationsActive.cbegin() + static_cast<int>(detectorID), 0);
+  }
+
   /// Gets upper-bound cut on max number of doublets per one singlet
   unsigned int GetMaxDoubletsPerSinglet() const { return fMaxDoubletsPerSinglet; }
 
@@ -181,6 +190,12 @@ public:
   /// Gets L1FieldValue object at primary vertex
   const L1FieldValue& GetVertexFieldValue() const { return fVertexFieldValue; }
 
+  /// @brief Gets random seed
+  ///
+  /// If random seed is zero, std::random_device is used to seed the random number generator.
+  int GetRandomSeed() const { return fRandomSeed; }
+
+
   /// Gets ghost suppression flag
   int GetGhostSuppression() const { return fGhostSuppression; }
 
@@ -268,6 +283,8 @@ private:
   int fTrackingLevel    = 0;  ///< tracking level
   int fGhostSuppression = 0;  ///< flag: if true, ghost tracks are suppressed
   float fMomentumCutOff = 0;  ///< minimum momentum of tracks
+  int fRandomSeed       = 1;  ///< random seed
+
 
   // ***************************
   // ** Flags for development **
@@ -278,7 +295,7 @@ private:
   bool fDevIsMatchDoubletsViaMc {false};        ///< Flag to match doublets using MC information
   bool fDevIsMatchTripletsViaMc {false};        ///< Flag to match triplets using Mc information
   bool fDevIsExtendTracksViaMc {false};         ///< Flag to extend tracks using Mc information
-  bool fDevIsSuppressOverlapHitsViaMc {false};  ///<  Flag to match hits in overlaps using Mc information
+  bool fDevIsSuppressOverlapHitsViaMc {false};  ///< Flag to match hits in overlaps using Mc information
 
   bool fDevIsParSearchWUsed       = false;  ///< Flag: when true, the parametrized search windows are used in track
                                             ///< finder; when false, the Kalman filter is used instead
@@ -310,6 +327,7 @@ private:
     ar& fTrackingLevel;
     ar& fGhostSuppression;
     ar& fMomentumCutOff;
+    ar& fRandomSeed;
 
     ar& fDevIsIgnoreHitSearchAreas;
     ar& fDevIsUseOfOriginalField;
diff --git a/reco/L1/L1Algo/L1Station.h b/reco/L1/L1Algo/L1Station.h
index 0b86797812e65485c35e5981bab2afaff63d73dd..f22946a8975fed64034e2c43bfe355daecc3c390 100644
--- a/reco/L1/L1Algo/L1Station.h
+++ b/reco/L1/L1Algo/L1Station.h
@@ -21,6 +21,9 @@
 ///
 class L1Station {
 public:
+  // TODO: SZh 12.05.2022: Rewrite type into L1DetectorID, change detector indexing scheme
+  // TODO: SZh 12.05.2022: Provide getters to stations
+
   int type        = undef::kI32;
   int timeInfo    = undef::kI32;  ///< flag: if time information can be used
   int fieldStatus = undef::kI32;  ///< flag: 1 - station is INSIDE the field, 0 - station is OUTSIDE the field
diff --git a/reco/L1/L1Algo/L1Utils.h b/reco/L1/L1Algo/L1Utils.h
index bd1b798ab9c0545d14901a3520566f86b9f36bc8..41ad13f8f5ee56ad8ac54a610224beb72dc94f3f 100644
--- a/reco/L1/L1Algo/L1Utils.h
+++ b/reco/L1/L1Algo/L1Utils.h
@@ -26,11 +26,14 @@
 #include "CaSimd.h"
 #include "L1Def.h"
 
+// TODO: SZh 16.05.2023:  Split this class into several headers and place them into L1Algo::utils
+
 
 /// Class contains some utility functions for L1Algo
 namespace L1Utils
 {
   /// NaN value for float
+  // TODO: SZh 16.05.2023: Replace this kNaN with L1Undef::kF
   constexpr float kNaN {std::numeric_limits<float>::signaling_NaN()};
 
   /// Comparison method for floats
diff --git a/reco/L1/L1Algo/utils/CaAlgoRandom.cxx b/reco/L1/L1Algo/utils/CaAlgoRandom.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..218abc50bcf55c1f94163b24d98839360bb867a4
--- /dev/null
+++ b/reco/L1/L1Algo/utils/CaAlgoRandom.cxx
@@ -0,0 +1,34 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// @file   CaAlgoRandom.cxx
+/// @brief  Random generator utility class for CA tracking (implementation)
+/// @since  16.05.2023
+/// @author Sergei Zharko <s.zharko@gsi.de>
+
+#include "CaAlgoRandom.h"
+
+using ca::algo::Random;
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+Random::Random() : Random(1) {}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+Random::Random(int seed) { this->SetSeed(seed); }
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void Random::SetSeed(int seed)
+{
+  if (seed) { fSeed = seed; }
+  else {
+    std::random_device rd;
+    unsigned int randomDeviceSeed = rd();
+    fSeed                         = randomDeviceSeed;
+  }
+  fGenerator.seed(fSeed);
+}
diff --git a/reco/L1/L1Algo/utils/CaAlgoRandom.h b/reco/L1/L1Algo/utils/CaAlgoRandom.h
new file mode 100644
index 0000000000000000000000000000000000000000..a98d18e850e5f3a4237e1a4988807ba711561ebf
--- /dev/null
+++ b/reco/L1/L1Algo/utils/CaAlgoRandom.h
@@ -0,0 +1,94 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// @file    CaAlgoRandom.h
+/// @brief   Random generator utility class for CA tracking
+/// @since   16.05.2023
+/// @authors Sergei Zharko <s.zharko@gsi.de>, Sergey Gorbunov <se.gorbunov@gsi.de>
+
+#ifndef CaAlgoRandom_h
+#define CaAlgoRandom_h 1
+
+#include <cstdint>
+#include <random>
+#include <type_traits>
+
+namespace ca::algo
+{
+  /// @brief A class, providing ROOT-free access to randomly generated variables
+  class Random {
+    using GeneratorType_t = std::mt19937_64;
+
+  public:
+    /// @brief  Default constructor
+    ///
+    /// Sets seed equal to 1
+    Random();
+
+    /// @brief  Constructor
+    /// @param  seed  A random seed
+    ///
+    /// If 0 is selected for the random seed, the generator is seeded with std::random_device
+    Random(int seed);
+
+    /// @brief  Destructor
+    ~Random() = default;
+
+    /// @brief  Copy constructor
+    Random(const Random& other) = delete;
+
+    /// @brief  Move constructor
+    Random(Random&& other) = delete;
+
+    /// @brief  Copy assignment operator
+    Random& operator=(const Random&) = delete;
+
+    /// @brief  Move assignment operator
+    Random& operator=(Random&&) = delete;
+
+    /// @brief  Gets seed of the random generator
+    int GetSeed() const { return fSeed; }
+
+    /// @brief  Sets seed to the random generator
+    /// @param  seed  A random seed
+    ///
+    /// If 0 is selected for the random seed, the generator is seeded with std::random_device
+    void SetSeed(int seed);
+
+    /// @brief  Returns a normally distributed random value, limited within a selected sigma range
+    /// @tparam T        Type of floating point
+    /// @param  mean     Mean of the distribution
+    /// @param  sigma    Sigma of the distribution
+    /// @param  nSigmas  Half-width of the generated numbers domain, expressed in number of sigmas
+    template<typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
+    T BoundedGaus(const T& mean, const T& sigma, const T& nSigmas) const;
+
+  private:
+    mutable GeneratorType_t fGenerator;  ///< Random number generator
+    unsigned int fSeed = 1;              ///< Random number seed
+  };
+}  // namespace ca::algo
+
+
+// *********************************************************
+// **     Template and inline function implementation     **
+// *********************************************************
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+template<typename T, std::enable_if_t<std::is_floating_point<T>::value, bool>>
+T ca::algo::Random::BoundedGaus(const T& mean, const T& sigma, const T& nSigmas) const
+{
+  assert(sigma > 0 && std::isfinite(sigma));
+  assert(nSigmas > 0 && std::isfinite(nSigmas));
+  std::normal_distribution rndGaus {mean, sigma};
+  double res = 0;
+  do {
+    res = rndGaus(fGenerator);
+  } while (std::fabs(res - mean) > nSigmas * sigma);
+  return res;
+}
+
+
+#endif  // CaAlgoRandom_h
diff --git a/reco/L1/L1Algo/utils/L1AlgoEfficiencyPerformance.h b/reco/L1/L1Algo/utils/L1AlgoEfficiencyPerformance.h
index 512d6ce217825b0178ccc4f9148844f67dc288d7..6d767fe1040ac1c4b465a0f4bd879c4af03c6018 100644
--- a/reco/L1/L1Algo/utils/L1AlgoEfficiencyPerformance.h
+++ b/reco/L1/L1Algo/utils/L1AlgoEfficiencyPerformance.h
@@ -224,12 +224,11 @@ bool L1AlgoEfficiencyPerformance<NHits>::AddOne(L1HitIndex_t* iHits)
 
   // obtain mc data
   for (int iih = 0; iih < NHits; iih++) {
-    int nMC = fL1->fvHitDebugInfo[iHits[iih]].mcPointIds.size();
-    for (int iMC = 0; iMC < nMC; iMC++) {
-      const int iMCP = fL1->fvHitDebugInfo[iHits[iih]].mcPointIds[iMC];
+    const int iMCP = fL1->fvHitDebugInfo[iHits[iih]].GetMCPointIndex();
+    if (iMCP > -1) {
       int mcId       = fL1->fvMCPoints[iMCP].ID;
       mcIds[iih].push_back(mcId);
-    }  // for mcPoints
+    }
   }    // for hits
 
   // find all reconstructed track id-s
@@ -250,11 +249,14 @@ bool L1AlgoEfficiencyPerformance<NHits>::AddOne(L1HitIndex_t* iHits)
   }
 
   // use first found // TODO: save all!!!
+  // UPD: SZh 24.05.2023: We save only one point index (the best matched)
   vector<int>& mcsN = mcIds[NHits - 1];
   for (unsigned int i = 0; i < mcsN.size(); i++) {
     if (mcsN[i] >= 0) {
       trlet.mcTrackId = mcsN[i];
-      trlet.iStation  = fL1->fvMCPoints[fL1->fvHitDebugInfo[iHits[0]].mcPointIds[0]].iStation;
+      int iMCP        = fL1->fvHitDebugInfo[iHits[0]].GetMCPointIndex();
+      assert(iMCP > -1);
+      trlet.iStation = fL1->fvMCPoints[fL1->fvHitDebugInfo[iHits[0]].GetMCPointIndex()].iStation;
       break;
     }
   }
diff --git a/reco/L1/L1LinkDef.h b/reco/L1/L1LinkDef.h
index ad9b390b8c78b25641fe023de28ebe4793ff7447..e5d1a2a9478c20f88431791c829bf07ef12bcfc2 100644
--- a/reco/L1/L1LinkDef.h
+++ b/reco/L1/L1LinkDef.h
@@ -35,7 +35,7 @@
 #pragma link C++ class CbmCaInputQaTrd + ;
 #pragma link C++ class CbmCaInputQaTof + ;
 #pragma link C++ enum cbm::ca::ETrackType;
-#pragma link C++ enum L1DetectorID;
+#pragma link C++ enum class L1DetectorID;
 #pragma link C++ class cbm::ca::OutputQa + ;
 #pragma link C++ class ca::tools::WindowFinder + ;
 
diff --git a/reco/L1/catools/CaToolsHitRecord.h b/reco/L1/catools/CaToolsHitRecord.h
new file mode 100644
index 0000000000000000000000000000000000000000..9915a0661b8c7cef1330971d8fc3cee0de335b17
--- /dev/null
+++ b/reco/L1/catools/CaToolsHitRecord.h
@@ -0,0 +1,45 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CbmCaHitRecord.h
+/// \brief  A header for cbm::ca::HitRecord structure
+/// \since  15.05.2023
+/// \author S.Zharko <s.zharko@gsi.de>
+
+#ifndef CbmCaHitRecord_h
+#define CbmCaHitRecord_h 1
+
+#include <cstdint>
+
+namespace ca::tools
+{
+  /// @brief A helper structure to store hits information from different detectors in a uniform manner
+  ///
+  /// @note  This structure is to be used ONLY at the TS/event initialization stage to fill hit arrays of different
+  ///        types.
+  ///
+  struct HitRecord {
+    double fX           = -1.;  ///< x component of hit position [cm]
+    double fY           = -1.;  ///< y component of hit position [cm]
+    double fDx          = -1.;  ///< error of x component of hit position [cm]
+    double fDy          = -1.;  ///< error of y component of hit position [cm]
+    double fDxy         = -1.;  ///< correlation between x and y components [cm]
+    double fU           = -1.;  ///< hit position in direction of front strips [cm]
+    double fV           = -1.;  ///< hit position in direction of back strips [cm]
+    double fDu          = -1.;  ///< hit position error in direction of front strips [cm]
+    double fDv          = -1.;  ///< hit position error in direction of back strips [cm]
+    double fZ           = -1.;  ///< z component of hit position [cm]
+    double fT           = -1.;  ///< time of hit [ns]
+    double fDt          = -1.;  ///< time error of hit [ns]
+    int64_t fDataStream = -1;   ///< Global index of detector module
+    int fPointId        = -1;   ///< index of MC point
+    int fExtId          = -2;   ///< external index of hit
+    int fStaId          = -2;   ///< index of active tracking station
+    int fStripF         = -2;   ///< index of front strip
+    int fStripB         = -2;   ///< index of back strip
+    int fDet            = -2;   ///< detector ID
+  };
+}  // namespace ca::tools
+
+#endif  // CbmCaHitRecord_h
diff --git a/reco/L1/catools/CaToolsMCData.h b/reco/L1/catools/CaToolsMCData.h
index 72c3d95e07ff5d39f9812df18822839dd0c03678..a20946c73b5a94dc8fc05cc5feb10b9622681b54 100644
--- a/reco/L1/catools/CaToolsMCData.h
+++ b/reco/L1/catools/CaToolsMCData.h
@@ -96,15 +96,15 @@ namespace ca::tools
       return std::accumulate(fvNofPointsUsed.cbegin(), fvNofPointsUsed.cbegin() + static_cast<int>(detID), 0);
     }
 
-    /// @brief Gets the first point index for a given detector subsystem
+    /// @brief Gets the next index of point, which is expected being after the last one for a given detector
     /// @param detID  Detector ID
     int GetLastPointIndex(L1DetectorID detID) const
     {
-      return std::accumulate(fvNofPointsUsed.cbegin(), fvNofPointsUsed.cbegin() + static_cast<int>(detID) + 1, 0) - 1;
+      return std::accumulate(fvNofPointsUsed.cbegin(), fvNofPointsUsed.cbegin() + static_cast<int>(detID) + 1, 0);
     }
 
     /// @brief Calculates global index of MC point
-    /// @param  iPointLocal  Local index of MC point
+    /// @param  iPointLocal  Local index of MC psinoint
     /// @param  detID        Detector ID
     ///
     /// The function calculates global external index of MC point as a sum of a given local index and total provided
@@ -114,7 +114,6 @@ namespace ca::tools
       return iPointLocal + std::accumulate(fvNofPointsOrig.cbegin(), fvNofPointsOrig.cbegin() + int(detID), 0);
     }
 
-
     /// Gets number of tracks in this event/TS
     int GetNofTracks() const { return fvTracks.size(); }
 
diff --git a/reco/L1/catools/CaToolsMCPoint.h b/reco/L1/catools/CaToolsMCPoint.h
index 158f35e6e3fb35e7377a718f94ca9bdfb790968e..5b5466dcd2398e78a13079a3e222bb3553b05ef9 100644
--- a/reco/L1/catools/CaToolsMCPoint.h
+++ b/reco/L1/catools/CaToolsMCPoint.h
@@ -62,6 +62,11 @@ namespace ca::tools
     /// @brief Gets MC event ID
     int GetEventId() const { return fLinkKey.fEvent; }
 
+    /// @brief Gets MC external ID
+    /// @note  External ID of a point shifted from the original external ID by the total number of points,
+    ///        produced in the preceding detector subsystems.
+    int GetExternalId() const { return fLinkKey.fIndex; }
+
     /// @brief Gets MC file ID
     int GetFileId() const { return fLinkKey.fFile; }
 
@@ -350,6 +355,7 @@ namespace ca::tools
 
     L1DetectorID fDetectorId;  ///< Detector ID of MC point
 
+    // TODO: SZh 17.05.2023: Check, if there are more then one index can be added
     L1Vector<int> fvHitIndexes {"ca::tools::MCPoint::fvHitIndexes"};  ///< Indexes of hits, assigned to this point
   };
 }  // namespace ca::tools
diff --git a/reco/L1/qa/CbmCaOutputQa.cxx b/reco/L1/qa/CbmCaOutputQa.cxx
index 69f1a33db568823fb803cedd34b75360279eb8d0..f2dc7dab18a7b7c997fdd2326aff5c1e8f9a300f 100644
--- a/reco/L1/qa/CbmCaOutputQa.cxx
+++ b/reco/L1/qa/CbmCaOutputQa.cxx
@@ -29,6 +29,11 @@ using cbm::ca::OutputQa;
 //
 OutputQa::OutputQa(int verbose, bool isMCUsed) : CbmQaTask("CbmCaOutputQa", "caout", verbose, isMCUsed)
 {
+  // Create MC module
+
+  // Create TS reader
+  fpTSReader = std::make_unique<TimeSliceReader>();
+
   // Turn on default track classes
   AddTrackType(ETrackType::kAll);
   AddTrackType(ETrackType::kGhost);
@@ -451,7 +456,7 @@ InitStatus OutputQa::InitDataBranches()
   if (!fpDataManager.get()) { fpDataManager = std::make_shared<L1IODataManager>(); }
 
   // Initialize time slice reader instance
-  if (!fpTSReader.get()) { fpTSReader = std::make_unique<TimeSliceReader>(fTrackingMode); }
+  fpTSReader->SetTrackingMode(fTrackingMode);
   fpTSReader->SetDetector(L1DetectorID::kMvd, fbUseMvd);
   fpTSReader->SetDetector(L1DetectorID::kSts, fbUseSts);
   fpTSReader->SetDetector(L1DetectorID::kMuch, fbUseMuch);
@@ -462,12 +467,11 @@ InitStatus OutputQa::InitDataBranches()
   fpTSReader->RegisterTracksContainer(fvRecoTracks);
   fpTSReader->RegisterQaHitContainer(fvHits);
   fpTSReader->RegisterHitIndexContainer(fvHitIds);
-
   if (!fpTSReader->InitRun()) { return kFATAL; }
 
   // Initialize MC module
   if (IsMCUsed()) {
-    if (!fpMCModule.get()) { fpMCModule = std::make_unique<MCModule>(fVerbose, fPerformanceMode); }
+    fpMCModule = std::make_shared<MCModule>(fVerbose, fPerformanceMode);
     fpMCModule->SetDetector(L1DetectorID::kMvd, fbUseMvd);
     fpMCModule->SetDetector(L1DetectorID::kSts, fbUseSts);
     fpMCModule->SetDetector(L1DetectorID::kMuch, fbUseMuch);
@@ -480,9 +484,9 @@ InitStatus OutputQa::InitDataBranches()
     fpMCModule->RegisterQaHitContainer(fvHits);
     fpMCModule->RegisterParameters(fpParameters);
     fpMCModule->RegisterFirstHitIndexes(fpTSReader->GetHitFirstIndexDet());
-
     if (!fpMCModule->InitRun()) { return kFATAL; }
   }
+
   return kSUCCESS;
 }
 
@@ -730,38 +734,20 @@ InitStatus OutputQa::InitTimeSlice()
   int nHits       = 0;
   int nRecoTracks = 0;
 
-  // Read MC tracks and points
-  if (IsMCUsed()) {
-    fpMCModule->InitEvent(nullptr);
-    nMCPoints = fMCData.GetNofPoints();
-    nMCTracks = fMCData.GetNofTracks();
-  }
 
   // Read reconstructed input
   fpTSReader->InitTimeSlice();
   nHits       = fvHits.size();
   nRecoTracks = fvRecoTracks.size();
 
-  static bool bDo = true;
-  if (bDo) {
-    for (int iP = 0; iP < nMCPoints; ++iP) {
-      const auto& point = fMCData.GetPoint(iP);
-      LOG(info) << iP << ' ' << (int) point.GetDetectorId() << ' ' << point.GetStationId();
-    }
-
-    for (int iH = 0; iH < nHits; ++iH) {
-      const auto& hit = fvHits[iH];
-      LOG(info) << iH << ' ' << (int) hit.GetDetectorType() << ' ' << hit.GetStationId();
-    }
-    bDo = false;
-  }
-
-  for (const auto& hit : fvHits) {
-    assert(hit.GetMCPointIndexes().size() < 2);
-  }
-
   // Match tracks and points
-  if (IsMCUsed()) { fpMCModule->MatchRecoAndMC(); }
+  // Read MC tracks and points
+  if (IsMCUsed()) {
+    fpMCModule->InitEvent(nullptr);
+    nMCPoints = fMCData.GetNofPoints();
+    nMCTracks = fMCData.GetNofTracks();
+    fpMCModule->MatchRecoAndMC();
+  }
 
   LOG_IF(info, fVerbose > 1) << fName << ": Data sample consists of " << nHits << " hits, " << nRecoTracks
                              << " reco tracks, " << nMCTracks << " MC tracks, " << nMCPoints << " MC points";
diff --git a/reco/L1/qa/CbmCaOutputQa.h b/reco/L1/qa/CbmCaOutputQa.h
index 1cc6216224126eb41189fe924c0dd1b9e9bfdea6..e3902ae4ff1e1564cbfd32a4f48c04043c5988bf 100644
--- a/reco/L1/qa/CbmCaOutputQa.h
+++ b/reco/L1/qa/CbmCaOutputQa.h
@@ -154,10 +154,10 @@ namespace cbm::ca
     void SetUseTof(bool flag = true) { fbUseTof = flag; }
 
     /// @brief Sets STS tracking mode
-    void SetStsTrackingMode() { fTrackingMode = ECbmTrackingMode::kSTS; }
+    void SetStsTrackingMode() { fTrackingMode = ECbmCaTrackingMode::kSTS; }
 
     /// @brief Sets mCBM global tracking mode
-    void SetMcbmTrackingMode() { fTrackingMode = ECbmTrackingMode::kMCBM; }
+    void SetMcbmTrackingMode() { fTrackingMode = ECbmCaTrackingMode::kMCBM; }
 
     /// @brief Sets performance mode
     /// @param mode  Performance mode (3 is default: TODO - test)
@@ -232,10 +232,10 @@ namespace cbm::ca
 
     int fPerformanceMode = 3;  ///< Performance mode
 
-    ECbmTrackingMode fTrackingMode = ECbmTrackingMode::kSTS;  ///< Tracking mode
+    ECbmCaTrackingMode fTrackingMode = ECbmCaTrackingMode::kSTS;  ///< Tracking mode
 
     std::unique_ptr<TimeSliceReader> fpTSReader       = nullptr;  ///< Reader of the time slice
-    std::unique_ptr<cbm::ca::MCModule> fpMCModule     = nullptr;  ///< MC module
+    std::shared_ptr<MCModule> fpMCModule              = nullptr;  ///< MC module
     std::shared_ptr<L1IODataManager> fpDataManager    = nullptr;  ///< Data manager
     std::shared_ptr<::ca::tools::Debugger> fpDebugger = nullptr;  ///< Debugger
     std::shared_ptr<L1Parameters> fpParameters        = nullptr;  ///< Tracking parameters object
diff --git a/reco/L1/qa/CbmCaTrackFitQa.h b/reco/L1/qa/CbmCaTrackFitQa.h
index 91686b14eabac1a826719f4fbefd5db0913ede19..051d200ba59d30d7ad47355d48c18fa62ce64666 100644
--- a/reco/L1/qa/CbmCaTrackFitQa.h
+++ b/reco/L1/qa/CbmCaTrackFitQa.h
@@ -183,19 +183,19 @@ namespace cbm::ca
     /// @param weight   Weight
     void FillResAndPull(ETrackParType type, double recoVal, double recoErr, double trueVal, double w);
 
-    TrackParArray_t<TH1F*> fvphResiduals = {0};  ///< Residuals for different track parameters
-    TrackParArray_t<TH1F*> fvphPulls     = {0};  ///< Pulls for different track parameters
+    TrackParArray_t<TH1F*> fvphResiduals = {{0}};  ///< Residuals for different track parameters
+    TrackParArray_t<TH1F*> fvphPulls     = {{0}};  ///< Pulls for different track parameters
 
-    TrackParArray_t<bool> fvbParIgnored = {0};  ///< Flag: true - parameter is ignored
+    TrackParArray_t<bool> fvbParIgnored = {{0}};  ///< Flag: true - parameter is ignored
 
     // ** Distribution properties **
-    TrackParArray_t<int> fvRBins  = {0};  ///< Number of bins, residuals
-    TrackParArray_t<double> fvRLo = {0};  ///< Lower boundary, residuals
-    TrackParArray_t<double> fvRUp = {0};  ///< Upper boundary, residuals
+    TrackParArray_t<int> fvRBins  = {{0}};  ///< Number of bins, residuals
+    TrackParArray_t<double> fvRLo = {{0}};  ///< Lower boundary, residuals
+    TrackParArray_t<double> fvRUp = {{0}};  ///< Upper boundary, residuals
 
-    TrackParArray_t<int> fvPBins  = {0};  ///< Number of bins, pulls
-    TrackParArray_t<double> fvPLo = {0};  ///< Lower boundary, pulls
-    TrackParArray_t<double> fvPUp = {0};  ///< Upper boundary, pulls
+    TrackParArray_t<int> fvPBins  = {{0}};  ///< Number of bins, pulls
+    TrackParArray_t<double> fvPLo = {{0}};  ///< Lower boundary, pulls
+    TrackParArray_t<double> fvPUp = {{0}};  ///< Upper boundary, pulls
 
     TString fsTitle = "";  ///< Title of the point