diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_emi_100GeV-101104.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_emi_100GeV-101104.json
index 6a457b299df5ab13110546ef453fd19e84880f60..89db76d6fba6ce5ffccb44cd3fc960118d86376e 100644
--- a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_emi_100GeV-101104.json
+++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_emi_100GeV-101104.json
@@ -1,5 +1,5 @@
 {
-    "file_length": 100,
+    "file_length": 200,
     "mass": 0.511,
     "maxE": 100.0,
     "minE": 100.0,
diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_epl_100GeV-101103.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_epl_100GeV-101103.json
index 02de3383c115c56eb3c327d23394809a1c0d912b..83c73af03df03cbbfdbb9da2f21d2e7fa879054e 100644
--- a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_epl_100GeV-101103.json
+++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_epl_100GeV-101103.json
@@ -1,5 +1,5 @@
 {
-    "file_length": 100,
+    "file_length": 200,
     "mass": 0.511,
     "maxE": 100.0,
     "minE": 100.0,
diff --git a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_gam_100GeV-102201.json b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_gam_100GeV-102201.json
index 11b14b31451de987fce19c7d7c3fa86fb2a94f45..2068c13e2f1c98aaedde8b3a24bf2e6278f13d69 100644
--- a/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_gam_100GeV-102201.json
+++ b/Control/CalypsoExample/Generation/data/mdc/FaserMC-MDC_PG_gam_100GeV-102201.json
@@ -1,5 +1,5 @@
 {
-    "file_length": 100,
+    "file_length": 200,
     "mass": 0.0,
     "maxE": 100.0,
     "minE": 100.0,
diff --git a/Generators/DIFGenerator/python/DIFSampler.py b/Generators/DIFGenerator/python/DIFSampler.py
index 69fe82660a4b9d9ae555799d2a8f76dbca5629c6..8ec22459aba93a430093c4bd7b2a3f13e2d0f206 100644
--- a/Generators/DIFGenerator/python/DIFSampler.py
+++ b/Generators/DIFGenerator/python/DIFSampler.py
@@ -5,7 +5,7 @@
 import ParticleGun as PG
 from math import sqrt, sin, cos, acos
 from random import uniform
-from AthenaCommon.SystemOfUnits import TeV, MeV
+from AthenaCommon.SystemOfUnits import TeV, GeV, MeV
 from AthenaCommon.PhysicalConstants import pi
 from ROOT import TLorentzVector
 
@@ -90,8 +90,12 @@ class DIFSampler(PG.ParticleSampler):
             else:
                 self.mom = None
 
-    def __init__(self, daughter1_pid = 11, daughter2_pid = -11, mother_pid = None, mother_mom = PG.EThetaMPhiSampler(sqrt((1*TeV)**2 + (10*MeV)**2),0,10*MeV,0),mother_pos = CylinderSampler([0, 100**2],[0, 2*pi],[-1500, 0],0)):
-        self._mother_sampler = PG.ParticleSampler(pid = mother_pid, mom = mother_mom, pos = mother_pos)
+    # def __init__(self, daughter1_pid = 11, daughter2_pid = -11, mother_pid = None, mother_mom = PG.EThetaMPhiSampler(sqrt((1*TeV)**2 + (10*MeV)**2),0,10*MeV,0),mother_pos = CylinderSampler([0, 100**2],[0, 2*pi],[-1500, 0],0)):
+    def __init__(self, daughter1_pid=13, daughter2_pid=-13, mother_pid=None,
+                 mother_mom=PG.EThetaMPhiSampler(sqrt((1*TeV)**2 + (500*MeV)**2), [0, 0.0002], 500*MeV, [0, 2*pi]),
+                 my_z_position=-1500):
+                 # mother_pos=CylinderSampler([0, 100**2], [0, 2*pi], [-1500, 0], 0)):
+        self._mother_sampler = PG.ParticleSampler(pid = mother_pid, mom = mother_mom, pos=CylinderSampler([0, 100**2], [0, 2*pi], my_z_position, 0))
 
         self.daughter1 = self.particle(daughter1_pid)
         self.daughter2 = self.particle(daughter2_pid)
diff --git a/Generators/FaserParticleGun/python/FaserParticleGunConfig.py b/Generators/FaserParticleGun/python/FaserParticleGunConfig.py
index 866a51beeca0107b71df42a165dfd54537450829..ac30494a4815f5bb06a5d67408b4c0551297a63b 100644
--- a/Generators/FaserParticleGun/python/FaserParticleGunConfig.py
+++ b/Generators/FaserParticleGun/python/FaserParticleGunConfig.py
@@ -190,7 +190,8 @@ def FaserParticleGunForeseeCfg(ConfigFlags, **kwargs) :
     return cfg
 
 def FaserParticleGunCfg(ConfigFlags) :
-    generator = ConfigFlags.Sim.Gun.setdefault("Generator", "SingleParticle")
+    # generator = ConfigFlags.Sim.Gun.setdefault("Generator", "SingleParticle")
+    generator = ConfigFlags.Sim.Gun.setdefault("Generator", "DecayInFlight")
     kwargs = ConfigFlags.Sim.Gun
     if generator == "SingleEcalParticle" :
         return FaserParticleGunSingleEcalParticleCfg(ConfigFlags, **kwargs)
diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/CMakeLists.txt b/Tracker/TrackerRecAlgs/FaserSpacePoints/CMakeLists.txt
index 4978495c385798463bd84f20276920cdde578765..e88d445536b1770103382549c17e502e4f5f8b09 100644
--- a/Tracker/TrackerRecAlgs/FaserSpacePoints/CMakeLists.txt
+++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/CMakeLists.txt
@@ -1,12 +1,9 @@
-################################################################################
-# Package: FaserSpacePoints
-################################################################################
+atlas_subdir(FaserSpacePoints)
 
-# Declare the package name:
-atlas_subdir( FaserSpacePoints )
+atlas_add_component(
+  FaserSpacePoints
+  src/components/*.cxx src/*.cxx src/*.h
+  LINK_LIBRARIES AthenaBaseComps TrackerSimData TrackerSimEvent TrackerSpacePoint TrackerPrepRawData)
 
-atlas_add_component( FaserSpacePoints
-                     src/components/*.cxx src/*.cxx src/*.h
-	                   LINK_LIBRARIES AthenaBaseComps TrackerSpacePoint TrackerPrepRawData)
-
-atlas_install_python_modules( python/*.py )
\ No newline at end of file
+atlas_install_python_modules( python/*.py )
+atlas_install_scripts( test/*.py )
diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsConfig.py b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..36a2008a833453937a2adf9c4c1c2f3d81525362
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsConfig.py
@@ -0,0 +1,17 @@
+"""
+Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+"""
+
+from AthenaConfiguration.ComponentFactory import CompFactory
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+
+
+def FaserSpacePointsCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    Tracker__FaserSpacePoints = CompFactory.Tracker.FaserSpacePoints
+    acc.addEventAlgo(Tracker__FaserSpacePoints(**kwargs))
+
+    thistSvc = CompFactory.THistSvc()
+    thistSvc.Output += ["HIST DATAFILE='SpacePoints.root' OPT='RECREATE'"]
+    acc.addService(thistSvc)
+    return acc
diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py
index 48197207d0c1b321e658b74ddb2d40d74ee244dd..78bae901d8c5319dd35ad4f101ff5cb291740395 100644
--- a/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py
+++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/python/FaserSpacePointsCosmics.py
@@ -22,7 +22,6 @@ Tracker__TruthSeededTrackFinder, THistSvc=CompFactory.getComps("Tracker::FaserSp
 def TruthSeededTrackFinderBasicCfg(flags, **kwargs):
     """Return ComponentAccumulator for TruthSeededTrackFinder"""
     acc = FaserSCT_GeometryCfg(flags)
-    kwargs.setdefault("SpacePointsSCTName", "SCT_SpacePointContainer")
     acc.addEventAlgo(Tracker__TruthSeededTrackFinder(**kwargs))
    # attach ToolHandles
     return acc
diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.cxx b/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.cxx
index b9722a7c2f4318fd6d8e4cf2c76437ced6078d8e..caa4af80a79286b6bdb76e18754541f7ee498568 100644
--- a/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.cxx
+++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.cxx
@@ -1,104 +1,128 @@
 #include "FaserSpacePoints.h"
 #include "Identifier/Identifier.h"
+#include "TrackerSimEvent/FaserSiHit.h"
 #include "TrackerSpacePoint/FaserSCT_SpacePoint.h"
 #include "TrackerPrepRawData/FaserSCT_ClusterCollection.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrackerReadoutGeometry/SCT_DetectorManager.h"
+
 
 namespace Tracker {
-  FaserSpacePoints::FaserSpacePoints(const std::string& name, ISvcLocator* pSvcLocator)
-    : AthReentrantAlgorithm(name, pSvcLocator) { }
 
-  
-  StatusCode FaserSpacePoints::initialize() {
-    ATH_MSG_INFO(name() << "::" << __FUNCTION__);
+FaserSpacePoints::FaserSpacePoints(const std::string& name, ISvcLocator* pSvcLocator)
+  : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name),
+    m_histSvc("THistSvc/THistSvc", name) {}
+
+
+StatusCode FaserSpacePoints::initialize() {
+  ATH_CHECK(m_spacePointContainerKey.initialize());
+  ATH_CHECK(m_siHitCollectionKey.initialize());
+  ATH_CHECK(m_simDataCollectionKey.initialize());
+  ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+  ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT"));
+  m_tree = new TTree("tree", "tree");
+  m_tree->Branch("run", &m_run, "run/I");
+  m_tree->Branch("event", &m_event, "event/I");
+  m_tree->Branch("station", &m_station, "station/I");
+  m_tree->Branch("layer", &m_layer, "layer/I");
+  m_tree->Branch("phi", &m_phi, "phi/I");
+  m_tree->Branch("eta", &m_eta, "eta/I");
+  m_tree->Branch("side", &m_side, "side/I");
+  m_tree->Branch("x", &m_x, "x/D");
+  m_tree->Branch("y", &m_y, "y/D");
+  m_tree->Branch("z", &m_z, "z/D");
+  m_tree->Branch("muon_hit", &m_muon_hit, "muon_hit/B");
+  m_tree->Branch("tx", &m_tx, "tx/D");
+  m_tree->Branch("ty", &m_ty, "ty/D");
+  m_tree->Branch("tz", &m_tz, "tz/D");
+  ATH_CHECK(histSvc()->regTree("/HIST/spacePoints", m_tree));
+  return StatusCode::SUCCESS;
+}
 
-    if ( m_sct_spcontainer.key().empty()) {
-      ATH_MSG_FATAL( "SCTs selected and no name set for SCT clusters");
-      return StatusCode::FAILURE;
-    }
-    ATH_CHECK( m_sct_spcontainer.initialize() );
 
-    ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+StatusCode FaserSpacePoints::finalize() {
+  return StatusCode::SUCCESS;
+}
 
-    std::string filePath = m_filePath;
-    m_outputFile = TFile::Open(filePath.c_str(), "RECREATE");
-    if (m_outputFile == nullptr) {
-      ATH_MSG_ERROR("Unable to open output file at " << m_filePath);
-      return StatusCode::FAILURE;
-    }
-    m_outputFile->cd();
+bool FaserSpacePoints::muon_hit(const TrackerSimDataCollection* simDataMap, Identifier id) const {
+  // check if Identifier in simDataMap
+  if (!simDataMap->count(id)) {
+    return false;
+  }
+  // check if hit originates from a muon (if the pdg code of the hit is -13)
+  TrackerSimData simData = simDataMap->at(id);
+  const std::vector<TrackerSimData::Deposit>& deposits = simData.getdeposits();
+  auto it = std::find_if(
+      deposits.begin(), deposits.end(), [](TrackerSimData::Deposit deposit) {
+        return deposit.first->pdg_id() == -13;
+      });
+  return it != deposits.end();
+}
 
-    std::string treeName = m_treeName;
-    m_outputTree = new TTree(treeName.c_str(), "tree");
-    if (m_outputTree == nullptr) {
-      ATH_MSG_ERROR("Unable to create TTree");
-      return StatusCode::FAILURE;
-    }
+StatusCode FaserSpacePoints::execute(const EventContext& ctx) const {
+  m_run = ctx.eventID().run_number();
+  m_event = ctx.eventID().event_number();
 
-    FaserSpacePoints::initializeTree();
-    return StatusCode::SUCCESS;
-  }
+  SG::ReadHandle<FaserSCT_SpacePointContainer> spacePointContainer {m_spacePointContainerKey, ctx};
+  ATH_CHECK(spacePointContainer.isValid());
 
-  
-  StatusCode FaserSpacePoints::finalize() {
-    ATH_MSG_INFO(name() << "::" << __FUNCTION__);
-    m_outputFile->cd();
-    m_outputTree->Write();
-    return StatusCode::SUCCESS;
-  }
+  SG::ReadHandle<FaserSiHitCollection> siHitCollection {m_siHitCollectionKey, ctx};
+  ATH_CHECK(siHitCollection.isValid());
+
+  SG::ReadHandle<TrackerSimDataCollection> simDataCollection {m_simDataCollectionKey, ctx};
+  ATH_CHECK(simDataCollection.isValid());
 
-  
-  StatusCode FaserSpacePoints::execute(const EventContext& ctx) const {
-    ATH_MSG_INFO(name() << "::" << __FUNCTION__);
-  
-    m_run = ctx.eventID().run_number();
-    m_event = ctx.eventID().event_number();
-    ATH_MSG_DEBUG("run = " << m_run);
-    ATH_MSG_DEBUG("event = " << m_event);
-
-    SG::ReadHandle<FaserSCT_SpacePointContainer> sct_spcontainer( m_sct_spcontainer, ctx );
-    if (!sct_spcontainer.isValid()){
-      ATH_MSG_FATAL("Could not find the data object " << sct_spcontainer.name());
-      return StatusCode::RECOVERABLE;
+
+  // create map of the IdentifierHash of a SCT sensor and the true position of the corresponding hit
+  std::map<IdentifierHash, HepGeom::Point3D<double>> truePositions;
+  for (const FaserSiHit& hit: *siHitCollection) {
+    if ((!hit.particleLink()) || (hit.particleLink()->pdg_id() != -13)) {
+      continue;
+    }
+    Identifier waferId = m_idHelper->wafer_id(hit.getStation(), hit.getPlane(), hit.getRow(), hit.getModule(), hit.getSensor());
+    IdentifierHash waferHash = m_idHelper->wafer_hash(waferId);
+    const HepGeom::Point3D<double> localPosition = hit.localStartPosition();
+    const TrackerDD::SiDetectorElement* element = m_detMgr->getDetectorElement(waferId);
+    if (element) {
+      const HepGeom::Point3D<double> globalPosition =
+          Amg::EigenTransformToCLHEP(element->transformHit()) * localPosition;
+      truePositions[waferHash] = globalPosition;
     }
+  }
+
 
-    m_nCollections = sct_spcontainer->size();
-    ATH_MSG_DEBUG("nCollections = " << m_nCollections);
-    FaserSCT_SpacePointContainer::const_iterator it = sct_spcontainer->begin();
-    FaserSCT_SpacePointContainer::const_iterator it_end = sct_spcontainer->end();
-
-    for(; it != it_end; ++it) {
-      const FaserSCT_SpacePointCollection* col = *it;
-      m_nSpacepoints = col->size();
-      ATH_MSG_DEBUG("nSpacepoints = " << m_nSpacepoints);
-
-      FaserSCT_SpacePointCollection::const_iterator it_sp = col->begin();
-      FaserSCT_SpacePointCollection::const_iterator it_sp_end = col->end();
-      for (; it_sp != it_sp_end; ++it_sp) {
-        const FaserSCT_SpacePoint* sp = *it_sp;
-        const auto id = sp->clusterList().first->identify();
-        int station = m_idHelper->station(id);
-        int plane = m_idHelper->layer(id);
-        m_layer = (station - 1) * 3 + plane;
-
-        Amg::Vector3D position = sp->globalPosition();
-        m_x = position.x();
-        m_y = position.y();
-        m_z = position.z();
-
-        m_outputTree->Fill();
+  for (const FaserSCT_SpacePointCollection* spacePointCollection : *spacePointContainer) {
+    for (const FaserSCT_SpacePoint* spacePoint : *spacePointCollection) {
+      Identifier id1 = spacePoint->cluster1()->identify();
+      Identifier id2 = spacePoint->cluster2()->identify();
+      m_station = m_idHelper->station(id1);
+      m_layer = m_idHelper->layer(id1);
+      m_phi = m_idHelper->phi_module(id1);
+      m_eta = m_idHelper->eta_module(id1);
+      m_side = m_idHelper->side(id1);
+      // check if both clusters originate from a muon
+      m_muon_hit = (muon_hit(simDataCollection.get(), id1) && muon_hit(simDataCollection.get(), id2));
+      // global reconstructed position of space point
+      Amg::Vector3D position = spacePoint->globalPosition();
+      m_x = position.x();
+      m_y = position.y();
+      m_z = position.z();
+      // global true position of simulated hit
+      IdentifierHash waferHash = spacePoint->elementIdList().first;
+      if (truePositions.count(waferHash)) {
+        auto truePosition = truePositions[waferHash];
+        m_tx = truePosition.x();
+        m_ty = truePosition.y();
+        m_tz = truePosition.z();
+      } else {
+        m_tx = -1;
+        m_ty = -1;
+        m_tz = -1;
       }
+      m_tree->Fill();
     }
-    return StatusCode::SUCCESS;
   }
+  return StatusCode::SUCCESS;
+}
 
-  void FaserSpacePoints::initializeTree() {
-    m_outputTree->Branch("run", &m_run);
-    m_outputTree->Branch("event", &m_event);
-    m_outputTree->Branch("layer", &m_layer);
-    m_outputTree->Branch("n_collections", &m_nCollections);
-    m_outputTree->Branch("n_spacepoints", &m_nSpacepoints);
-    m_outputTree->Branch("x", &m_x);
-    m_outputTree->Branch("y", &m_y);
-    m_outputTree->Branch("z", &m_z);
-  }
 }
diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.h b/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.h
index 28807d73e7ac7939c5b830a758846028feedb815..1cc43f65e2f1a674b692487a26421ad526b466f3 100644
--- a/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.h
+++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/src/FaserSpacePoints.h
@@ -2,45 +2,70 @@
 #define FASERSPACEPOINTS_H
 
 #include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "AthenaBaseComps/AthHistogramming.h"
 #include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrackerSimEvent/FaserSiHitCollection.h"
 #include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h"
+#include "TrackerSimData/TrackerSimDataCollection.h"
 #include <string>
 #include <atomic>
 
 #include "TTree.h"
 #include "TFile.h"
 
+class FaserSCT_ID;
+namespace  TrackerDD {
+class SCT_DetectorManager;
+}
+
+
 namespace Tracker {
-  class FaserSpacePoints : public AthReentrantAlgorithm {
-   public:
-    FaserSpacePoints(const std::string& name, ISvcLocator* pSvcLocator);
-    virtual ~FaserSpacePoints() = default;
-
-    virtual StatusCode initialize() override;
-    virtual StatusCode execute(const EventContext& ctx) const override;
-    virtual StatusCode finalize() override;
-
-   private:
-    void initializeTree();
-
-    mutable int m_run{0};
-    mutable int m_event{0};
-    mutable int m_layer{0};
-    mutable int m_nCollections{0};
-    mutable int m_nSpacepoints{0};
-    mutable float m_x{0};
-    mutable float m_y{0};
-    mutable float m_z{0};
-
-    const FaserSCT_ID* m_idHelper{nullptr};
-    SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_sct_spcontainer{this, "SpacePointsSCTName", "SCT spacepoint container"};
-
-    Gaudi::Property<std::string> m_filePath{this, "FilePath", "spacepoints.root", "Output root file for spacepoints"};
-    Gaudi::Property<std::string> m_treeName{this, "TreeName", "tree", ""};
-
-    TFile* m_outputFile;
-    TTree* m_outputTree;
-  };
+
+class FaserSpacePoints : public AthReentrantAlgorithm, AthHistogramming {
+ public:
+  FaserSpacePoints(const std::string& name, ISvcLocator* pSvcLocator);
+  virtual ~FaserSpacePoints() = default;
+
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext& ctx) const override;
+  virtual StatusCode finalize() override;
+
+  const ServiceHandle<ITHistSvc>& histSvc() const;
+
+ private:
+  const FaserSCT_ID* m_idHelper{nullptr};
+  const TrackerDD::SCT_DetectorManager* m_detMgr {nullptr};
+  bool muon_hit(const TrackerSimDataCollection* simDataMap, Identifier id) const;
+  ServiceHandle<ITHistSvc> m_histSvc;
+
+  SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_spacePointContainerKey {
+    this, "SpacePoints", "SCT_SpacePointContainer"};
+  SG::ReadHandleKey<FaserSiHitCollection> m_siHitCollectionKey {
+    this, "FaserSiHitCollection", "SCT_Hits"};
+  SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollectionKey {
+    this, "TrackerSimDataCollection", "SCT_SDO_Map"};
+
+  mutable TTree* m_tree;
+  mutable int m_run {0};
+  mutable int m_event {0};
+  mutable int m_station {0};
+  mutable int m_layer {0};
+  mutable int m_phi {0};
+  mutable int m_eta {0};
+  mutable int m_side {0};
+  mutable double m_x {0};
+  mutable double m_y {0};
+  mutable double m_z {0};
+  mutable bool m_muon_hit {false};
+  mutable double m_tx {0};
+  mutable double m_ty {0};
+  mutable double m_tz {0};
+};
+
+inline const ServiceHandle<ITHistSvc>& FaserSpacePoints::histSvc() const {
+  return m_histSvc;
+}
+
 }
 
 #endif // FASERSPACEPOINTS_H
diff --git a/Tracker/TrackerRecAlgs/FaserSpacePoints/test/FaserSpacePointsDbg.py b/Tracker/TrackerRecAlgs/FaserSpacePoints/test/FaserSpacePointsDbg.py
new file mode 100644
index 0000000000000000000000000000000000000000..a3d50f97a2127b4b33fec1c9cf50ab85218e8621
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/FaserSpacePoints/test/FaserSpacePointsDbg.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+import sys
+from AthenaCommon.Logging import log
+from AthenaCommon.Constants import DEBUG
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
+from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg
+from FaserSpacePoints.FaserSpacePointsConfig import FaserSpacePointsCfg
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+ConfigFlags.Input.Files = ['my.RDO.pool.root']
+ConfigFlags.Output.ESDFileName = "spacePoints.ESD.pool.root"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.lock()
+
+# Core components
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags))
+acc.merge(TrackerSpacePointFinderCfg(ConfigFlags))
+acc.merge(FaserSpacePointsCfg(ConfigFlags))
+acc.getEventAlgo("Tracker::FaserSpacePoints").OutputLevel = DEBUG
+
+sc = acc.run(maxEvents=1000)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/MCEvents/CMakeLists.txt b/Tracker/TrackerRecAlgs/MCEvents/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..edb6005ad67fab4e0fbb377aadee3a5fe3934235
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MCEvents/CMakeLists.txt
@@ -0,0 +1,10 @@
+atlas_subdir(MCEvents)
+
+atlas_add_component(
+        MCEvents
+        src/MCEventsAlg.h
+        src/MCEventsAlg.cxx
+        src/components/MCEvents_entries.cxx
+        LINK_LIBRARIES AthenaBaseComps GeneratorObjects StoreGateLib TrackerIdentifier TrackerSimEvent GaudiKernel)
+atlas_install_python_modules(python/*.py)
+atlas_install_scripts(test/*.py)
diff --git a/Tracker/TrackerRecAlgs/MCEvents/python/MCEventsConfig.py b/Tracker/TrackerRecAlgs/MCEvents/python/MCEventsConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..87fabb5738421fa804d7b6eced90c6a074a3829c
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MCEvents/python/MCEventsConfig.py
@@ -0,0 +1,9 @@
+from AthenaConfiguration.ComponentFactory import CompFactory
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+
+
+def MCEventsCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    mc_events_alg = CompFactory.MCEventsAlg
+    acc.addEventAlgo(mc_events_alg (**kwargs))
+    return acc
diff --git a/Tracker/TrackerRecAlgs/MCEvents/python/__init__.py b/Tracker/TrackerRecAlgs/MCEvents/python/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.cxx b/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e825850298b692e6841528cd61a897c3c3f584ff
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.cxx
@@ -0,0 +1,53 @@
+#include "MCEventsAlg.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+
+
+MCEventsAlg::MCEventsAlg(const std::string& name, ISvcLocator* pSvcLocator)
+    : AthReentrantAlgorithm(name, pSvcLocator) {}
+
+
+StatusCode MCEventsAlg::initialize() {
+  ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID"));
+  ATH_CHECK(m_mcEventKey.initialize());
+  ATH_CHECK(m_faserSiHitKey.initialize());
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode MCEventsAlg::execute(const EventContext& ctx) const {
+  SG::ReadHandle<FaserSiHitCollection> siHitCollection (m_faserSiHitKey, ctx);
+  std::map<int, std::vector<const FaserSiHit*>> particle_map {};
+  ATH_CHECK(siHitCollection.isValid());
+  for (const FaserSiHit& hit : *siHitCollection) {
+    int barcode = hit.particleLink().barcode();
+    particle_map[barcode].push_back(&hit);
+  }
+
+  SG::ReadHandle<McEventCollection> mcEvents (m_mcEventKey, ctx);
+  ATH_CHECK(mcEvents.isValid());
+  for (const HepMC::GenEvent* evt : *mcEvents) {
+    for (const HepMC::GenParticle* p : evt->particle_range()) {
+      const HepMC::FourVector vertex = p->production_vertex()->position();
+      const HepMC::FourVector momentum = p->momentum();
+      ATH_MSG_DEBUG("pdg: " << p->pdg_id() << ", barcode: " << p->barcode());
+      ATH_MSG_DEBUG("vertex: " << vertex.x() << ", " << vertex.y() << ", " << vertex.z());
+      ATH_MSG_DEBUG("momentum: " << momentum.px() << ", " << momentum.py() << ", " << momentum.pz());
+      auto hits = particle_map[p->barcode()];
+      for (const FaserSiHit* hit : hits) {
+        int station = hit->getStation();
+        int layer = hit->getPlane();
+        int phi = hit->getRow();
+        int eta = hit->getModule();
+        int side = hit->getSensor();
+        ATH_MSG_DEBUG(station << "/" << layer << "/" << phi << "/" << eta << "/" << side);
+      }
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode MCEventsAlg::finalize() {
+  return StatusCode::SUCCESS;
+}
diff --git a/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.h b/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..6b28d076f21f593e1ea0530e6148e55b22f28fd5
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MCEvents/src/MCEventsAlg.h
@@ -0,0 +1,26 @@
+#ifndef MCEVENTS_MCEVENTSALG_H
+#define MCEVENTS_MCEVENTSALG_H
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "TrackerSimEvent/FaserSiHitCollection.h"
+#include "GeneratorObjects/McEventCollection.h"
+
+class FaserSCT_ID;
+
+class MCEventsAlg : public AthReentrantAlgorithm {
+public:
+  MCEventsAlg(const std::string& name, ISvcLocator* pSvcLocator);
+  virtual ~MCEventsAlg() = default;
+
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext& ctx) const override;
+  virtual StatusCode finalize() override;
+
+private:
+  const FaserSCT_ID* m_idHelper {nullptr};
+  SG::ReadHandleKey<McEventCollection> m_mcEventKey { this, "McEventCollection", "BeamTruthEvent" };
+  SG::ReadHandleKey<FaserSiHitCollection> m_faserSiHitKey { this, "FaserSiHitCollection", "SCT_Hits" };
+};
+
+
+#endif // MCEVENTS_MCEVENTSALG_H
diff --git a/Tracker/TrackerRecAlgs/MCEvents/src/components/MCEvents_entries.cxx b/Tracker/TrackerRecAlgs/MCEvents/src/components/MCEvents_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..2fbef91d7d22c81a1d230bee04fc9a88b5a1daaa
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MCEvents/src/components/MCEvents_entries.cxx
@@ -0,0 +1,3 @@
+#include "../MCEventsAlg.h"
+
+DECLARE_COMPONENT(MCEventsAlg)
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/MCEvents/test/MCEventsDbg.py b/Tracker/TrackerRecAlgs/MCEvents/test/MCEventsDbg.py
new file mode 100644
index 0000000000000000000000000000000000000000..b8e6ad587cdb132f93b7e1d57c5b958c9270fd9b
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MCEvents/test/MCEventsDbg.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+import sys
+from AthenaCommon.Logging import log
+from AthenaCommon.Constants import DEBUG
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from MCEvents.MCEventsConfig import MCEventsCfg
+
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+# Configure
+ConfigFlags.Input.Files = ['my.RDO.pool.root']
+ConfigFlags.Output.ESDFileName = "MCEvents.ESD.root"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.lock()
+
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+acc.merge(MCEventsCfg(ConfigFlags))
+acc.getEventAlgo("MCEventsAlg").OutputLevel = DEBUG
+
+sc = acc.run(maxEvents=10)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/MyClusters/CMakeLists.txt b/Tracker/TrackerRecAlgs/MyClusters/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..751e1f04a43c5f154013f81a2a74b44495df5dea
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyClusters/CMakeLists.txt
@@ -0,0 +1,11 @@
+atlas_subdir(MyClusters)
+
+atlas_add_component(
+  MyClusters
+  src/MyClustersAlg.h
+  src/MyClustersAlg.cxx
+  src/components/MyClusters_entries.cxx
+  LINK_LIBRARIES AthenaBaseComps GeneratorObjects TrackerPrepRawData StoreGateLib GaudiKernel)
+
+atlas_install_python_modules(python/*.py)
+atlas_install_scripts(test/*.py)
diff --git a/Tracker/TrackerRecAlgs/MyClusters/python/MyClustersConfig.py b/Tracker/TrackerRecAlgs/MyClusters/python/MyClustersConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..64757e1a96f8dff63993a8a2275ca5cc2db0b7c2
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyClusters/python/MyClustersConfig.py
@@ -0,0 +1,17 @@
+"""
+Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+"""
+
+from AthenaConfiguration.ComponentFactory import CompFactory
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+
+
+def MyClustersCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    my_clusters_alg = CompFactory.MyClustersAlg
+    acc.addEventAlgo(my_clusters_alg (**kwargs))
+
+    thistSvc = CompFactory.THistSvc()
+    thistSvc.Output += ["HIST DATAFILE='MyClusters.root' OPT='RECREATE'"]
+    acc.addService(thistSvc)
+    return acc
diff --git a/Tracker/TrackerRecAlgs/MyClusters/python/__init__.py b/Tracker/TrackerRecAlgs/MyClusters/python/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.cxx b/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..050e5bed4949ad32855e899196bac03f91634ba8
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.cxx
@@ -0,0 +1,70 @@
+#include "MyClustersAlg.h"
+#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h"
+#include "TrackerPrepRawData/FaserSCT_Cluster.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+
+
+MyClustersAlg::MyClustersAlg(const std::string& name, ISvcLocator* pSvcLocator)
+    : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name),
+      m_histSvc("THistSvc/THistSvc", name) {}
+
+
+StatusCode MyClustersAlg::initialize() {
+  ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+
+  ATH_CHECK(m_clusterContainerKey.initialize());
+
+  m_tree = new TTree("tree", "tree");
+  m_tree->Branch("run", &m_run, "run/I");
+  m_tree->Branch("event", &m_event, "event/I");
+  m_tree->Branch("station", &m_station, "station/I");
+  m_tree->Branch("layer", &m_layer, "layer/I");
+  m_tree->Branch("phi", &m_phi, "phi/I");
+  m_tree->Branch("eta", &m_eta, "eta/I");
+  m_tree->Branch("side", &m_side, "side/I");
+  m_tree->Branch("x", &m_x, "x/D");
+  m_tree->Branch("y", &m_y, "y/D");
+  m_tree->Branch("z", &m_z, "z/D");
+  m_tree->Branch("lx", &m_lx, "lx/D");
+  m_tree->Branch("ly", &m_ly, "ly/D");
+  ATH_CHECK(histSvc()->regTree("/HIST/clusters", m_tree));
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode MyClustersAlg::execute(const EventContext& ctx) const {
+  m_run = ctx.eventID().run_number();
+  m_event = ctx.eventID().event_number();
+
+  SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer {m_clusterContainerKey, ctx};
+  ATH_CHECK(clusterContainer.isValid());
+
+  for (const auto& clusterCollection : *clusterContainer) {
+    for (const auto& cluster : *clusterCollection) {
+      auto id = cluster->identify();
+      m_station = m_idHelper->station(id);
+      m_layer = m_idHelper->layer(id);
+      m_eta = m_idHelper->eta_module(id);
+      m_phi = m_idHelper->phi_module(id);
+      m_side = m_idHelper->side(id);
+      auto localPos = cluster->localPosition();
+      m_lx = localPos.x();
+      m_ly = localPos.y();
+      auto localCov = cluster->localCovariance();
+      auto pos = cluster->globalPosition();
+      m_x = pos.x();
+      m_y = pos.y();
+      m_z = pos.z();
+      m_tree->Fill();
+      ATH_MSG_DEBUG("global position\n" << pos);
+      ATH_MSG_DEBUG("local position\n" << localPos);
+      ATH_MSG_DEBUG("local covariance\n" << localCov);
+    }
+  }
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode MyClustersAlg::finalize() {
+  return StatusCode::SUCCESS;
+}
diff --git a/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.h b/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..04c6202a7e7f36a886a25d854ef31fae2e555946
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyClusters/src/MyClustersAlg.h
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2021 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef MYCLUSTERS_MYCLUSTERSALG_H
+#define MYCLUSTERS_MYCLUSTERSALG_H
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "AthenaBaseComps/AthHistogramming.h"
+#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h"
+
+class TTree;
+class FaserSCT_ID;
+
+class MyClustersAlg : public AthReentrantAlgorithm, AthHistogramming {
+public:
+  MyClustersAlg(const std::string& name, ISvcLocator* pSvcLocator);
+  virtual ~MyClustersAlg() = default;
+
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext& ctx) const override;
+  virtual StatusCode finalize() override;
+
+  const ServiceHandle<ITHistSvc>& histSvc() const;
+
+private:
+  SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainerKey {
+      this, "FaserSCT_ClusterContainer", "SCT_ClusterContainer", "cluster container"};
+  ServiceHandle<ITHistSvc> m_histSvc;
+  const FaserSCT_ID* m_idHelper {nullptr};
+  mutable TTree* m_tree;
+
+  mutable unsigned int m_run;
+  mutable unsigned int m_event;
+  mutable unsigned int m_station;
+  mutable unsigned int m_layer;
+  mutable int m_eta;
+  mutable int m_phi;
+  mutable int m_side;
+  mutable double m_lx;
+  mutable double m_ly;
+  mutable double m_x;
+  mutable double m_y;
+  mutable double m_z;
+};
+
+
+inline const ServiceHandle<ITHistSvc>& MyClustersAlg::histSvc() const {
+  return m_histSvc;
+}
+
+
+#endif  // MYCLUSTERS_MYCLUSTERSALG_H
diff --git a/Tracker/TrackerRecAlgs/MyClusters/src/components/MyClusters_entries.cxx b/Tracker/TrackerRecAlgs/MyClusters/src/components/MyClusters_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..93cf0f53b350ced62ddc1c00a401a082fbb68f2a
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyClusters/src/components/MyClusters_entries.cxx
@@ -0,0 +1,3 @@
+#include "../MyClustersAlg.h"
+
+DECLARE_COMPONENT(MyClustersAlg)
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/MyClusters/test/MyClustersDbg.py b/Tracker/TrackerRecAlgs/MyClusters/test/MyClustersDbg.py
new file mode 100644
index 0000000000000000000000000000000000000000..c4ae4953adbe00bf94bcb2933d20bff32fcc107b
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyClusters/test/MyClustersDbg.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+import sys
+from AthenaCommon.Logging import log
+from AthenaCommon.Constants import DEBUG
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
+from MyClusters.MyClustersConfig import MyClustersCfg
+
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+# Configure
+ConfigFlags.Input.Files = ['my.RDO.pool.root']
+ConfigFlags.Output.ESDFileName = "MyClusters.ESD.root"
+ConfigFlags.Output.AODFileName = "MyClsuters.AOD.pool.root"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.lock()
+
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags))
+acc.merge(MyClustersCfg(ConfigFlags))
+acc.getEventAlgo("MyClustersAlg").OutputLevel = DEBUG
+
+sc = acc.run(maxEvents=10)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/CMakeLists.txt b/Tracker/TrackerRecAlgs/MyExtrapolationExample/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..72f4a7ac272d63a1060b39cb89a222fb4fc4e026
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/CMakeLists.txt
@@ -0,0 +1,12 @@
+atlas_subdir(MyExtrapolationExample)
+
+atlas_add_component(
+        MyExtrapolationExample
+        src/MyExtrapolationExample.h
+        src/MyExtrapolationExample.cxx
+        src/components/MyExtrapolationExample_entries.cxx
+        LINK_LIBRARIES AthenaBaseComps StoreGateLib GeneratorObjects FaserActsGeometryLib TrackerSimEvent TrackerIdentifier TrackerReadoutGeometry
+)
+
+atlas_install_python_modules(python/*.py)
+atlas_install_scripts(test/*.py)
diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/MyExtrapolationExampleConfig.py b/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/MyExtrapolationExampleConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..6c2738946d33457377968f29831b007461af969e
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/MyExtrapolationExampleConfig.py
@@ -0,0 +1,30 @@
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg
+
+# def FaserActsTrackingGeometrySvcCfg(flags, **kwargs):
+#     acc = ComponentAccumulator()
+#     FaserActsTrackingGeometrySvc = CompFactory.FaserActsTrackingGeometrySvc
+#     acc.addService(FaserActsTrackingGeometrySvc(name="FaserActsTrackingGeometrySvc", **kwargs))
+#     return acc
+
+# def FaserActsAlignmentCondAlgCfg(flags, **kwargs):
+#     acc = ComponentAccumulator()
+#     acc.addCondAlgo(CompFactory.FaserActsAlignmentCondAlg(name="FaserActsAlignmentCondAlg", **kwargs))
+#     return acc
+
+def MyExtrapolationExampleCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    acc.merge(MagneticFieldSvcCfg(flags))
+    # acc.merge(FaserActsTrackingGeometrySvcCfg(flags))
+    # acc.merge(FaserActsAlignmentCondAlgCfg(flags))
+
+    actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool")
+    actsExtrapolationTool.MaxSteps = 1000
+    actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool")
+
+    my_extrapolation_example = CompFactory.Tracker.MyExtrapolationExample(**kwargs)
+    my_extrapolation_example.ExtrapolationTool = actsExtrapolationTool
+    acc.addEventAlgo(my_extrapolation_example)
+    return acc
diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/__init__.py b/Tracker/TrackerRecAlgs/MyExtrapolationExample/python/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..aecebc372e415c6c58f1464706c6f25ea6001dc2
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx
@@ -0,0 +1,114 @@
+#include "MyExtrapolationExample.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+#include "GeoPrimitives/CLHEPtoEigenConverter.h"
+#include "Acts/Surfaces/PerigeeSurface.hpp"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrackerReadoutGeometry/SCT_DetectorManager.h"
+#include "TrackerReadoutGeometry/SiDetectorElement.h"
+#include <cmath>
+
+
+namespace Tracker {
+
+MyExtrapolationExample::MyExtrapolationExample(const std::string &name, ISvcLocator *pSvcLocator)
+    : AthReentrantAlgorithm(name, pSvcLocator) {}
+
+StatusCode MyExtrapolationExample::initialize() {
+  ATH_CHECK(m_mcEventCollectionKey.initialize());
+  ATH_CHECK(m_faserSiHitKey.initialize());
+  ATH_CHECK(m_extrapolationTool.retrieve());
+  ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+  ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT"));
+  return StatusCode::SUCCESS;
+}
+
+StatusCode MyExtrapolationExample::execute(const EventContext &ctx) const {
+  const Acts::GeometryContext gctx =
+      m_extrapolationTool->trackingGeometryTool()->getNominalGeometryContext().context();
+
+  std::vector<double> z_positions {};
+  SG::ReadHandle<FaserSiHitCollection> siHitCollection {m_faserSiHitKey, ctx};
+      ATH_CHECK(siHitCollection.isValid());
+  for (const FaserSiHit& hit : *siHitCollection) {
+    if ((hit.getStation() == 1) && (hit.getPlane() == 0) && (hit.getSensor() == 0)) {
+      if (hit.particleLink()) {
+        if (std::abs(hit.particleLink()->pdg_id()) != 13)
+          continue;
+        Identifier id = m_idHelper->wafer_id(hit.getStation(), hit.getPlane(), hit.getRow(), hit.getModule(), hit.getSensor());
+        const TrackerDD::SiDetectorElement* element = m_detMgr->getDetectorElement(id);
+        const HepGeom::Point3D<double> globalStartPosition =
+            Amg::EigenTransformToCLHEP(element->transformHit()) * hit.localStartPosition();
+        z_positions.push_back(globalStartPosition.z());
+        ATH_MSG_DEBUG("SiHit: " << globalStartPosition.x() << ", " << globalStartPosition.y() << ", " << globalStartPosition.z());
+      }
+    }
+  }
+
+  double z_mean = 0;
+  for (double z : z_positions) {
+    z_mean += z;
+  }
+  z_mean /= z_positions.size();
+
+  SG::ReadHandle<McEventCollection> mcEvents {m_mcEventCollectionKey, ctx};
+      ATH_CHECK(mcEvents.isValid());
+  if (mcEvents->size() != 1) {
+    ATH_MSG_ERROR("There should be exactly one event in the McEventCollection.");
+    return StatusCode::FAILURE;
+  }
+
+
+  for (const HepMC::GenParticle* particle : mcEvents->front()->particle_range()) {
+    if ((std::abs(particle->pdg_id()) != 13)) {
+      continue;
+    }
+    const HepMC::FourVector& vertex = particle->production_vertex()->position();
+    if (vertex.z() > 0) {
+      continue;
+    }
+    const HepMC::FourVector& momentum = particle->momentum();
+    double phi = momentum.phi();
+    double theta = momentum.theta();
+    double charge = particle->pdg_id() > 0 ? -1 : 1;
+    double abs_momentum = momentum.rho() * m_MeV2GeV;
+    double qop = charge / abs_momentum;
+    // The coordinate system of the Acts::PlaneSurface is defined as
+    // T = Z = normal, U = X x T = -Y, V = T x U = x
+//    Acts::BoundVector pars;
+//    pars << -vertex.y(), vertex.x(), phi, theta, qop, vertex.t();
+    Acts::BoundVector pars = Acts::BoundVector::Zero();
+    pars[Acts::eBoundLoc0] = -vertex.y();
+    pars[Acts::eBoundLoc1] = vertex.x();
+    pars[Acts::eBoundPhi] = phi;
+    pars[Acts::eBoundTheta] = theta;
+    pars[Acts::eBoundQOverP] = qop;
+    pars[Acts::eBoundTime] = vertex.t();
+
+    auto startSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+        Acts::Vector3(0, 0, vertex.z()), Acts::Vector3(0, 0, 1));
+    auto targetSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+        Acts::Vector3(0, 0, z_mean), Acts::Vector3(0, 0, 1));
+    Acts::BoundTrackParameters startParameters(
+        std::move(startSurface), pars, charge);
+    ATH_MSG_DEBUG("vertex: " << vertex.x() << ", " << vertex.y() << ", " << vertex.z());
+    ATH_MSG_DEBUG("vertex momentum: " << momentum.x() * m_MeV2GeV << ", " << momentum.y() * m_MeV2GeV << ", " << momentum.z() * m_MeV2GeV);
+    std::unique_ptr<const Acts::BoundTrackParameters> targetParameters =
+        m_extrapolationTool->propagate(ctx, startParameters, *targetSurface);
+    if (targetParameters) {
+      Acts::Vector3 targetPosition = targetParameters->position(gctx);
+      Acts::Vector3 targetMomentum = targetParameters->momentum();
+      ATH_MSG_DEBUG("vertex: " << vertex.x() << ", " << vertex.y() << ", " << vertex.z());
+      ATH_MSG_DEBUG("origin: " << targetPosition.x() << ", " << targetPosition.y() << ", " << targetPosition.z());
+      ATH_MSG_DEBUG("vertex momentum: " << momentum.x() * m_MeV2GeV << ", " << momentum.y() * m_MeV2GeV << ", " << momentum.z() * m_MeV2GeV);
+      ATH_MSG_DEBUG("origin momentum: " << targetMomentum.x() << ", " << targetMomentum.y() << ", " << targetMomentum.z());
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode MyExtrapolationExample::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+} // Tracker
diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.h b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.h
new file mode 100644
index 0000000000000000000000000000000000000000..cd5a2ed077310d3a07e5edd41787033593642c18
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.h
@@ -0,0 +1,42 @@
+/*
+Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef MYEXTRAPOLATIONEXAMPLE_MYEXTRAPOLATIONEXAMPLE_H
+#define MYEXTRAPOLATIONEXAMPLE_MYEXTRAPOLATIONEXAMPLE_H
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.h"
+#include "GeneratorObjects/McEventCollection.h"
+#include "TrackerSimEvent/FaserSiHitCollection.h"
+
+class FaserSCT_ID;
+namespace  TrackerDD {
+class SCT_DetectorManager;
+
+}
+namespace Tracker {
+
+class MyExtrapolationExample : public AthReentrantAlgorithm {
+ public:
+  MyExtrapolationExample(const std::string& name, ISvcLocator* pSvcLocator);
+
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext& ctx) const override;
+  virtual StatusCode finalize() override;
+
+private:
+  double m_MeV2GeV = 1e-3;
+  const FaserSCT_ID* m_idHelper {nullptr};
+  const TrackerDD::SCT_DetectorManager* m_detMgr {nullptr};
+  SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey {
+      this, "McEventCollection", "TruthEvent"};
+  SG::ReadHandleKey <FaserSiHitCollection> m_faserSiHitKey {
+    this, "FaserSiHitCollection", "SCT_Hits"};
+  ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool {
+    this, "ExtrapolationTool", "FaserActsExtrapolationTool"};
+};
+
+} // namespace Tracker
+
+#endif // MYEXTRAPOLATIONEXAMPLE_MYEXTRAPOLATIONEXAMPLE_H
diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/components/MyExtrapolationExample_entries.cxx b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/components/MyExtrapolationExample_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6601e0a3fe0e99d45ca137db49d8b63bb89573d1
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/components/MyExtrapolationExample_entries.cxx
@@ -0,0 +1,3 @@
+#include "../MyExtrapolationExample.h"
+
+DECLARE_COMPONENT(Tracker::MyExtrapolationExample)
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/test/MyExtrapolationExampleDbg.py b/Tracker/TrackerRecAlgs/MyExtrapolationExample/test/MyExtrapolationExampleDbg.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe83560fa4fe694fb643bfd514cfd2d2c8df4c14
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/test/MyExtrapolationExampleDbg.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+import sys
+from AthenaCommon.Logging import log
+from AthenaCommon.Constants import DEBUG, VERBOSE
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from MyExtrapolationExample.MyExtrapolationExampleConfig import MyExtrapolationExampleCfg
+
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+# Configure
+ConfigFlags.Input.Files = ['my.HITS.pool.root']
+ConfigFlags.Output.ESDFileName = "MyExtrapolationExample.ESD.root"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.lock()
+
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+acc.merge(MyExtrapolationExampleCfg(ConfigFlags))
+acc.getEventAlgo("Tracker::MyExtrapolationExample").OutputLevel = VERBOSE
+
+sc = acc.run(maxEvents=10)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/CMakeLists.txt b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f712d3881883fb0cdff9e8186b5b36578d48bf62
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/CMakeLists.txt
@@ -0,0 +1,12 @@
+atlas_subdir(TrackSeedPerformanceWriter)
+
+atlas_add_component(
+        TrackSeedPerformanceWriter
+        src/TrackSeedPerformanceWriter.h
+        src/TrackSeedPerformanceWriter.cxx
+        src/components/TrackSeedPerformanceWriter_entries.cxx
+        LINK_LIBRARIES AthenaBaseComps StoreGateLib TrkTrack TrackerSimData TrackerPrepRawData TrkRIO_OnTrack TrackerRIO_OnTrack
+)
+
+atlas_install_python_modules(python/*.py)
+atlas_install_scripts(test/*.py)
diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/TrackSeedPerformanceWriterConfig.py b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/TrackSeedPerformanceWriterConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..f8b0eca720b42ed668d7918bac86569007f4d68f
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/TrackSeedPerformanceWriterConfig.py
@@ -0,0 +1,30 @@
+"""
+Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+"""
+
+from AthenaConfiguration.ComponentFactory import CompFactory
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+
+
+
+def TrackSeedPerformanceWriterCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    kwargs.setdefault("TrackCollection", "SegmentFit")
+    TrackSeedPerformanceWriter = CompFactory.Tracker.TrackSeedPerformanceWriter
+    acc.addEventAlgo(TrackSeedPerformanceWriter(**kwargs))
+
+    itemList = ["xAOD::EventInfo#*",
+                "xAOD::EventAuxInfo#*",
+                "xAOD::FaserTriggerData#*",
+                "xAOD::FaserTriggerDataAux#*",
+                "FaserSCT_RDO_Container#*",
+                "Tracker::FaserSCT_ClusterContainer#*",
+                "TrackCollection#*"
+                ]
+    acc.merge(OutputStreamCfg(flags, "ESD", itemList))
+
+    thistSvc = CompFactory.THistSvc()
+    thistSvc.Output += ["HIST1 DATAFILE='TrackSeedPerformanceWriter.root' OPT='RECREATE'"]
+    acc.addService(thistSvc)
+    return acc
diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/__init__.py b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/python/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.cxx b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9c43a4e2a1bffc98af9c2fdd49385ddfaac0f2f9
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.cxx
@@ -0,0 +1,124 @@
+#include "TrackSeedPerformanceWriter.h"
+#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h"
+#include "TrackerPrepRawData/FaserSCT_Cluster.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+
+
+namespace Tracker {
+
+  TrackSeedPerformanceWriter::TrackSeedPerformanceWriter(const std::string &name, ISvcLocator *pSvcLocator)
+      : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name),
+        m_idHelper(nullptr), m_histSvc("THistSvc/THistSvc", name) {}
+
+
+  StatusCode TrackSeedPerformanceWriter::initialize() {
+    ATH_CHECK(m_trackCollectionKey.initialize());
+    ATH_CHECK(m_simDataCollectionKey.initialize());
+    ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+
+    m_tree = new TTree("tree", "tree");
+    m_tree->Branch("run", &m_run, "run/I");
+    m_tree->Branch("event", &m_event, "event/I");
+    m_tree->Branch("station", &m_station, "station/I");
+    m_tree->Branch("chi2", &m_chi2, "chi2/D");
+    m_tree->Branch("dof", &m_dof, "dof/I");
+    m_tree->Branch("nHits", &m_nHits, "nHits/I");
+    m_tree->Branch("x", &m_x, "x/D");
+    m_tree->Branch("y", &m_y, "y/D");
+    m_tree->Branch("z", &m_z, "z/D");
+    m_tree->Branch("px", &m_px, "px/D");
+    m_tree->Branch("py", &m_py, "py/D");
+    m_tree->Branch("pz", &m_pz, "pz/D");
+    // m_tree->Branch("barcode", &m_barcode, "barcode/I");
+    m_tree->Branch("barcodes", &m_barcodes);
+    m_tree->Branch("nMajorityHits", &m_nMajorityHits, "nMajorityHits/I");
+    m_tree->Branch("nMajorityParticle", &m_majorityParticle, "nMajorityParticle/I");
+    // m_tree->Branch("run", &m_run);
+    // m_tree->Branch("event", &m_event);
+    // m_tree->Branch("station", &m_station);
+    // m_tree->Branch("barcodes", &m_barcodes);
+    ATH_CHECK(histSvc()->regTree("/HIST1/TrackSeedPerformance", m_tree));
+
+    return StatusCode::SUCCESS;
+  }
+
+
+  StatusCode TrackSeedPerformanceWriter::execute(const EventContext &ctx) const {
+    m_run = ctx.eventID().run_number();
+    m_event = ctx.eventID().event_number();
+
+    SG::ReadHandle<TrackCollection> trackCollection{m_trackCollectionKey, ctx};
+    ATH_CHECK(trackCollection.isValid());
+
+    SG::ReadHandle<TrackerSimDataCollection> simDataCollection {m_simDataCollectionKey, ctx};
+    ATH_CHECK(simDataCollection.isValid());
+
+    for (const Trk::Track *track: *trackCollection) {
+      m_chi2 = track->fitQuality()->chiSquared();
+      m_dof = track->fitQuality()->numberDoF();
+      const Amg::Vector3D trackPosition = track->trackParameters()->front()->position();
+      const Amg::Vector3D trackMomentum = track->trackParameters()->front()->momentum();
+      m_x = trackPosition.x();
+      m_y = trackPosition.y();
+      m_z = trackPosition.z();
+      m_px = trackMomentum.x();
+      m_py = trackMomentum.y();
+      m_pz = trackMomentum.z();
+      m_nHits = track->measurementsOnTrack()->size();
+      m_barcodes = {};
+      m_hitCounts = {};
+      for (const auto meas: *track->measurementsOnTrack()) {
+        const auto *clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack *>(meas);
+        if (clusterOnTrack) {
+          const Tracker::FaserSCT_Cluster *cluster = clusterOnTrack->prepRawData();
+          Identifier id = cluster->identify();
+          m_barcode = matchHit(id, simDataCollection.get());
+          // fill hit map
+          if (m_hitCounts.count(m_barcode) > 0) {
+            m_hitCounts[m_barcode] += 1;
+          } else {
+            m_hitCounts[m_barcode] = 1;
+          }
+          m_barcodes.push_back(m_barcode);
+          m_station = m_idHelper->station(id);
+        }
+      }
+
+      // find majority particle
+      m_nMajorityHits = 0;
+      m_majorityParticle = 0;
+      for (const auto& hit : m_hitCounts) {
+        if (hit.second > m_nMajorityHits) {
+          m_majorityParticle = hit.first;
+          m_nMajorityHits = hit.second;
+        }
+      }
+      m_tree->Fill();
+    }
+
+    return StatusCode::SUCCESS;
+  }
+
+
+  StatusCode TrackSeedPerformanceWriter::finalize() {
+    return StatusCode::SUCCESS;
+  }
+
+
+  int TrackSeedPerformanceWriter::matchHit(
+      Identifier id, const TrackerSimDataCollection *simDataCollection) const {
+    int barcode = 0;
+    if (simDataCollection->count(id) != 0) {
+      const auto& deposits = simDataCollection->find(id)->second.getdeposits();
+      float highestDep = 0;
+      for (const TrackerSimData::Deposit &deposit : deposits) {
+        if (deposit.second > highestDep) {
+          highestDep = deposit.second;
+          barcode = deposit.first->barcode();
+        }
+      }
+    }
+    return barcode;
+  }
+
+}  // namespace Tracker
diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.h b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..86192d77c69193ee86b41a2123e42819d27051cc
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/TrackSeedPerformanceWriter.h
@@ -0,0 +1,61 @@
+#ifndef FASERACTSKALMANFILTER_TRACKSEEDPERFORMANCEWRITER_H
+#define FASERACTSKALMANFILTER_TRACKSEEDPERFORMANCEWRITER_H
+
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "AthenaBaseComps/AthHistogramming.h"
+#include "TrkTrack/TrackCollection.h"
+#include "TrackerSimData/TrackerSimDataCollection.h"
+
+class TTree;
+class FaserSCT_ID;
+
+
+namespace Tracker {
+  class TrackSeedPerformanceWriter : public AthReentrantAlgorithm, AthHistogramming {
+  public:
+    TrackSeedPerformanceWriter(const std::string &name, ISvcLocator *pSvcLocator);
+    virtual ~TrackSeedPerformanceWriter() = default;
+    virtual StatusCode initialize() override;
+    virtual StatusCode execute(const EventContext &ctx) const override;
+    virtual StatusCode finalize() override;
+    const ServiceHandle<ITHistSvc> &histSvc() const;
+
+  private:
+    int matchHit(Identifier id, const TrackerSimDataCollection *simDataCollection) const;
+    SG::ReadHandleKey<TrackCollection> m_trackCollectionKey {
+        this, "TrackCollection", "SegmentFit", "Input track collection name"};
+    SG::ReadHandleKey<TrackerSimDataCollection> m_simDataCollectionKey {
+        this, "TrackerSimDataCollection", "SCT_SDO_Map"};
+    ServiceHandle<ITHistSvc> m_histSvc;
+    const FaserSCT_ID *m_idHelper;
+    mutable TTree *m_tree;
+
+    mutable unsigned int m_run;
+    mutable unsigned int m_event;
+    mutable unsigned int m_station;
+    mutable double m_chi2;
+    mutable int m_dof;
+    mutable int m_nHits;
+    mutable double m_x;
+    mutable double m_y;
+    mutable double m_z;
+    mutable double m_px;
+    mutable double m_py;
+    mutable double m_pz;
+    mutable int m_barcode;
+    mutable int m_majorityParticle;
+    mutable int m_nMajorityHits;
+    mutable std::vector<int> m_barcodes;
+    mutable std::map<int, int> m_hitCounts;
+  };
+
+
+  inline const ServiceHandle<ITHistSvc> &TrackSeedPerformanceWriter::histSvc() const {
+    return m_histSvc;
+  }
+
+}  // namespace Tracker
+
+
+#endif // FASERACTSKALMANFILTER_TRACKSEEDPERFORMANCEWRITER_H
diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/components/TrackSeedPerformanceWriter_entries.cxx b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/components/TrackSeedPerformanceWriter_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9e569f003a45ef87af33da385a561d3b6a77c95a
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/src/components/TrackSeedPerformanceWriter_entries.cxx
@@ -0,0 +1,3 @@
+#include "../TrackSeedPerformanceWriter.h"
+
+DECLARE_COMPONENT(Tracker::TrackSeedPerformanceWriter)
diff --git a/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/test/TrackSeedPerformanceWriterDbg.py b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/test/TrackSeedPerformanceWriterDbg.py
new file mode 100644
index 0000000000000000000000000000000000000000..b00b9a623561d8b7ef3b57bc0f7bca7e824699c0
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackSeedPerformanceWriter/test/TrackSeedPerformanceWriterDbg.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+"""
+Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+"""
+
+import sys
+from AthenaCommon.Logging import log, logging
+from AthenaCommon.Constants import DEBUG, VERBOSE, INFO
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from AthenaConfiguration.TestDefaults import defaultTestFiles
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg
+from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
+from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg
+from TrackSeedPerformanceWriter.TrackSeedPerformanceWriterConfig import TrackSeedPerformanceWriterCfg
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+ConfigFlags.Input.Files = ['my.RDO.pool.root']
+ConfigFlags.Output.ESDFileName = "seeds.ESD.pool.root"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"
+ConfigFlags.Input.ProjectName = "data21"
+ConfigFlags.Input.isMC = True
+ConfigFlags.GeoModel.FaserVersion = "FASER-01"
+ConfigFlags.Common.isOnline = False
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.lock()
+
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+acc.merge(PoolWriteCfg(ConfigFlags))
+acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags))
+acc.merge(SegmentFitAlgCfg(ConfigFlags, MaxClusters=20, TanThetaCut=0.1))
+acc.merge(TrackSeedPerformanceWriterCfg(ConfigFlags))
+#acc.getEventAlgo("Tracker::SegmentFitAlg").OutputLevel = DEBUG
+acc.getEventAlgo("Tracker::TrackSeedPerformanceWriter").OutputLevel = DEBUG
+
+sc = acc.run(maxEvents=1000)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/TrackerData/CMakeLists.txt b/Tracker/TrackerRecAlgs/TrackerData/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..62e3b8e58115a157382c1e6b434e35ad0b4cb842
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/CMakeLists.txt
@@ -0,0 +1,15 @@
+atlas_subdir(TrackerData)
+
+atlas_add_component(
+  TrackerData
+  src/TrackerSegmentFitDataAlg.h
+  src/TrackerSegmentFitDataAlg.cxx
+  src/TrackerTruthDataAlg.h
+  src/TrackerTruthDataAlg.cxx
+  src/components/TrackerData_entries.cxx
+  LINK_LIBRARIES AthenaBaseComps GeneratorObjects TrackerSimEvent TrackerIdentifier
+    TrackerReadoutGeometry TrackerRIO_OnTrack TrackerPrepRawData TrkTrack
+)
+
+atlas_install_python_modules(python/*.py)
+atlas_install_scripts(test/*.py)
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/TrackerData/README b/Tracker/TrackerRecAlgs/TrackerData/README
new file mode 100644
index 0000000000000000000000000000000000000000..5c7cd869e46e21b3f82e68d2d55811f8d5b9b0d9
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/README
@@ -0,0 +1,9 @@
+This package can be used to write out the data from simulated hits and from
+tracks reconstructed with the TrackerSegmentFit algorithm.
+
+To write out information for the simulated hits run G4FaserAlgConfigNew_Test.py
+to simulate hits and TrackerTruthDbg.py to write out the information.
+
+To write out information for the tracks run G4FaserAlgConfigNew_Test.py to
+simulate hits, FaserSCT_DigitizationDbg.py to digitize them and
+TrackerSegmentFitDbg.py to write out the information.
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/TrackerData/python/TrackerSegmentFitDataConfig.py b/Tracker/TrackerRecAlgs/TrackerData/python/TrackerSegmentFitDataConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..74497753353d66363d6c09ba12cb9a4c899351ad
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/python/TrackerSegmentFitDataConfig.py
@@ -0,0 +1,19 @@
+"""
+Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+"""
+
+from AthenaConfiguration.ComponentFactory import CompFactory
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+
+
+def TrackerSegmentFitDataCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    kwargs.setdefault("TrackCollection", "SegmentFit")
+    TrackerSegmentFitDataAlg = CompFactory.Tracker.TrackerSegmentFitDataAlg
+    acc.addEventAlgo(TrackerSegmentFitDataAlg(**kwargs))
+
+    thistSvc = CompFactory.THistSvc()
+    thistSvc.Output += ["HIST2 DATAFILE='TrackerSegmentFitData.root' OPT='RECREATE'"]
+    acc.addService(thistSvc)
+
+    return acc
diff --git a/Tracker/TrackerRecAlgs/TrackerData/python/TrackerTruthDataConfig.py b/Tracker/TrackerRecAlgs/TrackerData/python/TrackerTruthDataConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..206fda5f90eebb94b06f61b2176938daee08c3b6
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/python/TrackerTruthDataConfig.py
@@ -0,0 +1,19 @@
+"""
+Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+"""
+
+from AthenaConfiguration.ComponentFactory import CompFactory
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+
+
+def TrackerTruthDataCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    kwargs.setdefault("FaserSiHitCollection", "SCT_Hits")
+    TrackerTruthDataAlg = CompFactory.Tracker.TrackerTruthDataAlg
+    acc.addEventAlgo(TrackerTruthDataAlg(**kwargs))
+
+    thistSvc = CompFactory.THistSvc()
+    thistSvc.Output += ["HIST1 DATAFILE='TrackerTruthData.root' OPT='RECREATE'"]
+    acc.addService(thistSvc)
+
+    return acc
diff --git a/Tracker/TrackerRecAlgs/TrackerData/python/__init__.py b/Tracker/TrackerRecAlgs/TrackerData/python/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.cxx b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..92545f3202a58880bbfb6ec6cfa55e3a0bc4396f
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.cxx
@@ -0,0 +1,107 @@
+#include "TrackerSegmentFitDataAlg.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrackerReadoutGeometry/SCT_DetectorManager.h"
+#include "TrackerReadoutGeometry/SiDetectorElement.h"
+#include "TrkTrack/Track.h"
+#include "TrkTrack/TrackStateOnSurface.h"
+#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h"
+#include "TrackerPrepRawData/FaserSCT_Cluster.h"
+#include <TTree.h>
+
+
+namespace Tracker {
+
+TrackerSegmentFitDataAlg::TrackerSegmentFitDataAlg(const std::string &name, ISvcLocator *pSvcLocator)
+    : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name),
+      m_detMgr(nullptr), m_idHelper(nullptr), m_histSvc("THistSvc/THistSvc", name) {}
+
+
+StatusCode TrackerSegmentFitDataAlg::initialize() {
+  ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT"));
+  ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+  ATH_CHECK(m_trackCollection.initialize());
+
+  m_tracks = new TTree("tracks", "tracks");
+  m_tracks->Branch("run_number", &m_run_number, "run_number/I");
+  m_tracks->Branch("event_number", &m_event_number, "event_number/I");
+  m_tracks->Branch("chi2", &m_chi2, "chi2/I");
+  m_tracks->Branch("dof", &m_nDOF, "dof/I");
+  m_tracks->Branch("number_clusters", &m_nClusters, "clusters/I");
+  m_tracks->Branch("x", &m_track_x, "x/D");
+  m_tracks->Branch("y", &m_track_y, "y/D");
+  m_tracks->Branch("z", &m_track_z, "z/D");
+  m_tracks->Branch("px", &m_track_px, "px/D");
+  m_tracks->Branch("py", &m_track_py, "py/D");
+  m_tracks->Branch("pz", &m_track_pz, "pz/D");
+  ATH_CHECK(histSvc()->regTree("/HIST2/tracks", m_tracks));
+
+  m_hits = new TTree("hits", "hits");
+  m_hits->Branch("run_number", &m_run_number, "run_number/I");
+  m_hits->Branch("event_number", &m_event_number, "event_number/I");
+  m_hits->Branch("station", &m_station, "station/I");
+  m_hits->Branch("plane", &m_plane, "plane/I");
+  m_hits->Branch("module", &m_module, "module/I");
+  m_hits->Branch("row", &m_row, "row/I");
+  m_hits->Branch("sensor", &m_sensor, "sensor/I");
+  m_hits->Branch("x", &m_x, "x/D");
+  m_hits->Branch("y", &m_y, "y/D");
+  m_hits->Branch("z", &m_z, "z/D");
+  ATH_CHECK(histSvc()->regTree("/HIST2/hits", m_hits));
+
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TrackerSegmentFitDataAlg::execute(const EventContext &ctx) const {
+
+  m_run_number = ctx.eventID().run_number();
+  m_event_number = ctx.eventID().event_number();
+
+  // Fill tree with clusters from tracker segment fit
+  SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection, ctx};
+  ATH_CHECK(trackCollection.isValid());
+
+  for (const Trk::Track* track : *trackCollection) {
+    m_chi2 = track->fitQuality()->chiSquared();
+    m_nDOF = track->fitQuality()->numberDoF();
+    m_nClusters = track->trackParameters()->size() - 1;
+    auto fitParameters = track->trackParameters()->front();
+    const Amg::Vector3D fitPosition = fitParameters->position();
+    const Amg::Vector3D fitMomentum = fitParameters->momentum();
+    m_track_x = fitPosition.x();
+    m_track_y = fitPosition.y();
+    m_track_z = fitPosition.z();
+    m_track_px = fitMomentum.x();
+    m_track_py = fitMomentum.y();
+    m_track_pz = fitMomentum.z();
+    m_tracks->Fill();
+
+    for (const Trk::TrackStateOnSurface* trackState : *track->trackStateOnSurfaces()) {
+      const auto* clusterOnTrack =
+          dynamic_cast<const FaserSCT_ClusterOnTrack*>(trackState->measurementOnTrack());
+      if (!clusterOnTrack)
+        continue;
+      const FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData();
+      Identifier id = cluster->identify();
+      m_station = m_idHelper->station(id);
+      m_plane = m_idHelper->layer(id);
+      m_module = m_idHelper->eta_module(id);
+      m_row = m_idHelper->phi_module(id);
+      m_sensor = m_idHelper->side(id);
+      m_strip = m_idHelper->strip(id);
+      Amg::Vector3D position = cluster->globalPosition();
+      m_x = position.x();
+      m_y = position.y();
+      m_z = position.z();
+      m_hits->Fill();
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrackerSegmentFitDataAlg::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+}  // namespace Tracker
diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.h b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..08ce4dd73290eadadc12c95a24932c5e52a781ea
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerSegmentFitDataAlg.h
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef TRACKERDATA_TRACKERSEGMENTFITDATAALG_H
+#define TRACKERDATA_TRACKERSEGMENTFITDATAALG_H
+
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "AthenaBaseComps/AthHistogramming.h"
+#include "TrkTrack/TrackCollection.h"
+
+class TTree;
+class FaserSCT_ID;
+namespace TrackerDD {
+class SCT_DetectorManager;
+}
+
+
+namespace Tracker {
+
+class TrackerSegmentFitDataAlg : public AthReentrantAlgorithm, AthHistogramming {
+public:
+  TrackerSegmentFitDataAlg(const std::string &name, ISvcLocator *pSvcLocator);
+  virtual ~TrackerSegmentFitDataAlg() = default;
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext &ctx) const override;
+  virtual StatusCode finalize() override;
+  const ServiceHandle <ITHistSvc> &histSvc() const;
+
+private:
+  SG::ReadHandleKey<TrackCollection> m_trackCollection {this, "TrackCollection", "SegmentFit", "Input track collection name"};
+
+  ServiceHandle <ITHistSvc> m_histSvc;
+
+  const TrackerDD::SCT_DetectorManager *m_detMgr;
+  const FaserSCT_ID *m_idHelper;
+
+  mutable TTree* m_tracks;
+  mutable TTree* m_hits;
+
+  mutable unsigned int m_run_number;
+  mutable unsigned int m_event_number;
+
+  mutable double m_chi2;
+  mutable unsigned int m_nDOF;
+  mutable unsigned int m_nClusters;
+  mutable double m_track_x;
+  mutable double m_track_y;
+  mutable double m_track_z;
+  mutable double m_track_px;
+  mutable double m_track_py;
+  mutable double m_track_pz;
+
+  mutable unsigned int m_station;
+  mutable unsigned int m_plane;
+  mutable unsigned int m_module;
+  mutable unsigned int m_row;
+  mutable unsigned int m_sensor;
+  mutable unsigned int m_strip;
+  mutable double m_x;
+  mutable double m_y;
+  mutable double m_z;
+};
+
+
+inline const ServiceHandle <ITHistSvc> &TrackerSegmentFitDataAlg::histSvc() const {
+  return m_histSvc;
+}
+
+}  // namespace Tracker
+
+#endif  // TRACKERDATA_TRACKERSEGMENTFITDATAALG_H
diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.cxx b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..188f8afb930a7c8006561076d582e2b685da4692
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.cxx
@@ -0,0 +1,123 @@
+#include "TrackerTruthDataAlg.h"
+#include "TrackerSimEvent/FaserSiHitCollection.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrackerReadoutGeometry/SCT_DetectorManager.h"
+#include "TrackerReadoutGeometry/SiDetectorElement.h"
+#include <TTree.h>
+#include <cmath>
+
+
+namespace Tracker {
+
+TrackerTruthDataAlg::TrackerTruthDataAlg(const std::string &name, ISvcLocator *pSvcLocator)
+    : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name),
+      m_sct(nullptr), m_sID(nullptr), m_histSvc("THistSvc/THistSvc", name) {}
+
+
+StatusCode TrackerTruthDataAlg::initialize() {
+  ATH_CHECK(detStore()->retrieve(m_sct, "SCT"));
+  ATH_CHECK(detStore()->retrieve(m_sID, "FaserSCT_ID"));
+  ATH_CHECK(m_mcEventCollectionKey.initialize());
+  ATH_CHECK(m_faserSiHitKey.initialize());
+
+  m_hits = new TTree("hits", "hits");
+  m_hits->Branch("run_number", &m_run_number, "run_number/I");
+  m_hits->Branch("event_number", &m_event_number, "event_number/I");
+  m_hits->Branch("station", &m_station, "station/I");
+  m_hits->Branch("plane", &m_plane, "plane/I");
+  m_hits->Branch("module", &m_module, "module/I");
+  m_hits->Branch("row", &m_row, "row/I");
+  m_hits->Branch("sensor", &m_sensor, "sensor/I");
+  m_hits->Branch("pdg", &m_pdg, "pdg/I");
+  m_hits->Branch("local_x", &m_local_x, "local_x/D");
+  m_hits->Branch("local_y", &m_local_y, "local_y/D");
+  m_hits->Branch("global_x", &m_global_x, "global_x/D");
+  m_hits->Branch("global_y", &m_global_y, "global_y/D");
+  m_hits->Branch("global_z", &m_global_z, "global_z/D");
+  m_hits->Branch("phi", &m_phi, "phi/D");
+  m_hits->Branch("theta", &m_theta, "theta/D");
+  ATH_CHECK(histSvc()->regTree("/HIST1/hits", m_hits));
+
+  m_particles = new TTree("particles", "particles");
+  m_particles->Branch("run_number", &m_run_number, "run_number/I");
+  m_particles->Branch("event_number", &m_event_number, "event_number/I");
+  m_particles->Branch("pdg", &m_pdg, "pdg/I");
+  m_particles->Branch("x", &m_vertex_x, "x/D");
+  m_particles->Branch("y", &m_vertex_y, "y/D");
+  m_particles->Branch("z", &m_vertex_z, "z/D");
+  m_particles->Branch("px", &m_px, "px/D");
+  m_particles->Branch("py", &m_py, "py/D");
+  m_particles->Branch("pz", &m_pz, "pz/D");
+  ATH_CHECK(histSvc()->regTree("/HIST1/particles", m_particles));
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrackerTruthDataAlg::execute(const EventContext &ctx) const {
+
+  m_run_number = ctx.eventID().run_number();
+  m_event_number = ctx.eventID().event_number();
+
+  // Fill tree with simulated particles
+  SG::ReadHandle<McEventCollection> mcEventCollection(m_mcEventCollectionKey, ctx);
+  ATH_CHECK(mcEventCollection.isValid());
+  for (const HepMC::GenEvent* event : *mcEventCollection) {
+    for (const HepMC::GenParticle* particle : event->particle_range()) {
+      m_pdg = particle->pdg_id();
+      const auto vertex = particle->production_vertex()->position();
+      m_vertex_x = vertex.x();
+      m_vertex_y = vertex.y();
+      m_vertex_z = vertex.z();
+      const HepMC::FourVector& momentum = particle->momentum();
+      m_px = momentum.x();
+      m_py = momentum.y();
+      m_pz = momentum.z();
+      m_particles->Fill();
+    }
+  }
+
+  // Fill tree with simulated hits
+  SG::ReadHandle<FaserSiHitCollection> siHitCollection(m_faserSiHitKey, ctx);
+  ATH_CHECK(siHitCollection.isValid());
+  for (const FaserSiHit &hit: *siHitCollection) {
+    if (!hit.particleLink().isValid())
+      continue;
+    m_station = hit.getStation();
+    m_plane = hit.getPlane();
+    m_module = hit.getModule();
+    m_row = hit.getRow();
+    m_sensor = hit.getSensor();
+    Identifier id = m_sID->wafer_id(m_station, m_plane, m_row, m_module, m_sensor);
+    const TrackerDD::SiDetectorElement *geoelement = m_sct->getDetectorElement(id);
+    if (!geoelement)
+      continue;
+    const auto localStartPos = hit.localStartPosition();
+    const HepGeom::Point3D<double> globalStartPos =
+        Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(localStartPos);
+    const auto localEndPos = hit.localEndPosition();
+    const HepGeom::Point3D<double> globalEndPos =
+        Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(localEndPos);
+    m_pdg = hit.particleLink()->pdg_id();
+    HepGeom::Vector3D<double> v = globalEndPos - globalStartPos;
+    m_phi = std::atan(v.y()/v.x());
+    m_theta = std::atan(std::sqrt(v.x() * v.x() + v.y() * v.y())/v.z());
+    ATH_MSG_DEBUG("local pos: " << localStartPos);
+    ATH_MSG_DEBUG("global pos: " << globalStartPos);
+    m_local_x = m_sensor == 0 ? -localStartPos.y() : localStartPos.y();
+    m_local_y = -localStartPos.z();
+    m_global_x = globalStartPos.x();
+    m_global_y = globalStartPos.y();
+    m_global_z = globalStartPos.z();
+    m_hits->Fill();
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrackerTruthDataAlg::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+}  // namespace Tracker
diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.h b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c4f51d2a6f19a44931457b3d91c94b935b0c0a2
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/src/TrackerTruthDataAlg.h
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef TRACKERDATA_TRACKERTRUTHDATAALG_H
+#define TRACKERDATA_TRACKERTRUTHDATAALG_H
+
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "AthenaBaseComps/AthHistogramming.h"
+#include "TrackerSimEvent/FaserSiHitCollection.h"
+#include "GeneratorObjects/McEventCollection.h"
+
+class TTree;
+class FaserSCT_ID;
+namespace TrackerDD {
+class SCT_DetectorManager;
+}
+
+
+namespace Tracker {
+
+class TrackerTruthDataAlg : public AthReentrantAlgorithm, AthHistogramming {
+public:
+  TrackerTruthDataAlg(const std::string &name, ISvcLocator *pSvcLocator);
+  virtual ~TrackerTruthDataAlg() = default;
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext &ctx) const override;
+  virtual StatusCode finalize() override;
+  const ServiceHandle <ITHistSvc> &histSvc() const;
+
+private:
+  SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey {this, "McEventCollection", "BeamTruthEvent"};
+  SG::ReadHandleKey <FaserSiHitCollection> m_faserSiHitKey{this, "FaserSiHitCollection", "SCT_Hits"};
+
+  ServiceHandle <ITHistSvc> m_histSvc;
+
+  const TrackerDD::SCT_DetectorManager *m_sct;
+  const FaserSCT_ID *m_sID;
+
+  mutable TTree *m_particles;
+  mutable TTree *m_hits;
+
+  mutable unsigned int m_run_number;
+  mutable unsigned int m_event_number;
+  mutable unsigned int m_station;
+  mutable unsigned int m_plane;
+  mutable unsigned int m_module;
+  mutable unsigned int m_row;
+  mutable unsigned int m_sensor;
+  mutable int m_pdg;
+  mutable double m_local_x;
+  mutable double m_local_y;
+  mutable double m_global_x;
+  mutable double m_global_y;
+  mutable double m_global_z;
+  mutable double m_vertex_x;
+  mutable double m_vertex_y;
+  mutable double m_vertex_z;
+  mutable double m_px;
+  mutable double m_py;
+  mutable double m_pz;
+  mutable double m_phi;
+  mutable double m_theta;
+};
+
+
+inline const ServiceHandle <ITHistSvc> &TrackerTruthDataAlg::histSvc() const {
+  return m_histSvc;
+}
+
+}  // namespace Tracker
+
+#endif  // TRACKERDATA_TRACKERTRUTHDATAALG_H
diff --git a/Tracker/TrackerRecAlgs/TrackerData/src/components/TrackerData_entries.cxx b/Tracker/TrackerRecAlgs/TrackerData/src/components/TrackerData_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..01018d29702f995ccf656c466989a2d06a74e30a
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/src/components/TrackerData_entries.cxx
@@ -0,0 +1,5 @@
+#include "../TrackerTruthDataAlg.h"
+#include "../TrackerSegmentFitDataAlg.h"
+
+DECLARE_COMPONENT(Tracker::TrackerTruthDataAlg )
+DECLARE_COMPONENT(Tracker::TrackerSegmentFitDataAlg)
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/TrackerData/test/TI12TrackerSegmentFitDataDbg.py b/Tracker/TrackerRecAlgs/TrackerData/test/TI12TrackerSegmentFitDataDbg.py
new file mode 100644
index 0000000000000000000000000000000000000000..b20d313f99654d07487651c645616b93a266789f
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/test/TI12TrackerSegmentFitDataDbg.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+""""
+Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+"""
+import sys
+from AthenaCommon.Logging import log
+from AthenaCommon.Constants import DEBUG
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg
+from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg
+from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
+from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg
+from TrackerData.TrackerSegmentFitDataConfig import TrackerSegmentFitDataCfg
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+ConfigFlags.Input.Files = ['/home/tboeckh/tmp/Faser-Physics-006470-00093.raw_middleStation.SPs']
+ConfigFlags.Output.ESDFileName = "TrackerSegmentFitData.ESD.pool.root"
+ConfigFlags.addFlag("Output.xAODFileName", f"TrackerSegmentFitData_xAOD.root")
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02"
+ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"
+ConfigFlags.Input.ProjectName = "data21"
+ConfigFlags.Input.isMC = False
+ConfigFlags.GeoModel.FaserVersion = "FASER-02"
+ConfigFlags.Common.isOnline = False
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.Detector.GeometryFaserSCT = True
+ConfigFlags.lock()
+
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags))
+acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, name="LevelClustering", DataObjectName="SCT_LEVELMODE_RDOs", ClusterToolTimingPattern="X1X"))
+acc.merge(SegmentFitAlgCfg(ConfigFlags, name=f"LevelFit", MaxClusters=44))
+acc.merge(TrackerSegmentFitDataCfg(ConfigFlags))
+acc.getEventAlgo("Tracker::TrackerSegmentFitDataAlg").OutputLevel = DEBUG
+itemList = ["xAOD::EventInfo#*",
+            "xAOD::EventAuxInfo#*",
+            "xAOD::FaserTriggerData#*",
+            "xAOD::FaserTriggerDataAux#*",
+            "FaserSCT_RDO_Container#*",
+            "Tracker::FaserSCT_ClusterContainer#*",
+            "TrackCollection#*"
+            ]
+acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList))
+
+replicaSvc = acc.getService("DBReplicaSvc")
+replicaSvc.COOLSQLiteVetoPattern = ""
+replicaSvc.UseCOOLSQLite = True
+replicaSvc.UseCOOLFrontier = False
+replicaSvc.UseGeomSQLite = True
+
+sc = acc.run(maxEvents=-1)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/TrackerData/test/TrackerSegmentFitDataDbg.py b/Tracker/TrackerRecAlgs/TrackerData/test/TrackerSegmentFitDataDbg.py
new file mode 100644
index 0000000000000000000000000000000000000000..bac4dd4035a48d731d77cdc98af54fd649f73948
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/test/TrackerSegmentFitDataDbg.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+""""
+Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+"""
+import sys
+from AthenaCommon.Logging import log
+from AthenaCommon.Constants import DEBUG
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg
+from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
+from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg
+from TrackerData.TrackerSegmentFitDataConfig import TrackerSegmentFitDataCfg
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+ConfigFlags.Input.Files = ["my.RDO.pool.root"]
+ConfigFlags.Output.ESDFileName = "TrackerSegmentFitData.ESD.pool.root"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"
+ConfigFlags.Input.ProjectName = "data22"
+ConfigFlags.Input.isMC = True
+ConfigFlags.GeoModel.FaserVersion = "FASER-01"
+ConfigFlags.Common.isOnline = False
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.Detector.GeometryFaserSCT = True
+ConfigFlags.addFlag("Output.xAODFileName", f"TrackerSegmentFitData_xAOD.root")
+ConfigFlags.lock()
+
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+acc.merge(PoolWriteCfg(ConfigFlags))
+
+acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, DataObjectName="SCT_RDOs"))
+acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.5, MinClustersPerFit=5, TanThetaCut=0.25))
+acc.merge(TrackerSegmentFitDataCfg(ConfigFlags))
+acc.getEventAlgo("Tracker::TrackerSegmentFitDataAlg").OutputLevel = DEBUG
+itemList = ["xAOD::EventInfo#*",
+            "xAOD::EventAuxInfo#*",
+            "xAOD::FaserTriggerData#*",
+            "xAOD::FaserTriggerDataAux#*",
+            "FaserSCT_RDO_Container#*",
+            "Tracker::FaserSCT_ClusterContainer#*",
+            "TrackCollection#*"
+            ]
+acc.merge(OutputStreamCfg(ConfigFlags, "ESD", itemList))
+
+sc = acc.run(maxEvents=-1)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/TrackerData/test/TrackerTruthDataDbg.py b/Tracker/TrackerRecAlgs/TrackerData/test/TrackerTruthDataDbg.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6b366d6ba9543d4bba4f87384d25b0e9b756603
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerData/test/TrackerTruthDataDbg.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+""""
+Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+"""
+import sys
+from AthenaCommon.Logging import log
+from AthenaCommon.Constants import DEBUG
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from TrackerData.TrackerTruthDataConfig import TrackerTruthDataCfg
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+ConfigFlags.Input.Files = ["my.HITS.pool.root"]
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"
+ConfigFlags.Input.ProjectName = "data22"
+ConfigFlags.Input.isMC = True
+ConfigFlags.GeoModel.FaserVersion = "FASER-01"
+ConfigFlags.Common.isOnline = False
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.Detector.GeometryFaserSCT = True
+ConfigFlags.lock()
+
+# Core components
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+
+acc.merge(TrackerTruthDataCfg(ConfigFlags))
+acc.getEventAlgo("Tracker::TrackerTruthDataAlg").OutputLevel = DEBUG
+
+# Execute and finish
+sc = acc.run(maxEvents=-1)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.cxx b/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.cxx
index ff163e105d51b02267ce35e3fdfe43737c5a184c..f12ccaa7d336bce3f9be4f0758d4ca06e1b878b9 100644
--- a/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.cxx
+++ b/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.cxx
@@ -507,16 +507,19 @@ SegmentFitAlg::selectFits(const FitMap& fits) const
     auto content = *it;
     ATH_MSG_VERBOSE("clusters: " << content->clusterMask.count() << " / chi2: " << content->fitChi2) ;
   }
-  ClusterSet usedClusters { clusterInfo::nClusters };
 
   while (info.size() > 0)
   {
     auto selected = info.front();
     ATH_MSG_VERBOSE("Selected nclust = " << selected->clusterMask.count() << " with chi2 = " << selected->fitChi2);
     selectedFits[selected->clusterMask] = selected;
-    usedClusters |= selected->clusterMask;
 
-    info.remove_if([&](std::shared_ptr<fitInfo> p) {return (p->clusterMask & ~usedClusters) != p->clusterMask;});
+    // remove fits for which the fraction of shared hits is larger than m_sharedFraction or the number of hits is
+    // smaller than m_minClustersPerFit
+    info.remove_if([&](std::shared_ptr<fitInfo> p) {return
+        ((p->clusterMask & selected->clusterMask).count() > m_sharedHitFraction * p->clusterMask.count())
+        || (p->clusterMask.count() < m_minClustersPerFit) ;}
+    );
   }
 
   m_numberOfSelectedFits += selectedFits.size();
diff --git a/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.h b/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.h
index eb41946cd0a9094a24919eaf6824705094afa234..757eb1a22752acbe72e0da7a0c6c7a89878bf76a 100644
--- a/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.h
+++ b/Tracker/TrackerRecAlgs/TrackerSegmentFit/src/SegmentFitAlg.h
@@ -414,6 +414,8 @@ class SegmentFitAlg : public AthReentrantAlgorithm
     DoubleProperty m_yResidualCut { this, "ResidualCut", 3 * Gaudi::Units::mm, "Cluster y tolerance for compatibility with extrapolated fit." };
     DoubleProperty m_tanThetaCut { this, "TanThetaCut", 0.0, "Maximum accepted tangent of track angle from beam axis; 0 means no cut."};
     DoubleProperty m_reducedChi2Cut { this, "ReducedChi2Cut", 10.0, "Maximum accepted chi^2 per degree of freedom for final fits; 0 means no cut." };
+    DoubleProperty m_sharedHitFraction { this, "SharedHitFraction", -1., "Fraction of hits which are allowed to be shared between two fits." };
+    IntegerProperty m_minClustersPerFit { this, "MinClustersPerFit", 4, "Minimum number of clusters a fit has to have." };
 
     mutable std::atomic<int> m_numberOfEvents{0};
     mutable std::atomic<int> m_numberExcessOccupancy{0};
diff --git a/Tracker/TrackerRecAlgs/TrackerSegmentFit/test/MCTrackerSegmentFit.py b/Tracker/TrackerRecAlgs/TrackerSegmentFit/test/MCTrackerSegmentFit.py
new file mode 100644
index 0000000000000000000000000000000000000000..05d4be97bc18d8598512b8a22a79f8cdf6436af7
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerSegmentFit/test/MCTrackerSegmentFit.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+"""Test various ComponentAccumulator Digitization configuration modules
+
+Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+"""
+import sys
+from AthenaCommon.Logging import log, logging
+from AthenaCommon.Constants import DEBUG, VERBOSE, INFO
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from AthenaConfiguration.TestDefaults import defaultTestFiles
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg
+from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+#from Digitization.DigitizationParametersConfig import writeDigitizationMetadata
+from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionCfg
+from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
+from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg
+from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg
+#from MCTruthSimAlgs.RecoTimingConfig import MergeRecoTimingObjCfg
+
+# Set up logging and new style config
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+# Configure
+ConfigFlags.Input.Files = ['my.RDO.pool.root']
+ConfigFlags.Output.ESDFileName = "segmentFit.ESD.pool.root"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"
+ConfigFlags.Input.ProjectName = "data21"
+ConfigFlags.Input.isMC = True
+ConfigFlags.GeoModel.FaserVersion = "FASER-01"
+ConfigFlags.Common.isOnline = False
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.addFlag("Output.xAODFileName", "segmentFit.xAOD.pool.root")
+# ConfigFlags.Detector.GeometryFaserSCT = True
+ConfigFlags.lock()
+
+# Core components
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+acc.merge(PoolWriteCfg(ConfigFlags))
+
+acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags))
+acc.merge(SegmentFitAlgCfg(ConfigFlags))
+#acc.getEventAlgo("Tracker::SegmentFitAlg").OutputLevel = DEBUG
+
+from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+itemList = ["xAOD::EventInfo#*",
+            "xAOD::EventAuxInfo#*",
+            "xAOD::FaserTriggerData#*",
+            "xAOD::FaserTriggerDataAux#*",
+            "FaserSCT_RDO_Container#*",
+            "Tracker::FaserSCT_ClusterContainer#*",
+            "TrackCollection#*"
+            ]
+acc.merge(OutputStreamCfg(ConfigFlags, "ESD", itemList))
+
+# Dump config
+# logging.getLogger('forcomps').setLevel(VERBOSE)
+# acc.foreach_component("*").OutputLevel = VERBOSE
+# acc.foreach_component("*ClassID*").OutputLevel = INFO
+# acc.getCondAlgo("FaserSCT_AlignCondAlg").OutputLevel = VERBOSE
+# acc.getCondAlgo("FaserSCT_DetectorElementCondAlg").OutputLevel = VERBOSE
+# acc.getService("StoreGateSvc").Dump = True
+# acc.getService("ConditionStore").Dump = True
+# acc.printConfig(withDetails=True)
+# ConfigFlags.dump()
+
+# Execute and finish
+sc = acc.run(maxEvents=-1)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/CMakeLists.txt b/Tracker/TrackerRecAlgs/TrackerTruth/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b52a694c458489bb341116be7568c18ffd9de8e6
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerTruth/CMakeLists.txt
@@ -0,0 +1,12 @@
+atlas_subdir(TrackerTruth)
+
+atlas_add_component(
+  TrackerTruth
+  src/TrackerTruthAlg.h
+  src/TrackerTruthAlg.cxx
+  src/components/TrackerTruth_entries.cxx
+  LINK_LIBRARIES AthenaBaseComps GeneratorObjects TrackerSimEvent TrackerIdentifier TrackerReadoutGeometry
+)
+
+atlas_install_python_modules( python/*.py )
+atlas_install_scripts( test/*.py )
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/ReadMe b/Tracker/TrackerRecAlgs/TrackerTruth/ReadMe
new file mode 100644
index 0000000000000000000000000000000000000000..a763932b380cc4982774d5e409328dadea867411
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerTruth/ReadMe
@@ -0,0 +1,6 @@
+This package can be used to write out the truth information of particles and hits from MC generated events.
+For particles the run number, event number, pdg code, vertex and momentum is written out and for hits the
+run number, event number, station, plane, module, row, sensor, local position, global position and pdg code of the
+corresponding particle is written out.
+
+To write out truth information generate MC data using the G4FaserAlgConfigNew_Test.py and run TrackerTruthDbg.py
diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/python/TrackerTruthConfig.py b/Tracker/TrackerRecAlgs/TrackerTruth/python/TrackerTruthConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..475e7ba6f60844cdea8c4b5da0ef4f43da70d2f5
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerTruth/python/TrackerTruthConfig.py
@@ -0,0 +1,19 @@
+"""
+Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+"""
+
+from AthenaConfiguration.ComponentFactory import CompFactory
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+
+
+def TrackerTruthCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    kwargs.setdefault("FaserSiHitCollection", "SCT_Hits")
+    TrackerTruthAlg = CompFactory.Tracker.TrackerTruthAlg
+    acc.addEventAlgo(TrackerTruthAlg(**kwargs))
+
+    thistSvc = CompFactory.THistSvc()
+    thistSvc.Output += ["HIST1 DATAFILE='TrackerTruth.root' OPT='RECREATE'"]
+    acc.addService(thistSvc)
+
+    return acc
diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/python/__init__.py b/Tracker/TrackerRecAlgs/TrackerTruth/python/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.cxx b/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..cc600bad74f6e16341757becc305ea0343416889
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.cxx
@@ -0,0 +1,112 @@
+#include "TrackerTruthAlg.h"
+#include "TrackerSimEvent/FaserSiHitCollection.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrackerReadoutGeometry/SCT_DetectorManager.h"
+#include "TrackerReadoutGeometry/SiDetectorElement.h"
+#include <TTree.h>
+
+
+namespace Tracker {
+
+TrackerTruthAlg::TrackerTruthAlg(const std::string &name, ISvcLocator *pSvcLocator)
+    : AthReentrantAlgorithm(name, pSvcLocator), AthHistogramming(name),
+      m_sct(nullptr), m_sID(nullptr), m_histSvc("THistSvc/THistSvc", name) {}
+
+
+StatusCode TrackerTruthAlg::initialize() {
+  ATH_CHECK(detStore()->retrieve(m_sct, "SCT"));
+  ATH_CHECK(detStore()->retrieve(m_sID, "FaserSCT_ID"));
+  ATH_CHECK(m_mcEventCollectionKey.initialize());
+  ATH_CHECK(m_faserSiHitKey.initialize());
+
+  m_hits = new TTree("hits", "hits");
+  m_hits->Branch("run_number", &m_run_number, "run_number/I");
+  m_hits->Branch("event_number", &m_event_number, "event_number/I");
+  m_hits->Branch("station", &m_station, "station/I");
+  m_hits->Branch("plane", &m_plane, "plane/I");
+  m_hits->Branch("module", &m_module, "module/I");
+  m_hits->Branch("row", &m_row, "row/I");
+  m_hits->Branch("sensor", &m_sensor, "sensor/I");
+  m_hits->Branch("pdg", &m_pdg, "pdg/I");
+  m_hits->Branch("local_x", &m_local_x, "local_x/D");
+  m_hits->Branch("local_y", &m_local_y, "local_y/D");
+  m_hits->Branch("global_x", &m_global_x, "global_x/D");
+  m_hits->Branch("global_y", &m_global_y, "global_y/D");
+  m_hits->Branch("global_z", &m_global_z, "global_z/D");
+  ATH_CHECK(histSvc()->regTree("/HIST1/hits", m_hits));
+
+  m_particles = new TTree("particles", "particles");
+  m_particles->Branch("run_number", &m_run_number, "run_number/I");
+  m_particles->Branch("event_number", &m_event_number, "event_number/I");
+  m_particles->Branch("pdg", &m_pdg, "pdg/I");
+  m_particles->Branch("x", &m_vertex_x, "x/D");
+  m_particles->Branch("y", &m_vertex_y, "y/D");
+  m_particles->Branch("z", &m_vertex_z, "z/D");
+  m_particles->Branch("px", &m_px, "px/D");
+  m_particles->Branch("py", &m_px, "py/D");
+  m_particles->Branch("pz", &m_px, "pz/D");
+  ATH_CHECK(histSvc()->regTree("/HIST1/particles", m_particles));
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrackerTruthAlg::execute(const EventContext &ctx) const {
+
+  m_run_number = ctx.eventID().run_number();
+  m_event_number = ctx.eventID().event_number();
+
+  // Fill tree with simulated particles
+  SG::ReadHandle<McEventCollection> mcEventCollection(m_mcEventCollectionKey, ctx);
+  ATH_CHECK(mcEventCollection.isValid());
+  for (const HepMC::GenEvent* event : *mcEventCollection) {
+    for (const HepMC::GenParticle* particle : event->particle_range()) {
+      m_pdg = particle->pdg_id();
+      const auto vertex = particle->production_vertex()->position();
+      m_vertex_x = vertex.x();
+      m_vertex_y = vertex.y();
+      m_vertex_z = vertex.z();
+      const HepMC::FourVector& momentum = particle->momentum();
+      m_px = momentum.x();
+      m_py = momentum.y();
+      m_pz = momentum.z();
+      m_particles->Fill();
+    }
+  }
+
+  // Fill tree with simulated hits
+  SG::ReadHandle<FaserSiHitCollection> siHitCollection(m_faserSiHitKey, ctx);
+  ATH_CHECK(siHitCollection.isValid());
+  for (const FaserSiHit &hit: *siHitCollection) {
+    if (!hit.particleLink().isValid())
+      continue;
+    const HepGeom::Point3D<double> localStartPos = hit.localStartPosition();
+    Identifier id = m_sID->wafer_id(hit.getStation(), hit.getPlane(), hit.getRow(), hit.getModule(), hit.getSensor());
+    const TrackerDD::SiDetectorElement *geoelement = m_sct->getDetectorElement(id);
+    if (!geoelement)
+      continue;
+    const HepGeom::Point3D<double> globalStartPos =
+        Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(localStartPos);
+    m_station = hit.getStation();
+    m_plane = hit.getPlane();
+    m_module = hit.getModule();
+    m_row = hit.getRow();
+    m_sensor = hit.getSensor();
+    m_pdg = hit.particleLink()->pdg_id();
+    m_local_x = localStartPos.x();
+    m_local_y = localStartPos.y();
+    m_global_x = globalStartPos.x();
+    m_global_y = globalStartPos.y();
+    m_global_z = globalStartPos.z();
+    m_hits->Fill();
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrackerTruthAlg::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+}  // namespace Tracker
diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.h b/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f21acc718500b5881bdb4956980fc1893c80747
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerTruth/src/TrackerTruthAlg.h
@@ -0,0 +1,72 @@
+/*
+  Copyright (C) 2022 CERN for the benefit of the FASER collaboration
+*/
+
+#ifndef TRACKERTRUTH_TRACKERTRUTHALG_H
+#define TRACKERTRUTH_TRACKERTRUTHALG_H
+
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "AthenaBaseComps/AthHistogramming.h"
+#include "TrackerSimEvent/FaserSiHitCollection.h"
+#include "GeneratorObjects/McEventCollection.h"
+
+class TTree;
+class FaserSCT_ID;
+namespace TrackerDD {
+class SCT_DetectorManager;
+}
+
+
+namespace Tracker {
+
+class TrackerTruthAlg : public AthReentrantAlgorithm, AthHistogramming {
+public:
+  TrackerTruthAlg(const std::string &name, ISvcLocator *pSvcLocator);
+  virtual ~TrackerTruthAlg() = default;
+  virtual StatusCode initialize() override;
+  virtual StatusCode execute(const EventContext &ctx) const override;
+  virtual StatusCode finalize() override;
+  const ServiceHandle <ITHistSvc> &histSvc() const;
+
+private:
+  SG::ReadHandleKey<McEventCollection> m_mcEventCollectionKey {this, "McEventCollection", "BeamTruthEvent"};
+  SG::ReadHandleKey <FaserSiHitCollection> m_faserSiHitKey{this, "FaserSiHitCollection", "SCT_Hits"};
+
+  ServiceHandle <ITHistSvc> m_histSvc;
+
+  const TrackerDD::SCT_DetectorManager *m_sct;
+  const FaserSCT_ID *m_sID;
+
+  mutable TTree *m_particles;
+  mutable TTree *m_hits;
+
+  mutable unsigned int m_run_number;
+  mutable unsigned int m_event_number;
+  mutable unsigned int m_station;
+  mutable unsigned int m_plane;
+  mutable unsigned int m_module;
+  mutable unsigned int m_row;
+  mutable unsigned int m_sensor;
+  mutable int m_pdg;
+  mutable double m_local_x;
+  mutable double m_local_y;
+  mutable double m_global_x;
+  mutable double m_global_y;
+  mutable double m_global_z;
+  mutable double m_vertex_x;
+  mutable double m_vertex_y;
+  mutable double m_vertex_z;
+  mutable double m_px;
+  mutable double m_py;
+  mutable double m_pz;
+};
+
+
+inline const ServiceHandle <ITHistSvc> &TrackerTruthAlg::histSvc() const {
+  return m_histSvc;
+}
+
+}  // namespace Tracker
+
+#endif
diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/src/components/TrackerTruth_entries.cxx b/Tracker/TrackerRecAlgs/TrackerTruth/src/components/TrackerTruth_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0f49f0e7edefeccc3908ebc6822928ad08abbe7c
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerTruth/src/components/TrackerTruth_entries.cxx
@@ -0,0 +1,3 @@
+#include "../TrackerTruthAlg.h"
+
+DECLARE_COMPONENT(Tracker::TrackerTruthAlg )
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/TrackerTruth/test/TrackerTruthDbg.py b/Tracker/TrackerRecAlgs/TrackerTruth/test/TrackerTruthDbg.py
new file mode 100644
index 0000000000000000000000000000000000000000..479edc81bb284720c94ef4b16196a5aa7ac0f5d3
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/TrackerTruth/test/TrackerTruthDbg.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+""""
+Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+"""
+import sys
+from AthenaCommon.Logging import log
+from AthenaCommon.Constants import DEBUG
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+from TrackerTruth.TrackerTruthConfig import TrackerTruthCfg
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+ConfigFlags.Input.Files = ["my.HITS.pool.root"]
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"
+ConfigFlags.Input.ProjectName = "data22"
+ConfigFlags.Input.isMC = True
+ConfigFlags.GeoModel.FaserVersion = "FASER-01"
+ConfigFlags.Common.isOnline = False
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.Detector.GeometryFaserSCT = True
+ConfigFlags.lock()
+
+# Core components
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+
+acc.merge(TrackerTruthCfg(ConfigFlags))
+acc.getEventAlgo("Tracker::TrackerTruthAlg").OutputLevel = DEBUG
+
+# Execute and finish
+sc = acc.run(maxEvents=-1)
+sys.exit(not sc.isSuccess())
diff --git a/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/src/TruthSeededTrackFinder.cxx b/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/src/TruthSeededTrackFinder.cxx
index d23327e1c5b6c8d59bcf7e41e7a9dbf58ca164bf..c88414a505231ab1fee984801da34f83982394ce 100755
--- a/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/src/TruthSeededTrackFinder.cxx
+++ b/Tracker/TrackerRecAlgs/TruthSeededTrackFinder/src/TruthSeededTrackFinder.cxx
@@ -113,10 +113,10 @@ namespace Tracker
     ATH_CHECK( m_faserSiHitKey.initialize() );
     ATH_CHECK( m_faserRdoKey.initialize());
     ATH_CHECK( m_sctMap.initialize());
-    ATH_MSG_INFO( "Using GenEvent collection with key " << m_mcEventKey.key());
-    ATH_MSG_INFO( "Using Faser SiHit collection with key " << m_faserSiHitKey.key());
-    ATH_MSG_INFO( "Using FaserSCT RDO Container with key " << m_faserRdoKey.key());
-    ATH_MSG_INFO( "Using SCT_SDO_Map with key "<< m_sctMap.key());
+    ATH_MSG_DEBUG( "Using GenEvent collection with key " << m_mcEventKey.key());
+    ATH_MSG_DEBUG( "Using Faser SiHit collection with key " << m_faserSiHitKey.key());
+    ATH_MSG_DEBUG( "Using FaserSCT RDO Container with key " << m_faserRdoKey.key());
+    ATH_MSG_DEBUG( "Using SCT_SDO_Map with key "<< m_sctMap.key());
 
     m_hist_n=new TH1D("sp_n","sp_n",20,0,20);
     m_hist_x=new TH1D("sp_x","sp_x",100,-200,200);
@@ -180,7 +180,7 @@ namespace Tracker
     CHECK(m_thistSvc->regHist("/TruthTrackSeeds/sp/InitReso_py",m_hist_InitReso_py));
     CHECK(m_thistSvc->regHist("/TruthTrackSeeds/sp/InitReso_pz",m_hist_InitReso_pz));
 	//!!!!!!!!!!!!!!!!!!!!
-    ATH_MSG_INFO( "TruthTrackSeeds::initialized" );
+    ATH_MSG_DEBUG( "TruthTrackSeeds::initialized" );
     return StatusCode::SUCCESS;
   }
 
@@ -194,11 +194,11 @@ namespace Tracker
 
     // Handles created from handle keys behave like pointers to the corresponding container
     SG::ReadHandle<McEventCollection> h_mcEvents(m_mcEventKey, ctx);
-    ATH_MSG_INFO("Read McEventContainer with " << h_mcEvents->size() << " events");
+    ATH_MSG_DEBUG("Read McEventContainer with " << h_mcEvents->size() << " events");
     if (h_mcEvents->size() == 0) return StatusCode::FAILURE;
 
     SG::ReadHandle<FaserSiHitCollection> h_siHits(m_faserSiHitKey, ctx);
-    ATH_MSG_INFO("Read FaserSiHitCollection with " << h_siHits->size() << " hits");
+    ATH_MSG_DEBUG("Read FaserSiHitCollection with " << h_siHits->size() << " hits");
 
     SG::ReadHandle<FaserSCT_RDO_Container> h_sctRDO(m_faserRdoKey, ctx);
 
@@ -206,7 +206,7 @@ namespace Tracker
     SG::WriteHandle<SpacePointForSeedCollection> seedContainer_SCT(m_seed_spcontainerKey, ctx );
 
     ATH_CHECK( seedContainer_SCT.record( std::make_unique<SpacePointForSeedCollection>() ) );
-    ATH_MSG_INFO("Created SpacePointContainer " << m_seed_spcontainerKey.key() << " N= " << m_idHelper->wafer_hash_max());
+    ATH_MSG_DEBUG("Created SpacePointContainer " << m_seed_spcontainerKey.key() << " N= " << m_idHelper->wafer_hash_max());
 
 
     const TrackerDD::SiDetectorElementCollection* elements = nullptr;
@@ -288,12 +288,12 @@ namespace Tracker
 	  SG::ReadHandle<TrackerSimDataCollection> h_collectionMap(m_sctMap, ctx);
 	  ATH_MSG_DEBUG("map size "<<h_collectionMap->size());
 	//!!!!!!!!!!!!!!!!!!!!
-		  std::cout<<"!!!!!!!!!  cluster: "<<sp->clusterList().first<<std::endl;
+//		  std::cout<<"!!!!!!!!!  cluster: "<<sp->clusterList().first<<std::endl;
 		  ATH_MSG_DEBUG("!!!!!!!!!  cluster: "<<sp->clusterList().first->rdoList() );
 	//!!!!!!!!!!!!!!!!!!!!
 	  if( h_collectionMap->count(identifier) == 0)
 	  {
-	    ATH_MSG_INFO("no map found w/identifier "<<identifier);
+	    ATH_MSG_DEBUG("no map found w/identifier "<<identifier);
 	    ++m_numberOfNoMap;
 	    continue;
 	  }
@@ -309,14 +309,14 @@ namespace Tracker
 	  for( const auto& depositPair : deposits)
 	  {
 	      //!!!!!!!!!!!!!!!!!!!!!!!!
-	      depositPair.first->print(std::cout);
-	        std::cout<<"!!!!!!!!!!!  pdg id =  "<<depositPair.first->pdg_id()<<std::endl;
+//	      depositPair.first->print(std::cout);
+//	        std::cout<<"!!!!!!!!!!!  pdg id =  "<<depositPair.first->pdg_id()<<std::endl;
 		if (depositPair.first->pdg_id() == -13) {
 		HepMC::FourVector pv = depositPair.first->production_vertex()->position();
 		HepMC::FourVector ev = depositPair.first->end_vertex()->position ();
 	        truthmom = depositPair.first->momentum();
-	        std::cout<<"!!!!!!!!!!!  production_vertex: ( "<<pv.x()<<",  "<<pv.y()<<",  "<<pv.z()<<" )  "<<std::endl;
-	        std::cout<<"!!!!!!!!!!!  end_vertex: ( "<<ev.x()<<",  "<<ev.y()<<",  "<<ev.z()<<" )  "<<std::endl;
+//	        std::cout<<"!!!!!!!!!!!  production_vertex: ( "<<pv.x()<<",  "<<pv.y()<<",  "<<pv.z()<<" )  "<<std::endl;
+//	        std::cout<<"!!!!!!!!!!!  end_vertex: ( "<<ev.x()<<",  "<<ev.y()<<",  "<<ev.z()<<" )  "<<std::endl;
 		}
 	      //!!!!!!!!!!!!!!!!!!!!!!!!
 	    if( depositPair.second > highestDep)
@@ -339,12 +339,12 @@ namespace Tracker
 		{
 		  // TODO: Check that daughter->production_vertex() and daughter->end_vertex() exist, and bracket the point you're interested in
 	          if (daughter->barcode() % 1000000 == primary->barcode()) {
-		     ATH_MSG_INFO("    daughter barcode: " << daughter->barcode() << " with energy " << daughter->momentum().e() << "  px = " << daughter->momentum().px() << "  py = " << daughter->momentum().py() << "  pz = " << daughter->momentum().pz() );
+		     ATH_MSG_DEBUG("    daughter barcode: " << daughter->barcode() << " with energy " << daughter->momentum().e() << "  px = " << daughter->momentum().px() << "  py = " << daughter->momentum().py() << "  pz = " << daughter->momentum().pz() );
 		 if (daughter->production_vertex() != nullptr && daughter->end_vertex() != nullptr) { 
 		HepMC::FourVector pv = daughter->production_vertex()->position();
 		HepMC::FourVector ev = daughter->end_vertex()->position ();
-	        std::cout<<"!!!!!!!!!!!  production_vertex: ( "<<pv.x()<<",  "<<pv.y()<<",  "<<pv.z()<<" )  "<<std::endl;
-	        std::cout<<"!!!!!!!!!!!  end_vertex: ( "<<ev.x()<<",  "<<ev.y()<<",  "<<ev.z()<<" )  "<<std::endl;
+//	        std::cout<<"!!!!!!!!!!!  production_vertex: ( "<<pv.x()<<",  "<<pv.y()<<",  "<<pv.z()<<" )  "<<std::endl;
+//	        std::cout<<"!!!!!!!!!!!  end_vertex: ( "<<ev.x()<<",  "<<ev.y()<<",  "<<ev.z()<<" )  "<<std::endl;
 		 }
 		  }
 		}
@@ -387,8 +387,8 @@ namespace Tracker
 	m_lp_end=hit.localEndPosition();
 	m_new_pos=m_lp_start+(m_lp_end-m_lp_start)*m_ran_pos;
 	//muPos=Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_new_pos);
-	std::cout<<"!!!!!!!!!!!  hit start pos: "<<Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_lp_start)<<std::endl;
-	std::cout<<"!!!!!!!!!!!  hit end pos: "<<Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_lp_end)<<std::endl;
+//	std::cout<<"!!!!!!!!!!!  hit start pos: "<<Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_lp_start)<<std::endl;
+//	std::cout<<"!!!!!!!!!!!  hit end pos: "<<Amg::EigenTransformToCLHEP(geoelement->transformHit()) * HepGeom::Point3D<double>(m_lp_end)<<std::endl;
 	}
 	      //!!!!!!!!!!!!!!!!!!!!!!!!
 	  }
