2828namespace o2 ::tpc
2929{
3030
31- struct CMVPerTF ; // forward declaration
32- struct CMVPerTFSparse ; // forward declaration
33- struct CMVPerTFHuffman ; // forward declaration
34- struct CMVPerTFCombined ; // forward declaration
35- struct CMVPerTFQuantized ; // forward declaration
36-
37- // / Delta+zigzag+varint compressed CMV data for one TF across all CRUs
38- // / Produced by CMVPerTF::compressVarint(), restored with decompress()
39- // / Each TTree entry corresponds to one CMVPerTFVarint object (one TF)
40- struct CMVPerTFVarint {
41- uint32_t firstOrbit{0 }; // /< First orbit of this TF (copied from CMVPerTF)
42- uint16_t firstBC{0 }; // /< First bunch crossing of this TF (copied from CMVPerTF)
43-
44- // / Delta+zigzag+varint encoded CMV values
45- // / Layout: CRU-major, time-minor; delta is reset to zero at each CRU boundary
46- std::vector<uint8_t > mCompressedData ;
47-
48- // / Restore a CMVPerTF from this compressed object into *cmv (must not be null)
49- void decompress (CMVPerTF* cmv) const ;
50-
51- private:
52- static uint16_t signedToCmv (int32_t val); // /< Signed integer -> sign-magnitude uint16_t
53- static int32_t zigzagDecode (uint32_t value); // /< Zigzag decode
54- static uint32_t decodeVarint (const uint8_t *& data, const uint8_t * end); // /< Varint decode
55-
56- public:
57- ClassDefNV (CMVPerTFVarint, 1 )
58- };
59-
60- // / Sparse-encoded CMV data for one TF across all CRUs
61- // / Produced by CMVPerTF::compressSparse(), restored with decompress()
62- // / Each TTree entry corresponds to one CMVPerTFSparse object (one TF)
63- // /
64- // / Encoding format (stored in mSparseData):
65- // / For each CRU 0..MaxCRU-1:
66- // / varint(N) — number of non-zero timebins in this CRU
67- // / For each of the N entries (in timebin order):
68- // / varint(delta) — absolute timeBin for the first entry; tb − prev_tb for subsequent ones
69- // / uint16_t(raw) — raw sign-magnitude CMV value (little-endian, 2 bytes)
70- struct CMVPerTFSparse {
71- uint32_t firstOrbit{0 }; // /< First orbit of this TF (copied from CMVPerTF)
72- uint16_t firstBC{0 }; // /< First bunch crossing of this TF (copied from CMVPerTF)
73-
74- // / Sparse-encoded CMV values
75- std::vector<uint8_t > mSparseData ;
76-
77- // / Restore a CMVPerTF from this sparse object into *cmv (must not be null)
78- void decompress (CMVPerTF* cmv) const ;
79-
80- private:
81- static uint32_t decodeVarint (const uint8_t *& data, const uint8_t * end); // /< Varint decode
82-
83- public:
84- ClassDefNV (CMVPerTFSparse, 1 )
85- };
86-
87- // / Delta+zigzag+canonical Huffman compressed CMV data for one TF across all CRUs
88- // / Produced by CMVPerTF::compressHuffman(), restored with decompress()
89- // /
90- // / Serialisation layout (mHuffmanData):
91- // / 4 bytes LE uint32_t : numSymbols — number of distinct zigzag-encoded delta symbols
92- // / numSymbols * 5 bytes : symbol table (canonical order, sorted by codeLen ASC then symbol ASC):
93- // / 4 bytes LE uint32_t : zigzag-encoded symbol value
94- // / 1 byte : canonical code length (1..32)
95- // / 8 bytes LE uint64_t : totalBits — number of valid bits in the bitstream
96- // / ceil(totalBits/8) bytes : bitstream, MSB-first packing within each byte
97- struct CMVPerTFHuffman {
98- uint32_t firstOrbit{0 }; // /< First orbit of this TF (copied from CMVPerTF)
99- uint16_t firstBC{0 }; // /< First bunch crossing of this TF (copied from CMVPerTF)
100-
101- // / Huffman-coded payload
102- std::vector<uint8_t > mHuffmanData ;
103-
104- // / Restore a CMVPerTF from this Huffman object into *cmv (must not be null)
105- void decompress (CMVPerTF* cmv) const ;
106-
107- ClassDefNV (CMVPerTFHuffman, 1 )
31+ struct CMVPerTF ; // forward declaration
32+ struct CMVPerTFCompressed ; // forward declaration
33+
34+ // / Bitmask flags describing which encoding stages are applied in CMVPerTFCompressed
35+ struct CMVEncoding {
36+ static constexpr uint8_t kNone = 0x00 ; // /< No compression — raw uint16 values stored flat
37+ static constexpr uint8_t kSparse = 0x01 ; // /< Non-zero positions stored sparsely (varint-encoded deltas)
38+ static constexpr uint8_t kDelta = 0x02 ; // /< Delta coding between consecutive values (dense only)
39+ static constexpr uint8_t kZigzag = 0x04 ; // /< Zigzag encoding of deltas or signed values
40+ static constexpr uint8_t kVarint = 0x08 ; // /< Varint compression of the value stream
41+ static constexpr uint8_t kHuffman = 0x10 ; // /< Canonical Huffman compression of the value stream
10842};
10943
110- // / Hybrid sparse+compressed-value encoding for one TF across all CRUs
111- // /
112- // / Non-zero positions are stored as sparse varint deltas (same as CMVPerTFSparse)
113- // / The remaining non-zero values are encoded according to mValueMode:
44+ // / Single compressed representation for one TF across all CRUs, stored in a TTree
45+ // / mFlags is a bitmask of CMVEncoding values that fully describes the encoding pipeline
46+ // / mData holds the encoded payload whose binary layout depends on mFlags:
11447// /
115- // / Mode 0 raw uint16_t — identical value encoding to CMVPerTFSparse
116- // / Mode 1 varint signed — zigzag+varint of the exact signed CMV value
117- // / Mode 2 Huffman signed — canonical Huffman over the same zigzag-encoded exact values
48+ // / Dense path (!kSparse):
49+ // / kZigzag absent → N × uint16_t LE (raw values, CRU-major order)
50+ // / kZigzag + kVarint → N × varint(zigzag(delta(signed(raw))))
51+ // / kZigzag + kHuffman → [Huffman table] + [bitstream] of zigzag(delta(signed(raw)))
11852// /
119- // / Binary layout of mData :
120- // / 4 bytes LE posStreamSize
121- // / [ posStream] for each CRU: varint(N), N× varint(tb_delta)
122- // / [ valStream]
123- // / mode 0: N_total × uint16_t LE
124- // / mode 1: N_total × varint(zigzag(cmvToSigned (raw)))
125- // / mode 2: [canonical Huffman table] + [8-byte totalBits ] + [bitstream]
126- struct CMVPerTFCombined {
53+ // / Sparse path (kSparse) :
54+ // / 4 bytes LE uint32_t : posStreamSize
55+ // / posStream: for each CRU: varint(N), N × varint(tb_delta)
56+ // / valStream (one entry per non-zero):
57+ // / default → uint16_t LE raw value
58+ // / kZigzag + kVarint → varint(zigzag(signed (raw)))
59+ // / kZigzag + kHuffman → [Huffman table ] + [bitstream] of zigzag(signed(raw))
60+ struct CMVPerTFCompressed {
12761 uint32_t firstOrbit{0 }; // /< First orbit of this TF
12862 uint16_t firstBC{0 }; // /< First bunch crossing of this TF
129- uint8_t mValueMode {0 }; // /< 0 = raw uint16, 1 = varint signed CMV, 2 = Huffman signed CMV
63+ uint8_t mFlags {0 }; // /< Bitmask of CMVEncoding values
13064
13165 std::vector<uint8_t > mData ; // /< Encoded payload
13266
133- // / Restore a CMVPerTF from this object into *cmv (must not be null)
67+ // / Restore a CMVPerTF from this compressed object into *cmv (must not be null)
13468 void decompress (CMVPerTF* cmv) const ;
13569
136- ClassDefNV (CMVPerTFCombined, 1 )
137- } ;
70+ // / Serialise into a TTree; each Fill() call appends one entry (one TF )
71+ std::unique_ptr<TTree> toTTree () const ;
13872
139- // / Sparse positions + quantized-value symbols for one TF across all CRUs
140- // /
141- // / Non-zero positions are stored as sparse varint deltas.
142- // / The corresponding values are encoded as quantized signed symbols:
143- // / Mode 0 raw symbols — 4-byte LE uint32 per symbol
144- // / Mode 1 varint symbols — varint(symbol)
145- // / Mode 2 Huffman symbols — canonical Huffman over symbol stream
146- // / Quantized symbols represent decimal-style values below the internally derived full-precision cutoff
147- // / and exact raw signed I8F7 values above it.
148- struct CMVPerTFQuantized {
149- uint32_t firstOrbit{0 }; // /< First orbit of this TF
150- uint16_t firstBC{0 }; // /< First bunch crossing of this TF
151- uint8_t mValueMode {0 }; // /< 0 = raw symbols, 1 = varint symbols, 2 = Huffman symbols
73+ private:
74+ // / Decode the sparse position stream; advances ptr past the position block
75+ // / Returns (cru, timeBin) pairs for every non-zero entry, in CRU-major order
76+ static std::vector<std::pair<int , uint32_t >> decodeSparsePositions (const uint8_t *& ptr, const uint8_t * end);
15277
153- std::vector<uint8_t > mData ; // /< Encoded payload
78+ // / Decode the value stream into raw uint32_t symbols
79+ // / Dispatches to Huffman, varint, or raw uint16 based on flags
80+ static std::vector<uint32_t > decodeValueStream (const uint8_t *& ptr, const uint8_t * end, uint32_t N, uint8_t flags);
15481
155- // / Restore nearest raw-I8F7 values into *cmv (must not be null)
156- void decompress (CMVPerTF* cmv) const ;
82+ // / Apply inverse zigzag and scatter decoded values into the sparse positions of *cmv
83+ static void decodeSparseValues (const std::vector<uint32_t >& symbols,
84+ const std::vector<std::pair<int , uint32_t >>& positions,
85+ uint8_t flags, CMVPerTF* cmv);
15786
158- // / Restore exact quantized float values into `values`, sized to CRU::MaxCRU * cmv::NTimeBinsPerTF
159- void decompressToFloatBuffer ( std::vector<float >& values) const ;
87+ // / Apply inverse zigzag and inverse delta, then fill the full dense CMV array in * cmv
88+ static void decodeDenseValues ( const std::vector<uint32_t >& symbols, uint8_t flags, CMVPerTF* cmv) ;
16089
161- ClassDefNV (CMVPerTFQuantized, 1 )
90+ public:
91+ ClassDefNV (CMVPerTFCompressed, 1 )
16292};
16393
16494// / CMV data for one TF across all CRUs
16595// / Raw 16-bit CMV values are stored in a flat C array indexed as [cru * NTimeBinsPerTF + timeBin]
166- // / CRU::MaxCRU and cmv::NTimeBinsPerTF are compile-time constants, so no dynamic allocation is needed
16796struct CMVPerTF {
16897 uint32_t firstOrbit{0 }; // /< First orbit of this TF, from heartbeatOrbit of the first CMV packet
16998 uint16_t firstBC{0 }; // /< First bunch crossing of this TF, from heartbeatBC of the first CMV packet
@@ -178,47 +107,18 @@ struct CMVPerTF {
178107 float getCMVFloat (const int cru, const int timeBin) const ;
179108
180109 // / Zero out raw CMV values whose float magnitude is below threshold
181- // / This converts the sign-magnitude raw value to 0x0000 for all entries with |float value| < threshold
182110 void zeroSmallValues (float threshold = 1 .0f );
183111
184112 // / Round values to the nearest integer ADC for all values whose rounded magnitude is <= threshold
185- // / Example: threshold=3
186- // / |v| < 0.5 ADC -> 0
187- // / |v| in [0.5, 1.5) ADC -> 1.0 ADC
188- // / |v| in [1.5, 2.5) ADC -> 2.0 ADC
189- // / |v| in [2.5, 3.5) ADC -> 3.0 ADC
190- // / |v| >= 3.5 ADC -> unchanged (full precision)
191- // /
192- // / threshold=0 rounding is not applied
193113 void roundToIntegers (uint16_t threshold);
194114
195115 // / Quantise |v| with a Gaussian-CDF recovery profile:
196- // / coarse decimal-style precision below and around mean, then a smooth return to the
197- // / full native I8F7 precision as the magnitude increases with width sigma
116+ // / Coarse decimal-style precision below and around mean, then a smooth return to the full native I8F7 precision as the magnitude increases with width sigma
198117 void trimGaussianPrecision (float mean, float sigma);
199118
200- // / Compress this object into a CMVPerTFVarint using delta+zigzag+varint encoding
201- CMVPerTFVarint compressVarint () const ;
202-
203- // / Compress this object into a CMVPerTFSparse storing only non-zero timebins
204- CMVPerTFSparse compressSparse () const ;
205-
206- // / Dedicated sparse + quantized-value compression
207- // / valueMode:
208- // / 0 = raw symbol stream
209- // / 1 = varint symbol stream
210- // / 2 = Huffman symbol stream
211- CMVPerTFQuantized compressQuantized (uint8_t valueMode = 0 , float quantizationMean = 1 .f, float quantizationSigma = 0 .f) const ;
212-
213- // / Hybrid sparse+compressed-value compression
214- // / Positions encoded as sparse varint deltas; values encoded according to valueMode:
215- // / 0 = raw uint16_t (same as compressSparse, no additional gain)
216- // / 1 = varint signed CMV value
217- // / 2 = Huffman signed CMV value
218- CMVPerTFCombined compressCombined (uint8_t valueMode = 0 ) const ;
219-
220- // / Compress this object using delta+zigzag+canonical-Huffman encoding
221- CMVPerTFHuffman compressHuffman () const ;
119+ // / Compress this object into a CMVPerTFCompressed using the encoding pipeline described by flags
120+ // / Quantisation (trimGaussianPrecision / roundToIntegers / zeroSmallValues) should be applied to this object before calling compress(); it is not part of the flags pipeline
121+ CMVPerTFCompressed compress (uint8_t flags) const ;
222122
223123 // / Serialise into a TTree; each Fill() call appends one entry (one TF)
224124 std::unique_ptr<TTree> toTTree () const ;
0 commit comments