CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_14/src/Utilities/RelMon/python/dirstructure.py

Go to the documentation of this file.
00001 ################################################################################
00002 # RelMon: a tool for automatic Release Comparison                              
00003 # https://twiki.cern.ch/twiki/bin/view/CMSPublic/RelMon
00004 #
00005 # $Author: anorkus $
00006 # $Date: 2012/11/21 15:22:14 $
00007 # $Revision: 1.3 $
00008 #
00009 #                                                                              
00010 # Danilo Piparo CERN - danilo.piparo@cern.ch                                   
00011 #                                                                              
00012 ################################################################################
00013 
00014 from array import array
00015 from copy import deepcopy
00016 from os import chdir,getcwd,listdir,makedirs,rmdir
00017 from os.path import exists,join
00018 
00019 import sys
00020 argv=sys.argv
00021 from ROOT import *
00022 sys.argv=argv
00023 
00024 from definitions import *
00025 from utils import setTDRStyle
00026 
00027 
00028 # Something nice and familiar
00029 setTDRStyle()
00030 
00031 # Do not display the canvases
00032 gROOT.SetBatch(kTRUE)
00033 
00034 
00035 #-------------------------------------------------------------------------------
00036 _log_level=5
00037 def logger(msg_level,message):
00038   if msg_level>=_log_level:
00039     print "[%s] %s" %(asctime(),message)
00040 
00041 #-------------------------------------------------------------------------------
00042 
00043 class Weighted(object):
00044   def __init__(self,name,weight=1):
00045     self.name=name
00046     self.weight=weight
00047 
00048 
00049 #-------------------------------------------------------------------------------
00050 class CompInfo(object):
00051   def __init__(self,sample="",release1="",release2="",run1="",run2="",tier1=0,tier2=0):
00052     self.sample=sample
00053     self.release1=release1
00054     self.release2=release2
00055     self.run1=run1
00056     self.run2=run2
00057     self.tier1=tier1
00058     self.tier2=tier2
00059     
00060 #-------------------------------------------------------------------------------
00061 class Directory(Weighted):
00062   def __init__(self,name,mother_dir="",meta=CompInfo(),draw_success=False,do_pngs=False):
00063     self.mother_dir=mother_dir
00064     self.meta=meta
00065     self.subdirs=[]
00066     self.comparisons=[]   
00067     self.n_fails=0
00068     self.n_successes=0
00069     self.n_nulls=0
00070     self.n_skiped = 0
00071     self.n_comp_skiped = 0
00072     self.n_comp_fails=0
00073     self.n_comp_successes=0
00074     self.n_comp_nulls=0 
00075     self.weight=0
00076     self.stats_calculated=False
00077     Weighted.__init__(self,name)
00078     self.draw_success=draw_success
00079     self.do_pngs=do_pngs
00080     self.rank_histo=TH1I("rh%s"%name,"",50,-0.01,1.001)
00081     self.rank_histo.SetDirectory(0)
00082 
00083   def is_empty(self):
00084     if len(self.subdirs)==0 and len(self.comparisons)==0:
00085       return True
00086     return False
00087   
00088   def calcStats(self,make_pie=True):
00089     '''Walk all subdirs and calculate weight,fails and successes.
00090     Moreove propagate the sample and releases names.
00091     '''
00092     if self.stats_calculated:
00093       return 0
00094     
00095     self.n_fails=0
00096     self.n_successes=0
00097     self.n_nulls=0
00098     self.n_comp_fails=0
00099     self.n_comp_successes=0
00100     self.n_comp_nulls=0  
00101     self.weight=0
00102     
00103     self.n_skiped = 0
00104     self.n_comp_skiped = 0
00105     
00106     # clean from empty dirs    
00107     self.subdirs = filter(lambda subdir: not subdir.is_empty(),self.subdirs)    
00108     
00109     for comp in self.comparisons:
00110       if comp.status == SKIPED: #in case its in black list & skiped 
00111           self.n_skiped += 1
00112           self.n_comp_skiped += 1
00113           self.weight+=1
00114       else: #else original code -> to check for Fails and Successes
00115           self.rank_histo.Fill(comp.rank)
00116           self.weight+=1
00117           if comp.status == FAIL:
00118               self.n_fails+=1
00119               self.n_comp_fails+=1
00120           elif comp.status == SUCCESS:
00121               self.n_successes+=1
00122               self.n_comp_successes+=1
00123           else:
00124               self.n_nulls+=1
00125               self.n_comp_nulls+=1
00126 
00127     for subdir in self.subdirs:
00128       subdir.mother_dir=join(self.mother_dir,self.name)
00129       subdir.calcStats(make_pie)
00130       subdir.meta=self.meta 
00131       self.weight+=subdir.weight
00132       self.n_fails+=subdir.n_fails
00133       self.n_successes+=subdir.n_successes
00134       self.n_nulls+=subdir.n_nulls
00135       
00136       self.n_skiped+=subdir.n_skiped
00137       
00138       self.rank_histo.Add(subdir.rank_histo)
00139 
00140     self.stats_calculated=True 
00141     #if make_pie:
00142       #self.__create_pie_image()
00143 
00144   def get_subdirs_dict(self):
00145     subdirdict={}
00146     for subdir in self.subdirs:
00147       subdirdict[subdir.name]=subdir
00148     return subdirdict
00149 
00150   def get_subdirs_names(self):
00151     subdirnames=[]
00152     for subdir in self.subdirs:
00153       subdirnames.append(subdir.name)
00154     return subdirnames
00155 
00156   def get_summary_chart_ajax(self,w=400,h=300):
00157     """Emit the ajax to build a pie chart using google apis...
00158     """
00159     url = "https://chart.googleapis.com/chart?"
00160     url+= "cht=p3" # Select the 3d chart
00161     #url+= "&chl=Success|Null|Fail" # give labels
00162     url+= "&chco=00FF00|FFFF00|FF0000|7A7A7A" # give colours to labels
00163     url+= "&chs=%sx%s" %(w,h)
00164     #url+= "&chtt=%s" %self.name
00165     url+= "&chd=t:%.2f,%.2f,%.2f,%.2f"%(self.get_success_rate(),self.get_null_rate(),self.get_fail_rate(),self.get_skiped_rate())
00166     
00167     return url
00168 
00169   def print_report(self,indent="",verbose=False):
00170     if len(indent)==0:
00171       self.calcStats(make_pie=False)
00172     # print small failure report
00173     if verbose:
00174       fail_comps=filter(lambda comp:comp.status==FAIL,self.comparisons)
00175       fail_comps=sorted(fail_comps,key=lambda comp:comp.name )    
00176       if len(fail_comps)>0:
00177         print indent+"* %s/%s:" %(self.mother_dir,self.name)
00178         for comp in fail_comps:
00179           print indent+" - %s: %s Test Failed (pval = %s) " %(comp.name,comp.test_name,comp.rank)
00180       for subdir in self.subdirs:
00181         subdir.print_report(indent+"  ",verbose)
00182     
00183     if len(indent)==0:
00184       print "\n%s - summary of %s tests:" %(self.name,self.weight)
00185       print " o Failiures: %.2f%% (%s/%s)" %(self.get_fail_rate(),self.n_fails,self.weight)
00186       print " o Nulls: %.2f%% (%s/%s) " %(self.get_null_rate(),self.n_nulls,self.weight)
00187       print " o Successes: %.2f%% (%s/%s) " %(self.get_success_rate(),self.n_successes,self.weight)
00188       print " o Skipped: %.2f%% (%s/%s) " %(self.get_skiped_rate(),self.n_skiped,self.weight)
00189 
00190   def get_skiped_rate(self):
00191     if self.weight == 0: return 0
00192     return 100.*self.n_skiped/self.weight
00193   def get_fail_rate(self):
00194     if self.weight == 0:return 0
00195     return 100.*self.n_fails/self.weight
00196     
00197   def get_success_rate(self):
00198     if self.weight == 0:return 1    
00199     return 100.*self.n_successes/self.weight
00200     
00201   def get_null_rate(self):
00202     if self.weight == 0:return 0    
00203     return 100.*self.n_nulls/self.weight
00204 
00205   def __get_full_path(self):
00206     #print "Mother is %s" %self.mother_dir
00207     if len(self.mother_dir)==0:
00208       return self.name
00209     return join(self.mother_dir,self.name)
00210     
00211   def __create_on_disk(self):
00212     if not exists(self.mother_dir) and len(self.mother_dir)!=0:
00213       makedirs(self.mother_dir)
00214     full_path=self.__get_full_path()    
00215     if not exists(full_path) and len(full_path)>0:
00216       makedirs(full_path)
00217 
00218   def get_summary_chart_name(self):
00219     return join(self.__get_full_path(),"summary_chart.png") 
00220 
00221   def __create_pie_image(self):
00222     self.__create_on_disk()
00223     vals=[]
00224     colors=[]
00225     for n,col in zip((self.n_fails,self.n_nulls,self.n_successes,self.n_skiped),(kRed,kYellow,kGreen,kBlue)):
00226       if n!=0:
00227         vals.append(n)
00228         colors.append(col)
00229     valsa=array('f',vals)
00230     colorsa=array('i',colors)
00231     can = TCanvas("cpie","TPie test",100,100);
00232     try:
00233       pie = TPie("ThePie",self.name,len(vals),valsa,colorsa);
00234       label_n=0
00235       if self.n_fails!=0:
00236         pie.SetEntryLabel(label_n, "Fail: %.1f(%i)" %(self.get_fail_rate(),self.n_fails) );
00237         label_n+=1
00238       if self.n_nulls!=0:
00239         pie.SetEntryLabel(label_n, "Null: %.1f(%i)" %(self.get_null_rate(),self.n_nulls) );      
00240         label_n+=1
00241       if self.n_successes!=0:
00242         pie.SetEntryLabel(label_n, "Success: %.1f(%i)" %(self.get_success_rate(),self.n_successes) );
00243       if self.n_skiped!=0:
00244         pie.SetEntryLabel(label_n, "Skipped: %.1f(%i)" %(self.get_skiped_rate(),self.n_skiped));
00245       pie.SetY(.52);
00246       pie.SetAngularOffset(0.);    
00247       pie.SetLabelsOffset(-.3);
00248       #pie.SetLabelFormat("#splitline{%val (%perc)}{%txt}");
00249       pie.Draw("3d  nol");
00250       can.Print(self.get_summary_chart_name());    
00251     except:
00252       print "self.name = %s" %self.name
00253       print "len(vals) = %s (vals=%s)" %(len(vals),vals)
00254       print "valsa = %s" %valsa
00255       print "colorsa = %s" %colorsa
00256 
00257   def prune(self,expandable_dir):
00258     """Eliminate from the tree the directory the expandable ones.
00259     """
00260     #print "pruning %s" %self.name
00261     exp_index=-1
00262     counter=0
00263     for subdir in self.subdirs:      
00264       # Eliminate any trace of the expandable path in the mother directories
00265       # for depths higher than 1
00266       subdir.mother_dir=subdir.mother_dir.replace("/"+expandable_dir,"")
00267       if subdir.name==expandable_dir:        
00268         exp_index=counter
00269       counter+=1
00270     
00271     # Did we find an expandable?
00272     if exp_index>=0:
00273       exp_dir=self.subdirs[exp_index]
00274       for subsubdir in exp_dir.subdirs:
00275         #print "*******",subsubdir.mother_dir,
00276         subsubdir.mother_dir=subsubdir.mother_dir.replace("/"+expandable_dir,"")
00277         while "//" in subsubdir.mother_dir:
00278           print subsubdir.mother_dir
00279           subsubdir.mother_dir=subsubdir.mother_dir.replace("//","/") 
00280         #print "*******",subsubdir.mother_dir
00281         self.subdirs.append(subsubdir)
00282           
00283         for comp in exp_dir.comparisons:
00284           comp.mother_dir=comp.mother_dir.replace("/"+expandable_dir,"")        
00285           while "//" in comp.mother_dir:
00286               comp.mother_dir
00287               comp.mother_dir=comp.mother_dir.replace("/")
00288           if not comp in self.comparisons:  #in case not to  append same comparisons few times
00289               self.comparisons.append(comp)  # add a comparison
00290               self.n_comp_fails = exp_dir.n_comp_fails  #copy to-be removed directory
00291               self.n_comp_nulls = exp_dir.n_comp_nulls  # numbers to parent directory
00292               self.n_comp_successes = exp_dir.n_comp_successes
00293               self.n_comp_skiped = exp_dir.n_comp_skiped
00294         
00295       del self.subdirs[exp_index]
00296       self.prune(expandable_dir)
00297     
00298     for subdir in self.subdirs:
00299       subdir.prune(expandable_dir)
00300 
00301   def __repr__(self):
00302     if self.is_empty():
00303       return "%s seems to be empty. Please check!" %self.name
00304     content="%s , Rates: Success %.2f%%(%s) - Fail %.2f%%(%s) - Null %.2f%%(%s)\n" %(self.name,self.get_success_rate(),self.n_successes,self.get_fail_rate(),self.n_fails,self.get_null_rate(),self.n_nulls)   
00305     for subdir in self.subdirs:
00306       content+=" %s\n" % subdir
00307     for comp in self.comparisons:
00308       content+=" %s\n" % comp
00309     return content
00310     
00311 #-------------------------------------------------------------------------------
00312 from multiprocessing import Process
00313 def print_multi_threaded(canvas,img_name):
00314     canvas.Print(img_name)
00315 
00316 tcanvas_print_processes=[]
00317 #-------------------------------------------------------------------------------
00318 
00319 class Comparison(Weighted):
00320   canvas_xsize=500
00321   canvas_ysize=400
00322   def __init__(self,name,mother_dir,h1,h2,stat_test,draw_success=False,do_pngs=False, skip=False):
00323     self.name=name
00324     self.png_name="placeholder.png"
00325     self.mother_dir=mother_dir
00326     self.img_name=""
00327     #self.draw_success=draw_success
00328     Weighted.__init__(self,name)
00329 
00330     stat_test.set_operands(h1,h2)
00331     if skip:
00332         self.status = SKIPED
00333         self.test_name=stat_test.name
00334         self.test_name=stat_test.name
00335         self.test_thr=stat_test.threshold
00336         self.rank = 0
00337     else:
00338         self.status=stat_test.get_status()
00339         self.rank=stat_test.get_rank()
00340         self.test_name=stat_test.name
00341         self.test_thr=stat_test.threshold
00342         self.do_pngs=do_pngs
00343         self.draw_success=draw_success or not do_pngs
00344         if ((self.status==FAIL or self.status==NULL or self.status == SKIPED or self.draw_success) and self.do_pngs):
00345             self.__make_image(h1,h2)      
00346         #self.__make_image(h1,h2)
00347 
00348   def __make_img_dir(self):    
00349     if not exists(self.mother_dir):
00350       makedirs(self.mother_dir)
00351     
00352   def __get_img_name(self):
00353     #self.__make_img_dir()    
00354     #print "MOTHER: ",self.mother_dir
00355     self.img_name="%s/%s.png"%(self.mother_dir,self.name)
00356     self.img_name=self.img_name.replace("Run summary","")
00357     self.img_name=self.img_name.replace("/","_")
00358     self.img_name=self.img_name.strip("_")
00359     #print "IMAGE NAME: %s " %self.img_name
00360     return self.img_name
00361 
00362   def tcanvas_slow(self,canvas):
00363     #print "About to print %s" %self.img_name
00364     #print_multi_threaded(canvas,self.img_name)
00365     #print "-->Printed"
00366 
00367     p = Process(target=print_multi_threaded, args=(canvas,self.img_name))
00368     p.start()
00369     tcanvas_print_processes.append(p)
00370     n_proc=len(tcanvas_print_processes)
00371     if n_proc>3:
00372       p_to_remove=[]
00373       for iprocess in xrange(0,n_proc):
00374         p=tcanvas_print_processes[iprocess]
00375         p.join()
00376         p_to_remove.append(iprocess)
00377 
00378       adjustment=0
00379       for iprocess in p_to_remove:
00380         tcanvas_print_processes.pop(iprocess-adjustment)
00381         adjustment+=1
00382 
00383   def __make_image(self,obj1,obj2):
00384     self.img_name=self.__get_img_name()
00385     if self.rank==-1:
00386       return 0
00387    
00388     canvas=TCanvas(self.name,self.name,Comparison.canvas_xsize,Comparison.canvas_ysize)
00389     objs=(obj1,obj2)
00390 
00391     # Add some specifics for the graphs
00392     obj1.SetTitle(self.name)
00393     
00394     if obj1.GetNbinsY()!=0 and not "2" in obj1.ClassName() :
00395       obj1 .SetLineWidth(2)
00396       obj2 .SetLineWidth(2)
00397 
00398       obj1.SetMarkerStyle(8)
00399       obj1.SetMarkerSize(.8)
00400 
00401       obj2.SetMarkerStyle(8)
00402       obj2.SetMarkerSize(.8)
00403 
00404       obj1.SetMarkerColor(kBlue)
00405       obj1.SetLineColor(kBlue)
00406 
00407       obj2.SetMarkerColor(kRed)
00408       obj2.SetLineColor(kRed)
00409 
00410       obj1.Draw("EP")
00411       #Statsbox      
00412       obj2.Draw("HistSames")
00413       #gPad.Update()
00414       #if 'stats' in map(lambda o: o.GetName(),list(gPad.GetListOfPrimitives())):
00415         #st = gPad.GetPrimitive("stats")      
00416         #st.SetY1NDC(0.575)
00417         #st.SetY2NDC(0.735)
00418         #st.SetLineColor(kRed)
00419         #st.SetTextColor(kRed)
00420         #print st      
00421     else:
00422       obj1.Draw("Colz")
00423       gPad.Update()
00424       #if 'stats' in map(lambda o: o.GetName(),list(gPad.GetListOfPrimitives())):
00425         #st = gPad.GetPrimitive("stats")      
00426         #st.SetY1NDC(0.575)
00427         #st.SetY2NDC(0.735)
00428         #st.SetLineColor(kRed)
00429         #st.SetTextColor(kRed)
00430         #print st
00431       obj2.Draw("ColSame")
00432 
00433     # Put together the TLatex for the stat test if possible    
00434     color=kGreen+2 # which is green, as everybody knows
00435     if self.status==FAIL:
00436       print "This comparison failed %f" %self.rank
00437       color=kRed
00438     elif self.status==NULL:
00439       color=kYellow
00440     elif self.status==SKIPED:
00441       color=kBlue #check if kBlue exists ;)
00442     
00443     lat_text="#scale[.7]{#color[%s]{%s: %2.2f}}" %(color,self.test_name,self.rank)
00444     lat=TLatex(.1,.91,lat_text)
00445     lat.SetNDC()
00446     lat.Draw()
00447   
00448     # Put also the stats together!
00449     n1=obj1.GetEntries()
00450     if n1> 100000:
00451       n1="%e"%n1
00452     else:
00453       n1="%s"%n1
00454     n2=obj2.GetEntries()
00455     if n2> 100000:
00456       n2="%e"%n2
00457     else:
00458       n2="%s"%n2
00459 
00460     lat_text1="#scale[.7]{#color[%s]{Entries: %s}}" %(obj1.GetLineColor(),n1)
00461     lat1=TLatex(.3,.91,lat_text1)
00462     lat1.SetNDC()
00463     lat1.Draw()
00464         
00465     
00466     lat_text2="#scale[.7]{#color[%s]{Entries: %s}}" %(obj2.GetLineColor(),n2)
00467     lat2=TLatex(.6,.91,lat_text2)
00468     lat2.SetNDC()
00469     lat2.Draw()
00470     
00471 
00472     self.tcanvas_slow(canvas)
00473 
00474   def __repr__(self):
00475     return "%s , (%s=%s). IMG=%s. status=%s" %(self.name,self.test_name,self.rank,self.img_name,self.status)
00476 
00477 #-------------------------------------------------------------------------------