From 4c84b681f9696dddc5d7f331a65407e33868a91a Mon Sep 17 00:00:00 2001
From: Teng Jian Khoo <teng.jian.khoo@cern.ch>
Date: Mon, 21 Nov 2016 15:20:48 +0100
Subject: [PATCH] 'DetectorEta updates, JetMomentTool fixes, simplify modifier
 lists and temp R21 jet calibration' (JetRec-03-01-00)

	* Updates to compute DetectorEta correctly, linked to JetMomentTool changes
	* Simplifying modifier lists
	* Tagging JetRec-03-01-00

2016-11-08 Joe Taenzer <joseph.taenzer@cern.ch>
	* Modified Mass Drop Tagger (mMDT) grooming tool, class def
	* mMDT grooming tool, source code
	* Added link to JetModifiedMassDrop class
	* Added JetModifiedMassDrop class
	* Added SymmetryMeasure and RecursionChoice enums, for python config
	* Added JetSoftDrop class
	* Tagging JetRec-03-00-99


Former-commit-id: cb1ba10e986d07b2e30bf180f4caf0428868090b
---
 .../Jet/JetRec/JetRec/JetModifiedMassDrop.h   |  88 +++++++++++
 .../Jet/JetRec/JetRec/selection.xml           |   4 +
 .../Jet/JetRec/Root/JetModifiedMassDrop.cxx   | 140 ++++++++++++++++++
 Reconstruction/Jet/JetRec/Root/LinkDef.h      |   2 +
 .../JetRec/python/JetRecCalibrationFinder.py  |   6 +-
 .../python/JetRecStandardToolManager.py       | 102 ++++++-------
 .../Jet/JetRec/python/JetRecStandardTools.py  |  45 +++++-
 .../Jet/JetRec/python/JetToolSupport.py       |   2 +-
 .../Jet/JetRec/share/JetRec_jobOptions.py     |  12 +-
 Reconstruction/Jet/JetRec/share/RunJetRec.py  |  19 +--
 .../Jet/JetRec/share/test_RunJetRec.py        |   6 +-
 11 files changed, 342 insertions(+), 84 deletions(-)
 create mode 100644 Reconstruction/Jet/JetRec/JetRec/JetModifiedMassDrop.h
 create mode 100644 Reconstruction/Jet/JetRec/Root/JetModifiedMassDrop.cxx

