diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/CMakeLists.txt b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/CMakeLists.txt
index 0d50f59a1331e80b609709aec7fbe756ab508327..4d703be048a6917beb4a40bca3b01b13c439279d 100644
--- a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/CMakeLists.txt
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/CMakeLists.txt
@@ -13,7 +13,7 @@ find_package( Boost )
 atlas_add_component( DerivationFrameworkMCTruth
                      src/*.cxx src/components/*.cxx
                      INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${FASTJET_INCLUDE_DIRS} ${HEPPDT_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
-                     LINK_LIBRARIES ${Boost_LIBRARIES} ${FASTJET_LIBRARIES} ${HEPPDT_LIBRARIES} ${ROOT_LIBRARIES} AthenaBaseComps AthenaKernel AtlasHepMCLib DerivationFrameworkInterfaces ExpressionEvaluationLib GaudiKernel GeneratorObjects MCTruthClassifierLib StoreGateLib TauAnalysisToolsLib TruthUtils xAODBase xAODEgamma xAODEventInfo xAODJet xAODMuon xAODTruth )
+                     LINK_LIBRARIES ${Boost_LIBRARIES} ${FASTJET_LIBRARIES} ${HEPPDT_LIBRARIES} ${ROOT_LIBRARIES} AthenaBaseComps AthenaKernel AtlasHepMCLib DerivationFrameworkInterfaces ExpressionEvaluationLib GaudiKernel GenInterfacesLib GeneratorObjects MCTruthClassifierLib StoreGateLib TauAnalysisToolsLib TruthUtils xAODBase xAODEgamma xAODEventInfo xAODEventShape xAODJet xAODMuon xAODTruth )
 
 # Install files from the package:
 atlas_install_python_modules( python/*.py )
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/python/GenFilterToolSetup.py b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/python/GenFilterToolSetup.py
index 530c5165733bbe97ce44a62df685ddc83512f021..6e46b304e038338e7bb18b6b92cc6bdb1d34fdca 100644
--- a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/python/GenFilterToolSetup.py
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/python/GenFilterToolSetup.py
@@ -11,8 +11,8 @@ if not hasattr(ToolSvc,'DFCommonTruthClassifier'):
     ToolSvc += DFCommonTruthClassifier
 
 #Save the post-shower HT and MET filter values that will make combining filtered samples easier (adds to the EventInfo)
-#from AthenaCommon import CfgMgr
-#DFCommonTruthGenFilter = CfgMgr.DerivationFramework__GenFilterTool(
-#  "DFCommonTruthGenFilt",
-#  )
-#ToolSvc += DFCommonTruthGenFilter
+from AthenaCommon import CfgMgr
+DFCommonTruthGenFilter = CfgMgr.DerivationFramework__GenFilterTool(
+  "DFCommonTruthGenFilt",
+  )
+ToolSvc += DFCommonTruthGenFilter
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/GenFilterTool.cxx b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/GenFilterTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5c2b9c64d6b4f80bfb1fbfb91f5e3ab4bee1c007
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/GenFilterTool.cxx
@@ -0,0 +1,230 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Class header file
+#include "GenFilterTool.h"
+
+// EDM includes
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODJet/JetContainer.h"
+
+// Tool handle interface
+#include "MCTruthClassifier/IMCTruthClassifier.h"
+
+namespace DerivationFramework {
+
+  using namespace MCTruthPartClassifier;
+
+  static bool isNonInteracting(int pid) {
+    const int apid = abs(pid);
+    if (apid == 12 || apid == 14 || apid == 16) return true; //< neutrinos
+    if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
+    if (apid == 39 || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
+    if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
+    return false;
+  }
+
+  static SG::AuxElement::Decorator<float> dec_genFiltHT("GenFiltHT");
+  static SG::AuxElement::Decorator<float> dec_genFiltMET("GenFiltMET");
+  static SG::AuxElement::Decorator<float> dec_genFiltPTZ("GenFiltPTZ");
+  static SG::AuxElement::Decorator<float> dec_genFiltFatJ("GenFiltFatJ");
+
+  GenFilterTool::GenFilterTool(const std::string& t, const std::string& n, const IInterface* p)
+    : AthAlgTool(t,n,p)
+    , m_classif("MCTruthClassifier/DFCommonTruthClassifier")
+  {
+
+    declareInterface<DerivationFramework::IAugmentationTool>(this);
+
+    declareProperty("EventInfoName",m_eventInfoName="EventInfo");
+    declareProperty("MCCollectionName",m_mcName="TruthParticles");
+    declareProperty("TruthJetCollectionName",m_truthJetsName="AntiKt4TruthWZJets");
+    declareProperty("MinJetPt",m_MinJetPt = 35e3);
+    declareProperty("MaxJetEta",m_MaxJetEta = 2.5);
+    declareProperty("MinLeptonPt",m_MinLepPt = 25e3);
+    declareProperty("MaxLeptonEta",m_MaxLepEta = 2.5);
+    declareProperty("SimBarcodeOffset", m_SimBarcodeOffset = 200000);
+  }
+
+
+  GenFilterTool::~GenFilterTool(){}
+
+
+  bool GenFilterTool::isPrompt( const xAOD::TruthParticle* tp ) const
+  {
+    ParticleOrigin orig = getPartOrigin(tp);
+    ATH_MSG_VERBOSE("Particle has origin " << orig);
+
+    switch(orig) {
+    case Unknown:
+    case PhotonConv:
+    case DalitzDec:
+    case ElMagProc:
+    case Mu:
+    case LightMeson:
+    case StrangeMeson:
+    case CharmedMeson:
+    case BottomMeson:
+    case CCbarMeson:
+    case JPsi:
+    case BBbarMeson:
+    case LightBaryon:
+    case StrangeBaryon:
+    case CharmedBaryon:
+    case BottomBaryon:
+    case PionDecay:
+    case KaonDecay:
+      return false;
+    default:
+      break;
+    }
+    return true;
+  }
+
+  MCTruthPartClassifier::ParticleOrigin GenFilterTool::getPartOrigin( const xAOD::TruthParticle* tp ) const
+  {
+    if(m_originMap.find(tp)==m_originMap.end()) {
+      std::pair<ParticleType, ParticleOrigin> classification = m_classif->particleTruthClassifier( tp );
+      m_originMap[tp] = classification.second;
+    }
+    return m_originMap[tp];
+  }
+
+
+  StatusCode GenFilterTool::addBranches() const{
+    ATH_MSG_VERBOSE("GenFilterTool::addBranches()");
+
+    const xAOD::EventInfo* eventInfo;
+    if (evtStore()->retrieve(eventInfo,m_eventInfoName).isFailure()) {
+      ATH_MSG_ERROR("could not retrieve event info " <<m_eventInfoName);
+      return StatusCode::FAILURE;
+    }
+
+    const xAOD::TruthParticleContainer* truthPC = 0;
+    if (evtStore()->retrieve(truthPC,m_mcName).isFailure()) {
+      ATH_MSG_ERROR("WARNING could not retrieve TruthParticleContainer " <<m_mcName);
+      return StatusCode::FAILURE;
+    }
+
+    m_originMap.clear();
+
+    float genFiltHT(0.), genFiltMET(0.), genFiltPTZ(0.), genFiltFatJ(0.);
+    ATH_CHECK( getGenFiltVars(truthPC, genFiltHT, genFiltMET, genFiltPTZ, genFiltFatJ) );
+
+    ATH_MSG_DEBUG("Computed generator filter quantities: HT " << genFiltHT/1e3 << ", MET " << genFiltMET/1e3 << ", PTZ " << genFiltPTZ/1e3 << ", FatJ " << genFiltFatJ/1e3 );
+
+    dec_genFiltHT(*eventInfo) = genFiltHT;
+    dec_genFiltMET(*eventInfo) = genFiltMET;
+    dec_genFiltPTZ(*eventInfo) = genFiltPTZ;
+    dec_genFiltFatJ(*eventInfo) = genFiltFatJ;
+
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode GenFilterTool::getGenFiltVars(const xAOD::TruthParticleContainer* tpc, float& genFiltHT, float& genFiltMET, float& genFiltPTZ, float& genFiltFatJ) const {
+    // Get jet container out
+    const xAOD::JetContainer* truthjets = 0;
+    if ( evtStore()->retrieve( truthjets, m_truthJetsName).isFailure() || !truthjets ){
+      ATH_MSG_ERROR( "No xAOD::JetContainer found in StoreGate with key " << m_truthJetsName );
+      return StatusCode::FAILURE;
+    }
+
+    // Get HT
+    genFiltHT = 0.;
+    for (const auto& tj : *truthjets) {
+      if ( tj->pt()>m_MinJetPt && fabs(tj->eta())<m_MaxJetEta ) {
+        ATH_MSG_VERBOSE("Adding truth jet with pt " << tj->pt()
+                        << ", eta " << tj->eta()
+                        << ", phi " << tj->phi()
+                        << ", nconst = " << tj->numConstituents());
+        genFiltHT += tj->pt();
+      }
+    }
+
+    // Get MET and add leptons to HT
+    float MEx(0.), MEy(0.);
+    for (const auto& tp : *tpc){
+      int pdgid = tp->pdgId();
+      if (tp->barcode() >= m_SimBarcodeOffset) continue; // Particle is from G4
+      if (pdgid==21 && tp->e()==0) continue; // Work around for an old generator bug
+      if ( tp->status() %1000 !=1 ) continue; // Stable!
+
+      if ((abs(pdgid)==11 || abs(pdgid)==13) && tp->pt()>m_MinLepPt && fabs(tp->eta())<m_MaxLepEta) {
+        if( isPrompt(tp) ) {
+          ATH_MSG_VERBOSE("Adding prompt lepton with pt " << tp->pt()
+                          << ", eta " << tp->eta()
+                          << ", phi " << tp->phi()
+                          << ", status " << tp->status()
+                          << ", pdgId " << pdgid);
+          genFiltHT += tp->pt();
+        }
+      }
+
+      if (isNonInteracting(pdgid) && isPrompt(tp) ) {
+        ATH_MSG_VERBOSE("Found prompt nonInteracting particle with pt " << tp->pt()
+                        << ", eta " << tp->eta()
+                        << ", phi " << tp->phi()
+                        << ", status " << tp->status()
+                        << ", pdgId " << pdgid);
+        MEx += tp->px();
+        MEy += tp->py();
+      }
+    }
+    genFiltMET = sqrt(MEx*MEx+MEy*MEy);
+
+    // Get PTZ
+    float PtZ(.0);
+    float MinPt_PTZ(5000.), MaxEta_PTZ(5.0), MinMass_PTZ(20000.), MaxMass_PTZ(14000000.);
+    bool AllowElecMu_PTZ = false;
+    bool AllowSameCharge_PTZ = false;
+    for (const xAOD::TruthParticle* pitr1 : *tpc){
+      int pdgId1 = pitr1->pdgId();
+      if (pitr1->barcode() >= m_SimBarcodeOffset) continue;
+      if (pitr1->status()!=1) continue;
+      // Pick electrons or muons with Pt > MinPt_PTZ and |eta| < m_maxEta
+      if (abs(pdgId1) == 11 || abs(pdgId1) == 13) {
+        if (pitr1->pt() >= MinPt_PTZ && fabs(pitr1->eta()) <= MaxEta_PTZ){
+          for (const xAOD::TruthParticle* pitr2 : *tpc){
+            if (pitr2==pitr1) continue;
+            if (pitr2->barcode() >= m_SimBarcodeOffset) continue;
+            if (pitr2->status()!=1) continue;
+            int pdgId2 = pitr2->pdgId();
+            // Pick electrons or muons with Pt > MinPt_PTZ and |eta| < MaxEta_PTZ
+            // If AllowSameCharge_PTZ is not true only pick those with opposite charge to the first particle
+            // If AllowElecMu_PTZ is true allow also Z -> emu compinations (with charge requirements as above)
+            if ((AllowSameCharge_PTZ  && (abs(pdgId2) == abs(pdgId1) || (AllowElecMu_PTZ && (abs(pdgId2) == 11 || abs(pdgId2) == 13) ) ) ) ||
+                (!AllowSameCharge_PTZ && (pdgId2 == -1*pdgId1 || (AllowElecMu_PTZ && (pdgId2 == (pdgId1 < 0 ? 1 : -1) * 11 || (pdgId1 < 0 ? 1 : -1) * pdgId2 == 13) ) ) ) ) {
+              if (pitr2->pt() >= MinPt_PTZ && fabs(pitr2->eta()) <= MaxEta_PTZ){
+                double invMass = (pitr1->p4()+pitr2->p4()).M();
+                double dilepPt = (pitr1->p4()+pitr2->p4()).Pt();
+                // Only consider pair that fall in the mass window
+                if (MinMass_PTZ < invMass && invMass < MaxMass_PTZ) {
+                  if (dilepPt > PtZ) PtZ = dilepPt;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    genFiltPTZ = PtZ;
+
+   //Get FatJ
+   // Get correct jet container
+   const xAOD::JetContainer* truthjets10 = 0;
+   if ( evtStore()->retrieve( truthjets10, "AntiKt10TruthJets").isFailure() || !truthjets10 ){
+     ATH_MSG_ERROR( "No xAOD::JetContainer found in StoreGate with key AntiKt10TruthJets" );
+     return StatusCode::FAILURE;
+   }
+   genFiltFatJ=0.;
+   for (const auto& j : *truthjets10) {
+     if (j->pt()>genFiltFatJ) genFiltFatJ=j->pt();
+   }
+
+
+    return StatusCode::SUCCESS;
+  }
+
+
+} /// namespace
\ No newline at end of file
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/GenFilterTool.h b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/GenFilterTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..68cf1c780247bd192d5868f69e701185bdbd4e8b
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/GenFilterTool.h
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * @file GenFilterTool.h
+ * @author TJ Khoo
+ * @date July 2015
+ * @brief tool to decorate EventInfo with quantities needed to disentangle generator filtered samples
+*/
+
+#ifndef DerivationFrameworkMCTruth_GenFilterTool_H
+#define DerivationFrameworkMCTruth_GenFilterTool_H
+
+// Base classes
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "DerivationFrameworkInterfaces/IAugmentationTool.h"
+
+// Tool handle for the MC truth classifier
+#include "GaudiKernel/ToolHandle.h"
+
+// EDM include -- typedef, so has to be included
+#include "xAODTruth/TruthParticleContainer.h"
+
+// Defs for the particle origin
+#include "MCTruthClassifier/MCTruthClassifierDefs.h"
+
+// STL includes
+#include <string>
+
+class IMCTruthClassifier;
+
+namespace DerivationFramework {
+
+  class GenFilterTool : public AthAlgTool, public IAugmentationTool {
+
+  public:
+    GenFilterTool(const std::string& t, const std::string& n, const IInterface* p);
+    ~GenFilterTool();
+    virtual StatusCode addBranches() const;
+
+    StatusCode getGenFiltVars(const xAOD::TruthParticleContainer* tpc, float& genFiltHT, float& genFiltMET, float& genFiltPTZ, float& genFiltFatJ) const;
+
+    bool isPrompt( const xAOD::TruthParticle* tp ) const;
+    MCTruthPartClassifier::ParticleOrigin getPartOrigin(const xAOD::TruthParticle* tp) const;
+
+  private:
+
+    std::string m_eventInfoName;
+    std::string m_mcName;
+    std::string m_truthJetsName;
+
+    float m_MinJetPt;  //!< Min pT for the truth jets
+    float m_MaxJetEta; //!< Max eta for the truth jets
+    float m_MinLepPt;  //!< Min pT for the truth leptons
+    float m_MaxLepEta; //!< Max eta for the truth leptons
+    int m_SimBarcodeOffset; //!< G4 particle barcode offset value (Particles having a barcode greater than this value are defined to be G4 particles)
+
+    mutable std::map<const xAOD::TruthParticle*,MCTruthPartClassifier::ParticleOrigin> m_originMap;
+    ToolHandle<IMCTruthClassifier> m_classif;
+  }; /// class
+
+} /// namespace
+
+#endif
\ No newline at end of file
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthEDDecorator.cxx b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthEDDecorator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f6859a93176cea04a586ba52b8a7fce301231d41
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthEDDecorator.cxx
@@ -0,0 +1,59 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// Class header file
+#include "TruthEDDecorator.h"
+
+// EDM includes
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODEventShape/EventShape.h"
+
+namespace DerivationFramework {
+
+  static const SG::AuxElement::Accessor<float> acc_Density("Density");
+
+  TruthEDDecorator::TruthEDDecorator(const std::string& t, const std::string& n, const IInterface* p)
+    : AthAlgTool(t,n,p)
+  {
+    declareInterface<DerivationFramework::IAugmentationTool>(this);
+    
+    declareProperty("EventInfoName",m_eventInfoName="EventInfo");
+    declareProperty("EnergyDensityKeys",m_edKeys={"TruthIsoCentralEventShape","TruthIsoForwardEventShape"});
+    declareProperty("DecorationSuffix",m_ed_suffix="_rho");
+  }
+
+
+  TruthEDDecorator::~TruthEDDecorator(){}
+
+
+  StatusCode TruthEDDecorator::initialize(){
+    for (size_t i=0;i<m_edKeys.size();++i){
+      m_dec_eventShape.push_back( SG::AuxElement::Decorator<float>(m_edKeys[i]+m_ed_suffix) );
+    }
+    return StatusCode::SUCCESS;
+  }
+
+
+  StatusCode TruthEDDecorator::addBranches() const{
+    ATH_MSG_VERBOSE("addBranches()");
+
+    // Get the event info that we will decorate onto
+    const xAOD::EventInfo* eventInfo(nullptr);
+    if (evtStore()->retrieve(eventInfo,m_eventInfoName).isFailure()) {
+      ATH_MSG_ERROR("could not retrieve event info " <<m_eventInfoName);
+      return StatusCode::FAILURE;
+    }
+
+    const xAOD::EventShape* eventShape(nullptr);
+    for (size_t i=0;i<m_edKeys.size();++i){
+      // Get the event shapes from which we'll get the densities
+      ATH_CHECK( evtStore()->retrieve(eventShape,m_edKeys[i]) );
+      // Decorate the densities onto the event info
+      m_dec_eventShape[i](*eventInfo) = acc_Density(*eventShape);
+    }
+
+    return StatusCode::SUCCESS;
+  }
+
+} /// namespace
\ No newline at end of file
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthEDDecorator.h b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthEDDecorator.h
new file mode 100644
index 0000000000000000000000000000000000000000..f1c991fa32f1c50f0952257ec668405291827090
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthEDDecorator.h
@@ -0,0 +1,45 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * @file TruthEDDecorator.h
+ * @author Zach Marshall
+ * @date Nov 2019
+ * @brief tool to decorate EventInfo with truth-level energy density
+*/
+
+#ifndef DerivationFrameworkMCTruth_TruthEDDecorator_H
+#define DerivationFrameworkMCTruth_TruthEDDecorator_H
+
+// Base classes
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "DerivationFrameworkInterfaces/IAugmentationTool.h"
+
+// Members
+#include "AthContainers/AuxElement.h"
+
+// STL includes
+#include <string>
+#include <vector>
+
+namespace DerivationFramework {
+
+  class TruthEDDecorator : public AthAlgTool, public IAugmentationTool {
+
+  public:
+    TruthEDDecorator(const std::string& t, const std::string& n, const IInterface* p);
+    ~TruthEDDecorator();
+    virtual StatusCode addBranches() const override final;
+    StatusCode initialize() override final;
+
+  private:
+    std::string m_eventInfoName;
+    std::vector<std::string> m_edKeys;
+    std::string m_ed_suffix;
+    std::vector<SG::AuxElement::Decorator<float> > m_dec_eventShape;
+  }; /// class
+
+} /// namespace
+
+#endif
\ No newline at end of file
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthMetaDataWriter.cxx b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthMetaDataWriter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1ace75c810dcf70698d6cd0d7247c5e32ebcf69e
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthMetaDataWriter.cxx
@@ -0,0 +1,136 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+/////////////////////////////////////////////////////////////////
+// TruthMetaDataWriter.cxx
+// Author: James Catmore (James.Catmore@cern.ch)
+
+// Header for this class
+#include "TruthMetaDataWriter.h"
+
+// EDM Objects that we need
+#include "xAODTruth/TruthMetaData.h"
+#include "xAODTruth/TruthMetaDataAuxContainer.h"
+#include "xAODEventInfo/EventInfo.h"
+
+// For accessing the tagInfo
+#include "AthenaPoolUtilities/CondAttrListCollection.h"
+
+// Service for the weights
+#include "GenInterfaces/IHepMCWeightSvc.h"
+
+// Constructor
+DerivationFramework::TruthMetaDataWriter::TruthMetaDataWriter(const std::string& t,
+                                                              const std::string& n,
+                                                              const IInterface* p)
+  : AthAlgTool(t,n,p)
+  , m_metaStore( "MetaDataStore", n )
+  , m_weightSvc( "HepMCWeightSvc/HepMCWeightSvc" , n )
+{
+    declareInterface<DerivationFramework::IAugmentationTool>(this);
+    declareProperty( "MetaObjectName", m_metaName = "TruthMetaData" );
+    declareProperty( "MetaDataStore", m_metaStore );
+}
+
+// Destructor
+DerivationFramework::TruthMetaDataWriter::~TruthMetaDataWriter() {
+}
+
+// Athena initialize and finalize
+StatusCode DerivationFramework::TruthMetaDataWriter::initialize()
+{
+    ATH_MSG_VERBOSE("initialize() ...");
+    // Initialize the service handles
+    CHECK( m_metaStore.retrieve() );
+    CHECK( m_weightSvc.retrieve() );
+
+    // Create an empty truth meta data container:
+    xAOD::TruthMetaDataAuxContainer* aux = new xAOD::TruthMetaDataAuxContainer();
+    m_tmd = new xAOD::TruthMetaDataContainer();
+    m_tmd->setStore( aux );
+    // Record it in the metadata store
+    CHECK( m_metaStore->record( aux, m_metaName + "Aux." ) );
+    CHECK( m_metaStore->record( m_tmd, m_metaName ) );
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode DerivationFramework::TruthMetaDataWriter::finalize()
+{
+    ATH_MSG_VERBOSE("finalize() ...");
+    return StatusCode::SUCCESS;
+}
+
+// Selection and collection creation
+StatusCode DerivationFramework::TruthMetaDataWriter::addBranches() const
+{
+
+    //The mcChannelNumber is used as a unique identifier for which truth meta data belongs to
+    uint32_t mcChannelNumber = 0;
+    // If this fails, we are running on a datatype with no EventInfo.  Such data types should
+    //  definitely not be mixing MC samples, so this should be safe (will fall back to 0 above)
+    if (evtStore()->contains<xAOD::EventInfo>("EventInfo")){
+      const DataHandle<xAOD::EventInfo> eventInfo = nullptr;
+      CHECK( evtStore()->retrieve(eventInfo, "EventInfo") );
+      mcChannelNumber = eventInfo->mcChannelNumber();
+    }
+
+    //Inserting in a (unordered_)set returns an <iterator, boolean> pair, where the boolean
+    //is used to check if the key already exists (returns false in the case it exists)
+    if( m_existingMetaDataChan.insert(mcChannelNumber).second ) {
+        xAOD::TruthMetaData* md = new xAOD::TruthMetaData();
+        m_tmd->push_back( md );
+
+        // Get the list of weights from the metadata
+        std::map<std::string,std::size_t> weight_name_map = m_weightSvc->weightNames();
+
+        std::vector<std::string> orderedWeightNameVec;
+        orderedWeightNameVec.reserve( weight_name_map.size() );
+        for (auto& entry: weight_name_map) {
+            orderedWeightNameVec.push_back(entry.first);
+        }
+
+        //The map from the HepMC record pairs the weight names with a corresponding index,
+        //it is not guaranteed that the indices are ascending when iterating over the map
+        std::sort(orderedWeightNameVec.begin(), orderedWeightNameVec.end(),
+                  [&](std::string i, std::string j){return weight_name_map.at(i) < weight_name_map.at(j);});
+
+        md->setMcChannelNumber(mcChannelNumber);
+        md->setWeightNames( std::move(orderedWeightNameVec) );
+
+        // Shamelessly stolen from the file meta data tool
+        const CondAttrListCollection* tagInfo(nullptr);
+        ATH_CHECK( detStore()->retrieve( tagInfo, "/TagInfo" ) );
+
+        // Access the first, and only channel of the object:
+        const CondAttrListCollection::AttributeList& al = tagInfo->attributeList( 0 );
+
+        if (al.exists("lhefGenerator")){
+            md->setLhefGenerator( al["lhefGenerator"].data< std::string >() );
+        }
+
+        if (al.exists("generators")){
+            md->setGenerators( al["generators"].data< std::string >() );
+        }
+
+        if (al.exists("evgenProcess")){
+            md->setEvgenProcess( al["evgenProcess"].data< std::string >() );
+        }
+
+        if (al.exists("evgenTune")){
+            md->setEvgenTune( al["evgenTune"].data< std::string >() );
+        }
+
+        if (al.exists("hardPDF")){
+            md->setHardPDF( al["hardPDF"].data< std::string >() );
+        }
+
+        if (al.exists("softPDF")){
+            md->setSoftPDF( al["softPDF"].data< std::string >() );
+        }
+        // Done getting things from the TagInfo
+
+    } // Done making the new truth metadata object
+    return StatusCode::SUCCESS;
+}
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthMetaDataWriter.h b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthMetaDataWriter.h
new file mode 100644
index 0000000000000000000000000000000000000000..56f254c80212e3d574d76e0ccc411b995c60bcae
--- /dev/null
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/TruthMetaDataWriter.h
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef DERIVATIONFRAMEWORK_TRUTHMETADATAWRITER_H
+#define DERIVATIONFRAMEWORK_TRUTHMETADATAWRITER_H
+
+// Base classes
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "DerivationFrameworkInterfaces/IAugmentationTool.h"
+
+// Handles to services
+#include "GaudiKernel/ServiceHandle.h"
+
+// EDM classes - typedefs, so have to #include them
+#include "xAODTruth/TruthMetaDataContainer.h"
+
+// Standard library includes
+#include <string>
+#include <unordered_set>
+
+// Forward declarations
+class IHepMCWeightSvc;
+
+namespace DerivationFramework {
+
+  class TruthMetaDataWriter : public AthAlgTool, public IAugmentationTool {
+    public: 
+      TruthMetaDataWriter(const std::string& t, const std::string& n, const IInterface* p);
+      ~TruthMetaDataWriter();
+      StatusCode initialize();
+      StatusCode finalize();
+      virtual StatusCode addBranches() const;
+
+    private:
+      /// Connection to the metadata store
+      ServiceHandle< StoreGateSvc > m_metaStore;
+      /// Service for retrieving the weight names
+      ServiceHandle< IHepMCWeightSvc > m_weightSvc;
+      /// The meta data container to be written out
+      xAOD::TruthMetaDataContainer* m_tmd;
+      /// SG key and name for meta data
+      std::string m_metaName;
+      /// Set for tracking the mc channels for which we already added meta data
+      mutable std::unordered_set<uint32_t> m_existingMetaDataChan; 
+
+  }; 
+}
+
+#endif
\ No newline at end of file
diff --git a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/components/DerivationFrameworkMCTruth_entries.cxx b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/components/DerivationFrameworkMCTruth_entries.cxx
index 685652d2c4b96f8dfd27c961a9b86c5fcc13bc3f..71be27ae597c5e16ad83a021f1c82f7a75852f60 100644
--- a/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/components/DerivationFrameworkMCTruth_entries.cxx
+++ b/PhysicsAnalysis/DerivationFramework/DerivationFrameworkMCTruth/src/components/DerivationFrameworkMCTruth_entries.cxx
@@ -17,6 +17,9 @@
 #include "src/HardScatterCollectionMaker.h"
 #include "src/TruthLinkRepointTool.h"
 #include "DerivationFrameworkMCTruth/TruthPVCollectionMaker.h"
+#include "src/GenFilterTool.h"
+#include "src/TruthEDDecorator.h"
+#include "src/TruthMetaDataWriter.h"
 
 using namespace DerivationFramework;
 
@@ -39,3 +42,6 @@ DECLARE_COMPONENT( TruthBornLeptonCollectionMaker )
 DECLARE_COMPONENT( HardScatterCollectionMaker )
 DECLARE_COMPONENT( TruthLinkRepointTool )
 DECLARE_COMPONENT( TruthPVCollectionMaker )
+DECLARE_COMPONENT( GenFilterTool )
+DECLARE_COMPONENT( TruthEDDecorator )
+DECLARE_COMPONENT( TruthMetaDataWriter )