From 9cf4a05a08e48b8020e91619082995fe532cc81d Mon Sep 17 00:00:00 2001
From: Dominik Smith <d.smith@gsi.de>
Date: Thu, 11 Jul 2024 16:38:21 +0200
Subject: [PATCH] Cleaned up the core tracking classes. Summary of changes:

- Removed access to ca::Framework from ca::TrackExtender, ca::TrackFitter
  ca::TripletConstructor, ca::CloneMerger, ca::TrackFinder and ca::TrackFinderWindow.
- Simplified the interfaces of these classes.
- General instruction-wise cleanup of these classes (applied std functions in
  some places etc.). In particular, streamlining of ca::TrackFinder.
- Made debugging functions in ca::Framework static.
- Moved TrackingMode enum from CaFramework.h to CaParameters.h (needed
  to avoid cyclic header file dependency).
- Moved some magnetic-field dependent variables to ca::TripletConstructor (they are
  only used there).
- Restricted the scope of many variables, i.e. turned class-fields into
  local variables in many instances (e.g. fvMonitorDataThread, fvTrackFinderWindow,
  fTrackingMode, fvWData, fvWindowStartThread, fvWindowEndThread,
  fvStatNwindows, fvStatNhitsProcessed, fvHitFirstTriplet and fvHitNofTriplets).
- Eliminated the Init() functions of some classes. Moved initialization
  to the constructors.
- Improved distinction between class-parameters and working data.
  Class parameters are passed to constructor, working data is passed as
  arguments to function calls.
---
 algo/ca/TrackingChain.cxx                     |   4 +-
 algo/ca/core/pars/CaParameters.h              |  11 +-
 algo/ca/core/tracking/CaCloneMerger.cxx       |  25 +-
 algo/ca/core/tracking/CaCloneMerger.h         |  18 +-
 algo/ca/core/tracking/CaFramework.cxx         |  47 +-
 algo/ca/core/tracking/CaFramework.h           | 121 +----
 algo/ca/core/tracking/CaTrackExtender.cxx     |  74 +--
 algo/ca/core/tracking/CaTrackExtender.h       |  13 +-
 algo/ca/core/tracking/CaTrackFinder.cxx       | 513 ++++++++----------
 algo/ca/core/tracking/CaTrackFinder.h         |  41 +-
 algo/ca/core/tracking/CaTrackFinderWindow.cxx | 286 +++++-----
 algo/ca/core/tracking/CaTrackFinderWindow.h   |  84 ++-
 algo/ca/core/tracking/CaTrackFitter.cxx       |  54 +-
 algo/ca/core/tracking/CaTrackFitter.h         |  17 +-
 .../ca/core/tracking/CaTripletConstructor.cxx | 156 +++---
 algo/ca/core/tracking/CaTripletConstructor.h  |  16 +-
 reco/L1/CbmL1.cxx                             |  20 +-
 reco/L1/CbmL1.h                               |  14 +-
 reco/L1/CbmL1Performance.cxx                  |   4 +-
 reco/L1/L1Algo/utils/L1AlgoDraw.cxx           |  38 +-
 20 files changed, 763 insertions(+), 793 deletions(-)

diff --git a/algo/ca/TrackingChain.cxx b/algo/ca/TrackingChain.cxx
index 39178f8573..6481750481 100644
--- a/algo/ca/TrackingChain.cxx
+++ b/algo/ca/TrackingChain.cxx
@@ -86,7 +86,7 @@ void TrackingChain::Init()
   fCaFramework.SetNofThreads(Opts().NumOMPThreads() == std::nullopt ? openmp::GetMaxThreads()
                                                                     : *(Opts().NumOMPThreads()));
   fCaFramework.ReceiveParameters(std::move(parameters));