@@ -430,8 +430,8 @@ namespace Tracker
 	if (istation==2 && ilayer==0) { match_N_2_0++; }
 	if (istation==2 && ilayer==1) { match_N_2_1++; }
 	if (istation==2 && ilayer==2) { match_N_2_2++; }
-	std::cout<<"!!!!!!!!!!! (station, layer) = ("<<istation<<", "<<ilayer<<")     positopn = ("<<gloPos.x()<<", "<<gloPos.y()<<", "<<gloPos.z()<<") "<<std::endl;
-       if (std::fabs(gloPos.x())>100) std::cout<<"!!!!!!!!!!! badXXX "<<std::endl;
+//	std::cout<<"!!!!!!!!!!! (station, layer) = ("<<istation<<", "<<ilayer<<")     positopn = ("<<gloPos.x()<<", "<<gloPos.y()<<", "<<gloPos.z()<<") "<<std::endl;
+//       if (std::fabs(gloPos.x())>100) std::cout<<"!!!!!!!!!!! badXXX "<<std::endl;
 	//!!!!!!!!!!!!!!!!!!!!
 	}
 	ATH_MSG_VERBOSE( nReceivedSPSCT << " SpacePoints successfully added to Container !" );
@@ -441,8 +441,8 @@ namespace Tracker
     m_hist_n->Fill(nTruthSP);
 
     //!!!!!!!!!!!!!!!!!!!!!!!!
