Project
Loading...
Searching...
No Matches
CMVContainer.cxx
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
14
15#include <stdexcept>
16#include <cstdint>
17#include <cmath>
18#include <algorithm>
19#include <map>
20#include <fmt/format.h>
21
22#include "TFile.h"
23
25#include "TPCBase/CRU.h"
26#include "DataFormatsTPC/CMV.h"
27
28namespace o2::tpc
29{
30
31// CMVPerTF private helpers
32
33int32_t CMVPerTF::cmvToSigned(uint16_t raw)
34{
35 const int32_t mag = raw & 0x7FFF;
36 return (raw >> 15) ? mag : -mag;
37}
38
39uint16_t CMVPerTF::quantizeBelowThreshold(uint16_t raw, float quantizationMean, float quantizationSigma)
40{
41 if (raw == 0u) {
42 return raw;
43 }
44
45 if (quantizationSigma <= 0.f) {
46 return raw;
47 }
48
49 const float adc = (raw & 0x7FFFu) / 128.f;
50 const float distance = (adc - quantizationMean) / quantizationSigma;
51 const float lossStrength = std::exp(-0.5f * distance * distance);
52
53 // A true Gaussian bell: strongest trimming around the mean, then gradual recovery away from it
54 float quantizedADC = adc;
55 if (lossStrength > 0.85f) {
56 quantizedADC = std::round(adc * 10.f) / 10.f;
57 } else if (lossStrength > 0.60f) {
58 quantizedADC = std::round(adc * 100.f) / 100.f;
59 } else if (lossStrength > 0.30f) {
60 quantizedADC = std::round(adc * 1000.f) / 1000.f;
61 } else if (lossStrength > 0.12f) {
62 quantizedADC = std::round(adc * 10000.f) / 10000.f;
63 } else if (lossStrength > 0.03f) {
64 quantizedADC = std::round(adc * 1000000.f) / 1000000.f;
65 }
66
67 // Snap the chosen decimal-style value back to the nearest raw I8F7 level
68 const uint16_t quantizedMagnitude = static_cast<uint16_t>(std::clamp(std::lround(quantizedADC * 128.f), 0l, 0x7FFFl));
69 return static_cast<uint16_t>((raw & 0x8000u) | quantizedMagnitude);
70}
71
72uint32_t CMVPerTF::zigzagEncode(int32_t value)
73{
74 return (static_cast<uint32_t>(value) << 1) ^ static_cast<uint32_t>(value >> 31);
75}
76
77void CMVPerTF::encodeVarintInto(uint32_t value, std::vector<uint8_t>& out)
78{
79 while (value > 0x7F) {
80 out.push_back(static_cast<uint8_t>((value & 0x7F) | 0x80));
81 value >>= 7;
82 }
83 out.push_back(static_cast<uint8_t>(value));
84}
85
86// Shared file-local helpers
87
88namespace
89{
90
91int32_t zigzagDecodeLocal(uint32_t value)
92{
93 return static_cast<int32_t>((value >> 1) ^ -(value & 1));
94}
95
96uint16_t signedToCmvLocal(int32_t val)
97{
98 const uint16_t mag = static_cast<uint16_t>(std::abs(val)) & 0x7FFF;
99 return static_cast<uint16_t>((val >= 0 ? 0x8000u : 0u) | mag);
100}
101
102uint32_t decodeVarintLocal(const uint8_t*& data, const uint8_t* end)
103{
104 uint32_t value = 0;
105 int shift = 0;
106 while (data < end && (*data & 0x80)) {
107 value |= static_cast<uint32_t>(*data & 0x7F) << shift;
108 shift += 7;
109 ++data;
110 }
111 if (data >= end) {
112 throw std::runtime_error("decodeVarintLocal: unexpected end of varint data");
113 }
114 value |= static_cast<uint32_t>(*data) << shift;
115 ++data;
116 return value;
117}
118
125void huffmanEncode(const std::vector<uint32_t>& symbols, std::vector<uint8_t>& buf)
126{
127 if (symbols.empty()) {
128 // Write a valid empty Huffman stream: numSymbols=0, totalBits=0.
129 // The decoder handles this correctly (returns an empty symbol vector).
130 for (int i = 0; i < 12; ++i) {
131 buf.push_back(0);
132 }
133 return;
134 }
135
136 // Frequency count
137 std::map<uint32_t, uint64_t> freq;
138 for (const uint32_t z : symbols) {
139 ++freq[z];
140 }
141
142 // Build tree using index-based min-heap
143 struct HNode {
144 uint64_t freq{0};
145 uint32_t sym{0};
146 int left{-1}, right{-1};
147 bool isLeaf{true};
148 };
149 std::vector<HNode> nodes;
150 nodes.reserve(freq.size() * 2);
151 for (const auto& [sym, f] : freq) {
152 nodes.push_back({f, sym, -1, -1, true});
153 }
154
155 auto cmp = [&](int a, int b) {
156 return nodes[a].freq != nodes[b].freq ? nodes[a].freq > nodes[b].freq : nodes[a].sym > nodes[b].sym;
157 };
158 std::vector<int> heap;
159 heap.reserve(nodes.size());
160 for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
161 heap.push_back(i);
162 }
163 std::make_heap(heap.begin(), heap.end(), cmp);
164
165 while (heap.size() > 1) {
166 std::pop_heap(heap.begin(), heap.end(), cmp);
167 const int a = heap.back();
168 heap.pop_back();
169 std::pop_heap(heap.begin(), heap.end(), cmp);
170 const int b = heap.back();
171 heap.pop_back();
172 nodes.push_back({nodes[a].freq + nodes[b].freq, 0, a, b, false});
173 heap.push_back(static_cast<int>(nodes.size()) - 1);
174 std::push_heap(heap.begin(), heap.end(), cmp);
175 }
176
177 // Assign code lengths via iterative DFS
178 std::map<uint32_t, uint8_t> codeLens;
179 {
180 const int root = heap[0];
181 std::vector<std::pair<int, int>> stack;
182 stack.push_back({root, 0});
183 while (!stack.empty()) {
184 auto [idx, depth] = stack.back();
185 stack.pop_back();
186 if (nodes[idx].isLeaf) {
187 codeLens[nodes[idx].sym] = static_cast<uint8_t>(depth == 0 ? 1 : depth);
188 } else {
189 stack.push_back({nodes[idx].left, depth + 1});
190 stack.push_back({nodes[idx].right, depth + 1});
191 }
192 }
193 }
194
195 // Sort by (codeLen ASC, symbol ASC) for canonical assignment
196 struct SymLen {
197 uint32_t sym;
198 uint8_t len;
199 };
200 std::vector<SymLen> symLens;
201 symLens.reserve(codeLens.size());
202 for (const auto& [sym, len] : codeLens) {
203 symLens.push_back({sym, len});
204 }
205 std::sort(symLens.begin(), symLens.end(), [](const SymLen& a, const SymLen& b) {
206 return a.len != b.len ? a.len < b.len : a.sym < b.sym;
207 });
208
209 // Assign canonical codes
210 std::map<uint32_t, std::pair<uint32_t, uint8_t>> codeTable;
211 {
212 uint32_t code = 0;
213 uint8_t prevLen = 0;
214 for (const auto& sl : symLens) {
215 if (prevLen != 0) {
216 code = (code + 1) << (sl.len - prevLen);
217 }
218 codeTable[sl.sym] = {code, sl.len};
219 prevLen = sl.len;
220 }
221 }
222
223 // Serialise table header
224 buf.reserve(buf.size() + 4 + symLens.size() * 5 + 8 + (symbols.size() / 8 + 1));
225 const uint32_t numSym = static_cast<uint32_t>(symLens.size());
226 for (int i = 0; i < 4; ++i) {
227 buf.push_back(static_cast<uint8_t>((numSym >> (8 * i)) & 0xFF));
228 }
229 for (const auto& sl : symLens) {
230 for (int i = 0; i < 4; ++i) {
231 buf.push_back(static_cast<uint8_t>((sl.sym >> (8 * i)) & 0xFF));
232 }
233 buf.push_back(sl.len);
234 }
235
236 // Placeholder for totalBits
237 const size_t totalBitsOffset = buf.size();
238 for (int i = 0; i < 8; ++i) {
239 buf.push_back(0);
240 }
241
242 // Encode bitstream (MSB-first)
243 uint64_t totalBits = 0;
244 uint8_t curByte = 0;
245 int bitsInByte = 0;
246 for (const uint32_t z : symbols) {
247 const auto& [code, len] = codeTable.at(z);
248 for (int b = static_cast<int>(len) - 1; b >= 0; --b) {
249 curByte = static_cast<uint8_t>(curByte | (((code >> b) & 1u) << (7 - bitsInByte)));
250 ++bitsInByte;
251 ++totalBits;
252 if (bitsInByte == 8) {
253 buf.push_back(curByte);
254 curByte = 0;
255 bitsInByte = 0;
256 }
257 }
258 }
259 if (bitsInByte > 0) {
260 buf.push_back(curByte);
261 }
262
263 // Backfill totalBits
264 for (int i = 0; i < 8; ++i) {
265 buf[totalBitsOffset + i] = static_cast<uint8_t>((totalBits >> (8 * i)) & 0xFF);
266 }
267}
268
272std::vector<uint32_t> huffmanDecode(const uint8_t*& ptr, const uint8_t* end, uint32_t N)
273{
274 auto readU32 = [&]() -> uint32_t {
275 if (ptr + 4 > end) {
276 throw std::runtime_error("huffmanDecode: unexpected end reading uint32");
277 }
278 const uint32_t v = static_cast<uint32_t>(ptr[0]) | (static_cast<uint32_t>(ptr[1]) << 8) |
279 (static_cast<uint32_t>(ptr[2]) << 16) | (static_cast<uint32_t>(ptr[3]) << 24);
280 ptr += 4;
281 return v;
282 };
283
284 const uint32_t numSym = readU32();
285 struct SymLen {
286 uint32_t sym;
287 uint8_t len;
288 };
289 std::vector<SymLen> symLens(numSym);
290 for (uint32_t i = 0; i < numSym; ++i) {
291 symLens[i].sym = readU32();
292 if (ptr >= end) {
293 throw std::runtime_error("huffmanDecode: unexpected end reading code length");
294 }
295 symLens[i].len = *ptr++;
296 }
297
298 std::map<uint8_t, uint32_t> firstCode;
299 std::map<uint8_t, std::vector<uint32_t>> symsByLen;
300 {
301 uint32_t code = 0;
302 uint8_t prevLen = 0;
303 for (const auto& sl : symLens) {
304 if (prevLen != 0) {
305 code = (code + 1) << (sl.len - prevLen);
306 }
307 if (!firstCode.count(sl.len)) {
308 firstCode[sl.len] = code;
309 }
310 symsByLen[sl.len].push_back(sl.sym);
311 prevLen = sl.len;
312 }
313 }
314
315 if (ptr + 8 > end) {
316 throw std::runtime_error("huffmanDecode: unexpected end reading totalBits");
317 }
318 uint64_t totalBits = 0;
319 for (int i = 0; i < 8; ++i) {
320 totalBits |= static_cast<uint64_t>(ptr[i]) << (8 * i);
321 }
322 ptr += 8;
323
324 const uint8_t minLen = symLens.empty() ? 1 : symLens.front().len;
325 const uint8_t maxLen = symLens.empty() ? 1 : symLens.back().len;
326 uint64_t bitsRead = 0;
327 uint8_t curByte = 0;
328 int bitPos = -1;
329
330 auto nextBit = [&]() -> int {
331 if (bitPos < 0) {
332 if (ptr >= end) {
333 throw std::runtime_error("huffmanDecode: unexpected end of bitstream");
334 }
335 curByte = *ptr++;
336 bitPos = 7;
337 }
338 const int bit = (curByte >> bitPos) & 1;
339 --bitPos;
340 return bit;
341 };
342
343 std::vector<uint32_t> out;
344 out.reserve(N);
345 while (out.size() < N) {
346 uint32_t accum = 0;
347 bool found = false;
348 for (uint8_t curLen = 1; curLen <= maxLen; ++curLen) {
349 if (bitsRead >= totalBits) {
350 throw std::runtime_error("huffmanDecode: bitstream exhausted before all symbols decoded");
351 }
352 accum = (accum << 1) | static_cast<uint32_t>(nextBit());
353 ++bitsRead;
354 if (curLen < minLen) {
355 continue;
356 }
357 const auto fcIt = firstCode.find(curLen);
358 if (fcIt == firstCode.end()) {
359 continue;
360 }
361 if (accum >= fcIt->second) {
362 const uint32_t idx = accum - fcIt->second;
363 const auto& sv = symsByLen.at(curLen);
364 if (idx < sv.size()) {
365 out.push_back(sv[idx]);
366 found = true;
367 break;
368 }
369 }
370 }
371 if (!found) {
372 throw std::runtime_error("huffmanDecode: invalid Huffman code in bitstream");
373 }
374 }
375 return out;
376}
377
378} // anonymous namespace
379
380// CMVPerTF public methods
381
382uint16_t CMVPerTF::getCMV(const int cru, const int timeBin) const
383{
384 if (cru < 0 || cru >= static_cast<int>(CRU::MaxCRU)) {
385 throw std::out_of_range(fmt::format("CMVPerTF::getCMV: cru {} out of range [0, {})", cru, static_cast<int>(CRU::MaxCRU)));
386 }
387 if (timeBin < 0 || static_cast<uint32_t>(timeBin) >= cmv::NTimeBinsPerTF) {
388 throw std::out_of_range(fmt::format("CMVPerTF::getCMV: timeBin {} out of range [0, {})", timeBin, static_cast<int>(cmv::NTimeBinsPerTF)));
389 }
390 return mDataPerTF[cru * cmv::NTimeBinsPerTF + timeBin];
391}
392
393float CMVPerTF::getCMVFloat(const int cru, const int timeBin) const
394{
395 const uint16_t raw = getCMV(cru, timeBin);
396 const uint16_t mag = raw & 0x7FFF;
397 if (mag == 0) {
398 return 0.0f; // 0x0000 and 0x8000 both represent zero; return +0 to avoid -0 display
399 }
400 const bool positive = (raw >> 15) & 1; // bit 15: sign (1=positive, 0=negative)
401 return positive ? mag / 128.f : -mag / 128.f;
402}
403
404void CMVPerTF::zeroSmallValues(float threshold)
405{
406 if (threshold <= 0.f) {
407 return;
408 }
409 for (uint32_t i = 0; i < static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF; ++i) {
410 const float mag = (mDataPerTF[i] & 0x7FFF) / 128.f;
411 if (mag < threshold) {
412 mDataPerTF[i] = 0;
413 }
414 }
415}
416
418{
419 if (threshold == 0) {
420 return;
421 }
422 for (uint32_t i = 0; i < static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF; ++i) {
423 const uint16_t raw = mDataPerTF[i];
424 if (raw == 0) {
425 continue;
426 }
427 const uint16_t rounded = static_cast<uint16_t>(((raw & 0x7FFFu) + 64u) >> 7);
428 if (rounded > threshold) {
429 continue; // above range: keep full precision
430 }
431 mDataPerTF[i] = (rounded == 0) ? 0 : static_cast<uint16_t>((raw & 0x8000u) | (rounded << 7));
432 }
433}
434
435void CMVPerTF::trimGaussianPrecision(float mean, float sigma)
436{
437 if (sigma <= 0.f) {
438 return;
439 }
440
441 for (uint32_t i = 0; i < static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF; ++i) {
442 mDataPerTF[i] = quantizeBelowThreshold(mDataPerTF[i], mean, sigma);
443 }
444}
445
447{
451 out.mFlags = flags;
452
454 // --- Sparse path: position stream + value stream ---
455
456 // Single pass per CRU: build the position stream and collect raw non-zero values.
457 std::vector<uint8_t> posStream;
458 std::vector<uint16_t> rawValues;
459
460 for (int cru = 0; cru < static_cast<int>(CRU::MaxCRU); ++cru) {
461 struct Entry {
462 uint32_t tb;
464 };
465 std::vector<Entry> entries;
466 for (uint32_t tb = 0; tb < cmv::NTimeBinsPerTF; ++tb) {
467 const uint16_t val = mDataPerTF[cru * cmv::NTimeBinsPerTF + tb];
468 if (val != 0) {
469 entries.push_back({tb, val});
470 }
471 }
472
473 encodeVarintInto(static_cast<uint32_t>(entries.size()), posStream);
474 uint32_t prevTB = 0;
475 bool first = true;
476 for (const auto& e : entries) {
477 encodeVarintInto(first ? e.tb : (e.tb - prevTB), posStream);
478 rawValues.push_back(e.val);
479 prevTB = e.tb;
480 first = false;
481 }
482 }
483
484 // Encode the value stream based on flags.
485 std::vector<uint8_t> valStream;
487 std::vector<uint32_t> zigzags;
488 zigzags.reserve(rawValues.size());
489 for (const uint16_t v : rawValues) {
490 zigzags.push_back(zigzagEncode(cmvToSigned(v)));
491 }
493 huffmanEncode(zigzags, valStream);
494 } else { // kVarint
495 for (const uint32_t z : zigzags) {
496 encodeVarintInto(z, valStream);
497 }
498 }
499 } else {
500 // Raw uint16 LE
501 for (const uint16_t v : rawValues) {
502 valStream.push_back(static_cast<uint8_t>(v & 0xFF));
503 valStream.push_back(static_cast<uint8_t>(v >> 8));
504 }
505 }
506
507 // Assemble: [4 bytes posStreamSize][posStream][valStream]
508 const uint32_t posStreamSize = static_cast<uint32_t>(posStream.size());
509 out.mData.reserve(4 + posStream.size() + valStream.size());
510 for (int i = 0; i < 4; ++i) {
511 out.mData.push_back(static_cast<uint8_t>((posStreamSize >> (8 * i)) & 0xFF));
512 }
513 out.mData.insert(out.mData.end(), posStream.begin(), posStream.end());
514 out.mData.insert(out.mData.end(), valStream.begin(), valStream.end());
515
516 } else {
517 // --- Dense path: all CRU * TimeBin values ---
518 const uint32_t total = static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF;
519
520 if (!(flags & CMVEncoding::kZigzag)) {
521 // No encoding: raw uint16 LE
522 out.mData.reserve(total * 2);
523 for (uint32_t i = 0; i < total; ++i) {
524 out.mData.push_back(static_cast<uint8_t>(mDataPerTF[i] & 0xFF));
525 out.mData.push_back(static_cast<uint8_t>(mDataPerTF[i] >> 8));
526 }
527 } else {
528 // Zigzag + optional delta (CRU-major, time-minor)
529 const bool useDelta = (flags & CMVEncoding::kDelta) != 0;
530 std::vector<uint32_t> zigzags;
531 zigzags.reserve(total);
532 for (int cru = 0; cru < static_cast<int>(CRU::MaxCRU); ++cru) {
533 int32_t prev = 0;
534 for (uint32_t tb = 0; tb < cmv::NTimeBinsPerTF; ++tb) {
535 const int32_t val = cmvToSigned(mDataPerTF[cru * cmv::NTimeBinsPerTF + tb]);
536 const int32_t encoded = useDelta ? (val - prev) : val;
537 if (useDelta) {
538 prev = val;
539 }
540 zigzags.push_back(zigzagEncode(encoded));
541 }
542 }
543
545 huffmanEncode(zigzags, out.mData);
546 } else { // kVarint
547 for (const uint32_t z : zigzags) {
548 encodeVarintInto(z, out.mData);
549 }
550 }
551 }
552 }
553
554 return out;
555}
556
557// CMVPerTFCompressed::decompress staged pipeline
558
559std::vector<std::pair<int, uint32_t>> CMVPerTFCompressed::decodeSparsePositions(const uint8_t*& ptr, const uint8_t* end)
560{
561 // Read 4-byte LE posStreamSize
562 if (ptr + 4 > end) {
563 throw std::runtime_error("CMVPerTFCompressed::decompress: truncated position header");
564 }
565 const uint32_t posStreamSize = static_cast<uint32_t>(ptr[0]) | (static_cast<uint32_t>(ptr[1]) << 8) |
566 (static_cast<uint32_t>(ptr[2]) << 16) | (static_cast<uint32_t>(ptr[3]) << 24);
567 ptr += 4;
568
569 const uint8_t* posEnd = ptr + posStreamSize;
570 if (posEnd > end) {
571 throw std::runtime_error("CMVPerTFCompressed::decompress: posStream overflows payload");
572 }
573
574 // Decode per-CRU varint(N) + N×varint(tb_delta)
575 std::vector<std::pair<int, uint32_t>> positions;
576 const uint8_t* p = ptr;
577 for (int cru = 0; cru < static_cast<int>(CRU::MaxCRU); ++cru) {
578 const uint32_t count = decodeVarintLocal(p, posEnd);
579 uint32_t tb = 0;
580 bool first = true;
581 for (uint32_t i = 0; i < count; ++i) {
582 const uint32_t delta = decodeVarintLocal(p, posEnd);
583 tb = first ? delta : (tb + delta);
584 first = false;
585 positions.emplace_back(cru, tb);
586 }
587 }
588 ptr = posEnd; // advance past the entire position block
589 return positions;
590}
591
592std::vector<uint32_t> CMVPerTFCompressed::decodeValueStream(const uint8_t*& ptr, const uint8_t* end, uint32_t N, uint8_t flags)
593{
595 // Huffman-encoded symbols
596 return huffmanDecode(ptr, end, N);
597 }
598
600 // Varint-encoded symbols
601 std::vector<uint32_t> out;
602 out.reserve(N);
603 for (uint32_t i = 0; i < N; ++i) {
604 out.push_back(decodeVarintLocal(ptr, end));
605 }
606 return out;
607 }
608
609 // Raw uint16 LE (no value encoding)
610 std::vector<uint32_t> out;
611 out.reserve(N);
612 for (uint32_t i = 0; i < N; ++i) {
613 if (ptr + 2 > end) {
614 throw std::runtime_error("CMVPerTFCompressed::decompress: unexpected end in raw value stream");
615 }
616 const uint16_t v = static_cast<uint16_t>(ptr[0]) | (static_cast<uint16_t>(ptr[1]) << 8);
617 ptr += 2;
618 out.push_back(v);
619 }
620 return out;
621}
622
623void CMVPerTFCompressed::decodeSparseValues(const std::vector<uint32_t>& symbols,
624 const std::vector<std::pair<int, uint32_t>>& positions,
625 uint8_t flags, CMVPerTF* cmv)
626{
627 const bool useZigzag = (flags & CMVEncoding::kZigzag) != 0;
628 for (uint32_t i = 0; i < static_cast<uint32_t>(positions.size()); ++i) {
630 if (useZigzag) {
631 raw = signedToCmvLocal(zigzagDecodeLocal(symbols[i]));
632 } else {
633 raw = static_cast<uint16_t>(symbols[i]);
634 }
635 cmv->mDataPerTF[positions[i].first * cmv::NTimeBinsPerTF + positions[i].second] = raw;
636 }
637}
638
639void CMVPerTFCompressed::decodeDenseValues(const std::vector<uint32_t>& symbols, uint8_t flags, CMVPerTF* cmv)
640{
641 const bool useZigzag = (flags & CMVEncoding::kZigzag) != 0;
642 const bool useDelta = (flags & CMVEncoding::kDelta) != 0;
643
644 if (!useZigzag) {
645 // Symbols are raw uint16 values; write directly
646 for (uint32_t i = 0; i < static_cast<uint32_t>(symbols.size()); ++i) {
647 cmv->mDataPerTF[i] = static_cast<uint16_t>(symbols[i]);
648 }
649 return;
650 }
651
652 // Inverse zigzag + optional inverse delta (CRU-major, time-minor)
653 uint32_t s = 0;
654 for (int cru = 0; cru < static_cast<int>(CRU::MaxCRU); ++cru) {
655 int32_t prev = 0;
656 for (uint32_t tb = 0; tb < cmv::NTimeBinsPerTF; ++tb, ++s) {
657 int32_t val = zigzagDecodeLocal(symbols[s]);
658 if (useDelta) {
659 val += prev;
660 prev = val;
661 }
662 cmv->mDataPerTF[s] = signedToCmvLocal(val);
663 }
664 }
665}
666
668{
669 if (!cmv) {
670 throw std::invalid_argument("CMVPerTFCompressed::decompress: cmv pointer is null");
671 }
672 cmv->firstOrbit = firstOrbit;
674 std::fill(std::begin(cmv->mDataPerTF), std::end(cmv->mDataPerTF), uint16_t(0));
675
676 const uint8_t* ptr = mData.data();
677 const uint8_t* end = ptr + mData.size();
678
680 // Stage 1: decode position stream
681 auto positions = decodeSparsePositions(ptr, end);
682 const uint32_t N = static_cast<uint32_t>(positions.size());
683
684 // Stage 2: decode value stream (Huffman / varint / raw)
685 auto symbols = decodeValueStream(ptr, end, N, mFlags);
686
687 // Stage 3: inverse zigzag and scatter into CMV array
688 decodeSparseValues(symbols, positions, mFlags, cmv);
689 } else {
690 const uint32_t N = static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF;
691
692 // Stage 1: decode value stream (Huffman / varint / raw)
693 auto symbols = decodeValueStream(ptr, end, N, mFlags);
694
695 // Stage 2: inverse zigzag, inverse delta, fill CMV array
696 decodeDenseValues(symbols, mFlags, cmv);
697 }
698}
699
700std::unique_ptr<TTree> CMVPerTF::toTTree() const
701{
702 auto tree = std::make_unique<TTree>("ccdb_object", "ccdb_object");
703 tree->SetAutoSave(0);
704 tree->SetDirectory(nullptr);
705
706 const CMVPerTF* ptr = this;
707 tree->Branch("CMVPerTF", &ptr);
708 tree->Fill();
709
710 tree->ResetBranchAddresses();
711 return tree;
712}
713
714std::unique_ptr<TTree> CMVPerTFCompressed::toTTree() const
715{
716 auto tree = std::make_unique<TTree>("ccdb_object", "ccdb_object");
717 tree->SetAutoSave(0);
718 tree->SetDirectory(nullptr);
719
720 const CMVPerTFCompressed* ptr = this;
721 tree->Branch("CMVPerTFCompressed", &ptr);
722 tree->Fill();
723
724 tree->ResetBranchAddresses();
725 return tree;
726}
727
728void CMVPerTF::writeToFile(const std::string& filename, const std::unique_ptr<TTree>& tree)
729{
730 TFile f(filename.c_str(), "RECREATE");
731 if (f.IsZombie()) {
732 throw std::runtime_error(fmt::format("CMVPerTF::writeToFile: cannot open '{}'", filename));
733 }
734 tree->Write();
735 f.Close();
736}
737
738} // namespace o2::tpc
Structs for storing CMVs to the CCDB.
Common mode values data format definition.
unsigned short int uint16_t
unsigned int uint32_t
std::vector< long > entries
int32_t i
o2::raw::RawFileWriter * raw
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder int32_t
uint32_t stack
Definition RawData.h:1
TBranch * ptr
@ MaxCRU
Definition CRU.h:31
GLint GLsizei count
Definition glcorearb.h:399
GLuint GLuint end
Definition glcorearb.h:469
const GLdouble * v
Definition glcorearb.h:832
GLdouble GLdouble right
Definition glcorearb.h:4077
GLint first
Definition glcorearb.h:399
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei GLsizei GLfloat distance
Definition glcorearb.h:5506
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLint left
Definition glcorearb.h:1979
GLuint GLfloat * val
Definition glcorearb.h:1582
GLint GLint GLsizei GLsizei GLsizei depth
Definition glcorearb.h:470
GLbitfield flags
Definition glcorearb.h:1570
GLenum GLenum GLsizei len
Definition glcorearb.h:4232
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glcorearb.h:2514
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
constexpr uint8_t bit
GPUdoubleBinary64 b
Global TPC definitions and constants.
std::string filename()
static constexpr uint8_t kDelta
Delta coding between consecutive values (dense only)
static constexpr uint8_t kVarint
Varint compression of the value stream.
static constexpr uint8_t kHuffman
Canonical Huffman compression of the value stream.
static constexpr uint8_t kSparse
Non-zero positions stored sparsely (varint-encoded deltas)
static constexpr uint8_t kZigzag
Zigzag encoding of deltas or signed values.
std::unique_ptr< TTree > toTTree() const
Serialise into a TTree; each Fill() call appends one entry (one TF)
void decompress(CMVPerTF *cmv) const
Restore a CMVPerTF from this compressed object into *cmv (must not be null)
std::vector< uint8_t > mData
Encoded payload.
uint32_t firstOrbitDPL
First orbit of this TF.
uint8_t mFlags
Bitmask of CMVEncoding values.
uint32_t firstOrbit
First orbit of this TF.
uint32_t firstOrbit
First orbit of this TF, from heartbeatOrbit of the first CMV packet.
void zeroSmallValues(float threshold=1.0f)
Zero out raw CMV values whose float magnitude is below threshold.
CMVPerTFCompressed compress(uint8_t flags) const
static void writeToFile(const std::string &filename, const std::unique_ptr< TTree > &tree)
Write the TTree to a ROOT file.
uint16_t mDataPerTF[CRU::MaxCRU *cmv::NTimeBinsPerTF]
void roundToIntegers(uint16_t threshold)
Round values to the nearest integer ADC for all values whose rounded magnitude is <= threshold.
void trimGaussianPrecision(float mean, float sigma)
std::unique_ptr< TTree > toTTree() const
Serialise into a TTree; each Fill() call appends one entry (one TF)
uint32_t firstOrbitDPL
First orbit of this TF, from DPL.
uint16_t getCMV(const int cru, const int timeBin) const
Return the raw 16-bit CMV value for a given CRU and timebin within this TF.
float getCMVFloat(const int cru, const int timeBin) const
Return the float CMV value for a given CRU and timebin within this TF.
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))
ArrayADC adc
char const *restrict const cmp
Definition x9.h:96