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_FV0_CTFCODER_H
17#define O2_FV0_CTFCODER_H
18
19#include "DataFormatsFV0/CTF.h"
25
26class TTree;
27
28namespace o2
29{
30namespace fv0
31{
32
34{
35 public:
36 CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FV0) {}
37 ~CTFCoder() final = default;
38
40 template <typename VEC>
41 o2::ctf::CTFIOSize encode(VEC& buff, const gsl::span<const Digit>& digitVec, const gsl::span<const ChannelData>& channelVec);
42
44 template <typename VDIG, typename VCHAN>
45 o2::ctf::CTFIOSize decode(const CTF::base& ec, VDIG& digitVec, VCHAN& channelVec);
46
47 void createCoders(const std::vector<char>& bufVec, o2::ctf::CTFCoderBase::OpType op) final;
48
49 private:
51 template <int MAJOR_VERSION, int MINOR_VERSION>
52 void compress(CompressedDigits& cd, const gsl::span<const Digit>& digitVec, const gsl::span<const ChannelData>& channelVec);
53 size_t estimateCompressedSize(const CompressedDigits& cc);
54
56 template <int MAJOR_VERSION, int MINOR_VERSION, typename VDIG, typename VCHAN>
57 void decompress(const CompressedDigits& cd, VDIG& digitVec, VCHAN& channelVec);
58
59 void appendToTree(TTree& tree, CTF& ec);
60 void readFromTree(TTree& tree, int entry, std::vector<Digit>& digitVec, std::vector<ChannelData>& channelVec);
61 void assignDictVersion(o2::ctf::CTFDictHeader& h) const final;
62};
63
65template <typename VEC>
66o2::ctf::CTFIOSize CTFCoder::encode(VEC& buff, const gsl::span<const Digit>& digitVec, const gsl::span<const ChannelData>& channelVec)
67{
69 // what to do which each field: see o2::ctd::Metadata explanation
70 constexpr MD optField[CTF::getNBlocks()] = {
71 MD::EENCODE_OR_PACK, // BLC_bcInc
72 MD::EENCODE_OR_PACK, // BLC_orbitInc
73 MD::EENCODE_OR_PACK, // BLC_nChan
74 MD::EENCODE_OR_PACK, // BLC_idChan
75 MD::EENCODE_OR_PACK, // BLC_cfdTime
76 MD::EENCODE_OR_PACK, // BLC_qtcAmpl
77 // extra slot was added in the end
78 MD::EENCODE_OR_PACK, // BLC_trigger
79 MD::EENCODE_OR_PACK // BLC_qtcChain
80 };
84 compress<1, 0>(cd, digitVec, channelVec);
85 } else {
86 compress<1, 1>(cd, digitVec, channelVec);
87 }
88 } else {
89 compress<1, 1>(cd, digitVec, channelVec);
90 }
91 // book output size with some margin
92 auto szIni = estimateCompressedSize(cd);
93 buff.resize(szIni);
94
95 auto ec = CTF::create(buff);
96 using ECB = CTF::base;
97
98 ec->setHeader(cd.header);
99 assignDictVersion(static_cast<o2::ctf::CTFDictHeader&>(ec->getHeader()));
100 ec->setANSHeader(mANSVersion);
101 // at every encoding the buffer might be autoexpanded, so we don't work with fixed pointer ec
102 o2::ctf::CTFIOSize iosize;
103#define ENCODEFV0(part, slot, bits) CTF::get(buff.data())->encode(part, int(slot), bits, optField[int(slot)], &buff, mCoders[int(slot)], getMemMarginFactor());
104 // clang-format off
105 iosize += ENCODEFV0(cd.bcInc, CTF::BLC_bcInc, 0);
106 iosize += ENCODEFV0(cd.orbitInc, CTF::BLC_orbitInc, 0);
107 iosize += ENCODEFV0(cd.nChan, CTF::BLC_nChan, 0);
108 iosize += ENCODEFV0(cd.idChan , CTF::BLC_idChan, 0);
109 iosize += ENCODEFV0(cd.cfdTime, CTF::BLC_cfdTime, 0);
110 iosize += ENCODEFV0(cd.qtcAmpl, CTF::BLC_qtcAmpl, 0);
111 // extra slot was added in the end
112 iosize += ENCODEFV0(cd.trigger, CTF::BLC_trigger, 0);
113 iosize += ENCODEFV0(cd.qtcChain, CTF::BLC_qtcChain, 0);
114 // clang-format on
115 CTF::get(buff.data())->print(getPrefix(), mVerbosity);
116 finaliseCTFOutput<CTF>(buff);
117 iosize.rawIn = sizeof(Digit) * digitVec.size() + sizeof(ChannelData) * channelVec.size();
118 return iosize;
119}
120
122template <typename VDIG, typename VCHAN>
123o2::ctf::CTFIOSize CTFCoder::decode(const CTF::base& ec, VDIG& digitVec, VCHAN& channelVec)
124{
126 cd.header = ec.getHeader();
127 const auto& hd = static_cast<const o2::ctf::CTFDictHeader&>(cd.header);
130 o2::ctf::CTFIOSize iosize;
131#define DECODEFV0(part, slot) ec.decode(part, int(slot), mCoders[int(slot)])
132 // clang-format off
133 iosize += DECODEFV0(cd.bcInc, CTF::BLC_bcInc);
134 iosize += DECODEFV0(cd.orbitInc, CTF::BLC_orbitInc);
135 iosize += DECODEFV0(cd.nChan, CTF::BLC_nChan);
136 iosize += DECODEFV0(cd.idChan, CTF::BLC_idChan);
137 iosize += DECODEFV0(cd.cfdTime, CTF::BLC_cfdTime);
138 iosize += DECODEFV0(cd.qtcAmpl, CTF::BLC_qtcAmpl);
139 // extra slot was added in the end
140 iosize += DECODEFV0(cd.trigger, CTF::BLC_trigger);
141 iosize += DECODEFV0(cd.qtcChain, CTF::BLC_qtcChain);
142 // triggers and qtcChain were added later, in old data they are absent:
143 if (cd.trigger.empty()) {
144 cd.trigger.resize(cd.header.nTriggers);
145 }
146 if (cd.qtcChain.empty()) {
147 cd.qtcChain.resize(cd.cfdTime.size());
148 }
149 // clang-format on
150 //
151 if (hd.minorVersion == 0 && hd.majorVersion == 1) {
152 decompress<1, 0>(cd, digitVec, channelVec);
153 } else {
154 decompress<1, 1>(cd, digitVec, channelVec);
155 }
156 iosize.rawIn = sizeof(Digit) * digitVec.size() + sizeof(ChannelData) * channelVec.size();
157 return iosize;
158}
159
161template <int MAJOR_VERSION, int MINOR_VERSION, typename VDIG, typename VCHAN>
162void CTFCoder::decompress(const CompressedDigits& cd, VDIG& digitVec, VCHAN& channelVec)
163{
164 digitVec.clear();
165 channelVec.clear();
166 digitVec.reserve(cd.header.nTriggers);
167 channelVec.reserve(cd.idChan.size());
168
169 uint32_t firstEntry = 0, clCount = 0, chipCount = 0;
171
172 for (uint32_t idig = 0; idig < cd.header.nTriggers; idig++) {
173 // restore ROFRecord
174 if (cd.orbitInc[idig]) { // non-0 increment => new orbit
175 ir.bc = cd.bcInc[idig]; // bcInc has absolute meaning
176 ir.orbit += cd.orbitInc[idig];
177 } else {
178 ir.bc += cd.bcInc[idig];
179 }
180 const auto& params = FV0DigParam::Instance();
181 int triggerGate = params.mTime_trg_gate;
182 firstEntry = channelVec.size();
183 uint8_t chID = 0;
184 int8_t nChanA = 0, nChanC = 0;
185 int32_t amplA = 0, amplC = Triggers::DEFAULT_AMP;
186 int16_t timeA = 0, timeC = Triggers::DEFAULT_TIME;
187 for (uint8_t ic = 0; ic < cd.nChan[idig]; ic++) {
188 auto icc = channelVec.size();
189 if constexpr (MINOR_VERSION == 0 && MAJOR_VERSION == 1) {
190 // Old decoding procedure, mostly for Pilot Beam in October 2021
191 chID += cd.idChan[icc];
192 } else {
193 // New decoding procedure, w/o sorted ChID requriment
194 chID = cd.idChan[icc];
195 }
196 const auto& chan = channelVec.emplace_back(chID, cd.cfdTime[icc], cd.qtcAmpl[icc], cd.qtcChain[icc]);
197 if (std::abs(chan.CFDTime) < triggerGate) {
198 amplA += chan.QTCAmpl;
199 timeA += chan.CFDTime;
200 nChanA++;
201 }
202 }
203 if (nChanA) {
204 timeA /= nChanA;
205 amplA *= 0.125;
206 } else {
209 }
210 Triggers trig;
211 trig.setTriggers(cd.trigger[idig], nChanA, nChanC, amplA, amplC, timeA, timeC);
212 digitVec.emplace_back(firstEntry, cd.nChan[idig], ir, trig, idig);
213 }
214}
216template <int MAJOR_VERSION, int MINOR_VERSION>
217void CTFCoder::compress(CompressedDigits& cd, const gsl::span<const Digit>& digitVec, const gsl::span<const ChannelData>& channelVec)
218{
219 // convert digits/channel to their compressed version
220 cd.clear();
221 cd.header.det = mDet;
222 if (!digitVec.size()) {
223 return;
224 }
225 uint32_t firstDig = digitVec.size(), nDigSel = digitVec.size(), nChanSel = channelVec.size();
226 std::vector<bool> reject(digitVec.size());
227 if (mIRFrameSelector.isSet()) {
228 for (size_t id = 0; id < digitVec.size(); id++) {
229 if (mIRFrameSelector.check(digitVec[id].mIntRecord) < 0) {
230 reject[id] = true;
231 nDigSel--;
232 nChanSel -= digitVec[id].ref.getEntries();
233 } else if (firstDig == digitVec.size()) {
234 firstDig = id;
235 }
236 }
237 } else {
238 firstDig = 0;
239 }
240 if (nDigSel == 0) { // nothing is selected
241 return;
242 }
243 const auto& dig0 = digitVec[firstDig];
244 cd.header.nTriggers = nDigSel;
245 cd.header.firstOrbit = dig0.getOrbit();
246 cd.header.firstBC = dig0.getBC();
247 cd.header.triggerGate = FV0DigParam::Instance().mTime_trg_gate;
248
249 cd.trigger.resize(cd.header.nTriggers);
250 cd.bcInc.resize(cd.header.nTriggers);
251 cd.orbitInc.resize(cd.header.nTriggers);
252 cd.nChan.resize(cd.header.nTriggers);
253
254 cd.idChan.resize(nChanSel);
255 cd.qtcChain.resize(nChanSel);
256 cd.cfdTime.resize(nChanSel);
257 cd.qtcAmpl.resize(nChanSel);
258
259 uint16_t prevBC = cd.header.firstBC;
260 uint32_t prevOrbit = cd.header.firstOrbit;
261 uint32_t ccount = 0, dcount = 0;
262 for (uint32_t idig = 0; idig < digitVec.size(); idig++) {
263 if (reject[idig]) {
264 continue;
265 }
266 const auto& digit = digitVec[idig];
267 const auto chanels = digit.getBunchChannelData(channelVec); // we assume the channels are sorted
268
269 // fill trigger info
270 cd.trigger[dcount] = digit.getTriggers().getTriggersignals();
271 if (prevOrbit == digit.getOrbit()) {
272 cd.bcInc[dcount] = digit.getBC() - prevBC;
273 cd.orbitInc[dcount] = 0;
274 } else {
275 cd.bcInc[dcount] = digit.getBC();
276 cd.orbitInc[dcount] = digit.getOrbit() - prevOrbit;
277 }
278 prevBC = digit.getBC();
279 prevOrbit = digit.getOrbit();
280 // fill channels info
281 cd.nChan[dcount] = chanels.size();
282 if (!cd.nChan[dcount]) {
283 LOG(debug) << "Digits with no channels";
284 dcount++;
285 continue;
286 }
287 uint8_t prevChan = 0;
288 for (uint8_t ic = 0; ic < cd.nChan[dcount]; ic++) {
289 if constexpr (MINOR_VERSION == 0 && MAJOR_VERSION == 1) {
290 cd.idChan[ccount] = chanels[ic].ChId - prevChan; // Old method, lets keep it for a while
291 } else {
292 cd.idChan[ccount] = chanels[ic].ChId;
293 }
294 cd.qtcChain[ccount] = chanels[ic].ChainQTC;
295 cd.cfdTime[ccount] = chanels[ic].CFDTime;
296 cd.qtcAmpl[ccount] = chanels[ic].QTCAmpl;
297 prevChan = chanels[ic].ChId;
298 ccount++;
299 }
300 dcount++;
301 }
302}
303
304} // namespace fv0
305} // namespace o2
306
307#endif // O2_FV0_CTFCODER_H
Declarations for CTFCoderBase class (support of external dictionaries)
Class to describe fired triggered and/or stored channels for the BC and to refer to channel data.
Definitions for FV0 CTF data.
Container class to store time and charge values of single FV0 channel.
#define ENCODEFV0(part, slot, bits)
#define DECODEFV0(part, slot)
uint64_t nChanC
int64_t timeC
uint64_t nChanA
int64_t amplA
int64_t timeA
int64_t amplC
Configurable digitization parameters.
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
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
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:66
o2::ctf::CTFIOSize decode(const CTF::base &ec, VDIG &digitVec, VCHAN &channelVec)
entropy decode clusters from buffer with CTF
Definition CTFCoder.h:123
void createCoders(const std::vector< char > &bufVec, o2::ctf::CTFCoderBase::OpType op) final
Definition CTFCoder.cxx:52
~CTFCoder() final=default
CTFCoder(o2::ctf::CTFCoderBase::OpType op)
Definition CTFCoder.h:36
long check(o2::dataformats::IRFrame fr, size_t bwd=0, size_t fwd=0)
GLuint entry
Definition glcorearb.h:5735
GLenum const GLfloat * params
Definition glcorearb.h:272
GLuint id
Definition glcorearb.h:650
uint8_t itsSharedClusterMap uint8_t
o2::fit::Triggers Triggers
Definition Digit.h:35
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
uint16_t firstBC
1st orbit of TF
Definition CTF.h:32
uint32_t firstOrbit
number of triggers in TF
Definition CTF.h:31
wrapper for the Entropy-encoded clusters of the TF
Definition CTF.h:62
@ BLC_orbitInc
Definition CTF.h:67
@ BLC_bcInc
Definition CTF.h:66
@ BLC_idChan
Definition CTF.h:70
@ BLC_qtcAmpl
Definition CTF.h:72
@ BLC_cfdTime
Definition CTF.h:71
@ BLC_nChan
Definition CTF.h:68
@ BLC_trigger
Definition CTF.h:75
@ BLC_qtcChain
Definition CTF.h:76
Intermediate, compressed but not yet entropy-encoded digits.
Definition CTF.h:38
std::vector< uint8_t > qtcChain
Definition CTF.h:52
std::vector< int16_t > qtcAmpl
Definition CTF.h:51
std::vector< int16_t > bcInc
Definition CTF.h:44
std::vector< uint8_t > nChan
Definition CTF.h:46
std::vector< uint8_t > idChan
Definition CTF.h:49
std::vector< int16_t > cfdTime
Definition CTF.h:50
std::vector< uint8_t > trigger
Definition CTF.h:43
std::vector< int32_t > orbitInc
Definition CTF.h:45
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()))