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