From 2c733f62c0d6860d1346afe230ded88afe4d4494 Mon Sep 17 00:00:00 2001
From: William Axel Leight <william.axel.leight@cern.ch>
Date: Thu, 3 Dec 2020 14:37:47 +0000
Subject: [PATCH] Move the TruthCategoriesDecorator to release 22

This tool runs during derivation and adds Higgs STXS truth information to the AOD.
To run it requires the TruthConverters package that was not yet in the release.
Additionally I had to make a couple of modifications to the HiggsTruthCategoryTool which is only used by this tool.
I was able to successfully run on a Higgs AOD with this enabled as part of PHYS and the results looked reasonable.
---
 .../GenInterfaces/IHiggsTruthCategoryTool.h   |   2 +-
 .../GenInterfaces/IxAODtoHepMCTool.h          |  46 +++
 Generators/TruthConverters/CMakeLists.txt     |  22 ++
 .../TruthConverters/Root/xAODtoHepMCTool.cxx  | 286 ++++++++++++++++++
 .../TruthConverters/selection.xml             |   5 +
 .../TruthConverters/xAODtoHepMCDict.h         |  11 +
 .../TruthConverters/xAODtoHepMCTool.h         |  55 ++++
 .../components/TruthConverters_entries.cxx    |   4 +
 .../Root/HiggsTruthCategoryTool.cxx           |  10 +-
 .../TruthRivetTools/HiggsTruthCategoryTool.h  |   4 +-
 .../DerivationFrameworkHiggs/CMakeLists.txt   |   4 +-
 .../TruthCategoriesDecorator.h                |  87 ++++++
 .../python/TruthCategories.py                 |  15 +
 .../share/HiggsMCsamples.cfg                  | 267 ++++++++++++++++
 .../src/TruthCategoriesDecorator.cxx          | 285 +++++++++++++++++
 .../DerivationFrameworkHiggs_entries.cxx      |   2 +
 16 files changed, 1096 insertions(+), 9 deletions(-)
 create mode 100644 Generators/GenInterfaces/GenInterfaces/IxAODtoHepMCTool.h
 create mode 100644 Generators/TruthConverters/CMakeLists.txt
 create mode 100644 Generators/TruthConverters/Root/xAODtoHepMCTool.cxx
 create mode 100644 Generators/TruthConverters/TruthConverters/selection.xml
 create mode 100644 Generators/TruthConverters/TruthConverters/xAODtoHepMCDict.h
 create mode 100644 Generators/TruthConverters/TruthConverters/xAODtoHepMCTool.h
 create mode 100644 Generators/TruthConverters/src/components/TruthConverters_entries.cxx
 create mode 100644 PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/DerivationFrameworkHiggs/TruthCategoriesDecorator.h
 create mode 100644 PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/python/TruthCategories.py
 create mode 100644 PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/share/HiggsMCsamples.cfg
 create mode 100644 PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/src/TruthCategoriesDecorator.cxx

diff --git a/Generators/GenInterfaces/GenInterfaces/IHiggsTruthCategoryTool.h b/Generators/GenInterfaces/GenInterfaces/IHiggsTruthCategoryTool.h
index 9220b3f0ea18..dd8b1e0de73c 100644
--- a/Generators/GenInterfaces/GenInterfaces/IHiggsTruthCategoryTool.h
+++ b/Generators/GenInterfaces/GenInterfaces/IHiggsTruthCategoryTool.h
@@ -25,7 +25,7 @@ class IHiggsTruthCategoryTool : public virtual asg::IAsgTool {
  public:
   virtual StatusCode initialize() = 0;
   virtual StatusCode finalize () = 0;  
-  virtual HTXS::HiggsClassification* getHiggsTruthCategoryObject(const HepMC::GenEvent& HepMCEvent, const HTXS::HiggsProdMode prodMode)=0;
+  virtual HTXS::HiggsClassification* getHiggsTruthCategoryObject(const HepMC::GenEvent& HepMCEvent, const HTXS::HiggsProdMode prodMode) const =0;
 };
 
 #endif //> !GENINTERFACES_IHIGGSTRUTHCATEGORYTOOL_H
