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 qTot; //< 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
84 GPUd() ClusterNative(uint32_t time, uint8_t flags, uint16_t pad, uint8_t sigmaTime, uint8_t sigmaPad, uint16_t qmax, uint16_t qtot) : padPacked(pad), sigmaTimePacked(sigmaTime), sigmaPadPacked(sigmaPad), qMax(qmax), qTot(qtot)
85 {
86 setTimePackedFlags(time, flags);
87 }
88
89 GPUd() uint16_t getQmax() const { return qMax; }
90 GPUd() uint16_t getQtot() const
91 {
92 if (isSaturated()) [[unlikely]] {
93 auto sQtot = getSaturatedQtot();
94 return sQtot < USHRT_MAX ? sQtot : USHRT_MAX;
95 }
96 return qTot;
97 }
98 GPUd() uint8_t getFlags() const { return timeFlagsPacked >> 24; }
99 GPUd() uint32_t getTimePacked() const { return timeFlagsPacked & 0xFFFFFF; }
100 GPUd() void setTimePackedFlags(uint32_t timePacked, uint8_t flags)
101 {
102 timeFlagsPacked = (timePacked & 0xFFFFFF) | (uint32_t)flags << 24;
103 }
104 GPUd() void setTimePacked(uint32_t timePacked)
105 {
106 timeFlagsPacked = (timePacked & 0xFFFFFF) | (timeFlagsPacked & 0xFF000000);
107 }
108 GPUd() void setFlags(uint8_t flags) { timeFlagsPacked = (timeFlagsPacked & 0xFFFFFF) | ((uint32_t)flags << 24); }
109 GPUd() float getTime() const { return unpackTime(timeFlagsPacked & 0xFFFFFF); }
110 GPUd() void setTime(float time)
111 {
112 timeFlagsPacked = (packTime(time) & 0xFFFFFF) | (timeFlagsPacked & 0xFF000000);
113 }
114 GPUd() void setTimeFlags(float time, uint8_t flags)
115 {
116 timeFlagsPacked = (packTime(time) & 0xFFFFFF) | ((decltype(timeFlagsPacked))flags << 24);
117 }
118
131 GPUd() float getPad() const { return unpackPad(padPacked); }
132 GPUd() void setPad(float pad) { padPacked = packPad(pad); }
133 GPUd() float getSigmaTime() const
134 {
135 if (isSaturated()) [[unlikely]] {
136 return 0;
137 }
138 return float(sigmaTimePacked) * (1.f / scaleSigmaTimePacked);
139 }
140 GPUd() void setSigmaTime(float sigmaTime)
141 {
142 uint32_t tmp = sigmaTime * scaleSigmaTimePacked + 0.5;
143 if (tmp > 0xFF) {
144 tmp = 0xFF;
145 }
146 sigmaTimePacked = tmp;
147 }
148 GPUd() float getSigmaPad() const { return float(sigmaPadPacked) * (1.f / scaleSigmaPadPacked); }
149 GPUd() void setSigmaPad(float sigmaPad)
150 {
151 uint32_t tmp = sigmaPad * scaleSigmaPadPacked + 0.5;
152 if (tmp > 0xFF) {
153 tmp = 0xFF;
154 }
155 sigmaPadPacked = tmp;
156 }
157
158 GPUd() bool isSaturated() const { return qTot > maxRegularQtot; }
159
160 GPUd() void setSaturatedQtot(uint32_t qtot)
161 {
162 this->qTot = USHRT_MAX;
163 if (qtot < maxSaturatedQtot) {
164 this->qTot = ((qtot + scaleSaturatedQtot / 2) / scaleSaturatedQtot) + maxRegularQtot;
165 }
166 }
167
168 GPUd() uint32_t getSaturatedQtot() const
169 {
170 return uint32_t(qTot - maxRegularQtot) * scaleSaturatedQtot;
171 }
172
173 GPUd() void setSaturatedTailLength(uint32_t tail)
174 {
175 sigmaTimePacked = encodeTailLength(tail);
176 }
177
178 GPUd() uint32_t getSaturatedTailLength() const
179 {
180 return decodeTailLength(sigmaTimePacked);
181 }
182
183 GPUd() bool operator<(const ClusterNative& rhs) const
184 {
185 if (this->getTimePacked() != rhs.getTimePacked()) {
186 return (this->getTimePacked() < rhs.getTimePacked());
187 } else if (this->padPacked != rhs.padPacked) {
188 return (this->padPacked < rhs.padPacked);
189 } else if (this->sigmaTimePacked != rhs.sigmaTimePacked) {
190 return (this->sigmaTimePacked < rhs.sigmaTimePacked);
191 } else if (this->sigmaPadPacked != rhs.sigmaPadPacked) {
192 return (this->sigmaPadPacked < rhs.sigmaPadPacked);
193 } else if (this->qMax != rhs.qMax) {
194 return (this->qMax < rhs.qMax);
195 } else if (this->qTot != rhs.qTot) {
196 return (this->qTot < rhs.qTot);
197 } else {
198 return (this->getFlags() < rhs.getFlags());
199 }
200 }
201
202 GPUd() bool operator==(const ClusterNative& rhs) const
203 {
204 return this->getTimePacked() == rhs.getTimePacked() &&
205 this->padPacked == rhs.padPacked &&
206 this->sigmaTimePacked == rhs.sigmaTimePacked &&
207 this->sigmaPadPacked == rhs.sigmaPadPacked &&
208 this->qMax == rhs.qMax &&
209 this->qTot == rhs.qTot &&
210 this->getFlags() == rhs.getFlags();
211 }
212
213 private:
214 static constexpr GPUd() uint32_t decodeTailLength(uint8_t code)
215 {
216 // Quantize tail length into 8bits.
217 // Max expected length is 1500 tbs.
218 // But allow outliers up to 8000 tbs.
219 //
220 // Full code layout is:
221 //
222 // | Code range | Decoded values | Step | Codes |
223 // | ---------: | -------------: | ----: | ----: |
224 // | `0..63` | `0..63` | `1` | `64` |
225 // | `64..95` | `64..126` | `2` | `32` |
226 // | `96..127` | `128..252` | `4` | `32` |
227 // | `128..159` | `256..504` | `8` | `32` |
228 // | `160..223` | `512..1520` | `16` | `64` |
229 // | `224..239` | `1552..2032` | `32` | `16` |
230 // | `240..255` | `2048..8048` | `400` | `16` |
231 //
232
233 if (code < 64) {
234 return code;
235 }
236
237 if (code < 160) {
238 uint32_t q = (uint32_t)code - 64u;
239 uint32_t exponent = (q >> 5) + 1u; // 1, 2, 3
240 uint32_t mantissa = q & 31u; // 0..31
241
242 return (32u + mantissa) << exponent;
243 }
244
245 if (code < 224) {
246 return 512u + 16u * ((uint32_t)code - 160u);
247 }
248
249 if (code < 240) {
250 return 1552u + 32u * ((uint32_t)code - 224u);
251 }
252
253 return 2048u + 400u * ((uint32_t)code - 240u);
254 }
255
256 static constexpr GPUd() uint8_t encodeTailLength(uint32_t value)
257 {
258 // Saturate above representable range.
259 if (value >= decodeTailLength(255)) [[unlikely]] {
260 return 255;
261 }
262
263 // Binary search for the first code whose decoded value >= value.
264 uint8_t lo = 0;
265 uint8_t hi = 255;
266
267 while (lo < hi) {
268 uint8_t mid = lo + ((hi - lo) >> 1);
269 uint32_t decoded = decodeTailLength(mid);
270
271 if (decoded < value) {
272 lo = mid + 1;
273 } else {
274 hi = mid;
275 }
276 }
277
278 // lo is now the first code with decoded >= value.
279 if (lo == 0) [[unlikely]] {
280 return 0;
281 }
282
283 uint8_t above_code = lo;
284 uint8_t below_code = lo - 1;
285
286 uint32_t above_value = decodeTailLength(above_code);
287 uint32_t below_value = decodeTailLength(below_code);
288
289 uint32_t above_error = above_value - value;
290 uint32_t below_error = value - below_value;
291
292 // Tie-break downward.
293 if (below_error <= above_error) {
294 return below_code;
295 } else {
296 return above_code;
297 }
298 }
299};
300
301// This is an index struct to access TPC clusters inside sectors and rows. It shall not own the data, but just point to
302// the data inside a buffer.
320
322{
323 int offset = 0;
324 for (unsigned int i = 0; i < constants::MAXSECTOR; i++) {
325 nClustersSector[i] = 0;
326 for (unsigned int j = 0; j < constants::MAXGLOBALPADROW; j++) {
330 offset += nClusters[i][j];
331 }
332 }
334}
335} // namespace tpc
336} // namespace o2
337#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 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 uint8_t uint16_t uint16_t qtot
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)
uint8_t uint16_t uint8_t uint8_t sigmaPad
GPUd() uint16_t getQtot() const
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)