From 93c59a6cc94457b6f841f5960220cf8f6dd5b1e8 Mon Sep 17 00:00:00 2001
From: Pierre-Antoine Delsart <delsart@in2p3.fr>
Date: Fri, 13 Nov 2020 18:05:08 +0000
Subject: [PATCH] Implement standard small R jet definition in new style jet
 config

---
 .../xAODJet/xAODJet/test_utils/JetFactory.h   | 173 ++++++++++++++++++
 .../Root/JetParticleAssociation.cxx           |   2 +-
 .../python/ParticleJetToolsConfig.py          |  10 +-
 .../python/JetCalibToolsConfig.py             |   2 +-
 .../JetMomentTools/JetForwardJvtTool.h        |   1 +
 .../JetMomentTools/JetForwardJvtToolBDT.h     |   1 +
 .../python/JetMomentToolsConfig.py            |  68 +++----
 .../Jet/JetRecConfig/python/JetDefinition.py  | 146 ++++++++++++---
 .../Jet/JetRecConfig/python/JetInputConfig.py |   3 +-
 .../Jet/JetRecConfig/python/JetModConfig.py   |  19 +-
 .../Jet/JetRecConfig/python/JetRecConfig.py   | 105 ++++++-----
 .../python/StandardJetConstits.py             |  24 ++-
 .../JetRecConfig/python/StandardJetMods.py    |  50 ++---
 .../JetRecConfig/python/StandardSmallRJets.py |  67 +++++--
 .../Jet/JetRecConfig/share/JetRecTestCfg.py   |  57 +++---
 .../JetRecTools/python/JetRecToolsConfig.py   |   6 +-
 .../HLTMenuConfig/Jet/JetRecoConfiguration.py |   6 +-
 .../HLTMenuConfig/Jet/TriggerJetMods.py       |  28 ++-
 .../python/HLTMenuConfig/Jet/generateJet.py   |   8 +-
 19 files changed, 537 insertions(+), 239 deletions(-)
 create mode 100644 Event/xAOD/xAODJet/xAODJet/test_utils/JetFactory.h

