Project
Loading...
Searching...
No Matches
HistogramRegistry.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
13#include <regex>
14#include <TList.h>
15#include <TClass.h>
16
17namespace o2::framework
18{
19
20template void HistogramRegistry::fill(const HistName& histName, double);
21template void HistogramRegistry::fill(const HistName& histName, float);
22template void HistogramRegistry::fill(const HistName& histName, int);
23
24constexpr HistogramRegistry::HistName::HistName(char const* const name)
25 : str(name),
26 hash(runtime_hash(name)),
27 idx(hash & REGISTRY_BITMASK)
28{
29}
30
31HistogramRegistry::HistogramRegistry(char const* const name, std::vector<HistogramSpec> histSpecs, OutputObjHandlingPolicy policy, bool sortHistos, bool createRegistryDir)
32 : mName(name), mPolicy(policy), mCreateRegistryDir(createRegistryDir), mSortHistos(sortHistos), mRegistryKey(), mRegistryValue()
33{
34 mRegistryKey.fill(0u);
35 for (auto& histSpec : histSpecs) {
36 insert(histSpec);
37 }
38}
39
40// return the OutputSpec associated to the HistogramRegistry
42{
44 auto lhash = runtime_hash(mName.data());
45 std::memset(desc.str, '_', 16);
46 std::stringstream s;
47 s << std::hex << lhash;
48 s << std::hex << mTaskHash;
49 s << std::hex << reinterpret_cast<uint64_t>(this);
50 std::memcpy(desc.str, s.str().data(), 12);
51 return OutputSpec{OutputLabel{mName}, "ATSK", desc, 0, Lifetime::QA};
52}
53
54OutputRef HistogramRegistry::ref(uint16_t pipelineIndex, uint16_t pipelineSize)
55{
56 return OutputRef{std::string{mName}, 0, o2::header::Stack{OutputObjHeader{mPolicy, OutputObjSourceType::HistogramRegistrySource, mTaskHash, pipelineIndex, pipelineSize}}};
57}
58
59void HistogramRegistry::setHash(uint32_t hash)
60{
61 mTaskHash = hash;
62}
63
64// create histogram from specification and insert it into the registry
65HistPtr HistogramRegistry::insert(const HistogramSpec& histSpec)
66{
67 validateHistName(histSpec.name, histSpec.hash);
68 const uint32_t idx = imask(histSpec.hash);
69 for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) {
70 TObject* rawPtr = nullptr;
71 std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(idx + i)]);
72 if (!rawPtr) {
73 registerName(histSpec.name);
74 mRegistryKey[imask(idx + i)] = histSpec.hash;
75 mRegistryValue[imask(idx + i)] = HistFactory::createHistVariant(histSpec);
76 lookup += i;
77 return mRegistryValue[imask(idx + i)];
78 }
79 }
80 LOGF(fatal, R"(Internal array of HistogramRegistry "%s" is full.)", mName);
81 return HistPtr();
82}
83
84// helper function that checks if histogram name can be used in registry
85void HistogramRegistry::validateHistName(const std::string& name, const uint32_t hash)
86{
87 // check that there are still slots left in the registry
88 if (mRegisteredNames.size() == MAX_REGISTRY_SIZE) {
89 LOGF(fatal, R"(HistogramRegistry "%s" is full! It can hold only %d histograms.)", mName, MAX_REGISTRY_SIZE);
90 }
91
92 // validate that hash is unique
93 auto it = std::find(mRegistryKey.begin(), mRegistryKey.end(), hash);
94 if (it != mRegistryKey.end()) {
95 auto idx = it - mRegistryKey.begin();
96 std::string collidingName{};
97 std::visit([&](const auto& hist) { collidingName = hist->GetName(); }, mRegistryValue[idx]);
98 LOGF(fatal, R"(Hash collision in HistogramRegistry "%s"! Please rename histogram "%s" or "%s".)", mName, name, collidingName);
99 }
100
101 // validate that name contains only allowed characters
102 if (!std::regex_match(name, std::regex("([a-zA-Z0-9])(([\\/_-])?[a-zA-Z0-9])*"))) {
103 LOGF(fatal, R"(Histogram name "%s" contains invalid characters. Only letters, numbers, and (except for the beginning or end of the word) the special characters '/', '_', '-' are allowed.)", name);
104 }
105}
106
108{
109 return insert(histSpec);
110}
111
112HistPtr HistogramRegistry::add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2)
113{
114 return insert({name, title, histConfigSpec, callSumw2});
115}
116
117HistPtr HistogramRegistry::add(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2)
118{
119 return insert({name, title, {histType, axes}, callSumw2});
120}
121
122HistPtr HistogramRegistry::add(const std::string& name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2)
123{
124 return add(name.c_str(), title, histType, axes, callSumw2);
125}
126
127// store a copy of an existing histogram (or group of histograms) under a different name
128void HistogramRegistry::addClone(const std::string& source, const std::string& target)
129{
130 auto doInsertClone = [&](const auto& sharedPtr) {
131 if (!sharedPtr.get()) {
132 return;
133 }
134 std::string sourceName{((TNamed*)sharedPtr.get())->GetName()};
135 // search for histograms starting with source_ substring
136 if (sourceName.rfind(source, 0) == 0) {
137 // when cloning groups of histograms source_ and target_ must end with "/"
138 if (sourceName.size() != source.size() && (source.back() != '/' || target.back() != '/')) {
139 return;
140 }
141 // when cloning a single histogram the specified target_ must not be a group name
142 if (sourceName.size() == source.size() && target.back() == '/') {
143 LOGF(fatal, "Cannot turn histogram into folder!");
144 }
145 std::string targetName{target};
146 targetName += sourceName.substr(sourceName.find(source) + source.size());
147 insertClone(targetName.data(), sharedPtr);
148 }
149 };
150
151 for (auto& histVariant : mRegistryValue) {
152 std::visit(doInsertClone, histVariant);
153 }
154}
155
156// function to query if name is already in use
157bool HistogramRegistry::contains(const HistName& histName)
158{
159 // check for all occurances of the hash
160 auto iter = mRegistryKey.begin();
161 while ((iter = std::find(iter, mRegistryKey.end(), histName.hash)) != mRegistryKey.end()) {
162 const char* curName = nullptr;
163 std::visit([&](auto&& hist) { if(hist) { curName = hist->GetName(); } }, mRegistryValue[iter - mRegistryKey.begin()]);
164 // if hash is the same, make sure that name is indeed the same
165 if (strcmp(curName, histName.str) == 0) {
166 return true;
167 }
168 }
169 return false;
170}
171
172// get rough estimate for size of histogram stored in registry
173double HistogramRegistry::getSize(const HistName& histName, double fillFraction)
174{
175 double size{};
176 std::visit([&fillFraction, &size](auto&& hist) { size = HistFiller::getSize(hist, fillFraction); }, mRegistryValue[getHistIndex(histName)]);
177 return size;
178}
179
180// get rough estimate for size of all histograms stored in registry
181double HistogramRegistry::getSize(double fillFraction)
182{
183 double size{};
184 for (auto j = 0u; j < MAX_REGISTRY_SIZE; ++j) {
185 std::visit([&fillFraction, &size](auto&& hist) { if(hist) { size += HistFiller::getSize(hist, fillFraction);} }, mRegistryValue[j]);
186 }
187 return size;
188}
189
191{
192 for (auto& value : mRegistryValue) {
193 std::visit([](auto&& hist) { hist.reset(); }, value);
194 }
195}
196
197// print some useful meta-info about the stored histograms
198void HistogramRegistry::print(bool showAxisDetails)
199{
200 std::vector<double> fillFractions{0.1, 0.25, 0.5};
201 std::vector<double> totalSizes(fillFractions.size());
202
203 uint32_t nHistos{};
204 bool containsSparseHist{};
205 auto printHistInfo = [&](auto&& hist) {
206 if (hist) {
207 using T = std::decay_t<decltype(*hist)>;
208 bool isSparse{};
209 if (hist->InheritsFrom(THnSparse::Class())) {
210 isSparse = true;
211 containsSparseHist = true;
212 }
213 ++nHistos;
214 std::vector<double> sizes;
215 std::string sizeInfo{};
216 if (isSparse) {
217 std::transform(std::begin(fillFractions), std::end(fillFractions), std::back_inserter(sizes), [&hist](auto& fraction) { return HistFiller::getSize(hist, fraction); });
218 for (int i = 0; i < fillFractions.size(); ++i) {
219 sizeInfo += fmt::format("{:.2f} kB ({:.0f} %)", sizes[i] * 1024, fillFractions[i] * 100);
220 if (i != fillFractions.size() - 1) {
221 sizeInfo += ", ";
222 }
223 }
224 } else {
225 double size = HistFiller::getSize(hist);
226 sizes.resize(fillFractions.size(), size);
227 sizeInfo = fmt::format("{:.2f} kB", sizes[0] * 1024);
228 }
229 std::transform(totalSizes.begin(), totalSizes.end(), sizes.begin(), totalSizes.begin(), std::plus<double>());
230 LOGF(info, "Hist %03d: %-35s %-19s [%s]", nHistos, hist->GetName(), hist->IsA()->GetName(), sizeInfo);
231
232 if (showAxisDetails) {
233 int nDim = 0;
234 if constexpr (std::is_base_of_v<THnBase, T>) {
235 nDim = hist->GetNdimensions();
236 } else if constexpr (std::is_base_of_v<TH1, T>) {
237 nDim = hist->GetDimension();
238 }
239 TAxis* axis{nullptr};
240 for (int d = 0; d < nDim; ++d) {
241 if constexpr (std::is_base_of_v<THnBase, T> || std::is_base_of_v<StepTHn, T>) {
242 axis = hist->GetAxis(d);
243 } else {
244 if (d == 0) {
245 axis = hist->GetXaxis();
246 } else if (d == 1) {
247 axis = hist->GetYaxis();
248 } else if (d == 2) {
249 axis = hist->GetZaxis();
250 }
251 }
252 LOGF(info, "- Axis %d: %-20s (%d bins)", d, axis->GetTitle(), axis->GetNbins());
253 }
254 }
255 }
256 };
257
258 std::string titleString{"======================== HistogramRegistry ========================"};
259 LOGF(info, "");
260 LOGF(info, "%s", titleString);
261 LOGF(info, "%s\"%s\"", std::string((int)(0.5 * titleString.size() - (1 + 0.5 * mName.size())), ' '), mName);
262 for (auto& curHistName : mRegisteredNames) {
263 std::visit(printHistInfo, mRegistryValue[getHistIndex(HistName{curHistName.data()})]);
264 }
265 std::string totalSizeInfo{};
266 if (containsSparseHist) {
267 for (int i = 0; i < totalSizes.size(); ++i) {
268 totalSizeInfo += fmt::format("{:.2f} MB ({:.0f} %)", totalSizes[i], fillFractions[i] * 100);
269 if (i != totalSizes.size() - 1) {
270 totalSizeInfo += ", ";
271 }
272 }
273 } else {
274 totalSizeInfo = fmt::format("{:.2f} MB", totalSizes[0]);
275 }
276 LOGF(info, "%s", std::string(titleString.size(), '='), titleString);
277 LOGF(info, "Total: %d histograms, ca. %s", nHistos, totalSizeInfo);
278 if (lookup) {
279 LOGF(info, "Due to index collisions, histograms were shifted by %d registry slots in total.", lookup);
280 }
281 LOGF(info, "%s", std::string(titleString.size(), '='), titleString);
282 LOGF(info, "");
283}
284
285// create output structure will be propagated to file-sink
287{
288 TList* list = new TList();
289 list->SetName(mName.data());
290
291 if (mSortHistos) {
292 auto caseInsensitiveCompare = [](const std::string& s1, const std::string& s2) {
293 return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(),
294 [](char c1, char c2) { return std::tolower(static_cast<unsigned char>(c1)) < std::tolower(static_cast<unsigned char>(c2)); });
295 };
296 std::sort(mRegisteredNames.begin(), mRegisteredNames.end(), caseInsensitiveCompare);
297 }
298
299 for (auto& curHistName : mRegisteredNames) {
300 TNamed* rawPtr = nullptr;
301 std::visit([&](const auto& sharedPtr) { rawPtr = (TNamed*)sharedPtr.get(); }, mRegistryValue[getHistIndex(HistName{curHistName.data()})]);
302 if (rawPtr) {
303 std::deque<std::string> path = splitPath(rawPtr->GetName());
304 std::string name = path.back();
305 path.pop_back();
306 TList* targetList{getSubList(list, path)};
307 if (targetList) {
308 rawPtr->SetName(name.data());
309 targetList->Add(rawPtr);
310 } else {
311 LOGF(fatal, "Specified subfolder could not be created.");
312 }
313 }
314 }
315
316 // place lists always at the top
317 std::function<void(TList*)> moveListsToTop;
318 moveListsToTop = [&](TList* list) {
319 TIter next(list);
320 TNamed* subList = nullptr;
321 std::vector<TObject*> subLists;
322 while ((subList = (TNamed*)next())) {
323 if (subList->InheritsFrom(TList::Class())) {
324 subLists.push_back(subList);
325 moveListsToTop((TList*)subList);
326 }
327 }
328 std::reverse(subLists.begin(), subLists.end());
329 for (auto curList : subLists) {
330 list->Remove(curList);
331 list->AddFirst(curList);
332 }
333 };
334 moveListsToTop(list);
335
336 // create dedicated directory containing all of the registrys histograms
337 if (mCreateRegistryDir) {
338 // propagate this to the writer by adding a 'flag' to the output list
339 list->AddLast(new TNamed("createFolder", ""));
340 }
341 return list;
342}
343
344// helper function to create resp. find the subList defined by path
345TList* HistogramRegistry::getSubList(TList* list, std::deque<std::string>& path)
346{
347 if (path.empty()) {
348 return list;
349 }
350 TList* targetList{nullptr};
351 std::string nextList = path[0];
352 path.pop_front();
353 if (auto subList = (TList*)list->FindObject(nextList.data())) {
354 if (subList->InheritsFrom(TList::Class())) {
355 targetList = getSubList((TList*)subList, path);
356 } else {
357 return nullptr;
358 }
359 } else {
360 subList = new TList();
361 subList->SetName(nextList.data());
362 list->Add(subList);
363 targetList = getSubList(subList, path);
364 }
365 return targetList;
366}
367
368// helper function to split user defined path/to/hist/name string
369std::deque<std::string> HistogramRegistry::splitPath(const std::string& pathAndNameUser)
370{
371 std::istringstream pathAndNameStream(pathAndNameUser);
372 std::deque<std::string> pathAndName;
373 std::string curDir;
374 while (std::getline(pathAndNameStream, curDir, '/')) {
375 pathAndName.push_back(curDir);
376 }
377 return pathAndName;
378}
379
380// helper function that checks if name of histogram is reasonable and keeps track of names already in use
381void HistogramRegistry::registerName(const std::string& name)
382{
383 if (name.empty() || name.back() == '/') {
384 LOGF(fatal, "Invalid name for a histogram.");
385 }
386 std::deque<std::string> path = splitPath(name);
387 std::string cumulativeName{};
388 int depth = path.size();
389 for (auto& step : path) {
390 if (step.empty()) {
391 LOGF(fatal, R"(Found empty group name in path for histogram "%s".)", name);
392 }
393 cumulativeName += step;
394 for (auto& curName : mRegisteredNames) {
395 // there is already a histogram where we want to put a folder or histogram
396 if (cumulativeName == curName) {
397 LOGF(fatal, R"(Histogram name "%s" is not compatible with existing names.)", name);
398 }
399 // for the full new histogram name we need to check that none of the existing histograms already uses this as a group name
400 if (depth == 1) {
401 if (curName.rfind(cumulativeName, 0) == 0 && curName.size() > cumulativeName.size() && curName.at(cumulativeName.size()) == '/') {
402 LOGF(fatal, R"(Histogram name "%s" is not compatible with existing names.)", name);
403 }
404 }
405 }
406 --depth;
407 cumulativeName += "/";
408 }
409 mRegisteredNames.push_back(name);
410}
411
412void HistFiller::badHistogramFill(char const* name)
413{
414 LOGF(fatal, "The number of arguments in fill function called for histogram %s is incompatible with histogram dimensions.", name);
415}
416
417template <typename T>
418HistPtr HistogramRegistry::insertClone(const HistName& histName, const std::shared_ptr<T> originalHist)
419{
420 validateHistName(histName.str, histName.hash);
421 for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) {
422 TObject* rawPtr = nullptr;
423 std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(histName.idx + i)]);
424 if (!rawPtr) {
425 registerName(histName.str);
426 mRegistryKey[imask(histName.idx + i)] = histName.hash;
427 mRegistryValue[imask(histName.idx + i)] = std::shared_ptr<T>(static_cast<T*>(originalHist->Clone(histName.str)));
428 lookup += i;
429 return mRegistryValue[imask(histName.idx + i)];
430 }
431 }
432 LOGF(fatal, R"(Internal array of HistogramRegistry "%s" is full.)", mName);
433 return HistPtr();
434}
435
436template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TH1>);
437template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TH2>);
438template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TH3>);
439template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TProfile>);
440template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TProfile2D>);
441template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TProfile3D>);
442template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<THnSparse>);
443template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<THn>);
444template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<StepTHn>);
445
446template <typename T>
447std::shared_ptr<T> HistogramRegistry::add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2)
448{
449 auto histVariant = add(name, title, histConfigSpec, callSumw2);
450 if (auto histPtr = std::get_if<std::shared_ptr<T>>(&histVariant)) {
451 return *histPtr;
452 } else {
453 throw runtime_error_f(R"(Histogram type specified in add<>("%s") does not match the actual type of the histogram!)", name);
454 }
455}
456
457template <typename T>
458std::shared_ptr<T> HistogramRegistry::add(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2)
459{
460 auto histVariant = add(name, title, histType, axes, callSumw2);
461 if (auto histPtr = std::get_if<std::shared_ptr<T>>(&histVariant)) {
462 return *histPtr;
463 } else {
464 throw runtime_error_f(R"(Histogram type specified in add<>("%s") does not match the actual type of the histogram!)", name);
465 }
466}
467
468template std::shared_ptr<TH1> HistogramRegistry::add<TH1>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
469template std::shared_ptr<TH1> HistogramRegistry::add<TH1>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
470template std::shared_ptr<TH2> HistogramRegistry::add<TH2>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
471template std::shared_ptr<TH2> HistogramRegistry::add<TH2>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
472template std::shared_ptr<TH3> HistogramRegistry::add<TH3>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
473template std::shared_ptr<TH3> HistogramRegistry::add<TH3>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
474template std::shared_ptr<TProfile> HistogramRegistry::add<TProfile>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
475template std::shared_ptr<TProfile> HistogramRegistry::add<TProfile>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
476template std::shared_ptr<TProfile2D> HistogramRegistry::add<TProfile2D>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
477template std::shared_ptr<TProfile2D> HistogramRegistry::add<TProfile2D>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
478template std::shared_ptr<TProfile3D> HistogramRegistry::add<TProfile3D>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
479template std::shared_ptr<TProfile3D> HistogramRegistry::add<TProfile3D>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
480template std::shared_ptr<THn> HistogramRegistry::add<THn>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
481template std::shared_ptr<THn> HistogramRegistry::add<THn>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
482template std::shared_ptr<THnSparse> HistogramRegistry::add<THnSparse>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
483template std::shared_ptr<THnSparse> HistogramRegistry::add<THnSparse>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
484template std::shared_ptr<StepTHn> HistogramRegistry::add<StepTHn>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
485template std::shared_ptr<StepTHn> HistogramRegistry::add<StepTHn>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
486
487} // namespace o2::framework
int32_t i
bool const GPUTPCGMMerger::trackCluster * c1
bool const GPUTPCGMMerger::trackCluster const clcomparestruct * c2
uint32_t j
Definition RawData.h:0
constexpr uint32_t runtime_hash(char const *str)
bool contains(const HistName &histName)
double getSize(const HistName &histName, double fillFraction=1.)
void fill(const HistName &histName, Ts... positionAndWeight)
TList * getListOfHistograms()
returns the list of histograms, properly sorted for writing.
void addClone(const std::string &source, const std::string &target)
void print(bool showAxisDetails=false)
HistPtr add(const HistogramSpec &histSpec)
OutputRef ref(uint16_t idx, uint16_t pipelineSize)
void clean()
deletes all the histograms from the registry
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
Definition glcorearb.h:2595
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
Definition glcorearb.h:5034
GLuint const GLchar * name
Definition glcorearb.h:781
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLenum target
Definition glcorearb.h:1641
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLint GLint GLsizei GLsizei GLsizei depth
Definition glcorearb.h:470
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::variant< std::shared_ptr< THn >, std::shared_ptr< THnSparse >, std::shared_ptr< TH3 >, std::shared_ptr< TH2 >, std::shared_ptr< TH1 >, std::shared_ptr< TProfile3D >, std::shared_ptr< TProfile2D >, std::shared_ptr< TProfile >, std::shared_ptr< StepTHn > > HistPtr
RuntimeErrorRef runtime_error_f(const char *,...)
OutputObjHandlingPolicy
Policy enum to determine OutputObj handling when writing.
value_T step
Definition TrackUtils.h:42
Definition list.h:40
static HistPtr createHistVariant(const HistogramSpec &histSpec)
static double getSize(std::shared_ptr< T > hist, double fillFraction=1.)
O2 header for OutputObj metadata.
a move-only header stack with serialized headers This is the flat buffer where all the headers in a m...
Definition Stack.h:36
const std::string str