Skip to content

Commit d037a9e

Browse files
authored
[Common,DPG] add occupancy wrt bunch crossings (tables BcOccs, BcOccsAll) (#18689)
1 parent e85325b commit d037a9e

6 files changed

Lines changed: 1180 additions & 76 deletions

File tree

‎Common/DataModel/EventSelection.h‎

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
#define COMMON_DATAMODEL_EVENTSELECTION_H_
1919

2020
#include <Framework/AnalysisDataModel.h>
21+
#include <Framework/Logger.h>
22+
23+
#include <algorithm>
24+
#include <cstdint>
25+
#include <ranges>
26+
#include <vector>
2127

2228
namespace o2::aod
2329
{
@@ -85,6 +91,111 @@ DECLARE_SOA_TABLE(EvSels, "AOD", "EVSEL", //!
8591
evsel::SumAmpFT0CInTimeRange,
8692
evsel::OccupancyMedianTime);
8793
using EvSel = EvSels::iterator;
94+
95+
// occupancy wrt BCs: same estimators and flags as in EvSels (occupancy from other collisions nearby in time),
96+
// calculated wrt a BC; collisions found in this BC are excluded (their number is stored in numCollsInBC)
97+
// N.B.: not related to the occupancy tables in OccupancyTables.h
98+
namespace bcocc
99+
{
100+
enum BcOccupancyFlags { // bits of occupancyFlags
101+
kNoCollInTimeRangeNarrow = 0, // no other collisions in specified time range (narrower than Strict)
102+
kNoCollInTimeRangeStrict, // no other collisions in specified time range
103+
kNoCollInTimeRangeStandard, // no other collisions in specified time range with per-collision multiplicity above threshold
104+
kNoCollInRofStrict, // no other collisions in this ITS Readout Frame
105+
kNoCollInRofStandard, // no other collisions in this ITS Readout Frame with per-collision multiplicity above threshold (no veto on collisions with close vZ)
106+
kNoHighMultCollInPrevRof, // FT0C amplitude in previous ITS ROF is below threshold
107+
kUpcMode // ITS ROF of this BC is in UPC mode: no collisions in the ROF, or collisions reconstructed in the UPC mode (set for all BCs, also without calculated occupancy)
108+
};
109+
DECLARE_SOA_COLUMN(NumTracksInTimeRange, trackOccupancyInTimeRange, int); //! Occupancy in specified time interval by a number of tracks from nearby collisions (-1 if not available) // o2-linter: disable=name/o2-column
110+
DECLARE_SOA_COLUMN(SumAmpFT0CInTimeRange, ft0cOccupancyInTimeRange, float); //! Occupancy in specified time interval by a sum of FT0C amplitudes from nearby collisions (-1 if not available) // o2-linter: disable=name/o2-column
111+
DECLARE_SOA_COLUMN(OccupancyMedianTime, occupancyMedianTime, float); //! Median time for the occupancy in specified time interval (the delta-time wrt to the BC at which occupancy crosses 1/2 of its full value)
112+
DECLARE_SOA_BITMAP_COLUMN(OccupancyFlags, occupancyFlags, 8); //! Bitmask of occupancy flags (see BcOccupancyFlags), check with occupancyFlags_bit(bit)
113+
DECLARE_SOA_COLUMN(NumCollsInBC, numCollsInBC, int16_t); //! Number of collisions found in this BC (excluded from the occupancy)
114+
DECLARE_SOA_COLUMN(NumCollsInRof, numCollsInRof, int16_t); //! Number of collisions found in the ITS ROF of this BC (within the TF), including the collisions in this BC (-1 if the ROF parameters are not available)
115+
} // namespace bcocc
116+
117+
// bc-joinable occupancy
118+
DECLARE_SOA_TABLE(BcOccs, "AOD", "BCOCC", //!
119+
bcocc::NumTracksInTimeRange,
120+
bcocc::SumAmpFT0CInTimeRange,
121+
bcocc::OccupancyMedianTime,
122+
bcocc::OccupancyFlags,
123+
bcocc::NumCollsInBC,
124+
bcocc::NumCollsInRof);
125+
using BcOcc = BcOccs::iterator;
126+
127+
// occupancy wrt every BC of the TFs present in the DF (not joinable): for each TF (in increasing order) all its BCs, in increasing order of global BC
128+
// same estimators and flags as in BcOccs
129+
DECLARE_SOA_TABLE(BcOccsAll, "AOD", "BCOCCALL", //!
130+
bc::GlobalBC,
131+
bcocc::NumTracksInTimeRange,
132+
bcocc::SumAmpFT0CInTimeRange,
133+
bcocc::OccupancyMedianTime,
134+
bcocc::OccupancyFlags,
135+
bcocc::NumCollsInBC,
136+
bcocc::NumCollsInRof);
137+
using BcOccAll = BcOccsAll::iterator;
138+
139+
namespace bcocc
140+
{
141+
// fast lookup of the aod::BcOccsAll entry for a given global BC
142+
// usage (within the process function, the index keeps a pointer to the table):
143+
// aod::bcocc::BcOccAllIndex bcOccAllIndexed(bcOccsAll);
144+
// auto occ = bcOccAllIndexed[bc.globalBC()]; // iterator of aod::BcOccsAll
145+
// int occByTracks = occ.trackOccupancyInTimeRange();
146+
template <typename TBcOccsAll>
147+
class BcOccAllIndex
148+
{
149+
public:
150+
explicit BcOccAllIndex(TBcOccsAll const& bcOccsAll) : mTable(&bcOccsAll)
151+
{
152+
const int64_t nRows = static_cast<int64_t>(bcOccsAll.size());
153+
// offset globalBC - row: constant along consecutive BCs, changes only where TFs are missing in the DF
154+
auto offsetAt = [&bcOccsAll](int64_t row) { return static_cast<int64_t>(bcOccsAll.iteratorAt(row).globalBC()) - row; };
155+
for (int64_t first = 0, end = 0; first < nRows; first = end) {
156+
// the offset is non-decreasing (global BCs are strictly increasing): the segment ends at the first row with a larger offset
157+
const int64_t offset = offsetAt(first);
158+
// binary search over the rows [first, nRows) for the end of the segment: the first row with a different offset
159+
end = *std::ranges::partition_point(std::views::iota(first, nRows), [&](int64_t row) { return offsetAt(row) == offset; });
160+
mSegments.push_back({offset + first, offset + end, offset});
161+
}
162+
}
163+
164+
// entry of aod::BcOccsAll for this global BC (fatal if the BC is not in the table)
165+
auto operator[](uint64_t globalBC) const
166+
{
167+
const int64_t row = rowOf(globalBC);
168+
if (row < 0) {
169+
LOGP(fatal, "BcOccAllIndex: global BC {} is not in aod::BcOccsAll ({} rows): its TF is not in this DF, or the occupancy is not available for this DF", globalBC, mTable->size());
170+
}
171+
return mTable->iteratorAt(row);
172+
}
173+
174+
// helper function to check if a global BC is contained in the table
175+
bool contains(uint64_t globalBC) const { return rowOf(globalBC) >= 0; }
176+
177+
private:
178+
// row of aod::BcOccsAll for this global BC, -1 if the BC is not in the table
179+
int64_t rowOf(uint64_t globalBC) const
180+
{
181+
const auto bc = static_cast<int64_t>(globalBC);
182+
for (const auto& seg : mSegments) { // a few segments: one per range of consecutive TFs in the DF
183+
if (bc >= seg.firstGlobalBC && bc < seg.endGlobalBC) {
184+
return bc - seg.offset;
185+
}
186+
}
187+
return -1;
188+
}
189+
190+
struct Segment {
191+
int64_t firstGlobalBC; // first global BC of the segment
192+
int64_t endGlobalBC; // last global BC of the segment + 1
193+
int64_t offset; // globalBC - row, constant within the segment
194+
};
195+
TBcOccsAll const* mTable; // not owned: the index is valid as long as the table (within the process function)
196+
std::vector<Segment> mSegments; // in increasing order of global BC
197+
};
198+
} // namespace bcocc
88199
} // namespace o2::aod
89200

90201
#endif // COMMON_DATAMODEL_EVENTSELECTION_H_

‎Common/TableProducer/eventSelectionService.cxx‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,17 @@ struct EventselectionRun3 { // o2-linter: disable=name/workflow-file (exception
112112

113113
o2::common::eventselection::EvselConfigurables evselOpts;
114114
o2::common::eventselection::EventSelectionModule evselmodule;
115+
o2::common::eventselection::BcOccConfigurables bcoccOpts;
116+
o2::common::eventselection::BcOccAllConfigurables bcoccAllOpts;
115117

116118
o2::common::eventselection::LumiConfigurables lumiOpts;
117119
o2::common::eventselection::LumiModule lumimodule;
118120

119121
Produces<aod::Timestamps> timestampTable; /// Table with SOR timestamps produced by the task
120122
Produces<aod::BcSels> bcsel;
121123
Produces<aod::EvSels> evsel;
124+
Produces<aod::BcOccs> bcocc;
125+
Produces<aod::BcOccsAll> bcoccall;
122126

123127
// for slicing
124128
SliceCache cache;
@@ -149,6 +153,8 @@ struct EventselectionRun3 { // o2-linter: disable=name/workflow-file (exception
149153
timestampMod.init(timestampConfigurables, metadataInfo);
150154
bcselmodule.init(context, bcselOpts, histos, metadataInfo);
151155
evselmodule.init(context, evselOpts, histos, metadataInfo);
156+
evselmodule.initBcOccupancy(context, bcoccOpts);
157+
evselmodule.initBcOccupancyAll(context, bcoccAllOpts);
152158
lumimodule.init(context, lumiOpts, histos);
153159
}
154160

@@ -163,6 +169,8 @@ struct EventselectionRun3 { // o2-linter: disable=name/workflow-file (exception
163169
timestampMod.process(bcs, ccdb, timestamps, timestampTable);
164170
bcselmodule.processRun3(ccdb, histos, bcs, timestamps, bcselsbuffer, bcsel);
165171
evselmodule.processRun3(ccdb, histos, bcs, collisions, pvTracks, ft0s, cache, timestamps, bcselsbuffer, evsel);
172+
evselmodule.processRun3BcOccupancy(bcs, bcselsbuffer, bcocc);
173+
evselmodule.processRun3BcOccupancyAll(bcs, bcoccall);
166174
lumimodule.process(ccdb, histos, bcs, timestamps, bcselsbuffer);
167175
}
168176
};

0 commit comments

Comments
 (0)