CMS 3D CMS Logo

pileupCalc.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 VERSION='1.00'
3 import os,sys,time
4 import optparse
5 from RecoLuminosity.LumiDB import pileupParser
6 from RecoLuminosity.LumiDB import selectionParser
7 from math import exp
8 from math import sqrt
9 
10 def parseInputFile(inputfilename):
11  '''
12  output ({run:[ls:[inlumi, meanint]]})
13  '''
14  selectf=open(inputfilename,'r')
15  inputfilecontent=selectf.read()
16  p=pileupParser.pileupParser(inputfilecontent)
17 
18 # p=inputFilesetParser.inputFilesetParser(inputfilename)
19  runlsbyfile=p.runsandls()
20  return runlsbyfile
21 
22 def MyErf(input):
23 
24  # Abramowitz and Stegun approximations for Erf (equations 7.1.25-28)
25  X = abs(input)
26 
27  p = 0.47047
28  b1 = 0.3480242
29  b2 = -0.0958798
30  b3 = 0.7478556
31 
32  T = 1.0/(1.0+p*X)
33  cErf = 1.0 - (b1*T + b2*T*T + b3*T*T*T)*exp(-1.0*X*X)
34  if input<0:
35  cErf = -1.0*cErf
36 
37  # Alternate Erf approximation:
38 
39  #A1 = 0.278393
40  #A2 = 0.230389
41  #A3 = 0.000972
42  #A4 = 0.078108
43 
44  #term = 1.0+ A1*X+ A2*X*X+ A3*X*X*X+ A4*X*X*X*X
45  #denom = term*term*term*term
46 
47  #dErf = 1.0 - 1.0/denom
48  #if input<0:
49  # dErf = -1.0*dErf
50 
51  return cErf
52 
53 
54 def fillPileupHistogram (lumiInfo, calcOption, hist, minbXsec, Nbins):
55  '''
56  lumiinfo:[intlumi per LS, mean interactions ]
57 
58  intlumi is the deadtime corrected average integraged lumi per lumisection
59  '''
60 
61  LSintLumi = lumiInfo[0]
62  RMSInt = lumiInfo[1]*minbXsec
63  AveNumInt = lumiInfo[2]*minbXsec
64 
65  #coeff = 0
66 
67  #if RMSInt > 0:
68  # coeff = 1.0/RMSInt/sqrt(6.283185)
69 
70  #expon = 2.0*RMSInt*RMSInt
71 
72  Sqrt2 = sqrt(2)
73 
74  ##Nbins = hist.GetXaxis().GetNbins()
75 
76  ProbFromRMS = []
77  BinWidth = hist.GetBinWidth(1)
78 
79  # First, re-constitute lumi distribution for this LS from RMS:
80  if RMSInt > 0:
81 
82  AreaLnew = -10.
83  AreaL = 0
84 
85  for obs in range (Nbins):
86  #Old Gaussian normalization; inaccurate for small rms and large bins
87  #val = hist.GetBinCenter(obs+1)
88  #prob = coeff*exp(-1.0*(val-AveNumInt)*(val-AveNumInt)/expon)
89  #ProbFromRMS.append(prob)
90 
91  left = hist.GetBinLowEdge(obs+1)
92  right = left+BinWidth
93 
94  argR = (AveNumInt-right)/Sqrt2/RMSInt
95  AreaR = MyErf(argR)
96 
97  if AreaLnew<-5.:
98  argL = (AveNumInt-left)/Sqrt2/RMSInt
99  AreaL = MyErf(argL)
100  else:
101  AreaL = AreaLnew
102  AreaLnew = AreaR # save R bin value for L next time
103 
104  NewProb = (AreaL-AreaR)*0.5
105 
106  ProbFromRMS.append(NewProb)
107 
108  #print left, right, argL, argR, AreaL, AreaR, NewProb
109 
110  else:
111  obs = hist.FindBin(AveNumInt)
112  for bin in range (Nbins):
113  ProbFromRMS.append(0.0)
114  if obs<Nbins+1:
115  ProbFromRMS[obs] = 1.0
116  if AveNumInt < 1.0E-5:
117  ProbFromRMS[obs] = 0. # just ignore zero values
118 
119  if calcOption == 'true': # Just put distribution into histogram
120  if RMSInt > 0:
121  totalProb = 0
122  for obs in range (Nbins):
123  prob = ProbFromRMS[obs]
124  val = hist.GetBinCenter(obs+1)
125  #print obs, val, RMSInt,coeff,expon,prob
126  totalProb += prob
127  hist.Fill (val, prob * LSintLumi)
128 
129  if 1.0-totalProb > 0.01:
130  print "Significant probability density outside of your histogram"
131  print "Consider using a higher value of --maxPileupBin"
132  print "Mean %f, RMS %f, Integrated probability %f" % (AveNumInt,RMSInt,totalProb)
133  # hist.Fill (val, (1 - totalProb) * LSintLumi)
134  else:
135  hist.Fill(AveNumInt,LSintLumi)
136  else: # have to convolute with a poisson distribution to get observed Nint
137  totalProb = 0
138  Peak = 0
139  BinWidth = hist.GetBinWidth(1)
140  for obs in range (Nbins):
141  Peak = hist.GetBinCenter(obs+1)
142  RMSWeight = ProbFromRMS[obs]
143  for bin in range (Nbins):
144  val = hist.GetBinCenter(bin+1)-0.5*BinWidth
145  prob = ROOT.TMath.Poisson (val, Peak)
146  totalProb += prob
147  hist.Fill (val, prob * LSintLumi * RMSWeight)
148 
149  if 1.0-totalProb > 0.01:
150  print "Significant probability density outside of your histogram"
151  print "Consider using a higher value of --maxPileupBin"
152 
153 
154  return hist
155 
156 
157 
158 ##############################
159 ## ######################## ##
160 ## ## ################## ## ##
161 ## ## ## Main Program ## ## ##
162 ## ## ################## ## ##
163 ## ######################## ##
164 ##############################
165 
166 if __name__ == '__main__':
167 
168  parser = optparse.OptionParser ("Usage: %prog [--options] output.root",
169  description = "Script to estimate pileup distribution using xing instantaneous luminosity information and minimum bias cross section. Output is TH1D stored in root file")
170 #
171 # parser = argparse.ArgumentParser(prog=os.path.basename(sys.argv[0]),description = "Pileup Lumi Calculation",formatter_class=argparse.ArgumentDefaultsHelpFormatter)
172  CalculationModeChoices = ['truth', 'observed']
173 
174  #
175  # parse arguments
176  #
177  #
178  # basic arguments
179  #
180  #parser.add_argument('action',choices=allowedActions,
181  # help='command actions')
182  parser.add_option('-o',dest='outputfile',action='store',
183  default='PileupCalc.root',
184  help='output root file')
185  parser.add_option('-i',dest='inputfile',action='store',
186  help='Input Run/LS file for your analysis in JSON format (required)')
187  parser.add_option('--inputLumiJSON',dest='inputLumiJSON',action='store',
188  help='Input Lumi/Pileup file in JSON format (required)')
189  parser.add_option('--calcMode',dest='calcMode',action='store',
190  help='Calculate either True ="true" or Observed="observed" distributions')
191  parser.add_option('--minBiasXsec',dest='minBiasXsec',action='store',
192  type=float,
193  default=73500,
194  help='Minimum bias cross section assumed (in microbbarn), default %default microbarn')
195  parser.add_option('--maxPileupBin',dest='maxPileupBin',action='store',
196  type=int,
197  default=25,
198  help='Maximum value of pileup histogram, default %default')
199  parser.add_option('--numPileupBins',dest='numPileupBins',action='store',
200  type=int,
201  default=1000,
202  help='number of bins in pileup histogram, default %default')
203  parser.add_option('--pileupHistName',dest='pileupHistName',action='store',
204  default='pileup',
205  help='name of pileup histogram, default %default')
206  parser.add_option('--verbose',dest='verbose',action='store_true',help='verbose mode for printing' )
207 
208  # parse arguments
209  try:
210  (options, args) = parser.parse_args()
211  except Exception as e:
212  print e
213  if not args:
214  parser.print_usage()
215  sys.exit()
216  if len (args) != 1:
217  parser.print_usage()
218  raise RuntimeError("Exactly one output file must be given")
219  output = args[0]
220 
221 # options=parser.parse_args()
222 
223  if options.verbose:
224  print 'General configuration'
225  print '\toutputfile: ',options.outputfile
226  print '\tAction: ',options.calcMode, 'luminosity distribution will be calculated'
227  print '\tinput selection file: ',options.inputfile
228  print '\tMinBiasXsec: ',options.minBiasXsec
229  print '\tmaxPileupBin: ',options.maxPileupBin
230  print '\tnumPileupBins: ',options.numPileupBins
231 
232  import ROOT
233  pileupHist = ROOT.TH1D (options.pileupHistName,options.pileupHistName,
234  options.numPileupBins,
235  0., options.maxPileupBin)
236 
237  nbins = options.numPileupBins
238  upper = options.maxPileupBin
239 
240  inpf = open (options.inputfile, 'r')
241  inputfilecontent = inpf.read()
242  inputRange = selectionParser.selectionParser (inputfilecontent).runsandls()
243 
244  #inputRange=inputFilesetParser.inputFilesetParser(options.inputfile)
245 
246  if options.calcMode in ['true','observed']:
247  inputPileupRange=parseInputFile(options.inputLumiJSON)
248 
249  # now, we have to find the information for the input runs and LumiSections
250  # in the Lumi/Pileup list. First, loop over inputs
251 
252  for (run, lslist) in sorted (inputRange.iteritems() ):
253  # now, look for matching run, then match lumi sections
254  # print "searching for run %d" % (run)
255  if run in inputPileupRange.keys():
256  #print run
257  LSPUlist = inputPileupRange[run]
258  # print "LSPUlist", LSPUlist
259  for LSnumber in lslist:
260  if LSnumber in LSPUlist.keys():
261  #print "found LS %d" % (LSnumber)
262  lumiInfo = LSPUlist[LSnumber]
263  # print lumiInfo
264  fillPileupHistogram (lumiInfo, options.calcMode,
265  pileupHist, options.minBiasXsec, nbins)
266  else: # trouble
267  print "Run %d, LumiSection %d not found in Lumi/Pileup input file. Check your files!" \
268  % (run,LSnumber)
269 
270  else: # trouble
271  print "Run %d not found in Lumi/Pileup input file. Check your files!" % (run)
272 
273 
274 
275 # print run
276 # print lslist
277 
278  histFile = ROOT.TFile.Open (output, 'recreate')
279  if not histFile:
280  raise RuntimeError("Could not open '%s' as an output root file" % output)
281  pileupHist.Write()
282  #for hist in histList:
283  # hist.Write()
284  histFile.Close()
285  sys.exit()
286 
287  else:
288  print "must specify a pileup calculation mode via --calcMode true or --calcMode observed"
289  sys.exit()
def parseInputFile(inputfilename)
Definition: pileupCalc.py:10
def fillPileupHistogram(lumiInfo, calcOption, hist, minbXsec, Nbins)
Definition: pileupCalc.py:54
def MyErf(input)
Definition: pileupCalc.py:22
T sqrt(T t)
Definition: SSEVec.h:18
Abs< T >::type abs(const T &t)
Definition: Abs.h:22