29#define DPRINT(...) printf(__VA_ARGS__)
33#define DPRINTB_IF(test, ...) \
34 if (iThread == 0 && (test)) \
37#define DPRINT(...) ((void)0)
38#define DPRINTB(...) ((void)0)
39#define DPRINTB_IF(test, ...) ((void)0)
55 return filteredCharge +
alpha * (
charge - filteredCharge);
60 const float length = tail.
tailEnd > tail.tailStart ? float(tail.tailEnd - tail.tailStart) : 1.f;
61 return tail.tailStart + 0.5f * (
length - 1.f);
66 const float length = tail.tailEnd > tail.tailStart ? float(tail.tailEnd - tail.tailStart) : 1.f;
73static GPUdi() uint16_t CloseHIPTails(
74 Kernel::GPUSharedMemory& smem,
76 int32_t iThread, int32_t nThreads,
80 Kernel::PadChargeAccu& acc,
83 const uint32_t
row = basePos.row();
84 const uint16_t nClosedTails = work_group_count(shouldCloseTail);
86 auto* nHIPTails = clusterer.mPnHIPTails;
87 auto* hipTails = GetHIPTails(clusterer,
row);
89 if (nClosedTails > 0) {
90 int16_t iClosedTail = work_group_scan_inclusive_add((int16_t)shouldCloseTail) - 1;
91 const bool shouldStoreTail = shouldCloseTail && acc.activeHIPTail.Length() > 0;
92 uint16_t nStoredTails = work_group_count(shouldStoreTail);
93 int16_t iStoredTail = work_group_scan_inclusive_add((int16_t)shouldStoreTail) - 1;
97 if (nStoredTails > 0) {
99 smem.tailStoreBase = CAMath::AtomicAdd(&nHIPTails[
row], (uint32_t)nStoredTails);
103 if (shouldCloseTail) {
104 smem.tailsClosedPad[iClosedTail] = iPadHandle;
105 smem.tailsClosed[iClosedTail] = acc.activeHIPTail;
108 if (shouldStoreTail) {
109 const uint32_t
idx = smem.tailStoreBase + iStoredTail + 1;
110 smem.tailsClosedStoreIdx[iClosedTail] =
idx;
112 hipTails[
idx] = {0, 0, (uint16_t)iPadHandle,
113 (uint16_t)acc.activeHIPTail.start, (uint16_t)acc.activeHIPTail.end,
118 acc.tailFilterCharge = 0;
119 acc.activeHIPTail.Reset();
126 for (uint16_t iTail = 0; iTail < nClosedTails; iTail++) {
127 const auto tailPad = smem.tailsClosedPad[iTail];
128 const auto tail = smem.tailsClosed[iTail];
129 const uint32_t tailStoreIdx = smem.tailsClosedStoreIdx[iTail];
133 for (uint16_t iTime = iThread; iTime < tail.Length(); iTime += nThreads) {
134 const int16_t
time = tail.start + iTime;
135 auto pos = basePos.delta({tailPad,
time});
136 const Charge q = chargeMap[
pos].unpack();
138 qMax = CAMath::Max(qMax, q);
142 smem.tailQTotScratch[iThread] = qTot;
143 smem.tailQMaxScratch[iThread] = qMax;
148 smem.tailQTotScratch[iThread] += smem.tailQTotScratch[iThread +
stride];
149 smem.tailQMaxScratch[iThread] = CAMath::Max(smem.tailQMaxScratch[iThread], smem.tailQMaxScratch[iThread +
stride]);
157 tailDescriptor.
qTot = smem.tailQTotScratch[0];
158 tailDescriptor.
qMax = smem.tailQMaxScratch[0];
165template <
bool CheckHIPTrigger,
bool CheckHIPTailEnd>
166static GPUdi()
void ScanCachedCharges(
Kernel::GPUSharedMemory& smem, uint16_t timeOffset, uint16_t pad,
Charge hipTailThreshold,
Charge hipTailFilterAlpha,
Kernel::PadChargeAccu& acc)
169 const Charge qs = smem.charges[
i][pad];
170 const int16_t curTB = timeOffset +
i;
172 acc.totalCharges += qs > 0;
173 acc.consecCharges = qs > 0 ? acc.consecCharges + 1 : 0;
174 acc.maxConsecCharges = CAMath::Max(acc.consecCharges, acc.maxConsecCharges);
175 acc.maxCharge = CAMath::Max<Charge>(qs, acc.maxCharge);
177 if (qs >= hipTailThreshold) {
178 if (acc.aboveThresholdStart < 0) {
179 acc.aboveThresholdStart = curTB;
182 acc.aboveThresholdStart = -1;
185 if constexpr (CheckHIPTrigger) {
187 acc.HIPtb = acc.aboveThresholdStart;
188 smem.tails[pad] = {acc.HIPtb, 0};
192 if constexpr (CheckHIPTailEnd) {
193 if (acc.activeHIPTail.IsOpen()) {
194 acc.tailFilterCharge = UpdateHIPTailFilter(acc.tailFilterCharge, qs, hipTailFilterAlpha);
195 if (acc.tailFilterCharge < hipTailThreshold) {
196 acc.activeHIPTail.end = curTB;
207 CheckBaselineGPU(nBlocks, nThreads, iBlock, iThread, smem, clusterer);
209 CheckBaselineCPU(nBlocks, nThreads, iBlock, iThread, smem, clusterer);
219GPUd()
void GPUTPCCFCheckPadBaseline::CheckBaselineGPU(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer)
227 const CfFragment& fragment = clusterer.mPmemory->fragment;
228 const bool hipFilterOn = clusterer.Param().rec.tpc.hipTailFilter;
229 const Charge hipTailThreshold = clusterer.Param().rec.tpc.hipTailFilterThreshold;
230 const Charge hipTailFilterAlpha = clusterer.Param().rec.tpc.hipTailFilterAlpha;
235 const auto iRow = iBlock;
236 const auto nPads = geo.NPads(iRow);
241 const int16_t iPadOffset = iThread % MaxNPadsPerRow;
242 const int16_t iTimeOffset = iThread / MaxNPadsPerRow;
243 const int16_t iPadHandle = iThread;
244 const bool handlePad = iPadHandle < nPads;
246 if (iPadHandle < MaxNPadsPerRow) {
247 smem.tails[iPadHandle] = {-1, -1};
258 for (uint16_t t = firstTB; t < lastTB; t += NumOfCachedTBs) {
260 bool thisThreadHasTrigger =
false;
261 for (uint16_t
tt = 0;
tt < NumOfCachedTBs;
tt += TimebinsPerCacheline) {
266 const Charge ql = iTimeLoad < lastTB && iPadOffset < nPads ? chargeMap[
pos].unpack() : 0;
267 smem.charges[
tt + iTimeOffset][iPadOffset] = ql;
269 thisThreadHasTrigger |= ql >=
Charge(MaxADC);
272 bool hasHIPTrigger =
false;
274 hasHIPTrigger = work_group_any(thisThreadHasTrigger);
286 if (!hasHIPTrigger) [[likely]] {
287 if (!acc.activeHIPTail.IsOpen()) {
288 ScanCachedCharges<false, false>(smem, t, iPadHandle, hipTailThreshold, hipTailFilterAlpha, acc);
290 ScanCachedCharges<false, true>(smem, t, iPadHandle, hipTailThreshold, hipTailFilterAlpha, acc);
293 if (!acc.activeHIPTail.IsOpen()) {
294 ScanCachedCharges<true, false>(smem, t, iPadHandle, hipTailThreshold, hipTailFilterAlpha, acc);
296 ScanCachedCharges<true, true>(smem, t, iPadHandle, hipTailThreshold, hipTailFilterAlpha, acc);
303 if (hasHIPTrigger) [[unlikely]] {
305 DPRINTB(
"%d: Trigger!\n", iBlock);
307 if (handlePad && acc.HIPtb < 0) {
310 for (int16_t
i = -SSClusterPadWidth;
i < 0;
i++) {
311 const auto p = iPadHandle +
i;
313 acc.HIPtb = CAMath::Max(smem.tails[p].start, acc.HIPtb);
317 for (int16_t
i = 1;
i <= SSClusterPadWidth;
i++) {
318 const auto p = iPadHandle +
i;
319 if (p < MaxNPadsPerRow) {
320 acc.HIPtb = CAMath::Max(smem.tails[p].start, acc.HIPtb);
325 bool shouldCloseTail = acc.HIPtb > -1 && acc.activeHIPTail.HasValue();
326 if (shouldCloseTail && acc.activeHIPTail.IsOpen()) {
327 DPRINT(
"%d: end = %d\n", iThread, acc.HIPtb);
328 acc.activeHIPTail.end = acc.HIPtb;
331 CloseHIPTails(smem, clusterer, iThread, nThreads, iPadHandle, basePos, chargeMap, acc, shouldCloseTail);
335 if (acc.HIPtb > -1) {
336 DPRINT(
"%d: start = %d\n", iThread, acc.HIPtb);
337 acc.activeHIPTail.SetOpen(acc.HIPtb);
338 acc.tailFilterCharge =
Charge(MaxADC);
343 smem.tails[iPadHandle].Reset();
353 updatePadBaseline(basePos.gpad + iPadHandle, clusterer, acc.totalCharges, acc.maxConsecCharges, acc.maxCharge);
357 const bool shouldCloseTail = acc.activeHIPTail.HasValue();
362 if (work_group_any(shouldCloseTail)) {
363 if (shouldCloseTail && acc.activeHIPTail.IsOpen()) {
364 acc.activeHIPTail.end = lastTB;
367 [[maybe_unused]]
const uint16_t nClosedTails = CloseHIPTails(smem, clusterer, iThread, nThreads, iPadHandle, basePos, chargeMap, acc, shouldCloseTail);
369 DPRINTB_IF(nClosedTails > 0,
"%d: Close remaining tails (%d)\n", iBlock, nClosedTails);
375GPUd()
void GPUTPCCFCheckPadBaseline::CheckBaselineCPU(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer)
383 const int32_t
row = iBlock;
384 const int32_t nPads = geo.NPads(
row);
385 const int32_t nVecPads = (nPads + PadsPerCacheline - 1) / PadsPerCacheline;
387 const CfFragment& fragment = clusterer.mPmemory->fragment;
388 const bool hipFilterOn = clusterer.Param().rec.tpc.hipTailFilter;
389 const Charge hipTailThreshold = clusterer.Param().rec.tpc.hipTailFilterThreshold;
390 const Charge hipTailFilterAlpha = clusterer.Param().rec.tpc.hipTailFilterAlpha;
391 auto* nHIPTails = clusterer.mPnHIPTails;
392 auto* hipTails = GetHIPTails(clusterer,
row);
396 using UShort8 = Vc::fixed_size_simd<uint16_t, PadsPerCacheline>;
397 using Short8 = Vc::fixed_size_simd<int16_t, PadsPerCacheline>;
398 using Charge8 = Vc::fixed_size_simd<float, PadsPerCacheline>;
400 std::vector<UShort8> totalChargesV(nVecPads, UShort8{Vc::Zero});
401 std::vector<UShort8> consecChargesV(nVecPads, UShort8{Vc::Zero});
402 std::vector<UShort8> maxConsecChargesV(nVecPads, UShort8{Vc::Zero});
403 std::vector<Charge8> maxChargeV(nVecPads, Charge8{Vc::Zero});
405 std::vector<Short8> localHipTbV(nVecPads, -1);
406 std::vector<Short8> broadcastHipTbV(nVecPads, -1);
407 std::vector<Short8> aboveThresholdStartV(nVecPads, -1);
408 std::vector<Short8> activeHIPTailStartV(nVecPads, -1);
409 std::vector<Short8> activeHIPTailEndV(nVecPads, -1);
410 std::vector<Charge8> tailFilterChargeV(nVecPads, Charge8{Vc::Zero});
412 for (int16_t t = 0; t < fragment.
length; t += NumOfCachedTBs) {
414 bool hasAnyTrigger =
false;
417 for (int16_t iVecPad = 0; iVecPad < nVecPads; iVecPad++) {
419 auto totalCharges = totalChargesV[iVecPad];
420 auto consecCharges = consecChargesV[iVecPad];
421 auto maxConsecCharges = maxConsecChargesV[iVecPad];
422 auto maxCharge = maxChargeV[iVecPad];
424 auto hipTb = Short8(-1);
425 auto aboveThresholdStart = aboveThresholdStartV[iVecPad];
426 auto activeHIPTailStart = activeHIPTailStartV[iVecPad];
427 auto activeHIPTailEnd = activeHIPTailEndV[iVecPad];
428 auto tailFilterCharge = tailFilterChargeV[iVecPad];
434 const uint16_t* packedChargeStart =
reinterpret_cast<uint16_t*
>(&chargeMap[basePos.delta({0, localtime})]);
435 const UShort8 packedCharges = t + localtime < fragment.
length
436 ? UShort8{packedChargeStart, Vc::Aligned}
438 const auto isCharge = packedCharges != 0;
442 if (isCharge.isNotEmpty()) {
443 totalCharges(isCharge)++;
445 consecCharges(not isCharge) = 0;
446 maxConsecCharges = Vc::max(consecCharges, maxConsecCharges);
454 maxCharge = Vc::max(maxCharge, unpackedCharges);
456 const auto aboveRisingEdge = unpackedCharges >= hipTailThreshold;
457 const auto startRisingEdge = aboveRisingEdge && aboveThresholdStart < 0;
458 aboveThresholdStart(startRisingEdge) = t + localtime;
459 aboveThresholdStart(!aboveRisingEdge) = -1;
461 const auto hasNewTrigger = hipTb < 0 && unpackedCharges >=
Charge(MaxADC);
462 hipTb(hasNewTrigger) = aboveThresholdStart;
463 hasAnyTrigger |= hasNewTrigger.isNotEmpty();
466 aboveThresholdStart = -1;
469 const auto tailOpen = activeHIPTailStart > -1 && activeHIPTailEnd < 0;
470 tailFilterCharge(tailOpen) = tailFilterCharge + hipTailFilterAlpha * (unpackedCharges - tailFilterCharge);
471 activeHIPTailEnd(tailOpen && tailFilterCharge < hipTailThreshold) = t + localtime;
474 totalChargesV[iVecPad] = totalCharges;
475 consecChargesV[iVecPad] = consecCharges;
476 maxConsecChargesV[iVecPad] = maxConsecCharges;
477 maxChargeV[iVecPad] = maxCharge;
479 localHipTbV[iVecPad] = hipTb;
480 aboveThresholdStartV[iVecPad] = aboveThresholdStart;
481 activeHIPTailStartV[iVecPad] = activeHIPTailStart;
482 activeHIPTailEndV[iVecPad] = activeHIPTailEnd;
483 tailFilterChargeV[iVecPad] = tailFilterCharge;
488 broadcastHipTbV = localHipTbV;
492 for (int16_t iVecPad = 0; iVecPad < nVecPads && hasAnyTrigger; iVecPad++) {
494 const auto hipTb = localHipTbV[iVecPad];
496 const auto hasHipTrigger = hipTb > -1;
497 if (hasHipTrigger.isNotEmpty()) [[unlikely]] {
500 for (uint16_t p = 0;
p < PadsPerCacheline;
p++) {
501 if (hasHipTrigger[p]) {
502 const int16_t pad = iVecPad * PadsPerCacheline +
p;
503 const int16_t neighborSt = CAMath::Max(0, pad - SSClusterPadWidth);
504 const int16_t neighborEnd = CAMath::Min(nPads, pad + SSClusterPadWidth + 1);
505 for (int16_t np = neighborSt; np < neighborEnd; np++) {
509 const auto pv = np / PadsPerCacheline;
510 const auto pi = np % PadsPerCacheline;
512 if (localHipTbV[pv][pi] < 0) {
513 broadcastHipTbV[pv][pi] = CAMath::Max<int16_t>(hipTb[p], broadcastHipTbV[pv][pi]);
522 for (int16_t iVecPad = 0; iVecPad < nVecPads && hasAnyTrigger; iVecPad++) {
524 auto hipTb = broadcastHipTbV[iVecPad];
525 auto aboveThresholdStart = aboveThresholdStartV[iVecPad];
526 auto activeHIPTailStart = activeHIPTailStartV[iVecPad];
527 auto activeHIPTailEnd = activeHIPTailEndV[iVecPad];
528 auto tailFilterCharge = tailFilterChargeV[iVecPad];
530 const auto shouldCloseTail = hipTb > -1 && activeHIPTailStart > -1;
531 activeHIPTailEnd(shouldCloseTail && activeHIPTailEnd < 0) = hipTb;
535 if (hipFilterOn && shouldCloseTail.isNotEmpty()) {
536 for (int16_t p = 0;
p < PadsPerCacheline;
p++) {
537 const int16_t pad = iVecPad * PadsPerCacheline +
p;
538 if (shouldCloseTail[p] && pad < nPads) {
541 for (int16_t
tt = activeHIPTailStart[p];
tt < activeHIPTailEnd[
p];
tt++) {
543 const auto pos = basePos.delta({
p,
tt});
544 const auto q = chargeMap[
pos].unpack();
546 tailQMax = CAMath::Max(tailQMax, q);
550 if (activeHIPTailEnd[p] > activeHIPTailStart[p]) {
551 const auto tailIdx = CAMath::AtomicAdd<uint32_t>(&nHIPTails[
row], 1) + 1;
553 hipTails[tailIdx] = {
556 .pad = uint16_t(pad),
557 .tailStart = uint16_t(activeHIPTailStart[p]),
558 .tailEnd = uint16_t(activeHIPTailEnd[p]),
569 activeHIPTailStart(hipTb > -1) = hipTb;
570 activeHIPTailEnd(hipTb > -1) = -1;
571 tailFilterCharge(hipTb > -1) = MaxADC;
573 aboveThresholdStartV[iVecPad] = aboveThresholdStart;
574 activeHIPTailStartV[iVecPad] = activeHIPTailStart;
575 activeHIPTailEndV[iVecPad] = activeHIPTailEnd;
576 tailFilterChargeV[iVecPad] = tailFilterCharge;
582 for (int16_t iVecPad = 0; iVecPad < nVecPads; iVecPad++) {
584 auto activeHIPTailStart = activeHIPTailStartV[iVecPad];
585 auto activeHIPTailEnd = activeHIPTailEndV[iVecPad];
587 const auto shouldCloseTail = activeHIPTailStart > -1;
588 activeHIPTailEnd(shouldCloseTail && activeHIPTailEnd < 0) = fragment.
length;
590 if (hipFilterOn && shouldCloseTail.isNotEmpty()) {
591 for (int16_t p = 0;
p < PadsPerCacheline;
p++) {
592 const int16_t pad = iVecPad * PadsPerCacheline +
p;
593 if (shouldCloseTail[p] && pad < nPads) {
596 for (int16_t
tt = activeHIPTailStart[p];
tt < activeHIPTailEnd[
p];
tt++) {
598 const auto pos = basePos.delta({
p,
tt});
599 const auto q = chargeMap[
pos].unpack();
601 tailQMax = CAMath::Max(tailQMax, q);
605 if (activeHIPTailEnd[p] > activeHIPTailStart[p]) {
606 const auto tailIdx = CAMath::AtomicAdd<uint32_t>(&nHIPTails[
row], 1) + 1;
608 hipTails[tailIdx] = {
611 .pad = uint16_t(pad),
612 .tailStart = uint16_t(activeHIPTailStart[p]),
613 .tailEnd = uint16_t(activeHIPTailEnd[p]),
625 for (int32_t iVecPad = 0; iVecPad < nVecPads; iVecPad++) {
627 const UShort8 totalCharges = totalChargesV[iVecPad];
628 const UShort8 maxConsecCharges = maxConsecChargesV[iVecPad];
629 const Charge8 maxCharge = maxChargeV[iVecPad];
633 for (
tpccf::Pad localpad = 0; localpad < PadsPerCacheline; localpad++) {
634 updatePadBaseline(basePos.gpad + localpad, clusterer, totalCharges[localpad], maxConsecCharges[localpad], maxCharge[localpad]);
642 const CfFragment& fragment = clusterer.mPmemory->fragment;
643 const int32_t totalChargesBaseline = clusterer.Param().rec.tpc.maxTimeBinAboveThresholdIn1000Bin * fragment.lengthWithoutOverlap() / 1000;
644 const int32_t consecChargesBaseline = clusterer.Param().rec.tpc.maxConsecTimeBinAboveThreshold;
645 const uint16_t saturationThreshold = clusterer.Param().rec.tpc.noisyPadSaturationThreshold;
646 const bool isNoisy = (!saturationThreshold || maxCharge < saturationThreshold) && ((totalChargesBaseline > 0 && totalCharges >= totalChargesBaseline) || (consecChargesBaseline > 0 && consecCharges >= consecChargesBaseline));
649 clusterer.mPpadIsNoisy[pad] =
true;
661 const uint32_t
row = iBlock;
663 const uint32_t nTails = CAMath::Min(clusterer.mPnHIPTails[
row], (uint32_t)MaxHIPTailsPerRow - 1);
668#ifdef GPUCA_DETERMINISTIC_MODE
671 GPUCommonAlgorithm::sortInBlock(tails + 1, tails + nTails + 1, [](
auto&&
t1,
auto&& t2) {
672 if (
t1.pad != t2.pad) {
673 return t1.pad < t2.pad;
674 }
else if (
t1.tailStart != t2.tailStart) {
675 return t1.tailStart < t2.tailStart;
676 }
else if (
t1.tailEnd != t2.tailEnd) {
677 return t1.tailEnd < t2.tailEnd;
678 }
else if (
t1.qTot != t2.qTot) {
679 return t1.qTot < t2.qTot;
681 return t1.qMax < t2.qMax;
690 for (uint32_t iTail = iThread + 1; iTail <= nTails; iTail += nThreads) {
691 auto* tail = &tails[iTail];
695 uint16_t overlapWindowStart = tail->
tailStart >= 5 ? tail->tailStart - 5 : 0;
696 uint16_t overlapWindowEnd = tail->tailStart + 5;
698 for (uint32_t jTail = iTail + 1; jTail <= nTails; jTail++) {
699 auto* tailNext = &tails[jTail];
700 if (tailNext->iPrev > 0) {
705 const bool overlapTime = tailNext->tailStart >= overlapWindowStart && tailNext->tailStart < overlapWindowEnd;
707 if (overlapPad && overlapTime) {
708 if (CAMath::AtomicCAS(&tailNext->iPrev, 0u, iTail)) {
720GPUd()
void GPUTPCCFHIPClusterizer::Thread<0>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer, uint8_t onlyMC)
726 const uint32_t
row = iBlock;
727 uint32_t nTails = clusterer.mPnHIPTails[
row];
728 nTails = CAMath::Min(nTails, (uint32_t)MaxHIPTailsPerRow - 1);
730 const auto* tails = GetHIPTails(clusterer,
row);
731 const auto& fragment = clusterer.mPmemory->fragment;
733 auto* clusterPosInRow = clusterer.mPhipClusterPosInRow
734 ? clusterer.mPhipClusterPosInRow +
row * MaxHIPTailsPerRow
737 for (uint32_t iTail = iThread + 1; iTail <= nTails; iTail += nThreads) {
739 const auto* tail = &tails[iTail];
740 if (tail->iPrev != 0) {
751 uint32_t tailStart = (uint32_t)-1;
752 uint32_t tailEnd = 0;
755 for (; tail != tails; tail = &tails[tail->iNext]) {
756 const float tailWeight = tail->qTot;
757 const float tailPad = tail->pad;
758 const float tailTime = HIPTailTimeMean(*tail);
759 qMax = CAMath::Max(qMax, tail->qMax);
761 padSum += tailWeight * tailPad;
762 padSqSum += tailWeight * tailPad * tailPad;
763 timeSum += tailWeight * tailTime;
764 tailStart = CAMath::Min<uint32_t>(tailStart, tail->tailStart);
765 tailEnd = CAMath::Max<uint32_t>(tailEnd, tail->tailEnd);
767 CPU_ONLY(labelAcc.collectTail(
row, tail->pad, tail->tailStart, tail->tailEnd));
770 const float weightSum = CAMath::Max(qTot, 1.f);
771 const float padMean = padSum / weightSum;
772 const float timeMean = timeSum / weightSum;
773 const float padSigma = CAMath::Sqrt(CAMath::Max(0.f, padSqSum / weightSum - padMean * padMean));
777 cn.setSaturatedQtot(qTot);
778 cn.setSaturatedTailLength(tailEnd - tailStart);
779 float clusterTime = fragment.
start + timeMean - clusterer.Param().rec.tpc.clustersShiftTimebinsClusterizer;
780 cn.setTimeFlags(clusterTime, 0);
782 cn.setSigmaPad(padSigma);
784 if (cn.
qMax >= 1023) {
792 index = CAMath::AtomicAdd(&clusterer.mPclusterInRow[
row], 1u);
793 if (
index < clusterer.mNMaxClusterPerRow) {
794 clusterer.mPclusterByRow[clusterer.mNMaxClusterPerRow *
row +
index] = cn;
796 if (clusterPosInRow) {
797 clusterPosInRow[iTail] =
index;
800 index = clusterPosInRow[iTail];
Class of a TPC cluster in TPC-native coordinates (row, time)
#define GPUCA_GET_THREAD_COUNT(...)
#define DPRINTB_IF(test,...)
GPUd() void GPUTPCCFCheckPadBaseline
Provides a basic fallback implementation for Vc.
static constexpr uint32_t NROWS
GLfloat GLfloat GLfloat alpha
GLuint GLsizei GLsizei * length
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLint GLenum GLboolean GLsizei stride
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
tpccf::TPCFragmentTime length