diff --git a/Reconstruction/Jet/JetRec/JetRec/JetModifiedMassDrop.h b/Reconstruction/Jet/JetRec/JetRec/JetModifiedMassDrop.h
new file mode 100644
index 00000000000..f32c5471a6c
--- /dev/null
+++ b/Reconstruction/Jet/JetRec/JetRec/JetModifiedMassDrop.h
@@ -0,0 +1,88 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// JetModifiedMassDrop.h
+
+#ifndef JetModifiedMassDrop_H
+#define JetModifiedMassDrop_H
+
+// Joe Taenzer
+// October 2016
+//
+// Tool to apply the modified mass drop tagger (mMDT) and groom jets by filtering with mMDT
+// mMDT is described in this paper: arXiv:1307.0007
+// See also: http://fastjet.hepforge.org/svn/contrib/contribs/RecursiveTools/tags/1.0.0/ModifiedMassDropTagger.hh       
+
+#include "AsgTools/AsgTool.h"
+#include "JetInterface/IJetGroomer.h"
+#include "JetInterface/IJetFromPseudojet.h"
+#include "AsgTools/ToolHandle.h"
+
+namespace JetRecGroomingParams{
+  enum SymmetryMeasure : int;
+  enum RecursionChoice : int;
+}
+
+
+class JetModifiedMassDrop
+: public asg::AsgTool,
+//  public fastjet::contrib::RecursiveSymmetryCutBase,
+  virtual public IJetGroomer {
+ASG_TOOL_CLASS(JetModifiedMassDrop, IJetGroomer)
+
+public:
+
+  // Equivalent enums to those defined in RecursiveSymmetryToolBase.hh
+  // Redefined here so they can be used in the python configuration
+  // See: http://fastjet.hepforge.org/svn/contrib/contribs/RecursiveTools/tags/1.0.0/RecursiveSymmetryCutBase.hh
+  /// an enum of the different (a)symmetry measures that can be used
+  enum SymmetryMeasure{scalar_z, ///< \f$ \min(p_{ti}, p_{tj})/(p_{ti} + p_{tj}) \f$
+                              vector_z, ///< \f$ \min(p_{ti}, p_{tj})/p_{t(i+j)} \f$
+                              y         ///  \f$ \min(p_{ti}^2,p_{tj}^2) \Delta R_{ij}^2 / m_{ij}^2 \f$
+                       
+  };
+
+  /// an enum for the options of how to choose which of two subjets to recurse into
+  enum RecursionChoice{larger_pt, ///< choose the subjet with larger \f$ p_t \f$
+                              larger_mt, ///< choose the subjet with larger \f$ m_t \equiv (m^2+p_t^2)^{\frac12}] \f$
+                              larger_m   ///  choose the subjet with larger mass (deprecated)
+  };
+
+  // Ctor.
+  JetModifiedMassDrop(std::string name);
+
+  // Dtor.
+  ~JetModifiedMassDrop();
+
+  // Initilization.
+  StatusCode initialize();
+
+  // Groom a jet and add result to a container.
+  int groom(const xAOD::Jet& jin, xAOD::JetContainer& jout) const;
+
+  // Dump to log.
+  void print() const;
+
+private:  // data
+
+  // Job options.
+  float m_zcut;                         // Cut on the symmetry measure
+  float m_mu;                           // Mass drop, mu = m_heavy/m_parent
+  bool m_doFilt;                        // Filter the jet after mass drop grooming
+  double m_filtR;                       // Filter radius to use
+  int m_filtNSub;                       // Number of subjets to keep in the filter
+
+  // Symmetry measure to use, either y or scalar_z, default is y
+  int m_sym;
+  // Recursion choice, larger_pt or larger_mt, default is larger_pt
+  int m_recursion;
+
+  JetRecGroomingParams::SymmetryMeasure test_sym;
+  JetRecGroomingParams::RecursionChoice test_rec;
+
+  ToolHandle<IJetFromPseudojet> m_bld;  // Tool to build jets.
+
+};
+
+#endif
diff --git a/Reconstruction/Jet/JetRec/JetRec/selection.xml b/Reconstruction/Jet/JetRec/JetRec/selection.xml
index 79949ac3bd7..4e1ed8885fe 100644
--- a/Reconstruction/Jet/JetRec/JetRec/selection.xml
+++ b/Reconstruction/Jet/JetRec/JetRec/selection.xml
@@ -17,6 +17,10 @@
 <class name="JetSplitter"/>
 <class name="JetToolRunner"/>
 <class name="JetTrimmer"/>
+<class name="JetSoftDrop"/>
+<class name="JetModifiedMassDrop"/>
+<enum name="JetModifiedMassDrop::SymmetryMeasure"/>
+<enum name="JetModifiedMassDrop::RecursionChoice"/>
 <class name="MuonSegmentPseudoJetGetter"/>
 <class name="PseudoJetGetter"/>
 <class name="PseudoJetGetterRegistry"/>
