From f9920bb59e50c803a6b1e5b1011e676e4710076c Mon Sep 17 00:00:00 2001
From: Tim Adye <Tim.Adye@cern.ch>
Date: Wed, 11 Apr 2018 18:04:26 +0100
Subject: [PATCH] Pull recent changes from SVN trunk (also tagged
 DCubeClient-00-00-52)

Updates from ChangeLog:

2017-07-10  Tim Adye  <T.J.Adye@rl.ac.uk>
	* Add support for TEfficiency plots (plotted as "graph" type)
	* fix graph statistics display and show y-mean/RMS instead of x-mean/RMS for 1D
	* don't crash on empty graph
	* graph plot style more like hist1d (red full circle, full-size plot, better ranges)
	M       python/DCubeConfig.py
	M       python/DCubeTester.py
	M       python/DCubePlotter.py

2017-03-26   Peter Sherwood  <peter@MacBook-Pro-7.fritz.box>
	* share/DCubeValid.xml: added new branch regex fo NN.N (eg 21.0)
	new cmtconfigs x86_64-slc6-gcc62-(opt, dev), new project Athena

2016-04-09  Atlas-Validation Runtimetester  <rtt@lxplus0003.cern.ch>
	* Tagging DCubeClient-00-00-51
	* Python 2.7.10 and ROOT 6.06/02 version update in dev nightly branch
	breaks the code to fetch histograms from a TFile instance, as the TFile.Get()
	function no longer accepts a unicode path, it needs ascii. Fixed by
	converting path to path.encode('ascii', 'ignore').

	M       python/DCubeTester.py
	M       python/DCubeApp.py


Former-commit-id: e45e8ee6212d7a75a6699633b2743ab4201d9b6b
---
 Tools/DCubeClient/python/DCubeApp.py       | 220 ++++++++--------
 Tools/DCubeClient/python/DCubeConfig.py    |   2 +-
 Tools/DCubeClient/python/DCubeOptParser.py |   6 +
 Tools/DCubeClient/python/DCubePlotter.py   | 186 ++++++-------
 Tools/DCubeClient/python/DCubeTester.py    | 290 +++++++++++++--------
 Tools/DCubeClient/share/DCubeValid.xml     |  19 +-
 6 files changed, 382 insertions(+), 341 deletions(-)

diff --git a/Tools/DCubeClient/python/DCubeApp.py b/Tools/DCubeClient/python/DCubeApp.py
index 9d510aae51a9..9cee9b55210f 100644
--- a/Tools/DCubeClient/python/DCubeApp.py
+++ b/Tools/DCubeClient/python/DCubeApp.py
@@ -14,7 +14,7 @@ from DCubeTester import DCubeTester
 from DCubePHPWriter import DCubePHPWriter
 import unittest
 ##
-# @class DCubeApp 
+# @class DCubeApp
 # @author Krzysztof Daniel Ciba (Krzysztof.Ciba@NOSPAMgmail.com)
 # @brief DCube client application
 class DCubeApp( DCubeObject ):
@@ -25,7 +25,7 @@ class DCubeApp( DCubeObject ):
     ## left over positional arguments as list
     args = None
 
-    ## path to monitored root file 
+    ## path to monitored root file
     monitoredURI = None
 
     ## path to reference root file
@@ -46,15 +46,15 @@ class DCubeApp( DCubeObject ):
 
         import ROOT
         global ROOT
-        
+
         monitoredURI = None
         if ( len(self.args) == 2 ):
-            self.monitoredURI = self.args[-1] 
-                
+            self.monitoredURI = self.args[-1]
+
         DCubeLogger( self.opts.log, logName="", toConsole=True )
 
         super( DCubeApp, self ).__init__( self )
-      
+
         ## DCubeVersion instance
         theVersion = DCubeVersion()
 
@@ -62,11 +62,11 @@ class DCubeApp( DCubeObject ):
         self.info( theVersion.python() )
         self.info( theVersion.root() )
 
-       
+
         ## DCubeValid instance
         self.valid = DCubeValid()
-        
-        for line in str(self.valid).split("\n"):    
+
+        for line in str(self.valid).split("\n"):
             self.info( line )
 
         self.__dumpOptions()
@@ -86,7 +86,7 @@ class DCubeApp( DCubeObject ):
                     self.info("*** SUCCESS ***")
                     sys.exit(0)
 
-            elif ( self.opts.config and self.monitoredURI ):            
+            elif ( self.opts.config and self.monitoredURI ):
 
                 self.info("RUN: test suite execution")
 
@@ -94,7 +94,7 @@ class DCubeApp( DCubeObject ):
                 runConfig =  dcubeConfig.getConfig( strict = False )
                 #if ( not runConfig ):
                 #    runConfig = dcubeConfig.getConfig( strict = False )
-                
+
 
                 if ( self.monitoredURI ):
                     if ( self.exists( self.monitoredURI ) ):
@@ -103,9 +103,9 @@ class DCubeApp( DCubeObject ):
                         self.error("monitored root file %s not found" % self.monitoredURI )
                 else:
                     raise DCubeException(  "wrong arguments, monitored file not specified!" )
-                
+
                 if ( runConfig ):
-                    
+
                     if ( self.runConfig ( runConfig ) ):
 
                         if ( self.tester ):
@@ -125,7 +125,7 @@ class DCubeApp( DCubeObject ):
             else:
                 self.error( "wrong set of CLI options, neither generation of config (-g) nor test suite excecution (-c CONFIG.XML MONITORED.root) specified" )
                 sys.exit(-1)
-                
+
         except DCubeException, value:
             self.epanic( value )
             self.epanic("*** FAILURE ***")
@@ -138,31 +138,31 @@ class DCubeApp( DCubeObject ):
         self.info("will run test suite using xml configuration..." )
 
         ## output XML DOM document
-        self.xmldoc = xml.dom.minidom.Document() 
+        self.xmldoc = xml.dom.minidom.Document()
         self.xmldoc.appendChild( xmlConfig )
 
         ## overwritting xml config to match run config
         self.debug("will overwrite xml config to match run config...")
-        xmlConfig.setAttribute( "branch", self.opts.branch ) 
+        xmlConfig.setAttribute( "branch", self.opts.branch )
         xmlConfig.setAttribute( "install", self.opts.install )
         xmlConfig.setAttribute( "cmtconfig", self.opts.cmtconfig )
         xmlConfig.setAttribute( "project", self.opts.project )
         xmlConfig.setAttribute( "jobId", self.opts.jobId )
         self.debug("done!")
 
-        config = "/".join( [ xmlConfig.getAttribute( "branch" ),
-                             xmlConfig.getAttribute( "install" ),
-                             xmlConfig.getAttribute( "cmtconfig" ),
-                             xmlConfig.getAttribute( "project" ),
-                             xmlConfig.getAttribute( "jobId" ) ] )
-        self.debug( "the run config is %s" % config )
+        config = "/".join([xmlConfig.getAttribute("branch"),
+                           xmlConfig.getAttribute("install"),
+                           xmlConfig.getAttribute("cmtconfig"),
+                           xmlConfig.getAttribute("project"),
+                           xmlConfig.getAttribute("jobId")])
+        self.debug("the run config is %s" % config)
 
         ## get pvalue limits
-        pvalues = xmlConfig.getElementsByTagName( "plimit" )
-        if ( len(pvalues) == 0 ):
+        pvalues = xmlConfig.getElementsByTagName("plimit")
+        if len(pvalues) == 0:
             self.warn("tag <plimit> not found, will use CLI pvalue limits FAIL=%f WARN=%f" % ( self.opts.pfail,
                                                                                                self.opts.pwarn ) )
-        elif ( len(pvalues) > 1 ):
+        elif len(pvalues) > 1:
             self.warn("too many <plimit> tags, will use CLI pvalue limits FAIL=%f WARN=%f" % ( self.opts.pfail,
                                                                                                self.opts.pwarn ) )
         else:
@@ -181,11 +181,11 @@ class DCubeApp( DCubeObject ):
 
         referenceNode = None
         self.referenceURI = None
-        ## reference root file    
+        ## reference root file
         if ( self.opts.reference != None ):
 
             self.referenceURI = os.path.abspath( self.opts.reference )
