CMS 3D CMS Logo

estimatePileup2.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 VERSION='2.00'
3 import os, sys
4 import coral
5 import optparse
6 from RecoLuminosity.LumiDB import sessionManager,csvSelectionParser,selectionParser,lumiCorrections,lumiCalcAPI
7 import six
8 
9 beamChoices=['PROTPHYS','IONPHYS']
10 
12  def __init__(self):
13  self.minBiasXsec=71300 #unit microbarn
14  self.rotationRate=11245.613 # for 3.5 TeV Beam energy
15  self.NBX=3564
16  self.rotationTime=1.0/self.rotationRate
17  self.lumiSectionLen=2**18*self.rotationTime
18 
19 def fillPileupHistogram (bxlumiinfo,pileupHistName,maxPileupBin,
20  runNumber=0, hist = None, debug = False):
21  '''
22  bxlumiinfo:[[cmslsnum(0),avgdelivered(1),avgrecorded(2),bxlumiarray[3]]]
23 
24  Given luminfo , deadfrac info and run number, will (create if necessary
25  and) fill histogram with expected pileup distribution. If a
26  histogram is created, it is owned by the user and is his/her
27  responsibility to clean up the memory.'''
28  if hist:
29  maxBin = hist.GetNbinsX()
30  upper = int( hist.GetBinLowEdge(maxBin) + \
31  hist.GetBinWidth(maxBin) + 0.25 )
32  else:
33  histname = '%s_%s' % (pileupHistName, runNumber)
34  hist = ROOT.TH1D (histname, histname, maxPileupBin + 1,
35  -0.5,maxPileupBin + 0.5)
36  upper = maxPileupBin
38  for perlsinfo in bxlumiinfo:
39  cmslsnum=perlsinfo[0]
40  avgdelivered=perlsinfo[1]
41  avgrecorded=perlsinfo[2]
42  bxdata=perlsinfo[3]
43  bxidx=bxdata[0]
44  bxvaluelist=bxdata[1]
45  #calculate livefrac
46  livetime=1
47  if avgrecorded<0:
48  avgrecorded=0
49  if avgdelivered:
50  livetime=avgrecorded/avgdelivered
51  else:
52  livetime=0
53  for idx,bxvalue in enumerate(bxvaluelist):
54  xingIntLumi=bxvalue * p.lumiSectionLen * livetime
55  if options.minBiasXsec:
56  mean = bxvalue * options.minBiasXsec * p.rotationTime
57  else:
58  mean = bxvalue * p.minBiasXsec * p.rotationTime
59  if mean > 100:
60  if runNumber:
61  print "mean number of pileup events > 100 for run %d, lum %d : m %f l %f" % \
62  (runNumber, lumiSection, mean, bxvalue)
63  else:
64  print "mean number of pileup events > 100 for lum %d: m %f l %f" % \
65  (cmslsnum, mean, bxvalue)
66  totalProb = 0
67  for obs in range (upper):
68  prob = ROOT.TMath.Poisson (obs, mean)
69  totalProb += prob
70  hist.Fill (obs, prob * xingIntLumi)
71  if debug:
72  xing=bxidx[idx]
73  print "ls", lumiSection, "xing", xing, "inst", bxvalue, \
74  "mean", mean, "totalProb", totalProb, 1 - totalProb
75  print " hist mean", hist.GetMean()
76  if totalProb < 1:
77  hist.Fill (obs, (1 - totalProb) * xingIntLumi)
78  return hist
79 
80 ##############################
81 ## ######################## ##
82 ## ## ################## ## ##
83 ## ## ## Main Program ## ## ##
84 ## ## ################## ## ##
85 ## ######################## ##
86 ##############################
87 
88 if __name__ == '__main__':
89  beamModeChoices = [ "","stable", "quiet", "either"]
90  amodetagChoices = [ "PROTPHYS","IONPHYS" ]
91  xingAlgoChoices =[ "OCC1","OCC2","ET"]
92  parser = optparse.OptionParser ("Usage: %prog [--options] output.root",
93  description = "Script to estimate pileup distribution using xing instantaneous luminosity information and minimum bias cross section. Output is TH1D stored in root file")
94  dbGroup = optparse.OptionGroup (parser, "Database Options")
95  inputGroup = optparse.OptionGroup (parser, "Input Options")
96  pileupGroup = optparse.OptionGroup (parser, "Pileup Options")
97  dbGroup.add_option ('-c', dest = 'connect', action = 'store',
98  default='frontier://LumiCalc/CMS_LUMI_PROD',
99  help = 'connect string to lumiDB ,default %default')
100  dbGroup.add_option ('-P', dest = 'authpath', action = 'store',
101  help = 'path to authentication file')
102  dbGroup.add_option ('--siteconfpath', dest = 'siteconfpath', action = 'store',
103  help = 'specific path to site-local-config.xml file, default to $CMS_PATH/SITECONF/local/JobConfig, ' \
104  'if path undefined, fallback to cern proxy&server')
105  dbGroup.add_option ('--debug', dest = 'debug', action = 'store_true',
106  help = 'debug')
107 
108  inputGroup.add_option ('-r', dest = 'runnumber', action = 'store',
109  help = 'run number')
110  inputGroup.add_option ('-i', dest = 'inputfile', action = 'store',
111  help = 'lumi range selection file')
112  inputGroup.add_option ('-b', dest = 'beamstatus', default='', choices=beamModeChoices,
113  help = "beam mode, optional for delivered action, default ('%%default' out of %s)" % beamModeChoices)
114  inputGroup.add_option ('--hltpath', dest = 'hltpath', action = 'store',
115  help = 'specific hltpath to calculate the recorded luminosity, default to all')
116  inputGroup.add_option ('--csvInput', dest = 'csvInput', type='string', default='',
117  help = 'Use CSV file from lumiCalc2.py instead of lumiDB')
118  inputGroup.add_option ('--without-correction', dest = 'withoutFineCorrection', action='store_true',
119  help = 'not apply fine correction on calibration')
120  pileupGroup.add_option('--algoname',dest='algoname',default='OCC1',
121  help = 'lumi algorithm , default %default')
122  pileupGroup.add_option ('--xingMinLum', dest = 'xingMinLum', type='float', default = 1.0e-3,
123  help = 'Minimum luminosity considered for "lsbylsXing" action, default %default')
124  pileupGroup.add_option ('--minBiasXsec', dest = 'minBiasXsec', type='float', default = 71300,
125  help = 'Minimum bias cross section assumed (in mb), default %default mb')
126  pileupGroup.add_option ('--histName', dest='pileupHistName', type='string', default = 'pileup',
127  help = 'Histrogram name (default %default)')
128  pileupGroup.add_option ('--maxPileupBin', dest='maxPileupBin', type='int', default = 10,
129  help = 'Maximum bin in pileup histogram (default %default)')
130  pileupGroup.add_option ('--saveRuns', dest='saveRuns', action='store_true',
131  help = 'Save pileup histograms for individual runs')
132  pileupGroup.add_option ('--debugLumi', dest='debugLumi',
133  action='store_true',
134  help = 'Print out debug info for individual lumis')
135  pileupGroup.add_option ('--nowarning', dest = 'nowarning',
136  action = 'store_true', default = False,
137  help = 'suppress bad for lumi warnings' )
138  parser.add_option_group (dbGroup)
139  parser.add_option_group (inputGroup)
140  parser.add_option_group (pileupGroup)
141  # parse arguments
142  try:
143  (options, args) = parser.parse_args()
144  except Exception as e:
145  print e
146  if not args:
147  parser.print_usage()
148  sys.exit()
149  if len (args) != 1:
150  parser.print_usage()
151  raise RuntimeError("Exactly one output file must be given")
152  output = args[0]
153  finecorrections=None
154  # get database session hooked up
155  if options.authpath:
156  os.environ['CORAL_AUTH_PATH'] = options.authpath
157 
158  svc=sessionManager.sessionManager(options.connect,authpath=options.authpath,debugON=options.debug)
159 
160  if not options.inputfile and not options.runnumber and not options.csvInput:
161  raise "must specify either a run (-r), an input run selection file (-i), or an input CSV file (--csvInput)"
162 
163  runDict = {}
164  if options.csvInput:
165  import re
166  # we're going to read in the CSV file and use this as not only
167  # the selection of which run/events to use, but also the
168  # source of the lumi information.
169  sepRE = re.compile (r'[\s,;:]+')
170  events = open (options.csvInput, 'r')
171  for line in events:
172  pieces = sepRE.split (line.strip())
173  if len (pieces) < 6:
174  continue
175  if len (pieces) % 2:
176  # not an even number
177  continue
178  try:
179  run, cmslsnum = int ( pieces[0] ), int ( pieces[1] )
180  delivered, recorded = float( pieces[2] ), float( pieces[3] )
181  xingIdx = [int(myidx) for myidx in pieces[4::2] ]
182  xingVal = [float(myval) for myval in pieces[5::2] ]
183 
184  #xingInstLumiArray = [( int(orbit), float(lum) ) \
185  # for orbit, lum in zip( pieces[4::2],
186  # pieces[5::2] ) ]
187  except:
188  continue
189  runDict.setdefault(run,[]).append([cmslsnum,delivered,recorded,(xingIdx,xingVal)])
190  #{run:[[cmslsnum,delivered,recorded,xingInstlumiArray]..]}
191  events.close()
192  else:
193  session=svc.openSession(isReadOnly=True,cpp2sqltype=[('unsigned int','NUMBER(10)'),('unsigned long long','NUMBER(20)')])
194  finecorrections=None
195  if options.runnumber:
196  inputRange = {int(options.runnumber):None}
197  else:
198  basename, extension = os.path.splitext (options.inputfile)
199  if extension == '.csv': # if file ends with .csv, use csv
200  # parser, else parse as json file
201  fileparsingResult = csvSelectionParser.csvSelectionParser (options.inputfile)
202  else:
203  f = open (options.inputfile, 'r')
204  inputfilecontent = f.read()
205  inputRange = selectionParser.selectionParser (inputfilecontent).runsandls()
206  if not inputRange:
207  print 'failed to parse the input file', options.inputfile
208  raise
209  if not options.withoutFineCorrection:
210  rruns=inputRange.keys()
211  schema=session.nominalSchema()
212  session.transaction().start(True)
213  finecorrections=lumiCorrections.correctionsForRange(schema,rruns)
214  session.transaction().commit()
215  session.transaction().start(True)
216  schema=session.nominalSchema()
217  lumiData=lumiCalcAPI.lumiForRange(schema,inputRange,beamstatus=options.beamstatus,withBXInfo=True,bxAlgo=options.algoname,xingMinLum=options.xingMinLum,withBeamIntensity=False,datatag=None,finecorrections=finecorrections)
218  session.transaction().commit()
219  # {run:[lumilsnum(0),cmslsnum(1),timestamp(2),beamstatus(3),beamenergy(4),deliveredlumi(5),recordedlumi(6),calibratedlumierror(7),(bxidx,bxvalues,bxerrs)(8),None]}}
220  ##convert lumiData to lumiDict format #{run:[[cmslsnum,avg]]}
221  for runnum,perrundata in lumiData.items():
222  bxlumiinfo=[]
223  for perlsdata in perrundata:
224  cmslsnum=perlsdata[1]
225  deliveredlumi=perlsdata[5]
226  recordedlumi=perlsdata[6]
227  bxlist=perlsdata[8]
228  bxlumiinfo.append([cmslsnum,deliveredlumi,recordedlumi,bxlist])
229  runDict.setdefault(runnum,[]).append([cmslsnum,deliveredlumi,recordedlumi,bxlist])
230  #print 'runDict ',runDict
231 
232  import ROOT
233  pileupHist = ROOT.TH1D (options.pileupHistName,options.pileupHistName,
234  options.maxPileupBin + 1,
235  -0.5, options.maxPileupBin + 0.5)
236  histList = []
237  for runNumber, lumiList in sorted( six.iteritems(runDict) ):
238  if options.saveRuns:
239  hist = fillPileupHistogram (lumiList,options.pileupHistName,options.maxPileupBin,
240  runNumber = runNumber,
241  debug = options.debugLumi)
242  pileupHist.Add (hist)
243  histList.append (hist)
244  else:
245  fillPileupHistogram (lumiList, options.pileupHistName,options.maxPileupBin,
246  hist = pileupHist,
247  debug = options.debugLumi)
248  histFile = ROOT.TFile.Open (output, 'recreate')
249  if not histFile:
250  raise RuntimeError("Could not open '%s' as an output root file" % output)
251  pileupHist.Write()
252  for hist in histList:
253  hist.Write()
254  histFile.Close()
255  sys.exit()
Definition: start.py:1
def fillPileupHistogram(bxlumiinfo, pileupHistName, maxPileupBin, runNumber=0, hist=None, debug=False)