54 int iModule = ctx.block_idx_x();
65 if (digisOut == digisTmp) {
67 for (
int i = ctx.thread_idx_x(); i < nDigis; i += ctx.block_dim_x()) {
68 digis[i] = digisTmp[i];
76 xpu::barrier(ctx.pos());
78 xpu::barrier(ctx.pos());
93 unsigned int* channelOffsets,
unsigned int const nDigis)
const
95 channelOffsets[0] = 0;
97 for (
unsigned int pos = ctx.thread_idx_x();
pos < nDigis - 1;
pos += (
unsigned int) ctx.block_dim_x()) {
100 if (currChannel != nextChannel) {
101 for (
int i = currChannel + 1; i <= nextChannel; i++) {
102 channelOffsets[i] =
pos + 1;
107 for (
int c = digis[nDigis - 1].GetChannel() + 1; c <
nChannels; c++) {
108 channelOffsets[c] = nDigis;
122 int const iModule = ctx.block_idx_x();
126 if (nDigis == 0)
return;
143 const i32 iGThread = ctx.block_dim_x() * ctx.block_idx_x() + ctx.thread_idx_x();
145 if (iGThread >= nDigisTotal) {
159 if (nDigis == 0)
return;
173 const u32 nextChannelEnd = (channel + 2 <
nChannels) ? channelOffsets[channel + 2] : nDigis;
176 u32 start = channelOffsets[channel + 1];
177 u32 end = nextChannelEnd;
178 while (start < end) {
179 u32 mid = (start + end) / 2;
181 if (deltaT < timeDiffDigis) {
189 for (
auto nextIter = start; nextIter < nextChannelEnd; nextIter++) {
197 if (deltaT < timeDiffDigis) {
204 digiConnector[iLocal].SetNext(nextIter);
205 digiConnector[nextIter].SetHasPrevious(
true);
220 const int nModuleSides = 2 *
nModules;
223 int iThread = ctx.block_dim_x() * ctx.block_idx_x() + ctx.thread_idx_x();
225 for (; iModule < nModuleSides; iModule++) {
227 if (iThread < nDigis) {
233 if (iModule >= nModuleSides) {
241 const int iDigi = iThread;
243 if (digiConnector[iDigi].HasPrevious()) {
247 if (!digiConnector[iDigi].HasNext()) {
251 else if (!digiConnector[digiConnector[iDigi].next()].HasNext()) {
285 for (
unsigned int currIter = ctx.thread_idx_x(); currIter < nDigis; currIter += (
unsigned int) ctx.block_dim_x()) {
287 if (digiConnector[currIter].HasPrevious())
continue;
297 const float timeError =
asic.timeResolution;
303 .fPositionError = 1.f / xpu::sqrt(24.f),
305 .fTimeError = timeError,
320 float eNoiseSq =
asic.noise *
asic.noise;
322 float chargePerAdc =
asic.dynamicRange / float(
asic.nAdc);
323 float eDigitSq = chargePerAdc * chargePerAdc / 12.f;
336 float eq1sq = width1 * width1 + eNoiseSq + eDigitSq;
338 float eq2sq = width2 * width2 + eNoiseSq + eDigitSq;
342 float timeError =
asic.timeResolution * 0.70710678f;
345 float x = x1 + 0.5f + (q2 - q1) / 3.f / xpu::max(q1, q2);
357 ex0sq = (q2 - q1) * (q2 - q1) / q2 / q2 / 72.f;
358 ex1sq = eq1sq / q2 / q2 / 9.f;
359 ex2sq = eq2sq * q1 * q1 / q2 / q2 / q2 / q2 / 9.f;
362 ex0sq = (q2 - q1) * (q2 - q1) / q1 / q1 / 72.f;
363 ex1sq = eq1sq * q2 * q2 / q1 / q1 / q1 / q1 / 9.f;
364 ex2sq = eq2sq / q1 / q1 / 9.f;
366 float xError = xpu::sqrt(ex0sq + ex1sq + ex2sq);
369 float charge = q1 + q2;
377 .fPositionError = xError,
378 .fTime = uint32_t(time),
379 .fTimeError = timeError,
392 auto calculateClusterCharges = [
this, &cProps, &digis, &digiConnector](
int index) {
394 float eNoiseSq =
asic.noise *
asic.noise;
395 float chargePerAdc =
asic.dynamicRange / float(
asic.nAdc);
396 float eDigitSq = chargePerAdc * chargePerAdc / 12.f;
401 float eChargeSq = lWidth * lWidth + eNoiseSq + eDigitSq;
403 if (!digiConnector[index].HasPrevious()) {
407 cProps.
eqFsq = eChargeSq;
409 else if (!digiConnector[index].HasNext()) {
413 cProps.
eqLsq = eChargeSq;
417 cProps.
eqMsq += eChargeSq;
422 calculateClusterCharges(digiIndex);
425 while (digiConnector[digiIndex].HasNext()) {
426 digiIndex = digiConnector[digiIndex].
next();
427 calculateClusterCharges(digiIndex);
436 float timeError = (cProps.
tResolSum / nDigis) / xpu::sqrt(nDigis);
437 float qSum = cProps.
qF + cProps.
qM + cProps.
qL;
440 cProps.
qM /= (nDigis - 2.f);
441 cProps.
eqMsq /= (nDigis - 2.f);
444 float x = 0.5f * (float(cProps.
chanF + cProps.
chanL) + (cProps.
qL - cProps.
qF) / cProps.
qM);
452 float exFsq = cProps.
eqFsq / cProps.
qM / cProps.
qM / 4.f;
453 float exMsq = cProps.
eqMsq * (cProps.
qL - cProps.
qF) * (cProps.
qL - cProps.
qF) / cProps.
qM / cProps.
qM / cProps.
qM
455 float exLsq = cProps.
eqLsq / cProps.
qM / cProps.
qM / 4.f;
456 float xError = xpu::sqrt(exFsq + exMsq + exLsq);
460 x = cProps.
xSum / qSum;
469 .fSize = int(nDigis),
471 .fPositionError = xError,
472 .fTime = uint32_t(cProps.
tSum),
473 .fTimeError = timeError,
485 int firstModule = ctx.block_idx_x();
486 int lastModule = ctx.block_idx_x();
487 if (ctx.grid_dim_x() == 1) {
492 for (
int iModule = firstModule; iModule <= lastModule; iModule++) {
501 if (nClusters == 0)
return;
508 clusterIdx = clsSort.sort(clusterIdx, nClusters, clusterIdxTmp, [](
const ClusterIdx a) {
return a.
fTime; });
521 int iThread = ctx.block_dim_x() * ctx.block_idx_x() + ctx.thread_idx_x();
526 for (; iModule <
nModules; iModule++) {
536 int iModuleF = iModule;
555 if (nClustersF == 0 || nClustersB == 0) {
565 iChunk * nClustersPerChunk;
569 if (iClusterF >= nClustersF) {
602 float maxSigmaBoth = 4.f * xpu::sqrt(maxTerrF * maxTerrF + maxTerrB * maxTerrB);
609 int end = nClustersB;
610 while (end - start > 1) {
611 int mid = (start + end) / 2;
612 auto timeDiffCluster =
GetTimeDiff(clusterIdxF[iClusterF], clusterIdxB[mid]);
613 if (maxSigmaBoth < timeDiffCluster) {
624 xpu::min(iClusterF + nClustersPerChunk, nClustersF);
629 for (; iClusterF < endClusterF; iClusterF++) {
633 float maxSigma = 4.f * xpu::sqrt(clsDataF.
fTimeError * clsDataF.
fTimeError + maxTerrB * maxTerrB);
635 for (
int iClusterB = startB; iClusterB < nClustersB; iClusterB++) {
641 if (timeDiff > 0 && timeDiff > maxSigmaBoth) {
645 else if (timeDiff > 0 && timeDiff > maxSigma) {
648 else if (timeDiff < 0 && xpu::abs(timeDiff) > maxSigma) {
655 if (doChargeCorrelation) {
657 if (xpu::abs(chargeDiff) > ChargeDelta) {
662 float timeCut = -1.f;
671 if (xpu::abs(timeDiff) > timeCut) {
689 float du = exF * xpu::cos(xpu::deg_to_rad() * pars.
stereoF);
692 float dv = exB * xpu::cos(xpu::deg_to_rad() * pars.
stereoB);
695 if (xF < 0.f || xF > pars.
dX || xB < 0.f || xB > pars.
dX) {
712 int nF1 = xpu::min(0, nF);
713 int nF2 = xpu::max(0, nF);
714 int nB1 = xpu::min(0, nB);
715 int nB2 = xpu::max(0, nB);
723 for (
int iF = nF1; iF <= nF2; iF++) {
724 float xFi = xF - float(iF) * pars.
dX;
725 for (
int iB = nB1; iB <= nB2; iB++) {
726 float xBi = xB - float(iB) * pars.
dX;
729 bool found =
Intersect(pars, xFi, exF, xBi, exB, xC, yC, varX, varY, varXY);
730 if (not found)
continue;
734 xC -= 0.5f * pars.
dX;
735 yC -= 0.5f * pars.
dY;
737 CreateHit(iBlock, xC, yC, varX, varY, varXY, idxF, clsF, idxB, clsB, du, dv);
746 int iChannel = int(centre);
747 float xDif = centre - float(iChannel);
751 int iStrip = iChannel - (isFront ? 0 :
nChannels);
755 float xCluster = (float(iStrip) + xDif + 0.5f) * pars.
pitch;
769 float&
y,
float& varX,
float& varY,
float& varXY)
const
788 if (xpu::abs(pars.
stereoF) < 0.001f) {
798 if (xpu::abs(pars.
stereoB) < 0.001f) {
813 varY = pars.
errorFac * (exF * exF + exB * exB);
822 return x >= -pars.
dX / 2.f
823 &&
x <= pars.
dX / 2.f
824 &&
y >= -pars.
dY / 2.f
825 &&
y <= pars.
dY / 2.f;
831 const Cluster& clsB,
float du,
float dv)
const
834 float globalX, globalY, globalZ;
835 ToGlobal(iModule, xLocal, yLocal, 0.f, globalX, globalY, globalZ);
840 float errX = xpu::sqrt(varX);
841 float errY = xpu::sqrt(varY);
844 float hitTime = 0.5f * (float(idxF.
fTime) + float(idxB.
fTime));
847 float hitTimeError = 0.5f * xpu::sqrt(etF * etF + etB * etB);
853 .fTime =
static_cast<u32>(hitTime),
857 .fTimeError = hitTimeError,
861 .fFrontClusterId = idxF.
fIdx,
862 .fBackClusterId = idxB.
fIdx,
868 xpu::atomic_add(&
monitor->nHitBucketOverflow, 1);
886 return v1 + (charge - e1) * (v2 - v1) / (e2 - e1);
894 gx = tr[0] + lx * rot[0] + ly * rot[1] + lz * rot[2];
895 gy = tr[1] + lx * rot[3] + ly * rot[4] + lz * rot[5];
896 gz = tr[2] + lx * rot[6] + ly * rot[7] + lz * rot[8];
XPU_EXPORT(sts::TheHitfinder)
XPU_EXPORT(cbm::algo::Params)
Data class for a single-channel message in the STS.
XPU_D uint16_t GetChannel() const
Channel number in module @value Channel number.
XPU_D uint16_t GetChargeU16() const
XPU_D uint32_t GetTimeU32() const
XPU_D unsigned int next() const
XPU_D void SaveMaxError(float errorValue, int iModule) const
xpu::buffer< PaddedToCacheLine< int > > nHitsPerModule
XPU_D float GetTimeDiff(const CbmStsDigi &d1, const CbmStsDigi &d2) const
XPU_D void CreateClusterFromConnectors1(int const iModule, const CbmStsDigi *digis, int const digiIndex) const
xpu::buffer< DigiConnector > digiConnectorsPerModule
XPU_D void AddCluster(int iModule, uint32_t time, const sts::Cluster &cls) const
XPU_D void CalculateChannelOffsets(FindClusters::context &ctx, CbmStsDigi *digis, unsigned int *channelOffsets, unsigned int nDigis) const
xpu::buffer< PaddedToCacheLine< int > > nClustersPerModule
XPU_D void SortClusters(SortClusters::context &) const
XPU_D void CalculateOffsetsParallel(FindClusters::context &) const
size_t hitsAllocatedPerModule
xpu::buffer< HitfinderMonDevice > monitor
xpu::buffer< float > landauTable
xpu::buffer< unsigned int > channelOffsetPerModule
xpu::buffer< ClusterIdx > clusterIdxPerModule
xpu::buffer< float > localToGlobalTranslationByModule
XPU_D bool Intersect(const HitfinderCache &pars, float xF, float exF, float xB, float exB, float &x, float &y, float &varX, float &varY, float &varXY) const
xpu::buffer< SensorPar > sensorPars
size_t maxClustersPerModule
xpu::buffer< CbmStsDigi > digisPerModuleTmp
XPU_D float GetTimeResolution(int, int) const
XPU_D void FindClustersSingleStep(FindClusters::context &) const
xpu::buffer< float > localToGlobalRotationByModule
xpu::buffer< size_t > digiOffsetPerModule
xpu::buffer< sts::Hit > hitsPerModule
XPU_D bool IsInside(const HitfinderCache &pars, float x, float y) const
XPU_D float LandauWidth(float charge) const
XPU_D void CreateClusterFromConnectorsN(int const iModule, const CbmStsDigi *digis, DigiConnector *digiConnector, int const digiIndex) const
XPU_D void CalculateClustersDigiWise(FindClusters::context &ctx, CbmStsDigi *digis, DigiConnector *digiConnector, unsigned int const nDigis) const
xpu::buffer< sts::Cluster > clusterDataPerModule
xpu::buffer< ClusterIdx * > clusterIdxSortedPerModule
XPU_D void IntersectClusters(int iBlock, const HitfinderCache &pars, const ClusterIdx &idxF, const sts::Cluster &clsF, const ClusterIdx &idxB, const sts::Cluster &clsB) const
XPU_D bool IsBackside(int iModule) const
sts::HitfinderPars::Asic asic
xpu::buffer< ClusterIdx > clusterIdxPerModuleTmp
xpu::buffer< CbmStsDigi > digisPerModule
XPU_D void SortDigisInSpaceAndTime(SortDigis::context &) const
XPU_D void CalculateClustersParallel(FindClusters::context &) const
XPU_D void CreateClusterFromConnectors2(int const iModule, const CbmStsDigi *digis, DigiConnector *digiConnector, int const digiIndex) const
XPU_D void ToGlobal(int iModule, float lx, float ly, float lz, float &gx, float &gy, float &gz) const
XPU_D int ChanDist(int c1, int c2) const
XPU_D void CreateHit(int iBlocks, float xLocal, float yLocal, float varX, float varY, float varXY, const ClusterIdx &idxF, const Cluster &clsF, const ClusterIdx &idxB, const sts::Cluster &clsB, float du, float dv) const
XPU_D void FindHits(FindHits::context &) const
XPU_D unsigned int GetNDigis(int iModule) const
XPU_D void FindClustersParallel(FindClusters::context &) const
xpu::buffer< PaddedToCacheLine< float > > maxClusterTimeErrorByModuleSide
XPU_D float GetClusterPosition(const HitfinderCache &pars, float centre, bool isFront) const
@ kFindHitsChunksPerModule
f32 chargeCorrelationDelta
XPU_D void operator()(context &)
xpu::kernel_context< shared_memory, constants > context
u32 fTime
Cluster time (average of digi times) [ns].
real fTimeError
Error of cluster time [ns].
real fPosition
Cluster centre in channel number units.
real fPositionError
Cluster centre error (r.m.s.) in channel number units.
real fCharge
Total charge.
xpu::kernel_context< shared_memory, constants > context
XPU_D void operator()(context &)
XPU_D void operator()(context &)
xpu::kernel_context< shared_memory, constants > context
xpu::kernel_context< shared_memory, constants > context
XPU_D void operator()(context &)
XPU_D void operator()(context &)
xpu::kernel_context< shared_memory, constants > context
XPU_D void operator()(context &)
xpu::block_sort< u32, ClusterIdx, kSortClustersBlockSize, kSortClustersItemsPerThread > sort_t
xpu::kernel_context< shared_memory, constants > context
XPU_D void operator()(context &)
xpu::block_sort< u64, CbmStsDigi, kSortDigisBlockSize, kSortDigisItemsPerThread > sort_t
xpu::kernel_context< shared_memory, constants > context