Project
Loading...
Searching...
No Matches
CTFCoderBase.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 _ALICEO2_CTFCODER_BASE_H_
17#define _ALICEO2_CTFCODER_BASE_H_
18
19#include <memory>
20#include <TFile.h>
21#include <TTree.h>
30#include "rANS/factory.h"
31#include "rANS/compat.h"
32#include "rANS/histogram.h"
33#include <filesystem>
37#include <any>
38
39namespace o2
40{
41namespace framework
42{
43class ProcessingContext;
44}
45namespace ctf
46{
47
50
52
54{
55
56 public:
57 enum class OpType : int { Encoder,
58 Decoder };
59
60 CTFCoderBase() = delete;
61 CTFCoderBase(int n, DetID det, float memFactor = 1.f) : mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f) {}
62 CTFCoderBase(OpType op, int n, DetID det, float memFactor = 1.f) : mOpType(op), mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f) {}
63 virtual ~CTFCoderBase() = default;
64
65 virtual void createCoders(const std::vector<char>& bufVec, o2::ctf::CTFCoderBase::OpType op) = 0;
66
67 // detector coder need to redefine this method if uses no default version, see comment in the cxx file
68 virtual void assignDictVersion(CTFDictHeader& h) const;
69
70 template <typename SPAN>
76
77 template <typename CTF>
78 std::vector<char> readDictionaryFromFile(const std::string& dictPath, bool mayFail = false);
79
80 template <typename CTF>
81 void createCodersFromFile(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op, bool mayFail = false);
82
83 template <typename S>
84 void createCoder(OpType op, const o2::rans::RenormedDenseHistogram<S>& renormedHistogram, int slot)
85 {
86 LOG_IF(warning, renormedHistogram.empty()) << fmt::format("Empty dictionary provided for slot {}, {} will assume literal symbols only", slot, (op == OpType::Encoder ? "encoding" : "decoding"));
87
89 switch (op) {
90 case OpType::Encoder:
91 mCoders[slot] = std::make_any<rans::compat::encoder_type<S>>(rans::compat::makeEncoder::fromRenormed(renormedHistogram));
92 break;
93 case OpType::Decoder:
94 mCoders[slot] = std::make_any<rans::compat::decoder_type<S>>(rans::compat::makeDecoder::fromRenormed(renormedHistogram));
95 break;
96 }
97 } else if (mANSVersion == ANSVersion1) {
98 switch (op) {
99 case OpType::Encoder:
100 mCoders[slot] = std::make_any<rans::denseEncoder_type<S>>(rans::makeDenseEncoder<>::fromRenormed(renormedHistogram));
101 break;
102 case OpType::Decoder:
103 mCoders[slot] = std::make_any<rans::defaultDecoder_type<S>>(rans::makeDecoder<>::fromRenormed(renormedHistogram));
104 break;
105 }
106 } else {
107 throw std::runtime_error("unsupported ANS version");
108 }
109 }
110
111 void clear()
112 {
113 for (auto c : mCoders) {
114 c.reset();
115 }
116 }
117
118 void setMemMarginFactor(float v) { mMemMarginFactor = v > 1.f ? v : 1.f; }
119 float getMemMarginFactor() const { return mMemMarginFactor; }
120
121 void setVerbosity(int v) { mVerbosity = v; }
122 int getVerbosity() const { return mVerbosity; }
123
124 const CTFDictHeader& getExtDictHeader() const { return mExtHeader; }
125
126 template <typename T>
127 static bool readFromTree(TTree& tree, const std::string brname, T& dest, int ev = 0);
128
129 // these are the helper methods for the parent encoding/decoding task
130 template <typename CTF>
132
133 template <typename CTF, typename BUF>
134 size_t finaliseCTFOutput(BUF& buffer);
135
136 template <typename CTF>
137 bool finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj);
138
139 void updateTimeDependentParams(o2::framework::ProcessingContext& pc, bool askTree = false);
140
144 long getIRFrameSelShift() const { return mIRFrameSelShift; }
145
146 inline const ctf::ANSHeader& getANSVersion() const noexcept { return mANSVersion; };
147 inline ctf::ANSHeader& getANSVersion() { return const_cast<ctf::ANSHeader&>(const_cast<const CTFCoderBase&>(*this).getANSVersion()); };
148 inline void setANSVersion(const ctf::ANSHeader& ansVersion) noexcept { mANSVersion = ansVersion; };
149 void setBCShift(int64_t n) { mBCShift = n; }
150 void setFirstTFOrbit(uint32_t n) { mFirstTFOrbit = n; }
151 auto getBCShift() const { return mBCShift; }
152 auto getFirstTFOrbit() const { return mFirstTFOrbit; }
153 void setSupportBCShifts(bool v = true) { mSupportBCShifts = v; }
154 bool getSupportBCShifts() const { return mSupportBCShifts; }
155
156 void setDictBinding(const std::string& s) { mDictBinding = s; }
157 const std::string& getDictBinding() const { return mDictBinding; }
158
159 void setTrigOffsBinding(const std::string& s) { mTrigOffsBinding = s; }
160 const std::string& getTrigOffsBinding() const { return mTrigOffsBinding; }
161
162 const DetID getDet() const { return mDet; }
163
164 protected:
165 void reportIRFrames();
166 std::string getPrefix() const { return o2::utils::Str::concat_string(mDet.getName(), "_CTF: "); }
167 void checkDictVersion(const CTFDictHeader& h) const;
168 bool isTreeDictionary(const void* buff) const;
169 bool canApplyBCShift(const o2::InteractionRecord& ir, long shift) const
170 {
171 auto diff = ir.differenceInBC({0, mFirstTFOrbit});
172 return diff < 0 ? true : diff >= shift;
173 }
175
176 template <typename source_IT>
177 [[nodiscard]] size_t estimateBufferSize(size_t slot, source_IT samplesBegin, source_IT samplesEnd);
178
179 template <typename source_T>
180 size_t estimateBufferSize(size_t slot, size_t nSamples);
181
182 template <typename source_T>
183 [[nodiscard]] size_t estimateBufferSize(size_t slot, const std::vector<source_T>& samples)
184 {
185 return estimateBufferSize(slot, samples.begin(), samples.end());
186 }
187
188 template <typename CTF>
189 std::vector<char> loadDictionaryFromTree(TTree* tree);
190 std::vector<std::any> mCoders; // encoders/decoders
192 std::string mDictBinding{"ctfdict"};
193 std::string mTrigOffsBinding{"trigoffset"};
194 CTFDictHeader mExtHeader; // external dictionary header
195 o2::utils::IRFrameSelector mIRFrameSelector; // optional IR frames selector
196 float mMemMarginFactor = 1.0f; // factor for memory allocation in EncodedBlocks
198 bool mSupportBCShifts{false};
199 OpType mOpType; // Encoder or Decoder
200 ctf::ANSHeader mANSVersion{ctf::ANSVersionCompat}; // Version of the ANSEncoder/Decoder
201 int64_t mBCShift = 0; // shift to apply to decoded IR (i.e. CTP offset if was not corrected on raw data decoding level)
202 uint32_t mFirstTFOrbit = 0;
203 size_t mIRFrameSelMarginBwd = 0; // margin in BC to add to the IRFrame lower boundary when selection is requested
204 size_t mIRFrameSelMarginFwd = 0; // margin in BC to add to the IRFrame upper boundary when selection is requested
205 long mIRFrameSelShift = 0; // Global shift of the IRFrames, to account for e.g. detector latency
206 int mVerbosity = 0;
207};
208
210template <typename T>
211bool CTFCoderBase::readFromTree(TTree& tree, const std::string brname, T& dest, int ev)
212{
213 auto* br = tree.GetBranch(brname.c_str());
214 if (br && br->GetEntries() > ev) {
215 auto* ptr = &dest;
216 br->SetAddress(&ptr);
217 br->GetEntry(ev);
218 br->ResetAddress();
219 return true;
220 }
221 return false;
222}
223
225template <typename CTF>
226void CTFCoderBase::createCodersFromFile(const std::string& dictPath, o2::ctf::CTFCoderBase::OpType op, bool mayFail)
227{
228 auto buff = readDictionaryFromFile<CTF>(dictPath, mayFail);
229 if (!buff.size()) {
230 if (mayFail) {
231 return;
232 }
233 throw std::runtime_error("Failed to create CTF dictionaty");
234 }
235 createCoders(buff, op);
236}
237
239template <typename CTF>
241{
242 std::vector<char> bufVec;
243 CTFHeader ctfHeader;
244 if (readFromTree(*tree, "CTFHeader", ctfHeader) && ctfHeader.detectors[mDet]) {
245 CTF::readFromTree(bufVec, *tree, mDet.getName());
246 }
247 return bufVec;
248}
249
251template <typename CTF>
252std::vector<char> CTFCoderBase::readDictionaryFromFile(const std::string& dictPath, bool mayFail)
253{
254 std::vector<char> bufVec;
255 std::unique_ptr<TFile> fileDict;
256 if (std::filesystem::exists(dictPath)) {
257 fileDict.reset(TFile::Open(dictPath.c_str()));
258 }
259 if (!fileDict || fileDict->IsZombie()) {
260 std::string errstr = fmt::format("CTF dictionary file {} for detector {} is absent", dictPath, mDet.getName());
261 if (mayFail) {
262 LOGP(info, "{}, will assume dictionary stored in CTF", errstr);
263 } else {
264 throw std::runtime_error(errstr);
265 }
266 return bufVec;
267 }
268 std::unique_ptr<TTree> tree;
269 std::unique_ptr<std::vector<char>> bv((std::vector<char>*)fileDict->GetObjectChecked(o2::base::NameConf::CCDBOBJECT.data(), "std::vector<char>"));
270 tree.reset((TTree*)fileDict->GetObjectChecked(o2::base::NameConf::CTFDICT.data(), "TTree"));
271 if (!tree) {
272 tree.reset((TTree*)fileDict->GetObjectChecked(o2::base::NameConf::CCDBOBJECT.data(), "TTree"));
273 }
274 if (tree) {
275 auto v = loadDictionaryFromTree<CTF>(tree.get());
276 bufVec.swap(v);
277 } else if (bv) {
278 bufVec.swap(*bv);
279 if (bufVec.size()) {
280 auto dictHeader = static_cast<const o2::ctf::CTFDictHeader&>(CTF::get(bufVec.data())->getHeader());
281 if (dictHeader.det != mDet) {
282 bufVec.clear();
283 LOGP(error, "{} contains dictionary vector for {}, expected {}", dictPath, dictHeader.det.getName(), mDet.getName());
284 }
285 }
286 }
287 if (bufVec.size()) {
288 mExtHeader = static_cast<CTFDictHeader&>(CTF::get(bufVec.data())->getHeader());
289 LOGP(debug, "Found {} in {}", mExtHeader.asString(), dictPath);
290 } else {
291 if (mayFail) {
292 LOGP(info, "{}, will assume dictionary stored in CTF", mDet.getName());
293 } else {
294 LOGP(fatal, "CTF dictionary file for detector {} is empty", mDet.getName());
295 }
296 }
297 return bufVec;
298}
299
301template <typename CTF>
303{
304 if (ic.options().hasOption("mem-factor")) {
305 setMemMarginFactor(ic.options().get<float>("mem-factor"));
306 }
307 if (ic.options().hasOption("irframe-margin-bwd")) {
308 mIRFrameSelMarginBwd = ic.options().get<uint32_t>("irframe-margin-bwd");
309 }
310 if (ic.options().hasOption("irframe-margin-fwd")) {
311 mIRFrameSelMarginFwd = ic.options().get<uint32_t>("irframe-margin-fwd");
312 }
313 if (ic.options().hasOption("irframe-shift")) {
314 mIRFrameSelShift = (long)ic.options().get<int32_t>("irframe-shift");
315 }
316 if (ic.options().hasOption("ans-version")) {
317 if (ic.options().isSet("ans-version")) {
318 const std::string ansVersionString = ic.options().get<std::string>("ans-version");
319 if (!ansVersionString.empty()) {
320 mANSVersion = ansVersionFromString(ansVersionString);
321 LOGP(info, "parsing ansVersionString {} into {}", ansVersionString, static_cast<std::string>(mANSVersion));
323 throw std::invalid_argument(fmt::format("Invalid ANS Version {}", ansVersionString));
324 }
325 }
326 }
327 }
328 auto dict = ic.options().get<std::string>("ctf-dict");
329 if (dict.empty() || dict == "ccdb") { // load from CCDB
330 mLoadDictFromCCDB = true;
331 } else {
332 if (dict != "none") { // none means per-CTF dictionary will created on the fly
333 createCodersFromFile<CTF>(dict, mOpType);
334 LOGP(info, "Loaded {} from {}", mExtHeader.asString(), dict);
335 } else {
336 LOGP(info, "Internal per-TF CTF Dict will be created");
337 }
338 mLoadDictFromCCDB = false; // don't try to load from CCDB
339 }
340}
341
343template <typename CTF, typename BUF>
345{
346 auto eeb = CTF::get(buffer.data()); // cast to container pointer
347 eeb->compactify(); // eliminate unnecessary padding
348 buffer.resize(eeb->size()); // shrink buffer to strictly necessary size
349 // eeb->print();
350 return eeb->size();
351}
352
354template <typename CTF>
356{
357 bool match = false;
358 if (mLoadDictFromCCDB && (match = (matcher == o2::framework::ConcreteDataMatcher(mDet.getDataOrigin(), "CTFDICT", 0)))) {
359 const auto* dict = (std::vector<char>*)obj;
360 if (dict->empty()) {
361 LOGP(info, "Empty dictionary object fetched from CCDB, internal per-TF CTF Dict will be created");
362 } else {
363 std::vector<char> bufVec;
364 if (isTreeDictionary(obj)) {
365 auto v = loadDictionaryFromTree<CTF>(reinterpret_cast<TTree*>(obj));
366 bufVec.swap(v);
367 dict = &bufVec;
368 }
369 createCoders(*dict, mOpType);
370 mExtHeader = static_cast<const CTFDictHeader&>(CTF::get(dict->data())->getHeader());
371 LOGP(info, "Loaded {} from CCDB", mExtHeader.asString());
372 }
373 mLoadDictFromCCDB = false; // we read the dictionary at most once!
374 } else if ((match = (matcher == o2::framework::ConcreteDataMatcher("CTP", "Trig_Offset", 0)))) {
375 const auto& trigOffsParam = o2::ctp::TriggerOffsetsParam::Instance();
376 auto bcshift = trigOffsParam.customOffset[mDet.getID()];
377 if (bcshift) {
378 if (mSupportBCShifts) {
379 LOGP(info, "Decoded IRs will be augmented by {} BCs, discarded if become prior to 1st orbit", bcshift);
380 setBCShift(-bcshift); // offset is subtracted
381 } else {
382 LOGP(alarm, "Decoding with {} BCs shift is requested, but the {} does not support this operation, ignoring request", bcshift, mDet.getName());
383 }
384 }
385 }
386 return match;
387}
388
389template <typename IT>
390[[nodiscard]] inline size_t CTFCoderBase::estimateBufferSize(size_t slot, IT samplesBegin, IT samplesEnd)
391{
392 using source_type = typename std::iterator_traits<IT>::value_type;
393 const size_t nSamples = std::distance(samplesBegin, samplesEnd);
394 return estimateBufferSize<source_type>(slot, nSamples);
395};
396
397template <typename source_T>
398[[nodiscard]] inline size_t CTFCoderBase::estimateBufferSize(size_t slot, size_t nSamples)
399{
400
401 std::any& coder = mCoders[slot];
402 if (coder.has_value()) {
403 const size_t alphabetRangeBits = [this, &coder]() {
405 const auto& encoder = std::any_cast<const rans::compat::encoder_type<source_T>&>(coder);
406 auto view = rans::trim(rans::makeHistogramView(encoder.getSymbolTable()));
407 return rans::utils::getRangeBits(view.getMin(), view.getMax());
408 } else if (mANSVersion == ANSVersion1) {
409 const auto& encoder = std::any_cast<const rans::denseEncoder_type<source_T>&>(coder);
410 auto view = rans::trim(rans::makeHistogramView(encoder.getSymbolTable()));
411 return rans::utils::getRangeBits(view.getMin(), view.getMax());
412 } else {
413 throw std::runtime_error("unsupported ANS version");
414 }
415 }();
416 return rans::compat::calculateMaxBufferSizeB(nSamples, alphabetRangeBits);
417 } else {
418 return nSamples * sizeof(source_T);
419 }
420};
421
422} // namespace ctf
423} // namespace o2
424
425#endif
representation of ANS Version number in a comparable way
Header: timestamps and format version for detector CTF dictionary.
Header for CTF collection.
uint32_t op
Class to check if give InteractionRecord or IRFrame is selected by the external IRFrame vector.
Definition of the Names Generator class.
uint32_t c
Definition RawData.h:2
TBranch * ptr
std::ostringstream debug
uint32_t source_type
Class for time synchronization of RawReader instances.
static constexpr std::string_view CCDBOBJECT
Definition NameConf.h:66
static constexpr std::string_view CTFDICT
Definition NameConf.h:92
size_t getIRFrameSelMarginBwd() const
ctf::ANSHeader & getANSVersion()
void createCoder(OpType op, const o2::rans::RenormedDenseHistogram< S > &renormedHistogram, int slot)
static bool readFromTree(TTree &tree, const std::string brname, T &dest, int ev=0)
void setTrigOffsBinding(const std::string &s)
void setSupportBCShifts(bool v=true)
void updateTimeDependentParams(o2::framework::ProcessingContext &pc, bool askTree=false)
long getIRFrameSelShift() const
void setDictBinding(const std::string &s)
void init(o2::framework::InitContext &ic)
const DetID getDet() const
CTFCoderBase(OpType op, int n, DetID det, float memFactor=1.f)
void setMemMarginFactor(float v)
void setANSVersion(const ctf::ANSHeader &ansVersion) noexcept
const ctf::ANSHeader & getANSVersion() const noexcept
std::vector< char > readDictionaryFromFile(const std::string &dictPath, bool mayFail=false)
void setSelectedIRFrames(const SPAN &sp)
bool canApplyBCShift(const o2::InteractionRecord &ir) const
bool getSupportBCShifts() const
void setBCShift(int64_t n)
const std::string & getDictBinding() const
float getMemMarginFactor() const
std::vector< std::any > mCoders
o2::utils::IRFrameSelector & getIRFramesSelector()
std::string mTrigOffsBinding
const CTFDictHeader & getExtDictHeader() const
std::vector< char > loadDictionaryFromTree(TTree *tree)
bool isTreeDictionary(const void *buff) const
bool finaliseCCDB(o2::framework::ConcreteDataMatcher &matcher, void *obj)
void checkDictVersion(const CTFDictHeader &h) const
const std::string & getTrigOffsBinding() const
ctf::ANSHeader mANSVersion
CTFDictHeader mExtHeader
size_t getIRFrameSelMarginFwd() const
std::string getPrefix() const
auto getBCShift() const
virtual void createCoders(const std::vector< char > &bufVec, o2::ctf::CTFCoderBase::OpType op)=0
auto getFirstTFOrbit() const
size_t finaliseCTFOutput(BUF &buffer)
size_t estimateBufferSize(size_t slot, source_IT samplesBegin, source_IT samplesEnd)
void createCodersFromFile(const std::string &dictPath, o2::ctf::CTFCoderBase::OpType op, bool mayFail=false)
o2::utils::IRFrameSelector mIRFrameSelector
CTFCoderBase(int n, DetID det, float memFactor=1.f)
void setFirstTFOrbit(uint32_t n)
virtual ~CTFCoderBase()=default
virtual void assignDictVersion(CTFDictHeader &h) const
size_t estimateBufferSize(size_t slot, const std::vector< source_T > &samples)
bool canApplyBCShift(const o2::InteractionRecord &ir, long shift) const
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:58
static constexpr const char * getName(ID id)
names of defined detectors
Definition DetID.h:145
static constexpr o2h::DataOrigin getDataOrigin(ID id)
Definition DetID.h:147
bool hasOption(const char *key) const
ConfigParamRegistry const & options()
Definition InitContext.h:33
static constexpr decltype(auto) fromRenormed(const RenormedHistogramConcept< container_T > &renormed)
Definition compat.h:221
static constexpr decltype(auto) fromRenormed(const RenormedHistogramConcept< container_T > &renormed)
Definition compat.h:174
static constexpr decltype(auto) fromRenormed(const RenormedHistogramConcept< container_T > &renormed)
Definition factory.h:106
static constexpr decltype(auto) fromRenormed(const RenormedDenseHistogram< source_T > &renormed)
Definition factory.h:195
void setSelectedIRFrames(const SPAN &sp, size_t bwd=0, size_t fwd=0, long shift=0, bool removeOverlaps=true)
functionality to maintain compatibility with previous version of this library
bool match(const std::vector< std::string > &queries, const char *pattern)
Definition dcs-ccdb.cxx:229
static factory classes for building histograms, encoders and decoders.
GLdouble n
Definition glcorearb.h:1982
GLuint buffer
Definition glcorearb.h:655
const GLdouble * v
Definition glcorearb.h:832
public interface for building and renorming histograms from source data.
ANSHeader ansVersionFromString(const std::string &ansVersionString)
Definition ANSHeader.h:57
constexpr ANSHeader ANSVersionCompat
Definition ANSHeader.h:54
constexpr ANSHeader ANSVersion1
Definition ANSHeader.h:55
constexpr ANSHeader ANSVersionUnspecified
Definition ANSHeader.h:53
size_t calculateMaxBufferSizeB(size_t nElements, size_t rangeBits)
Definition compat.h:282
constexpr uint32_t getRangeBits(T min, T max) noexcept
Definition utils.h:200
auto makeHistogramView(container_T &container, std::ptrdiff_t offset) noexcept -> HistogramView< decltype(std::begin(container))>
HistogramView< Hist_IT > trim(const HistogramView< Hist_IT > &buffer)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
int64_t differenceInBC(const InteractionRecord &other) const
Detector header base.
std::string asString() const
o2::detectors::DetID::mask_t detectors
Definition CTFHeader.h:33
static std::string concat_string(Ts const &... ts)
o2::InteractionRecord ir(0, 0)
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))