- std::cout<<"!!!!!!!!!!!  N_1_0 = "<<N_1_0<<",  N_1_1 = "<<N_1_1<<",  N_1_2 = "<<N_1_2<<",  N_2_0 = "<<N_2_0<<",  N_2_1 = "<<N_2_1<<",  N_2_2 = "<<N_2_2<<std::endl;
- std::cout<<"!!!!!!!!!!!  match_N_1_0 = "<<match_N_1_0<<",  match_N_1_1 = "<<match_N_1_1<<",  match_N_1_2 = "<<match_N_1_2<<",  match_N_2_0 = "<<match_N_2_0<<",  match_N_2_1 = "<<match_N_2_1<<",  match_N_2_2 = "<<match_N_2_2<<std::endl;
+// std::cout<<"!!!!!!!!!!!  N_1_0 = "<<N_1_0<<",  N_1_1 = "<<N_1_1<<",  N_1_2 = "<<N_1_2<<",  N_2_0 = "<<N_2_0<<",  N_2_1 = "<<N_2_1<<",  N_2_2 = "<<N_2_2<<std::endl;
+// std::cout<<"!!!!!!!!!!!  match_N_1_0 = "<<match_N_1_0<<",  match_N_1_1 = "<<match_N_1_1<<",  match_N_1_2 = "<<match_N_1_2<<",  match_N_2_0 = "<<match_N_2_0<<",  match_N_2_1 = "<<match_N_2_1<<",  match_N_2_2 = "<<match_N_2_2<<std::endl;
   if ( (N_1_0==1 && match_N_1_0==1) && (N_1_1==1 && match_N_1_1==1) && (N_1_2==1 && match_N_1_2==1) && (N_2_0==1 && match_N_2_0==1) && (N_2_1==1 && match_N_2_1==1) && (N_2_2==1 && match_N_2_2==1)) {
   Acts::Vector3 pos1_0(0., 0., 0.);
   Acts::Vector3 pos1_1(0., 0., 0.);
@@ -482,12 +482,12 @@ namespace Tracker
     }
   }
 	
