Project
Loading...
Searching...
No Matches
Clusterer.cxx
Go to the documentation of this file.
1// Copyright 2019-2026 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
15#include "Framework/Logger.h"
16
18
19#include <algorithm>
20#include <numeric>
21
22namespace o2::iotof
23{
24
25//__________________________________________________
26void Clusterer::process(gsl::span<const Digit> digits,
27 gsl::span<const DigROFRecord> digitROFs,
28 std::vector<o2::iotof::Cluster>& clusters,
29 std::vector<unsigned char>& patterns,
30 std::vector<o2::itsmft::ROFRecord>& clusterROFs,
31 const ConstDigitTruth* digitLabels,
32 ClusterTruth* clusterLabels,
33 gsl::span<const DigMC2ROFRecord> digMC2ROFs,
34 std::vector<o2::itsmft::MC2ROFRecord>* clusterMC2ROFs)
35{
36 LOG(info) << "Running clusterizer on " << digitROFs.size() << " ROFs, total digits: " << digits.size();
37
38 if (!mThread) {
39 mThread = std::make_unique<ClustererThread>(this);
40 }
41
42 for (size_t iROF = 0; iROF < digitROFs.size(); ++iROF) {
43 LOG(debug) << "Processing digit ROF " << iROF << "/" << digitROFs.size();
44 const auto& inROF = digitROFs[iROF];
45 const auto outFirst = static_cast<int>(clusters.size());
46 const int first = inROF.getFirstEntry();
47 const int nEntries = inROF.getNEntries();
48
49 if (nEntries == 0) {
50 LOG(debug) << "Digit ROF " << iROF << " has no entries, skipping";
51 clusterROFs.emplace_back(inROF.getBCData(), inROF.getROFrame(), outFirst, 0);
52 continue;
53 }
54
55 // Sort digit indices within this ROF by (chipID, col, row)
56 // chip by chip, column by column (taken from TRK).
57 mSortIdx.resize(nEntries);
58 std::iota(mSortIdx.begin(), mSortIdx.end(), first);
59 std::sort(mSortIdx.begin(), mSortIdx.end(), [&digits](int a, int b) {
60 const auto& da = digits[a];
61 const auto& db = digits[b];
62 if (da.getChipIndex() != db.getChipIndex()) {
63 return da.getChipIndex() < db.getChipIndex();
64 }
65 if (da.getColumn() != db.getColumn()) {
66 return da.getColumn() < db.getColumn();
67 }
68 return da.getRow() < db.getRow();
69 });
70 LOG(debug) << "Found " << nEntries << " digits for ROF " << iROF;
71
72 // Process blocks of chips with the same chipID
73 int sliceStart = 0;
74 while (sliceStart < nEntries) {
75 const int chipFirst = sliceStart;
76 const uint16_t chipID = digits[mSortIdx[sliceStart]].getChipIndex();
77 while (sliceStart < nEntries && digits[mSortIdx[sliceStart]].getChipIndex() == chipID) {
78 ++sliceStart;
79 }
80 const int chipN = sliceStart - chipFirst;
81
82 LOG(debug) << "Processing chip " << chipID << " with " << chipN << " digits, next chip start from index " << sliceStart;
83 mThread->processChip(digits, chipFirst, chipN, &clusters, &patterns, digitLabels, clusterLabels);
84 }
85
86 LOG(debug) << "Finished processing digit ROF " << iROF << ", produced " << (clusters.size() - outFirst) << " clusters";
87 clusterROFs.emplace_back(inROF.getBCData(), inROF.getROFrame(),
88 outFirst, static_cast<int>(clusters.size()) - outFirst);
89 }
90
91 LOG(info) << "Finished processing all digit ROFs, total clusters produced: " << clusters.size();
92 if (clusterMC2ROFs && !digMC2ROFs.empty()) {
93 clusterMC2ROFs->reserve(clusterMC2ROFs->size() + digMC2ROFs.size());
94 for (const auto& in : digMC2ROFs) {
95 clusterMC2ROFs->emplace_back(in.eventRecordID, in.rofRecordID, in.minROF, in.maxROF);
96 }
97 }
98}
99
100//__________________________________________________
101void Clusterer::ClustererThread::processChip(gsl::span<const Digit> digits,
102 int chipFirst, int chipN,
103 std::vector<Cluster>* clustersOut,
104 std::vector<unsigned char>* patternsOut,
105 const ConstDigitTruth* labelsDigPtr,
106 ClusterTruth* labelsClusPtr)
107{
108 // chipFirst and chipN are relative to mSortIdx (i.e. mSortIdx[chipFirst..chipFirst+chipN-1]
109 // are the global digit indices for this chip, already sorted by col then row).
110 // We use parent->mSortIdx to resolve the global index of each pixel.
111 const auto& sortIdx = parent->mSortIdx;
112
113 // TRK has per-ROF readout, so multiple hits belonging to the same chip, i.e. chipN > 1,
114 // are handled with a preclusterer. TF3 still does not have per-ROF readout, so we
115 // use finishChipSingleHitFast on all hits for now.
116 for (auto i = 0; i < chipN; ++i) {
117 finishChipSingleHitFast(digits, sortIdx[chipFirst + i], labelsDigPtr, labelsClusPtr);
118 }
119
120 // // TRK logic for per-ROF readout, not used for TF3 yet.
121 // if (chipN == 1) {
122 // LOG(debug) << "Processing single hit chip";
123 // finishChipSingleHitFast(digits, sortIdx[chipFirst], labelsDigPtr, labelsClusPtr);
124 // } else {
125 // LOG(debug) << "Processing multi-hit chip with " << chipN << " hits";
126 // // Call to initChip()
127 // // Call to updateChip()
128 // // Call to finishChip()
129 // // Code for preclusters needed
130 // }
131
132 // Flush per-thread output into the caller's containers
133 if (!clusters.empty()) {
134 clustersOut->insert(clustersOut->end(), clusters.begin(), clusters.end());
135 clusters.clear();
136 }
137 if (!patterns.empty()) {
138 patternsOut->insert(patternsOut->end(), patterns.begin(), patterns.end());
139 patterns.clear();
140 }
141 if (labelsClusPtr && labels.getNElements()) {
142 labelsClusPtr->mergeAtBack(labels);
143 labels.clear();
144 }
145}
146
147//__________________________________________________
148void Clusterer::ClustererThread::finishChipSingleHitFast(gsl::span<const Digit> digits,
149 uint32_t digitIdx,
150 const ConstDigitTruth* labelsDigPtr,
151 ClusterTruth* labelsClusPtr)
152{
153 const auto& digit = digits[digitIdx];
154 const uint16_t chipID = digit.getChipIndex();
155 const uint16_t row = digit.getRow();
156 const uint16_t col = digit.getColumn();
157 const double time = digit.getTime();
158
159 if (labelsClusPtr) {
160 int nlab = 0;
161 fetchMCLabels(digitIdx, labelsDigPtr, nlab);
162 const auto cnt = static_cast<uint32_t>(clusters.size());
163 for (int i = nlab; i--;) {
164 labels.addElement(cnt, labelsBuff[i]);
165 }
166 }
167
168 // 1×1 pattern: rowSpan=1, colSpan=1, one byte = 0x80
169 patterns.emplace_back(1);
170 patterns.emplace_back(1);
171 patterns.emplace_back(0x80);
172
173 Cluster cluster;
174 cluster.chipID = chipID;
175 cluster.row = row;
176 cluster.col = col;
177 cluster.size = 1;
178 cluster.time = time;
179 clusters.emplace_back(cluster);
180}
181
182//__________________________________________________
183void Clusterer::ClustererThread::fetchMCLabels(uint32_t digID, const ConstDigitTruth* labelsDig, int& nfilled)
184{
185 if (nfilled >= MaxLabels) {
186 return;
187 }
188 if (!labelsDig || digID >= labelsDig->getIndexedSize()) {
189 return;
190 }
191 const auto& lbls = labelsDig->getLabels(digID);
192 for (int i = lbls.size(); i--;) {
193 int ic = nfilled;
194 for (; ic--;) {
195 if (labelsBuff[ic] == lbls[i]) {
196 return; // already present
197 }
198 }
199 labelsBuff[nfilled++] = lbls[i];
200 if (nfilled >= MaxLabels) {
201 break;
202 }
203 }
204}
205
206} // namespace o2::iotof
std::vector< std::string > labels
std::ostringstream debug
int16_t time
Definition RawEventData.h:4
int32_t i
uint32_t col
Definition RawData.h:4
Definition of the IOTOF cluster finder.
gsl::span< const TruthElement > getLabels(uint32_t dataindex) const
void mergeAtBack(MCTruthContainer< TruthElement > const &other)
virtual void process(gsl::span< const Digit > digits, gsl::span< const DigROFRecord > digitROFs, std::vector< o2::iotof::Cluster > &clusters, std::vector< unsigned char > &patterns, std::vector< o2::itsmft::ROFRecord > &clusterROFs, const ConstDigitTruth *digitLabels=nullptr, ClusterTruth *clusterLabels=nullptr, gsl::span< const DigMC2ROFRecord > digMC2ROFs={}, std::vector< o2::itsmft::MC2ROFRecord > *clusterMC2ROFs=nullptr)
Definition Clusterer.cxx:26
std::vector< int > mSortIdx
reusable per-ROF sort buffer
Definition Clusterer.h:89
std::unique_ptr< ClustererThread > mThread
Definition Clusterer.h:88
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
uint16_t chipID
Definition Cluster.h:23
uint16_t size
Definition Cluster.h:26
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Cluster > clusters
std::vector< Digit > digits
std::vector< int > row