ATLAS Offline Software
Loading...
Searching...
No Matches
Run2ToRun3TrigNavConverterV2.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 <boost/functional/hash.hpp>
6#include <GaudiKernel/StatusCode.h>
7#include "AthLinks/ElementLinkVector.h"
16#include "SpecialCases.h"
17#include <limits>
18#include <cstdint>
19
20namespace TCU = TrigCompositeUtils;
21
22// helper class
24{
25 teIDs.push_back(te->getId());
26}
27
28// find if proxy is a child of other proxies, also follows to children of the children etc...
29bool ConvProxy::isChild(const ConvProxy* other ) const {
30 for ( auto c: children ) {
31 if (other == c)
32 return true;
33 if ( c->isChild(other) )
34 return true;
35 }
36 return false;
37}
38
39bool ConvProxy::isParent(const ConvProxy* other ) const {
40 for ( auto c: parents ) {
41 if (other == c)
42 return true;
43 if ( c->isParent(other) )
44 return true;
45 }
46 return false;
47}
48
49
50bool ConvProxy::mergeAllowed(const ConvProxy *other) const
51{
52 if (this == other)
53 return false; // no merging with self
54 // never merge children with parents
55 if ( isChild(other) )
56 return false;
57 if ( isParent(other) )
58 return false;
59 return true;
60}
61
63{
64 if (other == this)
65 {
66 return;
67 }
68 // copy over chains
69 runChains.insert(other->runChains.begin(), other->runChains.end());
70 passChains.insert(other->passChains.begin(), other->passChains.end());
71 teIDs.push_back(other->te->getId());
72 /* the intention of the code below is following.
73 Intial structure like is like this (the line is always bidirectional):
74 P1 P2 P3 <- parents
75 | | /
76 T1 T2 <- "this" and "other"
77 | |
78 C1 C2 <- children
79 1) Lets assume that the first proxies we treat are B1 & B2 ath they are mergable. The resulting structure should look like this:
80 P1 P2 P3
81 |/__/
82 T1 T2
83 |\
84 C1 C2
85
86 */
87 auto add = [](ConvProxy *toadd, std::set<ConvProxy *> &coll)
88 {
89 if (std::find(coll.begin(), coll.end(), toadd) == coll.end())
90 {
91 coll.insert(toadd);
92 }
93 };
94
95 auto remove = [](ConvProxy *torem, std::set<ConvProxy *> &coll)
96 {
97 auto place = std::find(coll.begin(), coll.end(), torem);
98 if (place != coll.end())
99 {
100 coll.erase(place);
101 }
102 };
103
104 // this is T <-> C connection
105 for (auto otherChild : other->children)
106 {
107 add(otherChild, children);
108 add(this, otherChild->parents);
109 }
110 // this is T <-> P connection rewiring
111 for (auto otherParent : other->parents)
112 {
113 add(otherParent, parents);
114 add(this, otherParent->children);
115 }
116
117 // now need to remove links back to the "other"
118 for (auto otherParent : other->parents)
119 {
120 remove(other, otherParent->children);
121 }
122
123 for (auto otherChild : other->children)
124 {
125 remove(other, otherChild->parents);
126 }
127 other->children.clear();
128 other->parents.clear();
129}
130
131std::string ConvProxy::description() const
132{
133 std::string ret;
134 ret += " N parents: " + std::to_string(parents.size());
135 ret += " N children: " + std::to_string(children.size());
136 std::ostringstream os;
137 for ( auto c: children )
138 os << c << " ";
139 ret += " ptrs: " + os.str();
140 ret += " feaHash: " + std::to_string(feaHash);
141 ret += " N run chains: " + std::to_string(runChains.size());
142 return ret;
143}
144
145// the algorithm
146Run2ToRun3TrigNavConverterV2::Run2ToRun3TrigNavConverterV2(const std::string &name, ISvcLocator *pSvcLocator) : AthReentrantAlgorithm(name, pSvcLocator)
147{
148}
149
153
155{
156 ATH_CHECK(m_trigOutputNavKey.initialize());
157 ATH_CHECK(m_tdt.empty() != m_trigNavKey.key().empty()); // either of the two has to be enabled but not both
158 if (!m_tdt.empty())
159 {
160 ATH_CHECK(m_tdt.retrieve());
161 ATH_MSG_INFO("Will use Trigger Navigation from TrigDecisionTool");
162 }
163 else
164 {
166 ATH_MSG_INFO("Will use Trigger Navigation decoded from TrigNavigation object");
167 }
168
169 if (!m_chainsToSave.empty()) {
170 ATH_MSG_DEBUG("Will only save features for these chains " << m_chainsToSave);
171 }
172
173 ATH_CHECK(m_configSvc.retrieve());
174 ATH_CHECK(m_clidSvc.retrieve());
175
176 // configured collections can be either just type name, or type#key
177 // decoding takes this into account, if only the type is configured then empty string is places in the decoded lookup map
178 // else CLID + a name is placed
179
180 for (const auto &name : m_collectionsToSave)
181 {
182 std::string typeName = name;
183 std::string collName;
184 size_t delimeterIndex = name.find('#');
185 if (delimeterIndex != std::string::npos)
186 {
187 typeName = name.substr(0, delimeterIndex);
188 collName = name.substr(delimeterIndex + 1);
189 }
190 CLID id{0};
191 ATH_CHECK(m_clidSvc->getIDOfTypeName(typeName, id));
192 ATH_MSG_DEBUG("Will be linking collection type " << typeName << " name (empty==all) " << collName);
193 if ( collName.empty() )
194 m_collectionsToSaveDecoded[id]; // creates empty set
195 else
196 m_collectionsToSaveDecoded[id].insert(collName);
197 }
198
199 for (const auto &name : m_roisToSave)
200 {
201 m_setRoiName.push_back(name);
202 }
203
204 // sanity check, i.e. if there is at least one entry w/o the coll name no other entries are needed for a given clid
205 for (auto [clid, keysSet] : m_collectionsToSaveDecoded)
206 {
207 if (keysSet.size() > 1 and keysSet.count("") != 0)
208 {
209 ATH_MSG_ERROR("Bad configuration for CLID " << clid << " requested saving of all (empty coll name configures) collections, yet there are also specific keys");
210 return StatusCode::FAILURE;
211 }
212
213 }
214
215 bool anyChainBad=false;
216 for ( auto chain: m_chainsToSave ) {
217 if ( chain.find('*') != std::string::npos or chain.find('|') != std::string::npos ) {
218 ATH_MSG_ERROR("Supplied chain name: " << chain << " contains wildcard characters, this is not supported by the conversion tool");
219 anyChainBad=true;
220 }
221 }
222 if ( anyChainBad ) {
223 ATH_MSG_ERROR("Supplied chain names contain wildcard characters, this is not supported by the conversion tool");
224 return StatusCode::FAILURE;
225 }
226 if ( m_chainsToSave.empty() ) {
227 ATH_MSG_INFO("No chains list supplied, the conversion will occur for all chains");
228 }
229
230 ATH_CHECK(m_clidSvc->getIDOfTypeName("TrigRoiDescriptor", m_roIDescriptorCLID));
231 ATH_CHECK(m_clidSvc->getIDOfTypeName("TrigRoiDescriptorCollection", m_roIDescriptorCollectionCLID));
232 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::TrigRingerRings", m_TrigRingerRingsCLID));
233 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::TrigRingerRingsContainer", m_TrigRingerRingsContainerCLID));
234 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::TrigEMCluster", m_TrigEMClusterCLID));
235 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::TrigEMClusterContainer", m_TrigEMClusterContainerCLID));
236 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::CaloCluster", m_CaloClusterCLID));
237 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::CaloClusterContainer", m_CaloClusterContainerCLID));
238 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::TrackParticleContainer", m_TrackParticleContainerCLID));
239 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::TauTrackContainer", m_TauTrackContainerCLID));
240 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::ElectronContainer", m_ElectronContainerCLID));
241 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::PhotonContainer", m_PhotonContainerCLID));
242 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::MuonContainer", m_MuonContainerCLID));
243 ATH_CHECK(m_clidSvc->getIDOfTypeName("xAOD::TauJetContainer", m_TauJetContainerCLID));
244
245 return StatusCode::SUCCESS;
246}
247
249{
250 return StatusCode::SUCCESS;
251}
252
253StatusCode Run2ToRun3TrigNavConverterV2::execute(const EventContext &context) const
254{
255 {
256 // configuration reading could not be done before the event loop
257 // it needs to be done only once though
258 std::scoped_lock lock(m_configUpdateMutex);
259 if (m_allTEIdsToChains.empty())
261 }
262
263 ConvProxySet_t convProxies;
264 HLT::StandaloneNavigation standaloneNav; // needed to keep TEs around, so it is out of the scope where it is filled and referenced
265 const HLT::TrigNavStructure *run2NavigationPtr = nullptr;
266 if (!m_trigNavKey.key().empty())
267 {
268 SG::ReadHandle navReadHandle(m_trigNavKey, context);
269 ATH_CHECK(navReadHandle.isValid());
270 standaloneNav.deserialize(navReadHandle->serialized());
271 run2NavigationPtr = &standaloneNav;
272 }
273 else
274 {
275 run2NavigationPtr = m_tdt->ExperimentalAndExpertMethods().getNavigation();
276 }
277
278 ATH_CHECK(mirrorTEsStructure(convProxies, *run2NavigationPtr));
279 // printProxies(convProxies, [](auto ){ return true;},
280 // {m_chainIdsPrinter});
281
283 ATH_CHECK(allProxiesConnected(convProxies));
284
286 // printProxies(convProxies, [](auto ){ return true;},
287 // {m_chainIdsPrinter});
288
290 ATH_MSG_DEBUG("Proxies to chains mapping done");
291
293
294 if (not m_chainsToSave.empty())
295 {
297 printProxies(convProxies, [](auto ){ return true;},
299 ATH_MSG_DEBUG("Removed proxies to chains that are not converted, remaining number of elements " << convProxies.size());
300 }
302 {
303 ATH_CHECK(allProxiesHaveChain(convProxies));
304 }
305 if (m_doCompression)
306 {
307 ATH_CHECK(doCompression(convProxies, *run2NavigationPtr));
308 // printProxies(convProxies, [](auto ){ return true;},
309 // {m_chainIdsPrinter});
310
311 }
312
314 auto decisionOutput = outputNavigation.ptr();
315 TrigCompositeUtils::newDecisionIn(decisionOutput, TCU::summaryPassNodeName()); // we rely on the fact that the 1st element is the top
316
318 {
319 ATH_CHECK(fillRelevantFeatures(convProxies, *run2NavigationPtr));
320 ATH_CHECK(fillRelevantRois(convProxies, *run2NavigationPtr));
321 ATH_CHECK(fillRelevantTracks(convProxies));
322 ATH_MSG_DEBUG("Features to link found");
323 }
324
325 ATH_CHECK(createIMHNodes(convProxies, *decisionOutput, context));
327 {
329 }
330
331 ATH_CHECK(createL1Nodes(convProxies, *decisionOutput, context));
332 ATH_CHECK(linkFeaNode(convProxies, *decisionOutput, *run2NavigationPtr, context));
333 ATH_CHECK(linkRoiNode(convProxies, *run2NavigationPtr));
334 ATH_CHECK(linkTrkNode(convProxies, *run2NavigationPtr));
335 ATH_CHECK(createSFNodes(convProxies, *decisionOutput, m_finalTEIdsToChains, context));
336 ATH_CHECK(updateTerminusNode(*decisionOutput, context));
337 ATH_MSG_DEBUG("Conversion done, from " << convProxies.size() << " elements to " << decisionOutput->size() << " elements");
338
339 printProxies(convProxies, [](auto ){ return true;},
341 ATH_MSG_DEBUG("Resulting nodes");
342 size_t index = 0;
343 for ( auto o: *decisionOutput) {
344 ATH_MSG_DEBUG("Index: " << index << " " << *o);
345 index++;
346 }
347
348 // dispose temporaries
349 for (auto proxy : convProxies)
350 {
351 delete proxy;
352 }
353
354 return StatusCode::SUCCESS;
355}
356
358 // chains of configs structure
359 // A B
360 // \/
361 // C
362 // where C is the output TE of sequence consuming A & B
363 // sometimes there are an additional leafs
364 // C
365 // |
366 // D
367 if ( not std::regex_match(ptrChain->name(), SpecialCases::isTopo) ) return 0;
368 size_t stepToConsider = 0;
369 const size_t sigsSize = ptrChain->signatures().size();
370 if ( sigsSize < 2 ) return 0;
371 for ( size_t step = sigsSize-1; step > 1; step --) {
372 if ( (ptrChain->signatures()[step-1])->outputTEs().size() == 2 and (ptrChain->signatures()[step])->outputTEs().size() == 1 ) {
373 stepToConsider = step;
374 break;
375 }
376 }
377 if ( stepToConsider == 0 ) return 0; // not a topo
378
379 //counting is right, need to see now if TEs are connected
380 auto finalTE = (ptrChain->signatures()[stepToConsider])->outputTEs()[0];
381 auto preFinalTEs = (ptrChain->signatures()[stepToConsider-1])->outputTEs();
382
383 auto finalSeq = m_configSvc->sequences().getSequence(finalTE->id());
384 std::set<HLT::te_id_type> tesInSeq;
385 std::set<HLT::te_id_type> tesInChain;
386
387 for ( auto te: finalSeq->inputTEs()) {
388 tesInSeq.insert(te->id());
389 }
390
391 for ( auto te: preFinalTEs) {
392 tesInChain.insert(te->id());
393 }
394
395 if (tesInSeq == tesInChain) {
396 return stepToConsider;
397 }
398 return 0;
399}
400
402{
403
404 ATH_CHECK(not m_configSvc->chains().empty());
405
406 // obtain map output TE -> input TE via sequences
407 for (auto ptrChain : m_configSvc->chains())
408 {
409 std::string chainName = ptrChain->name();
410
411 if (not m_chainsToSave.empty())
412 {
413 auto found = std::find(m_chainsToSave.begin(), m_chainsToSave.end(), chainName);
414 if (found == m_chainsToSave.end())
415 {
416 continue;
417 }
418 }
419
420 if (std::regex_match(chainName, SpecialCases::bjetMuChain )) {
421 ATH_CHECK(bjetMuChainConfigDecoder(allTEs, finalTEs, ptrChain));
422 continue;
423 }
424
425 // hack for etcut chains
426 // if we ever need to generalise that it should be moved to separate function
427 std::map<HLT::te_id_type, HLT::te_id_type> etcutReplacementTEs;
428 auto etcutReplacement = [&etcutReplacementTEs](HLT::te_id_type in) { auto out = etcutReplacementTEs.find(in); return (out == etcutReplacementTEs.end() ? in : out->second ); };
429 if ( chainName.find("etcut") != std::string::npos ) {
430 std::set<size_t> positionsOfEtCutLegs;
431 // use heuristics to mention
432 if( std::regex_match(chainName, SpecialCases::egammaDiEtcut) ) {
433 ATH_MSG_DEBUG("EtCut chains hack, chain with two etcut legs ");
434 positionsOfEtCutLegs.insert({0, 1});
435 } else if ( std::regex_match(chainName, SpecialCases::egammaCombinedWithEtcut) ) {
436 ATH_MSG_DEBUG("EtCut chains hack, egamma chain with second etcut leg ");
437 positionsOfEtCutLegs.insert({1});
438 } else if ( std::regex_match(chainName, SpecialCases::egammaEtcut) ) {
439 ATH_MSG_DEBUG("EtCut chains hack, single leg egamma chain");
440 positionsOfEtCutLegs.insert({0});
441 }
442
443 // pilot pass to fill the replacement map
444 std::map<size_t, HLT::te_id_type> positionToDesiredIDmap;
445 for (auto ptrHLTSignature : ptrChain->signatures()) {
446 size_t position = 0;
447 for (auto ptrHLTTE : ptrHLTSignature->outputTEs()) {
448 if (positionsOfEtCutLegs.count(position) and positionToDesiredIDmap.find(position) != positionToDesiredIDmap.end() ) {
449 etcutReplacementTEs[ptrHLTTE->id()] = positionToDesiredIDmap[position];
450 ATH_MSG_DEBUG("EtCut chains hack, TE " << ptrHLTTE->name() << " will be replaced by: " << TrigConf::HLTUtils::hash2string(positionToDesiredIDmap[position]));
451 } else {
452 if ( ptrHLTTE->name().find("calocalib") != std::string::npos and positionsOfEtCutLegs.count(position) ) { // we have final TE for this leg
453 positionToDesiredIDmap[position] = ptrHLTTE->id();
454 }
455 }
456 position++;
457 }
458 }
459 }
460
461 // chains with a single leg
462 HLT::Identifier chainId = HLT::Identifier(chainName);
463 ATH_MSG_DEBUG(" CHAIN name " << chainName << " CHAIN Id " << chainId);
464 for (auto ptrHLTSignature : ptrChain->signatures()) {
465 for (auto ptrHLTTE : ptrHLTSignature->outputTEs()) {
466 unsigned int teId = etcutReplacement(ptrHLTTE->id());
467 allTEs[teId].insert(chainId);
468 if (ptrHLTSignature == ptrChain->signatures().back()) {
469 finalTEs[teId].insert(chainId);
470 ATH_MSG_DEBUG("TE will be used to mark final chain decision " << ptrHLTTE->name() << " chain " << chainName );
471 }
472 }
473 }
474 // chains with a multiple legs
475 std::vector<int> multiplicities = ChainNameParser::multiplicities(chainName);
476
477 // dirty hacks for failing chains parsing
478 if(std::regex_match(chainName, SpecialCases::gammaXeChain))
479 multiplicities={1,1};
480
481 if ( multiplicities.size() > 1 ) {
482 ATH_MSG_DEBUG(" this " << (is2LegTopoChain(ptrChain) ? "is": "is not") << " topological chain");
483 // the chain structure (in terms of multiplicities) may change along the way
484 // we'll assign legs only to these TEs of the steps that have identical multiplicity pattern
485 // e.g. for the chain: HLT_2g25_loose_g20 the multiplicities are: [2, 1]
486
487 // hack for HLT.*tau.*xe.* case
488 if (std::regex_match(chainName, SpecialCases::tauXeChain)) {
489 std::vector<size_t> mult_hack; // type mismatch with ChainNameParser::multiplicities
490 if (multiplicities.size()==3) mult_hack={1,1};
491 else if (multiplicities.size()==2) mult_hack={1};
492 ptrChain->set_leg_multiplicities(mult_hack); // HLTChain needs vector<size_t>
493 }
494
495 // hack for mu2MunoL1Special
496 if (std::regex_match(chainName, SpecialCases::mu2MunoL1Special)) {
497 std::vector<size_t> mult_hack;
498 if (multiplicities.size()==3) mult_hack={1,1};
499 else if (multiplicities.size()==2) mult_hack={2}; // HLT_mu11_nomucomb_2mu4noL1_nscan03_L1MU11_2MU6
500 ptrChain->set_leg_multiplicities(mult_hack);
501 }
502
503 ATH_MSG_DEBUG("CHAIN " << chainName << " needs legs: " << multiplicities );
504 std::vector<unsigned int> teIdsLastHealthyStepIds;
505
506 for (auto ptrHLTSignature : ptrChain->signatures())
507 {
508 std::vector<int> teCounts;
509 std::vector<unsigned int> teIds;
510 unsigned int lastSeenId = 0;
511 for (auto ptrHLTTE : ptrHLTSignature->outputTEs())
512 {
513 if ( lastSeenId != ptrHLTTE->id()) {
514 teCounts.push_back(1);
515 teIds.push_back(ptrHLTTE->id());
516 } else {
517 teCounts.back()++;
518 }
519 lastSeenId = ptrHLTTE->id();
520 }
521
522 ATH_MSG_DEBUG("TE multiplicities seen in this step " << teCounts);
523 bool multiplicityCounts = multiplicities == teCounts;
524 // hack for HLT.*tau.*xe.* case
525 if(std::regex_match(chainName, SpecialCases::tauXeChain)) multiplicityCounts = true;
526 if ( multiplicityCounts ) {
527 teIdsLastHealthyStepIds = teIds;
528 ATH_MSG_DEBUG("There is a match, will assign chain leg IDs to TEs " << teCounts << " " << teIds);
529 for ( size_t legNumber = 0; legNumber < teIds.size(); ++ legNumber){
530 HLT::Identifier chainLegId = TrigCompositeUtils::createLegName(chainId, legNumber);
531 allTEs[etcutReplacement(teIds[legNumber])].insert(chainLegId);
532 }
533 }
534 }
535 for ( size_t legNumber = 0; legNumber < teIdsLastHealthyStepIds.size(); ++ legNumber ) {
536 HLT::Identifier chainLegId = TrigCompositeUtils::createLegName(chainId, legNumber);
537
538 ATH_MSG_DEBUG("created leg id " << chainLegId << " that will replace TE ID " << etcutReplacement(teIdsLastHealthyStepIds[legNumber]));
539 finalTEs[etcutReplacement(teIdsLastHealthyStepIds[legNumber])].insert(chainLegId);
540 }
541 }
542 }
543 ATH_MSG_DEBUG("Recognised " << allTEs.size() << " kinds of TEs and among them " << finalTEs.size() << " final types");
544 return StatusCode::SUCCESS;
545}
546
548 HLT::Identifier chainId = HLT::Identifier(ptrChain->name());
549
550 std::vector<unsigned int> muons;
551 std::vector<unsigned int> jets;
552 bool switchedTojets =false;
553 for (auto ptrHLTSignature : ptrChain->signatures()) {
554 for (auto ptrHLTTE : ptrHLTSignature->outputTEs()) {
555 if ( ptrHLTTE->name().find("_mu") == std::string::npos ) {
556 switchedTojets = true;
557 }
558
559 if ( switchedTojets)
560 jets.push_back(ptrHLTTE->id());
561 else
562 muons.push_back(ptrHLTTE->id());
563 }
564 }
565 ATH_CHECK(not muons.empty());
566 ATH_CHECK(not jets.empty());
567 std::reverse(std::begin(muons), std::end(muons));
568 std::reverse(std::begin(jets), std::end(jets));
569 finalTEs[muons[0]].insert(TrigCompositeUtils::createLegName(chainId, 0));
570 finalTEs[muons[0]].insert(chainId);
571 finalTEs[jets[0]].insert(TrigCompositeUtils::createLegName(chainId, 1));
572 finalTEs[jets[0]].insert(chainId);
573
574 for ( size_t index = 0; index < std::min(muons.size(), jets.size()); ++index)
575 {
576 allTEs[muons[index]].insert(TrigCompositeUtils::createLegName(chainId, 0));
577 allTEs[muons[index]].insert(chainId);
578 allTEs[jets[index]].insert(TrigCompositeUtils::createLegName(chainId, 1));
579 allTEs[jets[index]].insert(chainId);
580 }
581 return StatusCode::SUCCESS;
582}
583
584
585
587{
588
589 // iterate over the TEs, for each make the ConvProxy and build connections
590 std::map<const HLT::TriggerElement *, ConvProxy *> teToProxy;
591 ATH_MSG_DEBUG("TrigNavStructure with " << run2Nav.getAllTEs().size() << " TEs acquired");
592 for (auto te : run2Nav.getAllTEs())
593 {
594 // skip event seed node
596 continue;
597 auto proxy = new ConvProxy(te);
598 convProxies.insert(proxy);
599 teToProxy[te] = proxy;
600 // add linking
601 for (auto predecessor : HLT::TrigNavStructure::getDirectPredecessors(te))
602 {
603 ConvProxy *predecessorProxy = teToProxy[predecessor];
604 if (predecessorProxy != nullptr)
605 { // because we skip some
606 proxy->parents.insert(predecessorProxy);
607 predecessorProxy->children.insert(proxy);
608 }
609 }
610 }
611
613 {
614 int counter = -1;
615 for (auto proxy : convProxies)
616 {
617 counter++;
618 ATH_MSG_DEBUG("Proxy " << counter << " " << proxy->description() << "ptr " << proxy);
619 for (auto p : proxy->children)
620 ATH_MSG_DEBUG("Child ptr " << p);
621 for (auto p : proxy->parents)
622 ATH_MSG_DEBUG("Parent ptr " << p);
623
624 for (auto p : proxy->parents)
625 {
626 for (auto pp : p->parents)
627 {
628 if (pp == proxy)
629 {
630 ATH_MSG_WARNING("Weird, proxy is in parents list of parents");
631 }
632 }
633 }
634 for (auto c : proxy->children)
635 {
636 for (auto cc : c->children)
637 {
638 if (cc == proxy)
639 {
640 ATH_MSG_WARNING("Weird, proxy is in children list of children");
641 }
642 }
643 }
644 }
645 }
646
647 ATH_MSG_DEBUG("Created " << convProxies.size() << " proxy objects");
648 return StatusCode::SUCCESS;
649}
650
651
653 std::function<bool(const ConvProxy*)> selector,
654 const std::vector<std::function<void(const ConvProxy*)>>& printers) const {
655 ATH_MSG_DEBUG("Printing proxies");
656 ATH_MSG_DEBUG("" );
657 for ( auto p: proxies) {
658 if ( selector(p) ){
659 ATH_MSG_DEBUG("Proxy " << p->description() );
660 for (auto& printer: printers) {
661 printer(p);
662 }
663 ATH_MSG_DEBUG("" );
664 }
665 }
666}
667
669{
670
671 for (auto &ptrConvProxy : convProxies)
672 {
673 auto teId = ptrConvProxy->te->getId();
674 bool teActive = ptrConvProxy->te->getActiveState();
675 auto iter = allTEs.find(teId);
676 if (iter != allTEs.end())
677 {
678 ptrConvProxy->runChains.insert(iter->second.begin(), iter->second.end());
679 if (teActive)
680 {
681 ptrConvProxy->passChains.insert(iter->second.begin(), iter->second.end());
682 }
683 }
684
685 for (auto &objTeIdToChain : allTEs)
686 {
687 if (teId == objTeIdToChain.first)
688 {
689 for (auto &chainId : objTeIdToChain.second)
690 {
691 (ptrConvProxy->runChains).insert(chainId);
692 }
693 break;
694 }
695 }
696 }
697 return StatusCode::SUCCESS;
698}
699
701{
702 // propagate up (towards L1) chain IDs if they are not in proxies
703 // technically each proxy looks at the children proxies and inserts from it all unseen chains
704 // procedure is repeated until, no single proxy needs an update (tedious - we may be smarter in future)
705
706 while (true)
707 {
708 size_t numberOfUpdates = 0;
709 for (auto p : convProxies)
710 {
711 for (auto child : p->children)
712 {
713 size_t startSize = p->runChains.size();
714 p->runChains.insert(std::begin(child->runChains), std::end(child->runChains));
715
716 if (startSize != p->runChains.size())
717 { // some chain needed to be inserted
718 numberOfUpdates++;
719 // if update was need, it means set of chains that passed need update as well
720 p->passChains.insert(std::begin(child->runChains), std::end(child->runChains));
721 }
722 }
723 }
724 ATH_MSG_DEBUG("Needed to propagate chains from " << numberOfUpdates << " child(ren)");
725 if (numberOfUpdates == 0)
726 {
727 break;
728 }
729 }
730 return StatusCode::SUCCESS;
731}
732
734{
735 // remove proxies that have no chains
736 for (auto i = std::begin(convProxies); i != std::end(convProxies);)
737 {
738 if ((*i)->runChains.empty())
739 {
740 ConvProxy *toDel = *i;
741 // remove it from parents/children
742 for (auto parent : toDel->parents)
743 {
744 parent->children.erase(toDel);
745 }
746 for (auto child : toDel->children)
747 {
748 child->parents.erase(toDel);
749 }
750 delete toDel;
751 i = convProxies.erase(i);
752 }
753 else
754 {
755 ++i;
756 }
757 }
758 ATH_MSG_DEBUG("After eliminating proxies not associated to chainsof intereset left with " << convProxies.size());
759 return StatusCode::SUCCESS;
760}
761
763{
764
765 ATH_CHECK(collapseFeaturesProxies(convProxies, run2Nav));
768 {
769 ATH_CHECK(allProxiesHaveChain(convProxies));
770 ATH_CHECK(allProxiesConnected(convProxies));
771 }
772 ATH_MSG_DEBUG("Compression done");
773
774 return StatusCode::SUCCESS;
775}
776
777template <typename MAP>
778StatusCode Run2ToRun3TrigNavConverterV2::collapseProxies(ConvProxySet_t &convProxies, MAP &keyToProxyMap) const
779{
780 // collapse proxies based on the mapping in the map argument(generic) and clean proxiesSet
781 std::vector<ConvProxy *> todelete;
782 for (auto &[key, proxies] : keyToProxyMap)
783 {
784 if (proxies.size() > 1)
785 {
786 ATH_MSG_DEBUG("Merging " << proxies.size() << " similar proxies");
787 for (auto p : proxies)
788 {
789 if (p->mergeAllowed(*proxies.begin()))
790 {
791 (*proxies.begin())->merge(p);
792 todelete.push_back(p);
793 }
794 // TODO consider scanning proxies another time if merge is not allowed, it may be allowed with other proxies here
795 }
796 }
797 }
798 for (auto proxy : todelete)
799 {
800 convProxies.erase(proxy);
801 delete proxy;
802 }
803 // remove from proxies set all elements that are now unassociated (remember to delete after)
804 return StatusCode::SUCCESS;
805}
806
808{
809
810 const size_t beforeCount = convProxies.size();
811 std::map<uint64_t, ConvProxySet_t> feaToProxyMap;
812 for (auto proxy : convProxies)
813 {
814 proxy->feaHash = feaToHash(proxy->te->getFeatureAccessHelpers(), proxy->te, run2Nav);
815 if (proxy->feaHash != ConvProxy::MissingFEA)
816 feaToProxyMap[proxy->feaHash].insert(proxy);
817
818 ATH_MSG_VERBOSE("TE " << TrigConf::HLTUtils::hash2string(proxy->te->getId()) << " FEA hash " << proxy->feaHash);
819 for (const HLT::TriggerElement::FeatureAccessHelper& fea : proxy->te->getFeatureAccessHelpers())
820 {
821 ATH_MSG_VERBOSE("FEA: " << fea);
822 }
823 }
824
825 for (auto [feaHash, proxies] : feaToProxyMap)
826 {
827 auto first = *proxies.begin();
828 for (auto p : proxies)
829 {
830 if (filterFEAs(first->te->getFeatureAccessHelpers(), run2Nav) !=
831 filterFEAs(p->te->getFeatureAccessHelpers(), run2Nav))
832 {
833 ATH_MSG_ERROR("Proxies grouped by FEA hash have actually distinct features (specific FEAs are different)");
834 for (auto id: p->passChains ) ATH_MSG_ERROR("... chain id for this proxy " << id);
835 ATH_MSG_ERROR(".... TE id of this proxy: " << TrigConf::HLTUtils::hash2string(p->te->getId()));
836 for ( auto fea: first->te->getFeatureAccessHelpers() ) {
837 ATH_MSG_ERROR("FEA1 " << fea);
838 }
839 for ( auto fea: p->te->getFeatureAccessHelpers() ) {
840 ATH_MSG_ERROR("FEA2 " << fea);
841 }
842
843 return StatusCode::FAILURE;
844 }
845 }
846 }
847
848
849 ATH_CHECK(collapseProxies(convProxies, feaToProxyMap));
850 ATH_MSG_DEBUG("Proxies with features collapsing reduces size from " << beforeCount << " to " << convProxies.size());
851
852 return StatusCode::SUCCESS;
853}
854
856{
857 // merge proxies bases on the parent child relation (this has to run after feature based collapsing)
858 struct ParentChildCharacteristics
859 {
860 ConvProxy *parent = nullptr;
861 ConvProxy *child = nullptr;
862 size_t distanceFromParent = 0;
863 bool operator<(const ParentChildCharacteristics &rhs) const
864 {
865 if (parent != rhs.parent)
866 return parent < rhs.parent;
867 if (child != rhs.child)
868 return child < rhs.child;
869 return distanceFromParent < rhs.distanceFromParent;
870 }
871 };
872 const size_t beforeCount = convProxies.size();
873 std::map<ParentChildCharacteristics, ConvProxySet_t> groupedProxies;
874 for (auto proxy : convProxies)
875 {
876 if (proxy->feaHash == ConvProxy::MissingFEA)
877 {
878 ATH_MSG_VERBOSE("Featureless proxy to deal with: " << proxy->description());
879 /* the canonical case
880 merged parent
881 / | | \
882 C1 C2 C3 C4 <-- proxies to merge
883 \ | | /
884 merged child
885 */
886 auto hasSomeFeatures = [](const ConvProxy* p){ return p->feaHash != ConvProxy::MissingFEA; };
887 if (proxy->children.size() == 1 and
888 std::all_of(proxy->children.begin(), proxy->children.end(), hasSomeFeatures ) and
889 proxy->parents.size() == 1 and
890 std::all_of(proxy->parents.begin(), proxy->parents.end(), hasSomeFeatures )
891 )
892 {
893 ATH_MSG_VERBOSE("Proxy to possibly merge: " << proxy->description());
894 groupedProxies[{*(proxy->parents.begin()), *(proxy->children.begin()), 0}].insert(proxy);
895 // TODO expand it to cover longer featureless sequences
896 }
897 else
898 {
899 ATH_MSG_VERBOSE("Featureless proxy in noncanonical situation " << proxy->description());
900 ATH_MSG_VERBOSE("parents ");
901 for (auto pp : proxy->parents)
902 {
903 ATH_MSG_VERBOSE(pp->description());
904 }
905 ATH_MSG_VERBOSE("children ");
906 for (auto cp : proxy->children)
907 {
908 ATH_MSG_VERBOSE(cp->description());
909 }
910 }
911 }
912 }
913
914 ATH_CHECK(collapseProxies(convProxies, groupedProxies));
915 ATH_MSG_DEBUG("Proxies without features collapsing reduces size from " << beforeCount << " to " << convProxies.size());
916 return StatusCode::SUCCESS;
917}
918
920{
921 for (auto i = std::begin(convProxies); i != std::end(convProxies);)
922 {
923 if ((*i)->parents.size() > 1)
924 {
925 ConvProxy *toDel = *i;
926 // remove it from parents/children
927 for (auto parent : toDel->parents)
928 {
929 parent->children.erase(toDel);
930 }
931 for (auto child : toDel->children)
932 {
933 child->parents.erase(toDel);
934 }
935 delete toDel;
936 i = convProxies.erase(i);
937 }
938 else
939 {
940 ++i;
941 }
942 }
943 return StatusCode::SUCCESS;
944}
945
947{
948 // from all FEAs of the associated TE pick those objects that are to be linked
949 for (auto &proxy : convProxies)
950 {
951 if (proxy->te != nullptr)
952 {
953 // Determine which particle type is expected based on TE name
954 // This ensures Run3 retrieves the same object types as Run2
955 std::string teName = TrigConf::HLTUtils::hash2string(proxy->te->getId());
956 CLID expectedCLID = getExpectedParticleCLID(teName);
957
958 ATH_MSG_VERBOSE("TE " << teName << " expects CLID " << expectedCLID);
959
960 for (const HLT::TriggerElement::FeatureAccessHelper& helper : proxy->te->getFeatureAccessHelpers())
961 {
962 auto [sgKey, sgCLID, sgName] = getSgKey(run2Nav, helper);
963 if (sgKey != 0)
964 {
965 if (feaToSave(helper, sgName))
966 {
967 // If we have a specific expected CLID, only save features matching that type
968 if (expectedCLID != 0 && sgCLID != expectedCLID)
969 {
970 ATH_MSG_VERBOSE("Skipping feature with CLID " << sgCLID << " (name: " << sgName
971 << ") for TE " << teName << " because expected CLID is " << expectedCLID);
972 continue;
973 }
974 proxy->features.push_back(helper);
975 ATH_MSG_VERBOSE("Added feature with CLID " << sgCLID << " (name: " << sgName << ") for TE " << teName);
976 }
977 }
978 }
979 }
980 }
981
982 return StatusCode::SUCCESS;
983}
984
986{
987
988 // ordered_sorter
989 auto ordered_sorter = [&setRoiName = std::as_const(m_setRoiName)](const std::string &left, const std::string &right) -> bool
990 {
991 return std::find(cbegin(setRoiName), cend(setRoiName), left) < std::find(cbegin(setRoiName), cend(setRoiName), right);
992 };
993
994 std::map<std::string, HLT::TriggerElement::FeatureAccessHelper, decltype(ordered_sorter)> mp(ordered_sorter);
995
996 for (auto &proxy : convProxies)
997 {
998 // TODO need check & handling of case when there is more RoIs, now overwriting
999 if (HLT::TrigNavStructure::getRoINodes(proxy->te).size() > 1)
1000 ATH_MSG_DEBUG("Several RoIs pointing to a proxy, taking latest one for now");
1001
1002 mp.clear();
1003
1004 for (const HLT::TriggerElement::FeatureAccessHelper& helper : proxy->te->getFeatureAccessHelpers())
1005 {
1006 auto [sgKey, sgCLID, sgName] = getSgKey(run2Nav, helper);
1007 if (std::find(m_setRoiName.begin(), m_setRoiName.end(), sgName) == m_setRoiName.end())
1008 {
1009 // do not filter continue;
1010 continue;
1011 }
1012 mp[sgName] = helper;
1013 }
1014
1015 std::transform(cbegin(mp), cend(mp), back_inserter(proxy->rois),
1016 [](const std::map<std::string, HLT::TriggerElement::FeatureAccessHelper>::value_type &p)
1017 { return p.second; });
1018 }
1019
1020 // roiPropagator
1021 std::set<const ConvProxy*> visited;
1022 std::function<void(std::set<ConvProxy *> &, const std::vector<HLT::TriggerElement::FeatureAccessHelper> &)>
1023 roiPropagator = [&](std::set<ConvProxy *> &convProxyChildren, const std::vector<HLT::TriggerElement::FeatureAccessHelper> &roiParent)
1024 {
1025 for (auto &proxyChild : convProxyChildren)
1026 {
1027 if ( visited.count(proxyChild) == 1 ) {
1028 continue;
1029 }
1030 visited.insert(proxyChild);
1031 if (proxyChild->rois.empty())
1032 { // no roi update, copy from parent
1033 proxyChild->rois = roiParent;
1034 if (proxyChild->children.empty() == false)
1035 {
1036 roiPropagator(proxyChild->children, roiParent);
1037 }
1038 }
1039 }
1040 };
1041
1042 for (auto &proxy : convProxies)
1043 {
1044 roiPropagator(proxy->children, proxy->rois);
1045 }
1046
1047 return StatusCode::SUCCESS;
1048}
1049
1051{
1052 for (auto &proxy : convProxies)
1053 {
1054 for (const HLT::TriggerElement::FeatureAccessHelper& helper : proxy->te->getFeatureAccessHelpers())
1055 {
1056 if (helper.getCLID() == m_TrackParticleContainerCLID || helper.getCLID() == m_TauTrackContainerCLID)
1057 {
1058 proxy->tracks.push_back(helper);
1059 }
1060 }
1061 }
1062
1063 return StatusCode::SUCCESS;
1064}
1065
1066StatusCode Run2ToRun3TrigNavConverterV2::createIMHNodes(ConvProxySet_t &convProxies, xAOD::TrigCompositeContainer &decisions, const EventContext &context) const
1067{
1068 for (auto &proxy : convProxies)
1069 {
1071 for (auto chainId : proxy->runChains)
1072 {
1073 TrigCompositeUtils::addDecisionID(chainId, proxy->imNode);
1074 }
1075 proxy->hNode.push_back(TrigCompositeUtils::newDecisionIn(&decisions, TrigCompositeUtils::hypoAlgNodeName())); // H
1076 for (auto chainId : proxy->passChains)
1077 {
1078 TrigCompositeUtils::addDecisionID(chainId, proxy->hNode.back());
1079 }
1080
1081 TrigCompositeUtils::linkToPrevious(proxy->hNode.front(), proxy->imNode, context); // H low IM up
1082 }
1083 // connecting current IM to all Hs in parent proxies
1084 for (auto &proxy : convProxies)
1085 {
1086 for (auto &parentProxy : proxy->parents)
1087 {
1088 TrigCompositeUtils::linkToPrevious(proxy->imNode, parentProxy->hNode.front(), context); // IM low H up (in parent)
1089 }
1090 }
1091 ATH_MSG_DEBUG("IM & H nodes made, output nav elements " << decisions.size());
1092 return StatusCode::SUCCESS;
1093}
1094
1096 const TEIdToChainsMap_t &terminalIds, const EventContext &context) const
1097{
1098 // make node & link it properly
1099 auto makeSingleSFNode = [&decisions, &context](auto lastDecisionNode, auto chainIds, TrigCompositeUtils::DecisionID idStore = 0)
1100 {
1101 auto sfNode = TrigCompositeUtils::newDecisionIn(&decisions);
1102 sfNode->setName("SF");
1103 TrigCompositeUtils::linkToPrevious(decisions.at(0), sfNode, context);
1104 TrigCompositeUtils::linkToPrevious(sfNode, lastDecisionNode, context);
1105 for (auto chainId : chainIds)
1106 {
1107 if (idStore == 0)
1108 {
1109 TrigCompositeUtils::addDecisionID(chainId, sfNode);
1110 TrigCompositeUtils::addDecisionID(chainId, decisions.at(0));
1111 }
1112 else if (chainId.numeric() == idStore)
1113 {
1114 TrigCompositeUtils::addDecisionID(chainId, sfNode);
1115 TrigCompositeUtils::addDecisionID(chainId, decisions.at(0));
1116 }
1117 }
1118 return sfNode;
1119 };
1120 auto makeSFNodes = [makeSingleSFNode](auto proxy, TrigCompositeUtils::DecisionID idToStore = 0)
1121 {
1122 if (proxy->hNode.empty())
1123 { // nothing has passed, so link to the IM node
1124 // TODO make sure it needs to be done like that
1125 makeSingleSFNode(proxy->imNode, proxy->runChains, idToStore);
1126 }
1127 else
1128 {
1129 // makeSFNode(proxy->hNode[0], TCU::decisionIDs(proxy->hNode[0])); // not using passChains as there may be additional filtering
1130 for (auto &hNode : proxy->hNode)
1131 {
1132 makeSingleSFNode(hNode, proxy->passChains, idToStore); // using passChains
1133 }
1134 }
1135 };
1136
1137 for (auto proxy : convProxies)
1138 {
1139 // associate terminal nodes to filter nodes,
1140 if (proxy->children.empty())
1141 { // the H modes are terminal
1142 makeSFNodes(proxy);
1143 }
1144 else
1145 {
1146 // likely need more iterations
1147 // nonterminal nodes that are nevertheless terminal for a given chain
1148 std::vector<TCU::DecisionID> toRetain;
1149 for (auto teId : proxy->teIDs)
1150 {
1151 auto whereInMap = terminalIds.find(teId);
1152 if (whereInMap != terminalIds.end())
1153 {
1154 toRetain.insert(toRetain.end(), whereInMap->second.begin(), whereInMap->second.end());
1155 }
1156 }
1157 for (auto chainIdstore : toRetain)
1158 {
1159 makeSFNodes(proxy, chainIdstore);
1160 }
1161 }
1162 }
1163 // associate all nodes designated as final one with the filter nodes
1164
1165 ATH_MSG_DEBUG("SF nodes made, output nav elements " << decisions.size());
1166 return StatusCode::SUCCESS;
1167}
1168
1170{
1171 // Check that only ChainIDs (not LegIDs) are present in the terminus "HLTPassRaw" node.
1172 // Check that only chains which pass the event are included.
1173 TCU::Decision* terminus = decisions.at(0);
1174 ATH_CHECK( terminus->name() == TCU::summaryPassNodeName() );
1175 TCU::DecisionIDContainer currentIDs;
1176 TCU::DecisionIDContainer filteredIDs;
1177 TCU::decisionIDs(terminus, currentIDs); // Extract, std::vector -> std::set
1178 for (const TCU::DecisionID id : currentIDs)
1179 {
1180 const TCU::DecisionID idToCheck = ( TCU::isLegId(id) ? TCU::getIDFromLeg( HLT::Identifier(id) ).numeric() : id );
1181 const std::string chainName = HLT::Identifier(idToCheck).name();
1182 // Sanity check
1183 if (!m_chainsToSave.empty())
1184 {
1185 if (std::find(m_chainsToSave.begin(), m_chainsToSave.end(), chainName) == m_chainsToSave.end())
1186 {
1187 ATH_MSG_ERROR("Navigation information for chain " << chainName << " in "
1188 << TCU::summaryPassNodeName() << " but this chain wasn't on the list of chains to save");
1189 return StatusCode::FAILURE;
1190 }
1191 }
1192 if (m_tdt->isPassed(chainName))
1193 {
1194 filteredIDs.insert(idToCheck);
1195 }
1196 }
1197 terminus->setDecisions( std::vector<TCU::DecisionID>() ); // decisions.clear(), but via the xAOD setter function
1198 TCU::insertDecisionIDs(filteredIDs, terminus); // Insert, std::set -> std::vector
1199 ATH_MSG_VERBOSE("After filtering out leg IDs and checking isPassed, "
1200 "the terminus node goes from " << currentIDs.size() << " to " << filteredIDs.size() << " chain IDs.");
1201 if (msgLvl(MSG::VERBOSE))
1202 {
1203 for (const TCU::DecisionID id : filteredIDs)
1204 {
1205 ATH_MSG_VERBOSE(" -- Retained passing ID: " << HLT::Identifier(id));
1206 }
1207 }
1208 return StatusCode::SUCCESS;
1209}
1210
1212 const EventContext &context) const
1213{
1214
1215 auto makeL1Node = [&decisions, &context](auto firstDecisionNode, auto chainIds)
1216 {
1217 auto L1Node = TrigCompositeUtils::newDecisionIn(&decisions);
1218 L1Node->setName(TrigCompositeUtils::hltSeedingNodeName()); // L1
1219 for (auto chainId : chainIds)
1220 {
1221 TrigCompositeUtils::addDecisionID(chainId, L1Node);
1222 }
1223 TrigCompositeUtils::linkToPrevious(firstDecisionNode, L1Node, context); // IM -> L1
1224
1225 return L1Node;
1226 };
1227
1228 for (auto &proxy : convProxies)
1229 {
1230 // associate initial node to filter nodes,
1231 if (proxy->parents.empty())
1232 { // the IM node is initial
1233 proxy->l1Node = makeL1Node(proxy->imNode, TCU::decisionIDs(proxy->imNode)); // not using passChains as there may be additional filtering
1234 }
1235 }
1236
1237 ATH_MSG_DEBUG("L1 nodes made, output nav elements ");
1238 return StatusCode::SUCCESS;
1239}
1240
1242{
1243 size_t feaCount{0};
1244 if (proxy.features.empty())
1245 { // no features
1246 ++feaCount;
1247 }
1248 for (const auto &fea : proxy.features)
1249 {
1250 if (fea.getIndex().objectsBegin() == fea.getIndex().objectsEnd())
1251 {
1252 ++feaCount;
1253 }
1254 for (auto n = fea.getIndex().objectsBegin(); n < fea.getIndex().objectsEnd(); ++n)
1255 {
1256 ++feaCount;
1257 }
1258 }
1259 // 1 means a deafult H node created is enough, no need to expand H nodes
1260 return feaCount;
1261}
1262
1263StatusCode Run2ToRun3TrigNavConverterV2::linkFeaNode(ConvProxySet_t &convProxies, xAOD::TrigCompositeContainer &decisions, const HLT::TrigNavStructure &run2Nav, const EventContext &context) const
1264{
1265 // from all FEAs of the associated TE pick those objects that are to be linked
1266 for (const auto &proxy : convProxies)
1267 {
1268 auto [bestFeaIdx, bestObjIdx] = getHighestPtObject(*proxy, run2Nav);
1269
1270 auto feaN = getFeaSize(*proxy);
1271 if (feaN > 1)
1272 { // expand for more H nodes and connect them
1273 while (--feaN)
1274 {
1275 proxy->hNode.push_back(TrigCompositeUtils::newDecisionIn(&decisions, TrigCompositeUtils::hypoAlgNodeName())); // H
1276 for (auto chainId : proxy->passChains) // adding hash values of active chains to expanded H nodes
1277 {
1278 TrigCompositeUtils::addDecisionID(chainId, proxy->hNode.back());
1279 }
1280 // connecting to upeer IM node
1281 TrigCompositeUtils::linkToPrevious(proxy->hNode.back(), proxy->imNode, context); // H low IM up
1282 // connecting created H to IM in children proxies
1283 for (auto &childProxy : proxy->children)
1284 {
1285 TrigCompositeUtils::linkToPrevious(childProxy->imNode, proxy->hNode.back(), context); // IM child H up (just created))
1286 }
1287 }
1288 }
1289
1290 if (proxy->features.empty())
1291 { // no features attached, self link
1293 proxy->hNode.front()->setObjectLink<xAOD::TrigCompositeContainer>(TrigCompositeUtils::featureString(), linkToSelf);
1294 }
1295
1296 auto hNodeIter = proxy->hNode.begin();
1297 for (std::size_t feaIdx = 0; feaIdx < proxy->features.size(); ++feaIdx)
1298 {
1299 auto &fea = proxy->features[feaIdx];
1300 auto [sgKey, sgCLID, sgName] = getSgKey(run2Nav, fea);
1301 // link to itself when lined collection has size 0
1302 if (fea.getIndex().objectsBegin() == fea.getIndex().objectsEnd())
1303 {
1305 (*hNodeIter)->setObjectLink<xAOD::TrigCompositeContainer>(TrigCompositeUtils::featureString(), linkToSelf);
1306 ++hNodeIter;
1307 }
1308 for (auto n = fea.getIndex().objectsBegin(); n < fea.getIndex().objectsEnd(); ++n)
1309 {
1310 // connecting feature or subfeature
1311 const std::string& linkName = (feaIdx == bestFeaIdx && n == bestObjIdx) ?
1312 TrigCompositeUtils::featureString() : "subfeature";
1313 (*hNodeIter)->typelessSetObjectLink(linkName, sgKey, sgCLID, n, n + 1);
1314 ++hNodeIter;
1315 }
1316 }
1317 }
1318
1319 return StatusCode::SUCCESS;
1320}
1321
1323{
1324 // from all Rois of the associated TE pick those objects that are to be linked
1325 for (auto &proxy : convProxies)
1326 {
1327 for (auto &roi : proxy->rois)
1328 {
1329 auto [sgKey, sgCLID, sgName] = getSgKey(run2Nav, roi);
1330 if (proxy->l1Node)
1331 {
1332 proxy->l1Node->typelessSetObjectLink(TrigCompositeUtils::initialRoIString(), sgKey, sgCLID, roi.getIndex().objectsBegin());
1333 }
1334 if (proxy->rois.empty() == false)
1335 {
1336 proxy->imNode->typelessSetObjectLink(TrigCompositeUtils::roiString(), sgKey, sgCLID, roi.getIndex().objectsBegin());
1337 }
1338 }
1339 }
1340
1341 return StatusCode::SUCCESS;
1342}
1343
1345{
1346 for (auto &proxy : convProxies)
1347 {
1348 for (auto &trk : proxy->tracks)
1349 {
1350 if (proxy->imNode->hasObjectLink(TrigCompositeUtils::roiString()))
1351 {
1352 try
1353 {
1355 if (ROIElementLink.isValid())
1356 {
1357 static const SG::Decorator<ElementLink<TrigRoiDescriptorCollection>> viewBookkeeper("viewIndex");
1358 auto [sgKey, sgCLID, sgName] = getSgKey(run2Nav, trk);
1359 if (sgCLID == m_TrackParticleContainerCLID || sgCLID == m_TauTrackContainerCLID)
1360 {
1361 const char *tName = sgCLID == m_TrackParticleContainerCLID ? "TEMP_TRACKS" : "TEMP_TAU_TRACKS";
1362 auto d = std::make_unique<TrigCompositeUtils::Decision>();
1363 d->makePrivateStore();
1364 d->typelessSetObjectLink(tName, sgKey, sgCLID, trk.getIndex().objectsBegin());
1365 if (sgCLID == m_TrackParticleContainerCLID)
1366 {
1367 for (const ElementLink<xAOD::TrackParticleContainer> &track : d->objectCollectionLinks<xAOD::TrackParticleContainer>(tName))
1368 {
1369 if (track.isValid())
1370 {
1371 const xAOD::TrackParticle *t = *track;
1372 viewBookkeeper(*t) = ROIElementLink;
1373 }
1374 }
1375 }
1376 if (m_includeTauTrackFeatures == false && sgCLID == m_TauTrackContainerCLID)
1377 {
1378 for (const ElementLink<xAOD::TauTrackContainer> &track : d->objectCollectionLinks<xAOD::TauTrackContainer>(tName))
1379 {
1380 if (track.isValid())
1381 {
1382 const xAOD::TauTrack_v1 *t = *track;
1383 viewBookkeeper(*t) = ROIElementLink;
1384 }
1385 }
1386 }
1387 }
1388 }
1389 } catch (SG::ExcBadForwardLink&) {
1390 ATH_MSG_WARNING("Unable to create an ElementLink into a container with no entries");
1391 }
1392 }
1393 }
1394 }
1395
1396 return StatusCode::SUCCESS;
1397}
1398
1399// does not need to be a method, so kept as local
1401{
1402 CLID thePassBitsCLID = ClassID_traits<xAOD::TrigPassBits>::ID();
1404
1405 return fea.getCLID() == thePassBitsCLID or fea.getCLID() == thePassBitsContCLID;
1406}
1407
1408std::vector<HLT::TriggerElement::FeatureAccessHelper> Run2ToRun3TrigNavConverterV2::filterFEAs(const std::vector<HLT::TriggerElement::FeatureAccessHelper> &feaVector, const HLT::TrigNavStructure &navigationDecoder) const {
1409 std::vector<HLT::TriggerElement::FeatureAccessHelper> out;
1410 for (auto fea : feaVector)
1411 {
1412 if (feaToSkip(fea))
1413 {
1414 ATH_MSG_VERBOSE("Skipping in FEA hash calculation");
1415 continue;
1416 }
1417
1418 auto [sgKey, sgCLID, sgName] = getSgKey(navigationDecoder, fea);
1419
1420 if (sgKey == 0)
1421 {
1422 ATH_MSG_VERBOSE("Skipping unrecorded (missing in SG) FEA hash calculation - name in SG: " << sgName << " FEA " << fea);
1423 continue;
1424 }
1425 out.push_back(fea);
1426 }
1427 return out;
1428}
1429
1430uint64_t Run2ToRun3TrigNavConverterV2::feaToHash(const std::vector<HLT::TriggerElement::FeatureAccessHelper> &feaVector, const HLT::TriggerElement *te_ptr, const HLT::TrigNavStructure &navigationDecoder) const
1431{
1432 // FEA vectors hashing
1433 // Filter by expected particle type based on TE name to ensure correct feature type
1434 std::string teName = TrigConf::HLTUtils::hash2string(te_ptr->getId());
1435 CLID expectedCLID = getExpectedParticleCLID(teName);
1436
1437 ATH_MSG_VERBOSE("Calculating FEA hash for TE " << teName << " expecting CLID " << expectedCLID);
1438 uint64_t hash = 0;
1439 for (auto fea : filterFEAs(feaVector, navigationDecoder))
1440 {
1441 const auto & [sgKey, sgCLID, sgName] = getSgKey(navigationDecoder, fea);
1442
1443 // Apply TE-based filtering during hash calculation to prevent wrong merges
1444 if (expectedCLID != 0 && sgCLID != expectedCLID)
1445 {
1446 ATH_MSG_VERBOSE("Skipping FEA with CLID " << sgCLID << " for TE " << teName
1447 << " (expected " << expectedCLID << ")");
1448 continue;
1449 }
1450
1451 ATH_MSG_VERBOSE("Including FEA in hash CLID: " << fea.getCLID() << " te Id: " << te_ptr->getId());
1452 boost::hash_combine(hash, fea.getCLID());
1453 boost::hash_combine(hash, fea.getIndex().subTypeIndex());
1454 boost::hash_combine(hash, fea.getIndex().objectsBegin());
1455 boost::hash_combine(hash, fea.getIndex().objectsEnd());
1456 }
1457 // Include the originating TE identifier and pointer to ensure that
1458 // navigation elements stemming from different Trigger Elements do not
1459 // collapse into a single proxy even if their features are otherwise
1460 // identical. The TE ID alone is not sufficient, as multiple clones of the
1461 // same TE share the ID, so we also add the pointer value to the hash.
1462 boost::hash_combine(hash, te_ptr->getId());
1463 boost::hash_combine(hash, reinterpret_cast<std::uintptr_t>(te_ptr));
1464 ATH_MSG_VERBOSE("Obtained FEA hash " << hash);
1465 return hash;
1466}
1467
1469{
1470 auto iter = m_collectionsToSaveDecoded.find(fea.getCLID());
1471 if (iter != m_collectionsToSaveDecoded.end())
1472 {
1473 if ( iter->second.empty() )
1474 return true; // feature accepted for saving
1475 ATH_MSG_DEBUG("fea to save CLID: " << fea.getCLID() << ", sgName: " << sgName << " " <<iter->second.size() << " " << iter->second.empty() );
1476 return iter->second.contains(sgName);
1477 }
1478
1479 return false;
1480}
1481
1482
1483
1485{
1486 auto [sgKey, sgCLID, sgName] = getSgKey(run2Nav, roi);
1487 if (std::find(m_setRoiName.begin(), m_setRoiName.end(), sgName) != m_setRoiName.end())
1488 {
1489 return true;
1490 }
1491
1492 return false;
1493}
1494
1496{
1497 for (auto p : proxies)
1498 {
1499 if (p->runChains.empty())
1500 {
1501 ATH_MSG_ERROR("Proxy with no chains");
1502 return StatusCode::FAILURE;
1503 }
1504 }
1505 ATH_MSG_DEBUG("CHECK OK, no proxies w/o a chain");
1506 return StatusCode::SUCCESS;
1507}
1508
1510{
1511 for (auto p : proxies)
1512 {
1513 if (p->children.empty() and p->parents.empty() and not p->runChains.empty())
1514 {
1515 ATH_MSG_ERROR("Orphanted proxy N chains run:" << p->runChains.size());
1516 return StatusCode::FAILURE;
1517 }
1518 }
1519 ATH_MSG_DEBUG("CHECK OK, no orphanted proxies");
1520 return StatusCode::SUCCESS;
1521}
1522
1524{
1525 ATH_MSG_DEBUG("CHECK OK, no excessive number of H nodes per proxy");
1526 return StatusCode::SUCCESS;
1527}
1528
1530{
1531 // build map of all links to H nodes from IMs and FS
1532 std::set<const TrigCompositeUtils::Decision *> linkedHNodes;
1533 for (auto d : decisions)
1534 {
1535 if (d->name() == "IM" or d->name() == "FS")
1536 {
1537 for (auto el : TCU::getLinkToPrevious(d))
1538 {
1539 linkedHNodes.insert(*el); // dereferences to bare pointer
1540 }
1541 }
1542 }
1543 for (auto d : decisions)
1544 {
1545 if (d->name() == "H")
1546 {
1547 if (linkedHNodes.count(d) == 0)
1548 {
1549 ATH_MSG_ERROR("Orphaned H node");
1550 return StatusCode::FAILURE;
1551 }
1552 }
1553 }
1554 ATH_MSG_DEBUG("CHECK OK, all H modes are connected");
1555
1556 return StatusCode::SUCCESS;
1557}
1558
1559std::tuple<uint32_t, CLID, std::string> Run2ToRun3TrigNavConverterV2::getSgKey(const HLT::TrigNavStructure &navigationDecoder, const HLT::TriggerElement::FeatureAccessHelper &helper) const
1560{
1561 const std::string hltLabel = navigationDecoder.label(helper.getCLID(), helper.getIndex().subTypeIndex());
1562
1563 const CLID saveCLID = [&](const CLID &clid)
1564 {
1565 if (clid == m_roIDescriptorCLID)
1567 if (clid == m_TrigEMClusterCLID)
1569 if (clid == m_TrigRingerRingsCLID)
1571 return clid;
1572 }(helper.getCLID());
1573
1574 std::string type_name;
1575 if (m_clidSvc->getTypeNameOfID(saveCLID, type_name).isFailure())
1576 {
1577 return {0, 0, ""};
1578 }
1579
1580 const auto sgStringKey = HLTNavDetails::formatSGkey("HLT", type_name, hltLabel);
1581 const bool isAvailable = evtStore()->contains(saveCLID, sgStringKey);
1582 ATH_MSG_DEBUG(" Objects presence " << helper << " " << sgStringKey << (isAvailable ? " present" : " absent"));
1583 if (!isAvailable)
1584 {
1585 return {0, saveCLID, ""};
1586 }
1587
1588 return {evtStore()->stringToKey(sgStringKey, saveCLID), saveCLID, hltLabel}; // sgKey, sgCLID, sgName
1589}
1590
1591std::pair<std::size_t, std::size_t> Run2ToRun3TrigNavConverterV2::getHighestPtObject(
1592 const ConvProxy& proxy, const HLT::TrigNavStructure& run2Nav) const
1593{
1594 std::size_t bestFea = std::numeric_limits<std::size_t>::max();
1595 std::size_t bestObj = 0;
1596 float bestPt = -1.0;
1597
1598 for (std::size_t i = 0; i < proxy.features.size(); ++i) {
1599 const auto& fea = proxy.features[i];
1600 auto [sgKey, sgCLID, sgName] = getSgKey(run2Nav, fea);
1601 if (!feaToSave(fea, sgName)) {
1602 continue;
1603 }
1604 if (sgKey == 0) continue;
1605 const std::string* keyStr = evtStore()->keyToString(sgKey, sgCLID);
1606 if (!keyStr) continue;
1607 const xAOD::IParticleContainer* cont = nullptr;
1608 if (evtStore()->retrieve(cont, *keyStr).isFailure()) continue;
1609 for (auto n = fea.getIndex().objectsBegin(); n < fea.getIndex().objectsEnd(); ++n) {
1610 if (n >= cont->size()) continue;
1611 const xAOD::IParticle* p = (*cont)[n];
1612 if (!p) continue;
1613 if (p->pt() > bestPt) {
1614 bestPt = p->pt();
1615 bestFea = i;
1616 bestObj = n;
1617 }
1618 }
1619 }
1620 if (bestFea == std::numeric_limits<std::size_t>::max()) {
1621 for (std::size_t i = 0; i < proxy.features.size(); ++i) {
1622 auto [sgKey, sgCLID, sgName] = getSgKey(run2Nav, proxy.features[i]);
1623 if (!feaToSave(proxy.features[i], sgName)) continue;
1624 bestFea = i;
1625 bestObj = proxy.features[i].getIndex().objectsBegin();
1626 break;
1627 }
1628 }
1629 return {bestFea, bestObj};
1630}
1631
1633{
1634 // Determine which particle type is expected based on TE name
1635 // This mimics the logic from IParticleRetrievalTool::getEGammaTEType()
1636 // to ensure Run3 retrieves the same object types as Run2
1637
1638 // For egamma TEs, check for specific patterns
1639 if (teName.find("etcut") != std::string::npos &&
1640 teName.find("trkcut") == std::string::npos) {
1641 // etcut chains (without trkcut) use CaloCluster
1643 }
1644 else if (teName.rfind("EF_e", 0) == 0) {
1645 // TE name starts with "EF_e" -> Electron
1647 }
1648 else if (teName.rfind("EF_g", 0) == 0) {
1649 // TE name starts with "EF_g" -> Photon
1650 return m_PhotonContainerCLID;
1651 }
1652 else if (teName.rfind("EF_mu", 0) == 0 || teName.find("_mu") != std::string::npos) {
1653 // Muon TEs
1654 return m_MuonContainerCLID;
1655 }
1656 else if (teName.rfind("EF_tau", 0) == 0 || teName.find("_tau") != std::string::npos) {
1657 // Tau TEs
1658 return m_TauJetContainerCLID;
1659 }
1660
1661 // For non-physics TEs or TEs where we don't have a specific expectation,
1662 // return 0 to indicate all features should be saved
1663 return 0;
1664}
#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)
a traits class that associates a CLID to a type T It also detects whether T inherits from Gaudi DataO...
bool operator<(const DataVector< T > &a, const DataVector< T > &b)
Vector ordering relation.
uint32_t CLID
The Class ID type.
bool feaToSkip(const HLT::TriggerElement::FeatureAccessHelper &fea)
std::map< HLT::te_id_type, std::set< HLT::Identifier > > TEIdToChainsMap_t
std::set< ConvProxy * > ConvProxySet_t
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
size_type size() const noexcept
Returns the number of elements in the collection.
TrigCompositeUtils::DecisionID numeric() const
numeric ID
std::string name() const
reports human redable name
virtual bool deserialize(const std::vector< uint32_t > &input)
static bool isInitialNode(const TriggerElement *te)
queries if node is an initial one
std::vector< TriggerElement * > & getAllTEs()
access needed by slimming tools.
static const std::vector< TriggerElement * > & getRoINodes(const TriggerElement *somenode)
gets all RoI type nodes seeding indirectly this TriggerElement
static const std::vector< TriggerElement * > & getDirectPredecessors(const TriggerElement *te)
returns list of direct predecessors (nodes seeding me)
std::string label(class_id_type clid, const index_or_label_type &sti_or_label) const
the FeatureAccessHelper is a class used to keep track of features attached to this TE.
TriggerElement is the basic ingreedient of the interface between HLT algorithms and the navigation It...
StatusCode createIMHNodes(ConvProxySet_t &, xAOD::TrigCompositeContainer &, const EventContext &) const
StatusCode linkRoiNode(ConvProxySet_t &convProxies, const HLT::TrigNavStructure &run2Nav) const
Gaudi::Property< std::vector< std::string > > m_chainsToSave
std::function< void(const ConvProxy *)> m_teIDPrinter
PublicToolHandle< Trig::TrigDecisionTool > m_tdt
StatusCode extractTECtoChainMapping(TEIdToChainsMap_t &allTES, TEIdToChainsMap_t &finalTEs) const
Gaudi::Property< std::vector< std::string > > m_roisToSave
StatusCode collapseFeaturesProxies(ConvProxySet_t &convProxies, const HLT::TrigNavStructure &run2Nav) const
virtual StatusCode execute(const EventContext &context) const override
ServiceHandle< IClassIDSvc > m_clidSvc
StatusCode cureUnassociatedProxies(ConvProxySet_t &) const
StatusCode updateTerminusNode(xAOD::TrigCompositeContainer &, const EventContext &context) const
StatusCode mirrorTEsStructure(ConvProxySet_t &, const HLT::TrigNavStructure &run2Nav) const
StatusCode createSFNodes(const ConvProxySet_t &, xAOD::TrigCompositeContainer &, const TEIdToChainsMap_t &finalTEs, const EventContext &context) const
StatusCode removeTopologicalProxies(ConvProxySet_t &) const
SG::ReadHandleKey< xAOD::TrigNavigation > m_trigNavKey
Run2ToRun3TrigNavConverterV2(const std::string &name, ISvcLocator *pSvcLocator)
StatusCode removeUnassociatedProxies(ConvProxySet_t &) const
StatusCode linkFeaNode(ConvProxySet_t &convProxies, xAOD::TrigCompositeContainer &, const HLT::TrigNavStructure &run2Nav, const EventContext &context) const
StatusCode associateChainsToProxies(ConvProxySet_t &, const TEIdToChainsMap_t &) const
CLID getExpectedParticleCLID(const std::string &teName) const
Helper function to determine expected particle CLID based on TE name Returns 0 if no specific type is...
StatusCode bjetMuChainConfigDecoder(TEIdToChainsMap_t &allTES, TEIdToChainsMap_t &finalTEs, const TrigConf::HLTChain *ptrChain) const
std::pair< std::size_t, std::size_t > getHighestPtObject(const ConvProxy &, const HLT::TrigNavStructure &) const
Return pair of indices (feature index in proxy->features vector, object index) identifying the highes...
StatusCode noUnconnectedHNodes(const xAOD::TrigCompositeContainer &) const
bool feaToSave(const HLT::TriggerElement::FeatureAccessHelper &fea, const std::string &sgName) const
uint64_t feaToHash(const std::vector< HLT::TriggerElement::FeatureAccessHelper > &feaVector, const HLT::TriggerElement *te_ptr, const HLT::TrigNavStructure &navigationDecoder) const
returns true if this particular feature is to be saved (linked)
size_t is2LegTopoChain(const TrigConf::HLTChain *ptrChain) const
bool roiToSave(const HLT::TrigNavStructure &run2Nav, const HLT::TriggerElement::FeatureAccessHelper &fea) const
StatusCode doCompression(ConvProxySet_t &convProxies, const HLT::TrigNavStructure &run2Nav) const
StatusCode linkTrkNode(ConvProxySet_t &convProxies, const HLT::TrigNavStructure &run2Nav) const
StatusCode numberOfHNodesPerProxyNotExcessive(const ConvProxySet_t &) const
void printProxies(const ConvProxySet_t &proxies, std::function< bool(const ConvProxy *)> selector=[](const ConvProxy *){return true;}, const std::vector< std::function< void(const ConvProxy *)> > &printers={}) const
StatusCode fillRelevantTracks(ConvProxySet_t &convProxies) const
Gaudi::Property< bool > m_includeTauTrackFeatures
std::tuple< uint32_t, CLID, std::string > getSgKey(const HLT::TrigNavStructure &navigationDecoder, const HLT::TriggerElement::FeatureAccessHelper &helper) const
StatusCode fillRelevantRois(ConvProxySet_t &convProxies, const HLT::TrigNavStructure &run2Nav) const
StatusCode allProxiesHaveChain(const ConvProxySet_t &) const
SG::WriteHandleKey< xAOD::TrigCompositeContainer > m_trigOutputNavKey
StatusCode createL1Nodes(const ConvProxySet_t &convProxies, xAOD::TrigCompositeContainer &decisions, const EventContext &context) const
Gaudi::Property< std::vector< std::string > > m_collectionsToSave
std::function< void(const ConvProxy *)> m_chainIdsPrinter
std::map< CLID, std::set< std::string > > m_collectionsToSaveDecoded
StatusCode fillRelevantFeatures(ConvProxySet_t &convProxies, const HLT::TrigNavStructure &run2Nav) const
std::size_t getFeaSize(const ConvProxy &) const
virtual StatusCode initialize() override
StatusCode collapseFeaturelessProxies(ConvProxySet_t &) const
ServiceHandle< TrigConf::IHLTConfigSvc > m_configSvc
StatusCode allProxiesConnected(const ConvProxySet_t &) const
StatusCode collapseProxies(ConvProxySet_t &, MAP &) const
std::vector< HLT::TriggerElement::FeatureAccessHelper > filterFEAs(const std::vector< HLT::TriggerElement::FeatureAccessHelper > &feaVector, const HLT::TrigNavStructure &navigationDecoder) const
< both method skip TrigPassBits
Helper class to provide type-safe access to aux data.
Definition Decorator.h:59
virtual bool isValid() override final
Can the handle be successfully dereferenced?
pointer_type ptr()
Dereference the pointer.
HLT chain configuration information.
const std::vector< HLTSignature * > & signatures() const
static const std::string hash2string(HLTHash, const std::string &category="TE")
hash function translating identifiers into names (via internal dictionary)
const std::string & name() const
Class providing the definition of the 4-vector interface.
void setDecisions(const std::vector< TrigCompositeUtils::DecisionID > &decisions)
Set positive HLT chain decisions associated with this TrigComposite. Navigation use.
const std::string & name() const
Get a human-readable name for the object.
bool add(const std::string &hname, TKey *tobj)
Definition fastadd.cxx:55
std::vector< int > multiplicities(const std::string &chain)
std::string formatSGkey(const std::string &prefix, const std::string &containername, const std::string &label)
declaration of formatting function.
Definition Holder.cxx:122
const std::regex gammaXeChain
const std::regex egammaDiEtcut
const std::regex isTopo
const std::regex egammaCombinedWithEtcut
const std::regex egammaEtcut
const std::regex bjetMuChain
const std::regex mu2MunoL1Special
const std::regex tauXeChain
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 & inputMakerNodeName()
unsigned int DecisionID
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.
const std::vector< ElementLink< DecisionContainer > > getLinkToPrevious(const Decision *d)
returns links to previous decision object 'seed'
const std::string & featureString()
HLT::Identifier getIDFromLeg(const HLT::Identifier &legIdentifier)
Generate the HLT::Identifier which corresponds to the chain name from the leg name.
std::set< DecisionID > DecisionIDContainer
SG::WriteHandle< DecisionContainer > createAndStore(const SG::WriteHandleKey< DecisionContainer > &key, const EventContext &ctx)
Creates and right away records the DecisionContainer with the key.
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 & summaryPassNodeName()
void addDecisionID(DecisionID id, Decision *d)
Appends the decision (given as ID) to the decision object.
const std::string & hltSeedingNodeName()
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.
bool isLegId(const HLT::Identifier &legIdentifier)
Recognise whether the chain ID is a leg ID.
Definition index.py:1
void reverse(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of reverse for DataVector/List.
TrigCompositeContainer_v1 TrigCompositeContainer
Declare the latest version of the container.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
TauTrackContainer_v1 TauTrackContainer
Definition of the current TauTrack container version.
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.
std::set< ConvProxy * > children
std::vector< HLT::te_id_type > teIDs
static const uint64_t MissingFEA
bool mergeAllowed(const ConvProxy *other) const
std::set< HLT::Identifier > runChains
std::set< HLT::Identifier > passChains
std::set< ConvProxy * > parents
const HLT::TriggerElement * te
bool isParent(const ConvProxy *other) const
bool isChild(const ConvProxy *other) const
void merge(ConvProxy *other)
ConvProxy(const HLT::TriggerElement *te)
std::string description() const