CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_1/src/RecoLuminosity/LumiDB/scripts/specificLumi.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # dump all fills into files.
00004 # allfills.txt all the existing fills.
00005 # fill_num.txt all the runs in the fill
00006 # dumpFill -o outputdir
00007 # dumpFill -f fillnum generate runlist for the given fill
00008 #
00009 import os,os.path,sys,math,array,datetime,time,calendar,re
00010 import coral
00011 
00012 from RecoLuminosity.LumiDB import argparse,sessionManager,lumiTime,CommonUtil,lumiCalcAPI,lumiCorrections,lumiParameters
00013 MINFILL=1800
00014 MAXFILL=9999
00015 allfillname='allfills.txt'
00016 
00017 def getFillFromDB(schema,fillnum):
00018     '''
00019     output: {run:starttime}
00020     '''
00021     runtimesInFill={}
00022     fillrundict=lumiCalcAPI.fillrunMap(schema,fillnum)
00023     if len(fillrundict)>0:
00024         runs=fillrundict.values()[0]
00025         runlsdict=dict(zip(runs,[None]*len(runs)))
00026         runresult=lumiCalcAPI.runsummary(schema,runlsdict)    
00027         for perrundata in runresult:
00028             runtimesInFill[perrundata[0]]=perrundata[7]
00029     return runtimesInFill
00030 
00031 def listfilldir(indir):
00032     '''
00033     list all fills contained in the given dir
00034     input: indir
00035     output: [fill]
00036     '''
00037     fillnamepat=r'^[0-9]{4}$'
00038     p=re.compile(fillnamepat)
00039     processedfills=[]
00040     dirList=os.listdir(indir)
00041     for fname in dirList:
00042         if p.match(fname) and os.path.isdir(os.path.join(indir,fname)):#found fill dir
00043             allfs=os.listdir(os.path.join(indir,fname))
00044             for myfile in allfs:
00045                 sumfilenamepat=r'^[0-9]{4}_bxsum_CMS.txt$'
00046                 s=re.compile(sumfilenamepat)
00047                 if s.match(myfile):
00048                     #only if fill_summary_CMS.txt file exists
00049                     processedfills.append(int(fname))
00050     return processedfills
00051 
00052 def lastcompleteFill(infile):
00053     '''
00054     parse infile to find LASTCOMPLETEFILL
00055     input: input file name
00056     output: last completed fill number
00057     '''
00058     lastfill=None
00059     hlinepat=r'(LASTCOMPLETEFILL )([0-9]{4})'
00060     h=re.compile(hlinepat)
00061     dqmfile=open(infile,'r')
00062     for line in dqmfile:
00063         result=h.match(line)
00064         if result:
00065             lastfill=result.group(2)
00066             break
00067     return int(lastfill)
00068 
00069 def calculateSpecificLumi(lumi,lumierr,beam1intensity,beam1intensityerr,beam2intensity,beam2intensityerr):
00070     '''
00071     calculate specific lumi
00072     input: instlumi, instlumierror,beam1intensity,beam1intensityerror,beam2intensity,beam2intensityerror
00073     output (specific lumi value,specific lumi error)
00074     '''
00075     specificlumi=0.0
00076     specificlumierr=0.0
00077     if beam1intensity<0: beam1intensity=0
00078     if beam2intensity<0: beam2intensity=0
00079     if beam1intensity!=0.0 and  beam2intensity!=0.0:
00080         specificlumi=float(lumi)/(float(beam1intensity)*float(beam2intensity))
00081         specificlumierr=specificlumi*math.sqrt(lumierr**2/lumi**2+beam1intensityerr**2/beam1intensity**2+beam2intensityerr**2/beam2intensity**2)
00082     return (specificlumi,specificlumierr)
00083 
00084 def getFillFromFile(fillnum,inputdir):
00085     '''
00086     parse fill_xxx.txt files in the input directory for runs, starttime in the fill
00087     input: fillnumber, input dir
00088     output: {run:tarttime}
00089     '''
00090     runtimesInFill={}
00091     #look for files 'fill_num.txt' in inputdir
00092     for filename in os.listdir(inputdir):
00093         mpat=r'^fill_[0-9]{4}.txt$'
00094         m=re.compile(mpat)
00095         if m.match(filename) is None:
00096             continue
00097         filename=filename.strip()
00098         if filename.find('.')==-1: continue            
00099         basename,extension=filename.split('.')        
00100         if not extension or extension!='txt':
00101             continue
00102         if basename.find('_')==-1: continue
00103         prefix,number=basename.split('_')
00104         if not number : continue
00105         if fillnum!=int(number):continue
00106         f=open(os.path.join(inputdir,'fill_'+number+'.txt'),'r')
00107         for line in f:
00108             l=line.strip()
00109             fields=l.split(',')
00110             if len(fields)<2 : continue
00111             runtimesInFill[int(fields[0])]=fields[1]
00112         f.close()
00113     return runtimesInFill
00114 
00115 #####output methods####
00116 def filltofiles(allfills,runsperfill,runtimes,dirname):
00117     '''
00118     write runnumber:starttime map per fill to files
00119     '''
00120     f=open(os.path.join(dirname,allfillname),'w')
00121     for fill in allfills:
00122         print >>f,'%d'%(fill)
00123     f.close()
00124     for fill,runs in runsperfill.items():
00125         filename='fill_'+str(fill)+'.txt'
00126         if len(runs)!=0:
00127             f=open(os.path.join(dirname,filename),'w')
00128             for run in runs:
00129                 print >>f,'%d,%s'%(run,runtimes[run])
00130             f.close()
00131             
00132 def specificlumiTofile(fillnum,filldata,outdir):
00133     #
00134     #input : fillnum
00135     #        filldata: {bxidx:[[lstime,beamstatusfrac,lumivalue,lumierror,speclumi,speclumierr]],[]}
00136     #sorted by bxidx, sorted by lstime inside list
00137     #check outdir/fillnum subdir exists; if not, create it; else outdir=outdir/fillnum
00138     #
00139     if not filldata:
00140         print 'empty input data, do nothing for fill ',fillnum
00141         return
00142     timedict={}#{lstime:[[stablebeamfrac,lumi,lumierr,speclumi,speclumierr]]}
00143     filloutdir=os.path.join(outdir,str(fillnum))
00144     if not os.path.exists(filloutdir):
00145         os.mkdir(filloutdir)
00146     for cmsbxidx,perbxdata in filldata.items():
00147         lhcbucket=0
00148         if cmsbxidx!=0:
00149             lhcbucket=(cmsbxidx-1)*10+1
00150         a=sorted(perbxdata,key=lambda x:x[0])
00151         filename=str(fillnum)+'_lumi_'+str(lhcbucket)+'_CMS.txt'
00152         linedata=[]
00153         for perlsdata in a:
00154             ts=int(perlsdata[0])
00155             beamstatusfrac=perlsdata[1]
00156             lumi=perlsdata[2]
00157             lumierror=perlsdata[3]
00158             #beam1intensity=perlsdata[4]
00159             #beam2intensity=perlsdata[5]
00160             speclumi=perlsdata[4]
00161             speclumierror= perlsdata[5]
00162             if lumi>0:
00163                 linedata.append([ts,beamstatusfrac,lumi,lumierror,speclumi,speclumierror])
00164             if not timedict.has_key(ts):
00165                 timedict[ts]=[]
00166             timedict[ts].append([beamstatusfrac,lumi,lumierror,speclumi,speclumierror])
00167         if len(linedata)>10:#at least 10 good ls
00168             f=open(os.path.join(filloutdir,filename),'w')
00169             for line in linedata:
00170                 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])
00171             f.close()
00172     #print 'writing avg file'
00173     summaryfilename=str(fillnum)+'_lumi_CMS.txt'
00174     f=None
00175     lstimes=timedict.keys()
00176     lstimes.sort()
00177     fillseg=[]
00178     lscounter=0
00179     for lstime in lstimes:
00180         allvalues=timedict[lstime]
00181         transposedvalues=CommonUtil.transposed(allvalues,0.0)
00182         bstatfrac=transposedvalues[0][0]#beamstatus does not change with bx position
00183         lumivals=transposedvalues[1]
00184         lumitot=sum(lumivals)
00185         if bstatfrac==1.0 :
00186             fillseg.append([lstime,lumitot])
00187         lumierrs=transposedvalues[2]
00188         lumierrortot=math.sqrt(sum(map(lambda x:x**2,lumierrs)))
00189         specificvals=transposedvalues[3]
00190         specificavg=sum(specificvals)/float(len(specificvals))#avg spec lumi
00191         specificerrs=transposedvalues[4]
00192         specifictoterr=math.sqrt(sum(map(lambda x:x**2,specificerrs)))
00193         specificerravg=specifictoterr/float(len(specificvals))
00194         if lscounter==0:
00195             f=open(os.path.join(filloutdir,summaryfilename),'w')
00196         lscounter+=1
00197         print >>f,'%d\t%e\t%e\t%e\t%e\t%e'%(lstime,bstatfrac,lumitot,lumierrortot,specificavg,specificerravg)
00198     if f is not None:
00199         f.close()
00200     #print 'writing summary file'
00201     fillsummaryfilename=str(fillnum)+'_bxsum_CMS.txt'
00202     f=open(os.path.join(filloutdir,fillsummaryfilename),'w')    
00203     if len(fillseg)==0:
00204         print >>f,'%s'%('#no stable beams')
00205         f.close()
00206         return
00207     previoustime=fillseg[0][0]
00208     boundarytime=fillseg[0][0]
00209     #print 'boundary time ',boundarytime
00210     summaryls={}
00211     summaryls[boundarytime]=[]
00212     for [lstime,lumitot] in fillseg:#fillseg is everything with stable beam flag
00213         if lstime-previoustime>50.0:
00214             boundarytime=lstime
00215             #print 'found new boundary ',boundarytime
00216             summaryls[boundarytime]=[]
00217      #   print 'appending ',boundarytime,lstime,lumitot
00218         summaryls[boundarytime].append([lstime,lumitot])
00219         previoustime=lstime
00220     #print summaryls
00221    
00222     summarylstimes=summaryls.keys()
00223     summarylstimes.sort()
00224     lumip=lumiParameters.ParametersObject()
00225     for bts in summarylstimes:
00226         startts=bts
00227         tsdatainseg=summaryls[bts]
00228         #print 'tsdatainseg ',tsdatainseg
00229         stopts=tsdatainseg[-1][0]
00230         plu=max(CommonUtil.transposed(tsdatainseg,0.0)[1])
00231         lui=sum(CommonUtil.transposed(tsdatainseg,0.0)[1])*lumip.lslengthsec()
00232         print >>f,'%d\t%d\t%e\t%e'%(startts,stopts,plu,lui)
00233     f.close()
00234 
00235 def getSpecificLumi(schema,fillnum,inputdir,xingMinLum=0.0,norm='pp7TeV',withcorrection=True,amodetag='PROTPHYS',bxAlgo='OCC1'):
00236     '''
00237     specific lumi in 1e-30 (ub-1s-1) unit
00238     lumidetail occlumi in 1e-27
00239     1309_lumi_401_CMS.txt
00240     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)
00241     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
00242     result [(time,beamstatusfrac,lumi,lumierror,speclumi,speclumierror)]
00243     '''
00244     t=lumiTime.lumiTime()
00245     fillbypos={}#{bxidx:[[ts,beamstatusfrac,lumi,lumierror,spec1,specerror],[]]}
00246     runtimesInFill=getFillFromDB(schema,fillnum)#{runnum:starttimestr}
00247     runlist=runtimesInFill.keys()
00248     if not runlist: return fillbypos
00249     irunlsdict=dict(zip(runlist,[None]*len(runlist)))
00250     #print irunlsdict
00251     finecorrections=None
00252     driftcorrections=None
00253     if withcorrection :
00254         cterms=lumiCorrections.nonlinearV2()
00255         finecorrections=lumiCorrections.correctionsForRangeV2(schema,runlist,cterms)#constant+nonlinear corrections
00256         driftcorrections=lumiCorrections.driftcorrectionsForRange(schema,runlist,cterms)
00257     lumidetails=lumiCalcAPI.instCalibratedLumiForRange(schema,irunlsdict,beamstatus=None,amodetag=amodetag,withBXInfo=True,withBeamIntensity=True,bxAlgo=bxAlgo,xingMinLum=xingMinLum,norm=norm,finecorrections=finecorrections,driftcorrections=driftcorrections,usecorrectionv2=True)
00258     session.transaction().commit()
00259     #
00260     #output: {run:[lumilsnum(0),cmslsnum(1),timestamp(2),beamstatus(3),beamenergy(4),calibratedlumi(5),calibratedlumierr(6),startorbit(7),numorbit(8),(bxvalues,bxerrs)(9),(bxidx,b1intensities,b2intensities)(10)]}}
00261     #
00262     totalstablebeamls=0
00263     orderedrunlist=sorted(lumidetails)
00264     for run in orderedrunlist:
00265         perrundata=lumidetails[run]
00266         for perlsdata in perrundata:
00267             beamstatus=perlsdata[3]
00268             if beamstatus=='STABLE BEAMS':
00269                 totalstablebeamls+=1
00270     #print 'totalstablebeamls in fill ',totalstablebeamls
00271     if totalstablebeamls<10:#less than 10 LS in a fill has 'stable beam', it's no a good fill
00272         print 'fill ',fillnum,' , having less than 10 stable beam lS, is not good, skip'
00273         return fillbypos
00274     for run in orderedrunlist:
00275         perrundata=lumidetails[run]
00276         for perlsdata in perrundata:
00277             beamstatusfrac=0.0
00278             tsdatetime=perlsdata[2]
00279             ts=calendar.timegm(tsdatetime.utctimetuple())
00280             beamstatus=perlsdata[3]
00281             if beamstatus=='STABLE BEAMS':
00282                 beamstatusfrac=1.0
00283             (bxidxlist,bxvaluelist,bxerrolist)=perlsdata[9]
00284             maxlumi=0.0
00285             if len(bxvaluelist)!=0:
00286                 maxlumi=max(bxvaluelist)
00287             avginstlumi=0.0
00288             if len(bxvaluelist)!=0:
00289                 avginstlumi=sum(bxvaluelist)
00290             (intbxidxlist,b1intensities,b2intensities)=perlsdata[10]#contains only non-zero bx
00291             for bxidx in bxidxlist:
00292                 idx=bxidxlist.index(bxidx)
00293                 bxvalue=bxvaluelist[idx]
00294                 bxerror=bxerrolist[idx]
00295                 if bxvalue<max(xingMinLum,maxlumi*0.2):
00296                     continue
00297                 bintensityPos=-1
00298                 try:
00299                     bintensityPos=intbxidxlist.index(bxidx)
00300                 except ValueError:
00301                     pass
00302                 if bintensityPos<=0:
00303                     fillbypos.setdefault(bxidx,[]).append([ts,beamstatusfrac,bxvalue,bxerror,0.0,0.0])
00304                     continue
00305                 b1intensity=b1intensities[bintensityPos]
00306                 b2intensity=b2intensities[bintensityPos]
00307                 speclumi=calculateSpecificLumi(bxvalue,bxerror,b1intensity,0.0,b2intensity,0.0)
00308                 fillbypos.setdefault(bxidx,[]).append([ts,beamstatusfrac,bxvalue,bxerror,speclumi[0],speclumi[1]])
00309     return fillbypos
00310 
00311 
00312 ##############################
00313 ## ######################## ##
00314 ## ## ################## ## ##
00315 ## ## ## Main Program ## ## ##
00316 ## ## ################## ## ##
00317 ## ######################## ##
00318 ##############################
00319         
00320 if __name__ == '__main__':
00321     parser = argparse.ArgumentParser(prog=os.path.basename(sys.argv[0]),description = "specific lumi",formatter_class=argparse.ArgumentDefaultsHelpFormatter)
00322     amodetagChoices = [ "PROTPHYS","IONPHYS",'PAPHYS' ]
00323     xingAlgoChoices =[ "OCC1","OCC2","ET"]
00324     # parse arguments
00325     parser.add_argument('-c',dest='connect',
00326                         action='store',
00327                         required=False,
00328                         help='connect string to lumiDB,optional',
00329                         default='frontier://LumiCalc/CMS_LUMI_PROD')
00330     parser.add_argument('-P',dest='authpath',
00331                         action='store',
00332                         help='path to authentication file,optional')
00333     parser.add_argument('-i',dest='inputdir',
00334                         action='store',
00335                         required=False,
00336                         help='output dir',
00337                         default='.')
00338     parser.add_argument('-o',dest='outputdir',
00339                         action='store',
00340                         required=False,
00341                         help='output dir',
00342                         default='.')
00343     parser.add_argument('-f','--fill',dest='fillnum',
00344                         action='store',
00345                         required=False,
00346                         help='specific fill',
00347                         default=None)
00348     parser.add_argument('--minfill',dest='minfill',
00349                         type=int,
00350                         action='store',
00351                         required=False,
00352                         default=MINFILL,
00353                         help='min fill')
00354     parser.add_argument('--maxfill',dest='maxfill',
00355                         type=int,
00356                         action='store',
00357                         required=False,
00358                         default=MAXFILL,
00359                         help='maximum fillnumber '
00360                         )
00361     parser.add_argument('--amodetag',dest='amodetag',
00362                         action='store',
00363                         choices=amodetagChoices,
00364                         required=False,
00365                         help='specific accelerator mode choices [PROTOPHYS,IONPHYS,PAPHYS] (optional)')
00366     parser.add_argument('--xingMinLum', dest = 'xingMinLum',
00367                         type=float,
00368                         default=1e-03,
00369                         required=False,
00370                         help='Minimum luminosity considered for lumibylsXing action')
00371     parser.add_argument('--xingAlgo', dest = 'bxAlgo',
00372                         default='OCC1',
00373                         required=False,
00374                         help='algorithm name for per-bunch lumi ')
00375     parser.add_argument('--norm',dest='normfactor',action='store',
00376                         required=False,
00377                         help='norm',
00378                         default=None)
00379     #
00380     #command configuration 
00381     #
00382     parser.add_argument('--siteconfpath',dest='siteconfpath',action='store',
00383                         help='specific path to site-local-config.xml file, optional. If path undefined, fallback to cern proxy&server')
00384     #
00385     #switches
00386     #
00387     parser.add_argument('--without-correction',dest='withoutFineCorrection',action='store_true',
00388                         help='without fine correction on calibration' )
00389     parser.add_argument('--debug',dest='debug',action='store_true',
00390                         help='debug')
00391     options=parser.parse_args()
00392     if options.authpath:
00393         os.environ['CORAL_AUTH_PATH'] = options.authpath
00394     ##
00395     #query DB for all fills and compare with allfills.txt
00396     #if found newer fills, store  in mem fill number
00397     #reprocess anyway the last 1 fill in the dir
00398     #redo specific lumi for all marked fills
00399     ##    
00400     normfactor=options.normfactor
00401     svc=sessionManager.sessionManager(options.connect,authpath=options.authpath,debugON=options.debug)
00402     session=svc.openSession(isReadOnly=True,cpp2sqltype=[('unsigned int','NUMBER(10)'),('unsigned long long','NUMBER(20)')])
00403 
00404     fillstoprocess=[]
00405     maxfillnum=options.maxfill
00406     minfillnum=options.minfill
00407     if options.fillnum is not None: #if process a specific single fill
00408         fillstoprocess.append(int(options.fillnum))
00409     else:
00410         session.transaction().start(True)
00411         schema=session.nominalSchema()
00412         allfillsFromDB=lumiCalcAPI.fillInRange(schema,fillmin=minfillnum,fillmax=maxfillnum,amodetag=options.amodetag)
00413         processedfills=listfilldir(options.outputdir)
00414         lastcompletedFill=lastcompleteFill(os.path.join(options.inputdir,'runtofill_dqm.txt'))
00415         for pf in processedfills:
00416             if pf>lastcompletedFill:
00417                 print '\tremove unfinished fill from processed list ',pf
00418                 processedfills.remove(pf)
00419         for fill in allfillsFromDB:
00420             if fill not in processedfills :
00421                 if int(fill)<=lastcompletedFill:
00422                     if int(fill)>minfillnum and int(fill)<maxfillnum:
00423                         fillstoprocess.append(fill)
00424                 else:
00425                     print 'ongoing fill...',fill
00426         session.transaction().commit()
00427     print 'fills to process : ',fillstoprocess
00428     if len(fillstoprocess)==0:
00429         print 'no fill to process, exit '
00430         exit(0)
00431     finecorrections=None
00432     driftcorrections=None
00433     print '===== Start Processing Fills',fillstoprocess
00434     print '====='
00435     withcorrection=not options.withoutFineCorrection
00436     filldata={}
00437     session.transaction().start(True)
00438     for fillnum in fillstoprocess:# process per fill
00439         filldata=getSpecificLumi(session.nominalSchema(),fillnum,options.inputdir,xingMinLum=options.xingMinLum,norm=options.normfactor,withcorrection=withcorrection,amodetag=options.amodetag,bxAlgo=options.bxAlgo)
00440         specificlumiTofile(fillnum,filldata,options.outputdir)
00441     session.transaction().commit()
00442 
00443