Skip to content

Commit 79d97ef

Browse files
committed
[PWGEM] Fix potential missmatches between data and MC
In skimmerGammaCalo merged the filling of the reconstruction data table and the MC info table into one function to ensure both are filled at the same time using the exact same cuts. In associateMCinfoPhoton added additionl collision check for filling the mclabels tables. Before it was only checked that the reco collision has a matching mc_collision nothing else. However, when creating the `fEventLabels` look up map for the association of the collisions isSelected() function is called. This could result in EmMcParticles poiting to garbage EMMCEventIds.
1 parent 6553b66 commit 79d97ef

2 files changed

Lines changed: 162 additions & 132 deletions

File tree

PWGEM/PhotonMeson/TableProducer/associateMCinfoPhoton.cxx

Lines changed: 128 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ struct AssociateMCInfoPhoton {
7373
kElectron = 0x8,
7474
};
7575

76+
static constexpr uint16_t kNoMcParticleMask = (1 << 14); // isNoise bit: no genuine MC particle for this leg/track
77+
7678
Produces<o2::aod::EMMCEvents> mcevents;
7779
Produces<o2::aod::EMMCEventLabels> mceventlabels;
7880
Produces<o2::aod::EMMCParticles> emmcparticles;
@@ -90,6 +92,7 @@ struct AssociateMCInfoPhoton {
9092
Configurable<float> maxPt{"maxPt", 20.f, "max pT for BinnedGenPts table"};
9193
Configurable<float> maxY{"maxY", 0.9f, "max |rapidity| for BinnedGenPts table"};
9294
Configurable<bool> doStoreAllDaughters{"doStoreAllDaughters", false, "flag to enable storing of all photon, pi0, eta, eta' and omega daughters. This will increase the dervied data size!"};
95+
Configurable<bool> useIsSelected{"useIsSelected", true, "flag to enable the usage of isSelected from our EM event selection. Disabling this will increase the derived data size!"};
9396

9497
HistogramRegistry registry{"EMMCEvent"};
9598

@@ -164,15 +167,34 @@ struct AssociateMCInfoPhoton {
164167
}
165168
}
166169

