diff --git a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx
index 9f62fd57b12fa450f6e2218b841501ca2351cf2a..c3f5313c0e52ddc68009ac2d6d3e41103b103b8a 100644
--- a/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx
+++ b/Calorimeter/CaloDigiAlgs/src/CaloWaveformDigiAlg.cxx
@@ -6,6 +6,7 @@
 
 #include <map>
 #include <utility>
+#include <cmath>
 
 CaloWaveformDigiAlg::CaloWaveformDigiAlg(const std::string& name, 
 					 ISvcLocator* pSvcLocator)
@@ -99,19 +100,31 @@ CaloWaveformDigiAlg::execute(const EventContext& ctx) const {
   // Create structure to store pulse for each channel
   std::map<Identifier, std::vector<uint16_t>> waveforms = m_digiTool->create_waveform_map(m_ecalID);
 
+  // Sum energy for each channel (i.e. identifier)
+  std::map<unsigned int, float> esum;  
+  for (const auto& hit : *caloHitHandle) { 
+    esum[hit.identify()] += hit.energyLoss();
+  }
+
+  // Loop over time samples
   for (const auto& tk : m_timekernel) {
     std::map<unsigned int, float> counts;    
 
     // Convolve hit energy with evaluated kernel and sum for each hit id (i.e. channel)
-    for (const auto& hit : *caloHitHandle) { 
-      counts[hit.identify()] += tk * hit.energyLoss();
+    //for (const auto& hit : *caloHitHandle) { 
+    //  counts[hit.identify()] += tk * hit.energyLoss();
+    //}
+
+    // Convolve summed energy with evaluated kernel for each hit id (i.e. channel)
+    for (const auto& e : esum) {
+      counts[e.first] = tk * e.second;
     }
 
     // Subtract count from basleine and add result to correct waveform vector
     for (const auto& c : counts) {
 
-      unsigned int baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
-      int value = baseline - c.second;
+      float baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
+      int value = std::round(baseline - c.second);
 
       if (value < 0) {
 	ATH_MSG_WARNING("Found pulse " << c.second << " larger than baseline " << c.first);
diff --git a/Calorimeter/CaloRecAlgs/python/CaloRecAlgsConfig.py b/Calorimeter/CaloRecAlgs/python/CaloRecAlgsConfig.py
index 83839b9cba1a4c6a50eef52852ed8ee2127dfaa7..c49770ad2b7e9468eca196af582d2156b9ab977c 100644
--- a/Calorimeter/CaloRecAlgs/python/CaloRecAlgsConfig.py
+++ b/Calorimeter/CaloRecAlgs/python/CaloRecAlgsConfig.py
@@ -19,12 +19,11 @@ def CalorimeterReconstructionCfg(flags, **kwargs):
     kwargs.setdefault("CaloHitContainerKey", "CaloHits")
     kwargs.setdefault("PreshowerHitContainerKey", "PreshowerHits")
 
-    recoAlg = CompFactory.CaloRecAlg("CaloRecAlg", **kwargs)
-    acc.addEventAlgo(recoAlg)
-
-    dbInstance = kwargs.get("dbInstance", "TRIGGER_OFL") # what should this be set to???
+    acc.merge(CaloRecToolCfg(flags, **kwargs))
+    kwargs.pop("MC_calibTag")  # Remove this if it is specified so it does not get pased to CaloRecAlg
 
-    acc.merge(CaloRecToolCfg(flags))
+    recoAlg = CompFactory.CaloRecAlg("CaloRecAlg", isMC = flags.Input.isMC, **kwargs)
+    acc.addEventAlgo(recoAlg)
 
     return acc
 
diff --git a/Calorimeter/CaloRecAlgs/src/CaloRecAlg.cxx b/Calorimeter/CaloRecAlgs/src/CaloRecAlg.cxx
index f4f78d488d6c542637003e38ea0d8959f89b6b1c..b6df5fed6053f7499a6f45a95e4b51d2e6633ddd 100644
--- a/Calorimeter/CaloRecAlgs/src/CaloRecAlg.cxx
+++ b/Calorimeter/CaloRecAlgs/src/CaloRecAlg.cxx
@@ -91,12 +91,11 @@ StatusCode CaloRecAlg::execute(const EventContext& ctx) const {
     ATH_MSG_DEBUG("calo_hit filled has charge of " << charge << " pC");
 
     float gainRatio = 1.0;
-    if (m_isMC) {
-      gainRatio = 1.0; // put dummy value for now, this will end up being ratio of digi scale factors
-    } else {
+    if (!m_isMC) { // MC already has correct MIP charge stored in MIPcharge_ref, so only need to to HV extrapolation with reral data
       gainRatio = extrapolateHVgain(hit->channel());
-      ATH_MSG_DEBUG("HV gain ratio = " << gainRatio );
     }
+    ATH_MSG_DEBUG("HV gain ratio = " << gainRatio );
+
 
     float Nmip = (charge * gainRatio) / MIPcharge_ref;
     ATH_MSG_DEBUG("Nmip = " << Nmip );
diff --git a/Calorimeter/CaloRecTools/python/CaloRecToolConfig.py b/Calorimeter/CaloRecTools/python/CaloRecToolConfig.py
index 65be875da12b6deee3cbf9f35217cee6f40784ff..473a70f7327a39b4029b0af40045c84b1054cc35 100644
--- a/Calorimeter/CaloRecTools/python/CaloRecToolConfig.py
+++ b/Calorimeter/CaloRecTools/python/CaloRecToolConfig.py
@@ -19,8 +19,15 @@ def CaloRecToolCfg(flags, name="CaloRecTool", **kwargs):
     # Probably need to figure this out!
     dbInstance = kwargs.get("dbInstance", "TRIGGER_OFL")
 
+    MC_calibTag = kwargs.get("MC_calibTag", "")
+
+    # MC calibration db folder MIP_ref has version tags
+    if len(MC_calibTag) > 0:
+        acc.merge(addFolders(flags, "/WAVE/Calibration/MIP_ref", dbInstance, className="CondAttrListCollection", tag=MC_calibTag))
+    else:
+        acc.merge(addFolders(flags, "/WAVE/Calibration/MIP_ref", dbInstance, className="CondAttrListCollection"))
+
     acc.merge(addFolders(flags, "/WAVE/Calibration/HV", dbInstance, className="CondAttrListCollection"))
-    acc.merge(addFolders(flags, "/WAVE/Calibration/MIP_ref", dbInstance, className="CondAttrListCollection"))
 
     return acc
 
diff --git a/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py b/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py
index 03368e676c1e73caca7034aedc5fdcff20ed3e63..b945ffbbd19c024d549d0d0f84fdfca768759f68 100755
--- a/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py
+++ b/Control/CalypsoExample/Digitization/scripts/faser_digi_merge.py
@@ -29,6 +29,8 @@ parser.add_argument("-s", "--slice", type=int, default=0,
                     help="Specify file slice to produce")
 parser.add_argument("-f", "--files", type=int, default=5,
                     help="Specify number of input files to run in one batch")
+parser.add_argument("--complete", action="store_true",
+                    help="This is the complete run, remove segment numbers")
 parser.add_argument("-t", "--tag", default="",
                     help="Specify digi tag (to append to output filename)")
 parser.add_argument("--subtractTime", type=float, default=-999.,
@@ -69,24 +71,35 @@ if len(dirlist) == 0:
 print("HITS files available:")
 [print(file) for file in dirlist]
 
+# Get run number for pattern matching
+stem = dirlist[0].stem
+spl = stem.split('-')
+short = spl[1]
+run = spl[2]
+
 for seg in seglist:
-    # Assume these are in numerical order from 0
-    if seg >= len(dirlist):
-        print(f"Requested file segment {seg} but only {len(dirlist)} files found")
-        if args.partial:
-            break
-        else:
-            sys.exit(1)  # Abort this job
+    # No longer assume all HITS files are complete
+    #if seg >= len(dirlist):
+    #    print(f"Requested file segment {seg} but only {len(dirlist)} files found")
+    #    if args.partial:
+    #        break
+    #    else:
+    #        sys.exit(1)  # Abort this job
 
     # Check if segment number exists in hits file (this is not perfect)
-    segstr = f"{seg:05d}"
-    if segstr not in dirlist[seg].name:
-        print(f"Segment {segstr} not in file {dirlist[seg].name}!")
+    segstr = f"FaserMC-{short}-{run}-{seg:05d}*HITS.root"
+    matchlist = list(dirpath.glob(segstr))
+    if len(matchlist) == 0:
+        print(f"Segment {segstr} not found!")
         if not args.partial: sys.exit(1) # abort
+        continue
+    elif len(matchlist) > 1:
+        print(f"Segment {segstr} matched {len(matchlist)} files!")
+        sys.exit(1)  # Should never happen!
     else:
-        print(f"Segment {segstr} found in file {dirlist[seg]}")
+        print(f"Segment {segstr} found!")
 
-    filelist.append(dirlist[seg])  
+    filelist.append(matchlist[0])  
 
 if len(filelist) == 0:
     # Asked for range that doesn't exist
@@ -116,8 +129,11 @@ seghi = int(spl[3])
 if len(args.short) > 0:
     short += args.short
 
+# Shouldn't normally remove segments with MC as we may always add
+# more files later.  --complete overrides this if wanted
+
 # Build output filename
-if seglo == 0 and (seghi+1) == len(dirlist):  # Full run
+if args.complete and (seglo == 0) and ((seghi+1) == len(dirlist)):  # Full run
     outfile = f"FaserMC-{short}-{run}"
 elif seglo == seghi:  # Single segment
     outfile = f"FaserMC-{short}-{run}-{seglo:05}"
diff --git a/Control/CalypsoExample/Digitization/scripts/submit_faser_digi.sh b/Control/CalypsoExample/Digitization/scripts/submit_faser_digi.sh
index 34e0275042d59ec162c44e8198925e9f6d098853..fcf5e2045b192ef913a9fc1ea0b75c8fae4074bd 100644
--- a/Control/CalypsoExample/Digitization/scripts/submit_faser_digi.sh
+++ b/Control/CalypsoExample/Digitization/scripts/submit_faser_digi.sh
@@ -2,10 +2,10 @@
 # Used with a condor file to submit to vanilla universe
 #
 # Usage:
-# submit_faser_digi.sh [--highGain] filepath [release_directory] [working_directory]
+# submit_faser_digi.sh filepath [release_directory] [working_directory]
 #
 # Options:
-#   --highGain - apply high gain settings to the Calorimeter PMTs (for muons)
+#   --digiTag <tag> - override digitization tag for calo gain
 #   --geom - geometry setting
 #   --out - specify output location (in EOS) to copy output HITS file
 #   --log - specify output location (in EOS) for log file
@@ -186,6 +186,9 @@ cd "$file_stem"
 # Run job
 #
 faser_digi.py $geomstr $gainstr $timestr $tagstr "$file_path"
+digi_code=$?
+echo "Return code: $digi_code"
+
 #
 # Print out ending time
 date
@@ -196,25 +199,52 @@ export EOS_MGM_URL=root://eospublic.cern.ch
 #
 if ! [ -z "$outdest" ]
 then
+    echo "Output directory:"
     ls -l
-    echo "copy *-RDO.root to $outdest"
-    mkdir -p $outdest
-    eos cp *-RDO.root ${outdest}/ || true
+    thefile=`ls *-RDO.root`
+    if [ $? -eq 0 ]; then
+        echo "copy $thefile to $outdest"
+	eos mkdir -p $outdest
+	eos cp $thefile ${outdest}/${thefile} || true
+
+	# Check that this worked
+	eos ls ${outdest}/${thefile} > /dev/null
+        if [ $? -eq 0 ]; then
+            echo "file $thefile copied to $outdest"
+	    copy_code=0
+	else
+	    echo "didnt find $thefile in $outdest !"
+	    copy_code=1
+	fi
+    else
+        echo "ls *-RDO.root returned nothing!"
+        copy_code=1
+    fi
 fi
 #
 # Also copy log file
 if ! [ -z "$logdest" ]
 then
     cd ..
+    echo "Working directory:"
     ls -l
     echo "copy $logfile to $logdest"
-    mkdir -p $logdest
+    eos mkdir -p $logdest
     eos cp $logfile $logdest/$logfile
 elif ! [ -z "$outdest" ]
 then 
     cd ..
+    echo "Working directory:"
     ls -l
     echo "copy $logfile to $outdest"
-    mkdir -p $outdest
+    eos mkdir -p $outdest
     eos cp $logfile $outdest/$logfile
 fi
+
+# Make sure to return an error is calypso failed                                
+if [ $digi_code -ne 0 ] || [ $copy_code -ne 0 ]; then
+  exit 1
+else
+  exit 0
+fi
+
diff --git a/Control/CalypsoExample/Digitization/scripts/submit_faser_digi_merge.sh b/Control/CalypsoExample/Digitization/scripts/submit_faser_digi_merge.sh
index cb67ef8838ee26a01e15436bd44668e672b20379..50278c33e2435236fff3bc2b6a94c13aa5794817 100755
--- a/Control/CalypsoExample/Digitization/scripts/submit_faser_digi_merge.sh
+++ b/Control/CalypsoExample/Digitization/scripts/submit_faser_digi_merge.sh
@@ -2,10 +2,11 @@
 # Used with a condor file to submit to vanilla universe
 #
 # Usage:
-# submit_faser_digi_merge.sh [--highGain] dirpath slice nfiles [release_directory] [working_directory] 
+# submit_faser_digi_merge.sh dirpath slice nfiles [release_directory] [working_directory] 
 #
 # Options:
-#   --highGain - apply high gain settings to the Calorimeter PMTs (for muons)
+#   --digiTag <tag> - override digitization tag for calo gain
+#   --partial - allow missing files in merge
 #   --geom - geometry setting
 #   --out - specify output location (in EOS) to copy output HITS file
 #   --log - specify output location (in EOS) for log file
@@ -221,6 +222,8 @@ cd "$file_stem"
 # Run job
 #
 faser_digi_merge.py $partialstr $geomstr $gainstr $timestr $tagstr --slice $slice --files $nfiles $dir_path
+digi_code=$?
+echo "Return code: $digi_code"
 #
 # Print out ending time
 date
@@ -231,25 +234,52 @@ export EOS_MGM_URL=root://eospublic.cern.ch
 #
 if ! [ -z "$outdest" ]
 then
+    echo "Output directory:"
     ls -l
-    echo "copy *-RDO.root to $outdest"
-    mkdir -p $outdest
-    eos cp *-RDO.root ${outdest}/ || true
+    thefile=`ls *-RDO.root`
+    if [ $? -eq 0 ]; then
+        echo "copy $thefile to $outdest"
+	eos mkdir -p $outdest
+	eos cp $thefile ${outdest}/${thefile} || true
+
+	# Check that this worked
+	eos ls ${outdest}/${thefile} > /dev/null
+        if [ $? -eq 0 ]; then
+            echo "file $thefile copied to $outdest"
+	    copy_code=0
+	else
+	    echo "didnt find $thefile in $outdest !"
+	    copy_code=1
+	fi
+    else
+        echo "ls *-RDO.root returned nothing!"
+        copy_code=1
+    fi
 fi
 #
 # Also copy log file
 if ! [ -z "$logdest" ]
 then
     cd ..
+    echo "Working directory:"
     ls -l
     echo "copy $logfile to $logdest"
-    mkdir -p $logdest
+    eos mkdir -p $logdest
     eos cp $logfile $logdest/$logfile
 elif ! [ -z "$outdest" ]
 then 
     cd ..
+    echo "Working directory:"
     ls -l
     echo "copy $logfile to $outdest"
-    mkdir -p $outdest
+    eos mkdir -p $outdest
     eos cp $logfile $outdest/$logfile
 fi
+
+# Make sure to return an error is calypso failed                                
+if [ $digi_code -ne 0 ] || [ $copy_code -ne 0 ]; then
+  exit 1
+else
+  exit 0
+fi
+
diff --git a/Control/CalypsoExample/Generation/python/faser_parser.py b/Control/CalypsoExample/Generation/python/faser_parser.py
index 43f98387e7089cfdf258531ec57aeea072b70f53..055dd7200201ce69823d798609cb991d85f4e794 100644
--- a/Control/CalypsoExample/Generation/python/faser_parser.py
+++ b/Control/CalypsoExample/Generation/python/faser_parser.py
@@ -4,6 +4,13 @@
 #
 # Parser function for particle gun samples
 #
+
+def float_or_none(arg):
+    if arg is None or arg == "None":
+        return None
+
+    return float(arg)
+
 def faser_pgparser():
 
     import sys
@@ -33,15 +40,24 @@ def faser_pgparser():
                         help="Specify PDG ID of particle (note plus/minus different) or list (e.g.: --pid -13 13)")
     parser.add_argument("--mass", default=105.66, type=float,
                         help="Specify particle mass (in MeV)")
-    parser.add_argument("--radius", default=100., type=float,
+    parser.add_argument("--radius", default=100., type=float, nargs="*",
                         help="Specify radius (in mm)")
-    parser.add_argument("--angle", default=0.005, type=float,
+    parser.add_argument("--angle", default=0.005, type=float_or_none,
                         help="Specify angular width (in Rad)")
     parser.add_argument("--zpos", default=None, type=float,
                         help="Specify z position of particles (in mm) (helpful to avoid FASERnu)")
 
+    parser.add_argument("--pidd1", default=None, type=int, 
+                        help="Specify PDG ID of daugther 1 for DIF generator")
+    parser.add_argument("--pidd2", default=None, type=int, 
+                        help="Specify PDG ID of daugther 2 for DIF generator")
+
+
     parser.add_argument("--sampler", default="log",
-                        help="Specify energy sampling (log, lin, const)")
+                        help="Specify energy sampling (log, lin, const, hist, hist2D)")
+    parser.add_argument("--hist_name", default="",
+                        help="Specify energy sampling name for hist sampler file.root:hist")
+    
     parser.add_argument("--minE", default=10., type=float,
                         help="Minimum energy in GeV (for log or lin sampler)")
     parser.add_argument("--maxE", default=1000., type=float,
diff --git a/Control/CalypsoExample/Generation/scripts/faser_particlegun.py b/Control/CalypsoExample/Generation/scripts/faser_particlegun.py
index cc1628efdb9245e32b7abbbc9ca60a60b2151fad..169badecf7cf2a392a95b098a858634c5a2523c6 100755
--- a/Control/CalypsoExample/Generation/scripts/faser_particlegun.py
+++ b/Control/CalypsoExample/Generation/scripts/faser_particlegun.py
@@ -101,24 +101,50 @@ if __name__ == '__main__':
     from AthenaCommon.PhysicalConstants import pi
 
     if isinstance(args.pid, list):
-        # Note args.pid is a list, must make this a set for ParticleGun
-        pidarg = set(args.pid)
+        # Note args.pid is a list, must make this a set for ParticleGun if have > 1 
+        if len(args.pid) > 1:
+            pidarg = set(args.pid)
+        else:
+            pidarg = args.pid[0]
     else:
         # Just pass a single value
         pidarg = args.pid
 
     print(f"Using pid: {args.pid} => {pidarg}")
 
+    if isinstance(args.radius, list) and len(args.radius) == 1:
+        args.radius = args.radius[0]
+        
+
     # Create the simgun dictionary
     # Negative radius gives uniform sampling
     # Positive radius gives Gaussian sampling
-    sg_dict = {
-        "Generator" : "SingleParticle", 
-        "pid" : pidarg, "mass" : args.mass, 
-        "theta" :  PG.GaussianSampler(0, args.angle, oneside = True), 
-        "phi" : [0, 2*pi], "radius" : args.radius, 
-        "randomSeed" : args.outfile 
-    }
+
+    if args.pidd1:
+        if args.pidd2 is None:
+            args.pidd2 = -args.pidd1
+            
+        sg_dict = {
+            "Generator" : "DecayInFlight", 
+            "mother_pid" : pidarg,
+            "daughter1_pid" : args.pidd1,
+            "daughter2_pid" : args.pidd2,        
+            "mass" : args.mass, 
+            "theta" :  PG.GaussianSampler(0, args.angle, oneside = True) if args.angle is not None and args.angle != "None" else None,
+            "phi" : [0, 2*pi], "radius" : args.radius, 
+            "randomSeed" : args.outfile 
+            }
+
+    else:
+
+        sg_dict = {
+            "Generator" : "SingleParticle", 
+            "pid" : pidarg, "mass" : args.mass, 
+            "theta" :  PG.GaussianSampler(0, args.angle, oneside = True) if args.angle is not None and args.angle != "None" else None,
+            "phi" : [0, 2*pi], "radius" : args.radius, 
+            "randomSeed" : args.outfile 
+            }
+
 
     # -1000 is safely upstream of detector (to be checked)
     # Note zpos is in mm!
@@ -132,6 +158,12 @@ if __name__ == '__main__':
         sg_dict["energy"] = PG.LogSampler(args.minE*GeV, args.maxE*GeV)
     elif args.sampler == "const":
         sg_dict["energy"] = PG.ConstSampler(args.maxE*GeV)
+    elif args.sampler == "hist":
+        fname, hname = args.hist_name.split(":")
+        sg_dict["energy"] = PG.TH1Sampler(fname, hname)
+    elif args.sampler == "hist2D":
+        fname, hname = args.hist_name.split(":")
+        sg_dict["energy"] = PG.TH2Sampler(fname, hname)        
     else:
         print(f"Sampler {args.sampler} not known!")
         sys.exit(1)
diff --git a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
index b470cb3fd20ae482d4cd1aececd535191a35c00e..21e1d51a6af7d92ebac09d051e80c919d1c39687 100755
--- a/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
+++ b/Control/CalypsoExample/Reconstruction/scripts/faser_reco.py
@@ -33,6 +33,8 @@ parser.add_argument("-v", "--verbose", action='store_true',
                     help="Turn on DEBUG output")
 parser.add_argument("--isMC", action='store_true',
                     help="Running on digitised MC rather than data")
+parser.add_argument("--MC_calibTag", default="",
+                    help="Specify tag used to reconstruct MC calo energy: (WAVE-Calibration-01-LG-nofilt, WAVE-Calibration-01-LG, WAVE-Calibration-01-HG-nofilt, or WAVE-Calibration-01-HG) ")
 parser.add_argument("--testBeam", action='store_true',
                     help="Set geometry for 2021 test beam")
 
@@ -129,8 +131,6 @@ elif runtype == "TI12Data02":
 # Final 2022 TI12 geometry
 elif runtype == "TI12Data03":
     ConfigFlags.GeoModel.FaserVersion = "FASERNU-03" 
-    # ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02"
-    # Use the updated field map
     ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-03"
     useCal = True
     if not args.isMC:
@@ -141,7 +141,6 @@ else:
     print("Specify correct type or update list")
     sys.exit(1)
 
-
 # Must use original input string here, as pathlib mangles double // in path names
 ConfigFlags.Input.Files = [ args.file_path ]
 
@@ -194,14 +193,10 @@ if useLHC:
 from WaveRecAlgs.WaveRecAlgsConfig import WaveformReconstructionCfg    
 acc.merge(WaveformReconstructionCfg(ConfigFlags))
 
-# Calorimeter reconstruction
-if args.isMC:
-    # Not ready for MC quite yet
-    pass
-
-elif useCal:
+# Calorimeter Energy reconstruction
+if useCal:
     from CaloRecAlgs.CaloRecAlgsConfig import CalorimeterReconstructionCfg
-    acc.merge(CalorimeterReconstructionCfg(ConfigFlags))
+    acc.merge(CalorimeterReconstructionCfg(ConfigFlags, MC_calibTag=args.MC_calibTag))
 
 # Tracker clusters
 from TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
@@ -295,6 +290,12 @@ if not args.isMC:
 if args.verbose:
     acc.foreach_component("*").OutputLevel = VERBOSE
     ConfigFlags.dump()
+    # Print out POOL conditions
+    import os
+    print(f"ATLAS_POOLCOND_PATH: {os.environ['ATLAS_POOLCOND_PATH']}")
+    print(f"PoolSvc.ReadCatalog: {acc.getService('PoolSvc').ReadCatalog}")
+    print(f"PoolSvc.WriteCatalog: {acc.getService('PoolSvc').WriteCatalog}")
+
 else:
     acc.foreach_component("*").OutputLevel = INFO
 
@@ -314,5 +315,11 @@ b = time.time()
 from AthenaCommon.Logging import log
 log.info(f"Finish execution in {b-a} seconds")
 
-sys.exit(int(sc.isFailure()))
+# Signal errors
+if sc.isSuccess():
+    log.info("Execution succeeded")
+    sys.exit(0)
+else:
+    log.info("Execution failed, return 1")
+    sys.exit(1)
 
diff --git a/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh b/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh
index 4fe3e2d626796ab0ba52fddee0aee5e311cf59ed..f75b144a1bf2d0a725692dbaa82be34ad788cd5c 100755
--- a/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh
+++ b/Control/CalypsoExample/Reconstruction/scripts/submit_faser_reco.sh
@@ -8,7 +8,10 @@
 #   --out - specify output location (in EOS) to copy output HITS file
 #   --log - specify output location (in EOS) for log file
 #   --geom - specify geometry
+#
+# Monte Carlo options:
 #   --isMC - needed for MC reco
+#   --caloTag <tag> - override MC reco tag for calo gain (to match digi tag)
 # 
 # file_path - full file name (with path)
 # release_directory - optional path to release install directory (default pwd)
@@ -25,6 +28,9 @@
 # Keep track of time
 SECONDS=0
 #
+# Job option strings
+gainstr=""
+#
 # Parse command-line options
 while [ -n "$1" ]
 do 
@@ -45,9 +51,16 @@ do
 	  shift;;
 
       --isMC)
+	  echo "Set isMC true"
 	  ismc=1
 	  shift;;
 
+      --caloTag)
+	  echo "Override calo digi tag with $2"
+	  gainstr="--MC_calibTag $2"
+	  shift;
+	  shift;;
+
       --) # End of options
 	  shift; # Eat this
 	  break;; # And stop parsing
@@ -119,6 +132,7 @@ echo `date` - $HOSTNAME
 echo "File: $file_name"
 echo "Filepath: $file_path"
 echo "Geom: $geom"
+echo "Gain: $gainstr"
 echo "Release: $release_directory"
 echo "Output: $output_directory"
 echo "Starting: $starting_directory"
@@ -127,7 +141,6 @@ echo "Starting: $starting_directory"
 export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase
 source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh 
 #
-# Try automatic
 # Always go back to the starting directory in case paths are relative
 cd "$starting_directory"
 cd "$release_directory"
@@ -140,6 +153,11 @@ source run/setup.sh
 #
 echo "ATLAS_POOLCOND_PATH = $ATLAS_POOLCOND_PATH"
 #
+# Check if there are data overrides
+if [ -d "run/data/sqlite200" ]; then
+   cond_directory=`pwd -P`/run/data  # Get absolute path
+fi
+#
 # Try to find a release tag
 cd calypso
 recotag=`git describe --tags`
@@ -170,6 +188,29 @@ else
 fi
 cd "$file_stem"
 #
+# Check if there were data overrides in the release directory
+if [[ -z "$cond_directory" ]]; then
+    echo "No local conditions directory found!"
+else
+    echo "Local conditions directory found!  Copying to run directory..."
+    echo Copying $cond_directory
+    cp -r $cond_directory .
+    ls -R data
+fi
+# 
+# Further check if there is a pool conditions override
+#if [[ -d "data/poolcond" ]]; then
+#    echo "Local POOL directory found!"
+#    echo "Change ATLAS_POOLCOND_PATH"
+#    echo " from $ATLAS_POOLCOND_PATH"
+#    export ATLAS_POOLCOND_PATH=`pwd -P`/data
+#    echo " to $ATLAS_POOLCOND_PATH"
+#else
+#    echo "No local pool files found, use default:"
+#    echo " $ATLAS_POOLCOND_PATH"
+#fi
+echo "ATLAS_POOLCOND_PATH: $ATLAS_POOLCOND_PATH"
+#
 # Run job
 if [[ -z "$tag" ]]; then
     tagstr=""
@@ -189,7 +230,9 @@ else
     mcstr="--isMC"
 fi
 #
-faser_reco.py "--nevents=$nevents" $geomstr $tagstr $mcstr "$file_path" 
+faser_reco.py "--nevents=$nevents" $geomstr $tagstr $mcstr $gainstr "$file_path" 
+reco_code=$?
+echo "Return code: $reco_code"
 #
 # Print out ending time
 date
@@ -203,11 +246,27 @@ if ! [ -z "$outdest" ]
 then
     echo "Output directory:"
     ls -l
-    echo "copy *-xAOD.root to $outdest"
-    eos mkdir -p $outdest
-    # Keep this line from stopping script, so we might get a log file
-    # || true ensures script continues even if copy fails
-    eos cp *-xAOD.root ${outdest}/ || true   
+    thefile=`ls *-xAOD.root`
+    if [ $? -eq 0 ]; then
+	echo "copy $thefile to $outdest"
+	eos mkdir -p $outdest
+	# Keep this line from stopping script, so we might get a log file
+	# || true ensures script continues even if copy fails
+	eos cp $thefile ${outdest}/${thefile} || true   
+
+	# Check that it worked
+	eos ls ${outdest}/${thefile} > /dev/null
+	if [ $? -eq 0 ]; then
+	    echo "file $thefile copied to $outdest"
+	    copy_code=0
+	else
+	    echo "didnt find $thefile in $outdest !"
+	    copy_code=1
+	fi
+    else
+	echo "ls *-xAOD.root returned nothing!"
+	copy_code=1
+    fi
 fi
 #
 # Copy log file second
@@ -228,3 +287,11 @@ then
     eos mkdir -p $outdest
     eos cp $logfile $outdest/$logfile
 fi
+
+# Make sure to return an error is calypso failed
+if [ $reco_code -ne 0 ] || [ $copy_code -ne 0 ]; then
+  exit 1
+else
+  exit 0
+fi
+
diff --git a/Control/CalypsoExample/Simulation/scripts/submit_faser_simulate.sh b/Control/CalypsoExample/Simulation/scripts/submit_faser_simulate.sh
index 83a2470f1e93bd9703e0e44c5abca3a9aeebe7c1..6e4d4df2eac92d4836c2b77104093ab2dd81c01c 100755
--- a/Control/CalypsoExample/Simulation/scripts/submit_faser_simulate.sh
+++ b/Control/CalypsoExample/Simulation/scripts/submit_faser_simulate.sh
@@ -35,6 +35,11 @@ do
 	  xangle=1 
 	  shift;;  # This 'eats' the argument
 
+      --fshift)
+	  echo "Applying FLUKA crossing-angle shift"
+	  xangle=2
+	  shift;;
+
       -l | --log)
 	  logdest="$2";
 	  shift;
@@ -183,9 +188,16 @@ cd "${file_stem}"
 #fi
 if [[ -z "$xangle" ]]; then
     faser_simulate.py  --skip "$skip_events" -n "$nevts" "$infile" "$outfile"
+    sim_code=$?
+elif [[ $xangle == 1 ]]; then
+    faser_simulate.py  --yangle -0.000160 --yshift 12.0 --skip "$skip_events" -n "$nevts" "$infile" "$outfile"
+    sim_code=$?
 else
-    faser_simulate.py  --yangle -0.000150 --yshift 12.0 --skip "$skip_events" -n "$nevts" "$infile" "$outfile"
+    echo "Applying double crossing-angle shift for FLUKA!"
+    faser_simulate.py  --yangle -0.000310 --yshift 12.0 --skip "$skip_events" -n "$nevts" "$infile" "$outfile"
+    sim_code=$?
 fi
+echo "Return code: $sim_code"
 #
 # Print out ending time
 date
@@ -196,16 +208,34 @@ export EOS_MGM_URL=root://eospublic.cern.ch
 #
 if ! [ -z "$outdest" ]
 then
+    echo "Output directory:"
     ls -l
-    echo "copy *-HITS.root to $outdest"
-    eos mkdir -p $outdest
-    eos cp *-HITS.root ${outdest}/ || true
+    thefile=`ls *-HITS.root`
+    if [ $? -eq 0 ]; then
+	echo "copy $thefile to $outdest"
+	eos mkdir -p $outdest
+	eos cp $thefile ${outdest}/${thefile} || true
+
+	# Check that this worked
+	eos ls ${outdest}/${thefile} > /dev/null
+        if [ $? -eq 0 ]; then
+            echo "file $thefile copied to $outdest"
+	    copy_code=0
+	else
+	    echo "didnt find $thefile in $outdest !"
+	    copy_code=1
+	fi
+    else
+        echo "ls *-HITS.root returned nothing!"
+        copy_code=1
+    fi
 fi
 #
 # Also copy log file
 if ! [ -z "$logdest" ]
 then
     cd ..
+    echo "Working directory:"
     ls -l
     echo "copy $logfile to $logdest"
     eos mkdir -p $logdest
@@ -213,9 +243,17 @@ then
 elif ! [ -z "$outdest" ]
 then 
     cd ..
+    echo "Working directory:"
     ls -l
     echo "copy $logfile to $outdest"
     eos mkdir -p $outdest
     eos cp $logfile $outdest/$logfile
 fi
 
+# Make sure to return an error is calypso failed                                
+if [ $sim_code -ne 0 ] || [ $copy_code -ne 0 ]; then
+  exit 1
+else
+  exit 0
+fi
+
diff --git a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser02.py b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser02.py
index 2e944e3fc88b76d6794a7df7b9ce4469fc763d51..56b856fa824564a1368675eb45bb1d6166a7949d 100644
--- a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser02.py
+++ b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser02.py
@@ -53,11 +53,11 @@ if __name__ == "__main__":
     
 # Flags for this job
     ConfigFlags.Input.isMC = True                                # Needed to bypass autoconfig
-    ConfigFlags.GeoModel.FaserVersion     = "FASER-02"           # Default FASER geometry
-    ConfigFlags.IOVDb.GlobalTag           = "OFLCOND-"+ ConfigFlags.GeoModel.FaserVersion  # Always needed; must match FaserVersion
-    ConfigFlags.IOVDb.DBConnection        = "sqlite://;schema=" + ConfigFlags.GeoModel.FaserVersion + "_ALLP200.db;dbname=OFLP200"
+    ConfigFlags.GeoModel.FaserVersion     = "FASERNU-03"         # Default FASER geometry
+    ConfigFlags.IOVDb.GlobalTag           = "OFLCOND-FASER-02"   # Old field map 
+    ConfigFlags.IOVDb.DBConnection        = "sqlite://;schema=FASER-02_ALLP200.db;dbname=OFLP200"
     ConfigFlags.GeoModel.Align.Disable = True          # Hack to avoid loading alignment when we want to create it from scratch
-    ConfigFlags.addFlag("WriteAlignment.PoolFileName", ConfigFlags.GeoModel.FaserVersion + "_Align.pool.root") 
+    ConfigFlags.addFlag("WriteAlignment.PoolFileName", "FASER-02_Align.pool.root") 
 
 # Parse flags from command line and lock
     ConfigFlags.addFlag("AlignDbTool.AlignmentConstants", {}) 
diff --git a/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser03.py b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser03.py
new file mode 100755
index 0000000000000000000000000000000000000000..2bbddc7cde737cfd5506c0c4bc6610ca820fb55b
--- /dev/null
+++ b/Control/CalypsoExample/WriteAlignment/python/WriteAlignmentConfig_Faser03.py
@@ -0,0 +1,82 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+#!/usr/bin/env python
+import sys
+from AthenaCommon.Constants import VERBOSE, INFO
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+def WriteAlignmentCfg(flags, name="WriteAlignmentAlg", alignmentConstants={}, **kwargs):
+
+    # Initialize GeoModel
+    from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
+    a = FaserGeometryCfg(flags)
+
+    # This section is to allow alignment to be written to a conditions DB file
+    from IOVDbSvc.IOVDbSvcConfig import IOVDbSvcCfg
+    result = IOVDbSvcCfg(flags)
+    iovDbSvc = result.getPrimary()
+    iovDbSvc.dbConnection=flags.IOVDb.DBConnection
+    a.merge(result)
+
+    AthenaPoolCnvSvc=CompFactory.AthenaPoolCnvSvc
+    apcs=AthenaPoolCnvSvc()
+    a.addService(apcs)
+    EvtPersistencySvc=CompFactory.EvtPersistencySvc
+    a.addService(EvtPersistencySvc("EventPersistencySvc",CnvServices=[apcs.getFullJobOptName(),]))
+
+    a.addService(CompFactory.IOVRegistrationSvc(PayloadTable=False,OutputLevel=VERBOSE))
+
+    # Configure the algorithm itself
+    WriteAlignmentAlg = CompFactory.WriteAlignmentAlg
+    outputTool = CompFactory.AthenaOutputStreamTool("DbStreamTool", OutputFile = flags.WriteAlignment.PoolFileName, 
+                                                                    PoolContainerPrefix="ConditionsContainer", 
+                                                                    TopLevelContainerName = "<type>",
+                                                                    SubLevelBranchName= "<key>" )
+
+    trackerAlignDBTool = CompFactory.TrackerAlignDBTool("AlignDbTool", OutputTool = outputTool, 
+                                                                       OutputLevel=VERBOSE,
+                                                                       AlignmentConstants = {}) 
+    kwargs.setdefault("AlignDbTool", trackerAlignDBTool)
+    trackerAlignDBTool.AlignmentConstants = alignmentConstants 
+    a.addEventAlgo(WriteAlignmentAlg(name, **kwargs))
+
+    return a
+
+
+if __name__ == "__main__":
+    # from AthenaCommon.Logging import log, logging
+    from AthenaCommon.Configurable import Configurable
+    # from AthenaConfiguration.ComponentFactory import CompFactory
+    from CalypsoConfiguration.AllConfigFlags import ConfigFlags
+
+    Configurable.configurableRun3Behavior = True
+    
+# Flags for this job
+    ConfigFlags.Input.isMC = True                                # Needed to bypass autoconfig
+    ConfigFlags.GeoModel.FaserVersion     = "FASERNU-03"           # Default FASER geometry
+    ConfigFlags.IOVDb.GlobalTag           = "OFLCOND-FASER-03"
+    ConfigFlags.IOVDb.DBConnection        = "sqlite://;schema=FASER-03_ALLP200.db;dbname=OFLP200"
+    ConfigFlags.GeoModel.Align.Disable = True          # Hack to avoid loading alignment when we want to create it from scratch
+    ConfigFlags.addFlag("WriteAlignment.PoolFileName", "FASER-03_Align.pool.root") 
+
+# Parse flags from command line and lock
+    ConfigFlags.addFlag("AlignDbTool.AlignmentConstants", {}) 
+    ConfigFlags.fillFromArgs(sys.argv[1:])
+    ConfigFlags.lock()
+
+# Configure components
+    from CalypsoConfiguration.MainServicesConfig import MainServicesCfg
+    acc = MainServicesCfg(ConfigFlags)
+
+# Set things up to create a conditions DB with neutral Tracker alignment transforms
+    acc.merge(WriteAlignmentCfg(ConfigFlags, alignmentConstants=ConfigFlags.AlignDbTool.AlignmentConstants, ValidRunStart=1, ValidEvtStart=0, ValidRunEnd=9999999, ValidEvtEnd=9999999, CondTag=ConfigFlags.GeoModel.FaserVersion.replace("FASER", "TRACKER-ALIGN"), ))
+
+# Configure verbosity    
+    # ConfigFlags.dump()
+    # logging.getLogger('forcomps').setLevel(VERBOSE)
+    acc.foreach_component("*").OutputLevel = VERBOSE
+    acc.foreach_component("*ClassID*").OutputLevel = INFO
+    # log.setLevel(VERBOSE)
+    
+# Execute and finish
+    sys.exit(int(acc.run(maxEvents=1).isFailure()))
diff --git a/Generators/DIFGenerator/python/DIFSampler.py b/Generators/DIFGenerator/python/DIFSampler.py
index 8ec22459aba93a430093c4bd7b2a3f13e2d0f206..007830b63c82ec06f19af6fbd3169cfc10ce8e2e 100644
--- a/Generators/DIFGenerator/python/DIFSampler.py
+++ b/Generators/DIFGenerator/python/DIFSampler.py
@@ -93,9 +93,8 @@ class DIFSampler(PG.ParticleSampler):
     # 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))
+                 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)
 
         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 ac30494a4815f5bb06a5d67408b4c0551297a63b..d2e82a88d3fd6229b2e3ad33932ead7d5d650720 100644
--- a/Generators/FaserParticleGun/python/FaserParticleGunConfig.py
+++ b/Generators/FaserParticleGun/python/FaserParticleGunConfig.py
@@ -9,7 +9,7 @@ import ParticleGun as PG
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
 # from AthenaCommon.Constants import VERBOSE, INFO
-from AthenaCommon.SystemOfUnits import TeV
+from AthenaCommon.SystemOfUnits import TeV, GeV, MeV
 from AthenaCommon.PhysicalConstants import pi
 
 ### add radial pos sampler ### with gaussian beam implemented
@@ -144,7 +144,31 @@ def FaserParticleGunDecayInFlightCfg(ConfigFlags, **kwargs) :
     pg = cfg.getPrimary()
 
     from DIFGenerator import DIFSampler
-    pg.sampler = DIFSampler(**kwargs)
+
+    if "radius" in kwargs:
+        kwargs["mother_pos"]  =  RadialPosSampler(x = kwargs.setdefault("x", 0.0), 
+                                                  y = kwargs.setdefault("y", 0.0), 
+                                                  z = kwargs.setdefault("z", -3750.0),
+                                                  r = kwargs.setdefault("radius", 1.0),
+                                                  t = kwargs.setdefault("t", 0.0) )
+    else:
+        from DIFGenerator.DIFSampler import CylinderSampler
+        kwargs["mother_pos"]  = CylinderSampler([0, 100**2], [0, 2*pi], [-1500, 0], 0)
+    
+    if not "mother_mom" in kwargs:
+        kwargs["mother_mom"] = PG.EThetaMPhiSampler(kwargs.setdefault("energy", ((1*TeV)**2 + (500*MeV)**2)**0.5),
+                                                    kwargs.setdefault("theta", [0, 0.0002]),
+                                                    kwargs.setdefault("mass", 500*MeV),
+                                                    kwargs.setdefault("phi", [0, 2*pi]) )                                  
+        
+
+        
+    pg.sampler = DIFSampler(kwargs.setdefault("daughter1_pid", 13),
+                            kwargs.setdefault("daughter2_pid", -13),
+                            kwargs.setdefault("mother_pid", None),
+                            kwargs["mother_mom"],
+                            kwargs["mother_pos"] )
+
 
     return cfg
 
@@ -190,9 +214,12 @@ def FaserParticleGunForeseeCfg(ConfigFlags, **kwargs) :
     return cfg
 
 def FaserParticleGunCfg(ConfigFlags) :
-    # generator = ConfigFlags.Sim.Gun.setdefault("Generator", "SingleParticle")
-    generator = ConfigFlags.Sim.Gun.setdefault("Generator", "DecayInFlight")
+    generator = ConfigFlags.Sim.Gun.setdefault("Generator", "SingleParticle")
+    # generator = ConfigFlags.Sim.Gun.setdefault("Generator", "DecayInFlight")
+
     kwargs = ConfigFlags.Sim.Gun
+    del kwargs["Generator"]
+    
     if generator == "SingleEcalParticle" :
         return FaserParticleGunSingleEcalParticleCfg(ConfigFlags, **kwargs)
     elif generator == "Cosmics" :
diff --git a/Generators/FaserParticleGun/python/RadialPosSampler.py b/Generators/FaserParticleGun/python/RadialPosSampler.py
index 6fcd6829b29ea474d5c7380526d3c46bab9c6871..19b1db116991c082d0771699813df2fe94c0a1d9 100644
--- a/Generators/FaserParticleGun/python/RadialPosSampler.py
+++ b/Generators/FaserParticleGun/python/RadialPosSampler.py
@@ -35,12 +35,17 @@ class RadialPosSampler(Sampler):
     def r(self):
         "r position sampler"
 
-        fwhm = 2*self.radius
-        sig = fwhm/(2 * sqrt(2 * log(2)))
-
-        if self.radius < 0:
-            return sqrt(random.uniform(0, abs(self.radius**2)))
+        #fwhm = 2*self.radius
+        #sig = fwhm/(2 * sqrt(2 * log(2)))
+
+        if isinstance(self.radius, list) and len(self.radius) == 2:
+            # If a list of length 2, generate uniformally over an annulus from r[0] to r[1]
+            return sqrt(random.uniform(abs(self.radius[0]**2), abs(self.radius[1]**2)))
+        elif self.radius < 0:
+            # Generate uniformally up to |r| if r is < 0
+            return sqrt(random.uniform(0, abs(self.radius**2)))        
         else:
+            # Else generate as a Gaussian with widht r
             x = random.gauss(0, self.radius)
             y = random.gauss(0, self.radius)
             return sqrt(x**2 + y**2)
diff --git a/Generators/ForeseeGenerator/share/generate_forsee_events.py b/Generators/ForeseeGenerator/share/generate_forsee_events.py
index 3d84bb15354e0bd1ab8bf47eb1a380b27d08939a..6ef5d1d0377a147246b97b9e203fcc224355bae2 100644
--- a/Generators/ForeseeGenerator/share/generate_forsee_events.py
+++ b/Generators/ForeseeGenerator/share/generate_forsee_events.py
@@ -47,13 +47,13 @@ class ForeseeGenerator(object):
         else:
             self.foresee = Foresee(path = self.path)
 
-        # Generate 6 cm high to account for translation from ATLAS to FASER coord. system
+        # Generate 6.5 cm high to account for translation from ATLAS to FASER coord. system
         # TODO: relax this a bit as daughters may enter even if mother doesn't
 #         self.foresee.set_detector(selection="np.sqrt(x.x**2 + x.y**2)< 0.1",  
 #                                   channels=[self.mode], distance=480, length=1.5 ,
 #                                   luminosity=1/1000.) # 1 pb-1        
 
-        self.foresee.set_detector(selection="np.sqrt(x.x**2 + (x.y - 0.06)**2)< 0.1",  
+        self.foresee.set_detector(selection="np.sqrt(x.x**2 + (x.y - 0.065)**2)< 0.1",  
                                   channels=[self.mode], distance=480, length=1.5 ,
                                   luminosity=1/1000.) # 1 pb-1        
 
@@ -459,7 +459,7 @@ def production(args):
                 f.write()
 
             if args.outdir:
-                p = proc.run(["cp", filename, outdir + "/" + filename.split("/")[-1]])
+                p = proc.run(["cp", filename, outdir + "/" + filename.split("/")[-1].replace(".hepmc", f"{nrun}.hepmc")])
                 if not p.returncode:
                     proc.run(["rm", filename])
 
@@ -492,7 +492,7 @@ if __name__ == "__main__":
     parser.add_argument("--couplings", "-c", required = False, nargs = "+", help = "Couplings of mother (either single/mulitple values or tuple to pass to np.logspace)")
     parser.add_argument("--pid1", default = None, required = False, type = int, help = "PID of daughter 1")
     parser.add_argument("--pid2", default = None, type = int, help = "PID of daughter 2 (if not set then will be -PID1)")
-    parser.add_argument("--Ecom", default = "14", help = "Center of mass energy [TeV]")
+    parser.add_argument("--Ecom", default = "13.6", help = "Center of mass energy [TeV]")
     parser.add_argument("--outdir", "-o", default = None, help = "Output path")    
     parser.add_argument("--path", default = ".", help = "Path to foresee installation")
     parser.add_argument("--hepmc", action = "store_true", help = "Write HepMC events")
diff --git a/Generators/ForeseeGenerator/share/plot_validation.py b/Generators/ForeseeGenerator/share/plot_validation.py
index d4ff9c8b2cb9274a7aade2e8b0a0f6ceb6bf21e9..b3cfc2b55dd58ddd921c4833f7191fef16e618c3 100644
--- a/Generators/ForeseeGenerator/share/plot_validation.py
+++ b/Generators/ForeseeGenerator/share/plot_validation.py
@@ -65,6 +65,7 @@ def plotn(f, args, configs, x, y, outname):
         c._objs.append(plot(f, *cfg))
         
     c.Print(f"{args.output}/{outname}.eps")
+    c.Print(f"{args.output}/{outname}.png")    
 
     return
 
diff --git a/Generators/ForeseeGenerator/share/validate_grid.py b/Generators/ForeseeGenerator/share/validate_grid.py
index e3d5302dff75a44f6cc2a77497f625e6659706db..88edb1194ee6ecebe37464906b26a03afde7b1da 100644
--- a/Generators/ForeseeGenerator/share/validate_grid.py
+++ b/Generators/ForeseeGenerator/share/validate_grid.py
@@ -1,21 +1,27 @@
 import json
 import subprocess as proc
-import os
+from glob import glob
+import os, sys
 
 grid = "../calypso/Generators/ForeseeGenerator/share/points.json"
 
 with open(grid) as f:
     data = json.load(f)
 
-name = "DarkPhotonGrid2"
+name = "DarkPhotonGrid13p6_65mm"
 path = f"/bundle/data/FASER/Carl_Output/Foresee/{name}/"
-ecom = 14
+ecom = 13.6
 pid1 = 11
 pid2 = -11
 
 for coup, masses in data["samples"].items():
     for m in masses:
-        infile = f"{path}events_{ecom}TeV_m{m}GeV_c{float(coup):e}to_{pid1}_{pid2}_{name}.hepmc"
+        files = glob(f"{path}events_{ecom}TeV_m{m}GeV_c{float(coup):.1e}to_{pid1}_{pid2}_{name}*.hepmc")
+
+        if len(files) != 1:
+            continue
+        
+        infile = files[0]
         outfile = infile.replace(".hepmc", ".EVNT.pool.root")
         valfile = infile.replace(".hepmc", ".VAL.pool.root")
         valdir = infile.replace(".hepmc", "")
diff --git a/Generators/ParticleGun/python/histsampling.py b/Generators/ParticleGun/python/histsampling.py
index c64112cc84e23963b63ea381817d1457f1c2a122..9f541da7c972ac01170b8acfafc8001b6eea5a14 100644
--- a/Generators/ParticleGun/python/histsampling.py
+++ b/Generators/ParticleGun/python/histsampling.py
@@ -27,6 +27,9 @@ def load_hist(*args):
             h = args[0].Get(args[1]).Clone()
     if h is None:
         raise Exception("Error in histogram loading from " + args)
+    else:
+        h.SetDirectory(0)
+
     return h
 
 
@@ -40,7 +43,10 @@ def get_sampling_vars(h):
     globalbin_to_axisbin = {} # for reverse axis bin lookup to get edges
     globalbins = [] # because they aren't easily predicted, nor contiguous
     cheights = [0] # cumulative "histogram" from which to uniformly sample
-    if issubclass(type(h), ROOT.TH1):
+
+
+
+    if issubclass(type(h), ROOT.TH1) and not issubclass(type(h), ROOT.TH2):
         for ix in range(1, h.GetNbinsX()+1):
             iglobal = h.GetBin(ix)
             globalbins.append(iglobal)
@@ -109,10 +115,6 @@ class TH1(object):
             self.globalbins, self.globalbin_to_axisbin, self.cheights = get_sampling_vars(self.th1)
         return get_random_x(self.th1, self.globalbins, self.cheights, self.globalbin_to_axisbin)
 
-    def __getattr__(self, attr):
-        "Forward all attributes to the contained TH1"
-        return getattr(self.th1, attr)
-
 
 class TH2(object):
     "Minimal wrapper for ROOT TH2, for easy loading and to allow 2D sampling"
@@ -127,6 +129,4 @@ class TH2(object):
             self.globalbins, self.globalbin_to_axisbin, self.cheights = get_sampling_vars(self.th2)
         return get_random_xy(self.th2, self.globalbins, self.cheights, self.globalbin_to_axisbin)
 
-    def __getattr__(self, attr):
-        "Forward other attributes to the contained TH2"
-        return getattr(self.th2, attr)
+
diff --git a/Generators/ParticleGun/python/samplers.py b/Generators/ParticleGun/python/samplers.py
index 90e9676a5ce20dc1b52e48c79f0b36a7da49f639..d6e540ea6cf7a747d9152202cd488c135fa27099 100644
--- a/Generators/ParticleGun/python/samplers.py
+++ b/Generators/ParticleGun/python/samplers.py
@@ -1,7 +1,7 @@
 # Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
 
 import ROOT, math, random
-from ParticleGun.histsampling import TH1
+from ParticleGun.histsampling import TH1,TH2
 
 ## For convenience
 PI = math.pi
@@ -191,13 +191,26 @@ class TH1Sampler(ContinuousSampler):
 
     def __init__(self, *args):
         self.hist = TH1(*args)
-        if self.hist.GetEntries() < 1:
-            raise Exception("Histogram %s is EMPTY! Cannot sample" % self.hist.GetName())
+        if self.hist.th1.GetEntries() < 1:
+            raise Exception("Histogram %s is EMPTY! Cannot sample" % self.hist.th1.GetName())
 
     def shoot(self):
         return self.hist.GetRandom()
 
 
+class TH2Sampler(ContinuousSampler):
+    "Randomly sample from a 2D ROOT histogram."
+
+    def __init__(self, *args):
+        self.hist = TH2(*args)
+        if self.hist.th2.GetEntries() < 1:
+            raise Exception("Histogram %s is EMPTY! Cannot sample" % self.hist.th2.GetName())
+
+    def shoot(self):
+        return self.hist.GetRandom()
+    
+
+
 ########################################
 
 
@@ -572,9 +585,12 @@ class EThetaMPhiSampler(MomSampler):
 
     # TODO: ensure that E >= m!
 
-    def __init__(self, energy, theta, mass=0.0, phi=[0, TWOPI]):
+    def __init__(self, energy, theta=None, mass=0.0, phi=[0, TWOPI]):
         self.energy = energy
-        self.theta = theta
+        if theta is None:
+            self._theta = None
+        else:
+            self.theta = theta
         self.mass = mass
         self.phi = phi
 
@@ -616,10 +632,15 @@ class EThetaMPhiSampler(MomSampler):
         pz = p cos(theta)
         pt = p sin(theta)
         """
-        e = self.energy()
+
+        if self._theta is None:
+            e,theta = self.energy()
+        else:            
+            e = self.energy()
+            theta = self.theta()
+            
         m = self.mass()
         p = math.sqrt( e**2 - m**2 )
-        theta = self.theta()
         pz = p * math.cos(theta)
         pt = p * math.sin(theta)
         phi = self.phi()
diff --git a/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.cxx b/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.cxx
index e3d33d683e0b47d064216515cf83fb280cb9edd4..c353833fc5d100423c0a97c778cd5243db289184 100644
--- a/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.cxx
+++ b/PhysicsAnalysis/NeutrinoSearch/src/NeutrinoSearchAlg.cxx
@@ -750,4 +750,4 @@ NeutrinoSearchAlg::clearTree() const
   m_syVetoNu = 0;
   m_thetaxVetoNu = 0;
   m_thetayVetoNu = 0;
-}
\ No newline at end of file
+}
diff --git a/PhysicsAnalysis/NtupleDumper/CMakeLists.txt b/PhysicsAnalysis/NtupleDumper/CMakeLists.txt
index dc2dae3126aaa00283775626da1b29bbb0dd3ac3..fab78641d7ae2a3842904122968a80170bca9a28 100644
--- a/PhysicsAnalysis/NtupleDumper/CMakeLists.txt
+++ b/PhysicsAnalysis/NtupleDumper/CMakeLists.txt
@@ -1,4 +1,4 @@
-atlas_subdir(NtupleDumper)
+atlas_subdir( NtupleDumper )
 
 atlas_add_component(
         NtupleDumper
@@ -8,5 +8,5 @@ atlas_add_component(
         LINK_LIBRARIES AthenaBaseComps StoreGateLib xAODFaserWaveform xAODFaserCalorimeter xAODFaserTrigger xAODFaserLHC ScintIdentifier FaserCaloIdentifier GeneratorObjects FaserActsGeometryLib TrackerSimEvent TrackerSimData TrackerIdentifier TrackerReadoutGeometry TrkTrack GeoPrimitives TrackerRIO_OnTrack TrackerSpacePoint FaserActsKalmanFilterLib
 )
 
-atlas_install_python_modules(python/*.py)
-atlas_install_scripts(scripts/*.py)
+atlas_install_python_modules( python/*.py )
+atlas_install_scripts( scripts/*.py scripts/*.sh )
diff --git a/PhysicsAnalysis/NtupleDumper/python/NtupleDumperConfig.py b/PhysicsAnalysis/NtupleDumper/python/NtupleDumperConfig.py
index 5bc52c41df03c934465f97658a39aeb342350631..da44697fc23f3318f599d4451f03fcc196a3f463 100644
--- a/PhysicsAnalysis/NtupleDumper/python/NtupleDumperConfig.py
+++ b/PhysicsAnalysis/NtupleDumper/python/NtupleDumperConfig.py
@@ -2,103 +2,33 @@
     Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
 """
 
-from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
 from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg
+from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometryToolCfg
 
-def NtupleDumperAlgCfg(flags, **kwargs):
+def NtupleDumperAlgCfg(flags, OutName, **kwargs):
     # Initialize GeoModel
     from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
     acc = FaserGeometryCfg(flags)
 
     acc.merge(MagneticFieldSvcCfg(flags))
-    # acc.merge(FaserActsTrackingGeometrySvcCfg(flags))
-    # acc.merge(FaserActsAlignmentCondAlgCfg(flags))
+    #acc.merge(ActsTrackingGeometrySvcCfg(flags))
+    #acc.merge(FaserActsAlignmentCondAlgCfg(flags))
+
+    result, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(flags)
+    acc.merge(result)
 
     actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool")
-    actsExtrapolationTool.MaxSteps = 1000
-    actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool")
+    actsExtrapolationTool.MaxSteps = 10000
+    actsExtrapolationTool.TrackingGeometryTool = actsTrackingGeometryTool 
 
     NtupleDumperAlg = CompFactory.NtupleDumperAlg("NtupleDumperAlg",**kwargs)
     NtupleDumperAlg.ExtrapolationTool = actsExtrapolationTool
     acc.addEventAlgo(NtupleDumperAlg)
 
     thistSvc = CompFactory.THistSvc()
-    thistSvc.Output += ["HIST2 DATAFILE='Data-tuple.root' OPT='RECREATE'"]
+    thistSvc.Output += [f"HIST2 DATAFILE='{OutName}' OPT='RECREATE'"]
     acc.addService(thistSvc)
 
     return acc
 
-if __name__ == "__main__":
-
-    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 OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
-
-    # Set up logging and new style config
-    log.setLevel(INFO)
-    Configurable.configurableRun3Behavior = True
-
-    # Configure
-    ConfigFlags.Input.Files = [
-          '/eos/experiment/faser/rec/2022/p0008//008119/Faser-Physics-008119-00168-p0008-xAOD.root',
-
-
-    ]
-    ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-02"             # Always needed; must match FaserVersionS
-    ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"               # Use MC conditions for now
-    ConfigFlags.Input.ProjectName = "data21"                     # Needed to bypass autoconfig
-    ConfigFlags.Input.isMC = False                                # Needed to bypass autoconfig
-    ConfigFlags.GeoModel.FaserVersion     = "FASERNU-03"           # FASER geometry
-    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))
-
-    # algorithm
-    acc.merge(NtupleDumperAlgCfg(ConfigFlags, UseFlukaWeights=True))
-
-    # silencio
-    AthenaEventLoopMgr = CompFactory.AthenaEventLoopMgr()
-    AthenaEventLoopMgr.EventPrintoutInterval=500
-    acc.addService(AthenaEventLoopMgr)
-
-    # # Hack to avoid problem with our use of MC databases when isMC = False
-    replicaSvc = acc.getService("DBReplicaSvc")
-    replicaSvc.COOLSQLiteVetoPattern = ""
-    replicaSvc.UseCOOLSQLite = True
-    replicaSvc.UseCOOLFrontier = False
-    replicaSvc.UseGeomSQLite = True
-
-    # Timing
-    #acc.merge(MergeRecoTimingObjCfg(ConfigFlags))
-
-    # 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)
-
-    # Success should be 0
-    sys.exit(not sc.isSuccess())    
diff --git a/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.py b/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.py
index 8a47857614ebb70589ed7cb5ab6ca20aef91c878..8cb79460633e7cf16ba5818a43206c6dbe7c20ab 100755
--- a/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.py
+++ b/PhysicsAnalysis/NtupleDumper/scripts/analyzeRun.py
@@ -6,31 +6,9 @@
 
 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
 from AthenaConfiguration.ComponentFactory import CompFactory
-from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg
 
-
-def NtupleDumperAlgCfg(flags, OutName, **kwargs):
-    # Initialize GeoModel
-    from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
-    acc = FaserGeometryCfg(flags)
-
-    acc.merge(MagneticFieldSvcCfg(flags))
-    # acc.merge(FaserActsTrackingGeometrySvcCfg(flags))
-    # acc.merge(FaserActsAlignmentCondAlgCfg(flags))
-
-    actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool")
-    actsExtrapolationTool.MaxSteps = 10000
-    actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool")
-
-    NtupleDumperAlg = CompFactory.NtupleDumperAlg("NtupleDumperAlg",**kwargs)
-    NtupleDumperAlg.ExtrapolationTool = actsExtrapolationTool
-    acc.addEventAlgo(NtupleDumperAlg)
-
-    thistSvc = CompFactory.THistSvc()
-    thistSvc.Output += [f"HIST2 DATAFILE='{OutName}' OPT='RECREATE'"]
-    acc.addService(thistSvc)
-
-    return acc
+# Move NtupleDumperAlgCfg to python/NtupleDumperConfig
+from NtupleDumper.NtupleDumperConfig import NtupleDumperAlgCfg
 
 if __name__ == "__main__":
 
@@ -56,30 +34,41 @@ if __name__ == "__main__":
     Configurable.configurableRun3Behavior = True
 
     dataDir=f"/eos/experiment/faser/rec/2022/{ptag}/{runno:06d}"
-    if inputIsMC: dataDir=f"/eos/experiment/faser/sim/mdc/foresee/{ui.runnum}/rec/r0009/"
+
     files=sorted(glob.glob(f"{dataDir}/Faser*"))
-    if num==-1: num=len(files)
-    fileListInitial=files[0:num]#[num*filesPerJob:(num+1)*filesPerJob]
+    if filesPerJob <= 0: filesPerJob = len(files)
+
+    start = num*filesPerJob
+    end = (num+1)*filesPerJob
+    if end > len(files):
+        end = len(files)
+    fileListInitial=files[start:end]
     fileList=[]
     for fName in fileListInitial:
+        #if fName[:4] == '/eos':
+        #    fName = f'root:/{fName}'
+
         try:
             fh=ROOT.TFile(fName)
             fileList.append(fName)
         except OSError:
             print("Warning bad file: ",fName)
 
-    log.info(f"Analyzing Run {runno} files {0} to {num} (num={num})")
+    log.info(f"Analyzing Run {runno} files {start} to {end} (num={num})")
     log.info(f"Got {len(fileList)} files out of {len(fileListInitial)}")
 
-    outName=f"Data-tuple-{runno:06d}-{num:05d}-{filesPerJob}.root"
+    if start == 0 and end == len(files):
+        outName=f"Faser-Physics-{runno:06d}-{ptag}-PHYS.root"
+    else:
+        outName=f"Faser-Physics-{runno:06d}-{start:05d}-{(end-1):05d}-{ptag}-PHYS.root"
 
     # Configure
     ConfigFlags.Input.Files = fileList
     ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-03"             # Always needed; must match FaserVersionS
     ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"               # Use MC conditions for now
     ConfigFlags.Input.ProjectName = "data21"                     # Needed to bypass autoconfig
-    ConfigFlags.Input.isMC = inputIsMC                                # Needed to bypass autoconfig
-    ConfigFlags.GeoModel.FaserVersion     = "FASERNU-03"           # FASER geometry
+    ConfigFlags.Input.isMC = False                               # Needed to bypass autoconfig
+    ConfigFlags.GeoModel.FaserVersion   = "FASERNU-03"           # FASER geometry
     ConfigFlags.Common.isOnline = False
     ConfigFlags.GeoModel.Align.Dynamic = False
     ConfigFlags.Beam.NumberOfCollisions = 0.
@@ -93,36 +82,36 @@ if __name__ == "__main__":
     acc.merge(PoolReadCfg(ConfigFlags))
 
     # algorithm
-    acc.merge(NtupleDumperAlgCfg(ConfigFlags, outName, UseFlukaWeights=True))
+    acc.merge(NtupleDumperAlgCfg(ConfigFlags, outName))
 
     AthenaEventLoopMgr = CompFactory.AthenaEventLoopMgr()
     AthenaEventLoopMgr.EventPrintoutInterval=1000
     acc.addService(AthenaEventLoopMgr)
 
     # # Hack to avoid problem with our use of MC databases when isMC = False
-    if not inputIsMC:
-        replicaSvc = acc.getService("DBReplicaSvc")
-        replicaSvc.COOLSQLiteVetoPattern = ""
-        replicaSvc.UseCOOLSQLite = True
-        replicaSvc.UseCOOLFrontier = False
-        replicaSvc.UseGeomSQLite = True
+    replicaSvc = acc.getService("DBReplicaSvc")
+    replicaSvc.COOLSQLiteVetoPattern = ""
+    replicaSvc.UseCOOLSQLite = True
+    replicaSvc.UseCOOLFrontier = False
+    replicaSvc.UseGeomSQLite = True
 
     # Timing
     #acc.merge(MergeRecoTimingObjCfg(ConfigFlags))
 
     # 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()
+    if False:
+        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=ui.events)
+    sc = acc.run(maxEvents=-1)
 
     # Success should be 0
     sys.exit(not sc.isSuccess())    
diff --git a/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py b/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py
new file mode 100755
index 0000000000000000000000000000000000000000..27b30e25df16dd8baf1c4ce4b82b6a9e6a0f7b6f
--- /dev/null
+++ b/PhysicsAnalysis/NtupleDumper/scripts/faser_ntuple_maker.py
@@ -0,0 +1,284 @@
+#!/usr/bin/env python
+# 
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration 
+#
+# Run with
+# faser_ntuple_maker.py [options] 
+#
+# Options:
+#   --isMC - needed to reconstruct MC data
+#
+import sys
+import time
+import argparse
+
+a = time.time()
+
+parser = argparse.ArgumentParser(description="Run PHYS ntuple production")
+
+parser.add_argument("path",
+                    help="Fully qualified input path (directory or file)")
+
+parser.add_argument("--slice", type=int, default=0,
+                    help="Specify ordinal output file to produce")
+parser.add_argument("--files", type=int, default=1,
+                    help="Specify reco files per slice")
+parser.add_argument("--merge", type=int, default=1,
+                    help="Specify merged files per reco file (MC only)")
+parser.add_argument("--last", type=int, default=0,
+                    help="Specify last file in slice (normally --files)")
+
+parser.add_argument("--outfile", default="",
+                    help="Override output file name")
+                    
+parser.add_argument("-v", "--verbose", action='store_true', 
+                    help="Turn on DEBUG output")
+parser.add_argument("-n", "--nevents", type=int, default=-1,
+                    help="Specify number of events to process (default: all)")
+
+parser.add_argument("-t", "--tag", default="",
+                    help="Specify tag (to append to output filename)")
+
+parser.add_argument("--isMC", action='store_true',
+                    help="Running on digitised MC rather than data")
+parser.add_argument("--partial", action='store_true',
+                    help="Allow partial input files")
+
+parser.add_argument("--unblind", action='store_true',
+                    help="Don't apply signal blinding (default: do)")
+ 
+parser.add_argument("--fluka", action='store_true',
+                    help="Add FLUKA weights to ntuple")
+parser.add_argument("--genie", action='store_true',
+                    help="Add Genie weights to ntuple")
+
+args = parser.parse_args()
+
+from pathlib import Path
+
+# Must figure out what we are doing here
+filepath = Path(args.path)
+
+filelist = []
+# If this is a directory, need to create file list
+if filepath.is_dir():
+
+    # Use expected data pattern to find files (data only)
+    runstr = filepath.stem
+
+    # Make list of segments to search for
+    seglist = []
+    if args.merge > 1:
+        start = args.slice * args.files * args.merge
+
+        # Number of files to combine
+        if args.last > 0:
+            num = args.last
+        else:
+            num = args.files
+
+        # Make segment list
+        for i in range(start, start+num*args.merge, args.merge):
+            seg = f"{i:05d}-{(i+args.merge-1):05d}"
+            seglist.append(seg)
+
+    else:
+        start = args.slice * args.files
+        if args.last > 0:
+            end = start + args.last
+        else:
+            end = start + args.files
+
+        seglist = [f'{seg:05d}' for seg in range(start, end)]
+
+
+    for seg in seglist:
+
+        if args.isMC:
+            searchstr = f"FaserMC-*-{seg}-*xAOD.root"
+        else:
+            searchstr = f"Faser-Physics-{runstr}-{seg}-*xAOD.root"
+
+        flist = list(filepath.glob(searchstr))
+        if len(flist) == 0:
+            print(f"Didn't find file {searchstr}!")
+            if args.partial: continue
+            sys.exit(1)
+
+        elif len(flist) > 1:
+            print(f"Found multiple matches for {searchstr}!")
+            print(flist)
+            sys.exit(1)
+
+        filestr = str(flist[0].resolve())
+        # Use proper EOS file path here?
+        if filestr[:4] == '/eos':
+            filestr = f"root://eospublic.cern.ch/{filestr}"
+        filelist.append(filestr)
+    # End of loop over segments
+
+    # Parse name to create outfile
+    firstfile = Path(filelist[0])
+    firststem = str(firstfile.stem)
+    firstfaser = firststem.split('-')[0]
+    firstshort = firststem.split('-')[1]
+    runstr = firststem.split('-')[2]
+    firstseg = firststem.split('-')[3]
+    if args.merge > 1:
+        firstseg2 = firststem.split('-')[4]
+
+    lastfile = Path(filelist[-1])
+    laststem = str(lastfile.stem)
+    lastseg = laststem.split('-')[3]
+    if args.merge > 1:
+        lastseg = laststem.split('-')[4]
+
+    print(f"Faser = {firstfaser}")
+    print(f"Short = {firstshort}")
+    print(f"Run   = {runstr}")
+    print(f"First = {firstseg}")
+    print(f"Last  = {lastseg}")
+    print(f"Args  = {args.tag}")
+    print(f"Blind = {not args.unblind}")
+
+    # Find any tags
+    tagstr = firststem.replace(f"{firstfaser}-{firstshort}-{runstr}-{firstseg}", "")
+    if args.merge > 1:
+        tagstr = tagstr.replace(f"-{firstseg2}", "")
+
+    tagstr = tagstr.replace("-xAOD", "")
+
+    print(f"Tag   = {tagstr}")
+
+    # Build output name
+    outfile = f"{firstfaser}-{firstshort}-{runstr}-{firstseg}-{lastseg}"
+
+    # This will include the leading -
+    if len(tagstr) > 0:
+        outfile += f"{tagstr}"
+
+    if len(args.tag) > 0 and args.tag not in tagstr:
+        outfile += f"-{args.tag}"
+
+    outfile += "-PHYS.root"
+
+
+# If this is a single file, just process that
+# Could be a url, so don't check if this is a file
+else:
+    filelist.append(args.path)
+
+    # Build output name
+    filestem = str(filepath.stem)
+
+    # Remove -xAOD from end
+    if filestem[-5:] == "-xAOD":
+        filestem = filestem[:-5]
+
+    # Do we want to add a tag?
+    if len(args.tag) > 0 and args.tag not in filestem:
+        filestem += f"-{args.tag}"
+
+    outfile = f"{filestem}-PHYS.root"
+
+# Print out what we found
+if len(filelist) == 0:
+    printf("Found no files for {args.path}!")
+    sys.exit(1)
+elif len(filelist) == 1:
+    print("Processing file:")
+else:
+    print("Processing files:")
+for f in filelist:
+    print(f)
+
+# Override output file?
+if len(args.outfile) > 0:
+    outfile = args.outfile
+
+print("Output file:")
+print(outfile)
+
+# OK, lets run the job here
+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
+
+Configurable.configurableRun3Behavior = True
+
+# Configure
+ConfigFlags.Input.Files = filelist
+ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-03"         # Always needed; must match FaserVersionS
+ConfigFlags.Input.isMC = args.isMC
+if args.isMC:
+    ConfigFlags.IOVDb.DatabaseInstance = "OFLP200"           # Use MC conditions 
+else:
+    ConfigFlags.IOVDb.DatabaseInstance = "CONDBR3"           # Use data conditions
+
+ConfigFlags.Input.ProjectName = "data21"                     # Needed to bypass autoconfig
+
+ConfigFlags.GeoModel.FaserVersion   = "FASERNU-03"           # FASER geometry
+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))
+
+# algorithm
+from NtupleDumper.NtupleDumperConfig import NtupleDumperAlgCfg
+if args.isMC:
+    if args.genie:
+        acc.merge(NtupleDumperAlgCfg(ConfigFlags, outfile, UseGenieWeights=True))
+    elif args.fluka:
+        acc.merge(NtupleDumperAlgCfg(ConfigFlags, outfile, UseFlukaWeights=True))
+    else:
+        acc.merge(NtupleDumperAlgCfg(ConfigFlags, outfile))
+
+else:
+    acc.merge(NtupleDumperAlgCfg(ConfigFlags, outfile, DoBlinding=(not args.unblind)))
+
+if not args.verbose:
+    from AthenaConfiguration.ComponentFactory import CompFactory
+    AthenaEventLoopMgr = CompFactory.AthenaEventLoopMgr()
+    AthenaEventLoopMgr.EventPrintoutInterval=1000
+    acc.addService(AthenaEventLoopMgr)
+
+# Hack to avoid problem with our use of MC databases when isMC = False
+if not args.isMC:
+    replicaSvc = acc.getService("DBReplicaSvc")
+    replicaSvc.COOLSQLiteVetoPattern = ""
+    replicaSvc.UseCOOLSQLite = True
+    replicaSvc.UseCOOLFrontier = False
+    replicaSvc.UseGeomSQLite = True
+
+if args.verbose:
+    log.setLevel(VERBOSE)
+    acc.printConfig(withDetails=True)
+    ConfigFlags.dump()
+else:
+    log.setLevel(INFO)
+
+acc.getService("MessageSvc").Format = "% F%40W%S%7W%R%T %0W%M"
+
+# Execute and finish
+sc = acc.run(maxEvents=args.nevents)
+
+b = time.time()
+log.info(f"Finish execution in {b-a} seconds")
+
+# Success should be 0
+if sc.isSuccess():
+    log.info("Execution succeeded")
+    sys.exit(0)
+else:
+    log.info("Execution failed, return 1")
+    sys.exit(1)
+
diff --git a/PhysicsAnalysis/NtupleDumper/scripts/submit_faser_ntuple_maker.sh b/PhysicsAnalysis/NtupleDumper/scripts/submit_faser_ntuple_maker.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9e3273dbb970f5b5d80958f67656490c045a7612
--- /dev/null
+++ b/PhysicsAnalysis/NtupleDumper/scripts/submit_faser_ntuple_maker.sh
@@ -0,0 +1,282 @@
+#!/bin/bash
+#
+# Used with a condor file to submit a physics ntuple job
+#
+# Usage:
+# submit_ntuple_maker.sh dirpath slice nfiles [release_directory] [working_directory] 
+#
+# Options:
+#   --out - specify output location (in EOS) to copy output HITS file
+#   --log - specify output location (in EOS) for log file
+#   --isMC - needed for MC reco
+#   --partial - allow missing files
+#   --merge - merge factor of reco files (for MC)
+#   --fluka - create fluka weights
+#   --genie - create genie weights
+#
+# dirpath - full directory path to HITS files
+# slice - ordinal output file number
+# nfiles - number of HITS files to process per slice
+# release_directory - optional path to release install directory (default pwd)
+# working_directory - optional path to output directory location (default pwd)
+# lastfile - number of files in this slice (for last file, default 0)
+#
+# The release directory must already be set up 
+# (so an unqualified asetup can set up the release properly)
+#
+#----------------------------------------
+# Keep track of time
+SECONDS=0
+#
+# Defaults
+ismc=""
+partialstr=""
+mergestr=""
+flukastr=""
+geniestr=""
+unblindstr=""
+#
+# Parse command-line options
+while [ -n "$1" ]
+do 
+  case "$1" in
+      -l | --log)
+	  logdest="$2";
+	  shift;
+	  shift;; # Must eat 2 options here
+
+      -o | --out)
+	  outdest="$2";
+	  shift;
+	  shift;;
+
+      --isMC)
+	  ismc="--isMC"
+	  shift;;
+
+      --partial)
+	  echo "Allowing partial merge"
+	  partialstr="--partial"
+	  shift;;
+
+      --merge)
+	  mergestr="--merge $2";
+	  shift;
+	  shift;;
+
+      --fluka)
+	  flukastr="--fluka";
+	  shift;;
+
+      --genie)
+	  geniestr="--genie";
+	  shift;;
+
+      --unblind)
+	  unblindstr="--unblind";
+	  shift;;
+
+      --) # End of options
+	  shift; # Eat this
+	  break;; # And stop parsing
+
+    -*) 
+	  echo "Unknown option $1"
+	  shift;;
+
+    *) break;;  # Not an option, don't shift
+  esac
+done
+#
+# Parse command-line options
+dir_path=${1}
+slice=${2}
+nfiles=${3}
+release_directory=${4}
+working_directory=${5}
+last_file=${6}
+#
+# Set defaults if arguments aren't provided
+if [ -z "$dir_path" ]
+then
+  echo "No directory specified!"
+  echo "Usage: submit_ntuple_maker.sh directory slice nfiles [release dir] [output dir]"
+  exit 1
+fi
+#
+if [ -z "$slice" ]
+then
+  echo "Slice number not specified!"
+  echo "Usage: submit_ntuple_maker.sh directory slice nfiles [release dir] [output dir]"
+  exit 1
+fi
+#
+if [ -z "$nfiles" ]
+then
+  echo "Files per slice not specified!"
+  echo "Usage: submit_ntuple_maker.sh directory slice nfiles [release dir] [output dir]"
+  exit 1
+fi
+#
+if [ -z "$release_directory" ]
+then
+  release_directory=`pwd`
+fi
+#
+if [ -z "$working_directory" ]
+then
+  working_directory=`pwd`
+fi
+#
+starting_directory=`pwd`
+#
+# Now extract the run number and file stem
+#
+# First, get an example filename
+file_name=`ls -1 $dir_path | head -1`
+# 
+# Now split based on '.' to get stem
+defaultIFS=$IFS
+IFS='.'
+read file_stem ext <<< "$file_name"
+#
+# Finally extract the run number
+IFS='-'
+# Read the split words into an array based on delimiter
+read faser short run_number segment <<< "$file_stem"
+#
+# Set the IFS delimeter back or else echo doesn't work...
+IFS=$defaultIFS
+#
+# Make output directory if needed
+output_directory="$working_directory/$run_number"
+mkdir -p "$output_directory"
+#
+# Need to make up an output name
+printf -v slicestr "%04d" $slice
+#
+file_stem="$faser-$short-$run_number-$slicestr-PHYS"
+#
+# This magic redirects everything in this script to our log file
+logfile="${file_stem}.ntp.log"
+exec >& "$output_directory/$logfile"
+echo `date` - $HOSTNAME
+echo "Directory: $dir_path"
+echo "Slice: $slice"
+echo "NFiles: $nfiles"
+echo "Merge: $mergestr"
+echo "Release: $release_directory"
+echo "Output: $output_directory"
+echo "Starting: $starting_directory"
+echo "job: $file_stem"
+echo "Last: $last_file"
+#
+# Set up the release (do this automatically)?
+export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase
+source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh 
+#
+# Always go back to the starting directory in case paths are relative
+cd "$starting_directory"
+cd "$release_directory"
+#
+# Do this by hand
+asetup --input=calypso/asetup.faser Athena,22.0.49
+source run/setup.sh
+#
+echo "ATLAS_POOLCOND_PATH = $ATLAS_POOLCOND_PATH"
+#
+# Check if there are data overrides
+if [ -d "run/data/sqlite200" ]; then
+   cond_directory=`pwd -P`/run/data  # Get absolute path
+fi
+#
+# Try to find a release tag
+cd calypso
+recotag=`git describe --tags`
+if [[ "$recotag" == "reco/r"???? ]]; then
+  tag=`echo "$recotag" | cut -c 6-11`
+  echo "Found reco tag: $tag"
+fi
+if [[ "$recotag" == "digi/d"???? ]]; then
+  tag=`echo "$recotag" | cut -c 6-11`
+  echo "Found digi tag: $tag"
+fi
+if [[ "$recotag" == "sim/s"???? ]]; then
+  tag=`echo "$recotag" | cut -c 5-10`
+  echo "Found sim tag: $tag"
+fi
+#
+if [[ -z "$tag" ]]; then
+    tagstr=""
+else
+    tagstr="--tag $tag"
+fi
+#
+if [[ -z "$last_file" ]]; then
+    last_file_str=""
+else
+    last_file_str="--last $last_file"
+fi
+#
+# Move to the run directory
+cd "$starting_directory"
+cd "$output_directory"
+#
+# Make run directory
+if [[ -e "$file_stem" ]]; then
+    echo "Directory $file_stem already exists"
+else
+    mkdir "$file_stem"
+fi
+cd "$file_stem"
+#
+# Check if there are data overrides in the relese directory
+if [[ -z "$cond_directory" ]]; then
+    echo "No local conditions directory found!"
+else
+    echo "Local conditions directory found!  Copying to run directory..."
+    echo Copying $cond_directory
+    cp -r $cond_directory .
+    ls -R data
+fi
+#
+export EOS_MGM_URL=root://eospublic.cern.ch
+#
+# Run job
+#
+faser_ntuple_maker.py $last_file_str $partialstr $tagstr $ismc --slice $slice --files $nfiles $mergestr $flukastr $geniestr $unblindstr $dir_path
+ntup_code=$?
+echo "Return code: $ntup_code"
+#
+# Print out ending time
+date
+echo "Job finished after $SECONDS seconds"
+# 
+# Copy output to EOS if desired
+if ! [ -z "$outdest" ]
+then
+    ls -l
+    echo "copy *-PHYS.root to $outdest"
+    mkdir -p $outdest
+    eos cp *-PHYS.root ${outdest}/ || true
+fi
+#
+# Also copy log file
+if ! [ -z "$logdest" ]
+then
+    cd ..
+    ls -l
+    echo "copy $logfile to $logdest"
+    mkdir -p $logdest
+    eos cp $logfile $logdest/$logfile
+elif ! [ -z "$outdest" ]
+then 
+    cd ..
+    ls -l
+    echo "copy $logfile to $outdest"
+    mkdir -p $outdest
+    eos cp $logfile $outdest/$logfile
+fi
+
+# Make sure to return an error if ntuple failed
+exit $ntup_code
diff --git a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx
index 1369684d16f1071c2b5eab6e5853b87459d0e06a..3f476edb40480e5871a2df39a3cd2695ea894e4c 100644
--- a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx
+++ b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.cxx
@@ -106,6 +106,7 @@ StatusCode NtupleDumperAlg::initialize()
 
   ATH_CHECK(m_preshowerCalibratedContainer.initialize());
   ATH_CHECK(m_ecalCalibratedContainer.initialize());