-            
+
             self.debug("will use reference root file from CLI = %s" % self.referenceURI )
             referenceNode = self.xmldoc.createElement( "reference" )
             referenceNode.setAttribute( "file", self.referenceURI )
@@ -204,7 +204,7 @@ class DCubeApp( DCubeObject ):
                 referenceNode = reference[0]
                 self.referenceURI = os.path.abspath( referenceNode.getAttribute("file") )
                 self.__update( "reference", self.referenceURI )
-                    
+
             self.debug("will use reference root file from XML = %s" % self.referenceURI )
 
         # monitored root file
@@ -215,7 +215,7 @@ class DCubeApp( DCubeObject ):
 
         # date node
         dateNode = self.xmldoc.createElement( "date" )
-        dateCDataNode = self.xmldoc.createTextNode( self.opts.isodate ) 
+        dateCDataNode = self.xmldoc.createTextNode( self.opts.isodate )
 
         dateNode.appendChild( dateCDataNode )
 
@@ -227,18 +227,18 @@ class DCubeApp( DCubeObject ):
             self.__update("output", self.opts.monitored + ".dcube.xml" )
 
         # get <tdirectory> tags and run tester
-        tdirs = xmlConfig.getElementsByTagName( "TDirectory" )    
+        tdirs = xmlConfig.getElementsByTagName( "TDirectory" )
         if ( len(tdirs) == 0 ): raise DCubeException("no <TDirectory> tags found!")
         else:
             ## DCubeTester instance
             self.tester = DCubeTester( self.xmldoc, self.parsed )
-            
+
             self.refTFile = None
-            if ( self.exists( self.referenceURI ) ):
+            if self.exists(self.referenceURI):
                 try:
-                    self.refTFile = ROOT.TFile.Open( self.referenceURI, "READ" )
+                    self.refTFile = ROOT.TFile.Open(self.referenceURI, "READ")
                 except Exception, value:
-                    self.epanic( "cannot get handle for referece root file, all tests will be skipped, reason: %s" % str(value) )
+                    self.epanic( "cannot get handle for reference root file, all tests will be skipped, reason: %s" % str(value) )
             else:
                 self.warn("reference root file not exists, all tests will be skipped!")
 
@@ -247,24 +247,24 @@ class DCubeApp( DCubeObject ):
                 try:
                     self.monTFile = ROOT.TFile.Open( self.monitoredURI , "READ")
                 except Exception, value:
-                    msg = "cannot get handle for monitored root file, reason: %s" % str(value) 
+                    msg = "cannot get handle for monitored root file, reason: %s" % str(value)
                     raise DCubeException( msg )
             else:
                 raise DCubeException( "monitored root file %s not exists!" % self.monitoredURI )
-                
+
             # run DCubeTester recursively
-            self.test( tdirs[0], tdirs[0].getAttribute("name") ) 
+            self.test( tdirs[0], tdirs[0].getAttribute("name") )
 
             if ( self.refTFile ): self.refTFile.Close()
             if ( self.monTFile ): self.monTFile.Close()
 
-            # print and append summary node 
+            # print and append summary node
             xmlConfig.appendChild (  self.tester.summary() )
-                    
+
         # save output XML to file
         return self.__save( )
-    
-    
+
+
     ## get CDATA section
     # @param self "Me, myself and Irene"
     # @param nodelist list of XML DOM Node objects
@@ -273,67 +273,67 @@ class DCubeApp( DCubeObject ):
         for node in nodelist:
             if node.nodeType == node.TEXT_NODE:
                 out = out + node.data
-        return out 
-        
+        return out
+
     ## main worker here
     # @param self "Me, myself and Irene"
     # @param node xml \<tdirectory\> node
     # @param path full path inside both root files
-    def test( self, node, path ):
-
-        self.debug("now testing objects in path = %s" % path )
-
-        status = [ ]
+    def test(self, node, path):
+        self.debug("now testing objects in path = %s" % path)
+        status = []
         for child in node.childNodes:
-
-            if ( child.nodeType == node.ELEMENT_NODE ):
-                self.debug("child tagName %s" % child.tagName )
+            if child.nodeType == node.ELEMENT_NODE:
+                self.debug("child tagName %s" % child.tagName)
                 tagName = child.tagName
-                if ( tagName == "TDirectory" ):
-                    status.append ( self.test( child, os.path.join( path , child.getAttribute("name")  ) ) )
-                    
-                    for test in [ "KS", "chi2", "bbb" ]:
-                        for stat in [ "OK", "WARN", "FAIL" ]:
+                if tagName == "TDirectory":
+                    status.append(self.test(child, os.path.join(path, child.getAttribute("name"))))
+
+                    for test in ["KS", "chi2", "bbb"]:
+                        for stat in ["OK", "WARN", "FAIL"]:
                             attr = test + stat
-                                
-                            parentCounter = node.getAttribute( attr )
-                            if ( not parentCounter ): parentCounter = "0"
-                            
-                            nodeCounter = child.getAttribute( attr )
-                            if ( not nodeCounter ): nodeCounter = "0"
-                            
-                            node.setAttribute( attr, "%d" % ( int(parentCounter) + int(nodeCounter) )  )            
+
+                            parentCounter = node.getAttribute(attr)
+                            if not parentCounter:
+                                parentCounter = "0"
+
+                            nodeCounter = child.getAttribute(attr)
+                            if not nodeCounter:
+                                nodeCounter = "0"
+
+                            node.setAttribute(attr, "%d" % (int(parentCounter) + int(nodeCounter)))
                 else:
 
-                    if ( child.hasAttribute("name") ):
-                        objName = child.getAttribute( "name" )
-                        objTests = child.getAttribute( "tests" ).split(",")
-                        self.debug( "found type=%s name=%s tests=%s in path %s" % ( tagName, objName, str(objTests), path ) )
-                        
-                        if ( path == "/" ):
+                    if child.hasAttribute("name"):
+                        objName = child.getAttribute("name")
+                        objTests = child.getAttribute("tests").split(",")
+                        self.debug("found type=%s name=%s tests=%s in path %s" % (tagName, objName, str(objTests), path))
+
+                        if path == "/":
                             objPath = objName
                         else:
-                            objPath = os.path.join( path, objName )
-                        
-                        refObj = self.refTFile.Get( objPath )
-                        monObj = self.monTFile.Get( objPath )
-                    
-                        status.append( self.tester.test( child, monObj, refObj ) )
+                            objPath = os.path.join(path, objName)
+
+                        objPath = objPath.encode('ascii', 'ignore')
+
+                        refObj = self.refTFile.Get(objPath)
+                        monObj = self.monTFile.Get(objPath)
+
+                        status.append(self.tester.test(child, monObj, refObj))
                     else:
-                        self.warn( "empty attribute 'name' found for tag <%s> in path %s, skipping!" % ( tagName, path ) )
-                    
-        statusAttr = "OK"    
-        if ( ( "FAIL" in status ) or
-             ( None in status ) ):
-            statusAttr = "FAIL"    
-        elif ( "WARN" in status ):
-            statsuAttr = "WARN"
-
-        self.debug("TDirectory %s status %s" % ( path, statusAttr ) )
-        node.setAttribute( "status", statusAttr )
-
-        return statusAttr 
-        
+                        self.warn("empty attribute 'name' found for tag <%s> in path %s, skipping!" % (tagName, path))
+
+        statusAttr = "OK"
+        if (("FAIL" in status) or (None in status)):
+            statusAttr = "FAIL"
+        elif "WARN" in status:
+            statusAttr = "WARN"
+
+        self.debug("TDirectory %s status %s" % (path, statusAttr))
+        node.setAttribute("status", statusAttr)
+
+        return statusAttr
+
     ## update parsed options from DCubeOptParser
     # @param self "Me, myself and Irene"
     # @param key option name
@@ -341,7 +341,7 @@ class DCubeApp( DCubeObject ):
     def __update(  self, key, what ):
         self.debug("updating option %s to %s" % ( str(key), str(what) ) )
         self.opts._update_loose( { key : what } )
-        
+
     ## dump left arguments to logger
     # @param self "Me, myself and Irene"
     def __dumpArgs( self ):
@@ -361,17 +361,17 @@ class DCubeApp( DCubeObject ):
             if ( v == "" ): v = "not set"
             self.info("[%02d] %s %s" % ( i, k, v))
             i += 1
-        
+
     ## save new output XML to file
     # @param self "Me, myself and Irene"
     def __save( self ):
