CMS 3D CMS Logo

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