-  std::cout<<"!!!!!!!!!!!  pos1_0 = ("<<pos1_0.x()<<", "<<pos1_0.y()<<", "<<pos1_0.z()<<") "<<std::endl; 
-  std::cout<<"!!!!!!!!!!!  pos1_1 = ("<<pos1_1.x()<<", "<<pos1_1.y()<<", "<<pos1_1.z()<<") "<<std::endl;
-  std::cout<<"!!!!!!!!!!!  pos1_2 = ("<<pos1_2.x()<<", "<<pos1_2.y()<<", "<<pos1_2.z()<<") "<<std::endl;
-  std::cout<<"!!!!!!!!!!!  pos2_0 = ("<<pos2_0.x()<<", "<<pos2_0.y()<<", "<<pos2_0.z()<<") "<<std::endl; 
-  std::cout<<"!!!!!!!!!!!  pos2_1 = ("<<pos2_1.x()<<", "<<pos2_1.y()<<", "<<pos2_1.z()<<") "<<std::endl;
-  std::cout<<"!!!!!!!!!!!  pos2_2 = ("<<pos2_2.x()<<", "<<pos2_2.y()<<", "<<pos2_2.z()<<") "<<std::endl;
+//  std::cout<<"!!!!!!!!!!!  pos1_0 = ("<<pos1_0.x()<<", "<<pos1_0.y()<<", "<<pos1_0.z()<<") "<<std::endl;
+//  std::cout<<"!!!!!!!!!!!  pos1_1 = ("<<pos1_1.x()<<", "<<pos1_1.y()<<", "<<pos1_1.z()<<") "<<std::endl;
+//  std::cout<<"!!!!!!!!!!!  pos1_2 = ("<<pos1_2.x()<<", "<<pos1_2.y()<<", "<<pos1_2.z()<<") "<<std::endl;
+//  std::cout<<"!!!!!!!!!!!  pos2_0 = ("<<pos2_0.x()<<", "<<pos2_0.y()<<", "<<pos2_0.z()<<") "<<std::endl;
+//  std::cout<<"!!!!!!!!!!!  pos2_1 = ("<<pos2_1.x()<<", "<<pos2_1.y()<<", "<<pos2_1.z()<<") "<<std::endl;
+//  std::cout<<"!!!!!!!!!!!  pos2_2 = ("<<pos2_2.x()<<", "<<pos2_2.y()<<", "<<pos2_2.z()<<") "<<std::endl;
 
   double charge = 1;
   double B = 0.57;
@@ -527,21 +527,21 @@ namespace Tracker
 
   // the direction of momentum in the first station
   Acts::Vector3 direct1 = d1.normalized();
-  std::cout<<"!!!!!!!!!!!  direct1 = ("<<direct1.x()<<", "<<direct1.y()<<", "<<direct1.z()<<") "<<std::endl; 
+//  std::cout<<"!!!!!!!!!!!  direct1 = ("<<direct1.x()<<", "<<direct1.y()<<", "<<direct1.z()<<") "<<std::endl;
   // the direction of momentum in the second station
   Acts::Vector3 direct2 = d2.normalized();
-  std::cout<<"!!!!!!!!!!!  direct2 = ("<<direct2.x()<<", "<<direct2.y()<<", "<<direct2.z()<<") "<<std::endl; 
+//  std::cout<<"!!!!!!!!!!!  direct2 = ("<<direct2.x()<<", "<<direct2.y()<<", "<<direct2.z()<<") "<<std::endl;
   // the vector pointing from the center of circle to the particle at layer 2 in Y-Z plane
   double R1_z = charge * direct1.y() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z());
   double R1_y = -charge * direct1.z() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z());
-  std::cout<<"!!!!!!!!!!!  (R1_y, R1_z) = ("<<R1_y<<", "<<R1_z<<") "<<std::endl; 
+//  std::cout<<"!!!!!!!!!!!  (R1_y, R1_z) = ("<<R1_y<<", "<<R1_z<<") "<<std::endl;
   // the vector pointing from the center of circle to the particle at layer 3 in Y-Z plane
   double R2_z = charge * direct2.y() / std::sqrt(direct2.y()*direct2.y() + direct2.z()*direct2.z());
   double R2_y = -charge * direct2.z() / std::sqrt(direct2.y()*direct2.y() + direct2.z()*direct2.z());
-  std::cout<<"!!!!!!!!!!!  (R2_y, R2_z) = ("<<R2_y<<", "<<R2_z<<") "<<std::endl; 
+//  std::cout<<"!!!!!!!!!!!  (R2_y, R2_z) = ("<<R2_y<<", "<<R2_z<<") "<<std::endl;
   // the norm of radius
   double R = (pos2_0.z() - pos1_2.z()) / (R2_z - R1_z);
-  std::cout<<"!!!!!!!!!!!  R = "<<R<<std::endl; 
+//  std::cout<<"!!!!!!!!!!!  R = "<<R<<std::endl;
   // the norm of momentum in Y-Z plane
   double p_yz = 0.3*B*R / 1000.0;  // R(mm), p(GeV), B(T)
   double p_z = p_yz * direct1.z() / std::sqrt(direct1.y()*direct1.y() + direct1.z()*direct1.z());
@@ -550,8 +550,8 @@ namespace Tracker
   // total momentum at the layer 0
   const Acts::Vector3 mom(p_x, p_y, p_z);
   double p = mom.norm();
-  std::cout<<"!!!!!!!!!!!  InitTrack momentum on layer 0: ( "<<mom.x()*1000<<",  "<<mom.y()*1000<<",  "<<mom.z()*1000<<",  "<<p*1000<<")  "<<std::endl;
-  std::cout<<"!!!!!!!!!!!  truth momentum: ( "<<truthmom.px()<<",  "<<truthmom.py()<<",  "<<truthmom.pz()<<",  "<<truthmom.m()<<" )  "<<std::endl;
+//  std::cout<<"!!!!!!!!!!!  InitTrack momentum on layer 0: ( "<<mom.x()*1000<<",  "<<mom.y()*1000<<",  "<<mom.z()*1000<<",  "<<p*1000<<")  "<<std::endl;
+//  std::cout<<"!!!!!!!!!!!  truth momentum: ( "<<truthmom.px()<<",  "<<truthmom.py()<<",  "<<truthmom.pz()<<",  "<<truthmom.m()<<" )  "<<std::endl;
 
   if ((p_x*1000 - truthmom.px()) / std::fabs(truthmom.px()) < -10) m_hist_InitReso_px->Fill( -9.5 );
     else if ((p_x*1000 - truthmom.px()) / std::fabs(truthmom.px()) > 10) m_hist_InitReso_px->Fill( 9.5 );
@@ -593,15 +593,15 @@ namespace Tracker
   //---------------------------------------------------------------------------
   StatusCode TruthSeededTrackFinder::finalize()
   {
-    ATH_MSG_INFO( "Finalizing" );
-    ATH_MSG_INFO( m_numberOfEvents << " events processed" );
-    ATH_MSG_INFO( m_numberOfSPCollection << " spacepoint collections processed" );
-    ATH_MSG_INFO( m_numberOfEmptySPCollection<< " spacepoint collections empty" );
-    ATH_MSG_INFO( m_numberOfSP<< " sct SP collections processed" );
-    ATH_MSG_INFO( m_numberOfNoMap<< " not maped spacepoint" );
-    ATH_MSG_INFO( m_numberOfHits<< " sim hits" );
-    ATH_MSG_INFO( m_numberOfMatchSP<< " matched spacepoint" );
-    ATH_MSG_INFO( m_numberOfFills<< " spacepoint saved" );
+    ATH_MSG_DEBUG( "Finalizing" );
+    ATH_MSG_DEBUG( m_numberOfEvents << " events processed" );
+    ATH_MSG_DEBUG( m_numberOfSPCollection << " spacepoint collections processed" );
+    ATH_MSG_DEBUG( m_numberOfEmptySPCollection<< " spacepoint collections empty" );
+    ATH_MSG_DEBUG( m_numberOfSP<< " sct SP collections processed" );
+    ATH_MSG_DEBUG( m_numberOfNoMap<< " not maped spacepoint" );
+    ATH_MSG_DEBUG( m_numberOfHits<< " sim hits" );
+    ATH_MSG_DEBUG( m_numberOfMatchSP<< " matched spacepoint" );
+    ATH_MSG_DEBUG( m_numberOfFills<< " spacepoint saved" );
     return StatusCode::SUCCESS;
   }
 
diff --git a/Tracking/Acts/ActsInterop/CMakeLists.txt b/Tracking/Acts/ActsInterop/CMakeLists.txt
index 41632f128825078ea3e7bc471117c1e35caae2fa..63c79212852d5d2213c74f3bb27f7f145cd604a6 100755
--- a/Tracking/Acts/ActsInterop/CMakeLists.txt
+++ b/Tracking/Acts/ActsInterop/CMakeLists.txt
@@ -4,7 +4,9 @@ atlas_subdir( ActsInterop )
 
 # External dependencies:
 
-find_package(Acts COMPONENTS Core)
+#set( Acts_DIR /home/tboeckh/Documents/acts/run )
+#find_package( Acts REQUIRED COMPONENTS Core PATHS /home/tboeckh/Documents/acts/run NO_DEFAULT_PATH )
+find_package( Acts COMPONENTS Core )
 
 # Component(s) in the package:
 atlas_add_library( ActsInteropLib
diff --git a/Tracking/Acts/FaserActsGeometry/CMakeLists.txt b/Tracking/Acts/FaserActsGeometry/CMakeLists.txt
index a121316e188cc27c35f3d90f9a81b569089b9d19..48c9abd929200339bfaa071bfa6625cf3e2a98cd 100755
--- a/Tracking/Acts/FaserActsGeometry/CMakeLists.txt
+++ b/Tracking/Acts/FaserActsGeometry/CMakeLists.txt
@@ -8,6 +8,8 @@ find_package( Eigen )
 find_package( Boost )
 find_package( nlohmann_json )
 
+#set( Acts_DIR /home/tboeckh/Documents/acts/run )
+#find_package( Acts REQUIRED COMPONENTS Core PATHS /home/tboeckh/Documents/acts/run NO_DEFAULT_PATH )
 find_package( Acts COMPONENTS Core )
 
 atlas_add_library( FaserActsGeometryLib 
diff --git a/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt b/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt
index 7529f472a8de702fb76046cb78624a9111e65a03..b3f81e4ac59f82e9d53ebb75f68eaddbe3e4f74c 100644
--- a/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt
+++ b/Tracking/Acts/FaserActsGeometryInterfaces/CMakeLists.txt
@@ -4,6 +4,8 @@ atlas_subdir( FaserActsGeometryInterfaces )
 
 # External dependencies:
 find_package( Eigen )
+#set( Acts_DIR /home/tboeckh/Documents/acts/run )
+#find_package( Acts REQUIRED COMPONENTS Core PATHS /home/tboeckh/Documents/acts/run NO_DEFAULT_PATH )
 find_package( Acts COMPONENTS Core )
 find_package( nlohmann_json )
 # Component(s) in the package:
diff --git a/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt b/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt
index 34d9584f9f6b30b1683c962d6baa59037bc8d6f3..c5c0c5e454ab0b43622689bda4f7c3691ee1abca 100755
--- a/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt
+++ b/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt
@@ -5,8 +5,11 @@ atlas_subdir(FaserActsKalmanFilter)
 find_package( CLHEP )
 find_package( Eigen )
 find_package( Boost )
+#set( Acts_DIR /home/tboeckh/Documents/acts/run )
+#find_package( Acts REQUIRED COMPONENTS Core PATHS /home/tboeckh/Documents/acts/run NO_DEFAULT_PATH )
 find_package( Acts COMPONENTS Core )
 
+
 # Component(s) in the package:
 atlas_add_library( FaserActsKalmanFilterLib
     PUBLIC_HEADERS FaserActsKalmanFilter
@@ -22,21 +25,25 @@ atlas_add_library( FaserActsKalmanFilterLib
 )
 
 atlas_add_component(FaserActsKalmanFilter
+    FaserActsKalmanFilter/ActsTrackSeedTool.h
+    FaserActsKalmanFilter/CircleFit.h
+    FaserActsKalmanFilter/CKF2.h
     FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h
     FaserActsKalmanFilter/EffPlotTool.h
     FaserActsKalmanFilter/FASERSourceLink.h
     FaserActsKalmanFilter/FaserActsGeometryContainers.h
     FaserActsKalmanFilter/FaserActsKalmanFilterAlg.h
     FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h
+    FaserActsKalmanFilter/MyTrackSeedTool.h
     FaserActsKalmanFilter/IdentifierLink.h
     FaserActsKalmanFilter/IndexSourceLink.h
     FaserActsKalmanFilter/ITrackFinderTool.h
     FaserActsKalmanFilter/ITrackSeedTool.h
+    FaserActsKalmanFilter/KalmanFitterTool.h
 #    FaserActsKalmanFilter/ClusterTrackSeedTool.h
 #    FaserActsKalmanFilter/TruthTrackFinderTool.h
     FaserActsKalmanFilter/Measurement.h
 #    FaserActsKalmanFilter/MultiTrackFinderTool.h
-    FaserActsKalmanFilter/MyAmbiguitySolver.h
     FaserActsKalmanFilter/PerformanceWriterTool.h
     FaserActsKalmanFilter/PlotHelpers.h
     FaserActsKalmanFilter/ResPlotTool.h
@@ -49,16 +56,21 @@ atlas_add_component(FaserActsKalmanFilter
     FaserActsKalmanFilter/SPSimpleInitialParameterTool.h
     FaserActsKalmanFilter/SummaryPlotTool.h
     FaserActsKalmanFilter/TrackClassification.h
+    FaserActsKalmanFilter/TrackSeedWriterTool.h
     FaserActsKalmanFilter/TrackSelection.h
     FaserActsKalmanFilter/TrajectoryWriterTool.h
 #    FaserActsKalmanFilter/ProtoTrackWriterTool.h
     FaserActsKalmanFilter/TruthBasedInitialParameterTool.h
 #    FaserActsKalmanFilter/TruthSeededTrackFinderTool.h
     FaserActsKalmanFilter/ThreeStationTrackSeedTool.h
+    src/ActsTrackSeedTool.cxx
+    src/CKF2.cxx
 #    src/ClusterTrackSeedTool.cxx
     src/CombinatorialKalmanFilterAlg.cxx
     src/EffPlotTool.cxx
     src/FaserActsKalmanFilterAlg.cxx
+    src/MyTrackSeedTool.cxx
+    src/KalmanFitterTool.cxx
 #    src/MultiTrackFinderTool.cxx
     src/PerformanceWriterTool.cxx
     src/PlotHelpers.cxx
@@ -77,6 +89,7 @@ atlas_add_component(FaserActsKalmanFilter
     src/TruthBasedInitialParameterTool.cxx
     src/SummaryPlotTool.cxx
     src/TrackClassification.cxx
+    src/TrackSeedWriterTool.cxx
     src/TrackSelection.cxx
 #    src/TruthTrackFinderTool.cxx
 #    src/TruthSeededTrackFinderTool.cxx
diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ActsTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ActsTrackSeedTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..fe129a47d2867405ece6b807bf56803f814a2882
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ActsTrackSeedTool.h
@@ -0,0 +1,110 @@
+#ifndef FASERACTSKALMANFILTER_ACTSTRACKSEEDTOOL_H
+#define FASERACTSKALMANFILTER_ACTSTRACKSEEDTOOL_H
+
+
+#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "FaserActsKalmanFilter/ITrackSeedTool.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+#include "TrkTrack/TrackCollection.h"
+
+class FaserSCT_ID;
+namespace TrackerDD { class SCT_DetectorManager; }
+
+
+class ActsTrackSeedTool : public extends<AthAlgTool, ITrackSeedTool> {
+public:
+  ActsTrackSeedTool(const std::string& type, const std::string& name, const IInterface* parent);
+  virtual ~ActsTrackSeedTool() = default;
+  virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
+  virtual StatusCode run() override;
+
+  const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const override;
+  const std::shared_ptr<const Acts::Surface> initialSurface() const override;
+  const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override;
+  const std::shared_ptr<IdentifierLink> idLinks() const override;
+  const std::shared_ptr<std::vector<Measurement>> measurements() const override;
+  const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const override;
+  const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters() const override;
+  const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints() const override;
+
+private:
+  std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters;
+  std::shared_ptr<const Acts::Surface> m_initialSurface;
+  std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {};
+  std::shared_ptr<IdentifierLink> m_idLinks {};
+  std::shared_ptr<std::vector<Measurement>> m_measurements {};
+  std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> m_clusters {};
+  std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> m_seedClusters {};
+  std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> m_spacePoints {};
+
+  const FaserSCT_ID* m_idHelper {nullptr};
+  const TrackerDD::SCT_DetectorManager* m_detManager {nullptr};
+
+  ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {
+      this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"};
+  SG::ReadHandleKey<TrackCollection> m_trackCollection {
+      this, "TrackCollection", "SegmentFit", "Input track collection name" };
+  SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainerKey {
+      this, "ClusterContainer", "SCT_ClusterContainer"};
+
+  // position resolution of a cluster
+  Gaudi::Property<double> m_std_cluster {this, "std_cluster", 0.023};
+
+  // covariance of the initial parameters
+  Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1};
+  Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1};
+  Gaudi::Property<double> m_covPhi {this, "covPhi", 1};
+  Gaudi::Property<double> m_covTheta {this, "covTheta", 1};
+  Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1};
+  Gaudi::Property<double> m_covTime {this, "covTime", 1};
+  Gaudi::Property<double> m_origin {this, "origin", 0, "z position of the reference surface"};
+
+  static Acts::CurvilinearTrackParameters get_params(
+      const Acts::GeometryContext& gctx, const Amg::Vector3D& position_st1,
+      const Amg::Vector3D& position_st2, const Amg::Vector3D& position_st3,
+      const Acts::BoundSymMatrix& cov, double origin);
+};
+
+inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>>
+ActsTrackSeedTool::initialTrackParameters() const {
+  return m_initialTrackParameters;
+}
+
+inline const std::shared_ptr<const Acts::Surface>
+ActsTrackSeedTool::initialSurface() const {
+  return m_initialSurface;
+}
+
+inline const std::shared_ptr<std::vector<IndexSourceLink>>
+ActsTrackSeedTool::sourceLinks() const {
+  return m_sourceLinks;
+}
+
+inline const std::shared_ptr<IdentifierLink>
+ActsTrackSeedTool::idLinks() const {
+  return m_idLinks;
+}
+
+inline const std::shared_ptr<std::vector<Measurement>>
+ActsTrackSeedTool::measurements() const {
+  return m_measurements;
+}
+
+inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>>
+ActsTrackSeedTool::clusters() const {
+  return m_clusters;
+}
+
+inline const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>>
+ActsTrackSeedTool::seedClusters() const {
+  return m_seedClusters;
+}
+
+inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>>
+ActsTrackSeedTool::spacePoints() const {
+  return m_spacePoints;
+}
+
+#endif // FASERACTSKALMANFILTER_ACTSTRACKSEEDTOOL_H
diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CKF2.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CKF2.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e3b0e76af52738963d42f7cd716a1c32644ca47
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CKF2.h
@@ -0,0 +1,151 @@
+#ifndef FASERACTSKALMANFILTER_CKF2_H
+#define FASERACTSKALMANFILTER_CKF2_H
+
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h"
+#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+#include "Acts/TrackFitting/KalmanFitter.hpp"
+#include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp"
+#include "Acts/TrackFinding/MeasurementSelector.hpp"
+#include "FaserActsKalmanFilter/Measurement.h"
+#include "MagFieldConditions/FaserFieldCacheCondObj.h"
+#include "FaserActsKalmanFilter/TrajectoryWriterTool.h"
+#include "TrkTrack/TrackCollection.h"
+#include "FaserActsKalmanFilter/ITrackSeedTool.h"
+#include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h"
+#include "FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h"
+#include "FaserActsKalmanFilter/PerformanceWriterTool.h"
+#include "FaserActsKalmanFilter/KalmanFitterTool.h"
+#include <boost/dynamic_bitset.hpp>
+using ConstTrackStateProxy = Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>;
+using ClusterSet = boost::dynamic_bitset<>;
+
+class FaserSCT_ID;
+
+namespace Trk {
+class TrackStateOnSurface;
+}
+
+namespace TrackerDD {
+class SCT_DetectorManager;
+}
+
+class CKF2 : public AthAlgorithm {
+public:
+  CKF2(const std::string& name, ISvcLocator* pSvcLocator);
+  virtual ~CKF2() = default;
+
+  StatusCode initialize() override;
+  StatusCode execute() override;
+  StatusCode finalize() override;
+
+  using TrackFinderOptions =
+  Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor,
+      MeasurementCalibrator,
+      Acts::MeasurementSelector>;
+  using CKFResult = Acts::CombinatorialKalmanFilterResult<IndexSourceLink>;
+  using TrackFitterResult = Acts::Result<CKFResult>;
+  using TrackFinderResult = std::vector<TrackFitterResult>;
+
+  using KFResult =
+    Acts::Result<Acts::KalmanFitterResult<IndexSourceLink>>;
+
+  using TrackFitterOptions =
+  Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder,
+      Acts::VoidReverseFilteringLogic>;
+
+  using TrackParameters = Acts::CurvilinearTrackParameters;
+  using TrackParametersContainer = std::vector<TrackParameters>;
+
+  // Track Finding
+  class TrackFinderFunction {
+  public:
+    virtual ~TrackFinderFunction() = default;
+    virtual TrackFinderResult operator()(const IndexSourceLinkContainer&,
+                                         const TrackParametersContainer&,
+                                         const TrackFinderOptions&) const = 0;
+  };
+
+  static std::shared_ptr<TrackFinderFunction> makeTrackFinderFunction(
+      std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry,
+      bool resolvePassive, bool resolveMaterial, bool resolveSensitive);
+
+  // Track Fitting
+  class TrackFitterFunction {
+  public:
+    virtual ~TrackFitterFunction() = default;
+    virtual KFResult operator()(const std::vector<IndexSourceLink>&,
+                                const Acts::BoundTrackParameters&,
+                                const TrackFitterOptions&) const = 0;
+  };
+
+  struct TrajectoryInfo {
+    TrajectoryInfo(const FaserActsRecMultiTrajectory &traj) :
+        trajectory{traj}, clusterSet{nClusters} {
+      auto state = Acts::MultiTrajectoryHelpers::trajectoryState(traj.multiTrajectory(), traj.tips().front());
+      traj.multiTrajectory().visitBackwards(traj.tips().front(), [&](const ConstTrackStateProxy& state) {
+        auto typeFlags = state.typeFlags();
+        if (not typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) {
+          return true;
+        }
+        clusterSet.set(state.uncalibrated().index());
+        return true;
+      });
+      nMeasurements = state.nMeasurements;
+      chi2 = state.chi2Sum;
+    }
+
+    static size_t nClusters;
+    FaserActsRecMultiTrajectory trajectory;
+    ClusterSet clusterSet;
+    size_t nMeasurements;
+    double chi2;
+  };
+
+  static std::shared_ptr<TrackFitterFunction> makeTrackFitterFunction(
+      std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry);
+
+  virtual Acts::MagneticFieldContext getMagneticFieldContext(const EventContext& ctx) const;
+
+private:
+  void computeSharedHits(std::vector<IndexSourceLink>* sourceLinks, TrackFinderResult& results) const;
+  std::shared_ptr<TrackFinderFunction> m_fit;
+  std::shared_ptr<TrackFitterFunction> m_kf;
+  std::unique_ptr<const Acts::Logger> m_logger;
+  const FaserSCT_ID* m_idHelper {nullptr};
+  const TrackerDD::SCT_DetectorManager* m_detManager {nullptr};
+
+  Gaudi::Property<std::string> m_actsLogging {this, "ActsLogging", "VERBOSE"};
+  Gaudi::Property<int> m_minNumberMeasurements {this, "MinNumberMeasurements", 12};
+  Gaudi::Property<bool> m_backwardPropagation {this, "BackwardPropagation", false};
+  Gaudi::Property<bool> m_performanceWriter {this, "PerformanceWriter", true};
+  Gaudi::Property<bool> m_summaryWriter {this, "SummaryWriter", true};
+  Gaudi::Property<bool> m_noDiagnostics {this, "noDiagnostics", true, "Set ACTS logging level to INFO and do not run performance writer, states writer or summary writer"};
+  Gaudi::Property<bool> m_statesWriter {this, "StatesWriter", false};
+  Gaudi::Property<bool> m_resolvePassive {this, "resolvePassive", false};
+  Gaudi::Property<bool> m_resolveMaterial {this, "resolveMaterial", true};
+  Gaudi::Property<bool> m_resolveSensitive {this, "resolveSensitive", true};
+  Gaudi::Property<double> m_maxSteps {this, "maxSteps", 10000};
+  Gaudi::Property<double> m_chi2Max {this, "chi2Max", 15};
+  Gaudi::Property<unsigned long> m_nMax {this, "nMax", 10};
+  Gaudi::Property<size_t> m_nTrajectories {this, "nTrajectories", 2};
+  SG::ReadCondHandleKey<FaserFieldCacheCondObj> m_fieldCondObjInputKey {this, "FaserFieldCacheCondObj", "fieldCondObj", "Name of the Magnetic Field conditions object key"};
+  ToolHandle<ITrackSeedTool> m_trackSeedTool {this, "TrackSeed", "ClusterTrackSeedTool"};
+  ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"};
+  ToolHandle<PerformanceWriterTool> m_performanceWriterTool {this, "PerformanceWriterTool", "PerformanceWriterTool"};
+  ToolHandle<RootTrajectoryStatesWriterTool> m_trajectoryStatesWriterTool {this, "RootTrajectoryStatesWriterTool", "RootTrajectoryStatesWriterTool"};
+  ToolHandle<RootTrajectorySummaryWriterTool> m_trajectorySummaryWriterTool {this, "RootTrajectorySummaryWriterTool", "RootTrajectorySummaryWriterTool"};
+  ToolHandle<KalmanFitterTool> m_kalmanFitterTool1 {this, "KalmanFitterTool1", "KalmanFitterTool"};
+  ToolHandle<KalmanFitterTool> m_kalmanFitterTool2 {this, "KalmanFitterTool2", "KalmanFitterTool"};
+
+  std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, TrackFitterResult& fitResult) const;
+  std::unique_ptr<Trk::Track> makeTrack(const Acts::GeometryContext &geoCtx, const FaserActsRecMultiTrajectory &traj) const;
+  const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const;
+  SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "CKFTrackCollection", "CKFTrackCollection" };
+};
+
+#endif // FASERACTSKALMANFILTER_CKF2_H
+
diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CircleFit.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CircleFit.h
new file mode 100644
index 0000000000000000000000000000000000000000..664b7005ddfdb31998dc3a5665fdd871a9d8ce31
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CircleFit.h
@@ -0,0 +1,188 @@
+#ifndef FASERACTSKALMANFILTER_CIRCLEFIT_H
+#define FASERACTSKALMANFILTER_CIRCLEFIT_H
+
+#include "TrackerSpacePoint/FaserSCT_SpacePoint.h"
+#include <cmath>
+#include <vector>
+
+
+struct Circle {
+public:
+  Circle() = default;
+  Circle(double cx, double cy, double r) : cx(cx), cy(cy), r(r) {};
+
+  double cx = 0;
+  double cy = 0;
+  double r = 0;
+  double s = 0;
+  double i = 0;
+  double j = 0;
+};
+
+
+class CircleData {
+public:
+  CircleData(const std::vector<const Tracker::FaserSCT_SpacePoint*> &spacePoints) {
+    for (auto sp : spacePoints) {
+      m_x.push_back(sp->globalPosition().z());
+      m_y.push_back(sp->globalPosition().y());
+    }
+    m_size = spacePoints.size();
+  }
+
+  double meanX() const {
+    double mean = 0;
+    for (double i : m_x) mean += i;
+    return mean / m_size;
+  }
+
+  double meanY() const {
+    double mean = 0;
+    for (double i : m_y) mean += i;
+    return mean / m_size;
+  }
+
+  double x(int i) const {
+    return m_x[i];
+  }
+
+  double y(int i) const {
+    return m_y[i];
+  }
+
+  int size() const {
+    return m_size;
+  }
+
+private:
+  std::vector<double> m_x {};
+  std::vector<double> m_y {};
+  int m_size = 0;
+};
+
+
+double Sigma (CircleData& data, Circle& circle) {
+  double sum=0.,dx,dy;
+
+  for (int i=0; i<data.size(); i++) {
+    dx = data.x(i) - circle.cx;
+    dy = data.y(i) - circle.cy;
+    sum += (sqrt(dx*dx+dy*dy) - circle.r) * (sqrt(dx*dx+dy*dy) - circle.r);
+  }
+  return sqrt(sum/data.size());
+}
+
+
+Circle CircleFit(CircleData& data)
+/*
+      Circle fit to a given set of data points (in 2D)
+
+      This is an algebraic fit, due to Taubin, based on the journal article
+
+      G. Taubin, "Estimation Of Planar Curves, Surfaces And Nonplanar
+                  Space Curves Defined By Implicit Equations, With
+                  Applications To Edge And Range Image Segmentation",
+                  IEEE Trans. PAMI, Vol. 13, pages 1115-1138, (1991)
+
+      Input:  data     - the class of data (contains the given points):
+
+	      data.size()   - the number of data points
+	      data.X[] - the array of X-coordinates
+	      data.Y[] - the array of Y-coordinates
+
+     Output:
+               circle - parameters of the fitting circle:
+
+	       circle.a - the X-coordinate of the center of the fitting circle
+	       circle.b - the Y-coordinate of the center of the fitting circle
+ 	       circle.r - the radius of the fitting circle
+ 	       circle.s - the root mean square error (the estimate of sigma)
+ 	       circle.j - the total number of iterations
+
+     The method is based on the minimization of the function
+
+                  sum [(x-a)^2 + (y-b)^2 - R^2]^2
+              F = -------------------------------
+                      sum [(x-a)^2 + (y-b)^2]
+
+     This method is more balanced than the simple Kasa fit.
+
+     It works well whether data points are sampled along an entire circle or
+     along a small arc.
+
+     It still has a small bias and its statistical accuracy is slightly
+     lower than that of the geometric fit (minimizing geometric distances),
+     but slightly higher than that of the very similar Pratt fit.
+     Besides, the Taubin fit is slightly simpler than the Pratt fit
+
+     It provides a very good initial guess for a subsequent geometric fit.
+
+       Nikolai Chernov  (September 2012)
+
+*/
+{
+  int i,iter,IterMAX=99;
+
+  double Xi,Yi,Zi;
+  double Mz,Mxy,Mxx,Myy,Mxz,Myz,Mzz,Cov_xy,Var_z;
+  double A0,A1,A2,A22,A3,A33;
+  double Dy,xnew,x,ynew,y;
+  double DET,Xcenter,Ycenter;
+
+  Circle circle;
+
+  Mxx=Myy=Mxy=Mxz=Myz=Mzz=0.;
+  for (i=0; i<data.size(); i++) {
+    Xi = data.x(i) - data.meanX();
+    Yi = data.y(i) - data.meanY();
+    Zi = Xi*Xi + Yi*Yi;
+
+    Mxy += Xi*Yi;
+    Mxx += Xi*Xi;
+    Myy += Yi*Yi;
+    Mxz += Xi*Zi;
+    Myz += Yi*Zi;
+    Mzz += Zi*Zi;
+  }
+  Mxx /= data.size();
+  Myy /= data.size();
+  Mxy /= data.size();
+  Mxz /= data.size();
+  Myz /= data.size();
+  Mzz /= data.size();
+
+  Mz = Mxx + Myy;
+  Cov_xy = Mxx*Myy - Mxy*Mxy;
+  Var_z = Mzz - Mz*Mz;
+  A3 = 4*Mz;
+  A2 = -3*Mz*Mz - Mzz;
+  A1 = Var_z*Mz + 4*Cov_xy*Mz - Mxz*Mxz - Myz*Myz;
+  A0 = Mxz*(Mxz*Myy - Myz*Mxy) + Myz*(Myz*Mxx - Mxz*Mxy) - Var_z*Cov_xy;
+  A22 = A2 + A2;
+  A33 = A3 + A3 + A3;
+
+  for (x=0.,y=A0,iter=0; iter<IterMAX; iter++) {
+    Dy = A1 + x*(A22 + A33*x);
+    xnew = x - y/Dy;
+    if ((xnew == x)||(!std::isfinite(xnew))) break;
+    ynew = A0 + xnew*(A1 + xnew*(A2 + xnew*A3));
+    if (abs(ynew)>=abs(y))  break;
+    x = xnew;  y = ynew;
+  }
+
+  DET = x*x - x*Mz + Cov_xy;
+  Xcenter = (Mxz*(Myy - x) - Myz*Mxy)/DET/2;
+  Ycenter = (Myz*(Mxx - x) - Mxz*Mxy)/DET/2;
+
+  circle.cx = Xcenter + data.meanX();
+  circle.cy = Ycenter + data.meanY();
+  circle.r = sqrt(Xcenter*Xcenter + Ycenter*Ycenter + Mz);
+  circle.s = Sigma(data,circle);
+  circle.i = 0;
+  circle.j = iter;
+
+  return circle;
+}
+
+
+#endif // FASERACTSKALMANFILTER_CIRCLEFIT_H
\ No newline at end of file
diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h
index 892b15b98bf957186cdf64000a130ed2f51ea223..ba983f245fdce513858c27cb0a814b48313eac0b 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h
+++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/CombinatorialKalmanFilterAlg.h
@@ -6,7 +6,6 @@
 #include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h"
 #include "TrackerPrepRawData/FaserSCT_ClusterContainer.h"
 #include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
-#include "FaserActsKalmanFilter/TruthBasedInitialParameterTool.h"
 //#include "FaserActsKalmanFilter/SPSimpleInitialParameterTool.h"
 //#include "FaserActsKalmanFilter/SPSeedBasedInitialParameterTool.h"
 #include "Acts/TrackFinding/CombinatorialKalmanFilter.hpp"
@@ -19,6 +18,10 @@
 #include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h"
 #include "FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h"
 #include "FaserActsKalmanFilter/PerformanceWriterTool.h"
+#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h"
+#include <boost/dynamic_bitset.hpp>
+using ConstTrackStateProxy = Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>;
+using ClusterSet = boost::dynamic_bitset<>;
 
 
 class FaserSCT_ID;
@@ -44,8 +47,8 @@ public:
       Acts::CombinatorialKalmanFilterOptions<IndexSourceLinkAccessor,
                                              MeasurementCalibrator,
                                              Acts::MeasurementSelector>;
-  using TrackFitterResult =
-      Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>;
+  using CKFResult = Acts::CombinatorialKalmanFilterResult<IndexSourceLink>;
+  using TrackFitterResult = Acts::Result<CKFResult>;
   using TrackFinderResult = std::vector<TrackFitterResult>;
   using TrackParameters = Acts::CurvilinearTrackParameters;
   using TrackParametersContainer = std::vector<TrackParameters>;
@@ -58,6 +61,29 @@ public:
                                          const TrackFinderOptions&) const = 0;
   };
 
