From 4cf611f93a97f35f6d6970133b681ce8c1f676c4 Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Fri, 15 Mar 2024 18:09:26 +0100
Subject: [PATCH] CA online: bugfix in Nhitkeys for TOF; updates

---
 algo/ca/TrackingChain.cxx               | 10 ++--
 algo/ca/core/pars/CaStation.cxx         |  4 +-
 algo/ca/core/tracking/CaTrackFinder.cxx | 72 +++++++++++++++++--------
 algo/ca/core/utils/CaMonitor.h          |  2 +-
 algo/ca/core/utils/CaTrackingMonitor.h  | 21 +++++++-
 algo/ca/qa/CaInputQa.cxx                | 21 +++++++-
 algo/ca/qa/CaInputQa.h                  |  4 +-
 reco/L1/L1LinkDef.h                     |  4 +-
 8 files changed, 103 insertions(+), 35 deletions(-)

diff --git a/algo/ca/TrackingChain.cxx b/algo/ca/TrackingChain.cxx
index 17bfefa3ff..ad5673eda2 100644
--- a/algo/ca/TrackingChain.cxx
+++ b/algo/ca/TrackingChain.cxx
@@ -176,10 +176,10 @@ TrackingChain::Output_t TrackingChain::PrepareOutput()
 
   if (fOutputQa.IsSenderDefined()) {
     fCaMonitorData.StartTimer(ca::ETimer::OutputQa);
-    fQaBuilder.RegisterInputData(&fCaFramework.GetInputData());
-    fQaBuilder.RegisterTracks(&output.tracks);
-    fQaBuilder.RegisterRecoHitIndices(&fCaFramework.fRecoHits);
-    fQaBuilder.Build();
+    fOutputQa.RegisterInputData(&fCaFramework.GetInputData());
+    fOutputQa.RegisterTracks(&output.tracks);
+    fOutputQa.RegisterRecoHitIndices(&fCaFramework.fRecoHits);
+    fOutputQa.Exec();
     fCaMonitorData.StopTimer(ca::ETimer::OutputQa);
   }
 
@@ -253,7 +253,7 @@ void TrackingChain::ReadHits(PartitionedSpan<const ca::HitTypes_t::at<DetID>> hi
         //L_(info) << ", hit="  << iHitExt << ", f=" << hit.fFrontClusterId << ", b=" << hit.fBackClusterId;
       }
       else {
-        caHit.SetFrontKey(firstHitKey + iHitExt);
+        caHit.SetFrontKey(firstHitKey + iPartHit);
         caHit.SetBackKey(caHit.FrontKey());
       }
       caHit.SetX(hit.X());