diff --git a/Generators/GenInterfaces/GenInterfaces/IxAODtoHepMCTool.h b/Generators/GenInterfaces/GenInterfaces/IxAODtoHepMCTool.h
new file mode 100644
index 000000000000..2045eee2f551
--- /dev/null
+++ b/Generators/GenInterfaces/GenInterfaces/IxAODtoHepMCTool.h
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * dual-use tool for converting xAOD truth events back to HepMC
+ * Principal Authors (responsible for the core conversion algorithm): Josh McFayden and James Catmore
+ * Tool Author: Jim Lacey (Carleton University) 
+ * ... updated tool interface to be dual-use
+ * ... added missing PDF information and requirements to allow running on full sim (remove Geant4 secondaries)
+ * <james.lacey@cern.ch,jlacey@physics.carleton.ca>
+ * <dag.gillberg@cern.ch>
+ */
+
+#ifndef GENINTERFACES_IXAODTOHEPMCTOOL_H
+#define GENINTERFACES_IXAODTOHEPMCTOOL_H 1
+
+#include "AsgTools/IAsgTool.h"
+
+
+// STL includes
+#include <string>
+#include <map>
+
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODTruth/TruthEventContainer.h"
+
+#include "HepMC/GenEvent.h"
+
+namespace HepMC {
+  class GenEvent;
+  class GenParticle;
+  class GenVertex;
+}
+
+class IxAODtoHepMCTool : public virtual asg::IAsgTool {
+ public:
+  ASG_TOOL_INTERFACE( IxAODtoHepMCTool )  
+    virtual ~  IxAODtoHepMCTool () { };
+ public:
+  virtual StatusCode initialize() = 0;
+  virtual StatusCode finalize () = 0;
+  virtual std::vector<HepMC::GenEvent> getHepMCEvents(const xAOD::TruthEventContainer* xTruthEventContainer, const xAOD::EventInfo* eventInfo) const = 0;
+};
+
+#endif //> !GENINTERFACES_IXAODTOHEPMCTOOL_H
diff --git a/Generators/TruthConverters/CMakeLists.txt b/Generators/TruthConverters/CMakeLists.txt
new file mode 100644
index 000000000000..76b8dd3277a7
--- /dev/null
+++ b/Generators/TruthConverters/CMakeLists.txt
@@ -0,0 +1,22 @@
+# $Id: CMakeLists.txt 769086 2016-08-22 12:03:50Z krasznaa $
+################################################################################
+# Package: TruthConverters
+################################################################################
+
+# Set the name of the package:
+atlas_subdir( TruthConverters )
+
+# External(s) needed by the package:
+find_package( HepMC )
+
+# Component(s) in the package:
+atlas_add_library( TruthConvertersLib
+   TruthConverters/*.h Root/*.cxx
+   SHARED
+	PUBLIC_HEADERS TruthConverters
+	INCLUDE_DIRS ${HEPMC_INCLUDE_DIRS}
+	LINK_LIBRARIES ${HEPMC_LIBRARIES} AsgTools xAODEventInfo xAODTruth GenInterfacesLib )
+
+atlas_add_component( TruthConverters 
+	src/components/*.cxx
+	LINK_LIBRARIES TruthConvertersLib GaudiKernel GenInterfacesLib )
diff --git a/Generators/TruthConverters/Root/xAODtoHepMCTool.cxx b/Generators/TruthConverters/Root/xAODtoHepMCTool.cxx
new file mode 100644
index 000000000000..29972fe36750
--- /dev/null
+++ b/Generators/TruthConverters/Root/xAODtoHepMCTool.cxx
@@ -0,0 +1,286 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "TruthConverters/xAODtoHepMCTool.h"
+
+xAODtoHepMCTool::xAODtoHepMCTool( const std::string& name ) 
+  : asg::AsgTool( name ),
+  m_momFac(1.), //<-- MeV/GeV conversion factor
+  m_lenFac(1.), //<-- length conversion factor
+  m_signalOnly(true),
+  m_maxCount(0)
+{
+}
+
+
+StatusCode xAODtoHepMCTool::initialize() {
+  ATH_MSG_INFO ("Initializing xAODtoHepMCTool "<< name() << "...");
+  ATH_MSG_INFO ("SignalOnly         = " << m_signalOnly);
+  m_evtCount   = 0;
+  m_badSuggest = 0;
+  m_noProdVtx  = 0;
+  m_badBeams   = 0;
+  return StatusCode::SUCCESS;
+}
+
+
+
+StatusCode xAODtoHepMCTool :: finalize ()
+{
+  ATH_MSG_INFO ("==============================================================");
+  ATH_MSG_INFO ("==========    xAOD -> HepMC Tool :: Run Summary     ==========");
+  ATH_MSG_INFO ("==============================================================");
+  if( m_badSuggest ){
+    ATH_MSG_INFO ("Number of suggest_barcode failures = " << m_badSuggest);
+    ATH_MSG_INFO (" ... check input particle/vertex barcodes.");
+  } else {
+    ATH_MSG_INFO ("No suggest_barcode failures");
+  }
+  if ( m_noProdVtx ) {
+    ATH_MSG_INFO ("Number of events that have a missing production vertex = " << m_noProdVtx);
+  }else{
+    ATH_MSG_INFO ("No missing production vertices");
+  }
+  if ( m_badBeams ){
+    ATH_MSG_INFO ("Number events with improperly defined beamparticles = " << m_badBeams);
+    ATH_MSG_INFO ("Inconsistencies with the beam particles storage in the event record!");
+    ATH_MSG_INFO ("... check xAOD::TruthEvent record ...");
+  }else{
+    ATH_MSG_INFO ("No events with undefined beams.");
+  }
+  ATH_MSG_INFO ("==============================================================");
+  ATH_MSG_INFO ("===================    End Run Summary     ===================");
+  ATH_MSG_INFO ("==============================================================");
+  return StatusCode::SUCCESS;
+}
+
+std::vector<HepMC::GenEvent> xAODtoHepMCTool :: getHepMCEvents(const xAOD::TruthEventContainer* xTruthEventContainer, const xAOD::EventInfo* eventInfo) const
+{
+  ++m_evtCount;
+  bool doPrint = m_evtCount < m_maxCount;
+  // CREATE HEPMC EVENT COLLECTION
+  std::vector<HepMC::GenEvent> mcEventCollection;
+  // Loop over xAOD truth container
+  // Signal event is always first, followed by pileup events
+  ATH_MSG_DEBUG("Start event loop");
+  for (const xAOD::TruthEvent* xAODEvent : *xTruthEventContainer) {
+    if( doPrint ) ATH_MSG_DEBUG("XXX Printing xAOD Event");
+    if( doPrint ) printxAODEvent( xAODEvent,eventInfo );
+    // Create GenEvent for each xAOD truth event
+    ATH_MSG_DEBUG("Create new GenEvent");
+    HepMC::GenEvent hepmcEvent = createHepMCEvent(xAODEvent,eventInfo);
+    // Insert into McEventCollection
+    mcEventCollection.push_back(hepmcEvent);    
+    if( doPrint ) ATH_MSG_DEBUG("XXX Printing HepMC Event");
+    if( doPrint ) hepmcEvent.print();
+    // Quit if signal only
+    if( m_signalOnly ) break;
+  }  
+  return mcEventCollection;
+}
+
+
+HepMC::GenEvent xAODtoHepMCTool::createHepMCEvent(const xAOD::TruthEvent* xEvt, const xAOD::EventInfo* eventInfo) const {
+  
+  ///EVENT LEVEL
+  HepMC::GenEvent genEvt;
+
+  long long int evtNum = eventInfo->eventNumber();    
+  genEvt.set_event_number(evtNum);
+  ATH_MSG_DEBUG("Start createHepMCEvent for event " <<evtNum);
+  
+  // PARTICLES AND VERTICES  
+  // Map of existing vertices - needed for the tree linking
+  std::map<const xAOD::TruthVertex*,HepMC::GenVertex*> vertexMap;
+
+  // Loop over all of the particles in the event, call particle builder
+  // Call suggest_barcode only after insertion!  
+  for (auto tlink:xEvt->truthParticleLinks()) {
+    if (!tlink.isValid()) continue;
+    const xAOD::TruthParticle* xPart = *tlink;
+    
+    // sanity check
+    if (xPart == nullptr) {
+      ATH_MSG_WARNING("xAOD TruthParticle is equal to NULL. This should not happen!");
+      continue;
+    }
+
+    if( !xPart->hasProdVtx() && !xPart->hasDecayVtx() ){
+      ATH_MSG_WARNING("xAOD particle with no vertices, bc = "<<xPart->barcode());
+      continue;
+    }
+
+    // skip particles with barcode > 200000 --> Geant4 secondaries 
+    if ( xPart->barcode() > 200000 ) continue; 
+
+    // Create GenParticle
+    //presumably the GenEvent takes ownership of this, but creating a unique_ptr here as that will only happen if there's an associated vertex
+    std::unique_ptr<HepMC::GenParticle> hepmcParticle( createHepMCParticle(xPart) );
+    int bcpart = xPart->barcode();
+    
+    // status 10902 should be treated just as status 2
+    if ( hepmcParticle->status() == 10902 ) hepmcParticle->set_status(2);
+
+    // Get the production and decay vertices
+    if( xPart->hasProdVtx() ) {
+      const xAOD::TruthVertex* xAODProdVtx = xPart->prodVtx();
+      // skip production vertices with barcode > 200000 --> Geant4 secondaries 
+      if ( std::abs(xAODProdVtx->barcode()) > 200000 ) continue; 
+      bool prodVtxSeenBefore(false); // is this new?
+      HepMC::GenVertex* hepmcProdVtx = vertexHelper(xAODProdVtx,vertexMap,prodVtxSeenBefore);
+      // Set the decay/production links
+      hepmcProdVtx->add_particle_out(hepmcParticle.release());
+      // Insert into Event
+      if (!prodVtxSeenBefore){ 
+	genEvt.add_vertex(hepmcProdVtx);
+	if( !hepmcProdVtx->suggest_barcode(xAODProdVtx->barcode()) ){
+	  ATH_MSG_WARNING("suggest_barcode failed for vertex "<<xAODProdVtx->barcode());
+	  ++m_badSuggest;
+	}
+            }
+      if( !hepmcParticle->suggest_barcode(bcpart) ){
+	ATH_MSG_DEBUG("suggest_barcode failed for particle " <<bcpart);
+	++m_badSuggest;
+      }
+      bcpart = 0;
+    } else {
+      ATH_MSG_DEBUG("No production vertex found for particle "<<xPart->barcode());
+    }
+    
+    if( xPart->hasDecayVtx() ){
+      const xAOD::TruthVertex* xAODDecayVtx = xPart->decayVtx();
+      // skip decay vertices with barcode > 200000 --> Geant4 secondaries 
+      if ( fabs(xAODDecayVtx->barcode()) > 200000 ) continue; 
+      bool decayVtxSeenBefore(false); // is this new?
+      HepMC::GenVertex* hepmcDecayVtx = vertexHelper(xAODDecayVtx,vertexMap,decayVtxSeenBefore);
+      // Set the decay/production links
+      hepmcDecayVtx->add_particle_in(hepmcParticle.release());
+      // Insert into Event
+      if (!decayVtxSeenBefore){ 
+	genEvt.add_vertex(hepmcDecayVtx);
+	if( !hepmcDecayVtx->suggest_barcode(xAODDecayVtx->barcode()) ){
+	  ATH_MSG_WARNING("suggest_barcode failed for vertex "
+			  <<xAODDecayVtx->barcode());
+	  ++m_badSuggest;
+	}
+      }
+      if( bcpart != 0 ){
+	if( !hepmcParticle->suggest_barcode(bcpart) ){
+	  ATH_MSG_DEBUG("suggest_barcode failed for particle " <<bcpart);
+	  ++m_badSuggest;
+	}
+	bcpart = 0;
+      }
+    }
+
+  } // end of particle loop
+
+  const HepMC::GenEvent constGenEvt(genEvt);
+  ATH_MSG_DEBUG("Returning const GenEvent");
+  return constGenEvt;
+  
+}
+
+// Helper to check whether a vertex exists or not using a map; 
+// calls createHepMCVertex if not
+HepMC::GenVertex* xAODtoHepMCTool::vertexHelper(const xAOD::TruthVertex* xaodVertex,
+						std::map<const xAOD::TruthVertex*,HepMC::GenVertex*> &vertexMap,
+						bool &seenBefore) const {
+  
+  HepMC::GenVertex* hepmcVertex;
+  std::map<const xAOD::TruthVertex*,HepMC::GenVertex*>::iterator vMapItr;
+  vMapItr=vertexMap.find(xaodVertex);
+  // Vertex seen before?
+  if (vMapItr!=vertexMap.end()) {
+            // YES: use the HepMC::Vertex already in the map
+    hepmcVertex = (*vMapItr).second;
+    seenBefore = true;
+  } else {
+    // NO: create a new HepMC::Vertex
+    vertexMap[xaodVertex] = createHepMCVertex(xaodVertex);
+    hepmcVertex=vertexMap[xaodVertex];
+    seenBefore = false;
+  }
+  return hepmcVertex;
+  
+}
+
+// Create the HepMC GenParticle
+// Call suggest_barcode after insertion!
+HepMC::GenParticle* xAODtoHepMCTool::createHepMCParticle(const xAOD::TruthParticle* particle) const {
+  ATH_MSG_VERBOSE("Creating GenParticle for barcode " <<particle->barcode());
+  const HepMC::FourVector fourVec( m_momFac * particle->px(), m_momFac * particle->py(), m_momFac * particle->pz(), m_momFac * particle->e() );
+  HepMC::GenParticle* hepmcParticle=new HepMC::GenParticle(fourVec, particle->pdgId(), particle->status());
+  hepmcParticle->set_generated_mass( m_momFac * particle->m());
+  return hepmcParticle;
+}
+
+// Create the HepMC GenVertex
+// Call suggest_barcode after insertion!
+HepMC::GenVertex* xAODtoHepMCTool::createHepMCVertex(const xAOD::TruthVertex* vertex) const {
+  ATH_MSG_VERBOSE("Creating GenVertex for barcode " <<vertex->barcode());
+  HepMC::FourVector prod_pos( m_lenFac * vertex->x(), m_lenFac * vertex->y(),m_lenFac * vertex->z(), m_lenFac * vertex->t() );
+  HepMC::GenVertex* genVertex=new HepMC::GenVertex(prod_pos);
+  return genVertex;
+}
+
+// Print xAODTruth Event. The printout is particle oriented, unlike the
+// HepMC particle/vertex printout. Geant and pileup particles with
+// barcode>100000 are omitted.
+void xAODtoHepMCTool::printxAODEvent(const xAOD::TruthEvent* event, const xAOD::EventInfo* eventInfo) const{
+  
+  std::vector<int> bcPars;
+  std::vector<int> bcKids;
+
+  long long int evtNum = eventInfo->eventNumber();
+
+  std::cout <<"======================================================================================" <<std::endl;
+  std::cout <<"xAODTruth Event " << evtNum <<std::endl;
+  std::cout <<"   Barcode      PDG Id  Status   px(GeV)   py(GeV)   pz(GeV)    E(GeV)   Parent: Decay" <<std::endl;
+  std::cout <<"   -----------------------------------------------------------------------------------" <<std::endl;
+
+  int nPart = event->nTruthParticles();
+  for(int i=0; i<nPart; ++i){
+    const xAOD::TruthParticle* part = event->truthParticle(i);
+    if (part==nullptr) continue;
+    int bc = part->barcode();
+    if( bc > 100000 ) continue;
+    int id = part->pdgId();
+    if ( id != 25 ) continue;
+    int stat = part->status();
+    float px = part->px()/1000.;
+    float py = part->py()/1000.;
+    float pz = part->pz()/1000.;
+    float e = part->e()/1000.;
+    bcPars.clear();
+    bcKids.clear();
+
+    if( part->hasProdVtx() ){
+      const xAOD::TruthVertex* pvtx = part->prodVtx();
+      if( pvtx ) bcPars.push_back(pvtx->barcode());
+    }
+
+    if( part->hasDecayVtx() ){
+      const xAOD::TruthVertex* dvtx = part->decayVtx();
+      if( dvtx ) bcKids.push_back(dvtx->barcode());
+    }
+
+    std::cout <<std::setw(10)<<bc <<std::setw(12)<<id
+              <<std::setw(8)<<stat
+              <<std::setprecision(2)<<std::fixed
+              <<std::setw(10)<<px <<std::setw(10)<<py
+              <<std::setw(10)<<pz <<std::setw(10)<<e <<"   ";
+    std::cout <<"P: ";
+    for(unsigned int k=0; k<bcPars.size(); ++k){
+      std::cout <<bcPars[k] <<" ";
+    }
+    std::cout <<"  D: ";
+    for(unsigned int k=0; k<bcKids.size(); ++k){
+      std::cout <<bcKids[k] <<" ";
+    }
+    std::cout <<std::endl;
+  }
+  std::cout <<"======================================================================================" <<std::endl;
+}
diff --git a/Generators/TruthConverters/TruthConverters/selection.xml b/Generators/TruthConverters/TruthConverters/selection.xml
new file mode 100644
index 000000000000..a52825c0a277
--- /dev/null
+++ b/Generators/TruthConverters/TruthConverters/selection.xml
@@ -0,0 +1,5 @@
+
+<lcgdict>
+   <class name="xAODtoHepMCTool" />
+   <class name="IxAODtoHepMCTool" />
+</lcgdict>
diff --git a/Generators/TruthConverters/TruthConverters/xAODtoHepMCDict.h b/Generators/TruthConverters/TruthConverters/xAODtoHepMCDict.h
new file mode 100644
index 000000000000..a5e812f29ab0
--- /dev/null
+++ b/Generators/TruthConverters/TruthConverters/xAODtoHepMCDict.h
@@ -0,0 +1,11 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#ifndef TRUTHCONVERTERS_XAODTOHEPMCDICT_H
+#define TRUTHCONVERTERS_XAODTOHEPMCDICT_H
+
+#include "TruthConverters/xAODtoHepMCTool.h"
+
+#endif
diff --git a/Generators/TruthConverters/TruthConverters/xAODtoHepMCTool.h b/Generators/TruthConverters/TruthConverters/xAODtoHepMCTool.h
new file mode 100644
index 000000000000..15aa09edbef4
--- /dev/null
+++ b/Generators/TruthConverters/TruthConverters/xAODtoHepMCTool.h
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * dual-use tool for converting xAOD truth events back to HepMC
+ * Principal Authors (responsible for the core conversion algorithm): Josh McFayden and James Catmore
+ * Tool Author: Jim Lacey (Carleton University) 
+ * ... updated tool interface to be dual-use
+ * ... added missing PDF information and requirements to allow running on full sim (remove Geant4 secondaries)
+ * <james.lacey@cern.ch,jlacey@physics.carleton.ca>
+ * <dag.gillberg@cern.ch>
+ */
+
+#ifndef TRUTHCONVERTERS_XAODTOHEPMCTOOL_H
+#define TRUTHCONVERTERS_XAODTOHEPMCTOOL_H 1
+
+#include "AsgTools/AsgTool.h"
+#include "GenInterfaces/IxAODtoHepMCTool.h"
+
+
+class xAODtoHepMCTool: public asg::AsgTool, public virtual IxAODtoHepMCTool { 
+ public: 
+   ASG_TOOL_CLASS( xAODtoHepMCTool , IxAODtoHepMCTool )
+   xAODtoHepMCTool( const std::string& name );
+   virtual ~xAODtoHepMCTool () { };
+
+   virtual StatusCode  initialize() override;
+   StatusCode finalize () override;
+
+ public:
+   std::vector<HepMC::GenEvent> getHepMCEvents(const xAOD::TruthEventContainer* xTruthEventContainer, const xAOD::EventInfo* eventInfo) const override;
+
+ private:
+   HepMC::GenEvent createHepMCEvent(const xAOD::TruthEvent* xEvt, const xAOD::EventInfo* eventInfo) const;
+   HepMC::GenVertex* vertexHelper(const xAOD::TruthVertex*,std::map<const xAOD::TruthVertex*,HepMC::GenVertex*>&,bool&) const;
+   HepMC::GenParticle* createHepMCParticle(const xAOD::TruthParticle*) const;
+   HepMC::GenVertex* createHepMCVertex(const xAOD::TruthVertex*) const;
+   void printxAODEvent(const xAOD::TruthEvent* event, const xAOD::EventInfo* eventInfo) const;
+   
+ private:
+   /// Input container key (job property)
+   float m_momFac,m_lenFac;
+   bool m_signalOnly;
+   int m_maxCount;
+   /// Counters
+   //not sure if these need to be atomic but just in case this will run in MT
+   mutable std::atomic<int> m_evtCount;
+   mutable std::atomic<int> m_badSuggest;
+   int m_noProdVtx;
+   int m_badBeams;
+
+}; 
+
+#endif //> !XAODTOHEPMC_XAODTOHEPMCTOOL_H
diff --git a/Generators/TruthConverters/src/components/TruthConverters_entries.cxx b/Generators/TruthConverters/src/components/TruthConverters_entries.cxx
new file mode 100644
index 000000000000..fc6fea6d6af7
--- /dev/null
+++ b/Generators/TruthConverters/src/components/TruthConverters_entries.cxx
@@ -0,0 +1,4 @@
+
+#include "TruthConverters/xAODtoHepMCTool.h"
+
+DECLARE_COMPONENT( xAODtoHepMCTool )
diff --git a/Generators/TruthRivetTools/Root/HiggsTruthCategoryTool.cxx b/Generators/TruthRivetTools/Root/HiggsTruthCategoryTool.cxx
index d2790e23680f..0ba2d87a2802 100644
--- a/Generators/TruthRivetTools/Root/HiggsTruthCategoryTool.cxx
+++ b/Generators/TruthRivetTools/Root/HiggsTruthCategoryTool.cxx
@@ -21,7 +21,7 @@ StatusCode HiggsTruthCategoryTool::initialize() {
   ATH_MSG_INFO ("Initializing " << name() << "...");
   // Rivet analysis :: Higgs truth event classifier class
   higgsTemplateCrossSections = new Rivet::HiggsTemplateCrossSections();
-  // crreate an instance of the Rivet analysis handler
+  // create an instance of the Rivet analysis handler
   rivetAnaHandler = new Rivet::AnalysisHandler();
   // Add the Higgs truth classifier class to the handler
   rivetAnaHandler->addAnalysis(&(*higgsTemplateCrossSections));
@@ -32,8 +32,10 @@ StatusCode HiggsTruthCategoryTool :: finalize () {
   ATH_MSG_INFO (" ====================================================== ");
   ATH_MSG_INFO (" ---- Finalizing" << name() << "...");
   ATH_MSG_INFO (" ====================================================== ");
-  if ( !m_outHistos )
-    higgsTemplateCrossSections->printClassificationSummary( );
+  if ( !m_outHistos ){
+    //this seems to thrown an exception
+    //higgsTemplateCrossSections->printClassificationSummary( );
+  }
   else{
     // TODO:: update the tool properly deal with output files/paths
     rivetAnaHandler->finalize();
@@ -43,7 +45,7 @@ StatusCode HiggsTruthCategoryTool :: finalize () {
   return StatusCode::SUCCESS;  
 }
 
-HTXS::HiggsClassification* HiggsTruthCategoryTool :: getHiggsTruthCategoryObject (const HepMC::GenEvent& HepMCEvent, const HTXS::HiggsProdMode prodMode){
+HTXS::HiggsClassification* HiggsTruthCategoryTool :: getHiggsTruthCategoryObject (const HepMC::GenEvent& HepMCEvent, const HTXS::HiggsProdMode prodMode) const {
   if ( !m_isInitialized ) {
     higgsTemplateCrossSections->setHiggsProdMode(prodMode); 
     rivetAnaHandler->init(HepMCEvent); 
diff --git a/Generators/TruthRivetTools/TruthRivetTools/HiggsTruthCategoryTool.h b/Generators/TruthRivetTools/TruthRivetTools/HiggsTruthCategoryTool.h
index 77e63f24a749..7e6399d0a631 100644
--- a/Generators/TruthRivetTools/TruthRivetTools/HiggsTruthCategoryTool.h
+++ b/Generators/TruthRivetTools/TruthRivetTools/HiggsTruthCategoryTool.h
@@ -47,9 +47,9 @@ class HiggsTruthCategoryTool
    Rivet::HiggsTemplateCrossSections *higgsTemplateCrossSections; //!
    virtual StatusCode  initialize() override;
    StatusCode finalize () override;
-   HTXS::HiggsClassification* getHiggsTruthCategoryObject(const HepMC::GenEvent& HepMCEvent, const HTXS::HiggsProdMode prodMode) override;
+   HTXS::HiggsClassification* getHiggsTruthCategoryObject(const HepMC::GenEvent& HepMCEvent, const HTXS::HiggsProdMode prodMode) const override;
  private:
-   bool m_isInitialized;
+   mutable std::atomic<bool> m_isInitialized;
    bool m_outHistos;
 };
 
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/CMakeLists.txt b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/CMakeLists.txt
index 8b7686551e09..fcd11a2d7a85 100644
--- a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/CMakeLists.txt
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/CMakeLists.txt
@@ -11,9 +11,9 @@ atlas_add_component( DerivationFrameworkHiggs
                      src/*.cxx src/components/*.cxx
                      INCLUDE_DIRS ${CLHEP_INCLUDE_DIRS}
                      DEFINITIONS ${CLHEP_DEFINITIONS}
-                     LINK_LIBRARIES ${CLHEP_LIBRARIES} AthenaBaseComps DerivationFrameworkInterfaces TrigDecisionToolLib xAODEgamma xAODEventInfo xAODJet xAODMuon xAODTracking )
+                     LINK_LIBRARIES ${CLHEP_LIBRARIES} AthenaBaseComps DerivationFrameworkInterfaces TrigDecisionToolLib TruthRivetToolsLib TruthUtils PathResolver xAODEgamma xAODEventInfo xAODJet xAODMuon xAODTracking xAODTruth)
 
 # Install files from the package:
 atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
 atlas_install_joboptions( share/*.py )
-
+atlas_install_data( share/*.cfg )
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/DerivationFrameworkHiggs/TruthCategoriesDecorator.h b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/DerivationFrameworkHiggs/TruthCategoriesDecorator.h
new file mode 100644
index 000000000000..206f6109c8a0
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/DerivationFrameworkHiggs/TruthCategoriesDecorator.h
@@ -0,0 +1,87 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Tool to decorate the EventInfo object with truth categories informations 
+// Authors: T. Guillemin, J. Lacey, D. Gillberg
+	
+#ifndef DerivationFrameworkHiggs_TruthCategoriesDecorator_H
+#define DerivationFrameworkHiggs_TruthCategoriesDecorator_H
+
+#include <string>
+#include <vector>
+#include <TEnv.h>
+#include <TString.h>
+#include <TSystem.h>
+
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "DerivationFrameworkInterfaces/IAugmentationTool.h"
+
+// EDM: typedefs, so must be included and not forward-referenced
+#include "xAODTruth/TruthParticleContainer.h"
+#include "xAODEventInfo/EventInfo.h"
+
+// Note: must include TLorentzVector before the next one
+#include "TLorentzVector.h"
+#include "TruthRivetTools/HiggsTemplateCrossSectionsDefs.h"
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODTruth/TruthEventContainer.h"
+#include "StoreGate/WriteDecorHandleKeyArray.h"
+
+class IHiggsTruthCategoryTool;
+class IxAODtoHepMCTool;
+
+namespace DerivationFramework {
+  
+  class TruthCategoriesDecorator : public AthAlgTool, public IAugmentationTool {
+        
+  public:
+    TruthCategoriesDecorator(const std::string& t, const std::string& n, const IInterface* p);
+    ~TruthCategoriesDecorator();
+    StatusCode initialize();
+    StatusCode finalize();
+    virtual StatusCode addBranches() const;
+
+  private:
+    ToolHandle<IxAODtoHepMCTool> m_xAODtoHepMCTool;
+    ToolHandle<IHiggsTruthCategoryTool> m_higgsTruthCatTool;
+
+    SG::WriteDecorHandleKeyArray<xAOD::EventInfo> m_eventInfoIntDecors{this, "EventInfoIntDecors", {}, "List of int EventInfo decorations to be filled"};
+    SG::WriteDecorHandleKeyArray<xAOD::EventInfo> m_eventInfoFloatDecors{this, "EventInfoFloatDecors", {}, "List of float EventInfo decorations to be filled"};
+    SG::WriteDecorHandleKeyArray<xAOD::EventInfo> m_eventInfoVectorFloatDecors{this, "EventInfoVectorFloatDecors", {}, "List of vector float EventInfo decorations to be filled"};
+    SG::ReadHandleKey<xAOD::TruthEventContainer> m_truthEventCont{this,"TruthEventCont","TruthEvents","truth event container"};
+    std::vector<std::string> m_eventInfoIntDecorNames;
+    std::vector<std::string> m_eventInfoFloatDecorNames;
+    std::vector<std::string> m_eventInfoVectorFloatDecorNames;
+
+    // Path to TEnv file containing MC-channel-numbre <-> HiggsProdMode map
+    TEnv *m_config;
+    std::string m_configPath;
+
+    // Detail level. Steers amount of decoration.
+    //  0: basic information. Categoization ints, Higgs prod mode, Njets, Higgs pT
+    //  1: the above + Higgs boson 4-vec + associated V 4-vec
+    //  2: the above + truth jets built excluding the Higgs boson decay
+    //  3: the above + 4-vector sum of all decay products from Higgs boson and V-boson
+    int m_detailLevel;
+    
+    // methods to locate the TEnv input file
+    bool fileExists(TString fileName) { return gSystem->AccessPathName(fileName) == false; }
+
+    // Converts a string to a vector of integers
+    std::vector<int> vectorize(TString string, TString sep=" ") const;
+  
+    // Method to access the production mode for a given MC channel number
+    HTXS::HiggsProdMode getHiggsProductionMode(uint32_t mc_channel_number,HTXS::tH_type &th_type) const;
+ 
+    // Methods for decoration of four vectors
+    float getFloatDecor(const std::string key, const TLorentzVector p4) const;
+    std::vector<float> getVectorFloatDecor(const std::string key, const std::vector<TLorentzVector> p4s) const;
+
+
+  }; /// class
+  
+} /// namespace
+
+#endif
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/python/TruthCategories.py b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/python/TruthCategories.py
new file mode 100644
index 000000000000..a3c3bbf93a93
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/python/TruthCategories.py
@@ -0,0 +1,15 @@
+# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+
+from DerivationFrameworkCore.DerivationFrameworkMaster import DerivationFrameworkIsMonteCarlo,DerivationFrameworkJob
+from AthenaCommon.AppMgr import ToolSvc
+from AthenaCommon import CfgMgr
+
+if DerivationFrameworkIsMonteCarlo:
+
+    from DerivationFrameworkHiggs.DerivationFrameworkHiggsConf import DerivationFramework__TruthCategoriesDecorator
+    DFHTXSdecorator = DerivationFramework__TruthCategoriesDecorator(name = "DFHTXSdecorator")
+
+    ToolSvc += DFHTXSdecorator
+    DerivationFrameworkJob += CfgMgr.DerivationFramework__CommonAugmentation("TruthCategoriesCommonKernel",
+                                                                             AugmentationTools = [DFHTXSdecorator]
+                                                                             )
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/share/HiggsMCsamples.cfg b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/share/HiggsMCsamples.cfg
new file mode 100644
index 000000000000..ac0c2a1e12b3
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/share/HiggsMCsamples.cfg
@@ -0,0 +1,267 @@
+######################################################
+#
+# List of MC channel number for each Higgs MC sample of a given production mode.
+# Used by the Higgs boson simplified template cross section tool (HTXS)
+#
+# If two derviations use the same MCID it only needs to be listed one time 
+# (but it doesn't hurt to have it listed several times, as long as it's only for one production mode of course ;)
+#
+# Note: this follows the TEnv format. A config key-nmae folowed by MCIDs as "values".
+# MCIDs shoudl be space-separated (sveral space charcters are fine).
+# When adding MC IDs to a existing config key you need to start with a + character
+#
+######################################################
+
+
+HTXS.MCsamples.GGF:    341272 342172
+HTXS.MCsamples.VBF:    20672
+HTXS.MCsamples.WH:     342284
+HTXS.MCsamples.QQ2ZH:  341463
+HTXS.MCsamples.GG2ZH:  341099
+HTXS.MCsamples.TTH:    341271 342561
+HTXS.MCsamples.THQB:   343269
+HTXS.MCsamples.WHT:    341997 346486
+HTXS.MCsamples.BBH:    342097
+
+###############
+#  HGam samples
+#  i.e. HIGG1D1, HIGG1D2
+#
+
+  # mH=125, and MPI_OFF
++HTXS.MCsamples.GGF:     341000 342560 343981 345316 345415 345416 345417 345944
+  # mH = 60, 80, 100, 105 ... 150 ... 2000
++HTXS.MCsamples.GGF:     342020 342023 342008 342057 342058 342059 342060 342061 342062 342063 342064 342010 342012 342013 342014 342015
++HTXS.MCsamples.GGF:	 341445
++HTXS.MCsamples.GGF:     342016 342017 342018 342019 342021 342022 342024 342007 342009 342011 342607 342608 342609 342610 342611 
+  # special samples
++HTXS.MCsamples.GGF:     342612 342613 342614 342615 343470 343471 343472 343473 343474 345307 345308 345309 345310 345311 345312 345313 345314 345306 345961 346665 346666 346667
+
++HTXS.MCsamples.VBF:     341001 342026 342065 342066 342067 342068 342069 342070 342071 342072 342034 342036 342029 342030 342031 342032
++HTXS.MCsamples.VBF:     342033 342035 342025 342027 342028 345041 345042 345434 345435 345436 345437 345438 345439 345440 345441 345442 345443 345444 345448 345449 345450 345451 345452 345453 345454 345455 345834 346214
+
++HTXS.MCsamples.WH:      341067 342260 342073 342074 342075 342076 342077 342078 342079 342080 342258 342259 342261
++HTXS.MCsamples.WH:	 342262 342263 342264 342265 342266 342267 342268 342269 345317 345318 345320 345321 345548 345549 345550 345551 345552 345553 345554 345555 345556 345557 345558 345559 345560 345561 345562 345563 345963 345964
+
++HTXS.MCsamples.QQ2ZH:   341068 342272 342081 342082 342083 342084 342085 342086 342087 342088 342270 342271 342273 342274 342275 342276
++HTXS.MCsamples.QQ2ZH:   342277 342278 342279 342280 342281 345319 345322 345200 345201 345202 345204 345207 345208 345209 345210 345965
+  # HIGG1 gg -> ZH 
++HTXS.MCsamples.GG2ZH: 345061 345266 345267 345268 345269 345270 345271 345272 345273
+  #mH125, Pythia, aMC@NLO+Py8, aMC@NLO+HwPP
++HTXS.MCsamples.TTH:     341069 343436 341081 345863 345934 345932 346189
+  # Py8 mH=60..2000 GeV
++HTXS.MCsamples.TTH:     342046 342048 342038 342041 342042 342043 342044 342045 342047 342037 342039 342040 
+  # aMC@NLO+HwPP mH=100..150 GeV
++HTXS.MCsamples.TTH:     341976 341977 341978 341979 341980 341981 341982 341983 341984 341985 346303 346304
+  # aMCnloPy8
++HTXS.MCsamples.BBH:     342097 342098 343080 343081 343085 343086 343072 345315
+  # aMCnloPy8
++HTXS.MCsamples.THQB:    341988 341989 341990 343266 343267 343268 345933 346188 346221
++HTXS.MCsamples.WHT:     341998 341999
+
+###############
+#  HZZ samples
+#  i.e. HIGG2D* derivation
+#
+# https://twiki.cern.ch/twiki/bin/view/AtlasProtected/HZZllllRun2MCSamplesMC15c_25ns
+# Signal Samples, low mass
+# ggF
++HTXS.MCsamples.GGF:    341471 341500 341502 341504 341505 341506 341508 341510 346695 346701
+# VBF
++HTXS.MCsamples.VBF:    341488 341513 341515 341517 341518 341519 341521 341523 346228 346696 346702
+# ZH
++HTXS.MCsamples.QQ2ZH:  341946 341947 341948 341975 346698 346704 346645
+# WH
++HTXS.MCsamples.WH:     341963 341964 341965 346699 346700 346705 346706 346646 346647
+# ttH
++HTXS.MCsamples.TTH:    342561 342562 342563 342564 342565 342566 342567 342568 342569 345046 345047 345048 345936 346340 346341 346342
+# ggF EFT
++HTXS.MCsamples.GGF:    344158 344159 344160 344161 344162 344163 344164 344165 344166 344167 344169 344170 
++HTXS.MCsamples.GGF:    346574 346575 346576 346577 346578
+# VBF EFT
++HTXS.MCsamples.VBF:    343247 343248 343249 343250 343251 343252 343253 343254 343255 343256 343257 343258 343259 343260 343261 343262
++HTXS.MCsamples.VBF:    346608 346609 346610 346611 346612 346613 346614 346615 346616 346617 346618 346619 346620 346621 346622 346623 346624 346625 346626 346627 346628 346629 346630 346631
++HTXS.MCsamples.VBF:    346579 346580 346581 346582
+# ttH EFT
++HTXS.MCsamples.TTH:    346585 346586
+# VH EFT
+#    skip because cannot be separated into WH and QQ2ZH
+#                       344135 344136 344137 344138 344139 344140 344141 344142 344143 344144 344145 344146 344147 344148 344149 344150 344151
+#
+
++HTXS.MCsamples.WHT:    345966 346511
++HTXS.MCsamples.THQB:   345967
+
+# ggF different masses
++HTXS.MCsamples.GGF:    345576 345577 345578 345579 345581 345582 345583
+
+# ttH MG5
++HTXS.MCsamples.TTH:    346062 346063 346064
+# tWH MG5
++HTXS.MCsamples.WHT:    346759
+# tHjb MG5
++HTXS.MCsamples.THQB:    346677
+
+# Signal Samples, high mass
+# ggF - narrow width
++HTXS.MCsamples.GGF:    341274 341275 341276 341277 341278 341279 341280 341281 341282 341283 341284 341285 341286 341287 341288 341289 341290 341291 341292
+# ggF - 5%, 10%, and 15% width
++HTXS.MCsamples.GGF:    343204 343205 343206 343207
++HTXS.MCsamples.GGF:    343208 343209 343210 343211
++HTXS.MCsamples.GGF:    343184 343185 343186 343187 343188 343189 343190 343191 343192 343193 343194 343195 343196 343197 343198 343199 343200 343201 343202 343203 
+# VBF
++HTXS.MCsamples.VBF:    341293 341294 341295 341296 341297 341298 341299 341300 341301 341302 341303 341304 341305 341306 341307 341308 341309 341310 341311 
+# ZH
++HTXS.MCsamples.QQ2ZH:  341886 341887 341888
+# WH
++HTXS.MCsamples.WH:     341889 341890 341891
+# ggF noTau
++HTXS.MCsamples.GGF:    341420
+# bbH noTau
++HTXS.MCsamples.BBH:    344967 344968 344969 344970 344971 344972 344973 344974 344975 344976 344977 344978 344979 344980
+# VBF EFT 
++HTXS.MCsamples.VBF:    345049
+# VH EFT
+#    skip because cannot be separated into WH and QQ2ZH
+#                       345050 345051 345052                         
+# ggH
++HTXS.MCsamples.GGF:    345060 
+# ZH
++HTXS.MCsamples.QQ2ZH:  345038
+# WH
++HTXS.MCsamples.WH:     345039 345040
+# VBF noTau
++HTXS.MCsamples.VBF:    345434 345435 345436 345437 345438 345439 345440 345441 345442 345443 345444
++HTXS.MCsamples.VBF:    344235
+
+# EFT VBF
++HTXS.MCsamples.VBF:    345355 345356 345357 345358 345359 345360 345361 345362 345363 345364 345365 345366 345367 345368 345369 345370 345371 345372 345373 345374
+# EFT WH
++HTXS.MCsamples.WH:     345375 345376 345377 345378 345379 345380 345381 345382 345383 345384 345385 345386 345387 345388 345389 345390 345391 345392 345393 345394
+# EFT ZH
++HTXS.MCsamples.QQ2ZH:  345395 345396 345397 345398 345399 345400 345401 345402 345403 345404 345405 345406 345407 345408 345409 345410 345411 345412 345413 345414
+
+# ggZH 
++HTXS.MCsamples.GG2ZH:  345066 346697 346703
+
+# Herwig
++HTXS.MCsamples.GGF:    346446 346797
++HTXS.MCsamples.VBF:    346447 346878
++HTXS.MCsamples.QQ2ZH:  346448 346879
++HTXS.MCsamples.WH:     346449 346450 346880 346881
++HTXS.MCsamples.WHT:     346883
++HTXS.MCsamples.GG2ZH:  346451 346882
++HTXS.MCsamples.TTH:    346452 346453 346454
+
+# llqq
+# ggZH125
++HTXS.MCsamples.GG2ZH:  341094 341095 341096 341097 341098 341099
+# WlvH125_bb
++HTXS.MCsamples.WH:     341100
+# ZvvH125_bb, ZllH125_bb
++HTXS.MCsamples.QQ2ZH:  341101 341102
+# WxH125J_MINLO
++HTXS.MCsamples.WH:     341178 341179 341181 341182
+# ggHXXXNW_ZZllqq
++HTXS.MCsamples.GGF:    341312 341313 341314 341315 341316 341317 341318 341319 341320 341321 341322 341323 341324 341325 341326 341327 341328 341329 341330
+# VBFHXXXNW_ZZllqq
++HTXS.MCsamples.VBF:    341331 341332 341333 341334 341335 341336 341337 341338 341339 341340 341341 341342 341343 341344 341345 341346 341347 341348 341349
+# ZHXXXNW_ZZllqq
++HTXS.MCsamples.QQ2ZH:  341892 341893 341894
+# WHXXXNW_ZZllqq
++HTXS.MCsamples.WH:     341895 341896 341897
+# ggF 15% width 
++HTXS.MCsamples.GGF:    342908 342909 342910 342911 342912 342913 342914 342915 342916 342917 342918 342919 342920 342921 342922 342923 342924 342925 342926
+# ggF  5% width 
++HTXS.MCsamples.GGF:    342927 342928 342929 342930
+# ggF 10% width 
++HTXS.MCsamples.GGF:    342931 342932 342933 342934
+# ggF narrow width
++HTXS.MCsamples.GGF:    343573
+# VBF narrow width
++HTXS.MCsamples.VBF:    343574
+# WH EFT
++HTXS.MCsamples.WH:     343608
+# ZH EFT
++HTXS.MCsamples.QQ2ZH:  343619
+# THQB
++HTXS.MCsamples.THQB:   346414 346415
+
+# Hinv
+# ZH
++HTXS.MCsamples.QQ2ZH: 346693
+# ggZH
++HTXS.MCsamples.GG2ZH: 346694
+
+###############
+#  HWW samples
+#  i.e. HIGG3D* derivation
+#
+
++HTXS.MCsamples.GGF:    341079 343393 341122 341195 345324 345339 346802
+
++HTXS.MCsamples.VBF:    341080 341155 341206 345323 345340 345948 346877
+
++HTXS.MCsamples.WH:    342684 342685 342686 342687 342688 342689 342690 342816 342817 342818 342820 342821 342822 341421
++HTXS.MCsamples.WH:    341422 341423 341424 341425 341426 341427 341428 341429 341430 341431 3414232 341433 341434 341435 
++HTXS.MCsamples.WH:    34142136 343275 343276 343323 343345 345325 345326 345327 345433 345341
+
++HTXS.MCsamples.QQ2ZH:   341449 341450 341451 341452 341453 341454 341455 341456 341457 341458 341459 341460 341461 343334 343356 345336 345337 345445 345446
+
+
+###############
+#  HLeptons samples
+#
+#
++HTXS.MCsamples.GGF: 341122 341079 344092 341124 341905 341906 341907 342300 342301 344084 344088 341123 341902 341903 341904 342282 342302 341225 345120 345121 345122 345123 345126 345127 345128 345124 345125 345097 342178 345697 345698 345699 346564
++HTXS.MCsamples.VBF: 341155 341080 344093 341157 341911 341912 341913 344085 344089 341156 341908 341909 341910 342283 341254  345073 345074 345075 345076 345077 345078 345106 342189 346190 346191 346192 346193
++HTXS.MCsamples.TTH: 342170 342171 342172 343365 343366 343367 344388 345672 345673 345674 345873 345874 345875 346343 346344 346345 346443 346444 346445 346346 346347 346348
++HTXS.MCsamples.WH: 344094 344086 344090 342284 343942 345211 345212 345213 345214 345215 345216 345104 345105 346324 346325
++HTXS.MCsamples.QQ2ZH: 344095 344087 344091 342285 343953 345217 345218 345219 345103 346326
++HTXS.MCsamples.GG2ZH: 341096 345098 346329
++HTXS.MCsamples.BBH: 345533 
+
+###############
+# Hbb samples
+#
+#
++HTXS.MCsamples.WH: 345053 345054 345109 345110 346395 346396 346723 346724
++HTXS.MCsamples.QQ2ZH: 345055 345056 345111 345112 346397 346398 346725 346726
++HTXS.MCsamples.GG2ZH: 345057 345058 345113 345114 346399 346400 346727 346728
+
+###############
+# VBF HInv samples
++HTXS.MCsamples.GGF: 346588
++HTXS.MCsamples.WH: 346605 346606
++HTXS.MCsamples.QQ2ZH: 346607 
++HTXS.MCsamples.GG2ZH: 345596
++HTXS.MCsamples.TTH: 346632 346633 346634
++HTXS.MCsamples.VBF: 346600 312243 308567 308276 308275 308277 308278 308279 308280 308281 308282 308283
+
+#
+###########
+# HTop (multilepton) samples
+# i.e. HIGG8D1 derivation
+#
+  # aMCnloPy8
++HTXS.MCsamples.WHT: 342000 342001 342002 342003 342004 342005 
+  # aMCnloHw++
++HTXS.MCsamples.THQB: 341991 341992 341993 341994 341995 341996 343270 343271 343272 343273 343274
+  # aMCnloHw++
++HTXS.MCsamples.TTH: 341177 341270 341271
+
+###########
+## add new ttH samples
++HTXS.MCsamples.TTH: 346526 346525
+
+## add new ttH CP samples
++HTXS.MCsamples.TTH: 346303 346304 346595 346596 346597 346598 346601 346189
+
+###############
+#  EFT samples
+#
++HTXS.MCsamples.WH: 343599 343601 343610 343611
++HTXS.MCsamples.QQ2ZH: 343629 343624 343631 343614 343621 
++HTXS.MCsamples.WH: 345785 345786 345791 345792 345797 345798 345803 345804 345809 345810 345815 345816 345821 345822 345827 345828
++HTXS.MCsamples.QQ2ZH: 345787 345788 345793 345794 345799 345800 345805 345806 345811 345812 345817 345818 345823 345824 345829 345830
++HTXS.MCsamples.GG2ZH: 345789 345790 345795 345796 345801 345802 345807 345808 345813 345814 345819 345820 345825 345826 345831 345832
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/src/TruthCategoriesDecorator.cxx b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/src/TruthCategoriesDecorator.cxx
new file mode 100644
index 000000000000..864c59428a7c
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/src/TruthCategoriesDecorator.cxx
@@ -0,0 +1,285 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "DerivationFrameworkHiggs/TruthCategoriesDecorator.h"
+#include "xAODTruth/TruthParticleContainer.h"
+#include "xAODTruth/TruthVertex.h"
+#include "xAODJet/JetContainer.h"
+#include "TruthUtils/PIDHelpers.h"
+#include "PathResolver/PathResolver.h"
+
+#include "GenInterfaces/IHiggsTruthCategoryTool.h"
+#include "GenInterfaces/IxAODtoHepMCTool.h"
+
+#include "CLHEP/Units/SystemOfUnits.h"
+
+// Note: must include TLorentzVector before the next one
+#include "TLorentzVector.h"
+#include "TruthRivetTools/HiggsTemplateCrossSectionsDefs.h"
+#include "StoreGate/WriteDecorHandle.h"
+
+#include <TObjString.h>
+#include <TObjArray.h>
+
+namespace DerivationFramework {
+  
+  TruthCategoriesDecorator::TruthCategoriesDecorator(const std::string& t, const std::string& n, const IInterface* p):
+    AthAlgTool(t,n,p),
+    m_xAODtoHepMCTool("xAODtoHepMCTool"), 
+    m_higgsTruthCatTool("HiggsTruthCategoryTool"),
+    m_config(nullptr),
+    m_configPath("")
+  {
+    declareInterface<DerivationFramework::IAugmentationTool>(this);
+    declareProperty("ConfigPath",m_configPath="DerivationFrameworkHiggs/HiggsMCsamples.cfg");
+    declareProperty("DetailLevel",m_detailLevel=3);
+  }
+  
+  TruthCategoriesDecorator::~TruthCategoriesDecorator() {}
+  
+
+  StatusCode TruthCategoriesDecorator::initialize() {
+    
+    ATH_MSG_INFO("Initialize " );
+
+    // FOR xAOD->HEPMC ::  xAODtoHepMC tool
+    ATH_CHECK(m_xAODtoHepMCTool.retrieve());
+ 
+    // Higgs truth category tool 
+    ATH_CHECK(m_higgsTruthCatTool.retrieve());
+
+    // Open the TEnv configuration file
+    m_config = new TEnv();
+    int status = m_config->ReadFile(PathResolverFindCalibFile(m_configPath).c_str(),EEnvLevel(0));
+    if ( status != 0 ) {
+      ATH_MSG_FATAL("Failed to open TEnv file "<<m_configPath);
+      return StatusCode::FAILURE;
+    }
+
+    //All the decorations we want to add go here
+    m_eventInfoIntDecorNames.push_back("HTXS_prodMode");
+    m_eventInfoIntDecorNames.push_back("HTXS_errorCode");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage0_Category");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_Category_pTjet25");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_Category_pTjet30");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_FineIndex_pTjet30");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_FineIndex_pTjet25");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_2_Category_pTjet25");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_2_Category_pTjet30");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_2_FineIndex_pTjet30");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_2_FineIndex_pTjet25");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_2_Fine_Category_pTjet25");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_2_Fine_Category_pTjet30");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_2_Fine_FineIndex_pTjet25");
+    m_eventInfoIntDecorNames.push_back("HTXS_Stage1_2_Fine_FineIndex_pTjet30");
+    m_eventInfoIntDecorNames.push_back("HTXS_Njets_pTjet25");
+    m_eventInfoIntDecorNames.push_back("HTXS_Njets_pTjet30");
+    m_eventInfoIntDecorNames.push_back("HTXS_isZ2vvDecay");
+
+    m_eventInfoFloatDecorNames.push_back("HTXS_Higgs_pt");
+    std::string fourvecconts[4]={"_pt","_eta","_phi","_m"};
+    for(int i=0;i<4;i++){
+      m_eventInfoFloatDecorNames.push_back("HTXS_Higgs"+fourvecconts[i]);
+      m_eventInfoFloatDecorNames.push_back("HTXS_V"+fourvecconts[i]);
+      m_eventInfoFloatDecorNames.push_back("HTXS_Higgs_Decay"+fourvecconts[i]);
+      m_eventInfoFloatDecorNames.push_back("HTXS_V_Decay"+fourvecconts[i]);
+      m_eventInfoVectorFloatDecorNames.push_back("HTXS_V_jets25"+fourvecconts[i]);
+      m_eventInfoVectorFloatDecorNames.push_back("HTXS_V_jets30"+fourvecconts[i]);
+    }
+
+    for(auto name : m_eventInfoIntDecorNames) m_eventInfoIntDecors.emplace_back("EventInfo."+name);
+    for(auto name : m_eventInfoFloatDecorNames) m_eventInfoFloatDecors.emplace_back("EventInfo."+name);
+    for(auto name : m_eventInfoVectorFloatDecorNames) m_eventInfoVectorFloatDecors.emplace_back("EventInfo."+name);
+
+    ATH_CHECK(m_eventInfoIntDecors.initialize());
+    ATH_CHECK(m_eventInfoFloatDecors.initialize());
+    ATH_CHECK(m_eventInfoVectorFloatDecors.initialize());
+    ATH_CHECK(m_truthEventCont.initialize());
+    return StatusCode::SUCCESS;
+  }
+  
+  StatusCode TruthCategoriesDecorator::finalize(){
+    if(m_config) delete m_config;
+    return StatusCode::SUCCESS;
+  }
+
+  // Converts a string of numbers - separated by "sep" to a vector of integers
+  // sep is by default any number of space characters
+  std::vector<int> TruthCategoriesDecorator::vectorize(TString str, TString sep) const {
+    std::vector<int> result;
+    TObjArray *strings = str.Tokenize(sep.Data());
+    if (strings->GetEntries()==0) { delete strings; return result; }
+    TIter istr(strings);
+    while (TObjString* os=(TObjString*)istr()) {
+      result.push_back(atol(os->GetString()));
+    }
+    delete strings;
+    return result;
+  }
+
+  
+
+  HTXS::HiggsProdMode TruthCategoriesDecorator::getHiggsProductionMode(uint32_t mc_channel_number, HTXS::tH_type &th_type) const {
+    if (m_config==nullptr) {
+      ATH_MSG_ERROR("TEnv file pointer is NULL? Bad configuration.");
+      return HTXS::HiggsProdMode::UNKNOWN;
+    }
+
+    for (TString prodMode:{"GGF","VBF","WH","QQ2ZH","GG2ZH","TTH","BBH","TH","THQB","WHT"}) {
+
+      // loop over each mcID belonging to the production mode
+      for ( int mcID : vectorize(m_config->GetValue("HTXS.MCsamples."+prodMode,"")) ){
+        if (mcID==(int)mc_channel_number) {
+          ATH_MSG_INFO("Higgs production for MC channel number "<<mc_channel_number<<" mode is "<<prodMode);
+          // gah, need to convert
+          if (prodMode=="GGF"  ) return HTXS::HiggsProdMode::GGF;
+          if (prodMode=="VBF"  ) return HTXS::HiggsProdMode::VBF;
+          if (prodMode=="WH"   ) return HTXS::HiggsProdMode::WH;
+          if (prodMode=="QQ2ZH") return HTXS::HiggsProdMode::QQ2ZH;
+          if (prodMode=="GG2ZH") return HTXS::HiggsProdMode::GG2ZH;
+          if (prodMode=="TTH"  ) return HTXS::HiggsProdMode::TTH;
+          if (prodMode=="BBH"  ) return HTXS::HiggsProdMode::BBH;
+          if (prodMode=="TH"   ) return HTXS::HiggsProdMode::TH;
+          if (prodMode=="THQB" ) { th_type = HTXS::tH_type::THQB; return HTXS::HiggsProdMode::TH; }
+          if (prodMode=="WHT"  ) { th_type = HTXS::tH_type::TWH; return HTXS::HiggsProdMode::TH; }
+        }
+      }
+    }
+    // This is perfectly fine if we aren't running on a Higgs sample
+    ATH_MSG_INFO("Did not manage to extract Higgs production mode for MC channel number " << 
+                    mc_channel_number << ". HTXS categorization will hence not be derived.");
+    return HTXS::HiggsProdMode::UNKNOWN;
+  }
+
+  float TruthCategoriesDecorator::getFloatDecor(const std::string key, const TLorentzVector p4) const {
+    if(key.find("_pt")!=std::string::npos) return p4.Pt()*CLHEP::GeV;
+    else if(key.find("_eta")!=std::string::npos) return p4.Eta();
+    else if(key.find("_phi")!=std::string::npos) return p4.Phi();
+    else return p4.M()*CLHEP::GeV;
+  }
+
+  std::vector<float> TruthCategoriesDecorator::getVectorFloatDecor(const std::string key, const std::vector<TLorentzVector> p4s) const {
+    std::vector<float> vec;
+    if(key.find("_pt")!=std::string::npos){
+      for (auto p4:p4s) vec.push_back(p4.Pt()*CLHEP::GeV);
+    }
+    else if(key.find("_eta")!=std::string::npos){
+      for (auto p4:p4s) vec.push_back(p4.Eta());
+    }
+    else if(key.find("_phi")!=std::string::npos){
+      for (auto p4:p4s) vec.push_back(p4.Phi());
+    }
+    else if(key.find("_m")!=std::string::npos){
+      for (auto p4:p4s) vec.push_back(p4.M()*CLHEP::GeV);
+    }
+    return vec;
+  }
+
+
+  StatusCode TruthCategoriesDecorator::addBranches() const{
+
+    // Get a handle so we can retrieve the eventInfo information
+    SG::WriteDecorHandle<xAOD::EventInfo, int> prodModeHandle(m_eventInfoIntDecors.at(0));
+
+    // Extract the prodocution mode the first time 
+    static bool first = true;
+    static HTXS::HiggsProdMode prodMode = HTXS::HiggsProdMode::UNKNOWN;
+    static HTXS::tH_type th_type = HTXS::tH_type::noTH;
+    if (first) {
+      uint32_t mcChannelNumber = prodModeHandle->mcChannelNumber();
+      if(mcChannelNumber==0) mcChannelNumber = prodModeHandle->runNumber(); // EVNT input
+      prodMode = getHiggsProductionMode(mcChannelNumber,th_type);
+      first = false;
+    }
+
+    // If the production mode is unkown, the categorization will return -99
+    // Set HTXS_prodMode decoration to indicate that HTXS categorization was indeed run
+    if ( prodMode == HTXS::HiggsProdMode::UNKNOWN) {
+      //cheating a bit here, prodMode is the first decorator
+      prodModeHandle(0) = (int)prodMode;
+      return StatusCode::SUCCESS;
+    }
+
+    // Retrieve the xAOD truth
+    SG::ReadHandle<xAOD::TruthEventContainer> truthEventCont(m_truthEventCont);
+
+    // convert xAOD -> HepMC
+    std::vector<HepMC::GenEvent> hepmc_evts = m_xAODtoHepMCTool->getHepMCEvents( truthEventCont.cptr(), prodModeHandle.cptr() );
+
+    if (hepmc_evts.size()==0) {
+      // ANGRY MESSAGE HERE
+      return StatusCode::FAILURE;
+    }
+
+    // classify event according to simplified template cross section
+    HTXS::HiggsClassification *htxs =  m_higgsTruthCatTool->getHiggsTruthCategoryObject(hepmc_evts[0],prodMode);
+
+    // Decorate
+    prodModeHandle(0)=(int)htxs->prodMode;
+    for( auto& key : m_eventInfoIntDecors){
+      //already did this one
+      if(key.key().find("HTXS_prodMode")!=std::string::npos) continue;
+      SG::WriteDecorHandle<xAOD::EventInfo, int> handle(key);
+      if(key.key().find("HTXS_errorCode")!=std::string::npos) handle(0) = (int)htxs->errorCode;
+      else if(key.key().find("HTXS_Stage0_Category")!=std::string::npos) handle(0) = (int)htxs->stage0_cat;
+      // Stage-1 binning
+      else if(key.key().find("HTXS_Stage1_Category_pTjet25")!=std::string::npos) handle(0) = (int)htxs->stage1_cat_pTjet25GeV;
+      else if(key.key().find("HTXS_Stage1_Category_pTjet30")!=std::string::npos) handle(0) = (int)htxs->stage1_cat_pTjet30GeV;
+      else if(key.key().find("HTXS_Stage1_FineIndex_pTjet25")!=std::string::npos) handle(0) = HTXSstage1_to_HTXSstage1FineIndex(*htxs,th_type);
+      else if(key.key().find("HTXS_Stage1_FineIndex_pTjet30")!=std::string::npos) handle(0) = HTXSstage1_to_HTXSstage1FineIndex(*htxs,th_type,true);
+      // Stage-1.2 binning
+      else if(key.key().find("HTXS_Stage1_2_Category_pTjet25")!=std::string::npos) handle(0) = (int)htxs->stage1_2_cat_pTjet25GeV;
+      else if(key.key().find("HTXS_Stage1_2_Category_pTjet30")!=std::string::npos) handle(0) = (int)htxs->stage1_2_cat_pTjet30GeV;
+      else if(key.key().find("HTXS_Stage1_2_FineIndex_pTjet25")!=std::string::npos) handle(0) = HTXSstage1_2_to_HTXSstage1_2_FineIndex(*htxs,th_type);
+      else if(key.key().find("HTXS_Stage1_2_FineIndex_pTjet30")!=std::string::npos) handle(0) = HTXSstage1_2_to_HTXSstage1_2_FineIndex(*htxs,th_type,true);
+      // Stage-1.2 finer binning
+      else if(key.key().find("HTXS_Stage1_2_Fine_Category_pTjet25")!=std::string::npos) handle(0) = (int)htxs->stage1_2_fine_cat_pTjet25GeV;
+      else if(key.key().find("HTXS_Stage1_2_Fine_Category_pTjet30")!=std::string::npos) handle(0) = (int)htxs->stage1_2_fine_cat_pTjet30GeV;
+      else if(key.key().find("HTXS_Stage1_2_Fine_FineIndex_pTjet25")!=std::string::npos) handle(0) = HTXSstage1_2_Fine_to_HTXSstage1_2_Fine_FineIndex(*htxs,th_type);
+      else if(key.key().find("HTXS_Stage1_2_Fine_FineIndex_pTjet30")!=std::string::npos) handle(0) = HTXSstage1_2_Fine_to_HTXSstage1_2_Fine_FineIndex(*htxs,th_type,true);
+      //Njets
+      else if(key.key().find("HTXS_Njets_pTjet25")!=std::string::npos) handle(0) = (int)htxs->jets25.size();
+      else if(key.key().find("HTXS_Njets_pTjet30")!=std::string::npos) handle(0) = (int)htxs->jets30.size();
+      else if(key.key().find("HTXS_isZ2vvDecay")!=std::string::npos) handle(0) = (bool)htxs->isZ2vvDecay;
+    }
+    for( auto& key : m_eventInfoFloatDecors){
+      SG::WriteDecorHandle<xAOD::EventInfo, float> handle(key);
+      // At the very least, save the Higgs boson pT
+      if(key.key().find("HTXS_Higgs_pt")!=std::string::npos){
+	if (m_detailLevel==0) handle(0) = htxs->higgs.Pt()*CLHEP::GeV;
+      }
+      // The Higgs and the associated V (last instances prior to decay)
+      else if(key.key().find("HTXS_Higgs")!=std::string::npos && key.key().find("decay")==std::string::npos){
+	if (m_detailLevel>0) handle(0)=getFloatDecor(key.key(),htxs->higgs);
+      }
+      else if(key.key().find("HTXS_V")!=std::string::npos && key.key().find("decay")==std::string::npos && key.key().find("jets")==std::string::npos){
+	if (m_detailLevel>0) handle(0)=getFloatDecor(key.key(),htxs->V);
+      }
+      // Everybody might not want this ... but good for validation
+      else if(key.key().find("HTXS_Higgs_decay")!=std::string::npos){
+	if (m_detailLevel>2) handle(0)=getFloatDecor(key.key(),htxs->p4decay_higgs);
+      }
+      else if(key.key().find("HTXS_V_decay")!=std::string::npos){
+	if (m_detailLevel>2) handle(0)=getFloatDecor(key.key(),htxs->p4decay_V);
+      }
+    }
+    for( auto& key : m_eventInfoVectorFloatDecors){
+      SG::WriteDecorHandle<xAOD::EventInfo, std::vector<float> > handle(key);
+      // Jets built excluding Higgs decay products
+      if(key.key().find("HTXS_V_jets25")!=std::string::npos){
+	if (m_detailLevel>1) handle(0)=getVectorFloatDecor(key.key(),htxs->jets25);
+      }
+      else if(key.key().find("HTXS_V_jets30")!=std::string::npos){
+        if (m_detailLevel>1) handle(0)=getVectorFloatDecor(key.key(),htxs->jets30);
+      }
+    }
+
+    delete htxs;
+
+    return StatusCode::SUCCESS;
+
+  } // addBranches
+  
+} // namespace
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/src/components/DerivationFrameworkHiggs_entries.cxx b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/src/components/DerivationFrameworkHiggs_entries.cxx
index f57ec57c534e..4df39e7add8c 100644
--- a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/src/components/DerivationFrameworkHiggs_entries.cxx
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkHiggs/src/components/DerivationFrameworkHiggs_entries.cxx
@@ -1,9 +1,11 @@
 #include "DerivationFrameworkHiggs/SkimmingToolHIGG1.h"
 #include "DerivationFrameworkHiggs/SkimmingToolHIGG2.h"
 #include "DerivationFrameworkHiggs/SkimmingToolHIGG5VBF.h"
+#include "DerivationFrameworkHiggs/TruthCategoriesDecorator.h"
 using namespace DerivationFramework;
 
 DECLARE_COMPONENT( SkimmingToolHIGG1 )
 DECLARE_COMPONENT( SkimmingToolHIGG2 )
 DECLARE_COMPONENT( SkimmingToolHIGG5VBF )
+DECLARE_COMPONENT( TruthCategoriesDecorator )
 
-- 
GitLab