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