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 "Framework/ASoA.h"
14#include <regex>
15#include <TList.h>
16#include <TClass.h>
17
18namespace o2::framework
19{
20
21template void HistogramRegistry::fill(const HistName& histName, double);
22template void HistogramRegistry::fill(const HistName& histName, float);
23template void HistogramRegistry::fill(const HistName& histName, int);
24
25constexpr HistogramRegistry::HistName::HistName(char const* const name)
26 : str(name),
28 idx(hash & REGISTRY_BITMASK)
29{
30}
31
32HistogramRegistry::HistogramRegistry(char const* const name, std::vector<HistogramSpec> histSpecs, OutputObjHandlingPolicy policy, bool sortHistos, bool createRegistryDir)
33 : mName(name), mPolicy(policy), mCreateRegistryDir(createRegistryDir), mSortHistos(sortHistos), mRegistryKey(), mRegistryValue()
34{
35 mRegistryKey.fill(0u);
36 for (auto& histSpec : histSpecs) {
37 insert(histSpec);
38 }
39}
40
41// return the OutputSpec associated to the HistogramRegistry
43{
45 auto lhash = runtime_hash(mName.data());
46 std::memset(desc.str, '_', 16);
47 std::stringstream s;
48 s << std::hex << lhash;
49 s << std::hex << mTaskHash;
50 s << std::hex << reinterpret_cast<uint64_t>(this);
51 std::memcpy(desc.str, s.str().data(), 12);
52 return OutputSpec{OutputLabel{mName}, "ATSK", desc, 0, Lifetime::QA};
53}
54
55OutputRef HistogramRegistry::ref(uint16_t pipelineIndex, uint16_t pipelineSize) const
56{
57 OutputObjHeader header{mPolicy, OutputObjSourceType::HistogramRegistrySource, mTaskHash, pipelineIndex, pipelineSize};
58 // Copy the name of the registry to the haeder.
59 strncpy(header.containerName, mName.data(), OutputObjHeader::MAX_REGISTRY_NAME_SIZE);
60 header.createContainer = mCreateRegistryDir ? 1 : 0;
61 return OutputRef{std::string{mName}, 0, o2::header::Stack{header}};
62}
63
65{
66 mTaskHash = hash;
67}
68
69// create histogram from specification and insert it into the registry
70HistPtr HistogramRegistry::insert(const HistogramSpec& histSpec)
71{
72 validateHistName(histSpec.name, histSpec.hash);
73 const uint32_t idx = imask(histSpec.hash);
74 for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) {
75 TObject* rawPtr = nullptr;
76 std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(idx + i)]);
77 if (!rawPtr) {
78 registerName(histSpec.name);
79 mRegistryKey[imask(idx + i)] = histSpec.hash;
80 mRegistryValue[imask(idx + i)] = HistFactory::createHistVariant(histSpec);
81 lookup += i;
82 return mRegistryValue[imask(idx + i)];
83 }
84 }
85 LOGF(fatal, R"(Internal array of HistogramRegistry "%s" is full.)", mName);
86 return HistPtr();
87}
88
89// helper function that checks if histogram name can be used in registry
90void HistogramRegistry::validateHistName(const std::string& name, const uint32_t hash)
91{
92 // check that there are still slots left in the registry
93 if (mRegisteredNames.size() == MAX_REGISTRY_SIZE) {
94 LOGF(fatal, R"(HistogramRegistry "%s" is full! It can hold only %d histograms.)", mName, MAX_REGISTRY_SIZE);
95 }
96
97 // validate that hash is unique
98 auto it = std::find(mRegistryKey.begin(), mRegistryKey.end(), hash);
99 if (it != mRegistryKey.end()) {
100 auto idx = it - mRegistryKey.begin();
101 std::string collidingName{};
102 std::visit([&](const auto& hist) { collidingName = hist->GetName(); }, mRegistryValue[idx]);
103 LOGF(fatal, R"(Hash collision in HistogramRegistry "%s"! Please rename histogram "%s" or "%s".)", mName, name, collidingName);
104 }
105
106 // validate that name contains only allowed characters
107 if (!std::regex_match(name, std::regex("([a-zA-Z0-9])(([\\/_-])?[a-zA-Z0-9])*"))) {
108 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);
109 }
110}
111
113{
114 return insert(histSpec);
115}
116
117HistPtr HistogramRegistry::add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2)
118{
119 return insert({name, title, histConfigSpec, callSumw2});
120}
121
122HistPtr HistogramRegistry::add(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2)
123{
124 return insert({name, title, {histType, axes}, callSumw2});
125}
126
127HistPtr HistogramRegistry::add(const std::string& name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2)
128{
129 return add(name.c_str(), title, histType, axes, callSumw2);
130}
131
132// store a copy of an existing histogram (or group of histograms) under a different name
133void HistogramRegistry::addClone(const std::string& source, const std::string& target)
134{
135 auto doInsertClone = [&](const auto& sharedPtr) {
136 if (!sharedPtr.get()) {
137 return;
138 }
139 std::string sourceName{((TNamed*)sharedPtr.get())->GetName()};
140 // search for histograms starting with source_ substring
141 if (sourceName.rfind(source, 0) == 0) {
142 // when cloning groups of histograms source_ and target_ must end with "/"
143 if (sourceName.size() != source.size() && (source.back() != '/' || target.back() != '/')) {
144 return;
145 }
146 // when cloning a single histogram the specified target_ must not be a group name
147 if (sourceName.size() == source.size() && target.back() == '/') {
148 LOGF(fatal, "Cannot turn histogram into folder!");
149 }
150 std::string targetName{target};
151 targetName += sourceName.substr(sourceName.find(source) + source.size());
152 insertClone(targetName.data(), sharedPtr);
153 }
154 };
155
156 for (auto& histVariant : mRegistryValue) {
157 std::visit(doInsertClone, histVariant);
158 }
159}
160
161// function to query if name is already in use
162bool HistogramRegistry::contains(const HistName& histName)
163{
164 // check for all occurances of the hash
165 auto iter = mRegistryKey.begin();
166 while ((iter = std::find(iter, mRegistryKey.end(), histName.hash)) != mRegistryKey.end()) {
167 const char* curName = nullptr;
168 std::visit([&](auto&& hist) { if(hist) { curName = hist->GetName(); } }, mRegistryValue[iter - mRegistryKey.begin()]);
169 // if hash is the same, make sure that name is indeed the same
170 if (strcmp(curName, histName.str) == 0) {
171 return true;
172 }
173 }
174 return false;
175}
176
177// get rough estimate for size of histogram stored in registry
178double HistogramRegistry::getSize(const HistName& histName, double fillFraction)
179{
180 double size{};
181 std::visit([&fillFraction, &size](auto&& hist) { size = HistFiller::getSize(hist, fillFraction); }, mRegistryValue[getHistIndex(histName)]);
182 return size;
183}
184
185// get rough estimate for size of all histograms stored in registry
186double HistogramRegistry::getSize(double fillFraction)
187{
188 double size{};
189 for (auto j = 0u; j < MAX_REGISTRY_SIZE; ++j) {
190 std::visit([&fillFraction, &size](auto&& hist) { if(hist) { size += HistFiller::getSize(hist, fillFraction);} }, mRegistryValue[j]);
191 }
192 return size;
193}
194
196{
197 for (auto& value : mRegistryValue) {
198 std::visit([](auto&& hist) { hist.reset(); }, value);
199 }
200}
201
202// print some useful meta-info about the stored histograms
203void HistogramRegistry::print(bool showAxisDetails)
204{
205 std::vector<double> fillFractions{0.1, 0.25, 0.5};
206 std::vector<double> totalSizes(fillFractions.size());
207
208 uint32_t nHistos{};
209 bool containsSparseHist{};
210 auto printHistInfo = [&](auto&& hist) {
211 if (hist) {
212 using T = std::decay_t<decltype(*hist)>;
213 bool isSparse{};
214 if (hist->InheritsFrom(THnSparse::Class())) {
215 isSparse = true;
216 containsSparseHist = true;
217 }
218 ++nHistos;
219 std::vector<double> sizes;
220 std::string sizeInfo{};
221 if (isSparse) {
222 std::transform(std::begin(fillFractions), std::end(fillFractions), std::back_inserter(sizes), [&hist](auto& fraction) { return HistFiller::getSize(hist, fraction); });
223 for (int i = 0; i < fillFractions.size(); ++i) {
224 sizeInfo += fmt::format("{:.2f} kB ({:.0f} %)", sizes[i] * 1024, fillFractions[i] * 100);
225 if (i != fillFractions.size() - 1) {
226 sizeInfo += ", ";
227 }
228 }
229 } else {
230 double size = HistFiller::getSize(hist);
231 sizes.resize(fillFractions.size(), size);
232 sizeInfo = fmt::format("{:.2f} kB", sizes[0] * 1024);
233 }
234 std::transform(totalSizes.begin(), totalSizes.end(), sizes.begin(), totalSizes.begin(), std::plus<double>());
235 LOGF(info, "Hist %03d: %-35s %-19s [%s]", nHistos, hist->GetName(), hist->IsA()->GetName(), sizeInfo);
236
237 if (showAxisDetails) {
238 int nDim = 0;
239 if constexpr (std::is_base_of_v<THnBase, T>) {
240 nDim = hist->GetNdimensions();
241 } else if constexpr (std::is_base_of_v<TH1, T>) {
242 nDim = hist->GetDimension();
243 }
244 TAxis* axis{nullptr};
245 for (int d = 0; d < nDim; ++d) {
246 if constexpr (std::is_base_of_v<THnBase, T> || std::is_base_of_v<StepTHn, T>) {
247 axis = hist->GetAxis(d);
248 } else {
249 if (d == 0) {
250 axis = hist->GetXaxis();
251 } else if (d == 1) {
252 axis = hist->GetYaxis();
253 } else if (d == 2) {
254 axis = hist->GetZaxis();
255 }
256 }
257 LOGF(info, "- Axis %d: %-20s (%d bins)", d, axis->GetTitle(), axis->GetNbins());
258 }
259 }
260 }
261 };
262
263 std::string titleString{"======================== HistogramRegistry ========================"};
264 LOGF(info, "");
265 LOGF(info, "%s", titleString);
266 LOGF(info, "%s\"%s\"", std::string((int)(0.5 * titleString.size() - (1 + 0.5 * mName.size())), ' '), mName);
267 for (auto& curHistName : mRegisteredNames) {
268 std::visit(printHistInfo, mRegistryValue[getHistIndex(HistName{curHistName.data()})]);
269 }
270 std::string totalSizeInfo{};
271 if (containsSparseHist) {
272 for (int i = 0; i < totalSizes.size(); ++i) {
273 totalSizeInfo += fmt::format("{:.2f} MB ({:.0f} %)", totalSizes[i], fillFractions[i] * 100);
274 if (i != totalSizes.size() - 1) {
275 totalSizeInfo += ", ";
276 }
277 }
278 } else {
279 totalSizeInfo = fmt::format("{:.2f} MB", totalSizes[0]);
280 }
281 LOGF(info, "%s", std::string(titleString.size(), '='), titleString);
282 LOGF(info, "Total: %d histograms, ca. %s", nHistos, totalSizeInfo);
283 if (lookup) {
284 LOGF(info, "Due to index collisions, histograms were shifted by %d registry slots in total.", lookup);
285 }
286 LOGF(info, "%s", std::string(titleString.size(), '='), titleString);
287 LOGF(info, "");
288}
289
290void HistogramRegistry::apply(std::function<void(HistogramRegistry const&, TNamed* named)> callback) const
291{
292 // Keep the list sorted as originally done to avoid hidden dependency on the order, for now , for now.
293 auto finalList = mRegisteredNames;
294 auto caseInsensitiveCompare = [](const std::string& s1, const std::string& s2) {
295 return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(),
296 [](char c1, char c2) { return std::tolower(static_cast<unsigned char>(c1)) < std::tolower(static_cast<unsigned char>(c2)); });
297 };
298 if (mSortHistos) {
299 std::sort(finalList.begin(), finalList.end(), caseInsensitiveCompare);
300 }
301 for (auto& curHistName : finalList) {
302 TNamed* rawPtr = nullptr;
303 std::visit([&](const auto& sharedPtr) { rawPtr = (TNamed*)sharedPtr.get(); }, mRegistryValue[getHistIndex(HistName{curHistName.data()})]);
304 if (!rawPtr) {
305 // Skipping empty histograms
306 continue;
307 }
308 callback(*this, rawPtr);
309 }
310}
311
312// helper function to split user defined path/to/hist/name string
313std::deque<std::string> HistogramRegistry::splitPath(const std::string& pathAndNameUser)
314{
315 std::istringstream pathAndNameStream(pathAndNameUser);
316 std::deque<std::string> pathAndName;
317 std::string curDir;
318 while (std::getline(pathAndNameStream, curDir, '/')) {
319 pathAndName.push_back(curDir);
320 }
321 return pathAndName;
322}
323
324// helper function that checks if name of histogram is reasonable and keeps track of names already in use
325void HistogramRegistry::registerName(const std::string& name)
326{
327 if (name.empty() || name.back() == '/') {
328 LOGF(fatal, "Invalid name for a histogram.");
329 }
330 std::deque<std::string> path = splitPath(name);
331 std::string cumulativeName{};
332 int depth = path.size();
333 for (auto& step : path) {
334 if (step.empty()) {
335 LOGF(fatal, R"(Found empty group name in path for histogram "%s".)", name);
336 }
337 cumulativeName += step;
338 for (auto& curName : mRegisteredNames) {
339 // there is already a histogram where we want to put a folder or histogram
340 if (cumulativeName == curName) {
341 LOGF(fatal, R"(Histogram name "%s" is not compatible with existing names.)", name);
342 }
343 // for the full new histogram name we need to check that none of the existing histograms already uses this as a group name
344 if (depth == 1) {
345 if (curName.rfind(cumulativeName, 0) == 0 && curName.size() > cumulativeName.size() && curName.at(cumulativeName.size()) == '/') {
346 LOGF(fatal, R"(Histogram name "%s" is not compatible with existing names.)", name);
347 }
348 }
349 }
350 --depth;
351 cumulativeName += "/";
352 }
353 mRegisteredNames.push_back(name);
354}
355
356void HistFiller::badHistogramFill(char const* name)
357{
358 LOGF(fatal, "The number of arguments in fill function called for histogram %s is incompatible with histogram dimensions.", name);
359}
360
361template <typename T>
362HistPtr HistogramRegistry::insertClone(const HistName& histName, const std::shared_ptr<T> originalHist)
363{
364 validateHistName(histName.str, histName.hash);
365 for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) {
366 TObject* rawPtr = nullptr;
367 std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(histName.idx + i)]);
368 if (!rawPtr) {
369 registerName(histName.str);
370 mRegistryKey[imask(histName.idx + i)] = histName.hash;
371 mRegistryValue[imask(histName.idx + i)] = std::shared_ptr<T>(static_cast<T*>(originalHist->Clone(histName.str)));
372 lookup += i;
373 return mRegistryValue[imask(histName.idx + i)];
374 }
375 }
376 LOGF(fatal, R"(Internal array of HistogramRegistry "%s" is full.)", mName);
377 return HistPtr();
378}
379
380template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TH1>);
381template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TH2>);
382template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TH3>);
383template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TProfile>);
384template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TProfile2D>);
385template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<TProfile3D>);
386template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<THnSparse>);
387template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<THn>);
388template HistPtr HistogramRegistry::insertClone(const HistName&, const std::shared_ptr<StepTHn>);
389
390template <typename T>
391std::shared_ptr<T> HistogramRegistry::add(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2)
392{
393 auto histVariant = add(name, title, histConfigSpec, callSumw2);
394 if (auto histPtr = std::get_if<std::shared_ptr<T>>(&histVariant)) {
395 return *histPtr;
396 } else {
397 throw runtime_error_f(R"(Histogram type specified in add<>("%s") does not match the actual type of the histogram!)", name);
398 }
399}
400
401template <typename T>
402std::shared_ptr<T> HistogramRegistry::add(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2)
403{
404 auto histVariant = add(name, title, histType, axes, callSumw2);
405 if (auto histPtr = std::get_if<std::shared_ptr<T>>(&histVariant)) {
406 return *histPtr;
407 } else {
408 throw runtime_error_f(R"(Histogram type specified in add<>("%s") does not match the actual type of the histogram!)", name);
409 }
410}
411
412template std::shared_ptr<TH1> HistogramRegistry::add<TH1>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
413template std::shared_ptr<TH1> HistogramRegistry::add<TH1>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
414template std::shared_ptr<TH2> HistogramRegistry::add<TH2>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
415template std::shared_ptr<TH2> HistogramRegistry::add<TH2>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
416template std::shared_ptr<TH3> HistogramRegistry::add<TH3>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
417template std::shared_ptr<TH3> HistogramRegistry::add<TH3>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
418template std::shared_ptr<TProfile> HistogramRegistry::add<TProfile>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
419template std::shared_ptr<TProfile> HistogramRegistry::add<TProfile>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
420template std::shared_ptr<TProfile2D> HistogramRegistry::add<TProfile2D>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
421template std::shared_ptr<TProfile2D> HistogramRegistry::add<TProfile2D>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
422template std::shared_ptr<TProfile3D> HistogramRegistry::add<TProfile3D>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
423template std::shared_ptr<TProfile3D> HistogramRegistry::add<TProfile3D>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
424template std::shared_ptr<THn> HistogramRegistry::add<THn>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
425template std::shared_ptr<THn> HistogramRegistry::add<THn>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
426template std::shared_ptr<THnSparse> HistogramRegistry::add<THnSparse>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
427template std::shared_ptr<THnSparse> HistogramRegistry::add<THnSparse>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
428template std::shared_ptr<StepTHn> HistogramRegistry::add<StepTHn>(char const* const name, char const* const title, const HistogramConfigSpec& histConfigSpec, bool callSumw2);
429template std::shared_ptr<StepTHn> HistogramRegistry::add<StepTHn>(char const* const name, char const* const title, HistType histType, const std::vector<AxisSpec>& axes, bool callSumw2);
430
431} // namespace o2::framework
uint32_t hash
unsigned short int uint16_t
unsigned int uint32_t
std::vector< std::string > header
int32_t i
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events d
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)
void addClone(const std::string &source, const std::string &target)
void print(bool showAxisDetails=false)
HistPtr add(const HistogramSpec &histSpec)
void apply(std::function< void(HistogramRegistry const &, TNamed *named)> callback) const
OutputRef ref(uint16_t idx, uint16_t pipelineSize) const
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
GLint GLint GLsizei GLsizei GLsizei depth
Definition glcorearb.h:470
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
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
static HistPtr createHistVariant(const HistogramSpec &histSpec)
static double getSize(std::shared_ptr< T > hist, double fillFraction=1.)
O2 header for OutputObj metadata.
static constexpr const uint32_t MAX_REGISTRY_NAME_SIZE
a move-only header stack with serialized headers This is the flat buffer where all the headers in a m...
Definition Stack.h:33
const std::string str