+  struct TrajectoryInfo {
+    TrajectoryInfo(const FaserActsRecMultiTrajectory &traj) :
+        trajectory{traj}, clusterSet{nClusters} {
+      auto state = Acts::MultiTrajectoryHelpers::trajectoryState(traj.multiTrajectory(), traj.tips().front());
+      traj.multiTrajectory().visitBackwards(traj.tips().front(), [&](const ConstTrackStateProxy& state) {
+        auto typeFlags = state.typeFlags();
+        if (not typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) {
+          return true;
+        }
+        clusterSet.set(state.uncalibrated().index());
+        return true;
+      });
+      nMeasurements = state.nMeasurements;
+      chi2 = state.chi2Sum;
+    }
+
+    static size_t nClusters;
+    FaserActsRecMultiTrajectory trajectory;
+    ClusterSet clusterSet;
+    size_t nMeasurements;
+    double chi2;
+  };
+
   static std::shared_ptr<TrackFinderFunction> makeTrackFinderFunction(
       std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry,
       bool resolvePassive, bool resolveMaterial, bool resolveSensitive);
@@ -68,6 +94,7 @@ public:
   size_t m_numberOfTrackSeeds {0};
   size_t m_numberOfFittedTracks {0};
   size_t m_numberOfSelectedTracks {0};
+
   void computeSharedHits(std::vector<IndexSourceLink>* sourceLinks, TrackFinderResult& results) const;
   std::shared_ptr<TrackFinderFunction> m_fit;
   std::unique_ptr<const Acts::Logger> m_logger;
@@ -84,10 +111,10 @@ public:
   Gaudi::Property<bool> m_resolveMaterial {this, "resolveMaterial", true};
   Gaudi::Property<bool> m_resolveSensitive {this, "resolveSensitive", true};
   Gaudi::Property<bool> m_noDiagnostics {this, "noDiagnostics", true, "Set ACTS logging level to INFO and do not run performance writer, states writer or summary writer"};
-  Gaudi::Property<double> m_maxSteps {this, "maxSteps", 10000};
+  Gaudi::Property<double> m_maxSteps {this, "maxSteps", 1000};
   Gaudi::Property<double> m_chi2Max {this, "chi2Max", 15};
   Gaudi::Property<unsigned long> m_nMax {this, "nMax", 10};
-  Gaudi::Property<size_t> m_nTrajectories {this, "nTrajectories", 2};
+
   SG::ReadCondHandleKey<FaserFieldCacheCondObj> m_fieldCondObjInputKey {this, "FaserFieldCacheCondObj", "fieldCondObj", "Name of the Magnetic Field conditions object key"};
   ToolHandle<ITrackSeedTool> m_trackSeedTool {this, "TrackSeed", "ClusterTrackSeedTool"};
   ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"};
@@ -95,9 +122,11 @@ public:
   ToolHandle<RootTrajectoryStatesWriterTool> m_trajectoryStatesWriterTool {this, "RootTrajectoryStatesWriterTool", "RootTrajectoryStatesWriterTool"};
   ToolHandle<RootTrajectorySummaryWriterTool> m_trajectorySummaryWriterTool {this, "RootTrajectorySummaryWriterTool", "RootTrajectorySummaryWriterTool"};
 
-   std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, TrackFitterResult& fitResult) const;
-   const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const;
-   SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "CKFTrackCollection", "CKFTrackCollection" };
+  std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, TrackFitterResult& fitResult) const;
+  std::unique_ptr<Trk::Track> makeTrack(const Acts::GeometryContext &geoCtx, const FaserActsRecMultiTrajectory &traj) const;
+  const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const;
+  SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "CKFTrackCollection", "CKFTrackCollection" };
 };
 
 #endif // COMBINATORIALKALMANFILTERALG_H
+
diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackSeedTool.h
index 34b5c23c2516ec620a73ab74d192e7f76ae278fc..8345823daedd83b2ce1220b843303492f3101a57 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackSeedTool.h
+++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ITrackSeedTool.h
@@ -8,6 +8,7 @@
 #include "FaserActsKalmanFilter/Measurement.h"
 #include "Acts/EventData/TrackParameters.hpp"
 #include "TrackerPrepRawData/FaserSCT_Cluster.h"
+#include "TrackerSpacePoint/FaserSCT_SpacePoint.h"
 
 class ITrackSeedTool : virtual public IAlgTool {
 public:
@@ -20,6 +21,8 @@ public:
   virtual const std::shared_ptr<IdentifierLink> idLinks() const = 0;
   virtual const std::shared_ptr<std::vector<Measurement>> measurements() const = 0;
   virtual const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const = 0;
+  virtual const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters() const = 0;
+  virtual const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints() const = 0;
 };
 
 #endif  // FASERACTSKALMANFILTER_ITRACKSEEDTOOL_H
diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/KalmanFitterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/KalmanFitterTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c26faeb3f354618133ae478fca9a4f3cea947bd
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/KalmanFitterTool.h
@@ -0,0 +1,72 @@
+#ifndef FASERACTSKALMANFILTER_KALMANFITTERTOOL_H
+#define FASERACTSKALMANFILTER_KALMANFITTERTOOL_H
+
+#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "Acts/EventData/TrackParameters.hpp"
+#include "Acts/TrackFitting/KalmanFitter.hpp"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+#include "FaserActsKalmanFilter/IndexSourceLink.h"
+#include "FaserActsKalmanFilter/Measurement.h"
+#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h"
+#include "MagFieldConditions/FaserFieldCacheCondObj.h"
+#include "FaserActsKalmanFilter/RootTrajectoryStatesWriterTool.h"
+#include "FaserActsKalmanFilter/RootTrajectorySummaryWriterTool.h"
+#include "TrkTrack/Track.h"
+
+
+class FaserSCT_ID;
+
+class KalmanFitterTool : virtual public AthAlgTool {
+public:
+  KalmanFitterTool(const std::string &type, const std::string &name, const IInterface *parent);
+  virtual ~KalmanFitterTool() = default;
+  virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
+
+  using TrackParameters = Acts::BoundTrackParameters;
+  using IndexedParams = std::unordered_map<size_t, TrackParameters>;
+  using TrackFitterOptions =
+      Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic>;
+  using TrackFitterResult = Acts::Result<Acts::KalmanFitterResult<IndexSourceLink>>;
+  class TrackFitterFunction {
+  public:
+    virtual ~TrackFitterFunction() = default;
+    virtual TrackFitterResult operator()(const std::vector<IndexSourceLink>&,
+                                         const TrackParameters&,
+                                         const TrackFitterOptions&) const = 0;
+  };
+  static std::shared_ptr<TrackFitterFunction> makeTrackFitterFunction(
+      std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry);
+
+  virtual Acts::MagneticFieldContext getMagneticFieldContext(const EventContext& ctx) const;
+  std::unique_ptr<Trk::Track> fit(const EventContext& ctx, const Trk::Track& inputTrack,
+                                  std::vector<FaserActsRecMultiTrajectory> &trajectories,
+                                  const Acts::BoundVector& inputVector) const;
+
+private:
+  const FaserSCT_ID* m_idHelper {nullptr};
+  std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>>
+  getMeasurementsFromTrack(const Trk::Track &track) const;
+  // Acts::BoundTrackParameters getParametersFromTrack(const Acts::BoundVector& params, const Trk::TrackParameters *inputParameters) const;
+  Acts::BoundTrackParameters getParametersFromTrack(const Trk::TrackParameters *inputParameters, const Acts::BoundVector& inputVector) const;
+  std::shared_ptr<TrackFitterFunction> m_fit;
+  std::unique_ptr<const Acts::Logger> m_logger;
+  Gaudi::Property<std::string> m_actsLogging {this, "ActsLogging", "VERBOSE"};
+  Gaudi::Property<std::size_t> m_minMeasurements {this, "MinMeasurements", 12, "minimum number of measurements of the input track"};
+  Gaudi::Property<double> m_seedCovarianceScale {this, "SeedCovarianceScale", 100, "scale covariance from initial track"};
+  Gaudi::Property<bool> m_isMC {this, "isMC", false};
+  Gaudi::Property<bool> m_summaryWriter {this, "SummaryWriter", false};
+  Gaudi::Property<bool> m_statesWriter {this, "StatesWriter", false};
+  Gaudi::Property<bool> m_noDiagnostics {this, "noDiagnostics", true, "Set ACTS logging level to INFO and do not run performance writer, states writer or summary writer"};
+
+  SG::ReadCondHandleKey<FaserFieldCacheCondObj> m_fieldCondObjInputKey {this, "FaserFieldCacheCondObj", "fieldCondObj", "Name of the Magnetic Field conditions object key"};
+  ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"};
+  ToolHandle<RootTrajectoryStatesWriterTool> m_trajectoryStatesWriterTool {this, "RootTrajectoryStatesWriterTool", "RootTrajectoryStatesWriterTool"};
+  ToolHandle<RootTrajectorySummaryWriterTool> m_trajectorySummaryWriterTool {this, "RootTrajectorySummaryWriterTool", "RootTrajectorySummaryWriterTool"};
+  std::unique_ptr<Trk::Track> makeTrack(Acts::GeometryContext& tgContext, TrackFitterResult& fitResult) const;
+  const Trk::TrackParameters* ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const;
+};
+
+#endif //FASERACTSKALMANFILTER_KALMANFITTERTOOL_H
+
diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MyTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MyTrackSeedTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd29bbf5f020fe5ce139c8cbd12eb52154511110
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/MyTrackSeedTool.h
@@ -0,0 +1,117 @@
+#ifndef FASERACTSKALMANFILTER_MYTRACKSEEDTOOL_H
+#define FASERACTSKALMANFILTER_MYTRACKSEEDTOOL_H
+
+#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h"
+#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h"
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "Gaudi/Property.h"
+#include "GaudiKernel/IInterface.h"
+#include "GaudiKernel/StatusCode.h"
+
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+#include "FaserActsKalmanFilter/ITrackSeedTool.h"
+#include "TrkTrack/TrackCollection.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+class FaserSCT_ID;
+namespace TrackerDD { class SCT_DetectorManager; }
+
+
+class MyTrackSeedTool : public extends<AthAlgTool, ITrackSeedTool> {
+public:
+  MyTrackSeedTool(const std::string& type, const std::string& name, const IInterface* parent);
+  virtual ~MyTrackSeedTool() = default;
+  virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
+  virtual StatusCode run() override;
+
+  const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialTrackParameters() const override;
+  const std::shared_ptr<const Acts::Surface> initialSurface() const override;
+  const std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks() const override;
+  const std::shared_ptr<IdentifierLink> idLinks() const override;
+  const std::shared_ptr<std::vector<Measurement>> measurements() const override;
+  const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const override;
+  const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters() const override;
+  const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints() const override;
+
+private:
+  std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters;
+  std::shared_ptr<const Acts::Surface> m_initialSurface;
+  std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {};
+  std::shared_ptr<IdentifierLink> m_idLinks {};
+  std::shared_ptr<std::vector<Measurement>> m_measurements {};
+  std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> m_clusters {};
+  std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> m_seedClusters {};
+  std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> m_spacePoints {};
+
+  const FaserSCT_ID* m_idHelper {nullptr};
+  const TrackerDD::SCT_DetectorManager* m_detManager {nullptr};
+
+  ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {
+      this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"};
+  SG::ReadHandleKey<TrackCollection> m_trackCollection {
+      this, "TrackCollection", "SegmentFit", "Input track collection name" };
+  SG::ReadHandleKey<Tracker::FaserSCT_ClusterContainer> m_clusterContainerKey {
+      this, "ClusterContainer", "SCT_ClusterContainer"};
+  SG::ReadHandleKey<FaserSCT_SpacePointContainer> m_spacePointContainerKey {
+      this, "SpacePoints", "SCT_SpacePointContainer"};
+
+  // position resolution of a cluster
+  Gaudi::Property<double> m_std_cluster {this, "std_cluster", 0.04};
+
+  // covariance of the initial parameters
+  Gaudi::Property<double> m_covLoc0 {this, "covLoc0", 1};
+  Gaudi::Property<double> m_covLoc1 {this, "covLoc1", 1};
+  Gaudi::Property<double> m_covPhi {this, "covPhi", 1};
+  Gaudi::Property<double> m_covTheta {this, "covTheta", 1};
+  Gaudi::Property<double> m_covQOverP {this, "covQOverP", 1};
+  Gaudi::Property<double> m_covTime {this, "covTime", 1};
+  Gaudi::Property<double> m_origin {this, "origin", 0, "z position of the reference surface"};
+
+  static Acts::CurvilinearTrackParameters get_params(const Amg::Vector3D& p1, const Amg::Vector3D& p2, const Acts::BoundSymMatrix& cov, double origin);
+  // static std::pair<double, double> momentum(const std::map<int, Amg::Vector3D>& pos, double B=0.57);
+};
+
+inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>>
+MyTrackSeedTool::initialTrackParameters() const {
+  return m_initialTrackParameters;
+}
+
+inline const std::shared_ptr<const Acts::Surface>
+MyTrackSeedTool::initialSurface() const {
+  return m_initialSurface;
+}
+
+inline const std::shared_ptr<std::vector<IndexSourceLink>>
+MyTrackSeedTool::sourceLinks() const {
+  return m_sourceLinks;
+}
+
+inline const std::shared_ptr<IdentifierLink>
+MyTrackSeedTool::idLinks() const {
+  return m_idLinks;
+}
+
+inline const std::shared_ptr<std::vector<Measurement>>
+MyTrackSeedTool::measurements() const {
+  return m_measurements;
+}
+
+inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>>
+MyTrackSeedTool::clusters() const {
+  return m_clusters;
+}
+
+inline const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>>
+MyTrackSeedTool::seedClusters() const {
+  return m_seedClusters;
+}
+
+inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>>
+MyTrackSeedTool::spacePoints() const {
+  return m_spacePoints;
+}
+
+#endif  // FASERACTSKALMANFILTER_MYTRACKSEEDTOOL_H
diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ThreeStationTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ThreeStationTrackSeedTool.h
index a37f1dbf1061e636402e1069c49ac22a479c610b..3cf450414f20733b873ceda542f7c4ab44cdd573 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ThreeStationTrackSeedTool.h
+++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/ThreeStationTrackSeedTool.h
@@ -31,14 +31,31 @@ public:
   const std::shared_ptr<IdentifierLink> idLinks() const override;
   const std::shared_ptr<std::vector<Measurement>> measurements() const override;
   const std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters() const override;
+  const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters() const override;
+  const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints() const override;
 
 private:
+
+  struct Tracklet {
+   public:
+    Tracklet(const Amg::Vector3D& position, const std::vector<const Tracker::FaserSCT_Cluster*>& clusters)
+      : m_position(position), m_clusters(clusters) {}
+    inline const Amg::Vector3D position() const { return m_position; }
+    inline const std::vector<const Tracker::FaserSCT_Cluster*> clusters() const { return m_clusters; }
+    inline int size() const { return m_clusters.size(); }
+  private:
+    const Amg::Vector3D m_position;
+    const std::vector<const Tracker::FaserSCT_Cluster*> m_clusters;
+  };
+
   std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> m_initialTrackParameters;
   std::shared_ptr<const Acts::Surface> m_initialSurface;
   std::shared_ptr<std::vector<IndexSourceLink>> m_sourceLinks {};
   std::shared_ptr<IdentifierLink> m_idLinks {};
   std::shared_ptr<std::vector<Measurement>> m_measurements {};
   std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> m_clusters {};
+  std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> m_seedClusters {};
+  std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> m_spacePoints {};
 
   const FaserSCT_ID* m_idHelper {nullptr};
   const TrackerDD::SCT_DetectorManager* m_detManager {nullptr};
@@ -98,5 +115,14 @@ ThreeStationTrackSeedTool::clusters() const {
   return m_clusters;
 }
 
+inline const std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>>
+ThreeStationTrackSeedTool::seedClusters() const {
+  return m_seedClusters;
+}
+
+inline const std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>>
+ThreeStationTrackSeedTool::spacePoints() const {
+  return m_spacePoints;
+}
 
 #endif  // FASERACTSKALMANFILTER_THREESTATIONTRACKSEEDTOOL_H
diff --git a/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackSeedWriterTool.h b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackSeedWriterTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..e078acc19edd584ce2f514a4a3985bbaf7cc326c
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/FaserActsKalmanFilter/TrackSeedWriterTool.h
@@ -0,0 +1,50 @@
+#ifndef FASERACTSKALMANFILTER_TRACKSEEDWRITERTOOL_H
+#define FASERACTSKALMANFILTER_TRACKSEEDWRITERTOOL_H
+
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "Acts/EventData/TrackParameters.hpp"
+
+class TFile;
+class TTree;
+
+class TrackSeedWriterTool : public  AthAlgTool {
+ public:
+  TrackSeedWriterTool(const std::string& type,
+                      const std::string& name, const IInterface* parent);
+  virtual ~TrackSeedWriterTool() = default;
+  virtual StatusCode initialize() override;
+  virtual StatusCode finalize() override;
+  void writeout(const Acts::GeometryContext& gctx,
+                const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>>& initialParameters) const;
+
+private:
+  void initializeTree();
+  void clearVariables() const;
+  Gaudi::Property<std::string> m_filePath{this, "FilePath", "TrackSeeds.root", ""};
+  Gaudi::Property<std::string> m_treeName{this, "TreeName", "tree", ""};
+  TFile* m_file;
+  TTree* m_tree;
+
+  mutable int m_runNumber;
+  mutable int m_eventNumber;
+  mutable std::vector<float> m_eLOC0;
+  mutable std::vector<float> m_eLOC1;
+  mutable std::vector<float> m_ePHI;
+  mutable std::vector<float> m_eTHETA;
+  mutable std::vector<float> m_eQOP;
+  mutable std::vector<float> m_err_eLOC0;
+  mutable std::vector<float> m_err_eLOC1;
+  mutable std::vector<float> m_err_ePHI;
+  mutable std::vector<float> m_err_eTHETA;
+  mutable std::vector<float> m_err_eQOP;
+  mutable std::vector<float> m_x;
+  mutable std::vector<float> m_y;
+  mutable std::vector<float> m_z;
+  mutable std::vector<float> m_px;
+  mutable std::vector<float> m_py;
+  mutable std::vector<float> m_pz;
+};
+
+
+#endif // FASERACTSKALMANFILTER_TRACKSEEDWRITERTOOL_H
diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py
new file mode 100644
index 0000000000000000000000000000000000000000..728cc83e1cf04a37a67486bcaee6662e5dfb73ad
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py
@@ -0,0 +1,116 @@
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS and FASER collaborations
+
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from AthenaConfiguration.ComponentFactory import CompFactory
+from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg
+from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometrySvcCfg
+
+
+def FaserActsAlignmentCondAlgCfg(flags, **kwargs):
+    acc = ComponentAccumulator()
+    acc.addCondAlgo(CompFactory.FaserActsAlignmentCondAlg(name="FaserActsAlignmentCondAlg", **kwargs))
+    return acc
+
+
+def CKF2_OutputCfg(flags):
+    acc = ComponentAccumulator()
+    itemList = ["xAOD::EventInfo#*",
+                "xAOD::EventAuxInfo#*",
+                "TrackCollection#*",
+                ]
+    acc.merge(OutputStreamCfg(flags, "ESD", itemList))
+    ostream = acc.getEventAlgo("OutputStreamESD")
+    ostream.TakeItemsFromInput = True
+    return acc
+
+
+def CKF2Cfg(flags, **kwargs):
+    # acc = ComponentAccumulator()
+    acc = FaserSCT_GeometryCfg(flags)
+    acc.merge(MagneticFieldSvcCfg(flags))
+    # acc.merge(FaserActsAlignmentCondAlgCfg(flags))
+    acts_tracking_geometry_svc = ActsTrackingGeometrySvcCfg(flags)
+    acc.merge(acts_tracking_geometry_svc )
+
+# track_seed_tool = CompFactory.ClusterTrackSeedTool()
+    track_seed_tool = CompFactory.ThreeStationTrackSeedTool()
+    # track_seed_tool = CompFactory.ActsTrackSeedTool()
+    # track_seed_tool = CompFactory.MyTrackSeedTool()
+    sigma_loc0 = 1.9e-2
+    sigma_loc1 = 9e-1
+    sigma_phi = 3.3e-2
+    sigma_theta = 2.9e-4
+    p = 1000
+    sigma_p = 0.1 * p
+    sigma_qop = sigma_p / (p * p)
+    # initial_variance_inflation = [1000, 1000, 100, 100, 10000]
+    initial_variance_inflation = [100, 100, 100, 100, 1000]
+    track_seed_tool.covLoc0 = initial_variance_inflation[0] * sigma_loc1 * sigma_loc1
+    track_seed_tool.covLoc1 = initial_variance_inflation[1] * sigma_loc0 * sigma_loc0
+    track_seed_tool.covPhi = initial_variance_inflation[2] * sigma_phi * sigma_phi
+    track_seed_tool.covTheta = initial_variance_inflation[3] * sigma_theta * sigma_theta
+    track_seed_tool.covQOverP = initial_variance_inflation[4] * sigma_qop * sigma_qop
+    track_seed_tool.std_cluster = 0.0231
+    track_seed_tool.origin = 0
+
+    trajectory_states_writer_tool = CompFactory.RootTrajectoryStatesWriterTool()
+    trajectory_states_writer_tool.noDiagnostics = kwargs["noDiagnostics"]
+    trajectory_states_writer_tool1 = CompFactory.RootTrajectoryStatesWriterTool()
+    trajectory_states_writer_tool1.noDiagnostics = kwargs["noDiagnostics"]
+    trajectory_states_writer_tool1.FilePath = "track_states_ckf1.root"
+    trajectory_states_writer_tool2 = CompFactory.RootTrajectoryStatesWriterTool()
+    trajectory_states_writer_tool2.FilePath = "track_states_ckf2.root"
+    trajectory_states_writer_tool2.noDiagnostics = kwargs["noDiagnostics"]
+
+    trajectory_summary_writer_tool = CompFactory.RootTrajectorySummaryWriterTool(**kwargs)
+    trajectory_summary_writer_tool.noDiagnostics = kwargs["noDiagnostics"]
+    trajectory_summary_writer_tool1 = CompFactory.RootTrajectorySummaryWriterTool()
+    trajectory_summary_writer_tool1.FilePath = "track_summary_ckf1.root"
+    trajectory_summary_writer_tool1.noDiagnostics = kwargs["noDiagnostics"]
+    trajectory_summary_writer_tool2 = CompFactory.RootTrajectorySummaryWriterTool(**kwargs)
+    trajectory_summary_writer_tool2.FilePath = "track_summary_ckf2.root"
+    trajectory_summary_writer_tool2.noDiagnostics = kwargs["noDiagnostics"]
+
+    actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool")
+    actsExtrapolationTool.MaxSteps = 1000
+    actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool")
+
+    trajectory_performance_writer_tool = CompFactory.PerformanceWriterTool("PerformanceWriterTool", **kwargs)
+    trajectory_performance_writer_tool.ExtrapolationTool = actsExtrapolationTool
+    trajectory_performance_writer_tool.noDiagnostics = kwargs["noDiagnostics"]
+
+
+    ckf = CompFactory.CKF2(**kwargs)
+    kalman_fitter1 = CompFactory.KalmanFitterTool(name="fitterTool1", **kwargs)
+    kalman_fitter1.noDiagnostics = kwargs["noDiagnostics"]
+    kalman_fitter1.ActsLogging = "INFO"
+    kalman_fitter1.SummaryWriter = True
+    kalman_fitter1.StatesWriter = True
+    kalman_fitter1.SeedCovarianceScale = 10
+    kalman_fitter1.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool1
+    kalman_fitter1.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool1
+    ckf.KalmanFitterTool1 = kalman_fitter1
+
+    kalman_fitter2 = CompFactory.KalmanFitterTool(name="fitterTool2", **kwargs)
+    kalman_fitter2.noDiagnostics = kwargs["noDiagnostics"]
+    kalman_fitter2.ActsLogging = "INFO"
+    kalman_fitter2.SummaryWriter = True
+    kalman_fitter2.StatesWriter = True
+    kalman_fitter2.SeedCovarianceScale = 1
+    kalman_fitter2.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool2
+    kalman_fitter2.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool2
+    ckf.KalmanFitterTool2 = kalman_fitter2
+
+    ckf.TrackSeed = track_seed_tool
+    ckf.ActsLogging = "INFO"
+    ckf.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool
+    ckf.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool
+    ckf.PerformanceWriter = trajectory_performance_writer_tool
+
+    ckf.nMax = 10
+    ckf.chi2Max = 25
+    acc.addEventAlgo(ckf)
+    acc.merge(CKF2_OutputCfg(flags))
+    return acc
diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/CombinatorialKalmanFilterConfig.py b/Tracking/Acts/FaserActsKalmanFilter/python/CombinatorialKalmanFilterConfig.py
index eff59e223aa10a06a3e1f7202f350f6d7cb58243..fac9e7ec1713f9e387da5746ea5c9fd98519202e 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/python/CombinatorialKalmanFilterConfig.py
+++ b/Tracking/Acts/FaserActsKalmanFilter/python/CombinatorialKalmanFilterConfig.py
@@ -34,8 +34,10 @@ def CombinatorialKalmanFilterCfg(flags, **kwargs):
     acts_tracking_geometry_svc = ActsTrackingGeometrySvcCfg(flags)
     acc.merge(acts_tracking_geometry_svc )
 
-# track_seed_tool = CompFactory.ClusterTrackSeedTool()
+    # track_seed_tool = CompFactory.ClusterTrackSeedTool()
     track_seed_tool = CompFactory.ThreeStationTrackSeedTool()
+    # track_seed_tool = CompFactory.ActsTrackSeedTool()
+    # track_seed_tool = CompFactory.MyTrackSeedTool()
     sigma_loc0 = 1.9e-2
     sigma_loc1 = 9e-1
     sigma_phi = 3.3e-2
@@ -43,31 +45,29 @@ def CombinatorialKalmanFilterCfg(flags, **kwargs):
     p = 1000
     sigma_p = 0.1 * p
     sigma_qop = sigma_p / (p * p)
-    initial_variance_inflation = [100, 100, 100, 100, 100]
-    track_seed_tool.covLoc0 = initial_variance_inflation[0] * sigma_loc1 * sigma_loc1
-    track_seed_tool.covLoc1 = initial_variance_inflation[1] * sigma_loc0 * sigma_loc0
+    initial_variance_inflation = [100, 100, 100, 100, 1000]
+    track_seed_tool.covLoc0 = initial_variance_inflation[0] * sigma_loc0 * sigma_loc0
+    track_seed_tool.covLoc1 = initial_variance_inflation[1] * sigma_loc1 * sigma_loc1
     track_seed_tool.covPhi = initial_variance_inflation[2] * sigma_phi * sigma_phi
     track_seed_tool.covTheta = initial_variance_inflation[3] * sigma_theta * sigma_theta
     track_seed_tool.covQOverP = initial_variance_inflation[4] * sigma_qop * sigma_qop
     track_seed_tool.std_cluster = 0.023
     track_seed_tool.origin = 0
 
-    actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool")
-    actsExtrapolationTool.MaxSteps = 1000
-    actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool")
-
     trajectory_states_writer_tool = CompFactory.RootTrajectoryStatesWriterTool()
     trajectory_states_writer_tool.noDiagnostics = kwargs["noDiagnostics"]
     trajectory_states_writer_tool.MC = True
 
     trajectory_summary_writer_tool = CompFactory.RootTrajectorySummaryWriterTool()
-    trajectory_summary_writer_tool .noDiagnostics = kwargs["noDiagnostics"]
+    trajectory_summary_writer_tool.noDiagnostics = kwargs["noDiagnostics"]
 
+    actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool")
+    actsExtrapolationTool.MaxSteps = 1000
+    actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool")
     performance_writer_tool = CompFactory.PerformanceWriterTool("PerformanceWriterTool")
     performance_writer_tool.noDiagnostics = kwargs["noDiagnostics"]
     performance_writer_tool.ExtrapolationTool = actsExtrapolationTool
 
-
     ckf = CompFactory.CombinatorialKalmanFilterAlg(**kwargs)
     ckf.TrackSeed = track_seed_tool
     ckf.ActsLogging = "INFO"
@@ -75,10 +75,9 @@ def CombinatorialKalmanFilterCfg(flags, **kwargs):
     ckf.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool
     ckf.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool
     ckf.PerformanceWriterTool = performance_writer_tool
-    ckf.nTrajectories = 2
 
-    ckf.nMax = 1
-    ckf.chi2Max = 15
+    ckf.nMax = 10
+    ckf.chi2Max = 25
     acc.addEventAlgo(ckf)
     acc.merge(CombinatorialKalmanFilter_OutputCfg(flags))
     return acc
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4d90b6c7c619ec160bee114123066c7c25aa30a3
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx
@@ -0,0 +1,147 @@
+#include "FaserActsKalmanFilter/ActsTrackSeedTool.h"
+#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrackerReadoutGeometry/SCT_DetectorManager.h"
+#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h"
+#include "TrackerPrepRawData/FaserSCT_Cluster.h"
+#include "Identifier/Identifier.h"
+#include "Acts/Geometry/GeometryIdentifier.hpp"
+#include "boost/container/small_vector.hpp"
+#include "Acts/Seeding/EstimateTrackParamsFromSeed.hpp"
+
+using namespace Acts::UnitLiterals;
+
+
+ActsTrackSeedTool::ActsTrackSeedTool(
+    const std::string& type, const std::string& name, const IInterface* parent)
+    : base_class(type, name, parent) {}
+
+
+StatusCode ActsTrackSeedTool::initialize() {
+  ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+  ATH_CHECK(detStore()->retrieve(m_detManager, "SCT"));
+  ATH_CHECK(m_trackingGeometryTool.retrieve());
+  ATH_CHECK(m_trackCollection.initialize());
+  ATH_CHECK(m_clusterContainerKey.initialize());
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode ActsTrackSeedTool::run() {
+  SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection};
+  ATH_CHECK(trackCollection.isValid());
+
+  SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer {m_clusterContainerKey};
+  ATH_CHECK(clusterContainer.isValid());
+
+  using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>;
+  std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap();
+  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext();
+  Acts::GeometryContext geoctx = gctx.context();
+
+  const int kSize = 1;
+  using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>;
+  std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0};
+  std::vector<IndexSourceLink> sourceLinks;
+  std::vector<Measurement> measurements;
+  std::map<Index, Identifier> identifierLinkMap;
+  std::vector<const Tracker::FaserSCT_Cluster*> clusters {};
+  for (const Tracker::FaserSCT_ClusterCollection* clusterCollection : *clusterContainer) {
+    for (const Tracker::FaserSCT_Cluster* cluster : *clusterCollection) {
+      Identifier id = cluster->detectorElement()->identify();
+      identifierLinkMap[measurements.size()] = id;
+      if (identifierMap->count(id) != 0) {
+        Acts::GeometryIdentifier geoId = identifierMap->at(id);
+        IndexSourceLink sourceLink(geoId, measurements.size(), cluster);
+        // create measurement
+        const auto& par = cluster->localPosition();
+        Eigen::Matrix<double, 1, 1> pos {par.x(),};
+        Eigen::Matrix<double, 1, 1> cov {m_std_cluster * m_std_cluster,};
+        ThisMeasurement meas(sourceLink, Indices, pos, cov);
+        sourceLinks.push_back(sourceLink);
+        measurements.emplace_back(std::move(meas));
+        clusters.push_back(cluster);
+      }
+    }
+  }
+
+  std::map<int, std::vector<Amg::Vector3D>> station_position_map;
+  for (const Trk::Track* track : *trackCollection) {
+    auto momentum = track->trackParameters()->front()->momentum();
+    ATH_MSG_DEBUG("track momentum: " << momentum.x() << ", " << momentum.y() << ", " << momentum.z());
+    for (const Trk::TrackStateOnSurface* trackState : *(track->trackStateOnSurfaces())) {
+      auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> (trackState->measurementOnTrack());
+      if (clusterOnTrack) {
+        Identifier id = clusterOnTrack->identify();
+        int station = m_idHelper->station(id);
+        auto fitParameters = track->trackParameters()->front();
+        Amg::Vector3D fitPosition = fitParameters->position();
+        station_position_map[station].push_back(fitPosition);
+        break;
+      }
+    }
+  }
+
+  Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero();
+  cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0;
+  cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1;
+  cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi;
+  cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta;
+  cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP;
+  cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime;
+
+  std::vector<Acts::CurvilinearTrackParameters> initParams {};
+  for (const Amg::Vector3D& pos1 : station_position_map[1]) {
+    for (const Amg::Vector3D& pos2 : station_position_map[2]) {
+      for (const Amg::Vector3D& pos3 : station_position_map[3]) {
+        initParams.push_back(get_params(geoctx, pos1, pos2, pos3, cov, m_origin));
+//        auto seed = initParams.back();
+//        auto seed_momentum = seed.momentum();
+      }
+    }
+  }
+
+  m_initialTrackParameters = std::make_shared<std::vector<Acts::CurvilinearTrackParameters>>(initParams);
+  m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourceLinks);
+  m_idLinks = std::make_shared<IdentifierLink>(identifierLinkMap);
+  m_measurements = std::make_shared<std::vector<Measurement>>(measurements);
+  m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+      Acts::Vector3 {0, 0, m_origin}, Acts::Vector3{0, 0, -1});
+  m_clusters = std::make_shared<std::vector<const Tracker::FaserSCT_Cluster*>>(clusters);
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode ActsTrackSeedTool::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+
+Acts::CurvilinearTrackParameters ActsTrackSeedTool::get_params(
+    const Acts::GeometryContext& gctx, const Amg::Vector3D& pos1,
+    const Amg::Vector3D& pos2, const Amg::Vector3D& pos3,
+    const Acts::BoundSymMatrix& cov, double origin) {
+  const auto surface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+      Acts::Vector3 {0, 0, pos1.z()}, Acts::Vector3{0, 0, -1});
+  boost::container::small_vector<const Amg::Vector3D*, 3> spacepoints {};
+  spacepoints.push_back(&pos1);
+  spacepoints.push_back(&pos2);
+  spacepoints.push_back(&pos3);
+  auto trackParams = Acts::CurvilinearTrackParameters(Acts::Vector4{0, 0, 0, 0}, Acts::Vector3{0, 0, 0}, 0, 0, cov);
+  auto optParams = Acts::estimateTrackParamsFromSeed(
+      gctx, spacepoints.begin(), spacepoints.end(), *surface, Acts::Vector3{0.57_T, 0, 0}, 0.1_T);
+  if (not optParams.has_value()) {
+    std::cout << "Estimation of track parameters failed." << std::endl;
+  } else {
+    const auto& params = optParams.value();
+    double charge = std::copysign(1, params[Acts::eBoundQOverP]);
+    Acts::Vector4 pos {params.x(), params.y(), params.z(), params.w()};
+    Acts::Vector3 dir{std::sin(params[Acts::eBoundTheta]) * std::cos(params[Acts::eBoundPhi]),
+                      std::sin(params[Acts::eBoundTheta]) * std::sin(params[Acts::eBoundPhi]),
+                      std::cos(params[Acts::eBoundTheta])};
+    double abs_momentum = std::abs(1/params[Acts::eBoundQOverP]);
+    trackParams = Acts::CurvilinearTrackParameters(pos, dir, charge, abs_momentum, cov);
+  }
+  return trackParams;
+}
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..355e4a930024de1239d222e24fddf1f7560b6feb
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx
@@ -0,0 +1,647 @@
+#include "FaserActsKalmanFilter/CKF2.h"
+
+#include "StoreGate/ReadHandle.h"
+#include "StoreGate/ReadCondHandleKey.h"
+#include "TrackerSpacePoint/FaserSCT_SpacePointCollection.h"
+#include "TrackerSpacePoint/FaserSCT_SpacePoint.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrkPrepRawData/PrepRawData.h"
+#include "TrackerPrepRawData/FaserSCT_Cluster.h"
+#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h"
+#include "TrkRIO_OnTrack/RIO_OnTrack.h"
+#include "TrkSurfaces/Surface.h"
+#include "Identifier/Identifier.h"
+#include "Acts/Geometry/GeometryIdentifier.hpp"
+#include "Acts/EventData/TrackParameters.hpp"
+#include "FaserActsKalmanFilter/IndexSourceLink.h"
+#include "FaserActsKalmanFilter/Measurement.h"
+#include "FaserActsKalmanFilter/FaserActsRecMultiTrajectory.h"
+#include "Acts/Surfaces/PerigeeSurface.hpp"
+#include "Acts/MagneticField/MagneticFieldContext.hpp"
+#include "FaserActsKalmanFilter/TrackSelection.h"
+#include <algorithm>
+
+#include "FaserActsGeometry/FASERMagneticFieldWrapper.h"
+
+#include "Acts/Propagator/EigenStepper.hpp"
+#include "Acts/Propagator/Navigator.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/TrackFitting/GainMatrixSmoother.hpp"
+#include "Acts/TrackFitting/GainMatrixUpdater.hpp"
+
+
+#include "Acts/EventData/Measurement.hpp"
+#include "FaserActsKalmanFilter/CircleFit.h"
+
+size_t CKF2::TrajectoryInfo::nClusters {0};
+
+using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>;
+//std::array<Acts::BoundIndices, 2> indices = {Acts::eBoundLoc0, Acts::eBoundLoc1};
+
+
+CKF2::CKF2(
+    const std::string& name, ISvcLocator* pSvcLocator)
+    : AthAlgorithm(name, pSvcLocator) {}
+
+
+StatusCode CKF2::initialize() {
+  ATH_CHECK(m_fieldCondObjInputKey.initialize());
+  ATH_CHECK(m_trackingGeometryTool.retrieve());
+  ATH_CHECK(m_trackSeedTool.retrieve());
+  ATH_CHECK(m_kalmanFitterTool1.retrieve());
+  ATH_CHECK(m_kalmanFitterTool2.retrieve());
+  //  ATH_CHECK(m_trackCollection.initialize());
+  if (m_performanceWriter && !m_noDiagnostics) {
+    ATH_CHECK(m_performanceWriterTool.retrieve());
+  }
+  if (m_statesWriter && !m_noDiagnostics) {
+    ATH_CHECK(m_trajectoryStatesWriterTool.retrieve());
+  }
+  if (m_summaryWriter && !m_noDiagnostics) {
+    ATH_CHECK(m_trajectorySummaryWriterTool.retrieve());
+  }
+  ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID"));
+  m_fit = makeTrackFinderFunction(m_trackingGeometryTool->trackingGeometry(),
+                                  m_resolvePassive, m_resolveMaterial, m_resolveSensitive);
+  m_kf = makeTrackFitterFunction(m_trackingGeometryTool->trackingGeometry());
+  // FIXME fix Acts logging level
+  if (m_actsLogging == "VERBOSE") {
+    m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::VERBOSE);
+  } else if (m_actsLogging == "DEBUG") {
+    m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::DEBUG);
+  } else {
+    m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::INFO);
+  }
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode CKF2::execute() {
+  const EventContext& ctx = Gaudi::Hive::currentContext();
+
+  ATH_CHECK(m_trackCollection.initialize());
+  SG::WriteHandle<TrackCollection> trackContainer{m_trackCollection,ctx};
+  std::unique_ptr<TrackCollection> outputTracks = std::make_unique<TrackCollection>();
+
+  std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry
+      = m_trackingGeometryTool->trackingGeometry();
+
+  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext();
+  auto geoctx = gctx.context();
+  Acts::MagneticFieldContext magFieldContext = getMagneticFieldContext(ctx);
+  Acts::CalibrationContext calibContext;
+
+  CHECK(m_trackSeedTool->run());
+  std::shared_ptr<const Acts::Surface> initialSurface =
+      m_trackSeedTool->initialSurface();
+  std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>> initialParameters =
+      m_trackSeedTool->initialTrackParameters();
+  std::shared_ptr<std::vector<IndexSourceLink>> sourceLinks =
+      m_trackSeedTool->sourceLinks();
+  std::shared_ptr<IdentifierLink> idLinks = m_trackSeedTool->idLinks();
+  std::vector<Identifier> ids {};
+  for (const auto& idLink : *idLinks) {
+    ids.push_back(idLink.second);
+  }
+  std::shared_ptr<std::vector<Measurement>> measurements = m_trackSeedTool->measurements();
+  std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters = m_trackSeedTool->clusters();
+  std::shared_ptr<std::vector<const Tracker::FaserSCT_SpacePoint*>> spacePoints = m_trackSeedTool->spacePoints();
+  std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters = m_trackSeedTool->seedClusters();
+
+  TrajectoryInfo::nClusters = sourceLinks->size();
+
+  TrajectoriesContainer trajectories;
+  trajectories.reserve(initialParameters->size());
+
+  Acts::PropagatorPlainOptions pOptions;
+  pOptions.maxSteps = m_maxSteps;
+
+  Acts::MeasurementSelector::Config measurementSelectorCfg = {
+      {Acts::GeometryIdentifier(), {m_chi2Max, m_nMax}},
+  };
+
+  Acts::RotationMatrix3 rotation = Acts::RotationMatrix3::Identity();
+  rotation.col(0) = Acts::Vector3(0, 0, -1);
+  rotation.col(1) = Acts::Vector3(0, 1, 0);
+  rotation.col(2) = Acts::Vector3(1, 0, 0);
+  Acts::Translation3 trans(0., 0., 0.);
+  Acts::Transform3 trafo(rotation * trans);
+  initialSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(trafo);
+
+  // Set the CombinatorialKalmanFilter options
+  CKF2::TrackFinderOptions options(
+      geoctx, magFieldContext, calibContext,
+      IndexSourceLinkAccessor(), MeasurementCalibrator(*measurements),
+      Acts::MeasurementSelector(measurementSelectorCfg),
+      Acts::LoggerWrapper{*m_logger}, pOptions, &(*initialSurface));
+
+  // Perform the track finding for all initial parameters
+  ATH_MSG_DEBUG("Invoke track finding with " << initialParameters->size() << " seeds.");
+  IndexSourceLinkContainer tmp;
+  for (const auto& sl : *sourceLinks) {
+    tmp.emplace_hint(tmp.end(), sl);
+  }
+
+  for (const auto& init : *initialParameters) {
+    ATH_MSG_DEBUG("  position: " << init.position(geoctx).transpose());
+    ATH_MSG_DEBUG("  momentum: " << init.momentum().transpose());
+    ATH_MSG_DEBUG("  charge:   " << init.charge());
+  }
+
+  auto results = (*m_fit)(tmp, *initialParameters, options);
+
+  /*
+  for (std::size_t iseed = 0; iseed < results.size(); ++iseed) {
+    // The result for this seed
+    auto &result = results[iseed];
+    if (result.ok()) {
+      // Get the track finding output object
+      const auto &trackFindingOutput = result.value();
+
+      std::unique_ptr<Trk::Track> track = makeTrack(geoctx, result);
+
+      if (!trackFindingOutput.fittedParameters.empty()) {
+        const std::unordered_map<size_t, Acts::BoundTrackParameters> &params = trackFindingOutput.fittedParameters;
+        for (const auto &surface_params: params) {
+          ATH_MSG_VERBOSE("Fitted parameters for track " << iseed << ", surface " << surface_params.first);
+          ATH_MSG_VERBOSE("  position: " << surface_params.second.position(geoctx).transpose());
+          ATH_MSG_VERBOSE("  momentum: " << surface_params.second.momentum().transpose());
+          //          const auto& [currentTip, tipState] = trackFindingOutput.activeTips.back();
+          //          ATH_MSG_VERBOSE("  #measurements: " << tipState.nMeasurements);
+        }
+      } else {
+        ATH_MSG_DEBUG("No fitted parameters for track " << iseed);
+      }
+
+      m_kalmanFitterTool1->fit(ctx, *track);
+
+      // Create a Trajectories result struct
+      trajectories.emplace_back(trackFindingOutput.fittedStates,
+                                trackFindingOutput.lastMeasurementIndices,
+                                trackFindingOutput.fittedParameters);
+    } else {
+      ATH_MSG_WARNING("Track finding failed for seed " << iseed << " with error" << result.error());
+      // Track finding failed. Add an empty result so the output container has
+      // the same number of entries as the input.
+      trajectories.push_back(FaserActsRecMultiTrajectory());
+    }
+  }
+  */
+
+
+  // std::vector<TrackQuality> trackQuality;
+  // selectTracks(results, trackQuality);
+  //
+  // TrackFinderResult selectedResults;
+  // for (size_t i = 0; i < std::min(trackQuality.size(), (size_t)m_nTrajectories); ++i) {
+  //   selectedResults.push_back(Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(trackQuality[i].track));
+  // }
+
+  /*
+  TrackFinderResult minTrackRequirements {};
+  for (auto& result : results) {
+    if (not result.ok()) {
+      continue;
+    }
+    auto& ckfResult = result.value();
+    auto traj = FaserActsRecMultiTrajectory(ckfResult.fittedStates, ckfResult.lastMeasurementIndices, ckfResult.fittedParameters);
+    const auto& mj = traj.multiTrajectory();
+    const auto& trackTips = traj.tips();
+    size_t maxMeasurements = 0;
+    for (const auto& trackTip : trackTips) {
+      auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip);
+      size_t nMeasurements = trajState.nMeasurements;
+      if (nMeasurements > maxMeasurements) {
+        maxMeasurements = nMeasurements;
+      }
+    }
+    if (maxMeasurements >= m_minNumberMeasurements) {
+      minTrackRequirements.push_back(Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(ckfResult));
+    }
+  }
+
+  TrackFinderResult selectedResults {};
+  if (minTrackRequirements.size() > 2) {
+    std::pair<std::size_t, std::size_t> trackIndices = solveAmbiguity(results);
+    selectedResults.push_back(
+        Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(results.at(trackIndices.first).value()));
+    selectedResults.push_back(
+        Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(results.at(trackIndices.second).value()));
+  } else {
+    for (auto& result : minTrackRequirements) {
+      selectedResults.push_back(
+          Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(result.value()));
+    }
+  }
+   */
+  // computeSharedHits(sourceLinks.get(), selectedResults);
+
+  // results contains a MultiTrajectory for each track seed with a trajectory of each branch of the CKF.
+  // To simplify the ambiguity solving a list of MultiTrajectories is created, each containing only a single track.
+  std::list<TrajectoryInfo> allTrajectories;
+  for (auto &result : results) {
+    if (not result.ok()) {
+      continue;
+    }
+    CKFResult ckfResult = result.value();
+    for (size_t trackTip : ckfResult.lastMeasurementIndices) {
+      allTrajectories.emplace_back(TrajectoryInfo(FaserActsRecMultiTrajectory(
+          ckfResult.fittedStates, {trackTip}, {{trackTip, ckfResult.fittedParameters.at(trackTip)}})));
+    }
+  }
+
+  // the list of MultiTrajectories is sorted by the number of measurements using the chi2 value as a tie-breaker
+  allTrajectories.sort([](const TrajectoryInfo &left, const TrajectoryInfo &right) {
+    if (left.nMeasurements > right.nMeasurements) return true;
+    if (left.nMeasurements < right.nMeasurements) return false;
+    if (left.chi2 < right.chi2) return true;
+    else return false;
+  });
+
+  // select all tracks with at least 13 heats and with 6 or less shared hits, starting from the best track
+  // TODO use Gaudi parameters for the number of hits and shared hits
+  // TODO allow shared hits only in the first station?
+  std::vector<FaserActsRecMultiTrajectory> selectedTrajectories {};
+  while (not allTrajectories.empty()) {
+    TrajectoryInfo selected = allTrajectories.front();
+    selectedTrajectories.push_back(selected.trajectory);
+    allTrajectories.remove_if([&](const TrajectoryInfo &p) {
+      return (p.nMeasurements <= 12) || ((p.clusterSet & selected.clusterSet).count() > 6);
+    });
+  }
+
+  for (const FaserActsRecMultiTrajectory &traj : selectedTrajectories) {
+    const auto params = traj.trackParameters(traj.tips().front());
+    ATH_MSG_DEBUG("Fitted parameters");
+    ATH_MSG_DEBUG("  params:   " << params.parameters().transpose());
+    ATH_MSG_DEBUG("  position: " << params.position(geoctx).transpose());
+    ATH_MSG_DEBUG("  momentum: " << params.momentum().transpose());
+    ATH_MSG_DEBUG("  charge:   " << params.charge());
+    double charge = params.charge();
+    std::unique_ptr<Trk::Track> track = makeTrack(geoctx, traj);
+    if (track) {
+      // outputTracks->push_back(std::move(track));
+      std::unique_ptr<Trk::Track> track2 = m_kalmanFitterTool1->fit(ctx, *track, trajectories, Acts::BoundVector::Zero());
+      if (track2) {
+        std::unique_ptr<Trk::Track> track3 = m_kalmanFitterTool2->fit(ctx, *track2, trajectories, Acts::BoundVector::Zero());
+        outputTracks->push_back(std::move(track3));
+      }
+    }
+  }
+
+  // run the performance writer
+  if (m_statesWriter && !m_noDiagnostics) {
+    ATH_CHECK(m_trajectoryStatesWriterTool->write(geoctx, selectedTrajectories));
+  }
+  if (m_summaryWriter && !m_noDiagnostics) {
+    ATH_CHECK(m_trajectorySummaryWriterTool->write(geoctx, selectedTrajectories));
+  }
+  if  (m_performanceWriter && !m_noDiagnostics) {
+    ATH_CHECK(m_performanceWriterTool->write(geoctx, selectedTrajectories));
+  }
+  ATH_CHECK(trackContainer.record(std::move(outputTracks)));
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode CKF2::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+
+Acts::MagneticFieldContext CKF2::getMagneticFieldContext(const EventContext& ctx) const {
+  SG::ReadCondHandle<FaserFieldCacheCondObj> readHandle{m_fieldCondObjInputKey, ctx};
+  if (!readHandle.isValid()) {
+    std::stringstream msg;
+    msg << "Failed to retrieve magnetic field condition data " << m_fieldCondObjInputKey.key() << ".";
+    throw std::runtime_error(msg.str());
+  }
+  const FaserFieldCacheCondObj* fieldCondObj{*readHandle};
+  return Acts::MagneticFieldContext(fieldCondObj);
+}
+
+
+std::unique_ptr<Trk::Track>
+CKF2::makeTrack(const Acts::GeometryContext &geoCtx, const FaserActsRecMultiTrajectory &traj) const {
+  using ConstTrackStateProxy =
+      Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>;
+  std::unique_ptr<Trk::Track> newtrack = nullptr;
+  //Get the fit output object
+  DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{};
+  std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam;
+  // Loop over all the output state to create track state
+  traj.multiTrajectory().visitBackwards(traj.tips().front(), [&](const ConstTrackStateProxy& state) {
+    auto flag = state.typeFlags();
+    if (state.referenceSurface().associatedDetectorElement() != nullptr) {
+      // We need to determine the type of state
+      std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern;
+      const Trk::TrackParameters *parm;
+
+      // State is a hole (no associated measurement), use predicted para meters
+      if (flag[Acts::TrackStateFlag::HoleFlag] == true) {
+        const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                   state.predicted(),
+                                                   state.predictedCovariance());
+        parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+        // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm);
+        typePattern.set(Trk::TrackStateOnSurface::Hole);
+      }
+        // The state was tagged as an outlier, use filtered parameters
+      else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) {
+        const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                   state.filtered(), state.filteredCovariance());
+        parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+        typePattern.set(Trk::TrackStateOnSurface::Outlier);
+      }
+        // The state is a measurement state, use smoothed parameters
+      else {
+        const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                   state.smoothed(), state.smoothedCovariance());
+        actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam)));
+        //  const auto& psurface=actsParam.referenceSurface();
+        Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]);
+        //  const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]);
+        //  auto pos=actsParam.position(tgContext);
+        parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+        typePattern.set(Trk::TrackStateOnSurface::Measurement);
+      }
+      Tracker::FaserSCT_ClusterOnTrack* measState = nullptr;
+      if (state.hasUncalibrated()) {
+        const Tracker::FaserSCT_Cluster* fitCluster = state.uncalibrated().hit();
+        if (fitCluster->detectorElement() != nullptr) {
+          measState = new Tracker::FaserSCT_ClusterOnTrack{
+              fitCluster,
+              Trk::LocalParameters{
+                  Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1},
+                  Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2}
+              },
+              fitCluster->localCovariance(),
+              m_idHelper->wafer_hash(fitCluster->detectorElement()->identify())
+          };
+        }
+      }
+      double nDoF = state.calibratedSize();
+      const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF);
+      const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern);
+      // If a state was succesfully created add it to the trajectory
+      if (perState) {
+        finalTrajectory->insert(finalTrajectory->begin(), perState);
+      }
+    }
+    return;
+  });
+
+  // Create the track using the states
+  const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon);
+  // Trk::FitQuality* q = nullptr;
+  // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter     ); //Mark the fitter as KalmanFitter
+  newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr);
+  return newtrack;
+}
+
+
+std::unique_ptr<Trk::Track>
+CKF2::makeTrack(Acts::GeometryContext& geoCtx, TrackFitterResult& fitResult) const {
+  using ConstTrackStateProxy =
+  Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>;
+  std::unique_ptr<Trk::Track> newtrack = nullptr;
+  //Get the fit output object
+  const auto& fitOutput = fitResult.value();
+  if (fitOutput.fittedParameters.size() > 0) {
+    DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{};
+    std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam;
+    // Loop over all the output state to create track state
+    fitOutput.fittedStates.visitBackwards(fitOutput.lastMeasurementIndices.front(), [&](const ConstTrackStateProxy& state) {
+      auto flag = state.typeFlags();
+      if (state.referenceSurface().associatedDetectorElement() != nullptr) {
+        // We need to determine the type of state
+        std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern;
+        const Trk::TrackParameters *parm;
+
+        // State is a hole (no associated measurement), use predicted para meters
+        if (flag[Acts::TrackStateFlag::HoleFlag] == true) {
+          const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                     state.predicted(),
+                                                     state.predictedCovariance());
+          parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+          // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm);
+          typePattern.set(Trk::TrackStateOnSurface::Hole);
+        }
+          // The state was tagged as an outlier, use filtered parameters
+        else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) {
+          const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                     state.filtered(), state.filteredCovariance());
+          parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+          typePattern.set(Trk::TrackStateOnSurface::Outlier);
+        }
+          // The state is a measurement state, use smoothed parameters
+        else {
+          const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                     state.smoothed(), state.smoothedCovariance());
+          actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam)));
+          //  const auto& psurface=actsParam.referenceSurface();
+          Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]);
+          //  const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]);
+          //  auto pos=actsParam.position(tgContext);
+          parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+          typePattern.set(Trk::TrackStateOnSurface::Measurement);
+        }
+        Tracker::FaserSCT_ClusterOnTrack* measState = nullptr;
+        if (state.hasUncalibrated()) {
+          const Tracker::FaserSCT_Cluster* fitCluster = state.uncalibrated().hit();
+          if (fitCluster->detectorElement() != nullptr) {
+            measState = new Tracker::FaserSCT_ClusterOnTrack{
+                fitCluster,
+                Trk::LocalParameters{
+                    Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1},
+                    Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2}
+                },
+                fitCluster->localCovariance(),
+                m_idHelper->wafer_hash(fitCluster->detectorElement()->identify())
+            };
+          }
+        }
+        double nDoF = state.calibratedSize();
+        const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF);
+        const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern);
+        // If a state was succesfully created add it to the trajectory
+        if (perState) {
+          finalTrajectory->insert(finalTrajectory->begin(), perState);
+        }
+      }
+      return;
+    });
+
+    // Create the track using the states
+    const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon);
+    // Trk::FitQuality* q = nullptr;
+    // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter     ); //Mark the fitter as KalmanFitter
+    newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr);
+  }
+  return newtrack;
+}
+
+const Trk::TrackParameters*
+CKF2::ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const      {
+  using namespace Acts::UnitLiterals;
+  std::optional<AmgSymMatrix(5)> cov = std::nullopt;
+  if (actsParameter.covariance()){
+    AmgSymMatrix(5) newcov(actsParameter.covariance()->topLeftCorner(5, 5));
+    // Convert the covariance matrix to GeV
+    for(int i=0; i < newcov.rows(); i++){
+      newcov(i, 4) = newcov(i, 4)*1_MeV;
+    }
+    for(int i=0; i < newcov.cols(); i++){
+      newcov(4, i) = newcov(4, i)*1_MeV;
+    }
+    cov =  std::optional<AmgSymMatrix(5)>(newcov);
+  }
+  const Amg::Vector3D& pos=actsParameter.position(gctx);
+  double tphi=actsParameter.get<Acts::eBoundPhi>();
+  double ttheta=actsParameter.get<Acts::eBoundTheta>();
+  double tqOverP=actsParameter.get<Acts::eBoundQOverP>()*1_MeV;
+  double p = std::abs(1. / tqOverP);
+  Amg::Vector3D tmom(p * std::cos(tphi) * std::sin(ttheta), p * std::sin(tphi) * std::sin(ttheta), p * std::cos(ttheta));
+  const Trk::CurvilinearParameters * curv = new Trk::CurvilinearParameters(pos,tmom,tqOverP>0, cov);
+  return curv;
+}
+
+void CKF2::computeSharedHits(std::vector<IndexSourceLink>* sourceLinks, TrackFinderResult& results) const {
+  // Compute shared hits from all the reconstructed tracks
+  // Compute nSharedhits and Update ckf results
+  // hit index -> list of multi traj indexes [traj, meas]
+  static_assert(Acts::SourceLinkConcept<IndexSourceLink>,
+                "Source link does not fulfill SourceLinkConcept");
+
+  std::vector<std::size_t> firstTrackOnTheHit(
+      sourceLinks->size(), std::numeric_limits<std::size_t>::max());
+  std::vector<std::size_t> firstStateOnTheHit(
+      sourceLinks->size(), std::numeric_limits<std::size_t>::max());
+
+  for (unsigned int iresult = 0; iresult < results.size(); iresult++) {
+    if (not results.at(iresult).ok()) {
+      continue;
+    }
+
+    auto& ckfResult = results.at(iresult).value();
+    auto& measIndexes = ckfResult.lastMeasurementIndices;
+
+    for (auto measIndex : measIndexes) {
+      ckfResult.fittedStates.visitBackwards(measIndex, [&](const auto& state) {
+        if (not state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag))
+          return;
+
+        std::size_t hitIndex = state.uncalibrated().index();
+
+        // Check if hit not already used
+        if (firstTrackOnTheHit.at(hitIndex) ==
+            std::numeric_limits<std::size_t>::max()) {
+          firstTrackOnTheHit.at(hitIndex) = iresult;
+          firstStateOnTheHit.at(hitIndex) = state.index();
+          return;
+        }
+
+        // if already used, control if first track state has been marked
+        // as shared
+        int indexFirstTrack = firstTrackOnTheHit.at(hitIndex);
+        int indexFirstState = firstStateOnTheHit.at(hitIndex);
+        if (not results.at(indexFirstTrack).value().fittedStates.getTrackState(indexFirstState).typeFlags().test(Acts::TrackStateFlag::SharedHitFlag))
+          results.at(indexFirstTrack).value().fittedStates.getTrackState(indexFirstState).typeFlags().set(Acts::TrackStateFlag::SharedHitFlag);
+
+        // Decorate this track
+        results.at(iresult).value().fittedStates.getTrackState(state.index()).typeFlags().set(Acts::TrackStateFlag::SharedHitFlag);
+      });
+    }
+  }
+}
+
+
+namespace {
+
+using Updater = Acts::GainMatrixUpdater;
+using Smoother = Acts::GainMatrixSmoother;
+
+using Stepper = Acts::EigenStepper<>;
+using Navigator = Acts::Navigator;
+using Propagator = Acts::Propagator<Stepper, Navigator>;
+using CKF = Acts::CombinatorialKalmanFilter<Propagator, Updater, Smoother>;
+
+using TrackParametersContainer = std::vector<CKF2::TrackParameters>;
+
+struct TrackFinderFunctionImpl
+    : public CKF2::TrackFinderFunction {
+  CKF trackFinder;
+
+  TrackFinderFunctionImpl(CKF&& f) : trackFinder(std::move(f)) {}
+
+  CKF2::TrackFinderResult operator()(
+      const IndexSourceLinkContainer& sourcelinks,
+      const TrackParametersContainer& initialParameters,
+      const CKF2::TrackFinderOptions& options)
+  const override {
+    return trackFinder.findTracks(sourcelinks, initialParameters, options);
+  };
+};
+
+}  // namespace
+
+std::shared_ptr<CKF2::TrackFinderFunction>
+CKF2::makeTrackFinderFunction(
+    std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry,
+    bool resolvePassive, bool resolveMaterial, bool resolveSensitive) {
+  auto magneticField = std::make_shared<FASERMagneticFieldWrapper>();
+  Stepper stepper(std::move(magneticField));
+  Navigator::Config cfg{trackingGeometry};
+  cfg.resolvePassive = resolvePassive;
+  cfg.resolveMaterial = resolveMaterial;
+  cfg.resolveSensitive = resolveSensitive;
+  Navigator navigator(cfg);
+  Propagator propagator(std::move(stepper), std::move(navigator));
+  CKF trackFinder(std::move(propagator));
+
+  // build the track finder functions. owns the track finder object.
+  return std::make_shared<TrackFinderFunctionImpl>(std::move(trackFinder));
+}
+
+
+namespace {
+
+using Updater = Acts::GainMatrixUpdater;
+using Smoother = Acts::GainMatrixSmoother;
+using Stepper = Acts::EigenStepper<>;
+using Propagator = Acts::Propagator<Stepper, Acts::Navigator>;
+using Fitter = Acts::KalmanFitter<Propagator, Updater, Smoother>;
+
+struct TrackFitterFunctionImpl
+    : public CKF2::TrackFitterFunction {
+  Fitter trackFitter;
+
+  TrackFitterFunctionImpl(Fitter &&f) : trackFitter(std::move(f)) {}
+
+  CKF2::KFResult operator()(
+      const std::vector<IndexSourceLink> &sourceLinks,
+      const Acts::BoundTrackParameters &initialParameters,
+      const CKF2::TrackFitterOptions &options)
+  const override {
+    return trackFitter.fit(sourceLinks, initialParameters, options);
+  };
+};
+
+}  // namespace
+
+
+std::shared_ptr<CKF2::TrackFitterFunction>
+CKF2::makeTrackFitterFunction(
+    std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry) {
+  auto magneticField = std::make_shared<FASERMagneticFieldWrapper>();
+  auto stepper = Stepper(std::move(magneticField));
+  Acts::Navigator::Config cfg{trackingGeometry};
+  cfg.resolvePassive = false;
+  cfg.resolveMaterial = true;
+  cfg.resolveSensitive = true;
+  Acts::Navigator navigator(cfg);
+  Propagator propagator(std::move(stepper), std::move(navigator));
+  Fitter trackFitter(std::move(propagator));
+  return std::make_shared<TrackFitterFunctionImpl>(std::move(trackFitter));
+}
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx
index c565a135729fad666f5d1bdc4c2d6d4b5131579c..2ee66e278cd3488a4c99611c11d73a21bac2b3d2 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx
@@ -19,9 +19,11 @@
 #include "Acts/Surfaces/PerigeeSurface.hpp"
 #include "Acts/MagneticField/MagneticFieldContext.hpp"
 #include "FaserActsKalmanFilter/TrackSelection.h"
