3 Create ROOT Histograms from one or more ROOT TTrees or TNtuples. 5 Options are specified in the given configuration file. 14 Copyright (c) 2010 Michael Anderson <mbanderson@wisc.edu> 16 Permission is hereby granted, free of charge, to any person obtaining a copy 17 of this software and associated documentation files (the "Software"), to deal 18 in the Software without restriction, including without limitation the rights 19 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 copies of the Software, and to permit persons to whom the Software is 21 furnished to do so, subject to the following conditions: 23 The above copyright notice and this permission notice shall be included in 24 all copies or substantial portions of the Software. 26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 38 if '-h' in sys.argv
or '--help' in sys.argv:
40 Create ROOT Histograms from one or more ROOT TTrees or TNtuples. 42 Run by specifying configuration file: 45 Create default config file by running with no arguments: 49 from ROOT
import TFile, TTree, TH1F, TH2F, TH3F, gROOT
50 except Exception
as e:
52 print (
"Use a python that has PyROOT installed.")
54 from copy
import deepcopy
56 from array
import array
57 from datetime
import datetime
63 """Wrapper for TTrees and TNtuples, allowing association with 65 def __init__(self, treeName, fileName, scale=1.0, cuts=""):
74 """Wrapper for TH1 objects, associating TTree variables with a histogram""" 75 def __init__(self, treeVariable, histogram, cuts="", storeErrors=True):
78 self.
name = histogram.GetName()
80 if storeErrors: self.histogram.Sumw2()
83 """Joins list of cuts (strings) into something ROOT can handle. 84 Example: given ('1<2','','5>4') returns '1<2&&5>4'""" 85 list_of_nonempty_cuts = []
86 for cut
in list_of_cuts:
88 list_of_nonempty_cuts.append(cut)
89 return '&&'.
join(list_of_nonempty_cuts)
92 timeTaken = end - start
93 hours, remainder = divmod(timeTaken.seconds, 3600)
94 minutes, seconds = divmod(remainder, 60)
96 return "%i hours, %i minutes" % (hours, minutes)
98 return "%i minutes" % minutes
99 return "%i seconds" % seconds
102 """Writes configuration file for tree2hists""" 103 defaultConfig =
'''# Configuration file for tree2hists 106 ## the normal way to import from rootplot 107 from rootplot.tree2hists import RootTree, Plot 109 ## special import for CMSSW installations of rootplot 110 from PhysicsTools.PythonAnalysis.rootplot.tree2hists import RootTree, Plot 111 from array import array # to allow making Float_t arrays for ROOT hists 113 from ROOT import TH1F, TH2F # import other kinds of hists as neeeded 115 list_of_files = [RootTree("Treename", fileName="photons.root", scale=1.0, cuts=""), 116 RootTree("Treename", fileName="photons2.root", scale=1.0, cuts="")] 118 output_filename = "Hists_photons.root" 120 cut_for_all_files = "(!TTBit[36] && !TTBit[37] && !TTBit[38] && !TTBit[39] && !vtxIsFake && vtxNdof>4 && abs(vtxZ)<=15)" 122 # All plots are made for each "cut set". 123 # A "cut set" is 3 things: folder name to store hists in, string to add to hist titles, and cuts for these hists. 124 # Let cut_sets = [] to make all plots. 126 ("barrel15to20", "(|#eta|<1.45, 15<E_{T}<20)", "et>15&&et<20&&abs(eta)<1.45"), 127 ("barrel20to30", "(|#eta|<1.45, 20<E_{T}<30)", "et>20&&et<30&&abs(eta)<1.45"), 128 ("endcap15to20", "(1.7<|#eta|<2.5, 15<E_{T}<20)", "et>15&&et<20&&abs(eta)>1.7&&abs(eta)<2.5"), 129 ("endcap20to30", "(1.7<|#eta|<2.5, 20<E_{T}<30)", "et>20&&et<30&&abs(eta)>1.7&&abs(eta)<2.5") 132 # Define histograms to plot 133 bins_et = array("f", [15.0, 20.0, 30.0, 50.0, 80.0, 120.0]) # example custom bins 135 Plot("et" , TH1F("pho_et" , "Lead #gamma: E_{T};E_{T} (GeV);entries/bin", 25, 0.0, 100.0)), 136 Plot("eta" , TH1F("pho_eta" , "Lead #gamma: #eta;#eta;entries/bin" , 25, -3.0, 3.0)), 137 Plot("et" , TH1F("pho_et_binned" , "Lead #gamma: E_{T};E_{T} (GeV);entries/bin", len(bins_et)-1, bins_et)), 138 Plot("sigmaIetaIeta", TH1F("pho_sigmaIEtaIEta", "Lead #gamma: #sigma_{i#etai#eta};#sigma_{i#etai#eta};entries/bin",20, 0, 0.06)), 139 Plot("metEt/et" , TH1F("metEt_over_phoEt" , "MET / E_{T}(#gamma);MET/E_{T}(sc);entries/bin" , 20, 0.0, 3.0)), 140 Plot("phi:eta" , TH2F("phoPhi_vs_phoEta" , "Lead #gamma: #phi vs #eta;#eta;#phi" , 50, -2.5, 2.5, 18, -pi, pi)) 142 ''' % datetime.now().strftime(
"%b %d, %Y")
143 f = open(
't2h_config.py',
'w')
144 f.write(defaultConfig)
146 print "Created default configuration file: t2h_config.py" 147 print "Edit it, then run by typing:" 148 print " tree2hists t2h_config.py" 152 '''Open root files one at a time, make plots, then close them.''' 153 list_of_plots_to_write = []
156 for set_of_cuts
in list_of_cutSets:
157 histname_fix, title_fix, current_cut_set = set_of_cuts
158 for plot
in list_of_Plots:
159 new_plot = deepcopy(plot)
160 new_title =
' '.
join((plot.histogram.GetTitle(), title_fix))
161 new_plot.histogram.SetTitle(new_title)
162 list_of_plots_to_write.append((new_plot, set_of_cuts))
164 for j, rootTree
in enumerate(list_of_RootTrees):
165 rootTree.tfile = TFile(rootTree.fileName,
"read")
166 if rootTree.tfile.IsZombie():
167 print "Error opening %s, exiting..." % rootTree.fileName
170 rootTree.tfile.GetObject(rootTree.treeName, rootTree.ttree)
172 print "Error: %s not found in %s, exiting..." % (rootTree.treeName,
176 print "\n%s: Opened %s %i MB" % (datetime.now().strftime(
"%I:%M%p"),
178 path.getsize(rootTree.fileName)/1048576)
179 print " %s has %i entries, will plot with scale=%.2e, cuts='%s'" % (rootTree.treeName,
180 rootTree.ttree.GetEntries(),
185 print " # entries var >> histogram" 186 for i, (plot, set_of_cuts)
in enumerate(list_of_plots_to_write):
187 histname_fix, title_fix, current_cut_set = set_of_cuts
188 tmp_hist = plot.histogram.Clone(
"temp")
189 all_cuts =
join_cuts(cut_for_all_files, rootTree.cuts,
190 current_cut_set, plot.cuts)
191 rootTree.ttree.Draw(
"%s >> temp" % plot.treeVariable, all_cuts,
193 tmp_hist.Scale(rootTree.scale)
194 entries_before = plot.histogram.GetEntries()
195 plot.histogram.Add(tmp_hist)
196 entries_after = plot.histogram.GetEntries()
197 print " %3i %7i %20s >> %s/%s" % (i, entries_after-entries_before,
198 plot.treeVariable, histname_fix,
199 plot.histogram.GetName()),
201 print "\textra cuts: %s" % plot.cuts,
204 rootTree.tfile.Close()
205 print "%s: Closed %s" % (datetime.now().strftime(
"%I:%M%p"),
207 return list_of_plots_to_write
214 sys.path.insert(0,
'')
215 _temp = __import__(config_file, globals(), locals(),
216 [
'list_of_files',
'output_filename',
217 'cut_for_all_files',
'cut_sets',
'list_of_plots'], -1)
218 list_of_files = _temp.list_of_files
219 output_filename = _temp.output_filename
220 cut_for_all_files = _temp.cut_for_all_files
221 cut_sets = _temp.cut_sets
222 list_of_plots = _temp.list_of_plots
223 for rootTree
in list_of_files:
224 if not path.isfile(rootTree.fileName):
225 print "Error:\n %s\nnot found for input." % rootTree.fileName
227 hist_names = [plot.name
for plot
in list_of_plots]
228 if len(hist_names)>len(set(hist_names)):
230 print "Error: Each plot needs a unique name, exiting..." 232 if path.isfile(output_filename):
233 print "Warning: %s exists" % output_filename
234 except Exception
as e:
236 print "Error with %s" % config_file
239 if path.isfile(
'rootlogon.C'):
240 print "Loading rootlogon.C" 241 gROOT.Macro(
'rootlogon.C')
244 print "\n%i defined cut sets:" % len(cut_sets)
246 name, title_fix, current_cut_set = cut
247 print " %s\t: '%s'" % (name, current_cut_set)
248 cut_names = [name
for name,num,cut
in cut_sets]
249 if len(cut_names)>len(set(cut_names)):
250 print "Error: Each cut set needs a unique name, exiting..." 253 cut_sets = [(
"",
"",
"")]
255 print "\nCuts to apply to all files:\n\t'%s'" % cut_for_all_files
257 start_time = datetime.now()
262 end_time = datetime.now()
266 outputFile = TFile(output_filename,
"recreate")
267 if outputFile.IsZombie():
268 print "Error opening %s for output exiting..." % output_filename
270 print "\nOpened output file. Saving histograms..." 272 for set_of_cuts
in cut_sets:
273 outputFile.mkdir(set_of_cuts[0])
274 print " # entries histogram" 275 for i, (plot, cutset)
in enumerate(list_of_plots_to_write):
276 outputFile.cd(cutset[0])
277 print " %3i %7i %s/%s" % (i, plot.histogram.GetEntries(),
279 plot.histogram.GetName())
280 plot.histogram.Write()
283 print "\nScaled & added histograms from %i TTrees saved in\n %s" % (len(list_of_files), output_filename)
287 if len(sys.argv) > 1:
288 if path.isfile(sys.argv[1]):
289 config_file = sys.argv[1].
split(
'.')[0]
292 print "%s not found." % sys.argv[1]
293 print(
"Create default config file by running tree2hists " 297 if path.exists(
't2h_config.py'):
298 print "Run with specific config file, like:" 299 print " tree2hists t2h_config.py" 304 if __name__ ==
"__main__":
def join_cuts(list_of_cuts)
def make_all_hists_all_files(list_of_RootTrees, list_of_Plots, cut_for_all_files, list_of_cutSets)
def write_default_T2H_config()
def __init__(self, treeVariable, histogram, cuts="", storeErrors=True)
S & print(S &os, JobReport::InputFile const &f)
def __init__(self, treeName, fileName, scale=1.0, cuts="")
static std::string join(char **cmd)
def duration_to_string(start, end)
Define classes and generators #######################################.
def tree2hists_main(config_file)
Define the main program #############################################.