|
18 | 18 | #define COMMON_DATAMODEL_EVENTSELECTION_H_ |
19 | 19 |
|
20 | 20 | #include <Framework/AnalysisDataModel.h> |
| 21 | +#include <Framework/Logger.h> |
| 22 | + |
| 23 | +#include <algorithm> |
| 24 | +#include <cstdint> |
| 25 | +#include <ranges> |
| 26 | +#include <vector> |
21 | 27 |
|
22 | 28 | namespace o2::aod |
23 | 29 | { |
@@ -85,6 +91,111 @@ DECLARE_SOA_TABLE(EvSels, "AOD", "EVSEL", //! |
85 | 91 | evsel::SumAmpFT0CInTimeRange, |
86 | 92 | evsel::OccupancyMedianTime); |
87 | 93 | 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 |
88 | 199 | } // namespace o2::aod |
89 | 200 |
|
90 | 201 | #endif // COMMON_DATAMODEL_EVENTSELECTION_H_ |
0 commit comments