CbmRoot
Loading...
Searching...
No Matches
Hitfinder.h
Go to the documentation of this file.
1/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Felix Weiglhofer [committer], Kilian Hunold */
4
5#ifndef CBM_ALGO_STS_HITFINDER_H
6#define CBM_ALGO_STS_HITFINDER_H
7
8#include "CbmStsDigi.h"
9#include "Definitions.h"
10#include "gpu/DeviceImage.h"
11#include "gpu/PaddedValue.h"
12#include "gpu/Params.h"
13#include "sts/Cluster.h"
14#include "sts/Hit.h"
15#include "sts/HitfinderPars.h"
16
17#include <xpu/device.h>
18
19namespace cbm::algo
20{
21
22 // Block sizes / other compile time constants that need tuning
42} // namespace cbm::algo
43
44namespace cbm::algo::sts
45{
46
47 class Hitfinder; // forward declaration
48
49 // GPU Data structures
50 // TODO: Replace with regular StsCluster / StsHit once the changes
51 // land to make them fit for GPU
52 struct ClusterIdx {
55 };
56
57 // Declare Constant Memory
58 struct TheHitfinder : xpu::constant<GPUReco, Hitfinder> {
59 };
60
61 // Declare Kernels
62 struct SortDigis : xpu::kernel<GPUReco> {
63 using block_size = xpu::block_size<kSortDigisBlockSize>;
64 using sort_t = xpu::block_sort<u64, CbmStsDigi, kSortDigisBlockSize, kSortDigisItemsPerThread>;
65 using shared_memory = sort_t::storage_t;
66 using constants = xpu::cmem<TheHitfinder, Params>;
67 using context = xpu::kernel_context<shared_memory, constants>;
68 XPU_D void operator()(context&);
69 };
70
71 struct FindClusters : xpu::kernel<GPUReco> {
72 using block_size = xpu::block_size<kFindClusterBlockSize>;
73 using constants = xpu::cmem<TheHitfinder, Params>;
74 using context = xpu::kernel_context<shared_memory, constants>;
75 XPU_D void operator()(context&);
76 };
77
78 struct ChannelOffsets : xpu::kernel<GPUReco> {
79 using block_size = xpu::block_size<kFindClusterBlockSize>;
80 using constants = xpu::cmem<TheHitfinder, Params>;
81 using context = xpu::kernel_context<shared_memory, constants>;
82 XPU_D void operator()(context&);
83 };
84
85 struct CreateDigiConnections : xpu::kernel<GPUReco> {
86 using block_size = xpu::block_size<kFindClusterBlockSize>;
87 using constants = xpu::cmem<TheHitfinder, Params>;
88 using context = xpu::kernel_context<shared_memory, constants>;
89 XPU_D void operator()(context&);
90 };
91
92 struct CreateClusters : xpu::kernel<GPUReco> {
93 using block_size = xpu::block_size<kFindClusterBlockSize>;
94 using constants = xpu::cmem<TheHitfinder, Params>;
95 using context = xpu::kernel_context<shared_memory, constants>;
96 XPU_D void operator()(context&);
97 };
98
99 struct SortClusters : xpu::kernel<GPUReco> {
100 using block_size = xpu::block_size<kSortClustersBlockSize>;
101 using sort_t = xpu::block_sort<u32, ClusterIdx, kSortClustersBlockSize, kSortClustersItemsPerThread>;
102 using shared_memory = sort_t::storage_t;
103 using constants = xpu::cmem<TheHitfinder, Params>;
104 using context = xpu::kernel_context<shared_memory, constants>;
105 XPU_D void operator()(context&);
106 };
107
108 struct FindHits : xpu::kernel<GPUReco> {
109 using block_size = xpu::block_size<kFindHitsBlockSize>;
110 using constants = xpu::cmem<TheHitfinder, Params>;
111 using context = xpu::kernel_context<shared_memory, constants>;
112 using openmp = xpu::openmp_settings<xpu::schedule_static, 1>;
113 XPU_D void operator()(context&);
114 };
115
121
122 // Calibration data structures
123 struct SensorPar {
124 float dY;
125 float pitch;
126 float stereoF;
127 float stereoB;
128 float lorentzF;
129 float lorentzB;
130 };
131
132 // Cache for various parameters of the hitfindiner
133 // Used internally to avoid computing values multiple times
134 // TODO: is this really needed? Overhead from additional computations should be miniscule.
135 // TODO: Also store in shared memory, not registers. Values identical for all threads.
139 float errorFac;
140 float dX;
141 };
142
144 float tSum = 0.; // sum of digi times
145 int chanF = 9999999; // first channel in cluster
146 int chanL = -1; // last channel in cluster
147 float qF = 0.f; // charge in first channel
148 float qM = 0.f; // sum of charges in middle channels
149 float qL = 0.f; // charge in last cluster
150 float eqFsq = 0.f; // uncertainty of qF
151 float eqMsq = 0.f; // uncertainty of qMid
152 float eqLsq = 0.f; // uncertainty of qL
153 float tResolSum = 0.f;
154
155 float xSum = 0.f; // weighted charge sum, used to correct corrupt clusters
156 };
157
159 private:
160 unsigned int hasPreviousAndNext;
161
162 XPU_D unsigned int UnpackNext(unsigned int val) const { return val & ~(1u << 31); }
163
164 public:
165 XPU_D bool HasPrevious() const { return (hasPreviousAndNext >> 31) & 1u; }
166
167 XPU_D void SetHasPrevious(bool hasPrevious)
168 {
169 unsigned int old = hasPreviousAndNext;
170 unsigned int hasPreviousI = ((unsigned int) hasPrevious) << 31;
171 unsigned int assumed;
172
173 do {
174 assumed = old;
175 old = xpu::atomic_cas(&hasPreviousAndNext, assumed, UnpackNext(assumed) | hasPreviousI);
176 } while (old != assumed);
177 }
178
179 XPU_D unsigned int next() const { return UnpackNext(hasPreviousAndNext); }
180
181 XPU_D void SetNext(unsigned int next)
182 {
183 unsigned int old = hasPreviousAndNext;
184 unsigned int assumed;
185
186 next = xpu::min((1u << 31) - 1, next);
187
188 do {
189 assumed = old;
190 old = xpu::atomic_cas(&hasPreviousAndNext, assumed, (assumed & (1u << 31)) | next);
191 } while (old != assumed);
192 }
193
194 XPU_D bool HasNext() const { return UnpackNext(hasPreviousAndNext) != 0; }
195 };
196
197 // Hitfinder class. Holds pointers to buffers + algorithm.
198 class Hitfinder {
199
200 public:
201 // calibration / configuration data
202 // Only set once
203
204 int nModules; // Number of modules
205 int nChannels; // Number of channels per module
206
208
211 // Entries of landauTable. size = landauTableSize
212 xpu::buffer<float> landauTable;
213
214 // transformation matrix to convert local to global coordinate space
215 // size = nModules
218
219 // Sensor Parameters
220 // size = nModules
221 xpu::buffer<SensorPar> sensorPars;
222
223 // Monitor data
224 xpu::buffer<HitfinderMonDevice> monitor;
225
226 // input
227 // Store all digis in a flat array with a header that contains the offset for every module (front and back)
228 xpu::buffer<size_t> digiOffsetPerModule; // size = 2 * nModules + 1 entries, last entry contains total digi count
229 xpu::buffer<CbmStsDigi> digisPerModule; // Flat array of input digis. size = nDigisTotal
230
231 // Temporary Digi-Array used for sorting as sorting is not in place. size = nDigisTotal
232 xpu::buffer<CbmStsDigi> digisPerModuleTmp;
233
234 // DigiConnectors used internally by StsClusterizer
235 // Connects digis that belong to the same cluster via linked-list.
236 // size = nDigisTotal
237 xpu::buffer<DigiConnector> digiConnectorsPerModule;
238
239 // Digis are sorted by channel + within channel by time
240 // Contains the offset for each channel within each channel
241 // size = 2 * nModules * nChannels
242 xpu::buffer<unsigned int> channelOffsetPerModule;
243
244 // intermediate results
246
247 // Cluster Index by module. Produced by cluster finder.
248 // Stored as buckets with a max size of maxClustersPerModule
249 // Actual number of entries in each bucket is stored in nClustersPerModule
250 // size = 2 * nModules * maxClustersPerModule
251 xpu::buffer<ClusterIdx> clusterIdxPerModule;
252
253 // Temporary cluster index array used for sorting as sorting is not in place.
254 // size = 2 * nModules * maxClustersPerModule
255 xpu::buffer<ClusterIdx> clusterIdxPerModuleTmp;
256
257 // Pointer to sorted cluster idx for every module side.
258 // Either points to clusterIdxPerModule or clusterIdxPerModuleTmp.
259 // size = 2 * nModules
260 xpu::buffer<ClusterIdx*> clusterIdxSortedPerModule;
261
262 // Clusters stored by modules. Stored as buckets with a max size of maxClustersPerModule
263 // Actual number of entries in each bucket is stored in nClustersPerModule
264 // size = 2 * nModules * maxClustersPerModule
265 xpu::buffer<sts::Cluster> clusterDataPerModule;
266
267 // Number of clusters in each module
268 // size = 2 * nModules
269 // FIXME: Should be size_t!
270 xpu::buffer<PaddedToCacheLine<int>> nClustersPerModule;
271
272 // Max time error of clusters on front- and backside of a module
273 // size = 2 * nModules
274 xpu::buffer<PaddedToCacheLine<float>> maxClusterTimeErrorByModuleSide;
275
276 // output
277
278 // Max number of Hits that can be stored in each module
280
281 // Max number of hits that should be stored in each module
282 // Guaranteed to be <= hitsAllocatedPerModule,
283 // calculated from to the number of digis
284 // This is a seperate value to terminate faster if we encounter monster events
286
287 // Hits sorted by module. Stored in buckets of size maxHitsPerModule.
288 // Actual number of hits is stored in nHitsPerModule
289 // size = maxHitsPerModule * nModules
290 xpu::buffer<sts::Hit> hitsPerModule;
291
292 // Number of hits in each module
293 // size = nModules
294 // FIXME: Should be size_t!
295 xpu::buffer<PaddedToCacheLine<int>> nHitsPerModule;
296
297 // Flat array of hits. size = nHitsTotal
299 xpu::buffer<sts::Hit> hitsFlat;
300
301 public:
304 XPU_D void SortClusters(SortClusters::context&) const;
305 XPU_D void FindHits(FindHits::context&) const;
306
307 // Individual steps of cluster finder, for more granular time measurement
311
312 private:
313 XPU_D void CalculateChannelOffsets(FindClusters::context& ctx, CbmStsDigi* digis, unsigned int* channelOffsets,
314 unsigned int nDigis) const;
315
317 DigiConnector* digiConnector, unsigned int* channelOffsets,
318 unsigned int nDigis) const;
319
320 XPU_D void CalculateClustersDigiWise(FindClusters::context& ctx, CbmStsDigi* digis, DigiConnector* digiConnector,
321 unsigned int const nDigis) const;
322
323 XPU_D void CreateClusterFromConnectors1(int const iModule, const CbmStsDigi* digis, int const digiIndex) const;
324 XPU_D void CreateClusterFromConnectors2(int const iModule, const CbmStsDigi* digis, DigiConnector* digiConnector,
325 int const digiIndex) const;
326 XPU_D void CreateClusterFromConnectorsN(int const iModule, const CbmStsDigi* digis, DigiConnector* digiConnector,
327 int const digiIndex) const;
328
329 private:
330 XPU_D unsigned int GetNDigis(int iModule) const
331 {
332 return digiOffsetPerModule[iModule + 1] - digiOffsetPerModule[iModule];
333 }
334
335 XPU_D float GetTimeResolution(int /* iModule */, int /* channel */) const { return asic.timeResolution; }
336
337 XPU_D bool IsActive(int* channelStatus, int channel) const
338 {
339 // TODO add padding to channels to remove this?
340 if (channel < 0 || channel >= nChannels) {
341 return false;
342 }
343 return channelStatus[channel] > -1;
344 }
345
346 XPU_D int ChanLeft(int channel) const { return channel - 1; }
347
348 XPU_D int ChanRight(int channel) const { return channel + 1; }
349
350 XPU_D int ChanDist(int c1, int c2) const
351 {
352 int diff = c2 - c1;
353 // TODO handle wrap around
354 return diff;
355 }
356
357 XPU_D void AddCluster(int iModule, uint32_t time, const sts::Cluster& cls) const
358 {
361
362 u32 pos = xpu::atomic_add(&nClustersPerModule[iModule], 1);
363
364 if (size_t(pos) >= maxClustersPerModule) {
365 xpu::atomic_add(&monitor->nClusterBucketOverflow, 1);
366 return;
367 }
368
369 ClusterIdx idx{time, pos};
370 tgtIdx[idx.fIdx] = idx;
371 tgtData[idx.fIdx] = cls;
372 }
373
374 XPU_D bool IsBackside(int iModule) const { return iModule >= nModules; }
375
376 XPU_D float LandauWidth(float charge) const;
377
378 XPU_D void ToGlobal(int iModule, float lx, float ly, float lz, float& gx, float& gy, float& gz) const;
379
380 XPU_D void IntersectClusters(int iBlock, const HitfinderCache& pars, const ClusterIdx& idxF,
381 const sts::Cluster& clsF, const ClusterIdx& idxB, const sts::Cluster& clsB) const;
382 XPU_D float GetClusterPosition(const HitfinderCache& pars, float centre, bool isFront) const;
383 XPU_D bool Intersect(const HitfinderCache& pars, float xF, float exF, float xB, float exB, float& x, float& y,
384 float& varX, float& varY, float& varXY) const;
385 XPU_D bool IsInside(const HitfinderCache& pars, float x, float y) const;
386 XPU_D void CreateHit(int iBlocks, float xLocal, float yLocal, float varX, float varY, float varXY,
387 const ClusterIdx& idxF, const Cluster& clsF, const ClusterIdx& idxB, const sts::Cluster& clsB,
388 float du, float dv) const;
389
390 XPU_D void SaveMaxError(float errorValue, int iModule) const
391 {
392 float* maxError = &maxClusterTimeErrorByModuleSide[iModule];
393 float old{};
394 do {
395 old = *maxError;
396 if (old >= errorValue) {
397 break;
398 }
399 } while (!xpu::atomic_cas_block(maxError, *maxError, xpu::max(errorValue, *maxError)));
400 }
401 };
402
403} // namespace cbm::algo::sts
404
405#endif // CBM_ALGO_STS_HITFINDER_H
This file contains the definition of the PaddedValue class.
Data class for a single-channel message in the STS.
Definition CbmStsDigi.h:40
XPU_D unsigned int UnpackNext(unsigned int val) const
Definition Hitfinder.h:162
XPU_D void SetNext(unsigned int next)
Definition Hitfinder.h:181
XPU_D void SetHasPrevious(bool hasPrevious)
Definition Hitfinder.h:167
XPU_D bool HasNext() const
Definition Hitfinder.h:194
XPU_D bool HasPrevious() const
Definition Hitfinder.h:165
XPU_D unsigned int next() const
Definition Hitfinder.h:179
XPU_D void SaveMaxError(float errorValue, int iModule) const
Definition Hitfinder.h:390
XPU_D bool IsActive(int *channelStatus, int channel) const
Definition Hitfinder.h:337
xpu::buffer< PaddedToCacheLine< int > > nHitsPerModule
Definition Hitfinder.h:295
XPU_D void CreateClusterFromConnectors1(int const iModule, const CbmStsDigi *digis, int const digiIndex) const
xpu::buffer< DigiConnector > digiConnectorsPerModule
Definition Hitfinder.h:237
XPU_D void AddCluster(int iModule, uint32_t time, const sts::Cluster &cls) const
Definition Hitfinder.h:357
XPU_D void CalculateChannelOffsets(FindClusters::context &ctx, CbmStsDigi *digis, unsigned int *channelOffsets, unsigned int nDigis) const
Definition Hitfinder.cxx:92
xpu::buffer< PaddedToCacheLine< int > > nClustersPerModule
Definition Hitfinder.h:270
XPU_D void SortClusters(SortClusters::context &) const
XPU_D void CalculateOffsetsParallel(FindClusters::context &) const
XPU_D int ChanRight(int channel) const
Definition Hitfinder.h:348
XPU_D int ChanLeft(int channel) const
Definition Hitfinder.h:346
xpu::buffer< HitfinderMonDevice > monitor
Definition Hitfinder.h:224
xpu::buffer< float > landauTable
Definition Hitfinder.h:212
xpu::buffer< unsigned int > channelOffsetPerModule
Definition Hitfinder.h:242
xpu::buffer< ClusterIdx > clusterIdxPerModule
Definition Hitfinder.h:251
xpu::buffer< float > localToGlobalTranslationByModule
Definition Hitfinder.h:216
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
Definition Hitfinder.h:221
xpu::buffer< sts::Hit > hitsFlat
Definition Hitfinder.h:299
xpu::buffer< CbmStsDigi > digisPerModuleTmp
Definition Hitfinder.h:232
XPU_D float GetTimeResolution(int, int) const
Definition Hitfinder.h:335
XPU_D void FindClustersSingleStep(FindClusters::context &) const
Definition Hitfinder.cxx:73
xpu::buffer< float > localToGlobalRotationByModule
Definition Hitfinder.h:217
xpu::buffer< size_t > digiOffsetPerModule
Definition Hitfinder.h:228
xpu::buffer< sts::Hit > hitsPerModule
Definition Hitfinder.h:290
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
Definition Hitfinder.h:265
xpu::buffer< ClusterIdx * > clusterIdxSortedPerModule
Definition Hitfinder.h:260
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
Definition Hitfinder.h:374
sts::HitfinderPars::Asic asic
Definition Hitfinder.h:207
xpu::buffer< ClusterIdx > clusterIdxPerModuleTmp
Definition Hitfinder.h:255
xpu::buffer< CbmStsDigi > digisPerModule
Definition Hitfinder.h:229
XPU_D void SortDigisInSpaceAndTime(SortDigis::context &) const
Definition Hitfinder.cxx:52
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
Definition Hitfinder.h:350
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
Definition Hitfinder.h:330
XPU_D void FindClustersParallel(FindClusters::context &) const
XPU_D void FindClusterConnectionsDigiWise(FindClusters::context &ctx, CbmStsDigi *digis, DigiConnector *digiConnector, unsigned int *channelOffsets, unsigned int nDigis) const
xpu::buffer< PaddedToCacheLine< float > > maxClusterTimeErrorByModuleSide
Definition Hitfinder.h:274
XPU_D float GetClusterPosition(const HitfinderCache &pars, float centre, bool isFront) const
std::int32_t i32
Definition Definitions.h:20
std::uint32_t u32
Definition Definitions.h:21
@ kSortClustersItemsPerThread
Definition Hitfinder.h:36
@ kSortClustersBlockSize
Definition Hitfinder.h:35
@ kSortDigisItemsPerThread
Definition Hitfinder.h:34
@ kFindClusterBlockSize
Definition Hitfinder.h:37
@ kFindHitsBlockSize
Definition Hitfinder.h:38
@ kFindHitsChunksPerModule
Definition Hitfinder.h:40
@ kSortDigisBlockSize
Definition Hitfinder.h:33
XPU_D void operator()(context &)
Definition Hitfinder.cxx:21
xpu::block_size< kFindClusterBlockSize > block_size
Definition Hitfinder.h:79
xpu::kernel_context< shared_memory, constants > context
Definition Hitfinder.h:81
u32 fTime
Cluster time (average of digi times) [ns].
Definition Hitfinder.h:53
xpu::kernel_context< shared_memory, constants > context
Definition Hitfinder.h:95
XPU_D void operator()(context &)
Definition Hitfinder.cxx:33
xpu::block_size< kFindClusterBlockSize > block_size
Definition Hitfinder.h:93
xpu::block_size< kFindClusterBlockSize > block_size
Definition Hitfinder.h:86
xpu::kernel_context< shared_memory, constants > context
Definition Hitfinder.h:88
xpu::kernel_context< shared_memory, constants > context
Definition Hitfinder.h:74
XPU_D void operator()(context &)
Definition Hitfinder.cxx:18
xpu::block_size< kFindClusterBlockSize > block_size
Definition Hitfinder.h:72
xpu::openmp_settings< xpu::schedule_static, 1 > openmp
Definition Hitfinder.h:112
XPU_D void operator()(context &)
Definition Hitfinder.cxx:42
xpu::block_size< kFindHitsBlockSize > block_size
Definition Hitfinder.h:109
xpu::kernel_context< shared_memory, constants > context
Definition Hitfinder.h:111
xpu::block_size< kSortClustersBlockSize > block_size
Definition Hitfinder.h:100
XPU_D void operator()(context &)
Definition Hitfinder.cxx:39
sort_t::storage_t shared_memory
Definition Hitfinder.h:102
xpu::block_sort< u32, ClusterIdx, kSortClustersBlockSize, kSortClustersItemsPerThread > sort_t
Definition Hitfinder.h:101
xpu::kernel_context< shared_memory, constants > context
Definition Hitfinder.h:104
XPU_D void operator()(context &)
Definition Hitfinder.cxx:15
sort_t::storage_t shared_memory
Definition Hitfinder.h:65
xpu::block_size< kSortDigisBlockSize > block_size
Definition Hitfinder.h:63
xpu::block_sort< u64, CbmStsDigi, kSortDigisBlockSize, kSortDigisItemsPerThread > sort_t
Definition Hitfinder.h:64
xpu::kernel_context< shared_memory, constants > context
Definition Hitfinder.h:67