diff --git a/Reconstruction/Jet/JetRec/Root/JetModifiedMassDrop.cxx b/Reconstruction/Jet/JetRec/Root/JetModifiedMassDrop.cxx
new file mode 100644
index 00000000000..3d24308fb49
--- /dev/null
+++ b/Reconstruction/Jet/JetRec/Root/JetModifiedMassDrop.cxx
@@ -0,0 +1,140 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// JetModifiedMassDrop.cxx
+
+#include "JetRec/JetModifiedMassDrop.h"
+#include <iomanip>
+#include <algorithm>
+#include "fastjet/PseudoJet.hh"
+#include "fastjet/JetDefinition.hh"
+#include "fastjet/Selector.hh"
+#include "fastjet/tools/Filter.hh"
+#include "JetEDM/PseudoJetVector.h"
+
+#include "fastjet/ClusterSequence.hh"
+#include "fastjet/contrib/RecursiveSymmetryCutBase.hh"
+#include "fastjet/contrib/ModifiedMassDropTagger.hh"
+
+using std::setw;
+using fastjet::PseudoJet;
+using fastjet::contrib::RecursiveSymmetryCutBase;
+using xAOD::JetContainer;
+
+//**********************************************************************
+
+JetModifiedMassDrop::JetModifiedMassDrop(std::string name)
+: AsgTool(name), m_bld("") {
+  declareProperty("ZCut",            m_zcut = 0.1);
+  declareProperty("SymmetryMeasure", m_sym = scalar_z);
+  declareProperty("MassDrop",        m_mu = std::numeric_limits<double>::infinity() );
+  declareProperty("RecursionChoice", m_recursion = larger_pt);
+  declareProperty("doFilter",        m_doFilt = true);
+  declareProperty("FilterNsubjets",  m_filtNSub = 3);
+  declareProperty("FilterR",         m_filtR = 0.3);
+  declareProperty("JetBuilder",      m_bld);
+}
+
+//**********************************************************************
+
+JetModifiedMassDrop::~JetModifiedMassDrop() {
+}
+
+//**********************************************************************
+
+StatusCode JetModifiedMassDrop::initialize() {
+  if ( m_zcut < 0.0 || m_zcut > 10.0 ) {
+    ATH_MSG_WARNING("Invalid value for ZCut " << m_zcut);
+  }
+  if ( m_mu < 0.0 ) {
+    ATH_MSG_WARNING("Invalid value for MassDrop " << m_mu);
+  }
+  if ( m_sym != y && m_sym != scalar_z && m_sym != vector_z ) {
+    ATH_MSG_WARNING("Invalid value for SymmetryMeasure " << m_sym);
+    return StatusCode::FAILURE;
+  }
+  if ( m_recursion != larger_pt && m_recursion != larger_mt && m_recursion != larger_m ) {
+    ATH_MSG_WARNING("Invalid value for RecursionChoice " << m_recursion);
+    return StatusCode::FAILURE;
+  }
+  if ( m_bld.empty() ) {
+    ATH_MSG_ERROR("Unable to retrieve jet builder.");
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+//**********************************************************************
+
+int JetModifiedMassDrop::groom(const xAOD::Jet& jin, xAOD::JetContainer& jets) const {
+  if ( pseudojetRetriever() == nullptr ) {
+    ATH_MSG_WARNING("Pseudojet retriever is null.");
+    return 1;
+  }
+  const PseudoJet* ppjin = pseudojetRetriever()->pseudojet(jin);
+  if ( ppjin == 0 ) {
+    ATH_MSG_WARNING("Jet does not have a pseudojet.");
+    return 1;
+  }
+
+  ////////////////////////
+  //configure modified mass drop tagger tool
+  //http://fastjet.hepforge.org/svn/contrib/contribs/RecursiveTools/tags/1.0.0/ModifiedMassDropTagger.hh
+  ////////////////////////
+
+  // Could do this casting in the call to the ModifiedMassDropTagger constructor, doing it here for readability
+  RecursiveSymmetryCutBase::SymmetryMeasure sym       = static_cast<RecursiveSymmetryCutBase::SymmetryMeasure>(m_sym);
+  RecursiveSymmetryCutBase::RecursionChoice recursion = static_cast<RecursiveSymmetryCutBase::RecursionChoice>(m_recursion);
+
+  //create the modified mass drop tagger, apply it to the input pseudojet
+  fastjet::contrib::ModifiedMassDropTagger MMDT(m_zcut,sym,m_mu,recursion);
+  // Use grooming mode to avoid getting empty pseudojets
+  MMDT.set_grooming_mode();
+  PseudoJet pjMMDT = MMDT(*ppjin);
+  
+  bool didMMDT = pjMMDT.has_structure_of<fastjet::contrib::ModifiedMassDropTagger>();
+
+  // then filter the jet (useful for studies at moderate pt) if requested and if grooming succeeded
+  // with a dynamic Rfilt choice (as in arXiv:0802.2470)
+  PseudoJet filtpjMMDT = pjMMDT;
+  double Rfilt = m_filtR;
+  if ( m_doFilt && didMMDT ) {
+    Rfilt = std::min(m_filtR, pjMMDT.structure_of<fastjet::contrib::ModifiedMassDropTagger>().delta_R()*0.5);
+    fastjet::Filter filter(Rfilt, fastjet::SelectorNHardest(m_filtNSub));
+    filtpjMMDT = filter(pjMMDT);
+  }
+
+  int npMMDT = filtpjMMDT.pieces().size();
+  xAOD::Jet* pjet = m_bld->add(filtpjMMDT, jets, &jin);
+  //pjet->SetAttribute<int>("TransformType", xAOD::JetTransform::MMDT); // Possibly not needed
+  pjet->setAttribute("didMMDT", didMMDT);
+  pjet->setAttribute("ZCut", m_zcut);
+  pjet->setAttribute("mMDTSymmetryMeasure", m_sym);
+  pjet->setAttribute("mMDTRecursionChoice", m_recursion);
+  pjet->setAttribute("mMDTMu", m_mu);
+  pjet->setAttribute("FilterNSubjects", m_filtNSub);
+  pjet->setAttribute("FilterR", Rfilt);
+  pjet->setAttribute<int>("NmMDTSubjets", npMMDT);
+
+  ATH_MSG_DEBUG("Properties after softdrop:");
+  ATH_MSG_DEBUG("   ncon: " << pjMMDT.constituents().size() << "/"
+                            << ppjin->constituents().size());
+  ATH_MSG_DEBUG("   nsub: " << npMMDT);
+  if ( pjet == 0 ) {
+    ATH_MSG_ERROR("Unable to add jet to container");
+  } else {
+    ATH_MSG_DEBUG("Added jet to container.");
+  }
+  return 0;
+}
+
+//**********************************************************************
+
+void JetModifiedMassDrop::print() const {
+  //ATH_MSG_INFO("  Angular fraction min: " << m_zcut);
+  //ATH_MSG_INFO("  Angular exponent: " << m_beta);
+  ATH_MSG_INFO("  Jet builder: " << m_bld.name());
+}
+
+//**********************************************************************
diff --git a/Reconstruction/Jet/JetRec/Root/LinkDef.h b/Reconstruction/Jet/JetRec/Root/LinkDef.h
index 7e64b9a6e5f..4d836f93c45 100644
--- a/Reconstruction/Jet/JetRec/Root/LinkDef.h
+++ b/Reconstruction/Jet/JetRec/Root/LinkDef.h
@@ -21,6 +21,7 @@
 #include <JetRec/JetToolRunner.h>
 #include <JetRec/JetTrimmer.h>
 #include <JetRec/JetSoftDrop.h>
+#include <JetRec/JetModifiedMassDrop.h>
 #include <JetRec/MuonSegmentPseudoJetGetter.h>
 #include <JetRec/PseudoJetGetter.h>
 #include <JetRec/PseudoJetGetterRegistry.h>
@@ -53,6 +54,7 @@
 #pragma link C++ class JetToolRunner+;
 #pragma link C++ class JetTrimmer+;
 #pragma link C++ class JetSoftDrop+;
+#pragma link C++ class JetModifiedMassDrop+;
 #pragma link C++ class MuonSegmentPseudoJetGetter+;
 #pragma link C++ class PseudoJetGetter+;
 #pragma link C++ class PseudoJetGetterRegistry+;
diff --git a/Reconstruction/Jet/JetRec/python/JetRecCalibrationFinder.py b/Reconstruction/Jet/JetRec/python/JetRecCalibrationFinder.py
index 50ac18507f1..8d6319173e4 100644
--- a/Reconstruction/Jet/JetRec/python/JetRecCalibrationFinder.py
+++ b/Reconstruction/Jet/JetRec/python/JetRecCalibrationFinder.py
@@ -46,7 +46,7 @@ class JetRecCalibrationFinder:
     
   # Dictionary for calibration configurations.
   configDict = {
-    "reco"            : "JES_MC15cRecommendation_May2016.config",
+    "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",
@@ -117,7 +117,9 @@ class JetRecCalibrationFinder:
       evskey = evsprefix + evssuf
       jetlog.info( myname + "  Event shape key: " + evskey )
       # ...create the tool.
-      jtm += JetCalibrationTool(tname, JetCollection=jetdefn, ConfigFile=configfile, CalibSequence=fullseq, RhoKey=evskey)
+      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]
 
diff --git a/Reconstruction/Jet/JetRec/python/JetRecStandardToolManager.py b/Reconstruction/Jet/JetRec/python/JetRecStandardToolManager.py
index 3017084a6cf..aaf1ec63adc 100644
--- a/Reconstruction/Jet/JetRec/python/JetRecStandardToolManager.py
+++ b/Reconstruction/Jet/JetRec/python/JetRecStandardToolManager.py
@@ -10,7 +10,7 @@
 #
 # Usage:
 #   from JetRec.JetRecStandardToolManager import jtm
-#   jtm.addJetFinder("AntiKt4EMTopoJets", "AntiKt", 0.4, "em", "calib_topo_ungroomed")
+#   jtm.addJetFinder("AntiKt4EMTopoJets", "AntiKt", 0.4, "em", "calib_emtopo_ungroomed")
 #
 from AthenaCommon import Logging
 jetlog = Logging.logging.getLogger('JetRec_jobOptions')
@@ -191,26 +191,27 @@ track_ungroomed_modifiers = list(common_ungroomed_modifiers)
 if jetFlags.useTruth() and jtm.haveParticleJetTools:
   track_ungroomed_modifiers += [jtm.trackjetdrlabeler]
 
+# Modifiers for calibrated topo jets.
 # Modifiers for topo (and pflow) jets.
-topo_ungroomed_modifiers = ["jetfilter"]
-topo_ungroomed_modifiers += common_ungroomed_modifiers
-topo_ungroomed_modifiers += [jtm.jetens]
-topo_ungroomed_modifiers += [jtm.larhvcorr]
-topo_ungroomed_modifiers += [jtm.ecpsfrac]
+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():
-  topo_ungroomed_modifiers += [jtm.caloqual_cluster]
+  ungroomed_modifiers += [jtm.caloqual_cluster]
 if jetFlags.useTracks():
-  topo_ungroomed_modifiers += [jtm.jvf]
-  topo_ungroomed_modifiers += [jtm.jvt]
-  topo_ungroomed_modifiers += [jtm.trkmoms]
-  topo_ungroomed_modifiers += [jtm.trksummoms]
-  topo_ungroomed_modifiers += [jtm.charge]
-  topo_ungroomed_modifiers += ["trackassoc"]
-  topo_ungroomed_modifiers += [jtm.jetorigin_setpv]
+  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():
-  topo_ungroomed_modifiers += ["truthassoc"]
+  ungroomed_modifiers += ["truthassoc"]
   if jtm.haveParticleJetTools:
-    topo_ungroomed_modifiers += [jtm.jetdrlabeler]
+    ungroomed_modifiers += [jtm.jetdrlabeler]
 
 # Modifiers for groomed jets.
 groomed_modifiers = [ jtm.jetsorter,
@@ -225,10 +226,6 @@ groomed_modifiers = [ jtm.jetsorter,
                       jtm.encorr,
                       jtm.comshapes
                       ]
-
-
-# Modifiers for groomed topo jets.
-topo_groomed_modifiers = list(groomed_modifiers)
   
 # Function to filter out skipped tools.
 def filterout(skiptoolnames, tools):
@@ -250,79 +247,66 @@ def filterout(skiptoolnames, tools):
 
 # Modifiers for pflow jets.
 # Same as topo jets.
-pflow_ungroomed_modifiers = []
-pflow_ungroomed_modifiers += ["calib"]
-pflow_ungroomed_modifiers += topo_ungroomed_modifiers
-
 # 28may2015 - ecpsfrac is not yet working for pflow in xAOD.
-pflow_ungroomed_modifiers = filterout(["ecpsfrac"], pflow_ungroomed_modifiers)
+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.
-topo_ungroomed_modifiers += [jtm.clsmoms]
-topo_ungroomed_modifiers += [jtm.constfourmom]
+ungroomed_modifiers += [jtm.clsmoms]
 
 # Voronoi moments.
-#topo_ungroomed_modifiers += [jtm.voromoms]
-
-# Modifiers for calibrated topo jets.
-calib_topo_ungroomed_modifiers = []
-tmp_topo_ungroomed_modifiers = filterout(["jetens"], topo_ungroomed_modifiers)
-calib_topo_ungroomed_modifiers += [jtm.jetens, "calib", jtm.jetsorter]
-calib_topo_ungroomed_modifiers += tmp_topo_ungroomed_modifiers  
+#ungroomed_modifiers += [jtm.voromoms]
 
 # Add Btagging.
 btags = ["btag"]
 if jetFlags.useBTagging():
-  topo_ungroomed_modifiers += btags
-  calib_topo_ungroomed_modifiers += btags
+  ungroomed_modifiers += btags
 
-# EM only modifiers here
+# EM-only modifiers here
 emtopo_ungroomed_modifiers = []
-emtopo_ungroomed_modifiers += [jtm.constfourmom]
-emtopo_ungroomed_modifiers += topo_ungroomed_modifiers
+emtopo_ungroomed_modifiers += [jtm.constitfourmom_emtopo]
+emtopo_ungroomed_modifiers += ungroomed_modifiers
 
 # LC-only modifiers here
 lctopo_ungroomed_modifiers = []
-lctopo_ungroomed_modifiers += topo_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()) )
-  topo_ungroomed_modifiers        = filterout(jetFlags.skipTools(), topo_ungroomed_modifiers)
-  calib_topo_ungroomed_modifiers  = filterout(jetFlags.skipTools(), calib_topo_ungroomed_modifiers)
+  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)
-  topo_groomed_modifiers          = filterout(jetFlags.skipTools(), topo_groomed_modifiers)
-  groomed_modifiers               = filterout(jetFlags.skipTools(), groomed_modifiers)
-  pflow_ungroomed_modifiers       = filterout(jetFlags.skipTools(), pflow_ungroomed_modifiers)
+    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["topo_ungroomed"]        =       list(topo_ungroomed_modifiers)
-jtm.modifiersMap["calib_topo_ungroomed"]  = list(calib_topo_ungroomed_modifiers)
-jtm.modifiersMap["calib"]                 = list(calib_topo_ungroomed_modifiers)
+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)
 
