Fork me on GitHub

source: git/python/DelphesAnalysis/ControlPlots.py@ 952bbbc

Last change on this file since 952bbbc was ae1d49f, checked in by pavel <pavel@…>, 12 years ago

add DelphesAnalysis

  • Property mode set to 100644
File size: 7.6 KB
Line 
1#!/usr/bin/env python
2
3#######################################################################################
4### Option parsing and main routine #################################################
5#######################################################################################
6
7from optparse import OptionParser
8import sys
9import os
10usage="""%prog [options]"""
11description="""A simple script to generate control plots."""
12epilog="""Example:
13./ControlPlots.py -i ./ -o controlPlots_demo.root --all
14"""
15parser = OptionParser(usage=usage,add_help_option=True,description=description,epilog=epilog)
16parser.add_option("-c", "--conf", dest="conf", default=None,
17 help="Configuration file.")
18parser.add_option("-i", "--inputPath", dest="path",
19 help="Read input file from DIR.", metavar="DIR")
20parser.add_option("-o", "--output", dest='outputname', default=None,
21 help="Save output as FILE.", metavar="FILE")
22parser.add_option("--all",action="store_true",dest="all",
23 help="Process all levels.")
24parser.add_option("-l", "--level", dest="levels",
25 help="Specify a coma-separated list of levels to be processed. No space is allowed.")
26parser.add_option("--Njobs", type="int", dest='Njobs', default="1",
27 help="Number of jobs when splitting the processing.")
28parser.add_option("--jobNumber", type="int", dest='jobNumber', default="0",
29 help="Number of the job is a splitted set of jobs.")
30
31(options, args) = parser.parse_args()
32
33#special treatment of the config file... the rest of the options will be parsed in main.
34if options.conf is not None:
35 try:
36 theUserConf = __import__(os.path.splitext(options.conf)[0])
37 except:
38 raise ImportError("%s is not a valid configuration file."%options.conf)
39 else:
40 os.environ["DelphesAnalysisCfg"]=options.conf
41from CPconfig import configuration
42if options.outputname is None:
43 options.outputname = configuration.defaultFilename+".root"
44
45import Delphes
46import ROOT
47import itertools
48import time
49from importlib import import_module
50from AnalysisEvent import AnalysisEvent
51from BaseControlPlots import getArgSet
52import EventSelection
53import cProfile
54
55def main(options):
56 """simplistic program main"""
57 # do basic arg checking
58 if options.path is None:
59 print "Error: no input path specified."
60 parser.print_help()
61 return
62 levels = []
63 if options.all:
64 levels = range(EventSelection.eventCategories())
65 elif not options.levels is None:
66 levels= map(int,options.levels.split(','))
67 levels.sort()
68 if len(levels)==0:
69 print "Error: no level specified for processing."
70 parser.print_help()
71 return
72 if min(levels)<0:
73 print "Error: levels must be positive integers."
74 parser.print_help()
75 return
76 if max(levels)>=EventSelection.eventCategories():
77 print "Error: last level is",EventSelection.eventCategories()-1
78 parser.print_help()
79 return
80 if options.Njobs<1:
81 print "Error: Njobs must be strictly positive."
82 parser.print_help()
83 return
84 if options.jobNumber>=options.Njobs:
85 print "Error: jobNumber must be strictly smaller than Njobs."
86 parser.print_help()
87 return
88 # if all ok, run the procedure
89 runAnalysis(path=options.path,outputname=options.outputname, levels=levels, Njobs=options.Njobs, jobNumber=options.jobNumber)
90
91#######################################################################################
92### Central Routine: manage input/output, loop on events, manage weights and plots ###
93#######################################################################################
94
95def runAnalysis(path, levels, outputname="controlPlots.root", Njobs=1, jobNumber=1):
96 """produce all the plots in one go"""
97
98 # inputs
99 if os.path.isdir(path):
100 dirList=list(itertools.islice(os.listdir(path), jobNumber, None, Njobs))
101 files=[]
102 for fname in dirList:
103 files.append(path+"/"+fname)
104 elif os.path.isfile(path):
105 files=[path]
106 else:
107 files=[]
108
109 # output
110 output = ROOT.TFile(outputname, "RECREATE")
111 if configuration.runningMode=="dataset":
112 ROOT.RooAbsData.setDefaultStorageType(ROOT.RooAbsData.Tree)
113 rds = ROOT.RooDataSet(configuration.RDSname, configuration.RDSname, ROOT.RooArgSet())
114
115 # events iterator, plus configuration of standard collections and producers
116 events = AnalysisEvent(files)
117 EventSelection.prepareAnalysisEvent(events)
118
119 # prepare the plots
120 controlPlots=[]
121 if configuration.runningMode=="plots":
122 leafList = [None]*EventSelection.eventCategories()
123 createDirectory(EventSelection.categoriesHierarchy(), output, leafList)
124 for levelDir in leafList:
125 levelPlots=[]
126 for cp in configuration.controlPlots:
127 levelPlots.append(getattr(import_module(cp.module),cp.classname)(dir=levelDir.mkdir(cp.label),mode="plots"))
128 controlPlots.append(levelPlots)
129 else:
130 for cp in configuration.controlPlots:
131 controlPlots.append(getattr(import_module(cp.module),cp.classname)(dir=None, mode="dataset", dataset=rds))
132
133 # book histograms (separate iteration for clarity)
134 if configuration.runningMode=="plots":
135 for level in levels:
136 for conf,cp in zip(configuration.controlPlots,controlPlots[level]):
137 cp.beginJob(**conf.kwargs)
138 else:
139 for conf,cp in zip(configuration.controlPlots,controlPlots):
140 cp.beginJob(**conf.kwargs)
141 for cp in controlPlots[:1]:
142 cp.defineCategories(EventSelection.categoryNames)
143
144 # process events
145 i = 0
146 t0 = time.time()
147 for event in events:
148 # printout
149 if i%100==0 :
150 print "Processing... event %d. Last batch in %f s." % (i,(time.time()-t0))
151 t0 = time.time()
152 if configuration.runningMode=="plots":
153 # loop on channels
154 plots = filter(lambda x: EventSelection.isInCategory(x,event.category) ,levels)
155 # process the event once (for the first level)
156 selectionPlotsData=[]
157 for level in plots[:1]:
158 for cp in controlPlots[level]:
159 selectionPlotsData.append(cp.process(event))
160 # fill the histograms
161 for level in plots:
162 for cp, data in zip(controlPlots[level],selectionPlotsData):
163 cp.fill(data, event.weight(category=level))
164 else:
165 for cp in controlPlots[:1]:
166 # set categories (first CP only)
167 cp.setCategories(map(lambda c:EventSelection.isInCategory(c, event.category),range(EventSelection.eventCategories())))
168 for cp in controlPlots:
169 # process event (all CP)
170 cp.processEvent(event)
171 # add to the dataset
172 rds.add(getArgSet(controlPlots))
173 i += 1
174
175 # save all
176 if configuration.runningMode=="plots":
177 for level in levels:
178 for cp in controlPlots[level]:
179 cp.endJob()
180 else:
181 for cp in controlPlots:
182 cp.endJob()
183
184 # for dataset, write the merged RDS to file
185 if configuration.runningMode=="dataset":
186 output.cd()
187 ws_ras = ROOT.RooWorkspace(configuration.WSname, configuration.WSname)
188 getattr(ws_ras,'import')(rds.get())
189 output.Add(ws_ras)
190 ws_ras.Write()
191 rds.tree().Write()
192
193 # close the file
194 output.Close()
195
196def createDirectory(dirStructure, directory, leafList):
197 """Recursively creates the directories for the various stages"""
198 for key,item in dirStructure.iteritems():
199 if isinstance(item, dict):
200 createDirectory(item, directory.mkdir(key), leafList)
201 else:
202 leafList[item]=directory.mkdir("stage_"+str(item),key)
203
204#######################################################################################
205### Program bootstrap ################################################################
206#######################################################################################
207
208if __name__ == "__main__":
209 main(options)
210 #cProfile.run('main(options)', 'controlPlots.prof')
211
Note: See TracBrowser for help on using the repository browser.