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
417void CMVPerTF::roundToIntegers(uint16_t threshold)
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;
463 uint16_t val;
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) {
629 uint16_t raw;
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.
int32_t i
o2::raw::RawFileWriter * raw
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.
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