Project
Loading...
Searching...
No Matches
ClusterNative.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
15#ifndef ALICEO2_DATAFORMATSTPC_CLUSTERNATIVE_H
16#define ALICEO2_DATAFORMATSTPC_CLUSTERNATIVE_H
17#ifndef GPUCA_GPUCODE_DEVICE
18#include <climits>
19#include <cstdint>
20#include <cstddef> // for size_t
21#include <utility>
22#endif
24#include "GPUCommonDef.h"
25
26namespace o2
27{
28class MCCompLabel;
29namespace dataformats
30{
31template <class T>
32class ConstMCTruthContainer;
33template <class T>
34class ConstMCTruthContainerView;
35} // namespace dataformats
36} // namespace o2
37
38namespace o2
39{
40namespace tpc
41{
56 // NOTE: These states must match those from GPUTPCGMMergedTrackHit!
57 enum clusterState { flagSplitPad = 0x1, // Split in pad direction
58 flagSplitTime = 0x2, // Split in time direction
59 flagEdge = 0x4, // At edge of TPC sector
60 flagSingle = 0x8 }; // Single pad or single time-bin cluster
61
62 static constexpr int scaleTimePacked = 64; //< ~50 is needed for 0.1mm precision, but leads to float rounding artifacts around 20ms
63 static constexpr int scalePadPacked = 64; //< ~60 is needed for 0.1mm precision, but power of two avoids rounding
64 static constexpr int scaleSigmaTimePacked = 32; // 1/32nd of pad/timebin precision for cluster size
65 static constexpr int scaleSigmaPadPacked = 32;
66 static constexpr int scaleSaturatedQtot = 8;
67 static constexpr int maxRegularQtot = 25 * 1024;
68 static constexpr int maxSaturatedQtot = (USHRT_MAX - maxRegularQtot) * scaleSaturatedQtot;
69
70 uint32_t timeFlagsPacked; //< Contains the time in the lower 24 bits in a packed format, contains the flags in the
71 // upper 8 bits
72 uint16_t padPacked; //< Contains the pad in a packed format
73 uint8_t sigmaTimePacked; //< Sigma of the time in packed format
74 uint8_t sigmaPadPacked; //< Sigma of the pad in packed format
75 uint16_t qMax; //< QMax of the cluster
76 uint16_t qTotPacked; //< Total charge of the cluster
77
78 GPUd() static uint16_t packPad(float pad) { return (uint16_t)(pad * scalePadPacked + 0.5); }
79 GPUd() static uint32_t packTime(float time) { return (uint32_t)(time * scaleTimePacked + 0.5); }
80 GPUd() static float unpackPad(uint16_t pad) { return float(pad) * (1.f / scalePadPacked); }
81 GPUd() static float unpackTime(uint32_t time) { return float(time) * (1.f / scaleTimePacked); }
82
85 {
86 setTimePackedFlags(time, flags);
87 }
88
89 GPUd() uint16_t getQmax() const { return qMax; }
90 GPUd() uint32_t getQtot() const { return isSaturated() ? getSaturatedQtot() : (uint32_t)qTotPacked; }
91 GPUd() uint8_t getFlags() const { return timeFlagsPacked >> 24; }
92 GPUd() uint32_t getTimePacked() const { return timeFlagsPacked & 0xFFFFFF; }
93 GPUd() void setTimePackedFlags(uint32_t timePacked, uint8_t flags)
94 {
95 timeFlagsPacked = (timePacked & 0xFFFFFF) | (uint32_t)flags << 24;
96 }
97 GPUd() void setTimePacked(uint32_t timePacked)
98 {
99 timeFlagsPacked = (timePacked & 0xFFFFFF) | (timeFlagsPacked & 0xFF000000);
100 }
101 GPUd() void setFlags(uint8_t flags) { timeFlagsPacked = (timeFlagsPacked & 0xFFFFFF) | ((uint32_t)flags << 24); }
102 GPUd() float getTime() const { return unpackTime(timeFlagsPacked & 0xFFFFFF); }
103 GPUd() void setTime(float time)
104 {
105 timeFlagsPacked = (packTime(time) & 0xFFFFFF) | (timeFlagsPacked & 0xFF000000);
106 }
107 GPUd() void setTimeFlags(float time, uint8_t flags)
108 {
109 timeFlagsPacked = (packTime(time) & 0xFFFFFF) | ((decltype(timeFlagsPacked))flags << 24);
110 }
111
124 GPUd() float getPad() const { return unpackPad(padPacked); }
125 GPUd() void setPad(float pad) { padPacked = packPad(pad); }
126 GPUd() float getSigmaTime() const
127 {
128 if (isSaturated()) [[unlikely]] {
129 return 0;
130 }
131 return float(sigmaTimePacked) * (1.f / scaleSigmaTimePacked);
132 }
133 GPUd() void setSigmaTime(float sigmaTime)
134 {
135 uint32_t tmp = sigmaTime * scaleSigmaTimePacked + 0.5;
136 if (tmp > 0xFF) {
137 tmp = 0xFF;
138 }
139 sigmaTimePacked = tmp;
140 }
141 GPUd() float getSigmaPad() const { return float(sigmaPadPacked) * (1.f / scaleSigmaPadPacked); }
142 GPUd() void setSigmaPad(float sigmaPad)
143 {
144 uint32_t tmp = sigmaPad * scaleSigmaPadPacked + 0.5;
145 if (tmp > 0xFF) {
146 tmp = 0xFF;
147 }
148 sigmaPadPacked = tmp;
149 }
150
151 GPUd() bool isSaturated() const { return qTotPacked > maxRegularQtot; }
152
153 GPUd() void setSaturatedQtot(uint32_t qtot)
154 {
155 this->qTotPacked = USHRT_MAX;
156 if (qtot < maxSaturatedQtot) {
157 this->qTotPacked = ((qtot + scaleSaturatedQtot / 2) / scaleSaturatedQtot) + maxRegularQtot;
158 }
159 }
160
161 GPUd() uint32_t getSaturatedQtot() const
162 {
163 return uint32_t(qTotPacked - maxRegularQtot) * scaleSaturatedQtot;
164 }
165
166 GPUd() void setSaturatedTailLength(uint32_t tail)
167 {
168 sigmaTimePacked = encodeTailLength(tail);
169 }
170
171 GPUd() uint32_t getSaturatedTailLength() const
172 {
173 return decodeTailLength(sigmaTimePacked);
174 }
175
176 GPUd() bool operator<(const ClusterNative& rhs) const
177 {
178 if (this->getTimePacked() != rhs.getTimePacked()) {
179 return (this->getTimePacked() < rhs.getTimePacked());
180 } else if (this->padPacked != rhs.padPacked) {
181 return (this->padPacked < rhs.padPacked);
182 } else if (this->sigmaTimePacked != rhs.sigmaTimePacked) {
183 return (this->sigmaTimePacked < rhs.sigmaTimePacked);
184 } else if (this->sigmaPadPacked != rhs.sigmaPadPacked) {
185 return (this->sigmaPadPacked < rhs.sigmaPadPacked);
186 } else if (this->qMax != rhs.qMax) {
187 return (this->qMax < rhs.qMax);
188 } else if (this->qTotPacked != rhs.qTotPacked) {
189 return (this->getQtot() < rhs.getQtot());
190 } else {
191 return (this->getFlags() < rhs.getFlags());
192 }
193 }
194
195 GPUd() bool operator==(const ClusterNative& rhs) const
196 {
197 return this->getTimePacked() == rhs.getTimePacked() &&
198 this->padPacked == rhs.padPacked &&
199 this->sigmaTimePacked == rhs.sigmaTimePacked &&
200 this->sigmaPadPacked == rhs.sigmaPadPacked &&
201 this->qMax == rhs.qMax &&
202 this->qTotPacked == rhs.qTotPacked &&
203 this->getFlags() == rhs.getFlags();
204 }
205
206 private:
207 static constexpr GPUd() uint32_t decodeTailLength(uint8_t code)
208 {
209 // Quantize tail length into 8bits.
210 // Max expected length is 1500 tbs.
211 // But allow outliers up to 8000 tbs.
212 //
213 // Full code layout is:
214 //
215 // | Code range | Decoded values | Step | Codes |
216 // | ---------: | -------------: | ----: | ----: |
217 // | `0..63` | `0..63` | `1` | `64` |
218 // | `64..95` | `64..126` | `2` | `32` |
219 // | `96..127` | `128..252` | `4` | `32` |
220 // | `128..159` | `256..504` | `8` | `32` |
221 // | `160..223` | `512..1520` | `16` | `64` |
222 // | `224..239` | `1552..2032` | `32` | `16` |
223 // | `240..255` | `2048..8048` | `400` | `16` |
224 //
225
226 if (code < 64) {
227 return code;
228 }
229
230 if (code < 160) {
231 uint32_t q = (uint32_t)code - 64u;
232 uint32_t exponent = (q >> 5) + 1u; // 1, 2, 3
233 uint32_t mantissa = q & 31u; // 0..31
234
235 return (32u + mantissa) << exponent;
236 }
237
238 if (code < 224) {
239 return 512u + 16u * ((uint32_t)code - 160u);
240 }
241
242 if (code < 240) {
243 return 1552u + 32u * ((uint32_t)code - 224u);
244 }
245
246 return 2048u + 400u * ((uint32_t)code - 240u);
247 }
248
249 static constexpr GPUd() uint8_t encodeTailLength(uint32_t value)
250 {
251 // Saturate above representable range.
252 if (value >= decodeTailLength(255)) [[unlikely]] {
253 return 255;
254 }
255
256 // Binary search for the first code whose decoded value >= value.
257 uint8_t lo = 0;
258 uint8_t hi = 255;
259
260 while (lo < hi) {
261 uint8_t mid = lo + ((hi - lo) >> 1);
262 uint32_t decoded = decodeTailLength(mid);
263
264 if (decoded < value) {
265 lo = mid + 1;
266 } else {
267 hi = mid;
268 }
269 }
270
271 // lo is now the first code with decoded >= value.
272 if (lo == 0) [[unlikely]] {
273 return 0;
274 }
275
276 uint8_t above_code = lo;
277 uint8_t below_code = lo - 1;
278
279 uint32_t above_value = decodeTailLength(above_code);
280 uint32_t below_value = decodeTailLength(below_code);
281
282 uint32_t above_error = above_value - value;
283 uint32_t below_error = value - below_value;
284
285 // Tie-break downward.
286 if (below_error <= above_error) {
287 return below_code;
288 } else {
289 return above_code;
290 }
291 }
292};
293
294// This is an index struct to access TPC clusters inside sectors and rows. It shall not own the data, but just point to
295// the data inside a buffer.
313
315{
316 int offset = 0;
317 for (unsigned int i = 0; i < constants::MAXSECTOR; i++) {
318 nClustersSector[i] = 0;
319 for (unsigned int j = 0; j < constants::MAXGLOBALPADROW; j++) {
323 offset += nClusters[i][j];
324 }
325 }
327}
328} // namespace tpc
329} // namespace o2
330#endif
int16_t time
Definition RawEventData.h:4
int32_t i
uint32_t j
Definition RawData.h:0
A read-only version of MCTruthContainer allowing for storage optimisation.
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLintptr offset
Definition glcorearb.h:660
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLbitfield flags
Definition glcorearb.h:1570
uint8_t itsSharedClusterMap uint8_t
constexpr int MAXSECTOR
Definition Constants.h:28
constexpr int MAXGLOBALPADROW
Definition Constants.h:34
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string getTime(uint64_t ts)
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int nClustersSector[constants::MAXSECTOR]
const o2::dataformats::ConstMCTruthContainerView< o2::MCCompLabel > * clustersMCTruth
std::pair< ConstMCLabelContainer, ConstMCLabelContainerView > ConstMCLabelContainerViewWithBuffer
const ClusterNative * clusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int clusterOffset[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clustersLinear
uint8_t uint16_t uint8_t uint8_t uint16_t uint16_t qtotPacked
uint8_t uint16_t pad
GPUd() bool operator<(const ClusterNative &rhs) const
GPUd() static float unpackTime(uint32_t time)
static constexpr int scaleSigmaTimePacked
uint8_t uint16_t uint8_t sigmaTime
uint8_t uint16_t uint8_t uint8_t uint16_t qmax
GPUd() uint32_t getTimePacked() const
GPUd() void setFlags(uint8_t flags)
static constexpr int maxSaturatedQtot
GPUd() uint16_t getQmax() const
GPUd() uint8_t getFlags() const
GPUd() float getSigmaTime() const
static constexpr int scaleTimePacked
GPUdDefault() ClusterNative()=default
GPUd() float getTime() const
static constexpr int scaleSaturatedQtot
GPUd() uint32_t getSaturatedTailLength() const
GPUd() static float unpackPad(uint16_t pad)
GPUd() void setTime(float time)
GPUd() void setTimeFlags(float time
static constexpr int scaleSigmaPadPacked
GPUd() static uint16_t packPad(float pad)
GPUd() uint32_t getQtot() const
uint8_t uint16_t uint8_t uint8_t sigmaPad
GPUd() void setSigmaPad(float sigmaPad)
static constexpr int maxRegularQtot
GPUd() void setSaturatedTailLength(uint32_t tail)
GPUd() uint32_t getSaturatedQtot() const
GPUd() float getPad() const
static constexpr int scalePadPacked
GPUd() void setPad(float pad)
GPUd() void setTimePacked(uint32_t timePacked)
GPUd() void setSaturatedQtot(uint32_t qtot)
GPUd() static uint32_t packTime(float time)
GPUd() void setTimePackedFlags(uint32_t timePacked
GPUd() bool isSaturated() const
GPUd() float getSigmaPad() const
GPUd() void setSigmaTime(float sigmaTime)