170+
template <soa::is_iterator TCollision>
171+
bool passesCollisionGate(TCollision const& collisionIter)
172+
{
173+
if (!collisionIter.has_mcCollision()) {
174+
return false;
175+
}
176+
if (useIsSelected.value && !collisionIter.isSelected()) {
177+
return false;
178+
}
179+
return true;
180+
}
181+
167182
template <o2::soa::is_iterator TMCParticle, o2::soa::is_iterator TMCCollision>
168183
void selectMothersToStore(int motherId, int64_t mcParticleSize, TMCParticle& motherParticle, TMCParticle& daughterIter, TMCCollision const& mcCollisionIter, std::unordered_map<uint64_t, int>& fNewLabels, std::map<uint64_t, int>& fNewLabelsReversed, std::unordered_map<uint64_t, int>& fEventIdx, std::unordered_map<uint64_t, int>& fEventLabels, Counter& fCounter)
169184
{
170185
while (motherId > -1) {
171-
if (motherId < mcParticleSize) { // protect against bad mother indices. why is this needed?
186+
if (motherId < mcParticleSize) {
172187
motherParticle.setCursor(motherId);
173-
int eventIdx = fEventLabels.find(mcCollisionIter.globalIndex())->second;
174188

175-
// if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack
189+
auto evIt = fEventLabels.find(mcCollisionIter.globalIndex());
190+
if (evIt == fEventLabels.end()) {
191+
// Can't attribute this ancestor to a known event; stop walking rather than risk UB.
192+
LOG(warning) << "selectMothersToStore: mcCollision " << mcCollisionIter.globalIndex()
193+
<< " not found in fEventLabels, aborting mother-chain walk.";
194+
break;
195+
}
196+
int eventIdx = evIt->second;
197+
176198
if (!fNewLabels.contains(motherParticle.globalIndex())) {
177199
fNewLabels[motherParticle.globalIndex()] = fCounter.particles;
178200
fNewLabelsReversed[fCounter.particles] = motherParticle.globalIndex();
@@ -232,12 +254,7 @@ struct AssociateMCInfoPhoton {
232254
for (const auto& collision : collisions) {
233255
registry.fill(HIST("hEventCounter"), 1);
234256

235-
// TODO: investigate the collisions without corresponding mcCollision
236-
if (!collision.has_mcCollision()) {
237-
continue;
238-
}
239-
240-
if (!collision.isSelected()) {
257+
if (!passesCollisionGate(collision)) {
241258
continue;
242259
}
243260

@@ -359,122 +376,135 @@ struct AssociateMCInfoPhoton {
359376
auto o2TrackIter = o2tracks.begin();
360377
for (const auto& v0 : v0photons) {
361378
collisionIter.setCursor(v0.collisionId());
362-
if (!collisionIter.has_mcCollision()) {
363-
continue;
364-
}
365-
mcCollisionIter.setCursor(collisionIter.mcCollisionId());
366379

367-
ele.setCursor(v0.negTrackId());
368-
pos.setCursor(v0.posTrackId());
380+
// check if the collision is valid AND the legs have valid MC particles
381+
bool validMc = false;
382+
if (passesCollisionGate(collisionIter)) {
383+
mcCollisionIter.setCursor(collisionIter.mcCollisionId());
369384

370-
o2TrackEle.setCursor(ele.trackId());
371-
o2TrackPos.setCursor(pos.trackId());
385+
ele.setCursor(v0.negTrackId());
386+
pos.setCursor(v0.posTrackId());
387+
o2TrackEle.setCursor(ele.trackId());
388+
o2TrackPos.setCursor(pos.trackId());
372389

373-
if (!o2TrackEle.has_mcParticle() || !o2TrackPos.has_mcParticle()) {
374-
continue; // If no MC particle is found, skip the v0
390+
validMc = o2TrackEle.has_mcParticle() && o2TrackPos.has_mcParticle();
375391
}
376392

377-
for (const auto& leg : {pos, ele}) { // be carefull of order {pos, ele}!
378-
o2TrackIter.setCursor(leg.trackId());
379-
mcParticleIter.setCursor(o2TrackIter.mcParticleId());
380-
// LOGF(info, "mcParticleIter.globalIndex() = %d, mcParticleIter.index() = %d", mcParticleIter.globalIndex(), mcParticleIter.index()); // these are exactly the same.
381-
382-
// if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack
383-
auto [iter, isNew] = fNewLabels.try_emplace(mcParticleIter.globalIndex(), fCounter.particles);
384-
if (isNew) {
385-
fNewLabelsReversed[fCounter.particles] = mcParticleIter.globalIndex();
386-
fEventIdx[mcParticleIter.globalIndex()] = fEventLabels.find(mcCollisionIter.globalIndex())->second;
387-
fCounter.particles++;
388-
}
389-
v0legmclabels(iter->second, o2TrackIter.mcMask());
393+
for (const auto& leg : {pos, ele}) { // careful: order {pos, ele}, must stay fixed either way
394+
if (validMc) {
395+
o2TrackIter.setCursor(leg.trackId());
396+
mcParticleIter.setCursor(o2TrackIter.mcParticleId());
397+
398+
auto [iter, isNew] = fNewLabels.try_emplace(mcParticleIter.globalIndex(), fCounter.particles);
399+
if (isNew) {
400+
fNewLabelsReversed[fCounter.particles] = mcParticleIter.globalIndex();
401+
auto evIt = fEventLabels.find(mcCollisionIter.globalIndex());
402+
if (evIt != fEventLabels.end()) {
403+
fEventIdx[mcParticleIter.globalIndex()] = evIt->second;
404+
}
405+
fCounter.particles++;
406+
}
407+
v0legmclabels(iter->second, o2TrackIter.mcMask());
390408

391-
// Next, store mother-chain of this reconstructed track.
392-
int motherid = -999; // first mother index
393-
if (mcParticleIter.has_mothers()) {
394-
motherid = mcParticleIter.mothersIds()[0]; // first mother index
409+
int motherid = -999;
410+
if (mcParticleIter.has_mothers()) {
411+
motherid = mcParticleIter.mothersIds()[0];
412+
}
413+
selectMothersToStore(motherid, mcParticles.size(), motherParticle, daughterIter, mcCollisionIter,
414+
fNewLabels, fNewLabelsReversed, fEventIdx, fEventLabels, fCounter);
415+
} else {
416+
v0legmclabels(-1, kNoMcParticleMask); // no MC match for this leg, but the row must still exist
395417
}
396-
selectMothersToStore(motherid, mcParticles.size(), motherParticle, daughterIter, mcCollisionIter, fNewLabels, fNewLabelsReversed, fEventIdx, fEventLabels, fCounter);
397-
} // end of leg loop
418+
} // end of loop over legs {pos, ele}
398419
} // end of v0 loop
399420
}
400421

401422
if constexpr (static_cast<bool>(system & kElectron)) {
402423
auto o2TrackIter = o2tracks.begin();
403-
// auto emprimaryelectrons_coll = emprimaryelectrons.sliceBy(perCollisionEl, collision.globalIndex());
404424
for (const auto& emprimaryelectron : emprimaryelectrons) {
405425
collisionIter.setCursor(emprimaryelectron.collisionId());
406-
if (!collisionIter.has_mcCollision()) {
407-
continue;
408-
}
409-
mcCollisionIter.setCursor(collisionIter.mcCollisionId());
410426

411-
o2TrackIter.setCursor(emprimaryelectron.trackId());
412-
if (!o2TrackIter.has_mcParticle()) {
413-
continue; // If no MC particle is found, skip the dilepton
414-
}
415-
mcParticleIter.setCursor(o2TrackIter.mcParticleId());
427+
int32_t mcLabel = -1;
428+
uint16_t mcMask = kNoMcParticleMask;
416429

417-
// if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack
418-
auto [iter, isNew] = fNewLabels.try_emplace(mcParticleIter.globalIndex(), fCounter.particles);
419-
if (isNew) {
420-
fNewLabelsReversed[fCounter.particles] = mcParticleIter.globalIndex();
421-
fEventIdx[mcParticleIter.globalIndex()] = fEventLabels.find(mcCollisionIter.globalIndex())->second;
422-
fCounter.particles++;
423-
}
424-
emprimaryelectronmclabels(iter->second, o2TrackIter.mcMask());
430+
if (passesCollisionGate(collisionIter)) {
431+
mcCollisionIter.setCursor(collisionIter.mcCollisionId());
432+
o2TrackIter.setCursor(emprimaryelectron.trackId());
433+
434+
if (o2TrackIter.has_mcParticle()) {
435+
mcParticleIter.setCursor(o2TrackIter.mcParticleId());
436+
437+
// if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack
438+
auto [iter, isNew] = fNewLabels.try_emplace(mcParticleIter.globalIndex(), fCounter.particles);
439+
if (isNew) {
440+
fNewLabelsReversed[fCounter.particles] = mcParticleIter.globalIndex();
441+
auto evIt = fEventLabels.find(mcCollisionIter.globalIndex());
442+
if (evIt != fEventLabels.end()) {
443+
fEventIdx[mcParticleIter.globalIndex()] = evIt->second;
444+
}
445+
fCounter.particles++;
446+
}
447+
mcLabel = iter->second;
448+
mcMask = o2TrackIter.mcMask();
425449

426-
// Next, store mother-chain of this reconstructed track.
427-
int motherid = -999; // first mother index
428-
if (mcParticleIter.has_mothers()) {
429-
motherid = mcParticleIter.mothersIds()[0]; // first mother index
450+
int motherid = -999;
451+
if (mcParticleIter.has_mothers()) {
452+
motherid = mcParticleIter.mothersIds()[0];
453+
}
454+
selectMothersToStore(motherid, mcParticles.size(), motherParticle, daughterIter, mcCollisionIter,
455+
fNewLabels, fNewLabelsReversed, fEventIdx, fEventLabels, fCounter);
456+
} // if (o2TrackIter.has_mcParticle())
430457
}
431-
selectMothersToStore(motherid, mcParticles.size(), motherParticle, daughterIter, mcCollisionIter, fNewLabels, fNewLabelsReversed, fEventIdx, fEventLabels, fCounter);
458+
emprimaryelectronmclabels(mcLabel, mcMask); // always exactly one row per emprimaryelectron
432459
} // end of em primary electron loop
433460
}
434461

435462
if constexpr (static_cast<bool>(system & kEMC)) { // for emc photons
436-
// auto ememcclusters_coll = emcclusters.sliceBy(perCollisionEMC, collision.globalIndex());
437463
for (const auto& emccluster : emcclusters) {
438464
collisionIter.setCursor(emccluster.collisionId());
439-
if (!collisionIter.has_mcCollision()) {
440-
continue;
441-
}
442-
mcCollisionIter.setCursor(collisionIter.mcCollisionId());
443465

444-
// TODO: test
445-
if (emccluster.mcParticleIds().size() <= 0) {
446-
continue;
447-
}
448466
std::vector<int32_t> vEmcMcParticleIds;
449467
std::vector<float> vAmplitudes;
450468

451-
vEmcMcParticleIds.reserve(emccluster.mcParticleIds().size());
452-
vAmplitudes.reserve(emccluster.mcParticleIds().size());
453-
454-
for (size_t iCont = 0; iCont < emccluster.mcParticleIds().size(); iCont++) {
455-
mcPhoton.setCursor(emccluster.mcParticleIds()[iCont]);
469+
if (passesCollisionGate(collisionIter)) {
470+
mcCollisionIter.setCursor(collisionIter.mcCollisionId());
456471

457-
// if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack
458-
auto [iter, isNew] = fNewLabels.try_emplace(mcPhoton.globalIndex(), fCounter.particles);
459-
if (isNew) {
460-
fNewLabelsReversed[fCounter.particles] = mcPhoton.globalIndex();
461-
fEventIdx[mcPhoton.globalIndex()] = fEventLabels.find(mcCollisionIter.globalIndex())->second;
462-
fCounter.particles++;
472+
if (emccluster.mcParticleIds().size() != emccluster.amplitude().size()) {
473+
LOG(warning) << "Cluster " << emccluster.globalIndex()
474+
<< ": mcParticleIds/amplitude size mismatch ("
475+
<< emccluster.mcParticleIds().size() << " vs " << emccluster.amplitude().size() << ")";
463476
}
464-
vEmcMcParticleIds.emplace_back(iter->second);
465-
vAmplitudes.emplace_back(emccluster.amplitude()[iCont]);
466-
// ememcclustermclabels(fNewLabels.find(mcPhoton.index())->second);
467-
468-
// Next, store mother-chain of this reconstructed track.
469-
int motherid = -999; // first mother index
470-
if (mcPhoton.has_mothers()) {
471-
motherid = mcPhoton.mothersIds()[0]; // first mother index
477+
size_t nCont = std::min(emccluster.mcParticleIds().size(), emccluster.amplitude().size());
478+
479+
vEmcMcParticleIds.reserve(nCont);
480+
vAmplitudes.reserve(nCont);
481+
482+
for (size_t iCont = 0; iCont < nCont; iCont++) {
483+
mcPhoton.setCursor(emccluster.mcParticleIds()[iCont]);
484+
// if the MC truth particle corresponding to this reconstructed track which is not already written, add it to the skimmed MC stack
485+
auto [iter, isNew] = fNewLabels.try_emplace(mcPhoton.globalIndex(), fCounter.particles);
486+
if (isNew) {
487+
fNewLabelsReversed[fCounter.particles] = mcPhoton.globalIndex();
488+
auto evIt = fEventLabels.find(mcCollisionIter.globalIndex());
489+
if (evIt != fEventLabels.end()) { // keep your earlier guard here too
490+
fEventIdx[mcPhoton.globalIndex()] = evIt->second;
491+
}
492+
fCounter.particles++;
493+
}
494+
vEmcMcParticleIds.emplace_back(iter->second);
495+
vAmplitudes.emplace_back(emccluster.amplitude()[iCont]);
496+
497+
int motherid = -999;
498+
if (mcPhoton.has_mothers()) {
499+
motherid = mcPhoton.mothersIds()[0];
500+
}
501+
selectMothersToStore(motherid, mcParticles.size(), motherParticle, daughterIter, mcCollisionIter,
502+
fNewLabels, fNewLabelsReversed, fEventIdx, fEventLabels, fCounter);
472503
}
473-
selectMothersToStore(motherid, mcParticles.size(), motherParticle, daughterIter, mcCollisionIter, fNewLabels, fNewLabelsReversed, fEventIdx, fEventLabels, fCounter);
474504
} // end of loop over mc particles of the current emc cluster
505+
// whether or not the collision was okay, exactly one row is always written here so later the tables are ensured to have same size!
475506
ememcclustermclabels(vEmcMcParticleIds, vAmplitudes);
476-
477-
} // end of em emc cluster loop
507+
}
478508
}
479509

480510
// Loop over the label map, create the mother/daughter relationships if these exist and write the skimmed MC stack
@@ -517,7 +547,12 @@ struct AssociateMCInfoPhoton {
517547
}
518548
}
519549

520-
emmcparticles(fEventIdx.find(oldLabel)->second, mcParticleIter.pdgCode(), mcParticleIter.flags(), mcParticleIter.statusCode(),
550+
auto evIt = fEventIdx.find(oldLabel);
551+
if (evIt == fEventIdx.end()) {
552+
LOG(warning) << "emmcparticles: no event index for particle label " << oldLabel << ", skipping.";
553+
continue;
554+
}
555+
emmcparticles(evIt->second, mcParticleIter.pdgCode(), mcParticleIter.flags(), mcParticleIter.statusCode(),
521556
mothers, daughters,
522557
mcParticleIter.px(), mcParticleIter.py(), mcParticleIter.pz(), mcParticleIter.e(),
523558
mcParticleIter.vx(), mcParticleIter.vy(), mcParticleIter.vz());

0 commit comments

Comments
 (0)