From a6af70f5a347cda9f51971bc04e2e230c77c1da7 Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Wed, 18 Sep 2024 01:25:04 +0200
Subject: [PATCH] KF-setup initialization improvement

---
 algo/kf/core/CMakeLists.txt                   |   6 +-
 algo/kf/core/KfDefs.h                         |   4 +-
 algo/kf/core/geo/KfField.h                    |   2 +-
 algo/kf/core/geo/KfIMaterialMapFactory.h      |  43 ++++
 algo/kf/core/geo/KfModuleIndexMap.cxx         | 119 +++++++++
 algo/kf/core/geo/KfModuleIndexMap.h           | 193 +++++++++++++++
 algo/kf/core/geo/KfSetup.cxx                  |   2 +-
 algo/kf/core/geo/KfSetup.h                    |  62 ++---
 algo/kf/core/geo/KfSetupBuilder.cxx           | 108 ++++++++
 algo/kf/core/geo/KfSetupBuilder.h             | 233 ++++++++++++++++++
 algo/kf/core/geo/KfSetupInitializer.cxx       |  63 -----
 algo/kf/core/geo/KfSetupInitializer.h         | 166 -------------
 algo/kf/core/geo/KfTarget.cxx                 |   8 +-
 algo/kf/core/geo/KfTarget.h                   |  29 ++-
 reco/L1/CMakeLists.txt                        |   1 -
 reco/L1/CbmKfTrackingSetupInitializer.cxx     | 195 ---------------
 reco/L1/CbmKfTrackingSetupInitializer.h       |  53 ----
 reco/L1/CbmL1.cxx                             |  11 +-
 reco/L1/CbmL1DetectorID.h                     |   2 +-
 reco/L1/CbmL1Util.cxx                         |   3 +-
 reco/kfnew/CbmKfTrackingSetupInitializer.cxx  | 172 +++----------
 reco/kfnew/CbmKfTrackingSetupInitializer.h    |  32 ++-
 reco/kfnew/tools/CMakeLists.txt               |   4 +-
 ...apCreator.cxx => KfMaterialMapFactory.cxx} |  51 ++--
 ...ialMapCreator.h => KfMaterialMapFactory.h} |  14 +-
 25 files changed, 862 insertions(+), 714 deletions(-)
 create mode 100644 algo/kf/core/geo/KfIMaterialMapFactory.h
 create mode 100644 algo/kf/core/geo/KfModuleIndexMap.cxx
 create mode 100644 algo/kf/core/geo/KfModuleIndexMap.h
 create mode 100644 algo/kf/core/geo/KfSetupBuilder.cxx
 create mode 100644 algo/kf/core/geo/KfSetupBuilder.h
 delete mode 100644 algo/kf/core/geo/KfSetupInitializer.cxx
 delete mode 100644 algo/kf/core/geo/KfSetupInitializer.h
 delete mode 100644 reco/L1/CbmKfTrackingSetupInitializer.cxx
 delete mode 100644 reco/L1/CbmKfTrackingSetupInitializer.h
 rename reco/kfnew/tools/{KfMaterialMapCreator.cxx => KfMaterialMapFactory.cxx} (89%)
 rename reco/kfnew/tools/{KfMaterialMapCreator.h => KfMaterialMapFactory.h} (91%)

diff --git a/algo/kf/core/CMakeLists.txt b/algo/kf/core/CMakeLists.txt
index 7ee3882d8f..a39e049f2f 100644
--- a/algo/kf/core/CMakeLists.txt
+++ b/algo/kf/core/CMakeLists.txt
@@ -21,7 +21,8 @@ set(SRCS
   ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfFieldSlice.cxx
   ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfFieldRegion.cxx
   ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfSetup.cxx
-  ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfSetupInitializer.cxx
+  ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfSetupBuilder.cxx
+  ${CMAKE_CURRENT_SOURCE_DIR}/geo/KfModuleIndexMap.cxx
   ${CMAKE_CURRENT_SOURCE_DIR}/utils/KfUtils.cxx
 )
 
@@ -110,7 +111,8 @@ install(
     geo/KfMaterialMap.h 
     geo/KfModuleIndexMap.h 
     geo/KfSetup.h
-    geo/KfSetupInitializer.h
+    geo/KfSetupBuilder.h
+    geo/KfIMaterialMapFactory.h
     geo/KfTarget.h
     geo/KfField.h
 
diff --git a/algo/kf/core/KfDefs.h b/algo/kf/core/KfDefs.h
index efd12d4c76..59268c388c 100644
--- a/algo/kf/core/KfDefs.h
+++ b/algo/kf/core/KfDefs.h
@@ -72,8 +72,8 @@ namespace cbm::algo::kf::defs
   //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, ...)
+  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 680f2587c7..218c7ed1ea 100644
--- a/algo/kf/core/geo/KfField.h
+++ b/algo/kf/core/geo/KfField.h
@@ -456,7 +456,7 @@ namespace cbm::algo::kf
           fld[iNode] = GlobalField::GetFieldValue<double>(fFieldFn, fTarget[0], fTarget[1], z);
           z += fTargetStep;
         }
-        field.fPrimVertexField = FieldRegion<T>(fFieldType, fld[0], pos[0], fld[1], pos[1], fld[2], pos[2]);
+        field.fPrimVertexField = FieldRegion<T>(fld[0], pos[0], fld[1], pos[1], fld[2], pos[2]);
         // TODO: Provide alternative method for Orig
       }
     }