-        
+
         outputURI = os.path.abspath( self.opts.output )
         self.__backup( outputURI )
         try:
           fileXML = open( outputURI, "w+")
           self.xmldoc.normalize()
-      
+
           xmlstring =  self.xmldoc.toprettyxml(" ", "\n").split("\n")
           for line in xmlstring:
               if line.strip("\n").strip() != "":
@@ -405,8 +405,8 @@ class DCubeApp( DCubeObject ):
             except OSError, value:
                 msg = "creation of backup file %s failed - %s" % ( backupURI, str(value) )
                 self.epanic( msg )
-                    
-    ## check existence of file 
+
+    ## check existence of file
     # @param self "Me, myself and Irene"
     # @param filename a file name to check
     def exists( self, filename ):
@@ -417,23 +417,23 @@ class DCubeApp( DCubeObject ):
 
     ## produce PHP files
     # @param self "Me, myself and Irene"
-    # @return boolean status 
+    # @return boolean status
     def __producePHPs( self ):
         self.info("will produce PHP files...")
 
         if ( not self.opts.server ):
             self.error("path to DCubeServer not set, PHP files won't be produced")
             return False
-        
+
         if ( None not in ( self.opts.log, self.opts.config, self.opts.output ) ):
             phpWriter = DCubePHPWriter( self.parsed )
 
             phpURI = os.path.abspath( self.opts.output + ".php" )
             logURI = os.path.abspath( os.path.join( os.path.dirname(self.opts.output), "dcubelog.php" ) )
-            
+
             self.debug( "out php URI %s" % phpURI )
             self.debug( "log php URI %s" % logURI )
-            
+
             phpOK = False
             try:
                 filePHP = open( phpURI, "w+" )
@@ -457,15 +457,15 @@ class DCubeApp( DCubeObject ):
             return ( phpOK and logOK )
 
 
-    ## main comment in output XML file 
+    ## main comment in output XML file
     # @param self "Me, myself and Irene"
     # @return a comment string
     def __mainXMLComment( self ):
         pass
 
-    
-## 
-# @class test_DCubeApp 
+
+##
+# @class test_DCubeApp
 # @author Krzysztof Daniel Ciba (Krzysztof.Ciba@NOSPAMgmail.com)
 # @brief test case for DCubeApp
 # @todo cover more!
@@ -481,10 +481,10 @@ class test_DCubeApp( unittest.TestCase ):
                          "--jobId", "job_1",
                          "--server", "/afs/cern.ch/user/c/cibak/scratch1/dcube/dcube.php",
                          "monitored.root" ]
-        
+
         self.sysExitHolder = sys.exit
         def exitCode( value ):
-            print "sys.exit called with value %s" % str(value)    
+            print "sys.exit called with value %s" % str(value)
         sys.exit = exitCode
 
     ## test contructor
@@ -501,12 +501,12 @@ class test_DCubeApp( unittest.TestCase ):
         theApp = DCubeApp( )
         del theApp
 
-    
+
 ## test suite execution
 if __name__ == "__main__":
-    
+
     # sometimes I believe python interpreter ignores all my comments
     testLoader = unittest.TestLoader()
-    suite = testLoader.loadTestsFromTestCase(test_DCubeApp)      
+    suite = testLoader.loadTestsFromTestCase(test_DCubeApp)
     unittest.TextTestRunner(verbosity=3).run(suite)
-    
+
diff --git a/Tools/DCubeClient/python/DCubeConfig.py b/Tools/DCubeClient/python/DCubeConfig.py
index 49cf93372345..ea6823881d40 100644
--- a/Tools/DCubeClient/python/DCubeConfig.py
+++ b/Tools/DCubeClient/python/DCubeConfig.py
@@ -539,7 +539,7 @@ class DCubeConfig( DCubeUtils.DCubeObject ):
                 else:
                     self.warn("dimension > 2 for histogram '%s', skipping" % fp)
 
-            elif ( isa.InheritsFrom("TGraph") ):
+            elif ( isa.InheritsFrom("TGraph") or isa.InheritsFrom("TEfficiency") ):
 
                 self.debug( nbsp + " --> found object '%s' at location '%s' of name '%s'" % ( cl, path, name) )
 
diff --git a/Tools/DCubeClient/python/DCubeOptParser.py b/Tools/DCubeClient/python/DCubeOptParser.py
index b93915aa9be1..8f5b530b7bd2 100644
--- a/Tools/DCubeClient/python/DCubeOptParser.py
+++ b/Tools/DCubeClient/python/DCubeOptParser.py
@@ -163,6 +163,11 @@ class DCubeOptParser( object ):
                                help="batch mode for PyROOT [always on]")
 
     
+        self.__par.add_option( "--useVarNameForPlotName",
+                               action="store_true",
+                               dest="useVarNameForPlotName",
+                               help="Name output plots after the variable they contain [default: use a generated UUID as name]")
+
         self.__par.set_defaults( pwarn=0.95,
                                  pfail=0.75, 
                                  config="dcube_config.xml",
@@ -178,6 +183,7 @@ class DCubeOptParser( object ):
                                  jobId="*",
                                  generate=False,
                                  makeplots=False,
+                                 useVarNameForPlotName=False,
                                  root2null=False)
 
 
diff --git a/Tools/DCubeClient/python/DCubePlotter.py b/Tools/DCubeClient/python/DCubePlotter.py
index 0f3f4ea64bd3..cbb1016cfb8c 100644
--- a/Tools/DCubeClient/python/DCubePlotter.py
+++ b/Tools/DCubeClient/python/DCubePlotter.py
@@ -153,7 +153,10 @@ class DCubePlotter( DCubeObject ):
     ## get unique plot name
     # @param self "Me, myself and Irene"
     def __plotName( self, what="" ):
-        return  what + "_" + str(uuid.uuid4()) + ".png"
+        name = str(uuid.uuid4())
+        if self.opts.useVarNameForPlotName:
+            name = self.name
+        return  what + "_" + name + ".png"
 
     ## plot dispatcher
     # @param self "Me, myself and Irene"
@@ -178,10 +181,11 @@ class DCubePlotter( DCubeObject ):
             #self.debug("additional plot options are: '%s'" % str(plotOpts) )
            
             for opt in plotOpts:
-                if ( opt not in [ "logx", "logy", "logz", "norm" ] ):
+                if ( opt not in [ "logx", "logy", "logz", "norm", "enorm" ] ):
                     self.error("ignoring unknown additional plot option '%s'" % opt )
                 else:
                     self.plotOpts.append(opt)
+                if opt == "enorm": self.plotOpts.append("norm")
             self.debug("additional plot options are: '%s'" % str(plotOpts) )
             
 
@@ -260,6 +264,9 @@ class DCubePlotter( DCubeObject ):
         status = [ "OK" ]
         self.debug("plotting %s of type %s" % ( self.name, self.className ) )
 
+        title = "%s;%s;%s" % ( self.mon.GetTitle(),
+                               self.mon.GetXaxis().GetTitle(),
+                               self.mon.GetYaxis().GetTitle() )
         graph = ROOT.TMultiGraph()
 
         canvas = self.__getCanvas()
@@ -267,17 +274,22 @@ class DCubePlotter( DCubeObject ):
 
         xmin, xmax, ymin, ymax = self.__getMinMaxTGraph( self.mon, self.ref )
 
-        dx = abs(xmax - xmin) * 0.15
         dy = abs(ymax - ymin) 
+        y0 = ymin - dy * 0.1
+        if ymin >= 0.0 and y0 < 0.0: y0 = 0.0
+        ymin= y0
+        ymax = ymax + dy * (self.unzoom-1.0)
         
-        ROOT.gPad.DrawFrame( xmin - dx, ymin - dy * 0.4, xmax + dx, ymax + dy*self.unzoom)
+        ROOT.gPad.DrawFrame( xmin, ymin, xmax, ymax, title)
 
-        ROOT.gStyle.SetPadBottomMargin(0.2)
+##      remove unneeded padding (10/7/2017)
+#       ROOT.gStyle.SetPadBottomMargin(0.2)
         
      
+        self.mon.SetMarkerStyle( ROOT.kFullCircle )
         self.mon.SetMarkerColor( ROOT.kRed )
         self.mon.SetFillColor( ROOT.kRed )
