From 2cce5b1b415232f9738210c3c4972b3b7130d7a0 Mon Sep 17 00:00:00 2001
From: "s.zharko@gsi.de" <s.zharko@gsi.de>
Date: Sat, 5 Feb 2022 19:17:03 +0100
Subject: [PATCH] L1Algo init interface updates

---
 reco/L1/CMakeLists.txt               |   6 +-
 reco/L1/CbmL1.cxx                    |  93 ++++--
 reco/L1/CbmL1.h                      |  26 +-
 reco/L1/L1Algo/L1Algo.cxx            |  36 ++
 reco/L1/L1Algo/L1Algo.h              |   8 +-
 reco/L1/L1Algo/L1BaseStationInfo.cxx | 482 +++++++++++++++++++++++++++
 reco/L1/L1Algo/L1BaseStationInfo.h   | 446 ++++++-------------------
 reco/L1/L1Algo/L1CAIteration.cxx     |  25 ++
 reco/L1/L1Algo/L1CAIteration.h       | 121 +++++++
 reco/L1/L1Algo/L1Def.h               |   5 +-
 reco/L1/L1Algo/L1InitManager.cxx     | 291 ++++++++++++++++
 reco/L1/L1Algo/L1InitManager.h       | 167 ++++++++--
 reco/L1/L1Algo/L1Parameters.h        | 279 ++++++++--------
 reco/L1/L1Algo/L1Station.h           | 107 ++++--
 reco/L1/L1Algo/L1Vector.h            |   5 +-
 15 files changed, 1510 insertions(+), 587 deletions(-)
 create mode 100644 reco/L1/L1Algo/L1BaseStationInfo.cxx
 create mode 100644 reco/L1/L1Algo/L1CAIteration.cxx
 create mode 100644 reco/L1/L1Algo/L1CAIteration.h
 create mode 100644 reco/L1/L1Algo/L1InitManager.cxx

diff --git a/reco/L1/CMakeLists.txt b/reco/L1/CMakeLists.txt
index 6c6b0fefc5..1861b9a600 100644
--- a/reco/L1/CMakeLists.txt
+++ b/reco/L1/CMakeLists.txt
@@ -140,7 +140,9 @@ L1Algo/L1EventMatch.cxx
 L1Algo/L1MCEvent.cxx
 L1Algo/L1Fit.cxx
 CbmL1MCTrack.cxx
-
+L1Algo/L1CAIteration.cxx
+L1Algo/L1BaseStationInfo.cxx
+L1Algo/L1InitManager.cxx
 L1Algo/utils/L1AlgoDraw.cxx
 L1Algo/utils/L1AlgoEfficiencyPerformance.cxx
 L1Algo/utils/L1AlgoPulls.cxx
