Commit fa404f92 authored by Frank Winklmeier's avatar Frank Winklmeier
Browse files

Merge branch 'findLinkCaching_mark2' into 'master'

[ATR-21353] Refactor R3 feature access trigger navigation graph traversal to keep graph structure.

See merge request !35340
parents 7836bd3d 5cbe0501
......@@ -16,7 +16,7 @@ std::vector< TrigCompositeUtils::LinkInfo<CONTAINER> > Trig::ChainGroup::feature
ATH_MSG_ERROR("featureCollectionMode may only be called with: "
"TrigDefs::lastFeatureOfType - stop exploring each route through the navigation once a feature matching all requirements is found. "
"TrigDefs::allFeaturesOfType - always fully explore each route throught the navigation graph and collect all matching features.");
errState = true;
errState = true;
}
// TODO when we decide what happens to CacheGlobalMemory - this needs to be updated to use a ReadHandle
......@@ -47,7 +47,7 @@ std::vector< TrigCompositeUtils::LinkInfo<CONTAINER> > Trig::ChainGroup::feature
}
// For each chain, collect Navigation information
std::vector< ElementLinkVector<TrigCompositeUtils::DecisionContainer> > allLinearNavigationPaths;
TrigCompositeUtils::NavGraph navGraph;
// Loop over HLT chains
TrigCompositeUtils::DecisionIDContainer chainIDs;
......@@ -59,10 +59,10 @@ std::vector< TrigCompositeUtils::LinkInfo<CONTAINER> > Trig::ChainGroup::feature
// Obtain navigation routes for passed chains
// Final parameter TRUE as the chain passed (has its ID in terminusNode)
TrigCompositeUtils::recursiveGetDecisions(terminusNode, allLinearNavigationPaths, fchain->getChainHashId(), true);
TrigCompositeUtils::recursiveGetDecisions(terminusNode, navGraph, fchain->getChainHashId(), true);
ATH_MSG_DEBUG("Added all passed navigation paths for chain " << fchain->getChainName()
<< ", total paths:" << allLinearNavigationPaths.size());
ATH_MSG_DEBUG("Added all passed navigation data for chain " << fchain->getChainName()
<< ", total nodes:" << navGraph.nodes() << " total edges:" << navGraph.edges());
if (condition == TrigDefs::includeFailedDecisions) {
std::vector<const TrigCompositeUtils::Decision*> rejectedDecisionNodes =
......@@ -73,11 +73,11 @@ std::vector< TrigCompositeUtils::LinkInfo<CONTAINER> > Trig::ChainGroup::feature
for (const TrigCompositeUtils::Decision* rejectedNode : rejectedDecisionNodes) {
// Final parameter FALSE as the chain failed here (its ID was removed from rejectedNode)
TrigCompositeUtils::recursiveGetDecisions(rejectedNode, allLinearNavigationPaths, fchain->getChainHashId(), false);
TrigCompositeUtils::recursiveGetDecisions(rejectedNode, navGraph, fchain->getChainHashId(), false);
}
ATH_MSG_DEBUG("Added all failed navigation paths for chain " << fchain->getChainName()
<< ", total paths:" << allLinearNavigationPaths.size());
ATH_MSG_DEBUG("Added all failed navigation data for chain " << fchain->getChainName()
<< ", total nodes:" << navGraph.nodes() << " total edges:" << navGraph.edges());
}
} else {
......@@ -85,23 +85,19 @@ std::vector< TrigCompositeUtils::LinkInfo<CONTAINER> > Trig::ChainGroup::feature
}
}
if (allLinearNavigationPaths.size() == 0) {
ATH_MSG_DEBUG("No navigation paths found for this chain group of " << names().size() << " chains.");
if (navGraph.edges() == 0) {
ATH_MSG_DEBUG("No navigation path data found for this chain group of " << names().size() << " chains. "
<< "Total nodes:" << navGraph.nodes() << " total edges:" << navGraph.edges());
}
if (msg().level() <= MSG::VERBOSE) {
size_t count = 0;
for (const ElementLinkVector<TrigCompositeUtils::DecisionContainer>& path : allLinearNavigationPaths) {
ATH_MSG_VERBOSE("Printing path " << ++count << " of " << allLinearNavigationPaths.size() << ", path has " << path.size() << " elements.");
for (const ElementLink<TrigCompositeUtils::DecisionContainer>& node : path) {
ATH_MSG_VERBOSE(" -- " << node.dataID() << " #" << node.index());
}
}
navGraph.printAllPaths(msg(), MSG::VERBOSE);
}
const bool lastFeatureOfTypeFlag = (featureCollectionMode == TrigDefs::lastFeatureOfType);
std::vector<TrigCompositeUtils::LinkInfo<CONTAINER>> returnVector =
TrigCompositeUtils::getFeaturesOfType<CONTAINER>(allLinearNavigationPaths, containerSGKey, lastFeatureOfTypeFlag, navElementLinkKey, chainIDs);
TrigCompositeUtils::recursiveGetFeaturesOfType<CONTAINER>(navGraph, containerSGKey, lastFeatureOfTypeFlag, navElementLinkKey, chainIDs);
// Check for missing navigation data if requesting the default "feature" links
if (navElementLinkKey == TrigCompositeUtils::featureString()) {
......
/*
Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
*/
#ifndef TrigCompositeUtils_NavGraph_h
#define TrigCompositeUtils_NavGraph_h
#include <set>
#include "AthContainers/AuxElement.h"
#include "xAODTrigger/TrigCompositeContainer.h"
#include "xAODTrigger/TrigCompositeAuxContainer.h"
namespace TrigCompositeUtils {
/**
* @class NavGraphNode
* @brief Transient utility class to represent a node in a graph (m_decisionObject), and a set of edges (m_filteredSeeds)
* to other nodes which are parents of this node.
**/
class NavGraphNode {
public:
/**
* @brief Construct a NavGraphNode shadowing a node in the full xAOD navigation graph
* @param[in] me The Decision object node from the full xAOD navigation graph which this object is representing.
**/
NavGraphNode(const Decision* me);
/**
* @brief Form an edge in the graph from this node to another one.
* @param[in] to The "parent" or "seed" Decision object from the perspective of this Node's shadowed Decision object.
* @return True if a new edge was added. False if this was a duplicated call to add this edge.
**/
bool linksTo(const NavGraphNode* to);
/**
* @brief Return a const pointer to the Decision object node which this NavGraphNode is shadowing.
**/
const Decision* node() const;
/**
* @brief Return a set of const pointers to the Decision object nodes which this NavGraphNode seeds from.
* Note: NavGraph is used to represent a sub-graph of the full navigation graph, hence it is expected that
* the set of seeds returned from this function may be smaller than the set of seeds returned from the
* shadowed xAOD Decision Object.
**/
const std::set<const NavGraphNode*>& seeds() const;
private:
const Decision* m_decisionObject; //!< The Decision object node which I shadow
std::set<const NavGraphNode*> m_filteredSeeds; //!< My seeds (edges in the graph), filtered on per-chain requirements.
};
/**
* @class NavGraph
* @brief Structure to hold a transient Directed Acyclic Graph (DAG) structure.
* NavGraph is populated from, and forms a sub-graph over the full Run 3 trigger navigation graph in a single event.
* Requirements on specific chains, and the specification of allowable graph entry-points are considered in the construction of the NavGraph sub-graph.
* Once one of these sub-graphs is fully populated to a given specification, it is searched by the feature-retrieval code to find features.
**/
class NavGraph {
public:
/**
* @brief Construct an empty NavGraph
**/
NavGraph();
/**
* @brief Add a new NavGraphNode which shadows the xAOD Decision object "node" from the full navigation graph
* @param[in] node The xAOD Decision object which the new node will shadow. Will not cause duplication if node has already been added.
* @param[in] comingFrom If not null, used to indicate which xAOD Decision object was the seed of "node". This is used to form an edge in the graph.
* Alternately, if comingFrom is null then "node" is taken as a final node (one of the locations from which the graph should be explored) and hence is added
* to the finalNodes set.
**/
void addNode(const Decision* node, const Decision* comingFrom = nullptr);
/**
* @brief Get all final nodes.
* @return Set of final nodes. These are the nodes which were added without any "comingFrom".
* To explore the NavGraph fully, one should explore recursively from each of the final nodes.
**/
const std::set<NavGraphNode*>& finalNodes() const;
/**
* @return Total number of unique nodes in the NavGraph.
**/
size_t nodes() const;
/**
* @return Total number of unique edges in the NavGraph.
**/
size_t edges() const;
/**
* @bried Helper function. Print the internal graph structure to the terminal.
* @param[in] log Athena messaging service reference.
* @param[in] msgLevel Athena messaging service verbosity level.
**/
void printAllPaths(MsgStream& log, MSG::Level msgLevel = MSG::VERBOSE) const;
private:
/**
* @bried Internal helper function. Recursively print the graph structure from a single given starting node.
* @param[in] nav The node to recursively explore.
* @param[in] level The current depth of recursion. Used to pad output format.
* @param[in] log Athena messaging service reference.
* @param[in] msgLevel Athena messaging service verbosity level.
**/
void recursivePrintNavPath(const NavGraphNode& nav, size_t level, MsgStream& log, MSG::Level msgLevel) const;
std::map<const Decision*, NavGraphNode> m_nodes; //!< Map of nodes in the graph. Indexed on the underlying Decision object's transient pointer.
std::set<NavGraphNode*> m_finalNodes; //!< Entry points into the navigation graph. When iterating over the graph, start from all of these places.
size_t m_edges; //!< Statistics on the number of edges, connecting the nodes in the graph.
};
}
#endif // TrigCompositeUtils_NavGraph_h
......@@ -17,6 +17,7 @@
#include "StoreGate/ReadHandleKey.h"
#include "StoreGate/WriteHandle.h"
#include "GaudiKernel/ThreadLocalContext.h"
#include "GaudiKernel/MsgStream.h"
#include "AthContainers/AuxElement.h"
#include "xAODTrigger/TrigCompositeContainer.h"
......@@ -25,6 +26,7 @@
#include "TrigDecisionInterface/Conditions.h"
#include "HLTIdentifier.h"
#include "NavGraph.h"
namespace TrigCompositeUtils {
......@@ -251,17 +253,20 @@ namespace TrigCompositeUtils {
**/
std::vector<const Decision*> getRejectedDecisionNodes(StoreGateSvc* eventStore, const DecisionID id = 0);
/**
* @brief Search back in time from "start" and locate all linear paths back through Decision objects for a given chain.
* @param[in] start The Decision object to start the search from. Typically this will be one of the terminus objects from the HLTNav_Summary (regular or rerun).
* @param[out] linkVector Each entry in the outer vector represents a path through the graph. For each path, a vector of ElementLinks describing the path is returned.
* @brief Search back in time from "node" and locate all paths back through Decision objects for a given chain.
* @param[in] node The Decision object to start the search from. Typically this will be one of the terminus objects from the HLTNav_Summary.
* @param[inout] navPaths Holds a sub-graph of the full navigation graph, filtered by DecisionID. An already partially populated graph may be provided as input.
* @param[in] id Optional DecisionID of a Chain to trace through the navigation. If omitted, no chain requirement will be applied.
* @param[in] enforceDecisionOnStartNode If the check of DecisionID should be carried out on the start node.
* enforceDecisionOnStartNode should be true if navigating for a trigger which passed (e.g. starting from HLTPassRaw)
* enforceDecisionOnStartNode should be false if navigating for a trigger which failed but whose failing start node(s) were recovered via getRejectedDecisionNodes
**/
void recursiveGetDecisions(const Decision* start,
std::vector<ElementLinkVector<DecisionContainer>>& linkVector,
void recursiveGetDecisions(const Decision* node,
NavGraph& navGraph,
const DecisionID id = 0,
const bool enforceDecisionOnStartNode = true);
......@@ -269,12 +274,13 @@ namespace TrigCompositeUtils {
/**
* @brief Used by recursiveGetDecisions
* @see recursiveGetDecisions
* @param comingFrom The parent node which has a link in the navigation to this "node"
**/
void recursiveGetDecisionsInternal(const Decision* start,
const size_t location,
std::vector<ElementLinkVector<DecisionContainer>>& linkVector,
const DecisionID id = 0,
const bool enforceDecisionOnNode = true);
void recursiveGetDecisionsInternal(const Decision* node,
const Decision* comingFrom,
NavGraph& navGraph,
const DecisionID id,
const bool enforceDecisionOnNode);
/**
* @brief Additional information returned by the TrigerDecisionTool's feature retrieval, contained within the LinkInfo.
......@@ -330,20 +336,37 @@ namespace TrigCompositeUtils {
/**
* @brief Extract features from the supplied linkVector (obtained through recursiveGetDecisions).
* @param[in] linkVector Vector of paths through the navigation which are to be considered.
* @param[in] navPaths Sub-graph of the trigger navigation which is to be considered.
* @param[in] lastFeatureOfType True for TrigDefs::lastFeatureOfType. stops at the first feature (of the correct type) found per path through the navigation.
* @param[in] featureName Optional name of feature link as saved online. The "feature" link is enforced, others may have been added.
* @param[in] chains Optional set of Chain IDs which features are being requested for. Used to set the ActiveState of returned LinkInfo objects.
* @return Typed vector of LinkInfo. Each LinkInfo wraps an ElementLink to a feature and a pointer to the feature's Decision object in the navigation.
**/
template<class CONTAINER>
const std::vector< LinkInfo<CONTAINER> > getFeaturesOfType(
const std::vector<ElementLinkVector<DecisionContainer>>& linkVector,
const std::vector< LinkInfo<CONTAINER> > recursiveGetFeaturesOfType(
const NavGraph& navGraph,
const std::string containerSGKey = "",
const bool lastFeatureOfType = true,
const std::string& navElementLinkKey = featureString(),
const DecisionIDContainer chainIDs = DecisionIDContainer());
/**
* @see recursiveGetFeaturesOfType
* @brief Internal implimentation called by recursiveGetFeaturesOfType, and by itself
* @param[inout] features The untimate return vector. New links are to be appended.
* @param[inout] fullyExploredFrom Cache of graph nodes which have been fully explored, and hence don't need exploring again should they show up.
* @param[in] navGraphNode The current node in the navGraph which is being explored.
**/
template<class CONTAINER>
void recursiveGetFeaturesOfTypeInternal(
std::vector< LinkInfo<CONTAINER> >& features,
std::set<const NavGraphNode*>& fullyExploredFrom,
const NavGraphNode* navGraphNode,
const std::string containerSGKey,
const bool lastFeatureOfType,
const std::string& navElementLinkKey,
const DecisionIDContainer chainIDs);
/**
* @brief Perform a recursive search for ElementLinks of type T and name 'linkName', starting from Decision object 'start'
* For the case of multiple links, this function only returns the first one found. @see findLinks
......@@ -400,11 +423,6 @@ namespace TrigCompositeUtils {
**/
std::string dump( const Decision* tc, std::function< std::string( const Decision* )> printerFnc );
}
#include "TrigCompositeUtils/TrigCompositeUtils.icc"
......
......@@ -48,8 +48,6 @@ namespace TrigCompositeUtils {
// We can keep a record of nodes which we have already explored, these we can safely skip over.
if (visitedCache->count(start) == 1) {
return; // Early exit
} else {
visitedCache->insert(start);
}
}
ElementLinkVector<T> featureLinks;
......@@ -96,6 +94,10 @@ namespace TrigCompositeUtils {
for (const auto& seed : getLinkToPrevious(start)) {
findLinks<T>(*seed, linkName, links, behaviour);
}
// Fully explored this node
if (visitedCache != nullptr) {
visitedCache->insert(start);
}
}
template<typename T>
......@@ -128,9 +130,10 @@ namespace TrigCompositeUtils {
return LinkInfo<T>(); // invalid link
}
template<class CONTAINER>
void filterLinkVectorByContainerKey(const std::string& containerSGKey, ElementLinkVector<CONTAINER>& vector) {
if (containerSGKey == "") {
if (containerSGKey.empty()) {
return;
}
auto it = std::remove_if(vector.begin(), vector.end(), [&](const ElementLink<CONTAINER>& el) {
......@@ -140,97 +143,138 @@ namespace TrigCompositeUtils {
vector.erase(it, vector.end());
}
template<class CONTAINER>
const std::vector< LinkInfo<CONTAINER> > getFeaturesOfType(
const std::vector<ElementLinkVector<DecisionContainer>>& linkVector,
const std::vector< LinkInfo<CONTAINER> > recursiveGetFeaturesOfType(
const NavGraph& navGraph,
const std::string containerSGKey,
const bool lastFeatureOfType,
const std::string& navElementLinkKey,
const DecisionIDContainer chainIDs) {
std::vector< LinkInfo<CONTAINER> > features;
// For each unique path through the navigation for a given chain
for (const ElementLinkVector<DecisionContainer>& decisionPath : linkVector) {
// For each step along this path, starting at the terminus and working back towards L1
for (const ElementLink<DecisionContainer>& decisionObjLink : decisionPath) {
const Decision* decisionObj = (*decisionObjLink);
ElementLinkVector<CONTAINER> featureLinks;
// Look up what named links are available in the Decision Object
std::vector<std::string> availableLinkNames;
if (navElementLinkKey == "") {
const std::vector<std::string> getSingleLinkNames = decisionObj->getObjectNames<CONTAINER>();
const std::vector<std::string> getCollectionLinkNames = decisionObj->getObjectCollectionNames<CONTAINER>();
std::copy(getSingleLinkNames.begin(), getSingleLinkNames.end(), std::back_inserter(availableLinkNames));
std::copy(getCollectionLinkNames.begin(), getCollectionLinkNames.end(), std::back_inserter(availableLinkNames));
} else { // Just looking for an explicitly named feature
availableLinkNames.push_back( navElementLinkKey );
}
std::vector< LinkInfo<CONTAINER> > features; // The return vector
std::set<const NavGraphNode*> fullyExploredFrom; // Lets us navigate more efficiently
// Fetch the named links that we're interested in
for (const std::string& featureNameToGet : availableLinkNames) {
// This try block protects against ExcCLIDMismatch throws from
// features which do not derive from IParticle, when an IParticle interface is requested.
try {
// Slices may have added link collections. These links may have been to objects in different containers.
if (decisionObj->hasObjectCollectionLinks(featureNameToGet, ClassID_traits< CONTAINER >::ID())) {
ElementLinkVector<CONTAINER> collectionLinks = decisionObj->objectCollectionLinks<CONTAINER>( featureNameToGet );
filterLinkVectorByContainerKey<CONTAINER>(containerSGKey, collectionLinks);
std::copy(collectionLinks.begin(), collectionLinks.end(), std::back_inserter(featureLinks));
}
} catch (SG::ExcCLIDMismatch&) {
// This is in place to catch the exception caused by non-IParticle features when an IParticle interface is requested.
// We're fine to catch this silently and cary on looking at the next Decision object in the graph
}
try {
// Slices may have added single links. Note: the framework-specified "feature" link is always a single link.
if (decisionObj->hasObjectLink(featureNameToGet, ClassID_traits< CONTAINER >::ID())) {
ElementLinkVector<CONTAINER> singleEntryVector; // Filtering function operates on a vector
singleEntryVector.push_back( decisionObj->objectLink<CONTAINER>( featureNameToGet ) );
filterLinkVectorByContainerKey<CONTAINER>(containerSGKey, singleEntryVector);
std::copy(singleEntryVector.begin(), singleEntryVector.end(), std::back_inserter(featureLinks));
}
} catch (SG::ExcCLIDMismatch&) {
// Silently. As above.
}
}
// For each starting point through the navigation for a given chain-group
for (const NavGraphNode* finalNode : navGraph.finalNodes()) {
recursiveGetFeaturesOfTypeInternal<CONTAINER>(features,
fullyExploredFrom,
finalNode,
containerSGKey,
lastFeatureOfType,
navElementLinkKey,
chainIDs);
}
// Check if the Decsision object is active for a specific set of Chains-of-interest (as supplied by the TDT)
ActiveState state = ActiveState::UNSET;
if (chainIDs.size() > 0) {
// If we were given a list of chains to consider then we start assuming none passed this decisionObj
state = ActiveState::INACTIVE;
for (DecisionID id : chainIDs) {
if (std::count(decisionObj->decisions().begin(), decisionObj->decisions().end(), id) == 1) {
state = ActiveState::ACTIVE;
break;
}
}
}
return features;
}
// Copy the fetched links into the return vector
for (const ElementLink<CONTAINER>& featureLink : featureLinks) {
typename std::vector<LinkInfo<CONTAINER>>::iterator vecIt = std::find_if(features.begin(), features.end(), [&](const auto& li) { return li.link == featureLink; } );
if (vecIt == features.end()) {
// Link did not already exist - add it to the output
features.emplace_back( decisionObj, featureLink, state );
} else {
// Link already existed - if the link's state in the return vector is INACTIVE but is ACTIVE here,
// then we need to change it to ACTIVE as this denotes one-or-more of the requested chains were active for the object.
if (vecIt->state == ActiveState::INACTIVE) {
vecIt->state = ActiveState::ACTIVE;
}
}
template<class CONTAINER>
void recursiveGetFeaturesOfTypeInternal(
std::vector< LinkInfo<CONTAINER> >& features,
std::set<const NavGraphNode*>& fullyExploredFrom,
const NavGraphNode* navGraphNode,
const std::string containerSGKey,
const bool lastFeatureOfType,
const std::string& navElementLinkKey,
const DecisionIDContainer chainIDs) {
if (fullyExploredFrom.count(navGraphNode) == 1) {
return; // Already explored down from here
}
const Decision* decisionObj = navGraphNode->node();
ElementLinkVector<CONTAINER> featureLinks;
// Look up what named links are available in the Decision Object
std::vector<std::string> availableLinkNames;
if (navElementLinkKey == "") {
const std::vector<std::string> getSingleLinkNames = decisionObj->getObjectNames<CONTAINER>();
const std::vector<std::string> getCollectionLinkNames = decisionObj->getObjectCollectionNames<CONTAINER>();
std::copy(getSingleLinkNames.begin(), getSingleLinkNames.end(), std::back_inserter(availableLinkNames));
std::copy(getCollectionLinkNames.begin(), getCollectionLinkNames.end(), std::back_inserter(availableLinkNames));
} else { // Just looking for an explicitly named feature
availableLinkNames.push_back( navElementLinkKey );
}
// Fetch the named links that we're interested in
for (const std::string& featureNameToGet : availableLinkNames) {
// This try block protects against ExcCLIDMismatch throws from
// features which do not derive from IParticle, when an IParticle interface is requested.
try {
// Slices may have added link collections. These links may have been to objects in different containers.
if (decisionObj->hasObjectCollectionLinks(featureNameToGet, ClassID_traits< CONTAINER >::ID())) {
ElementLinkVector<CONTAINER> collectionLinks = decisionObj->objectCollectionLinks<CONTAINER>( featureNameToGet );
filterLinkVectorByContainerKey<CONTAINER>(containerSGKey, collectionLinks);
std::copy(collectionLinks.begin(), collectionLinks.end(), std::back_inserter(featureLinks));
}
} catch (SG::ExcCLIDMismatch&) {
// This is in place to catch the exception caused by non-IParticle features when an IParticle interface is requested.
// We're fine to catch this silently and cary on looking at the next Decision object in the graph
}
try {
// Slices may have added single links. Note: the framework-specified "feature" link is always a single link.
if (decisionObj->hasObjectLink(featureNameToGet, ClassID_traits< CONTAINER >::ID())) {
ElementLinkVector<CONTAINER> singleEntryVector; // Filtering function operates on a vector
singleEntryVector.push_back( decisionObj->objectLink<CONTAINER>( featureNameToGet ) );
filterLinkVectorByContainerKey<CONTAINER>(containerSGKey, singleEntryVector);
std::copy(singleEntryVector.begin(), singleEntryVector.end(), std::back_inserter(featureLinks));
}
} catch (SG::ExcCLIDMismatch&) {
// Silently. As above.
}
}
// Stop processing this path through the navigation if the lastFeatureOfType flag is set
if (featureLinks.size() && lastFeatureOfType) {
// Check if the Decsision object is active for a specific set of Chains-of-interest (as supplied by the TDT)
ActiveState state = ActiveState::UNSET;
if (chainIDs.size() > 0) {
// If we were given a list of chains to consider then we start assuming none passed this decisionObj
state = ActiveState::INACTIVE;
for (DecisionID id : chainIDs) {
if (std::count(decisionObj->decisions().begin(), decisionObj->decisions().end(), id) == 1) {
state = ActiveState::ACTIVE;
break;
}
}
}
} // for (decisionLink : decisionPath)
} // for (decisionPath : linkVector)
return features;
// Copy the fetched links into the return vector
for (const ElementLink<CONTAINER>& featureLink : featureLinks) {
typename std::vector<LinkInfo<CONTAINER>>::iterator vecIt = std::find_if(features.begin(), features.end(), [&](const auto& li) { return li.link == featureLink; } );
if (vecIt == features.end()) {
// Link did not already exist - add it to the output
features.emplace_back( decisionObj, featureLink, state );
} else {
// Link already existed - if the link's state in the return vector is INACTIVE but is ACTIVE here,
// then we need to change it to ACTIVE as this denotes one-or-more of the requested chains were active for the object.
if (vecIt->state == ActiveState::INACTIVE) {
vecIt->state = ActiveState::ACTIVE;
}
}
}
// Stop processing this path through the navigation if the lastFeatureOfType flag is set
if (featureLinks.size() && lastFeatureOfType) {
return;
}
// Recurse to decisionObj's seeds
for (const NavGraphNode* seedNavNode : navGraphNode->seeds()) {
recursiveGetFeaturesOfTypeInternal<CONTAINER>(features,
fullyExploredFrom,
seedNavNode,
containerSGKey,
lastFeatureOfType,
navElementLinkKey,
chainIDs);
}
// If we encounter this node again in the future, we don't need to explore it again as it's now fully explored.
fullyExploredFrom.insert( navGraphNode );
return;
}
}
/*
Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
*/
#include "TrigCompositeUtils/TrigCompositeUtils.h"
#include "TrigCompositeUtils/NavGraph.h"
namespace TrigCompositeUtils {
NavGraphNode::NavGraphNode(const Decision* me) : m_decisionObject(me){
}