Project
Loading...
Searching...
No Matches
CTFCoder.h
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
16#ifndef O2_FDD_CTFCODER_H
17#define O2_FDD_CTFCODER_H
18
19#include <algorithm>
20#include <iterator>
21#include <string>
22#include "FDDBase/Geometry.h"
23#include "DataFormatsFDD/CTF.h"
28
29class TTree;
30
31namespace o2
32{
33namespace fdd
34{
35
37{
38 public:
39 CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FDD) {}
40 ~CTFCoder() final = default;
41
43 template <typename VEC>
44 o2::ctf::CTFIOSize encode(VEC& buff, const gsl::span<const Digit>& digitVec, const gsl::span<const ChannelData>& channelVec);
45
47 template <typename VDIG, typename VCHAN>
48 o2::ctf::CTFIOSize decode(const CTF::base& ec, VDIG& digitVec, VCHAN& channelVec);
49
50 void createCoders(const std::vector<char>& bufVec, o2::ctf::CTFCoderBase::OpType op) final;
51
52 private:
54 template <int MAJOR_VERSION, int MINOR_VERSION>
55 void compress(CompressedDigits& cd, const gsl::span<const Digit>& digitVec, const gsl::span<const ChannelData>& channelVec);
56 size_t estimateCompressedSize(const CompressedDigits& cc);
57
59 template <int MAJOR_VERSION, int MINOR_VERSION, typename VDIG, typename VCHAN>
60 void decompress(const CompressedDigits& cd, VDIG& digitVec, VCHAN& channelVec);
61
62 void appendToTree(TTree& tree, CTF& ec);
63 void readFromTree(TTree& tree, int entry, std::vector<Digit>& digitVec, std::vector<ChannelData>& channelVec);
64 void assignDictVersion(o2::ctf::CTFDictHeader& h) const final;
65};
66
68template <typename VEC>
69o2::ctf::CTFIOSize CTFCoder::encode(VEC& buff, const gsl::span<const Digit>& digitVec, const gsl::span<const ChannelData>& channelVec)
70{
72 // what to do which each field: see o2::ctd::Metadata explanation
73 constexpr MD optField[CTF::getNBlocks()] = {
74 MD::EENCODE_OR_PACK, // BLC_trigger
75 MD::EENCODE_OR_PACK, // BLC_bcInc
76 MD::EENCODE_OR_PACK, // BLC_orbitInc
77 MD::EENCODE_OR_PACK, // BLC_nChan
78
79 MD::EENCODE_OR_PACK, // BLC_idChan
80 MD::EENCODE_OR_PACK, // BLC_time
81 MD::EENCODE_OR_PACK, // BLC_charge
82 MD::EENCODE_OR_PACK // BLC_feeBits
83 };
87 compress<1, 0>(cd, digitVec, channelVec);
88 } else {
89 compress<1, 1>(cd, digitVec, channelVec);
90 }
91 } else {
92 compress<1, 1>(cd, digitVec, channelVec);
93 }
94 // book output size with some margin
95 auto szIni = estimateCompressedSize(cd);
96 buff.resize(szIni);
97
98 auto ec = CTF::create(buff);
99 using ECB = CTF::base;
100
101 ec->setHeader(cd.header);
102 assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader()));
103
104 ec->setANSHeader(mANSVersion);
105 // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec
106 o2::ctf::CTFIOSize iosize;
107#define ENCODEFDD(part, slot, bits) CTF::get(buff.data())->encode(part, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)], getMemMarginFactor());
108 // clang-format off
109 iosize += ENCODEFDD(cd.trigger, CTF::BLC_trigger, 0);
110 iosize += ENCODEFDD(cd.bcInc, CTF::BLC_bcInc, 0);
111 iosize += ENCODEFDD(cd.orbitInc, CTF::BLC_orbitInc, 0);
112 iosize += ENCODEFDD(cd.nChan, CTF::BLC_nChan, 0);
113
114 iosize += ENCODEFDD(cd.idChan , CTF::BLC_idChan, 0);
115 iosize += ENCODEFDD(cd.time, CTF::BLC_time, 0);
116 iosize += ENCODEFDD(cd.charge, CTF::BLC_charge, 0);
117 iosize += ENCODEFDD(cd.feeBits, CTF::BLC_feeBits, 0);
118 // clang-format on
119 CTF::get(buff.data())->print(getPrefix(), mVerbosity);
120 finaliseCTFOutput<CTF>(buff);
121 iosize.rawIn = sizeof(Digit) * digitVec.size() + sizeof(ChannelData) * channelVec.size();
122 return iosize;
123}
124
126template <typename VDIG, typename VCHAN>
127o2::ctf::CTFIOSize CTFCoder::decode(const CTF::base& ec, VDIG& digitVec, VCHAN& channelVec)
128{
130 cd.header = ec.getHeader();
131 const auto& hd = static_cast<const o2::ctf::CTFDictHeader&>(cd.header);
134 o2::ctf::CTFIOSize iosize;
135#define DECODEFDD(part, slot) ec.decode(part, int(slot), mCoders[int(slot)])
136 // clang-format off
137 iosize += DECODEFDD(cd.trigger, CTF::BLC_trigger);
138 iosize += DECODEFDD(cd.bcInc, CTF::BLC_bcInc);
139 iosize += DECODEFDD(cd.orbitInc, CTF::BLC_orbitInc);
140 iosize += DECODEFDD(cd.nChan, CTF::BLC_nChan);
141
142 iosize += DECODEFDD(cd.idChan, CTF::BLC_idChan);
143 iosize += DECODEFDD(cd.time, CTF::BLC_time);
144 iosize += DECODEFDD(cd.charge, CTF::BLC_charge);
145 iosize += DECODEFDD(cd.feeBits, CTF::BLC_feeBits);
146 // clang-format on
147 //
148 if (hd.minorVersion == 0 && hd.majorVersion == 1) {
149 decompress<1, 0>(cd, digitVec, channelVec);
150 } else {
151 decompress<1, 1>(cd, digitVec, channelVec);
152 }
153 iosize.rawIn = sizeof(Digit) * digitVec.size() + sizeof(ChannelData) * channelVec.size();
154 return iosize;
155}
156
158template <int MAJOR_VERSION, int MINOR_VERSION, typename VDIG, typename VCHAN>
159void CTFCoder::decompress(const CompressedDigits& cd, VDIG& digitVec, VCHAN& channelVec)
160{
161 digitVec.clear();
162 channelVec.clear();
163 digitVec.reserve(cd.header.nTriggers);
164 channelVec.reserve(cd.idChan.size());
165
166 uint32_t firstEntry = 0, clCount = 0, chipCount = 0;
168
169 for (uint32_t idig = 0; idig < cd.header.nTriggers; idig++) {
170 // restore ROFRecord
171 if (cd.orbitInc[idig]) { // non-0 increment => new orbit
172 ir.bc = cd.bcInc[idig]; // bcInc has absolute meaning
173 ir.orbit += cd.orbitInc[idig];
174 } else {
175 ir.bc += cd.bcInc[idig];
176 }
177 firstEntry = channelVec.size();
178 uint8_t chID = 0;
179 int8_t nChanA = 0, nChanC = 0;
180 int32_t amplA = 0, amplC = 0;
181 int16_t timeA = 0, timeC = 0;
182 for (uint8_t ic = 0; ic < cd.nChan[idig]; ic++) {
183 auto icc = channelVec.size();
184 if constexpr (MINOR_VERSION == 0 && MAJOR_VERSION == 1) {
185 // Old decoding procedure, mostly for Pilot Beam in October 2021
186 chID += cd.idChan[icc];
187 } else {
188 // New decoding procedure, w/o sorted ChID requriment
189 chID = cd.idChan[icc];
190 }
191 const auto& chan = channelVec.emplace_back(chID, cd.time[icc], cd.charge[icc], cd.feeBits[icc]);
192 // rebuild digit
193 if (chan.mPMNumber > 7) { // A side
194 amplA += chan.mChargeADC;
195 timeA += chan.mTime;
196 nChanA++;
197
198 } else {
199 amplC += chan.mChargeADC;
200 timeC += chan.mTime;
201 nChanC++;
202 }
203 }
204 if (nChanA) {
205 timeA /= nChanA;
206 amplA *= 0.125;
207 } else {
210 }
211 if (nChanC) {
212 timeC /= nChanC;
213 amplC *= 0.125;
214 } else {
217 }
218 Triggers trig;
219 trig.setTriggers(cd.trigger[idig], nChanA, nChanC, amplA, amplC, timeA, timeC);
220 digitVec.emplace_back(firstEntry, cd.nChan[idig], ir, trig);
221 }
222}
223
225template <int MAJOR_VERSION, int MINOR_VERSION>
226void CTFCoder::compress(CompressedDigits& cd, const gsl::span<const Digit>& digitVec, const gsl::span<const ChannelData>& channelVec)
227{
228 // convert digits/channel to their compressed version
229 cd.clear();
230 cd.header.det = mDet;
231 if (!digitVec.size()) {
232 return;
233 }
234 uint32_t firstDig = digitVec.size(), nDigSel = digitVec.size(), nChanSel = channelVec.size();
235 std::vector<bool> reject(digitVec.size());
236 if (mIRFrameSelector.isSet()) {
237 for (size_t id = 0; id < digitVec.size(); id++) {
238 if (mIRFrameSelector.check(digitVec[id].mIntRecord) < 0) {
239 reject[id] = true;
240 nDigSel--;
241 nChanSel -= digitVec[id].ref.getEntries();
242 } else if (firstDig == digitVec.size()) {
243 firstDig = id;
244 }
245 }
246 } else {
247 firstDig = 0;
248 }
249 if (nDigSel == 0) { // nothing is selected
250 return;
251 }
252 const auto& dig0 = digitVec[firstDig];
253 cd.header.nTriggers = nDigSel;
254 cd.header.firstOrbit = dig0.mIntRecord.orbit;
255 cd.header.firstBC = dig0.mIntRecord.bc;
256
257 cd.trigger.resize(cd.header.nTriggers);
258 cd.bcInc.resize(cd.header.nTriggers);
259 cd.orbitInc.resize(cd.header.nTriggers);
260 cd.nChan.resize(cd.header.nTriggers);
261
262 cd.idChan.resize(nChanSel);
263 cd.time.resize(nChanSel);
264 cd.charge.resize(nChanSel);
265 cd.feeBits.resize(nChanSel);
266
267 uint16_t prevBC = cd.header.firstBC;
268 uint32_t prevOrbit = cd.header.firstOrbit;
269 uint32_t ccount = 0, dcount = 0;
270 for (uint32_t idig = 0; idig < digitVec.size(); idig++) {
271 if (reject[idig]) {
272 continue;
273 }
274 const auto& digit = digitVec[idig];
275 const auto chanels = digit.getBunchChannelData(channelVec); // we assume the channels are sorted
276
277 // fill trigger info
278 cd.trigger[dcount] = digit.mTriggers.getTriggersignals();
279 if (prevOrbit == digit.mIntRecord.orbit) {
280 cd.bcInc[dcount] = digit.mIntRecord.bc - prevBC;
281 cd.orbitInc[dcount] = 0;
282 } else {
283 cd.bcInc[dcount] = digit.mIntRecord.bc;
284 cd.orbitInc[dcount] = digit.mIntRecord.orbit - prevOrbit;
285 }
286 prevBC = digit.mIntRecord.bc;
287 prevOrbit = digit.mIntRecord.orbit;
288 // fill channels info
289 cd.nChan[dcount] = chanels.size();
290 if (!cd.nChan[dcount]) {
291 LOG(debug) << "Digits with no channels";
292 dcount++;
293 continue;
294 }
295 uint8_t prevChan = 0;
296 for (uint8_t ic = 0; ic < cd.nChan[dcount]; ic++) {
297 if constexpr (MINOR_VERSION == 0 && MAJOR_VERSION == 1) {
298 cd.idChan[ccount] = chanels[ic].mPMNumber - prevChan; // Old method, lets keep it for a while
299 } else {
300 cd.idChan[ccount] = chanels[ic].mPMNumber;
301 }
302 cd.time[ccount] = chanels[ic].mTime; // make sure it fits to short!!!
303 cd.charge[ccount] = chanels[ic].mChargeADC; // make sure we really need short!!!
304 cd.feeBits[ccount] = chanels[ic].mFEEBits;
305 prevChan = chanels[ic].mPMNumber;
306 ccount++;
307 }
308 dcount++;
309 }
310}
311
312} // namespace fdd
313} // namespace o2
314
315#endif // O2_FDD_CTFCODER_H
Declarations for CTFCoderBase class (support of external dictionaries)
Base definition of FIT-FDD geometry.
Definitions for FDD CTF data.
Container class to store values of single FDD channel.
#define DECODEFDD(part, slot)
#define ENCODEFDD(part, slot, bits)
uint64_t nChanC
int64_t timeC
uint64_t nChanA
int64_t amplA
int64_t timeA
int64_t amplC
uint32_t op
std::ostringstream debug
Class for time synchronization of RawReader instances.
void checkDictVersion(const CTFDictHeader &h) const
ctf::ANSHeader mANSVersion
CTFDictHeader mExtHeader
std::string getPrefix() const
o2::utils::IRFrameSelector mIRFrameSelector
<<======================== Auxiliary classes =======================<<
static auto get(void *head)
cast arbitrary buffer head to container class. Head is supposed to respect the alignment
const H & getHeader() const
void print(const std::string &prefix="", int verbosity=1) const
print itself
EncodedBlocks< CTFHeader, N, uint32_t > base
static auto create(void *head, size_t sz)
create container from arbitrary buffer of predefined size (in bytes!!!). Head is supposed to respect ...
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:58
CTFCoder(o2::ctf::CTFCoderBase::OpType op)
Definition CTFCoder.h:39
o2::ctf::CTFIOSize decode(const CTF::base &ec, VDIG &digitVec, VCHAN &channelVec)
entropy decode clusters from buffer with CTF
Definition CTFCoder.h:127
o2::ctf::CTFIOSize encode(VEC &buff, const gsl::span< const Digit > &digitVec, const gsl::span< const ChannelData > &channelVec)
entropy-encode digits to buffer with CTF
Definition CTFCoder.h:69
void createCoders(const std::vector< char > &bufVec, o2::ctf::CTFCoderBase::OpType op) final
Definition CTFCoder.cxx:50
~CTFCoder() final=default
static const int16_t DEFAULT_AMP
Definition Triggers.h:51
static const int16_t DEFAULT_TIME
Definition Triggers.h:50
void setTriggers(uint8_t trgsig, uint8_t chanA, uint8_t chanC, int32_t aamplA, int32_t aamplC, int16_t atimeA, int16_t atimeC)
Definition Triggers.h:97
long check(o2::dataformats::IRFrame fr, size_t bwd=0, size_t fwd=0)
GLuint entry
Definition glcorearb.h:5735
GLuint id
Definition glcorearb.h:650
uint8_t itsSharedClusterMap uint8_t
o2::fit::Triggers Triggers
Definition Digit.h:31
struct o2::upgrades_utils::@459 fdd
Collision labels.
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
Detector header base.
bool isValidDictTimeStamp() const
uint32_t nTriggers
Definition CTF.h:30
uint32_t firstOrbit
number of triggers in TF
Definition CTF.h:31
uint16_t firstBC
1st orbit of TF
Definition CTF.h:32
wrapper for the Entropy-encoded clusters of the TF
Definition CTF.h:62
@ BLC_orbitInc
Definition CTF.h:68
@ BLC_nChan
Definition CTF.h:69
@ BLC_bcInc
Definition CTF.h:67
@ BLC_charge
Definition CTF.h:73
@ BLC_trigger
Definition CTF.h:66
@ BLC_idChan
Definition CTF.h:71
@ BLC_time
Definition CTF.h:72
@ BLC_feeBits
Definition CTF.h:74
Intermediate, compressed but not yet entropy-encoded digits.
Definition CTF.h:38
std::vector< int32_t > orbitInc
Definition CTF.h:45
std::vector< uint8_t > feeBits
Definition CTF.h:52
std::vector< int16_t > time
Definition CTF.h:50
std::vector< uint8_t > trigger
Definition CTF.h:43
std::vector< int16_t > charge
Definition CTF.h:51
std::vector< int16_t > bcInc
Definition CTF.h:44
std::vector< uint8_t > idChan
Definition CTF.h:49
std::vector< uint8_t > nChan
Definition CTF.h:46
std::vector< o2::mch::ChannelCode > cc
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))