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;
119 if (!particles_muons.
isValid() || !particles_electrons.
isValid() ||
122 return StatusCode::FAILURE;
125 for (
const std::string& chain :
m_chains) {
132 ATH_MSG_DEBUG(
"Chain " << chain <<
" is on the exclusion list, skipping");
141 bool hasSupported =
false;
142 for (
const std::string& sig : ChainNameParseSignature) {
143 if (read_handles.find(sig) != read_handles.end()) {
149 ATH_MSG_DEBUG(
"Chain " << chain <<
" has no supported signatures, skipping");
157 const bool hasTau = std::find(ChainNameParseSignature.begin(),
158 ChainNameParseSignature.end(),
159 "tau") != ChainNameParseSignature.end();
160 const double drThreshold = hasTau ? 0.2 : 0.1;
165 std::replace(containerName.begin(), containerName.end(),
'.',
'_');
167 if (!
evtStore()->retrieve(composites, containerName).isSuccess()) {
176 ATH_MSG_INFO(
"Per-leg features of " << chain <<
" (no R2 reference):");
194 std::vector<const xAOD::IParticle*> r2MatchedPool;
195 if (useLinearisedR2) {
196 static const SG::AuxElement::ConstAccessor<std::vector<ElementLink<xAOD::IParticleContainer>>> accMatched(
"TrigMatchedObjects");
199 if (!link.isValid())
continue;
201 if (std::find(r2MatchedPool.begin(), r2MatchedPool.end(), orig) == r2MatchedPool.end()) {
202 r2MatchedPool.push_back(orig);
206 ATH_MSG_DEBUG(
"Chain " << chain <<
" uses linearised R2 matching: "
207 << composites->size() <<
" TrigMatch entries -> pool of "
208 << r2MatchedPool.size() <<
" individually matched objects");
211 bool isR2R3different =
false;
212 size_t nCombinationsTested = 0;
213 bool anyPassR2 =
false;
214 bool anyPassR3 =
false;
216 if (useLinearisedR2) {
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;
237 if (std::find(doneContainers.begin(), doneContainers.end(), handleItr->second) != doneContainers.end())
continue;
238 doneContainers.push_back(handleItr->second);
242 const bool passR3 =
m_matchingTool->match(*p, chain, drThreshold,
false);
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()
252 isR2R3different =
true;
256 m_failingChains[chain] += 1;
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()
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());
280 ATH_MSG_DEBUG(
"NestedUniqueCombinationGenerator: " << ChainMultiplicity.size() <<
" legs, " << ChainNameParseSignature.size() <<
" signatures");
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);
289 const size_t nOffline = (*read_handles[sig])->
size();
290 const size_t nRequired =
static_cast<size_t>(ChainMultiplicity[readhandlesIndex]);
292 <<
" offline objects, chain requires " << nRequired);
295 if (nOffline < nRequired) {
296 tooFewOffline =
true;
299 nucg.
add({nOffline, nRequired});
302 ATH_MSG_DEBUG(
"Not enough offline objects to form any combination for chain " << chain <<
", skipping");
308 const std::vector<size_t> combination = nucg();
311 std::vector<const xAOD::IParticle *> particles;
312 size_t location_in_combination = 0;
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;
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++;
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;
343 if (duplicateOffline) {
344 ATH_MSG_VERBOSE(
"Skipping combination with a repeated offline object for chain " << chain);
353 bool passR3 =
m_matchingTool->match(particles, chain, drThreshold,
false);
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);
369 isR2R3different =
true;
373 m_failingChains[chain] += 1;
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);
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);
407 if (anyPassR3 && !anyPassR2) {
408 if (composites->
empty()) {
417 <<
"but the R2 TrigMatch reference is EMPTY - unverifiable event");
419 m_emptyR2Chains[chain] += 1;
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;
431 m_failingChains[chain] += 1;
435 if (!isR2R3different && nCombinationsTested > 0) {
436 ATH_MSG_INFO(
"Chain " << chain <<
": R2/R3 agreement verified (" << nCombinationsTested
437 << (useLinearisedR2 ?
" objects)" :
" combinations)"));
442 ATH_MSG_DEBUG(
"################################### TrigMatch container for " << chain <<
" (" << composites->
size() <<
" combinations)");
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() <<
"):");
451 ATH_MSG_DEBUG(
" pt=" << iParticleR2->
pt() <<
" eta=" << iParticleR2->
eta() <<
" phi=" << iParticleR2->
phi()
452 <<
" [" << f.dataID() <<
":" << f.index() <<
"]");
465 ATH_MSG_ERROR(
"Could not determine number of legs for chain " << chain);
466 return StatusCode::FAILURE;
474 if (isR2R3different) {
477 ATH_MSG_ERROR(
"Could not determine number of legs for chain " << chain);
478 return StatusCode::FAILURE;
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);
487 if (!f.isValid())
continue;
489 ATH_MSG_ERROR(
" R2 object: pT=" << iParticleR2->
pt() <<
" eta=" << iParticleR2->
eta() <<
" phi=" << iParticleR2->
phi());
500 return StatusCode::SUCCESS;
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.