diff --git a/algo/kf/core/geo/KfIMaterialMapFactory.h b/algo/kf/core/geo/KfIMaterialMapFactory.h
new file mode 100644
index 0000000000..403a4019aa
--- /dev/null
+++ b/algo/kf/core/geo/KfIMaterialMapFactory.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   KfIMaterialMapFactory.h
+/// \brief  Interface to the material map creator
+/// \since  28.08.2024
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+#pragma once
+
+namespace cbm::algo::kf
+{
+  class MaterialMap;
+
+  /// \class IMaterialMapFactory
+  /// \brief Interface to the material map creator
+  class IMaterialMapFactory {
+   public:
+    /// \brief Destructor
+    virtual ~IMaterialMapFactory() = default;
+
+    /// \brief Generates a material budget map
+    /// \param zRef      Reference z-coordinate of the material layer [cm]
+    /// \param zMin      z-coordinate of the material layer lower boundary [cm]
+    /// \param zMax      z-coordinate of the material layer upper boundary [cm]
+    /// \param xyMax     Transverse size of the material layer [cm]
+    /// \param nBinsDim  Number of bins in the x(y) axis
+    ///
+    /// generate a material map, collecting the material between [zMin, zMax]
+    /// with radial rays from (0,0,targetZ) through the XY-bins at z == zRef.
+    ///
+    /// It creates a map with [nBinsDim x nBinsDim] bins, of a size of [+-xyMax, +-xyMax]
+    /// shooting fNraysBinPerDim x fNraysBinPerDim through each bin
+    ///
+    /// The calculated radiation thickness is a projection of the rad.thickness along the ray onto the Z axis.
+    /// RadThick = sum of (dZ / radLength) over ray trajectory pieces
+    ///
+    /// When doRadialProjection==false the rays are shoot horizontally along the Z axis
+    ///
+    virtual MaterialMap GenerateMaterialMap(double zRef, double zMin, double zMax, double xyMax, int nBinsDim) = 0;
+  };
+}  // namespace cbm::algo::kf
diff --git a/algo/kf/core/geo/KfModuleIndexMap.cxx b/algo/kf/core/geo/KfModuleIndexMap.cxx
new file mode 100644
index 0000000000..bdb3a1d724
--- /dev/null
+++ b/algo/kf/core/geo/KfModuleIndexMap.cxx
@@ -0,0 +1,119 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   KfModuleIndexMap.cxx
+/// \brief  A helper class to map external indices with the ones of KF-setup (implementation)
+/// \author Sergei Zharko <s.zharko@gsi.de>
+/// \since  16.09.2024
+
+#include "KfModuleIndexMap.h"
+
+namespace cbm::algo::kf
+{
+  // -------------------------------------------------------------------------------------------------------------------
+  //
+  void ModuleIndexMap::Reset()
+  {
+    fvLocToGlb.clear();
+    fvGlbToLoc.clear();
+    fvDetLocOffset.clear();
+    fvDetIntToExt.clear();
+    fvDetExtToInt.clear();
+  }
+
+  // -------------------------------------------------------------------------------------------------------------------
+  //
+  std::string ModuleIndexMap::ToString(int indentLevel) const
+  {
+    using fmt::format;
+    constexpr char IndentCh = '\t';
+    std::string indent(indentLevel, IndentCh);
+    std::stringstream msg;
+    msg << '\n' << indent << format("{:<50} ", "Detector internal to external index map: ");
+    for (auto id : fvDetIntToExt) {
+      msg << format("{:>8} ", id);
+    }
+    msg << '\n' << indent << format("{:<50} ", "Detector external to internal index map: ");
+    for (auto id : fvDetExtToInt) {
+      msg << format("{:>8} ", id);
+    }
+    msg << '\n' << indent << format("{:<50} ", "First global ID vs. internal detector: ");
+    for (auto id : fvDetLocOffset) {
+      msg << format("{:>8} ", id);
+    }
+    msg << '\n' << indent << format("{:<50} ", "Local ID to global ID: ");
+    for (auto id : fvLocToGlb) {
+      msg << format("{:>8} ", id);
+    }
+    msg << '\n' << indent << format("{:<50} ", "Geo ID to (detID:locID): ");
+    for (const auto& [iDetExt, iLoc] : fvGlbToLoc) {
+      msg << format("{:>3}:{:<3}", iDetExt, iLoc);
+    }
+
+    return msg.str();
+  }
+
+  // -------------------------------------------------------------------------------------------------------------------
+  //
+  ModuleIndexMap ModuleIndexMapFactory::MakeIndexMap() const
+  {
+    ModuleIndexMap indexMap;
+
+    auto& vDetIntToExt  = indexMap.fvDetIntToExt;
+    auto& vDetExtToInt  = indexMap.fvDetExtToInt;
+    auto& vDetLocOffset = indexMap.fvDetLocOffset;
+    auto& vLocToGlb     = indexMap.fvLocToGlb;
+    auto& vGlbToLoc     = indexMap.fvGlbToLoc;
+
+    // ------- Component layout
+    // Initialization of internal and external detector subsystem mapping
+    for (const auto& component : fvComponentLayers) {
+      auto iDetExt = component.fDetId;
+      if (iDetExt < 0) {
+        std::stringstream msg;
+        msg << "ModuleIndexMapFactory::MakeIndexMap: illegal detector subsystem enumeration: " << iDetExt
+            << " is out of range [0, " << defs::MaxNofDetSubsystems << "). Enties of the EDetID enumeration are "
+            << "required to be non-negative";
+        throw std::out_of_range(msg.str());
+      }
+      if (iDetExt >= static_cast<int>(vDetExtToInt.size())) {
+        vDetExtToInt.resize(iDetExt + 1, -1);
+      }
+
+      if (vDetExtToInt[iDetExt] == -1) {  // Detector subsystem is not registered
+        // Assign an internal index to the detID:
+        vDetExtToInt[iDetExt] = static_cast<int>(vDetIntToExt.size());
+        vDetIntToExt.push_back(iDetExt);
+      }
+    }
+    {  // Estimate offsets
+      int nDet = vDetIntToExt.size();
+      vDetLocOffset.resize(nDet + 1, 0);
+      for (const auto& component : fvComponentLayers) {
+        int pick            = vDetExtToInt[component.fDetId] + 1;
+        vDetLocOffset[pick] = std::max(vDetLocOffset[pick], component.fLocId + 1);
+      }
+      for (int iDet{0}; iDet < nDet; ++iDet) {
+        vDetLocOffset[iDet + 1] += vDetLocOffset[iDet];
+      }
+    }
+
+    vLocToGlb.resize(vDetLocOffset.back(), -1);
+    vGlbToLoc.resize(fvComponentLayers.size());
+    for (auto itComp = fvComponentLayers.cbegin(); itComp != fvComponentLayers.cend(); ++itComp) {
+      const auto& component{*itComp};
+      int iDetInt                              = vDetExtToInt[component.fDetId];
+      int iLoc                                 = component.fLocId;
+      int iGlb                                 = std::distance(fvComponentLayers.begin(), itComp);
+      vLocToGlb[vDetLocOffset[iDetInt] + iLoc] = iGlb;
+      vGlbToLoc[iGlb]                          = std::pair(component.fDetId, iLoc);
+    }
+
+    return indexMap;
+  }
+
+  // -------------------------------------------------------------------------------------------------------------------
+  //
+  void ModuleIndexMapFactory::Reset() { fvComponentLayers.clear(); }
+}  // namespace cbm::algo::kf
diff --git a/algo/kf/core/geo/KfModuleIndexMap.h b/algo/kf/core/geo/KfModuleIndexMap.h
new file mode 100644
index 0000000000..78c186de40
--- /dev/null
+++ b/algo/kf/core/geo/KfModuleIndexMap.h
@@ -0,0 +1,193 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   KfModuleIndexMap.h
+/// \brief  A helper class to map external indices with the ones of KF-setup
+/// \author Sergei Zharko <s.zharko@gsi.de>
+/// \since  10.09.2024
+
+#pragma once
+
+#include "KfDefs.h"
+
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/utility.hpp>
+
+#include <set>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <fmt/format.h>
+
+namespace cbm::algo::kf
+{
+
+  /// \class ModuleIndexMap
+  /// \brief Maps local detector and station indices to the material maps and field slices
+  ///
+  /// The class maps external indices of components combined into subsets to a plain global index.
+  /// The indices both of the components inside a subset (iLoc) and the indices of the
+  /// subsets themselves (iDetExt) must be unique, but can be unsorted and can have holes in their
+  /// ranges. The global index (iGlob) is assigned automatically depending on the element ordering.
+  ///
+  /// The mapping is organized with the sequential contiguous containers (std::vector). The containers
+  /// used are:
+  /// (i)   fvDetExtToInt [ iDetExt ]  =>  iDetInt
+  ///         size:  max(iDetExt)
+  /// (ii)  fvDetIntToExt [ iDetInt ]  =>  iDetExt (int)
+  ///         size:  number of registered subsystems
+  /// (iii) fvDetLocOffset [ iDetInt ]  =>  max number of elements for iDetInt - 1
+  ///         size:  max possible number of elements (including inactive/unused)
+  ///         fvDetLocOffset[0] = 0, fvDetLocOffset.back() = n of max possible elements
+  /// (iv)  fvGlbToLoc [ iGlob ] => pair(iDetInt, iLoc)
+  ///         size:  number of registered components
+  /// (v)   fvLocToGlb [ fvDetLocOffset[iDetInt] + iLoc] => iGlob
+  ///         size:  max possible number of components (including inactive/unused)
+  ///
+  class alignas(VcMemAlign) ModuleIndexMap {
+    friend class ModuleIndexMapFactory;
+    friend class boost::serialization::access;
+
+   public:
+    /// \brief Gets total number of components
+    int GetNofLayers() const { return fvDetLocOffset.back(); }
+
+    /// \brief Gets number of layers for a particular detector subsystem
+    /// \tparam  EDetID  concrete index type of the det ID (can be either an enum, or an integral type)
+    /// \param detId Detector ID of the component
+    ///
+    /// \note  The maximum possible number of components in the subset is returned. It accounts for
+    ///        inactive/unused components.
+    template<class EDetID>
+    int GetNofLayers(EDetID detId) const
+    {
+      return fvDetLocOffset[fvDetExtToInt[static_cast<int>(detId)] + 1]
+             - fvDetLocOffset[fvDetExtToInt[static_cast<int>(detId)]];
+    }
+
+    /// \brief Converts internal layer index to pair (detID, locID)
+    /// \tparam  EDetID  concrete index type of the det ID (can be either an enum, or an integral type)
+    /// \param globId  Internal layer index
+    /// \return  pair(detector ID, local ID) of the layer
+    template<class EDetID>
+    std::pair<EDetID, int> GlobalToLocal(int globId) const;
+
+    /// \brief Converts external pair (detID, locID) to internal layer index
+    /// \tparam  EDetID  concrete index type of the det ID (can be either an enum, or an integral type)
+    /// \param   locId   Local ID of the layer
+    /// \param   detId   Detector ID of the component
+    /// \note   if the (detId, locId) pair was not registered, returns -1
+    /// \return global index of the layer
+    template<class EDetID>
+    int LocalToGlobal(EDetID detId, int locId) const
+    {
+      return fvLocToGlb[fvDetLocOffset[fvDetExtToInt[static_cast<int>(detId)]] + locId];
+    }
+
+    /// \brief Disables a component
+    ///
+    ///
+    template<class EDetID>
+    void Disable(int locId, EDetID detId);
+
+    /// \brief Resets the instance
+    void Reset();
+
+    /// \brief String representation of the instance
+    std::string ToString(int indentLevel = 0) const;
+
+   private:
+    template<class Archive>
+    void serialize(Archive& ar, const unsigned int /*version*/)
+    {
+      ar& fvLocToGlb;
+      ar& fvGlbToLoc;
+      ar& fvDetLocOffset;
+      ar& fvDetIntToExt;
+      ar& fvDetExtToInt;
+    }
+
+    /// \brief Map of global component index to local (localId, intDetId)
+
+    std::vector<int> fvLocToGlb{};
+    std::vector<std::pair<int, int>> fvGlbToLoc{};
+    std::vector<int> fvDetLocOffset{};  ///< First index of component for det
+    std::vector<int> fvDetIntToExt{};   ///< Maps external detID to internal
+    std::vector<int> fvDetExtToInt{};   ///< Maps internal detID to external
+  };
+
+  /// \class  ModuleIndexMapFactory
+  /// \brief  Creates a valid module mapper
+  class ModuleIndexMapFactory {
+    /// \struct Component
+    /// \brief  Structure to keep information on layers
+    struct Component {
+      Component(int detId, int locId, double z) : fZ(z), fLocId(locId), fDetId(detId) {}
+      double fZ;   ///< Reference z-coordinate of the component
+      int fLocId;  ///< Local index of component
+      int fDetId;  ///< External index of detector subsystem
+      bool operator<(const Component& rhs) const { return fZ < rhs.fZ; }
+    };
+
+   public:
+    /// \brief Adds component info
+    /// \param detId  Detector subsytem index (external)
+    /// \param locId  Detector component local index (external)
+    /// \param z      Reference z-component of the component [cm]
+    template<class EDetID>
+    void AddComponent(EDetID detId, int locId, double z);
+
+    /// \brief Creates a module index map
+    ModuleIndexMap MakeIndexMap() const;
+
+    /// \brief Resets the instance
+    void Reset();
+
+   private:
+    std::set<Component> fvComponentLayers;
+  };
+
+  // -------------------------------------------------------------------------------------------------------------------
+  //
+  template<class EDetID>
+  void ModuleIndexMap::Disable(int locIdDisable, EDetID detIdDisable)
+  {
+    // Check, if the detector id is there
+    auto iDetExtDsbl{static_cast<int>(detIdDisable)};
+    if (iDetExtDsbl >= fvDetExtToInt.size()) {
+      return;  // Nothing to disable, detector is already not in the map
+    }
+
+    //auto iGeoDsbl{LocalToGeo(locIdDisable, detIdDisable)};
+  }
+
+  // -------------------------------------------------------------------------------------------------------------------
+  //
+  template<class EDetID>
+  inline std::pair<EDetID, int> ModuleIndexMap::GlobalToLocal(int globId) const
+  {
+    const auto& [iDetExt, iLoc] = fvGlbToLoc[globId];
+    return std::pair(static_cast<EDetID>(iDetExt), iLoc);
+  }
+
+  // -------------------------------------------------------------------------------------------------------------------
+  //
+  template<class EDetID>
+  void ModuleIndexMapFactory::AddComponent(EDetID detId, int locId, double z)
+  {
+    if (!fvComponentLayers.emplace(static_cast<int>(detId), locId, z).second) {
+      std::stringstream msg;
+      msg << "ModuleIndexMapFactory: attempt of adding a duplicating component with z = " << z
+          << ", detID = " << static_cast<int>(detId) << " and locId = " << locId
+          << ".\n The next components were already added:";
+      for (const auto& c : fvComponentLayers) {
+        msg << "\n\t- {z, detId, locId} = {" << c.fZ << ", " << c.fDetId << ", " << c.fLocId << "}";
+      }
+      throw std::logic_error(msg.str());
+    }
+  }
+
+
+}  // namespace cbm::algo::kf
diff --git a/algo/kf/core/geo/KfSetup.cxx b/algo/kf/core/geo/KfSetup.cxx
index dd4fa54a17..3854fd48dc 100644
--- a/algo/kf/core/geo/KfSetup.cxx
+++ b/algo/kf/core/geo/KfSetup.cxx
@@ -25,8 +25,8 @@ std::string Setup<T>::ToString(int verbosity, int indentLevel) const
     std::string indent(indentLevel, indentCh);
     msg << indent << "\n ----- KF Setup -----\n";
     msg << indent << "\nFloating-point type: " << typeid(T).name();
