CMS 3D CMS Logo

estimatePileup_makeJSON_2015.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 from __future__ import print_function
3 import os, sys
4 import coral
5 import array
6 import optparse
7 from RecoLuminosity.LumiDB import csvSelectionParser, selectionParser
8 import RecoLuminosity.LumiDB.lumiQueryAPI as LumiQueryAPI
9 import re
10 from math import sqrt
11 
12 from pprint import pprint
13 import six
14 
15 selBXs=[]
16 def CalcPileup (deadTable, parameters, luminometer, mode='deadtable'):
17  '''Given a deadtable, will calculate parameters of pileup distribution. Return formatted
18  string with LumiSection, LS integrated lumi, RMS of bunch to bunch lumi and pileup.'''
19 
20  LumiString = ""
21  LumiArray = []
22 
23  for lumiSection, deadArray in sorted (six.iteritems(deadTable)):
24  numerator = 0
25  if luminometer == "HFOC":
26  threshold = 8.
27  else:
28  threshold = 1.2
29  if mode == 'csv':
30  numerator = float (deadArray[1])
31  denominator = float (deadArray[0])
32  instLumiArray = deadArray[2]
33  livetime = 1
34  if numerator < 0:
35  numerator = 0
36  if denominator:
37  livetime = numerator / denominator
38 
39 
40 
41  #print "params", parameters.lumiSectionLen, parameters.rotationTime
42 
43  else:
44  print("no csv input! Doh!")
45  return
46  # totalInstLumi = reduce(lambda x, y: x+y, instLumiArray) # not needed
47  if lumiSection > 0:
48  TotalLumi = 0
49  TotalInt = 0
50  TotalInt2 = 0
51  TotalWeight = 0
52  TotalWeight2 = 0
53  FilledXings = 0
54  for xing, xingInstLumi, xingDelvLumi in instLumiArray:
55  if selBXs and xing not in selBXs:
56  continue
57  xingIntLumi = xingInstLumi * livetime # * parameters.lumiSectionLen
58  mean = xingInstLumi * parameters.rotationTime / parameters.lumiSectionLen
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, xingInstLumi))
63  else:
64  print("mean number of pileup events > 100 for lum %d: m %f l %f" % \
65  (lumiSection, mean, xingInstLumi))
66  #print "mean number of pileup events for lum %d: m %f idx %d l %f" % (lumiSection, mean, xing, xingIntLumi)
67 
68  if xingInstLumi > threshold:
69 
70  TotalLumi = TotalLumi+xingIntLumi
71  TotalInt+= mean*xingIntLumi
72  FilledXings = FilledXings+1
73  #print "xing inst lumi %f %f %d" % (xingIntLumi,TotalLumi,FilledXings)
74 
75  #compute weighted mean, then loop again to get weighted RMS
76  MeanInt = 0
77  if TotalLumi >0:
78  MeanInt = TotalInt/TotalLumi
79  for xing, xingInstLumi, xingDelvlumi in instLumiArray:
80  if selBXs and xing not in selBXs:
81  continue
82  if xingInstLumi > threshold:
83  xingIntLumi = xingInstLumi * livetime # * parameters.lumiSectionLen
84  mean = xingInstLumi * parameters.rotationTime / parameters.lumiSectionLen
85  TotalInt2+= xingIntLumi*(mean-MeanInt)*(mean-MeanInt)
86  TotalWeight+= xingIntLumi
87  TotalWeight2+= xingIntLumi*xingIntLumi
88 
89 
90 
91  if ((lumiSection > 0)):
92  #print " LS, Total lumi, filled xings %d, %f, %d" %(lumiSection,TotalLumi,FilledXings)
93  if FilledXings > 0:
94  AveLumi = TotalLumi/FilledXings
95  else:
96  AveLumi = 0
97  RMSLumi = 0
98  Denom = TotalWeight*TotalWeight-TotalWeight2
99  if TotalLumi > 0 and Denom > 0:
100  RMSLumi = sqrt(TotalWeight/(TotalWeight*TotalWeight-TotalWeight2)*TotalInt2)
101  LumiString = "[%d,%2.4e,%2.4e,%2.4e]," % (lumiSection, TotalLumi, RMSLumi, MeanInt)
102  LumiArray.append(lumiSection)
103  LumiArray.append(TotalLumi) # should really weight by total lumi in LS
104  LumiArray.append(RMSLumi)
105  LumiArray.append(MeanInt)
106  lumiX=MeanInt*parameters.lumiSectionLen*FilledXings*(1./parameters.rotationTime)
107 
108  #print lumiX
109  # if TotalLumi<(lumiX*0.8):
110 # print lumiSection
111 # print FilledXings
112 # print TotalLumi
113 # print lumiX
114 # print numerator
115 # print denominator
116 
117  #print FilledXings
118  return LumiArray
119 
120 
121 
122 ##############################
123 ## ######################## ##
124 ## ## ################## ## ##
125 ## ## ## Main Program ## ## ##
126 ## ## ################## ## ##
127 ## ######################## ##
128 ##############################
129 
130 # modified from the estimatePileup.py script in RecoLuminosity/LumiDB
131 # 5 Jan, 2012 Mike Hildreth
132 # As of now, .csv file is the only allowed input. See the old script for a variety
133 # of different ways to access the data.
134 
135 if __name__ == '__main__':
136  parameters = LumiQueryAPI.ParametersObject()
137  parser = optparse.OptionParser ("Usage: %prog [--options] output.root",
138  description = "Script to estimate average instantaneous bunch crossing luminosity using xing instantaneous luminosity information. Output is JSON format file with one entry per LumiSection")
139  inputGroup = optparse.OptionGroup (parser, "Input Options")
140  pileupGroup = optparse.OptionGroup (parser, "Pileup Options")
141  inputGroup.add_option ('--csvInput', dest = 'csvInput', type='string', default='',
142  help = 'Use CSV file from lumiCalc.py instead of lumiDB')
143  inputGroup.add_option ('--selBXs', dest = 'selBXs', type='string', default='',
144  help = 'CSV of BXs to use; if empty, select all')
145  parser.add_option_group (inputGroup)
146  parser.add_option_group (pileupGroup)
147  # parse arguments
148  (options, args) = parser.parse_args()
149 
150  if not args:
151  parser.print_usage()
152  sys.exit()
153  if len (args) != 1:
154  parser.print_usage()
155  raise RuntimeError("Please specify an output file as your last argument")
156  output = args[0]
157 
158  ## Let's start the fun
159  if not options.csvInput:
160  raise "you must specify an input CSV file with (--csvInput)"
161 
162  if options.selBXs != "":
163  for iBX in options.selBXs.split(","):
164  try:
165  BX=int(iBX)
166  if BX not in selBXs:
167  selBXs.append(BX)
168  except:
169  print(iBX,"is not an int")
170  selBXs.sort()
171  print("selBXs",selBXs)
172 
173  OUTPUTLINE = ""
174  if options.csvInput:
175  # we're going to read in the CSV file and use this as not only
176  # the selection of which run/events to use, but also the
177  # source of the lumi information.
178  sepRE = re.compile (r'[\]\[\s,;:]+')
179  events = open (options.csvInput, 'r')
180  OldRun = -1
181 
182  InGap = 0;
183  GapDict = {}
184  LastValidLumi = []
185  LastDelivered = 0
186 
187 
188  OUTPUTLINE+='{'
189  for line in events:
190  runLumiDict = {}
191  csvDict = {}
192 
193  if re.search( '^#', line):
194  continue
195 
196  pieces = sepRE.split (line.strip())
197 
198  ipiece = 0
199 
200  if len (pieces) < 15: # means we are missing data; keep track of LS, lumi
201  InGap = 1
202  try:
203  run, lumi = int ( pieces[0] ), int ( pieces[2] )
204  delivered, recorded = float( pieces[11] ), float( pieces[12] )
205  except:
206  if pieces[0] != 'run':
207  print(" cannot parse csv file ")
208  InGap = 0
209  continue
210  GapDict[lumi] = [delivered, recorded]
211  continue
212  #if len (pieces) % 2:
213  # not an even number
214  # continue
215  try:
216  run, lumi = int ( pieces[0] ), int ( pieces[2] )
217  delivered, recorded = float( pieces[11] ), float( pieces[12] )
218  luminometer = str( pieces[14] )
219  xingInstLumiArray = [( int(orbit), float(lum), float(lumdelv) ) \
220  for orbit, lum, lumdelv in zip( pieces[15::3],
221  pieces[16::3],
222  pieces[17::3]) ]
223  except:
224  print(" Bad Parsing: Check if the input format has changed")
225  print(pieces[0],pieces[1],pieces[2],pieces[3],pieces[4],pieces[5],pieces[6],pieces[7],pieces[8],pieces[9])
226  continue
227 
228  csvDict.setdefault (run, {})[lumi] = \
229  ( delivered, recorded, xingInstLumiArray )#( delivered, recorded, xingInstLumiArray )
230 
231  if run != OldRun:
232  if OldRun>0:
233  if InGap == 1: # We have some LS's at the end with no data
234  lastLumiS = 0
235  for lumiS, lumiInfo in sorted ( six.iteritems(GapDict) ):
236  record = lumiInfo[1]
237  lastLumiS = lumiS
238  if record > 0.01:
239 
240  peakratio = lumiInfo[0]/LastDelivered # roughly, ratio of inst lumi
241  pileup = LastValidLumi[3]*peakratio # scale for this LS
242  aveLumi = 0
243  if lumiInfo[0] >0:
244  aveLumi = LastValidLumi[1]*peakratio*lumiInfo[1]/lumiInfo[0] # scale by rec/del
245  LumiString = "[%d,%2.4e,%2.4e,%2.4e]," % (lumiS, aveLumi, LastValidLumi[2],pileup)
246  OUTPUTLINE += LumiString
247  else:
248  LumiString = "[%d,0.0,0.0,0.0]," % (lumiS)
249  OUTPUTLINE+=LumiString
250  #add one empty one at the end
251  LumiString = "[%d,0.0,0.0,0.0]," % (lastLumiS+1)
252  OUTPUTLINE+=LumiString
253 
254  InGap = 0
255  GapDict.clear()
256 
257  # add one empty lumi section at the end of each run, to mesh with JSON files
258  LumiString = "[%d,0.0,0.0,0.0]," % (LastValidLumi[0]+1)
259  OUTPUTLINE+=LumiString
260 
261  lastindex=len(OUTPUTLINE)-1
262  trunc = OUTPUTLINE[0:lastindex]
263  OUTPUTLINE = trunc
264  OUTPUTLINE += '], '
265  OldRun = run
266  OUTPUTLINE+= ('"%d":' % run )
267  OUTPUTLINE+= ' ['
268 
269  if lumi == 2: # there is a missing LS=1 for this run
270  OUTPUTLINE+= '[1,0.0,0.0,0.0],'
271 
272  for runNumber, lumiDict in sorted( six.iteritems(csvDict) ):
273  # print runNumber
274  LumiArray = CalcPileup (lumiDict, parameters, luminometer,
275  mode='csv')
276 
277  LastValidLumi = LumiArray
278  LastDelivered = lumiDict[LumiArray[0]][0]
279 
280  if InGap == 1: # We have some gap before this in entry in this run
281  for lumiS, lumiInfo in sorted ( six.iteritems(GapDict) ):
282  peakratio = lumiInfo[0]/LastDelivered # roughly, ratio of inst lumi
283  pileup = LumiArray[3]*peakratio # scale for this LS
284  aveLumi = 0
285  if lumiInfo[0] > 0:
286  aveLumi = LumiArray[1]*peakratio*lumiInfo[1]/lumiInfo[0] # scale by rec/del
287  LumiString = "[%d,%2.4e,%2.4e,%2.4e]," % (lumiS, aveLumi, LumiArray[2],pileup)
288  OUTPUTLINE += LumiString
289  InGap = 0
290  LumiString = "[%d,%2.4e,%2.4e,%2.4e]," % (LumiArray[0], LumiArray[1], LumiArray[2], LumiArray[3])
291  OUTPUTLINE += LumiString
292 
293 
294  lastindex=len(OUTPUTLINE)-1
295  trunc = OUTPUTLINE[0:lastindex]
296  OUTPUTLINE = trunc
297  OUTPUTLINE += ']}'
298  events.close()
299 
300  outputfile = open(output,'w')
301  if not outputfile:
302  raise RuntimeError("Could not open '%s' as an output JSON file" % output)
303 
304  outputfile.write(OUTPUTLINE)
305  outputfile.close()
306 
307  sys.exit()
308 
309 
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
OutputIterator zip(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp)
T sqrt(T t)
Definition: SSEVec.h:18
def CalcPileup(deadTable, parameters, luminometer, mode='deadtable')
#define str(s)