-        self.mon.SetFillStyle( 3005 )
+        self.mon.SetFillStyle( 3004 )
         self.mon.SetLineColor( ROOT.kRed )
             
                             
@@ -287,7 +299,7 @@ class DCubePlotter( DCubeObject ):
             self.ref.SetMarkerColor( ROOT.kBlue )
             self.ref.SetMarkerSize( 1.0 )        
             self.ref.SetFillColor( ROOT.kBlue )
-            self.ref.SetFillStyle( 3004 )
+            self.ref.SetFillStyle( 3005 )
             self.ref.SetLineColor( ROOT.kBlue )
             
             graph.Add( self.ref, "P" ) 
@@ -339,19 +351,15 @@ class DCubePlotter( DCubeObject ):
                 diffGraph.SetPoint(i, x, points[x] )
                 i += 1
 
-            xl = xmin - dx
-            xr = xmax + dx
-
             xmin, xmax, ymin, ymax = self.__getMinMaxTGraph( diffGraph )
             
             dy = abs(ymax - ymin) 
-
-            if ( ymin > ymax ):
-                a = ymin
-                ymin = ymax
-                ymax = ymin
+            y0 = ymin - dy * 0.1
+            if ymin >= 0.0 and y0 < 0.0: y0 = 0.0
+            ymax = ymax * self.unzoom
+            if ( ymax == 0.0 ): ymax = ymin + ( abs(ymin) * self.unzoom )
             
-            ROOT.gPad.DrawFrame( xl, ymin - (dy * 0.4), xr, ymax + (dy*self.unzoom) )
+            ROOT.gPad.DrawFrame( xmin, y0, xmax, ymax, "diff %s" % title)
             
             diffGraph.SetTitle( self.mon.GetTitle() )
             diffGraph.SetName( self.mon.GetName() )
@@ -372,106 +380,66 @@ class DCubePlotter( DCubeObject ):
     # @param self "Me, myself and Irene"
     def __getMinMaxTGraph( self, mon=None, ref=None ):
 
-        xmin = xmax = ymin=  ymax = None
-        if ( mon ):
-            x = ROOT.Double(0)
-            y = ROOT.Double(0)
-
-            exl = ROOT.Double(0)
-            exr = ROOT.Double(0)
-            eyl = ROOT.Double(0)
-            eyh = ROOT.Double(0) 
-
-            if ( self.className == "TGraph" ):
-                
-                for i in range( mon.GetN()  ):
-                    
-                    mon.GetPoint(i, x, y)
-                    
-                    if ( xmin == None ): xmin = ROOT.Double(x)
-                    if ( xmax == None ): xmax = ROOT.Double(x)
-                    if ( ymin == None ): ymin = ROOT.Double(y)
-                    if ( ymax == None ): ymax = ROOT.Double(y)
-                    
-                    if ( x < xmin ): xmin = x
-                    if ( x > xmax ): xmax = x
-                    if ( y < ymin ): ymin = y
-                    if ( y > ymax ): ymax = y
-                    
-                if ( ref ):
-                    for i in range( ref.GetN() ):
-
-                        ref.GetPoint(i, x, y)
-                        
-                        if ( xmin == None ): xmin = ROOT.Double(x)
-                        if ( xmax == None ): xmax = ROOT.Double(x)
-                        if ( ymin == None ): ymin = ROOT.Double(y)
-                        if ( ymax == None ): ymax = ROOT.Double(y)
-                        
-                        if ( x < xmin ): xmin = x
-                        if ( x > xmax ): xmax = x
-                        if ( y < ymin ): ymin = y
-                        if ( y > ymax ): ymax = y
-            else:
-
-                for i in range( mon.GetN() ):
-
-                    mon.GetPoint(i, x, y)
-
-                    exl = mon.GetErrorXhigh( i )
-                    exr = mon.GetErrorXlow( i )
-                    eyh = mon.GetErrorYhigh( i )
-                    eyl = mon.GetErrorYlow( i )
+        xmin = xmax = ymin = ymax = exmin = exmax = dxmin = None
+        xd = ROOT.Double(0)
+        yd = ROOT.Double(0)
+        for g in (ref, mon):
+            if g:
+                x0 = None
+                for i in range( g.GetN() ):
+
+                    g.GetPoint(i, xd, yd)
+                    x = float(xd)
+                    y = float(yd)
+
+                    if x0 is not None:
+                        dx = x - x0
+                        if dx > 0.0 and (dxmin is None or dx < dxmin): dxmin = dx
+                    x0 = x
+
+                    if ( self.className == "TGraph" ):
+                        exh = exl = eyh = eyl = 0.0
+                    else:
+                        exh = g.GetErrorXhigh( i )
+                        exl = g.GetErrorXlow( i )
+                        eyh = g.GetErrorYhigh( i )
+                        eyl = g.GetErrorYlow( i )
 
-                    xl = x - exr
-                    xr = x + exl
-                    yl = y - eyl
+                    xh = x + exh
+                    xl = x - exl
                     yh = y + eyh
+                    yl = y - eyl
 
-                    if ( xmin == None ): xmin = ROOT.Double(xl)
-                    if ( xmax == None ): xmax = ROOT.Double(xr)
-                    if ( ymin == None ): ymin = ROOT.Double(yl)
-                    if ( ymax == None ): ymax = ROOT.Double(yh)
-
-                    if ( xl < xmin ): xmin = xl
-                    if ( xr > xmax ): xmax = xr
-                    if ( yl < ymin ): ymin = yl
-                    if ( yh > ymax ): ymax = yh
-                    
-                if ( ref ):
-
-                    for i in range( ref.GetN() ):
-
-                        ref.GetPoint(i, x, y)
-                        
-                        exl = ref.GetErrorXhigh( i )
-                        exr = ref.GetErrorXlow( i )
-                        eyh = ref.GetErrorYhigh( i )
-                        eyl = ref.GetErrorYlow( i )
-                        
-                        xl = x - exr
-                        xr = x + exl
-                        yl = y - eyl
-                        yh = y + eyh
-
-                        if ( xmin == None ): xmin = ROOT.Double(xl)
-                        if ( xmax == None ): xmax = ROOT.Double(xr)
-                        if ( ymin == None ): ymin = ROOT.Double(yl)
-                        if ( ymax == None ): ymax = ROOT.Double(yh)
-
-                        if ( xl < xmin ): xmin = xl
-                        if ( xr > xmax ): xmax = xr
-                        if ( yl < ymin ): ymin = yl
-                        if ( yh > ymax ): ymax = yh
-
-
-            return ( xmin, xmax, ymin, ymax)
+                    if ( xmin is None or xl < xmin ): xmin, exmin = xl, exl
+                    if ( xmax is None or xh > xmax ): xmax, exmax = xh, exh
+                    if ( ymin is None or yl < ymin ): ymin        = yl
+                    if ( ymax is None or yh > ymax ): ymax        = yh
+
+        # if no x-errors, add half-bin width
+        if ( dxmin is not None ):
+            if ( exmin <= 0.0 ): xmin -= 0.5 * dxmin
+            if ( exmax <= 0.0 ): xmax += 0.5 * dxmin
+
+        # if no limits, then use graph range
+        if ref: g = ref
+        else:   g = mon
+        if g:
+            if ( xmin is None or xmin >= xmax ): xmin = g.GetHistogram().GetXaxis().GetXmin()
+            if ( xmax is None or xmin >= xmax ): xmax = g.GetHistogram().GetXaxis().GetXmax()
+            if ( ymin is None or ymin >= ymax ): ymin = g.GetHistogram().GetYaxis().GetXmin()
+            if ( ymax is None or ymin >= ymax ): ymax = g.GetHistogram().GetYaxis().GetXmax()
+
+        return ( xmin, xmax, ymin, ymax)
             
 
     def __normTH( self, obj=None ):
         if ( obj ):
-            self.debug( "will normalize histogram '%s'" % obj.GetName())
-            integral = obj.Integral()
+            if ( "enorm" in self.plotOpts ):
+                self.debug( "will normalize histogram '%s' to the number of entries" % obj.GetName())
+                integral = obj.GetEntries()
+            else:
+                self.debug( "will normalize histogram '%s'" % obj.GetName())
+                integral = obj.Integral()
             if ( integral != 0.0 ):
                 scale = 1.0 / integral
                 self.debug("integral = %f, scale = %f" % (integral, scale ) )