diff --git a/algo/ca/core/pars/CaStation.cxx b/algo/ca/core/pars/CaStation.cxx
index 254ffc44ac..9092cc24b4 100644
--- a/algo/ca/core/pars/CaStation.cxx
+++ b/algo/ca/core/pars/CaStation.cxx
@@ -85,8 +85,8 @@ std::string Station<DataT>::ToString(int verbosityLevel, int indentLevel, bool i
       msg << std::setw(columnSize) << std::setfill(' ') << "time status" << ' ';
       msg << std::setw(columnSize) << std::setfill(' ') << "field status" << ' ';
       msg << std::setw(columnSize) << std::setfill(' ') << "z [cm]" << ' ';
-      msg << std::setw(columnSize) << std::setfill(' ') << "Ymax [cm]" << ' ';
-      msg << std::setw(columnSize) << std::setfill(' ') << "Xmax [cm]";
+      msg << std::setw(columnSize) << std::setfill(' ') << "Xmax [cm]" << ' ';
+      msg << std::setw(columnSize) << std::setfill(' ') << "Ymax [cm]";
     }
     else {
       msg << indent;
diff --git a/algo/ca/core/tracking/CaTrackFinder.cxx b/algo/ca/core/tracking/CaTrackFinder.cxx
index cc3ce2f231..10b13bf4a8 100644
--- a/algo/ca/core/tracking/CaTrackFinder.cxx
+++ b/algo/ca/core/tracking/CaTrackFinder.cxx
@@ -56,24 +56,13 @@ void TrackFinder::FindTracks()
   auto timerStart = std::chrono::high_resolution_clock::now();
 
   frAlgo.fMonitorData.StartTimer(ETimer::PrepareDataStreams);
+  auto& wDataThread0 = frAlgo.fvWData[0];  // NOTE: Thread 0 must be always defined
 
   // ----- Reset data arrays -------------------------------------------------------------------------------------------
-  size_t nHitsExpected   = 2 * frAlgo.fInputData.GetNhits();
-  size_t nTracksExpected = 2 * frAlgo.fInputData.GetNhits() / frAlgo.GetParameters().GetNstationsActive();
 
-  for (int iThread = 0; iThread < frAlgo.GetNofThreads(); ++iThread) {
-    fvRecoTracks[iThread].clear();
-    fvRecoTracks[iThread].reserve(nTracksExpected / frAlgo.GetNofThreads());
-    fvRecoHitIndices[iThread].clear();
-    fvRecoHitIndices[iThread].reserve(nHitsExpected / frAlgo.GetNofThreads());
-    frAlgo.fvTrackFinderWindow[iThread].InitTimeslice();
-    auto& wData = frAlgo.fvWData[iThread];
-    wData.HitKeyFlags().reset(frAlgo.fInputData.GetNhitKeys(), 0);
-    for (int iS = 0; iS < frAlgo.GetParameters().GetNstationsActive(); ++iS) {
-      wData.TsHitIndices(iS).clear();
-      wData.TsHitIndices(iS).reserve(frAlgo.fInputData.GetNhits());
-    }
-  }
+  frAlgo.fvMonitorDataThread[0].StartTimer(ETimer::PrepareDataStreams4);
+  wDataThread0.HitKeyFlags().reset(frAlgo.fInputData.GetNhitKeys(), 0);
+  frAlgo.fvMonitorDataThread[0].StopTimer(ETimer::PrepareDataStreams4);
 
   frAlgo.fHitTimeInfo.reset(frAlgo.fInputData.GetNhits());
 
@@ -95,7 +84,6 @@ void TrackFinder::FindTracks()
 
   const int nDataStreams = frAlgo.fInputData.GetNdataStreams();
 
-  auto& wDataThread0 = frAlgo.fvWData[0];  // NOTE: Thread 0 must be always defined
   for (int iStream = 0; iStream < nDataStreams; ++iStream) {
 
     fscal maxTimeBeforeHit = std::numeric_limits<fscal>::lowest();
@@ -132,12 +120,10 @@ void TrackFinder::FindTracks()
         info.fEventTimeMax = 1.e10;
       }
 
+      // NOTE: if not a MT part, use wDataThread0.IsHitKeyUsed, it will be later copied to other threads
       if (info.fEventTimeMin > 500.e6 || info.fEventTimeMax < -500.) {  // cut hits with bogus start time > 500 ms
-        for (int iThread = 0; iThread < frAlgo.GetNofThreads(); ++iThread) {
-          auto& wData                      = frAlgo.fvWData[iThread];
-          wData.IsHitKeyUsed(h.FrontKey()) = 1;
-          wData.IsHitKeyUsed(h.BackKey())  = 1;
-        }
+        wDataThread0.IsHitKeyUsed(h.FrontKey()) = 1;
+        wDataThread0.IsHitKeyUsed(h.BackKey())  = 1;
         LOG(error) << "CATrackFinder: skip bogus hit " << h.ToString();
         continue;
       }
@@ -224,8 +210,10 @@ void TrackFinder::FindTracks()
   frAlgo.fRecoHits.clear();
   if (frAlgo.GetNofThreads() == 1) {
     this->FindTracksThread(0);
+    frAlgo.fMonitorData.StartTimer(ETimer::PrepareOutput);
     frAlgo.fRecoTracks = std::move(fvRecoTracks[0]);
     frAlgo.fRecoHits   = std::move(fvRecoHitIndices[0]);
+    frAlgo.fMonitorData.StopTimer(ETimer::PrepareOutput);
   }
   else {
     std::vector<std::thread> vThreadList;
@@ -238,6 +226,7 @@ void TrackFinder::FindTracks()
         th.join();
       }
     }
+    frAlgo.fMonitorData.StartTimer(ETimer::PrepareOutput);
     auto Operation  = [](size_t acc, const auto& v) { return acc + v.size(); };
     int nRecoTracks = std::accumulate(fvRecoTracks.begin(), fvRecoTracks.end(), 0, Operation);
     int nRecoHits   = std::accumulate(fvRecoHitIndices.begin(), fvRecoHitIndices.end(), 0, Operation);