+  ATH_CHECK(m_eventInfoKey.initialize());
 
   ATH_CHECK(detStore()->retrieve(m_sctHelper,       "FaserSCT_ID"));
   ATH_CHECK(detStore()->retrieve(m_vetoNuHelper,    "VetoNuID"));
@@ -160,8 +161,8 @@ StatusCode NtupleDumperAlg::initialize()
 
   //WAVEFORMS
   addWaveBranches("VetoNu",2,4);
-  addWaveBranches("VetoSt1",2,6);
-  addWaveBranches("VetoSt2",1,14);
+  addWaveBranches("VetoSt1",1,14);
+  addWaveBranches("VetoSt2",2,6);
   addWaveBranches("Timing",4,8);
   addWaveBranches("Preshower",2,12);
   addWaveBranches("Calo",4,0);
@@ -197,6 +198,7 @@ StatusCode NtupleDumperAlg::initialize()
   m_tree->Branch("TrackSegment_pz", &m_trackseg_pz);
 
   //TrackCollection
+  m_tree->Branch("Track_PropagationError", &m_propagationError, "Track_PropagationError/I");
   m_tree->Branch("longTracks", &m_longTracks, "longTracks/I");
   m_tree->Branch("Track_Chi2", &m_Chi2);
   m_tree->Branch("Track_nDoF", &m_DoF);
