ATLAS Offline Software
Loading...
Searching...
No Matches
uploadTools.py
Go to the documentation of this file.
2from csv import reader
3import math,os,glob,subprocess
4import datetime
5from collections import OrderedDict
6
7import pyAMI.client
8
9
10class UT:
11 # This class contains the various tools required to upload values to the AMI physicsParameterVals DB table.
12
13 def __init__(self,istest=True,verbose=False,alwaysyes=False,xsRefFile=None,delim=";"):
14 # initialise
15 self.istest=istest
16 self.verbose=verbose
17 self.alwaysyes=alwaysyes
18 self.xsRefFile=xsRefFile
19 self.delim=delim
21 self.newVals={}
22 if self.xsRefFile:
23 self.xsRefLines=open(self.xsRefFile).readlines()
24
25 if self.verbose: print "Initialising..."
26
27 self.client=pyAMI.client.Client(
28 'atlas'
29 #'atlas-replica'
30 )
31
32 self.colors=self.bcolors(False)
33
34 def checkUpload(self,origexplanation):
35 # check that you really want to commit to the DB
36
37 tmpans=False
38 if self.alwaysyes:
39 # always commit
40 return True,False,origexplanation
41
42 else:
43 answer='X'
44 while answer not in ['y','n','exp','a']: answer = raw_input('Continue with upload? (y/n/exp/a): ')
45 if answer=='y':
46 # upload with original explanation
47 print self.colors.OKGREEN+"Commiting upload!"+self.colors.ENDC
48 return True,False,origexplanation
49 elif answer=='a':
50 # upload with automatic explanation
51 print self.colors.OKGREEN+"Commiting upload!"+self.colors.ENDC
52 return True,False,"Automatic CentralPage upload"
53 elif answer=='exp':
54 # enter new explanation
55 explanswer='X'
56 while not tmpans:
57 explanation = raw_input('Please enter explanation: ')
58 explanswer='X'
59 while explanswer not in ['y','n','d','a']: explanswer = raw_input('Continue upload with new explanation "%s"? (y/n/d[go back to default]/a[automatic message]): '%explanation)
60 if explanswer in ['y','d','a']:
61 tmpans=True
62
63 print self.colors.OKGREEN+"Commiting upload!"+self.colors.ENDC
64 if explanswer=='y':
65 return True,True,explanation
66 elif explanswer=='a':
67 return True,False,"Automatic CentralPage upload"
68 elif explanswer=='d':
69 return True,False,origexplanation
70
71 else:
72 # do not commit
73 print self.colors.OKBLUE+"Not comitting upload."+self.colors.ENDC
74 return False,False,origexplanation
75
76
77
78 def cmdExec(self,cmd,explanation):
79 # execute AMI upload command
80 print "-->",cmd
81 oldexplanation=explanation
82 doUpload,newExplanation,explanation=self.checkUpload(oldexplanation)
83 if doUpload:
84 if newExplanation:
85 #cmd.replace('--explanation="%s"'%oldexplanation,'--explanation="%s"'%explanation)
86 newcmd=cmd.split(' --')
87 for n,x in enumerate(newcmd):
88 if 'explanation=' in x:
89 newcmd[n]='explanation="%s"'%explanation
90 break
91
92 cmd=' --'.join(newcmd)
93 print "-->",cmd
94
95 if not self.istest:
96 result = self.client.execute(cmd)
97 print result
98 else:
99 print "dummy!"
100
101 return doUpload
102
103 def getXSRef(self,HORef,explanation=None):
104 # Get reference cross section
105 foundRefXS=False
106 HOXS="UNKNOWN"
107 HOSrc="UNKNOWN"
108
109 # Read from Cross section Reference file
110 for highXsecLine in self.xsRefLines:
111 refexplanation="Unknown"
112 highXsecInfo=highXsecLine.split(',')
113 if len(highXsecInfo)<3:
114 print self.colors.FAIL+"ERROR: Higher-order cross section line only has %i fields (expected 3)"%len(highXsecInfo)+self.colors.ENDC
115 continue
116
117 highXsecRef=highXsecInfo[0].strip()
118 highXsecVal=highXsecInfo[1].strip()
119 if explanation:
120 highXsecSrc=explanation
121 else:
122 highXsecSrc=highXsecInfo[2].strip()
123
124 if str(highXsecRef) == str(HORef):
125 if highXsecVal=="Undefined" or highXsecVal=="":
126 print self.colors.FAIL+"ERROR: Higher order cross section value undefined - skipping"+self.colors.ENDC
127 highXsecVal="Unknown"
128 #continue
129 elif highXsecRef=="Undefined" or highXsecRef=="":
130 print self.colors.FAIL+"ERROR: Higher order cross section reference undefined - skipping"+self.colors.ENDC
131 highXsecRef="Unknown"
132 #continue
133 elif highXsecSrc=="Undefined" or highXsecSrc=="":
134 print self.colors.WARNING+"WARNING: Higher order cross section source undefined - skipping"+self.colors.ENDC
135
136 refexplanation=highXsecVal+","+highXsecSrc
137 HOXS=highXsecVal
138 HOSrc=highXsecSrc
139 foundRefXS=True
140 break
141
142 if foundRefXS:
143 #check if recalculation of HOXS is required...
144 print self.colors.FAIL+"New k-factor for existing HORef - do I need to recalculate HOXS and and propage to all samples with HORef?!"+self.colors.ENDC
146 else:
147 print self.colors.FAIL+"ERROR: Reference cross section %s not matched to CrossSectionReference file."%(HORef)+self.colors.ENDC
148 explanation="Unknown"
149 #HORef,HOXS,
150
151 # Enter new values for reference, cross section and source
152 HORef = "UNKNOWN"
153 newanswer='X'
154 tmpans=False
155
156 while not tmpans:
157 HORef = raw_input('Please enter new HORef for %s (or type "skip"): '%(HORef))
158 if HORef=='skip':
159 HORef="UNKNOWN"
160 newanswer='skip'
161 tmpans=True
162 continue
163 newanswer='X'
164 while newanswer not in ['y','n','skip']: newanswer = raw_input('Continue upload with new HORef = %s? (y/n/skip): '%HOXS)
165 if newanswer in ['y','skip']:
166 tmpans=True
167
168 HOXS = "UNKNOWN"
169 newanswer='X'
170 tmpans=False
171 while not tmpans and newanswer!='skip':
172 HOXS = raw_input('Please enter new HOXS for %s (or type "skip"): '%(HORef))
173 if HOXS=='skip':
174 HOXS="UNKNOWN"
175 newanswer='skip'
176 tmpans=True
177 continue
178 newanswer='X'
179 while newanswer not in ['y','n','skip']: newanswer = raw_input('Continue upload with new HOXS = %s? (y/n/skip): '%HOXS)
180 if newanswer in ['y','skip']:
181 tmpans=True
182
183 HOSrc = "UNKNOWN"
184 tmpans=False
185 while not tmpans and newanswer!='skip':
186 HOSrc = raw_input('Please enter new HOSrc for %s (or type "skip"): '%(HORef))
187 if HOSrc=='skip':
188 HOSrc="UNKNOWN"
189 newanswer='skip'
190 tmpans=True
191 continue
192
193 newanswer='X'
194 while newanswer not in ['y','n','skip']: newanswer = raw_input('Continue upload with new HOSrc = %s? (y/n/skip): '%HOSrc)
195 if newanswer in ['y','skip']:
196 tmpans=True
197
198 if newanswer=='skip':
199 print self.colors.OKBLUE+"INFO: Skipping new HOXS/HOSrc value for %s"%(HORef)+self.colors.ENDC
200 highXsecVal="UNKNOWN"
201 else:
202 print self.colors.OKGREEN+"INFO: Adding new HOXS,HOSrc values %s,%s for %s"%(HOXS,HOSrc,HORef)+self.colors.ENDC
203 self.addNewXSRefEntry(HORef,HOXS,HOSrc)
204
205
206 return HOXS,HORef,HOSrc
207
208
209
210 def getScope(self,ds):
211 # get Rucio scope from DS name
212 return ds.split('.')[0].split('_')[0]
213
214
215
216 def updateValue(self,ds,param,value,explanation,highXsecRef=None):
217 # update a DB value for a given ds
218 if param == "crossSection":
219 self.updateXS(ds,self.getScope(ds),value,explanation)
220 elif param == "genFiltEff":
221 self.updateFiltEff(ds,self.getScope(ds),value,explanation)
222 elif param == "kFactor":
223 #@todo work out how to upload new values to CrossSectionReference file if needed
224 self.updateKFactor(ds,self.getScope(ds),value,explanation,highXsecRef)
225 elif param == "processGroup":
226 self.updateProcGroup(ds,self.getScope(ds),value,explanation)
227 elif param == "physicsStatus":
228 self.updatePhysicsStatus(ds,self.getScope(ds),value,explanation)
229 elif param == "crossSectionRef":
230 self.updateXSRef(ds,self.getScope(ds),value,explanation)
231 else:
232 print self.colors.FAIL+"ERROR: %s upload not currently supported"%(param)+self.colors.ENDC
233
234
235 def removeParamEntry(self,ds,scope,param,explanation):
236 # remove value (set end date) for a given ds and parameter
237 cmd='RemovePhysicsParameterVals --paramName="%s" --logicalDatasetName="%s" --scope="%s" --physicsGroup="PMG" --explanation="%s"'%(param,ds,scope,explanation)
238 self.cmdExec(cmd,explanation)
239
240
241 def updateProcGroup(self,ds,scope,processGroup,explanation):
242 # update processGroup
243 cmd='AddPhysicsParameterVals --paramName="%s" --paramValue="%s" --logicalDatasetName="%s" --physicsGroup="PMG" --scope="%s" --explanation="%s"'%("processGroup",processGroup,ds,scope,explanation)
244 self.cmdExec(cmd,explanation)
245
246
247 def updateXS(self,ds,scope,xsVal,explanation):
248 # update cross section
249 cmd='AddPhysicsParameterVals --paramName="%s" --paramValue="%s" --logicalDatasetName="%s" --physicsGroup="PMG" --scope="%s" --explanation="%s"'%("crossSection",xsVal,ds,scope,explanation)
250 self.cmdExec(cmd,explanation)
251
252
253 def updateFiltEff(self,ds,scope,effVal,explanation):
254 # update filter efficiency
255 cmd='AddPhysicsParameterVals --paramName="%s" --paramValue="%s" --logicalDatasetName="%s" --physicsGroup="PMG" --scope="%s" --explanation="%s"'%("genFiltEff",effVal,ds,scope,explanation)
256 self.cmdExec(cmd,explanation)
257
258 def updateXSRef(self,ds,scope,XSRefVal,explanation):
259 # update cross section reference
260 highXsecVal,highXsecRef,highXsecSrc=self.getXSRef(XSRefVal)
261 refexplanation=highXsecVal+","+highXsecSrc
262 cmd='AddPhysicsParameterVals --paramName="%s" --paramValue="%s" --logicalDatasetName="%s" --physicsGroup="PMG" --scope="%s" --explanation="%s"'%("crossSectionRef",XSRefVal,ds,scope,refexplanation)
263 self.cmdExec(cmd,explanation)
264 if float(self.currentVals[ds]["kFactor"])==1.0:
265 print "INFO: New XSRef - need to (re)calculate kFactor"
266 self.updateKFactor(ds,scope,self.calcKFactor(highXsecRef,highXsecVal,self.newVals[ds]['crossSection']),explanation,highXsecRef,False)
267
268 def updateKFactor(self,ds,scope,kFactorVal,explanation,highXsecRef,updateRef=True,refexplanation=""):
269 # update k-factor
270 # k-factor explanation should be crossSectionRef value and crossSectionRef explanation should be "<HOXS>,<HOXS source>"
271
272 highXsecVal,highXsecRef,highXsecSrc=self.getXSRef(highXsecRef,refexplanation)
273
274 if highXsecRef=="Unknown":
275 # just upload k-factor with standard explanation because cross section reference can't be found
276 cmd='AddPhysicsParameterVals --paramName="%s" --paramValue="%s" --logicalDatasetName="%s" --physicsGroup="PMG" --scope="%s" --explanation="%s"'%("kFactor",kFactorVal,ds,scope,explanation)
277 self.cmdExec(cmd,explanation)
278 else:
279 # upload proper explanation and corresponding crossSectionRef
280 cmd='AddPhysicsParameterVals --paramName="%s" --paramValue="%s" --logicalDatasetName="%s" --physicsGroup="PMG" --scope="%s" --explanation="%s"'%("kFactor",kFactorVal,ds,scope,highXsecRef)
281 doExecKFact=self.cmdExec(cmd,highXsecRef)
282 if doExecKFact:
283 if updateRef and highXsecRef!=self.currentVals[ds]["crossSectionRef"]:
284 newexplanation=highXsecVal+","+highXsecSrc
285 if newexplanation!=refexplanation:
286 cmd_Ref='AddPhysicsParameterVals --paramName="crossSectionRef" --paramValue="%s" --logicalDatasetName="%s" --physicsGroup="PMG" --scope="%s" --explanation="%s"'%(highXsecRef,ds,scope,newexplanation)
287 self.cmdExec(cmd_Ref,refexplanation)
288 else:
289 print "INFO: crossSectionRef explanation the same as exiting - not uploading"
290 else:
291 print "INFO: Not uploading crossSectionRef it is identical to current value (%s)"%(highXsecRef)
292
293 def updatePhysicsStatus(self,ds,scope,val,explanation):
294 # update physics status
295 cmd='AddPhysicsParameterVals --paramName="%s" --paramValue="%s" --logicalDatasetName="%s" --physicsGroup="PMG" --scope="%s" --explanation="%s"'%("physicsStatus",val,ds,scope,explanation)
296 self.cmdExec(cmd,explanation)
297
298
299 def calcKFactor(self,highXsecRef,highXsecVal,Xsec,BR=1.0):
300 # calculate k-factor from HOXS value
301 print "INFO: - XsecRef = %s, HOxs = %s"%(highXsecRef,highXsecVal)
302 kFactor=(float(highXsecVal)/1000.)/(float(Xsec)/float(BR))
303 print "kFactor = %f - HOxs= %f / ( xs=%f / BR=%f)"%(kFactor,float(highXsecVal)/1000.,float(Xsec),float(BR))
304 return kFactor
305
307 # calculate k-factor for several samples inside a crossSectionGroup
308 print "Need implementation"
309
311 # May want to check for updates in AMI automatic cross section calculatiob because then k-factors would need recalculating
312 print "Need implementation"
313
314 def getDSListFromFile(self,filename):
315 # Get list of datasets from input file
316 outlist=[]
317 dslist=[]
318 myfile=open(filename)
319 inlist=myfile.readlines()
320 for line in inlist[1:]:
321 if not len(line.strip()) or line.strip()[0]=='#':
322 continue
323 elements=line.split(self.delim)
324 if elements[0] not in outlist:
325 outlist.append(elements[0])
326
327 return outlist
328
329
330
331 def getFieldsInFile(self,filename):
332 # work out what getMetadata fields are present in input file
333 #getMetadata.py --timestamp="2017-11-24 21:59:10" --physicsGroups="PMG,MCGN" --fields="ldn,dataset_number,crossSection,kFactor,genFiltEff,processGroup,crossSectionRef" --inDS="mc15_13TeV.410111.MadGraphPythia8EvtGen_A14NNPDF23LO_ttee_Np0.evgen.EVNT.e4265"
334 myfile=open(filename)
335 inlist=myfile.readlines()
336 foundCommand=False
337 fielddict={}
338 for line in inlist[1:]:
339 if '#getMetadata.py' in line:
340 foundCommand=True
341 fields=[arg for arg in line.split('--') if 'fields=' in arg][0].replace('fields=','')
342 fielddict={}
343 fielddict={f.strip():n for n,f in enumerate(fields.replace('"','').split(','))}
344 #need to make sure cross section is first in case we recalculate k-factor from it later
345 d = OrderedDict()
346 if 'crossSection' in fielddict:
347 d.update({'crossSection':fielddict['crossSection']})
348 del fielddict['crossSection']
349 d.update(fielddict)
350 return d
351 for line in inlist[0]:
352 foundCommand=True
353 fielddict={}
354 fielddict={f.split('/')[0].strip():n for n,f in enumerate(line.replace('"','').split(':'))}
355 d = OrderedDict()
356 if 'crossSection' in fielddict:
357 d.update({'crossSection':fielddict['crossSection']})
358 del fielddict['crossSection']
359 d.update(fielddict)
360 return d
361
362
363 self.colors.FAIL+"ERROR: Failed to find getMetadata.py command in file"+self.colors.ENDC
364 return
365
366
367 def getDetailsFromFile(self,filename):
368 # make dictionary for all the fields in every row of the input file
369 filedict={}
370 fielddict=self.getFieldsInFile(filename)
371
372 myfile=open(filename)
373 inlist=myfile.readlines()
374
375 for line in inlist[1:]:
376 if not len(line.strip()) or line.strip()[0]=='#' or 'ldn' in line:
377 continue
378 elements=line.strip().split(self.delim)
379 if len(elements)<len(fielddict):
380 print "ERROR: Number of elements found in line (%i) less than those in query fields (%i)"%(len(elements),len(fielddict))
381 print "ERROR: -> Elements:",elements
382 break
383 filedict[elements[fielddict["ldn"]]]={f:elements[fielddict[f]].strip() for f in fielddict if f != "ldn"}
384
385 return filedict
386
387
388 def getCurrentVals(self,dslist,fields):
389 # get current values in AMI DB by running getMetadata.py query
390 for f in glob.glob("/tmp/"+os.environ["USER"]+"/my.datasets*.txt"): os.remove(f)
391 nline=1
392 counter=1
393 nDS=len(dslist)
394 for ds in dslist:
395 if not os.access("/tmp/"+os.environ["USER"]+"/my.datasets"+str(counter)+".txt",os.R_OK):
396 dsfile=open("/tmp/"+os.environ["USER"]+"/my.datasets"+str(counter)+".txt",'w')
397 else:
398 dsfile=open("/tmp/"+os.environ["USER"]+"/my.datasets"+str(counter)+".txt",'a')
399 dsfile.write(ds+"\n")
400 dsfile.close()
401 nline=nline+1
402 if nline > 500:
403 nline=1
404 counter=counter+1
405
406
407 print "INFO: Found %i datasets, split into %i getMetadata queries"%(nDS,counter)
408
409 for f in glob.glob("/tmp/"+os.environ["USER"]+"/metadata*.txt"): os.remove(f)
410 metaFile=open("/tmp/"+os.environ["USER"]+"/metadata.txt",'w')
411
412
413 for i in range(1,counter+1):
414 print "getMetadata.py --delim="+self.delim+" --inDsTxt=/tmp/"+os.environ["USER"]+"/my.datasets"+str(i)+".txt --outFile=/tmp/"+os.environ["USER"]+"/metadata"+str(i)+".txt --fields"," ".join([f for f,n in fields.iteritems()])
415 getMeta = subprocess.Popen(["getMetadata.py","--delim="+self.delim+"","--inDsTxt=/tmp/"+os.environ["USER"]+"/my.datasets"+str(i)+".txt","--outFile=/tmp/"+os.environ["USER"]+"/metadata"+str(i)+".txt","--fields"]+[f for f,n in fields.iteritems()])
416 #,"ldn","dataset_number","crossSection","kFactor","genFiltEff","processGroup","crossSectionRef"])
417 getMeta.wait()
418 tmpMetaFile=open("/tmp/"+os.environ["USER"]+"/metadata"+str(i)+".txt",'r')
419 metaFile.write(tmpMetaFile.read())
420 tmpMetaFile.close()
421
422
423 metaFile.close()
424
425 metaFile=open("/tmp/"+os.environ["USER"]+"/metadata.txt",'r')
426 metaFileList=metaFile.readlines()
427 nDSFound=len([ ln for ln in metaFileList[1:] if ln[0]!='#' and len(ln.strip())])
428 if nDS == nDSFound:
429 print "INFO: %i/%i datasets found in AMI"%(nDSFound,nDS)
430 else:
431 print "WARNING: %i/%i datasets found in AMI"%(nDSFound,nDS)
432
433 return "/tmp/"+os.environ["USER"]+"/metadata.txt"
434
435
436 def addNewXSRefEntry(self,HORef,HOXS,HOSrc):
437 # Add new entry to CrossSectionReference file
438 #XsecTTbarNominal,831.76,https://twiki.cern.ch/twiki/bin/view/LHCPhysics/TtbarNNLO#Top_quark_pair_cross_sections_at
439 #@todo
440 reffile=open(self.xsRefFile,'a')
441 reffile.write("\n%s,%s,%s"%(HORef,HOXS,HOSrc))
442 reffile.close()
443
445 # Search AMI DB by crossSectionRef to return all relevant ds
446 #@todo
447 print "findAllSamplesForXSRef not implemented"
448
449
450 class bcolors :
451 # colors for print statements
452 def __init__(self,nocolour=False):
453 self.nocolour=nocolour
454
455 if not nocolour:
456 self.HEADER = '\033[95m'
457 self.OKBLUE = '\033[94m'
458 self.OKGREEN = '\033[92m'
459 self.WARNING = '\033[93m'
460 self.FAIL = '\033[91m'
461 self.ENDC = '\033[0m'
462 else:
463 self.HEADER = ''
464 self.OKBLUE = ''
465 self.OKGREEN = ''
466 self.WARNING = ''
467 self.FAIL = ''
468 self.ENDC = ''
469
470 def disable(self):
471 self.HEADER = ''
472 self.OKBLUE = ''
473 self.OKGREEN = ''
474 self.WARNING = ''
475 self.FAIL = ''
476 self.ENDC = ''
477
478
__init__(self, nocolour=False)
updateFiltEff(self, ds, scope, effVal, explanation)
getDSListFromFile(self, filename)
__init__(self, istest=True, verbose=False, alwaysyes=False, xsRefFile=None, delim=";")
updateXS(self, ds, scope, xsVal, explanation)
calcKFactor(self, highXsecRef, highXsecVal, Xsec, BR=1.0)
getFieldsInFile(self, filename)
updatePhysicsStatus(self, ds, scope, val, explanation)
getDetailsFromFile(self, filename)
updateProcGroup(self, ds, scope, processGroup, explanation)
checkUpload(self, origexplanation)
updateKFactor(self, ds, scope, kFactorVal, explanation, highXsecRef, updateRef=True, refexplanation="")
getCurrentVals(self, dslist, fields)
addNewXSRefEntry(self, HORef, HOXS, HOSrc)
getXSRef(self, HORef, explanation=None)
updateXSRef(self, ds, scope, XSRefVal, explanation)
getScope(self, ds)
updateValue(self, ds, param, value, explanation, highXsecRef=None)
cmdExec(self, cmd, explanation)
removeParamEntry(self, ds, scope, param, explanation)
findAllSamplesForXSRef(self)
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:310
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177