ATLAS Offline Software
HistogramFactory.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
5 
6 #include "TH1.h"
7 #include "TH2.h"
8 #include "TProfile.h"
9 #include "TProfile2D.h"
10 #include "TTree.h"
11 #include "TROOT.h"
12 
13 #include "HistogramException.h"
14 #include "HistogramFactory.h"
15 
16 using namespace Monitored;
17 
19  const std::string& histoPath)
20 : m_histSvc(histSvc)
21 {
22  size_t whereToStart = 0;
23  // do we have a leading slash? This distinguishes temporary streams in THistSvc
24  if (! histoPath.empty() && histoPath[0] == '/') {
25  whereToStart = 1;
26  }
27  size_t split = histoPath.find('/', whereToStart);
28  m_streamName = (whereToStart == 1 ? "/" : "") + histoPath.substr(0,split);
29  m_groupName = split!=std::string::npos ? histoPath.substr(split+1) : "";
30  // Infrequently, loading a ROOT class in a MT context can fail.
31  // So try to load the classes we'll need early.
32  TClass::GetClass("TH1F");
33  TClass::GetClass("TH1D");
34  TClass::GetClass("TH1C");
35  TClass::GetClass("TH1S");
36  TClass::GetClass("TH1I");
37  TClass::GetClass("TH2F");
38  TClass::GetClass("TH2D");
39  TClass::GetClass("TH2C");
40  TClass::GetClass("TH2S");
41  TClass::GetClass("TH2I");
42  TClass::GetClass("TProfile");
43  TClass::GetClass("TProfile2D");
44  TClass::GetClass("TEfficiency");
45  TClass::GetClass("TTree");
46 }
47 
48 
50  std::scoped_lock lock(m_createLock);
51  TNamed* rootObj(0);
52 
53  if (def.type == "TH1F") {
54  rootObj = create1D<TH1F>(def);
55  } else if (def.type == "TH1D") {
56  rootObj = create1D<TH1D>(def);
57  } else if (def.type == "TH1C") {
58  rootObj = create1D<TH1C>(def);
59  } else if (def.type == "TH1S") {
60  rootObj = create1D<TH1S>(def);
61  } else if (def.type == "TH1I") {
62  rootObj = create1D<TH1I>(def);
63  } else if (def.type == "TH2F") {
64  rootObj = create2D<TH2F>(def);
65  } else if (def.type == "TH2D") {
66  rootObj = create2D<TH2D>(def);
67  } else if (def.type == "TH2C") {
68  rootObj = create2D<TH2C>(def);
69  } else if (def.type == "TH2S") {
70  rootObj = create2D<TH2S>(def);
71  } else if (def.type == "TH2I") {
72  rootObj = create2D<TH2I>(def);
73  } else if (def.type == "TProfile") {
74  rootObj = create1DProfile<TProfile>(def);
75  } else if (def.type == "TProfile2D") {
76  rootObj = create2DProfile<TProfile2D>(def);
77  } else if (def.type == "TEfficiency") {
79  } else if (def.type == "TTree") {
80  rootObj = createTree(def);
81  }
82 
83  if (rootObj == 0) {
84  throw HistogramException("Can not create yet histogram of type: >" + def.type + "<\n" +
85  "Try one of: TH1[F,D,C,S,I], TH2[F,D,C,S,I], TProfile, TProfile2D, " +
86  "TEfficiency, TTree.");
87  }
88 
89  return rootObj;
90 }
91 
92 template<class H>
94  if ( def.xarray.size()!=0 ) {
95  return create<H,TH1>(def, def.xbins, &(def.xarray)[0]);
96  } else {
97  return create<H,TH1>(def, def.xbins, def.xmin, def.xmax);
98  }
99 }
100 
101 template<class H>
103  if (def.xarray.size()!=0) {
104  return create<H,TH1>(def, def.xbins, &(def.xarray)[0],
105  def.ymin, def.ymax);
106  } else {
107  return create<H,TH1>(def, def.xbins, def.xmin, def.xmax,
108  def.ymin, def.ymax);
109  }
110 }
111 
112 template<class H>
114  if (def.xarray.size()!=0 && def.yarray.size()!=0) {
115  return create<H,TH2>(def, def.xbins, &(def.xarray)[0],
116  def.ybins, &(def.yarray)[0]);
117  } else if (def.yarray.size()!=0) {
118  return create<H,TH2>(def, def.xbins, def.xmin, def.xmax,
119  def.ybins, &(def.yarray)[0]);
120  } else if (def.xarray.size()!=0) {
121  return create<H,TH2>(def, def.xbins, &(def.xarray)[0],
122  def.ybins, def.ymin, def.ymax);
123  } else {
124  return create<H,TH2>(def, def.xbins, def.xmin, def.xmax,
125  def.ybins, def.ymin, def.ymax);
126  }
127 }
128 
129 template<class H>
131  if (def.xarray.size()!=0 && def.yarray.size()!=0) {
132  return create<H,TH2>(def, def.xbins, &(def.xarray)[0],
133  def.ybins, &(def.yarray)[0]);
134  } else if (def.yarray.size()!=0) {
135  return create<H,TH2>(def, def.xbins, def.xmin, def.xmax,
136  def.ybins, &(def.yarray)[0]);
137  } else if (def.xarray.size()!=0) {
138  return create<H,TH2>(def, def.xbins, &(def.xarray)[0],
139  def.ybins, def.ymin, def.ymax);
140  } else {
141  return create<H,TH2>(def, def.xbins, def.xmin, def.xmax,
142  def.ybins, def.ymin, def.ymax,
143  def.zmin, def.zmax);
144  }
145 }
146 
148  std::string fullName = getFullName(def);
149 
150  // Check if efficiency exists already
151  TEfficiency* e = nullptr;
152  if ( m_histSvc->existsEfficiency(fullName) ) {
153  if ( !m_histSvc->getEfficiency(fullName,e) ) {
154  throw HistogramException("Histogram >"+ fullName + "< seems to exist but can not be obtained from THistSvc");
155  }
156  return e;
157  }
158 
159  // Otherwise, create the efficiency and register it
160  // Hold global lock until we have detached object from gDirectory
161  {
162  std::scoped_lock<std::mutex> dirLock(globalROOTMutex());
163  if (def.ybins==0 && def.zbins==0) { // 1D TEfficiency
164  if (def.xarray.size()!=0) {
165  e = new TEfficiency(def.alias.c_str(), def.title.c_str(),
166  def.xbins, &(def.xarray)[0]);
167  } else {
168  e = new TEfficiency(def.alias.c_str(), def.title.c_str(),
169  def.xbins, def.xmin, def.xmax);
170  }
171  } else if (def.ybins>0 && def.zbins==0) { // 2D TEfficiency
172  if (def.xarray.size()!=0 && def.yarray.size()!=0) {
173  e = new TEfficiency(def.alias.c_str(), def.title.c_str(),
174  def.xbins, &(def.xarray)[0], def.ybins, &(def.yarray)[0]);
175  } else {
176  e = new TEfficiency(def.alias.c_str(), def.title.c_str(),
177  def.xbins, def.xmin, def.xmax, def.ybins, def.ymin, def.ymax);
178  }
179  } else if (def.ybins>0 && def.zbins>0) { // 3D TEfficiency
180  e = new TEfficiency(def.alias.c_str(), def.title.c_str(),
181  def.xbins, def.xmin, def.xmax, def.ybins, def.ymin, def.ymax, def.zbins, def.zmin, def.zmax);
182  } else {
183  throw HistogramException("Histogram >"+ fullName + "< could not be defined. Check xbins, ybins, and zbins.");
184  }
185  e->SetDirectory(0);
186  }
187  if ( !m_histSvc->regEfficiency(fullName,e) ) {
188  delete e;
189  throw HistogramException("Histogram >"+ fullName + "< can not be registered in THistSvc");
190  }
191  TH1* total ATLAS_THREAD_SAFE = const_cast<TH1*>(e->GetTotalHistogram());
192  setLabels(total, def);
193  TH1* passed ATLAS_THREAD_SAFE = const_cast<TH1*>(e->GetPassedHistogram());
194  setLabels(passed, def);
195 
196  return e;
197 }
198 
199 template<class H, class HBASE, typename... Types>
201  std::string fullName = getFullName(def);
202 
203  // Check if histogram exists already
204  HBASE* histo = nullptr;
205  if ( m_histSvc->exists( fullName ) ) {
206  if ( !m_histSvc->getHist( fullName, histo ) ) {
207  throw HistogramException("Histogram >"+ fullName + "< seems to exist but can not be obtained from THistSvc");
208  }
209  return histo;
210  }
211 
212  // Create the histogram and register it
213  // Hold global lock until we have detached object from gDirectory
214  H* h = nullptr;
215  {
216  std::scoped_lock<std::mutex> dirLock(globalROOTMutex());
217  h = new H(def.alias.c_str(), def.title.c_str(), std::forward<Types>(hargs)...);
218  // cppcheck-suppress nullPointer; false positive
219  h->SetDirectory(0);
220  }
221  if ( !m_histSvc->regHist( fullName, static_cast<TH1*>(h) ) ) {
222  delete h;
223  throw HistogramException("Histogram >"+ fullName + "< can not be registered in THistSvc");
224 
225  }
226  h->GetYaxis()->SetTitleOffset(1.25); // magic shift to make histograms readable even if no post-procesing is done
227 
228  setLabels(h, def);
229  setOpts(h, def);
230 
231  return h;
232 }
233 
235  std::string fullName = getFullName(def);
236 
237  // Check if tree exists already
238  TTree* t = nullptr;
239  if ( m_histSvc->existsTree(fullName) ) {
240  if ( !m_histSvc->getTree(fullName,t) ) {
241  throw HistogramException("Tree >"+ fullName + "< seems to exist but can not be obtained from THistSvc");
242  }
243  return t;
244  }
245 
246  // Otherwise, create the tree and register it
247  // branches will be created by HistogramFillerTree
248  {
249  std::scoped_lock<std::mutex> dirLock(globalROOTMutex());
250  t = new TTree(def.alias.c_str(),def.title.c_str());
251  t->SetDirectory(0);
252  }
253  if ( !m_histSvc->regTree(fullName,std::unique_ptr<TTree>(t) ) ) {
254  throw HistogramException("Tree >"+ fullName + "< can not be registered in THistSvc");
255  }
256  // cppcheck-suppress deallocret; false positive
257  return t;
258 }
259 
261  // apply extension policy
262  const unsigned canExtendPolicy = def.kCanRebin ? TH1::kAllAxes : TH1::kNoAxis;
263  hist->SetCanExtend(canExtendPolicy);
264 
265  // apply Sumw2 option
266  hist->Sumw2(def.Sumw2);
267 }
268 
270  setLabels(hist->GetXaxis(), def.xlabels);
271  setLabels(hist->GetYaxis(), def.ylabels);
272  setLabels(hist->GetZaxis(), def.zlabels);
273 }
274 
275 void HistogramFactory::setLabels(TAxis* axis, const std::vector<std::string>& labels) {
276  if ( !labels.empty() ) {
277  const int nBin = axis->GetNbins();
278  for ( int bin=0; bin<nBin; bin++ ) {
279  axis->SetBinLabel(bin+1, labels[bin].c_str());
280  }
281  }
282 }
283 
284 namespace {
285  const static std::set<std::string> onlinePaths( { "EXPERT", "SHIFT", "DEBUG", "RUNSTAT", "EXPRESS" } );
286 }
287 std::string HistogramFactory::getFullName(const HistogramDef& def) const {
288 
289  // for online paths, always prepend a slash. Otherwise take it from provided stream name
290  std::string path;
291  if ( onlinePaths.count( def.path)!=0 ) {
292  path = "/" + def.path + "/" + m_streamName + "/" + m_groupName;
293  } else if ( def.path=="DEFAULT" ) {
294  path = "/" + m_streamName + "/" + m_groupName;
295  } else {
296  path = m_streamName + "/" + def.tld + "/" + m_groupName + "/" + def.path;
297  }
298 
299  // remove duplicate slashes
300  std::string fullName = path + "/" + def.alias;
301  fullName.erase( std::unique( fullName.begin(), fullName.end(),
302  [](const char a, const char b) {
303  return a == b and a == '/';
304  } ), fullName.end() );
305 
306  return fullName;
307 }
308 
310  std::string path = getFullName( def );
311 
312  bool exists = false;
313  if (def.type=="TEfficiency") {
314  exists = m_histSvc->existsEfficiency(path);
315  } else if (def.type=="TGraph") {
316  exists = m_histSvc->existsGraph(path);
317  } else if (def.type=="TTree") {
318  exists = m_histSvc->existsTree(path);
319  } else {
320  exists = m_histSvc->existsHist(path);
321  }
322 
323  // see docu here:
324  // https://acode-browser1.usatlas.bnl.gov/lxr/source/Gaudi/GaudiSvc/src/THistSvc/THistSvc.h#0146
325  // and here:
326  // https://acode-browser1.usatlas.bnl.gov/lxr/source/athena/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx#0216
327  // online implementation actually claims ownership of the object and we ever need to call this in online situation
328  //
329  if (exists)
330  m_histSvc->deReg(path).ignore(); // we actually ignore if that was sucessfull as we plan to use is eagerly to cleanup LumiBlock histograms history
331 }
Monitored::HistogramFactory::m_createLock
std::mutex m_createLock
Definition: HistogramFactory.h:170
Monitored::HistogramFactory::create
virtual TNamed * create(const HistogramDef &def)
Book and register ROOT object for given definition.
Definition: HistogramFactory.cxx:49
HistogramException.h
Monitored::HistogramDef::kCanRebin
bool kCanRebin
allow all axes to be rebinned
Definition: HistogramDef.h:47
Monitored::HistogramFactory::m_streamName
std::string m_streamName
defines the stream for THistSvc
Definition: HistogramFactory.h:167
Monitored::HistogramFactory::m_groupName
std::string m_groupName
defines location of group of histograms
Definition: HistogramFactory.h:168
athena.path
path
python interpreter configuration --------------------------------------—
Definition: athena.py:126
TrigCompositeUtils::passed
bool passed(DecisionID id, const DecisionIDContainer &idSet)
checks if required decision ID is in the set of IDs in the container
Definition: TrigCompositeUtilsRoot.cxx:117
plotmaker.hist
hist
Definition: plotmaker.py:148
WriteCellNoiseToCool.fullName
fullName
Definition: WriteCellNoiseToCool.py:461
yodamerge_tmp.axis
list axis
Definition: yodamerge_tmp.py:241
Monitored::HistogramDef::zmax
float zmax
z axis maximum
Definition: HistogramDef.h:71
bin
Definition: BinsDiffFromStripMedian.h:43
Monitored::HistogramException
Represents error occurred during accessing histograms objects.
Definition: HistogramException.h:14
Monitored::HistogramFactory::create1D
TH1 * create1D(const HistogramDef &def)
Helper for generic 'create' method for 1D histograms.
Definition: HistogramFactory.cxx:93
Monitored::HistogramDef::xbins
int xbins
number of y bins
Definition: HistogramDef.h:55
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
Monitored::HistogramDef::ylabels
std::vector< std::string > ylabels
labels for y axis
Definition: HistogramDef.h:65
Monitored::HistogramDef
the internal class used to keep parsed Filler properties
Definition: HistogramDef.h:15
D3PD::Types
std::tuple< WrapType< TYPES >... > Types
A simple tuple of multiple types.
Definition: PhysicsAnalysis/D3PDMaker/D3PDMakerUtils/D3PDMakerUtils/Types.h:61
Monitored::HistogramDef::yarray
std::vector< double > yarray
array of y bin edges
Definition: HistogramDef.h:66
Monitored::HistogramDef::tld
std::string tld
top level directory (below THistSvc stream)
Definition: HistogramDef.h:22
Monitored::HistogramFactory::setOpts
static void setOpts(TH1 *hist, const HistogramDef &def)
Setup various histogram options.
Definition: HistogramFactory.cxx:260
Monitored::HistogramFactory::create2DProfile
TH2 * create2DProfile(const HistogramDef &def)
Helper for generic 'create' method for 2DProfile histograms.
Definition: HistogramFactory.cxx:130
Monitored::HistogramFactory::m_histSvc
ServiceHandle< ITHistSvc > m_histSvc
Definition: HistogramFactory.h:166
Monitored::HistogramDef::xarray
std::vector< double > xarray
array of x bin edges
Definition: HistogramDef.h:59
Monitored::HistogramDef::xmax
float xmax
x axis maximum
Definition: HistogramDef.h:57
beamspotnt.labels
list labels
Definition: bin/beamspotnt.py:1447
H
#define H(x, y, z)
Definition: MD5.cxx:114
Monitored::HistogramDef::zbins
int zbins
number of z bins
Definition: HistogramDef.h:69
Monitored::HistogramDef::path
std::string path
booking path
Definition: HistogramDef.h:19
Monitored::HistogramDef::ymax
float ymax
y axis maximum
Definition: HistogramDef.h:64
Monitored::HistogramFactory::setLabels
static void setLabels(TH1 *hist, const HistogramDef &def)
Set labels for all axes.
Definition: HistogramFactory.cxx:269
Monitored
Generic monitoring tool for athena components.
Definition: GenericMonitoringTool.h:30
h
extractSporadic.h
list h
Definition: extractSporadic.py:97
PyPoolBrowser.rootObj
rootObj
Definition: PyPoolBrowser.py:111
Monitored::HistogramDef::xlabels
std::vector< std::string > xlabels
labels for x axis
Definition: HistogramDef.h:58
Monitored::HistogramFactory::getFullName
std::string getFullName(const HistogramDef &def) const
Invent path name.
Definition: HistogramFactory.cxx:287
Monitored::HistogramDef::xmin
float xmin
x axis minimum
Definition: HistogramDef.h:56
Monitored::HistogramFactory::HistogramFactory
HistogramFactory(const ServiceHandle< ITHistSvc > &histSvc, const std::string &groupName)
Default constructor.
Definition: HistogramFactory.cxx:18
MuonSegmentReaderConfig.histSvc
histSvc
Definition: MuonSegmentReaderConfig.py:96
Monitored::HistogramDef::Sumw2
bool Sumw2
store sum of squares of weights
Definition: HistogramDef.h:43
Monitored::HistogramDef::alias
std::string alias
unique alias for THistSvc
Definition: HistogramDef.h:17
Monitored::HistogramDef::ymin
float ymin
y axis minimum
Definition: HistogramDef.h:63
Monitored::HistogramFactory::create1DProfile
TH1 * create1DProfile(const HistogramDef &def)
Helper for generic 'create' method for 1DProfile histograms.
Definition: HistogramFactory.cxx:102
Monitored::HistogramFactory::create2D
TH2 * create2D(const HistogramDef &def)
Helper for generic 'create' method for 2D histograms.
Definition: HistogramFactory.cxx:113
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
Monitored::HistogramFactory::createTree
TTree * createTree(const HistogramDef &def)
Create and register tree.
Definition: HistogramFactory.cxx:234
Monitored::HistogramDef::type
std::string type
class name
Definition: HistogramDef.h:18
Monitored::HistogramFactory::globalROOTMutex
static std::mutex & globalROOTMutex()
Definition: HistogramFactory.h:68
HistogramFactory.h
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
a
TList * a
Definition: liststreamerinfos.cxx:10
sim_check_batch.hargs
list hargs
Definition: sim_check_batch.py:226
Monitored::HistogramDef::zmin
float zmin
z axis minimum
Definition: HistogramDef.h:70
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
python.dummyaccess.exists
def exists(filename)
Definition: dummyaccess.py:9
Monitored::HistogramDef::ybins
int ybins
number of y bins
Definition: HistogramDef.h:62
plotBeamSpotCompare.histo
histo
Definition: plotBeamSpotCompare.py:415
checker_macros.h
Define macros for attributes used to control the static checker.
Monitored::HistogramFactory::remove
virtual void remove(const HistogramDef &def)
Removes histogram (used online to get rid of old LB tagged histograms)
Definition: HistogramFactory.cxx:309
Monitored::HistogramDef::title
std::string title
title of the histogram
Definition: HistogramDef.h:20
Monitored::HistogramDef::zlabels
std::vector< std::string > zlabels
labels for z axis
Definition: HistogramDef.h:72
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
ServiceHandle< ITHistSvc >
Monitored::HistogramFactory::createEfficiency
TEfficiency * createEfficiency(const HistogramDef &def)
Create and register efficiency graph.
Definition: HistogramFactory.cxx:147