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 // Frequency count
128 std::map<uint32_t, uint64_t> freq;
129 for (const uint32_t z : symbols) {
130 ++freq[z];
131 }
132
133 // Build tree using index-based min-heap
134 struct HNode {
135 uint64_t freq{0};
136 uint32_t sym{0};
137 int left{-1}, right{-1};
138 bool isLeaf{true};
139 };
140 std::vector<HNode> nodes;
141 nodes.reserve(freq.size() * 2);
142 for (const auto& [sym, f] : freq) {
143 nodes.push_back({f, sym, -1, -1, true});
144 }
145
146 auto cmp = [&](int a, int b) {
147 return nodes[a].freq != nodes[b].freq ? nodes[a].freq > nodes[b].freq : nodes[a].sym > nodes[b].sym;
148 };
149 std::vector<int> heap;
150 heap.reserve(nodes.size());
151 for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
152 heap.push_back(i);
153 }
154 std::make_heap(heap.begin(), heap.end(), cmp);
155
156 while (heap.size() > 1) {
157 std::pop_heap(heap.begin(), heap.end(), cmp);
158 const int a = heap.back();
159 heap.pop_back();
160 std::pop_heap(heap.begin(), heap.end(), cmp);
161 const int b = heap.back();
162 heap.pop_back();
163 nodes.push_back({nodes[a].freq + nodes[b].freq, 0, a, b, false});
164 heap.push_back(static_cast<int>(nodes.size()) - 1);
165 std::push_heap(heap.begin(), heap.end(), cmp);
166 }
167
168 // Assign code lengths via iterative DFS
169 std::map<uint32_t, uint8_t> codeLens;
170 {
171 const int root = heap[0];
172 std::vector<std::pair<int, int>> stack;
173 stack.push_back({root, 0});
174 while (!stack.empty()) {
175 auto [idx, depth] = stack.back();
176 stack.pop_back();
177 if (nodes[idx].isLeaf) {
178 codeLens[nodes[idx].sym] = static_cast<uint8_t>(depth == 0 ? 1 : depth);
179 } else {
180 stack.push_back({nodes[idx].left, depth + 1});
181 stack.push_back({nodes[idx].right, depth + 1});
182 }
183 }
184 }
185
186 // Sort by (codeLen ASC, symbol ASC) for canonical assignment
187 struct SymLen {
188 uint32_t sym;
189 uint8_t len;
190 };
191 std::vector<SymLen> symLens;
192 symLens.reserve(codeLens.size());
193 for (const auto& [sym, len] : codeLens) {
194 symLens.push_back({sym, len});
195 }
196 std::sort(symLens.begin(), symLens.end(), [](const SymLen& a, const SymLen& b) {
197 return a.len != b.len ? a.len < b.len : a.sym < b.sym;
198 });
199
200 // Assign canonical codes
201 std::map<uint32_t, std::pair<uint32_t, uint8_t>> codeTable;
202 {
203 uint32_t code = 0;
204 uint8_t prevLen = 0;
205 for (const auto& sl : symLens) {
206 if (prevLen != 0) {
207 code = (code + 1) << (sl.len - prevLen);
208 }
209 codeTable[sl.sym] = {code, sl.len};
210 prevLen = sl.len;
211 }
212 }
213
214 // Serialise table header
215 buf.reserve(buf.size() + 4 + symLens.size() * 5 + 8 + (symbols.size() / 8 + 1));
216 const uint32_t numSym = static_cast<uint32_t>(symLens.size());
217 for (int i = 0; i < 4; ++i) {
218 buf.push_back(static_cast<uint8_t>((numSym >> (8 * i)) & 0xFF));
219 }
220 for (const auto& sl : symLens) {
221 for (int i = 0; i < 4; ++i) {
222 buf.push_back(static_cast<uint8_t>((sl.sym >> (8 * i)) & 0xFF));
223 }
224 buf.push_back(sl.len);
225 }
226
227 // Placeholder for totalBits
228 const size_t totalBitsOffset = buf.size();
229 for (int i = 0; i < 8; ++i) {
230 buf.push_back(0);
231 }
232
233 // Encode bitstream (MSB-first)
234 uint64_t totalBits = 0;
235 uint8_t curByte = 0;
236 int bitsInByte = 0;
237 for (const uint32_t z : symbols) {
238 const auto& [code, len] = codeTable.at(z);
239 for (int b = static_cast<int>(len) - 1; b >= 0; --b) {
240 curByte = static_cast<uint8_t>(curByte | (((code >> b) & 1u) << (7 - bitsInByte)));
241 ++bitsInByte;
242 ++totalBits;
243 if (bitsInByte == 8) {
244 buf.push_back(curByte);
245 curByte = 0;
246 bitsInByte = 0;
247 }
248 }
249 }
250 if (bitsInByte > 0) {
251 buf.push_back(curByte);
252 }
253
254 // Backfill totalBits
255 for (int i = 0; i < 8; ++i) {
256 buf[totalBitsOffset + i] = static_cast<uint8_t>((totalBits >> (8 * i)) & 0xFF);
257 }
258}
259
263std::vector<uint32_t> huffmanDecode(const uint8_t*& ptr, const uint8_t* end, uint32_t N)
264{
265 auto readU32 = [&]() -> uint32_t {
266 if (ptr + 4 > end) {
267 throw std::runtime_error("huffmanDecode: unexpected end reading uint32");
268 }
269 const uint32_t v = static_cast<uint32_t>(ptr[0]) | (static_cast<uint32_t>(ptr[1]) << 8) |
270 (static_cast<uint32_t>(ptr[2]) << 16) | (static_cast<uint32_t>(ptr[3]) << 24);
271 ptr += 4;
272 return v;
273 };
274
275 const uint32_t numSym = readU32();
276 struct SymLen {
277 uint32_t sym;
278 uint8_t len;
279 };
280 std::vector<SymLen> symLens(numSym);
281 for (uint32_t i = 0; i < numSym; ++i) {
282 symLens[i].sym = readU32();
283 if (ptr >= end) {
284 throw std::runtime_error("huffmanDecode: unexpected end reading code length");
285 }
286 symLens[i].len = *ptr++;
287 }
288
289 std::map<uint8_t, uint32_t> firstCode;
290 std::map<uint8_t, std::vector<uint32_t>> symsByLen;
291 {
292 uint32_t code = 0;
293 uint8_t prevLen = 0;
294 for (const auto& sl : symLens) {
295 if (prevLen != 0) {
296 code = (code + 1) << (sl.len - prevLen);
297 }
298 if (!firstCode.count(sl.len)) {
299 firstCode[sl.len] = code;
300 }
301 symsByLen[sl.len].push_back(sl.sym);
302 prevLen = sl.len;
303 }
304 }
305
306 if (ptr + 8 > end) {
307 throw std::runtime_error("huffmanDecode: unexpected end reading totalBits");
308 }
309 uint64_t totalBits = 0;
310 for (int i = 0; i < 8; ++i) {
311 totalBits |= static_cast<uint64_t>(ptr[i]) << (8 * i);
312 }
313 ptr += 8;
314
315 const uint8_t minLen = symLens.empty() ? 1 : symLens.front().len;
316 const uint8_t maxLen = symLens.empty() ? 1 : symLens.back().len;
317 uint64_t bitsRead = 0;
318 uint8_t curByte = 0;
319 int bitPos = -1;
320
321 auto nextBit = [&]() -> int {
322 if (bitPos < 0) {
323 if (ptr >= end) {
324 throw std::runtime_error("huffmanDecode: unexpected end of bitstream");
325 }
326 curByte = *ptr++;
327 bitPos = 7;
328 }
329 const int bit = (curByte >> bitPos) & 1;
330 --bitPos;
331 return bit;
332 };
333
334 std::vector<uint32_t> out;
335 out.reserve(N);
336 while (out.size() < N) {
337 uint32_t accum = 0;
338 bool found = false;
339 for (uint8_t curLen = 1; curLen <= maxLen; ++curLen) {
340 if (bitsRead >= totalBits) {
341 throw std::runtime_error("huffmanDecode: bitstream exhausted before all symbols decoded");
342 }
343 accum = (accum << 1) | static_cast<uint32_t>(nextBit());
344 ++bitsRead;
345 if (curLen < minLen) {
346 continue;
347 }
348 const auto fcIt = firstCode.find(curLen);
349 if (fcIt == firstCode.end()) {
350 continue;
351 }
352 if (accum >= fcIt->second) {
353 const uint32_t idx = accum - fcIt->second;
354 const auto& sv = symsByLen.at(curLen);
355 if (idx < sv.size()) {
356 out.push_back(sv[idx]);
357 found = true;
358 break;
359 }
360 }
361 }
362 if (!found) {
363 throw std::runtime_error("huffmanDecode: invalid Huffman code in bitstream");
364 }
365 }
366 return out;
367}
368
369} // anonymous namespace
370
371// CMVPerTF public methods
372
373uint16_t CMVPerTF::getCMV(const int cru, const int timeBin) const
374{
375 if (cru < 0 || cru >= static_cast<int>(CRU::MaxCRU)) {
376 throw std::out_of_range(fmt::format("CMVPerTF::getCMV: cru {} out of range [0, {})", cru, static_cast<int>(CRU::MaxCRU)));
377 }
378 if (timeBin < 0 || static_cast<uint32_t>(timeBin) >= cmv::NTimeBinsPerTF) {
379 throw std::out_of_range(fmt::format("CMVPerTF::getCMV: timeBin {} out of range [0, {})", timeBin, static_cast<int>(cmv::NTimeBinsPerTF)));
380 }
381 return mDataPerTF[cru * cmv::NTimeBinsPerTF + timeBin];
382}
383
384float CMVPerTF::getCMVFloat(const int cru, const int timeBin) const
385{
386 const uint16_t raw = getCMV(cru, timeBin);
387 const uint16_t mag = raw & 0x7FFF;
388 if (mag == 0) {
389 return 0.0f; // 0x0000 and 0x8000 both represent zero; return +0 to avoid -0 display
390 }
391 const bool positive = (raw >> 15) & 1; // bit 15: sign (1=positive, 0=negative)
392 return positive ? mag / 128.f : -mag / 128.f;
393}
394
395void CMVPerTF::zeroSmallValues(float threshold)
396{
397 if (threshold <= 0.f) {
398 return;
399 }
400 for (uint32_t i = 0; i < static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF; ++i) {
401 const float mag = (mDataPerTF[i] & 0x7FFF) / 128.f;
402 if (mag < threshold) {
403 mDataPerTF[i] = 0;
404 }
405 }
406}
407
408void CMVPerTF::roundToIntegers(uint16_t threshold)
409{
410 if (threshold == 0) {
411 return;
412 }
413 for (uint32_t i = 0; i < static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF; ++i) {
414 const uint16_t raw = mDataPerTF[i];
415 if (raw == 0) {
416 continue;
417 }
418 const uint16_t rounded = static_cast<uint16_t>(((raw & 0x7FFFu) + 64u) >> 7);
419 if (rounded > threshold) {
420 continue; // above range: keep full precision
421 }
422 mDataPerTF[i] = (rounded == 0) ? 0 : static_cast<uint16_t>((raw & 0x8000u) | (rounded << 7));
423 }
424}
425
426void CMVPerTF::trimGaussianPrecision(float mean, float sigma)
427{
428 if (sigma <= 0.f) {
429 return;
430 }
431
432 for (uint32_t i = 0; i < static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF; ++i) {
433 mDataPerTF[i] = quantizeBelowThreshold(mDataPerTF[i], mean, sigma);
434 }
435}
436
438{
441 out.firstBC = firstBC;
442 out.mFlags = flags;
443
445 // --- Sparse path: position stream + value stream ---
446
447 // Single pass per CRU: build the position stream and collect raw non-zero values.
448 std::vector<uint8_t> posStream;
449 std::vector<uint16_t> rawValues;
450
451 for (int cru = 0; cru < static_cast<int>(CRU::MaxCRU); ++cru) {
452 struct Entry {
453 uint32_t tb;
454 uint16_t val;
455 };
456 std::vector<Entry> entries;
457 for (uint32_t tb = 0; tb < cmv::NTimeBinsPerTF; ++tb) {
458 const uint16_t val = mDataPerTF[cru * cmv::NTimeBinsPerTF + tb];
459 if (val != 0) {
460 entries.push_back({tb, val});
461 }
462 }
463
464 encodeVarintInto(static_cast<uint32_t>(entries.size()), posStream);
465 uint32_t prevTB = 0;
466 bool first = true;
467 for (const auto& e : entries) {
468 encodeVarintInto(first ? e.tb : (e.tb - prevTB), posStream);
469 rawValues.push_back(e.val);
470 prevTB = e.tb;
471 first = false;
472 }
473 }
474
475 // Encode the value stream based on flags.
476 std::vector<uint8_t> valStream;
478 std::vector<uint32_t> zigzags;
479 zigzags.reserve(rawValues.size());
480 for (const uint16_t v : rawValues) {
481 zigzags.push_back(zigzagEncode(cmvToSigned(v)));
482 }
484 huffmanEncode(zigzags, valStream);
485 } else { // kVarint
486 for (const uint32_t z : zigzags) {
487 encodeVarintInto(z, valStream);
488 }
489 }
490 } else {
491 // Raw uint16 LE
492 for (const uint16_t v : rawValues) {
493 valStream.push_back(static_cast<uint8_t>(v & 0xFF));
494 valStream.push_back(static_cast<uint8_t>(v >> 8));
495 }
496 }
497
498 // Assemble: [4 bytes posStreamSize][posStream][valStream]
499 const uint32_t posStreamSize = static_cast<uint32_t>(posStream.size());
500 out.mData.reserve(4 + posStream.size() + valStream.size());
501 for (int i = 0; i < 4; ++i) {
502 out.mData.push_back(static_cast<uint8_t>((posStreamSize >> (8 * i)) & 0xFF));
503 }
504 out.mData.insert(out.mData.end(), posStream.begin(), posStream.end());
505 out.mData.insert(out.mData.end(), valStream.begin(), valStream.end());
506
507 } else {
508 // --- Dense path: all CRU * TimeBin values ---
509 const uint32_t total = static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF;
510
511 if (!(flags & CMVEncoding::kZigzag)) {
512 // No encoding: raw uint16 LE
513 out.mData.reserve(total * 2);
514 for (uint32_t i = 0; i < total; ++i) {
515 out.mData.push_back(static_cast<uint8_t>(mDataPerTF[i] & 0xFF));
516 out.mData.push_back(static_cast<uint8_t>(mDataPerTF[i] >> 8));
517 }
518 } else {
519 // Zigzag + optional delta (CRU-major, time-minor)
520 const bool useDelta = (flags & CMVEncoding::kDelta) != 0;
521 std::vector<uint32_t> zigzags;
522 zigzags.reserve(total);
523 for (int cru = 0; cru < static_cast<int>(CRU::MaxCRU); ++cru) {
524 int32_t prev = 0;
525 for (uint32_t tb = 0; tb < cmv::NTimeBinsPerTF; ++tb) {
526 const int32_t val = cmvToSigned(mDataPerTF[cru * cmv::NTimeBinsPerTF + tb]);
527 const int32_t encoded = useDelta ? (val - prev) : val;
528 if (useDelta) {
529 prev = val;
530 }
531 zigzags.push_back(zigzagEncode(encoded));
532 }
533 }
534
536 huffmanEncode(zigzags, out.mData);
537 } else { // kVarint
538 for (const uint32_t z : zigzags) {
539 encodeVarintInto(z, out.mData);
540 }
541 }
542 }
543 }
544
545 return out;
546}
547
548// CMVPerTFCompressed::decompress staged pipeline
549
550std::vector<std::pair<int, uint32_t>> CMVPerTFCompressed::decodeSparsePositions(const uint8_t*& ptr, const uint8_t* end)
551{
552 // Read 4-byte LE posStreamSize
553 if (ptr + 4 > end) {
554 throw std::runtime_error("CMVPerTFCompressed::decompress: truncated position header");
555 }
556 const uint32_t posStreamSize = static_cast<uint32_t>(ptr[0]) | (static_cast<uint32_t>(ptr[1]) << 8) |
557 (static_cast<uint32_t>(ptr[2]) << 16) | (static_cast<uint32_t>(ptr[3]) << 24);
558 ptr += 4;
559
560 const uint8_t* posEnd = ptr + posStreamSize;
561 if (posEnd > end) {
562 throw std::runtime_error("CMVPerTFCompressed::decompress: posStream overflows payload");
563 }
564
565 // Decode per-CRU varint(N) + NĂ—varint(tb_delta)
566 std::vector<std::pair<int, uint32_t>> positions;
567 const uint8_t* p = ptr;
568 for (int cru = 0; cru < static_cast<int>(CRU::MaxCRU); ++cru) {
569 const uint32_t count = decodeVarintLocal(p, posEnd);
570 uint32_t tb = 0;
571 bool first = true;
572 for (uint32_t i = 0; i < count; ++i) {
573 const uint32_t delta = decodeVarintLocal(p, posEnd);
574 tb = first ? delta : (tb + delta);
575 first = false;
576 positions.emplace_back(cru, tb);
577 }
578 }
579 ptr = posEnd; // advance past the entire position block
580 return positions;
581}
582
583std::vector<uint32_t> CMVPerTFCompressed::decodeValueStream(const uint8_t*& ptr, const uint8_t* end, uint32_t N, uint8_t flags)
584{
586 // Huffman-encoded symbols
587 return huffmanDecode(ptr, end, N);
588 }
589
591 // Varint-encoded symbols
592 std::vector<uint32_t> out;
593 out.reserve(N);
594 for (uint32_t i = 0; i < N; ++i) {
595 out.push_back(decodeVarintLocal(ptr, end));
596 }
597 return out;
598 }
599
600 // Raw uint16 LE (no value encoding)
601 std::vector<uint32_t> out;
602 out.reserve(N);
603 for (uint32_t i = 0; i < N; ++i) {
604 if (ptr + 2 > end) {
605 throw std::runtime_error("CMVPerTFCompressed::decompress: unexpected end in raw value stream");
606 }
607 const uint16_t v = static_cast<uint16_t>(ptr[0]) | (static_cast<uint16_t>(ptr[1]) << 8);
608 ptr += 2;
609 out.push_back(v);
610 }
611 return out;
612}
613
614void CMVPerTFCompressed::decodeSparseValues(const std::vector<uint32_t>& symbols,
615 const std::vector<std::pair<int, uint32_t>>& positions,
616 uint8_t flags, CMVPerTF* cmv)
617{
618 const bool useZigzag = (flags & CMVEncoding::kZigzag) != 0;
619 for (uint32_t i = 0; i < static_cast<uint32_t>(positions.size()); ++i) {
620 uint16_t raw;
621 if (useZigzag) {
622 raw = signedToCmvLocal(zigzagDecodeLocal(symbols[i]));
623 } else {
624 raw = static_cast<uint16_t>(symbols[i]);
625 }
626 cmv->mDataPerTF[positions[i].first * cmv::NTimeBinsPerTF + positions[i].second] = raw;
627 }
628}
629
630void CMVPerTFCompressed::decodeDenseValues(const std::vector<uint32_t>& symbols, uint8_t flags, CMVPerTF* cmv)
631{
632 const bool useZigzag = (flags & CMVEncoding::kZigzag) != 0;
633 const bool useDelta = (flags & CMVEncoding::kDelta) != 0;
634
635 if (!useZigzag) {
636 // Symbols are raw uint16 values; write directly
637 for (uint32_t i = 0; i < static_cast<uint32_t>(symbols.size()); ++i) {
638 cmv->mDataPerTF[i] = static_cast<uint16_t>(symbols[i]);
639 }
640 return;
641 }
642
643 // Inverse zigzag + optional inverse delta (CRU-major, time-minor)
644 uint32_t s = 0;
645 for (int cru = 0; cru < static_cast<int>(CRU::MaxCRU); ++cru) {
646 int32_t prev = 0;
647 for (uint32_t tb = 0; tb < cmv::NTimeBinsPerTF; ++tb, ++s) {
648 int32_t val = zigzagDecodeLocal(symbols[s]);
649 if (useDelta) {
650 val += prev;
651 prev = val;
652 }
653 cmv->mDataPerTF[s] = signedToCmvLocal(val);
654 }
655 }
656}
657
659{
660 if (!cmv) {
661 throw std::invalid_argument("CMVPerTFCompressed::decompress: cmv pointer is null");
662 }
663 cmv->firstOrbit = firstOrbit;
664 cmv->firstBC = firstBC;
665 std::fill(std::begin(cmv->mDataPerTF), std::end(cmv->mDataPerTF), uint16_t(0));
666
667 const uint8_t* ptr = mData.data();
668 const uint8_t* end = ptr + mData.size();
669
671 // Stage 1: decode position stream
672 auto positions = decodeSparsePositions(ptr, end);
673 const uint32_t N = static_cast<uint32_t>(positions.size());
674
675 // Stage 2: decode value stream (Huffman / varint / raw)
676 auto symbols = decodeValueStream(ptr, end, N, mFlags);
677
678 // Stage 3: inverse zigzag and scatter into CMV array
679 decodeSparseValues(symbols, positions, mFlags, cmv);
680 } else {
681 const uint32_t N = static_cast<uint32_t>(CRU::MaxCRU) * cmv::NTimeBinsPerTF;
682
683 // Stage 1: decode value stream (Huffman / varint / raw)
684 auto symbols = decodeValueStream(ptr, end, N, mFlags);
685
686 // Stage 2: inverse zigzag, inverse delta, fill CMV array
687 decodeDenseValues(symbols, mFlags, cmv);
688 }
689}
690
691std::unique_ptr<TTree> CMVPerTF::toTTree() const
692{
693 auto tree = std::make_unique<TTree>("ccdb_object", "ccdb_object");
694 tree->SetAutoSave(0);
695 tree->SetDirectory(nullptr);
696
697 const CMVPerTF* ptr = this;
698 tree->Branch("CMVPerTF", &ptr);
699 tree->Fill();
700
701 tree->ResetBranchAddresses();
702 return tree;
703}
704
705std::unique_ptr<TTree> CMVPerTFCompressed::toTTree() const
706{
707 auto tree = std::make_unique<TTree>("ccdb_object", "ccdb_object");
708 tree->SetAutoSave(0);
709 tree->SetDirectory(nullptr);
710
711 const CMVPerTFCompressed* ptr = this;
712 tree->Branch("CMVPerTFCompressed", &ptr);
713 tree->Fill();
714
715 tree->ResetBranchAddresses();
716 return tree;
717}
718
719void CMVPerTF::writeToFile(const std::string& filename, const std::unique_ptr<TTree>& tree)
720{
721 TFile f(filename.c_str(), "RECREATE");
722 if (f.IsZombie()) {
723 throw std::runtime_error(fmt::format("CMVPerTF::writeToFile: cannot open '{}'", filename));
724 }
725 tree->Write();
726 f.Close();
727}
728
729} // namespace o2::tpc
Structs for storing CMVs to the CCDB.
Common mode values data format definition.
int32_t i
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
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
GLboolean * data
Definition glcorearb.h:298
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
uint8_t itsSharedClusterMap uint8_t
constexpr uint8_t bit
Global TPC definitions and constants.
Definition SimTraits.h:168
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.
uint8_t mFlags
Bitmask of CMVEncoding values.
uint16_t firstBC
First bunch crossing of this TF.
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)
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.
uint16_t firstBC
First bunch crossing of this TF, from heartbeatBC of the first CMV packet.
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