ATLAS Offline Software
Loading...
Searching...
No Matches
TrigNavSlimmingMTAlg.cxx
Go to the documentation of this file.
1
2/*
3 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
4*/
5
7
9
12
13using namespace TrigCompositeUtils;
14
15
16// Particle Specialization
17// We transiently interact via the xAOD::IParticle interface.
18// There is code inside the TrigCompositeUtils::Decision to check
19// at runtime if this inheritance is possible.
20// But we copy into a xAOD::Particle object.
21template<>
24 const std::string& edgeName) const
25{
26
27 if (not decision->hasObjectLink(edgeName, ClassID_traits<xAOD::IParticleContainer>::ID())) { // Note: IParticle
28 // Nothing to do
29 return StatusCode::SUCCESS;
30 }
31
32 ElementLink<xAOD::IParticleContainer> currentEL = decision->objectLink<xAOD::IParticleContainer>(edgeName); // Note: IParticle
33
34 if (!currentEL.isValid()) {
35 // TODO: Upgrade this first message to a WARNING once the TriggerAPI for Run3 is filtering on the chains whose final-features get saved into the DAOD_PHYS
36 ATH_MSG_DEBUG("Unable to repack '" << edgeName << "' of container type xAOD::IParticleContainer for '"
37 << decision->name() << "' node, the link is invalid.");
38 ATH_MSG_DEBUG("Dump of DecisionObject: " << *decision);
39 return StatusCode::SUCCESS;
40 }
41
42 if (not m_repackFeaturesExclusionList.empty()) {
43 // Check the feature's StoreGate key against the exclusion list. If it is on the list, then we don't repack the feature.
44 // We instead leave it pointing to its current online physics object. It is assumed that this online physics object will
45 // be kept in the DAOD via signature specific logic.
46 const std::string featureStoreGateKey = currentEL.dataID();
47 for (const std::string& exclusionEntry : m_repackFeaturesExclusionList) {
48 if (featureStoreGateKey == exclusionEntry) {
49 ATH_MSG_VERBOSE("Will not repack this feature " << currentEL.index() << " from " << currentEL.dataID() << ", as this container is on the exclusion list");
50 return StatusCode::SUCCESS;
51 }
52 }
53 }
54
55 (**writeHandle).push_back( new xAOD::Particle() ); // Need to do this before performing the copy to assign with the Aux store
56
57 const xAOD::IParticle* current = *currentEL;
58 xAOD::Particle* remapped = (**writeHandle).back();
59
60 remapped->setP4( current->p4() );
61
62 ElementLink<xAOD::ParticleContainer> remappedEL(**writeHandle, (**writeHandle).size()-1);
63 decision->setObjectLink<xAOD::ParticleContainer>(edgeName, remappedEL); // Overwrite the existing link
64
65 ATH_MSG_VERBOSE("Repacked from index:" << currentEL.index() << " from key:" << currentEL.dataID()
66 << ", to index:" << remappedEL.index() << " to key:" << remappedEL.dataID());
67
68 return StatusCode::SUCCESS;
69}
70
71
72// ROI Specialization.
73// Not an xAOD object, can use a direct copy constructor.
74template<>
77{
78 // Specialization for ROIs, utilize copy constructor (no Aux store here)
79 (**writeHandle).push_back( new TrigRoiDescriptor(*object) );
80 return StatusCode::SUCCESS;
81}
82
83
84TrigNavSlimmingMTAlg::TrigNavSlimmingMTAlg(const std::string& name, ISvcLocator* pSvcLocator)
85 : AthReentrantAlgorithm(name, pSvcLocator)
86{
87}
88
89
91 ATH_CHECK( m_primaryInputCollection.initialize() );
92 ATH_CHECK( m_outputCollection.initialize() );
96
97 const bool removeRoI = (std::find(m_edgesToDrop.begin(), m_edgesToDrop.end(), roiString()) != m_edgesToDrop.end());
98 const bool removeInitialRoI = (std::find(m_edgesToDrop.begin(), m_edgesToDrop.end(), initialRoIString()) != m_edgesToDrop.end());
99
100 if (m_repackROIs and (removeRoI or removeInitialRoI)) {
101 ATH_MSG_WARNING("Possible miss-configuration. Cannot repack ROIs in the navigation slimming if they are being dropped");
102 }
103
104 if (not m_trigDec.empty()) {
105 ATH_CHECK( m_trigDec.retrieve() );
106 }
107 for (const std::string& output : m_allOutputContainers) {
108 if (output == m_primaryInputCollection.key()) {
109 continue; // We do want to search for failed nodes in the primary input (it may already be merged)
110 }
111 // We don't want to search for failed nodes in other possible summary keys, we might read in the
112 // summary collection from another running instance (e.g. an AODSlim alg reading in the output of
113 // ESDSlim in a RAWtoALL job).
114 m_allOutputContainersSet.insert(output);
115 }
117 msg() << MSG::INFO << "Initialized. Will *not* inspect the following SG Keys: ";
118 for (const std::string& key : m_allOutputContainersSet) {
119 msg() << key << " ";
120 }
121 msg() << endmsg;
122 return StatusCode::SUCCESS;
123}
124
125
126StatusCode TrigNavSlimmingMTAlg::execute(const EventContext& ctx) const {
127
128 // Prepare IO
129 Outputs outputContainers;
130
134 if (m_repackROIs) {
136 outputContainers.rois = &outputROIs;
137 }
138 if (m_repackFeatures) {
140 outputContainers.particles = &outputParticles;
141 }
142 if (m_repackMET) {
144 outputContainers.mets = &outputMETs;
145 }
146
148 outputContainers.nav = &outputNavigation;
149
151 ATH_CHECK(primaryInputHandle.isValid());
152
153 const Decision* terminusNode = TrigCompositeUtils::getTerminusNode(*primaryInputHandle);
154 if (!terminusNode) {
155 ATH_MSG_ERROR("Unable to locate the HLTPassRaw from the primary input navigation collection, size:" << primaryInputHandle->size());
156 return StatusCode::FAILURE;
157 }
158
159 // Stage 1. Build a transient representation of the navigation graph.
160 TrigTimeStamp stage1;
161 NavGraph transientNavGraph;
162
163 // We can optionally only keep data for a given set of chains. An empty set means to keep for all chains.
164 DecisionIDContainer chainIDs = {};
165 if (not m_chainsFilter.empty()) {
166 // Cache chain configuration from TDT once — the chain group resolution,
167 // trigger listing, and config lookups are static and need not be repeated per event.
168 std::call_once(m_chainIDsCacheFlag, [this]{
169 m_chainIDsCacheOK = cacheChainInfo().isSuccess();
170 });
171 if (!m_chainIDsCacheOK) {
172 ATH_MSG_ERROR("Failed to cache chain configuration from TrigDecisionTool");
173 return StatusCode::FAILURE;
174 }
175
176 // Per-event: optionally filter cached chains to only those passing this event
177 DecisionIDContainer passingChains;
178 if (not m_keepFailedBranches) {
179 TrigCompositeUtils::decisionIDs(terminusNode, passingChains);
180 }
181
182 for (const auto& info : m_cachedChainInfo) {
183 if (!passingChains.empty() && !passingChains.contains(info.chainID)) {
184 continue; // Optional additional filter on passing chains in this specific event
185 }
186 chainIDs.insert(info.chainID);
187 for (const auto& legID : info.legIDs) {
188 chainIDs.insert(legID);
189 }
190 }
191
192 ATH_MSG_DEBUG("Supplied " << m_chainsFilter.size() << " chain patterns. This converts to " << chainIDs.size() << " DecisionIDs to be preserved.");
193 if (chainIDs.empty()) {
194 // No chains are in the filter. We should reject everything. But an empty set is interpreted as keep-all. So we need to add a dummy entry.
195 chainIDs.insert( HLT::Identifier("HLT_dummy").numeric() );
196 }
197 } else {
198 ATH_MSG_DEBUG("No HLT-chain based filtering of the navigation graph will be performed.");
199 }
200
201 std::set<const Decision*> fullyExploredFrom;
202 // Note: We use the "internal" version of this call such that we maintain our own cache,
203 // as we may need to call this more than once if keepFailedBranches is true
205 nullptr, // 'Coming from' is nullptr for the first call of the recursive function
206 transientNavGraph,
207 fullyExploredFrom,
208 chainIDs,
209 /*enforce chainIDs on terminus node*/ true);
210
211 ATH_MSG_DEBUG("Collated nodes from passing paths, now have " << transientNavGraph.nodes() << " nodes with " << transientNavGraph.edges() << " edges");
212
213 // Stage 2. We can optionally include branches through the graph which were never accepted by any chain.
214 TrigTimeStamp stage2;
215 // These branches do not connect to the terminusNode, so we have to go hunting them explicitly.
216 // We need to pass in the evtStore as these nodes can be spread out over numerous collections.
217 // Like with the terminus node, we can restrict this search to only nodes which were rejected by certain chains.
218 // We also want to restrict the search to exclude the output collections of any other TrigNavSlimminMTAlg instances
219 // and let the function know what the primary input collection is - from the name of this we can tell if we need to search one or many containers.
221 std::vector<const Decision*> rejectedNodes = TrigCompositeUtils::getRejectedDecisionNodes(&*evtStore(), ctx, m_primaryInputCollection.key(), chainIDs, m_allOutputContainersSet);
222 for (const Decision* rejectedNode : rejectedNodes) {
223 // We do *not* enforce that a member of chainIDs must be present in the starting node (rejectedNode)
224 // specifically because we know that at least one of chainIDs was _rejected_ here, but is active in the rejected
225 // node's seeds.
227 nullptr, // 'Coming from' is nullptr for the first call of the recursive function
228 transientNavGraph,
229 fullyExploredFrom,
230 chainIDs,
231 /*enforce chainIDs on terminus node*/ false);
232 }
233 ATH_MSG_DEBUG("Collated nodes from failing paths, now have " << transientNavGraph.nodes() << " nodes with " << transientNavGraph.edges() << " edges");
234 }
235
236 // Stage 3. Walk all paths through the graph. Flag for thinning.
237 TrigTimeStamp stage3;
238 // Final nodes includes the terminus node, plus any rejected nodes (if these were collated).
240
241 if (msg().level() <= MSG::VERBOSE) {
242 ATH_MSG_VERBOSE("The navigation graph entering the slimming is:");
243 transientNavGraph.printAllPaths(msg(), MSG::VERBOSE);
244 }
245
246 // Stage 4. Do the thinning. Re-wire removed nodes as we go.
247 TrigTimeStamp stage4;
248 const size_t nodesBefore = transientNavGraph.nodes();
249 const size_t edgesBefore = transientNavGraph.edges();
250 std::vector<const Decision*> thinnedInputNodes = transientNavGraph.thin();
251
252 // TODO - thinnedInputNodes will be dropped, these may link to "features", "roi", or other objects in other containers.
253 // Need to let the slimming svc know that we no longer need the objects pointed to here, and hence they can be thinned.
254
255 ATH_MSG_DEBUG("Trigger navigation graph thinning going from " << nodesBefore << " nodes with " << edgesBefore << " edges, to "
256 << transientNavGraph.nodes() << " nodes with " << transientNavGraph.edges() << " edges");
257
258 if (msg().level() <= MSG::VERBOSE) {
259 ATH_MSG_VERBOSE("The navigation graph has been slimmed to the following paths:");
260 transientNavGraph.printAllPaths(msg(), MSG::VERBOSE);
261 }
262
263 // Stage 5. Fill the transientNavGraph structure (with NavGraphNode* nodes) back into an xAOD::DecisionContainer (with xAOD::Decision* nodes).
264 TrigTimeStamp stage5;
265 IOCacheMap cache; // Used to keep a one-to-one relationship between the const input Decision* and the mutable output Decision*
266
267 // Do the terminus node first - such that it ends up at index 0 of the outputNavigation (fast to locate in the future)
268 Decision* terminusNodeOut = nullptr;
269 const DecisionIDContainer emptySet = {};
270 ATH_CHECK(inputToOutput(terminusNode, &terminusNodeOut, cache, outputContainers, (m_applyChainsFilterToSummaryNodes ? chainIDs : emptySet), ctx));
271
272 const Decision* expressTerminusNode = TrigCompositeUtils::getExpressTerminusNode(*primaryInputHandle);
273 if (expressTerminusNode) {
274 // Do the express terminus node second - such that it ends up at index 1 of the outputNavigation (fast to locate in the future)
275 Decision* expressTerminusNodeOut = nullptr;
276 ATH_CHECK(inputToOutput(expressTerminusNode, &expressTerminusNodeOut, cache, outputContainers, (m_applyChainsFilterToSummaryNodes ? chainIDs : emptySet), ctx));
277 }
278
280 // Prescaled summary node might come third, it is optional.
282 if (prescaledNode) { // We can propagate it directly (potential for Run 4)
283 Decision* prescaleNodeOut = nullptr;
284 ATH_CHECK(inputToOutput(prescaledNode, &prescaleNodeOut, cache, outputContainers, (m_applyChainsFilterToSummaryNodes ? chainIDs : emptySet), ctx));
285 } else { // We can re-create this from the trigger bits
286 ATH_CHECK(createPresaledGraphNode(outputContainers, (m_applyChainsFilterToSummaryNodes ? chainIDs : emptySet)));
287 }
288 }
289
290 if (m_propagateL1Nodes) {
291 // L1 summary nodes are also optional.
292 const Decision* L1TBPNode = TrigCompositeUtils::getNodeByName(*primaryInputHandle, "L1TBP"); // TODO - upgrade to static string constants if we use this in production.
293 const Decision* L1TAVNode = TrigCompositeUtils::getNodeByName(*primaryInputHandle, "L1TAV");
294 if (L1TBPNode && L1TAVNode) {
295 Decision* L1TBPNodeOut = nullptr;
296 Decision* L1TAVNodeOut = nullptr;
297 ATH_CHECK(inputToOutput(L1TBPNode, &L1TBPNodeOut, cache, outputContainers, {}, ctx)); // No chain filtering, these are L1 items
298 ATH_CHECK(inputToOutput(L1TAVNode, &L1TAVNodeOut, cache, outputContainers, {}, ctx));
299 } else {
300 ATH_CHECK(createL1GraphNodes(outputContainers));
301 }
302 }
303
304 // Don't have to walk the graph here, just iterate through the set of (thinned) nodes.
305 // We won't end up with two terminus nodes because of this (it checks that the node hasn't already been processed)
306 const std::vector<NavGraphNode*> allNodes = transientNavGraph.allNodes();
307 for (const NavGraphNode* inputNode : allNodes) {
308 Decision* outputNode = nullptr;
309 ATH_CHECK(inputToOutput(inputNode->node(), &outputNode, cache, outputContainers, chainIDs, ctx));
310 }
311 // Now we have all of the new nodes in the output collection, can link them all up with their slimmed seeding relationships.
312 for (const NavGraphNode* inputNode : allNodes) {
313 ATH_CHECK(propagateSeedingRelation(inputNode, cache, ctx));
314 }
315
316 // We can perform an additional check on the output graph, we put a veto on the m_keepFailedBranches option as we are currently just exploring
317 // from the 'terminusNodeOut', more code would be needed to locate failing branches also in the output graph structure.
318 if (msg().level() <= MSG::VERBOSE && !m_keepFailedBranches) {
319 ATH_MSG_VERBOSE("The output navigation graph looks like this (output terminus node search only, converted back into a NavGraph one final time for printing)");
320 std::set<const Decision*> fullyExploredFromOut;
321 NavGraph transientNavGraphOut;
323 nullptr, // 'Coming from' is nullptr for the first call of the recursive function
324 transientNavGraphOut,
325 fullyExploredFromOut,
326 chainIDs,
327 /*enforce chainIDs on terminus node*/ true);
328 transientNavGraphOut.printAllPaths(msg(), MSG::VERBOSE);
329 }
330
331 if (msg().level() <= MSG::DEBUG) {
332 ATH_MSG_DEBUG("Navigation slimming and thinning timings:");
333 ATH_MSG_DEBUG(" 1. Transient Graph of Passed Nodes = " << stage1.millisecondsDifference(stage2) << " ms");
334 ATH_MSG_DEBUG(" 2. Transient Graph of Failed Nodes = " << stage2.millisecondsDifference(stage3) << " ms");
335 ATH_MSG_DEBUG(" 3. Flag Transient Graph For Thinning = " << stage3.millisecondsDifference(stage4) << " ms");
336 ATH_MSG_DEBUG(" 4. Perform Transient Graph Thinning = " << stage4.millisecondsDifference(stage5) << " ms");
337 ATH_MSG_DEBUG(" 5. Write xAOD Graph = " << stage5.millisecondsSince() << " ms");
338 }
339
340 return StatusCode::SUCCESS;
341}
342
343std::vector<size_t> TrigNavSlimmingMTAlg::lookupHardCodedLegMultiplicities(const std::string& chain) const {
344 if (chain == "HLT_id_cosmicid_L1MU11_EMPTY") return std::vector<size_t>(1,1); // size = 1, value at index 0 = 1
345 return std::vector<size_t>();
346}
347
349 for (const std::string& filter : m_chainsFilter) {
350 // We do this as filter->chains stage as filter could be a regexp matching a large number of chains
351 const Trig::ChainGroup* cg = m_trigDec->getChainGroup(filter);
352 std::vector<std::string> chains = cg->getListOfTriggers();
353 for (const std::string& chain : chains) {
354 const TrigConf::HLTChain* hltChain = m_trigDec->ExperimentalAndExpertMethods().getChainConfigurationDetails(chain);
355 const HLT::Identifier chainID( hltChain->chain_name() );
356 CachedChainInfo info;
357 info.chainID = chainID.numeric();
358 std::vector<size_t> legMultiplicites = hltChain->leg_multiplicities();
359 ATH_MSG_VERBOSE("Including " << chain << " and its " << legMultiplicites.size() << " legs in the trigger slimming output");
360 if (legMultiplicites.size() == 0) {
361 legMultiplicites = lookupHardCodedLegMultiplicities(chain);
362 if (legMultiplicites.size() == 0) {
363 ATH_MSG_ERROR("chain " << chainID << " has invalid configuration, no multiplicity data.");
364 return StatusCode::FAILURE;
365 }
366 }
367 if (legMultiplicites.size() > 1) {
368 // For multi-leg chains, the DecisionIDs are handled per leg.
369 // We don't care here exactly how many objects are required per leg, just that there are two-or-more legs
370 for (size_t legNumeral = 0; legNumeral < legMultiplicites.size(); ++legNumeral) {
371 const HLT::Identifier legID = TrigCompositeUtils::createLegName(chainID, legNumeral);
372 info.legIDs.push_back( legID.numeric() );
373 }
374 }
375 m_cachedChainInfo.push_back(std::move(info));
376 }
377 }
378 ATH_MSG_DEBUG("Cached " << m_cachedChainInfo.size() << " chain configurations for " << m_chainsFilter.size() << " chain patterns.");
379 return StatusCode::SUCCESS;
380}
381
382
383
385 Decision* prescaledNode = newDecisionIn(outputContainers.nav->ptr(), TrigCompositeUtils::summaryPrescaledNodeName());
386
387 const Trig::ChainGroup* cg = m_trigDec->getChainGroup("HLT_.*|EF_.*");
388 const std::vector<std::string> chains = cg->getListOfTriggers();
389 const std::vector<unsigned int> bits = cg->isPassedBitsForEach();
390 if (chains.size() != bits.size()) {
391 ATH_MSG_ERROR("Unexpected different sized chains and bits vectors");
392 return StatusCode::FAILURE;
393 }
394
395 DecisionIDContainer prescaledIDs;
396 for (size_t i = 0; i < bits.size(); ++i) {
397 if (bits[i] & TrigDefs::EF_prescaled) { prescaledIDs.insert( HLT::Identifier(chains[i]).numeric() ); }
398 }
399
400 if (m_applyChainsFilterToSummaryNodes && chainIDs.size()) { // Then apply the filter
401 std::erase_if(prescaledIDs, [&](int id) {
402 return !chainIDs.contains(id); // Keep only elements in chainIDs
403 });
404 }
405
406 TrigCompositeUtils::insertDecisionIDs(prescaledIDs, prescaledNode); // Copy the set of chains into the xAOD object
407 return StatusCode::SUCCESS;
408}
409
410StatusCode TrigNavSlimmingMTAlg::createL1GraphNodes(Outputs& outputContainers) const {
411 Decision* L1TBPNode = newDecisionIn(outputContainers.nav->ptr(), "L1TBP");
412 Decision* L1TAVNode = newDecisionIn(outputContainers.nav->ptr(), "L1TAV");
413 // Note - this is for offline use, there's no point in keeping TAP (trigger after prescale) as well as TAV
414
415 const Trig::ChainGroup* cg = m_trigDec->getChainGroup("L1_.*|L0_.*"); // Note: Future proofing for Run 4
416 std::vector<std::string> chains = cg->getListOfTriggers();
417 const std::vector<unsigned int> bits = cg->isPassedBitsForEach();
418 if (chains.size() != bits.size()) {
419 ATH_MSG_ERROR("Unexpected different sized chains and bits vectors");
420 return StatusCode::FAILURE;
421 }
422
423 DecisionIDContainer TBPIDs, TAVIDs;
424 for (size_t i = 0; i < bits.size(); ++i) {
425 if (bits[i] & TrigDefs::L1_isPassedBeforePrescale) { TBPIDs.insert( HLT::Identifier(chains[i]).numeric() ); }
426 if (bits[i] & TrigDefs::L1_isPassedAfterVeto) { TAVIDs.insert( HLT::Identifier(chains[i]).numeric() ); }
427 }
428
429 TrigCompositeUtils::insertDecisionIDs(TBPIDs, L1TBPNode);
430 TrigCompositeUtils::insertDecisionIDs(TAVIDs, L1TAVNode);
431 ATH_MSG_INFO("Created new TAV node at index " << L1TAVNode->index() << " with " << TBPIDs.size() << " = " << TAVIDs.size() << " decisions\n" << *L1TAVNode );
432 return StatusCode::SUCCESS;
433}
434
435
437 const TrigCompositeUtils::Decision* input,
439 IOCacheMap& cache,
440 Outputs& outputContainers,
441 const DecisionIDContainer& chainIDs,
442 const EventContext& ctx) const
443{
444 IOCacheMap::const_iterator it = cache.find(input);
445 if (it != cache.end()) {
446 *output = it->second;
447 } else {
448 *output = newDecisionIn(outputContainers.nav->ptr(), input, input->name(), ctx);
449 ATH_CHECK(propagateLinks(input, *output));
450 ATH_CHECK(propagateDecisionIDs(input, *output, chainIDs));
451 ATH_CHECK(repackLinks(*output, outputContainers));
452 cache[input] = *output;
453 }
454 return StatusCode::SUCCESS;
455}
456
457
459 const TrigCompositeUtils::NavGraphNode* inputNode,
460 IOCacheMap& cache,
461 const EventContext& ctx) const
462{
463 const Decision* inputDecision = inputNode->node(); // The incoming Decision objects, with links into the old graph
464 Decision* outputDecision = nullptr; // The outgoing Decision object, without graph links so far
465 {
466 IOCacheMap::const_iterator it = cache.find(inputDecision);
467 ATH_CHECK( it != cache.end() );
468 outputDecision = it->second;
469 }
470 for (const NavGraphNode* seed : inputNode->seeds()) {
471 const Decision* inputSeedDecision = seed->node(); // A Decision object the incoming Decision object links to (old graph)
472 const Decision* outputSeedDecision = nullptr; // The equivalent Decision Object in the slimmed outgoing graph
473 {
474 IOCacheMap::const_iterator it = cache.find(inputSeedDecision);
475 ATH_CHECK( it != cache.end() );
476 outputSeedDecision = it->second;
477 }
478 // Perform the linking only using nodes from the slimmed output graph
479 TrigCompositeUtils::linkToPrevious(outputDecision, outputSeedDecision, ctx);
480 }
481
482 // Don't run this check for "HLTPassRaw", this node is expected to link back to every passing physics object.
483 // Hence there may be more than 'sensibleUpperBoundOnNLinks' in aggregate here.
484 if (m_runtimeValidation and outputDecision->name() != TrigCompositeUtils::summaryPassNodeName()) {
485 const size_t sensibleUpperBoundOnNLinks = 100;
486 const size_t maxUpperBoundOnNLinks = 500;
487 // Note: Only in the NavGraphNode do we have the two-way links to check how many children link back to this node
488 const bool bad_in = inputNode->children().size() > sensibleUpperBoundOnNLinks;
489 //Note: Here we check more than "seed" links. We pick up external links too like "feature"
490 const bool bad_out = outputDecision->linkColNames().size() > sensibleUpperBoundOnNLinks;
491 const bool vbad = inputNode->children().size() > maxUpperBoundOnNLinks or outputDecision->linkColNames().size() > maxUpperBoundOnNLinks;
492 if (bad_in) {
493 ATH_MSG_WARNING("Saving a Decision object with a very large number of INCOMING graph edges. Number of in-edges: " << inputNode->children().size());
494 }
495 if (bad_out) {
496 ATH_MSG_WARNING("Saving a Decision object with a very large number of OUTGOING graph edges. Number of out-edges: " << outputDecision->linkColNames().size());
497 }
498 if (bad_in or bad_out) {
499 ATH_MSG_WARNING("Comes from: " << TrigCompositeUtils::decisionToElementLink(inputDecision, ctx).dataID());
500 ATH_MSG_DEBUG("Output Decision: " << *outputDecision);
501 }
502 if (vbad) {
503 ATH_MSG_ERROR("More than " << maxUpperBoundOnNLinks << " links, printing an ERROR such that this gets promptly investigated and reduced.");
504 }
505 }
506 return StatusCode::SUCCESS;
507}
508
509
511 const TrigCompositeUtils::Decision* input,
512 TrigCompositeUtils::Decision* output) const
513{
514 // ElementLinks form the edges in the graph. Start by copying all of them over.
515
516 output->copyAllLinksFrom( input );
517
518 // Special behavior to save additional disk space for keepOnlyFinalFeatures mode.
519 // In keepOnlyFinalFeatures we stop at the first hypoAlgNode, hence we will drop the preceding inputMakerNode, and all prior Steps in their entirety.
520 // This means we will also drop all "roi" edges, including the final ROI.
521 // We may want to keep this final "roi", and so to do this we can copy it down one level (away from L1) to live in the hypoAlgNode along side the "feature" link.
522 // Note: If "roi" is listed in m_edgesToDrop then we will still immediately drop this new element link in the m_edgesToDrop loop below.
523 const std::vector<ElementLink<DecisionContainer>> seeds = input->objectCollectionLinks<DecisionContainer>(seedString());
524 const Decision* const firstParent = (seeds.size() ? *seeds.at(0) : nullptr);
526 input->name() == hypoAlgNodeName() &&
527 firstParent &&
528 firstParent->name() == inputMakerNodeName() &&
529 firstParent->hasObjectLink(roiString()))
530 {
531 output->copyLinkFrom( firstParent, roiString() );
532 }
533
534 for (const std::string& toRemove : m_edgesToDrop) {
535 output->removeObjectLink(toRemove);
536 output->removeObjectCollectionLinks(toRemove);
537 // TODO - let the slimming svc know that we no longer need these objects
538 }
539
540 // Do not propagate "seed" links - TrigNavSlimmingMTAlg will
541 // propagate these following additional logic
542 output->removeObjectCollectionLinks( seedString() );
543
544 return StatusCode::SUCCESS;
545}
546
547
549 const TrigCompositeUtils::Decision* input,
551 const DecisionIDContainer& chainIDs) const
552{
553
554 // Get all DecisionIDs from the const input Decision*
555 DecisionIDContainer fromInput;
556 decisionIDs(input, fromInput);
557
558 DecisionIDContainer toOutput;
559 if ( chainIDs.size() ) {
560 // Applying ChainsFilter to the set of DecisionIDs
561 std::set_intersection(fromInput.begin(), fromInput.end(), chainIDs.begin(), chainIDs.end(),
562 std::inserter(toOutput, toOutput.begin()));
563 } else {
564 // Copying all DecisionIDs from input to output
565 toOutput.insert(fromInput.begin(), fromInput.end());
566 }
567
568 // Set the DecisionIDs into the mutable output Decision*
569 insertDecisionIDs(toOutput, output);
570
571 return StatusCode::SUCCESS;
572}
573
575 if (not msgLvl(MSG::DEBUG)) return;
576 if (output->hasObjectLink(featureString(), ClassID_traits<xAOD::IParticleContainer>::ID())) {
578 if (link.isValid()) {
579 const xAOD::IParticle& l = **link;
580 ATH_MSG_DEBUG("IParticle repacking debug. " << when << " : "
581 << "(pt:" << l.pt() << ",eta:" << l.eta() << ",phi:" << l.phi() << ",m:" << l.m() << ",e:" << l.e() << ")"
582 << " from:" << link.dataID());
583 if (when == " After") ATH_MSG_DEBUG("--");
584 }
585 }
586}
587
588
591 Outputs& outputContainers) const
592{
593
594 if (m_repackROIs) {
595 ATH_CHECK( doRepack<TrigRoiDescriptorCollection>(output, outputContainers.rois, roiString()) );
596 ATH_CHECK( doRepack<TrigRoiDescriptorCollection>(output, outputContainers.rois, initialRoIString()) );
597 }
598
599 if (m_repackFeatures) {
600 // Debug printing. Look at the four-momentum of any feature before the repacking.
601 // Note: Transiently we interact with the IParticle interface.
602 printIParticleRepackingDebug(output, "Before");
603
604 // Do any IParticle repacking
605 ATH_CHECK( doRepack<xAOD::ParticleContainer>(output, outputContainers.particles, featureString()) );
606 ATH_CHECK( doRepack<xAOD::ParticleContainer>(output, outputContainers.particles, "subfeature") );
607
608 // Debug printing. Look at the four-momentum of any feature after the repacking (the stored link is re-written)
609 printIParticleRepackingDebug(output, " After");
610 }
611
612 // Some features do not support an IParticle interface. These need their own containers.
613 // TODO. Apply some thinning?
614 if (m_repackMET) {
615 ATH_CHECK( doRepack<xAOD::TrigMissingETContainer>(output, outputContainers.mets, featureString()) );
616 }
617
618 return StatusCode::SUCCESS;
619}
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Athena::TPCnvVers::Current TrigRoiDescriptor
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
TrigCompositeUtils::DecisionID numeric() const
numeric ID
virtual bool isValid() override final
Can the handle be successfully dereferenced?
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
std::vector< NavGraphNode * > allNodes()
Get all nodes.
Definition NavGraph.cxx:103
void printAllPaths(MsgStream &log, MSG::Level msgLevel=MSG::VERBOSE) const
Helper function.
Definition NavGraph.cxx:165
std::vector< const Decision * > thin()
Perform thinning.
Definition NavGraph.cxx:123
HLT chain configuration information.
const std::vector< size_t > & leg_multiplicities() const
std::vector< size_t > lookupHardCodedLegMultiplicities(const std::string &chain) const
Supplemental leg multiplicity information to support MC20.
SG::WriteHandleKey< TrigRoiDescriptorCollection > m_outputRepackedROICollectionKey
Gaudi::Property< std::vector< std::string > > m_edgesToDrop
StatusCode createPresaledGraphNode(Outputs &outputContainers, const TrigCompositeUtils::DecisionIDContainer &chainIDs) const
Creates a new graph node from scratch, populates it with the Chain IDs of all HLT chains which were n...
StatusCode cacheChainInfo() const
One-time cache of chain+leg IDs from TrigDecisionTool configuration.
StatusCode doRepack(TrigCompositeUtils::Decision *decision, SG::WriteHandle< COLLECTION > *writeHandle, const std::string &edgeName) const
Look for an ElementLink<COLLECTION> with the given edge-name in 'decision', if found then make a copy...
Gaudi::Property< bool > m_keepFailedBranches
Gaudi::Property< std::vector< std::string > > m_allOutputContainers
Gaudi::Property< bool > m_repackFeatures
SG::WriteHandleKey< xAOD::TrigCompositeContainer > m_outputCollection
Gaudi::Property< bool > m_applyChainsFilterToSummaryNodes
Gaudi::Property< bool > m_runtimeValidation
StatusCode inputToOutput(const TrigCompositeUtils::Decision *input, TrigCompositeUtils::Decision **output, IOCacheMap &cache, Outputs &outputContainers, const TrigCompositeUtils::DecisionIDContainer &chainIDs, const EventContext &ctx) const
Map a const Decision object from an input collection to its equivalent in the output collection Where...
SG::WriteHandleKey< xAOD::ParticleContainer > m_outputRepackedFeaturesCollectionKey_Particle
SG::WriteHandleKey< xAOD::TrigMissingETContainer > m_outputRepackedFeaturesCollectionKey_MET
StatusCode propagateSeedingRelation(const TrigCompositeUtils::NavGraphNode *inputNode, IOCacheMap &cache, const EventContext &ctx) const
Copy the subset of "seed" links which are present in the inputNode.
void printIParticleRepackingDebug(const TrigCompositeUtils::Decision *output, const std::string &when) const
Print debug information relating to the re-packing of feature links as Particle objects.
StatusCode createL1GraphNodes(Outputs &outputContainers) const
Creates two new graph node from scratch, populates it using the TriggerDecisionTool with the hash of ...
StatusCode propagateDecisionIDs(const TrigCompositeUtils::Decision *input, TrigCompositeUtils::Decision *output, const TrigCompositeUtils::DecisionIDContainer &chainIDs) const
Copy DecisionIDs (passing chains and passing chain-legs) from input to output.
Gaudi::Property< bool > m_repackMET
Gaudi::Property< bool > m_repackROIs
std::set< std::string > m_allOutputContainersSet
Processed form of m_allOutputContainers.
Gaudi::Property< std::vector< std::string > > m_repackFeaturesExclusionList
Gaudi::Property< bool > m_keepOnlyFinalFeatures
StatusCode doRepackCopy(const typename COLLECTION::base_value_type *object, SG::WriteHandle< COLLECTION > *writeHandle) const
Performs the xAOD Copy.
SG::ReadHandleKey< xAOD::TrigCompositeContainer > m_primaryInputCollection
TrigNavSlimmingMTAlg(const std::string &name, ISvcLocator *pSvcLocator)
StatusCode repackLinks(TrigCompositeUtils::Decision *output, Outputs &outputContainers) const
Repacks ElementLinks in the DecisionObject to point to compact output containers written by this alg.
std::map< const TrigCompositeUtils::Decision *, TrigCompositeUtils::Decision * > IOCacheMap
Gaudi::Property< std::vector< std::string > > m_nodesToDrop
virtual StatusCode execute(const EventContext &ctx) const override
Gaudi::Property< bool > m_removeEmptySteps
virtual StatusCode initialize() override
Gaudi::Property< bool > m_propagatePrescaledNode
Gaudi::Property< bool > m_propagateL1Nodes
PublicToolHandle< Trig::TrigDecisionTool > m_trigDec
StatusCode propagateLinks(const TrigCompositeUtils::Decision *input, TrigCompositeUtils::Decision *output) const
Copy links (graph edges) from input to output.
Gaudi::Property< std::vector< std::string > > m_chainsFilter
nope - should be used for standalone also, perhaps need to protect the class def bits ifndef XAOD_ANA...
utility class to measure time duration in AthenaMT The pattern when it is useful: AlgA tags the begin...
double millisecondsSince() const
double millisecondsDifference(const TrigTimeStamp &other) const
std::vector< unsigned int > isPassedBitsForEach() const
return result of isPassedBits for each chain in the group
std::vector< std::string > getListOfTriggers() const
Class providing the definition of the 4-vector interface.
void setP4(const FourMom_t &vec)
Set the 4-vec.
bool setObjectLink(const std::string &name, const ElementLink< CONTAINER > &link)
Set the link to an object.
const std::vector< std::string > & linkColNames() const
Raw access to the persistent link names.
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.
ElementLink< CONTAINER > objectLink(const std::string &name) const
Get the link with the requested name.
const std::string & name() const
Get a human-readable name for the object.
SG::WriteHandle< CONT > createAndStoreNoAux(const SG::WriteHandleKey< CONT > &key, const EventContext &ctx)
Creates and right away records the Container CONT with the key.
HLT::Identifier createLegName(const HLT::Identifier &chainIdentifier, size_t counter)
Generate the HLT::Identifier which corresponds to a specific leg of a given chain.
const std::string & summaryPrescaledNodeName()
const std::string & inputMakerNodeName()
const Decision * getNodeByName(const DecisionContainer &container, const std::string &nodeName)
Returns the navigation node with a given name from a collection or nullptr if missing.
void insertDecisionIDs(const Decision *src, Decision *dest)
Appends the decision IDs of src to the dest decision object.
const std::string & roiString()
Decision * newDecisionIn(DecisionContainer *dc, const std::string &name)
Helper method to create a Decision object, place it in the container and return a pointer to it.
SG::WriteHandle< CONT > createAndStoreWithAux(const SG::WriteHandleKey< CONT > &key, const EventContext &ctx)
Creates and right away records the Container CONT with the key.
const std::string & featureString()
const Decision * getExpressTerminusNode(const DecisionContainer &container)
Returns the express-accept navigation node from a collection or nullptr if missing.
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...
std::set< DecisionID > DecisionIDContainer
const Decision * getTerminusNode(SG::ReadHandle< DecisionContainer > &container)
void recursiveFlagForThinning(NavGraph &graph, const bool keepOnlyFinalFeatures, const bool removeEmptySteps, const std::vector< std::string > &nodesToDrop)
Used by trigger navigation thinning.
SG::WriteHandle< DecisionContainer > createAndStore(const SG::WriteHandleKey< DecisionContainer > &key, const EventContext &ctx)
Creates and right away records the DecisionContainer with the key.
void recursiveGetDecisionsInternal(const Decision *node, const Decision *comingFrom, NavGraph &navGraph, std::set< const Decision * > &fullyExploredFrom, const DecisionIDContainer &ids, const bool enforceDecisionOnNode)
Used by recursiveGetDecisions.
const std::string & hypoAlgNodeName()
void linkToPrevious(Decision *d, const std::string &previousCollectionKey, size_t previousIndex)
Links to the previous object, location of previous 'seed' decision supplied by hand.
const std::string & initialRoIString()
const std::string & seedString()
const std::string & summaryPassNodeName()
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.
std::size_t erase_if(T_container &container, T_Func pred)
Particle_v1 Particle
Define the latest version of the particle class.
ParticleContainer_v1 ParticleContainer
Define the latest version of the particle class.
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.
Cached chain configuration from TrigDecisionTool (populated once on first event).