30#ifdef _PERFORM_TIMING_
50 const int MaxErrLog = 2;
51 static int errLocCount = 0;
52 if (errLocCount++ < MaxErrLog) {
53 LOGP(warn,
"Impossible ROF IR {}, does not exceed previous {}, discarding in clusterization", reader.
getInteractionRecord().
asString(), lastIR.asString());
60 mFiredChipsPtr.clear();
63 mFiredChipsPtr.push_back(curChipData);
64 nPix += curChipData->
getData().size();
67 auto& rof = vecROFRec->emplace_back(reader.
getInteractionRecord(), vecROFRec->size(), compClus->size(), 0);
69 uint16_t nFired = mFiredChipsPtr.size();
76 if (nFired < nThreads) {
82 uint16_t chipStep = nThreads > 1 ? (nThreads == 2 ? 20 : 10) : nFired;
83 int dynGrp = std::min(4, std::max(1, nThreads / 2));
84 if (nThreads > mThreads.size()) {
85 int oldSz = mThreads.size();
86 mThreads.resize(nThreads);
87 for (
int i = oldSz;
i < nThreads;
i++) {
88 mThreads[
i] = std::make_unique<ClustererThread>(
this,
i);
92#pragma omp parallel for schedule(dynamic, dynGrp) num_threads(nThreads)
94 for (uint16_t ic = 0; ic < nFired; ic += chipStep) {
95 auto ith = omp_get_thread_num();
97 mThreads[ith]->process(ic, std::min(chipStep, uint16_t(nFired - ic)),
98 &mThreads[ith]->compClusters,
99 patterns ? &mThreads[ith]->patterns :
nullptr,
101 labelsCl ? &mThreads[ith]->labels :
nullptr, rof);
103 mThreads[0]->process(0, nFired, compClus, patterns, labelsCl ? reader.
getDigitsMCTruth() :
nullptr, labelsCl, rof);
108 mThreads[0]->process(0, nFired, compClus, patterns, labelsCl ? reader.
getDigitsMCTruth() :
nullptr, labelsCl, rof);
112#ifdef _PERFORM_TIMING_
113 mTimerMerge.Start(
false);
115 size_t nClTot = 0, nPattTot = 0;
116 int chid = 0, thrStatIdx[nThreads];
117 for (
int ith = 0; ith < nThreads; ith++) {
118 std::sort(mThreads[ith]->stats.begin(), mThreads[ith]->stats.end(), [](
const ThreadStat&
a,
const ThreadStat&
b) { return a.firstChip < b.firstChip; });
120 nClTot += mThreads[ith]->compClusters.size();
121 nPattTot += mThreads[ith]->patterns.size();
123 compClus->reserve(nClTot);
125 patterns->reserve(nPattTot);
127 while (
chid < nFired) {
128 for (
int ith = 0; ith < nThreads; ith++) {
129 if (thrStatIdx[ith] >= mThreads[ith]->stats.size()) {
132 const auto& stat = mThreads[ith]->stats[thrStatIdx[ith]];
133 if (stat.firstChip ==
chid) {
136 if (stat.nClus > 0) {
137 const auto clbeg = mThreads[ith]->compClusters.begin() + stat.firstClus;
138 auto szold = compClus->size();
139 compClus->insert(compClus->end(), clbeg, clbeg + stat.nClus);
141 const auto ptbeg = mThreads[ith]->patterns.begin() + stat.firstPatt;
142 patterns->insert(patterns->end(), ptbeg, ptbeg + stat.nPatt);
151 for (
int ith = 0; ith < nThreads; ith++) {
152 mThreads[ith]->patterns.clear();
153 mThreads[ith]->compClusters.clear();
154 mThreads[ith]->labels.clear();
155 mThreads[ith]->stats.clear();
157#ifdef _PERFORM_TIMING_
161 mThreads[0]->stats.clear();
163 rof.setNEntries(compClus->size() - rof.getFirstEntry());
164 }
while (autoDecode);
166#ifdef _PERFORM_TIMING_
175 if (
stats.empty() ||
stats.back().firstChip +
stats.back().nChips != chip) {
176 stats.emplace_back(
ThreadStat{chip, 0, uint32_t(compClusPtr->size()), patternsPtr ? uint32_t(patternsPtr->size()) : 0, 0, 0});
178 for (
int ic = 0; ic < nChips; ic++) {
179 auto* curChipData =
parent->mFiredChipsPtr[chip + ic];
180 auto chipID = curChipData->getChipID();
181 if (
parent->mMaxBCSeparationToMask > 0) {
182 const auto& chipInPrevROF =
parent->mChipsOld[chipID];
184 parent->mMaxRowColDiffToMask ? curChipData->maskFiredInSample(
parent->mChipsOld[chipID],
parent->mMaxRowColDiffToMask) : curChipData->maskFiredInSample(
parent->mChipsOld[chipID]);
187 auto nclus0 = compClusPtr->size();
188 auto validPixID = curChipData->getFirstUnmasked();
189 auto npix = curChipData->getData().size();
190 if (validPixID < npix) {
191 auto valp = validPixID++;
192 if (validPixID == npix) {
196 for (; validPixID < npix; validPixID++) {
197 if (!curChipData->getData()[validPixID].isMasked()) {
201 finishChip(curChipData, compClusPtr, patternsPtr, labelsDigPtr, labelsClPtr);
204 if (
parent->mMaxBCSeparationToMask > 0) {
205 parent->mChipsOld[chipID].swap(*curChipData);
208 auto& currStat =
stats.back();
209 currStat.nChips += nChips;
210 currStat.nClus = compClusPtr->size() - currStat.firstClus;
211 currStat.nPatt = patternsPtr ? (patternsPtr->size() - currStat.firstPatt) : 0;
218 const auto& pixData = curChipData->
getData();
219 int nPreclusters = preClusters.size();
221 for (
int i = 1;
i < nPreclusters;
i++) {
222 if (preClusters[
i].
index !=
i) {
223 preClusters[
i].index = preClusters[preClusters[
i].index].index;
226 for (
int i1 = 0; i1 < nPreclusters; ++i1) {
227 auto& preCluster = preClusters[i1];
228 auto ci = preCluster.index;
234 int next = preCluster.head;
237 const auto& pixEntry =
pixels[next];
238 const auto pix = pixData[pixEntry.second];
239 pixArrBuff.push_back(pix);
240 bbox.adjust(pix.getRowDirect(), pix.getCol());
242 if (parent->mSquashingDepth) {
243 fetchMCLabels(curChipData->
getOrderedPixId(pixEntry.second), labelsDigPtr, nlab);
245 fetchMCLabels(pixEntry.second + curChipData->
getStartID(), labelsDigPtr, nlab);
248 next = pixEntry.first;
250 preCluster.index = -1;
251 for (
int i2 = i1 + 1; i2 < nPreclusters; ++i2) {
252 auto& preCluster2 = preClusters[i2];
253 if (preCluster2.index != ci) {
256 next = preCluster2.head;
258 const auto& pixEntry =
pixels[next];
259 const auto pix = pixData[pixEntry.second];
260 pixArrBuff.push_back(pix);
261 bbox.adjust(pix.getRowDirect(), pix.getCol());
263 if (parent->mSquashingDepth) {
264 fetchMCLabels(curChipData->
getOrderedPixId(pixEntry.second), labelsDigPtr, nlab);
266 fetchMCLabels(pixEntry.second + curChipData->
getStartID(), labelsDigPtr, nlab);
269 next = pixEntry.first;
271 preCluster2.index = -1;
273 if (
bbox.isAcceptableSize()) {
274 parent->streamCluster(pixArrBuff, &labelsBuff,
bbox, parent->mPattIdConverter, compClusPtr, patternsPtr, labelsClusPtr, nlab);
277 if (!parent->mDropHugeClusters) {
279 LOGP(warn,
"Splitting a huge cluster: chipID {}, rows {}:{} cols {}:{}{}",
bbox.chipID,
bbox.rowMin,
bbox.rowMax,
bbox.colMin,
bbox.colMax,
280 warnLeft == 1 ?
" (Further warnings will be muted)" :
"");
285 parent->mNHugeClus++;
289 std::vector<PixelData> pixbuf;
295 for (
const auto& pix : pixArrBuff) {
296 if (bboxT.
isInside(pix.getRowDirect(), pix.getCol())) {
297 pixbuf.push_back(pix);
300 if (!pixbuf.empty()) {
301 parent->streamCluster(pixbuf, &labelsBuff, bboxT, parent->mPattIdConverter, compClusPtr, patternsPtr, labelsClusPtr, nlab,
true);
317 auto pix = curChipData->
getData()[hit];
318 uint16_t
row = pix.getRowDirect(),
col = pix.getCol();
322 fetchMCLabels(curChipData->
getStartID() + hit, labelsDigPtr, nlab);
323 auto cnt = compClusPtr->size();
324 for (
int i = nlab;
i--;) {
333 patternsPtr->emplace_back(1);
334 patternsPtr->emplace_back(1);
335 patternsPtr->insert(patternsPtr->end(), std::begin(patt), std::begin(patt) + 1);
372 const auto pix = curChipData->
getData()[ip];
373 uint16_t
row = pix.getRowDirect();
374 if (currCol != pix.getCol()) {
378 if (pix.getCol() > currCol + 1) {
381 currCol = pix.getCol();
382 addNewPrecluster(ip,
row);
386 currCol = pix.getCol();
390 if (curr[
row - 1] >= 0) {
391 expandPreCluster(ip,
row, curr[
row - 1]);
393 addNewPrecluster(ip,
row);
397 int nnb = 0, lowestIndex = curr[
row - 1], lowestNb = 0, *nbrCol[4], nbrRow[4];
398 if (lowestIndex >= 0) {
400 nbrRow[nnb++] =
row - 1;
402 lowestIndex = 0x7ffff;
405#ifdef _ALLOW_DIAGONAL_ALPIDE_CLUSTERS_
406 for (
int i : {-1, 0, 1}) {
407 auto v = prev[
row +
i];
410 nbrRow[nnb] =
row +
i;
411 if (
v < lowestIndex) {
419 if (prev[
row] >= 0) {
422 if (prev[
row] < lowestIndex) {
430 addNewPrecluster(ip,
row);
432 expandPreCluster(ip,
row, lowestIndex);
434 for (
int inb = 0; inb < nnb; inb++) {
435 auto& prevIndex = (nbrCol[inb])[nbrRow[inb]];
436 prevIndex = preClusters[prevIndex].index = lowestIndex;