--- UserCode/RootMacros/tree2hists.py 2010/05/23 20:56:57 1.4 +++ UserCode/RootMacros/tree2hists.py 2010/06/02 16:06:43 1.5 @@ -14,73 +14,77 @@ Options are specified in the given confi ######## Import python libraries ############################################# import sys # For exiting program -if sys.version_info < (2, 6): - print "Go to a CMSSW dir and type 'cmsenv' first. (this loads a modern version of python)" +try: + from ROOT import TFile, TTree, TH1F, TH2F, TH3F, gROOT +except Exception, e: + print e + print ("Use a python that has PyROOT installed.") sys.exit(0) -from ROOT import TFile, TTree, TH1F, TH2F, TH3F, gROOT # Import any ROOT class you want -from copy import deepcopy # For copying histograms -from math import pi # For use in histogram bounds -from array import array # For making Float_t array ROOT wants (for hists) -from datetime import datetime # For output filename -from os import path # For finding file +from copy import deepcopy # For copying histograms +from math import pi # For use in histogram bounds +from array import array # For making Float_t array ROOT wants (for hists) +from datetime import datetime # For output filename +from os import path # For finding file ######## Define classes and generators ####################################### -class rootFile: +class RootTree: """Wrapper for TTrees and TNtuples, allowing association with a scale and cuts.""" - def __init__(self, fileName, scale=1.0, cuts="", tree=""): - self.name = fileName - self.scale = scale - self.cuts = cuts - self.file = TFile(fileName, "read") # Open TFile - if self.file.IsZombie(): - print "Error opening %s, exiting..." % self.name - sys.exit(0) - print "Opened %s, scale=%.2e, cuts='%s'" % (fileName, scale, cuts) - self.ttree = TTree() # Create empty TTree, and - try: # try to get TTree from file. - self.file.GetObject(tree, self.ttree) # ttreeName set in variables below - except: - print "Error: %s not found in %s, exiting..." % (tree, fileName) - sys.exit(0) - print "\t %s contains %.0f entries before cuts, %.0f after." % (tree, self.ttree.GetEntries(), self.ttree.GetEntries(cuts)) + def __init__(self, treeName, fileName, scale=1.0, cuts=""): + self.fileName = fileName + self.treeName = treeName + self.scale = scale + self.cuts = cuts + self.tfile = TFile() + self.ttree = TTree() class Plot: """Wrapper for TH1 objects, associating TTree variables with a histogram""" def __init__(self, treeVariable, histogram, cuts="", storeErrors=True): self.treeVariable = treeVariable - self.histogram = histogram - self.cuts = cuts + self.histogram = histogram + self.name = histogram.GetName() + self.cuts = cuts if storeErrors: self.histogram.Sumw2() -def joinCuts(*listOfCuts): - """Joines list of cuts (strings) into something ROOT can handle. - Example: given ("1<2","","5>4") returns '1<2&&5>4'""" - listOfNonEmptyCuts=[] - for cut in listOfCuts: +def join_cuts(*list_of_cuts): + """Joins list of cuts (strings) into something ROOT can handle. + Example: given ('1<2','','5>4') returns '1<2&&5>4'""" + list_of_nonempty_cuts = [] + for cut in list_of_cuts: if cut: - listOfNonEmptyCuts.append(cut) - return '&&'.join(listOfNonEmptyCuts) + list_of_nonempty_cuts.append(cut) + return '&&'.join(list_of_nonempty_cuts) -def writeDefaultT2HConfig(): +def duration_to_string(start, end): + timeTaken = end - start + hours, remainder = divmod(timeTaken.seconds, 3600) + minutes, seconds = divmod(remainder, 60) + if hours>0: + return "%i hours, %i minutes" % (hours, minutes) + elif minutes>0: + return "%i minutes" % minutes + return "%i seconds" % seconds + +def write_default_T2H_config(): """Writes configuration file for tree2hists""" defaultConfig = '''# Configuration file for tree2hists.py # Created %s. -from tree2hists import * +from tree2hists import RootTree, Plot, array, pi, TH1F -listOfFiles = [rootFile("MultiPhotonAnalyzer_SDEG.root", tree="NTuples/Analysis", scale=1.0, cuts=""), - rootFile("MultiPhotonAnalyzer_SD_EG_May7.root", tree="NTuples/Analysis", scale=1.0 cuts="")] +list_of_files = [RootTree("NTuples/Analysis", fileName="photons.root", scale=1.0, cuts=""), + RootTree("NTuples/Analysis", fileName="photons2.root", scale=1.0, cuts="")] -outputFilename = "Hists_Data_%%s.root" %% datetime.now().strftime("%%b%%d_%%I%%p") +output_filename = "Hists_photons.root" -cutForAllFiles = "(!TTBit[36] && !TTBit[37] && !TTBit[38] && !TTBit[39] && !vtxIsFake && vtxNdof>4 && abs(vtxZ)<=15)" + \ - "&&((isEB[0] && (seedSeverity[0]!=3 && seedSeverity[0]!=4 ) && (seedRecoFlag[0] != 2) ) || isEE[0])" +cut_for_all_files = "(!TTBit[36] && !TTBit[37] && !TTBit[38] && !TTBit[39] && !vtxIsFake && vtxNdof>4 && abs(vtxZ)<=15)" + \\ + "&&((isEB[0] && (seedSeverity[0]!=3 && seedSeverity[0]!=4 ) && (seedRecoFlag[0] != 2) ) || isEE[0])" -# All plots are made for each "cutSet". -# A "cutSet" is 3 things: folder name to store hists in, string to add to hist titles, and cuts for these hists. -# Set cutSet = [] to make all plots. -cutSets = [ +# All plots are made for each "cut set". +# A "cut set" is 3 things: folder name to store hists in, string to add to hist titles, and cuts for these hists. +# Let cut_sets = [] to make all plots. +cut_sets = [ ("barrel15to20", "(|#eta|<1.45, 1515&&et[0]<20&&abs(eta[0])<1.45"), ("barrel20to30", "(|#eta|<1.45, 2020&&et[0]<30&&abs(eta[0])<1.45"), ("endcap15to20", "(1.7<|#eta|<2.5, 1515&&et[0]<20&&abs(eta[0])>1.7&&abs(eta[0])<2.5"), @@ -90,7 +94,7 @@ cutSets = [ # Define histograms to plot bins_et = array("f", [15.0, 20.0, 30.0, 50.0, 80.0, 120.0]) bins_eta = array("f", [-2.5, -1.7, -1.45, 0.0, 1.45, 1.7, 2.5]) -listOfPlots = [ +list_of_plots = [ Plot("et[0]" , TH1F("pho_et" , "Lead #gamma: E_{T};E_{T} (GeV);entries/bin", len(bins_et)-1, bins_et)), Plot("eta[0]" , TH1F("pho_eta" , "Lead #gamma: #eta;#eta;entries/bin" , len(bins_eta)-1, bins_eta)), Plot("sigmaIetaIeta[0]", TH1F("pho_sigmaIEtaIEta", "Lead #gamma: #sigma_{i#etai#eta};#sigma_{i#etai#eta};entries/bin",20, 0, 0.06)), @@ -105,74 +109,141 @@ listOfPlots = [ print "Created default configuration file: t2h_config.py" print "Edit it, and run with:" print " tree2hists.py t2h_config.py" -######################################## +############################################################################## + +def make_all_hists_all_files(list_of_RootTrees, list_of_Plots, cut_for_all_files, list_of_cutSets): + '''Open root files one at a time, make plots, then close them.''' + list_of_plots_to_write = [] + + # Create plots for each set of cuts + for set_of_cuts in list_of_cutSets: + histname_fix, title_fix, current_cut_set = set_of_cuts + for plot in list_of_Plots: + new_plot = deepcopy(plot) + new_title = ' '.join((plot.histogram.GetTitle(), title_fix)) + new_plot.histogram.SetTitle(new_title) + list_of_plots_to_write.append((new_plot, set_of_cuts)) + + for j, rootTree in enumerate(list_of_RootTrees): + rootTree.tfile = TFile(rootTree.fileName, "read") # Open TFile + if rootTree.tfile.IsZombie(): + print "Error opening %s, exiting..." % rootTree.fileName + sys.exit(0) + try: # Try to get TTree from file. + rootTree.tfile.GetObject(rootTree.treeName, rootTree.ttree) + except: + print "Error: %s not found in %s, exiting..." % (rootTree.treeName, + rootTree.fileName) + sys.exit(1) + + print "\n%s: Opened %s %i MB" % (datetime.now().strftime("%I:%M%p"), + rootTree.fileName, + path.getsize(rootTree.fileName)/1048576) + print " %s has %i entries, will plot with scale=%.2e, cuts='%s'" % (rootTree.treeName, + rootTree.ttree.GetEntries(), + rootTree.scale, + rootTree.cuts) + + # Loop over plots + print " # entries var >> histogram" + for i, (plot, set_of_cuts) in enumerate(list_of_plots_to_write): + histname_fix, title_fix, current_cut_set = set_of_cuts + tmp_hist = plot.histogram.Clone("temp") # Create temp hist + all_cuts = join_cuts(cut_for_all_files, rootTree.cuts, + current_cut_set, plot.cuts) # Set cuts + rootTree.ttree.Draw( "%s >> temp" % plot.treeVariable, all_cuts, + "goff") # Draw with graphics off + tmp_hist.Scale(rootTree.scale) # Scale temp + entries_before = plot.histogram.GetEntries() + plot.histogram.Add(tmp_hist) # Add temp hist to total + entries_after = plot.histogram.GetEntries() + print " %3i %7i %20s >> %s/%s" % (i, entries_after-entries_before, + plot.treeVariable, histname_fix, + plot.histogram.GetName()), + if plot.cuts: + print "\textra cuts: %s" % plot.cuts, # plot-specific cuts + print + + rootTree.tfile.Close() # Close TFile + print "%s: Closed %s" % (datetime.now().strftime("%I:%M%p"), + rootTree.fileName) + return list_of_plots_to_write ######## Define the main program ############################################# def tree2hists_main(config_file): try: # Import only certain variables - _temp = __import__(config_file, globals(), locals(), ['listOfFiles','outputFilename','cutForAllFiles','cutSets','listOfPlots'], -1) - listOfFiles = _temp.listOfFiles - outputFilename = _temp.outputFilename - cutForAllFiles = _temp.cutForAllFiles - cutSets = _temp.cutSets - listOfPlots = _temp.listOfPlots - if not cutSets: cutSets = [("","","")] # Make all plots, no extra cuts + _temp = __import__(config_file, globals(), locals(), + ['list_of_files','output_filename', + 'cut_for_all_files','cut_sets','list_of_plots'], -1) + list_of_files = _temp.list_of_files + output_filename = _temp.output_filename + cut_for_all_files = _temp.cut_for_all_files + cut_sets = _temp.cut_sets + list_of_plots = _temp.list_of_plots + for rootTree in list_of_files: + if not path.isfile(rootTree.fileName): + print "Error:\n %s\nnot found for input." % rootTree.fileName + sys.exit(1) + hist_names = [plot.name for plot in list_of_plots] + if len(hist_names)>len(set(hist_names)): + print hist_names + print "Error: Each plot needs a unique name, exiting..." + sys.exit(1) + if path.isfile(output_filename): + print "Warning: %s exists" % output_filename except Exception, e: print e + print "Error with %s" % config_file sys.exit(1) if path.isfile('rootlogon.C'): print "Loading rootlogon.C" - gROOT.Macro('rootlogon.C') # Run ROOT logon script (for loading of functions) + gROOT.Macro('rootlogon.C') # Load functions from rootlogon script - outputFile = TFile(outputFilename, "recreate") - if not outputFile.IsZombie(): - print "Opened %s for output." % outputFilename + if cut_sets: + print "\n%i defined cut sets:" % len(cut_sets) + for cut in cut_sets: + name, title_fix, current_cut_set = cut + print " %s\t: '%s'" % (name, current_cut_set) + cut_names = [name for name,num,cut in cut_sets] + if len(cut_names)>len(set(cut_names)): + print "Error: Each cut set needs a unique name, exiting..." + sys.exit(1) else: - print "Error opening %s for output exiting..." % outputFilename - sys.exit(1) + cut_sets = [("","","")] # Make all plots, no extra cuts - listOfPlotsToWrite = [] + print "\nCuts to apply to all files:\n\t'%s'" % cut_for_all_files + + start_time = datetime.now() + list_of_plots_to_write = make_all_hists_all_files(list_of_files, + list_of_plots, + cut_for_all_files, + cut_sets) + end_time = datetime.now() + print "Done drawing all plots after %s." % duration_to_string(start_time, end_time) - print "\nCuts applied to all plots from all files:\n %s" % cutForAllFiles - numberOfPlots = len(listOfPlots) - print "\nCreating %i plots for each of %i cut sets..." % (numberOfPlots, len(cutSets)) - for setOfCuts in cutSets: # Make all plots for each cutSet - histNamePostfix, titlePostfix, currentCutSet = setOfCuts - print '\n Cut set "%s": %s' % (histNamePostfix, currentCutSet) - for i, plot in enumerate(listOfPlots): # Loop over plots - newTitle = ' '.join((plot.histogram.GetTitle(), titlePostfix)) - newPlot = deepcopy(plot) - dir = histNamePostfix - listOfPlotsToWrite.append((dir, newPlot)) - newPlot.histogram.SetTitle(newTitle) - for aFile in listOfFiles: # Loop over all TTrees - tempHist = newPlot.histogram.Clone("temp") # Create temp histogram - cuts = joinCuts(cutForAllFiles, aFile.cuts, currentCutSet, newPlot.cuts) # Set cuts for temp - aFile.ttree.Draw( "%s >> temp" % newPlot.treeVariable, cuts, "goff") # Draw into temp; graphics off - tempHist.Scale(aFile.scale) # Scale temp - newPlot.histogram.Add(tempHist) # Add temp to total histogram - print " %3i %7i %s >> %s/%s" % (i, newPlot.histogram.GetEntries(), newPlot.treeVariable, dir, newPlot.histogram.GetName()), - if newPlot.cuts: - print "\textra cuts: %s" % newPlot.cuts, # plot-specific cuts - print - print "done." - # Store and save/close files + outputFile = TFile(output_filename, "recreate") + if outputFile.IsZombie(): + print "Error opening %s for output exiting..." % output_filename + sys.exit(1) + print "\nOpened output file. Saving histograms..." outputFile.cd() - for setOfCuts in cutSets: - outputFile.mkdir(setOfCuts[0]) - for dir, plot in listOfPlotsToWrite: - outputFile.cd(dir) + for set_of_cuts in cut_sets: + outputFile.mkdir(set_of_cuts[0]) + print " # entries histogram" + for i, (plot, cutset) in enumerate(list_of_plots_to_write): + outputFile.cd(cutset[0]) + print " %3i %7i %s/%s" % (i, plot.histogram.GetEntries(), + cutset[0], + plot.histogram.GetName()) plot.histogram.Write() - outputFile.Close() - for aFile in listOfFiles: - aFile.file.Close() - print "\n\nHistograms stored in\n %s" % outputFilename -######################################## + print "Done saving." + print "\nScaled & added histograms from %i TTrees saved in\n %s" % (len(list_of_files), output_filename) +############################################################################## if __name__ == "__main__": if len(sys.argv) > 1: @@ -181,14 +252,15 @@ if __name__ == "__main__": tree2hists_main(config_file) else: print "%s not found." % sys.argv[1] - print "Create default config file by running tree2hists.py with no argument." + print("Create default config file by running tree2hists.py " + "with no argument.") sys.exit(1) else: if path.exists('t2h_config.py'): print "Specify a config file, like:" print "tree2hists.py t2h_config.py" sys.exit(1) - writeDefaultT2HConfig() + write_default_T2H_config() sys.exit(0) #import cProfile #cProfile.run('main()', 'fooprof')