105 {
106
107
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;
118
119 if (!particles_muons.
isValid() || !particles_electrons.
isValid() ||
122 return StatusCode::FAILURE;
123 }
124
125 for (
const std::string& chain :
m_chains) {
127
128
129
130
132 ATH_MSG_DEBUG(
"Chain " << chain <<
" is on the exclusion list, skipping");
133 continue;
134 }
135
136
139
140
141 bool hasSupported = false;
142 for (const std::string& sig : ChainNameParseSignature) {
144 hasSupported = true;
145 break;
146 }
147 }
148 if (!hasSupported) {
149 ATH_MSG_DEBUG(
"Chain " << chain <<
" has no supported signatures, skipping");
150 continue;
151 }
153
154
155
156
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
163
165 std::replace(containerName.begin(), containerName.end(), '.', '_');
167 if (!
evtStore()->retrieve(composites, containerName).isSuccess()) {
170
171
172
173
175 if (nLegs > 0) {
176 ATH_MSG_INFO(
"Per-leg features of " << chain <<
" (no R2 reference):");
179 }
180 }
181 continue;
182 }
183
184
185
186
187
188
189
190
191
192
194 std::vector<const xAOD::IParticle*> r2MatchedPool;
195 if (useLinearisedR2) {
196 static const SG::AuxElement::ConstAccessor<std::vector<ElementLink<xAOD::IParticleContainer>>> accMatched("TrigMatchedObjects");
198 for (const ElementLink<xAOD::IParticleContainer>& link : accMatched(*entry)) {
199 if (!
link.isValid())
continue;
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231 std::vector<const SG::ReadHandle<xAOD::IParticleContainer>*> doneContainers;
232 for (const std::string& sig : ChainNameParseSignature) {
235
236
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)) {
242 const bool passR3 =
m_matchingTool->match(*p, chain, drThreshold,
false);
243
244 anyPassR2 |= passR2;
245 anyPassR3 |= passR3;
246
247 if (passR2 && !passR3) {
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 {
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)) {
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
279 HLT::NestedUniqueCombinationGenerator nucg;
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];
286 ATH_MSG_DEBUG(
"Signature " << sig <<
" not supported, skipping chain " << chain);
287 continue;
288 }
290 const size_t nRequired = static_cast<size_t>(ChainMultiplicity[readhandlesIndex]);
292 << " offline objects, chain requires " << nRequired);
293
294
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
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];
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());
323 location_in_combination++;
324 }
325 }
326
327
328
329
330
331
332
333
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
349
350
351
352
353 bool passR3 =
m_matchingTool->match(particles, chain, drThreshold,
false);
355
356 anyPassR2 |= passR2;
357 anyPassR3 |= passR3;
358
359
360 if (passR2 && !passR3) {
362 << " - R3 conversion may be missing trigger information");
363 for (const auto& p : particles) {
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 {
373 m_failingChains[
chain] += 1;
374 }
375 }
376
377 else if (!passR2 && passR3) {
378 ATH_MSG_DEBUG(
"R3 passes but R2 fails (expected) for chain " << chain);
380 for (const auto& p : particles) {
383 ATH_MSG_DEBUG(
" Particle pT=" <<
p->pt() <<
" eta=" <<
p->eta() <<
" phi=" <<
p->phi()
384 << " R2:" << r2 << " R3:" << r3);
385 }
386 }
387 }
388
389 else {
390 ++nCombinationsTested;
392 ATH_MSG_DEBUG(
"R2/R3 match for chain " << chain <<
" passR2: " << passR2 <<
" passR3: " << passR3);
393 for (const auto& p : particles) {
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 }
404
405
406
407 if (anyPassR3 && !anyPassR2) {
408 if (composites->empty()) {
409
410
411
412
413
414
415
417 << "but the R2 TrigMatch reference is EMPTY - unverifiable event");
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
426
427
428
429
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
442 ATH_MSG_DEBUG(
"################################### TrigMatch container for " << chain <<
" (" << composites->size() <<
" combinations)");
443 int comboIdx = 0;
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) {
451 ATH_MSG_DEBUG(
" pt=" << iParticleR2->
pt() <<
" eta=" << iParticleR2->
eta() <<
" phi=" << iParticleR2->
phi()
452 <<
" [" <<
f.dataID() <<
":" <<
f.index() <<
"]");
453 } else {
455 }
456 }
457 }
458 }
459
460
461
464 if (nLegs == 0) {
465 ATH_MSG_ERROR(
"Could not determine number of legs for chain " << chain);
466 return StatusCode::FAILURE;
467 }
471 }
472
473
474 if (isR2R3different) {
476 if (nLegs == 0) {
477 ATH_MSG_ERROR(
"Could not determine number of legs for chain " << chain);
478 return StatusCode::FAILURE;
479 }
480
481
482 ATH_MSG_ERROR(
"R2 pre-matched objects for " << chain <<
":");
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;
489 ATH_MSG_ERROR(
" R2 object: pT=" << iParticleR2->
pt() <<
" eta=" << iParticleR2->
eta() <<
" phi=" << iParticleR2->
phi());
490 }
491 }
492
493
497 }
498 }
499
500 return StatusCode::SUCCESS;
501}
#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.
size_t size() const
Number of registered mappings.
ServiceHandle< StoreGateSvc > & evtStore()
bool msgLvl(const MSG::Level lvl) const
void add(const UniqueCombinationGenerator &gen)
virtual bool isValid() override final
Can the handle be successfully dereferenced?
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.
Gaudi::Property< std::vector< std::string > > m_chains
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
Gaudi::Property< bool > m_printSubfeatures
static const xAOD::IParticle * resolveOriginal(const xAOD::IParticle *p)
Resolve a possible shallow copy to its original object via the "originalObjectLink" decoration (mirro...
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.
std::mutex m_failingChainsMutex
PublicToolHandle< Trig::R3MatchingTool > m_matchingTool
Gaudi::Property< std::string > m_inputPrefix
Gaudi::Property< std::vector< std::string > > m_chainsToExclude
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< int > multiplicities(const std::string &chain)
std::vector< std::string > signatures(const std::string &chain)
mapped_type at(key_type key) const
Look up an element in the map.
pointer & link(pointer p) const
Return a reference to the link for an element.
float j(const xAOD::IParticle &, const xAOD::TrackMeasurementValidation &hit, const Eigen::Matrix3d &jab_inv)
static const unsigned int allowResurrectedDecision
static const unsigned int Physics
TrigCompositeContainer_v1 TrigCompositeContainer
Declare the latest version of the container.
TrigComposite_v1 TrigComposite
Declare the latest version of the class.