From 42ffbe9daa48df2436dad71a05a582f9aa3987a8 Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Thu, 12 Sep 2024 16:17:26 +0200
Subject: [PATCH] Index map for kf-setup

---
 algo/ca/core/pars/CaInitManager.cxx          |   2 +-
 algo/kf/core/CMakeLists.txt                  |   1 +
 algo/kf/core/KfDefs.h                        |   3 +
 algo/kf/core/geo/KfField.h                   |   5 +
 reco/L1/CbmCaMCModule.cxx                    |   2 +-
 reco/L1/CbmCaTimeSliceReader.cxx             |   4 +-
 reco/L1/CbmKfTrackingSetupInitializer.cxx    | 195 +++++++++++++++++++
 reco/L1/CbmKfTrackingSetupInitializer.h      |  53 +++++
 reco/L1/CbmL1.cxx                            |   4 +-
 reco/L1/CbmL1.h                              |   2 +-
 reco/L1/CbmL1DetectorID.h                    |  18 +-
 reco/L1/CbmL1Util.cxx                        |   2 +-
 reco/L1/CbmL1Util.h                          |   2 +-
 reco/L1/qa/CbmCaInputQaSetup.cxx             |   6 +-
 reco/L1/qa/CbmCaTrackFitQa.h                 |   3 +
 reco/L1/utils/CbmCaIdealHitProducerDet.h     |   4 +-
 reco/kfnew/CbmKfTrackingSetupInitializer.cxx |  41 ++--
 reco/kfnew/CbmKfTrackingSetupInitializer.h   |  15 ++
 18 files changed, 321 insertions(+), 41 deletions(-)
 create mode 100644 reco/L1/CbmKfTrackingSetupInitializer.cxx
 create mode 100644 reco/L1/CbmKfTrackingSetupInitializer.h

diff --git a/algo/ca/core/pars/CaInitManager.cxx b/algo/ca/core/pars/CaInitManager.cxx
index b19b370ed2..703ca67540 100644
--- a/algo/ca/core/pars/CaInitManager.cxx
+++ b/algo/ca/core/pars/CaInitManager.cxx
@@ -243,7 +243,7 @@ void InitManager::InitStationLayout()
   for (const auto& aStation : fvStationInfo) {
     ++fParameters.fvFirstGeoId[static_cast<int>(aStation.GetDetectorID()) + 1];
   }
