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_
0 commit comments