Skip to content

Commit 90d4fb6

Browse files
committed
Added CMV container and factorize workflow
1 parent adf86b5 commit 90d4fb6

File tree

7 files changed

+628
-20
lines changed

7 files changed

+628
-20
lines changed

DataFormats/Detectors/TPC/include/DataFormatsTPC/CMV.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
namespace o2::tpc::cmv
2626
{
2727

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

3234
/// Header definition of the CMVs
3335
struct Header {
@@ -96,10 +98,10 @@ struct Data {
9698
}
9799
};
98100

99-
/// CMV full data container: one packet carries NTimeBins time bins
101+
/// CMV full data container: one packet carries NTimeBinsPerPacket
100102
struct Container {
101-
Header header; ///< CMV data header
102-
Data data[NTimeBins]; ///< data values for given number of time bins
103+
Header header; ///< CMV data header
104+
Data data[NTimeBinsPerPacket]; ///< data values
103105

104106
// Header and data accessors
105107
const Header& getHeader() const { return header; }
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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+
12+
/// @file CMVContainer.h
13+
/// @author Tuba Gündem, tuba.gundem@cern.ch
14+
/// @brief Struct for storing CMVs to the CCDB
15+
16+
#ifndef ALICEO2_TPC_CMVCONTAINER_H_
17+
#define ALICEO2_TPC_CMVCONTAINER_H_
18+
19+
#include <vector>
20+
#include <string>
21+
#include <memory>
22+
#include <stdexcept>
23+
24+
#include <fmt/format.h>
25+
26+
#include "TTree.h"
27+
#include "TFile.h"
28+
29+
#include "DataFormatsTPC/CMV.h"
30+
31+
namespace o2::tpc
32+
{
33+
34+
/// CMVContainer: accumulator for one aggregation interval
35+
struct CMVContainer {
36+
37+
uint32_t nTFs{0}; ///< number of TFs accumulated
38+
uint32_t nCRUs{0}; ///< number of contributing CRUs
39+
long firstTF{0}; ///< first TF counter in this aggregation interval
40+
41+
std::vector<float> cmvValues{}; ///< CMV float values
42+
std::vector<uint32_t> cru{}; ///< CRU indices
43+
std::vector<uint32_t> timebin{}; ///< absolute timebins within the TF
44+
std::vector<uint32_t> tf{}; ///< TF counters
45+
46+
/// Pre-allocate storage for the expected number of entries: expectedTFs × expectedCRUs × NTimeBinsPerTF
47+
void reserve(uint32_t expectedTFs, uint32_t expectedCRUs)
48+
{
49+
const std::size_t n = static_cast<std::size_t>(expectedTFs) * expectedCRUs * o2::tpc::cmv::NTimeBinsPerTF;
50+
cmvValues.reserve(n);
51+
cru.reserve(n);
52+
timebin.reserve(n);
53+
tf.reserve(n);
54+
}
55+
56+
/// Append one (cmv, cru, timebin, tf) tuple
57+
void addEntry(float cmvVal, uint32_t cruID, uint32_t tb, uint32_t tfCounter)
58+
{
59+
cmvValues.push_back(cmvVal);
60+
cru.push_back(cruID);
61+
timebin.push_back(tb);
62+
tf.push_back(tfCounter);
63+
}
64+
65+
/// Append one full CRU packet (NTimeBinsPerPacket consecutive timebins)
66+
/// \param packet pointer to NTimeBinsPerPacket floats
67+
/// \param cruID CRU index
68+
/// \param tbOffset absolute timebin of the first sample in this packet
69+
/// \param tfCounter TF counter
70+
void addPacket(const float* packet, uint32_t cruID, uint32_t tbOffset, uint32_t tfCounter)
71+
{
72+
for (uint32_t tb = 0; tb < o2::tpc::cmv::NTimeBinsPerPacket; ++tb) {
73+
addEntry(packet[tb], cruID, tbOffset + tb, tfCounter);
74+
}
75+
}
76+
77+
std::size_t size() const { return cmvValues.size(); }
78+
bool empty() const { return cmvValues.empty(); }
79+
80+
/// Clear all data and reset counters
81+
void clear()
82+
{
83+
cmvValues.clear();
84+
cru.clear();
85+
timebin.clear();
86+
tf.clear();
87+
nTFs = 0;
88+
nCRUs = 0;
89+
firstTF = 0;
90+
}
91+
92+
std::string summary() const
93+
{
94+
return fmt::format("CMVContainer: {} entries, {} TFs, {} CRUs, firstTF={}",
95+
size(), nTFs, nCRUs, firstTF);
96+
}
97+
98+
/// Build an in-memory TTree with one branch per field and one entry per tuple
99+
std::unique_ptr<TTree> toTTree() const
100+
{
101+
const std::size_t n = size();
102+
if (n == 0) {
103+
throw std::runtime_error("CMVContainer::toTTree() called on empty container");
104+
}
105+
106+
auto tree = std::make_unique<TTree>("CMVTree", "TPC common mode values");
107+
tree->SetAutoSave(0);
108+
109+
// Point branches directly at the vector data — single Fill() call writes all rows
110+
float* pCmv = const_cast<float*>(cmvValues.data());
111+
uint32_t* pCru = const_cast<uint32_t*>(cru.data());
112+
uint32_t* pTimebin = const_cast<uint32_t*>(timebin.data());
113+
uint32_t* pTf = const_cast<uint32_t*>(tf.data());
114+
115+
tree->Branch("cmv", pCmv, fmt::format("cmv[{}]/F", n).c_str());
116+
tree->Branch("cru", pCru, fmt::format("cru[{}]/i", n).c_str());
117+
tree->Branch("timebin", pTimebin, fmt::format("timebin[{}]/i", n).c_str());
118+
tree->Branch("tf", pTf, fmt::format("tf[{}]/i", n).c_str());
119+
120+
tree->Fill();
121+
return tree;
122+
}
123+
124+
/// Write the container as a TTree inside a TFile on disk
125+
/// \param filename path to the output ROOT file
126+
void writeToFile(const std::string& filename) const
127+
{
128+
TFile f(filename.c_str(), "RECREATE");
129+
if (f.IsZombie()) {
130+
throw std::runtime_error(fmt::format("CMVContainer::writeToFile: cannot open '{}'", filename));
131+
}
132+
auto tree = toTTree();
133+
tree->Write();
134+
f.Close();
135+
}
136+
137+
/// Restore a CMVContainer from a TTree previously written by toTTree()
138+
static CMVContainer fromTTree(TTree* tree)
139+
{
140+
if (!tree) {
141+
throw std::runtime_error("CMVContainer::fromTTree: null TTree pointer");
142+
}
143+
144+
CMVContainer c;
145+
const Long64_t nEntries = tree->GetEntries();
146+
if (nEntries <= 0) {
147+
return c;
148+
}
149+
150+
// Read the array branches back into vectors in one GetEntry() call
151+
std::vector<float> bCmv(nEntries);
152+
std::vector<uint32_t> bCru(nEntries), bTimebin(nEntries), bTf(nEntries);
153+
154+
tree->SetBranchAddress("cmv", bCmv.data());
155+
tree->SetBranchAddress("cru", bCru.data());
156+
tree->SetBranchAddress("timebin", bTimebin.data());
157+
tree->SetBranchAddress("tf", bTf.data());
158+
159+
tree->GetEntry(0);
160+
161+
c.cmvValues = std::move(bCmv);
162+
c.cru = std::move(bCru);
163+
c.timebin = std::move(bTimebin);
164+
c.tf = std::move(bTf);
165+
166+
return c;
167+
}
168+
169+
ClassDefNV(CMVContainer, 1)
170+
};
171+
172+
} // namespace o2::tpc
173+
174+
#endif // ALICEO2_TPC_CMVCONTAINER_H_

Detectors/TPC/workflow/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,9 @@ o2_add_executable(cmv-distribute
304304
SOURCES src/tpc-distribute-cmv.cxx
305305
PUBLIC_LINK_LIBRARIES O2::TPCWorkflow)
306306

307-
# o2_add_executable(cmv-producer
308-
# COMPONENT_NAME tpc
309-
# SOURCES src/tpc-cmv-producer.cxx
310-
# PUBLIC_LINK_LIBRARIES O2::TPCWorkflow)
307+
o2_add_executable(cmv-factorize
308+
COMPONENT_NAME tpc
309+
SOURCES src/tpc-factorize-cmv.cxx
310+
PUBLIC_LINK_LIBRARIES O2::TPCWorkflow)
311311

312312
add_subdirectory(readers)

Detectors/TPC/workflow/include/TPCWorkflow/TPCFLPCMVSpec.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class TPCFLPCMVDevice : public o2::framework::Task
4949

5050
void run(o2::framework::ProcessingContext& pc) final
5151
{
52-
// LOGP(info, "Processing CMVs for TF {} for CRUs {} to {}", processing_helpers::getCurrentTF(pc), mCRUs.front(), mCRUs.back());
52+
LOGP(info, "Processing CMVs for TF {} for CRUs {} to {}", processing_helpers::getCurrentTF(pc), mCRUs.front(), mCRUs.back());
5353

5454
++mCountTFsForBuffer;
5555

@@ -63,7 +63,7 @@ class TPCFLPCMVDevice : public o2::framework::Task
6363
if (mCountTFsForBuffer >= mNTFsBuffer) {
6464
mCountTFsForBuffer = 0;
6565
for (const auto cru : mCRUs) {
66-
// LOGP(info, "Sending CMVs of size {} for TF {}", mCMVs[cru].size(), processing_helpers::getCurrentTF(pc));
66+
LOGP(info, "Sending CMVs of size {} for TF {}", mCMVs[cru].size(), processing_helpers::getCurrentTF(pc));
6767
sendOutput(pc.outputs(), cru);
6868
}
6969
}

0 commit comments

Comments
 (0)