-  fCaFramework.Init(ca::Framework::TrackingMode::kMcbm);
+  fCaFramework.Init(ca::TrackingMode::kMcbm);
 
   // ------ Initialize QA modules
   if (fQa.IsSenderDefined()) {
@@ -110,7 +110,7 @@ TrackingChain::Output_t TrackingChain::Run(Input_t recoResults)
 
   // ----- Run reconstruction ------------------------------------------------------------------------------------------
   fCaFramework.SetMonitorData(fCaMonitorData);
-  fCaFramework.fTrackFinder.FindTracks();
+  fCaFramework.FindTracks();
   fCaMonitorData = fCaFramework.GetMonitorData();
 
   // ----- Init output data --------------------------------------------------------------------------------------------
diff --git a/algo/ca/core/pars/CaParameters.h b/algo/ca/core/pars/CaParameters.h
index a7809c1155..30a0496d7c 100644
--- a/algo/ca/core/pars/CaParameters.h
+++ b/algo/ca/core/pars/CaParameters.h
@@ -35,8 +35,15 @@ namespace cbm::algo::ca
   /// Type definitions for used containers
   using IterationsContainer_t = cbm::algo::ca::Vector<cbm::algo::ca::Iteration>;
   template<typename DataT>
-  using StationsContainer_t   = std::array<ca::Station<DataT>, constants::size::MaxNstations>;
-  using MaterialContainer_t   = std::array<ca::MaterialMap, constants::size::MaxNstations>;
+  using StationsContainer_t = std::array<ca::Station<DataT>, constants::size::MaxNstations>;
+  using MaterialContainer_t = std::array<ca::MaterialMap, constants::size::MaxNstations>;
+
+  enum TrackingMode
+  {
+    kSts,
+    kGlobal,
+    kMcbm
+  };
 
   /// \class cbm::algo::ca::Parameters
   /// \brief A container for all external parameters of the CA tracking algorithm
diff --git a/algo/ca/core/tracking/CaCloneMerger.cxx b/algo/ca/core/tracking/CaCloneMerger.cxx
index 53c1eba4bf..5755539265 100644
--- a/algo/ca/core/tracking/CaCloneMerger.cxx
+++ b/algo/ca/core/tracking/CaCloneMerger.cxx
@@ -22,7 +22,7 @@ using namespace cbm::algo;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-CloneMerger::CloneMerger(const ca::Framework& algo) : frAlgo(algo) {}
+CloneMerger::CloneMerger(const ca::Parameters<fvec>& pars, const float mass) : fParameters(pars), fDefaultMass(mass) {}
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
@@ -30,8 +30,11 @@ CloneMerger::~CloneMerger() {}
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void CloneMerger::Exec(Vector<Track>& extTracks, Vector<ca::HitIndex_t>& extRecoHits)
+void CloneMerger::Exec(const ca::InputData& input, WindowData& wData)
 {
+  Vector<Track>& extTracks            = wData.RecoTracks();
+  Vector<ca::HitIndex_t>& extRecoHits = wData.RecoHitIndices();
+
   Vector<unsigned short>& firstStation = fTrackFirstStation;
   Vector<unsigned short>& lastStation  = fTrackLastStation;
   Vector<ca::HitIndex_t>& firstHit     = fTrackFirstHit;
@@ -65,10 +68,10 @@ void CloneMerger::Exec(Vector<Track>& extTracks, Vector<ca::HitIndex_t>& extReco
 
   for (int iTr = 0; iTr < nTracks; iTr++) {
     firstHit[iTr]     = start_hit;
-    firstStation[iTr] = frAlgo.GetInputData().GetHit(extRecoHits[start_hit]).Station();
+    firstStation[iTr] = input.GetHit(extRecoHits[start_hit]).Station();
     start_hit += extTracks[iTr].fNofHits - 1;
     lastHit[iTr]     = start_hit;
-    lastStation[iTr] = frAlgo.GetInputData().GetHit(extRecoHits[start_hit]).Station();
+    lastStation[iTr] = input.GetHit(extRecoHits[start_hit]).Station();
     start_hit++;
 
     isStored[iTr]              = false;
@@ -78,12 +81,12 @@ void CloneMerger::Exec(Vector<Track>& extTracks, Vector<ca::HitIndex_t>& extReco
   }
 
   ca::TrackFit fitB;
-  fitB.SetParticleMass(frAlgo.GetDefaultParticleMass());
+  fitB.SetParticleMass(fDefaultMass);
   fitB.SetMask(fmask::One());
   fitB.SetQp0(fvec(0.));
 
   ca::TrackFit fitF;
-  fitF.SetParticleMass(frAlgo.GetDefaultParticleMass());
+  fitF.SetParticleMass(fDefaultMass);
   fitF.SetMask(fmask::One());
   fitF.SetQp0(fvec(0.));
 
@@ -93,7 +96,7 @@ void CloneMerger::Exec(Vector<Track>& extTracks, Vector<ca::HitIndex_t>& extReco
   ca::FieldRegion<fvec> fld _fvecalignment;
 
   // Max length for merging
-  unsigned char maxLengthForMerge = static_cast<unsigned char>(frAlgo.GetParameters().GetNstationsActive() - 3);
+  unsigned char maxLengthForMerge = static_cast<unsigned char>(fParameters.GetNstationsActive() - 3);
 
   for (int iTr = 0; iTr < nTracks; iTr++) {
     if (extTracks[iTr].fNofHits > maxLengthForMerge) continue;
@@ -119,8 +122,8 @@ void CloneMerger::Exec(Vector<Track>& extTracks, Vector<ca::HitIndex_t>& extReco
 
       unsigned short stam;
 
-      fBf = frAlgo.GetParameters().GetStation(staf).fieldSlice.GetFieldValue(Tf.X(), Tf.Y());
-      fBb = frAlgo.GetParameters().GetStation(stab).fieldSlice.GetFieldValue(Tb.X(), Tb.Y());
+      fBf = fParameters.GetStation(staf).fieldSlice.GetFieldValue(Tf.X(), Tf.Y());
+      fBb = fParameters.GetStation(stab).fieldSlice.GetFieldValue(Tb.X(), Tb.Y());
 
       unsigned short dist = firstStation[iTr] - lastStation[jTr];
 
@@ -129,10 +132,10 @@ void CloneMerger::Exec(Vector<Track>& extTracks, Vector<ca::HitIndex_t>& extReco
       else
         stam = staf - 1;
 
-      fvec zm = frAlgo.GetParameters().GetStation(stam).fZ;
+      fvec zm = fParameters.GetStation(stam).fZ;
       fvec xm = fvec(0.5) * (Tf.GetX() + Tf.Tx() * (zm - Tf.Z()) + Tb.GetX() + Tb.Tx() * (zm - Tb.Z()));
       fvec ym = fvec(0.5) * (Tf.Y() + Tf.Ty() * (zm - Tf.Z()) + Tb.Y() + Tb.Ty() * (zm - Tb.Z()));
-      fBm     = frAlgo.GetParameters().GetStation(stam).fieldSlice.GetFieldValue(xm, ym);
+      fBm     = fParameters.GetStation(stam).fieldSlice.GetFieldValue(xm, ym);
       fld.Set(fBb, Tb.Z(), fBm, zm, fBf, Tf.Z());
 
       fvec zMiddle = fvec(0.5) * (Tb.Z() + Tf.Z());
diff --git a/algo/ca/core/tracking/CaCloneMerger.h b/algo/ca/core/tracking/CaCloneMerger.h
index 0cef1c285d..d063c32f08 100644
--- a/algo/ca/core/tracking/CaCloneMerger.h
+++ b/algo/ca/core/tracking/CaCloneMerger.h
@@ -9,11 +9,13 @@
 
 #pragma once  // include this header only once per compilation unit
 
-#include "CaHit.h"   // For ca::HitIndex_t
+#include "CaHit.h"  // For ca::HitIndex_t
+#include "CaInputData.h"
+#include "CaParameters.h"
 #include "CaSimd.h"  // TEMPORARY FOR fvec, fscal
 #include "CaTrack.h"
 #include "CaVector.h"
-
+#include "CaWindowData.h"
 
 namespace cbm::algo::ca
 {
@@ -31,7 +33,7 @@ namespace cbm::algo::ca
   class CloneMerger {
    public:
     /// Default constructor
-    CloneMerger(const ca::Framework& algo);
+    CloneMerger(const ca::Parameters<fvec>& pars, const float mass);
 
     /// Destructor
     ~CloneMerger();
@@ -51,9 +53,10 @@ namespace cbm::algo::ca
     /// Registers
 
     /// Executes track clones merging algorithm and updates input containers
-    /// \param  extTracks   Reference to the external container of reconstructed tracks
-    /// \param  extRecoHits Reference to the external container of reconstructed hit indexes
-    void Exec(Vector<Track>& extTracks, Vector<ca::HitIndex_t>&);
+    /// \param  input       Reference to input data
+    /// \param  wData       Reference to the external container of reconstructed tracks and hit indices
+    //void Exec(Vector<Track>& extTracks, Vector<ca::HitIndex_t>&, const ca::InputData& input);
+    void Exec(const ca::InputData& input, WindowData& wData);
 
    private:
     // ***************
@@ -122,7 +125,8 @@ namespace cbm::algo::ca
 
     Vector<ca::HitIndex_t> fRecoHitsNew{"CaCloneMerger::fRecoHitsNew"};  ///< vector of track hits after the merge
 
-    const ca::Framework& frAlgo;  ///< Reference to the main track finder algorithm class
+    const Parameters<fvec>& fParameters;            ///< Object of Framework parameters class
+    float fDefaultMass{constants::phys::MuonMass};  ///< mass of the propagated particle [GeV/c2]
   };
 
 }  // namespace cbm::algo::ca
diff --git a/algo/ca/core/tracking/CaFramework.cxx b/algo/ca/core/tracking/CaFramework.cxx
index 43a7085dbe..ed3d8d2007 100644
--- a/algo/ca/core/tracking/CaFramework.cxx
+++ b/algo/ca/core/tracking/CaFramework.cxx
@@ -1,12 +1,19 @@
 /* Copyright (C) 2010-2021 Frankfurt Institute for Advanced Studies, Goethe-Universität Frankfurt, Frankfurt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Igor Kulakov [committer], Maksym Zyzak, Valentina Akishina */
+   Authors: Igor Kulakov [committer], Maksym Zyzak, Valentina Akishina, Ivan Kisel, Sergey Gorbunov, Sergei Zharko, Dominik Smith */
 
 #include "CaFramework.h"
 
 #include "CaGridEntry.h"
+#include "CaTimer.h"
+#include "CaTrack.h"
 // #include "CaToolsDebugger.h"
 
+#include <chrono>
+#include <fstream>
+#include <sstream>
+#include <thread>
+
 using namespace cbm::algo::ca;
 
 namespace
@@ -14,31 +21,24 @@ namespace
   using namespace cbm::algo;  // to keep ca:: prefices in the code
 }
 
-Framework::Framework()
-{
-
-}
-
 using cbm::algo::ca::ECounter;  // monitor counter key type
 using cbm::algo::ca::EDetectorID;
 using cbm::algo::ca::ETimer;  // monitor timer key type
 using cbm::algo::ca::KfFramework_t;
 using cbm::algo::ca::KfParameters_t;
+using cbm::algo::ca::Track;
+using constants::phys::ProtonMassD;
+using constants::phys::SpeedOfLightInv;
+using constants::phys::SpeedOfLightInvD;
 //using cbm::ca::tools::Debugger;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
 void Framework::Init(const TrackingMode mode)
 {
-  fTrackingMode = mode;
-  for (int iThread = 0; iThread < fNofThreads; ++iThread) {
-    fvWData.emplace_back();
-    fvMonitorDataThread.emplace_back();
-  }
-  for (int iThread = 0; iThread < fNofThreads; ++iThread) {
-    fvTrackFinderWindow.emplace_back(*this, fvWData[iThread], fvMonitorDataThread[iThread]);
-  }
-  fTrackFinder.Init();
+  fpTrackFinder =
+    std::make_unique<ca::TrackFinder>(fParameters, fDefaultMass, mode, fMonitorData, fNofThreads, fCaRecoTime);
+
   fKf.Init();
 }
 
@@ -62,20 +62,9 @@ void Framework::ReceiveInputData(InputData&& inputData)
 //
 void Framework::ReceiveParameters(Parameters<fvec>&& parameters)
 {
-  fParameters = std::move(parameters);
-
+  fParameters          = std::move(parameters);
   fNstationsBeforePipe = fParameters.GetNstationsActive(static_cast<EDetectorID>(0));
 
-  // FIXME: SZh 24.08.2022
-  //        This approach is suitable only for a case, when all the stations inside a magnetic field come right before
-  //        all the stations outside of the field!
-  fNfieldStations = std::lower_bound(fParameters.GetStations().cbegin(),
-                                     fParameters.GetStations().cbegin() + fParameters.GetNstationsActive(),
-                                     0,  // we are looking for the first zero element
-                                     [](const ca::Station<fvec>& s, int edge) { return bool(s.fieldStatus) > edge; })
-                    - fParameters.GetStations().cbegin();
-
-
   ca::FieldRegion<fvec>::ForceUseOfOriginalField(fParameters.DevIsUseOfOriginalField());
 }
 
@@ -90,7 +79,7 @@ void Framework::ReceiveKfSettings(KfParameters_t&& pars, KfSetup_t&& setup)
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-int Framework::GetMcTrackIdForCaHit(int /*iHit*/) const
+int Framework::GetMcTrackIdForCaHit(int /*iHit*/)
 {
   return -1;
   /*
@@ -101,7 +90,7 @@ int Framework::GetMcTrackIdForCaHit(int /*iHit*/) const
   */
 }
 
-int Framework::GetMcTrackIdForWindowHit(int /*iHit*/) const
+int Framework::GetMcTrackIdForWindowHit(int /*iHit*/)
 {
   return -1;
   /*
diff --git a/algo/ca/core/tracking/CaFramework.h b/algo/ca/core/tracking/CaFramework.h
index 409b165cb9..4b20fae8e2 100644
--- a/algo/ca/core/tracking/CaFramework.h
+++ b/algo/ca/core/tracking/CaFramework.h
@@ -14,14 +14,12 @@
 #include "CaInputData.h"
 #include "CaMeasurementXy.h"
 #include "CaParameters.h"
+#include "CaSimd.h"
 #include "CaStation.h"
 #include "CaTimer.h"
 #include "CaTimesliceHeader.h"
 #include "CaTrack.h"
-#include "CaTrackExtender.h"
 #include "CaTrackFinder.h"
-#include "CaTrackFinderWindow.h"
-#include "CaTrackFitter.h"
 #include "CaTrackParam.h"
 #include "CaTrackingMonitor.h"
 #include "CaTriplet.h"
@@ -38,7 +36,7 @@
 namespace cbm::algo::ca
 {
   class TripletConstructor;
-
+  class Track;
 
   namespace
   {
@@ -60,31 +58,11 @@ namespace cbm::algo::ca
   using CaMaterialArray_t = std::array<ca::MaterialMap, constants::size::MaxNstations>;
   using Tindex            = int;  // TODO: Replace with ca::HitIndex_t, if suitable
 
-
   /// Main class of CA track finder algorithm
+  /// Class implements a clones merger algorithm for the CA track finder
   ///
   class Framework {
    public:
-    // *************************
-    // ** Friend classes list **
-    // *************************
-
-    friend class ca::TripletConstructor;
-    friend class ca::TrackExtender;
-    friend class ca::TrackFitter;
-    friend class ca::TrackFinderWindow;
-    friend class ca::TrackFinder;
-
-    ///---------------------------
-    /// Internal enumerations
-
-    enum TrackingMode
-    {
-      kSts,
-      kGlobal,
-      kMcbm
-    };
-
     // **********************************
     // ** Member functions declaration **
     // **********************************
@@ -92,7 +70,7 @@ namespace cbm::algo::ca
     // ** Constructors and destructor
 
     /// Constructor
-    Framework();
+    Framework(){};
 
     /// Copy constructor
     Framework(const Framework&) = delete;
@@ -109,24 +87,6 @@ namespace cbm::algo::ca
     /// Destructor
     ~Framework() = default;
 
-
-    // ** Functions, which pack and unpack indexes of station and triplet **
-
-    // TODO: move to ca::Triplet class (S.Zharko)
-    /// Packs station and triplet indices to an unique triplet ID
-    /// \param  iStation  Index of station in the active stations array
-    /// \param  iTriplet  Index of triplet
-    static unsigned int PackTripletId(unsigned int iStation, unsigned int iTriplet);
-
-    /// Unpacks the triplet ID to its station index
-    /// \param  id  Unique triplet ID
-    static unsigned int TripletId2Station(unsigned int id);
-
-    /// Unpacks the triplet ID to its triplet index
-    /// \param  id  Unique triplet ID
-    static unsigned int TripletId2Triplet(unsigned int id);
-
-
     /// Sets Framework parameters object
     /// \param other - reference to the Parameters object
     void SetParameters(const Parameters<fvec>& other) { fParameters = other; }
@@ -187,18 +147,25 @@ namespace cbm::algo::ca
     /// \brief Sets monitor data
     void SetMonitorData(const TrackingMonitorData& monitorData) { fMonitorData = monitorData; }
 
+    TrackingMode GetTrackingMode() { return fpTrackFinder->GetTrackingMode(); }
+
+    const std::vector<ca::WindowData>& GetWData() { return fpTrackFinder->GetWData(); }
+
    public:
+    void FindTracks()
+    {
+      std::tie(fRecoTracks, fRecoHits) = fpTrackFinder->FindTracks(fInputData, fTsHeader);
+      return;
+    };
+
     /// Gets number of stations before the pipe (MVD stations in CBM)
     // int GetNstationsBeforePipe() const { return fNstationsBeforePipe; }
 
-    /// Gets number of stations situated in field region (MVD + STS in CBM)
-    int GetNfieldStations() const { return fNfieldStations; }
-
     /// Get mc track ID for a hit (debug tool)
-    int GetMcTrackIdForCaHit(int iHit) const;
+    static int GetMcTrackIdForCaHit(int iHit);
 
     /// Get mc track ID for a hit (debug tool)
-    int GetMcTrackIdForWindowHit(int iGridHit) const;
+    static int GetMcTrackIdForWindowHit(int iGridHit);
 
     // const CbmL1MCTrack* GetMcTrackForWindowHit(int iHit) const;
 
@@ -223,7 +190,6 @@ namespace cbm::algo::ca
     KfFramework_t fKf;  ///< KF framework instance
 
     int fNstationsBeforePipe{0};                    ///< number of stations before pipe (MVD stations in CBM)
-    int fNfieldStations{0};                         ///< number of stations in the field region
     float fDefaultMass{constants::phys::MuonMass};  ///< mass of the propagated particle [GeV/c2]
     TimesliceHeader fTsHeader;                      ///< current timeslice header
 
@@ -237,13 +203,16 @@ namespace cbm::algo::ca
     Vector<unsigned char> fvHitKeyFlags{
       "Framework::fvHitKeyFlags"};  ///< List of key flags: has been this hit or cluster already used
 
-    TrackingMonitorData fMonitorData{};                    ///< Tracking monitor data (statistics per call)
-    std::vector<TrackingMonitorData> fvMonitorDataThread;  ///< Tracking monitor data per thread
+    TrackingMonitorData fMonitorData{};  ///< Tracking monitor data (statistics per call)
 
     int fNofThreads = 1;  ///< Number of threads to execute the track-finder
+                          ///
+    bool checkTripletMatch(const ca::Triplet& l, const ca::Triplet& r, fscal& dchi2) const;
+
+    std::unique_ptr<ca::TrackFinder> fpTrackFinder;  ///< Track finder steer class for the entire time slice
 
    public:
-    Vector<CaHitTimeInfo> fHitTimeInfo;
+    //   Vector<CaHitTimeInfo> fHitTimeInfo;
 
     double fCaRecoTime{0.};  // time of the track finder + fitter
 
@@ -254,52 +223,6 @@ namespace cbm::algo::ca
     fvec Err{0.f};
 
    public:
-    std::vector<ca::WindowData> fvWData;                     ///< Intrnal data processed in a time-window
-    std::vector<ca::TrackFinderWindow> fvTrackFinderWindow;  ///< Track finder algorithm for the time window
-    ca::TrackFinder fTrackFinder{*this};                     ///< Track finder steer class for the entire time slice
-    TrackingMode fTrackingMode{kSts};
-
-   private:
-    /// =================================  DATA PART  =================================
-
-    /// ----- Different parameters of CATrackFinder -----
-
-    bool fIsTargetField{false};  ///< is the magnetic field present at the target
-
-
   } _fvecalignment;
 
-
-  // ********************************************
-  // ** Inline member functions implementation **
-  // ********************************************
-
-  // ---------------------------------------------------------------------------------------------------------------------
-  //
-  [[gnu::always_inline]] inline unsigned int Framework::PackTripletId(unsigned int iStation, unsigned int iTriplet)
-  {
-#ifndef FAST_CODE
-    assert(iStation < constants::size::MaxNstations);
-    assert(iTriplet < constants::size::MaxNtriplets);
-#endif
-    constexpr unsigned int kMoveStation = constants::size::TripletBits;
-    return (iStation << kMoveStation) + iTriplet;
-  }
-
-  // ---------------------------------------------------------------------------------------------------------------------
-  //
-  [[gnu::always_inline]] inline unsigned int Framework::TripletId2Station(unsigned int id)
-  {
-    constexpr unsigned int kMoveStation = constants::size::TripletBits;
-    return id >> kMoveStation;
-  }
-
-  // ---------------------------------------------------------------------------------------------------------------------
-  //
-  [[gnu::always_inline]] inline unsigned int Framework::TripletId2Triplet(unsigned int id)
-  {
-    constexpr unsigned int kTripletMask = (1u << constants::size::TripletBits) - 1u;
-    return id & kTripletMask;
-  }
-
 }  // namespace cbm::algo::ca
diff --git a/algo/ca/core/tracking/CaTrackExtender.cxx b/algo/ca/core/tracking/CaTrackExtender.cxx
index 6ece464b2e..a7070603b4 100644
--- a/algo/ca/core/tracking/CaTrackExtender.cxx
+++ b/algo/ca/core/tracking/CaTrackExtender.cxx
@@ -9,6 +9,7 @@
 #include "CaDefines.h"
 #include "CaFramework.h"
 #include "CaGridArea.h"
+#include "CaInputData.h"
 #include "CaTrack.h"
 #include "CaTrackFit.h"
 #include "CaTrackParam.h"
@@ -23,7 +24,10 @@ using namespace cbm::algo::ca;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-TrackExtender::TrackExtender(const ca::Framework& algo, WindowData& wData) : frAlgo(algo), frWData(wData) {}
+TrackExtender::TrackExtender(const ca::Parameters<fvec>& pars, const float mass) : fParameters(pars), fDefaultMass(mass)
+{
+}
+
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
@@ -38,7 +42,7 @@ void TrackExtender::FitBranchFast(const ca::Branch& t, TrackParamV& Tout, const
   CBMCA_DEBUG_ASSERT(t.NHits >= 3);
 
   ca::TrackFit fit;
-  fit.SetParticleMass(frAlgo.GetDefaultParticleMass());
+  fit.SetParticleMass(fDefaultMass);
   fit.SetMask(fmask::One());
   fit.SetTrack(Tout);
   TrackParamV& T = fit.Tr();
@@ -51,17 +55,17 @@ void TrackExtender::FitBranchFast(const ca::Branch& t, TrackParamV& Tout, const
   const int iFirstHit         = (upstream) ? nHits - 1 : 0;
   const int iLastHit          = (upstream) ? 0 : nHits - 1;
 
-  const ca::Hit& hit0 = frAlgo.GetInputData().GetHit(hits[iFirstHit]);
-  const ca::Hit& hit1 = frAlgo.GetInputData().GetHit(hits[iFirstHit + step]);
-  const ca::Hit& hit2 = frAlgo.GetInputData().GetHit(hits[iFirstHit + 2 * step]);
+  const ca::Hit& hit0 = fInputData->GetHit(hits[iFirstHit]);
+  const ca::Hit& hit1 = fInputData->GetHit(hits[iFirstHit + step]);
+  const ca::Hit& hit2 = fInputData->GetHit(hits[iFirstHit + 2 * step]);
 
   int ista0 = hit0.Station();
   int ista1 = hit1.Station();
   int ista2 = hit2.Station();
 
-  const ca::Station<fvec>& sta0 = frAlgo.GetParameters().GetStation(ista0);
-  const ca::Station<fvec>& sta1 = frAlgo.GetParameters().GetStation(ista1);
-  const ca::Station<fvec>& sta2 = frAlgo.GetParameters().GetStation(ista2);
+  const ca::Station<fvec>& sta0 = fParameters.GetStation(ista0);
+  const ca::Station<fvec>& sta1 = fParameters.GetStation(ista1);
+  const ca::Station<fvec>& sta2 = fParameters.GetStation(ista2);
 
   fvec x0 = hit0.X();
   fvec y0 = hit0.Y();
@@ -109,13 +113,13 @@ void TrackExtender::FitBranchFast(const ca::Branch& t, TrackParamV& Tout, const
   fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0);
 
   for (int i = iFirstHit + step; step * i <= step * iLastHit; i += step) {
-    const ca::Hit& hit      = frAlgo.GetInputData().GetHit(hits[i]);
-    int ista                = hit.Station();
-    const ca::Station<fvec>& sta = frAlgo.GetParameters().GetStation(ista);
+    const ca::Hit& hit           = fInputData->GetHit(hits[i]);
+    int ista                     = hit.Station();
+    const ca::Station<fvec>& sta = fParameters.GetStation(ista);
 
     fit.Extrapolate(hit.Z(), fld);
     fit.FilterHit(sta, hit);
-    auto radThick = frAlgo.GetParameters().GetMaterialThickness(ista, T.X(), T.Y());
+    auto radThick = fParameters.GetMaterialThickness(ista, T.X(), T.Y());
     fit.MultipleScattering(radThick);
     fit.EnergyLossCorrection(radThick, fvec(upstream ? 1. : -1.));
 
@@ -146,29 +150,29 @@ void TrackExtender::FitBranch(const ca::Branch& t, TrackParamV& T, const bool up
 void TrackExtender::FindMoreHits(ca::Branch& t, TrackParamV& Tout, const bool upstream, const fvec qp0)
 {
   Vector<ca::HitIndex_t> newHits{"ca::TrackExtender::newHits"};
-  newHits.reserve(frAlgo.GetParameters().GetNstationsActive());
+  newHits.reserve(fParameters.GetNstationsActive());
 
   ca::TrackFit fit;
-  fit.SetParticleMass(frAlgo.GetDefaultParticleMass());
+  fit.SetParticleMass(fDefaultMass);
   fit.SetMask(fmask::One());
   fit.SetTrack(Tout);
   fit.SetQp0(qp0);
 
   const signed short int step = -2 * static_cast<int>(upstream) + 1;  // increment for station index
   const int iFirstHit         = (upstream) ? 2 : t.NofHits() - 3;
-  //  int ista = frAlgo.GetInputData().GetHit(t.Hits[iFirstHit]).iSt + 2 * step; // current station. set to the end of track
+  //  int ista = fInputData->GetHit(t.Hits[iFirstHit]).iSt + 2 * step; // current station. set to the end of track
 
-  const ca::Hit& hit0 = frAlgo.GetInputData().GetHit(t.Hits()[iFirstHit]);  // optimize
-  const ca::Hit& hit1 = frAlgo.GetInputData().GetHit(t.Hits()[iFirstHit + step]);
-  const ca::Hit& hit2 = frAlgo.GetInputData().GetHit(t.Hits()[iFirstHit + 2 * step]);
+  const ca::Hit& hit0 = fInputData->GetHit(t.Hits()[iFirstHit]);  // optimize
+  const ca::Hit& hit1 = fInputData->GetHit(t.Hits()[iFirstHit + step]);
+  const ca::Hit& hit2 = fInputData->GetHit(t.Hits()[iFirstHit + 2 * step]);
 
   const int ista0 = hit0.Station();
   const int ista1 = hit1.Station();
   const int ista2 = hit2.Station();
 
-  const ca::Station<fvec>& sta0 = frAlgo.GetParameters().GetStation(ista0);
-  const ca::Station<fvec>& sta1 = frAlgo.GetParameters().GetStation(ista1);
-  const ca::Station<fvec>& sta2 = frAlgo.GetParameters().GetStation(ista2);
+  const ca::Station<fvec>& sta0 = fParameters.GetStation(ista0);
+  const ca::Station<fvec>& sta1 = fParameters.GetStation(ista1);
+  const ca::Station<fvec>& sta2 = fParameters.GetStation(ista2);
 
   fvec x0 = hit0.X();
   fvec y0 = hit0.Y();
@@ -192,14 +196,14 @@ void TrackExtender::FindMoreHits(ca::Branch& t, TrackParamV& Tout, const bool up
 
   int ista = ista2 + 2 * step;  // skip one station. if there would be hit it has to be found on previous stap
 
-  if (ista2 == frWData.CurrentIteration()->GetFirstStationIndex()) ista = ista2 + step;
+  if (ista2 == frWData->CurrentIteration()->GetFirstStationIndex()) ista = ista2 + step;
 
-  const float pickGather = frWData.CurrentIteration()->GetPickGather();
+  const float pickGather = frWData->CurrentIteration()->GetPickGather();
   const fvec pickGather2 = pickGather * pickGather;
-  const fvec maxDZ       = frWData.CurrentIteration()->GetMaxDZ();
-  for (; (ista < frAlgo.GetParameters().GetNstationsActive()) && (ista >= 0); ista += step) {  // CHECKME why ista2?
+  const fvec maxDZ       = frWData->CurrentIteration()->GetMaxDZ();
+  for (; (ista < fParameters.GetNstationsActive()) && (ista >= 0); ista += step) {  // CHECKME why ista2?
 
-    const ca::Station<fvec>& sta = frAlgo.GetParameters().GetStation(ista);
+    const ca::Station<fvec>& sta = fParameters.GetStation(ista);
 
     fit.Extrapolate(sta.fZ, fld);
 
@@ -208,12 +212,12 @@ void TrackExtender::FindMoreHits(ca::Branch& t, TrackParamV& Tout, const bool up
 
     TrackParamV& tr = fit.Tr();
 
-    const auto& grid = frWData.Grid(ista);
+    const auto& grid = frWData->Grid(ista);
     ca::GridArea area(grid, tr.X()[0], tr.Y()[0],
                       (sqrt(pickGather * tr.C00()) + grid.GetMaxRangeX() + maxDZ * abs(tr.Tx()))[0],
                       (sqrt(pickGather * tr.C11()) + grid.GetMaxRangeY() + maxDZ * abs(tr.Ty()))[0]);
 
-    if (frAlgo.GetParameters().DevIsIgnoreHitSearchAreas()) {
+    if (fParameters.DevIsIgnoreHitSearchAreas()) {
       area.DoLoopOverEntireGrid();
     }
 
@@ -221,10 +225,10 @@ void TrackExtender::FindMoreHits(ca::Branch& t, TrackParamV& Tout, const bool up
 
     while (area.GetNextObjectId(ih)) {  // loop over the hits in the area
 
-      if (frWData.IsHitSuppressed(ih)) {
+      if (frWData->IsHitSuppressed(ih)) {
         continue;
       }
-      const ca::Hit& hit = frWData.Hit(ih);
+      const ca::Hit& hit = frWData->Hit(ih);
 
       if (sta.timeInfo && tr.NdfTime()[0] > -2.) {
         fscal dt = hit.T() - tr.Time()[0];
@@ -233,7 +237,7 @@ void TrackExtender::FindMoreHits(ca::Branch& t, TrackParamV& Tout, const bool up
 
       //if (GetFUsed((*fStripFlag)[hit.f] | (*fStripFlag)[hit.b])) continue;  // if used
 
-      if (frWData.IsHitKeyUsed(hit.FrontKey()) || frWData.IsHitKeyUsed(hit.BackKey())) {
+      if (frWData->IsHitKeyUsed(hit.FrontKey()) || frWData->IsHitKeyUsed(hit.BackKey())) {
         continue;
       }
 
@@ -262,12 +266,12 @@ void TrackExtender::FindMoreHits(ca::Branch& t, TrackParamV& Tout, const bool up
     if (iHit_best < 0) break;
 
 
-    const ca::Hit& hit = frWData.Hit(iHit_best);
+    const ca::Hit& hit = frWData->Hit(iHit_best);
     newHits.push_back(hit.Id());
 
     fit.Extrapolate(hit.Z(), fld);
     fit.FilterHit(sta, hit);
-    auto radThick = frAlgo.GetParameters().GetMaterialThickness(ista, tr.X(), tr.Y());
+    auto radThick = fParameters.GetMaterialThickness(ista, tr.X(), tr.Y());
     fit.MultipleScattering(radThick);
     fit.EnergyLossCorrection(radThick, upstream ? fvec(1.f) : fvec(-1.f));
 
@@ -304,8 +308,10 @@ void TrackExtender::FindMoreHits(ca::Branch& t, TrackParamV& Tout, const bool up
 }  // void ca::Framework::FindMoreHits
 
 /// Try to extrapolate and find additional hits on other stations
-fscal TrackExtender::ExtendBranch(ca::Branch& t)
+fscal TrackExtender::ExtendBranch(ca::Branch& t, const InputData& input, WindowData& wData)
 {
+  fInputData = &input;
+  frWData    = &wData;
   //   const unsigned int minNHits = 3;
 
   TrackParamV T;
diff --git a/algo/ca/core/tracking/CaTrackExtender.h b/algo/ca/core/tracking/CaTrackExtender.h
index e5762fb67e..875db7cb35 100644
--- a/algo/ca/core/tracking/CaTrackExtender.h
+++ b/algo/ca/core/tracking/CaTrackExtender.h
@@ -11,16 +11,17 @@
 
 #include "CaBranch.h"
 #include "CaHit.h"
+#include "CaParameters.h"
 #include "CaSimd.h"
 #include "CaTrackParam.h"
 #include "CaVector.h"
 #include "CaWindowData.h"
 
-
 namespace cbm::algo::ca
 {
   class Track;
   class Framework;
+  class InputData;
 
   namespace
   {
@@ -33,7 +34,7 @@ namespace cbm::algo::ca
   class TrackExtender {
    public:
     /// Default constructor
-    TrackExtender(const ca::Framework& algo, WindowData& wData);
+    TrackExtender(const ca::Parameters<fvec>& pars, const float mass);
 
     /// Destructor
     ~TrackExtender();
@@ -53,7 +54,7 @@ namespace cbm::algo::ca
 
     /// Find additional hits for existing track both downstream and upstream
     /// \return chi2
-    fscal ExtendBranch(ca::Branch& t);
+    fscal ExtendBranch(ca::Branch& t, const ca::InputData& input, WindowData& wData);
 
    private:
     ///-------------------------------
@@ -88,8 +89,10 @@ namespace cbm::algo::ca
     ///-------------------------------
     /// Data members
 
-    const ca::Framework& frAlgo;  ///< Reference to the main track finder algorithm class
-    WindowData& frWData;
+    const Parameters<fvec>& fParameters;  ///< Object of Framework parameters class
+    const InputData* fInputData;          ///< Tracking input data
+    WindowData* frWData;
+    float fDefaultMass{constants::phys::MuonMass};  ///< mass of the propagated particle [GeV/c2]
   };
 
 }  // namespace cbm::algo::ca
diff --git a/algo/ca/core/tracking/CaTrackFinder.cxx b/algo/ca/core/tracking/CaTrackFinder.cxx
index 1892ea5fbb..6afe5987e1 100644
--- a/algo/ca/core/tracking/CaTrackFinder.cxx
+++ b/algo/ca/core/tracking/CaTrackFinder.cxx
@@ -18,39 +18,66 @@
  *
  */
 
-#include "CaFramework.h"
+#include "CaTrackFinder.h"
+
 #include "CaTimer.h"
 #include "CaTrack.h"
+#include "CaTriplet.h"
 
 #include <chrono>
 #include <fstream>
 #include <sstream>
 #include <thread>
 
+
 using namespace cbm::algo::ca;
 
-using cbm::algo::ca::ECounter;
-using cbm::algo::ca::ETimer;
+using cbm::algo::ca::ECounter;  // monitor counter key type
+using cbm::algo::ca::ETimer;    // monitor timer key type
 using cbm::algo::ca::Track;
+using constants::phys::ProtonMassD;
+using constants::phys::SpeedOfLightInv;
+using constants::phys::SpeedOfLightInvD;
 
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-TrackFinder::TrackFinder(ca::Framework& algo) : frAlgo(algo) {}
 
-// ---------------------------------------------------------------------------------------------------------------------
-//
-TrackFinder::~TrackFinder() {}
+TrackFinder::TrackFinder(const ca::Parameters<fvec>& pars, const float mass, const ca::TrackingMode& mode,
+                         TrackingMonitorData& monitorData, int nThreads, double& recoTime)
+  : fParameters(pars)
+  , fDefaultMass(mass)
+  , fTrackingMode(mode)
+  , fMonitorData(monitorData)
+  , fvMonitorDataThread(nThreads)
+  , fvWData(nThreads)
+  , fNofThreads(nThreads)
+  , fCaRecoTime(recoTime)
+  , fvRecoTracks(nThreads)
+  , fvRecoHitIndices(nThreads)
+  , fWindowLength((ca::TrackingMode::kMcbm == mode) ? 500 : 10000)
+{
+  assert(fNofThreads > 0);
+
+  for (int iThread = 0; iThread < fNofThreads; ++iThread) {
+    fvRecoTracks[iThread].SetName(std::string("TrackFinder::fvRecoTracks_") + std::to_string(iThread));
+    fvRecoHitIndices[iThread].SetName(std::string("TrackFinder::fvRecoHitIndices_") + std::to_string(iThread));
+  }
+}
 
 // ---------------------------------------------------------------------------------------------------------------------
+//CBM Level 1 4D Reconstruction
+//Finds tracks using the Cellular Automaton algorithm
 //
-void TrackFinder::FindTracks()
+TrackFinder::Output_t TrackFinder::FindTracks(const InputData& input, TimesliceHeader& tsHeader)
 {
-  frAlgo.fRecoTracks.clear();
-  frAlgo.fRecoHits.clear();
-  if (frAlgo.GetInputData().GetNhits() < 1) {
+  Output_t output;
+  Vector<Track>& recoTracks        = output.first;   //reconstructed tracks
+  Vector<ca::HitIndex_t>& recoHits = output.second;  //packed hits of reconstructed tracks
+
+  if (input.GetNhits() < 1) {
     LOG(warn) << "No hits were passed to the ca::TrackFinder. Stopping the routine";
-    return;
+    return output;
   }
 
   //
@@ -58,74 +85,60 @@ void TrackFinder::FindTracks()
   // It splits the input data into sub-timeslices
   // and runs the track finder over the sub-slices
   //
-  frAlgo.fMonitorData.StartTimer(ETimer::Tracking);
-  frAlgo.fMonitorData.StartTimer(ETimer::PrepareTimeslice);
-  frAlgo.fMonitorData.IncrementCounter(ECounter::TrackingCall);
-  frAlgo.fMonitorData.IncrementCounter(ECounter::RecoHit, frAlgo.fInputData.GetNhits());
+  fMonitorData.StartTimer(ETimer::Tracking);
+  fMonitorData.StartTimer(ETimer::PrepareTimeslice);
+  fMonitorData.IncrementCounter(ECounter::TrackingCall);
+  fMonitorData.IncrementCounter(ECounter::RecoHit, input.GetNhits());
 
   auto timerStart = std::chrono::high_resolution_clock::now();
 
-  auto& wDataThread0 = frAlgo.fvWData[0];  // NOTE: Thread 0 must be always defined
+  auto& wDataThread0 = fvWData[0];  // NOTE: Thread 0 must be always defined
 
   // ----- Reset data arrays -------------------------------------------------------------------------------------------
 
-  wDataThread0.HitKeyFlags().reset(frAlgo.fInputData.GetNhitKeys(), 0);
-
-  frAlgo.fHitTimeInfo.reset(frAlgo.fInputData.GetNhits());
+  wDataThread0.HitKeyFlags().reset(input.GetNhitKeys(), 0);
 
+  fHitTimeInfo.reset(input.GetNhits());
 
   // TODO: move these values to Parameters namespace (S.Zharko)
 
   // length of sub-TS
-  fscal minProtonMomentum = 0.1;
-
-  fscal targX = frAlgo.GetParameters().GetTargetPositionX()[0];
-  fscal targY = frAlgo.GetParameters().GetTargetPositionY()[0];
-  fscal targZ = frAlgo.GetParameters().GetTargetPositionZ()[0];
+  const fscal minProtonMomentum = 0.1;
+  const fscal preFactor         = sqrt(1. + ProtonMassD * ProtonMassD / (minProtonMomentum * minProtonMomentum));
+  const fscal targX             = fParameters.GetTargetPositionX()[0];
+  const fscal targY             = fParameters.GetTargetPositionY()[0];
+  const fscal targZ             = fParameters.GetTargetPositionZ()[0];
 
   fStatTsStart    = std::numeric_limits<fscal>::max();  // end time of the TS
   fStatTsEnd      = 0.;                                 // end time of the TS
   fStatNhitsTotal = 0;
 
-  // calculate possible event time for the hits (frAlgo.fHitTimeInfo array)
-
-  const int nDataStreams = frAlgo.fInputData.GetNdataStreams();
+  // calculate possible event time for the hits (fHitTimeInfo array)
+  const int nDataStreams = input.GetNdataStreams();
 
   for (int iStream = 0; iStream < nDataStreams; ++iStream) {
 
     fscal maxTimeBeforeHit = std::numeric_limits<fscal>::lowest();
-
-    int nStreamHits = frAlgo.fInputData.GetStreamNhits(iStream);
+    const int nStreamHits  = input.GetStreamNhits(iStream);
     fStatNhitsTotal += nStreamHits;
 
     for (int ih = 0; ih < nStreamHits; ++ih) {
 
-      ca::HitIndex_t caHitId = frAlgo.fInputData.GetStreamStartIndex(iStream) + ih;
-      const ca::Hit& h       = frAlgo.fInputData.GetHit(caHitId);
-
-      const ca::Station<fvec>& st = frAlgo.GetParameters().GetStation(h.Station());
-
-      fscal dx = h.X() - targX;
-      fscal dy = h.Y() - targY;
-      fscal dz = h.Z() - targZ;
-      fscal l  = sqrt(dx * dx + dy * dy + dz * dz);
-
-      fscal timeOfFlightMin = l * constants::phys::SpeedOfLightInv;
-      fscal timeOfFlightMax =
-        1.5 * l
-        * sqrt(1. + constants::phys::ProtonMassD * constants::phys::ProtonMassD / minProtonMomentum / minProtonMomentum)
-        * constants::phys::SpeedOfLightInvD;
+      ca::HitIndex_t caHitId      = input.GetStreamStartIndex(iStream) + ih;
+      const ca::Hit& h            = input.GetHit(caHitId);
+      const ca::Station<fvec>& st = fParameters.GetStation(h.Station());
+      const fscal dx              = h.X() - targX;
+      const fscal dy              = h.Y() - targY;
+      const fscal dz              = h.Z() - targZ;
+      const fscal l               = sqrt(dx * dx + dy * dy + dz * dz);
+      const fscal timeOfFlightMin = l * SpeedOfLightInv;
+      const fscal timeOfFlightMax = 1.5 * l * preFactor * SpeedOfLightInvD;
+      const fscal dt              = h.RangeT();
       // TODO: Is it possible, that the proton mass selection affects the search of heavier particles?
-      fscal dt = h.RangeT();
-
-      CaHitTimeInfo& info = frAlgo.fHitTimeInfo[caHitId];
-      info.fEventTimeMin  = h.T() - dt - timeOfFlightMax;
-      info.fEventTimeMax  = h.T() + dt - timeOfFlightMin;
 
-      if (!st.timeInfo) {
-        info.fEventTimeMin = -1.e10;
-        info.fEventTimeMax = 1.e10;
-      }
+      CaHitTimeInfo& info = fHitTimeInfo[caHitId];
+      info.fEventTimeMin  = st.timeInfo ? (h.T() - dt - timeOfFlightMax) : -1.e10;
+      info.fEventTimeMax  = st.timeInfo ? (h.T() + dt - timeOfFlightMin) : 1.e10;
 
       // NOTE: if not a MT part, use wDataThread0.IsHitKeyUsed, it will be later copied to other threads
       if (info.fEventTimeMin > 500.e6 || info.fEventTimeMax < -500.) {  // cut hits with bogus start time > 500 ms
@@ -134,33 +147,23 @@ void TrackFinder::FindTracks()
         LOG(error) << "CATrackFinder: skip bogus hit " << h.ToString();
         continue;
       }
-
-      if (maxTimeBeforeHit < info.fEventTimeMax) {
-        maxTimeBeforeHit = info.fEventTimeMax;
-      }
+      maxTimeBeforeHit       = std::max(maxTimeBeforeHit, info.fEventTimeMax);
       info.fMaxTimeBeforeHit = maxTimeBeforeHit;
-
-      if (fStatTsStart > info.fEventTimeMax - fWindowMargin) {
-        fStatTsStart = info.fEventTimeMax - fWindowMargin;  // 5 ns margin
-      }
-      if (fStatTsEnd < info.fEventTimeMin) {
-        fStatTsEnd = info.fEventTimeMin;
-      }
+      fStatTsStart           = std::min(fStatTsStart, info.fEventTimeMax - fWindowMargin);  // 5 ns margin
+      fStatTsEnd             = std::max(fStatTsEnd, info.fEventTimeMin);
     }
 
     fscal minTimeAfterHit = std::numeric_limits<fscal>::max();
     // loop in the reverse order to fill CaHitTimeInfo::fMinTimeAfterHit fields
 
     for (int ih = nStreamHits - 1; ih >= 0; --ih) {
-      ca::HitIndex_t caHitId = frAlgo.fInputData.GetStreamStartIndex(iStream) + ih;
-      const ca::Hit& h       = frAlgo.fInputData.GetHit(caHitId);
+      ca::HitIndex_t caHitId = input.GetStreamStartIndex(iStream) + ih;
+      const ca::Hit& h       = input.GetHit(caHitId);
       if (wDataThread0.IsHitKeyUsed(h.FrontKey()) || wDataThread0.IsHitKeyUsed(h.BackKey())) {
         continue;
       }  // the hit is skipped
-      CaHitTimeInfo& info = frAlgo.fHitTimeInfo[caHitId];
-      if (minTimeAfterHit > info.fEventTimeMin) {
-        minTimeAfterHit = info.fEventTimeMin;
-      }
+      CaHitTimeInfo& info   = fHitTimeInfo[caHitId];
+      minTimeAfterHit       = std::min(minTimeAfterHit, info.fEventTimeMin);
       info.fMinTimeAfterHit = minTimeAfterHit;
     }
 
@@ -170,12 +173,12 @@ void TrackFinder::FindTracks()
         tmp++;
         LOG(warning) << "\n\n stream " << iStream << " hits " << nStreamHits << "\n\n";
         for (int ih = 0; (ih < nStreamHits) && (tmp < 10000); ++ih) {
-          ca::HitIndex_t caHitId = frAlgo.fInputData.GetStreamStartIndex(iStream) + ih;
-          const ca::Hit& h       = frAlgo.fInputData.GetHit(caHitId);
+          ca::HitIndex_t caHitId = input.GetStreamStartIndex(iStream) + ih;
+          const ca::Hit& h       = input.GetHit(caHitId);
           if (wDataThread0.IsHitKeyUsed(h.FrontKey()) || wDataThread0.IsHitKeyUsed(h.BackKey())) {
             continue;
           }  // the hit is skipped
-          CaHitTimeInfo& info = frAlgo.fHitTimeInfo[caHitId];
+          CaHitTimeInfo& info = fHitTimeInfo[caHitId];
           if (h.Station() < 4) {
             tmp++;
             LOG(warning) << " hit sta " << h.Station() << " stream " << iStream << " time " << h.T() << " event time "
@@ -187,14 +190,8 @@ void TrackFinder::FindTracks()
     }
   }
 
-
-  if (fStatTsEnd < fStatTsStart) {  // all hits belong to one sub-timeslice
-    fStatTsEnd = fStatTsStart;
-  }
-
-  if (fStatTsEnd > fStatTsStart + 500.e6) {  // 500 ms maximal length of the TS
-    fStatTsEnd = fStatTsStart + 500.e6;
-  }
+  fStatTsEnd = std::max(fStatTsEnd, fStatTsStart);            // all hits belong to one sub-timeslice
+  fStatTsEnd = std::min(fStatTsEnd, fStatTsStart + 500.e6f);  // 500 ms maximal length of the TS
 
   LOG(debug) << "CA tracker process time slice " << fStatTsStart * 1.e-6 << " -- " << fStatTsEnd * 1.e-6
              << " [ms] with " << fStatNhitsTotal << " hits";
@@ -206,25 +203,26 @@ void TrackFinder::FindTracks()
     nWindows = 1;
   }
 
-  int nWindowsThread = nWindows / frAlgo.GetNofThreads();
+  int nWindowsThread = nWindows / fNofThreads;
   float windowDelta  = fWindowLength - fWindowOverlap - fWindowMargin;
   //LOG(info) << "CA: estimated number of time windows: " << nWindows;
 
+  std::vector<float> vWindowStartThread(fNofThreads), vWindowEndThread(fNofThreads);
 
-  fvWindowStartThread[0] = fStatTsStart;
+  vWindowStartThread[0] = fStatTsStart;
   {  // Estimation of number of hits in time windows
     //Timer time;
     //time.Start();
-    int nSt = frAlgo.GetParameters().GetNstationsActive();
+    int nSt = fParameters.GetNstationsActive();
 
     // Count number of hits per window and station
-    double a            = fStatTsStart + fWindowOverlap + fWindowMargin;
-    double b            = fWindowLength - fWindowOverlap - fWindowMargin;
-    HitIndex_t nHitsTot = frAlgo.fInputData.GetNhits();
+    const double a      = fStatTsStart + fWindowOverlap + fWindowMargin;
+    const double b      = fWindowLength - fWindowOverlap - fWindowMargin;
+    HitIndex_t nHitsTot = input.GetNhits();
     std::vector<HitIndex_t> nHitsWindowSta(nWindows * nSt, 0);
     for (HitIndex_t iHit = 0; iHit < nHitsTot; ++iHit) {
-      const auto& hit = frAlgo.fInputData.GetHit(iHit);
-      //const auto& timeInfo = frAlgo.fHitTimeInfo[iHit];
+      const auto& hit = input.GetHit(iHit);
+      //const auto& timeInfo = fHitTimeInfo[iHit];
       size_t iWindow = static_cast<size_t>((hit.T() - a) / b);
       if (iWindow >= static_cast<size_t>(nWindows)) {
         LOG(error) << "ca: Hit out of range: iHit = " << iHit << ", time = " << hit.T() * 1.e-6
@@ -236,7 +234,7 @@ void TrackFinder::FindTracks()
     }
 
     // Remove hits from the "monster events"
-    if (ca::Framework::TrackingMode::kMcbm == frAlgo.fTrackingMode) {
+    if (ca::TrackingMode::kMcbm == fTrackingMode) {
       auto maxNofHitsSta = static_cast<HitIndex_t>(50 * fWindowLength / 1.e3);
       for (auto& content : nHitsWindowSta) {
         if (content > maxNofHitsSta) {
@@ -248,22 +246,20 @@ void TrackFinder::FindTracks()
     // Integrate number of hits per window
     std::vector<HitIndex_t> nHitsWindow;
     nHitsWindow.reserve(nWindows);
-    auto windowStaIt          = nHitsWindowSta.begin();
     HitIndex_t nHitsCollected = 0;
-    while (windowStaIt != nHitsWindowSta.end()) {
-      nHitsCollected = nHitsWindow.emplace_back(std::accumulate(windowStaIt, windowStaIt + nSt, nHitsCollected));
-      windowStaIt    = windowStaIt + nSt;
+    for (auto it = nHitsWindowSta.begin(); it != nHitsWindowSta.end(); it += nSt) {
+      nHitsCollected = nHitsWindow.emplace_back(std::accumulate(it, it + nSt, nHitsCollected));
     }
 
     // Get time range for threads
-    HitIndex_t nHitsPerThread = nHitsCollected / frAlgo.GetNofThreads();
+    HitIndex_t nHitsPerThread = nHitsCollected / fNofThreads;
     auto windowIt             = nHitsWindow.begin();
     size_t iWbegin            = 0;
-    for (int iTh = 1; iTh < frAlgo.GetNofThreads(); ++iTh) {
-      windowIt                   = std::lower_bound(windowIt, nHitsWindow.end(), iTh * nHitsPerThread);
-      iWbegin                    = std::distance(nHitsWindow.begin(), windowIt) + 1;
-      fvWindowStartThread[iTh]   = fStatTsStart + iWbegin * windowDelta;
-      fvWindowEndThread[iTh - 1] = fvWindowStartThread[iTh];
+    for (int iTh = 1; iTh < fNofThreads; ++iTh) {
+      windowIt                  = std::lower_bound(windowIt, nHitsWindow.end(), iTh * nHitsPerThread);
+      iWbegin                   = std::distance(nHitsWindow.begin(), windowIt) + 1;
+      vWindowStartThread[iTh]   = fStatTsStart + iWbegin * windowDelta;
+      vWindowEndThread[iTh - 1] = vWindowStartThread[iTh];
     }
     //time.Stop();
     //LOG(info) << "Thread boarders estimation time: " << time.GetTotalMs() << " ms";
@@ -272,120 +268,114 @@ void TrackFinder::FindTracks()
 
 
   // cut data into sub-timeslices and process them one by one
-  //for (int iThread = 0; iThread < frAlgo.GetNofThreads(); ++iThread) {
-  //  fvWindowStartThread[iThread] = fStatTsStart + iThread * nWindowsThread * windowDelta;
-  //  fvWindowEndThread[iThread] =
-  //    fvWindowStartThread[iThread] + nWindowsThread * windowDelta + fWindowOverlap + fWindowMargin;
+  //for (int iThread = 0; iThread < fNofThreads; ++iThread) {
+  //  vWindowStartThread[iThread] = fStatTsStart + iThread * nWindowsThread * windowDelta;
+  //  vWindowEndThread[iThread] =
+  //    vWindowStartThread[iThread] + nWindowsThread * windowDelta + fWindowOverlap + fWindowMargin;
   //}
-  fvWindowEndThread[frAlgo.GetNofThreads() - 1] = fStatTsEnd;
+  vWindowEndThread[fNofThreads - 1] = fStatTsEnd;
 
-  for (int iThread = 0; iThread < frAlgo.GetNofThreads(); ++iThread) {
-    double start = fvWindowStartThread[iThread] * 1.e-6;
-    double end   = fvWindowEndThread[iThread] * 1.e-6;
+  for (int iThread = 0; iThread < fNofThreads; ++iThread) {
+    double start = vWindowStartThread[iThread] * 1.e-6;
+    double end   = vWindowEndThread[iThread] * 1.e-6;
     LOG(trace) << "Thread: " << iThread << " from " << start << " ms  to " << end << " ms (delta = " << end - start
                << " ms)";
   }
 
-  frAlgo.fMonitorData.StopTimer(ETimer::PrepareTimeslice);
+  // Statistics for monitoring
+  std::vector<int> vStatNwindows(fNofThreads), vStatNhitsProcessed(fNofThreads);
+
+  fMonitorData.StopTimer(ETimer::PrepareTimeslice);
   // Save tracks
-  if (frAlgo.GetNofThreads() == 1) {
-    this->FindTracksThread(0);
-    frAlgo.fMonitorData.StartTimer(ETimer::StoreTracksFinal);
-    frAlgo.fRecoTracks = std::move(fvRecoTracks[0]);
-    frAlgo.fRecoHits   = std::move(fvRecoHitIndices[0]);
-    frAlgo.fMonitorData.StopTimer(ETimer::StoreTracksFinal);
+  if (fNofThreads == 1) {
+    this->FindTracksThread(input, 0, std::ref(vWindowStartThread[0]), std::ref(vWindowEndThread[0]),
+                           std::ref(vStatNwindows[0]), std::ref(vStatNhitsProcessed[0]));
+    fMonitorData.StartTimer(ETimer::StoreTracksFinal);
+    recoTracks = std::move(fvRecoTracks[0]);
+    recoHits   = std::move(fvRecoHitIndices[0]);
+    fMonitorData.StopTimer(ETimer::StoreTracksFinal);
   }
   else {
     std::vector<std::thread> vThreadList;
-    vThreadList.reserve(frAlgo.GetNofThreads());
-    for (int iTh = 0; iTh < frAlgo.GetNofThreads(); ++iTh) {
-      vThreadList.emplace_back(&TrackFinder::FindTracksThread, this, iTh);
+    vThreadList.reserve(fNofThreads);
+    for (int iTh = 0; iTh < fNofThreads; ++iTh) {
+      vThreadList.emplace_back(&TrackFinder::FindTracksThread, this, std::ref(input), iTh,
+                               std::ref(vWindowStartThread[iTh]), std::ref(vWindowEndThread[iTh]),
+                               std::ref(vStatNwindows[iTh]), std::ref(vStatNhitsProcessed[iTh]));
     }
     for (auto& th : vThreadList) {
       if (th.joinable()) {
         th.join();
       }
     }
-    frAlgo.fMonitorData.StartTimer(ETimer::StoreTracksFinal);
+    fMonitorData.StartTimer(ETimer::StoreTracksFinal);
     auto Operation  = [](size_t acc, const auto& v) { return acc + v.size(); };
     int nRecoTracks = std::accumulate(fvRecoTracks.begin(), fvRecoTracks.end(), 0, Operation);
     int nRecoHits   = std::accumulate(fvRecoHitIndices.begin(), fvRecoHitIndices.end(), 0, Operation);
-    frAlgo.fRecoTracks.reserve(nRecoTracks);
-    frAlgo.fRecoHits.reserve(nRecoHits);
-    for (int iTh = 0; iTh < frAlgo.GetNofThreads(); ++iTh) {
-      frAlgo.fRecoTracks.insert(frAlgo.fRecoTracks.end(), fvRecoTracks[iTh].begin(), fvRecoTracks[iTh].end());
-      frAlgo.fRecoHits.insert(frAlgo.fRecoHits.end(), fvRecoHitIndices[iTh].begin(), fvRecoHitIndices[iTh].end());
+    recoTracks.reserve(nRecoTracks);
+    recoHits.reserve(nRecoHits);
+    for (int iTh = 0; iTh < fNofThreads; ++iTh) {
+      recoTracks.insert(recoTracks.end(), fvRecoTracks[iTh].begin(), fvRecoTracks[iTh].end());
+      recoHits.insert(recoHits.end(), fvRecoHitIndices[iTh].begin(), fvRecoHitIndices[iTh].end());
     }
-    frAlgo.fMonitorData.StopTimer(ETimer::StoreTracksFinal);
+    fMonitorData.StopTimer(ETimer::StoreTracksFinal);
   }
 
-  frAlgo.fMonitorData.IncrementCounter(ECounter::RecoTrack, frAlgo.fRecoTracks.size());
-  frAlgo.fMonitorData.IncrementCounter(ECounter::RecoHitUsed, frAlgo.fRecoHits.size());
+  fMonitorData.IncrementCounter(ECounter::RecoTrack, recoTracks.size());
+  fMonitorData.IncrementCounter(ECounter::RecoHitUsed, recoHits.size());
 
-  auto timerEnd      = std::chrono::high_resolution_clock::now();
-  frAlgo.fCaRecoTime = (double) (std::chrono::duration<double>(timerEnd - timerStart).count());
+  auto timerEnd = std::chrono::high_resolution_clock::now();
+  fCaRecoTime   = (double) (std::chrono::duration<double>(timerEnd - timerStart).count());
 
   // Add thread monitors to the main monitor
-  for (auto& monitor : frAlgo.fvMonitorDataThread) {
-    frAlgo.fMonitorData.AddMonitorData(monitor, true);
-    //frAlgo.fMonitorData.AddMonitorData(monitor);
+  for (auto& monitor : fvMonitorDataThread) {
+    fMonitorData.AddMonitorData(monitor, true);
+    //fMonitorData.AddMonitorData(monitor);
     monitor.Reset();
   }
 
-  int statNhitsProcessedTotal = 0;
-  int statNwindowsTotal       = 0;
-  for (int iThread = 0; iThread < frAlgo.GetNofThreads(); ++iThread) {
-    statNhitsProcessedTotal += fvStatNhitsProcessed[iThread];
-    statNwindowsTotal += fvStatNwindows[iThread];
-  }
+  const int statNhitsProcessedTotal = std::accumulate(vStatNhitsProcessed.begin(), vStatNhitsProcessed.end(), 0);
+  const int statNwindowsTotal       = std::accumulate(vStatNwindows.begin(), vStatNwindows.end(), 0);
 
   // Filling TS headear
-  auto& tsHeader   = frAlgo.fTsHeader;
   tsHeader.Start() = fStatTsStart;
   tsHeader.End()   = fStatTsEnd;
 
-  frAlgo.fMonitorData.StopTimer(ETimer::Tracking);
+  fMonitorData.StopTimer(ETimer::Tracking);
 
-  LOG(debug) << "CA tracker: time slice finished. Reconstructed " << frAlgo.fRecoTracks.size() << " tracks with "
-             << frAlgo.fRecoHits.size() << " hits. Processed " << statNhitsProcessedTotal << " hits in "
-             << statNwindowsTotal << " time windows. Reco time " << frAlgo.fCaRecoTime / 1.e9 << " s";
+  LOG(debug) << "CA tracker: time slice finished. Reconstructed " << recoTracks.size() << " tracks with "
+             << recoHits.size() << " hits. Processed " << statNhitsProcessedTotal << " hits in " << statNwindowsTotal
+             << " time windows. Reco time " << fCaRecoTime / 1.e9 << " s";
+  return output;
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void TrackFinder::FindTracksThread(int iThread)
+void TrackFinder::FindTracksThread(const InputData& input, int iThread, float& windowStart, float& windowEnd,
+                                   int& statNwindows, int& statNhitsProcessed)
 {
   //std::stringstream filename;
   //filename << "./dbg_caTrackFinder::FindTracksThread_" << iThread << ".txt";
   //std::ofstream out(filename.str());
-  auto& monitor = frAlgo.fvMonitorDataThread[iThread];
+  auto& monitor = fvMonitorDataThread[iThread];
   Timer timer;
   timer.Start();
   monitor.StartTimer(ETimer::TrackingThread);
   monitor.StartTimer(ETimer::PrepareThread);
 
   // Init vectors
-  auto& wData = frAlgo.fvWData[iThread];
+  auto& wData = fvWData[iThread];
   {
-    int nStations          = frAlgo.GetParameters().GetNstationsActive();
-    size_t nHitsTot        = frAlgo.fInputData.GetNhits();
-    size_t nHitKeys        = frAlgo.fInputData.GetNhitKeys();
-    size_t nHitsExpected   = 2 * nHitsTot;
-    size_t nTracksExpected = 2 * nHitsTot / nStations;
-    size_t nThreads        = frAlgo.GetNofThreads();
+    const int nStations          = fParameters.GetNstationsActive();
+    const size_t nHitsTot        = input.GetNhits();
+    const size_t nHitsExpected   = 2 * nHitsTot;
+    const size_t nTracksExpected = 2 * nHitsTot / nStations;
     fvRecoTracks[iThread].clear();
-    fvRecoTracks[iThread].reserve(nTracksExpected / nThreads);
+    fvRecoTracks[iThread].reserve(nTracksExpected / fNofThreads);
     fvRecoHitIndices[iThread].clear();
-    fvRecoHitIndices[iThread].reserve(nHitsExpected / nThreads);
-    frAlgo.fvTrackFinderWindow[iThread].InitTimeslice();
+    fvRecoHitIndices[iThread].reserve(nHitsExpected / fNofThreads);
     if (iThread != 0) {
-      auto& wData0 = frAlgo.fvWData[0];
-      // slow ...
-      wData.HitKeyFlags().clear();
-      wData.HitKeyFlags().reserve(nHitKeys);
-      for (const auto& flag : wData0.HitKeyFlags()) {
-        wData.HitKeyFlags().emplace_back(flag);
-      }
+      wData.HitKeyFlags() = fvWData[0].HitKeyFlags();
     }
     for (int iS = 0; iS < nStations; ++iS) {
       wData.TsHitIndices(iS).clear();
@@ -393,78 +383,76 @@ void TrackFinder::FindTracksThread(int iThread)
     }
   }
 
-  const int nDataStreams    = frAlgo.fInputData.GetNdataStreams();
-  bool areUntouchedDataLeft = true;  // is the whole TS processed
+  const int nDataStreams = input.GetNdataStreams();
   std::vector<HitIndex_t> sliceFirstHit(nDataStreams, 0);
   std::vector<HitIndex_t> sliceLastHit(nDataStreams, 0);
 
   // Define first hit, skip all the hits, which are before the first window
   for (int iStream = 0; iStream < nDataStreams; ++iStream) {
-    sliceFirstHit[iStream] = frAlgo.fInputData.GetStreamStartIndex(iStream);
-    sliceLastHit[iStream]  = frAlgo.fInputData.GetStreamStopIndex(iStream);
+    sliceFirstHit[iStream] = input.GetStreamStartIndex(iStream);
+    sliceLastHit[iStream]  = input.GetStreamStopIndex(iStream);
     for (HitIndex_t caHitId = sliceFirstHit[iStream]; caHitId < sliceLastHit[iStream]; ++caHitId) {
-      CaHitTimeInfo& info = frAlgo.fHitTimeInfo[caHitId];
-      const ca::Hit& h    = frAlgo.fInputData.GetHit(caHitId);
+      const ca::Hit& h = input.GetHit(caHitId);
       if (wData.IsHitKeyUsed(h.FrontKey()) || wData.IsHitKeyUsed(h.BackKey())) {
         continue;
       }
-      if (info.fMaxTimeBeforeHit < fvWindowStartThread[iThread]) {
+      const CaHitTimeInfo& info = fHitTimeInfo[caHitId];
+      if (info.fMaxTimeBeforeHit < windowStart) {
         sliceFirstHit[iStream] = caHitId + 1;
       }
-      if (info.fMinTimeAfterHit > fvWindowEndThread[iThread]) {
+      if (info.fMinTimeAfterHit > windowEnd) {
         sliceLastHit[iStream] = caHitId;
       }
     }
   }
 
-  fvStatNwindows[iThread]       = 0;
-  fvStatNhitsProcessed[iThread] = 0;
-
   int statLastLogTimeChunk = -1;
 
+  // Track finder algorithm for the time window
+  ca::TrackFinderWindow trackFinderWindow(fParameters, fDefaultMass, fTrackingMode, fvMonitorDataThread[iThread]);
+  trackFinderWindow.InitTimeslice(input.GetNhitKeys());
+
   monitor.StopTimer(ETimer::PrepareThread);
 
+  bool areUntouchedDataLeft = true;  // is the whole TS processed
+
   while (areUntouchedDataLeft) {
-    frAlgo.fvMonitorDataThread[iThread].IncrementCounter(ECounter::SubTS);
+    fvMonitorDataThread[iThread].IncrementCounter(ECounter::SubTS);
     // select the sub-slice hits
-    for (int iS = 0; iS < frAlgo.GetParameters().GetNstationsActive(); ++iS) {
-      frAlgo.fvWData[iThread].TsHitIndices(iS).clear();
+    for (int iS = 0; iS < fParameters.GetNstationsActive(); ++iS) {
+      wData.TsHitIndices(iS).clear();
     }
-
     areUntouchedDataLeft = false;
 
     // TODO: SG: skip empty regions and start the subslice with the earliest hit
 
-    fvStatNwindows[iThread]++;
-    //out << fvStatNwindows[iThread] << ' ';
+    statNwindows++;
+    //out << statNwindows << ' ';
 
     int statNwindowHits = 0;
 
-    frAlgo.fvMonitorDataThread[iThread].StartTimer(ETimer::PrepareWindow);
+    fvMonitorDataThread[iThread].StartTimer(ETimer::PrepareWindow);
     for (int iStream = 0; iStream < nDataStreams; ++iStream) {
       for (ca::HitIndex_t caHitId = sliceFirstHit[iStream]; caHitId < sliceLastHit[iStream]; ++caHitId) {
-        const CaHitTimeInfo& info = frAlgo.fHitTimeInfo[caHitId];
-        const ca::Hit& h          = frAlgo.fInputData.GetHit(caHitId);
+        const CaHitTimeInfo& info = fHitTimeInfo[caHitId];
+        const ca::Hit& h          = input.GetHit(caHitId);
         if (wData.IsHitKeyUsed(h.FrontKey()) || wData.IsHitKeyUsed(h.BackKey())) {
           // the hit is already reconstructed
           continue;
         }
-        if (info.fEventTimeMin
-            > fvWindowStartThread[iThread] + fWindowLength) {  // the hit is too late for the sub slice
+        if (info.fEventTimeMin > windowStart + fWindowLength) {  // the hit is too late for the sub slice
           areUntouchedDataLeft = true;
-          if (info.fMinTimeAfterHit > fvWindowStartThread[iThread] + fWindowLength) {
+          if (info.fMinTimeAfterHit > windowStart + fWindowLength) {
             // this hit and all later hits are out of the sub-slice
             break;
           }
         }
-        else {
-          if (fvWindowStartThread[iThread] <= info.fEventTimeMax) {  // the hit belongs to the sub-slice
-            frAlgo.fvWData[iThread].TsHitIndices(h.Station()).push_back(caHitId);
-            statNwindowHits++;
-            if (info.fMaxTimeBeforeHit < fvWindowStartThread[iThread] + fWindowLength - fWindowOverlap) {
-              // this hit and all hits before are before the overlap
-              sliceFirstHit[iStream] = caHitId + 1;
-            }
+        else if (windowStart <= info.fEventTimeMax) {  // the hit belongs to the sub-slice
+          wData.TsHitIndices(h.Station()).push_back(caHitId);
+          statNwindowHits++;
+          if (info.fMaxTimeBeforeHit < windowStart + fWindowLength - fWindowOverlap) {
+            // this hit and all hits before are before the overlap
+            sliceFirstHit[iStream] = caHitId + 1;
           }
         }  // else the hit has been alread processed in previous sub-slices
       }
@@ -472,40 +460,38 @@ void TrackFinder::FindTracksThread(int iThread)
 
     //out << statNwindowHits << ' ';
     //if (statNwindowHits == 0) {  // Empty window
-    //  frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::PrepareWindow);
+    //  fvMonitorDataThread[iThread].StopTimer(ETimer::PrepareWindow);
     //  out << 0 << ' ' << 0 << ' ' << 0 << '\n';
     //  continue;
     //}
 
-    if (ca::Framework::TrackingMode::kMcbm == frAlgo.fTrackingMode) {
+    if (ca::TrackingMode::kMcbm == fTrackingMode) {
       // cut at 50 hits per station per 1 us.
       int maxStationHits = (int) (50 * fWindowLength / 1.e3);
-      for (int ista = 0; ista < frAlgo.GetParameters().GetNstationsActive(); ++ista) {
-        int nHitsSta = static_cast<int>(frAlgo.fvWData[iThread].TsHitIndices(ista).size());
+      for (int ista = 0; ista < fParameters.GetNstationsActive(); ++ista) {
+        int nHitsSta = static_cast<int>(wData.TsHitIndices(ista).size());
         if (nHitsSta > maxStationHits) {
           statNwindowHits -= nHitsSta;
-          frAlgo.fvWData[iThread].TsHitIndices(ista).clear();
+          wData.TsHitIndices(ista).clear();
         }
       }
     }
 
-    fvStatNhitsProcessed[iThread] += statNwindowHits;
+    statNhitsProcessed += statNwindowHits;
 
     // print the LOG for every 10 ms of data processed
     if constexpr (0) {
-      int currentChunk = (int) ((fvWindowStartThread[iThread] - fStatTsStart) / 10.e6);
+      int currentChunk = (int) ((windowStart - fStatTsStart) / 10.e6);
       if (!areUntouchedDataLeft || currentChunk > statLastLogTimeChunk) {
         statLastLogTimeChunk = currentChunk;
-        double dataRead =
-          100. * (fvWindowStartThread[iThread] + fWindowLength - fStatTsStart) / (fStatTsEnd - fStatTsStart);
+        double dataRead      = 100. * (windowStart + fWindowLength - fStatTsStart) / (fStatTsEnd - fStatTsStart);
         if (dataRead > 100.) {
           dataRead = 100.;
         }
-        LOG(info) << "CA tracker process sliding window N " << fvStatNwindows[iThread] << ": time "
-                  << fvWindowStartThread[iThread] / 1.e6 << " ms + " << fWindowLength / 1.e3 << " us) with "
-                  << statNwindowHits << " hits. "
+        LOG(info) << "CA tracker process sliding window N " << statNwindows << ": time " << windowStart / 1.e6
+                  << " ms + " << fWindowLength / 1.e3 << " us) with " << statNwindowHits << " hits. "
                   << " Processing " << dataRead << " % of the TS time and "
-                  << 100. * fvStatNhitsProcessed[iThread] / fStatNhitsTotal << " % of TS hits."
+                  << 100. * statNhitsProcessed / fStatNhitsTotal << " % of TS hits."
                   << " Already reconstructed " << fvRecoTracks[iThread].size() << " tracks on thread #" << iThread;
       }
     }
@@ -513,107 +499,68 @@ void TrackFinder::FindTracksThread(int iThread)
 
     //out << statNwindowHits << ' ';
 
-    frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::PrepareWindow);
+    fvMonitorDataThread[iThread].StopTimer(ETimer::PrepareWindow);
 
     //Timer trackingInWindow;  //DBG
     //trackingInWindow.Start();
-    frAlgo.fvMonitorDataThread[iThread].StartTimer(ETimer::TrackingWindow);
-    frAlgo.fvTrackFinderWindow[iThread].CaTrackFinderSlice();
-    frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::TrackingWindow);
+    fvMonitorDataThread[iThread].StartTimer(ETimer::TrackingWindow);
+    trackFinderWindow.CaTrackFinderSlice(input, wData);
+    fvMonitorDataThread[iThread].StopTimer(ETimer::TrackingWindow);
     //trackingInWindow.Stop();
     //out << trackingInWindow.GetTotalMs() << ' ';
 
     // save reconstructed tracks with no hits in the overlap region
-    //if (fvWindowStartThread[iThread] > 13.23e6 && fvWindowStartThread[iThread] < 13.26e6) {
-    fvWindowStartThread[iThread] += fWindowLength - fWindowOverlap;
+    //if (windowStart > 13.23e6 && windowStart < 13.26e6) {
+    windowStart += fWindowLength - fWindowOverlap;
     // we should add hits from reconstructed but not stored tracks to the new sub-timeslice
     // we do it in a simple way by extending the tsStartNew
     // TODO: only add those hits from the region before tsStartNew that belong to the not stored tracks
-    //out << frAlgo.fvWData[iThread].RecoHitIndices().size() << ' ';
-    //out << frAlgo.fvWData[iThread].RecoTracks().size() << '\n';
-
-    frAlgo.fvMonitorDataThread[iThread].StartTimer(ETimer::StoreTracksWindow);
-    int trackFirstHit = 0;
-    for (const auto& track : frAlgo.fvWData[iThread].RecoTracks()) {
-      bool isTrackCompletelyInOverlap = true;
-      for (int ih = 0; ih < track.fNofHits; ih++) {
-        int caHitId         = frAlgo.fvWData[iThread].RecoHitIndex(trackFirstHit + ih);
-        CaHitTimeInfo& info = frAlgo.fHitTimeInfo[caHitId];
-        if (info.fEventTimeMax < fvWindowStartThread[iThread]) {  // this hit is before the overlap
-          isTrackCompletelyInOverlap = false;
-          break;
-        }
-      }
+    //out << fvWData[iThread].RecoHitIndices().size() << ' ';
+    //out << fvWData[iThread].RecoTracks().size() << '\n';
 
-      if (!areUntouchedDataLeft) {  // don't reject tracks in the overlap when no more data are left
-        isTrackCompletelyInOverlap = 0;
-      }
+    fvMonitorDataThread[iThread].StartTimer(ETimer::StoreTracksWindow);
+    auto trackFirstHit = wData.RecoHitIndices().begin();
+
+    for (const auto& track : wData.RecoTracks()) {
+
+      const bool isTrackCompletelyInOverlap =
+        std::all_of(trackFirstHit, trackFirstHit + track.fNofHits, [&](int caHitId) {
+          CaHitTimeInfo& info = fHitTimeInfo[caHitId];
+          return info.fEventTimeMax >= windowStart;
+        });
 
-      if (isTrackCompletelyInOverlap) {
-        //
-        // Don't save tracks from the overlap region, since they might have additional hits in the next subslice
-        //
-
-        // release the track hits
-        for (int i = 0; i < track.fNofHits; i++) {
-          int caHitId                      = frAlgo.fvWData[iThread].RecoHitIndex(trackFirstHit + i);
-          const auto& h                    = frAlgo.fInputData.GetHit(caHitId);
-          wData.IsHitKeyUsed(h.FrontKey()) = 0;
-          wData.IsHitKeyUsed(h.BackKey())  = 0;
+      // Don't save tracks from the overlap region, since they might have additional hits in the next subslice.
+      // Don't reject tracks in the overlap when no more data are left
+      const bool useFlag = !isTrackCompletelyInOverlap || !areUntouchedDataLeft;
+
+      for (int i = 0; i < track.fNofHits; i++) {
+        const int caHitId                = *(trackFirstHit + i);
+        const auto& h                    = input.GetHit(caHitId);
+        wData.IsHitKeyUsed(h.FrontKey()) = static_cast<int>(useFlag);
+        wData.IsHitKeyUsed(h.BackKey())  = static_cast<int>(useFlag);
+
+        if (useFlag) {
+          fvRecoHitIndices[iThread].push_back(caHitId);
         }
       }
-      else {  // save the track
+      if (useFlag) {
         fvRecoTracks[iThread].push_back(track);
-        // mark the track hits as used
-        for (int i = 0; i < track.fNofHits; i++) {
-          int caHitId                      = frAlgo.fvWData[iThread].RecoHitIndex(trackFirstHit + i);
-          const auto& h                    = frAlgo.fInputData.GetHit(caHitId);
-          wData.IsHitKeyUsed(h.FrontKey()) = 1;
-          wData.IsHitKeyUsed(h.BackKey())  = 1;
-          fvRecoHitIndices[iThread].push_back(caHitId);
-        }
       }
+
       trackFirstHit += track.fNofHits;
     }  // sub-timeslice tracks
-    frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::StoreTracksWindow);
+    fvMonitorDataThread[iThread].StopTimer(ETimer::StoreTracksWindow);
 
-    if (fvWindowStartThread[iThread] > fvWindowEndThread[iThread]) {
+    if (windowStart > windowEnd) {
       break;
     }
     else {
-      fvWindowStartThread[iThread] -= fWindowMargin;  // do 5 ns margin
+      windowStart -= fWindowMargin;  // do 5 ns margin
     }
   }
-  frAlgo.fvMonitorDataThread[iThread].StopTimer(ETimer::TrackingThread);
+  fvMonitorDataThread[iThread].StopTimer(ETimer::TrackingThread);
   //timer.Stop();
   //LOG(info) << "CA: finishing tracking on thread " << iThread << " (time: " << timer.GetTotalMs() << " ms, "
-  //          << "hits processed: " << fvStatNhitsProcessed[iThread] << ", "
+  //          << "hits processed: " << statNhitsProcessed << ", "
   //          << "hits used: " << fvRecoHitIndices[iThread].size() << ')';
 }
-
-// ---------------------------------------------------------------------------------------------------------------------
-//
-void TrackFinder::Init()
-{
-  assert(frAlgo.GetNofThreads() > 0);
-
-  fvWindowStartThread.clear();
-  fvWindowStartThread.resize(frAlgo.GetNofThreads());
-  fvWindowEndThread.clear();
-  fvWindowEndThread.resize(frAlgo.GetNofThreads());
-  fvStatNwindows.clear();
-  fvStatNwindows.resize(frAlgo.GetNofThreads());
-  fvStatNhitsProcessed.clear();
-  fvStatNhitsProcessed.resize(frAlgo.GetNofThreads());
-  fvRecoTracks.clear();
-  fvRecoTracks.resize(frAlgo.GetNofThreads());
-  fvRecoHitIndices.clear();
-  fvRecoHitIndices.resize(frAlgo.GetNofThreads());
-
-  for (int iThread = 0; iThread < frAlgo.GetNofThreads(); ++iThread) {
-    fvRecoTracks[iThread].SetName(std::string("TrackFinder::fvRecoTracks_") + std::to_string(iThread));
-    fvRecoHitIndices[iThread].SetName(std::string("TrackFinder::fvRecoHitIndices_") + std::to_string(iThread));
-  }
-
-  fWindowLength = (ca::Framework::TrackingMode::kMcbm == frAlgo.fTrackingMode) ? 500 : 10000;
-}
diff --git a/algo/ca/core/tracking/CaTrackFinder.h b/algo/ca/core/tracking/CaTrackFinder.h
index ffe5a856a2..7f270d633b 100644
--- a/algo/ca/core/tracking/CaTrackFinder.h
+++ b/algo/ca/core/tracking/CaTrackFinder.h
@@ -9,6 +9,10 @@
 #include "CaBranch.h"
 #include "CaHit.h"
 #include "CaSimd.h"
+#include "CaTimesliceHeader.h"
+#include "CaTrackExtender.h"
+#include "CaTrackFinderWindow.h"
+#include "CaTrackFitter.h"
 #include "CaTrackParam.h"
 #include "CaVector.h"
 
@@ -29,11 +33,13 @@ namespace cbm::algo::ca
   ///
   class TrackFinder {
    public:
-    /// Default constructor
-    TrackFinder(ca::Framework& algo);
+    typedef std::pair<Vector<Track>, Vector<ca::HitIndex_t>> Output_t;
 
+    /// Default constructora
+    TrackFinder(const ca::Parameters<fvec>& pars, const float mass, const ca::TrackingMode& mode,
+                TrackingMonitorData& monitorData, int nThreads, double& recoTime);
     /// Destructor
-    ~TrackFinder();
+    ~TrackFinder() = default;
 
     /// Copy constructor
     TrackFinder(const TrackFinder&) = delete;
@@ -47,31 +53,36 @@ namespace cbm::algo::ca
     /// Move assignment operator
     TrackFinder& operator=(TrackFinder&&) = delete;
 
-    void FindTracks();
-    void FindTracksThread(int iThread);
-    void Init();
+    Output_t FindTracks(const InputData& input, TimesliceHeader& tsHeader);
 
     const auto& GetRecoTracksContainer(int iThread) const { return fvRecoTracks[iThread]; }
     const auto& GetRecoHitIndicesContainer(int iThread) const { return fvRecoHitIndices[iThread]; }
+    TrackingMode GetTrackingMode() const { return fTrackingMode; }
+    const std::vector<ca::WindowData>& GetWData() const { return fvWData; }
 
    private:
     // -------------------------------
     // Private methods
+    void FindTracksThread(const InputData& input, int iThread, float& windowStart, float& windowEnd, int& statNwindows,
+                          int& statNhitsProcessed);
+    //   bool checkTripletMatch(const ca::Triplet& l, const ca::Triplet& r, fscal& dchi2) const;
 
-    bool checkTripletMatch(const ca::Triplet& l, const ca::Triplet& r, fscal& dchi2) const;
-
-
-   private:
     // -------------------------------
     // Data members
 
-    ca::Framework& frAlgo;  ///< Reference to the main track finder algorithm class
+    Vector<CaHitTimeInfo> fHitTimeInfo;
+
+    const Parameters<fvec>& fParameters;            ///< Object of Framework parameters class
+    float fDefaultMass{constants::phys::MuonMass};  ///< mass of the propagated particle [GeV/c2]
+    ca::TrackingMode fTrackingMode;
+
+    TrackingMonitorData& fMonitorData;                     ///< Tracking monitor data (statistics per call)
+    std::vector<TrackingMonitorData> fvMonitorDataThread;  ///< Tracking monitor data per thread
 
-    std::vector<float> fvWindowStartThread;
-    std::vector<float> fvWindowEndThread;
+    std::vector<ca::WindowData> fvWData;  ///< Intrnal data processed in a time-window
 
-    std::vector<int> fvStatNwindows;
-    std::vector<int> fvStatNhitsProcessed;
+    int fNofThreads;      ///< Number of threads to execute the track-finder
+    double& fCaRecoTime;  // time of the track finder + fitter
 
     std::vector<Vector<Track>> fvRecoTracks;           ///< reconstructed tracks
     std::vector<Vector<HitIndex_t>> fvRecoHitIndices;  ///< packed hits of reconstructed tracks
diff --git a/algo/ca/core/tracking/CaTrackFinderWindow.cxx b/algo/ca/core/tracking/CaTrackFinderWindow.cxx
index 3ad43cadb0..ff9b0a5b8e 100644
--- a/algo/ca/core/tracking/CaTrackFinderWindow.cxx
+++ b/algo/ca/core/tracking/CaTrackFinderWindow.cxx
@@ -46,13 +46,15 @@ using namespace cbm::algo::ca;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-TrackFinderWindow::TrackFinderWindow(ca::Framework& algo, ca::WindowData& wData, ca::TrackingMonitorData& monitorData)
-  : frAlgo(algo)
-  , frWData(wData)
+TrackFinderWindow::TrackFinderWindow(const ca::Parameters<fvec>& pars, const float mass, const ca::TrackingMode& mode,
+                                     ca::TrackingMonitorData& monitorData)
+  : fParameters(pars)
+  , fDefaultMass(mass)
+  , fTrackingMode(mode)
   , frMonitorData(monitorData)
-  , fTrackExtender(frAlgo, frWData)
-  , fCloneMerger(frAlgo)
-  , fTrackFitter(frAlgo, frWData)
+  , fTrackExtender(pars, mass)
+  , fCloneMerger(pars, mass)
+  , fTrackFitter(pars, mass, mode)
 {
   for (unsigned int i = 0; i < constants::size::MaxNstations; ++i) {
     fvTriplets[i].SetName(std::stringstream() << "TrackFinderWindow::fTriplets[" << i << "]");
@@ -68,7 +70,8 @@ TrackFinderWindow::~TrackFinderWindow() {}
 //
 
 
-bool TrackFinderWindow::checkTripletMatch(const ca::Triplet& l, const ca::Triplet& r, fscal& dchi2) const
+bool TrackFinderWindow::checkTripletMatch(const ca::Triplet& l, const ca::Triplet& r, fscal& dchi2,
+                                          WindowData& wData) const
 {
   dchi2 = 1.e20;
 
@@ -79,7 +82,7 @@ bool TrackFinderWindow::checkTripletMatch(const ca::Triplet& l, const ca::Triple
   if (r.GetLSta() != l.GetMSta()) return false;
 
 
-  const float tripletLinkChi2 = frWData.CurrentIteration()->GetTripletLinkChi2();
+  const float tripletLinkChi2 = wData.CurrentIteration()->GetTripletLinkChi2();
   if (r.IsMomentumFitted()) {
     assert(l.IsMomentumFitted());
 
@@ -120,7 +123,6 @@ bool TrackFinderWindow::checkTripletMatch(const ca::Triplet& l, const ca::Triple
   return true;
 }
 
-void TrackFinderWindow::InitTimeslice() { fvHitKeyToTrack.reset(frAlgo.fInputData.GetNhitKeys(), -1); }
 
 // **************************************************************************************************
 // *                                                                                                *
@@ -130,65 +132,62 @@ void TrackFinderWindow::InitTimeslice() { fvHitKeyToTrack.reset(frAlgo.fInputDat
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void TrackFinderWindow::ReadWindowData()
+void TrackFinderWindow::ReadWindowData(const ca::InputData& input, WindowData& wData)
 {
   int nHits = 0;
-  for (int iS = 0; iS < frAlgo.GetParameters().GetNstationsActive(); iS++) {
-    frWData.HitStartIndexOnStation(iS) = nHits;
-    frWData.NofHitsOnStation(iS)       = frWData.TsHitIndices(iS).size();
-    nHits += frWData.NofHitsOnStation(iS);
+  for (int iS = 0; iS < fParameters.GetNstationsActive(); iS++) {
+    wData.HitStartIndexOnStation(iS) = nHits;
+    wData.NofHitsOnStation(iS)       = wData.TsHitIndices(iS).size();
+    nHits += wData.NofHitsOnStation(iS);
   }
-  frWData.HitStartIndexOnStation(frAlgo.GetParameters().GetNstationsActive()) = nHits;
-  frWData.ResetHitData(nHits);
-
-  for (int iS = 0; iS < frAlgo.GetParameters().GetNstationsActive(); iS++) {
-    int iFstHit = frWData.HitStartIndexOnStation(iS);
-    for (ca::HitIndex_t ih = 0; ih < frWData.TsHitIndices(iS).size(); ++ih) {
-      ca::Hit h = frAlgo.fInputData.GetHit(frWData.TsHitIndex(iS, ih));
-      h.SetId(frWData.TsHitIndex(iS, ih));
-      frWData.Hit(iFstHit + ih) = h;
+  wData.HitStartIndexOnStation(fParameters.GetNstationsActive()) = nHits;
+  wData.ResetHitData(nHits);
+
+  for (int iS = 0; iS < fParameters.GetNstationsActive(); iS++) {
+    int iFstHit = wData.HitStartIndexOnStation(iS);
+    for (ca::HitIndex_t ih = 0; ih < wData.TsHitIndices(iS).size(); ++ih) {
+      ca::Hit h = input.GetHit(wData.TsHitIndex(iS, ih));
+      h.SetId(wData.TsHitIndex(iS, ih));
+      wData.Hit(iFstHit + ih) = h;
     }
   }
 
   if constexpr (fDebug) {
     LOG(info) << "===== Sliding Window hits: ";
     for (int i = 0; i < nHits; ++i) {
-      LOG(info) << "    " << frWData.Hit(i).ToString();
+      LOG(info) << "    " << wData.Hit(i).ToString();
     }
     LOG(info) << "===== ";
   }
 
-  fvHitFirstTriplet.reset(nHits, 0);
-  fvHitNofTriplets.reset(nHits, 0);
 
+  wData.RecoTracks().clear();
+  wData.RecoTracks().reserve(2 * nHits / fParameters.GetNstationsActive());
 
-  frWData.RecoTracks().clear();
-  frWData.RecoTracks().reserve(2 * nHits / frAlgo.GetParameters().GetNstationsActive());
-
-  frWData.RecoHitIndices().clear();
-  frWData.RecoHitIndices().reserve(2 * nHits);
+  wData.RecoHitIndices().clear();
+  wData.RecoHitIndices().reserve(2 * nHits);
 
   fvTrackCandidates.clear();
   fvTrackCandidates.reserve(nHits / 10);
   for (unsigned int iS = 0; iS < constants::size::MaxNstations; iS++) {
-    int nHitsStation = frWData.TsHitIndices(iS).size();
+    int nHitsStation = wData.TsHitIndices(iS).size();
     fvTriplets[iS].clear();
     fvTriplets[iS].reserve(2 * nHitsStation);
   }
 }
 
-void TrackFinderWindow::CaTrackFinderSlice()
+void TrackFinderWindow::CaTrackFinderSlice(const ca::InputData& input, WindowData& wData)
 {
   /********************************/ /**
    * CATrackFinder routine setting
    ***********************************/
 
   frMonitorData.StartTimer(ETimer::InitWindow);
-  ReadWindowData();
+  ReadWindowData(input, wData);
   frMonitorData.StopTimer(ETimer::InitWindow);
 
   frMonitorData.StartTimer(ETimer::PrepareGrid);
-  for (int iS = 0; iS < frAlgo.GetParameters().GetNstationsActive(); ++iS) {
+  for (int iS = 0; iS < fParameters.GetNstationsActive(); ++iS) {
 
     bool timeUninitialised = 1;
     fscal lasttime         = 0;
@@ -200,8 +199,8 @@ void TrackFinderWindow::CaTrackFinderSlice()
     fscal gridMinY = -0.1;
     fscal gridMaxY = 0.1;
 
-    for (ca::HitIndex_t ih = 0; ih < frWData.TsHitIndices(iS).size(); ++ih) {
-      const ca::Hit& h = frAlgo.fInputData.GetHit(frWData.TsHitIndex(iS, ih));
+    for (ca::HitIndex_t ih = 0; ih < wData.TsHitIndices(iS).size(); ++ih) {
+      const ca::Hit& h = input.GetHit(wData.TsHitIndex(iS, ih));
 
       if (h.X() < gridMinX) {
         gridMinX = h.X();
@@ -230,7 +229,7 @@ void TrackFinderWindow::CaTrackFinderSlice()
     // TODO: changing the grid also changes the result. Investigate why it happens.
     // TODO: find the optimal grid size
 
-    int nSliceHits = frWData.TsHitIndices(iS).size();
+    int nSliceHits = wData.TsHitIndices(iS).size();
     fscal sizeY    = gridMaxY - gridMinY;
     fscal sizeX    = gridMaxX - gridMinX;
     int nBins2D    = 1 + nSliceHits;
@@ -238,20 +237,20 @@ void TrackFinderWindow::CaTrackFinderSlice()
     fscal yStep = 0.3 * sizeY / sqrt(nBins2D);
     fscal xStep = 0.8 * sizeX / sqrt(nBins2D);
 
-    fscal scale = frAlgo.GetParameters().GetStation(iS).GetZ<float>() - frAlgo.GetParameters().GetTargetPositionZ()[0];
+    fscal scale = fParameters.GetStation(iS).GetZ<float>() - fParameters.GetTargetPositionZ()[0];
 
     if (yStep > 0.3 * scale) yStep = 0.3 * scale;
     if (yStep < 0.01 * scale) yStep = 0.01 * scale;
     if (xStep > 0.3 * scale) xStep = 0.3 * scale;
     if (xStep < 0.01 * scale) xStep = 0.01 * scale;
 
-    auto& grid = frWData.Grid(iS);
+    auto& grid = wData.Grid(iS);
     grid.BuildBins(gridMinX, gridMaxX, gridMinY, gridMaxY, xStep, yStep);
     /* clang-format off */
-    grid.StoreHits(frWData.Hits(), 
-                   frWData.HitStartIndexOnStation(iS), 
-                   frWData.NofHitsOnStation(iS),
-                   frWData.HitKeyFlags());
+    grid.StoreHits(wData.Hits(), 
+                   wData.HitStartIndexOnStation(iS), 
+                   wData.NofHitsOnStation(iS),
+                   wData.HitKeyFlags());
     /* clang-format on */
   }
   frMonitorData.StopTimer(ETimer::PrepareGrid);
@@ -260,30 +259,30 @@ void TrackFinderWindow::CaTrackFinderSlice()
   //
   frMonitorData.StartTimer(ETimer::FindTracks);
   // TODO: Get rid of fCurrentTierationIndex. If it is needed of logs, please used caIteration.GetName()
-  for (int iIteration = 0; iIteration < frAlgo.GetParameters().GetNcaIterations(); ++iIteration) {
+  for (int iIteration = 0; iIteration < fParameters.GetNcaIterations(); ++iIteration) {
 
     // ----- Prepare iteration
     //
     frMonitorData.StartTimer(ETimer::PrepareIteration);
-    const auto& caIteration = frAlgo.GetParameters().GetCAIterations()[iIteration];
-    frWData.SetCurrentIteration(&caIteration);
-    frWData.SetCurrentIterationIndex(iIteration);
+    const auto& caIteration = fParameters.GetCAIterations()[iIteration];
+    wData.SetCurrentIteration(&caIteration);
+    wData.SetCurrentIterationIndex(iIteration);
 
     if (iIteration > 0) {
-      for (int ista = 0; ista < frAlgo.GetParameters().GetNstationsActive(); ++ista) {
-        frWData.Grid(ista).RemoveUsedHits(frWData.Hits(), frWData.HitKeyFlags());
+      for (int ista = 0; ista < fParameters.GetNstationsActive(); ++ista) {
+        wData.Grid(ista).RemoveUsedHits(wData.Hits(), wData.HitKeyFlags());
       }
     }
 
-    int nHits = frWData.Hits().size();
+    int nHits = wData.Hits().size();
     // --> frAlgo.fIsWindowHitSuppressed.reset(frAlgo.fWindowHits.size(), 0);
-    frWData.ResetHitSuppressionFlags();  // TODO: ??? No effect?
-    for (int j = 0; j < frAlgo.GetParameters().GetNstationsActive(); j++) {
+    wData.ResetHitSuppressionFlags();  // TODO: ??? No effect?
+    for (int j = 0; j < fParameters.GetNstationsActive(); j++) {
       fvTriplets[j].clear();
     }
 
-    fvHitFirstTriplet.reset(nHits, 0);
-    fvHitNofTriplets.reset(nHits, 0);
+    Vector<int> vHitFirstTriplet(nHits, 0);  /// link hit -> first triplet { hit, *, *}
+    Vector<int> vHitNofTriplets(nHits, 0);   /// link hit ->n triplets { hit, *, *}
 
     {
       // #pragma omp  task
@@ -295,21 +294,19 @@ void TrackFinderWindow::CaTrackFinderSlice()
 
         // Select magnetic field. For primary tracks - fVtxFieldValue, for secondary tracks - st.fieldSlice
         if (caIteration.GetPrimaryFlag()) {
-          frWData.TargB() = frAlgo.GetParameters().GetVertexFieldValue();
+          wData.TargB() = fParameters.GetVertexFieldValue();
         }
         else {
-          frWData.TargB() = frAlgo.GetParameters().GetStation(0).fieldSlice.GetFieldValue(0, 0);
+          wData.TargB() = fParameters.GetStation(0).fieldSlice.GetFieldValue(0, 0);
         }  // NOTE: calculates field frAlgo.fTargB in the center of 0th station
 
-        frAlgo.fIsTargetField = (fabs(frWData.TargB().y[0]) > 0.001);
-
-        frWData.TargetMeasurement().SetX(frAlgo.GetParameters().GetTargetPositionX());
-        frWData.TargetMeasurement().SetY(frAlgo.GetParameters().GetTargetPositionY());
-        frWData.TargetMeasurement().SetDx2(SigmaTargetX * SigmaTargetX);
-        frWData.TargetMeasurement().SetDxy(0);
-        frWData.TargetMeasurement().SetDy2(SigmaTargetY * SigmaTargetY);
-        frWData.TargetMeasurement().SetNdfX(1);
-        frWData.TargetMeasurement().SetNdfY(1);
+        wData.TargetMeasurement().SetX(fParameters.GetTargetPositionX());
+        wData.TargetMeasurement().SetY(fParameters.GetTargetPositionY());
+        wData.TargetMeasurement().SetDx2(SigmaTargetX * SigmaTargetX);
+        wData.TargetMeasurement().SetDxy(0);
+        wData.TargetMeasurement().SetDy2(SigmaTargetY * SigmaTargetY);
+        wData.TargetMeasurement().SetNdfX(1);
+        wData.TargetMeasurement().SetNdfY(1);
       }
     }
     frMonitorData.StopTimer(ETimer::PrepareIteration);
@@ -318,20 +315,20 @@ void TrackFinderWindow::CaTrackFinderSlice()
     //
     frMonitorData.StartTimer(ETimer::ConstructTriplets);
 
-    ca::TripletConstructor constructor(frAlgo, frWData);
+    ca::TripletConstructor constructor(fParameters, input, wData, fDefaultMass, fTrackingMode);
 
     // indices of the two neighbouring station, taking into account allowed gaps
     std::vector<std::pair<int, int>> staPattern;
-    for (int gap = 0; gap <= frWData.CurrentIteration()->GetMaxStationGap(); gap++) {
+    for (int gap = 0; gap <= wData.CurrentIteration()->GetMaxStationGap(); gap++) {
       for (int i = 0; i <= gap; i++) {
         staPattern.push_back(std::make_pair(1 + i, 2 + gap));
       }
     }
 
-    const int iStFirst = frWData.CurrentIteration()->GetFirstStationIndex();
-    for (int istal = frAlgo.GetParameters().GetNstationsActive() - 2; istal >= iStFirst; istal--) {
+    const int iStFirst = wData.CurrentIteration()->GetFirstStationIndex();
+    for (int istal = fParameters.GetNstationsActive() - 2; istal >= iStFirst; istal--) {
       // start with downstream chambers
-      const auto& grid     = frWData.Grid(istal);
+      const auto& grid     = wData.Grid(istal);
       Tindex nGridEntriesL = grid.GetEntries().size();
       for (Tindex iel = 0; iel < nGridEntriesL; ++iel) {
         ca::HitIndex_t ihitl = grid.GetEntries()[iel].GetObjectId();
@@ -341,8 +338,8 @@ void TrackFinderWindow::CaTrackFinderSlice()
           fvTriplets[istal].insert(fvTriplets[istal].end(), constructor.GetTriplets().begin(),
                                    constructor.GetTriplets().end());
         }
-        fvHitFirstTriplet[ihitl] = frAlgo.PackTripletId(istal, oldSize);
-        fvHitNofTriplets[ihitl]  = fvTriplets[istal].size() - oldSize;
+        vHitFirstTriplet[ihitl] = PackTripletId(istal, oldSize);
+        vHitNofTriplets[ihitl]  = fvTriplets[istal].size() - oldSize;
       }
     }  // istal
     frMonitorData.StopTimer(ETimer::ConstructTriplets);
@@ -351,7 +348,7 @@ void TrackFinderWindow::CaTrackFinderSlice()
     //
     frMonitorData.StartTimer(ETimer::SearchNeighbours);
 
-    for (int istal = frAlgo.GetParameters().GetNstationsActive() - 2; istal >= iStFirst; istal--) {
+    for (int istal = fParameters.GetNstationsActive() - 2; istal >= iStFirst; istal--) {
       // start with downstream chambers
       for (unsigned int it = 0; it < fvTriplets[istal].size(); ++it) {
 
@@ -360,15 +357,14 @@ void TrackFinderWindow::CaTrackFinderSlice()
         tr.SetFNeighbour(0);
         tr.SetNNeighbours(0);
 
-        unsigned int nNeighbours = fvHitNofTriplets[tr.GetMHit()];
-
-        unsigned int neighLocation = fvHitFirstTriplet[tr.GetMHit()];
-        unsigned int neighStation  = frAlgo.TripletId2Station(neighLocation);
-        unsigned int neighTriplet  = frAlgo.TripletId2Triplet(neighLocation);
+        unsigned int nNeighbours   = vHitNofTriplets[tr.GetMHit()];
+        unsigned int neighLocation = vHitFirstTriplet[tr.GetMHit()];
+        unsigned int neighStation  = TripletId2Station(neighLocation);
+        unsigned int neighTriplet  = TripletId2Triplet(neighLocation);
 
         if (nNeighbours > 0) {
           assert((int) neighStation >= istal + 1
-                 && (int) neighStation <= istal + 1 + frWData.CurrentIteration()->GetMaxStationGap());
+                 && (int) neighStation <= istal + 1 + wData.CurrentIteration()->GetMaxStationGap());
         }
 
         unsigned char level = 0;
@@ -378,7 +374,7 @@ void TrackFinderWindow::CaTrackFinderSlice()
           ca::Triplet& neighbour = fvTriplets[neighStation][neighTriplet];
 
           fscal dchi2 = 0.;
-          if (!checkTripletMatch(tr, neighbour, dchi2)) continue;
+          if (!checkTripletMatch(tr, neighbour, dchi2, wData)) continue;
 
           if (tr.GetFNeighbour() == 0) {
             tr.SetFNeighbour(neighLocation);
@@ -407,7 +403,7 @@ void TrackFinderWindow::CaTrackFinderSlice()
     // min level to start triplet. So min track length = min_level+3.
     int min_level = std::min(caIteration.GetMinNhits(), caIteration.GetMinNhitsStation0()) - 3;
 
-    if (frWData.CurrentIteration()->GetTrackFromTripletsFlag()) {
+    if (wData.CurrentIteration()->GetTrackFromTripletsFlag()) {
       min_level = 0;
     }
 
@@ -419,48 +415,47 @@ void TrackFinderWindow::CaTrackFinderSlice()
 
 
     // collect consequtive: the longest tracks, shorter, more shorter and so on
-    for (int firstTripletLevel = frAlgo.GetParameters().GetNstationsActive() - 3; firstTripletLevel >= min_level;
+    for (int firstTripletLevel = fParameters.GetNstationsActive() - 3; firstTripletLevel >= min_level;
          firstTripletLevel--) {
       // choose length in triplets number - firstTripletLevel - the maximum possible triplet level among all triplets in the searched candidate
 
       //  how many levels to check
-      int nlevel = (frAlgo.GetParameters().GetNstationsActive() - 2) - firstTripletLevel + 1;
+      int nlevel = (fParameters.GetNstationsActive() - 2) - firstTripletLevel + 1;
 
       const unsigned char min_best_l =
         (firstTripletLevel > min_level) ? firstTripletLevel + 2 : min_level + 3;  // loose maximum
 
 
       fvTrackCandidates.clear();
-      fvTrackCandidates.reserve(frWData.Hits().size() / 10);
+      fvTrackCandidates.reserve(wData.Hits().size() / 10);
 
-      for (const auto& h : frWData.Hits()) {
+      for (const auto& h : wData.Hits()) {
         fvHitKeyToTrack[h.FrontKey()] = -1;
         fvHitKeyToTrack[h.BackKey()]  = -1;
       }
 
       //== Loop over triplets with the required level, find and store track candidates
 
-      for (int istaF = iStFirst; istaF <= frAlgo.GetParameters().GetNstationsActive() - 3 - firstTripletLevel;
-           ++istaF) {
+      for (int istaF = iStFirst; istaF <= fParameters.GetNstationsActive() - 3 - firstTripletLevel; ++istaF) {
 
         if (--nlevel == 0) break;  //TODO: SG: this is not needed
 
         for (Tindex itrip = 0; itrip < (Tindex) fvTriplets[istaF].size(); ++itrip) {
 
           ca::Triplet& first_trip = (fvTriplets[istaF][itrip]);
-          const auto& fstTripLHit = frWData.Hit(first_trip.GetLHit());
-          if (frWData.IsHitKeyUsed(fstTripLHit.FrontKey()) || frWData.IsHitKeyUsed(fstTripLHit.BackKey())) {
+          const auto& fstTripLHit = wData.Hit(first_trip.GetLHit());
+          if (wData.IsHitKeyUsed(fstTripLHit.FrontKey()) || wData.IsHitKeyUsed(fstTripLHit.BackKey())) {
             continue;
           }
 
           //  skip track candidates that are too short
 
-          int minNhits = frWData.CurrentIteration()->GetMinNhits();
+          int minNhits = wData.CurrentIteration()->GetMinNhits();
 
           if (fstTripLHit.Station() == 0) {
-            minNhits = frWData.CurrentIteration()->GetMinNhitsStation0();
+            minNhits = wData.CurrentIteration()->GetMinNhitsStation0();
           }
-          if (frWData.CurrentIteration()->GetTrackFromTripletsFlag()) {
+          if (wData.CurrentIteration()->GetTrackFromTripletsFlag()) {
             minNhits = 0;
           }
 
@@ -482,8 +477,8 @@ void TrackFinderWindow::CaTrackFinderSlice()
 
           best_tr = curr_tr;
 
-          CAFindTrack(istaF, best_tr, &first_trip, curr_tr, min_best_l,
-                      new_tr);  /// reqursive func to build a tree of possible track-candidates and choose the best
+          /// reqursive func to build a tree of possible track-candidates and choose the best
+          CAFindTrack(istaF, best_tr, &first_trip, curr_tr, min_best_l, new_tr, wData);
 
           if (best_tr.NofHits() < firstTripletLevel + 2) continue;  // loose maximum one hit
 
@@ -497,17 +492,16 @@ void TrackFinderWindow::CaTrackFinderSlice()
 
           // TODO: automatize the NDF calculation
 
-          if (ca::Framework::TrackingMode::kGlobal == frAlgo.fTrackingMode
-              || ca::Framework::TrackingMode::kMcbm == frAlgo.fTrackingMode) {
+          if (ca::TrackingMode::kGlobal == fTrackingMode || ca::TrackingMode::kMcbm == fTrackingMode) {
             ndf = best_tr.NofHits() * 2 - 4;
           }
 
           best_tr.SetChi2(best_tr.Chi2() / ndf);
-          if (frAlgo.GetParameters().GetGhostSuppression()) {
+          if (fParameters.GetGhostSuppression()) {
             if (3 == best_tr.NofHits()) {
-              if (!frWData.CurrentIteration()->GetPrimaryFlag() && (istaF != 0))
+              if (!wData.CurrentIteration()->GetPrimaryFlag() && (istaF != 0))
                 continue;  // too /*short*/ non-MAPS track
-              if (frWData.CurrentIteration()->GetPrimaryFlag() && (best_tr.Chi2() > 5.0)) continue;
+              if (wData.CurrentIteration()->GetPrimaryFlag() && (best_tr.Chi2() > 5.0)) continue;
             }
           }
           fvTrackCandidates.push_back(best_tr);
@@ -517,10 +511,10 @@ void TrackFinderWindow::CaTrackFinderSlice()
           tr.SetAlive(true);
           if constexpr (fDebug) {
             std::stringstream s;
-            s << "iter " << frWData.CurrentIterationIndex() << ", track candidate " << fvTrackCandidates.size() - 1
+            s << "iter " << wData.CurrentIterationIndex() << ", track candidate " << fvTrackCandidates.size() - 1
               << " found, L = " << best_tr.NofHits() << " chi2= " << best_tr.Chi2() << " hits: ";
             for (auto hitId : tr.Hits()) {
-              s << hitId << " (mc " << frAlgo.GetMcTrackIdForCaHit(hitId) << ") ";
+              s << hitId << " (mc " << ca::Framework::GetMcTrackIdForCaHit(hitId) << ") ";
             }
             LOG(info) << s.str();
           }
@@ -545,7 +539,7 @@ void TrackFinderWindow::CaTrackFinderSlice()
             continue;
           }
           for (auto& hitId : tr.Hits()) {
-            const ca::Hit& h = frAlgo.fInputData.GetHit(hitId);
+            const ca::Hit& h = input.GetHit(hitId);
             bool isAlive     = true;
             {  // front  strip
               auto& stripF = fvHitKeyToTrack[h.FrontKey()];
@@ -596,14 +590,14 @@ void TrackFinderWindow::CaTrackFinderSlice()
 
           tr.SetAlive(true);
           for (int iHit = 0; tr.IsAlive() && (iHit < (int) tr.Hits().size()); ++iHit) {
-            const ca::Hit& h = frAlgo.fInputData.GetHit(tr.Hits()[iHit]);
+            const ca::Hit& h = input.GetHit(tr.Hits()[iHit]);
             tr.SetAlive(tr.IsAlive() && (fvHitKeyToTrack[h.FrontKey()] == tr.Id())
                         && (fvHitKeyToTrack[h.BackKey()] == tr.Id()));
           }
 
           if (!tr.IsAlive()) {  // release strips
             for (auto hitId : tr.Hits()) {
-              const ca::Hit& h = frAlgo.fInputData.GetHit(hitId);
+              const ca::Hit& h = input.GetHit(hitId);
               if (fvHitKeyToTrack[h.FrontKey()] == tr.Id()) {
                 fvHitKeyToTrack[h.FrontKey()] = -1;
               }
@@ -627,34 +621,34 @@ void TrackFinderWindow::CaTrackFinderSlice()
         ca::Branch& tr = fvTrackCandidates[iCandidate];
 
         if constexpr (fDebug) {
-          LOG(info) << "iter " << frWData.CurrentIterationIndex() << ", track candidate " << iCandidate
+          LOG(info) << "iter " << wData.CurrentIterationIndex() << ", track candidate " << iCandidate
                     << ": alive = " << tr.IsAlive();
         }
 
         if (!tr.IsAlive()) continue;
 
-        if (frWData.CurrentIteration()->GetExtendTracksFlag()) {
-          if (tr.NofHits() < frAlgo.GetParameters().GetNstationsActive()) {
-            fTrackExtender.ExtendBranch(tr);
+        if (wData.CurrentIteration()->GetExtendTracksFlag()) {
+          if (tr.NofHits() < fParameters.GetNstationsActive()) {
+            fTrackExtender.ExtendBranch(tr, input, wData);
           }
         }
 
         for (auto iHit : tr.Hits()) {
-          const ca::Hit& hit = frAlgo.fInputData.GetHit(iHit);
+          const ca::Hit& hit = input.GetHit(iHit);
           /// used strips are marked
-          frWData.IsHitKeyUsed(hit.FrontKey()) = 1;
-          frWData.IsHitKeyUsed(hit.BackKey())  = 1;
-          frWData.RecoHitIndices().push_back(iHit);
+          wData.IsHitKeyUsed(hit.FrontKey()) = 1;
+          wData.IsHitKeyUsed(hit.BackKey())  = 1;
+          wData.RecoHitIndices().push_back(iHit);
         }
         Track t;
         t.fNofHits = tr.NofHits();
-        frWData.RecoTracks().push_back(t);
+        wData.RecoTracks().push_back(t);
         if (0) {  // SG debug
           std::stringstream s;
           s << "store track " << iCandidate << " chi2= " << tr.Chi2() << "\n";
           s << " hits: ";
           for (unsigned int ih = 0; ih < tr.Hits().size(); ih++) {
-            s << frAlgo.GetMcTrackIdForCaHit(tr.Hits()[ih]) << " ";
+            s << ca::Framework::GetMcTrackIdForCaHit(tr.Hits()[ih]) << " ";
           }
           LOG(info) << s.str();
         }
@@ -666,11 +660,11 @@ void TrackFinderWindow::CaTrackFinderSlice()
 
     frMonitorData.StartTimer(ETimer::SuppressHitKeys);
     // suppress strips of suppressed hits
-    for (unsigned int ih = 0; ih < frWData.Hits().size(); ih++) {
-      if (frWData.IsHitSuppressed(ih)) {
-        const ca::Hit& hit                   = frWData.Hit(ih);
-        frWData.IsHitKeyUsed(hit.FrontKey()) = 1;
-        frWData.IsHitKeyUsed(hit.BackKey())  = 1;
+    for (unsigned int ih = 0; ih < wData.Hits().size(); ih++) {
+      if (wData.IsHitSuppressed(ih)) {
+        const ca::Hit& hit                 = wData.Hit(ih);
+        wData.IsHitKeyUsed(hit.FrontKey()) = 1;
+        wData.IsHitKeyUsed(hit.BackKey())  = 1;
       }
     }
     frMonitorData.StopTimer(ETimer::SuppressHitKeys);
@@ -679,16 +673,16 @@ void TrackFinderWindow::CaTrackFinderSlice()
 
   // Fit tracks
   frMonitorData.StartTimer(ETimer::FitTracks);
-  fTrackFitter.FitCaTracks();
+  fTrackFitter.FitCaTracks(input, wData);
   frMonitorData.StopTimer(ETimer::FitTracks);
 
   // Merge clones
   frMonitorData.StartTimer(ETimer::MergeClones);
-  fCloneMerger.Exec(frWData.RecoTracks(), frWData.RecoHitIndices());
+  fCloneMerger.Exec(input, wData);
   frMonitorData.StopTimer(ETimer::MergeClones);
 
   frMonitorData.StartTimer(ETimer::FitTracks);
-  fTrackFitter.FitCaTracks();
+  fTrackFitter.FitCaTracks(input, wData);
   frMonitorData.StopTimer(ETimer::FitTracks);
 }
 
@@ -703,7 +697,7 @@ void TrackFinderWindow::CaTrackFinderSlice()
      ****************************************************************/
 
 void TrackFinderWindow::CAFindTrack(int ista, ca::Branch& best_tr, const ca::Triplet* curr_trip, ca::Branch& curr_tr,
-                                    unsigned char min_best_l, ca::Branch* new_tr)
+                                    unsigned char min_best_l, ca::Branch* new_tr, WindowData& wData)
 /// recursive search for tracks
 /// input: @ista - station index, @&best_tr - best track for the privious call
 /// output: @&NCalls - number of function calls
@@ -713,14 +707,14 @@ void TrackFinderWindow::CAFindTrack(int ista, ca::Branch& best_tr, const ca::Tri
   {
     // -- finish with current track
     // add rest of hits
-    const auto& hitM = frWData.Hit(curr_trip->GetMHit());
-    const auto& hitR = frWData.Hit(curr_trip->GetRHit());
+    const auto& hitM = wData.Hit(curr_trip->GetMHit());
+    const auto& hitR = wData.Hit(curr_trip->GetRHit());
 
-    if (!(frWData.IsHitKeyUsed(hitM.FrontKey()) || frWData.IsHitKeyUsed(hitM.BackKey()))) {
+    if (!(wData.IsHitKeyUsed(hitM.FrontKey()) || wData.IsHitKeyUsed(hitM.BackKey()))) {
       curr_tr.AddHit(hitM.Id());
     }
 
-    if (!(frWData.IsHitKeyUsed(hitR.FrontKey()) || frWData.IsHitKeyUsed(hitR.BackKey()))) {
+    if (!(wData.IsHitKeyUsed(hitR.FrontKey()) || wData.IsHitKeyUsed(hitR.BackKey()))) {
       curr_tr.AddHit(hitR.Id());
     }
 
@@ -728,13 +722,12 @@ void TrackFinderWindow::CAFindTrack(int ista, ca::Branch& best_tr, const ca::Tri
     // TODO: SZh 21.08.2023: Replace hard-coded value with a parameter
     int ndf = curr_tr.NofHits() * 2 - 5;
 
-    if (ca::Framework::TrackingMode::kGlobal == frAlgo.fTrackingMode
-        || ca::Framework::TrackingMode::kMcbm == frAlgo.fTrackingMode) {
+    if (ca::TrackingMode::kGlobal == fTrackingMode || ca::TrackingMode::kMcbm == fTrackingMode) {
       ndf = curr_tr.NofHits() * 2 - 4;
     }
 
 
-    if (curr_tr.Chi2() > frWData.CurrentIteration()->GetTrackChi2Cut() * ndf) {
+    if (curr_tr.Chi2() > wData.CurrentIteration()->GetTrackChi2Cut() * ndf) {
       return;
     }
 
@@ -754,16 +747,16 @@ void TrackFinderWindow::CAFindTrack(int ista, ca::Branch& best_tr, const ca::Tri
 
       unsigned int ID = curr_trip->GetFNeighbour() + in;
 
-      unsigned int Station = frAlgo.TripletId2Station(ID);
-      unsigned int Triplet = frAlgo.TripletId2Triplet(ID);
+      unsigned int Station = TripletId2Station(ID);
+      unsigned int Triplet = TripletId2Triplet(ID);
 
       const ca::Triplet& new_trip = fvTriplets[Station][Triplet];
 
       fscal dchi2 = 0.;
-      if (!checkTripletMatch(*curr_trip, new_trip, dchi2)) continue;
+      if (!checkTripletMatch(*curr_trip, new_trip, dchi2, wData)) continue;
 
-      const auto& hitL = frWData.Hit(new_trip.GetLHit());                                   // left hit of new triplet
-      if (frWData.IsHitKeyUsed(hitL.FrontKey()) || frWData.IsHitKeyUsed(hitL.BackKey())) {  //hits are used
+      const auto& hitL = wData.Hit(new_trip.GetLHit());                                 // left hit of new triplet
+      if (wData.IsHitKeyUsed(hitL.FrontKey()) || wData.IsHitKeyUsed(hitL.BackKey())) {  //hits are used
         //  no used hits allowed -> compare and store track
         if ((curr_tr.NofHits() > best_tr.NofHits())
             || ((curr_tr.NofHits() == best_tr.NofHits()) && (curr_tr.Chi2() < best_tr.Chi2()))) {
@@ -777,12 +770,13 @@ void TrackFinderWindow::CAFindTrack(int ista, ca::Branch& best_tr, const ca::Tri
 
 
         if constexpr (0) {  //SGtrd2d debug!!
-          int mc01 = frAlgo.GetMcTrackIdForWindowHit(curr_trip->GetLHit());
-          int mc02 = frAlgo.GetMcTrackIdForWindowHit(curr_trip->GetMHit());
-          int mc03 = frAlgo.GetMcTrackIdForWindowHit(curr_trip->GetRHit());
-          int mc11 = frAlgo.GetMcTrackIdForWindowHit(new_trip.GetLHit());
-          int mc12 = frAlgo.GetMcTrackIdForWindowHit(new_trip.GetMHit());
-          int mc13 = frAlgo.GetMcTrackIdForWindowHit(new_trip.GetRHit());
+          int mc01 = ca::Framework::GetMcTrackIdForWindowHit(curr_trip->GetLHit());
+          int mc02 = ca::Framework::GetMcTrackIdForWindowHit(curr_trip->GetMHit());
+          int mc03 = ca::Framework::GetMcTrackIdForWindowHit(curr_trip->GetRHit());
+          int mc11 = ca::Framework::GetMcTrackIdForWindowHit(new_trip.GetLHit());
+          int mc12 = ca::Framework::GetMcTrackIdForWindowHit(new_trip.GetMHit());
+          int mc13 = ca::Framework::GetMcTrackIdForWindowHit(new_trip.GetRHit());
+
           if ((mc01 == mc02) && (mc02 == mc03)) {
             LOG(info) << " sta " << ista << " mc0 " << mc01 << " " << mc02 << " " << mc03 << " mc1 " << mc11 << " "
                       << mc12 << " " << mc13 << " chi2 " << curr_tr.Chi2() / (2 * (curr_tr.NofHits() + 2) - 4)
@@ -794,17 +788,17 @@ void TrackFinderWindow::CAFindTrack(int ista, ca::Branch& best_tr, const ca::Tri
 
         int ndf = 2 * (new_L + 2) - 5;
 
-        if (ca::Framework::TrackingMode::kGlobal == frAlgo.fTrackingMode) {  //SGtrd2d!!!
+        if (ca::TrackingMode::kGlobal == fTrackingMode) {  //SGtrd2d!!!
           ndf = 2 * (new_L + 2) - 4;
         }
-        else if (ca::Framework::TrackingMode::kMcbm == frAlgo.fTrackingMode) {
+        else if (ca::TrackingMode::kMcbm == fTrackingMode) {
           ndf = 2 * (new_L + 2) - 4;
         }
         else {
           ndf = new_L;  // TODO: SG:  2 * (new_L + 2) - 5
         }
 
-        if (new_chi2 > frWData.CurrentIteration()->GetTrackChi2Cut() * ndf) continue;
+        if (new_chi2 > wData.CurrentIteration()->GetTrackChi2Cut() * ndf) continue;
 
         // add new hit
         new_tr[ista] = curr_tr;
@@ -813,7 +807,7 @@ void TrackFinderWindow::CAFindTrack(int ista, ca::Branch& best_tr, const ca::Tri
         const int new_ista = ista + new_trip.GetMSta() - new_trip.GetLSta();
         new_tr[ista].SetChi2(new_chi2);
 
-        CAFindTrack(new_ista, best_tr, &new_trip, new_tr[ista], min_best_l, new_tr);
+        CAFindTrack(new_ista, best_tr, &new_trip, new_tr[ista], min_best_l, new_tr, wData);
       }  // add triplet to track
     }    // for neighbours
   }      // level = 0
diff --git a/algo/ca/core/tracking/CaTrackFinderWindow.h b/algo/ca/core/tracking/CaTrackFinderWindow.h
index d26cb0000c..5e6aa450a0 100644
--- a/algo/ca/core/tracking/CaTrackFinderWindow.h
+++ b/algo/ca/core/tracking/CaTrackFinderWindow.h
@@ -38,8 +38,8 @@ namespace cbm::algo::ca
   class TrackFinderWindow {
    public:
     /// Default constructor
-    TrackFinderWindow(ca::Framework& algo, ca::WindowData& wData, ca::TrackingMonitorData& monitorData);
-
+    TrackFinderWindow(const ca::Parameters<fvec>& pars, const float mass, const ca::TrackingMode& mode,
+                      ca::TrackingMonitorData& monitorData);
     /// Destructor
     ~TrackFinderWindow();
 
@@ -55,20 +55,37 @@ namespace cbm::algo::ca
     /// Move assignment operator
     TrackFinderWindow& operator=(TrackFinderWindow&&) = delete;
 
-    void ReadWindowData();
-    void CaTrackFinderSlice();
-
-    void CAFindTrack(int ista, ca::Branch& best_tr, const ca::Triplet* curr_trip, ca::Branch& curr_tr,
-                     unsigned char min_best_l, ca::Branch* new_tr);
+    void CaTrackFinderSlice(const ca::InputData& input, WindowData& wData);
 
     /// \note The function initializes global arrays for a given thread
-    void InitTimeslice();
+    void InitTimeslice(size_t nHitKeys) { fvHitKeyToTrack.reset(nHitKeys, -1); }
 
    private:
     ///-------------------------------
     /// Private methods
 
-    bool checkTripletMatch(const ca::Triplet& l, const ca::Triplet& r, fscal& dchi2) const;
+    void ReadWindowData(const ca::InputData& input, WindowData& wData);
+
+    void CAFindTrack(int ista, ca::Branch& best_tr, const ca::Triplet* curr_trip, ca::Branch& curr_tr,
+                     unsigned char min_best_l, ca::Branch* new_tr, WindowData& wData);
+
+    bool checkTripletMatch(const ca::Triplet& l, const ca::Triplet& r, fscal& dchi2, WindowData& wData) const;
+
+    // ** Functions, which pack and unpack indexes of station and triplet **
+
+    // TODO: move to ca::Triplet class (S.Zharko)
+    /// Packs station and triplet indices to an unique triplet ID
+    /// \param  iStation  Index of station in the active stations array
+    /// \param  iTriplet  Index of triplet
+    static unsigned int PackTripletId(unsigned int iStation, unsigned int iTriplet);
+
+    /// Unpacks the triplet ID to its station index
+    /// \param  id  Unique triplet ID
+    static unsigned int TripletId2Station(unsigned int id);
+
+    /// Unpacks the triplet ID to its triplet index
+    /// \param  id  Unique triplet ID
+    static unsigned int TripletId2Triplet(unsigned int id);
 
 
    private:
@@ -82,20 +99,53 @@ namespace cbm::algo::ca
     /// \note  The candidates may share any amount of hits.
     Vector<ca::Branch> fvTrackCandidates{"TrackFinderWindow::fTrackCandidates"};
 
-    Vector<int> fvHitFirstTriplet{"TrackFinderWindow::fvHitFirstTriplet"};  /// link hit -> first triplet { hit, *, *}
-    Vector<int> fvHitNofTriplets{"TrackFinderWindow::fvHitNofTriplets"};    /// link hit ->n triplets { hit, *, *}
-
     /// \note Global array for a given thread
     Vector<int> fvHitKeyToTrack{"TrackFinderWindow::fvHitKeyToTrack"};
 
-    ca::Framework& frAlgo;                 ///< Reference to the main track finder algorithm class
     static constexpr bool fDebug = false;  // print debug info
 
-    WindowData& frWData;
+    const Parameters<fvec>& fParameters;            ///< Object of Framework parameters class
+    float fDefaultMass{constants::phys::MuonMass};  ///< mass of the propagated particle [GeV/c2]
+    ca::TrackingMode fTrackingMode;
+
     TrackingMonitorData& frMonitorData;  ///< Reference to monitor data
-    TrackExtender fTrackExtender;  ///< Object of the track extender algorithm
-    CloneMerger fCloneMerger;      ///< Object of  the clone merger algorithm
-    TrackFitter fTrackFitter;      ///< Object of the track extender algorithm
+    TrackExtender fTrackExtender;        ///< Object of the track extender algorithm
+    CloneMerger fCloneMerger;            ///< Object of  the clone merger algorithm
+    TrackFitter fTrackFitter;            ///< Object of the track extender algorithm
   };
 
+  // ********************************************
+  // ** Inline member functions implementation **
+  // ********************************************
+
+  // ---------------------------------------------------------------------------------------------------------------------
+  //
+  [[gnu::always_inline]] inline unsigned int TrackFinderWindow::PackTripletId(unsigned int iStation,
+                                                                              unsigned int iTriplet)
+  {
+#ifndef FAST_CODE
+    assert(iStation < constants::size::MaxNstations);
+    assert(iTriplet < constants::size::MaxNtriplets);
+#endif
+    constexpr unsigned int kMoveStation = constants::size::TripletBits;
+    return (iStation << kMoveStation) + iTriplet;
+  }
+
+  // ---------------------------------------------------------------------------------------------------------------------
+  //
+  [[gnu::always_inline]] inline unsigned int TrackFinderWindow::TripletId2Station(unsigned int id)
+  {
+    constexpr unsigned int kMoveStation = constants::size::TripletBits;
+    return id >> kMoveStation;
+  }
+
+  // ---------------------------------------------------------------------------------------------------------------------
+  //
+  [[gnu::always_inline]] inline unsigned int TrackFinderWindow::TripletId2Triplet(unsigned int id)
+  {
+    constexpr unsigned int kTripletMask = (1u << constants::size::TripletBits) - 1u;
+    return id & kTripletMask;
+  }
+
+
 }  // namespace cbm::algo::ca
diff --git a/algo/ca/core/tracking/CaTrackFitter.cxx b/algo/ca/core/tracking/CaTrackFitter.cxx
index 26a0f22a15..00a599fb12 100644
--- a/algo/ca/core/tracking/CaTrackFitter.cxx
+++ b/algo/ca/core/tracking/CaTrackFitter.cxx
@@ -20,7 +20,12 @@ using namespace cbm::algo;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-TrackFitter::TrackFitter(ca::Framework& algo, WindowData& wData) : frAlgo(algo), frWData(wData) {}
+TrackFitter::TrackFitter(const ca::Parameters<fvec>& pars, const float mass, const ca::TrackingMode& mode)
+  : fParameters(pars)
+  , fDefaultMass(mass)
+  , fTrackingMode(mode)
+{
+}
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
@@ -28,10 +33,10 @@ TrackFitter::~TrackFitter() {}
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-void TrackFitter::FitCaTracks()
+void TrackFitter::FitCaTracks(const ca::InputData& input, WindowData& wData)
 {
   //  LOG(info) << " Start CA Track Fitter ";
-  int start_hit = 0;  // for interation in frWData.RecoHitIndices()
+  int start_hit = 0;  // for interation in wData.RecoHitIndices()
 
   //  static ca::FieldValue fldB0, fldB1, fldB2 _fvecalignment;
   //  static ca::FieldRegion fld _fvecalignment;
@@ -42,17 +47,17 @@ void TrackFitter::FitCaTracks()
   ca::FieldValue<fvec> fldB01, fldB11, fldB21 _fvecalignment;
   ca::FieldRegion<fvec> fld1 _fvecalignment;
 
-  const int nStations = frAlgo.GetParameters().GetNstationsActive();
+  const int nStations = fParameters.GetNstationsActive();
   int nTracks_SIMD    = fvec::size();
 
   ca::TrackFit fit;  // fit parameters coresponding to the current track
   TrackParamV& tr = fit.Tr();
-  fit.SetParticleMass(frAlgo.GetDefaultParticleMass());
+  fit.SetParticleMass(fDefaultMass);
   fit.SetDoFitVelocity(true);
 
   Track* t[fvec::size()]{nullptr};
 
-  const ca::Station<fvec>* sta = frAlgo.GetParameters().GetStations().begin();
+  const ca::Station<fvec>* sta = fParameters.GetStations().begin();
 
   // Spatial-time position of a hit vs. station and track in the portion
 
@@ -102,19 +107,19 @@ void TrackFitter::FitCaTracks()
     mxy[ista].SetCov(1., 0., 1.);
   }
 
-  unsigned short N_vTracks = frWData.RecoTracks().size();  // number of tracks processed per one SSE register
+  unsigned short N_vTracks = wData.RecoTracks().size();  // number of tracks processed per one SSE register
 
   for (unsigned short itrack = 0; itrack < N_vTracks; itrack += fvec::size()) {
 
     if (N_vTracks - itrack < static_cast<unsigned short>(fvec::size())) nTracks_SIMD = N_vTracks - itrack;
 
     for (int i = 0; i < nTracks_SIMD; i++) {
-      t[i] = &frWData.RecoTrack(itrack + i);
+      t[i] = &wData.RecoTrack(itrack + i);
     }
 
     // fill the rest of the SIMD vectors with something reasonable
     for (uint i = nTracks_SIMD; i < fvec::size(); i++) {
-      t[i] = &frWData.RecoTrack(itrack);
+      t[i] = &wData.RecoTrack(itrack);
     }
 
     // get hits of current track
@@ -133,7 +138,7 @@ void TrackFitter::FitCaTracks()
 
       for (int ih = 0; ih < nHitsTrack; ih++) {
 
-        const ca::Hit& hit = frAlgo.GetInputData().GetHit(frWData.RecoHitIndex(start_hit++));
+        const ca::Hit& hit = input.GetHit(wData.RecoHitIndex(start_hit++));
         const int ista     = hit.Station();
 
         //if (sta[ista].fieldStatus) { isFieldPresent[iVec] = true; }
@@ -197,16 +202,15 @@ void TrackFitter::FitCaTracks()
       }
 
       for (int ih = nHitsTrack - 1; ih >= 0; ih--) {
-        const int ista         = iSta[ih];
-        const ca::Station<fvec>& st = frAlgo.GetParameters().GetStation(ista);
-        By[ista][iVec]         = st.fieldSlice.cy[0][0];
+        const int ista              = iSta[ih];
+        const ca::Station<fvec>& st = fParameters.GetStation(ista);
+        By[ista][iVec]              = st.fieldSlice.cy[0][0];
       }
     }
 
     fit.GuessTrack(z_end, x, y, z, time, By, w, w_time, nStations);
 
-    if (ca::Framework::TrackingMode::kGlobal == frAlgo.fTrackingMode
-        || ca::Framework::TrackingMode::kMcbm == frAlgo.fTrackingMode) {
+    if (ca::TrackingMode::kGlobal == fTrackingMode || ca::TrackingMode::kMcbm == fTrackingMode) {
       tr.Qp() = fvec(1. / 1.1);
     }
 
@@ -259,8 +263,8 @@ void TrackFitter::FitCaTracks()
 
         fit.SetMask(initialised);
         fit.Extrapolate(z[ista], fld1);
-        fit.MultipleScattering(frAlgo.GetParameters().GetMaterialThickness(ista, tr.X(), tr.Y()));
-        fit.EnergyLossCorrection(frAlgo.GetParameters().GetMaterialThickness(ista, tr.X(), tr.Y()), fvec(1.f));
+        fit.MultipleScattering(fParameters.GetMaterialThickness(ista, tr.X(), tr.Y()));
+        fit.EnergyLossCorrection(fParameters.GetMaterialThickness(ista, tr.X(), tr.Y()), fvec(1.f));
 
         fit.SetMask(initialised && w[ista]);
         fit.FilterXY(mxy[ista]);
@@ -279,12 +283,12 @@ void TrackFitter::FitCaTracks()
       {
         fitpv.SetMask(fmask::One());
 
-        ca::MeasurementXy<fvec> vtxInfo = frWData.TargetMeasurement();
+        ca::MeasurementXy<fvec> vtxInfo = wData.TargetMeasurement();
         vtxInfo.SetDx2(1.e-8);
         vtxInfo.SetDxy(0.);
         vtxInfo.SetDy2(1.e-8);
 
-        if (ca::Framework::TrackingMode::kGlobal == frAlgo.fTrackingMode) {
+        if (ca::TrackingMode::kGlobal == fTrackingMode) {
           ca::FieldRegion<fvec> fldFull _fvecalignment;
           fldFull.SetUseOriginalField(true);
           fitpv.SetMaxExtrapolationStep(1.);
@@ -292,13 +296,13 @@ void TrackFitter::FitCaTracks()
             fitpv.SetQp0(fitpv.Tr().Qp());
             fitpv.Tr()      = fit.Tr();
             fitpv.Tr().Qp() = fitpv.Qp0();
-            fitpv.Extrapolate(frAlgo.GetParameters().GetTargetPositionZ(), fldFull);
+            fitpv.Extrapolate(fParameters.GetTargetPositionZ(), fldFull);
             fitpv.FilterXY(vtxInfo);
           }
         }
         else {
           fitpv.SetQp0(fitpv.Tr().Qp());
-          fitpv.Extrapolate(frAlgo.GetParameters().GetTargetPositionZ(), fld);
+          fitpv.Extrapolate(fParameters.GetTargetPositionZ(), fld);
         }
       }
 
@@ -308,7 +312,7 @@ void TrackFitter::FitCaTracks()
       //fit.FilterVi(TrackParamV::kClightNsInv);
 
       TrackParamV Tf = fit.Tr();
-      if (ca::Framework::TrackingMode::kGlobal == frAlgo.fTrackingMode) {
+      if (ca::TrackingMode::kGlobal == fTrackingMode) {
         Tf.Qp() = fitpv.Tr().Qp();
       }
 
@@ -363,8 +367,8 @@ void TrackFitter::FitCaTracks()
 
         fit.SetMask(initialised);
         fit.Extrapolate(z[ista], fld);
-        fit.MultipleScattering(frAlgo.GetParameters().GetMaterialThickness(ista, tr.X(), tr.Y()));
-        fit.EnergyLossCorrection(frAlgo.GetParameters().GetMaterialThickness(ista, tr.X(), tr.Y()), fvec(-1.f));
+        fit.MultipleScattering(fParameters.GetMaterialThickness(ista, tr.X(), tr.Y()));
+        fit.EnergyLossCorrection(fParameters.GetMaterialThickness(ista, tr.X(), tr.Y()), fvec(-1.f));
         fit.SetMask(initialised && w[ista]);
         fit.FilterXY(mxy[ista]);
         fit.FilterTime(time[ista], dt2[ista], sta[ista].timeInfo);
@@ -381,7 +385,7 @@ void TrackFitter::FitCaTracks()
       //fit.FilterVi(TrackParamV::kClightNsInv);
 
       TrackParamV Tl = fit.Tr();
-      if (ca::Framework::TrackingMode::kGlobal == frAlgo.fTrackingMode) {
+      if (ca::TrackingMode::kGlobal == fTrackingMode) {
         Tl.Qp() = fitpv.Tr().Qp();
       }
 
diff --git a/algo/ca/core/tracking/CaTrackFitter.h b/algo/ca/core/tracking/CaTrackFitter.h
index 2b451763b3..d452716908 100644
--- a/algo/ca/core/tracking/CaTrackFitter.h
+++ b/algo/ca/core/tracking/CaTrackFitter.h
@@ -10,6 +10,8 @@
 
 #include "CaBranch.h"
 #include "CaHit.h"
+#include "CaInputData.h"
+#include "CaParameters.h"
 #include "CaSimd.h"
 #include "CaTrackParam.h"
 #include "CaVector.h"
@@ -19,20 +21,18 @@
 namespace cbm::algo::ca
 {
   class Track;
-  class Framework;
 
   namespace
   {
     using namespace cbm::algo;  // to keep ca:: prefices in the code
   }
 
-
   /// Class implements a track fit the CA track finder
   ///
   class TrackFitter {
    public:
     /// Default constructor
-    TrackFitter(ca::Framework& algo, WindowData& wData);
+    TrackFitter(const ca::Parameters<fvec>& pars, const float mass, const ca::TrackingMode& mode);
 
     /// Destructor
     ~TrackFitter();
@@ -49,20 +49,17 @@ namespace cbm::algo::ca
     /// Move assignment operator
     TrackFitter& operator=(TrackFitter&&) = delete;
 
-
     /// Fit tracks, found by the CA tracker
-    void FitCaTracks();
+    void FitCaTracks(const ca::InputData& input, WindowData& wData);
 
-   private:
-    ///-------------------------------
-    /// Private methods
 
    private:
     ///-------------------------------
     /// Data members
 
-    ca::Framework& frAlgo;  ///< Reference to the main track finder algorithm class
-    ca::WindowData& frWData;
+    const Parameters<fvec>& fParameters;            ///< Object of Framework parameters class
+    float fDefaultMass{constants::phys::MuonMass};  ///< mass of the propagated particle [GeV/c2]
+    ca::TrackingMode fTrackingMode;
   };
 
 }  // namespace cbm::algo::ca
diff --git a/algo/ca/core/tracking/CaTripletConstructor.cxx b/algo/ca/core/tracking/CaTripletConstructor.cxx
index 9476f0f8d6..e10dea41f4 100644
--- a/algo/ca/core/tracking/CaTripletConstructor.cxx
+++ b/algo/ca/core/tracking/CaTripletConstructor.cxx
@@ -19,7 +19,26 @@
 
 using namespace cbm::algo::ca;
 
-TripletConstructor::TripletConstructor(ca::Framework& algo, WindowData& wData) : frAlgo(algo), frWData(wData) {}
+TripletConstructor::TripletConstructor(const ca::Parameters<fvec>& pars, const ca::InputData& input, WindowData& wData,
+                                       const float mass, const ca::TrackingMode& mode)
+  : fParameters(pars)
+  , fInputData(input)
+  , frWData(wData)
+  , fDefaultMass(mass)
+  , fTrackingMode(mode)
+{
+  // FIXME: SZh 24.08.2022
+  //        This approach is suitable only for a case, when all the stations inside a magnetic field come right before
+  //        all the stations outside of the field!
+  fNfieldStations = std::lower_bound(fParameters.GetStations().cbegin(),
+                                     fParameters.GetStations().cbegin() + fParameters.GetNstationsActive(),
+                                     0,  // we are looking for the first zero element
+                                     [](const ca::Station<fvec>& s, int edge) { return bool(s.fieldStatus) > edge; })
+                    - fParameters.GetStations().cbegin();
+
+  fIsTargetField = (fabs(frWData.TargB().y[0]) > 0.001);
+}
+
 
 void TripletConstructor::InitStations(int istal, int istam, int istar)
 {
@@ -29,29 +48,29 @@ void TripletConstructor::InitStations(int istal, int istam, int istar)
   fIstaM = istam;
   fIstaR = istar;
 
-  if (fIstaM >= frAlgo.fParameters.GetNstationsActive()) {
+  if (fIstaM >= fParameters.GetNstationsActive()) {
     return;
   }
 
-  fStaL = &frAlgo.fParameters.GetStation(fIstaL);
-  fStaM = &frAlgo.fParameters.GetStation(fIstaM);
-  fStaR = &frAlgo.fParameters.GetStation(fIstaR);
+  fStaL = &fParameters.GetStation(fIstaL);
+  fStaM = &fParameters.GetStation(fIstaM);
+  fStaR = &fParameters.GetStation(fIstaR);
 
 
   {  // two stations for approximating the field between the target and the left hit
     int sta1 = fIstaL;
-    if (sta1 >= frAlgo.fNfieldStations) {
-      sta1 = frAlgo.fNfieldStations - 1;
+    if (sta1 >= fNfieldStations) {
+      sta1 = fNfieldStations - 1;
     }
     if (sta1 < 1) {
       sta1 = 1;
     }
     int sta0 = sta1 / 2;  // station between fIstaL and the target
 
-    assert(0 <= sta0 && sta0 < sta1 && sta1 < frAlgo.fParameters.GetNstationsActive());
+    assert(0 <= sta0 && sta0 < sta1 && sta1 < fParameters.GetNstationsActive());
 
-    fFld0Sta[0] = &frAlgo.fParameters.GetStation(sta0);
-    fFld0Sta[1] = &frAlgo.fParameters.GetStation(sta1);
+    fFld0Sta[0] = &fParameters.GetStation(sta0);
+    fFld0Sta[1] = &fParameters.GetStation(sta1);
   }
 
   {  // three stations for approximating the field between the left and the right hit
@@ -59,7 +78,7 @@ void TripletConstructor::InitStations(int istal, int istam, int istar)
     int sta0 = fIstaL;
     int sta1 = fIstaM;
     int sta2 = fIstaM + 1;
-    if (sta2 >= frAlgo.fParameters.GetNstationsActive()) {
+    if (sta2 >= fParameters.GetNstationsActive()) {
       sta2 = fIstaM;
       sta1 = fIstaM - 1;
       if (sta0 >= sta1) {
@@ -69,16 +88,16 @@ void TripletConstructor::InitStations(int istal, int istam, int istar)
         sta0 = 0;
       }
     }
-    if (frAlgo.fParameters.GetNstationsActive() >= 3) {
-      assert(0 <= sta0 && sta0 < sta1 && sta1 < sta2 && sta2 < frAlgo.fParameters.GetNstationsActive());
+    if (fParameters.GetNstationsActive() >= 3) {
+      assert(0 <= sta0 && sta0 < sta1 && sta1 < sta2 && sta2 < fParameters.GetNstationsActive());
     }
 
-    fFld1Sta[0] = &frAlgo.fParameters.GetStation(sta0);
-    fFld1Sta[1] = &frAlgo.fParameters.GetStation(sta1);
-    fFld1Sta[2] = &frAlgo.fParameters.GetStation(sta2);
+    fFld1Sta[0] = &fParameters.GetStation(sta0);
+    fFld1Sta[1] = &fParameters.GetStation(sta1);
+    fFld1Sta[2] = &fParameters.GetStation(sta2);
   }
 
-  fFit.SetParticleMass(frAlgo.GetDefaultParticleMass());
+  fFit.SetParticleMass(fDefaultMass);
   if (frWData.CurrentIteration()->GetElectronFlag()) {
     fFit.SetParticleMass(constants::phys::ElectronMass);
   }
@@ -95,7 +114,7 @@ void TripletConstructor::CreateTripletsForHit(int istal, int istam, int istar, c
 
   if (!fIsInitialized) return;
 
-  fIhitL        = iHitL;
+  fIhitL           = iHitL;
   const auto& hitl = frWData.Hit(fIhitL);
 
   // fit a straight line through the target and the left hit.
@@ -117,10 +136,10 @@ void TripletConstructor::CreateTripletsForHit(int istal, int istam, int istar, c
     fvec zl         = hitl.Z();
     fvec time       = hitl.T();
     fvec timeEr2    = hitl.dT2();
-    const fvec dzli = 1.f / (zl - frAlgo.GetParameters().GetTargetPositionZ());
+    const fvec dzli = 1.f / (zl - fParameters.GetTargetPositionZ());
 
-    const fvec tx = (xl - frAlgo.GetParameters().GetTargetPositionX()) * dzli;
-    const fvec ty = (yl - frAlgo.GetParameters().GetTargetPositionY()) * dzli;
+    const fvec tx = (xl - fParameters.GetTargetPositionX()) * dzli;
+    const fvec ty = (yl - fParameters.GetTargetPositionY()) * dzli;
 
     TrackParamV& T = fFit.Tr();
 
@@ -157,7 +176,7 @@ void TripletConstructor::CreateTripletsForHit(int istal, int istam, int istar, c
     {
       ca::FieldValue<fvec> B0 = fFld0Sta[0]->fieldSlice.GetFieldValueForLine(T);
       ca::FieldValue<fvec> B1 = fFld0Sta[1]->fieldSlice.GetFieldValueForLine(T);
-      fld0.Set(frWData.TargB(), frAlgo.GetParameters().GetTargetPositionZ(), B0, fFld0Sta[0]->fZ, B1, fFld0Sta[1]->fZ);
+      fld0.Set(frWData.TargB(), fParameters.GetTargetPositionZ(), B0, fFld0Sta[0]->fZ, B1, fFld0Sta[1]->fZ);
     }
 
     {  // field, made by the left hit, the middle station and the right station
@@ -170,9 +189,9 @@ void TripletConstructor::CreateTripletsForHit(int istal, int istam, int istar, c
 
     // add the target constraint
 
-    fFit.FilterWithTargetAtLine(frAlgo.GetParameters().GetTargetPositionZ(), frWData.TargetMeasurement(), fld0);
+    fFit.FilterWithTargetAtLine(fParameters.GetTargetPositionZ(), frWData.TargetMeasurement(), fld0);
 
-    fFit.MultipleScattering(frAlgo.fParameters.GetMaterialThickness(fIstaL, T.GetX(), T.GetY()));
+    fFit.MultipleScattering(fParameters.GetMaterialThickness(fIstaL, T.GetX(), T.GetY()));
 
     // extrapolate to the middle hit
 
@@ -190,17 +209,16 @@ void TripletConstructor::CreateTripletsForHit(int istal, int istam, int istar, c
 void TripletConstructor::FindDoublets()
 {
   /// Find the doublets. Reformat data into portions of doublets.
-
   int iMC = -1;
-  if (frAlgo.fParameters.DevIsMatchDoubletsViaMc()) {
-    iMC = frAlgo.GetMcTrackIdForWindowHit(fIhitL);
+  if (fParameters.DevIsMatchDoubletsViaMc()) {
+    iMC = ca::Framework::GetMcTrackIdForWindowHit(fIhitL);
     if (iMC < 0) {
       return;
     }
   }
 
   CollectHits(fTrL, fIstaM, frWData.CurrentIteration()->GetDoubletChi2Cut(), iMC, fHitsM_2,
-              frAlgo.fParameters.GetMaxDoubletsPerSinglet());
+              fParameters.GetMaxDoubletsPerSinglet());
 }
 
 
@@ -215,7 +233,7 @@ void TripletConstructor::FitDoublets()
   fTracks_2.clear();
   fTracks_2.reserve(hitsMtmp.size());
 
-  bool isMomentumFitted = (frAlgo.fIsTargetField || (staL().fieldStatus != 0) || (staM().fieldStatus != 0));
+  bool isMomentumFitted = (fIsTargetField || (staL().fieldStatus != 0) || (staM().fieldStatus != 0));
 
   double maxQp = frWData.CurrentIteration()->GetMaxQp();
   for (unsigned int i2 = 0; i2 < hitsMtmp.size(); i2++) {
@@ -246,12 +264,12 @@ void TripletConstructor::FitDoublets()
 
     fFit.SetQp0(isMomentumFitted ? fFit.Tr().GetQp() : maxQp);
 
-    fFit.MultipleScattering(frAlgo.fParameters.GetMaterialThickness(fIstaM, T2.GetX(), T2.Y()));
+    fFit.MultipleScattering(fParameters.GetMaterialThickness(fIstaM, T2.GetX(), T2.Y()));
 
     fFit.SetQp0(fFit.Tr().Qp());
 
     // check if there are other hits close to the doublet on the same station
-    if (ca::Framework::kMcbm != frAlgo.fTrackingMode) {
+    if (ca::kMcbm != fTrackingMode) {
       // TODO: SG: adjust cuts, put them to parameters
 
       fscal tx = T2.Tx()[0];
@@ -282,12 +300,14 @@ void TripletConstructor::FitDoublets()
           continue;
         }
 
-        if (frAlgo.fParameters.DevIsSuppressOverlapHitsViaMc()) {
-          int iMC = frAlgo.GetMcTrackIdForWindowHit(fIhitL);
-          if ((iMC != frAlgo.GetMcTrackIdForWindowHit(indM)) || (iMC != frAlgo.GetMcTrackIdForWindowHit(indClone))) {
+        if (fParameters.DevIsSuppressOverlapHitsViaMc()) {
+          int iMC = ca::Framework::GetMcTrackIdForWindowHit(fIhitL);
+          if ((iMC != ca::Framework::GetMcTrackIdForWindowHit(indM))
+              || (iMC != ca::Framework::GetMcTrackIdForWindowHit(indClone))) {
             continue;
           }
         }
+
         frWData.SuppressHit(indClone);
       }
     }
@@ -300,7 +320,7 @@ void TripletConstructor::FitDoublets()
 
 void TripletConstructor::FindTriplets()
 {
-  if (fIstaR >= frAlgo.fParameters.GetNstationsActive()) {
+  if (fIstaR >= fParameters.GetNstationsActive()) {
     return;
   }
   FindRightHit();
@@ -317,10 +337,10 @@ void TripletConstructor::FindRightHit()
 
   fFit.SetQp0(fvec(0.));
 
-  if (fIstaR >= frAlgo.fParameters.GetNstationsActive()) return;
+  if (fIstaR >= fParameters.GetNstationsActive()) return;
 
   {
-    int maxTriplets = fHitsM_2.size() * frAlgo.fParameters.GetMaxTripletPerDoublets();
+    int maxTriplets = fHitsM_2.size() * fParameters.GetMaxTripletPerDoublets();
     fHitsM_3.clear();
     fHitsR_3.clear();
     fHitsM_3.reserve(maxTriplets);
@@ -345,8 +365,8 @@ void TripletConstructor::FindRightHit()
 
       int ih0           = ihit[0];
       int ih1           = ihit[1];
-      const ca::Hit& h0 = frAlgo.fInputData.GetHit(ih0);
-      const ca::Hit& h1 = frAlgo.fInputData.GetHit(ih1);
+      const ca::Hit& h0 = fInputData.GetHit(ih0);
+      const ca::Hit& h1 = fInputData.GetHit(ih1);
 
       LOG(info) << "\n======  Extrapolated Doublet : "
                 << "  iter " << frWData.CurrentIteration()->GetName() << " hits: {" << fIstaL << "/" << ih0 << " "
@@ -360,7 +380,7 @@ void TripletConstructor::FindRightHit()
     bool isDoubletGood = false;
     int iMC            = -1;
     do {
-      if (frAlgo.kSts == frAlgo.fTrackingMode && (T2.C44()[0] < 0)) {
+      if (ca::TrackingMode::kSts == fTrackingMode && (T2.C44()[0] < 0)) {
         break;
       }
       if (T2.C00()[0] < 0 || T2.C11()[0] < 0 || T2.C22()[0] < 0 || T2.C33()[0] < 0 || T2.C55()[0] < 0) {
@@ -372,10 +392,10 @@ void TripletConstructor::FindRightHit()
       if (fabs(T2.Ty()[0]) > maxSlope) {
         break;
       }
-      if (frAlgo.fParameters.DevIsMatchTripletsViaMc()) {
+      if (fParameters.DevIsMatchTripletsViaMc()) {
         int indM = fHitsM_2[i2];
-        iMC      = frAlgo.GetMcTrackIdForWindowHit(fIhitL);
-        if (iMC < 0 || iMC != frAlgo.GetMcTrackIdForWindowHit(indM)) {
+        iMC      = ca::Framework::GetMcTrackIdForWindowHit(fIhitL);
+        if (iMC < 0 || iMC != ca::Framework::GetMcTrackIdForWindowHit(indM)) {
           break;
         }
       }
@@ -397,10 +417,10 @@ void TripletConstructor::FindRightHit()
     }
 
     Vector<ca::HitIndex_t> collectedHits;
-    CollectHits(T2, fIstaR, tripletChi2Cut, iMC, collectedHits, frAlgo.fParameters.GetMaxTripletPerDoublets());
+    CollectHits(T2, fIstaR, tripletChi2Cut, iMC, collectedHits, fParameters.GetMaxTripletPerDoublets());
 
-    if (collectedHits.size() >= frAlgo.fParameters.GetMaxTripletPerDoublets()) {
-      LOG(debug) << "Ca: GetMaxTripletPerDoublets==" << frAlgo.fParameters.GetMaxTripletPerDoublets()
+    if (collectedHits.size() >= fParameters.GetMaxTripletPerDoublets()) {
+      LOG(debug) << "Ca: GetMaxTripletPerDoublets==" << fParameters.GetMaxTripletPerDoublets()
                  << " reached in findTripletsStep0()";
       // reject already created triplets for this doublet
       collectedHits.clear();
@@ -412,7 +432,7 @@ void TripletConstructor::FindRightHit()
       ca::HitIndex_t irh = collectedHits[ih];
       if constexpr (fDebugDublets) {
         ca::HitIndex_t ihit = frWData.Hit(irh).Id();
-        const ca::Hit& h    = frAlgo.fInputData.GetHit(ihit);
+        const ca::Hit& h    = fInputData.GetHit(ihit);
         LOG(info) << "  hit " << ihit << " " << h.ToString();
       }
       if (frWData.IsHitSuppressed(irh)) {
@@ -455,7 +475,7 @@ void TripletConstructor::FitTriplets()
     fit.SetParticleMass(constants::phys::ElectronMass);
   }
   else {
-    fit.SetParticleMass(frAlgo.GetDefaultParticleMass());
+    fit.SetParticleMass(fDefaultMass);
   }
   const int NHits = 3;  // triplets
 
@@ -464,7 +484,7 @@ void TripletConstructor::FitTriplets()
 
   ca::Station<fvec> sta[3];
   for (int is = 0; is < NHits; ++is) {
-    sta[is] = frAlgo.fParameters.GetStation(ista[is]);
+    sta[is] = fParameters.GetStation(ista[is]);
   };
 
   bool isMomentumFitted = ((staL().fieldStatus != 0) || (staM().fieldStatus != 0) || (staR().fieldStatus != 0));
@@ -480,10 +500,10 @@ void TripletConstructor::FitTriplets()
 
     ca::HitIndex_t ihit[NHits] = {frWData.Hit(iwhit[0]).Id(), frWData.Hit(iwhit[1]).Id(), frWData.Hit(iwhit[2]).Id()};
 
-    if (frAlgo.fParameters.DevIsMatchTripletsViaMc()) {
-      int mc1 = frAlgo.GetMcTrackIdForCaHit(ihit[0]);
-      int mc2 = frAlgo.GetMcTrackIdForCaHit(ihit[1]);
-      int mc3 = frAlgo.GetMcTrackIdForCaHit(ihit[2]);
+    if (fParameters.DevIsMatchTripletsViaMc()) {
+      int mc1 = ca::Framework::GetMcTrackIdForCaHit(ihit[0]);
+      int mc2 = ca::Framework::GetMcTrackIdForCaHit(ihit[1]);
+      int mc3 = ca::Framework::GetMcTrackIdForCaHit(ihit[2]);
       if ((mc1 != mc2) || (mc1 != mc3)) {
         continue;
       }
@@ -494,7 +514,7 @@ void TripletConstructor::FitTriplets()
     ca::MeasurementXy<fvec> mxy[NHits];
 
     for (int ih = 0; ih < NHits; ++ih) {
-      const ca::Hit& hit = frAlgo.fInputData.GetHit(ihit[ih]);
+      const ca::Hit& hit = fInputData.GetHit(ihit[ih]);
       mxy[ih] = ca::MeasurementXy<fvec>(hit.X(), hit.Y(), hit.dX2(), hit.dY2(), hit.dXY(), fvec::One(), fvec::One());
 
       x[ih]   = hit.X();
@@ -518,7 +538,7 @@ void TripletConstructor::FitTriplets()
     };
 
     fld.Set(B[0], sta[0].fZ, B[1], sta[1].fZ, B[2], sta[2].fZ);
-    fldTarget.Set(frWData.TargB(), frAlgo.GetParameters().GetTargetPositionZ(), B[0], sta[0].fZ, B[1], sta[1].fZ);
+    fldTarget.Set(frWData.TargB(), fParameters.GetTargetPositionZ(), B[0], sta[0].fZ, B[1], sta[1].fZ);
 
     TrackParamV& T = fit.Tr();
 
@@ -556,11 +576,11 @@ void TripletConstructor::FitTriplets()
         T.NdfTime() = sta[ih0].timeInfo ? 0 : -1;
 
         //  add the target constraint
-        fit.FilterWithTargetAtLine(frAlgo.GetParameters().GetTargetPositionZ(), frWData.TargetMeasurement(), fldTarget);
+        fit.FilterWithTargetAtLine(fParameters.GetTargetPositionZ(), frWData.TargetMeasurement(), fldTarget);
 
         for (int ih = 1; ih < NHits; ++ih) {
           fit.Extrapolate(z[ih], fld);
-          auto radThick = frAlgo.fParameters.GetMaterialThickness(ista[ih], T.X(), T.Y());
+          auto radThick = fParameters.GetMaterialThickness(ista[ih], T.X(), T.Y());
           fit.MultipleScattering(radThick);
           fit.EnergyLossCorrection(radThick, fvec(-1.f));
           fit.FilterXY(mxy[ih]);
@@ -594,7 +614,7 @@ void TripletConstructor::FitTriplets()
 
         for (int ih = NHits - 2; ih >= 0; --ih) {
           fit.Extrapolate(z[ih], fld);
-          auto radThick = frAlgo.fParameters.GetMaterialThickness(ista[ih], T.X(), T.Y());
+          auto radThick = fParameters.GetMaterialThickness(ista[ih], T.X(), T.Y());
           fit.MultipleScattering(radThick);
           fit.EnergyLossCorrection(radThick, fvec(1.f));
           fit.FilterXY(mxy[ih]);
@@ -609,13 +629,14 @@ void TripletConstructor::FitTriplets()
       int ih0 = ihit[0];
       int ih1 = ihit[1];
       int ih2 = ihit[2];
-      int mc1 = frAlgo.GetMcTrackIdForCaHit(ih0);
-      int mc2 = frAlgo.GetMcTrackIdForCaHit(ih1);
-      int mc3 = frAlgo.GetMcTrackIdForCaHit(ih2);
+      int mc1 = ca::Framework::GetMcTrackIdForCaHit(ih0);
+      int mc2 = ca::Framework::GetMcTrackIdForCaHit(ih1);
+      int mc3 = ca::Framework::GetMcTrackIdForCaHit(ih2);
+
       if (1 || (mc1 >= 0) && (mc1 == mc2) && (mc1 == mc3)) {
-        const ca::Hit& h0 = frAlgo.fInputData.GetHit(ih0);
-        const ca::Hit& h1 = frAlgo.fInputData.GetHit(ih1);
-        const ca::Hit& h2 = frAlgo.fInputData.GetHit(ih2);
+        const ca::Hit& h0 = fInputData.GetHit(ih0);
+        const ca::Hit& h1 = fInputData.GetHit(ih1);
+        const ca::Hit& h2 = fInputData.GetHit(ih2);
         //const CbmL1MCTrack& mctr = CbmL1::Instance()->GetMcTracks()[mc1];
         LOG(info) << "== fitted triplet: "
                   << " iter " << frWData.CurrentIterationIndex() << " hits: {" << fIstaL << "/" << ih0 << " " << fIstaM
@@ -700,7 +721,7 @@ void TripletConstructor::CollectHits(const TrackParamV& Tr, const int iSta, cons
   collectedHits.clear();
   collectedHits.reserve(maxNhits);
 
-  const ca::Station<fvec>& sta = frAlgo.fParameters.GetStation(iSta);
+  const ca::Station<fvec>& sta = fParameters.GetStation(iSta);
 
   fFit.SetTrack(Tr);
   TrackParamV& T = fFit.Tr();
@@ -721,7 +742,7 @@ void TripletConstructor::CollectHits(const TrackParamV& Tr, const int iSta, cons
               << (sqrt(Pick_m22 * T.C00()) + grid.GetMaxRangeX() + maxDZ * abs(T.Tx()))[0] << " "
               << (sqrt(Pick_m22 * T.C11()) + grid.GetMaxRangeY() + maxDZ * abs(T.Ty()))[0];
   }
-  if (frAlgo.fParameters.DevIsIgnoreHitSearchAreas()) {
+  if (fParameters.DevIsIgnoreHitSearchAreas()) {
     area.DoLoopOverEntireGrid();
   }
 
@@ -740,7 +761,8 @@ void TripletConstructor::CollectHits(const TrackParamV& Tr, const int iSta, cons
       LOG(info) << "   check the hit.. ";
     }
     if (iMC >= 0) {  // match via MC
-      if (iMC != frAlgo.GetMcTrackIdForWindowHit(ih)) {
+
+      if (iMC != ca::Framework::GetMcTrackIdForWindowHit(ih)) {
         if constexpr (fDebugCollectHits) {
           LOG(info) << "   hit mc does not match";
         }
diff --git a/algo/ca/core/tracking/CaTripletConstructor.h b/algo/ca/core/tracking/CaTripletConstructor.h
index de18a4d718..162e0c5279 100644
--- a/algo/ca/core/tracking/CaTripletConstructor.h
+++ b/algo/ca/core/tracking/CaTripletConstructor.h
@@ -34,7 +34,8 @@ namespace cbm::algo::ca
 
     /// Constructor
     /// \param nThreads  Number of threads for multi-threaded mode
-    TripletConstructor(ca::Framework& algo, ca::WindowData& wData);
+    TripletConstructor(const ca::Parameters<fvec>& pars, const ca::InputData& input, WindowData& wData,
+                       const float mass, const ca::TrackingMode& mode);
 
     /// Copy constructor
     TripletConstructor(const TripletConstructor&) = delete;
@@ -89,8 +90,18 @@ namespace cbm::algo::ca
     const ca::Station<fvec>& staR() { return *fStaR; }
 
    private:
+    const Parameters<fvec>& fParameters;  ///< Object of Framework parameters class
+    const InputData& fInputData;          ///< Tracking input data
+    WindowData& frWData;
+    float fDefaultMass{constants::phys::MuonMass};  ///< mass of the propagated particle [GeV/c2]
+    ca::TrackingMode fTrackingMode;
+
+    bool fIsTargetField{false};  ///< is the magnetic field present at the target
+
+    // Number of stations situated in field region (MVD + STS in CBM)
+    int fNfieldStations{0};
+
     bool fIsInitialized{false};  ///< is initialized;
-    ca::Framework& frAlgo;       ///< reference to ca::Framework object
 
     int fIstaL{-1};  ///< left station index
     int fIstaM{-1};  ///< middle station index
@@ -119,7 +130,6 @@ namespace cbm::algo::ca
     Vector<ca::Triplet> fTriplets{"TripletConstructor::fTriplets"};
 
     ca::TrackFit fFit;
-    WindowData& frWData;
 
    private:
     static constexpr bool fDebugDublets     = false;  // print debug info for dublets
diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx
index a2d72bd140..59e4629e60 100644
--- a/reco/L1/CbmL1.cxx
+++ b/reco/L1/CbmL1.cxx
@@ -197,7 +197,7 @@ try {
   fUseTRD  = false;
   fUseTOF  = false;
 
-  if (ca::Framework::TrackingMode::kSts == fTrackingMode) {
+  if (ca::TrackingMode::kSts == fTrackingMode) {
     fUseMVD  = true;
     fUseSTS  = true;
     fUseMUCH = false;
@@ -208,7 +208,7 @@ try {
     if (findTask) fUseMVD = findTask->MvdUsage();
   }
 
-  if (ca::Framework::TrackingMode::kMcbm == fTrackingMode) {
+  if (ca::TrackingMode::kMcbm == fTrackingMode) {
     fUseMVD  = false;
     fUseSTS  = true;
     fUseMUCH = true;
@@ -217,7 +217,7 @@ try {
     // fInitManager.DevSetIgnoreHitSearchAreas(true);  // uncomment for debug
   }
 
-  if (ca::Framework::TrackingMode::kGlobal == fTrackingMode) {
+  if (ca::TrackingMode::kGlobal == fTrackingMode) {
     //at the moment trd2d tracking only
     fUseMVD  = false;
     fUseSTS  = false;
@@ -264,9 +264,9 @@ try {
 
       std::string mainConfig = std::string(gSystem->Getenv("VMCWORKDIR")) + "/macro/L1/configs/";
       switch (fTrackingMode) {
-        case ca::Framework::TrackingMode::kSts: mainConfig += "ca_params_sts.yaml"; break;
-        case ca::Framework::TrackingMode::kMcbm: mainConfig += "ca_params_mcbm.yaml"; break;
-        case ca::Framework::TrackingMode::kGlobal: mainConfig += "ca_params_global.yaml"; break;
+        case ca::TrackingMode::kSts: mainConfig += "ca_params_sts.yaml"; break;
+        case ca::TrackingMode::kMcbm: mainConfig += "ca_params_mcbm.yaml"; break;
+        case ca::TrackingMode::kGlobal: mainConfig += "ca_params_global.yaml"; break;
       }
       fInitManager.SetConfigMain(mainConfig);
     }
@@ -372,7 +372,7 @@ try {
         // TODO: SZh 15.08.2022: Replace station type with ca::EDetectorID
         stationInfo.SetStationType(1);  // MVD
         stationInfo.SetTimeInfo(!bDisableTime && mvdInterface->IsTimeInfoProvided(iSt));
-        stationInfo.SetFieldStatus(fTrackingMode == ca::Framework::TrackingMode::kMcbm ? 0 : 1);
+        stationInfo.SetFieldStatus(fTrackingMode == ca::TrackingMode::kMcbm ? 0 : 1);
         stationInfo.SetZref(mvdInterface->GetZref(iSt));
         stationInfo.SetZmin(mvdInterface->GetZmin(iSt));
         stationInfo.SetZmax(mvdInterface->GetZmax(iSt));
@@ -395,7 +395,7 @@ try {
         // TODO: SZh 15.08.2022: Replace station type with ca::EDetectorID
         stationInfo.SetStationType(0);  // STS
         stationInfo.SetTimeInfo(!bDisableTime && stsInterface->IsTimeInfoProvided(iSt));
-        stationInfo.SetFieldStatus(ca::Framework::TrackingMode::kMcbm == fTrackingMode ? 0 : 1);
+        stationInfo.SetFieldStatus(ca::TrackingMode::kMcbm == fTrackingMode ? 0 : 1);
         stationInfo.SetZref(stsInterface->GetZref(iSt));
         stationInfo.SetZmin(stsInterface->GetZmin(iSt));
         stationInfo.SetZmax(stsInterface->GetZmax(iSt));
@@ -450,7 +450,7 @@ try {
         stationInfo.SetXmax(std::max(fabs(trdInterface->GetXmax(iSt)), fabs(trdInterface->GetXmin(iSt))));
         stationInfo.SetYmax(std::max(fabs(trdInterface->GetYmax(iSt)), fabs(trdInterface->GetYmin(iSt))));
 
-        if (ca::Framework::TrackingMode::kGlobal == fTrackingMode) {
+        if (ca::TrackingMode::kGlobal == fTrackingMode) {
           stationInfo.SetTimeInfo(false);
         }
         stationInfo.SetTrackingStatus(true);
@@ -645,7 +645,7 @@ void CbmL1::Reconstruct(CbmEvent* event)
     LOG_IF(info, fVerbose > 0) << "\n=======  Ca Track finder: process timeslice ...";
   }
 
-  fpAlgo->fTrackFinder.FindTracks();
+  fpAlgo->FindTracks();
   //       IdealTrackFinder();
   fTrackingTime = fpAlgo->fCaRecoTime;  // TODO: remove (not used)
 
diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h
index 76bde7f973..2d6c6d1d57 100644
--- a/reco/L1/CbmL1.h
+++ b/reco/L1/CbmL1.h
@@ -258,9 +258,9 @@ class CbmL1 : public FairTask {
   }
 
   void SetExtrapolateToTheEndOfSTS(bool b) { fExtrapolateToTheEndOfSTS = b; }
-  void SetStsOnlyMode() { fTrackingMode = ca::Framework::TrackingMode::kSts; }
-  void SetMcbmMode() { fTrackingMode = ca::Framework::TrackingMode::kMcbm; }
-  void SetGlobalMode() { fTrackingMode = ca::Framework::TrackingMode::kGlobal; }
+  void SetStsOnlyMode() { fTrackingMode = ca::TrackingMode::kSts; }
+  void SetMcbmMode() { fTrackingMode = ca::TrackingMode::kMcbm; }
+  void SetGlobalMode() { fTrackingMode = ca::TrackingMode::kGlobal; }
 
   ca::TrackingMonitor fMonitor{};  ///< Tracking monitor
 
@@ -440,7 +440,7 @@ class CbmL1 : public FairTask {
 
   ca::Framework* fpAlgo = nullptr;  ///< Pointer to the L1 track finder algorithm
 
-  ca::Framework::TrackingMode fTrackingMode = ca::Framework::TrackingMode::kSts;  ///< Tracking mode
+  ca::TrackingMode fTrackingMode = ca::TrackingMode::kSts;  ///< Tracking mode
 
   ca::Vector<CbmL1Track> fvRecoTracks = {"CbmL1::fvRecoTracks"};  ///< Reconstructed tracks container
 
@@ -468,7 +468,7 @@ class CbmL1 : public FairTask {
   ///
   int fSTAPDataMode = 4;  ///< Option to work with files for the standalone mode
 
-  TString fSTAPDataDir = ".";  ///< Name of input/output directory for running in a STAP mode
+  TString fSTAPDataDir    = ".";     ///< Name of input/output directory for running in a STAP mode
   TString fSTAPDataPrefix = "test";  ///< Name of input/output file prefix. The prefix is defined by output TTree file
   TString fSTAPParamFile  = "";      ///< Name of the parameter file (generated automatically, if not provided manually)
 
@@ -487,8 +487,8 @@ class CbmL1 : public FairTask {
   static constexpr std::string_view kSTAPAlgoIDataDir = "input_hits";
 
 
-  Int_t fTrackingLevel     = 2;     // currently not used
-  Double_t fMomentumCutOff = 0.1;   // currently not used
+  Int_t fTrackingLevel     = 2;    // currently not used
+  Double_t fMomentumCutOff = 0.1;  // currently not used
 
   bool fUseMVD  = false;  ///< if Mvd data should be processed
   bool fUseSTS  = false;  ///< if Mvd data should be processed
diff --git a/reco/L1/CbmL1Performance.cxx b/reco/L1/CbmL1Performance.cxx
index 2ee6f2bd06..66be5f0a40 100644
--- a/reco/L1/CbmL1Performance.cxx
+++ b/reco/L1/CbmL1Performance.cxx
@@ -1133,7 +1133,7 @@ void CbmL1::TrackFitPerformance()
                          {"pvi", "Pull Vi [residual/estimated_error]", 100, -10., 10.},
                          {"distrVi", "Vi distribution [1/c]", 100, 0., 4.}};
 
-      if (ca::Framework::kGlobal == fpAlgo->fTrackingMode) {
+      if (ca::TrackingMode::kGlobal == fpAlgo->GetTrackingMode()) {
         Table[4].l = -100.;
         Table[4].r = 100.;
       }
@@ -1166,7 +1166,7 @@ void CbmL1::TrackFitPerformance()
                                  {"pvi", "Pull Vi [residual/estimated_error]", 100, -10., 10.},
                                  {"distrVi", "Vi distribution [1/c]", 100, -10., 10.}};
 
-      if (ca::Framework::kGlobal == fpAlgo->fTrackingMode) {
+      if (ca::TrackingMode::kGlobal == fpAlgo->GetTrackingMode()) {
         TableVertex[4].l = -1.;
         TableVertex[4].r = 1.;
       }
diff --git a/reco/L1/L1Algo/utils/L1AlgoDraw.cxx b/reco/L1/L1Algo/utils/L1AlgoDraw.cxx
index a203bc8bfc..56e657724c 100644
--- a/reco/L1/L1Algo/utils/L1AlgoDraw.cxx
+++ b/reco/L1/L1Algo/utils/L1AlgoDraw.cxx
@@ -79,18 +79,18 @@ void L1AlgoDraw::InitL1Draw(ca::Framework* algo_)
 
   vHits.clear();
   vHitsQa.clear();
-  auto nHits = algo->fvWData[0].Hits().size();
+  auto nHits = algo->GetWData()[0].Hits().size();
   vHits.reserve(nHits);
   vHitsQa.reserve(nHits);
-  for (const auto& hit : algo->fvWData[0].Hits()) {
+  for (const auto& hit : algo->GetWData()[0].Hits()) {
     vHits.push_back(hit);
     int iQaHit = hit.Id();
     vHitsQa.push_back(CbmL1::Instance()->GetQaHits()[iQaHit]);
   }
   NStations = algo->GetParameters().GetNstationsActive();
   for (int i = 0; i < NStations; i++) {
-    HitsStartIndex[i] = algo->fvWData[0].HitStartIndexOnStation(i);
-    HitsStopIndex[i]  = HitsStartIndex[i] + algo->fvWData[0].NofHitsOnStation(i);
+    HitsStartIndex[i] = algo->GetWData()[0].HitStartIndexOnStation(i);
+    HitsStopIndex[i]  = HitsStartIndex[i] + algo->GetWData()[0].NofHitsOnStation(i);
     vStations[i]      = algo->GetParameters().GetStation(i);
   }
 }
@@ -244,12 +244,12 @@ void L1AlgoDraw::DrawRecoTracks()
   int NRecTracks = 0;
   //   CbmL1 &L1 = *CbmL1::Instance();
 
-  int curRecoHit                                  = 0;
-  cbm::algo::ca::Vector<ca::HitIndex_t>& recoHits = algo->fvWData[0].RecoHitIndices();
-  for (vector<Track>::iterator it = algo->fvWData[0].RecoTracks().begin(); it != algo->fvWData[0].RecoTracks().end();
-       ++it) {
-    Track& T  = *it;
-    int nHits = T.fNofHits;
+  int curRecoHit                                        = 0;
+  const cbm::algo::ca::Vector<ca::HitIndex_t>& recoHits = algo->GetWData()[0].RecoHitIndices();
+  for (vector<Track>::const_iterator it = algo->GetWData()[0].RecoTracks().begin();
+       it != algo->GetWData()[0].RecoTracks().end(); ++it) {
+    const Track& T = *it;
+    int nHits      = T.fNofHits;
     //     if (nHits > 5) continue; // draw clones
     //     YZ->cd(); YZ->Update();
     //     XZ->cd(); XZ->Update();
@@ -485,8 +485,8 @@ void L1AlgoDraw::DrawDoublet(int il, int ir)
 void L1AlgoDraw::DrawInfo()
 {
   cout << " vHits.size = " << algo->GetInputData().GetNhits() << endl;
-  cout << " vRecoHits.size = " << algo->fvWData[0].RecoHitIndices().size() << endl;
-  cout << " vTracks.size = " << algo->fvWData[0].RecoTracks().size() << endl;
+  cout << " vRecoHits.size = " << algo->GetWData()[0].RecoHitIndices().size() << endl;
+  cout << " vTracks.size = " << algo->GetWData()[0].RecoTracks().size() << endl;
 }
 
 void L1AlgoDraw::DrawTarget()
@@ -571,10 +571,10 @@ void L1AlgoDraw::DrawInputHits()
 
   for (int ista = NStations - 1; ista >= 0; ista--) {  //  //start downstream chambers
     ca::Station<ca::fvec>& st = vStations[ista];
-    Int_t n_poly      = 0;
-    Int_t n_poly_fake = 0;
+    Int_t n_poly              = 0;
+    Int_t n_poly_fake         = 0;
     for (int ih = HitsStartIndex[ista]; ih < HitsStopIndex[ista]; ih++) {
-      ca::Hit& h = vHits[ih];
+      ca::Hit& h      = vHits[ih];
       const auto& hQa = vHitsQa[ih];
       int iMC         = hQa.GetBestMcPointId();
       //if( (vSFlag[h.f] | vSFlagB[h.b] )&0x02 ) continue; // if used
@@ -704,11 +704,11 @@ void L1AlgoDraw::DrawRestHits(ca::HitIndex_t* StsRestHitsStartIndex, ca::HitInde
 
   for (int ista = NStations - 1; ista >= 0; ista--) {  //  //start downstream chambers
     ca::Station<ca::fvec>& st = vStations[ista];
-    Int_t n_poly      = 0;
-    Int_t n_poly_fake = 0;
+    Int_t n_poly              = 0;
+    Int_t n_poly_fake         = 0;
     for (ca::HitIndex_t iRestHit = StsRestHitsStartIndex[ista]; iRestHit < StsRestHitsStopIndex[ista]; iRestHit++) {
-      int ih     = realIHit[iRestHit];
-      ca::Hit& h = vHits[ih];
+      int ih            = realIHit[iRestHit];
+      ca::Hit& h        = vHits[ih];
       const auto& qaHit = vHitsQa[ih];
       int iMC           = qaHit.GetBestMcPointId();
       //if( (vSFlag[h.f] | vSFlagB[h.b] )&0x02 ) continue; // if used
-- 
GitLab