@@ -247,6 +236,7 @@ void TrackFinder::FindTracks()
       frAlgo.fRecoTracks.insert(frAlgo.fRecoTracks.end(), fvRecoTracks[iTh].begin(), fvRecoTracks[iTh].end());
       frAlgo.fRecoHits.insert(frAlgo.fRecoHits.end(), fvRecoHitIndices[iTh].begin(), fvRecoHitIndices[iTh].end());
     }
+    frAlgo.fMonitorData.StopTimer(ETimer::PrepareOutput);
   }
 
   frAlgo.fMonitorData.StopTimer(ETimer::FindTracks);
@@ -286,11 +276,49 @@ void TrackFinder::FindTracksThread(int iThread)
   LOG(info) << "---- CA: searching for tracks on thread " << iThread;
   frAlgo.fvMonitorDataThread[iThread].StartTimer(ETimer::FindTracksThread);
 
+  // Init vectors
+  auto& wData = frAlgo.fvWData[iThread];
+  {
+    int nStations          = frAlgo.GetParameters().GetNstationsActive();
+    size_t nHitsTot        = frAlgo.fInputData.GetNhits();
+    size_t nHitKeys        = frAlgo.fInputData.GetNhitKeys();
+    size_t nHitsExpected   = 2 * nHitsTot;
+    size_t nTracksExpected = 2 * nHitsTot / nStations;
+    size_t nThreads        = frAlgo.GetNofThreads();
+    frAlgo.fvMonitorDataThread[iThread].StartTimer(ETimer::PrepareDataStreams1);
+    fvRecoTracks[iThread].clear();
+    fvRecoTracks[iThread].reserve(nTracksExpected / nThreads);
+    frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::PrepareDataStreams1);
+    frAlgo.fvMonitorDataThread[iThread].StartTimer(ETimer::PrepareDataStreams2);
+    fvRecoHitIndices[iThread].clear();
+    fvRecoHitIndices[iThread].reserve(nHitsExpected / nThreads);
+    frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::PrepareDataStreams2);
+    frAlgo.fvMonitorDataThread[iThread].StartTimer(ETimer::PrepareDataStreams3);
+    frAlgo.fvTrackFinderWindow[iThread].InitTimeslice();
+    frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::PrepareDataStreams3);
+    if (iThread != 0) {
+      auto& wData0 = frAlgo.fvWData[0];
+      frAlgo.fvMonitorDataThread[iThread].StartTimer(ETimer::PrepareDataStreams4);
+      // slow ...
+      wData.HitKeyFlags().clear();
+      wData.HitKeyFlags().reserve(nHitKeys);
+      for (const auto& flag : wData0.HitKeyFlags()) {
+        wData.HitKeyFlags().emplace_back(flag);
+      }
+      frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::PrepareDataStreams4);
+    }
+    frAlgo.fvMonitorDataThread[iThread].StartTimer(ETimer::PrepareDataStreams5);
+    for (int iS = 0; iS < nStations; ++iS) {
+      wData.TsHitIndices(iS).clear();
+      wData.TsHitIndices(iS).reserve(nHitsTot);
+    }
+    frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::PrepareDataStreams5);
+  }
+
   const int nDataStreams    = frAlgo.fInputData.GetNdataStreams();
   bool areUntouchedDataLeft = true;  // is the whole TS processed
   std::vector<HitIndex_t> sliceFirstHit(nDataStreams, 0);
   std::vector<HitIndex_t> sliceLastHit(nDataStreams, 0);
