diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IOUtils.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IOUtils.h index ea8986348820e..c95e3045a8664 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IOUtils.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/IOUtils.h @@ -56,9 +56,10 @@ constexpr float DefClusErrorCol = o2::itsmft::SegmentationAlpide::PitchCol * 0.5 constexpr float DefClusError2Row = DefClusErrorRow * DefClusErrorRow; constexpr float DefClusError2Col = DefClusErrorCol * DefClusErrorCol; -int loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& events, gsl::span clusters, +template +int loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& events, gsl::span clusters, gsl::span::iterator& pattIt, const itsmft::TopologyDictionary& dict, - const dataformats::MCTruthContainer* mClsLabels = nullptr, const o2::mft::Tracker* tracker = nullptr); + const dataformats::MCTruthContainer* mClsLabels = nullptr, const o2::mft::Tracker* tracker = nullptr); void convertCompactClusters(gsl::span clusters, gsl::span::iterator& pattIt, diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/ROframe.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/ROframe.h index b267cd6cbe9ac..f00517e1a371c 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/ROframe.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/ROframe.h @@ -37,13 +37,11 @@ namespace o2 namespace mft { -class TrackCA; -class TrackLTF; - +template class ROframe { public: - ROframe(Int_t ROframeId); + ROframe(const Int_t ROframeId) : mROframeId{ROframeId} {} Int_t getROFrameId() const { return mROframeId; } Int_t getTotalClusters() const; @@ -57,31 +55,44 @@ class ROframe const Int_t getClusterExternalIndex(Int_t layerId, const Int_t clusterId) const { return mClusterExternalIndices[layerId][clusterId]; } - std::vector& getTracksLTF(); - TrackLTF& getCurrentTrackLTF(); - - std::vector& getTracksCA(); - TrackCA& getCurrentTrackCA(); - - Road& getCurrentRoad(); - - template - void addClusterToLayer(Int_t layer, T&&... args); + std::vector& getTracks() { return mTracks; } + T& getCurrentTrack() { return mTracks.back(); } - void addClusterLabelToLayer(Int_t layer, const MCCompLabel label); - void addClusterExternalIndexToLayer(Int_t layer, const Int_t idx); + Road& getCurrentRoad() { return mRoads.back(); } - void addTrackLTF() { mTracksLTF.emplace_back(); } + template + void addClusterToLayer(Int_t layer, C&&... args) + { + mClusters[layer].emplace_back(std::forward(args)...); + } + void addClusterLabelToLayer(Int_t layer, const MCCompLabel label) { mClusterLabels[layer].emplace_back(label); } + void addClusterExternalIndexToLayer(Int_t layer, const Int_t idx) { mClusterExternalIndices[layer].push_back(idx); } - void addTrackCA(const Int_t); + void addTrack(bool isCA = false) + { + mTracks.emplace_back(isCA); + } - void addRoad(); + void addRoad() { mRoads.emplace_back(); } void initialize(bool fullClusterScan = false); void sortClusters(); - void clear(); + void clear() + { + + for (Int_t iLayer = 0; iLayer < constants::mft::LayersNumber; ++iLayer) { + mClusters[iLayer].clear(); + mClusterLabels[iLayer].clear(); + mClusterExternalIndices[iLayer].clear(); + for (Int_t iBin = 0; iBin < constants::index_table::MaxRPhiBins; ++iBin) { + mClusterBinIndexRange[iLayer][iBin] = std::pair(0, -1); + } + } + mTracks.clear(); + mRoads.clear(); + } const Int_t getNClustersInLayer(Int_t layerId) const { return mClusters[layerId].size(); } @@ -91,74 +102,10 @@ class ROframe std::array, constants::mft::LayersNumber> mClusterLabels; std::array, constants::mft::LayersNumber> mClusterExternalIndices; std::array, constants::index_table::MaxRPhiBins>, constants::mft::LayersNumber> mClusterBinIndexRange; - std::vector mTracksLTF; - std::vector mTracksCA; + std::vector mTracks; std::vector mRoads; }; -template -void ROframe::addClusterToLayer(Int_t layer, T&&... values) -{ - mClusters[layer].emplace_back(std::forward(values)...); -} - -inline void ROframe::addClusterLabelToLayer(Int_t layer, const MCCompLabel label) { mClusterLabels[layer].emplace_back(label); } - -inline void ROframe::addClusterExternalIndexToLayer(Int_t layer, const Int_t idx) -{ - mClusterExternalIndices[layer].push_back(idx); -} - -inline TrackLTF& ROframe::getCurrentTrackLTF() -{ - return mTracksLTF.back(); -} - -inline std::vector& ROframe::getTracksLTF() -{ - return mTracksLTF; -} - -inline void ROframe::addRoad() -{ - mRoads.emplace_back(); -} - -inline Road& ROframe::getCurrentRoad() -{ - return mRoads.back(); -} - -inline void ROframe::addTrackCA(const Int_t roadId) -{ - mTracksCA.emplace_back(); -} - -inline TrackCA& ROframe::getCurrentTrackCA() -{ - return mTracksCA.back(); -} - -inline std::vector& ROframe::getTracksCA() -{ - return mTracksCA; -} - -inline void ROframe::clear() -{ - for (Int_t iLayer = 0; iLayer < constants::mft::LayersNumber; ++iLayer) { - mClusters[iLayer].clear(); - mClusterLabels[iLayer].clear(); - mClusterExternalIndices[iLayer].clear(); - for (Int_t iBin = 0; iBin < constants::index_table::MaxRPhiBins; ++iBin) { - mClusterBinIndexRange[iLayer][iBin] = std::pair(0, -1); - } - } - mTracksLTF.clear(); - mTracksCA.clear(); - mRoads.clear(); -} - } // namespace mft } // namespace o2 diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackCA.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackCA.h index 33911f1c47abd..a48c95ecff317 100644 --- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackCA.h +++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackCA.h @@ -32,8 +32,11 @@ class TrackLTF : public TrackMFTExt { public: TrackLTF() = default; + TrackLTF(const bool isCA) { setCA(isCA); } + TrackLTF(const TrackLTF& t) = default; ~TrackLTF() = default; + const std::array& getXCoordinates() const { return mX; } const std::array& getYCoordinates() const { return mY; } const std::array& getZCoordinates() const { return mZ; } @@ -56,23 +59,35 @@ class TrackLTF : public TrackMFTExt std::array mClusterId; std::array mMCCompLabels; - ClassDefNV(TrackLTF, 10); + ClassDefNV(TrackLTF, 11); }; //_________________________________________________________________________________________________ -class TrackCA : public TrackLTF +class TrackLTFL : public TrackLTF // A track model for B=0 { + using SMatrix44Sym = ROOT::Math::SMatrix>; + public: - TrackCA() + TrackLTFL() = default; + TrackLTFL(const bool isCA) { setCA(isCA); } + TrackLTFL(const TrackLTFL& t) = default; + ~TrackLTFL() = default; + + // Kalman filter/fitting update for linear tracks + bool update(const std::array& p, const std::array& cov) { - TrackLTF(); - this->setCA(true); + // TODO + return true; } - TrackCA(const TrackCA& t) = default; - ~TrackCA() = default; private: - ClassDefNV(TrackCA, 10); + /// Covariance matrix of track parameters, ordered as follows:
+  ///                                 
+  ///                                 
+  ///                  
+  ///                  
+  SMatrix44Sym mCovariances{}; ///< \brief Covariance matrix of track parameters
+  ClassDefNV(TrackLTFL, 0);
 };
 
 //_________________________________________________________________________________________________
