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