-  auto& wData = frAlgo.fvWData[iThread];
 
   // Define first hit, skip all the hits, which are before the first window
   for (int iStream = 0; iStream < nDataStreams; ++iStream) {
diff --git a/algo/ca/core/utils/CaMonitor.h b/algo/ca/core/utils/CaMonitor.h
index 79dde7560b..32fe600c7d 100644
--- a/algo/ca/core/utils/CaMonitor.h
+++ b/algo/ca/core/utils/CaMonitor.h
@@ -84,7 +84,7 @@ namespace cbm::algo::ca
 
     /// \brief Gets timer
     /// \param key Timer key
-    const Timer& GetTimer(ETimerKey /*key*/) const { return fMonitorData.GetTimer(); }
+    const Timer& GetTimer(ETimerKey key) const { return fMonitorData.GetTimer(key); }
 
     /// \brief Gets timer name
     /// \param key Timer key
diff --git a/algo/ca/core/utils/CaTrackingMonitor.h b/algo/ca/core/utils/CaTrackingMonitor.h
index 0981f0e019..2af786c5cb 100644
--- a/algo/ca/core/utils/CaTrackingMonitor.h
+++ b/algo/ca/core/utils/CaTrackingMonitor.h
@@ -7,7 +7,12 @@
 /// \since  19.10.2023
 /// \author S.Zharko <s.zharko@gsi.de>
 
-#pragma once
+// NOTE: SZh: #prama once does not work properly in ROOT macros, so to use there enums from the header one
+//            have to use old approach to protect from multiple includes
+//#pragma once
+
+#ifndef CaTrackingMonitor_h
+#define CaTrackingMonitor_h 1
 
 #include "CaMonitor.h"
 
@@ -47,12 +52,18 @@ namespace cbm::algo::ca
     PrepareInput,
     FindTracks,
     PrepareDataStreams,
+    PrepareDataStreams1,
+    PrepareDataStreams2,
+    PrepareDataStreams3,
+    PrepareDataStreams4,
+    PrepareDataStreams5,
     FindTracksThread,
     PrepareHitsWindow,
     TrackFinderWindow,
     TrackFitterWindow,
     CloneMergerWindow,
     StoreTracksWindow,
+    PrepareOutput,
     TripletConstructionWindow,
     NeighboringTripletSearchWindow,
     //InputQa,
@@ -87,8 +98,14 @@ namespace cbm::algo::ca
       SetCounterName(ECounter::UndefinedTofHit, "undefined_TOF_hits");
       //SetTimerName(ETimer::Tracking, "full_tracking");
       SetTimerName(ETimer::PrepareInput, "input_data_initialization");
+      SetTimerName(ETimer::PrepareOutput, "int._output_data_initialization");
       SetTimerName(ETimer::FindTracks, "find_tracks_procedure");
       SetTimerName(ETimer::PrepareDataStreams, "data_streams_preparation");
+      SetTimerName(ETimer::PrepareDataStreams1, "data_streams_preparation_(1)");
+      SetTimerName(ETimer::PrepareDataStreams2, "data_streams_preparation_(2)");
+      SetTimerName(ETimer::PrepareDataStreams3, "data_streams_preparation_(3)");
+      SetTimerName(ETimer::PrepareDataStreams4, "data_streams_preparation_(4)");
+      SetTimerName(ETimer::PrepareDataStreams5, "data_streams_preparation_(5)");
       SetTimerName(ETimer::FindTracksThread, "find_tracks_on_thread");
       SetTimerName(ETimer::PrepareHitsWindow, "hit_preparation_in_window");
       SetTimerName(ETimer::TrackFinderWindow, "track_finder_in_window");
@@ -111,3 +128,5 @@ namespace cbm::algo::ca
   };
 
 }  // namespace cbm::algo::ca
+
+#endif
diff --git a/algo/ca/qa/CaInputQa.cxx b/algo/ca/qa/CaInputQa.cxx
index c63cb0cea9..a5f55575ee 100644
--- a/algo/ca/qa/CaInputQa.cxx
+++ b/algo/ca/qa/CaInputQa.cxx
@@ -122,7 +122,21 @@ void InputQa::Init()
         fQaData.MakeObj<Prof2D>(name, titl, nBinsXY, vMinX[iSt], vMaxX[iSt], nBinsXY, vMinY[iSt], vMaxY[iSt], 0., 1.);
     }
   }
-
+  for (auto hitSet : kHitSets) {
+    constexpr int NBins = 1000000;
+    auto setNm          = EHitSet::Input == hitSet ? "input" : "used";
+    auto setTl          = EHitSet::Input == hitSet ? "Input" : "Used";
+    {
+      auto name                    = format("hit_{}_front_key_index", setNm);
+      auto titl                    = format("{} hit front key index;ID_{{key}}/N_{{keys}};Count", setTl);
+      fvphHitFrontKeyIndex[hitSet] = fQaData.MakeObj<H1D>(name, titl, NBins, 0., 1.);
+    }
+    {
+      auto name                   = format("hit_{}_back_key_index", setNm);
+      auto titl                   = format("{} hit back key index;ID_{{key}}/N_{{keys}};Count", setTl);
+      fvphHitBackKeyIndex[hitSet] = fQaData.MakeObj<H1D>(name, titl, NBins, 0., 1.);
+    }
+  }
 
   // ----- Init canvases
   // Hit occupancies
