CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
specificLumi.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 ########################################################################
3 # Command to produce perbunch and specific lumi #
4 # #
5 # Author: Zhen Xie #
6 ########################################################################
7 #
8 # dump all fills into files.
9 # allfills.txt all the existing fills.
10 # fill_num.txt all the runs in the fill
11 # dumpFill -o outputdir
12 # dumpFill -f fillnum generate runlist for the given fill
13 #
14 import os,os.path,sys,math,array,datetime,time,calendar,re
15 import coral
16 
17 from RecoLuminosity.LumiDB import argparse,sessionManager,lumiTime,CommonUtil,lumiCalcAPI,lumiParameters,revisionDML,normDML
18 MINFILL=1800
19 MAXFILL=9999
20 allfillname='allfills.txt'
21 
22 def getFillFromDB(schema,fillnum):
23  '''
24  output: {run:starttime}
25  '''
26  runtimesInFill={}
27  fillrundict=lumiCalcAPI.fillrunMap(schema,fillnum)
28  if len(fillrundict)>0:
29  runs=fillrundict.values()[0]
30  runlsdict=dict(list(zip(runs,[None]*len(runs))))
31  runresult=lumiCalcAPI.runsummary(schema,runlsdict)
32  for perrundata in runresult:
33  runtimesInFill[perrundata[0]]=perrundata[7]
34  return runtimesInFill
35 
36 def listfilldir(indir):
37  '''
38  list all fills contained in the given dir
39  input: indir
40  output: [fill]
41  '''
42  fillnamepat=r'^[0-9]{4}$'
43  p=re.compile(fillnamepat)
44  processedfills=[]
45  dirList=os.listdir(indir)
46  for fname in dirList:
47  if p.match(fname) and os.path.isdir(os.path.join(indir,fname)):#found fill dir
48  allfs=os.listdir(os.path.join(indir,fname))
49  for myfile in allfs:
50  sumfilenamepat=r'^[0-9]{4}_bxsum_CMS.txt$'
51  s=re.compile(sumfilenamepat)
52  if s.match(myfile):
53  #only if fill_summary_CMS.txt file exists
54  processedfills.append(int(fname))
55  return processedfills
56 
57 def lastcompleteFill(infile):
58  '''
59  parse infile to find LASTCOMPLETEFILL
60  input: input file name
61  output: last completed fill number
62  '''
63  lastfill=None
64  hlinepat=r'(LASTCOMPLETEFILL )([0-9]{4})'
65  h=re.compile(hlinepat)
66  dqmfile=open(infile,'r')
67  for line in dqmfile:
68  result=h.match(line)
69  if result:
70  lastfill=result.group(2)
71  break
72  return int(lastfill)
73 
74 def calculateSpecificLumi(lumi,lumierr,beam1intensity,beam1intensityerr,beam2intensity,beam2intensityerr):
75  '''
76  calculate specific lumi
77  input: instlumi, instlumierror,beam1intensity,beam1intensityerror,beam2intensity,beam2intensityerror
78  output (specific lumi value,specific lumi error)
79  '''
80  specificlumi=0.0
81  specificlumierr=0.0
82  if beam1intensity<0: beam1intensity=0
83  if beam2intensity<0: beam2intensity=0
84  if beam1intensity>0.0 and beam2intensity>0.0:
85  specificlumi=float(lumi)/(float(beam1intensity)*float(beam2intensity))
86  specificlumierr=specificlumi*math.sqrt(lumierr**2/lumi**2+beam1intensityerr**2/beam1intensity**2+beam2intensityerr**2/beam2intensity**2)
87  return (specificlumi,specificlumierr)
88 
89 def getFillFromFile(fillnum,inputdir):
90  '''
91  parse fill_xxx.txt files in the input directory for runs, starttime in the fill
92  input: fillnumber, input dir
93  output: {run:tarttime}
94  '''
95  runtimesInFill={}
96  #look for files 'fill_num.txt' in inputdir
97  for filename in os.listdir(inputdir):
98  mpat=r'^fill_[0-9]{4}.txt$'
99  m=re.compile(mpat)
100  if m.match(filename) is None:
101  continue
102  filename=filename.strip()
103  if filename.find('.')==-1: continue
104  basename,extension=filename.split('.')
105  if not extension or extension!='txt':
106  continue
107  if basename.find('_')==-1: continue
108  prefix,number=basename.split('_')
109  if not number : continue
110  if fillnum!=int(number):continue
111  f=open(os.path.join(inputdir,'fill_'+number+'.txt'),'r')
112  for line in f:
113  l=line.strip()
114  fields=l.split(',')
115  if len(fields)<2 : continue
116  runtimesInFill[int(fields[0])]=fields[1]
117  f.close()
118  return runtimesInFill
119 
120 #####output methods####
121 def filltofiles(allfills,runsperfill,runtimes,dirname):
122  '''
123  write runnumber:starttime map per fill to files
124  '''
125  f=open(os.path.join(dirname,allfillname),'w')
126  for fill in allfills:
127  print >>f,'%d'%(fill)
128  f.close()
129  for fill,runs in runsperfill.items():
130  filename='fill_'+str(fill)+'.txt'
131  if len(runs)!=0:
132  f=open(os.path.join(dirname,filename),'w')
133  for run in runs:
134  print >>f,'%d,%s'%(run,runtimes[run])
135  f.close()
136 
137 def specificlumiTofile(fillnum,filldata,outdir):
138  #
139  #input : fillnum
140  # filldata: {bxidx:[[lstime,beamstatusfrac,lumivalue,lumierror,speclumi,speclumierr]],[]}
141  #sorted by bxidx, sorted by lstime inside list
142  #check outdir/fillnum subdir exists; if not, create it; else outdir=outdir/fillnum
143  #
144  if not filldata:
145  print 'empty input data, do nothing for fill ',fillnum
146  return
147  timedict={}#{lstime:[[stablebeamfrac,lumi,lumierr,speclumi,speclumierr]]}
148  filloutdir=os.path.join(outdir,str(fillnum))
149  if not os.path.exists(filloutdir):
150  os.mkdir(filloutdir)
151  for cmsbxidx,perbxdata in filldata.items():
152  lhcbucket=0
153  if cmsbxidx!=0:
154  lhcbucket=(cmsbxidx-1)*10+1
155  a=sorted(perbxdata,key=lambda x:x[0])
156  filename=str(fillnum)+'_lumi_'+str(lhcbucket)+'_CMS.txt'
157  linedata=[]
158  for perlsdata in a:
159  ts=int(perlsdata[0])
160  beamstatusfrac=perlsdata[1]
161  lumi=perlsdata[2]
162  lumierror=perlsdata[3]
163  #beam1intensity=perlsdata[4]
164  #beam2intensity=perlsdata[5]
165  speclumi=perlsdata[4]
166  speclumierror= perlsdata[5]
167  if lumi>0:
168  linedata.append([ts,beamstatusfrac,lumi,lumierror,speclumi,speclumierror])
169  if ts not in timedict:
170  timedict[ts]=[]
171  timedict[ts].append([beamstatusfrac,lumi,lumierror,speclumi,speclumierror])
172  if len(linedata)>10:#at least 10 good ls
173  f=open(os.path.join(filloutdir,filename),'w')
174  for line in linedata:
175  print >>f, '%d\t%e\t%e\t%e\t%e\t%e'%(line[0],line[1],line[2],line[3],line[4],line[5])
176  f.close()
177  #print 'writing avg file'
178  summaryfilename=str(fillnum)+'_lumi_CMS.txt'
179  f=None
180  lstimes=timedict.keys()
181  lstimes.sort()
182  fillseg=[]
183  lscounter=0
184  for lstime in lstimes:
185  allvalues=timedict[lstime]
186  transposedvalues=CommonUtil.transposed(allvalues,0.0)
187  bstatfrac=transposedvalues[0][0]#beamstatus does not change with bx position
188  lumivals=transposedvalues[1]
189  lumitot=sum(lumivals)
190  if bstatfrac==1.0 :
191  fillseg.append([lstime,lumitot])
192  lumierrs=transposedvalues[2]
193  lumierrortot=math.sqrt(sum(map(lambda x:x**2,lumierrs)))
194  specificvals=transposedvalues[3]
195  specificavg=sum(specificvals)/float(len(specificvals))#avg spec lumi
196  specificerrs=transposedvalues[4]
197  specifictoterr=math.sqrt(sum(map(lambda x:x**2,specificerrs)))
198  specificerravg=specifictoterr/float(len(specificvals))
199  if lscounter==0:
200  f=open(os.path.join(filloutdir,summaryfilename),'w')
201  lscounter+=1
202  print >>f,'%d\t%e\t%e\t%e\t%e\t%e'%(lstime,bstatfrac,lumitot,lumierrortot,specificavg,specificerravg)
203  if f is not None:
204  f.close()
205  #print 'writing summary file'
206  fillsummaryfilename=str(fillnum)+'_bxsum_CMS.txt'
207  f=open(os.path.join(filloutdir,fillsummaryfilename),'w')
208  if len(fillseg)==0:
209  print >>f,'%s'%('#no stable beams')
210  f.close()
211  return
212  previoustime=fillseg[0][0]
213  boundarytime=fillseg[0][0]
214  #print 'boundary time ',boundarytime
215  summaryls={}
216  summaryls[boundarytime]=[]
217  for [lstime,lumitot] in fillseg:#fillseg is everything with stable beam flag
218  if lstime-previoustime>50.0:
219  boundarytime=lstime
220  #print 'found new boundary ',boundarytime
221  summaryls[boundarytime]=[]
222  # print 'appending ',boundarytime,lstime,lumitot
223  summaryls[boundarytime].append([lstime,lumitot])
224  previoustime=lstime
225  #print summaryls
226 
227  summarylstimes=summaryls.keys()
228  summarylstimes.sort()
230  for bts in summarylstimes:
231  startts=bts
232  tsdatainseg=summaryls[bts]
233  #print 'tsdatainseg ',tsdatainseg
234  stopts=tsdatainseg[-1][0]
235  plu=max(CommonUtil.transposed(tsdatainseg,0.0)[1])
236  lui=sum(CommonUtil.transposed(tsdatainseg,0.0)[1])*lumip.lslengthsec()
237  print >>f,'%d\t%d\t%e\t%e'%(startts,stopts,plu,lui)
238  f.close()
239 
240 def getSpecificLumi(schema,fillnum,inputdir,dataidmap,normmap,xingMinLum=0.0,amodetag='PROTPHYS',bxAlgo='OCC1'):
241  '''
242  specific lumi in 1e-30 (ub-1s-1) unit
243  lumidetail occlumi in 1e-27
244  1309_lumi_401_CMS.txt
245  time(in seconds since January 1,2011,00:00:00 UTC) stab(fraction of time spent in stable beams for this time bin) l(lumi in Hz/ub) dl(point-to-point error on lumi in Hz/ub) sl(specific lumi in Hz/ub) dsl(error on specific lumi)
246  20800119.0 1 -0.889948 0.00475996848729 0.249009 0.005583287562 -0.68359 6.24140208607 0.0 0.0 0.0 0.0 0.0 0.0 0.0383576 0.00430892097862 0.0479095 0.00430892097862 66.6447 4.41269758764 0.0 0.0 0.0
247  result [(time,beamstatusfrac,lumi,lumierror,speclumi,speclumierror)]
248  '''
250  fillbypos={}#{bxidx:[[ts,beamstatusfrac,lumi,lumierror,spec1,specerror],[]]}
251  runtimesInFill=getFillFromDB(schema,fillnum)#{runnum:starttimestr}
252  runlist=runtimesInFill.keys()
253  if not runlist: return fillbypos
254  irunlsdict=dict(list(zip(runlist,[None]*len(runlist))))
255  #prirunlsdict
256  GrunsummaryData=lumiCalcAPI.runsummaryMap(session.nominalSchema(),irunlsdict)
257  lumidetails=lumiCalcAPI.deliveredLumiForIds(schema,irunlsdict,dataidmap,GrunsummaryData,beamstatusfilter=None,normmap=normmap,withBXInfo=True,bxAlgo=bxAlgo,xingMinLum=xingMinLum,withBeamIntensity=True,lumitype='HF')
258  #
259  #output: {run:[lumilsnum(0),cmslsnum(1),timestamp(2),beamstatus(3),beamenergy(4),deliveredlumi(5),calibratedlumierr(6),(bxvalues,bxerrs)(7),(bxidx,b1intensities,b2intensities)(8),fillnum(9)]}
260  #
261  totalstablebeamls=0
262  orderedrunlist=sorted(lumidetails)
263  for run in orderedrunlist:
264  perrundata=lumidetails[run]
265  for perlsdata in perrundata:
266  beamstatus=perlsdata[3]
267  if beamstatus=='STABLE BEAMS':
268  totalstablebeamls+=1
269  #print 'totalstablebeamls in fill ',totalstablebeamls
270  if totalstablebeamls<10:#less than 10 LS in a fill has 'stable beam', it's no a good fill
271  print 'fill ',fillnum,' , having less than 10 stable beam lS, is not good, skip'
272  return fillbypos
274  for run in orderedrunlist:
275  perrundata=lumidetails[run]
276  for perlsdata in perrundata:
277  beamstatusfrac=0.0
278  tsdatetime=perlsdata[2]
279  ts=calendar.timegm(tsdatetime.utctimetuple())
280  beamstatus=perlsdata[3]
281  if beamstatus=='STABLE BEAMS':
282  beamstatusfrac=1.0
283  (bxidxlist,bxvaluelist,bxerrolist)=perlsdata[7]
284  #instbxvaluelist=[x/lumiparam.lslengthsec() for x in bxvaluelist if x]
285  instbxvaluelist=[x for x in bxvaluelist if x]
286  maxlumi=0.0
287  if len(instbxvaluelist)!=0:
288  maxlumi=max(instbxvaluelist)
289  avginstlumi=0.0
290  if len(instbxvaluelist)!=0:
291  avginstlumi=sum(instbxvaluelist)
292  (intbxidxlist,b1intensities,b2intensities)=perlsdata[8]#contains only non-zero bx
293  for bxidx in bxidxlist:
294  idx=bxidxlist.index(bxidx)
295  instbxvalue=bxvaluelist[idx]
296  bxerror=bxerrolist[idx]
297  if instbxvalue<max(xingMinLum,maxlumi*0.2):
298  continue
299  bintensityPos=-1
300  try:
301  bintensityPos=intbxidxlist.index(bxidx)
302  except ValueError:
303  pass
304  if bintensityPos<=0:
305  fillbypos.setdefault(bxidx,[]).append([ts,beamstatusfrac,instbxvalue,bxerror,0.0,0.0])
306  continue
307  b1intensity=b1intensities[bintensityPos]
308  b2intensity=b2intensities[bintensityPos]
309  speclumi=calculateSpecificLumi(instbxvalue,bxerror,b1intensity,0.0,b2intensity,0.0)
310  fillbypos.setdefault(bxidx,[]).append([ts,beamstatusfrac,instbxvalue,bxerror,speclumi[0],speclumi[1]])
311  return fillbypos
312 
313 
314 ##############################
315 ## ######################## ##
316 ## ## ################## ## ##
317 ## ## ## Main Program ## ## ##
318 ## ## ################## ## ##
319 ## ######################## ##
320 ##############################
321 
322 if __name__ == '__main__':
323  parser = argparse.ArgumentParser(prog=os.path.basename(sys.argv[0]),description = "specific lumi",formatter_class=argparse.ArgumentDefaultsHelpFormatter)
324  amodetagChoices = [ "PROTPHYS","IONPHYS",'PAPHYS' ]
325  xingAlgoChoices =[ "OCC1","OCC2","ET"]
326  # parse arguments
327  parser.add_argument('-c',dest='connect',
328  action='store',
329  required=False,
330  help='connect string to lumiDB,optional',
331  default='frontier://LumiCalc/CMS_LUMI_PROD')
332  parser.add_argument('-P',dest='authpath',
333  action='store',
334  help='path to authentication file,optional')
335  parser.add_argument('-i',dest='inputdir',
336  action='store',
337  required=False,
338  help='output dir',
339  default='.')
340  parser.add_argument('-o',dest='outputdir',
341  action='store',
342  required=False,
343  help='output dir',
344  default='.')
345  parser.add_argument('-f','--fill',dest='fillnum',
346  action='store',
347  required=False,
348  help='specific fill',
349  default=None)
350  parser.add_argument('--minfill',dest='minfill',
351  type=int,
352  action='store',
353  required=False,
354  default=MINFILL,
355  help='min fill')
356  parser.add_argument('--maxfill',dest='maxfill',
357  type=int,
358  action='store',
359  required=False,
360  default=MAXFILL,
361  help='maximum fillnumber '
362  )
363  parser.add_argument('--amodetag',dest='amodetag',
364  action='store',
365  choices=amodetagChoices,
366  required=False,
367  help='specific accelerator mode choices [PROTOPHYS,IONPHYS,PAPHYS] (optional)')
368  parser.add_argument('--xingMinLum', dest = 'xingMinLum',
369  type=float,
370  default=1e-03,
371  required=False,
372  help='Minimum luminosity considered for lumibylsXing action')
373  parser.add_argument('--xingAlgo', dest = 'bxAlgo',
374  default='OCC1',
375  required=False,
376  help='algorithm name for per-bunch lumi ')
377  parser.add_argument('--normtag',dest='normtag',action='store',
378  required=False,
379  help='norm tag',
380  default=None)
381  parser.add_argument('--datatag',dest='datatag',action='store',
382  required=False,
383  help='data tag',
384  default=None)
385  #
386  #command configuration
387  #
388  parser.add_argument('--siteconfpath',dest='siteconfpath',action='store',
389  help='specific path to site-local-config.xml file, optional. If path undefined, fallback to cern proxy&server')
390  #
391  #switches
392  #
393  parser.add_argument('--without-correction',dest='withoutNorm',action='store_true',
394  help='without any correction/calibration' )
395  parser.add_argument('--debug',dest='debug',action='store_true',
396  help='debug')
397  options=parser.parse_args()
398  if options.authpath:
399  os.environ['CORAL_AUTH_PATH'] = options.authpath
400  ##
401  #query DB for all fills and compare with allfills.txt
402  #if found newer fills, store in mem fill number
403  #reprocess anyway the last 1 fill in the dir
404  #redo specific lumi for all marked fills
405  ##
406  svc=sessionManager.sessionManager(options.connect,authpath=options.authpath,debugON=options.debug)
407  session=svc.openSession(isReadOnly=True,cpp2sqltype=[('unsigned int','NUMBER(10)'),('unsigned long long','NUMBER(20)')])
408 
409  fillstoprocess=[]
410  maxfillnum=options.maxfill
411  minfillnum=options.minfill
412  if options.fillnum is not None: #if process a specific single fill
413  fillstoprocess.append(int(options.fillnum))
414  else:
415  session.transaction().start(True)
416  schema=session.nominalSchema()
417  allfillsFromDB=lumiCalcAPI.fillInRange(schema,fillmin=minfillnum,fillmax=maxfillnum,amodetag=options.amodetag)
418  processedfills=listfilldir(options.outputdir)
419  lastcompletedFill=lastcompleteFill(os.path.join(options.inputdir,'runtofill_dqm.txt'))
420  for pf in processedfills:
421  if pf>lastcompletedFill:
422  print '\tremove unfinished fill from processed list ',pf
423  processedfills.remove(pf)
424  for fill in allfillsFromDB:
425  if fill not in processedfills :
426  if int(fill)<=lastcompletedFill:
427  if int(fill)>minfillnum and int(fill)<maxfillnum:
428  fillstoprocess.append(fill)
429  else:
430  print 'ongoing fill...',fill
431  session.transaction().commit()
432  print 'fills to process : ',fillstoprocess
433  if len(fillstoprocess)==0:
434  print 'no fill to process, exit '
435  exit(0)
436 
437 
438  print '===== Start Processing Fills',fillstoprocess
439  print '====='
440  filldata={}
441  #
442  # check datatag
443  #
444  reqfillmin=min(fillstoprocess)
445  reqfillmax=max(fillstoprocess)
446  session.transaction().start(True)
447  runlist=lumiCalcAPI.runList(session.nominalSchema(),options.fillnum,runmin=None,runmax=None,fillmin=reqfillmin,fillmax=reqfillmax,startT=None,stopT=None,l1keyPattern=None,hltkeyPattern=None,amodetag=options.amodetag,nominalEnergy=None,energyFlut=None,requiretrg=False,requirehlt=False)
448 
449  datatagname=options.datatag
450  if not datatagname:
451  (datatagid,datatagname)=revisionDML.currentDataTag(session.nominalSchema())
452  dataidmap=revisionDML.dataIdsByTagId(session.nominalSchema(),datatagid,runlist=runlist,withcomment=False)
453  #{run:(lumidataid,trgdataid,hltdataid,())}
454  else:
455  dataidmap=revisionDML.dataIdsByTagName(session.nominalSchema(),datatagname,runlist=runlist,withcomment=False)
456 
457  #
458  # check normtag and get norm values if required
459  #
460  normname='NONE'
461  normid=0
462  normvalueDict={}
463  if not options.withoutNorm:
464  normname=options.normtag
465  if not normname:
466  normmap=normDML.normIdByType(session.nominalSchema(),lumitype='HF',defaultonly=True)
467  if len(normmap):
468  normname=normmap.keys()[0]
469  normid=normmap[normname]
470  else:
471  normid=normDML.normIdByName(session.nominalSchema(),normname)
472  if not normid:
473  raise RuntimeError('[ERROR] cannot resolve norm/correction')
474  sys.exit(-1)
475  normvalueDict=normDML.normValueById(session.nominalSchema(),normid) #{since:[corrector(0),{paramname:paramvalue}(1),amodetag(2),egev(3),comment(4)]}
476  session.transaction().commit()
477  for fillnum in fillstoprocess:# process per fill
478  session.transaction().start(True)
479  filldata=getSpecificLumi(session.nominalSchema(),fillnum,options.inputdir,dataidmap,normvalueDict,xingMinLum=options.xingMinLum,amodetag=options.amodetag,bxAlgo=options.bxAlgo)
480  specificlumiTofile(fillnum,filldata,options.outputdir)
481  session.transaction().commit()
482 
483 
Definition: start.py:1
boost::dynamic_bitset append(const boost::dynamic_bitset<> &bs1, const boost::dynamic_bitset<> &bs2)
this method takes two bitsets bs1 and bs2 and returns result of bs2 appended to the end of bs1 ...
def calculateSpecificLumi
Definition: specificLumi.py:74
def getFillFromFile
Definition: specificLumi.py:89
def dataIdsByTagId
Definition: revisionDML.py:798
def transposed
Definition: CommonUtil.py:146
OutputIterator zip(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp)
def normIdByType
Definition: normDML.py:92
def dataIdsByTagName
Definition: revisionDML.py:689
T min(T a, T b)
Definition: MathUtil.h:58
def runsummary
Lumi data management and calculation API # # Author: Zhen Xie #.
Definition: lumiCalcAPI.py:10
def specificlumiTofile
def fillrunMap
Definition: lumiCalcAPI.py:41
def currentDataTag
Definition: revisionDML.py:513
def lastcompleteFill
Definition: specificLumi.py:57
def fillInRange
Definition: lumiCalcAPI.py:35
def normValueById
Definition: normDML.py:181
def deliveredLumiForIds
Definition: lumiCalcAPI.py:369
def filltofiles
output methods####
def runsummaryMap
Definition: lumiCalcAPI.py:21
def normIdByName
Definition: normDML.py:60
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run