@@ -304,6 +306,24 @@ StatusCode NtupleDumperAlg::initialize()
   m_tree->Branch("truthPdg", &m_truthPdg, "truthPdg/I");
   m_tree->Branch("CrossSection", &m_crossSection, "crossSection/D");
 
+
+  // first 10 truth particles 
+
+  m_tree->Branch("truth_P", &m_truth_P);
+  m_tree->Branch("truth_px", &m_truth_px);
+  m_tree->Branch("truth_py", &m_truth_py);
+  m_tree->Branch("truth_pz", &m_truth_pz);
+  m_tree->Branch("truth_m", &m_truth_m);
+  m_tree->Branch("truth_pdg", &m_truth_pdg);
+
+  m_tree->Branch("truth_prod_x", &m_truth_prod_x);
+  m_tree->Branch("truth_prod_y", &m_truth_prod_y);
+  m_tree->Branch("truth_prod_z", &m_truth_prod_z);
+
+  m_tree->Branch("truth_dec_x", &m_truth_dec_x);
+  m_tree->Branch("truth_dec_y", &m_truth_dec_y);
+  m_tree->Branch("truth_dec_z", &m_truth_dec_z);
+
   // for mother + daughter particle truth infomation 
 
   m_tree->Branch("truthM_P", &m_truthM_P);
@@ -410,6 +430,8 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
     bool trig_coincidence_vetoesORpreshower_and_calo = false;
     if ( ((m_tap&2)!=0) && ((m_tap&1)!=0) ) trig_coincidence_vetoesORpreshower_and_calo = true;
 
+    bool trig_calo = (m_tap & 1);
+
     // for random trigger, store charge of scintillators in histograms
     if (trig_random) {
       // Read in Waveform containers
@@ -462,7 +484,8 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
 
       return StatusCode::SUCCESS; // finished with this randomly triiggered event
 
-    } else if ( !(trig_coincidence_preshower_and_vetoes || trig_coincidence_timing_and_vetoesORpreshower || trig_coincidence_timing_and_calo || trig_coincidence_vetoesORpreshower_and_calo) ) { 
+      // Try adding calo-only trigger
+    } else if ( !(trig_coincidence_preshower_and_vetoes || trig_coincidence_timing_and_vetoesORpreshower || trig_coincidence_timing_and_calo || trig_coincidence_vetoesORpreshower_and_calo || trig_calo) ) { 
       // don't process events that fail to activate coincidence triggers
       return StatusCode::SUCCESS;
     }
@@ -546,30 +569,64 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
     SG::ReadHandle<xAOD::TruthParticleContainer> truthParticleContainer { m_truthParticleContainer, ctx };
     if (truthParticleContainer.isValid() && truthParticleContainer->size() > 0)
     {
-      for (auto particle : *truthParticleContainer)
-      {
-        if ( particle->barcode() <= 3) 
-        {
 
-	if ( particle->barcode() == 1) // mother particle (A')
-	  {
-
-	  m_truthM_P.push_back(particle->p4().P());
-	  m_truthM_px.push_back(particle->p4().X());
-	  m_truthM_py.push_back(particle->p4().Y());
-	  m_truthM_pz.push_back(particle->p4().Z());
-
-	  if ( particle->hasProdVtx()) {
-	    m_truthM_x.push_back(particle->prodVtx()->x());
-	    m_truthM_y.push_back(particle->prodVtx()->y());
-	    m_truthM_z.push_back(particle->prodVtx()->z());
-	  } else {
+      int ipart(0);
+      for (auto particle : *truthParticleContainer)
+      {      
+
+	// loop over first 10 truth particles (for non A' samples)
+
+	if (ipart++ < 10) {
+	    
+	  m_truth_P.push_back(particle->p4().P());
+	  m_truth_px.push_back(particle->p4().X());
+	  m_truth_py.push_back(particle->p4().Y());
+	  m_truth_pz.push_back(particle->p4().Z());
+	  m_truth_m.push_back(particle->m());
+	  m_truth_pdg.push_back(particle->pdgId());
+
+	    if ( particle->hasProdVtx()) {
+	        m_truth_prod_x.push_back(particle->prodVtx()->x());
+		m_truth_prod_y.push_back(particle->prodVtx()->y());
+		m_truth_prod_z.push_back(particle->prodVtx()->z());
+	      } else {
+		m_truth_prod_x.push_back(NaN);
+		m_truth_prod_y.push_back(NaN);
+		m_truth_prod_z.push_back(NaN);
+	      }
+
+	    if ( particle->hasDecayVtx()) {
+	      m_truth_dec_x.push_back(particle->decayVtx()->x());
+	      m_truth_dec_y.push_back(particle->decayVtx()->y());
+	      m_truth_dec_z.push_back(particle->decayVtx()->z());
+	      } else {
+		m_truth_dec_x.push_back(NaN);
+		m_truth_dec_y.push_back(NaN);
+		m_truth_dec_z.push_back(NaN);
+	    }
+	}
+	
+	     	     
+       if ( particle->barcode() == 1 || particle->barcode() == 2 || particle->barcode() == 3 ) {
+
+	 if ( particle->pdgId() == 32) { // mother particle (A')
+	  
+	   m_truthM_P.push_back(particle->p4().P());
+	   m_truthM_px.push_back(particle->p4().X());
+	   m_truthM_py.push_back(particle->p4().Y());
+	   m_truthM_pz.push_back(particle->p4().Z());
+
+	 if ( particle->hasDecayVtx()) { // decay vertex for A' particle 
+	    m_truthM_x.push_back(particle->decayVtx()->x());
+	    m_truthM_y.push_back(particle->decayVtx()->y());
+	    m_truthM_z.push_back(particle->decayVtx()->z());
+	 } else {
 	    m_truthM_x.push_back(NaN);
 	    m_truthM_y.push_back(NaN);
 	    m_truthM_z.push_back(NaN);
 	  }
+	 }
 
-	  }
 	if ( particle->pdgId() == 11) // daughter particle (positron)
 	  {
 	    m_truthd0_P.push_back(particle->p4().P());
@@ -604,12 +661,13 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
 	    m_truthd1_z.push_back(NaN);
 	  }
 	  }
-	}
+       }
       }
-    }
+    }	  
   }
 
   // load in calibrated calo container
+  if (m_doCalib) {
   SG::ReadHandle<xAOD::CalorimeterHitContainer> ecalCalibratedContainer { m_ecalCalibratedContainer, ctx };
   ATH_CHECK(ecalCalibratedContainer.isValid());
   for (auto hit : *ecalCalibratedContainer) {
@@ -649,6 +707,7 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
 
     ATH_MSG_DEBUG("Calibrated preshower: ch is " << ch << ", edep is " << hit->E_dep() << ", E_EM is " << hit->E_EM() << ", Nmip is " << hit->Nmip() << ", fit_to_raw_ratio is " << hit->fit_to_raw_ratio());
   }
+  }
 
   // process all waveeform data fro all scintillator and calorimeter channels
   SG::ReadHandle<xAOD::WaveformHitContainer> vetoNuContainer { m_vetoNuContainer, ctx };
@@ -673,14 +732,23 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
   FillWaveBranches(*ecalContainer);
 
   // enforce blinding such that events that miss the veto layers and have a large calo signal are skipped and not in the output root file
