diff --git a/Control/AthenaConfiguration/python/AthConfigFlags.py b/Control/AthenaConfiguration/python/AthConfigFlags.py
index 9dde73038417965f09854d8dde1dc930bfc75e35..8c9e3d7e808906037c10e804776be94499d0ca67 100644
--- a/Control/AthenaConfiguration/python/AthConfigFlags.py
+++ b/Control/AthenaConfiguration/python/AthConfigFlags.py
@@ -172,11 +172,14 @@ class FlagAddress(object):
 
     def __iter__(self):
         self._flags.loadAllDynamicFlags()
+        rmap = self._flags._renamed_map()
         used = set()
         for flag in self._flags._flagdict.keys():
             if flag.startswith(self._name.rstrip('.') + '.'):
+                newflag = rmap[flag]
                 ntrim = len(self._name) + 1
-                remaining = flag[ntrim:].split('.',1)[0]
+                n_dots_in = flag[:ntrim].count('.')
+                remaining = newflag.split('.')[n_dots_in]
                 if remaining not in used:
                     yield remaining
                     used.add(remaining)
@@ -290,9 +293,10 @@ class AthConfigFlags(object):
 
     def __iter__(self):
         self.loadAllDynamicFlags()
+        rmap = self._renamed_map()
         used = set()
         for flag in self._flagdict:
-            first = flag.split('.',1)[0]
+            first = rmap[flag].split('.',1)[0]
             if first not in used:
                 yield first
                 used.add(first)
@@ -308,6 +312,11 @@ class AthConfigFlags(object):
 
 
     def _renamed_map(self):
+        """mapping from the old names to the new names
+
+        This is the inverse of _renamed, which maps new names to old
+        names
+        """
         def rename(key):
             for new, old in self._renames.items():
                 if key.startswith(old + '.'):
@@ -420,7 +429,7 @@ class AthConfigFlags(object):
         return False
 
     def hasFlag(self, name):
-        return name in self._flagdict
+        return name in self._renamed_map().values()
 
     def _set(self,name,value):
         self._tryModify()
@@ -465,6 +474,7 @@ class AthConfigFlags(object):
         cln = AthConfigFlags()
         cln._flagdict = deepcopy(self._flagdict)
         cln._dynaflags = copy(self._dynaflags)
+        cln._renames = deepcopy(self._renames)
         return cln
 
 
diff --git a/Control/AthenaConfiguration/test/testAthConfigFlags.py b/Control/AthenaConfiguration/test/testAthConfigFlags.py
index c0aa7dcc8a42116c7db6997acf6b7c2fdc377f85..a18ddac44a2a5ea3fdf692db7c717612a0812f6a 100755
--- a/Control/AthenaConfiguration/test/testAthConfigFlags.py
+++ b/Control/AthenaConfiguration/test/testAthConfigFlags.py
@@ -324,6 +324,30 @@ class TestFlagsSetupDynamic(FlagsSetup):
         self.assertTrue( self.flags.hasFlag("Z.A") )
         self.assertTrue( self.flags.hasCategory("Z.C") )
 
+    def test_cloneExists(self):
+        """test if flags can be found after cloning"""
+        clonef = self.flags.cloneAndReplace('W', 'Z')
+        clonef.loadAllDynamicFlags()
+        self.assertTrue(clonef.hasFlag('W.A'))
+        self.assertFalse(clonef.hasFlag('Z.A'))
+
+    def test_cloneIter(self):
+        # top level check
+        self.assertTrue('Z' in self.flags)
+        self.assertTrue('A' in self.flags.Z)
+        clonez2w = self.flags.cloneAndReplace('W', 'Z')
+        self.assertFalse('Z' in clonez2w)
+        self.assertTrue('W' in clonez2w)
+        self.assertFalse('Z' in clonez2w.W)
+        self.assertTrue('A' in clonez2w.W)
+
+        # check one level down
+        self.assertTrue('C' in self.flags.Z)
+        clonec2x = self.flags.cloneAndReplace('Z.X', 'Z.C')
+        self.assertTrue('X' in clonec2x.Z)
+        self.assertFalse('C' in clonec2x.Z)
+
+
     def test_cloneHash(self):
         # compare copy hash to clone hash, should be equal
         copyflags = copy.deepcopy(self.flags)
diff --git a/Control/AthenaPython/share/copy_file.py b/Control/AthenaPython/share/copy_file.py
deleted file mode 100644
index 3c3fd958330ff431ae3a6d75c42c44ae782e58be..0000000000000000000000000000000000000000
--- a/Control/AthenaPython/share/copy_file.py
+++ /dev/null
@@ -1,27 +0,0 @@
-## @file: AthenaPython/copy_file.py
-## @purpose: simple jobo to copy any file, leveraging the auto-config fwk
-## @date January 2010
-## @author Sebastien Binet <binet@cern.ch>
-
-__version__ = "$Revision: 293864 $"
-__author__  = "Sebastien Binet <binet@cern.ch>"
-__doc__ = "simple jobo to copy any file, leveraging the auto-config fwk"
-
-## percolate through the auto-configuration
-
-## input files configuration
-from AthenaCommon.AthenaCommonFlags import jobproperties as jp
-acf = jp.AthenaCommonFlags
-assert len(acf.FilesInput()) != 0, \
-       "this jobo fragment needs the autoconfig-fwk." \
-       "FilesInput needs to be filled"
-
-import AthenaPython.ConfigLib as apcl
-cfg = apcl.copy_file(src=acf.FilesInput(),
-                     dst="copy_file.pool")
-
-if cfg.is_rdo() or cfg.is_esd() or cfg.is_aod():
-    # main jobos
-    include ('RecExCond/RecExCommon_flags.py')
-    include ('RecExCommon/RecExCommon_topOptions.py')
-
diff --git a/Control/AthenaPython/share/icopy_file.py b/Control/AthenaPython/share/icopy_file.py
deleted file mode 100644
index ce7b1b4749fc5033d7030fc1d6bc4dac477ba5bf..0000000000000000000000000000000000000000
--- a/Control/AthenaPython/share/icopy_file.py
+++ /dev/null
@@ -1,35 +0,0 @@
-## @file: AthenaPython/icopy_file.py
-## @purpose: simple jobo to copy any file, leveraging the auto-config fwk
-## @date January 2010
-## @author Sebastien Binet <binet@cern.ch>
-
-__version__ = "$Revision: 293864 $"
-__author__  = "Sebastien Binet <binet@cern.ch>"
-__doc__ = "simple jobo to copy any file, leveraging the auto-config fwk"
-
-## percolate through the auto-configuration
-
-## input files configuration
-from AthenaCommon.AthenaCommonFlags import jobproperties as jp
-acf = jp.AthenaCommonFlags
-_input_files = globals()['FNAME']
-if isinstance(_input_files, str):
-    _input_files = [_input_files]
-acf.FilesInput = _input_files
-del _input_files
-
-# events to process
-acf.EvtMax = EvtMax = theApp.EvtMax = globals().get('EVTMAX', -1)
-
-import AthenaPython.ConfigLib as apcl
-cfg = apcl.AutoCfg(name='copy-file',
-                   input_files=acf.FilesInput(),
-                   output_file=globals().get('OFNAME', 'copy_file.pool'))
-cfg.configure_job()
-
-if cfg.is_rdo() or cfg.is_esd() or cfg.is_aod():
-    # main jobos
-    include ('RecExCond/RecExCommon_flags.py')
-    include ('RecExCommon/RecExCommon_topOptions.py')
-
-
diff --git a/Control/AthenaPython/share/iread_file.py b/Control/AthenaPython/share/iread_file.py
deleted file mode 100644
index 398d27da60ccb274518fe26f7f040284c329b079..0000000000000000000000000000000000000000
--- a/Control/AthenaPython/share/iread_file.py
+++ /dev/null
@@ -1,25 +0,0 @@
-## @file: AthenaPython/iread_file.py
-## @purpose: simple jobo to read any file, leveraging the auto-config fwk
-## @date January 2010
-## @author Sebastien Binet <binet@cern.ch>
-
-__version__ = "$Revision: 273745 $"
-__author__  = "Sebastien Binet <binet@cern.ch>"
-__doc__ = "simple jobo to read any file, leveraging the auto-config fwk"
-
-## percolate through the auto-configuration
-
-## input files configuration
-from AthenaCommon.AthenaCommonFlags import jobproperties as jp
-acf = jp.AthenaCommonFlags
-_input_files = globals().get('FNAME', [])
-if isinstance(_input_files, str):
-    _input_files = [_input_files]
-acf.FilesInput = _input_files
-del _input_files
-
-# events to process
-acf.EvtMax = EvtMax = globals().get('EVTMAX', -1)
-
-# main jobos
-include('AthenaPython/read_file.py')
diff --git a/Control/AthenaPython/share/read_file.py b/Control/AthenaPython/share/read_file.py
deleted file mode 100644
index 968462572a3e2fe1ddf87f5c1f148c06538087e1..0000000000000000000000000000000000000000
--- a/Control/AthenaPython/share/read_file.py
+++ /dev/null
@@ -1,30 +0,0 @@
-## @file: AthenaPython/read_file.py
-## @purpose: simple jobo to read any file, leveraging the auto-config fwk
-## @date November 2009
-## @author Sebastien Binet <binet@cern.ch>
-
-__version__ = "$Revision: 279865 $"
-__author__  = "Sebastien Binet <binet@cern.ch>"
-__doc__ = "simple jobo to read any file, leveraging the auto-config fwk"
-
-## percolate through the auto-configuration
-
-## input files configuration
-from AthenaCommon.AthenaCommonFlags import jobproperties as jp
-acf = jp.AthenaCommonFlags
-assert len(acf.FilesInput()) != 0, \
-       "this jobo fragment needs the autoconfig-fwk." \
-       "FilesInput needs to be filled"
-
-from AthenaConfiguration.AllConfigFlags import ConfigFlags
-ConfigFlags.Input.Files = acf.FilesInput()
-
-import AthenaPython.ConfigLib as apcl
-cfg = apcl.AutoCfg(name='read-file',
-                   input_files=acf.FilesInput())
-cfg.configure_job()
-
-if not cfg.is_evgen():
-    # main jobos
-    include ('RecExCond/RecExCommon_flags.py')
-    include ('RecExCommon/RecExCommon_topOptions.py')
diff --git a/Control/StoreGate/src/SGHiveMgrSvc.h b/Control/StoreGate/StoreGate/SGHiveMgrSvc.h
similarity index 85%
rename from Control/StoreGate/src/SGHiveMgrSvc.h
rename to Control/StoreGate/StoreGate/SGHiveMgrSvc.h
index 8621f0c85745b74416062db176c5a0f4bbdf136a..c4d9dec45d8777be971717a1311df3cedf746ffd 100644
--- a/Control/StoreGate/src/SGHiveMgrSvc.h
+++ b/Control/StoreGate/StoreGate/SGHiveMgrSvc.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef STOREGATE_HIVEMGRSVC_H
@@ -19,17 +19,19 @@
 
 class StoreGateSvc;
 class ISvcLocator;
-
+class HltEventLoopMgr;       // friend
+class HltAsyncEventLoopMgr;  // friend
 
 /** @class HiveMgrSvc
  *  @brief A service that manages a multi-event collection of StoreGateSvc
  *  It implements the IHiveWhiteBoard interface
  *
- *  $Id: SGHiveMgrSvc.h 794852 2017-01-31 23:24:04Z leggett $
  **/
 namespace SG {
 class HiveMgrSvc : public extends<Service, IHiveWhiteBoard> {
   friend class TestSGHiveMgrSvc;
+  friend class ::HltEventLoopMgr;
+  friend class ::HltAsyncEventLoopMgr;
 public:
   //@{ @name IHiveWhiteBoard implementation
   /** Activate an given 'slot' for all subsequent calls within the
@@ -106,12 +108,21 @@ public:
   virtual ~HiveMgrSvc() {}
 
 private:
+  /** Set number of concurrent processes
+   *
+   * This can only be called by "friends" of this class. Its sole purpose
+   * is to have a common entry point within ATLAS to call the private
+   * methods of Gaudi::ConcurrencyFlags.
+   *
+   * @param numProcs  [IN]   Number of concurrent processes
+   */
+  static void setNumProcs(size_t numProcs);
+
   ServiceHandle<StoreGateSvc> m_hiveStore;
   size_t m_nSlots; //property settable also by setNumberOfStores
   std::vector<SG::HiveEventSlot> m_slots;
   std::mutex m_mutex; //< protects m_slots access
   std::atomic<size_t> m_freeSlots {0};
-  //maybe  ServiceHandle<ActiveStoreSvc> m_active;
 
 };
 } //namespace SG
diff --git a/Control/StoreGate/src/SGHiveMgrSvc.cxx b/Control/StoreGate/src/SGHiveMgrSvc.cxx
index 8f3a7b9b18a2ff9a668e8ac92212679ad547782e..d9f245020076ecfb2b9bd814b2257438cc476b17 100644
--- a/Control/StoreGate/src/SGHiveMgrSvc.cxx
+++ b/Control/StoreGate/src/SGHiveMgrSvc.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "GaudiKernel/ConcurrencyFlags.h"
@@ -8,7 +8,7 @@
 #include "AthenaKernel/StoreID.h"
 #include "StoreGate/StoreGateSvc.h"
 #include "StoreGate/tools/SGImplSvc.h"
-#include "SGHiveMgrSvc.h"
+#include "StoreGate/SGHiveMgrSvc.h"
 
 using namespace SG;
 
@@ -24,6 +24,18 @@ HiveMgrSvc::HiveMgrSvc(const std::string& name,
 }
 
 
+/** Set number of concurrent processes
+ *
+ * This can only be called by "friends" of this class. Its sole purpose
+ * is to have a common entry point within ATLAS to call the private
+ * methods of Gaudi::ConcurrencyFlags.
+ *
+ * @param numProcs  [IN]   Number of concurrent processes
+ */
+void HiveMgrSvc::setNumProcs(size_t numProcs)
+{
+  Gaudi::Concurrency::ConcurrencyFlags::setNumProcs(numProcs);
+}
 
 /** Activate an given 'slot' for all subsequent calls within the
  * same thread id.
diff --git a/Control/StoreGate/src/components/StoreGateSvc_entries.cxx b/Control/StoreGate/src/components/StoreGateSvc_entries.cxx
index 68da1664d271c092aca4b52075d40ab03cfd6ee8..2dd23462ada7af5ca1faa2255dd76ebd4594e98b 100644
--- a/Control/StoreGate/src/components/StoreGateSvc_entries.cxx
+++ b/Control/StoreGate/src/components/StoreGateSvc_entries.cxx
@@ -2,7 +2,7 @@
 #include "StoreGate/ActiveStoreSvc.h"
 #include "StoreGate/tools/SGImplSvc.h"
 #include "StoreGate/SegMemSvc.h"
-#include "../SGHiveMgrSvc.h"
+#include "StoreGate/SGHiveMgrSvc.h"
 
 DECLARE_COMPONENT( ActiveStoreSvc )
 DECLARE_COMPONENT( StoreGateSvc )
diff --git a/Control/StoreGate/test/SGHive_test.cxx b/Control/StoreGate/test/SGHive_test.cxx
index 69969e475d31df3a387e4e7f9990fb3f934adcd9..7bb1b153abdfc3cf665f5d3e566c33021700e2f6 100644
--- a/Control/StoreGate/test/SGHive_test.cxx
+++ b/Control/StoreGate/test/SGHive_test.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 /***************************************************************************
@@ -14,7 +14,7 @@
 #include "TestTools/initGaudi.h"
 #include "TestTools/SGassert.h"
 #include "GaudiKernel/IHiveWhiteBoard.h"
-#include "../src/SGHiveMgrSvc.h"
+#include "StoreGate/SGHiveMgrSvc.h"
 #include "StoreGate/StoreGateSvc.h"
 #include "StoreGate/SGtests.h"
 
diff --git a/Control/StoreGate/test/SGTiming_test.cxx b/Control/StoreGate/test/SGTiming_test.cxx
index dbe3a1345152545edec6a59ce856f8975a7cd927..5e9aa31e62ec4c3369b327d94ed7902a5d4613b6 100644
--- a/Control/StoreGate/test/SGTiming_test.cxx
+++ b/Control/StoreGate/test/SGTiming_test.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 #undef NDEBUG
@@ -10,7 +10,7 @@
 #include "TestTools/initGaudi.h"
 #include "TestTools/SGassert.h"
 #include "GaudiKernel/IHiveWhiteBoard.h"
-#include "../src/SGHiveMgrSvc.h"
+#include "StoreGate/SGHiveMgrSvc.h"
 #include "StoreGate/StoreGateSvc.h"
 #include "StoreGate/SGtests.h"
 
diff --git a/DataQuality/DataQualityConfigurations/config/AFP/collisions_run.config b/DataQuality/DataQualityConfigurations/config/AFP/collisions_run.config
index d8c3d56d2e2127e77f05caad3e4437c5a1748383..189700ad9722f444c9cf31beecf4fe8a9f26436a 100644
--- a/DataQuality/DataQualityConfigurations/config/AFP/collisions_run.config
+++ b/DataQuality/DataQualityConfigurations/config/AFP/collisions_run.config
@@ -107,6 +107,10 @@ output top_level {
 					}
 				}
 			}
+			output CrossBar {
+				output side${side} {
+				}
+			}
 		}
 		output ToFSiTCorr {
 		}
@@ -538,6 +542,14 @@ dir AFP {
 				}
 			}
 		}
+		dir CrossBar {
+			dir side(?P<side>A|C) {
+				regex = 1
+				output = AFP/ToF/CrossBar/side${side}
+				hist crossBarDeltaT_(?P=side)_[0123](AB|AC|AD|BC|BD|CD) {
+				} 
+			}
+		}
 	}
 	dir ToFSiTCorr {
 		output = AFP/ToFSiTCorr
diff --git a/DataQuality/DataQualityUtils/src/HanOutputFile.cxx b/DataQuality/DataQualityUtils/src/HanOutputFile.cxx
index 4356d006fc498ec410cd36bb10832d3d0330a159..c693a4d54510f9e8145f0d422529c20e39337dd7 100644
--- a/DataQuality/DataQualityUtils/src/HanOutputFile.cxx
+++ b/DataQuality/DataQualityUtils/src/HanOutputFile.cxx
@@ -32,6 +32,7 @@
 #include <TStyle.h>
 #include <TText.h>
 #include <TImageDump.h>
+#include <TFrame.h>
 
 #include <boost/algorithm/string/case_conv.hpp>
 #include <boost/lexical_cast.hpp>
@@ -633,7 +634,7 @@ namespace dqutils
         return "Undefined";
       }
       // Extract JSON object
-      TObjString* JSON_obj = dynamic_cast<TObjString*>(gDirectory->GetKey(JSON_name.c_str())->ReadObj());
+      std::unique_ptr<TObjString> JSON_obj(dynamic_cast<TObjString*>(gDirectory->GetKey(JSON_name.c_str())->ReadObj()));
       if (not JSON_obj)
       {
         std::cerr << "HanOutputFile::getInfo : dynamic cast failed\n";
@@ -1052,6 +1053,7 @@ namespace dqutils
             {
               o << " title " << hisTitle << "\n";
             }
+            delete h;
           }
           else
           {
@@ -1892,7 +1894,7 @@ namespace dqutils
             if (colln)
             {
               WasCollectionReference = true;
-              TIterator* icolln = colln->MakeIterator();
+              std::unique_ptr<TIterator> icolln(colln->MakeIterator());
               TObject* ref2;
               while ((ref2 = icolln->Next()))
               {
@@ -2300,7 +2302,7 @@ namespace dqutils
     //deallocate image buffer with free(x), see https://root.cern.ch/doc/master/classTASImage.html
     free(x);
     delete hobj;
-    delete hRef;
+    delete ref;
     delete legend;
     return rvPair;
   }
@@ -3188,36 +3190,41 @@ namespace dqutils
     //////
     TProfile* phRef = dynamic_cast<TProfile*>(hRef);
     TProfile* ph = dynamic_cast<TProfile*>(h);
-    TH1F* clonehist;
-    TH1F* clonehistref;
+    std::unique_ptr<TH1F> clonehist; // we will release this later, but use a unique_ptr in case we return early
+    std::unique_ptr<TH1F> clonehistref;
     // transform if profiles
     if (ph != 0)
     {
-      clonehist = (TH1F*)ph->ProjectionX();
+      clonehist.reset((TH1F*)ph->ProjectionX());
     }
     else
     {
-      clonehist = (TH1F*)h->Clone();
-      clonehist->Sumw2();
+      clonehist.reset((TH1F*)h->Clone());
+      if (!clonehist->GetSumw2()) {
+        clonehist->Sumw2();
+      }
     }
     if (phRef != 0)
     {
-      clonehistref = (TH1F*)phRef->ProjectionX();
+      clonehistref.reset((TH1F*)phRef->ProjectionX());
     }
     else
     {
-      clonehistref = (TH1F*)hRef->Clone();
-      clonehistref->Sumw2();
+      clonehistref.reset((TH1F*)hRef->Clone());
+      if (!clonehist->GetSumw2()) {
+        clonehistref->Sumw2();
+      }
     }
     if (!clonehist or !clonehistref)
     {
       return;
     }
-    clonehist->Divide(clonehistref);
+    clonehist->SetBit(kCanDelete);
+    clonehist->Divide(clonehistref.get());
     /// Error Bars fixed
     //////
 
-    formatTH1(myC_ratiopad.get(), clonehist);
+    formatTH1(myC_ratiopad.get(), clonehist.get());
     clonehist->SetTitle("");
 
     // extract delta value from string that holds the draw options
@@ -3230,42 +3237,69 @@ namespace dqutils
 
     clonehist->GetYaxis()->SetNdivisions(3, true);
     clonehist->SetMarkerStyle(1);
-    clonehist->Draw("E");
+    clonehist->Draw("E"); // plots into myC_ratiopad
     clonehist->GetXaxis()->SetTitleSize(0.11);
     clonehist->GetXaxis()->SetLabelSize(0.11);
     clonehist->GetYaxis()->SetTitleSize(0.11);
     clonehist->GetYaxis()->SetLabelSize(0.11);
-    myC_main->cd();
-    TPad* lowerPad = new TPad("lowerPad", "lowerPad", .005, .060, .995, .250);
+    myC_main->cd(); // lowerPad and upperPad plotted into myC_main
+    TPad* lowerPad = new TPad("lowerPad", "lowerPad", .005, .060, .995, .250); // deleted by myC_main
     lowerPad->SetTopMargin(0);
     lowerPad->SetFillStyle(0);
     lowerPad->Draw();
-    TPad* upperPad = new TPad("upperPad", "upperPad", .005, .250, .995, .995);
+    TPad* upperPad = new TPad("upperPad", "upperPad", .005, .250, .995, .995); // deleted by myC_main
     upperPad->SetBottomMargin(0);
     upperPad->SetFillStyle(0);
     upperPad->Draw();
 
     lowerPad->cd();
-    myC_ratiopad->DrawClonePad();
+    myC_ratiopad->DrawClonePad(); // clone contents of myC_ratiopad to lowerPad (will fix ownership later)
     // Draw y=1 lineon ratio plot
-    TLine* line = new TLine;
-    line->SetLineColor(kRed);
-    line->SetLineWidth(1);
+    TLine line;
+    line.SetLineColor(kRed);
+    line.SetLineWidth(1);
     // method belove might be a problem when axis range changed
     double xmin = clonehist->GetXaxis()->GetXmin();
     double xmax = clonehist->GetXaxis()->GetXmax();
     // double xmin = BINLOEDGE(clonehist, 1)-BINWIDTH(clonehist, 1);
     // double xmax = BINLOEDGE(clonehist, clonehist->GetNbinsX() ) +  2.0*BINWIDTH(clonehist, clonehist->GetNbinsX() ) ;
-    line->DrawLine(xmin, 1, xmax, 1);
+    line.DrawLine(xmin, 1, xmax, 1);
     upperPad->cd();
     myC_upperpad->SetBottomMargin(0);
     myC_upperpad->SetFillStyle(0);
     h->GetXaxis()->SetLabelSize(0.);
     h->GetXaxis()->SetTitleSize(0.);
-    myC_upperpad->DrawClonePad();
+    myC_upperpad->DrawClonePad(); // clone original canvas (i.e. main plot) into upperPad (will fix ownership later)
     myC_upperpad->cd();
-    myC_upperpad->Clear();
-    myC_main->DrawClonePad();
+    myC_upperpad->Clear(); // reset original canvas
+    myC_main->DrawClonePad(); // clone contents of myC_main back into original canvas (will fix ownership shortly)
+    clonehist.release(); // this will be deleted by lowerpad cleanup
+    // At this point myC_main contains the original lowerPad and upperPad, which contain clones of the original canvas
+    // and ownership of clonehist. Iterate one level down and mark contained objects as deleteable. This will delete
+    // the pads, as well as clonehist.
+    for (TObject* o : *(myC_main->GetListOfPrimitives())) {
+      o->SetBit(kCanDelete);
+      if (auto* o2 = dynamic_cast<TPad*>(o)) {
+        for (auto* o3: *(o2->GetListOfPrimitives())) {
+          if (!dynamic_cast<TFrame*>(o3)) {
+            o3->SetBit(kCanDelete);
+          }
+        }
+      }
+    }
+    // At this point myC_upperpad contains clones of all its objects, including the pads. None of them have pointers
+    // outside of myC_upperpad and its contained cloned pads. Mark them all deleteable. The original plot will be deleted
+    // in the calling code.
+    for (TObject* o : *(myC_upperpad->GetListOfPrimitives())) {
+      o->SetBit(kCanDelete);
+      if (auto* o2 = dynamic_cast<TPad*>(o)) {
+        for (auto* o3: *(o2->GetListOfPrimitives())) {
+          if (!dynamic_cast<TFrame*>(o3)) {
+            o3->SetBit(kCanDelete);
+          }
+        }
+      }
+    }
   }
 
   void HanOutputFile::ratioplot2D(TCanvas* canvas_top, TH2* h2, TH2* h2Ref, std::string display)
diff --git a/Event/xAOD/xAODTrigger/Root/gFexJetRoI_v1.cxx b/Event/xAOD/xAODTrigger/Root/gFexJetRoI_v1.cxx
index ad2080b6776b7fe4824c16b77bd5a61187e736fe..ddae643da25c4eded4cf07b573e8fe3dd0ddefff 100755
--- a/Event/xAOD/xAODTrigger/Root/gFexJetRoI_v1.cxx
+++ b/Event/xAOD/xAODTrigger/Root/gFexJetRoI_v1.cxx
@@ -138,14 +138,6 @@ namespace xAOD {
   int16_t gFexJetRoI_v1::unpackEt() const {
   // Data content = TOB
     int16_t energy = (word() >> s_etBit) & s_etMask; 
-    int SIGNMASK = 0x0800;
-    int EXTENDS =  0xF000;
-    if (gFexType() == gRho){
-      if( (SIGNMASK & energy ) ) {
-            energy = ( EXTENDS  | energy); 
-      }
-    }
-
     return energy; 
   }
 
diff --git a/ForwardDetectors/AFP/AFP_Digitization/CMakeLists.txt b/ForwardDetectors/AFP/AFP_Digitization/CMakeLists.txt
index 7ff5d2e1167c6950eff43770b6c7d003a8f9aa51..a9a830504934fe146e8d0abcb7b6627229b1f926 100644
--- a/ForwardDetectors/AFP/AFP_Digitization/CMakeLists.txt
+++ b/ForwardDetectors/AFP/AFP_Digitization/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 
 # Declare the package name:
 atlas_subdir( AFP_Digitization )
@@ -16,4 +16,3 @@ atlas_add_component( AFP_Digitization
 
 # Install files from the package:
 atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
-atlas_install_joboptions( share/*.py )
diff --git a/ForwardDetectors/AFP/AFP_Digitization/share/AFP_Digitization_JobOptions.py b/ForwardDetectors/AFP/AFP_Digitization/share/AFP_Digitization_JobOptions.py
deleted file mode 100644
index c0155265b2169bd247831363014d55adef6db9e1..0000000000000000000000000000000000000000
--- a/ForwardDetectors/AFP/AFP_Digitization/share/AFP_Digitization_JobOptions.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from AthenaCommon.AlgSequence                  import AlgSequence
-job = AlgSequence()
-from AthenaCommon import CfgGetter
-job += CfgGetter.getAlgorithm("AFP_DigiTop/AFP_DigiTop", tryDefaultConfigurable=True)
-afp = job.AFP_DigiTop.DigitizationTool
diff --git a/ForwardDetectors/AFP/AFP_Digitization/share/AFP_PileUpTool_JobOptions.py b/ForwardDetectors/AFP/AFP_Digitization/share/AFP_PileUpTool_JobOptions.py
deleted file mode 100644
index 6035491a62f0da415d3aef316292e01a7bc7837c..0000000000000000000000000000000000000000
--- a/ForwardDetectors/AFP/AFP_Digitization/share/AFP_PileUpTool_JobOptions.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from AthenaCommon.AlgSequence import AlgSequence
-job = AlgSequence()
-from AthenaCommon import CfgGetter
-job.PileUpToolsAlg.PileUpTools += [  CfgGetter.getPrivateTool("AFP_PileUpTool", checkType=True) ]
-afpPileUpTool = job.PileUpToolsAlg.PileUpTools[ "AFP_PileUpTool" ]
diff --git a/ForwardDetectors/AFP/AFP_Digitization/share/DigitizationRTT_AFP.py b/ForwardDetectors/AFP/AFP_Digitization/share/DigitizationRTT_AFP.py
deleted file mode 100644
index 71a02d5f15d9ec32295cc791cc3a0bd78b47c732..0000000000000000000000000000000000000000
--- a/ForwardDetectors/AFP/AFP_Digitization/share/DigitizationRTT_AFP.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from AthenaCommon.AthenaCommonFlags import jobproperties
-
-jobproperties.AthenaCommonFlags.PoolHitsInput = ["atlasG4.hits.pool.root"]
-jobproperties.AthenaCommonFlags.PoolRDOOutput =  "digi.pool.root"
-jobproperties.AthenaCommonFlags.EvtMax = -1
-
-from AthenaCommon.GlobalFlags import jobproperties
-
-jobproperties.Global.DetDescrVersion = 'ATLAS-GEO-20-00-01'
-
-
-from AthenaCommon.DetFlags import DetFlags
-
-DetFlags.AFP_setOn()
-DetFlags.Truth_setOn()
-
-include("Digitization/Digitization.py")
-
-Service("StoreGateSvc").ActivateHistory = False
-Service("GeoModelSvc").IgnoreTagDifference = True
-
diff --git a/ForwardDetectors/AFP/AFP_GeoModel/python/AFP_GeoModel_joboption.py b/ForwardDetectors/AFP/AFP_GeoModel/python/AFP_GeoModel_joboption.py
deleted file mode 100644
index 2b0f11719812047c12a4600a7fd42b282e1b91bc..0000000000000000000000000000000000000000
--- a/ForwardDetectors/AFP/AFP_GeoModel/python/AFP_GeoModel_joboption.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-
-from IOVDbSvc.CondDB import conddb
-from AFP_GeoModel.AFP_GeoModelConf import AFP_DetectorTool
-
-def getAFP_DetectorTool(name="AFP_DetectorTool"):
-
-	#instatiate the tool
-	theAFP_DetectorTool=AFP_DetectorTool(name)
-
-	return theAFP_DetectorTool
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/Run3AFPMonitoring/AFPToFAlgorithm.h b/ForwardDetectors/AFP/Run3AFPMonitoring/Run3AFPMonitoring/AFPToFAlgorithm.h
index 04a494e0d5969325085492c8743b5e333ceba7ad..3edc0390aa739fdd6be098b5e777dde464015a88 100644
--- a/ForwardDetectors/AFP/Run3AFPMonitoring/Run3AFPMonitoring/AFPToFAlgorithm.h
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/Run3AFPMonitoring/AFPToFAlgorithm.h
@@ -10,6 +10,8 @@
 #include "StoreGate/ReadHandleKey.h"
 #include "xAODForward/AFPToFHitContainer.h"
 #include "xAODForward/AFPToFHit.h"
+#include "xAODForward/AFPTrackContainer.h"
+#include "xAODForward/AFPTrack.h"
 #include "LumiBlockData/BunchCrossingCondData.h"
 
 #include "TRandom3.h"
@@ -20,13 +22,16 @@ public:
 	virtual ~AFPToFAlgorithm();
 	virtual StatusCode initialize() override;
 	virtual StatusCode fillHistograms( const EventContext& ctx ) const override;
+	virtual StatusCode fillHistograms_crossBarDeltaT( const xAOD::AFPTrackContainer&, const xAOD::AFPToFHitContainer& ) const;
 
 private:
 	std::map<std::string,int> m_StationNamesGroup;
 	std::map<std::string,int> m_TrainsToFGroup;
 	std::map<std::string,std::map<std::string,int>> m_BarsInTrainsA;
 	std::map<std::string,std::map<std::string,int>> m_BarsInTrainsC;
+	std::map<std::string,int> m_GroupChanCombDeltaT;
 	SG::ReadHandleKey<xAOD::AFPToFHitContainer> m_afpToFHitContainerKey;
+	SG::ReadHandleKey<xAOD::AFPTrackContainer> m_afpTrackContainerKey;
 	SG::ReadCondHandleKey<BunchCrossingCondData> m_bunchCrossingKeyToF{this, "BunchCrossingKey", "BunchCrossingData", "Key BunchCrossing CDO" };
 
 protected:
@@ -37,7 +42,12 @@ protected:
 	std::vector<std::string> m_trainsToFA = { "T0", "T1" , "T2" , "T3" };
 	std::vector<std::string> m_trainsToFC = { "T0", "T1" , "T2" , "T3" };
 	std::vector<std::string> m_barsToF = { "A", "B" , "C" , "D" };
-	
+
+	std::vector<std::string> m_chanComb = {
+		"0AB", "0AC", "0AD", "0BC", "0BD", "0CD",
+		"1AB", "1AC", "1AD", "1BC", "1BD", "1CD",
+		"2AB", "2AC", "2AD", "2BC", "2BD", "2CD",
+		"3AB", "3AC", "3AD", "3BC", "3BD", "3CD"};
 };
 #endif
 
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/python/Run3AFPExampleMonitorAlgorithm.py b/ForwardDetectors/AFP/Run3AFPMonitoring/python/Run3AFPExampleMonitorAlgorithm.py
index f26948decd3f601c88c8f29736a08db6f119f794..a9f389fce7a335ca4c518dbc329fb8a3e3d0c3b6 100644
--- a/ForwardDetectors/AFP/Run3AFPMonitoring/python/Run3AFPExampleMonitorAlgorithm.py
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/python/Run3AFPExampleMonitorAlgorithm.py
@@ -48,7 +48,7 @@ def Run3AFPExampleMonitoringConfig(inputFlags):
     xLabelsStationsPlanes = ['fA3','fA2','fA1','fA0','nA3','nA2','nA1','nA0','nC0','nC1','nC2','nC3','fC0','fC1','fC2','fC3']
     xLabelsForEventsPerStation = [ 'fA', '-','-','-', 'nA', '-', '-', '-', 'nC', '-', '-', '-', 'fC', '-', '-', '-', ]
     xLabelsHitBarVsTrain = [ 'A', 'B', 'C', 'D']
-    yLabelsHitBarVsTrain = [ '3', '2', '1', '0']
+    yLabelsHitBarVsTrain = [ '0', '1', '2', '3']
     xLabelsToFEff = [ 'A', 'B', 'C', 'D', 'Tr']
     yLabelsToFEff = [ '0', '1', '2', '3']
     #xLabelsStationsPlanesProposed = ['fC3', 'fC2', 'fC1', 'fC0', 'nC3', 'nC2', 'nC1', 'nC0', 'nA0', 'nA1', 'nA2', 'nA3', 'fA0', 'fA1' 'fA2','fA3']
@@ -237,7 +237,12 @@ def Run3AFPExampleMonitoringConfig(inputFlags):
     arrayToF.defineHistogram('lbAToF', title='ToF hits vs lumiblock divided by <mu> (train {0}, bar {1}), side A; lb; hits/<mu>', type='TH1F', path='ToFHitsVsLb/sideA', xbins=2000, xmin=0.5, xmax=2000.5, weight = 'lbAToF_Weight')
     arrayToF.defineHistogram('lbCToF', title='ToF hits vs lumiblock divided by <mu> (train {0}, bar {1}), side C; lb; hits/<mu>', type='TH1F', path='ToFHitsVsLb/sideC', xbins=2000, xmin=0.5, xmax=2000.5, weight = 'lbCToF_Weight')
     
-    
+    #array for ToF cross-bar delta t
+    chan_combinations_list = [  "0AB", "0AC", "0AD", "0BC", "0BD", "0CD", "1AB", "1AC", "1AD", "1BC", "1BD", "1CD", 
+                    "2AB", "2AC", "2AD", "2BC", "2BD", "2CD", "3AB", "3AC", "3AD", "3BC", "3BD", "3CD"]
+    arrayToFCrossBarDeltaT = helper.addArray([chan_combinations_list], afpToFAlgorithm, 'AFPToFTool', topPath='AFP/ToF/')
+    arrayToFCrossBarDeltaT.defineHistogram('crossBarDeltaT_A', title='ToF cross-bar <delta> time (channel combination {0}), side A; <delta> t, [ps]; events', type='TH1D', path='CrossBar/sideA', xbins=400, xmin=-1500.0, xmax=1500.0)
+    arrayToFCrossBarDeltaT.defineHistogram('crossBarDeltaT_C', title='ToF cross-bar <delta> time (channel combination {0}), side C; <delta> t, [ps]; events', type='TH1D', path='CrossBar/sideC', xbins=400, xmin=-1500.0, xmax=1500.0)
     # Finalize. The return value should be a tuple of the ComponentAccumulator
     result.merge(helper.result())
     return result
@@ -248,7 +253,7 @@ if __name__=='__main__':
     # Set the Athena configuration flags
     from AthenaConfiguration.AllConfigFlags import initConfigFlags
     flags = initConfigFlags()
-    flags.Input.Files = ['/eos/user/v/vlysenko/AOD_data22_13p6TeV_DS_429142/data22_13p6TeV.00429142.physics_Main.merge.AOD.f1253_m2112._lb0521._0001.1']
+    flags.Input.Files = ['/eos/user/v/vlysenko/AOD_testing/AOD_data22_13p6TeV_DS_429142/data22_13p6TeV.00429142.physics_Main.merge.AOD.f1253_m2112._lb0521._0001.1']
     flags.Input.isMC = False
     flags.Output.HISTFileName = 'AFPTest-337176-10k-FMETrains-MU.root'
     
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPToFAlgorithm.cxx b/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPToFAlgorithm.cxx
index 21a2fb90084d31e43ac76d0176529d98cf0fa4a0..0b70f3389e76250915370d35ef5fd1941cec4fd9 100644
--- a/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPToFAlgorithm.cxx
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPToFAlgorithm.cxx
@@ -14,10 +14,11 @@
 
 AFPToFAlgorithm::AFPToFAlgorithm( const std::string& name, ISvcLocator* pSvcLocator )
 :AthMonitorAlgorithm(name,pSvcLocator)
-, m_afpToFHitContainerKey("AFPToFHitContainer")
+, m_afpToFHitContainerKey("AFPToFHitContainer"), m_afpTrackContainerKey( "AFPTrackContainer" )
 
 {
 	declareProperty( "AFPToFHitContainer", m_afpToFHitContainerKey );
+	declareProperty( "AFPTrackContainer", m_afpTrackContainerKey );
 }
 
 
@@ -31,10 +32,14 @@ StatusCode AFPToFAlgorithm::initialize() {
 	m_TrainsToFGroup    = buildToolMap<int>(m_tools, "AFPToFTool", m_trainsToF);
 	m_BarsInTrainsA     = buildToolMap<std::map<std::string,int>>(m_tools, "AFPToFTool", m_trainsToFA, m_barsToF);
 	m_BarsInTrainsC     = buildToolMap<std::map<std::string,int>>(m_tools,"AFPToFTool", m_trainsToFC, m_barsToF);
+	m_GroupChanCombDeltaT    = buildToolMap<int>(m_tools, "AFPToFTool", m_chanComb);
+
 
 	// We must declare to the framework in initialize what SG objects we are going to use
 	SG::ReadHandleKey<xAOD::AFPToFHitContainer> afpToFHitContainerKey("AFPToFHits");
 	ATH_CHECK(m_afpToFHitContainerKey.initialize());
+	SG::ReadHandleKey<xAOD::AFPTrackContainer> afpTrackContainerKey( "AFPTracks" );
+    ATH_CHECK( m_afpTrackContainerKey.initialize() );
 	
 	ATH_MSG_INFO( "BunchCrossingKey initialization (ToF)" );
 	ATH_CHECK(m_bunchCrossingKeyToF.initialize());
@@ -208,6 +213,13 @@ StatusCode AFPToFAlgorithm::fillHistograms( const EventContext& ctx ) const {
 
 	ATH_CHECK( afpToFHitContainer.initialize() );
 
+	SG::ReadHandle<xAOD::AFPTrackContainer> afpTrackContainer( m_afpTrackContainerKey, ctx );
+    if ( !afpTrackContainer.isValid() ) {
+        ATH_MSG_WARNING( "evtStore() does not contain hits collection with name " << m_afpTrackContainerKey );
+        return StatusCode::SUCCESS;
+    }
+    ATH_CHECK( afpTrackContainer.initialize() );
+
 	nTofHits = afpToFHitContainer->size();
 	fill("AFPToFTool", lb, nTofHits);
 
@@ -297,6 +309,87 @@ StatusCode AFPToFAlgorithm::fillHistograms( const EventContext& ctx ) const {
 		}
 	}
 
-	return StatusCode::SUCCESS;
+	return fillHistograms_crossBarDeltaT(*afpTrackContainer, *afpToFHitContainer);
 }
 
+StatusCode AFPToFAlgorithm::fillHistograms_crossBarDeltaT(
+        const xAOD::AFPTrackContainer& afpTrackContainer,
+        const xAOD::AFPToFHitContainer& afpToFHitContainer) const {
+    // Initialize monitored variables for histogram filling
+    Monitored::Scalar<float> crossBarDeltaT[2] = {
+            Monitored::Scalar<float>( "crossBarDeltaT_A", 0.0 ),
+            Monitored::Scalar<float>( "crossBarDeltaT_C", 0.0 )
+        };
+
+	bool channel_present[2][16] = {};
+	bool multihit[2] = {};
+	std::size_t track_count[2] = {};
+	std::size_t train_count[2][4] = {};
+
+	for (const xAOD::AFPTrack* tracksItr : afpTrackContainer)  
+	{ 
+		const auto side = tracksItr->stationID() == 3;
+		// Ignore tracks that are not from FAR stations
+		if (tracksItr->stationID() != 0 && tracksItr->stationID() != 3) 
+			continue;
+		++track_count[side];
+	}
+
+    // Load the necessary information
+	auto times = std::vector<std::vector<std::vector<float>>>(2, std::vector<std::vector<float>>(4, std::vector<float>(4, -10000)));
+	for (const xAOD::AFPToFHit* hitsItr : afpToFHitContainer)
+	{
+		const auto side = hitsItr->stationID() == 3;
+        const auto train = hitsItr->trainID();
+        const auto bar = hitsItr->barInTrainID();
+        const auto channel = 4 * train + bar;
+		const auto tof_time = hitsItr->time();
+		const auto TimePs=(tof_time)*1000;
+		//Cut on only 1 SiT track in the monitored station
+		if (track_count[side] != 1) continue;
+		// Ignore hits with an impossible origin
+		if (hitsItr->stationID() != 0 && hitsItr->stationID() != 3)
+			continue;
+		if (channel >= 16) continue;
+		if (channel_present[side][channel])
+			multihit[side] = true;
+		channel_present[side][channel] = true;
+		++train_count[side][train];
+
+		times[side][train][bar]=TimePs;
+
+	}
+
+	for (uint8_t side : {0, 1}) 
+	{
+		// Cut on only 1 SiT track in the monitored station
+		if (track_count[side] != 1) continue;
+		// Cut on maximum of 1 hit in each ToF channel
+		if (multihit[side]) continue;
+		//Cut on maximum 1 train per event
+		uint8_t multrain[2] = {};
+		for (uint8_t train; train < 4; ++train)
+			if (train_count[side][train]>1)
+				++multrain[side];
+		if (multrain[side]>1)
+			continue;
+		//fill histos
+		for (uint8_t train = 0; train < 4; ++train)
+			for (uint8_t bar1 = 0; bar1 < 4; ++bar1)
+				for (uint8_t bar2 = 0; bar2 < 4; bar2++)
+					if (bar2>bar1)
+					{
+						int comb = bar1*bar2+bar2-1;
+						if (comb==5) {comb=4;}
+						if (comb==8) {comb=5;}
+						int global_comb = train*6 + comb;
+						if (times[side][train][bar1]>-10000 && times[side][train][bar2]>-10000)
+						{
+							crossBarDeltaT[side] = (times[side][train][bar1] - times[side][train][bar2]);
+							fill(m_tools[m_GroupChanCombDeltaT.at(m_chanComb.at(global_comb))], crossBarDeltaT[side]);
+						}
+					}   
+	}
+
+    return StatusCode::SUCCESS;
+}
\ No newline at end of file
diff --git a/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPToFSiTAlgorithm.cxx b/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPToFSiTAlgorithm.cxx
index e5b4d2a1135649bbe82b0d6b59e1171357ee888a..0ccf515bfcab896ba66abfc473d77f1daf09b9a7 100644
--- a/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPToFSiTAlgorithm.cxx
+++ b/ForwardDetectors/AFP/Run3AFPMonitoring/src/AFPToFSiTAlgorithm.cxx
@@ -51,7 +51,7 @@ StatusCode AFPToFSiTAlgorithm::fillHistograms( const EventContext& ctx ) const {
         ATH_MSG_WARNING( "evtStore() does not contain hits collection with name " << m_afpTrackContainerKey );
         return StatusCode::SUCCESS;
     }
-    ATH_CHECK( afpSiHitContainer.initialize() );
+    ATH_CHECK( afpTrackContainer.initialize() );
 
     SG::ReadHandle<xAOD::AFPToFHitContainer> afpToFHitContainer( m_afpToFHitContainerKey, ctx );
     if ( !afpToFHitContainer.isValid() ) {
diff --git a/ForwardDetectors/ForwardRec/CMakeLists.txt b/ForwardDetectors/ForwardRec/CMakeLists.txt
index fa0e77ce8bf7a5e0a6968a738b899a1ac291a109..a58e50428e50ae3145d7425ae7b62cf594006d98 100644
--- a/ForwardDetectors/ForwardRec/CMakeLists.txt
+++ b/ForwardDetectors/ForwardRec/CMakeLists.txt
@@ -3,13 +3,10 @@
 # Declare the package name:
 atlas_subdir( ForwardRec )
 
-# Install files from the package:
-atlas_install_joboptions( share/*.py )
-
 # Install files from the package:
 atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )   
 
-
+# Tests in the package:
 atlas_add_test( LucidConfig_test
     SCRIPT python -m  ForwardRec.LucidRecConfig 
     POST_EXEC_SCRIPT noerror.sh)
diff --git a/ForwardDetectors/ForwardRec/share/AFP_Rec_OutputItemList_jobOptions.py b/ForwardDetectors/ForwardRec/share/AFP_Rec_OutputItemList_jobOptions.py
deleted file mode 100644
index 30a75a66407ef2fcced51631eafc0c2a5eb15683..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardRec/share/AFP_Rec_OutputItemList_jobOptions.py
+++ /dev/null
@@ -1,25 +0,0 @@
-AFP_ItemList=[]
-
-# AFP Silicon hits containers
-AFP_ItemList.append("xAOD::AFPSiHitContainer#AFPSiHitContainer")
-AFP_ItemList.append("xAOD::AFPSiHitAuxContainer#AFPSiHitContainerAux.")
-AFP_ItemList.append("xAOD::AFPSiHitsClusterContainer#AFPSiHitsClusterContainer")
-AFP_ItemList.append("xAOD::AFPSiHitsClusterAuxContainer#AFPSiHitsClusterContainerAux.")
-
-# for runs with more BCX ids i.e. before timing in the detectors
-for bcIDshift in range (1, 6):
-    name = "AFPSiHitContainerBcIDplus" + str(bcIDshift)
-    AFP_ItemList.append("xAOD::AFPSiHitContainer#" + name)
-    AFP_ItemList.append("xAOD::AFPSiHitAuxContainer#" + name + "Aux.")
-
-AFP_ItemList.append("xAOD::AFPTrackContainer#AFPTrackContainer")
-AFP_ItemList.append("xAOD::AFPTrackAuxContainer#AFPTrackContainerAux.")
-AFP_ItemList.append("xAOD::AFPToFHitContainer#AFPToFHitContainer")
-AFP_ItemList.append("xAOD::AFPToFHitAuxContainer#AFPToFHitContainerAux.")
-AFP_ItemList.append("xAOD::AFPProtonContainer#AFPProtonContainer")
-AFP_ItemList.append("xAOD::AFPProtonAuxContainer#AFPProtonContainerAux.")
-AFP_ItemList.append("xAOD::AFPToFTrackContainer#AFPToFTrackContainer")
-AFP_ItemList.append("xAOD::AFPToFTrackAuxContainer#AFPToFTrackContainerAux.")
-AFP_ItemList.append("xAOD::AFPVertexContainer#AFPVertexContainer")
-AFP_ItemList.append("xAOD::AFPVertexAuxContainer#AFPVertexContainerAux.")
-
diff --git a/ForwardDetectors/ForwardRec/share/ALFARec_OuputItemList_jobOptions.py b/ForwardDetectors/ForwardRec/share/ALFARec_OuputItemList_jobOptions.py
deleted file mode 100644
index fb5c58d827d9b56e85a833ad6d57dbe12449ce00..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardRec/share/ALFARec_OuputItemList_jobOptions.py
+++ /dev/null
@@ -1,21 +0,0 @@
-AlfaItemList=[]
-
-#AlfaItemList.ItemList+= ["ALFA_HitCollection#*"]
-#AlfaItemList.ItemList+= ["ALFA_ODHitCollection#*"]
-#AlfaItemList.ItemList+= ["ALFA_DigitCollection#*"]
-#AlfaItemList.ItemList+= ["ALFA_ODDigitCollection#*"]
-#AlfaItemList.ItemList+= ["ALFA_RawDataContainer#*"]
-
-
-
-AlfaItemList.append("ALFA_DigitCollection#ALFA_DigitCollection")
-AlfaItemList.append("ALFA_ODDigitCollection#ALFA_ODDigitCollection")
-#AlfaItemList.append("ALFA_RawDataContainer#ALFA_RawDataContainer")
-AlfaItemList.append("ALFA_RawDataContainer#ALFA_RawData")
-AlfaItemList.append("ALFA_LocRecEvCollection#ALFA_LocRecEvCollection")
-AlfaItemList.append("ALFA_LocRecODEvCollection#ALFA_LocRecODEvCollection")
-AlfaItemList.append("ALFA_LocRecCorrEvCollection#ALFA_LocRecCorrEvCollection")
-AlfaItemList.append("ALFA_LocRecCorrODEvCollection#ALFA_LocRecCorrODEvCollection")
-AlfaItemList.append("ALFA_CLinkEvent#ALFA_CLinkEvent")
-AlfaItemList.append("xAOD::ALFADataContainer#ALFADataContainer")
-AlfaItemList.append("xAOD::ALFADataAuxContainer#ALFADataContainerAux.")
diff --git a/ForwardDetectors/ForwardRec/share/ForwardRec_jobOptions.py b/ForwardDetectors/ForwardRec/share/ForwardRec_jobOptions.py
deleted file mode 100644
index bb448de71ca3c9d966f9d3d9801fdc3e47384633..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardRec/share/ForwardRec_jobOptions.py
+++ /dev/null
@@ -1,46 +0,0 @@
-include.block ('ForwardRec/ForwardRec_jobOptions.py')
-
-from AthenaCommon.Resilience import treatException   
-from AthenaCommon.DetFlags import DetFlags
-from RecExConfig.RecFlags import rec
-
-if (rec.doLucid):
-  include ( "ForwardRec/LUCID_Rec_jobOptions.py" )
-
-#if (rec.doForwardDet and rec.doZdc):
-#  include ( "ZdcRec/ZdcRec_jobOptions.py" )
-
-if DetFlags.makeRIO.ZDC_on() and not rec.doWriteBS() : 
-  try:
-      #from ZdcRec.ZdcRawChannelGetter import ZdcRawChannelGetter
-      #ZdcRawChannelGetter()
-    from ZdcRec.ZdcModuleGetter import ZdcModuleGetter
-    ZdcModuleGetter()
-  except Exception:
-    treatException("Problem with ZdcModuleGetter. Switched off.")
-    DetFlags.makeRIO.ZDC_setOff()
-
-if rec.doAlfa() and rec.doESD():
-    if DetFlags.readRDOBS.ALFA_on():
-        #Needed for real-data reconstruction:
-        from ALFA_RawDataByteStreamCnv.ALFA_RawDataByteStreamCnvConf import ALFA_RawDataProvider
-        topSequence+=ALFA_RawDataProvider()
-
-        from ALFA_Raw2Digit.ALFA_Raw2DigitConf import ALFA_Raw2Digit
-        
-        topSequence+=ALFA_Raw2Digit(MeasuredDataType = "tunnel")
-        pass
-
-    #For both, real and simulated data:
-    #from IOVDbSvc.CondDB import conddb
-    #conddb.addFolder("FWD","/FWD/ALFA/position_calibration<tag>FWDALFAposition_calibration-run373-v2</tag>")
-
-    include("ALFA_LocRec/ALFA_LocRec_joboption.py")
-    include("ALFA_LocRecCorr/ALFA_LocRecCorr_joboption.py")
-    include("ALFA_CLinkAlg/ALFA_CLinkAlg_joboption.py")        
-
-if rec.doAFP() and rec.doESD():
-  from AthenaConfiguration.ComponentAccumulator import CAtoGlobalWrapper
-  from AthenaConfiguration.AllConfigFlags import ConfigFlags
-  from ForwardRec.AFPRecConfig import AFPRecCfg
-  CAtoGlobalWrapper(AFPRecCfg, ConfigFlags)
diff --git a/ForwardDetectors/ForwardRec/share/LUCID_Rec_jobOptions.py b/ForwardDetectors/ForwardRec/share/LUCID_Rec_jobOptions.py
deleted file mode 100644
index bc16c161c88c6322cdf0fd51fcfd13d64812f629..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardRec/share/LUCID_Rec_jobOptions.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from AthenaCommon.Logging import logging
-mlog = logging.getLogger( 'RDOtoESD_Lucid: ' )
-
-from AthenaCommon.GlobalFlags import globalflags
-from RecExConfig.RecFlags import rec
-from RecExConfig.ObjKeyStore import objKeyStore
-
-if rec.doESD: 
-  if DetFlags.readRDOPool.Lucid_on():
-    include("LUCID_RawDataByteStreamCnv/LUCID_DigitRawDataCnv.py")
-  if globalflags.DataSource()=='geant4':
-    objKeyStore.addStreamESD("LUCID_DigitContainer", "Lucid_Digits")
-  objKeyStore.addStreamESD("LUCID_RawDataContainer", "Lucid_RawData")
diff --git a/ForwardDetectors/ForwardTransport/python/ForwardTransportConfigDb.py b/ForwardDetectors/ForwardTransport/python/ForwardTransportConfigDb.py
deleted file mode 100644
index 64b3133ef304452046047159dae0aa20d05f4a42..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransport/python/ForwardTransportConfigDb.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
-
-from AthenaCommon.CfgGetter import addTool
-addTool("ForwardTransport.ForwardTransportConfigLegacy.getForwardTransportModel","ForwardTransportModel")
diff --git a/ForwardDetectors/ForwardTransportSvc/CMakeLists.txt b/ForwardDetectors/ForwardTransportSvc/CMakeLists.txt
index bbdb04e01af69fe442233d447b4e73e3993e90af..a1d9fba5f990558c3eb6fc9cf62d8fb439ca160c 100644
--- a/ForwardDetectors/ForwardTransportSvc/CMakeLists.txt
+++ b/ForwardDetectors/ForwardTransportSvc/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 
 # Declare the package name:
 atlas_subdir( ForwardTransportSvc )
@@ -26,5 +26,4 @@ atlas_add_library( ForwardTransportSvc
 
 # Install files from the package:
 atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
-atlas_install_joboptions( share/*.py )
 
diff --git a/ForwardDetectors/ForwardTransportSvc/python/ForwardTransportFlags.py b/ForwardDetectors/ForwardTransportSvc/python/ForwardTransportFlags.py
deleted file mode 100644
index 02b3998d60eb8bae86e076afc07124e8b32e00b8..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/python/ForwardTransportFlags.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-import os
-
-from AthenaCommon.JobProperties import JobProperty, JobPropertyContainer
-from AthenaCommon.JobProperties import jobproperties
-
-class detectorFlag(JobProperty):
-    """ Detector Flag. """
-
-    statusOn=True
-    allowedTypes=['str']
-    allowedValues = ["ALFA", 
-                     "ZDC"]
-    StoredValue='ALFA'
-
-class beamEnergy(JobProperty):
-    """ Energy of the beam. """
-
-    statusOn=True
-    allowedTypes=['str']
-    allowedValues = ["3.5TeV", 
-                     "4.0TeV", 
-                     "7.0TeV"]
-    StoredValue='4.0TeV'
-
-class collisionBeta(JobProperty):
-    """ Beta function at the interaction point. """
-
-    statusOn=True
-    allowedTypes=['str']  
-    allowedValues = ["0000.55m", 
-                     "0000.60m",
-                     "0000.65m",
-                     "0001.00m",
-                     "0001.50m",
-                     "0090.00m",
-                     "0500.00m",
-                     "1000.00m",
-                     "2625.00m"]
-    StoredValue='0090.00m'
-
-class twissFileType(JobProperty):
-    """ Twiss file type: nominal(for performance studies) or real(measured). """
-
-    statusOn=True
-    allowedTypes=['str']
-    allowedValues = ["nominal", 
-                     "real"]
-    StoredValue='nominal'
-
-class twissFileVersion(JobProperty):
-    """ Twiss file version. """
-
-    statusOn=True
-    allowedTypes=['str']
-    allowedValues = ["v01", 
-                     "v02",
-                     "v03",
-                     "v04"]
-    StoredValue='v01'
-
-class twissFilePath1(JobProperty):
-    """ Path to TwissFile1 """
-
-    statusOn=True
-    allowedTypes=['str']
-    StoredValue='beam1.tfs'
-
-class twissFilePath2(JobProperty):
-    """ Path to TwissFile2 """
-
-    statusOn=True
-    allowedTypes=['str']
-    StoredValue='beam2.tfs'
-
-class ForwardTransportFlags(JobPropertyContainer):
-    """ Container of all ForwardTransport flags."""
-
-    def SetTwissFilePaths(self):
-        beamEnergy       = self.beamEnergy.get_Value()
-        collisionBeta    = self.collisionBeta.get_Value()
-        twissFileType    = self.twissFileType.get_Value()
-        twissFileVersion = self.twissFileVersion.get_Value()
-
-        base_path = os.getenv('TwissFilesPATH') + "/" + beamEnergy + "/" + collisionBeta + "/" + twissFileType + "/" + twissFileVersion
-
-        twiss1 = base_path + '/beam1.tfs'           
-        twiss2 = base_path + '/beam2.tfs'
-
-        self.twissFilePath1.set_Value(twiss1)
-        self.twissFilePath2.set_Value(twiss2)
-
-        return
-
-jobproperties.add_Container(ForwardTransportFlags)
-
-list_jobproperties=[detectorFlag,beamEnergy,collisionBeta,twissFileType,twissFileVersion,twissFilePath1,twissFilePath2]
-
-for i in list_jobproperties:
-    jobproperties.ForwardTransportFlags.add_JobProperty(i)
-
-forwardTransportFlags = jobproperties.ForwardTransportFlags
diff --git a/ForwardDetectors/ForwardTransportSvc/python/ForwardTransportSvcConfigDb.py b/ForwardDetectors/ForwardTransportSvc/python/ForwardTransportSvcConfigDb.py
deleted file mode 100644
index aaa57617d5714098ce50468f4901ef0fa38ffc65..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/python/ForwardTransportSvcConfigDb.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
-
-from AthenaCommon.CfgGetter import addService
-
-addService("ForwardTransportSvc.ForwardTransportSvcConfigLegacy.getForwardTransportSvc", "ForwardTransportSvc")
diff --git a/ForwardDetectors/ForwardTransportSvc/share/ForwardTransportSvcConfig.ALFA.py b/ForwardDetectors/ForwardTransportSvc/share/ForwardTransportSvcConfig.ALFA.py
deleted file mode 100644
index 893209dd3f1ce0b2baeacefc0d62cfca8688b4ac..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/ForwardTransportSvcConfig.ALFA.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-forwardTransportFlags.detectorFlag = "ALFA"
-
-from AthenaCommon.CfgGetter import getService
-forwardTransportSvc = getService("ForwardTransportSvc", checkType=True)
diff --git a/ForwardDetectors/ForwardTransportSvc/share/ForwardTransportSvcConfig.ZDC.py b/ForwardDetectors/ForwardTransportSvc/share/ForwardTransportSvcConfig.ZDC.py
deleted file mode 100644
index 14c7c470323ad47e7aa289639fa7b83b47c2af40..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/ForwardTransportSvcConfig.ZDC.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-forwardTransportFlags.detectorFlag = "ZDC"
-
-from AthenaCommon.CfgGetter import getService
-forwardTransportSvc = getService("ForwardTransportSvc", checkType=True)
diff --git a/ForwardDetectors/ForwardTransportSvc/share/postInclude.ForwardTransportSvcConfig.FillRootTree.py b/ForwardDetectors/ForwardTransportSvc/share/postInclude.ForwardTransportSvcConfig.FillRootTree.py
deleted file mode 100644
index 424d149d5bc1871f08a13369bc3527605421848f..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/postInclude.ForwardTransportSvcConfig.FillRootTree.py
+++ /dev/null
@@ -1,6 +0,0 @@
-forwardTransportSvc.FillRootTree = True
-
-from GaudiSvc.GaudiSvcConf import THistSvc
-THistSvc = THistSvc()
-THistSvc.Output = ["AANT DATAFILE='fwdTransport.root' OPT='RECREATE'"]
-svcMgr += THistSvc
diff --git a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0000.55m_nominal_v01.py b/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0000.55m_nominal_v01.py
deleted file mode 100644
index 0a877680acf48608346749b5dcd49c7cfb8b068c..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0000.55m_nominal_v01.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-
-forwardTransportFlags.beamEnergy       = "3.5TeV"
-forwardTransportFlags.collisionBeta    = "0000.55m"
-forwardTransportFlags.twissFileType    = "nominal"
-forwardTransportFlags.twissFileVersion = "v01"
diff --git a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v01.py b/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v01.py
deleted file mode 100644
index 83e47498e7492fcdb0ebb4fb77bc3816b6164593..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v01.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-
-forwardTransportFlags.beamEnergy       = "3.5TeV"
-forwardTransportFlags.collisionBeta    = "0090.00m"
-forwardTransportFlags.twissFileType    = "nominal"
-forwardTransportFlags.twissFileVersion = "v01"
diff --git a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v02.py b/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v02.py
deleted file mode 100644
index 1d1901ebfad4d86bf44235aa4de34cd310b3aa44..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v02.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-
-forwardTransportFlags.beamEnergy       = "3.5TeV"
-forwardTransportFlags.collisionBeta    = "0090.00m"
-forwardTransportFlags.twissFileType    = "nominal"
-forwardTransportFlags.twissFileVersion = "v02"
diff --git a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v03.py b/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v03.py
deleted file mode 100644
index e48b43f8ef265ecdd68558daffae63fd9175511a..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v03.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-
-forwardTransportFlags.beamEnergy       = "3.5TeV"
-forwardTransportFlags.collisionBeta    = "0090.00m"
-forwardTransportFlags.twissFileType    = "nominal"
-forwardTransportFlags.twissFileVersion = "v03"
diff --git a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v04.py b/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v04.py
deleted file mode 100644
index da4a582ad512b57a9a9ca97fa000479b19772c86..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_3.5TeV_0090.00m_nominal_v04.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-
-forwardTransportFlags.beamEnergy       = "3.5TeV"
-forwardTransportFlags.collisionBeta    = "0090.00m"
-forwardTransportFlags.twissFileType    = "nominal"
-forwardTransportFlags.twissFileVersion = "v04"
diff --git a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_4.0TeV_0000.55m_nominal_v01.py b/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_4.0TeV_0000.55m_nominal_v01.py
deleted file mode 100644
index 2620b7825b007d5bd2f65ea91e4d0d9e068470d7..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_4.0TeV_0000.55m_nominal_v01.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-
-forwardTransportFlags.beamEnergy       = "4.0TeV"
-forwardTransportFlags.collisionBeta    = "0000.55m"
-forwardTransportFlags.twissFileType    = "nominal"
-forwardTransportFlags.twissFileVersion = "v01"
diff --git a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_4.0TeV_0090.00m_nominal_v01.py b/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_4.0TeV_0090.00m_nominal_v01.py
deleted file mode 100644
index 7e0020c4840fb30c772acfc4158a7dc009b5b56b..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_4.0TeV_0090.00m_nominal_v01.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-
-forwardTransportFlags.beamEnergy       = "4.0TeV"
-forwardTransportFlags.collisionBeta    = "0090.00m"
-forwardTransportFlags.twissFileType    = "nominal"
-forwardTransportFlags.twissFileVersion = "v01"
diff --git a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_7.0TeV_0000.55m_nominal_v01.py b/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_7.0TeV_0000.55m_nominal_v01.py
deleted file mode 100644
index 597d014a18214a0e4dd9745f868a25a37a963b11..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_7.0TeV_0000.55m_nominal_v01.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-
-forwardTransportFlags.beamEnergy       = "7.0TeV"
-forwardTransportFlags.collisionBeta    = "0000.55m"
-forwardTransportFlags.twissFileType    = "nominal"
-forwardTransportFlags.twissFileVersion = "v01"
diff --git a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_7.0TeV_2625.00m_nominal_v01.py b/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_7.0TeV_2625.00m_nominal_v01.py
deleted file mode 100644
index f99f3f069752f7d62b83e589ff157a80b689582d..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ForwardTransportSvc/share/preInclude.ForwardTransportFlags_7.0TeV_2625.00m_nominal_v01.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ForwardTransportSvc.ForwardTransportFlags import forwardTransportFlags
-
-forwardTransportFlags.beamEnergy       = "7.0TeV"
-forwardTransportFlags.collisionBeta    = "2625.00m"
-forwardTransportFlags.twissFileType    = "nominal"
-forwardTransportFlags.twissFileVersion = "v01"
diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysisTool.cxx b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysisTool.cxx
index 942d42bfc378d30e312d9db80342df485fa0f220..8f25c2cb88221d70b34d3602eeb772152f695daa 100644
--- a/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysisTool.cxx
+++ b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysisTool.cxx
@@ -41,6 +41,7 @@ ZdcAnalysisTool::ZdcAnalysisTool(const std::string& name)
     // The following job properties enable/disable and affect the calibration of the ZDC energies
     //
     declareProperty("DoCalib", m_doCalib = true);
+    declareProperty("CalibVersion", m_calibVersion = "");
     declareProperty("DoTrigEff", m_doTrigEff = true);
     declareProperty("DoTimeCalib", m_doTimeCalib = true);
     declareProperty("ZdcAnalysisConfigPath", m_zdcAnalysisConfigPath = "$ROOTCOREBIN/data/ZdcAnalysis", "ZDC Analysis config file path");
@@ -1757,13 +1758,17 @@ void ZdcAnalysisTool::setEnergyCalibrations(unsigned int runNumber)
 
     std::array<std::array<std::unique_ptr<TSpline>, 4>, 2> splines;
 
+    // "m_calibVersion", called CalibVersion when settings parameters in python, is a directory within the run-based calibration file
+    TString calibVersion;
+    if (m_calibVersion != "") calibVersion = m_calibVersion + "/";
+    
     for (int iside = 0; iside < 2; iside++)
     {
         for (int imod = 0; imod < 4; imod++)
         {
             sprintf(name, "ZDC_Ecalib_run%u_s%d_m%d", runNumber, iside, imod);
             ATH_MSG_DEBUG("Searching for spline " << name);
-            TSpline3* s = (TSpline3*) fCalib->GetObjectChecked(name, "TSpline3");
+            TSpline3* s = (TSpline3*) fCalib->GetObjectChecked(calibVersion+TString(name), "TSpline3");
             if (!s && m_doCalib)
             {
                 ATH_MSG_WARNING("No calibrations for run " << runNumber);
@@ -1809,6 +1814,10 @@ void ZdcAnalysisTool::setTimeCalibrations(unsigned int runNumber)
     ATH_MSG_INFO("Opening time calibration file " << filename);
     std::unique_ptr<TFile> fCalib (TFile::Open(filename.c_str(), "READ"));
 
+    // "m_calibVersion", called CalibVersion when settings parameters in python, is a directory within the run-based calibration file
+    TString calibVersion = "";
+    if (m_calibVersion != "") calibVersion = m_calibVersion + "/";
+
     if (fCalib && !fCalib->IsZombie())
     {
       bool success = true;
@@ -1820,26 +1829,26 @@ void ZdcAnalysisTool::setTimeCalibrations(unsigned int runNumber)
             for (int imod = 0; imod < 4; imod++)
             {
                 sprintf(name, "ZDC_T0calib_run%u_HG_s%d_m%d", runNumber, iside, imod);
-                spline.reset (static_cast<TSpline3*>(fCalib->GetObjectChecked(name, "TSpline3")));
+                spline.reset (static_cast<TSpline3*>(fCalib->GetObjectChecked(calibVersion+TString(name), "TSpline3")));
                 if (spline)
                 {
                     T0HGOffsetSplines[iside][imod] = std::move (spline);
                 }
                 else
                 {
-                    ATH_MSG_WARNING("No time calib. spline " << name);
+                    ATH_MSG_WARNING("No time calib. spline " << calibVersion+name);
 		    success = false;
                 }
 
                 sprintf(name, "ZDC_T0calib_run%u_LG_s%d_m%d", runNumber, iside, imod);
-                spline.reset (static_cast<TSpline3*>(fCalib->GetObjectChecked(name, "TSpline3")));
+                spline.reset (static_cast<TSpline3*>(fCalib->GetObjectChecked(calibVersion+TString(name), "TSpline3")));
                 if (spline)
                 {
                     T0LGOffsetSplines[iside][imod] = std::move (spline);
                 }
                 else
                 {
-                    ATH_MSG_WARNING("No time calib. spline " << name);
+                    ATH_MSG_WARNING("No time calib. spline " << calibVersion+name);
 		    success = false;
                 }
             }
@@ -1848,13 +1857,13 @@ void ZdcAnalysisTool::setTimeCalibrations(unsigned int runNumber)
         if (success) 
 	  m_zdcDataAnalyzer->LoadT0Calibrations(T0HGOffsetSplines, T0LGOffsetSplines);
 	else
-	  ATH_MSG_WARNING("Time calibration failed - no T0 offsets loaded " << name);
+	  ATH_MSG_WARNING("Time calibration failed - no T0 offsets loaded " << calibVersion+name);
 
         fCalib->Close();
     }
     else
     {
-        ATH_MSG_WARNING("No time calibration file " << name);
+        ATH_MSG_WARNING("No time calibration file " << filename);
     }
 }
 
diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcAnalysisTool.h b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcAnalysisTool.h
index bdd29022eb4a5e6d1a87f9d8098cfc8e1128009e..f938e23a58a825d0ba6a0a893179b804cec48571 100644
--- a/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcAnalysisTool.h
+++ b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcAnalysisTool.h
@@ -156,7 +156,8 @@ private:
   bool m_doTrigEff;
   int m_forceCalibRun;
   int m_forceCalibLB;
-
+  std::string m_calibVersion;
+  
   //  Parameters that control the pulse fitting analysis
   //
   unsigned int m_numSample;
diff --git a/ForwardDetectors/ZDC/ZdcRec/CMakeLists.txt b/ForwardDetectors/ZDC/ZdcRec/CMakeLists.txt
index 06f389fad1be09ac5841aa5e53e00d05e90aa7c4..4220d824dc344f1e3dfc7a66d52ec1bda613f9e7 100644
--- a/ForwardDetectors/ZDC/ZdcRec/CMakeLists.txt
+++ b/ForwardDetectors/ZDC/ZdcRec/CMakeLists.txt
@@ -22,4 +22,3 @@ atlas_add_component( ZdcRec
 
 # Install files from the package:
 atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
-atlas_install_joboptions( share/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} --extend-ignore=F401,F821 )
diff --git a/ForwardDetectors/ZDC/ZdcRec/python/ZdcModuleGetter.py b/ForwardDetectors/ZDC/ZdcRec/python/ZdcModuleGetter.py
deleted file mode 100644
index fda4e772243706a215a4502d6845ccfd32e64da6..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ZDC/ZdcRec/python/ZdcModuleGetter.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
-
-# specifies egamma"standard"
-from AthenaCommon.Logging import logging
-from AtlasGeoModel.CommonGMJobProperties import CommonGeometryFlags as geoFlags
-
-from RecExConfig.Configured import Configured
-
-
-class ZdcModuleGetter ( Configured ) :
-
-    def preconfigure (self):
-      mlog = logging.getLogger ('ZdcModuleGetter.py::preconfigure:')
-      mlog.info('entering')
-
-      preconfigureBase = super (ZdcModuleGetter,self).preconfigure() 
-
-      
-      if not preconfigureBase:
-          return False
-      
-      return True
-
-
-    def configure(self):
-        mlog = logging.getLogger ('ZdcModuleGetter.py::configure:')
-        mlog.info('entering')
-
-        from AthenaCommon.DetFlags import DetFlags
-        if not DetFlags.detdescr.ZDC_on():
-            mlog.info("not DetFlags.detdescr.Zdc_on : Quit.")
-            return False
-
-        if not DetFlags.makeRIO.ZDC_on():
-            mlog.info("not DetFlags.makeRIO.Zdc_on : Quit.")
-            return False
-
-        from AthenaCommon.AppMgr import ToolSvc
-        from AthenaCommon import CfgMgr
-        mlog.info("adding ZDC::ZdcAnalysisTool to ToolSvc with default parameters, and no calibrations enabled")
-        ToolSvc += CfgMgr.ZDC__ZdcAnalysisTool("ZdcAnalysisTool",DoCalib=False,Configuration="PbPb2018")   
-        #zdcAnalysisTool = CfgMgr.ZDC__ZdcAnalysisTool("ZdcAnalysisTool",DoCalib=False,Configuration="pPb2016")   
-        
-        #zdcAnalysisTool.FixTau1=True
-        #zdcAnalysisTool.FixTau2=True
-        #zdcAnalysisTool.Tau1=5
-        #zdcAnalysisTool.Tau2=21
-        #zdcAnalysisTool.Peak2ndDerivThresh=15
-
-        try:
-            
-            mlog.info("trying to get ZDC reco for "+geoFlags.Run())
-
-            if (geoFlags.Run() == "RUN2"):
-                from ZdcRec.ZdcRecConf import ZdcRecV3
-                mlog.info("got ZdcRecV3, configuring it for Run2")
-                self._zdcRecHandle = ZdcRecV3()
-                self._zdcRecHandle.ZdcAnalysisTool.LHCRun=2
-            if (geoFlags.Run() == "RUN3"):
-                from ZdcRec.ZdcRecConf import ZdcRecRun3
-                mlog.info("got ZdcRecRun3, configuring it for Run3")
-                self._zdcRecHandle = ZdcRecRun3()
-                self._zdcRecHandle.ZdcAnalysisTool.LHCRun=3
-
-        except Exception:
-            mlog.error("could not get handle to ZDC reco")
-            import traceback
-            traceback.print_exc()
-            return False
-
-        # output to AOD:
-        #W.L. 2016-04-15, removed for AOD-item list. See ATLASRECTS-3023 
-        #objKeyStore.addManyTypesStreamAOD(self.output())        
-
-        # add to topsequence 
-        mlog.info("now adding to topSequence")
-        from AthenaCommon.AlgSequence import AlgSequence
-        topSequence = AlgSequence()
-        topSequence += self.zdcRecHandle()
-        mlog.info("added ZDC reconstruction for "+geoFlags.Run())
-
-        return True
-
-    def zdcRecHandle(self):
-        return self._zdcRecHandle
-
-
-    def outputKey(self) :
-        return self._output[self._outputType]
-
-    def outputType(self):
-        return self._outputType
-
-    def outputTypeKey(self) :
-        return str(self.outputType()+"#"+self.outputKey())
-
diff --git a/ForwardDetectors/ZDC/ZdcRec/python/ZdcRawChannelGetter.py b/ForwardDetectors/ZDC/ZdcRec/python/ZdcRawChannelGetter.py
deleted file mode 100644
index 9c7199a349d8299eee11b572a6cac5f8a721e3a0..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ZDC/ZdcRec/python/ZdcRawChannelGetter.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-# specifies egamma"standard"
-from AthenaCommon.Logging import logging
-
-from RecExConfig.Configured import Configured
-
-
-class ZdcRawChannelGetter ( Configured ) :
-    _outputType = "ZdcRawChannelCollection"
-
-    _output = { _outputType: ["ZdcRawChannelCollection" ]}
-
-
-    def preconfigure (self):
-      mlog = logging.getLogger ('ZdcRawChannelGetter.py::preconfigure:')
-      mlog.info('entering')
-
-      preconfigureBase = super (ZdcRawChannelGetter,self).preconfigure() 
-
-      
-      if not preconfigureBase:
-          return False
-
-      #mlog = logging.getLogger( 'Configured::preconfigure:%s:' % self.__class__.__name__.replace( ".", '_' )  )
-      #mlog.debug("Output= %s" % self.output() )
-      #
-      #if self.checkExistingOutput ():
-      #   return False
-
-      # a bit unusual: check if input exist before scheduling the alg. Will nt report ERROR in input does not exist
-      from RecExConfig.ObjKeyStore import objKeyStore
-      if not objKeyStore.isInInput("ZdcDigitsCollection","ZdcDigitsCollection"):
-         mlog.info("no ZdcDigitsCollection : Quit.")
-         return False
-
-      
-      return True
-
-
-    def configure(self):
-        mlog = logging.getLogger ('ZdcRawChannelGetter.py::configure:')
-        mlog.info('entering')
-
-        from AthenaCommon.DetFlags import DetFlags
-        if not DetFlags.detdescr.ZDC_on():
-            mlog.info("not DetFlags.detdescr.Zdc_on : Quit.")
-            return False
-
-        if not DetFlags.makeRIO.ZDC_on():
-            mlog.info("not DetFlags.makeRIO.Zdc_on : Quit.")
-            return False
-
-
-        try:
-            from ZdcRec.ZdcRecConf import ZdcRec
-            self._zdcRecHandle = ZdcRec()
-        except Exception:
-            import traceback
-            mlog.error("could not get handle to ZdcRec")
-            mlog.error(traceback.format_exc())
-            return False
-
-
-        # output to ESD:
-        from RecExConfig.ObjKeyStore import objKeyStore
-        objKeyStore.addManyTypesStreamESD(self.output())
-        # output to AOD:
-        objKeyStore.addManyTypesStreamAOD(self.output())        
-
-        # add to topsequence 
-        mlog.info("now adding to topSequence")
-        from AthenaCommon.AlgSequence import AlgSequence
-        topSequence = AlgSequence()
-        topSequence += self.zdcRecHandle()
-
-        return True
-
-    def zdcRecHandle(self):
-        return self._zdcRecHandle
-
-
-    def outputKey(self) :
-        return self._output[self._outputType]
-
-    def outputType(self):
-        return self._outputType
-
-    def outputTypeKey(self) :
-        return str(self.outputType()+"#"+self.outputKey())
-
diff --git a/ForwardDetectors/ZDC/ZdcRec/python/ZdcRecConfig.py b/ForwardDetectors/ZDC/ZdcRec/python/ZdcRecConfig.py
index 6d64f2767aca703661e7554c06191f747c06375b..6dade187bc77f8d664bd85b6e334c343e36d0fae 100644
--- a/ForwardDetectors/ZDC/ZdcRec/python/ZdcRecConfig.py
+++ b/ForwardDetectors/ZDC/ZdcRec/python/ZdcRecConfig.py
@@ -32,10 +32,14 @@ def ZdcRecOutputCfg(flags):
     acc.merge(addToESD(flags,ZDC_ItemList))
     acc.merge(addToAOD(flags,ZDC_ItemList))
 
+    from xAODMetaDataCnv.InfileMetaDataConfig import SetupMetaDataForStreamCfg
+    acc.merge(SetupMetaDataForStreamCfg(flags,streamName="AOD"))
+    
+
     return acc
 
 
-def ZdcAnalysisToolCfg(flags, run, config="LHCf2022", DoCalib=False, DoTimeCalib=False, DoTrigEff=False):
+def ZdcAnalysisToolCfg(flags, run, config="PbPb2023", DoCalib=False, DoTimeCalib=False, DoTrigEff=False):
     acc = ComponentAccumulator()
 
     print('ZdcAnalysisToolCfg: setting up ZdcAnalysisTool with config='+config)
@@ -58,7 +62,7 @@ def ZdcLEDAnalysisToolCfg(flags, config = 'ppPbPb2023'):
     return acc
 
 
-def ZdcTrigValToolCfg(flags, config = 'LHCf2022'):
+def ZdcTrigValToolCfg(flags, config = 'PbPb2023'):
     acc = ComponentAccumulator()
     
     acc.merge(TrigDecisionToolCfg(flags))
@@ -135,7 +139,8 @@ def ZdcRecRun3Cfg(flags):
     elif flags.Input.ProjectName == "data23_900GeV":
         config = "pp2023"
     elif flags.Input.ProjectName == "data23_comm":
-        config = "pp2023"
+        config = "PbPb2023"
+        doCalib = True
     elif flags.Input.ProjectName == "data23_13p6TeV":
         config = "pp2023"
     elif flags.Input.ProjectName == "data23_5p36TeV":
@@ -143,17 +148,20 @@ def ZdcRecRun3Cfg(flags):
     elif flags.Input.ProjectName == "data23_hi":
         config = "PbPb2023"
         doCalib = True
-
+        doTimeCalib = True
+        
     print('ZdcRecRun3Cfg: doCalib = '+str(doCalib)+' for project '+flags.Input.ProjectName)
     
     anaTool = acc.popToolsAndMerge(ZdcAnalysisToolCfg(flags,3,config,doCalib,doTimeCalib,doTrigEff))
     centroidTool = acc.popToolsAndMerge(RpdSubtractCentroidToolCfg(flags))
 
-    if ( (flags.Input.isMC) or (flags.Trigger.doZDC) ): # if doZDC flag is true we are in a trigger reprocessing -> no TrigValidTool
+    if ( flags.Input.isMC ):
+        zdcTools = [anaTool,centroidTool] # expand list as needed
+    elif ( flags.Trigger.doZDC ): # if doZDC flag is true we are in a trigger reprocessing -> no TrigValidTool
         zdcTools = [anaTool] # expand list as needed
     elif (flags.Common.isOnline): # running online, no trigger info
         zdcTools = [anaTool,centroidTool] # expand list as needed
-    else:
+    else: # default (not MC, not trigger repoc, not online)
         trigTool = acc.popToolsAndMerge(ZdcTrigValToolCfg(flags,config))   
         zdcTools = [anaTool,trigTool,centroidTool] # expand list as needed
         
@@ -298,15 +306,13 @@ def ZdcRecCfg(flags):
 
 if __name__ == '__main__':
 
-    """ This is selftest & Zdc analysis transform at the same time"""
+    """ This is selftest & ZDC calibration transform at the same time"""
     from AthenaConfiguration.AllConfigFlags import initConfigFlags
     from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+    from AthenaConfiguration.TestDefaults import defaultGeometryTags
 
     flags = initConfigFlags()
 
-    from AthenaConfiguration.TestDefaults import defaultGeometryTags
-    flags.GeoModel.AtlasVersion=defaultGeometryTags.RUN3
-
     flags.Scheduler.CheckDependencies = True
     flags.Scheduler.ShowDataDeps = True
     flags.Scheduler.ShowDataFlow = True
@@ -352,6 +358,7 @@ if __name__ == '__main__':
     if not pn:
         raise ValueError('Unknown project name')
     
+
     if not isLED:
         year = int(pn.split('_')[0].split('data')[1])
         if (year < 20):
@@ -360,8 +367,10 @@ if __name__ == '__main__':
         elif (year > 20):
             flags.Trigger.EDMVersion=3
             flags.GeoModel.Run = LHCPeriod.Run3
+            flags.GeoModel.AtlasVersion=defaultGeometryTags.RUN3
     else:
         flags.Trigger.EDMVersion=3
+        flags.GeoModel.AtlasVersion = defaultGeometryTags.RUN3
         flags.GeoModel.Run = LHCPeriod.Run3
 
     if (flags.Input.isMC):
diff --git a/ForwardDetectors/ZDC/ZdcRec/python/ZdcRecUtils.py b/ForwardDetectors/ZDC/ZdcRec/python/ZdcRecUtils.py
deleted file mode 100644
index 5e33f24947a80db7a5ea502d8b96cca4a108f792..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ZDC/ZdcRec/python/ZdcRecUtils.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-def AppendOutputList(HIAODItemList) :
-    """Adds HIGlobalAODOutputList to the list passed in as an argument"""
-    HIAODItemList+= ["xAOD::ZdcModuleContainer#ZdcModules","xAOD::ZdcModuleAuxContainer#ZdcModulesAux.","xAOD::ZdcModuleContainer#ZdcSums","xAOD::ZdcModuleAuxContainer#ZdcSumsAux."] 
diff --git a/ForwardDetectors/ZDC/ZdcRec/python/__init__.py b/ForwardDetectors/ZDC/ZdcRec/python/__init__.py
index bbb64cb3e77e4717d0cc19d7341f99d59786198c..70e75c66b832e123f5e6d70a2e1bb6159c1a45ae 100755
--- a/ForwardDetectors/ZDC/ZdcRec/python/__init__.py
+++ b/ForwardDetectors/ZDC/ZdcRec/python/__init__.py
@@ -1,15 +1,5 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 
-#=======================================================================
-# File: LArROD/python/__init__.py
-#=======================================================================
-__version__ = '1.0.0'
-__author__  = 'David Rousseau '
-__all__ = [ 'ZdcModuleGetter'] 
 __doc__ =""" - Python modules for the ATLAS Reconstruction -
          ZdcModuleGetter - build ZdcModuleContainer from ZdcTriggerTowers>
          """
-__description__ ='Python interface for ATLAS reconstruction '
-
-#
-#=======================================================================
diff --git a/ForwardDetectors/ZDC/ZdcRec/share/ZdcRecConfig.py b/ForwardDetectors/ZDC/ZdcRec/share/ZdcRecConfig.py
deleted file mode 100644
index 5695b0db7e6ca8a259cbc71969f6de4e4075d568..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ZDC/ZdcRec/share/ZdcRecConfig.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-from RecExConfig.RecFlags import rec
-rec.doInDet.set_Value_and_Lock(False)
-rec.doCalo.set_Value_and_Lock(False)
-rec.doMuon.set_Value_and_Lock(False)
-rec.doForwardDet.set_Value_and_Lock(True)
-rec.doTrigger.set_Value_and_Lock(False)
-rec.doEgamma.set_Value_and_Lock(False)
-rec.doMuonCombined.set_Value_and_Lock(False)
-rec.doTau.set_Value_and_Lock(False)
-rec.doJetMissingETTag.set_Value_and_Lock(False)
-from JetRec.JetRecFlags import jetFlags
-jetFlags.Enabled.set_Value_and_Lock(False)
-rec.doAlfa.set_Value_and_Lock(False)
-rec.doAFP.set_Value_and_Lock(False)
-rec.doLucid.set_Value_and_Lock(False)
-rec.doTrigger.set_Value_and_Lock(False)
-rec.doHeavyIon.set_Value_and_Lock(False)
diff --git a/ForwardDetectors/ZDC/ZdcRec/share/recozdctestfile.zsh b/ForwardDetectors/ZDC/ZdcRec/share/recozdctestfile.zsh
deleted file mode 100755
index 992c1719e7bb39af988f418948f9a37e688b1d81..0000000000000000000000000000000000000000
--- a/ForwardDetectors/ZDC/ZdcRec/share/recozdctestfile.zsh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/zsh
-
-zrun=285947
-if [ ! -z $1 ]; then
-   zrun=$1
-fi
-
-zmax=100
-if [ ! -z $2 ]; then
-   zmax=$2
-fi
-
-zfile=data15_calib.00$zrun.calibration_.daq.RAW._lb0000._ROS-FWD-ZDC-00._0001.data
-zin=root://eosatlas.cern.ch//eos/atlas/atlascerngroupdisk/det-zdc/ZdcData/calib/$zfile
-zdir=run$zrun
-zesd=zdclaser.run00$zrun.ESD.pool.root
-zaod=zdclaser.run00$zrun.AOD.pool.root
-
-mkdir $zdir
-cd $zdir
-
-xrdcp $zin .
-
-echo Running on $zin
-echo Running $zmax events
-
-Reco_tf.py --outputESDFile=$zesd --outputAODFile=$zaod --preInclude ZdcRec/ZdcRecConfig.py --postExec 'e2a:from ZdcRec.ZdcRecUtils import AppendOutputList;AppendOutputList(StreamAOD.ItemList);' --conditionsTag CONDBR2-BLKPA-2015-11  --geometryVersion ATLAS-R2-2015-03-01-00 --maxEvents $zmax --inputBSFile $zfile
-
-rm $zesd
-mv $zaod ..
\ No newline at end of file
diff --git a/HLT/Trigger/TrigControl/TrigPSC/src/Config.cxx b/HLT/Trigger/TrigControl/TrigPSC/src/Config.cxx
index f269309e7c41ac51fbc66cee5eac5f44a45c23fb..5e0d724717d21eb3658cddcbe349dbecf48027ac 100644
--- a/HLT/Trigger/TrigControl/TrigPSC/src/Config.cxx
+++ b/HLT/Trigger/TrigControl/TrigPSC/src/Config.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 /**
@@ -332,6 +332,7 @@ void psc::Config::fillopt_common(const ptree& hlt)
   optmap["SOFTTIMEOUTFRACTION"] = hltmppu.get_child("softTimeoutFraction").data();
   optmap["NEVENTSLOTS"]         = hltmppu.get_child("numberOfEventSlots").data();
   optmap["NTHREADS"]            = hltmppu.get_child("numberOfAthenaMTThreads").data();
+  optmap["NPROCS"]              = hltmppu.get_child("numForks").data();
   optmap["MAXEVENTSIZEMB"]      = hltmppu.get_child("maximumHltResultMb").data();
 }
 
diff --git a/HLT/Trigger/TrigControl/TrigPSC/src/Psc.cxx b/HLT/Trigger/TrigControl/TrigPSC/src/Psc.cxx
index 2bc49f536959abd121e980fd9b55ba0d5d844082..1fd03e9da47b0b748fe3e2c5e93022efbc9077c8 100644
--- a/HLT/Trigger/TrigControl/TrigPSC/src/Psc.cxx
+++ b/HLT/Trigger/TrigControl/TrigPSC/src/Psc.cxx
@@ -315,7 +315,9 @@ bool psc::Psc::configure(const ptree& config)
     {"DF_Ppid", "DF_PPID"},
     {"DF_Pid", "DF_PID"},
     {"DF_HostId", "DF_HOST_ID"},
-    {"DF_RandomSeed", "DF_RANDOM_SEED"}};
+    {"DF_RandomSeed", "DF_RANDOM_SEED"},
+    {"DF_NumberOfWorkers", "NPROCS"}
+  };
   if(!setDFProperties(props))
     return false;
 
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltAsyncEventLoopMgr.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltAsyncEventLoopMgr.cxx
index 46d94485603eb86f75350ed940f2605b4dbb41b5..35a03585893eaea60524182cab2617c626b5c902 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/HltAsyncEventLoopMgr.cxx
+++ b/HLT/Trigger/TrigControl/TrigServices/src/HltAsyncEventLoopMgr.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 // Local includes
@@ -18,6 +18,7 @@
 #include "ByteStreamData/ByteStreamMetadataContainer.h"
 #include "EventInfoUtils/EventInfoFromxAOD.h"
 #include "StoreGate/StoreGateSvc.h"
+#include "StoreGate/SGHiveMgrSvc.h"
 
 // Gaudi includes
 #include "GaudiKernel/ConcurrencyFlags.h"
@@ -134,6 +135,20 @@ StatusCode HltAsyncEventLoopMgr::initialize()
   else
     ATH_MSG_WARNING("Failed to retrieve the job property AvalancheSchedulerSvc.ThreadPoolSize");
 
+  const std::string& procs = m_jobOptionsSvc->get("DataFlowConfig.DF_NumberOfWorkers");
+  if (!procs.empty()) {
+    ATH_MSG_INFO(" ---> NumProcs                  = " << procs);
+    try {
+      SG::HiveMgrSvc::setNumProcs(std::stoi(procs));
+    }
+    catch (const std::logic_error& ex) {
+      ATH_MSG_ERROR("Cannot convert " << procs << "to integer: " << ex.what());
+      return StatusCode::FAILURE;
+    }
+  }
+  else
+    ATH_MSG_WARNING("Failed to retrieve the job property DataFlowconfig.DF_NumberOfWorkers");
+
   if (m_maxParallelIOTasks.value() <= 0) {
     ATH_CHECK(m_maxParallelIOTasks.fromString(threads));
   }
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx
index b39aeec572a1a19a9036510988e6d6c7844f16d8..7165eb559da58780a5da96bd96bd0c475b62847b 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx
+++ b/HLT/Trigger/TrigControl/TrigServices/src/HltEventLoopMgr.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 // Trigger includes
@@ -16,6 +16,7 @@
 #include "ByteStreamData/ByteStreamMetadataContainer.h"
 #include "EventInfoUtils/EventInfoFromxAOD.h"
 #include "StoreGate/StoreGateSvc.h"
+#include "StoreGate/SGHiveMgrSvc.h"
 
 // Gaudi includes
 #include "GaudiKernel/ConcurrencyFlags.h"
@@ -121,6 +122,20 @@ StatusCode HltEventLoopMgr::initialize()
   else
     ATH_MSG_WARNING("Failed to retrieve the job property AvalancheSchedulerSvc.ThreadPoolSize");
 
+  const std::string& procs = m_jobOptionsSvc->get("DataFlowConfig.DF_NumberOfWorkers");
+  if (!procs.empty()) {
+    ATH_MSG_INFO(" ---> NumProcs                  = " << procs);
+    try {
+      SG::HiveMgrSvc::setNumProcs(std::stoi(procs));
+    }
+    catch (const std::logic_error& ex) {
+      ATH_MSG_ERROR("Cannot convert " << procs << "to integer: " << ex.what());
+      return StatusCode::FAILURE;
+    }
+  }
+  else
+    ATH_MSG_WARNING("Failed to retrieve the job property DataFlowconfig.DF_NumberOfWorkers");
+
   if (m_maxParallelIOTasks.value() <= 0) {
     ATH_CHECK(m_maxParallelIOTasks.fromString(threads));
   }
diff --git a/LArCalorimeter/LArBadChannelTool/python/LArMissingFebs2Ascii.py b/LArCalorimeter/LArBadChannelTool/python/LArMissingFebs2Ascii.py
new file mode 100644
index 0000000000000000000000000000000000000000..75804469ed4369decc08a134dad5f2cd4b3f68a4
--- /dev/null
+++ b/LArCalorimeter/LArBadChannelTool/python/LArMissingFebs2Ascii.py
@@ -0,0 +1,98 @@
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+from AthenaConfiguration.ComponentFactory import CompFactory
+from IOVDbSvc.IOVDbSvcConfig import addFolders
+
+
+def LArBadFebs2AsciiCfg(flags,OutputFile,dbname="LAR_OFL",folder=None,tag=None):
+    from LArGeoAlgsNV.LArGMConfig import LArGMCfg
+    result=LArGMCfg(flags)
+
+    from LArCabling.LArCablingConfig import LArOnOffIdMappingCfg
+    result.merge(LArOnOffIdMappingCfg(flags))
+    
+    if folder is None:
+        if dbname == "LAR_ONL":
+            folder="/LAR/BadChannels/KnownBADFEBs"
+        else: 
+            folder="/LAR/BadChannelsOfl/KnownBADFEBs"
+
+    if tag is not None:
+        if not tag.startswith("LAR"):
+            if not tag.startswith("-"): tag= "-"+tag
+            tag="".join(folder.split("/"))+tag
+   
+        print("Tag=",tag)
+
+    result.merge(addFolders(flags,folder,dbname,tag=tag,
+                            className="AthenaAttributeList"))
+
+    result.addCondAlgo(CompFactory.LArBadFebCondAlg("LArKnownBadFebAlg",ReadKey=folder,WriteKey="LArBadFeb"))
+
+    result.addEventAlgo(CompFactory.LArBadFeb2Ascii(FileName=OutputFile))
+                        
+    return result
+
+
+
+if __name__=="__main__":
+    import sys,argparse
+    parser= argparse.ArgumentParser()
+    parser.add_argument("--loglevel", default=None, help="logging level (ALL, VERBOSE, DEBUG,INFO, WARNING, ERROR, or FATAL")
+    parser.add_argument("-r","--runnumber",default=0x7fffffff, type=int, help="run number to query the DB")
+    parser.add_argument("-l","--lbnumber",default=1, type=int, help="LB number to query the DB")
+    parser.add_argument("-d","--database",default="LAR_OFL", help="Database name or sqlite file name")
+    parser.add_argument("-o","--output",default="bf_output.txt", help="output file name")
+    parser.add_argument("-f","--folder",default=None, help="database folder to read")
+    parser.add_argument("-t","--tag",default=None, help="folder-level tag to read")
+
+    (args,leftover)=parser.parse_known_args(sys.argv[1:])
+
+    if len(leftover)>0:
+        print("ERROR, unhandled argument(s):",leftover)
+        sys.exit(-1)
+    
+    from AthenaConfiguration.AllConfigFlags import initConfigFlags
+    from LArCalibProcessing.LArCalibConfigFlags import addLArCalibFlags
+    flags=initConfigFlags()
+    addLArCalibFlags(flags)
+
+    flags.Input.isMC = False
+    flags.IOVDb.DatabaseInstance="CONDBR2"
+    flags.LAr.doAlign=False
+    flags.Input.RunNumbers=[args.runnumber]
+    flags.IOVDb.GlobalTag="CONDBR2-ES1PA-2022-06"
+    from AthenaConfiguration.TestDefaults import defaultGeometryTags
+    flags.GeoModel.AtlasVersion=defaultGeometryTags.RUN3
+    
+    if args.loglevel:
+        from AthenaCommon import Constants
+        if hasattr(Constants,args.loglevel):
+            flags.Exec.OutputLevel=getattr(Constants,args.loglevel)
+        else:
+            raise ValueError("Unknown log-level, allowed values are ALL, VERBOSE, DEBUG,INFO, WARNING, ERROR, FATAL")
+
+    flags.lock()
+
+    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+    cfg=MainServicesCfg(flags)
+    #MC Event selector since we have no input data file
+    from McEventSelector.McEventSelectorConfig import McEventSelectorCfg
+    cfg.merge(McEventSelectorCfg(flags,
+                                 FirstLB=args.lbnumber,
+                                 EventsPerRun      = 1,
+                                 FirstEvent        = 1,
+                                 InitialTimeStamp  = 0,
+                                 TimeStampInterval = 1))
+
+    cfg.merge(LArBadFebs2AsciiCfg(flags,args.output, 
+                                  dbname=args.database,
+                                  folder=args.folder,
+                                  tag=args.tag))
+    
+
+
+    sc=cfg.run(1)
+    if sc.isSuccess():
+        sys.exit(0)
+    else:
+        sys.exit(1)
diff --git a/LArCalorimeter/LArBadChannelTool/python/LArMissingFebsDBAlg.py b/LArCalorimeter/LArBadChannelTool/python/LArMissingFebsDBAlg.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b598083551ecffd4d7bbc571b85f0ca23c052ed
--- /dev/null
+++ b/LArCalorimeter/LArBadChannelTool/python/LArMissingFebsDBAlg.py
@@ -0,0 +1,118 @@
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+from AthenaConfiguration.ComponentFactory import CompFactory
+from AthenaCommon.Logging import logging
+
+
+def LArBadFebDBAlgCfg(flags,InputFile,dbname="LAR_OFL",folder=None,tag=None,
+                          IOVStart=[0,0],IOVEnd=[0x7FFFFFFF,0xFFFFFFFF]):
+
+    logger = logging.getLogger( "LArBadFebDBAlgCfg" )
+    from LArGeoAlgsNV.LArGMConfig import LArGMCfg
+    result=LArGMCfg(flags)
+
+    from LArCabling.LArCablingConfig import LArOnOffIdMappingCfg
+    result.merge(LArOnOffIdMappingCfg(flags))
+
+    if folder is None:
+        if dbname == "LAR_ONL":
+            folder="/LAR/BadChannels/KnownBADFEBs"
+        else: 
+            folder="/LAR/BadChannelsOfl/KnownBADFEBs"
+
+    if tag is not None:
+        if not tag.startswith("LAR"):
+            if not tag.startswith("-"): tag= "-"+tag
+            tag="".join(folder.split("/"))+tag
+   
+    print("Tag=",tag)
+
+       
+    logger.info("Writing to folder %s, tag %s",folder,tag)
+    result.addCondAlgo(CompFactory.LArBadFebCondAlg("LArKnownBadFebAlg",ReadKey="",InputFileName=InputFile,WriteKey="LArBadFeb"))
+
+    #Thats the registration algo
+    theLArDBAlg=CompFactory.LArBadChannelDBAlg()
+    theLArDBAlg.WritingMode = 1
+    theLArDBAlg.FEBFolder=folder
+    result.addEventAlgo(theLArDBAlg)
+
+    from RegistrationServices.OutputConditionsAlgConfig import OutputConditionsAlgCfg
+    result.merge(OutputConditionsAlgCfg(flags,"dummy.pool.root",
+                                        ObjectList=["AthenaAttributeList#"+folder],
+                                        IOVTagList=[tag], 
+                                        Run1=IOVStart[0],LB1=IOVStart[1],
+                                        Run2=IOVEnd[0],LB2=IOVEnd[1]))
+
+    return result
+
+    
+if __name__=="__main__":
+    import sys,argparse
+    parser= argparse.ArgumentParser()
+    parser.add_argument("inputfile")
+    parser.add_argument("--loglevel", default=None, help="logging level (ALL, VERBOSE, DEBUG,INFO, WARNING, ERROR, or FATAL")
+    parser.add_argument("-r","--runnumber",default=0, type=int, help="IOV start (runnumber)")
+    parser.add_argument("-l","--lbnumber",default=0, type=int, help="IOV start (LB number)")
+    parser.add_argument("--runnumber2",default=0x7FFFFFFF, type=int, help="IOV start (runnumber)")
+    parser.add_argument("--lbnumber2",default=0xFFFFFFFF, type=int, help="IOV start (LB number)")
+    parser.add_argument("-o","--output",default="BadFebs.db", help="sqlite output file name")
+    parser.add_argument("-f","--folder",default=None, help="database folder to create")
+    parser.add_argument("-t","--tag",default=None, help="folder-level tag (or tag-suffix) to create")
+
+
+    (args,leftover)=parser.parse_known_args(sys.argv[1:])
+
+    if len(leftover)>0:
+        print("ERROR, unhandled argument(s):",leftover)
+        sys.exit(-1)
+
+    from AthenaConfiguration.AllConfigFlags import initConfigFlags
+    from LArCalibProcessing.LArCalibConfigFlags import addLArCalibFlags
+    flags=initConfigFlags()
+    addLArCalibFlags(flags)
+
+    flags.Input.isMC = False
+    flags.IOVDb.DatabaseInstance="CONDBR2"
+    flags.LAr.doAlign=False
+    flags.Input.RunNumbers=[args.runnumber if args.runnumber>0 else 300000]
+    flags.IOVDb.GlobalTag="CONDBR2-ES1PA-2022-06"
+    from AthenaConfiguration.TestDefaults import defaultGeometryTags
+    flags.GeoModel.AtlasVersion=defaultGeometryTags.RUN3
+
+    flags.IOVDb.DBConnection="sqlite://;schema="+args.output+";dbname=CONDBR2"
+
+    if args.loglevel:
+        from AthenaCommon import Constants
+        if hasattr(Constants,args.loglevel):
+            flags.Exec.OutputLevel=getattr(Constants,args.loglevel)
+        else:
+            raise ValueError("Unknown log-level, allowed values are ALL, VERBOSE, DEBUG,INFO, WARNING, ERROR, FATAL")
+
+    flags.lock()
+
+    from AthenaConfiguration.MainServicesConfig import MainServicesCfg
+    cfg=MainServicesCfg(flags)
+    #MC Event selector since we have no input data file
+    from McEventSelector.McEventSelectorConfig import McEventSelectorCfg
+    cfg.merge(McEventSelectorCfg(flags,
+                                 FirstLB=args.lbnumber,
+                                 EventsPerRun      = 1,
+                                 FirstEvent        = 1,
+                                 InitialTimeStamp  = 0,
+                                 TimeStampInterval = 1))
+
+    cfg.merge(LArBadFebDBAlgCfg(flags, 
+                                args.inputfile,
+                                folder=args.folder,
+                                tag=args.tag,
+                                IOVStart=[args.runnumber,args.lbnumber],
+                                IOVEnd=[args.runnumber2,args.lbnumber2]
+                                ))
+    
+
+
+    sc=cfg.run(1)
+    if sc.isSuccess():
+        sys.exit(0)
+    else:
+        sys.exit(1)
diff --git a/LArCalorimeter/LArBadChannelTool/share/LArBuildMissingFebDB.sh b/LArCalorimeter/LArBadChannelTool/share/LArBuildMissingFebDB.sh
index c6ad3e56d7b21525ec9b38aaa133c88e67cde5b6..caed20d48d32db2e476a6705764c5c8e17a248e5 100755
--- a/LArCalorimeter/LArBadChannelTool/share/LArBuildMissingFebDB.sh
+++ b/LArCalorimeter/LArBadChannelTool/share/LArBuildMissingFebDB.sh
@@ -163,7 +163,8 @@ IFS=' '
 
 
 echo "Running athena to read current database content..."
-athena.py -c "OutputFile=\"${oldTextFile}\";RunNumber=${runnumber};LBNumber=${lbnumber};Folder=\"${Folder}\";GlobalTag=\"${gtag}\";tag=\"${fldtag}-${upd4TagName}\";" LArBadChannelTool/LArMissingFebs2Ascii.py > oracle2ascii.log 2>&1
+python -m LArBadChannelTool.LArMissingFebs2Ascii  -r ${runnumber} -l ${lbnumber} -o ${oldTextFile} -t ${upd4TagName} -f ${Folder} > oracle2ascii.log 2>&1
+
 if [ $? -ne 0 ];  then
     echo "Athena reported an error reading back sqlite file ! Please check oracle2ascii.log!"
     exit 5
@@ -195,9 +196,7 @@ fi
 
 echo "TagSuffix: " $upd4TagName
 echo "Running athena to build sqlite database file ..."
-prefix="${prefix}IOVBeginRun=${runnumber};IOVBeginLB=${lbnumber};sqlite=\"${outputSqlite}.tmp\";Folder=\"${Folder}\";GlobalTag=\"${gtag}\";TagPostfix=\"-${upd4TagName}\";"
-echo "prefix: ${prefix}"
-athena.py -c $prefix LArBadChannelTool/LArMissingFebDbAlg.py > ascii2sqlite.log 2>&1
+python -m LArBadChannelTool.LArMissingFebsDBAlg  -r ${runnumber} -l ${lbnumber} -o ${outputSqlite}.tmp -f ${Folder} -t ${upd4TagName}  $inputTextFile > ascii2sqlite.log 2>&1
 
 if [ $? -ne 0 ];  then
     echo "Athena reported an error! Please check ascii2sqlite.log!"
@@ -220,13 +219,13 @@ fi
 cp ${outputSqlite}.tmp ${outputSqlite}
 
 if [ $onerun -eq 1 ] || [ $lbnumbere -ge 0 ]; then
-   pref="RunNumber=${runnumber};LBNumber=${lbnumber};"
+   pref="-r ${runnumber} -l=${lbnumber};"
 else   
    pref=""
 fi
-pref="${pref}sqlite=\"${outputSqlite}\";OutputFile=\"${outputTextFile}\";Folder=\"${Folder}\";GlobalTag=\"${gtag}\";tag=\"${fldtag}-${upd4TagName}\";"
+
 echo "Running athena to test readback of sqlite database file"
-athena.py  -c ${pref} LArBadChannelTool/LArMissingFebs2Ascii.py > sqlite2ascii.log 2>&1
+python -m LArBadChannelTool.LArMissingFebs2Ascii  -d ${outputSqlite} -o ${outputTextFile} -t ${upd4TagName} -f ${Folder} $pref > sqlite2ascii.log 2>&1
 
 if [ $? -ne 0 ];  then
     echo "Athena reported an error reading back sqlite file ! Please check sqlite2ascii.log!"
diff --git a/LArCalorimeter/LArCafJobs/LArCafJobs/LArNoiseBursts.h b/LArCalorimeter/LArCafJobs/LArCafJobs/LArNoiseBursts.h
index 9b21877028c6a98baa57243b21433e7eb2a54df1..686dafda412aaaaa104e8d9fd7d1238b2a9ea8f9 100644
--- a/LArCalorimeter/LArCafJobs/LArCafJobs/LArNoiseBursts.h
+++ b/LArCalorimeter/LArCafJobs/LArCafJobs/LArNoiseBursts.h
@@ -99,7 +99,7 @@ class ATLAS_NOT_THREAD_SAFE LArNoiseBursts : public AthAlgorithm  {
    SG::ReadCondHandleKey<BunchCrossingCondData> m_bcDataKey 
      {this, "BunchCrossingCondDataKey", "BunchCrossingData" ,"SG Key of BunchCrossing CDO"};
    /*Tools*/
-   ToolHandle< Trig::TrigDecisionTool > m_trigDec;
+   PublicToolHandle< Trig::TrigDecisionTool > m_trigDec{this, "TrigDecisionTool", "", "Handle to the TrigDecisionTool"};
 
    /*services*/
    const LArOnlineID* m_LArOnlineIDHelper;
@@ -218,11 +218,14 @@ class ATLAS_NOT_THREAD_SAFE LArNoiseBursts : public AthAlgorithm  {
    std::vector<float> m_nt_etacell;
    std::vector<float> m_nt_signifcell;
    //float m_nt_noisycellpercent;
+   std::vector<short> m_nt_barrelec_noisy;
+   std::vector<short> m_nt_posneg_noisy;
    std::vector<short> m_nt_ft_noisy;
    std::vector<short> m_nt_slot_noisy;
    std::vector<short> m_nt_channel_noisy;
    std::vector<short>    m_nt_cellpartlayerindex;
    std::vector< unsigned int > m_nt_cellIdentifier;
+   std::vector< unsigned int > m_nt_onlIdentifier;
    std::vector<float> m_nt_noisycellpart;
    std::vector<int> m_nt_noisycellHVphi;
    std::vector<int> m_nt_noisycellHVeta;
diff --git a/LArCalorimeter/LArCafJobs/python/LArNoiseConfig.py b/LArCalorimeter/LArCafJobs/python/LArNoiseConfig.py
index 15c8e4cff504164df30a2f8957bff9f7265a4b89..f519f695a76daebebe6fab26d9f2c9abb450ddd6 100644
--- a/LArCalorimeter/LArCafJobs/python/LArNoiseConfig.py
+++ b/LArCalorimeter/LArCafJobs/python/LArNoiseConfig.py
@@ -27,12 +27,13 @@ def LArNoiseCfg(flags):
     result.merge(LArCollisionTimeCfg(flags))
 
     from TrigDecisionTool.TrigDecisionToolConfig import TrigDecisionToolCfg
-    result.merge(TrigDecisionToolCfg(flags))
+    tdt = result.getPrimaryAndMerge(TrigDecisionToolCfg(flags))
 
     noiseAlg=CompFactory.LArNoiseBursts("LArNoiseBursts")
     noiseAlg.SigmaCut = flags.LArNoise.SigmaCut
     noiseAlg.NumberOfBunchesInFront = flags.LArNoise.NumberOfBunchesInFront
     noiseAlg.KeepOnlyCellID = flags.LArNoise.KeepOnlyCellID
+    noiseAlg.TrigDecisionTool = tdt
     result.addEventAlgo(noiseAlg)
 
     if (flags.LArNoise.outNtupLAr!=""):
@@ -59,16 +60,16 @@ def LArNoiseFromRawCfg(flags):
 
     result=ComponentAccumulator()
 
-    from LArByteStream.LArRawDataReadingConfig import LArRawDataReadingCfg
-    result.merge(LArRawDataReadingCfg(flags))
+    #from LArByteStream.LArRawDataReadingConfig import LArRawDataReadingCfg
+    #result.merge(LArRawDataReadingCfg(flags))
 
-    #Setup cabling
-    from LArCabling.LArCablingConfig import LArOnOffIdMappingCfg
-    result.merge(LArOnOffIdMappingCfg(flags))
-    # setup bad chan and missing febs
-    from LArBadChannelTool.LArBadChannelConfig import LArBadChannelCfg,LArBadFebCfg
-    LArBadChannelCfg(flags)
-    LArBadFebCfg(flags)
+    ##Setup cabling
+    #from LArCabling.LArCablingConfig import LArOnOffIdMappingCfg
+    #result.merge(LArOnOffIdMappingCfg(flags))
+    ## setup bad chan and missing febs
+    #from LArBadChannelTool.LArBadChannelConfig import LArBadChannelCfg,LArBadFebCfg
+    #LArBadChannelCfg(flags)
+    #LArBadFebCfg(flags)
 
     from CaloRec.CaloRecoConfig import CaloRecoCfg
     result.merge(CaloRecoCfg(flags))
@@ -87,9 +88,11 @@ def LArNoiseFromRawCfg(flags):
        from LArCellRec.LArTimeVetoAlgConfig import LArTimeVetoAlgCfg
        result.merge(LArTimeVetoAlgCfg(flags))
 
-       if (flags.LArNoise.outHistLAr == ""):
-          from TrigDecisionTool.TrigDecisionToolConfig import TrigDecisionToolCfg
-          result.merge(TrigDecisionToolCfg(flags))
+       from LArCafJobs.LArSCDumperSkeleton import L1CaloMenuCfg
+       result.merge(L1CaloMenuCfg(flags))
+
+       from TrigDecisionTool.TrigDecisionToolConfig import TrigDecisionToolCfg
+       tdt = result.getPrimaryAndMerge(TrigDecisionToolCfg(flags))
 
 
     if (flags.LArNoise.outNtupLAr != ""):
@@ -97,6 +100,7 @@ def LArNoiseFromRawCfg(flags):
        noiseAlg.SigmaCut = flags.LArNoise.SigmaCut
        noiseAlg.NumberOfBunchesInFront = flags.LArNoise.NumberOfBunchesInFront
        noiseAlg.KeepOnlyCellID = flags.LArNoise.KeepOnlyCellID
+       noiseAlg.TrigDecisionTool = tdt
        result.addEventAlgo(noiseAlg)
 
        result.addService(CompFactory.THistSvc(Output=["TTREE DATAFILE='"+flags.LArNoise.outNtupLAr+"' OPT='RECREATE'",]))
@@ -133,9 +137,17 @@ if __name__=="__main__":
     
     from LArNoiseFlags import addNoiseFlags
     addNoiseFlags(flags)
-    #flags.Input.Files=['/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/MetadataTests/data18/data18_13TeV.00363979.physics_Main.daq.ESD.0750._0001.pool.root']
-    flags.Input.Files=['/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/RecExOnline/data16_13TeV.00302347.express_express.merge.RAW._lb0432._SFO-ALL._0001.1']
+    #flags.Input.Files=['/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/TrigP1Test/data23_cos.00457007.physics_CosmicMuons.merge.RAW._lb0043._SFO-ALL._0001.1']
+    flags.Input.Files=['/eos/atlas/atlastier0/rucio/data23_13p6TeV/express_express/00461002/data23_13p6TeV.00461002.express_express.merge.RAW/data23_13p6TeV.00461002.express_express.merge.RAW._lb0922._SFO-ALL._0001.1']
+
+    from AthenaConfiguration.TestDefaults import defaultGeometryTags
+    flags.GeoModel.AtlasVersion = defaultGeometryTags.RUN3
 
+    flags.Trigger.triggerConfig = 'DB'    
+    flags.Trigger.doID=False
+    flags.Trigger.doMuon=False
+    flags.Trigger.doLVL1=False
+    flags.Trigger.doHLT=False
     flags.lock()
 
     from AthenaConfiguration.MainServicesConfig import MainServicesCfg
diff --git a/LArCalorimeter/LArCafJobs/python/LArNoiseFromRawSkeleton.py b/LArCalorimeter/LArCafJobs/python/LArNoiseFromRawSkeleton.py
index d0d1308e27ae73ed0ed86bfadbe37dc466acb485..5ba6342e73dd559ca4fd71d5f092e5c8266a161b 100644
--- a/LArCalorimeter/LArCafJobs/python/LArNoiseFromRawSkeleton.py
+++ b/LArCalorimeter/LArCafJobs/python/LArNoiseFromRawSkeleton.py
@@ -49,6 +49,10 @@ def fromRunArgs(runArgs):
     if hasattr(runArgs,"maxEvents"):
         flags.Exec.MaxEvents=runArgs.maxEvents
 
+    from AthenaConfiguration.TestDefaults import defaultGeometryTags
+    flags.GeoModel.AtlasVersion = defaultGeometryTags.RUN3
+    flags.Trigger.triggerConfig = 'DB'    
+    flags.Trigger.L1.doCTP = True
     flags.Trigger.doID=False
     flags.Trigger.doMuon=False
     flags.Trigger.doLVL1=False
diff --git a/LArCalorimeter/LArCafJobs/python/LArReadCellsConfig.py b/LArCalorimeter/LArCafJobs/python/LArReadCellsConfig.py
index 7b2f65251d9f0cc012187436a36a22b8577afb03..2dc7722dc67fa8fcb3ee5ddc9bf798c5d4a27fcc 100644
--- a/LArCalorimeter/LArCafJobs/python/LArReadCellsConfig.py
+++ b/LArCalorimeter/LArCafJobs/python/LArReadCellsConfig.py
@@ -39,6 +39,7 @@ def LArReadCellsCfg(flags):
     dumperAlg=CompFactory.LArReadCells("LArReadCells")
     dumperAlg.output = flags.LArShapeDump.outputNtup
     dumperAlg.etCut = -1500.
+    dumperAlg.etCut2 = -1500.
 
     result.addEventAlgo(dumperAlg)
 
diff --git a/LArCalorimeter/LArCafJobs/python/LArReadCellsSkeleton.py b/LArCalorimeter/LArCafJobs/python/LArReadCellsSkeleton.py
index 6c9eefa346bd7e7d7e55f76acce05aa6511735a1..45e584704e41133e60f7c0f99642a3b39a998cd0 100644
--- a/LArCalorimeter/LArCafJobs/python/LArReadCellsSkeleton.py
+++ b/LArCalorimeter/LArCafJobs/python/LArReadCellsSkeleton.py
@@ -20,6 +20,8 @@ def fromRunArgs(runArgs):
     processPreInclude(runArgs, flags)
     processPreExec(runArgs, flags)
 
+    from AthenaConfiguration.TestDefaults import defaultGeometryTags
+    flags.GeoModel.AtlasVersion = defaultGeometryTags.RUN3
     flags.LAr.ROD.forceIter=True
     flags.LAr.OFCShapeFolder="4samples3bins17phases"
     flags.Input.Files=runArgs.inputBSFile
diff --git a/LArCalorimeter/LArCafJobs/python/LArSCDumperSkeleton.py b/LArCalorimeter/LArCafJobs/python/LArSCDumperSkeleton.py
index 7a9ace939e4309e2d913a8e7295bba2be176e81b..37f86884628b618bef67b1f8023a9352cd982b0c 100644
--- a/LArCalorimeter/LArCafJobs/python/LArSCDumperSkeleton.py
+++ b/LArCalorimeter/LArCafJobs/python/LArSCDumperSkeleton.py
@@ -127,7 +127,7 @@ def fromRunArgs(runArgs):
 
     cfg.merge(LArSC2NtupleCfg(flags, AddBadChannelInfo=flags.LArSCDump.doBC, AddFEBTempInfo=False, isSC=True, isFlat=False,
                             OffId=flags.LArSCDump.doOfflineId, AddHash=flags.LArSCDump.doHash, AddCalib=flags.LArSCDump.doCalib, RealGeometry=flags.LArSCDump.doGeom, ExpandId=flags.LArSCDump.expandId, # from LArCond2NtupleBase 
-                            NSamples=flags.LArSCDump.nSamples, FTlist={}, FillBCID=flags.LArSCDump.doBCID, ContainerKey=flags.LArSCDump.digitsKey,  # from LArDigits2Ntuple
+                            NSamples=flags.LArSCDump.nSamples, FTlist=[], FillBCID=flags.LArSCDump.doBCID, ContainerKey=flags.LArSCDump.digitsKey,  # from LArDigits2Ntuple
                             SCContainerKeys=CKeys, OverwriteEventNumber = flags.LArSCDump.overwriteEvN, Net=flags.LArSCDump.nEt, # from LArSC2Ntuple
                             FillRODEnergy = flags.LArSCDump.doRawChan, FillLB = True, FillTriggerType = True,
                             TrigNames=["L1_EM3","L1_EM7","L1_EM15","L1_EM22VHI","L1_eEM5","L1_eEM15","L1_eEM22M"],
diff --git a/LArCalorimeter/LArCafJobs/python/LArShapeDumperSkeleton.py b/LArCalorimeter/LArCafJobs/python/LArShapeDumperSkeleton.py
index 3a8ebe6efcab99d018e5adc947307e2b6cc15a18..1e2cd94fb5597c614036d71efcd8df6d6d0a8a24 100644
--- a/LArCalorimeter/LArCafJobs/python/LArShapeDumperSkeleton.py
+++ b/LArCalorimeter/LArCafJobs/python/LArShapeDumperSkeleton.py
@@ -20,6 +20,8 @@ def fromRunArgs(runArgs):
     processPreInclude(runArgs, flags)
     processPreExec(runArgs, flags)
 
+    from AthenaConfiguration.TestDefaults import defaultGeometryTags
+    flags.GeoModel.AtlasVersion = defaultGeometryTags.RUN3
     flags.LAr.ROD.forceIter=True
     flags.LAr.OFCShapeFolder="4samples3bins17phases"
     flags.Input.Files=runArgs.inputBSFile
diff --git a/LArCalorimeter/LArCafJobs/share/LArNoiseBursts_fromraw_tf.py b/LArCalorimeter/LArCafJobs/share/LArNoiseBursts_fromraw_tf.py
new file mode 100755
index 0000000000000000000000000000000000000000..6a425acab604ec61143f46592a8876425996f937
--- /dev/null
+++ b/LArCalorimeter/LArCafJobs/share/LArNoiseBursts_fromraw_tf.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
+
+__doc__ = """JobTransform to run LAr Noise Burst jobs"""
+
+
+import sys
+from PyJobTransforms.transform import transform
+from PyJobTransforms.trfExe import athenaExecutor
+from PyJobTransforms.trfArgs import addAthenaArguments, addDetectorArguments
+import PyJobTransforms.trfArgClasses as trfArgClasses
+
+if __name__ == '__main__':
+
+    executorSet = set()
+    executorSet.add(athenaExecutor(name = 'LArNoiseBursts_from_raw', skeletonFile = None,
+                    skeletonCA='LArCafJobs.LArNoiseFromRawSkeleton',
+                    substep = 'r2e', inData = ['BS',], outData = ['NTUP_LARNOISE','NTUP_HECNOISE','HIST_LARNOISE']))
+    
+    trf = transform(executor = executorSet) 
+    addAthenaArguments(trf.parser)
+    addDetectorArguments(trf.parser)
+    
+    trf.parser.add_argument('--inputBSFile', nargs='+',
+                            type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='input'),
+                            help='Input BS file', group='Reco Files')
+    
+    trf.parser.add_argument('--outputNTUP_LARNOISEFile', nargs='+',
+                            type=trfArgClasses.argFactory(trfArgClasses.argNTUPFile, io='output'),
+                            help='Output LAr Noise Burst file', group='Ntuple Files')
+ 
+    trf.parser.add_argument('--outputNTUP_HECNOISEFile', nargs='+',
+                            type=trfArgClasses.argFactory(trfArgClasses.argNTUPFile, io='output'),
+                            help='Output HECNoise file', group='Ntuple Files')
+ 
+    trf.parser.add_argument('--outputHIST_LARNOISEFile', nargs='+',
+                            type=trfArgClasses.argFactory(trfArgClasses.argHISTFile, io='output',countable=False),
+                            help='Output Noise hist file', group='Hist Files')
+ 
+    trf.parseCmdLineArgs(sys.argv[1:])
+    trf.execute()
+    trf.generateReport()
+
diff --git a/LArCalorimeter/LArCafJobs/share/LArNoiseBursts_tf.py b/LArCalorimeter/LArCafJobs/share/LArNoiseBursts_tf.py
index 02e9a296e61ddd75b8390cfd6a331ea2918e7056..82c179fa428e797d886eb07ce7dbcf9567f0423d 100755
--- a/LArCalorimeter/LArCafJobs/share/LArNoiseBursts_tf.py
+++ b/LArCalorimeter/LArCafJobs/share/LArNoiseBursts_tf.py
@@ -17,14 +17,12 @@ if __name__ == '__main__':
     executorSet.add(athenaExecutor(name = 'LArNoiseBursts',
                                    skeletonCA='LArCafJobs.LArNoiseSkeleton',
                                    substep = 'e2a', inData = ['ESD',], outData = ['NTUP_LARNOISE','NTUP_HECNOISE']))
-   
     trf = transform(executor = executorSet) 
     addAthenaArguments(trf.parser)
     addDetectorArguments(trf.parser)
     trf.parser.add_argument('--inputESDFile', nargs='+',
                             type=trfArgClasses.argFactory(trfArgClasses.argPOOLFile, io='input'),
                             help='Input pool file', group='Reco Files')
-   
     trf.parser.add_argument('--outputNTUP_LARNOISEFile', nargs='+',
                             type=trfArgClasses.argFactory(trfArgClasses.argNTUPFile, io='output'),
                             help='Output LAr Noise Burst file', group='Ntuple Files')
diff --git a/LArCalorimeter/LArCafJobs/share/LArReadCells_overlay.py b/LArCalorimeter/LArCafJobs/share/LArReadCells_overlay.py
deleted file mode 100644
index cf291c8c884d18061f43531580fe9c0fcecfacb5..0000000000000000000000000000000000000000
--- a/LArCalorimeter/LArCafJobs/share/LArReadCells_overlay.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-###############################################################
-#
-# Job options file to read data overlay  pool file with LArRawChannel and run LArReadCells
-#
-#==============================================================
-from AthenaCommon.DetFlags import DetFlags
-DetFlags.detdescr.all_setOn()
-DetFlags.Muon_setOff()
-DetFlags.Forward_setOff()
-
-
-from AthenaCommon.GlobalFlags import globalflags
-globalflags.DetGeo = 'atlas'
-globalflags.DataSource = 'data'
-globalflags.InputFormat = 'pool'
-
-from RecExConfig.RecFlags import rec
-rec.readESD.set_Value_and_Lock(False)
-rec.readRDO.set_Value_and_Lock(True)
-
-from AthenaCommon.BeamFlags import jobproperties
-jobproperties.Beam.numberOfCollisions.set_Value_and_Lock(20.0)
-jobproperties.Beam.bunchSpacing.set_Value_and_Lock(25)
-
-from LArROD.LArRODFlags import larRODFlags
-larRODFlags.readDigits.set_Value_and_Lock(False)
-
-from LArConditionsCommon.LArCondFlags import larCondFlags
-larCondFlags.LoadElecCalib.set_Value_and_Lock(True)
-
-from CaloRec.CaloCellFlags import jobproperties
-jobproperties.CaloCellFlags.doLArDeadOTXCorr=False
-jobproperties.CaloCellFlags.doLArThinnedDigits=False
-jobproperties.CaloCellFlags.doPileupOffsetBCIDCorr=False
-
-include( "AthenaPoolCnvSvc/ReadAthenaPool_jobOptions.py" )
-include( "PartPropSvc/PartPropSvc.py" )
-#
-# Pool Converters
-#
-include( "EventAthenaPool/EventAthenaPool_joboptions.py" )
-include( "GeneratorObjectsAthenaPool/GeneratorObjectsAthenaPool_joboptions.py" )
-include( "LArAthenaPool/LArAthenaPool_joboptions.py" )
-include( "G4SimAthenaPOOL/G4SimAthenaPOOL_joboptions.py" )
-
-# Get a handle to the ServiceManager
-from AthenaCommon.AppMgr import ServiceMgr as svcMgr
-# Get a handle to the ApplicationManager
-from AthenaCommon.AppMgr import theApp
-
-#
-# Pool input
-#
-PoolRDOInput = [
-"test1/dataOverlayRDO.pool.root"
-]
-
-svcMgr.EventSelector.InputCollections = PoolRDOInput
-from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
-athenaCommonFlags.FilesInput = PoolRDOInput
-
-# the Tile, LAr and Calo detector description package
-from AthenaCommon.GlobalFlags import jobproperties
-jobproperties.Global.DetDescrVersion='ATLAS-R2-2015-03-01-00'
-
-from AtlasGeoModel import SetGeometryVersion
-from AtlasGeoModel import GeoModelInit
-
-from IOVDbSvc.CondDB import conddb
-conddb.blockFolder("/LAR/LArCellPositionShift")
-conddb.addFolderWithTag("LAR_OFL","/LAR/LArCellPositionShift","LArCellPositionShift-ideal",force=True,forceMC=True,className="CaloRec::CaloCellPositionShift")
-
-include( "CaloConditions/CaloConditions_jobOptions.py" )
-include( "LArDetDescr/LArDetDescr_joboptions.py" )
-include( "LArConditionsCommon/LArConditionsCommon_comm_jobOptions.py")
-include("TileConditions/TileConditions_jobOptions.py" )
-include( "TileConditions/TileConditions_jobOptions.py" ) 
-
-from RecExConfig.ObjKeyStore import objKeyStore
-objKeyStore.readInputFile('RecExPers/OKS_streamRDO.py')
-
-from AthenaCommon.AlgSequence import AlgSequence
-topSequence = AlgSequence()
-
-from CaloRec.CaloCellGetter import CaloCellGetter
-CaloCellGetter()
-
-topSequence += CfgMgr.LArReadCells()
-topSequence.LArReadCells.etCut = -1e6
-
-#--------------------------------------------------------------
-# Set output level threshold (2=DEBUG, 3=INFO, 4=WARNING, 5=ERROR, 6=FATAL )
-#-------------------------------------------------------------
-svcMgr.MessageSvc.OutputLevel      = INFO
-
-if not hasattr(ServiceMgr, 'THistSvc'):
-   from GaudiSvc.GaudiSvcConf import THistSvc
-   ServiceMgr += THistSvc()
-
-ServiceMgr.THistSvc.Output  = ["SPLASH DATAFILE='ntuple1.root' OPT='RECREATE'"]
-
-#--------------------------------------------------------------
-# Event related parameters
-#--------------------------------------------------------------
-# Number of events to be processed (default is 10)
-theApp.EvtMax = 1000000
-theApp.EvtSel = "EventSelector"
-
diff --git a/LArCalorimeter/LArCafJobs/share/samples_tweaks.py b/LArCalorimeter/LArCafJobs/share/samples_tweaks.py
deleted file mode 100644
index 4aa6a47fa58d773fb069c3e525dba3330f0aabbf..0000000000000000000000000000000000000000
--- a/LArCalorimeter/LArCafJobs/share/samples_tweaks.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-# Reco_trf tweaks (use as preInclude in Reco_trf)
-
-## Default changes (done for f274 tag)
-# InDetFlags.useBeamConstraint.set_Value_and_Lock(True)
-from CaloRec.CaloCellFlags import jobproperties
-jobproperties.CaloCellFlags.doLArDeadOTXCorr.set_Value_and_Lock(False)
-
-# Special for LArCafJobs: remove unneccessary stuff
-from RecExConfig.RecFlags import rec
-rec.doJetMissingETTag.set_Value_and_Lock(False)
-rec.doMuon.set_Value_and_Lock(False)
-rec.doMuonCombined.set_Value_and_Lock(False)
-rec.doInDet.set_Value_and_Lock(False)
-rec.doEgamma.set_Value_and_Lock(False)
-rec.doTau.set_Value_and_Lock(False)
-rec.doPerfMon.set_Value_and_Lock(False)
-rec.doWriteESD.set_Value_and_Lock(False)
-rec.doDPD.set_Value_and_Lock(False)
-#rec.doTrigger.set_Value_and_Lock(False)
-rec.doZdc.set_Value_and_Lock(False)
-rec.doLucid.set_Value_and_Lock(False)
-
-# Set data source
-from AthenaCommon.GlobalFlags import globalflags
-globalflags.DataSource.set_Value_and_Lock('data')
-
-# Make sure all the shapes are loaded
-from LArConditionsCommon.LArCondFlags import larCondFlags
-larCondFlags.LArCoolChannelSelection.set_Value_and_Lock('')
diff --git a/LArCalorimeter/LArCafJobs/src/LArNoiseBursts.cxx b/LArCalorimeter/LArCafJobs/src/LArNoiseBursts.cxx
index 6d6ca9db311c9f1aa26761099eb4c96798cc5efc..00a2046d7a1828d585a1f828d36eb0838edd5622 100644
--- a/LArCalorimeter/LArCafJobs/src/LArNoiseBursts.cxx
+++ b/LArCalorimeter/LArCafJobs/src/LArNoiseBursts.cxx
@@ -67,7 +67,7 @@ using namespace std;
 int nlarcell=0;
 int n_noisy_cell_part[8] = {0,0,0,0,0,0,0,0};
 int n_cell_part[8] = {0,0,0,0,0,0,0,0};
-std::vector<short> v_ft_noisy, v_slot_noisy, v_channel_noisy;
+std::vector<short> v_barrelec_noisy, v_posneg_noisy,v_ft_noisy, v_slot_noisy, v_channel_noisy;
 std::vector<bool> v_isbarrel, v_isendcap, v_isfcal, v_ishec;
 std::vector<short> v_layer; 
 std::vector<int> v_partition,v_noisycellHVphi,v_noisycellHVeta;
@@ -77,6 +77,7 @@ std::vector<bool> v_isbadcell;
 std::vector<IdentifierHash>  v_IdHash;
 std::vector<int> v_cellpartlayerindex;
 std::vector<Identifier> v_cellIdentifier;
+std::vector<HWIdentifier> v_onlIdentifier;
 
 //////////////////////////////////////////////////////////////////////////////////////
 /// Constructor
@@ -87,7 +88,6 @@ LArNoiseBursts::LArNoiseBursts(const std::string& name,
   : AthAlgorithm(name, pSvcLocator),
     m_thistSvc(nullptr),
     m_tree(nullptr),
-    m_trigDec( "Trig::TrigDecisionTool/TrigDecisionTool" ),
     m_LArOnlineIDHelper(nullptr),
     m_LArHVLineIDHelper(nullptr),
     m_LArElectrodeIDHelper(nullptr),
@@ -177,11 +177,14 @@ LArNoiseBursts::LArNoiseBursts(const std::string& name,
     m_nt_etacell(0),
     m_nt_signifcell(0),
     //m_nt_noisycellpercent(0),
+    m_nt_barrelec_noisy(0),
+    m_nt_posneg_noisy(0),
     m_nt_ft_noisy(0),
     m_nt_slot_noisy(0),
     m_nt_channel_noisy(0),
     m_nt_cellpartlayerindex(0),
     m_nt_cellIdentifier(0),
+    m_nt_onlIdentifier(0),
     m_nt_noisycellpart(0),
     m_nt_noisycellHVphi(0),
     m_nt_noisycellHVeta(0),
@@ -204,10 +207,6 @@ LArNoiseBursts::LArNoiseBursts(const std::string& name,
     m_nt_cellIdentifier_sat(0)
  {
 
-   // Trigger
-   declareProperty( "TrigDecisionTool", m_trigDec );
-   
-   
    //event cuts
    declareProperty("SigmaCut", m_sigmacut = 3.0);
    declareProperty("NumberOfBunchesInFront",m_frontbunches = 36);
@@ -252,13 +251,7 @@ StatusCode LArNoiseBursts::initialize() {
   ATH_MSG_DEBUG ( "Initializing LArNoiseBursts" );
  
   // Trigger Decision Tool
-  if(!m_trigDec.empty()){
-    if(m_trigDec.retrieve().isFailure()){
-      ATH_MSG_WARNING ( "Failed to retrieve trigger decision tool " << m_trigDec );
-    }else{
-      ATH_MSG_INFO ( "Retrieved tool " << m_trigDec );
-    }
-   }
+  ATH_CHECK( m_trigDec.retrieve() );
   
   ATH_CHECK( m_cablingKey.initialize() );
   ATH_CHECK( m_BCKey.initialize() );
@@ -402,8 +395,11 @@ StatusCode LArNoiseBursts::initialize() {
 
   // Properties of cells with fabs(energy/noise)>3
   m_tree->Branch("NoisyCellPartitionLayerIndex",&m_nt_cellpartlayerindex); /// NEW Identifier of the cell
-  m_tree->Branch("NoisyCellOnlineIdentifier",&m_nt_cellIdentifier); // Identifier of the noisy cell
+  m_tree->Branch("NoisyCellIdentifier",&m_nt_cellIdentifier); // Identifier of the noisy cell
+  m_tree->Branch("NoisyCellOnlineIdentifier",&m_nt_onlIdentifier); // Identifier of the noisy cell
   m_tree->Branch("NoisyCellPartition",&m_nt_partition); // Partition in 1 integer: 0:embc 1:emba 2:emecc 3:emeca 4:fcalc 5:fcala 6:hecc 7:heca
+  m_tree->Branch("NoisyCellBarrelEc",&m_nt_barrelec_noisy);            // BC 
+  m_tree->Branch("NoisyCellPosNeg",&m_nt_posneg_noisy);                // side 
   m_tree->Branch("NoisyCellFT",&m_nt_ft_noisy);                        // FT 
   m_tree->Branch("NoisyCellSlot",&m_nt_slot_noisy);                    // Slot
   m_tree->Branch("NoisyCellChannel",&m_nt_channel_noisy);              // Channel
@@ -558,6 +554,8 @@ StatusCode LArNoiseBursts::clear() {
   m_nt_partition.clear();
   m_nt_layer.clear();
   //m_nt_noisycellpercent = -1;
+  m_nt_barrelec_noisy.clear();
+  m_nt_posneg_noisy.clear();
   m_nt_ft_noisy.clear();
   m_nt_slot_noisy.clear();
   m_nt_channel_noisy.clear();
@@ -565,6 +563,7 @@ StatusCode LArNoiseBursts::clear() {
   m_nt_cellsize    = -1;
   m_nt_cellpartlayerindex.clear();
   m_nt_cellIdentifier.clear();
+  m_nt_onlIdentifier.clear();
   m_nt_noisycellpart.clear();
   m_nt_samples.clear();
   m_nt_gain.clear();
@@ -986,12 +985,13 @@ StatusCode LArNoiseBursts::doLArNoiseBursts(){
   m_nb_sat = 0;
   m_noisycell =0;
   nlarcell = 0;
+  v_barrelec_noisy.clear(); v_posneg_noisy.clear();
   v_ft_noisy.clear();v_slot_noisy.clear();v_channel_noisy.clear();
   v_isbarrel.clear();v_isendcap.clear();v_isfcal.clear();v_ishec.clear();
   v_layer.clear();v_partition.clear();v_energycell.clear();v_qfactorcell.clear(); 
   v_phicell.clear();v_etacell.clear();v_signifcell.clear();v_isbadcell.clear();
   v_IdHash.clear();v_noisycellHVeta.clear();v_noisycellHVphi.clear();
-  v_cellpartlayerindex.clear();v_cellIdentifier.clear();
+  v_cellpartlayerindex.clear();v_cellIdentifier.clear();v_onlIdentifier.clear();
 
   float eCalo;
   float qfactor;
@@ -1141,7 +1141,10 @@ StatusCode LArNoiseBursts::doLArNoiseBursts(){
       m_nt_signifcell.push_back( v_signifcell[i]);
       m_nt_partition.push_back( v_partition[i]);   
       m_nt_cellIdentifier.push_back(v_cellIdentifier[i].get_identifier32().get_compact());
+      m_nt_onlIdentifier.push_back(v_onlIdentifier[i].get_identifier32().get_compact());
       if(!m_keepOnlyCellID){
+        m_nt_barrelec_noisy.push_back( v_barrelec_noisy[i]);
+        m_nt_posneg_noisy.push_back( v_posneg_noisy[i]);
         m_nt_ft_noisy.push_back( v_ft_noisy[i]);
         m_nt_slot_noisy.push_back( v_slot_noisy[i]);
         m_nt_channel_noisy.push_back( v_channel_noisy[i]);
@@ -1251,6 +1254,8 @@ StatusCode LArNoiseBursts::fillCell(HWIdentifier onlID
     }
     // Store all cells in positive and negative 3 sigma tails...
     if(significance > m_sigmacut || qfactor > 4000){
+      v_barrelec_noisy.push_back(m_LArOnlineIDHelper->barrel_ec(onlID));
+      v_posneg_noisy.push_back(m_LArOnlineIDHelper->pos_neg(onlID));
       v_ft_noisy.push_back(m_LArOnlineIDHelper->feedthrough(onlID));
       v_slot_noisy.push_back(m_LArOnlineIDHelper->slot(onlID));
       v_channel_noisy.push_back(m_LArOnlineIDHelper->channel(onlID));
@@ -1272,6 +1277,7 @@ StatusCode LArNoiseBursts::fillCell(HWIdentifier onlID
       v_partition.push_back(partition);
       v_IdHash.push_back(channelHash);
       v_cellIdentifier.push_back(cabling->cnvToIdentifier(onlID));
+      v_onlIdentifier.push_back(onlID);
     // ...but count only cells in positive 3 sigma tails!
       if (significance > m_sigmacut){
 	m_noisycell++;
diff --git a/LArCalorimeter/LArCafJobs/src/LArSamplesMerge.cxx b/LArCalorimeter/LArCafJobs/src/LArSamplesMerge.cxx
index add996da199075a386c74234ff326fdb25a4aa69..b78a9fd9c74b7aa00dbb36ab19b7c6eb8feafad1 100644
--- a/LArCalorimeter/LArCafJobs/src/LArSamplesMerge.cxx
+++ b/LArCalorimeter/LArCafJobs/src/LArSamplesMerge.cxx
@@ -13,6 +13,7 @@
 #include "TROOT.h"
 #include "TApplication.h"
 #include "TSystem.h"
+#include "TFile.h"
 #include "CxxUtils/checker_macros.h"
 
 using namespace LArSamples;
@@ -57,8 +58,11 @@ int  main ATLAS_NOT_THREAD_SAFE (int argc, char** argv) {
     std::cout << "ERROR: Failed to merge files" << std::endl;
     result=-2;
   }
-  else
+  else {
     std::cout << "Wrote output file " << outFileName << " with " << output->nEvents() << " events." << std::endl;
+    output->file()->Close();
+    std::cout << "Out file closed"<<std::endl;
+  }  
 
   return result;
 }
diff --git a/LArCalorimeter/LArCalibTools/LArCalibTools/LArDigits2Ntuple.h b/LArCalorimeter/LArCalibTools/LArCalibTools/LArDigits2Ntuple.h
index e9ad32988c8bc9e9e5f89ecae580ea3dd38125a2..5e84bbfe9b3f781463d1fc96d61782dfe5861092 100644
--- a/LArCalorimeter/LArCalibTools/LArCalibTools/LArDigits2Ntuple.h
+++ b/LArCalorimeter/LArCalibTools/LArCalibTools/LArDigits2Ntuple.h
@@ -37,7 +37,7 @@ class LArDigits2Ntuple : public LArCond2NtupleBase
   NTuple::Item<long> m_ntNsamples;
   NTuple::Item<short> m_gain;
   NTuple::Item<short> m_bcid;
-  NTuple::Item<short> m_ELVL1Id;
+  NTuple::Item<unsigned long> m_ELVL1Id;
   NTuple::Item<unsigned long long> m_IEvent;
   NTuple::Array<short>  m_samples;
   //
diff --git a/LArCalorimeter/LArCalibTools/LArCalibTools/LArSC2Ntuple.h b/LArCalorimeter/LArCalibTools/LArCalibTools/LArSC2Ntuple.h
index 7ccc565134129cd5dcbe28217e31d3fc2d8fa9bd..2130c9d33bf03de890f696a2adfd91bfebf941ab 100644
--- a/LArCalorimeter/LArCalibTools/LArCalibTools/LArSC2Ntuple.h
+++ b/LArCalorimeter/LArCalibTools/LArCalibTools/LArSC2Ntuple.h
@@ -10,7 +10,9 @@
 #include "LArRawEvent/LArRawChannelContainer.h"
 #include "TrigDecisionTool/TrigDecisionTool.h"
 #include "xAODEventInfo/EventInfo.h"
+#include "LArRawEvent/LArLATOMEHeaderContainer.h"
 #include "TrigT1CaloEvent/TriggerTower.h"
+#include "TrigT1CaloCalibToolInterfaces/IL1CaloxAODOfflineTriggerTowerTools.h"
 
 class LArSC2Ntuple : public LArDigits2Ntuple
 {
@@ -44,6 +46,7 @@ class LArSC2Ntuple : public LArDigits2Ntuple
   SG::ReadHandleKey<xAOD::EventInfo> m_eventInfoKey{this, "LArStatusFlag", "EventInfo", "Key for EventInfo object"};
   SG::ReadDecorHandleKey<xAOD::EventInfo> m_eventInfoDecorKey{this, "EventInfoDecorKey", "EventInfo.larFlags"};
 
+  SG::ReadHandleKey<LArLATOMEHeaderContainer> m_LArLatomeHeaderContainerKey { this, "LArLatomeHeaderKey", "SC_LATOME_HEADER" };
   Gaudi::Property< std::string > m_triggerTowerKey{this, "TriggerTowerKey", "TriggerTowers", "Trigger Tower container"};
 
   NTuple::Item<short> m_latomeChannel;
diff --git a/LArCalorimeter/LArCalibTools/python/LArSC2NtupleConfig.py b/LArCalorimeter/LArCalibTools/python/LArSC2NtupleConfig.py
index ce919f1baf51ba32b86ac7f7fda1ab5fefb9c245..e8104d3e2aaae99999f9c30c18a2d59f9a28e54d 100644
--- a/LArCalorimeter/LArCalibTools/python/LArSC2NtupleConfig.py
+++ b/LArCalorimeter/LArCalibTools/python/LArSC2NtupleConfig.py
@@ -51,6 +51,8 @@ def LArSC2NtupleCfg(flags, **kwargs):
 
        alg=CompFactory.LArSC2Ntuple('LArSC2Ntuple',**kwargs)
 
+       print(alg)
+
        cfg.addEventAlgo(alg)
 
        return cfg
diff --git a/LArCalorimeter/LArCalibTools/src/LArDigits2Ntuple.cxx b/LArCalorimeter/LArCalibTools/src/LArDigits2Ntuple.cxx
index 58b9bdab5926715be1926491972dc6436caa4081..2e03210c86c6278f05917ef33185564d2508bf8d 100644
--- a/LArCalorimeter/LArCalibTools/src/LArDigits2Ntuple.cxx
+++ b/LArCalorimeter/LArCalibTools/src/LArDigits2Ntuple.cxx
@@ -6,7 +6,6 @@
 #include "LArRawEvent/LArDigitContainer.h"
 #include "Identifier/HWIdentifier.h"
 #include "LArRawEvent/LArSCDigit.h"
-#include "LArRawEvent/LArLATOMEHeaderContainer.h"
 
 LArDigits2Ntuple::LArDigits2Ntuple(const std::string& name, ISvcLocator* pSvcLocator):
   LArCond2NtupleBase(name, pSvcLocator),
@@ -35,10 +34,12 @@ StatusCode LArDigits2Ntuple::initialize()
     return sc;
   }
   
-  sc = m_nt->addItem("samples",m_Nsamples,m_samples);
-  if (sc!=StatusCode::SUCCESS) {
-    ATH_MSG_ERROR( "addItem 'samples' failed" );
-    return sc;
+  if(m_contKey.key().size()) {
+     sc = m_nt->addItem("samples",m_Nsamples,m_samples);
+     if (sc!=StatusCode::SUCCESS) {
+       ATH_MSG_ERROR( "addItem 'samples' failed" );
+       return sc;
+     }
   }
    
   sc = m_nt->addItem("Nsamples",m_ntNsamples,0,32);
@@ -55,19 +56,13 @@ StatusCode LArDigits2Ntuple::initialize()
     }
   }
 
-  if(!m_isSC){
-    sc = m_nt->addItem("ELVL1Id",m_ELVL1Id);
-    if (sc!=StatusCode::SUCCESS) {
-       ATH_MSG_ERROR( "addItem 'ELVL1Id' failed" );
-       return sc;
-    }
-  }else{
-    sc   = m_nt->addItem("ELVL1Id",m_ELVL1Id);
-    if (sc!=StatusCode::SUCCESS) {
-      ATH_MSG_ERROR( "addItem 'ELVL1Id' failed" );
-      return sc;
-    }
+  sc = m_nt->addItem("ELVL1Id",m_ELVL1Id);
+  if (sc!=StatusCode::SUCCESS) {
+     ATH_MSG_ERROR( "addItem 'ELVL1Id' failed" );
+     return sc;
+  }
 
+  if(!m_isSC){
     sc	   = m_nt->addItem("Gain",m_gain,-1,3);
     if (sc!=StatusCode::SUCCESS) {
       ATH_MSG_ERROR( "addItem 'Gain' failed" );
@@ -160,13 +155,13 @@ StatusCode LArDigits2Ntuple::execute()
   for( const LArDigit *digi : DigitContainer ){
 
     if(m_fillBCID) m_bcid	= thisbcid; 
+    m_ELVL1Id	   = thisELVL1Id; 
     m_IEvent	   = thisevent;
 
     unsigned int trueMaxSample	   = digi->nsamples();
 
     if (!m_isSC){
       m_gain	   = digi->gain();
-      m_ELVL1Id	   = thisELVL1Id; 
       if(m_gain < CaloGain::INVALIDGAIN || m_gain > CaloGain::LARNGAIN) m_gain  = CaloGain::LARNGAIN;
     }
     if(trueMaxSample>m_Nsamples){
diff --git a/LArCalorimeter/LArCalibTools/src/LArSC2Ntuple.cxx b/LArCalorimeter/LArCalibTools/src/LArSC2Ntuple.cxx
index 1e479521f440784e5e5c206d5e116221869b2500..17882a4b9da5926b742873abb2386ca2d732283c 100644
--- a/LArCalorimeter/LArCalibTools/src/LArSC2Ntuple.cxx
+++ b/LArCalorimeter/LArCalibTools/src/LArSC2Ntuple.cxx
@@ -31,6 +31,8 @@ StatusCode LArSC2Ntuple::initialize() {
   ATH_CHECK( m_eventInfoKey.initialize() );
   ATH_CHECK( m_eventInfoDecorKey.initialize() );
 
+  ATH_CHECK(m_LArLatomeHeaderContainerKey.initialize() );
+
   StatusCode sc=m_nt->addItem("latomeChannel",m_latomeChannel);
   if (sc.isFailure()) {
     ATH_MSG_ERROR( "addItem 'latomeChannel' failed" );
@@ -87,13 +89,6 @@ StatusCode LArSC2Ntuple::initialize() {
 	return sc;
       }
       
-    }else if ( ck == "SC_LATOME_HEADER" ){	// SC LATOME HEADER
-      sc	   = m_nt->addItem("bcidLATOMEHEAD",m_bcidLATOMEHEAD);
-      if (sc.isFailure()) {
-	ATH_MSG_ERROR( "addItem 'bcidLATOMEHEAD' failed" );
-	return sc;
-      }
-      
     }else if ( ck == "SC_ET" ){ // SC_ET RawSCContainer
       sc = m_nt->addItem("energyVec_ET", m_Net, m_energyVec_ET);
       if (sc.isFailure()) {
@@ -132,6 +127,12 @@ StatusCode LArSC2Ntuple::initialize() {
     
   }// end container key loop
 
+  sc      = m_nt->addItem("bcidLATOMEHEAD",m_bcidLATOMEHEAD);
+  if (sc.isFailure()) {
+    ATH_MSG_ERROR( "addItem 'bcidLATOMEHEAD' failed" );
+    return sc;
+  }
+
   if(m_fillTType) {
      sc = m_evt_nt->addItem("TType",  m_TType);
      if (sc.isFailure()) {
@@ -208,6 +209,7 @@ StatusCode LArSC2Ntuple::execute()
 
   // This should be used for main readout later, once TDAQ fill event headers also in calib. runs properly
   unsigned long thisbcid	  = evt->bcid();
+  unsigned long thisELVL1Id;
   unsigned long  thisttype = evt->level1TriggerType();
   //
   /// set it here once and no need to set at each SC/cell
@@ -268,13 +270,14 @@ StatusCode LArSC2Ntuple::execute()
       ATH_MSG_DEBUG( "Got LArRawSCContainer with key SC_ET_ID" );
   }
   
-  if ((std::find(m_contKeys.begin(), m_contKeys.end(), "SC_LATOME_HEADER")	  != m_contKeys.end()) ){
-    sc	   = evtStore()->retrieve(headcontainer,"SC_LATOME_HEADER");  
-    if (sc.isFailure()) {
-      ATH_MSG_WARNING( "Unable to retrieve LArLATOMEHeaderContainer with key SC_LATOME_HEADER from DetectorStore. " );
-    } 
-    else
-      ATH_MSG_DEBUG( "Got LArLATOMEHeaderContainer with key SC_LATOME_HEADER " ); 
+  SG::ReadHandle<LArLATOMEHeaderContainer> hdrCont(m_LArLatomeHeaderContainerKey);
+  if (! hdrCont.isValid()) {
+     ATH_MSG_WARNING( "No LArLATOME container found in TDS" );
+  } else {
+     ATH_MSG_DEBUG( "LArLATOME container found");
+     headcontainer=&*hdrCont;
+     thisELVL1Id   = (*hdrCont->begin())->L1Id();
+     ATH_MSG_DEBUG( " ELVL1I FROM LATOME HEADER " << thisELVL1Id );
   }
   
   if (headcontainer){// loop through header container and fill map
@@ -344,6 +347,7 @@ StatusCode LArSC2Ntuple::execute()
   for( int c    = 0;c<cellsno;++c ){
     if(m_fillBCID) m_bcid	   = thisbcid; 
 
+    m_ELVL1Id = thisELVL1Id;
     m_IEvent	   = thisevent;
     if(m_overwriteEventNumber) m_IEvent   = ctx.evt();
 
@@ -362,7 +366,7 @@ StatusCode LArSC2Ntuple::execute()
 
       if(trueMaxSample>m_Nsamples){
 	if(!m_ipass){
-	  ATH_MSG_WARNING( "The number of samples in data is larger than the one specified by JO: " << trueMaxSample << " > " << m_Nsamples << " --> only " << m_Nsamples << " will be available in the ntuple " );
+	  ATH_MSG_DEBUG( "The number of samples in data is larger than the one specified by JO: " << trueMaxSample << " > " << m_Nsamples << " --> only " << m_Nsamples << " will be available in the ntuple " );
 	  m_ipass   = 1;
 	}
 	trueMaxSample   = m_Nsamples;
@@ -382,6 +386,7 @@ StatusCode LArSC2Ntuple::execute()
 	    const LArLATOMEHeader*headmap   = LATOMEHeadMap[scdigi->SourceId()];
 	    if(headmap){
 	      m_bcidLATOMEHEAD   = headmap->BCId();
+              m_ELVL1Id = headmap->L1Id();
 	    }
 	  }   
 	  m_latomeChannel	   = scdigi->Channel();
@@ -410,7 +415,7 @@ StatusCode LArSC2Ntuple::execute()
     
       if(trueMaxSample>m_Nsamples){
         if(!m_ipass){
-          ATH_MSG_WARNING( "The number of samples in data is larger than the one specified by JO: " << trueMaxSample << " > " << m_Nsamples << " --> only " << m_Nsamples << " will be available in the ntuple " );
+          ATH_MSG_DEBUG( "The number of samples in data is larger than the one specified by JO: " << trueMaxSample << " > " << m_Nsamples << " --> only " << m_Nsamples << " will be available in the ntuple " );
           m_ipass=1;
         }
         trueMaxSample = m_Nsamples;
@@ -433,6 +438,7 @@ StatusCode LArSC2Ntuple::execute()
 	    const LArLATOMEHeader*headmap   = LATOMEHeadMap[scdigi->SourceId()];
 	    if(headmap){
 	      m_bcidLATOMEHEAD   = headmap->BCId();
+              m_ELVL1Id = headmap->L1Id();
 	    }
 	  }   
 	  m_latomeChannel	   = scdigi->Channel();
@@ -458,7 +464,7 @@ StatusCode LArSC2Ntuple::execute()
     
       if(trueMaxSample>m_Nsamples){
         if(!m_ipass){
-          ATH_MSG_WARNING( "The number of samples in data is larger than the one specified by JO: " << trueMaxSample << " > " << m_Nsamples << " --> only " << m_Nsamples << " will be available in the ntuple " );
+          ATH_MSG_DEBUG( "The number of samples in data is larger than the one specified by JO: " << trueMaxSample << " > " << m_Nsamples << " --> only " << m_Nsamples << " will be available in the ntuple " );
           m_ipass=1;
         }
         trueMaxSample = m_Nsamples;
@@ -484,6 +490,7 @@ StatusCode LArSC2Ntuple::execute()
            const LArLATOMEHeader*headmap   = LATOMEHeadMap[scdigi->SourceId()];
            if(headmap){
              m_bcidLATOMEHEAD	   = headmap->BCId();
+             m_ELVL1Id = headmap->L1Id();
            }
          }
          m_latomeChannel	   = scdigi->Channel();
@@ -507,6 +514,7 @@ StatusCode LArSC2Ntuple::execute()
 	  const LArLATOMEHeader*headmap   = LATOMEHeadMap[rawSC->SourceId()];
 	  if(headmap){
 	    m_bcidLATOMEHEAD	   = headmap->BCId();
+            m_ELVL1Id = headmap->L1Id();
 	  }
 	}
         if( m_fillRawChan && RawChannelContainer ){
@@ -541,6 +549,7 @@ StatusCode LArSC2Ntuple::execute()
 	  const LArLATOMEHeader*headmap   = LATOMEHeadMap[rawSC->SourceId()];
 	  if(headmap){
 	    m_bcidLATOMEHEAD	   = headmap->BCId();
+            m_ELVL1Id = headmap->L1Id();
 	  }
 	}
         if( m_fillRawChan && RawChannelContainer ){
@@ -628,7 +637,7 @@ void LArSC2Ntuple::fillRODEnergy(HWIdentifier SCId, rawChanMap_t &rawChanMap, co
        m_ROD_time[i] = rawChanMap[hwcell]->time();
        m_ROD_id[i] = rawChanMap[hwcell]->hardwareID().get_identifier32().get_compact();
     } else {
-       ATH_MSG_WARNING(i<<"-th cell invalid Id");
+       ATH_MSG_DEBUG(i<<"-th cell invalid Id");
     }
  }
 
diff --git a/LArCalorimeter/LArExample/LArCalibProcessing/share/LArSC2NtupleDumper.py b/LArCalorimeter/LArExample/LArCalibProcessing/share/LArSC2NtupleDumper.py
index f5ebc05e9ba1426acad520e9bb776cda7e008fe6..56f6818a72ee13120fcf2378d8b3a1eb41662042 100755
--- a/LArCalorimeter/LArExample/LArCalibProcessing/share/LArSC2NtupleDumper.py
+++ b/LArCalorimeter/LArExample/LArCalibProcessing/share/LArSC2NtupleDumper.py
@@ -23,24 +23,24 @@ if __name__=='__main__':
   parser.add_argument('-m','--maxev', dest='maxev', default=-1, help='Max number of events to dump', type=int)
   parser.add_argument('-x','--outlevel', dest='olevel', default=5, help='OuputLevel for dumping algo', type=int)
   parser.add_argument('-o','--outfile', dest='outfile', default="Digits.root", help='Output root filename', type=str)
-  parser.add_argument('-s','--addSamples', dest='samples', default=True, help='Add Samples to output ntuple', type=bool)
-  parser.add_argument('-a','--addSampBas', dest='samplesBas', default=False, help='Add ADC_BAS to output ntuple', type=bool)
-  parser.add_argument('-z','--addEt', dest='Et', default=False, help='Add ET to output ntuple', type=bool)
-  parser.add_argument('-g','--addEtId', dest='EtId', default=False, help='Add ET_ID to output ntuple', type=bool)
-  parser.add_argument('-l','--addLatHeader', dest='lheader', default=True, help='Add LATOME Header to output ntuple', type=bool)
-  parser.add_argument('-b','--addBCID', dest='bcid', default=True, help='Add BCID info to output ntuple', type=bool)
-  parser.add_argument('-e','--expandId', dest='expid', default=False, help='Expand online Id to fields', type=bool)
+  parser.add_argument('-s','--addSamples', dest='samples', default=False, help='Add Samples to output ntuple', action="store_true")
+  parser.add_argument('-a','--addSampBas', dest='samplesBas', default=False, help='Add ADC_BAS to output ntuple', action="store_true")
+  parser.add_argument('-z','--addEt', dest='Et', default=False, help='Add ET to output ntuple', action="store_true")
+  parser.add_argument('-g','--addEtId', dest='EtId', default=False, help='Add ET_ID to output ntuple', action="store_true")
+  parser.add_argument('-l','--noLatHeader', dest='lheader', default=True, help='Add LATOME Header to output ntuple', action='store_false')
+  parser.add_argument('-b','--noBCID', dest='bcid', default=True, help='Add BCID info to output ntuple', action='store_false')
+  parser.add_argument('-e','--expandId', dest='expid', default=False, help='Expand online Id to fields', action='store_true')
   parser.add_argument('-n','--nsamp', dest='nsamp', default=0, help='Number of samples to dump', type=int)
-  parser.add_argument('-c','--overEvNumber', dest='overEvN', default=False, help='Overwrite event number', type=bool)
-  parser.add_argument('-d','--addHash', dest='ahash', default=False, help='Add hash number to output ntuple', type=bool)
-  parser.add_argument('-j','--addOffline', dest='offline', default=False, help='Add offline Id to output ntuple', type=bool)
-  parser.add_argument('-k','--addCalib', dest='calib', default=False, help='Add calib. info to output ntuple', type=bool)
-  parser.add_argument('-t','--addGeom', dest='geom', default=False, help='Add real geom info to output ntuple', type=bool)
-  parser.add_argument('-u','--addBC', dest='bc', default=False, help='Add Bad. chan info to output ntuple', type=bool)
-  parser.add_argument('-w','--addROD', dest='rod', default=False, help='Add ROD energies sum to output ntuple', type=bool)
-  parser.add_argument('-v','--addEvTree', dest='evtree', default=False, help='Add tree with per event info to output ntuple', type=bool)
-  parser.add_argument('-q','--addNoisyRO', dest='noisyRO', default=False, help='Add reco and info from LArNoisyROSummary to output ntuple', type=bool)
-  parser.add_argument('--addTT', dest='TT', default=False, help='Add info from LArTriggerTowers to output ntuple', type=bool)
+  parser.add_argument('-c','--overEvNumber', dest='overEvN', default=False, help='Overwrite event number', action='store_true')
+  parser.add_argument('-d','--addHash', dest='ahash', default=False, help='Add hash number to output ntuple', action='store_true')
+  parser.add_argument('-j','--addOffline', dest='offline', default=False, help='Add offline Id to output ntuple', action='store_true')
+  parser.add_argument('-k','--addCalib', dest='calib', default=False, help='Add calib. info to output ntuple', action='store_true')
+  parser.add_argument('-t','--addGeom', dest='geom', default=False, help='Add real geom info to output ntuple', action='store_true')
+  parser.add_argument('-u','--noBC', dest='bc', default=False, help='Add Bad. chan info to output ntuple', action='store_true')
+  parser.add_argument('-w','--addROD', dest='rod', default=False, help='Add ROD energies sum to output ntuple', action='store_true')
+  parser.add_argument('-v','--addEvTree', dest='evtree', default=False, help='Add tree with per event info to output ntuple', action='store_true')
+  parser.add_argument('-q','--addNoisyRO', dest='noisyRO', default=False, help='Add reco and info from LArNoisyROSummary to output ntuple', action='store_true')
+  parser.add_argument('--addTT', dest='TT', default=False, help='Add info from LArTriggerTowers to output ntuple', action='store_true')
 
   args = parser.parse_args()
   if help in args and args.help is not None and args.help:
@@ -70,6 +70,10 @@ if __name__=='__main__':
   if args.run != 0:
      flags.Input.RunNumbers = [args.run]
 
+  # geometry
+  from AthenaConfiguration.TestDefaults import defaultGeometryTags
+  flags.GeoModel.AtlasVersion = defaultGeometryTags.RUN3
+
   # first autoconfig
   from LArConditionsCommon.LArRunFormat import getLArDTInfoForRun
   try:
@@ -159,6 +163,8 @@ if __name__=='__main__':
   #flags.Debug.DumpEvtStore=True
 
   flags.lock()
+  flags.dump('LArSCDump.*')
+
 
   #Import the MainServices (boilerplate)
   from AthenaConfiguration.MainServicesConfig import MainServicesCfg
@@ -182,17 +188,13 @@ if __name__=='__main__':
      acc.merge(LArBadFebCfg(flags))
 
   if args.geom:
-      log.warning("Adding real geometry is not working yet")
-      args.geom=False
-      # FIXME
-      #acc.addCondAlgo(CompFactory.CaloAlignCondAlg(LArAlignmentStore="",CaloCellPositionShiftFolder=""))
-      #acc.addCondAlgo(CompFactory.CaloSuperCellAlignCondAlg())
-      #AthReadAlg_ExtraInputs.append(('CaloSuperCellDetDescrManager', 'ConditionStore+CaloSuperCellDetDescrManager')) 
+      acc.addCondAlgo(CompFactory.CaloAlignCondAlg(LArAlignmentStore="",CaloCellPositionShiftFolder=""))
+      acc.addCondAlgo(CompFactory.CaloSuperCellAlignCondAlg())
 
   from LArCalibTools.LArSC2NtupleConfig import LArSC2NtupleCfg
   acc.merge(LArSC2NtupleCfg(flags, AddBadChannelInfo=args.bc, AddFEBTempInfo=False, isSC=True, isFlat=False, 
                             OffId=args.offline, AddHash=args.ahash, AddCalib=args.calib, RealGeometry=args.geom, ExpandId=args.expid, # from LArCond2NtupleBase 
-                            NSamples=flags.LArSCDump.nSamples, FTlist={}, FillBCID=args.bcid, ContainerKey=flags.LArSCDump.digitsKey,  # from LArDigits2Ntuple
+                            NSamples=flags.LArSCDump.nSamples, FTlist=[], FillBCID=args.bcid, ContainerKey=flags.LArSCDump.digitsKey,  # from LArDigits2Ntuple
                             SCContainerKeys=CKeys, OverwriteEventNumber = args.overEvN,                        # from LArSC2Ntuple
                             FillRODEnergy = flags.LArSCDump.doRawChan,
                             FillLB=args.evtree, FillTriggerType = args.evtree,
diff --git a/LArCalorimeter/LArL1Sim/CMakeLists.txt b/LArCalorimeter/LArL1Sim/CMakeLists.txt
index 24faf0fa3a33d09239173b7bd468be623b74f52c..4b986ace221b43f1fe386a5278cf830c451c1ef8 100644
--- a/LArCalorimeter/LArL1Sim/CMakeLists.txt
+++ b/LArCalorimeter/LArL1Sim/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 
 # Declare the package name:
 atlas_subdir( LArL1Sim )
@@ -14,7 +14,5 @@ atlas_add_component( LArL1Sim
                      LINK_LIBRARIES ${CLHEP_LIBRARIES} AthAllocators AthenaBaseComps GaudiKernel GeoModelInterfaces LArDigitizationLib CaloDetDescrLib CaloEvent CaloIdentifier CaloTriggerToolLib AthenaKernel StoreGateLib LArCablingLib LArElecCalib LArIdentifier LArRawEvent LArSimEvent LArRawConditions PathResolver )
 
 # Install files from the package:
-atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
-atlas_install_joboptions( share/*.py )
 atlas_install_runtime( share/Fcal_ptweights_table7.data )
 
diff --git a/LArCalorimeter/LArL1Sim/python/LArTTL1Getter.py b/LArCalorimeter/LArL1Sim/python/LArTTL1Getter.py
deleted file mode 100644
index 34baaf283238e46d4d26b6921f492dc0e9d82781..0000000000000000000000000000000000000000
--- a/LArCalorimeter/LArL1Sim/python/LArTTL1Getter.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-# Author: F. Ledroit (ledroit@lpsc.in2p3.fr)
-# LArTTL1 creation from LArHits with LArTTL1Maker algorithm
-
-from AthenaCommon.Logging import logging
-from RecExConfig.Configured import Configured
-from AthenaCommon.AlgSequence import AlgSequence
-topSequence = AlgSequence()
-import traceback
-
-class LArTTL1Getter ( Configured )  :
-
-        
-    def configure(self):
-        mlog = logging.getLogger( 'LArTTL1Getter::configure:' )
-        mlog.info ('entering')        
-
-        # get handle to upstream object
-        try:
-            from LArL1Sim.LArTTL1Getter import LArTTL1Getter
-            theLArTTL1Getter=LArTTL1Getter()
-        except Exception:
-            mlog.error("could not get handle to LArTTL1Getter Quit")
-            traceback.print_exc()
-            return False
-
-        if not theLArTTL1Getter.usable():
-            if not self.ignoreConfigError():
-                mlog.error("LArTTL1Getter unusable. Quit.")
-                return False
-            else:
-                mlog.error("LArTTL1Getter unusable. Continue nevertheless")
-                
-        # Instantiation of the C++ algorithm
-        try:        
-            from LArL1Sim.LArL1SimConf import LArTTL1Maker                
-        except Exception:
-            mlog.error("could not import LArL1Sim.LArTTL1Maker")
-            traceback.print_exc()
-            return False
-
-        theLArTTL1Maker=LArTTL1Maker()
-        self._LArTTL1Maker = theLArTTL1Maker
-
-        # Configure LArTTL1Maker here
-        #theLArTTL1Maker.SubDetectors="LAr_All"
-        #theLArTTL1Maker.EmBarrelHitContainerName="LArHitEMB"
-        #theLArTTL1Maker.EmEndCapHitContainerName="LArHitEMEC"
-        #theLArTTL1Maker.HecHitContainerName="LArHitHEC"
-        #theLArTTL1Maker.ForWardHitContainerName="LArHitFCAL"
-        
-        #theLArTTL1Maker.EmTTL1ContainerName="LArTTL1EM"
-        #theLArTTL1Maker.HadTTL1ContainerName="LArTTL1HAD"
-        
-        #theLArTTL1Maker.NoiseOnOff=true
-        
-        #theLArTTL1Maker.PileUp=false
-        #theLArTTL1Maker.UseTriggerTime=false
-        #theLArTTL1Maker.TriggerTimeToolName="CosmicTriggerTimeTool"
-        
-        #theLArTTL1Maker.EmBarrelCalibrationCoeffs=[1.03,  1.024, 1.019, 1.02,  1.02,  1.024, 1.03,  1.046, 1.06, 1.053, 1.057, 1.062, 1.063, 1.076, 1.176]
-        #theLArTTL1Maker.EmEndCapCalibrationCoeffs=[1.176, 1.061, 1.087, 1.015, 1.019, 1.014, 1.014, 1.009, 1.01, 1.003, 1.016, 1.003, 0.993, 1.005, 0.963]
-        #theLArTTL1Maker.HECCalibrationCoeffs=[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]
-        #theLArTTL1Maker.EmFcalCalibrationCoeffs=[1., 1., 1., 1.]
-        #theLArTTL1Maker.HadFcalCalibrationCoeffs=[1., 1., 1., 1.]
-        
-        #theLArTTL1Maker.NoEmCalibrationMode=false
-        #theLArTTL1Maker.NoHadCalibrationMode=false
-        #theLArTTL1Maker.ChronoTest=false
-        #theLArTTL1Maker.DebugThreshold=5000.
-
-        from AthenaCommon.AlgSequence import AlgSequence
-        topSequence = AlgSequence()
-
-        # check if LArdigitization is run before. If yes, uses hit map from detector store produces from lardigitization
-        from AthenaCommon.DetFlags import DetFlags
-        if DetFlags.digitize.LAr_on():
-            mlog.info("Using hit map from LArHitEMapMaker algoritm")
-        else:
-            mlog.info("digitmaker1 not found in topSequence, using own map in LArTTL1Maker")
-            theLArTTL1Maker.useMapFromStore = False
- 
-        
-        
-        # now add algorithm to topSequence
-        # this should always come at the end
-
-        mlog.info(" now adding to topSequence")        
-        topSequence += theLArTTL1Maker
-
-        
-        return True
-
-    def LArTTL1Maker(self):
-        return self._LArTTL1Maker
-   
-
-
diff --git a/LArCalorimeter/LArL1Sim/python/__init__.py b/LArCalorimeter/LArL1Sim/python/__init__.py
deleted file mode 100644
index 2bdd27b889870931ec71250e8d09d1382e1ead9c..0000000000000000000000000000000000000000
--- a/LArCalorimeter/LArL1Sim/python/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-# File: LArL1Sim/python/__init__.py
-__version__ = '1.0.0'
-__author__  = 'Fabienne (ledroit@lpsc.in2p3.fr) '
- 
diff --git a/LArCalorimeter/LArL1Sim/share/LArL1Sim_poolTestRead_jobOptions.py b/LArCalorimeter/LArL1Sim/share/LArL1Sim_poolTestRead_jobOptions.py
deleted file mode 100755
index 4e552ad6ed1bb71ec1bd2dcb3a682528d0e0a106..0000000000000000000000000000000000000000
--- a/LArCalorimeter/LArL1Sim/share/LArL1Sim_poolTestRead_jobOptions.py
+++ /dev/null
@@ -1,80 +0,0 @@
-#*************************************************************************************+
-# +                                                                                   +
-# + Author ........: F. Ledroit                                                       +
-# + Institut ......: LPSC Grenoble                                                    +
-# + Creation date .: 17/12/2004      Version 0.01                                     +
-# + Subject .......: Job Option file to test the reading of pool persistified LArTTL1 +
-#                    The test runs the calib algo and produces the calib ntuple       +
-#=====================================================================================+
-
-
-#setup GeoModel
-DetDescrVersion = "ATLAS-GEO-02-01-00"
-#DetDescrVersion = "ATLAS-GEO-03-00-00"
-
-from AthenaCommon.GlobalFlags import globalflags
-# --- default is atlas geometry
-#globalflags.DetGeo = 'atlas'
-# --- set defaults
-globalflags.DataSource = 'geant4'
-#globalflags.InputFormat = 'pool'
-# --- set geometry version
-globalflags.DetDescrVersion = DetDescrVersion
-# --- printout
-globalflags.print_JobProperties()
-
-#--------------------------------------------------------------
-# Load POOL support
-#--------------------------------------------------------------
-include( "AthenaPoolCnvSvc/ReadAthenaPool_jobOptions.py" )
-
-# for ddcnvsvc
-#include( "LArDetDescr/LArDetDescr_joboptions.py" )
-#include( "LArAthenaPool/LArAthenaPool_joboptions.py" )
-#theApp.Dlls   += [ "LArAthenaPoolPoolCnv" ]
-
-# Define input
-#EventSelector = Service( "EventSelector" )
-#EventSelector.InputCollections  = [ "TTL1PoolFile2.root" ]
-#EventSelector.InputCollections  = [ "/afs/cern.ch/user/d/droussea/scratch0/g50GeV_rel_0_CSC-00-01-00.RDO.pool.root" ]
-#EventSelector.InputCollections  = [ "atlasMis_MyOutputFile.digit.RDO.00002.root" ]
-ServiceMgr.EventSelector.InputCollections = ["rfio:/castor/cern.ch/grid/atlas/atlasmcdisk/valid1/RDO/valid1.007003.singlepart_e_Et25.digit.RDO.e322_s484_tid027349/RDO.027349._00001.pool.root.1"]
-#ServiceMgr.EventSelector.InputCollections  = [ "rfio:/castor/cern.ch/grid/atlas/atlasmcdisk/valid1/RDO/valid1.107204.singlepart_mu4.digit.RDO.e347_s462_d145_tid029243/RDO.029243._00400.pool.root.1" ]
-#ServiceMgr.EventSelector.InputCollections = ["rfio:/castor/cern.ch/grid/atlas/atlasmcdisk/valid1/RDO/valid1.107204.singlepart_mu4.digit.RDO.e347_s462_d144_tid029220/RDO.029220._00001.pool.root.1"]
-#ServiceMgr.EventSelector.InputCollections = ["rfio:/castor/cern.ch/grid/atlas/atlasmcdisk/valid1/RDO/valid1.107204.singlepart_mu4.digit.RDO.e347_s462_d147_tid030079/RDO.030079._00001.pool.root.1"]
-#ServiceMgr.EventSelector.InputCollections = ["rfio:/castor/cern.ch/grid/atlas/atlasmcdisk/valid1/RDO/valid1.107204.singlepart_mu4.digit.RDO.e347_s462_d133_tid027180/RDO.027180._00001.pool.root.1"]
-
-
-
-# ............ declare the used top algo.
-# --------------------------------------------------------
-#load relevant libraries
-theApp.Dlls += [ "LArL1Sim" ]
-theApp.TopAlg += [ "LArTTL1Calib"]
-#--------------------------------------------------------------
-# Private Application Configuration options
-#--------------------------------------------------------------
-# Select the appropriate shared library
-theApp.Dlls += [ "HbookCnv" ]
-# Select HBOOK or ROOT persistency (HBOOK is default)
-theApp.HistogramPersistency = "HBOOK"
-
-#--------------------------------------------------------------
-# Set output level threshold (2=DEBUG, 3=INFO, 4=WARNING, 5=ERROR, 6=FATAL )
-#--------------------------------------------------------------
-MessageSvc = Service( "MessageSvc" )
-MessageSvc.OutputLevel      = 2
-MessageSvc.useColors   = TRUE
-
-#--------------------------------------------------------------
-# Histogram output file 
-#--------------------------------------------------------------
-# Specify the appropriate output file type
-HistogramPersistencySvc = Service( "HistogramPersistencySvc" )
-HistogramPersistencySvc.OutputFile  = "histo.hbook"
-#--------------------------------------------------------------
-# Ntuples
-#--------------------------------------------------------------
-NTupleSvc = Service( "NTupleSvc" )
-NTupleSvc.Output     = [ "FILE1 DATAFILE='tuple1.hbook' OPT='NEW'" ]
-
diff --git a/LArCalorimeter/LArL1Sim/share/LArL1Sim_readRDO_jobOptions.py b/LArCalorimeter/LArL1Sim/share/LArL1Sim_readRDO_jobOptions.py
deleted file mode 100644
index 3db53c55eabef358a4e0daef4c56dca4e2805c4b..0000000000000000000000000000000000000000
--- a/LArCalorimeter/LArL1Sim/share/LArL1Sim_readRDO_jobOptions.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# +==========================================================================================+
-# +                                                                                          +
-# + Author ........: F. Ledroit                                                              +
-# + Institut ......: LPSC Grenoble                                                           +
-# + Creation date .: 06/08/2009      Version 0.01                                            +
-# + Subject .......: Job Option file to read TTL1s in a RDO file by means of the calib algo  +
-# +==========================================================================================+ 
-#import AthenaCommon.AtlasUnixStandardJob
-#import AthenaCommon.AtlasUnixGeneratorJob
-from AthenaCommon.Logging import logging
-from RecExConfig.Configured import Configured
-from AthenaCommon.AlgSequence import AlgSequence
-topSequence = AlgSequence()
-import traceback
-
-from AthenaCommon.GlobalFlags import GlobalFlags
-GlobalFlags.DetGeo.set_atlas()
-GlobalFlags.DataSource.set_geant4()
-
-from AthenaCommon.DetFlags import DetFlags
-# - Select detectors 
-DetFlags.ID_setOff()
-DetFlags.Calo_setOn()
-DetFlags.Muon_setOff()
-DetFlags.Truth_setOff()
-DetFlags.LVL1_setOff()
-DetFlags.digitize.all_setOff()
-
-# following line to be cleaned away as soon as all subsequent jO have migrated
-include( "LArDetDescr/LArDetDescr_joboptions.py" )
-
-#setup GeoModel
-DetDescrVersion="ATLAS-GEO-06-00-00"
-from AthenaCommon.JobProperties import jobproperties
-jobproperties.Global.DetDescrVersion = DetDescrVersion
-from AtlasGeoModel import SetGeometryVersion
-from AtlasGeoModel import GeoModelInit
-
- 
-from AthenaCommon.ConfigurableDb import getConfigurable
-from AthenaCommon.AppMgr import ServiceMgr as svcMgr
-svcMgr += getConfigurable( "ProxyProviderSvc" )()
-svcMgr.ProxyProviderSvc.ProviderNames += [ "CondProxyProvider" ]
-svcMgr += getConfigurable( "CondProxyProvider" )()
-# la ligne suivante est necessaire, sinon le job plante !?!?!?!!!!!
-svcMgr.CondProxyProvider.InputCollections = [ "LArTTCellMap-HadFcalFix.pool.root" ]
-
-
-# Number of events to be processed (default is 10)
-theApp.EvtMax = 10
-
-# Set output level threshold (2=DEBUG, 3=INFO, 4=WARNING, 5=ERROR, 6=FATAL )
-svcMgr.MessageSvc.OutputLevel = 3
-svcMgr.MessageSvc.useColors   = TRUE
-svcMgr.MessageSvc.debugLimit = 100000
-
-
-import AthenaPoolCnvSvc.ReadAthenaPool
-
-#svcMgr.IOVDbSvc.GlobalTag="OFLCOND-CSC-01-00-00"
-svcMgr.EventSelector.InputCollections = ["rfio:/castor/cern.ch/grid/atlas/atlasmcdisk/valid1/RDO/valid1.105144.PythiaZee.digit.RDO.e380_s523_tid046366/RDO.046366._00001.pool.root.1"]
-#PoolRDOInput = ["rfio:/castor/cern.ch/grid/atlas/atlasmcdisk/valid1/RDO/valid1.105144.PythiaZee.digit.RDO.e380_s523_tid046366/RDO.046366._00001.pool.root.1"]
-
-try:        
-    from LArL1Sim.LArL1SimConf import LArTTL1Calib                
-except:
-    mlog.error("could not import LArL1Sim.LArTTL1Calib")
-        
-theLArTTL1Calib=LArTTL1Calib()
-topSequence += theLArTTL1Calib
-
-#theApp.TopAlg += [ "LArTTL1Calib"]
-#LArTTL1Calib = Algorithm( "LArTTL1Calib" )
-#--------------------------------------------------------------
-# Set output level threshold (2=DEBUG, 3=INFO, 4=WARNING, 5=ERROR, 6=FATAL )
-#--------------------------------------------------------------
-#LArTTL1Calib.OutputLevel = 2
-
-
-#--------------------------------------------------------------
-# Select HBOOK or ROOT persistency
-#--------------------------------------------------------------
-theApp.HistogramPersistency = "HBOOK"
-#--------------------------------------------------------------
-# Histogram output file 
-#--------------------------------------------------------------
-# Specify the appropriate output file type
-HistogramPersistencySvc = Service( "HistogramPersistencySvc" )
-HistogramPersistencySvc.OutputFile  = "histoRDO.hbook"
-#HistogramPersistencySvc.OutputFile  = "histo.rt"
-#--------------------------------------------------------------
-# Ntuples
-#--------------------------------------------------------------
-NTupleSvc = Service( "NTupleSvc" )
-NTupleSvc.Output     = [ "FILE1 DATAFILE='tuple1RDO.hbook' OPT='NEW'" ]
-#
-#
-# End of job options file
-#
-###############################################################
diff --git a/LArCalorimeter/LArL1Sim/share/LArSCSimpleMaker_jobOptions.py b/LArCalorimeter/LArL1Sim/share/LArSCSimpleMaker_jobOptions.py
deleted file mode 100644
index 6781d5e7a471a99e9f5aa6ce66a5490df58a8c3a..0000000000000000000000000000000000000000
--- a/LArCalorimeter/LArL1Sim/share/LArSCSimpleMaker_jobOptions.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from LArL1Sim.LArL1SimConf import LArSCSimpleMaker
-topSequence+=LArSCSimpleMaker()
diff --git a/LArCalorimeter/LArL1Sim/share/SimpleSC_From_ESD.py b/LArCalorimeter/LArL1Sim/share/SimpleSC_From_ESD.py
deleted file mode 100755
index c9c6ddee50e36347f5e72a5647e2fb97c0f3db29..0000000000000000000000000000000000000000
--- a/LArCalorimeter/LArL1Sim/share/SimpleSC_From_ESD.py
+++ /dev/null
@@ -1,191 +0,0 @@
-
-EvtMax=10
-doRawData = False
-
-
-from RecExConfig.RecFlags  import rec
-from AthenaCommon.BeamFlags import jobproperties
-from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
-from AthenaCommon.GlobalFlags import globalflags
-from D3PDMakerCoreComps.D3PDObject import D3PDObject
-
-bdir = "/afs/cern.ch/user/h/hma/work/public/data/"
-PoolESDFile =bdir + "ESD.01204497._005853.pool.root.1"
-
-
-athenaCommonFlags.PoolESDInput.set_Value_and_Lock([PoolESDFile])
-rec.readESD.set_Value_and_Lock(True)
-
-tuple_name = "caloD3PD_from_esd.root" 
-
-#
-#from MuonCnvExample.MuonCnvFlags import muonCnvFlags
-#muonCnvFlags.RpcCablingMode="new"
-#
-
-rec.AutoConfiguration=['everything']
-athenaCommonFlags.EvtMax.set_Value_and_Lock(EvtMax)
-
-rec.doHist.set_Value_and_Lock(False)
-rec.doCBNT.set_Value_and_Lock(False)
-rec.doWriteTAGCOM.set_Value_and_Lock(False)
-rec.doWriteTAG.set_Value_and_Lock(False)
-rec.doWriteAOD.set_Value_and_Lock(False)
-rec.doWriteESD.set_Value_and_Lock(False)
-rec.doAOD.set_Value_and_Lock(False)
-rec.doMonitoring.set_Value_and_Lock(False)
-rec.readAOD.set_Value_and_Lock(False)
-
-# RecExCommon
-include ("RecExCommon/RecExCommon_topOptions.py")
-
-# D3PDMaker calo block
-
-from D3PDMakerCoreComps.MakerAlg import *
-from CaloD3PDMaker.ClusterD3PDObject import *
-from CaloD3PDMaker.CaloCellD3PDObject import *
-from CaloD3PDMaker.CaloInfoD3PDObject import *
-from CaloD3PDMaker.LArDigitD3PDObject import *
-from CaloD3PDMaker.TileDigitD3PDObject import *
-from EventCommonD3PDMaker.EventInfoD3PDObject import *
-#from CaloD3PDMaker.TileRawChannelD3PDObject import *
-
-from LArL1Sim.LArL1SimConf import LArSCSimpleMaker
-topSequence+=LArSCSimpleMaker()
-
-print 'CHECK topSequence'
-print topSequence
-
-include( "LArDetDescr/LArDetDescr_joboptions.py" )
-include( "CaloConditions/CaloConditions_jobOptions.py" )
-
-alg = MakerAlg("caloD3PD", topSequence, file = tuple_name , D3PDSvc = 'D3PD::RootD3PDSvc')
-alg += EventInfoD3PDObject (10)
-
-alg += AllCaloCellD3PDObject (10)
-#alg += SelCaloCellD3PDObject (10)
-# alg += EMCellD3PDObject (10)
-# alg += HECCellD3PDObject (10)
-# alg += FCALCellD3PDObject (10)
-# alg += TileCellD3PDObject (10)
-
-#alg += CaloInfoD3PDObject (10)
-
-#alg += ClusterD3PDObject (10)
-
-#alg += LArDigitD3PDObject (2)
-
-alg += AllCaloCellD3PDObject (1,sgkey='SCellContainer',prefix='scells_')
-alg.scells_Filler.scells_Filler_Detail1.SaveId=True 
-
-import CaloD3PDMaker
-from D3PDMakerCoreComps.D3PDObject import make_SGDataVector_D3PDObject
-
-if doRawData : 
-
-  LArDigitD3PDObject = make_SGDataVector_D3PDObject( "LArDigitContainer",
-                                                   "LArDigitContainer_MC",
-                                                   "lardigit_", "LArDigitD3PDObject" )
-
-  LArDigitD3PDObject.defineBlock( 0, 'Digits',
-                                CaloD3PDMaker.LArDigitFillerTool,
-                                SaveDigit= True,
-                                SaveId = True,
-                                SaveSCAAddress= False,
-                                DumpIterResults= False )
-  alg+=LArDigitD3PDObject(0)
-
-  
-  TileDigitD3PDObject = D3PDObject (makeTileDigitD3PDObject, 'tiledigit_', 'TileDigitD3PDObject')
-
-  TileDigitD3PDObject.defineBlock (0, 'Digits',
-                                CaloD3PDMaker.TileDigitFillerTool,
-                                SaveOfflineInfo= True,
-                                SaveHardwareInfo=True,
-                                )
-  alg+=TileDigitD3PDObject(0)
-
-
-  import CaloD3PDMaker
-  import D3PDMakerCoreComps
-  from D3PDMakerCoreComps.D3PDObject import D3PDObject
-  
-  TileRawChannelSGKey='TileRawChannelCnt'
-
-  def makeTileRawChannelD3PDObject (name, prefix, object_name='TileRawChannelD3PDObject', getter = None,
-                           sgkey = None,
-                           label = None):
-    if sgkey == None: sgkey = TileRawChannelSGKey
-    if label == None: label = prefix
-
-    if not getter:
-        getter = CaloD3PDMaker.SGTileRawChannelGetterTool \
-                 (name + '_Getter',
-                  TypeName = 'TileRawChannelContainer',
-                  SGKey = sgkey,
-                  Label = label)
-
-    # create the selected cells
-    from D3PDMakerConfig.D3PDMakerFlags import D3PDMakerFlags
-    return D3PDMakerCoreComps.VectorFillerTool (name,
-                                                Prefix = prefix,
-                                                Getter = getter,
-                                                ObjectName = object_name,
-                                                SaveMetadata = \
-                                                D3PDMakerFlags.SaveObjectMetadata())
-
-  TileRawChannelD3PDObject = D3PDObject( makeTileRawChannelD3PDObject, 'tileraw_',
-                                       'TileRawChannelD3PDObject' )
-
-  TileRawChannelD3PDObject.defineBlock (0, 'RawChannel',
-                                CaloD3PDMaker.TileRawChannelFillerTool,
-                                SaveHardwareInfo=True,
-                                SaveRawChannel= True,
-                                )
-
-
-  TileRawChannelD3PDObject.defineBlock (1, 'Hardware',
-                                CaloD3PDMaker.TileRawChannelFillerTool,
-                                SaveHardwareInfo=True,
-                                SaveRawChannel= False,
-                                )
-
-  alg+=TileRawChannelD3PDObject(0)
-
-
-
-#from CaloD3PDMaker.LArRawChannelD3PDObject import *
-#alg+=LArRawChannelD3PDObject(0)
-
-from TrigCaloD3PDMaker.TrigCaloD3PDMakerConf \
-     import D3PD__TriggerTowerFillerTool, D3PD__TriggerTowerFillerTool
-
-TriggerTowerCollection_sgkey = 'TriggerTowers'
-TriggerTowerD3PDObject = make_SGDataVector_D3PDObject(
-                                    'DataVector<LVL1::TriggerTower>',
-                                    TriggerTowerCollection_sgkey,
-                                    'tt_',
-                                    'TriggerTowerD3PDObject')
-
-# Level 0
-TriggerTowerD3PDObject.defineBlock(0, 'Basics',
-                                    D3PD__TriggerTowerFillerTool)
-alg+=TriggerTowerD3PDObject(0)
-
-
-
-import CaloD3PDMaker
-import D3PDMakerCoreComps
-from D3PDMakerCoreComps.D3PDObject import D3PDObject
-
-
-
-#if readRaw :
-#  # put OF iteration results on SG 
-#  ToolSvc.LArRawChannelBuilderToolOFCIter.StoreTiming=True
-
-print 'CHECK : svcMgr.DetDescrCnvSvc : '
-print svcMgr.DetDescrCnvSvc
-#svcMgr.StoreGateSvc.Dump=True
-svcMgr.MessageSvc.OutputLevel = INFO
-
diff --git a/LArCalorimeter/LArMonitoring/python/LArSuperCellMonAlg.py b/LArCalorimeter/LArMonitoring/python/LArSuperCellMonAlg.py
index 5d821c6a47aa7846e8a78a2533df87510ef61161..550e10ebb31de4658e635cacff5de1c76856a939 100644
--- a/LArCalorimeter/LArMonitoring/python/LArSuperCellMonAlg.py
+++ b/LArCalorimeter/LArMonitoring/python/LArSuperCellMonAlg.py
@@ -45,7 +45,7 @@ def LArSuperCellMonConfig(flags, **kwargs):
     cfg.merge(emulateSC_Cfg(flags))
 
     from LArCellRec.LArRAWtoSuperCellConfig import LArRAWtoSuperCellCfg
-    cfg.merge(LArRAWtoSuperCellCfg(flags,mask=mask) )
+    cfg.merge(LArRAWtoSuperCellCfg(flags,SCellContainerOut="EmulatedSuperCells",mask=mask) )
 
     # Reco SC:
     #get SC onl-offl mapping from DB    
@@ -83,7 +83,7 @@ def LArSuperCellMonConfig(flags, **kwargs):
     
     #return cfg
     algname='LArSuperCellMonAlg'
-    lArCellMonAlg=CompFactory.LArSuperCellMonAlg(algname,CaloCellContainerReco="SCell_ET_RECO",doSCReco=True)
+    lArCellMonAlg=CompFactory.LArSuperCellMonAlg(algname,CaloCellContainerReco="SCell_ET_RECO",CaloCellContainerRef=flags.Trigger.L1.L1CaloSuperCellContainerName,doSCReco=True,CaloCellContainer='EmulatedSuperCells')
 
 
     if flags.Input.isMC is False and not flags.Common.isOnline:
@@ -116,7 +116,7 @@ def LArSuperCellMonConfigCore(helper, algclass, flags, isCosmics=False, isMC=Fal
     LArSuperCellMonAlg.MonGroupName = GroupName
 
     LArSuperCellMonAlg.EnableLumi = False
-    LArSuperCellMonAlg.CaloCellContainer = flags.LAr.DT.ET_IDKey
+    LArSuperCellMonAlg.CaloCellContainer = 'EmulatedSuperCells'
     LArSuperCellMonAlg.CaloCellContainerRef = flags.Trigger.L1.L1CaloSuperCellContainerName
     LArSuperCellMonAlg.RemoveMasked = RemoveMasked
     
@@ -330,6 +330,7 @@ if __name__=='__main__':
     from AthenaCommon.Constants import DEBUG
     from AthenaCommon.Constants import WARNING
     from AthenaConfiguration.Enums import LHCPeriod, BunchStructureSource
+    from AthenaConfiguration.TestDefaults import defaultGeometryTags
     from AthenaCommon.Logging import log
     log.setLevel(DEBUG)
 
@@ -342,7 +343,8 @@ if __name__=='__main__':
     #flags.Input.Files = ['/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/OverlayTests/data15_13TeV.00278748.physics_ZeroBias.merge.RAW._lb0384._SFO-ALL._0001.1']
     #flags.Input.Files = ['../data22_13p6TeV/data22_13p6TeV.00432180.physics_Main.daq.RAW._lb0335._SFO-16._0001.data']
     #flags.Input.Files = ['/eos/atlas/atlastier0/daq/data22_13p6TeV/express_express/00432180/data22_13p6TeV.00432180.express_express.daq.RAW/data22_13p6TeV.00432180.express_express.daq.RAW._lb0374._SFO-12._0001.data']
-    flags.Input.Files = ['/eos/atlas/atlastier0/daq/data22_13p6TeV/express_express/00439798/data22_13p6TeV.00439798.express_express.daq.RAW/data22_13p6TeV.00439798.express_express.daq.RAW._lb1085._SFO-16._0001.data']
+    #flags.Input.Files = ['/eos/atlas/atlastier0/daq/data22_13p6TeV/express_express/00439798/data22_13p6TeV.00439798.express_express.daq.RAW/data22_13p6TeV.00439798.express_express.daq.RAW._lb1085._SFO-16._0001.data']
+    flags.Input.Files = ['/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/TrigP1Test/data22_13p6TeV.00440499.physics_EnhancedBias.merge.RAW._lb0470._SFO-11._0001.1']
 
     #flags.Calo.Cell.doPileupOffsetBCIDCorr=True
     flags.Output.HISTFileName = 'LArSuperCellMonOutput.root'
@@ -356,6 +358,7 @@ if __name__=='__main__':
     flags.Exec.OutputLevel=WARNING
     flags.Beam.BunchStructureSource=BunchStructureSource.FILLPARAMS
     #flags.Beam.BunchStructureSource=BunchStructureSource.Lumi
+    flags.GeoModel.AtlasVersion = defaultGeometryTags.RUN3
     import sys
     flags.fillFromArgs(sys.argv[1:])
     flags.lock()
@@ -363,8 +366,8 @@ if __name__=='__main__':
     # Initialize configuration object, add accumulator, merge, and run.
     from AthenaConfiguration.MainServicesConfig import MainServicesCfg 
     cfg = MainServicesCfg(flags)
-    storeGateSvc = cfg.getService("StoreGateSvc")
-    storeGateSvc.Dump=True
+    #storeGateSvc = cfg.getService("StoreGateSvc")
+    #storeGateSvc.Dump=True
 
     # in case of tier0 workflow:
     #from CaloRec.CaloRecoConfig import CaloRecoCfg
diff --git a/MuonSpectrometer/MuonConfig/python/MuonCablingConfig.py b/MuonSpectrometer/MuonConfig/python/MuonCablingConfig.py
index df20bd423e8bd69d30fe6260fc8b4640ae32aeb1..20e0d3f7ad897dbe65e84e0abf40003ff5dab39b 100644
--- a/MuonSpectrometer/MuonConfig/python/MuonCablingConfig.py
+++ b/MuonSpectrometer/MuonConfig/python/MuonCablingConfig.py
@@ -41,11 +41,6 @@ def RPCCablingConfigCfg(flags):
         # Relevant folder tags are set for now, until new global tag (RUN3-02) becomes avaialble
         rpcTrigEta="/RPC/TRIGGER/CM_THR_ETA <tag>RPCTriggerCMThrEta_RUN12_MC16_04</tag> <forceRunNumber>330000</forceRunNumber>"
         rpcTrigPhi="/RPC/TRIGGER/CM_THR_PHI <tag>RPCTriggerCMThrPhi_RUN12_MC16_04</tag> <forceRunNumber>330000</forceRunNumber>"
-        from AthenaConfiguration.Enums  import LHCPeriod
-        if flags.Input.isMC and flags.GeoModel.Run >= LHCPeriod.Run3:        # from Run3 on geometry
-           rpcCabMap="/RPC/CABLING/MAP_SCHEMA <tag>RPCCablingMapSchema_2015-2018Run3-4</tag> <forceRunNumber>330000</forceRunNumber>"
-           rpcCabMapCorr="/RPC/CABLING/MAP_SCHEMA_CORR <tag>RPCCablingMapSchemaCorr_2015-2018Run3-4</tag> <forceRunNumber>330000</forceRunNumber>"
-
 
     from IOVDbSvc.IOVDbSvcConfig import addFolders
     acc.merge(addFolders(flags, [rpcCabMap,rpcCabMapCorr], dbName, className='CondAttrListCollection' ))
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/CMakeLists.txt b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/CMakeLists.txt
index 7b6d7ad657580970b0ed29058d927af7dac88324..d0120494585b5c1092a57e33e6c09330872cf001 100644
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/CMakeLists.txt
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/CMakeLists.txt
@@ -32,7 +32,6 @@ set(FTDSource
   Root/GNN.cxx
   Root/GNNTool.cxx
   Root/GNNToolifiers.cxx
-  Root/customGetter.cxx
   Root/FlipTagEnums.cxx
   Root/AssociationEnums.cxx
   Root/VRJetOverlapDecorator.cxx
@@ -44,6 +43,10 @@ set(FTDSource
   Root/VRJetOverlapDecorator.cxx
   Root/FTagDataDependencyNames.cxx
   Root/TrackClassifier.cxx
+  Root/ConstituentsLoader.cxx
+  Root/TracksLoader.cxx
+  Root/IParticlesLoader.cxx
+  Root/CustomGetterUtils.cxx
   Root/StringUtils.cxx
 )
 if (NOT XAOD_STANDALONE)
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/ConstituentsLoader.h b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/ConstituentsLoader.h
new file mode 100644
index 0000000000000000000000000000000000000000..a493129eb6e3cea5c9ee129c76f51513ced9665d
--- /dev/null
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/ConstituentsLoader.h
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+
+  This is a virtual class to represent loader of any type of constituents.
+  It defines the interface for loading constituents from a jet 
+  and extracting their features for the NN evaluation.
+*/
+
+#ifndef CONTITUENTS_LOADER_H
+#define CONTITUENTS_LOADER_H
+
+// local includes
+#include "FlavorTagDiscriminants/FlipTagEnums.h"
+#include "FlavorTagDiscriminants/AssociationEnums.h"
+#include "FlavorTagDiscriminants/OnnxUtil.h"
+#include "FlavorTagDiscriminants/FTagDataDependencyNames.h"
+#include "FlavorTagDiscriminants/StringUtils.h"
+
+// EDM includes
+#include "xAODJet/Jet.h"
+#include "xAODBTagging/BTagging.h"
+
+// STL includes
+#include <string>
+#include <vector>
+
+namespace FlavorTagDiscriminants {
+
+    enum class ConstituentsEDMType {CHAR, UCHAR, INT, FLOAT, DOUBLE, CUSTOM_GETTER};
+    enum class ConstituentsSortOrder {
+        ABS_D0_SIGNIFICANCE_DESCENDING,
+        D0_SIGNIFICANCE_DESCENDING,
+        PT_DESCENDING,
+        ABS_D0_DESCENDING
+    };
+    enum class ConstituentsSelection {
+        ALL,
+        IP3D_2018,
+        DIPS_TIGHT_UPGRADE,
+        DIPS_LOOSE_UPGRADE,
+        DIPS_LOOSE_202102,
+        LOOSE_202102_NOIP,
+        R22_DEFAULT,
+        R22_LOOSE
+    };
+    enum class ConstituentsType {
+        IPARTICLE,
+        TRACK
+    };
+
+    struct InputVariableConfig {
+        std::string name;
+        ConstituentsEDMType type;
+        bool flip_sign;
+    };
+
+    struct ConstituentsInputConfig {
+        std::string name;
+        std::string output_name;
+        ConstituentsType type;
+        ConstituentsSortOrder order;
+        ConstituentsSelection selection;
+        std::vector<InputVariableConfig> inputs;
+    };
+
+    ConstituentsInputConfig createConstituentsLoaderConfig(
+      std::string name,
+      std::vector<std::string> input_variables,
+      FlipTagConfig flip_config
+    );
+
+    // Virtual class to represent loader of any type of constituents
+    class IConstituentsLoader {
+        public:
+            IConstituentsLoader(ConstituentsInputConfig cfg) {
+              m_config = cfg;
+            };
+            virtual ~IConstituentsLoader() = default;
+            virtual std::tuple<std::string, input_pair, std::vector<const xAOD::IParticle*>> getData(
+                const xAOD::Jet& jet, 
+                [[maybe_unused]] const SG::AuxElement& btag) const = 0;
+            virtual FTagDataDependencyNames getDependencies() const = 0;
+            virtual std::set<std::string> getUsedRemap() const = 0;
+            virtual std::string getName() const = 0;
+            virtual ConstituentsType getType() const = 0;
+
+        protected:
+            FTagDataDependencyNames m_deps;
+            ConstituentsInputConfig m_config;
+            std::set<std::string> m_used_remap;
+            std::string m_name;
+    };
+}
+
+
+#endif
\ No newline at end of file
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/CustomGetterUtils.h b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/CustomGetterUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..33d3c4c8fbb2bb5ec33a0faaf0f6a4cff6cab33e
--- /dev/null
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/CustomGetterUtils.h
@@ -0,0 +1,109 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+// The CustomGetterUtils file is a catch-all for various getter functinos
+// that need to be hard coded for whatever reason. Some of these are
+// accessing methods like `pt` which have no name in the EDM, others
+// can't be stored in the edm directly for various reasons.
+
+
+// EDM includes
+#include "xAODJet/JetFwd.h"
+#include "xAODTracking/TrackParticleFwd.h"
+#include "xAODBase/IParticle.h"
+#include "AthContainers/AuxElement.h"
+#include "FlavorTagDiscriminants/DataPrepUtilities.h"
+
+
+#include <functional>
+#include <string>
+#include <set>
+
+#ifndef CUSTOM_GETTER_UTILS_H
+#define CUSTOM_GETTER_UTILS_H
+
+namespace FlavorTagDiscriminants {
+
+  /// Utils to produce Constituent -> vector<double> functions
+  ///
+  /// DL2 configures the its inputs when the algorithm is initalized,
+  /// meaning that the list of track and jet properties that are used
+  /// as inputs won't be known at compile time. Instead we build an
+  /// array of "getter" functions, each of which returns one input for
+  /// the tagger. The function here returns those getter functions.
+  ///
+  /// Many of the getter functions are trivial: they will, for example,
+  /// read one double of auxdata off of the BTagging object. The
+  /// sequence input getters tend to be more complicated. Since we'd
+  /// like to avoid reimplementing the logic in these functions in
+  /// multiple places, they are exposed here.
+  ///
+  /// NOTE: This file is for experts only, don't expect support.
+  ///
+
+  namespace getter_utils {
+
+    using IParticles = std::vector<const xAOD::IParticle*>;
+    using Tracks = std::vector<const xAOD::TrackParticle*>;
+
+    using SequenceFromIParticles = std::function<std::vector<double>(
+            const xAOD::Jet&,
+            const IParticles&)>;
+    using SequenceFromTracks = std::function<std::vector<double>(
+            const xAOD::Jet&,
+            const Tracks&)>;
+    
+
+    std::function<std::pair<std::string, double>(const xAOD::Jet&)>
+    customGetterAndName(const std::string&);
+
+    template <typename T>
+    std::pair<
+    std::function<std::vector<double>(
+      const xAOD::Jet&,
+      const std::vector<const T*>&)>,
+    std::set<std::string>>
+    customSequenceGetterWithDeps(const std::string& name,
+                                const std::string& prefix);
+
+    /**
+     * @brief Template class to extract features from sequence of constituents
+     * 
+     * @tparam T constituent type
+     * 
+     * It supports the following types of constituents:
+     * - xAOD::IParticle
+     * - xAOD::TrackParticle
+    */
+    template <typename T>
+    class CustomSequenceGetter {
+        public:
+          using Constituents = std::vector<const T*>;
+          using NamedSequenceFromConstituents = std::function<std::pair<std::string, std::vector<double>>(
+              const xAOD::Jet&,
+              const Constituents&)>;
+          CustomSequenceGetter(std::vector<InputVariableConfig> inputs,
+                              const FTagOptions& options);
+
+          std::pair<std::vector<float>, std::vector<int64_t>> getFeats(const xAOD::Jet& jet, const Constituents& constituents) const;
+          std::map<std::string, std::vector<double>> getDL2Feats(const xAOD::Jet& jet, const Constituents& constituents) const;
+
+          std::set<std::string> getDependencies() const;
+          std::set<std::string> getUsedRemap() const;
+          
+        private:
+          std::pair<NamedSequenceFromConstituents, std::set<std::string>> customNamedSeqGetterWithDeps(
+            const std::string& name,
+            const std::string& prefix);
+          std::pair<NamedSequenceFromConstituents, std::set<std::string>> seqFromConsituents(
+            const InputVariableConfig& cfg, 
+            const FTagOptions& options);
+          std::vector<NamedSequenceFromConstituents> m_sequencesFromConstituents;
+          std::set<std::string> m_deps;
+          std::set<std::string> m_used_remap;        
+        };
+    }
+}
+
+#endif
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/DL2.h b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/DL2.h
index 66f2384425f954138a4aec78dfb3adc8044a60e3..daa171939f0c82f101d0b9581cbbccc3b3d08fd0 100644
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/DL2.h
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/DL2.h
@@ -7,6 +7,7 @@
 
 // local includes
 #include "FlavorTagDiscriminants/DataPrepUtilities.h"
+#include "FlavorTagDiscriminants/TracksLoader.h"
 
 // forward declarations
 namespace lwt {
@@ -20,7 +21,7 @@ namespace FlavorTagDiscriminants {
   public:
     DL2(const lwt::GraphConfig&,
         const std::vector<FTagInputConfig>&,
-        const std::vector<FTagTrackSequenceConfig>& = {},
+        const std::vector<ConstituentsInputConfig>& = {},
         const FTagOptions& = FTagOptions());
     void decorate(const xAOD::BTagging& btag) const;
     void decorate(const xAOD::Jet& jet) const;
@@ -37,7 +38,7 @@ namespace FlavorTagDiscriminants {
     std::unique_ptr<lwt::NanReplacer> m_variable_cleaner;
     std::vector<internal::VarFromBTag> m_varsFromBTag;
     std::vector<internal::VarFromJet> m_varsFromJet;
-    std::vector<internal::TrackSequenceBuilder> m_trackSequenceBuilders;
+    std::vector<std::shared_ptr<TracksLoader>> m_tracksLoaders;
     std::map<std::string, internal::OutNodeFloat> m_decorators;
     float m_defaultValue;
     std::function<char(const internal::Tracks&)> m_invalid_track_checker;
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/DataPrepUtilities.h b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/DataPrepUtilities.h
index c9844de3a7d8870f22232a971aa9e3d0ba24002b..d180c313589f7f4c421fd118b668c04568b7ae42 100644
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/DataPrepUtilities.h
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/DataPrepUtilities.h
@@ -10,6 +10,7 @@
 #include "FlavorTagDiscriminants/AssociationEnums.h"
 #include "FlavorTagDiscriminants/FTagDataDependencyNames.h"
 #include "FlavorTagDiscriminants/OnnxUtil.h"
+#include "FlavorTagDiscriminants/ConstituentsLoader.h"
 
 // EDM includes
 #include "xAODJet/Jet.h"
@@ -30,23 +31,6 @@
 namespace FlavorTagDiscriminants {
 
   enum class EDMType {CHAR, UCHAR, INT, FLOAT, DOUBLE, CUSTOM_GETTER};
-  enum class SortOrder {
-    ABS_D0_SIGNIFICANCE_DESCENDING,
-    D0_SIGNIFICANCE_DESCENDING,
-    PT_DESCENDING,
-    ABS_D0_DESCENDING
-  };
-  enum class TrackSelection {
-    ALL,
-    IP3D_2018,
-    DIPS_TIGHT_UPGRADE,
-    DIPS_LOOSE_UPGRADE,
-    DIPS_LOOSE_202102,
-    LOOSE_202102_NOIP,
-    R22_DEFAULT,
-    R22_LOOSE
-  };
-
 
   // Structures to define DL2/GNNTool input.
   //
@@ -56,19 +40,6 @@ namespace FlavorTagDiscriminants {
     EDMType type;
     std::string default_flag;
   };
-  struct FTagTrackInputConfig
-  {
-    std::string name;
-    EDMType type;
-    bool flip_sign;
-  };
-  struct FTagTrackSequenceConfig
-  {
-    std::string name;
-    SortOrder order;
-    TrackSelection selection;
-    std::vector<FTagTrackInputConfig> inputs;
-  };
 
   // other DL2/GNNTool options
   struct FTagOptions {
@@ -89,20 +60,13 @@ namespace FlavorTagDiscriminants {
   namespace internal {
     // typedefs
     typedef std::pair<std::string, double> NamedVar;
-    typedef std::pair<std::string, std::vector<double> > NamedSeq;
     typedef xAOD::Jet Jet;
     typedef xAOD::BTagging BTagging;
     typedef std::vector<const xAOD::TrackParticle*> Tracks;
-    typedef std::function<double(const xAOD::TrackParticle*,
-                                 const xAOD::Jet&)> TrackSortVar;
-    typedef std::function<bool(const xAOD::TrackParticle*)> TrackFilter;
-    typedef std::function<Tracks(const Tracks&,
-                                 const xAOD::Jet&)> TrackSequenceFilter;
 
     // getter functions
     typedef std::function<NamedVar(const SG::AuxElement&)> VarFromBTag;
     typedef std::function<NamedVar(const Jet&)> VarFromJet;
-    typedef std::function<NamedSeq(const Jet&, const Tracks&)> SeqFromTracks;
 
     // ___________________________________________________________________
     // Getter functions
@@ -164,49 +128,6 @@ namespace FlavorTagDiscriminants {
         }
     };
 
-    // The track getter is responsible for getting the tracks from the
-    // jet applying a selection, and then sorting the tracks.
-    class TracksFromJet{
-      public:
-        TracksFromJet(SortOrder, TrackSelection, const FTagOptions&);
-        Tracks operator()(const xAOD::Jet& jet,
-                          const SG::AuxElement& btag) const;
-      private:
-        using AE = SG::AuxElement;
-        using IPC = xAOD::IParticleContainer;
-        using TPC = xAOD::TrackParticleContainer;
-        using TrackLinks = std::vector<ElementLink<TPC>>;
-        using PartLinks = std::vector<ElementLink<IPC>>;
-        using TPV = std::vector<const xAOD::TrackParticle*>;
-        std::function<TPV(const SG::AuxElement&)> m_associator;
-
-        TrackSortVar m_trackSortVar;
-        TrackFilter m_trackFilter;
-    };
-
-    // The sequence getter takes in tracks and calculates arrays of
-    // values which are better suited for inputs to the NNs
-    template <typename T>
-    class SequenceGetter{
-      private:
-        SG::AuxElement::ConstAccessor<T> m_getter;
-        std::string m_name;
-      public:
-        SequenceGetter(const std::string& name):
-          m_getter(name),
-          m_name(name)
-          {
-          }
-        NamedSeq operator()(const xAOD::Jet&, const Tracks& trks) const {
-          std::vector<double> seq;
-          for (const xAOD::TrackParticle* track: trks) {
-            seq.push_back(m_getter(*track));
-          }
-          return {m_name, seq};
-        }
-    };
-
-
     // Filler functions
     //
     // factory functions to produce callable objects that build inputs
@@ -214,28 +135,10 @@ namespace FlavorTagDiscriminants {
       VarFromBTag varFromBTag(const std::string& name,
                               EDMType,
                               const std::string& defaultflag);
-      TrackSortVar trackSortVar(SortOrder, const FTagOptions&);
-      std::pair<TrackFilter,std::set<std::string>> trackFilter(
-        TrackSelection, const FTagOptions&);
-      std::pair<SeqFromTracks,std::set<std::string>> seqFromTracks(
-        const FTagTrackInputConfig&, const FTagOptions&);
-      std::pair<TrackSequenceFilter,std::set<std::string>> flipFilter(
-        const FTagOptions&);
     }
 
-
     typedef SG::AuxElement::Decorator<float> OutputSetterFloat;
-    typedef std::vector<std::pair<std::string, OutputSetterFloat > > OutNodeFloat;
-
-    struct TrackSequenceBuilder {
-      TrackSequenceBuilder(SortOrder,
-                           TrackSelection,
-                           const FTagOptions&);
-      std::string name;
-      internal::TracksFromJet tracksFromJet;
-      internal::TrackSequenceFilter flipFilter;
-      std::vector<internal::SeqFromTracks> sequencesFromTracks;
-    };
+    typedef std::vector<std::pair<std::string, OutputSetterFloat>> OutNodeFloat;
 
   }
 
@@ -249,7 +152,7 @@ namespace FlavorTagDiscriminants {
     // structure.
     std::tuple<
       std::vector<FTagInputConfig>,
-      std::vector<FTagTrackSequenceConfig>,
+      std::vector<ConstituentsInputConfig>,
       FTagOptions>
     createGetterConfig( lwt::GraphConfig& graph_config,
       FlipTagConfig flip_config,
@@ -264,15 +167,6 @@ namespace FlavorTagDiscriminants {
     createBvarGetters(
       const std::vector<FTagInputConfig>& inputs);
 
-    // return the track getter functions for the NNs
-    std::tuple<
-      std::vector<internal::TrackSequenceBuilder>,
-      FTagDataDependencyNames,
-      std::set<std::string>>
-    createTrackGetters(
-      const std::vector<FTagTrackSequenceConfig>& track_sequences,
-      const FTagOptions& options);
-
     // return the decorators for the NNs
     std::tuple<
       std::map<std::string, internal::OutNodeFloat>,
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/GNN.h b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/GNN.h
index 6a25bca60ca293c8777b0bc3b0d846280a9eea70..9851255067d1f2c903d679b12cf0cb348956d923 100644
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/GNN.h
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/GNN.h
@@ -18,6 +18,8 @@
 #include "FlavorTagDiscriminants/GNNOptions.h"
 
 #include "FlavorTagDiscriminants/DataPrepUtilities.h"
+#include "FlavorTagDiscriminants/TracksLoader.h"
+#include "FlavorTagDiscriminants/IParticlesLoader.h"
 
 // EDM includes
 #include "xAODBTagging/BTaggingFwd.h"
@@ -58,7 +60,6 @@ namespace FlavorTagDiscriminants {
     virtual std::set<std::string> getConstituentAuxInputKeys() const;
 
     std::shared_ptr<const OnnxUtil> m_onnxUtil;
-
   private:
     // type definitions for ONNX output decorators
     using TPC = xAOD::TrackParticleContainer;
@@ -87,7 +88,7 @@ namespace FlavorTagDiscriminants {
     std::string m_input_node_name;
     std::vector<internal::VarFromBTag> m_varsFromBTag;
     std::vector<internal::VarFromJet> m_varsFromJet;
-    std::vector<internal::TrackSequenceBuilder> m_trackSequenceBuilders;
+    std::vector<std::shared_ptr<IConstituentsLoader>> m_constituentsLoaders;
 
     Decorators m_decorators;
     float m_defaultValue;
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/IParticlesLoader.h b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/IParticlesLoader.h
new file mode 100644
index 0000000000000000000000000000000000000000..b0abdc0f4ad60ea419c7e27734b38cc6bd23fcdd
--- /dev/null
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/IParticlesLoader.h
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+
+  This is a subclass of IConstituentsLoader. It is used to load the general IParticles from the jet 
+  and extract their features for the NN evaluation. For now it supports only neutral flow objects.
+  Charged flow objects have experimental support and are not recommended for use.
+*/
+
+#ifndef IPARTICLES_LOADER_H
+#define IPARTICLES_LOADER_H
+
+// local includes
+#include "FlavorTagDiscriminants/ConstituentsLoader.h"
+#include "FlavorTagDiscriminants/CustomGetterUtils.h"
+
+// EDM includes
+#include "xAODJet/JetFwd.h"
+#include "xAODBase/IParticle.h"
+
+// STL includes
+#include <string>
+#include <vector>
+#include <functional>
+#include <exception>
+#include <type_traits>
+#include <regex>
+
+namespace FlavorTagDiscriminants {
+
+    ConstituentsInputConfig createIParticlesLoaderConfig(
+      std::pair<std::string, std::vector<std::string>> iparticle_names
+    );
+    // Subclass for IParticles loader inherited from abstract IConstituentsLoader class
+    class IParticlesLoader : public IConstituentsLoader {
+      public:
+        IParticlesLoader(ConstituentsInputConfig, const FTagOptions& options);
+        std::tuple<std::string, input_pair, std::vector<const xAOD::IParticle*>> getData(
+          const xAOD::Jet& jet, 
+          [[maybe_unused]] const SG::AuxElement& btag) const override ;
+        FTagDataDependencyNames getDependencies() const override;
+        std::set<std::string> getUsedRemap() const override;
+        std::string getName() const override;
+        ConstituentsType getType() const override;
+      protected:
+        // typedefs
+        typedef xAOD::Jet Jet;
+        typedef std::pair<std::string, double> NamedVar;
+        typedef std::pair<std::string, std::vector<double> > NamedSeq;
+        // iparticle typedefs
+        typedef std::vector<const xAOD::IParticle*> IParticles;
+        typedef std::function<double(const xAOD::IParticle*,
+                                    const Jet&)> IParticleSortVar;
+
+        // getter function
+        typedef std::function<NamedSeq(const Jet&, const IParticles&)> SeqFromIParticles;
+
+        // usings for IParticle getter
+        using AE = SG::AuxElement;
+        using IPC = xAOD::IParticleContainer;
+        using PartLinks = std::vector<ElementLink<IPC>>;
+        using IPV = std::vector<const xAOD::IParticle*>;
+
+        IParticleSortVar iparticleSortVar(ConstituentsSortOrder);
+        
+        std::vector<const xAOD::IParticle*> getIParticlesFromJet(const xAOD::Jet& jet) const;
+
+        IParticleSortVar m_iparticleSortVar;
+        getter_utils::CustomSequenceGetter<xAOD::IParticle> m_customSequenceGetter;        
+        std::function<IPV(const Jet&)> m_associator;
+        bool m_isCharged;
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/TracksLoader.h b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/TracksLoader.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc222952889f28c659b30808e0c3442397366d2d
--- /dev/null
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/TracksLoader.h
@@ -0,0 +1,96 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+
+  This is a subclass of IConstituentsLoader. It is used to load the tracks from the jet 
+  and extract their features for the NN evaluation.
+*/
+
+#ifndef TRACKS_LOADER_H
+#define TRACKS_LOADER_H
+
+// local includes
+#include "FlavorTagDiscriminants/FlipTagEnums.h"
+#include "FlavorTagDiscriminants/AssociationEnums.h"
+
+#include "FlavorTagDiscriminants/ConstituentsLoader.h"
+#include "FlavorTagDiscriminants/DataPrepUtilities.h"
+#include "FlavorTagDiscriminants/BTagTrackIpAccessor.h"
+#include "FlavorTagDiscriminants/CustomGetterUtils.h"
+
+// EDM includes
+#include "xAODJet/Jet.h"
+#include "xAODBTagging/BTagging.h"
+
+// external libraries
+#include "lwtnn/lightweight_network_config.hh"
+
+// STL includes
+#include <string>
+#include <vector>
+#include <functional>
+#include <exception>
+#include <type_traits>
+#include <regex>
+
+namespace FlavorTagDiscriminants {
+
+    // tracksConfig 
+    ConstituentsInputConfig createTracksLoaderConfig(
+      std::pair<std::string, std::vector<std::string>> trk_names,
+      FlipTagConfig flip_config
+    );
+
+
+    // Subclass for Tracks loader inherited from abstract IConstituentsLoader class
+    class TracksLoader : public IConstituentsLoader {
+      public:
+        typedef std::vector<const xAOD::TrackParticle*> Tracks;
+
+        TracksLoader(ConstituentsInputConfig, const FTagOptions& options);
+        std::tuple<std::string, input_pair, std::vector<const xAOD::IParticle*>> getData(
+          const xAOD::Jet& jet, 
+          [[maybe_unused]] const SG::AuxElement& btag) const override;
+        std::tuple<char, std::map<std::string, std::vector<double>>>  getDL2Data(
+          const xAOD::Jet& jet, 
+          const SG::AuxElement& btag, 
+          std::function<char(const Tracks&)> ip_checker) const;
+        FTagDataDependencyNames getDependencies() const override;
+        std::set<std::string> getUsedRemap() const override;
+        std::string getName() const override;
+        ConstituentsType getType() const override;
+      private:
+        // typedefs
+        typedef xAOD::Jet Jet;
+        typedef xAOD::TrackParticle Track;
+        // tracks typedefs
+        typedef std::function<double(const Track*,
+                                    const Jet&)> TrackSortVar;
+        typedef std::function<bool(const Track*)> TrackFilter;
+        typedef std::function<Tracks(const Tracks&,
+                                    const Jet&)> TrackSequenceFilter;
+
+        // usings for track getter
+        using AE = SG::AuxElement;
+        using IPC = xAOD::IParticleContainer;
+        using TPC = xAOD::TrackParticleContainer;
+        using TrackLinks = std::vector<ElementLink<TPC>>;
+        using PartLinks = std::vector<ElementLink<IPC>>;
+        using TPV = std::vector<const xAOD::TrackParticle*>;
+
+        TrackSortVar trackSortVar(ConstituentsSortOrder, const FTagOptions&);
+        std::pair<TrackFilter,std::set<std::string>> trackFilter(
+          ConstituentsSelection, const FTagOptions&);
+        std::pair<TrackSequenceFilter,std::set<std::string>> flipFilter(
+          const FTagOptions&);
+        
+        Tracks getTracksFromJet(const Jet& jet, const AE& btag) const;
+
+        TrackSortVar m_trackSortVar;
+        TrackFilter m_trackFilter;
+        TrackSequenceFilter m_flipFilter;
+        std::function<TPV(const SG::AuxElement&)> m_associator;
+        getter_utils::CustomSequenceGetter<xAOD::TrackParticle> m_customSequenceGetter;
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/customGetter.h b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/customGetter.h
deleted file mode 100644
index 6f846747476bf7e319c78584c7d7f482569b03cd..0000000000000000000000000000000000000000
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/FlavorTagDiscriminants/customGetter.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-*/
-
-// The customGetter file is a catch-all for various getter functinos
-// that need to be hard coded for whatever reason. Some of these are
-// accessing methods like `pt` which have no name in the EDM, others
-// can't be stored in the edm directly for various reasons.
-
-
-// EDM includes
-#include "xAODJet/JetFwd.h"
-#include "xAODTracking/TrackParticleFwd.h"
-#include "AthContainers/AuxElement.h"
-
-#include <functional>
-#include <string>
-#include <set>
-
-#ifndef CUSTOM_GETTER_H
-#define CUSTOM_GETTER_H
-
-namespace FlavorTagDiscriminants {
-
-  /// Factory function to produce TrackParticle -> vector<double> functions
-  ///
-  /// DL2 configures the its inputs when the algorithm is initalized,
-  /// meaning that the list of track and jet properties that are used
-  /// as inputs won't be known at compile time. Instead we build an
-  /// array of "getter" functions, each of which returns one input for
-  /// the tagger. The function here returns those getter functions.
-  ///
-  /// Many of the getter functions are trivial: they will, for example,
-  /// read one double of auxdata off of the BTagging object. The
-  /// sequence input getters tend to be more complicated. Since we'd
-  /// like to avoid reimplementing the logic in these functions in
-  /// multiple places, they are exposed here.
-  ///
-  /// This function will return a getter based on a string key. See the
-  /// implementation for the definitions.
-  ///
-  /// NOTE: This function is for experts only, don't expect support.
-  ///
-
-  using SequenceFromTracks = std::function<std::vector<double>(
-    const xAOD::Jet&,
-    const std::vector<const xAOD::TrackParticle*>&)>;
-
-  std::pair<SequenceFromTracks, std::set<std::string>>
-  customSequenceGetterWithDeps(
-    const std::string& name,   // name of the getter
-    const std::string& prefix  // prefix for track accessor
-    );
-
-  // internal functions
-  namespace internal {
-    std::function<std::pair<std::string, double>(const xAOD::Jet&)>
-    customGetterAndName(const std::string&);
-
-    std::pair<std::function<std::pair<std::string, std::vector<double>>(
-      const xAOD::Jet&,
-      const std::vector<const xAOD::TrackParticle*>&)>,
-      std::set<std::string>>
-    customNamedSeqGetterWithDeps(const std::string&, const std::string&);
-  }
-}
-
-#endif
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/README.md b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/README.md
index f774c31a1777d6d8a7bbd4869d6833d28b77edd1..1b76a0a16a481f635512a7ad2027f5ec8f78d723 100644
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/README.md
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/README.md
@@ -107,9 +107,9 @@ Some components of Hbb tagging also live here. These include:
 
 There are also several tools that you _probably_ don't have to touch:
 
- - `customGetter`: DL2 relies on some information that isn't stored in
+ - `CustomGetterUtils`: DL2 relies on some information that isn't stored in
    accessors that we can get with a string (i.e. `pt`, `eta`,
-   ...). These are defined in `customGetter`.
+   ...). These are defined in `CustomGetterUtils`.
 
 
 
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/ConstituentsLoader.cxx b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/ConstituentsLoader.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6433f58e212148ad405c525988de5fee8de6a754
--- /dev/null
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/ConstituentsLoader.cxx
@@ -0,0 +1,162 @@
+/*
+Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FlavorTagDiscriminants/ConstituentsLoader.h"
+
+namespace {
+  using namespace FlavorTagDiscriminants;
+
+  // define a regex literal operator
+  std::regex operator "" _r(const char* c, size_t /* length */) {
+    return std::regex(c);
+  }
+
+  // ____________________________________________________________________
+  //
+  // We define a few structures to map variable names to type, default
+  // value, etc.
+  //
+  typedef std::vector<std::pair<std::regex, ConstituentsEDMType>> TypeRegexes;
+  typedef std::vector<std::pair<std::regex, std::string>> StringRegexes;
+  typedef std::vector<std::pair<std::regex, ConstituentsSortOrder>> SortRegexes;
+  typedef std::vector<std::pair<std::regex, ConstituentsSelection>> SelRegexes;
+  
+  ConstituentsInputConfig get_iparticle_input_config(
+    const std::string& name,
+    const std::vector<std::string>& input_variables,
+    const TypeRegexes& type_regexes) {
+    ConstituentsInputConfig config;
+    config.name = name;
+    config.order = ConstituentsSortOrder::PT_DESCENDING;
+    for (const auto& varname: input_variables) {
+      InputVariableConfig input;
+      size_t pos = varname.find("flow_");
+      if (pos != std::string::npos){
+        input.name = varname.substr(pos+5);
+      }
+      else{
+        input.name = varname;
+      }
+      input.flip_sign = false;
+      input.type = str::match_first(type_regexes, input.name,
+                                "iparticle type matching");
+      config.inputs.push_back(input);
+    }
+    return config;
+  }
+
+  ConstituentsInputConfig get_track_input_config(
+    const std::string& name,
+    const std::vector<std::string>& input_variables,
+    const TypeRegexes& type_regexes,
+    const SortRegexes& sort_regexes,
+    const SelRegexes& select_regexes,
+    const std::regex& re,
+    const FlipTagConfig& flip_config) {
+    ConstituentsInputConfig config;
+    config.name = name;
+    config.order = str::match_first(sort_regexes, name,
+                              "track order matching");
+    config.selection = str::match_first(select_regexes, name,
+                                  "track selection matching");
+    for (const auto& varname: input_variables) {
+      InputVariableConfig input;
+      input.name = varname;
+      input.type = str::match_first(type_regexes, varname,
+                                "track type matching");
+
+      input.flip_sign=false;
+      if ((flip_config != FlipTagConfig::STANDARD) && std::regex_match(varname, re)){
+        input.flip_sign=true;
+      }
+      config.inputs.push_back(input);
+    }
+    return config;
+  }
+}
+
+namespace FlavorTagDiscriminants {
+    //
+    // Create a configuration for the constituents loaders
+    //
+    ConstituentsInputConfig createConstituentsLoaderConfig(
+      std::string name,
+      std::vector<std::string> input_variables,
+      FlipTagConfig flip_config
+    ){
+      ConstituentsInputConfig config;
+
+      TypeRegexes iparticle_type_regexes {
+          // iparticle variables
+          // ConstituentsEDMType picked correspond to the first matching regex
+          {"(pt|deta|dphi|energy)"_r, ConstituentsEDMType::CUSTOM_GETTER}
+      };
+      TypeRegexes trk_type_regexes {
+          // Some innermost / next-to-innermost hit variables had a different
+          // definition in 21p9, recomputed here with customGetter to reuse
+          // existing training
+          // ConstituentsEDMType picked correspond to the first matching regex
+          {"numberOf.*21p9"_r, ConstituentsEDMType::CUSTOM_GETTER},
+          {"numberOf.*"_r, ConstituentsEDMType::UCHAR},
+          {"btagIp_(d0|z0SinTheta)Uncertainty"_r, ConstituentsEDMType::FLOAT},
+          {"(numberDoF|chiSquared|qOverP|theta)"_r, ConstituentsEDMType::FLOAT},
+          {"(^.*[_])?(d|z)0.*"_r, ConstituentsEDMType::CUSTOM_GETTER},
+          {"(log_)?(ptfrac|dr|pt).*"_r, ConstituentsEDMType::CUSTOM_GETTER},
+          {"(deta|dphi)"_r, ConstituentsEDMType::CUSTOM_GETTER},
+          {"phi|theta|qOverP"_r, ConstituentsEDMType::FLOAT},
+          {"(phi|theta|qOverP)Uncertainty"_r, ConstituentsEDMType::CUSTOM_GETTER},
+          {"leptonID"_r, ConstituentsEDMType::CHAR}
+      };
+      // We have a number of special naming conventions to sort and
+      // filter tracks. The track nodes should be named according to
+      //
+      // tracks_<selection>_<sort-order>
+      //
+      SortRegexes trk_sort_regexes {
+          {".*absSd0sort"_r, ConstituentsSortOrder::ABS_D0_SIGNIFICANCE_DESCENDING},
+          {".*sd0sort"_r, ConstituentsSortOrder::D0_SIGNIFICANCE_DESCENDING},
+          {".*ptsort"_r, ConstituentsSortOrder::PT_DESCENDING},
+          {".*absD0DescendingSort"_r, ConstituentsSortOrder::ABS_D0_DESCENDING},
+      };
+      SelRegexes trk_select_regexes {
+          {".*_ip3d_.*"_r, ConstituentsSelection::IP3D_2018},
+          {".*_dipsTightUpgrade_.*"_r, ConstituentsSelection::DIPS_TIGHT_UPGRADE},
+          {".*_dipsLooseUpgrade_.*"_r, ConstituentsSelection::DIPS_LOOSE_UPGRADE},
+          {".*_all_.*"_r, ConstituentsSelection::ALL},
+          {".*_dipsLoose202102_.*"_r, ConstituentsSelection::DIPS_LOOSE_202102},
+          {".*_loose202102NoIpCuts_.*"_r, ConstituentsSelection::LOOSE_202102_NOIP},
+          {".*_r22default_.*"_r, ConstituentsSelection::R22_DEFAULT},
+          {".*_r22loose_.*"_r, ConstituentsSelection::R22_LOOSE},
+      };
+      
+      if (name.find("tracks") != std::string::npos){
+        std::regex flip_sequences;
+        if (flip_config == FlipTagConfig::FLIP_SIGN || flip_config == FlipTagConfig::NEGATIVE_IP_ONLY){
+          flip_sequences=std::regex(".*signed_[dz]0.*");
+        }
+        if (flip_config == FlipTagConfig::SIMPLE_FLIP){
+          flip_sequences=std::regex("(.*signed_[dz]0.*)|d0|z0SinTheta");
+        }
+        config = get_track_input_config(
+          name, input_variables,
+          trk_type_regexes, trk_sort_regexes, trk_select_regexes,
+          flip_sequences, flip_config);
+        config.type = ConstituentsType::TRACK;
+        config.output_name = "track_features";
+      }
+      else if (name.find("flow") != std::string::npos){
+        config = get_iparticle_input_config(
+          name, input_variables,
+          iparticle_type_regexes);
+        config.type = ConstituentsType::IPARTICLE;
+        config.output_name = "flow_features";
+      }
+      else{
+        throw std::runtime_error(
+          "Unknown constituent type: " + name + ". Only tracks and neutrals are supported."
+          );
+      }
+      return config;
+    }
+}
\ No newline at end of file
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/CustomGetterUtils.cxx b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/CustomGetterUtils.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fda23bb834582b4ca2a12124323cb48cda89f9fc
--- /dev/null
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/CustomGetterUtils.cxx
@@ -0,0 +1,495 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+#include "FlavorTagDiscriminants/BTagTrackIpAccessor.h"
+#include "FlavorTagDiscriminants/CustomGetterUtils.h"
+
+#include <optional>
+
+namespace {
+
+  using FlavorTagDiscriminants::getter_utils::SequenceFromTracks;
+  using FlavorTagDiscriminants::getter_utils::SequenceFromIParticles;
+  // ______________________________________________________________________
+  // Custom getters for jet-wise quantities
+  //
+  // this function is not at all optimized, but then it doesn't have
+  // to be since it should only be called in the initialization stage.
+  //
+  std::function<double(const xAOD::Jet&)> customGetter(
+    const std::string& name)
+  {
+    if (name == "pt") {
+      return [](const xAOD::Jet& j) -> float {return j.pt();};
+    }
+    if (name == "log_pt") {
+      return [](const xAOD::Jet& j) -> float {return std::log(j.pt());};
+    }
+    if (name == "eta") {
+      return [](const xAOD::Jet& j) -> float {return j.eta();};
+    }
+    if (name == "abs_eta") {
+      return [](const xAOD::Jet& j) -> float {return std::abs(j.eta());};
+    }
+    if (name == "energy") {
+      return [](const xAOD::Jet& j) -> float {return j.e();};
+    }
+    if (name == "mass") {
+      return [](const xAOD::Jet& j) -> float {return j.m();};
+    }
+
+    throw std::logic_error("no match for custom getter " + name);
+  }
+
+
+  // _______________________________________________________________________
+  // Custom getters for constituent variables (CJGetter -> Constituent and Jet Getter)
+  template <typename T>
+  class CJGetter
+  {
+    using F = std::function<double(const T&, const xAOD::Jet&)>;
+    private:
+      F m_getter;
+    public:
+        CJGetter(F getter):
+        m_getter(getter)
+        {}
+      std::vector<double> operator()(
+        const xAOD::Jet& jet,
+        const std::vector<const T*>& particles) const {
+        std::vector<double> sequence;
+        sequence.reserve(particles.size());
+        for (const auto* particle: particles) {
+          sequence.push_back(m_getter(*particle, jet));
+        }
+        return sequence;
+      }
+  };
+
+
+  // The sequence getter takes in constituents and calculates arrays of
+  // values which are better suited for inputs to the NNs
+  template <typename T, typename U>
+  class SequenceGetter{
+    private:
+      SG::AuxElement::ConstAccessor<T> m_getter;
+      std::string m_name;
+    public:
+      SequenceGetter(const std::string& name):
+        m_getter(name),
+        m_name(name)
+        {
+        }
+      std::pair<std::string, std::vector<double>> operator()(const xAOD::Jet&, const std::vector<const U*>& consts) const {
+        std::vector<double> seq;
+        for (const U* el: consts) {
+          seq.push_back(m_getter(*el));
+        }
+        return {m_name, seq};
+      }
+  };
+
+
+  // Getters from xAOD::TrackParticle with IP dependencies
+  std::optional<SequenceFromTracks>
+  getterFromTracksWithIpDep(
+    const std::string& name,
+    const std::string& prefix)
+  {
+    using Tp = xAOD::TrackParticle;
+    using Jet = xAOD::Jet;
+
+    BTagTrackIpAccessor a(prefix);
+    if (name == "IP3D_signed_d0_significance") {
+      return CJGetter<Tp>([a](const Tp& tp, const Jet& j){
+        return a.getSignedIp(tp, j).ip3d_signed_d0_significance;
+      });
+    }
+    if (name == "IP3D_signed_z0_significance") {
+      return CJGetter<Tp>([a](const Tp& tp, const Jet& j){
+        return a.getSignedIp(tp, j).ip3d_signed_z0_significance;
+      });
+    }
+    if (name == "IP2D_signed_d0") {
+      return CJGetter<Tp>([a](const Tp& tp, const Jet& j){
+        return a.getSignedIp(tp, j).ip2d_signed_d0;
+      });
+    }
+    if (name == "IP3D_signed_d0") {
+      return CJGetter<Tp>([a](const Tp& tp, const Jet& j){
+        return a.getSignedIp(tp, j).ip3d_signed_d0;
+      });
+    }
+    if (name == "IP3D_signed_z0") {
+      return CJGetter<Tp>([a](const Tp& tp, const Jet& j){
+        return a.getSignedIp(tp, j).ip3d_signed_z0;
+      });
+    }
+    if (name == "d0" || name == "btagIp_d0") {
+      return CJGetter<Tp>([a](const Tp& tp, const Jet&){
+        return a.d0(tp);
+      });
+    }
+    if (name == "z0SinTheta" || name == "btagIp_z0SinTheta") {
+      return CJGetter<Tp>([a](const Tp& tp, const Jet&){
+        return a.z0SinTheta(tp);
+      });
+    }
+    if (name == "d0Uncertainty") {
+      return CJGetter<Tp>([a](const Tp& tp, const Jet&){
+        return a.d0Uncertainty(tp);
+      });
+    }
+    if (name == "z0SinThetaUncertainty") {
+      return CJGetter<Tp>([a](const Tp& tp, const Jet&){
+        return a.z0SinThetaUncertainty(tp);
+      });
+    }
+    return std::nullopt;
+  }
+
+  // Getters from xAOD::TrackParticle without IP dependencies
+  std::optional<SequenceFromTracks>
+  getterFromTracksNoIpDep(const std::string& name)
+  {
+    using Tp = xAOD::TrackParticle;
+    using Jet = xAOD::Jet;
+
+    if (name == "phiUncertainty") {
+      return CJGetter<Tp>([](const Tp& tp, const Jet&) {
+          return std::sqrt(tp.definingParametersCovMatrixDiagVec().at(2));
+      });
+    }
+    if (name == "thetaUncertainty") {
+      return CJGetter<Tp>([](const Tp& tp, const Jet&) {
+          return std::sqrt(tp.definingParametersCovMatrixDiagVec().at(3));
+      });
+    }
+    if (name == "qOverPUncertainty") {
+      return CJGetter<Tp>([](const Tp& tp, const Jet&) {
+          return std::sqrt(tp.definingParametersCovMatrixDiagVec().at(4));
+      });
+    }
+    if (name == "z0RelativeToBeamspot") {
+      return CJGetter<Tp>([](const Tp& tp, const Jet&) {
+          return tp.z0();
+      });
+    }
+    if (name == "log_z0RelativeToBeamspotUncertainty") {
+      return CJGetter<Tp>([](const Tp& tp, const Jet&) {
+          return std::log(std::sqrt(tp.definingParametersCovMatrixDiagVec().at(1)));
+      });
+    }
+    if (name == "z0RelativeToBeamspotUncertainty") {
+      return CJGetter<Tp>([](const Tp& tp, const Jet&) {
+          return std::sqrt(tp.definingParametersCovMatrixDiagVec().at(1));
+      });
+    }
+    if (name == "numberOfPixelHitsInclDead") {
+      SG::AuxElement::ConstAccessor<unsigned char> pix_hits("numberOfPixelHits");
+      SG::AuxElement::ConstAccessor<unsigned char> pix_dead("numberOfPixelDeadSensors");
+      return CJGetter<Tp>([pix_hits, pix_dead](const Tp& tp, const Jet&) {
+        return pix_hits(tp) + pix_dead(tp);
+      });
+    }
+    if (name == "numberOfSCTHitsInclDead") {
+      SG::AuxElement::ConstAccessor<unsigned char> sct_hits("numberOfSCTHits");
+      SG::AuxElement::ConstAccessor<unsigned char> sct_dead("numberOfSCTDeadSensors");
+      return CJGetter<Tp>([sct_hits, sct_dead](const Tp& tp, const Jet&) {
+        return sct_hits(tp) + sct_dead(tp);
+      });
+      }
+    if (name == "numberOfInnermostPixelLayerHits21p9") {
+      SG::AuxElement::ConstAccessor<unsigned char> barrel_hits("numberOfInnermostPixelLayerHits");
+      SG::AuxElement::ConstAccessor<unsigned char> endcap_hits("numberOfInnermostPixelLayerEndcapHits");
+      return CJGetter<Tp>([barrel_hits, endcap_hits](const Tp& tp, const Jet&) {
+        return barrel_hits(tp) + endcap_hits(tp);
+      });
+    }
+    if (name == "numberOfNextToInnermostPixelLayerHits21p9") {
+      SG::AuxElement::ConstAccessor<unsigned char> barrel_hits("numberOfNextToInnermostPixelLayerHits");
+      SG::AuxElement::ConstAccessor<unsigned char> endcap_hits("numberOfNextToInnermostPixelLayerEndcapHits");
+      return CJGetter<Tp>([barrel_hits, endcap_hits](const Tp& tp, const Jet&) {
+        return barrel_hits(tp) + endcap_hits(tp);
+      });
+    }
+    if (name == "numberOfInnermostPixelLayerSharedHits21p9") {
+      SG::AuxElement::ConstAccessor<unsigned char> barrel_hits("numberOfInnermostPixelLayerSharedHits");
+      SG::AuxElement::ConstAccessor<unsigned char> endcap_hits("numberOfInnermostPixelLayerSharedEndcapHits");
+      return CJGetter<Tp>([barrel_hits, endcap_hits](const Tp& tp, const Jet&) {
+        return barrel_hits(tp) + endcap_hits(tp);
+      });
+    }
+    if (name == "numberOfInnermostPixelLayerSplitHits21p9") {
+      SG::AuxElement::ConstAccessor<unsigned char> barrel_hits("numberOfInnermostPixelLayerSplitHits");
+      SG::AuxElement::ConstAccessor<unsigned char> endcap_hits("numberOfInnermostPixelLayerSplitEndcapHits");
+      return CJGetter<Tp>([barrel_hits, endcap_hits](const Tp& tp, const Jet&) {
+        return barrel_hits(tp) + endcap_hits(tp);
+      });
+    }
+    return std::nullopt;
+  }
+
+
+  // Getters from general xAOD::IParticle and derived classes
+  template <typename T>
+  std::optional<
+  std::function<std::vector<double>(
+    const xAOD::Jet&,
+    const std::vector<const T*>&)>
+  >
+  getterFromIParticles(const std::string& name)
+  {
+    using Jet = xAOD::Jet;
+
+    if (name == "pt") {
+      return CJGetter<T>([](const T& p, const Jet&) {
+        return p.pt();
+      });
+    }
+    if (name == "log_pt") {
+      return CJGetter<T>([](const T& p, const Jet&) {
+        return std::log(p.pt());
+      });
+    }
+    if (name == "ptfrac") {
+      return CJGetter<T>([](const T& p, const Jet& j) {
+        return p.pt() / j.pt();
+      });
+    }
+    if (name == "log_ptfrac") {
+      return CJGetter<T>([](const T& p, const Jet& j) {
+        return std::log(p.pt() / j.pt());
+      });
+    }
+
+    if (name == "eta") {
+      return CJGetter<T>([](const T& p, const Jet&) {
+        return p.eta();
+      });
+    }
+    if (name == "deta") {
+      return CJGetter<T>([](const T& p, const Jet& j) {
+        return p.eta() - j.eta();
+      });
+    }
+    if (name == "abs_deta") {
+      return CJGetter<T>([](const T& p, const Jet& j) {
+        return copysign(1.0, j.eta()) * (p.eta() - j.eta());
+      });
+    }
+
+    if (name == "phi") {
+      return CJGetter<T>([](const T& p, const Jet&) {
+        return p.phi();
+      });
+    }
+    if (name == "dphi") {
+      return CJGetter<T>([](const T& p, const Jet& j) {
+        return p.p4().DeltaPhi(j.p4());
+      });
+    }
+
+    if (name == "dr") {
+      return CJGetter<T>([](const T& p, const Jet& j) {
+        return p.p4().DeltaR(j.p4());
+      });
+    }
+    if (name == "log_dr") {
+      return CJGetter<T>([](const T& p, const Jet& j) {
+        return std::log(p.p4().DeltaR(j.p4()));
+      });
+    }
+    if (name == "log_dr_nansafe") {
+      return CJGetter<T>([](const T& p, const Jet& j) {
+        return std::log(p.p4().DeltaR(j.p4()) + 1e-7);
+      });
+    }
+
+    if (name == "mass") {
+      return CJGetter<T>([](const T& p, const Jet&) {
+        return p.m();
+      });
+    }
+    if (name == "energy") {
+      return CJGetter<T>([](const T& p, const Jet&) {
+        return p.e();
+      });
+    }
+    return std::nullopt;
+  }
+
+}
+  namespace FlavorTagDiscriminants {
+  namespace getter_utils {
+    // ________________________________________________________________
+    // Interface functions
+    //
+    // As long as we're giving lwtnn pair<name, double> objects, we
+    // can't use the raw getter functions above (which only return a
+    // double). Instead we'll wrap those functions in another function,
+    // which returns the pair we wanted.
+    //
+    // Case for jet variables
+    std::function<std::pair<std::string, double>(const xAOD::Jet&)>
+    customGetterAndName(const std::string& name) {
+      auto getter = customGetter(name);
+      return [name, getter](const xAOD::Jet& j) {
+               return std::make_pair(name, getter(j));
+             };
+    }
+
+    // Case for constituent variables
+    // Returns getter function with dependencies
+    template <typename T>
+    std::pair<
+    std::function<std::vector<double>(
+      const xAOD::Jet&,
+      const std::vector<const T*>&)>,
+    std::set<std::string>>
+    customSequenceGetterWithDeps(const std::string& name,
+                                const std::string& prefix) {
+
+      if constexpr (std::is_same_v<T, xAOD::TrackParticle>) {
+        if (auto getter = getterFromTracksWithIpDep(name, prefix)) {
+          auto deps = BTagTrackIpAccessor(prefix).getTrackIpDataDependencyNames();
+          return {*getter, deps};
+        }
+        if (auto getter = getterFromTracksNoIpDep(name)) {
+          return {*getter, {}};
+        }
+      }
+      if (auto getter = getterFromIParticles<T>(name)){
+        return {*getter, {}};
+      }
+      throw std::logic_error("no match for custom getter " + name);
+    }
+    
+    // ________________________________________________________________________
+    // Class implementation
+    //
+    template <typename T>
+    std::pair<typename CustomSequenceGetter<T>::NamedSequenceFromConstituents, std::set<std::string>> 
+    CustomSequenceGetter<T>::customNamedSeqGetterWithDeps(const std::string& name,
+                                 const std::string& prefix) {
+      auto [getter, deps] = customSequenceGetterWithDeps<T>(name, prefix);
+      return {
+        [n=name, g=getter](const xAOD::Jet& j,
+                       const std::vector<const T*>& t) {
+          return std::make_pair(n, g(j, t));
+        },
+        deps
+      };
+    }
+
+    template <typename T>
+    std::pair<typename CustomSequenceGetter<T>::NamedSequenceFromConstituents, std::set<std::string>> 
+    CustomSequenceGetter<T>::seqFromConsituents(
+        const InputVariableConfig& cfg, 
+        const FTagOptions& options){
+      const std::string prefix = options.track_prefix;
+      switch (cfg.type) {
+        case ConstituentsEDMType::INT: return {
+            SequenceGetter<int, T>(cfg.name), {cfg.name}
+          };
+        case ConstituentsEDMType::FLOAT: return {
+            SequenceGetter<float, T>(cfg.name), {cfg.name}
+          };
+        case ConstituentsEDMType::CHAR: return {
+            SequenceGetter<char, T>(cfg.name), {cfg.name}
+          };
+        case ConstituentsEDMType::UCHAR: return {
+            SequenceGetter<unsigned char, T>(cfg.name), {cfg.name}
+          };
+        case ConstituentsEDMType::CUSTOM_GETTER: {
+          return customNamedSeqGetterWithDeps(
+            cfg.name, options.track_prefix);
+        }
+        default: {
+          throw std::logic_error("Unknown EDM type for constituent.");
+        }
+      }
+    }
+
+    template <typename T>
+    CustomSequenceGetter<T>::CustomSequenceGetter(
+      std::vector<InputVariableConfig> inputs,
+      const FTagOptions& options)
+    {
+        std::map<std::string, std::string> remap = options.remap_scalar;
+        for (const InputVariableConfig& input_cfg: inputs) {
+          auto [seqGetter, seq_deps] = seqFromConsituents(
+          input_cfg, options);
+
+          if(input_cfg.flip_sign){
+            auto seqGetter_flip=[g=seqGetter](const xAOD::Jet&jet, const Constituents& constituents){
+              auto [n,v] = g(jet,constituents);
+              std::for_each(v.begin(), v.end(), [](double &n){ n=-1.0*n; });
+              return std::make_pair(n,v);
+            };
+            m_sequencesFromConstituents.push_back(seqGetter_flip);
+          }
+          else{
+            m_sequencesFromConstituents.push_back(seqGetter);
+          }
+          m_deps.merge(seq_deps);
+          if (auto h = remap.extract(input_cfg.name)){
+            m_used_remap.insert(h.key());
+          }
+        }
+    }
+
+    template <typename T>
+    std::pair<std::vector<float>, std::vector<int64_t>> CustomSequenceGetter<T>::getFeats(
+      const xAOD::Jet& jet, const Constituents& constituents) const
+    {
+      std::vector<float> cnsts_feats;
+      int num_vars = m_sequencesFromConstituents.size();
+      int num_cnsts = 0;
+
+      int cnst_var_idx = 0;
+      for (const auto& seq_builder: m_sequencesFromConstituents){
+        auto double_vec = seq_builder(jet, constituents).second;
+
+        if (cnst_var_idx==0){
+            num_cnsts = static_cast<int>(double_vec.size());
+            cnsts_feats.resize(num_cnsts * num_vars);
+        }
+
+        // need to transpose + flatten
+        for (unsigned int cnst_idx=0; cnst_idx<double_vec.size(); cnst_idx++){
+          cnsts_feats.at(cnst_idx*num_vars + cnst_var_idx)
+              = double_vec.at(cnst_idx);
+        }
+        cnst_var_idx++;
+      }
+      std::vector<int64_t> cnsts_feat_dim = {num_cnsts, num_vars};
+      return {cnsts_feats, cnsts_feat_dim};
+    }
+
+    template <typename T>
+    std::map<std::string, std::vector<double>> CustomSequenceGetter<T>::getDL2Feats(
+      const xAOD::Jet& jet, const Constituents& constituents) const
+    {
+      std::map<std::string, std::vector<double>> feats;
+      for (const auto& seq_builder: m_sequencesFromConstituents){
+        feats.insert(seq_builder(jet, constituents));
+      }
+      return feats;
+    }
+
+    template <typename T>
+    std::set<std::string> CustomSequenceGetter<T>::getDependencies() const {
+      return m_deps;
+    }
+    template <typename T>
+    std::set<std::string> CustomSequenceGetter<T>::getUsedRemap() const {
+      return m_used_remap;
+    }
+
+
+    // Explicit instantiations of supported types (IParticle, TrackParticle)
+    template class CustomSequenceGetter<xAOD::IParticle>;
+    template class CustomSequenceGetter<xAOD::TrackParticle>;
+  }
+}
\ No newline at end of file
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DL2.cxx b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DL2.cxx
index 7e453a08cc171a31471e23c3112640a29af13b36..1e94b9860d490ab406496340281ee16e9ea9d154 100644
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DL2.cxx
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DL2.cxx
@@ -21,7 +21,7 @@ namespace FlavorTagDiscriminants {
   // TODO: make this work with more input nodes
   DL2::DL2(const lwt::GraphConfig& graph_config,
            const std::vector<FTagInputConfig>& inputs,
-           const std::vector<FTagTrackSequenceConfig>& track_sequences,
+           const std::vector<ConstituentsInputConfig>& tracks_configs,
            const FTagOptions& options):
     m_jetLink(jetLinkName),
     m_input_node_name(""),
@@ -44,11 +44,10 @@ namespace FlavorTagDiscriminants {
     m_varsFromBTag = vb;
     m_varsFromJet = vj;
     m_dataDependencyNames += ds;
-
-    auto [tsb, td, rt] = dataprep::createTrackGetters(
-      track_sequences, options);
-    m_dataDependencyNames += td;
-    m_trackSequenceBuilders = tsb;
+    
+    for (auto config : tracks_configs){
+      m_tracksLoaders.push_back(std::make_shared<TracksLoader>(config, options));
+    }
 
     auto [decorators, dd, rd] = dataprep::createDecorators(
       graph_config, options);
@@ -61,9 +60,13 @@ namespace FlavorTagDiscriminants {
     m_is_defaults = is_defaults;
     m_dataDependencyNames += ipdd;
 
+    // Update dependencies and used remap from the tracks loaders.
+    for (auto loader : m_tracksLoaders){
+      m_dataDependencyNames += loader->getDependencies();
+      rd.merge(loader->getUsedRemap());
+    }
     // check that all remapping was used
     rd.merge(rc);
-    rd.merge(rt);
     dataprep::checkForUnusedRemaps(options.remap_scalar, rd);
   }
 
@@ -111,15 +114,11 @@ namespace FlavorTagDiscriminants {
     // add track sequences, check if any are invalid
     char invalid = 0;
     std::map<std::string, std::map<std::string, std::vector<double>>> seqs;
-    for (const auto& builder: m_trackSequenceBuilders) {
 
-      Tracks sorted_tracks = builder.tracksFromJet(jet, btag);
-      if (m_invalid_track_checker(sorted_tracks)) invalid = 1;
-      Tracks flipped_tracks = builder.flipFilter(sorted_tracks, jet);
-
-      for (const auto& seq_builder: builder.sequencesFromTracks) {
-        seqs[builder.name].insert(seq_builder(jet, flipped_tracks));
-      }
+    for (auto loader : m_tracksLoaders){
+      std::map<std::string, std::vector<double>> feats;
+      std::tie(invalid, feats) = loader->getDL2Data(jet, btag, m_invalid_track_checker);
+      seqs[loader->getName()] = feats;
     }
 
     for (const auto& def: m_is_defaults) {
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DL2HighLevel.cxx b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DL2HighLevel.cxx
index c1e489f471dbbd152241f7dfe1f74affb5d34613..6aa1e9c3f7055acd7f5c907a6fdafedced382ea1 100644
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DL2HighLevel.cxx
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DL2HighLevel.cxx
@@ -40,7 +40,7 @@ namespace FlavorTagDiscriminants {
       throw std::logic_error("DL2 doesn't support multiple inputs");
     }
 
-    auto [input_config, trk_config, options] = dataprep::createGetterConfig(
+    auto [input_config, constituents_configs, options] = dataprep::createGetterConfig(
       config, flip_config, std::move(remap_scalar), track_link_type);
     options.default_output_value = default_output_value;
 
@@ -48,7 +48,7 @@ namespace FlavorTagDiscriminants {
       new DL2(
         config,                 // lwtnn config
         input_config,           // EDM input config
-        trk_config,             // edm track input config
+        constituents_configs,   // edm track input config
         options
         ));
   }
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DataPrepUtilities.cxx b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DataPrepUtilities.cxx
index 57437dcfbadf2bcab6ba716b798ac4230576eeb6..916f0e5ee2b98d0d7aa9e05c45301400f0459121 100644
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DataPrepUtilities.cxx
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/DataPrepUtilities.cxx
@@ -1,10 +1,10 @@
 /*
-Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "FlavorTagDiscriminants/DataPrepUtilities.h"
 #include "FlavorTagDiscriminants/BTagTrackIpAccessor.h"
-#include "FlavorTagDiscriminants/customGetter.h"
+#include "FlavorTagDiscriminants/CustomGetterUtils.h"
 #include "FlavorTagDiscriminants/StringUtils.h"
 
 #include "xAODBTagging/BTaggingUtilities.h"
@@ -18,11 +18,7 @@ namespace {
   }
 
   using FlavorTagDiscriminants::EDMType;
-  using FlavorTagDiscriminants::SortOrder;
-  using FlavorTagDiscriminants::TrackSelection;
-  using FlavorTagDiscriminants::FTagTrackSequenceConfig;
   using FlavorTagDiscriminants::FTagInputConfig;
-  using FlavorTagDiscriminants::FTagTrackInputConfig;
   using FlavorTagDiscriminants::FlipTagConfig;
   // ____________________________________________________________________
   // High level adapter stuff
@@ -32,8 +28,6 @@ namespace {
   //
   typedef std::vector<std::pair<std::regex, EDMType> > TypeRegexes;
   typedef std::vector<std::pair<std::regex, std::string> > StringRegexes;
-  typedef std::vector<std::pair<std::regex, SortOrder> > SortRegexes;
-  typedef std::vector<std::pair<std::regex, TrackSelection> > TrkSelRegexes;
 
   // Function to map the regular expressions + the list of inputs to a
   // list of variable configurations.
@@ -49,16 +43,6 @@ namespace {
                     std::map<std::string, std::string>& replaced_vars,
                     std::map<std::string, double>& defaults);
 
-  // Function to map the regex + list of inputs to variable config,
-  // this time for sequence inputs.
-  std::vector<FTagTrackSequenceConfig> get_track_input_config(
-    const std::vector<std::pair<std::string, std::vector<std::string>>>& names,
-    const TypeRegexes& type_regexes,
-    const SortRegexes& sort_regexes,
-    const TrkSelRegexes& select_regexes,
-    const std::regex& flip_re,
-    const FlipTagConfig& flip_config);
-
   // replace strings for flip taggers
   void rewriteFlipConfig(lwt::GraphConfig&, const StringRegexes&);
 
@@ -119,41 +103,6 @@ namespace {
     }
   }
 
-
-  std::vector<FTagTrackSequenceConfig> get_track_input_config(
-    const std::vector<std::pair<std::string, std::vector<std::string>>>& names,
-    const TypeRegexes& type_regexes,
-    const SortRegexes& sort_regexes,
-    const TrkSelRegexes& select_regexes,
-    const std::regex& flip_re,
-    const FlipTagConfig& flip_config) {
-    std::vector<FTagTrackSequenceConfig> nodes;
-    for (const auto& name_node: names) {
-      FTagTrackSequenceConfig node;
-      node.name = name_node.first;
-      node.order = str::match_first(sort_regexes, name_node.first,
-                               "track order matching");
-      node.selection = str::match_first(select_regexes, name_node.first,
-                                   "track selection matching");
-      for (const auto& varname: name_node.second) {
-        FTagTrackInputConfig input;
-        input.name = varname;
-        input.type = str::match_first(type_regexes, varname,
-                                 "track type matching");
-
-        input.flip_sign=false;
-        if ((flip_config != FlipTagConfig::STANDARD) && std::regex_match(varname, flip_re)){
-          input.flip_sign=true;
-        }
-        
-        node.inputs.push_back(input);
-      }
-      nodes.push_back(node);
-    }
-    return nodes;
-  }
-
-
   void rewriteFlipConfig(lwt::GraphConfig& config,
                          const StringRegexes& res){
     std::string context = "building negative tag b-btagger";
@@ -194,80 +143,6 @@ namespace FlavorTagDiscriminants {
   // Internal code
   namespace internal {
 
-    // Track Getter Class
-    TracksFromJet::TracksFromJet(
-      SortOrder order,
-      TrackSelection selection,
-      const FTagOptions& options):
-      m_trackSortVar(get::trackSortVar(order, options)),
-      m_trackFilter(get::trackFilter(selection, options).first){
-
-      // We have several ways to get tracks: either we retrieve an
-      // IParticleContainer and cast the pointers to TrackParticle, or
-      // we retrieve a TrackParticleContainer directly. Unfortunately
-      // the way tracks are stored isn't consistent across the EDM, so
-      // we allow configuration for both setups.
-      //
-      if (options.track_link_type == TrackLinkType::IPARTICLE) {
-        SG::AuxElement::ConstAccessor<PartLinks> acc(options.track_link_name);
-        m_associator = [acc](const SG::AuxElement& btag) -> TPV {
-          TPV tracks;
-          for (const ElementLink<IPC>& link: acc(btag)) {
-            if (!link.isValid()) {
-              throw std::logic_error("invalid particle link");
-            }
-            const auto* trk = dynamic_cast<const xAOD::TrackParticle*>(*link);
-            if (!trk) {
-              throw std::logic_error("iparticle does not cast to Track");
-            }
-            tracks.push_back(trk);
-          }
-          return tracks;
-        };
-      } else if (options.track_link_type == TrackLinkType::TRACK_PARTICLE){
-        SG::AuxElement::ConstAccessor<TrackLinks> acc(options.track_link_name);
-        m_associator = [acc](const SG::AuxElement& btag) -> TPV {
-          TPV tracks;
-          for (const ElementLink<TPC>& link: acc(btag)) {
-            if (!link.isValid()) {
-              throw std::logic_error("invalid track link");
-            }
-            tracks.push_back(*link);
-          }
-          return tracks;
-        };
-      } else {
-        throw std::logic_error("Unknown TrackLinkType");
-      }
-    }
-
-    Tracks TracksFromJet::operator()(const xAOD::Jet& jet,
-                                     const SG::AuxElement& btagging) const {
-
-      std::vector<std::pair<double, const xAOD::TrackParticle*>> tracks;
-      for (const xAOD::TrackParticle *tp : m_associator(btagging)) {
-        if (m_trackFilter(tp)) {
-          tracks.push_back({m_trackSortVar(tp, jet), tp});
-        };
-      }
-      std::sort(tracks.begin(), tracks.end(), std::greater<>());
-      std::vector<const xAOD::TrackParticle*> only_tracks;
-      only_tracks.reserve(tracks.size());
-      for (const auto& trk: tracks) {
-        only_tracks.push_back(trk.second);
-      }
-      return only_tracks;
-    }
-
-    // constructor
-    internal::TrackSequenceBuilder::TrackSequenceBuilder(
-      SortOrder sort,
-      TrackSelection selection,
-      const FTagOptions& options):
-      tracksFromJet(sort, selection, options),
-      flipFilter(internal::get::flipFilter(options).first){
-    }
-
     // ______________________________________________________________________
     // Internal utility functions
     //
@@ -305,284 +180,6 @@ namespace FlavorTagDiscriminants {
           }
         }
       }
-
-      // factory for functions which return the sort variable we
-      // use to order tracks
-      TrackSortVar trackSortVar(SortOrder config, const FTagOptions& options)
-      {
-        typedef xAOD::TrackParticle Tp;
-        typedef xAOD::Jet Jet;
-        BTagTrackIpAccessor aug(options.track_prefix);
-        switch(config) {
-        case SortOrder::ABS_D0_SIGNIFICANCE_DESCENDING:
-          return [aug](const Tp* tp, const Jet&) {
-                   return std::abs(aug.d0(*tp) / aug.d0Uncertainty(*tp));
-                 };
-        case SortOrder::D0_SIGNIFICANCE_DESCENDING:
-          return [aug](const Tp* tp, const Jet& j) {
-                   return aug.getSignedIp(*tp, j).ip3d_signed_d0_significance;
-                 };
-        case SortOrder::PT_DESCENDING:
-          return [](const Tp* tp, const Jet&) {return tp->pt();};
-        case SortOrder::ABS_D0_DESCENDING:
-          return [aug](const Tp* tp, const Jet&) {
-            return std::abs(aug.d0(*tp));
-          };
-
-        default: {
-          throw std::logic_error("Unknown sort function");
-        }
-        }
-      } // end of track sort getter
-
-      // factory for functions that return true for tracks we want to
-      // use, false for those we don't want
-      std::pair<TrackFilter,std::set<std::string>> trackFilter(
-        TrackSelection config, const FTagOptions& options) {
-
-        typedef xAOD::TrackParticle Tp;
-        typedef SG::AuxElement AE;
-        BTagTrackIpAccessor aug(options.track_prefix);
-        auto data_deps = aug.getTrackIpDataDependencyNames();
-
-        // make sure we record accessors as data dependencies
-        std::set<std::string> track_deps;
-        auto addAccessor = [&track_deps](const std::string& n) {
-                             AE::ConstAccessor<unsigned char> a(n);
-                             track_deps.insert(n);
-                             return a;
-                           };
-        auto pix_hits = addAccessor("numberOfPixelHits");
-        auto pix_holes = addAccessor("numberOfPixelHoles");
-        auto pix_shared = addAccessor("numberOfPixelSharedHits");
-        auto pix_dead = addAccessor("numberOfPixelDeadSensors");
-        auto sct_hits = addAccessor("numberOfSCTHits");
-        auto sct_holes = addAccessor("numberOfSCTHoles");
-        auto sct_shared = addAccessor("numberOfSCTSharedHits");
-        auto sct_dead = addAccessor("numberOfSCTDeadSensors");
-
-        // data deps is all possible dependencies. We insert here to
-        // avoid removing them from track_deps (as merge would).
-        data_deps.insert(track_deps.begin(), track_deps.end());
-
-        switch (config) {
-        case TrackSelection::ALL: return {[](const Tp*) {return true;}, {} };
-          // the following numbers come from Nicole, Dec 2018:
-          // pt > 1 GeV
-          // abs(d0) < 1 mm
-          // abs(z0 sin(theta)) < 1.5 mm
-          // >= 7 si hits
-          // <= 2 si holes
-          // <= 1 pix holes
-        case TrackSelection::IP3D_2018:
-          return {
-            [=](const Tp* tp) {
-              // from the track selector tool
-              if (std::abs(tp->eta()) > 2.5) return false;
-              double n_module_shared = (pix_shared(*tp) + sct_shared(*tp) / 2);
-              if (n_module_shared > 1) return false;
-              if (tp->pt() <= 1e3) return false;
-              if (std::abs(aug.d0(*tp)) >= 1.0) return false;
-              if (std::abs(aug.z0SinTheta(*tp)) >= 1.5) return false;
-              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 7) return false;
-              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
-              if (pix_holes(*tp) > 1) return false;
-              return true;
-            }, data_deps
-          };
-          // Tight track selection for DIPS upgrade config
-          // abs(eta) < 4 
-          // pt > 1 GeV
-          // abs(d0) < 1 mm
-          // abs(z0 sin(theta)) < 1.5 mm
-          // No cuts for si hits, si holes and pix holes - only reconstruction selection is applied
-        case TrackSelection::DIPS_TIGHT_UPGRADE:
-          return {
-            [=](const Tp* tp) {
-              // from the track selector tool
-              if (std::abs(tp->eta()) > 4.0) return false;
-              if (tp->pt() <= 1e3) return false;
-              if (std::abs(aug.d0(*tp)) >= 1.0) return false;
-              if (std::abs(aug.z0SinTheta(*tp)) >= 1.5) return false;
-              return true;
-            }, data_deps
-          };
-          // Loose track selection for DIPS upgrade config
-          // abs(eta) < 4
-          // pt > 0.5 GeV
-          // abs(d0) < 3.5 mm
-          // abs(z0 sin(theta)) < 5.0 mm
-          // No cuts for si hits, si holes and pix holes - only reconstruction selection is applied
-        case TrackSelection::DIPS_LOOSE_UPGRADE:
-          return {
-            [=](const Tp* tp) {
-              // from the track selector tool
-              if (std::abs(tp->eta()) > 4.0) return false;
-              if (tp->pt() <= 0.5e3) return false;
-              if (std::abs(aug.d0(*tp)) >= 3.5) return false;
-              if (std::abs(aug.z0SinTheta(*tp)) >= 5.0) return false;
-              return true;
-            }, data_deps
-          };
-          // Loose track selection for DIPS
-          // pt > 0.5 GeV
-          // abs(d0) < 3.5 mm
-          // abs(z0 sin(theta)) < 5.0 mm
-          // >= 7 si hits
-          // <= 2 si holes
-          // <= 1 pix holes
-        case TrackSelection::DIPS_LOOSE_202102:
-          return {
-            [=](const Tp* tp) {
-              // from the track selector tool
-              if (std::abs(tp->eta()) > 2.5) return false;
-              double n_module_shared = (pix_shared(*tp) + sct_shared(*tp) / 2);
-              if (n_module_shared > 1) return false;
-              if (tp->pt() <= 0.5e3) return false;
-              if (std::abs(aug.d0(*tp)) >= 3.5) return false;
-              if (std::abs(aug.z0SinTheta(*tp)) >= 5.0) return false;
-              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 7) return false;
-              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
-              if (pix_holes(*tp) > 1) return false;
-              return true;
-            }, data_deps
-          };
-        case TrackSelection::LOOSE_202102_NOIP:
-          return {
-            [=](const Tp* tp) {
-              if (std::abs(tp->eta()) > 2.5) return false;
-              double n_module_shared = (pix_shared(*tp) + sct_shared(*tp) / 2);
-              if (n_module_shared > 1) return false;
-              if (tp->pt() <= 0.5e3) return false;
-              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 7) return false;
-              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
-              if (pix_holes(*tp) > 1) return false;
-              return true;
-            }, track_deps
-          };
-        // R22_DEFAULT is similar to DIPS_LOOSE_202102, but modifies the min Si hit cut to 8,
-        // which is the default tracking CP recommendation for r22, see
-        // https://twiki.cern.ch/twiki/bin/view/AtlasProtected/TrackingCPRecsRun2R22#Selection_Criteria
-        case TrackSelection::R22_DEFAULT:
-          return {
-            [=](const Tp* tp) {
-              // from the track selector tool
-              if (std::abs(tp->eta()) > 2.5) return false;
-              double n_module_shared = (pix_shared(*tp) + sct_shared(*tp) / 2);
-              if (n_module_shared > 1) return false;
-              if (tp->pt() <= 0.5e3) return false;
-              if (std::abs(aug.d0(*tp)) >= 3.5) return false;
-              if (std::abs(aug.z0SinTheta(*tp)) >= 5.0) return false;
-              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 8) return false;
-              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
-              if (pix_holes(*tp) > 1) return false;
-              return true;
-            }, data_deps
-          };
-        // R22_LOOSE is similar to R22_DEFAULT, but removes the shared module cut 
-        // and loosens the d0 cut
-        case TrackSelection::R22_LOOSE:
-          return {
-            [=](const Tp* tp) {
-              // from the track selector tool
-              if (std::abs(tp->eta()) > 2.5) return false;
-              if (tp->pt() <= 0.5e3) return false;
-              if (std::abs(aug.d0(*tp)) >= 5.0) return false;
-              if (std::abs(aug.z0SinTheta(*tp)) >= 5.0) return false;
-              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 8) return false;
-              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
-              if (pix_holes(*tp) > 1) return false;
-              return true;
-            }, data_deps
-          };
-        default:
-          throw std::logic_error("unknown track selection function");
-        }
-      }
-
-      // factory for functions that build std::vector objects from
-      // track sequences
-      std::pair<SeqFromTracks,std::set<std::string>> seqFromTracks(
-        const FTagTrackInputConfig& cfg, const FTagOptions& options)
-      {
-        const std::string prefix = options.track_prefix;
-        switch (cfg.type) {
-          case EDMType::INT: return {
-              SequenceGetter<int>(cfg.name), {cfg.name}
-            };
-          case EDMType::FLOAT: return {
-              SequenceGetter<float>(cfg.name), {cfg.name}
-            };
-          case EDMType::CHAR: return {
-              SequenceGetter<char>(cfg.name), {cfg.name}
-            };
-          case EDMType::UCHAR: return {
-              SequenceGetter<unsigned char>(cfg.name), {cfg.name}
-            };
-          case EDMType::CUSTOM_GETTER: {
-            return customNamedSeqGetterWithDeps(
-              cfg.name, options.track_prefix);
-
-          }
-          default: {
-            throw std::logic_error("Unknown EDM type for tracks");
-          }
-        }
-      }
-
-      // here we define filters for the "flip" taggers
-      //
-      // start by defining the raw functions, there's a factory
-      // function below to convert the configuration enums to a
-      // std::function
-      Tracks negativeIpOnly(BTagTrackIpAccessor& aug,
-                            const Tracks& tracks,
-                            const xAOD::Jet& j) {
-        Tracks filtered;
-        // we want to reverse the order of the tracks as part of the
-        // flipping
-        for (auto ti = tracks.crbegin(); ti != tracks.crend(); ti++) {
-          const xAOD::TrackParticle* tp = *ti;
-          double sip = aug.getSignedIp(*tp, j).ip3d_signed_d0_significance;
-          if (sip < 0) filtered.push_back(tp);
-        }
-        return filtered;
-      }
-
-      // factory function
-      std::pair<TrackSequenceFilter,std::set<std::string>> flipFilter(
-        const FTagOptions& options)
-      {
-        namespace ph = std::placeholders;  // for _1, _2, _3
-        BTagTrackIpAccessor aug(options.track_prefix);
-        switch(options.flip) {
-        case FlipTagConfig::NEGATIVE_IP_ONLY:
-          // flips order and removes tracks with negative IP
-          return {
-            std::bind(&negativeIpOnly, aug, ph::_1, ph::_2),
-            aug.getTrackIpDataDependencyNames()
-          };
-        case FlipTagConfig::FLIP_SIGN:
-          // Just flips the order
-          return {
-            [](const Tracks& tr, const xAOD::Jet& ) {
-              return Tracks(tr.crbegin(), tr.crend());},
-            {}
-          };
-        case FlipTagConfig::SIMPLE_FLIP:
-          // Just flips the order
-          return {
-            [](const Tracks& tr, const xAOD::Jet& ) {
-              return Tracks(tr.crbegin(), tr.crend());},
-            {}
-          };
-        case FlipTagConfig::STANDARD:
-          return {[](const Tracks& tr, const xAOD::Jet& ) { return tr; }, {}};
-        default: {
-          throw std::logic_error("Unknown flip config");
-        }
-        }
-      }
     } // end of get namespace
   } // end of internal namespace
 
@@ -633,7 +230,7 @@ namespace FlavorTagDiscriminants {
     //
     std::tuple<
       std::vector<FTagInputConfig>,
-      std::vector<FTagTrackSequenceConfig>,
+      std::vector<ConstituentsInputConfig>,
       FTagOptions>
     createGetterConfig( lwt::GraphConfig& config,
       FlipTagConfig flip_config,
@@ -641,19 +238,9 @@ namespace FlavorTagDiscriminants {
       TrackLinkType track_link_type
     ){
 
-      // get the regex to rewrite the inputs if we're using flip taggers
+      // we rewrite the inputs if we're using flip taggers
       StringRegexes flip_converters = getNameFlippers(flip_config);
 
-      // some sequences also need to be sign-flipped. We apply this by
-      // changing the input scaling and normalizations
-      std::regex flip_sequences;
-      if (flip_config == FlipTagConfig::FLIP_SIGN || flip_config == FlipTagConfig::NEGATIVE_IP_ONLY){
-        flip_sequences=std::regex(".*signed_[dz]0.*");
-      }
-      if (flip_config == FlipTagConfig::SIMPLE_FLIP){
-        flip_sequences=std::regex("(.*signed_[dz]0.*)|d0|z0SinTheta");
-      }
-
       if (flip_config != FlipTagConfig::STANDARD) {
         rewriteFlipConfig(config, flip_converters);
       }
@@ -716,9 +303,9 @@ namespace FlavorTagDiscriminants {
         input_names, type_regexes, default_flag_regexes);
       }
 
-      // build the track inputs
+      // build the constituents inputs
 
-      std::vector<std::pair<std::string, std::vector<std::string> > > trk_names;
+      std::vector<std::pair<std::string, std::vector<std::string>>> constituent_names;
       for (auto& node: config.input_sequences) {
         remap_inputs(node.variables, remap_scalar,
 		     node.defaults);
@@ -727,52 +314,18 @@ namespace FlavorTagDiscriminants {
         for (const auto& var: node.variables) {
           names.push_back(var.name);
         }
-        trk_names.emplace_back(node.name, names);
+        constituent_names.emplace_back(node.name, names);
       }
 
-      TypeRegexes trk_type_regexes {
-        // Some innermost / next-to-innermost hit variables had a different
-        // definition in 21p9, recomputed here with customGetter to reuse
-        // existing training
-        // EDMType picked correspond to the first matching regex
-        {"numberOf.*21p9"_r, EDMType::CUSTOM_GETTER},
-        {"numberOf.*"_r, EDMType::UCHAR},
-        {"btagIp_(d0|z0SinTheta)Uncertainty"_r, EDMType::FLOAT},
-        {"(numberDoF|chiSquared|qOverP|theta)"_r, EDMType::FLOAT},
-        {"(^.*[_])?(d|z)0.*"_r, EDMType::CUSTOM_GETTER},
-        {"(log_)?(ptfrac|dr|pt).*"_r, EDMType::CUSTOM_GETTER},
-        {"(deta|dphi)"_r, EDMType::CUSTOM_GETTER},
-        {"phi|theta|qOverP"_r, EDMType::FLOAT},
-        {"(phi|theta|qOverP)Uncertainty"_r, EDMType::CUSTOM_GETTER},
-        {"leptonID"_r, EDMType::CHAR}
-      };
-      // We have a number of special naming conventions to sort and
-      // filter tracks. The track nodes should be named according to
-      //
-      // tracks_<selection>_<sort-order>
-      //
-      SortRegexes trk_sort_regexes {
-        {".*absSd0sort"_r, SortOrder::ABS_D0_SIGNIFICANCE_DESCENDING},
-        {".*sd0sort"_r, SortOrder::D0_SIGNIFICANCE_DESCENDING},
-        {".*ptsort"_r, SortOrder::PT_DESCENDING},
-        {".*absD0DescendingSort"_r, SortOrder::ABS_D0_DESCENDING},
-      };
-      TrkSelRegexes trk_select_regexes {
-        {".*_ip3d_.*"_r, TrackSelection::IP3D_2018},
-        {".*_dipsTightUpgrade_.*"_r, TrackSelection::DIPS_TIGHT_UPGRADE},
-        {".*_dipsLooseUpgrade_.*"_r, TrackSelection::DIPS_LOOSE_UPGRADE},
-        {".*_all_.*"_r, TrackSelection::ALL},
-        {".*_dipsLoose202102_.*"_r, TrackSelection::DIPS_LOOSE_202102},
-        {".*_loose202102NoIpCuts_.*"_r, TrackSelection::LOOSE_202102_NOIP},
-        {".*_r22default_.*"_r, TrackSelection::R22_DEFAULT},
-        {".*_r22loose_.*"_r, TrackSelection::R22_LOOSE},
-      };
-
-      auto trk_config = get_track_input_config(
-        trk_names, trk_type_regexes, trk_sort_regexes, trk_select_regexes,flip_sequences,flip_config);
+      std::vector<ConstituentsInputConfig> constituent_configs;
+      for (auto el: constituent_names){
+        constituent_configs.push_back(
+          createConstituentsLoaderConfig(el.first, el.second, flip_config));
+      }
 
       // some additional options
       FTagOptions options;
+      
       if (auto h = remap_scalar.extract(options.track_prefix)) {
         options.track_prefix = h.mapped();
       }
@@ -785,9 +338,8 @@ namespace FlavorTagDiscriminants {
       options.flip = flip_config;
       options.remap_scalar = remap_scalar;
       options.track_link_type = track_link_type;
-      return std::make_tuple(input_config, trk_config, options);
-    } // end of getGetterConfig
-
+      return std::make_tuple(input_config, constituent_configs, options);
+    }
 
     // Translate configuration to getter functions
     //
@@ -811,7 +363,7 @@ namespace FlavorTagDiscriminants {
           deps.bTagInputs.insert(input.name);
           varsFromBTag.push_back(filler);
         } else {
-          varsFromJet.push_back(internal::customGetterAndName(input.name));
+          varsFromJet.push_back(getter_utils::customGetterAndName(input.name));
         }
         if (input.default_flag.size() > 0) {
           deps.bTagInputs.insert(input.default_flag);
@@ -822,63 +374,6 @@ namespace FlavorTagDiscriminants {
     }
 
 
-    // Translate configuration to track getters
-    //
-    // This focuses on the track inputs, i.e. the inputs for dips, the
-    // code for the track inputs is above.
-    std::tuple<
-      std::vector<internal::TrackSequenceBuilder>,
-      FTagDataDependencyNames,
-      std::set<std::string>>
-    createTrackGetters(
-      const std::vector<FTagTrackSequenceConfig>& track_sequences,
-      const FTagOptions& options)
-    {
-      FTagDataDependencyNames deps;
-      std::vector<internal::TrackSequenceBuilder> trackSequenceBuilders;
-      std::map<std::string, std::string> remap = options.remap_scalar;
-      std::set<std::string> used_remap;
-
-      for (const FTagTrackSequenceConfig& cfg: track_sequences) {
-        internal::TrackSequenceBuilder track_getter(
-          cfg.order, cfg.selection, options);
-        // add the tracking data dependencies
-        auto track_data_deps = internal::get::trackFilter(
-          cfg.selection, options).second;
-        track_data_deps.merge(internal::get::flipFilter(options).second);
-
-        track_getter.name = cfg.name;
-        for (const FTagTrackInputConfig& input_cfg: cfg.inputs) {
-          auto [seqGetter, deps] = internal::get::seqFromTracks(
-            input_cfg, options);
-
-          if(input_cfg.flip_sign){
-            auto seqGetter_flip=[g=seqGetter](const xAOD::Jet&jet, const internal::Tracks& trks){
-              auto [n,v] = g(jet,trks);
-              std::for_each(v.begin(), v.end(), [](double &n){ n=-1.0*n; });
-              return std::make_pair(n,v);
-            };
-            track_getter.sequencesFromTracks.push_back(seqGetter_flip);
-          }
-          else{
-            track_getter.sequencesFromTracks.push_back(seqGetter);
-          }
-          track_data_deps.merge(deps);
-
-	  if (auto h = remap.extract(input_cfg.name)){
-            used_remap.insert(h.key());
-          }
-
-        }
-        trackSequenceBuilders.push_back(track_getter);
-        deps.trackInputs.merge(track_data_deps);
-        deps.bTagInputs.insert(options.track_link_name);
-      }
-
-      return std::make_tuple(trackSequenceBuilders, deps, used_remap);
-    }
-
-
     // Translate configuration to setter functions
     //
     // This returns the "decorators" that we use to save outputs to
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/GNN.cxx b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/GNN.cxx
index e1ba8c3ad28a8ac62cf253c20a15cb368d893703..9aadb5352a697a3827f987599164cc6b262dfd01 100644
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/GNN.cxx
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/GNN.cxx
@@ -50,20 +50,32 @@ namespace FlavorTagDiscriminants {
     auto lwt_config = m_onnxUtil->getLwtConfig();
 
     // Create configuration objects for data preprocessing.
-    auto [inputs, track_sequences, options] = dataprep::createGetterConfig(
+    auto [inputs, constituents_configs, options] = dataprep::createGetterConfig(
         lwt_config, o.flip_config, o.variable_remapping, o.track_link_type);
+    
+    int n_track_sequences = 0;
+    for (auto config : constituents_configs){
+      switch (config.type){
+      case ConstituentsType::TRACK:
+        m_constituentsLoaders.push_back(std::make_shared<TracksLoader>(config, options));
+        n_track_sequences++;
+        break;
+      case ConstituentsType::IPARTICLE:
+        m_constituentsLoaders.push_back(std::make_shared<IParticlesLoader>(config, options));
+        break;
+      }
+    }
 
+    if ((n_track_sequences != 1) && m_decorate_tracks){
+      throw std::runtime_error("Only one track sequence is supported when decorating tracks.");
+    }
+    
     // Initialize jet and b-tagging input getters.
     auto [vb, vj, ds] = dataprep::createBvarGetters(inputs);
     m_varsFromBTag = vb;
     m_varsFromJet = vj;
     m_dataDependencyNames = ds;
 
-    // Initialize track input getters.
-    auto [tsb, td, rt] = dataprep::createTrackGetters(track_sequences, options);
-    m_trackSequenceBuilders = tsb;
-    m_dataDependencyNames += td;
-
     // Retrieve the configuration for the model outputs.
     OnnxUtil::OutputConfig gnn_output_config = m_onnxUtil->getOutputConfig();
 
@@ -71,8 +83,11 @@ namespace FlavorTagDiscriminants {
     auto [dd, rd] = createDecorators(gnn_output_config, options);
     m_dataDependencyNames += dd;
 
-    // Check that all remaps have been used.
-    rd.merge(rt);
+    // Update dependencies and used remap from the constituents loaders.
+    for (auto loader : m_constituentsLoaders){
+      m_dataDependencyNames += loader->getDependencies();
+      rd.merge(loader->getUsedRemap());
+    }
     dataprep::checkForUnusedRemaps(options.remap_scalar, rd);
   }
 
@@ -130,42 +145,17 @@ namespace FlavorTagDiscriminants {
     input_pair jet_info (jet_feat, jet_feat_dim);
     gnn_input.insert({"jet_features", jet_info});
 
-    // Only one track sequence is allowed because the tracks are declared
-    // outside the loop over sequences.
-    // Having more than one sequence would overwrite them.
-    // These are only used outside the loop to write the track links.
-    if (m_trackSequenceBuilders.size() > 1) {
-      throw std::runtime_error("Only one track sequence is supported");
-    }
     Tracks input_tracks;
-    for (const auto& builder: m_trackSequenceBuilders) {
-      std::vector<float> track_feat; // (#tracks, #feats).flatten
-      int num_track_vars = static_cast<int>(builder.sequencesFromTracks.size());
-      int num_tracks = 0;
 
-      Tracks sorted_tracks = builder.tracksFromJet(jet, btag);
-      input_tracks = builder.flipFilter(sorted_tracks, jet);
-
-      int track_var_idx=0;
-      for (const auto& seq_builder: builder.sequencesFromTracks) {
-        auto double_vec = seq_builder(jet, input_tracks).second;
-
-        if (track_var_idx==0){
-          num_tracks = static_cast<int>(double_vec.size());
-          track_feat.resize(num_tracks * num_track_vars);
+    for (auto loader : m_constituentsLoaders){
+      auto [sequence_name, sequence_data, sequence_constituents] = loader->getData(jet, btag);
+      gnn_input.insert({sequence_name, sequence_data});
+      // collect tracks for decoration
+      if ((loader->getType() == ConstituentsType::TRACK) && m_decorate_tracks){
+        for (auto constituent : sequence_constituents){
+          input_tracks.push_back(dynamic_cast<const xAOD::TrackParticle*>(constituent));
         }
-
-        // need to transpose + flatten
-        for (unsigned int track_idx=0; track_idx<double_vec.size(); track_idx++){
-          track_feat.at(track_idx*num_track_vars + track_var_idx)
-            = double_vec.at(track_idx);
-        }
-        track_var_idx++;
       }
-      std::vector<int64_t> track_feat_dim = {num_tracks, num_track_vars};
-
-      input_pair track_info (track_feat, track_feat_dim);
-      gnn_input.insert({"track_features", track_info});
     }
 
     // run inference
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/IParticlesLoader.cxx b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/IParticlesLoader.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..725e8b3c27f410fc107a71b78dc317657f0ec6ce
--- /dev/null
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/IParticlesLoader.cxx
@@ -0,0 +1,111 @@
+/*
+Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FlavorTagDiscriminants/IParticlesLoader.h"
+#include "xAODPFlow/FlowElement.h"
+#include "FlavorTagDiscriminants/StringUtils.h"
+
+namespace FlavorTagDiscriminants {
+    
+    // factory for functions which return the sort variable we
+    // use to order iparticles
+    IParticlesLoader::IParticleSortVar IParticlesLoader::iparticleSortVar(
+        ConstituentsSortOrder config) 
+    {
+      typedef xAOD::IParticle Ip;
+      typedef xAOD::Jet Jet;
+      switch(config) {
+        case ConstituentsSortOrder::PT_DESCENDING:
+          return [](const Ip* tp, const Jet&) {return tp->pt();};
+        default: {
+          throw std::logic_error("Unknown sort function");
+        }
+      }
+    } // end of iparticle sort getter
+
+    IParticlesLoader::IParticlesLoader(
+        ConstituentsInputConfig cfg,
+        const FTagOptions& options
+    ):
+        IConstituentsLoader(cfg),
+        m_iparticleSortVar(IParticlesLoader::iparticleSortVar(cfg.order)),
+        m_customSequenceGetter(getter_utils::CustomSequenceGetter<xAOD::IParticle>(
+          cfg.inputs, options))
+    {
+        SG::AuxElement::ConstAccessor<PartLinks> acc("constituentLinks");
+        m_associator = [acc](const xAOD::Jet& jet) -> IPV {
+          IPV particles;
+          for (const ElementLink<IPC>& link : acc(jet)){
+            if (!link.isValid()) {
+              throw std::logic_error("invalid particle link");
+            }
+            particles.push_back(*link);
+          }
+          return particles;
+        };
+
+        if (cfg.name.find("charged") != std::string::npos){
+            m_isCharged = true;
+        } else {
+            m_isCharged = false;
+        }
+        m_used_remap = m_customSequenceGetter.getUsedRemap();
+        m_name = cfg.name;
+    }
+
+    std::vector<const xAOD::IParticle*> IParticlesLoader::getIParticlesFromJet(
+        const xAOD::Jet& jet
+    ) const
+    {
+        std::vector<std::pair<double, const xAOD::IParticle*>> particles;
+        for (const xAOD::IParticle *tp : m_associator(jet)) {
+          particles.push_back({m_iparticleSortVar(tp, jet), tp});
+        }
+        std::sort(particles.begin(), particles.end(), std::greater<>());
+        std::vector<const xAOD::IParticle*> only_particles;
+        for (const auto& particle: particles) {
+          auto* flow = dynamic_cast<const xAOD::FlowElement*>(particle.second);
+          const xAOD::IParticle* obj = nullptr;
+          if (!flow){
+            throw std::runtime_error("IParticlesLoader: Dynamic cast to FlowElement failed");
+          }
+          if ((flow->isCharged() != m_isCharged)) continue;
+          else {
+            if (m_isCharged){
+              obj = flow->chargedObject(0);
+            }
+            else{
+              obj = flow;
+            }
+          }
+          if (!obj){
+            continue;
+          }
+          only_particles.push_back(obj);
+        }
+        return only_particles;
+    }
+
+    std::tuple<std::string, input_pair, std::vector<const xAOD::IParticle*>> IParticlesLoader::getData(
+      const xAOD::Jet& jet, 
+      [[maybe_unused]] const SG::AuxElement& btag) const {
+        IParticles sorted_particles = getIParticlesFromJet(jet);
+
+        return std::make_tuple(m_config.output_name, m_customSequenceGetter.getFeats(jet, sorted_particles), sorted_particles);
+    }
+
+    FTagDataDependencyNames IParticlesLoader::getDependencies() const {
+        return m_deps;
+    }
+    std::set<std::string> IParticlesLoader::getUsedRemap() const {
+        return m_used_remap;
+    }
+    std::string IParticlesLoader::getName() const {
+        return m_name;
+    }
+    ConstituentsType IParticlesLoader::getType() const {
+        return m_config.type;
+    }
+
+}
\ No newline at end of file
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/TracksLoader.cxx b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/TracksLoader.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..05a406b655af5cf52d0a96eb5d05326913323f40
--- /dev/null
+++ b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/TracksLoader.cxx
@@ -0,0 +1,387 @@
+/*
+Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "FlavorTagDiscriminants/FlipTagEnums.h"
+#include "FlavorTagDiscriminants/AssociationEnums.h"
+#include "FlavorTagDiscriminants/TracksLoader.h"
+#include "FlavorTagDiscriminants/StringUtils.h"
+
+namespace FlavorTagDiscriminants {
+
+    // factory for functions which return the sort variable we
+    // use to order tracks
+    TracksLoader::TrackSortVar TracksLoader::trackSortVar(
+        ConstituentsSortOrder config, 
+        const FTagOptions& options) 
+    {
+      typedef xAOD::TrackParticle Tp;
+      typedef xAOD::Jet Jet;
+      BTagTrackIpAccessor aug(options.track_prefix);
+      switch(config) {
+        case ConstituentsSortOrder::ABS_D0_SIGNIFICANCE_DESCENDING:
+          return [aug](const Tp* tp, const Jet&) {
+            return std::abs(aug.d0(*tp) / aug.d0Uncertainty(*tp));
+          };
+        case ConstituentsSortOrder::D0_SIGNIFICANCE_DESCENDING:
+          return [aug](const Tp* tp, const Jet& j) {
+            return aug.getSignedIp(*tp, j).ip3d_signed_d0_significance;
+          };
+        case ConstituentsSortOrder::PT_DESCENDING:
+          return [](const Tp* tp, const Jet&) {return tp->pt();};
+        case ConstituentsSortOrder::ABS_D0_DESCENDING:
+          return [aug](const Tp* tp, const Jet&) {
+            return std::abs(aug.d0(*tp));
+          };
+
+        default: {
+          throw std::logic_error("Unknown sort function");
+        }
+      }
+    } // end of track sort getter
+
+    // factory for functions that return true for tracks we want to
+    // use, false for those we don't want
+    std::pair<TracksLoader::TrackFilter,std::set<std::string>> TracksLoader::trackFilter(
+        ConstituentsSelection config, 
+        const FTagOptions& options) 
+    {
+
+        typedef xAOD::TrackParticle Tp;
+        typedef SG::AuxElement AE;
+        BTagTrackIpAccessor aug(options.track_prefix);
+        auto data_deps = aug.getTrackIpDataDependencyNames();
+
+        // make sure we record accessors as data dependencies
+        std::set<std::string> track_deps;
+        auto addAccessor = [&track_deps](const std::string& n) {
+                             AE::ConstAccessor<unsigned char> a(n);
+                             track_deps.insert(n);
+                             return a;
+                           };
+        auto pix_hits = addAccessor("numberOfPixelHits");
+        auto pix_holes = addAccessor("numberOfPixelHoles");
+        auto pix_shared = addAccessor("numberOfPixelSharedHits");
+        auto pix_dead = addAccessor("numberOfPixelDeadSensors");
+        auto sct_hits = addAccessor("numberOfSCTHits");
+        auto sct_holes = addAccessor("numberOfSCTHoles");
+        auto sct_shared = addAccessor("numberOfSCTSharedHits");
+        auto sct_dead = addAccessor("numberOfSCTDeadSensors");
+
+        // data deps is all possible dependencies. We insert here to
+        // avoid removing them from track_deps (as merge would).
+        data_deps.insert(track_deps.begin(), track_deps.end());
+
+        switch (config) {
+        case ConstituentsSelection::ALL: return {[](const Tp*) {return true;}, {} };
+          // the following numbers come from Nicole, Dec 2018:
+          // pt > 1 GeV
+          // abs(d0) < 1 mm
+          // abs(z0 sin(theta)) < 1.5 mm
+          // >= 7 si hits
+          // <= 2 si holes
+          // <= 1 pix holes
+        case ConstituentsSelection::IP3D_2018:
+          return {
+            [=](const Tp* tp) {
+              // from the track selector tool
+              if (std::abs(tp->eta()) > 2.5) return false;
+              double n_module_shared = (pix_shared(*tp) + sct_shared(*tp) / 2);
+              if (n_module_shared > 1) return false;
+              if (tp->pt() <= 1e3) return false;
+              if (std::abs(aug.d0(*tp)) >= 1.0) return false;
+              if (std::abs(aug.z0SinTheta(*tp)) >= 1.5) return false;
+              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 7) return false;
+              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
+              if (pix_holes(*tp) > 1) return false;
+              return true;
+            }, data_deps
+          };
+          // Tight track selection for DIPS upgrade config
+          // abs(eta) < 4 
+          // pt > 1 GeV
+          // abs(d0) < 1 mm
+          // abs(z0 sin(theta)) < 1.5 mm
+          // No cuts for si hits, si holes and pix holes - only reconstruction selection is applied
+        case ConstituentsSelection::DIPS_TIGHT_UPGRADE:
+          return {
+            [=](const Tp* tp) {
+              // from the track selector tool
+              if (std::abs(tp->eta()) > 4.0) return false;
+              if (tp->pt() <= 1e3) return false;
+              if (std::abs(aug.d0(*tp)) >= 1.0) return false;
+              if (std::abs(aug.z0SinTheta(*tp)) >= 1.5) return false;
+              return true;
+            }, data_deps
+          };
+          // Loose track selection for DIPS upgrade config
+          // abs(eta) < 4
+          // pt > 0.5 GeV
+          // abs(d0) < 3.5 mm
+          // abs(z0 sin(theta)) < 5.0 mm
+          // No cuts for si hits, si holes and pix holes - only reconstruction selection is applied
+        case ConstituentsSelection::DIPS_LOOSE_UPGRADE:
+          return {
+            [=](const Tp* tp) {
+              // from the track selector tool
+              if (std::abs(tp->eta()) > 4.0) return false;
+              if (tp->pt() <= 0.5e3) return false;
+              if (std::abs(aug.d0(*tp)) >= 3.5) return false;
+              if (std::abs(aug.z0SinTheta(*tp)) >= 5.0) return false;
+              return true;
+            }, data_deps
+          };
+          // Loose track selection for DIPS
+          // pt > 0.5 GeV
+          // abs(d0) < 3.5 mm
+          // abs(z0 sin(theta)) < 5.0 mm
+          // >= 7 si hits
+          // <= 2 si holes
+          // <= 1 pix holes
+        case ConstituentsSelection::DIPS_LOOSE_202102:
+          return {
+            [=](const Tp* tp) {
+              // from the track selector tool
+              if (std::abs(tp->eta()) > 2.5) return false;
+              double n_module_shared = (pix_shared(*tp) + sct_shared(*tp) / 2);
+              if (n_module_shared > 1) return false;
+              if (tp->pt() <= 0.5e3) return false;
+              if (std::abs(aug.d0(*tp)) >= 3.5) return false;
+              if (std::abs(aug.z0SinTheta(*tp)) >= 5.0) return false;
+              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 7) return false;
+              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
+              if (pix_holes(*tp) > 1) return false;
+              return true;
+            }, data_deps
+          };
+        case ConstituentsSelection::LOOSE_202102_NOIP:
+          return {
+            [=](const Tp* tp) {
+              if (std::abs(tp->eta()) > 2.5) return false;
+              double n_module_shared = (pix_shared(*tp) + sct_shared(*tp) / 2);
+              if (n_module_shared > 1) return false;
+              if (tp->pt() <= 0.5e3) return false;
+              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 7) return false;
+              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
+              if (pix_holes(*tp) > 1) return false;
+              return true;
+            }, track_deps
+          };
+        // R22_DEFAULT is similar to DIPS_LOOSE_202102, but modifies the min Si hit cut to 8,
+        // which is the default tracking CP recommendation for r22, see
+        // https://twiki.cern.ch/twiki/bin/view/AtlasProtected/TrackingCPRecsRun2R22#Selection_Criteria
+        case ConstituentsSelection::R22_DEFAULT:
+          return {
+            [=](const Tp* tp) {
+              // from the track selector tool
+              if (std::abs(tp->eta()) > 2.5) return false;
+              double n_module_shared = (pix_shared(*tp) + sct_shared(*tp) / 2);
+              if (n_module_shared > 1) return false;
+              if (tp->pt() <= 0.5e3) return false;
+              if (std::abs(aug.d0(*tp)) >= 3.5) return false;
+              if (std::abs(aug.z0SinTheta(*tp)) >= 5.0) return false;
+              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 8) return false;
+              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
+              if (pix_holes(*tp) > 1) return false;
+              return true;
+            }, data_deps
+          };
+        // R22_LOOSE is similar to R22_DEFAULT, but removes the shared module cut 
+        // and loosens the d0 cut
+        case ConstituentsSelection::R22_LOOSE:
+          return {
+            [=](const Tp* tp) {
+              // from the track selector tool
+              if (std::abs(tp->eta()) > 2.5) return false;
+              if (tp->pt() <= 0.5e3) return false;
+              if (std::abs(aug.d0(*tp)) >= 5.0) return false;
+              if (std::abs(aug.z0SinTheta(*tp)) >= 5.0) return false;
+              if (pix_hits(*tp) + pix_dead(*tp) + sct_hits(*tp) + sct_dead(*tp) < 8) return false;
+              if ((pix_holes(*tp) + sct_holes(*tp)) > 2) return false;
+              if (pix_holes(*tp) > 1) return false;
+              return true;
+            }, data_deps
+          };
+        default:
+          throw std::logic_error("unknown track selection function");
+        }
+    }
+
+    // here we define filters for the "flip" taggers
+    //
+    // start by defining the raw functions, there's a factory
+    // function below to convert the configuration enums to a
+    // std::function
+    std::vector<const xAOD::TrackParticle*> negativeIpOnly(
+        BTagTrackIpAccessor& aug,
+        const std::vector<const xAOD::TrackParticle*>& tracks,
+        const xAOD::Jet& j) 
+    {
+        std::vector<const xAOD::TrackParticle*> filtered;
+        // we want to reverse the order of the tracks as part of the
+        // flipping
+        for (auto ti = tracks.crbegin(); ti != tracks.crend(); ti++) {
+          const xAOD::TrackParticle* tp = *ti;
+          double sip = aug.getSignedIp(*tp, j).ip3d_signed_d0_significance;
+          if (sip < 0) filtered.push_back(tp);
+        }
+        return filtered;
+      }
+
+    // factory function
+    std::pair<TracksLoader::TrackSequenceFilter,std::set<std::string>> TracksLoader::flipFilter(
+        const FTagOptions& options)
+    {
+        namespace ph = std::placeholders;  // for _1, _2, _3
+        BTagTrackIpAccessor aug(options.track_prefix);
+        switch(options.flip) {
+        case FlipTagConfig::NEGATIVE_IP_ONLY:
+          // flips order and removes tracks with negative IP
+          return {
+            std::bind(&negativeIpOnly, aug, ph::_1, ph::_2),
+            aug.getTrackIpDataDependencyNames()
+          };
+        case FlipTagConfig::FLIP_SIGN:
+          // Just flips the order
+          return {
+            [](const Tracks& tr, const xAOD::Jet& ) {
+              return Tracks(tr.crbegin(), tr.crend());},
+            {}
+          };
+        case FlipTagConfig::SIMPLE_FLIP:
+          // Just flips the order
+          return {
+            [](const Tracks& tr, const xAOD::Jet& ) {
+              return Tracks(tr.crbegin(), tr.crend());},
+            {}
+          };
+
+        case FlipTagConfig::STANDARD:
+          return {[](const Tracks& tr, const xAOD::Jet& ) { return tr; }, {}};
+        default: {
+          throw std::logic_error("Unknown flip config");
+        }
+        }
+    }
+
+    TracksLoader::TracksLoader(
+        ConstituentsInputConfig cfg,
+        const FTagOptions& options
+    ):
+        IConstituentsLoader(cfg),
+        m_trackSortVar(TracksLoader::trackSortVar(cfg.order, options)),
+        m_trackFilter(TracksLoader::trackFilter(cfg.selection, options).first),
+        m_flipFilter(TracksLoader::flipFilter(options).first),
+        m_customSequenceGetter(getter_utils::CustomSequenceGetter<xAOD::TrackParticle>(
+          cfg.inputs, options))
+    {
+        // We have several ways to get tracks: either we retrieve an
+        // IParticleContainer and cast the pointers to TrackParticle, or
+        // we retrieve a TrackParticleContainer directly. Unfortunately
+        // the way tracks are stored isn't consistent across the EDM, so
+        // we allow configuration for both setups.
+        //
+        if (options.track_link_type == TrackLinkType::IPARTICLE) {
+            SG::AuxElement::ConstAccessor<PartLinks> acc(options.track_link_name);
+            m_associator = [acc](const SG::AuxElement& btag) -> TPV {
+            TPV tracks;
+            for (const ElementLink<IPC>& link: acc(btag)) {
+                if (!link.isValid()) {
+                throw std::logic_error("invalid particle link");
+                }
+                const auto* trk = dynamic_cast<const xAOD::TrackParticle*>(*link);
+                if (!trk) {
+                throw std::logic_error("iparticle does not cast to Track");
+                }
+                tracks.push_back(trk);
+            }
+            return tracks;
+            };
+        } else if (options.track_link_type == TrackLinkType::TRACK_PARTICLE){
+            SG::AuxElement::ConstAccessor<TrackLinks> acc(options.track_link_name);
+            m_associator = [acc](const SG::AuxElement& btag) -> TPV {
+            TPV tracks;
+            for (const ElementLink<TPC>& link: acc(btag)) {
+                if (!link.isValid()) {
+                throw std::logic_error("invalid track link");
+                }
+                tracks.push_back(*link);
+            }
+            return tracks;
+            };
+        } else {
+            throw std::logic_error("Unknown TrackLinkType");
+        }
+        auto track_data_deps = trackFilter(cfg.selection, options).second;
+        track_data_deps.merge(flipFilter(options).second);
+        track_data_deps.merge(m_customSequenceGetter.getDependencies());
+        m_deps.trackInputs.merge(track_data_deps);
+        m_deps.bTagInputs.insert(options.track_link_name);
+        m_used_remap = m_customSequenceGetter.getUsedRemap();
+        m_name = cfg.name;
+    }
+
+    std::vector<const xAOD::TrackParticle*> TracksLoader::getTracksFromJet(
+        const xAOD::Jet& jet,
+        const SG::AuxElement& btag) const
+    {
+        std::vector<std::pair<double, const Track*>> tracks;
+        for (const Track *tp : m_associator(btag)) {
+            if (m_trackFilter(tp)) {
+                tracks.push_back({m_trackSortVar(tp, jet), tp});
+            };
+        }
+        std::sort(tracks.begin(), tracks.end(), std::greater<>());
+        std::vector<const Track*> only_tracks;
+        only_tracks.reserve(tracks.size());
+        for (const auto& trk: tracks) {
+            only_tracks.push_back(trk.second);
+        }
+        return only_tracks;
+    }
+
+    std::tuple<std::string, input_pair, std::vector<const xAOD::IParticle*>> TracksLoader::getData(
+      const xAOD::Jet& jet, 
+      [[maybe_unused]] const SG::AuxElement& btag) const {
+        Tracks flipped_tracks;
+        Tracks sorted_tracks = getTracksFromJet(jet, btag);
+        std::vector<const xAOD::IParticle*> flipped_tracks_ip;
+
+        flipped_tracks = m_flipFilter(sorted_tracks, jet);
+        
+        for (const auto& trk: flipped_tracks) {
+            flipped_tracks_ip.push_back(trk);
+        }
+
+        return std::make_tuple(m_config.output_name, m_customSequenceGetter.getFeats(jet, flipped_tracks), flipped_tracks_ip);
+    }
+
+    std::tuple<char, std::map<std::string, std::vector<double>>> TracksLoader::getDL2Data(
+      const xAOD::Jet& jet, 
+      const SG::AuxElement& btag, 
+      std::function<char(const Tracks&)> ip_checker) const{
+      char invalid = 0;
+      Tracks flipped_tracks;
+      std::vector<const xAOD::IParticle*> flipped_tracks_ip;
+
+      Tracks sorted_tracks = getTracksFromJet(jet, btag);
+      if (ip_checker(sorted_tracks)) invalid = 1;
+      flipped_tracks = m_flipFilter(sorted_tracks, jet);
+      
+      auto feats = m_customSequenceGetter.getDL2Feats(jet, flipped_tracks);
+      return std::make_tuple(invalid, feats);
+    };
+
+    FTagDataDependencyNames TracksLoader::getDependencies() const {
+        return m_deps;
+    }
+    std::set<std::string> TracksLoader::getUsedRemap() const {
+        return m_used_remap;
+    }
+    std::string TracksLoader::getName() const {
+        return m_name;
+    }
+    ConstituentsType TracksLoader::getType() const {
+        return m_config.type;
+    }
+}
\ No newline at end of file
diff --git a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/customGetter.cxx b/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/customGetter.cxx
deleted file mode 100644
index 933b54e76ac71aa5c5886a523ef5f01a3e803ff8..0000000000000000000000000000000000000000
--- a/PhysicsAnalysis/JetTagging/FlavorTagDiscriminants/Root/customGetter.cxx
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
-*/
-#include "FlavorTagDiscriminants/customGetter.h"
-#include "FlavorTagDiscriminants/BTagTrackIpAccessor.h"
-
-#include "xAODJet/JetContainer.h"
-#include "xAODTracking/TrackParticle.h"
-
-#include <optional>
-
-namespace {
-  // ______________________________________________________________________
-  // Custom getters for jet-wise quantities
-  //
-  // this function is not at all optimized, but then it doesn't have
-  // to be since it should only be called in the initialization stage.
-  //
-  std::function<double(const xAOD::Jet&)> customGetter(
-    const std::string& name)
-  {
-    if (name == "pt") {
-      return [](const xAOD::Jet& j) -> float {return j.pt();};
-    }
-    if (name == "log_pt") {
-      return [](const xAOD::Jet& j) -> float {return std::log(j.pt());};
-    }
-    if (name == "eta") {
-      return [](const xAOD::Jet& j) -> float {return j.eta();};
-    }
-    if (name == "abs_eta") {
-      return [](const xAOD::Jet& j) -> float {return std::abs(j.eta());};
-    }
-    if (name == "energy") {
-      return [](const xAOD::Jet& j) -> float {return j.e();};
-    }
-    if (name == "mass") {
-      return [](const xAOD::Jet& j) -> float {return j.m();};
-    }
-
-    throw std::logic_error("no match for custom getter " + name);
-  }
-
-
-  // _______________________________________________________________________
-  // Custom getters for track variables
-
-  template <typename T>
-  class TJGetter
-  {
-  private:
-    T m_getter;
-  public:
-    TJGetter(T getter):
-      m_getter(getter)
-      {}
-    std::vector<double> operator()(
-      const xAOD::Jet& jet,
-      const std::vector<const xAOD::TrackParticle*>& tracks) const {
-      std::vector<double> sequence;
-      sequence.reserve(tracks.size());
-      for (const auto* track: tracks) {
-        sequence.push_back(m_getter(*track, jet));
-      }
-      return sequence;
-    }
-  };
-
-  std::optional<FlavorTagDiscriminants::SequenceFromTracks>
-  sequenceWithIpDep(
-    const std::string& name,
-    const std::string& prefix)
-  {
-
-    using Tp = xAOD::TrackParticle;
-    using Jet = xAOD::Jet;
-
-    BTagTrackIpAccessor a(prefix);
-    if (name == "IP3D_signed_d0_significance") {
-      return TJGetter([a](const Tp& t, const Jet& j){
-          return a.getSignedIp(t, j).ip3d_signed_d0_significance;
-      });
-    }
-    if (name == "IP3D_signed_z0_significance") {
-      return TJGetter([a](const Tp& t, const Jet& j){
-        return a.getSignedIp(t, j).ip3d_signed_z0_significance;
-      });
-    }
-    if (name == "IP2D_signed_d0") {
-      return TJGetter([a](const Tp& t, const Jet& j){
-        return a.getSignedIp(t, j).ip2d_signed_d0;
-      });
-    }
-    if (name == "IP3D_signed_d0") {
-      return TJGetter([a](const Tp& t, const Jet& j){
-        return a.getSignedIp(t, j).ip3d_signed_d0;
-      });
-    }
-    if (name == "IP3D_signed_z0") {
-      return TJGetter([a](const Tp& t, const Jet& j){
-        return a.getSignedIp(t, j).ip3d_signed_z0;
-      });
-    }
-    if (name == "d0" || name == "btagIp_d0") {
-      return TJGetter([a](const Tp& t, const Jet&){
-        return a.d0(t);
-      });
-    }
-    if (name == "z0SinTheta" || name == "btagIp_z0SinTheta") {
-      return TJGetter([a](const Tp& t, const Jet&){
-        return a.z0SinTheta(t);
-      });
-    }
-    if (name == "d0Uncertainty") {
-      return TJGetter([a](const Tp& t, const Jet&){
-        return a.d0Uncertainty(t);
-      });
-    }
-    if (name == "z0SinThetaUncertainty") {
-      return TJGetter([a](const Tp& t, const Jet&){
-        return a.z0SinThetaUncertainty(t);
-      });
-    }
-    return std::nullopt;
-  }
-
-  std::optional<FlavorTagDiscriminants::SequenceFromTracks>
-  sequenceNoIpDep(const std::string& name)
-  {
-
-    using Tp = xAOD::TrackParticle;
-    using Jet = xAOD::Jet;
-
-    if (name == "pt") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return t.pt();
-      });
-    }
-    if (name == "log_pt") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return std::log(t.pt());
-      });
-    }
-    if (name == "ptfrac") {
-      return TJGetter([](const Tp& t, const Jet& j) {
-        return t.pt() / j.pt();
-      });
-    }
-    if (name == "log_ptfrac") {
-      return TJGetter([](const Tp& t, const Jet& j) {
-        return std::log(t.pt() / j.pt());
-      });
-    }
-
-    if (name == "eta") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return t.eta();
-      });
-    }
-    if (name == "deta") {
-      return TJGetter([](const Tp& t, const Jet& j) {
-        return t.eta() - j.eta();
-      });
-    }
-    if (name == "abs_deta") {
-      return TJGetter([](const Tp& t, const Jet& j) {
-        return copysign(1.0, j.eta()) * (t.eta() - j.eta());
-      });
-    }
-
-    if (name == "phi") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return t.phi();
-      });
-    }
-    if (name == "dphi") {
-      return TJGetter([](const Tp& t, const Jet& j) {
-        return t.p4().DeltaPhi(j.p4());
-      });
-    }
-
-    if (name == "dr") {
-      return TJGetter([](const Tp& t, const Jet& j) {
-        return t.p4().DeltaR(j.p4());
-      });
-    }
-    if (name == "log_dr") {
-      return TJGetter([](const Tp& t, const Jet& j) {
-        return std::log(t.p4().DeltaR(j.p4()));
-      });
-    }
-    if (name == "log_dr_nansafe") {
-      return TJGetter([](const Tp& t, const Jet& j) {
-        return std::log(t.p4().DeltaR(j.p4()) + 1e-7);
-      });
-    }
-
-    if (name == "mass") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return t.m();
-      });
-    }
-    if (name == "energy") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return t.e();
-      });
-    }
-
-    if (name == "phiUncertainty") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return std::sqrt(t.definingParametersCovMatrixDiagVec().at(2));
-      });
-    }
-    if (name == "thetaUncertainty") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return std::sqrt(t.definingParametersCovMatrixDiagVec().at(3));
-      });
-    }
-    if (name == "qOverPUncertainty") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return std::sqrt(t.definingParametersCovMatrixDiagVec().at(4));
-      });
-    }
-    if (name == "z0RelativeToBeamspot") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return t.z0();
-      });
-    }
-    if (name == "log_z0RelativeToBeamspotUncertainty") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return std::log(std::sqrt(t.definingParametersCovMatrixDiagVec().at(1)));
-      });
-    }
-    if (name == "z0RelativeToBeamspotUncertainty") {
-      return TJGetter([](const Tp& t, const Jet&) {
-        return std::sqrt(t.definingParametersCovMatrixDiagVec().at(1));
-      });
-    }
-
-    if (name == "numberOfPixelHitsInclDead") {
-      SG::AuxElement::ConstAccessor<unsigned char> pix_hits("numberOfPixelHits");
-      SG::AuxElement::ConstAccessor<unsigned char> pix_dead("numberOfPixelDeadSensors");
-      return TJGetter([pix_hits, pix_dead](const Tp& t, const Jet&) {
-        return pix_hits(t) + pix_dead(t);
-      });
-    }
-    if (name == "numberOfSCTHitsInclDead") {
-      SG::AuxElement::ConstAccessor<unsigned char> sct_hits("numberOfSCTHits");
-      SG::AuxElement::ConstAccessor<unsigned char> sct_dead("numberOfSCTDeadSensors");
-      return TJGetter([sct_hits, sct_dead](const Tp& t, const Jet&) {
-        return sct_hits(t) + sct_dead(t);
-      });
-    }
-    if (name == "numberOfInnermostPixelLayerHits21p9") {
-      SG::AuxElement::ConstAccessor<unsigned char> barrel_hits("numberOfInnermostPixelLayerHits");
-      SG::AuxElement::ConstAccessor<unsigned char> endcap_hits("numberOfInnermostPixelLayerEndcapHits");
-      return TJGetter([barrel_hits, endcap_hits](const Tp& t, const Jet&) {
-        return barrel_hits(t) + endcap_hits(t);
-      });
-    }
-    if (name == "numberOfNextToInnermostPixelLayerHits21p9") {
-      SG::AuxElement::ConstAccessor<unsigned char> barrel_hits("numberOfNextToInnermostPixelLayerHits");
-      SG::AuxElement::ConstAccessor<unsigned char> endcap_hits("numberOfNextToInnermostPixelLayerEndcapHits");
-      return TJGetter([barrel_hits, endcap_hits](const Tp& t, const Jet&) {
-        return barrel_hits(t) + endcap_hits(t);
-      });
-    }
-    if (name == "numberOfInnermostPixelLayerSharedHits21p9") {
-      SG::AuxElement::ConstAccessor<unsigned char> barrel_hits("numberOfInnermostPixelLayerSharedHits");
-      SG::AuxElement::ConstAccessor<unsigned char> endcap_hits("numberOfInnermostPixelLayerSharedEndcapHits");
-      return TJGetter([barrel_hits, endcap_hits](const Tp& t, const Jet&) {
-        return barrel_hits(t) + endcap_hits(t);
-      });
-    }
-    if (name == "numberOfInnermostPixelLayerSplitHits21p9") {
-      SG::AuxElement::ConstAccessor<unsigned char> barrel_hits("numberOfInnermostPixelLayerSplitHits");
-      SG::AuxElement::ConstAccessor<unsigned char> endcap_hits("numberOfInnermostPixelLayerSplitEndcapHits");
-      return TJGetter([barrel_hits, endcap_hits](const Tp& t, const Jet&) {
-        return barrel_hits(t) + endcap_hits(t);
-      });
-    }
-
-
-    return std::nullopt;
-  }
-
-}
-
-namespace FlavorTagDiscriminants {
-  namespace internal {
-
-    // ________________________________________________________________
-    // Interface functions
-    //
-    // As long as we're giving lwtnn pair<name, double> objects, we
-    // can't use the raw getter functions above (which only return a
-    // double). Instead we'll wrap those functions in another function,
-    // which returns the pair we wanted.
-    //
-    // Case for jet variables
-    std::function<std::pair<std::string, double>(const xAOD::Jet&)>
-    customGetterAndName(const std::string& name) {
-      auto getter = customGetter(name);
-      return [name, getter](const xAOD::Jet& j) {
-               return std::make_pair(name, getter(j));
-             };
-    }
-
-    // Case for track variables
-    std::pair<std::function<std::pair<std::string, std::vector<double>>(
-      const xAOD::Jet&,
-      const std::vector<const xAOD::TrackParticle*>&)>,
-      std::set<std::string>>
-    customNamedSeqGetterWithDeps(const std::string& name,
-                                 const std::string& prefix) {
-      auto [getter, deps] = customSequenceGetterWithDeps(name, prefix);
-      return {
-        [n=name, g=getter](const xAOD::Jet& j,
-                       const std::vector<const xAOD::TrackParticle*>& t) {
-          return std::make_pair(n, g(j, t));
-        },
-        deps
-      };
-    }
-  }
-  // ________________________________________________________________________
-  // Master track getter list
-  //
-  // These functions are wrapped by the customNamedSeqGetter function
-  // below to become the ones that are actually used in DL2.
-  //
-  std::pair<SequenceFromTracks, std::set<std::string>>
-  customSequenceGetterWithDeps(const std::string& name,
-                               const std::string& prefix) {
-
-    if (auto getter = sequenceWithIpDep(name, prefix)) {
-      auto deps = BTagTrackIpAccessor(prefix).getTrackIpDataDependencyNames();
-      return {*getter, deps};
-    }
-
-    if (auto getter = sequenceNoIpDep(name)) {
-      return {*getter, {}};
-    }
-    throw std::logic_error("no match for custom getter " + name);
-  }
-
-}
-
diff --git a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/CMakeLists.txt b/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/CMakeLists.txt
deleted file mode 100644
index 373fc78720998cdaf8b4f9fd366e71a0194b5d7a..0000000000000000000000000000000000000000
--- a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-# Declare the package name:
-atlas_subdir( NTUPtoNTUPCore )
-
-# Install files from the package:
-atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
-atlas_install_joboptions( share/*.py )
diff --git a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/MultipleNTUPStreamManager.py b/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/MultipleNTUPStreamManager.py
deleted file mode 100644
index 29c3ddd092f6fdf675d7ff2e7ef6bc6f4fd81a6b..0000000000000000000000000000000000000000
--- a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/MultipleNTUPStreamManager.py
+++ /dev/null
@@ -1,214 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-from OutputStreamAthenaPool.MultipleStreamManager import AugmentedStreamBase, AugmentedPoolStream
-from AthenaCommon.AppMgr import theApp
-
-class AugmentedNTUPStream( AugmentedStreamBase ):
-    def  __init__(self, StreamName, FileName, tupleName = None, asAlg = False ):
-
-        # Initialize the base class:
-        AugmentedStreamBase.__init__(self,StreamName)
-
-        # Check if the user specified a tree name or not:
-        if tupleName is None:
-            tupleName = StreamName
-
-        # event-by-event stream
-        from AthenaRootComps.WriteAthenaRoot import createNtupleOutputStream
-        from AthenaRootComps.AthenaRootCompsConf import Athena__RootNtupleOutputMetadataTool as RootNtupleOutputMetadataTool
-
-        self.Stream = createNtupleOutputStream( StreamName, FileName, tupleName, asAlg)
-        metadataTool = RootNtupleOutputMetadataTool( StreamName + "Meta" )
-        metadataTool.OutputFile = FileName
-        metadataTool.StreamName = StreamName
-        metadataTool.TupleName = tupleName
-        theApp.serviceMgr().ToolSvc += metadataTool
-        self.Stream.HelperTools = [metadataTool]
-
-        return
-
-    def SetOutputFileName(self, name):
-        self.Stream.OutputFile = name
-        return
-
-    #########################################
-    #Items & MetaDataItems
-    def AddItem(self, item):
-        self._AddValidItemToList(item, self.Stream.ItemList)
-        return
-
-    def RemoveItem(self, item):
-        self._RemoveValidItemFromList(item, self.Stream.ItemList)
-        return
-
-    def GetItems(self):
-        return self.Stream.ItemList
-
-    def AddMetaDataItem(self, item):
-        return
-
-    def RemoveMetaDataItem(self, item):
-        pass
-
-    def GetMetaDataItems(self):
-        pass
-
-    #########################################
-    def Print(self):
-        print ("**** AugmentedPoolStream",self.Name,"****")
-        print ("Output file:")
-        print (self.Stream.OutputFile)
-        print ("AcceptAlgs:")
-        print (self.Stream.AcceptAlgs)
-        print ("RequireAlgs:")
-        print (self.Stream.RequireAlgs)
-        print ("VetoAlgs:")
-        print (self.Stream.VetoAlgs)
-        print ("OtherAlgs to bookkeep (but not directly used by the Stream):")
-        print (self.OtherAlgs)
-        print ("Master prescale:")
-        print (self.GetPrescale())
-        print ("ItemList:")
-        print (self.Stream.ItemList)
-        return
-#############################################################
-class MultipleNTUPStreamManager:
-    def __init__(self):
-        self.StreamList=[]
-        self.nStream=0
-        self.StreamDict={}
-        self._Locked=False
-        return
-
-    def NewNTUPStream(self,StreamName,FileName=None,TreeName=None,asAlg=False):
-        # Check if a file name was specified or not:
-        if FileName is None:
-            FileName = StreamName + ".root"
-        # Use the common function for creating the stream:
-        return self.NewStream( StreamName, FileName, type='ntup', asAlg = asAlg,
-                               TreeName = TreeName )
-    def NewStream(self,StreamName,FileName="default",type='pool',asAlg=False,TreeName=None):
-        if FileName=="default":
-            FileName=StreamName+".pool.root"
-        try:
-            #Check wheter a stream with the same name already exists
-            index=self.StreamDict[StreamName]
-        except KeyError:
-            #The stream doesn't already exist. Register it and set it up.
-            #(This is expected, not actually an error.)
-            index=self.nStream
-            if type=='ntup':
-                self.StreamList += [ AugmentedNTUPStream(StreamName,FileName,TreeName,asAlg) ]
-            else:
-                raise RuntimeError("Unknown type '%s'"%type)
-
-            self.StreamDict[StreamName]=index
-            self.nStream+=1
-        else:
-            #This is the real error case...
-            raise NameError("Stream %s already exists"%StreamName)
-        return self.StreamList[index]
-    
-    def GetStream(self, NameOrIndex):
-        #If NameOrIndex is an int, treat it as an index
-        if isinstance(NameOrIndex, int):
-            if NameOrIndex < self.nStream:
-                return self.StreamList[NameOrIndex]
-            else:
-                raise IndexError("ERROR: No stream with index %i is defined in MultipleNTUPStreamManager."%NameOrIndex)
-
-        #else treat NameOrIndex as a name in the Stream Dictionary
-        try:
-            #Check wheter a stream with the same name already exists
-            index=self.StreamDict[NameOrIndex]
-        except KeyError:
-            raise NameError("Stream %s undefined!"%NameOrIndex)
-        
-        return self.StreamList[index]
-    
-    def StreamExists(self, StreamName):
-        return StreamName in self.StreamDict
-
-    def Print(self):
-        print ("**** MultipleNTUPStreamManager INFOS ****" )
-        print ("Number of streams:", self.nStream)
-        i=0
-        for Stream in self.StreamList:
-            print ("----------------------- Stream #",i," -----------------------")
-            Stream.Print()
-            i+=1
-        return
-
-    #Commands for the real manager (normal users only manipulate their own streams with the functions above)
-    def Lock(self):
-        self._Locked=True
-        return
-
-    def Unlock(self):
-        self._Locked=False
-        return
-    
-    def AddItemToAllStreams(self, item):
-        if self._Locked is True:
-            raise AssertionError("MSMgr is locked. AddItemToAllStreams cannot be used.")
-        for Stream in self.StreamList:
-            Stream.AddItem(item)
-        return
-    
-    def RemoveItemFromAllStreams(self, item):
-        if self._Locked is True:
-            raise AssertionError("MSMgr is locked. RemoveItemFromAllStreams cannot be used.")
-        for Stream in self.StreamList:
-            Stream.RemoveItem(item)
-        return
-    
-    def AddMetaDataItemToAllStreams(self, item):
-        if self._Locked is True:
-            raise AssertionError("MSMgr is locked. AddMetaDataItemToAllStreams cannot be used.")
-        for Stream in self.StreamList:
-            Stream.AddMetaDataItem(item)
-        return
-
-    def RemoveMetaDataItemFromAllStreams(self, item):
-        if self._Locked is True:
-            raise AssertionError("MSMgr is locked. AddMetaDataItemFromAllStreams cannot be used.")
-        for Stream in self.StreamList:
-            Stream.RemoveMetaDataItem(item)
-        return
-
-    def RenameAllStreams(self, NameList):
-        if self._Locked is True:
-            raise AssertionError("MSMgr is locked. RenameAllStreams cannot be used.")
-        if not isinstance(NameList, list):
-            raise TypeError("RenameAllStreams does not accep arguments of type %s"%type(NameList))
-        if len(NameList) != self.nStream:
-            raise IndexError("NameList needs to have the same length as self.StreamList.")
-        
-        i=0
-        while i<self.nStream:
-            self.StreamList[i].SetOutputFileName(NameList[i])
-            i+=1            
-        return
-
-    def WriteSkimDecisionsOfAllStreams(self):
-        if self._Locked:
-            raise AssertionError("MSMgr is locked. WriteSkimDecisionsOfAllStreams cannot be used.")
-        
-        from AthenaCommon.AlgSequence import AlgSequence
-        topSequence = AlgSequence()
-        for Stream in self.StreamList:
-            if Stream.GetAcceptAlgs() or Stream.GetOtherAlgsToBookkeep() or Stream.GetRequireAlgs() or Stream.GetVetoAlgs():
-                sdw=Stream.GetSkimDecisionsWriter()
-                topSequence+=sdw
-                if isinstance(Stream,AugmentedPoolStream):
-                    Stream.AddItem("SkimDecisionCollection#"+sdw.SkimDecisionsContainerName)
-        return
-
-
-############################################################################
-# Create one instance of MultipleNTUPStreamManager (MNSMgr) if not already done.
-# Otherwise, do dothing (avoid overwriting MSMgr!).
-if 'MNSMgr' in vars():
-    raise RuntimeError("MNSMgr already exists?!? This will almost certainly create erroneous results.")
-MNSMgr=MultipleNTUPStreamManager()
-
diff --git a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/NTUPUtils.py b/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/NTUPUtils.py
deleted file mode 100644
index a164d9043696f44a0d8854ab79ecfe9d04db3fe8..0000000000000000000000000000000000000000
--- a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/NTUPUtils.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-from RecExConfig.RecoFunctions import AddValidItemToList
-def SetupOutputNTUPs(runArgs,flagContainerList):
-     NTUPScripts=[]
-     for flagContainer in flagContainerList:
-         for flagName in flagContainer.__dict__.keys():
-             flag=getattr(flagContainer,flagName)
-             if hasattr(flag,"StreamName"):
-                 ntupName=flag.StreamName.lstrip("Stream")
-                 argName='output'+ntupName+'File'
-                 if hasattr(runArgs,argName):
-                     if hasattr(flag,"FileName"):
-                         flag.FileName=getattr(runArgs,argName)
-                         flag.set_Value_and_Lock( True )
-                         if hasattr(flag,"NTUPScript"):
-                             AddValidItemToList(flag.NTUPScript,NTUPScripts)
-                         elif hasattr (flag, 'configure'):
-                             NTUPScripts.append(flag.configure)
-                         else:
-                             raise RuntimeError("No athena script attached to argument '%s'"%argName)
-                     else:
-                         raise RuntimeError("%s is not conform with the job transform convention, hence unusable. Please fix this."%ntupName)
-
-     return NTUPScripts
-
-def SetupOutputSkimNTUPs(runArgs,flagContainerList):
-     SkimNTUPScripts=[]
-     for flagContainer in flagContainerList:
-         for flagName in flagContainer.__dict__.keys():
-             flag=getattr(flagContainer,flagName)
-             if hasattr(flag,"StreamName"):
-                 ntupName=flag.StreamName.lstrip("Stream")
-                 argName='output'+ntupName+'File'
-                 if hasattr(runArgs,argName):
-                     if hasattr(flag,"FileName"):
-                         flag.FileName=getattr(runArgs,argName)
-                         flag.set_Value_and_Lock( True )
-                         if hasattr(flag,"SkimNTUPScript"):
-                             AddValidItemToList(flag.SkimNTUPScript,SkimNTUPScripts)
-                         elif hasattr (flag, 'configure'):
-                             SkimNTUPScripts.append(flag.configure)
-                         else:
-                             raise RuntimeError("No athena script attached to argument '%s'"%argName)
-                     else:
-                         raise RuntimeError("%s is not conform with the job transform convention, hence unusable. Please fix this."%ntupName)
-
-     return SkimNTUPScripts
-
-def NTUPtoNTUPProdFlags():
-    from NTUPtoNTUPCore.NTUPtoNTUPProdFlags import prodFlags
-    return prodFlags
-
-def SkimProdFlags():
-    from NTUPtoNTUPCore.SkimProdFlags import prodFlags
-    return prodFlags
-
-def MNSMgr():
-    from NTUPtoNTUPCore.MultipleNTUPStreamManager import MNSMgr
-    return MNSMgr
diff --git a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/NTUPtoNTUPProdFlags.py b/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/NTUPtoNTUPProdFlags.py
deleted file mode 100644
index e16dae173b4632e20a4e0fb1dd16091d742e022d..0000000000000000000000000000000000000000
--- a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/NTUPtoNTUPProdFlags.py
+++ /dev/null
@@ -1,111 +0,0 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-
-# NTUPtoNTUPProdFlags.py for NTUP->NTUP
-#
-
-from AthenaCommon.JobProperties import JobProperty, JobPropertyContainer
-from AthenaCommon.JobProperties import jobproperties
-
-listAllKnownNTUPtoNTUP=[]
-
-
-class NTUPtoNTUPProdFlags (JobPropertyContainer):
-    """ The NTUPtoNTUPProdFlags flag/job property  container."""
-jobproperties.add_Container(NTUPtoNTUPProdFlags)
-
-prodFlags = jobproperties.NTUPtoNTUPProdFlags
-
-# This function correctly determines the name of the output file.
-# If the transform set the FileName to the "official" name and locked
-# the jobProperty, that one will be used. Otherwise the user sets it.
-def buildFileName( jobPropFlag ):
-    if jobPropFlag.is_locked() :
-        fileName = jobPropFlag.FileName
-    else :
-        fileName = (prodFlags.OutputDirectoryName() +
-                    prodFlags.OutputPoolRootFileNamePrefix() +
-                    jobPropFlag.StreamName +
-                    prodFlags.OutputMiddleName() +
-                    ".root")
-
-    return fileName
-
-# Allows prodflags from elsewhere to be defined 
-def _importFlagsFromModule (mod):
-    """Given the full name of a module MOD, import it.
-Then look for objects in the module with names like WriteNTUP_RED that
-derive from JobProperty and add them to our list."""
-    name = mod.rsplit('.', 1)[-1]
-    mod = __import__ (mod, fromlist = [name])
-    for k, v in mod.__dict__.items():
-        if (k.startswith ('WriteNTUP_RED') and
-            issubclass (v, JobProperty)):
-            if hasattr (v, 'NTUPScript') :
-                prodFlags.add_JobProperty (v)
-                listAllKnownNTUPtoNTUP.append (getattr (prodFlags, k))
-    return
-   
-class TreeName(JobProperty):
-    """ Tree name """
-    statusOn     = True
-    allowedTypes = ['str']
-    StoredValue  = ""
-    pass
-prodFlags.add_JobProperty(TreeName)
-
-from RecExConfig.RecoFunctions import AddValidItemToList,RemoveValidItemFromList
-class NTUPScripts(JobProperty):
-    """ Setting NTUPScripts+=['MyPackage/NTUPOptions.py'] will execute NTUPOptions.py
-    """ 
-    statusOn=True
-    allowedTypes=['list']
-    StoredValue=[]
-    def append(self,item):
-        if self.is_locked():
-            self._log.info('The JobProperty %s is blocked', self.__name__)
-        else:
-            AddValidItemToList(item,self.StoredValue)
-        return
-    def remove(self,item):
-        if self.is_locked():
-            self._log.info('The JobProperty %s is blocked', self.__name__)
-        else:
-            RemoveValidItemFromList(item,self.StoredValue)
-        return
-prodFlags.add_JobProperty(NTUPScripts)
-
-class WriteMyNTUP (JobProperty):
-    """skimming NTUP"""
-    statusOn = True
-    allowedTypes = ['bool']
-    StoredValue = False
-    StreamName = 'StreamNTUP_MYNTUP'
-    FileName = ''
-    isVirtual = False
-    NTUPScript = "NTUPtoNTUPExample/MyNTUP_prodJobOFragment.py"
-    TreeNames = ['physics']
-    SubSteps = ['n2n']
-prodFlags.add_JobProperty (WriteMyNTUP)
-listAllKnownNTUPtoNTUP.append (prodFlags.WriteMyNTUP)
-
-class WriteMyNTUP2 (JobProperty):
-    """test NTUP"""
-    statusOn = True
-    allowedTypes = ['bool']
-    StoredValue = False
-    StreamName = 'StreamNTUP_MYNTUP2'
-    FileName = ''
-    isVirtual = False
-    NTUPScript = "NTUPtoNTUPExample/MyNTUP2_prodJobOFragment.py"
-    TreeNames = ['physics']
-    SubSteps = ['n2n']
-prodFlags.add_JobProperty (WriteMyNTUP2)
-listAllKnownNTUPtoNTUP.append (prodFlags.WriteMyNTUP2)
-
-################################################################
-# Following block of stream names for the Derivation Framework #
-
-_importFlagsFromModule('DerivationFrameworkCore.DerivationFrameworkProdFlags')
-
-# End of Derivation Framework formats #
-#######################################
diff --git a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/__init__.py b/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/__init__.py
deleted file mode 100644
index 74583d364ec2ca794156596c7254d9b234a940c6..0000000000000000000000000000000000000000
--- a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/python/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
diff --git a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/share/NTUPtoNTUP_topOptions.py b/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/share/NTUPtoNTUP_topOptions.py
deleted file mode 100644
index f84f42b46351dca5a7c2bd3839ef9792233e251f..0000000000000000000000000000000000000000
--- a/PhysicsAnalysis/NTUPtoNTUP/NTUPtoNTUPCore/share/NTUPtoNTUP_topOptions.py
+++ /dev/null
@@ -1,35 +0,0 @@
-include.block ("NTUPtoNTUP_topOptions.py")
-
-from AthenaCommon.Logging import logging
-logNTUPtoNTUP_topOptions = logging.getLogger( 'NTUPtoNTUP_topOptions' )
-from AthenaCommon.AlgSequence import AlgSequence
-topSequence = AlgSequence()
-from AthenaCommon.AppMgr import ToolSvc,theApp,ServiceMgr
-
-### Set Input
-import AthenaRootComps.ReadAthenaRoot
-from AthenaCommon.AthenaCommonFlags import jobproperties
-ntupFlags=jobproperties.NTUPtoNTUPProdFlags
-ServiceMgr.EventSelector.InputCollections = athenaCommonFlags.FilesInput()
-ServiceMgr.EventSelector.TupleName = jobproperties.NTUPtoNTUPProdFlags.TreeName()
-
-# Number of events to be processed, skip event
-theApp.EvtMax = athenaCommonFlags.EvtMax()
-try:
-    ServiceMgr.EventSelector.SkipEvents = athenaCommonFlags.SkipEvents()
-except Exception:
-    treatException("Could not set EventSelector.SkipEvents")
-
-# TODO: event bookkeeping?
-
-### NTUP->NTUP
-ntupFlags=jobproperties.NTUPtoNTUPProdFlags
-printfunc ("Content of rec.NTUPScripts = %s", ntupFlags.NTUPScripts)
-if ntupFlags.NTUPScripts()!=[]:
-  for ntup in ntupFlags.NTUPScripts():
-      NTUPName = str(ntup)
-      printfunc ("Including %s...",NTUPName)
-      include(ntup)
-      pass
-else:
-  printfunc ("no scripts in NTUPScripts...")
diff --git a/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/src/TFCSONNXHandler.cxx b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/src/TFCSONNXHandler.cxx
index 18f0eee944bf85118fd15381f915d40db15de19d..daceba332ac4b2ef47159c5ac9cf709daf007dfa 100644
--- a/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/src/TFCSONNXHandler.cxx
+++ b/Simulation/ISF/ISF_FastCaloSim/ISF_FastCaloSimEvent/src/TFCSONNXHandler.cxx
@@ -325,6 +325,8 @@ void TFCSONNXHandler::readSerializedSession() {
   ATH_MSG_DEBUG("Transforming bytes to session.");
   Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test");
   Ort::SessionOptions opts{nullptr};
+  // Prevent ONNX from spawning additional threads
+  opts.SetIntraOpNumThreads( 1 );
   m_session =
       std::make_unique<Ort::Session>(env, m_bytes.data(), m_bytes.size(), opts);
   ATH_MSG_DEBUG("Transformed bytes to session.");
diff --git a/TestBeam/TBDetDescrAlg/TBDetDescrAlg/ATLAS_CHECK_THREAD_SAFETY b/TestBeam/TBDetDescrAlg/ATLAS_CHECK_THREAD_SAFETY
similarity index 100%
rename from TestBeam/TBDetDescrAlg/TBDetDescrAlg/ATLAS_CHECK_THREAD_SAFETY
rename to TestBeam/TBDetDescrAlg/ATLAS_CHECK_THREAD_SAFETY
diff --git a/TestBeam/TBDetDescrAlg/CMakeLists.txt b/TestBeam/TBDetDescrAlg/CMakeLists.txt
index c3d0e86823198b96bbb5dcece8980214216dadfc..a6298498526c01e4217f008fa9905cfeb65b0179 100644
--- a/TestBeam/TBDetDescrAlg/CMakeLists.txt
+++ b/TestBeam/TBDetDescrAlg/CMakeLists.txt
@@ -1,21 +1,14 @@
-# Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 
 # Declare the package name:
 atlas_subdir( TBDetDescrAlg )
 
 # Component(s) in the package:
-atlas_add_library( TBDetDescrAlgLib
-                   src/TB*.cxx
-                   PUBLIC_HEADERS TBDetDescrAlg
-                   LINK_LIBRARIES AthenaBaseComps
-                   PRIVATE_LINK_LIBRARIES DetDescrCnvSvcLib GaudiKernel TBDetDescr )
-
 atlas_add_component( TBDetDescrAlg
+                     src/*.cxx
                      src/components/*.cxx
-                     LINK_LIBRARIES TBDetDescrAlgLib )
+                     PRIVATE_LINK_LIBRARIES AthenaBaseComps DetDescrCnvSvcLib GaudiKernel TBDetDescr )
 
-# Install files from the package:
-atlas_install_joboptions( share/*.py )
 # Install files from the package:
 atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
 
diff --git a/TestBeam/TBDetDescrAlg/share/TBDetDescrLoader_jobOptions.py b/TestBeam/TBDetDescrAlg/share/TBDetDescrLoader_jobOptions.py
deleted file mode 100755
index c2aa2d4a1a27b96091f2d194afd170b4f07b23d9..0000000000000000000000000000000000000000
--- a/TestBeam/TBDetDescrAlg/share/TBDetDescrLoader_jobOptions.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from TBDetDescrAlg.TBDetDescrAlgConf import *
-theTBDetDescrLoader=TBDetDescrLoader()
-
-theTBDetDescrLoader.TBElementContainer = "TBElementCnt"
-theTBDetDescrLoader.TBDetDescrManager  = "TBDetDescrMgr"
-
-from AthenaCommon.DetFlags import DetFlags
-
-if not 'doSim' in dir():
-    # apparently we are not running RecExTB,
-    # most probably running simulation or digitization
-
-    Stream1.ItemList+=["TBElementContainer#*"]
-
-    if DetFlags.writeRDOPool.any_on():
-        # looks like this is digitization job
-        # just copy container from input file to output file
-
-        theTBDetDescrLoader.ReadAction = 1
-        theTBDetDescrLoader.WriteAction = 0
-
-    else:
-        # looks like this is simulation job
-        # need to initialize TBDetDesrManager in Detector Store from FADS
-        include( "TBDetDescrCnv/TBDetDescrCnv_jobOptions.py" )
-
-        # do not read anything from StoreGate
-        theTBDetDescrLoader.ReadAction = 0
-        # and write TBDetDescrContainer to StoreGate every event
-        theTBDetDescrLoader.WriteAction = 2
-
-else:
-    # doSim can be set to False by TileCal jobOptions
-    # make independent cross-check
-
-    if DetFlags.writeRDOPool.any_on():
-        # looks like this is digitization job
-        # just copy container from input file to output file
-
-        Stream1.ItemList+=["TBElementContainer#*"]
-        theTBDetDescrLoader.ReadAction = 1
-        theTBDetDescrLoader.WriteAction = 0
-
-    else:
-        # reconstruction job
-        # reading ByteStream or POOL file with digits
-    
-        if doSim:
-            # data from simulation, read TBDetDescr just once
-            theTBDetDescrLoader.ReadAction = 1
-            theTBDetDescrLoader.WriteAction = 0
-        else:
-            # real data, create dummy TBDetDescrManager
-            theTBDetDescrLoader.ReadAction = -1
-            theTBDetDescrLoader.WriteAction = 0
-
-
-from AthenaCommon.AlgSequence import AlgSequence
-topSequence = AlgSequence()
-
-topSequence += theTBDetDescrLoader
diff --git a/TestBeam/TBDetDescrAlg/src/TBDetDescrLoader.cxx b/TestBeam/TBDetDescrAlg/src/TBDetDescrLoader.cxx
index 764cc7aa32bd8725bf25cc7347cf1a26026c3373..1dfabffc05d2fc6047b44deb45f3d9fc7730c54e 100755
--- a/TestBeam/TBDetDescrAlg/src/TBDetDescrLoader.cxx
+++ b/TestBeam/TBDetDescrAlg/src/TBDetDescrLoader.cxx
@@ -1,9 +1,8 @@
 /*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 //Gaudi Includes
-//#include "GaudiKernel/Bootstrap.h"
 #include "GaudiKernel/IDataProviderSvc.h"
 #include "GaudiKernel/SmartDataPtr.h"
 
@@ -12,7 +11,7 @@
 //TBDetDescr includes
 #include "TBDetDescr/TBElementContainer.h"
 #include "TBDetDescr/TBDetDescrManager.h"
-#include "TBDetDescrAlg/TBDetDescrLoader.h"
+#include "TBDetDescrLoader.h"
 
 // Constructor & destructor
 TBDetDescrLoader::TBDetDescrLoader(const std::string& name, ISvcLocator* pSvcLocator)
diff --git a/TestBeam/TBDetDescrAlg/TBDetDescrAlg/TBDetDescrLoader.h b/TestBeam/TBDetDescrAlg/src/TBDetDescrLoader.h
similarity index 100%
rename from TestBeam/TBDetDescrAlg/TBDetDescrAlg/TBDetDescrLoader.h
rename to TestBeam/TBDetDescrAlg/src/TBDetDescrLoader.h
diff --git a/TestBeam/TBDetDescrAlg/src/components/TBDetDescrAlg_entries.cxx b/TestBeam/TBDetDescrAlg/src/components/TBDetDescrAlg_entries.cxx
index 46b2dc3b6471e68129a31348edb302866a978077..46f4401dd8317be09679c26c0d7e5041e6749171 100644
--- a/TestBeam/TBDetDescrAlg/src/components/TBDetDescrAlg_entries.cxx
+++ b/TestBeam/TBDetDescrAlg/src/components/TBDetDescrAlg_entries.cxx
@@ -1,5 +1,4 @@
-#include "TBDetDescrAlg/TBDetDescrLoader.h"
-
+#include "../TBDetDescrLoader.h"
 
 DECLARE_COMPONENT( TBDetDescrLoader )
 
diff --git a/Tracking/TrkVertexFitter/TrkVKalVrtCore/src/VtCFit.cxx b/Tracking/TrkVertexFitter/TrkVKalVrtCore/src/VtCFit.cxx
index 32eecc0c1a2891192ddb9efcb3fb2c4b657e87f5..e41e20720d91dda7c70dd84c149b7dbf71167d7b 100644
--- a/Tracking/TrkVertexFitter/TrkVKalVrtCore/src/VtCFit.cxx
+++ b/Tracking/TrkVertexFitter/TrkVKalVrtCore/src/VtCFit.cxx
@@ -1,5 +1,5 @@
 /*
-   Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+   Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
    */
 
 #include "TrkVKalVrtCore/VtCFit.h"
@@ -706,8 +706,11 @@ int vtcfit( VKVertex * vk) {
     double tt2=vk->tmpArr[kt]->tt[1];
     double tt3=vk->tmpArr[kt]->tt[2];
     vk->tmpArr[kt]->parf0[0] = twci[0]*tt1 + twci[1]*tt2 + twci[3]*tt3 - twbci[0]*dxyz[0] - twbci[1]*dxyz[1] - twbci[2]*dxyz[2];
+    if( !std::isfinite(vk->tmpArr[kt]->parf0[0]) ) return -19; // Rare FPE presumably seen in trigger
     vk->tmpArr[kt]->parf0[1] = twci[1]*tt1 + twci[2]*tt2 + twci[4]*tt3 - twbci[3]*dxyz[0] - twbci[4]*dxyz[1] - twbci[5]*dxyz[2];
+    if( !std::isfinite(vk->tmpArr[kt]->parf0[1]) ) return -19; // Rare FPE presumably seen in trigger
     vk->tmpArr[kt]->parf0[2] = twci[3]*tt1 + twci[4]*tt2 + twci[5]*tt3 - twbci[6]*dxyz[0] - twbci[7]*dxyz[1] - twbci[8]*dxyz[2];
+    if( !std::isfinite(vk->tmpArr[kt]->parf0[2]) ) return -19; // Rare FPE presumably seen in trigger
     if( (vk->TrackList[kt]->iniP[2] + vk->tmpArr[kt]->parf0[2]) * vk->TrackList[kt]->iniP[2] < 0 ){
       vk->tmpArr[kt]->parf0[2]= - vk->TrackList[kt]->iniP[2]/4.; } // VK 15.12.2009 - Protection against change of sign
     vk->TrackList[kt]->fitP[0] = vk->TrackList[kt]->iniP[0] + vk->tmpArr[kt]->parf0[0];
diff --git a/Trigger/TrigAlgorithms/TrigFastTrackFinder/src/TrigFastTrackFinder.cxx b/Trigger/TrigAlgorithms/TrigFastTrackFinder/src/TrigFastTrackFinder.cxx
index bcde59b726f986625bea6505f31a81b58b5998bc..43fdf2c0004544aca13b858df4126d7093d7dade 100644
--- a/Trigger/TrigAlgorithms/TrigFastTrackFinder/src/TrigFastTrackFinder.cxx
+++ b/Trigger/TrigAlgorithms/TrigFastTrackFinder/src/TrigFastTrackFinder.cxx
@@ -430,6 +430,7 @@ StatusCode TrigFastTrackFinder::execute(const EventContext& ctx) const {
       ATH_MSG_ERROR("No Roi found for " << m_roiCollectionKey.key() );
       return StatusCode::FAILURE;
     }
+
     TrigRoiDescriptor internalRoI = **roiCollection->begin();
 
     ATH_CHECK(findTracks(trackEventData, internalRoI, inputTracks, *outputTracks, ctx));
diff --git a/Trigger/TrigEvent/TrigNavTools/CMakeLists.txt b/Trigger/TrigEvent/TrigNavTools/CMakeLists.txt
index 88f1c60865a6dab5da86ca22453be9984536a74e..4bbc056c828a6d33029f6666549d2666e1f6491a 100644
--- a/Trigger/TrigEvent/TrigNavTools/CMakeLists.txt
+++ b/Trigger/TrigEvent/TrigNavTools/CMakeLists.txt
@@ -18,3 +18,12 @@ atlas_add_component( TrigNavTools
 atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
 atlas_install_joboptions( share/*.py )
 atlas_install_scripts( share/*.py )
+
+atlas_add_test( NavConversionConfigTest
+                SCRIPT python -m TrigNavTools.NavConverterConfig
+                POST_EXEC_SCRIPT nopost.sh )
+
+
+atlas_add_test( ExecuteConversion
+                SCRIPT testTrigR2ToR3NavGraphConversionV2.py
+                POST_EXEC_SCRIPT nopost.sh )                
\ No newline at end of file
diff --git a/Trigger/TrigEvent/TrigNavTools/python/NavConverterConfig.py b/Trigger/TrigEvent/TrigNavTools/python/NavConverterConfig.py
index 65ee99ba6ebdbcd89e14045c988120812fe6625b..c968218a078d22f1ddc2b0273c2eadaf835bdca3 100644
--- a/Trigger/TrigEvent/TrigNavTools/python/NavConverterConfig.py
+++ b/Trigger/TrigEvent/TrigNavTools/python/NavConverterConfig.py
@@ -43,7 +43,7 @@ def NavConverterCfg(flags, chainsFilter = []):
     log.info("Assuming these collections are relevant for trigger: %s", " ".join(types))
     cnvAlg.Collections = types
     cnvAlg.Chains = chainsFilter
-    cnvAlg.doCompression = False # set True for compression
+    cnvAlg.doCompression = True # set True for compression
     acc.addEventAlgo(cnvAlg)
 
     checker = CompFactory.Trig.NavigationTesterAlg(FailOnDifference = True, TrigDecisionTool = tdt) # optional: OutputLevel = DEBUG
@@ -59,15 +59,15 @@ def NavConverterCfg(flags, chainsFilter = []):
     checker.RetrievalToolRun3Nav = CompFactory.Trig.R3IParticleRetrievalTool(TrigDecisionTool = run3tdt)
     checker.Chains = chainsFilter
     acc.addEventAlgo(checker)
-
     return acc
 
 
 if __name__ == "__main__":
+    # this is only config test, actual tests are in share/testTrigR2... scripts
     from AthenaConfiguration.AllConfigFlags import initConfigFlags
     from AthenaConfiguration.TestDefaults import defaultTestFiles
     flags = initConfigFlags()
-    flags.Input.Files = defaultTestFiles.RAW_RUN2
+    flags.Input.Files = defaultTestFiles.AOD_RUN2_DATA
     flags.Trigger.doEDMVersionConversion = True
     flags.lock()
 
diff --git a/Trigger/TrigEvent/TrigNavTools/share/testTrigR2ToR3NavGraphConversionV2.py b/Trigger/TrigEvent/TrigNavTools/share/testTrigR2ToR3NavGraphConversionV2.py
index fa3d6887e8faa9cde1338fa2c392bd3fe77fa016..bbd514ae2aad73699df515105ea07d5c316592d1 100755
--- a/Trigger/TrigEvent/TrigNavTools/share/testTrigR2ToR3NavGraphConversionV2.py
+++ b/Trigger/TrigEvent/TrigNavTools/share/testTrigR2ToR3NavGraphConversionV2.py
@@ -17,10 +17,11 @@ if __name__=='__main__':
 
     flags.Input.Files=["/cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/Tier0ChainTests/data18_13TeV.00357772.physics_Main.recon.AOD.r13286/AOD.27654050._000557.pool.root.1"]
 
-    flags.Output.AODFileName = "outAOD.pool.root"
     flags.Detector.GeometryLAr=True
     flags.Detector.GeometryTile=True
-    flags.Exec.MaxEvents = 1000
+    flags.Exec.MaxEvents = -1
+    flags.Exec.SkipEvents = 0
+    flags.Trigger.doEDMVersionConversion=True
     flags.fillFromArgs()
     flags.lock()
 
@@ -39,41 +40,26 @@ if __name__=='__main__':
     confSvc = CompFactory.TrigConf.xAODConfigSvc("xAODConfigSvc")
     cfg.addService(confSvc)
     from AthenaCommon.Constants import DEBUG
-    alg = CompFactory.Run2ToRun3TrigNavConverterV2("TrigNavCnv", OutputLevel=DEBUG, TrigConfigSvc=confSvc)
-    alg.doSelfValidation = False
-    alg.doCompression = True
-    alg.addTauTracks = False
-
-    alg.Collections = ["xAOD::TrigEMCluster", "xAOD::TrigEMClusterContainer", "xAOD::TrigRingerRings", "xAOD::TrigRingerRingsContainer", "xAOD::TrigRNNOutput", "xAOD::TrigRNNOutputContainer", "xAOD::CaloClusterContainer", "xAOD::L2StandAloneMuonContainer", "xAOD::L2StandAloneMuonAuxContainer", "xAOD::L2CombinedMuonContainer", "xAOD::L2CombinedMuonAuxContainer","xAOD::L2IsoMuonContainer", "xAOD::MuonContainer", "xAOD::MuonAuxContainer","xAOD::TauJetContainer", "xAOD::ElectronContainer", "xAOD::PhotonContainer", "xAOD::JetContainer", "xAOD::BTaggingContainer", "xAOD::BTagVertexContainer", "xAOD::JetElementContainer", "xAOD::TrigMissingET", "xAOD::TrigBphysContainer"]
-    if (alg.addTauTracks):
-        alg.Collections.append("xAOD::TauTrackContainer")
     
     # simple mu test cases
-    alg.Chains = ["HLT_mu4","HLT_mu6","HLT_mu10","HLT_mu6_2mu4","HLT_mu22"]
-
-    alg.Rois = ["initialRoI","forID","forID1","forID2","forMS","forSA","forTB","forMT","forCB"]
+    chains = \
+    ['HLT_2e12_lhloose_nod0_mu10', 'HLT_2mu14', 'HLT_2mu20_L12MU20_OVERLAY', 'HLT_2mu4_bJpsimumu', 'HLT_2mu4_bUpsimumu', 'HLT_2mu6_bJpsimumu', 'HLT_2mu6_bUpsimumu', 'HLT_3mu3_mu3noL1_L13MU4', 'HLT_3mu4', 'HLT_3mu4_mu2noL1', 'HLT_3mu6', 'HLT_3mu6_msonly', 'HLT_3mu6_msonly_L1MU4_UNPAIRED_ISO', 'HLT_3mu6_msonly_L1MU6_EMPTY', 'HLT_4mu4', 'HLT_e12_lhloose_nod0_2mu10', 'HLT_e17_lhloose_nod0_mu14', 'HLT_e26_lhmedium_nod0_mu8noL1', 'HLT_e7_lhmedium_nod0_mu24', 'HLT_e9_lhvloose_nod0_mu20_mu8noL1', 'HLT_e9_lhvloose_nod0_mu20_mu8noL1_L1EM7_MU20', 'HLT_mu10', 'HLT_mu10_bJpsi_TrkPEB', 'HLT_mu10_bJpsi_Trkloose', 'HLT_mu11_bJpsi_TrkPEB', 'HLT_mu11_mu6_bJpsimumu', 'HLT_mu11_mu6_bUpsimumu', 'HLT_mu13_mu13_idperf_Zmumu', 'HLT_mu14', 'HLT_mu14_ivarloose_L1MU11_tau35_medium1_tracktwoEF_L1MU11_TAU20IM', 'HLT_mu14_ivarloose_L1MU11_tau35_medium1_tracktwo_L1MU11_TAU20IM', 'HLT_mu14_ivarloose_L1MU11_tau35_mediumRNN_tracktwoMVA_L1MU11_TAU20IM', 'HLT_mu14_ivarloose_tau25_medium1_tracktwo', 'HLT_mu14_ivarloose_tau25_medium1_tracktwoEF', 'HLT_mu14_ivarloose_tau25_medium1_tracktwoEF_L1DR-MU10TAU12I_TAU12I-J25', 'HLT_mu14_ivarloose_tau25_medium1_tracktwoEF_L1MU10_TAU12IM_3J12', 'HLT_mu14_ivarloose_tau25_medium1_tracktwo_L1DR-MU10TAU12I_TAU12I-J25', 'HLT_mu14_ivarloose_tau25_medium1_tracktwo_L1MU10_TAU12IM_3J12', 'HLT_mu14_ivarloose_tau25_mediumRNN_tracktwoMVA', 'HLT_mu14_ivarloose_tau25_mediumRNN_tracktwoMVA_L1DR-MU10TAU12I_TAU12I-J25', 'HLT_mu14_ivarloose_tau25_mediumRNN_tracktwoMVA_L1MU10_TAU12IM_3J12', 'HLT_mu14_ivarloose_tau35_medium1_tracktwo', 'HLT_mu14_ivarloose_tau35_medium1_tracktwoEF', 'HLT_mu14_ivarloose_tau35_mediumRNN_tracktwoMVA', 'HLT_mu18', 'HLT_mu20', 'HLT_mu20_2mu2noL1_JpsimumuFS', 'HLT_mu20_2mu4_JpsimumuL2', 'HLT_mu20_2mu4noL1', 'HLT_mu20_bJpsi_TrkPEB', 'HLT_mu20_ivarmedium_mu8noL1', 'HLT_mu20_msonly_iloosems_mu6noL1_msonly_nscan05_L1MU4_UNPAIRED_ISO', 'HLT_mu20_msonly_iloosems_mu6noL1_msonly_nscan05_L1MU6_EMPTY', 'HLT_mu20_msonly_mu15noL1_msonly_nscan05_noComb', 'HLT_mu20_msonly_mu15noL1_msonly_nscan05_noComb_L1MU4_UNPAIRED_ISO', 'HLT_mu20_msonly_mu15noL1_msonly_nscan05_noComb_L1MU6_EMPTY', 'HLT_mu20_msonly_mu6noL1_msonly_nscan05', 'HLT_mu22', 'HLT_mu22_mu8noL1', 'HLT_mu22_mu8noL1_TagandProbe', 'HLT_mu24', 'HLT_mu24_ivarmedium', 'HLT_mu26_ivarmedium', 'HLT_mu4', 'HLT_mu4_bJpsi_TrkPEB', 'HLT_mu4_bJpsi_Trkloose', 'HLT_mu4_j15_boffperf_split_dr05_dz02', 'HLT_mu4_j25_boffperf_split_dr05_dz02', 'HLT_mu4_j35_boffperf_split_dr05_dz02', 'HLT_mu4_j45_gsc55_boffperf_split_dr05_dz02', 'HLT_mu4_mu4_idperf_bJpsimumu_noid', 'HLT_mu50', 'HLT_mu6', 'HLT_mu60_0eta105_msonly', 'HLT_mu6_2mu4', 'HLT_mu6_bJpsi_TrkPEB', 'HLT_mu6_bJpsi_Trkloose', 'HLT_mu6_bJpsi_lowpt_TrkPEB', 'HLT_mu6_dRl1_mu20_msonly_iloosems_mu6noL1_dRl1_msonly', 'HLT_mu6_idperf', 'HLT_mu6_j110_gsc150_boffperf_split_dr05_dz02', 'HLT_mu6_j150_gsc175_boffperf_split_dr05_dz02', 'HLT_mu6_j175_gsc260_boffperf_split_dr05_dz02', 'HLT_mu6_j60_gsc85_boffperf_split_dr05_dz02', 'HLT_mu6_j85_gsc110_boffperf_split_dr05_dz02', 'HLT_mu6_mu4_bJpsimumu', 'HLT_mu6_mu4_bUpsimumu', 'HLT_mu6_nomucomb_2mu4_nomucomb_L1MU6_3MU4', 'HLT_mu80_msonly_3layersEC']
+    chains=["HLT_tau35_medium1_tracktwo_tau25_medium1_tracktwo_03dR30_L1DR-TAU20ITAU12I-J25"]
 
 
-    cfg.addEventAlgo(alg, sequenceName="AthAlgSeq")
-    from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
-    outputType="AOD"
-    toRecord = ["xAOD::TrigCompositeContainer#HLTNav_All", "xAOD::TrigCompositeAuxContainer#HLTNav_AllAux.",
-                "xAOD::TrigCompositeContainer#HLTNav_Summary", "xAOD::TrigCompositeAuxContainer#HLTNav_SummaryAux."]
-    outputCfg = OutputStreamCfg(flags, outputType, ItemList=toRecord, disableEventTag=True, takeItemsFromInput = True)
-    streamAlg = outputCfg.getEventAlgo("OutputStream"+outputType)
-    # need to expand possible options for the OutputStreamCfg to be able to pass also the metadata containers
-    streamAlg.MetadataItemList += ["xAOD::TriggerMenuContainer#TriggerMenu", "xAOD::TriggerMenuAuxContainer#TriggerMenuAux."]
-    cfg.addPublicTool(CompFactory.xAODMaker.TriggerMenuMetaDataTool("TriggerMenuMetaDataTool"))
-    cfg.addService( CompFactory.MetaDataSvc("MetaDataSvc", MetaDataTools = [cfg.getPublicTool("TriggerMenuMetaDataTool")]))
-
-    cfg.merge(outputCfg)
+    from TrigNavTools.NavConverterConfig import NavConverterCfg
+    cfg.merge(NavConverterCfg(flags, chains))
 
     # input EDM needs calo det descrition for conversion (uff)
     from LArGeoAlgsNV.LArGMConfig import LArGMCfg
     from TileGeoModel.TileGMConfig import TileGMCfg
     cfg.merge(LArGMCfg(flags))
     cfg.merge(TileGMCfg(flags))
-
+    msg = cfg.getService('MessageSvc'); 
+    msg.debugLimit=0
+    msg.infoLimit=0 
+    msg.warningLimit=0 
+    msg.Format='% F%35W%C% F%9W%e%7W%R%T %0W%M'
     cfg.printConfig(withDetails=True, summariseProps=False) # set True for exhaustive info
     sc = cfg.run()
     sys.exit(0 if sc.isSuccess() else 1)
diff --git a/Trigger/TrigEvent/TrigNavTools/src/NavigationTesterAlg.cxx b/Trigger/TrigEvent/TrigNavTools/src/NavigationTesterAlg.cxx
index 9b20063ff62c3238e8ed2aba89fe625c1e6c9dbb..81846e7a2cbcd60c86da6116790d98042c19eb1c 100644
--- a/Trigger/TrigEvent/TrigNavTools/src/NavigationTesterAlg.cxx
+++ b/Trigger/TrigEvent/TrigNavTools/src/NavigationTesterAlg.cxx
@@ -54,7 +54,7 @@ namespace std {
 namespace Trig {
 
     NavigationTesterAlg::NavigationTesterAlg(const std::string &name, ISvcLocator *pSvcLocator) :
-        AthAlgorithm(name, pSvcLocator)
+        AthReentrantAlgorithm(name, pSvcLocator)
     {}
 
     StatusCode NavigationTesterAlg::initialize()
@@ -67,7 +67,7 @@ namespace Trig {
         return StatusCode::SUCCESS;
     }
 
-    StatusCode NavigationTesterAlg::execute()
+    StatusCode NavigationTesterAlg::execute(const EventContext &) const
     {
         for (const std::string &chain : m_chains)
         {
diff --git a/Trigger/TrigEvent/TrigNavTools/src/NavigationTesterAlg.h b/Trigger/TrigEvent/TrigNavTools/src/NavigationTesterAlg.h
index 51c429863576238b29b589626972838df48965e8..bd32bf5f59e4513e52ec6a540d4201b5248260fb 100644
--- a/Trigger/TrigEvent/TrigNavTools/src/NavigationTesterAlg.h
+++ b/Trigger/TrigEvent/TrigNavTools/src/NavigationTesterAlg.h
@@ -2,7 +2,7 @@
   Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
 */
 
-#include "AthenaBaseComps/AthAlgorithm.h"
+#include "AthenaBaseComps/AthReentrantAlgorithm.h"
 #include "GaudiKernel/ToolHandle.h"
 #include "Gaudi/Property.h"
 #include "TriggerMatchingTool/IIParticleRetrievalTool.h"
@@ -11,14 +11,14 @@
 #include <vector>
 
 namespace Trig {
-    class NavigationTesterAlg : public AthAlgorithm
+    class NavigationTesterAlg : public AthReentrantAlgorithm
     {
     public:
         NavigationTesterAlg(const std::string &name, ISvcLocator *pSvcLocator);
         ~NavigationTesterAlg() override = default;
 
         StatusCode initialize() override;
-        StatusCode execute() override;
+        StatusCode execute(const EventContext &context) const override;
 
     private:
         PublicToolHandle<Trig::TrigDecisionTool> m_tdt{this, "TrigDecisionTool", "", "When enabled read navigation from TDT/off by default"};
diff --git a/Trigger/TrigEvent/TrigNavTools/src/Run2ToRun3TrigNavConverterV2.cxx b/Trigger/TrigEvent/TrigNavTools/src/Run2ToRun3TrigNavConverterV2.cxx
index abc71fd89c41dbe3df0d0860609acf201a691baf..9cd41db0088ce99b9b9c343b317ac321a0c343ee 100644
--- a/Trigger/TrigEvent/TrigNavTools/src/Run2ToRun3TrigNavConverterV2.cxx
+++ b/Trigger/TrigEvent/TrigNavTools/src/Run2ToRun3TrigNavConverterV2.cxx
@@ -2,8 +2,9 @@
   Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
 */
 
+#include <boost/functional/hash.hpp>
+#include <GaudiKernel/StatusCode.h>
 #include "AthLinks/ElementLinkVector.h"
-#include "TrigConfHLTUtils/HLTUtils.h"
 #include "xAODTrigger/TrigPassBitsContainer.h"
 #include "AthenaKernel/ClassID_traits.h"
 #include "TrigNavStructure/TriggerElement.h"
@@ -220,6 +221,10 @@ StatusCode Run2ToRun3TrigNavConverterV2::finalize()
 
 StatusCode Run2ToRun3TrigNavConverterV2::execute(const EventContext &context) const
 {
+  // ATH_MSG_INFO("EVENT " << context.evt());
+  // if ( 4 == context.evt() )  return StatusCode::SUCCESS;
+  // ATH_MSG_INFO("EVENT processing " << context.evt());
+
   {
     // configuration reading could not be done before the event loop
     // it needs to be done only once though
@@ -340,7 +345,7 @@ StatusCode Run2ToRun3TrigNavConverterV2::extractTECtoChainMapping(TEIdToChainsMa
       // e.g. for the chain: HLT_2g25_loose_g20 the multiplicities are: [2, 1]
       // 
       ATH_MSG_DEBUG("CHAIN " << chainName << " needs legs: " << multiplicities );
-      std::vector<unsigned int> teIdsLastHealthyStep;
+      std::vector<unsigned int> teIdsLastHealthyStepIds;
 
       for (auto ptrHLTSignature : ptrChain->signatures())
         {
@@ -360,17 +365,19 @@ StatusCode Run2ToRun3TrigNavConverterV2::extractTECtoChainMapping(TEIdToChainsMa
 
           ATH_MSG_DEBUG("TE multiplicities seen in this step " << teCounts);
           if ( multiplicities == teCounts ) {
-            teIdsLastHealthyStep = teIds;
-            ATH_MSG_DEBUG("There is a match, will assign chain leg IDs to TEs " << teCounts);
+            teIdsLastHealthyStepIds = teIds;
+            ATH_MSG_DEBUG("There is a match, will assign chain leg IDs to TEs " << teCounts << " " << teIds);
             for ( size_t legNumber = 0; legNumber < teIds.size(); ++ legNumber){
               HLT::Identifier chainLegId = TrigCompositeUtils::createLegName(chainId, legNumber);
               allTEs[teIds[legNumber]].insert(chainLegId);
             }
           } 
         }
-        for ( size_t legNumber = 0; legNumber < teIdsLastHealthyStep.size(); ++ legNumber ) {
+        for ( size_t legNumber = 0; legNumber < teIdsLastHealthyStepIds.size(); ++ legNumber ) {
           HLT::Identifier chainLegId = TrigCompositeUtils::createLegName(chainId, legNumber);
-          finalTEs[teIdsLastHealthyStep[legNumber]].insert(chainLegId);
+
+          ATH_MSG_DEBUG("created leg id " << chainLegId << " that will replace TE ID " << teIdsLastHealthyStepIds[legNumber]);
+          finalTEs[teIdsLastHealthyStepIds[legNumber]].insert(chainLegId);
         }
     }
 
@@ -444,6 +451,23 @@ StatusCode Run2ToRun3TrigNavConverterV2::mirrorTEsStructure(ConvProxySet_t &conv
   return StatusCode::SUCCESS;
 }
 
+
+void Run2ToRun3TrigNavConverterV2::printProxies(const ConvProxySet_t& proxies, 
+                                                std::function<bool(const ConvProxy*)> selector,
+                                                std::vector<std::function<void(const ConvProxy*)>> printers) const {
+  ATH_MSG_DEBUG("Printing proxies");
+  ATH_MSG_DEBUG("" );
+  for ( auto p: proxies) {
+    if ( selector(p) ){
+      ATH_MSG_DEBUG("Proxy " << p->description() );
+      for (auto& printer: printers) {
+        printer(p);
+      }
+      ATH_MSG_DEBUG("" );
+    }
+  }
+}
+
 StatusCode Run2ToRun3TrigNavConverterV2::associateChainsToProxies(ConvProxySet_t &convProxies, const TEIdToChainsMap_t &allTEs) const
 {
 
@@ -600,22 +624,23 @@ StatusCode Run2ToRun3TrigNavConverterV2::collapseFeaturesProxies(ConvProxySet_t
       ATH_MSG_VERBOSE("FEA: " << fea);
     }
   }
-  if (m_doSelfValidation)
+
+  for (auto [feaHash, proxies] : feaToProxyMap)
   {
-    for (auto [feaHash, proxies] : feaToProxyMap)
+    auto first = *proxies.begin();
+    for (auto p : proxies)
     {
-      auto first = *proxies.begin();
-      for (auto p : proxies)
+      if (not feaEqual(p->te->getFeatureAccessHelpers(), first->te->getFeatureAccessHelpers()))
       {
-        if (not feaEqual(p->te->getFeatureAccessHelpers(), first->te->getFeatureAccessHelpers()))
-        {
-          ATH_MSG_ERROR("Proxies grouped by FEA hash have actually distinct features (specific FEAs are different)");
-          return StatusCode::FAILURE;
-        }
+        ATH_MSG_ERROR("Proxies grouped by FEA hash have actually distinct features (specific FEAs are different)");
+        for (auto id: p->passChains ) ATH_MSG_ERROR("... chain id for this proxy " << id);
+        ATH_MSG_ERROR(".... TE id of this proxy: " << TrigConf::HLTUtils::hash2string(p->te->getId()));
+        return StatusCode::FAILURE;
       }
     }
   }
 
+
   ATH_CHECK(collapseProxies(convProxies, feaToProxyMap));
   ATH_MSG_DEBUG("Proxies with features collapsing reduces size from " << beforeCount << " to " << convProxies.size());
 
@@ -1116,13 +1141,13 @@ bool feaToSkip(const HLT::TriggerElement::FeatureAccessHelper &fea)
 uint64_t Run2ToRun3TrigNavConverterV2::feaToHash(const std::vector<HLT::TriggerElement::FeatureAccessHelper> &feaVector, const HLT::TriggerElement *te_ptr, const HLT::TrigNavStructure &navigationDecoder) const
 {
   // FEA vectors hashing
-
+  ATH_MSG_VERBOSE("Calculating FEA hash");
   uint64_t hash = 0;
   for (auto fea : feaVector)
   {
     if (feaToSkip(fea))
     {
-      ATH_MSG_VERBOSE("Skipping TrigPassBits in FEA hash calculation");
+      ATH_MSG_VERBOSE("Skipping in FEA hash calculation");
       continue;
     }
 
@@ -1130,28 +1155,33 @@ uint64_t Run2ToRun3TrigNavConverterV2::feaToHash(const std::vector<HLT::TriggerE
 
     if (sgKey == 0)
     {
-      ATH_MSG_VERBOSE("Skipping TrigPassBits in FEA hash calculation - CLID not present: " << sgCLID);
+      ATH_MSG_VERBOSE("Skipping unrecorded (missing in SG) FEA hash calculation - name in SG: " << sgName << " FEA " << fea);
       continue;
     }
 
-    ATH_MSG_DEBUG("feature CLID: " << fea.getCLID() << " te Id: " << te_ptr->getId());
-    uint64_t repr64 = static_cast<uint64_t>(fea.getCLID()) << 32 | static_cast<uint64_t>(fea.getIndex().subTypeIndex()) << 24 | (fea.getIndex().objectsBegin() << 16 ^ fea.getIndex().objectsEnd());
-    hash ^= repr64;
+    ATH_MSG_VERBOSE("Including FEA in hash CLID: " << fea.getCLID() << " te Id: " << te_ptr->getId());
+    boost::hash_combine(hash, fea.getCLID());
+    boost::hash_combine(hash, fea.getIndex().subTypeIndex());
+    boost::hash_combine(hash, fea.getIndex().objectsBegin());
+    boost::hash_combine(hash, fea.getIndex().objectsEnd());
   }
+  ATH_MSG_VERBOSE("Obtained FEA hash " << hash);
   return hash;
 }
 
 bool Run2ToRun3TrigNavConverterV2::feaEqual(const std::vector<HLT::TriggerElement::FeatureAccessHelper> &a,
                                             const std::vector<HLT::TriggerElement::FeatureAccessHelper> &b) const
 {
+  ATH_MSG_VERBOSE("Comparison of FEAs");
   if (a.size() != b.size())
     return false;
 
   for (size_t i = 0; i < a.size(); ++i)
   {
+    ATH_MSG_VERBOSE("Comparison FEA a:" << a[i] << " FEA b:"  << b[i]);
     if (feaToSkip(a[i]) and feaToSkip(b[i]))
     {
-      ATH_MSG_VERBOSE("Skipping TrigPassBits in FEA comparison");
+      ATH_MSG_VERBOSE("Skipping FEA in comparison helper");
       continue;
     }
     if (not(a[i] == b[i]))
diff --git a/Trigger/TrigEvent/TrigNavTools/src/Run2ToRun3TrigNavConverterV2.h b/Trigger/TrigEvent/TrigNavTools/src/Run2ToRun3TrigNavConverterV2.h
index 8c901912291eb545866ded8b3f8574654391e642..99d66649403763c53577f1e136f54de6750dbb82 100644
--- a/Trigger/TrigEvent/TrigNavTools/src/Run2ToRun3TrigNavConverterV2.h
+++ b/Trigger/TrigEvent/TrigNavTools/src/Run2ToRun3TrigNavConverterV2.h
@@ -21,6 +21,7 @@
 #include "TrigDecisionTool/TrigDecisionTool.h"
 #include "TrigConfHLTData/HLTSignature.h"
 #include "TrigConfHLTData/HLTTriggerElement.h"
+#include "TrigConfHLTUtils/HLTUtils.h"
 
 // STL includes
 #include <string>
@@ -136,6 +137,17 @@ private:
 
   bool roiToSave(const HLT::TrigNavStructure &run2Nav, const HLT::TriggerElement::FeatureAccessHelper &fea) const;
 
+  // debugging aid, prints selected proxies
+  void printProxies(const ConvProxySet_t& proxies,
+                    std::function<bool(const ConvProxy*)> selector=[](const ConvProxy*){return true;},
+                    std::vector<std::function<void(const ConvProxy*)>> printers={}) const;
+
+  // useful printers
+  std::function<void(const ConvProxy*)> m_chainIdsPrinter = [&](const ConvProxy* p){ for (auto id: p->passChains ) ATH_MSG_DEBUG("chain id " << id); };
+  std::function<void(const ConvProxy*)> m_teIDPrinter = [&](const ConvProxy* p){ ATH_MSG_DEBUG("TE id " << TrigConf::HLTUtils::hash2string(p->te->getId())); };
+
+
+
   std::size_t getFeaSize(const ConvProxy &) const;
 
   // self validators
diff --git a/Trigger/TrigSteer/DecisionHandling/src/ViewCreatorJetSuperROITool.cxx b/Trigger/TrigSteer/DecisionHandling/src/ViewCreatorJetSuperROITool.cxx
index c15c7b305a9dc2c3745b3d8ae1c34fce7cf67e39..66626859ac068e54ac92c019bbf56863597fc496 100644
--- a/Trigger/TrigSteer/DecisionHandling/src/ViewCreatorJetSuperROITool.cxx
+++ b/Trigger/TrigSteer/DecisionHandling/src/ViewCreatorJetSuperROITool.cxx
@@ -80,16 +80,24 @@ StatusCode ViewCreatorJetSuperROITool::attachROILinks( TrigCompositeUtils::Decis
       double phiMinus = CxxUtils::wrapToPi( jetPhi - m_roiPhiWidth );
       double phiPlus  = CxxUtils::wrapToPi( jetPhi + m_roiPhiWidth );
 
-      // Should retrieve beamspot offset from somewhere
-      double zMinus = -1. * m_roiZWidth;
-      double zPlus  = m_roiZWidth;
-
-      /// don't mess about with unique_ptr here as the pointer management is 
-      /// done by the Roi itself
-      superRoI->push_back( new TrigRoiDescriptor( jetEta, etaMinus, etaPlus,
-						  jetPhi, phiMinus, phiPlus,
-						  0.,zMinus,zPlus ) );
 
+      if ( m_roiZWidth > 0 ) { 
+	// Should retrieve beamspot offset from somewhere
+	double zMinus = -1. * m_roiZWidth;
+	double zPlus  = m_roiZWidth;
+	
+	/// don't mess about with unique_ptr here as the pointer management is 
+	/// done by the Roi itself
+	superRoI->push_back( new TrigRoiDescriptor( jetEta, etaMinus, etaPlus,
+						    jetPhi, phiMinus, phiPlus,
+						    0.,zMinus,zPlus ) );
+      }
+      else {
+	superRoI->push_back( new TrigRoiDescriptor( jetEta, etaMinus, etaPlus,
+						    jetPhi, phiMinus, phiPlus ) );
+      }
+
+	
       /// only set this to true here, just in case. It will still be false, 
       /// if there are no constituents, but it doesn;t really matter one way 
       /// or another in that case 
diff --git a/Trigger/TrigSteer/DecisionHandling/src/ViewCreatorJetSuperROITool.h b/Trigger/TrigSteer/DecisionHandling/src/ViewCreatorJetSuperROITool.h
index 891473eb40777eb5d2ebd9f72a22c1b83e412d87..a456c1349f46fc9f7866c6ac3cb23ec870faef42 100644
--- a/Trigger/TrigSteer/DecisionHandling/src/ViewCreatorJetSuperROITool.h
+++ b/Trigger/TrigSteer/DecisionHandling/src/ViewCreatorJetSuperROITool.h
@@ -61,7 +61,7 @@ public:
     "Extent of the ROI in phi from its centre"};
 
   // Need to get beamspot position from somewhere to recentre?
-  Gaudi::Property< double > m_roiZWidth {this,"RoIZWidth",150.0,
+  Gaudi::Property< double > m_roiZWidth {this,"RoIZWidth",-999,
       "Z Half Width in mm"};
 
 };
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXByteStream/src/gFexByteStreamTool.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXByteStream/src/gFexByteStreamTool.cxx
index 461c362c6e321e88cd763adba55fdc76be784a94..9449c501b51b19baf67a28eea283624c7ba3c678 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXByteStream/src/gFexByteStreamTool.cxx
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXByteStream/src/gFexByteStreamTool.cxx
@@ -469,9 +469,12 @@ int16_t gFexByteStreamTool::fillGlobal(const std::vector<uint32_t> &tob, const i
     if (sum_x > 0x0007FF) sum_x  = 0x0007FF;
     if (sum_y > 0x0007FF) sum_y  = 0x0007FF;
 
-    if (type == 1) {
+    if (type == 1) {//we are considering the scalar case (sum_x = MET and sum_y = SumEt) 
         ATH_MSG_DEBUG("  scalar tob, saving " << scalar << " in X component");
-        sum_x = scalar;
+        sum_x = scalar; //Total MET 
+        if( sum_y > 0x000FFF) sum_y = 0x000FFF; //Overflow control for SumEt
+        if( sum_y < 0) sum_y = 0;
+
     }
 
     ATH_MSG_DEBUG("  fillGlobal type " << type << std::dec << " sum_x " << sum_x << " sum_y " << sum_y);
@@ -490,9 +493,10 @@ int16_t gFexByteStreamTool::fillGlobal(const std::vector<uint32_t> &tob, const i
 
     int MET2 = sum_x * sum_x + sum_y * sum_y;
     int16_t MET = 0x0;
+    MET2 = MET2 >> 12;
+    MET = std::sqrt(MET2);
 
-    if (MET2 > 0x000FFF) MET = 0x000FFF;
-    else MET = std::sqrt(MET2);
+    if (MET > 0x000FFF) MET = 0x000FFF;
 
     return MET;
 
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauAlgoBase.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauAlgoBase.h
index 1c95131be53280246b0769ce6936a02774e89f66..f179c3736a946178cdb9d944048850f723bb3343 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauAlgoBase.h
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauAlgoBase.h
@@ -44,7 +44,8 @@ public:
   setThresholds(const std::vector<unsigned int> & /*rHadThreshold*/,
                 const std::vector<unsigned int> & /*bdtThreshold*/,
                 unsigned int /*etThreshold*/,
-                unsigned int /*etThresholdForRHad*/) override{};
+                unsigned int /*etThresholdForRHad*/,
+		unsigned int /*bdtMinEtThreshold*/) override{};
   virtual void getRCore(std::vector<unsigned int> &rCoreVec) const override;
   virtual unsigned int rCoreCore() const override { return 0; }
   virtual unsigned int rCoreEnv() const override { return 0; }
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauBDT.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauBDT.h
index 3d204b1916edcc2933fa4c18e8e6c0ca58c981ac..303c81ee0fb0e9fa4184c30792a6e87c8c81ff43 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauBDT.h
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauBDT.h
@@ -39,7 +39,9 @@ public:
                                         unsigned int *fracMultipliers);
   void setPointerToBDTThresholdsParam(int index, unsigned int *bdtThresholds);
   void setPointerToETThresholdParam(unsigned int *etThreshold);
-  void setPointerToETThresholdForFracParam(unsigned int *etThresholdForFrac);
+  void setPointerToMaxETParam(unsigned int *maxEtThreshold);
+  void setPointerToBDTMinETParam(unsigned int *bdtMinEtThreshold);
+
   void buildBDTVariables();
   void computeBDTScore();
   void computeETEstimate();
@@ -109,7 +111,8 @@ private:
   unsigned int *m_fracMultipliers[3]{};
   unsigned int *m_bdtThresholds[3]{};
   unsigned int *m_etThreshold{};
-  unsigned int *m_etThresholdForFrac{};
+  unsigned int *m_maxEtThreshold{};
+  unsigned int *m_bdtMinEtThreshold{};
   unsigned int m_bdtScore = 0;
   unsigned int m_bdtScoreShifted = 0;
   unsigned int m_eTEstimate = 0;
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauBDTAlgo.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauBDTAlgo.h
index 786b0b1fae904eca7ad7a82b385f300082e7fe6d..6a61b3c2a1b1d7fa04309a46e6438106ab277f49 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauBDTAlgo.h
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/eFEXtauBDTAlgo.h
@@ -53,7 +53,8 @@ public:
   virtual void setThresholds(const std::vector<unsigned int> &rHadThreshold,
                              const std::vector<unsigned int> &bdtThreshold,
                              unsigned int etThreshold,
-                             unsigned int etThresholdForRHad) override;
+                             unsigned int etThresholdForRHad,
+			     unsigned int bdtMinEtThreshold) override;
 
   // Seed is hard-coded to 1 to reduce eta asymmetry 
   // which is stronger when it's hard-coded to 0 and 
@@ -70,7 +71,8 @@ private:
   unsigned int m_hadFracMultipliers[3];
   unsigned int m_bdtThresholds[3];
   unsigned int m_etThreshold;
-  unsigned int m_etThresholdForHadFrac;
+  unsigned int m_maxEtThreshold;
+  unsigned int m_bdtMinEtThreshold;
 
   unsigned int m_bdtScore;
 
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/gFEXJetAlgo.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/gFEXJetAlgo.h
index 4ee03e2fdcc4c1becf7ec51453392651028bac82..063bede987b738ed13dff07e10265b34dd1c8755 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/gFEXJetAlgo.h
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/L1CaloFEXSim/gFEXJetAlgo.h
@@ -37,7 +37,7 @@ namespace LVL1 {
     /** standard Athena-Algorithm method */
     virtual StatusCode initialize() override;
 
-    virtual void pileUpCalculation(gTowersType &twrs, int rhoThreshold_Max, int rhoThreshold_Min, int inputScale,  int &PUCp) const override;
+    virtual void pileUpCalculation(gTowersType &twrs, int rhoThreshold_Max, int inputScale,  int &PUCp) const override;
     
     virtual std::vector<std::unique_ptr<gFEXJetTOB>> largeRfinder(const gTowersType& Atwr, 
                                                                   const gTowersType& Btwr,
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXFPGA.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXFPGA.cxx
index a79d71a75f08857ec133b3936ea3ff6e86fffdc7..230ed021f0012c97b1b011e5645975b9a57a864c 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXFPGA.cxx
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXFPGA.cxx
@@ -317,6 +317,7 @@ StatusCode eFEXFPGA::execute(eFEXOutputCollection* inputOutputCollection){
       unsigned int RhadBitS = 3;
 
       unsigned int maxEtCountsTau = thr_eTAU.maxEtCounts(m_eFexStep);
+      unsigned int bdtMinEtCounts = thr_eTAU.minIsoEtCounts(m_eFexStep);
       if (eTauTobEt >= maxEtCountsTau) {
         rCoreWP = 3;
         rHadWP = 3;
@@ -331,7 +332,7 @@ StatusCode eFEXFPGA::execute(eFEXOutputCollection* inputOutputCollection){
       threshBDT.push_back(iso_loose.rCore_fw());
       threshBDT.push_back(iso_medium.rCore_fw());
       threshBDT.push_back(iso_tight.rCore_fw());
-      m_eFEXtauBDTAlgoTool->setThresholds(threshRHad, threshBDT, ptTauMinToTopoInEfexCounts, maxEtCountsTau);
+      m_eFEXtauBDTAlgoTool->setThresholds(threshRHad, threshBDT, ptTauMinToTopoInEfexCounts, maxEtCountsTau, bdtMinEtCounts);
       // Re-compute after setting thresholds. 
       // Threshold bits in the BDT algorithm's implementation are computed inside the algorithm class
       m_eFEXtauBDTAlgoTool->compute();
@@ -354,9 +355,12 @@ StatusCode eFEXFPGA::execute(eFEXOutputCollection* inputOutputCollection){
       std::vector<uint32_t> xtobwords;
       std::vector<uint32_t> xtobwordsBDT;
 
-      ATH_MSG_DEBUG("m_id: " << m_id << ", eta_ind: " <<eta_ind << ", phi_ind: " 
-		      <<phi_ind << ", eTauBDTTobEt: " <<eTauBDTTobEt
-		      <<", eTauTobEt: "<<eTauTobEt << ", ptTauMinToTopoCounts: " << ptTauMinToTopoCounts<< ", maxEtCountsTau: " <<maxEtCountsTau << ", bdtScore: "<<bdtScore);
+      ATH_MSG_DEBUG("m_id: " << m_id << ", eta_ind: " << eta_ind << ", phi_ind: "
+		      << phi_ind << ", eTauBDTTobEt: " << eTauBDTTobEt
+		      << ", eTauTobEt: " << eTauTobEt << ", ptTauMinToTopoCounts: "
+		      << ptTauMinToTopoCounts << ", maxEtCountsTau: " << maxEtCountsTau
+		      << ", bdtScore: " << bdtScore << "bdtMinEtCounts: " << bdtMinEtCounts);
+
       uint32_t tobwordBDT = m_eFEXFormTOBsTool->formTauBDTTOBWord(m_id, eta_ind, phi_ind, eTauBDTTobEt, rHadWP, bdtCondition, bdtSeed, ptTauMinToTopoCounts);
       xtobwordsBDT = m_eFEXFormTOBsTool->formTauBDTxTOBWords(m_efexid, m_id, eta_ind, phi_ind, eTauBDTTobEt, rHadWP, bdtCondition, bdtSeed, ptTauMinToTopoCounts, bdtScore);
       uint32_t tobword = m_eFEXFormTOBsTool->formTauTOBWord(m_id, eta_ind, phi_ind, eTauTobEt, rHadWP, rCoreWP, seed, und, ptTauMinToTopoCounts);
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauBDT.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauBDT.cxx
index 80efb1a380bc63e14d999a603ffd720dc766236e..782eea55d4bc4b9619244dc7dfe86d84021f6543 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauBDT.cxx
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauBDT.cxx
@@ -66,9 +66,14 @@ void LVL1::eFEXtauBDT::setPointerToETThresholdParam(unsigned int *etThreshold) {
   m_etThreshold = etThreshold;
 }
 
-void LVL1::eFEXtauBDT::setPointerToETThresholdForFracParam(
-    unsigned int *etThresholdForFrac) {
-  m_etThresholdForFrac = etThresholdForFrac;
+void LVL1::eFEXtauBDT::setPointerToMaxETParam(
+    unsigned int *maxEtThreshold) {
+  m_maxEtThreshold = maxEtThreshold;
+}
+
+void LVL1::eFEXtauBDT::setPointerToBDTMinETParam(
+    unsigned int *bdtMinEtThreshold) {
+  m_bdtMinEtThreshold = bdtMinEtThreshold;
 }
 
 unsigned int *LVL1::eFEXtauBDT::superCellToPtr(int eta, int phi, int layer) {
@@ -171,6 +176,9 @@ void LVL1::eFEXtauBDT::initBDTVars() {
 void LVL1::eFEXtauBDT::next() {
   buildBDTVariables();
   computeTowers();
+  computeETEstimate();
+  computeHADETEstimate();
+  computeEMETEstimate();
   computeBDTCondition();
   computeFracCondition();
   computeIsCentralTowerSeed();
@@ -345,13 +353,9 @@ unsigned int LVL1::eFEXtauBDT::BitLeftShift(unsigned int number, int by,
 }
 
 void LVL1::eFEXtauBDT::computeFracCondition() {
-  computeETEstimate();
-  computeHADETEstimate();
-  computeEMETEstimate();
-
   int n_multipliers = sizeof(m_fracMultipliers) / sizeof(m_fracMultipliers[0]);
 
-  if ((m_eTEstimate >= *m_etThresholdForFrac) or m_eTEstimateOverflow or
+  if ((m_eTEstimate >= *m_maxEtThreshold) or m_eTEstimateOverflow or
       m_HAD_eTEstimateOverflow) {
 
     m_fracCondition = (1 << (n_multipliers - 1)) - 1;
@@ -389,6 +393,13 @@ void LVL1::eFEXtauBDT::computeBDTCondition() {
   // the parameters
   m_bdtScoreShifted = (m_bdtScore >> toShiftRight);
 
+  if ((m_eTEstimate >= *m_maxEtThreshold) or m_eTEstimateOverflow or
+      m_eTEstimate < *m_bdtMinEtThreshold) {
+
+    m_bdtCondition = (1 << (n_thresholds - 1)) - 1;
+    return;
+  }
+
   int i = 0;
   for (; i < n_thresholds; i++) {
     if (m_bdtScoreShifted < *(m_bdtThresholds[i])) {
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauBDTAlgo.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauBDTAlgo.cxx
index cf357c89415fa08cc3db1d265eb7ae122a45828f..ebb2a0f372c011ee7dc248427766d74440effce0 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauBDTAlgo.cxx
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/eFEXtauBDTAlgo.cxx
@@ -108,8 +108,9 @@ void LVL1::eFEXtauBDTAlgo::setThresholdPointers() {
     m_bdtAlgoImpl->setPointerToBDTThresholdsParam(i, &(m_bdtThresholds[i]));
   }
 
-  m_bdtAlgoImpl->setPointerToETThresholdForFracParam(&m_etThresholdForHadFrac);
+  m_bdtAlgoImpl->setPointerToMaxETParam(&m_maxEtThreshold);
   m_bdtAlgoImpl->setPointerToETThresholdParam(&m_etThreshold);
+  m_bdtAlgoImpl->setPointerToBDTMinETParam(&m_bdtMinEtThreshold);
 }
 
 // Calculate reconstructed ET value
@@ -160,11 +161,12 @@ bool LVL1::eFEXtauBDTAlgo::isBDT() const { return true; }
 void LVL1::eFEXtauBDTAlgo::setThresholds(
     const std::vector<unsigned int> &rHadThreshold,
     const std::vector<unsigned int> &bdtThreshold, unsigned int etThreshold,
-    unsigned int etThresholdForRHad) {
+    unsigned int maxEtThreshold, unsigned int bdtMinEtThreshold) {
   for (int i = 0; i < 3; i++) {
     m_hadFracMultipliers[i] = rHadThreshold[i];
     m_bdtThresholds[i] = bdtThreshold[i];
   }
   m_etThreshold = etThreshold;
-  m_etThresholdForHadFrac = etThresholdForRHad;
+  m_maxEtThreshold = maxEtThreshold;
+  m_bdtMinEtThreshold = bdtMinEtThreshold;
 }
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/gFEXJetAlgo.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/gFEXJetAlgo.cxx
index 79b6643ca37927133e515d180cc753f7614b6547..bf3822fc94d5ace5b38398a780f9cf256903bf2d 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/gFEXJetAlgo.cxx
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/gFEXJetAlgo.cxx
@@ -1336,7 +1336,7 @@ void gFEXJetAlgo::jetOutAB(const gTowersType & jets,
 }
 
 
-void gFEXJetAlgo::pileUpCalculation(gTowersType &twrs, int rhoThreshold_Max, int rhoThreshold_Min, int inputScale,  int &PUCp /*, int &PUChres*/) const {
+void gFEXJetAlgo::pileUpCalculation(gTowersType &twrs, int rhoThreshold_Max, int inputScale,  int &PUCp /*, int &PUChres*/) const {
   // input are 50 MeV "fine" scale towers (i.e. inputScale = 1)
   // to use 200 MeV towers use inputScale = 4  
   // PUCp output is the pileup correction for 69 towers at 200 MeV energy scale 
@@ -1352,7 +1352,7 @@ void gFEXJetAlgo::pileUpCalculation(gTowersType &twrs, int rhoThreshold_Max, int
       if (fineGT > FEXAlgoSpaceDefs::fineCeiling ) fineGT = FEXAlgoSpaceDefs::fineCeiling;
       if (fineGT < FEXAlgoSpaceDefs::fineFloor ) fineGT = FEXAlgoSpaceDefs::fineFloor;
 
-      if( (fineGT > rhoThreshold_Min) && (fineGT < rhoThreshold_Max) ) {
+      if( fineGT < rhoThreshold_Max ) {
       pucSum = pucSum + fineGT;
       nSum = nSum + 1;
       }
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/gFEXSim.cxx b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/gFEXSim.cxx
index ad4806f198d7054307f7561821227dfe88577f58..94740de4271d62fbc23a716ea43279abd110f342 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/gFEXSim.cxx
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXSim/src/gFEXSim.cxx
@@ -174,17 +174,11 @@ StatusCode gFEXSim::executegFEXSim(const gTowersIDs& tmp_gTowersIDs_subset, gFEX
    float gLJ_rhoMaxA = 0;
    float gLJ_rhoMaxB = 0;
    float gLJ_rhoMaxC = 0;
-   float gLJ_rhoMinA = 0;
-   float gLJ_rhoMinB = 0;
-   float gLJ_rhoMinC = 0;
-
-   gLJ_rhoMaxA = (thr_gLJ.rhoTowerMax('A'))*1000;//Note that the values are given in GeV but need to be converted in MeV to be used in PU calculation
-   gLJ_rhoMaxB = (thr_gLJ.rhoTowerMax('B'))*1000;//Note that the values are given in GeV but need to be converted in MeV to be used in PU calculation
-   gLJ_rhoMaxC = (thr_gLJ.rhoTowerMax('C'))*1000;//Note that the values are given in GeV but need to be converted in MeV to be used in PU calculation
-   gLJ_rhoMinA = (thr_gLJ.rhoTowerMin('A'))*1000;//Note that the values are given in GeV but need to be converted in MeV to be used in PU calculation
-   gLJ_rhoMinB = (thr_gLJ.rhoTowerMin('B'))*1000;//Note that the values are given in GeV but need to be converted in MeV to be used in PU calculation
-   gLJ_rhoMinC = (thr_gLJ.rhoTowerMin('C'))*1000;//Note that the values are given in GeV but need to be converted in MeV to be used in PU calculation
-   
+ 
+   gLJ_rhoMaxA = 200;//Note that the values are given in GeV but need to be converted in MeV to be used in PU calculation
+   gLJ_rhoMaxB = 200;//Note that the values are given in GeV but need to be converted in MeV to be used in PU calculation
+   gLJ_rhoMaxC = 200;//Note that the values are given in GeV but need to be converted in MeV to be used in PU calculation
+
 
    //Parameters related to gJ (small-R jet objects - gBlock)
    auto & thr_gJ = l1Menu->thrExtraInfo().gJ();
@@ -201,9 +195,9 @@ StatusCode gFEXSim::executegFEXSim(const gTowersIDs& tmp_gTowersIDs_subset, gFEX
    int jetThreshold = FEXAlgoSpaceDefs::jetThr; //this threshold is set by the online software 
 
    if (FEXAlgoSpaceDefs::ENABLE_PUC == true){
-      m_gFEXJetAlgoTool->pileUpCalculation(Atwr50, gLJ_rhoMaxA, gLJ_rhoMinA,  1,  pucA);
-      m_gFEXJetAlgoTool->pileUpCalculation(Btwr50, gLJ_rhoMaxB, gLJ_rhoMinB,  1,  pucB);
-      m_gFEXJetAlgoTool->pileUpCalculation(Ctwr50, gLJ_rhoMaxC, gLJ_rhoMinC,  1,  pucC);
+      m_gFEXJetAlgoTool->pileUpCalculation(Atwr50, gLJ_rhoMaxA,  1,  pucA);
+      m_gFEXJetAlgoTool->pileUpCalculation(Btwr50, gLJ_rhoMaxB,  1,  pucB);
+      m_gFEXJetAlgoTool->pileUpCalculation(Ctwr50, gLJ_rhoMaxC,  1,  pucC);
    }
    
    
@@ -216,14 +210,6 @@ StatusCode gFEXSim::executegFEXSim(const gTowersIDs& tmp_gTowersIDs_subset, gFEX
    std::array<uint32_t, 7> CTOB1_dat = {0};
    std::array<uint32_t, 7> CTOB2_dat = {0};
 
-   // Use the gFEXJetAlgoTool
-
-  //  for(unsigned int irow = 0; irow < FEXAlgoSpaceDefs::ABCrows; irow++ ){
-  //   for(unsigned int icolumn =0; icolumn<FEXAlgoSpaceDefs::ABcolumns; icolumn++){
-  //     // set 18 bits on
-  //     std::cout<<"[executegFEXSim] A: [" << irow << "][" << icolumn << "] " << Asat[irow][icolumn] << ", " << static_cast<unsigned>(Asat[irow][icolumn]) << ", " << static_cast<bool>(Asat[irow][icolumn]) << std::endl;
-  //   }
-  // }
 
    // Pass the energy matrices to the algo tool, and run the algorithms
    auto tobs_v = m_gFEXJetAlgoTool->largeRfinder(Atwr, Btwr, Ctwr, Asat, Bsat, Csat, pucA, pucB, pucC,
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXtauAlgo.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXtauAlgo.h
index f29611b2c23c155525fcd4ad8c00b0c883b79b73..6b97004f0d6daec1dfa99c1d1a9f8c077b01fab0 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXtauAlgo.h
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IeFEXtauAlgo.h
@@ -51,7 +51,12 @@ Interface definition for eFEXtauAlgo
     virtual unsigned int getBDTScore() const = 0;
     virtual unsigned int getBDTCondition() const = 0;
     virtual bool isBDT() const = 0;
-    virtual void setThresholds(const std::vector<unsigned int>& rHadThreshold, const std::vector<unsigned int>& bdtThreshold, unsigned int etThreshold, unsigned int etThresholdForRHad) = 0;
+
+    virtual void setThresholds(const std::vector<unsigned int>& rHadThreshold,
+		    const std::vector<unsigned int>& bdtThreshold,
+		    unsigned int etThreshold,
+		    unsigned int etThresholdForRHad,
+		    unsigned int bdtMinEtThreshold) = 0;
 
   private:
 
diff --git a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IgFEXJetAlgo.h b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IgFEXJetAlgo.h
index 4ca264ee09f25440c652c7b28e7fda414d0382e3..3ca309104b76ec7aad7e8e0aac8aa081d1fde087 100644
--- a/Trigger/TrigT1/L1CaloFEX/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IgFEXJetAlgo.h
+++ b/Trigger/TrigT1/L1CaloFEX/L1CaloFEXToolInterfaces/L1CaloFEXToolInterfaces/IgFEXJetAlgo.h
@@ -24,7 +24,7 @@ Interface definition for eFEXegAlgo
     static const InterfaceID& interfaceID( ) ;
 
 
-    virtual void pileUpCalculation(gTowersType &twrs, int rhoThreshold_Max, int rhoThreshold_Min, int inputScale,  int &PUCp) const = 0;
+    virtual void pileUpCalculation(gTowersType &twrs, int rhoThreshold_Max, int inputScale,  int &PUCp) const = 0;
 
     virtual std::vector<std::unique_ptr<gFEXJetTOB>> largeRfinder(const gTowersType& Atwr, 
                                                                   const gTowersType& Btwr,
diff --git a/Trigger/TrigTools/TrigInDetConfig/CMakeLists.txt b/Trigger/TrigTools/TrigInDetConfig/CMakeLists.txt
index 3d452c4c168353db1890f8099d44ded27ab741f4..2ced2d0d787d5aeeb55b8e31402aa1c564fb53b8 100644
--- a/Trigger/TrigTools/TrigInDetConfig/CMakeLists.txt
+++ b/Trigger/TrigTools/TrigInDetConfig/CMakeLists.txt
@@ -15,3 +15,7 @@ atlas_add_test( trigInDetFastTrackingCfg
 atlas_add_test( TrigTrackingPassFlags
    SCRIPT python -m unittest -v TrigInDetConfig.TrigTrackingPassFlags
    POST_EXEC_SCRIPT nopost.sh )
+
+atlas_add_test( BuildSignatureFlags
+   SCRIPT python -m unittest -v TrigInDetConfig.BuildSignatureFlags
+   POST_EXEC_SCRIPT nopost.sh )
diff --git a/Trigger/TrigTools/TrigInDetConfig/python/BuildSignatureFlags.py b/Trigger/TrigTools/TrigInDetConfig/python/BuildSignatureFlags.py
new file mode 100644
index 0000000000000000000000000000000000000000..257070dfb54957354b445cd9b9995c46da7dc893
--- /dev/null
+++ b/Trigger/TrigTools/TrigInDetConfig/python/BuildSignatureFlags.py
@@ -0,0 +1,796 @@
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+
+from AthenaConfiguration.AthConfigFlags import AthConfigFlags
+from TrkConfig.TrackingPassFlags import createTrackingPassFlags,createITkTrackingPassFlags
+from TrigEDMConfig.TriggerEDM import recordable
+
+from AthenaCommon.Logging import logging
+import AthenaCommon.SystemOfUnits as Units
+import math
+from copy import deepcopy
+from collections.abc import Callable
+
+log = logging.getLogger("__name__")
+
+def defaultTrigTrackingFlags(flags : AthConfigFlags):
+
+  flags.addFlag("input_name",           "")
+  flags.addFlag("name",                 "")
+  flags.addFlag("suffix",               "")
+
+  flags.addFlag("pTmin",                1.*Units.GeV)      #fix - consolidate pTmin and minPT
+  flags.addFlag("TripletDoPPS",         True)
+  flags.addFlag("Triplet_D0Max",        4.0)
+  flags.addFlag("Triplet_D0_PPS_Max",   1.7)
+  flags.addFlag("DoPhiFiltering",       True)
+  flags.addFlag("doZFinder",            False)
+  flags.addFlag("doZFinderOnly",        False)
+  flags.addFlag("doResMon",             False)
+  flags.addFlag("doCloneRemoval",       True)
+  flags.addFlag("doSeedRedundancyCheck",False)
+  flags.addFlag("DoubletDR_Max",        270)
+  flags.addFlag("SeedRadBinWidth",      2)
+  flags.addFlag("holeSearch_FTF",       False)
+  flags.addFlag("electronPID",          False)
+  flags.addFlag("etaHalfWidth",         0.1)
+  flags.addFlag("phiHalfWidth",         0.1)
+  flags.addFlag("zedHalfWidth",        -999)    # don't set this parameter unless it is >= 0)
+  flags.addFlag("doFullScan",           False)
+  flags.addFlag("monPS",                1)
+  flags.addFlag("monPtMin",             1*Units.GeV)
+  flags.addFlag("doTRT",                True)
+  flags.addFlag("keepTrackParameters",  False) # Keep track parameters in conversion to TrackParticles
+  flags.addFlag("UsePixelSpacePoints",  True)
+  flags.addFlag("TrackInitialD0Max",    20.0)
+  flags.addFlag("TrackZ0Max",           300.0)
+  flags.addFlag("isLRT",                False)
+  flags.addFlag("UseTrigSeedML",        0)
+  flags.addFlag("nClustersMin",         7)
+  flags.addFlag("roi",                  "")
+  flags.addFlag("LRT_D0Min",            2.0)
+  flags.addFlag("LRT_HardPtMin",        1.0*Units.GeV)
+  flags.addFlag("doRecord",             True)
+  flags.addFlag("vertex",               "")
+  flags.addFlag("adaptiveVertex",       False)
+  flags.addFlag("addSingleTrackVertices", False)
+  flags.addFlag("TracksMaxZinterval",   1) #mm
+  flags.addFlag("minNSiHits_vtx",       10)        #from vtxCuts
+  flags.addFlag("vertex_jet",           "")
+  flags.addFlag("adaptiveVertex_jet",   False)
+  flags.addFlag("dodEdxTrk",            False)
+  flags.addFlag("doHitDV",              False)
+  flags.addFlag("doDisappearingTrk",    False)
+  flags.addFlag("useDynamicRoiZWidth",  False)
+
+  #precision tracking configuration values
+  #__provisional change__:
+  #the following settings are incorrect but this is what is being used in the production running
+  #at the moment. Setting them explicitly here will prevent trigger count differences in
+  #https://gitlab.cern.ch/atlas/athena/-/merge_requests/56607
+  flags.addFlag("maxRPhiImpact", 10.)
+  flags.addFlag("maxRPhiImpactEM",  50.) # mm       #fix2024 - error - only maxRPhiImpEM used
+  flags.addFlag("maxRPhiImpEM",    300.)
+  flags.maxZImpact = 250.
+  flags.maxEta     = 2.7
+  flags.addFlag("minSiClusters", 7)
+  flags.addFlag("maxSiHoles", 5)
+  flags.maxPixelHoles   = 5
+  flags.addFlag("maxSCTHoles", 5)                   #fix2024 - consolidate names maxSctHoles and others in addFlag here
+  flags.maxDoubleHoles  = 2
+  flags.addFlag("doEmCaloSeed", False)
+
+  flags.useSeedFilter         = False
+  flags.doBremRecoverySi = False                    #fix2023 setTrue for electron once validated
+
+  flags.addFlag("refitROT", True) 
+  flags.addFlag("trtExtensionType", "xf") 
+  flags.addFlag("doTruth",  False)  
+  flags.addFlag("perigeeExpression","BeamLine")   #always use beamline regardless of Reco.EnableHI
+  flags.addFlag("SuperRoI",  False)               #TBD - move to bphys/menu
+  
+  flags.addFlag("trkTracks_FTF",   "")
+  flags.addFlag("trkTracks_IDTrig","")
+  flags.addFlag("tracks_FTF",      "")        
+  flags.addFlag("tracks_IDTrig",   "")  
+
+
+def defaultInDetTrigTrackingFlags() -> AthConfigFlags:
+
+  flags = createTrackingPassFlags()
+  defaultTrigTrackingFlags(flags)
+  
+  flags.minPT = flags.pTmin   #hack to sync pT threshold used in offline and trigger
+    
+  flags.minClusters         = 7   #hardcoded to preserve trigger settings (not used for FTF config)
+  flags.minSiNotShared      = 5
+  flags.maxShared           = 2
+  flags.Xi2max              = 9. 
+  flags.Xi2maxNoAdd         = 25.
+  flags.nHolesMax           = 2
+  flags.nHolesGapMax        = 2
+  flags.nWeightedClustersMin= 6
+  flags.roadWidth           =10.
+      
+  flags.useNewParameterizationTRT = True
+  flags.minTRTonTrk          =9
+
+  #TODO - simple ambiguitues
+  flags.useTIDE_Ambi = False  
+
+  #2023fix - it should read 2
+  flags.maxSiHoles           = 5
+  flags.maxSCTHoles          = 5
+  #end 
+
+  return flags  
+
+def defaultITkTrigTrackingFlags() -> AthConfigFlags:
+  
+  flags = createITkTrackingPassFlags()
+  defaultTrigTrackingFlags(flags)
+  
+  flags.minPT               = [flags.pTmin] #ITk flags have eta dependant settings
+  flags.Xi2max              = [9.]
+  flags.Xi2maxNoAdd         = [25.]
+  flags.nHolesMax           = [2]
+  flags.nHolesGapMax        = [2]
+  flags.nWeightedClustersMin= [6]
+  flags.maxDoubleHoles      = [2]
+  flags.maxPixelHoles       = [5]
+  flags.maxZImpact          = [250.0]
+  flags.doTRT               = False
+  flags.doZFinder           = False
+  flags.DoPhiFiltering      = True
+  flags.UsePixelSpacePoints = True # In LRT cases they use only SCT SP, but for ITk we want pixel SP
+  flags.doDisappearingTrk   = False # Not working yet for ITk
+  flags.doCaloSeededBremSi  = False
+  flags.doCaloSeededAmbiSi  = False
+  flags.DoubletDR_Max       = 150.0
+  
+  return flags
+
+def defaultModeTrigTrackingFlags(flags: AthConfigFlags) -> AthConfigFlags:
+  return flags
+
+def signatureTrigTrackingFlags(mode : str) -> AthConfigFlags:
+
+  signatureSet = {
+    "electron"      : electron,
+    "photon"        : electron,
+    
+    "muon"          : muon,
+    "muonIso"       : muonIso,
+    "muonIsoMS"     : muonIso,
+    "muonCore"      : muon,
+    "muonFS"        : muon,
+    "muonLate"      : muon,
+    
+    "tauCore"       : tauCore,
+    "tauIso"        : tauIso,
+    
+    "bjet"          : bjet,
+    
+    "fullScan"      : fullScan,
+    "FS"            : fullScan,
+    "jetSuper"      : jetSuper,
+
+    "beamSpot"      : beamSpot,
+    "BeamSpot"      : beamSpot,
+    "beamSpotFS"    : beamSpotFS,
+                
+    "cosmics"      : cosmics,
+    "bmumux"       : bmumux,
+    "minBias"      : minBias,
+    
+    "electronLRT"  : electronLRT,
+    "muonLRT"      : muonLRT,
+    "tauLRT"       : tauLRT,
+    "bjetLRT"      : bjetLRT,
+    "fullScanLRT"  : fullScanLRT,
+    "DJetLRT"      : DJetLRT,
+    "DVtxLRT"      : DVtxLRT,
+  }
+
+  flags = AthConfigFlags()
+
+  if   mode == "InDet":                       
+    category = 'Trigger.InDetTracking'        
+    defaults = defaultInDetTrigTrackingFlags  
+  elif mode == "ITk":                         
+    category = 'Trigger.ITkTracking'          
+    defaults = defaultITkTrigTrackingFlags    
+  else:                                       
+    log.error("Acts not supported yet")       
+                                            
+     
+  class categoryGeneratorWrapper():
+    """ wrap function which can be consumed by addFlagsCategory and provide its args """
+    def __init__(self, fun : Callable[[AthConfigFlags, str, str], AthConfigFlags], 
+                 flags : AthConfigFlags, signatureInstance : str, recoMode : str):
+      self.flags = flags
+      self.sig = signatureInstance
+      self.fun = fun
+      self.mode= recoMode
+    def run(self):
+      return self.fun(self.flags,self.sig,self.mode)
+    
+  for i in signatureSet.keys():
+    trackingflags = deepcopy(defaults())
+    a = categoryGeneratorWrapper(signatureSet[i],trackingflags,i,mode)
+    signatureCategory = "{}.{}".format(category,i)
+    flags.addFlagsCategory(signatureCategory,a.run,prefix=True)
+
+  addGlobalFlags(flags, category)        # they should not be needed / backward compatibility
+  
+  return flags
+
+
+def signatureActions(func):
+  """ convenience decorator to automate config steps """
+  def invokeSteps(*args, **kwargs):
+    flagsSig = func(*args, **kwargs)     #invoke signature specific code
+    recoMode = args[2]
+    derivedFromFlags(flagsSig,recoMode)  #invoke code dependant on signature flags
+    return flagsSig
+  return invokeSteps
+
+
+@signatureActions
+def electron(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+  
+  flags.input_name = instanceName
+  flags.name      = "electron"
+  flags.suffix    = "Electron"
+  flags.roi       = "HLT_Roi_Electron"
+  flags.etaHalfWidth        = 0.05   # this size should be increased to 0.1
+  flags.phiHalfWidth        = 0.1
+  flags.doCloneRemoval      = True 
+  flags.doSeedRedundancyCheck = True
+  flags.doTRT               = True
+  flags.keepTrackParameters = True
+  flags.electronPID         = True
+  return flags
+
+@signatureActions
+def muon(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+  
+  flags.input_name = instanceName
+  flags.name      = "muon"
+  flags.suffix    = "Muon"
+  flags.roi       = "HLT_Roi_L2SAMuon"
+  flags.Triplet_D0Max       = 10.0
+  flags.doResMon            = True
+  flags.DoPhiFiltering      = False
+  flags.doSeedRedundancyCheck = True
+  flags.monPtMin            = 12*Units.GeV
+  return flags
+  
+@signatureActions
+def muonIso(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name      = "muonIso"
+  flags.suffix    = "MuonIso"
+  flags.roi       = "HLT_Roi_MuonIso"
+  flags.etaHalfWidth        = 0.35
+  flags.phiHalfWidth        = 0.35
+  flags.zedHalfWidth        = 10.0
+  return flags
+
+@signatureActions
+def tauCore(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+  
+  flags.input_name = instanceName
+  flags.name     = "tauCore"
+  flags.suffix   = "TauCore"
+  flags.roi      = "HLT_Roi_TauCore"
+  flags.pTmin    = flags.minPT = 0.8*Units.GeV
+  flags.holeSearch_FTF = True
+  return flags
+  
+@signatureActions
+def tauIso(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+  
+  flags.input_name = instanceName
+  flags.name     = "tauIso"
+  flags.suffix   = "TauIso"
+  flags.roi      = "HLT_Roi_TauIso"
+  flags.etaHalfWidth   = 0.4
+  flags.phiHalfWidth   = 0.4
+  flags.zedHalfWidth   = 7.0
+  flags.adaptiveVertex = True
+  flags.addSingleTrackVertices = True
+  flags.vertex         = "HLT_IDVertex_Tau"
+  flags.electronPID    = False
+  flags.pTmin          = flags.minPT = 0.8*Units.GeV
+  return flags
+
+@signatureActions
+def bjet(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "bjet"
+  flags.suffix   = "Bjet"
+  flags.roi      = "HLT_Roi_Bjet"
+  flags.etaHalfWidth    = 0.4
+  flags.phiHalfWidth    = 0.4
+  flags.zedHalfWidth    = 10.0
+  flags.pTmin           = flags.minPT = 0.8*Units.GeV
+  flags.Xi2max          = 12.
+  return flags
+
+@signatureActions
+def jetSuper(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "jetSuper"
+  flags.suffix   = "JetSuper"
+  flags.vertex   = "HLT_IDVertex_JetSuper"
+  flags.adaptiveVertex = True
+  flags.addSingleTrackVertices = True
+  flags.roi          = "HLT_Roi_JetSuper"
+  flags.etaHalfWidth = 0.3
+  flags.phiHalfWidth = 0.3
+  flags.doFullScan   = True
+  flags.pTmin = flags.minPT       = 1*Units.GeV
+  #-----
+  flags.doTRT           = False
+  flags.DoubletDR_Max   = 200
+  flags.SeedRadBinWidth = 10
+  flags.doSeedRedundancyCheck = True
+  flags.TripletDoPPS    = False
+  flags.nClustersMin    = 8
+  flags.UseTrigSeedML   = 4
+  flags.roadWidth =         5.
+  return flags
+
+@signatureActions
+def minBias(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "minBias"
+  flags.suffix   = "MinBias"
+  flags.roi      = "HLT_Roi_MinBias"
+  flags.doFullScan      = True
+  flags.pTmin  = flags.minPT         = 0.1*Units.GeV # TODO: double check
+  flags.doTRT           = False      #backward compatibility with EFIDTracking.py:makeInDetPatternRecognition
+  flags.etaHalfWidth    = 3
+  flags.phiHalfWidth    = math.pi
+  flags.doZFinder       = True
+  flags.doZFinderOnly   = True
+  
+  flags.nClustersMin        = 5
+  flags.useSeedFilter       = True
+  flags.maxPrimaryImpact    = 10.*Units.mm
+  flags.maxRPhiImpact       = 10.*Units.mm
+  flags.maxZImpact          = 150.*Units.mm
+  flags.roadWidth           = 20
+  flags.usePrdAssociationTool = False     #for backward compatibility #2023fix?
+  return flags
+  
+@signatureActions
+def beamSpot(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "beamSpot"
+  flags.suffix   = "BeamSpot"
+  flags.roi      = "HLT_Roi_FS"
+  flags.doFullScan      = True
+  flags.doZFinder       = True
+  flags.DoubletDR_Max   = 200
+  flags.SeedRadBinWidth = 10
+  flags.etaHalfWidth    = 3
+  flags.phiHalfWidth    = math.pi
+  flags.doTRT           = False
+  flags.doSeedRedundancyCheck = True
+  flags.doRecord        = False
+  return flags
+
+
+@signatureActions
+def fullScan(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "fullScan"
+  flags.suffix   = "FS"
+  flags.roi      = "HLT_Roi_FS"
+  flags.vertex              = "HLT_IDVertex_FS"
+  flags.adaptiveVertex      = True
+  # these are being evaluated and may be added
+  # flags.addSingleTrackVertices = True
+  # flags.TracksMaxZinterval = 3
+  flags.vertex_jet          = "HLT_IDVertex_FS"
+  flags.adaptiveVertex_jet  = True
+  flags.doFullScan      = True
+  flags.etaHalfWidth    = 3.
+  flags.phiHalfWidth    = math.pi
+  flags.doTRT           = False
+  flags.DoubletDR_Max   = 200
+  flags.SeedRadBinWidth = 10
+  flags.doSeedRedundancyCheck = True
+  flags.TripletDoPPS    = False
+  flags.nClustersMin    = 8
+  flags.UseTrigSeedML   = 4
+  flags.dodEdxTrk         = True
+  flags.doHitDV           = True
+  flags.doDisappearingTrk = True
+  flags.roadWidth =         5.
+  return flags
+
+
+@signatureActions
+def beamSpotFS(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "fullScan"
+  flags.suffix   = "FS"
+  flags.roi      = "HLT_Roi_FS"
+  flags.doFullScan      = True
+  flags.etaHalfWidth    = 3.
+  flags.phiHalfWidth    = math.pi
+  flags.doTRT           = False
+  flags.DoubletDR_Max   = 200
+  flags.SeedRadBinWidth = 10
+  flags.TripletDoPPS    = False
+  flags.nClustersMin    = 8
+  flags.UseTrigSeedML   = 4
+  flags.doRecord        = False
+  return flags
+
+
+@signatureActions
+def cosmics(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name        = "cosmics"
+  flags.suffix      = "Cosmic"
+  flags.roi         = "HLT_Roi_Cosmics"
+  flags.Triplet_D0Max       = 1000.0
+  flags.Triplet_D0_PPS_Max  = 1000.0
+  flags.TrackInitialD0Max   = 1000.
+  flags.TrackZ0Max          = 1000.
+  flags.doTRT           = False      #no real reason except of backward compatibility with
+                                     #EFIDTracking.py:makeInDetPatternRecognition
+                                     #2023fix
+  flags.doFullScan      = True
+  flags.etaHalfWidth    = 3
+  flags.phiHalfWidth    = math.pi
+
+  flags.minPT = flags.pTmin = 0.5*Units.GeV
+  flags.nClustersMin        = 4
+  flags.minSiNotShared      = 3
+  flags.maxShared           = 0
+  flags.nHolesMax           = 3
+  flags.maxSiHoles          = 3
+  flags.maxSCTHoles         = 3
+  flags.maxPixelHoles       = 3
+  flags.maxDoubleHoles      = 1
+  flags.maxPrimaryImpact    = 1000.
+  flags.maxRPhiImpact       = 1000.
+  flags.maxZImpact          = 10000.
+  flags.Xi2max              = 60.  if recoMode=="InDet" else [60.]
+  flags.Xi2maxNoAdd         = 100. if recoMode=="InDet" else [100.] 
+  flags.nWeightedClustersMin= 8
+  flags.useSeedFilter       = True
+  flags.usePrdAssociationTool = False     #for backward compatibility #2023fix?
+  flags.roadWidth =        75.
+  if recoMode=="InDet":
+    flags.minTRTonTrk         = 20
+
+  return flags
+
+@signatureActions
+def bmumux(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name      = "bphysics"
+  flags.suffix    = "Bmumux"
+  flags.roi       = "HLT_Roi_Bmumux"
+  flags.Triplet_D0Max       = 10.
+  flags.DoPhiFiltering      = False
+  flags.etaHalfWidth        = 0.75
+  flags.phiHalfWidth        = 0.75
+  flags.zedHalfWidth        = 50.
+  flags.doSeedRedundancyCheck = True
+  flags.SuperRoI = True
+  return flags
+
+@signatureActions
+def electronLRT(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name       = "electronLRT"
+  flags.suffix     = "ElecLRT"
+  flags.roi        = "HLT_Roi_Electron"
+  flags.etaHalfWidth        = 0.1
+  flags.phiHalfWidth        = 0.4
+  flags.UsePixelSpacePoints = False
+  flags.Triplet_D0Max       = 300.
+  flags.TrackInitialD0Max   = 300.
+  flags.TrackZ0Max          = 500.
+  flags.zedHalfWidth        = 225.
+  flags.keepTrackParameters = True
+  flags.doSeedRedundancyCheck = True
+  flags.nClustersMin        = 8
+  flags.isLRT               = True
+  #pt config
+  flags.maxZImpact        = 500.
+  flags.maxRPhiImpact     = 300.
+  flags.maxRPhiImpactEM   = 300.
+  flags.maxEta            = 2.7
+  flags.maxDoubleHoles    = 0
+  flags.maxSiHoles        = 2
+  flags.maxPixelHoles     = 1
+  flags.maxSCTHoles       = 1
+  flags.minSiClusters     = 8
+  flags.doEmCaloSeed      = False
+  return flags
+
+
+@signatureActions
+def muonLRT(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name       = "muonLRT"
+  flags.suffix     = "MuonLRT"
+  flags.roi        = "HLT_Roi_Muon"
+  flags.UsePixelSpacePoints = False
+  flags.etaHalfWidth        = 0.2
+  flags.phiHalfWidth        = 0.4
+  flags.Triplet_D0Max       = 300.
+  flags.TrackInitialD0Max   = 300.
+  flags.TrackZ0Max          = 500.
+  flags.zedHalfWidth        = 225.
+  flags.doSeedRedundancyCheck = True
+  flags.nClustersMin        = 8
+  flags.isLRT               = True
+  flags.doResMon            = True
+  flags.DoPhiFiltering      = False
+  #pt config
+  flags.maxZImpact        = 500.
+  flags.maxRPhiImpact     = 300.
+  flags.maxRPhiImpEM      = 300.
+  flags.maxEta            = 2.7
+  flags.maxDoubleHoles    = 0
+  flags.maxSiHoles        = 2
+  flags.maxPixelHoles     = 1
+  flags.maxSCTHoles       = 1
+  flags.minSiClusters     = 8
+  flags.doEmCaloSeed      = False
+  return flags
+
+
+
+@signatureActions
+def tauLRT(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "tauLRT"
+  flags.suffix   = "TauLRT"
+  flags.roi      = "HLT_Roi_TauLRT"
+  flags.vertex   = "HLT_IDVertex_Tau" # TODO: does this need renaming?
+  flags.pTmin = flags.minPT       = 0.8*Units.GeV
+  flags.etaHalfWidth = 0.4
+  flags.phiHalfWidth = 0.4
+  flags.zedHalfWidth = 225.
+  flags.doTRT        = True
+  flags.UsePixelSpacePoints = False
+  flags.Triplet_D0Max       = 300.
+  flags.TrackInitialD0Max   = 300.
+  flags.TrackZ0Max          = 500.
+  flags.nClustersMin        = 8
+  flags.isLRT               = True
+  #pt config
+  flags.maxZImpact        = 500.
+  flags.maxRPhiImpact     = 300.
+  flags.maxRPhiImpEM      = 300.
+  flags.maxEta            = 2.7
+  flags.maxDoubleHoles    = 0
+  flags.maxSiHoles        = 2
+  flags.maxPixelHoles     = 1
+  flags.maxSCTHoles       = 1
+  flags.minSiClusters     = 8
+  flags.doEmCaloSeed      = False
+  return flags
+
+
+@signatureActions
+def bjetLRT(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "bjetLRT"
+  flags.suffix   = "BjetLRT"
+  flags.roi      = "HLT_Roi_Bjet"
+  flags.etaHalfWidth = 0.4
+  flags.phiHalfWidth = 0.4
+  flags.UsePixelSpacePoints = False
+  flags.Triplet_D0Max       = 300.
+  flags.TrackInitialD0Max   = 300.
+  flags.TrackZ0Max          = 500.
+  flags.nClustersMin        = 8
+  flags.isLRT               = True
+  #pt config
+  flags.maxZImpact        = 500.
+  flags.maxRPhiImpact     = 300.
+  flags.maxRPhiImpactEM   = 300.
+  flags.maxEta            = 2.7
+  flags.maxDoubleHoles    = 0
+  flags.maxSiHoles        = 2
+  flags.maxPixelHoles     = 1
+  flags.maxSCTHoles       = 1
+  flags.minSiClusters     = 8
+  flags.doEmCaloSeed      = False
+  return flags
+
+
+@signatureActions
+def fullScanLRT(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "fullScanLRT"
+  flags.suffix   = "FSLRT"
+  flags.roi      = "HLT_Roi_FS"
+  flags.doFullScan      = True
+  flags.etaHalfWidth    = 3.
+  flags.phiHalfWidth    = math.pi
+  flags.doTRT           = False
+  flags.doSeedRedundancyCheck = True
+  flags.UsePixelSpacePoints   = False
+  flags.Triplet_D0Max         = 300.
+  flags.TrackInitialD0Max     = 300.
+  flags.TrackZ0Max            = 500.
+  flags.Triplet_D0_PPS_Max    = 300.
+  flags.DoubletDR_Max         = 200
+  flags.nClustersMin          = 8
+  flags.isLRT                 = True
+  #pt config
+  flags.maxZImpact        = 500.
+  flags.maxRPhiImpact     = 300.
+  flags.maxRPhiImpactEM   = 300.
+  flags.maxEta            = 2.7
+  flags.maxDoubleHoles    = 0
+  flags.maxSiHoles        = 2
+  flags.maxPixelHoles     = 1
+  flags.maxSCTHoles       = 1
+  flags.minSiClusters     = 8
+  flags.doEmCaloSeed      = False
+  return flags
+
+
+@signatureActions
+def DJetLRT(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "DJetLRT"
+  flags.suffix   = "DJLRT"
+  flags.roi      = "HLT_Roi_DJ"
+  flags.doFullScan      = False
+  flags.etaHalfWidth    = 0.4
+  flags.phiHalfWidth    = 0.4
+  flags.zedHalfWidth    = 225.
+  flags.doTRT           = False
+  flags.doSeedRedundancyCheck = True
+  flags.UsePixelSpacePoints   = False
+  flags.Triplet_D0Max         = 300.
+  flags.TrackInitialD0Max     = 300.
+  flags.TrackZ0Max            = 500.
+  flags.Triplet_D0_PPS_Max    = 300.
+  flags.DoubletDR_Max         = 200
+  flags.nClustersMin          = 8
+  flags.isLRT                 = True
+  #pt config
+  flags.maxZImpact        = 500.
+  flags.maxRPhiImpact     = 300.
+  flags.maxRPhiImpactEM   = 300.
+  flags.maxEta            = 2.7
+  flags.maxDoubleHoles    = 0
+  flags.maxSiHoles        = 2
+  flags.maxPixelHoles     = 1
+  flags.maxSCTHoles       = 1
+  flags.minSiClusters     = 8
+  flags.doEmCaloSeed      = False
+  return flags
+
+
+@signatureActions
+def DVtxLRT(flags: AthConfigFlags, instanceName: str, recoMode: str) -> AthConfigFlags:
+
+  flags.input_name = instanceName
+  flags.name     = "DVtxLRT"
+  flags.suffix   = "DVLRT"
+  flags.roi      = "HLT_Roi_DV"
+  flags.doFullScan      = False
+  flags.etaHalfWidth    = 0.35
+  flags.phiHalfWidth    = 0.35
+  flags.doTRT           = False
+  flags.doSeedRedundancyCheck = True
+  flags.UsePixelSpacePoints   = False
+  flags.Triplet_D0Max         = 300.
+  flags.TrackInitialD0Max     = 300.
+  flags.TrackZ0Max            = 500.
+  flags.Triplet_D0_PPS_Max    = 300.
+  flags.DoubletDR_Max         = 200
+  flags.nClustersMin          = 8
+  flags.isLRT                 = True
+  #pt config
+  flags.maxZImpact        = 500.
+  flags.maxRPhiImpact     = 300.
+  flags.maxRPhiImpactEM   = 300.
+  flags.maxEta            = 2.7
+  flags.maxDoubleHoles    = 0
+  flags.maxSiHoles        = 2
+  flags.maxPixelHoles     = 1
+  flags.maxSCTHoles       = 1
+  flags.minSiClusters     = 8
+  flags.doEmCaloSeed      = False
+  return flags
+
+
+def derivedFromFlags(flags: AthConfigFlags, recoMode : str):
+
+  flags.trkTracks_FTF     = f'HLT_IDTrkTrack_{flags.suffix}_FTF'
+  flags.trkTracks_IDTrig  = f'HLT_IDTrkTrack_{flags.suffix}_IDTrig'
+  flags.tracks_FTF    = collToRecordable(flags, f'HLT_IDTrack_{flags.suffix}_FTF')
+  flags.tracks_IDTrig = \
+    collToRecordable(flags,"HLT_IDTrack_{}_IDTrig".format(flags.suffix if flags.input_name != "tauIso" else "Tau"))
+
+  if flags.isLRT:
+    flags.minClusters         = 8 if recoMode=="InDet" else [8]
+    flags.nHolesGapMax        = 1 if recoMode=="InDet" else [1]
+    flags.nWeightedClustersMin= 8 if recoMode=="InDet" else [8]
+    flags.maxSiHoles          = 2 if recoMode=="InDet" else [2]
+    flags.maxSCTHoles         = 1 if recoMode=="InDet" else [1]
+    flags.maxPixelHoles       = 1 if recoMode=="InDet" else [1]
+    flags.maxDoubleHoles      = 0 if recoMode=="InDet" else [0]
+    
+  if recoMode == "ITk":
+    flags.extension           = flags.input_name       #needed in the ITk mode?
+
+
+def collToRecordable(flags,name):
+  ret = name
+  signature = flags.input_name
+  firstStage = True if "FTF" in name else False
+  record = True
+  if firstStage:
+    if signature in ["minBias","bjetLRT",
+                     "beamSpot","BeamSpot"]:
+      record = False
+  else:
+    if signature in ["tauCore","tauIso","tauIsoBDT",
+                     "jet","fullScan","FS","jetSuper",
+                     "beamSpot", "BeamSpot","beamSpotFS",
+                     "bjetLRT","DJetLRT","DVtxLRT"]:
+      record = False
+
+  if record:
+    ret = recordable(name)
+      
+  return ret
+
+def addGlobalFlags(flags: AthConfigFlags, category : str):
+  flags.addFlag(f'{category}.RoiZedWidthDefault', 180.0 * Units.mm)
+  flags.addFlag(f'{category}.doGPU', False)
+  flags.addFlag(f'{category}.fixSeedPhi', True)
+
+  
+import unittest
+
+class FlagValuesTest(unittest.TestCase):
+    def setUp(self):
+        from AthenaConfiguration.AllConfigFlags import initConfigFlags
+        flags = initConfigFlags()
+        flags.Trigger.InDetTracking.electron.pTmin=3.
+        self.newflags = flags.cloneAndReplace('Tracking.ActiveConfig', 'Trigger.InDetTracking.electron',  
+                                              keepOriginal = True)
+        self.newflags2 = flags.cloneAndReplace('Tracking.ActiveConfig', 'Trigger.InDetTracking.muonLRT',
+                                               keepOriginal = True)
+        
+    def runTest(self):
+        self.assertEqual(self.newflags.Tracking.ActiveConfig.pTmin,  3.,             msg="Preset value lost")        
+        self.assertEqual(self.newflags.Tracking.ActiveConfig.input_name, "electron", msg="Incorrect config")
+        self.assertEqual(self.newflags2.Tracking.ActiveConfig.input_name, "muonLRT", msg="Incorrect config")
+
+  
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Trigger/TrigTools/TrigInDetConfig/python/ConfigSettings.py b/Trigger/TrigTools/TrigInDetConfig/python/ConfigSettings.py
deleted file mode 100644
index af0e49fead2879892211f71e7f4450f50a6b9931..0000000000000000000000000000000000000000
--- a/Trigger/TrigTools/TrigInDetConfig/python/ConfigSettings.py
+++ /dev/null
@@ -1,514 +0,0 @@
-#  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
-
-__author__ = "Mark Sutton, Matous Vozak"
-__doc__    = "ConfigSettings"
-
-import math
-from TrigInDetConfig.ConfigSettingsBase import _ConfigSettingsBase
-from TrigEDMConfig.TriggerEDM import recordable
-from AthenaCommon.SystemOfUnits import GeV
-
-
-class ConfigSettings_electron( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name      = "electron"
-      self._suffix    = "Electron"
-      self._roi       = "HLT_Roi_Electron"
-      # this soze of 0.05 should be increased to 0.1
-      self._etaHalfWidth        = 0.05
-      self._phiHalfWidth        = 0.1
-      self._doCloneRemoval      = True #Previously False in Run2!
-      self._doSeedRedundancyCheck = True
-      self._doTRT               = True
-      self._keepTrackParameters = True
-      self._electronPID         = True
-
-
-class ConfigSettings_muon( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name      = "muon"
-      self._suffix    = "Muon"
-      self._roi       = "HLT_Roi_L2SAMuon"
-      self._Triplet_D0Max       = 10.0
-      self._doResMon            = True
-      self._DoPhiFiltering      = False
-      self._doSeedRedundancyCheck = True
-      self._monPtMin            = 12*GeV
-
-
-class ConfigSettings_muonIso( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name      = "muonIso"
-      self._suffix    = "MuonIso"
-      self._roi       = "HLT_Roi_MuonIso"
-      self._etaHalfWidth        = 0.35
-      self._phiHalfWidth        = 0.35
-      self._zedHalfWidth        = 10.0
-
-
-class ConfigSettings_tau( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "tau"
-      self._suffix   = "Tau"
-      self._roi      = "HLT_Roi_Tau"
-      self._vertex   = "HLT_IDVertex_Tau"
-      self._adaptiveVertex  = True
-      self._pTmin           = 0.8*GeV
-      self._etaHalfWidth    = 0.4
-      self._phiHalfWidth    = 0.4
-      self._doTRT           = True
-      self._electronPID     = False
-      # potential change coming up ...
-      # self._minNSiHits_vtx = 6
-
-
-class ConfigSettings_tauCore( _ConfigSettingsBase ):
-    def __init__( self ):
-       _ConfigSettingsBase.__init__(self)
-       self._name     = "tauCore"
-       self._suffix   = "TauCore"
-       self._roi      = "HLT_Roi_TauCore"
-       self._pTmin    = 0.8*GeV
-       self._holeSearch_FTF = True
-
-class ConfigSettings_tauIso( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "tauIso"
-      self._suffix   = "TauIso"
-      self._roi      = "HLT_Roi_TauIso"
-      self._etaHalfWidth   = 0.4
-      self._phiHalfWidth   = 0.4
-      self._zedHalfWidth   = 7.0
-      self._adaptiveVertex = True
-      self._addSingleTrackVertices = True
-      self._vertex         = "HLT_IDVertex_Tau"
-      self._electronPID    = False
-      self._pTmin          = 0.8*GeV
-      # potential change coming up ...
-      # self._minNSiHits_vtx = 6
-
-   def tracks_IDTrig(self):
-      if self._doRecord:
-         return recordable('HLT_IDTrack_Tau_IDTrig')
-      else:
-         return 'HLT_IDTrack_Tau_IDTrig'
-
-
-# inherit everythiong from the tauIso instance - only
-# the Roi name is changed to protect the innocent
-class ConfigSettings_tauIsoBDT( ConfigSettings_tauIso ):
-   def __init__( self ):
-      ConfigSettings_tauIso.__init__(self)
-      self._roi      = "HLT_Roi_TauIsoBDT"
-
-
-class ConfigSettings_bjet( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "bjet"
-      self._suffix   = "Bjet"
-      self._roi      = "HLT_Roi_Bjet"
-      self._etaHalfWidth    = 0.4
-      self._phiHalfWidth    = 0.4
-      self._zedHalfWidth    = 10.0
-      self._pTmin  = 0.8*GeV
-
-class ConfigSettings_jetSuper( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "jetSuper"
-      self._suffix   = "JetSuper"
-      self._vertex   = "HLT_IDVertex_JetSuper"
-      self._adaptiveVertex = True
-      self._addSingleTrackVertices = True
-      self._roi          = "HLT_Roi_JetSuper"
-      self._etaHalfWidth = 0.3
-      self._phiHalfWidth = 0.3
-      self._zedHalfWidth = 180.0
-      self._doFullScan   = True
-      self._pTmin        = 1*GeV
-      #-----
-      self._doTRT           = False
-      self._DoubletDR_Max   = 200
-      self._SeedRadBinWidth = 10
-      self._doSeedRedundancyCheck = True
-      self._TripletDoPPS    = False
-      self._nClustersMin    = 8
-      self._UseTrigSeedML   = 4
-
-
-class ConfigSettings_minBias( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "minBias"
-      self._suffix   = "MinBias"
-      self._roi      = "HLT_Roi_MinBias"
-      self._doFullScan      = True
-      self._pTmin           = 0.1*GeV # TODO: double check
-      self._doTRT           = False      #backward compatibility with EFIDTracking.py:makeInDetPatternRecognition
-      self._etaHalfWidth    = 3
-      self._phiHalfWidth    = math.pi
-      self._doZFinder       = True
-      self._doZFinderOnly   = True
-
-
-
-class ConfigSettings_beamSpot( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "beamSpot"
-      self._suffix   = "BeamSpot"
-      self._roi      = "HLT_Roi_FS"
-      self._doFullScan      = True
-      self._doZFinder       = True
-      self._DoubletDR_Max   = 200
-      self._SeedRadBinWidth = 10
-      self._etaHalfWidth    = 3
-      self._phiHalfWidth    = math.pi
-      self._doTRT           = False
-      self._doSeedRedundancyCheck = True
-      self._doRecord        = False
-
-
-class ConfigSettings_fullScan( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "fullScan"
-      self._suffix   = "FS"
-      self._roi      = "HLT_Roi_FS"
-      self._vertex              = "HLT_IDVertex_FS"
-      self._adaptiveVertex      = True
-      # these are being evaluated and may be added
-      # self._addSingleTrackVertices = True
-      # self._TracksMaxZinterval = 3
-      self._vertex_jet          = "HLT_IDVertex_FS"
-      self._adaptiveVertex_jet  = True
-      self._doFullScan      = True
-      self._etaHalfWidth    = 3.
-      self._phiHalfWidth    = math.pi
-      self._doTRT           = False
-      self._DoubletDR_Max   = 200
-      self._SeedRadBinWidth = 10
-      self._doSeedRedundancyCheck = True
-      self._TripletDoPPS    = False
-      self._nClustersMin    = 8
-      self._UseTrigSeedML   = 4
-      self._dodEdxTrk         = True
-      self._doHitDV           = True
-      self._doDisappearingTrk = True
-
-class ConfigSettings_beamSpotFS( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "fullScan"
-      self._suffix   = "FS"
-      self._roi      = "HLT_Roi_FS"
-      self._doFullScan      = True
-      self._etaHalfWidth    = 3.
-      self._phiHalfWidth    = math.pi
-      self._doTRT           = False
-      self._DoubletDR_Max   = 200
-      self._SeedRadBinWidth = 10
-      self._TripletDoPPS    = False
-      self._nClustersMin    = 8
-      self._UseTrigSeedML   = 4
-      self._doRecord        = False
-
-
-class ConfigSettings_cosmics( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name        = "cosmics"
-      self._suffix      = "Cosmic"
-      self._roi         = "HLT_Roi_Cosmics"
-      self._Triplet_D0Max       = 1000.0
-      self._Triplet_D0_PPS_Max  = 1000.0
-      self._TrackInitialD0Max   = 1000.
-      self._TrackZ0Max          = 1000.
-      self._doTRT           = False      #no real reason except of backward compatibility with
-                                         #EFIDTracking.py:makeInDetPatternRecognition
-                                         #2023fix
-      self._doFullScan      = True
-      self._etaHalfWidth    = 3
-      self._phiHalfWidth    = math.pi
-
-
-class ConfigSettings_bmumux( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name      = "bphysics"
-      self._suffix    = "Bmumux"
-      self._roi       = "HLT_Roi_Bmumux"
-      self._Triplet_D0Max       = 10.
-      self._DoPhiFiltering      = False
-      self._etaHalfWidth        = 0.75
-      self._phiHalfWidth        = 0.75
-      self._zedHalfWidth        = 50.
-      self._doSeedRedundancyCheck = True
-      self._SuperRoI = True
-
-   @property
-   def SuperRoI(self):
-      return self._SuperRoI
-       
-
-
-class ConfigSettings_electronLRT( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name       = "electronLRT"
-      self._suffix     = "ElecLRT"
-      self._roi        = "HLT_Roi_Electron"
-      self._etaHalfWidth        = 0.1
-      self._phiHalfWidth        = 0.4
-      self._UsePixelSpacePoints = False
-      self._Triplet_D0Max       = 300.
-      self._TrackInitialD0Max   = 300.
-      self._TrackZ0Max          = 500.
-      self._zedHalfWidth        = 225.
-      self._keepTrackParameters = True
-      self._doSeedRedundancyCheck = True
-      self._nClustersMin        = 8
-      self._isLRT               = True
-      #pt config
-      self._maxZImpact        = 500.
-      self._maxRPhiImpact     = 300.
-      self._maxRPhiImpactEM   = 300.
-      self._maxEta            = 2.7
-      self._maxDoubleHoles    = 0
-      self._maxSiHoles        = 2
-      self._maxPixelHoles     = 1
-      self._maxSCTHoles       = 1
-      self._minSiClusters     = 8
-      self._doEmCaloSeed      = False
-
-      
-class ConfigSettings_muonLRT( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name       = "muonLRT"
-      self._suffix     = "MuonLRT"
-      self._roi        = "HLT_Roi_Muon"
-      self._UsePixelSpacePoints = False
-      self._etaHalfWidth        = 0.2
-      self._phiHalfWidth        = 0.4
-      self._Triplet_D0Max       = 300.
-      self._TrackInitialD0Max   = 300.
-      self._TrackZ0Max          = 500.
-      self._zedHalfWidth        = 225.
-      self._doSeedRedundancyCheck = True
-      self._nClustersMin        = 8
-      self._isLRT               = True
-      self._doResMon            = True
-      self._DoPhiFiltering      = False
-      #pt config
-      self._maxZImpact        = 500.
-      self._maxRPhiImpact     = 300.
-      self._maxRPhiImpEM      = 300.
-      self._maxEta            = 2.7
-      self._maxDoubleHoles    = 0
-      self._maxSiHoles        = 2
-      self._maxPixelHoles     = 1
-      self._maxSCTHoles       = 1
-      self._minSiClusters     = 8
-      self._doEmCaloSeed      = False
-
-
-class ConfigSettings_tauLRT( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "tauLRT"
-      self._suffix   = "TauLRT"
-      self._roi      = "HLT_Roi_TauLRT"
-      self._vertex   = "HLT_IDVertex_Tau" # TODO: does this need renaming?
-      self._pTmin        = 0.8*GeV
-      self._etaHalfWidth = 0.4
-      self._phiHalfWidth = 0.4
-      self._zedHalfWidth = 225.
-      self._doTRT        = True
-      self._UsePixelSpacePoints = False
-      self._Triplet_D0Max       = 300.
-      self._TrackInitialD0Max   = 300.
-      self._TrackZ0Max          = 500.
-      self._nClustersMin        = 8
-      self._isLRT               = True
-      #pt config
-      self._maxZImpact        = 500.
-      self._maxRPhiImpact     = 300.
-      self._maxRPhiImpEM      = 300.
-      self._maxEta            = 2.7
-      self._maxDoubleHoles    = 0
-      self._maxSiHoles        = 2
-      self._maxPixelHoles     = 1
-      self._maxSCTHoles       = 1
-      self._minSiClusters     = 8
-      self._doEmCaloSeed      = False
-
-class ConfigSettings_bjetLRT( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "bjetLRT"
-      self._suffix   = "BjetLRT"
-      self._roi      = "HLT_Roi_Bjet"
-      self._etaHalfWidth = 0.4
-      self._phiHalfWidth = 0.4
-      self._UsePixelSpacePoints = False
-      self._Triplet_D0Max       = 300.
-      self._TrackInitialD0Max   = 300.
-      self._TrackZ0Max          = 500.
-      self._nClustersMin        = 8
-      self._isLRT               = True
-      #pt config
-      self._maxZImpact        = 500.
-      self._maxRPhiImpact     = 300.
-      self._maxRPhiImpactEM   = 300.
-      self._maxEta            = 2.7
-      self._maxDoubleHoles    = 0
-      self._maxSiHoles        = 2
-      self._maxPixelHoles     = 1
-      self._maxSCTHoles       = 1
-      self._minSiClusters     = 8
-      self._doEmCaloSeed      = False
-
-
-class ConfigSettings_fullScanLRT( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "fullScanLRT"
-      self._suffix   = "FSLRT"
-      self._roi      = "HLT_Roi_FS"
-      self._doFullScan      = True
-      self._etaHalfWidth    = 3.
-      self._phiHalfWidth    = math.pi
-      self._doTRT           = False
-      self._doSeedRedundancyCheck = True
-      self._UsePixelSpacePoints   = False
-      self._Triplet_D0Max         = 300.
-      self._TrackInitialD0Max     = 300.
-      self._TrackZ0Max            = 500.
-      self._Triplet_D0_PPS_Max    = 300.
-      self._DoubletDR_Max         = 200
-      self._nClustersMin          = 8
-      self._isLRT                 = True
-      #pt config
-      self._maxZImpact        = 500.
-      self._maxRPhiImpact     = 300.
-      self._maxRPhiImpactEM   = 300.
-      self._maxEta            = 2.7
-      self._maxDoubleHoles    = 0
-      self._maxSiHoles        = 2
-      self._maxPixelHoles     = 1
-      self._maxSCTHoles       = 1
-      self._minSiClusters     = 8
-      self._doEmCaloSeed      = False
-
-
-class ConfigSettings_DJetLRT( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "DJetLRT"
-      self._suffix   = "DJLRT"
-      self._roi      = "HLT_Roi_DJ"
-      self._doFullScan      = False
-      self._etaHalfWidth    = 0.4
-      self._phiHalfWidth    = 0.4
-      self._zedHalfWidth    = 225.
-      self._doTRT           = False
-      self._doSeedRedundancyCheck = True
-      self._UsePixelSpacePoints   = False
-      self._Triplet_D0Max         = 300.
-      self._TrackInitialD0Max     = 300.
-      self._TrackZ0Max            = 500.
-      self._Triplet_D0_PPS_Max    = 300.
-      self._DoubletDR_Max         = 200
-      self._nClustersMin          = 8
-      self._isLRT                 = True
-      #pt config
-      self._maxZImpact        = 500.
-      self._maxRPhiImpact     = 300.
-      self._maxRPhiImpactEM   = 300.
-      self._maxEta            = 2.7
-      self._maxDoubleHoles    = 0
-      self._maxSiHoles        = 2
-      self._maxPixelHoles     = 1
-      self._maxSCTHoles       = 1
-      self._minSiClusters     = 8
-      self._doEmCaloSeed      = False
-
-
-
-class ConfigSettings_DVtxLRT( _ConfigSettingsBase ):
-   def __init__( self ):
-      _ConfigSettingsBase.__init__(self)
-      self._name     = "DVtxLRT"
-      self._suffix   = "DVLRT"
-      self._roi      = "HLT_Roi_DV"
-      self._doFullScan      = False
-      self._etaHalfWidth    = 0.35
-      self._phiHalfWidth    = 0.35
-      self._doTRT           = False
-      self._doSeedRedundancyCheck = True
-      self._UsePixelSpacePoints   = False
-      self._Triplet_D0Max         = 300.
-      self._TrackInitialD0Max     = 300.
-      self._TrackZ0Max            = 500.
-      self._Triplet_D0_PPS_Max    = 300.
-      self._DoubletDR_Max         = 200
-      self._nClustersMin          = 8
-      self._isLRT                 = True
-      #pt config
-      self._maxZImpact        = 500.
-      self._maxRPhiImpact     = 300.
-      self._maxRPhiImpactEM   = 300.
-      self._maxEta            = 2.7
-      self._maxDoubleHoles    = 0
-      self._maxSiHoles        = 2
-      self._maxPixelHoles     = 1
-      self._maxSCTHoles       = 1
-      self._minSiClusters     = 8
-      self._doEmCaloSeed      = False
-
-
-ConfigSettingsInstances = {
-   "electron"     : ConfigSettings_electron(),
-   "photon"       : ConfigSettings_electron(),
-
-    "muon"        : ConfigSettings_muon(),
-    "muonIso"     : ConfigSettings_muonIso(),
-    "muonIsoMS"   : ConfigSettings_muonIso(),
-    "muonCore"    : ConfigSettings_muon(),
-    "muonFS"      : ConfigSettings_muon(),
-    "muonLate"    : ConfigSettings_muon(),
-
-    "tau"         : ConfigSettings_tau(),
-    "tauTau"      : ConfigSettings_tau(),
-    "tauCore"     : ConfigSettings_tauCore(),
-    "tauIso"      : ConfigSettings_tauIso(),
-    "tauIsoBDT"   : ConfigSettings_tauIsoBDT(),
-
-    "bjet"        : ConfigSettings_bjet(),
-
-    "fullScan"    : ConfigSettings_fullScan(),
-    "FS"          : ConfigSettings_fullScan(),
-    "jetSuper"    : ConfigSettings_jetSuper(),
-
-    "beamSpot"    : ConfigSettings_beamSpot(),
-    "BeamSpot"    : ConfigSettings_beamSpot(),
-    "beamSpotFS"  : ConfigSettings_beamSpotFS(),
-
-    "cosmics"     : ConfigSettings_cosmics(),
-    "bmumux"      : ConfigSettings_bmumux(),
-    "minBias"     : ConfigSettings_minBias(),
-
-    "electronLRT"    : ConfigSettings_electronLRT(),
-    "muonLRT"        : ConfigSettings_muonLRT(),
-    "tauLRT"         : ConfigSettings_tauLRT(),
-    "bjetLRT"        : ConfigSettings_bjetLRT(),
-    "fullScanLRT"    : ConfigSettings_fullScanLRT(),
-    "DJetLRT"        : ConfigSettings_DJetLRT(),
-    "DVtxLRT"        : ConfigSettings_DVtxLRT() }
diff --git a/Trigger/TrigTools/TrigInDetConfig/python/ConfigSettingsBase.py b/Trigger/TrigTools/TrigInDetConfig/python/ConfigSettingsBase.py
deleted file mode 100644
index 306bff02fbe18b5e719e3a23a588082e2609041c..0000000000000000000000000000000000000000
--- a/Trigger/TrigTools/TrigInDetConfig/python/ConfigSettingsBase.py
+++ /dev/null
@@ -1,424 +0,0 @@
-#  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
-
-__author__ = "Mark Sutton, Matous Vozak"
-__doc__    = "ConfigSettingsBase"
-
-
-
-
-from TrigEDMConfig.TriggerEDM import recordable
-from AthenaCommon.SystemOfUnits import GeV
-
-class _ConfigSettingsBase() :
-   def __init__( self ) :
-     # default values
-      self._input_name          = None
-      self._name                = None
-      self._suffix              = None
-      self._pTmin               = 1.*GeV
-      self._TripletDoPPS        = True
-      self._Triplet_D0Max       = 4.0
-      self._Triplet_D0_PPS_Max  = 1.7
-      self._DoPhiFiltering      = True
-      self._doZFinder           = False
-      self._doZFinderOnly       = False
-      self._doResMon            = False
-      self._doCloneRemoval      = True
-      self._doSeedRedundancyCheck = False
-      self._DoubletDR_Max       = 270
-      self._SeedRadBinWidth     = 2
-      self._holeSearch_FTF      = False
-      self._electronPID         = False
-      self._etaHalfWidth        = 0.1
-      self._phiHalfWidth        = 0.1
-      self._zedHalfWidth        = -999 # don't set this parameter unless it is >= 0
-      self._doFullScan          = False
-      self._monPS               = 1
-      self._monPtMin            = 1*GeV
-      self._doTRT               = True
-      self._keepTrackParameters = False # Keep track parameters in conversion to TrackParticles
-      self._UsePixelSpacePoints = True
-      self._TrackInitialD0Max   = 20.0
-      self._TrackZ0Max          = 300.0
-      self._isLRT               = False
-      self._UseTrigSeedML       = 0
-      self._nClustersMin        = 7
-      self._roi                 = None
-      self._isLRT               = False
-      self._LRT_D0Min            = 2.0
-      self._LRT_HardPtMin        = 1.0*GeV
-      self._doRecord            = True
-      self._vertex              = None
-      self._adaptiveVertex      = False
-      self._addSingleTrackVertices = False
-      self._TracksMaxZinterval  = 1 #mm
-      self._minNSiHits_vtx      = 10        #from vtxCuts
-      self._vertex_jet          = None
-      self._adaptiveVertex_jet  = False
-      self._dodEdxTrk           = False 
-      self._doHitDV             = False 
-      self._doDisappearingTrk   = False
-      self._useDynamicRoiZWidth = False
-
-      #precision tracking configuration values
-      #__provisional change__:
-      #the following settings are incorrect but this is what is being used in the production running
-      #at the moment. Setting them explicitly here will prevent trigger count differences in
-      #https://gitlab.cern.ch/atlas/athena/-/merge_requests/56607
-      self._maxRPhiImpact   = 10.
-      self._maxRPhiImpactEM = 50. # mm
-      self._maxZImpact      = 250.
-      self._maxEta          = 2.7
-      self._minSiClusters   = 7
-      self._maxSiHoles      = 5
-      self._maxPixelHoles   = 5
-      self._maxSCTHoles    = 5
-      self._maxDoubleHoles  = 2
-      self._usePixel        = None
-      self._useSCT          = None
-      self._doEmCaloSeed    = None
-      self._minTRTonTrk     = None
-      self._useSiSPSeededTrackFinder = False
-
-      if hasattr(self.__class__, 'override') and callable(getattr(self.__class__, 'override')) :
-         self.override()
-
-   # assign to this override method to add additional global functionality 
-   # to the base class, such as to globally override any of the 
-   # variables above
-   # def override(self):   
-   #      pass
-
-   def tracks_FTF(self):
-      if not self._suffix:
-         raise Exception( "ID Trigger configuration:  called with non existent slice: ", self._name, self._input_name  )
-      if self._doRecord:
-         return recordable('HLT_IDTrack_{}_FTF'.format( self._suffix ))
-      else:
-         return 'HLT_IDTrack_{}_FTF'.format( self._suffix )
-
-   def tracks_IDTrig(self):
-      if self._doRecord:
-         return recordable('HLT_IDTrack_{}_IDTrig'.format( self._suffix ))
-      else:
-         return 'HLT_IDTrack_{}_IDTrig'.format( self._suffix )
-
-
-   def trkTracks_FTF(self):
-         return 'HLT_IDTrkTrack_{}_FTF'.format( self._suffix )
-
-   def trkTracks_IDTrig(self):
-         return 'HLT_IDTrkTrack_{}_IDTrig'.format( self._suffix )
-
-   @property
-   def name(self):
-      return self._name
-
-   @property
-   def input_name(self):
-      return self._input_name
-
-   @property
-   def suffix(self):
-      return self._suffix
-
-   @property
-   def pTmin(self):
-      return self._pTmin
-
-   @property
-   def TripletDoPPS(self):
-      return self._TripletDoPPS
-
-   @property
-   def Triplet_D0Max(self):
-      return self._Triplet_D0Max
-
-   @property
-   def Triplet_D0_PPS_Max(self):
-      return self._Triplet_D0_PPS_Max
-
-   @property
-   def DoPhiFiltering(self):
-      return self._DoPhiFiltering
-
-   @property
-   def doZFinder(self):
-      return self._doZFinder
-
-   @property
-   def doZFinderOnly(self):
-      return self._doZFinderOnly
-
-   @property
-   def doResMon(self):
-      return self._doResMon
-
-   @property
-   def electronPID(self):
-      return self._electronPID
-
-   @property
-   def doCloneRemoval(self):
-      return self._doCloneRemoval
-
-   @property
-   def doSeedRedundancyCheck(self):
-      return self._doSeedRedundancyCheck
-
-   @property
-   def DoubletDR_Max(self):
-      return self._DoubletDR_Max
-
-   @property
-   def SeedRadBinWidth(self):
-      return self._SeedRadBinWidth
-
-   @property
-   def etaHalfWidth(self):
-      return self._etaHalfWidth
-
-   @property
-   def phiHalfWidth(self):
-      return self._phiHalfWidth
-
-   @property
-   def zedHalfWidth(self):
-      return self._zedHalfWidth
-
-   @property
-   def doFullScan(self):
-      return self._doFullScan
-
-   @property
-   def monPS(self):
-      return self._monPS
-
-   @property
-   def monPtMin(self):
-      return self._monPtMin
-
-   @property
-   def doTRT(self):
-      return self._doTRT
-
-   @property
-   def keepTrackParameters(self):
-      return self._keepTrackParameters
-
-   @property
-   def UsePixelSpacePoints(self):
-       return self._UsePixelSpacePoints
-
-   @property
-   def TrackInitialD0Max(self):
-       return self._TrackInitialD0Max
-
-   @property
-   def holeSearch_FTF(self):
-       return self._holeSearch_FTF
-
-   @property
-   def TrackZ0Max(self):
-       return self._TrackZ0Max
-
-   @property
-   def isLRT(self):
-       return self._isLRT
-
-   @property
-   def LRT_D0Min(self):
-       return self._LRT_D0Min
-
-   @property
-   def LRT_HardMinPt(self):
-       return self._LRT_HardPtMin
-
-   @property
-   def roi(self):
-      return self._roi
-
-   @property
-   def UseTrigSeedML(self):
-      return self._UseTrigSeedML
-
-   @property
-   def nClustersMin(self):
-      return self._nClustersMin
-
-   @property
-   def isRecordable(self):
-      return self._doRecord
-
-   @property
-   def doRecord(self):
-      return self._doRecord
-
-   @property
-   def vertex(self):
-      if not self._vertex:
-         raise Exception( "ID Trigger configuration: vertex not defined for slice: ", self._name, self._input_name  )
-      if self._doRecord:
-         return recordable(self._vertex)
-      else:
-         return self._vertex
-
-   @property
-   def vertex_jet(self):
-      if not self._vertex_jet:
-         raise Exception( "ID Trigger configuration: vertex_jet not defined for slice: ", self._name, self._input_name  )
-      if self._doRecord:
-         return recordable(self._vertex_jet)
-      else:
-         return self._vertex_jet
-
-   @property
-   def adaptiveVertex(self):
-       return self._adaptiveVertex
-
-   @property
-   def adaptiveVertex_jet(self):
-       return self._adaptiveVertex_jet
-
-   @property
-   def addSingleTrackVertices(self):
-       return self._addSingleTrackVertices
-
-   @property
-   def minNSiHits_vtx(self):
-       return self._minNSiHits_vtx
-
-   @property
-   def TracksMaxZinterval(self):
-      return self._TracksMaxZinterval
-
-   @property
-   def dodEdxTrk(self):
-       return self._dodEdxTrk
-
-   @property
-   def doHitDV(self):
-       return self._doHitDV
-
-   @property
-   def doDisappearingTrk(self):
-       return self._doDisappearingTrk
-
-   @property
-   def usePixelNN(self):
-     raise Exception( "ID Trigger configuration:  usePixelNN not implemented temporarily")
-
-   @property
-   def maxRPhiImpact(self):
-      return self._maxRPhiImpact
-
-   @property
-   def maxRPhiImpactEM(self):
-      return self._maxRPhiImpactEM
-
-   @property
-   def maxZImpact(self):
-      return self._maxZImpact
-
-   @property
-   def maxEta(self):
-      return self._maxEta
-
-   @property
-   def minSiClusters(self):
-      return self._minSiClusters
-
-   @property
-   def maxSiHoles(self):
-      return self._maxSiHoles
-
-   @property
-   def maxPixelHoles(self):
-      return self._maxPixelHoles
-
-   @property
-   def maxSCTHoles(self):
-      return self._maxSCTHoles
-
-   @property
-   def maxDoubleHoles(self):
-      return self._maxDoubleHoles
-
-   @property
-   def usePixel(self):
-      return self._usePixel
-   
-   @property
-   def useSCT(self):
-      return self._useSCT
-   
-   @property
-   def doEmCaloSeed(self):
-      return self._doEmCaloSeed
-
-   @property
-   def minTRTonTrk(self):
-      return self._minTRTonTrk
-
-   @property
-   def useDynamicRoiZWidth(self):
-      return self._useDynamicRoiZWidth
-
-   @property
-   def useSiSPSeededTrackFinder(self):
-      return self._useSiSPSeededTrackFinder
-
-   def printout(self):
-      from AthenaCommon.Logging import logging
-      log = logging.getLogger("InDetTrigConfig: ")
-
-      log.info( " %s :", self._name )
-      log.info( " %s :", self._input_name )
-      log.info( "   pTmin                 : %s", self._pTmin )
-      log.info( "   TripletDoPPS          : %s", self._TripletDoPPS )
-      log.info( "   Triplet_D0Max         : %s", self._Triplet_D0Max )
-      log.info( "   Triplet_D0_PPS_Max    : %s", self._Triplet_D0_PPS_Max )
-      log.info( "   doZFinder             : %s", self._doZFinder )
-      log.info( "   doResMon              : %s", self._doResMon )
-      log.info( "   DoPhiFiltering        : %s", self._DoPhiFiltering )
-      log.info( "   doCloneRemoval        : %s", self._doCloneRemoval )
-      log.info( "   doSeedRedundancyCheck : %s", self._doSeedRedundancyCheck )
-      log.info( "   DoubletDR_Max         : %s", self._DoubletDR_Max )
-      log.info( "   SeedRadBinWidth       : %s", self._SeedRadBinWidth )
-      log.info( "   etaHalfWidth          : %s", self._etaHalfWidth )
-      log.info( "   phiHalfWidth          : %s", self._phiHalfWidth )
-      log.info( "   doFullScan            : %s", self._doFullScan )
-      log.info( "   monPS                 : %s", self._monPS )
-      log.info( "   monPtMin              : %s", self._monPtMin )
-      log.info( "   doTRT                 : %s", self._doTRT )
-      log.info( "   keepTrackParameters   : %s", self._keepTrackParameters )
-      log.info( "   UsePixelSpacePoints   : %s", self._UsePixelSpacePoints )
-      log.info( "   TrackInitialD0Max     : %s", self._TrackInitialD0Max )
-      log.info( "   TrackZ0Max            : %s", self._TrackZ0Max )
-      log.info( "   adaptiveVertex        : %s", self._adaptiveVertex )
-      log.info( "   isLRT                 : %s", self._isLRT )
-      log.info( "   LRTD0Min              : %s", self._LRT_D0Min )
-      log.info( "   LRTHardPtmin          : %s", self._LRT_HardPtMin )
-      log.info( "   doHitDV               : %s", self._doHitDV )
-      log.info( "   nClustersMin          : %s", self._nClustersMin )
-      log.info( "   suffix                : %s", self._suffix )
-      log.info( "   roi                   : %s", self._roi )
-      log.info( "   addSingleTrackVertices: %s", self._addSingleTrackVertices )
-      log.info( "   maxRPhiImpact         : %s", self._maxRPhiImpact )
-      log.info( "   maxRPhiImpactEM       : %s", self._maxRPhiImpactEM )
-      log.info( "   maxZImpact            : %s", self._maxZImpact )
-      log.info( "   maxEta                : %s", self._maxEta )
-      log.info( "   maxSiHoles            : %s", self._maxSiHoles )
-      log.info( "   maxPixelHoles         : %s", self._maxPixelHoles )
-      log.info( "   maxSCTHoles           : %s", self._maxSCTHoles )
-      log.info( "   maxDoubleHoles        : %s", self._maxDoubleHoles )
-      log.info( "   usePixel              : %s", self._usePixel )
-      log.info( "   useSCT                : %s", self._useSCT )
-      log.info( "   doEmCaloSeed          : %s", self._doEmCaloSeed )
-      log.info( "   minTRTonTrk           : %s", self._minTRTonTrk )
-      log.info( "   useDynamicRoiZWidth   : %s", self._useDynamicRoiZWidth )
-      log.info( "   useSiSPSeededTrackFinder : %s", self._useSiSPSeededTrackFinder )
-
-if __name__=='__main__':
-   config = _ConfigSettingsBase()
-   config.printout()
diff --git a/Trigger/TrigTools/TrigInDetConfig/python/TrigTrackingPassFlags.py b/Trigger/TrigTools/TrigInDetConfig/python/TrigTrackingPassFlags.py
index 61c43c149fb879b6724b931085eb24cadc3c573b..a29408dac1c8f2168634b15da707aab70248de01 100644
--- a/Trigger/TrigTools/TrigInDetConfig/python/TrigTrackingPassFlags.py
+++ b/Trigger/TrigTools/TrigInDetConfig/python/TrigTrackingPassFlags.py
@@ -1,189 +1,12 @@
-# Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 import AthenaCommon.SystemOfUnits as Units
 
-from TrkConfig.TrackingPassFlags import createTrackingPassFlags,createITkTrackingPassFlags
-from TrigEDMConfig.TriggerEDM import recordable
 
-def signatureSpecificSettingOfFlags(flags,mode):
-  
-  #temporary - to be reworked
-  if mode=="InDet":
-    flags.minPT = flags.pTmin   #hack to sync pT threshold used in offline and trigger
-    
-    flags.minClusters         = 7   #hardcoded to preserve trigger settings (not used for FTF config)
-    flags.minSiNotShared      = 5
-    flags.maxShared           = 2
-    flags.Xi2max              = 9. if flags.input_name != "bjet" else 12.
-    flags.Xi2maxNoAdd         = 25.
-    flags.nHolesMax           = 2
-    flags.nHolesGapMax        = 2
-    flags.nWeightedClustersMin= 6
-    flags.roadWidth           =10.
-    if flags.input_name in ['jetSuper','fullScan','fullScanUTT']:
-      flags.roadWidth =         5.
-    elif flags.input_name == 'cosmics':
-      flags.roadWidth =        75.
-      
-    flags.useNewParameterizationTRT = True
-    flags.minTRTonTrk          =9
-
-    #TODO - simple ambiguitues
-    flags.useTIDE_Ambi = False  
-
-    #2023fix - it should read 2
-    flags.maxSiHoles           = 5
-    flags.maxSCTHoles          = 5
-    #end 
-    
-  else:                         #ITk specific settings can be done here while we rely on ConfigSettings
-    flags.minPT = [flags.pTmin] #ITk flags have eta dependant settings
-    flags.Xi2max              = [9.]
-    flags.Xi2maxNoAdd         = [25.]
-    flags.nHolesMax           = [2]
-    flags.nHolesGapMax        = [2]
-    flags.nWeightedClustersMin= [6]
-    flags.maxDoubleHoles      = [2]
-    flags.maxPixelHoles       = [5]
-    flags.maxZImpact          = [250.0]
-    flags.doTRT               = False
-    flags.extension           = flags.input_name
-    flags.doZFinder           = False
-    flags.DoPhiFiltering      = True
-    flags.UsePixelSpacePoints = True # In LRT cases they use only SCT SP, but for ITk we want pixel SP
-    flags.doDisappearingTrk   = False # Not working yet for ITk
-    flags.doCaloSeededBremSi  = False
-    flags.doCaloSeededAmbiSi  = False
-    flags.DoubletDR_Max       = 150.0
-  
-  flags.useSeedFilter         = False
-
-  if flags.isLRT:
-    flags.minClusters         = 8 if mode=="InDet" else [8]
-    flags.nHolesGapMax        = 1 if mode=="InDet" else [1]
-    flags.nWeightedClustersMin= 8 if mode=="InDet" else [8]
-    flags.maxSiHoles          = 2 if mode=="InDet" else [2]
-    flags.maxSCTHoles         = 1 if mode=="InDet" else [1]
-    flags.maxPixelHoles       = 1 if mode=="InDet" else [1]
-    flags.maxDoubleHoles      = 0 if mode=="InDet" else [0]
-    
-  if flags.input_name=="cosmics":
-    flags.minPT               = 0.5*Units.GeV
-    flags.nClustersMin        = 4
-    flags.minSiNotShared      = 3
-    flags.maxShared           = 0
-    flags.nHolesMax           = 3
-    flags.maxSiHoles          = 3
-    flags.maxSCTHoles         = 3
-    flags.maxPixelHoles       = 3
-    flags.maxDoubleHoles      = 1
-    flags.maxPrimaryImpact    = 1000.
-    flags.maxRPhiImpact       = 1000.
-    flags.maxZImpact          = 10000.
-    flags.Xi2max              = 60.  if mode=="InDet" else [60.]
-    flags.Xi2maxNoAdd         = 100. if mode=="InDet" else [100.]
-    flags.nWeightedClustersMin= 8
-    flags.minTRTonTrk         = 20
-    flags.useSeedFilter       = True
-    flags.usePrdAssociationTool = False     #for backward compatibility #2023fix?
-    
-  elif flags.input_name=="minBias":
-    flags.minPT               = 0.1*Units.GeV
-    flags.nClustersMin        = 5
-    flags.useSeedFilter       = True
-    flags.maxPrimaryImpact    = 10.*Units.mm
-    flags.maxRPhiImpact       = 10.*Units.mm
-    flags.maxZImpact          = 150.*Units.mm
-    flags.roadWidth           = 20
-    flags.usePrdAssociationTool = False     #for backward compatibility #2023fix?
-
-  flags.doBremRecoverySi = False  #setTrue for electron once validated
-    
-  def collToRecordable(flags,name):
-    ret = name
-    signature = flags.input_name
-    firstStage = True if "FTF" in name else False
-    record = True
-    if firstStage:
-      if signature in ["tau","tauTau",
-                       "minBias","bjetLRT",
-                       "beamSpot","BeamSpot"]:
-        record = False
-    else:
-      if signature in ["tauCore","tauIso","tauIsoBDT",
-                       "jet","fullScan","FS","jetSuper",
-                       "beamSpot", "BeamSpot","beamSpotFS",
-                       "bjetLRT","DJetLRT","DVtxLRT"]:
-        record = False
-
-    if record:
-      ret = recordable(name)
-      
-    return ret
-
-  flags.addFlag("trkTracks_FTF",    f'HLT_IDTrkTrack_{flags.suffix}_FTF')
-  flags.addFlag("trkTracks_IDTrig", f'HLT_IDTrkTrack_{flags.suffix}_IDTrig')
-  flags.addFlag("tracks_FTF",    
-                collToRecordable(flags, f'HLT_IDTrack_{flags.suffix}_FTF'))
-  flags.addFlag("tracks_IDTrig", 
-                collToRecordable(flags, "HLT_IDTrack_{}_IDTrig".format(flags.suffix if flags.input_name != "tauIso" else "Tau")))
-
-  flags.addFlag("refitROT", True) 
-  flags.addFlag("trtExtensionType", "xf") 
-  flags.addFlag("doTruth",  False)  
-  flags.addFlag("perigeeExpression","BeamLine")   #always use beamline regardless of Reco.EnableHI
-  
 def createTrigTrackingPassFlags(mode="InDet"):
-  def __flagsFromConfigSettings(settings, mode):
-    if mode == "InDet":
-      flags = createTrackingPassFlags()
-    elif mode == "ITk":
-      flags = createITkTrackingPassFlags()
-    else:
-      raise RuntimeError("createTrigTrackingPassFlags cannot create flags for detector not in InDet or ITk: {}".format(mode)) 
-  
-    for setting, value in settings.__dict__.items():
-        setting = setting.lstrip("_")
-        if setting in flags._flagdict:
-            if value is not None: 
-                flags._flagdict[setting].set(value)
-        else:
-            if value is None: 
-                flags.addFlag(setting, lambda pf: None)
-            else:
-                flags.addFlag(setting, value)
-
-    signatureSpecificSettingOfFlags(flags,mode)
 
-    return flags
-    
-  #hide instantiation of flags in a function that can be consumed by addFlagsCategory
-  def flagsFactory(settings,mode):
-    def hidearg():
-        return __flagsFromConfigSettings(settings,mode)
-    return hidearg
+  from TrigInDetConfig.BuildSignatureFlags import signatureTrigTrackingFlags
+  return signatureTrigTrackingFlags(mode)
 
-  from AthenaConfiguration.AthConfigFlags import AthConfigFlags
-  flags = AthConfigFlags()
-  
-  from TrigInDetConfig.ConfigSettings import ConfigSettingsInstances
-  def __getInDetTrigConfig(name : str):
-    config = ConfigSettingsInstances[name]
-    config._input_name = name
-    return config
-  
-  category = 'Trigger.InDetTracking' if mode=="InDet" else 'Trigger.ITkTracking'
-  
-  for i in ConfigSettingsInstances.keys():
-    signatureCategory = "{}.{}".format(category,i)
-    factory = flagsFactory(__getInDetTrigConfig(i),mode)
-    flags.addFlagsCategory(signatureCategory,factory,prefix=True)
-
-  #TBD make a function for global settings too
-  flags.addFlag(f'{category}.RoiZedWidthDefault', 180.0 * Units.mm)
-
-  flags.addFlag(f'{category}.doGPU', False)
-
-  return flags
 
 
 import unittest
@@ -195,18 +18,15 @@ class FlagsCopiedTest(unittest.TestCase):
         flags.Trigger.doID
         flags.Trigger.InDetTracking.muon
         flags.Trigger.InDetTracking.electron.minPT = 2.0 * Units.GeV
+        flags.Trigger.ITkTracking.muon
         self.newflags = flags.cloneAndReplace('Tracking.ActiveConfig', 'Trigger.InDetTracking.electron')
-
+        self.newflags4 = flags.cloneAndReplace('Tracking.ActiveConfig', 'Trigger.ITkTracking.muon')
+        
         self.newflags.dump(".*InDet")
 
     def runTest(self):
         self.assertEqual(self.newflags.Tracking.ActiveConfig.minPT, 2.0 * Units.GeV, msg="Flags are not copied")
-
-
-
-class UnsetFlagsTest(FlagsCopiedTest):
-    def runTest(self):
-        self.assertEqual(self.newflags.Tracking.ActiveConfig.vertex_jet, None)
+        self.assertEqual(type(self.newflags4.Tracking.ActiveConfig.minPT), list, msg="Eta dependant cuts don't exist")
 
 
 if __name__ == "__main__":
diff --git a/Trigger/TrigValidation/TrigAnalysisTest/share/ref_RDOtoRDOTrig_v1Dev_build.ref b/Trigger/TrigValidation/TrigAnalysisTest/share/ref_RDOtoRDOTrig_v1Dev_build.ref
index 479ea810f470fac4fe067a27f0d509f9aa143054..f5fef41842dbfd29f38d66b598e45dc9ee77099c 100644
--- a/Trigger/TrigValidation/TrigAnalysisTest/share/ref_RDOtoRDOTrig_v1Dev_build.ref
+++ b/Trigger/TrigValidation/TrigAnalysisTest/share/ref_RDOtoRDOTrig_v1Dev_build.ref
@@ -19123,6 +19123,30 @@ HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn177_p
     1: 50
     2: 182
     3: 20
+? HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn280_pf_ftf_presel2c20XX2c20bgtwo85_L1MU8F_2jJ40_jJ50
+: eventCount: 4
+  stepCounts:
+    0: 10
+    1: 5
+    2: 4
+    3: 4
+  stepFeatures:
+    0: 50
+    1: 25
+    2: 80
+    3: 9
+? HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn280_pf_ftf_presel2c20XX2c20bgtwo85_L1jJ85p0ETA21_3jJ40p0ETA25
+: eventCount: 8
+  stepCounts:
+    0: 16
+    1: 10
+    2: 9
+    3: 8
+  stepFeatures:
+    0: 80
+    1: 50
+    2: 182
+    3: 20
 ? HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn282_pf_ftf_presel2c20XX2c20bgtwo85_L1J45p0ETA21_3J15p0ETA25
 : eventCount: 8
   stepCounts:
diff --git a/Trigger/TrigValidation/TrigP1Test/share/ref_v1Dev_decodeBS_build.ref b/Trigger/TrigValidation/TrigP1Test/share/ref_v1Dev_decodeBS_build.ref
index 1db9e8970d8ce872a4c419aa761d71b7e3a2e678..91ca1dfb2e6e3bb8952490d7734842f155240c9b 100644
--- a/Trigger/TrigValidation/TrigP1Test/share/ref_v1Dev_decodeBS_build.ref
+++ b/Trigger/TrigValidation/TrigP1Test/share/ref_v1Dev_decodeBS_build.ref
@@ -7547,6 +7547,14 @@ HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn177_p
 : eventCount: 0
 ? HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn280_pf_ftf_presel2c20XX2c20bgtwo85_L1J45p0ETA21_3J15p0ETA25
 : eventCount: 0
+? HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn280_pf_ftf_presel2c20XX2c20bgtwo85_L1MU8F_2jJ40_jJ50
+: eventCount: 0
+  stepCounts:
+    0: 1
+  stepFeatures:
+    0: 5
+? HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn280_pf_ftf_presel2c20XX2c20bgtwo85_L1jJ85p0ETA21_3jJ40p0ETA25
+: eventCount: 0
 ? HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn282_pf_ftf_presel2c20XX2c20bgtwo85_L1J45p0ETA21_3J15p0ETA25
 : eventCount: 0
 ? HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn285_pf_ftf_presel2c20XX2c20bgtwo85_L1J45p0ETA21_3J15p0ETA25
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/Physics_pp_run3_v1.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/Physics_pp_run3_v1.py
index 245cfe6668c669f75b8a39ada5e16070cde58565..fcf0fb45a17e11baf790ca246678172be8674465 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/Physics_pp_run3_v1.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLT/Menu/Physics_pp_run3_v1.py
@@ -746,7 +746,7 @@ def setupMenu(menu_name):
 
         # ATR-24268, ATR-19501, ATR-28162
         # B->K*ee chains
-        ChainProp(name='HLT_e5_lhvloose_bBeeM6000_L1BKeePrimary', l1SeedThresholds=['eEM5'], stream=['BphysDelayed','express'], groups=SupportPhIGroup+BphysElectronGroup, monGroups=['bphysMon:online','bphysMon:shifter']),
+        ChainProp(name='HLT_e5_lhvloose_bBeeM6000_L1BKeePrimary', l1SeedThresholds=['eEM5'], stream=['BphysDelayed','express'], groups=SupportPhIGroup+BphysElectronGroup, monGroups=['bphysMon:online']),
         ChainProp(name='HLT_2e5_lhvloose_bBeeM6000_L1BKeePrimary', l1SeedThresholds=['eEM5'], stream=['BphysDelayed','express'], groups=SupportPhIGroup+BphysElectronGroup, monGroups=['bphysMon:online','bphysMon:shifter']),
         ChainProp(name='HLT_e5_lhvloose_e3_lhvloose_bBeeM6000_L1BKeePrimary', l1SeedThresholds=['eEM5','eEM5'], stream=['BphysDelayed'], groups=SupportPhIGroup+BphysElectronGroup, monGroups=['bphysMon:online','bphysMon:shifter']),
         ChainProp(name='HLT_e5_lhvloose_bBeeM6000_L1BKeePrescaled', l1SeedThresholds=['eEM5'], stream=['BphysDelayed'], groups=EOFBeePhIGroup+BphysElectronGroup),
@@ -1412,8 +1412,8 @@ def setupMenu(menu_name):
         ChainProp(name='HLT_j0_HT940_pf_ftf_preselcHT450_L1HT190-jJ40s5pETA21', l1SeedThresholds=['FSNOSEED'], stream=[PhysicsStream,'express'], groups=PrimaryPhIGroup+SingleJetGroup+Topo3Group, monGroups=['jetMon:online', 'jetMon:shifter']), 
 
         # Multijet delayed stream
-        ChainProp(name='HLT_6j35c_020jvt_pf_ftf_presel6c25_L14jJ40', l1SeedThresholds=['FSNOSEED'], stream=['VBFDelayed', 'express'], groups=PrimaryPhIGroup+MultiJetGroup, monGroups=['jetMon:t0']),
-        ChainProp(name='HLT_6j45c_020jvt_pf_ftf_presel6c25_L14jJ40', l1SeedThresholds=['FSNOSEED'], stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiJetGroup),
+        ChainProp(name='HLT_6j35c_020jvt_pf_ftf_presel6c25_L14jJ40', l1SeedThresholds=['FSNOSEED'], stream=[PhysicsStream, 'express'], groups=PrimaryPhIGroup+MultiJetGroup, monGroups=['jetMon:t0']),
+        ChainProp(name='HLT_6j45c_020jvt_pf_ftf_presel6c25_L14jJ40', l1SeedThresholds=['FSNOSEED'], stream=[PhysicsStream], groups=PrimaryPhIGroup+MultiJetGroup),
 
         # TLA chains
         ChainProp(name='HLT_j20_PhysicsTLA_L1jJ160', l1SeedThresholds=['FSNOSEED'], stream=['TLA'], groups=PrimaryPhIGroup+SingleJetGroup, monGroups=['tlaMon:shifter']),
@@ -1505,7 +1505,7 @@ def setupMenu(menu_name):
 
         # HH4b primaries
         # Muon+jet legacy seeded, backup for L1Topo muon-in-jet
-        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn177_pf_ftf_presel2c20XX2c20b85_L1MU8F_2jJ40_jJ50', l1SeedThresholds=['FSNOSEED']*5, stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiBjetGroup),
+        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn177_pf_ftf_presel2c20XX2c20b85_L1MU8F_2jJ40_jJ50', l1SeedThresholds=['FSNOSEED']*5, stream=[PhysicsStream], groups=PrimaryPhIGroup+MultiBjetGroup),
         # Support chain
         ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_boffperf_pf_ftf_presel2c20XX2c20b85_L1jJ85p0ETA21_3jJ40p0ETA25', l1SeedThresholds=['FSNOSEED']*4, stream=[PhysicsStream],  monGroups=['idMon:t0'], groups=SupportPhIGroup+MultiBjetGroup),
 
@@ -1570,13 +1570,13 @@ def setupMenu(menu_name):
         ChainProp(name='HLT_j65a_j45a_2j35a_SHARED_2j35_0eta290_020jvt_bgn170_j0_DJMASS1000j50_pf_ftf_presela60XXa40XX2a25_L1jMJJ-500-NFF', l1SeedThresholds=['FSNOSEED']*5,stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiBjetGroup+Topo3Group),
 
         # HH4b primary triggers
-        # 3b symmetric b-jet pt for Physics_Main
+        # 3b asymmetric b-jet pt for Physics_Main
         ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_3j20c_020jvt_bgn182_pf_ftf_presel2c20XX2c20b85_L1jJ85p0ETA21_3jJ40p0ETA25', l1SeedThresholds=['FSNOSEED']*5, stream=[PhysicsStream], groups=PrimaryPhIGroup+MultiBjetGroup),
-        # 2b symmetric b-jet pt for VBFDelayed
-        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn177_pf_ftf_presel2c20XX2c20b85_L1jJ85p0ETA21_3jJ40p0ETA25', l1SeedThresholds=['FSNOSEED']*5, stream=['VBFDelayed'], monGroups=['idMon:t0'], groups=PrimaryPhIGroup+MultiBjetGroup),
+        # 2b asymmetric b-jet pt for VBFDelayed
+        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn177_pf_ftf_presel2c20XX2c20b85_L1jJ85p0ETA21_3jJ40p0ETA25', l1SeedThresholds=['FSNOSEED']*5, stream=[PhysicsStream], monGroups=['idMon:t0'], groups=PrimaryPhIGroup+MultiBjetGroup),
         # Candidates for allhad ttbar delayed stream
-        ChainProp(name='HLT_5j35c_020jvt_j25c_020jvt_SHARED_j25c_020jvt_bgn160_pf_ftf_presel5c25XXc25b85_L14jJ40', l1SeedThresholds=['FSNOSEED']*3, stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiBjetGroup),
-        ChainProp(name='HLT_5j45c_020jvt_j25c_020jvt_SHARED_j25c_020jvt_bgn160_pf_ftf_presel5c25XXc25b85_L14jJ40', l1SeedThresholds=['FSNOSEED']*3, stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiBjetGroup),
+        ChainProp(name='HLT_5j35c_020jvt_j25c_020jvt_SHARED_j25c_020jvt_bgn160_pf_ftf_presel5c25XXc25b85_L14jJ40', l1SeedThresholds=['FSNOSEED']*3, stream=[PhysicsStream], groups=PrimaryPhIGroup+MultiBjetGroup),
+        ChainProp(name='HLT_5j45c_020jvt_j25c_020jvt_SHARED_j25c_020jvt_bgn160_pf_ftf_presel5c25XXc25b85_L14jJ40', l1SeedThresholds=['FSNOSEED']*3, stream=[PhysicsStream], groups=PrimaryPhIGroup+MultiBjetGroup),
 
         # support chains
         ChainProp(name='HLT_j20_0eta290_020jvt_boffperf_pf_ftf_L1jJ30', l1SeedThresholds=['FSNOSEED'], groups=SupportPhIGroup+SingleBjetGroup),
@@ -1593,7 +1593,8 @@ def setupMenu(menu_name):
         # GN2
         # HH4b primaries
         # Muon+jet legacy seeded, backup for L1Topo muon-in-jet
-        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn277_pf_ftf_presel2c20XX2c20bgtwo85_L1MU8F_2jJ40_jJ50', l1SeedThresholds=['FSNOSEED']*5, stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiBjetGroup),
+        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn277_pf_ftf_presel2c20XX2c20bgtwo85_L1MU8F_2jJ40_jJ50', l1SeedThresholds=['FSNOSEED']*5, stream=[PhysicsStream], groups=PrimaryPhIGroup+MultiBjetGroup),
+        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn280_pf_ftf_presel2c20XX2c20bgtwo85_L1MU8F_2jJ40_jJ50', l1SeedThresholds=['FSNOSEED']*5, stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiBjetGroup),
 
         # Phase I inputs GN2
         #  Single b-jet
@@ -1639,13 +1640,15 @@ def setupMenu(menu_name):
         ChainProp(name='HLT_j65a_j45a_2j35a_SHARED_2j35_0eta290_020jvt_bgn270_j0_DJMASS1000j50_pf_ftf_presela60XXa40XX2a25_L1jMJJ-500-NFF', l1SeedThresholds=['FSNOSEED']*5,stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiBjetGroup+Topo3Group),
 
         # HH4b primary triggers
-        # 3b symmetric b-jet pt for Physics_Main
+        # 3b asymmetric b-jet pt for Physics_Main
         ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_3j20c_020jvt_bgn282_pf_ftf_presel2c20XX2c20bgtwo85_L1jJ85p0ETA21_3jJ40p0ETA25', l1SeedThresholds=['FSNOSEED']*5, stream=[PhysicsStream], groups=PrimaryPhIGroup+MultiBjetGroup),
-        # 2b symmetric b-jet pt for VBFDelayed
-        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn277_pf_ftf_presel2c20XX2c20bgtwo85_L1jJ85p0ETA21_3jJ40p0ETA25', l1SeedThresholds=['FSNOSEED']*5, stream=['VBFDelayed'], monGroups=['idMon:t0'], groups=PrimaryPhIGroup+MultiBjetGroup),
+        # 2b asymmetric b-jet pt for VBFDelayed
+        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn277_pf_ftf_presel2c20XX2c20bgtwo85_L1jJ85p0ETA21_3jJ40p0ETA25', l1SeedThresholds=['FSNOSEED']*5, stream=[PhysicsStream], monGroups=['idMon:t0'], groups=PrimaryPhIGroup+MultiBjetGroup),
+        # 2b asymmetric b-jet pt for with looser b-tagging (ATR-28870)
+        ChainProp(name='HLT_j75c_020jvt_j50c_020jvt_j25c_020jvt_j20c_020jvt_SHARED_2j20c_020jvt_bgn280_pf_ftf_presel2c20XX2c20bgtwo85_L1jJ85p0ETA21_3jJ40p0ETA25', l1SeedThresholds=['FSNOSEED']*5, stream=['VBFDelayed'], monGroups=['idMon:t0'], groups=PrimaryPhIGroup+MultiBjetGroup),
         # Candidates for allhad ttbar delayed stream
-        ChainProp(name='HLT_5j35c_020jvt_j25c_020jvt_SHARED_j25c_020jvt_bgn260_pf_ftf_presel5c25XXc25bgtwo85_L14jJ40', l1SeedThresholds=['FSNOSEED']*3, stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiBjetGroup),
-        ChainProp(name='HLT_5j45c_020jvt_j25c_020jvt_SHARED_j25c_020jvt_bgn260_pf_ftf_presel5c25XXc25bgtwo85_L14jJ40', l1SeedThresholds=['FSNOSEED']*3, stream=['VBFDelayed'], groups=PrimaryPhIGroup+MultiBjetGroup),
+        ChainProp(name='HLT_5j35c_020jvt_j25c_020jvt_SHARED_j25c_020jvt_bgn260_pf_ftf_presel5c25XXc25bgtwo85_L14jJ40', l1SeedThresholds=['FSNOSEED']*3, stream=[PhysicsStream], groups=PrimaryPhIGroup+MultiBjetGroup),
+        ChainProp(name='HLT_5j45c_020jvt_j25c_020jvt_SHARED_j25c_020jvt_bgn260_pf_ftf_presel5c25XXc25bgtwo85_L14jJ40', l1SeedThresholds=['FSNOSEED']*3, stream=[PhysicsStream], groups=PrimaryPhIGroup+MultiBjetGroup),
 
     ]