diff --git a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/DefaultTools.py b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/DefaultTools.py
deleted file mode 100644
index 216d829411ffd96399ba44972edb173558be1807..0000000000000000000000000000000000000000
--- a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/DefaultTools.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-
-def declareDefaultTools():
-
-  from JetRecConfig.JetRecFlags import jetFlags
-  from JetRecConfig.JetRecStandardToolManager import jtm
-  from MCTruthClassifier.MCTruthClassifierConf import MCTruthClassifier
-  from JetRec.JetRecConf import PseudoJetGetter
-
-  try:
-    from ParticleJetTools.ParticleJetToolsConf import Analysis__JetQuarkLabel
-    jtm.haveParticleJetTools = True
-  except:
-    jtm.haveParticleJetTools = False
-  if jtm.haveParticleJetTools:
-    from ParticleJetTools.ParticleJetToolsConf import Analysis__JetConeLabeling
-    from ParticleJetTools.ParticleJetToolsConf import Analysis__JetPartonTruthLabel
-    from ParticleJetTools.ParticleJetToolsConf import CopyTruthJetParticles
-    from ParticleJetTools.ParticleJetToolsConf import ParticleJetDeltaRLabelTool
-
-  ghostScaleFactor = 1e-40
-
-  #--------------------------------------------------------------
-  # Truth selection.
-  #--------------------------------------------------------------
-
-  if jetFlags.useTruth:
-      truthClassifier = MCTruthClassifier(name = "JetMCTruthClassifier",
-                                         ParticleCaloExtensionTool="")
-      jtm += truthClassifier
-
-      jtm += CopyTruthJetParticles("truthpartcopy", OutputName="JetInputTruthParticles",
-                                   MCTruthClassifier=truthClassifier)
-      jtm += CopyTruthJetParticles("truthpartcopywz", OutputName="JetInputTruthParticlesNoWZ",
-                                   MCTruthClassifier=truthClassifier,
-                                   IncludePromptLeptons=False,
-                                   IncludeMuons=True,IncludeNeutrinos=True)
-
-  # Truth.
-  if jetFlags.useTruth and jtm.haveParticleJetTools:
-    # ParticleJetTools tools may be omitted in analysi releases.
-    #ift jtm.haveParticleJetTools:
-    # Delta-R truth parton label: truthpartondr.
-    jtm += Analysis__JetQuarkLabel(
-        "jetquarklabel",
-        McEventCollection = "TruthEvents"
-      )
-    jtm += Analysis__JetConeLabeling(
-        "truthpartondr",
-        JetTruthMatchTool = jtm.jetquarklabel
-        )
-
-    # Parton truth label.
-    jtm += Analysis__JetPartonTruthLabel("partontruthlabel")
-
-    # Cone matching for B, C and tau truth for all but track jets.
-    jtm += ParticleJetDeltaRLabelTool(
-      "jetdrlabeler",
-      LabelName = "HadronConeExclTruthLabelID",
-      DoubleLabelName = "HadronConeExclExtendedTruthLabelID",
-      BLabelName = "ConeExclBHadronsFinal",
-      CLabelName = "ConeExclCHadronsFinal",
-      TauLabelName = "ConeExclTausFinal",
-      BParticleCollection = "TruthLabelBHadronsFinal",
-      CParticleCollection = "TruthLabelCHadronsFinal",
-      TauParticleCollection = "TruthLabelTausFinal",
-      PartPtMin = 5000.0,
-      JetPtMin =     0.0,
-      DRMax = 0.3,
-      MatchMode = "MinDR"
-    )
-
-    # Cone matching for B, C and tau truth for track jets.
-    jtm += ParticleJetDeltaRLabelTool(
-      "trackjetdrlabeler",
-      LabelName = "HadronConeExclTruthLabelID",
-      DoubleLabelName = "HadronConeExclExtendedTruthLabelID",
-      BLabelName = "ConeExclBHadronsFinal",
-      CLabelName = "ConeExclCHadronsFinal",
-      TauLabelName = "ConeExclTausFinal",
-      BParticleCollection = "TruthLabelBHadronsFinal",
-      CParticleCollection = "TruthLabelCHadronsFinal",
-      TauParticleCollection = "TruthLabelTausFinal",
-      PartPtMin = 5000.0,
-      JetPtMin = 4500.0,
-      DRMax = 0.3,
-      MatchMode = "MinDR"
-    )
-
-    jtm += PseudoJetGetter(
-      "truthget",
-      Label = "Truth",
-      InputContainer = jtm.truthpartcopy.OutputName,
-      OutputContainer = "PseudoJetTruth",
-      GhostScale = 0.0,
-      SkipNegativeEnergy = True,
-
-    )
-    jtm += PseudoJetGetter(
-      "truthwzget",
-      Label = "TruthWZ",
-      InputContainer = jtm.truthpartcopywz.OutputName,
-      OutputContainer = "PseudoJetTruthWZ",
-      GhostScale = 0.0,
-      SkipNegativeEnergy = True,
-
-    )
-    jtm += PseudoJetGetter(
-      "gtruthget",
-      Label = "GhostTruth",
-      InputContainer = jtm.truthpartcopy.OutputName,
-      OutputContainer = "PseudoJetGhostTruth",
-      GhostScale = ghostScaleFactor,
-      SkipNegativeEnergy = True,
-    )
-
-    # Truth flavor tags.
-    for ptype in jetFlags.truthFlavorTags():
-      jtm += PseudoJetGetter(
-        "gtruthget_" + ptype,
-        InputContainer = "TruthLabel" + ptype,
-        Label = "Ghost" + ptype,
-        OutputContainer = "PseudoJetGhost" + ptype,
-        SkipNegativeEnergy = True,
-        GhostScale = ghostScaleFactor,
-      )
-
-
diff --git a/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..7be92cfb4cd7002994e3e1b5f7b04f448f9b1c4f
--- /dev/null
+++ b/PhysicsAnalysis/AnalysisCommon/ParticleJetTools/python/ParticleJetToolsConfig.py
@@ -0,0 +1,109 @@
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+
+########################################################################
+#                                                                      #
+# ParticleJetToolsConfig: A helper module for configuring tools for    #
+# truth jet reconstruction and classification                          #
+# Author: TJ Khoo                                                      #
+#                                                                      #
+########################################################################
+
+from AthenaCommon import Logging
+jrtlog = Logging.logging.getLogger('ParticleJetToolsConfig')
+
+from ParticleJetTools import ParticleJetToolsConf
+from MCTruthClassifier import MCTruthClassifierConf
+
+# Putting MCTruthClassifier here as we needn't stick jet configs in really foreign packages
+def getMCTruthClassifier():
+    # Assume mc15 value
+    firstSimCreatedBarcode = 200000
+    truthclassif = MCTruthClassifierConf.MCTruthClassifier(
+        "JetMCTruthClassifier",
+        barcodeG4Shift=firstSimCreatedBarcode,
+        xAODTruthLinkVector=""
+        )
+    # Config neessary only for Athena releases
+    import os
+    if "AtlasProject" in os.environ.keys():
+        if os.environ["AtlasProject"] in ["Athena","AthDerivation"]:
+            truthclassif.ParticleCaloExtensionTool=""
+    return truthclassif
+
+# Generates truth particle containers for truth labeling
+truthpartoptions = {
+    "Partons":{"ToolType":ParticleJetToolsConf.CopyTruthPartons,"ptmin":5000},
+    "BosonTop":{"ToolType":ParticleJetToolsConf.CopyBosonTopLabelTruthParticles,"ptmin":100000},
+    "FlavourLabel":{"ToolType":ParticleJetToolsConf.CopyFlavorLabelTruthParticles,"ptmin":5000},
+}
+def getCopyTruthLabelParticles(truthtype):
+    truthcategory = ""
+    if truthtype == "Partons":
+        truthcategory = "Partons"
+    if truthtype in ["WBosons", "ZBosons", "HBosons", "TQuarksFinal"]:
+        truthcategory = "BosonTop"
+    else:
+        truthcategory = "FlavourLabel"
+    tooltype = truthpartoptions[truthcategory]["ToolType"]
+    ptmin = truthpartoptions[truthcategory]["ptmin"]
+    ctp = tooltype("truthpartcopy_{0}".format(truthtype),
+                   PtMin = ptmin,
+                   OutputName = "TruthLabel{0}".format(truthtype))
+    return ctp
+
+# Generates input truth particle containers for truth jets
+def getCopyTruthJetParticles(modspec):
+    truthclassif = getMCTruthClassifier()
+
+    # Commented for now -- we ideally need a dual-use input file peeker
+    # # Input file is EVNT
+    # if objKeyStore.isInInput( "McEventCollection", "GEN_EVENT" ):
+    #    barCodeFromMetadata=0
+
+    truthpartcopy = ParticleJetToolsConf.CopyTruthJetParticles(
+        "truthpartcopy"+modspec,
+        OutputName="JetInputTruthParticles"+modspec,
+        MCTruthClassifier=truthclassif,
+        BarCodeFromMetadata=2)
+    if modspec=="NoWZ":
+        truthpartcopy.IncludePromptLeptons=False
+        # truthpartcopy.IncludePromptPhotons=False # Needs cherry-pick from 21.2
+        truthpartcopy.IncludeMuons=True
+        truthpartcopy.IncludeNeutrinos=True
+    return truthpartcopy
+
+def getJetQuarkLabel():
+    jetquarklabel = ParticleJetToolsConf.Analysis__JetQuarkLabel(
+        "jetquarklabel",
+        McEventCollection = "TruthEvents"
+        )
+    return jetquarklabel
+
+def getJetConeLabeling():
+    jetquarklabel = getJetQuarkLabel()
+    truthpartonlabel = ParticleJetToolsConf.Analysis__JetConeLabeling(
+        "truthpartondr",
+        JetTruthMatchTool = jetquarklabel
+        )
+    return truthpartonlabel
+
+  # Cone matching for B, C and tau truth for all but track jets.
+def getJetDeltaRLabelTool(modspec):
+    jetptmin = float(modspec)
+    jetdrlabeler = ParticleJetToolsConf.ParticleJetDeltaRLabelTool(
+        "jetdrlabeler_jetpt{0}GeV".format(int(jetptmin/1000)),
+        LabelName = "HadronConeExclTruthLabelID",
+        DoubleLabelName = "HadronConeExclExtendedTruthLabelID",
+        BLabelName = "ConeExclBHadronsFinal",
+        CLabelName = "ConeExclCHadronsFinal",
+        TauLabelName = "ConeExclTausFinal",
+        BParticleCollection = "TruthLabelBHadronsFinal",
+        CParticleCollection = "TruthLabelCHadronsFinal",
+        TauParticleCollection = "TruthLabelTausFinal",
+        PartPtMin = 5000.,
+        DRMax = 0.3,
+        MatchMode = "MinDR"
+        )
+    jetdrlabeler.JetPtMin = jetptmin
+    return jetdrlabeler
+
diff --git a/Reconstruction/Jet/JetCalibTools/CMakeLists.txt b/Reconstruction/Jet/JetCalibTools/CMakeLists.txt
index cc91dcd05139af95363d29662553e7b32a7ad2fd..085c9517d9ccab5c27363e2d3bb752547976dda9 100644
--- a/Reconstruction/Jet/JetCalibTools/CMakeLists.txt
+++ b/Reconstruction/Jet/JetCalibTools/CMakeLists.txt
@@ -108,3 +108,4 @@ else()
 
 endif()
 