-
     msg << indent << "\nTARGET:\n" << fTarget.ToString(indentLevel + 1, verbosity);
+    msg << indent << "\nMODULE INDEXING SCHEME:\n" << fModuleIndexMap.ToString(indentLevel + 1);
     msg << indent << "\nMATERIAL LAYERS:\n";
     for (const auto& layer : fvMaterialLayers) {
       msg << layer.ToString(indentLevel + 1, verbosity) << '\n';
diff --git a/algo/kf/core/geo/KfSetup.h b/algo/kf/core/geo/KfSetup.h
index 2f1a8a3d84..39ce0ca775 100644
--- a/algo/kf/core/geo/KfSetup.h
+++ b/algo/kf/core/geo/KfSetup.h
@@ -12,11 +12,11 @@
 #include "KfDefs.h"
 #include "KfField.h"
 #include "KfMaterialMap.h"
+#include "KfModuleIndexMap.h"
 #include "KfTarget.h"
 #include "KfVector.h"
 
 #include <boost/serialization/access.hpp>
-#include <boost/serialization/split_free.hpp>
 
 #include <fstream>
 #include <optional>
@@ -32,10 +32,10 @@ namespace cbm::algo::kf
   template<typename T>
   class alignas(VcMemAlign) Setup {
     friend class boost::serialization::access;  // Boost serializer methods
+    friend class SetupBuilder;
     template<typename>
     friend class Setup;
 
-
    public:
     /// \brief Constructor
     /// \param fldMode  Field mode
@@ -53,7 +53,8 @@ namespace cbm::algo::kf
     /// \tparam I  Underlying floating-point data type of the source
     template<typename I>
     Setup(const Setup<I>& other)
-      : fvMaterialLayers(other.fvMaterialLayers)
+      : fModuleIndexMap(other.fModuleIndexMap)
+      , fvMaterialLayers(other.fvMaterialLayers)
       , fField(other.fField)
       , fTarget(other.fTarget)
     {
@@ -68,10 +69,6 @@ namespace cbm::algo::kf
     /// \brief Move assignment operator
     //Setup& operator=(Setup&&) noexcept;
 
-    /// \brief Sets material layer
-    /// \param map     Material map
-    void AddMaterial(const MaterialMap& map) { fvMaterialLayers.emplace_back(map); }
-
     /// \brief Makes an instance of the field depending on the template parameter
     /// \throw  std::logic_error  If the particular field member is undefined (nullopt)
     const Field<T>& GetField() const { return fField; }
@@ -80,6 +77,19 @@ namespace cbm::algo::kf
     /// \param iLayer  Index of layer
     const MaterialMap& GetMaterial(int iLayer) const { return fvMaterialLayers[iLayer]; }
 
+    /// \brief Gets material layer from external indices
+    /// \tparam  EDetID  Index of the detector subsystem
+    /// \param iDet  DetectorID
+    /// \param iLoc  Local index of the module
+    template<class EDetID>
+    const MaterialMap& GetMaterial(EDetID iDet, int iLoc) const
+    {
+      return fvMaterialLayers[fModuleIndexMap.LocalToGlobal(iDet, iLoc)];
+    }
+
+    /// \brief Gets module index map
+    const ModuleIndexMap& GetModuleIndexMap() const { return fModuleIndexMap; }
+
     /// \brief Gets number of defined material layers
     int GetNofMaterialLayers() const { return static_cast<int>(fvMaterialLayers.size()); }
 
@@ -91,40 +101,20 @@ namespace cbm::algo::kf
     /// \param indentLevel  Indent level of the string output
     std::string ToString(int verbosity = 1, int indentLevel = 0) const;
 
-    /// \brief Sets field
-    void SetField(const Field<double>& field) { fField = Field<T>(field); }
-
-    /// \brief Sets target (moves from the source)
-    /// \param target  Target instance
-    void SetTarget(const Target<double>& target) { fTarget = target; }
-
    private:
-    /// \brief BOOST serialization load method
-    template<class Archive>
-    void load(Archive& ar, const unsigned int /*version*/)
-    {
-      ar >> fvMaterialLayers;
-      ar >> fTarget;
-      ar >> fField;
-    }
-
-    template<class Archive>
-    void save(Archive& ar, const unsigned int /*version*/) const
-    {
-      ar << fvMaterialLayers;
-      ar << fTarget;
-      ar << fField;
-    }
-
     template<class Archive>
-    void serialize(Archive& ar, const unsigned int version)
+    void serialize(Archive& ar, const unsigned int /*version*/)
     {
-      boost::serialization::split_member(ar, *this, version);
+      ar& fModuleIndexMap;
+      ar& fvMaterialLayers;
+      ar& fTarget;
+      ar& fField;
     }
 
-    std::vector<MaterialMap> fvMaterialLayers = {};  ///< Container of the material maps
-    Field<T> fField;                                 ///< Interpolated field (NOTE: maybe make optional)
-    Target<T> fTarget;                               ///< Target layer
+    ModuleIndexMap fModuleIndexMap{};             ///< Index map (internal->external)
+    std::vector<MaterialMap> fvMaterialLayers{};  ///< Container of the material maps
+    Field<T> fField;                              ///< Interpolated field (NOTE: maybe make optional)
+    Target<T> fTarget;                            ///< Target layer
   };
 
 }  // namespace cbm::algo::kf
diff --git a/algo/kf/core/geo/KfSetupBuilder.cxx b/algo/kf/core/geo/KfSetupBuilder.cxx
new file mode 100644
index 0000000000..e8cff76b4c
--- /dev/null
+++ b/algo/kf/core/geo/KfSetupBuilder.cxx
@@ -0,0 +1,108 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// @file   KfSetupBuilder.h
+/// @brief  A base KF-Setup initialization class (source)
+/// @since  28.03.2024
+/// @author Sergei Zharko <s.zharko@gsi.de>
+
+#include "KfSetupBuilder.h"
+
+#include <sstream>
+
+using cbm::algo::kf::SetupBuilder;
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void SetupBuilder::Init()
+{
+  // Check setters
+  if (fGeoLayers.size() == 0) {
+    throw std::runtime_error("kf::SetupBuilder: no geometry layers initialized");
+  }
+  if (!fpMaterialMapFactory.get()) {
+    throw std::runtime_error("kf::SetupBuilder: no material map factory provided");
+  }
+
+  // Init target properties
+  {
+    // Material budget
+    double zMin{fTarget.GetZ() + kTargetCenterOffset};
+    double zMax{fTarget.GetZ() + fTarget.GetDz() * kTargetMaterialOffset};
+    double rMax{fTarget.GetR() * kTargetMaterialTransverseSizeMargin};
+    fTarget.SetMaterial(
+      fpMaterialMapFactory->GenerateMaterialMap(fTarget.GetZ(), zMin, zMax, rMax, kTargetMaterialMapNofBins));
+
+    // Field region
+    fFieldFactory.SetStep(kTargetFieldInitStep);
+  }
+
+  // Init geometry layers
+  {
+    // Estimate acceptance slope
+    double acceptanceSlope = -1.;  // arbitrary negative value
+    for (const auto& layer : fGeoLayers) {
+      double tCurr = std::max(std::fabs(layer.fXmax), std::fabs(layer.fYmax)) / (layer.fZref - fTarget.GetZ());
+      assert(tCurr > 0);
+      acceptanceSlope = std::max(acceptanceSlope, tCurr);
+    }
+
+    fvMaterial.reserve(fGeoLayers.size());
+    double zLast{fTarget.GetZ() + fTarget.GetDz() * kTargetMaterialOffset};
+    for (auto layerIt = fGeoLayers.cbegin(); layerIt != fGeoLayers.cend(); ++layerIt) {
+      double z1 = layerIt->fZmax;
+      double z2 = z1;
+      if (std::next(layerIt) != fGeoLayers.cend()) {
+        z2 = std::next(layerIt)->fZmin;
+      }
+      double zNew{0.5 * (z1 + z2)};
+      double xyMax{acceptanceSlope * (layerIt->fZref - fTarget.GetZ())};
+      auto material{fpMaterialMapFactory->GenerateMaterialMap(layerIt->fZref, zLast, zNew, xyMax, fMatMapNofBins)};
+      fvMaterial.push_back(std::move(material));
+      // Note: square material maps to follow the material budget map regions
+      fFieldFactory.AddSliceReference(xyMax, xyMax, layerIt->fZref);
+      fModuleIndexFactory.AddComponent<int>(layerIt->fDetID, layerIt->fLocID, layerIt->fZref);
+      zLast = zNew;
+    }
+  }
+  LOG(info) << "Initialized";
+  fbPropertiesInitialized = true;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void SetupBuilder::Reset()
+{
+  fbPropertiesInitialized = false;
+  fFieldFactory.Reset();
+  fGeoLayers.clear();
+  fpMaterialMapFactory = nullptr;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void SetupBuilder::SetTargetProperty(double x, double y, double z, double dz, double r)
+{
+  fbPropertiesInitialized = false;
+  fTarget.SetX(x);
+  fTarget.SetY(y);
+  fTarget.SetZ(z);
+  fTarget.SetDz(dz);
+  fTarget.SetR(r);
+  fFieldFactory.SetTarget(x, y, z);
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void SetupBuilder::Store(const Setup<double>& setup, const std::string& fileName)
+{
+  std::ofstream ofs(fileName, std::ios::binary);
+  if (!ofs) {
+    std::stringstream msg;
+    msg << "kf::SetupBuilder::Store: failed openning file \"" << fileName << "\" to store the setup";
+    throw std::runtime_error(msg.str());
+  }
+  boost::archive::binary_oarchive oa(ofs);
+  oa << setup;
+}
diff --git a/algo/kf/core/geo/KfSetupBuilder.h b/algo/kf/core/geo/KfSetupBuilder.h
new file mode 100644
index 0000000000..b67338ea5b
--- /dev/null
+++ b/algo/kf/core/geo/KfSetupBuilder.h
@@ -0,0 +1,233 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// @file   KfSetupBuilder.h
+/// @brief  A base KF-Setup initialization class (header)
+/// @since  28.03.2024
+/// @author Sergei Zharko <s.zharko@gsi.de>
+
+#pragma once  // include this header only once per compilation unit
+
+#include "KfIMaterialMapFactory.h"
+#include "KfSetup.h"
+
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/archive/binary_oarchive.hpp>
+
+#include <fstream>
+#include <memory>
+#include <optional>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace cbm::algo::kf
+{
+  /// \struct GeoLayer
+  /// \brief  A helper structure to store geometrical information of the layers
+  template<class EDetID>
+  struct GeoLayer {
+    GeoLayer(EDetID detID, int iLoc, double zRef, double zMin, double zMax, double xMax, double yMax)
+      : fZref(zRef)
+      , fZmin(zMin)
+      , fZmax(zMax)
+      , fXmax(xMax)
+      , fYmax(yMax)
+      , fDetID(detID)
+      , fLocID(iLoc)
+    {
+    }
+
+    double fZref;   ///< Reference z-coordinate [cm]
+    double fZmin;   ///< Lower z-coordinate boundary [cm]
+    double fZmax;   ///< Upper z-coordinate boundary [cm]
+    double fXmax;   ///< Half size of the layer in the x-direction [cm]
+    double fYmax;   ///< Half size of the layer in the y-direction [cm]
+    EDetID fDetID;  ///< Index of detector subsystem
+    int fLocID;     ///< Local index of the detector module
+    bool operator<(const GeoLayer& rhs) const { return fZref < rhs.fZref; }
+  };
+
+  /// \class  SetupBuilder
+  /// \brief  Creates a valid initialized Setup instance
+  class SetupBuilder {
+   public:
+    /// \brief Default constructor
+    SetupBuilder() = default;
+
+    /// \brief Copy constructor
+    SetupBuilder(const SetupBuilder&) = delete;
+
+    /// \brief Move constructor
+    SetupBuilder(SetupBuilder&&) = delete;
+
+    /// \brief Destructor
+    virtual ~SetupBuilder() = default;
+
+    /// \brief Copy assignment operator
+    SetupBuilder& operator=(const SetupBuilder&) = delete;
+
+    /// \brief Move assignment operator
+    SetupBuilder& operator=(SetupBuilder&&) = delete;
+
+    /// \brief Adds material layer
+    /// \tparam EDetID   detector ID index type
+    /// \param  geoLayer A geometrical layer
+    template<class EDetID>
+    void AddLayer(const GeoLayer<EDetID>& geoLayer);
+
+    /// \brief  Initializes, validates and cashes the parameters
+    /// \throw  std::runtime_error If pre-initialization was incomplete
+    void Init();
+
+    /// \brief Creates a setup instance
+    template<typename T>
+    Setup<T> MakeSetup() const;
+
+    /// \brief Resets the instance
+    void Reset();
+
+    /// \brief Sets magnetic field function
+    /// \param fieldMode  Magnetic field mode:
+    /// \param fieldFn    Magnetic field function
+    /// \param fieldType  Magnetic field type
+    void SetFieldProperty(EFieldMode fieldMode, const FieldFn_t& fieldFn, EFieldType fieldType)
+    {
+      fbPropertiesInitialized = false;
+      fFieldFactory.SetFieldFunction(fieldFn, fieldType);
+      fFieldFactory.SetFieldMode(fieldMode);
+    }
+
+    /// \brief Sets material map creator
+    /// \param pMaterialFactory  Pointer to the actual material map creator instance
+    void SetMaterialMapFactory(const std::shared_ptr<IMaterialMapFactory>& pMaterialFactory)
+    {
+      fbPropertiesInitialized = false;
+      fpMaterialMapFactory    = pMaterialFactory;
+    }
+
+    /// \brief Sets target initialization properties
+    /// \param x  Target x-coordinate [cm]
+    /// \param y  Target y-coordinate [cm]
+    /// \param z  Target z-coordinate [cm]
+    /// \param dz Target half-thickness [cm]
+    /// \param r  Target transverse size (XYmax)
+    void SetTargetProperty(double x, double y, double z, double dz, double r);
+
+
+    // ********************
+    // ** Static methods **
+    // ********************
+
+    /// \brief  Stores a serialized setup to a file
+    /// \param  setup     A reference to the Setup (NOTE: a double-Setup must be passed explicitly)
+    /// \param  fileName  Output file name
+    ///
+    /// Only a Setup with T = double can be serialized, so if a particular setup instance has another floating-point
+    /// type, it will be converted to the double-version. In the serialization only the interpolated magnetic field
+    /// variant is stored, the original field version will be set to nullopt during the loading from the file.
+    static void Store(const Setup<double>& setup, const std::string& fileName);
+
+    /// \brief  Loads a serialized setup from a file
+    /// \tparam T         Underlying floating-point type for the output setup object
+    /// \param  fileName  Input file name
+    /// \throw  std::runtime_error  If the fileName cannot be opened
+    template<typename T>
+    static Setup<T> Load(const std::string& fileName);
+
+   private:
+    // TODO: Define target material more precisely
+    static constexpr double kTargetCenterOffset{0.05};                 // Offset from target center [cm]
+    static constexpr double kTargetMaterialOffset{2.};                 // Offset of the target material [in dz]
+    static constexpr double kTargetMaterialTransverseSizeMargin{1.3};  // Margin of target transverse size
+    static constexpr double kTargetFieldInitStep{2.5};  // Step between nodal points to determine field near target [cm]
+    static constexpr int kTargetMaterialMapNofBins{20};
+
+    std::set<GeoLayer<int>> fGeoLayers{};                                ///< Set of geo layers
+    std::vector<MaterialMap> fvMaterial{};                               ///< Material map container
+    std::shared_ptr<IMaterialMapFactory> fpMaterialMapFactory{nullptr};  ///< Material map creator
+    ModuleIndexMapFactory fModuleIndexFactory;                           ///< Module index factory
+    FieldFactory fFieldFactory;                                          ///< Instance of field factory
+    Target<double> fTarget;                                              ///< Target properties
+    int fMatMapNofBins{100};                                             ///< Number of bins in material maps
+    bool fbPropertiesInitialized{false};  ///< Flag: if all the necessary fields are initialized
+  };
+
+
+  // ********************************
+  // ** Template method definition **
+  // ********************************
+
+
+  // ---------------------------------------------------------------------------------------------------------------------
+  //
+  template<class EDetID>
+  void SetupBuilder::AddLayer(const GeoLayer<EDetID>& geoLayer)
+  {
+    fbPropertiesInitialized = false;
+    auto layer = fGeoLayers.emplace(static_cast<int>(geoLayer.fDetID), geoLayer.fLocID, geoLayer.fZref, geoLayer.fZmin,
+                                    geoLayer.fZmax, geoLayer.fXmax, geoLayer.fYmax);
+    if (!layer.second) {
+      std::stringstream msg;
+      msg << "SetupBuilder::AddLayer: attempt of adding a duplicating geometry layer: ";
+      msg << "DetID = " << static_cast<int>(geoLayer.fDetID) << ", localID = " << geoLayer.fLocID
+          << "fZref = " << geoLayer.fZref << ", fZmin = " << geoLayer.fZmin << ", fZmax = " << geoLayer.fZmax
+          << ", fXmax = " << geoLayer.fXmax << ", fYmax = " << geoLayer.fYmax
+          << ".\nThe next layers were already added:";
+      for (const auto& el : fGeoLayers) {
+        msg << "\n\t- DetID = " << static_cast<int>(el.fDetID) << ", localID = " << el.fLocID << "fZref = " << el.fZref
+            << ", fZmin = " << el.fZmin << ", fZmax = " << el.fZmax << ", fXmax = " << el.fXmax
+            << ", fYmax = " << el.fYmax;
+      }
+      throw std::logic_error(msg.str());
+    }
+  }
+
+  // ---------------------------------------------------------------------------------------------------------------------
+  //
+  template<typename T>
+  Setup<T> SetupBuilder::MakeSetup() const
+  {
+    Setup<T> setup(fFieldFactory.GetFieldMode());
+
+    if (!fbPropertiesInitialized) {
+      throw std::logic_error("kf::SetupBuilder: attempt to create an uninitialized setup");
+    }
+
+    setup.fTarget = this->fTarget;
+    for (const auto& material : this->fvMaterial) {
+      setup.fvMaterialLayers.push_back(material);
+    }
+    setup.fField          = fFieldFactory.MakeField<T>();
+    setup.fModuleIndexMap = fModuleIndexFactory.MakeIndexMap();
+    return setup;
+  }
+
+  // -------------------------------------------------------------------------------------------------------------------
+  //
+  template<typename T>
+  Setup<T> SetupBuilder::Load(const std::string& fileName)
+  {
+    Setup<double> setup(EFieldMode::Intrpl);
+    std::ifstream ifs(fileName, std::ios::binary);
+    if (!ifs) {
+      std::stringstream msg;
+      msg << "kf::SetupBuilder::Load: intput setup file \"" << fileName << "\" was not found";
+      throw std::runtime_error(msg.str());
+    }
+    try {
+      boost::archive::binary_iarchive ia(ifs);
+      ia >> setup;
+    }
+    catch (const std::exception& err) {
+      std::stringstream msg;
+      msg << "kf::SetupBuilder::Load: input setup file \"" << fileName
+          << "\" has inconsistent format or was "
+             "corrupted. The exception message: "
+          << err.what();
+      throw std::runtime_error(msg.str());
+    }
+    return Setup<T>(setup);
+  }
+}  // namespace cbm::algo::kf
diff --git a/algo/kf/core/geo/KfSetupInitializer.cxx b/algo/kf/core/geo/KfSetupInitializer.cxx
deleted file mode 100644
index 3148dc428d..0000000000
--- a/algo/kf/core/geo/KfSetupInitializer.cxx
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Sergei Zharko [committer] */
-
-/// @file   KfSetupInitializer.h
-/// @brief  A base KF-Setup initialization class (source)
-/// @since  28.03.2024
-/// @author Sergei Zharko <s.zharko@gsi.de>
-
-#include "KfSetupInitializer.h"
-
-using cbm::algo::kf::SetupInitializer;
-
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void SetupInitializer::AddMaterial(const MaterialMap& material)
-{
-  if (!fMaterialLayers.emplace(material).second) {
-    std::stringstream msg;
-    msg << "SetupInitializer::AddMaterial: attempt of adding a duplicating material layer " << material.ToString()
-        << ".\nThe next material layers were already added:";
-    for (const auto& el : fMaterialLayers) {
-      msg << "\n\t- " << el.ToString();
-    }
-    throw std::logic_error(msg.str());
-  }
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void SetupInitializer::Reset()
-{
-  fFieldFactory.Reset();
-  fMaterialLayers.clear();
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void SetupInitializer::SetTargetProperties(double x, double y, double z, double fieldInitStep,
-                                           const MaterialMap& material)
-{
-  fTarget.SetX(x);
-  fTarget.SetY(y);
-  fTarget.SetZ(z);
-  fTarget.SetMaterial(material);
-  fFieldFactory.SetTarget(x, y, z);
-  fFieldFactory.SetStep(fieldInitStep);
-}
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void SetupInitializer::Store(const Setup<double>& setup, const std::string& fileName)
-{
-  std::ofstream ofs(fileName, std::ios::binary);
-  if (!ofs) {
-    std::stringstream msg;
-    msg << "kf::SetupInitializer::Store: failed openning file \"" << fileName << "\" to store the setup";
-    throw std::runtime_error(msg.str());
-  }
-  boost::archive::binary_oarchive oa(ofs);
-  oa << setup;
-}
diff --git a/algo/kf/core/geo/KfSetupInitializer.h b/algo/kf/core/geo/KfSetupInitializer.h
deleted file mode 100644
index 1f2f51e51c..0000000000
--- a/algo/kf/core/geo/KfSetupInitializer.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Sergei Zharko [committer] */
-
-/// @file   KfSetupInitializer.h
-/// @brief  A base KF-Setup initialization class (header)
-/// @since  28.03.2024
-/// @author Sergei Zharko <s.zharko@gsi.de>
-
-#pragma once  // include this header only once per compilation unit
-
-#include "KfSetup.h"
-
-#include <boost/archive/binary_iarchive.hpp>
-#include <boost/archive/binary_oarchive.hpp>
-
-#include <fstream>
-#include <optional>
-#include <sstream>
-#include <string>
-#include <vector>
-
-namespace cbm::algo::kf
-{
-  /// \class  SetupInitializer
-  /// \brief  Creates a valid initialized Setup instance
-  class SetupInitializer {
-   public:
-    /// \brief Default constructor
-    SetupInitializer() = default;
-
-    /// \brief Copy constructor
-    SetupInitializer(const SetupInitializer&) = delete;
-
-    /// \brief Move constructor
-    SetupInitializer(SetupInitializer&&) = delete;
-
-    /// \brief Destructor
-    virtual ~SetupInitializer() = default;
-
-    /// \brief Copy assignment operator
-    SetupInitializer& operator=(const SetupInitializer&) = delete;
-
-    /// \brief Move assignment operator
-    SetupInitializer& operator=(SetupInitializer&&) = delete;
-
-    /// \brief Adds magnetic field slice reference
-    /// \param halfSizeX  Half-size of the slice in x-direction [cm]
-    /// \param halfSizeY  Half-size of the slice in y-direction [cm]
-    /// \param refZ       Reference z-position of the slice [cm]
-    void AddFieldSliceReference(double halfSizeX, double halfSizeY, double refZ)
-    {
-      fFieldFactory.AddSliceReference(halfSizeX, halfSizeY, refZ);
-    }
-
-    /// \brief Adds material layer
-    /// \param material  Material layer
-    void AddMaterial(const MaterialMap& material);
-
-    /// \brief  Virtual function, which initializes a KF-setup
-    /// \return true  Initialization was successful
-    /// \return false Initialization failed
-    ///
-    /// This function can be re-implemented for a particular use-case...
-    virtual bool InitProperties() { return false; }
-
-    /// \brief Creates a setup instance
-    template<typename T>
-    Setup<T> MakeSetup() const;
-
-    /// \brief Resets the instance
-    void Reset();
-
-    /// \brief Sets magnetic field function
-    /// \param fieldMode  Magnetic field mode:
-    /// \param fieldFn    Magnetic field function
-    /// \param fieldType  Magnetic field type
-    void SetFieldProperty(EFieldMode fieldMode, const FieldFn_t& fieldFn, EFieldType fieldType)
-    {
-      fFieldFactory.SetFieldFunction(fieldFn, fieldType);
-      fFieldFactory.SetFieldMode(fieldMode);
-    }
-
-    /// \brief Sets target initialization properties
-    /// \param x               Target x-coordinate [cm]
-    /// \param y               Target y-coordinate [cm]
-    /// \param z               Target z-coordinate [cm]
-    /// \param fieldInitStep   Step between the nodal points in the target field region initialization [cm]
-    /// \param material        Target material layer
-    void SetTargetProperties(double x, double y, double z, double fieldInitStep, const MaterialMap& material);
-
-    /// \brief  Stores a serialized setup to a file
-    /// \param  setup     A reference to the Setup (NOTE: a double-Setup must be passed explicitly)
-    /// \param  fileName  Output file name
-    ///
-    /// Only a Setup with T = double can be serialized, so if a particular setup instance has another floating-point
-    /// type, it will be converted to the double-version. In the serialization only the interpolated magnetic field
-    /// variant is stored, the original field version will be set to nullopt during the loading from the file.
-    static void Store(const Setup<double>& setup, const std::string& fileName);
-
-    /// \brief  Loads a serialized setup from a file
-    /// \tparam T         Underlying floating-point type for the output setup object
-    /// \param  fileName  Input file name
-    /// \throw  std::runtime_error  If the fileName cannot be opened
-    template<typename T>
-    static Setup<T> Load(const std::string& fileName);
-
-   private:
-    std::set<MaterialMap> fMaterialLayers{};  ///< Set of material maps
-    FieldFactory fFieldFactory;               ///< Instance of field factory
-    Target<double> fTarget;                   ///< Field to keep target properties
-    bool fbPropertiesInitialized{false};      ///< Flag: if all the necessary fields are initialized
-  };
-
-
-  // ********************************
-  // ** Template method definition **
-  // ********************************
-
-  // ---------------------------------------------------------------------------------------------------------------------
-  //
-  template<typename T>
-  Setup<T> SetupInitializer::MakeSetup() const
-  {
-    Setup<T> setup(fFieldFactory.GetFieldMode());
-    // Target initialization
-    setup.SetTarget(fTarget);
-
-    // Field initialization
-    setup.SetField(fFieldFactory.MakeField<double>());
-
-    // Material layers initialization
-    for (const auto& material : fMaterialLayers) {
-      setup.AddMaterial(material);
-    }
-
-    return setup;
-  }
-
-  // -------------------------------------------------------------------------------------------------------------------
-  //
-  template<typename T>
-  Setup<T> SetupInitializer::Load(const std::string& fileName)
-  {
-    Setup<double> setup(EFieldMode::Intrpl);
-    std::ifstream ifs(fileName, std::ios::binary);
-    if (!ifs) {
-      std::stringstream msg;
-      msg << "kf::SetupInitializer::Load: intput setup file \"" << fileName << "\" was not found";
-      throw std::runtime_error(msg.str());
-    }
-    try {
-      boost::archive::binary_iarchive ia(ifs);
-      ia >> setup;
-    }
-    catch (const std::exception& err) {
-      std::stringstream msg;
-      msg << "kf::SetupInitializer::Load: input setup file \"" << fileName
-          << "\" has inconsistent format or was "
-             "corrupted. The exception message: "
-          << err.what();
-      throw std::runtime_error(msg.str());
-    }
-    return Setup<T>(setup);
-  }
-}  // namespace cbm::algo::kf
diff --git a/algo/kf/core/geo/KfTarget.cxx b/algo/kf/core/geo/KfTarget.cxx
index 6f4864d125..bc8b00a188 100644
--- a/algo/kf/core/geo/KfTarget.cxx
+++ b/algo/kf/core/geo/KfTarget.cxx
@@ -17,11 +17,12 @@ using cbm::algo::kf::Target;
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<typename T>
-Target<T>::Target(const MaterialMap& material, double x, double y, double z)
-  : fMaterial(material)
-  , fX(utils::simd::Cast<double, T>(x))
+Target<T>::Target(double x, double y, double z, double dz, double r)
+  : fX(utils::simd::Cast<double, T>(x))
   , fY(utils::simd::Cast<double, T>(y))
   , fZ(utils::simd::Cast<double, T>(z))
+  , fDz(utils::simd::Cast<double, T>(dz))
+  , fR(utils::simd::Cast<double, T>(r))
 {
 }
 
@@ -46,6 +47,7 @@ std::string Target<T>::ToString(int indentLevel, int verbose) const
   std::string indent(indentLevel, IndentChar);
   auto Cnv = [&](const auto& val) { return utils::simd::Cast<T, Literal_t<T>>(val); };  // alias for the conversion fn
   msg << indent << "position: {" << Cnv(fX) << ", " << Cnv(fY) << ", " << Cnv(fZ) << "} [cm]\n";
+  msg << indent << "half-thickness: " << Cnv(fDz) << " [cm]\n";
   msg << indent << "material:\n" << indent << IndentChar << "  " << fMaterial.ToString(verbose);
   return msg.str();
 }
diff --git a/algo/kf/core/geo/KfTarget.h b/algo/kf/core/geo/KfTarget.h
index 51ab42ed1c..e901c6c58f 100644
--- a/algo/kf/core/geo/KfTarget.h
+++ b/algo/kf/core/geo/KfTarget.h
@@ -31,11 +31,12 @@ namespace cbm::algo::kf
     Target() = default;
 
     /// \brief Constructor from parameters
-    /// \param material  Instance of the material budget map near the target region
     /// \param x         x-coordinate of the nominal target center [cm]
     /// \param y         y-coordinate of the nominal target center [cm]
     /// \param z         z-coordinate of the nominal target center [cm]
-    Target(const MaterialMap& material, double x, double y, double z);
+    /// \param dz        half-thickness of the target [cm]
+    /// \param r         size of target
+    Target(double x, double y, double z, double dz, double r);
 
     /// \brief Copy constructor
     /// \tparam I  Underlying floating-point type of the source
@@ -45,6 +46,8 @@ namespace cbm::algo::kf
       , fX(utils::simd::Cast<I, T>(other.fX))
       , fY(utils::simd::Cast<I, T>(other.fY))
       , fZ(utils::simd::Cast<I, T>(other.fZ))
+      , fDz(utils::simd::Cast<I, T>(other.fDz))
+      , fR(utils::simd::Cast<I, T>(other.fR))
     {
     }
 
@@ -57,12 +60,18 @@ namespace cbm::algo::kf
     /// \brief Gets x-coordinate of the nominal target center
     const T& GetX() const { return fX; }
 
-    /// \brief Gets x-coordinate of the nominal target center
+    /// \brief Gets y-coordinate of the nominal target center
     const T& GetY() const { return fY; }
 
-    /// \brief Gets x-coordinate of the nominal target center
+    /// \brief Gets z-coordinate of the nominal target center
     const T& GetZ() const { return fZ; }
 
+    /// \brief Gets target half-thickness
+    const T& GetDz() const { return fDz; }
+
+    /// \brief Gets transverse size of target
+    const T& GetR() const { return fR; }
+
     /// \brief Gets material map
     const MaterialMap& GetMaterial() const { return fMaterial; }
 
@@ -82,6 +91,14 @@ namespace cbm::algo::kf
     /// \param z  x-coordinate [cm]
     void SetZ(const T& z) { fZ = z; }
 
+    /// \brief Sets target half-thickness
+    /// \param dz  half-thickness [cm]
+    void SetDz(const T& dz) { fDz = dz; }
+
+    /// \brief Sets target transverse size
+    /// \brief Transverse size of target [cm]
+    void SetR(const T& r) { fR = r; }
+
     /// \brief String representation of the class
     /// \param indentLevel  Indent level of the string output
     /// \param verbose      Verbosity level
@@ -97,11 +114,15 @@ namespace cbm::algo::kf
       ar& fX;
       ar& fY;
       ar& fZ;
+      ar& fDz;
+      ar& fR;
     }
 
     MaterialMap fMaterial{};  ///< Material map in the target region
     T fX{defs::Undef<T>};     ///< x-coordinate of the nominal target center [cm]
     T fY{defs::Undef<T>};     ///< y-coordinate of the nominal target center [cm]
     T fZ{defs::Undef<T>};     ///< z-coordinate of the nominal target center [cm]
+    T fDz{defs::Undef<T>};    ///< Half-thickness of the target [cm]
+    T fR{defs::Undef<T>};     ///< Half-thickness of the target [cm]
   };
 }  // namespace cbm::algo::kf
diff --git a/reco/L1/CMakeLists.txt b/reco/L1/CMakeLists.txt
index 8201ea78ec..8d8b26c1ae 100644
--- a/reco/L1/CMakeLists.txt
+++ b/reco/L1/CMakeLists.txt
@@ -162,7 +162,6 @@ set(PRIVATE_DEPENDENCIES
   CbmRecoSts  # <==== !!!! was bringing dependency on the "online" version of the Algo library which brought the NO_ROOT flag !!!!!
   CbmSimSteer
   CbmRecoBase
-  KfCbm
   KFParticle
   external::yaml-cpp
   FairRoot::GeoBase
diff --git a/reco/L1/CbmKfTrackingSetupInitializer.cxx b/reco/L1/CbmKfTrackingSetupInitializer.cxx
deleted file mode 100644
index 9650ac1588..0000000000
--- a/reco/L1/CbmKfTrackingSetupInitializer.cxx
+++ /dev/null
@@ -1,195 +0,0 @@
-/* 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
deleted file mode 100644
index 50e643bb15..0000000000
--- a/reco/L1/CbmKfTrackingSetupInitializer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* 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 ca54da6acc..55488de212 100644
--- a/reco/L1/CbmL1.cxx
+++ b/reco/L1/CbmL1.cxx
@@ -544,17 +544,18 @@ try {
     // Creating a setup
     auto pSetupInitializer = std::make_unique<TrackingSetupInitializer>();
     pSetupInitializer->Use(fUseMVD, fUseSTS, fUseMUCH, fUseTRD, fUseTOF);
-    pSetupInitializer->InitProperties();
+    pSetupInitializer->Init(cbm::algo::kf::EFieldMode::Intrpl);
     auto trackerSetup = pSetupInitializer->MakeSetup<double>();
-    LOG(info) << "!!!!\n!!!!\n!!!!\n!!!! KF SETUP:\n" << trackerSetup.ToString(0) << "\n!!!!\n!!!!\n!!!!";
+    LOG(info) << "!!!!\n!!!!\n!!!!\n!!!! KF SETUP:\n"
+              << trackerSetup.ToString(0) << "\nsize: " << sizeof(trackerSetup) << "\n!!!!\n!!!!\n!!!!";
 
     // Storing setup
-    TrackingSetupInitializer::Store(trackerSetup, "./trackerSetup.geo.kf.bin");
+    cbm::algo::kf::SetupBuilder::Store(trackerSetup, "./trackerSetup.geo.kf.bin");
 
     // Reading setup (now in fvec):
-    auto trackerSetupVec = TrackingSetupInitializer::Load<fvec>("./trackerSetup.geo.kf.bin");
+    auto trackerSetupVec = cbm::algo::kf::SetupBuilder::Load<fvec>("./trackerSetup.geo.kf.bin");
     LOG(info) << "!!!!\n!!!!\n!!!!\n!!!! KF SETUP (from file):\n"
-              << trackerSetupVec.ToString(1) << "\n!!!!\n!!!!\n!!!!";
+              << trackerSetupVec.ToString(1) << "\nsize:" << sizeof(trackerSetupVec) << "\n!!!!\n!!!!\n!!!!";
 
 
     {
diff --git a/reco/L1/CbmL1DetectorID.h b/reco/L1/CbmL1DetectorID.h
index 5ecdda9522..72258838ac 100644
--- a/reco/L1/CbmL1DetectorID.h
+++ b/reco/L1/CbmL1DetectorID.h
@@ -10,8 +10,8 @@
 #pragma once
 
 //#include "CaDefs.h"
-#include "CbmEnumArray.h"
 #include "CbmDefs.h"
+#include "CbmEnumArray.h"
 
 #include <string>
 
diff --git a/reco/L1/CbmL1Util.cxx b/reco/L1/CbmL1Util.cxx
index 393b966555..745f6db483 100644
--- a/reco/L1/CbmL1Util.cxx
+++ b/reco/L1/CbmL1Util.cxx
@@ -3,8 +3,9 @@
    Authors: Sergey Gorbunov [committer] */
 
 #include "CbmL1Util.h"
-#include "FairTrackParam.h"
+
 #include "CaDefs.h"
+#include "FairTrackParam.h"
 
 namespace cbm::L1Util
 {
diff --git a/reco/kfnew/CbmKfTrackingSetupInitializer.cxx b/reco/kfnew/CbmKfTrackingSetupInitializer.cxx
index 107431d132..bfb13b1c3f 100644
--- a/reco/kfnew/CbmKfTrackingSetupInitializer.cxx
+++ b/reco/kfnew/CbmKfTrackingSetupInitializer.cxx
@@ -20,22 +20,21 @@
 #include "FairField.h"
 #include "FairRunAna.h"
 #include "KfDefs.h"
-#include "KfMaterialMapCreator.h"
+#include "KfMaterialMapFactory.h"
 #include "Logger.h"
 
-#include "KfModuleIndexMap.h"
-
 #include <functional>
 
 using cbm::kf::TrackingSetupInitializer;
-using kf::tools::MaterialMapCreator;
+using kf::tools::MaterialMapFactory;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-bool TrackingSetupInitializer::InitProperties()
+bool TrackingSetupInitializer::Init(cbm::algo::kf::EFieldMode fldMode)
 try {
-  using cbm::algo::kf::EFieldMode;
   using cbm::algo::kf::EFieldType;
+  using cbm::algo::kf::GeoLayer;
+  fBuilder.Reset();
 
   // Check, if a subsystem exists in the setup
   fbUseMvd &= CbmSetup::Instance()->IsActive(ECbmModuleId::kMvd);
@@ -46,146 +45,51 @@ try {
 
   // Magnetic field initialization
   if (FairRunAna::Instance()->GetField()) {
-    this->SetFieldProperty(EFieldMode::Intrpl, OriginalField(), EFieldType::Normal);
+    fBuilder.SetFieldProperty(fldMode, OriginalField(), EFieldType::Normal);
   }
   else {
-    this->SetFieldProperty(EFieldMode::Intrpl, ZeroField(), EFieldType::Null);
+    fBuilder.SetFieldProperty(fldMode, 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]
-      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 = [&](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))),
-                                     .detID = detID,
-                                     .iStLoc = iSt});
-      }
-    };
-    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();
-
-    // 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));
+  auto CollectStations = [&](const auto* pIfs, ETrackingDetID detID) -> void {
+    if (!pIfs) {
+      return;
     }
-
-    
-
-    // 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;
-      if (std::next(layerIt) != geoStations.end()) {
-        z2 = std::next(layerIt)->zMin;
+    for (int iSt = 0; iSt < pIfs->GetNtrackingStations(); ++iSt) {
+      if (iSt == 1 && detID == ETrackingDetID::Mvd || iSt == 2 && detID == ETrackingDetID::Sts) {
+        continue;  // !!!!!!!!!!!!! TEST
       }
-      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);
-      indexMapInitializer.AddComponent(layerIt->detID, layerIt->iStLoc, layerIt->zRef);
-      zLast = zNew;
+      fBuilder.AddLayer(
+        GeoLayer<ETrackingDetID>{.fDetID = detID,  // ca::Tracking detector id scheme
+                                 .fLocID = iSt,    // ca::Tracking station indexing
+                                 .fZref  = pIfs->GetZref(iSt),
+                                 .fZmin  = pIfs->GetZmin(iSt),
+                                 .fZmax  = pIfs->GetZmax(iSt),
+                                 .fXmax  = std::max(std::fabs(pIfs->GetXmin(iSt)), std::fabs(pIfs->GetXmax(iSt))),
+                                 .fYmax  = std::max(std::fabs(pIfs->GetYmin(iSt)), std::fabs(pIfs->GetYmax(iSt)))});
     }
+  };
+  CollectStations(fbUseMvd ? CbmMvdTrackingInterface::Instance() : nullptr, ETrackingDetID::Mvd);
+  CollectStations(fbUseSts ? CbmStsTrackingInterface::Instance() : nullptr, ETrackingDetID::Sts);
+  CollectStations(fbUseMuch ? CbmMuchTrackingInterface::Instance() : nullptr, ETrackingDetID::Much);
+  CollectStations(fbUseTrd ? CbmTrdTrackingInterface::Instance() : nullptr, ETrackingDetID::Trd);
+  CollectStations(fbUseTof ? CbmTofTrackingInterface::Instance() : nullptr, ETrackingDetID::Tof);
 
-    auto indexMap = indexMapInitializer.MakeIndexMap();
-    LOG(info) << "---> Index map: " << indexMap.ToString();
+  // Retriev target properties
+  const auto* pTarget = Target::Instance();
+  fBuilder.SetTargetProperty(pTarget->GetX(), pTarget->GetY(), pTarget->GetZ(), pTarget->GetDz(), pTarget->GetRmax());
 
+  // Init material map creator
+  auto pMaterialFactory = std::make_shared<MaterialMapFactory>();
+  pMaterialFactory->SetSafeMaterialInitialization(kMatCreatorSafeMode);
+  pMaterialFactory->SetDoRadialProjection(pTarget->GetZ());
+  pMaterialFactory->SetNraysPerDim(kMatCreatorNrays);
+  fBuilder.SetMaterialMapFactory(pMaterialFactory);
 
-    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);
-      }
-    }
-  }
+  fBuilder.Init();
+
   LOG(info) << "kf::TrackingSetupInitializer: Tracking setup was initialized successfully";
   return true;
 }
