CMS 3D CMS Logo

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