-  if ( (!isMC) && m_doBlinding) {
-    if ( m_calo_total_E_EM/1000.0 > 10.0 ) { // energy is in MeV so divide by 1000 to compare to 10 GeV
+  // Only blind colliding BCIDs (+/- 1)
+  if ( (!isMC) && m_doBlinding && abs(m_distanceToCollidingBCID) <= 1) {
+    if (m_calo_total_E_EM > m_blindingCaloThreshold ) { // energy is in MeV
       if (m_wave_status[4] == 1 and m_wave_status[5] == 1 and m_wave_status[6] == 1 and m_wave_status[7] == 1 and m_wave_status[14] == 1) {  // hit status == 1 means it is below threshold. channles 4 and 5 are vetoNu, channels 6,7, and 14 are veto
         return StatusCode::SUCCESS;
       }
     }
   }
 
+  SG::ReadDecorHandle<xAOD::EventInfo,uint32_t> eventInfo (m_eventInfoKey, ctx);
+  if (eventInfo->errorState(xAOD::EventInfo_v1::SCT) == xAOD::EventInfo::Error) {
+    m_propagationError = 1;
+    ATH_MSG_DEBUG("NtupleDumper: xAOD::EventInfo::SCT::Error");
+  } else {
+    m_propagationError = 0;
+  }
+
   // get geometry context
   FaserActsGeometryContext faserGeometryContext = m_trackingGeometryTool->getNominalGeometryContext();
   auto gctx = faserGeometryContext.context();
@@ -766,8 +834,16 @@ StatusCode NtupleDumperAlg::execute(const EventContext &ctx) const
   // loop over all reconstructed tracks and use only the tracks that have hits in all three tracking stations (excludes IFT)
   // store track parameters at most upstream measurement and at most downstream measurement
   // extrapolate track to all scintillator positions and store extrapolated position and angle
-  SG::ReadHandle<TrackCollection> trackCollection {m_trackCollectionWithoutIFT, ctx}; // use track collection that excludes IFT
+  SG::ReadHandle<TrackCollection> trackCollection;
+  if (m_useIFT) {
+    SG::ReadHandle<TrackCollection> tc {m_trackCollection, ctx}; // use track collection that excludes IFT
+    trackCollection = tc;
+  } else {
+    SG::ReadHandle<TrackCollection> tc {m_trackCollectionWithoutIFT, ctx}; // use track collection that excludes IFT
+    trackCollection = tc;
+  }
   ATH_CHECK(trackCollection.isValid());
+
   for (const Trk::Track* track : *trackCollection)
   {
     if (track == nullptr) continue;
@@ -1218,6 +1294,44 @@ NtupleDumperAlg::clearTree() const
   m_truthLeptonMomentum = 0;
   m_truthBarcode = 0;
   m_truthPdg = 0;
+
+  m_truth_P.clear();
+  m_truth_px.clear();
+  m_truth_py.clear();
+  m_truth_pz.clear();
+  m_truth_m.clear();
+  m_truth_pdg.clear();
+  m_truth_prod_x.clear();
+  m_truth_prod_y.clear();
+  m_truth_prod_z.clear();
+  m_truth_dec_x.clear();
+  m_truth_dec_y.clear();
+  m_truth_dec_z.clear();
+
+  m_truthM_P.clear();
+  m_truthM_px.clear();
+  m_truthM_py.clear();
+  m_truthM_pz.clear();
+  m_truthM_x.clear();
+  m_truthM_y.clear();
+  m_truthM_z.clear();
+
+  m_truthd0_P.clear();
+  m_truthd0_px.clear();
+  m_truthd0_py.clear();
+  m_truthd0_pz.clear();
+  m_truthd0_x.clear();
+  m_truthd0_y.clear();
+  m_truthd0_z.clear();
+
+  m_truthd1_P.clear();
+  m_truthd1_px.clear();
+  m_truthd1_py.clear();
+  m_truthd1_pz.clear();
+  m_truthd1_x.clear();
+  m_truthd1_y.clear();
+  m_truthd1_z.clear();
+
 }
 
 void NtupleDumperAlg::setNaN() const {
diff --git a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h
index 5cc342021993ca07354e6a4924f7e5cfb07ae552..6d4ccc381a4b65831678a657c035ecc4e79c2b65 100644
--- a/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h
+++ b/PhysicsAnalysis/NtupleDumper/src/NtupleDumperAlg.h
@@ -21,6 +21,8 @@
 #include "FaserActsKalmanFilter/IFiducialParticleTool.h"
 #include "FaserActsKalmanFilter/ITrackTruthMatchingTool.h"
 #include "TrackerSimEvent/FaserSiHitCollection.h"
+#include "xAODEventInfo/EventInfo.h"
+#include "StoreGate/ReadDecorHandle.h"
 
 #include <vector>
 
@@ -84,7 +86,8 @@ private:
 
   SG::ReadHandleKey<xAOD::FaserTriggerData> m_FaserTriggerData     { this, "FaserTriggerDataKey", "FaserTriggerData", "ReadHandleKey for xAOD::FaserTriggerData"};
   SG::ReadHandleKey<xAOD::WaveformClock> m_ClockWaveformContainer     { this, "WaveformClockKey", "WaveformClock", "ReadHandleKey for ClockWaveforms Container"};
-  ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool { this, "ExtrapolationTool", "FaserActsExtrapolationTool" };  
+  SG::ReadDecorHandleKey<xAOD::EventInfo> m_eventInfoKey{this, "EventInfoKey", "EventInfo"};
+  ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool { this, "ExtrapolationTool", "FaserActsExtrapolationTool" };
   ToolHandle<IFaserActsTrackingGeometryTool> m_trackingGeometryTool {this, "TrackingGeometryTool", "FaserActsTrackingGeometryTool"};
   ToolHandle<ITrackTruthMatchingTool> m_trackTruthMatchingTool {this, "TrackTruthMatchingTool", "TrackTruthMatchingTool"};
   ToolHandle<IFiducialParticleTool> m_fiducialParticleTool {this, "FiducialParticleTool", "FiducialParticleTool"};
@@ -98,6 +101,8 @@ private:
   const PreshowerID* m_preshowerHelper;
   const EcalID*      m_ecalHelper;
 
+  BooleanProperty m_useIFT            { this, "UseIFT", false, "Use IFT tracks" };
+  BooleanProperty m_doCalib           { this, "DoCalib", true, "Fill calibrated calorimeter quantities" };
   BooleanProperty m_doBlinding        { this, "DoBlinding", true, "Blinding will not output events with Calo signal > 10 GeV e-" };
   BooleanProperty m_useFlukaWeights   { this, "UseFlukaWeights", false, "Flag to weight events according to value stored in HepMC::GenEvent" };
   BooleanProperty m_useGenieWeights   { this, "UseGenieWeights", false, "Flag to weight events according to Genie luminosity" };
@@ -106,6 +111,8 @@ private:
   DoubleProperty  m_genieLuminosity   { this, "GenieLuminosity", 150.0, "Genie luminosity in inverse fb." };
   DoubleProperty  m_minMomentum       { this, "MinMomentum", 50000.0, "Write out all truth particles with a momentum larger MinMomentum"};
 
+  DoubleProperty m_blindingCaloThreshold {this, "BlindingCaloThreshold", 25000.0, "Blind events with Ecal energy above threshold (in MeV)"}; 
+
   double m_baseEventCrossSection {1.0};
   const double kfemtoBarnsPerMilliBarn {1.0e12};
 
@@ -189,6 +196,7 @@ private:
   mutable std::vector<double> m_trackseg_pz;
 
   mutable int    m_longTracks;
+  mutable int m_propagationError;
   mutable std::vector<double> m_Chi2;
   mutable std::vector<double> m_DoF;
   mutable std::vector<double> m_xup;
@@ -274,7 +282,7 @@ private:
   mutable std::vector<double> m_truthM_py;
   mutable std::vector<double> m_truthM_pz;
 
-  mutable std::vector<double> m_truthM_x;
+  mutable std::vector<double> m_truthM_x; // decay vertex of A'
   mutable std::vector<double> m_truthM_y;
   mutable std::vector<double> m_truthM_z;
 
@@ -284,7 +292,7 @@ private:
   mutable std::vector<double> m_truthd0_py;
   mutable std::vector<double> m_truthd0_pz;
 
-  mutable std::vector<double> m_truthd0_x;
+  mutable std::vector<double> m_truthd0_x; // production vertex for daughter particles 
   mutable std::vector<double> m_truthd0_y;
   mutable std::vector<double> m_truthd0_z;
 
@@ -298,6 +306,27 @@ private:
   mutable std::vector<double> m_truthd1_y;
   mutable std::vector<double> m_truthd1_z;
 
+  // first 10 truth particles 
+
+  mutable std::vector<double> m_truth_P;
+  mutable std::vector<double> m_truth_px;
+  mutable std::vector<double> m_truth_py;
+  mutable std::vector<double> m_truth_pz;
+  mutable std::vector<double> m_truth_m;
+
+  mutable std::vector<double> m_truth_dec_x; // components of decay vertex (mm)
+  mutable std::vector<double> m_truth_dec_y;
+  mutable std::vector<double> m_truth_dec_z;
+
+  mutable std::vector<double> m_truth_prod_x; // components of production vertex (mm)
+  mutable std::vector<double> m_truth_prod_y;
+  mutable std::vector<double> m_truth_prod_z;
+
+  mutable std::vector<int> m_truth_pdg; // pdg of first 10 truth particles 
+
+
+
+
   mutable double m_truthLeptonMomentum;
   mutable int    m_truthBarcode;
   mutable int    m_truthPdg;
diff --git a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx
index ea03a77f16d12cd4cb45c99c96a20c1fbc8323e7..1869860e84a401fffbfe6a588d6b8e78ba702e9a 100644
--- a/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx
+++ b/Scintillator/ScintDigiAlgs/src/ScintWaveformDigiAlg.cxx
@@ -3,6 +3,7 @@
 #include "ScintSimEvent/ScintHitIdHelper.h"
 
 #include <map>
+#include <cmath>
 
 
 ScintWaveformDigiAlg::ScintWaveformDigiAlg(const std::string& name, 
@@ -110,42 +111,68 @@ ScintWaveformDigiAlg::execute(const EventContext& ctx) const {
     waveforms = m_digiTool->create_waveform_map(m_preshowerID);
   } 
 
+  // Sum energy for each channel (i.e. identifier)
+  std::map<Identifier, float> esum;  
+
+  Identifier id;
+  for (const auto& hit : *scintHitHandle) { 
+    if (first.isTrigger()) {
+      Identifier plate_id = m_triggerID->plate_id(hit.getIdentifier());      
+      // Need to do something better here, but for now just fill both
+      id = m_triggerID->pmt_id(plate_id, 0); // ID for PMT 0
+      esum[id] += hit.energyLoss();
+      id = m_triggerID->pmt_id(plate_id, 1); // ID for PMT 1
+      esum[id] += hit.energyLoss();
+    } else {
+      // All others have only 1 PMT
+      // Use detector id (not hit id) throughout
+      id = hit.getIdentifier();
+      esum[id] += hit.energyLoss();
+    }
+  }
+
   // Loop over time samples
-  // Should really do sums first, as repeating these in the loop is a waste
   for (const auto& tk : m_timekernel) {
     std::map<Identifier, float> counts;
    
-    // Convolve hit energy with evaluated kernel and sum for each hit id (i.e. channel)
-    Identifier id;
-    for (const auto& hit : *scintHitHandle) {            
-
-      // Special handling for trigger scintillator
-      if (first.isTrigger()) {
-	// Hits are created per plate
-	// Need to split between 2 PMTs
-
-	// Identifier from hit is plate ID
-	Identifier plate_id = m_triggerID->plate_id(hit.getIdentifier());
-
-	// Need to do something better here, but for now just fill both
-	id = m_triggerID->pmt_id(plate_id, 0); // ID for PMT 0
-	counts[id] += tk * hit.energyLoss();
-	id = m_triggerID->pmt_id(plate_id, 1); // ID for PMT 1
-	counts[id] += tk * hit.energyLoss();
-
-      } else {
-	// All others have only 1 PMT
-	// Use detector id (not hit id) throughout
-	id = hit.getIdentifier();
-	counts[id] += tk * hit.energyLoss();
-      }
+//     // Convolve hit energy with evaluated kernel and sum for each hit id (i.e. channel)
+//     Identifier id;
+//     for (const auto& hit : *scintHitHandle) {            
+// 
+//       // Special handling for trigger scintillator
+//       if (first.isTrigger()) {
+// 	// Hits are created per plate
+// 	// Need to split between 2 PMTs
+// 
+// 	// Identifier from hit is plate ID
+// 	Identifier plate_id = m_triggerID->plate_id(hit.getIdentifier());
+// 
+// 	// Need to do something better here, but for now just fill both
+// 	id = m_triggerID->pmt_id(plate_id, 0); // ID for PMT 0
+// 	counts[id] += tk * hit.energyLoss();
+// 	id = m_triggerID->pmt_id(plate_id, 1); // ID for PMT 1
+// 	counts[id] += tk * hit.energyLoss();
+// 
+//       } else {
+// 	// All others have only 1 PMT
+// 	// Use detector id (not hit id) throughout
+// 	id = hit.getIdentifier();
+// 	counts[id] += tk * hit.energyLoss();
+//       }
+//     }
+
+    // Convolve summed energy with evaluated kernel for each hit id (i.e. channel)
+    for (const auto& e : esum) {
+      // Convert hit id to Identifier and store 
+      id = e.first;
+      counts[id] = tk * e.second;
     }
 
     // Subtract count from basleine and add result to correct waveform vector
     for (const auto& c : counts) {
 
-      unsigned int baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
-      int value = baseline - c.second;
+      float baseline = m_digiTool->generate_baseline(m_base_mean, m_base_rms);
+      int value = std::round(baseline - c.second);
 
       if (value < 0) {
 	ATH_MSG_WARNING("Found pulse " << c.second << " larger than baseline " << c.first);
diff --git a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx
index 4483eb5b4cd52b31aa70cb915ba6500641297685..227a1d7c2157aa09c54f2803b2654bec924610e0 100644
--- a/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx
+++ b/Tracker/TrackerAlignTools/TrackerAlignGenTools/src/TrackerAlignDBTool.cxx
@@ -209,8 +209,8 @@ StatusCode TrackerAlignDBTool::createDB() const
 	{
 	  const auto iStation = m_sctid->station(ident);
 	  const auto iLayer = m_sctid->layer(ident); 
-      const auto iModuleEta = m_sctid->eta_module(ident);
-      const auto iModulePhi = m_sctid->phi_module(ident);
+	  const auto iModuleEta = m_sctid->eta_module(ident);
+	  const auto iModulePhi = m_sctid->phi_module(ident);
 	  int iModule = iModulePhi;
 	  if (iModuleEta < 0) iModule +=4;
 
@@ -258,26 +258,31 @@ StatusCode TrackerAlignDBTool::createDB() const
 	    auto iStation = m_sctid->station(ident);
 	    auto iLayer = m_sctid->layer(ident);
 
-        const auto buildKey = [](auto iStation, auto iLayer) {
-            std::stringstream ss;
-            ss << iStation << iLayer; 
-            return ss.str();
-        };
-        
-        const auto key = buildKey(iStation, iLayer); 
-        if (not (m_alignment.find(key) == m_alignment.end())) {
-          const std::vector<double> c = m_alignment.value().find(key)->second;
-          ATH_MSG_VERBOSE("Applying correction for " << key);
-          ATH_MSG_VERBOSE(c[0] << " " << c[1] << " " << c[2] << " " << c[3] << " " << c[4] << " " << c[5]);
-          Amg::Translation3D newtranslation(c[0], c[1], c[2]);
-          Amg::Transform3D alignment = newtranslation * Amg::RotationMatrix3D::Identity();
-          alignment *= Amg::AngleAxis3D(c[5], Amg::Vector3D(0.,0.,1.));
-          alignment *= Amg::AngleAxis3D(c[4], Amg::Vector3D(0.,1.,0.));
-          alignment *= Amg::AngleAxis3D(c[3], Amg::Vector3D(1.,0.,0.));
-
-	      pat->add(ident2, Amg::EigenTransformToCLHEP(alignment));
+	    const auto buildKey = [](auto iStation, auto iLayer) {
+	      std::stringstream ss;
+	      ss << iStation << iLayer; 
+	      return ss.str();
+	    };
+
+	    const auto key = buildKey(iStation, iLayer); 
+	    if (not (m_alignment.find(key) == m_alignment.end())) {
+	      const std::vector<double> c = m_alignment.value().find(key)->second;
+	      ATH_MSG_VERBOSE("Applying correction for " << key);
+	      ATH_MSG_VERBOSE(c[0] << " " << c[1] << " " << c[2] << " " << c[3] << " " << c[4] << " " << c[5]);
+	      Amg::Translation3D newtranslation(c[0], c[1], c[2]);
+	      Amg::Transform3D alignment = newtranslation * Amg::RotationMatrix3D::Identity();
+	      alignment *= Amg::AngleAxis3D(c[5], Amg::Vector3D(0.,0.,1.));
+	      alignment *= Amg::AngleAxis3D(c[4], Amg::Vector3D(0.,1.,0.));
+	      alignment *= Amg::AngleAxis3D(c[3], Amg::Vector3D(1.,0.,0.));
+
+	      Amg::Translation3D newtransl(0,0,element->transform().translation()[2]);
+	      Amg::Transform3D newcorr= newtransl * Amg::RotationMatrix3D::Identity();
+
+	      pat->add(ident2, Amg::EigenTransformToCLHEP(newcorr*alignment*newcorr.inverse()));
+
+//	      pat->add(ident2, Amg::EigenTransformToCLHEP(alignment));
 	    } else {
-          ATH_MSG_VERBOSE("No correction given for " << key);
+	      ATH_MSG_VERBOSE("No correction given for " << key);
 	    }
 	  } 
 	  else 
@@ -294,12 +299,6 @@ StatusCode TrackerAlignDBTool::createDB() const
   std::string key1 = dirkey(ident1, 1);
   if ((pat = getTransPtr(key1))) 
   {
-    //	Amg::Translation3D translation(0.1,0.2,0.3);
-    //Amg::Transform3D globshift=translation*Amg::RotationMatrix3D::Identity();
-    //std::cout<<"rotation"<<std::endl;
-    //std::cout<<globshift.rotation()(0,0)<<" , "<<globshift.rotation()(1,1)<<" , "<<globshift.rotation()(2,2)<<std::endl;
-    //std::cout<<"translation"<<std::endl;
-    //std::cout<<globshift.translation()(0,0)<<" , "<<globshift.translation()(1,1)<<" , "<<globshift.translation()(2,2)<<std::endl;
     Amg::Transform3D globshift;
     globshift.setIdentity();
     for (int station : m_stations)
diff --git a/Tracker/TrackerDetDescr/FaserSCT_GeoModel/python/FaserSCT_GeoModelConfig.py b/Tracker/TrackerDetDescr/FaserSCT_GeoModel/python/FaserSCT_GeoModelConfig.py
index 038c8c38bb3c6d0daed962726f310867873a4c02..b9a3215b3696127b083a3cd6a71fa25e10f227be 100644
--- a/Tracker/TrackerDetDescr/FaserSCT_GeoModel/python/FaserSCT_GeoModelConfig.py
+++ b/Tracker/TrackerDetDescr/FaserSCT_GeoModel/python/FaserSCT_GeoModelConfig.py
@@ -2,7 +2,7 @@
 
 from AthenaConfiguration.ComponentFactory import CompFactory
 from AthenaConfiguration.Enums import ProductionStep
-from IOVDbSvc.IOVDbSvcConfig import addFolders, addFoldersSplitOnline
+from IOVDbSvc.IOVDbSvcConfig import addFolders #, addFoldersSplitOnline
 
 def FaserSCT_GeometryCfg( flags ):
     from FaserGeoModel.GeoModelConfig import GeoModelCfg
@@ -27,17 +27,20 @@ def FaserSCT_GeometryCfg( flags ):
     if flags.GeoModel.Align.Disable:
         return acc
 
+    # Don't specify db= in addFolders calls below
+    # dbname set globally to OFLP200 for MC and CONDBR3 for data
+    # Now have proper data and MC DBs for the alignment
     if flags.GeoModel.Align.Dynamic:
         # acc.merge(addFoldersSplitOnline(flags,"INDET","/Indet/Onl/AlignL1/ID","/Indet/AlignL1/ID",className="CondAttrListCollection"))
         # acc.merge(addFoldersSplitOnline(flags,"INDET","/Indet/Onl/AlignL2/SCT","/Indet/AlignL2/SCT",className="CondAttrListCollection"))
         # acc.merge(addFoldersSplitOnline(flags,"INDET","/Indet/Onl/AlignL3","/Indet/AlignL3",className="AlignableTransformContainer"))
         print("FaserSCT dynamic align flag is not supported!")
     else:
-        print("Override Alignment dbname to OFLP200, fix this when alignment available in CONDBR3")
         if flags.Common.Project != "AthSimulation" and (flags.Common.ProductionStep != ProductionStep.Simulation or flags.Overlay.DataOverlay):
-            acc.merge(addFolders(flags,"/Tracker/Align", "SCT_OFL", className="AlignableTransformContainer", db="OFLP200"))
+            acc.merge(addFolders(flags,"/Tracker/Align", "SCT_OFL", className="AlignableTransformContainer"))
         else:
-            acc.merge(addFolders(flags, "/Tracker/Align", "SCT_OFL", db="OFLP200"))
+            acc.merge(addFolders(flags, "/Tracker/Align", "SCT_OFL"))
+
     if flags.Common.Project != "AthSimulation": # Protection for AthSimulation builds
         if flags.Common.ProductionStep != ProductionStep.Simulation or flags.Overlay.DataOverlay:
             FaserSCT_AlignCondAlg = CompFactory.FaserSCT_AlignCondAlg
diff --git a/Tracker/TrackerDetDescr/TrackerReadoutGeometry/src/SCT_DetectorManager.cxx b/Tracker/TrackerDetDescr/TrackerReadoutGeometry/src/SCT_DetectorManager.cxx
index 33aa094fc5abee616cd7713d054c510eed394960..96acb3c5f306e472c35af834f597f0c2a74c0f86 100755
--- a/Tracker/TrackerDetDescr/TrackerReadoutGeometry/src/SCT_DetectorManager.cxx
+++ b/Tracker/TrackerDetDescr/TrackerReadoutGeometry/src/SCT_DetectorManager.cxx
@@ -180,6 +180,7 @@ namespace TrackerDD {
                                                        GeoVAlignmentStore* alignStore) const
   {
     if (level == 0) { // 0 - At the element level
+      std::cout<<"like SCT_DetectorManager::setAlignableTransformDelta 183 level "<<level<<std::endl;
 
       // We retrieve it via a hashId.
       IdentifierHash idHash = m_idHelper->wafer_hash(id);
@@ -194,6 +195,7 @@ namespace TrackerDD {
         SiDetectorElement * element =  m_elementCollection[idHash];
         if (!element) return false;
 
+      std::cout<<"like SCT_DetectorManager::setAlignableTransformDelta 198"<<std::endl;
 
         // Its a local transform
         //See header file for definition of m_isLogical          
@@ -213,6 +215,7 @@ namespace TrackerDD {
 
     } else if (level == 1) { // module level
 
+      std::cout<<"like SCT_DetectorManager::setAlignableTransformDelta 218"<<std::endl;
       // We retrieve it via a hashId.
       IdentifierHash idHash = m_idHelper->wafer_hash(id);
       if (!idHash.is_valid()) return false;
diff --git a/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx
index aecebc372e415c6c58f1464706c6f25ea6001dc2..a194e065b23c83dc4b345a73a50f1ec499a95916 100644
--- a/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx
+++ b/Tracker/TrackerRecAlgs/MyExtrapolationExample/src/MyExtrapolationExample.cxx
@@ -23,6 +23,8 @@ StatusCode MyExtrapolationExample::initialize() {
 }
 
 StatusCode MyExtrapolationExample::execute(const EventContext &ctx) const {
+  // The following uses the nominal geometry (without alignment)
+  // To use the aligned version, use getGeometryContext() instead
   const Acts::GeometryContext gctx =
       m_extrapolationTool->trackingGeometryTool()->getNominalGeometryContext().context();
 
diff --git a/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/python/TrackerSpacePointFormationConfig.py b/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/python/TrackerSpacePointFormationConfig.py
index 4bd7402d130957407bdf9d3ca3a660b18530060a..d98f18b66a4f4d5a6eb8fa461382b021b10de7b9 100644
--- a/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/python/TrackerSpacePointFormationConfig.py
+++ b/Tracker/TrackerRecAlgs/TrackerSpacePointFormation/python/TrackerSpacePointFormationConfig.py
@@ -67,7 +67,8 @@ def TrackerSpacePointFinderCfg(flags, **kwargs):
     """Return ComponentAccumulator for SCT SpacePoints and Output"""
     acc=TrackerDDSiElementPropertiesTableCondAlgCfg(flags)
     acc.merge(TrackerSpacePointFinderBasicCfg(flags, **kwargs))
-    acc.merge(TrackerSpacePointFinder_OutputCfg(flags))
+    if flags.Output.doWriteESD:
+       acc.merge(TrackerSpacePointFinder_OutputCfg(flags))
     return acc
 
 def StatisticsCfg(flags, **kwargs):
diff --git a/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py b/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py
index d81e6fd90ce1bd9128b715857840fd93c9fcf126..9b13d866e9ef5808d3953f5a7529683341566aa4 100644
--- a/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py
+++ b/Tracking/Acts/FaserActsGeometry/python/ActsGeometryConfig.py
@@ -37,6 +37,7 @@ def ActsTrackingGeometryToolCfg(configFlags, name = "ActsTrackingGeometryTool" )
   result = ComponentAccumulator()
   acc = ActsTrackingGeometrySvcCfg(configFlags)
   result.merge(acc) 
+  result.merge(ActsAlignmentCondAlgCfg(configFlags))
   Acts_ActsTrackingGeometryTool = FaserActsTrackingGeometryTool
   actsTrackingGeometryTool = Acts_ActsTrackingGeometryTool("TrackingGeometryTool")
   result.addPublicTool(actsTrackingGeometryTool)
@@ -61,7 +62,7 @@ def ActsAlignmentCondAlgCfg(configFlags, name = "ActsAlignmentCondAlg", **kwargs
   acc = ActsTrackingGeometrySvcCfg(configFlags)
   result.merge(acc)
   
-  Acts_ActsAlignmentCondAlg = CompFactory.ActsAlignmentCondAlg
+  Acts_ActsAlignmentCondAlg = CompFactory.FaserActsAlignmentCondAlg
   actsAlignmentCondAlg = Acts_ActsAlignmentCondAlg(name, **kwargs)
   result.addCondAlgo(actsAlignmentCondAlg)
   
@@ -98,17 +99,6 @@ def ActsMaterialTrackWriterSvcCfg(name="FaserActsMaterialTrackWriterSvc",
   result.addService(ActsMaterialTrackWriterSvc, primary=True)
   return result
 
-def ActsMaterialStepConverterToolCfg(name = "ActsMaterialStepConverterTool" ) :
-  result=ComponentAccumulator()
-  
-  Acts_ActsMaterialStepConverterTool = CompFactory.ActsMaterialStepConverterTool
-  ActsMaterialStepConverterTool = Acts_ActsMaterialStepConverterTool(name)
-
-  from AthenaCommon.Constants import INFO
-  ActsMaterialStepConverterTool.OutputLevel = INFO
-
-  result.addPublicTool(ActsMaterialStepConverterTool, primary=True)
-  return result
 
 def ActsSurfaceMappingToolCfg(configFlags, name = "FaserActsSurfaceMappingTool" ) :
   result=ComponentAccumulator()
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.cxx
index 5f0735b99c7192d7d761191046157b42340e7cf9..3e38e6fd02c81a67a6f90450b96d074d680006c7 100644
--- a/Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.cxx
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsAlignmentCondAlg.cxx
@@ -108,10 +108,12 @@ StatusCode FaserActsAlignmentCondAlg::execute() {
     size_t nElems = 0;
     trkGeom->visitSurfaces([&actsAlignStore, &nElems](const Acts::Surface *srf) {
       const Acts::DetectorElementBase *detElem =
-          srf->associatedDetectorElement();
+      srf->associatedDetectorElement();
+      if(detElem){
       const auto *gmde = static_cast<const FaserActsDetectorElement *>(detElem);
       gmde->storeTransform(actsAlignStore.get());
       nElems++;
+      }
     });
     ATH_MSG_DEBUG("FaserActsAlignmentStore populated for " << nElems
                                                       << " detector elements");
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsDetectorElement.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsDetectorElement.cxx
index 5545334849da0bb6b068c768773ae4878e52b5f5..59357dfc70de1a9b9d025d2c2bbf2b5a7d0a421b 100644
--- a/Tracking/Acts/FaserActsGeometry/src/FaserActsDetectorElement.cxx
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsDetectorElement.cxx
@@ -118,9 +118,10 @@ FaserActsDetectorElement::transform(const Acts::GeometryContext& anygctx) const
 void
 FaserActsDetectorElement::storeTransform(FaserActsAlignmentStore* gas) const
 {
-  Amg::Transform3D g2l
-        = m_detElement->getMaterialGeom()->getDefAbsoluteTransform()
-        * Amg::CLHEPTransformToEigen(m_detElement->recoToHitTransform());
+//  Amg::Transform3D g2l
+//        = m_detElement->getMaterialGeom()->getDefAbsoluteTransform()
+//        * Amg::CLHEPTransformToEigen(m_detElement->recoToHitTransform());
+  Amg::Transform3D g2l = m_detElement->transform() ;
 
   // need to make sure translation has correct units
   g2l.translation() *= length_unit;
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx
index 0e92508b08f01b792c15913a45f37cda8c0eb5c0..d31fe8d3c11e804e115aef2cc6dfc08a2354b9e7 100644
--- a/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsExtrapolationTool.cxx
@@ -126,8 +126,7 @@ FaserActsExtrapolationTool::propagationSteps(const EventContext& ctx,
 
     Acts::MagneticFieldContext mctx = getMagneticFieldContext(ctx);
     const FaserActsGeometryContext& gctx
-      //= m_trackingGeometryTool->getGeometryContext(ctx);
-      = m_trackingGeometryTool->getNominalGeometryContext();
+      = m_trackingGeometryTool->getGeometryContext(ctx);
 
     auto anygctx = gctx.context();
 
@@ -200,8 +199,7 @@ FaserActsExtrapolationTool::propagate(const EventContext& ctx,
 
   Acts::MagneticFieldContext mctx = getMagneticFieldContext(ctx);
   const FaserActsGeometryContext& gctx
-      //= m_trackingGeometryTool->getGeometryContext(ctx);
-      = m_trackingGeometryTool->getNominalGeometryContext();
+      = m_trackingGeometryTool->getGeometryContext(ctx);
 
   auto anygctx = gctx.context();
 
@@ -319,8 +317,7 @@ FaserActsExtrapolationTool::propagate(const EventContext& ctx,
   ATH_MSG_VERBOSE(name() << "::" << __FUNCTION__ << " begin");
 
   Acts::MagneticFieldContext mctx = getMagneticFieldContext(ctx);
-  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext();
-//  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getGeometryContext(ctx);
+  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getGeometryContext(ctx);
 
   auto anygctx = gctx.context();
 
diff --git a/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx
index a45c7c06d37214248a19b189ca40886339c9f1b4..aef43cf4022b059edf059d614d22929b84644871 100644
--- a/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx
+++ b/Tracking/Acts/FaserActsGeometry/src/FaserActsTrackingGeometrySvc.cxx
@@ -63,7 +63,7 @@ FaserActsTrackingGeometrySvc::initialize()
 
   //get all the subdetectors
   const GeoModelExperiment* theExpt = nullptr;
-  ATH_CHECK( m_detStore->retrieve( theExpt ,"FASER"));
+  ATH_CHECK( m_detStore->retrieve( theExpt ));
   const GeoVDetectorManager *vetoManager = theExpt->getManager("Veto");
   const GeoVDetectorManager *triggerManager = theExpt->getManager("Trigger");
   const GeoVDetectorManager *dipoleManager = theExpt->getManager("Dipole");
diff --git a/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt b/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt
index f93c094287a4966f84689abaa2615da2b2ef8882..874d604249142448e76634c8dac9a8d0ef1db8f5 100755
--- a/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt
+++ b/Tracking/Acts/FaserActsKalmanFilter/CMakeLists.txt
@@ -29,6 +29,7 @@ atlas_add_component(FaserActsKalmanFilter
     CircleFit.h
     CircleFitTrackSeedTool.h
     CKF2.h
+    CKF2Alignment.h
     CombinatorialKalmanFilterAlg.h
     EffPlotTool.h
     FASERSourceLink.h
@@ -73,6 +74,7 @@ atlas_add_component(FaserActsKalmanFilter
     src/CircleFit.cxx
     src/CircleFitTrackSeedTool.cxx
     src/CKF2.cxx
+    src/CKF2Alignment.cxx
     src/CreateTrkTrackTool.h
     src/CreateTrkTrackTool.cxx
 #    src/ClusterTrackSeedTool.cxx
diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Alignment.py b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Alignment.py
new file mode 100644
index 0000000000000000000000000000000000000000..eb5f84da0eb61bf7031090cf49911b9728ea82d0
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Alignment.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+
+import sys
+from AthenaCommon.Logging import log, logging
+from AthenaCommon.Constants import 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 TrackerPrepRawDataFormation.TrackerPrepRawDataFormationConfig import FaserSCT_ClusterizationCfg
+from TrackerSpacePointFormation.TrackerSpacePointFormationConfig import TrackerSpacePointFinderCfg
+from TrackerSegmentFit.TrackerSegmentFitConfig import SegmentFitAlgCfg
+from FaserActsKalmanFilter.GhostBustersConfig import GhostBustersCfg
+from TruthSeededTrackFinder.TruthSeededTrackFinderConfig import TruthSeededTrackFinderCfg
+from FaserSCT_GeoModel.FaserSCT_GeoModelConfig import FaserSCT_GeometryCfg
+from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometryToolCfg
+from FaserActsGeometry.ActsGeometryConfig import ActsExtrapolationToolCfg
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg
+from AthenaConfiguration.ComponentFactory import CompFactory
+
+THistSvc=CompFactory.getComps("THistSvc")
+
+CKF2Alignment, FaserActsExtrapolationTool, FaserActsTrackingGeometryTool=CompFactory.getComps("CKF2Alignment", "FaserActsExtrapolationTool","FaserActsTrackingGeometryTool")
+from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometrySvcCfg
+
+
+def CKF2AlignmentCfg(flags, **kwargs):
+    acc = FaserSCT_GeometryCfg(flags)
+    acc.merge(MagneticFieldSvcCfg(flags))
+    result, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(flags)
+#    acts_tracking_geometry_svc = ActsTrackingGeometrySvcCfg(flags)
+    acc.merge(result)
+    track_seed_tool = CompFactory.CircleFitTrackSeedTool()
+    #remove the IFT in the track finding or not
+    track_seed_tool.removeIFT = False
+    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 = [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.TrackCollection = "Segments"
+    # useless in the alignment, will clean them up
+    trajectory_states_writer_tool = CompFactory.RootTrajectoryStatesWriterTool()
+    trajectory_states_writer_tool.noDiagnostics = kwargs.pop("noDiagnostics", True)
+    trajectory_states_writer_tool1 = CompFactory.RootTrajectoryStatesWriterTool()
+    trajectory_states_writer_tool1.noDiagnostics = kwargs.pop("noDiagnostics", True)
+    trajectory_states_writer_tool1.FilePath = "/pool/track_states_ckf1_10root"
+    
+    trajectory_summary_writer_tool = CompFactory.RootTrajectorySummaryWriterTool()
+    trajectory_summary_writer_tool.noDiagnostics = kwargs.pop("noDiagnostics", True)
+    trajectory_summary_writer_tool1 = CompFactory.RootTrajectorySummaryWriterTool()
+    trajectory_summary_writer_tool1.FilePath = "/pool/track_summary_ckf1_0.root"
+    trajectory_summary_writer_tool1.noDiagnostics = kwargs.pop("noDiagnostics", True)
+    actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool")
+    actsExtrapolationTool.MaxSteps = 1000
+    actsExtrapolationTool.TrackingGeometryTool = actsTrackingGeometryTool
+    acc.merge(result)
+    
+    trajectory_performance_writer_tool = CompFactory.PerformanceWriterTool("PerformanceWriterTool")
+    trajectory_performance_writer_tool.ExtrapolationTool = actsExtrapolationTool
+    trajectory_performance_writer_tool.noDiagnostics = kwargs.pop("noDiagnostics", True)
+    ckf2fit = CompFactory.CKF2Alignment(**kwargs)
+    #biased residual or unbiased
+    ckf2fit.BiasedResidual = False
+    ckf2fit.ExtrapolationTool = actsExtrapolationTool
+    ckf2fit.TrackingGeometryTool=actsTrackingGeometryTool
+    kalman_fitter1 = CompFactory.KalmanFitterTool(name="fitterTool1")
+    kalman_fitter1.noDiagnostics = True
+    kalman_fitter1.ActsLogging = "INFO"
+    kalman_fitter1.SummaryWriter = False
+    kalman_fitter1.StatesWriter = False
+    kalman_fitter1.SeedCovarianceScale = 10
+    kalman_fitter1.isMC = False
+    kalman_fitter1.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool1
+    kalman_fitter1.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool1
+    ckf2fit.KalmanFitterTool1 = kalman_fitter1
+    ckf2fit.TrackSeed = track_seed_tool
+    ckf2fit.ActsLogging = "INFO"
+    ckf2fit.isMC = False
+    ckf2fit.nMax = 10
+    ckf2fit.chi2Max = 100000
+    ckf2fit.maxSteps = 5000
+    histSvc= CompFactory.THistSvc()
+    # output ntuple
+    histSvc.Output +=  [ "CKF2Alignment DATAFILE='kfalignment_mc.root' OPT='RECREATE'"]
+    acc.addService(histSvc)
+    acc.addEventAlgo(ckf2fit)
+    return acc
+
+if __name__ == "__main__":
+
+#   log.setLevel(INFO)
+   Configurable.configurableRun3Behavior = True
+   
+   # Configure
+   ConfigFlags.Input.Files = [ '' ] #input RDO
+   ConfigFlags.IOVDb.GlobalTag = "OFLCOND-FASER-03"
+   ConfigFlags.GeoModel.FaserVersion     = "FASERNU-03"           # FASER cosmic ray geometry (station 2 only)
+   ConfigFlags.TrackingGeometry.MaterialSource = "material-maps.json" # material map
+   ConfigFlags.Input.isMC = True
+   ConfigFlags.GeoModel.Align.Dynamic = False
+   ConfigFlags.Input.ProjectName = "data21"                     # Needed to bypass autoconfig
+   ConfigFlags.Beam.NumberOfCollisions = 0.
+   ConfigFlags.addFlag("Input.InitialTimeStamp", 0)
+   ConfigFlags.Exec.MaxEvents = -1
+   ConfigFlags.Output.doWriteESD = False
+   #ConfigFlags.Concurrency.NumThreads = 1
+#   ConfigFlags.addFlag("Alignment.Output", "ckf_alignment.root")
+   ConfigFlags.fillFromArgs(sys.argv[1:])
+   ConfigFlags.dump()
+   ConfigFlags.lock()
+   
+   from FaserGeoModel.FaserGeoModelConfig import FaserGeometryCfg
+   # Core components
+   acc = MainServicesCfg(ConfigFlags)
+   acc.merge(FaserGeometryCfg(ConfigFlags))
+   acc.merge(PoolReadCfg(ConfigFlags))
+   acc.merge(PoolWriteCfg(ConfigFlags))
+   from FaserByteStreamCnvSvc.FaserByteStreamCnvSvcConfig import FaserByteStreamCnvSvcCfg
+   # Inner Detector
+   acc.merge(FaserSCT_ClusterizationCfg(ConfigFlags))
+   acc.merge(TrackerSpacePointFinderCfg(ConfigFlags))
+   acc.merge(SegmentFitAlgCfg(ConfigFlags, SharedHitFraction=0.61, MinClustersPerFit=5, TanThetaXZCut=0.083))
+   acc.merge(GhostBustersCfg(ConfigFlags))
+   acc.merge(CKF2AlignmentCfg(ConfigFlags))
+   logging.getLogger('forcomps').setLevel(INFO)
+   acc.foreach_component("*").OutputLevel = INFO
+   acc.foreach_component("*ClassID*").OutputLevel = INFO
+   
+   # Execute and finish
+   sc = acc.run()
+   sys.exit(not sc.isSuccess())
diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py
index 1035484b832fec4f32ca36400309a36cd250ed91..5d6ed5c4f3170cfc57b058d6bc9432329c1da561 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py
+++ b/Tracking/Acts/FaserActsKalmanFilter/python/CKF2Config.py
@@ -8,6 +8,7 @@ from AthenaConfiguration.ComponentFactory import CompFactory
 from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
 from MagFieldServices.MagFieldServicesConfig import MagneticFieldSvcCfg
 from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometrySvcCfg
+from FaserActsGeometry.ActsGeometryConfig import ActsTrackingGeometryToolCfg
 
 
 def FaserActsAlignmentCondAlgCfg(flags, **kwargs):
@@ -72,7 +73,11 @@ def CKF2Cfg(flags, **kwargs):
 
     actsExtrapolationTool = CompFactory.FaserActsExtrapolationTool("FaserActsExtrapolationTool")
     actsExtrapolationTool.MaxSteps = 1000
-    actsExtrapolationTool.TrackingGeometryTool = CompFactory.FaserActsTrackingGeometryTool("TrackingGeometryTool")
+
+    #use the tracking geometry tool which has enabled the alignment condition algo
+    result, actsTrackingGeometryTool = ActsTrackingGeometryToolCfg(flags)
+    actsExtrapolationTool.TrackingGeometryTool = actsTrackingGeometryTool
+    acc.merge(result)
 
     trajectory_performance_writer_tool = CompFactory.PerformanceWriterTool("PerformanceWriterTool")
     trajectory_performance_writer_tool.ExtrapolationTool = actsExtrapolationTool
@@ -95,15 +100,14 @@ def CKF2Cfg(flags, **kwargs):
     ckf.RootTrajectoryStatesWriterTool = trajectory_states_writer_tool
     ckf.RootTrajectorySummaryWriterTool = trajectory_summary_writer_tool
     ckf.PerformanceWriterTool = trajectory_performance_writer_tool
+    ckf.TrackingGeometryTool=actsTrackingGeometryTool
     ckf.isMC = flags.Input.isMC
     ckf.SummaryWriter = True
     ckf.StatesWriter = False
     ckf.PerformanceWriter = False
 
     ckf.nMax = 10
-    # Use larger chi2 cut until alignment improves
-    # ckf.chi2Max = 25
-    ckf.chi2Max = 100000
+    ckf.chi2Max = 25
     # Protect against running out of memory on busy events
     ckf.maxSteps = 5000
     acc.addEventAlgo(ckf)
diff --git a/Tracking/Acts/FaserActsKalmanFilter/python/GhostBustersConfig.py b/Tracking/Acts/FaserActsKalmanFilter/python/GhostBustersConfig.py
index ebe56d179393fcf3f51cb8df510271fbf5a85ebe..57d7c035d2fe56f3ec62a4a9c0013421c37b57ff 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/python/GhostBustersConfig.py
+++ b/Tracking/Acts/FaserActsKalmanFilter/python/GhostBustersConfig.py
@@ -26,7 +26,8 @@ def GhostBustersCfg(flags, **kwargs):
     acts_tracking_geometry_svc = ActsTrackingGeometrySvcCfg(flags)
     acc.merge(acts_tracking_geometry_svc )
     acc.addEventAlgo(CompFactory.GhostBusters(**kwargs))
-    acc.merge(GhostBusters_OutputCfg(flags))
+    if flags.Output.doWriteESD:
+       acc.merge(GhostBusters_OutputCfg(flags))
 
     # thistSvc = CompFactory.THistSvc()
     # thistSvc.Output += ["HIST2 DATAFILE='GhostBusters.root' OPT='RECREATE'"]
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx
index 4161c19eecbc6b30b0436732f76498f71f3f4fa6..817fcfea171e76d70d75f49a540e0604f2f52984 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/ActsTrackSeedTool.cxx
@@ -36,7 +36,7 @@ StatusCode ActsTrackSeedTool::run(std::vector<int> /*maskedLayers*/) {
 
   using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>;
   std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap();
-  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext();
+  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getGeometryContext();
   Acts::GeometryContext geoctx = gctx.context();
 
   const int kSize = 1;
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx
index 858b97d6b2655859d77f027b31a57ce5782b95ae..f990be9458e0ee2ac0a5bdef8b670703f1424c26 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.cxx
@@ -2,6 +2,7 @@
 
 #include "StoreGate/ReadHandle.h"
 #include "StoreGate/ReadCondHandleKey.h"
+#include "StoreGate/WriteDecorHandle.h"
 #include "TrackerSpacePoint/FaserSCT_SpacePointCollection.h"
 #include "TrackerSpacePoint/FaserSCT_SpacePoint.h"
 #include "TrackerIdentifier/FaserSCT_ID.h"
@@ -28,9 +29,9 @@
 #include "Acts/Propagator/Propagator.hpp"
 #include "Acts/TrackFitting/GainMatrixSmoother.hpp"
 #include "Acts/TrackFitting/GainMatrixUpdater.hpp"
-
-
 #include "Acts/EventData/Measurement.hpp"
+#include "Acts/Propagator/PropagatorError.hpp"
+#include "Acts/TrackFinding/CombinatorialKalmanFilterError.hpp"
 
 size_t CKF2::TrajectoryInfo::nClusters {0};
 
@@ -49,6 +50,7 @@ StatusCode CKF2::initialize() {
   ATH_CHECK(m_kalmanFitterTool1.retrieve());
   ATH_CHECK(m_createTrkTrackTool.retrieve());
   ATH_CHECK(m_trackCollection.initialize());
+  ATH_CHECK(m_eventInfoKey.initialize());
   if (m_performanceWriter && !m_noDiagnostics) {
     ATH_CHECK(m_performanceWriterTool.retrieve());
   }
@@ -78,13 +80,15 @@ StatusCode CKF2::execute() {
   const EventContext& ctx = Gaudi::Hive::currentContext();
   m_numberOfEvents++;
 
+  SG::WriteDecorHandle<xAOD::EventInfo,uint32_t> eventInfo (m_eventInfoKey, ctx);
+
   SG::WriteHandle 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& faserActsGeometryContext = m_trackingGeometryTool->getNominalGeometryContext();
+  const FaserActsGeometryContext& faserActsGeometryContext = m_trackingGeometryTool->getGeometryContext();
   auto gctx = faserActsGeometryContext.context();
   Acts::MagneticFieldContext magFieldContext = getMagneticFieldContext(ctx);
   Acts::CalibrationContext calibContext;
@@ -150,6 +154,14 @@ StatusCode CKF2::execute() {
   std::list<TrajectoryInfo> allTrajectories;
   for (auto &result : results) {
     if (not result.ok()) {
+      // TODO use status bits for different errors
+      // result.error() == Acts::CombinatorialKalmanFilterError::NoTrackFound
+      if (result.error() == Acts::PropagatorError::StepCountLimitReached ||
+          result.error() == Acts::CombinatorialKalmanFilterError::PropagationReachesMaxSteps) {
+        if (!eventInfo->updateErrorState(xAOD::EventInfo::SCT, xAOD::EventInfo::Error)) {
+          ATH_MSG_WARNING (" cannot set error state for SCT");
+        }
+      }
       continue;
     }
     CKFResult ckfResult = result.value();
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.h b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.h
index 2111afcf6b52d46b45e1e2539d105290b937689e..170f0353904bef82095146c50bf98d5721ef2138 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.h
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2.h
@@ -21,6 +21,7 @@
 #include "KalmanFitterTool.h"
 #include <boost/dynamic_bitset.hpp>
 #include "CreateTrkTrackTool.h"
+#include "xAODEventInfo/EventInfo.h"
 using ConstTrackStateProxy = Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>;
 using ClusterSet = boost::dynamic_bitset<>;
 
@@ -148,6 +149,7 @@ private:
   ToolHandle<CreateTrkTrackTool> m_createTrkTrackTool {this, "CreateTrkTrackTool", "CreateTrkTrackTool"};
   Gaudi::Property<bool> m_isMC {this, "isMC", false};
   SG::WriteHandleKey<TrackCollection> m_trackCollection { this, "OutputCollection", "CKFTrackCollection", "Output track collection name" };
+  SG::WriteDecorHandleKey<xAOD::EventInfo> m_eventInfoKey{this, "EventInfoKey", "EventInfo"};
 };
 
 #endif // FASERACTSKALMANFILTER_CKF2_H
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CKF2Alignment.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2Alignment.cxx
new file mode 100755
index 0000000000000000000000000000000000000000..afd377fc5effaa67f7c9e949bf6ad31c2bddd665
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2Alignment.cxx
@@ -0,0 +1,1405 @@
+#include "CKF2Alignment.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 "FaserActsRecMultiTrajectory.h"
+#include "TrackSelection.h"
+#include <algorithm>
+
+#include "FaserActsGeometry/FASERMagneticFieldWrapper.h"
+
+#include "Acts/Propagator/EigenStepper.hpp"
+#include "Acts/Propagator/Navigator.hpp"
+#include "Acts/Surfaces/PerigeeSurface.hpp"
+#include "Acts/Surfaces/PlaneSurface.hpp"
+#include "Acts/Surfaces/RectangleBounds.hpp"
+#include "Acts/MagneticField/MagneticFieldContext.hpp"
+#include "Acts/Propagator/Propagator.hpp"
+#include "Acts/TrackFitting/GainMatrixSmoother.hpp"
+#include "Acts/TrackFitting/GainMatrixUpdater.hpp"
+
+
+#include "Acts/EventData/Measurement.hpp"
+#include "Acts/Definitions/Units.hpp"
+#include "TFile.h"
+#include "TTree.h"
+#include "TMath.h"
+#include "TMatrixDSym.h"
+#include "TMatrixD.h"
+#include <fstream>
+#include <iostream>
+
+size_t CKF2Alignment::TrajectoryInfo::nClusters {0};
+
+using TrajectoriesContainer = std::vector<FaserActsRecMultiTrajectory>;
+
+using namespace Acts::UnitLiterals;
+
+CKF2Alignment::CKF2Alignment(
+    const std::string& name, ISvcLocator* pSvcLocator)
+  : AthAlgorithm(name, pSvcLocator), m_thistSvc("THistSvc", name) {}
+
+
+  StatusCode CKF2Alignment::initialize() {
+    ATH_CHECK(m_fieldCondObjInputKey.initialize());
+    ATH_CHECK(m_trackingGeometryTool.retrieve());
+    ATH_CHECK(m_extrapolationTool.retrieve());
+    ATH_CHECK(m_trackSeedTool.retrieve());
+    ATH_CHECK(m_kalmanFitterTool1.retrieve());
+    ATH_CHECK(m_createTrkTrackTool.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);
+    }
+    CHECK(m_thistSvc.retrieve());
+    m_tree= new TTree("trackParam","tree");
+    initializeTree();
+    CHECK(m_thistSvc->regTree("/CKF2Alignment/trackParam",m_tree));
+    m_tree->AutoSave();
+    return StatusCode::SUCCESS;
+  }
+
+
+StatusCode CKF2Alignment::execute() {
+  clearVariables();
+  const EventContext& ctx = Gaudi::Hive::currentContext();
+  m_numberOfEvents++;
+
+  ATH_MSG_DEBUG("get the tracking geometry");
+  bool save=false;
+  std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry
+    = m_trackingGeometryTool->trackingGeometry();
+
+  const FaserActsGeometryContext& faserActsGeometryContext = m_trackingGeometryTool->getGeometryContext();
+  auto gctx = faserActsGeometryContext.context();
+  Acts::MagneticFieldContext magFieldContext = getMagneticFieldContext(ctx);
+  Acts::CalibrationContext calibContext;
+  ATH_MSG_DEBUG("get the seed");
+
+  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();
+  double origin = m_trackSeedTool->targetZPosition();
+
+  ATH_MSG_DEBUG("get the output of seeding");
+  std::shared_ptr<std::vector<Measurement>> measurements = m_trackSeedTool->measurements();
+  std::shared_ptr<std::vector<const Tracker::FaserSCT_Cluster*>> clusters = m_trackSeedTool->clusters();
+  std::vector<const Tracker::FaserSCT_Cluster*> clusters_sta0;
+  clusters_sta0.clear();
+  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());
+  if(sourceLinks->size()<15||sourceLinks->size()>40)return StatusCode::SUCCESS;
+  ATH_MSG_DEBUG("size of clusters/sourcelinks "<<clusters->size()<<"/"<<sourceLinks->size());
+
+  Acts::PropagatorPlainOptions pOptions;
+  pOptions.maxSteps = m_maxSteps;
+
+  Acts::MeasurementSelector::Config measurementSelectorCfg = {
+    {Acts::GeometryIdentifier(), {m_chi2Max, m_nMax}},
+  };
+
+
+  // Set the CombinatorialKalmanFilter options
+  CKF2Alignment::TrackFinderOptions options(
+      gctx, magFieldContext, calibContext,
+      IndexSourceLinkAccessor(), MeasurementCalibrator(*measurements),
+      Acts::MeasurementSelector(measurementSelectorCfg),
+      Acts::LoggerWrapper{*m_logger}, pOptions, &(*initialSurface));
+
+  // Perform the track finding for all initial parameters
+  m_numberOfTrackSeeds += initialParameters->size();
+  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(gctx).transpose());
+    ATH_MSG_DEBUG("  momentum: " << init.momentum().transpose());
+    ATH_MSG_DEBUG("  charge:   " << init.charge());
+  }
+
+  ATH_MSG_DEBUG("sourcelink size "<<tmp.size());
+  auto results = (*m_fit)(tmp, *initialParameters, options);
+
+  // results contain 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)}})));
+    }
+  }
+  m_numberOfFittedTracks += allTrajectories.size();
+
+  // 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);
+	});
+  }
+
+
+  //only use the first track
+  int trackid=0;
+  for (const FaserActsRecMultiTrajectory &traj : selectedTrajectories) {
+    if(trackid>0)continue;
+    trackid++;
+    const auto& mj = traj.multiTrajectory();
+    const auto& trackTips = traj.tips();
+    if(trackTips.empty())continue;
+    auto& trackTip = trackTips.front();
+    auto trajState = Acts::MultiTrajectoryHelpers::trajectoryState(mj, trackTip);
+    if(trajState.nMeasurements<15)continue;
+
+    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(gctx).transpose());
+    ATH_MSG_DEBUG("  momentum: " << params.momentum().transpose());
+    ATH_MSG_DEBUG("  charge:   " << params.charge());
+    ATH_MSG_VERBOSE("checkte track");
+    std::vector<double> t_align_stationId_sp;
+    std::vector<double> t_align_centery_sp;
+    std::vector<double> t_align_layerId_sp;
+    std::vector<double> t_align_moduleId_sp;
+    std::vector<double> t_align_clustersize_sp;
+    std::vector<double> t_align_stereoId;
+    std::vector<double> t_align_global_residual_y_sp;
+    std::vector<double> t_align_global_measured_y_sp;
+    std::vector<double> t_align_global_measured_x_sp;
+    std::vector<double> t_align_global_measured_z_sp;
+    std::vector<double> t_align_global_measured_ye_sp;
+    std::vector<double> t_align_global_fitted_ye_sp;
+    std::vector<double> t_align_global_fitted_y_sp;
+    std::vector<double> t_align_global_fitted_x_sp;
+    std::vector<double> t_align_local_residual_x_sp;
+    std::vector<double> t_align_unbiased;
+    std::vector<double> t_align_local_pull_x_sp;
+    std::vector<double> t_align_local_measured_x_sp;
+    std::vector<double> t_align_local_measured_xe_sp;
+    std::vector<double> t_align_local_fitted_xe_sp;
+    std::vector<double> t_align_local_fitted_x_sp;
+    std::vector<double> t_align_derivation_x_x;
+    std::vector<double> t_align_derivation_x_y;
+    std::vector<double> t_align_derivation_x_z;
+    std::vector<double> t_align_derivation_x_rx;
+    std::vector<double> t_align_derivation_x_ry;
+    std::vector<double> t_align_derivation_x_rz;
+    std::vector<double> t_align_derivation_global_y_x;
+    std::vector<double> t_align_derivation_global_y_y;
+    std::vector<double> t_align_derivation_global_y_z;
+    std::vector<double> t_align_derivation_global_y_rx;
+    std::vector<double> t_align_derivation_global_y_ry; 
+    std::vector<double> t_align_derivation_global_y_rz;
+    bool foundift=false;
+    std::unique_ptr<const Acts::BoundTrackParameters> ini_Param=nullptr;
+    //get residual from ACTS
+    if(m_biased){
+      mj.visitBackwards(trackTip, [&](const auto &state) {
+	  /// Only fill the track states with non-outlier measurement
+	  auto typeFlags = state.typeFlags();
+	  if (not typeFlags.test(Acts::TrackStateFlag::MeasurementFlag) and not typeFlags.test(Acts::TrackStateFlag::OutlierFlag))
+	  {
+	  return true;
+	  }
+
+	  const auto& surface = state.referenceSurface();
+	  Acts::BoundVector meas = state.projector().transpose() * state.calibrated();
+	  Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]);
+	  const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(meas[Acts::eBoundPhi], meas[Acts::eBoundTheta]);
+	  Acts::Vector3 mom(1, 1, 1);
+	  Acts::Vector3 global = surface.localToGlobal(gctx, local, dir);
+	  if (state.hasSmoothed())
+	  {
+	  Acts::BoundTrackParameters parameter(
+	      state.referenceSurface().getSharedPtr(),
+	      state.smoothed(),
+	      state.smoothedCovariance());
+	  auto covariance = state.smoothedCovariance();
+
+	  /// Local hit residual info
+	  auto H = state.effectiveProjector();
+	  auto resCov = state.effectiveCalibratedCovariance() +
+	    H * covariance * H.transpose();
+	  auto residual = state.effectiveCalibrated() - H * state.smoothed();
+
+	  if (state.hasUncalibrated()) {
+	    const Tracker::FaserSCT_Cluster* cluster = state.uncalibrated().hit();
+	    auto trans2 = cluster->detectorElement()->surface().transform();
+	    auto trans1 = trans2;
+	    Identifier id = cluster->identify();
+	    int istation = m_idHelper->station(id);
+	    int ilayer = m_idHelper->layer(id);
+	    int stereoid = m_idHelper->side(id);
+	    if(stereoid==1){
+	      trans1=cluster->detectorElement()->otherSide()->surface().transform();
+	    }
+	    ATH_MSG_DEBUG("  save the residual "<<residual(Acts::eBoundLoc0));
+	    const auto iModuleEta = m_idHelper->eta_module(id);
+	    const auto iModulePhi = m_idHelper->phi_module(id);
+	    int iModule = iModulePhi;
+	    if (iModuleEta < 0) iModule +=4;
+	    ATH_MSG_DEBUG("ID "<<istation<<"/"<<ilayer<<"/"<<iModule<<"/"<<stereoid<<"/"<<ilayer);
+	    t_align_stationId_sp.push_back(istation);
+	    t_align_centery_sp.push_back(cluster->detectorElement()->center().y());
+	    t_align_layerId_sp.push_back(ilayer);
+	    t_align_moduleId_sp.push_back(iModule);
+	    t_align_clustersize_sp.push_back(cluster->rdoList().size());
+	    t_align_stereoId.push_back(stereoid);
+	    t_align_global_measured_x_sp.push_back(cluster->globalPosition().x());
+	    t_align_global_measured_y_sp.push_back(cluster->globalPosition().y());
+	    t_align_global_measured_z_sp.push_back(cluster->globalPosition().z());
+	    t_align_global_fitted_x_sp.push_back(global.x());
+	    t_align_global_fitted_y_sp.push_back(global.y());
+	    t_align_local_residual_x_sp.push_back(residual(Acts::eBoundLoc0));
+	    t_align_unbiased.push_back(0);
+	    t_align_local_pull_x_sp.push_back(residual(Acts::eBoundLoc0)/sqrt(resCov(Acts::eBoundLoc0, Acts::eBoundLoc0)));
+	    t_align_local_measured_x_sp.push_back(cluster->localPosition().x());
+	    t_align_local_measured_xe_sp.push_back(sqrt(cluster->localCovariance()(0,0)));
+	    t_align_local_fitted_xe_sp.push_back(sqrt(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0)));
+	    t_align_local_fitted_x_sp.push_back(meas[Acts::eBoundLoc0]);
+	    save=true;
+	    Amg::Vector2D local_mea=cluster->localPosition() ; 
+	    t_align_derivation_x_x.push_back(getDerivation(ctx, parameter, trans1,local_mea, 0, stereoid, trans2, 0));
+	    t_align_derivation_x_y.push_back(getDerivation(ctx, parameter, trans1,local_mea, 1, stereoid, trans2, 0));
+	    t_align_derivation_x_z.push_back(getDerivation(ctx, parameter, trans1,local_mea, 2, stereoid, trans2, 0));
+	    t_align_derivation_x_rx.push_back(getDerivation(ctx, parameter, trans1,local_mea, 3, stereoid, trans2, 0));
+	    t_align_derivation_x_ry.push_back(getDerivation(ctx, parameter, trans1,local_mea, 4, stereoid, trans2, 0));
+	    t_align_derivation_x_rz.push_back(getDerivation(ctx, parameter, trans1,local_mea, 5, stereoid, trans2, 0));
+	    t_align_derivation_global_y_x.push_back(getDerivation(ctx, parameter, trans1,local_mea, 0, stereoid, trans2, 1));
+	    t_align_derivation_global_y_y.push_back(getDerivation(ctx, parameter, trans1,local_mea, 1, stereoid, trans2, 1));
+	    t_align_derivation_global_y_z.push_back(getDerivation(ctx, parameter, trans1,local_mea, 2, stereoid, trans2, 1));
+	    t_align_derivation_global_y_rx.push_back(getDerivation(ctx, parameter, trans1,local_mea, 3, stereoid, trans2, 1));
+	    t_align_derivation_global_y_ry.push_back(getDerivation(ctx, parameter, trans1,local_mea, 4, stereoid, trans2, 1));
+	    t_align_derivation_global_y_rz.push_back(getDerivation(ctx, parameter, trans1,local_mea, 5, stereoid, trans2, 1));
+	    ATH_MSG_VERBOSE("local derivation "<<t_align_derivation_x_x.back()<<" "<<t_align_derivation_x_y.back()<<" "<<t_align_derivation_x_z.back()<<" "<<t_align_derivation_x_rx.back()<<" "<<t_align_derivation_x_ry.back()<<" "<<t_align_derivation_x_rz.back());
+	    ATH_MSG_VERBOSE("global derivation "<<t_align_derivation_global_y_x.back()<<" "<<t_align_derivation_global_y_y.back()<<" "<<t_align_derivation_global_y_z.back()<<""<<t_align_derivation_global_y_rx.back()<<" "<<t_align_derivation_global_y_ry.back()<<" "<<t_align_derivation_global_y_rz.back());
+	    //get the residual for IFT
+	    if(istation==1&&ilayer==0&&!foundift){
+	      Amg::Transform3D ini_trans = Amg::Translation3D(0,0, -1910.) * Amg::RotationMatrix3D::Identity();
+	      auto ini_surface = Acts::Surface::makeShared<Acts::PlaneSurface>(ini_trans, std::make_shared<const Acts::RectangleBounds>(1000.,1000.));
+	      ini_Param = m_extrapolationTool->propagate( ctx, parameter, *ini_surface, Acts::backward);
+	      //std::unique_ptr<const Acts::BoundTrackParameters> ini_Param = m_extrapolationTool->propagate( ctx, parameter, *ini_surface, Acts::backward);
+	      //find the closet cluster
+	      if(ini_Param!=nullptr){
+		for(int i=0;i<3;i++){
+		  for(int st=0;st<2;st++){
+		    double chisq=999.;
+		    size_t iclus=999;
+		    double fitx=-999.;
+		    double fity=-999.;
+		    double gfitx=-999.;
+		    double gfity=-999.;
+		    double resi=-999.;
+		    for(size_t ic =0 ;ic <clusters->size();ic++){
+		      auto cluster = clusters->at(ic);
+		      Identifier id = cluster->identify();
+		      int jstation = m_idHelper->station(id);
+		      int jlayer = m_idHelper->layer(id);
+		      if(jstation!=0||jlayer!=i)continue;
+		      int jstereoid = m_idHelper->side(id);
+		      if(st==0){if(jstereoid==1)continue;}
+		      if(st==1){if(jstereoid!=1)continue;}
+		      auto trans2 = cluster->detectorElement()->surface().transform();
+		      Amg::Transform3D shift_trans = Amg::Translation3D(0,0, cluster->globalPosition().z()) * Amg::RotationMatrix3D::Identity();
+		      auto shift_surface = Acts::Surface::makeShared<Acts::PlaneSurface>(shift_trans, std::make_shared<const Acts::RectangleBounds>(1000.,1000.));
+		      auto shift_Param = m_extrapolationTool->propagate( ctx, *ini_Param, *shift_surface);
+		      if(shift_Param!=nullptr){
+			auto shift_parameter = shift_Param->parameters();
+			Amg::Vector2D local_m(shift_parameter[Acts::eBoundLoc0],shift_parameter[Acts::eBoundLoc1]);
+			Amg::Vector3D glopos(local_m.x(),local_m.y(),cluster->globalPosition().z());
+			auto localpos=trans2.inverse()*glopos;
+			ATH_MSG_DEBUG("looping cluster "<<local_m.x()<<" "<<local_m.y()<<" : "<<cluster->globalPosition());
+			ATH_MSG_DEBUG("local   cluster "<<localpos.x()<<" "<<localpos.y()<<" : "<<cluster->localPosition());
+			double dist2 =(glopos.x()-cluster->globalPosition().x())*(glopos.x()-cluster->globalPosition().x())/40./40.+(glopos.y()-cluster->globalPosition().y())*(glopos.y()-cluster->globalPosition().y());
+			if(dist2<chisq){
+			  chisq=dist2;
+			  iclus=ic;
+			  fitx=localpos.x();
+			  fity=localpos.y();
+			  gfitx=glopos.x();
+			  gfity=glopos.y();
+			  resi=cluster->localPosition().x() - localpos.x();
+			}
+		      }
+		    }
+		    if(iclus>200)continue;
+		    clusters_sta0.push_back(clusters->at(iclus));
+		    foundift=true;
+		    ATH_MSG_DEBUG(" local position "<<fitx<<" "<<fity<<" : "<<clusters->at(iclus)->localPosition());
+		    ATH_MSG_DEBUG(" global position "<<gfitx<<" "<<gfity<<" : "<<clusters->at(iclus)->globalPosition());
+		    Amg::Vector3D localresi(clusters->at(iclus)->localPosition().x()-fitx,clusters->at(iclus)->localPosition().y()-fity,0.);
+		    auto gloresi=clusters->at(iclus)->detectorElement()->surface().transform()*localresi;
+		    ATH_MSG_DEBUG(" local/global residual "<<localresi.x()<<" "<<localresi.y()<<" : "<<gloresi.x()<<" "<<gloresi.y()<<" "<<gloresi.z());
+
+		    Identifier id = clusters->at(iclus)->identify();
+		    int istation = m_idHelper->station(id);
+		    int ilayer = m_idHelper->layer(id);
+		    if(istation!=0||ilayer!=i)continue;
+		    int stereoid = m_idHelper->side(id);
+		    auto trans2 = clusters->at(iclus)->detectorElement()->surface().transform();
+		    auto trans1 = trans2;
+		    if(stereoid==1){
+		      trans1=clusters->at(iclus)->detectorElement()->otherSide()->surface().transform();
+		    }
+		    ATH_MSG_DEBUG("  save the residual "<<resi);
+		    const auto iModuleEta = m_idHelper->eta_module(id);
+		    const auto iModulePhi = m_idHelper->phi_module(id);
+		    int iModule = iModulePhi;
+		    if (iModuleEta < 0) iModule +=4;
+		    ATH_MSG_DEBUG("ID "<<istation<<"/"<<ilayer<<"/"<<iModule<<"/"<<stereoid<<"/"<<ilayer);
+		    t_align_stationId_sp.push_back(istation);
+		    t_align_centery_sp.push_back(clusters->at(iclus)->detectorElement()->center().y());
+		    t_align_layerId_sp.push_back(ilayer);
+		    t_align_moduleId_sp.push_back(iModule);
+		    t_align_clustersize_sp.push_back(clusters->at(iclus)->rdoList().size());
+		    t_align_stereoId.push_back(stereoid);
+		    t_align_global_measured_x_sp.push_back(clusters->at(iclus)->globalPosition().x());
+		    t_align_global_measured_y_sp.push_back(clusters->at(iclus)->globalPosition().y());
+		    t_align_global_measured_z_sp.push_back(clusters->at(iclus)->globalPosition().z());
+		    t_align_global_fitted_x_sp.push_back(gfitx);
+		    t_align_global_fitted_y_sp.push_back(gfity);
+		    t_align_local_residual_x_sp.push_back(resi);
+		    t_align_unbiased.push_back(2);
+		    t_align_local_pull_x_sp.push_back(resi/sqrt(clusters->at(iclus)->localCovariance()(0,0)));
+		    t_align_local_measured_x_sp.push_back(clusters->at(iclus)->localPosition().x());
+		    t_align_local_measured_xe_sp.push_back(sqrt(cluster->localCovariance()(0,0)));
+		    t_align_local_fitted_xe_sp.push_back(sqrt(cluster->localCovariance()(0,0)));
+		    t_align_local_fitted_x_sp.push_back(fitx);
+		    Amg::Vector2D local_mea=clusters->at(iclus)->localPosition() ; 
+		    t_align_derivation_x_x.push_back(getDerivation(ctx, parameter, trans1,local_mea, 0, stereoid, trans2, 0));
+		    t_align_derivation_x_y.push_back(getDerivation(ctx, parameter, trans1,local_mea, 1, stereoid, trans2, 0));
+		    t_align_derivation_x_z.push_back(getDerivation(ctx, parameter, trans1,local_mea, 2, stereoid, trans2, 0));
+		    t_align_derivation_x_rx.push_back(getDerivation(ctx, parameter, trans1,local_mea, 3, stereoid, trans2, 0));
+		    t_align_derivation_x_ry.push_back(getDerivation(ctx, parameter, trans1,local_mea, 4, stereoid, trans2, 0));
+		    t_align_derivation_x_rz.push_back(getDerivation(ctx, parameter, trans1,local_mea, 5, stereoid, trans2, 0));
+		    t_align_derivation_global_y_x.push_back(getDerivation(ctx, parameter, trans1,local_mea, 0, stereoid, trans2, 1));
+		    t_align_derivation_global_y_y.push_back(getDerivation(ctx, parameter, trans1,local_mea, 1, stereoid, trans2, 1));
+		    t_align_derivation_global_y_z.push_back(getDerivation(ctx, parameter, trans1,local_mea, 2, stereoid, trans2, 1));
+		    t_align_derivation_global_y_rx.push_back(getDerivation(ctx, parameter, trans1,local_mea, 3, stereoid, trans2, 1));
+		    t_align_derivation_global_y_ry.push_back(getDerivation(ctx, parameter, trans1,local_mea, 4, stereoid, trans2, 1));
+		    t_align_derivation_global_y_rz.push_back(getDerivation(ctx, parameter, trans1,local_mea, 5, stereoid, trans2, 1));
+		    ATH_MSG_VERBOSE("local derivation "<<t_align_derivation_x_x.back()<<" "<<t_align_derivation_x_y.back()<<" "<<t_align_derivation_x_z.back()<<" "<<t_align_derivation_x_rx.back()<<" "<<t_align_derivation_x_ry.back()<<" "<<t_align_derivation_x_rz.back());
+		    ATH_MSG_VERBOSE("global derivation "<<t_align_derivation_global_y_x.back()<<" "<<t_align_derivation_global_y_y.back()<<" "<<t_align_derivation_global_y_z.back()<<""<<t_align_derivation_global_y_rx.back()<<" "<<t_align_derivation_global_y_ry.back()<<" "<<t_align_derivation_global_y_rz.back());
+		  }
+		}
+	      }
+	    }
+	  }
+	  }
+	  return true;
+      });
+      ATH_MSG_VERBOSE("check track");
+
+      std::unique_ptr<Trk::Track> track = m_createTrkTrackTool->createTrack(gctx, traj);
+      if (track==nullptr||ini_Param==nullptr) continue;
+      origin = -1910.;
+      std::vector<TSOS4Residual> unbiase_resi= m_kalmanFitterTool1->getUnbiasedResidual(ctx, gctx, track.get(), Acts::BoundVector::Zero(), m_isMC, origin,clusters_sta0, *ini_Param);
+      ATH_MSG_DEBUG(" found tsos size "<<unbiase_resi.size());
+      if(unbiase_resi.size()>0){
+
+	ATH_MSG_DEBUG(" check the tsos");
+	for (auto& tsos : unbiase_resi){
+	  ATH_MSG_DEBUG(" check the param");
+	  auto cluster = tsos.cluster;
+	  ATH_MSG_DEBUG("Positions "<<tsos.fit_global_x<<" "<<tsos.fit_global_y<<" "<<tsos.fit_global_z<<" , "<<cluster->globalPosition().x()<<" "<<cluster->globalPosition().y()<<" "<<cluster->globalPosition().z());
+	  ATH_MSG_DEBUG("Found the ctsos ");
+	  double localx =  tsos.fit_local_x;
+	  double localy =  tsos.fit_local_y;
+	  double globalx= tsos.fit_global_x;
+	  double globaly= tsos.fit_global_y;
+	  double globalz= tsos.fit_global_z;
+	  //transfer to cluster surface
+	  Amg::Vector3D glo_pos(globalx,globaly,globalz);
+	  std::optional<Amg::Vector2D> loc_pos  = cluster->detectorElement()->surface().globalToLocal(glo_pos);
+
+	  ATH_MSG_DEBUG("local pos "<<localx<<" "<<localy<<" ,  "<<loc_pos->x()<<" "<<loc_pos->y()<<" :vs "<<cluster->localPosition().x()<<" "<<cluster->localPosition().y());
+	  localx = loc_pos->x();
+	  localy = loc_pos->y();
+	  ATH_MSG_DEBUG("global pos "<<globalx<<" "<<globaly<<" vs "<<cluster->globalPosition().x()<<" "<<cluster->globalPosition().y());
+	  //	  outputTracks->push_back(std::move(newtrack));
+	  ATH_MSG_DEBUG("Global pos "<<globalx<<" , "<<globaly);
+	  auto trans2 = cluster->detectorElement()->surface().transform();
+	  auto trans1 = trans2;
+	  Identifier id = cluster->identify();
+	  int istation = m_idHelper->station(id);
+	  int ilayer = m_idHelper->layer(id);
+	  if(istation!=0)continue;
+	  //int layerid = istation*3 + ilayer;
+	  //	  if(layerid == 0 || layerid == 11)continue;
+	  int stereoid = m_idHelper->side(id);
+	  if(stereoid==1){
+	    trans1=cluster->detectorElement()->otherSide()->surface().transform();
+	  }
+	  Acts::BoundTrackParameters fitParameter=tsos.parameter;
+	  const auto iModuleEta = m_idHelper->eta_module(id);
+	  const auto iModulePhi = m_idHelper->phi_module(id);
+	  int iModule = iModulePhi;
+	  if (iModuleEta < 0) iModule +=4;
+	  ATH_MSG_DEBUG("ID "<<istation<<"/"<<ilayer<<"/"<<iModule<<"/"<<stereoid<<"/"<<ilayer);
+	  t_align_stationId_sp.push_back(istation);
+	  t_align_centery_sp.push_back(cluster->detectorElement()->center().y());
+	  t_align_layerId_sp.push_back(ilayer);
+	  t_align_moduleId_sp.push_back(iModule);
+	  t_align_clustersize_sp.push_back(cluster->rdoList().size());
+	  t_align_stereoId.push_back(stereoid);
+	  Amg::Vector2D local_mea=cluster->localPosition() ; 
+	  Amg::Vector2D local_meae=cluster->localPosition() + Amg::Vector2D(sqrt(cluster->localCovariance()(0,0)),0);
+	  Amg::Vector2D local_fit(localx, localy);
+	  Amg::Vector2D local_fite(localx+0.0001, localy+0.0001);
+	  ATH_MSG_DEBUG("  save the residual "<<local_mea.x()-local_fit.x()<<" vs "<<tsos.residual);
+	  t_align_local_residual_x_sp.push_back(tsos.residual);
+	  t_align_unbiased.push_back(1);
+	  t_align_local_pull_x_sp.push_back((local_mea.x()-local_fit.x())/(sqrt(((cluster->localCovariance()(0,0)+(local_fite.x()-local_fit.x())*(local_fite.x()-local_fit.x()))))));
+	  t_align_local_measured_x_sp.push_back(local_mea.x());
+	  t_align_local_measured_xe_sp.push_back(fabs(local_meae.x()-local_mea.x()));
+	  t_align_local_fitted_xe_sp.push_back(fabs(local_fit.x()-local_fite.x()));
+	  t_align_local_fitted_x_sp.push_back(local_fit.x());
+
+	  Amg::Vector3D global_fit= cluster->detectorElement()->surface().localToGlobal(local_fit);
+	  Amg::Vector3D global_fite= cluster->detectorElement()->surface().localToGlobal( local_fite);
+	  Amg::Vector3D global_mea= cluster->detectorElement()->surface().localToGlobal( local_mea);
+	  Amg::Vector3D global_meae= cluster->detectorElement()->surface().localToGlobal( local_meae);
+	  t_align_global_residual_y_sp.push_back(global_mea.y()-global_fit.y());
+	  t_align_global_measured_x_sp.push_back(global_mea.x());
+	  t_align_global_measured_y_sp.push_back(global_mea.y());
+	  t_align_global_measured_z_sp.push_back(global_mea.z());
+	  t_align_global_measured_ye_sp.push_back(fabs(global_mea.y()-global_meae.y()));
+	  t_align_global_fitted_ye_sp.push_back(fabs(global_fite.y()-global_fite.y()));
+	  t_align_global_fitted_x_sp.push_back(global_fit.x());
+	  t_align_global_fitted_y_sp.push_back(global_fit.y());
+	  t_align_derivation_x_x.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 0, stereoid, trans2, 0));
+	  t_align_derivation_x_y.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 1, stereoid, trans2, 0));
+	  t_align_derivation_x_z.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 2, stereoid, trans2, 0));
+	  t_align_derivation_x_rx.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 3, stereoid, trans2, 0));
+	  t_align_derivation_x_ry.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 4, stereoid, trans2, 0));
+	  t_align_derivation_x_rz.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 5, stereoid, trans2, 0));
+	  t_align_derivation_global_y_x.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 0, stereoid, trans2, 1));
+	  t_align_derivation_global_y_y.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 1, stereoid, trans2, 1));
+	  t_align_derivation_global_y_z.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 2, stereoid, trans2, 1));
+	  t_align_derivation_global_y_rx.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 3, stereoid, trans2, 1));
+	  t_align_derivation_global_y_ry.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 4, stereoid, trans2, 1));
+	  t_align_derivation_global_y_rz.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 5, stereoid, trans2, 1));
+	  ATH_MSG_VERBOSE("local derivation "<<t_align_derivation_x_x.back()<<" "<<t_align_derivation_x_y.back()<<" "<<t_align_derivation_x_z.back()<<" "<<t_align_derivation_x_rx.back()<<" "<<t_align_derivation_x_ry.back()<<" "<<t_align_derivation_x_rz.back());
+	  ATH_MSG_VERBOSE("global derivation "<<t_align_derivation_global_y_x.back()<<" "<<t_align_derivation_global_y_y.back()<<" "<<t_align_derivation_global_y_z.back()<<""<<t_align_derivation_global_y_rx.back()<<" "<<t_align_derivation_global_y_ry.back()<<" "<<t_align_derivation_global_y_rz.back());
+	}
+      }
+    }
+    else{
+      std::unique_ptr<Trk::Track> track = m_createTrkTrackTool->createTrack(gctx, traj);
+      if (track!=nullptr) {
+	for (const Trk::MeasurementBase *meas : *track->measurementsOnTrack()) {
+	  const auto* clusterOnTrack = dynamic_cast<const Tracker::FaserSCT_ClusterOnTrack*>(meas);
+	  if (clusterOnTrack) {
+	    const Tracker::FaserSCT_Cluster* cluster = clusterOnTrack->prepRawData();
+	    ATH_MSG_DEBUG("  Found the cluster to be remove "<<cluster->globalPosition());
+	    //remove the cluster and re-fit to get unbiased residual
+	    Identifier id = clusterOnTrack->identify();
+	    Identifier waferId = m_idHelper->wafer_id(id);
+	    ATH_MSG_DEBUG("like cluster ID "<<m_idHelper->layer(id)<<" "<<m_idHelper->station(id));
+	    double localx(-999);
+	    double localxe(999);
+	    double localy(-999);
+	    double localye(999);
+	    double globalx(-999);
+	    double globaly(999);
+	    double globalz(999);
+//	    int charge =0;
+//	    Acts::BoundSymMatrix cov = Acts::BoundSymMatrix::Identity();
+	    ATH_MSG_DEBUG("  make unbiased residual");
+	    m_numberOfSelectedTracks++;
+	    if((*track->measurementsOnTrack()).size()<15)continue;
+	    //remove the cluster and re-fit to get unbiased residual
+	    std::vector<TSOS4Residual> unbiase_resi= m_kalmanFitterTool1->getUnbiasedResidual(ctx, gctx, track.get(), cluster->globalPosition().z(), Acts::BoundVector::Zero(), m_isMC, origin);
+	    if(unbiase_resi.size()>0){
+
+	      ATH_MSG_DEBUG(" check the tsos");
+	      for (auto& tsos : unbiase_resi){
+		ATH_MSG_DEBUG(" check the param");
+		if(tsos.cluster->identify()!=cluster->identify())continue;
+		ATH_MSG_DEBUG("Positions "<<tsos.fit_global_x<<" "<<tsos.fit_global_y<<" "<<tsos.fit_global_z<<" , "<<cluster->globalPosition().x()<<" "<<cluster->globalPosition().y()<<" "<<cluster->globalPosition().z());
+		ATH_MSG_DEBUG("Found the ctsos ");
+		localx =  tsos.fit_local_x;
+		localy =  tsos.fit_local_y;
+		globalx= tsos.fit_global_x;
+		globaly= tsos.fit_global_y;
+		globalz= tsos.fit_global_z;
+		//transfer to cluster surface
+		Amg::Vector3D glo_pos(globalx,globaly,globalz);
+		std::optional<Amg::Vector2D> loc_pos  = cluster->detectorElement()->surface().globalToLocal(glo_pos);
+
+		ATH_MSG_DEBUG("local pos "<<localx<<" "<<localy<<" ,  "<<loc_pos->x()<<" "<<loc_pos->y()<<" :vs "<<cluster->localPosition().x()<<" "<<cluster->localPosition().y());
+		localx = loc_pos->x();
+		localy = loc_pos->y();
+		ATH_MSG_DEBUG("global pos "<<globalx<<" "<<globaly<<" vs "<<cluster->globalPosition().x()<<" "<<cluster->globalPosition().y());
+		save=true;
+		ATH_MSG_DEBUG("Global pos "<<globalx<<" , "<<globaly);
+		auto trans2 = cluster->detectorElement()->surface().transform();
+		auto trans1 = trans2;
+		Identifier id = cluster->identify();
+		int istation = m_idHelper->station(id);
+		int ilayer = m_idHelper->layer(id);
+		int stereoid = m_idHelper->side(id);
+		if(stereoid==1){
+		  trans1=cluster->detectorElement()->otherSide()->surface().transform();
+		}
+		Acts::BoundTrackParameters fitParameter=tsos.parameter;
+		const auto iModuleEta = m_idHelper->eta_module(id);
+		const auto iModulePhi = m_idHelper->phi_module(id);
+		int iModule = iModulePhi;
+		if (iModuleEta < 0) iModule +=4;
+		ATH_MSG_DEBUG("ID "<<istation<<"/"<<ilayer<<"/"<<iModule<<"/"<<stereoid<<"/"<<ilayer);
+		t_align_centery_sp.push_back(cluster->detectorElement()->center().y());
+		t_align_stationId_sp.push_back(istation);
+		t_align_layerId_sp.push_back(ilayer);
+		t_align_moduleId_sp.push_back(iModule);
+		t_align_clustersize_sp.push_back(cluster->rdoList().size());
+		t_align_stereoId.push_back(stereoid);
+		Amg::Vector2D local_mea=cluster->localPosition() ; 
+		Amg::Vector2D local_meae=cluster->localPosition() + Amg::Vector2D(sqrt(cluster->localCovariance()(0,0)),0);
+		Amg::Vector2D local_fit(localx, localy);
+		Amg::Vector2D local_fite(localx+localxe, localy+localye);
+		ATH_MSG_DEBUG("  save the residual "<<local_mea.x()-local_fit.x()<<" vs "<<tsos.residual);
+		t_align_local_residual_x_sp.push_back(tsos.residual);
+		t_align_unbiased.push_back(3);
+		t_align_local_pull_x_sp.push_back((local_mea.x()-local_fit.x())/(sqrt(((cluster->localCovariance()(0,0)+(local_fite.x()-local_fit.x())*(local_fite.x()-local_fit.x()))))));
+		t_align_local_measured_x_sp.push_back(local_mea.x());
+		t_align_local_measured_xe_sp.push_back(fabs(local_meae.x()-local_mea.x()));
+		t_align_local_fitted_xe_sp.push_back(fabs(local_fit.x()-local_fite.x()));
+		t_align_local_fitted_x_sp.push_back(local_fit.x());
+
+		Amg::Vector3D global_fit= cluster->detectorElement()->surface().localToGlobal(local_fit);
+		Amg::Vector3D global_fite= cluster->detectorElement()->surface().localToGlobal( local_fite);
+		Amg::Vector3D global_mea= cluster->detectorElement()->surface().localToGlobal( local_mea);
+		Amg::Vector3D global_meae= cluster->detectorElement()->surface().localToGlobal( local_meae);
+		t_align_global_residual_y_sp.push_back(global_mea.y()-global_fit.y());
+		t_align_global_measured_x_sp.push_back(global_mea.x());
+		t_align_global_measured_y_sp.push_back(global_mea.y());
+		t_align_global_measured_z_sp.push_back(global_mea.z());
+		t_align_global_measured_ye_sp.push_back(fabs(global_mea.y()-global_meae.y()));
+		t_align_global_fitted_ye_sp.push_back(fabs(global_fite.y()-global_fite.y()));
+		t_align_global_fitted_x_sp.push_back(global_fit.x());
+		t_align_global_fitted_y_sp.push_back(global_fit.y());
+		t_align_derivation_x_x.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 0, stereoid, trans2, 0));
+		t_align_derivation_x_y.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 1, stereoid, trans2, 0));
+		t_align_derivation_x_z.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 2, stereoid, trans2, 0));
+		t_align_derivation_x_rx.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 3, stereoid, trans2, 0));
+		t_align_derivation_x_ry.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 4, stereoid, trans2, 0));
+		t_align_derivation_x_rz.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 5, stereoid, trans2, 0));
+		t_align_derivation_global_y_x.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 0, stereoid, trans2, 1));
+		t_align_derivation_global_y_y.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 1, stereoid, trans2, 1));
+		t_align_derivation_global_y_z.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 2, stereoid, trans2, 1));
+		t_align_derivation_global_y_rx.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 3, stereoid, trans2, 1));
+		t_align_derivation_global_y_ry.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 4, stereoid, trans2, 1));
+		t_align_derivation_global_y_rz.push_back(getDerivation(ctx, fitParameter, trans1,local_mea, 5, stereoid, trans2, 1));
+		ATH_MSG_VERBOSE("local derivation "<<t_align_derivation_x_x.back()<<" "<<t_align_derivation_x_y.back()<<" "<<t_align_derivation_x_z.back()<<" "<<t_align_derivation_x_rx.back()<<" "<<t_align_derivation_x_ry.back()<<" "<<t_align_derivation_x_rz.back());
+		ATH_MSG_VERBOSE("global derivation "<<t_align_derivation_global_y_x.back()<<" "<<t_align_derivation_global_y_y.back()<<" "<<t_align_derivation_global_y_z.back()<<""<<t_align_derivation_global_y_rx.back()<<" "<<t_align_derivation_global_y_ry.back()<<" "<<t_align_derivation_global_y_rz.back());
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    ATH_MSG_VERBOSE("finish getting residuals");
+    if(save){
+      ATH_MSG_VERBOSE("save the results");
+      m_fitParam_nMeasurements.push_back(trajState.nMeasurements);
+      m_fitParam_nStates.push_back(trajState.nStates);
+      m_fitParam_nOutliers.push_back(trajState.nOutliers);
+      m_fitParam_nHoles.push_back(trajState.nHoles);
+      m_fitParam_chi2.push_back(trajState.chi2Sum);
+      m_fitParam_ndf.push_back(trajState.NDF);
+      m_fitParam_x.push_back(params.position(gctx).transpose().x());
+      m_fitParam_y.push_back(params.position(gctx).transpose().y());
+      m_fitParam_z.push_back(params.position(gctx).transpose().z());
+      m_fitParam_charge.push_back(params.charge());
+      m_fitParam_px.push_back(params.momentum().transpose().x());
+      m_fitParam_py.push_back(params.momentum().transpose().y());
+      m_fitParam_pz.push_back(params.momentum().transpose().z());
+      m_align_stationId_sp.push_back(t_align_stationId_sp);
+      m_align_centery_sp.push_back(t_align_centery_sp);
+      m_align_layerId_sp.push_back(t_align_layerId_sp);
+      m_align_moduleId_sp.push_back(t_align_moduleId_sp); 
+      m_align_clustersize_sp.push_back(t_align_clustersize_sp); 
+      m_align_stereoId.push_back(t_align_stereoId);
+      m_align_global_residual_y_sp.push_back(t_align_global_residual_y_sp);
+      m_align_global_measured_x_sp.push_back(t_align_global_measured_x_sp);
+      m_align_global_measured_y_sp.push_back(t_align_global_measured_y_sp);
+      m_align_global_measured_z_sp.push_back(t_align_global_measured_z_sp);
+      m_align_global_measured_ye_sp.push_back(t_align_global_measured_ye_sp);
+      m_align_global_fitted_ye_sp.push_back(t_align_global_fitted_ye_sp);
+      m_align_global_fitted_x_sp.push_back(t_align_global_fitted_x_sp);
+      m_align_global_fitted_y_sp.push_back(t_align_global_fitted_y_sp);
+      m_align_local_residual_x_sp.push_back(t_align_local_residual_x_sp);
+      m_align_unbiased_sp.push_back(t_align_unbiased);
+      m_align_local_pull_x_sp.push_back(t_align_local_pull_x_sp);
+      m_align_local_measured_x_sp.push_back(t_align_local_measured_x_sp);
+      m_align_local_measured_xe_sp.push_back(t_align_local_measured_xe_sp);
+      m_align_local_fitted_xe_sp.push_back(t_align_local_fitted_xe_sp);
+      m_align_local_fitted_x_sp.push_back(t_align_local_fitted_x_sp);
+      m_align_derivation_x_x.push_back(t_align_derivation_x_x);
+      m_align_derivation_x_y.push_back(t_align_derivation_x_y);
+      m_align_derivation_x_z.push_back(t_align_derivation_x_z);
+      m_align_derivation_x_rx.push_back(t_align_derivation_x_rx);
+      m_align_derivation_x_ry.push_back(t_align_derivation_x_ry);
+      m_align_derivation_x_rz.push_back(t_align_derivation_x_rz);
+      m_align_derivation_global_y_x.push_back(t_align_derivation_global_y_x);
+      m_align_derivation_global_y_y.push_back(t_align_derivation_global_y_y);
+      m_align_derivation_global_y_z.push_back(t_align_derivation_global_y_z);
+      m_align_derivation_global_y_rx.push_back(t_align_derivation_global_y_rx);
+      m_align_derivation_global_y_ry.push_back(t_align_derivation_global_y_ry);
+      m_align_derivation_global_y_rz.push_back(t_align_derivation_global_y_rz);
+    }
+  }
+
+  if(save)
+    m_tree->Fill();
+
+  return StatusCode::SUCCESS;
+}
+
+
+StatusCode CKF2Alignment::finalize() {
+  ATH_MSG_INFO("CombinatorialKalmanFilterAlg::finalize()");
+  ATH_MSG_INFO(m_numberOfEvents << " events processed.");
+  ATH_MSG_INFO(m_numberOfTrackSeeds << " seeds.");
+  ATH_MSG_INFO(m_numberOfFittedTracks << " fitted tracks.");
+  ATH_MSG_INFO(m_numberOfSelectedTracks << " selected and re-fitted tracks.");
+  //nominal geometry
+  double nominaly[4][3][8]={0.};
+  double sigma=0.064;
+  nominaly[1][0][4]= -95.61;
+  nominaly[1][0][0]=-95.61;
+  nominaly[1][0][5]= -31.87;
+  nominaly[1][0][1]=-31.87;
+  nominaly[1][0][6]= 31.873;
+  nominaly[1][0][2]=31.877;
+  nominaly[1][0][7]= 95.61;
+  nominaly[1][0][3]=95.61;
+  nominaly[1][1][4]= -100.61;
+  nominaly[1][1][0]=-100.61;
+  nominaly[1][1][5]= -36.87;
+  nominaly[1][1][1]=-36.87;
+  nominaly[1][1][6]= 26.87;
+  nominaly[1][1][2]=26.87;
+  nominaly[1][1][7]= 90.61;
+  nominaly[1][1][3]=90.61;
+  nominaly[1][2][4]= -90.61;
+  nominaly[1][2][0]=-90.61;
+  nominaly[1][2][5]= -26.87;
+  nominaly[1][2][1]=-26.87;
+  nominaly[1][2][6]= 36.87;
+  nominaly[1][2][2]=36.87;
+  nominaly[1][2][7]= 100.61;
+  nominaly[1][2][3]=100.61;
+  nominaly[2][0][4]= -95.61;
+  nominaly[2][0][0]=-95.61;
+  nominaly[2][0][5]= -31.87;
+  nominaly[2][0][1]=-31.87;
+  nominaly[2][0][6]= 31.87;
+  nominaly[2][0][2]=31.87;
+  nominaly[2][0][7]= 95.61;
+  nominaly[2][0][3]=95.61;
+  nominaly[2][1][4]= -100.61;
+  nominaly[2][1][0]=-100.61;
+  nominaly[2][1][5]= -36.87;
+  nominaly[2][1][1]=-36.87;
+  nominaly[2][1][6]= 26.87;
+  nominaly[2][1][2]=26.87;
+  nominaly[2][1][7]= 90.61;
+  nominaly[2][1][3]=90.61;
+  nominaly[2][2][4]= -90.61;
+  nominaly[2][2][0]=-90.61;
+  nominaly[2][2][5]= -26.87;
+  nominaly[2][2][1]=-26.87;
+  nominaly[2][2][6]= 36.87;
+  nominaly[2][2][2]=36.87;
+  nominaly[2][2][7]= 100.61;
+  nominaly[2][2][3]=100.61;
+  nominaly[3][0][4]= -95.61;
+  nominaly[3][0][0]=-95.61;
+  nominaly[3][0][5]= -31.87;
+  nominaly[3][0][1]=-31.87;
+  nominaly[3][0][6]= 31.87;
+  nominaly[3][0][2]=31.87;
+  nominaly[3][0][7]= 95.61;
+  nominaly[3][0][3]=95.61;
+  nominaly[3][1][4]= -100.61;
+  nominaly[3][1][0]=-100.61;
+  nominaly[3][1][5]= -36.87;
+  nominaly[3][1][1]=-36.87;
+  nominaly[3][1][6]= 26.87;
+  nominaly[3][1][2]=26.87;
+  nominaly[3][1][7]= 90.61;
+  nominaly[3][1][3]=90.61;
+  nominaly[3][2][4]= -90.61;
+  nominaly[3][2][0]=-90.61;
+  nominaly[3][2][5]= -26.87;
+  nominaly[3][2][1]=-26.87;
+  nominaly[3][2][6]= 36.87;
+  nominaly[3][2][2]=36.87;
+  nominaly[3][2][7]=100.61;
+  nominaly[3][2][3]=100.61;
+  //dump the matrix to a txt file for alignment
+  std::vector<double>* t_fitParam_chi2=0;
+  std::vector<double>* t_fitParam_pz=0;
+  std::vector<double>* t_fitParam_x=0;
+  std::vector<double>* t_fitParam_y=0;
+  std::vector<std::vector<double>>* t_fitParam_align_local_residual_x_sp=0;
+  std::vector<std::vector<double>>* t_fitParam_align_local_measured_x_sp=0;
+  std::vector<std::vector<double>>* t_fitParam_align_local_measured_xe_sp=0;
+  std::vector<std::vector<double>>* t_fitParam_align_stationId_sp=0;
+  std::vector<std::vector<double>>* t_fitParam_align_centery_sp=0;
+  std::vector<std::vector<double>>* t_fitParam_align_layerId_sp=0;
+  std::vector<std::vector<double>>* t_fitParam_align_moduleId_sp=0;
+  std::vector<std::vector<double>>* t_fitParam_align_unbiased_sp=0;
+  std::vector<std::vector<double>>* t_fitParam_align_local_derivation_x_x=0;
+  std::vector<std::vector<double>>* t_fitParam_align_local_derivation_x_y=0;
+  std::vector<std::vector<double>>* t_fitParam_align_local_derivation_x_z=0;
+  std::vector<std::vector<double>>* t_fitParam_align_local_derivation_x_rx=0;
+  std::vector<std::vector<double>>* t_fitParam_align_local_derivation_x_ry=0;
+  std::vector<std::vector<double>>* t_fitParam_align_local_derivation_x_rz=0;
+  std::vector<std::vector<double>>* t_fitParam_align_global_derivation_y_x=0;
+  std::vector<std::vector<double>>* t_fitParam_align_global_derivation_y_y=0;
+  std::vector<std::vector<double>>* t_fitParam_align_global_derivation_y_z=0;
+  std::vector<std::vector<double>>* t_fitParam_align_global_derivation_y_rx=0;
+  std::vector<std::vector<double>>* t_fitParam_align_global_derivation_y_ry=0;
+  std::vector<std::vector<double>>* t_fitParam_align_global_derivation_y_rz=0;
+  std::vector<std::vector<double>>* t_fitParam_align_stereoId=0;
+  std::vector<int>* t_fitParam_nMeasurements=0;
+  m_tree->SetBranchAddress("fitParam_nMeasurements", &t_fitParam_nMeasurements);
+  m_tree->SetBranchAddress("fitParam_align_stereoId",&t_fitParam_align_stereoId);
+  m_tree->SetBranchAddress("fitParam_align_local_derivation_x_x",&t_fitParam_align_local_derivation_x_x);
+  m_tree->SetBranchAddress("fitParam_align_local_derivation_x_y",&t_fitParam_align_local_derivation_x_y);
+  m_tree->SetBranchAddress("fitParam_align_local_derivation_x_z",&t_fitParam_align_local_derivation_x_z);
+  m_tree->SetBranchAddress("fitParam_align_local_derivation_x_rx",&t_fitParam_align_local_derivation_x_rx);
+  m_tree->SetBranchAddress("fitParam_align_local_derivation_x_ry",&t_fitParam_align_local_derivation_x_ry);
+  m_tree->SetBranchAddress("fitParam_align_local_derivation_x_rz",&t_fitParam_align_local_derivation_x_rz);
+  m_tree->SetBranchAddress("fitParam_align_global_derivation_y_x",&t_fitParam_align_global_derivation_y_x);
+  m_tree->SetBranchAddress("fitParam_align_global_derivation_y_y",&t_fitParam_align_global_derivation_y_y);
+  m_tree->SetBranchAddress("fitParam_align_global_derivation_y_z",&t_fitParam_align_global_derivation_y_z);
+  m_tree->SetBranchAddress("fitParam_align_global_derivation_y_rx",&t_fitParam_align_global_derivation_y_rx);
+  m_tree->SetBranchAddress("fitParam_align_global_derivation_y_ry",&t_fitParam_align_global_derivation_y_ry);
+  m_tree->SetBranchAddress("fitParam_align_global_derivation_y_rz",&t_fitParam_align_global_derivation_y_rz);
+  m_tree->SetBranchAddress("fitParam_align_local_residual_x_sp",&t_fitParam_align_local_residual_x_sp);
+  m_tree->SetBranchAddress("fitParam_chi2",&t_fitParam_chi2);
+  m_tree->SetBranchAddress("fitParam_pz",&t_fitParam_pz);
+  m_tree->SetBranchAddress("fitParam_x",&t_fitParam_x);
+  m_tree->SetBranchAddress("fitParam_y",&t_fitParam_y);
+  m_tree->SetBranchAddress("fitParam_align_local_measured_x_sp",&t_fitParam_align_local_measured_x_sp);
+  m_tree->SetBranchAddress("fitParam_align_local_measured_xe_sp",&t_fitParam_align_local_measured_xe_sp);
+  m_tree->SetBranchAddress("fitParam_align_layerId_sp",&t_fitParam_align_layerId_sp);
+  m_tree->SetBranchAddress("fitParam_align_moduleId_sp",&t_fitParam_align_moduleId_sp);
+  m_tree->SetBranchAddress("fitParam_align_unbiased_sp",&t_fitParam_align_unbiased_sp);
+  m_tree->SetBranchAddress("fitParam_align_stationId_sp",&t_fitParam_align_stationId_sp);
+  m_tree->SetBranchAddress("fitParam_align_centery_sp",&t_fitParam_align_centery_sp);
+  int ntrk_mod[12][8]={0};
+  int ntrk_sta[4]={0};
+  int ntrk_lay[12]={0};
+  //define matrix
+  int Ndim=6;
+  std::vector<TMatrixD> denom_lay;
+  std::vector<TMatrixD> num_lay;
+  std::vector<std::vector<TMatrixD>> denom_mod;
+  std::vector<std::vector<TMatrixD>> num_mod;
+  std::vector<std::vector<TMatrixD>> denom_mod1;
+  std::vector<std::vector<TMatrixD>> num_mod1;
+  //initialize to 0
+  auto num_matrix = [](int n) {
+    TMatrixD num_t(n,1);
+    for(int i=0;i<n;i++){
+      num_t[i][0]=0.;
+    }
+    return num_t;
+  };
+  auto denom_matrix = [](int n) {
+    TMatrixD denom_t(n,n);
+    for(int i=0;i<n;i++){
+      for(int j=0;j<n;j++){
+	denom_t[i][j]=0.;
+      }
+    }
+    return denom_t;
+  };
+  std::vector<TMatrixD> denom_sta;
+  std::vector<TMatrixD> num_sta;
+  for(int i=0;i<4;i++){
+    denom_sta.push_back(denom_matrix(Ndim));
+    num_sta.push_back(num_matrix(Ndim));
+  }
+  for(int i=0;i<12;i++){
+    denom_lay.push_back(denom_matrix(Ndim));
+    num_lay.push_back(num_matrix(Ndim));
+    std::vector<TMatrixD> denom_l;
+    std::vector<TMatrixD> num_l;
+    std::vector<TMatrixD> denom_l1;
+    std::vector<TMatrixD> num_l1;
+    for(int j=0;j<8;j++){
+      denom_l.push_back(denom_matrix(Ndim));
+      num_l.push_back(num_matrix(Ndim));
+      denom_l1.push_back(denom_matrix(Ndim));
+      num_l1.push_back(num_matrix(Ndim));
+    }
+    denom_mod.push_back(denom_l1);
+    denom_mod1.push_back(denom_l1);
+    num_mod.push_back(num_l);
+    num_mod1.push_back(num_l1);
+  }
+  double chi_mod_y[12][8]={0};
+  std::cout<<"found "<<m_tree->GetEntries()<<" events "<<std::endl;
+  //loop over all the entries
+  for(int ievt=0;ievt<m_tree->GetEntries();ievt++){
+    m_tree->GetEntry(ievt);
+    if(ievt%10000==0)std::cout<<"processing "<<ievt<<" event"<<std::endl;
+    if(t_fitParam_chi2->size()<1)continue;
+    for(int i=0;i<1;i+=1){
+      if(t_fitParam_chi2->at(i)>100||t_fitParam_pz->at(i)<300||sqrt(t_fitParam_x->at(i)*t_fitParam_x->at(i)+t_fitParam_y->at(i)*t_fitParam_y->at(i))>95)continue;
+      if(t_fitParam_align_local_residual_x_sp->at(i).size()<15)continue;//only     use good track
+      for(size_t j=0;j<t_fitParam_align_local_residual_x_sp->at(i).size();j++){
+	double resx1=999.;
+	double x1e=999.;
+	if(m_biased&&t_fitParam_align_stationId_sp->at(i).at(j)==0){
+	  if(t_fitParam_align_unbiased_sp->at(i).at(j)==1){
+	    resx1=(t_fitParam_align_local_residual_x_sp->at(i).at(j));
+	    x1e=sqrt(t_fitParam_align_local_measured_xe_sp->at(i).at(j));
+	    if(fabs(resx1)>1.0)continue;
+	  }
+	  else continue;
+	}
+	else{
+	  resx1=t_fitParam_align_local_residual_x_sp->at(i).at(j);
+	  x1e=sqrt(t_fitParam_align_local_measured_xe_sp->at(i).at(j));
+	  if(fabs(resx1)>0.2)continue;
+	}
+	TMatrixD m1(Ndim,1);
+	m1[0][0]=t_fitParam_align_local_derivation_x_x->at(i).at(j)/x1e;
+	m1[1][0]=t_fitParam_align_local_derivation_x_y->at(i).at(j)/x1e;
+	m1[2][0]=t_fitParam_align_local_derivation_x_z->at(i).at(j)/x1e;
+	m1[3][0]=t_fitParam_align_local_derivation_x_rx->at(i).at(j)/x1e;
+	m1[4][0]=t_fitParam_align_local_derivation_x_ry->at(i).at(j)/x1e;
+	m1[5][0]=t_fitParam_align_local_derivation_x_rz->at(i).at(j)/x1e;
+	TMatrixD m2(1,Ndim);
+	TMatrixD m3(Ndim,Ndim);
+	m2.Transpose(m1);
+	m3=m1*m2;
+	TMatrixD m4(Ndim,1);
+	m4[0][0]=t_fitParam_align_local_derivation_x_x->at(i).at(j)/x1e*resx1/x1e;
+	m4[1][0]=t_fitParam_align_local_derivation_x_y->at(i).at(j)/x1e*resx1/x1e;
+	m4[2][0]=t_fitParam_align_local_derivation_x_z->at(i).at(j)/x1e*resx1/x1e;
+	m4[3][0]=t_fitParam_align_local_derivation_x_rx->at(i).at(j)/x1e*resx1/x1e;
+	m4[4][0]=t_fitParam_align_local_derivation_x_ry->at(i).at(j)/x1e*resx1/x1e;
+	m4[5][0]=t_fitParam_align_local_derivation_x_rz->at(i).at(j)/x1e*resx1/x1e;
+	TMatrixD m6(Ndim,1);
+	m6=m4;
+	TMatrixD mg1(Ndim,1);
+	mg1[0][0]=t_fitParam_align_global_derivation_y_x->at(i).at(j)/x1e;
+	mg1[1][0]=t_fitParam_align_global_derivation_y_y->at(i).at(j)/x1e;
+	mg1[2][0]=t_fitParam_align_global_derivation_y_z->at(i).at(j)/x1e;
+	mg1[3][0]=t_fitParam_align_global_derivation_y_rx->at(i).at(j)/x1e;
+	mg1[4][0]=t_fitParam_align_global_derivation_y_ry->at(i).at(j)/x1e;
+	mg1[5][0]=t_fitParam_align_global_derivation_y_rz->at(i).at(j)/x1e;
+	TMatrixD mg2(1,Ndim);
+	TMatrixD mg3(Ndim,Ndim);
+	mg2.Transpose(mg1);
+	mg3=mg1*mg2;
+	TMatrixD mg4(Ndim,1);
+	mg4[0][0]=t_fitParam_align_global_derivation_y_x->at(i).at(j)/x1e*resx1/x1e;
+	mg4[1][0]=t_fitParam_align_global_derivation_y_y->at(i).at(j)/x1e*resx1/x1e;
+	mg4[2][0]=t_fitParam_align_global_derivation_y_z->at(i).at(j)/x1e*resx1/x1e;
+	mg4[3][0]=t_fitParam_align_global_derivation_y_rx->at(i).at(j)/x1e*resx1/x1e;
+	mg4[4][0]=t_fitParam_align_global_derivation_y_ry->at(i).at(j)/x1e*resx1/x1e;
+	mg4[5][0]=t_fitParam_align_global_derivation_y_rz->at(i).at(j)/x1e*resx1/x1e;
+	TMatrixD mg6(Ndim,1);
+	mg6=mg4;
+	int istation=t_fitParam_align_stationId_sp->at(i).at(j);
+	int ilayer=t_fitParam_align_layerId_sp->at(i).at(j);
+	int imodule=t_fitParam_align_moduleId_sp->at(i).at(j);
+	//station: 1,2,3
+	if(istation>=0&&istation<4){
+	  denom_sta[istation]+=mg3;
+	  num_sta[istation]+=mg6;
+	  ntrk_sta[istation]+=1;
+	}
+	int ilayer_tot = ilayer + (istation )*3;
+	double deltay=t_fitParam_align_centery_sp->at(i).at(j)-nominaly[istation][ilayer][imodule];
+	ATH_MSG_DEBUG("nominal/new geometry Y position = "<<nominaly[istation][ilayer][imodule]<<"/"<<t_fitParam_align_centery_sp->at(i).at(j));
+	chi_mod_y[ilayer_tot][imodule]+=deltay/sigma/sigma;
+	if(ilayer_tot>=0&&ilayer_tot<12){
+	  denom_lay[ilayer_tot]+=mg3;
+	  num_lay[ilayer_tot]+=mg6;
+	  ntrk_lay[ilayer_tot]+=1;
+	  denom_mod[ilayer_tot][imodule]+=m3;
+	  num_mod[ilayer_tot][imodule]+=m6;
+	  ntrk_mod[ilayer_tot][imodule]+=1;
+	}
+      }
+    }
+  }
+
+  std::cout<<"Get the nominal transform"<<std::endl;
+  //get the alignment constants
+  std::ofstream align_output("alignment_matrix.txt",std::ios::out);
+  for(int i=0;i<4;i++){
+    for(int ii=0;ii<Ndim;ii++){
+      align_output<<i<<" "<<ii<<" "<<denom_sta[i][ii][0]<<" "<<denom_sta[i][ii][1]<<" "<<denom_sta[i][ii][2]<<" "<<denom_sta[i][ii][3]<<" "<<denom_sta[i][ii][4]<<" "<<denom_sta[i][ii][5]<<" "<<0<<std::endl;
+      if(ii==0)
+	std::cout<<i<<" "<<ii<<" "<<denom_sta[i][ii][0]<<" "<<denom_sta[i][ii][1]<<" "<<denom_sta[i][ii][2]<<" "<<denom_sta[i][ii][3]<<" "<<denom_sta[i][ii][4]<<" "<<denom_sta[i][ii][5]<<" "<<0<<std::endl;
+    }
+    align_output<<i<<" "<<6<<" "<<num_sta[i][0][0]<<" "<<num_sta[i][1][0]<<" "<<num_sta[i][2][0]<<" "<<num_sta[i][3][0]<<" "<<num_sta[i][4][0]<<" "<<num_sta[i][5][0]<<" "<<ntrk_sta[i]<<std::endl;
+  }
+  std::cout<<"Get the deltas for stations"<<std::endl;
+  //layers
+  for(size_t i=0;i<denom_lay.size();i++){
+    for(int ii=0;ii<Ndim;ii++){
+      align_output<<i/3<<i%3<<" "<<ii<<" "<<denom_lay[i][ii][0]<<" "<<denom_lay[i][ii][1]<<" "<<denom_lay[i][ii][2]<<" "<<denom_lay[i][ii][3]<<" "<<denom_lay[i][ii][4]<<" "<<denom_lay[i][ii][5]<<" "<<0<<std::endl;
+    }
+    align_output<<i/3<<i%3<<" "<<6<<" "<<num_lay[i][0][0]<<" "<<num_lay[i][1][0]<<" "<<num_lay[i][2][0]<<" "<<num_lay[i][3][0]<<" "<<num_lay[i][4][0]<<" "<<num_lay[i][5][0]<<" "<<ntrk_lay[i]<<std::endl;
+  }
+
+  std::cout<<"Get the deltas for layers"<<std::endl;
+  for(size_t i=0;i<denom_lay.size();i++){
+    for(  size_t j=0;j<num_mod[i].size();j++){
+      for(int ii=0;ii<Ndim;ii++){
+	align_output<<i/3<<i%3<<j<<" "<<ii<<" "<<denom_mod[i][j][ii][0]<<" "<<denom_mod[i][j][ii][1]<<" "<<denom_mod[i][j][ii][2]<<" "<<denom_mod[i][j][ii][3]<<" "<<denom_mod[i][j][ii][4]<<" "<<denom_mod[i][j][ii][5]<<" "<<chi_mod_y[i][j]<<std::endl;
+      }
+      align_output<<i/3<<i%3<<j<<" "<<6<<" "<<num_mod[i][j][0][0]<<" "<<num_mod[i][j][1][0]<<" "<<num_mod[i][j][2][0]<<" "<<num_mod[i][j][3][0]<<" "<<num_mod[i][j][4][0]<<" "<<num_mod[i][j][5][0]<<" "<<ntrk_mod[i][j]<<std::endl;
+    }
+  }
+  std::cout<<"closing the output"<<std::endl;
+  align_output.close();
+  return StatusCode::SUCCESS;
+}
+
+
+Acts::MagneticFieldContext CKF2Alignment::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);
+}
+
+
+
+
+void CKF2Alignment::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<CKF2Alignment::TrackParameters>;
+
+  struct TrackFinderFunctionImpl
+    : public CKF2Alignment::TrackFinderFunction {
+      CKF trackFinder;
+
+      TrackFinderFunctionImpl(CKF&& f) : trackFinder(std::move(f)) {}
+
+      CKF2Alignment::TrackFinderResult operator()(
+	  const IndexSourceLinkContainer& sourcelinks,
+	  const TrackParametersContainer& initialParameters,
+	  const CKF2Alignment::TrackFinderOptions& options)
+	const override {
+	  return trackFinder.findTracks(sourcelinks, initialParameters, options);
+	};
+    };
+
+}  // namespace
+
+std::shared_ptr<CKF2Alignment::TrackFinderFunction>
+CKF2Alignment::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 CKF2Alignment::TrackFitterFunction {
+      Fitter trackFitter;
+
+      TrackFitterFunctionImpl(Fitter &&f) : trackFitter(std::move(f)) {}
+
+      CKF2Alignment::KFResult operator()(
+	  const std::vector<IndexSourceLink> &sourceLinks,
+	  const Acts::BoundTrackParameters &initialParameters,
+	  const CKF2Alignment::TrackFitterOptions &options)
+	const override {
+	  return trackFitter.fit(sourceLinks, initialParameters, options);
+	};
+    };
+
+}  // namespace
+
+
+std::shared_ptr<CKF2Alignment::TrackFitterFunction>
+CKF2Alignment::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));
+}
+
+
+void CKF2Alignment::initializeTree(){
+  m_tree->Branch("evtId",&m_numberOfEvents);
+  m_tree->Branch("fitParam_x", &m_fitParam_x);
+  m_tree->Branch("fitParam_charge", &m_fitParam_charge);
+  m_tree->Branch("fitParam_y", &m_fitParam_y);
+  m_tree->Branch("fitParam_z", &m_fitParam_z);
+  m_tree->Branch("fitParam_px", &m_fitParam_px);
+  m_tree->Branch("fitParam_py", &m_fitParam_py);
+  m_tree->Branch("fitParam_pz", &m_fitParam_pz);
+  m_tree->Branch("fitParam_chi2", &m_fitParam_chi2);
+  m_tree->Branch("fitParam_ndf", &m_fitParam_ndf);
+  m_tree->Branch("fitParam_nHoles", &m_fitParam_nHoles);
+  m_tree->Branch("fitParam_nOutliers", &m_fitParam_nOutliers);
+  m_tree->Branch("fitParam_nStates", &m_fitParam_nStates);
+  m_tree->Branch("fitParam_nMeasurements", &m_fitParam_nMeasurements);
+  m_tree->Branch("fitParam_align_stereoId", &m_align_stereoId);
+  m_tree->Branch("fitParam_align_stationId_sp", &m_align_stationId_sp);
+  m_tree->Branch("fitParam_align_centery_sp", &m_align_centery_sp);
+  m_tree->Branch("fitParam_align_layerId_sp", &m_align_layerId_sp);
+  m_tree->Branch("fitParam_align_moduleId_sp", &m_align_moduleId_sp);
+  m_tree->Branch("fitParam_align_clustersize_sp", &m_align_clustersize_sp);
+  m_tree->Branch("fitParam_align_local_derivation_x_x", &m_align_derivation_x_x);
+  m_tree->Branch("fitParam_align_local_derivation_x_y", &m_align_derivation_x_y);
+  m_tree->Branch("fitParam_align_local_derivation_x_z", &m_align_derivation_x_z);
+  m_tree->Branch("fitParam_align_local_derivation_x_rx", &m_align_derivation_x_rx);
+  m_tree->Branch("fitParam_align_local_derivation_x_ry", &m_align_derivation_x_ry);
+  m_tree->Branch("fitParam_align_local_derivation_x_rz", &m_align_derivation_x_rz);
+  m_tree->Branch("fitParam_align_global_derivation_y_x", &m_align_derivation_global_y_x);
+  m_tree->Branch("fitParam_align_global_derivation_y_y", &m_align_derivation_global_y_y);
+  m_tree->Branch("fitParam_align_global_derivation_y_z", &m_align_derivation_global_y_z);
+  m_tree->Branch("fitParam_align_global_derivation_y_rx", &m_align_derivation_global_y_rx);
+  m_tree->Branch("fitParam_align_global_derivation_y_ry", &m_align_derivation_global_y_ry);
+  m_tree->Branch("fitParam_align_global_derivation_y_rz", &m_align_derivation_global_y_rz);
+  m_tree->Branch("fitParam_align_local_residual_x_sp", &m_align_local_residual_x_sp);
+  m_tree->Branch("fitParam_align_unbiased_sp", &m_align_unbiased_sp);
+  m_tree->Branch("fitParam_align_local_pull_x_sp", &m_align_local_pull_x_sp);
+  m_tree->Branch("fitParam_align_local_measured_x_sp", &m_align_local_measured_x_sp);
+  m_tree->Branch("fitParam_align_local_measured_xe_sp", &m_align_local_measured_xe_sp);
+  m_tree->Branch("fitParam_align_local_fitted_xe_sp", &m_align_local_fitted_xe_sp);
+  m_tree->Branch("fitParam_align_local_fitted_x_sp", &m_align_local_fitted_x_sp);
+  m_tree->Branch("fitParam_align_global_residual_y_sp", &m_align_global_residual_y_sp);
+  m_tree->Branch("fitParam_align_global_measured_x_sp", &m_align_global_measured_x_sp);
+  m_tree->Branch("fitParam_align_global_measured_y_sp", &m_align_global_measured_y_sp);
+  m_tree->Branch("fitParam_align_global_measured_ye_sp", &m_align_global_measured_ye_sp);
+  m_tree->Branch("fitParam_align_global_measured_z_sp", &m_align_global_measured_z_sp);
+  m_tree->Branch("fitParam_align_global_fitted_ye_sp", &m_align_global_fitted_ye_sp);
+  m_tree->Branch("fitParam_align_global_fitted_x_sp", &m_align_global_fitted_x_sp);
+  m_tree->Branch("fitParam_align_global_fitted_y_sp", &m_align_global_fitted_y_sp);
+}
+
+void CKF2Alignment::clearVariables(){
+  m_fitParam_x.clear();
+  m_fitParam_charge.clear();
+  m_fitParam_y.clear();
+  m_fitParam_z.clear();
+  m_fitParam_px.clear();
+  m_fitParam_py.clear();
+  m_fitParam_pz.clear();
+  m_fitParam_chi2.clear();
+  m_fitParam_ndf.clear();
+  m_fitParam_nHoles.clear();
+  m_fitParam_nOutliers.clear();
+  m_fitParam_nStates.clear();
+  m_fitParam_nMeasurements.clear();
+  m_align_derivation_x_x.clear();
+  m_align_derivation_x_y.clear();
+  m_align_derivation_x_z.clear();
+  m_align_derivation_x_rx.clear();
+  m_align_derivation_x_ry.clear();
+  m_align_derivation_x_rz.clear();
+  m_align_derivation_global_y_x.clear();
+  m_align_derivation_global_y_y.clear();
+  m_align_derivation_global_y_z.clear();
+  m_align_derivation_global_y_rx.clear();
+  m_align_derivation_global_y_ry.clear();
+  m_align_derivation_global_y_rz.clear();
+  m_align_local_residual_x_sp.clear();
+  m_align_unbiased_sp.clear();
+  m_align_local_pull_x_sp.clear();
+  m_align_local_measured_x_sp.clear();
+  m_align_local_measured_xe_sp.clear();
+  m_align_local_fitted_xe_sp.clear();
+  m_align_local_fitted_x_sp.clear();
+  m_align_global_residual_y_sp.clear();
+  m_align_global_measured_x_sp.clear();
+  m_align_global_measured_y_sp.clear();
+  m_align_global_measured_z_sp.clear();
+  m_align_global_measured_ye_sp.clear();
+  m_align_global_fitted_ye_sp.clear();
+  m_align_global_fitted_x_sp.clear();
+  m_align_global_fitted_y_sp.clear();
+  m_align_stationId_sp.clear();
+  m_align_centery_sp.clear();
+  m_align_layerId_sp.clear();
+  m_align_moduleId_sp.clear();
+  m_align_clustersize_sp.clear();
+  m_align_stereoId.clear();
+}
+
+
+double CKF2Alignment::getLocalDerivation(Amg::Transform3D trans1, Amg::Vector2D loc_pos, int ia, int side , Amg::Transform3D trans2)const {
+  double delta[6]={0.001,0.001,0.001,0.0001,0.0001,0.0001};
+  auto translation_m = Amg::Translation3D(0,0,0);
+  Amg::Transform3D transform_m= translation_m* Amg::RotationMatrix3D::Identity();
+  auto translation_p = Amg::Translation3D(0,0,0);
+  Amg::Transform3D transform_p= translation_p* Amg::RotationMatrix3D::Identity();
+  switch (ia)
+  {
+    case 0:
+      transform_m *= Amg::Translation3D(0-delta[ia],0,0);
+      transform_p *= Amg::Translation3D(0+delta[ia],0,0);
+      break;
+    case 1:
+      transform_m *= Amg::Translation3D(0,0-delta[ia],0);
+      transform_p *= Amg::Translation3D(0,0+delta[ia],0);
+      break;
+    case 2:
+      transform_m *= Amg::Translation3D(0,0,0-delta[ia]);
+      transform_p *= Amg::Translation3D(0,0,0+delta[ia]);
+      break;
+    case 3:
+      transform_m *= Amg::AngleAxis3D(0-delta[ia], Amg::Vector3D(1,0,0));
+      transform_p *= Amg::AngleAxis3D(0+delta[ia], Amg::Vector3D(1,0,0));
+      break;
+    case 4:
+      transform_m *= Amg::AngleAxis3D(0-delta[ia], Amg::Vector3D(0,1,0));
+      transform_p *= Amg::AngleAxis3D(0+delta[ia], Amg::Vector3D(0,1,0));
+      break;
+    case 5:
+      transform_m *= Amg::AngleAxis3D(0-delta[ia], Amg::Vector3D(0,0,1));
+      transform_p *= Amg::AngleAxis3D(0+delta[ia], Amg::Vector3D(0,0,1));
+      break;
+    default:
+      ATH_MSG_FATAL("Unknown alignment parameter" );
+      break;
+  }
+
+  auto local3 = Amg::Vector3D(loc_pos.x(),loc_pos.y(),0.);
+  Amg::Vector3D glo_pos = trans1 * local3;
+  Amg::Vector3D local_m = (trans1 * transform_m).inverse()*glo_pos;
+  Amg::Vector3D local_p = (trans1 * transform_p).inverse()*glo_pos;
+  if(side!=1)
+    return (local_p.x()-local_m.x())/2./delta[ia];
+  else{
+    Amg::Vector3D local_m2=trans2.inverse()*trans1*local_m;
+    Amg::Vector3D local_p2=trans2.inverse()*trans1*local_p;
+    return (local_p2.x()-local_m2.x())/2./delta[ia];
+  }
+}
+
+
+double CKF2Alignment::getDerivation(const EventContext& ctx, Acts::BoundTrackParameters& fitParameters, Amg::Transform3D trans1, Amg::Vector2D loc_pos, int ia, int side , Amg::Transform3D trans2, int global)const {
+  double delta[6]={0.001,0.001,0.001,0.0001,0.0001,0.0001};
+  auto translation_m = Amg::Translation3D(0,0,0);
+  Amg::Transform3D transform_m= translation_m* Amg::RotationMatrix3D::Identity();
+  auto translation_p = Amg::Translation3D(0,0,0);
+  Amg::Transform3D transform_p= translation_p* Amg::RotationMatrix3D::Identity();
+  switch (ia)
+  {
+    case 0:
+      transform_m *= Amg::Translation3D(0-delta[ia],0,0);
+      transform_p *= Amg::Translation3D(0+delta[ia],0,0);
+      break;
+    case 1:
+      transform_m *= Amg::Translation3D(0,0-delta[ia],0);
+      transform_p *= Amg::Translation3D(0,0+delta[ia],0);
+      break;
+    case 2:
+      transform_m *= Amg::Translation3D(0,0,0-delta[ia]);
+      transform_p *= Amg::Translation3D(0,0,0+delta[ia]);
+      break;
+    case 3:
+      transform_m *= Amg::AngleAxis3D(0-delta[ia], Amg::Vector3D(1,0,0));
+      transform_p *= Amg::AngleAxis3D(0+delta[ia], Amg::Vector3D(1,0,0));
+      break;
+    case 4:
+      transform_m *= Amg::AngleAxis3D(0-delta[ia], Amg::Vector3D(0,1,0));
+      transform_p *= Amg::AngleAxis3D(0+delta[ia], Amg::Vector3D(0,1,0));
+      break;
+    case 5:
+      transform_m *= Amg::AngleAxis3D(0-delta[ia], Amg::Vector3D(0,0,1));
+      transform_p *= Amg::AngleAxis3D(0+delta[ia], Amg::Vector3D(0,0,1));
+      break;
+    default:
+      ATH_MSG_FATAL("Unknown alignment parameter" );
+      break;
+  }
+
+  auto local3 = Amg::Vector3D(loc_pos.x(),loc_pos.y(),0.);
+  Amg::Vector3D glo_pos = trans2 * local3;
+  auto trans_m = trans1 * transform_m;
+  auto trans_p = trans1 * transform_p;
+  if(side==1 && global!=1){
+    trans_m = trans1 * transform_m * trans1.inverse() * trans2;
+    trans_p = trans1 * transform_p * trans1.inverse() * trans2;
+  }
+  if (global==1){
+    Amg::Transform3D trans_g = Amg::Translation3D(0,0, glo_pos.z()) * Amg::RotationMatrix3D::Identity();
+    auto trans_l2g = trans_g.inverse()*trans1;
+    trans_m = trans1 * trans_l2g.inverse() * transform_m * trans_l2g;
+    trans_p = trans1 * trans_l2g.inverse() * transform_p * trans_l2g;
+    if(side==1){
+      auto tmpm = trans_m;
+      auto tmpp = trans_p;
+      trans_m = tmpm * trans1.inverse() * trans2;
+      trans_p = tmpp * trans1.inverse() * trans2;
+    }
+  }
+
+  Amg::Transform3D ini_trans = Amg::Translation3D(0,0, glo_pos.z()-10) * Amg::RotationMatrix3D::Identity();
+  auto ini_surface = Acts::Surface::makeShared<Acts::PlaneSurface>(ini_trans, std::make_shared<const Acts::RectangleBounds>(1000.,1000.));
+  std::unique_ptr<const Acts::BoundTrackParameters> ini_Param = m_extrapolationTool->propagate( ctx, fitParameters, *ini_surface, Acts::backward);
+  if(ini_Param==nullptr)return -9999.;
+
+
+  auto shift_m_surface = Acts::Surface::makeShared<Acts::PlaneSurface>(trans_m, std::make_shared<const Acts::RectangleBounds>(1000.,1000.));
+  auto shift_p_surface = Acts::Surface::makeShared<Acts::PlaneSurface>(trans_p, std::make_shared<const Acts::RectangleBounds>(1000.,1000.));
+  auto shift_m_Param = m_extrapolationTool->propagate( ctx, *ini_Param, *shift_m_surface, Acts::forward);
+  auto shift_p_Param = m_extrapolationTool->propagate( ctx, *ini_Param, *shift_p_surface, Acts::forward);
+  if(shift_m_Param!=nullptr||shift_p_Param!=nullptr){
+    auto shift_m_parameter = shift_m_Param->parameters();
+    auto shift_p_parameter = shift_p_Param->parameters();
+    Amg::Vector2D local_m(shift_m_parameter[Acts::eBoundLoc0],shift_m_parameter[Acts::eBoundLoc1]);
+    Amg::Vector2D local_p(shift_p_parameter[Acts::eBoundLoc0],shift_p_parameter[Acts::eBoundLoc1]);
+    return (local_p.x()-local_m.x())/2./delta[ia];
+  }
+  return -99999.;
+}
+
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CKF2Alignment.h b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2Alignment.h
new file mode 100755
index 0000000000000000000000000000000000000000..1cc5f368942797b2a193ed69fdebf4bf2db2df4c
--- /dev/null
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/CKF2Alignment.h
@@ -0,0 +1,199 @@
+#ifndef FASERACTSKALMANFILTER_CKF2ALIGNMENT_H
+#define FASERACTSKALMANFILTER_CKF2ALIGNMENT_H
+
+
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "TrackerSpacePoint/FaserSCT_SpacePointContainer.h"
+#include "TrackerPrepRawData/FaserSCT_ClusterContainer.h"
+#include "FaserActsGeometryInterfaces/IFaserActsTrackingGeometryTool.h"
+#include "FaserActsGeometryInterfaces/IFaserActsExtrapolationTool.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 "TrkTrack/TrackCollection.h"
+#include "FaserActsKalmanFilter/ITrackSeedTool.h"
+#include "KalmanFitterTool.h"
+#include <boost/dynamic_bitset.hpp>
+#include "GaudiKernel/ITHistSvc.h"
+#include "CreateTrkTrackTool.h"
+
+using ConstTrackStateProxy = Acts::detail_lt::TrackStateProxy<IndexSourceLink, 6, true>;
+using ClusterSet = boost::dynamic_bitset<>;
+
+class TTree;
+class FaserSCT_ID;
+
+
+namespace TrackerDD {
+  class SCT_DetectorManager;
+}
+
+class CKF2Alignment : public AthAlgorithm {
+  public:
+    CKF2Alignment(const std::string& name, ISvcLocator* pSvcLocator);
+    virtual ~CKF2Alignment() = default;
+
+    StatusCode initialize() override;
+    StatusCode execute() override;
+    StatusCode finalize() override;
+    void initializeTree();
+    void clearVariables();
+
+    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:
+    int  m_numberOfEvents {0};
+    int  m_numberOfTrackSeeds {0};
+    int  m_numberOfFittedTracks {0};
+    int  m_numberOfSelectedTracks {0};
+
+    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<bool> m_biased{this, "BiasedResidual", true};
+    Gaudi::Property<std::string> m_actsLogging {this, "ActsLogging", "VERBOSE"};
+    Gaudi::Property<int> m_minNumberMeasurements {this, "MinNumberMeasurements", 12};
+    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};
+    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<KalmanFitterTool> m_kalmanFitterTool1 {this, "KalmanFitterTool1", "KalmanFitterTool"};
+    ToolHandle<CreateTrkTrackTool> m_createTrkTrackTool {this, "CreateTrkTrackTool", "CreateTrkTrackTool"};
+    Gaudi::Property<bool> m_isMC {this, "isMC", false};
+    ToolHandle<IFaserActsExtrapolationTool> m_extrapolationTool{this, "ExtrapolationTool", "FaserActsExtrapolationTool"};
+
+    double getDerivation(const EventContext& ctx, Acts::BoundTrackParameters& fitParameters, Amg::Transform3D trans1, Amg::Vector2D loc_pos, int ia, int side , Amg::Transform3D trans2, int global)const ;
+    double getLocalDerivation(Amg::Transform3D trans1, Amg::Vector2D loc_pos, int ia, int side , Amg::Transform3D trans2)const;
+    //output ntuple
+    ServiceHandle<ITHistSvc>  m_thistSvc;
+    TTree* m_tree;
+    mutable int m_eventId=0;
+    mutable int m_trackId=0;
+    mutable std::vector<double> m_fitParam_x;
+    mutable std::vector<double> m_fitParam_charge;
+    mutable std::vector<double> m_fitParam_y;
+    mutable std::vector<double> m_fitParam_z;
+    mutable std::vector<double> m_fitParam_px;
+    mutable std::vector<double> m_fitParam_py;
+    mutable std::vector<double> m_fitParam_pz;
+    mutable std::vector<double> m_fitParam_chi2;
+    mutable std::vector<int> m_fitParam_ndf;
+    mutable std::vector<int> m_fitParam_nHoles;
+    mutable std::vector<int> m_fitParam_nOutliers;
+    mutable std::vector<int> m_fitParam_nStates;
+    mutable std::vector<int> m_fitParam_nMeasurements;
+    mutable std::vector<std::vector<double>> m_align_stationId_sp;
+    mutable std::vector<std::vector<double>> m_align_centery_sp;
+    mutable std::vector<std::vector<double>> m_align_layerId_sp;
+    mutable std::vector<std::vector<double>> m_align_moduleId_sp;
+    mutable std::vector<std::vector<double>> m_align_clustersize_sp;
+    mutable std::vector<std::vector<double>> m_align_global_residual_y_sp;
+    mutable std::vector<std::vector<double>> m_align_global_measured_x_sp;
+    mutable std::vector<std::vector<double>> m_align_global_measured_y_sp;
+    mutable std::vector<std::vector<double>> m_align_global_measured_z_sp;
+    mutable std::vector<std::vector<double>> m_align_global_measured_ye_sp;
+    mutable std::vector<std::vector<double>> m_align_global_fitted_ye_sp;
+    mutable std::vector<std::vector<double>> m_align_global_fitted_y_sp;
+    mutable std::vector<std::vector<double>> m_align_global_fitted_x_sp;
+    mutable std::vector<std::vector<double>> m_align_local_residual_x_sp;
+    mutable std::vector<std::vector<double>> m_align_unbiased_sp;
+    mutable std::vector<std::vector<double>> m_align_local_pull_x_sp;
+    mutable std::vector<std::vector<double>> m_align_local_measured_x_sp;
+    mutable std::vector<std::vector<double>> m_align_local_measured_xe_sp;
+    mutable std::vector<std::vector<double>> m_align_local_fitted_xe_sp;
+    mutable std::vector<std::vector<double>> m_align_local_fitted_x_sp;
+    mutable std::vector<std::vector<double>> m_align_derivation_x_x;
+    mutable std::vector<std::vector<double>> m_align_derivation_x_y;
+    mutable std::vector<std::vector<double>> m_align_derivation_x_z;
+    mutable std::vector<std::vector<double>> m_align_derivation_x_rx;
+    mutable std::vector<std::vector<double>> m_align_derivation_x_ry;
+    mutable std::vector<std::vector<double>> m_align_derivation_x_rz;
+    mutable std::vector<std::vector<double>> m_align_derivation_global_y_x;
+    mutable std::vector<std::vector<double>> m_align_derivation_global_y_y;
+    mutable std::vector<std::vector<double>> m_align_derivation_global_y_z;
+    mutable std::vector<std::vector<double>> m_align_derivation_global_y_rx;
+    mutable std::vector<std::vector<double>> m_align_derivation_global_y_ry;
+    mutable std::vector<std::vector<double>> m_align_derivation_global_y_rz;
+    mutable std::vector<std::vector<double>> m_align_stereoId;
+};
+
+#endif // FASERACTSKALMANFILTER_CKF2Alignment_H
+
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.cxx
index 41611bad5882de7e15ce3de15f6c4833fbf10581..952f75287f594e5df31feb2b6a493bfe235a4086 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.cxx
@@ -7,7 +7,6 @@
 #include "Identifier/Identifier.h"
 #include "Acts/Geometry/GeometryIdentifier.hpp"
 #include "CircleFit.h"