diff --git a/Event/xAOD/xAODJet/xAODJet/test_utils/JetFactory.h b/Event/xAOD/xAODJet/xAODJet/test_utils/JetFactory.h
new file mode 100644
index 00000000000..46963860e39
--- /dev/null
+++ b/Event/xAOD/xAODJet/xAODJet/test_utils/JetFactory.h
@@ -0,0 +1,173 @@
+// this file is -*- C++ -*-
+/*
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef XAODJET_TEST_JETFACTORY_H
+#define XAODJET_TEST_JETFACTORY_H
+
+#include <map>
+#include <vector>
+#include "xAODJet/JetContainer.h"
+#include "xAODJet/JetAuxContainer.h"
+
+#include "xAODCaloEvent/CaloClusterContainer.h"
+#include "xAODCaloEvent/CaloClusterAuxContainer.h"
+
+#ifndef XAOD_STANDALONE
+// allows to test EL 
+#include "AthLinks/ElementLink.h"
+#include "SGTools/TestStore.h" 
+using namespace SGTest;
+#else
+#include "xAODRootAccess/Init.h"
+#include "xAODRootAccess/TEvent.h"
+#include "xAODRootAccess/TStore.h"
+#include "xAODRootAccess/TActiveStore.h"
+#endif
+
+
+namespace xAOD {
+  namespace JetTests {
+
+
+    template<typename T>
+    void record ATLAS_NOT_THREAD_SAFE (T* cont, const std::string & name) {
+#ifndef XAOD_STANDALONE
+  // *********************** init in Athena 
+# ifdef SGTOOLS_CURRENTEVENTSTORE_H
+  initTestStore();
+# else
+  SG::getDataSourcePointerFunc = getTestDataSourcePointer;
+# endif
+  store.record(cont, name); 
+  store.record((xAOD::IParticleContainer*)cont, name);  // also store the container as an IParticleContainer
+#else
+  // *********************** init in standalone 
+
+  gErrorIgnoreLevel = kWarning;
+  assert( xAOD::Init() );
+  // Create a TEvent object:
+  xAOD::TEvent eventstore(xAOD::TEvent::kClassAccess);
+
+  xAOD::TStore tds;
+  xAOD::TStore* transDataStore = xAOD::TActiveStore::store();
+
+  assert( transDataStore != 0 );
+
+  tds.record(cont, name).ignore();
+ 
+#endif
+      
+    }
+
+
+
+    /// Create and return an empty JetContainer. JetContainer has an AuxContainer associated and is recorded in an event store so its elements can be used as ElementLink.
+    JetContainer * createEmptyJetContainer ATLAS_NOT_THREAD_SAFE (const std::string & name)  {
+      JetContainer * jetCont = new JetContainer();
+      JetAuxContainer* aux = new xAOD::JetAuxContainer();
+      jetCont->setStore(aux);
+      record(jetCont, name);
+      return jetCont;
+    }
+    
+
+
+    /// Fill input JetContainer with new jets which 4-momentum are given by jet4moms
+    void fillJets(JetContainer & jetCont,  const  std::vector<xAOD::JetFourMom_t>& jet4moms ){      
+      for( const xAOD::JetFourMom_t &v : jet4moms ){
+	jetCont.push_back(new xAOD::Jet());
+	xAOD::Jet *jet = jetCont.back();
+	jet->setJetP4( v ); // set the P4 of the last inserted jet
+      }  
+      
+    }
+
+    /// Fill input JetContainer with new jets which 4-momentum are given by jet4moms and with attributes as given by the map "jetAttMap". It is expected that vectors in this map have same lenght as jet4moms
+    void fillJets(JetContainer & jetCont,  const  std::vector<xAOD::JetFourMom_t>& jet4moms,
+		  const std::map<std::string, std::vector<float>> jetAttMap
+		  ){      
+      int i=0;
+      for( const xAOD::JetFourMom_t &v : jet4moms ){
+	jetCont.push_back(new xAOD::Jet());
+	xAOD::Jet *jet = jetCont.back();
+	jet->setJetP4( v ); // set the P4 of the last inserted jet
+	for( const auto& attpair : jetAttMap) { jet->setAttribute<float>(attpair.first, attpair.second[i]);}
+	i++;
+      }  
+      
+    }
+
+
+    /// Fill input JetContainer with a list of test jets
+    void fillStandardTestJets(JetContainer& jetCont){
+      static const std::vector<xAOD::JetFourMom_t> jet4moms =
+	{
+	 xAOD::JetFourMom_t(40000, 0, 1, 10000 ),
+	 xAOD::JetFourMom_t(40000, 0.01, 2, 10000 ),
+	 xAOD::JetFourMom_t(40000, 0.01, 2, 0.),
+	 xAOD::JetFourMom_t(40000, 0.2, 2, 10000.),
+	 xAOD::JetFourMom_t(40000, 1.0, 2, 10000.),
+	 xAOD::JetFourMom_t(40000, 1.001, 2, 10000.),
+	 xAOD::JetFourMom_t(40000, 2., 2, 10000.),
+	 xAOD::JetFourMom_t(40000, 3., 2, 10000.),
+	 xAOD::JetFourMom_t(40000, 3.22, 2, 10000.),
+	 xAOD::JetFourMom_t(40000, 4., 2, 10000.),
+	 xAOD::JetFourMom_t(40000, 5., 2, 10000.),
+	 xAOD::JetFourMom_t(40000, 5.5, 2, 10000.),
+	 
+	 xAOD::JetFourMom_t(0.1, 1.0, 2, 10000.),
+	 xAOD::JetFourMom_t(100000, 1.0, 2, 10000.),
+	 xAOD::JetFourMom_t(500000, 1.0, 2, 10000.),
+	 xAOD::JetFourMom_t(1000000, 1.0, 2, 10000.),
+	 xAOD::JetFourMom_t(10000000, 1.0, 2, 10000.),
+	 
+	 xAOD::JetFourMom_t(100000, 1.0, 2, 100000.),
+	 xAOD::JetFourMom_t(100000, 1.0, 2, 1000000.)
+	};
+      
+      std::map< std::string, std::vector<float> > jetAttMap =
+	{ { "Width", std::vector<float>(jet4moms.size(), 0.123 )} };
+      fillJets(jetCont, jet4moms, jetAttMap);
+
+      // also set scales :
+      for(Jet* jet: jetCont){
+	jet->setJetP4(xAOD::JetScale::JetConstitScaleMomentum, 0.9*jet->jetP4());
+	jet->setJetP4(xAOD::JetScale::JetEMScaleMomentum, 0.7*jet->jetP4());
+      }
+    }
+    
+    
+    
+    /// Create and return an empty CaloClusterAuxContainer. CaloClusterAuxContainer has an AuxContainer associated and is recorded in an event store so its elements can be used as ElementLink.
+    CaloClusterContainer * createEmptyCaloClusterContainer ATLAS_NOT_THREAD_SAFE (const std::string & name) {
+      CaloClusterContainer * clustCont = new CaloClusterContainer();
+      xAOD::CaloClusterAuxContainer* aux = new xAOD::CaloClusterAuxContainer();
+      clustCont->setStore(aux);
+      record(clustCont, name);
+      return clustCont;
+    }
+    
+    
+    /// Fill input CaloClusterAuxContainer with a list of test clusters (with only their default and Raw 4-momentum set)
+    void fillStandardTestClusters ATLAS_NOT_THREAD_SAFE (CaloClusterContainer & clustCont){
+      
+      for(int i=0; i<10; i++){
+	xAOD::CaloCluster *cl = new xAOD::CaloCluster();
+	clustCont.push_back(cl);
+	
+#define SETCLUSTERMOM( E, eta, phi ) cl->setE(E);cl->setEta(eta);cl->setPhi(phi);cl->setM(0)
+#define SETCLUSTERRAWMOM( E, eta, phi ) cl->setRawE(E);cl->setRawEta(eta);cl->setRawPhi(phi);cl->setRawM(0)
+	SETCLUSTERMOM( 1000+i*1.1, -5+i*0.1, 0);
+	SETCLUSTERRAWMOM( 500+i*2.2, -5+i*0.1, 0);
+	
+      }
+    }
+    
+    
+  }
+}
+
+#endif
+
diff --git a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/Root/JetParticleAssociation.cxx b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/Root/JetParticleAssociation.cxx
index 49f28af9b1b..cc54bbce726 100644
--- a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/Root/JetParticleAssociation.cxx
+++ b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/Root/JetParticleAssociation.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 // author: cpollard@cern.ch
diff --git a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py
index c35dfe4c54e..12ed1504396 100644
--- a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py
+++ b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py
@@ -41,6 +41,7 @@ def getCopyTruthLabelParticles(truthtype):
         truthcategory = "Partons"
     elif truthtype in ["WBosons", "ZBosons", "HBosons", "TQuarksFinal"]:
         truthcategory = "BosonTop"
+        toolProperties['ParticleType'] = truthtype
     else:
         truthcategory = "FlavourLabel"
         toolProperties['ParticleType'] = truthtype
@@ -89,8 +90,13 @@ def getJetConeLabeling():
         )
     return truthpartonlabel
 
-  # Cone matching for B, C and tau truth for all but track jets.
-def getJetDeltaRLabelTool(modspec):
+def getJetDeltaRLabelTool(jetdef, modspec):
+    """returns a ParticleJetDeltaRLabelTool 
+    Cone matching for B, C and tau truth for all but track jets.
+
+    This function is meant to be used as callback from JetRecConfig where 
+    it is called as func(jetdef, modspec). Hence the jetdef argument even if not used in this case.
+    """
     jetptmin = float(modspec)
     jetdrlabeler = CompFactory.ParticleJetDeltaRLabelTool(
         "jetdrlabeler_jetpt{0}GeV".format(int(jetptmin/1000)),
diff --git a/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py b/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py
index 61e9cca8e9c..53cc8da8690 100644
--- a/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py
+++ b/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py
@@ -187,6 +187,6 @@ def getCalibSpecsFromString(modspec):
     return calibcontext, data_type, calibseq, rhoname, pvname, gscdepth
 
 # This method instantiates the JetCalibTool given the input mod specification
-def getJetCalibToolFromString(modspec,jetdef):
+def getJetCalibToolFromString(jetdef, modspec):
     calibcontext, data_type, calibseq, rhoname, pvname, gscdepth = getCalibSpecsFromString(modspec)
     return getJetCalibTool(jetdef.basename,calibcontext,data_type,calibseq,rhoname,pvname,gscdepth)
diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetForwardJvtTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetForwardJvtTool.h
index 479f898a884..6982167a924 100644
--- a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetForwardJvtTool.h
+++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetForwardJvtTool.h
@@ -27,6 +27,7 @@
 #include "xAODTracking/VertexContainer.h"
 #include "xAODMissingET/MissingETContainer.h"
 #include "xAODCaloEvent/CaloCluster.h"
+#include "xAODTracking/VertexContainer.h"
 #include "JetInterface/IJetDecorator.h"
 #include "AsgTools/IAsgTool.h"
 
diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetForwardJvtToolBDT.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetForwardJvtToolBDT.h
index 300f7db52b4..87ba3dd0fc0 100644
--- a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetForwardJvtToolBDT.h
+++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetForwardJvtToolBDT.h
@@ -38,6 +38,7 @@
 #include "AsgDataHandles/ReadDecorHandle.h"
 #include "AsgDataHandles/WriteDecorHandleKey.h"
 #include "AsgDataHandles/WriteDecorHandle.h"
+#include "xAODTracking/VertexContainer.h"
 
 
 namespace TMVA{ class Reader; }
diff --git a/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py b/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py
index dfab14517e7..cff7c264dee 100644
--- a/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py
+++ b/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py
@@ -1,12 +1,17 @@
 # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 
-########################################################################
-#                                                                      #
-# JetMomentToolsConfig: A helper module for configuring jet moment     #
-# tools, in support of JetRecConfig.JetModConfig.                      #
-# Author: TJ Khoo                                                      #
-#                                                                      #
-########################################################################
+"""
+                                                                      
+ JetMomentToolsConfig: A helper module for configuring jet moment     
+ tools, in support of JetRecConfig.JetModConfig. 
+ Author: TJ Khoo                                                      
+
+
+IMPORTANT : all the getXYZTool(jetdef, modspec) functions are meant to be used as callback from the main JetRecConfig module 
+when we need to convert definitions of tools into the actual tools. At this point the functions are invoked as 
+ func(jetdef, modspec)
+Hence they have jetdef and modspec arguments even if not needed in every case.
+"""
 
 from AthenaCommon import Logging
 jetmomentlog = Logging.logging.getLogger('JetMomentToolsConfig')
@@ -17,15 +22,8 @@ from AthenaConfiguration.ComponentFactory import CompFactory
 
 from xAODBase.xAODType import xAODType
 
-def getCaloQualityTool():
-    caloqual = CompFactory.JetCaloQualityTool(
-      "caloqual",
-      TimingCuts = [5, 10],
-      Calculations = ["LArQuality", "N90Constituents", "FracSamplingMax",  "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF", "BchCorrCell"],
-    )
-    return caloqual
 
-def getEMScaleMomTool(jetdef):
+def getEMScaleMomTool(jetdef, modspec=""):
     # This may need updating e.g. for evolving trigger cluster container names
     # We do the non-trivial summation over constituents unless the jets were
     # built directly from EM-scale topoclusters, in which case we can just
@@ -46,7 +44,7 @@ def getEMScaleMomTool(jetdef):
 
     return emscalemom
 
-def getConstitFourMomTool(jetdef):
+def getConstitFourMomTool(jetdef, modspec=""):
     ### Not ideal, but because CaloCluster.Scale is an internal class
     ### it makes the dict load really slow.
     ### So just copy the enum to a dict...
@@ -93,22 +91,23 @@ def getConstitFourMomTool(jetdef):
     return cfourmom
 
 # Jet vertex fraction with selection.
-def getJVFTool(modspec=""):
+def getJVFTool(jetdec, modspec):
     jettrackselloose = JetRecToolsConfig.getTrackSelTool(modspec)
-
+    # retrieve the tracking keys to be used with modspec : 
+    trackingKeys = trackcollectionmap[modspec]
     jvf = CompFactory.JetVertexFractionTool(
         "jvf",
-        VertexContainer = trackcollectionmap[modspec]["Vertices"],
-        AssociatedTracks = trackcollectionmap[modspec]["GhostTracksLabel"],
-        TrackVertexAssociation = trackcollectionmap[modspec]["TVA"],
-        TrackParticleContainer  = trackcollectionmap[modspec]["Tracks"],
+        VertexContainer = trackingKeys["Vertices"],
+        AssociatedTracks = trackingKeys["GhostTracksLabel"],
+        TrackVertexAssociation = trackingKeys["TVA"],
+        TrackParticleContainer  = trackingKeys["Tracks"],
         TrackSelector = jettrackselloose,
     )
     return jvf
 
 
 # Jet vertex fraction with selection.
-def getJVTTool(modspec=""):
+def getJVTTool(jetdef, modspec):
     jvt = CompFactory.JetVertexTaggerTool(
         "jvt",
         VertexContainer = trackcollectionmap[modspec]["Vertices"],
@@ -116,27 +115,30 @@ def getJVTTool(modspec=""):
     return jvt
 
 
-def getTrackMomentsTool(modspec=""):
+def getTrackMomentsTool(jetdef, modspec):
     jettrackselloose = JetRecToolsConfig.getTrackSelTool(modspec)
+    # retrieve the tracking keys to be used with modspec : 
+    trackingKeys = trackcollectionmap[modspec]
 
     trackmoments = CompFactory.JetTrackMomentsTool(
         "trkmoms",
-        VertexContainer = trackcollectionmap[modspec]["Vertices"],
-        AssociatedTracks = trackcollectionmap[modspec]["GhostTracksLabel"],
-        TrackVertexAssociation = trackcollectionmap[modspec]["TVA"],
+        VertexContainer = trackingKeys["Vertices"],
+        AssociatedTracks = trackingKeys["GhostTracksLabel"],
+        TrackVertexAssociation = trackingKeys["TVA"],
         TrackMinPtCuts = [500, 1000],
         TrackSelector = jettrackselloose
     )
     return trackmoments
 
-def getTrackSumMomentsTool(modspec=""):
+def getTrackSumMomentsTool(jetdef, modspec):
     jettrackselloose = JetRecToolsConfig.getTrackSelTool(modspec)
-
+    # retrieve the tracking keys to be used with modspec : 
+    trackingKeys = trackcollectionmap[modspec]
     tracksummoments = CompFactory.JetTrackSumMomentsTool(
         "trksummoms",
-        VertexContainer = trackcollectionmap[modspec]["Vertices"],
-        AssociatedTracks = trackcollectionmap[modspec]["GhostTracksLabel"],
-        TrackVertexAssociation = trackcollectionmap[modspec]["TVA"],
+        VertexContainer = trackingKeys["Vertices"],
+        AssociatedTracks = trackingKeys["GhostTracksLabel"],
+        TrackVertexAssociation = trackingKeys["TVA"],
         RequireTrackPV = True,
         TrackSelector = jettrackselloose
     )
@@ -144,7 +146,7 @@ def getTrackSumMomentsTool(modspec=""):
 
 # This tool sets a decoration saying which the nominal HS PV was.
 # Historically it did the origin correction, but now we do this to constituents
-def getOriginCorrVxTool(modspec=""):
+def getOriginCorrVxTool(jetdef, modspec):
     origin_setpv = CompFactory.JetOriginCorrectionTool(
       "jetorigin_setpv",
       VertexContainer = trackcollectionmap[modspec]["Vertices"],
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py b/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py
index b762ff29784..9142d30d879 100644
--- a/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py
+++ b/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py
@@ -5,6 +5,18 @@
 JetDefinition: A module for classes encoding definitions of jets and 
 related objects for configuring jet reconstruction                   
 
+Various classes encode definitions of different types of components used in Jet Reco.
+They are : 
+
+ - JetInputDef : describes how to build a source container, typically external to the jet domain. This includes input to jet finding  (ex: CaloCluster, Track) but also other sources like EventDensity...
+
+ - JetConstitSource : describes specifically a input constituents source (an input to a PseudoJetAlgorithm), thus referring to a JetInputDef. 
+ - JetConstitSeq : a subclass of JetConstitSource, describing how the constituents are modified by a JetConstituentModSequence (ex: PU or Origin correction).
+ - JetConstitModifier : describes a constituent modifier tool to be used in a JetConstituentModSequence
+
+ - JetDefinition : describes a full jet reco sequence. Uses a JetConstitSource and a list of JetModifier
+ - JetModifier : describes a JetModifier c++ tool. 
+
 Author: TJ Khoo, P-A Delsart                                         
                                                                      
 """
@@ -17,10 +29,11 @@ jetlog = Logging.logging.getLogger('JetDefinition')
 from xAODBase.xAODType import xAODType
 from .Utilities import make_lproperty, onlyAttributesAreProperties, clonable, make_alias
 
-# Code from JetRecUtils
-# define the convention that we write R truncating the decimal point
-# if R>=1, then we write R*10
 def formatRvalue(parameter):
+    """Define the convention that we write R truncating the decimal point
+    if R>=1, then we write R*10.
+    (Code from JetRecUtils )
+    """
     # impose precision limits where there could be ambiguity
     if int(10*parameter)>=1 and int(100*parameter % 10):
         #jetlog.warning('Radius parameter {0} exceeds allowable precision of 0.1'.format(parameter))
@@ -53,9 +66,8 @@ class JetDefinition(object):
                  radius,              # The jet radius specifier (clustering cutoff)
                  inputdef,            # The input JetConstit
                  ptmin=5e3*MeV,       # The pt cutoff for fastjet in MeV
-                 ptminfilter=5e3*MeV, # The minimum pt to retain xAOD jets after calibration in MeV
-                 ghostdefs=[],        # The list of JetGhosts to ghost-associate
-                 modifiers=[],        # The list of JetModifiers to execute after jet finding
+                 ghostdefs=[],        # The list of alias to JetGhosts to ghost-associate
+                 modifiers=[],        # The list of alias to JetModifiers to execute after jet finding
                  extrainputs=[],      # The list of additional input types needed for jet finding
                  standardRecoMode = False, # 
                  prefix = "",         # allows to tune the full JetContainer name
@@ -78,9 +90,6 @@ class JetDefinition(object):
         self._defineName()
         
         self.ptmin = ptmin # The pt down to which FastJet is run
-        self.ptminfilter = ptminfilter # The pt above which xAOD::Jets are kept, may include calibration
-        if ptmin<1000.*MeV or ptminfilter<1000.*MeV:
-            jetlog.warning("Very low filter threshold set: ptmin {0:.0f} MeV, ptminfilter {1:.0f} MeV. Are you sure?")
 
         self.ghostdefs = ghostdefs     # Objects to ghost-associate
         self.modifiers = modifiers     # Tools to modify the jet
@@ -100,7 +109,7 @@ class JetDefinition(object):
 
             
     def __hash__(self):
-        return hash((self.__radius,self.__inputdef,self.ptmin,self.ptminfilter,str(self.ghostdefs),str(self.modifiers),str(self.extrainputs)))
+        return hash((self.__radius,self.__inputdef,self.ptmin,str(self.ghostdefs),str(self.modifiers),str(self.extrainputs)))
 
     def __eq__(self,rhs):
         return self.__hash__() == rhs.__hash__()
@@ -198,14 +207,15 @@ class JetDefinition(object):
 @clonable
 @onlyAttributesAreProperties
 class JetModifier(object):
-    """Helper to instantiate a generic jet modifier
+    """Helper to define the config of a IJetModifier tool.
     Tools that typically have more complex properties set should have
     their own dedicated helper 'createfn' functions defined"""
 
     def __init__(self,tooltype,toolname,
                  createfn=None,
                  filterfn=_condAlwaysPass,                 
-                 prereqs=[],modspec=None,passJetDef=False,
+                 prereqs=[],modspec=None,
+                 **properties
                  ):
         # For the easy cases where no helper function is needed.
         # They will be ignored in the case of a helper,
@@ -214,11 +224,10 @@ class JetModifier(object):
         self.tooltype = tooltype
         self.toolname = toolname
 
-        # The helper function may take up to 2 parameters:
+        # The helper function may take 2 parameters:
         # a "modifier specification" string and the jet
-        # definition, which will be passed in based
-        # on the values of modspec and passJetDef.
-        #
+        # definition
+
         # The helper function always returns the desired
         # modifier, and a ComponentAccumulator instance, 
         # in case additional supporting tools/services
@@ -228,7 +237,6 @@ class JetModifier(object):
         else:
             self.createfn = createfn
         self.modspec = modspec
-        self.passJetDef = passJetDef
 
         # Prereqs is normally a list.
         # However, in special cases, the prereqs may
@@ -241,6 +249,9 @@ class JetModifier(object):
         #  The function must return a tuple : (bool, "reason of failure")
         self.filterfn = filterfn 
 
+        # These will be set as the Gaudi properties of the C++ tool
+        self.properties = properties
+        
         self._instanceMap = {}
         #self._locked = lock
                 
@@ -255,16 +266,16 @@ class JetModifier(object):
     @make_lproperty
     def modspec(self):pass
     @make_lproperty
-    def passJetDef(self):pass
-    @make_lproperty
     def prereqs(self):pass
     @make_lproperty
     def filterfn(self):pass
+    @make_lproperty
+    def properties(self):pass
 
     
     
     def __hash__(self):
-        return hash((self.toolname,self.tooltype,self.createfn.__name__,self.modspec,self.passJetDef,str(self.prereqs)))
+        return hash((self.toolname,self.tooltype,self.createfn.__name__,self.modspec,str(self.prereqs)))
 
     def __eq__(self,rhs):
         return self.__hash__() == rhs.__hash__()
@@ -278,9 +289,15 @@ class JetModifier(object):
     # Need to override __repr__ for printing in lists etc
     __repr__ = __str__
 
-    def getGenericModifier(self,**kwargs):
+    def getGenericModifier(self,jetdef, modspec):
+        """returns a real tool instance accoding to this definition : simply instantiating from
+        class self.tooltype and with name self.toolname ( actually : self.toolname.format(modspec) )
+        Since this function will be called as a callback from JetRecConfig as 'func(jetdef, modspec)', it must accept
+        the jetdef argument, even if unused in this case.
+        """
         from AthenaConfiguration.ComponentFactory import CompFactory
-        tool = CompFactory.getComp(self.tooltype)(self.toolname)
+        name = self.toolname.format(modspec=modspec)
+        tool = CompFactory.getComp(self.tooltype)(name)
         return tool
 
 
@@ -310,7 +327,7 @@ class JetInputDef(object):
      - filterfn : a function taking a CondFlags as argument and deciding if this JetModifier is compatible
                   with the conditions (same as JetModifier.filterfn )
                   The function must return a tuple : (bool, "reason of failure")
-     - prereqs : a list of prerequisites for this input definition.
+     - prereqs : a list of prerequisites (str) for this input definition.
     """
     def __init__(self, name, objtype, algoBuilder=None, specs=None, filterfn= _condAlwaysPass, prereqs=[]):
         self.name = name
@@ -374,8 +391,73 @@ class JetConstitModifier(object):
     def tooltype(self): pass
     @make_lproperty
     def properties(self): pass
-    
 
+
+
+
+from enum import IntEnum, auto
+class JetInputType(IntEnum):
+    """We reproduce the Enum from in xAODJet/​JetContainerInfo.h, xAOD::JetInput : loading the C++ library
+    can slow down a lot the configuration. 
+    Note : this is different from the xAODType which describes *only* c++ types whereas JetInputType describes
+    categories of inputs to jets.
+    """
+    LCTopo=0
+    EMTopo=auto()
+    TopoTower=auto()
+    Tower=auto()
+    Truth=auto()  
+    TruthWZ=auto()
+    Track=auto()
+    PFlow=auto()      
+    LCPFlow=auto()      # LC PFlow
+    EMPFlow=auto()      # EM Pflow at EM scale
+    EMCPFlow=auto()     # EM Pflow calibrated to LC scale
+    Jet=auto()
+    LCTopoOrigin=auto()
+    EMTopoOrigin=auto()
+    TrackCaloCluster=auto()
+    TruthDressedWZ=auto() # Truth jets without prompt e/mu (or dressed photons) or prompt gammas
+    EMTopoOriginSK=auto()
+    EMTopoOriginCS=auto()
+    EMTopoOriginVor=auto()
+    EMTopoOriginCSSK=auto()
+    EMTopoOriginVorSK=auto()
+    LCTopoOriginSK=auto()
+    LCTopoOriginCS=auto()
+    LCTopoOriginVor=auto()
+    LCTopoOriginCSSK=auto()
+    LCTopoOriginVorSK=auto()
+    EMPFlowSK=auto()
+    EMPFlowCS=auto()
+    EMPFlowVor=auto()
+    EMPFlowCSSK=auto()
+    EMPFlowVorSK=auto()
+    TruthCharged=auto() # Truth jets with only charged particles
+    EMTopoOriginTime=auto()
+    EMTopoOriginSKTime=auto()
+    EMTopoOriginCSSKTime=auto()
+    EMTopoOriginVorSKTime=auto()
+    EMPFlowTime=auto()
+    EMPFlowSKTime=auto()
+    EMPFlowCSSKTime=auto()
+    EMPFlowVorSKTime=auto()
+    HI=auto()
+    HIClusters=auto()
+    Other = 100
+    EMPFlowFE = 200 # Temporary, until xAOD::PFO is phased out and replaced with xAOD::FlowElement
+    Uncategorized= 1000
+
+    def fromxAODType(xt):
+        """Returns a default JetInputType for a given xAODType """
+        _xaodTojetinputMap = {
+            xAODType.CaloCluster   : JetInputType.LCTopo,
+            xAODType.ParticleFlow  : JetInputType.EMPFlow,
+            xAODType.TrackParticle : JetInputType.Track,
+            xAODType.TruthParticle : JetInputType.Truth,    
+        }
+        return _xaodTojetinputMap.get(xt, JetInputType.Other) 
+        
 @clonable
 @onlyAttributesAreProperties
 class JetConstitSource(object):
@@ -390,9 +472,11 @@ class JetConstitSource(object):
                  containername,   # The key of the source container in the event store. 
                  prereqs = [],    # will contain references to JetInputDef 
                  label = None,    # used to describe a category for these constits. if None, will default to name
+                 jetinputtype=None, # The JetInputType category. Can be passed as a string.
+                                    #  if None, set according to objtype. 
                  filterfn=_condAlwaysPass,                 
                  lock = False,    # lock all properties of this instance
-    ):    
+                 ):    
 
         self.name = name 
         self.containername = containername
@@ -403,6 +487,10 @@ class JetConstitSource(object):
         self.basetype = objtype
         self.filterfn = filterfn 
 
+        jetinputtype = jetinputtype or JetInputType.fromxAODType( objtype )
+        if isinstance(jetinputtype, str): jetinputtype = JetInputType[jetinputtype]
+        self.jetinputtype = jetinputtype
+        
         self._locked = lock
 
     @make_lproperty
@@ -417,6 +505,9 @@ class JetConstitSource(object):
     @make_lproperty
     def filterfn(self):pass
 
+    @make_lproperty
+    def jetinputtype(self): pass
+    
     # make an alias on containername so JetConstitSource and JetConstitSeq share an interface
     inputname = make_alias("containername")
 
@@ -434,12 +525,13 @@ class JetConstitSeq(JetConstitSource):
                  inputname=None,    # input collection which will be transformed into the source constituents
                  outputname=None,  #  output collection, will be set to self.containername
                  prereqs = [],     # will contain references to JetInputDef 
-                 label = None, 
+                 label = None,
+                 jetinputtype=None,
                  filterfn=_condAlwaysPass,                 
                  lock = False,    # lock all properties of this instance
     ):    
         
-        JetConstitSource.__init__(self,name, objtype, outputname, prereqs=prereqs, filterfn=filterfn,label=label,lock=False, finalinit=False, )
+        JetConstitSource.__init__(self,name, objtype, outputname, prereqs=prereqs, jetinputtype=jetinputtype, filterfn=filterfn,label=label,lock=False, finalinit=False, )
         self.inputname  = inputname or name
         self.modifiers = modifiers
 
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetInputConfig.py b/Reconstruction/Jet/JetRecConfig/python/JetInputConfig.py
index 6c9e48d3f66..8d088449776 100644
--- a/Reconstruction/Jet/JetRecConfig/python/JetInputConfig.py
+++ b/Reconstruction/Jet/JetRecConfig/python/JetInputConfig.py
@@ -19,7 +19,8 @@ def _buildJetAlgForInput(suffix, tools ):
 def buildJetSelectedTracks( parentjetdef, inputspec ):
     from JetRecTools import JetRecToolsConfig
     # Jet track selection
-    t = JetRecToolsConfig.getTrackSelTool(doWriteTracks=True)
+    t = JetRecToolsConfig.getTrackSelTool(doWriteTracks=True,
+                                          cutLevel="NoCut", minPt=500) 
     return _buildJetAlgForInput("JetSelectedTrack",
                                 tools = [ t ]
                                 )
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py b/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py
index 9d157f17c2b..13ec64fcc86 100644
--- a/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py
+++ b/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py
@@ -13,25 +13,26 @@ modlog = Logging.logging.getLogger('JetModConfig')
 
 def getModifier(jetdef, moddef, modspec):
     """Translate JetModifier into a concrete tool"""
-    modtool = None
     modlog.verbose("Retrieving modifier {0}".format(str(moddef)))
 
-    # Define some optional keyword arguments
-    kwargs = {}
-    if moddef.passJetDef:
-        kwargs["jetdef"] = jetdef
-    if modspec!="":
-        kwargs["modspec"] = modspec
-
     # Get the modifier tool
     try:
-        modtool = moddef.createfn(**kwargs)
+        modtool = moddef.createfn(jetdef, modspec)
     except Exception as e:
         modlog.error( "Unhandled modifier specification {0} for mod {1} acting on jet def {2}!".format(modspec,moddef,jetdef.basename) )
         modlog.error( "Received exception \"{0}\"".format(e) )
         modlog.error( "Helper function is \"{0}\"".format(moddef.createfn) )
         raise ValueError( "JetModConfig unable to handle mod {0} with spec \"{1}\"".format(moddef,modspec) )
 
+
+    # now we overwrite the default properties of the tool, by those
+    # set in the moddef :
+    for k,v in moddef.properties.items():
+        if callable(v) :
+            # The value we got is a function : we call it to get the actual value we want to set on the tool
+            v = v(jetdef, modspec)
+        setattr(modtool, k, v)
+    
     return modtool
 
 
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py b/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py
index 88b0b327b36..80ffcc3bda1 100644
--- a/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py
+++ b/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py
@@ -45,11 +45,11 @@ def JetRecCfg(jetdef0, configFlags):
     jetsfullname = jetdef.fullname()
     jetlog.info("Setting up to find {0}".format(jetsfullname))
 
-    sequencename = jetsfullname
+    sequenceName = jetsfullname
 
     components = ComponentAccumulator()
     from AthenaCommon.CFElements import parOR
-    components.addSequence( parOR(sequencename) )
+    components.addSequence( parOR(sequenceName) )
 
     # create proper config instances for each input and ghost aliases in this jetdef
     # this implicitely calculates and adds the dependencies.
@@ -59,38 +59,62 @@ def JetRecCfg(jetdef0, configFlags):
     # if in standardRecoMode we will remove whatever is incompatible and still try to run
     # if not, we raise an exception
     removeComponentFailingConditions(jetdef, configFlags, raiseOnFailure= not jetdef.standardRecoMode)
-        
+    
     
     # Schedule the various input collections.
     # We don't have to worry about ordering, as the scheduler
     # will handle the details. Just merge the components.
-    inputcomps = JetInputCfg(jetdef, configFlags, sequenceName=jetsfullname)
+    inputcomps = JetInputCfg(jetdef, configFlags, sequenceName)
     components.merge(inputcomps)
+
+    # schedule the algs to create fastjet::PseudoJet objects out of the inputs
+    pjCompo, pjContainer = PseudoJetCfg(jetdef, configFlags, sequenceName)
+    components.merge(pjCompo)
+    
+    # Generate a JetRecAlg to run the jet finding and modifiers
+    jetrecalg = getJetRecAlg( jetdef, pjContainer)
+    components.addEventAlgo(jetrecalg, sequenceName)
     
+    jetlog.info("Scheduled JetAlgorithm instance \"jetalg_{0}\"".format(jetsfullname))
+    return components
+
+def PseudoJetCfg(jetdef, configFlags, sequenceName):
+    """Builds a ComponentAccumulator for creating PseudoJetContainer needed by jetdef.
+    IMPORTANT returns a tuple : (components, finalPJContainerName) """
+    
+    components = ComponentAccumulator(sequenceName)
     # Schedule the constituent PseudoJetAlg
     constitpjalg = getConstitPJGAlg( jetdef.inputdef )
-    constitpjkey = constitpjalg.OutputContainer
-    components.addEventAlgo( constitpjalg, jetsfullname )
-
-    pjContNames = [constitpjkey]
-
+    components.addEventAlgo( constitpjalg, sequenceName )
+    finalPJContainer = constitpjalg.OutputContainer
+    
     # Schedule the ghost PseudoJetAlgs
     ghostlist = [ key for key in jetdef._prereqOrder if key.startswith('ghost:')]
-    for ghostkey in ghostlist:
-        ghostdef = jetdef._prereqDic[ghostkey]
-        ghostpjalg = getGhostPJGAlg( ghostdef )
-        components.addEventAlgo( ghostpjalg, sequencename )
-        ghostpjkey = ghostpjalg.OutputContainer
-        pjContNames.append( ghostpjkey )
-
-    # Generate a JetAlgorithm to run the jet finding and modifiers
-    # (via a JetRecTool instance).
-    jetrecalg = getJetAlgorithm(jetsfullname, jetdef, pjContNames)
-    components.addEventAlgo(jetrecalg, sequencename)
+    if ghostlist != []:
+        pjContNames = [finalPJContainer]
+        for ghostkey in sorted(ghostlist):
+            ghostdef = jetdef._prereqDic[ghostkey]
+            ghostpjalg = getGhostPJGAlg( ghostdef )
+            components.addEventAlgo( ghostpjalg, sequenceName )
+            pjContNames.append( ghostpjalg.OutputContainer )
+
+        mergeId = mergedPJId( pjContNames )
+        finalPJContainer = constitpjalg.OutputContainer+"_merged"+mergeId
+        mergerName = "PJMerger_id"+mergeId
+        mergeAlg =CompFactory.PseudoJetMerger(
+            mergerName,
+            InputPJContainers = pjContNames,
+            OutputContainer = finalPJContainer,
+        )
+        components.addEventAlgo( mergeAlg, sequenceName)
 
-    jetlog.info("Scheduled JetAlgorithm instance \"jetalg_{0}\"".format(jetsfullname))
-    return components
+    return components, finalPJContainer
 
+_mergedPJContainers = dict()
+def mergedPJId(pjList):
+    t = tuple(pjList)
+    currentSize = len(_mergedPJContainers)
+    return str(_mergedPJContainers.setdefault(t, currentSize))
 
 
 ########################################################################
@@ -138,9 +162,9 @@ def JetInputCfg(jetOrConstitdef, configFlags, sequenceName='AthAlgSeq'):
                 constitalg = ConstModHelpers.getConstitModAlg(inputInstance)
                 if constitalg:
                     components.addEventAlgo(constitalg, primary=isprimary)
-        else:
+        else: # it must be a JetInputDef
             jetlog.debug("Requesting input {} with function {} and specs {}".format(inputInstance.name, inputInstance.algoBuilder, inputInstance.specs) )
-            # inputInstance must be a JetInputDef
+            # check if it has something to build an Algorithm
             if inputInstance.algoBuilder:
                 components.addEventAlgo( inputInstance.algoBuilder( jetdef, inputInstance.specs ), primary=isprimary )
             else:
@@ -230,22 +254,21 @@ def getJetAlgorithm(jetname, jetdef, pjContNames, monTool = None):
 ########################################################################
 # Function that substitues JetRecTool + JetAlgorithm
 #
-def getJetRecAlg(jetname, jetdef, pjContNames, modlist):
-
-    jclust = CompFactory.JetClusterer("builder")
-    jclust.JetAlgorithm = jetdef.algorithm
-    jclust.JetRadius = jetdef.radius
-    jclust.PtMin = jetdef.ptmin
-    jclust.InputPseudoJets = pjContNames
-    jclust.GhostArea = 0.01 # In which cases do we not want areas?
-    jclust.JetInputType = jetdef.inputdef.basetype
+def getJetRecAlg( jetdef, pjContNames):
+    """ """
+    jclust = CompFactory.JetClusterer(
+        "builder",
+        JetAlgorithm = jetdef.algorithm,
+        JetRadius = jetdef.radius,
+        PtMin = jetdef.ptmin,
+        InputPseudoJets = pjContNames,
+        GhostArea = 0.01, # In which cases do we not want areas?
+        JetInputType = jetdef.inputdef.jetinputtype,
+    )
 
-    from . import JetModConfig
-    mods = []
-    for moddef,modspec in modlist:
-        mod = JetModConfig.getModifier(jetdef,moddef,modspec)
-        mods.append(mod)
+    mods = buildJetModifierList(jetdef)
 
+    jetname = jetdef.fullname()
     jra = CompFactory.JetRecAlg(
         "jetrecalg_"+jetname,
         Provider = jclust,
@@ -442,13 +465,9 @@ if __name__=="__main__":
 
     # Add the components from our jet reconstruction job
     from StandardJetDefs import AntiKt4EMTopo
-    AntiKt4EMTopo.ptminfilter = 15e3
-    AntiKt4EMTopo.modifiers = ["Calib:T0:mc","Sort"] + ["JVT"] + ["PartonTruthLabel"]
+    AntiKt4EMTopo.modifiers = ["Calib:T0:mc","Filter:15000","Sort"] + ["JVT"] + ["PartonTruthLabel"]
     cfg.merge(JetRecCfg(AntiKt4EMTopo,ConfigFlags,jetnameprefix="New"))
 
     cfg.printConfig(withDetails=False,summariseProps=True)
 
-    cfg.run(maxEvents=10)
 
-    import sys
-    sys.exit(0)
diff --git a/Reconstruction/Jet/JetRecConfig/python/StandardJetConstits.py b/Reconstruction/Jet/JetRecConfig/python/StandardJetConstits.py
index 13005ce8aa2..ae888b49029 100644
--- a/Reconstruction/Jet/JetRecConfig/python/StandardJetConstits.py
+++ b/Reconstruction/Jet/JetRecConfig/python/StandardJetConstits.py
@@ -78,10 +78,10 @@ _stdInputList = [
 
 
 _truthFlavours = ["BHadronsInitial", "BHadronsFinal", "BQuarksFinal",
-               "CHadronsInitial", "CHadronsFinal", "CQuarksFinal",
-               "TausFinal",
-               "WBosons", "ZBosons", "HBosons", "TQuarksFinal",
-               "Partons",]
+                  "CHadronsInitial", "CHadronsFinal", "CQuarksFinal",
+                  "TausFinal",
+                  "WBosons", "ZBosons", "HBosons", "TQuarksFinal",
+                  "Partons",]
 for label in  _truthFlavours:    
     # re-use the main truth input definition : 
     _stdInputList.append( JetInputDef("TruthLabel"+label, xAODType.TruthParticle,
@@ -150,7 +150,7 @@ for ji in _stdModList:
 ## List of standard constituent sequences
 ##  This sequences uses the above constit modifiers     
 _stdSeqList = [
-    # Format is :
+    # Format is typically :
     # JetConstitSeq( name , input_cont_type, list_of_modifiers, inputcontainer, outputcontainer )
     # or
     # JetConstitSource( name, input_cont_type, containername)
@@ -158,9 +158,12 @@ _stdSeqList = [
 
     # *****************************
     # Cluster constituents 
-    JetConstitSeq("EMTopoOrigin", xAODType.CaloCluster, ["EM","Origin"], "CaloCalTopoClusters", "EMOriginTopoClusters"),
-    JetConstitSeq("LCTopoOrigin",xAODType.CaloCluster, ["LC","Origin"],"CaloCalTopoClusters", "LCOriginTopoClusters"),
-    JetConstitSeq("LCTopoCSSK",  xAODType.CaloCluster, ["LC","Origin","CS","SK"],"CaloCalTopoClusters", "LCOriginTopoCSSK"),
+    JetConstitSeq("EMTopoOrigin", xAODType.CaloCluster, ["EM","Origin"],
+                  "CaloCalTopoClusters", "EMOriginTopoClusters", jetinputtype="EMTopo"),
+    JetConstitSeq("LCTopoOrigin",xAODType.CaloCluster, ["LC","Origin"],
+                  "CaloCalTopoClusters", "LCOriginTopoClusters", jetinputtype="LCTopo"),
+    JetConstitSeq("LCTopoCSSK",  xAODType.CaloCluster, ["LC","Origin","CS","SK"],
+                  "CaloCalTopoClusters", "LCOriginTopoCSSK", jetinputtype="LCTopo"),
     
 
 
@@ -172,7 +175,8 @@ _stdSeqList = [
     JetConstitSeq("EMPFlow", xAODType.ParticleFlow,["CorrectPFO", "CHS"] , 'JetETMissParticleFlowObjects', 'CHSParticleFlowObjects'),
 
     # Particle Flow Objects with Constituent Subtraction + SoftKiller
-    JetConstitSeq("EMPFlowCSSK", xAODType.ParticleFlow,["CorrectPFO",  "CS","SK", "CHS"] , 'JetETMissParticleFlowObjects', 'CSSKParticleFlowObjects'),
+    JetConstitSeq("EMPFlowCSSK", xAODType.ParticleFlow,["CorrectPFO",  "CS","SK", "CHS"] ,
+                  'JetETMissParticleFlowObjects', 'CSSKParticleFlowObjects', jetinputtype="EMPFlow"),
 
 
     # *****************************
@@ -192,7 +196,7 @@ _stdSeqList = [
     # Truth particles (see JetInputDef declarations above for more details)
     JetConstitSource("Truth", xAODType.TruthParticle, "JetInputTruthParticles" ),
     
-    JetConstitSource("TruthWZ", xAODType.TruthParticle, "JetInputTruthParticlesNoWZ" ),
+    JetConstitSource("TruthWZ", xAODType.TruthParticle, "JetInputTruthParticlesNoWZ", jetinputtype="TruthWZ"),
 ]
 
 for label in  _truthFlavours:    
diff --git a/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py b/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py
index a0f3d4017a9..c2ec26f1a02 100644
--- a/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py
+++ b/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py
@@ -13,32 +13,29 @@ The JetModifier config class is defined in JetDefinition.py
    2. Tool Name (ignored if the helper is a custom one)
   [3.] Config helper
   [4.] Prereqs (default to []). Can also be a function.
-  [5.] Flag passJetDef specifying if the helper needs the jet definition
+
         --> should this be by default? prefer to avoid ignored args
 """
 from .JetDefinition import JetModifier
+from AthenaConfiguration.ComponentFactory import CompFactory
 
 jetmoddict = {}
 
 ########################################################################
 # Define the simple modifier setups here -- those defined in JetRec.
 
-from AthenaConfiguration.ComponentFactory import CompFactory
-def getJetFilterTool(modspec):
-    threshold = int(modspec)
-    jetptfilter = CompFactory.JetFilterTool("jetptfilter_{0}mev".format(threshold))
-    jetptfilter.PtMin = threshold
-    return jetptfilter
 jetrecmods = {
     "Sort":   JetModifier("JetSorter","jetsort"),
-    "Filter": JetModifier("JetFilterTool","jetptfilter",createfn=getJetFilterTool),
+    "Filter": JetModifier("JetFilterTool","jetptfilter_{modspec}",
+                          # we give a function as PtMin : it will be evaluated when instantiating the tool (modspec will come alias usage like "Filter:10000" --> PtMin=100000) 
+                          PtMin = lambda _,modspec: int(modspec) ) #
 }
 jetmoddict.update (jetrecmods)
 
 ########################################################################
 # Below, we populate the jetmoddict with modifier definitions for tools
 # that are defined in other packages.
-# The helper functions for tools in PackageName live in modules called
+# When necessary, the helper functions 'createfn' for tools in PackageName live in modules called
 # PackageName.PackageConfig (modules to be moved)
 
 # Calibration
@@ -46,7 +43,7 @@ from JetCalibTools import JetCalibToolsConfig
 jetcalibmods = {
     "Calib": JetModifier("JetCalibrationTool","jetcalib_jetcoll_calibseq",
                          createfn=JetCalibToolsConfig.getJetCalibToolFromString,
-                         prereqs=JetCalibToolsConfig.getJetCalibToolPrereqs,passJetDef=True)
+                         prereqs=JetCalibToolsConfig.getJetCalibToolPrereqs)
     }
 jetmoddict.update(jetcalibmods)
 
@@ -67,15 +64,16 @@ jetmomentmods = {
     # More complex cases here
     "CaloEnergies":    JetModifier("JetCaloEnergies", "jetens",
                                    prereqs=["mod:EMScaleMom"]
-    ),
+                                   ),
     "CaloQuality":     JetModifier("JetCaloQualityTool", "caloqual",
-                                   createfn=JetMomentToolsConfig.getCaloQualityTool),
+                                   TimingCuts = [5,10],
+                                   Calculations = ["LArQuality", "N90Constituents", "FracSamplingMax",  "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF", "BchCorrCell"],),
+
     "ConstitFourMom":  JetModifier("JetConstitFourMomTool", "constitfourmom_basename",
-                                   createfn=JetMomentToolsConfig.getConstitFourMomTool,
-                                   passJetDef=True),
+                                   createfn=JetMomentToolsConfig.getConstitFourMomTool,),
     "EMScaleMom":      JetModifier("JetEMScaleMomTool", "emscalemom_basename",
-                                   createfn=JetMomentToolsConfig.getEMScaleMomTool,
-                                   passJetDef=True),
+                                   createfn=JetMomentToolsConfig.getEMScaleMomTool,),
+
     "JVF":             JetModifier("JetVertexFractionTool", "jvf",
                                    createfn=JetMomentToolsConfig.getJVFTool,
                                    prereqs = ["mod:TrackMoments"] ),
@@ -93,6 +91,8 @@ jetmomentmods = {
     "TrackSumMoments": JetModifier("JetTrackSumMomentsTool", "trksummoms",
                                    createfn=JetMomentToolsConfig.getTrackSumMomentsTool,
                                    prereqs = [ "input:JetTrackVtxAssoc","ghost:Track" ]),
+    "Charge" : JetModifier("JetChargeTool", "jetcharge", 
+                                   prereqs = [ "ghost:Track" ]),
 }
 jetmoddict.update(jetmomentmods)
 
@@ -105,7 +105,9 @@ particlejetmods = {
 
     # More complex cases here
     "TruthPartonDR":    JetModifier("Analysis::JetConeLabeling","truthpartondr",
-                                    createfn=ParticleJetToolsConfig.getJetConeLabeling),
+                                    JetTruthMatchTool = lambda *l : CompFactory.Analysis.JetQuarkLabel("jetquarklabel", McEventCollection='TruthEvents') ),
+
+                                    
     "JetDeltaRLabel":   JetModifier("ParticleJetDeltaRLabelTool","jetdrlabeler_jetptmin",
                                     createfn=ParticleJetToolsConfig.getJetDeltaRLabelTool,
                                     prereqs=["ghost:BHadronsFinal",
@@ -116,17 +118,3 @@ jetmoddict.update(particlejetmods)
 
 # Todo: jet substructure moment tools
 
-# This can also be expanded by users if they would rather do this than
-# pass in JetModifier instances in the JetDefinition
-
-
-## TEMPORARY HACK (change the names of ghost tracks )
-from JetRecTools.JetRecToolsConfig import trackcollectionmap
-trackcollectionmap[""] =  {
-    "Tracks":           "InDetTrackParticles",
-    "JetTracks":        "JetSelectedTracks",
-    "Vertices":         "PrimaryVertices",
-    "TVA":              "JetTrackVtxAssoc",
-    "GhostTracks":      "PseudoJetGhostTrack",
-    "GhostTracksLabel": "GhostTrack",
-    }
diff --git a/Reconstruction/Jet/JetRecConfig/python/StandardSmallRJets.py b/Reconstruction/Jet/JetRecConfig/python/StandardSmallRJets.py
index 54f83e59704..af23c0a965e 100644
--- a/Reconstruction/Jet/JetRecConfig/python/StandardSmallRJets.py
+++ b/Reconstruction/Jet/JetRecConfig/python/StandardSmallRJets.py
@@ -12,13 +12,13 @@ from xAODBase.xAODType import xAODType
 standardghosts =  ["Track","MuonSegment","Truth"]
 
 
-flavourghosts = ["TruthLabel"+ghosttype  for ghosttype in [
-    "BHadronsInitial", "BHadronsFinal", "BQuarksFinal",
-    "CHadronsInitial", "CHadronsFinal", "CQuarksFinal",
-    "TausFinal",
-    "WBosons", "ZBosons", "HBosons", "TQuarksFinal",
-    "Partons",]
-]
+#flavourghosts = ["TruthLabel"+ghosttype  for ghosttype in [
+flavourghosts = [ "BHadronsInitial", "BHadronsFinal", "BQuarksFinal",
+                  "CHadronsInitial", "CHadronsFinal", "CQuarksFinal",
+                  "TausFinal",
+                  "WBosons", "ZBosons", "HBosons", "TQuarksFinal",
+                  "Partons",]
+
 
 
 
@@ -27,10 +27,16 @@ flavourghosts = ["TruthLabel"+ghosttype  for ghosttype in [
 # Modifiers for the standard small R jets 
 # *********************************************************
 # (use tuples rather than lists to prevent accidental modification)
-standardrecomods = ( "Filter:10000","Width","TrackMoments","TrackSumMoments","JVF","JVT","OriginSetPV",
-                    "CaloEnergies", )
-clustermods      = ("ECPSFrac","ClusterMoments",)# "LArHVCorr" )
-truthmods        =  ("PartonTruthLabel","TruthPartonDR","JetDeltaRLabel:5000"  ) # not working well yet ?
+standardrecomods = (
+    "ConstitFourMom",   "CaloEnergies",
+    "Calib:T0:mc",
+    "Sort","Filter:10000",
+    "LArHVCorr", "Width",
+     "CaloQuality", "TrackMoments","TrackSumMoments",
+    "JVF","JVT","OriginSetPV", "Charge",
+)
+clustermods      = ("ECPSFrac","ClusterMoments",) 
+truthmods        =  ("PartonTruthLabel","TruthPartonDR","JetDeltaRLabel:5000"  ) 
 pflowmods        = ()
 
 
@@ -41,8 +47,8 @@ pflowmods        = ()
 
 
 AntiKt4EMPFlow = JetDefinition("AntiKt",0.4,cst.EMPFlow,
-                               ghostdefs = standardghosts , # not working well yet : flavourghosts,
-                               modifiers = ("Calib:T0:mc",)+standardrecomods+truthmods, 
+                               ghostdefs = standardghosts+flavourghosts , # not working well yet : flavourghosts,
+                               modifiers = standardrecomods+truthmods, 
                                standardRecoMode = True,                               
                                lock = True
 )
@@ -50,9 +56,8 @@ AntiKt4EMPFlow = JetDefinition("AntiKt",0.4,cst.EMPFlow,
 
 
 
-
 AntiKt4LCTopo = JetDefinition("AntiKt",0.4,cst.LCTopoOrigin,
-                              ghostdefs = standardghosts, # not working well yet : flavourghosts,,
+                              ghostdefs = standardghosts+flavourghosts, 
                               modifiers = standardrecomods+truthmods+clustermods,
                               standardRecoMode = True,
                               lock = True,
@@ -60,20 +65,42 @@ AntiKt4LCTopo = JetDefinition("AntiKt",0.4,cst.LCTopoOrigin,
 
 
 AntiKt4EMTopo = JetDefinition("AntiKt",0.4,cst.EMTopoOrigin,
-                              ghostdefs = standardghosts, # not working well yet : flavourghosts,,
+                              ghostdefs = standardghosts+flavourghosts, 
                               modifiers = standardrecomods+truthmods+clustermods,
                               standardRecoMode = True,
                               lock = True,
 )
 
 AntiKt4Truth = JetDefinition("AntiKt",0.4, cst.Truth,
-                              modifiers = [],
-                              standardRecoMode = True,
-                              lock = True,
+                             ghostdefs = flavourghosts,
+                             modifiers = ("Sort","Filter:10000", "Width")+truthmods,
+                             standardRecoMode = True,
+                             lock = True,
 )
 
 AntiKt4TruthWZ = JetDefinition("AntiKt",0.4, cst.TruthWZ,
-                               modifiers = [],
+                               ghostdefs = flavourghosts,
+                               modifiers = ("Sort","Filter:10000", "Width")+truthmods,
                                standardRecoMode = True,
                                lock = True,
 )
+
+
+
+
+
+def StandardSmallRJetCfg(configFlags):
+    from JetRecConfig.JetRecConfig import JetRecCfg
+
+    standarSmallRList = [
+        AntiKt4EMPFlow,
+        AntiKt4LCTopo,
+        AntiKt4Truth,
+        ]
+
+    compacc = JetRecCfg( standarSmallRList[0], configFlags)
+    for jetdef in standarSmallRList[1:]:
+        compacc.merge( JetRecCfg(jetdef, configFlags) )
+
+    return compacc
+        
diff --git a/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py b/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py
index 4ce98c12c40..518ea15ad8d 100755
--- a/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py
+++ b/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py
@@ -7,44 +7,21 @@ from pprint import pprint, pformat
 from AthenaCommon import Logging
 jetlog = Logging.logging.getLogger("testJetRecDeps")
 
-def JetRecTestCfg(jetdefs,configFlags,args):
-
-    if args.printDependencies:
-        for jetdef in jetdefs:
-            deps = JetRecConfig.resolveDependencies(jetdef)
-            jetlog.info("Dumping dependency dict for {0}".format(jetdef))
-            depstr = pformat(deps)
-            jetlog.info(depstr)
-
-    if args.printAccumulators:
-        jetlog.info("Printing component accumulators for each jet collection")
-    jetcas = []
-    for jetdef in jetdefs:
-       jetcomps = JetRecConfig.JetRecCfg(jetdef,configFlags)
-       if args.printAccumulators:
-           jetcomps.printConfig(withDetails=args.verboseAccumulators,summariseProps=True)
-       jetcas.append(jetcomps)
-
-    jetlog.info("Printing component accumulator for entire sequence")
-    components = ComponentAccumulator()
-    for ca in jetcas:
-        components.merge(ca)
-    components.printConfig(withDetails=args.verboseAccumulators,summariseProps=True)
-
-    return components
-
 def DefineJetCollections(configFlags):
 
-    from JetRecConfig.StandardSmallRJets import standardrecomods, clustermods, truthmods, standardghosts, AntiKt4EMPFlow, AntiKt4Truth, AntiKt4TruthWZ
-
     ########################################################################
+    # import the standard definitions 
+    from JetRecConfig.StandardSmallRJets import  AntiKt4EMPFlow, AntiKt4EMTopo, AntiKt4Truth, AntiKt4TruthWZ
+
     # Example for defining a custom definition
     from JetRecConfig.JetDefinition import JetConstitSeq, JetDefinition, xAODType
+    from JetRecConfig.StandardSmallRJets import standardrecomods, clustermods, truthmods, standardghosts
     EMTopoCSSK = JetConstitSeq("EMTopoOriginCSSK", xAODType.CaloCluster, ["EM","Origin","CS","SK"], "CaloCalTopoClusters", "EMOriginTopoCSSK", label="EMTopoOriginCSSK")
-    AntiKt4EMTopoCSSK = JetDefinition("AntiKt",0.4,EMTopoCSSK,ptmin=2e3,ptminfilter=2e3,prefix="New")
-    AntiKt4EMTopoCSSK.modifiers   = ["ConstitFourMom"]
-    AntiKt4EMTopoCSSK.modifiers  += standardrecomods + clustermods + truthmods
-    AntiKt4EMTopoCSSK.ghostdefs   = standardghosts
+    AntiKt4EMTopoCSSK = JetDefinition("AntiKt",0.4,EMTopoCSSK,ptmin=2e3,prefix="New")
+    recomods = tuple( mod for mod in standardrecomods if not mod.startswith("Calib") ) # remove calib modifier : no calib exists for EMTopoCSSK
+    AntiKt4EMTopoCSSK.modifiers   = ["Filter:2000","ConstitFourMom"]
+    AntiKt4EMTopoCSSK.modifiers  += recomods + clustermods + truthmods
+    AntiKt4EMTopoCSSK.ghostdefs   = standardghosts 
     AntiKt4EMTopoCSSK.extrainputs = ["EventDensity"]
 
     ########################################################################
@@ -52,16 +29,19 @@ def DefineJetCollections(configFlags):
     from JetRecConfig.StandardJetConstits import jetconstitdic
     AntiKt4EMPFlowCSSK = AntiKt4EMPFlow.clone(prefix="New")
     AntiKt4EMPFlowCSSK.inputdef    = jetconstitdic["EMPFlowCSSK"]
-    AntiKt4EMPFlowCSSK.modifiers   = ["ConstitFourMom"]
+    AntiKt4EMPFlowCSSK.modifiers   = ["Filter:2000","ConstitFourMom"]
     AntiKt4EMPFlowCSSK.extrainputs = ["EventDensity"]
 
     jetdefs = [
+        # we re-clone the standard with a prefix to avoid conflicts with pre-existing in-file collections
+        AntiKt4EMTopo.clone(prefix="New"),
+        AntiKt4EMPFlow.clone(prefix="New"),
         AntiKt4EMTopoCSSK,
         AntiKt4EMPFlowCSSK,
     ]
     if configFlags.Input.isMC:
-        jetdefs += [AntiKt4Truth,
-                    AntiKt4TruthWZ]
+        jetdefs += [AntiKt4Truth.clone(prefix="New"),
+                    AntiKt4TruthWZ.clone(prefix="New"),]
     
     return jetdefs
 
@@ -136,7 +116,12 @@ if __name__=="__main__":
     jetdefs = DefineJetCollections(ConfigFlags)
 
     # Add the components from our jet reconstruction job
-    cfg.merge(JetRecTestCfg(jetdefs,ConfigFlags,args))
+    from JetRecConfig.JetRecConfig import JetRecCfg
+    for jetdef in jetdefs:
+        comp = JetRecCfg(jetdef,ConfigFlags)
+        comp.printConfig(withDetails=args.verboseAccumulators,summariseProps=True)
+        
+        cfg.merge(comp)
 
     # Write what we produced to AOD
     # First define the output list
diff --git a/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py b/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py
index 85753fe040b..73d36b3410a 100644
--- a/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py
+++ b/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py
@@ -29,13 +29,13 @@ trackcollectionmap = {
     }
 }
 
-def getTrackSelTool(trkopt="",doWriteTracks=False):
+def getTrackSelTool(trkopt="",doWriteTracks=False, cutLevel="Loose", minPt=500):
 
     # Track selector needs its own hierarchical config getter in JetRecTools?
     idtrackselloose = CompFactory.getComp("InDet::InDetTrackSelectionTool")(
         "idtrackselloose",
-        CutLevel         = "Loose",
-        minPt            = 500,
+        CutLevel         = cutLevel,
+        minPt            = minPt,
         UseTrkTrackTools = False,
         Extrapolator     = "",
         TrackSummaryTool = ""
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoConfiguration.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoConfiguration.py
index d02b8838e59..1e775defaf4 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoConfiguration.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoConfiguration.py
@@ -8,8 +8,9 @@
 # jet reco code.
 
 from JetRecConfig.JetDefinition import JetConstitSeq,JetConstitSource, xAODType, JetDefinition
-from . import TriggerJetMods # this is to define the ConstitFourMom_copy JetModifierC
-TriggerJetMods.ConstitFourMom_copy
+# this is to define trigger specific JetModifiers (ex: ConstitFourMom_copy) : 
+from .TriggerJetMods import jetmoddict  # noqa: F401
+
 from AthenaCommon.Logging import logging
 log = logging.getLogger("TriggerMenuMT.HLTMenuConfig.Jet.JetRecoConfiguration")
 
@@ -180,7 +181,6 @@ def defineGroomedJets(jetRecoDict,ungroomedDef):#,ungroomedJetsName):
 ##########################################################################################
 # Generation of modifier lists. So far only calib, but can add track, substructure mods
 
-from JetRecConfig.StandardJetMods import jetmoddict
 
 # Make generating the list a bit more comprehensible
 def getModSpec(modname,modspec=''):
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/TriggerJetMods.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/TriggerJetMods.py
index 89531ab3a85..24f760f7a0f 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/TriggerJetMods.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/TriggerJetMods.py
@@ -3,20 +3,18 @@ from JetRecConfig.JetDefinition import JetModifier
 
 ########################################################################
 # Special modifier setups used by jet trigger, but not in offline
+# We just extend the jetmoddict from the standard config.
 
-# No need for the special momentum scales, just copy the basic four-vec
-# to "DetectorEtaPhi", because we're not doing origin correction
-# and certainly not with the offline collection names
-from AthenaConfiguration.ComponentFactory import CompFactory
-def getConstitFourMomTool_copy():
-    cfourmom = CompFactory.JetConstitFourMomTool("constitfourmom_copy",
-                                                 JetScaleNames = ["DetectorEtaPhi"],
-                                                 AltConstitColls = [""],
-                                                 AltConstitScales = [0],
-                                                 AltJetScales = ["JetConstitScaleMomentum"])
-    return cfourmom
-
-ConstitFourMom_copy = JetModifier("JetConstitFourMomTool", "constitfourmom_copy",
-                                   createfn=getConstitFourMomTool_copy)
 from JetRecConfig.StandardJetMods import jetmoddict
-jetmoddict['ConstitFourMom_copy'] = ConstitFourMom_copy
+jetmoddict.update(
+
+    # No need for the special momentum scales, just copy the basic four-vec
+    # to "DetectorEtaPhi", because we're not doing origin correction
+    # and certainly not with the offline collection names    
+    ConstitFourMom_copy  = JetModifier("JetConstitFourMomTool", "constitfourmom_copy",
+                                       JetScaleNames = ["DetectorEtaPhi"],
+                                       AltConstitColls = [""],
+                                       AltConstitScales = [0],
+                                       AltJetScales = ["JetConstitScaleMomentum"]                                       
+                                       )
+)
diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/generateJet.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/generateJet.py
index e84e9cf305a..11a1e9117e5 100644
--- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/generateJet.py
+++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/generateJet.py
@@ -64,14 +64,14 @@ def generateChains( flags, chainDict ):
     jetinputdefdic.setdefault(clustersname , JetInputDef(clustersname, xAODType.CaloCluster) )
     #hardcoded jet collection for now 
     clustermods = ["ECPSFrac","ClusterMoments"]
-    trigMinPt = 7e3
+    trigMinPt = 7000
     HLT_EMTopo = JetConstitSeq( "HLT_EMTopo",xAODType.CaloCluster, ["EM"], clustersname, clustersname,label="EMTopo")
     
-    HLT_AntiKt4EMTopo_subjesIS = JetDefinition( "AntiKt", 0.4, HLT_EMTopo, ptmin=trigMinPt,ptminfilter=trigMinPt,
+    HLT_AntiKt4EMTopo_subjesIS = JetDefinition( "AntiKt", 0.4, HLT_EMTopo, ptmin=trigMinPt,
                                                 prefix="HLT_",
                                                 suffix = "_subjesIS",
                                                )
-    HLT_AntiKt4EMTopo_subjesIS.modifiers = ["Calib:TrigRun2:data:JetArea_EtaJES_GSC_Insitu:HLT_Kt4EMTopoEventShape","Sort"] + clustermods 
+    HLT_AntiKt4EMTopo_subjesIS.modifiers = ["Calib:TrigRun2:data:JetArea_EtaJES_GSC_Insitu:HLT_Kt4EMTopoEventShape","Sort", "Filter:"+str(trigMinPt)] + clustermods 
 
     # May need a switch to disable automatic modifier prerequisite generation
     jetRecoComps = JetRecConfig.JetRecCfg(HLT_AntiKt4EMTopo_subjesIS, flags) 
@@ -93,7 +93,7 @@ def generateChains( flags, chainDict ):
                                 CA = acc)
 
     jetStep = ChainStep(name=stepName, Sequences=[jetSequence], chainDicts=[chainDict])
-
+    
     l1Thresholds=[]
     for part in chainDict['chainParts']:
         l1Thresholds.append(part['L1threshold'])
-- 
GitLab