+atlas_install_python_modules( python/*.py )
diff --git a/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py b/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..727e82cd76996a9682d7375a9bdf3bd2925af53a
--- /dev/null
+++ b/Reconstruction/Jet/JetCalibTools/python/JetCalibToolsConfig.py
@@ -0,0 +1,166 @@
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+
+########################################################################
+#                                                                      #
+# JetCalibConfig: A helper module for configuring jet calibration      #
+# The intention is to encode a limited set of configurations that      #
+# are sane, to ease consistency for various users.                     #
+# This module should eventually go in JetCalibTools and be kept in     #
+# sync with the latest available recommendations.                      #
+# Author: TJ Khoo                                                      #
+#                                                                      #
+########################################################################
+
+from AthenaCommon import Logging
+jetcaliblog = Logging.logging.getLogger('JetCalibToolsConfig')
+
+from JetCalibTools import JetCalibToolsConf
+
+all = ['getJetCalibTool']
+
+# These context definitions could be placed in another package and made
+# more robust with a small python class to hold the info.
+# The convention is: config file, calibarea, default calibration sequence
+pflowcontexts = {
+    "T0":("JES_MC15cRecommendation_PFlow_Aug2016_rel21.config","00-04-77","JetArea_Residual_EtaJES"),
+    # Omit smearing, to avoid any efficiency loss
+    "AnalysisLatest":("JES_data2017_2016_2015_Consolidated_PFlow_2018_Rel21.config","00-04-82","JetArea_Residual_EtaJES_GSC"),
+}
+
+topocontexts = {
+    "T0":("JES_MC15cRecommendation_May2016_rel21.config","00-04-77","JetArea_Residual_EtaJES"),
+    # Placeholder from a vague approximation of the 2017 setup?
+    "Trigger":("JES_MC15cRecommendation_May2016_Trigger.config","00-04-77","JetArea_Residual_EtaJES"),
+    # Omit smearing, to avoid any efficiency loss
+    "AnalysisLatest":("JES_data2017_2016_2015_Consolidated_EMTopo_2018_Rel21.config","00-04-82","JetArea_Residual_EtaJES_GSC"),
+}
+
+rscanlc2 = {
+    "RScanLatest":("JES_MC16Recommendation_Rscan2LC_22Feb2018_rel21.config","00-04-81","JetArea_Residual_EtaJES_GSC")
+}
+
+rscanlc6 = {
+    "RScanLatest":("JES_MC16Recommendation_Rscan6LC_22Feb2018_rel21.config","00-04-81","JetArea_Residual_EtaJES_GSC")
+}
+
+fatjetcontexts = {
+    "CombinedMass": ("JES_MC16recommendation_FatJet_JMS_comb_19Jan2018.config","00-04-81","EtaJES_JMS"),
+    "CaloMass":     ("JES_MC16recommendation_FatJet_JMS_calo_29Nov2017.config","00-04-81","EtaJES_JMS"),
+    "TAMass":       ("JES_MC16recommendation_FatJet_JMS_TA_29Nov2017.config","00-04-81","EtaJES_JMS"),
+}
+
+# List AFII config files separately, to avoid needing to specify a different context
+af2configs = {
+    "AntiKt4EMPFlow": "JES_MC16Recommendation_AFII_PFlow_April2018_rel21.config",
+    "AntiKt4EMTopo":  "JES_MC16Recommendation_AFII_EMTopo_April2018_rel21.config",
+    "AntiKt4LCTopo":  "JES_MC16Recommendation_AFII_EMTopo_April2018_rel21.config",
+}
+
+calibcontexts = {
+    # Standard AntiKt4
+    "AntiKt4EMPFlow":pflowcontexts,
+    "AntiKt4EMTopo":topocontexts,
+    "AntiKt4LCTopo":topocontexts,
+    # Standard trimmed
+    "AntiKt10LCTopoTrimmedPtFrac5SmallR20":fatjetcontexts,
+    # R-Scan
+    "AntiKt2LCTopo":rscanlc2,
+    "AntiKt6LCTopo":rscanlc6,
+
+}
+
+hasInSitu = ["AntiKt4LCTopo", "AntiKt4EMTopo", "AntiKt4EMPFlow"]
+
+# This method extracts the relevant configuration, does some consistency checks,
+# then forwards the configuration to defineJetCalibTool, returning the output.
+# At present the interface allows for the calibseq to be chosen freely, other
+# than checking that the data source is data for the in situ correction.
+# The calibarea could be made configurable as well, but then might need to be
+# added to the tool name to ensure uniqueness.
+# Due to the hackiness of DualUseConfig public tool handling, we need to pass
+# an AlgSequence...
+def getJetCalibTool(jetcollection, context, data_type, calibseq = ""):
+    # In principle we could autoconfigure
+    if not data_type in ['data','mc','afii']:
+        jetcaliblog.error("JetCalibConfig accepts data_type values: 'data', 'mc', 'afii'")
+        raise ValueError("Unsupported data_type provided: '{0}".format(data_type))
+
+    if jetcollection.endswith("Jets"):
+        jetcaliblog.error("Jet collection '{0}'should be specified w/o 'Jets' in the name.".format(jetcollection))
+        raise ValueError("Bad jet collection formatting in getJetCalibTool.")
+
+    jetcaliblog.debug("Preparing calibration for {0}, in context {1} on sample type {2}".format(jetcollection,context,data_type))
+
+    jetcontexts = calibcontexts[jetcollection]
+    try:
+        configfile, calibarea, calibseq_def = jetcontexts[context]
+        calibseq_tmp = calibseq if calibseq else calibseq_def
+        if data_type == 'data' and calibseq_tmp.endswith("GSC") and jetcollection in hasInSitu:
+            if calibseq_tmp == calibseq_def:
+                calibseq_tmp += "_InSitu"
+            # May not be strictly necessary if already checked in JCT
+            elif not calibseq_tmp.endswith("InSitu"):
+                jetcaliblog.warning("Calibration of jets requested in data without in situ calibration.")
+        configfile_tmp = configfile
+        if data_type == "afii" and jetcollection in af2configs.keys():
+            configfile_tmp = af2configs[jetcollection]
+        data_type_tmp = data_type
+        # Most likely an oversight, but R20/21 JetRecCalibrationFinder did not set the data flag
+        # This affects the residual correction by scaling mu.
+        # We should revert this later on, set up now for validation purposes
+        if context == "T0":
+            data_type_tmp = "data"
+        return defineJetCalibTool(jetcollection, configfile_tmp, calibarea, calibseq_tmp, data_type_tmp)
+    except KeyError as e:
+        jetcaliblog.error("Context '{0}' not found for jet collection '{1}'".format(context,jetcollection))
+        jetcaliblog.error("Options are '{0}".format(','.join(jetcontexts.keys())))
+        raise e
+    return None
+
+# This method actually sets up the tool
+def defineJetCalibTool(jetcollection, configfile, calibarea, calibseq, data_type):
+    # Abbreviate the calib sequence
+    calibseqshort = ''.join([ step[0] for step in calibseq.split('_') ])
+    toolname = "jetcalib_{0}_{1}".format(jetcollection,calibseqshort)
+    #
+    jct = JetCalibToolsConf.JetCalibrationTool(toolname,
+        JetCollection = jetcollection,
+        ConfigFile = configfile,
+        CalibArea = calibarea,
+        CalibSequence = calibseq,
+        IsData = (data_type == "data")
+    )
+    return jct
+
+# This method extends the basic config getter to specify the requisite jet
+# moments or other inputs
+def getJetCalibToolPrereqs(modspec,jetdef):
+    calibcontext, data_type, calibseq = getCalibSpecsFromString(modspec)
+    if calibseq=="":
+        cfg, calibarea, calibseq = calibcontexts[jetdef.basename][calibcontext]
+    # For now, only dependent on calibseq -- can ignore InSitu, which is
+    # added when getting the concrete tool
+    prereqs = []
+    prereqs.append("mod:ConstitFourMom")
+    if "JetArea" in calibseq:
+        prereqs.append("input:EventDensity")
+    if "GSC" in calibseq:
+        prereqs += ["mod:CaloEnergies",
+                    "mod:TrackMoments",
+                    "ghost:MuonSegment"]
+    jetcaliblog.debug("Prereqs for calibseq '{0}': {1}".format(calibseq,str(prereqs)))
+    return prereqs
+
+# This method translates the mod specification string into calibration specifications
+def getCalibSpecsFromString(modspec):
+    calibseq = ""
+    calibspecs = modspec.split(':')
+    # Probably want data_type to come from elsewhere
+    calibcontext, data_type = calibspecs[:2]
+    if len(calibspecs)>2: calibseq = calibspecs[2]
+    return calibcontext, data_type, calibseq
+
+# This method instantiates the JetCalibTool given the input mod specification
+def getJetCalibToolFromString(modspec,jetdef):
+    calibcontext, data_type, calibseq = getCalibSpecsFromString(modspec)
+    return getJetCalibTool(jetdef.basename,calibcontext,data_type,calibseq)
diff --git a/Reconstruction/Jet/JetMomentTools/python/DefaultTools.py b/Reconstruction/Jet/JetMomentTools/python/DefaultTools.py
deleted file mode 100644
index 32d39fa8370087c25193ba7030e84e004fe8eb8d..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetMomentTools/python/DefaultTools.py
+++ /dev/null
@@ -1,378 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-
-from JetMomentTools.JetMomentToolsConf import JetCaloQualityTool
-from JetMomentTools.JetMomentToolsConf import JetWidthTool
-from JetMomentTools.JetMomentToolsConf import JetCaloEnergies
-from JetMomentTools.JetMomentToolsConf import JetECPSFractionTool
-from JetMomentTools.JetMomentToolsConf import JetVertexFractionTool
-from JetMomentTools.JetMomentToolsConf import JetVertexTaggerTool
-from JetMomentTools.JetMomentToolsConf import JetTrackMomentsTool
-from JetMomentTools.JetMomentToolsConf import JetTrackSumMomentsTool
-from JetMomentTools.JetMomentToolsConf import JetClusterMomentsTool
-from JetMomentTools.JetMomentToolsConf import JetVoronoiMomentsTool
-from JetMomentTools.JetMomentToolsConf import JetIsolationTool
-from JetMomentTools.JetMomentToolsConf import JetLArHVTool
-from JetMomentTools.JetMomentToolsConf import JetOriginCorrectionTool
-from JetMomentTools.JetMomentToolsConf import JetConstitFourMomTool
-
-def declareDefaultTools():
-
-  from JetRecConfig.JetRecFlags import jetFlags
-  from JetRecConfig.JetRecStandardToolManager import jtm
-  try:
-    from JetMomentTools.JetMomentToolsConf import JetCaloCellQualityTool
-    jtm.haveJetCaloCellQualityTool = True
-  except ImportError:
-    jtm.haveJetCaloCellQualityTool = False
-
-  try:
-    from JetMomentTools.JetMomentToolsConf import JetJetBadChanCorrTool
-    jtm.haveJetBadChanCorrTool = True
-  except ImportError:
-    jtm.haveJetBadChanCorrTool = False
-
-  from JetRecTools.JetRecToolsConf import TrackVertexAssociationTool
-  from JetRec.JetRecConf import PseudoJetGetter
-  from JetRecTools.JetRecToolsConf import TrackPseudoJetGetter
-  from InDetTrackSelectionTool.InDetTrackSelectionToolConf import InDet__InDetTrackSelectionTool
-  from JetRecTools.JetRecToolsConf import JetTrackSelectionTool
-  from JetRecTools.JetRecToolsConf import SimpleJetTrackSelectionTool
-
-  #--------------------------------------------------------------
-  # Non-substructure moment builders.
-  #--------------------------------------------------------------
-
-  # Quality from clusters.
-  jtm += JetCaloQualityTool(
-    "caloqual_cluster",
-    TimingCuts = [5, 10],
-    Calculations = ["LArQuality", "N90Constituents", "FracSamplingMax",  "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF", "BchCorrCell"],
-  )
-
-  # Quality from cells.
-  if jtm.haveJetCaloCellQualityTool:
-    jtm += JetCaloCellQualityTool(
-      "caloqual_cell",
-      LArQualityCut = 4000,
-      TileQualityCut = 254,
-      TimingCuts = [5, 10],
-      Calculations = ["LArQuality", "N90Cells", "FracSamplingMax",  "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF"]
-    )
-
-  # Jet width.
-  jtm += JetWidthTool("width", WeightPFOToolEM=jtm.pflowweighter, WeightPFOToolLC=jtm.pflowweighterLC)
-
-  # Calo layer energies.
-  jtm += JetCaloEnergies("jetens")
-
-  # Read in missing cell map (needed for the following)
-  # commented out : incompatible with trigger : ATR-9696
-  ## if jtm.haveJetRecCalo:
-  ##     def missingCellFileReader(): 
-  ##       import os
-  ##       dataPathList = os.environ[ 'DATAPATH' ].split(os.pathsep)
-  ##       dataPathList.insert(0, os.curdir)
-  ##       from AthenaCommon.Utils.unixtools import FindFile
-  ##       RefFileName = FindFile( "JetBadChanCorrTool.root" ,dataPathList, os.R_OK )
-  ##       from AthenaCommon.AppMgr import ServiceMgr
-  ##       if not hasattr(ServiceMgr, 'THistSvc'):
-  ##         from GaudiSvc.GaudiSvcConf import THistSvc
-  ##         ServiceMgr += THistSvc()
-  ##       ServiceMgr.THistSvc.Input += ["JetBadChanCorrTool DATAFILE=\'%s\' OPT=\'READ\'" % RefFileName]
-  ##       missingCellFileReader.called = True 
-
-  ##     missingCellFileReader()
-
-  ##     jtm += MissingCellListTool(
-  ##       "missingcells",
-  ##       AddCellList = [],
-  ##       RemoveCellList = [],
-  ##       AddBadCells = True,
-  ##       DeltaRmax = 1.0,
-  ##       AddCellFromTool = False,
-  ##       LArMaskBit = 608517,
-  ##       TileMaskBit = 1,
-  ##       MissingCellMapName = "MissingCaloCellsMap"
-  ## )
-
-  ## # Bad channel corrections from cells
-  ## if jtm.haveJetBadChanCorrTool:
-  ##   jtm += JetBadChanCorrTool(
-  ##     "bchcorrcell",
-  ##     NBadCellLimit = 10000,
-  ##     StreamName = "/JetBadChanCorrTool/",
-  ##     ProfileName = "JetBadChanCorrTool.root",
-  ##     ProfileTag = "",
-  ##     UseCone = True,
-  ##     UseCalibScale = False,
-  ##     MissingCellMap = "MissingCaloCellsMap",
-  ##     ForceMissingCellCheck = False,
-  ##     UseClusters = False,
-  ##   )
-
-  ##   # Bad channel corrections from clusters
-  ##   jtm += JetBadChanCorrTool(
-  ##     "bchcorrclus",
-  ##     NBadCellLimit = 0,
-  ##     StreamName = "",
-  ##     ProfileName = "",
-  ##     ProfileTag = "",
-  ##     UseCone = True,
-  ##     UseCalibScale = False,
-  ##     MissingCellMap = "",
-  ##     ForceMissingCellCheck = False,
-  ##     UseClusters = True
-  ##   )
-
-  # Bad LAr fractions.
-  jtm += JetECPSFractionTool(
-    "ecpsfrac",
-  )
-
-  #--------------------------------------------------------------
-  # Track-vertex association.
-  #--------------------------------------------------------------
-  from TrackVertexAssociationTool.TrackVertexAssociationToolConf import CP__TightTrackVertexAssociationTool
-  jtm += CP__TightTrackVertexAssociationTool("jetTighTVAtool", dzSinTheta_cut=3, doPV=True)
-
-  jtm += TrackVertexAssociationTool(
-    "tvassoc",
-    TrackParticleContainer  = jtm.trackContainer,
-    TrackVertexAssociation  = "JetTrackVtxAssoc",
-    VertexContainer         = jtm.vertexContainer,
-    TrackVertexAssoTool     = jtm.jetTighTVAtool,
-  )
-
-  jtm += TrackVertexAssociationTool(
-    "tvassoc_old",
-    TrackParticleContainer  = jtm.trackContainer,
-    TrackVertexAssociation  = "JetTrackVtxAssoc_old",
-    VertexContainer         = jtm.vertexContainer,
-    MaxTransverseDistance   = 1.5,
-    MaxLongitudinalDistance = 1.0e7,
-    MaxZ0SinTheta = 1.5
-  )
-
-  #--------------------------------------------------------------
-  # Track selection.
-  #--------------------------------------------------------------
-
-  # This is the InDet loose selection from
-  # https://twiki.cern.ch/twiki/bin/view/AtlasProtected/InDetTrackingPerformanceGuidelines
-  # October 28, 2014
-  #jtm += InDet__InDetDetailedTrackSelectionTool(
-  jtm += InDet__InDetTrackSelectionTool(
-    "trk_trackselloose",
-    CutLevel                = "Loose"
-  )
-
-  jtm += JetTrackSelectionTool(
-    "trackselloose",
-    InputContainer  = jtm.trackContainer,
-    OutputContainer = "JetSelectedTracks",
-    Selector        = jtm.trk_trackselloose
-  )
-
-  jtm += InDet__InDetTrackSelectionTool(
-    "trk_trackselloose_trackjets",
-    CutLevel                = "Loose"
-  )
-
-  jtm += JetTrackSelectionTool(
-     "trackselloose_trackjets",
-    InputContainer  = jtm.trackContainer,
-    OutputContainer = "JetSelectedTracks_LooseTrackJets",
-    Selector        = jtm.trk_trackselloose_trackjets
-  )
-
-  if jetFlags.useInDetTrackSelection():
-    jtm += JetTrackSelectionTool(
-      "tracksel",
-      InputContainer  = jtm.trackContainer,
-      OutputContainer = "JetSelectedTracks",
-      Selector        = jtm.trk_trackselloose
-    )
-  else:
-    jtm += SimpleJetTrackSelectionTool(
-      "tracksel",
-      PtMin = 500.0,
-      InputContainer  = jtm.trackContainer,
-      OutputContainer = "JetSelectedTracks",
-    )
-
-
-  # Tracks.
-  jtm += TrackPseudoJetGetter(
-    "trackget",
-    InputContainer = jtm.trackselloose_trackjets.OutputContainer,
-    Label = "Track",
-    OutputContainer = "PseudoJetTracks",
-    TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-    SkipNegativeEnergy = True,
-    GhostScale = 0.0
-  )
-
-
-  # Ghost tracks.
-  jtm += TrackPseudoJetGetter(
-    "gtrackget",
-    InputContainer = jtm.tracksel.OutputContainer,
-    Label = "GhostTrack",
-    OutputContainer = "PseudoJetGhostTracks",
-    TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-    SkipNegativeEnergy = True,
-    GhostScale = 1e-20
-  )
-
-
-  # Jet vertex fraction.
-  jtm += JetVertexFractionTool(
-    "jvfold",
-    VertexContainer = jtm.vertexContainer,
-    AssociatedTracks = "GhostTrack",
-    TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-    JVFName = "JVFOld"
-  )
-
-  # Jet vertex fraction with selection.
-  jtm += JetVertexFractionTool(
-    "jvf",
-    VertexContainer = jtm.vertexContainer,
-    AssociatedTracks = "GhostTrack",
-    TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-    TrackSelector = jtm.trackselloose,
-    JVFName = "JVF"
-  )
-
-  # Jet vertex tagger.
-  jtm += JetVertexTaggerTool(
-    "jvt",
-    VertexContainer = jtm.vertexContainer,
-    TrackParticleContainer  = jtm.trackContainer,
-    AssociatedTracks = "GhostTrack",
-    TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-    TrackSelector = jtm.trackselloose,
-    JVTName = "Jvt",
-    K_JVFCorrScale = 0.01,
-    Z0Cut = 3.0,
-    PUTrkPtCut = 30000.0
-  )
-
-  # Jet track info.
-  jtm += JetTrackMomentsTool(
-    "trkmoms",
-    VertexContainer = jtm.vertexContainer,
-    AssociatedTracks = "GhostTrack",
-    TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-    TrackMinPtCuts = [500, 1000],
-    TrackSelector = jtm.trackselloose
-  )
-
-  # Jet track vector sum info
-  jtm += JetTrackSumMomentsTool(
-    "trksummoms",
-    VertexContainer = jtm.vertexContainer,
-    AssociatedTracks = "GhostTrack",
-    TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-    RequireTrackPV = True,
-    TrackSelector = jtm.trackselloose
-  )
-
-  # Jet cluster info.
-  jtm += JetClusterMomentsTool(
-    "clsmoms",
-    DoClsPt = True,
-    DoClsSecondLambda = True,
-    DoClsCenterLambda = True,
-    DoClsSecondR = True
-  )
-
-
-  jtm += JetVoronoiMomentsTool(
-    "voromoms",
-    AreaXmin= -5.,
-    AreaXmax=  5.,
-    AreaYmin= -3.141592,
-    AreaYmax=  3.141592
-  )
-
-  # Isolations.
-  # Note absence of PseudoJetGetter property means the jet inputs
-  # are obtained according to the InputType property of the jet.
-  jtm += JetIsolationTool(
-    "jetisol",
-    IsolationCalculations = ["IsoDelta:2:SumPt", "IsoDelta:3:SumPt"],
-  )
-  jtm += JetIsolationTool(
-    "run1jetisol",
-    IsolationCalculations = ["IsoKR:11:Perp", "IsoKR:11:Par", "IsoFixedCone:6:SumPt",],
-  )
-
-
-  # Bad LAr fractions.
-  jtm += JetLArHVTool("larhvcorr")
-
-
-  # Jet origin correction.
-  jtm += JetOriginCorrectionTool(
-    "jetorigincorr",
-    VertexContainer = jtm.vertexContainer,
-    OriginCorrectedName = "JetOriginConstitScaleMomentum"
-  )
-
-  # Just set the PV without applying origin correction
-  jtm += JetOriginCorrectionTool(
-    "jetorigin_setpv",
-    VertexContainer = jtm.vertexContainer,
-    OriginCorrectedName = "",
-    OnlyAssignPV = True,
-  )
-
-
-### 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...
-### Defined in Event/xAOD/xAODCaloEvent/versions/CaloCluster_v1.h
-CaloClusterStates = { 
-  "UNKNOWN"       : -1,
-  "UNCALIBRATED"  :  0,
-  "CALIBRATED"    :  1,
-  "ALTCALIBRATED" :  2,
-  "NSTATES"       :  3
-  }
-
-### Workaround for inability of Gaudi to parse single-element tuple
-import GaudiPython.Bindings as GPB
-_old_setattr = GPB.iProperty.__setattr__
-def _new_setattr(self, name, value):
-   if type(value) == tuple:
-       value = list(value)
-   return _old_setattr(self, name, value)
-GPB.iProperty.__setattr__ = _new_setattr
-###
-
-jtm += JetConstitFourMomTool(
-  "constitfourmom_lctopo",
-  JetScaleNames = ["DetectorEtaPhi"],
-  AltConstitColls = ["CaloCalTopoClusters"],
-  AltConstitScales = [CaloClusterStates["CALIBRATED"]],
-  AltJetScales = [""]
-  )
-
-jtm += JetConstitFourMomTool(
-  "constitfourmom_emtopo",
-  JetScaleNames = ["DetectorEtaPhi","JetLCScaleMomentum"],
-  AltConstitColls = ["CaloCalTopoClusters","LCOriginTopoClusters" if jetFlags.useTracks() else "CaloCalTopoClusters"],
-  AltConstitScales = [CaloClusterStates["UNCALIBRATED"],CaloClusterStates["CALIBRATED"]],
-  AltJetScales = ["",""]
-  )
-
-jtm += JetConstitFourMomTool(
-  "constitfourmom_pflow",
-  JetScaleNames = ["DetectorEtaPhi"],
-  AltConstitColls = [""],
-  AltConstitScales = [0],
-  AltJetScales = ["JetConstitScaleMomentum"]
-  )
-
diff --git a/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py b/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..a30b13be9b97ed3c18358767b2a6f0b268aef519
--- /dev/null
+++ b/Reconstruction/Jet/JetMomentTools/python/JetMomentToolsConfig.py
@@ -0,0 +1,121 @@
+# Copyright (C) 2002-2019 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                                                      #
+#                                                                      #
+########################################################################
+
+from AthenaCommon import Logging
+jetmomentlog = Logging.logging.getLogger('JetMomentToolsConfig')
+
+from JetRecTools import JetRecToolsConfig
+from JetMomentTools import JetMomentToolsConf
+
+def getCaloQualityTool():
+    caloqual = JetMomentToolsConf.JetCaloQualityTool(
+      "caloqual",
+      TimingCuts = [5, 10],
+      Calculations = ["LArQuality", "N90Constituents", "FracSamplingMax",  "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF", "BchCorrCell"],
+    )
+    return caloqual
+
+def getConstitFourMomTool(jetdef):
+    # All this code needs to live in a JetMomentTools module
+
+    ### 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...
+    ### Defined in Event/xAOD/xAODCaloEvent/versions/CaloCluster_v1.h
+    CaloClusterStates = {
+      "UNKNOWN"       : -1,
+      "UNCALIBRATED"  :  0,
+      "CALIBRATED"    :  1,
+      "ALTCALIBRATED" :  2,
+      "NSTATES"       :  3
+      }
+
+    ### Workaround for inability of Gaudi to parse single-element tuple
+    try:
+        import GaudiPython.Bindings as GPB
+        _old_setattr = GPB.iProperty.__setattr__
+        def _new_setattr(self, name, value):
+           if type(value) == tuple:
+               value = list(value)
+           return _old_setattr(self, name, value)
+        GPB.iProperty.__setattr__ = _new_setattr
+    except:
+        pass
+    ###
+    cfourmom = JetMomentToolsConf.JetConstitFourMomTool("constitfourmom_{0}".format(jetdef.basename))
+    if "LCTopo" in jetdef.basename:
+        cfourmom.JetScaleNames = ["DetectorEtaPhi"]
+        cfourmom.AltConstitColls = ["CaloCalTopoClusters"]
+        cfourmom.AltConstitScales = [CaloClusterStates["CALIBRATED"]]
+        cfourmom.AltJetScales = [""]
+    elif "EMTopo" in jetdef.basename:
+        cfourmom.JetScaleNames = ["DetectorEtaPhi","JetLCScaleMomentum"]
+        cfourmom.AltConstitColls = ["CaloCalTopoClusters","LCOriginTopoClusters" if "Origin" in jetdef.inputdef.modifiers else "CaloCalTopoClusters"]
+        cfourmom.AltConstitScales = [CaloClusterStates["UNCALIBRATED"],CaloClusterStates["CALIBRATED"]]
+        cfourmom.AltJetScales = ["",""]
+    elif "EMPFlow" in jetdef.basename:
+        cfourmom.JetScaleNames = ["DetectorEtaPhi"]
+        cfourmom.AltConstitColls = [""]
+        cfourmom.AltConstitScales = [0]
+        cfourmom.AltJetScales = ["JetConstitScaleMomentum"]
+
+    return cfourmom
+
+# Jet vertex fraction with selection.
+def getJVFTool():
+    jettrackselloose = JetRecToolsConfig.getTrackSelTool()
+
+    jvf = JetMomentToolsConf.JetVertexFractionTool(
+        "jvf",
+        VertexContainer = "PrimaryVertices",
+        AssociatedTracks = "GhostTrack",
+        TrackVertexAssociation = "JetTrackVtxAssoc",
+        TrackParticleContainer  = "JetSelectedTracks",
+        TrackSelector = jettrackselloose,
+    )
+    return jvf
+
+
+def getTrackMomentsTool():
+    jettrackselloose = JetRecToolsConfig.getTrackSelTool()
+
+    trackmoments = JetMomentToolsConf.JetTrackMomentsTool(
+        "trkmoms",
+        VertexContainer = "PrimaryVertices",
+        AssociatedTracks = "GhostTrack",
+        TrackVertexAssociation = "JetTrackVtxAssoc",
+        TrackMinPtCuts = [500, 1000],
+        TrackSelector = jettrackselloose
+    )
+    return trackmoments
+
+def getTrackSumMomentsTool():
+    jettrackselloose = JetRecToolsConfig.getTrackSelTool()
+
+    tracksummoments = JetMomentToolsConf.JetTrackSumMomentsTool(
+        "trksummoms",
+        VertexContainer = "PrimaryVertices",
+        AssociatedTracks = "GhostTrack",
+        TrackVertexAssociation = "JetTrackVtxAssoc",
+        RequireTrackPV = True,
+        TrackSelector = jettrackselloose
+    )
+    return tracksummoments
+
+# 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():
+    origin_setpv = JetMomentToolsConf.JetOriginCorrectionTool(
+      "jetorigin_setpv",
+      VertexContainer = "PrimaryVertices",
+      OriginCorrectedName = "",
+      OnlyAssignPV = True,
+    )
+    return origin_setpv
diff --git a/Reconstruction/Jet/JetRec/python/DefaultTools.py b/Reconstruction/Jet/JetRec/python/DefaultTools.py
deleted file mode 100644
index b66bd49c020a2ba0b664bdaaec0809a0e1cdbeb6..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRec/python/DefaultTools.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-
-from JetRecConf import JetPseudojetRetriever
-from JetRecConf import JetConstituentsRetriever
-from JetRecConf import JetRecTool
-from JetRecConf import PseudoJetGetter
-from JetRecConf import MuonSegmentPseudoJetGetter
-from JetRecConf import JetFromPseudojet
-from JetRecConf import JetConstitRemover
-from JetRecConf import JetSorter
-
-def declareDefaultTools():
-  from JetRecConfig.JetRecFlags import jetFlags
-  from JetRecConfig.JetRecStandardToolManager import jtm
-
-  ghostScaleFactor = 1e-40
-
-  #--------------------------------------------------------------
-  # Jet reco infrastructure.
-  #--------------------------------------------------------------
-
-  # Jet pseudojet retriever.
-  jtm += JetPseudojetRetriever("jpjretriever")
-
-  # Jet constituent retriever.
-  labs = []
-  if jetFlags.useTracks():
-    labs += ["Track"]
-    labs += ["AntiKt2TrackJet", "AntiKt2TrackJet"]
-  if jetFlags.useMuonSegments():
-    labs += ["MuonSegment",]
-  if jetFlags.useTruth():
-    labs += ["Truth"]
-    for lab in jetFlags.truthFlavorTags():
-      labs += [lab]
-  jtm += JetConstituentsRetriever(
-    "jconretriever",
-    UsePseudojet = True,
-    UseJetConstituents = True,
-    PseudojetRetriever = jtm.jpjretriever,
-    GhostLabels = labs,
-    GhostScale = ghostScaleFactor
-  )
-
-  #--------------------------------------------------------------
-  # Pseudojet builders.
-  #--------------------------------------------------------------
-
-  # Clusters.
-  jtm += PseudoJetGetter(
-    "lcget",
-    InputContainer = "CaloCalTopoClusters",
-    Label = "LCTopo",
-    OutputContainer = "PseudoJetLCTopo",
-    SkipNegativeEnergy = True,
-    GhostScale = 0.0
-  )
-
-  # EM clusters.
-  jtm += PseudoJetGetter(
-    "emget",
-    InputContainer = "CaloCalTopoClusters",
-    Label = "EMTopo",
-    OutputContainer = "PseudoJetEMTopo",
-    SkipNegativeEnergy = True,
-    GhostScale = 0.0
-  )
-
-
-  # Muon segments
-  jtm += MuonSegmentPseudoJetGetter(
-    "gmusegget",
-    InputContainer = "MuonSegments",
-    Label = "GhostMuonSegment",
-    OutputContainer = "PseudoJetGhostMuonSegment",
-    Pt = 1.e-20
-  )
-
-  # AntiKt2 track jets.
-  jtm += PseudoJetGetter(
-    "gakt2trackget", # give a unique name
-    InputContainer = jetFlags.containerNamePrefix() + "AntiKt2PV0TrackJets", # SG key
-    Label = "GhostAntiKt2TrackJet",   # this is the name you'll use to retrieve associated ghosts
-    OutputContainer = "PseudoJetGhostAntiKt2TrackJet",
-    SkipNegativeEnergy = True,
-    GhostScale = ghostScaleFactor,   # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so.
-  )
-
-#  # AntiKt3 track jets.
-#  jtm += PseudoJetGetter(
-#    "gakt3trackget", # give a unique name
-#    InputContainer = jetFlags.containerNamePrefix() + "AntiKt3PV0TrackJets", # SG key
-#    Label = "GhostAntiKt3TrackJet",   # this is the name you'll use to retrieve associated ghosts
-#    OutputContainer = "PseudoJetGhostAntiKt3TrackJet",
-#    SkipNegativeEnergy = True,
-#    GhostScale = ghostScaleFactor,   # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so.
-#  )
-
-  # AntiKt4 track jets.
-  jtm += PseudoJetGetter(
-    "gakt4trackget", # give a unique name
-    InputContainer = jetFlags.containerNamePrefix() + "AntiKt4PV0TrackJets", # SG key
-    Label = "GhostAntiKt4TrackJet",   # this is the name you'll use to retrieve associated ghosts
-    OutputContainer = "PseudoJetGhostAntiKt4TrackJet",
-    SkipNegativeEnergy = True,
-    GhostScale = ghostScaleFactor,   # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so.
-  )
-
-  #--------------------------------------------------------------
-  # Jet builder.
-  # The tool manager must have one jet builder.
-  #--------------------------------------------------------------
-
-  jtm.addJetBuilderWithArea(JetFromPseudojet(
-    "jblda",
-    Attributes = ["ActiveArea", "ActiveArea4vec"]
-  ))
-
-  jtm.addJetBuilderWithoutArea(JetFromPseudojet(
-    "jbldna",
-    Attributes = []
-  ))
-
-  # Number of associated muon segments.
-  #jtm += JetMuonSegmentMomentsTool("muonsegs")
-
-  # Remove constituents (useful for truth jets in evgen pile-up file)
-  jtm += JetConstitRemover("removeconstit")
-
-  # Sort jets by pT
-  # May be deisred after calibration or grooming.
-  jtm += JetSorter("jetsorter")
diff --git a/Reconstruction/Jet/JetRec/python/JetRecStandard.py b/Reconstruction/Jet/JetRec/python/JetRecStandard.py
index a39a0e09747706da835e882ac0db11fe29cc8192..d5c93c1caa6633b3165d96edc23326fddc9ac0ac 100644
--- a/Reconstruction/Jet/JetRec/python/JetRecStandard.py
+++ b/Reconstruction/Jet/JetRec/python/JetRecStandard.py
@@ -116,6 +116,6 @@ if jetFlags.eventShapeTools() == None:
 # Import the jet tool manager.
 from JetRec.JetRecStandardToolManager import jtm
 # Import the constituent tool manager
-from JetRecTools.JetRecToolsConfig import ctm
+from JetRecTools.ConstitToolManager import ctm
 
 jetlog.info( myname + "End." )
diff --git a/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py b/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py
index e3c1b11dae8fd0485cd6dd416a49a94d469cb37f..d2b0bc2915d1be5dd4a40fb65408e3f306f8cd1e 100644
--- a/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py
+++ b/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py
@@ -240,7 +240,7 @@ jtm += JetConstituentsRetriever(
 #--------------------------------------------------------------
 
 # Prepare a sequence of input constituent modifiers
-from JetRecTools.JetRecToolsConfig import ctm
+from JetRecTools.ConstitToolManager import ctm
 jtm += ctm.buildConstitModifSequence( "JetConstitSeq_LCOrigin",
     OutputContainer='LCOriginTopoClusters',
     InputContainer= 'CaloCalTopoClusters',
diff --git a/Reconstruction/Jet/JetRecConfig/CMakeLists.txt b/Reconstruction/Jet/JetRecConfig/CMakeLists.txt
index 18ea0632da48d38e9122f7c94643599a28416584..b76e3c087ec8e2b5849f4f8afd5ba4fef410d018 100644
--- a/Reconstruction/Jet/JetRecConfig/CMakeLists.txt
+++ b/Reconstruction/Jet/JetRecConfig/CMakeLists.txt
@@ -1,3 +1,4 @@
+# $Id: CMakeLists.txt 801725 2017-03-28 19:23:28Z khoo $
 ################################################################################
 # Package: JetRecConfig
 ################################################################################
@@ -5,12 +6,6 @@
 # Declare the package name:
 atlas_subdir( JetRecConfig )
 
-# Declare the package's dependencies:
-atlas_depends_on_subdirs( PUBLIC
-                          GaudiKernel )
-
 # Install files from the package:
 atlas_install_python_modules( python/*.py )
 atlas_install_joboptions( share/*.py )
-atlas_install_joboptions( share/JetRec_jobOptions.py )
-
diff --git a/Reconstruction/Jet/JetRecConfig/README.md b/Reconstruction/Jet/JetRecConfig/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d2a01ffe30ce4625c159e4efbbee2d2507afd255
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/README.md
@@ -0,0 +1,143 @@
+# JetRecConfig: Smart jet reconstruction configuration
+
+## Introduction
+
+This package is an attempt to build up jet configuration hierarchically through
+modular configuration helpers that stay local to the source packages.
+
+## Usage
+
+Before reading further, it may be useful to also refer to the Run 3 configuration
+documentation:
+https://twiki.cern.ch/twiki/bin/viewauth/AtlasComputing/AthenaJobConfigRun3
+
+The backbone of this configuration framework is a set of classes that encode
+what is meaningful in a jet definition or jet constituent, such that helper
+code can interpret the definitions to generate all necessary tools/algs.
+These are defined in `JetDefinition.py`, and currently comprise:
+* `JetConstit`: A set of constituents used for jet finding, which may have
+  constituent modifiers applied.
+* `JetDefinition`: A jet configuration, fundamentally the clustering algorithm,
+  radius, and input constituent type. Can be extended with lists of jet
+  modifiers. Jet grooming is still to be added (might be a derived class?)
+* `JetGhost`: A set of objects to be ghost-associated to the jets. Very
+  simplistic class at present.
+* `JetModifier`: A configuration of a tool that adds jet moments or otherwise
+  manipulates the jet collection.
+
+Once the constituent and definition have been defined, these are passed to
+the `JetRecConfig.JetRecCfg` function, which builds up all needed
+tools and algorithms sequentially, including any of their prerequisites,
+such that one is guaranteed a working reconstruction sequence. These are
+placed in a ComponentAccumulator, that can be merged with the main
+Athena job and potentially with other jet reconstruction sequences.
+
+As an intermediate step, the dictionary of dependencies for the jet reco job
+can be extracted without attempting to configure any Athena tools/algs. This
+is done by passing the jet definition to `JetRecConfig.resolveDependencies`,
+allowing quick checking of the elements that will be integrated to form the
+jet collection, including input collections, ghosts and modifiers.
+
+If working with standard objects, the user can to do something like
+```
+from StandardJetDefs import AntiKt4LCTopo
+lcjetcfg = JetRecConfig.JetRecCfg(jetseq,AntiKt4LCTopo)
+```
+For minor variations, one can copy and modify the standard definitions:
+```
+from StandardJetDefs import LCTopoOrigin, AntiKt4LCTopo
+from copy import deepcopy
+LCTopoCSSK = deepcopy(LCTopoOrigin)
+LCTopoCSSK.modifiers += ["CS","SK"]
+AntiKt4LCTopoCSSK = deepcopy(AntiKt4LCTopo)
+AntiKt4LCTopoCSSK.inputdef = LCTopoCSSK
+lccsskjetcfg = JetRecConfig.JetRecCfg(jetseq,AntiKt4LCTopoCSSK)
+```
+The definitions can of course be built up from scratch by users who want full
+control.
+
+At this time, the only use of configuration flags is to peek in the input
+file (the first one) to determine if certain prerequisite collections are
+present and therefore need not be built.
+See:
+https://indico.cern.ch/event/697121/contributions/2859415/attachments/1585431/2506572/JobConfig_SoftCoord_Jan18.pdf
+
+### Note on JetModifier configuration
+
+To provide a large variety of modifier tool configurations in an organised way,
+each modifier tool is configured via the `JetModifier` helper class. This in
+turn delegates setup of the configuration to a helper function that specifies
+non-default tool properties, and may take into account the details of the jets.
+Every modifier keeps track of its prerequisites, which may be other modifiers,
+jet input objects (e.g. tracks) or ghosts (e.g. GhostTracks).
+
+The simplest possible `JetModifier` is one that only needs to produce a default
+tool, e.g.
+```
+jetsort = JetModifier("JetSorter","jetsort")
+```
+Another modifier may not need any special configuration, but does require that
+some other mods be run first:
+```
+jvt = JetModifier("JetVertexTaggerTool", "jvt",
+                  prereqs = [ "mod:JVF" ])
+```
+Finally, a helper function might be defined to set up the tool correctly,
+possibly with input from a string encoding of the modifier setup:
+```
+def getJetFilterTool(modspec):
+    from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+    ca = ComponentAccumulator()
+    threshold = int(modspec)
+    jetptfilter = JetRecConf.JetFilterTool("jetptfilter_{0}mev".format(threshold))
+    jetptfilter.PtMin = threshold
+    ca.addPublicTool( jetptfilter )
+    return jetptfilter, ca
+
+"Filter": JetModifier("JetFilterTool","jetptfilter",helperfn=getJetFilterTool),
+```
+A helper function can potentially be provided for the prereqs as well.
+
+This permits us to build up a dictionary of modifier configurations, keyed by
+strings, so a user can simply set a list of strings describing how they want
+to apply the modifiers, e.g.
+```
+AntiKt4LCTopo.modifiers = ["Calib:AnalysisLatest:mc","Sort","JVT"]
+```
+which will first ensure that all tools are called that are needed for
+calibration, then sort the collection (a filter is also applied, controlled
+by other options), and finally compute JVT, again adding all modifiers required
+by JVT. In the process, jet track selection and ghost association will be
+added to the job.
+
+The set of standard modifiers (for offline reconstruction) is concentrated
+in JetRecConfig/python/StandardJetMods.py, which in turn accesses tool
+configuration helpers that are defined in the packages containing the tool
+C++ implementations. This allows a local lookup of the specific default
+configurations, while making it easy to determine where the source code
+for those tools live.
+
+### Instructions
+
+To run:
+```
+cd $MYWORKDIR
+mkdir run
+cd run
+python JetRecTestCfg.py -H # Get instructions
+```
+You can dump printouts of the dependency dict and/or component accumulators
+for each jet collection or run a full job in serial or multithreaded modes.
+
+# TODO
+
+* Set up configuration helpers for:
+  * Jet substructure moment tools
+* Develop a generic configuration helper for grooming jets
+  * This should support both finding+grooming and standalone grooming based
+    on the input collection being pre-made.
+  * Some autoconfiguration could be useful here? However, missing data
+    dependencies should be covered by the AthenaMT scheduler.
+* Some steering flags will eventually be needed to cope with different
+  situations. However, hopefully they can mostly just modify the top-level
+  configurations, without needing anything propagated into the helpers.
diff --git a/Reconstruction/Jet/JetRecConfig/python/ConstModHelpers.py b/Reconstruction/Jet/JetRecConfig/python/ConstModHelpers.py
new file mode 100644
index 0000000000000000000000000000000000000000..7bd9971894f554e65586f037b62d5671eed95ab9
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/python/ConstModHelpers.py
@@ -0,0 +1,102 @@
+# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+
+########################################################################
+#                                                                      #
+# ConstModUtils: A module for configuring constituent modifiers        #
+# Author: TJ Khoo                                                      #
+#                                                                      #
+########################################################################
+
+from ROOT import xAOD
+xAOD.Type.ObjectType
+
+from AthenaCommon import Logging
+constmodlog = Logging.logging.getLogger('ConstModHelpers')
+
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+
+from JetRec import JetRecConf
+from JetRecTools import JetRecToolsConf
+from PFlowUtils import PFlowUtilsConf
+
+# Tool types and configs can be expanded if the user
+# wishes to add their own custom definitions
+
+# Maybe we need a config class in JetDefinition?
+ConstModTools = {
+    "Origin": JetRecToolsConf.CaloClusterConstituentsOrigin,
+    "EM":     JetRecToolsConf.ClusterAtEMScaleTool,
+    "Vor":    JetRecToolsConf.VoronoiWeightTool,
+    "CS":     JetRecToolsConf.ConstituentSubtractorTool,
+    "SK":     JetRecToolsConf.SoftKillerWeightTool
+}
+
+ConstModConfigs = {
+    "Origin": {},
+    "EM":     {},
+    "Vor":    {"doSpread":False, "nSigma":0},
+    "CS":     {"MaxEta":5.},
+    "SK":     {}
+}
+
+def ConstitModCfg(inputtype,sequence,suffix=""):
+    components = ComponentAccumulator()
+
+    # May wish to pass an empty sequence for regular PFlow
+    modlist = []
+    if inputtype == xAOD.Type.ParticleFlow:
+        weightPFO = PFlowUtilsConf.CP__WeightPFOTool("weightPFO")
+        correctPFO = JetRecToolsConf.CorrectPFOTool("correctPFO",
+            InputType = inputtype,
+            WeightPFOTool = weightPFO
+        )
+        modlist.append(correctPFO)
+    inputname = {xAOD.Type.CaloCluster:  "TopoCluster",
+                 xAOD.Type.ParticleFlow: "EMPFlow"
+                 }[inputtype]
+
+    for step in sequence:
+        if step == "LC":
+            continue # Nothing to do for LC clusters
+        tool = None
+
+        toolname = "ConstitMod{0}_{1}{2}".format(inputname,step,suffix)
+        tool = ConstModTools[step](toolname,**ConstModConfigs[step])
+        if inputtype == xAOD.Type.ParticleFlow:
+            tool.IgnoreChargedPFO=True
+            tool.ApplyToChargedPFO=False
+        tool.InputType = inputtype
+        modlist.append(tool)
+
+    sequenceshort = "".join(sequence)
+    seqname = "ConstitMod{0}_{1}{2}".format(sequenceshort,inputname,suffix)
+    inputcontainer = ""
+    outputcontainer = ""
+    if inputtype==xAOD.Type.ParticleFlow:
+        inputcontainer = "JetETMiss"
+        outputcontainer = sequenceshort if sequenceshort else "CHS"
+        chstool = JetRecToolsConf.ChargedHadronSubtractionTool("chsPFO")
+        chstool.InputType = inputtype
+        modlist.append(chstool)
+    elif inputtype==xAOD.Type.CaloCluster:
+        inputcontainer = "CaloCalTopoClusters"
+        outputcontainer = sequenceshort+"TopoClusters"
+    else:
+        constmodlog.error("Only ParticleFlow and CaloCluster currently supported!")
+        raise TypeError("Unsupported input type {0}".format(inputtype))
+
+    # If no mods are needed, don't give back a tool
+    if not modlist: return components
+
+    modseq = JetRecToolsConf.JetConstituentModSequence(seqname,
+        InputType=inputtype,
+        OutputContainer = outputcontainer,
+        InputContainer= inputcontainer,
+        Modifiers = [ mod for mod in modlist]
+    )
+
+    constitmodalg = JetRecConf.JetAlgorithm("jetalg_{0}".format(modseq.getName()))
+    constitmodalg.Tools = [modseq]
+    components.addEventAlgo( constitmodalg )
+
+    return components
diff --git a/Reconstruction/Jet/JetRecConfig/python/FastJetInterfaceConfig.py b/Reconstruction/Jet/JetRecConfig/python/FastJetInterfaceConfig.py
deleted file mode 100644
index d9641147035eca31a06e7ddc30c70eb43925bc47..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/FastJetInterfaceConfig.py
+++ /dev/null
@@ -1,174 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-
-from AthenaCommon.SystemOfUnits import *
-from AthenaCommon.Logging import logging
-
-from JetRec.JetRecConf import FastJetInterfaceTool
-
-_fastjetLog = logging.getLogger("FastJetInterfaceConfiguration")
-
-# set up some enumerator values
-def enums(name='Enum',**enums):
-    return type( name, (), enums)
-
-# recognized keys
-fastjet_conf_tags = enums('FastJetConfTags',
-                          Strategy=[ 'default', 'Best', 
-                                     'N2MinHeapTiled','N2Tiled', 'N2PoorTiled', 'N2Plain',
-                                     'N3Dumb', 
-                                     'NlnN', 'NlnN3pi', 'NlnN4pi', 'NlnNCam4pi', 'NlnNCam2pi2R', 'NlNCam',
-                                     'plugin_strategy' ],
-                          RecombScheme = [ 'default', 'E', 'pt', 'pt2', 'Et', 'Et2', 'BIpt', 'BIpt2' ],
-                          Algorithm   = [ 'default', 'kt', 'Kt', 'anti-kt', 'AntiKt', 'cambridge', 'CamKt',
-                                          'genkt', 'passive cambridge', 'passive genkt',
-                                          'CMSCone', 'SISCone'],
-                          JetAreaMethod = [ 'default', 'VoronoiArea', 'ActiveArea', 
-                                            'ActiveAreaExplicitGhost', 'PassiveArea', '1GhostPassiveArea' ],
-                          SISSplitMergeScale = [ 'default', 'pttilde', 'PtTilde', 'Pt', 'Et', 'mt' ], 
-                          )
-
-# Ghosted area parameters
-fastjet_gas = enums('FastJetGhostAreaSettings',
-                    def_ghost_maxrap  = 6.0,   #fastjet::gas::def_ghost_maxrap
-                    def_repeat        = 1,     #fastjet::gas::def_repeat
-                    def_ghost_area    = 0.01,  #fastjet::gas::def_ghost_area
-                    def_grid_scatter  = 1.0,   #fastjet::gas::def_grid_scatter
-                    def_kt_scatter    = 0.1,   #fastjet::gas::def_kt_scatter
-                    def_mean_ghost_kt = 1e-100,#fastjet::gas::def_mean_ghost_kt
-    )
-
-# ignored keys
-config_ignored_keys = enums('SetupIgnoredKeys',
-                            ControlKeys = ["_alreadyChecked_","_locked_","_ignoreUnknown_" ])
-
-# Default FastJet configuration dictionary: 
-#
-# Most keys are the same as the corresponding FastJet tags or enumerator names.
-# In addition, for backward compatibility, the following tags are recognized:
-#
-#  
-defFastJetInterfaceConfigDict = {
-    # -- overall setup and process control
-    'Algorithm'               : "anti-kt",
-    'JetAreaMethod'           : "VoronoiArea",
-    'CalculateJetArea'        : False,
-    # -- kt-style parameters
-    'Strategy'                : "Best",
-    'RecombScheme'            : "E",
-    # -- CMS cone parameters
-    'CMS_SeedThreshold'       : 15.*GeV,
-    # -- SIS cone parameters
-    'SIS_OverlapThreshold'    : 0.75,
-    'SIS_NumPassMax'          : 0,
-    'SIS_ProtojetPtMin'       : 0.0,
-    'SIS_DoCaching'           : False,
-    'SIS_SplitMergeScale'     : 'PtTilde',
-    'SIS_SplitMergeStopScale' : 0.0,
-    # -- jet algorithm parameters
-    'Radius'                  : 0.4,       # ATLAS default
-    'Inclusive'               : True,      # ATLAS default
-    'InclusivePtMin'          : 0.*GeV,
-    'ExclusiveDcut'           : 0.5,       
-    'ExclusiveNjets'          : 3,
-    # -- jet area calculation directives and parameters
-    'VoronoiEffectiveRfact'   : 1.0,   # Voronoi
-    'GhostMaxRapidity'        : fastjet_gas.def_ghost_maxrap,   
-    'GhostMinRapidity'        : -fastjet_gas.def_ghost_maxrap,   
-    'GhostRepeats'            : fastjet_gas.def_repeat,
-    'GhostAreaSize'           : fastjet_gas.def_ghost_area,
-    'GhostGridScatter'        : fastjet_gas.def_grid_scatter,
-    'GhostKtScatter'          : fastjet_gas.def_kt_scatter,
-    'GhostMeanKt'             : fastjet_gas.def_mean_ghost_kt
-    }
-
-# Check whole dictionary or key/value assigments and return dictionary with
-# invalid options stripped (if allowed) or exception thrown for invalid options
-def checkAndUpdate(**options):
-    # already checked
-    if options.get("_alreadyChecked_",False) or options.get("_locked_",False):
-        return options
-
-    # check what to do with unknowns
-    ignoreUnknown = options.pop("_ignoreUnknown_",False)
-
-    # check every entry
-    for k in options.keys():
-        if k not in defFastJetInterfaceConfigDict :
-            if ignoreUnknown :
-                _fastjetLog.warning("Option %s unknown - ignoring it!"%(k))
-                options.pop(k)
-            else :
-                _fastjetLog.error("Option %s unknown - abort configuration!"%(k))
-                raise Exception
-
-    checkedOptions = dict(defFastJetInterfaceConfigDict)
-    for k,v in defFastJetInterfaceConfigDict.iteritems():
-        t = type(v)
-        if t in ( list, set, dict ) :
-            checkedOptions[k] = t(v)
-
-    checkedOptions['_alreadyChecked_'] = True
-    checkedOptions.update(options)
-
-    # check settings for Strategy
-    key = "Strategy"
-    #    print checkedOptions
-    tag = checkedOptions[key]
-    _fastjetLog.info("Test option %s",key)
-    if checkedOptions[key] not in fastjet_conf_tags.Strategy :
-        _fastjetLog.error("Strategy \042%s\042 not recognized - fatal! Allowed values are: ",checkedOptions['Strategy'])
-        for s in fastjet_conf_tags.Strategy :
-            _fastjetLog.error("\042%s\042",s)
-        raise Exception
-    
-    # check settings for RecombScheme
-    if checkedOptions['RecombScheme'] not in fastjet_conf_tags.RecombScheme :
-        _fastjetLog.error("RecombScheme \042%s\042 not recognized - fatal! Allowed values are: ",checkedOptions['RecombScheme'])
-        for s in fastjet_conf_tags.RecombScheme :
-            _fastjetLog.error("\042%s\042",s)
-        raise Exception
-    
-    # check settings for Algorithm
-    if checkedOptions['Algorithm'] not in fastjet_conf_tags.Algorithm :
-        _fastjetLog.error("Algorithm \042%s\042 not recognized - fatal! Allowed values are: ",checkedOptions['Algorithm'])
-        for s in fastjet_conf_tags.Algorithm :
-            _fastjetLog.error("\042%%s\042",s)
-        raise Exception
-
-    # check settings for JetAreaMethod
-    if checkedOptions['JetAreaMethod'] not in fastjet_conf_tags.JetAreaMethod :
-        _fastjetLog.error("JetAreaMethod \042%s\042 not recognized - fatal! Allowed values are: ",checkedOptions['JetAreaMethod'])
-        for s in fastjet_conf_tags.JetAreaMethod :
-            _fastjetLog.error("\042%s\042",s)
-        raise Exception
-
-    # check settings for SIS split merge scale
-    if checkedOptions['SIS_SplitMergeScale'] not in fastjet_conf_tags.SISSplitMergeScale :
-      _fastjetLog.error("SIS_SplitMergeScale \042%2\042 not recognized - fatal! Allowed values are: ",checkedOptions['SIS_SplitMergeScale'])
-      for s in fastjet_conf_tags.SISSplitMergeScale :
-        _fastjetLog.error("\042%s\042",s)
-      raise Exception
-
-    return checkedOptions
-            
-
-def getFastJetInterfaceConfig(name,**options):
-    # get tool configuration 
-    fjTool = FastJetInterfaceTool(name)
-    from AthenaCommon.AppMgr import ToolSvc
-    ToolSvc += fjTool
-    # check job options
-    options = checkAndUpdate(**options)    
-    # set tool properties
-    for k,v in options.iteritems():
-        if k not in config_ignored_keys.ControlKeys :
-            setattr(fjTool,k,v)
-    # return tool configuration object
-    return fjTool
-
-#def dumpFastJetInterfaceConfig(**options=**defFastJetInterfaceConfigDict):
-#    # write out all attributes
-#    for k,v in options.iteritems():
-#        _fastjetLog.message("Config::%s value %s",%(k),%(v))
-    
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetAlgorithm.py b/Reconstruction/Jet/JetRecConfig/python/JetAlgorithm.py
deleted file mode 100644
index 487a68a39f4d0a97464739dcb570b93182711ecf..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/JetAlgorithm.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-# JetAlgorithm.py
-#
-# David Adams
-# March 2014
-# October 2014: Update to provide a fn that allow specification of alg sequence.
-#
-# Configure the jet algorithm after the tool manager has been configured.
-
-from AthenaCommon import Logging
-jetlog = Logging.logging.getLogger('JetRec_jobOptions')
-
-# Record the jet algorithm here.
-# Retrieve this with "from JetRec.JetAlgorithm import jetalg" *after*
-# calling addJetRecoToAlgSequence().
-jetalg = None
-
-# Function to add jet reconstruction to an algorithm sequence
-#               job: algorithm sequence
-#          useTruth: Flag to schedule building of selected-truth containers
-#   eventShapeTools: Keys for the event shape tools to be run
-#   separateJetAlgs: Run JetRecTools in separate algs (experts only)
-#             debug: Debug level (0 for quiet). See below.
-def addJetRecoToAlgSequence(job =None, useTruth =None, eventShapeTools =None,
-                            separateJetAlgs= None, debug =None):
-
-  myname = "JetAlgorithm: "
-
-  # We need this to modify the global variable.
-  global jetalg
-
-  # Import message level flags.
-  from GaudiKernel.Constants import DEBUG
-
-  # Import the jet reconstruction control flags.
-  from JetRecFlags import jetFlags
-
-  # Import the standard jet tool manager.
-  from JetRecStandardToolManager import jtm
-
-  # Set sequence and flags as needed.
-  if job == None:
-    from AthenaCommon.AlgSequence import AlgSequence
-    job = AlgSequence()
-  if useTruth == None:
-    useTruth = jetFlags.useTruth()
-  if eventShapeTools == None:
-    eventShapeTools = jetFlags.eventShapeTools()
-    if eventShapeTools == None:
-      eventShapeTools = []
-  if separateJetAlgs == None:
-    separateJetAlgs = jetFlags.separateJetAlgs()
-
-
-  from RecExConfig.ObjKeyStore import cfgKeyStore
-  # Event shape tools.
-  evstools = []
-  evsDict = {
-    "emtopo"   : ("EMTopoEventShape",   jtm.emget),
-    "lctopo"   : ("LCTopoEventShape",   jtm.lcget),
-    "empflow"  : ("EMPFlowEventShape",  jtm.empflowget),
-    "emcpflow" : ("EMCPFlowEventShape", jtm.emcpflowget),
-    "lcpflow"  : ("LCPFlowEventShape",  jtm.lcpflowget),
-  }
-
-  if jetFlags.useTracks():
-    evsDict["emtopo"] = ("EMTopoEventShape",   jtm.emoriginget)
-    evsDict["lctopo"] = ("LCTopoEventShape",   jtm.lcoriginget)
-  jetlog.info( myname + "Event shape tools: " + str(eventShapeTools) )
-
-  for evskey in eventShapeTools:
-    from EventShapeTools.EventDensityConfig import configEventDensityTool
-    if evskey in evsDict:
-      (toolname, getter) = evsDict[evskey]
-      if toolname in jtm.tools:
-        jetlog.info( myname + "Skipping duplicate event shape: " + toolname )
-      else:
-        jetlog.info( myname + "Adding event shape " + evskey )
-        if not cfgKeyStore.isInInputFile("xAOD::EventShape",toolname):
-          jtm += configEventDensityTool(toolname, getter, 0.4)
-          evstools += [jtm.tools[toolname]]
-    else:
-      jetlog.info( myname + "Invalid event shape key: " + evskey )
-      raise Exception
-
-  # Add the tool runner. It runs the jetrec tools.
-  rtools = []
-  # Add the truth tools.
-  if useTruth:    
-    from JetRec.JetFlavorAlgs import scheduleCopyTruthParticles
-    rtools += scheduleCopyTruthParticles()
-    
-    # build truth jet input :
-    rtools += [ jtm.truthpartcopy, jtm.truthpartcopywz ]
-
-  ## if jetFlags.useCells():
-  ##   rtools += [jtm.missingcells] commented out : incompatible with trigger : ATR-9696
-  if jetFlags.useTracks:
-    rtools += [jtm.tracksel,
-               jtm.tvassoc,
-               jtm.trackselloose_trackjets,
-               ]
-   
-  # Add the algorithm. It runs the jetrec tools.
-  from JetRec.JetRecConf import JetAlgorithm
-  ctools = []
-  if jetFlags.useTracks:
-    if not cfgKeyStore.isInInputFile("xAOD::CaloClusterContainer","LCOriginTopoClusters"):
-      ctools += [jtm.JetConstitSeq_LCOrigin]
-    if not cfgKeyStore.isInInputFile("xAOD::CaloClusterContainer","EMOriginTopoClusters"):
-      ctools += [jtm.JetConstitSeq_EMOrigin]
-  from JetRec.JetRecConf import JetToolRunner
-  runners = []
-  if len(ctools)>0:
-    jtm += JetToolRunner("jetconstit",
-                         EventShapeTools=[],
-                         Tools=ctools,
-                         Timer=jetFlags.timeJetToolRunner()
-                         )
-    jtm.jetconstit
-    runners = [jtm.jetconstit]
-
-  if jetFlags.separateJetAlgs():
-
-    jtm += JetToolRunner("jetrun",
-                         EventShapeTools=evstools,
-                         Tools=rtools,
-                         Timer=jetFlags.timeJetToolRunner()
-                         )
-    runners += [jetrun]
-
-    job += JetAlgorithm("jetalg")
-    jetalg = job.jetalg
-    jetalg.Tools = runners
-
-    for t in jtm.jetrecs:
-      jalg = JetAlgorithm("jetalg"+t.name())
-      jalg.Tools = [t]
-      job+= jalg
-
-  else:
-    from JetRec.JetRecConf import JetToolRunner
-    jtm += JetToolRunner("jetrun",
-                         EventShapeTools=evstools,
-                         Tools=rtools+jtm.jetrecs,
-                         Timer=jetFlags.timeJetToolRunner()
-                         )
-    runners += [jtm.jetrun]
-
-    job += JetAlgorithm("jetalg")
-    jetalg = job.jetalg
-    jetalg.Tools = runners
-    if jetFlags.debug > 0:
-      jtm.setOutputLevel(jtm.jetrun, DEBUG)
-      jetalg.OutputLevel = DEBUG
-    if jetFlags.debug > 1:
-      for tool in jtm.jetrecs:
-        jtm.setOutputLevel(tool, DEBUG)
-    if jetFlags.debug > 2:
-      for tool in jtm.finders:
-        jtm.setOutputLevel(tool, DEBUG)
-    if jetFlags.debug > 3:
-      jtm.setOutputLevel(jtm.jetBuilderWithArea, DEBUG)
-      jtm.setOutputLevel(jtm.jetBuilderWithoutArea, DEBUG)
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py b/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d1496345f7a16b57de5ec2bfeb8387f1ba1c975
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/python/JetDefinition.py
@@ -0,0 +1,321 @@
+# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+
+########################################################################
+#                                                                      #
+# JetDefinition: A module for classes encoding definitions of jets and #
+# related objects for configuring jet reconstruction                   #
+# Author: TJ Khoo                                                      #
+#                                                                      #
+########################################################################
+
+__all__ =  ["JetConstit", "JetGhost", "JetDefinition","xAOD"]
+
+# Code from JetRecUtils
+# define the convention that we write R truncating the decimal point
+# if R>=1, then we write R*10
+from AthenaCommon import Logging
+jetlog = Logging.logging.getLogger('JetDefinition')
+
+from ROOT import xAOD
+xAOD.Type.ObjectType
+
+def formatRvalue(parameter):
+    # 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))
+        raise ValueError('Bad radius parameter')
+    if int(parameter)>=1:
+        return "{0:.0f}".format(10*parameter)
+    else:
+        return "{0:.1g}".format(10*parameter).replace('.','')
+
+# Could also split off a VR name builder
+def buildJetAlgName(finder, mainParam, variableRMassScale=None, variableRMinRadius=None):  # variableRMassScale (Rho) in MeV
+    if ( variableRMassScale and variableRMinRadius ):
+        rmaxstr = formatRvalue(mainParam)
+        rminstr = formatRvalue(variableRMinRadius)
+        return finder + "VR" + str(int(variableRMassScale/1000)) + "Rmax" + rmaxstr + "Rmin" + rminstr
+    return finder + formatRvalue(mainParam)
+
+# A class that defines the type of object used to build a jet
+class JetConstit(object):
+    def __init__(self, type, modifiers=[]):
+        self.__basetype = type
+        self.__modifiers = modifiers
+
+        self.defineLabelAndContainerName()
+        pass
+
+    def __hash__(self):
+        return hash((self.__basetype,str(self.__modifiers)))
+
+    def __eq__(self,rhs):
+        return self.__hash__() == rhs.__hash__()
+
+    def __ne__(self,rhs):
+        return (not __eq__(self,rhs))
+
+    # Define type and modifiers as properties, with
+    # custom setter/getter such that if changed, these
+    # force resetting of the label and container name
+    @property
+    def basetype(self):
+        return self.__basetype
+    @basetype.setter
+    def basetype(self,basetype):
+        self.__basetype = basetype
+        self.defineLabelAndContainerName()
+
+    @property
+    def modifiers(self):
+        return self.__modifiers
+    @modifiers.setter
+    def modifiers(self,modifiers):
+        self.__modifiers = modifiers
+        self.defineLabelAndContainerName()
+
+    def defineLabelAndContainerName(self):
+        labelnames = {
+            xAOD.Type.CaloCluster:      "Topo",
+            xAOD.Type.ParticleFlow:     "EMPFlow",
+            xAOD.Type.TrackParticle:    "Track",
+            xAOD.Type.TruthParticle:    "Truth",
+            xAOD.Type.TrackCaloCluster: "TrackCaloCluster",
+            xAOD.Type.Jet:              "Jets",
+            }
+
+        self.label = ""
+        self.inputname = ""
+
+        # Truth "modifiers" specify the selection tool config
+        # e.g. WZ, WZDressed, DarkHadrons, ...
+        # Track "modifiers" specifiy the vertex association
+        # Other "modifiers" determine the constit mods e.g.
+        # origin correction, PU suppression etc
+        # Topoclusters should also specify EM or LC
+        # Jets just specify the jet definition
+        modstring = ""
+        if self.__modifiers:
+            for mod in self.__modifiers:
+                # Handle special case of topocluster state
+                if mod in ["EM","LC"]:
+                    self.label += mod
+                    self.inputname += mod
+                else:
+                    modstring += mod
+
+        if self.__basetype==xAOD.Type.Jet:
+            self.label += labelnames[self.__basetype]
+        else:
+            self.label += labelnames[self.__basetype]
+            self.label += modstring
+            if self.__basetype==xAOD.Type.TruthParticle:
+                self.label = self.label.replace("NoWZ","WZ")
+
+        containernames = {
+            xAOD.Type.CaloCluster:      "TopoClusters",
+            xAOD.Type.ParticleFlow:     "ParticleFlowObjects",
+            xAOD.Type.TrackParticle:    "JetSelectedTracks",
+            xAOD.Type.TruthParticle:    "JetInputTruthParticles",
+            xAOD.Type.TrackCaloCluster: "TrackCaloClusters",
+            xAOD.Type.Jet:              "Jets",
+            }
+        defaultaffixes = {
+            xAOD.Type.CaloCluster:      "CaloCal",
+            xAOD.Type.ParticleFlow:     "CHS",
+            xAOD.Type.TrackParticle:    "",
+            xAOD.Type.TruthParticle:    "",
+            xAOD.Type.TrackCaloCluster: "CombinedAndNeutral",
+            xAOD.Type.Jet:              "",
+            }
+
+        if not modstring:
+            modstring = defaultaffixes[self.__basetype]
+        modsfirst = [xAOD.Type.TruthParticle, xAOD.Type.TrackCaloCluster]
+        if self.__basetype in modsfirst:
+            self.inputname += containernames[self.basetype]+modstring
+        else:
+            self.inputname += modstring+containernames[self.basetype]
+
+    pass
+
+    # Define a string conversion for printing
+    def __str__(self):
+        return "JetConstit({0}: {1})".format(self.label,self.inputname)
+    # Need to override __repr__ for printing in lists etc
+    __repr__ = __str__
+
+# Not too clear at this point what other info is needed
+# In principle one might want to state the truth types etc
+class JetGhost(object):
+    def __init__(self, inputtype):
+        self.inputtype = inputtype
+        self.label = "Ghost"+inputtype
+        pass
+
+    def __hash__(self):
+        return hash(self.inputtype)
+
+    def __eq__(self,rhs):
+        return self.__hash__() == rhs.__hash__()
+
+    def __ne__(self,rhs):
+        return (not __eq__(self,rhs))
+
+    # Define a string conversion for printing
+    def __str__(self):
+        return "JetGhost(Ghost{0})".format(self.inputtype)
+    # Need to override __repr__ for printing in lists etc
+    __repr__ = __str__
+
+
+class JetDefinition(object):
+    def __init__(self, algorithm, radius, inputdef,
+                 ptmin=5000., ptminfilter=5000.,
+                 ghostdefs=[], modifiers=[]):
+
+        # Should add some type checking here
+        # Could use JetContainerInfo conversion
+        self.__algorithm = algorithm
+        if not self.__algorithm in ["Kt","AntiKt","CamKt"]:
+            jetlog.error("FastJet algorithm specification was not one of Kt, AntiKt, CamKt!")
+            raise KeyError("Invalid fastjet algorithm choice: {0}".format(self.algorithm))
+
+        self.__radius = radius
+        self.__inputdef = inputdef
+        self.defineName()
+
+        self.ptmin = ptmin # The pt down to which FastJet is run
+        self.ptminfilter = ptminfilter # The pt above which xAOD::Jets are kept
+        if ptmin<1000. or ptminfilter<1000.:
+            jetlog.warning("Very low filter threshold set: ptmin {0:.0f} MeV, ptminfilter {1:.0f} MeV. Are you sure?")
+        self.ghostdefs = ghostdefs
+        self.modifiers = modifiers
+
+        # Should this be a derived class?
+        self.grooming = None
+
+        # These should probably go in a derived class
+        self.VRMinRadius = None
+        self.VRMassScale = None
+
+        pass
+
+    def __hash__(self):
+        return hash((self.__radius,self.__inputdef,self.ptmin,self.ptminfilter,str(self.ghostdefs),str(self.modifiers)))
+
+    def __eq__(self,rhs):
+        return self.__hash__() == rhs.__hash__()
+
+    def __ne__(self,rhs):
+        return (not __eq__(self,rhs))
+
+    # Define core attributes as properties, with
+    # custom setter/getter such that if changed, these
+    # force resetting of the jet name
+    @property
+    def algorithm(self):
+        return self.__algorithm
+    @algorithm.setter
+    def algorithm(self,algorithm):
+        self.__algorithm = algorithm
+        self.defineName()
+
+    @property
+    def radius(self):
+        return self.__radius
+    @radius.setter
+    def radius(self,radius):
+        self.__radius = radius
+        self.defineName()
+
+    @property
+    def inputdef(self):
+        return self.__inputdef
+    @inputdef.setter
+    def inputdef(self,inputdef):
+        self.__inputdef = inputdef
+        self.defineName()
+
+    def defineName(self):
+        self.basename = buildJetAlgName(self.__algorithm,self.__radius)+self.__inputdef.label
+        if self.inputdef.basetype == xAOD.Type.CaloCluster:
+            # Omit cluster origin correction from jet name
+            # Keep the origin correction explicit because sometimes we may not
+            # wish to apply it, whereas PFlow corrections are applied implicitly
+            self.basename = self.basename.replace("Origin","")
+        pass
+
+    # Define a string conversion for printing
+    def __str__(self):
+        return "JetDefinition({0}, ptmin: {1} MeV)".format(self.basename,self.ptmin)
+    # Need to override __repr__ for printing in lists etc
+    __repr__ = __str__
+
+########################################################################
+# Helper to instantiate a generic jet modifier
+# Tools that typically have more complex properties set should have
+# their own dedicated helper functions defined
+from AthenaCommon import CfgMgr
+
+class JetModifier(object):
+    def __init__(self,tooltype,toolname,
+                 helperfn=None,
+                 prereqs=[],modspec=None,passJetDef=False):
+        # For the easy cases where no helper function is needed.
+        # They will be ignored in the case of a helper,
+        # but are still required such that it's obvious what
+        # the tool name and type are when defining the config.
+        self.tooltype = tooltype
+        self.toolname = toolname
+
+        # The helper function may take up to 2 parameters:
+        # a "modifier specification" string and the jet
+        # definition, which will be passed in based
+        # on the values of modspec and passJetDef.
+        #
+        # The helper function always returns the desired
+        # modifier, and a ComponentAccumulator instance, 
+        # in case additional supporting tools/services
+        # need to be set up.
+        if helperfn==None:
+            self.helperfn = self.getGenericModifier
+        else:
+            self.helperfn = helperfn
+        self.modspec = modspec
+        self.passJetDef = passJetDef
+
+        # Prereqs is normally a list.
+        # However, in special cases, the prereqs may
+        # depend on either or both of modspec and jetdef,
+        # in which case a helper function can be defined.
+        self.prereqs = prereqs
+
+    def __hash__(self):
+        return hash((self.toolname,self.tooltype,self.helperfn.__name__,self.modspec,self.passJetDef,str(self.prereqs)))
+
+    def __eq__(self,rhs):
+        return self.__hash__() == rhs.__hash__()
+
+    def __ne__(self,rhs):
+        return (not __eq__(self,rhs))
+
+    # Define a string conversion for printing
+    def __str__(self):
+        return "JetModifier({0}/{1})".format(self.tooltype,self.toolname)
+    # Need to override __repr__ for printing in lists etc
+    __repr__ = __str__
+
+    def getGenericModifier(self,**kwargs):
+        tool = getattr(CfgMgr,self.tooltype)(self.toolname)
+        return tool
+
+    def getPrereqs(self,modspec="",jetdef=None):
+        prereqs = []
+        if self.prereqs.__class__ == list:
+            prereqs += self.prereqs
+        else:
+            prereqs += self.prereqs(modspec,jetdef)
+        jetlog.verbose("Prereqs for {0}: [{1}]".format(self.toolname,", ".join(prereqs)))
+        return prereqs
+
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetFlavorAlgs.py b/Reconstruction/Jet/JetRecConfig/python/JetFlavorAlgs.py
deleted file mode 100644
index 30ff8c7fc77136641a32df649871f00aa0f420d0..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/JetFlavorAlgs.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-# JetFlavorAlgs.py
-#
-# David Adams
-# September 2014
-
-from AthenaCommon import Logging
-jetlog = Logging.logging.getLogger('JetRec_jobOptions')
-
-# Import the jet reconstruction control flags.
-from JetRecFlags import jetFlags
-
-jetlog.info( str(jetFlags.truthFlavorTags()) )
-
-def scheduleCopyTruthParticles():
-  myname = "scheduleCopyTruthParticles: "
-  from JetRecStandardToolManager import jtm
-  if not jtm.haveParticleJetTools: return
-  from ParticleJetTools.ParticleJetToolsConf import CopyFlavorLabelTruthParticles
-  from ParticleJetTools.ParticleJetToolsConf import CopyBosonTopLabelTruthParticles
-  from ParticleJetTools.ParticleJetToolsConf import CopyTruthPartons
-  from ParticleJetTools.CopyTruthParticlesAlg import CopyTruthParticlesAlg
-
-  tools = []
-  for ptype in jetFlags.truthFlavorTags():
-    toolname = "CopyTruthTag" + ptype
-    if toolname in jtm.tools:
-      jetlog.info( myname + "Skipping previously-defined tool: " + toolname )
-      jetlog.info( jtm.tools[toolname] )
-    else:
-      jetlog.info( myname + "Scheduling " + toolname )
-      ptmin = 5000
-      if ptype == "Partons":
-        ctp = CopyTruthPartons(toolname)
-      elif ptype in ["WBosons", "ZBosons", "HBosons", "TQuarksFinal"]:
-        ctp = CopyBosonTopLabelTruthParticles(toolname)
-        ctp.ParticleType = ptype
-        ptmin = 100000
-      else:
-        ctp = CopyFlavorLabelTruthParticles(toolname)
-        ctp.ParticleType = ptype
-      ctp.OutputName = "TruthLabel" + ptype
-      ctp.PtMin = ptmin
-      jtm += ctp
-      #theJob += CopyTruthParticlesAlg(ctp, toolname + "Alg")
-      jetlog.info( ctp )
-      tools.append( ctp )
-  return tools
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py b/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..858dfb85994bc95cce1a0b5e939d4be6e51242a9
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/python/JetModConfig.py
@@ -0,0 +1,96 @@
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+
+########################################################################
+#                                                                      #
+# JetModConfig: A helper module for configuring jet modifier tools     #
+# Author: TJ Khoo                                                      #
+#                                                                      #
+########################################################################
+
+from AthenaCommon import Logging
+modlog = Logging.logging.getLogger('JetModConfig')
+
+########################################################################
+# Function for generating a list of JetModifier tools
+# Keep a default empty modstrings as we might want to actually
+# specify some defaults (e.g. calib/filter/sort) for specific configs
+#
+# First incarnation is "dumb" but we want this to be "smart" and set up
+# the right tools in order, propagating dependencies.
+#
+def getFinalModifierListAndPrereqs(mods_initial, jetdef):
+    if len(mods_initial)==0: return [], set()
+    mods_final = []
+    # By the end of the recursion, all mods should have been applied already.
+    prereqs = set()
+
+    modlog.verbose("Initial mod list: " + str(mods_initial))
+
+    # Loop over the initial list
+    # Extract the concrete definition and specifier string
+    # Then grab any prereqs, and expand if the list contains mods
+    for mod in mods_initial:
+        moddef, modspec = getModDefAndSpec( mod )
+        modreqs = moddef.getPrereqs(modspec,jetdef)
+        prereqmods = []
+        for req in modreqs:
+            reqtype, reqspec = req.split(':',1)
+            if reqtype == "mod":
+                prereqmods.append(reqspec)
+            else:
+                prereqs.add( req )
+        # Recursion happens here
+        prereqmods_final, moreprereqs = getFinalModifierListAndPrereqs( prereqmods, jetdef )
+        prereqs.update( moreprereqs )
+        mods_final += prereqmods_final + [(moddef,modspec)]
+
+    modlog.verbose("Current input prereqs: {0}".format(prereqs))
+    modlog.verbose("Final modlist: {0}".format(mods_final))
+    return mods_final, prereqs
+
+# [Optional] Args are:
+#    1. Tool Type (may be ignored if the helper is a custom one)
+#    2. Tool Name (may be ignored if the helper is a custom one)
+#   [3.] Config helper
+#   [4.] Prereqs (default to []). If "None", will try to get from the function.
+#   [5.] Flag passJetDef specifying if the helper needs the jet definition
+# We use a helper class to encapsulate the modifier configuration
+
+# Translate modifier string into JetModifier if necessary
+# Extracts the modspec from the string or the config object
+def getModDefAndSpec(mod):
+    from StandardJetMods import jetmoddict
+    moddef = mod
+    modspec = ""
+    if mod.__class__ == type("str"):
+        modkey = mod
+        if ":" in mod:
+            modkey, modspec = mod.split(':',1)
+        moddef = jetmoddict[modkey]
+    else:
+        modspec = moddef.modspec
+    modlog.verbose("Interpreted modifier string {0} as {1} with specification \"{2}\"".format(mod,moddef,modspec))
+    return moddef, modspec
+
+# Translate JetModifier into a concrete tool
+def getModifier(jetdef, moddef, modspec):
+    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.helperfn(**kwargs)
+    except Exception as e:
+        modlog.error( "Unhandled modifier specification {0} for {1}!".format(moddef,jetdef.basename) )
+        modlog.error( "Received exception \"{0}\"".format(e) )
+        modlog.error( "Helper function is \"{0}\"".format(moddef.helperfn) )
+        raise ValueError( "JetModConfig unable to handle mod {0}".format(moddef) )
+
+    return modtool
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecCalibrationFinder.py b/Reconstruction/Jet/JetRecConfig/python/JetRecCalibrationFinder.py
deleted file mode 100644
index a24bc37aad1fd3ea6c4028b3acfb7009cc227c42..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/JetRecCalibrationFinder.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-# JetRecCalibrationFinder.py
-
-# David Adams
-# September 2014
-#
-# Class to retrieve the calibration tool for a given jet definition
-# and calibration sequence.  The calibration tool is created if it
-# does not already exist.
-#
-# Usage:
-#   from JetRec.JetRecCalibrationFinder import jrcf
-#   tool = jrcf.find(alg, rad, inp, seq, con)
-#
-# Arguments:
-#   alg - Algorithm name: AntiKt, CamKt or Kt
-#   rad - Jet size parameter, e.g. 0.4
-#   inp - Input type: EMTopo or LCTopo
-#   seq - Calibration sequence as one letter for each step, e.g. "ar"
-#            a = Active area correction (rho*A)
-#            r = Pileup residual correction (i.e. using mu and NPV)
-#            j = JES correction (from MC)
-#            g = GSC correction (from MC)
-#            i = Insitu correction (data only)
-#   con - Configuration file name or entry in jrcf.configDict
-#
-# To add to the confid dictionary:
-#   jrcf.configDict["myname"] = "someConfigFile.config"
-
-from AthenaCommon import Logging
-jetlog = Logging.logging.getLogger('JetRec_jobOptions')
-
-class JetRecCalibrationFinder:
-    
-  # Dictionary of calibrations steps.
-  calibStep = {
-    "a":"JetArea",
-    "r":"Residual",
-    "o":"Origin",
-    "j":"AbsoluteEtaJES",
-    "g":"GSC",
-    "i":"Insitu",
-    "m":"JMS",
-  }
-    
-  # Dictionary for calibration configurations.
-  configDict = {
-    "reco"            : "JES_MC15cRecommendation_May2016_rel21.config",
-    "trigger"         : "JES_Full2012dataset_Preliminary_Trigger.config",
-    "triggerNoPileup" : "JES_Full2012dataset_Preliminary_Trigger_NoPileup.config",
-    "trigger2016"     : "JES_MC15cRecommendation_May2016_Trigger.config",
-    "triggerTrim"     : "JES_MC15recommendation_FatJet_June2015.config",
-    "pflow"           : "JES_MC15cRecommendation_PFlow_Aug2016.config"
-  }
-
-  def find(self, alg, rad, inpin, seq, configkeyin, evsprefix):
-    from JetCalibTools.JetCalibToolsConf import JetCalibrationTool
-    from JetRec.JetRecStandardToolManager import jtm
-    inp = inpin
-    # Find the configuration file.
-    configkey = configkeyin
-    if configkey == "": configkey = "reco"
-    if configkey in self.configDict:
-      configfile = self.configDict[configkey]
-    else:
-      configfile = configkey
-    # Assign name for tool
-    jetdefn = alg + str(int(10*rad+0.1)) + inp.split("Origin")[0]
-    tname = "calib_" + jetdefn + "_" + configkey.replace(".","_") + "_" + seq
-    # Display configuration.
-    myname = "JetRecCalibrationFinder:find: "
-    jetlog.info( myname + "Building jet calibration tool." )
-    jetlog.info( myname + "  Arguments:" )
-    jetlog.info( myname + "    alg: " + str(alg) )
-    jetlog.info( myname + "    rad: " + str(rad) )
-    jetlog.info( myname + "    inp: " + str(inp) )
-    jetlog.info( myname + "    seq: " + str(seq) )
-    jetlog.info( myname + "  Jet definition: " + jetdefn )
-    jetlog.info( myname + "  Configuration file: " + configfile )
-
-    if tname in jtm.tools:
-      jetlog.info( myname + "  Skipping previously-defined tool: " + tname )
-    else:
-      # build calib tool
-      jetlog.info( myname + "  Creating " + tname )
-      # ...define calbration sequence
-      try:
-        fullseq = [self.calibStep[l] for l in seq] # translate letters
-      except KeyError as err:
-        jetlog.info( myname + "  ERROR Invalid sequence: " + seq )
-        jetlog.info( myname + "  ERROR Unknown sequence key: " + err.message )
-        raise err
-      fullseq = '_'.join(fullseq)  # join seq names with a '_'
-      jetlog.info( myname + "  Calibration sequence: " + fullseq )
-      # ...define the key for the event shape container
-      if   inpin == "EMTopo":
-        evssuf="EMTopoEventShape"
-      elif inpin == "LCTopo":
-        evssuf="LCTopoEventShape"
-      elif inpin == "EMTopoOrigin":
-        evssuf="EMTopoOriginEventShape"
-      elif inpin == "LCTopoOrigin":
-        evssuf="LCTopoOriginEventShape"
-      elif inpin == "EMPFlow":
-        evssuf="EMPFlowEventShape"
-      elif inpin == "EMCPFlow":
-        evssuf="EMCPFlowEventShape"
-      elif inpin == "LCPFlow":
-        evssuf="LCPFlowEventShape"
-      elif inpin.startswith("LCTopoTrimmed"):
-        evssuf="LCTopoEventShape"
-      else:
-        evssuf="INVALID"
-        jetlog.info( myname + "  ERROR: Invalid input specifier: " + inp )
-        raise KeyError
-      evskey = evsprefix + evssuf
-      jetlog.info( myname + "  Event shape key: " + evskey )
-      # ...create the tool.
-      setDetEtaPhi = (configkey != "reco") # Temporary setting to avoid clash with modifiers that set detector eta
-      jtm += JetCalibrationTool(tname, JetCollection=jetdefn, ConfigFile=configfile, CalibSequence=fullseq, RhoKey=evskey,
-                                DoSetDetectorEta=setDetEtaPhi)
-
-    return jtm.tools[tname]
-
-# This is the only instance of the above class that should be used to
-# that should be used to fetch calibration tools.
-jrcf = JetRecCalibrationFinder()
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py b/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py
index ec6c44ccb85e7184aaa9f454c731f7e850d10291..7865879b150986f4b5610e0a24989182e7359e16 100644
--- a/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py
+++ b/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py
@@ -1,712 +1,460 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+
+########################################################################
+#                                                                      #
+# JetRecConfig: A helper module for configuring jet reconstruction     #
+# Author: TJ Khoo                                                      #
+#                                                                      #
+########################################################################
+
+from AthenaCommon import Logging
+jetlog = Logging.logging.getLogger('JetRecConfig')
+
+from ROOT import xAOD
+xAOD.Type.ObjectType
+
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+
+# CfgMgr is more convenient but it helps to be explicit about where
+# things are defined.
+# So, import package conf modules rather than a dozen individual classes
+from JetRec import JetRecConf
+
+__all__ = ["xAOD", "JetRecCfg", "resolveDependencies"]
+
+########################################################################
+# Top-level function for running jet finding
+# (i.e. clustering from inputs)
+# This returns a ComponentAccumulator that can be merged with others
+# from elsewhere in the job, but will provide everything needed to
+# reconstruct one jet collection.
+# This could still be modularised further into the subcomponents of the
+# jet reconstruction job. For now, based on public tools, as private
+# tool migration has not been completed.
+#
+# Receives the jet definition and input flags, mainly for input file
+# peeking such that we don't attempt to reproduce stuff that's already
+# in the input file
+def JetRecCfg(jetdef, configFlags, jetnameprefix="",jetnamesuffix=""):
+    components = ComponentAccumulator()
+
+    jetsfullname = jetnameprefix+jetdef.basename+jetnamesuffix+"Jets"
+    jetlog.info("Setting up to find {0}".format(jetsfullname))
 
-# JetRecStandardTools.py
+    deps = resolveDependencies( jetdef )
+    
+    # Schedule the various input collections.
+    # We don't have to worry about ordering, as the scheduler
+    # will handle the details. Just merge the components.
+    # 
+    # To facilitate running in serial mode, we also prepare
+    # the constituent PseudoJetGetter here (needed for rho)
+    inputcomps, constitpjkey = JetInputCfgAndConstitPJName(deps["inputs"], configFlags)
+    components.merge(inputcomps)
+    pjs = [constitpjkey]
+
+    # Schedule the ghost PseudoJetGetterAlgs
+    for ghostdef in deps["ghosts"]:
+        ghostpjcomps, ghostpjkey = GhostPJGCfgAndOutputName( ghostdef )
+        components.merge( ghostpjcomps )
+        pjs.append( ghostpjkey )
+
+    # Generate a JetAlgorithm to run the jet finding and modifiers
+    # (via a JetRecTool instance).
+    reccomps = JetAlgorithmCfg(jetsfullname, jetdef, pjs, deps["mods"])
+    components.merge(reccomps)
+
+    jetlog.info("Scheduled JetAlgorithm instance \"jetalg_{0}\"".format(jetsfullname))
+    return components
+
+########################################################################
+# The real workhorse -- establishes the full sequence of jet reco,
+# recursively expanding the prerequisites
 #
-# David Adams
-# March 2014
+# Avoids constructing any configurables at this stage, the goal being
+# to produce a human-readable job description.
+def resolveDependencies(jetdef):
+
+    jetlog.info("Resolving dependencies for {0} definition".format(jetdef.basename))
+
+    # Accumulate prerequisites of the base constituent type
+    # We just collect everything and sort out the types later
+    prereqs = set() # Resolve duplication as we go
+    prereqs.update( getConstitPrereqs( jetdef.inputdef ) )
+
+    # Add the Filter modifier if desired (usually it is)
+    # It might be simpler to just eliminate ptminfilter
+    # and always make this an explicit modifier
+    mods_initial = list(jetdef.modifiers)
+    if jetdef.ptminfilter>1e-9:
+        filtstr = "Filter:{0:.0f}".format(jetdef.ptminfilter)
+        # Insert pt filter after calibration if present
+        idx=-1
+        for imod, mod in enumerate(mods_initial):
+            if mod.startswith("Calib"):
+                idx = imod+1
+                break
+        mods_initial.insert(idx,filtstr)
+
+    # Accumulate prerequisites of the modifiers, as these are
+    # the most extensive. Internally resolves modifier chains,
+    # returning an updated modifiers list
+    # Need to use a list, as the order matters.
+    # The elements of the "final" list are tuples extracting
+    # the modifier specification.
+    import JetModConfig
+    mods_final, modprereqs = JetModConfig.getFinalModifierListAndPrereqs( mods_initial, jetdef )
+
+    # Remove the duplicates in the mod list -- just do this
+    # once at the end and preserve ordering.
+    def dedupe(mylist):
+        outlist = []
+        usedset = set()
+        for item in mylist:
+            if not (item in usedset):
+                outlist.append(item)
+                usedset.add(item)
+        return outlist
+    mods_final = dedupe( mods_final )
+
+    prereqs.update( modprereqs )
+
+    # Ghost prerequisites are only of type input, so we can
+    # afford to sort now.
+    prereqdict = {"ghost":set(), "input":set()}
+    prereqdict.update( classifyPrereqs(prereqs) )
+
+    # Copy the explicitly requested ghost defs and add to
+    # these those required by modifiers.
+    ghostdefs = set(jetdef.ghostdefs).union(prereqdict["ghost"])
+    # Expand from strings to JetGhost objects where needed.
+    ghostdefs = expandPrereqs( "ghost",ghostdefs )
+    
+    # Accumulate prerequisites of the ghost-associated types
+    jetlog.info("  Full list of ghosts: ")
+    for ghostdef in sorted(list(ghostdefs)):
+        jetlog.info("    " + str(ghostdef))
+        gprereqs = getGhostPrereqs(ghostdef)
+        prereqdict["input"].update( [req.split(':',1)[1] for req in gprereqs] )
+
+    jetlog.info("  Full list of mods: ")
+    for mod, modspec in mods_final:
+        jetlog.info("    " + str(mod) + ("" if not modspec else ": \"{0}\"".format(modspec)))
+
+    # Return a dict of the dependencies, converting sets to lists.
+    # May want to further separate input deps.
+    dependencies = {
+        "inputs":  [jetdef.inputdef] + sorted(list( prereqdict["input"] )),
+        "ghosts":  list( ghostdefs ),
+        "mods":    mods_final
+        }
+
+    # We don't expand the inputs at this stage, as they are diverse
+    # and don't have a dedicated config class.
+    # Doing so may trigger another level of expansion if the inputs
+    # include a jet collection.
+    return dependencies
+    
+########################################################################
+# Function for classifying prerequisites
 #
-# Define the low-level tools used in jet reconstruction.
+def classifyPrereqs(prereqs):
+    prereqdict = {}
+    for req in prereqs:
+        key,val = req.split(":",1)
+        jetlog.verbose( "Interpreted prereqs: {0} --> {1}".format(key,val) )
+        if not key in prereqdict.keys():
+            prereqdict[key] = set()
+        prereqdict[key].add(val)
+            
+    return prereqdict
+
+########################################################################
+# Function for expanding prerequisites into definitions
+# Only supporting ghosts for now, but could be extended
 #
-# Tools are configured and put in the global jet tool manager so
-# they can be accessed when configuring JetRec tools.
+def expandPrereqs(reqtype,prereqs):
+    reqdefs = set()
+    from JetDefinition import JetGhost
+    for req in prereqs:
+        if reqtype=="ghost":
+            if req.__class__ == JetGhost:
+                reqdefs.add( req )
+            else:
+                ghostdef = JetGhost(req)
+                reqdefs.add( ghostdef )
+                jetlog.debug("Expanded prereq {0} to {1}".format(req,ghostdef))
+        else:
+            jetlog.error("Prereqs \"{0}\" unsupported!".format(reqtype))
+            return None              
+    return reqdefs
+
+
+########################################################################
+# Function for setting up inputs to jet finding
 #
-# Execute this file to add the definitions to
-# JetRecStandardToolManager.jtm, e.g.
-#   import JetRecConfig.JetRecStandardTools
-
-# Import the jet flags.
-# from JetRecFlags import jetFlags
-
-# if not "UseTriggerStore " in locals():
-#   UseTriggerStore = False
-
-# # get levels defined VERBOSE=1 etc.
-# from GaudiKernel.Constants import *
-
-# from eflowRec.eflowRecFlags import jobproperties
-
-# from JetRecStandardToolManager import jtm
-# from InDetTrackSelectionTool.InDetTrackSelectionToolConf import InDet__InDetTrackSelectionTool
-# from MCTruthClassifier.MCTruthClassifierConf import MCTruthClassifier
-
-# from PFlowUtils.PFlowUtilsConf import CP__RetrievePFOTool as RetrievePFOTool
-# from JetRecTools.JetRecToolsConf import TrackPseudoJetGetter
-# from JetRecTools.JetRecToolsConf import JetTrackSelectionTool
-# from JetRecTools.JetRecToolsConf import SimpleJetTrackSelectionTool
-# from JetRecTools.JetRecToolsConf import TrackVertexAssociationTool
-# try:
-#   from JetRecCalo.JetRecCaloConf import MissingCellListTool
-#   jtm.haveJetRecCalo = True
-# except ImportError:
-#   jtm.haveJetRecCalo = False
-# from JetRecTools.JetRecToolsConf import PFlowPseudoJetGetter
-# from JetRec.JetRecConf import JetPseudojetRetriever
-# from JetRec.JetRecConf import JetConstituentsRetriever
-# from JetRec.JetRecConf import JetRecTool
-# from JetRec.JetRecConf import PseudoJetGetter
-# from JetRec.JetRecConf import MuonSegmentPseudoJetGetter
-# from JetRec.JetRecConf import JetFromPseudojet
-# from JetRec.JetRecConf import JetConstitRemover
-# from JetRec.JetRecConf import JetSorter
-# from JetMomentTools.JetMomentToolsConf import JetCaloQualityTool
-# try:
-#   from JetMomentTools.JetMomentToolsConf import JetCaloCellQualityTool
-#   jtm.haveJetCaloCellQualityTool = True
-# except ImportError:
-#   jtm.haveJetCaloCellQualityTool = False
-# from JetMomentTools.JetMomentToolsConf import JetWidthTool
-# from JetMomentTools.JetMomentToolsConf import JetCaloEnergies
-# try:
-#   from JetMomentTools.JetMomentToolsConf import JetJetBadChanCorrTool
-#   jtm.haveJetBadChanCorrTool = True
-# except ImportError:
-#   jtm.haveJetBadChanCorrTool = False
-# from JetMomentTools.JetMomentToolsConf import JetECPSFractionTool
-# from JetMomentTools.JetMomentToolsConf import JetVertexFractionTool
-# from JetMomentTools.JetMomentToolsConf import JetVertexTaggerTool
-# from JetMomentTools.JetMomentToolsConf import JetTrackMomentsTool
-# from JetMomentTools.JetMomentToolsConf import JetTrackSumMomentsTool
-# from JetMomentTools.JetMomentToolsConf import JetClusterMomentsTool
-# from JetMomentTools.JetMomentToolsConf import JetVoronoiMomentsTool
-# from JetMomentTools.JetMomentToolsConf import JetIsolationTool
-# from JetMomentTools.JetMomentToolsConf import JetLArHVTool
-# from JetMomentTools.JetMomentToolsConf import JetOriginCorrectionTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import KtDeltaRTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import NSubjettinessTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import KTSplittingScaleTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import AngularityTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import DipolarityTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import PlanarFlowTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import KtMassDropTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import EnergyCorrelatorTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import CenterOfMassShapesTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import JetPullTool
-# from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import JetChargeTool
-# try:
-#   from JetSubStructureMomentTools.JetSubStructureMomentToolsConf import ShowerDeconstructionTool
-#   jtm.haveShowerDeconstructionTool = True
-# except ImportError:
-#   jtm.haveShowerDeconstructionTool = False
-# try:
-#   from ParticleJetTools.ParticleJetToolsConf import Analysis__JetQuarkLabel
-#   jtm.haveParticleJetTools = True
-# except:
-#   jtm.haveParticleJetTools = False
-# if jtm.haveParticleJetTools:
-#   from ParticleJetTools.ParticleJetToolsConf import Analysis__JetConeLabeling
-#   from ParticleJetTools.ParticleJetToolsConf import Analysis__JetPartonTruthLabel
-#   from ParticleJetTools.ParticleJetToolsConf import CopyTruthJetParticles
-#   from ParticleJetTools.ParticleJetToolsConf import ParticleJetDeltaRLabelTool
-
-# #--------------------------------------------------------------
-# # Track selection.
-# #--------------------------------------------------------------
-
-# # This is the InDet loose selection from
-# # https://twiki.cern.ch/twiki/bin/view/AtlasProtected/InDetTrackingPerformanceGuidelines
-# # October 28, 2014
-# #jtm += InDet__InDetDetailedTrackSelectionTool(
-# jtm += InDet__InDetTrackSelectionTool(
-#   "trk_trackselloose",
-#   minPt                = 400.0,
-#   maxAbsEta            = 2.5,
-#   minNSiHits           = 7,
-#   maxNPixelSharedHits  = 1,
-#   maxOneSharedModule   = True,
-#   maxNSiHoles          = 2,
-#   maxNPixelHoles       = 1,
-# )
-
-# jtm += JetTrackSelectionTool(
-#   "trackselloose",
-#   InputContainer  = jtm.trackContainer,
-#   OutputContainer = "JetSelectedTracks",
-#   Selector        = jtm.trk_trackselloose
-# )
-
-# jtm += InDet__InDetTrackSelectionTool(
-#   "trk_trackselloose_trackjets",
-#   CutLevel                = "Loose"
-# )
-
-# jtm += JetTrackSelectionTool(
-#    "trackselloose_trackjets",
-#   InputContainer  = jtm.trackContainer,
-#   OutputContainer = "JetSelectedTracks_LooseTrackJets",
-#   Selector        = jtm.trk_trackselloose_trackjets
-# )
-
-# if jetFlags.useInDetTrackSelection():
-#   jtm += JetTrackSelectionTool(
-#     "tracksel",
-#     InputContainer  = jtm.trackContainer,
-#     OutputContainer = "JetSelectedTracks",
-#     Selector        = jtm.trk_trackselloose
-#   )
-# else:
-#   jtm += SimpleJetTrackSelectionTool(
-#     "tracksel",
-#     PtMin = 500.0,
-#     InputContainer  = jtm.trackContainer,
-#     OutputContainer = "JetSelectedTracks",
-#   )
-
-# #--------------------------------------------------------------
-# # Track-vertex association.
-# #--------------------------------------------------------------
-# from TrackVertexAssociationTool.TrackVertexAssociationToolConf import CP__TightTrackVertexAssociationTool
-# jtm += CP__TightTrackVertexAssociationTool("jetTighTVAtool", dzSinTheta_cut=3, doPV=True)
-
-# jtm += TrackVertexAssociationTool(
-#   "tvassoc",
-#   TrackParticleContainer  = jtm.trackContainer,
-#   TrackVertexAssociation  = "JetTrackVtxAssoc",
-#   VertexContainer         = jtm.vertexContainer,
-#   TrackVertexAssoTool     = jtm.jetTighTVAtool,
-# )
-
-# jtm += TrackVertexAssociationTool(
-#   "tvassoc_old",
-#   TrackParticleContainer  = jtm.trackContainer,
-#   TrackVertexAssociation  = "JetTrackVtxAssoc_old",
-#   VertexContainer         = jtm.vertexContainer,
-#   MaxTransverseDistance   = 1.5,
-#   MaxLongitudinalDistance = 1.0e7,
-#   MaxZ0SinTheta = 1.5
-# )
-
-# #--------------------------------------------------------------
-# # Truth selection.
-# #--------------------------------------------------------------
-
-# if jetFlags.useTruth:
-#     truthClassifier = MCTruthClassifier(name = "JetMCTruthClassifier",
-#                                        ParticleCaloExtensionTool="")
-#     jtm += truthClassifier
-
-#     jtm += CopyTruthJetParticles("truthpartcopy", OutputName="JetInputTruthParticles",
-#                                  MCTruthClassifier=truthClassifier)
-#     jtm += CopyTruthJetParticles("truthpartcopywz", OutputName="JetInputTruthParticlesNoWZ",
-#                                  MCTruthClassifier=truthClassifier,
-#                                  IncludeWZLeptons=False, #IncludeTauLeptons=False,
-#                                  IncludeMuons=True,IncludeNeutrinos=True)
-
-
-# #--------------------------------------------------------------
-# # Jet reco infrastructure.
-# #--------------------------------------------------------------
-
-# # Jet pseudojet retriever.
-# jtm += JetPseudojetRetriever("jpjretriever")
-
-# # Jet constituent retriever.
-# labs = []
-# if jetFlags.useTracks():
-#   labs += ["Track"]
-#   labs += ["AntiKt3TrackJet", "AntiKt3TrackJet"]
-# if jetFlags.useMuonSegments():
-#   labs += ["MuonSegment",]
-# if jetFlags.useTruth():
-#   labs += ["Truth"]
-#   for lab in jetFlags.truthFlavorTags():
-#     labs += [lab]
-# jtm += JetConstituentsRetriever(
-#   "jconretriever",
-#   UsePseudojet = True,
-#   UseJetConstituents = True,
-#   PseudojetRetriever = jtm.jpjretriever,
-#   GhostLabels = labs,
-#   GhostScale = 1.e-20
-# )
-
-# #--------------------------------------------------------------
-# # Pseudojet builders.
-# #--------------------------------------------------------------
-
-# # Clusters.
-# jtm += PseudoJetGetter(
-#   "lcget",
-#   InputContainer = "CaloCalTopoClusters",
-#   Label = "LCTopo",
-#   OutputContainer = "PseudoJetLCTopo",
-#   SkipNegativeEnergy = True,
-#   GhostScale = 0.0
-# )
-
-# # EM clusters.
-# jtm += PseudoJetGetter(
-#   "emget",
-#   InputContainer = "CaloCalTopoClusters",
-#   Label = "EMTopo",
-#   OutputContainer = "PseudoJetEMTopo",
-#   SkipNegativeEnergy = True,
-#   GhostScale = 0.0
-# )
-
-# # Tracks.
-# jtm += TrackPseudoJetGetter(
-#   "trackget",
-#   InputContainer = jtm.trackselloose_trackjets.OutputContainer,
-#   Label = "Track",
-#   OutputContainer = "PseudoJetTracks",
-#   TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-#   SkipNegativeEnergy = True,
-#   GhostScale = 0.0
-# )
-
-# # Ghost tracks.
-# jtm += TrackPseudoJetGetter(
-#   "gtrackget",
-#   InputContainer = jtm.tracksel.OutputContainer,
-#   Label = "GhostTrack",
-#   OutputContainer = "PseudoJetGhostTracks",
-#   TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-#   SkipNegativeEnergy = True,
-#   GhostScale = 1e-20
-# )
-
-# # Muon segments
-# jtm += MuonSegmentPseudoJetGetter(
-#   "gmusegget",
-#   InputContainer = "MuonSegments",
-#   Label = "GhostMuonSegment",
-#   OutputContainer = "PseudoJetGhostMuonSegment",
-#   Pt = 1.e-20
-# )
-
-# # Retriever for pflow objects.
-# jtm += RetrievePFOTool("pflowretriever")
-
-# useVertices = True
-# if False == jetFlags.useVertices:
-#   useVertices = False
-
-# if True == jobproperties.eflowRecFlags.useUpdated2015ChargedShowerSubtraction:
-#   useChargedWeights = True
-# else:
-#   useChargedWeights = False
-
-# useTrackVertexTool = False
-# if True == jetFlags.useTrackVertexTool:
-#   useTrackVertexTool = True
-
-# # EM-scale pflow.
-# jtm += PFlowPseudoJetGetter(
-#   "empflowget",
-#   Label = "EMPFlow",
-#   OutputContainer = "PseudoJetEMPFlow",
-#   RetrievePFOTool = jtm.pflowretriever,
-#   InputIsEM = True,
-#   CalibratePFO = False,
-#   SkipNegativeEnergy = True,
-#   UseChargedWeights = useChargedWeights,
-#   UseVertices = useVertices,
-#   UseTrackToVertexTool = useTrackVertexTool
-# )
-
-# # Calibrated EM-scale pflow.
-# jtm += PFlowPseudoJetGetter(
-#   "emcpflowget",
-#   Label = "EMCPFlow",
-#   OutputContainer = "PseudoJetEMCPFlow",
-#   RetrievePFOTool = jtm.pflowretriever,
-#   InputIsEM = True,
-#   CalibratePFO = True,
-#   SkipNegativeEnergy = True,
-#   UseChargedWeights = useChargedWeights,
-#   UseVertices = useVertices,
-#   UseTrackToVertexTool = useTrackVertexTool
-# )
-
-# # LC-scale pflow.
-# jtm += PFlowPseudoJetGetter(
-#   "lcpflowget",
-#   Label = "LCPFlow",
-#   OutputContainer = "PseudoJetLCPFlow",
-#   RetrievePFOTool = jtm.pflowretriever,
-#   InputIsEM = False,
-#   CalibratePFO = False,
-#   SkipNegativeEnergy = True,
-#   UseChargedWeights = useChargedWeights,
-#   UseVertices = useVertices,
-#   UseTrackToVertexTool = useTrackVertexTool
-# )
-
-# # AntiKt2 track jets.
-# jtm += PseudoJetGetter(
-#   "gakt2trackget", # give a unique name
-#   InputContainer = jetFlags.containerNamePrefix() + "AntiKt2PV0TrackJets", # SG key
-#   Label = "GhostAntiKt2TrackJet",   # this is the name you'll use to retrieve associated ghosts
-#   OutputContainer = "PseudoJetGhostAntiKt2TrackJet",
-#   SkipNegativeEnergy = True,
-#   GhostScale = 1.e-20,   # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so.
-# )
-
-# # AntiKt3 track jets.
-# jtm += PseudoJetGetter(
-#   "gakt3trackget", # give a unique name
-#   InputContainer = jetFlags.containerNamePrefix() + "AntiKt3PV0TrackJets", # SG key
-#   Label = "GhostAntiKt3TrackJet",   # this is the name you'll use to retrieve associated ghosts
-#   OutputContainer = "PseudoJetGhostAntiKt3TrackJet",
-#   SkipNegativeEnergy = True,
-#   GhostScale = 1.e-20,   # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so.
-# )
-
-# # AntiKt4 track jets.
-# jtm += PseudoJetGetter(
-#   "gakt4trackget", # give a unique name
-#   InputContainer = jetFlags.containerNamePrefix() + "AntiKt4PV0TrackJets", # SG key
-#   Label = "GhostAntiKt4TrackJet",   # this is the name you'll use to retrieve associated ghosts
-#   OutputContainer = "PseudoJetGhostAntiKt4TrackJet",
-#   SkipNegativeEnergy = True,
-#   GhostScale = 1.e-20,   # This makes the PseudoJet Ghosts, and thus the reco flow will treat them as so.
-# )
-
-# # Truth.
-# if jetFlags.useTruth and jtm.haveParticleJetTools:
-#   jtm += PseudoJetGetter(
-#     "truthget",
-#     Label = "Truth",
-#     InputContainer = jtm.truthpartcopy.OutputName,
-#     OutputContainer = "PseudoJetTruth",
-#     GhostScale = 0.0,
-#     SkipNegativeEnergy = True,
-
-#   )
-#   jtm += PseudoJetGetter(
-#     "truthwzget",
-#     Label = "TruthWZ",
-#     InputContainer = jtm.truthpartcopywz.OutputName,
-#     OutputContainer = "PseudoJetTruthWZ",
-#     GhostScale = 0.0,
-#     SkipNegativeEnergy = True,
+# This includes constituent modifications, track selection, copying of
+# input truth particles and event density calculations
+def JetInputCfgAndConstitPJName(inputdeps, configFlags):
+    jetlog.info("Setting up jet inputs.")
+    components = ComponentAccumulator()
+
+    jetlog.info("Inspecting first input file")
+    # Get the list of SG keys for the first input file
+    # I consider it silly to run on a set of mixed file types
+    firstinput = configFlags.Input.Files[0]
+    import os, pickle
+    # Cache details in a pickle file
+    cachename = "fpcache.{0}.pkl".format(firstinput)
+    fileinfo = None
+    if os.path.isfile(cachename):
+        jetlog.debug("Reading file info from cache \"{0}\"".format(cachename))
+        fpcache = open(cachename)
+        fileinfo = pickle.load(fpcache)
+    else:
+        from FilePeeker.FilePeeker import PeekFiles
+        fileinfo = PeekFiles([firstinput])[firstinput]
+        fpcache = open(cachename,'w')
+        pickle.dump(fileinfo,fpcache)
+        jetlog.debug("Wrote file info to cache \"{0}\"".format(cachename))
+    # PeekFiles returns a dict for each input file
+    filecontents = fileinfo["SGKeys"].split(' ')
+    
+    constit = inputdeps[0]
+    # Truth and track particle inputs are handled later
+    if constit.basetype not in [xAOD.Type.TruthParticle, xAOD.Type.TrackParticle]:
+        # Protection against reproduction of existing containers
+        if constit.inputname in filecontents:
+            jetlog.debug("Input container {0} for label {1} already in input file.".format(constit.inputname, constit.label))
+        else:
+            jetlog.debug("Preparing Constit Mods for label {0} from {1}".format(constit.label,constit.inputname))
+            # May need to generate constituent modifier sequences to
+            # produce the input collection
+            import ConstModHelpers
+            constitcomps = ConstModHelpers.ConstitModCfg(constit.basetype,constit.modifiers)
+            components.merge( constitcomps )
+
+    # Schedule the constituent PseudoJetGetterAlg
+    constitpjcomps, constitpjkey = ConstitPJGCfgAndOutputName( constit )
+    components.merge( constitpjcomps )
+
+    # Track selection and vertex association kind of go hand in hand, though it's not
+    # completely impossible that one might want one and not the other
+    if "JetSelectedTracks" in inputdeps or "JetTrackVtxAssoc" in inputdeps:
+        jetlog.debug("Setting up input track containers and track-vertex association")
+        from JetRecTools import JetRecToolsConfig
+        # Jet track selection
+        jettrackselloose = JetRecToolsConfig.getTrackSelTool()
+        jettvassoc = JetRecToolsConfig.getTrackVertexAssocTool()
+
+        jettrkprepalg = JetRecConf.JetAlgorithm("jetalg_TrackPrep")
+        jettrkprepalg.Tools = [ jettrackselloose, jettvassoc ]
+        components.addEventAlgo( jettrkprepalg )
+
+    # Resolve the rest of the input dependencies
+    for dep in inputdeps[1:]:
+        # Generate prequisite truth particle collections
+        # There may be more than one.
+        if dep.startswith("JetInputTruthParticles"):
+            # Special conditions e.g. "WZ" are set as a suffix preceded by ":"
+            truthmod = ''
+            if ":" in dep:
+                truthmod = dep.split(':')[1]
+            tpcname = "truthpartcopy"+truthmod
+            jetlog.debug("Setting up input truth particle container JetInputTruthParticles{0}".format(truthmod))
+
+            from ParticleJetTools.ParticleJetToolsConfig import getCopyTruthJetParticles
+            tpc = getCopyTruthJetParticles(truthmod)
+
+            tpcalg = JetRecConf.JetAlgorithm("jetalg_{0}".format(tpcname))
+            tpcalg.Tools = [tpc]
+            components.addEventAlgo(tpcalg)
+
+        # Truth particles specifically for truth labels
+        elif dep.startswith("TruthLabel"):
+            truthlabel = dep[10:]
+            tpcname = "truthpartcopy_"+truthlabel
+
+            jetlog.debug("Setting up input truth particle container TruthLabel{0}".format(truthlabel))
+            from ParticleJetTools.ParticleJetToolsConfig import getCopyTruthLabelParticles
+            tpc = getCopyTruthLabelParticles(truthlabel)
+
+            tpcalg = JetRecConf.JetAlgorithm("jetalg_{0}".format(tpcname))
+            tpcalg.Tools = [tpc]
+            components.addEventAlgo(tpcalg)
+
+        # Calculate the event density for jet area subtraction taking the
+        # jet constituents as input
+        # Possibly not needed if constituent suppression has been applied.
+        # Will want to update the standalone ED python for other uses,
+        # e.g. isolation or rho from constituents that are not used to
+        # build a particular jet collection (e.g. neutral PFOs)
+        #
+        # Needs protection against reproduction of existing containers
+        elif dep == "EventDensity":
+            rhokey = "Kt4"+constit.label+"EventShape"
+            if rhokey in filecontents:
+                jetlog.debug("Event density {0} for label {1} already in input file.".format(rhokey, constit.label))
+            else:
+                rhotoolname = "EventDensity_Kt4"+constit.label
+
+                jetlog.debug("Setting up event density calculation Kt4{0}".format(constit.label))
+                from EventShapeTools import EventShapeToolsConf
+                rhotool = EventShapeToolsConf.EventDensityTool(rhotoolname)
+                rhotool.InputContainer = constitpjkey
+                rhotool.OutputContainer = rhokey
+
+                eventshapealg = EventShapeToolsConf.EventDensityAthAlg("{0}Alg".format(rhotoolname))
+                eventshapealg.EventDensityTool = rhotool
+                components.addEventAlgo(eventshapealg)
+
+    return components, constitpjkey
+
+########################################################################
+# Functions for generating PseudoJetGetters, including determining
+# the prerequisites for their operation
+#
+def getConstitPrereqs(basedef):
+    prereqs = []
+    if basedef.basetype==xAOD.Type.TrackParticle:
+        prereqs = ["input:JetSelectedTracks","input:JetTrackVtxAssoc"]
+    elif basedef.basetype==xAOD.Type.TruthParticle:
+        prereqs = ["input:JetInputTruthParticles:"+basedef.inputname[22:]]
+    return prereqs
+
+def getGhostPrereqs(ghostdef):
+    jetlog.verbose("Getting ghost PseudoJets of type {0}".format(ghostdef.inputtype))
+
+    prereqs = []
+    if ghostdef.inputtype=="Track":
+        prereqs = ["input:JetSelectedTracks","input:JetTrackVtxAssoc"]
+    elif ghostdef.inputtype.startswith("TruthLabel"):
+        truthsuffix = ghostdef.inputtype[5:]
+        prereqs = ["input:TruthLabel"+truthsuffix]
+    elif ghostdef.inputtype == "Truth":
+        prereqs = ["input:JetInputTruthParticles"]
+    return prereqs
+
+def ConstitPJGCfgAndOutputName(basedef):
+    ca = ComponentAccumulator()
+    jetlog.debug("Getting PseudoJetAlg for label {0} from {1}".format(basedef.label,basedef.inputname))
+    # 
+    getter = JetRecConf.PseudoJetGetter("pjg_"+basedef.label,
+        InputContainer = basedef.inputname,
+        OutputContainer = "PseudoJet"+basedef.label,
+        Label = basedef.label,
+        SkipNegativeEnergy=True,
+        GhostScale=0.
+        )
+
+    pjgalg = JetRecConf.PseudoJetAlgorithm(
+        "pjgalg_"+basedef.label,
+        PJGetter = getter
+        )
+    ca.addEventAlgo( pjgalg )
+    return ca, getter.OutputContainer
+
+def GhostPJGCfgAndOutputName(ghostdef):
+    ca = ComponentAccumulator()
+    label = "Ghost"+ghostdef.inputtype
+    kwargs = {
+        "OutputContainer":    "PseudoJet"+label,
+        "Label":              label,
+        "SkipNegativeEnergy": True,
+        "GhostScale":         1e-40
+        }
+
+    pjgclass = JetRecConf.PseudoJetGetter
+    if ghostdef.inputtype=="MuonSegment":
+        # Muon segments have a specialised type
+        pjgclass = JetRecConf.MuonSegmentPseudoJetGetter
+        kwargs = {
+            "InputContainer":"MuonSegments",
+            "OutputContainer":"PseudoJet"+label,
+            "Label":label,
+            "Pt":1e-20
+            }
+    elif ghostdef.inputtype=="Track":
+        kwargs["InputContainer"] = "JetSelectedTracks"
+    elif ghostdef.inputtype.startswith("TruthLabel"):
+        truthsuffix = ghostdef.inputtype[5:]
+        kwargs["InputContainer"] = "TruthLabel"+truthsuffix
+    elif ghostdef.inputtype == "Truth":
+        kwargs["InputContainer"] = "JetInputTruthParticles"
+    else:
+        raise ValueError("Unhandled ghost type {0} received!".format(ghostdef.inputtype))
+
+    getter = pjgclass("pjg_"+label, **kwargs)
+
+    pjgalg = JetRecConf.PseudoJetAlgorithm(
+        "pjgalg_"+label,
+        PJGetter = getter
+        )
+    ca.addEventAlgo( pjgalg )
+    return ca, getter.OutputContainer
+
+########################################################################
+# Function for configuring the jet algorithm and builders, given the
+# set of dependencies
+#
+def JetAlgorithmCfg(jetname, jetdef, pjs, modlist):
+    jetlog.debug("Configuring JetAlgorithm \"jetalg_{0}\"".format(jetname))
+    components = ComponentAccumulator()
+
+    builder = getJetBuilder()
+
+    finder = getJetFinder(jetname, jetdef)
+    finder.JetBuilder = builder
+
+    import JetModConfig
+    mods = []
+    for moddef,modspec in modlist:
+        mod = JetModConfig.getModifier(jetdef,moddef,modspec)
+        mods.append(mod)
+
+    rectool = getJetRecTool(jetname,finder,pjs,mods)
+
+    jetalg = JetRecConf.JetAlgorithm("jetalg_"+jetname)
+    jetalg.Tools = [rectool]
+    components.addEventAlgo(jetalg)
+
+    return components
     
-#   )
-#   jtm += PseudoJetGetter(
-#     "gtruthget",
-#     Label = "GhostTruth",
-#     InputContainer = jtm.truthpartcopy.OutputName,
-#     OutputContainer = "PseudoJetGhostTruth",
-#     GhostScale = 1.e-20,
-#     SkipNegativeEnergy = True,
-#   )
-
-#   # Truth flavor tags.
-#   for ptype in jetFlags.truthFlavorTags():
-#     jtm += PseudoJetGetter(
-#       "gtruthget_" + ptype,
-#       InputContainer = "TruthLabel" + ptype,
-#       Label = "Ghost" + ptype,
-#       OutputContainer = "PseudoJetGhost" + ptype,
-#       SkipNegativeEnergy = True,
-#       GhostScale = 1e-20
-#     )
-
-#   # ParticleJetTools tools may be omitted in analysi releases.
-#   #ift jtm.haveParticleJetTools:
-#   # Delta-R truth parton label: truthpartondr.
-#   jtm += Analysis__JetQuarkLabel(
-#       "jetquarklabel",
-#       McEventCollection = "TruthEvents"
-#     )
-#   jtm += Analysis__JetConeLabeling(
-#       "truthpartondr",
-#       JetTruthMatchTool = jtm.jetquarklabel
-#       )
-  
-#   # Parton truth label.
-#   jtm += Analysis__JetPartonTruthLabel("partontruthlabel")
-
-#   # Cone matching for B, C and tau truth for all but track jets.
-#   jtm += ParticleJetDeltaRLabelTool(
-#     "jetdrlabeler",
-#     LabelName = "HadronConeExclTruthLabelID",
-#     BLabelName = "ConeExclBHadronsFinal",
-#     CLabelName = "ConeExclCHadronsFinal",
-#     TauLabelName = "ConeExclTausFinal",
-#     BParticleCollection = "TruthLabelBHadronsFinal",
-#     CParticleCollection = "TruthLabelCHadronsFinal",
-#     TauParticleCollection = "TruthLabelTausFinal",
-#     PartPtMin = 5000.0,
-#     JetPtMin =     0.0,
-#     DRMax = 0.3,
-#     MatchMode = "MinDR"
-#   )
-
-#   # Cone matching for B, C and tau truth for track jets.
-#   jtm += ParticleJetDeltaRLabelTool(
-#     "trackjetdrlabeler",
-#     LabelName = "HadronConeExclTruthLabelID",
-#     BLabelName = "ConeExclBHadronsFinal",
-#     CLabelName = "ConeExclCHadronsFinal",
-#     TauLabelName = "ConeExclTausFinal",
-#     BParticleCollection = "TruthLabelBHadronsFinal",
-#     CParticleCollection = "TruthLabelCHadronsFinal",
-#     TauParticleCollection = "TruthLabelTausFinal",
-#     PartPtMin = 5000.0,
-#     JetPtMin = 4500.0,
-#     DRMax = 0.3,
-#     MatchMode = "MinDR"
-#   )
-
-# #--------------------------------------------------------------
-# # Jet builder.
-# # The tool manager must have one jet builder.
-# #--------------------------------------------------------------
-
-# jtm.addJetBuilderWithArea(JetFromPseudojet(
-#   "jblda",
-#   Attributes = ["ActiveArea", "ActiveArea4vec"]
-# ))
-
-# jtm.addJetBuilderWithoutArea(JetFromPseudojet(
-#   "jbldna",
-#   Attributes = []
-# ))
-
-# #--------------------------------------------------------------
-# # Non-substructure moment builders.
-# #--------------------------------------------------------------
-
-# # Quality from clusters.
-# jtm += JetCaloQualityTool(
-#   "caloqual_cluster",
-#   TimingCuts = [5, 10],
-#   Calculations = ["LArQuality", "N90Constituents", "FracSamplingMax",  "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF", "BchCorrCell"],
-# )
-
-# # Quality from cells.
-# if jtm.haveJetCaloCellQualityTool:
-#   jtm += JetCaloCellQualityTool(
-#     "caloqual_cell",
-#     LArQualityCut = 4000,
-#     TileQualityCut = 254,
-#     TimingCuts = [5, 10],
-#     Calculations = ["LArQuality", "N90Cells", "FracSamplingMax",  "NegativeE", "Timing", "HECQuality", "Centroid", "AverageLArQF"]
-#   )
-
-# # Jet width.
-# jtm += JetWidthTool("width")
-
-# # Calo layer energies.
-# jtm += JetCaloEnergies("jetens")
-
-# # Read in missing cell map (needed for the following)
-# # commented out : incompatible with trigger : ATR-9696
-# ## if jtm.haveJetRecCalo:
-# ##     def missingCellFileReader(): 
-# ##       import os
-# ##       dataPathList = os.environ[ 'DATAPATH' ].split(os.pathsep)
-# ##       dataPathList.insert(0, os.curdir)
-# ##       from AthenaCommon.Utils.unixtools import FindFile
-# ##       RefFileName = FindFile( "JetBadChanCorrTool.root" ,dataPathList, os.R_OK )
-# ##       from AthenaCommon.AppMgr import ServiceMgr
-# ##       if not hasattr(ServiceMgr, 'THistSvc'):
-# ##         from GaudiSvc.GaudiSvcConf import THistSvc
-# ##         ServiceMgr += THistSvc()
-# ##       ServiceMgr.THistSvc.Input += ["JetBadChanCorrTool DATAFILE=\'%s\' OPT=\'READ\'" % RefFileName]
-# ##       missingCellFileReader.called = True 
-
-# ##     missingCellFileReader()
-
-# ##     jtm += MissingCellListTool(
-# ##       "missingcells",
-# ##       AddCellList = [],
-# ##       RemoveCellList = [],
-# ##       AddBadCells = True,
-# ##       DeltaRmax = 1.0,
-# ##       AddCellFromTool = False,
-# ##       LArMaskBit = 608517,
-# ##       TileMaskBit = 1,
-# ##       MissingCellMapName = "MissingCaloCellsMap"
-# ## )
-
-# ## # Bad channel corrections from cells
-# ## if jtm.haveJetBadChanCorrTool:
-# ##   jtm += JetBadChanCorrTool(
-# ##     "bchcorrcell",
-# ##     NBadCellLimit = 10000,
-# ##     StreamName = "/JetBadChanCorrTool/",
-# ##     ProfileName = "JetBadChanCorrTool.root",
-# ##     ProfileTag = "",
-# ##     UseCone = True,
-# ##     UseCalibScale = False,
-# ##     MissingCellMap = "MissingCaloCellsMap",
-# ##     ForceMissingCellCheck = False,
-# ##     UseClusters = False,
-# ##   )
-  
-# ##   # Bad channel corrections from clusters
-# ##   jtm += JetBadChanCorrTool(
-# ##     "bchcorrclus",
-# ##     NBadCellLimit = 0,
-# ##     StreamName = "",
-# ##     ProfileName = "",
-# ##     ProfileTag = "",
-# ##     UseCone = True,
-# ##     UseCalibScale = False,
-# ##     MissingCellMap = "",
-# ##     ForceMissingCellCheck = False,
-# ##     UseClusters = True
-# ##   )
-
-# # Jet vertex fraction.
-# jtm += JetVertexFractionTool(
-#   "jvfold",
-#   VertexContainer = jtm.vertexContainer,
-#   AssociatedTracks = "GhostTrack",
-#   TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-#   JVFName = "JVFOld"
-# )
-
-# # Jet vertex fraction with selection.
-# jtm += JetVertexFractionTool(
-#   "jvf",
-#   VertexContainer = jtm.vertexContainer,
-#   AssociatedTracks = "GhostTrack",
-#   TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-#   TrackSelector = jtm.trackselloose,
-#   JVFName = "JVF"
-# )
-
-# # Jet vertex tagger.
-# jtm += JetVertexTaggerTool(
-#   "jvt",
-#   VertexContainer = jtm.vertexContainer,
-#   TrackParticleContainer  = jtm.trackContainer,
-#   AssociatedTracks = "GhostTrack",
-#   TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-#   TrackSelector = jtm.trackselloose,
-#   JVTName = "Jvt",
-#   K_JVFCorrScale = 0.01,
-#   Z0Cut = 3.0,
-#   PUTrkPtCut = 30000.0
-# )
-
-# # Jet track info.
-# jtm += JetTrackMomentsTool(
-#   "trkmoms",
-#   VertexContainer = jtm.vertexContainer,
-#   AssociatedTracks = "GhostTrack",
-#   TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-#   TrackMinPtCuts = [500, 1000],
-#   TrackSelector = jtm.trackselloose
-# )
-
-# # Jet track vector sum info
-# jtm += JetTrackSumMomentsTool(
-#   "trksummoms",
-#   VertexContainer = jtm.vertexContainer,
-#   AssociatedTracks = "GhostTrack",
-#   TrackVertexAssociation = jtm.tvassoc.TrackVertexAssociation,
-#   RequireTrackPV = True,
-#   TrackSelector = jtm.trackselloose
-# )
-
-# # Jet cluster info.
-# jtm += JetClusterMomentsTool(
-#   "clsmoms",
-#   DoClsPt = True,
-#   DoClsSecondLambda = True,
-#   DoClsCenterLambda = True,
-#   DoClsSecondR = True
-# )
-
-# jtm += JetVoronoiMomentsTool(
-#   "voromoms",
-#   AreaXmin= -5.,
-#   AreaXmax=  5.,
-#   AreaYmin= -3.141592,
-#   AreaYmax=  3.141592
-# )
-
-# # Number of associated muon segments.
-# #jtm += JetMuonSegmentMomentsTool("muonsegs")
-
-# # Isolations.
-# # Note absence of PseudoJetGetter property means the jet inputs
-# # are obtained according to the InputType property of the jet.
-# jtm += JetIsolationTool(
-#   "jetisol",
-#   IsolationCalculations = ["IsoDelta:2:SumPt", "IsoDelta:3:SumPt"],
-# )
-# jtm += JetIsolationTool(
-#   "run1jetisol",
-#   IsolationCalculations = ["IsoKR:11:Perp", "IsoKR:11:Par", "IsoFixedCone:6:SumPt",],
-# )
-
-# # Bad LAr fractions.
-# jtm += JetLArHVTool("larhvcorr")
-
-# # Bad LAr fractions.
-# jtm += JetECPSFractionTool(
-#   "ecpsfrac",
-#   ECPSFractionThreshold = 0.80
-# )
-
-# # Jet origin correction.
-# jtm += JetOriginCorrectionTool(
-#   "jetorigincorr",
-#   VertexContainer = jtm.vertexContainer,
-#   OriginCorrectedName = "JetOriginConstitScaleMomentum"
-# )
-
-# #--------------------------------------------------------------
-# # Substructure moment builders.
-# #--------------------------------------------------------------
-
-# # Nsubjettiness
-# jtm += NSubjettinessTool(
-#   "nsubjettiness",
-#   Alpha = 1.0
-# )
-
-# # KtDR
-# jtm += KtDeltaRTool(
-#   "ktdr",
-#   JetRadius = 0.4
-# )
-
-# # Kt-splitter
-# jtm += KTSplittingScaleTool("ktsplitter")
-
-# # Angularity.
-# jtm += AngularityTool("angularity")
-
-# # Dipolarity.
-# jtm += DipolarityTool("dipolarity", SubJetRadius = 0.3)
-
-# # Planar flow.
-# jtm += PlanarFlowTool("planarflow")
-
-# # Kt mass drop.
-# jtm += KtMassDropTool("ktmassdrop")
-
-# # Energy correlations.
-# jtm += EnergyCorrelatorTool("encorr", Beta = 1.0)
-
-# # COM shapes.
-# jtm += CenterOfMassShapesTool("comshapes")
-
-# # Jet pull
-# jtm += JetPullTool(
-#   "pull",
-#   UseEtaInsteadOfY = False,
-#   IncludeTensorMoments = True
-# )
-
-# # Jet charge
-# jtm += JetChargeTool("charge", K=1.0)
-
-# # Shower deconstruction.
-# if jtm.haveShowerDeconstructionTool:
-#   jtm += ShowerDeconstructionTool("showerdec")
-
-# # Remove constituents (useful for truth jets in evgen pile-up file)
-# jtm += JetConstitRemover("removeconstit")
-
-# # Sort jets by pT
-# # May be deisred after calibration or grooming.
-# jtm += JetSorter("jetsorter")
-
-# #  LocalWords:  JetRecStandardTools
+
+########################################################################
+# Function for generating a jet builder, i.e. converter from
+# fastjet EDM to xAOD EDM
+#
+def getJetBuilder(doArea=True):
+    # Do we have any reasons for not using the area one?
+    # Maybe CPU reduction if we don't need areas for calibration
+    builder = JetRecConf.JetFromPseudojet("jetbuild")
+    if doArea:
+        builder.Attributes = ["ActiveArea","ActiveAreaFourVector"]
+    return builder
+
+########################################################################
+# Function for generating a jet finder, i.e. interface to fastjet
+#
+def getJetFinder(jetname, jetdef):
+    finder = JetRecConf.JetFinder("jetfind_"+jetname,
+        JetAlgorithm = jetdef.algorithm,
+        JetRadius = jetdef.radius,
+        PtMin = jetdef.ptmin,
+        GhostArea = 0.01,
+        RandomOption = 1,
+    )
+    return finder
+
+########################################################################
+# Function for generating a JetRecTool
+#
+def getJetRecTool(jetname, finder, pjs, mods):
+    # Create the JetRecTool and pass the inputs
+    jetrec = JetRecConf.JetRecTool("jetrec_"+jetname,
+        OutputContainer = jetname,
+        InputPseudoJets = pjs,
+        JetFinder = finder,
+        JetModifiers = mods
+    )
+    return jetrec
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecFlags.py b/Reconstruction/Jet/JetRecConfig/python/JetRecFlags.py
deleted file mode 100644
index 00e00d5b8b643db47c75f5487a6ffd672cc57940..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/JetRecFlags.py
+++ /dev/null
@@ -1,240 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-# JetRecFlags.py
-#
-# David Adams
-# Updated March 2015
-#
-# These are flags for controlling the behavior of jet reconstruction
-# in RecExCommon (which includes JetRec/JetRec_jobOptions.py) and in
-# the example jet reconstruction options RunJetRec.py.
-#
-# Typical usage is
-#   from JetRec.JetRecFlags import jetFlags
-#   if jetFlags.UseTruth:
-#     doSomethingWithTruth()
-#
-# Properties:
-#   Enabled - Skip all jet reco if false (drop whe rec.doJets is added)
-#   debug - JetRecTools are run a DEBUG level
-#   useTruth - Truth jets and association are enabled (for MC)
-#   useTopo  - Topocluster jets are enabled
-#   useTracks - Track jets and association are enabled
-#   useVertices - Toggles whether PFlow jet reconstruction makes use of vertex information.
-#   useMuonSegmentss - Muon segemnt association is enabled
-#   usePFlow - PFlow jets and associations are enabled
-#   useInDetTrackSelection - The inner detector track selection
-#     tool is used. This requires track propagator exist.
-#   jetAODList - The list of jet collections to be written out
-#   And much more--see below.
-
-from AthenaCommon.JobProperties import JobProperty, JobPropertyContainer
-from AthenaCommon.JobProperties import jobproperties
-
-class JetRecFlags(JobPropertyContainer):
-  """ The Jet making flag property container
-  """
-  pass
-
-class Enabled(JobProperty):
-  """ If false will prevent run of any Jet Alg
-  """
-  statusOn     = True     
-  allowedTypes = ['bool']  # type
-  StoredValue  = True      # default value
-
-class debug(JobProperty):
-  """ If > 0, debug (or higher) messages are written by jet tools.
-  """
-  statusOn     = True     
-  allowedTypes = ['int']  # type
-  StoredValue  = 0        # default value
-
-class useTruth(JobProperty):
-  """ If true, truth is present and used in jet reconstruction.
-      The status is set on in JetRecStandardToolManager.
-  """
-  statusOn     = False    
-  allowedTypes = ['bool']  # type
-  StoredValue  = True      # default value
-
-class truthFlavorTags(JobProperty):
-  """ List of flavor tags for truth tagging jets.
-  """
-  statusOn     = True     
-  allowedTypes = ['array']  # type
-  StoredValue  = ["BHadronsInitial", "BHadronsFinal", "BQuarksFinal",
-                  "CHadronsInitial", "CHadronsFinal", "CQuarksFinal",
-                  "TausFinal",
-                  "WBosons", "ZBosons", "HBosons", "TQuarksFinal",
-                  "Partons",
-                 ]
-  
-class useTopo(JobProperty):
-  """ If true, topoclusters are present and used in jet reconstruction.
-      The status is set on in JetRecStandardToolManager.
-  """
-  statusOn     = False    
-  allowedTypes = ['bool']  # type
-  StoredValue  = True      # default value
-
-class useTracks(JobProperty):
-  """ If true, tracks and vertices are present and used in jet reconstruction.
-      The status is set on in JetRecStandardToolManager.
-  """
-  statusOn     = False    
-  allowedTypes = ['bool']  # type
-  StoredValue  = True      # default value
-
-class useVertices(JobProperty):
-  """ If true, vertices are present and used in pflow jet reconstruction.
-  """
-  statusOn     = False     
-  allowedTypes = ['bool']  # type
-  StoredValue  = True      # default value
-
-class useMuonSegments(JobProperty):
-  """ If true, muon segments are present and used in jet reconstruction.
-      The status is set on in JetRecStandardToolManager.
-  """
-  statusOn     = False    
-  allowedTypes = ['bool']  # type
-  StoredValue  = True      # default value
-
-class usePFlow(JobProperty):
-  """ If true, pflow objects are present and used in jet reconstruction.
-      The status is set in JetRecStandardToolManager.
-  """
-  statusOn     = True    
-  allowedTypes = ['bool']  # type
-  StoredValue  = True      # default value
-
-class eventShapeTools(JobProperty):
-  """ List of event shape tools that should be called to calculate rho.
-      Allowed values are "emtopo", "lctopo", "emorig", "lcorig", "empflow", "emcpflow", "lcpflow".
-  """
-  statusOn     = True     
-  allowedTypes = ['None', 'list']  # type
-  StoredValue  = None              # default value
-
-class useInDetTrackSelection(JobProperty):
-  """ If true, the InDet track selection tool is used.
-  """
-  statusOn     = True     
-  allowedTypes = ['bool']  # type
-  StoredValue  = False     # default value
-
-class useCells(JobProperty):
-  """ If true, calo cells are accesible
-  """
-  statusOn     = True     
-  allowedTypes = ['bool']  # type
-  StoredValue  = False     # default value
-
-class useCaloQualityTool(JobProperty):
-  """ If true, the (slow) CaloQuality tool is used
-  """
-  statusOn     = True     
-  allowedTypes = ['bool']  # type
-  StoredValue  = True      # default value
-
-class useBTagging(JobProperty):
-  """ If true, then btagging is done when requested
-  """
-  statusOn     = True     
-  allowedTypes = ['bool']  # type
-  StoredValue  = False     # default value
-
-class skipTools(JobProperty):
-  """ List of modifier tools to exclude
-  """
-  statusOn     = True     
-  allowedTypes = ['list']  # type
-  StoredValue  = []        # default value
-
-class additionalTopoGetters(JobProperty):
-  """ List of PseudoJet getters to add for Topo jets.
-      E.g. to tag jets with track jets
-  """
-  statusOn     = True     
-  allowedTypes = ['list']  # type
-  StoredValue  = []        # default value
-
-class defaultCalibOpt(JobProperty):
-  """ Calibration applied to topo jets during jet building. See JetRecCalibrationFinder.
-  """
-  statusOn     = True     
-  allowedTypes = ['str']    # type
-  StoredValue  = ""   # default value
-
-class containerNamePrefix(JobProperty):
-  """ Prefix for jet collection names
-  """
-  statusOn     = True     
-  allowedTypes = ['str']    # type
-  StoredValue  = ""         # default value
-
-class separateJetAlgs(JobProperty):
-  """ If true, find and build jet containers in separate alg. Used for debugging.
-  """
-  statusOn     = True     
-  allowedTypes = ['bool']  # type
-  StoredValue  = False      # default value
-
-class timeJetToolRunner(JobProperty):
-  """ Timing flag for JetToolRunner: 0 for no timing, 1 for some, 2 for detailed
-  """
-  statusOn     = True     
-  allowedTypes = ['int']  # type
-  StoredValue  = 0        # default value
-
-class timeJetRecTool(JobProperty):
-  """ Timing flag for JetRecTool: 0 for no timing, 1 for some, 2 for detailed
-  """
-  statusOn     = True     
-  allowedTypes = ['int']  # type
-  StoredValue  = 0        # default value
-
-class jetAODList(JobProperty):
-  """ The collections to be saved in (x)AOD files
-  """
-  statusOn = True
-  allowedTypes = ['list']  
-  StoredValue  = []   
-
-class useTrackVertexTool(JobProperty):
-  """ Toggles whether to use track-vertex tool (only known client is currently pflow jet finding)
-  """
-  statusOn = True
-  allowedTypes = ['bool']
-  StoredValue = False
-
-
-
-jobproperties.add_Container(JetRecFlags)
-
-jobproperties.JetRecFlags.add_JobProperty(Enabled)
-jobproperties.JetRecFlags.add_JobProperty(debug)
-jobproperties.JetRecFlags.add_JobProperty(useTruth)
-jobproperties.JetRecFlags.add_JobProperty(truthFlavorTags)
-jobproperties.JetRecFlags.add_JobProperty(useTopo)
-jobproperties.JetRecFlags.add_JobProperty(useTracks)
-jobproperties.JetRecFlags.add_JobProperty(useVertices)
-jobproperties.JetRecFlags.add_JobProperty(useInDetTrackSelection)
-jobproperties.JetRecFlags.add_JobProperty(useMuonSegments)
-jobproperties.JetRecFlags.add_JobProperty(usePFlow)
-jobproperties.JetRecFlags.add_JobProperty(eventShapeTools)
-jobproperties.JetRecFlags.add_JobProperty(jetAODList)
-jobproperties.JetRecFlags.add_JobProperty(useCells)
-jobproperties.JetRecFlags.add_JobProperty(useCaloQualityTool)
-jobproperties.JetRecFlags.add_JobProperty(useBTagging)
-jobproperties.JetRecFlags.add_JobProperty(skipTools)
-jobproperties.JetRecFlags.add_JobProperty(additionalTopoGetters)
-jobproperties.JetRecFlags.add_JobProperty(defaultCalibOpt)
-jobproperties.JetRecFlags.add_JobProperty(containerNamePrefix)
-jobproperties.JetRecFlags.add_JobProperty(separateJetAlgs)
-jobproperties.JetRecFlags.add_JobProperty(timeJetToolRunner)
-jobproperties.JetRecFlags.add_JobProperty(timeJetRecTool)
-jobproperties.JetRecFlags.add_JobProperty(useTrackVertexTool)
-
-jetFlags = jobproperties.JetRecFlags
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecStandard.py b/Reconstruction/Jet/JetRecConfig/python/JetRecStandard.py
deleted file mode 100644
index aa958567624f384041119d831bbeeb90d3ce3262..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/JetRecStandard.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-# JetRecStandard.py
-#
-# David Adams
-# October 2014
-# Updated March 2015
-#
-# Wrapper for JetRecStandardToolManager.py that first uses RecExCommon to set flags.
-# High-level RecExCommon scripts should use this in place or JetRecStandardToolManager.
-#
-# Call with
-#   from JetRec.JetRecStandard import jtm
-#
-# Jet flags should be set before making this call. Those for truth, clusters, tracks
-# and muon segments will be set here iff they are not already set.
-
-from AthenaCommon import Logging
-jetlog = Logging.logging.getLogger('JetRec_jobOptions')
-
-myname = "JetRecStandard: "
-jetlog.info( myname + "Begin.")
-
-from RecExConfig.RecFlags import rec 
-from InDetRecExample.InDetJobProperties import InDetFlags
-from JetRecFlags import jetFlags
-
-# Function to display flag value and status.
-def sflagstat(flag):
-  return str(flag()) + " (status=" + str(flag.statusOn) + ")"
-
-# Import the jet reconstruction control flags.
-from JetRecFlags import jetFlags
-from RecExConfig.ObjKeyStore import cfgKeyStore
-
-# Skip truth if rec says it is absent.
-# No action if someone has already set the flag.
-jetlog.info( myname + "Initial useTruth: " + sflagstat(jetFlags.useTruth))
-jetlog.info( myname + "     rec.doTruth: " + str(rec.doTruth()) )
-if not jetFlags.useTruth.statusOn:
-  jetFlags.useTruth = rec.doTruth()
-jetlog.info( myname + "  Final useTruth: " + sflagstat(jetFlags.useTruth))
-
-# Skip use of topoclusters if not built
-# No action if someone has already set the flag.
-jetlog.info( myname + "Initial use topoclusters: " + str(jetFlags.useTopo()))
-if not jetFlags.useTopo.statusOn:
-  jetFlags.useTopo = rec.doCalo()
-jetlog.info( myname + "  Final use topoclusters: " + str(jetFlags.useTopo()))
-
-# Skip tracks if tracks or vertices are not present in the job.
-# No action if someone has already set the flag.
-haveTracks = cfgKeyStore.isInTransient('xAOD::TrackParticleContainer','InDetTrackParticles')
-haveVertices = cfgKeyStore.isInTransient("xAOD::VertexContainer","PrimaryVertices")
-recTracks = rec.doInDet()
-recVertices = bool(InDetFlags.doVertexFinding) and (recTracks or haveTracks)
-jetlog.info( myname + "Initial useTracks: " + sflagstat(jetFlags.useTracks) )
-jetlog.info( myname + "      rec doInDet: " + str(recTracks) )
-jetlog.info( myname + "  doVertexFinding: " + str(recVertices) )
-jetlog.info( myname + "      have tracks: " + str(haveTracks) )
-jetlog.info( myname + "    have vertices: " + str(haveVertices) )
-if not jetFlags.useTracks.statusOn:
-  jetFlags.useTracks = (recTracks or haveTracks) and (recVertices or haveVertices)
-jetlog.info( myname + "  Final useTracks: " + sflagstat(jetFlags.useTracks) )
- 
-if not jetFlags.useVertices.statusOn:
-  jetFlags.useVertices = (recVertices or haveVertices)
-jetlog.info( myname + "   useVertices: " + sflagstat(jetFlags.useVertices) )
-
-# Disable usage of vertices in pflow jets, if we are using cosmic data.
-from AthenaCommon.BeamFlags import jobproperties
-if jobproperties.Beam.beamType == 'cosmics':
-  jetFlags.useVertices = False
-
-# Skip pflow if we are not using tracks.
-jetlog.info( myname + "Initial usePFlow: " + sflagstat(jetFlags.usePFlow) )
-if not jetFlags.usePFlow.statusOn:
-  jetFlags.usePFlow = jetFlags.useTracks()
-jetlog.info( myname + "Final usePFlow: " + sflagstat(jetFlags.usePFlow) )
-
-# Skip use of muon segments if not built.
-# No action if someone has already set the flag.
-jetlog.info( myname + "Initial use muon segments: " + sflagstat(jetFlags.useMuonSegments) )
-if not jetFlags.useMuonSegments.statusOn:
-  jetFlags.useMuonSegments = rec.doMuon() and rec.doMuonCombined()
-jetlog.info( myname + "  Final use muon segments: " + sflagstat(jetFlags.useMuonSegments) )
-
-# Use rec flag to control BTagging.
-# No. Disable this unit we get support from Btagging to do this.
-# No action if someone has already set the flag.
-jetlog.info( myname + "Initial use Btagging: " + str(jetFlags.useBTagging) )
-jetlog.info( myname + "     rec do BTagging: " + str(rec.doBTagging()) )
-if not jetFlags.useBTagging.statusOn:
-  #jetFlags.useBTagging = rec.doBTagging()
-  jetFlags.useBTagging = False
-jetlog.info( myname + "  Final use Btagging: " + str(jetFlags.useBTagging) )
-
-# The following can be used to exclude tools from reconstruction.
-if 0:
-  jetFlags.skipTools = ["comshapes"]
-jetlog.info( "Skipped tools: %s", jetFlags.skipTools())
-
-from RecExConfig.RecAlgsFlags import recAlgs
-if not recAlgs.doEFlow():
-  jetFlags.usePFlow = False
-
-# Set the list of rho calculations.
-# If caller has set jetFlags.eventShapeTools(), then we use those values.
-if jetFlags.eventShapeTools() == None:
-  jetFlags.eventShapeTools = []
-  if jetFlags.useTopo():
-    jetFlags.eventShapeTools += ['emtopo', 'lctopo']
-  if jetFlags.usePFlow():
-    jetFlags.eventShapeTools += ['empflow']
-
-# Import the jet tool manager.
-from JetRecStandardToolManager import jtm
-
-jetlog.info( myname + "End." )
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecStandardToolManager.py b/Reconstruction/Jet/JetRecConfig/python/JetRecStandardToolManager.py
deleted file mode 100644
index c35a8e3abe9af773840f13a888faeb5d9ab379a2..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/JetRecStandardToolManager.py
+++ /dev/null
@@ -1,311 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-# JetRecStandardToolManager.py
-#
-# David Adams
-# March 2014
-#
-# Constructs an instance jtm of the JetToolManager with
-# standard definitions for jet tools.
-#
-# Usage:
-#   from JetRec.JetRecStandardToolManager import jtm
-#   jtm.addJetFinder("AntiKt4EMTopoJets", "AntiKt", 0.4, "em", "emtopo_ungroomed")
-#
-from AthenaCommon import Logging
-jetlog = Logging.logging.getLogger('JetRec_jobOptions')
-
-import copy
-
-myname = "JetRecStandardToolManager.py: "
-
-jetlog.info( myname + "Defining standard tools" )
-
-#########################################################
-# Set and lock flags.
-#########################################################
-
-from JetRecFlags import jetFlags
-
-# Set status on for flags that are initialized with status off.
-jetFlags.useTruth.set_On()
-jetFlags.useTopo.set_On()
-jetFlags.useTracks.set_On()
-jetFlags.usePFlow.set_On()
-jetFlags.useMuonSegments.set_On()
-jetFlags.useBTagging.set_On()
-
-# Lock all the flags used here so that later attempts to change
-# the value will fail with an error message.
-jetFlags.useTruth.lock()
-jetFlags.useTopo.lock()
-jetFlags.useTracks.lock()
-jetFlags.useMuonSegments.lock()
-jetFlags.useBTagging.lock()
-jetFlags.useCaloQualityTool.lock()
-jetFlags.additionalTopoGetters.lock()
-jetFlags.truthFlavorTags.lock()
-jetFlags.skipTools.lock()
-
-# Display all flags used here.
-jetlog.info( myname + "jetFlags.useTruth: " + str(jetFlags.useTruth()) )
-jetlog.info( myname + "jetFlags.useTopo: " + str(jetFlags.useTopo()) )
-jetlog.info( myname + "jetFlags.useTracks: " + str(jetFlags.useTracks()) )
-jetlog.info( myname + "jetFlags.useMuonSegments: " + str(jetFlags.useMuonSegments()) )
-jetlog.info( myname + "jetFlags.useBTagging: " + str(jetFlags.useBTagging()) )
-jetlog.info( myname + "jetFlags.useCaloQualityTool: " + str(jetFlags.useCaloQualityTool()) )
-jetlog.info( myname + "jetFlags.additionalTopoGetters: " + str(jetFlags.additionalTopoGetters()) )
-jetlog.info( myname + "jetFlags.truthFlavorTags: " + str(jetFlags.truthFlavorTags()) )
-jetlog.info( myname + "jetFlags.skipTools: " + str(jetFlags.skipTools()) )
-
-#########################################################
-# Create standard tool manager.
-#########################################################
-
-# Import the jet tool manager.
-from JetToolSupport import JetToolManager
-
-# Global jet tool manager with standard definitions
-jtm = JetToolManager()
-
-# Pt thresholds in MeV
-jtm.ptminFinder = 2000
-jtm.ptminFilter =    0
-
-# Add standard tool definitions to the tool manager.
-import JetRecStandardTools
-
-if 0:
-  jetlog.info( "First call to JetRecStandardToolManager.py:" )
-  from traceback import format_exc 
-  jetlog.info( format_exc() )
-  jetlog.info( "Exception" )
-  raise Exception
-  from traceback import print_stack
-  print_stack() 
-
-#########################################################
-# Getters
-#########################################################
-
-# Pseudojet getters
-empfgetters =  [jtm.empflowget]
-emcpfgetters = [jtm.emcpflowget]
-lcpfgetters =  [jtm.lcpflowget]
-
-trackgetters = [jtm.trackget]
-# Add track ghosts
-emgetters = [jtm.emget]
-lcgetters = [jtm.lcget]
-if jetFlags.useTracks():
-  emgetters = [jtm.emoriginget]
-  lcgetters = [jtm.lcoriginget]
-  emgetters += [jtm.gtrackget]
-  lcgetters += [jtm.gtrackget]
-  empfgetters += [jtm.gtrackget]
-  emcpfgetters += [jtm.gtrackget]
-  lcpfgetters += [jtm.gtrackget]
-
-if jetFlags.useMuonSegments():
-  emgetters += [jtm.gmusegget]
-  lcgetters += [jtm.gmusegget]
-  empfgetters  += [jtm.gmusegget]
-  emcpfgetters += [jtm.gmusegget]
-  lcpfgetters += [jtm.gmusegget]
-# Add jet ghosts.
-if 1:
-  for gettername in jetFlags.additionalTopoGetters():
-    getter = jtm[gettername]
-    emgetters += [getter]
-    lcgetters += [getter]
-# Add truth getter and truth ghosts.
-if jetFlags.useTruth():
-  truthgetters = [jtm.truthget]
-  truthwzgetters = [jtm.truthwzget]
-  trackgetters += [jtm.gtruthget]
-  emgetters += [jtm.gtruthget]
-  lcgetters += [jtm.gtruthget]
-  empfgetters += [jtm.gtruthget]
-  emcpfgetters += [jtm.gtruthget]
-  lcpfgetters += [jtm.gtruthget]
-  # Add truth cone matching and truth flavor ghosts.
-  flavorgetters = []
-  for ptype in jetFlags.truthFlavorTags():
-    flavorgetters += [getattr(jtm, "gtruthget_" + ptype)]
-  emgetters      += flavorgetters
-  lcgetters      += flavorgetters
-  truthgetters   += flavorgetters
-  truthwzgetters += flavorgetters
-  trackgetters   += flavorgetters
-  empfgetters    += flavorgetters
-  emcpfgetters   += flavorgetters
-  lcpfgetters    += flavorgetters
-# Add track jet ghosts.
-if jetFlags.useTracks():
-  trackjetgetters = []
-  trackjetgetters += [jtm.gakt2trackget]
-#  trackjetgetters += [jtm.gakt3trackget]
-  trackjetgetters += [jtm.gakt4trackget]
-  emgetters += trackjetgetters
-  lcgetters += trackjetgetters
-  empfgetters += trackjetgetters
-  emcpfgetters += trackjetgetters
-  lcpfgetters += trackjetgetters
-
-
-# Add getter lists to jtm indexed by input type name.
-jtm.gettersMap["emtopo"]    = list(emgetters)
-jtm.gettersMap["lctopo"]    = list(lcgetters)
-jtm.gettersMap["empflow"]   = list(empfgetters)
-jtm.gettersMap["emcpflow"]  = list(emcpfgetters)
-jtm.gettersMap["lcpflow"]   = list(lcpfgetters)
-jtm.gettersMap["track"]     = list(trackgetters)
-jtm.gettersMap["ztrack"]    = list(trackgetters)
-jtm.gettersMap["pv0track"]  = list(trackgetters)
-if jetFlags.useTruth():
-  jtm.gettersMap["truth"]   = list(truthgetters)
-  jtm.gettersMap["truthwz"] = list(truthwzgetters)
-
-#########################################################
-# Modifiers
-#########################################################
-
-# Modifiers for ungroomed jets from all input types.
-common_ungroomed_modifiers = [
-  jtm.width,
-]
-
-# Add parton truth labels and truth jet modifiers.
-if jetFlags.useTruth():
-  if jtm.haveParticleJetTools:
-    common_ungroomed_modifiers += [jtm.partontruthlabel]
-    common_ungroomed_modifiers += [jtm.truthpartondr]
-
-  # Modifiers for truth jets.
-  truth_ungroomed_modifiers = list(common_ungroomed_modifiers)
-  if jtm.haveParticleJetTools:
-    truth_ungroomed_modifiers += [jtm.jetdrlabeler]
-
-# Modifiers for track jets.
-track_ungroomed_modifiers = list(common_ungroomed_modifiers)
-if jetFlags.useTruth() and jtm.haveParticleJetTools:
-  track_ungroomed_modifiers += [jtm.trackjetdrlabeler]
-
-# Modifiers for topo (and pflow) jets.
-ungroomed_modifiers = [jtm.jetens, "calib", jtm.jetsorter] # calibration first. turn off with calibopt
-ungroomed_modifiers += ["jetfilter"]
-ungroomed_modifiers += common_ungroomed_modifiers
-ungroomed_modifiers += [jtm.larhvcorr]
-ungroomed_modifiers += [jtm.ecpsfrac]
-if jetFlags.useCaloQualityTool():
-  ungroomed_modifiers += [jtm.caloqual_cluster]
-if jetFlags.useTracks():
-  ungroomed_modifiers += [jtm.jvf]
-  ungroomed_modifiers += [jtm.jvt]
-  ungroomed_modifiers += [jtm.trkmoms]
-  ungroomed_modifiers += [jtm.trksummoms]
-  ungroomed_modifiers += [jtm.charge]
-  ungroomed_modifiers += ["trackassoc"]
-  ungroomed_modifiers += [jtm.jetorigin_setpv]
-if jetFlags.useTruth():
-  ungroomed_modifiers += ["truthassoc"]
-  if jtm.haveParticleJetTools:
-    ungroomed_modifiers += [jtm.jetdrlabeler]
-
-# Modifiers for groomed jets.
-groomed_modifiers = [ jtm.jetsorter,
-                      jtm.jetisol,
-                      jtm.ktdr,
-                      jtm.nsubjettiness,
-                      jtm.ktsplitter,
-                      jtm.angularity,
-                      jtm.dipolarity,
-                      jtm.planarflow,
-                      jtm.ktmassdrop,
-                      jtm.encorr,
-                      jtm.comshapes
-                      ]
-
-# Function to filter out skipped tools.
-def filterout(skiptoolnames, tools):
-  outtools = []
-  remtoolnames = []
-  nrem = 0
-  for tool in tools:
-    keep = True
-    for toolname in skiptoolnames:
-      skiptool = jtm[toolname]
-      same = tool == skiptool
-      if same:
-        keep = False
-        remtoolnames += [toolname]
-    if keep:
-      outtools += [tool]
-  jetlog.info( myname + "Removed tools: " + str(remtoolnames) )
-  return outtools
-
-# Modifiers for pflow jets.
-# Same as topo jets.
-# 28may2015 - ecpsfrac is not yet working for pflow in xAOD.
-pflow_ungroomed_modifiers = []
-pflow_ungroomed_modifiers += [jtm.constitfourmom_pflow]
-pflow_ungroomed_modifiers += filterout(["ecpsfrac"], ungroomed_modifiers)
-
-# Here add tools to be run for topo jets and NOT for pflow.
-
-# Cluster moments.
-ungroomed_modifiers += [jtm.clsmoms]
-
-# Voronoi moments.
-#ungroomed_modifiers += [jtm.voromoms]
-
-# Add Btagging.
-btags = ["btag"]
-if jetFlags.useBTagging():
-  ungroomed_modifiers += btags
-
-# EM only modifiers here
-emtopo_ungroomed_modifiers = []
-emtopo_ungroomed_modifiers += [jtm.constitfourmom_emtopo]
-emtopo_ungroomed_modifiers += ungroomed_modifiers
-
-# LC-only modifiers here
-lctopo_ungroomed_modifiers = []
-lctopo_ungroomed_modifiers += [jtm.constitfourmom_lctopo]
-lctopo_ungroomed_modifiers += ungroomed_modifiers
-
-# Filter out skipped tools.
-if len(jetFlags.skipTools()):
-  jetlog.info( myname + "Tools to be skipped: " + str(jetFlags.skipTools()) )
-  ungroomed_modifiers               = filterout(jetFlags.skipTools(), ungroomed_modifiers)
-  if jetFlags.useTruth():
-    truth_ungroomed_modifiers       = filterout(jetFlags.skipTools(), truth_ungroomed_modifiers)
-  track_ungroomed_modifiers         = filterout(jetFlags.skipTools(), track_ungroomed_modifiers)
-  groomed_modifiers                 = filterout(jetFlags.skipTools(), groomed_modifiers)
-  pflow_ungroomed_modifiers         = filterout(jetFlags.skipTools(), pflow_ungroomed_modifiers)
-  emtopo_ungroomed_modifiers        = filterout(jetFlags.skipTools(), emtopo_ungroomed_modifiers)
-  lctopo_ungroomed_modifiers        = filterout(jetFlags.skipTools(), lctopo_ungroomed_modifiers)
-
-# Add modifier lists to jtm indexed by modifier type name.
-jtm.modifiersMap["none"]                  = []
-jtm.modifiersMap["ungroomed"]             =            list(ungroomed_modifiers)
-
-jtm.modifiersMap["emtopo_ungroomed"]      =     list(emtopo_ungroomed_modifiers)
-jtm.modifiersMap["lctopo_ungroomed"]      =     list(lctopo_ungroomed_modifiers)
-jtm.modifiersMap["pflow_ungroomed"]       =      list(pflow_ungroomed_modifiers)
-
-if jetFlags.useTruth():
-  jtm.modifiersMap["truth_ungroomed"]     =      list(truth_ungroomed_modifiers)
-jtm.modifiersMap["track_ungroomed"]       =      list(track_ungroomed_modifiers)
-jtm.modifiersMap["groomed"]               =              list(groomed_modifiers)
-
-# Also index modifier type names by input type name.
-# These are used when the modifier list is omitted.
-jtm.modifiersMap["track"]                 = list(track_ungroomed_modifiers)
-jtm.modifiersMap["ztrack"]                = list(track_ungroomed_modifiers)
-jtm.modifiersMap["pv0track"]              = list(track_ungroomed_modifiers)
-if jetFlags.useTruth():
-  jtm.modifiersMap["truth"]               = list(truth_ungroomed_modifiers)
-  jtm.modifiersMap["truthwz"]             = list(truth_ungroomed_modifiers)
-
-jetlog.info( myname + "End." )
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecStandardTools.py b/Reconstruction/Jet/JetRecConfig/python/JetRecStandardTools.py
deleted file mode 100644
index 73fc970779c913789e6c56b5ea5bf42eba0aa680..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/JetRecStandardTools.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-# JetRecStandardTools.py
-#
-# David Adams
-# March 2014
-#
-# Define the low-level tools used in jet reconstruction.
-#
-# Tools are configured and put in the global jet tool manager so
-# they can be accessed when configuring JetRec tools.
-#
-# Execute this file to add the definitions to
-# JetRecStandardToolManager.jtm, e.g.
-#   import JetRecStandardTools
-
-# Import the jet flags.
-from JetRecFlags import jetFlags
-
-from JetRecStandardToolManager import jtm
-
-if not "UseTriggerStore " in locals():
-  UseTriggerStore = False
-
-# get levels defined VERBOSE=1 etc.
-from GaudiKernel.Constants import *
-
-try:
-  from JetRecCalo.JetRecCaloConf import MissingCellListTool
-  jtm.haveJetRecCalo = True
-except ImportError:
-  jtm.haveJetRecCalo = False
-
-# Import configurations from jet packages
-import JetMomentTools.DefaultTools
-import JetSubStructureMomentTools.DefaultTools
-import ParticleJetTools.DefaultTools
-import JetRec.DefaultTools 
-import PFlowUtils.DefaultTools
-import JetRecTools.DefaultTools
-
-JetMomentTools.DefaultTools.declareDefaultTools()
-JetSubStructureMomentTools.DefaultTools.declareDefaultTools()
-ParticleJetTools.DefaultTools.declareDefaultTools()
-JetRec.DefaultTools.declareDefaultTools()
-PFlowUtils.DefaultTools.declareDefaultTools()
-JetRecTools.DefaultTools.declareDefaultTools()
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecUtils.py b/Reconstruction/Jet/JetRecConfig/python/JetRecUtils.py
deleted file mode 100644
index 74ae8129b00821792d7bde861d619f27e0d244d2..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/JetRecUtils.py
+++ /dev/null
@@ -1,111 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-from AthenaCommon.AppMgr import ToolSvc
-
-from AthenaCommon import Logging
-jetlog = Logging.logging.getLogger('JetRec_jobOptions')
-
-def retrieveAODList():
-    from JetRecFlags import jetFlags
-    from RecExConfig.RecFlags import rec
-
-    if rec.doESD():
-        return jetFlags.jetAODList()
-    # then we are merging or doing a AOD ?
-    # We can not simply copy what we have from input since some
-    # jobs starts from empty files. See ATEAM-191.
-    # We hard code the list here while waiting for a more robust solution
-    l = [
-        # event shape objects
-        'xAOD::EventShape#Kt4EMPFlowEventShape',                    'xAOD::EventShapeAuxInfo#Kt4EMPFlowEventShapeAux.',
-        'xAOD::EventShape#Kt4EMTopoOriginEventShape',               'xAOD::EventShapeAuxInfo#Kt4EMTopoOriginEventShapeAux.',
-        'xAOD::EventShape#Kt4LCTopoOriginEventShape',               'xAOD::EventShapeAuxInfo#Kt4LCTopoOriginEventShapeAux.',
-        'xAOD::EventShape#NeutralParticleFlowIsoCentralEventShape', 'xAOD::EventShapeAuxInfo#NeutralParticleFlowIsoCentralEventShapeAux.',
-        'xAOD::EventShape#NeutralParticleFlowIsoForwardEventShape', 'xAOD::EventShapeAuxInfo#NeutralParticleFlowIsoForwardEventShapeAux.',
-        'xAOD::EventShape#ParticleFlowIsoCentralEventShape',        'xAOD::EventShapeAuxInfo#ParticleFlowIsoCentralEventShapeAux.',
-        'xAOD::EventShape#ParticleFlowIsoForwardEventShape',        'xAOD::EventShapeAuxInfo#ParticleFlowIsoForwardEventShapeAux.',
-        'xAOD::EventShape#TopoClusterIsoCentralEventShape',         'xAOD::EventShapeAuxInfo#TopoClusterIsoCentralEventShapeAux.',
-        'xAOD::EventShape#TopoClusterIsoForwardEventShape',         'xAOD::EventShapeAuxInfo#TopoClusterIsoForwardEventShapeAux.',
-
-        'xAOD::JetContainer#AntiKt10LCTopoJets',                    'xAOD::JetAuxContainer#AntiKt10LCTopoJetsAux.',
-        'xAOD::JetContainer#AntiKt2PV0TrackJets',                   'xAOD::JetAuxContainer#AntiKt2PV0TrackJetsAux.', 
-        #'xAOD::JetContainer#AntiKt3PV0TrackJets',                   'xAOD::JetAuxContainer#AntiKt3PV0TrackJetsAux.', 
-        'xAOD::JetContainer#AntiKt4EMPFlowJets',                    'xAOD::JetAuxContainer#AntiKt4EMPFlowJetsAux.',
-        'xAOD::JetContainer#AntiKt4EMTopoJets',                     'xAOD::JetAuxContainer#AntiKt4EMTopoJetsAux.',
-        'xAOD::JetContainer#AntiKt4LCTopoJets',                     'xAOD::JetAuxContainer#AntiKt4LCTopoJetsAux.',
-        'xAOD::JetContainer#AntiKt4PV0TrackJets',                   'xAOD::JetAuxContainer#AntiKt4PV0TrackJetsAux.', 
-        #'xAOD::JetContainer#CamKt12LCTopoJets',                     'xAOD::JetAuxContainer#CamKt12LCTopoJetsAux.',
-
-        'xAOD::CaloClusterContainer#EMOriginTopoClusters',          'xAOD::ShallowAuxContainer#EMOriginTopoClustersAux.',
-        'xAOD::CaloClusterContainer#LCOriginTopoClusters' ,         'xAOD::ShallowAuxContainer#LCOriginTopoClustersAux.',
-        ]
-
-    if rec.doTruth():
-        l += [
-            'xAOD::JetContainer#AntiKt10TruthJets',                 'xAOD::JetAuxContainer#AntiKt10TruthJetsAux.',
-            'xAOD::JetContainer#AntiKt10TruthWZJets',               'xAOD::JetAuxContainer#AntiKt10TruthWZJetsAux.',
-            'xAOD::JetContainer#AntiKt4TruthJets',                  'xAOD::JetAuxContainer#AntiKt4TruthJetsAux.',
-            'xAOD::JetContainer#AntiKt4TruthWZJets',                'xAOD::JetAuxContainer#AntiKt4TruthWZJetsAux.',
-            'xAOD::JetContainer#CamKt12TruthJets',                  'xAOD::JetAuxContainer#CamKt12TruthJetsAux.',
-            'xAOD::JetContainer#CamKt12TruthWZJets',                'xAOD::JetAuxContainer#CamKt12TruthWZJetsAux.',
-            ]
-
-    return l 
-    ## inputcontent = objKeyStore['inputFile'].list()
-    ## typeToSave = [ 'xAOD::JetContainer', 'xAOD::JetAuxContainer', 'xAOD::JetTrigAuxContainer' , 'xAOD::EventShape', 'xAOD::EventShapeAuxInfo' ]
-
-    ## def saveThisObject(o):
-    ##     # we must not write out any HLT jet containers - writing of those is controlled from trigger software, not offline jet software
-    ##     if  "HLT_" in o:
-    ##         return False
-    ##     # return True if o is of a desired type    
-    ##     return any( o.startswith( typ ) for typ in typeToSave )
-
-    ## esdjets = [ o for o in inputcontent if saveThisObject(o) ]
-
-    ## return esdjets
-
-def buildJetAlgName(finder, mainParam, variableRMassScale=0, variableRMinRadius=0):  # variableRMassScale (Rho) in MeV
-    if ( variableRMassScale > 0 ):
-        return finder + "VR" + str(int(variableRMassScale/1000)) + "Rmax" + str(int(mainParam*10)) + "Rmin" +str(int(variableRMinRadius*10))
-    return finder + str(int(mainParam*10))
-
-def buildJetContName(finder, mainParam, input, variableRMassScale=0, variableRMinRadius=0):
-    return buildJetAlgName(finder, mainParam, variableRMassScale, variableRMinRadius) +input+"Jets" # could be more elaborated...
-
-def interpretJetName(jetcollName,  finder = None,input=None, mainParam=None):
-    # first step : guess the finder, input , mainParam, if needed
-    if finder is None:
-        for a in [ 'AntiKt','CamKt','Kt', 'Cone','SISCone','CMSCone']:
-            if jetcollName.startswith(a):
-                finder = a
-                break
-        if finder is None:
-            jetrec.info( "Error could not guess jet finder type in ",jetcollName )
-            return 
-
-    if input is None:
-        for i in ['LCTopo','Tower','EMTopo', "Truth", "ZTrack", 'PV0Track']:
-            if i in jetcollName:
-                input = i
-                if i== "Tower":
-                    if 'Ghost' in jetcollName:
-                        input = 'Tower'
-                    else:
-                        input = "TopoTower"
-                break
-        if input is None:
-            jetrec.info( "Error could not guess input type in ",jetcollName )
-            return
-        
-    if mainParam is None:
-        # get the 2 chars following finder :
-        mp = jetcollName[len(finder):len(finder)+2]
-        mp = mp[0] if not mp[1] in '0123456789' else mp
-        try :
-            mainParam = float(mp)/10.
-        except ValueError :
-            jetrec.info( "Error could not guess main parameter in ",jetcollName )
-            return
-
-    return finder, mainParam, input
diff --git a/Reconstruction/Jet/JetRecConfig/python/JetToolSupport.py b/Reconstruction/Jet/JetRecConfig/python/JetToolSupport.py
deleted file mode 100644
index 0f16025a53c96abcb603fd3b0e4a951d4c81f934..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/python/JetToolSupport.py
+++ /dev/null
@@ -1,627 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-# JetToolSupport.py
-#
-# David Adams
-# March 2014
-#
-# Defines the jet tool manager (class JetToolManager, JTM for short)
-# which can be used to configure jet reconstruction tools.
-#
-# Use add or "+=" to register a tool both with this an instance of this
-# class and with ToolSvc. The advantage of doing it here is there is a
-# check to make sure the same name is not used more than once.
-#
-# Tools are locked when registered. The method setOutputLevel may
-# be used to override this lock to change the tool's output level.
-#
-# Methods are provide to configure a jetrec tool along with its
-# associated finder or groomer. The member "jetrecs" holds the full
-# list of offline jetrec tools and can be used to configure the tool or
-# algorithm that loops over such tools. The member trigjetrecs holds
-# the same for the trigger.  The members "finders" and
-# "groomers" hold the finding and grooming tools used by the jetrec
-# tools.
-#
-# The prefix for messages from this tool is held by the member "prefix"
-# and the member "debug" may be set to 1 to obtain more messages.
-#
-# The members "jetBuilderWithArea" and "jetBuilderWithoutArea" hold the
-# jet builders used by all jetrec tools.
-#
-# The member "ghostArea" specifies the area to use for the ghosts
-# generated for jet finding.
-
-from AthenaCommon import Logging
-jetlog = Logging.logging.getLogger('JetRec_jobOptions')
-
-# import the jet flags.
-from JetRecFlags import jetFlags
-
-# The tool manager
-class JetToolManager:
-  prefix = "JetToolManager: "
-  debug = 0
-  m_jetBuilder = None
-  jetBuilderWithArea = None
-  jetBuilderWithoutArea = None
-  tools = { }
-  finders = []
-  groomers = []
-  jetrecs = []
-  trigjetrecs = []
-  # Jet container names. Add input containers to this list:
-  # jetcons += ["SomeExistingJetContainer"]
-  jetcons = []
-  # pT thresholds in MeV (for finding and filtering after calibration)
-  ptminFinder = 2000
-  ptminFilter = 10000
-  # Map of getter lists.
-  gettersMap = {}
-  # Map of modifier lists
-  modifiersMap = {}
-
-  vertexContainer = "PrimaryVertices"
-  trackContainer = "InDetTrackParticles"
-
-  # Print a message to the log.
-  def msg(self, lvl, mymsg):
-    if lvl <= self.debug: jetlog.debug( self.prefix + str(mymsg) )
-
-  # Add a tool.
-  def add(self, mytool):
-    myname = mytool.name()
-    self.msg(1, "Adding tool " + myname)
-    if myname in self.tools:
-      self.msg(0, "Tool " + myname + " is already registered")
-      raise LookupError
-    else:
-      jetlog.info( type(mytool) )
-      self.tools[myname] = mytool
-      from AthenaCommon.AppMgr import ToolSvc 
-      ToolSvc += mytool
-      mytool.lock()
-      setattr(self, myname, mytool)
-      return mytool
-
-  # Add a tool with a local name (alias).
-  # Used to provide alternative names for tools with long names.
-  def addNamed(self, myname, mytool):
-    if myname in self.tools:
-      self.msg( "Name " + myname + " is already registered")
-      raise LookupError
-    self.tools[myname] = self.add(mytool)
-    setattr(self, myname, mytool)
-    return mytool
-
-  # Ad op+= as alternative syntax to add.
-  def __iadd__(self, mytool):
-    self.add(mytool)
-    return self
-
-  # Add for a jet builder.
-  # The jet builder is used by by all finders an groomers and
-  # must be added with one of these methods.
-  def addJetBuilderWithArea(self, mytool):
-    if self.add(mytool):
-      self.jetBuilderWithArea = mytool
-      self.msg(1, "Jet builder with area added: " + mytool.name())
-      return mytool
-    else:
-      self.msg(0, "Error adding jet builder with area.")
-      raise LookupError
-  def addJetBuilderWithoutArea(self, mytool):
-    if self.add(mytool):
-      self.jetBuilderWithoutArea = mytool
-      self.msg(1, "Jet builder without area added: " + mytool.name())
-      return mytool
-    else:
-      self.msg(0, "Error adding jet builder without area.")
-      raise LookupError
-
-  # Return the list of modifiers associated with a name.
-  # If the argument is a list, it is returned directly.
-  def getModifiers(self, modifiersin, altname =None):
-    if modifiersin == None:
-      return self.modifiersMap[altname]
-    if type(modifiersin) == str:
-      return self.modifiersMap[modifiersin]
-    return modifiersin
-
-  # Build the list of modifiers, replacing the string "calib:XXX:CALIB" with
-  # the appropriate calibration tool.
-  def buildModifiers(self, modifiersin, finder, getters, altname, output, calibOpt):
-    from GaudiKernel.Proxy.Configurable import ConfigurableAlgTool
-    from JetRec.JetRecConf import JetFinder
-    outmods = []
-    inmods = self.getModifiers(modifiersin, altname)
-    ncalib = 0
-    for mod in inmods:
-      jetlog.info( self.prefix + "Adding modifier " + str(mod) )
-      mod0 = ""
-      # Split mod = a:b:c... into mod0="a" and modarr = [a, b, c, ...]
-      if type(mod) == str:
-        if len(mod) == 0: continue
-        modarr = mod.split(":")
-        mod0 = modarr[0]
-      # Fully configured tool.
-      if isinstance(mod, ConfigurableAlgTool):
-        self.msg(2, "  Adding modifier " + mod.name())
-        outmods += [mod]
-      # Add jet calibration:
-      #   calib:XXX:CALIB - Applies calibration sequence XXX (see JetRecCalibrationFinder)
-      #                     using JetCalibrationTool with configuration (or key) CONFIG.
-      elif mod0 == "calib":
-        ncalib += 1
-        alg = finder.JetAlgorithm
-        rad = finder.JetRadius
-        get = getters[0]
-        inp = get.Label
-        copt = calibOpt
-        if type(calibOpt)==str and len(calibOpt):
-          calargs = calibOpt.split(":")
-        else:
-          calargs = modarr[1:]
-        if len(calargs) == 0:
-          copt = jetFlags.defaultCalibOpt
-          if type(copt)==str and len(copt):
-            calargs = copt.split(":")
-          else:
-            jetlog.info( self.prefix + 'ERROR: If the modifier "calib" is used, then calibOpt or jetFlags.CalibOpt must be a non-blank string.' )
-            jetlog.info( self.prefix + 'ERROR: Another alternative is to use the modifier string format "calib:<OPT>", e.g. "calib:a"' )
-            raise Exception
-        if len(calargs) == 0 or calargs[0]=="":
-          jetlog.info( self.prefix + "ERROR: Calibration requested without option." )
-          jetlog.info( self.prefix + "       Add calibOpt to tool string, jet build command or to jetFlags.defaultCalibOpt" )
-          raise Exception
-        seq = calargs[0]
-        if seq == "none":
-          jetlog.info( self.prefix + "Skipping calibration." )
-          continue
-        config = ""
-        evsprefix = "Kt4"
-        if len(calargs) > 1:
-          config = calargs[1]
-        if len(calargs) > 2:
-          evsprefix = calargs[2]
-        self.msg(0, "  Adding " + seq + " calibration for " + alg + " R=" + str(rad) + " " + inp)
-        self.msg(0, "  Configuration key/file: " + config)
-        self.msg(0, "  Event shape prefix: " + evsprefix)
-        from JetRecCalibrationFinder import jrcf
-        calmod = jrcf.find(alg, rad, inp, seq, config, evsprefix)
-        jetlog.info( self.prefix + "Adding calib modifier " + str(calmod) )
-        outmods += [calmod]
-      # truthassoc - Does truth jet association replacing the input anme with "Truth"
-      elif mod == "truthassoc":
-        sinp = getters[0].Label.split("Origin")[0]
-        salg = finder.JetAlgorithm
-        srad = str(int(10*finder.JetRadius))
-        cname = output.replace(sinp, "Truth")
-        if cname == output:
-            jetlog.info( sinp, cname, output )
-            raise TypeError
-        # Check that the building of the association tool has been scheduled.
-        if not cname in self.jetcons:
-          jetlog.info( self.prefix + "Truth association skipped because container is missing: " + cname )
-          jetlog.info( self.prefix + "Add to jetcons if input stream is expected to have this." )
-        tname = mod + "_" + salg + srad
-        if not tname in self.tools:
-          from JetMomentTools.JetMomentToolsConf import JetPtAssociationTool
-          self += JetPtAssociationTool(tname, InputContainer=cname, AssociationName="GhostTruth")
-        outmods += [self.tools[tname]]
-      # trackassoc - Does track jet association replacing the input name with "Track"
-      elif mod == "trackassoc":
-        sinp = getters[0].Label.split("Origin")[0]
-        salg = finder.JetAlgorithm
-        srad = str(int(10*finder.JetRadius))
-        cname = output.replace(sinp, "PV0Track")
-        if cname == output:
-            jetlog.info( sinp, cname, output )
-            raise TypeError
-        # Check that the building of the association tool has been scheduled.
-        if not cname in self.jetcons:
-          jetlog.info( self.prefix + "Track association skipped because container is missing: " + cname )
-          jetlog.info( self.prefix + "Add to jetcons if input stream is expected to have this." )
-        else:
-          tname = mod + "_" + salg + srad
-          if not tname in self.tools:
-            from JetMomentTools.JetMomentToolsConf import JetPtAssociationTool
-            self += JetPtAssociationTool(tname, InputContainer=cname, AssociationName="GhostTrack")
-          outmods += [self.tools[tname]]
-      # jetfilter - Filter to remove jets with pT < self.ptminFilter
-      elif mod == "jetfilter":
-        if self.ptminFilter <= 0:
-          jetlog.info( self.prefix + "Jet filter requested without a threshold." )
-          raise Exception
-        tname = "jetpt" + str(self.ptminFilter)
-        if not tname in self.tools:
-          from JetRec.JetRecConf import JetFilterTool
-          self.add( JetFilterTool(tname, PtMin=self.ptminFilter) ) 
-        outmods += [self.tools[tname]]
-      # btag - btagging
-      elif mod == "btag":
-        from BTagging.BTaggingConfiguration import getConfiguration
-        ConfInstance = getConfiguration()
-        from AthenaCommon.AppMgr import ToolSvc 
-        sinp = getters[0].Label
-        salg = finder.JetAlgorithm
-        srad = str(int(10*finder.JetRadius))
-        bspec = salg + srad + sinp
-        jetlog.info( self.prefix + "Scheduling btagging for " + bspec )
-        btagger = ConfInstance.setupJetBTaggerTool(ToolSvc, bspec)
-        jetlog.info( btagger )
-        self.add(btagger)
-        outmods += [btagger]
-      elif mod == "largeR":
-        outmods += jtm.modifiersMap["largeR"]
-      else:
-        raise TypeError
-    # Check calibration.
-    if calibOpt != "":
-      if ncalib==0:
-        jetlog.info( self.prefix + "Calibration option (" + calibOpt + ") provided without any calibration modifiers." )
-      elif ncalib > 1:
-        jetlog.info( self.prefix + "Calibration option (" + calibOpt + ") provided with multiple calibration modifiers." )
-        raise Exception
-
-        
-    return outmods
-
-  # Create a jet finder without a JetRecToosl.
-  #   alg = akgorithm name (Kt, CamKt, AntiKt)
-  #   radius = size parameter
-  #   rndseed: RandomOption for the finder
-  #   gettersin = array of input pseudojet builders (or name in gettersMap)
-  #   modifiersin = list of modifier tools (or name of such in modifiersMap)
-  #                 If absent, the gettersin name is used.
-  #   consumers = sequence of jet consumers to run after reco
-  #   ivtx = None: ordinary jet finding
-  #            -1: Separate finding for each vertex
-  #           >=0: Finding only for vertex ivtx.
-  #   ghostArea: if > 0, then ghosts are found with this inverse density
-  #   rndseed: RandomOption for the finder
-  #   variableRMinRadius: Min radius for variable-R finding
-  #   variableRMassScale: Mass scale for variable-R finding
-  #   calibOpt: Calibration option, e.g. "ar". See JetRecCalibrationFinder.py.
-  # returns lofinder, hifinder where finder is the lowest-level finder and hifinder
-  #         is the highest.
-  def addJetFinderTool(self, toolname, alg, radius, ivtx =None,
-                       ghostArea =0.0, ptmin =0.0, rndseed =1,
-                       variableRMinRadius =-1.0, variableRMassScale =-1.0):
-    myname = "JetToolManager:addJetFinderTool: "
-    if toolname in self.tools:
-      self.msg(0, "Tool " + myname + " is already registered")
-      raise LookupError
-    self.msg(2, "Adding finder tool")
-    if ghostArea == 0.0:
-      self.m_jetBuilder = self.jetBuilderWithoutArea
-    else:
-      self.m_jetBuilder = self.jetBuilderWithArea
-    if self.m_jetBuilder == None:
-      self.msg(0, "Jet builder must be specified")
-      raise Error
-    from JetRec.JetRecConf import JetFinder
-    areaSuffix= "Area" if ghostArea>0.0 else ""
-    finder = JetFinder(toolname);
-    finder.JetAlgorithm = alg
-    finder.JetRadius = radius
-    finder.VariableRMinRadius = variableRMinRadius
-    finder.VariableRMassScale = variableRMassScale
-    finder.RandomOption = rndseed
-    finder.GhostArea = ghostArea
-    if ptmin > 0.0:
-      finder.PtMin = ptmin
-    else:
-      finder.PtMin = self.ptminFinder
-    finder.JetBuilder = self.m_jetBuilder
-    self += finder
-    self.finders += [finder]
-    hifinder = finder;
-    if type(ivtx) is int:
-      from JetRec.JetRecConf import JetByVertexFinder
-      vfinder = JetByVertexFinder(
-        toolname + "ByVertex",
-        JetFinder = finder,
-        Vertex = ivtx
-      )
-      self += vfinder
-      self.finders += [vfinder]
-      hifinder = vfinder;
-    return (finder, hifinder)
-
-  # Create a jet finder and rectool.
-  #   output = name for output container (and JetRecTool)
-  #   alg = akgorithm name (Kt, CamKt, AntiKt)
-  #   radius = size parameter
-  #   rndseed: RandomOption for the finder
-  #   isTrigger: If true, the trigger store is used and the tools is added to
-  #              trigjetrecs instead of jetrecs
-  #   useTriggerStore: If true, the trigger store is used.
-  #   gettersin = array of input pseudojet builders (or name in gettersMap)
-  #   modifiersin = list of modifier tools (or name of such in modifiersMap)
-  #                 If absent, the gettersin name is used.
-  #   consumers = sequence of jet consumers to run after reco
-  #   ivtx = None: ordinary jet finding (unless gettersin = ztrack or pv0track)
-  #            -1: Separate finding fore each vertex
-  #           >=0: Finding only for vertex ivtx.
-  #   ghostArea: if > 0, then ghosts are found with this inverse density
-  #   ptminFilter: If > 0, then this is used as the pT threhold for filtering jets.
-  #   rndseed: RandomOption for the finder
-  #   isTrigger: If true, the trigger store is used and the tools is added to
-  #              trigjetrecs instead of jetrecs
-  #   useTriggerStore: If true, the trigger store is used (only for testing)
-  #   variableRMinRadius: Min radius for variable-R finding
-  #   variableRMassScale: Mass scale for variable-R finding
-  #   calibOpt: Calibration option, e.g. "ar". See JetRecCalibrationFinder.py.
-  def addJetFinder(self, output, alg, radius, gettersin, modifiersin =None,
-                   consumers =None, ivtxin =None,
-                   ghostArea =0.0, ptmin =0.0, ptminFilter =0.0, rndseed =1,
-                   isTrigger =False, useTriggerStore =False,
-                   variableRMinRadius =-1.0, variableRMassScale =-1.0,
-                   calibOpt ="", jetPseudojetCopier ="",
-                   warnIfDuplicate=True,
-                   overwrite=False):
-    self.msg(2, "Adding finder")
-    from JetRec.JetRecConf import JetRecTool
-    if type(gettersin) == str:
-      getters = self.gettersMap[gettersin]
-    else:
-      getters = gettersin
-    # If jet finding by vertex is not specified, check for special input type names
-    ivtx = ivtxin
-    if ivtx == None:
-      if gettersin == "ztrack": ivtx = -1        # Find tracs separatesly for each vertex
-      elif gettersin == "pv0track": ivtx = 0     # Find tracks only for 1st vertex
-    # Retrieve/build the jet finder.
-    lofinder,hifinder = self.addJetFinderTool(output+"Finder", alg, radius, ivtx, ghostArea, ptmin, rndseed, 
-                                            variableRMinRadius, variableRMassScale)
-    jetrec = JetRecTool(output)
-    jetrec.PseudoJetGetters = getters
-    jetrec.JetFinder = hifinder
-    jetrec.OutputContainer = output
-    ptminSave = self.ptminFilter
-    if ptminFilter > 0.0: self.ptminFilter = ptminFilter
-    jetrec.JetModifiers = self.buildModifiers(modifiersin, lofinder, getters, gettersin, output, calibOpt)
-    if consumers != None:
-      jetrec.JetConsumers = consumers
-    self.ptminFilter = ptminSave
-    jetrec.Trigger = isTrigger or useTriggerStore
-    jetrec.Timer = jetFlags.timeJetRecTool()
-    jetrec.WarnIfDuplicate = warnIfDuplicate
-    jetrec.Overwrite = overwrite
-
-    self += jetrec
-    if isTrigger:
-      self.trigjetrecs += [jetrec]
-    else:
-      self.jetrecs += [jetrec]
-    self.jetcons += [output]
-    return jetrec
-
-  # Create a mass-drop filter and rectool.
-  #   output = name for output container (and JetRecTool)
-  #   mumax = MuMax used in the filter
-  #   ymin = YMin used in the filter
-  #   input = name of the input jet container
-  #   modifiersin = list of modifier tools (or name of such in modifiersMap)
-  #   doArea = whether to write jet areas (default false because work is needed to 
-  #            recover this for reclustered jets).
-  def addJetSplitter(self, output, mumax, ymin, input, modifiersin ="groomed",
-                     isTrigger =False, useTriggerStore =False, doArea =True):
-    from JetRec.JetRecConf import JetSplitter
-    from JetRec.JetRecConf import JetRecTool
-    groomer = JetSplitter(output + "Groomer")
-    groomer.MuMax = mumax
-    groomer.YMin = ymin
-    groomer.BDRS = False
-    groomer.NSubjetMax = 3
-    if doArea:
-      groomer.JetBuilder = self.jetBuilderWithArea
-    else:
-      groomer.JetBuilder = self.jetBuilderWithoutArea
-    self += groomer
-    jetrec = JetRecTool(output)
-    jetrec.JetGroomer = groomer
-    jetrec.InputContainer = input
-    jetrec.OutputContainer = output
-    jetrec.JetModifiers = self.getModifiers(modifiersin)
-    jetrec.Trigger = isTrigger or useTriggerStore
-    jetrec.Timer = jetFlags.timeJetRecTool()
-    self += jetrec
-    if isTrigger:
-      self.trigjetrecs += [jetrec]
-    else:
-      self.jetrecs += [jetrec]
-    self.jetcons += [output]
-    return jetrec
-
-  # Create a Trimmer and rectool.
-  #   output = name for output container (and JetRecTool)
-  #   rclus = RClus used in the trimming
-  #   ptfrac = PtFrac used in the trimming
-  #   input = name of the input jet container
-  #   modifiersin = list of modifier tools (or name of such in modifiersMap)
-  def addJetTrimmer(self, output, rclus, ptfrac, input, modifiersin ="groomed",
-                    pseudojetRetriever ="jpjretriever",
-                    isTrigger =False, useTriggerStore =False, doArea =True):
-    from JetRec.JetRecConf import JetTrimmer
-    from JetRec.JetRecConf import JetRecTool
-    groomer = JetTrimmer(output + "Groomer")
-    groomer.RClus = rclus
-    groomer.PtFrac = ptfrac
-    if doArea:
-      groomer.JetBuilder = self.jetBuilderWithArea
-    else:
-      groomer.JetBuilder = self.jetBuilderWithoutArea
-    self += groomer
-    jetrec = JetRecTool(output)
-    jetrec.JetGroomer = groomer
-    jetrec.InputContainer = input
-    jetrec.OutputContainer = output
-    jetrec.JetModifiers = self.getModifiers(modifiersin)
-    jetrec.Trigger = isTrigger or useTriggerStore
-    jetrec.Timer = jetFlags.timeJetRecTool()
-    if pseudojetRetriever in self.tools:
-      jetrec.JetPseudojetRetriever = self.tools[pseudojetRetriever]
-    else:
-      jetlog.info( "Requested jet pseudojet retriever is not a registered tool: " \
-            + pseudojetRetriever )
-      raise KeyError
-    self += jetrec
-    if isTrigger:
-      self.trigjetrecs += [jetrec]
-    else:
-      self.jetrecs += [jetrec]
-    self.jetcons += [output]
-    return jetrec
-
-  # Create a Pruner and rectool.
-  #   output = name for output container (and JetRecTool)
-  #   rcut = RCut used in the pruning
-  #   zcut = ZCut used in the pruning
-  #   input = name of the input jet container
-  #   modifiersin = list of modifier tools (or name of such in modifiersMap)
-  def addJetPruner(self, output, rcut, zcut, input, modifiersin ="groomed",
-                   isTrigger =False, useTriggerStore =False, doArea =True):
-    from JetRec.JetRecConf import JetPruner
-    from JetRec.JetRecConf import JetRecTool
-    groomer = JetPruner(output + "Groomer")
-    groomer.RCut = rcut
-    groomer.ZCut = zcut
-    if doArea:
-      groomer.JetBuilder = self.jetBuilderWithArea
-    else:
-      groomer.JetBuilder = self.jetBuilderWithoutArea
-    self += groomer
-    jetrec = JetRecTool(output)
-    jetrec.JetGroomer = groomer
-    jetrec.InputContainer = input
-    jetrec.OutputContainer = output
-    jetrec.JetModifiers = self.getModifiers(modifiersin)
-    jetrec.Trigger = isTrigger or useTriggerStore
-    jetrec.Timer = jetFlags.timeJetRecTool()
-    self += jetrec
-    if isTrigger:
-      self.trigjetrecs += [jetrec]
-    else:
-      self.jetrecs += [jetrec]
-    self.jetcons += [output]
-    return jetrec
-
-  # Create a jet reclusterer and rectool.
-  #   output = name for output container (and JetRecTool)
-  #   alg = akgorithm name (Kt, CamKt, AntiKt)
-  #   radius = size parameter
-  #   input = name for the input jet collection
-  #   rndseed: RandomOption for the finder
-  #   isTrigger: If true, the trigger store is used and the tools is added to
-  #              trigjetrecs instead of jetrecs
-  #   useTriggerStore: If true, the trigger store is used.
-  #   modifiersin = list of modifier tools (or name of such in modifiersMap)
-  #                 If absent, the gettersin name is used.
-  #   consumers = sequence of jet consumers to run after reco
-  #   ivtx = None: ordinary jet finding (unless gettersin = ztrack or pv0track)
-  #            -1: Separate finding fore each vertex
-  #           >=0: Finding only for vertex ivtx.
-  #   ghostArea: if > 0, then ghosts are found with this inverse density
-  #   ptminFilter: If > 0, then this is used as the pT threhold for filtering jets.
-  #   rndseed: RandomOption for the finder
-  #   isTrigger: If true, the trigger store is used and the tools is added to
-  #              trigjetrecs instead of jetrecs
-  #   useTriggerStore: If true, the trigger store is used (only for testing)
-  #   variableRMinRadius: Min radius for variable-R finding
-  #   variableRMassScale: Mass scale for variable-R finding
-  #   calibOpt: Calibration option, e.g. "ar". See JetRecCalibrationFinder.py.
-  def addJetReclusterer(self, output, alg, radius, input, modifiersin =None,
-                        consumers =None, ivtx =None,
-                        ghostArea =0.0, ptmin =0.0, ptminFilter =0.0, rndseed =1,
-                        isTrigger =False, useTriggerStore =False,
-                        variableRMinRadius =-1.0, variableRMassScale =-1.0,
-                        calibOpt ="", jetPseudojetCopier =""):
-    self.msg(2, "Adding reclusterer")
-    from JetRec.JetRecConf import JetRecTool
-    from JetRec.JetRecConf import JetReclusterer
-    # Retrieve/build the jet finder.
-    lofinder,hifinder = self.addJetFinderTool(output+"Finder", alg, radius, ivtx, ghostArea, ptmin, rndseed, 
-                                              variableRMinRadius, variableRMassScale)
-    reclname = output + "Reclusterer"
-    groomer = JetReclusterer(
-      reclname,
-      JetConstituentsRetriever = self.tools["jconretriever"],
-      JetFinder = hifinder
-    )
-    self += groomer
-    jetrec = JetRecTool(output)
-    jetrec.InputContainer = input
-    jetrec.OutputContainer = output
-    jetrec.JetGroomer = groomer
-    jetrec.JetModifiers = self.getModifiers(modifiersin)
-    if consumers != None:
-      jetrec.JetConsumers = consumers
-    jetrec.Trigger = isTrigger or useTriggerStore
-    jetrec.Timer = jetFlags.timeJetRecTool()
-    self += jetrec
-    if isTrigger:
-      self.trigjetrecs += [jetrec]
-    else:
-      self.jetrecs += [jetrec]
-    self.jetcons += [output]
-    return jetrec
-
-  # Create a copying rectool.
-  #   output = name for output container (and JetRecTool)
-  #   output = name for input container
-  #   modifiersin = list of modifier tools (or name of such in modifiersMap)
-  def addJetCopier(self, output, input, modifiersin, ptminFilter =0.0, radius =0.0, alg ="", inp ="",
-                   isTrigger=False, useTriggerStore=False, calibOpt ="", shallow =True):
-    from JetRec.JetRecConf import JetRecTool
-    jetrec = JetRecTool(output)
-    jetrec.InputContainer = input
-    jetrec.OutputContainer = output
-    ptminSave = self.ptminFilter
-    if ptminFilter > 0.0: self.ptminFilter = ptminFilter
-    class finder:
-      JetRadius = radius
-      JetAlgorithm = alg
-    class get:
-      Label = inp
-    getters = [get]
-    jetrec.JetModifiers = self.buildModifiers(modifiersin, finder, getters, None, output, calibOpt)
-    self.ptminFilter = ptminSave
-    jetrec.Trigger = isTrigger or useTriggerStore
-    jetrec.Timer = jetFlags.timeJetRecTool()
-    jetrec.ShallowCopy = shallow
-    self += jetrec
-    self.jetrecs += [jetrec]
-    self.jetcons += [output]
-    return jetrec
-
-  # Ad op[] to return a tool.
-  def __getitem__(self, toolname):
-    return self.tools[toolname]
-
-  # Change the output level of a tool.
-  def setOutputLevel(self, toolid, level):
-    from GaudiKernel.Proxy.Configurable import ConfigurableAlgTool
-    if type(toolid) == str:
-      tool = self[toolid]
-    else:
-      tool = toolid
-    locked = tool.isLocked()
-    oldlevel = "undefined"
-    if locked:
-      dbglvl = 0
-      slock = "locked"
-      tool.unlock()
-    else:
-      dbglvl = 1
-      slock = "unlocked"
-    aname = "OutputLevel"
-    if hasattr(tool, aname):
-      oldlevel = getattr(tool, aname)
-    setattr(tool, aname, level)
-    if locked:
-      tool.lock()
-    self.msg(0, "Changed output level of " + slock + " tool " + tool.name() + \
-             " from " + str(oldlevel) + " to " + str(level) + ".")
-
diff --git a/Reconstruction/Jet/JetRecConfig/python/README.md b/Reconstruction/Jet/JetRecConfig/python/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..8c7f6811d28f71d9c7db2d5398277246357e438b
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/python/README.md
@@ -0,0 +1,65 @@
+# JetRecConfig/python
+
+## Module contents
+
+### JetRecConfig.py
+
+* This is the top-level jet reconstruction module, containing the
+  function JetRecCfg() that returns a configured ComponentAccumulator
+  with the standalone jet reconstruction sequence.
+* The function resolveDependencies() can be called to retrieve a
+  dict containing the full set of input collections, ghost associations
+  and jet modifiers needed to satisfy the user's needs as encoded
+  in the provided JetDefinition.
+
+### JetDefinition.py
+
+* This module defines a number of configuration classes used to define
+  a jet reconstruction job. The classes are listed below together with
+  the information that they contain.
+  * JetDefinition -- defines the jet collection
+     * jet clustering algorithm (kt, Cambridge/Aachen, anti-kt)
+     * radius
+     * input type (JetConstit object)
+     * name
+     * minimum pt (separately for fastjet and xAOD jet conversion)
+     * ghost list
+     * modifier list
+  * JetConstit -- defines inputs to jet finding
+     * base type (type of xAOD object)
+     * modifier list (corrections/filters applied before jet finding)
+  * JetGhost -- defines objects to be associated with ghost association
+     * input type (type of xAOD object)
+     * label (identifier, e.g. type of truth particle [TruthPartons], ...)
+  * JetModifier -- defines tools that operate on the jet collection
+     * tooltype
+     * tool name
+     * a helper function defining how to configure the tool
+     * a string describing to the helper function how to configure the tool
+     * a flag stating whether the jet definition is needed to configure the tool
+     * a list of prerequisites (inputs, ghosts, other mods) or a helper function returning such a list
+
+### ConstModHelpers.py
+
+* This module assists setup of constituent modifiers, i.e. operations
+  like filtering and four-momentum corrections applied prior to jet finding.
+* It is called from JetRecConfig.py
+
+### JetModConfig.py
+
+* This module assists configuration of modifiers, including resolving
+  their dependencies as the job is scheduled.
+* When a list of desired modifiers is provided, a full list of all
+  modifiers needing to be run such that the desired modifiers will
+  be executed is returned, along with the sets of ghosts and input
+  collections needing to be set up.
+
+### StandardJetDefs.py
+
+* This module holds a library of standard jet and constituent definitions
+  that are regularly used in reconstruction.
+
+### StandardJetMods.py
+
+* This module holds a library of standard jet modifiers that are
+  frequently scheduled in reconstruction.
diff --git a/Reconstruction/Jet/JetRecConfig/python/StandardJetDefs.py b/Reconstruction/Jet/JetRecConfig/python/StandardJetDefs.py
new file mode 100644
index 0000000000000000000000000000000000000000..b3a883b43fa4137fbccb46d290d67316cc74ee22
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/python/StandardJetDefs.py
@@ -0,0 +1,71 @@
+# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+
+########################################################################
+#                                                                      #
+# StandardJetDefs: A module defining standard definitions for jet      #
+# constituents and jet algorithms.                                     #
+# These can be copied and modified by users who want something a bit   #
+# different from what is provided.                                     #
+# Standard lists of ghost associated particles and modifiers are       #
+# provided elsewhere.                                                  #
+#                                                                      #
+# Author: TJ Khoo                                                      #
+# * Written for the time being to work in R21, but with R22 in mind    #
+#                                                                      #
+########################################################################
+
+
+########################################################################
+# Typical jet constituents
+from JetDefinition import xAOD, JetConstit
+from copy import deepcopy
+
+# Topoclusters with origin correction.
+# We don't currently use raw TopoClusters, though some handling
+# could be added to support this.
+EMTopoOrigin = JetConstit(xAOD.Type.CaloCluster, ["EM","Origin"])
+LCTopoOrigin = JetConstit(xAOD.Type.CaloCluster, ["LC","Origin"])
+# LC clusters with Constituent Subtraction + SoftKiller
+LCTopoCSSK = deepcopy(LCTopoOrigin)
+LCTopoCSSK.modifiers += ["CS","SK"]
+
+# EM-scale particle flow objects with charged hadron subtraction
+# For now we don't specify a scale, as only one works well, but
+# this could be incorporated into the naming scheme and config
+CHSPFlow = JetConstit(xAOD.Type.ParticleFlow)
+# Particle Flow Objects with Constituent Subtraction + SoftKiller
+CSSKPFlow = deepcopy(CHSPFlow)
+CSSKPFlow.modifiers += ["CS","SK"]
+
+# Track particles from the primary vertex
+PV0Track = JetConstit(xAOD.Type.TrackParticle,["PV0"])
+
+# Truth particles from the hard scatter vertex prior to Geant4 simulation.
+# Neutrinos and muons are omitted; all other stable particles are included.
+Truth = JetConstit(xAOD.Type.TruthParticle)
+
+# Truth particles from the hard scatter vertex prior to Geant4 simulation.
+# Prompt electrons, muons and neutrinos are excluded, all other stable particles
+# are included, in particular leptons and neutrinos from hadron decays.
+TruthWZ = JetConstit(xAOD.Type.TruthParticle,["NoWZ"])
+
+########################################################################
+# Typical jet algorithm definitions
+# Filter pts, ghost lists and modifier lists can be updated by the user,
+# though there is some risk of overwriting...
+from JetDefinition import JetDefinition
+
+# Standard small-radius (0.4) AntiKt jets
+AntiKt4LCTopo = JetDefinition("AntiKt",0.4,LCTopoOrigin)
+AntiKt4EMTopo = JetDefinition("AntiKt",0.4,EMTopoOrigin)
+AntiKt4EMPFlow = JetDefinition("AntiKt",0.4,CHSPFlow)
+
+# Standard large-radius (1.0) AntiKt ungroomed jets
+AntiKt10LCTopo = JetDefinition("AntiKt",1.0,LCTopoOrigin)
+AntiKt10LCTopoCSSK = JetDefinition("AntiKt",1.0,LCTopoCSSK)
+
+# Standard truth jets
+AntiKt4Truth = JetDefinition("AntiKt",0.4,Truth)
+AntiKt4TruthWZ = JetDefinition("AntiKt",0.4,TruthWZ)
+AntiKt10Truth = JetDefinition("AntiKt",1.0,Truth)
+AntiKt10TruthWZ = JetDefinition("AntiKt",1.0,TruthWZ)
diff --git a/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py b/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py
new file mode 100644
index 0000000000000000000000000000000000000000..eeaf1f00e57a238ad22d338232020798ae2f08a1
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/python/StandardJetMods.py
@@ -0,0 +1,105 @@
+from JetDefinition import JetModifier
+
+########################################################################
+# Define the dictionary of tool configurations using the helpers defined
+# in package configs.
+# This dict maps a modifier alias to the JetModifier config object
+# that in turn will be responsible for generating a configured tool.
+#
+# [Optional] Args to the JetModifier constructor are:
+#    1. Tool Type (ignored if the helper is a custom one)
+#    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
+jetmoddict = {}
+
+########################################################################
+# Define the simple modifier setups here -- those defined in JetRec.
+from JetRec import JetRecConf
+def getJetFilterTool(modspec):
+    threshold = int(modspec)
+    jetptfilter = JetRecConf.JetFilterTool("jetptfilter_{0}mev".format(threshold))
+    jetptfilter.PtMin = threshold
+    return jetptfilter
+jetrecmods = {
+    "Sort":   JetModifier("JetSorter","jetsort"),
+    "Filter": JetModifier("JetFilterTool","jetptfilter",helperfn=getJetFilterTool),
+}
+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
+# PackageName.PackageConfig (modules to be moved)
+
+# Calibration
+from JetCalibTools import JetCalibToolsConfig
+jetcalibmods = {
+    "Calib": JetModifier("JetCalibrationTool","jetcalib_jetcoll_calibseq",
+                         helperfn=JetCalibToolsConfig.getJetCalibToolFromString,
+                         prereqs=JetCalibToolsConfig.getJetCalibToolPrereqs,passJetDef=True)
+    }
+jetmoddict.update(jetcalibmods)
+
+# TBD:
+# All items below in principle will support decoration mode, rather
+# than only non-const modification. Mode of operation should be
+# determined by interface called from parent tool/alg.
+
+# Standard jet moments
+from JetMomentTools import JetMomentToolsConfig
+jetmomentmods = {
+    # Easy cases, no special config or prereqs, just default tool config
+    "CaloEnergies":    JetModifier("JetCaloEnergies", "jetens"),
+    "ClusterMoments":  JetModifier("JetClusterMomentsTool", "clsmoms"),
+    "LArHVCorr":       JetModifier("JetLArHVTool", "larhvcorr"),
+    "ECPSFrac":        JetModifier("JetECPSFractionTool", "ecpsfrac"),
+    "Width":           JetModifier("JetWidthTool", "width"),
+
+    # More complex cases here
+    "CaloQuality":     JetModifier("JetCaloQualityTool", "caloqual",
+                                   helperfn=JetMomentToolsConfig.getCaloQualityTool),
+    "ConstitFourMom":  JetModifier("JetConstitFourMomTool", "jetconstitfourmom_basename",
+                                   helperfn=JetMomentToolsConfig.getConstitFourMomTool,
+                                   passJetDef=True),
+    "JVF":             JetModifier("JetVertexFractionTool", "jvf",
+                                   helperfn=JetMomentToolsConfig.getJVFTool,
+                                   prereqs = ["mod:TrackSumMoments"] ),
+    "JVT":             JetModifier("JetVertexTaggerTool", "jvt",
+                                   prereqs = [ "mod:JVF" ]),
+    "OriginSetPV":     JetModifier("JetOriginCorrectionTool", "origin_setpv",
+                                   prereqs = [ "mod:JVF" ]),
+    "TrackMoments":    JetModifier("JetTrackMomentsTool", "trkmoms",
+                                   helperfn=JetMomentToolsConfig.getTrackMomentsTool,
+                                   prereqs = [ "input:JetSelectedTracks","input:JetTrackVtxAssoc","ghost:Track" ]),
+    "TrackSumMoments": JetModifier("JetTrackMomentsTool", "trksummoms",
+                                   helperfn=JetMomentToolsConfig.getTrackMomentsTool,
+                                   prereqs = [ "input:JetSelectedTracks","input:JetTrackVtxAssoc","ghost:Track" ]),
+    }
+jetmoddict.update(jetmomentmods)
+
+# Truth labelling moments
+from ParticleJetTools import ParticleJetToolsConfig
+particlejetmods = {
+    # Easy cases, no special config or prereqs, just default tool config
+    "PartonTruthLabel": JetModifier("Analysis__JetPartonTruthLabel","partontruthlabel",
+                                    prereqs=["ghost:TruthLabelPartons"]),
+
+    # More complex cases here
+    "TruthPartonDR":    JetModifier("Analysis__JetConeLabeling","truthpartondr",
+                                    helperfn=ParticleJetToolsConfig.getJetConeLabeling),
+    "JetDeltaRLabel":   JetModifier("ParticleJetDeltaRLabelTool","jetdrlabeler_jetptmin",
+                                    helperfn=ParticleJetToolsConfig.getJetDeltaRLabelTool,
+                                    prereqs=["input:TruthLabelBHadronsFinal",
+                                             "input:TruthLabelCHadronsFinal",
+                                             "input:TruthLabelTausFinal"])
+    }
+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
diff --git a/Reconstruction/Jet/JetRecConfig/python/__init__.py b/Reconstruction/Jet/JetRecConfig/python/__init__.py
index 74583d364ec2ca794156596c7254d9b234a940c6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/Reconstruction/Jet/JetRecConfig/python/__init__.py
+++ b/Reconstruction/Jet/JetRecConfig/python/__init__.py
@@ -1,2 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
diff --git a/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py b/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py
new file mode 100644
index 0000000000000000000000000000000000000000..5397dfba6a761cd2b70884914b0888a445cbfae0
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/share/JetRecTestCfg.py
@@ -0,0 +1,206 @@
+from JetRecConfig import JetRecConfig
+from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
+
+from pprint import pprint, pformat
+
+from AthenaCommon import Logging
+jetlog = Logging.logging.getLogger("testJetRecDeps")
+
+def JetRecTestCfg(configFlags,args):
+
+    jetlist = configFlags.JetRec.Definitions
+    if args.printDependencies:
+        for jetdef in jetlist:
+            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 jetlist:
+       jetcomps = JetRecConfig.JetRecCfg(jetdef,configFlags,jetnameprefix=configFlags.JetRec.Prefix)
+       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(args.verboseAccumulators,summariseProps=True)
+
+    return components
+
+def DefineJetCollections():
+
+    # Here we define the jet configurations we want to build
+    # These mod and ghost lists should go in a common module
+    standardrecomods = ["Width","TrackMoments","TrackSumMoments","JVF","JVT","OriginSetPV",
+                        "CaloEnergies","LArHVCorr"]
+    clustermods = ["ECPSFrac","ClusterMoments"]
+    truthmods = ["PartonTruthLabel","TruthPartonDR","JetDeltaRLabel:5000"]
+
+    from JetRecConfig.JetDefinition import JetGhost
+    ghostlist = ["Track","MuonSegment","Truth"]
+    standardghosts = [JetGhost(ghosttype) for ghosttype in ghostlist]
+    flavourghostlist = ["BHadronsInitial", "BHadronsFinal", "BQuarksFinal",
+                        "CHadronsInitial", "CHadronsFinal", "CQuarksFinal",
+                        "TausFinal",
+                        "WBosons", "ZBosons", "HBosons", "TQuarksFinal",
+                        "Partons",
+                        ]
+    flavourghosts = [JetGhost("TruthLabel"+ghosttype) for ghosttype in flavourghostlist]
+    standardghosts += flavourghosts
+
+    ########################################################################
+    # First a demonstration of just building jets using standard definitions
+    from JetRecConfig.StandardJetDefs import AntiKt4LCTopo, AntiKt4EMPFlow, AntiKt4Truth, AntiKt4TruthWZ
+
+    # This updates the original jet definitions, so might be a little risky
+    # in derivation code. Safer would be to always deepcopy into a local variable.
+    AntiKt4LCTopo.ptminfilter = 15e3
+    AntiKt4LCTopo.modifiers = ["Calib:T0:mc","Sort"] + standardrecomods + clustermods + truthmods
+    AntiKt4LCTopo.ghostdefs = standardghosts
+    #AntiKt4LCTopo.modifiers = ["Calib:AnalysisLatest:mc"]
+
+    AntiKt4EMPFlow.ptminfilter = 10e3
+    AntiKt4EMPFlow.modifiers = ["Calib:T0:mc","Sort"] + standardrecomods + truthmods
+    AntiKt4EMPFlow.ghostdefs = standardghosts
+    #AntiKt4EMPFlow.modifiers = ["Calib:AnalysisLatest:mc"]
+
+    from copy import deepcopy
+    AntiKt4Truth.ptminfilter = 2e3
+
+    AntiKt4TruthWZ.ptminfilter = 2e3
+
+    ########################################################################
+    # Now we define our own definitions
+    from JetRecConfig.JetDefinition import JetConstit, JetDefinition, xAOD
+    LCTopoCSSK = JetConstit(xAOD.Type.CaloCluster, ["LC","Origin","CS","SK"])
+    AntiKt4LCTopoCSSK = JetDefinition("AntiKt",0.4,LCTopoCSSK,ptmin=2e3,ptminfilter=2e3)
+    AntiKt4LCTopoCSSK.modifiers = ["ConstitFourMom"] + standardrecomods + clustermods + truthmods
+    AntiKt4LCTopoCSSK.ghostdefs = standardghosts
+
+    ########################################################################
+    # We can also copy and modify the standard ones
+    from copy import deepcopy
+    from JetRecConfig.StandardJetDefs import CHSPFlow
+
+    CSSKPFlow = deepcopy(CHSPFlow)
+    CSSKPFlow.modifiers = ["CS","SK"]
+    AntiKt4EMPFlowCSSK = deepcopy(AntiKt4EMPFlow)
+    AntiKt4EMPFlowCSSK.inputdef = CSSKPFlow
+    AntiKt4EMPFlowCSSK.modifiers = ["ConstitFourMom"] + standardrecomods + truthmods
+    AntiKt4EMPFlowCSSK.ptmin = 2e3
+    AntiKt4EMPFlowCSSK.ptminfilter = 2e3
+    AntiKt4EMPFlowCSSK.ghostdefs = standardghosts
+
+    jetdefs = [#AntiKt4Truth,
+               #AntiKt4TruthWZ,
+               AntiKt4LCTopo,
+               AntiKt4EMPFlow,
+               AntiKt4LCTopoCSSK,
+               AntiKt4EMPFlowCSSK]
+    return jetdefs
+
+if __name__=="__main__":
+    from argparse import ArgumentParser
+    parser = ArgumentParser(prog="JetRecTestCfg: An example configuration module for jet reconstruction",
+                            usage="Call with an input file, pass -n=0 to skip execution, -t 0 for serial or 1 for threaded execution.")
+    #
+    parser.add_argument("-H", "--Help", default=False, action="store_true", help="Evidently pyROOT interferes with help :(")
+    #
+    parser.add_argument("-f", "--filesIn", type=str, help="Comma-separated list of input files")
+    parser.add_argument("-M", "--msgLvl",   default="INFO", help="The message verbosity")
+    parser.add_argument("-n", "--nEvents",  default=0, type=int, help="The number of events to run. 0 skips execution")
+    #
+    parser.add_argument("-t", "--nThreads", default=1, type=int, help="The number of concurrent threads to run. 0 uses serial Athena.")
+    #
+    parser.add_argument("-D", "--dumpSG",   default=False, action="store_true", help="Toggle StoreGate dump on each event")
+    parser.add_argument("-d", "--printDependencies",   default=False, action="store_true", help="Print the dependency dicts for each jet collection")
+    parser.add_argument("-a", "--printAccumulators",   default=False, action="store_true", help="Print the component accumulators for each jet collection separately")
+    parser.add_argument("-V", "--verboseAccumulators", default=False, action="store_true", help="Print full details of the AlgSequence for each accumulator")
+    args = parser.parse_args()
+
+    if args.Help:
+        parser.print_help()
+        import sys
+        sys.exit(0)
+
+    # Setting needed for the ComponentAccumulator to do its thing
+    from AthenaCommon.Configurable import Configurable
+    Configurable.configurableRun3Behavior=True
+
+    # Set message levels
+    from AthenaCommon import Constants
+    msgLvl = getattr(Constants,args.msgLvl)
+    from AthenaCommon.Logging import log
+    log.setLevel(msgLvl)
+    
+    # Config flags steer the job at various levels
+    from AthenaConfiguration.AllConfigFlags import ConfigFlags
+    ConfigFlags.Input.isMC  = True
+    ConfigFlags.Input.Files = args.filesIn.split(",")
+
+    # Flags relating to multithreaded execution
+    ConfigFlags.Concurrency.NumThreads = args.nThreads
+    if args.nThreads>0:
+        ConfigFlags.Scheduler.ShowDataDeps = True
+        ConfigFlags.Scheduler.ShowDataFlow = True
+        ConfigFlags.Scheduler.ShowControlFlow = True
+        ConfigFlags.Concurrency.NumConcurrentEvents = args.nThreads
+
+    ########################################################################
+    # Define flags steering the jet reco config
+    jetdefs = DefineJetCollections()
+    ConfigFlags.addFlag("JetRec.Definitions",jetdefs)
+    ConfigFlags.addFlag("JetRec.Prefix","New")
+
+    # Prevent the flags from being modified
+    ConfigFlags.lock()
+
+    # Get a ComponentAccumulator setting up the fundamental Athena job
+    from AthenaConfiguration.MainServicesConfig import MainServicesThreadedCfg 
+    cfg=MainServicesThreadedCfg(ConfigFlags) 
+
+    # Add the components for reading in pool files
+    from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
+    cfg.merge(PoolReadCfg(ConfigFlags))
+
+    # Add the components from our jet reconstruction job
+    cfg.merge(JetRecTestCfg(ConfigFlags,args))
+
+    # # build eventinfo attribute list
+    # from OutputStreamAthenaPool.OutputStreamAthenaPoolConf import EventInfoAttListTool, EventInfoTagBuilder
+    # EventInfoTagBuilder = EventInfoTagBuilder(AttributeList="SimpleTag")
+    # cfg.addEventAlgo(EventInfoTagBuilder,"AthAlgSeq")
+    
+    # Write what we produced to AOD
+    # First define the output list
+    outputlist = []
+    originaljets = ["AntiKt4EMPFlowJets"]
+    for jetcoll in originaljets:
+        outputlist += ["xAOD::JetContainer#"+jetcoll,
+                       "xAOD::JetAuxContainer#"+jetcoll+"Aux."]
+    for jetdef in ConfigFlags.JetRec.Definitions:
+        key = "{0}{1}Jets".format(ConfigFlags.JetRec.Prefix,jetdef.basename)
+        outputlist += ["xAOD::JetContainer#"+key,
+                       "xAOD::JetAuxContainer#"+key+"Aux."]
+
+    # # Now get the output stream components
+    # from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
+    # cfg.merge(OutputStreamCfg(ConfigFlags,"xAOD",ItemList=outputlist))
+    # pprint( cfg.getEventAlgo("OutputStreamxAOD").ItemList )
+  
+    # Optionally, print the contents of the store every event
+    cfg.getService("StoreGateSvc").Dump = args.dumpSG
+
+    # Save this configuration to a pickle file
+    f=open("JetRecTest.pkl","w")
+    cfg.store(f)
+    f.close()
+
+    # Run the job
+    cfg.run(maxEvents=args.nEvents)
diff --git a/Reconstruction/Jet/JetRecConfig/share/JetRec_jobOptions.py b/Reconstruction/Jet/JetRecConfig/share/JetRec_jobOptions.py
deleted file mode 100644
index 297bbfd593f6e3a01c1f0a203334091da92fec34..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecConfig/share/JetRec_jobOptions.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# JetRec_jobOptions.py
-#
-# David Adams
-# February 2014
-#
-# RecExCommon job options for running jet reconstruction.
-#
-# Run with
-# > athena.py test_RunJetRec.py
-#
-
-myname = "JetRec_jobOptions: "
-print myname + "Begin."
-
-# Import the jet tool manager.
-from JetRecConfig.JetRecStandard import jtm
-
-#--------------------------------------------------------------
-# Define the finders and groomers.
-# Each line configures a finder or groomer and its associated jetrec tool.
-# The first argument is the name of the output collection and the jetrec tool.
-# The fifth argument is the list of modifiers.
-# Non-zero ghostArea enables calculation of active area.
-#--------------------------------------------------------------
-
-# Finders.
-from JetRecConfig.JetRecFlags import jetFlags
-if jetFlags.useTruth():
-  jtm.addJetFinder("AntiKt4TruthJets",    "AntiKt", 0.4,    "truth", ptmin= 5000)
-  jtm.addJetFinder("AntiKt4TruthWZJets",  "AntiKt", 0.4,  "truthwz", ptmin= 5000)
-  jtm.addJetFinder("AntiKt10TruthJets",   "AntiKt", 1.0,    "truth", ptmin=40000)
-  jtm.addJetFinder("AntiKt10TruthWZJets", "AntiKt", 1.0,  "truthwz", ptmin=40000)
-  jtm.addJetFinder("CamKt12TruthJets",     "CamKt", 1.2,    "truth", ptmin=40000)
-  jtm.addJetFinder("CamKt12TruthWZJets",   "CamKt", 1.2,  "truthwz", ptmin=40000)
-if jetFlags.useTracks():
-  jtm.addJetFinder("AntiKt2PV0TrackJets", "AntiKt", 0.2, "pv0track", ptmin= 2000)
-  jtm.addJetFinder("AntiKt3PV0TrackJets", "AntiKt", 0.3, "pv0track", ptmin= 2000)
-  jtm.addJetFinder("AntiKt4PV0TrackJets", "AntiKt", 0.4, "pv0track", ptmin= 2000)
-if jetFlags.useTopo():
-  jtm.addJetFinder("AntiKt4EMTopoJets",   "AntiKt", 0.4,   "emtopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter= 5000, calibOpt="aro")
-  jtm.addJetFinder("AntiKt4LCTopoJets",   "AntiKt", 0.4,   "lctopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter= 7000, calibOpt="aro")
-  jtm.addJetFinder("AntiKt10LCTopoJets",  "AntiKt", 1.0,   "lctopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter=50000, calibOpt="none")
-  jtm.addJetFinder("CamKt12LCTopoJets",    "CamKt", 1.2,   "lctopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter=50000, calibOpt="none")
-if jetFlags.usePFlow():
-  jtm.addJetFinder("AntiKt4EMPFlowJets",  "AntiKt", 0.4,  "empflow", "pflow", ghostArea=0.01, ptmin= 2000, ptminFilter= 5000, calibOpt="a:pflow")
-
-#--------------------------------------------------------------
-# Build output container list.
-#--------------------------------------------------------------
-
-# Both standard and aux container must be listed explicitly.
-# For release 19, the container version must be explicit.
-
-for jetrec in jtm.jetrecs:
-  jetFlags.jetAODList += [ "xAOD::JetContainer#" + jetrec.name() ]
-  auxprefix = ""
-  if jetrec.Trigger:
-    auxprefix = "Trig"
-  jetFlags.jetAODList += [ "xAOD::Jet" + auxprefix + "AuxContainer#" + jetrec.name() + "Aux." ]
-
-
-# For testing. These blocks should not be enabled in production.
-if jetFlags.debug > 0:
-  jetlog.info( "JetRec_jobOptions.py: Requested output stream: ")
-  jetlog.info( "%s", jetFlags.jetAODList )
-if jetFlags.debug > 1:
-  jetlog.info( "JetRec_jobOptions.py: Setting output level to DEBUG for all jetrecs")
-  for jetrec in jtm.jetrecs:
-    jtm.setOutputLevel(jetrec, DEBUG)
-
-#--------------------------------------------------------------
-# Add jet reco to algorithm sequence.
-#--------------------------------------------------------------
-from JetRecConfig.JetAlgorithm import addJetRecoToAlgSequence
-addJetRecoToAlgSequence()
-
-#--------------------------------------------------------------
-# save event shapes set with the JetAlgorithm
-#--------------------------------------------------------------
-for esTool in jtm.jetrun.EventShapeTools :
-    t = getattr(ToolSvc, esTool.getName() )
-    jetFlags.jetAODList += [ "xAOD::EventShape#"+t.OutputContainer,
-                             "xAOD::EventShapeAuxInfo#"+t.OutputContainer+'Aux.' ]
-
-print myname + "Begin."
diff --git a/Reconstruction/Jet/JetRecConfig/share/README.md b/Reconstruction/Jet/JetRecConfig/share/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..3a768c83199d87b5687f66bfc8e8e4287f13615c
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/share/README.md
@@ -0,0 +1,20 @@
+# JetRecConfig/share
+
+## JobOptions contents
+
+### JetRecTestCfg.py
+
+This module encodes an example/test job for jet reconstruction,
+which builds a small number of standard jet collections and writes
+them to an output xAOD file.
+
+Call `python JetRecTestCfg.py -H` for help.
+
+### test_JetDefinitions_properties.py
+
+This script tests whether jet definition properties correctly
+update all necessary information when they are altered by
+a user, for example when using a deepcopy-update pattern to
+construct new JetConstit or JetDefinition instances.
+
+Should be moved to a test/ dir and turned into a unit test.
diff --git a/Reconstruction/Jet/JetRecConfig/share/test_JetDefinitions_properties.py b/Reconstruction/Jet/JetRecConfig/share/test_JetDefinitions_properties.py
new file mode 100644
index 0000000000000000000000000000000000000000..b614b69554bd667cb5d043b6d3b04efd8a171030
--- /dev/null
+++ b/Reconstruction/Jet/JetRecConfig/share/test_JetDefinitions_properties.py
@@ -0,0 +1,58 @@
+# A test of the property setting/getting on JetDefinition classes
+# We want the defining attributes on each class to trigger resets of
+# derived attributes, such as container names, labels etc
+
+def printJetConstit(name, jetconstit):
+    print "{0} constituents".format(name)
+    print "    basetype:        {0}".format(jetconstit.basetype)
+    print "    modifiers list:  {0}".format(str(jetconstit.modifiers))
+    print "    label:           {0}".format(jetconstit.label)
+    print "    input container: {0}".format(jetconstit.inputname)
+    print ""
+
+def printJetDefinition(name, jetdef):
+    print "{0} jets".format(name)
+    print "    algorithm:      {0}".format(jetdef.algorithm)
+    print "    radius:         {0}".format(jetdef.radius)
+    print "    input label:    {0}".format(jetdef.inputdef.label)
+    print "    basename:       {0}".format(jetdef.basename)
+    print "    modifiers list: {0}".format(str(jetdef.modifiers))
+    print ""
+
+# Start with a basic constituent and print some information
+from JetRecConfig.JetDefinition import *
+CHSPFlow = JetConstit(xAOD.Type.ParticleFlow, [])
+printJetConstit("CHSPFlow",CHSPFlow)
+
+# Now copy and progressively change some of the aspects
+from copy import deepcopy
+CSSKPFlow = deepcopy(CHSPFlow)
+printJetConstit("CSSKPFlow (fresh copy from CHSPFlow)",CSSKPFlow)
+CSSKPFlow.modifiers += ["CS","SK"]
+printJetConstit("CSSKPFlow (set mods)",CSSKPFlow)
+
+CSSKLCTopo = deepcopy(CSSKPFlow)
+printJetConstit("CSSKLCTopo (fresh copy from CSSKPFlow)",CSSKLCTopo)
+CSSKLCTopo.basetype = xAOD.Type.CaloCluster
+printJetConstit("CSSKLCTopo (set input type)",CSSKLCTopo)
+
+# Now we do this with a basic jet definition
+AntiKt4EMPFlow = JetDefinition("AntiKt",0.4,CHSPFlow,ptminfilter=10e3)
+AntiKt4EMPFlow.modifiers = ["Calib:T0:mc","Sort"]
+printJetDefinition("AntiKt4EMPFlow",AntiKt4EMPFlow)
+
+AntiKt4EMPFlowCSSK = deepcopy(AntiKt4EMPFlow)
+printJetDefinition("AntiKt4EMPFlowCSSK (fresh copy from AntiKt4EMPFlow)",AntiKt4EMPFlowCSSK)
+AntiKt4EMPFlowCSSK.inputdef = CSSKPFlow
+AntiKt4EMPFlowCSSK.modifiers = ["JetConstitFourMomTool"]
+printJetDefinition("AntiKt4EMPFlowCSSK (update input def)",AntiKt4EMPFlowCSSK)
+
+AntiKt10EMPFlowCSSK = deepcopy(AntiKt4EMPFlowCSSK)
+printJetDefinition("AntiKt10EMPFlowCSSK (fresh copy from AntiKt4EMPFlowCSSK)",AntiKt10EMPFlowCSSK)
+AntiKt10EMPFlowCSSK.radius = 1.0
+printJetDefinition("AntiKt10EMPFlowCSSK (update radius)",AntiKt10EMPFlowCSSK)
+
+CamKt10EMPFlowCSSK = deepcopy(AntiKt10EMPFlowCSSK)
+printJetDefinition("CamKt10EMPFlowCSSK (fresh copy from AntiKt10EMPFlowCSSK)",CamKt10EMPFlowCSSK)
+CamKt10EMPFlowCSSK.algorithm = "CamKt"
+printJetDefinition("CamKt10EMPFlowCSSK (update radius)",CamKt10EMPFlowCSSK)
diff --git a/Reconstruction/Jet/JetRecTools/python/ConstitToolManager.py b/Reconstruction/Jet/JetRecTools/python/ConstitToolManager.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c7ce136c1fe80722e22f1405bb176a43027c17b
--- /dev/null
+++ b/Reconstruction/Jet/JetRecTools/python/ConstitToolManager.py
@@ -0,0 +1,135 @@
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+
+import os
+from AthenaCommon import Logging, CfgMgr
+
+
+# -----------------------------------
+# ConstitModifier
+# -----------------------------------
+class ConstituentToolManager(object):
+    """This class is modelled after JetToolManager.
+    It is intended to be a central place where to
+      * register constituent modifier tools
+      * map them to shortcut
+      * collect them in a mod sequencer tool
+    This class is provided standalone, but could be merged with JetToolManager if needed.
+
+    and example call could be :
+
+    clustModSeq = ctm.buildConstitModifSequence( 'JetWeightedTopoClusters',
+                                             inputName= 'CaloCalTopoClusters',
+                                             modList = [  'clust_weight'] )
+
+
+    """
+
+    # map of tool names or alias to tool instance
+    #  (there can be multiple entries pointing to the same instance) 
+    modifiersMap = dict()
+
+    # map of named standard list of modifiers
+    standardModifierLists = dict()
+
+    import ROOT
+    from ROOT import xAOD
+    xAOD.Type.ObjectType # Trigger dict load
+    # map of known input collections to their type
+    inputContainerMap = dict( CaloCalTopoClusters = xAOD.Type.CaloCluster, CaloTopoClusters = xAOD.Type.CaloCluster,
+                              EMOriginTopoClusters = xAOD.Type.CaloCluster, LCOriginTopoClusters = xAOD.Type.CaloCluster, 
+                              InDetTrackParticles = xAOD.Type.TrackParticle, JetETMiss = xAOD.Type.ParticleFlow )
+
+    log = Logging.logging.getLogger("ConstituentToolManager")
+
+    def add(self, tool, alias=None):
+        """Register a tool in the manager.  If alias is given, the tool is also registered under the alias key"""
+        name = tool.name()
+        if name in self.modifiersMap:
+            self.log.warning("Tool named "+name+" already registered. Not adding a new one")
+            return self.modifiersMap[name]
+        if alias is not None and alias in self.modifiersMap:
+            self.log.warning("Tool named "+alias+" already registered. Not adding a new one under this alias. Was "+name)            
+            return self.modifiersMap[alias]
+
+        from AthenaCommon.AppMgr import ToolSvc
+
+        self.modifiersMap[name] = tool
+        if alias: self.modifiersMap[alias] = tool
+        return tool
+
+    
+    def __iadd__(self, tool):
+        """Enables the += syntax to add tool """
+        self.add(tool)
+        return self
+
+    def buildConstitModifSequence(self, seqName, OutputContainer , InputContainer, modList, InputType=None):
+        """Returns a configured JetConstituentModSequence instance.
+        The tool is build according to
+           seqName (str)    : name of the JetConstituentModSequence tool
+           OutputContainer (str) : name of desired output constituents container (property of JetConstituentModSequence)
+           InputContainer  (str) : name of input constituents container (property of JetConstituentModSequence)
+           modList (str or list): if str, this is taken as a shortcut to a knonw, default list of modifier tools (from self.standardModifierLists)
+                                  if list, entries are eihter configured modifier tools either strings in which case they are shortcut to known modifier tool (in self.modifiersMap).
+          InputType : (int or None) the type of particles in the input container. If None attempt is made to guess it from InputContainer (from self.inputContainerMap).
+          
+        """
+        
+        #seqName = OutputContainer+'_modSeq'
+
+        # Deal with input -----------------
+        if InputType is None:
+            # get it from the known inputs
+            InputType = self.inputContainerMap[ InputContainer ]
+        if InputType is None:
+            self.log.error( seqName+'. Unknown input container : '+InputContainer )
+            return 
+
+        # deal with modifiers ---------------
+        if isinstance(modList, str):
+            modKey = modList
+            # translate into a known list :
+            modList = self.standardModifierLists.get( modKey , None)
+            if modList is None :
+                self.log.error( seqName+". Unknown shortcut for constit modifier list : "+modKey)
+                return None
+        # loop over modList
+        finalList = []
+        for t in modList:
+            if isinstance(t,str):
+                # translate into a real tool
+                tool = self.modifiersMap.get(t,None)
+                if tool is None:
+                    self.log.error( seqName+". Unknown shortcut for constit modifier list : "+t)
+                    return None
+                t = tool
+                t.InputType = InputType
+            # append to the final list
+            finalList.append( t )
+            
+        constModSeq = CfgMgr.JetConstituentModSequence( seqName, # the name of the tool 
+                                                        InputContainer = InputContainer,
+                                                        OutputContainer = OutputContainer,
+                                                        InputType = InputType,
+                                                        Modifiers = finalList, # pass the list of modifier we want 
+                                                        )
+        self += constModSeq
+        
+        return constModSeq
+
+
+# -----------------------------------
+# the main ConstituentToolManager instance
+ctm = ConstituentToolManager()
+# -----------------------------------
+    
+# -----------------------------------
+# add standard tools to ctm
+ctm.add( CfgMgr.SoftKillerWeightTool("JetConstit_SoftKiller", SKGridSize=0.6) ,
+         alias = 'softkiller' )
+
+ctm.add( CfgMgr.ClusterAtEMScaleTool("JetConstit_ClusEM") ,
+         alias = 'clus_emscale' )
+
+ctm.add( CfgMgr.CaloClusterConstituentsOrigin("JetConstit_ClusOrigin") ,
+         alias = 'clus_origin' )
diff --git a/Reconstruction/Jet/JetRecTools/python/DefaultTools.py b/Reconstruction/Jet/JetRecTools/python/DefaultTools.py
deleted file mode 100644
index e34be27b9704ac484115dba544284e90ed23f90d..0000000000000000000000000000000000000000
--- a/Reconstruction/Jet/JetRecTools/python/DefaultTools.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-
-def declareDefaultTools():
-  from JetRecConfig.JetRecFlags import jetFlags
-  from JetRecConfig.JetRecStandardToolManager import jtm
-  from JetRec.JetRecConf import PseudoJetGetter
-
-  #--------------------------------------------------------------
-  # Pseudojet builders.
-  #--------------------------------------------------------------
-
-  # Prepare a sequence of input constituent modifiers
-  from JetRecToolsConfig import ctm
-  jtm += ctm.buildConstitModifSequence( "JetConstitSeq_LCOrigin",
-                                        OutputContainer='LCOriginTopoClusters',
-                                        InputContainer= 'CaloCalTopoClusters',
-                                        modList = [  'clus_origin' ] )
-  
-  jtm += ctm.buildConstitModifSequence( "JetConstitSeq_EMOrigin",
-                                        OutputContainer='EMOriginTopoClusters',
-                                        InputContainer= 'CaloCalTopoClusters',                                      
-                                        modList = [ 'clus_emscale', 'clus_origin' ] )
-
-  jtm += PseudoJetGetter(
-    "lcoriginget",
-    InputContainer = jtm.JetConstitSeq_LCOrigin.OutputContainer,
-    Label = "LCTopoOrigin",
-    OutputContainer = jtm.JetConstitSeq_LCOrigin.OutputContainer+"PseudoJet",
-    SkipNegativeEnergy = True,
-    GhostScale = 0.0
-  )
-
-  jtm += PseudoJetGetter(
-    "emoriginget",
-    InputContainer = jtm.JetConstitSeq_EMOrigin.OutputContainer,
-    Label = "EMTopoOrigin",
-    OutputContainer = jtm.JetConstitSeq_EMOrigin.OutputContainer+"PseudoJet",
-    SkipNegativeEnergy = True,
-    GhostScale = 0.0
-  )
diff --git a/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py b/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py
index 05d7554f12265efd050c635ad023bf9aa88a842d..e52d62176e5b48898a104e35b8d9883dc0568b3a 100644
--- a/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py
+++ b/Reconstruction/Jet/JetRecTools/python/JetRecToolsConfig.py
@@ -1,166 +1,54 @@
-# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-
-import os
-from AthenaCommon import Logging, CfgMgr
-
-## # ------------------------------------------------
-## # Bad/Missing Cells list creation
-## jtm += MissingCellListTool("MissingCellListTool",
-##                            AddBadCells = True,
-##                            )
-## # ------------------------------------------------
-
-# Bad channel correction tools
-def badChanInputHistoHelper():
-    # keep it as a function for now : might be easier to deal with when
-    # root-only config will be needed.
-    # new setup for THistService    
-    dataPathList = os.environ[ 'DATAPATH' ].split(os.pathsep)
-    dataPathList.insert(0, os.curdir)
-    from AthenaCommon.Utils.unixtools import FindFile
-    RefFileName = FindFile( "JetBadChanCorrTool.root" ,dataPathList, os.R_OK )
- 
-
-    from AthenaCommon.AppMgr import ServiceMgr
-    if not hasattr(ServiceMgr, 'THistSvc'):
-        from GaudiSvc.GaudiSvcConf import THistSvc
-        ServiceMgr += THistSvc()
-    ServiceMgr.THistSvc.Input += ["JetBadChanCorrTool DATAFILE=\'%s\' OPT=\'READ\'" % RefFileName]
-    badChanInputHistoHelper.called = True
-
-
-    badChanInputHistoHelper()
-    from JetRec.JetRecStandard import jtm
-    jtm += CfgMgr.JetBadChanCorrTool("JetBadChanCorrTool", MissingCellMap="MissingCaloCellsMap")
-
-
-# -----------------------------------
-# ConstitModifier
-# -----------------------------------
-class ConstituentToolManager(object):
-    """This class is modelled after JetToolManager.
-    It is intended to be a central place where to
-      * register constituent modifier tools
-      * map them to shortcut
-      * collect them in a mod sequencer tool
-    This class is provided standalone, but could be merged with JetToolManager if needed.
-
-    and example call could be :
-
-    clustModSeq = ctm.buildConstitModifSequence( 'JetWeightedTopoClusters',
-                                             inputName= 'CaloCalTopoClusters',
-                                             modList = [  'clust_weight'] )
-
-
-    """
-
-    # map of tool names or alias to tool instance
-    #  (there can be multiple entries pointing to the same instance) 
-    modifiersMap = dict()
-
-    # map of named standard list of modifiers
-    standardModifierLists = dict()
-
-    import ROOT
-    from ROOT import xAOD
-    xAOD.Type.ObjectType # Trigger dict load
-    # map of known input collections to their type
-    inputContainerMap = dict( CaloCalTopoClusters = xAOD.Type.CaloCluster, CaloTopoClusters = xAOD.Type.CaloCluster,
-                              EMOriginTopoClusters = xAOD.Type.CaloCluster, LCOriginTopoClusters = xAOD.Type.CaloCluster, 
-                              InDetTrackParticles = xAOD.Type.TrackParticle, JetETMiss = xAOD.Type.ParticleFlow )
-
-    log = Logging.logging.getLogger("ConstituentToolManager")
-
-    def add(self, tool, alias=None):
-        """Register a tool in the manager.  If alias is given, the tool is also registered under the alias key"""
-        name = tool.name()
-        if name in self.modifiersMap:
-            self.log.warning("Tool named "+name+" already registered. Not adding a new one")
-            return self.modifiersMap[name]
-        if alias is not None and alias in self.modifiersMap:
-            self.log.warning("Tool named "+alias+" already registered. Not adding a new one under this alias. Was "+name)            
-            return self.modifiersMap[alias]
-
-        from AthenaCommon.AppMgr import ToolSvc
-
-        self.modifiersMap[name] = tool
-        if alias: self.modifiersMap[alias] = tool
-        return tool
-
-    
-    def __iadd__(self, tool):
-        """Enables the += syntax to add tool """
-        self.add(tool)
-        return self
-
-    def buildConstitModifSequence(self, seqName, OutputContainer , InputContainer, modList, InputType=None):
-        """Returns a configured JetConstituentModSequence instance.
-        The tool is build according to
-           seqName (str)    : name of the JetConstituentModSequence tool
-           OutputContainer (str) : name of desired output constituents container (property of JetConstituentModSequence)
-           InputContainer  (str) : name of input constituents container (property of JetConstituentModSequence)
-           modList (str or list): if str, this is taken as a shortcut to a knonw, default list of modifier tools (from self.standardModifierLists)
-                                  if list, entries are eihter configured modifier tools either strings in which case they are shortcut to known modifier tool (in self.modifiersMap).
-          InputType : (int or None) the type of particles in the input container. If None attempt is made to guess it from InputContainer (from self.inputContainerMap).
-          
-        """
-        
-        #seqName = OutputContainer+'_modSeq'
-
-        # Deal with input -----------------
-        if InputType is None:
-            # get it from the known inputs
-            InputType = self.inputContainerMap[ InputContainer ]
-        if InputType is None:
-            self.log.error( seqName+'. Unknown input container : '+InputContainer )
-            return 
-
-        # deal with modifiers ---------------
-        if isinstance(modList, str):
-            modKey = modList
-            # translate into a known list :
-            modList = self.standardModifierLists.get( modKey , None)
-            if modList is None :
-                self.log.error( seqName+". Unknown shortcut for constit modifier list : "+modKey)
-                return None
-        # loop over modList
-        finalList = []
-        for t in modList:
-            if isinstance(t,str):
-                # translate into a real tool
-                tool = self.modifiersMap.get(t,None)
-                if tool is None:
-                    self.log.error( seqName+". Unknown shortcut for constit modifier list : "+t)
-                    return None
-                t = tool
-                t.InputType = InputType
-            # append to the final list
-            finalList.append( t )
-            
-        constModSeq = CfgMgr.JetConstituentModSequence( seqName, # the name of the tool 
-                                                        InputContainer = InputContainer,
-                                                        OutputContainer = OutputContainer,
-                                                        InputType = InputType,
-                                                        Modifiers = finalList, # pass the list of modifier we want 
-                                                        )
-        self += constModSeq
-        
-        return constModSeq
-
-
-# -----------------------------------
-# the main ConstituentToolManager instance
-ctm = ConstituentToolManager()
-# -----------------------------------
-    
-# -----------------------------------
-# add standard tools to ctm
-ctm.add( CfgMgr.SoftKillerWeightTool("JetConstit_SoftKiller", SKGridSize=0.6) ,
-         alias = 'softkiller' )
-
-ctm.add( CfgMgr.ClusterAtEMScaleTool("JetConstit_ClusEM") ,
-         alias = 'clus_emscale' )
-
-ctm.add( CfgMgr.CaloClusterConstituentsOrigin("JetConstit_ClusOrigin") ,
-         alias = 'clus_origin' )
+# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+
+########################################################################
+#                                                                      #
+# JetModConfig: A helper module for configuring tools that support     #
+# jet reconstruction                                                   #
+# Author: TJ Khoo                                                      #
+#                                                                      #
+########################################################################
+
+from AthenaCommon import Logging
+jrtlog = Logging.logging.getLogger('JetRecToolsConfig')
+
+# Package configurable imports
+from InDetTrackSelectionTool import InDetTrackSelectionToolConf
+from TrackVertexAssociationTool import TrackVertexAssociationToolConf
+from JetRecTools import JetRecToolsConf
+
+# Could be made more configurable,
+# e.g. specify CutLevel via modspec
+def getTrackSelTool():
+    # Track selector needs its own hierarchical config getter in JetRecTools?
+    idtrackselloose = InDetTrackSelectionToolConf.InDet__InDetTrackSelectionTool(
+        "idtrackselloose",
+        CutLevel = "Loose",
+        minPt    = 500
+    )
+    jettrackselloose = JetRecToolsConf.JetTrackSelectionTool(
+        "jettrackselloose",
+        InputContainer  = "InDetTrackParticles",
+        OutputContainer = "JetSelectedTracks",
+        Selector        = idtrackselloose
+    )
+    return jettrackselloose
+
+# Could be made more configurable,
+# e.g. specify association type
+def getTrackVertexAssocTool():
+    # Track-vertex association
+    # In R21 and prior this was the "tight" tool, but that performed poorly
+    # In fact, keeping it "tight" in R21 was a mistake
+    # idtvassoc = getUniquePublicTool(algseq,"CP::LooseTrackVertexAssociationTool",
+    #     "idloosetvassoc")
+    idtvassoc = TrackVertexAssociationToolConf.CP__TightTrackVertexAssociationTool("idtighttvassoc")
+
+    jettvassoc = JetRecToolsConf.TrackVertexAssociationTool(
+        "jettvassoc",
+        TrackParticleContainer  = "InDetTrackParticles",
+        TrackVertexAssociation  = "JetTrackVtxAssoc",
+        VertexContainer         = "PrimaryVertices",
+        TrackVertexAssoTool     = idtvassoc,
+    )
+    return jettvassoc