-  for (int iDet = 1; iDet < static_cast<int>(fParameters.fvFirstGeoId.size()); ++iDet) {
+  for (int iDet = 1; iDet < static_cast<int>(fParameters.fvFirstGeoId.size()) - 1; ++iDet) {
     fParameters.fvFirstGeoId[iDet + 1] += fParameters.fvFirstGeoId[iDet];
   }
 
diff --git a/algo/kf/core/CMakeLists.txt b/algo/kf/core/CMakeLists.txt
index d818b5fb71..7ee3882d8f 100644
--- a/algo/kf/core/CMakeLists.txt
+++ b/algo/kf/core/CMakeLists.txt
@@ -108,6 +108,7 @@ install(
     geo/KfFieldSlice.h
     geo/KfFieldValue.h
     geo/KfMaterialMap.h 
+    geo/KfModuleIndexMap.h 
     geo/KfSetup.h
     geo/KfSetupInitializer.h
     geo/KfTarget.h
diff --git a/algo/kf/core/KfDefs.h b/algo/kf/core/KfDefs.h
index a71a871d19..efd12d4c76 100644
--- a/algo/kf/core/KfDefs.h
+++ b/algo/kf/core/KfDefs.h
@@ -71,6 +71,9 @@ namespace cbm::algo::kf::defs
   // ----- Array sizes -------------------------------------------------------------------------------------------------
   //constexpr int MaxNofFieldSlices    = 64;  ///< Max number of field slices
   //constexpr int MaxNofMaterialLayers = 32;  ///< Max number of the material layers
+  // NOTE: max uint8_t is assumed in order to satisfy fles::Subsystem
+  constexpr int MaxNofDetSubsystems = 256;    ///< Max number of detector types (STS, TRD, RICH,...)
+  constexpr int MaxNofDetComponents = 128;    ///< Max number of detector components (stations, layers, ...)
 
   // ----- Control -----------------------------------------------------------------------------------------------------
   constexpr int DebugLvl     = 0;     ///< Level of debug output
diff --git a/algo/kf/core/geo/KfField.h b/algo/kf/core/geo/KfField.h
index e1227faa5a..680f2587c7 100644
--- a/algo/kf/core/geo/KfField.h
+++ b/algo/kf/core/geo/KfField.h
@@ -140,6 +140,10 @@ namespace cbm::algo::kf
       /// \param fieldSlice  Field slice object
       void AddFieldSlice(const FieldSlice<T>& fieldSlice) { fvFieldSlices.push_back(fieldSlice); }
 
+      /// \brief Gets field slice
+      /// \param sliceID  Index of slice
+      const auto& GetFieldSlice(int sliceID) const { return fvFieldSlices[sliceID]; }
+
       /// \brief Creates field value object
       /// \param sliceID  Index of slice
       /// \param x        x-coordinate of the point [cm]
@@ -152,6 +156,7 @@ namespace cbm::algo::kf
       /// \brief Gets number of field slices in the instance
       int GetNofFieldSlices() const { return fvFieldSlices.size(); }
 
+
       /// \brief Creates field region object
       /// \brief fldType  FieldType
       /// \param b0  Field value in the first node [kG]
diff --git a/reco/L1/CbmCaMCModule.cxx b/reco/L1/CbmCaMCModule.cxx
index 3c458329d2..0c3859c2c0 100644
--- a/reco/L1/CbmCaMCModule.cxx
+++ b/reco/L1/CbmCaMCModule.cxx
@@ -385,7 +385,7 @@ void MCModule::CheckInit() const
   }
 
   // Check detectors initialization
-  for (int iD = 0; iD < static_cast<int>(ca::EDetectorID::kEND); ++iD) {
+  for (int iD = 0; iD < static_cast<int>(ca::EDetectorID::END); ++iD) {
     if (fvbUseDet[iD]) {
       if (!fvpBrPoints[iD]) {
         throw std::logic_error(Form("MC points are unavailable for %s", kDetName[iD]));
diff --git a/reco/L1/CbmCaTimeSliceReader.cxx b/reco/L1/CbmCaTimeSliceReader.cxx
index ca37e5da0b..bd367294c2 100644
--- a/reco/L1/CbmCaTimeSliceReader.cxx
+++ b/reco/L1/CbmCaTimeSliceReader.cxx
@@ -80,7 +80,7 @@ void TimeSliceReader::CheckInit() const
   //throw std::logic_error("Time slice branch is unavailable");
   //}
 
-  for (int iDet = 0; iDet < static_cast<int>(ca::EDetectorID::kEND); ++iDet) {
+  for (int iDet = 0; iDet < static_cast<int>(ca::EDetectorID::END); ++iDet) {
     if (fvbUseDet[iDet] && !fvpBrHits[iDet]) {
       throw std::logic_error(std::string(kDetName[iDet]) + " hits branch is not found");
     }
@@ -474,7 +474,7 @@ void TimeSliceReader::ReadHits()
   fFirstHitKey = 0;
 
   // TODO: Address case with CbmEvent != nullptr
-  for (int iDet = 0; iDet < static_cast<int>(ca::EDetectorID::kEND); ++iDet) {
+  for (int iDet = 0; iDet < static_cast<int>(ca::EDetectorID::END); ++iDet) {
     if (fvbUseDet[iDet]) {
       fvNofHitsTotal[iDet] = fpEvent ? fpEvent->GetNofData(kCbmHitType[iDet]) : fvpBrHits[iDet]->GetEntriesFast();
     }
diff --git a/reco/L1/CbmKfTrackingSetupInitializer.cxx b/reco/L1/CbmKfTrackingSetupInitializer.cxx
new file mode 100644
index 0000000000..9650ac1588
--- /dev/null
+++ b/reco/L1/CbmKfTrackingSetupInitializer.cxx
@@ -0,0 +1,195 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CbmKfTrackingSetupInitializer.cxx
+/// \brief  Tracking setup initializer in CBM (source)
+/// \since  28.08.2024
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+#include "CbmKfTrackingSetupInitializer.h"
+
+#include "CbmKfOriginalField.h"
+#include "CbmKfTarget.h"
+#include "CbmMuchTrackingInterface.h"
+#include "CbmMvdTrackingInterface.h"
+#include "CbmSetup.h"
+#include "CbmStsTrackingInterface.h"
+#include "CbmTofTrackingInterface.h"
+#include "CbmTrdTrackingInterface.h"
+#include "FairField.h"
+#include "FairRunAna.h"
+#include "KfDefs.h"
+#include "KfMaterialMapCreator.h"
+#include "Logger.h"
+
+#include <functional>
+
+using cbm::kf::TrackingSetupInitializer;
+using kf::tools::MaterialMapCreator;
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+bool TrackingSetupInitializer::InitProperties()
+try {
+  using cbm::algo::kf::EFieldType;
+
+  // Check, if a subsystem exists in the setup
+  fbUseMvd &= CbmSetup::Instance()->IsActive(ECbmModuleId::kMvd);
+  fbUseSts &= CbmSetup::Instance()->IsActive(ECbmModuleId::kSts);
+  fbUseMuch &= CbmSetup::Instance()->IsActive(ECbmModuleId::kMuch);
+  fbUseTrd &= CbmSetup::Instance()->IsActive(ECbmModuleId::kTrd);
+  fbUseTof &= CbmSetup::Instance()->IsActive(ECbmModuleId::kTof);
+
+  // Magnetic field initialization
+  if (FairRunAna::Instance()->GetField()) {
+    this->SetFieldFunction(OriginalField(), EFieldType::Normal);
+  }
+  else {
+    //this->SetFieldFunction(cbm::algo::kf::defs::ZeroFieldFn, EFieldType::Null);
+    this->SetFieldFunction(ZeroField(), EFieldType::Null);
+  }
+
+  // Tracking station property initialization
+  {
+    // Geometrical layer (contains information on the station sizes)
+    //
+    struct GeoLayer {
+      double zRef;  // Reference z-coordinate [cm]
+      double zMin;  // Lower z-coordinate boundary [cm]
+      double zMax;  // Upper z-coordinate boundary [cm]
+      double xMax;  // Half size of the layer in the x-direction [cm]
+      double yMax;  // Half size of the layer in the y-direction [cm]
+      bool operator<(const GeoLayer& rhs) const { return zRef < rhs.zRef; }
+    };
+    std::set<GeoLayer> geoStations;
+
+    auto CollectStations = [&](const auto* pIfs) -> void {
+      if (!pIfs) {
+        return;
+      }
+      for (int iSt = 0; iSt < pIfs->GetNtrackingStations(); ++iSt) {
+        geoStations.emplace(GeoLayer{.zRef = pIfs->GetZref(iSt),
+                                     .zMin = pIfs->GetZmin(iSt),
+                                     .zMax = pIfs->GetZmax(iSt),
+                                     .xMax = std::max(std::fabs(pIfs->GetXmin(iSt)), std::fabs(pIfs->GetXmax(iSt))),
+                                     .yMax = std::max(std::fabs(pIfs->GetYmin(iSt)), std::fabs(pIfs->GetYmax(iSt)))});
+      }
+    };
+    CollectStations(fbUseMvd ? CbmMvdTrackingInterface::Instance() : nullptr);
+    CollectStations(fbUseSts ? CbmStsTrackingInterface::Instance() : nullptr);
+    CollectStations(fbUseMuch ? CbmMuchTrackingInterface::Instance() : nullptr);
+    CollectStations(fbUseTrd ? CbmTrdTrackingInterface::Instance() : nullptr);
+    CollectStations(fbUseTof ? CbmTofTrackingInterface::Instance() : nullptr);
+
+    // Retriev target properties
+    const auto* pTarget = Target::Instance();
+
+    // Init material map creator
+    MaterialMapCreator materialCreator{};
+    materialCreator.SetSafeMaterialInitialization(kMatCreatorSafeMode);
+    materialCreator.SetDoRadialProjection(pTarget->GetZ());
+    materialCreator.SetNraysPerDim(kMatCreatorNrays);
+
+    // Target initialization
+    double zLast =
+      pTarget->GetZ() + pTarget->GetDz() + kTargMaterialOffset;  // z-coordinate of the target material upper limit
+    {
+      // Material of the target
+      double xyMax{1.3 * pTarget->GetRmax()};
+      int nBins{std::min(static_cast<int>(std::ceil(2. * xyMax / kMatCreatorPitch)), kMatCreatorMaxNbins)};
+      assert(nBins > 0);
+      double zFirst{pTarget->GetZ() - pTarget->GetDz()};  // z-coordinate of the target material lower limit
+      LOG(info) << "- collecting target material (z = " << zFirst << " - " << zLast << ", size = " << xyMax << ")\n";
+      this->SetTargetProperties(pTarget->GetX(), pTarget->GetY(), pTarget->GetZ(), kTargFieldInitStep,
+                                materialCreator.GenerateMaterialMap(pTarget->GetZ(), zFirst, zLast, xyMax, nBins));
+    }
+
+    // Material and field layers initialization
+
+    for (const auto& layer : geoStations) {
+      LOG(info) << " >>>>> LAYER >>>>> " << layer.zRef;
+    }
+
+    for (auto layerIt = geoStations.begin(); layerIt != geoStations.end(); ++layerIt) {
+      double z1 = layerIt->zMax;
+      double z2 = z1;
+      if (std::next(layerIt) != geoStations.end()) {
+        z2 = std::next(layerIt)->zMin;
+      }
+      double zNew  = 0.5 * (z1 + z2);
+      double xyMax = 1.3 * std::max(std::fabs(layerIt->xMax), std::fabs(layerIt->yMax));
+      int nBins    = std::min(static_cast<int>(std::ceil(2. * xyMax / kMatCreatorPitch)), kMatCreatorMaxNbins);
+      assert(nBins > 0);
+
+      LOG(info) << "- collecting material between z = " << zLast << " and " << zNew << " [cm]";
+      this->AddMaterial(materialCreator.GenerateMaterialMap(layerIt->zRef, zLast, zNew, xyMax, nBins));
+      this->AddFieldSliceReference(layerIt->xMax, layerIt->yMax, layerIt->zRef);
+      zLast = zNew;
+    }
+
+    if constexpr (0) {
+      // Estimate acceptance
+      std::vector<cbm::algo::kf::MaterialMap> mapsTest;
+      mapsTest.reserve(geoStations.size());
+      double slope{0.};
+      zLast =
+        pTarget->GetZ() + pTarget->GetDz() + kTargMaterialOffset;  // z-coordinate of the target material upper limit
+      for (auto layerIt = geoStations.begin(); layerIt != geoStations.end(); ++layerIt) {
+        double xyMax = 1.3 * std::max(std::fabs(layerIt->xMax), std::fabs(layerIt->yMax));
+        slope        = std::max(slope, xyMax / (layerIt->zRef - pTarget->GetZ()));
+      }
+      for (auto layerIt = geoStations.begin(); layerIt != geoStations.end(); ++layerIt) {
+        double z1 = layerIt->zMax;
+        double z2 = z1;
+        if (std::next(layerIt) != geoStations.end()) {
+          z2 = std::next(layerIt)->zMin;
+        }
+        double zNew  = 0.5 * (z1 + z2);
+        double xyMax = slope * (layerIt->zRef - pTarget->GetZ());
+        //int nBins    = std::min(static_cast<int>(std::ceil(2. * xyMax / kMatCreatorPitch)), kMatCreatorMaxNbins);
+        int nBins = 100;
+        assert(nBins > 0);
+
+        LOG(info) << "* collecting material between z = " << zLast << " and " << zNew << " [cm]";
+        mapsTest.push_back(materialCreator.GenerateMaterialMap(layerIt->zRef, zLast, zNew, xyMax, nBins));
+        zLast = zNew;
+      }
+      for (const auto& map : mapsTest) {
+        LOG(info) << "TEST: " << map.ToString(0, 2);
+      }
+      {
+        // Addition test
+        int iInactive{2};
+        auto& M1{mapsTest[iInactive]};
+        auto& M2{mapsTest[iInactive + 1]};
+        auto M12gen{
+          materialCreator.GenerateMaterialMap(M2.GetZref(), M1.GetZmin(), M2.GetZmax(), M2.GetXYmax(), M2.GetNbins())};
+        auto M12add{M2};
+        M12add.Add(M1);
+        LOG(info) << "MATERIAL MAP ADDITION TEST:";
+        LOG(info) << "M1=\n" << M1.ToString(0, 2);
+        LOG(info) << "M2=\n" << M2.ToString(0, 2);
+        LOG(info) << "M12gen=\n" << M2.ToString(0, 2);
+        LOG(info) << "M12add=\n" << M2.ToString(0, 2);
+      }
+    }
+  }
+  LOG(info) << "kf::TrackingSetupInitializer: Tracking setup was initialized successfully";
+  return true;
+}
+catch (const std::exception& err) {
+  LOG(error) << "kf::TrackingSetupInitializer: Tracking setup was not initialized. Reason: " << err.what();
+  return false;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void TrackingSetupInitializer::Use(bool mvd, bool sts, bool much, bool trd, bool tof)
+{
+  fbUseMvd  = mvd;
+  fbUseSts  = sts;
+  fbUseMuch = much;
+  fbUseTrd  = trd;
+  fbUseTof  = tof;
+}
diff --git a/reco/L1/CbmKfTrackingSetupInitializer.h b/reco/L1/CbmKfTrackingSetupInitializer.h
new file mode 100644
index 0000000000..50e643bb15
--- /dev/null
+++ b/reco/L1/CbmKfTrackingSetupInitializer.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CbmKfTrackingSetupInitializer.h
+/// \brief  Tracking setup initializer in CBM (source)
+/// \since  28.08.2024
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+#pragma once
+
+#include "KfSetupInitializer.h"
+
+#include <tuple>
+
+namespace cbm::kf
+{
+  /// \class TrackingSetupInitializer
+  /// \brief Encapsulation of the kf::Setup initialization routines for CBM
+  class TrackingSetupInitializer : public cbm::algo::kf::SetupInitializer {
+   public:
+    /// \brief  Initializes the instance
+    /// \param  mvd   Is MVD used
+    /// \param  sts   Is STS used
+    /// \param  much  Is MuCh used
+    /// \param  trd   Is TRD used
+    /// \param  tof   Is TOF used
+    bool InitProperties() override;
+
+    /// \brief  Enables/disables detector subsystems in the setup
+    /// \param  mvd   Is MVD used
+    /// \param  sts   Is STS used
+    /// \param  much  Is MuCh used
+    /// \param  trd   Is TRD used
+    /// \param  tof   Is TOF used
+    void Use(bool mvd, bool sts, bool much, bool trd, bool tof);
+
+   private:
+    // Material map creator properties (TODO: Provide setters, if needed)
+    static constexpr double kMatCreatorPitch{0.1};    ///< Material budget map minimal bin size [cm]
+    static constexpr int kMatCreatorMaxNbins{100};    ///< Max number of bins in the material budget map in x(y) axis
+    static constexpr int kMatCreatorNrays{3};         ///< Number of rays per dimension for the material budget
+    static constexpr bool kMatCreatorSafeMode{true};  ///< Safe mode of the material map creation
+    static constexpr double kTargFieldInitStep{2.5};  ///< Step between nodes in the target field initialization [cm]
+    static constexpr double kTargMaterialOffset{1};   ///< Offset between target upper limit and its material zMax [cm]
+
+    bool fbUseMvd{false};   ///< Are MVD stations included in the tracking setup
+    bool fbUseSts{false};   ///< Are STS stations included in the tracking setup
+    bool fbUseMuch{false};  ///< Are MuCh stations included in the tracking setup
+    bool fbUseTrd{false};   ///< Are TRD stations included in the tracking setup
+    bool fbUseTof{false};   ///< Are TOF stations included in the tracking setup
+  };
+}  // namespace cbm::kf
diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx
index a51a3f5bed..ca54da6acc 100644
--- a/reco/L1/CbmL1.cxx
+++ b/reco/L1/CbmL1.cxx
@@ -140,7 +140,7 @@ void CbmL1::CheckDetectorPresence()
 //
 void CbmL1::DisableTrackingStation(ca::EDetectorID detID, int iSt)
 {
-  if (ca::EDetectorID::kEND != detID) {
+  if (ca::EDetectorID::END != detID) {
     fvmDisabledStationIDs[detID].insert(iSt);
   }
 }
@@ -539,7 +539,7 @@ try {
   }
   fpAlgo->Init(fTrackingMode);
 
-  if constexpr (0) {
+  if constexpr (1) {
     // **** FEATURE: KF-SETUP INITIALIZATION *****
     // Creating a setup
     auto pSetupInitializer = std::make_unique<TrackingSetupInitializer>();
diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h
index 6f4d78a9bf..8c88c7f405 100644
--- a/reco/L1/CbmL1.h
+++ b/reco/L1/CbmL1.h
@@ -253,7 +253,7 @@ class CbmL1 : public FairTask {
       case ca::EDetectorID::kMuch: return "MuCh";
       case ca::EDetectorID::kTrd: return "TRD";
       case ca::EDetectorID::kTof: return "TOF";
-      case ca::EDetectorID::kEND: break;
+      case ca::EDetectorID::END: break;
     }
     return "";
   }
diff --git a/reco/L1/CbmL1DetectorID.h b/reco/L1/CbmL1DetectorID.h
index 3a55f207c7..5ecdda9522 100644
--- a/reco/L1/CbmL1DetectorID.h
+++ b/reco/L1/CbmL1DetectorID.h
@@ -9,20 +9,12 @@
 
 #pragma once
 
-#include "CaDefs.h"
-#include "CaEnumArray.h"
+//#include "CaDefs.h"
+#include "CbmEnumArray.h"
 #include "CbmDefs.h"
 
 #include <string>
 
-namespace cbm::ca
-{
-  namespace phys      = cbm::algo::ca::constants::phys;
-  namespace constants = cbm::algo::ca::constants;
-  namespace clrs      = cbm::algo::ca::constants::clrs;
-  namespace ca        = cbm::algo::ca;  ///< CA core namespace (TO BE USED IN CBM-specific interfaces)
-}  // namespace cbm::ca
-
 namespace cbm::algo::ca
 {
   /// \enum  cbm::algo::ca::EDetectorID
@@ -37,7 +29,7 @@ namespace cbm::algo::ca
     kMuch,
     kTrd,
     kTof,
-    kEND  ///< End of enumeration
+    END  ///< End of enumeration
   };
 }  // namespace cbm::algo::ca
 
@@ -59,10 +51,12 @@ class CbmTofHit;
 
 namespace cbm::ca
 {
+  namespace ca = cbm::algo::ca;
+
   /// @brief  Alias to array, indexed by L1DetectorID enum
   /// @note   To be used only in CBM-specific code
   template<typename T>
-  using DetIdArr_t = ca::EnumArray<ca::EDetectorID, T>;
+  using DetIdArr_t = cbm::core::EnumArray<ca::EDetectorID, T>;
 
   /// @brief  List of
 
diff --git a/reco/L1/CbmL1Util.cxx b/reco/L1/CbmL1Util.cxx
index b1fe7b81e1..393b966555 100644
--- a/reco/L1/CbmL1Util.cxx
+++ b/reco/L1/CbmL1Util.cxx
@@ -3,8 +3,8 @@
    Authors: Sergey Gorbunov [committer] */
 
 #include "CbmL1Util.h"
-
 #include "FairTrackParam.h"
+#include "CaDefs.h"
 
 namespace cbm::L1Util
 {
diff --git a/reco/L1/CbmL1Util.h b/reco/L1/CbmL1Util.h
index b0ae43cf87..aefd392a0e 100644
--- a/reco/L1/CbmL1Util.h
+++ b/reco/L1/CbmL1Util.h
@@ -51,7 +51,7 @@ namespace cbm::L1Util
       case ECbmModuleId::kMuch: return cbm::algo::ca::EDetectorID::kMuch;
       case ECbmModuleId::kTrd: return cbm::algo::ca::EDetectorID::kTrd;
       case ECbmModuleId::kTof: return cbm::algo::ca::EDetectorID::kTof;
-      default: return cbm::algo::ca::EDetectorID::kEND;
+      default: return cbm::algo::ca::EDetectorID::END;
     }
   }
 
diff --git a/reco/L1/qa/CbmCaInputQaSetup.cxx b/reco/L1/qa/CbmCaInputQaSetup.cxx
index 375e2726f8..3152a36ed3 100644
--- a/reco/L1/qa/CbmCaInputQaSetup.cxx
+++ b/reco/L1/qa/CbmCaInputQaSetup.cxx
@@ -36,7 +36,7 @@ void InputQaSetup::CheckInit() const
   if (IsMCUsed() && !fpMCEventHeader) {
     throw std::logic_error("MC event header branch is unavailable");
   }
-  for (int iD = 0; iD < static_cast<int>(ca::EDetectorID::kEND); ++iD) {
+  for (int iD = 0; iD < static_cast<int>(ca::EDetectorID::END); ++iD) {
     if (fvbUseDet[iD]) {
       if (!fvpBrHits[iD]) {
         throw std::logic_error(Form("Hit branch is unavailable for %s", kDetName[iD]));
@@ -324,13 +324,13 @@ try {
   int nStGeo = fpParameters->GetNstationsGeometry();
 
   MakeQaDirectory("hit_occupancy");
-  for (int iD = 0; iD < static_cast<int>(ca::EDetectorID::kEND); ++iD) {
+  for (int iD = 0; iD < static_cast<int>(ca::EDetectorID::END); ++iD) {
     if (fvbUseDet[iD]) {
       MakeQaDirectory(Form("hit_occupancy/%s", kDetName[iD]));
     }
   }
   MakeQaDirectory("point_occupancy");
-  for (int iD = 0; iD < static_cast<int>(ca::EDetectorID::kEND); ++iD) {
+  for (int iD = 0; iD < static_cast<int>(ca::EDetectorID::END); ++iD) {
     if (fvbUseDet[iD]) {
       MakeQaDirectory(Form("point_occupancy/%s", kDetName[iD]));
     }
diff --git a/reco/L1/qa/CbmCaTrackFitQa.h b/reco/L1/qa/CbmCaTrackFitQa.h
index 5574a39cc9..9f0e3474d8 100644
--- a/reco/L1/qa/CbmCaTrackFitQa.h
+++ b/reco/L1/qa/CbmCaTrackFitQa.h
@@ -35,6 +35,9 @@ class CbmQaCanvas;
 
 namespace cbm::ca
 {
+  namespace phys      = cbm::algo::ca::constants::phys;
+  namespace constants = cbm::algo::ca::constants;
+
   /// TODO: SZh 02.05.2023: Move ETrackParType to another class and apply it everywhere to track parameters
   /// @brief Enumeration for track parameter type
   enum class ETrackParType
diff --git a/reco/L1/utils/CbmCaIdealHitProducerDet.h b/reco/L1/utils/CbmCaIdealHitProducerDet.h
index d1e74c3ab7..d0407cd8f5 100644
--- a/reco/L1/utils/CbmCaIdealHitProducerDet.h
+++ b/reco/L1/utils/CbmCaIdealHitProducerDet.h
@@ -288,9 +288,9 @@ namespace cbm::ca
         CheckBranch(fpBrHits, "TofHit");
         CheckBranch(fpBrHitMatches, "TofHitMatch");
         break;
-      case ca::EDetectorID::kEND:
+      case ca::EDetectorID::END:
         LOG(fatal) << "CA ideal hit producer for " << kDetName[DetID]
-                   << ": Wrong template argument is used: ca::EDetectorID::kEND";
+                   << ": Wrong template argument is used: ca::EDetectorID::END";
         break;
     }
 
diff --git a/reco/kfnew/CbmKfTrackingSetupInitializer.cxx b/reco/kfnew/CbmKfTrackingSetupInitializer.cxx
index b93a130611..107431d132 100644
--- a/reco/kfnew/CbmKfTrackingSetupInitializer.cxx
+++ b/reco/kfnew/CbmKfTrackingSetupInitializer.cxx
@@ -23,6 +23,8 @@
 #include "KfMaterialMapCreator.h"
 #include "Logger.h"
 
+#include "KfModuleIndexMap.h"
+
 #include <functional>
 
 using cbm::kf::TrackingSetupInitializer;
@@ -60,27 +62,32 @@ try {
       double zMax;  // Upper z-coordinate boundary [cm]
       double xMax;  // Half size of the layer in the x-direction [cm]
       double yMax;  // Half size of the layer in the y-direction [cm]
+      ETrackingDetID detID;  ///< Index of tracking detector
+      int iStLoc;                 ///< Local station of the layer
+
       bool operator<(const GeoLayer& rhs) const { return zRef < rhs.zRef; }
     };
     std::set<GeoLayer> geoStations;
 
-    auto CollectStations = [&](const auto* pIfs) -> void {
+    auto CollectStations = [&](ETrackingDetID detID, const auto* pIfs) -> void {
       if (!pIfs) {
         return;
       }
       for (int iSt = 0; iSt < pIfs->GetNtrackingStations(); ++iSt) {
-        geoStations.emplace(GeoLayer{.zRef = pIfs->GetZref(iSt),
-                                     .zMin = pIfs->GetZmin(iSt),
-                                     .zMax = pIfs->GetZmax(iSt),
-                                     .xMax = std::max(std::fabs(pIfs->GetXmin(iSt)), std::fabs(pIfs->GetXmax(iSt))),
-                                     .yMax = std::max(std::fabs(pIfs->GetYmin(iSt)), std::fabs(pIfs->GetYmax(iSt)))});
+        geoStations.emplace(GeoLayer{.zRef  = pIfs->GetZref(iSt),
+                                     .zMin  = pIfs->GetZmin(iSt),
+                                     .zMax  = pIfs->GetZmax(iSt),
+                                     .xMax  = std::max(std::fabs(pIfs->GetXmin(iSt)), std::fabs(pIfs->GetXmax(iSt))),
+                                     .yMax  = std::max(std::fabs(pIfs->GetYmin(iSt)), std::fabs(pIfs->GetYmax(iSt))),
+                                     .detID = detID,
+                                     .iStLoc = iSt});
       }
     };
-    CollectStations(fbUseMvd ? CbmMvdTrackingInterface::Instance() : nullptr);
-    CollectStations(fbUseSts ? CbmStsTrackingInterface::Instance() : nullptr);
-    CollectStations(fbUseMuch ? CbmMuchTrackingInterface::Instance() : nullptr);
-    CollectStations(fbUseTrd ? CbmTrdTrackingInterface::Instance() : nullptr);
-    CollectStations(fbUseTof ? CbmTofTrackingInterface::Instance() : nullptr);
+    CollectStations(ETrackingDetID::Mvd, fbUseMvd ? CbmMvdTrackingInterface::Instance() : nullptr);
+    CollectStations(ETrackingDetID::Sts, fbUseSts ? CbmStsTrackingInterface::Instance() : nullptr);
+    CollectStations(ETrackingDetID::Much, fbUseMuch ? CbmMuchTrackingInterface::Instance() : nullptr);
+    CollectStations(ETrackingDetID::Trd, fbUseTrd ? CbmTrdTrackingInterface::Instance() : nullptr);
+    CollectStations(ETrackingDetID::Tof, fbUseTof ? CbmTofTrackingInterface::Instance() : nullptr);
 
     // Retriev target properties
     const auto* pTarget = Target::Instance();
@@ -105,12 +112,11 @@ try {
                                 materialCreator.GenerateMaterialMap(pTarget->GetZ(), zFirst, zLast, xyMax, nBins));
     }
 
-    // Material and field layers initialization
+    
 
-    for (const auto& layer : geoStations) {
-      LOG(info) << " >>>>> LAYER >>>>> " << layer.zRef;
-    }
+    // Material and field layers initialization
 
+    cbm::algo::kf::ModuleIndexMapInitializer<ETrackingDetID> indexMapInitializer;
     for (auto layerIt = geoStations.begin(); layerIt != geoStations.end(); ++layerIt) {
       double z1 = layerIt->zMax;
       double z2 = z1;
@@ -125,9 +131,14 @@ try {
       LOG(info) << "- collecting material between z = " << zLast << " and " << zNew << " [cm]";
       this->AddMaterial(materialCreator.GenerateMaterialMap(layerIt->zRef, zLast, zNew, xyMax, nBins));
       this->AddFieldSliceReference(layerIt->xMax, layerIt->yMax, layerIt->zRef);
+      indexMapInitializer.AddComponent(layerIt->detID, layerIt->iStLoc, layerIt->zRef);
       zLast = zNew;
     }
 
+    auto indexMap = indexMapInitializer.MakeIndexMap();
+    LOG(info) << "---> Index map: " << indexMap.ToString();
+
+
     if constexpr (0) {
       // Estimate acceptance
       std::vector<cbm::algo::kf::MaterialMap> mapsTest;
diff --git a/reco/kfnew/CbmKfTrackingSetupInitializer.h b/reco/kfnew/CbmKfTrackingSetupInitializer.h
index 50e643bb15..42ff65f9f0 100644
--- a/reco/kfnew/CbmKfTrackingSetupInitializer.h
+++ b/reco/kfnew/CbmKfTrackingSetupInitializer.h
@@ -15,6 +15,21 @@
 
 namespace cbm::kf
 {
+  /// \enum  ETrackingDetID
+  /// \brief Enumeration for tracking detector subsystems
+  ///
+  // TODO: SZh 12.09.2024:  For me it's unclear, if we should move this entire file to CbmL1, or move the tracking
+  //                        detector IDs declaration here. For now this enum should fully follow the definition
+  //                        of cbm::algo::ca::EDetectorID.
+  enum class ETrackingDetID {
+    Mvd = 0x10,
+    Sts = 0x20,
+    Much,
+    Trd = 0x40,
+    Tof = 0x30,
+    END
+  };
+
   /// \class TrackingSetupInitializer
   /// \brief Encapsulation of the kf::Setup initialization routines for CBM
   class TrackingSetupInitializer : public cbm::algo::kf::SetupInitializer {
-- 
GitLab