From c75e9332e2c5f88a6ab56a25fb58c498469640ad Mon Sep 17 00:00:00 2001
From: Tim Martin <tim.martin@cern.ch>
Date: Fri, 4 Sep 2020 16:12:25 +0000
Subject: [PATCH] Make TrigDecisionTool compile under AnalysisBase

---
 Projects/AnalysisBase/package_filters.txt     |   6 +-
 .../TrigDecisionTool/CMakeLists.txt           |  12 +-
 .../Root/CacheGlobalMemory.cxx                |  27 +-
 .../Root/DecisionObjectHandleStandalone.cxx   |   3 +
 .../TrigDecisionTool/Root/ExpertMethods.cxx   |  39 +-
 .../Root/TrigDecisionTool.cxx                 |  44 ++-
 .../Root/TrigDecisionToolCore.cxx             |  27 +-
 .../TrigDecisionTool/CacheGlobalMemory.h      |  20 +-
 .../TrigDecisionTool/DecisionAccess.h         |  11 +-
 .../DecisionObjectHandleStandalone.h          |   2 +-
 .../TrigDecisionTool/DecisionUnpackerAthena.h |   7 +-
 .../DecisionUnpackerStandalone.h              |   2 +-
 .../TrigDecisionTool/ExpertMethods.h          |  18 +-
 .../TrigDecisionTool/TrigDecisionTool.h       |  37 +-
 .../TrigDecisionTool/TrigDecisionToolCore.h   |   8 +-
 .../src/DecisionUnpackerAthena.cxx            |   2 +
 .../TrigDecisionEvent/TrigDecision.h          |   2 +-
 .../TrigSteeringEvent/CMakeLists.txt          |   2 +-
 .../TrigSteeringEvent/GenericResult.h         |   2 +-
 .../TrigSteeringEvent/HLTResult.h             |   8 +-
 .../TrigSteeringEvent/Lvl1Result.h            |   3 +-
 .../TrigSteeringEvent/src/HLTResult.cxx       |   1 -
 .../TrigCompositeUtils/CMakeLists.txt         |   9 +-
 .../{src => Root}/NavGraph.cxx                |   0
 .../Root/TrigCompositeUtils.cxx               | 369 +++++++++++++++++-
 .../TrigCompositeUtils/TrigCompositeUtils.h   |   8 +
 .../src/TrigCompositeUtils.cxx                | 356 -----------------
 27 files changed, 585 insertions(+), 440 deletions(-)
 rename Trigger/TrigSteer/TrigCompositeUtils/{src => Root}/NavGraph.cxx (100%)
 delete mode 100644 Trigger/TrigSteer/TrigCompositeUtils/src/TrigCompositeUtils.cxx

diff --git a/Projects/AnalysisBase/package_filters.txt b/Projects/AnalysisBase/package_filters.txt
index ac7fa92925a..e1865aa1233 100644
--- a/Projects/AnalysisBase/package_filters.txt
+++ b/Projects/AnalysisBase/package_filters.txt
@@ -121,9 +121,9 @@
 + Tools/PathResolver
 + Trigger/TrigAnalysis/TrigAnalysisInterfaces
 + Trigger/TrigAnalysis/TrigBunchCrossingTool
-#+ Trigger/TrigAnalysis/TrigDecisionTool
-#+ Trigger/TrigAnalysis/TrigTauAnalysis/TrigTauMatching
-#+ Trigger/TrigAnalysis/TriggerMatchingTool
++ Trigger/TrigAnalysis/TrigDecisionTool
++ Trigger/TrigAnalysis/TrigTauAnalysis/TrigTauMatching
++ Trigger/TrigAnalysis/TriggerMatchingTool
 + Trigger/TrigConfiguration/TrigConfBase
 + Trigger/TrigConfiguration/TrigConfHLTData
 + Trigger/TrigConfiguration/TrigConfHLTUtils
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/CMakeLists.txt b/Trigger/TrigAnalysis/TrigDecisionTool/CMakeLists.txt
index 3462185aecb..d4206f18c50 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/CMakeLists.txt
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/CMakeLists.txt
@@ -15,8 +15,10 @@ if( XAOD_STANDALONE )
       INCLUDE_DIRS ${Boost_INCLUDE_DIRS}
       PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
       LINK_LIBRARIES ${Boost_LIBRARIES} AsgTools xAODBase xAODTrigger
-      TrigConfHLTData TrigConfL1Data TrigNavStructure TrigRoiConversionLib TrigConfInterfaces
-      PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} TrigSteeringEvent )
+      TrigConfHLTData TrigConfL1Data TrigNavStructure TrigRoiConversionLib 
+      TrigConfInterfaces TrigDecisionInterface AsgDataHandlesLib 
+      TrigCompositeUtilsLib
+      PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} TrigSteeringEvent  )
 else()
    if( XAOD_ANALYSIS )
       atlas_add_library( TrigDecisionToolLib
@@ -26,8 +28,9 @@ else()
          PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
          LINK_LIBRARIES ${Boost_LIBRARIES} AsgTools EventInfo xAODBase
          xAODTrigger GaudiKernel TrigConfHLTData TrigConfL1Data
-         TrigNavStructure StoreGateLib TrigRoiConversionLib TrigCompositeUtilsLib  TrigConfInterfaces
-         PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps
+         TrigNavStructure StoreGateLib TrigRoiConversionLib TrigCompositeUtilsLib 
+         TrigConfInterfaces TrigDecisionEvent TrigDecisionInterface
+         PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps AsgDataHandlesLib 
          TrigSteeringEvent AthenaKernel )
    else()
       atlas_add_library( TrigDecisionToolLib
@@ -40,6 +43,7 @@ else()
          TrigConfL1Data TrigDecisionEvent TrigMuonEvent TrigNavStructure
          TrigStorageDefinitions StoreGateLib TrigNavigationLib
          TrigRoiConversionLib TrigCompositeUtilsLib TrigConfInterfaces
+         TrigDecisionInterface AsgDataHandlesLib
          PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} AthenaBaseComps
          TrigSteeringEvent AthenaKernel )
    endif()
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/Root/CacheGlobalMemory.cxx b/Trigger/TrigAnalysis/TrigDecisionTool/Root/CacheGlobalMemory.cxx
index 8f598bb1513..223dbd2c8ae 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/Root/CacheGlobalMemory.cxx
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/Root/CacheGlobalMemory.cxx
@@ -24,6 +24,8 @@
 #include "TrigConfHLTData/HLTSignature.h"
 #include "TrigNavStructure/TriggerElement.h"
 
+#include "AsgDataHandles/ReadHandle.h"
+
 #include "TrigSteeringEvent/Lvl1Item.h"
 
 #include "TrigDecisionTool/CacheGlobalMemory.h"
@@ -55,8 +57,10 @@ Trig::CacheGlobalMemory::CacheGlobalMemory() :
   m_confChains(nullptr),
   m_expressStreamContainer(nullptr),
   m_decisionKeyPtr(nullptr),
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
   m_oldDecisionKeyPtr(nullptr),
   m_oldEventInfoKeyPtr(nullptr),
+#endif
   m_navigationKeyPtr(nullptr),
   m_bgCode(0)
 {}