@@ -153,16 +168,17 @@ inline void TrackLTF::sort()
 
 namespace framework
 {
+
 template 
 struct is_messageable;
 template <>
-struct is_messageable : std::true_type {
+struct is_messageable : std::true_type {
 };
 
 template 
 struct is_messageable;
 template <>
-struct is_messageable : std::true_type {
+struct is_messageable : std::true_type {
 };
 
 } // namespace framework
diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackFitter.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackFitter.h
index 0aa56f1005b26..efd59f81a62ac 100644
--- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackFitter.h
+++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/TrackFitter.h
@@ -29,7 +29,8 @@ namespace o2
 namespace mft
 {
 
-/// Class to fit a track to a set of clusters
+/// Class to fit a forward track to a set of clusters
+template 
 class TrackFitter
 {
 
@@ -50,16 +51,16 @@ class TrackFitter
   void setVerbosity(float v) { mVerbose = v; }
   void setTrackModel(float m) { mTrackModel = m; }
 
-  bool initTrack(TrackLTF& track, bool outward = false);
-  bool fit(TrackLTF& track, bool outward = false);
+  bool initTrack(T& track, bool outward = false);
+  bool fit(T& track, bool outward = false);
 
   /// Return the maximum chi2 above which the track can be considered as abnormal
   static constexpr double getMaxChi2() { return SMaxChi2; }
 
  private:
-  bool propagateToZ(TrackLTF& track, double z);
-  bool propagateToNextClusterWithMCS(TrackLTF& track, double z, int& startingLayerID, const int& newLayerID);
-  bool computeCluster(TrackLTF& track, int cluster, int& startingLayerID);
+  bool propagateToZ(T& track, double z);
+  bool propagateToNextClusterWithMCS(T& track, double z, int& startingLayerID, const int& newLayerID);
+  bool computeCluster(T& track, int cluster, int& startingLayerID);
 
   bool mFieldON = true;
   Float_t mBZField; // kiloGauss.
@@ -71,7 +72,8 @@ class TrackFitter
 };
 
 // Functions to estimate momentum and charge from track curvature
-Double_t invQPtFromFCF(const TrackLTF& track, Double_t bFieldZ, Double_t& chi2);
+template 
+Double_t invQPtFromFCF(const T& track, Double_t bFieldZ, Double_t& chi2);
 Bool_t LinearRegression(Int_t nVal, std::vector& xVal, std::vector& yVal, std::vector& yErr, Double_t& a, Double_t& ae, Double_t& b, Double_t& be);
 
 } // namespace mft
diff --git a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Tracker.h b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Tracker.h
index a301af50f40db..731bc1885cdc6 100644
--- a/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Tracker.h
+++ b/Detectors/ITSMFT/MFT/tracking/include/MFTTracking/Tracker.h
@@ -33,8 +33,9 @@ namespace o2
 namespace mft
 {
 
-class TrackLTF;
+class T;
 
+template 
 class Tracker : public TrackerConfig
 {
 
@@ -52,10 +53,9 @@ class Tracker : public TrackerConfig
   auto& getTracksLTF() { return mTracksLTF; }
   auto& getTrackLabels() { return mTrackLabels; }
 
-  void clustersToTracks(ROframe&, std::ostream& = std::cout);
+  void clustersToTracks(ROframe&, std::ostream& = std::cout);
 
-  template 
-  void computeTracksMClabels(const T&);
+  void computeTracksMClabels(const std::vector&);
 
   void setROFrame(std::uint32_t f) { mROFrame = f; }
   std::uint32_t getROFrame() const { return mROFrame; }
@@ -64,33 +64,33 @@ class Tracker : public TrackerConfig
   void initConfig(const MFTTrackingParam& trkParam, bool printConfig = false);
 
  private:
-  void findTracks(ROframe&);
-  void findTracksLTF(ROframe&);
-  void findTracksCA(ROframe&);
-  void findTracksLTFfcs(ROframe&);
-  void findTracksCAfcs(ROframe&);
-  void computeCellsInRoad(ROframe&);
+  void findTracks(ROframe&);
+  void findTracksLTF(ROframe&);
+  void findTracksCA(ROframe&);
+  void findTracksLTFfcs(ROframe&);
+  void findTracksCAfcs(ROframe&);
+  void computeCellsInRoad(ROframe&);
   void runForwardInRoad();
-  void runBackwardInRoad(ROframe&);
+  void runBackwardInRoad(ROframe&);
   void updateCellStatusInRoad();
 
-  bool fitTracks(ROframe&);
+  bool fitTracks(ROframe&);
 
   const Int_t isDiskFace(Int_t layer) const { return (layer % 2); }
   const Float_t getDistanceToSeed(const Cluster&, const Cluster&, const Cluster&) const;
-  void getBinClusterRange(const ROframe&, const Int_t, const Int_t, Int_t&, Int_t&) const;
+  void getBinClusterRange(const ROframe&, const Int_t, const Int_t, Int_t&, Int_t&) const;
   const Float_t getCellDeviation(const Cell&, const Cell&) const;
   const Bool_t getCellsConnect(const Cell&, const Cell&) const;
-  void addCellToCurrentTrackCA(const Int_t, const Int_t, ROframe&);
-  void addCellToCurrentRoad(ROframe&, const Int_t, const Int_t, const Int_t, const Int_t, Int_t&);
+  void addCellToCurrentTrackCA(const Int_t, const Int_t, ROframe&);
+  void addCellToCurrentRoad(ROframe&, const Int_t, const Int_t, const Int_t, const Int_t, Int_t&);
 
   Float_t mBz = 5.f;
   std::uint32_t mROFrame = 0;
   std::vector mTracks;
-  std::vector mTracksLTF;
+  std::vector mTracksLTF;
   std::vector mClusters;
   std::vector mTrackLabels;
-  std::unique_ptr mTrackFitter = nullptr;
+  std::unique_ptr> mTrackFitter = nullptr;
 
   Int_t mMaxCellLevel = 0;
 
@@ -119,7 +119,8 @@ class Tracker : public TrackerConfig
 };
 
 //_________________________________________________________________________________________________
-inline const Float_t Tracker::getDistanceToSeed(const Cluster& cluster1, const Cluster& cluster2, const Cluster& cluster) const
+template 
+inline const Float_t Tracker::getDistanceToSeed(const Cluster& cluster1, const Cluster& cluster2, const Cluster& cluster) const
 {
   // the seed is between "cluster1" and "cluster2" and cuts the plane
   // of the "cluster" at a distance dR from it
@@ -136,7 +137,8 @@ inline const Float_t Tracker::getDistanceToSeed(const Cluster& cluster1, const C
 }
 
 //_________________________________________________________________________________________________
-inline void Tracker::getBinClusterRange(const ROframe& event, const Int_t layer, const Int_t bin, Int_t& clsMinIndex, Int_t& clsMaxIndex) const
+template 
+inline void Tracker::getBinClusterRange(const ROframe& event, const Int_t layer, const Int_t bin, Int_t& clsMinIndex, Int_t& clsMaxIndex) const
 {
   const auto& pair = event.getClusterBinIndexRange(layer)[bin];
   clsMinIndex = pair.first;
@@ -144,7 +146,8 @@ inline void Tracker::getBinClusterRange(const ROframe& event, const Int_t layer,
 }
 
 //_________________________________________________________________________________________________
-inline const Float_t Tracker::getCellDeviation(const Cell& cell1, const Cell& cell2) const
+template 
+inline const Float_t Tracker::getCellDeviation(const Cell& cell1, const Cell& cell2) const
 {
   Float_t cell1dx = cell1.getX2() - cell1.getX1();
   Float_t cell1dy = cell1.getY2() - cell1.getY1();
@@ -163,7 +166,8 @@ inline const Float_t Tracker::getCellDeviation(const Cell& cell1, const Cell& ce
 }
 
 //_________________________________________________________________________________________________
-inline const Bool_t Tracker::getCellsConnect(const Cell& cell1, const Cell& cell2) const
+template 
+inline const Bool_t Tracker::getCellsConnect(const Cell& cell1, const Cell& cell2) const
 {
   Float_t cell1x2 = cell1.getX2();
   Float_t cell1y2 = cell1.getY2();
@@ -180,8 +184,8 @@ inline const Bool_t Tracker::getCellsConnect(const Cell& cell1, const Cell& cell
 }
 
 //_________________________________________________________________________________________________
-template 
-inline void Tracker::computeTracksMClabels(const T& tracks)
+template 
+inline void Tracker::computeTracksMClabels(const std::vector& tracks)
 {
   /// Moore's Voting Algorithm
   for (auto& track : tracks) {
diff --git a/Detectors/ITSMFT/MFT/tracking/src/IOUtils.cxx b/Detectors/ITSMFT/MFT/tracking/src/IOUtils.cxx
index 67f4545085bf3..76224fd48cf49 100644
--- a/Detectors/ITSMFT/MFT/tracking/src/IOUtils.cxx
+++ b/Detectors/ITSMFT/MFT/tracking/src/IOUtils.cxx
@@ -36,7 +36,8 @@ namespace mft
 {
 
 //_________________________________________________________
-int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, gsl::span clusters, gsl::span::iterator& pattIt, const itsmft::TopologyDictionary& dict, const dataformats::MCTruthContainer* mcLabels, const o2::mft::Tracker* tracker)
+template 
+int ioutils::loadROFrameData(const o2::itsmft::ROFRecord& rof, ROframe& event, gsl::span clusters, gsl::span::iterator& pattIt, const itsmft::TopologyDictionary& dict, const dataformats::MCTruthContainer* mcLabels, const o2::mft::Tracker* tracker)
 {
   event.clear();
   GeometryTGeo* geom = GeometryTGeo::Instance();
@@ -119,6 +120,13 @@ void ioutils::convertCompactClusters(gsl::span clu
     cl3d.setErrors(sigmaX2, sigmaY2, 0);
   }
 }
+template int o2::mft::ioutils::loadROFrameData(const o2::itsmft::ROFRecord&, ROframe&, gsl::span,
+                                                                  gsl::span::iterator&, const itsmft::TopologyDictionary&,
+                                                                  const dataformats::MCTruthContainer*, const o2::mft::Tracker*);
+
+template int o2::mft::ioutils::loadROFrameData(const o2::itsmft::ROFRecord&, ROframe&, gsl::span,
+                                                                   gsl::span::iterator&, const itsmft::TopologyDictionary&,
+                                                                   const dataformats::MCTruthContainer*, const o2::mft::Tracker*);
 
 } // namespace mft
 } // namespace o2
diff --git a/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingLinkDef.h b/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingLinkDef.h
index e281b4247a44f..9df79161358bc 100644
--- a/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingLinkDef.h
+++ b/Detectors/ITSMFT/MFT/tracking/src/MFTTrackingLinkDef.h
@@ -15,9 +15,9 @@
 #pragma link off all classes;
 #pragma link off all functions;
 #pragma link C++ class o2::mft::TrackLTF + ;
-#pragma link C++ class o2::mft::TrackCA + ;
+#pragma link C++ class o2::mft::TrackLTFL + ;
 #pragma link C++ class std::vector < o2::mft::TrackLTF> + ;
-#pragma link C++ class std::vector < o2::mft::TrackCA> + ;
+#pragma link C++ class std::vector < o2::mft::TrackLTFL> + ;
 #pragma link C++ class o2::mft::TrackerConfig + ;
 #pragma link C++ class o2::mft::MFTTrackingParam + ;
 #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::mft::MFTTrackingParam> + ;
diff --git a/Detectors/ITSMFT/MFT/tracking/src/ROframe.cxx b/Detectors/ITSMFT/MFT/tracking/src/ROframe.cxx
index fc4d75fca59de..9d4c4b6c9b103 100644
--- a/Detectors/ITSMFT/MFT/tracking/src/ROframe.cxx
+++ b/Detectors/ITSMFT/MFT/tracking/src/ROframe.cxx
@@ -21,11 +21,8 @@ namespace o2
 namespace mft
 {
 
-ROframe::ROframe(const Int_t ROframeId) : mROframeId{ROframeId}
-{
-}
-
-Int_t ROframe::getTotalClusters() const
+template 
+Int_t ROframe::getTotalClusters() const
 {
   size_t totalClusters{0};
   for (auto& clusters : mClusters) {
@@ -34,14 +31,16 @@ Int_t ROframe::getTotalClusters() const
   return Int_t(totalClusters);
 }
 
-void ROframe::initialize(bool fullClusterScan)
+template 
+void ROframe::initialize(bool fullClusterScan)
 {
   if (!fullClusterScan) {
     sortClusters();
   }
 }
 
-void ROframe::sortClusters()
+template 
+void ROframe::sortClusters()
 {
   Int_t nClsInLayer, binPrevIndex, clsMinIndex, clsMaxIndex, jClsLayer;
   // sort the clusters in R-Phi
@@ -77,5 +76,8 @@ void ROframe::sortClusters()
   } // layers
 }
 
+template class ROframe;
+template class ROframe;
+
 } // namespace mft
 } // namespace o2
diff --git a/Detectors/ITSMFT/MFT/tracking/src/TrackFitter.cxx b/Detectors/ITSMFT/MFT/tracking/src/TrackFitter.cxx
index 75b0f0c2e5c0c..f97ed4bcdb299 100644
--- a/Detectors/ITSMFT/MFT/tracking/src/TrackFitter.cxx
+++ b/Detectors/ITSMFT/MFT/tracking/src/TrackFitter.cxx
@@ -38,161 +38,231 @@ namespace mft
 {
 
 //_________________________________________________________________________________________________
-bool TrackFitter::fit(TrackLTF& track, bool outward)
+template 
+bool TrackFitter::fit(T& track, bool outward)
 {
-  /// Fit a track using its attached clusters
-  /// Returns false in case of failure
+  if constexpr (std::is_same::value) {
+    /// Fit a track using its attached clusters
+    /// Returns false in case of failure
 
-  auto nClusters = track.getNumberOfPoints();
-  auto lastLayer = track.getLayers()[(outward ? 0 : nClusters - 1)];
+    auto nClusters = track.getNumberOfPoints();
+    auto lastLayer = track.getLayers()[(outward ? 0 : nClusters - 1)];
 
-  if (mVerbose) {
-    std::cout << "Seed covariances: \n"
-              << track.getCovariances() << std::endl
-              << std::endl;
-  }
+    if (mVerbose) {
+      std::cout << "Seed covariances: \n"
+                << track.getCovariances() << std::endl
+                << std::endl;
+    }
 
-  // recursively compute clusters, updating the track parameters
-  if (!outward) { // Inward for vertexing
-    while (nClusters-- > 0) {
-      if (!computeCluster(track, nClusters, lastLayer)) {
-        return false;
+    // recursively compute clusters, updating the track parameters
+    if (!outward) { // Inward for vertexing
+      while (nClusters-- > 0) {
+        if (!computeCluster(track, nClusters, lastLayer)) {
+          return false;
+        }
       }
-    }
-  } else { // Outward for MCH matching
-    int ncl = 0;
-    while (ncl < nClusters) {
-      if (!computeCluster(track, ncl, lastLayer)) {
-        return false;
+    } else { // Outward for MCH matching
+      int ncl = 0;
+      while (ncl < nClusters) {
+        if (!computeCluster(track, ncl, lastLayer)) {
+          return false;
+        }
+        ncl++;
       }
-      ncl++;
     }
-  }
-  if (mVerbose) {
-    std::cout << "Track Chi2 = " << track.getTrackChi2() << std::endl;
-    std::cout << " ***************************** Done fitting *****************************\n";
+    if (mVerbose) {
+      std::cout << "Track Chi2 = " << track.getTrackChi2() << std::endl;
+      std::cout << " ***************************** Done fitting *****************************\n";
+    }
+  } else { // Magnet off: linear tracks
+    // Do nothing while there is no alignment
   }
 
   return true;
 }
 
 //_________________________________________________________________________________________________
-bool TrackFitter::initTrack(TrackLTF& track, bool outward)
+template 
+bool TrackFitter::initTrack(T& track, bool outward)
 {
 
-  // initialize the starting track parameters and cluster
-  double sigmainvQPtsq;
-  double chi2invqptquad;
-  auto invQPt0 = invQPtFromFCF(track, mBZField, sigmainvQPtsq);
-  if (std::abs(mBZField) < 0.5) { // Temporary workaround for MFT tracking with magnet off;
-    invQPt0 = 1e-5;
-  }
-  auto nPoints = track.getNumberOfPoints();
-  auto k = TMath::Abs(o2::constants::math::B2C * mBZField);
-  auto Hz = std::copysign(1, mBZField);
+  if constexpr (std::is_same::value) { // Magnet on
+    // initialize the starting track parameters
+    double sigmainvQPtsq;
+    double chi2invqptquad;
+    auto invQPt0 = invQPtFromFCF(track, mBZField, sigmainvQPtsq);
+    auto nPoints = track.getNumberOfPoints();
+    auto k = TMath::Abs(o2::constants::math::B2C * mBZField);
+    auto Hz = std::copysign(1, mBZField);
 
-  if (mVerbose) {
-    std::cout << "\n ***************************** Start Fitting new track ***************************** \n";
-    std::cout << "N Clusters = " << nPoints << std::endl;
-  }
+    if (mVerbose) {
+      std::cout << "\n ***************************** Start Fitting new track ***************************** \n";
+      std::cout << "N Clusters = " << nPoints << std::endl;
+    }
 
-  track.setInvQPtSeed(invQPt0);
-  track.setChi2QPtSeed(chi2invqptquad);
-  track.setInvQPt(invQPt0);
-
-  /// Compute the initial track parameters to seed the Kalman filter
-  int first_cls, last_cls;
-  if (outward) { // MCH matching
-    first_cls = 1;
-    last_cls = 0;
-  } else { // Vertexing
-    first_cls = nPoints - 1;
-    last_cls = nPoints - 2;
-  }
+    track.setInvQPtSeed(invQPt0);
+    track.setChi2QPtSeed(chi2invqptquad);
+    track.setInvQPt(invQPt0);
+
+    /// Compute the initial track parameters to seed the Kalman filter
+    int first_cls, last_cls;
+    if (outward) { // MCH matching
+      first_cls = 1;
+      last_cls = 0;
+    } else { // Vertexing
+      first_cls = nPoints - 1;
+      last_cls = nPoints - 2;
+    }
 
-  auto x0 = track.getXCoordinates()[first_cls];
-  auto y0 = track.getYCoordinates()[first_cls];
-  auto z0 = track.getZCoordinates()[first_cls];
-
-  //Compute tanl using first two clusters
-  auto deltaX = track.getXCoordinates()[1] - track.getXCoordinates()[0];
-  auto deltaY = track.getYCoordinates()[1] - track.getYCoordinates()[0];
-  auto deltaZ = track.getZCoordinates()[1] - track.getZCoordinates()[0];
-  auto deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY);
-  auto tanl0 = 0.5 * TMath::Sqrt2() * (deltaZ / deltaR) *
-               TMath::Sqrt(TMath::Sqrt((invQPt0 * deltaR * k) * (invQPt0 * deltaR * k) + 1) + 1);
-
-  // Compute phi at the last cluster using two last clusters
-  deltaX = track.getXCoordinates()[first_cls] - track.getXCoordinates()[last_cls];
-  deltaY = track.getYCoordinates()[first_cls] - track.getYCoordinates()[last_cls];
-  deltaZ = track.getZCoordinates()[first_cls] - track.getZCoordinates()[last_cls];
-  deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY);
-  auto phi0 = TMath::ATan2(deltaY, deltaX) - 0.5 * Hz * invQPt0 * deltaZ * k / tanl0;
-  auto sigmax0sq = track.getSigmasX2()[first_cls];
-  auto sigmay0sq = track.getSigmasY2()[first_cls];
-  auto sigmax1sq = track.getSigmasX2()[last_cls];
-  auto sigmay1sq = track.getSigmasY2()[last_cls];
-  auto sigmaDeltaXsq = sigmax0sq + sigmax1sq;
-  auto sigmaDeltaYsq = sigmay0sq + sigmay1sq;
-
-  track.setX(x0);
-  track.setY(y0);
-  track.setZ(z0);
-  track.setPhi(phi0);
-  track.setTanl(tanl0);
+    auto x0 = track.getXCoordinates()[first_cls];
+    auto y0 = track.getYCoordinates()[first_cls];
+    auto z0 = track.getZCoordinates()[first_cls];
+
+    //Compute tanl using first two clusters
+    auto deltaX = track.getXCoordinates()[1] - track.getXCoordinates()[0];
+    auto deltaY = track.getYCoordinates()[1] - track.getYCoordinates()[0];
+    auto deltaZ = track.getZCoordinates()[1] - track.getZCoordinates()[0];
+    auto deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY);
+    auto tanl0 = 0.5 * TMath::Sqrt2() * (deltaZ / deltaR) *
+                 TMath::Sqrt(TMath::Sqrt((invQPt0 * deltaR * k) * (invQPt0 * deltaR * k) + 1) + 1);
+
+    // Compute phi at the last cluster using two last clusters
+    deltaX = track.getXCoordinates()[first_cls] - track.getXCoordinates()[last_cls];
+    deltaY = track.getYCoordinates()[first_cls] - track.getYCoordinates()[last_cls];
+    deltaZ = track.getZCoordinates()[first_cls] - track.getZCoordinates()[last_cls];
+    deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY);
+    auto phi0 = TMath::ATan2(deltaY, deltaX) - 0.5 * Hz * invQPt0 * deltaZ * k / tanl0;
+
+    track.setX(x0);
+    track.setY(y0);
+    track.setZ(z0);
+    track.setPhi(phi0);
+    track.setTanl(tanl0);
 
-  if (mVerbose) {
-    std::cout << " Init " << (track.isCA() ? "CA Track " : "LTF Track") << std::endl;
-    auto model = (mTrackModel == Helix) ? "Helix" : (mTrackModel == Quadratic) ? "Quadratic"
-                                                  : (mTrackModel == Optimized) ? "Optimized"
-                                                                               : "Linear";
-    std::cout << "Track Model: " << model << std::endl;
-    std::cout << "  initTrack: X = " << x0 << " Y = " << y0 << " Z = " << z0 << " Tgl = " << tanl0 << "  Phi = " << phi0 << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl;
-  }
+    if (mVerbose) {
+      std::cout << " Init " << (track.isCA() ? "CA Track " : "LTF Track") << std::endl;
+      auto model = (mTrackModel == Helix) ? "Helix" : (mTrackModel == Quadratic) ? "Quadratic"
+                                                    : (mTrackModel == Optimized) ? "Optimized"
+                                                                                 : "Linear";
+      std::cout << "Track Model: " << model << std::endl;
+      std::cout << "  initTrack: X = " << x0 << " Y = " << y0 << " Z = " << z0 << " Tgl = " << tanl0 << "  Phi = " << phi0 << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl;
+    }
+
+    SMatrix55Sym lastParamCov;
+    float qptsigma = TMath::Max(std::abs(track.getInvQPt()), .5);
+    float tanlsigma = TMath::Max(std::abs(track.getTanl()), .5);
+
+    lastParamCov(0, 0) = 1;                              // 
+    lastParamCov(1, 1) = 1;                              // 
+    lastParamCov(2, 2) = TMath::Pi() * TMath::Pi() / 16; // 
+    lastParamCov(3, 3) = 10 * tanlsigma * tanlsigma;     // 
+    lastParamCov(4, 4) = 10 * qptsigma * qptsigma;       // 
+
+    track.setCovariances(lastParamCov);
+    track.setTrackChi2(0.);
+
+  } else { // Magnet off: linear tracks
 
-  SMatrix55Sym lastParamCov;
-  float qptsigma = TMath::Max(std::abs(track.getInvQPt()), .5);
-  float tanlsigma = TMath::Max(std::abs(track.getTanl()), .5);
+    // initialize the starting track parameters
+    double chi2invqptquad;
+    auto invQPt0 = 0;
+
+    auto nPoints = track.getNumberOfPoints();
+
+    if (mVerbose) {
+      std::cout << "\n ***************************** Start Fitting new track ***************************** \n";
+      std::cout << "N Clusters = " << nPoints << std::endl;
+    }
+
+    track.setInvQPtSeed(0);
+    track.setChi2QPtSeed(0);
+    track.setInvQPt(invQPt0);
+
+    /// Compute the initial track parameters to seed the Kalman filter
+    int first_cls, last_cls;
+    if (outward) { // MCH matching
+      first_cls = nPoints - 1;
+      last_cls = 0;
+    } else { // Vertexing
+      first_cls = nPoints - 1;
+      last_cls = 0;
+    }
 
-  lastParamCov(0, 0) = 1;                              // 
-  lastParamCov(1, 1) = 1;                              // 
-  lastParamCov(2, 2) = TMath::Pi() * TMath::Pi() / 16; // 
-  lastParamCov(3, 3) = 10 * tanlsigma * tanlsigma;     // 
-  lastParamCov(4, 4) = 10 * qptsigma * qptsigma;       // 
+    auto x0 = track.getXCoordinates()[first_cls];
+    auto y0 = track.getYCoordinates()[first_cls];
+    auto z0 = track.getZCoordinates()[first_cls];
 
-  track.setCovariances(lastParamCov);
-  track.setTrackChi2(0.);
+    auto deltaX = track.getXCoordinates()[first_cls] - track.getXCoordinates()[last_cls];
+    auto deltaY = track.getYCoordinates()[first_cls] - track.getYCoordinates()[last_cls];
+    auto deltaZ = track.getZCoordinates()[first_cls] - track.getZCoordinates()[last_cls];
+    auto deltaR = TMath::Sqrt(deltaX * deltaX + deltaY * deltaY);
+    auto tanl0 = deltaZ / deltaR;
+    auto phi0 = TMath::ATan2(deltaY, deltaX);
+
+    track.setX(x0);
+    track.setY(y0);
+    track.setZ(z0);
+    track.setPhi(phi0);
+    track.setTanl(tanl0);
+
+    if (mVerbose) {
+      std::cout << " Init " << (track.isCA() ? "CA Track " : "LTF Track") << std::endl;
+      auto model = "Linear";
+      std::cout << "Track Model: " << model << std::endl;
+      std::cout << "  initTrack: X = " << x0 << " Y = " << y0 << " Z = " << z0 << " Tgl = " << tanl0 << "  Phi = " << phi0 << " pz = " << track.getPz() << " q/pt = " << track.getInvQPt() << std::endl;
+    }
+
+    SMatrix55Sym lastParamCov;
+    float qptsigma = TMath::Max(std::abs(track.getInvQPt()), .5);
+    float tanlsigma = TMath::Max(std::abs(track.getTanl()), .5);
+
+    lastParamCov(0, 0) = 1;                              // 
+    lastParamCov(1, 1) = 1;                              // 
+    lastParamCov(2, 2) = TMath::Pi() * TMath::Pi() / 16; // 
+    lastParamCov(3, 3) = 10 * tanlsigma * tanlsigma;     // 
+    lastParamCov(4, 4) = 10 * qptsigma * qptsigma;       // 
+
+    track.setCovariances(lastParamCov);
+    track.setTrackChi2(0.);
+  }
 
   return true;
 }
 
 //_________________________________________________________________________________________________
-bool TrackFitter::propagateToZ(TrackLTF& track, double z)
+template 
+bool TrackFitter::propagateToZ(T& track, double z)
 {
   // Propagate track to the z position of the new cluster
-  switch (mTrackModel) {
-    case Linear:
-      track.propagateToZlinear(z);
-      break;
-    case Quadratic:
-      track.propagateToZquadratic(z, mBZField);
-      break;
-    case Helix:
-      track.propagateToZhelix(z, mBZField);
-      break;
-    case Optimized:
-      track.propagateToZ(z, mBZField);
-      break;
-    default:
-      std::cout << " Invalid track model.\n";
-      return false;
-      break;
+  if constexpr (std::is_same::value) { // Magnet on
+
+    switch (mTrackModel) {
+      case Linear:
+        track.propagateToZlinear(z);
+        break;
+      case Quadratic:
+        track.propagateToZquadratic(z, mBZField);
+        break;
+      case Helix:
+        track.propagateToZhelix(z, mBZField);
+        break;
+      case Optimized:
+        track.propagateToZ(z, mBZField);
+        break;
+      default:
+        std::cout << " Invalid track model.\n";
+        return false;
+        break;
+    }
+  } else {
+    // Do nothing while there is no alignment
   }
   return true;
 }
 
 //_________________________________________________________________________________________________
-bool TrackFitter::propagateToNextClusterWithMCS(TrackLTF& track, double z, int& startingLayerID, const int& newLayerID)
+template 
+bool TrackFitter::propagateToNextClusterWithMCS(T& track, double z, int& startingLayerID, const int& newLayerID)
 {
 
   // Propagate track to the next cluster z position, adding angular MCS effects at the center of
@@ -274,7 +344,8 @@ bool TrackFitter::propagateToNextClusterWithMCS(TrackLTF& track, double z, int&
 }
 
 //_________________________________________________________________________________________________
-bool TrackFitter::computeCluster(TrackLTF& track, int cluster, int& startingLayerID)
+template 
+bool TrackFitter::computeCluster(T& track, int cluster, int& startingLayerID)
 {
   /// Propagate track to the z position of the new cluster
   /// accounting for MCS dispersion in the current layer and the other(s) crossed
@@ -322,7 +393,8 @@ bool TrackFitter::computeCluster(TrackLTF& track, int cluster, int& startingLaye
 }
 
 //_________________________________________________________________________________________________
-Double_t invQPtFromFCF(const TrackLTF& track, Double_t bFieldZ, Double_t& sigmainvqptsq)
+template 
+Double_t invQPtFromFCF(const T& track, Double_t bFieldZ, Double_t& sigmainvqptsq)
 {
 
   const std::array& xPositions = track.getXCoordinates();
@@ -512,5 +584,8 @@ Bool_t LinearRegression(Int_t nVal, std::vector& xVal, std::vector;
+template class TrackFitter;
+
 } // namespace mft
 } // namespace o2
diff --git a/Detectors/ITSMFT/MFT/tracking/src/Tracker.cxx b/Detectors/ITSMFT/MFT/tracking/src/Tracker.cxx
index 8d6cc0782c3c4..5dc7eb3514534 100644
--- a/Detectors/ITSMFT/MFT/tracking/src/Tracker.cxx
+++ b/Detectors/ITSMFT/MFT/tracking/src/Tracker.cxx
@@ -27,13 +27,15 @@ namespace mft
 {
 
 //_________________________________________________________________________________________________
-Tracker::Tracker(bool useMC) : mUseMC{useMC}
+template 
+Tracker::Tracker(bool useMC) : mUseMC{useMC}
 {
-  mTrackFitter = std::make_unique();
+  mTrackFitter = std::make_unique>();
 }
 
 //_________________________________________________________________________________________________
-void Tracker::setBz(Float_t bz)
+template 
+void Tracker::setBz(Float_t bz)
 {
   /// Configure track propagation
   mBz = bz;
@@ -41,7 +43,8 @@ void Tracker::setBz(Float_t bz)
 }
 
 //_________________________________________________________________________________________________
-void Tracker::initConfig(const MFTTrackingParam& trkParam, bool printConfig)
+template 
+void Tracker::initConfig(const MFTTrackingParam& trkParam, bool printConfig)
 {
   /// initialize from MFTTrackingParam (command line configuration parameters)
 
@@ -91,7 +94,8 @@ void Tracker::initConfig(const MFTTrackingParam& trkParam, bool printConfig)
 }
 
 //_________________________________________________________________________________________________
-void Tracker::initialize(bool fullClusterScan)
+template 
+void Tracker::initialize(bool fullClusterScan)
 {
   mRoad.initialize();
 
@@ -191,7 +195,8 @@ void Tracker::initialize(bool fullClusterScan)
 }
 
 //_________________________________________________________________________________________________
-void Tracker::clustersToTracks(ROframe& event, std::ostream& timeBenchmarkOutputStream)
+template 
+void Tracker::clustersToTracks(ROframe& event, std::ostream& timeBenchmarkOutputStream)
 {
   mTracks.clear();
   mTrackLabels.clear();
@@ -200,7 +205,8 @@ void Tracker::clustersToTracks(ROframe& event, std::ostream& timeBenchmarkOutput
 }
 
 //_________________________________________________________________________________________________
-void Tracker::findTracks(ROframe& event)
+template 
+void Tracker::findTracks(ROframe& event)
 {
   if (!mFullClusterScan) {
     findTracksLTF(event);
@@ -212,7 +218,8 @@ void Tracker::findTracks(ROframe& event)
 }
 
 //_________________________________________________________________________________________________
-void Tracker::findTracksLTF(ROframe& event)
+template 
+void Tracker::findTracksLTF(ROframe& event)
 {
   // find (high momentum) tracks by the Linear Track Finder (LTF) method
 
@@ -266,7 +273,7 @@ void Tracker::findTracksLTF(ROframe& event)
           }
           clsInLayer2 = it2 - event.getClustersInLayer(layer2).begin();
 
-          // start a TrackLTF
+          // start a Track type T
           nPoints = 0;
 
           // add the first seed point
@@ -340,15 +347,15 @@ void Tracker::findTracksLTF(ROframe& event)
             continue;
           }
 
-          // add a new TrackLTF
-          event.addTrackLTF();
+          // add a new Track
+          event.addTrack();
           for (Int_t point = 0; point < nPoints; ++point) {
             auto layer = trackPoints[point].layer;
             auto clsInLayer = trackPoints[point].idInLayer;
             Cluster& cluster = event.getClustersInLayer(layer)[clsInLayer];
             mcCompLabel = mUseMC ? event.getClusterLabels(layer, cluster.clusterId) : MCCompLabel();
             extClsIndex = event.getClusterExternalIndex(layer, cluster.clusterId);
-            event.getCurrentTrackLTF().setPoint(cluster, layer, clsInLayer, mcCompLabel, extClsIndex);
+            event.getCurrentTrack().setPoint(cluster, layer, clsInLayer, mcCompLabel, extClsIndex);
             // mark the used clusters
             cluster.setUsed(true);
           }
@@ -360,7 +367,8 @@ void Tracker::findTracksLTF(ROframe& event)
 }
 
 //_________________________________________________________________________________________________
-void Tracker::findTracksLTFfcs(ROframe& event)
+template 
+void Tracker::findTracksLTFfcs(ROframe& event)
 {
   // find (high momentum) tracks by the Linear Track Finder (LTF) method
   // with full scan of the clusters in the target plane
@@ -409,7 +417,7 @@ void Tracker::findTracksLTFfcs(ROframe& event)
         }
         clsInLayer2 = it2 - event.getClustersInLayer(layer2).begin();
 
-        // start a TrackLTF
+        // start a track type T
         nPoints = 0;
 
         // add the first seed point
@@ -474,15 +482,15 @@ void Tracker::findTracksLTFfcs(ROframe& event)
           continue;
         }
 
-        // add a new TrackLTF
-        event.addTrackLTF();
+        // add a new Track
+        event.addTrack();
         for (Int_t point = 0; point < nPoints; ++point) {
           auto layer = trackPoints[point].layer;
           auto clsInLayer = trackPoints[point].idInLayer;
           Cluster& cluster = event.getClustersInLayer(layer)[clsInLayer];
           mcCompLabel = mUseMC ? event.getClusterLabels(layer, cluster.clusterId) : MCCompLabel();
           extClsIndex = event.getClusterExternalIndex(layer, cluster.clusterId);
-          event.getCurrentTrackLTF().setPoint(cluster, layer, clsInLayer, mcCompLabel, extClsIndex);
+          event.getCurrentTrack().setPoint(cluster, layer, clsInLayer, mcCompLabel, extClsIndex);
           // mark the used clusters
           cluster.setUsed(true);
         }
@@ -493,7 +501,8 @@ void Tracker::findTracksLTFfcs(ROframe& event)
 }
 
 //_________________________________________________________________________________________________
-void Tracker::findTracksCA(ROframe& event)
+template 
+void Tracker::findTracksCA(ROframe& event)
 {
   // layers: 0, 1, 2, ..., 9
   // rules for combining first/last plane in a road:
@@ -627,7 +636,8 @@ void Tracker::findTracksCA(ROframe& event)
 }
 
 //_________________________________________________________________________________________________
-void Tracker::findTracksCAfcs(ROframe& event)
+template 
+void Tracker::findTracksCAfcs(ROframe& event)
 {
   // layers: 0, 1, 2, ..., 9
   // rules for combining first/last plane in a road:
@@ -742,7 +752,8 @@ void Tracker::findTracksCAfcs(ROframe& event)
 }
 
 //_________________________________________________________________________________________________
-void Tracker::computeCellsInRoad(ROframe& event)
+template 
+void Tracker::computeCellsInRoad(ROframe& event)
 {
   Int_t layer1, layer1min, layer1max, layer2, layer2min, layer2max;
   Int_t nPtsInLayer1, nPtsInLayer2;
@@ -793,7 +804,8 @@ void Tracker::computeCellsInRoad(ROframe& event)
 }
 
 //_________________________________________________________________________________________________
-void Tracker::runForwardInRoad()
+template 
+void Tracker::runForwardInRoad()
 {
   Int_t layerR, layerL, icellR, icellL;
   Int_t iter = 0;
@@ -840,7 +852,8 @@ void Tracker::runForwardInRoad()
 }
 
 //_________________________________________________________________________________________________
-void Tracker::runBackwardInRoad(ROframe& event)
+template 
+void Tracker::runBackwardInRoad(ROframe& event)
 {
   if (mMaxCellLevel == 1) {
     return; // we have only isolated cells
@@ -947,8 +960,8 @@ void Tracker::runBackwardInRoad(ROframe& event)
         continue;
       }
 
-      // add a new TrackCA
-      event.addTrackCA(mRoad.getRoadId());
+      // add a new Track setting isCA = true
+      event.addTrack(true);
       for (icell = 0; icell < nCells; ++icell) {
         layerC = trackCells[icell].layer;
         cellIdC = trackCells[icell].idInLayer;
@@ -959,12 +972,14 @@ void Tracker::runBackwardInRoad(ROframe& event)
         event.getClustersInLayer(cellC.getFirstLayerId())[cellC.getFirstClusterIndex()].setUsed(true);
         event.getClustersInLayer(cellC.getSecondLayerId())[cellC.getSecondClusterIndex()].setUsed(true);
       }
+      event.getCurrentTrack().sort();
     } // end loop cells
   }   // end loop start layer
 }
 
 //_________________________________________________________________________________________________
-void Tracker::updateCellStatusInRoad()
+template 
+void Tracker::updateCellStatusInRoad()
 {
   Int_t layerMin, layerMax;
   mRoad.getLength(layerMin, layerMax);
@@ -977,7 +992,8 @@ void Tracker::updateCellStatusInRoad()
 }
 
 //_________________________________________________________________________________________________
-void Tracker::addCellToCurrentRoad(ROframe& event, const Int_t layer1, const Int_t layer2, const Int_t clsInLayer1, const Int_t clsInLayer2, Int_t& cellId)
+template 
+void Tracker::addCellToCurrentRoad(ROframe& event, const Int_t layer1, const Int_t layer2, const Int_t clsInLayer1, const Int_t clsInLayer2, Int_t& cellId)
 {
   Cell& cell = mRoad.addCellInLayer(layer1, layer2, clsInLayer1, clsInLayer2, cellId);
 
@@ -997,9 +1013,10 @@ void Tracker::addCellToCurrentRoad(ROframe& event, const Int_t layer1, const Int
 }
 
 //_________________________________________________________________________________________________
-void Tracker::addCellToCurrentTrackCA(const Int_t layer1, const Int_t cellId, ROframe& event)
+template 
+void Tracker::addCellToCurrentTrackCA(const Int_t layer1, const Int_t cellId, ROframe& event)
 {
-  TrackCA& trackCA = event.getCurrentTrackCA();
+  auto& trackCA = event.getCurrentTrack();
   const Cell& cell = mRoad.getCellsInLayer(layer1)[cellId];
   const Int_t layer2 = cell.getSecondLayerId();
   const Int_t clsInLayer1 = cell.getFirstClusterIndex();
@@ -1023,28 +1040,22 @@ void Tracker::addCellToCurrentTrackCA(const Int_t layer1, const Int_t cellId, RO
 }
 
 //_________________________________________________________________________________________________
-bool Tracker::fitTracks(ROframe& event)
+template 
+bool Tracker::fitTracks(ROframe& event)
 {
-  for (auto& track : event.getTracksLTF()) {
-    TrackLTF outParam = track;
+  for (auto& track : event.getTracks()) {
+    T outParam = track;
     mTrackFitter->initTrack(track);
     mTrackFitter->fit(track);
     mTrackFitter->initTrack(outParam, true);
     mTrackFitter->fit(outParam, true);
     track.setOutParam(outParam);
   }
-  for (auto& track : event.getTracksCA()) {
-    track.sort();
-    TrackCA outParam = track;
-    mTrackFitter->initTrack(track);
-    mTrackFitter->fit(track);
-    mTrackFitter->initTrack(outParam, true);
-    mTrackFitter->fit(outParam, true);
-    track.setOutParam(outParam);
-  }
-
   return true;
 }
 
+template class Tracker;
+template class Tracker;
+
 } // namespace mft
 } // namespace o2
diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackerSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackerSpec.h
index 971886b25cb57..c07a355f4d6d2 100644
--- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackerSpec.h
+++ b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/TrackerSpec.h
@@ -17,6 +17,7 @@
 #include "MFTTracking/Tracker.h"
 
 #include "Framework/DataProcessorSpec.h"
+#include "MFTTracking/TrackCA.h"
 #include "Framework/Task.h"
 #include "DataFormatsParameters/GRPObject.h"
 #include "DataFormatsITSMFT/TopologyDictionary.h"
@@ -26,9 +27,11 @@ namespace o2
 {
 namespace mft
 {
+using o2::mft::TrackLTF;
 
 class TrackerDPL : public o2::framework::Task
 {
+
  public:
   TrackerDPL(bool useMC) : mUseMC(useMC) {}
   ~TrackerDPL() override = default;
@@ -38,9 +41,11 @@ class TrackerDPL : public o2::framework::Task
 
  private:
   bool mUseMC = false;
+  bool mFieldOn = true;
   o2::itsmft::TopologyDictionary mDict;
   std::unique_ptr mGRP = nullptr;
-  std::unique_ptr mTracker = nullptr;
+  std::unique_ptr> mTracker = nullptr;
+  std::unique_ptr> mTrackerL = nullptr;
   TStopwatch mTimer;
 };
 
diff --git a/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx
index 64bb585383486..6641981635740 100644
--- a/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx
+++ b/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx
@@ -94,8 +94,8 @@ void ClustererDPL::run(ProcessingContext& pc)
   }
   const o2::dataformats::ConstMCTruthContainerView labels(labelbuffer);
 
-  LOG(INFO) << "MFTClusterer pulled " << digits.size() << " digits, in "
-            << rofs.size() << " RO frames";
+  LOG(DEBUG) << "MFTClusterer pulled " << digits.size() << " digits, in "
+             << rofs.size() << " RO frames";
 
   o2::itsmft::DigitPixelReader reader;
   reader.setDigits(digits);
@@ -130,7 +130,7 @@ void ClustererDPL::run(ProcessingContext& pc)
 
   // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF
   // -> consider recalculationg maxROF
-  LOG(INFO) << "MFTClusterer pushed " << clusCompVec.size() << " compressed clusters, in " << clusROFVec.size() << " RO frames";
+  LOG(DEBUG) << "MFTClusterer pushed " << clusCompVec.size() << " compressed clusters, in " << clusROFVec.size() << " RO frames";
 }
 
 DataProcessorSpec getClustererSpec(bool useMC)
diff --git a/Detectors/ITSMFT/MFT/workflow/src/TrackWriterSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/TrackWriterSpec.cxx
index 99beec65b57ec..72821a8cff7ac 100644
--- a/Detectors/ITSMFT/MFT/workflow/src/TrackWriterSpec.cxx
+++ b/Detectors/ITSMFT/MFT/workflow/src/TrackWriterSpec.cxx
@@ -44,7 +44,7 @@ DataProcessorSpec getTrackWriterSpec(bool useMC)
     *tracksSize = tracks.size();
   };
   auto logger = [tracksSize](std::vector const& rofs) {
-    LOG(INFO) << "MFTTrackWriter pulled " << *tracksSize << " tracks, in " << rofs.size() << " RO frames";
+    LOG(DEBUG) << "MFTTrackWriter pulled " << *tracksSize << " tracks, in " << rofs.size() << " RO frames";
   };
   return MakeRootTreeWriterSpec("mft-track-writer",
                                 "mfttracks.root",
diff --git a/Detectors/ITSMFT/MFT/workflow/src/TrackerSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/TrackerSpec.cxx
index 670bdbf9848bc..2b785205d0eb8 100644
--- a/Detectors/ITSMFT/MFT/workflow/src/TrackerSpec.cxx
+++ b/Detectors/ITSMFT/MFT/workflow/src/TrackerSpec.cxx
@@ -53,6 +53,9 @@ void TrackerDPL::init(InitContext& ic)
     o2::base::Propagator::initFieldFromGRP(grp);
     auto field = static_cast(TGeoGlobalMagField::Instance()->GetField());
 
+    Bool_t continuous = mGRP->isDetContinuousReadOut("MFT");
+    LOG(INFO) << "MFTTracker RO: continuous=" << continuous;
+
     o2::base::GeometryManager::loadGeometry();
     o2::mft::GeometryTGeo* geom = o2::mft::GeometryTGeo::Instance();
     geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot,
@@ -61,16 +64,24 @@ void TrackerDPL::init(InitContext& ic)
     // tracking configuration parameters
     auto& trackingParam = MFTTrackingParam::Instance();
     // create the tracker: set the B-field, the configuration and initialize
-    mTracker = std::make_unique(mUseMC);
+
     double centerMFT[3] = {0, 0, -61.4}; // Field at center of MFT
     auto Bz = field->getBz(centerMFT);
-    if (Bz == 0) {
-      Bz = 0.1; // Temporary workaround for MFT tracking with magnet off;
-      LOG(INFO) << " Temporary workaround for MFT tracking with magnet off. Bz = " << Bz;
+    if (Bz != 0) {
+      LOG(INFO) << "Starting MFT tracker: Field is on!";
+      mFieldOn = true;
+      mTracker = std::make_unique>(mUseMC);
+      mTracker->setBz(Bz);
+      mTracker->initConfig(trackingParam, true);
+      mTracker->initialize(trackingParam.FullClusterScan);
+    } else {
+      LOG(INFO) << "Starting MFT Linear tracker: Field is off!";
+      mFieldOn = false;
+      mTrackerL = std::make_unique>(mUseMC);
+      mTrackerL->initConfig(trackingParam, true);
+      mTrackerL->initialize(trackingParam.FullClusterScan);
     }
-    mTracker->setBz(Bz);
-    mTracker->initConfig(trackingParam, true);
-    mTracker->initialize(trackingParam.FullClusterScan);
+
   } else {
     throw std::runtime_error(o2::utils::Str::concat_string("Cannot retrieve GRP from the ", filename));
   }
@@ -90,8 +101,7 @@ void TrackerDPL::run(ProcessingContext& pc)
   mTimer.Start(false);
   gsl::span patterns = pc.inputs().get>("patterns");
   auto compClusters = pc.inputs().get>("compClusters");
-  auto nTracksLTF = 0;
-  auto nTracksCA = 0;
+  auto ntracks = 0;
 
   // code further down does assignment to the rofs and the altered object is used for output
   // we therefore need a copy of the vector rather than an object created directly on the input data,
@@ -112,72 +122,110 @@ void TrackerDPL::run(ProcessingContext& pc)
               << mc2rofs.size() << " MC events";
   }
 
-  //std::vector tracks;
   auto& allClusIdx = pc.outputs().make>(Output{"MFT", "TRACKCLSID", 0, Lifetime::Timeframe});
   std::vector trackLabels;
   std::vector allTrackLabels;
-  std::vector tracksLTF;
-  std::vector tracksCA;
+  std::vector tracks;
+  std::vector tracksL;
   auto& allTracksMFT = pc.outputs().make>(Output{"MFT", "TRACKS", 0, Lifetime::Timeframe});
 
   std::uint32_t roFrame = 0;
-  o2::mft::ROframe event(0);
-
-  Bool_t continuous = mGRP->isDetContinuousReadOut("MFT");
-  LOG(INFO) << "MFTTracker RO: continuous=" << continuous;
-
-  // tracking configuration parameters
-  auto& trackingParam = MFTTrackingParam::Instance();
-
-  // snippet to convert found tracks to final output tracks with separate cluster indices
-  auto copyTracks = [&event](auto& tracks, auto& allTracks, auto& allClusIdx) {
-    for (auto& trc : tracks) {
-      trc.setExternalClusterIndexOffset(allClusIdx.size());
-      int ncl = trc.getNumberOfPoints();
-      for (int ic = 0; ic < ncl; ic++) {
-        auto externalClusterID = trc.getExternalClusterIndex(ic);
-        allClusIdx.push_back(externalClusterID);
+
+  if (mFieldOn) {
+    o2::mft::ROframe event(0);
+
+    // tracking configuration parameters
+    auto& trackingParam = MFTTrackingParam::Instance();
+
+    // snippet to convert found tracks to final output tracks with separate cluster indices
+    auto copyTracks = [&event](auto& tracks, auto& allTracks, auto& allClusIdx) {
+      for (auto& trc : tracks) {
+        trc.setExternalClusterIndexOffset(allClusIdx.size());
+        int ncl = trc.getNumberOfPoints();
+        for (int ic = 0; ic < ncl; ic++) {
+          auto externalClusterID = trc.getExternalClusterIndex(ic);
+          allClusIdx.push_back(externalClusterID);
+        }
+        allTracks.emplace_back(trc);
       }
-      allTracks.emplace_back(trc);
-    }
-  };
-
-  gsl::span::iterator pattIt = patterns.begin();
-  for (auto& rof : rofs) {
-    int nclUsed = ioutils::loadROFrameData(rof, event, compClusters, pattIt, mDict, labels, mTracker.get());
-    if (nclUsed) {
-      event.setROFrameId(roFrame);
-      event.initialize(trackingParam.FullClusterScan);
-      LOG(INFO) << "ROframe: " << roFrame << ", clusters loaded : " << nclUsed;
-      mTracker->setROFrame(roFrame);
-      mTracker->clustersToTracks(event);
-      tracksLTF.swap(event.getTracksLTF());
-      tracksCA.swap(event.getTracksCA());
-      nTracksLTF += tracksLTF.size();
-      nTracksCA += tracksCA.size();
-
-      if (mUseMC) {
-        mTracker->computeTracksMClabels(tracksLTF);
-        mTracker->computeTracksMClabels(tracksCA);
-        trackLabels.swap(mTracker->getTrackLabels());
-        std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels));
-        trackLabels.clear();
+    };
+
+    gsl::span::iterator pattIt = patterns.begin();
+    for (auto& rof : rofs) {
+      int nclUsed = ioutils::loadROFrameData(rof, event, compClusters, pattIt, mDict, labels, mTracker.get());
+      if (nclUsed) {
+        event.setROFrameId(roFrame);
+        event.initialize(trackingParam.FullClusterScan);
+        LOG(DEBUG) << "ROframe: " << roFrame << ", clusters loaded : " << nclUsed;
+        mTracker->setROFrame(roFrame);
+        mTracker->clustersToTracks(event);
+        tracks.swap(event.getTracks());
+        ntracks += tracks.size();
+
+        if (mUseMC) {
+          mTracker->computeTracksMClabels(tracks);
+          trackLabels.swap(mTracker->getTrackLabels());
+          std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels));
+          trackLabels.clear();
+        }
+
+        LOG(DEBUG) << "Found MFT tracks: " << tracks.size();
+        int first = allTracksMFT.size();
+        int number = tracks.size();
+        rof.setFirstEntry(first);
+        rof.setNEntries(number);
+        copyTracks(tracks, allTracksMFT, allClusIdx);
       }
+      roFrame++;
+    }
+  } else { // Use Linear Tracker for Field off
+    o2::mft::ROframe event(0);
+
+    // tracking configuration parameters
+    auto& trackingParam = MFTTrackingParam::Instance();
 
-      LOG(INFO) << "Found tracks LTF: " << tracksLTF.size();
-      LOG(INFO) << "Found tracks CA: " << tracksCA.size();
-      int first = allTracksMFT.size();
-      int number = tracksLTF.size() + tracksCA.size();
-      rof.setFirstEntry(first);
-      rof.setNEntries(number);
-      copyTracks(tracksLTF, allTracksMFT, allClusIdx);
-      copyTracks(tracksCA, allTracksMFT, allClusIdx);
+    // snippet to convert found tracks to final output tracks with separate cluster indices
+    auto copyTracks = [&event](auto& tracks, auto& allTracks, auto& allClusIdx) {
+      for (auto& trc : tracks) {
+        trc.setExternalClusterIndexOffset(allClusIdx.size());
+        int ncl = trc.getNumberOfPoints();
+        for (int ic = 0; ic < ncl; ic++) {
+          auto externalClusterID = trc.getExternalClusterIndex(ic);
+          allClusIdx.push_back(externalClusterID);
+        }
+        allTracks.emplace_back(trc);
+      }
+    };
+
+    gsl::span::iterator pattIt = patterns.begin();
+    for (auto& rof : rofs) {
+      int nclUsed = ioutils::loadROFrameData(rof, event, compClusters, pattIt, mDict, labels, mTrackerL.get());
+      if (nclUsed) {
+        event.setROFrameId(roFrame);
+        event.initialize(trackingParam.FullClusterScan);
+        LOG(INFO) << "ROframe: " << roFrame << ", clusters loaded : " << nclUsed;
+        mTrackerL->setROFrame(roFrame);
+        mTrackerL->clustersToTracks(event);
+        tracksL.swap(event.getTracks());
+        ntracks += tracksL.size();
+
+        if (mUseMC) {
+          mTrackerL->computeTracksMClabels(tracksL);
+          trackLabels.swap(mTrackerL->getTrackLabels());
+          std::copy(trackLabels.begin(), trackLabels.end(), std::back_inserter(allTrackLabels));
+          trackLabels.clear();
+        }
+
+        LOG(DEBUG) << "Found MFT tracks: " << tracks.size();
+        int first = allTracksMFT.size();
+        int number = tracksL.size();
+        rof.setFirstEntry(first);
+        rof.setNEntries(number);
+        copyTracks(tracksL, allTracksMFT, allClusIdx);
+      }
+      roFrame++;
     }
-    roFrame++;
   }
-
-  LOG(INFO) << "MFTTracker found " << nTracksLTF << " tracks LTF";
-  LOG(INFO) << "MFTTracker found " << nTracksCA << " tracks CA";
   LOG(INFO) << "MFTTracker pushed " << allTracksMFT.size() << " tracks";
 
   if (mUseMC) {