-jtm.modifiersMap["pflow"]                 =      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["topo_groomed"]          =         list(topo_groomed_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["emtopo"]    = list(emtopo_ungroomed_modifiers)
-jtm.modifiersMap["lctopo"]    = list(lctopo_ungroomed_modifiers)
-jtm.modifiersMap["track"]     = list(track_ungroomed_modifiers)
-jtm.modifiersMap["ztrack"]    = list(track_ungroomed_modifiers)
-jtm.modifiersMap["pv0track"]  = list(track_ungroomed_modifiers)
+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)
+  jtm.modifiersMap["truth"]               = list(truth_ungroomed_modifiers)
+  jtm.modifiersMap["truthwz"]             = list(truth_ungroomed_modifiers)
 
 jetlog.info( myname + "End." )
diff --git a/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py b/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py
index 1d288854f91..19075089be3 100644
--- a/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py
+++ b/Reconstruction/Jet/JetRec/python/JetRecStandardTools.py
@@ -362,7 +362,7 @@ jtm += PFlowPseudoJetGetter(
   Label = "LCPFlow",
   OutputContainer = "PseudoJetLCPFlow",
   RetrievePFOTool = jtm.pflowretriever,
-  WeightPFOTool = jtm.pflowweighter,
+  WeightPFOTool = jtm.pflowweighter_LC,
   InputIsEM = False,
   CalibratePFO = False,
   SkipNegativeEnergy = True,
@@ -527,7 +527,7 @@ if jtm.haveJetCaloCellQualityTool:
   )
 
 # Jet width.
