From 871eae4503d0bd87059bc020e77fd0e28fc76e18 Mon Sep 17 00:00:00 2001
From: Benjamin Michael Wynne <b.m.wynne@ed.ac.uk>
Date: Fri, 14 Dec 2018 16:35:09 +0000
Subject: [PATCH] HLT navigation dump

---
 .../xAODTrigger/Root/TrigComposite_v1.cxx     |  31 +++
 .../xAODTrigger/versions/TrigComposite_v1.h   |   3 +
 .../TrigUpgradeTest/share/checkAOD.py         |  23 ++
 .../TrigValidation/TrigValAlgs/CMakeLists.txt |   7 +-
 .../TrigValAlgs/TrigValAlgs/TrigEDMChecker.h  |  18 +-
 .../TrigValAlgs/src/TrigEDMChecker.cxx        | 197 +++++++++++++++++-
 6 files changed, 271 insertions(+), 8 deletions(-)
 create mode 100644 Trigger/TrigValidation/TrigUpgradeTest/share/checkAOD.py

diff --git a/Event/xAOD/xAODTrigger/Root/TrigComposite_v1.cxx b/Event/xAOD/xAODTrigger/Root/TrigComposite_v1.cxx
index 1d691a39956..aea7b853e1e 100644
--- a/Event/xAOD/xAODTrigger/Root/TrigComposite_v1.cxx
+++ b/Event/xAOD/xAODTrigger/Root/TrigComposite_v1.cxx
@@ -472,6 +472,37 @@ namespace xAOD {
       return acc( *this );
    }
 
+   void TrigComposite_v1::typelessSetObjectLink( const std::string& name, const uint32_t key, const uint32_t clid, const uint16_t beginIndex, const uint16_t endIndex ) {
+
+     // Loop over collections
+     if ( endIndex - beginIndex > 1 ) {
+
+       const std::string mangledName = name + s_collectionSuffix;
+       for ( unsigned int index = beginIndex; index < endIndex; ++index ) {
+
+         // Check uniqueness
+         if ( std::find( linkColNamesNC().begin(), linkColNamesNC().end(), mangledName ) == linkColNamesNC().end() ) {
+
+           this->linkColNamesNC().push_back( mangledName );
+           this->linkColKeysNC().push_back( key );
+           this->linkColIndicesNC().push_back( index );
+           this->linkColClidsNC().push_back( clid );
+         }
+       }
+     }
+     else {
+
+       // Check uniqueness
+       if ( std::find( linkColNamesNC().begin(), linkColNamesNC().end(), name ) == linkColNamesNC().end() ) {
+
+         this->linkColNamesNC().push_back( name );
+         this->linkColKeysNC().push_back( key );
+         this->linkColIndicesNC().push_back( beginIndex );
+         this->linkColClidsNC().push_back( clid );
+       }
+     }
+   }
+
    //
    /////////////////////////////////////////////////////////////////////////////
 