diff --git a/Tools/DCubeClient/python/DCubeTester.py b/Tools/DCubeClient/python/DCubeTester.py
index 943cdc3c5fd1..154101899b42 100644
--- a/Tools/DCubeClient/python/DCubeTester.py
+++ b/Tools/DCubeClient/python/DCubeTester.py
@@ -11,17 +11,18 @@ from DCubeUtils import DCubeObject, DCubeException
 from DCubePlotter import DCubePlotter
 import ROOT
 import unittest
+import math
 
 ##
 # @class DCubeTester
 # @author Krzysztof Daniel Ciba (Krzysztof.Ciba@NOSPAMgmail.com)
-# @brief perform statictics tests and plotting  
+# @brief perform statictics tests and plotting
 class DCubeTester( DCubeObject ):
 
     ## XML DOM Document instance
     xmldoc = None
 
-    ## XML DOM Element instance 
+    ## XML DOM Element instance
     node = None
 
     ## handle for monitored root object
@@ -35,7 +36,7 @@ class DCubeTester( DCubeObject ):
 
     ## intarnal histogram counter
     __nbObjs = 0
-    
+
     ## statistics summary table
     sumTable = { "KS"   : { "OK"   : 0,
                             "WARN" : 0,
@@ -57,15 +58,15 @@ class DCubeTester( DCubeObject ):
                   2 : "there is bin in ref hist with low then 1 exp number of event",
                   3 : "there are bins in both histograms with less than 1 event" }
 
-    
+
     ## summary status
     __status = ""
-    
+
     ## c'tor
     # @param self "Me, myself and Irene"
     # @param xmldoc XML DOM Document instance
     def __init__( self, xmldoc, parsed ):
-        
+
         super( DCubeTester, self ).__init__( self )
         self.xmldoc = xmldoc
         self.opts, self.args = parsed
@@ -73,22 +74,21 @@ class DCubeTester( DCubeObject ):
                        "bbb"  : self.__testBBB,
                        "chi2" : self.__testChi2,
                        "meanY": self.__testMeanY }
-       
+
 
         if ( self.opts.makeplots ):
             self.info("will produce plot files")
             self.__plotter = DCubePlotter( xmldoc, parsed )
         else:
             self.warn("making of plots disabled")
-            
-    ## 
+
+    ##
     # @param self "Me, myself and Irene"
-    # @param node DOM XML  node 
+    # @param node DOM XML  node
     # @param mon monitored ROOT object
     # @param ref reference ROOT object
-    # @return modified XML node 
-    def test( self, node, mon=None, ref=None ):
-
+    # @return modified XML node
+    def test(self, node, mon=None, ref=None):
         self.__nbObjs += 1
 
         self.node = self.mon = self.ref = None
@@ -100,29 +100,28 @@ class DCubeTester( DCubeObject ):
         self.ref = ref
 
         # mon exists?
-        if ( not self.mon ):
+        if not self.mon:
             status = "FAIL;monitored not found"
-            self.node.setAttribute( "status", status )
+            self.node.setAttribute("status", status)
             if status not in self.errors.keys():
-                self.errors[ status ] = 1
+                self.errors[status] = 1
             else:
-                self.errors[ status ] = self.errors[ status ] + 1
+                self.errors[status] = self.errors[status] + 1
             self.error("monitored object not found!")
             return "FAIL"
 
-        cl = self.mon.Class().GetName() 
-        isHist = False
-        if ( cl[:2] in ( "TH", "TP") ): isHist = True
-       
+        cl = self.mon.Class().GetName()
+        isHist = (cl[:2] in ("TH", "TP"))
+
         # dimension OK?
-        if ( isHist and self.mon.GetDimension() > 2 ):
+        if (isHist and self.mon.GetDimension() > 2):
             status = "FAIL;unsupported object, dimension bigger than 2"
-            self.node.setAttribute( "status", status )
-            if ( status not in self.errors.keys() ):
-                self.errors[ status ] = 1
+            self.node.setAttribute("status", status)
+            if status not in self.errors.keys():
+                self.errors[status] = 1
             else:
-                self.errors[ status ] = self.errors[ status ] + 1
-            self.error( "unsuported object found" )
+                self.errors[status] = self.errors[status] + 1
+            self.error("unsuported object found")
             return "FAIL"
 
         # reference exists?
@@ -134,7 +133,7 @@ class DCubeTester( DCubeObject ):
                 self.errors[ status ] = 1
             else:
                 self.errors[ status ] = self.errors[ status ] + 1
-    
+
         if ( self.mon and self.ref ):
             # same class?
             monClassName = self.mon.Class().GetName()
@@ -152,44 +151,60 @@ class DCubeTester( DCubeObject ):
 
 
         if ( isHist ):
-            self.monBins = [ self.mon.GetNbinsX(), self.mon.GetNbinsY() ]  
+            self.monBins = [ self.mon.GetNbinsX(), self.mon.GetNbinsY() ]
         if ( isHist and self.ref ):
             self.refBins = [ self.ref.GetNbinsX(), self.ref.GetNbinsY() ]
-      
+
         if ( isHist and self.mon and self.ref ):
             # same binnig?
             monBins = [ "%s=%d" % ( x, y) for ( x, y) in zip(["x", "y"], self.monBins ) ]
-            refBins = [ "%s=%d" % ( x, y) for ( x, y) in zip(["x", "y"], self.refBins ) ]                         
+            refBins = [ "%s=%d" % ( x, y) for ( x, y) in zip(["x", "y"], self.refBins ) ]
             diffBins = [ "mon %s ref %s" % (x, y) for (x,y) in zip(monBins,refBins) if x != y ]
             if ( diffBins  ):
-                status = "FAIL;different binnig"
+                status = "FAIL;different binning"
                 self.node.setAttribute( "status", status + " %s" % " ".join(diffBins) )
                 if ( status not in self.errors.keys() ):
                     self.errors[ status ] = 1
                 else:
                     self.errors[ status ] = self.errors[ status ] + 1
                 self.error("different binning for mon and ref objects!")
-                return "FAIL" 
+                return "FAIL"
 
-        status = "OK"                    
+        if cl == "TEfficiency":
+            # Replace with TGraphAsymmErrors for stats and plotting
+            self.mon = mon.CreateGraph("AP")
+            self.ref = ref.CreateGraph("AP")
+            # remove x-error bars
+            for i in range( self.mon.GetN() ):
+                self.mon.SetPointEXlow( i, 0.0 )
+                self.mon.SetPointEXhigh( i, 0.0 )
+            for i in range( self.ref.GetN() ):
+                self.ref.SetPointEXlow( i, 0.0 )
+                self.ref.SetPointEXhigh( i, 0.0 )
+            isHist = False
+
+        status = "OK"
         if ( isHist ):
             status = self.__grabHistogramStat()
         else:
-            status = self.__grabGraphStat() 
+            status = self.__grabGraphStat()
 
         plotStatus = "OK"
         if ( self.opts.makeplots ):
-            plotStatus = self.__makePlots() 
+            plotStatus = self.__makePlots()
         else:
             plotStatus = "WARN;plots not reqested"
         self.node.setAttribute( "plots", plotStatus)
 
         return status
-        
 
-    ## grab statistic info for TGraphXXX  
+
+    ## grab statistic info for TGraphXXX
     # @param self "Me, myself and Irene"
     def __grabGraphStat( self ):
+        if self.mon.GetHistogram().GetDimension() == 1: axis = 2  # change to y-mean and y-RMS (10/7/2017)
+        else:                                           axis = 1  # TGraph2D probably not supported anyway
+
         statNode = self.xmldoc.createElement( "stat" )
         self.node.appendChild( statNode )
 
@@ -200,15 +215,15 @@ class DCubeTester( DCubeObject ):
         nbPointsNode.appendChild( nbPointsCData )
 
         meanNode = self.xmldoc.createElement( "mean" )
-        meanCData = self.xmldoc.createTextNode( "%4.3f" % self.mon.GetMean() )
+        meanCData = self.xmldoc.createTextNode( "%4.3f" % self.mon.GetMean(axis) )
         if ( self.ref ):