-jtm += JetWidthTool("width")
+jtm += JetWidthTool("width", WeightPFOToolEM=jtm.pflowweighter, WeightPFOToolLC=jtm.pflowweighter_LC)
 
 # Calo layer energies.
 jtm += JetCaloEnergies("jetens")
@@ -699,8 +699,47 @@ jtm += JetOriginCorrectionTool(
   OnlyAssignPV = True,
 )
 
+# Load the xAODCaloEvent dictionary for cluster scale enum
+import cppyy
+try: cppyy.loadDictionary('xAODCaloEventDict')
+except: pass
+from ROOT import xAOD
+# Touch an unrelated class so the dictionary is loaded
+# and therefore the CaloCluster version typedef is recognised
+xAOD.CaloVertexedTopoCluster
+
+### 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 = [xAOD.CaloCluster.CALIBRATED],
+  AltJetScales = [""]
+  )
+
+jtm += JetConstitFourMomTool(
+  "constitfourmom_emtopo",
+  JetScaleNames = ["DetectorEtaPhi","JetLCScaleMomentum"],
+  AltConstitColls = ["CaloCalTopoClusters","LCOriginTopoClusters" if jetFlags.useTracks() else "CaloCalTopoClusters"],
+  AltConstitScales = [xAOD.CaloCluster.UNCALIBRATED,xAOD.CaloCluster.CALIBRATED],
+  AltJetScales = ["",""]
+  )
+
 jtm += JetConstitFourMomTool(
-  "constfourmom"
+  "constitfourmom_pflow",
+  JetScaleNames = ["DetectorEtaPhi"],
+  AltConstitColls = [""],
+  AltConstitScales = [0],
+  AltJetScales = ["JetConstitScaleMomentum"]
   )
 
 #--------------------------------------------------------------