diff --git a/Event/xAOD/xAODTrigger/xAODTrigger/versions/TrigComposite_v1.h b/Event/xAOD/xAODTrigger/xAODTrigger/versions/TrigComposite_v1.h
index dd7ca44018b..0f55daf1f17 100644
--- a/Event/xAOD/xAODTrigger/xAODTrigger/versions/TrigComposite_v1.h
+++ b/Event/xAOD/xAODTrigger/xAODTrigger/versions/TrigComposite_v1.h
@@ -206,6 +206,9 @@ namespace xAOD {
       /// Raw access to the persistent link CLIDs
       const std::vector< uint32_t >& linkColClids() const;
 
+      /// Add a link without type
+      void typelessSetObjectLink( const std::string& name, const uint32_t key, const uint32_t clid, const uint16_t beginIndex, const uint16_t endIndex = 0 );
+
       /// @}
 
       /// For use in validation, when copying element links from one object to another
diff --git a/Trigger/TrigValidation/TrigUpgradeTest/share/checkAOD.py b/Trigger/TrigValidation/TrigUpgradeTest/share/checkAOD.py
new file mode 100644
index 00000000000..15996631172
--- /dev/null
+++ b/Trigger/TrigValidation/TrigUpgradeTest/share/checkAOD.py
@@ -0,0 +1,23 @@
+include("AthenaPoolDataModelTest/esdtoesd_base.py")
+
+svcMgr.EventSelector.InputCollections   = [ "/eos/atlas/atlascerngroupdisk/data-art/grid-output/21.0/Athena/x86_64-slc6-gcc62-opt/2018-12-08T2201/TrigAnalysisTest/test_physics_pp_v7_rdotoesdaod_grid/AOD.pool.root" ]
+#svcMgr.EventSelector.InputCollections   = [ "myESD.pool.root" ]
+from TrigValAlgs.TrigValAlgsConf import TrigEDMChecker
+MessageSvc.defaultLimit = 9999999
+MessageSvc.useColors = True
+checker                                 = TrigEDMChecker()
+checker.OutputLevel                     = DEBUG
+checker.doDumpAll                       = False
+checker.doDumpStoreGate                 = False
+checker.doDumpNavigation                = True
+checker.doDumpTrigCompsiteNavigation    = True
+
+checker.Decisions = "exportTest"
+checker.dumpTrigCompositeContainers = [ "exportTest" ]
+
+
+from AthenaCommon.AppMgr import topSequence
+topSequence += checker
+
+theApp.EvtMax = 10
+svcMgr.EventSelector.SkipEvents = 9
diff --git a/Trigger/TrigValidation/TrigValAlgs/CMakeLists.txt b/Trigger/TrigValidation/TrigValAlgs/CMakeLists.txt
index db647d60d28..9553cb8672b 100644
--- a/Trigger/TrigValidation/TrigValAlgs/CMakeLists.txt
+++ b/Trigger/TrigValidation/TrigValAlgs/CMakeLists.txt
@@ -8,6 +8,7 @@ atlas_subdir( TrigValAlgs )
 # Declare the package's dependencies:
 atlas_depends_on_subdirs( PUBLIC
                           Control/AthenaBaseComps
+                          Control/AthAnalysisBaseComps
                           GaudiKernel
                           TestPolicy
                           Trigger/TrigAnalysis/TrigDecisionTool
@@ -45,9 +46,13 @@ atlas_depends_on_subdirs( PUBLIC
                           Reconstruction/Particle
                           Reconstruction/tauEvent
                           Tracking/TrkEvent/VxSecVertex
+                          Trigger/TrigNavigation
+                          Trigger/TrigNavStructure
+                          Trigger/TrigConfiguration/TrigConfHLTData
                           Trigger/TrigConfiguration/TrigConfigSvc
                           Trigger/TrigEvent/TrigDecisionEvent
                           Trigger/TrigEvent/TrigMissingEtEvent
+                          Trigger/TrigSteer/DecisionHandling
                           Trigger/TrigTruthEvent/TrigInDetTruthEvent
                           Trigger/TrigT1/TrigT1Interfaces )
 
@@ -60,7 +65,7 @@ atlas_add_component( TrigValAlgs
                      src/*.cxx
                      src/components/*.cxx
                      INCLUDE_DIRS ${XERCESC_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS}
-                     LINK_LIBRARIES ${XERCESC_LIBRARIES} ${CLHEP_LIBRARIES} AthenaBaseComps GaudiKernel TrigDecisionToolLib TrigCaloEvent TrigInDetEvent TrigMuonEvent TrigNavToolsLib TrigNavigationLib TrigParticle TrigSteeringEvent AthenaKernel CxxUtils EventInfo xAODEventInfo xAODBTagging xAODEgamma xAODJet xAODMuon xAODTau xAODTracking xAODTrigBphys xAODTrigCalo xAODTrigEgamma xAODTrigMinBias xAODTrigMissingET xAODTrigMuon xAODCore xAODTrigger AnalysisTriggerEvent MuonCombinedToolInterfaces Particle tauEvent VxSecVertex TrigConfigSvcLib TrigConfHLTData TrigRoiConversionLib TrigDecisionEvent TrigMissingEtEvent TrigInDetTruthEvent TrigT1Interfaces )
+                     LINK_LIBRARIES ${XERCESC_LIBRARIES} ${CLHEP_LIBRARIES} AthenaBaseComps AthAnalysisBaseCompsLib GaudiKernel TrigDecisionToolLib TrigCaloEvent TrigInDetEvent TrigMuonEvent TrigNavToolsLib TrigNavigationLib TrigParticle TrigSteeringEvent AthenaKernel CxxUtils EventInfo xAODEventInfo xAODBTagging xAODEgamma xAODJet xAODMuon xAODTau xAODTracking xAODTrigBphys xAODTrigCalo xAODTrigEgamma xAODTrigMinBias xAODTrigMissingET xAODTrigMuon xAODCore xAODTrigger AnalysisTriggerEvent MuonCombinedToolInterfaces Particle tauEvent VxSecVertex TrigConfigSvcLib TrigConfHLTData TrigRoiConversionLib TrigDecisionEvent TrigMissingEtEvent TrigInDetTruthEvent TrigT1Interfaces DecisionHandlingLib )
 
 # Install files from the package:
 atlas_install_headers( TrigValAlgs )
diff --git a/Trigger/TrigValidation/TrigValAlgs/TrigValAlgs/TrigEDMChecker.h b/Trigger/TrigValidation/TrigValAlgs/TrigValAlgs/TrigEDMChecker.h
index d6197e72c42..eb2298c6124 100755
--- a/Trigger/TrigValidation/TrigValAlgs/TrigValAlgs/TrigEDMChecker.h
+++ b/Trigger/TrigValidation/TrigValAlgs/TrigValAlgs/TrigEDMChecker.h
@@ -9,12 +9,20 @@
 #include "GaudiKernel/ObjectVector.h"
 #include "CLHEP/Units/SystemOfUnits.h"
 
-#include "AthenaBaseComps/AthAlgorithm.h"
+#include "AthAnalysisBaseComps/AthAnalysisAlgorithm.h"
 
 #include "xAODTrigger/TrigCompositeContainer.h"
 
 #include "AthenaKernel/IClassIDSvc.h"
 
+#include "StoreGate/ReadHandleKey.h"
+#include "StoreGate/WriteHandleKey.h"
+#include "xAODTrigger/TrigNavigation.h"
+#include "DecisionHandling/TrigCompositeUtils.h"
+#include "TrigNavigation/Navigation.h"
+#include "GaudiKernel/ToolHandle.h"
+
+
 #include <string>
 
 // forward declarations of muon track classes used in TrigMuonEFInfo
@@ -28,7 +36,7 @@ namespace Rec {
   class IMuonPrintingTool;
 }
 
-class TrigEDMChecker : public AthAlgorithm  {
+class TrigEDMChecker : public AthAnalysisAlgorithm  {
 
  public:
 
@@ -173,6 +181,9 @@ class TrigEDMChecker : public AthAlgorithm  {
    bool m_doDumpAllTrigComposite;
    std::vector<std::string> m_dumpTrigCompositeContainers;
 
+   bool m_doDumpNavigation;
+   StatusCode dumpNavigation();
+
    /**
     * @brief Dump information on TrigComposite collections
     *
@@ -201,6 +212,9 @@ class TrigEDMChecker : public AthAlgorithm  {
 
    ServiceHandle< ::IClassIDSvc > m_clidSvc;
 
+   SG::ReadHandleKey< xAOD::TrigNavigation > m_navigationHandleKey{ this, "TrigNavigation", "TrigNavigation", "" };
+   SG::WriteHandleKey<TrigCompositeUtils::DecisionContainer> m_decisionsKey{ this, "Decisions", "RoIDecisions", "Decisions created from TEs" };
+   ToolHandle< HLT::Navigation > m_navigationTool{ this, "NavigationTool", "HLT::Navigation/Navigation", "" };
 };
 
 #endif // TRIG_EDM_CHECKER_H
diff --git a/Trigger/TrigValidation/TrigValAlgs/src/TrigEDMChecker.cxx b/Trigger/TrigValidation/TrigValAlgs/src/TrigEDMChecker.cxx
index abebc076bba..e9d474636d1 100644
--- a/Trigger/TrigValidation/TrigValAlgs/src/TrigEDMChecker.cxx
+++ b/Trigger/TrigValidation/TrigValAlgs/src/TrigEDMChecker.cxx
@@ -13,6 +13,10 @@
 
 #include "xAODTrigger/TrigPassBitsContainer.h"
 #include "xAODTrigger/TrigPassBits.h"
+#include "xAODTrigger/TriggerMenuContainer.h"
+#include "TrigNavStructure/TriggerElement.h"
+#include "TrigConfHLTData/HLTUtils.h"
+
 #include "AthContainers/debug.h"
 #include "xAODJet/JetContainer.h"
 #include "xAODJet/JetConstituentVector.h"
@@ -98,6 +102,7 @@
 
 #include <iostream>
 #include <fstream>
+#include <queue>
 
 static  int trackWarningNum;
 static  int vertexWarningNum;
@@ -105,7 +110,7 @@ static  int  maxRepWarnings;
 
 
 TrigEDMChecker::TrigEDMChecker(const std::string& name, ISvcLocator* pSvcLocator)
-  : AthAlgorithm(name, pSvcLocator),
+  : AthAnalysisAlgorithm(name, pSvcLocator),
     m_muonPrinter("Rec::MuonPrintingTool/MuonPrintingTool"),
     m_clidSvc( "ClassIDSvc", name )
 {
@@ -155,6 +160,7 @@ TrigEDMChecker::TrigEDMChecker(const std::string& name, ISvcLocator* pSvcLocator
   declareProperty("doDumpAllTrigComposite", m_doDumpAllTrigComposite = false );
   declareProperty("dumpTrigCompositeContainers", m_dumpTrigCompositeContainers, "List of TC to dump" );
   declareProperty("doDumpTrigCompsiteNavigation", m_doDumpTrigCompsiteNavigation = false );
+  declareProperty("doDumpNavigation", m_doDumpNavigation = false );
   declareProperty( "ClassIDSvc", m_clidSvc, "Service providing CLID info" );
 }
 
@@ -164,6 +170,10 @@ TrigEDMChecker::~TrigEDMChecker() {}
 
 StatusCode TrigEDMChecker::initialize() {
 
+  ATH_CHECK( m_navigationHandleKey.initialize() );
+  ATH_CHECK( m_decisionsKey.initialize() );
+  ATH_CHECK( m_navigationTool.retrieve() );
+
   ATH_MSG_DEBUG("Initializing TrigEDMChecker");
 
   ATH_MSG_INFO("REGTEST Initializing...");
@@ -518,6 +528,15 @@ StatusCode TrigEDMChecker::execute() {
     ATH_MSG_DEBUG(evtStore()->dump());
   }
 
+  if (m_doDumpAll || m_doDumpNavigation) {
+    StatusCode sc = dumpNavigation();
+    if ( sc.isFailure() ) {
+      ATH_MSG_ERROR("The method dumpNavigation() failed");
+    }
+  }
+
+	ATH_CHECK( dumpTrigComposite() );
+
   if (m_doDumpAll || m_doDumpTrigCompsiteNavigation) {
     std::string trigCompositeSteering;
     ATH_CHECK(TrigCompositeNavigationToDot(trigCompositeSteering));
@@ -532,8 +551,9 @@ StatusCode TrigEDMChecker::execute() {
     ofile << trigCompositeSteering;
   }
 
-	ATH_CHECK( dumpTrigComposite() );
-	
+
+
+
 	return StatusCode::SUCCESS;
 
 }
@@ -4053,10 +4073,16 @@ StatusCode TrigEDMChecker::checkTrigCompositeElementLink(const xAOD::TrigComposi
 
 
 StatusCode TrigEDMChecker::TrigCompositeNavigationToDot(std::string& returnValue) {
-  std::vector<std::string> keys;
+
   // This constexpr is evaluated at compile time
   const CLID TrigCompositeCLID = static_cast<CLID>( ClassID_traits< xAOD::TrigCompositeContainer >::ID() );
-  evtStore()->keys(TrigCompositeCLID, keys);
+  std::vector<std::string> keys;
+  if ( m_doDumpAll ) {
+    evtStore()->keys(TrigCompositeCLID, keys);
+  }
+  else {
+    std::vector<std::string> keys = m_dumpTrigCompositeContainers;
+  }
   std::string typeNameTC;
   ATH_CHECK(m_clidSvc->getTypeNameOfID(TrigCompositeCLID, typeNameTC));
   ATH_MSG_DEBUG("Got " <<  keys.size() << " keys for " << typeNameTC);
@@ -4132,3 +4158,164 @@ StatusCode TrigEDMChecker::TrigCompositeNavigationToDot(std::string& returnValue
   returnValue.assign( ss.str() );
   return StatusCode::SUCCESS;
 }
+
+StatusCode TrigEDMChecker::dumpNavigation()
+{
+  // Get object from store
+  const xAOD::TrigNavigation * navigationHandle = nullptr;
+  ATH_CHECK( evtStore()->retrieve( navigationHandle, m_navigationHandleKey.key() ) );
+  // Proper version doesn't work - conversion issue?
+  //SG::ReadHandle< xAOD::TrigNavigation > navigationHandle = SG::ReadHandle< xAOD::TrigNavigation >( m_navigationHandleKey );
+  //if ( !navigationHandle.isValid() ) ATH_MSG_FATAL( "Could not retrieve navigation" );
+
+  // Get serialised navigation info
+  const std::vector< unsigned int > serialisedNavigation = navigationHandle->serialized();
+  ATH_MSG_INFO( "Serialised navigation size: " << serialisedNavigation.size() );
+
+  // Convert the input
+  HLT::Navigation* testNav = m_navigationTool.get();
+  testNav->deserialize( serialisedNavigation );
+
+  // Make a map of TE name hashes
+  const xAOD::TriggerMenuContainer * testMenu = nullptr;
+  ATH_CHECK( inputMetaStore()->retrieve( testMenu, "TriggerMenu" ) );
+  std::map< int, std::string > hash2string;
+  for ( auto const& sequence : testMenu->front()->sequenceInputTEs() ) {
+    for ( auto const& name : sequence ) {
+      int hash = TrigConf::HLTUtils::string2hash( name );
+      hash2string[ hash ] = name;
+    }
+  }
+
+  // Map TE names to chain names
+  unsigned int chainCounter = 0;
+  std::map< int, std::string > hash2chain;
+  for ( auto const& chain : testMenu->front()->chainSignatureOutputTEs() ) {
+
+    // Find the chain name
+    std::string chainName = testMenu->front()->chainNames()[ chainCounter ];
+    ++chainCounter;
+
+    // Find all associated TEs
+    for ( auto const& signature : chain ) {
+      for ( auto const& name : signature ) {
+        int hash = TrigConf::HLTUtils::string2hash( name );
+        hash2string[ hash ] = name; // for decoding
+        hash2chain[ hash ] = chainName;
+      }
+    }
+  }
+
+  // Define a map of TE features, to the TEs that use them. Needs a custom sort lambda
+  auto cmpLambda = []( const HLT::TriggerElement::FeatureAccessHelper &lhs, const HLT::TriggerElement::FeatureAccessHelper &rhs) { 
+
+    // Compare indices if CLID matches
+    if ( lhs.getCLID() == rhs.getCLID() ) return ( lhs.getIndex() < rhs.getIndex() );
+
+    // Compare CLIDs
+    else return ( lhs.getCLID() < rhs.getCLID() );
+  };
+  std::map< HLT::TriggerElement::FeatureAccessHelper, std::vector< HLT::TriggerElement* >, decltype(cmpLambda) > feature2element(cmpLambda);
+
+  // Retrieve all TE features and add them to the map
+  std::vector< HLT::TriggerElement* > allTEs;
+  testNav->getAll( allTEs, false );
+  for ( auto element : allTEs ) {
+
+    // Add TE features to the big map 
+    for ( auto helper : element->getFeatureAccessHelpers() ) {
+      feature2element[ helper ].push_back( element );
+    }
+  }
+
+  // Debug - output all TEs and their ancestors
+  // No duplication - only print terminal nodes
+  for ( auto element : allTEs ) {
+    if ( testNav->isTerminalNode( element ) ) {
+      ATH_MSG_INFO( "+++++++++++ " << hash2string[ element->getId() ] << " is terminal node" );
+      ATH_MSG_INFO( "ptr: " << element );
+      std::queue< HLT::TriggerElement* > allAncestors;
+      allAncestors.push( element );
+      while ( allAncestors.size() ) {
+
+        HLT::TriggerElement * thisElement = allAncestors.front();
+        allAncestors.pop();
+        auto theseAncestors = thisElement->getRelated( HLT::TriggerElement::Relation::seededByRelation );
+
+        // Dump TE
+        ATH_MSG_INFO( "te: " << thisElement->getId() << " " << hash2string[ thisElement->getId() ] );
+        ATH_MSG_INFO( "  chain: " << hash2chain[ thisElement->getId() ] );
+        for ( auto helper : thisElement->getFeatureAccessHelpers() ) {
+          ATH_MSG_INFO( "   feat: " << helper );
+        }
+        ATH_MSG_INFO( theseAncestors.size() << " ancestors" );
+
+        // Examine ancestors
+        for ( auto ancestor : theseAncestors ) {
+          allAncestors.push( ancestor );
+        }
+      }
+    }
+  }
+
+  // Make the decision container
+  SG::WriteHandle< TrigCompositeUtils::DecisionContainer > outputNavigation = TrigCompositeUtils::createAndStore( m_decisionsKey, getContext() ); 
+  auto decisionOutput = outputNavigation.ptr();
+
+  // Find unique chains associated with a feature
+  std::map< HLT::TriggerElement const*, std::vector< int > > element2decisions;
+  for ( auto pair : feature2element ) {
+
+    // Get the feature info
+    std::string featureName = testNav->label( pair.first.getCLID(), pair.first.getIndex().subTypeIndex() );
+    auto sgKey = evtStore()->stringToKey( featureName, pair.first.getCLID() );
+
+    // Store RoIs with appropriate label ?
+    std::string storeFeatureName = "feature";
+/*    if ( pair.first.getCLID() == ClassID_traits< TrigRoiDescriptor >::ID() ) {
+      storeFeatureName = "roi";
+    }*/
+
+    // Make a decision object for the feature
+    auto decision = TrigCompositeUtils::newDecisionIn( decisionOutput );
+    decision->typelessSetObjectLink( storeFeatureName, sgKey, pair.first.getCLID(), pair.first.getIndex().objectsBegin(), pair.first.getIndex().objectsEnd() );
+
+    // Examine associated TEs, look for chains
+    std::set< std::string > passedChains;
+    for ( HLT::TriggerElement const* element : pair.second ) {
+
+      // TODO - find out what chains actually passed!
+      passedChains.insert( hash2chain[ element->getId() ] );
+
+      // Index the TE
+      int decisionNumber = decisionOutput->size() - 1;
+      element2decisions[ element ].push_back( decisionNumber );
+    }
+
+    // Store unique chains in the decision
+    for ( auto& chain : passedChains ) {
+      TrigCompositeUtils::addDecisionID( TrigConf::HLTUtils::string2hash( chain ), decision );
+    }
+  }
+
+  // Store decision ancestry (had to go through once before to ensure indices populated)
+  unsigned int decisionCounter = 0;
+  for ( auto pair : feature2element ) {
+
+    // Get current decision
+    auto decision = decisionOutput->at( decisionCounter );
+    ++decisionCounter;
+
+    // Find ancestor TEs
+    for ( auto element : pair.second ) {
+      auto theseAncestors = element->getRelated( HLT::TriggerElement::Relation::seededByRelation );
+      for ( auto ancestor : theseAncestors ) {
+        for ( int decisionIndex : element2decisions[ ancestor ] ) {
+          TrigCompositeUtils::linkToPrevious( decision, m_decisionsKey.key(), decisionIndex );
+        }
+      }
+    }
+  }
+
+  return StatusCode::SUCCESS;
+}
-- 
GitLab