-#include "FaserActsKalmanFilter/MyAmbiguitySolver.h"
 #include <algorithm>
 
+
+size_t CombinatorialKalmanFilterAlg::TrajectoryInfo::nClusters {0};
+
 using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>;
 std::array<Acts::BoundIndices, 2> indices = {Acts::eBoundLoc0, Acts::eBoundLoc1};
 
@@ -36,13 +38,18 @@ StatusCode CombinatorialKalmanFilterAlg::initialize() {
   ATH_CHECK(m_trackingGeometryTool.retrieve());
   ATH_CHECK(m_trackSeedTool.retrieve());
   //  ATH_CHECK(m_trackCollection.initialize());
-  ATH_CHECK(m_performanceWriterTool.retrieve());
-  ATH_CHECK(m_trajectoryStatesWriterTool.retrieve());
-  ATH_CHECK(m_trajectorySummaryWriterTool.retrieve());
+  if (m_performanceWriter && !m_noDiagnostics) {
+    ATH_CHECK(m_performanceWriterTool.retrieve());
+  }
+  if (m_statesWriter && !m_noDiagnostics) {
+    ATH_CHECK(m_trajectoryStatesWriterTool.retrieve());
+  }
+  if (m_summaryWriter && !m_noDiagnostics) {
+    ATH_CHECK(m_trajectorySummaryWriterTool.retrieve());
+  }
   ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID"));
   m_fit = makeTrackFinderFunction(m_trackingGeometryTool->trackingGeometry(),
                                   m_resolvePassive, m_resolveMaterial, m_resolveSensitive);
-  // FIXME fix Acts logging level
   if (m_actsLogging == "VERBOSE" && !m_noDiagnostics) {
     m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::VERBOSE);
   } else if (m_actsLogging == "DEBUG" && !m_noDiagnostics) {
@@ -68,8 +75,8 @@ StatusCode CombinatorialKalmanFilterAlg::execute() {
 
   const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext();
   auto geoctx = gctx.context();
-  Acts::MagneticFieldContext magctx = getMagneticFieldContext(ctx);
-  Acts::CalibrationContext calctx;
+  Acts::MagneticFieldContext magFieldContext = getMagneticFieldContext(ctx);
+  Acts::CalibrationContext calibContext;
 
   CHECK(m_trackSeedTool->run());
   std::shared_ptr<const Acts::Surface> initialSurface =
@@ -81,6 +88,9 @@ StatusCode CombinatorialKalmanFilterAlg::execute() {
   std::shared_ptr<IdentifierLink> idLinks = m_trackSeedTool->idLinks();
   std::shared_ptr<std::vector<Measurement>> measurements = m_trackSeedTool->measurements();
   std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters = m_trackSeedTool->clusters();
+  std::shared_ptr<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>> seedClusters = m_trackSeedTool->seedClusters();
+
+  TrajectoryInfo::nClusters = sourceLinks->size();
 
   TrajectoriesContainer trajectories;
   trajectories.reserve(initialParameters->size());
@@ -88,114 +98,78 @@ StatusCode CombinatorialKalmanFilterAlg::execute() {
   Acts::PropagatorPlainOptions pOptions;
   pOptions.maxSteps = m_maxSteps;
 
-  Acts::GeometryContext geoContext = m_trackingGeometryTool->getNominalGeometryContext().context();
-  Acts::MagneticFieldContext magFieldContext = getMagneticFieldContext(ctx);
-  Acts::CalibrationContext calibContext;
   Acts::MeasurementSelector::Config measurementSelectorCfg = {
     {Acts::GeometryIdentifier(), {m_chi2Max, m_nMax}},
   };
 
+  Acts::RotationMatrix3 rotation = Acts::RotationMatrix3::Identity();
+  rotation.col(0) = Acts::Vector3(0, 0, -1);
+  rotation.col(1) = Acts::Vector3(0, 1, 0);
+  rotation.col(2) = Acts::Vector3(1, 0, 0);
+  Acts::Translation3 trans(0., 0., 0.);
+  Acts::Transform3 trafo(rotation * trans);
+  initialSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(trafo);
+
   // Set the CombinatorialKalmanFilter options
   CombinatorialKalmanFilterAlg::TrackFinderOptions options(
-      geoContext, magFieldContext, calibContext,
+      geoctx, magFieldContext, calibContext,
       IndexSourceLinkAccessor(), MeasurementCalibrator(*measurements),
       Acts::MeasurementSelector(measurementSelectorCfg),
       Acts::LoggerWrapper{*m_logger}, pOptions, &(*initialSurface));
 
+  m_numberOfTrackSeeds += initialParameters->size();
+
   // Perform the track finding for all initial parameters
   ATH_MSG_DEBUG("Invoke track finding with " << initialParameters->size() << " seeds.");
-  m_numberOfTrackSeeds += initialParameters->size();
   IndexSourceLinkContainer tmp;
   for (const auto& sl : *sourceLinks) {
     tmp.emplace_hint(tmp.end(), sl);
   }
   auto results = (*m_fit)(tmp, *initialParameters, options);
-  m_numberOfFittedTracks += results.size();
-
-  std::vector<TrackQuality> trackQuality;
-  selectTracks(results, trackQuality);
 
-  TrackFinderResult selectedResults;
-  for (size_t i = 0; i < std::min(trackQuality.size(), (size_t)m_nTrajectories); ++i) {
-    selectedResults.push_back(Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(trackQuality[i].track));
-  }
-  m_numberOfSelectedTracks += selectedResults.size();
-  /*
-  TrackFinderResult minTrackRequirements {};
-  for (auto& result : results) {
+  // results contains a MultiTrajectory for each track seed with a trajectory of each branch of the CKF.
+  // To simplify the ambiguity solving a list of MultiTrajectories is created, each containing only a single track.
+  std::list<TrajectoryInfo> allTrajectories;
+  for (auto &result : results) {
     if (not result.ok()) {
       continue;
     }
-    auto& ckfResult = result.value();
-    auto traj = FaserActsRecMultiTrajectory(ckfResult.fittedStates, ckfResult.lastMeasurementIndices, ckfResult.fittedParameters);
-    const auto& mj = traj.multiTrajectory();
-    const auto& trackTips = traj.tips();
-    size_t maxMeasurements = 0;
-    for (const auto& trackTip : trackTips) {
-      auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip);
-      size_t nMeasurements = trajState.nMeasurements;
-      if (nMeasurements > maxMeasurements) {
-        maxMeasurements = nMeasurements;
-      }
-    }
-    if (maxMeasurements >= m_minNumberMeasurements) {
-      minTrackRequirements.push_back(Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(ckfResult));
+    CKFResult ckfResult = result.value();
+    for (size_t trackTip : ckfResult.lastMeasurementIndices) {
+      allTrajectories.emplace_back(TrajectoryInfo(FaserActsRecMultiTrajectory(
+          ckfResult.fittedStates, {trackTip}, {{trackTip, ckfResult.fittedParameters.at(trackTip)}})));
     }
   }
 
-  TrackFinderResult selectedResults {};
-  if (minTrackRequirements.size() > 2) {
-    std::pair<std::size_t, std::size_t> trackIndices = solveAmbiguity(results);
-    selectedResults.push_back(
-        Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(results.at(trackIndices.first).value()));
-    selectedResults.push_back(
-        Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(results.at(trackIndices.second).value()));
-  } else {
-    for (auto& result : minTrackRequirements) {
-      selectedResults.push_back(
-          Acts::Result<Acts::CombinatorialKalmanFilterResult<IndexSourceLink>>(result.value()));
-    }
+  // the list of MultiTrajectories is sorted by the number of measurements using the chi2 value as a tie-breaker
+  allTrajectories.sort([](const TrajectoryInfo &left, const TrajectoryInfo &right) {
+    if (left.nMeasurements > right.nMeasurements) return true;
+    if (left.nMeasurements < right.nMeasurements) return false;
+    if (left.chi2 < right.chi2) return true;
+    else return false;
+  });
+
+  // select all tracks with at least 13 heats and with 6 or less shared hits, starting from the best track
+  // TODO use Gaudi parameters for the number of hits and shared hits
+  // TODO allow shared hits only in the first station?
+  std::vector<FaserActsRecMultiTrajectory> selectedTrajectories {};
+  while (not allTrajectories.empty()) {
+    TrajectoryInfo selected = allTrajectories.front();
+    selectedTrajectories.push_back(selected.trajectory);
+    allTrajectories.remove_if([&](const TrajectoryInfo &p) {
+      return (p.nMeasurements <= 12) || ((p.clusterSet & selected.clusterSet).count() > 6);
+    });
   }
-   */
-  computeSharedHits(sourceLinks.get(), selectedResults);
-
-  // Loop over the track finding results for all initial parameters
-  for (std::size_t iseed = 0; iseed < selectedResults.size(); ++iseed) {
-    // The result for this seed
-    auto& result = selectedResults[iseed];
-    if (result.ok()) {
-      // Get the track finding output object
-      const auto& trackFindingOutput = result.value();
-
-      std::unique_ptr<Trk::Track> track = makeTrack(geoctx, result);
-      if (track) {
-        outputTracks->push_back(std::move(track));
-      }
 
-      if (!trackFindingOutput.fittedParameters.empty()) {
-        const std::unordered_map<size_t, Acts::BoundTrackParameters>& params = trackFindingOutput.fittedParameters;
-        for (const auto& surface_params : params) {
-          ATH_MSG_VERBOSE("Fitted parameters for track " << iseed << ", surface " << surface_params.first);
-          ATH_MSG_VERBOSE("  position: " << surface_params.second.position(geoctx).transpose());
-          ATH_MSG_VERBOSE("  momentum: " << surface_params.second.momentum().transpose());
-//          const auto& [currentTip, tipState] = trackFindingOutput.activeTips.back();
-//          ATH_MSG_VERBOSE("  #measurements: " << tipState.nMeasurements);
-        }
-      } else {
-        ATH_MSG_DEBUG("No fitted parameters for track " << iseed);
-      }
-      // Create a Trajectories result struct
-      trajectories.emplace_back(trackFindingOutput.fittedStates,
-                                trackFindingOutput.lastMeasurementIndices,
-                                trackFindingOutput.fittedParameters);
-    } else {
-      ATH_MSG_WARNING("Track finding failed for seed " << iseed << " with error" << result.error());
-      // Track finding failed. Add an empty result so the output container has
-      // the same number of entries as the input.
-      trajectories.push_back(FaserActsRecMultiTrajectory());
+  // create Trk::Tracks from the trajectories
+  for (const FaserActsRecMultiTrajectory &traj : selectedTrajectories) {
+    std::unique_ptr<Trk::Track> track = makeTrack(geoctx, traj);
+    if (track) {
+      outputTracks->push_back(std::move(track));
     }
   }
 
+  // run the performance writer
   if (m_statesWriter && !m_noDiagnostics) {
     ATH_CHECK(m_trajectoryStatesWriterTool->write(geoctx, trajectories));
   }
@@ -233,83 +207,80 @@ Acts::MagneticFieldContext CombinatorialKalmanFilterAlg::getMagneticFieldContext
 }
 
 std::unique_ptr<Trk::Track>
-CombinatorialKalmanFilterAlg::makeTrack(Acts::GeometryContext& geoCtx, TrackFitterResult& fitResult) const {
+CombinatorialKalmanFilterAlg::makeTrack(const Acts::GeometryContext &geoCtx, const FaserActsRecMultiTrajectory &traj) const {
   using ConstTrackStateProxy =
-  Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>;
+      Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>;
   std::unique_ptr<Trk::Track> newtrack = nullptr;
   //Get the fit output object
-  const auto& fitOutput = fitResult.value();
-  if (fitOutput.fittedParameters.size() > 0) {
-    DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{};
-    std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam;
-    // Loop over all the output state to create track state
-    fitOutput.fittedStates.visitBackwards(fitOutput.lastMeasurementIndices.front(), [&](const ConstTrackStateProxy& state) {
-      auto flag = state.typeFlags();
-      if (state.referenceSurface().associatedDetectorElement() != nullptr) {
-        // We need to determine the type of state
-        std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern;
-        const Trk::TrackParameters *parm;
-
-        // State is a hole (no associated measurement), use predicted para meters
-        if (flag[Acts::TrackStateFlag::HoleFlag] == true) {
-          const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
-                                                     state.predicted(),
-                                                     state.predictedCovariance());
-          parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
-          // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm);
-          typePattern.set(Trk::TrackStateOnSurface::Hole);
-        }
-          // The state was tagged as an outlier, use filtered parameters
-        else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) {
-          const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
-                                                     state.filtered(), state.filteredCovariance());
-          parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
-          typePattern.set(Trk::TrackStateOnSurface::Outlier);
-        }
-          // The state is a measurement state, use smoothed parameters
-        else {
-          const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
-                                                     state.smoothed(), state.smoothedCovariance());
-          actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam)));
-          //  const auto& psurface=actsParam.referenceSurface();
-          Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]);
-          //  const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]);
-          //  auto pos=actsParam.position(tgContext);
-          parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
-          typePattern.set(Trk::TrackStateOnSurface::Measurement);
-        }
-        Tracker::FaserSCT_ClusterOnTrack* measState = nullptr;
-        if (state.hasUncalibrated()) {
-          const Tracker::FaserSCT_Cluster* fitCluster = state.uncalibrated().hit();
-          if (fitCluster->detectorElement() != nullptr) {
-            measState = new Tracker::FaserSCT_ClusterOnTrack{
-                fitCluster,
-                Trk::LocalParameters{
-                    Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1},
-                    Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2}
-                },
-                fitCluster->localCovariance(),
-                m_idHelper->wafer_hash(fitCluster->detectorElement()->identify())
-            };
-          }
-        }
-        double nDoF = state.calibratedSize();
-        const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF);
-        const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern);
-        // If a state was succesfully created add it to the trajectory
-        if (perState) {
-          finalTrajectory->insert(finalTrajectory->begin(), perState);
+  DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{};
+  std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam;
+  // Loop over all the output state to create track state
+  traj.multiTrajectory().visitBackwards(traj.tips().front(), [&](const ConstTrackStateProxy& state) {
+    auto flag = state.typeFlags();
+    if (state.referenceSurface().associatedDetectorElement() != nullptr) {
+      // We need to determine the type of state
+      std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern;
+      const Trk::TrackParameters *parm;
+
+      // State is a hole (no associated measurement), use predicted para meters
+      if (flag[Acts::TrackStateFlag::HoleFlag] == true) {
+        const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                   state.predicted(),
+                                                   state.predictedCovariance());
+        parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+        // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm);
+        typePattern.set(Trk::TrackStateOnSurface::Hole);
+      }
+        // The state was tagged as an outlier, use filtered parameters
+      else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) {
+        const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                   state.filtered(), state.filteredCovariance());
+        parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+        typePattern.set(Trk::TrackStateOnSurface::Outlier);
+      }
+        // The state is a measurement state, use smoothed parameters
+      else {
+        const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                   state.smoothed(), state.smoothedCovariance());
+        actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam)));
+        //  const auto& psurface=actsParam.referenceSurface();
+        Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]);
+        //  const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]);
+        //  auto pos=actsParam.position(tgContext);
+        parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+        typePattern.set(Trk::TrackStateOnSurface::Measurement);
+      }
+      Tracker::FaserSCT_ClusterOnTrack* measState = nullptr;
+      if (state.hasUncalibrated()) {
+        const Tracker::FaserSCT_Cluster* fitCluster = state.uncalibrated().hit();
+        if (fitCluster->detectorElement() != nullptr) {
+          measState = new Tracker::FaserSCT_ClusterOnTrack{
+              fitCluster,
+              Trk::LocalParameters{
+                  Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1},
+                  Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2}
+              },
+              fitCluster->localCovariance(),
+              m_idHelper->wafer_hash(fitCluster->detectorElement()->identify())
+          };
         }
       }
