Project
Loading...
Searching...
No Matches
CTFCoder.cxx
Go to the documentation of this file.
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
15
17#include <TTree.h>
18
19namespace o2::itsmft
20{
21
23// Register encoded data in the tree (Fill is not called, will be done by caller)
24template <int N>
25void CTFCoder<N>::appendToTree(TTree& tree, CTF& ec, int id)
26{
27 ec.appendToTree(tree, id >= 0 ? fmt::format("{}_{}", mDet.getName(), id) : mDet.getName());
28}
29
31// extract and decode data from the tree
32template <int N>
33void CTFCoder<N>::readFromTree(TTree& tree, int entry, int id, std::vector<ROFRecord>& rofRecVec,
34 std::vector<CompClusterExt>& cclusVec, std::vector<unsigned char>& pattVec, const NoiseMap* noiseMap, const LookUp& clPattLookup)
35{
36 assert(entry >= 0 && entry < tree.GetEntries());
37 CTF ec;
38 ec.readFromTree(tree, id >= 0 ? fmt::format("{}_{}", mDet.getName(), id) : mDet.getName(), entry);
39 decode(ec, rofRecVec, cclusVec, pattVec, noiseMap, clPattLookup);
40}
41
43template <int N>
44void CTFCoder<N>::compress(CompressedClusters& cc,
45 const gsl::span<const ROFRecord>& rofRecVec,
46 const gsl::span<const CompClusterExt>& cclusVec,
47 const gsl::span<const unsigned char>& pattVec,
48 const LookUp& clPattLookup, int strobeLength)
49{
50 // store in the header the orbit of 1st ROF
51 cc.clear();
52 cc.header.det = mDet;
53 if (!rofRecVec.size()) {
54 return;
55 }
56 uint32_t firstROF = rofRecVec.size(), nrofSel = rofRecVec.size(), nClusSel = cclusVec.size();
57 std::vector<bool> reject(rofRecVec.size());
58 if (mIRFrameSelector.isSet()) {
59 for (size_t ir = 0; ir < rofRecVec.size(); ir++) {
60 auto irStart = rofRecVec[ir].getBCData();
61 if (mIRFrameSelector.check({irStart, irStart + strobeLength - 1}) < 0) {
62 reject[ir] = true;
63 nrofSel--;
64 nClusSel -= rofRecVec[ir].getNEntries();
65 } else if (firstROF == rofRecVec.size()) {
66 firstROF = ir;
67 }
68 }
69 } else {
70 firstROF = 0;
71 }
72 if (nrofSel == 0) { // nothing is selected
73 return;
74 }
75 assert(nClusSel <= cclusVec.size());
76
77 const auto& rofRec0 = rofRecVec[firstROF];
78 cc.header.firstOrbit = rofRec0.getBCData().orbit;
79 cc.header.firstBC = rofRec0.getBCData().bc;
80 cc.header.nROFs = nrofSel;
81 cc.header.nClusters = nClusSel;
82
83 cc.firstChipROF.resize(nrofSel);
84 cc.bcIncROF.resize(nrofSel);
85 cc.orbitIncROF.resize(nrofSel);
86 cc.nclusROF.resize(nrofSel);
87 //
88 cc.row.resize(nClusSel);
89 cc.colInc.resize(nClusSel);
90 // cc.chipInc.resize(cc.header.nClusters); // this is the version with chipInc stored for every pixel
91 cc.chipInc.reserve(1000); // this is the version with chipInc stored once per new chip
92 cc.chipMul.reserve(1000); // this is the version with chipInc stored once per new chip
93 cc.pattID.resize(nClusSel);
94
95 bool selectPatterns = nrofSel < rofRecVec.size();
96 if (!selectPatterns) { // nothing is rejected, simply copy the patterns
97 cc.header.nPatternBytes = pattVec.size();
98 cc.pattMap.resize(pattVec.size()); // to be resized in case of selection
99 memcpy(cc.pattMap.data(), pattVec.data(), pattVec.size());
100 } else {
101 cc.pattMap.reserve(pattVec.size());
102 }
103
104 uint16_t prevBC = cc.header.firstBC;
105 uint32_t prevOrbit = cc.header.firstOrbit;
106 int irofOut = 0, iclOut = 0;
107 auto pattIt = pattVec.begin(), pattIt0 = pattVec.begin();
108 for (uint32_t irof = 0; irof < rofRecVec.size(); irof++) {
109 const auto& rofRec = rofRecVec[irof];
110 const auto& intRec = rofRec.getBCData();
111
112 if (reject[irof]) { // need to skip some patterns
113 if (selectPatterns && pattIt != pattIt0) { // copy what was already selected
114 cc.pattMap.insert(cc.pattMap.end(), pattIt0, pattIt);
115 pattIt0 = pattIt;
116 }
117 for (int icl = rofRec.getFirstEntry(); icl < rofRec.getFirstEntry() + rofRec.getNEntries(); icl++) {
118 const auto& clus = cclusVec[icl];
119 if (clus.getPatternID() == o2::itsmft::CompCluster::InvalidPatternID || clPattLookup.isGroup(clus.getPatternID())) {
121 }
122 }
123 pattIt = pattIt0;
124 continue;
125 }
126 if (intRec.orbit == prevOrbit) {
127 cc.orbitIncROF[irofOut] = 0;
128#ifdef _CHECK_INCREMENTES_
129 if (intRec.bc < prevBC) {
130 LOG(warning) << "Negative BC increment " << intRec.bc << " -> " << prevBC;
131 }
132#endif
133 cc.bcIncROF[irofOut] = int16_t(intRec.bc - prevBC); // store increment of BC if in the same orbit
134 } else {
135 cc.orbitIncROF[irofOut] = int32_t(intRec.orbit - prevOrbit);
136#ifdef _CHECK_INCREMENTES_
137 if (intRec.orbit < prevOrbit) {
138 LOG(warning) << "Negative Orbit increment " << intRec.orbit << " -> " << prevOrbit;
139 }
140#endif
141 cc.bcIncROF[irofOut] = intRec.bc; // otherwise, store absolute bc
142 prevOrbit = intRec.orbit;
143 }
144 prevBC = intRec.bc;
145 auto ncl = rofRec.getNEntries();
146 cc.nclusROF[irofOut] = ncl;
147 if (!ncl) { // no hits data for this ROF
148 cc.firstChipROF[irofOut] = 0;
149 irofOut++;
150 continue;
151 }
152 cc.firstChipROF[irofOut] = cclusVec[rofRec.getFirstEntry()].getChipID();
153 int icl = rofRec.getFirstEntry(), iclMax = icl + ncl;
154
155 uint16_t prevChip = cc.firstChipROF[irofOut], prevCol = 0;
156 if (icl != iclMax) { // there are still clusters to store
157 cc.chipMul.push_back(0);
158 cc.chipInc.push_back(0);
159 }
160 for (; icl < iclMax; icl++) { // clusters within a chip are stored in increasing column number
161 const auto& cl = cclusVec[icl];
162 cc.row[iclOut] = cl.getRow(); // row is practically random, store it as it is
163 cc.pattID[iclOut] = cl.getPatternID();
164 if (selectPatterns && (cc.pattID[iclOut] == o2::itsmft::CompCluster::InvalidPatternID || clPattLookup.isGroup(cl.getPatternID()))) {
166 }
167 if (cl.getChipID() == prevChip) { // for the same chip store column increment
168 // cc.chipInc[iclOut] = 0; // this is the version with chipInc stored for every pixel
169 cc.chipMul.back()++; // this is the version with chipInc stored once per new chip
170 cc.colInc[iclOut] = int16_t(cl.getCol()) - prevCol;
171 prevCol = cl.getCol();
172 } else { // for new chips store chipID increment and abs. column
173 // cc.chipInc[iclOut] = cl.getChipID() - prevChip; // this is the version with chipInc stored for every pixel
174 cc.chipInc.push_back(int16_t(cl.getChipID() - prevChip)); // this is the version with chipInc stored once per new chip
175#ifdef _CHECK_INCREMENTES_
176 if (cl.getChipID() < prevChip) {
177 LOG(warning) << "Negative Chip increment " << cl.getChipID() << " -> " << prevChip;
178 }
179#endif
180 cc.chipMul.push_back(1); // this is the version with chipInc stored once per new chip
181 prevCol = cc.colInc[iclOut] = cl.getCol();
182 prevChip = cl.getChipID();
183 }
184 iclOut++;
185 }
186 irofOut++;
187 }
188 if (selectPatterns && pattIt != pattIt0) { // copy leftover patterns
189 cc.pattMap.insert(cc.pattMap.end(), pattIt0, pattIt);
190 pattIt0 = pattIt;
191 }
192 cc.header.nPatternBytes = cc.pattMap.size();
193 cc.header.nChips = cc.chipMul.size();
194}
195
197template <int N>
198void CTFCoder<N>::createCoders(const std::vector<char>& bufVec, o2::ctf::CTFCoderBase::OpType op)
199{
200 const auto ctf = CTF::getImage(bufVec.data());
201 CompressedClusters cc; // just to get member types
202#define MAKECODER(part, slot) createCoder(op, std::get<rans::RenormedDenseHistogram<typename decltype(part)::value_type>>(ctf.getDictionary<typename decltype(part)::value_type>(slot, mANSVersion)), int(slot))
203 // clang-format off
204 MAKECODER(cc.firstChipROF, CTF::BLCfirstChipROF);
205 MAKECODER(cc.bcIncROF, CTF::BLCbcIncROF );
206 MAKECODER(cc.orbitIncROF, CTF::BLCorbitIncROF );
207 MAKECODER(cc.nclusROF, CTF::BLCnclusROF );
208 //
209 MAKECODER(cc.chipInc, CTF::BLCchipInc );
210 MAKECODER(cc.chipMul, CTF::BLCchipMul );
211 MAKECODER(cc.row, CTF::BLCrow );
212 MAKECODER(cc.colInc, CTF::BLCcolInc );
213 MAKECODER(cc.pattID, CTF::BLCpattID );
214 MAKECODER(cc.pattMap, CTF::BLCpattMap );
215 // clang-format on
216}
217
219template <int N>
221{
222 size_t sz = 0;
223 // RS FIXME this is very crude estimate, instead, an empirical values should be used
224
225 sz += estimateBufferSize(static_cast<int>(CTF::BLCfirstChipROF), cc.firstChipROF);
226 sz += estimateBufferSize(static_cast<int>(CTF::BLCbcIncROF), cc.bcIncROF);
227 sz += estimateBufferSize(static_cast<int>(CTF::BLCorbitIncROF), cc.orbitIncROF);
228 sz += estimateBufferSize(static_cast<int>(CTF::BLCnclusROF), cc.nclusROF);
229 //
230 sz += estimateBufferSize(static_cast<int>(CTF::BLCchipInc), cc.chipInc);
231 sz += estimateBufferSize(static_cast<int>(CTF::BLCchipMul), cc.chipMul);
232 sz += estimateBufferSize(static_cast<int>(CTF::BLCrow), cc.row);
233 sz += estimateBufferSize(static_cast<int>(CTF::BLCcolInc), cc.colInc);
234 sz += estimateBufferSize(static_cast<int>(CTF::BLCpattID), cc.pattID);
235 sz += estimateBufferSize(static_cast<int>(CTF::BLCpattMap), cc.pattMap);
236 sz *= 2. / 3; // if needed, will be autoexpanded
237 LOG(debug) << "Estimated output size is " << sz << " bytes";
238 return sz;
239}
240
242template <int N>
243CompressedClusters CTFCoder<N>::decodeCompressedClusters(const CTF::base& ec, o2::ctf::CTFIOSize& iosize)
244{
245 CompressedClusters cc;
246 cc.header = ec.getHeader();
247 checkDictVersion(static_cast<const o2::ctf::CTFDictHeader&>(cc.header));
248 ec.print(getPrefix(), mVerbosity);
249#define DECODEITSMFT(part, slot) ec.decode(part, int(slot), mCoders[int(slot)])
250 // clang-format off
251 iosize += DECODEITSMFT(cc.firstChipROF, CTF::BLCfirstChipROF);
252 iosize += DECODEITSMFT(cc.bcIncROF, CTF::BLCbcIncROF);
253 iosize += DECODEITSMFT(cc.orbitIncROF, CTF::BLCorbitIncROF);
254 iosize += DECODEITSMFT(cc.nclusROF, CTF::BLCnclusROF);
255 //
256 iosize += DECODEITSMFT(cc.chipInc, CTF::BLCchipInc);
257 iosize += DECODEITSMFT(cc.chipMul, CTF::BLCchipMul);
258 iosize += DECODEITSMFT(cc.row, CTF::BLCrow);
259 iosize += DECODEITSMFT(cc.colInc, CTF::BLCcolInc);
260 iosize += DECODEITSMFT(cc.pattID, CTF::BLCpattID);
261 iosize += DECODEITSMFT(cc.pattMap, CTF::BLCpattMap);
262 // clang-format on
263 return cc;
264}
265
266template class CTFCoder<o2::detectors::DetID::ITS>;
267template class CTFCoder<o2::detectors::DetID::MFT>;
268} // namespace o2::itsmft
#define MAKECODER(part, slot)
std::string getName(const TDataMember *dm, int index, int size)
std::ostringstream debug
uint32_t op
class for entropy encoding/decoding of ITS/MFT compressed clusters data
#define DECODEITSMFT(part, slot)
static auto getImage(const void *newHead)
get const image of the container wrapper, with pointers in the image relocated to new head
EncodedBlocks< CTFHeader, N, uint32_t > base
void createCoders(const std::vector< char > &bufVec, o2::ctf::CTFCoderBase::OpType op) final
Definition CTFCoder.cxx:198
static void skipPattern(iterator &pattIt)
static constexpr unsigned short InvalidPatternID
Definition CompCluster.h:46
bool isGroup(int id) const
Definition LookUp.h:43
GLuint entry
Definition glcorearb.h:5735
Detector header base.
@ BLCnclusROF
Definition CTF.h:77
@ BLCfirstChipROF
Definition CTF.h:74
@ BLCbcIncROF
Definition CTF.h:75
@ BLCorbitIncROF
Definition CTF.h:76
Compressed but not yet entropy-encoded clusters.
Definition CTF.h:45
std::vector< o2::mch::ChannelCode > cc
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
coder decode(ctfImage, triggersD, clustersD)
o2::InteractionRecord ir(0, 0)
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))
LookUp clPattLookup
std::vector< unsigned char > pattVec
std::vector< CompClusterExt > cclusVec