Skip to content

Commit feb5129

Browse files
committed
AOD: don't emit MC collisions borrowed from the previous timeframe
With --orbitsEarly (the timeframe history effect in O2DPG), the per-TF collision context is prefixed with the tail collisions of the previous timeframe. The AOD producer emitted BC and McCollision rows (plus McParticles) for these borrowed collisions as well, so merging per-TF AODs produced duplicate, non-monotonic BC entries and double-counted MC events. We now apply an ownership cut at mStartIR (orbitFirstSampled): collisions with globalBC below the TF start are skipped in collectBCs, the McCollision table and the McParticles table. McCollision indices are compacted accordingly, and reconstructed-track MC labels pointing into a dropped collision are invalidated (-1). The cut is applied uniformly to every TF, including the first one of a job, so that AODs of neighbouring jobs can also be merged without duplication. Merged AO2Ds now have a sorted, duplicate-free BC table and exactly one McCollision row per generated event, making the post-hoc AODBcRewriter (in O2DPG) repair unnecessary for new productions.
1 parent 6bc6de6 commit feb5129

1 file changed

Lines changed: 47 additions & 4 deletions

File tree

Detectors/AOD/src/AODProducerWorkflowSpec.cxx

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ void AODProducerWorkflowDPL::collectBCs(const o2::globaltracking::RecoContainer&
236236
// collecting non-empty BCs and enumerating them
237237
for (auto& rec : mcRecords) {
238238
uint64_t globalBC = rec.toLong();
239+
if (globalBC < mStartIR.toLong()) {
240+
// MC collision borrowed from the previous timeframe (due to collision-context
241+
// overlap); it is owned and stored by that timeframe's AOD, skip it here to
242+
// avoid duplicate BC/MCCollision rows after merging
243+
continue;
244+
}
239245
bcsMap[globalBC] = 1;
240246
}
241247

@@ -1198,6 +1204,16 @@ void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader&
11981204
int event = colInfo.eventID;
11991205
int source = colInfo.sourceID;
12001206
int mcColId = colInfo.colIndex;
1207+
if (mcColId < 0) {
1208+
// <event, source> belongs to an MC collision dropped by the producer (borrowed
1209+
// from the previous timeframe, see collectBCs); none of its tracks end up in the
1210+
// McParticles table, so invalidate any entries the marking phase above may have
1211+
// added for it (e.g. via dangling reconstructed-track MC labels)
1212+
for (auto& entry : mToStore[source][event]) {
1213+
entry.second = -1;
1214+
}
1215+
continue;
1216+
}
12011217
std::vector<MCTrack> const& mcParticles = mcReader.getTracks(source, event);
12021218
LOG(debug) << "Event=" << event << " source=" << source << " collision=" << mcColId;
12031219
auto& preselect = mToStore[source][event];
@@ -2220,6 +2236,22 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc)
22202236
const auto& mcRecords = mcReader->getDigitizationContext()->getEventRecords();
22212237
const auto& mcParts = mcReader->getDigitizationContext()->getEventParts();
22222238

2239+
// Collisions whose nominal BC predates the start of this timeframe were
2240+
// already produced (and stored) by the previous timeframe's AOD due to
2241+
// the collision-context overlap introduced by --orbitsEarly; drop them
2242+
// here to avoid duplicate BC/MCCollision rows after merging timeframes.
2243+
// Build a remap from the original (per-context) MC collision index to a
2244+
// compact index covering only the collisions owned by this timeframe.
2245+
std::vector<int> mcCollOldToNew(nMCCollisions, -1);
2246+
{
2247+
int newIdx = 0;
2248+
for (int iCol = 0; iCol < nMCCollisions; iCol++) {
2249+
if (mcRecords[iCol].toLong() >= mStartIR.toLong()) {
2250+
mcCollOldToNew[iCol] = newIdx++;
2251+
}
2252+
}
2253+
}
2254+
22232255
// if signal filtering enabled, let's check if there are more than one source; otherwise fatalise
22242256
if (mUseSigFiltMC) {
22252257
std::vector<int> sourceIDs{};
@@ -2252,6 +2284,19 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc)
22522284
for (int iCol = 0; iCol < nMCCollisions; iCol++) {
22532285
const auto time = mcRecords[iCol].getTimeOffsetWrtBC();
22542286
auto globalBC = mcRecords[iCol].toLong();
2287+
auto& colParts = mcParts[iCol];
2288+
auto nParts = colParts.size();
2289+
if (mcCollOldToNew[iCol] < 0) {
2290+
// collision borrowed from the previous timeframe (see collectBCs and the
2291+
// mcCollOldToNew remap above): no BC/MCCollision row is stored for it, but
2292+
// its <event, source> pairs still need to be registered with colIndex = -1
2293+
// so that fillMCParticlesTable can size mToStore correctly and invalidate
2294+
// any track labels dangling into these MC events
2295+
for (auto colPart : colParts) {
2296+
mcColToEvSrc.emplace_back(MCColInfo{-1, colPart.sourceID, colPart.entryID, globalBC});
2297+
}
2298+
continue;
2299+
}
22552300
auto item = bcsMap.find(globalBC);
22562301
int bcID = -1;
22572302
if (item != bcsMap.end()) {
@@ -2261,8 +2306,6 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc)
22612306
<< "for MC collision; BC = " << globalBC
22622307
<< ", mc collision = " << iCol;
22632308
}
2264-
auto& colParts = mcParts[iCol];
2265-
auto nParts = colParts.size();
22662309
for (auto colPart : colParts) {
22672310
auto eventID = colPart.entryID;
22682311
auto sourceID = colPart.sourceID;
@@ -2277,13 +2320,13 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc)
22772320
hepmcPdfInfosCursor.cursor,
22782321
hepmcHeavyIonsCursor.cursor,
22792322
header,
2280-
iCol,
2323+
mcCollOldToNew[iCol],
22812324
bcID,
22822325
time,
22832326
0,
22842327
sourceID);
22852328
}
2286-
mcColToEvSrc.emplace_back(MCColInfo{iCol, sourceID, eventID, globalBC}); // point background and injected signal events to one collision
2329+
mcColToEvSrc.emplace_back(MCColInfo{mcCollOldToNew[iCol], sourceID, eventID, globalBC}); // point background and injected signal events to one collision
22872330
}
22882331
}
22892332
}

0 commit comments

Comments
 (0)