@@ -190,7 +204,7 @@ void InputQa::Exec()
     assert(false);
   }
 
-  int nHitsInput = fpInputData->GetHits().size();
+  int nHitsInput = fpInputData->GetNhits();
   // Map: if hit used in tracking
   std::vector<unsigned char> vbHitUsed(nHitsInput, false);
   for (int iH : (*fpvRecoHits)) {
@@ -226,4 +240,7 @@ void InputQa::FillHitDistributionsForHitSet(InputQa::EHitSet hitSet, const Hit&
   fvphHitOccupXY[iSt][hitSet]->Fill(x, y);
   fvphHitOccupZX[iSt][hitSet]->Fill(z, x);
   fvphHitOccupZY[iSt][hitSet]->Fill(z, y);
+  auto nKeys = static_cast<double>(fpInputData->GetNhitKeys());
+  fvphHitFrontKeyIndex[hitSet]->Fill(hit.FrontKey() / nKeys);
+  fvphHitBackKeyIndex[hitSet]->Fill(hit.BackKey() / nKeys);
 }
diff --git a/algo/ca/qa/CaInputQa.h b/algo/ca/qa/CaInputQa.h
index 47b355395c..96bb7bdbb1 100644
--- a/algo/ca/qa/CaInputQa.h
+++ b/algo/ca/qa/CaInputQa.h
@@ -69,7 +69,6 @@ namespace cbm::algo::ca
     /// \param  hit     Reference to hit
     void FillHitDistributionsForHitSet(EHitSet hitSet, const ca::Hit& hit);
 
-
     static constexpr double kXYZMargin = 0.05;  ///< Margin for occupancy distributions in XY plane
     static constexpr int knHitSets     = 2;     ///< Number of hit sets: input/used
 
@@ -80,5 +79,8 @@ namespace cbm::algo::ca
     OccupHistContainer_t fvphHitOccupZY;  ///< hist: Hit occupancy in different stations in ZY plane
 
     std::vector<qa::Prof2D*> fvphHitUsageXY;  ///< prof: Hit usage in different stations in XY plane
+
+    HitSetArray_t<qa::H1D*> fvphHitFrontKeyIndex = {nullptr, nullptr};  ///< Indices of front hit keys
+    HitSetArray_t<qa::H1D*> fvphHitBackKeyIndex  = {nullptr, nullptr};  ///< Indices of back hit keys
   };
 }  // namespace cbm::algo::ca
diff --git a/reco/L1/L1LinkDef.h b/reco/L1/L1LinkDef.h
index 17d90b2a46..27191282ad 100644
--- a/reco/L1/L1LinkDef.h
+++ b/reco/L1/L1LinkDef.h
@@ -10,6 +10,9 @@
 #pragma link off all classes;
 #pragma link off all functions;
 
+#pragma link C++ enum class cbm::algo::ca::ETimer;
+#pragma link C++ enum class cbm::algo::ca::ECounter;
+#pragma link C++ enum class cbm::algo::ca::EDetectorID;
 #pragma link C++ class cbm::algo::ca::TrackingMonitor - ;
 #pragma link C++ class CbmTrackingDetectorInterfaceInit + ;
 #pragma link C++ class CbmL1 + ;
@@ -32,7 +35,6 @@
 #pragma link C++ class CbmCaInputQaTrd + ;
 #pragma link C++ class CbmCaInputQaTof + ;
 #pragma link C++ enum cbm::ca::ETrackType;
-#pragma link C++ enum class cbm::algo::ca::EDetectorID;
 #pragma link C++ class cbm::ca::OutputQa + ;
 #pragma link C++ class cbm::ca::tools::WindowFinder + ;
 //#pragma link C++ class cbm::ca::IdealHitProducer < L1DetectorID::kMvd > + ;
-- 
GitLab