-            meanNode.setAttribute( "ref" , "%4.3f" % self.ref.GetMean() )
+            meanNode.setAttribute( "ref" , "%4.3f" % self.ref.GetMean(axis) )
         meanNode.appendChild( meanCData )
 
         rmsNode = self.xmldoc.createElement( "rms" )
-        rmsCData = self.xmldoc.createTextNode( "%d" % self.mon.GetRMS() )
+        rmsCData = self.xmldoc.createTextNode( "%4.3f" % self.mon.GetRMS(axis) )
         if ( self.ref ):
-            rmsNode.setAttribute( "ref" , "%d" % self.ref.GetRMS() )
+            rmsNode.setAttribute( "ref" , "%4.3f" % self.ref.GetRMS(axis) )
         rmsNode.appendChild( rmsCData )
 
         statNode.appendChild( nbPointsNode )
@@ -216,9 +231,9 @@ class DCubeTester( DCubeObject ):
         statNode.appendChild( rmsNode )
 
         return "OK"
-        
-        
-        
+
+
+
     ## grab basic statistics - nb of entries, mean and RMS
     # @param self "Me, myself and Irene"
     def __grabHistogramStat( self ):
@@ -235,33 +250,54 @@ class DCubeTester( DCubeObject ):
 
         statNode.appendChild( entriesNode )
 
-        dim = self.mon.GetDimension() 
+        dim = self.mon.GetDimension()
 
         ### To dump MeanY values
         if ( "TProfile" in self.mon.Class().GetName() ): dim = 2
 
-        # store under and overflows 
+        # store under and overflows
         monU = []
         monO = []
         refU = []
         refO = []
 
+        #store underflows and overflows to check is some of them are inf or nan
+        vals = []
+
         if ( dim == 1 ):
             monU.append( self.mon.GetBinContent(0) )
+            vals.append( self.mon.GetBinContent(0) )
             monO.append( self.mon.GetBinContent( self.mon.GetNbinsX()+1 ) )
+            vals.append( self.mon.GetBinContent( self.mon.GetNbinsX()+1 ) )
             if ( self.ref ):
                 refU.append( self.ref.GetBinContent(0) )
+                vals.append( self.ref.GetBinContent(0) )
                 refO.append( self.ref.GetBinContent( self.ref.GetNbinsX()+1 ) )
+                vals.append( self.ref.GetBinContent( self.ref.GetNbinsX()+1 ) )
         elif ( dim == 2 ):
             monU.append( self.mon.GetBinContent( 0, 0 ) )
+            vals.append( self.mon.GetBinContent( 0, 0 ) )
             monO.append( self.mon.GetBinContent( self.mon.GetNbinsX()+1, 0 ) )
+            vals.append( self.mon.GetBinContent( self.mon.GetNbinsX()+1, 0 ) )
             monU.append( self.mon.GetBinContent( 0,  self.mon.GetNbinsY()+1) )
-            monO.append( self.mon.GetBinContent( self.mon.GetNbinsX()+1, self.mon.GetNbinsY()+1 ) )  
+            vals.append( self.mon.GetBinContent( 0,  self.mon.GetNbinsY()+1) )
+            monO.append( self.mon.GetBinContent( self.mon.GetNbinsX()+1, self.mon.GetNbinsY()+1 ) )
+            vals.append( self.mon.GetBinContent( self.mon.GetNbinsX()+1, self.mon.GetNbinsY()+1 ) )
             if ( self.ref ):
                 refU.append( self.ref.GetBinContent( 0, 0 ) )
+                vals.append( self.ref.GetBinContent( 0, 0 ) )
                 refO.append( self.ref.GetBinContent( self.ref.GetNbinsX()+1, 0 ) )
+                vals.append( self.ref.GetBinContent( self.ref.GetNbinsX()+1, 0 ) )
                 refU.append( self.ref.GetBinContent( 0,  self.ref.GetNbinsY()+1) )
-                refO.append( self.ref.GetBinContent( self.ref.GetNbinsX()+1, self.ref.GetNbinsY()+1 ) )  
+                vals.append( self.ref.GetBinContent( 0,  self.ref.GetNbinsY()+1) )
+                refO.append( self.ref.GetBinContent( self.ref.GetNbinsX()+1, self.ref.GetNbinsY()+1 ) )
+                vals.append( self.ref.GetBinContent( self.ref.GetNbinsX()+1, self.ref.GetNbinsY()+1 ) )
+
+        #check if some values are inf or nan
+        if ( self.__checkValues(vals) != "OK" ):
+            self.warn( "some values in histogram are infinity or NaN, skipping!")
+            self.node.setAttribute( "status", "FAIL;monitored or reference histogram contains inf or NaN values")
+            return "FAIL"
 
         underflowNode = self.xmldoc.createElement( "underflow" )
         underflowCData = self.xmldoc.createTextNode( "%d" % sum( monU ) )
@@ -277,7 +313,7 @@ class DCubeTester( DCubeObject ):
 
         statNode.appendChild( underflowNode )
         statNode.appendChild( overflowNode )
-        
+
         dimName = [ "x", "y", "z" ]
         for i in range( 1, dim+1 ):
             self.debug( "gathering statistics along %s axis" % dimName[i-1] )
@@ -285,7 +321,7 @@ class DCubeTester( DCubeObject ):
             dimNode = self.xmldoc.createElement( "dim" )
             dimNode.setAttribute( "name", dimName[i-1] )
             dimNode.setAttribute( "bins", "%d" % self.monBins[i-1])
-        
+
             underflowNode = self.xmldoc.createElement( "underflow" )
             underflowCData  = self.xmldoc.createTextNode( "%d" % monU[i-1] )
             if ( self.ref ):
@@ -293,7 +329,7 @@ class DCubeTester( DCubeObject ):
             underflowNode.appendChild( underflowCData )
 
             dimNode.appendChild( underflowNode )
-        
+
             overflowNode = self.xmldoc.createElement( "overflow" )
             overflowCData  = self.xmldoc.createTextNode( "%d" % monO[i-1] )
             if ( self.ref ):
@@ -301,27 +337,27 @@ class DCubeTester( DCubeObject ):
             overflowNode.appendChild( overflowCData )
 
             dimNode.appendChild( overflowNode )
-            
+
             meanNode = self.xmldoc.createElement( "mean" )
             if ( self.ref ):
                 meanNode.setAttribute( "ref", "%3.2e" % self.ref.GetMean(i) )
 
             meanCData = self.xmldoc.createTextNode( "%3.2e" % self.mon.GetMean( i ) )
             meanNode.appendChild( meanCData )
-            
+
             meanErrorNode = self.xmldoc.createElement( "mean_unc" )
             if ( self.ref ):
                 meanErrorNode.setAttribute( "ref", "%3.2e" % self.ref.GetMeanError(i) )
 
             meanErrorCData = self.xmldoc.createTextNode( "%3.2e" % self.mon.GetMeanError( i ) )
             meanErrorNode.appendChild( meanErrorCData )
-            
+
             rmsNode = self.xmldoc.createElement( "rms" )
             if ( self.ref ):
                 rmsNode.setAttribute( "ref", "%3.2e" % self.ref.GetRMS(i) )
             rmsCData = self.xmldoc.createTextNode( "%3.2e" % self.mon.GetRMS(i) )
             rmsNode.appendChild( rmsCData )
-        
+
             rmsErrorNode = self.xmldoc.createElement( "rms_unc" )
             if ( self.ref ):
                 rmsErrorNode.setAttribute( "ref", "%3.2e" % self.ref.GetRMSError(i) )
@@ -340,31 +376,52 @@ class DCubeTester( DCubeObject ):
         status = [ ]
 
         tests = [t for t in self.node.getAttribute('tests').strip().split(',') if t]
-        
+
+
+        if ( self.node.getAttribute('pwarn') ):
+            try:
+                pwarn = float ( self.node.getAttribute('pwarn').strip() )
+            except TypeError, value:
+                raise DCubeException( "histogram %s pvalue limit for WARN is NAN" % self.node.getAttribute('name') )
+            self.info("overriding pvalue limits for histogram %s: new WARN limit is pwarn=%s" % ( self.node.getAttribute('name'), pwarn ) )
+        else:
+            pwarn = self.opts.pwarn
+
+        if ( self.node.getAttribute('pfail') ):
+            try:
+                pfail = float ( self.node.getAttribute('pfail').strip() )
+            except TypeError, value:
+                raise DCubeException( "histogram %s pvalue limit for FAIL is NAN" % self.node.getAttribute('name') )
+            self.info("overriding pvalue limits for histogram %s: new FAIL limit is pfail=%s" % ( self.node.getAttribute('name'), pfail ) )
+        else:
+            pfail = self.opts.pfail
+
+
+
         if ( "all" in tests ): tests = [ "KS", "chi2", "bbb", "meany" ]
 
         if ( None not in ( self.mon, self.ref ) ):
