ATLAS Offline Software
Loading...
Searching...
No Matches
TrigNavSlimmingMTAlg.cxx
Go to the documentation of this file.
1
2/*
3 Copyright (C) 2002-2025 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 const Decision* applyPassingChainsFilter = nullptr;
167 if (not m_keepFailedBranches) { // In this case, we should further restrict the chainIDs to only chains which pass the event
168 applyPassingChainsFilter = terminusNode;
169 }
170 ATH_CHECK(fillChainIDs(chainIDs, applyPassingChainsFilter));
171 ATH_MSG_DEBUG("Supplied " << m_chainsFilter.size() << " chain patterns. This converts to " << chainIDs.size() << " DecisionIDs to be preserved.");
172 if (chainIDs.empty()) {
173 // 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.
174 chainIDs.insert( HLT::Identifier("HLT_dummy").numeric() );
175 }
176 } else {
177 ATH_MSG_DEBUG("No HLT-chain based filtering of the navigation graph will be performed.");
178 }
179
180 std::set<const Decision*> fullyExploredFrom;
181 // Note: We use the "internal" version of this call such that we maintain our own cache,
182 // as we may need to call this more than once if keepFailedBranches is true
184 nullptr, // 'Coming from' is nullptr for the first call of the recursive function
185 transientNavGraph,
186 fullyExploredFrom,
187 chainIDs,
188 /*enforce chainIDs on terminus node*/ true);
189
190 ATH_MSG_DEBUG("Collated nodes from passing paths, now have " << transientNavGraph.nodes() << " nodes with " << transientNavGraph.edges() << " edges");
191
192 // Stage 2. We can optionally include branches through the graph which were never accepted by any chain.
193 TrigTimeStamp stage2;
194 // These branches do not connect to the terminusNode, so we have to go hunting them explicitly.
195 // We need to pass in the evtStore as these nodes can be spread out over numerous collections.
196 // Like with the terminus node, we can restrict this search to only nodes which were rejected by certain chains.
197 // We also want to restrict the search to exclude the output collections of any other TrigNavSlimminMTAlg instances
198 // 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.
200 std::vector<const Decision*> rejectedNodes = TrigCompositeUtils::getRejectedDecisionNodes(&*evtStore(), ctx, m_primaryInputCollection.key(), chainIDs, m_allOutputContainersSet);
201 for (const Decision* rejectedNode : rejectedNodes) {
202 // We do *not* enforce that a member of chainIDs must be present in the starting node (rejectedNode)
203 // specifically because we know that at least one of chainIDs was _rejected_ here, but is active in the rejected
204 // node's seeds.
206 nullptr, // 'Coming from' is nullptr for the first call of the recursive function
207 transientNavGraph,
208 fullyExploredFrom,
209 chainIDs,
210 /*enforce chainIDs on terminus node*/ false);
211 }
212 ATH_MSG_DEBUG("Collated nodes from failing paths, now have " << transientNavGraph.nodes() << " nodes with " << transientNavGraph.edges() << " edges");
213 }
214
215 // Stage 3. Walk all paths through the graph. Flag for thinning.
216 TrigTimeStamp stage3;
217 // Final nodes includes the terminus node, plus any rejected nodes (if these were collated).
219
220 if (msg().level() <= MSG::VERBOSE) {
221 ATH_MSG_VERBOSE("The navigation graph entering the slimming is:");
222 transientNavGraph.printAllPaths(msg(), MSG::VERBOSE);
223 }
224
225 // Stage 4. Do the thinning. Re-wire removed nodes as we go.
226 TrigTimeStamp stage4;
227 const size_t nodesBefore = transientNavGraph.nodes();
228 const size_t edgesBefore = transientNavGraph.edges();
229 std::vector<const Decision*> thinnedInputNodes = transientNavGraph.thin();
230
231 // TODO - thinnedInputNodes will be dropped, these may link to "features", "roi", or other objects in other containers.
232 // Need to let the slimming svc know that we no longer need the objects pointed to here, and hence they can be thinned.
233
234 ATH_MSG_DEBUG("Trigger navigation graph thinning going from " << nodesBefore << " nodes with " << edgesBefore << " edges, to "
235 << transientNavGraph.nodes() << " nodes with " << transientNavGraph.edges() << " edges");
236
237 if (msg().level() <= MSG::VERBOSE) {
238 ATH_MSG_VERBOSE("The navigation graph has been slimmed to the following paths:");
239 transientNavGraph.printAllPaths(msg(), MSG::VERBOSE);
240 }
241
242 // Stage 5. Fill the transientNavGraph structure (with NavGraphNode* nodes) back into an xAOD::DecisionContainer (with xAOD::Decision* nodes).
243 TrigTimeStamp stage5;
244 IOCacheMap cache; // Used to keep a one-to-one relationship between the const input Decision* and the mutable output Decision*
245
246 // Do the terminus node first - such that it ends up at index 0 of the outputNavigation (fast to locate in the future)
247 Decision* terminusNodeOut = nullptr;
248 const DecisionIDContainer emptySet = {};
249 ATH_CHECK(inputToOutput(terminusNode, &terminusNodeOut, cache, outputContainers, (m_applyChainsFilterToSummaryNodes ? chainIDs : emptySet), ctx));
250
251 const Decision* expressTerminusNode = TrigCompositeUtils::getExpressTerminusNode(*primaryInputHandle);
252 if (expressTerminusNode) {
253 // Do the express terminus node second - such that it ends up at index 1 of the outputNavigation (fast to locate in the future)
254 Decision* expressTerminusNodeOut = nullptr;
255 ATH_CHECK(inputToOutput(expressTerminusNode, &expressTerminusNodeOut, cache, outputContainers, (m_applyChainsFilterToSummaryNodes ? chainIDs : emptySet), ctx));
256 }
257
259 // Prescaled summary node might come third, it is optional.
261 if (prescaledNode) { // We can propagate it directly (potential for Run 4)
262 Decision* prescaleNodeOut = nullptr;
263 ATH_CHECK(inputToOutput(prescaledNode, &prescaleNodeOut, cache, outputContainers, (m_applyChainsFilterToSummaryNodes ? chainIDs : emptySet), ctx));
264 } else { // We can re-create this from the trigger bits
265 ATH_CHECK(createPresaledGraphNode(outputContainers, (m_applyChainsFilterToSummaryNodes ? chainIDs : emptySet)));
266 }
267 }
268
269 if (m_propagateL1Nodes) {
270 // L1 summary nodes are also optional.
271 const Decision* L1TBPNode = TrigCompositeUtils::getNodeByName(*primaryInputHandle, "L1TBP"); // TODO - upgrade to static string constants if we use this in production.
272 const Decision* L1TAVNode = TrigCompositeUtils::getNodeByName(*primaryInputHandle, "L1TAV");
273 if (L1TBPNode && L1TAVNode) {
274 Decision* L1TBPNodeOut = nullptr;
275 Decision* L1TAVNodeOut = nullptr;
276 ATH_CHECK(inputToOutput(L1TBPNode, &L1TBPNodeOut, cache, outputContainers, {}, ctx)); // No chain filtering, these are L1 items
277 ATH_CHECK(inputToOutput(L1TAVNode, &L1TAVNodeOut, cache, outputContainers, {}, ctx));
278 } else {
279 ATH_CHECK(createL1GraphNodes(outputContainers));
280 }
281 }
282
283 // Don't have to walk the graph here, just iterate through the set of (thinned) nodes.
284 // We won't end up with two terminus nodes because of this (it checks that the node hasn't already been processed)
285 const std::vector<NavGraphNode*> allNodes = transientNavGraph.allNodes();
286 for (const NavGraphNode* inputNode : allNodes) {
287 Decision* outputNode = nullptr;
288 ATH_CHECK(inputToOutput(inputNode->node(), &outputNode, cache, outputContainers, chainIDs, ctx));
289 }
290 // Now we have all of the new nodes in the output collection, can link them all up with their slimmed seeding relationships.
291 for (const NavGraphNode* inputNode : allNodes) {
292 ATH_CHECK(propagateSeedingRelation(inputNode, cache, ctx));
293 }
294
295 // 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
296 // from the 'terminusNodeOut', more code would be needed to locate failing branches also in the output graph structure.
297 if (msg().level() <= MSG::VERBOSE && !m_keepFailedBranches) {
298 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)");
299 std::set<const Decision*> fullyExploredFromOut;
300 NavGraph transientNavGraphOut;
302 nullptr, // 'Coming from' is nullptr for the first call of the recursive function
303 transientNavGraphOut,
304 fullyExploredFromOut,
305 chainIDs,
306 /*enforce chainIDs on terminus node*/ true);
307 transientNavGraphOut.printAllPaths(msg(), MSG::VERBOSE);
308 }
309
310 if (msg().level() <= MSG::DEBUG) {
311 ATH_MSG_DEBUG("Navigation slimming and thinning timings:");
312 ATH_MSG_DEBUG(" 1. Transient Graph of Passed Nodes = " << stage1.millisecondsDifference(stage2) << " ms");
313 ATH_MSG_DEBUG(" 2. Transient Graph of Failed Nodes = " << stage2.millisecondsDifference(stage3) << " ms");
314 ATH_MSG_DEBUG(" 3. Flag Transient Graph For Thinning = " << stage3.millisecondsDifference(stage4) << " ms");
315 ATH_MSG_DEBUG(" 4. Perform Transient Graph Thinning = " << stage4.millisecondsDifference(stage5) << " ms");
316 ATH_MSG_DEBUG(" 5. Write xAOD Graph = " << stage5.millisecondsSince() << " ms");
317 }
318
319 return StatusCode::SUCCESS;
320}
321
322std::vector<size_t> TrigNavSlimmingMTAlg::lookupHardCodedLegMultiplicities(const std::string& chain) const {
323 if (chain == "HLT_id_cosmicid_L1MU11_EMPTY") return std::vector<size_t>(1,1); // size = 1, value at index 0 = 1
324 return std::vector<size_t>();
325}
326
327StatusCode TrigNavSlimmingMTAlg::fillChainIDs(DecisionIDContainer& chainIDs, const Decision* applyPassingChainsFilter) const {
328 DecisionIDContainer passingChains;
329 if (applyPassingChainsFilter) { // Expect either nullptr or a pointer to the terminus node here.
330 TrigCompositeUtils::decisionIDs(applyPassingChainsFilter, passingChains); // Extract all passing chains into the passingChains set
331 }
332
333 for (const std::string& filter : m_chainsFilter) {
334 // We do this as filter->chains stage as filter could be a regexp matching a large number of chains
335 const Trig::ChainGroup* cg = m_trigDec->getChainGroup(filter);
336 std::vector<std::string> chains = cg->getListOfTriggers();
337 for (const std::string& chain : chains) {
338 const TrigConf::HLTChain* hltChain = m_trigDec->ExperimentalAndExpertMethods().getChainConfigurationDetails(chain);
339 const HLT::Identifier chainID( hltChain->chain_name() );
340 if (passingChains.size() && passingChains.count( chainID.numeric() ) == 0) { // Optional additional filter on passing chains in this specific event
341 ATH_MSG_VERBOSE("Skipping " << chain << " as it didn't pass this event");
342 continue;
343 }
344 chainIDs.insert( chainID.numeric() );
345 std::vector<size_t> legMultiplicites = hltChain->leg_multiplicities();
346 ATH_MSG_VERBOSE("Including " << chain << " and its " << legMultiplicites.size() << " legs in the trigger slimming output");
347 if (legMultiplicites.size() == 0) {
348 legMultiplicites = lookupHardCodedLegMultiplicities(chain);
349 if (legMultiplicites.size() == 0) {
350 ATH_MSG_ERROR("chain " << chainID << " has invalid configuration, no multiplicity data.");
351 return StatusCode::FAILURE;
352 }
353 }
354 if (legMultiplicites.size() > 1) {
355 // For multi-leg chains, the DecisionIDs are handled per leg.
356 // We don't care here exactly how many objects are required per leg, just that there are two-or-more legs
357 for (size_t legNumeral = 0; legNumeral < legMultiplicites.size(); ++legNumeral) {
358 const HLT::Identifier legID = TrigCompositeUtils::createLegName(chainID, legNumeral);
359 chainIDs.insert( legID.numeric() );
360 }
361 }
362 }
363 }
364 return StatusCode::SUCCESS;
365}
366
368 Decision* prescaledNode = newDecisionIn(outputContainers.nav->ptr(), TrigCompositeUtils::summaryPrescaledNodeName());
369
370 const Trig::ChainGroup* cg = m_trigDec->getChainGroup("HLT_.*|EF_.*");
371 const std::vector<std::string> chains = cg->getListOfTriggers();
372 const std::vector<unsigned int> bits = cg->isPassedBitsForEach();
373 if (chains.size() != bits.size()) {
374 ATH_MSG_ERROR("Unexpected different sized chains and bits vectors");
375 return StatusCode::FAILURE;
376 }
377
378 DecisionIDContainer prescaledIDs;
379 for (size_t i = 0; i < bits.size(); ++i) {
380 if (bits[i] & TrigDefs::EF_prescaled) { prescaledIDs.insert( HLT::Identifier(chains[i]).numeric() ); }
381 }
382
383 if (m_applyChainsFilterToSummaryNodes && chainIDs.size()) { // Then apply the filter
384 std::erase_if(prescaledIDs, [&](int id) {
385 return !chainIDs.contains(id); // Keep only elements in chainIDs
386 });
387 }
388
389 TrigCompositeUtils::insertDecisionIDs(prescaledIDs, prescaledNode); // Copy the set of chains into the xAOD object
390 return StatusCode::SUCCESS;
391}
392
393StatusCode TrigNavSlimmingMTAlg::createL1GraphNodes(Outputs& outputContainers) const {
394 Decision* L1TBPNode = newDecisionIn(outputContainers.nav->ptr(), "L1TBP");
395 Decision* L1TAVNode = newDecisionIn(outputContainers.nav->ptr(), "L1TAV");
396 // Note - this is for offline use, there's no point in keeping TAP (trigger after prescale) as well as TAV
397
398 const Trig::ChainGroup* cg = m_trigDec->getChainGroup("L1_.*|L0_.*"); // Note: Future proofing for Run 4
399 std::vector<std::string> chains = cg->getListOfTriggers();
400 const std::vector<unsigned int> bits = cg->isPassedBitsForEach();
401 if (chains.size() != bits.size()) {
402 ATH_MSG_ERROR("Unexpected different sized chains and bits vectors");
403 return StatusCode::FAILURE;
404 }
405
406 DecisionIDContainer TBPIDs, TAVIDs;
407 for (size_t i = 0; i < bits.size(); ++i) {
408 if (bits[i] & TrigDefs::L1_isPassedBeforePrescale) { TBPIDs.insert( HLT::Identifier(chains[i]).numeric() ); }
409 if (bits[i] & TrigDefs::L1_isPassedAfterVeto) { TAVIDs.insert( HLT::Identifier(chains[i]).numeric() ); }
410 }
411
412 TrigCompositeUtils::insertDecisionIDs(TBPIDs, L1TBPNode);
413 TrigCompositeUtils::insertDecisionIDs(TAVIDs, L1TAVNode);
414 ATH_MSG_INFO("Created new TAV node at index " << L1TAVNode->index() << " with " << TBPIDs.size() << " = " << TAVIDs.size() << " decisions\n" << *L1TAVNode );
415 return StatusCode::SUCCESS;
416}
417
418
420 const TrigCompositeUtils::Decision* input,
422 IOCacheMap& cache,
423 Outputs& outputContainers,
424 const DecisionIDContainer& chainIDs,
425 const EventContext& ctx) const
426{
427 IOCacheMap::const_iterator it = cache.find(input);
428 if (it != cache.end()) {
429 *output = it->second;
430 } else {
431 *output = newDecisionIn(outputContainers.nav->ptr(), input, input->name(), ctx);
432 ATH_CHECK(propagateLinks(input, *output));
433 ATH_CHECK(propagateDecisionIDs(input, *output, chainIDs));
434 ATH_CHECK(repackLinks(*output, outputContainers));
435 cache[input] = *output;
436 }
437 return StatusCode::SUCCESS;
438}
439
440
442 const TrigCompositeUtils::NavGraphNode* inputNode,
443 IOCacheMap& cache,
444 const EventContext& ctx) const
445{
446 const Decision* inputDecision = inputNode->node(); // The incoming Decision objects, with links into the old graph
447 Decision* outputDecision = nullptr; // The outgoing Decision object, without graph links so far
448 {
449 IOCacheMap::const_iterator it = cache.find(inputDecision);
450 ATH_CHECK( it != cache.end() );
451 outputDecision = it->second;
452 }
453 for (const NavGraphNode* seed : inputNode->seeds()) {
454 const Decision* inputSeedDecision = seed->node(); // A Decision object the incoming Decision object links to (old graph)
455 const Decision* outputSeedDecision = nullptr; // The equivalent Decision Object in the slimmed outgoing graph
456 {
457 IOCacheMap::const_iterator it = cache.find(inputSeedDecision);
458 ATH_CHECK( it != cache.end() );
459 outputSeedDecision = it->second;
460 }
461 // Perform the linking only using nodes from the slimmed output graph
462 TrigCompositeUtils::linkToPrevious(outputDecision, outputSeedDecision, ctx);
463 }
464
465 // Don't run this check for "HLTPassRaw", this node is expected to link back to every passing physics object.
466 // Hence there may be more than 'sensibleUpperBoundOnNLinks' in aggregate here.
467 if (m_runtimeValidation and outputDecision->name() != TrigCompositeUtils::summaryPassNodeName()) {
468 const size_t sensibleUpperBoundOnNLinks = 100;
469 const size_t maxUpperBoundOnNLinks = 500;
470 // Note: Only in the NavGraphNode do we have the two-way links to check how many children link back to this node
471 const bool bad_in = inputNode->children().size() > sensibleUpperBoundOnNLinks;
472 //Note: Here we check more than "seed" links. We pick up external links too like "feature"
473 const bool bad_out = outputDecision->linkColNames().size() > sensibleUpperBoundOnNLinks;
474 const bool vbad = inputNode->children().size() > maxUpperBoundOnNLinks or outputDecision->linkColNames().size() > maxUpperBoundOnNLinks;
475 if (bad_in) {
476 ATH_MSG_WARNING("Saving a Decision object with a very large number of INCOMING graph edges. Number of in-edges: " << inputNode->children().size());
477 }
478 if (bad_out) {
479 ATH_MSG_WARNING("Saving a Decision object with a very large number of OUTGOING graph edges. Number of out-edges: " << outputDecision->linkColNames().size());
480 }
481 if (bad_in or bad_out) {
482 ATH_MSG_WARNING("Comes from: " << TrigCompositeUtils::decisionToElementLink(inputDecision, ctx).dataID());
483 ATH_MSG_DEBUG("Output Decision: " << *outputDecision);
484 }
485 if (vbad) {
486 ATH_MSG_ERROR("More than " << maxUpperBoundOnNLinks << " links, printing an ERROR such that this gets promptly investigated and reduced.");
487 }
488 }
489 return StatusCode::SUCCESS;
490}
491
492
494 const TrigCompositeUtils::Decision* input,
495 TrigCompositeUtils::Decision* output) const
496{
497 // ElementLinks form the edges in the graph. Start by copying all of them over.
498
499 output->copyAllLinksFrom( input );
500
501 // Special behavior to save additional disk space for keepOnlyFinalFeatures mode.
502 // In keepOnlyFinalFeatures we stop at the first hypoAlgNode, hence we will drop the preceding inputMakerNode, and all prior Steps in their entirety.
503 // This means we will also drop all "roi" edges, including the final ROI.
504 // 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.
505 // Note: If "roi" is listed in m_edgesToDrop then we will still immediately drop this new element link in the m_edgesToDrop loop below.
506 const std::vector<ElementLink<DecisionContainer>> seeds = input->objectCollectionLinks<DecisionContainer>(seedString());
507 const Decision* const firstParent = (seeds.size() ? *seeds.at(0) : nullptr);
509 input->name() == hypoAlgNodeName() &&
510 firstParent &&
511 firstParent->name() == inputMakerNodeName() &&
512 firstParent->hasObjectLink(roiString()))
513 {
514 output->copyLinkFrom( firstParent, roiString() );
515 }
516
517 for (const std::string& toRemove : m_edgesToDrop) {
518 output->removeObjectLink(toRemove);
519 output->removeObjectCollectionLinks(toRemove);
520 // TODO - let the slimming svc know that we no longer need these objects
521 }
522
523 // Do not propagate "seed" links - TrigNavSlimmingMTAlg will
524 // propagate these following additional logic
525 output->removeObjectCollectionLinks( seedString() );
526
527 return StatusCode::SUCCESS;
528}
529
530
532 const TrigCompositeUtils::Decision* input,
534 const DecisionIDContainer& chainIDs) const
535{
536
537 // Get all DecisionIDs from the const input Decision*
538 DecisionIDContainer fromInput;
539 decisionIDs(input, fromInput);
540
541 DecisionIDContainer toOutput;
542 if ( chainIDs.size() ) {
543 // Applying ChainsFilter to the set of DecisionIDs
544 std::set_intersection(fromInput.begin(), fromInput.end(), chainIDs.begin(), chainIDs.end(),
545 std::inserter(toOutput, toOutput.begin()));
546 } else {
547 // Copying all DecisionIDs from input to output
548 toOutput.insert(fromInput.begin(), fromInput.end());
549 }
550
551 // Set the DecisionIDs into the mutable output Decision*
552 insertDecisionIDs(toOutput, output);
553
554 return StatusCode::SUCCESS;
555}
556
558 if (not msgLvl(MSG::DEBUG)) return;
559 if (output->hasObjectLink(featureString(), ClassID_traits<xAOD::IParticleContainer>::ID())) {
561 if (link.isValid()) {
562 const xAOD::IParticle& l = **link;
563 ATH_MSG_DEBUG("IParticle repacking debug. " << when << " : "
564 << "(pt:" << l.pt() << ",eta:" << l.eta() << ",phi:" << l.phi() << ",m:" << l.m() << ",e:" << l.e() << ")"
565 << " from:" << link.dataID());
566 if (when == " After") ATH_MSG_DEBUG("--");
567 }
568 }
569}
570
571
574 Outputs& outputContainers) const
575{
576
577 if (m_repackROIs) {
578 ATH_CHECK( doRepack<TrigRoiDescriptorCollection>(output, outputContainers.rois, roiString()) );
579 ATH_CHECK( doRepack<TrigRoiDescriptorCollection>(output, outputContainers.rois, initialRoIString()) );
580 }
581
582 if (m_repackFeatures) {
583 // Debug printing. Look at the four-momentum of any feature before the repacking.
584 // Note: Transiently we interact with the IParticle interface.
585 printIParticleRepackingDebug(output, "Before");
586
587 // Do any IParticle repacking
588 ATH_CHECK( doRepack<xAOD::ParticleContainer>(output, outputContainers.particles, featureString()) );
589 ATH_CHECK( doRepack<xAOD::ParticleContainer>(output, outputContainers.particles, "subfeature") );
590
591 // Debug printing. Look at the four-momentum of any feature after the repacking (the stored link is re-written)
592 printIParticleRepackingDebug(output, " After");
593 }
594
595 // Some features do not support an IParticle interface. These need their own containers.
596 // TODO. Apply some thinning?
597 if (m_repackMET) {
598 ATH_CHECK( doRepack<xAOD::TrigMissingETContainer>(output, outputContainers.mets, featureString()) );
599 }
600
601 return StatusCode::SUCCESS;
602}
#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
size_t index() const
Return the index of this element within its container.
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 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
StatusCode fillChainIDs(TrigCompositeUtils::DecisionIDContainer &chainIDs, const TrigCompositeUtils::Decision *applyPassingChainsFilter) const
Convert the ChainsFilter into the set of chain-IDd and chain-leg-IDs which comprises all of the Decis...
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.