Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
33e2fd0
TPC: Processing of common mode values in O2
tubagundem Mar 9, 2026
940e41c
Added CMVContainer.cxx, fixed missing links and includes
tubagundem Mar 10, 2026
2075879
Fix formatting
tubagundem Mar 10, 2026
4471254
Removed unused includes, directly write the TTree object to CCDB with…
tubagundem Mar 10, 2026
bf10504
Changed the decoding and encoding of CMVs, removed grouping per side
tubagundem Mar 11, 2026
5d1cc3b
Update the dataformat of CMV
tubagundem Mar 12, 2026
0a4d8ac
Updated the CMVContainer, corrected the timestamp range for CCDB
tubagundem Mar 18, 2026
dc3ff00
Fix formatting
tubagundem Mar 18, 2026
a4a09b1
Removed factorize workflow, updated the distribute workflow accordingly
tubagundem Mar 18, 2026
3ead34a
Fix formatting
tubagundem Mar 18, 2026
82663fb
Extend error tracking in CMVToVectorSpec.cxx
tubagundem Mar 18, 2026
37e12af
Replace CMVPerInterval with per TF TTree accumulation and raw uint16_…
tubagundem Mar 25, 2026
baf4d6d
Added delta+zigzag+varint compression, added drawCMV.C macro for visu…
tubagundem Mar 26, 2026
3c207a6
Added small value zeroing, added `--use-compression` and `--cmv-zero-…
tubagundem Mar 31, 2026
9fc3e05
Added sparse and HUffman encoding to the CMVContainer, updatet the dr…
tubagundem Apr 1, 2026
5d720d4
Added CMVPerTFCombined to CMVContainer to combine sparse encoding wit…
tubagundem Apr 3, 2026
8e5cf37
Added gaussian dynamic precision
tubagundem Apr 8, 2026
27b73e3
Refactored CMVContainer, unified CMV compression in a flag based cont…
tubagundem Apr 9, 2026
d218dec
Added CMV workflow documentation to README and fixed CMV packet size …
tubagundem Apr 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions DataFormats/Detectors/TPC/include/DataFormatsTPC/CMV.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/// @file CMV.h
/// @author Tuba Gündem, tuba.gundem@cern.ch
/// @brief Common mode values data format definition

/// The data is sent by the CRU as 256+16 bit words. The CMV data layout is as follows:
/// - 256-bit Header: [version:8][packetID:8][errorCode:8][magicWord:8][heartbeatOrbit:32][heartbeatBC:16][padding:176]
/// - 16-bit CMV value: [CMV:16]

#ifndef ALICEO2_DATAFORMATSTPC_CMV_H
#define ALICEO2_DATAFORMATSTPC_CMV_H

#include <bitset>

namespace o2::tpc::cmv
{

static constexpr uint32_t NTimeBinsPerPacket = 3564; ///< number of time bins (covering 8 heartbeats)
static constexpr uint32_t NPacketsPerTFPerCRU = 4; ///< 4 packets per timeframe
static constexpr uint32_t NTimeBinsPerTF = NTimeBinsPerPacket * NPacketsPerTFPerCRU; ///< maximum number of timebins per timeframe (14256)
static constexpr uint32_t SignificantBits = 2; ///< number of bits used for floating point precision
static constexpr float FloatConversion = 1.f / float(1 << SignificantBits); ///< conversion factor from integer representation to float

/// Header definition of the CMVs
struct Header {
static constexpr uint8_t MagicWord = 0xDC;
union {
Comment thread
tubagundem marked this conversation as resolved.
uint32_t word0 = 0; ///< bits 0 - 31
struct {
uint8_t version : 8; ///< version
uint8_t packetID : 8; ///< packet id
uint8_t errorCode : 8; ///< errors
uint8_t magicWord : 8; ///< magic word
};
};
union {
uint32_t word1 = 0; ///< bits 32 - 63
struct {
uint32_t heartbeatOrbit : 32; ///< first heart beat timing of the package
};
};
union {
uint16_t word2 = 0; ///< bits 64 - 79
struct {
uint16_t heartbeatBC : 16; ///< first BC id of the package
};
};
union {
uint16_t word3 = 0; ///< bits 80 - 95
struct {
uint16_t unused1 : 16; ///< reserved
};
};
union {
uint32_t word4 = 0; ///< bits 96 - 127
struct {
uint32_t unused2 : 32; ///< reserved
};
};
union {
uint64_t word5 = 0; ///< bits 128 - 191
struct {
uint64_t unused3 : 64; ///< reserved
};
};
union {
uint64_t word6 = 0; ///< bits 192 - 255
struct {
uint64_t unused4 : 64; ///< reserved
};
};
};

/// CMV single data container
struct Data {
uint16_t CMV{0}; ///< 16bit ADC value
Comment thread
tubagundem marked this conversation as resolved.
Outdated

// Raw integer accessors
uint16_t getCMV() const { return CMV; }
void setCMV(uint16_t value) { CMV = value; }

// Float helpers using SignificantBits for fixed-point conversion
float getCMVFloat() const { return static_cast<float>(CMV) * FloatConversion; }
void setCMVFloat(float value)
{
// round to nearest representable fixed-point value
setCMV(uint32_t((value + 0.5f * FloatConversion) / FloatConversion));
}
};

/// CMV full data container: one packet carries NTimeBinsPerPacket
struct Container {
Header header; ///< CMV data header
Data data[NTimeBinsPerPacket]; ///< data values

// Header and data accessors
const Header& getHeader() const { return header; }
Header& getHeader() { return header; }

const Data* getData() const { return data; }
Data* getData() { return data; }

// Per-time-bin CMV accessors
uint16_t getCMV(uint32_t timeBin) const { return data[timeBin].getCMV(); }
void setCMV(uint32_t timeBin, uint16_t value) { data[timeBin].setCMV(value); }

float getCMVFloat(uint32_t timeBin) const { return data[timeBin].getCMVFloat(); }
void setCMVFloat(uint32_t timeBin, float value) { data[timeBin].setCMVFloat(value); }
};

} // namespace o2::tpc::cmv

#endif
3 changes: 2 additions & 1 deletion Detectors/TPC/base/include/TPCBase/RDHUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#define AliceO2_TPC_RDHUtils_H

#include "DetectorsRaw/RDHUtils.h"
//#include "Headers/RAWDataHeader.h"
// #include "Headers/RAWDataHeader.h"

namespace o2
{
Expand All @@ -28,6 +28,7 @@ static constexpr FEEIDType UserLogicLinkID = 15; ///< virtual link ID for ZS dat
static constexpr FEEIDType IDCLinkID = 20; ///< Identifier for integrated digital currents
static constexpr FEEIDType ILBZSLinkID = 21; ///< Identifier for improved link-based ZS
static constexpr FEEIDType DLBZSLinkID = 22; ///< Identifier for dense link-based ZS
static constexpr FEEIDType CMVLinkID = 23; ///< Identifier for common mode values
static constexpr FEEIDType SACLinkID = 25; ///< Identifier for sampled analog currents

/// compose feeid from cru, endpoint and link
Expand Down
4 changes: 3 additions & 1 deletion Detectors/TPC/calibration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ o2_add_library(TPCCalibration
src/DigitAdd.cxx
src/CorrectdEdxDistortions.cxx
src/PressureTemperatureHelper.cxx
src/CMVContainer.cxx
PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC O2::TPCBaseRecSim
O2::TPCReconstruction ROOT::Minuit
Microsoft.GSL::GSL
Expand Down Expand Up @@ -115,7 +116,8 @@ o2_target_root_dictionary(TPCCalibration
include/TPCCalibration/TPCMShapeCorrection.h
include/TPCCalibration/DigitAdd.h
include/TPCCalibration/CorrectdEdxDistortions.h
include/TPCCalibration/PressureTemperatureHelper.h)
include/TPCCalibration/PressureTemperatureHelper.h
include/TPCCalibration/CMVContainer.h)

o2_add_test_root_macro(macro/comparePedestalsAndNoise.C
PUBLIC_LINK_LIBRARIES O2::TPCBaseRecSim
Expand Down
76 changes: 76 additions & 0 deletions Detectors/TPC/calibration/include/TPCCalibration/CMVContainer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/// @file CMVContainer.h
/// @author Tuba Gündem, tuba.gundem@cern.ch
/// @brief Struct for storing CMVs to the CCDB

#ifndef ALICEO2_TPC_CMVCONTAINER_H_
#define ALICEO2_TPC_CMVCONTAINER_H_

#include <vector>
#include <string>
#include <memory>

#include "TTree.h"

namespace o2::tpc
{

/// CMVContainer: accumulator for one aggregation interval
struct CMVContainer {

uint32_t nTFs{0}; ///< number of TFs accumulated
uint32_t nCRUs{0}; ///< number of contributing CRUs
long firstTF{0}; ///< first TF counter in this aggregation interval

std::vector<float> cmvValues{}; ///< CMV float values
std::vector<uint32_t> cru{}; ///< CRU indices
std::vector<uint32_t> timebin{}; ///< absolute timebins within the TF
std::vector<uint32_t> tf{}; ///< TF counters

/// Pre-allocate storage for the expected number of entries: expectedTFs × expectedCRUs × NTimeBinsPerTF
void reserve(uint32_t expectedTFs, uint32_t expectedCRUs);

/// Append one (cmv, cru, timebin, tf) tuple
void addEntry(float cmvVal, uint32_t cruID, uint32_t tb, uint32_t tfCounter);

/// Append one full CRU packet (NTimeBinsPerPacket consecutive timebins)
/// \param packet pointer to NTimeBinsPerPacket floats
/// \param cruID CRU index
/// \param tbOffset absolute timebin of the first sample in this packet
/// \param tfCounter TF counter
void addPacket(const float* packet, uint32_t cruID, uint32_t tbOffset, uint32_t tfCounter);

std::size_t size() const;
bool empty() const;

/// Clear all data and reset counters
void clear();

std::string summary() const;

/// Build an in-memory TTree with one branch per field and one entry per tuple
std::unique_ptr<TTree> toTTree() const;

/// Write the container as a TTree inside a TFile on disk
/// \param filename path to the output ROOT file
void writeToFile(const std::string& filename) const;

/// Restore a CMVContainer from a TTree previously written by toTTree()
static CMVContainer fromTTree(TTree* tree, int entry = 0);

ClassDefNV(CMVContainer, 1)
Comment thread
tubagundem marked this conversation as resolved.
Outdated
};

} // namespace o2::tpc

#endif // ALICEO2_TPC_CMVCONTAINER_H_
138 changes: 138 additions & 0 deletions Detectors/TPC/calibration/src/CMVContainer.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/// @file CMVContainer.cxx
/// @author Tuba Gündem, tuba.gundem@cern.ch

#include <stdexcept>
#include <fmt/format.h>

#include "TFile.h"

#include "TPCCalibration/CMVContainer.h"
#include "DataFormatsTPC/CMV.h"

namespace o2::tpc
{

void CMVContainer::reserve(uint32_t expectedTFs, uint32_t expectedCRUs)
{
const std::size_t n = static_cast<std::size_t>(expectedTFs) * expectedCRUs * o2::tpc::cmv::NTimeBinsPerTF;
cmvValues.reserve(n);
cru.reserve(n);
timebin.reserve(n);
tf.reserve(n);
}

void CMVContainer::addEntry(float cmvVal, uint32_t cruID, uint32_t tb, uint32_t tfCounter)
{
cmvValues.push_back(cmvVal);
cru.push_back(cruID);
timebin.push_back(tb);
tf.push_back(tfCounter);
}

void CMVContainer::addPacket(const float* packet, uint32_t cruID, uint32_t tbOffset, uint32_t tfCounter)
{
for (uint32_t tb = 0; tb < o2::tpc::cmv::NTimeBinsPerPacket; ++tb) {
addEntry(packet[tb], cruID, tbOffset + tb, tfCounter);
}
}

std::size_t CMVContainer::size() const { return cmvValues.size(); }

bool CMVContainer::empty() const { return cmvValues.empty(); }

void CMVContainer::clear()
{
cmvValues.clear();
cru.clear();
timebin.clear();
tf.clear();
nTFs = 0;
nCRUs = 0;
firstTF = 0;
}

std::string CMVContainer::summary() const
{
return fmt::format("CMVContainer: {} entries, {} TFs, {} CRUs, firstTF={}",
size(), nTFs, nCRUs, firstTF);
}

std::unique_ptr<TTree> CMVContainer::toTTree() const
{
const std::size_t n = size();
if (n == 0) {
throw std::runtime_error("CMVContainer::toTTree() called on empty container");
}

auto tree = std::make_unique<TTree>("CMVTree", "TPC common mode values");
tree->SetAutoSave(0);

// Point branches directly at the vector data — single Fill() call writes all rows
float* pCmv = const_cast<float*>(cmvValues.data());
uint32_t* pCru = const_cast<uint32_t*>(cru.data());
uint32_t* pTimebin = const_cast<uint32_t*>(timebin.data());
uint32_t* pTf = const_cast<uint32_t*>(tf.data());

tree->Branch("cmv", pCmv, fmt::format("cmv[{}]/F", n).c_str());
tree->Branch("cru", pCru, fmt::format("cru[{}]/i", n).c_str());
tree->Branch("timebin", pTimebin, fmt::format("timebin[{}]/i", n).c_str());
tree->Branch("tf", pTf, fmt::format("tf[{}]/i", n).c_str());
Comment thread
tubagundem marked this conversation as resolved.
Outdated

tree->Fill();
return tree;
}

void CMVContainer::writeToFile(const std::string& filename) const
{
TFile f(filename.c_str(), "RECREATE");
if (f.IsZombie()) {
throw std::runtime_error(fmt::format("CMVContainer::writeToFile: cannot open '{}'", filename));
}
auto tree = toTTree();
tree->Write();
f.Close();
}

CMVContainer CMVContainer::fromTTree(TTree* tree, int entry)
{
if (!tree) {
throw std::runtime_error("CMVContainer::fromTTree: null TTree pointer");
}

CMVContainer c;
const Long64_t nEntries = tree->GetEntries();
if (nEntries <= 0) {
return c;
}

// Read the array branches back into vectors in one GetEntry() call
std::vector<float> bCmv(nEntries);
std::vector<uint32_t> bCru(nEntries), bTimebin(nEntries), bTf(nEntries);

tree->SetBranchAddress("cmv", bCmv.data());
tree->SetBranchAddress("cru", bCru.data());
tree->SetBranchAddress("timebin", bTimebin.data());
tree->SetBranchAddress("tf", bTf.data());

tree->GetEntry(entry);

c.cmvValues = std::move(bCmv);
c.cru = std::move(bCru);
c.timebin = std::move(bTimebin);
c.tf = std::move(bTf);

return c;
}

} // namespace o2::tpc
2 changes: 2 additions & 0 deletions Detectors/TPC/calibration/src/TPCCalibrationLinkDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,6 @@
#pragma link C++ class o2::tpc::DigitAdd + ;
#pragma link C++ class std::vector < o2::tpc::DigitAdd> + ;
#pragma link C++ class o2::tpc::PressureTemperatureHelper + ;
#pragma link C++ class o2::tpc::CMVContainer + ;

#endif
Loading