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,
33 gsl::span<const DigMC2ROFRecord> digMC2ROFs,
34 std::vector<o2::itsmft::MC2ROFRecord>* clusterMC2ROFs)
36 LOG(info) <<
"RUNNING CLUSTERIZER ON " << digitROFs.size() <<
" ROFs, TOTAL DIGITS: " <<
digits.size();
39 mThread = std::make_unique<ClustererThread>(
this);
42 for (
size_t iROF = 0; iROF < digitROFs.size(); ++iROF) {
43 LOG(
debug) <<
"Processing ROF " << iROF <<
"/" << digitROFs.size();
44 const auto& digitsThisROF = digitROFs[iROF];
45 const auto nStoredCls =
static_cast<int>(
clusters.size());
46 const int first = digitsThisROF.getFirstEntry();
47 const int nDigits = digitsThisROF.getNEntries();
50 clusterROFs.emplace_back(digitsThisROF.getBCData(), digitsThisROF.getROFrame(), nStoredCls, 0);
59 const auto& da = digits[a];
60 const auto& db = digits[b];
61 if (da.getChipIndex() != db.getChipIndex()) {
62 return da.getChipIndex() < db.getChipIndex();
64 if (da.getRow() != db.getRow()) {
65 return da.getRow() < db.getRow();
67 if (da.getColumn() != db.getColumn()) {
68 return da.getColumn() < db.getColumn();
70 return da.getTime() < db.getTime();
72 LOG(
debug) <<
"Found " << nDigits <<
" digits for ROF " << iROF;
76 while (iDigit < nDigits) {
77 const int firstDigit = iDigit;
81 while (iDigit < nDigits &&
digits[
mSortIdx[iDigit]].getChipIndex() == chipID) {
84 const int nDigitsThisChip = iDigit - firstDigit;
86 LOG(
debug) <<
"Processing chip " << chipID <<
" with " << nDigitsThisChip <<
" digits, next digit starts from index " << iDigit;
87 mThread->processChip(
digits, firstDigit, nDigitsThisChip, &
clusters, &patterns, digitLabels, clusterLabels);
90 LOG(
debug) <<
"Finished processing digit ROF " << iROF <<
", produced " << (
clusters.size() - nStoredCls) <<
" clusters";
91 clusterROFs.emplace_back(digitsThisROF.getBCData(), digitsThisROF.getROFrame(),
92 nStoredCls,
static_cast<int>(
clusters.size()) - nStoredCls);
95 LOG(info) <<
"FINISHED PROCESSING ALL DIGIT ROFS, TOTAL CLUSTERS PRODUCED: " <<
clusters.size();
96 if (clusterMC2ROFs && !digMC2ROFs.empty()) {
97 clusterMC2ROFs->reserve(clusterMC2ROFs->size() + digMC2ROFs.size());
98 for (
const auto& in : digMC2ROFs) {
99 clusterMC2ROFs->emplace_back(in.eventRecordID, in.rofRecordID, in.minROF, in.maxROF);
103 LOG(info) <<
"WRITING CLUSTER TOPOLOGY MAP TO FILE TF3ClusterTopologies.root";
104 mThread->writeTopologiesToFile(
"TF3ClusterTopologies.root");
108void Clusterer::ClustererThread::processChip(gsl::span<const Digit>
digits,
109 int firstDigitIdx,
int nDigits,
110 std::vector<Cluster>* clustersOut,
111 std::vector<unsigned char>* patternsOut,
118 const auto& sortIdx = mParent->mSortIdx;
121 findClustersSingleHit(
digits, sortIdx[firstDigitIdx], labelsDigPtr, labelsClusPtr);
123 std::vector<uint32_t> digitIdxs(nDigits);
125 for (
int i = 0;
i < nDigits; ++
i) {
126 digitIdxs[
i] = sortIdx[firstDigitIdx +
i];
129 findClustersMultipleHits(
131 gsl::span<const uint32_t>(digitIdxs),
142 const size_t base = clustersOut->size();
144 for (
size_t i = 0;
i < mClusters.size(); ++
i) {
145 auto labels = mLabels.getLabels(
i);
149 for (
const auto& l :
labels) {
157 if (!mClusters.empty()) {
158 clustersOut->insert(clustersOut->end(), mClusters.begin(), mClusters.end());
161 if (!mPatterns.empty()) {
162 patternsOut->insert(patternsOut->end(), mPatterns.begin(), mPatterns.end());
168void Clusterer::ClustererThread::findClustersSingleHit(gsl::span<const Digit>
digits,
173 const auto& digit =
digits[digitIdx];
174 const uint16_t chipID = digit.getChipIndex();
175 const uint16_t
row = digit.getRow();
176 const uint16_t
col = digit.getColumn();
177 const time_t
time = digit.getTime();
180 int nStoredLabels = 0;
181 fetchMCLabels(digitIdx, labelsDigPtr, nStoredLabels);
182 const auto nCls =
static_cast<uint32_t
>(mClusters.size());
183 for (
int i = 0;
i < nStoredLabels;
i++) {
184 mLabels.addElement(nCls, mLabelsBuff[
i]);
188 const uint16_t minRow =
row;
189 const uint16_t minCol =
col;
190 uint8_t rowSpan{1}, colSpan{1};
191 uint32_t clsTopology{0};
192 constexpr uint16_t firedDigitsMask = (1U << 0);
193 mClsTopoClassifier.getTopology(firedDigitsMask, minRow, rowSpan, minCol, colSpan, clsTopology);
195 Cluster cluster(
row,
col, rowSpan, colSpan, firedDigitsMask, clsTopology, chipID,
time);
197 LOG(
debug) <<
"Pushing back cluster with row: " <<
row <<
", col: " <<
col
198 <<
", rowSpan: " <<
static_cast<int>(rowSpan) <<
", colSpan: " <<
static_cast<int>(colSpan)
199 <<
", pattern: " << firedDigitsMask <<
", topology: " <<
static_cast<int>(clsTopology)
200 <<
", chipID: " << chipID <<
", time: " <<
time;
202 mClusters.emplace_back(cluster);
203 mPatterns.emplace_back(
static_cast<unsigned char>(firedDigitsMask));
206std::vector<std::vector<uint32_t>> Clusterer::ClustererThread::buildPreclusters(gsl::span<const Digit>
digits, gsl::span<const uint32_t> digitIdxs,
int maxTimeDiffNSigma,
float timeResolution)
208 std::vector<std::vector<uint32_t>> preclusters;
209 std::vector<bool> used(digitIdxs.size(),
false);
211 auto areNeighbours = [&](
const Digit&
a,
const Digit&
b) {
212 return std::abs(
static_cast<int>(
a.getRow()) -
static_cast<int>(
b.getRow())) <= 1 &&
213 std::abs(
static_cast<int>(
a.getColumn()) -
static_cast<int>(
b.getColumn())) <= 1 &&
214 std::abs(
a.getTime() -
b.getTime()) <= maxTimeDiffNSigma * timeResolution;
217 for (
size_t i = 0;
i < digitIdxs.size(); ++
i) {
222 std::vector<uint32_t> precluster;
223 std::vector<size_t> toVisit{
i};
226 while (!toVisit.empty()) {
227 const size_t cur = toVisit.back();
229 precluster.push_back(digitIdxs[cur]);
232 for (
size_t j = 0;
j < digitIdxs.size(); ++
j) {
233 if (!used[
j] && areNeighbours(
digits[digitIdxs[cur]],
digits[digitIdxs[
j]])) {
235 toVisit.push_back(
j);
240 preclusters.push_back(std::move(precluster));
246void Clusterer::ClustererThread::findClustersMultipleHits(gsl::span<const Digit>
digits,
247 gsl::span<const uint32_t> digitIdxs,
254 float timeResolution = digitizerParams.timeResolution;
256 int maxTimeDiffNSigma = clustererParams.maxTimeDiffNSigma;
257 int maxFiredDigitsForCls = clustererParams.maxFiredDigitsForCls;
261 std::vector<std::vector<uint32_t>> preclusters = buildPreclusters(
digits, digitIdxs, maxTimeDiffNSigma, timeResolution);
262 uint16_t chipID =
digits[digitIdxs[0]].getChipIndex();
264 for (
const auto& precluster : preclusters) {
266 const auto nStoredCls =
static_cast<uint32_t
>(mClusters.size());
269 if (precluster.size() == 1) {
270 const auto& digit =
digits[precluster[0]];
271 const uint16_t
row = digit.getRow();
272 const uint16_t
col = digit.getColumn();
273 const time_t
time = digit.getTime();
277 fetchMCLabels(precluster[0], labelsDigPtr, nMcLabels);
278 for (
int i = nMcLabels;
i--;) {
279 mLabels.addElement(nStoredCls, mLabelsBuff[
i]);
283 const uint16_t minRow =
row;
284 const uint16_t minCol =
col;
285 uint8_t rowSpan{1}, colSpan{1};
286 uint32_t clsTopology{0};
288 constexpr uint16_t firedDigitsMask = (1U << 0);
289 mClsTopoClassifier.getTopology(firedDigitsMask, minRow, rowSpan, minCol, colSpan, clsTopology);
291 Cluster cluster(minRow, minCol, rowSpan, colSpan, firedDigitsMask, clsTopology, chipID,
time);
293 LOG(
debug) <<
"Pushing back cluster with row: " <<
row <<
", col: " <<
col
294 <<
", rowSpan: " <<
static_cast<int>(rowSpan) <<
", colSpan: " <<
static_cast<int>(colSpan)
295 <<
", pattern: " << firedDigitsMask <<
", topology: " <<
static_cast<int>(clsTopology)
296 <<
", chipID: " << chipID <<
", time: " <<
time;
298 mClusters.emplace_back(cluster);
299 mPatterns.emplace_back(
static_cast<unsigned char>(firedDigitsMask));
302 uint16_t minRow = std::numeric_limits<uint16_t>::max();
303 uint16_t maxRow = std::numeric_limits<uint16_t>::min();
304 uint16_t minCol = std::numeric_limits<uint16_t>::max();
305 uint16_t maxCol = std::numeric_limits<uint16_t>::min();
310 time_t clsTime = 0.0;
311 for (
const auto& idx : precluster) {
312 const auto& digit =
digits[idx];
313 minRow = std::min(minRow, digit.getRow());
314 minCol = std::min(minCol, digit.getColumn());
315 maxRow = std::max(maxRow, digit.getRow());
316 maxCol = std::max(maxCol, digit.getColumn());
317 clsTime += digit.getTime();
318 fetchMCLabels(idx, labelsDigPtr, nMcLabels);
320 clsTime /= precluster.size();
321 const uint8_t rowSpan = maxRow - minRow + 1;
322 const uint8_t colSpan = maxCol - minCol + 1;
325 uint16_t firedDigitsMask = 0;
327 if (rowSpan * colSpan > maxFiredDigitsForCls) {
329 Cluster cluster(minRow, minCol, rowSpan, colSpan, Cluster::InvalidPatternID, Topologies::kHuge, chipID, clsTime);
330 mClusters.emplace_back(cluster);
331 mPatterns.emplace_back(Cluster::InvalidPatternID);
336 for (
const auto& idx : precluster) {
337 const auto& digit =
digits[idx];
338 const uint16_t rowOffset = digit.getRow() - minRow;
339 const uint16_t colOffset = digit.getColumn() - minCol;
342 const uint16_t bitIndex = rowOffset * colSpan + colOffset;
345 if (bitIndex < ClusterInfo::NBitsPattern) {
346 firedDigitsMask |= (1U << bitIndex);
350 uint32_t clsTopology{0};
351 mClsTopoClassifier.getTopology(firedDigitsMask, minRow, rowSpan, minCol, colSpan, clsTopology);
354 for (
int i = 0;
i < nMcLabels;
i++) {
355 mLabels.addElement(nStoredCls, mLabelsBuff[
i]);
357 Cluster cluster(minRow, minCol, rowSpan, colSpan, firedDigitsMask, clsTopology, chipID, clsTime);
358 LOG(
debug) <<
"Pushing back cluster with row: " << minRow <<
", col: " << minCol
359 <<
", rowSpan: " <<
static_cast<int>(rowSpan) <<
", colSpan: " <<
static_cast<int>(colSpan)
360 <<
", pattern: " << firedDigitsMask <<
", topology: " <<
static_cast<int>(clsTopology)
361 <<
", chipID: " << chipID <<
", time: " << clsTime;
362 mClusters.emplace_back(cluster);
363 mPatterns.emplace_back(
static_cast<unsigned char>(firedDigitsMask));
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)