-             
+
             if ( "TProfile" in self.mon.Class().GetName() ):
                 if ( "meany" in tests ):
                     status.append( self.__testMeanY.__call__( statNode ) )
             else:
                 for test in tests:
                     if ( test != "meany" ):
-                        status.append( self.tests[ test ].__call__( statNode ) )
-                    
+                        status.append( self.tests[ test ].__call__( statNode, pwarn, pfail ) )
+
         statusAttr = "OK"
         if ( "FAIL" in status ): statusAttr = "FAIL"
         elif ( "WARN" in status ): statusAttr = "WARN"
-        
+
         self.node.setAttribute( "stest", statusAttr )
 
         return statusAttr
-                    
+
     ## perform @f$\chi^2@f$ test
     # @param self "Me, myself and Irene"
     # @param statNode <stat> element
-    def __testChi2( self, statNode ):
+    def __testChi2( self, statNode, pwarn, pfail ):
 
         chi2 = ROOT.Double( 0.0 )
         igood = ROOT.Long( 0 )
@@ -389,8 +446,8 @@ class DCubeTester( DCubeObject ):
             else:
                 self.warn( ig )
 
-        status = self.__getTestStatus( pval ) 
-        self.sumTable["chi2"][status] = self.sumTable["chi2"][status] + 1   
+        status = self.__getTestStatus( pval, pwarn, pfail )
+        self.sumTable["chi2"][status] = self.sumTable["chi2"][status] + 1
 
         if ( ndf != 0 ):
             self.info( "*** Pearson's chi2 *** chi2 (/ndf) = %4.3f (/%d = %4.3f) status=%s" % ( chi2,
@@ -407,7 +464,7 @@ class DCubeTester( DCubeObject ):
 
         pValueNode.setAttribute( "test", "chi2" )
         pValueNode.setAttribute( "status", status )
-       
+
         counter = self.parent.getAttribute( "chi2" + status )
         if ( not counter ): counter = "0"
         self.parent.setAttribute( "chi2" + status, "%d" % ( int(counter) + 1 )  )
@@ -422,7 +479,7 @@ class DCubeTester( DCubeObject ):
     ## perform Kolmogorov-Smirnoff test
     # @param self "Me, myself and Irene"
     # @param statNode <stat> element
-    def __testKS( self, statNode ):
+    def __testKS( self, statNode, pwarn, pfail ):
 
         nbBins,nbBinsSame,nbBinsDiff = self.__testEqual()
         self.debug("*** Kolmogorov-Smirnoff *** all none-empty bins=%d all equal non-empty bins=%d" % ( nbBins, nbBinsSame ) )
@@ -434,9 +491,9 @@ class DCubeTester( DCubeObject ):
             self.debug( "*** Kolmogorov-Smirnoff *** both histograms are equal!" )
         else:
             pval = self.mon.KolmogorovTest( self.ref, "D" )
-        
-        status = self.__getTestStatus( pval ) 
-        self.sumTable["KS"][status] = self.sumTable["KS"][status] + 1     
+
+        status = self.__getTestStatus( pval, pwarn, pfail )
+        self.sumTable["KS"][status] = self.sumTable["KS"][status] + 1
 
         self.info( "*** Kolmogorov-Smirnoff *** (D) p-value=%4.3f status=%s" % ( pval, status ) )
 
@@ -454,7 +511,7 @@ class DCubeTester( DCubeObject ):
 
         statNode.appendChild( pValueNode )
         return status
-        
+
     ##  ** provide check if equal **
     # returns (nbBins,nbBinsSame,nbBinsDiff)
     #   nbBins - nb of bins not zero
@@ -480,14 +537,14 @@ class DCubeTester( DCubeObject ):
     ## perform "bin-by-bin" statistic test
     # @param self "Me, myself and Irene"
     # @param statNode <stat> element
-    def __testBBB( self, statNode ):
+    def __testBBB( self, statNode, pwarn, pfail ):
 
         nbBins,nbBinsSame,nbBinsDiff = self.__testEqual()
         self.debug("*** bin-by-bin *** all none-empty bins=%d all equal non-empty bins=%d" % ( nbBins, nbBinsSame ) )
 
         pval = 0.0
         if ( nbBins != 0.0 ):
-            pval = nbBinsSame / nbBins  
+            pval = nbBinsSame / nbBins
             self.debug("*** bin-by-bin *** p-value=%4.3f" % pval )
         elif ( nbBinsSame == 0.0 ):
             pval = 1.0
@@ -497,11 +554,11 @@ class DCubeTester( DCubeObject ):
             # AS: this part is never called?!
             self.warn( "*** bin-by-bin *** reference histogram is empty, while monitored has some entries" )
             self.debug( "*** bin-by-bin *** test failed" )
-        
-        status = self.__getTestStatus( pval )
+
+        status = self.__getTestStatus( pval, pwarn, pfail )
         self.info("*** bin-by-bin *** p-value=%4.3f status=%s" % ( pval, status ) )
 
-        self.sumTable["bbb"][status] = self.sumTable["bbb"][status] + 1     
+        self.sumTable["bbb"][status] = self.sumTable["bbb"][status] + 1
 
         pValueNode = self.xmldoc.createElement( "pvalue" )
         pValueCData = self.xmldoc.createTextNode( "%4.3f" % pval )
@@ -529,13 +586,13 @@ class DCubeTester( DCubeObject ):
         avgEffref = self.ref.GetMean( 2 ) * 100
 
         self.debug("*** MeanY Test *** refMean=%4.3f and monMean=%4.3f" % ( avgEffref, avgEffmon ) )
-        
+
         pval = abs(avgEffmon - avgEffref)
 
         status = self.__getMeanTestStatus( pval )
         self.info("*** Mean Test *** p-value=%4.3f status=%s" % ( pval, status ) )
 
-        self.sumTable["meanY"][status] = self.sumTable["meanY"][status] + 1     
+        self.sumTable["meanY"][status] = self.sumTable["meanY"][status] + 1
 
         pValueNode = self.xmldoc.createElement( "pvalue" )
         pValueCData = self.xmldoc.createTextNode( "%4.3f" % pval )
@@ -552,19 +609,19 @@ class DCubeTester( DCubeObject ):
         statNode.appendChild( pValueNode )
 
         return status
-    
-    
-    ## get test status for given pvalue 
+
+
+    ## get test status for given pvalue
     # @param self "Me, myself and Irene"
     # @param pval p-value from test
-    def __getTestStatus( self, pval ):
-        if ( ( pval < 0.0 or pval > 1.0 ) or  
-             ( pval <= self.opts.pfail ) ): return "FAIL"
-        if ( pval > self.opts.pwarn ): return "OK"
+    def __getTestStatus( self, pval, pwarn, pfail ):
+        if ( ( pval < 0.0 or pval > 1.0 ) or
+             ( pval <= pfail ) ): return "FAIL"
+        if ( pval > pwarn ): return "OK"
         return "WARN"
 
 
-    ## get test status for given pvalue 
+    ## get test status for given pvalue
     # @param self "Me, myself and Irene"
     # @param pval p-value from test
     def __getMeanTestStatus( self, pval ):
@@ -580,10 +637,10 @@ class DCubeTester( DCubeObject ):
             plotOpts = self.node.getAttribute( "plotopts" )
             status = self.__plotter.plot( self.node, self.mon, self.ref, plotOpts  )
             return status
-    
+
 
     ## string representation of DCubeTester
-    # @param self "Me, myself and Irene" 
+    # @param self "Me, myself and Irene"
     def __str__( self ):
         out  = "*"*61 + "\n"
         out += "* RUN SUMMARY\n"
@@ -591,7 +648,7 @@ class DCubeTester( DCubeObject ):
         out += "* objects processed = %d\n" % self.__nbObjs
         out += "* STATISTICS TESTS TABLE\n"
         out += "* " + "-"*45 + "\n"
-        out += "* | %-8s | %8s | %8s | %8s |\n" % ( "test", "OK", "WARN", "FAIL") 
+        out += "* | %-8s | %8s | %8s | %8s |\n" % ( "test", "OK", "WARN", "FAIL")
         self.allGOOD = 0
         self.allWARN = 0
         self.allFAIL = 0
@@ -605,20 +662,20 @@ class DCubeTester( DCubeObject ):
             self.allFAIL += nbFAIL
             out += "* " + "-"*45+"\n"
             out += "* | %-8s | %8d | %8d | %8d |\n" % ( key, nbGOOD, nbWARN, nbFAIL )
-            
+
         out += "* " + "-"*45+"\n"
 
-        
+
         out += "* | %-8s | %8d | %8d | %8d |\n" % ( "all", self.allGOOD, self.allWARN, self.allFAIL )
         out += "* " + "-"*45+"\n"
 
         self.fracGOOD = 0.0
         self.fracWARN = 0.0
         self.fracFAIL = 0.0
-        all = float( self.allGOOD + self.allWARN + self.allFAIL ) 
+        all = float( self.allGOOD + self.allWARN + self.allFAIL )
         if ( all ):
-            self.fracGOOD = 100 * float( self.allGOOD ) / all 
-            self.fracWARN = 100 * float( self.allWARN ) / all 
+            self.fracGOOD = 100 * float( self.allGOOD ) / all
+            self.fracWARN = 100 * float( self.allWARN ) / all
             self.fracFAIL = 100 * float( self.allFAIL ) / all
         out += "* | %%        |    %04.2f |    %04.2f |    %04.2f |\n" % ( self.fracGOOD, self.fracWARN, self.fracFAIL )
         out += "* " + "-"*45+"\n"
@@ -629,16 +686,16 @@ class DCubeTester( DCubeObject ):
         i = 1
         for key, value in self.errors.iteritems( ):
             sev, what = key.split(";")
-            
+
             out += "* [%02d] %4s %-30s - occured %d " %  (i, sev, what, value )
             if ( value == 1 ): out += "time\n"
             else: out += "times\n"
             i += 1
 
         out += "*"*61+"\n"
-        
+
         self.__status = ""
-        
+
         if ( self.allFAIL != 0 ):
             self.__status = "FAIL"
         elif ( self.allWARN != 0 or self.nbErrors != 0 ):
@@ -647,17 +704,17 @@ class DCubeTester( DCubeObject ):
             self.__status = "OK"
 
         out += "* OVERALL STATISTICS STATUS: %-4s\n" % self.__status
-                    
+
         out += "*"*61
-        
+
         return out
 
-    ## put summary to the logger and create summary node 
+    ## put summary to the logger and create summary node
     # @param self "Me, myself and Irene"
     # @return summary XML Element
     def summary( self ):
-        
-        for line in str(self).split("\n"): 
+
+        for line in str(self).split("\n"):
             self.info( line )
 
         summaryNode = self.xmldoc.createElement( "summary" )
@@ -667,18 +724,18 @@ class DCubeTester( DCubeObject ):
 
         testTable = self.xmldoc.createElement( "table" )
         testTable.appendChild( self.__sumTableRow( [ "test", "OK", "WARN", "FAIL" ] ) )
-        for test, results in self.sumTable.iteritems(): 
+        for test, results in self.sumTable.iteritems():
             testTable.appendChild( self.__sumTableRow( [ test,
                                                          results["OK"],
                                                          results["WARN"],
                                                          results["FAIL"] ] ) )
-            
+
         testTable.appendChild( self.__sumTableRow( ["sum", self.allGOOD, self.allWARN, self.allFAIL ] ) )
         testTable.appendChild( self.__sumTableRow( ["fraction",
                                                     "%4.2f" % self.fracGOOD,
                                                     "%4.2f" % self.fracWARN,
                                                     "%4.2f" % self.fracFAIL ] ) )
-        
+
         summaryNode.appendChild( testTable )
 
         errorsNode = self.xmldoc.createElement( "errors" )
@@ -690,12 +747,12 @@ class DCubeTester( DCubeObject ):
             errorNode.setAttribute( "times", "%d" % times )
             errorNode.setAttribute( "what", error )
             errorsNode.appendChild( errorNode )
-            
+
         summaryNode.appendChild( errorsNode )
-        
-        return summaryNode 
 
-    ## produce summary table row 
+        return summaryNode
+
+    ## produce summary table row
     # @param self "Me, myself and Irene"
     def __sumTableRow( self, what ):
         row = self.xmldoc.createElement( "tr" )
@@ -710,11 +767,18 @@ class DCubeTester( DCubeObject ):
     # @param self "Me, myself and Irene"
     def status( self ):
         return self.__status
-        
-        
+
+    #check that values in histogram are not infinity or nan
+    def __checkValues( self, values ):
+        for val in values:
+            if ( math.isinf(abs( val ) ) or math.isnan( val ) ) :
+                return "BAD"
+        return "OK"
+
+
 ##
 # @class test_DCubeTester
-# @author Krzysztof Daniel Ciba (Krzysztof.Ciba@NOSPAMgmail.com) 
+# @author Krzysztof Daniel Ciba (Krzysztof.Ciba@NOSPAMgmail.com)
 # @brief test case for DCubeTester class
 class test_DCubeTester( unittest.TestCase ):
 
@@ -732,5 +796,5 @@ class test_DCubeTester( unittest.TestCase ):
 ## test case execution
 if __name__ == "__main__":
     pass
-    
+
 
diff --git a/Tools/DCubeClient/share/DCubeValid.xml b/Tools/DCubeClient/share/DCubeValid.xml
index 55e421c88630..f2cb9d111eda 100644
--- a/Tools/DCubeClient/share/DCubeValid.xml
+++ b/Tools/DCubeClient/share/DCubeValid.xml
@@ -18,6 +18,7 @@
 <branch>devval</branch>
 <branch>bugfix</branch>
 <branch>point1</branch>
+<branch re="\d{2}\.\d{1}$">NN.N</branch>
 <branch re="\d{2}\.\d{1}\.\d{1}X$">NN.N.NX</branch>
 <branch re="\d{2}\.\d{1}\.\d{1}X\.Y$">NN.N.NX.Y</branch>
 <branch re="\d{2}\.\d{1}\.\d{1}X\.Y\-VAL$">NN.N.NX.Y-VAL</branch>
@@ -44,14 +45,6 @@
 <install>*</install>
 
 <!-- known CMTCONFIG values -->
-<cmt>i686-slc3-gcc323-dbg</cmt>
-<cmt>i686-slc3-gcc323-opt</cmt>
-<cmt>i686-slc4-gcc34-dbg</cmt>
-<cmt>i686-slc4-gcc34-opt</cmt>
-<cmt>i686-slc4-gcc43-dbg</cmt>
-<cmt>i686-slc4-gcc43-opt</cmt>
-<cmt>x86_64-slc4-gcc34-dbg</cmt>
-<cmt>x86_64-slc4-gcc34-opt</cmt>
 <cmt>i686-slc5-gcc34-dbg</cmt>
 <cmt>i686-slc5-gcc34-opt</cmt>
 <cmt>i686-slc5-gcc43-dbg</cmt>
@@ -60,6 +53,16 @@
 <cmt>x86_64-slc5-gcc34-opt</cmt>
 <cmt>x86_64-slc5-gcc43-dbg</cmt>
 <cmt>x86_64-slc5-gcc43-opt</cmt>
+<cmt>x86_64-slc6-gcc46-opt</cmt>
+<cmt>x86_64-slc6-gcc46-dbg</cmt>
+<cmt>x86_64-slc6-gcc47-opt</cmt>
+<cmt>x86_64-slc6-gcc47-dbg</cmt>
+<cmt>x86_64-slc6-gcc48-opt</cmt>
+<cmt>x86_64-slc6-gcc48-dbg</cmt>
+<cmt>x86_64-slc6-gcc49-opt</cmt>
+<cmt>x86_64-slc6-gcc49-dbg</cmt>
+<cmt>x86_64-slc6-gcc62-opt</cmt>
+<cmt>x86_64-slc6-gcc62-dbg</cmt>
 <!-- this one matches to ALL -->
 <cmt>*</cmt>
 
-- 
GitLab