ATLAS Offline Software
Loading...
Searching...
No Matches
NavigationDAODTesterAlgv2.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <GaudiKernel/StatusCode.h>
8#include <algorithm>
9
15
16namespace TCU = TrigCompositeUtils;
17
18namespace Trig {
19
20NavigationDAODTesterAlgv2::NavigationDAODTesterAlgv2(const std::string &name, ISvcLocator *pSvcLocator) :
21 AthReentrantAlgorithm(name, pSvcLocator)
22{}
23
25 ATH_CHECK(m_tdt.retrieve());
26 ATH_CHECK(m_matchingTool.retrieve());
28
29 if (m_chains.empty()) {
30 ATH_MSG_WARNING("No chains provided, algorithm will be no-op");
31 }
32
33 return StatusCode::SUCCESS;
34}
35
36std::size_t NavigationDAODTesterAlgv2::numberOfLegs(const std::string& chain) const {
37 // The number of legs is the number of distinct signature blocks in the
38 // chain name, i.e. the size of the multiplicities vector. Note this is NOT
39 // the sum of the multiplicities (that would be the total number of physics
40 // objects required by the chain over all legs).
41 return ChainNameParser::multiplicities(chain).size();
42}
43
45 const std::vector<std::string>& patterns) {
46 for (const std::string& pattern : patterns) {
47 if (chain.find(pattern) != std::string::npos) return true;
48 }
49 return false;
50}
51
53 static const SG::AuxElement::ConstAccessor<ElementLink<xAOD::IParticleContainer>>
54 accOOL("originalObjectLink");
55 if (accOOL.isAvailable(*p) && accOOL(*p).isValid()) {
56 return *accOOL(*p);
57 }
58 return p;
59}
60
62 std::vector<const xAOD::IParticle*> pool,
63 const std::vector<const xAOD::IParticle*>& particles) {
64 // Consume-once semantics, mirroring MatchFromCompositeTool::testCombination:
65 // each given particle must find its own entry in the pool of individually
66 // matched objects. For the single-particle calls of the per-object
67 // comparison path this reduces to a plain membership test.
68 for (const xAOD::IParticle* p : particles) {
69 auto itr = std::find(pool.begin(), pool.end(), resolveOriginal(p));
70 if (itr == pool.end()) return false;
71 pool.erase(itr);
72 }
73 return true;
74}
75
77 std::size_t nLegs,
78 MSG::Level level,
79 const std::string& linkName) const {
80 const bool isSub = !linkName.empty();
81 const char* tag = isSub ? "[subfeature]" : "[feature]";
82 for (std::size_t leg = 0; leg < nLegs; ++leg) {
84 frd.setChainGroup(chain);
85 frd.setRestrictRequestToLeg(static_cast<int>(leg));
86 if (isSub) {
87 frd.setLinkName(linkName);
88 }
89 // Default feature collection mode (lastFeatureOfType) is correct for
90 // DAOD - only the final feature is kept after slimming.
91 auto features = m_tdt->features<xAOD::IParticleContainer>(frd);
92 msg() << level << " Leg " << leg << " "
93 << (isSub ? "subfeatures" : "features") << " (" << features.size() << "):" << endmsg;
94 for (const auto& feature : features) {
95 if (feature.isValid()) {
96 msg() << level << " " << tag << " pt=" << (*feature.link)->pt()
97 << " eta=" << (*feature.link)->eta()
98 << " phi=" << (*feature.link)->phi()
99 << " [" << feature.link.dataID() << ":" << feature.link.index() << "]" << endmsg;
100 }
101 }
102 }
103}
104
105StatusCode NavigationDAODTesterAlgv2::execute(const EventContext& ctx) const {
106
107 // Get offline particle containers
108 SG::ReadHandle<xAOD::IParticleContainer> particles_muons{"Muons", ctx};
109 SG::ReadHandle<xAOD::IParticleContainer> particles_electrons{"Electrons", ctx};
110 SG::ReadHandle<xAOD::IParticleContainer> particles_taus{"TauJets", ctx};
111 SG::ReadHandle<xAOD::IParticleContainer> particles_photons{"Photons", ctx};
112
113 std::map<std::string, SG::ReadHandle<xAOD::IParticleContainer>*> read_handles;
114 read_handles["e"] = &particles_electrons;
115 read_handles["mu"] = &particles_muons;
116 read_handles["tau"] = &particles_taus;
117 read_handles["g"] = &particles_photons;
118
119 if (!particles_muons.isValid() || !particles_electrons.isValid() ||
120 !particles_taus.isValid() || !particles_photons.isValid()) {
121 ATH_MSG_ERROR("Couldn't retrieve IParticles containers");
122 return StatusCode::FAILURE;
123 }
124
125 for (const std::string& chain : m_chains) {
126 if (!m_tdt->isPassed(chain, TrigDefs::Physics | TrigDefs::allowResurrectedDecision)) continue;
127
128 // Skip chains on the exception list (substring match). These are
129 // pathological chain families whose TrigMatch layout does not support
130 // the generic R2/R3 comparison and have no dedicated handling (yet).
132 ATH_MSG_DEBUG("Chain " << chain << " is on the exclusion list, skipping");
133 continue;
134 }
135
136 // Get the chain structure using ChainNameParser
137 auto ChainMultiplicity = ChainNameParser::multiplicities(chain);
138 auto ChainNameParseSignature = ChainNameParser::signatures(chain);
139
140 // Filter to only process chains with supported signatures (e, mu, g, tau)
141 bool hasSupported = false;
142 for (const std::string& sig : ChainNameParseSignature) {
143 if (read_handles.find(sig) != read_handles.end()) {
144 hasSupported = true;
145 break;
146 }
147 }
148 if (!hasSupported) {
149 ATH_MSG_DEBUG("Chain " << chain << " has no supported signatures, skipping");
150 continue;
151 }
152 ATH_MSG_DEBUG("Passing " << chain);
153
154 // DR=0.2 for chains with any tau leg, 0.1 otherwise. This follows the
155 // convention used when the TrigMatch branches are created at DAOD
156 // production time (see DerivationFrameworkPhys/PhysCommonConfig.py).
157 const bool hasTau = std::find(ChainNameParseSignature.begin(),
158 ChainNameParseSignature.end(),
159 "tau") != ChainNameParseSignature.end();
160 const double drThreshold = hasTau ? 0.2 : 0.1;
161
162 // Retrieve the TrigMatch container (used for the R2 match and for the
163 // DEBUG dump below).
164 std::string containerName = m_inputPrefix + chain;
165 std::replace(containerName.begin(), containerName.end(), '.', '_');
166 const xAOD::TrigCompositeContainer* composites(nullptr);
167 if (!evtStore()->retrieve(composites, containerName).isSuccess()) {
168 ATH_MSG_DEBUG("No branch in this DAOD for " << chain);
170 // Converter-debugging mode (e.g. directly after conversion at
171 // AOD level): no R2 reference exists, but the per-leg feature
172 // assignment - where the cross-leg pooling defect shows up -
173 // can still be inspected.
174 const std::size_t nLegs = numberOfLegs(chain);
175 if (nLegs > 0) {
176 ATH_MSG_INFO("Per-leg features of " << chain << " (no R2 reference):");
177 dumpFeaturesPerLeg(chain, nLegs, MSG::INFO);
178 dumpFeaturesPerLeg(chain, nLegs, MSG::INFO, "subfeature");
179 }
180 }
181 continue;
182 }
183
184 // nomucomb-family chains: the derivation stored the R2 matches
185 // linearised - one TrigComposite entry of vector size 1 per
186 // individually matched offline muon (e.g. HLT_2mu10_nomucomb with 3
187 // matched muons -> 3 entries of size 1) instead of one entry of size
188 // = sum of leg multiplicities per matched combination.
189 // MatchFromCompositeTool requires the full combination within a single
190 // entry, so it can never match there. Rebuild the R2 reference instead:
191 // the pool of individually matched offline objects, gathered once per
192 // chain/event.
193 const bool useLinearisedR2 = matchesAnyPattern(chain, m_linearisedR2Chains);
194 std::vector<const xAOD::IParticle*> r2MatchedPool;
195 if (useLinearisedR2) {
196 static const SG::AuxElement::ConstAccessor<std::vector<ElementLink<xAOD::IParticleContainer>>> accMatched("TrigMatchedObjects");
197 for (const xAOD::TrigComposite* entry : *composites) {
198 for (const ElementLink<xAOD::IParticleContainer>& link : accMatched(*entry)) {
199 if (!link.isValid()) continue; // e.g. removed by thinning
200 const xAOD::IParticle* orig = resolveOriginal(*link);
201 if (std::find(r2MatchedPool.begin(), r2MatchedPool.end(), orig) == r2MatchedPool.end()) {
202 r2MatchedPool.push_back(orig);
203 }
204 }
205 }
206 ATH_MSG_DEBUG("Chain " << chain << " uses linearised R2 matching: "
207 << composites->size() << " TrigMatch entries -> pool of "
208 << r2MatchedPool.size() << " individually matched objects");
209 }
210
211 bool isR2R3different = false;
212 size_t nCombinationsTested = 0;
213 bool anyPassR2 = false;
214 bool anyPassR3 = false;
215
216 if (useLinearisedR2) {
217 // Per-object comparison. The linearised reference holds individually
218 // matched objects with no combination structure and no online-object
219 // identity, so combination-level R2 verdicts cannot be reconstructed
220 // faithfully. Two benign cases would otherwise be flagged as ERRORs
221 // (both observed with HLT_2mu10_nomucomb, run 284500):
222 // - a collimated offline pair matched to the SAME single online
223 // muon: per-object R2 stores both, while R3 correctly demands
224 // distinct online objects per combination;
225 // - the converter demotes the lower-pT online muon of a shared RoI
226 // to a "subfeature", which the baseline comparison excludes
227 // (IncludeSubfeatures=False).
228 // Comparing per object keeps the genuine-defect signature visible:
229 // an object the R2 derivation matched but whose feature the
230 // converted navigation lost entirely still gives R2:1 R3:0.
231 std::vector<const SG::ReadHandle<xAOD::IParticleContainer>*> doneContainers;
232 for (const std::string& sig : ChainNameParseSignature) {
233 auto handleItr = read_handles.find(sig);
234 if (handleItr == read_handles.end()) continue;
235 // Legs may share an offline container (e.g. mu6 + 2mu4):
236 // process each container once.
237 if (std::find(doneContainers.begin(), doneContainers.end(), handleItr->second) != doneContainers.end()) continue;
238 doneContainers.push_back(handleItr->second);
239
240 for (const xAOD::IParticle* p : **(handleItr->second)) {
241 const bool passR2 = matchLinearisedR2(r2MatchedPool, {p});
242 const bool passR3 = m_matchingTool->match(*p, chain, drThreshold, false);
243
244 anyPassR2 |= passR2;
245 anyPassR3 |= passR3;
246
247 if (passR2 && !passR3) {
248 ATH_MSG_ERROR("R2 passes but R3 fails for chain " << chain
249 << " (per-object linearised check) - converted navigation may have lost this object");
250 ATH_MSG_ERROR(" Particle pT=" << p->pt() << " eta=" << p->eta() << " phi=" << p->phi()
251 << " R2:1 R3:0");
252 isR2R3different = true;
253
254 {
255 std::lock_guard<std::mutex> lock(m_failingChainsMutex);
256 m_failingChains[chain] += 1;
257 }
258 }
259 else if (!passR2 && passR3) {
260 ATH_MSG_DEBUG("R3 passes but R2 fails (expected) for chain " << chain
261 << " (per-object linearised check)");
262 ATH_MSG_DEBUG(" Particle pT=" << p->pt() << " eta=" << p->eta() << " phi=" << p->phi()
263 << " R2:0 R3:1");
264 }
265 else {
266 ++nCombinationsTested;
267 if (passR2 && msgLvl(MSG::DEBUG)) {
268 ATH_MSG_DEBUG("R2/R3 match for chain " << chain
269 << " (per-object linearised check) passR2: " << passR2 << " passR3: " << passR3);
270 ATH_MSG_DEBUG(" Particle pT=" << p->pt() << " eta=" << p->eta() << " phi=" << p->phi());
271 }
272 }
273 }
274 }
275 }
276 else {
277
278 // Setup combination generator based on multiplicities of offline physics objects for each leg
280 ATH_MSG_DEBUG("NestedUniqueCombinationGenerator: " << ChainMultiplicity.size() << " legs, " << ChainNameParseSignature.size() << " signatures");
281
282 bool tooFewOffline = false;
283 for (size_t readhandlesIndex = 0; readhandlesIndex < ChainNameParseSignature.size(); readhandlesIndex++) {
284 const std::string& sig = ChainNameParseSignature[readhandlesIndex];
285 if (read_handles.find(sig) == read_handles.end()) {
286 ATH_MSG_DEBUG("Signature " << sig << " not supported, skipping chain " << chain);
287 continue;
288 }
289 const size_t nOffline = (*read_handles[sig])->size();
290 const size_t nRequired = static_cast<size_t>(ChainMultiplicity[readhandlesIndex]);
291 ATH_MSG_DEBUG("Signature \"" << sig << "\": " << nOffline
292 << " offline objects, chain requires " << nRequired);
293 // If a leg has fewer offline objects than required, no valid combination
294 // can be formed. Skip to avoid out-of-range access in the generator loop.
295 if (nOffline < nRequired) {
296 tooFewOffline = true;
297 break;
298 }
299 nucg.add({nOffline, nRequired});
300 }
301 if (tooFewOffline) {
302 ATH_MSG_DEBUG("Not enough offline objects to form any combination for chain " << chain << ", skipping");
303 continue;
304 }
305
306 // Loop over all possible combinations of offline physics objects
307 do {
308 const std::vector<size_t> combination = nucg();
309 ++nucg;
310
311 std::vector<const xAOD::IParticle *> particles;
312 size_t location_in_combination = 0;
313
314 for (size_t ChainNameIndex = 0; ChainNameIndex < ChainNameParseSignature.size(); ++ChainNameIndex) {
315 const std::string& sig = ChainNameParseSignature[ChainNameIndex];
316 if (read_handles.find(sig) == read_handles.end()) continue;
317
318 for (size_t ChainMultipIndex = 0; ChainMultipIndex < static_cast<size_t>(ChainMultiplicity[ChainNameIndex]); ++ChainMultipIndex) {
319 const xAOD::IParticle* p = (*read_handles[sig])->at(combination[location_in_combination]);
320 ATH_MSG_VERBOSE("objectIndex --> " << sig << " " << combination[location_in_combination]
321 << " pT: " << p->pt() << " eta: " << p->eta() << " phi: " << p->phi());
322 particles.push_back(p);
323 location_in_combination++;
324 }
325 }
326
327 // Combination hygiene: legs sharing an offline container can draw
328 // the SAME offline object into two slots (the per-leg generators
329 // are independent). Such degenerate combinations are not physical
330 // trigger combinations - the R2 reference never contains them -
331 // while R3 can accept them through duplicated online copies (the
332 // same muon reconstructed in overlapping RoIs appears several
333 // times in the converted navigation). Skip them.
334 bool duplicateOffline = false;
335 for (size_t i = 0; i < particles.size() && !duplicateOffline; ++i) {
336 for (size_t j = i + 1; j < particles.size(); ++j) {
337 if (particles[i] == particles[j]) {
338 duplicateOffline = true;
339 break;
340 }
341 }
342 }
343 if (duplicateOffline) {
344 ATH_MSG_VERBOSE("Skipping combination with a repeated offline object for chain " << chain);
345 continue;
346 }
347
348 // R3: full combination matching via buildCombinations (DR-based,
349 // 0.2 for tau chains, 0.1 otherwise).
350 // R2: single full-combination match against the pre-stored TrigMatch
351 // container using pointer/shallow equality (configured on the
352 // MatchFromCompositeTool; its DR/rerun arguments are ignored).
353 bool passR3 = m_matchingTool->match(particles, chain, drThreshold, false);
354 bool passR2 = m_matchFromCompositeTool->match(particles, chain);
355
356 anyPassR2 |= passR2;
357 anyPassR3 |= passR3;
358
359 // ERROR: R2 says pass but R3 doesn't - this indicates missing trigger information in R3
360 if (passR2 && !passR3) {
361 ATH_MSG_ERROR("R2 passes but R3 fails for chain " << chain
362 << " - R3 conversion may be missing trigger information");
363 for (const auto& p : particles) {
364 bool r3 = m_matchingTool->match(*p, chain, drThreshold, false);
365 bool r2 = m_matchFromCompositeTool->match(*p, chain);
366 ATH_MSG_ERROR(" Particle pT=" << p->pt() << " eta=" << p->eta() << " phi=" << p->phi()
367 << " R2:" << r2 << " R3:" << r3);
368 }
369 isR2R3different = true;
370
371 {
372 std::lock_guard<std::mutex> lock(m_failingChainsMutex);
373 m_failingChains[chain] += 1;
374 }
375 }
376 // EXPECTED (but rare): R3 passes but R2 doesn't - R3 can form more combinations
377 else if (!passR2 && passR3) {
378 ATH_MSG_DEBUG("R3 passes but R2 fails (expected) for chain " << chain);
379 if (msgLvl(MSG::DEBUG)) {
380 for (const auto& p : particles) {
381 bool r3 = m_matchingTool->match(*p, chain, drThreshold, false);
382 bool r2 = m_matchFromCompositeTool->match(*p, chain);
383 ATH_MSG_DEBUG(" Particle pT=" << p->pt() << " eta=" << p->eta() << " phi=" << p->phi()
384 << " R2:" << r2 << " R3:" << r3);
385 }
386 }
387 }
388 // OK: both agree
389 else {
390 ++nCombinationsTested;
391 if (msgLvl(MSG::DEBUG)) {
392 ATH_MSG_DEBUG("R2/R3 match for chain " << chain << " passR2: " << passR2 << " passR3: " << passR3);
393 for (const auto& p : particles) {
394 bool r3 = m_matchingTool->match(*p, chain, drThreshold, false);
395 bool r2 = m_matchFromCompositeTool->match(*p, chain);
396 ATH_MSG_DEBUG(" Particle pT=" << p->pt() << " eta=" << p->eta() << " phi=" << p->phi()
397 << " R2:" << r2 << " R3:" << r3);
398 }
399 }
400 }
401 } while (nucg);
402
403 } // end generic combination path
404
405 // Chain-level sanity check: if R3 found at least one matching combination
406 // then R2 should also have found at least one.
407 if (anyPassR3 && !anyPassR2) {
408 if (composites->empty()) {
409 // The chain passed and R3 matched, but the derivation wrote NO
410 // R2 reference entries at all. TrigMatch production reads the
411 // original Run-2 navigation and is independent of the
412 // conversion, so an empty reference cannot indicate a
413 // conversion defect - the event is simply unverifiable by this
414 // comparison. Verified on independent derivations of the same
415 // events (e.g. HLT_g35_loose_g25_loose, HLT_e2x_..._mu8noL1).
416 ATH_MSG_WARNING("Chain " << chain << ": chain passed and R3 matched, "
417 << "but the R2 TrigMatch reference is EMPTY - unverifiable event");
418 std::lock_guard<std::mutex> lock(m_failingChainsMutex);
419 m_emptyR2Chains[chain] += 1;
420 }
421 else {
422 ATH_MSG_ERROR("Chain " << chain << ": R3 found at least one match but R2 found none "
423 << "- possible inconsistency between converted navigation and TrigMatch container");
424 isR2R3different = true;
425 // Count this in the finalize() summary as well. Chains that fail
426 // only this chain-level check would otherwise be missing from
427 // the "Failing chains count" deliverable of a full sweep. The two
428 // increments cannot double-count within one event: the
429 // per-combination one requires passR2, this one requires !anyPassR2.
430 std::lock_guard<std::mutex> lock(m_failingChainsMutex);
431 m_failingChains[chain] += 1;
432 }
433 }
434
435 if (!isR2R3different && nCombinationsTested > 0) {
436 ATH_MSG_INFO("Chain " << chain << ": R2/R3 agreement verified (" << nCombinationsTested
437 << (useLinearisedR2 ? " objects)" : " combinations)"));
438 }
439
440 // Dump TrigMatch container content at DEBUG level (composites already retrieved above)
441 if (msgLvl(MSG::DEBUG)) {
442 ATH_MSG_DEBUG("################################### TrigMatch container for " << chain << " (" << composites->size() << " combinations)");
443 int comboIdx = 0;
444 for (const xAOD::TrigComposite* combination : *composites) {
445 static const SG::AuxElement::ConstAccessor<std::vector<ElementLink<xAOD::IParticleContainer>>> accMatched("TrigMatchedObjects");
446 const std::vector<ElementLink<xAOD::IParticleContainer>> featuresInCombination = accMatched(*combination);
447 ATH_MSG_DEBUG(" Combo[" << comboIdx++ << "] (size=" << featuresInCombination.size() << "):");
448 for (const ElementLink<xAOD::IParticleContainer>& f : featuresInCombination) {
449 if (f.isValid()) {
450 const xAOD::IParticle* iParticleR2 = resolveOriginal(*f);
451 ATH_MSG_DEBUG(" pt=" << iParticleR2->pt() << " eta=" << iParticleR2->eta() << " phi=" << iParticleR2->phi()
452 << " [" << f.dataID() << ":" << f.index() << "]");
453 } else {
454 ATH_MSG_WARNING(" INVALID LINK in TrigMatch container for " << chain);
455 }
456 }
457 }
458 }
459
460 // Optional: print primary features and subfeatures per leg for inspection
461 // (subfeatures are lower-pT objects from the Run2->Run3 conversion).
462 if (m_printSubfeatures && msgLvl(MSG::DEBUG)) {
463 const std::size_t nLegs = numberOfLegs(chain);
464 if (nLegs == 0) {
465 ATH_MSG_ERROR("Could not determine number of legs for chain " << chain);
466 return StatusCode::FAILURE;
467 }
468 ATH_MSG_DEBUG("Subfeature inspection for " << chain);
469 dumpFeaturesPerLeg(chain, nLegs, MSG::DEBUG); // primary features
470 dumpFeaturesPerLeg(chain, nLegs, MSG::DEBUG, "subfeature"); // subfeatures
471 }
472
473 // Diagnostics dump on a failing chain
474 if (isR2R3different) {
475 const std::size_t nLegs = numberOfLegs(chain);
476 if (nLegs == 0) {
477 ATH_MSG_ERROR("Could not determine number of legs for chain " << chain);
478 return StatusCode::FAILURE;
479 }
480
481 // Dump R2 pre-matched objects
482 ATH_MSG_ERROR("R2 pre-matched objects for " << chain << ":");
483 for (const xAOD::TrigComposite* combination : *composites) {
484 static const SG::AuxElement::ConstAccessor<std::vector<ElementLink<xAOD::IParticleContainer>>> accMatched("TrigMatchedObjects");
485 const std::vector<ElementLink<xAOD::IParticleContainer>> featuresInCombination = accMatched(*combination);
486 for (const ElementLink<xAOD::IParticleContainer>& f : featuresInCombination) {
487 if (!f.isValid()) continue;
488 const xAOD::IParticle* iParticleR2 = resolveOriginal(*f);
489 ATH_MSG_ERROR(" R2 object: pT=" << iParticleR2->pt() << " eta=" << iParticleR2->eta() << " phi=" << iParticleR2->phi());
490 }
491 }
492
493 // Dump R3 features and subfeatures per leg
494 ATH_MSG_ERROR("R3 features per leg for " << chain << ":");
495 dumpFeaturesPerLeg(chain, nLegs, MSG::ERROR);
496 dumpFeaturesPerLeg(chain, nLegs, MSG::ERROR, "subfeature");
497 }
498 }
499
500 return StatusCode::SUCCESS;
501}
502
504 ATH_MSG_INFO("Failing chains count: " << m_failingChains.size());
505
506 std::vector<std::pair<std::string, int>> sortedChains(m_failingChains.begin(), m_failingChains.end());
507 std::sort(sortedChains.begin(), sortedChains.end(), [](const auto& a, const auto& b) {
508 return a.second > b.second;
509 });
510
511 for (const auto& chain : sortedChains) {
512 ATH_MSG_INFO("Failing chain: " << chain.first << " count: " << chain.second);
513 }
514
515 // Chains with events that cannot be verified: the chain passed and the
516 // converted navigation matched, but the R2 TrigMatch reference container
517 // was empty (a derivation-side property, independent of the conversion).
518 ATH_MSG_INFO("Chains with unverifiable events (empty R2 reference): " << m_emptyR2Chains.size());
519 std::vector<std::pair<std::string, int>> sortedEmpty(m_emptyR2Chains.begin(), m_emptyR2Chains.end());
520 std::sort(sortedEmpty.begin(), sortedEmpty.end(), [](const auto& a, const auto& b) {
521 return a.second > b.second;
522 });
523 for (const auto& chain : sortedEmpty) {
524 ATH_MSG_INFO("Unverifiable (empty R2) chain: " << chain.first << " count: " << chain.second);
525 }
526
527 return StatusCode::SUCCESS;
528}
529
530} // end namespace Trig
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
static Double_t a
Independent verification of trigger object matching on DAOD level.
size_t size() const
Number of registered mappings.
ServiceHandle< StoreGateSvc > & evtStore()
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.
bool empty() const noexcept
Returns true if the collection is empty.
An ensemble of UniqueCombinationGenerator API description.
void add(const UniqueCombinationGenerator &gen)
virtual bool isValid() override final
Can the handle be successfully dereferenced?
FeatureRequestDescriptor & setLinkName(const std::string &navElementLinkKey)
Set the Link Name Key.
FeatureRequestDescriptor & setChainGroup(const std::string &chainGroupName)
Set the desired Chain or Chain Group.
FeatureRequestDescriptor & setRestrictRequestToLeg(const int restrictToLegIndex)
Set to -1 by default, indicating that all legs of multi-leg chains are searched.
Gaudi::Property< bool > m_dumpFeaturesWithoutR2
static bool matchesAnyPattern(const std::string &chain, const std::vector< std::string > &patterns)
True if the chain name contains any of the patterns (substring match).
void dumpFeaturesPerLeg(const std::string &chain, std::size_t nLegs, MSG::Level level, const std::string &linkName="") const
Dump the per-leg R3 features of a chain at the given message level.
PublicToolHandle< Trig::TrigDecisionTool > m_tdt
Gaudi::Property< std::vector< std::string > > m_chains
virtual StatusCode initialize() override
virtual StatusCode execute(const EventContext &context) const override
PublicToolHandle< Trig::MatchFromCompositeTool > m_matchFromCompositeTool
std::size_t numberOfLegs(const std::string &chain) const
Number of legs of a chain, derived from ChainNameParser::multiplicities().
Gaudi::Property< std::vector< std::string > > m_linearisedR2Chains
static const xAOD::IParticle * resolveOriginal(const xAOD::IParticle *p)
Resolve a possible shallow copy to its original object via the "originalObjectLink" decoration (mirro...
NavigationDAODTesterAlgv2(const std::string &name, ISvcLocator *pSvcLocator)
static bool matchLinearisedR2(std::vector< const xAOD::IParticle * > pool, const std::vector< const xAOD::IParticle * > &particles)
R2 verdict for chains with linearised TrigMatch layout (e.g.
PublicToolHandle< Trig::R3MatchingTool > m_matchingTool
Gaudi::Property< std::string > m_inputPrefix
Gaudi::Property< std::vector< std::string > > m_chainsToExclude
Class providing the definition of the 4-vector interface.
virtual double eta() const =0
The pseudorapidity ( ) of the particle.
virtual double pt() const =0
The transverse momentum ( ) of the particle.
virtual double phi() const =0
The azimuthal angle ( ) of the particle.
std::vector< std::string > patterns
Definition listroot.cxx:187
std::vector< int > multiplicities(const std::string &chain)
std::vector< std::string > signatures(const std::string &chain)
The common trigger namespace for trigger analysis tools.
Framework include files.
Definition libname.h:15
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TrigCompositeContainer_v1 TrigCompositeContainer
Declare the latest version of the container.
TrigComposite_v1 TrigComposite
Declare the latest version of the class.
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.