3 Create ROOT Histograms from one or more ROOT TTrees or TNtuples. 5 Options are specified in the given configuration file. 7 from __future__
import print_function
15 Copyright (c) 2010 Michael Anderson <mbanderson@wisc.edu> 17 Permission is hereby granted, free of charge, to any person obtaining a copy 18 of this software and associated documentation files (the "Software"), to deal 19 in the Software without restriction, including without limitation the rights 20 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 copies of the Software, and to permit persons to whom the Software is 22 furnished to do so, subject to the following conditions: 24 The above copyright notice and this permission notice shall be included in 25 all copies or substantial portions of the Software. 27 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 39 if '-h' in sys.argv
or '--help' in sys.argv:
41 Create ROOT Histograms from one or more ROOT TTrees or TNtuples. 43 Run by specifying configuration file: 46 Create default config file by running with no arguments: 50 from ROOT
import TFile, TTree, TH1F, TH2F, TH3F, gROOT
51 except Exception
as e:
53 print (
"Use a python that has PyROOT installed.")
55 from copy
import deepcopy
57 from array
import array
58 from datetime
import datetime
64 """Wrapper for TTrees and TNtuples, allowing association with 66 def __init__(self, treeName, fileName, scale=1.0, cuts=""):
75 """Wrapper for TH1 objects, associating TTree variables with a histogram""" 76 def __init__(self, treeVariable, histogram, cuts="", storeErrors=True):
79 self.
name = histogram.GetName()
81 if storeErrors: self.histogram.Sumw2()
84 """Joins list of cuts (strings) into something ROOT can handle. 85 Example: given ('1<2','','5>4') returns '1<2&&5>4'""" 86 list_of_nonempty_cuts = []
87 for cut
in list_of_cuts:
89 list_of_nonempty_cuts.append(cut)
90 return '&&'.
join(list_of_nonempty_cuts)
93 timeTaken = end - start
94 hours, remainder = divmod(timeTaken.seconds, 3600)
95 minutes, seconds = divmod(remainder, 60)
97 return "%i hours, %i minutes" % (hours, minutes)
99 return "%i minutes" % minutes
100 return "%i seconds" % seconds
103 """Writes configuration file for tree2hists""" 104 defaultConfig =
'''# Configuration file for tree2hists 107 ## the normal way to import from rootplot 108 from rootplot.tree2hists import RootTree, Plot 110 ## special import for CMSSW installations of rootplot 111 from PhysicsTools.PythonAnalysis.rootplot.tree2hists import RootTree, Plot 112 from array import array # to allow making Float_t arrays for ROOT hists 114 from ROOT import TH1F, TH2F # import other kinds of hists as neeeded 116 list_of_files = [RootTree("Treename", fileName="photons.root", scale=1.0, cuts=""), 117 RootTree("Treename", fileName="photons2.root", scale=1.0, cuts="")] 119 output_filename = "Hists_photons.root" 121 cut_for_all_files = "(!TTBit[36] && !TTBit[37] && !TTBit[38] && !TTBit[39] && !vtxIsFake && vtxNdof>4 && abs(vtxZ)<=15)" 123 # All plots are made for each "cut set". 124 # A "cut set" is 3 things: folder name to store hists in, string to add to hist titles, and cuts for these hists. 125 # Let cut_sets = [] to make all plots. 127 ("barrel15to20", "(|#eta|<1.45, 15<E_{T}<20)", "et>15&&et<20&&abs(eta)<1.45"), 128 ("barrel20to30", "(|#eta|<1.45, 20<E_{T}<30)", "et>20&&et<30&&abs(eta)<1.45"), 129 ("endcap15to20", "(1.7<|#eta|<2.5, 15<E_{T}<20)", "et>15&&et<20&&abs(eta)>1.7&&abs(eta)<2.5"), 130 ("endcap20to30", "(1.7<|#eta|<2.5, 20<E_{T}<30)", "et>20&&et<30&&abs(eta)>1.7&&abs(eta)<2.5") 133 # Define histograms to plot 134 bins_et = array("f", [15.0, 20.0, 30.0, 50.0, 80.0, 120.0]) # example custom bins 136 Plot("et" , TH1F("pho_et" , "Lead #gamma: E_{T};E_{T} (GeV);entries/bin", 25, 0.0, 100.0)), 137 Plot("eta" , TH1F("pho_eta" , "Lead #gamma: #eta;#eta;entries/bin" , 25, -3.0, 3.0)), 138 Plot("et" , TH1F("pho_et_binned" , "Lead #gamma: E_{T};E_{T} (GeV);entries/bin", len(bins_et)-1, bins_et)), 139 Plot("sigmaIetaIeta", TH1F("pho_sigmaIEtaIEta", "Lead #gamma: #sigma_{i#etai#eta};#sigma_{i#etai#eta};entries/bin",20, 0, 0.06)), 140 Plot("metEt/et" , TH1F("metEt_over_phoEt" , "MET / E_{T}(#gamma);MET/E_{T}(sc);entries/bin" , 20, 0.0, 3.0)), 141 Plot("phi:eta" , TH2F("phoPhi_vs_phoEta" , "Lead #gamma: #phi vs #eta;#eta;#phi" , 50, -2.5, 2.5, 18, -pi, pi)) 143 ''' % datetime.now().strftime(
"%b %d, %Y")
144 f = open(
't2h_config.py',
'w')
145 f.write(defaultConfig)
147 print(
"Created default configuration file: t2h_config.py")
148 print(
"Edit it, then run by typing:")
149 print(
" tree2hists t2h_config.py")
153 '''Open root files one at a time, make plots, then close them.''' 154 list_of_plots_to_write = []
157 for set_of_cuts
in list_of_cutSets:
158 histname_fix, title_fix, current_cut_set = set_of_cuts
159 for plot
in list_of_Plots:
160 new_plot = deepcopy(plot)
161 new_title =
' '.
join((plot.histogram.GetTitle(), title_fix))
162 new_plot.histogram.SetTitle(new_title)
163 list_of_plots_to_write.append((new_plot, set_of_cuts))
165 for j, rootTree
in enumerate(list_of_RootTrees):
166 rootTree.tfile = TFile(rootTree.fileName,
"read")
167 if rootTree.tfile.IsZombie():
168 print(
"Error opening %s, exiting..." % rootTree.fileName)
171 rootTree.tfile.GetObject(rootTree.treeName, rootTree.ttree)
173 print(
"Error: %s not found in %s, exiting..." % (rootTree.treeName,
177 print(
"\n%s: Opened %s %i MB" % (datetime.now().strftime(
"%I:%M%p"),
179 path.getsize(rootTree.fileName)/1048576))
180 print(
" %s has %i entries, will plot with scale=%.2e, cuts='%s'" % (rootTree.treeName,
181 rootTree.ttree.GetEntries(),
186 print(
" # entries var >> histogram")
187 for i, (plot, set_of_cuts)
in enumerate(list_of_plots_to_write):
188 histname_fix, title_fix, current_cut_set = set_of_cuts
189 tmp_hist = plot.histogram.Clone(
"temp")
190 all_cuts =
join_cuts(cut_for_all_files, rootTree.cuts,
191 current_cut_set, plot.cuts)
192 rootTree.ttree.Draw(
"%s >> temp" % plot.treeVariable, all_cuts,
194 tmp_hist.Scale(rootTree.scale)
195 entries_before = plot.histogram.GetEntries()
196 plot.histogram.Add(tmp_hist)
197 entries_after = plot.histogram.GetEntries()
198 print(
" %3i %7i %20s >> %s/%s" % (i, entries_after-entries_before,
199 plot.treeVariable, histname_fix,
200 plot.histogram.GetName()), end=
' ')
202 print(
"\textra cuts: %s" % plot.cuts, end=
' ')
205 rootTree.tfile.Close()
206 print(
"%s: Closed %s" % (datetime.now().strftime(
"%I:%M%p"),
208 return list_of_plots_to_write
215 sys.path.insert(0,
'')
216 _temp = __import__(config_file, globals(), locals(),
217 [
'list_of_files',
'output_filename',
218 'cut_for_all_files',
'cut_sets',
'list_of_plots'], -1)
219 list_of_files = _temp.list_of_files
220 output_filename = _temp.output_filename
221 cut_for_all_files = _temp.cut_for_all_files
222 cut_sets = _temp.cut_sets
223 list_of_plots = _temp.list_of_plots
224 for rootTree
in list_of_files:
225 if not path.isfile(rootTree.fileName):
226 print(
"Error:\n %s\nnot found for input." % rootTree.fileName)
228 hist_names = [plot.name
for plot
in list_of_plots]
229 if len(hist_names)>len(set(hist_names)):
231 print(
"Error: Each plot needs a unique name, exiting...")
233 if path.isfile(output_filename):
234 print(
"Warning: %s exists" % output_filename)
235 except Exception
as e:
237 print(
"Error with %s" % config_file)
240 if path.isfile(
'rootlogon.C'):
241 print(
"Loading rootlogon.C")
242 gROOT.Macro(
'rootlogon.C')
245 print(
"\n%i defined cut sets:" % len(cut_sets))
247 name, title_fix, current_cut_set = cut
248 print(
" %s\t: '%s'" % (name, current_cut_set))
249 cut_names = [name
for name,num,cut
in cut_sets]
250 if len(cut_names)>len(set(cut_names)):
251 print(
"Error: Each cut set needs a unique name, exiting...")
254 cut_sets = [(
"",
"",
"")]
256 print(
"\nCuts to apply to all files:\n\t'%s'" % cut_for_all_files)
258 start_time = datetime.now()
263 end_time = datetime.now()
267 outputFile = TFile(output_filename,
"recreate")
268 if outputFile.IsZombie():
269 print(
"Error opening %s for output exiting..." % output_filename)
271 print(
"\nOpened output file. Saving histograms...")
273 for set_of_cuts
in cut_sets:
274 outputFile.mkdir(set_of_cuts[0])
275 print(
" # entries histogram")
276 for i, (plot, cutset)
in enumerate(list_of_plots_to_write):
277 outputFile.cd(cutset[0])
278 print(
" %3i %7i %s/%s" % (i, plot.histogram.GetEntries(),
280 plot.histogram.GetName()))
281 plot.histogram.Write()
283 print(
"Done saving.")
284 print(
"\nScaled & added histograms from %i TTrees saved in\n %s" % (len(list_of_files), output_filename))
288 if len(sys.argv) > 1:
289 if path.isfile(sys.argv[1]):
290 config_file = sys.argv[1].
split(
'.')[0]
293 print(
"%s not found." % sys.argv[1])
294 print(
"Create default config file by running tree2hists " 298 if path.exists(
't2h_config.py'):
299 print(
"Run with specific config file, like:")
300 print(
" tree2hists t2h_config.py")
305 if __name__ ==
"__main__":
std::vector< std::string_view > split(std::string_view, const char *)
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 #############################################.