ATLAS Offline Software
Loading...
Searching...
No Matches
FeatureRequestHelpers.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <vector>
6
9
10#ifndef XAOD_STANDALONE
12#endif
13
15
16 std::vector<TrigCompositeUtils::TypelessLinkInfo> typelessFeaturesImplimentation(
18 const CLID clid,
20 MsgStream& msg,
21 const EventContext& ctx,
22 const asg::EventStoreType* eventStore,
23 const bool printWarningMessages)
24 {
25 HLT::Identifier chainID(frd.chainGroup());
26
27 bool errState = false;
29 msg << MSG::ERROR << "features may only be called with: "
30 "TrigDefs::Physics - features from the legs of the chain(s) which passed the trigger. "
31 "TrigDefs::includeFailedDecisions - all features from the chain(s) irrespective of pass/fail of each Step." << endmsg;
32 errState = true;
33 }
34
36 msg << MSG::ERROR << "featureCollectionMode may only be called with: "
37 "TrigDefs::lastFeatureOfType - stop exploring each route through the navigation once a feature matching all requirements is found. "
38 "TrigDefs::allFeaturesOfType - always fully explore each route through the navigation graph and collect all matching features." << endmsg;
39 errState = true;
40 }
41
43 if (!navigationRH.isValid()) {
44 msg << MSG::ERROR << "Unable to read trigger navigation from " << navRHKey.key() << ". Cannot retrieve features." << endmsg;
45 errState = true;
46 }
47
48 // We always want to search from the passed raw terminus node to find features for passed chains.
49 const TrigCompositeUtils::Decision* terminusNode = nullptr;
50 if (!errState) {
51 terminusNode = TrigCompositeUtils::getTerminusNode(navigationRH);
52 if (terminusNode == nullptr) {
53 msg << MSG::ERROR << "Unable to locate HLTPassRaw element of " << navRHKey.key()
54 << ", collection contains " << navigationRH->size() << " nodes." << endmsg;
55 errState = true;
56 }
57 }
58
59 if (errState) {
60 msg << MSG::ERROR << "Encountered one or more errors in FeatureRequestHelpers::typelessFeaturesImplimentation" << endmsg;
61 throw std::runtime_error("Encountered one or more errors in FeatureRequestHelpers::typelessFeaturesImplimentation");
62 }
63
64 // The sub-graph from which we will extract features
66
67 // Collect the set of chain legs for the chain we are fetching
69 chainIDs.insert( chainID.numeric() );
70
71 const std::vector<int> legMultiplicites = ChainNameParser::multiplicities(chainID.name());
72 if (legMultiplicites.size() == 0) {
73 msg << MSG::ERROR << "chain " << chainID << " has invalid configuration, no parsed multiplicity data." << endmsg;
74 throw std::runtime_error("Encountered chain which could not be parsed in FeatureRequestHelpers::typelessFeaturesImplimentation");
75 } else if (legMultiplicites.size() > 1) {
76 if (frd.restrictRequestToLeg() >= static_cast<int>(legMultiplicites.size()) && printWarningMessages) {
77 msg << MSG::WARNING << "Requested features from leg index " << frd.restrictRequestToLeg() << " for chain " << chainID <<
78 " but this chain only has " << legMultiplicites.size() << " legs" << endmsg;
79 }
80 // For multi-leg chains, the DecisionIDs are handled per leg.
81 // We don't care here exactly how many objects are required per leg, just that there are two-or-more legs
82 for (size_t legNumeral = 0; legNumeral < legMultiplicites.size(); ++legNumeral) {
83 // If frd.restrictRequestToLeg() is -1 then we are NOT filtering on legs, we return features over all legs.
84 if (frd.restrictRequestToLeg() != -1 and frd.restrictRequestToLeg() != static_cast<int>(legNumeral)) {
85 continue;
86 }
87 HLT::Identifier legID = TrigCompositeUtils::createLegName(chainID, legNumeral);
88 chainIDs.insert( legID.numeric() );
89 }
90 }
91 if (msg.level() <= MSG::DEBUG) msg << MSG::DEBUG << "Fetching navigation data for chain " << chainID << " with " << legMultiplicites.size() << " leg(s)." << endmsg;
92 if (msg.level() <= MSG::VERBOSE) {
93 for (const TrigCompositeUtils::DecisionID printID : chainIDs) {
94 msg << MSG::VERBOSE << " -- Collecting for chain or chain-leg: " << HLT::Identifier(printID) << endmsg;
95 }
96 }
97
98 // Obtain navigation routes for objects which pass
99 // Final parameter TRUE as the chain passed (has its ID in terminusNode)
100 TrigCompositeUtils::recursiveGetDecisions(terminusNode, navGraph, chainIDs, true);
101
102 if (msg.level() <= MSG::DEBUG) {
103 msg << "Added all passed navigation data for chain " << chainID
104 << ", total nodes:" << navGraph.nodes() << " total edges:" << navGraph.edges() << " final nodes:" << navGraph.finalNodes().size() << endmsg;
105 }
106
107 // Obtain navigation routes for objects which fail.
108 // Supplying nullptr as the first argument instead of a pointer to the event store means that we can
109 // only seach in compact navigation collections (everything in a single container).
110 // This is always the case offline.
112 std::vector<const TrigCompositeUtils::Decision*> rejectedDecisionNodes =
113 TrigCompositeUtils::getRejectedDecisionNodes(nullptr, ctx, navRHKey.key(), chainIDs);
114
115 if (msg.level() <= MSG::DEBUG) {
116 msg << MSG::DEBUG << "Chain " << chainID << " has " << rejectedDecisionNodes.size()
117 << " dangling nodes in the graph from objects which were rejected." << endmsg;
118 }
119
120 for (const TrigCompositeUtils::Decision* rejectedNode : rejectedDecisionNodes) {
121 // Final parameter FALSE as the chain failed here (its ID was removed from rejectedNode)
122 TrigCompositeUtils::recursiveGetDecisions(rejectedNode, navGraph, chainIDs, false);
123 }
124
125 if (msg.level() <= MSG::DEBUG) {
126 msg << MSG::DEBUG << "Added all failed navigation data for chain " << chainID
127 << ", total nodes:" << navGraph.nodes() << " total edges:" << navGraph.edges() << " final nodes:" << navGraph.finalNodes().size() << endmsg;
128 }
129 }
130
131 if (msg.level() <= MSG::DEBUG) {
132 msg << MSG::DEBUG << "Finished adding nodes to sub-graph. "
133 << "Total nodes:" << navGraph.nodes() << " total edges:" << navGraph.edges() << " final nodes:" << navGraph.finalNodes().size() << endmsg;
134 }
135 if (msg.level() <= MSG::VERBOSE && navGraph.finalNodes().size()) {
136 for (const TrigCompositeUtils::NavGraphNode* n : navGraph.finalNodes()) {
137 msg << MSG::VERBOSE << " Final node:" << TrigCompositeUtils::decisionToElementLink(n->node(), ctx).dataID() << " #" << n->node()->index() << endmsg;
138 }
139 navGraph.printAllPaths(msg, MSG::VERBOSE);
140 }
141
142 return typelessGetFeatures(
143 navGraph,
144 frd,
145 clid,
146 std::move(chainIDs),
147 ctx,
148 eventStore);
149 }
150
151
152 const std::vector<TrigCompositeUtils::TypelessLinkInfo> typelessGetFeatures(
153 const TrigCompositeUtils::NavGraph& navGraph,
155 const CLID clid,
157 const EventContext& ctx,
158 const asg::EventStoreType* eventStore)
159 {
160 std::vector<TrigCompositeUtils::TypelessLinkInfo> features; // The return vector
161 std::set<const TrigCompositeUtils::NavGraphNode*> fullyExploredFrom; // Lets us navigate more efficiently
162
163 // For each starting point through the navigation for a given chain-group
164 for (const TrigCompositeUtils::NavGraphNode* finalNode : navGraph.finalNodes()) {
166 features,
167 fullyExploredFrom,
168 finalNode,
169 //
170 frd,
171 clid,
172 chainIDs,
173 ctx,
174 eventStore);
175 }
176
177 return features;
178 }
179
180
182 std::vector<TrigCompositeUtils::TypelessLinkInfo>& features,
183 std::set<const TrigCompositeUtils::NavGraphNode*>& fullyExploredFrom,
184 const TrigCompositeUtils::NavGraphNode* navGraphNode,
185 // The following are passed down from typelessGetFeatures
187 const CLID clid,
189 const EventContext& ctx,
190 const asg::EventStoreType* eventStore)
191 {
192
193 const TrigCompositeUtils::Decision* decisionObj = navGraphNode->node();
194 const TrigCompositeUtils::Decision* decisionObjChild = (navGraphNode->children().size() == 1 ? navGraphNode->children()[0]->node() : nullptr);
195 const std::vector<TrigCompositeUtils::DecisionID> &ids = TrigCompositeUtils::decisionIDs(decisionObj);
196 std::vector<sgkey_t> featureKeys;
197 std::vector<CLID> featureClids;
198 std::vector<TrigCompositeUtils::Decision::index_type> featureIndices;
199
200 // Look up what named links are available in the Decision Object
201 std::vector<std::string> availableLinkNames;
202 if (frd.linkName().empty()) { // If no link name is requested, then use all available names (look these up)
203 const std::vector<std::string> getSingleLinkNames = decisionObj->getObjectNames(clid);
204 const std::vector<std::string> getCollectionLinkNames = decisionObj->getObjectCollectionNames(clid);
205 std::copy(getSingleLinkNames.begin(), getSingleLinkNames.end(), std::back_inserter(availableLinkNames));
206 std::copy(getCollectionLinkNames.begin(), getCollectionLinkNames.end(), std::back_inserter(availableLinkNames));
207 } else { // Just looking for an explicitly named feature
208 availableLinkNames.push_back( frd.linkName() );
209 }
210
211 // Fetch the named links that we're interested in
212 for (const std::string& featureNameToGet : availableLinkNames) {
213 // This try block protects against ExcCLIDMismatch throws from
214 // features which do not derive from IParticle, when an IParticle interface is requested.
215#ifndef XAOD_STANDALONE
216 try {
217#endif
218 // Slices may have added link collections. These links may have been to objects in different containers.
219 if (decisionObj->hasObjectCollectionLinks(featureNameToGet, clid)) {
220 std::vector<sgkey_t> keyVec;
221 std::vector<CLID> clidVec;
222 std::vector<TrigCompositeUtils::Decision::index_type> indexVec;
223 decisionObj->typelessGetObjectCollectionLinks(featureNameToGet, keyVec, clidVec, indexVec);
224 filterLinkVectorByContainerKey(frd.SGKeyExpression(), keyVec, clidVec, indexVec, ctx, eventStore);
225 std::copy(keyVec.begin(), keyVec.end(), std::back_inserter(featureKeys));
226 std::copy(clidVec.begin(), clidVec.end(), std::back_inserter(featureClids));
227 std::copy(indexVec.begin(), indexVec.end(), std::back_inserter(featureIndices));
228 }
229#ifndef XAOD_STANDALONE
230 } catch (SG::ExcCLIDMismatch&) {
231 // This is in place to catch the exception caused by non-IParticle features when an IParticle interface is requested.
232 // We're fine to catch this silently and carry on looking at the next Decision object in the graph
233 }
234 try {
235#endif
236 // Slices may have added single links. Note: the framework-specified "feature" link is always a single link.
237 if (decisionObj->hasObjectLink(featureNameToGet, clid)) {
238 sgkey_t fKey;
239 CLID fClid;
241 decisionObj->typelessGetObjectLink(featureNameToGet, fKey, fClid, fIndex);
242 // Filtering function operates on a vector
243 std::vector<sgkey_t> keyVec = {fKey};
244 std::vector<CLID> clidVec = {fClid};
245 std::vector<TrigCompositeUtils::Decision::index_type> indexVec = {fIndex};
246 filterLinkVectorByContainerKey(frd.SGKeyExpression(), keyVec, clidVec, indexVec, ctx, eventStore);
247 std::copy(keyVec.begin(), keyVec.end(), std::back_inserter(featureKeys));
248 std::copy(clidVec.begin(), clidVec.end(), std::back_inserter(featureClids));
249 std::copy(indexVec.begin(), indexVec.end(), std::back_inserter(featureIndices));
250 }
251#ifndef XAOD_STANDALONE
252 } catch (SG::ExcCLIDMismatch&) {
253 // Silently. As above.
254 }
255#endif
256 }
257
258 // Check if the Decision object is active for a specific set of Chains-of-interest (as supplied by the TDT)
260 if (chainIDs.size() > 0) {
261 // If we were given a list of chains to consider then we start assuming none passed this decisionObj
263 for (TrigCompositeUtils::DecisionID id : chainIDs) {
264 if (std::count(decisionObj->decisions().begin(), decisionObj->decisions().end(), id) == 1) {
266 break;
267 }
268 }
269 // But consider also the ComboHypo, this will have run immediately after the Hypo and could have failed this chain due to combinatorics.
270 // This statement will only activate for the case that we are looking for "feature" edges (which is the default).
271 if (state == TrigCompositeUtils::ActiveState::ACTIVE && decisionObjChild && decisionObjChild->name() == TrigCompositeUtils::comboHypoAlgNodeName()) {
273 for (TrigCompositeUtils::DecisionID id : chainIDs) {
274 if (std::count(decisionObjChild->decisions().begin(), decisionObjChild->decisions().end(), id) == 1) {
276 break;
277 }
278 }
279 }
280 }
281
282 for (size_t i = 0; i < featureKeys.size(); ++i) {
283 typename std::vector<TrigCompositeUtils::TypelessLinkInfo>::iterator vecIt =
284 std::find_if(features.begin(), features.end(), [&](const auto& li) { return li.key == featureKeys[i] and li.clid == featureClids[i] and li.index == featureIndices[i]; } );
285 if (vecIt == features.end()) {
286 // Link did not already exist - add it to the output
287 features.emplace_back( decisionObj, featureKeys[i], featureClids[i], featureIndices[i], state ); // Note: This populates the set of passed IDs from decisionObj
288 } else {
289 // Link already existed - if the link's state in the return vector is INACTIVE but is ACTIVE here,
290 // then we need to change it to ACTIVE as this denotes one-or-more of the requested chains were active for the object.
293 }
294 // Always update the set of passed IDs for feature retrieval. The std::optional must have_value due to the choice of constructor above
295 vecIt->decisions->insert(ids.begin(), ids.end());
296 }
297 }
298
299 // Stop processing this path through the navigation if the lastFeatureOfType flag is set
300 if (featureKeys.size() && (frd.featureCollectionMode() & TrigDefs::lastFeatureOfType)) {
301 return;
302 }
303
304 // Recurse to decisionObj's seeds
305 for (const TrigCompositeUtils::NavGraphNode* seedNavNode : navGraphNode->seeds()) {
306 if (fullyExploredFrom.count(seedNavNode) == 1) {
307 continue; // Already explored down from here
308 }
310 features,
311 fullyExploredFrom,
312 seedNavNode,
313 // Following are passed down from typelessGetFeatures
314 frd,
315 clid,
316 chainIDs,
317 ctx,
318 eventStore);
319 }
320
321 // If we encounter this node again in the future, we don't need to explore it again as it's now fully explored.
322
323 fullyExploredFrom.insert( navGraphNode );
324 }
325
327 const std::regex& expression,
328 std::vector<sgkey_t>& keyVec,
329 std::vector<CLID>& clidVec,
330 std::vector<TrigCompositeUtils::Decision::index_type>& indexVec,
331 [[maybe_unused]] const EventContext& ctx,
332 [[maybe_unused]] const asg::EventStoreType* eventStore)
333 {
334 if (std::regex_match("", expression)) { // No filtering if empty string supplied as pattern
335 return;
336 }
337 std::vector<size_t> indicesToRemove;
338 for (size_t i = 0; i < keyVec.size(); ++i) {
339#ifdef XAOD_STANDALONE
340 const std::string keyStr = eventStore->event()->getName(keyVec[i]);
341 const std::string* keyStrPtr = (keyStr.empty() ? nullptr : &keyStr);
342#else
343 const std::string* keyStrPtr = Atlas::getExtendedEventContext(ctx).proxy()->keyToString(keyVec[i], clidVec[i]);
344
345#endif
346 // We will not be able to resolve the key for any collection which isn't in the POOL file.
347 // We reject the link in this case
348 if (not keyStrPtr or not std::regex_match(*keyStrPtr, expression)) {
349 indicesToRemove.push_back(i);
350 }
351 }
352 // Do the erasing. NOTE, must back-iterate to keep the indices matching
353 for (auto it = indicesToRemove.rbegin(); it != indicesToRemove.rend(); ++it) {
354 keyVec.erase(keyVec.begin() + *it);
355 clidVec.erase(clidVec.begin() + *it);
356 indexVec.erase(indexVec.begin() + *it);
357 }
358 }
359
360} // namespace FeatureRequestHelpers
#define endmsg
uint32_t CLID
The Class ID type.
TrigCompositeUtils::DecisionID numeric() const
numeric ID
std::string name() const
reports human redable name
Exception — Attempt to set DataLink / ElementLink with CLID <clid> to object with CLID <clid>.
Property holding a SG store/key/clid from which a ReadHandle is made.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const std::string & key() const
Return the StoreGate ID for the referenced object.
Transient utility class to represent a node in a graph (m_decisionObject), and a vector of edges (m_f...
Definition NavGraph.h:20
const std::vector< NavGraphNode * > & children() const
Return a vector of const pointers to the Decision object nodes which are the children of this NavGrap...
Definition NavGraph.cxx:50
const std::vector< NavGraphNode * > & seeds() const
Return a vector of const pointers to the Decision object nodes which this NavGraphNode seeds from.
Definition NavGraph.cxx:46
const Decision * node() const
Return a const pointer to the Decision object node which this NavGraphNode is shadowing.
Definition NavGraph.cxx:41
Structure to hold a transient Directed Acyclic Graph (DAG) structure.
Definition NavGraph.h:111
const std::vector< NavGraphNode * > & finalNodes() const
Get all final nodes.
Definition NavGraph.cxx:99
void printAllPaths(MsgStream &log, MSG::Level msgLevel=MSG::VERBOSE) const
Helper function.
Definition NavGraph.cxx:165
const std::regex & SGKeyExpression() const
const std::vector< TrigCompositeUtils::DecisionID > & decisions() const
Get positive HLT chain decisions associated with this TrigComposite. Navigation use.
bool hasObjectLink(const std::string &name, const CLID clid=CLID_NULL) const
Check if a link to an object with a given name and type exists. CLID_NULL to not check type.
bool typelessGetObjectLink(const std::string &name, sgkey_t &key, uint32_t &clid, index_type &index) const
Fetches a single link without type.
bool typelessGetObjectCollectionLinks(const std::string &name, std::vector< sgkey_t > &keyVec, std::vector< uint32_t > &clidVec, std::vector< index_type > &indexVec) const
Fetches a collection of links without type.
bool hasObjectCollectionLinks(const std::string &collectionName, const CLID clid=CLID_NULL) const
Check if links exist to a collection of objects with given name and type. CLID_NULL to not check type...
std::vector< std::string > getObjectNames() const
Look up all links stored to objects of (container) type CONTAINER.
const std::string & name() const
Get a human-readable name for the object.
std::vector< std::string > getObjectCollectionNames() const
Look up all links stored to collections objects from (container) type CONTAINER.
const ExtendedEventContext & getExtendedEventContext(const EventContext &ctx)
Retrieve an extended context from a context object.
std::vector< int > multiplicities(const std::string &chain)
void typelessGetFeaturesInternal(std::vector< TrigCompositeUtils::TypelessLinkInfo > &features, std::set< const TrigCompositeUtils::NavGraphNode * > &fullyExploredFrom, const TrigCompositeUtils::NavGraphNode *navGraphNode, const Trig::FeatureRequestDescriptor &frd, const CLID clid, const TrigCompositeUtils::DecisionIDContainer chainIDs, const EventContext &ctx, const asg::EventStoreType *eventStore)
Internal implementation called by typelessGetFeatures, and by itself.
void filterLinkVectorByContainerKey(const std::regex &expression, std::vector< sgkey_t > &keyVec, std::vector< CLID > &clidVec, std::vector< TrigCompositeUtils::Decision::index_type > &indexVec, const EventContext &ctx, const asg::EventStoreType *eventStore)
Removes type erased element links from the supplied vectors if they do not come from the specified co...
const std::vector< TrigCompositeUtils::TypelessLinkInfo > typelessGetFeatures(const TrigCompositeUtils::NavGraph &navGraph, const Trig::FeatureRequestDescriptor &frd, const CLID clid, const TrigCompositeUtils::DecisionIDContainer chainIDs, const EventContext &ctx, const asg::EventStoreType *eventStore)
Extract features from the supplied navGraph (obtained through typelessGetFeaturesInternal).
std::vector< TrigCompositeUtils::TypelessLinkInfo > typelessFeaturesImplimentation(const Trig::FeatureRequestDescriptor &frd, const CLID clid, const SG::ReadHandleKey< TrigCompositeUtils::DecisionContainer > &navRHKey, MsgStream &msg, const EventContext &ctx, const asg::EventStoreType *eventStore, const bool printWarningMessages)
Standalone implementation of feature retrieval, common between TrigDecisionTool and TrigDecisionToolL...
HLT::Identifier createLegName(const HLT::Identifier &chainIdentifier, size_t counter)
Generate the HLT::Identifier which corresponds to a specific leg of a given chain.
unsigned int DecisionID
ActiveState
Additional information returned by the TrigerDecisionTool's feature retrieval, contained within the L...
Definition ActiveState.h:18
@ ACTIVE
The link was still active for one-or-more of the HLT Chains requested in the TDT.
Definition ActiveState.h:20
@ UNSET
Default property of state.
Definition ActiveState.h:19
@ INACTIVE
The link was inactive for all of the HLT Chains requested in the TDT.
Definition ActiveState.h:21
void recursiveGetDecisions(const Decision *start, NavGraph &navGraph, const DecisionIDContainer &ids, const bool enforceDecisionOnStartNode)
Search back in time from "node" and locate all paths back through Decision objects for a given chain.
std::vector< const Decision * > getRejectedDecisionNodes(const asg::EventStoreType *eventStore, const EventContext &ctx, const std::string &summaryCollectionKey, const DecisionIDContainer &ids, const std::set< std::string > &keysToIgnore)
Query all DecisionCollections in the event store, locate all Decision nodes in the graph where an obj...
const std::string & comboHypoAlgNodeName()
std::set< DecisionID > DecisionIDContainer
const Decision * getTerminusNode(SG::ReadHandle< DecisionContainer > &container)
void decisionIDs(const Decision *d, DecisionIDContainer &destination)
Extracts DecisionIDs stored in the Decision object.
ElementLink< DecisionContainer > decisionToElementLink(const Decision *d, const EventContext &ctx)
Takes a raw pointer to a Decision and returns an ElementLink to the Decision.
static const unsigned int includeFailedDecisions
Run3 synonym of alsoDeactivateTEs.
static const unsigned int lastFeatureOfType
Run 3 "enum". Only return the final feature along each route through the navigation.
static const unsigned int allFeaturesOfType
Run 3 "enum". Return all features along legs (still with type and container checks)
StoreGateSvc EventStoreType
the type returned by AsgTool::evtStore
MsgStream & msg
Definition testRead.cxx:32