@@ -334,9 +338,12 @@ bool Trig::CacheGlobalMemory::assert_decision() {
 
   // here we unpack the decision. Note: the navigation will be unpacked only on demand (see navigation())
   bool contains_xAOD_decision = false;
+
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
   bool is_l1result_configured = false;
   bool contains_decision = false;
   bool contains_old_event_info = false;
+#endif
   
   if(!m_unpacker){
     ATH_MSG_INFO("decision not set on first (?) assert. deciding how to unpack");
@@ -352,7 +359,7 @@ bool Trig::CacheGlobalMemory::assert_decision() {
       contains_xAOD_decision = decisionReadHandle.isValid();
     }
 
-#ifndef XAOD_ANALYSIS
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
 
     if (!m_oldDecisionKeyPtr->empty()) {
       SG::ReadHandle<TrigDec::TrigDecision> oldDecisionReadHandle = SG::makeHandle(*m_oldDecisionKeyPtr, context);
@@ -391,12 +398,9 @@ bool Trig::CacheGlobalMemory::assert_decision() {
   }//if(!m_unpacker)
 
   if(!m_unpacker){
-    ATH_MSG_ERROR("No source of Trigger Decision in file. "
-      << "(Looked for xAOD::TrigDecision? "
-      << (m_decisionKeyPtr->empty() ? "NO" : "YES")
-      << ", has xAOD::TrigDecision? " 
-      << (contains_xAOD_decision ? "YES" : "NO")
-      << ". Looked for old TrigDec::TrigDecision? "
+    std::stringstream extra;
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
+    extra << ". Looked for old TrigDec::TrigDecision? "
       << (m_oldDecisionKeyPtr->empty() ? "NO" : "YES")
       << ", has TrigDec::TrigDecision? " 
       << (contains_decision ? "YES" : "NO")
@@ -405,7 +409,14 @@ bool Trig::CacheGlobalMemory::assert_decision() {
       << ". Looked for old EventInfo? "
       << (m_oldEventInfoKeyPtr->empty() ? "NO" : "YES")
       << ", has old EventInto? "  
-      << (contains_old_event_info ? "YES" : "NO")
+      << (contains_old_event_info ? "YES" : "NO");
+#endif
+    ATH_MSG_ERROR("No source of Trigger Decision in file. "
+      << "(Looked for xAOD::TrigDecision? "
+      << (m_decisionKeyPtr->empty() ? "NO" : "YES")
+      << ", has xAOD::TrigDecision? " 
+      << (contains_xAOD_decision ? "YES" : "NO")
+      << extra.str()
       << ". Check UseRun1DecisionFormat and UseOldEventInfoDecisionFormat flags if reading pre-xAOD or BS input).");
     throw std::runtime_error("Trig::CacheGlobalMemory::assert_decision(): No source of Trigger Decision in file.");
   }
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/Root/DecisionObjectHandleStandalone.cxx b/Trigger/TrigAnalysis/TrigDecisionTool/Root/DecisionObjectHandleStandalone.cxx
index 6a37ccb3d74..ad8b848c91e 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/Root/DecisionObjectHandleStandalone.cxx
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/Root/DecisionObjectHandleStandalone.cxx
@@ -7,6 +7,9 @@
 // Local include(s):
 #include "TrigDecisionTool/DecisionObjectHandleStandalone.h"
 
+#include "AsgTools/CurrentContext.h"
+#include "AsgDataHandles/ReadHandle.h"
+
 // Include for the event store type:
 #ifdef XAOD_STANDALONE
 #   include "AsgTools/SgTEvent.h"
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/Root/ExpertMethods.cxx b/Trigger/TrigAnalysis/TrigDecisionTool/Root/ExpertMethods.cxx
index 64052d3495c..20b6e5d0fcd 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/Root/ExpertMethods.cxx
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/Root/ExpertMethods.cxx
@@ -23,6 +23,8 @@
 #include "TrigNavigation/AccessProxy.h"
 #endif
 
+#include "AsgDataHandles/ReadHandle.h"
+
 #include "TrigSteeringEvent/Chain.h"
 #include "TrigConfHLTData/HLTSignature.h"
 #include "TrigConfHLTData/HLTTriggerElement.h"
@@ -33,12 +35,25 @@
 
 #include "xAODTrigger/TrigDecision.h"
 
+
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
+
 Trig::ExpertMethods::ExpertMethods(SG::SlotSpecificObj<Trig::CacheGlobalMemory>* cgm) 
   : m_cacheGlobalMemory(cgm),
     m_useExperimentalAndExpertMethods(false)   
 {
 }
 
+#else // Analysis or Standalone
+
+Trig::ExpertMethods::ExpertMethods(Trig::CacheGlobalMemory* cgm) 
+  : m_cacheGlobalMemory(cgm),
+    m_useExperimentalAndExpertMethods(false)   
+{
+}
+
+#endif
+
 Trig::ExpertMethods::~ExpertMethods() {}
 
 bool Trig::ExpertMethods::checkExperimentalAndExpertMethods() const {
@@ -76,30 +91,42 @@ const LVL1CTP::Lvl1Item* Trig::ExpertMethods::getItemDetails(const std::string&
   return cgm()->item(chain);
 }
 
-#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS)
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
+
 const HLT::NavigationCore* Trig::ExpertMethods::getNavigation() const
 {
   if (!(checkExperimentalAndExpertMethods())) return 0;
   return dynamic_cast<const HLT::NavigationCore*>(cgm()->navigation());
 }
-#else
+
+Trig::CacheGlobalMemory* Trig::ExpertMethods::cgm(bool onlyConfig) const {
+  if ( ! onlyConfig ) {
+    if ( !const_cast<Trig::CacheGlobalMemory*>(m_cacheGlobalMemory->get())->assert_decision() ) {
+      ATH_MSG_WARNING("TDT has not ben able to unpack trigger decision");    
+    } 
+  } 
+  return m_cacheGlobalMemory->get(); 
+}
+
+#else // Analysis or Standalone
+
 const HLT::TrigNavStructure* Trig::ExpertMethods::getNavigation() const
 {
   if (!(checkExperimentalAndExpertMethods())) return 0;
   return cgm()->navigation();
 }
-#endif
-
 
 Trig::CacheGlobalMemory* Trig::ExpertMethods::cgm(bool onlyConfig) const {
   if ( ! onlyConfig ) {
-    if ( !const_cast<Trig::CacheGlobalMemory*>(m_cacheGlobalMemory->get())->assert_decision() ) {
+    if ( !const_cast<Trig::CacheGlobalMemory*>(m_cacheGlobalMemory)->assert_decision() ) {
       ATH_MSG_WARNING("TDT has not ben able to unpack trigger decision");    
     } 
   } 
-  return m_cacheGlobalMemory->get(); 
+  return m_cacheGlobalMemory; 
 }
 
+#endif
+
 
 
 
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionTool.cxx b/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionTool.cxx
index d1b00685ed2..932d4278c11 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionTool.cxx
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionTool.cxx
@@ -34,9 +34,9 @@ static std::vector<std::string> s_instances;
 
 
 Trig::TrigDecisionTool::TrigDecisionTool(const std::string& name) :
-  asg::AsgMetadataTool(name),
+  asg::AsgMetadataTool(name)
 #ifndef XAOD_STANDALONE
-  AthMessaging( Athena::getMessageSvc(), name)
+  ,AthMessaging( Athena::getMessageSvc(), name)
 #endif
 #ifndef XAOD_ANALYSIS
   ,m_fullNavigation("HLT::Navigation/Navigation", this)
@@ -95,8 +95,12 @@ Trig::TrigDecisionTool::initialize() {
      return StatusCode::FAILURE;
    }
 
+
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full athena
    ATH_CHECK(m_oldDecisionKey.initialize( m_useRun1DecisionFormat ) );
    ATH_CHECK(m_oldEventInfoKey.initialize( m_useOldEventInfoDecisionFormat ) );
+#endif
+
    ATH_CHECK(m_HLTSummaryKeyIn.initialize(m_navigationFormat == "TrigComposite"));
    ATH_CHECK(m_navigationKey.initialize(m_navigationFormat == "TriggerElement"));
    ATH_CHECK(m_decisionKey.initialize());
@@ -170,13 +174,28 @@ Trig::TrigDecisionTool::initialize() {
    return StatusCode::SUCCESS;
 }
 
+std::vector<uint32_t>* Trig::TrigDecisionTool::getKeys() {
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full athena
+  return m_configKeysCache.get();
+#else // Analysis or Standalone
+  return &m_configKeysCache;
+#endif 
+}
+
+
+
 StatusCode Trig::TrigDecisionTool::beginEvent() {
 
   CacheGlobalMemory* cgmPtr = cgm();
   cgmPtr->setDecisionKeyPtr( &m_decisionKey );
-  cgmPtr->setOldDecisionKeyPtr( &m_oldDecisionKey );
   cgmPtr->setNavigationKeyPtr( &m_navigationKey );
+
+  size_t slot = 0;
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full athena
+  cgmPtr->setOldDecisionKeyPtr( &m_oldDecisionKey );
   cgmPtr->setOldEventInfoKeyPtr( &m_oldEventInfoKey );
+  slot = Gaudi::Hive::currentContext().slot();
+#endif
 
   //invalidate handle so that we read a new decision object
   if(cgm()->unpacker()){
@@ -200,21 +219,19 @@ StatusCode Trig::TrigDecisionTool::beginEvent() {
     
     if(!keysMatch){
 
-      ATH_MSG_INFO("Tool: updating config in slot " 
-        << Gaudi::Hive::currentContext().slot()
+      ATH_MSG_INFO("Tool: updating config in slot " << slot
         << " with SMK: " << m_configTool->masterKey() 
         << " and L1PSK: " << m_configTool->lvl1PrescaleKey() 
         << " and HLTPSK: " << m_configTool->hltPrescaleKey());
       
-      std::vector<uint32_t>* keys = m_configKeysCache.get();
+      std::vector<uint32_t>* keys = getKeys();
       keys->resize(3);
       keys->at(0) = m_configTool->masterKey();
       keys->at(1) = m_configTool->lvl1PrescaleKey();
       keys->at(2) = m_configTool->hltPrescaleKey();
       configurationUpdate( m_configTool->chainList(), m_configTool->ctpConfig() );
     } else{
-      ATH_MSG_VERBOSE("Tool: Cached Trigger configuration keys match for this event in slot " 
-        << Gaudi::Hive::currentContext().slot());
+      ATH_MSG_VERBOSE("Tool: Cached Trigger configuration keys match for this event in slot " << slot);
     }
 #ifndef XAOD_ANALYSIS
   }
@@ -231,21 +248,20 @@ StatusCode Trig::TrigDecisionTool::beginEvent() {
 
     if(!keysMatch){
 
-      ATH_MSG_INFO("Svc: updating config in slot " 
-        << Gaudi::Hive::currentContext().slot()
+      ATH_MSG_INFO("Svc: updating config in slot " << slot
         << " with SMK: " << m_configSvc->masterKey() 
         << " and L1PSK: " << m_configSvc->lvl1PrescaleKey() 
         << " and HLTPSK: " << m_configSvc->hltPrescaleKey());
 
-      std::vector<uint32_t>* keys = m_configKeysCache.get();
+      std::vector<uint32_t>* keys = getKeys();
       keys->resize(3);
       keys->at(0) = m_configSvc->masterKey();
       keys->at(1) = m_configSvc->lvl1PrescaleKey();
       keys->at(2) = m_configSvc->hltPrescaleKey();
       configurationUpdate( m_configSvc->chainList(), m_configSvc->ctpConfig() );
     }else{
-      ATH_MSG_VERBOSE("Svc: Cached Trigger configuration keys match for this event in slot " 
-        << Gaudi::Hive::currentContext().slot());    }
+      ATH_MSG_VERBOSE("Svc: Cached Trigger configuration keys match for this event in slot " << slot);
+    }
   }
 #endif
 
@@ -263,7 +279,7 @@ StatusCode Trig::TrigDecisionTool::beginInputFile() {
 }
 
 bool Trig::TrigDecisionTool::configKeysMatch(uint32_t smk, uint32_t lvl1psk, uint32_t hltpsk){
-  std::vector<uint32_t>* keys = m_configKeysCache.get(); // Slot-specific object.
+  std::vector<uint32_t>* keys = getKeys(); // Slot-specific object in full athena.
   if (keys->size() != 3) {
     return false;
   }
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionToolCore.cxx b/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionToolCore.cxx
index 89ec36fb4e9..e703f253edb 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionToolCore.cxx
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/Root/TrigDecisionToolCore.cxx
@@ -19,22 +19,41 @@
 
 #include "TrigDecisionTool/TrigDecisionToolCore.h"
 
+
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
+
 Trig::TrigDecisionToolCore::TrigDecisionToolCore()
 {
   SG::SlotSpecificObj<Trig::CacheGlobalMemory>* ptr = &m_cacheGlobalMemory;
   m_expertMethods=new ExpertMethods(ptr);
 }
 
-Trig::TrigDecisionToolCore::~TrigDecisionToolCore() {
-  delete m_expertMethods;
-}
-
 Trig::CacheGlobalMemory* Trig::TrigDecisionToolCore::cgm() const { 
   const Trig::CacheGlobalMemory* ptr = m_cacheGlobalMemory.get();
   // A consiquence of placing the cache in a slot-specific wrapper 
   return const_cast<Trig::CacheGlobalMemory*>(ptr);
 }
 
+#else // Analysis or Standalone
+
+Trig::TrigDecisionToolCore::TrigDecisionToolCore()
+{
+  Trig::CacheGlobalMemory* ptr = &m_cacheGlobalMemory;
+  m_expertMethods=new ExpertMethods(ptr);
+}
+
+Trig::CacheGlobalMemory* Trig::TrigDecisionToolCore::cgm() const { 
+  return const_cast<Trig::CacheGlobalMemory*>(&m_cacheGlobalMemory);
+}
+
+#endif
+
+
+Trig::TrigDecisionToolCore::~TrigDecisionToolCore() {
+  delete m_expertMethods;
+}
+
+
 StatusCode Trig::TrigDecisionToolCore::initialize() {
   ChainGroupInitialize();
   return StatusCode::SUCCESS;
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/CacheGlobalMemory.h b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/CacheGlobalMemory.h
index 81215f7310b..cca01aa534e 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/CacheGlobalMemory.h
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/CacheGlobalMemory.h
@@ -32,18 +32,21 @@
 #include "TrigConfL1Data/CTPConfig.h"
 
 #include "TrigSteeringEvent/Chain.h"
-#include "TrigDecisionEvent/TrigDecision.h"
 
 #include "TrigDecisionTool/IDecisionUnpacker.h"
 #include "TrigDecisionTool/Logger.h"
 #include "AsgTools/AsgMessaging.h"
 
-#include "StoreGate/ReadHandleKey.h"
+#include "AsgDataHandles/ReadHandleKey.h"
 
 #include "xAODTrigger/TrigCompositeContainer.h"
 #include "xAODTrigger/TrigDecision.h"
 #include "xAODTrigger/TrigNavigation.h"
+
+#ifndef XAOD_STANDALONE
 #include "EventInfo/EventInfo.h"
+#include "TrigDecisionEvent/TrigDecision.h"
+#endif
 
 namespace HLT {
   class Chain;
@@ -104,9 +107,9 @@ namespace Trig {
 
     const HLT::TrigNavStructure* navigation() const {   //!< gives back pointer to navigation object (unpacking if necessary)
       if(!m_unpacker->unpacked_navigation()){
-	if(const_cast<CacheGlobalMemory*>(this)->unpackNavigation().isFailure()){
-	  ATH_MSG_WARNING("unpack Navigation failed");
-	}
+        if(const_cast<CacheGlobalMemory*>(this)->unpackNavigation().isFailure()){
+          ATH_MSG_WARNING("unpack Navigation failed");
+	      }
       }
       return m_navigation; 
     }
@@ -142,8 +145,11 @@ namespace Trig {
 
     void setDecisionKeyPtr(SG::ReadHandleKey<xAOD::TrigDecision>* k) { m_decisionKeyPtr = k; }
     void setNavigationKeyPtr(SG::ReadHandleKey<xAOD::TrigNavigation>* k) { m_navigationKeyPtr = k; }
+
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
     void setOldDecisionKeyPtr(SG::ReadHandleKey<TrigDec::TrigDecision>* k) { m_oldDecisionKeyPtr = k; }
     void setOldEventInfoKeyPtr(SG::ReadHandleKey<EventInfo>* k) { m_oldEventInfoKeyPtr = k; }
+#endif
 
     SG::ReadHandleKey<xAOD::TrigDecision>* xAODTrigDecisionKey() { return m_decisionKeyPtr; }
 
@@ -211,8 +217,12 @@ namespace Trig {
     mutable const xAOD::TrigCompositeContainer* m_expressStreamContainer;
 
     SG::ReadHandleKey<xAOD::TrigDecision>* m_decisionKeyPtr; //!< Parent TDT's read handle key
+
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
     SG::ReadHandleKey<TrigDec::TrigDecision>* m_oldDecisionKeyPtr; //!< Parent TDT's read handle key
     SG::ReadHandleKey<EventInfo>* m_oldEventInfoKeyPtr; //!< Parent TDT's read handle key
+#endif
+
     SG::ReadHandleKey<xAOD::TrigNavigation>* m_navigationKeyPtr; //!< Parent TDT's read handle key
 
     typedef std::unordered_map<std::string, const TrigConf::HLTChain*> ChainHashMap_t;
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionAccess.h b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionAccess.h
index eb22260dde7..20b09dbecfb 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionAccess.h
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionAccess.h
@@ -33,6 +33,8 @@
 
 #include "TrigCompositeUtils/TrigCompositeUtils.h"
 
+#include "AsgDataHandles/ReadHandle.h"
+
 namespace HLT {
   class Chain;
 }
@@ -111,6 +113,7 @@ namespace Trig {
     /// @name Run 3 functions
     /// @{
 
+
     /**
      * @brief Runs 3+. Returns all features related to given chain group
      * @param[in] group Chain group to return features for.
@@ -155,7 +158,7 @@ namespace Trig {
      **/
     template<class CONTAINER, class FEATURE_CONTAINER>
     std::pair< typename CONTAINER::const_iterator, typename CONTAINER::const_iterator > 
-    associateToEventView(SG::ReadHandle<CONTAINER>& inViewContainer,
+    associateToEventView(typename SG::ReadHandle<CONTAINER>& inViewContainer,
                          const TrigCompositeUtils::LinkInfo<FEATURE_CONTAINER> linkInfo,
                          const std::string& roiName = TrigCompositeUtils::roiString()) const;
 
@@ -169,7 +172,7 @@ namespace Trig {
      **/
     template<class CONTAINER>
     std::pair< typename CONTAINER::const_iterator, typename CONTAINER::const_iterator > 
-    associateToEventView(SG::ReadHandle<CONTAINER>& inViewContainer,
+    associateToEventView(typename SG::ReadHandle<CONTAINER>& inViewContainer,
                          const TrigCompositeUtils::Decision* decisionObject,
                          const std::string& roiName = TrigCompositeUtils::roiString()) const;
 
@@ -182,7 +185,7 @@ namespace Trig {
      **/
     template<class CONTAINER>
     std::pair< typename CONTAINER::const_iterator, typename CONTAINER::const_iterator > 
-    associateToEventView(SG::ReadHandle<CONTAINER>& inViewContainer,
+    associateToEventView(typename SG::ReadHandle<CONTAINER>& inViewContainer,
                          const ElementLink<TrigRoiDescriptorCollection>& matchROI) const;
 
     /**
@@ -200,7 +203,7 @@ namespace Trig {
      **/
     template<class CONTAINER>
     std::pair< typename CONTAINER::const_iterator, typename CONTAINER::const_iterator > 
-    associateToEventView(SG::ReadHandle<CONTAINER>& inViewContainer,
+    associateToEventView(typename SG::ReadHandle<CONTAINER>& inViewContainer,
                          const uint32_t matchIndex,
                          const uint32_t matchKey = 0,
                          const bool isFullscan = false) const;
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionObjectHandleStandalone.h b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionObjectHandleStandalone.h
index 05c79a9f7fd..09b72d0f690 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionObjectHandleStandalone.h
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionObjectHandleStandalone.h
@@ -22,7 +22,7 @@
 #include "TrigDecisionTool/DecisionObjectHandle.h"
 #include "TrigDecisionTool/EventPtrDef.h"
 
-#include "StoreGate/ReadHandleKey.h"
+#include "AsgDataHandles/ReadHandleKey.h"
 
 
 namespace Trig {
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionUnpackerAthena.h b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionUnpackerAthena.h
index f3d3b3b746c..bf9e0054424 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionUnpackerAthena.h
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionUnpackerAthena.h
@@ -14,13 +14,16 @@
 #include "TrigDecisionTool/Logger.h"
 #include "AsgTools/AsgMessaging.h"
 
-#include "StoreGate/ReadHandleKey.h"
+#include "AsgDataHandles/ReadHandleKey.h"
 
-#include "TrigDecisionEvent/TrigDecision.h"
 
 
 class StoreGateSvc;
 
+namespace TrigDec {
+  class TrigDecision;
+}
+
 namespace HLT {
   class TrigNavStructure;
 }
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionUnpackerStandalone.h b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionUnpackerStandalone.h
index f4784403510..08f81638859 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionUnpackerStandalone.h
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/DecisionUnpackerStandalone.h
@@ -24,7 +24,7 @@
 #include "xAODTrigger/TrigDecision.h"
 #include "xAODTrigger/TrigNavigation.h"
 
-#include "StoreGate/ReadHandleKey.h"
+#include "AsgDataHandles/ReadHandleKey.h"
 
 // Forward declaration(s):
 namespace HLT {
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/ExpertMethods.h b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/ExpertMethods.h
index 71878fb3965..2e78e09266f 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/ExpertMethods.h
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/ExpertMethods.h
@@ -30,10 +30,10 @@
 
 #include "TrigDecisionTool/Logger.h"
 
-#include "AthenaKernel/SlotSpecificObj.h"
 
 #if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS)
 #include "TrigNavigation/NavigationCore.h"
+#include "AthenaKernel/SlotSpecificObj.h"
 #endif
 
 namespace HLT {
@@ -53,7 +53,12 @@ namespace Trig {
   class ExpertMethods : public virtual Logger {
   public:      
 
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS)
     ExpertMethods(SG::SlotSpecificObj<Trig::CacheGlobalMemory>* m_cacheGlobalMemory);
+#else
+    ExpertMethods(Trig::CacheGlobalMemory* m_cacheGlobalMemory);
+#endif
+
     virtual ~ExpertMethods();
 
     /**
@@ -92,9 +97,9 @@ namespace Trig {
     /**
      * @brief return HLT::NavigationCore
      **/
-#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS)
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
     const HLT::NavigationCore* getNavigation() const;
-#else
+#else // Analysis or Standalone
     const HLT::TrigNavStructure* getNavigation() const;
 #endif
 
@@ -106,7 +111,12 @@ namespace Trig {
 
   private:
 
-    SG::SlotSpecificObj<Trig::CacheGlobalMemory>* m_cacheGlobalMemory;    
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
+    SG::SlotSpecificObj<Trig::CacheGlobalMemory>* m_cacheGlobalMemory;
+#else // Analysis or Standalone
+    Trig::CacheGlobalMemory* m_cacheGlobalMemory;
+#endif    
+
     Trig::CacheGlobalMemory* cgm(bool onlyConfig=false) const;
 
     bool m_useExperimentalAndExpertMethods;
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/TrigDecisionTool.h b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/TrigDecisionTool.h
index 6316ea07216..ff65a864512 100755
--- a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/TrigDecisionTool.h
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/TrigDecisionTool.h
@@ -22,11 +22,12 @@
 
 #include "AsgTools/AsgMetadataTool.h"
 #include "AsgTools/ToolHandle.h"
+#include "AsgTools/PropertyWrapper.h"
 
 #include "TrigConfInterfaces/ITrigConfigTool.h" 
 #ifndef XAOD_STANDALONE
 #include "AthenaBaseComps/AthMessaging.h"
-
+#include "EventInfo/EventInfo.h"
 
 #ifndef XAOD_ANALYSIS
 #include "TrigNavigation/Navigation.h"
@@ -46,7 +47,6 @@
 
 #include "xAODTrigger/TrigDecision.h"
 #include "xAODTrigger/TrigNavigation.h"
-#include "EventInfo/EventInfo.h"
 
 // base classes
 #include "TrigDecisionTool/TrigDecisionToolCore.h"
@@ -119,7 +119,8 @@ namespace Trig {
   private:
       
     bool configKeysMatch(uint32_t smk, uint32_t lvl1psk, uint32_t hltpsk);
-    SG::SlotSpecificObj< std::vector<uint32_t> > m_configKeysCache; //!< cache for config keys. only update CacheGlobalMemory when these change
+
+    std::vector<uint32_t>* getKeys();
 
     ToolHandle<TrigConf::ITrigConfigTool> m_configTool{this, "ConfigTool", "TrigConf::xAODConfigTool"};    //!< trigger configuration service handle
 
@@ -127,25 +128,33 @@ namespace Trig {
     #if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS)
     ServiceHandle<TrigConf::ITrigConfigSvc> m_configSvc{this, "TrigConfigSvc", ""};    //!< trigger configuration service handle
     ToolHandle<HLT::Navigation> m_fullNavigation;
-    #endif
-    HLT::TrigNavStructure* m_navigation;
-    
-    Gaudi::Property<bool> m_acceptMultipleInstance{this, "AcceptMultipleInstance", false};
 
-    SG::ReadHandleKey<xAOD::TrigNavigation> m_navigationKey {this, "NavigationKey", "TrigNavigation",
-      "Storegate key of Run1, Run2 Trig Navigation"};
-
-    SG::ReadHandleKey<TrigDec::TrigDecision> m_oldDecisionKey {this, "OldTrigDecisionKey", "TrigDecision",
-      "Storegate key of old pre-xAOD Decision object"};
+    Gaudi::Property<bool> m_useOldEventInfoDecisionFormat {this, "UseOldEventInfoDecisionFormat", false,
+      "For use when reading old BS with trigger decision information available in the EventInfo"};
 
     SG::ReadHandleKey<EventInfo> m_oldEventInfoKey {this, "OldEventInfoKey", "EventInfo",
       "Storegate key of old pre-xAOD EventInfo object"};
 
+    SG::ReadHandleKey<TrigDec::TrigDecision> m_oldDecisionKey {this, "OldTrigDecisionKey", "TrigDecision",
+      "Storegate key of old pre-xAOD Decision object"};
+
     Gaudi::Property<bool> m_useRun1DecisionFormat {this, "UseAODDecision", false,
       "For use when reading old ESD/AOD with only a TrigDec::TrigDecision and no xAOD::TrigDecision"};
 
-    Gaudi::Property<bool> m_useOldEventInfoDecisionFormat {this, "UseOldEventInfoDecisionFormat", false,
-      "For use when reading old BS with trigger decision information available in the EventInfo"};
+    SG::SlotSpecificObj< std::vector<uint32_t> > m_configKeysCache; //!< cache for config keys. only update CacheGlobalMemory when these change
+
+    #else // Analysis or standalone 
+
+    std::vector<uint32_t>  m_configKeysCache; //!< cache for config keys. only update CacheGlobalMemory when these change 
+
+    #endif
+
+    HLT::TrigNavStructure* m_navigation;
+    
+    Gaudi::Property<bool> m_acceptMultipleInstance{this, "AcceptMultipleInstance", false};
+
+    SG::ReadHandleKey<xAOD::TrigNavigation> m_navigationKey {this, "NavigationKey", "TrigNavigation",
+      "Storegate key of Run1, Run2 Trig Navigation"};
 
     /// @name Run 3 properties
     /// @{
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/TrigDecisionToolCore.h b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/TrigDecisionToolCore.h
index 7fb149ed732..1bc0d47cd52 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/TrigDecisionToolCore.h
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/TrigDecisionTool/TrigDecisionToolCore.h
@@ -62,7 +62,13 @@ namespace Trig {
 
     
   private:
-    SG::SlotSpecificObj<Trig::CacheGlobalMemory> m_cacheGlobalMemory;    
+
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full Athena
+    SG::SlotSpecificObj<Trig::CacheGlobalMemory> m_cacheGlobalMemory;
+#else // Analysis or Standalone
+    Trig::CacheGlobalMemory m_cacheGlobalMemory;
+#endif
+
     Trig::ExpertMethods* m_expertMethods;
     TrigDecisionToolCore (const TrigDecisionToolCore&);
     TrigDecisionToolCore& operator= (const TrigDecisionToolCore&);
diff --git a/Trigger/TrigAnalysis/TrigDecisionTool/src/DecisionUnpackerAthena.cxx b/Trigger/TrigAnalysis/TrigDecisionTool/src/DecisionUnpackerAthena.cxx
index 7ff8b090b3d..36f0fc0660d 100644
--- a/Trigger/TrigAnalysis/TrigDecisionTool/src/DecisionUnpackerAthena.cxx
+++ b/Trigger/TrigAnalysis/TrigDecisionTool/src/DecisionUnpackerAthena.cxx
@@ -14,6 +14,8 @@
 #include "TrigDecisionTool/DecisionUnpackerAthena.h"
 #include "TrigDecisionTool/DecisionObjectHandleAthena.h"
 #include "TrigNavigation/NavigationCore.h"
+#include "TrigDecisionEvent/TrigDecision.h"
+
 
 namespace Trig {
   DecisionUnpackerAthena::DecisionUnpackerAthena(SG::ReadHandleKey<TrigDec::TrigDecision>* olddeckey) : m_handle(new DecisionObjectHandleAthena(olddeckey)){
diff --git a/Trigger/TrigEvent/TrigDecisionEvent/TrigDecisionEvent/TrigDecision.h b/Trigger/TrigEvent/TrigDecisionEvent/TrigDecisionEvent/TrigDecision.h
index ce5f9b9ab1b..f2191f60068 100755
--- a/Trigger/TrigEvent/TrigDecisionEvent/TrigDecisionEvent/TrigDecision.h
+++ b/Trigger/TrigEvent/TrigDecisionEvent/TrigDecisionEvent/TrigDecision.h
@@ -29,7 +29,7 @@
 #include "TrigSteeringEvent/Lvl1Result.h"
 #include "TrigSteeringEvent/HLTResult.h"
 
-#include "AthenaKernel/CLASS_DEF.h"
+#include "xAODCore/CLASS_DEF.h"
 #include <string>
 #include <stdint.h>
 
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/CMakeLists.txt b/Trigger/TrigEvent/TrigSteeringEvent/CMakeLists.txt
index cb0a27f8fa8..fbfdd079e27 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/CMakeLists.txt
+++ b/Trigger/TrigEvent/TrigSteeringEvent/CMakeLists.txt
@@ -81,7 +81,7 @@ atlas_add_test( TrigPassBits_test
    LINK_LIBRARIES TrigSteeringEvent
    POST_EXEC_SCRIPT nopost.sh )
 
-if( NOT XAOD_STANDALONE )
+if( NOT XAOD_STANDALONE AND NOT XAOD_ANALYSIS )
    atlas_add_test( Operators_test
       SOURCES test/Operators_test.cxx
       LINK_LIBRARIES AthenaKernel GaudiKernel TrigSteeringEvent
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/GenericResult.h b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/GenericResult.h
index 7ee2c098d5b..0a40be1ddca 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/GenericResult.h
+++ b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/GenericResult.h
@@ -16,7 +16,7 @@
  */
 
 #include <stdint.h>
-#include "AthenaKernel/CLASS_DEF.h"
+#include "xAODCore/CLASS_DEF.h"
 
 class GenericResult {
  public:
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResult.h b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResult.h
index 1af1bc3a6e9..7e0860b64b8 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResult.h
+++ b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/HLTResult.h
@@ -19,8 +19,14 @@
 #include <stdint.h>
 #include "TrigSteeringEvent/Enums.h"
 #include "TrigSteeringEvent/GenericResult.h"
+
+#ifdef XAOD_STANDALONE
+#include "xAODCore/ClassID_traits.h"
+#else
 #include "AthenaKernel/IClassIDSvc.h"
-#include "AthenaKernel/CLASS_DEF.h"
+#endif
+
+#include "xAODCore/CLASS_DEF.h"
 #include "CxxUtils/checker_macros.h"
 
 /****************************************************************************************
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/Lvl1Result.h b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/Lvl1Result.h
index 53ae0e6c79f..39533970fe2 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/Lvl1Result.h
+++ b/Trigger/TrigEvent/TrigSteeringEvent/TrigSteeringEvent/Lvl1Result.h
@@ -23,7 +23,7 @@
 #define TRIGSTEERINGEVENT_Lvl1Result_H
 
 #include <stdint.h>
-#include "AthenaKernel/CLASS_DEF.h"
+#include "xAODCore/CLASS_DEF.h"
 #include "TrigSteeringEvent/Lvl1Item.h"
 
 namespace LVL1CTP {
@@ -77,6 +77,7 @@ namespace LVL1CTP {
 
 } // end of namespace
 
+
 CLASS_DEF( LVL1CTP::Lvl1Result, 21091893, 1)
 
 #endif
diff --git a/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResult.cxx b/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResult.cxx
index 08fe8e47f67..eca55294878 100644
--- a/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResult.cxx
+++ b/Trigger/TrigEvent/TrigSteeringEvent/src/HLTResult.cxx
@@ -5,7 +5,6 @@
 #include "TrigSteeringEvent/HLTResult.h"
 #include "TrigSteeringEvent/HLTExtraData.h"
 
-#include "AthenaKernel/CLASS_DEF.h"
 #include <cassert>
 #include <algorithm>
 #include <numeric>
diff --git a/Trigger/TrigSteer/TrigCompositeUtils/CMakeLists.txt b/Trigger/TrigSteer/TrigCompositeUtils/CMakeLists.txt
index 8788fd23e45..889df3253c3 100644
--- a/Trigger/TrigSteer/TrigCompositeUtils/CMakeLists.txt
+++ b/Trigger/TrigSteer/TrigCompositeUtils/CMakeLists.txt
@@ -4,19 +4,16 @@
 atlas_subdir( TrigCompositeUtils )
 
 # Set up the (non-)standalone compilation.
-set( extra_srcs )
 set( extra_libs )
 if( NOT XAOD_STANDALONE )
-  set( extra_srcs src/*.cxx )
-  set( extra_libs GaudiKernel AthenaKernel AthLinks StoreGateLib AthContainers
-    xAODTrigger )
+  set( extra_libs GaudiKernel AthenaKernel AthLinks StoreGateLib AthContainers )
 endif()
 
 # Add the package's dual use library.
 atlas_add_library( TrigCompositeUtilsLib
-  TrigCompositeUtils/*.h TrigCompositeUtils/*.icc Root/*.cxx ${extra_srcs}
+  TrigCompositeUtils/*.h TrigCompositeUtils/*.icc Root/*.cxx
   PUBLIC_HEADERS TrigCompositeUtils
-  LINK_LIBRARIES TrigConfHLTUtilsLib CxxUtils AsgMessagingLib AsgDataHandlesLib TrigDecisionInterface xAODTrigger ${extra_libs} )
+  LINK_LIBRARIES TrigConfHLTUtilsLib CxxUtils AsgMessagingLib AsgDataHandlesLib AsgTools TrigDecisionInterface xAODBase xAODTrigger ${extra_libs}  )
 
 # Install files from the package.
 atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} )
diff --git a/Trigger/TrigSteer/TrigCompositeUtils/src/NavGraph.cxx b/Trigger/TrigSteer/TrigCompositeUtils/Root/NavGraph.cxx
similarity index 100%
rename from Trigger/TrigSteer/TrigCompositeUtils/src/NavGraph.cxx
rename to Trigger/TrigSteer/TrigCompositeUtils/Root/NavGraph.cxx
diff --git a/Trigger/TrigSteer/TrigCompositeUtils/Root/TrigCompositeUtils.cxx b/Trigger/TrigSteer/TrigCompositeUtils/Root/TrigCompositeUtils.cxx
index 2275e2e1ba2..f050f42c4e7 100644
--- a/Trigger/TrigSteer/TrigCompositeUtils/Root/TrigCompositeUtils.cxx
+++ b/Trigger/TrigSteer/TrigCompositeUtils/Root/TrigCompositeUtils.cxx
@@ -2,9 +2,376 @@
   Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
+// See similar workaround the lack of CLID in standalone releases in TrigComposite_v1.h
+#include "xAODBase/IParticleContainer.h"
+#ifdef XAOD_STANDALONE
+#include "xAODCore/CLASS_DEF.h"
+CLASS_DEF( xAOD::IParticleContainer, 1241842700, 1 )
+#endif // XAOD_STANDALONE
+
+#include "AsgDataHandles/WriteHandle.h"
+#include "AsgDataHandles/ReadHandle.h"
+#include "AthContainers/AuxElement.h"
+
 #include "TrigCompositeUtils/TrigCompositeUtils.h"
 
-namespace TrigCompositeUtils {
+#include <unordered_map>
+#include <regex>
+#include <iomanip> // std::setfill
+
+static const SG::AuxElement::Accessor< std::vector<TrigCompositeUtils::DecisionID> > readWriteAccessor("decisions");
+static const SG::AuxElement::ConstAccessor< std::vector<TrigCompositeUtils::DecisionID> > readOnlyAccessor("decisions");
+
+namespace TrigCompositeUtils {  
 
   ANA_MSG_SOURCE (msgFindLink, "TrigCompositeUtils.findLink")
+  ANA_MSG_SOURCE (msgRejected, "TrigCompositeUtils.getRejectedDecisionNodes")
+
+
+  SG::WriteHandle<DecisionContainer> createAndStore( const SG::WriteHandleKey<DecisionContainer>& key, const EventContext& ctx ) {
+    SG::WriteHandle<DecisionContainer> handle( key, ctx );
+    auto data = std::make_unique<DecisionContainer>() ;
+    auto aux = std::make_unique<DecisionAuxContainer>() ;
+    data->setStore( aux.get() );
+    handle.record( std::move( data ), std::move( aux )  ).ignore();
+    return handle;
+  }
+
+  void createAndStore( SG::WriteHandle<DecisionContainer>& handle ) {
+    auto data = std::make_unique<DecisionContainer>() ;
+    auto aux = std::make_unique<DecisionAuxContainer>() ;
+    data->setStore( aux.get() );
+    handle.record( std::move( data ), std::move( aux )  ).ignore();
+  }
+
+  Decision* newDecisionIn ( DecisionContainer* dc, const std::string& name) {
+    Decision * x = new Decision;
+    dc->push_back( x );
+    if ( ! name.empty() ) {
+      x->setName( name );
+    }
+    return x;
+  }
+
+  Decision* newDecisionIn ( DecisionContainer* dc, const Decision* dOld, const std::string& name, const EventContext& ctx ) {
+    Decision* dNew =  newDecisionIn( dc, name );
+    linkToPrevious(dNew, dOld, ctx); // Sets up link to 'seed' collection, points to dOld
+    return dNew;
+  }
+
+  void addDecisionID( DecisionID id,  Decision* d ) {   
+    std::vector<DecisionID>& decisions = readWriteAccessor( *d );
+    if ( decisions.size() == 0 or decisions.back() != id) 
+      decisions.push_back( id );
+  }
+  
+  void decisionIDs( const Decision* d, DecisionIDContainer& destination ) {    
+    const std::vector<DecisionID>& decisions = readOnlyAccessor( *d );    
+    destination.insert( decisions.begin(), decisions.end() );
+  }
+
+  const std::vector<DecisionID>& decisionIDs( const Decision* d ) {    
+    return readOnlyAccessor( *d );    
+  }
+
+  std::vector<DecisionID>& decisionIDs( Decision* d ) {
+    return readWriteAccessor( *d );
+  }
+
+  void insertDecisionIDs(const Decision* src, Decision* dest ){
+    DecisionIDContainer srcIds;
+    decisionIDs( src, srcIds ); // Now stored in a set
+    insertDecisionIDs( srcIds, dest);
+  }
+
+  void insertDecisionIDs( const DecisionIDContainer& src, Decision* dest ) {
+    DecisionIDContainer collateIDs;
+    // Decision are xAOD objects backed by a std::vector
+    // Here we use a std::set to de-duplicate IDs from src and dest before setting dest
+    decisionIDs( dest, collateIDs ); // Set operation 1. Get from dest
+    collateIDs.insert( src.begin(), src.end() ); // Set operation 2. Get from src
+    decisionIDs( dest ).clear(); // Clear target
+    // Copy from set to (ordered) vector
+    decisionIDs( dest ).insert( decisionIDs(dest).end(), collateIDs.begin(), collateIDs.end() );
+  }
+
+  void uniqueDecisionIDs(Decision* dest) {
+    // Re-use above insertDecisionIDs method.
+    // This implicitly performs de-duplication
+    return insertDecisionIDs(dest, dest);
+  }
+
+  bool allFailed( const Decision* d ) {
+    const std::vector<DecisionID>& decisions = readOnlyAccessor( *d );    
+    return decisions.empty();
+  }
+
+  bool isAnyIDPassing( const Decision* d,  const DecisionIDContainer& required ) {
+    for ( DecisionID id : readOnlyAccessor( *d ) ) {
+      if ( required.count( id ) > 0 ) {
+        return true;
+      }
+    }
+    return false;
+  }    
+
+  bool passed( DecisionID id, const DecisionIDContainer& idSet ) {
+    return idSet.count( id ) != 0;
+  }
+
+#if !defined(XAOD_STANDALONE) && !defined(XAOD_ANALYSIS) // Full athena
+  ElementLink<DecisionContainer> decisionToElementLink(const Decision* d, const EventContext& ctx) {
+    const DecisionContainer* container = dynamic_cast<const DecisionContainer*>( d->container() );
+    if( ! container ) {
+      throw std::runtime_error("TrigCompositeUtils::convertToElementLink Using convertToElementLink(d) requires that the Decision d is already in a container");
+    }
+    return ElementLink<DecisionContainer>(*container, d->index(), ctx);
+  }
+#else // Analysis or Standalone
+  ElementLink<DecisionContainer> decisionToElementLink(const Decision* d, const EventContext&) {
+    const DecisionContainer* container = dynamic_cast<const DecisionContainer*>( d->container() );
+    if( ! container ) {
+      throw std::runtime_error("TrigCompositeUtils::convertToElementLink Using convertToElementLink(d) requires that the Decision d is already in a container");
+    }
+    return ElementLink<DecisionContainer>(*container, d->index());
+  }
+#endif
+
+  void linkToPrevious( Decision* d, const std::string& previousCollectionKey, size_t previousIndex ) {
+    ElementLink<DecisionContainer> seed = ElementLink<DecisionContainer>( previousCollectionKey, previousIndex );
+    if (!seed.isValid()) {
+      throw std::runtime_error("TrigCompositeUtils::linkToPrevious Invalid Decision Link key or index provided");
+    } else {
+      d->addObjectCollectionLink("seed", seed);
+    }
+  }
+
+  void linkToPrevious( Decision* d, const Decision* dOld, const EventContext& ctx ) {
+    d->addObjectCollectionLink(seedString(), decisionToElementLink(dOld, ctx));
+  }
+
+  bool hasLinkToPrevious( const Decision* d ) {
+    return d->hasObjectCollectionLinks( seedString() );
+  }
+
+  const ElementLinkVector<DecisionContainer> getLinkToPrevious( const Decision* d ) {
+    return d->objectCollectionLinks<DecisionContainer>( seedString() );
+  }
+
+
+  bool copyLinks(const Decision* src, Decision* dest) {
+    return dest->copyAllLinksFrom(src);
+  }
+
+
+  HLT::Identifier createLegName(const HLT::Identifier& chainIdentifier, size_t counter) {
+    if (chainIdentifier.name().substr(0,4) != "HLT_") {
+      throw std::runtime_error("TrigCompositeUtils::createLegName chainIdentifier '"+chainIdentifier.name()+"' does not start 'HLT_'");
+    }
+    if (counter > 999) {
+      throw std::runtime_error("TrigCompositeUtils::createLegName Leg counters above 999 are invalid.");
+    }
+    std::stringstream legStringStream;
+    legStringStream << "leg" << std::setfill('0') << std::setw(3) << counter << "_" << chainIdentifier.name();
+    return HLT::Identifier( legStringStream.str() );
+  }
+
+  
+  HLT::Identifier getIDFromLeg(const HLT::Identifier& legIdentifier) {
+    if (legIdentifier.name().find("HLT_",0)==0 ){
+      return legIdentifier;
+    } else if (isLegId(legIdentifier)){
+      return HLT::Identifier(legIdentifier.name().substr(7));
+    } else{
+      throw std::runtime_error("TrigCompositeUtils::getIDFromLeg legIdentifier '"+legIdentifier.name()+"' does not start with 'HLT_' or 'leg' ");
+    }
+  }
+
+  
+  bool isLegId(const HLT::Identifier& legIdentifier) {
+    return (legIdentifier.name().find("leg",0)==0);
+  }
+  
+  
+  const Decision* find( const Decision* start, const std::function<bool( const Decision* )>& filter ) {
+    if ( filter( start ) ) return start;
+
+    if ( hasLinkToPrevious(start) ) {
+      const ElementLinkVector<DecisionContainer> seeds = getLinkToPrevious(start);
+      for (const ElementLink<DecisionContainer>& seedEL : seeds) {
+        const Decision* result = find( *seedEL, filter );
+        if (result) return result;
+      }
+    }
+    
+    return nullptr;
+  }
+
+  bool HasObject::operator()( const Decision* composite ) const {
+    return composite->hasObjectLink( m_name );
+  }
+
+  bool HasObjectCollection::operator()( const Decision* composite ) const {
+    return composite->hasObjectCollectionLinks( m_name );
+  }
+
+ std::vector<const Decision*> getRejectedDecisionNodes(asg::EventStoreType* eventStore, const DecisionID id) {
+    std::vector<const Decision*> output;
+    // The list of containers we need to read can change on a file-by-file basis (it depends on the SMK)
+    // Hence we query SG for all collections rather than maintain a large and ever changing ReadHandleKeyArray
+
+    std::vector<std::string> keys;
+    // TODO TODO TODO NEED TO REPLACE THIS WITH A STANDALONE-FRIENDLY VERSION
+#ifndef XAOD_STANDALONE
+    eventStore->keys(static_cast<CLID>( ClassID_traits< DecisionContainer >::ID() ), keys);
+#else
+    throw std::runtime_error("Cannot yet obtain rejected HLT features in AnalysisBase");
+#endif
+
+    // Loop over each DecisionContainer,
+    for (const std::string& key : keys) {
+      // Get and check this container
+      if ( key.find("HLTNav") != 0 ) {
+        continue; // Only concerned about the decision containers which make up the navigation, they have name prefix of HLTNav
+      }
+      if ( key == "HLTNav_Summary" ) {
+        continue; //  This is where accepted paths start. We are looking for rejected ones
+      }
+      const DecisionContainer* container = nullptr;
+      if ( eventStore->retrieve( container, key ).isFailure() ) {
+        throw std::runtime_error("Unable to retrieve " + key + " from event store.");
+      }
+      for (const Decision* d : *container) {
+        if (!d->hasObjectLink(featureString())) {
+          // TODO add logic for ComboHypo where this is expected
+          continue; // Only want Decision objects created by HypoAlgs
+        }
+        const ElementLinkVector<DecisionContainer> mySeeds = d->objectCollectionLinks<DecisionContainer>(seedString());
+        if (mySeeds.size() == 0) {
+          continue;
+        }
+        const bool allSeedsValid = std::all_of(mySeeds.begin(), mySeeds.end(), [](const ElementLink<DecisionContainer>& s) { return s.isValid(); });
+        if (!allSeedsValid) {
+          using namespace msgRejected;
+          ANA_MSG_WARNING("A Decision object in " << key << " has invalid seeds. "
+            << "The trigger navigation information is incomplete. Skipping this Decision object.");
+          continue;
+        }
+        DecisionIDContainer activeChainsIntoThisDecision;
+        decisionIDs(*(mySeeds.at(0)), activeChainsIntoThisDecision); // Get list of active chains from the first parent
+        if (mySeeds.size() > 1) {
+          for (size_t i = 1; i < mySeeds.size(); ++i) {
+            // If there are more than one parent, we only want to keep the intersection of all of the seeds
+            DecisionIDContainer moreActiveChains;
+            decisionIDs(*(mySeeds.at(i)), moreActiveChains);
+            DecisionIDContainer intersection;
+            std::set_intersection(activeChainsIntoThisDecision.begin(), activeChainsIntoThisDecision.end(),
+              moreActiveChains.begin(), moreActiveChains.end(),
+              std::inserter(intersection, intersection.begin()));
+            activeChainsIntoThisDecision = intersection; // Update the output to only be the intersection and continue to any other seeds
+          }
+        }
+        // We now know what chains were active coming into this Decision (d) from ALL seeds
+        // This is the logic required for each HypoTool to have activated and checked if its chain passes
+        // So the size of activeChainsIntoThisDecision corresponds to the number of HypoTools which will have run
+        // What do we care about? A chain, or all chains?
+        DecisionIDContainer chainsToCheck;
+        if (id == 0) { // We care about *all* chains
+          chainsToCheck = activeChainsIntoThisDecision;
+        } else { // We care about *one* chain
+          chainsToCheck.insert(id);
+        }
+        // We have found a rejected decision node *iff* a chainID to check is *not* present here
+        // I.e. the HypoTool for the chain returned a NEGATIVE decision
+        DecisionIDContainer activeChainsPassedByThisDecision;
+        decisionIDs(d, activeChainsPassedByThisDecision);
+        for (const DecisionID checkID : chainsToCheck) {
+          if (activeChainsPassedByThisDecision.count(checkID) == 0 && // I was REJECTED here ...
+              activeChainsIntoThisDecision.count(checkID) == 1) { // ... but PASSSED by all my inputs
+            output.push_back(d);
+            break;
+          }
+        }
+      }
+    }
+    return output;
+  }
+
+  void recursiveGetDecisionsInternal(const Decision* node, 
+    const Decision* comingFrom, 
+    NavGraph& navGraph, 
+    const DecisionID id,
+    const bool enforceDecisionOnNode) {
+
+    // Does this Decision satisfy the chain requirement?
+    DecisionIDContainer idSet = {id};
+    if (enforceDecisionOnNode && id != 0 && !isAnyIDPassing(node, idSet)) {
+      return; // Stop propagating down this leg. It does not concern the chain with DecisionID = id
+    }
+
+    // This Decision object is part of this path through the Navigation
+    navGraph.addNode(node, comingFrom);
+    
+    // Continue to the path(s) by looking at this Decision object's seed(s)
+    if ( hasLinkToPrevious(node) ) {
+      // Do the recursion
+      for ( ElementLink<DecisionContainer> seed : getLinkToPrevious(node)) {
+        const Decision* seedDecision = *(seed); // Dereference ElementLink
+        // Sending true as final parameter for enforceDecisionOnStartNode as we are recursing away from the supplied start node
+        recursiveGetDecisionsInternal(seedDecision, node, navGraph, id, /*enforceDecisionOnNode*/ true);
+      }
+    }
+    return;
+  }
+
+  void recursiveGetDecisions(const Decision* start, 
+    NavGraph& navGraph, 
+    const DecisionID id,
+    const bool enforceDecisionOnStartNode) {
+
+    // Note: we do not require navGraph to be an empty graph. We can extend it.
+    recursiveGetDecisionsInternal(start, /*comingFrom*/nullptr, navGraph, id, enforceDecisionOnStartNode);
+    
+    return;
+  }
+
+
+  std::string dump( const Decision* tc, std::function< std::string( const Decision* )> printerFnc ) {
+    std::string ret; 
+    ret += printerFnc( tc );
+    if ( hasLinkToPrevious(tc) ) {
+      const ElementLinkVector<DecisionContainer> seeds = getLinkToPrevious(tc);
+      for (const ElementLink<DecisionContainer>& seedEL : seeds) {
+        ret += " -> " + dump( *seedEL, printerFnc );
+      }
+    }
+    return ret;
+  }
+
+  
+  const std::string& initialRoIString() {
+    return Decision::s_initialRoIString;
+  }
+
+  const std::string& initialRecRoIString() {
+    return Decision::s_initialRecRoIString;
+  }
+
+  const std::string& roiString() {
+    return Decision::s_roiString;
+  }
+
+  const std::string& viewString() {
+    return Decision::s_viewString;
+  }
+
+  const std::string& featureString() {
+    return Decision::s_featureString;
+  }
+
+  const std::string& seedString() {
+    return Decision::s_seedString;
+  }
+  
 }
+
diff --git a/Trigger/TrigSteer/TrigCompositeUtils/TrigCompositeUtils/TrigCompositeUtils.h b/Trigger/TrigSteer/TrigCompositeUtils/TrigCompositeUtils/TrigCompositeUtils.h
index a5eaf77bd2d..40862643bb3 100644
--- a/Trigger/TrigSteer/TrigCompositeUtils/TrigCompositeUtils/TrigCompositeUtils.h
+++ b/Trigger/TrigSteer/TrigCompositeUtils/TrigCompositeUtils/TrigCompositeUtils.h
@@ -18,6 +18,12 @@
 #include "AsgTools/CurrentContext.h"
 #include "AsgTools/EventStoreType.h"
 #include "AsgMessaging/MsgStream.h"
+#include "AsgMessaging/MessageCheck.h"
+
+
+#ifdef XAOD_STANDALONE
+#include "AsgTools/SgTEvent.h"
+#endif
 
 #include "AthContainers/AuxElement.h"
 #include "xAODTrigger/TrigCompositeContainer.h"
@@ -30,6 +36,8 @@
 
 namespace TrigCompositeUtils {
 
+  ANA_MSG_HEADER (msgRejected)
+
   /// alias types, for readability and to simplify future evolution
   typedef SG::WriteHandle<DecisionContainer> DecisionWriteHandle;
 
diff --git a/Trigger/TrigSteer/TrigCompositeUtils/src/TrigCompositeUtils.cxx b/Trigger/TrigSteer/TrigCompositeUtils/src/TrigCompositeUtils.cxx
deleted file mode 100644
index e570baed736..00000000000
--- a/Trigger/TrigSteer/TrigCompositeUtils/src/TrigCompositeUtils.cxx
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
-  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
-*/
-
-#include "StoreGate/WriteHandle.h"
-#include "StoreGate/ReadHandle.h"
-#include "AthContainers/AuxElement.h"
-#include "GaudiKernel/EventContext.h"
-#include "GaudiKernel/GaudiException.h"
-
-#include "StoreGate/WriteHandle.h"
-#include "TrigCompositeUtils/TrigCompositeUtils.h"
-
-#include <unordered_map>
-#include <regex>
-
-static const SG::AuxElement::Accessor< std::vector<TrigCompositeUtils::DecisionID> > readWriteAccessor("decisions");
-static const SG::AuxElement::ConstAccessor< std::vector<TrigCompositeUtils::DecisionID> > readOnlyAccessor("decisions");
-
-namespace TrigCompositeUtils {  
-
-  SG::WriteHandle<DecisionContainer> createAndStore( const SG::WriteHandleKey<DecisionContainer>& key, const EventContext& ctx ) {
-    SG::WriteHandle<DecisionContainer> handle( key, ctx );
-    auto data = std::make_unique<DecisionContainer>() ;
-    auto aux = std::make_unique<DecisionAuxContainer>() ;
-    data->setStore( aux.get() );
-    handle.record( std::move( data ), std::move( aux )  ).ignore();
-    return handle;
-  }
-
-  void createAndStore( SG::WriteHandle<DecisionContainer>& handle ) {
-    auto data = std::make_unique<DecisionContainer>() ;
-    auto aux = std::make_unique<DecisionAuxContainer>() ;
-    data->setStore( aux.get() );
-    handle.record( std::move( data ), std::move( aux )  ).ignore();
-  }
-
-  Decision* newDecisionIn ( DecisionContainer* dc, const std::string& name) {
-    Decision * x = new Decision;
-    dc->push_back( x );
-    if ( ! name.empty() ) {
-      x->setName( name );
-    }
-    return x;
-  }
-
-  Decision* newDecisionIn ( DecisionContainer* dc, const Decision* dOld, const std::string& name, const EventContext& ctx ) {
-    Decision* dNew =  newDecisionIn( dc, name );
-    linkToPrevious(dNew, dOld, ctx); // Sets up link to 'seed' collection, points to dOld
-    return dNew;
-  }
-
-  void addDecisionID( DecisionID id,  Decision* d ) {   
-    std::vector<DecisionID>& decisions = readWriteAccessor( *d );
-    if ( decisions.size() == 0 or decisions.back() != id) 
-      decisions.push_back( id );
-  }
-  
-  void decisionIDs( const Decision* d, DecisionIDContainer& destination ) {    
-    const std::vector<DecisionID>& decisions = readOnlyAccessor( *d );    
-    destination.insert( decisions.begin(), decisions.end() );
-  }
-
-  const std::vector<DecisionID>& decisionIDs( const Decision* d ) {    
-    return readOnlyAccessor( *d );    
-  }
-
-  std::vector<DecisionID>& decisionIDs( Decision* d ) {
-    return readWriteAccessor( *d );
-  }
-
-  void insertDecisionIDs(const Decision* src, Decision* dest ){
-    DecisionIDContainer srcIds;
-    decisionIDs( src, srcIds ); // Now stored in a set
-    insertDecisionIDs( srcIds, dest);
-  }
-
-  void insertDecisionIDs( const DecisionIDContainer& src, Decision* dest ) {
-    DecisionIDContainer collateIDs;
-    // Decision are xAOD objects backed by a std::vector
-    // Here we use a std::set to de-duplicate IDs from src and dest before setting dest
-    decisionIDs( dest, collateIDs ); // Set operation 1. Get from dest
-    collateIDs.insert( src.begin(), src.end() ); // Set operation 2. Get from src
-    decisionIDs( dest ).clear(); // Clear target
-    // Copy from set to (ordered) vector
-    decisionIDs( dest ).insert( decisionIDs(dest).end(), collateIDs.begin(), collateIDs.end() );
-  }
-
-  void uniqueDecisionIDs(Decision* dest) {
-    // Re-use above insertDecisionIDs method.
-    // This implicitly performs de-duplication
-    return insertDecisionIDs(dest, dest);
-  }
-
-  bool allFailed( const Decision* d ) {
-    const std::vector<DecisionID>& decisions = readOnlyAccessor( *d );    
-    return decisions.empty();
-  }
-
-  bool isAnyIDPassing( const Decision* d,  const DecisionIDContainer& required ) {
-    for ( DecisionID id : readOnlyAccessor( *d ) ) {
-      if ( required.count( id ) > 0 ) {
-        return true;
-      }
-    }
-    return false;
-  }    
-
-  bool passed( DecisionID id, const DecisionIDContainer& idSet ) {
-    return idSet.count( id ) != 0;
-  }
-
-  ElementLink<DecisionContainer> decisionToElementLink(const Decision* d, const EventContext& ctx) {
-    const DecisionContainer* container = dynamic_cast<const DecisionContainer*>( d->container() );
-    if( ! container ) {
-      throw GaudiException("Using convertToElementLink(d) requires that the Decision d is already in a container",
-        "TrigCompositeUtils::convertToElementLink", StatusCode::FAILURE);
-    }
-    return ElementLink<DecisionContainer>(*container, d->index(), ctx);
-  }
-
-  void linkToPrevious( Decision* d, const std::string& previousCollectionKey, size_t previousIndex ) {
-    ElementLink<DecisionContainer> seed = ElementLink<DecisionContainer>( previousCollectionKey, previousIndex );
-    if (!seed.isValid()) {
-      throw GaudiException("Invalid Decision Link key or index provided", "TrigCompositeUtils::linkToPrevious", StatusCode::FAILURE);
-    } else {
-      d->addObjectCollectionLink("seed", seed);
-    }
-  }
-
-  void linkToPrevious( Decision* d, const Decision* dOld, const EventContext& ctx ) {
-    d->addObjectCollectionLink(seedString(), decisionToElementLink(dOld, ctx));
-  }
-
-  bool hasLinkToPrevious( const Decision* d ) {
-    return d->hasObjectCollectionLinks( seedString() );
-  }
-
-  const ElementLinkVector<DecisionContainer> getLinkToPrevious( const Decision* d ) {
-    return d->objectCollectionLinks<DecisionContainer>( seedString() );
-  }
-
-
-  bool copyLinks(const Decision* src, Decision* dest) {
-    return dest->copyAllLinksFrom(src);
-  }
-
-
-  HLT::Identifier createLegName(const HLT::Identifier& chainIdentifier, size_t counter) {
-    if (chainIdentifier.name().substr(0,4) != "HLT_") {
-      throw GaudiException("chainIdentifier '"+chainIdentifier.name()+"' does not start 'HLT_'",
-        "TrigCompositeUtils::createLegName", StatusCode::FAILURE);
-    }
-    if (counter > 999) {
-      throw GaudiException("Leg counters above 999 are invalid.", "TrigCompositeUtils::createLegName", StatusCode::FAILURE);
-    }
-    std::stringstream legStringStream;
-    legStringStream << "leg" << std::setfill('0') << std::setw(3) << counter << "_" << chainIdentifier.name();
-    return HLT::Identifier( legStringStream.str() );
-  }
-
-  
-  HLT::Identifier getIDFromLeg(const HLT::Identifier& legIdentifier) {
-    if (legIdentifier.name().find("HLT_",0)==0 ){
-      return legIdentifier;
-    } else if (isLegId(legIdentifier)){
-      return HLT::Identifier(legIdentifier.name().substr(7));
-    } else{
-      throw GaudiException("legIdentifier '"+legIdentifier.name()+"' does not start with 'HLT_' or 'leg' ",
-        "TrigCompositeUtils::getIDFromLeg", StatusCode::FAILURE);
-    }
-  }
-
-  
-  bool isLegId(const HLT::Identifier& legIdentifier) {
-    return (legIdentifier.name().find("leg",0)==0);
-  }
-  
-  
-  const Decision* find( const Decision* start, const std::function<bool( const Decision* )>& filter ) {
-    if ( filter( start ) ) return start;
-
-    if ( hasLinkToPrevious(start) ) {
-      const ElementLinkVector<DecisionContainer> seeds = getLinkToPrevious(start);
-      for (const ElementLink<DecisionContainer>& seedEL : seeds) {
-        const Decision* result = find( *seedEL, filter );
-        if (result) return result;
-      }
-    }
-    
-    return nullptr;
-  }
-
-  bool HasObject::operator()( const Decision* composite ) const {
-    return composite->hasObjectLink( m_name );
-  }
-
-  bool HasObjectCollection::operator()( const Decision* composite ) const {
-    return composite->hasObjectCollectionLinks( m_name );
-  }
-
- std::vector<const Decision*> getRejectedDecisionNodes(StoreGateSvc* eventStore, const DecisionID id) {
-    std::vector<const Decision*> output;
-    // The list of containers we need to read can change on a file-by-file basis (it depends on the SMK)
-    // Hence we query SG for all collections rather than maintain a large and ever changing ReadHandleKeyArray
-
-    std::vector<std::string> keys;
-    eventStore->keys(static_cast<CLID>( ClassID_traits< DecisionContainer >::ID() ), keys);
-
-    // Loop over each DecisionContainer,
-    for (const std::string& key : keys) {
-      // Get and check this container
-      if ( key.find("HLTNav") != 0 ) {
-        continue; // Only concerned about the decision containers which make up the navigation, they have name prefix of HLTNav
-      }
-      if ( key == "HLTNav_Summary" ) {
-        continue; //  This is where accepted paths start. We are looking for rejected ones
-      }
-      const DecisionContainer* container = nullptr;
-      if ( eventStore->retrieve( container, key ).isFailure() ) {
-        throw std::runtime_error("Unable to retrieve " + key + " from event store.");
-      }
-      for (const Decision* d : *container) {
-        if (!d->hasObjectLink(featureString())) {
-          // TODO add logic for ComboHypo where this is expected
-          continue; // Only want Decision objects created by HypoAlgs
-        }
-        const ElementLinkVector<DecisionContainer> mySeeds = d->objectCollectionLinks<DecisionContainer>(seedString());
-        if (mySeeds.size() == 0) {
-          continue;
-        }
-        const bool allSeedsValid = std::all_of(mySeeds.begin(), mySeeds.end(), [](const ElementLink<DecisionContainer>& s) { return s.isValid(); });
-        if (!allSeedsValid) {
-          MsgStream(Athena::getMessageSvc(), "TrigCompositeUtils::getRejectedDecisionNodes") << MSG::WARNING
-            << "A Decision object in " << key << " has invalid seeds. "
-            << "The trigger navigation information is incomplete. Skipping this Decision object." << endmsg;
-          continue;
-        }
-        DecisionIDContainer activeChainsIntoThisDecision;
-        decisionIDs(*(mySeeds.at(0)), activeChainsIntoThisDecision); // Get list of active chains from the first parent
-        if (mySeeds.size() > 1) {
-          for (size_t i = 1; i < mySeeds.size(); ++i) {
-            // If there are more than one parent, we only want to keep the intersection of all of the seeds
-            DecisionIDContainer moreActiveChains;
-            decisionIDs(*(mySeeds.at(i)), moreActiveChains);
-            DecisionIDContainer intersection;
-            std::set_intersection(activeChainsIntoThisDecision.begin(), activeChainsIntoThisDecision.end(),
-              moreActiveChains.begin(), moreActiveChains.end(),
-              std::inserter(intersection, intersection.begin()));
-            activeChainsIntoThisDecision = intersection; // Update the output to only be the intersection and continue to any other seeds
-          }
-        }
-        // We now know what chains were active coming into this Decision (d) from ALL seeds
-        // This is the logic required for each HypoTool to have activated and checked if its chain passes
-        // So the size of activeChainsIntoThisDecision corresponds to the number of HypoTools which will have run
-        // What do we care about? A chain, or all chains?
-        DecisionIDContainer chainsToCheck;
-        if (id == 0) { // We care about *all* chains
-          chainsToCheck = activeChainsIntoThisDecision;
-        } else { // We care about *one* chain
-          chainsToCheck.insert(id);
-        }
-        // We have found a rejected decision node *iff* a chainID to check is *not* present here
-        // I.e. the HypoTool for the chain returned a NEGATIVE decision
-        DecisionIDContainer activeChainsPassedByThisDecision;
-        decisionIDs(d, activeChainsPassedByThisDecision);
-        for (const DecisionID checkID : chainsToCheck) {
-          if (activeChainsPassedByThisDecision.count(checkID) == 0 && // I was REJECTED here ...
-              activeChainsIntoThisDecision.count(checkID) == 1) { // ... but PASSSED by all my inputs
-            output.push_back(d);
-            break;
-          }
-        }
-      }
-    }
-    return output;
-  }
-
-  void recursiveGetDecisionsInternal(const Decision* node, 
-    const Decision* comingFrom, 
-    NavGraph& navGraph, 
-    const DecisionID id,
-    const bool enforceDecisionOnNode) {
-
-    // Does this Decision satisfy the chain requirement?
-    DecisionIDContainer idSet = {id};
-    if (enforceDecisionOnNode && id != 0 && !isAnyIDPassing(node, idSet)) {
-      return; // Stop propagating down this leg. It does not concern the chain with DecisionID = id
-    }
-
-    // This Decision object is part of this path through the Navigation
-    navGraph.addNode(node, comingFrom);
-    
-    // Continue to the path(s) by looking at this Decision object's seed(s)
-    if ( hasLinkToPrevious(node) ) {
-      // Do the recursion
-      for ( ElementLink<DecisionContainer> seed : getLinkToPrevious(node)) {
-        const Decision* seedDecision = *(seed); // Dereference ElementLink
-        // Sending true as final parameter for enforceDecisionOnStartNode as we are recursing away from the supplied start node
-        recursiveGetDecisionsInternal(seedDecision, node, navGraph, id, /*enforceDecisionOnNode*/ true);
-      }
-    }
-    return;
-  }
-
-  void recursiveGetDecisions(const Decision* start, 
-    NavGraph& navGraph, 
-    const DecisionID id,
-    const bool enforceDecisionOnStartNode) {
-
-    // Note: we do not require navGraph to be an empty graph. We can extend it.
-    recursiveGetDecisionsInternal(start, /*comingFrom*/nullptr, navGraph, id, enforceDecisionOnStartNode);
-    
-    return;
-  }
-
-
-  std::string dump( const Decision* tc, std::function< std::string( const Decision* )> printerFnc ) {
-    std::string ret; 
-    ret += printerFnc( tc );
-    if ( hasLinkToPrevious(tc) ) {
-      const ElementLinkVector<DecisionContainer> seeds = getLinkToPrevious(tc);
-      for (const ElementLink<DecisionContainer>& seedEL : seeds) {
-        ret += " -> " + dump( *seedEL, printerFnc );
-      }
-    }
-    return ret;
-  }
-
-  
-  const std::string& initialRoIString() {
-    return Decision::s_initialRoIString;
-  }
-
-  const std::string& initialRecRoIString() {
-    return Decision::s_initialRecRoIString;
-  }
-
-  const std::string& roiString() {
-    return Decision::s_roiString;
-  }
-
-  const std::string& viewString() {
-    return Decision::s_viewString;
-  }
-
-  const std::string& featureString() {
-    return Decision::s_featureString;
-  }
-
-  const std::string& seedString() {
-    return Decision::s_seedString;
-  }
-  
-}
-
-- 
GitLab