-      return;
-    });
-
-    // Create the track using the states
-    const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon);
-    // Trk::FitQuality* q = nullptr;
-    // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter     ); //Mark the fitter as KalmanFitter
-    newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr);
-  }
+      double nDoF = state.calibratedSize();
+      const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF);
+      const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern);
+      // If a state was succesfully created add it to the trajectory
+      if (perState) {
+        finalTrajectory->insert(finalTrajectory->begin(), perState);
+      }
+    }
+    return;
+  });
+
+  // Create the track using the states
+  const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon);
+  // Trk::FitQuality* q = nullptr;
+  // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter     ); //Mark the fitter as KalmanFitter
+  newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr);
   return newtrack;
 }
 
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..686047ae7232deb09ca207f6599666f0bd022aa3
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx
@@ -0,0 +1,355 @@
+#include "FaserActsKalmanFilter/KalmanFitterTool.h"
+
+#include "FaserActsGeometry/FASERMagneticFieldWrapper.h"
+
+#include "Acts/Propagator/EigenStepper.hpp"
+#include "Acts/Propagator/Navigator.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/TrackFitting/GainMatrixSmoother.hpp"
+#include "Acts/TrackFitting/GainMatrixUpdater.hpp"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+
+#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h"
+
+
+KalmanFitterTool::KalmanFitterTool(const std::string& type, const std::string& name, const IInterface* parent) :
+    AthAlgTool(type, name, parent) {}
+
+
+StatusCode KalmanFitterTool::initialize() {
+  ATH_CHECK(m_fieldCondObjInputKey.initialize());
+  ATH_CHECK(m_trackingGeometryTool.retrieve());
+  ATH_CHECK(detStore()->retrieve(m_idHelper,"FaserSCT_ID"));
+  if (m_statesWriter && !m_noDiagnostics) ATH_CHECK(m_trajectoryStatesWriterTool.retrieve());
+  if (m_summaryWriter && !m_noDiagnostics) ATH_CHECK(m_trajectorySummaryWriterTool.retrieve());
+  m_fit = makeTrackFitterFunction(m_trackingGeometryTool->trackingGeometry());
+  if (m_actsLogging == "VERBOSE" && !m_noDiagnostics) {
+    m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::VERBOSE);
+  } else if (m_actsLogging == "DEBUG" && !m_noDiagnostics) {
+    m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::DEBUG);
+  } else {
+    m_logger = Acts::getDefaultLogger("KalmanFitter", Acts::Logging::INFO);
+  }
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode KalmanFitterTool::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+std::unique_ptr<Trk::Track>
+KalmanFitterTool::fit(const EventContext &ctx, const Trk::Track &inputTrack,
+                      std::vector<FaserActsRecMultiTrajectory> &trajectories,
+                      const Acts::BoundVector& inputVector = Acts::BoundVector::Zero()) const {
+  std::unique_ptr<Trk::Track> newTrack = nullptr;
+  std::vector<FaserActsRecMultiTrajectory> myTrajectories;
+
+  if (!inputTrack.measurementsOnTrack() || inputTrack.measurementsOnTrack()->size() < m_minMeasurements) {
+    ATH_MSG_DEBUG("Input track has no or too little measurements and cannot be fitted");
+    return nullptr;
+  }
+
+  if (!inputTrack.trackParameters() || inputTrack.trackParameters()->empty()) {
+    ATH_MSG_DEBUG("Input track has no track parameters and cannot be fitted");
+    return nullptr;
+  }
+
+
+  auto pSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+      Acts::Vector3 {0, 0, 0}, Acts::Vector3{0, 0, -1});
+
+  Acts::GeometryContext gctx = m_trackingGeometryTool->getNominalGeometryContext().context();
+  Acts::MagneticFieldContext mfContext = getMagneticFieldContext(ctx);
+  Acts::CalibrationContext calibContext = Acts::CalibrationContext();
+
+  auto [sourceLinks, measurements] = getMeasurementsFromTrack(inputTrack);
+  auto trackParameters = getParametersFromTrack(inputTrack.trackParameters()->front(), inputVector);
+  ATH_MSG_DEBUG("trackParameters: " << trackParameters.parameters().transpose());
+  ATH_MSG_DEBUG("position: " << trackParameters.parameters().transpose());
+  ATH_MSG_DEBUG("momentum: " << trackParameters.momentum().transpose());
+  ATH_MSG_DEBUG("charge: " << trackParameters.charge());
+
+  Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic>
+      kfOptions(gctx, mfContext, calibContext, MeasurementCalibrator(measurements),
+                Acts::VoidOutlierFinder(), Acts::VoidReverseFilteringLogic(), Acts::LoggerWrapper{*m_logger},
+                Acts::PropagatorPlainOptions(), &(*pSurface));
+  kfOptions.multipleScattering = false;
+  kfOptions.energyLoss = false;
+
+  ATH_MSG_DEBUG("Invoke fitter");
+  auto result = (*m_fit)(sourceLinks, trackParameters, kfOptions);
+
+  if (result.ok()) {
+    const auto& fitOutput = result.value();
+    if (fitOutput.fittedParameters) {
+      const auto& params = fitOutput.fittedParameters.value();
+      ATH_MSG_DEBUG("ReFitted parameters");
+      ATH_MSG_DEBUG("  params:   " << params.parameters().transpose());
+      ATH_MSG_DEBUG("  position: " << params.position(gctx).transpose());
+      ATH_MSG_DEBUG("  momentum: " << params.momentum().transpose());
+      ATH_MSG_DEBUG("  charge:   " << params.charge());
+      using IndexedParams = std::unordered_map<size_t, Acts::BoundTrackParameters>;
+      IndexedParams indexedParams;
+      indexedParams.emplace(fitOutput.lastMeasurementIndex, std::move(params));
+      std::vector<size_t> trackTips;
+      trackTips.reserve(1);
+      trackTips.emplace_back(fitOutput.lastMeasurementIndex);
+      // trajectories.emplace_back(std::move(fitOutput.fittedStates),
+      //                           std::move(trackTips),
+      //                           std::move(indexedParams));
+      myTrajectories.emplace_back(std::move(fitOutput.fittedStates),
+                                  std::move(trackTips),
+                                  std::move(indexedParams));
+    } else {
+      ATH_MSG_DEBUG("No fitted parameters for track");
+    }
+    newTrack = makeTrack(gctx, result);
+  }
+
+  if (m_statesWriter && !m_noDiagnostics) {
+    StatusCode statusStatesWriterTool = m_trajectoryStatesWriterTool->write(gctx, myTrajectories);
+  }
+  if (m_summaryWriter && !m_noDiagnostics) {
+    StatusCode statusSummaryWriterTool = m_trajectorySummaryWriterTool->write(gctx, myTrajectories);
+  }
+
+  return newTrack;
+}
+
+
+namespace {
+
+using Updater = Acts::GainMatrixUpdater;
+using Smoother = Acts::GainMatrixSmoother;
+using Stepper = Acts::EigenStepper<>;
+using Propagator = Acts::Propagator<Stepper, Acts::Navigator>;
+using Fitter = Acts::KalmanFitter<Propagator, Updater, Smoother>;
+
+struct TrackFitterFunctionImpl
+    : public KalmanFitterTool::TrackFitterFunction {
+  Fitter trackFitter;
+
+  TrackFitterFunctionImpl(Fitter &&f) : trackFitter(std::move(f)) {}
+
+  KalmanFitterTool::TrackFitterResult operator()(
+      const std::vector<IndexSourceLink> &sourceLinks,
+      const KalmanFitterTool::TrackParameters &initialParameters,
+      const KalmanFitterTool::TrackFitterOptions &options)
+  const override {
+    return trackFitter.fit(sourceLinks, initialParameters, options);
+  };
+};
+
+}  // namespace
+
+
+std::shared_ptr<KalmanFitterTool::TrackFitterFunction>
+KalmanFitterTool::makeTrackFitterFunction(
+    std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry) {
+  auto magneticField = std::make_shared<FASERMagneticFieldWrapper>();
+  auto stepper = Stepper(std::move(magneticField));
+  Acts::Navigator::Config cfg{trackingGeometry};
+  cfg.resolvePassive = false;
+  cfg.resolveMaterial = true;
+  cfg.resolveSensitive = true;
+  Acts::Navigator navigator(cfg);
+  Propagator propagator(std::move(stepper), std::move(navigator));
+  Fitter trackFitter(std::move(propagator));
+  return std::make_shared<TrackFitterFunctionImpl>(std::move(trackFitter));
+}
+
+
+Acts::MagneticFieldContext KalmanFitterTool::getMagneticFieldContext(const EventContext& ctx) const {
+  SG::ReadCondHandle<FaserFieldCacheCondObj> readHandle{m_fieldCondObjInputKey, ctx};
+  if (!readHandle.isValid()) {
+    std::stringstream msg;
+    msg << "Failed to retrieve magnetic field condition data " << m_fieldCondObjInputKey.key() << ".";
+    throw std::runtime_error(msg.str());
+  }
+  const FaserFieldCacheCondObj* fieldCondObj{*readHandle};
+  return Acts::MagneticFieldContext(fieldCondObj);
+}
+
+
+std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>>
+KalmanFitterTool::getMeasurementsFromTrack(const Trk::Track &track) const {
+  const int kSize = 1;
+  std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0};
+  using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>;
+  using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>;
+
+  std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap();
+  std::vector<IndexSourceLink> sourceLinks;
+  std::vector<Measurement> measurements;
+  for (const Trk::MeasurementBase *meas : *track.measurementsOnTrack()) {
+    const auto* clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*>(meas);
+    const Tracker::FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData();
+    if (clusterOnTrack) {
+      Identifier id = clusterOnTrack->identify();
+      Identifier waferId = m_idHelper->wafer_id(id);
+      if (identifierMap->count(waferId) != 0) {
+        Acts::GeometryIdentifier geoId = identifierMap->at(waferId);
+        IndexSourceLink sourceLink(geoId, measurements.size(), cluster);
+        Eigen::Matrix<double, 1, 1> pos {meas->localParameters()[Trk::locX],};
+        Eigen::Matrix<double, 1, 1> cov {0.08 * 0.08 / 12};
+        ThisMeasurement actsMeas(sourceLink, Indices, pos, cov);
+        sourceLinks.push_back(sourceLink);
+        measurements.emplace_back(std::move(actsMeas));
+      }
+    }
+  }
+  return std::make_tuple(sourceLinks, measurements);
+}
+
+
+Acts::BoundTrackParameters
+KalmanFitterTool::getParametersFromTrack(const Trk::TrackParameters *inputParameters,
+                                         const Acts::BoundVector& inputVector) const {
+  using namespace Acts::UnitLiterals;
+  std::shared_ptr<const Acts::Surface> pSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+      Acts::Vector3 {0, 0, 0}, Acts::Vector3{0, 0, -1});
+
+  auto atlasParam = inputParameters->parameters();
+  auto center = inputParameters->associatedSurface().center();
+  // Acts::BoundVector params {center[Trk::locY], center[Trk::locX],
+  //                           atlasParam[Trk::phi0], atlasParam[Trk::theta],
+  //                           charge / (inputParameters->momentum().norm() * 1_MeV),
+  //                           0.};
+  Acts::BoundVector params;
+  if (inputVector == Acts::BoundVector::Zero()) {
+    params(0.0) = center[Trk::locY];
+    params(1.0) = center[Trk::locX];
+    params(2.0) = atlasParam[Trk::phi0];
+    params(3.0) = atlasParam[Trk::theta];
+    // input charge is 1 for positively charged particles and 0 for negatively charged particles!
+    double charge = 2 * inputParameters->charge() - 1;
+    params(4.0) = charge / (inputParameters->momentum().norm() * 1_MeV);
+    params(5.0) = 0.;
+  } else {
+    params = inputVector;
+  }
+  Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Identity();
+  cov.topLeftCorner(5, 5) = *inputParameters->covariance();
+
+  for(int i=0; i < cov.rows(); i++){
+    cov(i, 4) = cov(i, 4)/1_MeV;
+  }
+  for(int i=0; i < cov.cols(); i++){
+    cov(4, i) = cov(4, i)/1_MeV;
+  }
+  for (int i = 0; i < 6; ++i) {
+    cov(i,i) = m_seedCovarianceScale * cov(i,i);
+  }
+
+  return Acts::BoundTrackParameters(pSurface, params, inputParameters->charge(), cov);
+}
+
+
+std::unique_ptr<Trk::Track>
+KalmanFitterTool::makeTrack(Acts::GeometryContext& geoCtx, TrackFitterResult& fitResult) const {
+  using ConstTrackStateProxy =
+      Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>;
+  std::unique_ptr<Trk::Track> newtrack = nullptr;
+  //Get the fit output object
+  const auto& fitOutput = fitResult.value();
+  if (fitOutput.fittedParameters) {
+    DataVector<const Trk::TrackStateOnSurface>* finalTrajectory = new DataVector<const Trk::TrackStateOnSurface>{};
+    std::vector<std::unique_ptr<const Acts::BoundTrackParameters>> actsSmoothedParam;
+    // Loop over all the output state to create track state
+    fitOutput.fittedStates.visitBackwards(fitOutput.lastMeasurementIndex, [&](const ConstTrackStateProxy& state) {
+      auto flag = state.typeFlags();
+      if (state.referenceSurface().associatedDetectorElement() != nullptr) {
+        // We need to determine the type of state
+        std::bitset<Trk::TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes> typePattern;
+        const Trk::TrackParameters *parm;
+
+        // State is a hole (no associated measurement), use predicted para meters
+        if (flag[Acts::TrackStateFlag::HoleFlag] == true) {
+          const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                     state.predicted(),
+                                                     state.predictedCovariance());
+          parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+          // auto boundaryCheck = m_boundaryCheckTool->boundaryCheck(*p arm);
+          typePattern.set(Trk::TrackStateOnSurface::Hole);
+        }
+          // The state was tagged as an outlier, use filtered parameters
+        else if (flag[Acts::TrackStateFlag::OutlierFlag] == true) {
+          const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                     state.filtered(), state.filteredCovariance());
+          parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+          typePattern.set(Trk::TrackStateOnSurface::Outlier);
+        }
+          // The state is a measurement state, use smoothed parameters
+        else {
+          const Acts::BoundTrackParameters actsParam(state.referenceSurface().getSharedPtr(),
+                                                     state.smoothed(), state.smoothedCovariance());
+          actsSmoothedParam.push_back(std::make_unique<const Acts::BoundTrackParameters>(Acts::BoundTrackParameters(actsParam)));
+          //  const auto& psurface=actsParam.referenceSurface();
+          Acts::Vector2 local(actsParam.parameters()[Acts::eBoundLoc0], actsParam.parameters()[Acts::eBoundLoc1]);
+          //  const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(actsParam.parameters()[Acts::eBoundPhi], actsParam.parameters()[Acts::eBoundTheta]);
+          //  auto pos=actsParam.position(tgContext);
+          parm = ConvertActsTrackParameterToATLAS(actsParam, geoCtx);
+          typePattern.set(Trk::TrackStateOnSurface::Measurement);
+        }
+        Tracker::FaserSCT_ClusterOnTrack* measState = nullptr;
+        if (state.hasUncalibrated()) {
+          const Tracker::FaserSCT_Cluster* fitCluster = state.uncalibrated().hit();
+          if (fitCluster->detectorElement() != nullptr) {
+            measState = new Tracker::FaserSCT_ClusterOnTrack{
+                fitCluster,
+                Trk::LocalParameters{
+                    Trk::DefinedParameter{fitCluster->localPosition()[0], Trk::loc1},
+                    Trk::DefinedParameter{fitCluster->localPosition()[1], Trk::loc2}
+                },
+                fitCluster->localCovariance(),
+                m_idHelper->wafer_hash(fitCluster->detectorElement()->identify())
+            };
+          }
+        }
+        double nDoF = state.calibratedSize();
+        const Trk::FitQualityOnSurface *quality = new Trk::FitQualityOnSurface(state.chi2(), nDoF);
+        const Trk::TrackStateOnSurface *perState = new Trk::TrackStateOnSurface(measState, parm, quality, nullptr, typePattern);
+        // If a state was succesfully created add it to the trajectory
+        if (perState) {
+          finalTrajectory->insert(finalTrajectory->begin(), perState);
+        }
+      }
+      return;
+    });
+
+    // Create the track using the states
+    const Trk::TrackInfo newInfo(Trk::TrackInfo::TrackFitter::KalmanFitter, Trk::ParticleHypothesis::muon);
+    // Trk::FitQuality* q = nullptr;
+    // newInfo.setTrackFitter(Trk::TrackInfo::TrackFitter::KalmanFitter     ); //Mark the fitter as KalmanFitter
+    newtrack = std::make_unique<Trk::Track>(newInfo, std::move(*finalTrajectory), nullptr);
+  }
+  return newtrack;
+}
+
+
+const Trk::TrackParameters*
+KalmanFitterTool::ConvertActsTrackParameterToATLAS(const Acts::BoundTrackParameters &actsParameter, const Acts::GeometryContext& gctx) const {
+  using namespace Acts::UnitLiterals;
+  std::optional<AmgSymMatrix(5)> cov = std::nullopt;
+  if (actsParameter.covariance()){
+    AmgSymMatrix(5) newcov(actsParameter.covariance()->topLeftCorner(5, 5));
+    // Convert the covariance matrix to GeV
+    for(int i=0; i < newcov.rows(); i++){
+      newcov(i, 4) = newcov(i, 4)*1_MeV;
+    }
+    for(int i=0; i < newcov.cols(); i++){
+      newcov(4, i) = newcov(4, i)*1_MeV;
+    }
+    cov =  std::optional<AmgSymMatrix(5)>(newcov);
+  }
+  const Amg::Vector3D& pos=actsParameter.position(gctx);
+  double tphi=actsParameter.get<Acts::eBoundPhi>();
+  double ttheta=actsParameter.get<Acts::eBoundTheta>();
+  double tqOverP=actsParameter.get<Acts::eBoundQOverP>()*1_MeV;
+  double p = std::abs(1. / tqOverP);
+  Amg::Vector3D tmom(p * std::cos(tphi) * std::sin(ttheta), p * std::sin(tphi) * std::sin(ttheta), p * std::cos(ttheta));
+  const Trk::CurvilinearParameters * curv = new Trk::CurvilinearParameters(pos,tmom,tqOverP>0, cov);
+  return curv;
+}
+
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/MyTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/MyTrackSeedTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..c2648161b595230fc626544d4e9dd11fdf4118e5
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/MyTrackSeedTool.cxx
@@ -0,0 +1,143 @@
+#include "FaserActsKalmanFilter/MyTrackSeedTool.h"
+
+#include "TrackerRIO_OnTrack/FaserSCT_ClusterOnTrack.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "TrackerReadoutGeometry/SCT_DetectorManager.h"
+#include "TrackerPrepRawData/FaserSCT_Cluster.h"
+#include "TrackerPrepRawData/FaserSCT_ClusterCollection.h"
+#include "TrackerSpacePoint/FaserSCT_SpacePoint.h"
+#include "TrackerSpacePoint/FaserSCT_SpacePointCollection.h"
+#include "Identifier/Identifier.h"
+#include "Acts/Geometry/GeometryIdentifier.hpp"
+
+
+MyTrackSeedTool::MyTrackSeedTool( const std::string& type, const std::string& name, const IInterface* parent) :
+    base_class(type, name, parent) {}
+
+
+StatusCode MyTrackSeedTool::initialize() {
+  ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+  ATH_CHECK(detStore()->retrieve(m_detManager, "SCT"));
+  ATH_CHECK(m_trackingGeometryTool.retrieve());
+  ATH_CHECK(m_trackCollection.initialize());
+  ATH_CHECK(m_clusterContainerKey.initialize());
+  ATH_CHECK(m_spacePointContainerKey.initialize());
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode MyTrackSeedTool::run() {
+
+  // create track seeds for multiple tracks
+  SG::ReadHandle<TrackCollection> trackCollection {m_trackCollection};
+  ATH_CHECK(trackCollection.isValid());
+
+  SG::ReadHandle<Tracker::FaserSCT_ClusterContainer> clusterContainer {m_clusterContainerKey};
+  ATH_CHECK(clusterContainer.isValid());
+
+  SG::ReadHandle<FaserSCT_SpacePointContainer> spacePointContainer {m_spacePointContainerKey};
+  ATH_CHECK(spacePointContainer.isValid());
+
+  using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>;
+  std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap();
+
+  std::map<Identifier, const Tracker::FaserSCT_SpacePoint*> spacePointMap {};
+  for (const FaserSCT_SpacePointCollection* spacePointCollection : *spacePointContainer) {
+    for (const Tracker::FaserSCT_SpacePoint *spacePoint: *spacePointCollection) {
+      Identifier id1 = spacePoint->cluster1()->identify();
+      spacePointMap[id1] = spacePoint;
+      Identifier id2 = spacePoint->cluster2()->identify();
+      spacePointMap[id2] = spacePoint;
+    }
+  }
+
+  const int kSize = 1;
+  using ThisMeasurement = Acts::Measurement<IndexSourceLink, Acts::BoundIndices, kSize>;
+  std::array<Acts::BoundIndices, kSize> Indices = {Acts::eBoundLoc0};
+  std::vector<IndexSourceLink> sourceLinks;
+  std::vector<Measurement> measurements;
+  std::map<Index, Identifier> identifierLinkMap;
+  std::vector<const Tracker::FaserSCT_SpacePoint*> spacePoints {};
+  std::vector<const Tracker::FaserSCT_Cluster*> clusters {};
+  for (const Tracker::FaserSCT_ClusterCollection* clusterCollection : *clusterContainer) {
+    for (const Tracker::FaserSCT_Cluster* cluster : *clusterCollection) {
+      Identifier id = cluster->detectorElement()->identify();
+      identifierLinkMap[measurements.size()] = id;
+      if (identifierMap->count(id) != 0) {
+        Acts::GeometryIdentifier geoId = identifierMap->at(id);
+        IndexSourceLink sourceLink(geoId, measurements.size(), cluster);
+        // create measurement
+        const auto& par = cluster->localPosition();
+        Eigen::Matrix<double, 1, 1> pos {par.x(),};
+        Eigen::Matrix<double, 1, 1> cov {m_std_cluster * m_std_cluster,};
+        ThisMeasurement meas(sourceLink, Indices, pos, cov);
+        sourceLinks.push_back(sourceLink);
+        measurements.emplace_back(std::move(meas));
+        clusters.push_back(cluster);
+        if (spacePointMap.count(cluster->identify()) > 0) {
+          spacePoints.push_back(spacePointMap[cluster->identify()]);
+        } else {
+          spacePoints.push_back(nullptr);
+        }
+      }
+    }
+  }
+
+
+  Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero();
+  cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = m_covLoc0;
+  cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = m_covLoc1;
+  cov(Acts::eBoundPhi, Acts::eBoundPhi) = m_covPhi;
+  cov(Acts::eBoundTheta, Acts::eBoundTheta) = m_covTheta;
+  cov(Acts::eBoundQOverP, Acts::eBoundQOverP) = m_covQOverP;
+  cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime;
+
+  std::map<int, std::vector<Amg::Vector3D>> stationHitMap {};
+  for (const Trk::Track* track : *trackCollection) {
+    const Amg::Vector3D position = track->trackParameters()->front()->position();
+    for (const Trk::TrackStateOnSurface* trackState : *(track->trackStateOnSurfaces())) {
+      auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> (trackState->measurementOnTrack());
+      if (clusterOnTrack) {
+        int station = m_idHelper->station(clusterOnTrack->identify());
+        stationHitMap[station].push_back(position);
+        break;
+      }
+    }
+  }
+
+
+  std::vector<Acts::CurvilinearTrackParameters> initParams {};
+  for (size_t i = 0; i < stationHitMap.size(); ++i) {
+    for (size_t j = i+1; j < stationHitMap.size(); ++j) {
+      for (const auto &p1 : stationHitMap[i]) {
+        for (const auto &p2 : stationHitMap[j]) {
+          initParams.push_back(get_params(p1, p2, cov, m_origin));
+        }
+      }
+    }
+  }
+
+  m_initialTrackParameters = std::make_shared<std::vector<Acts::CurvilinearTrackParameters>>(initParams);
+  m_sourceLinks = std::make_shared<std::vector<IndexSourceLink>>(sourceLinks);
+  m_idLinks = std::make_shared<IdentifierLink>(identifierLinkMap);
+  m_measurements = std::make_shared<std::vector<Measurement>>(measurements);
+  m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+      Acts::Vector3 {0, 0, m_origin}, Acts::Vector3{0, 0, -1});
+  m_clusters = std::make_shared<std::vector<const Tracker::FaserSCT_Cluster*>>(clusters);
+  m_spacePoints = std::make_shared<std::vector<const Tracker::FaserSCT_SpacePoint*>>(spacePoints);
+  // m_seedClusters = std::make_shared<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>>({});
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode MyTrackSeedTool::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+
+Acts::CurvilinearTrackParameters MyTrackSeedTool::get_params(const Amg::Vector3D& p1, const Amg::Vector3D& p2, const Acts::BoundSymMatrix& cov, double origin) {
+  Acts::Vector3 dir = p2 - p1;
+  Acts::Vector3 pos = p1 - (p1.z() - origin)/dir.z() * dir;
+  Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0};
+  return Acts::CurvilinearTrackParameters(pos4, dir, 10000000, 1, cov);
+}
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.cxx
index b01d58ed37c095c451c3f453cbbcc4f261945cec..c545c551adeb640a985ab4999d0864ecd817fb7c 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/PerformanceWriterTool.cxx
@@ -11,23 +11,23 @@ PerformanceWriterTool::PerformanceWriterTool(
 
 
 StatusCode PerformanceWriterTool::initialize() {
-  if (!m_noDiagnostics) {
     ATH_CHECK(m_extrapolationTool.retrieve());
     ATH_CHECK(m_mcEventCollectionKey.initialize());
     ATH_CHECK(m_simDataCollectionKey.initialize());
 
-    std::string filePath = m_filePath;
-    m_outputFile = TFile::Open(filePath.c_str(), "RECREATE");
-    if (m_outputFile == nullptr) {
-      ATH_MSG_WARNING("Unable to open output file at " << m_filePath);
-      return StatusCode::RECOVERABLE;
+    if (!m_noDiagnostics) {
+      std::string filePath = m_filePath;
+      m_outputFile = TFile::Open(filePath.c_str(), "RECREATE");
+      if (m_outputFile == nullptr) {
+        ATH_MSG_WARNING("Unable to open output file at " << m_filePath);
+        return StatusCode::RECOVERABLE;
+      }
     }
 
     // initialize the residual and efficiency plots tool
     m_resPlotTool.book(m_resPlotCache);
     m_effPlotTool.book(m_effPlotCache);
     m_summaryPlotTool.book(m_summaryPlotCache);
-  }
   return StatusCode::SUCCESS;
 }
 
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx
index b857ce4788a0a8b51ad8bcc8080761bb732adac9..634e356a887d45afa6ddf7c06a1d8e4566d0ef8b 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectoryStatesWriterTool.cxx
@@ -23,13 +23,13 @@ RootTrajectoryStatesWriterTool::RootTrajectoryStatesWriterTool(
     : AthAlgTool(type, name, parent) {}
 
 StatusCode RootTrajectoryStatesWriterTool::initialize() {
-  if (!m_noDiagnostics) {
-    ATH_CHECK(m_mcEventCollectionKey.initialize());
-    ATH_CHECK(m_simDataCollectionKey.initialize());
-    ATH_CHECK(m_faserSiHitKey.initialize());
-    ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
-    ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT"));
+  ATH_CHECK(m_mcEventCollectionKey.initialize());
+  ATH_CHECK(m_simDataCollectionKey.initialize());
+  ATH_CHECK(m_faserSiHitKey.initialize());
+  ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+  ATH_CHECK(detStore()->retrieve(m_detMgr, "SCT"));
 
+  if (!m_noDiagnostics) {
     std::string filePath = m_filePath;
     std::string treeName = m_treeName;
     m_outputFile = TFile::Open(filePath.c_str(), "RECREATE");
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.cxx
index 2d8765e3163930e003b0d1a6eeaeb999256b9432..bb916b9bfefeaf47c013b29122c12eb48f17abf7 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/RootTrajectorySummaryWriterTool.cxx
@@ -32,11 +32,11 @@ RootTrajectorySummaryWriterTool::RootTrajectorySummaryWriterTool(
 
 
 StatusCode RootTrajectorySummaryWriterTool::initialize() {
-  if (!m_noDiagnostics) {
-        ATH_CHECK(m_simDataCollectionKey.initialize());
-        ATH_CHECK(m_mcEventCollectionKey.initialize());
-        ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
+  ATH_CHECK(m_simDataCollectionKey.initialize());
+  ATH_CHECK(m_mcEventCollectionKey.initialize());
+  ATH_CHECK(detStore()->retrieve(m_idHelper, "FaserSCT_ID"));
 
+  if (!m_noDiagnostics) {
     std::string filePath = m_filePath;
     std::string treeName = m_treeName;
     m_outputFile = TFile::Open(filePath.c_str(), "RECREATE");
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.cxx
index b9e53c66f50eb6f4974ca04fdbd7fa028f2954e3..8c6eb8c0328b0ca194cb06083cc3c019cdbc0fd7 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/ThreeStationTrackSeedTool.cxx
@@ -61,22 +61,26 @@ StatusCode ThreeStationTrackSeedTool::run() {
   }
 
 
-  std::map<int, std::vector<Amg::Vector3D>> station_position_map;
+  std::map<int, std::vector<Tracklet>> station_tracklet_map;
   for (const Trk::Track* track : *trackCollection) {
     auto momentum = track->trackParameters()->front()->momentum();
-    ATH_MSG_DEBUG("track momentum: " << momentum.x() << ", " << momentum.y() << ", " << momentum.z());
+    int station = -1;
+    Amg::Vector3D trackletPosition {0, 0, 0};
+    std::vector<const Tracker::FaserSCT_Cluster*> trackletClusters {};
     for (const Trk::TrackStateOnSurface* trackState : *(track->trackStateOnSurfaces())) {
       auto clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*> (trackState->measurementOnTrack());
       if (clusterOnTrack) {
-        Identifier id = clusterOnTrack->identify();
-        int station = m_idHelper->station(id);
-        auto fitParameters = track->trackParameters()->front();
-        Amg::Vector3D fitPosition = fitParameters->position();
-        ATH_MSG_DEBUG("cluster position: " << fitPosition.x() << ", " << fitPosition.y() << ", " << fitPosition.z());
-        station_position_map[station].push_back(fitPosition);
-        break;
+        const Tracker::FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData();
+        trackletClusters.push_back(cluster);
+        if (station == -1) {
+          Identifier id = clusterOnTrack->identify();
+          station = m_idHelper->station(id);
+          auto fitParameters = track->trackParameters()->front();
+          trackletPosition = fitParameters->position();
+        }
       }
     }
+    station_tracklet_map[station].push_back(Tracklet(trackletPosition, trackletClusters));
   }
 
   Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Zero();
@@ -88,12 +92,13 @@ StatusCode ThreeStationTrackSeedTool::run() {
   cov(Acts::eBoundTime, Acts::eBoundTime) = m_covTime;
 
   std::vector<Acts::CurvilinearTrackParameters> initParams {};
-  for (const Amg::Vector3D& pos1 : station_position_map[1]) {
-    for (const Amg::Vector3D& pos2 : station_position_map[2]) {
-      for (const Amg::Vector3D& pos3 : station_position_map[3]) {
-        initParams.push_back(get_params(pos1, pos2, pos3, cov, m_origin));
-        auto seed = initParams.back();
-        auto seed_momentum = seed.momentum();
+  std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>> seeds;
+  for (const auto& tracklet1 : station_tracklet_map[1]) {
+    for (const auto& tracklet2 : station_tracklet_map[2]) {
+      for (const auto& tracklet3 : station_tracklet_map[3]) {
+        initParams.push_back(get_params(tracklet1.position(), tracklet2.position(), tracklet3.position(), cov, m_origin));
+        std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3> seed {tracklet1.clusters(), tracklet2.clusters(), tracklet3.clusters()};
+        seeds.push_back(seed);
       }
     }
   }
@@ -105,6 +110,7 @@ StatusCode ThreeStationTrackSeedTool::run() {
   m_initialSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
       Acts::Vector3 {0, 0, m_origin}, Acts::Vector3{0, 0, -1});
   m_clusters = std::make_shared<std::vector<const Tracker::FaserSCT_Cluster*>>(clusters);
+  m_seedClusters = std::make_shared<std::vector<std::array<std::vector<const Tracker::FaserSCT_Cluster*>, 3>>>(seeds);
 
   return StatusCode::SUCCESS;
 }
@@ -120,8 +126,8 @@ Acts::CurvilinearTrackParameters ThreeStationTrackSeedTool::get_params(
   Acts::Vector3 dir = position_st2 - position_st1;
   Acts::Vector3 pos = position_st1 - (position_st1.z() - origin)/dir.z() * dir;
   Acts::Vector4 pos4 {pos.x(), pos.y(), pos.z(), 0};
-  auto [abs_momenutm, charge] = momentum({{1, position_st1}, {2, position_st2}, {3, position_st3}});
-  return Acts::CurvilinearTrackParameters(pos4, dir, abs_momenutm, charge, cov);
+  auto [abs_momentum, charge] = momentum({{1, position_st1}, {2, position_st2}, {3, position_st3}});
+  return Acts::CurvilinearTrackParameters(pos4, dir, abs_momentum, charge, cov);
 }
 std::pair<double, double> ThreeStationTrackSeedTool::momentum(const std::map<int, Amg::Vector3D>& pos, double B) {
   Acts::Vector3 vec_l = pos.at(3) - pos.at(1);
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.cxx
index 3feae9515e6007f91ca0696e03c8151ebdb456ea..785bf2be17d9fe0c612b0250c6eae67ae801626e 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackClassification.cxx
@@ -46,20 +46,16 @@ void identifyContributingParticles(
       return true;
     }
     // register all particles that generated this hit
-    Identifier id = state.uncalibrated().hit()->identify();
-    if (simDataCollection.count(id) == 0) {
-      return true;
-    }
-    const auto& deposits = simDataCollection.find(id)->second.getdeposits();
-    int barcode = 0;
-    float highestDep = 0;
-    for (const TrackerSimData::Deposit &deposit : deposits) {
-      if (deposit.second > highestDep) {
-        highestDep = deposit.second;
-        barcode = deposit.first->barcode();
+    std::vector<Identifier> ids = state.uncalibrated().hit()->rdoList();
+    for (const Identifier &id : ids) {
+      if (simDataCollection.count(id) == 0) {
+        return true;
+      }
+      const auto &deposits = simDataCollection.find(id)->second.getdeposits();
+      for (const TrackerSimData::Deposit &deposit : deposits) {
+        increaseHitCount(particleHitCounts, deposit.first->barcode());
       }
     }
-    increaseHitCount(particleHitCounts, barcode);
     return true;
   });
   sortHitCount(particleHitCounts);
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TrackSeedWriterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSeedWriterTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..42c4d1b7969d00e67b1f73ee21ff08a043c15df6
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/TrackSeedWriterTool.cxx
@@ -0,0 +1,116 @@
+#include "FaserActsKalmanFilter/TrackSeedWriterTool.h"
+#include "TFile.h"
+#include "TTree.h"
+
+TrackSeedWriterTool::TrackSeedWriterTool(const std::string& type,
+                                         const std::string& name,
+                                         const IInterface* parent)
+    : AthAlgTool( type, name, parent ) {}
+
+
+StatusCode TrackSeedWriterTool::initialize() {
+  ATH_MSG_INFO("TrackSeedWriterTool::initialize");
+
+  std::string filePath = m_filePath;
+  std::string treeName = m_treeName;
+
+  m_file = TFile::Open(filePath.c_str(), "RECREATE");
+  if (m_file == nullptr) {
+    ATH_MSG_ERROR("Unable to open output file at " << m_filePath);
+    return StatusCode::FAILURE;
+  }
+  m_file->cd();
+  m_tree = new TTree(treeName.c_str(), "tree");
+  if (m_tree == nullptr) {
+    ATH_MSG_ERROR("Unable to create TTree");
+    return StatusCode::FAILURE;
+  }
+
+  TrackSeedWriterTool::initializeTree();
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode TrackSeedWriterTool::finalize() {
+  m_file->cd();
+  m_tree->Write();
+  return StatusCode::SUCCESS;
+}
+
+
+void TrackSeedWriterTool::initializeTree() {
+  m_tree->Branch("run_number", &m_runNumber);
+  m_tree->Branch("event_number", &m_eventNumber);
+  m_tree->Branch("eLOC0", &m_eLOC0);
+  m_tree->Branch("eLOC1", &m_eLOC1);
+  m_tree->Branch("ePHI", &m_ePHI);
+  m_tree->Branch("eTHETA", &m_eTHETA);
+  m_tree->Branch("eQOP", &m_eQOP);
+  m_tree->Branch("err_eLOC0", &m_err_eLOC0);
+  m_tree->Branch("err_eLOC1", &m_err_eLOC1);
+  m_tree->Branch("err_ePHI", &m_err_ePHI);
+  m_tree->Branch("err_eTHETA", &m_err_eTHETA);
+  m_tree->Branch("err_eQOP", &m_err_eQOP);
+  m_tree->Branch("x", &m_x);
+  m_tree->Branch("y", &m_y);
+  m_tree->Branch("z", &m_z);
+  m_tree->Branch("px", &m_px);
+  m_tree->Branch("py", &m_py);
+  m_tree->Branch("pz", &m_pz);
+}
+
+
+void TrackSeedWriterTool::writeout(
+    const Acts::GeometryContext& gctx,
+    const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>>& initialParametersContainer) const {
+  m_runNumber = Gaudi::Hive::currentContext().eventID().run_number();
+  m_eventNumber = Gaudi::Hive::currentContext().eventID().event_number();
+  for (Acts::CurvilinearTrackParameters initialParameters : *initialParametersContainer) {
+    const auto& parameters = initialParameters.parameters();
+    const Acts::Vector3& center = initialParameters.referenceSurface().center(gctx);
+    m_eLOC0.push_back(center[Acts::eBoundLoc0]);
+    m_eLOC1.push_back(center[Acts::eBoundLoc1]);
+    m_ePHI.push_back(parameters[Acts::eBoundPhi]);
+    m_eTHETA.push_back(parameters[Acts::eBoundTheta]);
+    m_eQOP.push_back(parameters[Acts::eBoundQOverP]);
+
+    const auto& covariance = *initialParameters.covariance();
+    m_err_eLOC0.push_back(sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0)));
+    m_err_eLOC1.push_back(sqrt(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1)));
+    m_err_ePHI.push_back(sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi)));
+    m_err_eTHETA.push_back(sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta)));
+    m_err_eQOP.push_back(sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP)));
+
+    const auto& position = initialParameters.position(gctx);
+    const auto& momentum = initialParameters.momentum();
+    m_x.push_back(position.x());
+    m_y.push_back(position.y());
+    m_z.push_back(position.z());
+    m_px.push_back(momentum.x());
+    m_py.push_back(momentum.y());
+    m_pz.push_back(momentum.z());
+  }
+  m_tree->Fill();
+  clearVariables();
+}
+
+
+void TrackSeedWriterTool::clearVariables() const {
+  m_eLOC0.clear();
+  m_eLOC1.clear();
+  m_ePHI.clear();
+  m_eTHETA.clear();
+  m_eQOP.clear();
+  m_err_eLOC0.clear();
+  m_err_eLOC1.clear();
+  m_err_ePHI.clear();
+  m_err_eTHETA.clear();
+  m_err_eQOP.clear();
+  m_x.clear();
+  m_y.clear();
+  m_z.clear();
+  m_px.clear();
+  m_py.clear();
+  m_pz.clear();
+}
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx
index 0a79b99832495297ac3a3ebd419a1134c8f3a9e3..8d56370abefe0f7399095ac3b62d5bc387ad2f35 100755
--- a/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx
@@ -20,6 +20,11 @@
 //#include "FaserActsKalmanFilter/ClusterTrackSeedTool.h"
 #include "FaserActsKalmanFilter/ThreeStationTrackSeedTool.h"
 #include "FaserActsKalmanFilter/PerformanceWriterTool.h"
+#include "FaserActsKalmanFilter/TrackSeedWriterTool.h"
+#include "FaserActsKalmanFilter/ActsTrackSeedTool.h"
+#include "FaserActsKalmanFilter/CKF2.h"
+#include "FaserActsKalmanFilter/KalmanFitterTool.h"
+#include "FaserActsKalmanFilter/MyTrackSeedTool.h"
 
 
 DECLARE_COMPONENT(FaserActsKalmanFilterAlg)
@@ -40,3 +45,8 @@ DECLARE_COMPONENT(RootTrajectorySummaryWriterTool)
 //DECLARE_COMPONENT(ClusterTrackSeedTool)
 DECLARE_COMPONENT(ThreeStationTrackSeedTool)
 DECLARE_COMPONENT(PerformanceWriterTool)
+DECLARE_COMPONENT(TrackSeedWriterTool)
+DECLARE_COMPONENT(ActsTrackSeedTool)
+DECLARE_COMPONENT(CKF2)
+DECLARE_COMPONENT(KalmanFitterTool)
+DECLARE_COMPONENT(MyTrackSeedTool)
diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/CKF2.py b/Tracking/Acts/FaserActsKalmanFilter/test/CKF2.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d41a03a33273d3003677932920b059df871b3d5
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/test/CKF2.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+import sys
+from AthenaCommon.Logging import log, logging
+from AthenaCommon.Constants import DEBUG, VERBOSE, INFO
+from AthenaCommon.Configurable import Configurable
+from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+# from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg
+from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
+from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg
+from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg
+from FaserActsKalmanFilter.CKF2Config import CKF2Cfg
+
+log.setLevel(DEBUG)
+Configurable.configurableRun3Behavior = True
+
+ConfigFlags.Input.Files = ['my.RDO.pool.root']
+ConfigFlags.Output.ESDFileName = "CKF.ESD.pool.root"
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
+ConfigFlags.GeoModel.FaserVersion = "FASER-01"
+ConfigFlags.GeoModel.Align.Dynamic = False
+ConfigFlags.Beam.NumberOfCollisions = 0.
+ConfigFlags.TrackingGeometry.MaterialSource = "Input"
+ConfigFlags.lock()
+
+acc = MainServicesCfg(ConfigFlags)
+acc.merge(PoolReadCfg(ConfigFlags))
+# acc.merge(PoolWriteCfg(ConfigFlags))
+
+acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags))
+acc.merge(TrackerSpacePointFinderCfg(ConfigFlags))
+acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.51, MinClustersPerFit=5, TanThetaCut=0.25))
+acc.merge(CKF2Cfg(ConfigFlags, noDiagnostics=True))
+
+# logging.getLogger('forcomps').setLevel(VERBOSE)
+# acc.foreach_component("*").OutputLevel = VERBOSE
+# acc.foreach_component("*ClassID*").OutputLevel = VERBOSE
+# acc.getService("StoreGateSvc").Dump = True
+# acc.getService("ConditionStore").Dump = True
+# acc.printConfig(withDetails=True)
+# ConfigFlags.dump()
+
+sc = acc.run(maxEvents=-1)
+sys.exit(not sc.isSuccess())
diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py b/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py
index 887c03812bce040d5cdf43f0559a499cbbe02b89..308d6f1c55e0eacfa96c59cd4e82d59fd5cb0211 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py
+++ b/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg.py
@@ -9,6 +9,7 @@ from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
 from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
 # from AthenaPoolCnvSvc.PoolWriteConfig import PoolWriteCfg
 from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
+from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg
 from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg
 from FaserActsKalmanFilter.CombinatorialKalmanFilterConfig import CombinatorialKalmanFilterCfg
 
@@ -29,9 +30,10 @@ acc.merge(PoolReadCfg(ConfigFlags))
 # acc.merge(PoolWriteCfg(ConfigFlags))
 
 acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags))
-acc.merge(SegmentFitAlgCfg(ConfigFlags))
-acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags))
-# acc.getEventAlgo("CombinatorialKalmanFilterAlg").OutputLevel = VERBOSE
+acc.merge(TrackerSpacePointFinderCfg(ConfigFlags))
+acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.51, MinClustersPerFit=5, TanThetaCut=0.25))
+acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags, noDiagnostics=True))
+acc.getEventAlgo("CombinatorialKalmanFilterAlg").OutputLevel = VERBOSE
 
 # logging.getLogger('forcomps').setLevel(INFO)
 # acc.foreach_component("*").OutputLevel = INFO
diff --git a/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg_Data.py b/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg_Data.py
index 81b9f6acd6c2c42d74de52e12d775d4dff2d0307..3ea0fccd734ab65888d3b3a9c7505d2d2dc63738 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg_Data.py
+++ b/Tracking/Acts/FaserActsKalmanFilter/test/CombinatorialKalmanFilterAlg_Data.py
@@ -17,6 +17,7 @@ Configurable.configurableRun3Behavior = True
 
 ConfigFlags.Input.Files = ['/home/tboeckh/Documents/data/raw/TI12/MiddleStationTrack.raw']
 ConfigFlags.Output.ESDFileName = "CKF.ESD.pool.root"
+ConfigFlags.addFlag("Output.xAODFileName", f"CKF.xAOD.root")
 ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-01"
 ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"
 ConfigFlags.Input.ProjectName = "data21"
@@ -33,7 +34,19 @@ acc.merge(PoolWriteCfg(ConfigFlags))
 acc.merge(FaserByteStreamCnvSvcCfg(ConfigFlags))
 acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags, DataObjectName="SCT_LEVELMODE_RDOs", ClusterToolTimingPattern="X1X"))
 acc.merge(SegmentFitAlgCfg(ConfigFlags))
-acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags, noDiagnostics=True))
+acc.merge(CombinatorialKalmanFilterCfg(ConfigFlags, SummaryWriter=False, StatesWriter=False, PerformanceWriter=False))
+acc.getEventAlgo("CombinatorialKalmanFilterAlg").OutputLevel = VERBOSE
+
+from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+itemList = ["xAOD::EventInfo#*",
+            "xAOD::EventAuxInfo#*",
+            "FaserSCT_RDO_Container#*",
+            "Tracker::FaserSCT_ClusterContainer#*",
+            "TrackCollection#*"]
+acc.merge(OutputStreamCfg(ConfigFlags, "xAOD", itemList))
+
+print( "Writing out xAOD objects:" )
+print( acc.getEventAlgo("OutputStreamxAOD").ItemList )
 
 # logging.getLogger('forcomps').setLevel(VERBOSE)
 # acc.foreach_component("*").OutputLevel = VERBOSE
@@ -50,5 +63,5 @@ replicaSvc.UseCOOLSQLite = True
 replicaSvc.UseCOOLFrontier = False
 replicaSvc.UseGeomSQLite = True
 
-sc = acc.run(maxEvents=-1)
+sc = acc.run(maxEvents=20)
 sys.exit(not sc.isSuccess())
diff --git a/Tracking/Acts/README.md b/Tracking/Acts/README.md
index 2a0874fce87ed08d42fa4ac7c77d0226d430e318..5b4c24356a742621045dc568190bcb9c2315acca 100644
--- a/Tracking/Acts/README.md
+++ b/Tracking/Acts/README.md
@@ -6,3 +6,13 @@
 3) To write the tracking geometry, type the command: FaserActsWriteTrackingGeometry.py
 
 4) To run the extrapolator, type the command: FaserActsExtrapolationAlg.py
+
+5) The track finding requires a json file with the correct material in the directory in which you run it. A copy can be found on lxplus: /afs/cern.ch/user/t/tboeckh/public/material/material-maps.json  
+   If you do not want to use the material you have to comment out this line: ConfigFlags.TrackingGeometry.MaterialSource = "Input"
+
+6) To enable additional output set the noDiagnostics flag to False
+
+7) To do the track finding, type the command: CombinatorialKalmanFilterAlg.py
+
+8) To do the track finding and re-fit the best tracks, type the command: CKF2.py  
+   (this is the recommended approach)