diff --git a/reco/kfnew/CbmKfTrackingSetupInitializer.h b/reco/kfnew/CbmKfTrackingSetupInitializer.h
index 42ff65f9f0..73fc04f2a3 100644
--- a/reco/kfnew/CbmKfTrackingSetupInitializer.h
+++ b/reco/kfnew/CbmKfTrackingSetupInitializer.h
@@ -9,7 +9,7 @@
 
 #pragma once
 
-#include "KfSetupInitializer.h"
+#include "KfSetupBuilder.h"
 
 #include <tuple>
 
@@ -21,26 +21,23 @@ namespace cbm::kf
   // 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,
+  enum class ETrackingDetID
+  {
+    Mvd = 0,
+    Sts,
     Much,
-    Trd = 0x40,
-    Tof = 0x30,
+    Trd,
+    Tof,
     END
   };
 
   /// \class TrackingSetupInitializer
   /// \brief Encapsulation of the kf::Setup initialization routines for CBM
-  class TrackingSetupInitializer : public cbm::algo::kf::SetupInitializer {
+  class TrackingSetupInitializer {
    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;
+    /// \param  fldMode  Field mode
+    bool Init(cbm::algo::kf::EFieldMode fldMode);
 
     /// \brief  Enables/disables detector subsystems in the setup
     /// \param  mvd   Is MVD used
@@ -50,7 +47,16 @@ namespace cbm::kf
     /// \param  tof   Is TOF used
     void Use(bool mvd, bool sts, bool much, bool trd, bool tof);
 
+    /// \brief Makes setup object
+    template<typename T>
+    cbm::algo::kf::Setup<T> MakeSetup()
+    {
+      return fBuilder.MakeSetup<T>();
+    }
+
    private:
+    cbm::algo::kf::SetupBuilder fBuilder{};
+
     // 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
diff --git a/reco/kfnew/tools/CMakeLists.txt b/reco/kfnew/tools/CMakeLists.txt
index 3a072d4a73..2f4a9baf52 100644
--- a/reco/kfnew/tools/CMakeLists.txt
+++ b/reco/kfnew/tools/CMakeLists.txt
@@ -3,7 +3,7 @@ set(INCLUDE_DIRECTORIES
 )
 
 set(SRCS 
-  ${CMAKE_CURRENT_SOURCE_DIR}/KfMaterialMapCreator.cxx
+  ${CMAKE_CURRENT_SOURCE_DIR}/KfMaterialMapFactory.cxx
 )
 
 SET_SOURCE_FILES_PROPERTIES(${SRCS} PROPERTIES COMPILE_FLAGS "-O3")
@@ -55,7 +55,7 @@ install(TARGETS KfTools DESTINATION lib)
 
 install(
   FILES
-    KfMaterialMapCreator.h
+    KfMaterialMapFactory.h
   DESTINATION
     include/
 )
diff --git a/reco/kfnew/tools/KfMaterialMapCreator.cxx b/reco/kfnew/tools/KfMaterialMapFactory.cxx
similarity index 89%
rename from reco/kfnew/tools/KfMaterialMapCreator.cxx
rename to reco/kfnew/tools/KfMaterialMapFactory.cxx
index b138863da4..49437007ee 100644
--- a/reco/kfnew/tools/KfMaterialMapCreator.cxx
+++ b/reco/kfnew/tools/KfMaterialMapFactory.cxx
@@ -2,13 +2,13 @@
    SPDX-License-Identifier: GPL-3.0-only
    Authors: Sergei Zharko [committer] */
 
-/// \file   KfMaterialMapCreator.cxx
+/// \file   KfMaterialMapFactory.cxx
 /// \brief  Utility to generate material budget map from the TGeoNavigator representation of the Setup (implementation)
 /// \author Sergey Gorbunov <se.gorbunov@gsi.de>
 /// \author Sergei Zharko <s.zharko@gsi.de>
 /// \date   29.08.2024
 
-#include "KfMaterialMapCreator.h"
+#include "KfMaterialMapFactory.h"
 
 #include "KfMaterialMap.h"
 #include "TGeoManager.h"
@@ -24,11 +24,11 @@
 #include <thread>
 
 using cbm::algo::kf::MaterialMap;
-using kf::tools::MaterialMapCreator;
+using kf::tools::MaterialMapFactory;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-MaterialMapCreator::MaterialMapCreator(int verbose) : fVerbose(verbose)
+MaterialMapFactory::MaterialMapFactory(int verbose) : fVerbose(verbose)
 {
   // constructor
 
@@ -67,7 +67,7 @@ MaterialMapCreator::MaterialMapCreator(int verbose) : fVerbose(verbose)
   msg << "\n    - fix illegal overlaps in the geometry via gGeoManager->CheckOverlaps()";
   msg << "\n    - run with CbmL1::SetSafeMaterialInitialization() option. ";
   msg << "\n      It fixes the crash, but slows down the initialization significantly.";
-  msg << "\n    - manually disable voxel finders for problematic volumes in CaToolsMaterialMapCreator.cxx";
+  msg << "\n    - manually disable voxel finders for problematic volumes in CaToolsMaterialMapFactory.cxx";
   msg << '\n';
   msg << "\n------------------------------------------------------------------------------------";
   LOG_IF(info, fVerbose > 0) << msg.str();
@@ -143,7 +143,7 @@ MaterialMapCreator::MaterialMapCreator(int verbose) : fVerbose(verbose)
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-MaterialMapCreator::~MaterialMapCreator()
+MaterialMapFactory::~MaterialMapFactory()
 {
   // destructor
 
@@ -172,7 +172,7 @@ MaterialMapCreator::~MaterialMapCreator()
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-TGeoNavigator* MaterialMapCreator::GetCurrentNavigator(int iThread)
+TGeoNavigator* MaterialMapFactory::GetCurrentNavigator(int iThread)
 {
   // Get navigator for current thread, create it if it doesnt exist.
   // Produce an error when anything goes wrong
@@ -187,12 +187,12 @@ TGeoNavigator* MaterialMapCreator::GetCurrentNavigator(int iThread)
     }
 
     if (navi != gGeoManager->GetCurrentNavigator()) {
-      LOG(fatal) << "ca::tools::MaterialMapCreator: unexpected behavior of TGeoManager::AddNavigator() !!";
+      LOG(fatal) << "ca::tools::MaterialMapFactory: unexpected behavior of TGeoManager::AddNavigator() !!";
     }
   }
 
   if (!navi) {
-    LOG(fatal) << "ca::tools::MaterialMapCreator: can not find / create TGeoNavigator for thread " << iThread;
+    LOG(fatal) << "ca::tools::MaterialMapFactory: can not find / create TGeoNavigator for thread " << iThread;
   }
 
   return navi;
@@ -200,7 +200,7 @@ TGeoNavigator* MaterialMapCreator::GetCurrentNavigator(int iThread)
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void MaterialMapCreator::CleanUpThreads()
+void MaterialMapFactory::CleanUpThreads()
 {
   // clean up thread data in TGeoManager
 
@@ -212,7 +212,7 @@ void MaterialMapCreator::CleanUpThreads()
   GetCurrentNavigator(-1);
 }
 
-void MaterialMapCreator::InitThreads()
+void MaterialMapFactory::InitThreads()
 {
   // (re)initialise the number of threads in TGeoManager
 
@@ -230,21 +230,22 @@ void MaterialMapCreator::InitThreads()
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-MaterialMap MaterialMapCreator::GenerateMaterialMap(double zRef, double zMin, double zMax, double xyMax, int nBinsDim)
+MaterialMap MaterialMapFactory::GenerateMaterialMap(double zRef, double zMin, double zMax, double xyMax, int nBinsDim)
 {
   if (fDoRadialProjection) {
-    if (fTargetZ >= zRef - 0.1) {
+    if (fTargetZ + 0.05 >= zRef) {
       LOG(warn)
-        << "kf::tools::MaterialMapCreator: the material reference z-coordinate must be at least 0.1 cm downstream "
+        << "kf::tools::MaterialMapFactory: the material reference z-coordinate must be at least 0.1 cm downstream "
            "the target. Shifting the reference z-coordinate to the lower limit: target Z = "
         << fTargetZ << ", material reference z = " << zRef;
     }
-    zRef = std::max(zRef, fTargetZ + 1.);
+    zRef = std::max(zRef, fTargetZ + 0.05);
     zMin = std::max(fTargetZ, zMin);
+    zMax = std::max(zMax, zRef + 0.05);
   }
 
   if (!(zMin <= zRef && zRef <= zMax)) {
-    LOG(fatal) << "kf::tools::MaterialMapCreator: the material parameters are inconsistent. It must be: zMin " << zMin
+    LOG(fatal) << "kf::tools::MaterialMapFactory: the material parameters are inconsistent. It must be: zMin " << zMin
                << " <= zRef " << zRef << " <= zMax " << zMax;
   }
 
@@ -263,8 +264,8 @@ MaterialMap MaterialMapCreator::GenerateMaterialMap(double zRef, double zMin, do
     nThreadRays[i]    = 0;
   }
 
-  LOG_IF(info, fVerbose > 1) << "kf::tools::MaterialMapCreator: Generate material map using " << fNthreads
-                             << " threads..";
+  LOG_IF(info, fVerbose > -1) << "kf::tools::MaterialMapFactory: Generate material map using " << fNthreads
+                              << " threads..";
 
   auto naviThread = [&](int iThread) {
     // create a navigator for this thread
@@ -306,24 +307,24 @@ MaterialMap MaterialMapCreator::GenerateMaterialMap(double zRef, double zMin, do
 
               if (!node) {
                 // may happen when tracing outside of the CBM volume -> produce a warning
-                LOG(warning) << "kf::tools::MaterialMapCreator: TGeoNavigator can not find the geo node";
+                LOG(warning) << "kf::tools::MaterialMapFactory: TGeoNavigator can not find the geo node";
                 break;
               }
 
               TGeoMedium* medium = node->GetMedium();
               if (!medium) {
-                LOG(fatal) << "kf::tools::MaterialMapCreator: TGeoNavigator can not find the geo medium";
+                LOG(fatal) << "kf::tools::MaterialMapFactory: TGeoNavigator can not find the geo medium";
               }
 
               TGeoMaterial* material = medium->GetMaterial();
               if (!material) {
-                LOG(fatal) << "kf::tools::MaterialMapCreator: TGeoNavigator can not find the geo material";
+                LOG(fatal) << "kf::tools::MaterialMapFactory: TGeoNavigator can not find the geo material";
               }
 
               double radLen = material->GetRadLen();
 
               if (radLen < kMinRadLength) {  // 0.5612 is rad. length of Lead at normal density
-                LOG(fatal) << "kf::tools::MaterialMapCreator: failed assertion! "
+                LOG(fatal) << "kf::tools::MaterialMapFactory: failed assertion! "
                            << "     TGeoNavigator returns a suspicious material with an unrealistic "
                            << "radiation length of " << radLen << " cm. "
                            << "     The allowed minimum is 0.56 cm (Lead has 0.5612 cm). Check your material! "
@@ -356,7 +357,7 @@ MaterialMap MaterialMapCreator::GenerateMaterialMap(double zRef, double zMin, do
                 }
                 else {
                   LOG(fatal)
-                    << "kf::tools::MaterialMapCreator: TGeoNavigator propagates the ray upstream. Something is wrong."
+                    << "kf::tools::MaterialMapFactory: TGeoNavigator propagates the ray upstream. Something is wrong."
                     << " z old " << z << " z new " << zNew << ", dz " << dz;
                 }
               }
@@ -367,7 +368,7 @@ MaterialMap MaterialMapCreator::GenerateMaterialMap(double zRef, double zMin, do
             nRays++;
             nThreadRays[iThread]++;
             if (fVerbose > 2 && nThreadRays[iThread] % 1000000 == 0) {
-              LOG(info) << "kf::tools::MaterialMapCreator:  report from thread " << iThread << ":   material map is "
+              LOG(info) << "kf::tools::MaterialMapFactory:  report from thread " << iThread << ":   material map is "
                         << 100. * nThreadRays[iThread] / nThreadRaysExpected << " \% done";
             }
           }
@@ -400,7 +401,7 @@ MaterialMap MaterialMapCreator::GenerateMaterialMap(double zRef, double zMin, do
     nCrosses += nThreadCrosses[i];
   }
 
-  LOG_IF(info, fVerbose > 0) << "kf::tools::MaterialMapCreator:     shooted " << nRays << " rays. Each ray crossed "
+  LOG_IF(info, fVerbose > 0) << "kf::tools::MaterialMapFactory:     shooted " << nRays << " rays. Each ray crossed "
                              << nCrosses * 1. / nRays << " material boundaries in average";
 
   return matBudget;
diff --git a/reco/kfnew/tools/KfMaterialMapCreator.h b/reco/kfnew/tools/KfMaterialMapFactory.h
similarity index 91%
rename from reco/kfnew/tools/KfMaterialMapCreator.h
rename to reco/kfnew/tools/KfMaterialMapFactory.h
index 4814228e60..60de48e78f 100644
--- a/reco/kfnew/tools/KfMaterialMapCreator.h
+++ b/reco/kfnew/tools/KfMaterialMapFactory.h
@@ -2,7 +2,7 @@
    SPDX-License-Identifier: GPL-3.0-only
    Authors: Sergei Zharko [committer] */
 
-/// \file   KfMaterialMapCreator.h
+/// \file   KfMaterialMapFactory.h
 /// \brief  Utility to generate material budget map from the TGeoNavigator representation of the Setup (implementation)
 /// \author Sergey Gorbunov <se.gorbunov@gsi.de>
 /// \author Sergei Zharko <s.zharko@gsi.de>
@@ -10,6 +10,7 @@
 
 #pragma once
 
+#include "KfIMaterialMapFactory.h"
 #include "Rtypes.h"
 #include "TObject.h"
 
@@ -21,16 +22,16 @@ namespace cbm::algo::kf
 
 namespace kf::tools
 {
-  /// \class MaterialMapCreator
+  /// \class MaterialMapFactory
   /// \brief An utility class to create a material budget map from the TGeo
-  class MaterialMapCreator {
+  class MaterialMapFactory : public cbm::algo::kf::IMaterialMapFactory {
    public:
     /// \brief Constructor from parameters
     /// \param verbose  Verbosity level (0 - only warning/error output)
-    MaterialMapCreator(int verbose = 0);
+    MaterialMapFactory(int verbose = 0);
 
     /// \brief Destructor
-    ~MaterialMapCreator();
+    ~MaterialMapFactory();
 
     /// \brief Project rays radially from the targetZ througth the XY-bins at a reference z.
     /// \param targetZ  z-coordinate of the target [cm]
@@ -65,7 +66,8 @@ namespace kf::tools
     ///
     /// When doRadialProjection==false the rays are shoot horizontally along the Z axis
     ///
-    cbm::algo::kf::MaterialMap GenerateMaterialMap(double zRef, double zMin, double zMax, double xyMax, int nBinsDim);
+    cbm::algo::kf::MaterialMap GenerateMaterialMap(double zRef, double zMin, double zMax, double xyMax,
+                                                   int nBinsDim) override;
 
     /// \brief Enables safe mode of the material initialization
     void SetSafeMaterialInitialization(bool val = true) { fDoSafeInitialization = val; }
-- 
GitLab