You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Give every timeframe its own slot in the collision context
This fixes a problem in the timeframe index structure of the collision
context and adds a unit test.
- getTimeFrameBoundaries closed only one timeframe per collision, so a
timeframe without collisions was left out of the index structure
entirely and the collisions after it were assigned to the wrong
timeframe.
- The number of extracted per-timeframe contexts was therefore the number
of non-empty timeframes, not the number of timeframes asked for, and
the last tf<N>/collisioncontext.root could be missing.
- The scan now closes every timeframe a collision skips over and pads the
result to the number of timeframes the caller asks for, so entry i always
describes orbits [start + i*orbitsPerTF, start + (i+1)*orbitsPerTF).
- applyMaxCollisionFilter keeps an empty timeframe empty when it re-indexes,
and extractSingleTimeframe returns a valid empty context for it.
- o2-steer-colcontexttool passes the number of timeframes it asked for,
reports timeframes that came out empty together with the mean number of
collisions per timeframe implied by the interaction rate, and refuses to
continue when --noEmptyTF was requested.
https://its.cern.ch/jira/browse/O2-7132
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: DataFormats/simulation/include/SimulationDataFormat/DigitizationContext.h
+5-1Lines changed: 5 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -135,7 +135,11 @@ class DigitizationContext
135
135
voidapplyMaxCollisionFilter(std::vector<std::tuple<int, int, int>>& timeframeindices, long startOrbit, long orbitsPerTF, int maxColl, double orbitsEarly = 0.);
136
136
137
137
/// get timeframe structure --> index markers where timeframe starts/ends/is_influenced_by
// nTimeframes, when positive, is the number of timeframes the caller asked for; the result is
396
+
// padded with empty timeframes (or truncated) to exactly that length.
397
+
std::vector<std::pair<int, int>> getTimeFrameBoundaries(std::vector<o2::InteractionTimeRecord> const& irecords, long startOrbit, long orbitsPerTF, long nTimeframes = -1)
393
398
{
394
399
std::vector<std::pair<int, int>> result;
395
400
401
+
auto pad_and_return = [&result, nTimeframes](int index) {
402
+
if (nTimeframes > 0) {
403
+
while ((long)result.size() < nTimeframes) {
404
+
result.emplace_back(std::pair<int, int>(index, index - 1)); // an empty timeframe
405
+
}
406
+
result.resize(nTimeframes);
407
+
}
408
+
return result;
409
+
};
410
+
396
411
// the goal is to determine timeframe boundaries inside the interaction record vectors
397
-
// determine if we can do anything
398
412
if (irecords.size() == 0) {
399
-
// nothing to do
400
-
return result;
413
+
returnpad_and_return(0);
401
414
}
402
415
403
416
if (irecords.back().orbit < startOrbit) {
404
417
LOG(error) << "start orbit larger than last collision entry";
405
-
returnresult;
418
+
returnpad_and_return((int)irecords.size());
406
419
}
407
420
408
421
// skip to the first index falling within our constrained
"timeframeID", bpo::value<int>(&optvalues.tfid)->default_value(0), "Timeframe id of the first timeframe int this context. Allows to generate contexts for different start orbits")(
239
240
"first-orbit", bpo::value<double>(&optvalues.firstFractionalOrbit)->default_value(0), "First (fractional) orbit in the run (HBFUtils.firstOrbit + BC from decimal)")(
240
241
"maxCollsPerTF", bpo::value<int>(&optvalues.maxCollsPerTF)->default_value(-1), "Maximal number of MC collisions to put into one timeframe. By default no constraint.")(
241
-
"noEmptyTF", bpo::bool_switch(&optvalues.noEmptyTF), "Enforce to have at least one collision")(
242
+
"noEmptyTF", bpo::bool_switch(&optvalues.noEmptyTF), "Fail if any of the timeframes asked for ends up without a collision (and shift the first collision into the sampled orbit range)")(
"with-vertices", bpo::value<std::string>(&optvalues.vertexModeString)->default_value("kNoVertex"), "Assign vertices to collisions. Argument is the vertex mode. Defaults to no vertexing applied")(
244
245
"timestamp", bpo::value<long>(&optvalues.timestamp)->default_value(-1L), "Timestamp for CCDB queries / anchoring")(
@@ -660,7 +661,10 @@ int main(int argc, char* argv[])
660
661
}
661
662
LOG(info) << "-------- DENSE CONTEXT ------->>";
662
663
663
-
auto timeframeindices = digicontext.calcTimeframeIndices(orbitstart, options.orbitsPerTF, options.orbitsEarly);
664
+
// the number of timeframes we were asked for; passing it makes sure that a timeframe without
665
+
// collisions keeps its own slot instead of shifting every later timeframe down by one
0 commit comments