Hammer  1.0.0
Helicity Amplitude Module for Matrix Element Reweighting
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Histos.cc
Go to the documentation of this file.
1 ///
2 /// @file Histos.cc
3 /// @brief Hammer histogram manager
4 ///
5 
6 //**** This file is a part of the HAMMER library
7 //**** Copyright (C) 2016 - 2020 The HAMMER Collaboration
8 //**** HAMMER is licensed under version 3 of the GPL; see COPYING for details
9 //**** Please note the MCnet academic guidelines; see GUIDELINES for details
10 
11 // -*- C++ -*-
12 #include <functional>
13 
14 #include "Hammer/Histos.hh"
15 #include "Hammer/Math/Histogram.hh"
18 #include "Hammer/ExternalData.hh"
21 
23 
25 
26 #include "Hammer/Math/Utils.hh"
27 #include "Hammer/Tools/Logging.hh"
28 
29 using namespace std;
30 
31 namespace Hammer {
32 
33  namespace MD = MultiDimensional;
34 
35  Histos::Histos(DictionaryManager* dict) : _dictionaries{dict}, _initialized{false} {
36  }
37 
38  Histos::~Histos() noexcept {
39  clear();
40  _dictionaries = nullptr;
41  }
42 
43  void Histos::addHistogramDefinition(const string& name, const IndexList& binSizes, bool hasUnderOverFlow,
44  const MD::BinRangeList& ranges, bool shouldCompress, bool withErrors) {
46  if (name != "Total Sum of Weights") { //now defunct as histo is no longer added in initRun
47  auto it = _histogramDefs.find(name);
48  if (it != _histogramDefs.end()) {
49  MSG_ERROR(string("A histogram with name '") + name + string("' is already present! Not adding"));
50  return;
51  }
52  auto resdef = _histogramDefs.emplace(
53  name, HistogramDefinition{hasUnderOverFlow, binSizes, ranges, shouldCompress, withErrors});
54  if (!resdef.second) {
55  MSG_ERROR(string("Invalid histogram definition for histogram '") + name +
56  string("'! Not adding. The Sesame Street Count is on his way."));
57  return;
58  }
59  ith = _histograms.emplace(name, SchemeDict<HistogramSet>{}).first;
60  }
61  else {
62  _histogramDefs.insert(
63  {name, HistogramDefinition{hasUnderOverFlow, binSizes, ranges, shouldCompress, withErrors}});
64 
65  ith = _histograms.emplace(name, SchemeDict<HistogramSet>{}).first;
66  }
67  if (_histograms.begin()->second.size() > 0) {
68  for (auto& elem : _histograms.begin()->second) {
69  ith->second.emplace(elem.first, HistogramSet{});
70  }
71  }
72  }
73 
74  void Histos::addHistogramDefinition(const string& name, const MD::BinEdgeList& binEdges,
75  bool hasUnderOverFlow, bool shouldCompress, bool withErrors) {
76  auto it = _histogramDefs.find(name);
77  if (it != _histogramDefs.end() && name != "Total Sum of Weights") { //now defunct as histo is no longer added in initRun
78  MSG_ERROR(string("A histogram with name '") + name + string("' is already present! Not adding"));
79  return;
80  }
81  auto resdef = _histogramDefs.emplace(name, HistogramDefinition{hasUnderOverFlow, binEdges, shouldCompress, withErrors});
82  if(!resdef.second) {
83  MSG_ERROR(string("Invalid histogram definition for histogram '") + name + string("'! Not adding. The Sesame Street Count is on his way."));
84  return;
85  }
86  else {
87  auto res = _histograms.emplace(name, SchemeDict<HistogramSet>{});
88  if(_initialized) {
89  for(auto& elem: _dictionaries->schemeDefs().getFFSchemeNames()) {
90  res.first->second.emplace(elem, HistogramSet{});
91  }
92  }
93  }
94  }
95 
96  void Histos::createProjectedHistogram(const string& oldName, const string& newName,
97  const set<uint16_t>& collapsedIndexPositions) {
98  auto itNew = _histogramDefs.find(newName);
99  auto itOld = _histogramDefs.find(oldName);
100  if (itNew != _histogramDefs.end()) {
101  MSG_ERROR(string("Histogram '") + newName + string("' already exists. Not projecting"));
102  return;
103  }
104  if (itOld == _histogramDefs.end()) {
105  MSG_ERROR(string("Cannot find histogram '") + oldName + string("'. Not projecting"));
106  return;
107  }
108  MD::BinEdgeList newBinEdges = itOld->second.getIndexing().edges();
109  for(auto itPos = collapsedIndexPositions.crbegin(); itPos != collapsedIndexPositions.crend(); ++itPos) {
110  newBinEdges.erase(newBinEdges.begin() + *itPos);
111  }
112  if(newBinEdges.size() == 0) {
113  MSG_ERROR(string("You are trying to project all the dimensions of histogram '") + oldName + string("'! Mascalzone!"));
114  return;
115  }
116  auto resdef = _histogramDefs.emplace(newName, HistogramDefinition{itOld->second.getIndexing().hasUnderOverFlow(), newBinEdges,
117  itOld->second.shouldCompress(),
118  itOld->second.shouldKeepErrors()});
119  if (!resdef.second) {
120  MSG_ERROR(string("Invalid histogram definition for histogram '") + newName +
121  string("'! Not adding. The Sesame Street Count is on his way."));
122  return;
123  } else {
124  auto resScheme = _histograms.emplace(newName, SchemeDict<HistogramSet>{});
125  auto itHistoOld = _histograms.find(oldName);
126  for(auto& elemScheme: itHistoOld->second) {
127  resScheme.first->second.emplace(elemScheme.first, HistogramSet{elemScheme.second, resdef.first->first, resdef.first->second, collapsedIndexPositions});
128  }
129  }
130  }
131 
132 
133  void Histos::removeHistogram(const string& name) {
134  auto it = _histogramDefs.find(name);
135  if (it == _histogramDefs.end()) {
136  MSG_ERROR(string("Cannot find histogram '") + name + string("'. Not removing"));
137  return;
138  }
139  _histogramDefs.erase(it);
140  _histograms.erase(name);
141  }
142 
143 
144  void Histos::setHistogramCompression(const std::string& name, bool value) {
145  auto it = _histogramDefs.find(name);
146  if (it == _histogramDefs.end()) {
147  MSG_ERROR(string("Cannot find histogram '") + name + string("'. Not setting compression"));
148  return;
149  }
150  it->second.setCompression(value);
151  }
152 
153  void Histos::setHistogramKeepErrors(const std::string& name, bool value) {
154  auto it = _histogramDefs.find(name);
155  if (it == _histogramDefs.end()) {
156  MSG_ERROR(string("Cannot find histogram '") + name + string("'. Not setting compression"));
157  return;
158  }
159  it->second.setKeepErrors(value);
160  }
161 
162  void Histos::addHistogramFixedData(const std::string& name, MD::SharedTensorData data) {
163  auto it = _histogramDefs.find(name);
164  if (it == _histogramDefs.end()) {
165  MSG_ERROR(string("Cannot find histogram '") + name + string("'. Not adding fixed data."));
166  return;
167  }
168  it->second.addFixedData(data);
169  }
170 
171  void Histos::resetHistogramFixedData(const std::string& name) {
172  auto it = _histogramDefs.find(name);
173  if (it == _histogramDefs.end()) {
174  MSG_ERROR(string("Cannot find histogram '") + name + string("'. Not resetting fixed data."));
175  return;
176  }
177  it->second.resetFixedData();
178  }
179 
180  void Histos::init() {
181  // initSettings();
182  for(auto& elem: _histograms) {
183  elem.second.clear();
184  }
185  for(auto& elem: _dictionaries->schemeDefs().getFFSchemeNames()) {
186  for(auto& elem2: _histograms) {
187  bool compress = _histogramDefs.find(elem2.first)->second.shouldCompress();
188  elem2.second.emplace(elem, HistogramSet{compress});
189  }
190  }
191  for(auto& elem: _histogramDefs) {
192  elem.second.setKeepErrors(elem.second.shouldKeepErrors() || *getSetting<bool>("KeepErrors"));
193  }
194  _initialized = true;
195  }
196 
197  void Histos::setEventId(EventUID eventId) {
198  _currentEventId = eventId;
199  }
200 
201  void Histos::clear() {
202  _histograms.clear();
203  _histogramDefs.clear();
204  _currentEventId.clear();
205  _initialized = false;
206  }
207 
208  IndexList Histos::getBinIndices(const string& name, const MD::BinValue& value) const {
209  auto it = _histogramDefs.find(name);
210  if(it != _histogramDefs.end()) {
211  return it->second.getIndexing().valueToPos(value);
212  }
213  throw Error("Histogram name not found. You can't handle the truth!");
214  }
215 
216  size_t Histos::size() const {
217  return _histogramDefs.size();
218  }
219 
220  bool Histos::canFill(const string& name, const vector<double>& values) {
221  auto it = _histogramDefs.find(name);
222  if(it != _histogramDefs.end()) {
223  return it->second.getIndexing().isValid(values);
224  }
225  MSG_ERROR(string("Can't find name ") + string(name) + string(" in histogram request."));
226  return false;
227  }
228 
229  void Histos::checkExists(const string& name) {
230  auto it = _histograms.find(name);
231  if(it == _histograms.end()) {
232  MSG_ERROR(string("The histogram '") + string(name) + string("' does not exist. The Dude does not abide."));
233  }
234  }
235 
236  const HistogramSet* Histos::getEntry(const string& name, const string& scheme) const {
237  auto it = _histograms.find(name);
238  if(it != _histograms.end()) {
239  auto it2 = it->second.find(scheme);
240  if(it2 != it->second.end()) {
241  return &it2->second;
242  }
243  MSG_ERROR(string("Can't find scheme ") + string(scheme) + string(" in histogram request. Returning empty histogram list. Hey Stella!!! (Check addHistogram is applied before initRun)"));
244  return nullptr;
245  }
246  MSG_ERROR(string("Can't find name ") + string(name) + string(" in histogram request. Returning empty histogram list. Hey Stella!!! (Check addHistogram is applied before initRun)"));
247  return nullptr;
248  }
249 
250  HistogramSet* Histos::getEntry(const string& name, const string& scheme) {
251  auto it = _histograms.find(name);
252  if(it != _histograms.end()) {
253  auto it2 = it->second.find(scheme);
254  if(it2 != it->second.end()) {
255  return &it2->second;
256  }
257  MSG_ERROR(string("Can't find scheme ") + string(scheme) + string(" in histogram request. Returning empty histogram list. Hey Stella!!! (Check addHistogram is applied before initRun)"));
258  return nullptr;
259  }
260  MSG_ERROR(string("Can't find name ") + string(name) + string(" in histogram request. Returning empty histogram list. Hey Stella!!! (Check addHistogram is applied before initRun)"));
261  return nullptr;
262  }
263 
264  EventUIDGroup Histos::getHistogramEventIds(const string& name, const string& scheme) const {
265  auto entry = getEntry(name, scheme);
266  if(entry != nullptr) {
267  return entry->getEventIdsInHistogram();
268  }
269  MSG_ERROR("Wrong name/scheme in histogram request. Returning empty eventID list.");
270  return EventUIDGroup{};
271  }
272 
273 
274 
275  MD::BinEdgeList Histos::getHistogramEdges(const string& name) const {
276  auto it = _histogramDefs.find(name);
277  if(it != _histogramDefs.end()) {
278  return it->second.getIndexing().edges();
279  }
280  MSG_ERROR(string("Can't find name ") + string(name) +
281  string(" in histogram request. Returning empty bin edges list. Hey Stella!!! (Check addHistogram is "
282  "applied before initRun)"));
283  return {};
284  }
285 
286  IndexList Histos::getHistogramShape(const string& name) const {
287  auto it = _histogramDefs.find(name);
288  if (it != _histogramDefs.end()) {
289  return it->second.getIndexing().dims();
290  }
291  MSG_ERROR(string("Can't find name ") + string(name) +
292  string(" in histogram request. Returning empty bin edges list. Hey Stella!!! (Check addHistogram is "
293  "applied before initRun)"));
294  return {};
295  }
296 
297  bool Histos::getUnderOverFlows(const string& name) const {
298  auto it = _histogramDefs.find(name);
299  if (it != _histogramDefs.end()) {
300  return it->second.getIndexing().hasUnderOverFlow();
301  }
302  MSG_ERROR(string("Can't find name ") + string(name) +
303  string(" in histogram request."));
304  return false;
305  }
306 
307  vector<Tensor> Histos::getExternalData(const string& scheme, vector<LabelsList> labels) const {
308  vector<Tensor> result;
309  result.reserve(labels.size());
310  transform(labels.begin(), labels.end(), back_inserter(result),
311  [this, &scheme](LabelsList val) -> const Tensor& {
312  return _dictionaries->externalData().getExternalVectors(scheme, val);
313  });
314  return result;
315  }
316 
317  EventIdGroupDict<IOHistogram> Histos::getHistograms(const string& name, const string& scheme) const {
318  auto entry = getEntry(name, scheme);
319  if(entry != nullptr) {
320  auto externalData = getExternalData(scheme, entry->getHistogramLabels());
321  return entry->specializeEventHistograms(externalData);
322  }
323  MSG_ERROR("Wrong name/scheme in histogram request. Returning empty histogram map");
325  }
326 
327  IOHistogram Histos::getHistogram(const string& name, const string& scheme) const {
328  auto entry = getEntry(name, scheme);
329  if(entry != nullptr) {
330  auto externalData = getExternalData(scheme, entry->getHistogramLabels());
331  return entry->specializeSumHistogram(externalData);
332  }
333  MSG_ERROR("Wrong name/scheme in histogram request. Returning empty histogram.");
334  return IOHistogram{};
335  }
336 
337  vector<string> Histos::getHistogramNames() const {
338  vector<string> result;
339  transform(_histogramDefs.begin(), _histogramDefs.end(), back_inserter(result), [](const pair<string, HistogramDefinition>& val) -> string { return val.first; });
340  return result;
341  }
342 
343  vector<EventUID> Histos::getEventIDRepsForHisto(const string& name, const string& scheme) const {
344  auto entry = getEntry(name, scheme);
345  if(entry != nullptr) {
346  return entry->getEventUIDRepresentatives();
347  }
348  return {};
349  }
350 
351 // IOHistogram Histos::getHistogram(const string& name, const string& scheme) const {
352 // auto entry = getEntry(name, scheme);
353 // if(entry != nullptr && entry->size() > 0) {
354 // IOHistogram result;
355 // for(auto it = begin(*entry); it != end(*entry); ++it) {
356 // if(it->second) {
357 // if(result.size() == 0) {
358 // result = it->second->evalToList(externalData);
359 // }
360 // else {
361 // auto result_temp = it->second->evalToList(externalData);
362 // transform(result.begin(), result.end(), result_temp.begin(),
363 // result.begin(), plus<BinContents>());
364 // }
365 // }
366 // }
367 // return result;
368 // }
369 // MSG_ERROR("Wrong name/scheme in histogram request. Returning empty histogram list");
370 // return IOHistogram{};
371 // }
372 
373  bool Histos::isValidHistogram(const string& name, size_t dim) const {
374  auto it = _histogramDefs.find(name);
375  if (it == _histogramDefs.end())
376  return false;
377  bool valid = true;
378  auto& def = it->second;
379  valid &= (def.getIndexing().rank() == dim);
380  return valid;
381  }
382 
383 #ifdef HAVE_ROOT
384 
385  static unique_ptr<TH1D> createTH1D(const string& name, const vector<vector<double>>& edges) {
386  Int_t nbinsX = static_cast<Int_t>(edges[0].size()) - 1;
387  unique_ptr<TH1D> result(new TH1D{name.c_str(), name.c_str(), nbinsX, edges[0].data()});
388  return result;
389  }
390 
391  static unique_ptr<TH2D> createTH2D(const string& name, const vector<vector<double>>& edges) {
392  Int_t nbinsX = static_cast<Int_t>(edges[0].size()) - 1;
393  Int_t nbinsY = static_cast<Int_t>(edges[1].size()) - 1;
394  unique_ptr<TH2D> result(new TH2D{name.c_str(), name.c_str(), nbinsX, edges[0].data(), nbinsY, edges[1].data()});
395  return result;
396  }
397 
398  static unique_ptr<TH3D> createTH3D(const string& name, const vector<vector<double>>& edges) {
399  Int_t nbinsX = static_cast<Int_t>(edges[0].size()) - 1;
400  Int_t nbinsY = static_cast<Int_t>(edges[1].size()) - 1;
401  Int_t nbinsZ = static_cast<Int_t>(edges[2].size()) - 1;
402  unique_ptr<TH3D> result(new TH3D{name.c_str(), name.c_str(), nbinsX, edges[0].data(), nbinsY, edges[1].data(), nbinsZ, edges[2].data()});
403  return result;
404  }
405 
406  static void evalToTH1D(const IOHistogram& input, const IndexList& dimensions,
407  TH1D& rootHistogram, bool hasUnderOverFlow, bool add = false) {
408  ASSERT(dimensions.size() == 1);
409  size_t base = hasUnderOverFlow ? 0 : 1;
410  ASSERT(rootHistogram.GetNbinsX() + 2 * (1 - base) == dimensions[0]);
411  double entries = 0.;
412  array<double, 4> stats;
413  if (add) {
414  entries = rootHistogram.GetEntries();
415  rootHistogram.GetStats(stats.data());
416  }
417  for (IndexType i1 = 0; i1 < dimensions[0]; ++i1) {
418  double value = input[i1].sumWi;
419  double err2 = input[i1].sumWi2;
420  stats[0] += value;
421  stats[1] += err2;
422  if (add) {
423  value += rootHistogram.GetBinContent(static_cast<Int_t>(i1 + base));
424  err2 += pow(rootHistogram.GetBinError(static_cast<Int_t>(i1 + base)), 2);
425  }
426  rootHistogram.SetBinContent(static_cast<Int_t>(i1 + base), value);
427  rootHistogram.SetBinError(static_cast<Int_t>(i1 + base), sqrt(err2));
428  entries += static_cast<double>(input[i1].n);
429  }
430  rootHistogram.SetEntries(entries);
431  rootHistogram.PutStats(stats.data());
432  }
433 
434  static void evalToTH2D(const IOHistogram& input, const IndexList& dimensions, TH2D& rootHistogram,
435  function<PositionType(const IndexList&)>& calcCoords, bool hasUnderOverFlow, bool add = false) {
436  ASSERT(dimensions.size() == 2);
437  size_t base = hasUnderOverFlow ? 0 : 1;
438  ASSERT(rootHistogram.GetNbinsX() + 2 * (1 - base) == dimensions[0]);
439  ASSERT(rootHistogram.GetNbinsY() + 2 * (1 - base) == dimensions[1]);
440  double entries = 0;
441  array<double, 7> stats;
442  if (add) {
443  entries = rootHistogram.GetEntries();
444  rootHistogram.GetStats(stats.data());
445  }
446  for (IndexType i1 = 0; i1 < dimensions[0]; ++i1) {
447  for (IndexType i2 = 0; i2 < dimensions[1]; ++i2) {
448  double value = input[calcCoords({i1, i2})].sumWi;
449  double err2 = input[calcCoords({i1, i2})].sumWi2;
450  stats[0] += value;
451  stats[1] += err2;
452  if (add) {
453  value += rootHistogram.GetBinContent(static_cast<Int_t>(i1 + base), static_cast<Int_t>(i2 + base));
454  err2 +=
455  pow(rootHistogram.GetBinError(static_cast<Int_t>(i1 + base), static_cast<Int_t>(i2 + base)), 2);
456  }
457  rootHistogram.SetBinContent(static_cast<Int_t>(i1 + base), static_cast<Int_t>(i2 + base), value);
458  rootHistogram.SetBinError(static_cast<Int_t>(i1 + base), static_cast<Int_t>(i2 + base), sqrt(err2));
459  entries += static_cast<double>(input[calcCoords({i1, i2})].n);
460  }
461  }
462  rootHistogram.SetEntries(entries);
463  rootHistogram.PutStats(stats.data());
464  }
465 
466  static void evalToTH3D(const IOHistogram& input, const IndexList& dimensions, TH3D& rootHistogram,
467  function<PositionType(const IndexList&)>& calcCoords, bool hasUnderOverFlow,
468  bool add = false) {
469  ASSERT(dimensions.size() == 3);
470  size_t base = hasUnderOverFlow ? 0 : 1;
471  ASSERT(rootHistogram.GetNbinsX() + 2 * (1 - base) == dimensions[0]);
472  ASSERT(rootHistogram.GetNbinsY() + 2 * (1 - base) == dimensions[1]);
473  ASSERT(rootHistogram.GetNbinsZ() + 2 * (1 - base) == dimensions[2]);
474  double entries = 0;
475  array<double, 11> stats;
476  if (add) {
477  entries = rootHistogram.GetEntries();
478  rootHistogram.GetStats(stats.data());
479  }
480  for (IndexType i1 = 0; i1 < dimensions[0]; ++i1) {
481  for (IndexType i2 = 0; i2 < dimensions[1]; ++i2) {
482  for (IndexType i3 = 0; i3 < dimensions[2]; ++i3) {
483  double value = input[calcCoords({i1, i2, i3})].sumWi;
484  double err2 = input[calcCoords({i1, i2, i3})].sumWi2;
485  stats[0] += value;
486  stats[1] += err2;
487  if (add) {
488  value +=
489  rootHistogram.GetBinContent(static_cast<Int_t>(i1 + base), static_cast<Int_t>(i2 + base),
490  static_cast<Int_t>(i3 + base));
491  err2 +=
492  pow(rootHistogram.GetBinError(static_cast<Int_t>(i1 + base), static_cast<Int_t>(i2 + base),
493  static_cast<Int_t>(i3 + base)),
494  2);
495  }
496  rootHistogram.SetBinContent(static_cast<Int_t>(i1 + base), static_cast<Int_t>(i2 + base),
497  static_cast<Int_t>(i3 + base), value);
498  rootHistogram.SetBinError(static_cast<Int_t>(i1 + base), static_cast<Int_t>(i2 + base),
499  static_cast<Int_t>(i3 + base), sqrt(err2));
500  entries += static_cast<double>(input[calcCoords({i1, i2, i3})].n);
501  }
502  }
503  }
504  rootHistogram.SetEntries(entries);
505  rootHistogram.PutStats(stats.data());
506  }
507 
508  bool Histos::isValidHistogram(const string& name, const TH1D& h) const {
509  auto it = _histogramDefs.find(name);
510  if (it == _histogramDefs.end())
511  return false;
512  bool valid = true;
513  auto& def = it->second;
514  valid &= (def.getIndexing().rank() == 1);
515  if(valid) {
516  size_t base = def.getIndexing().hasUnderOverFlow() ? 1 : 0;
517  valid &= (h.GetNbinsX() + 2 * base == def.getIndexing().dims()[0]);
518  }
519  return valid;
520  }
521 
522  bool Histos::isValidHistogram(const string& name, const TH2D& h) const {
523  auto it = _histogramDefs.find(name);
524  if (it == _histogramDefs.end())
525  return false;
526  bool valid = true;
527  auto& def = it->second;
528  valid &= (def.getIndexing().rank() == 2);
529  if (valid) {
530  size_t base = def.getIndexing().hasUnderOverFlow() ? 1 : 0;
531  valid &= (h.GetNbinsX() + 2 * base == def.getIndexing().dims()[0]);
532  valid &= (h.GetNbinsY() + 2 * base == def.getIndexing().dims()[1]);
533  }
534  return valid;
535  }
536 
537  bool Histos::isValidHistogram(const string& name, const TH3D& h) const {
538  auto it = _histogramDefs.find(name);
539  if (it == _histogramDefs.end())
540  return false;
541  bool valid = true;
542  auto& def = it->second;
543  valid &= (def.getIndexing().rank() == 3);
544  if (valid) {
545  size_t base = def.getIndexing().hasUnderOverFlow() ? 1 : 0;
546  valid &= (h.GetNbinsX() + 2 * base == def.getIndexing().dims()[0]);
547  valid &= (h.GetNbinsY() + 2 * base == def.getIndexing().dims()[1]);
548  valid &= (h.GetNbinsZ() + 2 * base == def.getIndexing().dims()[2]);
549  }
550  return valid;
551  }
552 
553 
554  EventIdGroupDict<unique_ptr<TH1D>> Histos::getHistograms1D(const string& name, const string& scheme) const {
555  if(isValidHistogram(name, 1)) {
556  auto hammerHistos = getHistograms(name, scheme);
557  if (hammerHistos.size() > 0) {
558  auto& def = _histogramDefs.find(name)->second;
559  EventIdGroupDict<unique_ptr<TH1D>> result;
560  for (auto it = begin(hammerHistos); it != end(hammerHistos); ++it) {
561  auto th1d = createTH1D(name, def.getIndexing().edges());
562  evalToTH1D(it->second, def.getIndexing().dims(), *th1d, def.getIndexing().hasUnderOverFlow());
563  result.insert(make_pair(it->first, move(th1d)));
564  }
565  return result;
566  }
567  }
568  MSG_ERROR("Wrong name/scheme/dimensionality in histogram request. Returning empty histogram list");
569  return EventIdGroupDict<unique_ptr<TH1D>>{};
570  }
571 
572  EventIdGroupDict<unique_ptr<TH2D>> Histos::getHistograms2D(const string& name, const string& scheme) const {
573  if (isValidHistogram(name, 2)) {
574  auto hammerHistos = getHistograms(name, scheme);
575  if (hammerHistos.size() > 0) {
576  EventIdGroupDict<unique_ptr<TH2D>> result;
577  auto& def = _histogramDefs.find(name)->second;
578  function<PositionType(const IndexList&)> fun = [&](const IndexList& val) -> PositionType { return def.getIndexing().indicesToPos(val); };
579  for (auto it = begin(hammerHistos); it != end(hammerHistos); ++it) {
580  auto th2d = createTH2D(name, def.getIndexing().edges());
581  evalToTH2D(it->second, def.getIndexing().dims(), *th2d, fun, def.getIndexing().hasUnderOverFlow());
582  result.insert(make_pair(it->first, move(th2d)));
583  }
584  return result;
585  }
586  }
587  MSG_ERROR("Wrong name/scheme/dimensionality in histogram request. Returning empty histogram list");
588  return EventIdGroupDict<unique_ptr<TH2D>>{};
589  }
590 
591  EventIdGroupDict<unique_ptr<TH3D>> Histos::getHistograms3D(const string& name, const string& scheme) const {
592  if (isValidHistogram(name, 3)) {
593  auto hammerHistos = getHistograms(name, scheme);
594  if (hammerHistos.size() > 0) {
595  EventIdGroupDict<unique_ptr<TH3D>> result;
596  auto& def = _histogramDefs.find(name)->second;
597  function<PositionType(const IndexList&)> fun = [&](const IndexList& val) -> PositionType { return def.getIndexing().indicesToPos(val); };
598  for (auto it = begin(hammerHistos); it != end(hammerHistos); ++it) {
599  auto th3d = createTH3D(name, def.getIndexing().edges());
600  evalToTH3D(it->second, def.getIndexing().dims(), *th3d, fun, def.getIndexing().hasUnderOverFlow());
601  result.insert(make_pair(it->first, move(th3d)));
602  }
603  return result;
604  }
605  }
606  MSG_ERROR("Wrong name/scheme/dimensionality in histogram request. Returning empty histogram list");
607  return EventIdGroupDict<unique_ptr<TH3D>>{};
608  }
609 
610  unique_ptr<TH1D> Histos::getHistogram1D(const string& name, const string& scheme) const {
611  if (isValidHistogram(name, 1)) {
612  auto hammerHisto = getHistogram(name, scheme);
613  if (hammerHisto.size() > 0) {
614  auto& def = _histogramDefs.find(name)->second;
615  auto th1d = createTH1D(name, def.getIndexing().edges());
616  evalToTH1D(hammerHisto, def.getIndexing().dims(), *th1d, def.getIndexing().hasUnderOverFlow());
617  return th1d;
618  }
619  }
620  MSG_ERROR("Wrong name/scheme/dimensionality in histogram request. Returning empty histogram list");
621  return unique_ptr<TH1D>{};
622  }
623 
624  unique_ptr<TH2D> Histos::getHistogram2D(const string& name, const string& scheme) const {
625  if (isValidHistogram(name, 2)) {
626  auto hammerHisto = getHistogram(name, scheme);
627  if (hammerHisto.size() > 0) {
628  auto& def = _histogramDefs.find(name)->second;
629  function<PositionType(const IndexList&)> fun =
630  [&](const IndexList& val) -> PositionType { return def.getIndexing().indicesToPos(val); };
631  auto th2d = createTH2D(name, def.getIndexing().edges());
632  evalToTH2D(hammerHisto, def.getIndexing().dims(), *th2d, fun, def.getIndexing().hasUnderOverFlow());
633  return th2d;
634  }
635  }
636  MSG_ERROR("Wrong name/scheme/dimensionality in histogram request. Returning empty histogram list");
637  return unique_ptr<TH2D>{};
638  }
639 
640  unique_ptr<TH3D> Histos::getHistogram3D(const string& name, const string& scheme) const {
641  if (isValidHistogram(name, 3)) {
642  auto hammerHisto = getHistogram(name, scheme);
643  if (hammerHisto.size() > 0) {
644  auto& def = _histogramDefs.find(name)->second;
645  function<PositionType(const IndexList&)> fun =
646  [&](const IndexList& val) -> PositionType { return def.getIndexing().indicesToPos(val); };
647  auto th3d = createTH3D(name, def.getIndexing().edges());
648  evalToTH3D(hammerHisto, def.getIndexing().dims(), *th3d, fun, def.getIndexing().hasUnderOverFlow());
649  return th3d;
650  }
651  }
652  MSG_ERROR("Wrong name/scheme/dimensionality in histogram request. Returning empty histogram list");
653  return unique_ptr<TH3D>{};
654  }
655 
656  void Histos::setHistogram1D(const string& name, const string& scheme,
657  TH1D& rootHistogram) const {
658  if (isValidHistogram(name, rootHistogram)) {
659  auto hammerHisto = getHistogram(name, scheme);
660  if (hammerHisto.size() > 0) {
661  auto& def = _histogramDefs.find(name)->second;
662  evalToTH1D(hammerHisto, def.getIndexing().dims(), rootHistogram, def.getIndexing().hasUnderOverFlow());
663  }
664  else {
665  MSG_ERROR(string("Wrong scheme in setting ROOT histogram '") + name + string("'. Not set."));
666  }
667  }
668  else {
669  MSG_ERROR(string("The Hammer and ROOT histograms corresponding to '") + name + string("' have incompatible layouts. Not set."));
670  }
671  }
672 
673  void Histos::setHistogram2D(const string& name, const string& scheme,
674  TH2D& rootHistogram) const {
675  if (isValidHistogram(name, rootHistogram)) {
676  auto hammerHisto = getHistogram(name, scheme);
677  if (hammerHisto.size() > 0) {
678  auto& def = _histogramDefs.find(name)->second;
679  function<PositionType(const IndexList&)> fun =
680  [&](const IndexList& val) -> PositionType { return def.getIndexing().indicesToPos(val); };
681  evalToTH2D(hammerHisto, def.getIndexing().dims(), rootHistogram, fun, def.getIndexing().hasUnderOverFlow());
682  }
683  else {
684  MSG_ERROR(string("Wrong scheme in setting ROOT histogram '") + name + string("'. Not set."));
685  }
686  }
687  else {
688  MSG_ERROR(string("The Hammer and ROOT histograms corresponding to '") + name + string("' have incompatible layouts. Not set."));
689  }
690  }
691 
692  void Histos::setHistogram3D(const string& name, const string& scheme,
693  TH3D& rootHistogram) const {
694  if (isValidHistogram(name, rootHistogram)) {
695  auto hammerHisto = getHistogram(name, scheme);
696  if (hammerHisto.size() > 0) {
697  auto& def = _histogramDefs.find(name)->second;
698  function<PositionType(const IndexList&)> fun =
699  [&](const IndexList& val) -> PositionType { return def.getIndexing().indicesToPos(val); };
700  evalToTH3D(hammerHisto, def.getIndexing().dims(), rootHistogram, fun, def.getIndexing().hasUnderOverFlow());
701  }
702  else {
703  MSG_ERROR(string("Wrong scheme in setting ROOT histogram '") + name + string("'. Not set."));
704  }
705  }
706  else {
707  MSG_ERROR(string("The Hammer and ROOT histograms corresponding to '") + name + string("' have incompatible layouts. Not set."));
708  }
709  }
710 
711  void Histos::setHistograms1D(const string& name, const string& scheme,
712  EventIdGroupDict<unique_ptr<TH1D>>& rootHistograms) const {
713  if (isValidHistogram(name, *(rootHistograms.begin()->second))) {
714  auto hammerHistos = getHistograms(name, scheme);
715  if (hammerHistos.size() > 0) {
716  auto& def = _histogramDefs.find(name)->second;
717  for (auto it = begin(hammerHistos); it != end(hammerHistos); ++it) {
718  auto itRoot = rootHistograms.find(it->first);
719  if(itRoot == rootHistograms.end()) {
720  auto th1d = createTH1D(name, def.getIndexing().edges());
721  auto res = rootHistograms.insert(make_pair(it->first, move(th1d)));
722  itRoot = res.first;
723  }
724  evalToTH1D(it->second, def.getIndexing().dims(), *(itRoot->second), def.getIndexing().hasUnderOverFlow());
725  }
726  }
727  else {
728  MSG_ERROR(string("Wrong scheme in setting ROOT histogram '") + name + string("'. Not set."));
729  }
730  }
731  else {
732  MSG_ERROR(string("The Hammer and ROOT histograms corresponding to '") + name + string("' have incompatible layouts. Not set."));
733  }
734  }
735 
736  void Histos::setHistograms2D(const string& name, const string& scheme,
737  EventIdGroupDict<unique_ptr<TH2D>>& rootHistograms) const {
738  if (isValidHistogram(name, *(rootHistograms.begin()->second))) {
739  auto hammerHistos = getHistograms(name, scheme);
740  if (hammerHistos.size() > 0) {
741  auto& def = _histogramDefs.find(name)->second;
742  function<PositionType(const IndexList&)> fun =
743  [&](const IndexList& val) -> PositionType { return def.getIndexing().indicesToPos(val); };
744  for (auto it = begin(hammerHistos); it != end(hammerHistos); ++it) {
745  auto itRoot = rootHistograms.find(it->first);
746  if (itRoot == rootHistograms.end()) {
747  auto th2d = createTH2D(name, def.getIndexing().edges());
748  auto res = rootHistograms.insert(make_pair(it->first, move(th2d)));
749  itRoot = res.first;
750  }
751  evalToTH2D(it->second, def.getIndexing().dims(), *(itRoot->second), fun, def.getIndexing().hasUnderOverFlow());
752  }
753  }
754  else {
755  MSG_ERROR(string("Wrong scheme in setting ROOT histogram '") + name + string("'. Not set."));
756  }
757  }
758  else {
759  MSG_ERROR(string("The Hammer and ROOT histograms corresponding to '") + name + string("' have incompatible layouts. Not set."));
760  }
761  }
762 
763  void Histos::setHistograms3D(const string& name, const string& scheme,
764  EventIdGroupDict<unique_ptr<TH3D>>& rootHistograms) const {
765  if (isValidHistogram(name, *(rootHistograms.begin()->second))) {
766  auto hammerHistos = getHistograms(name, scheme);
767  if (hammerHistos.size() > 0) {
768  auto& def = _histogramDefs.find(name)->second;
769  function<PositionType(const IndexList&)> fun =
770  [&](const IndexList& val) -> PositionType { return def.getIndexing().indicesToPos(val); };
771  for (auto it = begin(hammerHistos); it != end(hammerHistos); ++it) {
772  auto itRoot = rootHistograms.find(it->first);
773  if (itRoot == rootHistograms.end()) {
774  auto th3d = createTH3D(name, def.getIndexing().edges());
775  auto res = rootHistograms.insert(make_pair(it->first, move(th3d)));
776  itRoot = res.first;
777  }
778  evalToTH3D(it->second, def.getIndexing().dims(), *(itRoot->second), fun, def.getIndexing().hasUnderOverFlow());
779  }
780  }
781  else {
782  MSG_ERROR(string("Wrong scheme in setting ROOT histogram '") + name + string("'. Not set."));
783  }
784  }
785  else {
786  MSG_ERROR(string("The Hammer and ROOT histograms corresponding to '") + name + string("' have incompatible layouts. Not set."));
787  }
788  }
789 
790 #endif
791 
792  void Histos::fillHisto(const string& name, const string& scheme, const IndexList& binPosition, Tensor& value, double extraWeight) {
793  auto itDef = _histogramDefs.find(name);
794  if(itDef == _histogramDefs.end()) {
795  MSG_ERROR(string("Unable to find histogram ") + name + string(". Histogram not filled."));
796  return;
797  }
798  LabelsList newlabs = value.labels();
799  IndexList newdims = value.dims();
800  Tensor temp = itDef->second.getFixedData(_currentEventId, scheme, newlabs);
801  bool processed = false;
802  if (temp.rank() > 0) {
803  temp.dot(value);
804  newlabs = temp.labels();
805  newdims = temp.dims();
806  if (!isZero(extraWeight - 1.0)) {
807  temp *= extraWeight;
808  }
809  processed = true;
810  }
811  else {
812  if (!isZero(extraWeight - 1.0)) {
813  temp = value * extraWeight;
814  processed = true;
815  }
816  }
817  auto entry = getEntry(name, scheme);
818  if(entry == nullptr) {
819  MSG_ERROR(string("Unable to find histogram ") + name + string(". Histogram not filled."));
820  return;
821  }
822  Histogram* histo = entry->getHistogram(_currentEventId);
823  if(histo == nullptr) {
824  auto id = entry->addEventId(_currentEventId, newlabs);
825  histo = entry->getHistogram(id);
826  if(histo == nullptr) {
827  histo = entry->addHistogram(id, makeHistogram(name, itDef->second, newdims, newlabs));
828  }
829  }
830  if(processed) {
831  histo->fillBin(temp, binPosition);
832  }
833  else {
834  histo->fillBin(value, binPosition);
835  }
836  }
837 
838  Log& Histos::getLog() const {
839  return Log::getLog("Hammer.Histos");
840  }
841 
842  void Histos::defineSettings() {
843  setPath("Histos");
844  addSetting<bool>("KeepErrors", false);
845  }
846 
847  bool Histos::writeDefinition(flatbuffers::FlatBufferBuilder* msgwriter, const string& name) const {
848  auto ithisto = _histogramDefs.find(name);
849  if (ithisto != _histogramDefs.end()) {
850  ithisto->second.write(msgwriter, name);
851  return true;
852  }
853  return false;
854  }
855 
856 
857  bool Histos::writeHistogram(flatbuffers::FlatBufferBuilder* msgwriter, const string& histogramName, const string& schemeName, const EventUID& eventIDs) const {
858  auto ithisto = _histograms.find(histogramName);
859  if (ithisto != _histograms.end()) {
860  auto itscheme = ithisto->second.find(schemeName);
861  if(itscheme != ithisto->second.end()) {
862  auto serialScheme = msgwriter->CreateString(schemeName);
863  auto res = itscheme->second.write(msgwriter, eventIDs);
864  res->add_scheme(serialScheme);
865  auto out = res->Finish();
866  msgwriter->Finish(out);
867  return true;
868  }
869  }
870  return false;
871  }
872 
873 
874  string Histos::readDefinition(const Serial::FBHistoDefinition* msgreader, bool merge) {
875  if (msgreader != nullptr) {
876  auto itdef = _histogramDefs.find(msgreader->name()->c_str());
877  if(itdef == _histogramDefs.end()) {
878  itdef = _histogramDefs.emplace(msgreader->name()->c_str(), HistogramDefinition{msgreader}).first;
879  }
880  else {
881  if(merge) {
882  if(!itdef->second.checkDefinition(msgreader)) {
883  MSG_ERROR("Invalid merge for histogram '" + itdef->first + "': definitions do not match.");
884  return "";
885  }
886  }
887  else {
888  itdef->second = HistogramDefinition{msgreader};
889  }
890  }
891  return itdef->first;
892  }
893  else {
894  MSG_ERROR("Invalid record for histogram definition");
895  return "";
896  }
897  }
898 
899  HistoInfo Histos::readHistogram(const Serial::FBHistogram* msgreader, bool merge) {
900  if (msgreader != nullptr) {
901  auto ithisto = _histograms.find(msgreader->name()->c_str());
902  if(ithisto == _histograms.end()) {
903  auto res = _histograms.emplace(msgreader->name()->c_str(), SchemeDict<HistogramSet>{});
904  if(!res.second) {
905  MSG_ERROR(string("Unable to add read histogram '") + msgreader->name()->c_str() + string("'."));
906  return HistoInfo{"", "", EventUIDGroup{}};
907  }
908  ithisto = res.first;
909  }
910  auto itscheme = ithisto->second.find(msgreader->scheme()->c_str());
911  if(itscheme == ithisto->second.end()) {
912  auto res2 = ithisto->second.emplace(msgreader->scheme()->c_str(), HistogramSet{});
913  if(!res2.second) {
914  MSG_ERROR(string("Unable to add read histogram '") + ithisto->first + string("'."));
915  return HistoInfo{"", "", EventUIDGroup{}};
916  }
917  itscheme = res2.first;
918  }
919  auto itdef = _histogramDefs.find(ithisto->first);
920  if(itdef == _histogramDefs.end()) {
921  MSG_ERROR(string("Unable to add read histogram '") + ithisto->first + string("': definition not found."));
922  return HistoInfo{"", "", EventUIDGroup{}};
923  }
924  auto result = itscheme->second.read(msgreader, itdef->second, merge);
925  if(result.size() > 0) {
926  return HistoInfo{ithisto->first, itscheme->first, result};
927  }
928  else {
929  MSG_ERROR("Invalid merge for histogram '" + ithisto->first + "'");
930  return HistoInfo{"", "", EventUIDGroup{}};
931  }
932  }
933  else {
934  MSG_ERROR("Invalid record for histogram");
935  return HistoInfo{"", "", EventUIDGroup{}};
936  }
937  }
938 
939 } // namespace Hammer
std::set< ProcessUID > EventUID
Definition: IndexTypes.hh:53
const MD::BinnedIndexing< MD::SequentialIndexing > & getIndexing() const
Multidimensional histogram class with Tensor as cell bins.
Definition: Histogram.hh:39
LabelsList labels() const
get the labels of all the indices at once
Definition: Tensor.cc:83
~Histos() noexcept
Definition: Histos.cc:38
size_t PositionType
#define ASSERT(x)
Definition: Exceptions.hh:95
Container class for values of WC and FF vectors.
std::vector< std::vector< double >> BinEdgeList
std::vector< BinContents > IOHistogram
Definition: IOTypes.hh:132
std::set< EventUID > EventUIDGroup
Definition: IndexTypes.hh:56
Non-sparse tensor indexer.
Message logging routines.
uint16_t IndexType
Hammer histogram manager.
std::map< std::string, T > HistoNameDict
Definition: Histos.fhh:21
std::shared_ptr< IContainer > SharedTensorData
size_t rank() const
rank of the tensor
Definition: Tensor.cc:75
auto begin(reversion_wrapper< T > w)
Definition: Tools/Utils.hh:79
Hammer histogram class.
HistoNameDict< SchemeDict< HistogramSet > > _histograms
Definition: Histos.hh:278
std::vector< IndexType > IndexList
Logging class.
Definition: Logging.hh:33
HistoNameDict< HistogramDefinition > _histogramDefs
Definition: Histos.hh:277
UMap< EventUIDGroup, T > EventIdGroupDict
Definition: IndexTypes.hh:58
Multidimensional tensor class with complex numbers as elements.
Definition: Tensor.hh:33
Generic error class.
Definition: Exceptions.hh:23
bool isZero(const std::complex< double > val)
Definition: Math/Utils.hh:25
void clear()
Definition: Histos.cc:201
ROOT includes.
Container class for Scheme Definitions.
std::vector< IndexLabel > LabelsList
std::map< SchemeName, T > SchemeDict
Definition: IndexTypes.hh:64
Tensor & dot(const Tensor &other, const UniqueLabelsList &indices={})
contract this tensor with another and stores the result in this tensor
Definition: Tensor.cc:114
DictionaryManager * _dictionaries
Definition: Histos.hh:280
#define MSG_ERROR(x)
Definition: Logging.hh:367
Binned tensor (histogram) indexer.
IndexList dims() const
get the dimensions of all the indices at once
Definition: Tensor.cc:79
std::vector< BinRange > BinRangeList
void fillBin(const Tensor &value, Args...rest)
set the value of a histogram bin based on the bin indices
void addHistogramDefinition(const std::string &histogramName, const IndexList &binSizes, bool hasUnderOverFlow=true, const MD::BinRangeList &ranges={}, bool shouldCompress=false, bool withErrors=false)
Definition: Histos.cc:43
auto end(reversion_wrapper< T > w)
Definition: Tools/Utils.hh:84
Serialization related typedefs and includes.
std::vector< double > BinValue
Global container class for amplitudes, rates, FFs, data.