@@ -270,6 +272,8 @@ Install(FILES CbmL1Counters.h
               L1Algo/L1UMeasurementInfo.h
               L1Algo/L1XYMeasurementInfo.h
               L1Algo/L1BaseStationInfo.h
+              L1Algo/L1InitManager.h
+              L1Algo/L1CAIteration.h
               L1Algo/L1Parameters.h
               L1Algo/utils/L1Functions.h
               vectors/vec_arithmetic.h
diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx
index 5daeaef357..f340ac7334 100644
--- a/reco/L1/CbmL1.cxx
+++ b/reco/L1/CbmL1.cxx
@@ -768,36 +768,80 @@ InitStatus CbmL1::Init()
 
   algo->SetL1Parameters(fL1Parameters);
 
+
+#ifdef FEATURING_L1ALGO_INIT
   /********************************************************************************************************************
-   *                                                                                                                  *
    *                     EXPERIMENTAL FEATURE: usage of L1InitManager for L1Algo initialization                       *
-   *                                                                                                                  *
-   *   Stage 1: Repeat initialization steps in parallel to the original code                                          *
-   *   Stage 2: Compare two initialization procedures                                                                 *
-   *   Stage 3: Remove old initialization                                                                             *
-   *                                                                                                                  *
    ********************************************************************************************************************/
 
-  // Get reference to the L1Algo initialization manager
+  // NOTE: The 
+
+  // Step 0: Get reference to the L1Algo initialization manager
   L1InitManager * initMan = algo->GetL1InitManager();
+
+  // Step 1: Initialize magnetic field function
+  // Set magnetic field slices
+  auto fieldGetterFcn = 
+    [](const double (&inPos)[3], double (&outB)[3]) {CbmKF::Instance()->GetMagneticField()->GetFieldValue(inPos, outB);};
+  initMan->SetFieldFunction(fieldGetterFcn);
+
+
+  /// TODO: temporary for tests, must be initialized somewhere in run_reco.C or similar
+  fActiveTrackingDetectorIDs = {L1DetectorID::kMvd, L1DetectorID::kSts };
+
+  /// Step 2: initialize IDs of detectors active in tracking
+  initMan->SetActiveDetectorIDs(fActiveTrackingDetectorIDs);
+
+
   constexpr double PI = 3.14159265358; // TODO: why cmath is not used?
 
-  // Fill STS info:
-  for (int iSt = 0; iSt < NStsStations; ++iSt) {
+  /// Step 2: initialize IDs 
+  initMan->SetStationsNumberCrosscheck(L1DetectorID::kMvd, NMvdStations);
+  initMan->SetStationsNumberCrosscheck(L1DetectorID::kSts, NStsStations);
+  initMan->SetStationsNumberCrosscheck(L1DetectorID::kMuch, NMuchStations);
+  
+
+  // Setup MVD stations info
+  for (int iSt = 0; iSt < NMvdStations; ++iSt) { // NOTE: example using in-stack defined objects
+    CbmMvdDetector* mvdDetector     =  CbmMvdDetector::Instance();
+    CbmMvdStationPar* mvdStationPar = mvdDetector->GetParameterFile();
+
+    CbmKFTube& t = CbmKF::Instance()->vMvdMaterial[iSt];
+    auto stationInfo = L1BaseStationInfo(L1DetectorID::kMvd, iSt);
+    stationInfo.SetStationType(1); // MVD // TODO: to be exchanged with specific flags (timeInfo, fieldInfo etc.)
+    stationInfo.SetTimeInfo(0);
+    stationInfo.SetZ(t.z);
+    stationInfo.SetMaterial(t.dz, t.RadLength);
+    stationInfo.SetXmax(t.R);
+    stationInfo.SetYmax(t.R);
+    stationInfo.SetRmin(t.r);
+    stationInfo.SetRmax(t.R);
+    fscal mvdFrontPhi = 0;
+    fscal mvdBackPhi = PI / 2.;
+    fscal mvdFrontSigma = mvdStationPar->GetXRes(iSt) / 10000;
+    fscal mvdBackSigma = mvdStationPar->GetYRes(iSt) / 10000;
+    stationInfo.SetFrontBackStripsGeometry(mvdFrontPhi, mvdFrontSigma, mvdBackPhi, mvdBackSigma);
+    initMan->AddStation(stationInfo);
+  }
+
+  // Setup STS stations info
+  for (int iSt = 0; iSt < NStsStations; ++iSt) { // NOTE: example using smart pointers
     auto cbmSts = CbmStsSetup::Instance()->GetStation(iSt);
-    auto stsStation = new L1BaseStationInfo();
-    stsStation->SetStationID(iSt);
-    stsStation->SetStationType(0); // STS 
+    std::unique_ptr<L1BaseStationInfo> stationInfo(new L1BaseStationInfo(L1DetectorID::kSts, iSt));
+    // TODO: replace with std::make_unique, when C++14 is avaliable!!!!
+    // auto stsStation = std::make_unique<L1BaseStationInfo>(L1DetectorID::kSts, iSt);
+    stationInfo->SetStationType(0); // STS 
+    stationInfo->SetTimeInfo(0);
 
     // Setup station geometry and material
-    stsStation->SetZ(cbmSts->GetZ());
+    stationInfo->SetZ(cbmSts->GetZ());
     double stsXmax = cbmSts->GetXmax();
     double stsYmax = cbmSts->GetYmax();
-    stsStation->SetXmax(stsXmax);
-    stsStation->SetYmax(stsYmax);
-    stsStation->SetRmin(0);
-    stsStation->SetRmax(stsXmax > stsYmax ? stsXmax : stsYmax);
-    stsStation->SetMaterial(cbmSts->GetSensorD(), cbmSts->GetRadLength());
+    stationInfo->SetXmax(stsXmax);
+    stationInfo->SetYmax(stsYmax);
+    stationInfo->SetRmin(0);
+    stationInfo->SetRmax(stsXmax > stsYmax ? stsXmax : stsYmax);
+    stationInfo->SetMaterial(cbmSts->GetSensorD(), cbmSts->GetRadLength());
 
     // Setup strips geometry
     //   TODO: why fscal instead of double in initialization?
@@ -805,22 +849,15 @@ InitStatus CbmL1::Init()
     fscal stsBackPhi  = cbmSts->GetSensorRotation() + cbmSts->GetSensorStereoAngle(1) * PI / 180.;
     fscal stsFrontSigma = cbmSts->GetSensorPitch(0) / sqrt(12);
     fscal stsBackSigma  = stsFrontSigma;
-    stsStation->SetFrontBackStripsGeometry(stsFrontPhi, stsFrontSigma, stsBackPhi, stsBackSigma);
-
-    // Setup magnetic field
-    // NOTE: Such solution is needed to prevent L1Algo from FairRoot dependencies
-    auto getFieldValueFcn = [](const double (&inXYZ)[3], double (&outB)[3]) {
-      CbmKF::Instance()->GetMagneticField()->GetFieldValue(inXYZ, outB);
-    };
-    stsStation->SetFieldSlice(getFieldValueFcn);
-    initMan->AddStation(stsStation);
-    delete stsStation;
+    stationInfo->SetFrontBackStripsGeometry(stsFrontPhi, stsFrontSigma, stsBackPhi, stsBackSigma);
+    initMan->AddStation(stationInfo);
   }
   initMan->PrintStations(/*vebosity = */ 1);
 
   /********************************************************************************************************************
    ********************************************************************************************************************/
 
+#endif // FEATURING_L1ALGO_INIT
 
 
   algo->Init(geo, fUseHitErrors, fTrackingMode, fMissingHits);
diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h
index 4428b32d51..c14f056a6c 100644
--- a/reco/L1/CbmL1.h
+++ b/reco/L1/CbmL1.h
@@ -76,10 +76,22 @@ class CbmL1HitStore {
 public:
   int ExtIndex;
   int iStation;
-  double x, y, time, dx, dy, dt, dxy;
+  double x;
+  double y;
+  double time;
+  double dx;
+  double dy;
+  double dt;
+  double dxy;
   int Det;
 };
 
+
+/// Enumeration for the detector subsystems used in L1 tracking
+/// Note: L1DetectorID has a forward declaration in L1InitManager.h and L1BaseStationInfo.h
+enum class L1DetectorID { kMvd, kSts, kMuch, kTof, kTrd };
+
+
 // TODO: insert documentation!
 //
 /// L1Algo runtime constants modification can be performed in run_reco.C. Example:
@@ -124,6 +136,13 @@ public:
 
   L1Parameters* GetL1Parameters() { return &fL1Parameters; }
 
+  /// Gets a set of active detectors used in tracking
+  // TODO: think about return (value, reference or const reference?)
+  std::set<L1DetectorID> GetActiveTrackingDetectorIDs() const { return fActiveTrackingDetectorIDs; }
+  /// Sets a vector of detectors used in tracking
+  void SetActiveTrackingDetectorIDs(const std::set<L1DetectorID>& init) { fActiveTrackingDetectorIDs = init; }
+
+
   void SetStsMaterialBudgetFileName(TString fileName) { fStsMatBudgetFileName = fileName; }
   void SetMvdMaterialBudgetFileName(TString fileName) { fMvdMatBudgetFileName = fileName; }
   void SetMuchMaterialBudgetFileName(TString fileName) { fMuchMatBudgetFileName = fileName; }
@@ -224,6 +243,11 @@ private:
   static CbmL1* fInstance;
   L1Parameters fL1Parameters;
 
+  std::set<L1DetectorID> fActiveTrackingDetectorIDs {
+    L1DetectorID::kMvd, 
+    L1DetectorID::kSts 
+  };  ///< Set of detectors active in tracking
+
   L1AlgoInputData* fData {nullptr};
 
   L1Vector<CbmL1MCPoint> vMCPoints {"CbmL1::vMCPoints"};
diff --git a/reco/L1/L1Algo/L1Algo.cxx b/reco/L1/L1Algo/L1Algo.cxx
index 3c2c4f3c15..55ee25a1e2 100644
--- a/reco/L1/L1Algo/L1Algo.cxx
+++ b/reco/L1/L1Algo/L1Algo.cxx
@@ -225,6 +225,42 @@ void L1Algo::Init(const L1Vector<fscal>& geo, const bool UseHitErrors, const Tra
 #ifndef TBB2
   std::cout << "L1Algo initialized" << std::endl;
 #endif  // TBB2
+
+  //
+  // NEW INITIALIZATION (BETA)
+  //
+  
+
+  LOG(debug) << "\\";
+  LOG(debug) << " \\";
+  LOG(debug) << "     Original L1Station vector content";
+  LOG(debug) << " /";
+  LOG(debug) << "/";
+  int nStations = fL1InitManager.GetStationsNumber();
+  for (const auto& aStation: vStations) {
+    int idx = &aStation - vStations;
+    if (idx == nStations) {
+      break;
+    }
+    LOG(debug) << "Station Global No: " << idx;
+    aStation.Print();
+  }
+  LOG(debug) << "\\";
+  LOG(debug) << " \\";
+  LOG(debug) << "     New L1Station vector content";
+  LOG(debug) << " /";
+  LOG(debug) << "/";
+  fL1InitManager.TransferL1StationArray(fStationsNew);
+  nStations = fL1InitManager.GetStationsNumber();
+  for (const auto& aStation: fStationsNew) {
+    int idx = &aStation - &fStationsNew.front();
+    if (idx == nStations) {
+      break;
+    }
+    LOG(debug) << "Station Global No: " << idx;
+    aStation.Print();
+
+  }
 }
 
 
diff --git a/reco/L1/L1Algo/L1Algo.h b/reco/L1/L1Algo/L1Algo.h
index 9b4685bb30..1bfbf4c89a 100644
--- a/reco/L1/L1Algo/L1Algo.h
+++ b/reco/L1/L1Algo/L1Algo.h
@@ -42,6 +42,7 @@ class L1AlgoDraw;
 #include <iostream>
 #include <limits>
 #include <map>
+#include <array>
 
 #include "L1Branch.h"
 #include "L1Field.h"
@@ -125,14 +126,14 @@ public:
   static unsigned int TripletId2Thread(unsigned int ID)
   {
     constexpr unsigned int kMoveThread = L1Parameters::kTripletBits;
-    constexpr unsigned int kThreadMask = (1 << L1Parameters::kThreadBits) - 1;
+    constexpr unsigned int kThreadMask = (1u << L1Parameters::kThreadBits) - 1u;
     return (ID >> kMoveThread) & kThreadMask;
   }
 
   /// unpack the triplet ID to its triplet index
   static unsigned int TripletId2Triplet(unsigned int ID)
   {
-    constexpr unsigned int kTripletMask = (1 << L1Parameters::kTripletBits) - 1;
+    constexpr unsigned int kTripletMask = (1u << L1Parameters::kTripletBits) - 1u;
     return ID & kTripletMask;
   }
 
@@ -206,7 +207,10 @@ public:
   int NStsStations {0};     ///< number of sts stations
   int fNfieldStations {0};  ///< number of stations in the field region
 
+
+  // TODO: Replace _fvecalignment with C++11 alignas(16) attibute, see vStationsNew
   L1Station vStations[L1Parameters::kMaxNstations] _fvecalignment;  // station info
+  alignas(16) std::array<L1Station, L1Parameters::kMaxNstations> fStationsNew; 
   L1Vector<L1Material> fRadThick {"fRadThick"};        // material for each station
 
   int NStsStrips {0};                   // number of strips
diff --git a/reco/L1/L1Algo/L1BaseStationInfo.cxx b/reco/L1/L1Algo/L1BaseStationInfo.cxx
new file mode 100644
index 0000000000..5beae9b526
--- /dev/null
+++ b/reco/L1/L1Algo/L1BaseStationInfo.cxx
@@ -0,0 +1,482 @@
+/* Copyright (C) 2016-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov, Sergei Zharko [committer] */
+
+/************************************************************************************************************
+ * @file L1BaseStationInfo.cxx
+ * @bried Realization of L1BaseStationInfo class large methods
+ * @since 18.01.2022
+ *
+ * The class is implemented to connect concrete experimental setup (CBM or BMN in CbmL1 
+ * or BmnL1) with general L1Tracking algorithm. Each derived class must contain general
+ * algorithms sutable for the particular station type.
+ * 
+ ***********************************************************************************************************/
+
+// FairRoot
+#include <FairLogger.h>
+
+// L1Algo core
+#include "L1BaseStationInfo.h"
+#include "L1Parameters.h"
+#include "L1Def.h"
+
+// C++ STL
+#include <utility>
+#include <iomanip>
+
+//
+// CONSTRUCTORS AND DESTRUCTOR
+//
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+L1BaseStationInfo::L1BaseStationInfo() noexcept
+{
+  LOG(DEBUG) << "L1BaseStationInfo: Default constructor called for " << this << '\n';  // Temporary
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+L1BaseStationInfo::L1BaseStationInfo(L1DetectorID detectorID, int stationID) noexcept
+  : fDetectorID(detectorID)
+  , fStationID(stationID)
+{
+  LOG(DEBUG) << "L1BaseStationInfo: Constructor (detectorID, stationID) called for " << this << '\n';  // Temporary
+  fInitFlags[kEDetectorID] = true;
+  fInitFlags[kEStationID] = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+L1BaseStationInfo::~L1BaseStationInfo() noexcept
+{
+  LOG(DEBUG) << "L1BaseStationInfo: Destructor called for " << this << '\n';  // Temporary
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+L1BaseStationInfo::L1BaseStationInfo(const L1BaseStationInfo& other) noexcept
+  : fDetectorID(other.fDetectorID)
+  , fStationID(other.fStationID)
+  , fXmax(other.fXmax)
+  , fYmax(other.fYmax)
+  , fZPos(other.fZPos)
+  , fL1Station(other.fL1Station)
+  , fInitFlags(other.fInitFlags)
+{ 
+  LOG(debug) << "L1BaseStationInfo: Copy constructor called: " << &other << " was copied into " << this;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+L1BaseStationInfo::L1BaseStationInfo(L1BaseStationInfo&& other) noexcept
+{
+  LOG(debug) << "L1BaseStationInfo: Move constructor called: " << &other << " was moved into " << this;
+  this->Swap(other);
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+L1BaseStationInfo& L1BaseStationInfo::operator=(const L1BaseStationInfo& other) noexcept
+{
+  LOG(debug) << "L1BaseStationInfo: Copy operator= called for " << &other << " was copied into" << this;
+  if (this != &other) {
+    L1BaseStationInfo(other).Swap(*this);
+  }
+  return *this;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+L1BaseStationInfo& L1BaseStationInfo::operator=(L1BaseStationInfo&& other) noexcept
+{
+  LOG(debug) << "L1BaseStationInfo: Move operator= called for " << &other << " was copied into" << this; 
+  if (this != &other) {
+    L1BaseStationInfo tmp(std::move(other));
+    this->Swap(tmp);
+  }
+  return *this;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::Swap(L1BaseStationInfo& other) noexcept
+{
+  std::swap(fDetectorID, other.fDetectorID);
+  std::swap(fStationID, other.fStationID);
+  std::swap(fXmax, other.fXmax);
+  std::swap(fYmax, other.fYmax);
+  std::swap(fZPos, other.fZPos);
+  std::swap(fL1Station, other.fL1Station);
+  std::swap(fInitFlags, other.fInitFlags);
+}
+
+//
+// BASIC METHODS
+//
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::Print(int verbosity) const
+{
+  if (verbosity == 0) {
+    LOG(info) 
+      << "L1BaseStationInfo object: {stationID, detectorID, address} = {" << fStationID << ", " 
+      << static_cast<int>(fDetectorID) << ", " << this << '}';
+  }
+  else if(verbosity > 0) {
+    LOG(info) << "L1BaseStationInfo object: at " << this;
+    LOG(info) << "- Station ID:              " << fStationID;
+    LOG(info) << "- Detector ID:             " << static_cast<int>(fDetectorID);
+    LOG(info) << "- L1Station fields:";
+    LOG(info) << "--- Station type ID:             " << fL1Station.type;
+    LOG(info) << "--- Time info ID:                " << fL1Station.timeInfo;
+    LOG(info) << "--- z position:                  " << fL1Station.z[0];
+    LOG(info) << "--- Rmin:                        " << fL1Station.Rmin[0];
+    LOG(info) << "--- Rmax:                        " << fL1Station.Rmax[0];
+    LOG(info) << "--- Thickness (X), cm:           " << fL1Station.materialInfo.thick[0];
+    LOG(info) << "--- Radiational length (X0), cm: " << fL1Station.materialInfo.RL[0];
+    if (verbosity > 1) {
+      LOG(info) << "--- X / X0:                      " << fL1Station.materialInfo.RadThick[0];
+      LOG(info) << "--- log(X / X0):                 " << fL1Station.materialInfo.logRadThick[0];
+      LOG(info) << "--- Field approximation coefficients:";
+      LOG(info) << "      idx         CX         CY         CZ";
+      for (int idx = 0; idx < L1Parameters::kMaxNFieldApproxCoefficients; ++idx) {
+        LOG(info) 
+          << std::setw(9) << std::setfill(' ') << idx << ' ' << std::setw(10) << std::setfill(' ')
+          << fL1Station.fieldSlice.cx[idx][0] << ' ' << std::setw(10) << std::setfill(' ')
+          << fL1Station.fieldSlice.cy[idx][0] << ' ' << std::setw(10) << std::setfill(' ')
+          << fL1Station.fieldSlice.cz[idx][0];
+      }
+      LOG(info) << "--- Strips geometry:";
+      LOG(info) << "----- Front:";
+      LOG(info) << "------- cos(phi):            " << fL1Station.frontInfo.cos_phi[0];
+      LOG(info) << "------- sin(phi):            " << fL1Station.frontInfo.sin_phi[0];
+      LOG(info) << "------- sigma2:              " << fL1Station.frontInfo.sigma2[0];
+      LOG(info) << "----- Back:";
+      LOG(info) << "------- cos(phi):            " << fL1Station.backInfo.cos_phi[0];
+      LOG(info) << "------- sin(phi):            " << fL1Station.backInfo.sin_phi[0];
+      LOG(info) << "------- sigma2:              " << fL1Station.backInfo.sigma2[0];
+      LOG(info) << "----- XY cov matrix:";
+      LOG(info) << "------- C00:                 " << fL1Station.XYInfo.C00[0];
+      LOG(info) << "------- C10:                 " << fL1Station.XYInfo.C10[0];
+      LOG(info) << "------- C11:                 " << fL1Station.XYInfo.C11[0];
+      LOG(info) << "----- X layer:";
+      LOG(info) << "------- cos(phi):            " << fL1Station.xInfo.cos_phi[0];
+      LOG(info) << "------- sin(phi):            " << fL1Station.xInfo.sin_phi[0];
+      LOG(info) << "------- sigma2:              " << fL1Station.xInfo.sigma2[0];
+      LOG(info) << "----- Y layer:";
+      LOG(info) << "------- cos(phi):            " << fL1Station.yInfo.cos_phi[0];
+      LOG(info) << "------- sin(phi):            " << fL1Station.yInfo.sin_phi[0];
+      LOG(info) << "------- sigma2:              " << fL1Station.yInfo.sigma2[0];
+      LOG(info) << "";
+    }
+    LOG(info) << "- Additional fields:";
+    LOG(info) << "--- Xmax:                    " << fXmax;
+    LOG(info) << "--- Ymax:                    " << fYmax;
+  }
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::Reset()
+{
+  L1BaseStationInfo other;
+  std::swap(*this, other);
+}
+
+
+//
+// GETTERS
+//
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+const L1Station& L1BaseStationInfo::GetL1Station() const
+{
+   bool isStationInitialized = IsInitialized();
+   if (!isStationInitialized) {
+     LOG(error)
+       << "L1BaseStationInfo::GetL1Station: attempt to get an L1Staion object from uninitialized L1BaseStation with "
+       << "stationID = "<< fStationID << " and detectorID = " << static_cast<int>(fDetectorID);
+     assert((!isStationInitialized));
+   }
+   return fL1Station;
+}
+
+
+//
+// SETTERS
+//
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetStationID(int inID)
+{
+  if (! fInitFlags[kEStationID]) {
+    fStationID = inID;
+    fInitFlags[kEStationID] = true;
+  }
+  else {
+    LOG(warn) << "L1BaseStationInfo::SetStationID: Attempt of station ID redifinition";
+  }
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetDetectorID(L1DetectorID inID)
+{
+  if (! fInitFlags[kEDetectorID]) {
+    fDetectorID = inID;
+    fInitFlags[kEDetectorID] = true;
+  }
+  else {
+    LOG(warn) << "L1BaseStationInfo::SetDetectorID: Attempt of detector ID redifinition";
+  }
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetStationType(int inType)
+{
+  if (! fInitFlags[kEtype]) {
+    fL1Station.type    = inType;
+    fInitFlags[kEtype] = true;
+  }
+  else {
+    LOG(warn) << "L1BaseStationInfo::SetStationType: Attempt of station type redifinition";
+  }
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetTimeInfo(int inTimeInfo)
+{
+  fL1Station.timeInfo    = inTimeInfo;
+  fInitFlags[kEtimeInfo] = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetZ(double inZ)
+{
+  fL1Station.z = inZ; // setting simd vector of single-precision floats, which is passed to high performanced L1Algo
+  fZPos = inZ;        // setting precised value to use in field approximation etc
+  fInitFlags[kEz] = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetRmin(double inRmin)
+{
+  fL1Station.Rmin    = inRmin;
+  fInitFlags[kERmin] = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetRmax(double inRmax)
+{
+  fL1Station.Rmax    = inRmax;
+  fInitFlags[kERmax] = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetMaterial(double inThickness, double inRL)
+{
+#ifndef L1_NO_ASSERT  // check for zero denominator
+  L1_ASSERT(inRL, "Attempt of entering zero inRL (radiational length) value");
+#endif
+  fL1Station.materialInfo.thick       = inThickness;
+  fL1Station.materialInfo.RL          = inRL;
+  fL1Station.materialInfo.RadThick    = fL1Station.materialInfo.thick / fL1Station.materialInfo.RL;
+  fL1Station.materialInfo.logRadThick = log(fL1Station.materialInfo.RadThick);
+  fInitFlags[kEmaterialInfoThick]     = true;
+  fInitFlags[kEmaterialInfoRL]        = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetFieldSlice(const double* Cx, const double* Cy, const double* Cz)
+{
+  if (fInitFlags[kEfieldSlice]) {
+    LOG(warn) 
+      << "L1BaseStationInfo::SetFieldSlice: Attempt to redifine field slice for station with detectorID = "
+      << static_cast<int>(fDetectorID) << " and stationID = " << fStationID << ". Redifinition ignored";
+    return;
+  }
+
+  for (int idx = 0; idx < L1Parameters::kMaxNFieldApproxCoefficients; ++idx) {
+    fL1Station.fieldSlice.cx[idx] = Cx[idx];
+    fL1Station.fieldSlice.cy[idx] = Cy[idx];
+    fL1Station.fieldSlice.cz[idx] = Cz[idx];
+  }
+
+  fInitFlags[kEfieldSlice] = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetFieldSlice(const std::function<void(const double (&xyz)[3], double (&B)[3])>& getFieldValue)
+{
+  if (fInitFlags[kEfieldSlice]) {
+    LOG(warn) 
+      << "L1BaseStationInfo::SetFieldSlice: Attempt to redifine field slice for station with detectorID = "
+      << static_cast<int>(fDetectorID) << " and stationID = " << fStationID << ". Redifinition ignored";
+    return;
+  }
+
+#ifndef L1_NO_ASSERT  // check for zero denominator
+  L1_ASSERT(fInitFlags[kEz], "Attempt to set magnetic field slice before setting z position of the station");
+  L1_ASSERT(fInitFlags[kEXmax], "Attempt to set magnetic field slice before setting Xmax size of the station");
+  L1_ASSERT(fInitFlags[kEYmax], "Attempt to set magnetic field slice before setting Ymax size of the station");
+#endif
+  constexpr int M = L1Parameters::kMaxFieldApproxPolynomialOrder;
+  constexpr int N = L1Parameters::kMaxNFieldApproxCoefficients;
+  constexpr int D = 3; ///> number of dimensions
+
+  // SLE initialization
+  double A[N][N + D] = {}; // augmented matrix
+  double dx = (fXmax / N / 2 < 1.) ? fXmax / N / 4. : 1.;
+  double dy = (fYmax / N / 2 < 1.) ? fYmax / N / 4. : 1.;
+  
+  for (double x = -fXmax; x <= fXmax; x += dx) {
+    for (double y = -fYmax; y <= fYmax; y += dy) {
+      double r = sqrt(fabs(x * x / fXmax / fXmax + y / fYmax * y / fYmax));
+      if (r > 1.) {
+        continue;
+      }
+      double p[D] = {x, y, fZPos};
+      double B[D] = {};
+      getFieldValue(p, B);
+
+      double m[N] = {1};
+      m[0] = 1;
+      for (int i = 1; i <= M; ++i) {
+        int k = (i - 1) * i / 2;
+        int l = i * (i + 1) / 2;
+        for (int j = 0; j < i; ++j) {
+          m[l + j] = x * m[k + j];
+        }
+        m[l + i] = y * m[k + i - 1];
+      }
+
+      double w = 1. / (r * r + 1);
+      for (int i = 0; i < N; ++i) {
+        // fill the left part of the matrix 
+        for (int j = 0; j < N; ++j) {
+          A[i][j] += w * m[i] * m[j];
+        }
+        // fill the right part of the matrix
+        for (int j = 0; j < D; ++j) {
+          A[i][N + j] += w * B[j] * m[i];
+        }
+      }
+    }
+  }
+
+  // SLE solution (Gaussian elimination)
+  //   
+  for (int kCol = 0; kCol < N - 1; ++kCol) {
+    for (int jRow = kCol + 1; jRow < N; ++jRow) {
+      double factor = A[jRow][kCol] / A[kCol][kCol];
+      for (int iCol = kCol; iCol < N + D; ++iCol) {
+        A[jRow][iCol] -= factor * A[kCol][iCol];
+      }
+    }
+  }
+  for (int kCol = N - 1; kCol > 0; --kCol) {
+    for (int jRow = kCol - 1; jRow >= 0; --jRow) {
+      double factor = A[jRow][kCol] / A[kCol][kCol];
+      for (int iCol = kCol; iCol < N + D; ++iCol) {
+        A[jRow][iCol] -= factor * A[kCol][iCol];
+      }
+    }
+  }
+
+  for (int j = 0; j < N; ++j) {
+    fL1Station.fieldSlice.cx[j] = A[j][N + 0] / A[j][j];
+    fL1Station.fieldSlice.cy[j] = A[j][N + 1] / A[j][j];
+    fL1Station.fieldSlice.cz[j] = A[j][N + 2] / A[j][j];
+  }
+
+  fInitFlags[kEfieldSlice] = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetFrontBackStripsGeometry(double frontPhi, double frontSigma, double backPhi, double backSigma)
+{
+  // TODO: may be is it better to define separate setters for these values and then calculate the
+  //       rest somewhere below?
+
+  //----- Original code from L1Algo ---------------------------------------------------------------------//
+  double cFront = cos(frontPhi);
+  double sFront = sin(frontPhi);
+  double cBack = cos(backPhi);
+  double sBack = sin(backPhi);
+
+  // NOTE: Here additional double variables are used to save the precission
+
+  fL1Station.frontInfo.cos_phi = cFront;
+  fL1Station.frontInfo.sin_phi = sFront;
+  fL1Station.frontInfo.sigma2  = frontSigma * frontSigma;
+
+  fL1Station.backInfo.cos_phi = cBack;
+  fL1Station.backInfo.sin_phi = sBack;
+  fL1Station.backInfo.sigma2  = backSigma * backSigma;
+
+  //if (fabs(b_phi - f_phi) < .1) {
+  //  double th  = b_phi - f_phi;
+  //  double det = cos(th);
+  //  det *= det;
+  //  fL1Station.XYInfo.C00 = (s_b * s_b * f_sigma * f_sigma + s_f * s_f * b_sigma * b_sigma) / det;
+  //  fL1Station.XYInfo.C10 = -(s_b * c_b * f_sigma * f_sigma + s_f * c_f * b_sigma * b_sigma) / det;
+  //  fL1Station.XYInfo.C11 = (c_b * c_b * f_sigma * f_sigma + c_f * c_f * b_sigma * b_sigma) / det;
+  //} else {
+  //  double det = c_f * s_b - s_f * c_b;
+  //  det *= det;
+  //  fL1Station.XYInfo.C00 = (s_b * s_b * f_sigma * f_sigma + s_f * s_f * b_sigma * b_sigma) / det;
+  //  fL1Station.XYInfo.C10 = -(s_b * c_b * f_sigma * f_sigma + s_f * c_f * b_sigma * b_sigma) / det;
+  //  fL1Station.XYInfo.C11 = (c_b * c_b * f_sigma * f_sigma + c_f * c_f * b_sigma * b_sigma) / det;
+  //}
+
+  double det = (fabs(backPhi - frontPhi) < 0.1) ? cos(backPhi - frontPhi) : (cFront * sBack - sFront * cBack);
+  det *= det;
+  fL1Station.XYInfo.C00 = (sBack * sBack * frontSigma * frontSigma + sFront * sFront * backSigma * backSigma) / det;
+  fL1Station.XYInfo.C10 = -(sBack * cBack * frontSigma * frontSigma + sFront * cFront * backSigma * backSigma) / det;
+  fL1Station.XYInfo.C11 = (cBack * cBack * frontSigma * frontSigma + cFront * cFront * backSigma * backSigma) / det;
+
+  fL1Station.xInfo.cos_phi = -sFront / (cFront * sBack - cBack * sFront);
+  fL1Station.xInfo.sin_phi = sBack / (cFront * sBack - cBack * sFront);
+  fL1Station.xInfo.sigma2  = fL1Station.XYInfo.C00;
+
+  fL1Station.yInfo.cos_phi = cBack / (cBack * sFront - cFront * sBack);
+  fL1Station.yInfo.sin_phi = -cFront / (cBack * sFront - cFront * sBack);
+  fL1Station.yInfo.sigma2  = fL1Station.XYInfo.C11;
+  //-----------------------------------------------------------------------------------------------------//
+
+  fInitFlags[kEstripsFrontPhi]   = true;
+  fInitFlags[kEstripsFrontSigma] = true;
+  fInitFlags[kEstripsBackPhi]    = true;
+  fInitFlags[kEstripsBackSigma]  = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetXmax(double aSize)
+{
+  fXmax = aSize;
+  fInitFlags[kEXmax] = true;
+}
+
+//----------------------------------------------------------------------------------------------------------------------//
+//
+void L1BaseStationInfo::SetYmax(double aSize)
+{
+  fYmax = aSize;
+  fInitFlags[kEYmax] = true;
+}
+
diff --git a/reco/L1/L1Algo/L1BaseStationInfo.h b/reco/L1/L1Algo/L1BaseStationInfo.h
index f298ea9217..f9cc5a4b01 100644
--- a/reco/L1/L1Algo/L1BaseStationInfo.h
+++ b/reco/L1/L1Algo/L1BaseStationInfo.h
@@ -8,40 +8,28 @@
  * @since 18.12.2021
  *
  * The class is implemented to connect concrete experimental setup (CBM or BMN in CbmL1 
- * or BmnL1) with general L1Tracking algorithm. Each derived class must contain general
- * algorithms sutable for the particular station type.
+ * or BmnL1) with general L1Algo tracking.
  * 
  ***********************************************************************************************************/
 
 #ifndef L1BaseStationInfo_h
 #define L1BaseStationInfo_h 1
 
-// L1 core
-#include "L1Def.h"
-#include "L1Parameters.h"
-#include "L1Station.h"
-
-// FairRoot
-#include "FairField.h"
-
-// Root
-#include "TMatrixD.h"
-#include "TVectorD.h"
-
 // C++ std
 #include <bitset>
-#include <iomanip>
-#include <string>
 #include <functional>
-//#include <cmath>
 
-/// A base class which provides interface to L1Algo station geometry
+#include "L1Station.h"
 
+enum class L1DetectorID;
+
+/// A base class which provides interface to L1Algo station geometry
 class L1BaseStationInfo {
 private:
   enum
   {  // Here we list all the fields, which must be initialized by user
     // Basic fields initialization
+    kEDetectorID,
     kEStationID,
     kEXmax,
     kEYmax,
@@ -63,277 +51,54 @@ private:
   };
 
 public:
-  L1BaseStationInfo()
-  {
-    std::cout << ">>>>>> L1BaseStationInfo: Constructor called\n";  // Temporary
-  }
-  virtual ~L1BaseStationInfo()
-  {
-    std::cout << ">>>>>> L1BaseStationInfo: Destructor called\n";  // Temporary
-  }
-
-  //-------------------------------------------------------------------------------------------------------//
-  //    Basic methods                                                                                      //
-  //-------------------------------------------------------------------------------------------------------//
-
-  /// Returns the name of the station (TODO: connect official naming)
-  std::string GetTypeName() const { return fTypeName; }
-  /// Checks if all the necessary fields are initialized by user
-  bool IsInitialized() const { return fInitFlags.size() == fInitFlags.count(); }
-  /// Transfers all gathered data to L1Algo (TODO)
-  void TransferL1Station()
-  { /**********/
-  }
-  void TransferData()
-  { /*********/
-  }
-
-  //-------------------------------------------------------------------------------------------------------//
-  //    Interface for L1Station object initialization                                                      //
-  //-------------------------------------------------------------------------------------------------------//
+  /// Default constructor
+  L1BaseStationInfo() noexcept;
+  /// Constructor from stationID and detectorID
+  L1BaseStationInfo(L1DetectorID detetorID, int stationID) noexcept;
+  /// Destructor
+  ~L1BaseStationInfo() noexcept;
+  /// Copy constructor
+  L1BaseStationInfo(const L1BaseStationInfo& other) noexcept;
+  /// Move constructor
+  L1BaseStationInfo(L1BaseStationInfo&& other) noexcept;
+  /// Copy operator=
+  L1BaseStationInfo& operator=(const L1BaseStationInfo& other) noexcept;
+  /// Move operator=
+  L1BaseStationInfo& operator=(L1BaseStationInfo&& other) noexcept;
+  /// Swap method for easier implementation of above ones (NOTE: all the fields must be accounted carefully here)
+  void Swap(L1BaseStationInfo& other) noexcept;
 
   //
-  //  Setters
+  // BASIC METHODS
   //
-  /// Sets station ID
-  void SetStationID(int inID)
-  {
-    if (! fInitFlags[kEStationID]) {
-      fStationID = inID;
-      fInitFlags[kEStationID] = true;
-    }
-#ifndef FAST_CODE
-    else {
-      LOG(WARNING) << __FILE__ << ":" << __LINE__ << " Attempt of station ID redifinition\n";
-    }
-#endif // ! FAST_CODE
-  }
-  /// Sets type of station
-  void SetStationType(int inType)
-  {
-    if (! fInitFlags[kEtype]) {
-      fL1Station.type    = inType;
-      fInitFlags[kEtype] = true;
-    }
-#ifndef FAST_CODE
-    else {
-      LOG(WARNING) << __FILE__ << ":" << __LINE__ << " Attempt of station type redifinition\n";
-    }
-#endif // ! FAST_CODE
-  }
-  // TODO: Temporary method, a type must be selected automatically in the derived classes
-  void SetTimeInfo(int inTimeInfo)
-  {
-    fL1Station.timeInfo    = inTimeInfo;
-    fInitFlags[kEtimeInfo] = true;
-  }
-  // ???
-
-  /// Sets nominal z position of the station
-  void SetZ(double inZ)
-  {
-    fL1Station.z = inZ; // setting simd vector of single-precision floats, which is passed to high performanced L1Algo
-    fZPos = inZ; // setting precise value to use in field approximation etc
-    fInitFlags[kEz] = true;
-  }
-  /// Sets min transverse size of the station
-  void SetRmin(double inRmin)
-  {
-    fL1Station.Rmin    = inRmin;
-    fInitFlags[kERmin] = true;
-  }
-  /// Sets max transverse size of the station
-  void SetRmax(double inRmax)
-  {
-    fL1Station.Rmax    = inRmax;
-    fInitFlags[kERmax] = true;
-  }
-
-  /// Sets station thickness and radiational length
-  void SetMaterial(double inThickness, double inRL)
-  {
-#ifndef L1_NO_ASSERT  // check for zero denominator
-    L1_ASSERT(inRL, "Attempt of entering zero inRL (radiational length) value");
-#endif
-    fL1Station.materialInfo.thick       = inThickness;
-    fL1Station.materialInfo.RL          = inRL;
-    fL1Station.materialInfo.RadThick    = fL1Station.materialInfo.thick / fL1Station.materialInfo.RL;
-    fL1Station.materialInfo.logRadThick = log(fL1Station.materialInfo.RadThick);
-    fInitFlags[kEmaterialInfoThick]     = true;
-    fInitFlags[kEmaterialInfoRL]        = true;
-  }
-
-  /// Sets arrays of the approximation coefficients for the field x, y and z-components, respectively
-  void SetFieldSlice(const double* Cx, const double* Cy, const double* Cz)
-  {
-    for (int idx = 0; idx < L1Parameters::kMaxNFieldApproxCoefficients; ++idx) {
-      fL1Station.fieldSlice.cx[idx] = Cx[idx];
-      fL1Station.fieldSlice.cy[idx] = Cy[idx];
-      fL1Station.fieldSlice.cz[idx] = Cz[idx];
-    }
-    fInitFlags[kEfieldSlice]      = true;
-  }
-  /// Sets arrays of the approcimation 
-  /// \param getField A user function, which gets a xyz array of position coordinates and fills B array
-  ///                 of magnetic field components in position
-  void SetFieldSlice(const std::function<void(const double (&xyz)[3], double (&B)[3])>& getFieldValue)
-  {
-    std::cout << ">>>>>>> CALL: SetFieldSlice\n";
-#ifndef L1_NO_ASSERT  // check for zero denominator
-    L1_ASSERT(fInitFlags[kEz], "Attempt to set magnetic field slice before setting z position of the station");
-    L1_ASSERT(fInitFlags[kEXmax], "Attempt to set magnetic field slice before setting Xmax size of the station");
-    L1_ASSERT(fInitFlags[kEYmax], "Attempt to set magnetic field slice before setting Ymax size of the station");
-#endif
-    constexpr int M = L1Parameters::kMaxFieldApproxPolynomialOrder;
-    constexpr int N = L1Parameters::kMaxNFieldApproxCoefficients;
-    constexpr int D = 3; ///> number of dimensions
-
-    // SLE initialization
-    double A[N][N + D] = {}; // augmented matrix
-    double dx = (fXmax / N / 2 < 1.) ? fXmax / N / 4. : 1.;
-    double dy = (fYmax / N / 2 < 1.) ? fYmax / N / 4. : 1.;
-    
-    for (double x = -fXmax; x <= fXmax; x += dx) {
-      for (double y = -fYmax; y <= fYmax; y += dy) {
-        double r = sqrt(fabs(x * x / fXmax / fXmax + y / fYmax * y / fYmax));
-        if (r > 1.) {
-          continue;
-        }
-        double p[D] = {x, y, fZPos};
-        double B[D] = {};
-        getFieldValue(p, B);
-
-        double m[N] = {1};
-        m[0] = 1;
-        for (int i = 1; i <= M; ++i) {
-          int k = (i - 1) * (i) / 2;
-          int l = i * (i + 1) / 2;
-          for (int j = 0; j < i; ++j) {
-            m[l + j] = x * m[k + j];
-          }
-          m[l + i] = y * m[k + i - 1];
-        }
-
-        double w = 1. / (r * r + 1);
-        for (int i = 0; i < N; ++i) {
-          // fill the left part of the matrix 
-          for (int j = 0; j < N; ++j) {
-            A[i][j] += w * m[i] * m[j];
-          }
-          // fill the right part of the matrix
-          for (int j = 0; j < D; ++j) {
-            A[i][N + j] += w * B[j] * m[i];
-          }
-        }
-      }
-    }
-
-    // SLE solution (Gaussian elimination)
-    //   
-    for (int kCol = 0; kCol < N - 1; ++kCol) {
-      for (int jRow = kCol + 1; jRow < N; ++jRow) {
-        double factor = A[jRow][kCol] / A[kCol][kCol];
-        for (int iCol = kCol; iCol < N + D; ++iCol) {
-          A[jRow][iCol] -= factor * A[kCol][iCol];
-        }
-      }
-    }
-    for (int kCol = N - 1; kCol > 0; --kCol) {
-      for (int jRow = kCol - 1; jRow >= 0; --jRow) {
-        double factor = A[jRow][kCol] / A[kCol][kCol];
-        for (int iCol = kCol; iCol < N + D; ++iCol) {
-          A[jRow][iCol] -= factor * A[kCol][iCol];
-        }
-      }
-    }
 
-    for (int j = 0; j < N; ++j) {
-      fL1Station.fieldSlice.cx[j] = A[j][N + 0] / A[j][j];
-      fL1Station.fieldSlice.cy[j] = A[j][N + 1] / A[j][j];
-      fL1Station.fieldSlice.cz[j] = A[j][N + 2] / A[j][j];
-    }
-
-    fInitFlags[kEfieldSlice] = true;
+  /// Checks if all the necessary fields are initialized by user
+  bool IsInitialized() const { return fInitFlags.size() == fInitFlags.count(); }
+  /// Prints registered fields
+  /// verbosity = 0: print only station id, detector id and address in one line
+  /// verbosity = 1: print basic L1Station fields
+  /// verbosity = 2: print all L1Staion fields
+  void Print(int verbosity = 0) const;
+  /// Print initialization flags (debug function)
+  void PrintInit() const;
+  /// Resets fields to the default values
+  void Reset();
+  /// Less operator for L1BaseStationInfo object to perform their sorts. Sorting is carried out first by fDetectorID,
+  /// and then by fStationID
+  bool operator<(const L1BaseStationInfo& right) const
+  { 
+    return fDetectorID != right.fDetectorID ? fDetectorID < right.fDetectorID : fStationID < right.fStationID;
   }
 
-  /// Sets stereo angles and sigmas for front and back strips, automatically set frontInfo, backInfo,
-  /// XYInfo, xInfo and yInfo
-  void SetFrontBackStripsGeometry(double f_phi, double f_sigma, double b_phi, double b_sigma)
-  {
-    // TODO: may be is it better to define separate setters for these values and then calculate the
-    //       rest somewhere below?
-    // TODO: move into .cxx file
-
-    //----- Original code from L1Algo ---------------------------------------------------------------------//
-    double c_f = cos(f_phi);
-    double s_f = sin(f_phi);
-    double c_b = cos(b_phi);
-    double s_b = sin(b_phi);
-
-    // NOTE: Here additional double variables are used to save the precission
-
-    fL1Station.frontInfo.cos_phi = c_f;
-    fL1Station.frontInfo.sin_phi = s_f;
-    fL1Station.frontInfo.sigma2  = f_sigma * f_sigma;
-
-    fL1Station.backInfo.cos_phi = c_b;
-    fL1Station.backInfo.sin_phi = s_b;
-    fL1Station.backInfo.sigma2  = b_sigma * b_sigma;
-
-    //if (fabs(b_phi - f_phi) < .1) {
-    //  double th  = b_phi - f_phi;
-    //  double det = cos(th);
-    //  det *= det;
-    //  fL1Station.XYInfo.C00 = (s_b * s_b * f_sigma * f_sigma + s_f * s_f * b_sigma * b_sigma) / det;
-    //  fL1Station.XYInfo.C10 = -(s_b * c_b * f_sigma * f_sigma + s_f * c_f * b_sigma * b_sigma) / det;
-    //  fL1Station.XYInfo.C11 = (c_b * c_b * f_sigma * f_sigma + c_f * c_f * b_sigma * b_sigma) / det;
-    //} else {
-    //  double det = c_f * s_b - s_f * c_b;
-    //  det *= det;
-    //  fL1Station.XYInfo.C00 = (s_b * s_b * f_sigma * f_sigma + s_f * s_f * b_sigma * b_sigma) / det;
-    //  fL1Station.XYInfo.C10 = -(s_b * c_b * f_sigma * f_sigma + s_f * c_f * b_sigma * b_sigma) / det;
-    //  fL1Station.XYInfo.C11 = (c_b * c_b * f_sigma * f_sigma + c_f * c_f * b_sigma * b_sigma) / det;
-    //}
-
-    double det = (fabs(b_phi - f_phi) < 0.1) ? cos(b_phi - f_phi) : (c_f * s_b - s_f * c_b);
-    det *= det;
-    fL1Station.XYInfo.C00 = (s_b * s_b * f_sigma * f_sigma + s_f * s_f * b_sigma * b_sigma) / det;
-    fL1Station.XYInfo.C10 = -(s_b * c_b * f_sigma * f_sigma + s_f * c_f * b_sigma * b_sigma) / det;
-    fL1Station.XYInfo.C11 = (c_b * c_b * f_sigma * f_sigma + c_f * c_f * b_sigma * b_sigma) / det;
-
-    fL1Station.xInfo.cos_phi = -s_f / (c_f * s_b - c_b * s_f);
-    fL1Station.xInfo.sin_phi = s_b / (c_f * s_b - c_b * s_f);
-    fL1Station.xInfo.sigma2  = fL1Station.XYInfo.C00;
-
-    fL1Station.yInfo.cos_phi = c_b / (c_b * s_f - c_f * s_b);
-    fL1Station.yInfo.sin_phi = -c_f / (c_b * s_f - c_f * s_b);
-    fL1Station.yInfo.sigma2  = fL1Station.XYInfo.C11;
-    //-----------------------------------------------------------------------------------------------------//
-
-    fInitFlags[kEstripsFrontPhi]   = true;
-    fInitFlags[kEstripsFrontSigma] = true;
-    fInitFlags[kEstripsBackPhi]    = true;
-    fInitFlags[kEstripsBackSigma]  = true;
-  }
-  /// Sets maximum distance between station center and its edge in x direction
-  void SetXmax(double aSize)
-  {
-    fXmax = aSize;
-    fInitFlags[kEXmax] = true;
-  }
-  /// Sets maximum distance between station center and its edge in y direction
-  void SetYmax(double aSize)
-  {
-    fYmax = aSize;
-    fInitFlags[kEYmax] = true;
-  }
 
   //
-  // Getters
+  // GETTERS
   //
 
   /// Gets station ID
   int GetStationID() const { return fStationID; }
+  /// Gets detector ID
+  L1DetectorID GetDetectorID() const { return fDetectorID; }
   /// Gets station type
   int GetStationType() const { return fL1Station.type; }
   /// Gets SIMD vectorized z position of the station
@@ -346,11 +111,11 @@ public:
   fvec GetRmax() const { return fL1Station.Rmax; }
 
   /// Gets material thickness
-  fvec GetMaterialThick() const { return fL1Station.materialInfo.thick; }
+  fvec GetMaterialThickness() const { return fL1Station.materialInfo.thick; }
   // TODO: investigate if thick, RL and RadThick are useful, may be we should have only
   //       GetMateralLogRadThick?
   /// Gets the radiation length of the station material
-  fvec GetMaterialRL() const { return fL1Station.materialInfo.RL; }  // TODO: -//-
+  fvec GetMaterialRadLength() const { return fL1Station.materialInfo.RL; }  // TODO: -//-
   /// Gets the relative material thickness in units of the radiational length
   fvec GetMaterialRadThick() const { return fL1Station.materialInfo.RadThick; }  // TODO: Rename?
   /// Gets log of the relative material thickness in units of the radiational length
@@ -375,81 +140,68 @@ public:
   /// Gets maximum distance between station center and its edge in y direction
   double GetYmax() const { return fYmax; }
 
+  /// Gets a reference to L1Station info field of the L1BaseStation info
+  const L1Station& GetL1Station() const;
+  /// Gets a reference to Bitset object of initialization bits
+  const std::bitset<L1BaseStationInfo::kEND>& GetInitFlags() const { return fInitFlags; }
 
-  //-------------------------------------------------------------------------------------------------------//
-  //    Other methods                                                                                      //
-  //-------------------------------------------------------------------------------------------------------//
+  
 
-  /// Prints registered fields (TODO: tmp, may be one needs to wrap it into debug directives)
-  void Print()
-  {
-    LOG(INFO) << "== L1Algo: station info ===========================================================";
-    LOG(INFO) << "";
-    LOG(INFO) << "    Station ID:              " << fStationID;
-    LOG(INFO) << "  L1Station fields:";
-    LOG(INFO) << "    Station type ID:         " << fL1Station.type;
-    LOG(INFO) << "    z position:              " << fL1Station.z[0];
-    LOG(INFO) << "    Rmin:                    " << fL1Station.Rmin[0];
-    LOG(INFO) << "    Rmax:                    " << fL1Station.Rmax[0];
-    LOG(INFO) << "    Thickness (X):           " << fL1Station.materialInfo.thick[0];
-    LOG(INFO) << "    Radiational length (X0): " << fL1Station.materialInfo.RL[0];
-    LOG(INFO) << "    X / X0:                  " << fL1Station.materialInfo.RadThick[0];
-    LOG(INFO) << "    log(X / X0):             " << fL1Station.materialInfo.logRadThick[0];
-    LOG(INFO) << "    Field approximation coefficients:";
-    LOG(INFO) << "      idx         CX         CY         CZ";
-    for (int idx = 0; idx < L1Parameters::kMaxNFieldApproxCoefficients; ++idx) {
-      LOG(INFO) << std::setw(9) << std::setfill(' ') << idx << ' ' << std::setw(10) << std::setfill(' ')
-                << fL1Station.fieldSlice.cx[idx][0] << ' ' << std::setw(10) << std::setfill(' ')
-                << fL1Station.fieldSlice.cy[idx][0] << ' ' << std::setw(10) << std::setfill(' ')
-                << fL1Station.fieldSlice.cz[idx][0];
-    }
-    LOG(INFO) << "    Strips geometry:";
-    LOG(INFO) << "      Front:";
-    LOG(INFO) << "        cos(phi):            " << fL1Station.frontInfo.cos_phi[0];
-    LOG(INFO) << "        sin(phi):            " << fL1Station.frontInfo.sin_phi[0];
-    LOG(INFO) << "        sigma2:              " << fL1Station.frontInfo.sigma2[0];
-    LOG(INFO) << "      Back:";
-    LOG(INFO) << "        cos(phi):            " << fL1Station.backInfo.cos_phi[0];
-    LOG(INFO) << "        sin(phi):            " << fL1Station.backInfo.sin_phi[0];
-    LOG(INFO) << "        sigma2:              " << fL1Station.backInfo.sigma2[0];
-    LOG(INFO) << "      XY cov matrix:";
-    LOG(INFO) << "        C00:                 " << fL1Station.XYInfo.C00[0];
-    LOG(INFO) << "        C10:                 " << fL1Station.XYInfo.C10[0];
-    LOG(INFO) << "        C11:                 " << fL1Station.XYInfo.C11[0];
-    LOG(INFO) << "      X layer:";
-    LOG(INFO) << "        cos(phi):            " << fL1Station.xInfo.cos_phi[0];
-    LOG(INFO) << "        sin(phi):            " << fL1Station.xInfo.sin_phi[0];
-    LOG(INFO) << "        sigma2:              " << fL1Station.xInfo.sigma2[0];
-    LOG(INFO) << "      Y layer:";
-    LOG(INFO) << "        cos(phi):            " << fL1Station.yInfo.cos_phi[0];
-    LOG(INFO) << "        sin(phi):            " << fL1Station.yInfo.sin_phi[0];
-    LOG(INFO) << "        sigma2:              " << fL1Station.yInfo.sigma2[0];
-    LOG(INFO) << "";
-    LOG(INFO) << "  Additiona fields:";
-    LOG(INFO) << "    Xmax:                    " << fXmax;
-    LOG(INFO) << "    Ymax:                    " << fYmax;
-    LOG(INFO) << "";
-    LOG(INFO) << "===================================================================================";
-  }
-  void Reset() {
-    L1BaseStationInfo other;
-    std::swap(*this, other);
-  }
+  //
+  //  SETTERS
+  //
 
-private:
-  
-  std::bitset<L1BaseStationInfo::kEND> fInitFlags;  ///< Class fileds initialization flags
-  std::string fTypeName {"BASE"};  ///< Station type name (TODO: probably should be replaced with function of type)
-  L1Station fL1Station {};  ///< L1Station structure, describes a station in L1Algo
-  int fStationID {-1}; ///< Station ID
+  /// Sets station ID
+  void SetStationID(int inID);
+  /// Sets detector ID
+  void SetDetectorID(L1DetectorID inID );
+
+  /// Sets type of station
+  void SetStationType(int inType); // TODO: this is a temporary solution since 
+  /// Sets flag: 0 - time information is not provided by this detector type
+  //             1 - time information is provided by the detector and can be used in tracking
+  void SetTimeInfo(int inTimeInfo);
+  /// Sets nominal z position of the station
+  void SetZ(double inZ);
+  /// Sets min transverse size of the station
+  void SetRmin(double inRmin);
+  /// Sets max transverse size of the station
+  void SetRmax(double inRmax);
+  /// Sets station thickness and radiational length
+  /// \param thickness         thickness of station
+  /// \param radiationalLength radiational length of station
+  void SetMaterial(double thickness, double radiationalLength);
+  /// Sets field approximation at the station plain
+  /// \param Cx Array of approximation coefficients for x field component
+  /// \param Cy Array of approximation coefficients for y field component
+  /// \param Cz Array of approximation coefficients for z field component
+  void SetFieldSlice(const double* Cx, const double* Cy, const double* Cz);
+  /// Sets arrays of the approcimation 
+  /// \param getField A user function, which gets a xyz array of position coordinates and fills B array
+  ///                 of magnetic field components in position
+  void SetFieldSlice(const std::function<void(const double (&xyz)[3], double (&B)[3])>& getFieldValue);
+  /// Sets stereo angles and sigmas for front and back strips
+  /// \param f_phi   Stereoangle of front strips
+  /// \param f_sigma Sigma of front strips
+  /// \param b_phi   Stereoangle of back strips
+  /// \param b_sigma Sigma of back strips
+  void SetFrontBackStripsGeometry(double fPhi, double fSigma, double bPhi, double bSigma);
+  /// Sets maximum distance between station center and its edge in x direction
+  void SetXmax(double aSize);
+  /// Sets maximum distance between station center and its edge in y direction
+  void SetYmax(double aSize);
+
+private: 
+  L1DetectorID fDetectorID {static_cast<L1DetectorID>(0)};  ///< Detector ID 
+  int          fStationID {-1};  ///< Station ID
   double fXmax {0};  ///< Maximum distance between station center and its edge in x direction
   double fYmax {0};  ///< Maximum distance between station center and its edge in y direction
   double fZPos {0};  ///< z position of the station in double precision, used in field approximation
-  // TODO (!!!!) MUST THINK ABOUT THIS OBJECT LIFE TIME: will it be better to copy
-  //             or to move it to the core? If the second, what should we do with
-  //             getters? Do we need to lock them, when the fL1Station object will
-  //             be transfered?
+  L1Station fL1Station {};  ///< L1Station structure, describes a station in L1Algo
+  std::bitset<L1BaseStationInfo::kEND> fInitFlags;  ///< Class fileds initialization flags
 };
 
+/// swap function for two L1BaseStationInfo objects, expected to be used instead of std::swap
+inline void swap(L1BaseStationInfo& a, L1BaseStationInfo& b) noexcept { a.Swap(b); }
 
 #endif  // L1BaseStationInfo_h
diff --git a/reco/L1/L1Algo/L1CAIteration.cxx b/reco/L1/L1Algo/L1CAIteration.cxx
new file mode 100644
index 0000000000..33a5acc536
--- /dev/null
+++ b/reco/L1/L1Algo/L1CAIteration.cxx
@@ -0,0 +1,25 @@
+/* Copyright (C) 2016-2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov, Sergei Zharko [committer] */
+
+#include <FairLogger.h>
+#include "L1CAIteration.h"
+
+L1CAIteration::L1CAIteration(const std::string& name, L1CAIterationType type)
+: fName(name),
+  fType(type)
+{
+  this->Print();
+}
+
+void L1CAIteration::Print() const
+{
+  LOG(INFO) << "CA Track Finder Iteration: " << fName;
+  LOG(INFO) << "\t\t-type" << static_cast<int>(fType);
+  LOG(INFO) << "\tTrack cuts:";
+  LOG(INFO) << "\t\t- chi2 cut" << fTrackChi2Cut;
+  LOG(INFO) << "\tTriplet cuts:";
+  LOG(INFO) << "\t\t- chi2 cut" << fTripletChi2Cut;
+  LOG(INFO) << "\tDoublet cuts:";
+  LOG(INFO) << "\t\t- chi2 cut" << fDoubletChi2Cut;
+}
diff --git a/reco/L1/L1Algo/L1CAIteration.h b/reco/L1/L1Algo/L1CAIteration.h
new file mode 100644
index 0000000000..f75ae3bbd2
--- /dev/null
+++ b/reco/L1/L1Algo/L1CAIteration.h
@@ -0,0 +1,121 @@
+/* Copyright (C) 2016-2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov, Sergei Zharko [committer] */
+
+
+/************************************************************************************************************
+ * @file L1CAIteration.h
+ * @brief Class for L1 CA Track Finder Iteration 
+ * @since 01.15.2022
+ *
+ ***********************************************************************************************************/
+
+#ifndef L1CAIteration_h
+#define L1CAIteration_h 1
+
+/// All possible iteration types of Track Finder algorithm to select  
+///
+enum class L1CAIterationType {
+  kFastPrim,       ///< primary fast tracks
+  kAllPrim,        ///< primary all tracks
+  kAllPrimJump,    ///< primary all tracks with jumped triplets
+  kAllSec,         ///< secondary all tracks
+  kAllPrimE,       ///< primary all electron tracks
+  kAllSecE,        ///< secondary all electron tracks 
+  kFastPrimJump,   ///< primary fast tracks with jumped triplets
+  kAllSecJump      ///< secondary all tracks with jumped triplets
+};
+
+
+/// Class describes L1 Track finder iteration
+///
+class L1CAIteration {
+public:
+  L1CAIteration() = default;
+  ~L1CAIteration() = default;
+  L1CAIteration(const L1CAIteration& /*other*/) = default;
+  L1CAIteration(L1CAIteration&& /*other*/) = default;
+  L1CAIteration& operator=(const L1CAIteration& /*other*/) = default;
+  L1CAIteration& operator=(L1CAIteration&& /*other*/) = default;
+
+  L1CAIteration(const std::string& /*name*/, L1CAIterationType /*type*/);
+
+  //
+  // BASIC METHODS
+  //
+
+  /// Prints iteration options
+  void Print() const;
+
+  //
+  // SETTERS
+  //
+
+  //-------------------------------------------------------------------------------------------------------------------
+  // Basic fields setters
+  //-------------------------------------------------------------------------------------------------------------------
+
+  /// Sets name for this iteration, the name should be unique
+  // TODO: develope naming system and checkers
+  void SetName(const std::string& name) { fName = name; }
+  /// Sets type of the iteration
+  void SetType(L1CAIterationType type) { fType = type; }
+
+  //-------------------------------------------------------------------------------------------------------------------
+  // Cuts setters
+  //-------------------------------------------------------------------------------------------------------------------
+
+  /// Sets track chi2 upper cut
+  void SetTrackChi2Cut(float input) { fTrackChi2Cut = input; }
+  /// Sets triplet chi2 upper cut
+  void SetTripletChi2Cut(float input) { fTripletChi2Cut = input; }
+  /// Sets doublet chi2 upper cut
+  void SetDoubletChi2Cut(float input) { fDoubletChi2Cut = input; }
+
+
+  //
+  // GETTERS
+  //
+
+  //-------------------------------------------------------------------------------------------------------------------
+  // Basic fields getters
+  //-------------------------------------------------------------------------------------------------------------------
+
+  /// Gets the name of the iteration
+  std::string GetName() const { return fName; }
+  /// Gets the type of the iteration
+  L1CAIterationType GetType() { return fType; }
+
+  //-------------------------------------------------------------------------------------------------------------------
+  // Cuts getters
+  //-------------------------------------------------------------------------------------------------------------------
+
+  /// Gets track chi2 upper cut
+  float GetTrackChi2Cut() const { return fTrackChi2Cut; }
+  /// Gets triplet chi2 upper cut
+  float GetTripletChi2Cut() const { return fTripletChi2Cut; }
+  /// Gets doublet chi2 upper cut
+  float GetDoubletChi2Cut() const { return fDoubletChi2Cut; }
+
+private:
+  
+  //-------------------------------------------------------------------------------------------------------------------
+  // Basic fields                                                   
+  //-------------------------------------------------------------------------------------------------------------------
+
+  std::string fName;  ///< Iteration name
+  L1CAIterationType fType;  ///< Iteration type
+
+  //-------------------------------------------------------------------------------------------------------------------
+  // Track finder dependent cuts                                                   
+  //-------------------------------------------------------------------------------------------------------------------
+  
+  float fTrackChi2Cut;  ///> track chi2 upper cut
+  float fTripletChi2Cut;  ///> triplet chi2 upper cut
+  float fDoubletChi2Cut;  ///> doublet chi2 upper cut
+
+  
+
+};
+
+#endif // L1CAIteration_h
diff --git a/reco/L1/L1Algo/L1Def.h b/reco/L1/L1Algo/L1Def.h
index f6974adc5d..904817e62f 100644
--- a/reco/L1/L1Algo/L1Def.h
+++ b/reco/L1/L1Algo/L1Def.h
@@ -65,10 +65,7 @@ typedef int index_type;
 
 /// Hash for unordered_map with enum class keys
 struct EnumClassHash {
-  template <typename T> size_t operator()(T t) const 
-  {
-    return static_cast<size_t>(t);
-  }
+  template <typename T> int operator()(T t) const { return static_cast<int>(t); }
 };
 
 #endif
diff --git a/reco/L1/L1Algo/L1InitManager.cxx b/reco/L1/L1Algo/L1InitManager.cxx
new file mode 100644
index 0000000000..590ffdd57a
--- /dev/null
+++ b/reco/L1/L1Algo/L1InitManager.cxx
@@ -0,0 +1,291 @@
+/* Copyright (C) 2016-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergey Gorbunov, Sergei Zharko [committer] */
+
+/************************************************************************************************************
+ * @file L1InitManager.cxx
+ * @bried Input data management class for L1Algo
+ * @since 19.01.2022
+ *
+ ***********************************************************************************************************/
+
+#include "L1InitManager.h"
+#include <algorithm>
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+void L1InitManager::AddStation(const L1BaseStationInfo& inStation)
+{
+  // Check if other fields were defined already
+  // Active detector IDs
+  if (!fInitFlags[L1InitManager::kEactiveDetectorIDs]) {
+    LOG(error) 
+      << "L1InitManager::AddStation: station initialization called before the active detectors set had been initialized";
+    assert((fInitFlags[L1InitManager::kEactiveDetectorIDs]));
+  }
+
+  // Number of stations check
+  if (!fInitFlags[L1InitManager::kEstationsNumberCrosscheck]) {
+    LOG(error) 
+      << "L1InitManager::AddStation: station initialization called before the numbers of stations for each detector "
+      << "had been initialized";
+    assert((fInitFlags[L1InitManager::kEstationsNumberCrosscheck]));
+  }
+
+  // Field function
+  if (!fInitFlags[L1InitManager::kEfieldFunction]) {
+    LOG(error) 
+      << "L1InitManager::AddStation: station initialization called before the magnetic field function was intialized";
+    assert((fInitFlags[L1InitManager::kEfieldFunction]));
+  }
+
+  // Check activeness of this station type
+  bool isDetectorActive = fActiveDetectorIDs.find(inStation.GetDetectorID()) != fActiveDetectorIDs.end();
+  if (isDetectorActive) {
+    // initialize magnetic field slice
+    L1BaseStationInfo inStationCopy = L1BaseStationInfo(inStation); // make a copy of station so it can be initialized
+    inStationCopy.SetFieldSlice(fFieldFunction);
+    bool isStationInitialized = inStationCopy.IsInitialized();
+    if (!isStationInitialized) {
+      LOG(debug) << "L1InitManager::AddStation: station init flags (original)" << inStation.GetInitFlags();
+      LOG(debug) << "L1InitManager::AddStation: station init flags (copy)    " << inStation.GetInitFlags();
+      LOG(error) 
+        << "L1InitManager::AddStation: Trying to add incompletely initialized object with detectorID = "
+        << static_cast<int>(inStationCopy.GetDetectorID()) << " and stationID = " << inStationCopy.GetStationID();
+        assert((isStationInitialized));
+    }
+    // insert the station in a set
+    auto insertionResult = fStationsInfo.insert(std::move(inStationCopy));
+    if (!insertionResult.second) {
+      LOG(error) 
+        << "L1InitManager::AddStation: attempt to insert a dublicating L1BaseStationInfo with StationID = "
+        << inStation.GetStationID() << " and DetectorID = " << static_cast<int>(inStation.GetDetectorID()) << ":";
+      LOG(error) << ">>> Already inserted L1BaseStationInfo object:";
+      insertionResult.first->Print();
+      LOG(error) << ">>> A dublicating L1BaseStationInfo object:";
+      inStation.Print();
+      assert((insertionResult.second)); // TODO: rewrite the assertion
+    }
+  }
+  LOG(debug) 
+    << "L1InitManager: adding a station with stationID = " << inStation.GetStationID() << " and detectorID = "
+    << static_cast<int>(inStation.GetDetectorID()) << ". Is active: " << isDetectorActive;
+
+  
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+void L1InitManager::Init() const
+{ // To be implemented
+  // Plans:
+  //  1. Must make a final check of the inititalization and turn on a corresponding trigger in L1Algo class to accept
+  //     the incoming data
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+void L1InitManager::PrintStations(int verbosityLevel) const
+{
+  if (verbosityLevel < 1) {
+    for (auto& station : fStationsInfo) {
+      LOG(info) << "----------- station: ";
+      LOG(info) << "\ttype = " << station.GetStationType();  // TMP
+      LOG(info) << "\tz = " << station.GetZdouble(); 
+    }
+  }
+  else {
+    for (auto& station : fStationsInfo) {
+      station.Print();
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+void L1InitManager::TransferL1StationArray(std::array<L1Station, L1Parameters::kMaxNstations>& destinationArray)
+{
+  /// First of all, we must check if L1Station was properly initialized
+  // TODO: actually, false condition will never reached (must thing about it, may be remove assertions from 
+  // CheckStationInfo and leave only warnings and flag)
+  bool ifStationsInitialized = CheckStationsInfo();
+  if (!ifStationsInitialized) {
+    LOG(error) << "L1InitManager::TransferL1StationArray: attempt to pass unitialized L1Station array to L1Algo core";
+    assert((ifStationsInitialized));
+  }
+
+  /// Check if destinationArraySize is enough for the transfer
+  int  totalStationsNumber = this->GetStationsNumber();
+  bool ifDestinationArraySizeOk = totalStationsNumber <= static_cast<int>(destinationArray.size());
+  if (!ifDestinationArraySizeOk) {
+    LOG(error) 
+      << "L1InitManager::TransferL1StationArray: destination array size (" << destinationArray.size()
+      << ") is smaller then actual number of active tracking stations (" << totalStationsNumber << ")";
+    assert((ifDestinationArraySizeOk));
+  }
+
+  auto destinationArrayIterator = destinationArray.begin();
+  for (const auto& item: fStationsInfo) {
+    *destinationArrayIterator = std::move(item.GetL1Station());
+    ++destinationArrayIterator;
+  }
+  LOG(info) << "L1InitManager: L1Station vector was successfully transfered to L1Algo core :)";
+}
+
+//
+// GETTERS
+//
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+int L1InitManager::GetStationsNumber(L1DetectorID detectorID) const
+{
+  auto ifDetectorIdDesired = [&detectorID](const L1BaseStationInfo& station) {
+    return station.GetDetectorID() == detectorID;
+  };
+  return std::count_if(fStationsInfo.begin(), fStationsInfo.end(), ifDetectorIdDesired);
+}
+
+//
+// SETTERS
+//
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+void L1InitManager::SetActiveDetectorIDs(const std::set<L1DetectorID>& detectorIDs)
+{
+  // TODO: To think about redifinition possibilities: should it be allowed or not?
+  fActiveDetectorIDs = detectorIDs;
+  fInitFlags[L1InitManager::kEactiveDetectorIDs] = true;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+void L1InitManager::SetFieldFunction(const std::function<void(const double (&xyz)[3], double (&B)[3])>& fieldFunction)
+{
+  if (!fInitFlags[L1InitManager::kEfieldFunction]) {
+    fFieldFunction = fieldFunction;
+    fInitFlags[L1InitManager::kEfieldFunction] = true;
+  }
+  else {
+    LOG(warn) << "L1InitManager::SetFieldFunction: attemt to reinitialize the field function. Ignored";
+  }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+void L1InitManager::SetStationsNumberCrosscheck(L1DetectorID detectorID, int nStations)
+{
+  // NOTE: We add and check only those detectors which will be active (?)
+  // For INACTIVE detectors the initialization code for it inside CbmL1/BmnL1 can (and must) be still in,
+  // but it will be ignored inside L1InitManager.
+  if (fActiveDetectorIDs.find(detectorID) != fActiveDetectorIDs.end()) { 
+    fStationsNumberCrosscheck[detectorID] = nStations;
+  }
+  
+  // Check if all the station numbers for active detectors are initialized now:
+  LOG(debug) << "SetStationsNumberCrosscheck called for detectorID = " << static_cast<int>(detectorID);
+  if (!fInitFlags[L1InitManager::kEstationsNumberCrosscheck]) {
+    bool ifInitialized = true;
+    for (auto item: fActiveDetectorIDs) {
+      if (fStationsNumberCrosscheck.find(item) == fStationsNumberCrosscheck.end()) {
+        LOG(warn) 
+          << "L1InitManager::SetStationsNumberCrosscheck: uninitialized number of stations for detectorID = "
+          << static_cast<int>(item);
+        ifInitialized = false;
+        break;
+      }
+    }
+    fInitFlags[L1InitManager::kEstationsNumberCrosscheck] = ifInitialized;
+  }
+  LOG(debug) << "InitResult: " << fInitFlags[L1InitManager::kEstationsNumberCrosscheck];
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+void L1InitManager::SetReferencePrimaryVertexPoints(double z0, double z1, double z2)
+{
+  if (fInitFlags[L1InitManager::kEprimaryVertexField]) {
+    LOG(warn) 
+      << "L1InitManager::SetReferencePrimaryVertexPoints: attempt to redefine reference points for field calculation "
+      << "near primary vertex. Ignore";
+    return;
+  }
+
+  // Check for field function
+  if (!fInitFlags[L1InitManager::kEfieldFunction]) {
+    LOG(error) 
+      << "L1InitManager::SetReferencePrimaryVertexPoints: attempt to set reference points for field calculation near "
+      << "primary vertex before the magnetic field function intialization";
+    assert((fInitFlags[L1InitManager::kEfieldFunction]));
+  }
+
+  constexpr int numberOfDimensions {3};
+  constexpr int numberOfReferencePoints {3};
+
+  std::array<double, numberOfReferencePoints> inputZ = { z0, z1, z2 }; // tmp array to store input assigned with index
+  std::array<L1FieldValue, numberOfReferencePoints> B = {};
+  std::array<fvec, numberOfReferencePoints> z = { z0, z1, z2 };
+  for (int idx = 0; idx < numberOfReferencePoints; ++idx) {
+    double point[numberOfDimensions] = {0., 0., inputZ[idx] };
+    double field[numberOfDimensions] = {};
+    fFieldFunction(point, field);
+    B[idx].x = field[0];
+    B[idx].y = field[1];
+    B[idx].z = field[2];
+  }
+  fPrimaryVertexFieldRegion.Set(B[0], z[0], B[1], z[1], B[2], z[2]);
+  fPrimaryVertexFieldValue = B[0];
+
+  fInitFlags[L1InitManager::kEprimaryVertexField] = true;
+}
+
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+bool L1InitManager::CheckStationsInfo()
+{
+  if (!fInitFlags[L1InitManager::kEstationsInfo]) {
+    bool ifInitPassed = true;
+
+    if (!fInitFlags[L1InitManager::kEifStationNumbersChecked]) {
+      for (const auto& itemDetector: fActiveDetectorIDs) {
+        int actualStationsNumber = GetStationsNumber(itemDetector);
+        int expectedStationsNumber = fStationsNumberCrosscheck.at(itemDetector);
+        if (actualStationsNumber != expectedStationsNumber) {
+          LOG(error) 
+            << "L1InitManager::CheckStationsInfo: Incorrect number of L1BaseStationInfo objects passed to the L1Manager "
+            << "for L1DetectorID = " << static_cast<int>(itemDetector) << ": " << actualStationsNumber << " of " 
+            << expectedStationsNumber << " expected";
+          ifInitPassed = false;
+        }
+      }
+      fInitFlags[L1InitManager::kEifStationNumbersChecked] = ifInitPassed;
+    }
+    if (!ifInitPassed) {
+      LOG(error) << "L1InitManager::CheckStationsInfo: initialization failed";
+      assert((ifInitPassed));
+    }
+
+    // Check for maximum allowed number of stations
+    int totalStationsNumber = GetStationsNumber();
+    if (totalStationsNumber > L1Parameters::kMaxNstations) {
+      LOG(fatal) 
+        << "Actual total number of registered stations (" << totalStationsNumber << ") is larger then designed one ("
+        << L1Parameters::kMaxNstations << "). Please, select another set of active tracking detectors";
+      // TODO: We have to provide an instruction of how to increase the kMaxNstations number keeping the code consistent
+      assert((totalStationsNumber <= L1Parameters::kMaxNstations));
+    }
+
+    fInitFlags[L1InitManager::kEstationsInfo] = true;
+  } 
+  else {
+    LOG(warn) << "L1InitManager: L1BaseStationInfo set has already been initialized";
+  }
+  // NOTE: we return a flag here to reduce a number of calls outside the funcition. In other hands we keep this flag
+  // to be consistent with other class fields initialization rules
+  return fInitFlags[L1InitManager::kEstationsInfo];
+} 
+
diff --git a/reco/L1/L1Algo/L1InitManager.h b/reco/L1/L1Algo/L1InitManager.h
index e234f1dac9..efc1e34833 100644
--- a/reco/L1/L1Algo/L1InitManager.h
+++ b/reco/L1/L1Algo/L1InitManager.h
@@ -8,20 +8,71 @@
  * @since 24.12.2021
  *
  ***********************************************************************************************************/
+#ifndef L1InitManager_h
+#define L1InitManager_h 1
 
 #include "L1BaseStationInfo.h"
 #include "L1Parameters.h"
-#include "L1Vector.h"
+#include "L1Field.h"
 
 //#include <string>
-#include <unordered_map>
+#include <bitset>
+#include <set>
+#include <memory> //unique_ptr
+
+/// Forward declaration of the tracking detectors scoped enumeration. Concrete realization of this enumeration must be
+/// determined in the concrete setup class (i.e. CbmL1/BmnL1)
+enum class L1DetectorID;
 
 /// Initialization manager for L1Aglo
 ///
-/// The L1InitManager class provides interface for L1Algo initialization
-
+/// ==== Expected initialization steps ==== (TODO: keep this instruction up-to-date)
+///
+/// 0. Implement your enum class L1DetectorID with detector systems used for tracking:
+///    IMPORTANT!!! Detectors must be sorted in the beam direction
+///    /// Concrete L1DetectorID implementation for CBM
+///    enum class L1DetectorID {
+///      kMvd,
+///      kSts,
+///      kMuch,
+///      kTof,
+///      kTrd
+///    };
+///
+/// 1. Get a pointer to the :L1InitManager field of L1Algo:
+/// 
+///    L1InitManager * initMan = algo->GetL1InitManager();
+///
+/// 2. Initialize a set of L1DetectorID's for detectors active in tracking:
+///
+///    std::set<L1DetectorID> activeTrackingDetectors { L1Detector::kMvd, L1Detector::kSts };
+///    initMan->SetActiveDetectorIDs(activeTrackingDetectors);
+///
+/// 3. Initialize number of stations for each detector:
+///
+///    initMan->SetStationsNumberCrosscheck(L1DetectorID::kMvd, NMvdStations)
+///    initMan->SetStationsNumberCrosscheck(L1DetectorID::kMvd, NStsStations);
+///
+/// 3. Initialize each station using L1BaseStationInfo:
+///
 class L1InitManager {
+private:
+  enum {
+    kEactiveDetectorIDs,        ///< If the detector sequence is set
+    kEstationsNumberCrosscheck, ///< If the crosscheck station numbers were setup
+    kEfieldFunction,            ///< If magnetic field getter funciton is set
+    kEprimaryVertexField,       ///< If magnetic field value and region defined at primary vertex
+    kEifStationNumbersChecked,  ///< If the station number was already checked
+    kEstationsInfo,             ///< If all the planned stations were added to the manager
+    kEL1StationTransfered,      ///< If the L1Station vector was already transfered to destination array
+    kEND
+  };
 public:
+  
+  //
+  // CONSTRUCTORS AND DESTRUCTOR
+  //
+
   /// Default constructor
   L1InitManager() = default;
   /// Destructor
@@ -35,40 +86,84 @@ public:
   /// Move assignment operator is forbidden
   L1InitManager& operator=(L1InitManager&& /*other*/) = delete;
 
+
+  //
+  // BASIC METHODS
+  //
+
+
   /// Adds another station of a given type using reference to a L1BaseStationInfo object
-  void AddStation(const L1BaseStationInfo& inStation)
-  {
-    fvStationsInfo.push_back(inStation);
-    ++fmStationsNumber[inStation.GetStationType()];
-    // TODO: Think, how we would like to initialize station ID
-  }
+  void AddStation(const L1BaseStationInfo& inStation);
   /// Adds another station of a given type using pointer to a L1BaseStationInfo object
-  void AddStation(const L1BaseStationInfo* inStationPtr)
-  {
-    fvStationsInfo.push_back(*inStationPtr);  // Copy is occured
-    ++fmStationsNumber[inStationPtr->GetStationType()];
-  }
-
-  /// Prints out a list of stations
-  void PrintStations(int verbosityLevel = 0)
-  {
-    if (verbosityLevel < 1) {
-      for (auto& station : fvStationsInfo) {
-        LOG(INFO) << "----------- station: ";
-        LOG(INFO) << "\ttype = " << station.GetStationType();  // TMP
-        LOG(INFO) << "\tz = " << station.GetZdouble(); 
-      }
-    }
-    else {
-      for (auto& station : fvStationsInfo) {
-        station.Print();
-      }
-    }
-  }
+  void AddStation(const L1BaseStationInfo* inStationPtr) { AddStation(*inStationPtr); }
+  /// Adds another station of a given type using std::unique_ptr-wraped pointer to L1BaseStationInfo
+  // TODO: Test weaknesses here
+  void AddStation(const std::unique_ptr<L1BaseStationInfo>& inStationUniquePtr) { AddStation(*inStationUniquePtr); }
+  /// Initializes L1Algo: transfers all caputred data to the L1 tracking core
+  void Init() const;
+  /// Prints a list of stations
+  void PrintStations(int verbosityLevel = 0) const;
+
+  /// Transfer an array of L1Stations formed inside a set of L1BaseStationInfo to a destination std::array
+  void TransferL1StationArray(std::array<L1Station, L1Parameters::kMaxNstations>& destinationArray);
+
+  //
+  // GETTERS
+  //
+
+  /// Gets a set of actie detectors for this analysis
+  std::set<L1DetectorID> GetActiveDetectorIDs() const { return fActiveDetectorIDs; }
+  /// Gets a total number of stations (NOTE: this number includes both active and unactive stations!)
+  int GetStationsNumber() const { return static_cast<int>(fStationsInfo.size()); }
+  /// Gets a number of stations for a particualr detector ID
+  int GetStationsNumber(L1DetectorID detectorID) const;
+  /// Gets a L1FieldRegion object at primary vertex
+  const L1FieldRegion& GetPrimaryVertexFieldRegion() const { return fPrimaryVertexFieldRegion; }
+  /// Gets a L1FieldValue object at primary vertex
+  const L1FieldValue& GetPrimaryVertexFieldValue() const { return fPrimaryVertexFieldValue; }
+
+  //
+  // SETTERS
+  //
+
+  /// Sets a set of active tracking detector IDs
+  void SetActiveDetectorIDs(const std::set<L1DetectorID>& detectorIDs);
+  /// Sets a magnetic field function, which will be applied for all the stations
+  void SetFieldFunction(const std::function<void(const double (&xyz)[3], double (&B)[3])>& fieldFcn);
+  /// Sets a number of stations for a particular tracking detector ID to provide initialization cross-check
+  void SetStationsNumberCrosscheck(L1DetectorID detectorID, int nStations);
+  /// Sets z coordinates referecne points in a vicinity of primary vertex to calculate L1FieldValue and L1FieldReference 
+  /// values
+  // TODO: Consider posibility for linear approximation
+  void SetReferencePrimaryVertexPoints(double z0, double z1, double z2);
+  
+
 
 private:
-  // TODO: TEST IT!!!!!!!!!!!!!!!!!!!!!
-  L1Vector<L1BaseStationInfo> fvStationsInfo {"L1InitManager::fvStationsInfo"};  ///< Vector containing all the stations
-  // TODO: Max stations is probably not optimal for vector initialization. Must think, what to do here. 
-  std::unordered_map<int, int> fmStationsNumber;  ///< Number of each station type <station type, counter>
+  /// Checker for L1BaseStationInfo set
+  /// \return true if all L1BaseStationInfo objects were initialized properly. Similar effect can be achieved by 
+  /// calling the fInitFlags[L1InitManager::kEstationsInfo] flag
+  bool CheckStationsInfo();
+
+  /* Basic fields */
+
+  std::bitset<L1InitManager::kEND> fInitFlags {};  ///< Initialization flags
+  std::set<L1DetectorID> fActiveDetectorIDs {};    ///< Set of tracking detectors, active during this analysis session
+  
+  /* Stations related fields */
+  
+  std::set<L1BaseStationInfo> fStationsInfo {};    ///< Set of L1BaseStationInfo objects
+  /// Map of station numbers used for initialization crosscheck   
+  std::unordered_map<L1DetectorID, int, EnumClassHash> fStationsNumberCrosscheck {};
+  /// A function which returns magnetic field vector B in a radius-vector xyz
+  std::function<void(const double (&xyz)[3], double (&B)[3])> fFieldFunction {[](const double (&)[3], double (&)[3]){}};
+  // NOTE: Stations of daetectors which will not be assigned as active, will not be included in the tracking!!!!!!!
+  // NOTE: fTotalNumberOfStations is excess field for logic, but it's imortant to track L1Algo initialization
+  
+  /* Vertex related fields */
+  L1FieldValue   fPrimaryVertexFieldValue {}; ///> L1FieldValue object at primary vertex
+  L1FieldRegion  fPrimaryVertexFieldRegion {}; ///> L1FieldRegion object at primary vertex
+  
 };
+
+#endif // L1InitManager_h
diff --git a/reco/L1/L1Algo/L1Parameters.h b/reco/L1/L1Algo/L1Parameters.h
index 59a3ea5e1e..3bc052549a 100644
--- a/reco/L1/L1Algo/L1Parameters.h
+++ b/reco/L1/L1Algo/L1Parameters.h
@@ -30,44 +30,46 @@
 
 // TODO: Create independent class of L1CATrackFinderIterations ???
 
-/// All possible iteration species of Track Finder algorithm
-enum class L1CATrackFinderIter {
-  kFastPrim,       ///< primary fast tracks
-  kAllPrim,        ///< primary all tracks
-  kAllPrimJump,    ///< primary all tracks with jumped triplets
-  kAllSec,         ///< secondary all tracks
-  kAllPrimE,       ///< primary all electron tracks
-  kAllSecE,        ///< secondary all electron tracks 
-  kFastPrimJump,   ///< primary fast tracks with jumped triplets
-  kAllSecJump      ///< secondary all tracks with jumped triplets
-};
-
-// Type for mapping L1CATrackFinder parameters, which are dependent from the current track finder iteration
-template <typename T>
-using L1CATrackFinderIterParameterMap_t = std::unordered_map<L1CATrackFinderIter, T, EnumClassHash>;
 
-
-const L1CATrackFinderIterParameterMap_t<std::string> kTrackFinderIterNames = {
-  { L1CATrackFinderIter::kFastPrim,     "Primary tracks, fast" },
-  { L1CATrackFinderIter::kAllPrim,      "Primary tracks, all" },
-  { L1CATrackFinderIter::kAllPrimJump,  "Primary tracks with jumped triplets, all" },
-  { L1CATrackFinderIter::kAllSec,       "Secondary tracks, all" },
-  { L1CATrackFinderIter::kAllPrimE,     "Primary electron tracks, all" },
-  { L1CATrackFinderIter::kAllSecE,      "Secondary electron tracks, all" },
-  { L1CATrackFinderIter::kFastPrimJump, "Primary tracks with jumped triplets, fast" },
-  { L1CATrackFinderIter::kAllSecJump,   "Secondary tracks with jumped triplets, all" }
-};
-
-const L1CATrackFinderIterParameterMap_t<std::string> kTrackFinderIterNamesShort = {
-  { L1CATrackFinderIter::kFastPrim,     "FastPrim" },
-  { L1CATrackFinderIter::kAllPrim,      "AllPrim" },
-  { L1CATrackFinderIter::kAllPrimJump,  "AllPrimJump" },
-  { L1CATrackFinderIter::kAllSec,       "AllSec" },
-  { L1CATrackFinderIter::kAllPrimE,     "AllPrimE" },
-  { L1CATrackFinderIter::kAllSecE,      "AllSecE" },
-  { L1CATrackFinderIter::kFastPrimJump, "FastPrimJump" },
-  { L1CATrackFinderIter::kAllSecJump,   "AllSecJump" }
-};
+/////// > Will be moved to a separate class
+/// All possible iteration species of Track Finder algorithm
+// enum class L1CATrackFinderIter {
+//   kFastPrim,       ///< primary fast tracks
+//   kAllPrim,        ///< primary all tracks
+//   kAllPrimJump,    ///< primary all tracks with jumped triplets
+//   kAllSec,         ///< secondary all tracks
+//   kAllPrimE,       ///< primary all electron tracks
+//   kAllSecE,        ///< secondary all electron tracks 
+//   kFastPrimJump,   ///< primary fast tracks with jumped triplets
+//   kAllSecJump      ///< secondary all tracks with jumped triplets
+// };
+// 
+// // Type for mapping L1CATrackFinder parameters, which are dependent from the current track finder iteration
+// template <typename T>
+// using L1CATrackFinderIterParameterMap_t = std::unordered_map<L1CATrackFinderIter, T, EnumClassHash>;
+// 
+// ////// > Will be moved to separate class
+// const L1CATrackFinderIterParameterMap_t<std::string> kTrackFinderIterNames = {
+//   { L1CATrackFinderIter::kFastPrim,     "Primary tracks, fast" },
+//   { L1CATrackFinderIter::kAllPrim,      "Primary tracks, all" },
+//   { L1CATrackFinderIter::kAllPrimJump,  "Primary tracks with jumped triplets, all" },
+//   { L1CATrackFinderIter::kAllSec,       "Secondary tracks, all" },
+//   { L1CATrackFinderIter::kAllPrimE,     "Primary electron tracks, all" },
+//   { L1CATrackFinderIter::kAllSecE,      "Secondary electron tracks, all" },
+//   { L1CATrackFinderIter::kFastPrimJump, "Primary tracks with jumped triplets, fast" },
+//   { L1CATrackFinderIter::kAllSecJump,   "Secondary tracks with jumped triplets, all" }
+// };
+// 
+// const L1CATrackFinderIterParameterMap_t<std::string> kTrackFinderIterNamesShort = {
+//   { L1CATrackFinderIter::kFastPrim,     "FastPrim" },
+//   { L1CATrackFinderIter::kAllPrim,      "AllPrim" },
+//   { L1CATrackFinderIter::kAllPrimJump,  "AllPrimJump" },
+//   { L1CATrackFinderIter::kAllSec,       "AllSec" },
+//   { L1CATrackFinderIter::kAllPrimE,     "AllPrimE" },
+//   { L1CATrackFinderIter::kAllSecE,      "AllSecE" },
+//   { L1CATrackFinderIter::kFastPrimJump, "FastPrimJump" },
+//   { L1CATrackFinderIter::kAllSecJump,   "AllSecJump" }
+// };
 
 class L1Parameters {
 public:
@@ -79,15 +81,17 @@ public:
                                                            // order instead of this?
   static constexpr int kMaxFieldApproxPolynomialOrder {5}; ///> Order of polynomial to approximate field in the vicinity of station plane
 
-  static constexpr unsigned int kStationBits {6};  ///> Amount of bits to code one station
-  static constexpr unsigned int kThreadBits {6};  ///> Amount of bits to code one thread
-  static constexpr unsigned int kTripletBits {32 - kStationBits - kThreadBits};  ///> Amount of bits to code one triple
+  static constexpr unsigned int kStationBits {6u};  ///> Amount of bits to code one station
+  static constexpr unsigned int kThreadBits {6u};  ///> Amount of bits to code one thread
+  static constexpr unsigned int kTripletBits {32u - kStationBits - kThreadBits};  ///> Amount of bits to code one triple
+
+  static constexpr int kMaxNstations { 1u << kStationBits };  ///> Max number of stations, 2^6  = 64
+  static constexpr int kMaxNthreads  { 1u << kThreadBits };  ///> Max number of threads, 2^6  = 64
+  static constexpr int kMaxNtriplets { 1u << kTripletBits };  ///> Max number of triplets, 2^20 = 1,048,576
 
-  static constexpr unsigned int kMaxNstations {1 << kStationBits};  ///> Max number of stations, 2^6  = 64
-  static constexpr unsigned int kMaxNthreads {1 << kThreadBits};  ///> Max number of threads, 2^6  = 64
-  static constexpr unsigned int kMaxNtriplets {1 << kTripletBits};  ///> Max number of triplets, 2^20 = 1,048,576
+  static constexpr int kStandardIOWidth {15};  ///> Width of one output entry, passed to the std::setw()
 
-  static constexpr short kStandardIOWidth = 15;  ///> Width of one output entry, passed to the std::setw()
+  static constexpr int kAssertionLevel {0};  ///> Assertion level
 
 public:
   //-------------------------------------------------------------------------------------------------------//
@@ -141,73 +145,74 @@ public:
   /// Sets upper-bound cut on max number of triplets per one doublet
   void SetMaxTripletPerDoublets(unsigned int value) { fMaxTripletPerDoublets = value; }
 
-  /// Sets track finder iteration sequence
-  void SetTrackFinderIterSequence(const L1Vector<L1CATrackFinderIter>& iterations) {
-    fTrackFinderIterSequence = iterations;
-  }
-  
-  /// Sets track Chi2 upper cut
-  /// \param tfIteration Track Finder iteration of the L1 algorithm run
-  /// \param chi2Cut     Upper cut on track chi2 during selected iteration 
-  void SetTrackChi2Cut(L1CATrackFinderIter tfIteration, float chi2Cut) { fTrackChi2Cut[tfIteration] = chi2Cut; }
-  void SetTrackChi2Cut(float chi2Cut) { SetSameValueToMap(chi2Cut, fTrackChi2Cut); }
-  void SetTrackChi2Cut(const L1CATrackFinderIterParameterMap_t<float>& newValues) 
-  { 
-    SetMappedValuesToMap(newValues, fTrackChi2Cut); 
-  }
-  /// Sets triplet Chi2 upper cut
-  /// \param tfIteration Track Finder iteration of the L1 algorithm run
-  /// \param chi2Cut     Upper cut on triplet chi2 during selected iteration 
-  void SetTripletChi2Cut(L1CATrackFinderIter tfIteration, float chi2Cut) { fTripletChi2Cut[tfIteration] = chi2Cut; }
-  void SetTripletChi2Cut(float chi2Cut) { SetSameValueToMap(chi2Cut, fTripletChi2Cut); }
-  void SetTripletChi2Cut(const L1CATrackFinderIterParameterMap_t<float>& newValues) 
-  {
-    SetMappedValuesToMap(newValues, fTripletChi2Cut);
-  }
-  /// Sets triplet Chi2 upper cut 
-  /// \param tfIteration Track Finder iteration of the L1 algorithm run
-  /// \param chi2Cut     Upper cut on triplet chi2 during selected iteration 
-  void SetDoubletChi2Cut(L1CATrackFinderIter tfIteration, float chi2Cut) { fDoubletChi2Cut[tfIteration] = chi2Cut; }
-  void SetDoubletChi2Cut(float chi2Cut) { SetSameValueToMap(chi2Cut, fDoubletChi2Cut); }
-  void SetDoubletChi2Cut(const L1CATrackFinderIterParameterMap_t<float>& newValues) 
-  { 
-    SetMappedValuesToMap(newValues, fDoubletChi2Cut);
-  }
+  // /// Sets track finder iteration sequence
+  // void SetTrackFinderIterSequence(const L1Vector<L1CATrackFinderIter>& iterations) {
+  //   fTrackFinderIterSequence = iterations;
+  // }
+  // 
+  // /// Sets track Chi2 upper cut
+  // /// \param tfIteration Track Finder iteration of the L1 algorithm run
+  // /// \param chi2Cut     Upper cut on track chi2 during selected iteration 
+  // void SetTrackChi2Cut(L1CATrackFinderIter tfIteration, float chi2Cut) { fTrackChi2Cut[tfIteration] = chi2Cut; }
+  // void SetTrackChi2Cut(float chi2Cut) { SetSameValueToMap(chi2Cut, fTrackChi2Cut); }
+  // void SetTrackChi2Cut(const L1CATrackFinderIterParameterMap_t<float>& newValues) 
+  // { 
+  //   SetMappedValuesToMap(newValues, fTrackChi2Cut); 
+  // }
+  // /// Sets triplet Chi2 upper cut
+  // /// \param tfIteration Track Finder iteration of the L1 algorithm run
+  // /// \param chi2Cut     Upper cut on triplet chi2 during selected iteration 
+  // void SetTripletChi2Cut(L1CATrackFinderIter tfIteration, float chi2Cut) { fTripletChi2Cut[tfIteration] = chi2Cut; }
+  // void SetTripletChi2Cut(float chi2Cut) { SetSameValueToMap(chi2Cut, fTripletChi2Cut); }
+  // void SetTripletChi2Cut(const L1CATrackFinderIterParameterMap_t<float>& newValues) 
+  // {
+  //   SetMappedValuesToMap(newValues, fTripletChi2Cut);
+  // }
+  // /// Sets triplet Chi2 upper cut 
+  // /// \param tfIteration Track Finder iteration of the L1 algorithm run
+  // /// \param chi2Cut     Upper cut on triplet chi2 during selected iteration 
+  // void SetDoubletChi2Cut(L1CATrackFinderIter tfIteration, float chi2Cut) { fDoubletChi2Cut[tfIteration] = chi2Cut; }
+  // void SetDoubletChi2Cut(float chi2Cut) { SetSameValueToMap(chi2Cut, fDoubletChi2Cut); }
+  // void SetDoubletChi2Cut(const L1CATrackFinderIterParameterMap_t<float>& newValues) 
+  // { 
+  //   SetMappedValuesToMap(newValues, fDoubletChi2Cut);
+  // }
+  // 
   
   // ***** Getters ***** //
   unsigned int GetMaxDoubletsPerSinglet() const { return fMaxDoubletsPerSinglet; }
   unsigned int GetMaxTripletPerDoublets() const { return fMaxTripletPerDoublets; }
   
-  /// Gets track Chi2 upper cut
-  /// \param tfIteration Track Finder iteration of the L1 algorithm run
-  /// \return            Upper cut on track chi2 during selected iteration 
-  float GetTrackChi2Cut(L1CATrackFinderIter tfIteration)   const { return fTrackChi2Cut.at(tfIteration); }
-  /// Gets triplet Chi2 upper cut
-  /// \param tfIteration Track Finder iteration of the L1 algorithm run
-  /// \return            Upper cut on triplet chi2 during selected iteration 
-  float GetTripletChi2Cut(L1CATrackFinderIter tfIteration) const { return fTripletChi2Cut.at(tfIteration); }
-  /// Gets triplet Chi2 upper cut
-  /// \param tfIteration Track Finder iteration of the L1 algorithm run
-  /// \return            Upper cut on triplet chi2 during selected iteration 
-  float GetDoubletChi2Cut(L1CATrackFinderIter tfIteration) const { return fDoubletChi2Cut.at(tfIteration); }
+  // /// Gets track Chi2 upper cut
+  // /// \param tfIteration Track Finder iteration of the L1 algorithm run
+  // /// \return            Upper cut on track chi2 during selected iteration 
+  // float GetTrackChi2Cut(L1CATrackFinderIter tfIteration)   const { return fTrackChi2Cut.at(tfIteration); }
+  // /// Gets triplet Chi2 upper cut
+  // /// \param tfIteration Track Finder iteration of the L1 algorithm run
+  // /// \return            Upper cut on triplet chi2 during selected iteration 
+  // float GetTripletChi2Cut(L1CATrackFinderIter tfIteration) const { return fTripletChi2Cut.at(tfIteration); }
+  // /// Gets triplet Chi2 upper cut
+  // /// \param tfIteration Track Finder iteration of the L1 algorithm run
+  // /// \return            Upper cut on triplet chi2 during selected iteration 
+  // float GetDoubletChi2Cut(L1CATrackFinderIter tfIteration) const { return fDoubletChi2Cut.at(tfIteration); }
   
   
   //-------------------------------------------------------------------------------------------------------//
   //    Auxilary methods                                                                                   //
   //-------------------------------------------------------------------------------------------------------//
 public:
-  void PrintTrackFinderIterSequence() const
-  {  
-    LOG(INFO) << "== L1Algo track finder iterations sequence ==========";
-    LOG(INFO) << "";
-    int idx = 0;
-    for (auto& iteration: fTrackFinderIterSequence) {
-      LOG(INFO) << "  " << std::setw(2) << std::setfill(' ') << idx << ") " << kTrackFinderIterNames.at(iteration);
-      ++idx;
-    }
-    LOG(INFO) << "";
-    LOG(INFO) << "=====================================================";
-  }
+  //void PrintTrackFinderIterSequence() const
+  //{  
+  //  LOG(INFO) << "== L1Algo track finder iterations sequence ==========";
+  //  LOG(INFO) << "";
+  //  int idx = 0;
+  //  for (auto& iteration: fTrackFinderIterSequence) {
+  //    LOG(INFO) << "  " << std::setw(2) << std::setfill(' ') << idx << ") " << kTrackFinderIterNames.at(iteration);
+  //    ++idx;
+  //  }
+  //  LOG(INFO) << "";
+  //  LOG(INFO) << "=====================================================";
+  //}
 
 private:
   /// Aux method for printing mapped Track Finder parameters
@@ -224,45 +229,45 @@ private:
   unsigned int fMaxDoubletsPerSinglet {150};  ///<
   unsigned int fMaxTripletPerDoublets {15};  ///<
 
-  L1Vector<L1CATrackFinderIter> fTrackFinderIterSequence {}; ///< Sequence of iterations in the track finder algorithm 
+  // L1Vector<L1CATrackFinderIter> fTrackFinderIterSequence {}; ///< Sequence of iterations in the track finder algorithm 
 
-  // TODO: Develope naming system for these constants
-  L1CATrackFinderIterParameterMap_t<float> fTrackChi2Cut {
-    { L1CATrackFinderIter::kFastPrim,     10.f },
-    { L1CATrackFinderIter::kAllPrim,      10.f },
-    { L1CATrackFinderIter::kAllPrimJump,  10.f },
-    { L1CATrackFinderIter::kAllSec,       10.f },
-    { L1CATrackFinderIter::kAllPrimE,     10.f },
-    { L1CATrackFinderIter::kAllSecE,      10.f },
-    { L1CATrackFinderIter::kFastPrimJump, 10.f },
-    { L1CATrackFinderIter::kAllSecJump,   10.f }
-  };
-  // TODO: What is the meaning of the following numbers?
-  //   23.4450 <- 7.815 * 3
-  //   18.7560 <- 6.252 * 3
-  //   11.3449 * 2. / 3.
-  //   
-  L1CATrackFinderIterParameterMap_t<float> fTripletChi2Cut {
-    { L1CATrackFinderIter::kFastPrim,     23.4450f }, // kFastPrimIter
-    { L1CATrackFinderIter::kAllPrim,      23.4450f },
-    { L1CATrackFinderIter::kAllPrimE,     23.4450f },
-    { L1CATrackFinderIter::kAllPrimJump,  18.7560f },
-    { L1CATrackFinderIter::kAllSec,       18.7560f },
-    { L1CATrackFinderIter::kAllSecE,      18.7560f },
-    { L1CATrackFinderIter::kFastPrimJump, 21.1075f },
-    { L1CATrackFinderIter::kAllSecJump,   21.1075f }
-  };
+  // // TODO: Develope naming system for these constants
+  // L1CATrackFinderIterParameterMap_t<float> fTrackChi2Cut {
+  //   { L1CATrackFinderIter::kFastPrim,     10.f },
+  //   { L1CATrackFinderIter::kAllPrim,      10.f },
+  //   { L1CATrackFinderIter::kAllPrimJump,  10.f },
+  //   { L1CATrackFinderIter::kAllSec,       10.f },
+  //   { L1CATrackFinderIter::kAllPrimE,     10.f },
+  //   { L1CATrackFinderIter::kAllSecE,      10.f },
+  //   { L1CATrackFinderIter::kFastPrimJump, 10.f },
+  //   { L1CATrackFinderIter::kAllSecJump,   10.f }
+  // };
+  // // TODO: What is the meaning of the following numbers?
+  // //   23.4450 <- 7.815 * 3
+  // //   18.7560 <- 6.252 * 3
+  // //   11.3449 * 2. / 3.
+  // //   
+  // L1CATrackFinderIterParameterMap_t<float> fTripletChi2Cut {
+  //   { L1CATrackFinderIter::kFastPrim,     23.4450f }, // kFastPrimIter
+  //   { L1CATrackFinderIter::kAllPrim,      23.4450f },
+  //   { L1CATrackFinderIter::kAllPrimE,     23.4450f },
+  //   { L1CATrackFinderIter::kAllPrimJump,  18.7560f },
+  //   { L1CATrackFinderIter::kAllSec,       18.7560f },
+  //   { L1CATrackFinderIter::kAllSecE,      18.7560f },
+  //   { L1CATrackFinderIter::kFastPrimJump, 21.1075f },
+  //   { L1CATrackFinderIter::kAllSecJump,   21.1075f }
+  // };
 
-  L1CATrackFinderIterParameterMap_t<float> fDoubletChi2Cut {
-    { L1CATrackFinderIter::kFastPrim,     11.3449 * 2.f / 3.f },
-    { L1CATrackFinderIter::kAllPrim,      11.3449 * 2.f / 3.f },
-    { L1CATrackFinderIter::kAllPrimJump,  11.3449 * 2.f / 3.f },
-    { L1CATrackFinderIter::kAllSec,       11.3449 * 2.f / 3.f },
-    { L1CATrackFinderIter::kAllPrimE,     11.3449 * 2.f / 3.f },
-    { L1CATrackFinderIter::kAllSecE,      11.3449 * 2.f / 3.f },
-    { L1CATrackFinderIter::kFastPrimJump, 11.3449 * 2.f / 3.f },
-    { L1CATrackFinderIter::kAllSecJump,   11.3449 * 2.f / 3.f }
-  };
+  // L1CATrackFinderIterParameterMap_t<float> fDoubletChi2Cut {
+  //   { L1CATrackFinderIter::kFastPrim,     11.3449 * 2.f / 3.f },
+  //   { L1CATrackFinderIter::kAllPrim,      11.3449 * 2.f / 3.f },
+  //   { L1CATrackFinderIter::kAllPrimJump,  11.3449 * 2.f / 3.f },
+  //   { L1CATrackFinderIter::kAllSec,       11.3449 * 2.f / 3.f },
+  //   { L1CATrackFinderIter::kAllPrimE,     11.3449 * 2.f / 3.f },
+  //   { L1CATrackFinderIter::kAllSecE,      11.3449 * 2.f / 3.f },
+  //   { L1CATrackFinderIter::kFastPrimJump, 11.3449 * 2.f / 3.f },
+  //   { L1CATrackFinderIter::kAllSecJump,   11.3449 * 2.f / 3.f }
+  // };
 };
 
 #endif  // L1Parameters_h
diff --git a/reco/L1/L1Algo/L1Station.h b/reco/L1/L1Algo/L1Station.h
index fd3770e428..b2305966b3 100644
--- a/reco/L1/L1Algo/L1Station.h
+++ b/reco/L1/L1Algo/L1Station.h
@@ -13,23 +13,24 @@
 class L1Station {
 
 public:
-  L1Station()
-    : type(0)
-    , timeInfo(0)
-    , z(0)
-    , Rmin(0)
-    , Rmax(0)
-    , Sy(0)
-    ,  /// z-position, min & max station radius, field integral
-    materialInfo()
-    , fieldSlice()
-    , frontInfo()
-    , backInfo()
-    , xInfo()
-    , yInfo()
-    , XYInfo()
-  {
-  }
+  // TODO: rewrite initialization (default values to fields, remove constructor (check struct))
+  //L1Station()
+  //  : type(0)
+  //  , timeInfo(0)
+  //  , z(0)
+  //  , Rmin(0)
+  //  , Rmax(0)
+  //  , Sy(0)
+  //  ,  /// z-position, min & max station radius, field integral
+  //  materialInfo()
+  //  , fieldSlice()
+  //  , frontInfo()
+  //  , backInfo()
+  //  , xInfo()
+  //  , yInfo()
+  //  , XYInfo()
+  //{
+  //}
 
   // TODO: test this constructors
   //L1Station(const L1Station &) = default;
@@ -37,19 +38,65 @@ public:
   //L1Station(L1Station &&) = default;
   //L1Station & operator=(L1Station &&) = default;
 
-  int type;
-  int timeInfo;
-  fvec z;
-  fvec Rmin;
-  fvec Rmax;
-  fvec Sy;
-  L1MaterialInfo materialInfo;
-  L1FieldSlice fieldSlice;
-  L1UMeasurementInfo frontInfo;
-  L1UMeasurementInfo backInfo;
-  L1UMeasurementInfo xInfo;
-  L1UMeasurementInfo yInfo;
-  L1XYMeasurementInfo XYInfo;
+  int type {0};
+  int timeInfo {0};
+  fvec z {0};
+  fvec Rmin {0};
+  fvec Rmax {0};
+  fvec Sy {0};
+  L1MaterialInfo materialInfo {};
+  L1FieldSlice fieldSlice {};
+  L1UMeasurementInfo frontInfo {};
+  L1UMeasurementInfo backInfo {};
+  L1UMeasurementInfo xInfo {};
+  L1UMeasurementInfo yInfo {};
+  L1XYMeasurementInfo XYInfo {};
+
+
+  void Print() const
+  {
+    LOG(info) << "==== L1Station object at " << this;
+    LOG(info) << "- L1Station fields:";
+    LOG(info) << "--- Station type ID:             " << type;
+    LOG(info) << "--- z position:                  " << z[0];
+    LOG(info) << "--- Rmin:                        " << Rmin[0];
+    LOG(info) << "--- Rmax:                        " << Rmax[0];
+    LOG(info) << "--- Thickness (X), cm:           " << materialInfo.thick[0];
+    LOG(info) << "--- Radiational length (X0), cm: " << materialInfo.RL[0];
+    LOG(info) << "--- X / X0:                      " << materialInfo.RadThick[0];
+    LOG(info) << "--- log(X / X0):                 " << materialInfo.logRadThick[0];
+    LOG(info) << "--- Field approximation coefficients:";
+    LOG(info) << "      idx         CX         CY         CZ";
+    for (int idx = 0; idx < 21; ++idx) {
+      LOG(info) 
+        << std::setw(9) << std::setfill(' ') << idx << ' ' << std::setw(10) << std::setfill(' ')
+        << fieldSlice.cx[idx][0] << ' ' << std::setw(10) << std::setfill(' ')
+        << fieldSlice.cy[idx][0] << ' ' << std::setw(10) << std::setfill(' ')
+        << fieldSlice.cz[idx][0];
+    }
+    LOG(info) << "--- Strips geometry:";
+    LOG(info) << "----- Front:";
+    LOG(info) << "------- cos(phi):            " << frontInfo.cos_phi[0];
+    LOG(info) << "------- sin(phi):            " << frontInfo.sin_phi[0];
+    LOG(info) << "------- sigma2:              " << frontInfo.sigma2[0];
+    LOG(info) << "----- Back:";
+    LOG(info) << "------- cos(phi):            " << backInfo.cos_phi[0];
+    LOG(info) << "------- sin(phi):            " << backInfo.sin_phi[0];
+    LOG(info) << "------- sigma2:              " << backInfo.sigma2[0];
+    LOG(info) << "----- XY cov matrix:";
+    LOG(info) << "------- C00:                 " << XYInfo.C00[0];
+    LOG(info) << "------- C10:                 " << XYInfo.C10[0];
+    LOG(info) << "------- C11:                 " << XYInfo.C11[0];
+    LOG(info) << "----- X layer:";
+    LOG(info) << "------- cos(phi):            " << xInfo.cos_phi[0];
+    LOG(info) << "------- sin(phi):            " << xInfo.sin_phi[0];
+    LOG(info) << "------- sigma2:              " << xInfo.sigma2[0];
+    LOG(info) << "----- Y layer:";
+    LOG(info) << "------- cos(phi):            " << yInfo.cos_phi[0];
+    LOG(info) << "------- sin(phi):            " << yInfo.sin_phi[0];
+    LOG(info) << "------- sigma2:              " << yInfo.sigma2[0];
+    LOG(info) << "";
+  }
 
 } _fvecalignment;
 
diff --git a/reco/L1/L1Algo/L1Vector.h b/reco/L1/L1Algo/L1Vector.h
index 81b88d25c1..51ecf90d7a 100644
--- a/reco/L1/L1Algo/L1Vector.h
+++ b/reco/L1/L1Algo/L1Vector.h
@@ -45,7 +45,10 @@ public:
   {
   }
 
-
+  /// Constructor to make initializations like L1Vector<int> myVector {"MyVector", {1, 2, 3}}
+  L1Vector(const std::string& name, std::initializer_list<T> init): Tbase(init), fName(name)
+  {
+  }
 
   L1Vector(const L1Vector& v) : Tbase() { *this = v; }
 
-- 
GitLab