diff --git a/Reconstruction/Jet/JetRec/python/JetToolSupport.py b/Reconstruction/Jet/JetRec/python/JetToolSupport.py
index 3ffcb8b6af4..812fb324c36 100644
--- a/Reconstruction/Jet/JetRec/python/JetToolSupport.py
+++ b/Reconstruction/Jet/JetRec/python/JetToolSupport.py
@@ -191,7 +191,7 @@ class JetToolManager:
         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"
+      # truthassoc - Does truth jet association replacing the input name with "Truth"
       elif mod == "truthassoc":
         sinp = getters[0].Label.split("Origin")[0]
         salg = finder.JetAlgorithm
diff --git a/Reconstruction/Jet/JetRec/share/JetRec_jobOptions.py b/Reconstruction/Jet/JetRec/share/JetRec_jobOptions.py
index dc8ff13debe..b9e27391cf4 100644
--- a/Reconstruction/Jet/JetRec/share/JetRec_jobOptions.py
+++ b/Reconstruction/Jet/JetRec/share/JetRec_jobOptions.py
@@ -43,12 +43,12 @@ if not jetFlags.useVertices():
   calibopt = "a"
   jetlog.info(myname + "No vertices -- switch calibopt to " + calibopt)
 if jetFlags.useTopo():
-  jtm.addJetFinder("AntiKt4EMTopoJets",   "AntiKt", 0.4,   "emtopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter= 5000, calibOpt=calibopt)
-  jtm.addJetFinder("AntiKt4LCTopoJets",   "AntiKt", 0.4,   "lctopo", "calib", ghostArea=0.01, ptmin= 2000, ptminFilter= 7000, calibOpt=calibopt)
-  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")
+  jtm.addJetFinder("AntiKt4EMTopoJets",   "AntiKt", 0.4,   "emtopo", "emtopo_ungroomed", ghostArea=0.01, ptmin= 2000, ptminFilter= 5000, calibOpt=calibopt)
+  jtm.addJetFinder("AntiKt4LCTopoJets",   "AntiKt", 0.4,   "lctopo", "lctopo_ungroomed", ghostArea=0.01, ptmin= 2000, ptminFilter= 7000, calibOpt=calibopt)
+  jtm.addJetFinder("AntiKt10LCTopoJets",  "AntiKt", 1.0,   "lctopo", "lctopo_ungroomed", ghostArea=0.01, ptmin= 2000, ptminFilter=50000, calibOpt="none")
+#  jtm.addJetFinder("CamKt12LCTopoJets",    "CamKt", 1.2,   "lctopo", "calib", ghostArea=0.01, ptmin= 5000, ptminFilter=50000, calibOpt="none")
 if jetFlags.usePFlow():
-  jtm.addJetFinder("AntiKt4EMPFlowJets",  "AntiKt", 0.4,  "empflow", "pflow", ghostArea=0.01, ptmin= 2000, ptminFilter= 5000, calibOpt=calibopt+":pflow")
+  jtm.addJetFinder("AntiKt4EMPFlowJets",  "AntiKt", 0.4,   "empflow", "pflow_ungroomed", ghostArea=0.01, ptmin= 2000, ptminFilter= 5000, calibOpt=calibopt+":pflow")
 
 #--------------------------------------------------------------
 # Build output container list.
@@ -68,8 +68,6 @@ if jetFlags.useTracks() and jetFlags.useTopo():
     jetFlags.jetAODList += [ "xAOD::CaloClusterContainer#EMOriginTopoClusters" , "xAOD::CaloClusterContainer#LCOriginTopoClusters" ,
                              "xAOD::ShallowAuxContainer#LCOriginTopoClustersAux.", "xAOD::ShallowAuxContainer#EMOriginTopoClustersAux."] 
 
-
-
 # For testing. These blocks should not be enabled in production.
 if jetFlags.debug > 0:
   jetlog.info( myname + "Requested output stream: ")
diff --git a/Reconstruction/Jet/JetRec/share/RunJetRec.py b/Reconstruction/Jet/JetRec/share/RunJetRec.py
index cfce3604b64..8d28fed2348 100644
--- a/Reconstruction/Jet/JetRec/share/RunJetRec.py
+++ b/Reconstruction/Jet/JetRec/share/RunJetRec.py
@@ -33,11 +33,11 @@ useDRTruthFlavor = jetFlags.useTruth
 #--------------------------------------------------------------
 
 # Update the modifier lists.
-if useLArHVCorr:
-  jtm.modifiersMap["calib"] += [jtm.larhvcorr]
-jtm.modifiersMap["mycalib"] = jtm.modifiersMap["calib"]
-if jtm.haveShowerDeconstructionTool:
-  jtm.modifiersMap["mycalib"]
+# if useLArHVCorr:
+#   jtm.modifiersMap["calib"] += [jtm.larhvcorr]
+# jtm.modifiersMap["mycalib"] = jtm.modifiersMap["calib"]
+# if jtm.haveShowerDeconstructionTool:
+#   jtm.modifiersMap["mycalib"]
 
 # Finders.
 # Calibration for topo jets: calibOpt =
@@ -62,10 +62,11 @@ if jetFlags.useTracks:
   jtm.addJetFinder("Run2AntiKt4TrackJets",    "AntiKt", 0.4,    "track", ghostArea=gatrack, ptmin= 2000)
   jtm.addJetFinder("Run2AntiKt4ZTrackJets",   "AntiKt", 0.4,   "ztrack", ghostArea=gatrack, ptmin= 2000)
   jtm.addJetFinder("Run2AntiKt4PV0TrackJets", "AntiKt", 0.4, "pv0track", ghostArea=gatrack, ptmin= 2000)
-jtm.addJetFinder(  "Run2AntiKt4EMTopoJets",   "AntiKt", 0.4,   "emtopo", "mycalib", ptmin=2000, ptminFilter= 5000, ghostArea=gatopo, calibOpt="ar")
-jtm.addJetFinder(  "Run2AntiKt4LCTopoJets",   "AntiKt", 0.4,   "lctopo", "mycalib", ptmin=2000, ptminFilter= 7000, ghostArea=gatopo, calibOpt="ar")
-jtm.addJetFinder(  "Run2AntiKt10LCTopoJets",  "AntiKt", 1.0,   "lctopo", "mycalib", ptmin=2000, ptminFilter=50000, ghostArea=gatopo, calibOpt="a")
-jtm.addJetFinder(  "Run2CamKt12LCTopoJets",    "CamKt", 1.2,   "lctopo", "mycalib", ptmin=2000, ptminFilter=50000, ghostArea=gatopo, calibOpt="a")
+jtm.addJetFinder(  "Run2AntiKt4EMTopoJets",   "AntiKt", 0.4,   "emtopo", "emtopo_ungroomed", ptmin=2000, ptminFilter= 5000, ghostArea=gatopo, calibOpt="ar")
+jtm.addJetFinder(  "Run2AntiKt4LCTopoJets",   "AntiKt", 0.4,   "lctopo", "lctopo_ungroomed", ptmin=2000, ptminFilter= 7000, ghostArea=gatopo, calibOpt="ar")
+jtm.addJetFinder(  "Run2AntiKt4EMPFlowJets",  "AntiKt", 0.4,  "empflow", "pflow_ungroomed",  ptmin=2000, ptminFilter= 5000, ghostArea=gatopo, calibOpt="ar:pflow")
+jtm.addJetFinder(  "Run2AntiKt10LCTopoJets",  "AntiKt", 1.0,   "lctopo", "lctopo_ungroomed", ptmin=2000, ptminFilter=50000, ghostArea=gatopo, calibOpt="none")
+jtm.addJetFinder(  "Run2CamKt12LCTopoJets",    "CamKt", 1.2,   "lctopo", "lctopo_ungroomed", ptmin=2000, ptminFilter=50000, ghostArea=gatopo, calibOpt="none")
 
 # Groomers.
 if runJetGrooming:
diff --git a/Reconstruction/Jet/JetRec/share/test_RunJetRec.py b/Reconstruction/Jet/JetRec/share/test_RunJetRec.py
index fd975b1779f..0bfdbbfa6fc 100644
--- a/Reconstruction/Jet/JetRec/share/test_RunJetRec.py
+++ b/Reconstruction/Jet/JetRec/share/test_RunJetRec.py
@@ -110,11 +110,11 @@ if len(vertexCollectionName):
   jtm.tvassoc.VertexContainer = vertexCollectionName
   jtm.tvassoc.lock()
 
-if 0:
+if 1:
   print myname + "Setting output level to VERBOSE for all jetrecs"
   for jetrec in jtm.jetrecs:
     jtm.setOutputLevel(jetrec, VERBOSE)
-elif 0:
+elif 1:
   print myname + "Setting output level to DEBUG for all jetrecs"
   for jetrec in jtm.jetrecs:
     jtm.setOutputLevel(jetrec, DEBUG)
@@ -242,7 +242,7 @@ for name in names:
   jdmp.MaxObject = 20
   jdmp.IntMoments = ["AlgorithmType", "InputType"]
   jdmp.IntMoments += ["ConstituentScale"]
-  if isTopo:
+  if isTopo and isAntiKt4:
     jdmp.IntMoments += ["OriginCorrected"]
     jdmp.IntMoments += ["PileupCorrected"]
   if jetFlags.useMuonSegments() and isTopo:
-- 
GitLab