-#include "Identifier/Identifier.h"
 #include "LinearFit.h"
 #include "TrackClassification.h"
 #include <array>
@@ -80,12 +79,14 @@ StatusCode CircleFitTrackSeedTool::run(std::vector<int> maskedLayers) {
       if (std::find(maskedLayers.begin(), maskedLayers.end(), 3 * m_idHelper->station(id) + m_idHelper->layer(id)) != maskedLayers.end()) {
         continue;
       }
+//      if(m_idHelper->station(id)==0) continue;
       CircleFitTrackSeedTool::s_indexMap[cluster->identify()] = measurements.size();
       if (identifierMap->count(id) != 0) {
         Acts::GeometryIdentifier geoId = identifierMap->at(id);
         IndexSourceLink sourceLink(geoId, measurements.size(), cluster);
         // create measurement
         const auto& par = cluster->localPosition();
+	auto cova = cluster->localCovariance();
         Eigen::Matrix<double, 1, 1> pos {par.x(),};
         Eigen::Matrix<double, 1, 1> cov {0.0231 * 0.0231,};
         ThisMeasurement meas(sourceLink, Indices, pos, cov);
@@ -101,7 +102,13 @@ StatusCode CircleFitTrackSeedTool::run(std::vector<int> maskedLayers) {
   std::array<std::vector<Segment>, 4> segments {};
   for (const Trk::Track* track : *trackCollection) {
     auto s = Segment(track, m_idHelper, maskedLayers);
+    //remove IFT in seeding
+    if(m_removeIFT){
+    if (s.station != -1 &&s.station != 0) segments[s.station].push_back(s);
+    }
+    else{
     if (s.station != -1) segments[s.station].push_back(s);
+    }
   }
 
   std::vector<Segment> combination {};
@@ -151,7 +158,7 @@ StatusCode CircleFitTrackSeedTool::run(std::vector<int> maskedLayers) {
       selectedSeeds.begin(), selectedSeeds.end(), [](const Seed &lhs, const Seed &rhs) {
         return lhs.minZ < rhs.minZ;
       });
-  double origin = !selectedSeeds.empty() ? minSeed->minZ - 1 : 0;
+  double origin = !selectedSeeds.empty() ? minSeed->minZ - 10 : 0;
   m_targetZPosition = origin;
   std::vector<Acts::CurvilinearTrackParameters> initParams {};
   for (const Seed &seed : selectedSeeds) {
@@ -212,6 +219,7 @@ CircleFitTrackSeedTool::Segment::Segment(const Trk::Track* track, const FaserSCT
         }
       }
       station = idHelper->station(id);
+//      if(station==0)continue;
       clusterSet.set(CircleFitTrackSeedTool::s_indexMap.at(id));
       auto fitParameters = track->trackParameters()->front();
       position = fitParameters->position();
@@ -265,12 +273,11 @@ CircleFitTrackSeedTool::Seed::Seed(const std::vector<Segment> &segments) :
   size = clusters.size();
 }
 
+
 void CircleFitTrackSeedTool::Seed::fit() {
   CircleFit::CircleData circleData(positions);
   CircleFit::Circle circle = CircleFit::circleFit(circleData);
   momentum = circle.r > 0 ? circle.r * 0.001 * 0.3 * 0.55 : 9999999.;
-  // the magnetic field bends a positively charged particle downwards, thus the
-  // y-component of the center of a fitted circle is negative.
   charge = circle.cy < 0 ? 1 : -1;
 }
 
@@ -281,8 +288,6 @@ void CircleFitTrackSeedTool::Seed::fakeFit(double B) {
   cy = circle.cy;
   r = circle.r;
   momentum = r * 0.3 * B * m_MeV2GeV;
-  // the magnetic field bends a positively charged particle downwards, thus the
-  // y-component of the center of a fitted circle is negative.
   charge = circle.cy < 0 ? 1 : -1;
 }
 
@@ -292,6 +297,7 @@ void CircleFitTrackSeedTool::Seed::linearFit(const std::vector<Acts::Vector2> &p
   c0 = origin[1] - origin[0] * c1;
 }
 
+
 double CircleFitTrackSeedTool::Seed::getY(double z) {
   double sqt = std::sqrt(-cx*cx + 2*cx*z + r*r - z*z);
   return abs(cy - sqt) < abs(cy + sqt) ? cy - sqt : cy + sqt;
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.h
index 7866b89fc32fe2ccd8a0391f421b1d203ff1e8e0..0467c92620eebd955f0a78f11cfdea3fd0cb0b1d 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.h
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/CircleFitTrackSeedTool.h
@@ -116,6 +116,7 @@ private:
   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<bool> m_removeIFT{this, "removeIFT", false};
 };
 
 inline const std::shared_ptr<std::vector<Acts::CurvilinearTrackParameters>>
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx
index ee2a864b51d0cd632322128256666679c4beb490..dcb167496790d2b5af143b55b86cc4698f902976 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/CombinatorialKalmanFilterAlg.cxx
@@ -73,7 +73,7 @@ StatusCode CombinatorialKalmanFilterAlg::execute() {
   std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry
       = m_trackingGeometryTool->trackingGeometry();
 
-  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext();
+  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getGeometryContext();
   auto geoctx = gctx.context();
   Acts::MagneticFieldContext magFieldContext = getMagneticFieldContext(ctx);
   Acts::CalibrationContext calibContext;
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx
index f88b4e15f59fc7e7d3a4b434c8328942982a67ba..5dd831f9592b5323280d5cc09e10798fa342966f 100755
--- a/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/FaserActsKalmanFilterAlg.cxx
@@ -109,7 +109,7 @@ StatusCode FaserActsKalmanFilterAlg::execute() {
   std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry
       = m_trackingGeometryTool->trackingGeometry();
 
-  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getNominalGeometryContext();
+  const FaserActsGeometryContext& gctx = m_trackingGeometryTool->getGeometryContext();
   auto geoctx = gctx.context();
   Acts::MagneticFieldContext magctx = getMagneticFieldContext(ctx);
   Acts::CalibrationContext calctx;
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx
index 051687e21c6d0b1c1874a26ac4ddeb5d55c55124..c0d02183f5616df5b624152fee61d4c1bf6bba37 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.cxx
@@ -39,6 +39,329 @@ StatusCode KalmanFitterTool::finalize() {
   return StatusCode::SUCCESS;
 }
 
+//get the unbiased residual for the cluster at Z =  clusz
+//output is a vector of the outliers
+//
+std::vector<TSOS4Residual>
+KalmanFitterTool::getUnbiasedResidual(const EventContext &ctx, const Acts::GeometryContext &gctx,
+                      Trk::Track* inputTrack, double clusz, const Acts::BoundVector& inputVector,
+                      bool isMC, double origin) const {
+  std::vector<TSOS4Residual> resi;
+  resi.clear();
+  std::vector<FaserActsRecMultiTrajectory> myTrajectories;
+  ATH_MSG_DEBUG("start kalmanfilter "<<inputTrack->measurementsOnTrack()->size()<<" "<<origin<<" "<<clusz);
+
+  if (!inputTrack->measurementsOnTrack() || inputTrack->measurementsOnTrack()->size() < m_minMeasurements) {
+    ATH_MSG_DEBUG("Input track has no or too little measurements and cannot be fitted");
+    return resi;
+  }
+
+  if (!inputTrack->trackParameters() || inputTrack->trackParameters()->empty()) {
+    ATH_MSG_DEBUG("Input track has no track parameters and cannot be fitted");
+    return resi;
+  }
+
+
+  auto pSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+      Acts::Vector3 {0, 0, origin}, Acts::Vector3{0, 0, -1});
+
+  Acts::MagneticFieldContext mfContext = getMagneticFieldContext(ctx);
+  Acts::CalibrationContext calibContext = Acts::CalibrationContext();
+
+  auto [sourceLinks, measurements] = getMeasurementsFromTrack(inputTrack);
+  auto trackParameters = getParametersFromTrack(inputTrack->trackParameters()->front(), inputVector, origin);
+  ATH_MSG_DEBUG("trackParameters: " << trackParameters.parameters().transpose());
+  ATH_MSG_DEBUG("position: " << trackParameters.position(gctx).transpose());
+  ATH_MSG_DEBUG("momentum: " << trackParameters.momentum().transpose());
+  ATH_MSG_DEBUG("charge: " << trackParameters.charge());
+  ATH_MSG_DEBUG("size of measurements : " << sourceLinks.size());
+
+  FaserActsOutlierFinder faserActsOutlierFinder{0};
+  faserActsOutlierFinder.cluster_z=clusz;
+  faserActsOutlierFinder.StateChiSquaredPerNumberDoFCut=10000.;
+  Acts::KalmanFitterOptions<MeasurementCalibrator, FaserActsOutlierFinder, Acts::VoidReverseFilteringLogic>
+      kfOptions(gctx, mfContext, calibContext, MeasurementCalibrator(measurements),
+                faserActsOutlierFinder, Acts::VoidReverseFilteringLogic(), Acts::LoggerWrapper{*m_logger},
+                //FaserActsOutlierFinder(), Acts::VoidReverseFilteringLogic(), Acts::LoggerWrapper{*m_logger},
+                //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);
+      myTrajectories.emplace_back(std::move(fitOutput.fittedStates),
+                                  std::move(trackTips),
+                                  std::move(indexedParams));
+      for (const FaserActsRecMultiTrajectory &traj : myTrajectories) {
+	const auto& mj = traj.multiTrajectory();
+	const auto& trackTips = traj.tips();
+	if(trackTips.empty())continue;
+	auto& trackTip = trackTips.front();
+	mj.visitBackwards(trackTip, [&](const auto &state) {
+	    auto typeFlags = state.typeFlags();
+	    if (not typeFlags.test(Acts::TrackStateFlag::OutlierFlag))
+	    {
+	    return true;
+	    }
+
+	    if (state.hasUncalibrated()&&state.hasSmoothed()) {
+	Acts::BoundTrackParameters parameter(
+	    state.referenceSurface().getSharedPtr(),
+	    state.smoothed(),
+	    state.smoothedCovariance());
+	auto covariance = state.smoothedCovariance();
+	    auto H = state.effectiveProjector();
+	    auto residual = state.effectiveCalibrated() - H * state.smoothed();
+	    const Tracker::FaserSCT_Cluster* cluster = state.uncalibrated().hit();
+	    const auto& surface = state.referenceSurface();
+	    Acts::BoundVector meas = state.projector().transpose() * state.calibrated();
+	    Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]);
+	    const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(meas[Acts::eBoundPhi], meas[Acts::eBoundTheta]);
+	    resi.push_back({local.x(),local.y(),parameter.position(gctx).x(), parameter.position(gctx).y(), parameter.position(gctx).z(), cluster,residual(Acts::eBoundLoc0),parameter});
+	    ATH_MSG_DEBUG("  residual/global position:   " << residual(Acts::eBoundLoc0)<<" "<<parameter.position(gctx).x()<<" "<<parameter.position(gctx).y()<<" "<<parameter.position(gctx).z());
+	    }
+	    return true;
+	});
+
+      }
+
+    } else {
+      ATH_MSG_DEBUG("No fitted parameters for track");
+    }
+  }
+  return resi;
+
+}
+
+//get the unbiased residual for IFT, i.e. remove whole IFT in the track fitting
+//output is a vector of the outliers
+//
+std::vector<TSOS4Residual>
+KalmanFitterTool::getUnbiasedResidual(const EventContext &ctx, const Acts::GeometryContext &gctx,
+                      Trk::Track* inputTrack,  const Acts::BoundVector& inputVector,
+                      bool isMC, double origin, std::vector<const Tracker::FaserSCT_Cluster*>& clusters, const Acts::BoundTrackParameters ini_Param) const {
+  std::vector<TSOS4Residual> resi;
+  resi.clear();
+  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 resi;
+  }
+
+  if (!inputTrack->trackParameters() || inputTrack->trackParameters()->empty()) {
+    ATH_MSG_DEBUG("Input track has no track parameters and cannot be fitted");
+    return resi;
+  }
+
+
+  auto pSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+      Acts::Vector3 {0, 0, origin}, Acts::Vector3{0, 0, -1});
+
+  Acts::MagneticFieldContext mfContext = getMagneticFieldContext(ctx);
+  Acts::CalibrationContext calibContext = Acts::CalibrationContext();
+
+  auto [sourceLinks, measurements] = getMeasurementsFromTrack(inputTrack/*, wafer_id*/, clusters);
+  ATH_MSG_DEBUG("trackParameters: " << ini_Param.parameters().transpose());
+  ATH_MSG_DEBUG("position: " << ini_Param.position(gctx).transpose());
+  ATH_MSG_DEBUG("momentum: " << ini_Param.momentum().transpose());
+  ATH_MSG_DEBUG("charge: " << ini_Param.charge());
+
+  FaserActsOutlierFinder faserActsOutlierFinder{0};
+  faserActsOutlierFinder.cluster_z=-1000000.;
+  faserActsOutlierFinder.StateChiSquaredPerNumberDoFCut=10000.;
+  Acts::KalmanFitterOptions<MeasurementCalibrator, FaserActsOutlierFinder, Acts::VoidReverseFilteringLogic>
+      kfOptions(gctx, mfContext, calibContext, MeasurementCalibrator(measurements),
+                faserActsOutlierFinder, 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, ini_Param, 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);
+      myTrajectories.emplace_back(std::move(fitOutput.fittedStates),
+                                  std::move(trackTips),
+                                  std::move(indexedParams));
+      for (const FaserActsRecMultiTrajectory &traj : myTrajectories) {
+	const auto& mj = traj.multiTrajectory();
+	const auto& trackTips = traj.tips();
+	if(trackTips.empty())continue;
+	auto& trackTip = trackTips.front();
+	mj.visitBackwards(trackTip, [&](const auto &state) {
+	    auto typeFlags = state.typeFlags();
+	    if (not typeFlags.test(Acts::TrackStateFlag::OutlierFlag))
+	    {
+	    return true;
+	    }
+
+	    if (state.hasUncalibrated()&&state.hasSmoothed()) {
+	Acts::BoundTrackParameters parameter(
+	    state.referenceSurface().getSharedPtr(),
+	    state.smoothed(),
+	    state.smoothedCovariance());
+	auto covariance = state.smoothedCovariance();
+	    auto H = state.effectiveProjector();
+	    auto residual = state.effectiveCalibrated() - H * state.smoothed();
+	    const Tracker::FaserSCT_Cluster* cluster = state.uncalibrated().hit();
+	    const auto& surface = state.referenceSurface();
+	    Acts::BoundVector meas = state.projector().transpose() * state.calibrated();
+	    Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]);
+	    const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(meas[Acts::eBoundPhi], meas[Acts::eBoundTheta]);
+	    resi.push_back({local.x(),local.y(),parameter.position(gctx).x(), parameter.position(gctx).y(), parameter.position(gctx).z(), cluster,residual(Acts::eBoundLoc0),parameter});
+	    }
+	    return true;
+	});
+
+      }
+
+    } else {
+      ATH_MSG_DEBUG("No fitted parameters for track");
+    }
+  }
+  return resi;
+
+}
+
+//get the unbiased residual for IFT, i.e. remove whole IFT in the track fitting
+//output is a vector of the outliers
+//
+std::vector<TSOS4Residual>
+KalmanFitterTool::getUnbiasedResidual(const EventContext &ctx, const Acts::GeometryContext &gctx,
+                      Trk::Track* inputTrack,  const Acts::BoundVector& inputVector,
+                      bool isMC, double origin) const {
+  std::vector<TSOS4Residual> resi;
+  resi.clear();
+  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 resi;
+  }
+
+  if (!inputTrack->trackParameters() || inputTrack->trackParameters()->empty()) {
+    ATH_MSG_DEBUG("Input track has no track parameters and cannot be fitted");
+    return resi;
+  }
+
+
+  auto pSurface = Acts::Surface::makeShared<Acts::PlaneSurface>(
+      Acts::Vector3 {0, 0, origin}, Acts::Vector3{0, 0, -1});
+
+  Acts::MagneticFieldContext mfContext = getMagneticFieldContext(ctx);
+  Acts::CalibrationContext calibContext = Acts::CalibrationContext();
+
+  auto [sourceLinks, measurements] = getMeasurementsFromTrack(inputTrack/*, wafer_id*/);
+  auto trackParameters = getParametersFromTrack(inputTrack->trackParameters()->front(), inputVector, origin);
+  ATH_MSG_DEBUG("trackParameters: " << trackParameters.parameters().transpose());
+  ATH_MSG_DEBUG("position: " << trackParameters.position(gctx).transpose());
+  ATH_MSG_DEBUG("momentum: " << trackParameters.momentum().transpose());
+  ATH_MSG_DEBUG("charge: " << trackParameters.charge());
+
+
+  FaserActsOutlierFinder faserActsOutlierFinder{0};
+  faserActsOutlierFinder.cluster_z=-1000000.;
+  faserActsOutlierFinder.StateChiSquaredPerNumberDoFCut=10000.;
+  Acts::KalmanFitterOptions<MeasurementCalibrator, FaserActsOutlierFinder, Acts::VoidReverseFilteringLogic>
+      kfOptions(gctx, mfContext, calibContext, MeasurementCalibrator(measurements),
+                faserActsOutlierFinder, 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);
+      myTrajectories.emplace_back(std::move(fitOutput.fittedStates),
+                                  std::move(trackTips),
+                                  std::move(indexedParams));
+      for (const FaserActsRecMultiTrajectory &traj : myTrajectories) {
+	const auto& mj = traj.multiTrajectory();
+	const auto& trackTips = traj.tips();
+	if(trackTips.empty())continue;
+	auto& trackTip = trackTips.front();
+	mj.visitBackwards(trackTip, [&](const auto &state) {
+	    auto typeFlags = state.typeFlags();
+	    if (not typeFlags.test(Acts::TrackStateFlag::OutlierFlag))
+	    {
+	    return true;
+	    }
+
+	    if (state.hasUncalibrated()&&state.hasSmoothed()) {
+	Acts::BoundTrackParameters parameter(
+	    state.referenceSurface().getSharedPtr(),
+	    state.smoothed(),
+	    state.smoothedCovariance());
+	auto covariance = state.smoothedCovariance();
+	    auto H = state.effectiveProjector();
+	    auto residual = state.effectiveCalibrated() - H * state.smoothed();
+	    const Tracker::FaserSCT_Cluster* cluster = state.uncalibrated().hit();
+	    const auto& surface = state.referenceSurface();
+	    Acts::BoundVector meas = state.projector().transpose() * state.calibrated();
+	    Acts::Vector2 local(meas[Acts::eBoundLoc0], meas[Acts::eBoundLoc1]);
+	    const Acts::Vector3 dir = Acts::makeDirectionUnitFromPhiTheta(meas[Acts::eBoundPhi], meas[Acts::eBoundTheta]);
+resi.push_back({local.x(),local.y(),parameter.position(gctx).x(), parameter.position(gctx).y(), parameter.position(gctx).z(), cluster,residual(Acts::eBoundLoc0),parameter});
+	    }
+	    return true;
+	    });
+
+      }
+
+    } else {
+      ATH_MSG_DEBUG("No fitted parameters for track");
+    }
+  }
+  return resi;
+
+}
+
 std::unique_ptr<Trk::Track>
 KalmanFitterTool::fit(const EventContext &ctx, const Acts::GeometryContext &gctx,
                       Trk::Track* inputTrack, const Acts::BoundVector& inputVector,
@@ -70,9 +393,12 @@ KalmanFitterTool::fit(const EventContext &ctx, const Acts::GeometryContext &gctx
   ATH_MSG_DEBUG("momentum: " << trackParameters.momentum().transpose());
   ATH_MSG_DEBUG("charge: " << trackParameters.charge());
 
-  Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic>
+  FaserActsOutlierFinder faserActsOutlierFinder{0};
+  faserActsOutlierFinder.cluster_z=-1000000.;
+  faserActsOutlierFinder.StateChiSquaredPerNumberDoFCut=10000.;
+  Acts::KalmanFitterOptions<MeasurementCalibrator, FaserActsOutlierFinder, Acts::VoidReverseFilteringLogic>
       kfOptions(gctx, mfContext, calibContext, MeasurementCalibrator(measurements),
-                Acts::VoidOutlierFinder(), Acts::VoidReverseFilteringLogic(), Acts::LoggerWrapper{*m_logger},
+                faserActsOutlierFinder, Acts::VoidReverseFilteringLogic(), Acts::LoggerWrapper{*m_logger},
                 Acts::PropagatorPlainOptions(), &(*pSurface));
   kfOptions.multipleScattering = false;
   kfOptions.energyLoss = false;
@@ -95,9 +421,6 @@ KalmanFitterTool::fit(const EventContext &ctx, const Acts::GeometryContext &gctx
       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));
@@ -172,6 +495,84 @@ Acts::MagneticFieldContext KalmanFitterTool::getMagneticFieldContext(const Event
 }
 
 
+std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>>
+KalmanFitterTool::getMeasurementsFromTrack(Trk::Track *track, std::vector<const Tracker::FaserSCT_Cluster*>& clusters) const {
+  const int kSize = 1;
+      ATH_MSG_DEBUG("clusters in refit "<<clusters.size());
+  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(auto cluster : clusters){
+      Identifier id = cluster->identify();
+      int ista = m_idHelper->station(id);
+      int ilay = m_idHelper->layer(id);
+      ATH_MSG_DEBUG("station/layer "<<ista<<" "<<ilay);
+      Identifier waferId = m_idHelper->wafer_id(id);
+      if (identifierMap->count(waferId) != 0) {
+      ATH_MSG_DEBUG("found the identifier "<<ista<<" "<<ilay);
+        Acts::GeometryIdentifier geoId = identifierMap->at(waferId);
+        IndexSourceLink sourceLink(geoId, measurements.size(), cluster);
+        Eigen::Matrix<double, 1, 1> pos {cluster->localPosition().x()};
+        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));
+      }
+  }
+  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);
+}
+
+std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>>
+KalmanFitterTool::getMeasurementsFromTrack(Trk::Track *track, Identifier& wafer_id) 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);
+}
 std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>>
 KalmanFitterTool::getMeasurementsFromTrack(Trk::Track *track) const {
   const int kSize = 1;
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.h b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.h
index 0894e3ab2139decc1f0950a89f6200dc9ea2930f..584cda2c98bf32d7050150a690a0926439e11f91 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.h
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/KalmanFitterTool.h
@@ -15,9 +15,54 @@
 #include "TrkTrack/Track.h"
 #include "TrkTrack/TrackCollection.h"
 #include "CreateTrkTrackTool.h"
+#include "TrackerIdentifier/FaserSCT_ID.h"
+#include "Identifier/Identifier.h"
 
+struct TSOS4Residual{
+  double fit_local_x;
+  double fit_local_y;
+  double fit_global_x;
+  double fit_global_y;
+  double fit_global_z;
+  const Tracker::FaserSCT_Cluster* cluster;
+  double residual;
+	Acts::BoundTrackParameters parameter;
+
+};
 
 class FaserSCT_ID;
+//set the cluster to be removed as outlier in order to get the unbiased residual
+/// Outlier finder using a Chi2 cut.
+struct FaserActsOutlierFinder {
+  double StateChiSquaredPerNumberDoFCut = 10000.;
+  double cluster_z = -10000.;
+  template <typename track_state_t>
+    bool operator()(const track_state_t& state) const {
+      //remove the whole IFT
+      if(cluster_z<-10000){
+	if(state.uncalibrated().hit()->globalPosition().z()<-100)return true;
+      }
+
+      if (not state.hasCalibrated() or not state.hasPredicted()) {
+	return false;
+      }
+      return Acts::visit_measurement(
+	  state.calibrated(), state.calibratedCovariance(),
+	  state.calibratedSize(),
+	  [&](const auto calibrated, const auto calibratedCovariance) {
+	  //remove the cluster
+	  if(fabs(state.uncalibrated().hit()->globalPosition().z()-cluster_z)<3)return true;
+	  constexpr size_t kMeasurementSize = decltype(calibrated)::RowsAtCompileTime;
+	  const auto H =
+	  state.projector()
+	  .template topLeftCorner<kMeasurementSize, Acts::BoundIndices::eBoundSize>()
+	  .eval();
+	  const auto residual = calibrated - H * state.predicted(); 
+	  double chi2 = (residual.transpose() * ((calibratedCovariance + H * state.predictedCovariance() * H.transpose())).inverse() * residual).value();
+	  return bool(chi2 > StateChiSquaredPerNumberDoFCut * kMeasurementSize);
+	  });
+    }
+};
 
 class KalmanFitterTool : virtual public AthAlgTool {
 public:
@@ -29,7 +74,8 @@ public:
   using TrackParameters = Acts::BoundTrackParameters;
   using IndexedParams = std::unordered_map<size_t, TrackParameters>;
   using TrackFitterOptions =
-      Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic>;
+      Acts::KalmanFitterOptions<MeasurementCalibrator, FaserActsOutlierFinder, Acts::VoidReverseFilteringLogic>;
+      //Acts::KalmanFitterOptions<MeasurementCalibrator, Acts::VoidOutlierFinder, Acts::VoidReverseFilteringLogic>;
   using TrackFitterResult = Acts::Result<Acts::KalmanFitterResult<IndexSourceLink>>;
   class TrackFitterFunction {
   public:
@@ -45,12 +91,27 @@ public:
                                   Trk::Track *inputTrack,
                                   const Acts::BoundVector& inputVector = Acts::BoundVector::Zero(),
                                   bool isMC=false, double origin=0) const;
+  std::vector<TSOS4Residual> getUnbiasedResidual(const EventContext &ctx, const Acts::GeometryContext &gctx,
+                                  Trk::Track *inputTrack,
+                                  const Acts::BoundVector& inputVector = Acts::BoundVector::Zero(),
+                                  bool isMC=false, double origin=0) const;
+  std::vector<TSOS4Residual> getUnbiasedResidual(const EventContext &ctx, const Acts::GeometryContext &gctx,
+                                  Trk::Track *inputTrack, double clusz,
+                                  const Acts::BoundVector& inputVector ,
+                                  bool isMC, double origin) const;
+  std::vector<TSOS4Residual> getUnbiasedResidual(const EventContext &ctx, const Acts::GeometryContext &gctx,
+                                  Trk::Track *inputTrack,
+                                  const Acts::BoundVector& inputVector ,
+                                  bool isMC, double origin, std::vector<const Tracker::FaserSCT_Cluster*>& clus,const Acts::BoundTrackParameters ini_Param) const;
 
 private:
   const FaserSCT_ID* m_idHelper {nullptr};
   std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>>
   getMeasurementsFromTrack(Trk::Track *track) const;
-  // Acts::BoundTrackParameters getParametersFromTrack(const Acts::BoundVector& params, const Trk::TrackParameters *inputParameters) const;
+  std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>>
+  getMeasurementsFromTrack(Trk::Track *track, Identifier& wafer_id) const;
+  std::tuple<std::vector<IndexSourceLink>, std::vector<Measurement>>
+  getMeasurementsFromTrack(Trk::Track *track, std::vector<const Tracker::FaserSCT_Cluster*>& clusters) const;
   Acts::BoundTrackParameters getParametersFromTrack(const Trk::TrackParameters *inputParameters, const Acts::BoundVector& inputVector, double origin) const;
   std::shared_ptr<TrackFitterFunction> m_fit;
   std::unique_ptr<const Acts::Logger> m_logger;
@@ -67,6 +128,12 @@ private:
   ToolHandle<RootTrajectoryStatesWriterTool> m_trajectoryStatesWriterTool {this, "RootTrajectoryStatesWriterTool", "RootTrajectoryStatesWriterTool"};
   ToolHandle<RootTrajectorySummaryWriterTool> m_trajectorySummaryWriterTool {this, "RootTrajectorySummaryWriterTool", "RootTrajectorySummaryWriterTool"};
   ToolHandle<CreateTrkTrackTool> m_createTrkTrackTool {this, "CreateTrkTrackTool", "CreateTrkTrackTool"};
+
+//  Acts::KalmanFitterExtensions<Acts::VectorMultiTrajectory> getExtensions();
+  
+//    FaserActsOutlierFinder  m_outlierFinder{0};
+//  ReverseFilteringLogic m_reverseFilteringLogic{0};
+//  Acts::KalmanFitterExtensions<Acts::VectorMultiTrajectory> m_kfExtensions;
 };
 
 #endif //FASERACTSKALMANFILTER_KALMANFITTERTOOL_H
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx
index f0d9796f1a16ce52aee2bf52dbc11ec28c96a7a5..7f9f427960ba221d8fd3f489cbb0e38d627ffc9f 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/TruthSeededTrackFinderTool.cxx
@@ -46,7 +46,7 @@ StatusCode TruthSeededTrackFinderTool::run() {
   SG::ReadHandle<SpacePointForSeedCollection> spacePointCollection {m_spacePointCollectionKey};
   ATH_CHECK(spacePointCollection.isValid());
 
-  Acts::GeometryContext geoctx = m_trackingGeometryTool->getNominalGeometryContext().context();
+  Acts::GeometryContext geoctx = m_trackingGeometryTool->getGeometryContext().context();
 
   std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry
       = m_trackingGeometryTool->trackingGeometry();
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.cxx
index bfd5e9b740bbeb53529fc2c6e1048656187e1d5a..672be6fa934ead4725a43d81bc2f5e156612449e 100644
--- a/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/TruthTrackFinderTool.cxx
@@ -39,7 +39,7 @@ StatusCode TruthTrackFinderTool::run() {
 
   using IdentifierMap = std::map<Identifier, Acts::GeometryIdentifier>;
   std::shared_ptr<IdentifierMap> identifierMap = m_trackingGeometryTool->getIdentifierMap();
-  Acts::GeometryContext gctx = m_trackingGeometryTool->getNominalGeometryContext().context();
+  Acts::GeometryContext gctx = m_trackingGeometryTool->getGeometryContext().context();
   const int kSize = 2;
   using ParametersVector = Acts::ActsVector<kSize>;
   using CovarianceMatrix = Acts::ActsSymMatrix<kSize>;
@@ -188,4 +188,4 @@ StatusCode TruthTrackFinderTool::run() {
 
 StatusCode TruthTrackFinderTool::finalize() {
   return StatusCode::SUCCESS;
-}
\ No newline at end of file
+}
diff --git a/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx b/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx
index d9fefbddfb3b5e651f5ac697ac231bb9e41918d3..be32f4959409c57903c674bf7fd5d28209ad295d 100755
--- a/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx
+++ b/Tracking/Acts/FaserActsKalmanFilter/src/components/FaserActsKalmanFilter_entries.cxx
@@ -23,6 +23,7 @@
 #include "../TrackSeedWriterTool.h"
 #include "../ActsTrackSeedTool.h"
 #include "../CKF2.h"
+#include "../CKF2Alignment.h"
 #include "../KalmanFitterTool.h"
 #include "../MyTrackSeedTool.h"
 #include "../SeedingAlg.h"
@@ -53,6 +54,7 @@ DECLARE_COMPONENT(PerformanceWriterTool)
 DECLARE_COMPONENT(TrackSeedWriterTool)
 DECLARE_COMPONENT(ActsTrackSeedTool)
 DECLARE_COMPONENT(CKF2)
+DECLARE_COMPONENT(CKF2Alignment)
 DECLARE_COMPONENT(KalmanFitterTool)
 DECLARE_COMPONENT(MyTrackSeedTool)
 DECLARE_COMPONENT(SeedingAlg)
diff --git a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h
index c30351902a1b79e9a58ad33d5f58a5d04ed13faa..37cb7af183c2d89b9ada3579f76820bfe6487c5c 100644
--- a/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h
+++ b/Waveform/WaveDigiTools/WaveDigiTools/IWaveformDigitisationTool.h
@@ -51,7 +51,7 @@ public:
   virtual std::vector<float> evaluate_timekernel(TF1* kernel) const = 0;
 
   /// Generate random baseline 
-  virtual unsigned int generate_baseline(int mean, int rms) const = 0;
+  virtual float generate_baseline(float mean, float rms) const = 0;
  
   /// Create structure to store pulse for each channel
   template <class T> 
diff --git a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx
index c62d7f8a753490907bd1e8a513cad5341a2a46be..3a48027d57e3710a2ec592aed6a9ed749b9f6848 100644
--- a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx
+++ b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.cxx
@@ -22,7 +22,7 @@ WaveformDigitisationTool::initialize() {
   ATH_MSG_INFO( name() << "::initalize()" );
 
   m_nsamples = 600;
-  m_random = new TRandom3();
+  m_random = new TRandom3(0);
 
   return StatusCode::SUCCESS;
 }
@@ -41,7 +41,7 @@ WaveformDigitisationTool::evaluate_timekernel(TF1* kernel) const {
   return timekernel;
 }
 
-unsigned int 
-WaveformDigitisationTool::generate_baseline(int mean, int rms) const {
+float
+WaveformDigitisationTool::generate_baseline(float mean, float rms) const {
   return m_random->Gaus(mean, rms);
 }
diff --git a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h
index e2dd5169152845824927baeeae7ce8fc36ab46f8..b6554c337830fbd2183752cc1b05123ea827b4f1 100644
--- a/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h
+++ b/Waveform/WaveDigiTools/src/WaveformDigitisationTool.h
@@ -32,7 +32,7 @@ class WaveformDigitisationTool: public extends<AthAlgTool, IWaveformDigitisation
   std::vector<float> evaluate_timekernel(TF1* kernel) const;
 
   /// Generate random baseline 
-  unsigned int generate_baseline(int mean, int rms) const;
+  float generate_baseline(float mean, float rms) const;
 
 
  private:
diff --git a/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx b/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx
index 8882027bfc13a7b28a7043f2b9feb70ed8e25877..f7ef9339ae32919ef6600cf099da2d42c5eb4a69 100644
--- a/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx
+++ b/Waveform/WaveRecTools/src/WaveformReconstructionTool.cxx
@@ -759,6 +759,12 @@ WaveformReconstructionTool::fitGaussian(const WaveformFitResult& raw, const std:
     // Find time here
     gfit.time = gfunc.GetX( gfit.peak * m_timingPeakFraction, time.front(), gfit.mean );
 
+    if (isnan(gfit.time)) {
+      ATH_MSG_WARNING(" Gaussian fit returned time as NaN, assume fit failed");
+      gfit = raw;
+      gfit.fit_status = false;
+    }
+
     ATH_MSG_DEBUG("G Fit   Mean: " << gfit.mean << " RMS: " << gfit.sigma 
 		  << " Peak: " << gfit.peak << " Int: " << gfit.integral << " Time: " << gfit.time);
   }
@@ -839,6 +845,12 @@ WaveformReconstructionTool::fitCBall(const WaveformFitResult& gfit,
     // Find time here
     cbfit.time = cbfunc.GetX( cbfit.peak * m_timingPeakFraction, time.front(), cbfit.mean );
 
+    if (isnan(cbfit.time)) {
+      ATH_MSG_WARNING(" Crystal Ball fit returned time as NaN, assume fit failes");
+      cbfit.time = gfit.time;
+      cbfit.fit_status = false;
+    }
+
     ATH_MSG_DEBUG("CB Fit  Mean: " << cbfit.mean << " RMS: " << cbfit.sigma 
 		  << " Peak: " << cbfit.peak << " Int: " << cbfit.integral
 		  << " Time: " << cbfit.time 
diff --git a/Waveform/WaveformConditions/WaveCondUtils/scripts/makeDigiDB.py b/Waveform/WaveformConditions/WaveCondUtils/scripts/makeDigiDB.py
index 202c5e266107d9e753c26b79d4de470d2f35653e..40e4247398e516c884152f5e30de34fd26977a8c 100755
--- a/Waveform/WaveformConditions/WaveCondUtils/scripts/makeDigiDB.py
+++ b/Waveform/WaveformConditions/WaveCondUtils/scripts/makeDigiDB.py
@@ -108,7 +108,13 @@ preshower_record['cb_sigma'] = 4.0
 preshower_record['cb_alpha'] = -0.32
 preshower_record['cb_n'] = 1000.
 
+# Dec. 10, 2022
+# Values: 0.56, 5.6, 16.8, 168
+# Dec. 19, 2022
+# Lowered by 10% to 0.51, 5.1, 15.3, 153
+
 # Low gain, filters in default
+calo_record['cb_norm'] = 0.51
 tag = "WAVE-Digitization-01-LG"
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, calo_record, 0, tag)
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, vetonu_record, 1, tag)
@@ -126,7 +132,7 @@ wave_folder.createTagRelation("OFLCOND-FASER-03", "WAVE-01")
 
 # Low gain, filters out
 tag = "WAVE-Digitization-01-LG-nofilt"
-calo_record['cb_norm'] = 5.6
+calo_record['cb_norm'] = 5.1
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, calo_record, 0, tag)
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, vetonu_record, 1, tag)
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, veto_record, 2, tag)
@@ -135,7 +141,7 @@ folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, preshower_record,
 
 # High gain
 tag = "WAVE-Digitization-01-HG"
-calo_record['cb_norm'] = 16.8
+calo_record['cb_norm'] = 15.3
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, calo_record, 0, tag)
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, vetonu_record, 1, tag)
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, veto_record, 2, tag)
@@ -144,7 +150,7 @@ folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, preshower_record,
 
 # High gain, filters out
 tag = "WAVE-Digitization-01-HG-nofilt"
-calo_record['cb_norm'] = 168
+calo_record['cb_norm'] = 153
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, calo_record, 0, tag)
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, vetonu_record, 1, tag)
 folder.storeObject( cool.ValidityKeyMin, cool.ValidityKeyMax, veto_record, 2, tag)