|
1 | | -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. |
| 1 | +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. |
2 | 2 | // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. |
3 | 3 | // All rights not expressly granted are reserved. |
4 | 4 | // |
|
11 | 11 |
|
12 | 12 | /// \file Clusterer.h |
13 | 13 | /// \brief Definition of the ITS cluster finder |
14 | | -#ifndef ALICEO2_ITS_CLUSTERER_H |
15 | | -#define ALICEO2_ITS_CLUSTERER_H |
16 | | - |
17 | | -#define _PERFORM_TIMING_ |
18 | | - |
19 | | -// uncomment this to not allow diagonal clusters, e.g. like |* | |
20 | | -// | *| |
21 | | -#define _ALLOW_DIAGONAL_ALPIDE_CLUSTERS_ |
22 | | - |
23 | | -#include <utility> |
24 | | -#include <vector> |
25 | | -#include <cstring> |
26 | | -#include <memory> |
27 | | -#include <gsl/span> |
| 14 | +#ifndef ALICEO2_ITS3_CLUSTERER_H |
| 15 | +#define ALICEO2_ITS3_CLUSTERER_H |
28 | 16 |
|
29 | 17 | #include "ITSMFTBase/SegmentationAlpide.h" |
30 | | -#include "DataFormatsITSMFT/CompCluster.h" |
31 | | -#include "DataFormatsITSMFT/ROFRecord.h" |
32 | | -#include "ITSMFTReconstruction/PixelReader.h" |
33 | | -#include "ITSMFTReconstruction/PixelData.h" |
| 18 | +#include "ITSMFTReconstruction/Clusterer.h" |
| 19 | +#include "ITS3Base/SegmentationMosaix.h" |
34 | 20 | #include "ITS3Reconstruction/LookUp.h" |
35 | | -#include "SimulationDataFormat/MCCompLabel.h" |
36 | | -#include "CommonConstants/LHCConstants.h" |
37 | | - |
38 | | -#ifdef _PERFORM_TIMING_ |
39 | | -#include <TStopwatch.h> |
40 | | -#endif |
41 | | - |
42 | | -class TTree; |
43 | 21 |
|
44 | | -namespace o2 |
| 22 | +namespace o2::its3 |
45 | 23 | { |
46 | | -class MCCompLabel; |
47 | | -namespace dataformats |
48 | | -{ |
49 | | -template <typename T> |
50 | | -class ConstMCTruthContainerView; |
51 | | -template <typename T> |
52 | | -class MCTruthContainer; |
53 | | -} // namespace dataformats |
54 | | - |
55 | | -namespace its3 |
56 | | -{ |
57 | | - |
58 | | -using CompClusCont = std::vector<itsmft::CompClusterExt>; |
59 | | -using PatternCont = std::vector<unsigned char>; |
60 | | -using ROFRecCont = std::vector<itsmft::ROFRecord>; |
61 | | - |
62 | | -// template <class CompClusCont, class PatternCont, class ROFRecCont> // container types (PMR or std::vectors) |
63 | | - |
64 | | -class Clusterer |
65 | | -{ |
66 | | - using PixelReader = o2::itsmft::PixelReader; |
67 | | - using PixelData = o2::itsmft::PixelData; |
68 | | - using ChipPixelData = o2::itsmft::ChipPixelData; |
69 | | - using CompCluster = o2::itsmft::CompCluster; |
70 | | - using CompClusterExt = o2::itsmft::CompClusterExt; |
71 | | - using Label = o2::MCCompLabel; |
72 | | - using MCTruth = o2::dataformats::MCTruthContainer<o2::MCCompLabel>; |
73 | | - using ConstMCTruth = o2::dataformats::ConstMCTruthContainerView<o2::MCCompLabel>; |
74 | | - |
75 | | - public: |
76 | | - static constexpr int MaxLabels = 10; |
77 | | - static constexpr int MaxHugeClusWarn = 5; // max number of warnings for HugeCluster |
78 | | - |
79 | | - struct BBox { |
80 | | - uint16_t chipID = 0xffff; |
81 | | - uint16_t rowMin = 0xffff; |
82 | | - uint16_t colMin = 0xffff; |
83 | | - uint16_t rowMax = 0; |
84 | | - uint16_t colMax = 0; |
85 | | - BBox(uint16_t c) : chipID(c) {} |
86 | | - bool isInside(uint16_t row, uint16_t col) const { return row >= rowMin && row <= rowMax && col >= colMin && col <= colMax; } |
87 | | - [[nodiscard]] auto rowSpan() const { return rowMax - rowMin + 1; } |
88 | | - [[nodiscard]] auto colSpan() const { return colMax - colMin + 1; } |
89 | | - bool isAcceptableSize() const { return colMax - colMin < o2::itsmft::ClusterPattern::MaxColSpan && rowMax - rowMin < o2::itsmft::ClusterPattern::MaxRowSpan; } |
90 | | - void clear() |
91 | | - { |
92 | | - rowMin = colMin = 0xffff; |
93 | | - rowMax = colMax = 0; |
94 | | - } |
95 | | - void adjust(uint16_t row, uint16_t col) |
96 | | - { |
97 | | - if (row < rowMin) { |
98 | | - rowMin = row; |
99 | | - } |
100 | | - if (row > rowMax) { |
101 | | - rowMax = row; |
102 | | - } |
103 | | - if (col < colMin) { |
104 | | - colMin = col; |
105 | | - } |
106 | | - if (col > colMax) { |
107 | | - colMax = col; |
108 | | - } |
109 | | - } |
110 | | - }; |
111 | | - |
112 | | - //========================================================= |
113 | | - /// methods and transient data used within a thread |
114 | | - struct ThreadStat { |
115 | | - uint16_t firstChip = 0; |
116 | | - uint16_t nChips = 0; |
117 | | - uint32_t firstClus = 0; |
118 | | - uint32_t firstPatt = 0; |
119 | | - uint32_t nClus = 0; |
120 | | - uint32_t nPatt = 0; |
121 | | - }; |
122 | | - |
123 | | - struct ClustererThread { |
124 | | - Clusterer* parent = nullptr; // parent clusterer |
125 | | - int id = -1; |
126 | | - // buffers for entries in preClusterIndices in 2 columns, to avoid boundary checks, we reserve |
127 | | - // extra elements in the beginning and the end |
128 | | - int* column1 = nullptr; |
129 | | - int* column2 = nullptr; |
130 | | - int* curr = nullptr; // pointer on the 1st row of currently processed columnsX |
131 | | - int* prev = nullptr; // pointer on the 1st row of previously processed columnsX |
132 | | - int size = itsmft::SegmentationAlpide::NRows + 2; |
133 | | - // pixels[].first is the index of the next pixel of the same precluster in the pixels |
134 | | - // pixels[].second is the index of the referred pixel in the ChipPixelData (element of mChips) |
135 | | - std::vector<std::pair<int, uint32_t>> pixels; |
136 | | - std::vector<int> preClusterHeads; // index of precluster head in the pixels |
137 | | - std::vector<int> preClusterIndices; |
138 | | - uint16_t currCol = 0xffff; ///< Column being processed |
139 | | - bool noLeftCol = true; ///< flag that there is no column on the left to check |
140 | | - std::array<Label, MaxLabels> labelsBuff; //! temporary buffer for building cluster labels |
141 | | - std::vector<PixelData> pixArrBuff; //! temporary buffer for pattern calc. |
142 | | - // |
143 | | - /// temporary storage for the thread output |
144 | | - CompClusCont compClusters; |
145 | | - PatternCont patterns; |
146 | | - MCTruth labels; |
147 | | - std::vector<ThreadStat> stats; // statistics for each thread results, used at merging |
148 | | - /// |
149 | | - ///< reset column buffer, for the performance reasons we use memset |
150 | | - void resetColumn(int* buff) const { std::memset(buff, -1, sizeof(int) * (size - 2)); } |
151 | | - |
152 | | - ///< swap current and previous column buffers |
153 | | - void swapColumnBuffers() { std::swap(prev, curr); } |
154 | | - |
155 | | - ///< add cluster at row (entry ip in the ChipPixeData) to the precluster with given index |
156 | | - void expandPreCluster(uint32_t ip, uint16_t row, int preClusIndex) |
157 | | - { |
158 | | - auto& firstIndex = preClusterHeads[preClusterIndices[preClusIndex]]; |
159 | | - pixels.emplace_back(firstIndex, ip); |
160 | | - firstIndex = pixels.size() - 1; |
161 | | - curr[row] = preClusIndex; |
162 | | - } |
163 | | - |
164 | | - ///< add new precluster at given row of current column for the fired pixel with index ip in the ChipPixelData |
165 | | - void addNewPrecluster(uint32_t ip, uint16_t row) |
166 | | - { |
167 | | - preClusterHeads.push_back(pixels.size()); |
168 | | - // new head does not point yet (-1) on other pixels, store just the entry of the pixel in the ChipPixelData |
169 | | - pixels.emplace_back(-1, ip); |
170 | | - int lastIndex = preClusterIndices.size(); |
171 | | - preClusterIndices.push_back(lastIndex); |
172 | | - curr[row] = lastIndex; // store index of the new precluster in the current column buffer |
173 | | - } |
174 | | - |
175 | | - void fetchMCLabels(int digID, const ConstMCTruth* labelsDig, int& nfilled); |
176 | | - void initChip(const ChipPixelData* curChipData, uint32_t first); |
177 | | - void updateChip(const ChipPixelData* curChipData, uint32_t ip); |
178 | | - void finishChip(ChipPixelData* curChipData, CompClusCont* compClus, PatternCont* patterns, |
179 | | - const ConstMCTruth* labelsDig, MCTruth* labelsClus); |
180 | | - void finishChipSingleHitFast(uint32_t hit, ChipPixelData* curChipData, CompClusCont* compClusPtr, |
181 | | - PatternCont* patternsPtr, const ConstMCTruth* labelsDigPtr, MCTruth* labelsClusPTr); |
182 | | - void process(uint16_t chip, uint16_t nChips, CompClusCont* compClusPtr, PatternCont* patternsPtr, |
183 | | - const ConstMCTruth* labelsDigPtr, MCTruth* labelsClPtr, const itsmft::ROFRecord& rofPtr); |
184 | 24 |
|
185 | | - ~ClustererThread() |
186 | | - { |
187 | | - delete[] column1; |
188 | | - delete[] column2; |
189 | | - } |
| 25 | +static_assert(o2::itsmft::SegmentationAlpide::NRows >= SegmentationMosaix::NRows); |
| 26 | +using Clusterer = o2::itsmft::ClustererT<LookUp, o2::itsmft::SegmentationAlpide::NRows>; |
190 | 27 |
|
191 | | - ClustererThread(Clusterer* par = nullptr, int _id = -1) : parent(par), id(_id), curr(column2 + 1), prev(column1 + 1) {} |
192 | | - ClustererThread(const ClustererThread&) = delete; |
193 | | - ClustererThread(ClustererThread&&) = delete; |
194 | | - ClustererThread& operator=(const ClustererThread&) = delete; |
195 | | - ClustererThread& operator=(ClustererThread&&) = delete; |
196 | | - }; |
197 | | - //========================================================= |
| 28 | +} // namespace o2::its3 |
198 | 29 |
|
199 | | - Clusterer(); |
200 | | - Clusterer(Clusterer&&) = delete; |
201 | | - Clusterer& operator=(Clusterer&&) = delete; |
202 | | - ~Clusterer() = default; |
203 | | - Clusterer(const Clusterer&) = delete; |
204 | | - Clusterer& operator=(const Clusterer&) = delete; |
205 | | - |
206 | | - void process(int nThreads, PixelReader& r, CompClusCont* compClus, PatternCont* patterns, ROFRecCont* vecROFRec, MCTruth* labelsCl = nullptr); |
207 | | - |
208 | | - template <typename VCLUS, typename VPAT> |
209 | | - static void streamCluster(const std::vector<PixelData>& pixbuf, const std::array<Label, MaxLabels>* lblBuff, const BBox& bbox, const its3::LookUp& pattIdConverter, |
210 | | - VCLUS* compClusPtr, VPAT* patternsPtr, MCTruth* labelsClusPtr, int nlab, bool isIB, bool isHuge = false); |
211 | | - |
212 | | - bool isContinuousReadOut() const { return mContinuousReadout; } |
213 | | - void setContinuousReadOut(bool v) { mContinuousReadout = v; } |
214 | | - |
215 | | - int getMaxBCSeparationToMask() const { return mMaxBCSeparationToMask; } |
216 | | - void setMaxBCSeparationToMask(int n) { mMaxBCSeparationToMask = n; } |
217 | | - |
218 | | - int getMaxRowColDiffToMask() const { return mMaxRowColDiffToMask; } |
219 | | - void setMaxRowColDiffToMask(int v) { mMaxRowColDiffToMask = v; } |
220 | | - |
221 | | - int getMaxROFDepthToSquash() const { return mSquashingDepth; } |
222 | | - void setMaxROFDepthToSquash(int v) { mSquashingDepth = v; } |
223 | | - |
224 | | - int getMaxBCSeparationToSquash() const { return mMaxBCSeparationToSquash; } |
225 | | - void setMaxBCSeparationToSquash(int n) { mMaxBCSeparationToSquash = n; } |
226 | | - |
227 | | - void print() const; |
228 | | - void clear(); |
229 | | - |
230 | | - ///< load the dictionary of cluster topologies |
231 | | - void setDictionary(const its3::TopologyDictionary* dict) |
232 | | - { |
233 | | - LOGP(info, "Setting TopologyDictionary with IB size={} & OB size={}", dict->getSize(true), dict->getSize(false)); |
234 | | - mPattIdConverter.setDictionary(dict); |
235 | | - // dict->print(); |
236 | | - } |
237 | | - |
238 | | - TStopwatch& getTimer() { return mTimer; } // cannot be const |
239 | | - TStopwatch& getTimerMerge() { return mTimerMerge; } // cannot be const |
240 | | - |
241 | | - void setNChips(int n) |
242 | | - { |
243 | | - mChips.resize(n); |
244 | | - mChipsOld.resize(n); |
245 | | - } |
246 | | - |
247 | | - private: |
248 | | - void flushClusters(CompClusCont* compClus, MCTruth* labels); |
249 | | - |
250 | | - // clusterization options |
251 | | - bool mContinuousReadout = true; ///< flag continuous readout |
252 | | - |
253 | | - ///< mask continuosly fired pixels in frames separated by less than this amount of BCs (fired from hit in prev. ROF) |
254 | | - int mMaxBCSeparationToMask = static_cast<int>(6000. / o2::constants::lhc::LHCBunchSpacingNS + 10); |
255 | | - int mMaxRowColDiffToMask = 0; ///< provide their difference in col/row is <= than this |
256 | | - int mNHugeClus = 0; ///< number of encountered huge clusters |
257 | | - |
258 | | - ///< Squashing options |
259 | | - int mSquashingDepth = 0; ///< squashing is applied to next N rofs |
260 | | - int mMaxBCSeparationToSquash = 6000. / o2::constants::lhc::LHCBunchSpacingNS + 10; |
261 | | - |
262 | | - std::vector<std::unique_ptr<ClustererThread>> mThreads; // buffers for threads |
263 | | - std::vector<ChipPixelData> mChips; // currently processed ROF's chips data |
264 | | - std::vector<ChipPixelData> mChipsOld; // previously processed ROF's chips data (for masking) |
265 | | - std::vector<ChipPixelData*> mFiredChipsPtr; // pointers on the fired chips data in the decoder cache |
266 | | - |
267 | | - its3::LookUp mPattIdConverter; //! Convert the cluster topology to the corresponding entry in the dictionary. |
268 | | - // |
269 | | -#ifdef _PERFORM_TIMING_ |
270 | | - TStopwatch mTimer; |
271 | | - TStopwatch mTimerMerge; |
272 | 30 | #endif |
273 | | -}; |
274 | | - |
275 | | -template <typename VCLUS, typename VPAT> |
276 | | -void Clusterer::streamCluster(const std::vector<PixelData>& pixbuf, const std::array<Label, MaxLabels>* lblBuff, const Clusterer::BBox& bbox, const its3::LookUp& pattIdConverter, |
277 | | - VCLUS* compClusPtr, VPAT* patternsPtr, MCTruth* labelsClusPtr, int nlab, bool isIB, bool isHuge) |
278 | | -{ |
279 | | - if (labelsClusPtr && lblBuff) { // MC labels were requested |
280 | | - auto cnt = compClusPtr->size(); |
281 | | - for (int i = nlab; i--;) { |
282 | | - labelsClusPtr->addElement(cnt, (*lblBuff)[i]); |
283 | | - } |
284 | | - } |
285 | | - auto colSpanW = bbox.colSpan(); |
286 | | - auto rowSpanW = bbox.rowSpan(); |
287 | | - // add to compact clusters, which must be always filled |
288 | | - std::array<unsigned char, itsmft::ClusterPattern::MaxPatternBytes> patt{}; |
289 | | - for (const auto& pix : pixbuf) { |
290 | | - uint32_t ir = pix.getRowDirect() - bbox.rowMin, ic = pix.getCol() - bbox.colMin; |
291 | | - int nbits = ir * colSpanW + ic; |
292 | | - patt[nbits >> 3] |= (0x1 << (7 - (nbits % 8))); |
293 | | - } |
294 | | - uint16_t pattID = (isHuge || pattIdConverter.size(isIB) == 0) ? CompCluster::InvalidPatternID : pattIdConverter.findGroupID(rowSpanW, colSpanW, isIB, patt.data()); |
295 | | - uint16_t row = bbox.rowMin, col = bbox.colMin; |
296 | | - LOGP(debug, "PattID: findGroupID({},{},{})={}", row, col, patt[0], pattID); |
297 | | - if (pattID == CompCluster::InvalidPatternID || pattIdConverter.isGroup(pattID, isIB)) { |
298 | | - if (pattID != CompCluster::InvalidPatternID) { |
299 | | - // For groupped topologies, the reference pixel is the COG pixel |
300 | | - float xCOG = 0., zCOG = 0.; |
301 | | - itsmft::ClusterPattern::getCOG(rowSpanW, colSpanW, patt.data(), xCOG, zCOG); |
302 | | - row += round(xCOG); |
303 | | - col += round(zCOG); |
304 | | - } |
305 | | - if (patternsPtr) { |
306 | | - patternsPtr->emplace_back((unsigned char)rowSpanW); |
307 | | - patternsPtr->emplace_back((unsigned char)colSpanW); |
308 | | - int nBytes = rowSpanW * colSpanW / 8; |
309 | | - if (((rowSpanW * colSpanW) % 8) != 0) { |
310 | | - nBytes++; |
311 | | - } |
312 | | - patternsPtr->insert(patternsPtr->end(), std::begin(patt), std::begin(patt) + nBytes); |
313 | | - } |
314 | | - } |
315 | | - compClusPtr->emplace_back(row, col, pattID, bbox.chipID); |
316 | | -} |
317 | | - |
318 | | -} // namespace its3 |
319 | | -} // namespace o2 |
320 | | -#endif /* ALICEO2_ITS_CLUSTERER_H */ |
0 commit comments