Skip to content

Commit 5d720d4

Browse files
committed
Added CMVPerTFCombined to CMVContainer to combine sparse encoding with varint/Huffman compression, updated drawing macro and workflow options accordingly
1 parent 9fc3e05 commit 5d720d4

File tree

5 files changed

+538
-280
lines changed

5 files changed

+538
-280
lines changed

Detectors/TPC/calibration/include/TPCCalibration/CMVContainer.h

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@
2828
namespace o2::tpc
2929
{
3030

31-
struct CMVPerTF; // forward declaration
32-
struct CMVPerTFSparse; // forward declaration
33-
struct CMVPerTFHuffman; // forward declaration
31+
struct CMVPerTF; // forward declaration
32+
struct CMVPerTFSparse; // forward declaration
33+
struct CMVPerTFHuffman; // forward declaration
34+
struct CMVPerTFCombined; // forward declaration
3435

3536
/// Delta+zigzag+varint compressed CMV data for one TF across all CRUs
36-
/// Produced by CMVPerTF::compress(), restored with decompress()
37-
/// Each TTree entry corresponds to one CMVPerTFCompressed object (one TF)
38-
struct CMVPerTFCompressed {
37+
/// Produced by CMVPerTF::compressVarint(), restored with decompress()
38+
/// Each TTree entry corresponds to one CMVPerTFVarint object (one TF)
39+
struct CMVPerTFVarint {
3940
uint32_t firstOrbit{0}; ///< First orbit of this TF (copied from CMVPerTF)
4041
uint16_t firstBC{0}; ///< First bunch crossing of this TF (copied from CMVPerTF)
4142

@@ -52,7 +53,7 @@ struct CMVPerTFCompressed {
5253
static uint32_t decodeVarint(const uint8_t*& data, const uint8_t* end); ///< Varint decode
5354

5455
public:
55-
ClassDefNV(CMVPerTFCompressed, 1)
56+
ClassDefNV(CMVPerTFVarint, 1)
5657
};
5758

5859
/// Sparse-encoded CMV data for one TF across all CRUs
@@ -105,6 +106,35 @@ struct CMVPerTFHuffman {
105106
ClassDefNV(CMVPerTFHuffman, 1)
106107
};
107108

109+
/// Hybrid sparse+compressed-value encoding for one TF across all CRUs
110+
///
111+
/// Non-zero positions are stored as sparse varint deltas (same as CMVPerTFSparse).
112+
/// The remaining non-zero values are encoded according to mValueMode:
113+
///
114+
/// Mode 0 raw uint16_t — identical value encoding to CMVPerTFSparse
115+
/// Mode 1 varint signed — zigzag+varint of the exact signed CMV value
116+
/// Mode 2 Huffman signed — canonical Huffman over the same zigzag-encoded exact values
117+
///
118+
/// Binary layout of mData:
119+
/// 4 bytes LE posStreamSize
120+
/// [posStream] for each CRU: varint(N), N×varint(tb_delta)
121+
/// [valStream]
122+
/// mode 0: N_total × uint16_t LE
123+
/// mode 1: N_total × varint(zigzag(cmvToSigned(raw)))
124+
/// mode 2: [canonical Huffman table] + [8-byte totalBits] + [bitstream]
125+
struct CMVPerTFCombined {
126+
uint32_t firstOrbit{0}; ///< First orbit of this TF
127+
uint16_t firstBC{0}; ///< First bunch crossing of this TF
128+
uint8_t mValueMode{0}; ///< 0 = raw uint16, 1 = varint signed CMV, 2 = Huffman signed CMV
129+
130+
std::vector<uint8_t> mData; ///< Encoded payload
131+
132+
/// Restore a CMVPerTF from this object into *cmv (must not be null)
133+
void decompress(CMVPerTF* cmv) const;
134+
135+
ClassDefNV(CMVPerTFCombined, 1)
136+
};
137+
108138
/// CMV data for one TF across all CRUs
109139
/// Raw 16-bit CMV values are stored in a flat C array indexed as [cru * NTimeBinsPerTF + timeBin]
110140
/// CRU::MaxCRU and cmv::NTimeBinsPerTF are compile-time constants, so no dynamic allocation is needed
@@ -125,23 +155,30 @@ struct CMVPerTF {
125155
/// This converts the sign-magnitude raw value to 0x0000 for all entries with |float value| < threshold
126156
void zeroSmallValues(float threshold = 1.0f);
127157

128-
/// Apply dynamic precision reduction: round values to the nearest integer ADC for all values whose rounded magnitude is <= steps
129-
/// Example: steps=3
158+
/// Round values to the nearest integer ADC for all values whose rounded magnitude is <= threshold
159+
/// Example: threshold=3
130160
/// |v| < 0.5 ADC -> 0
131161
/// |v| in [0.5, 1.5) ADC -> 1.0 ADC
132162
/// |v| in [1.5, 2.5) ADC -> 2.0 ADC
133163
/// |v| in [2.5, 3.5) ADC -> 3.0 ADC
134164
/// |v| >= 3.5 ADC -> unchanged (full precision)
135165
///
136-
/// steps=0 dynamic precision is not applied
137-
void applyDynamicPrecision(uint16_t steps);
166+
/// threshold=0 rounding is not applied
167+
void roundToIntegers(uint16_t threshold);
138168

139-
/// Compress this object into a CMVPerTFCompressed using delta+zigzag+varint encoding
140-
CMVPerTFCompressed compress() const;
169+
/// Compress this object into a CMVPerTFVarint using delta+zigzag+varint encoding
170+
CMVPerTFVarint compressVarint() const;
141171

142172
/// Compress this object into a CMVPerTFSparse storing only non-zero timebins
143173
CMVPerTFSparse compressSparse() const;
144174

175+
/// Hybrid sparse+compressed-value compression
176+
/// Positions encoded as sparse varint deltas; values encoded according to valueMode:
177+
/// 0 = raw uint16_t (same as compressSparse, no additional gain)
178+
/// 1 = varint signed CMV value
179+
/// 2 = Huffman signed CMV value
180+
CMVPerTFCombined compressCombined(uint8_t valueMode = 0) const;
181+
145182
/// Compress this object using delta+zigzag+canonical-Huffman encoding
146183
CMVPerTFHuffman compressHuffman() const;
147184

@@ -162,4 +199,4 @@ struct CMVPerTF {
162199

163200
} // namespace o2::tpc
164201

165-
#endif // ALICEO2_TPC_CMVCONTAINER_H_
202+
#endif // ALICEO2_TPC_CMVCONTAINER_H_

Detectors/TPC/calibration/macro/drawCMV.C

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,34 +78,42 @@ TObjArray* drawCMV(std::string_view filename, std::string_view outDir)
7878
TH2F* h2d = new TH2F("hCMVvsTimeBin", ";Timebin (200 ns);Common Mode Values (ADC)",
7979
100, 0, nTimeBins,
8080
110, -100.5, 9.5);
81-
h2d->SetStats(0);
81+
h2d->SetStats(1);
8282

83-
// auto-detect branch format: sparse, huffman, compressed (delta+zigzag+varint), or raw CMVPerTF
83+
// auto-detect branch format
84+
const bool isCombined = (tree->GetBranch("CMVPerTFCombined") != nullptr);
8485
const bool isSparse = (tree->GetBranch("CMVPerTFSparse") != nullptr);
8586
const bool isHuffman = (tree->GetBranch("CMVPerTFHuffman") != nullptr);
86-
const bool isCompressed = (tree->GetBranch("CMVPerTFCompressed") != nullptr);
87+
const bool isVarint = (tree->GetBranch("CMVPerTFVarint") != nullptr);
8788
const bool isRaw = (tree->GetBranch("CMVPerTF") != nullptr);
88-
if (!isSparse && !isHuffman && !isCompressed && !isRaw) {
89-
fmt::print("ERROR: no recognised branch found (expected CMVPerTFSparse, CMVPerTFHuffman, CMVPerTFCompressed, or CMVPerTF)\n");
89+
if (!isCombined && !isSparse && !isHuffman && !isVarint && !isRaw) {
90+
fmt::print("ERROR: no recognised branch found (expected CMVPerTFCombined, CMVPerTFSparse, CMVPerTFHuffman, CMVPerTFVarint, or CMVPerTF)\n");
9091
return arrCanvases;
9192
}
92-
const std::string branchFormat = isSparse ? "CMVPerTFSparse (sparse)" : (isHuffman ? "CMVPerTFHuffman (delta+zigzag+Huffman)" : (isCompressed ? "CMVPerTFCompressed (delta+zigzag+varint)" : "CMVPerTF (raw)"));
93+
const std::string branchFormat =
94+
isCombined ? "CMVPerTFCombined (sparse + compressed exact values)" : isSparse ? "CMVPerTFSparse (sparse)"
95+
: isHuffman ? "CMVPerTFHuffman (delta+zigzag+Huffman)"
96+
: isVarint ? "CMVPerTFVarint (delta+zigzag+varint)"
97+
: "CMVPerTF (raw)";
9398
fmt::print("Branch format: {}\n", branchFormat);
9499

95100
// branch setup — only one pointer is active depending on the detected format
101+
o2::tpc::CMVPerTFCombined* tfCombined = nullptr;
96102
o2::tpc::CMVPerTFSparse* tfSparse = nullptr;
97103
o2::tpc::CMVPerTFHuffman* tfHuffman = nullptr;
98-
o2::tpc::CMVPerTFCompressed* tfCompressed = nullptr;
104+
o2::tpc::CMVPerTFVarint* tfVarint = nullptr;
99105
o2::tpc::CMVPerTF* tfRaw = nullptr;
100106
// staging object for decompression
101-
CMVPerTF* tfDecoded = (isSparse || isHuffman || isCompressed) ? new CMVPerTF() : nullptr;
107+
CMVPerTF* tfDecoded = (isCombined || isSparse || isHuffman || isVarint) ? new CMVPerTF() : nullptr;
102108

103-
if (isSparse) {
109+
if (isCombined) {
110+
tree->SetBranchAddress("CMVPerTFCombined", &tfCombined);
111+
} else if (isSparse) {
104112
tree->SetBranchAddress("CMVPerTFSparse", &tfSparse);
105113
} else if (isHuffman) {
106114
tree->SetBranchAddress("CMVPerTFHuffman", &tfHuffman);
107-
} else if (isCompressed) {
108-
tree->SetBranchAddress("CMVPerTFCompressed", &tfCompressed);
115+
} else if (isVarint) {
116+
tree->SetBranchAddress("CMVPerTFVarint", &tfVarint);
109117
} else {
110118
tree->SetBranchAddress("CMVPerTF", &tfRaw);
111119
}
@@ -117,14 +125,17 @@ TObjArray* drawCMV(std::string_view filename, std::string_view outDir)
117125

118126
// resolve to a unified pointer regardless of storage format
119127
const CMVPerTF* tf = nullptr;
120-
if (isSparse) {
128+
if (isCombined) {
129+
tfCombined->decompress(tfDecoded);
130+
tf = tfDecoded;
131+
} else if (isSparse) {
121132
tfSparse->decompress(tfDecoded);
122133
tf = tfDecoded;
123134
} else if (isHuffman) {
124135
tfHuffman->decompress(tfDecoded);
125136
tf = tfDecoded;
126-
} else if (isCompressed) {
127-
tfCompressed->decompress(tfDecoded);
137+
} else if (isVarint) {
138+
tfVarint->decompress(tfDecoded);
128139
tf = tfDecoded;
129140
} else {
130141
tf = tfRaw;
@@ -137,15 +148,17 @@ TObjArray* drawCMV(std::string_view filename, std::string_view outDir)
137148
for (int cru = 0; cru < nCRUs; ++cru) {
138149
for (int tb = 0; tb < nTimeBins; ++tb) {
139150
h2d->Fill(tb, tf->getCMVFloat(cru, tb));
151+
// fmt::print("cru: {}, tb: {}, cmv: {}\n", cru, tb, tf->getCMVFloat(cru, tb));
140152
}
141153
}
142154
}
143155

144156
delete tfDecoded;
145157
tree->ResetBranchAddresses();
158+
delete tfCombined;
146159
delete tfSparse;
147160
delete tfHuffman;
148-
delete tfCompressed;
161+
delete tfVarint;
149162

150163
fmt::print("firstOrbit: {}\n", firstOrbit);
151164

0 commit comments

Comments
 (0)