def getVarNames( dataset, effName='efficiency' ): """.. function:: getVarNames( dataset, effName='efficiency' ) -> [ binnedvar1,...], effName From a dataset extract which binned variables have and returns the list of the variable's names and the efficiency name :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name. Default value: 'efficiency' :type effName: string :return: 2-tuple composed by a list with the names of the binned variables and a string with the name of the efficiency :rtype: list of strings, string :raise AttributeError: not found the efficiency name introduced """ #---- Checking the variables in dataset _swapDict = getVarDict( dataset ) #--- All the binned variables in the dataset datasetVarList = filter( lambda x: x.lower().find(effName) == -1, _swapDict.iterkeys() ) #--- Name of the efficiency effList = filter( lambda x: x.lower().find(effName) != -1, _swapDict.iterkeys() ) #---- Sanity check: should have only one name if len(effList) < 1: message ="""There is no efficiency variable called '%s'in the RooDataSet '%s'""" % (effName, dataset.GetName()) printError( isbinnedVar.__module__+'.'+isbinnedVar.__name__, message, AttributeError ) elif len(effList) > 1: message ="""It cannot be possible to parse the efficiency name, found '%s' in the RooDataSet '%s'\n""" % (str(effList), dataset.GetName()) message +="""Check your root file and let only one variable to contain the name '%s'""" % effName printError( isbinnedVar.__module__+'.'+isbinnedVar.__name__, message, AttributeError ) return datasetVarList, effList[0]
def graphclassname(tnp, dataname): """.. function:: graphclassname( tnp, dataname ) -> name Giving a pytnp instance and a RooDataSet name contained in it, the function returns a string which defines the graph class that RooDataSet belongs. A graph class is defined by the keys ``effType``, ``objectType`` and ``methodUsed`` :param tnp: object instance of pytnp class :type tnp: pytnp :param dataname: name of the RooDataSet :type str: string :return name: name of the graph class :rtype: string :raise UserWarning: when the RooDataSet do not belong to the pyntp instance introduced """ #-- Check dataset try: return tnp[dataname]['effType'] + '_' + tnp[dataname][ 'objectType'] + '_' + tnp[dataname]['methodUsed'] except KeyError: message = "The RooDataSet '%s' do not belong to the pyntp instance introduced" % dataname printError(graphclassname.__module__ + '.' + graphclassname.__name__, message, UserWarning)
def write(self, fileOut, vartouse): """.. method:: write( fileOut ) Create a root file with all the RooDataSets and TH2F maps of the instance. :param fileOut: name of the output root file :type fileOut: string :raise IOError: problems opening the file """ import os import ROOT f = ROOT.TFile(fileOut,'RECREATE') if f.IsZombie(): message = 'Cannot open \'%s\' file. Check your permissions' % fileOut printError( self.__module__+'.write', message, IOError ) howDatasets = 0 for name,dataSet in self.RooDataSet.iteritems(): # Use only the variables introduced by the user argset = dataSet.get() allvariables = argset.contentsString().split(',') newvariables = ROOT.RooArgSet() for var in vartouse: #Checking it is in the argset if not var in allvariables: message = "Variable '%s' is not in the RooDataSet '%s'" % ( var, dataSet.GetName()) printError( self.__module__+'.write', message, RuntimeError ) newvariables.add( argset[var] ) #And the efficiency newvariables.add( argset[self.effName] ) # The new RooDataSet newdataSet = dataSet.reduce( newvariables ) newdataSet.Write(name.replace('/','_')) try: for namehisto,histoTuple in self[name]['TH2F'].iteritems(): for histo in histoTuple: #Watch out: not use the key name because we have 3 histos histo.Write('TH2F_'+histo.GetName().replace('/','_')) howDatasets += 1 except KeyError: pass f.Close() #--- Check you have first the TH2F keys in your RooDataSet dict if howDatasets == 0: try: os.remove( fileOut ) except IOError: #Why can't you remove something you have create = pass message = "Do not stored any TH2F map. You must use 'plotEffMap' method first." printWarning( self.__module__, message )
def getVarDict(dataset, __effName='efficiency'): """.. function:: getVarDict( dataset, effName='efficiency' ) -> dict Given a RooDataSet, the function returns a dictionary whose keys are the binned variables and efficiency names and the values are a dictionary with some useful info:: { 'var1': { 'latexName': 'blaba', 'unit': 'unit', 'binN': NumberBins, 'arrayBins' : (val1,...,valN+1) }, ... } :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name :type effName: string :return: see above :rtype: dict :raise TypeError: if the dataset is not a ROOT.RooDataSet :raise AttributeError: not found the effiency name introduced """ import ROOT varinfo = {} try: arg = dataset.get() except AttributeError: message = 'The object \'%s\' is not a RooDataSet' % str(dataset) printError(getVarDict.__module__ + '.' + getVarDict.__name__, message, TypeError) #-- Get the list with the name of the variables varList = arg.contentsString().split(',') for name in varList: if isinstance(arg[name], ROOT.RooCategory): continue binN, arrayBinPointer = getBinning(arg[name]) # Some memory problems with the Double array--> to tuple arrayBin = tuple([arrayBinPointer[i] for i in xrange(binN + 1)]) varinfo[name] = { 'unit': arg[name].getUnit(), 'latexName': arg[name].getTitle().Data(), \ 'binN' : binN, 'arrayBins': arrayBin } #Note: some TString instance--> normalizing to str with Data method try: effName = filter(lambda x: x.lower().find(__effName) != -1, [i for i in varinfo.iterkeys()])[0] except IndexError: message = 'The RooDataSet \'%s\' does not have the \'%s\' variable as efficiency' % ( dataset.GetName(), __effName) printError(getVarDict.__module__ + '.' + getVarDict.__name__, message, AttributeError) varinfo[effName]['latexName'] = '#varepsilon' return varinfo
def tableEff(dataset, effName='efficiency'): """ tableEff( dataset, 'effName' ) --> tableDict Giving a RooDataSet, the function returns a dictionary where every key is the 'variables' of the RooDataSet. Each value is a list of tuples (var, varErrorLo, varErrorHigh): :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name :type effName: string :return: dict with efficiency values and binned variables :rtype: dict The output dictionary looks like:: { 'efficiency': [ (eff1,effLo1,effHi1), (eff2,effLo2,effHi2), ... ], 'var_x' : [ (varX1,xLo1,xHi1), (varX2,xLo2,xHi2), .... ], 'var_y' : [ (varY1,yLo1,yHi1), (varY2,yLo2,yHi2), .... ], ... } .. note:: There is another version to extract the table, see the function :func:`listTableEff`, a little more efficient than this one """ #--- Getting variables from dataset, note that if dataset is not a RooDataSet, #--- getVarDict raise an AttributeError exception _swapDict = getVarDict(dataset) datasetVarList = [i for i in _swapDict.iterkeys()] #--- Is efficiency in dataset? if not effName in datasetVarList: message = 'Do not found \'%s\' as the name of the efficiency in the dataset \'%s\'' % ( effName, dataSet.GetName()) printError(tableEff.__module__ + '.' + tableEff.__name__, message, KeyError) #--- Extract the RooArgSet (container of variables) argset = dataset.get() #--- Output table dictionary _table = dict([(var, []) for var in _swapDict.iterkeys()]) #--- Looping all the 'events' for ev in xrange(dataset.numEntries()): #--- event dataset.get(ev) for varName, valueList in _table.iteritems(): variable = argset[varName] valueList.append( (variable.getVal(), variable.getVal() + variable.getErrorLo(), variable.getVal() + variable.getErrorHi())) #-- In principle, I don't have to control errors: getVarDict is coherent with dataset.get, the same variables must #-- exist return _table
def getVarDict( dataset, __effName='efficiency' ): """.. function:: getVarDict( dataset, effName='efficiency' ) -> dict Given a RooDataSet, the function returns a dictionary whose keys are the binned variables and efficiency names and the values are a dictionary with some useful info:: { 'var1': { 'latexName': 'blaba', 'unit': 'unit', 'binN': NumberBins, 'arrayBins' : (val1,...,valN+1) }, ... } :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name :type effName: string :return: see above :rtype: dict :raise TypeError: if the dataset is not a ROOT.RooDataSet :raise AttributeError: not found the effiency name introduced """ import ROOT varinfo = {} try: arg = dataset.get() except AttributeError: message = 'The object \'%s\' is not a RooDataSet' % str(dataset) printError( getVarDict.__module__+'.'+getVarDict.__name__, message, TypeError ) #-- Get the list with the name of the variables varList = arg.contentsString().split(',') for name in varList: if isinstance(arg[name],ROOT.RooCategory): continue binN, arrayBinPointer = getBinning( arg[name] ) # Some memory problems with the Double array--> to tuple arrayBin = tuple( [ arrayBinPointer[i] for i in xrange(binN+1) ] ) varinfo[name] = { 'unit': arg[name].getUnit(), 'latexName': arg[name].getTitle().Data(), \ 'binN' : binN, 'arrayBins': arrayBin } #Note: some TString instance--> normalizing to str with Data method try: effName = filter( lambda x: x.lower().find(__effName) != -1, [i for i in varinfo.iterkeys()] )[0] except IndexError: message = 'The RooDataSet \'%s\' does not have the \'%s\' variable as efficiency' % (dataset.GetName(), __effName) printError( getVarDict.__module__+'.'+getVarDict.__name__, message, AttributeError ) varinfo[effName]['latexName'] = '#varepsilon' return varinfo
def tableEff( dataset, effName = 'efficiency' ): """ tableEff( dataset, 'effName' ) --> tableDict Giving a RooDataSet, the function returns a dictionary where every key is the 'variables' of the RooDataSet. Each value is a list of tuples (var, varErrorLo, varErrorHigh): :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name :type effName: string :return: dict with efficiency values and binned variables :rtype: dict The output dictionary looks like:: { 'efficiency': [ (eff1,effLo1,effHi1), (eff2,effLo2,effHi2), ... ], 'var_x' : [ (varX1,xLo1,xHi1), (varX2,xLo2,xHi2), .... ], 'var_y' : [ (varY1,yLo1,yHi1), (varY2,yLo2,yHi2), .... ], ... } .. note:: There is another version to extract the table, see the function :func:`listTableEff`, a little more efficient than this one """ #--- Getting variables from dataset, note that if dataset is not a RooDataSet, #--- getVarDict raise an AttributeError exception _swapDict = getVarDict( dataset ) datasetVarList = [ i for i in _swapDict.iterkeys() ] #--- Is efficiency in dataset? if not effName in datasetVarList: message = 'Do not found \'%s\' as the name of the efficiency in the dataset \'%s\'' % (effName,dataSet.GetName()) printError( tableEff.__module__+'.'+tableEff.__name__, message, KeyError ) #--- Extract the RooArgSet (container of variables) argset = dataset.get() #--- Output table dictionary _table = dict( [ (var, []) for var in _swapDict.iterkeys() ] ) #--- Looping all the 'events' for ev in xrange( dataset.numEntries() ): #--- event dataset.get(ev) for varName, valueList in _table.iteritems(): variable = argset[varName] valueList.append( (variable.getVal(), variable.getVal()+variable.getErrorLo(), variable.getVal()+variable.getErrorHi()) ) #-- In principle, I don't have to control errors: getVarDict is coherent with dataset.get, the same variables must #-- exist return _table
def __check_keywords__(self, keywords): """.. method:: __check_keywords__( keywords ) Checks the keywords passed to the constructor :raise KeyError: invalid keyword :raise TypeError: invalid format of ``variables`` """ #FIXME : ojo, dataset ha quedado huerfana... #--- Keys valid valid_keys = [ 'resonance', 'dataset', 'mcTrue', 'variables', 'effName', 'configfile' ] #---- Some initializations using user inputs ---# dataset = '' for i in keywords.keys(): if not i in valid_keys: message = 'Invalid instance of pytnp: you can not use %s as key argument, ' % i message += 'key arguments valids are \'%s\'' % str(valid_keys) # print help(self.__init__) printError( self.__check_keywords__.__module__ + '.___check_keywords__', message, KeyError) #---Checking the correct format and storing #---the names provided by the user elif i == 'resonance': #Message to be sended if the value is not a tuple message ='Not valid resonance=%s key; resonance key must be a tuple containing (\'name\',\'nameInLatex\')' \ % str(keywords['resonance']) if len(keywords['resonance']) != 2: printError(self.__module__, message, KeyError) else: #Checking the tuple format is (name, nameInLatex) if keywords['resonance'][0].find('#') != -1 \ or keywords['resonance'][0].find('{') != -1 : printError(self.__module__, message, KeyError) #--- Storing resonance provided by user self.resonance = keywords['resonance'][0] self.resLatex = keywords['resonance'][1] elif i == 'effName': self.effName = keywords[i] elif i == 'dataset': dataset = keywords[i] elif i == 'variables': #-- Sanity checks if not isinstance(keywords[i], list): message = 'Not valid \'variables=%s\' key; must be a list containing n variables names' % str( keywords[i]) printError(self.__module__, message, TypeError) else: self.userVariables = [var for var in keywords[i]] elif i == 'configfile': self.configfile = keywords[i] #elif i == 'mcTrue' --> TO BE DEPRECATED OR ACTIVATED? return dataset
def isEffNoNull(dataset, effName='efficiency'): """.. function:: isEffNoNull( dataset, effName='efficiency' ) -> bool Given a dataset, the function evaluates if the variable effName has any value different from zero returning True, otherwise return False. :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name :type effName: string :return: True if the dataset contains at least one efficiency value different zero :rtype: bool :raise AttributeError: not found the effiency name introduced """ #-- Checking efficiency is there isEff = isVar(dataset, effName) if not isEff: message = """There is no efficiency variable called '%s'in the RooDataSet '%s'""" % ( effName, dataset.GetName()) printError(isEffNoNull.__module__ + '.' + isEffNoNull.__name__, message, AttributeError) #_swapDict = getVarDict( dataset ) #effList = filter( lambda x: x.lower().find(effName) != -1, _swapDict.iterkeys() ) #if len(effList) < 1: # message ="""There is no efficiency variable called '%s'in the RooDataSet '%s'""" % (effName, dataset.GetName()) # printError( isEffNoNull.__module__+'.'+isEffNoNull.__name__, message, AttributeError ) #elif len(effList) > 1: # message ="""It cannot be possible to parse the efficiency name, found '%s'in the RooDataSet '%s'\n""" % (str(effList), dataset.GetName()) # message +="""Check your root file and let only one variable to contain the name '%s'""" % effName # printError( isEffNoNull.__module__+'.'+isEffNoNull.__name__, message, AttributeError ) _table = tableEff(dataset, effName) # FIXME: Comparation between double and 0.0 -- better abs(var) < 1e-10, for example zeroList = filter( lambda (var, varLo, varHi): var == 0.0 and varLo == 0.0 and varHi == 0.0, _table[effName]) if len(zeroList) == len(_table[effName]): return False else: return True
def write(self, fileOut): """.. method:: write( fileOut ) Create a root file with all the RooDataSets and TH2F maps of the instance. :param fileOut: name of the output root file :type fileOut: string :raise IOError: problems opening the file """ import os import ROOT f = ROOT.TFile(fileOut, 'RECREATE') if f.IsZombie(): message = 'Cannot open \'%s\' file. Check your permissions' % fileOut printError(self.__module__ + '.write', message, IOError) howDatasets = 0 for name, dataSet in self.RooDataSet.iteritems(): dataSet.Write(name.replace('/', '_')) try: for namehisto, histoTuple in self[name]['TH2F'].iteritems(): for histo in histoTuple: #Watch out: not use the key name because we have 3 histos histo.Write('TH2F_' + histo.GetName().replace('/', '_')) howDatasets += 1 except KeyError: pass f.Close() #--- Check you have first the TH2F keys in your RooDataSet dict if howDatasets == 0: try: os.remove(fileOut) except IOError: #Why can't you remove something you have create = pass message = "Do not stored any TH2F map. You must use 'plotEffMap' method first." printWarning(self.__module__, message)
def write(self, fileOut): """.. method:: write( fileOut ) Create a root file with all the RooDataSets and TH2F maps of the instance. :param fileOut: name of the output root file :type fileOut: string :raise IOError: problems opening the file """ import os import ROOT f = ROOT.TFile(fileOut,'RECREATE') if f.IsZombie(): message = 'Cannot open \'%s\' file. Check your permissions' % fileOut printError( self.__module__+'.write', message, IOError ) howDatasets = 0 for name,dataSet in self.RooDataSet.iteritems(): dataSet.Write(name.replace('/','_')) try: for namehisto,histoTuple in self[name]['TH2F'].iteritems(): for histo in histoTuple: #Watch out: not use the key name because we have 3 histos histo.Write('TH2F_'+histo.GetName().replace('/','_')) howDatasets += 1 except KeyError: pass f.Close() #--- Check you have first the TH2F keys in your RooDataSet dict if howDatasets == 0: try: os.remove( fileOut ) except IOError: #Why can't you remove something you have create = pass message = "Do not stored any TH2F map. You must use 'plotEffMap' method first." printWarning( self.__module__, message )
def __check_keywords__(self, keywords ): """.. method:: __check_keywords__( keywords ) Checks the keywords passed to the constructor :raise KeyError: invalid keyword :raise TypeError: invalid format of ``variables`` """ #FIXME : ojo, dataset ha quedado huerfana... #--- Keys valid valid_keys = ['resonance', 'dataset', 'mcTrue','variables', 'effName', 'configfile' ] #---- Some initializations using user inputs ---# dataset = '' for i in keywords.keys(): if not i in valid_keys: message = 'Invalid instance of pytnp: you can not use %s as key argument, ' % i message += 'key arguments valids are \'%s\'' % str(valid_keys) # print help(self.__init__) printError( self.__check_keywords__.__module__+'.___check_keywords__', message, KeyError ) #---Checking the correct format and storing #---the names provided by the user elif i == 'resonance': #Message to be sended if the value is not a tuple message ='Not valid resonance=%s key; resonance key must be a tuple containing (\'name\',\'nameInLatex\')' \ % str(keywords['resonance']) if len(keywords['resonance']) != 2: printError( self.__module__, message, KeyError ) else: #Checking the tuple format is (name, nameInLatex) if keywords['resonance'][0].find('#') != -1 \ or keywords['resonance'][0].find('{') != -1 : printError( self.__module__, message, KeyError ) #--- Storing resonance provided by user self.resonance = keywords['resonance'][0] self.resLatex = keywords['resonance'][1] elif i == 'effName': self.effName = keywords[i] elif i == 'dataset': dataset = keywords[i] elif i == 'variables': #-- Sanity checks if not isinstance(keywords[i], list): message ='Not valid \'variables=%s\' key; must be a list containing n variables names' % str(keywords[i]) printError( self.__module__, message, TypeError ) else: self.userVariables = [ var for var in keywords[i] ] elif i == 'configfile': self.configfile = keywords[i] #elif i == 'mcTrue' --> TO BE DEPRECATED OR ACTIVATED? return dataset
def isEffNoNull( dataset, effName='efficiency' ): """.. function:: isEffNoNull( dataset, effName='efficiency' ) -> bool Given a dataset, the function evaluates if the variable effName has any value different from zero returning True, otherwise return False. :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name :type effName: string :return: True if the dataset contains at least one efficiency value different zero :rtype: bool :raise AttributeError: not found the effiency name introduced """ #-- Checking efficiency is there isEff = isVar( dataset, effName ) if not isEff: message ="""There is no efficiency variable called '%s'in the RooDataSet '%s'""" % (effName, dataset.GetName()) printError( isEffNoNull.__module__+'.'+isEffNoNull.__name__, message, AttributeError ) #_swapDict = getVarDict( dataset ) #effList = filter( lambda x: x.lower().find(effName) != -1, _swapDict.iterkeys() ) #if len(effList) < 1: # message ="""There is no efficiency variable called '%s'in the RooDataSet '%s'""" % (effName, dataset.GetName()) # printError( isEffNoNull.__module__+'.'+isEffNoNull.__name__, message, AttributeError ) #elif len(effList) > 1: # message ="""It cannot be possible to parse the efficiency name, found '%s'in the RooDataSet '%s'\n""" % (str(effList), dataset.GetName()) # message +="""Check your root file and let only one variable to contain the name '%s'""" % effName # printError( isEffNoNull.__module__+'.'+isEffNoNull.__name__, message, AttributeError ) _table = tableEff( dataset, effName ) # FIXME: Comparation between double and 0.0 -- better abs(var) < 1e-10, for example zeroList = filter( lambda (var,varLo,varHi): var == 0.0 and varLo == 0.0 and varHi == 0.0, _table[effName] ) if len(zeroList) == len(_table[effName]): return False else: return True
def getVarNames(dataset, effName='efficiency'): """.. function:: getVarNames( dataset, effName='efficiency' ) -> [ binnedvar1,...], effName From a dataset extract which binned variables have and returns the list of the variable's names and the efficiency name :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name. Default value: 'efficiency' :type effName: string :return: 2-tuple composed by a list with the names of the binned variables and a string with the name of the efficiency :rtype: list of strings, string :raise AttributeError: not found the efficiency name introduced """ #---- Checking the variables in dataset _swapDict = getVarDict(dataset) #--- All the binned variables in the dataset datasetVarList = filter(lambda x: x.lower().find(effName) == -1, _swapDict.iterkeys()) #--- Name of the efficiency effList = filter(lambda x: x.lower().find(effName) != -1, _swapDict.iterkeys()) #---- Sanity check: should have only one name if len(effList) < 1: message = """There is no efficiency variable called '%s'in the RooDataSet '%s'""" % ( effName, dataset.GetName()) printError(isbinnedVar.__module__ + '.' + isbinnedVar.__name__, message, AttributeError) elif len(effList) > 1: message = """It cannot be possible to parse the efficiency name, found '%s' in the RooDataSet '%s'\n""" % ( str(effList), dataset.GetName()) message += """Check your root file and let only one variable to contain the name '%s'""" % effName printError(isbinnedVar.__module__ + '.' + isbinnedVar.__name__, message, AttributeError) return datasetVarList, effList[0]
def graphclassname( tnp, dataname ): """.. function:: graphclassname( tnp, dataname ) -> name Giving a pytnp instance and a RooDataSet name contained in it, the function returns a string which defines the graph class that RooDataSet belongs. A graph class is defined by the keys ``effType``, ``objectType`` and ``methodUsed`` :param tnp: object instance of pytnp class :type tnp: pytnp :param dataname: name of the RooDataSet :type str: string :return name: name of the graph class :rtype: string :raise UserWarning: when the RooDataSet do not belong to the pyntp instance introduced """ #-- Check dataset try: return tnp[dataname]['effType']+'_'+tnp[dataname]['objectType']+'_'+tnp[dataname]['methodUsed'] except KeyError: message = "The RooDataSet '%s' do not belong to the pyntp instance introduced" % dataname printError( graphclassname.__module__+'.'+graphclassname.__name__, message, UserWarning )
def getEff( dataSet, input_effName='efficiency', **keywords): """.. function:: getEff(dataset, effName='efficiency', var1=value[,var2=value2, ...]) -> eff, effErrorLow, effErrorHigh (,dict) Giving a binned variables returns the efficiency which corresponds to those values. There is 2 output signatures depending of the argument variables introduced; if the variables are the exhausted set of the RooDataSet, the output will be a tuple of efficiency (CASE 1). Otherwise if the input variables don't cover all the RooDataSet binned variables, the output will be the efficiency tuple plus a dictionary which the names of the resting variables as keys and the tuples of their bin values as values (CASE 2). :param dataset: dataset :type dataset: ROOT.RooDataSet :param input_effName: efficiency name :type input_effName: string :keyword var: var=value :rtype var: object :return: tuple with efficiency values (and a dictionary) :rtype: float,float,float(,dict) :raise UserWarning: if do not introduce at least one variable as keyword """ #---- Checking the variables in dataset _swapDict = getVarDict( dataSet ) #--- All the binned variables in the dataset datasetVarList, effName = getVarNames( dataSet, input_effName ) varList = [] nameVarList = [] for var,value in keywords.iteritems(): if not isbinnedVar( dataSet, var, effName, warning=True ): raise KeyError varList.append( (var,value) ) nameVarList.append( var ) #---- Sanity check if len(nameVarList) < 1: message ="""You must introduce at least one variable""" printError( getEff.__module__+'.'+getEff.__name__, message, UserWarning ) #--- Variables the user don't ask. This is the case when the user #--- wants a list of efficiency given a fixed value of one variable noAskVar = filter( lambda x: x not in nameVarList, datasetVarList ) listReturn = False effVarList = None if len(noAskVar) != 0: listReturn = True effVarList = [] #---- Sanity check if len( varList ) > len(datasetVarList):#FIXME---> can be more than 2 variables... message ="""You are using more variables than in dataset '%s'""" % dataSet.GetName() printError(getEff.__module__+'.'+getEff.__name__, message, AttributeError ) #-- Get the table of efficiencies tableList = listTableEff( dataSet ) for valDict in tableList: #-- From the list of the variables we want the efficiencies (varList), put the value inside #--- of the ranges (valDict[var][1:][i]) in the list fList = filter( lambda (var,value): valDict[var][1:][0] <= value and valDict[var][1:][1] > value , varList ) #-- If our variables are all the variables available, we have 1-to-1 correspondence #--- with a efficiency value-> return this value if not listReturn and len(fList) == len( varList ): return valDict[effName] #-- If our variables are less than the variables available, we're going to return #--- a list with the (restOfvariables,efficiencies) in order to recover the 1-to-1 correspondence elif listReturn and len(fList) != 0: restVarDict = dict( [ (_name, valDict[_name]) for _name in noAskVar ] ) effVarList.append( (valDict[effName],restVarDict) ) if listReturn and len(effVarList) > 0 : #--output: (tuple,dict) where tuple is efficiency values and dict have the #--- names of the variables as keys and tuple as values return effVarList message = '\033[1;34mpytnp.getEff Info: There is no bin where live ' for var,val in varList: message += var+'='+str(val)+', ' message = message[:-2]+'\033[1;m' print message # FIXME: Strange behaviour with version 3_6_1_patch4 (really with the RooFit (3.12 ??) included in this version: # The values of the listTableEff do not fill correctly. All the dictionary is filled of the same value (the last found value) # Still have this problem with RooFit 3.13, root-v5.27, python 2.6 ... return None
def __extract__(self, Dir, dictObjects, regexp): """.. method:: __extract__(dir, dictT, regexp) -> dict Recursive function to extract from a 'tag and probe' ROOT file all the relevant information. Returning a dictionary which stores all (TCanvas, RooFitResult,) RooDataSet (and RooPlot) with matches with regexp:: {# 'TCanvas': # {'directory/subdirectory/.../nameOfTCanvas' : <ROOT.TCanvas object>, # ... # }, # 'RooFitResult' : # { 'directory/subdirectory/.../nameOfRooFitResult': <ROOT.RooFitResult object>, # ... # }, 'RooDataSet': { 'directory/subdirectory/.../nameOfRooDataSet': <ROOT.RooDataSet object>, ... }, } :param dir: root TDirectory (note TFile inherit from TDirectory) where to extract :type dir: ROOT.TDirectory :param dictT: directory where to store the information extracted :type dictT: dict :param regexp: ?? (TO BE CHECKED) :type regexp: string :return: dictionary (see above) :rtype: dict :raise AttributeError: the root file is not an standard T&P .. warning:: DEPRECATED TCanvas, RooFitResult and RooPlot storage """ if pytnp.counter%100 == 0: print '.', sys.stdout.flush() # FIXED------------------------------------------------- #_dirSave = ROOT.gDirectory #Python --> _dirSave is a reference to ROOT.gDirectory, # so whenever gDirectory changes, _dirSaves # changes too. I can't use the gDirectory #------------------------------------------------------- _dirSave = Dir #Storing the father->child info try: listOfKeys = Dir.GetListOfKeys() ##-- Checking that is a Tag and Probe fit ## file. IF it is not, then we find ## some not expected TKeys (as TTree, etc.. ) except AttributeError: message = """The root file is not an standard T&P fit file""" printError( self.__module__, message, AttributeError ) for key in Dir.GetListOfKeys(): className = key.GetClassName() if key.IsFolder(): ##-- Extracting the Folder from Dir _subdir = Dir.Get(key.GetName()) ##-- And browsing inside recursively pytnp.counter += 1 dictObjects = self.__extract__(_subdir,dictObjects,regexp) ##-- To avoid segmentation faults, we need to return ## at the original directory in order to continue ## extracting subdirectories (or elements of the directory) _dirSave.cd() ##-- Storing in the dictionary the interesting objects elif className in self.classNames: pytnp.counter += 1 #--Skipping if not match (Note that anything.find('') gives 0 if (Dir.GetPath()+key.GetName()).find(regexp) == -1: continue try: #Asuming unique id object-->complet path dictObjects[className][Dir.GetPath().split(':/')[1]+'/'+key.GetName()] = Dir.Get(key.GetName()) except KeyError: dictObjects[className] = { Dir.GetPath().split(':/')[1]+'/'+key.GetName(): Dir.Get(key.GetName()) } return dictObjects
def __getType__(self, name, structure): """.. method:: __getType__( 'RooDataSet name', dictionary ) -> dictionary Build a dictionary where the key is the pathname (in standard T&P format) and the values are also dictionaries storing relevant info of the dataset. :raise ValueError: file root format incorrect :raise AttributeError: Misuse of configuration file """ import re from management import parserConfig #-- Dictionary to store structure[name] = { 'effType': {}, 'objectType': {}, 'methodUsed': {}, 'isMC' : {} } #-- Extracting pathname = name.split('/') if len(pathname) != 3: #-- The storage format is not in T6P standard message = 'The format of the \'%s\' file is not in T&P standard.' % self.__fileroot__.GetName() printError( self.__module__, message, ValueError ) effType = pathname[0] objectType = pathname[1] methodUsed = pathname[2] #-- Mapping #--- Check and put values provided by the user try: #--- If not enter config, self.configfile is None and #--- parserConfig raise a TypeError exception. #--- If is not there some key, the AttributeError is raised try: tupleAttr = parserConfig( self.configfile, self.resonance+'::'+name ) except AttributeError: Message = "If the error above is related with the identifier:\n" Message += "Coherence broken between configuration file and 'pytnp' instanciation\n" Message += "Check you have a object called '%s' in your configuration file" % self.resonance printError( self.__module__+'.pytnp', Message, AttributeError ) #--- If nothing the tupleAttr is None so NameError exception too structure[name]['effType'] = tupleAttr[0] structure[name]['objectType'] = tupleAttr[1] structure[name]['isMC'] = tupleAttr[2] #FIXME: To be implemented #try: # structure[name]['legend'] = tupleAttr[3] #except IndexError: # pass except (NameError,TypeError): #---- Type of efficiency if effType == 'histoTrigger': structure[name]['effType'] = 'Trigger' elif effType == 'histoMuFromTk': structure[name]['effType'] = 'MuonID' else: structure[name]['effType'] = 'unknown' #---- Type of efficiency structure[name]['objectType'] = objectType.split('_')[0] #---- Is mcTrue regexp = re.compile( '\S*_(?P<mc>mcTrue)' ) try: # Check if it mcTrue regexp.search( objectType ).group( 'mc' ) structure[name]['isMC'] = 1 except AttributeError: structure[name]['isMC'] = 0 #---- Method Used structure[name]['methodUsed'] = methodUsed return structure
def __init__(self, filerootName, **keywords): """.. class:: pytnp(filerootName [, resonance=(id,nameLatex), effName='efficiency_name', variables=[varname1,varname2,..], configfile=file, dataset=type, mcTrue=true ] ) Class encapsulating the contents of a Tag and Probe root file (generated from CMSSW T&P package). The root file must have a two-level directory hierarchy, where the RooDataSet (whose actually contains the information) is in the bottom. The pytnp class is based in the RooDataSet, a instance of this class returns a dictionary (self) whose keys are the names (absolute path) of the RooDataSet, the values are dictionaries themselves with keys storing useful information of the RooDataSet. A generic example is shown:: { 'firstlevel/secondlevel/dataset_eff': { 'effType': efficiency_type 'binnedVar': binnedvardict 'methodUsed': method_used 'variables': vardict 'dataset': roodataset 'isMC': 0|1 'eff': efficiencyname 'objectType': object_type }, ...., } where ``firstlevel/secondlevel/dataset_eff`` is the name of the dataset, the dictionary values have a ``efficiency_type``, ``method_used`` and ``object_type`` strings which they going to be extracted from the root file or from the configuration file provided by the user. The keys ``binnedVar`` and ``variables`` are dictionaries which contains useful information for the binned variables and all the variables (respectively) in the RooDataSet (see :mod:`pytnp.libpytnp.tnputils.getVarDict`). The ``dataset`` key contains the RooDataSet object itself. The ``configfile`` keyword can be used to change the values found by the constructor when parsing the root file. An example of configuration file:: DataNames = { # root file name: TnP_Z_DATA_TriggerFromMu_Trigger_ProbeMu11_Eta_Fit.root 'ProbeMu11_Eta_Fit': ( "Z#rightarrow#mu#mu, HLTMu11 trigger",'Z_11' ), # root file is: TnP_Z_DATA_TriggerFromMu_Trigger_ProbeMu9_Eta_Fit.root 'ProbeMu9_Eta_Fit' : ("Z#rightarrow#mu#mu, HLTMu9 trigger", 'Z_9' ), } #Attributes Z_11 = { 'tpTree/PASSING_all/fit_eff': ( 'HLT_trigger' , 'Glb_muons' , 0 ), 'tpTree/PASSING_all/cnt_eff': ( 'HLT_trigger' , 'Glb_muons' , 1 ), } Z_9 = { 'tpTree/PASSING_all/fit_eff': ( 'HLT_trigger' , 'Glb_muons' , 0 ), 'tpTree/PASSING_all/cnt_eff': ( 'HLT_trigger' , 'Glb_muons' , 1 ), } The ``DataNames`` is a mandatory dictionary. It is used to identify a root file with a ``pytnpname``, the keys are expressions which can describe the name of the root file (using the ``find`` method of a string) and the values are tuples of strings with the latex name (to be put in the legends) and the ``pytnpname``. Using this identifier it possible to construct another dictionaries with the informationn of each dataset (or some dataset) in the root file. The names of the dictionary objects must be the same as the ``pytnpname`` defined before; this dictionaries have as keys the name of the datasets to be modified and the values are tuples with the ``effType``, ``objectType`` and ``isMC`` attributes. :param filerootName: name of the root file :type filerootName: string :keyword resonance: assigns a (pytnpname,latexName) :type resonance: (strings,string) :keyword effName: Providing the efficiency name finded inside the RooDataSets. Otherwise, we assume the name ``efficiency``. CAVEAT: all the RooDataSet MUST have the same efficiency name. :type effName: string :keyword variables: Binned variables considered :type variables: list of strings :keyword configfile: the configuration file to be used (if any) :type configfile: string :keyword dataset: Store only dataset matching this effType (TO BE DEPRECATED) :type dataset: string :keyword mcTrue: Setting True, it stores the mcTrue info and will associate each dataset with their mcTrue dataset. (TO BE DEPRECATED) :type mcTrue: bool :raise IOError: Invalid root file name :raise TypeError: Invalid format of the root file (do not have the proper directory structure) :raise KeyError: Invalid name of efficiency, not found in the dataset :raise ValueError: Not found the binned variables introduced """ import ROOT from getresname import getResName from tnputils import getVarDict, isEffNoNull #--- Checking the keys dictionary passed ----# dataset = self.__check_keywords__( keywords ) #FIXMEE #--- Extracting the members print 'Extracting info from '+filerootName+'.', sys.stdout.flush() fileroot = ROOT.TFile(filerootName) #--- Checking the extraction was fine if fileroot.IsZombie(): message = 'Invalid root dataset or root dataset not found, \'%s\'' % filerootName printError( self.__module__, message, IOError ) #--- Extract all the objects of the rootfile and put them as attributes of the instance self.__dict__ = self.__extract__(fileroot, self.__dict__, dataset) #--- Checking everything was fine if not 'RooDataSet' in self.__dict__.keys(): message = """The root file is not an standard T&P fit file""" printError( self.__module, message, TypeError ) print '' self.__fileroot__ = fileroot #-- Get the resonances names #----- If they had not been provided by the user if not self.resonance: self.resonance, self.resLatex = getResName( filerootName ) #--- Encapsulate the hierarchy of the directories: for name in self.__dict__['RooDataSet'].iterkeys(): self.__attrDict__ = self.__getType__(name,self.__attrDict__) #--- Associate the names of the mcTrue and counting MC True to a fit_eff #----- Getting all the MC True RooDataSets: [ (name,dictionary),...] mcTrueData = filter( lambda x: x[1]['isMC'] == 1, self.__attrDict__.iteritems() ) #---- Loop over all RooDataSets fitted but not MC for Name,Dict in filter( lambda x: x[1]['isMC'] == 0 and x[1]['methodUsed'] == 'fit_eff', self.__attrDict__.iteritems() ): #---- Getting the parter to mcTrueData: all with the same objectType and effType #------ Can be cnt, fit_eff and sbs partner = filter( lambda x: x[1]['objectType'] == Dict['objectType'] and x[1]['effType'] == Dict['effType'], \ mcTrueData ) #--- Looping over the MC RooDataSet which is the same efficiency type and category as the fitted RooDataSets for mcName, mcDict in partner: #---- Only want the reference to fit_eff and cnt_eff mcTrue if mcDict['methodUsed'] == 'fit_eff' or mcDict['methodUsed'] == 'cnt_eff' : try: self.__attrDict__[Name]['refMC'][ mcDict['methodUsed'] ] = mcName except KeyError: self.__attrDict__[Name]['refMC'] = { mcDict['methodUsed'] : mcName } _prov = set() #--- The dictionary itself contains only the RooDataSets #todelete = [] for name, dataSet in self.__dict__['RooDataSet'].iteritems(): #try: self[name] = self.__attrDict__[name] # To get also the no fit_eff --> Except sbs (not implemented yet) and cnt no MC #except KeyError: # self[name] = self.__getType__(name,{})[name] #--- Skipping sbs, cnt no MC #**if self.__attrDict__[name]['methodUsed'] == 'sbs_eff': #or \ # ( self.__attrDict__[name]['methodUsed'] == 'cnt_eff' and self.__attrDict__[name]['isMC'] == 0): #** self.pop(name) #** todelete.append( name ) #** continue self[name]['dataset'] = dataSet #--To store the categories we have _prov.add( self[name]['objectType'] ) #--- We are not interested about the MC, only in cnt and fit_eff #**map( lambda (Name,Dumm): self.__attrDict__.pop(Name), mcTrueData ) #--- We are not interested about the sbs and cnt not MC #**map( lambda y: self.__attrDict__.pop( y[0] ), filter( lambda x: x[1]['isMC'] == 0 and x[1]['methodUsed'] != 'fit_eff',\ # self.__attrDict__.iteritems() ) ) #-- Storing the categories we have self.categories = list(_prov) #--- Don-'t forget delete also in RooDataSet attribute #for name in todelete: # self.RooDataSet.pop( name ) #----- Variables, binned, efficiency, user introduced, ... #--- The list will contain those dataset which don't have anyone of the variables entered #--- by the user (in case the user enter someone) and the datasets will be removed deleteDataset = set([]) #--- Getting the variables names of the RooDataSet for name, dataset in self.RooDataSet.iteritems(): self[name]['variables'] = getVarDict(dataset) #--- Check that efficiency is in there if not self.effName in self[name]['variables'].keys(): try: message = """The efficiency name introduce '%s' is not in the '%s' RooDataSet.\n""" % (keywords['effName'], name ) message += """I have these variables located:""" except KeyError: message = """The efficiency name per default 'efficiency' is not in the '%s' RooDataSet.\n""" message +="""You should introduced the name when instance the class =>"""\ """ a = pytnp( 'filename.root', effName='whatever' )\n"""\ """I have these variables located:""" message += ' ' for i in self[name]['variables']: message += i+', ' message = message[:-2] message += '\n\033[1;33m CAVEAT: The efficiency name \033[1;m\033[1;39mMUST\033[1;m\033[1;33m'\ 'have the same name for all the RooDataSets in the rootfile\033[1;m' printError( self.__module__+'.pytnp', message, KeyError ) #--- Check the variables introduced by the user are there and #------ Setting the binned Variables: extract efficiencies from last list message = '' _warningPrint = False _havetodelete = False lostVar = '' self[name]['binnedVar'] = {} if len(self.userVariables) != 0 : for var in self.userVariables: if not var in self[name]['variables']: lostVar += var+', ' _warningPrint = True _havetodelete = True else: self[name]['binnedVar'][var] = self[name]['variables'][var] if _havetodelete: deleteDataset.add( name ) if _warningPrint: lostVar = lostVar[:-2] message += """Variable '%s' is not in the '%s' RooDataSet. Skipping it... """ % ( lostVar,name) printWarning( self.__module__+'.pytnp', message ) else: #The user didn't introduce binned variables, I take everyone self[name]['binnedVar'] = dict([ (var, self[name]['variables'][var]) \ for var in filter( lambda x: x.lower().find(self.effName) == -1, self[name]['variables'] ) ]) #if _errorPrint: # message += """ ----> I found: """ # for var in self[name]['variables']: # message += var+', ' # message = message[:-2] # printError( self.__module__, message, UserWarning ) self[name]['eff'] = filter( lambda x: x.lower().find(self.effName) != -1, self[name]['variables'] )[0] for _dataout in deleteDataset: self.pop( _dataout ) self.RooDataSet.pop( _dataout ) self.__attrDict__.pop( _dataout ) #-- Something wrong if we pop out all the datasets we had if len(self) == 0: message = """There is no RooDataSet that fulfill the binned variables introduced""" printError( self.__module__, message, ValueError ) #--- Extracting those RooDataSet which have null values of efficiency _todelete = [] for name, _datasetObject in self.RooDataSet.iteritems(): if not isEffNoNull( _datasetObject, self.effName ): _todelete.append( name ) del _datasetObject message = "The RooDataSet '%s' have all '%s' values null. Skipping the storage..." % (name, self.effName) printWarning( self.__module__+'.pytnp', message ) map( lambda name: self.pop( name ), _todelete ) map( lambda name: self.__attrDict__.pop( name ), _todelete ) for __attr in self.classNames: map( lambda name: self.__getattribute__( __attr ).pop( name ) , _todelete )
def newtableLatex( dataset, effName, varX, varY, **keyword ): """.. function tableLatex( dataset, effName, 'var_column', 'var_row', [outfile='name.tex', varXname='latex name', varYname='latex name'] ) -> dict Giving a RooDataSet and two variables, the function returns a table in latex format. If enters the keyword 'outfile' also the table will put it into the file. (The keyword var is a list with the name of the variables the user want to dump. TODO, not yet implemented) :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name :type effName: string :param varX: the name of the variable you want to be as column :rtype varX: string :param varY: the name of the variable you want to be as row .. seealso:: :func:`tableLatex` """ #TODO: The keyword var is a list with the name of the variables the user want to dump. #TODO: CHECK IF WORKS CORRECTLY message = "Use this function with caution! Still in development.\n Use instead the tableLatex function" printWarning( newtableLatex, message ) #---- Checking the variables in dataset varDict = getVarDict( dataset ) #--- All the binned variables in the dataset datasetVarList = filter( lambda x: x.lower().find(effName) == -1, varDict.iterkeys() ) effList = filter( lambda x: x.lower().find(effName) != -1, varDict.iterkeys() ) #---- Sanity check if len(effList) != 1: message ="""The RooDataSet '%s' does not contain a variable called '%s' as efficiency"""\ % ( dataset.GetName(), effName ) printError( tableLatex.__module__+'.'+tableLatex.__name__, message, AttributeError ) #---- Variables are there? for var in [ varX, varY ]: if var not in datasetVarList: message ="""The RooDataSet '%s' does not contain a binned variable called '%s'"""\ % ( dataset.GetName(), var ) printError( tableLatex.__module__+'.'+tableLatex.__name__, message, AttributeError ) # The table _tableDict = tableEff( dataset, effName ) bins = {} varName = {} varUnit = {} for var in [varX, varY]: #-- dictionary-List with the min and max values per bin (min,max),... bins[var] = [ ( varDict[var]['arrayBins'][i], varDict[var]['arrayBins'][i+1] ) \ for i in xrange( len(varDict[var]['arrayBins'])-1) ] # Latex name of variables, maybe introduced by user otherwise take from construction try: # Remember to parse linux to latex \theta --> \\theta varName[var] = '$'+keywords[var].replace('\\','\\\\')+'$' except NameError: varName[var] = '$'+varDict[var]['latexName'].replace('\\','\\\\').replace('#','\\')+'$' varUnit[var] = varDict[var]['unit'] if len(varUnit[var]) != 0: varUnit[var] = '$({\\rm '+varUnit[var]+'})$' #Some usefuls function to deal with latex edges = lambda x,y: '(%0.1f, %0.1f)' % (x,y) effsetter = lambda eff,lo,hi: '$%.3f\\pm^{%.3f}_{%.3f}$ & ' % (eff,hi-eff,eff-lo) central = lambda low,high: (high+low)/2.0 #-- Table latex construction toLatex = '\\begin{tabular}{c' #-- Number of table columns toLatex += 'c'*varDict[varY]['binN']+'}\\hline\n' #-- Header (first line) toLatex += varName[varX]+varUnit[varX]+' {\\boldmath$\\backslash$}'+\ varName[varY]+varUnit[varX]+' & ' #-- varY bins are put on the first line for low, high in bins[varY]: toLatex += edges(low,high)+' & ' toLatex = toLatex[:-2]+'\\\\ \\hline\n' #--- Finally, fill the table, line by line for lowX,highX in bins[varX]: toLatex += edges(lowX,highX)+' & ' for lowY,highY in bins[varY]: try: eff,effErrorLow,effErrorHig = eval('getEff(dataset,effName,'+\ varX+'=central(lowX,highX), '+varY+'=central(lowY,highY))') toLatex += effsetter(eff,effErrorLow,effErrorHig) #Empty bin except TypeError: toLatex += ' & ' toLatex = toLatex[:-2]+'\\\\\n' toLatex += ' \\hline\n' toLatex += '\\end{tabular}' print toLatex return toLatex
def tableLatex(dataset, inputEffName = 'efficiency'): """ tableLatex( dataset, inputEffName ) -> list Giving a RooDataSet, the function returns a table in latex format :param dataset: dataset :type dataset: ROOT.RooDataSet :param inputEffName: efficiency name :type inputEffName: string :return: string in latex format :rtype: string """ #---- Checking the variables in dataset _swapDict = getVarDict( dataset ) #--- All the binned variables in the dataset datasetVarList = filter( lambda x: x.lower().find(inputEffName) == -1, _swapDict.iterkeys() ) _swapeffList = filter( lambda x: x.lower().find(inputEffName) != -1, _swapDict.iterkeys() ) #---- Sanity check if len(_swapeffList) != 1: message ="""ERROR: Unexpected Error!! It seems that in '%s' there is no"""\ """ efficiency variable...""" % dataSet.GetName() printError( tableLatex.__module__+'.'+tableLatex.__name__, message, AttributeError ) effName = _swapeffList[0] #Getting table effList = listTableEff(dataset) ## Getting bins of variables #---- Dictionary with the bins for each binned variable binsTMP = map( lambda nameVar: { nameVar: set([ (i[nameVar][1],i[nameVar][2]) for i in effList ]) }, datasetVarList ) bins = {} #List from the map, only each item is a dict. Joining for Dict in binsTMP: for key,valDict in Dict.iteritems(): bins[key] = valDict for key,SET in bins.iteritems(): bins[key] = sorted(list(SET)) #Assuming we have 2 binned variables: if len(bins) != 2: message = """\033[1;31mtableLatex Error: only two variables, by the moment\033[1;31m""" print message #FIXME etaBins = None for i,j in sorted(bins.iteritems()): etaBins = j etaName = i break ptBins = None KK = 0 for i,j in sorted(bins.iteritems()): if KK == 1: ptBins = j ptName = i break KK += 1 etaNbins = len(etaBins) ptNbins = len(ptBins) #Some usefuls function edges = lambda x,y: '(%0.1f, %0.1f)' % (x,y) effsetter = lambda eff,lo,hi: '$%.3f\\pm^{%.3f}_{%.3f}$ & ' % (eff,hi-eff,eff-lo) central = lambda low,high: (high+low)/2.0 toLatex = '\\begin{tabular}{c' #Number of columns toLatex += 'c'*etaNbins+'}\\hline\n' #header toLatex += '$p_T^\\mu({\\rm GeV})$ {\\boldmath$\\backslash$}$\\eta^\\mu$ & ' for low,high in etaBins: toLatex += edges(low,high)+' & ' toLatex = toLatex[:-2]+'\\\\ \\hline\n' #Filling the table for lowPt,highPt in ptBins: toLatex += edges(lowPt,highPt)+' & ' for lowEta,highEta in etaBins: try: eff,effErrorLow,effErrorHig = eval('getEff(dataset,inputEffName,'+\ ptName+'=central(lowPt,highPt), '+etaName+'=central(lowEta,highEta))') toLatex += effsetter(eff,effErrorLow,effErrorHig) #Empty bin except TypeError: toLatex += ' & ' toLatex = toLatex[:-2]+'\\\\\n' toLatex += ' \\hline\n' toLatex += '\\end{tabular}' # print toLatex return toLatex
def getResName( aFile, **keywords ): """.. function:: getResName( fileName[, config=configfile] ) -> pytnpname,latexstring Extract from file name, T&P-like, the resonance and returns it plain and in Latex format. :param fileName: the root file name :type fileName: string :keyword config: configuration file to impose the results of this function. Makes use of the ``DataNames`` dictionary placed :type config: string :return: unique identifier (pytnpname) and latex description of this root file :rtype: tuple of strings .. warning:: This function is highly dependent of the name of the file (if you don't use a config file). Standard Format: NameOFResonance_X_blabla.root :raise KeyError: keyword erroneous :raise TypeError: no config file provided and no root file name in standard format :raise RuntimeError: somethin wrong happens. Warn to developers .. note:: Probably will change to ``tnputils`` module """ import re regexp = re.compile( '\D*(?P<NUMBER>\dS)' ) resonance = '' resonanceLatex = '' # Hardcoded dict: include here new resonances nameDict = { 'JPsi' : ('J/#Psi','JPsi'), 'Upsilon': ('All #Upsilon','AllUpsilons'), 'Z' : ('Z#rightarrow#mu#mu','Z') } # Complements adjectDict = { 'DATA' : (' Data', '_DATA'), 'ReWeight' : (' ReWeight ', '_ReWeight'), 'GoodCowboys' : (' GCS', '_GoodCowboysAndSeagulls'), '_MC_' : (' MC', ''), '_Spring10_' : (' MC', ''), } #-- Add and/or updating the keys, entered by the user isDone = False for key, _file in keywords.iteritems(): if key != 'config': message = "Invalid argument key '%s', only accepted 'config" % key printError( getResName.__module__+'.'+getResName.__name__, message, KeyError ) #-- Controlling the None case if _file: for name, value in parserConfig( keywords['config'], 'DataNames' ).iteritems(): nameDict[name] = value isDone = True # User rules, so... # Posible try!! FIXME!! resonanceLatex = nameDict[aFile][0] resonance = nameDict[aFile][1] return resonance,resonanceLatex try: num = regexp.search( aFile ).group( 'NUMBER' ) resonanceLatex = '#Upsilon('+num+')' resonance = 'Upsilon'+num except AttributeError: #Reverse sorted to assure DATA is the last one for name, (resLatex,res) in sorted(nameDict.iteritems(),reverse=True): if aFile.find( name ) != -1: resonanceLatex = resLatex resonance = res if resonance == '': message ="""This function is highly dependent of the \n"""\ """name of the file, you need an standard format like:\n"""\ """ NameOFResonance_X_blabla.root"""\ """Unrecognized name: \033[1;m\033[1;39m '%s'\033[1;m""" % aFile printError( getResName.__module__+'.'+getResName.__name__, message, TypeError ) except: message ="""UNEXPECTED ERROR!! Send a e-mail to the developer(s) with all information\n"""\ """needed to reproduce this error""" printError( getresname.__module__+'.'+getresname.__name__, message, RuntimeError ) #All work is done if isDone: return resonance, resonanceLatex #Including others.. # FIXME: To be DEPRECATED for name, (resLatex,res) in sorted(adjectDict.iteritems(),reverse=True): if aFile.find( name ) != -1: resonanceLatex += resLatex resonance += res return resonance,resonanceLatex
def getEffFromDict( dataset, input_effName='efficiency', **keywords): """.. function:: getEffFromDict(RooDataSet, effName, var1=value[,var2=value2, ...]) -> eff, effErrorLow, effErrorHigh, dict Giving a binned variables returns the efficiency which corresponds to those values. If the introduced variables are the exhausted set of the RooDataSet, the output will be a tuple of efficiency plus a None object (CASE 1). Otherwise if the input variables don't cover all the RooDataSet binned variables, the output will be the efficiency tuple plus a dictionary which the names of the remaining variables and efficiency as keys and the tuples of their values as dictionary values (CASE 2). :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name. Default value 'efficiency' :type effName: string :keyword var1: name of the value with its value :rtype var1: float :return: tuple with efficiency values and a dictionary (None) :rtype: float,float,float,dict :raise AttributeError: if the dataset do not contain ``var`` :raise UserWarning: if do not introduce at least one variable as keyword """ #--- All the binned variables in the dataset datasetVarList, effName = getVarNames( dataset, input_effName ) #--- Checking if vars are in, and storing them in a list nameVarValueList = [] nameVarList = [] for var,value in keywords.iteritems(): if not isbinnedVar( dataset, var, effName ): message ="""The RooDataSet '%s' does not contain '%s' as binned variable""" % (dataset.GetName(), var) printError( getEff.__module__+'.'+getEff.__name__, message, AttributeError ) nameVarValueList.append( (var,value) ) nameVarList.append( var ) #---- Sanity check if len(nameVarList) < 1: message ="""You must introduce at least one variable""" printError( getEffFromDict.__module__+'.'+getEffFromDict.__name__, message, UserWarning ) #--- Binned variables which are not entered as arguments of this function noAskVar = filter( lambda x: x not in nameVarList, datasetVarList ) #--- Has introduce the user all the binned variables? #--- If so, when find the efficiency value just return it #--- otherwise it must store all the efficiency values #--- which corresponds to the same variable value (the other #--- binned variables will vary). isbinnedComplete = False dictReturn = None noAskStr = '' if len(noAskVar) == 0: isbinnedComplete = True else: dictReturn = { effName: [] } #-- Want to keep the values of the binned values don't ask by the user #-- in order to save them to the dictionary tupleNoAskStr = '' for var in noAskVar: dictReturn[var] = [] noAskStr += ',_table[\''+var+'\']' _table = tableEff( dataset, effName ) #-- Checking the position where there are matches indexDict = {} for var,value in nameVarValueList: _ind = 0 indexDict[var] = [] for central,low,high in _table[var]: if low <= value and high > value: indexDict[var].append( _ind ) _ind += 1 #-- Merging all the matches indexes indexList = indexDict.values() indexSet = set( indexList[0] ) for i in xrange(len(indexList)-1): indexSet = indexSet.intersection( indexList[i+1] ) _tableList = eval('zip(_table[effName]'+noAskStr+')') for i in filter( lambda _ind: _ind in indexSet, xrange(len(_tableList)) ): try: eff,theOthers = _tableList[i] #-- Note the behaviour of tuple: (a,b,c) != ((a,b,c),) if len(theOthers) == 3: theOthers = (theOthers,) dictReturn[effName].append( eff ) _index = 0 for name in noAskVar: #-- The order of variables are in noAskVar dictReturn[name].append( theOthers[_index] ) _index += 1 except ValueError: #-- Note: due to the zip, the output will be ((eff,effL,effH),) eff,effL,effH = _tableList[i][0] return eff, effL, effH, None if (len(dictReturn[effName])) > 0: return dictReturn
def getResName(aFile, **keywords): """.. function:: getResName( fileName[, config=configfile] ) -> pytnpname,latexstring Extract from file name, T&P-like, the resonance and returns it plain and in Latex format. :param fileName: the root file name :type fileName: string :keyword config: configuration file to impose the results of this function. Makes use of the ``DataNames`` dictionary placed :type config: string :return: unique identifier (pytnpname) and latex description of this root file :rtype: tuple of strings .. warning:: This function is highly dependent of the name of the file (if you don't use a config file). Standard Format: NameOFResonance_X_blabla.root :raise KeyError: keyword erroneous :raise TypeError: no config file provided and no root file name in standard format :raise RuntimeError: somethin wrong happens. Warn to developers .. note:: Probably will change to ``tnputils`` module """ import re regexp = re.compile('\D*(?P<NUMBER>\dS)') resonance = '' resonanceLatex = '' # Hardcoded dict: include here new resonances nameDict = { 'JPsi': ('J/#Psi', 'JPsi'), 'Upsilon': ('All #Upsilon', 'AllUpsilons'), 'Z': ('Z#rightarrow#mu#mu', 'Z') } # Complements adjectDict = { 'DATA': (' Data', '_DATA'), 'ReWeight': (' ReWeight ', '_ReWeight'), 'GoodCowboys': (' GCS', '_GoodCowboysAndSeagulls'), '_MC_': (' MC', ''), '_Spring10_': (' MC', ''), } #-- Add and/or updating the keys, entered by the user isDone = False for key, _file in keywords.iteritems(): if key != 'config': message = "Invalid argument key '%s', only accepted 'config" % key printError(getResName.__module__ + '.' + getResName.__name__, message, KeyError) #-- Controlling the None case if _file: for name, value in parserConfig(keywords['config'], 'DataNames').iteritems(): nameDict[name] = value isDone = True # User rules, so... # Posible try!! FIXME!! resonanceLatex = nameDict[aFile][0] resonance = nameDict[aFile][1] return resonance, resonanceLatex try: num = regexp.search(aFile).group('NUMBER') resonanceLatex = '#Upsilon(' + num + ')' resonance = 'Upsilon' + num except AttributeError: #Reverse sorted to assure DATA is the last one for name, (resLatex, res) in sorted(nameDict.iteritems(), reverse=True): if aFile.find(name) != -1: resonanceLatex = resLatex resonance = res if resonance == '': message ="""This function is highly dependent of the \n"""\ """name of the file, you need an standard format like:\n"""\ """ NameOFResonance_X_blabla.root"""\ """Unrecognized name: \033[1;m\033[1;39m '%s'\033[1;m""" % aFile printError(getResName.__module__ + '.' + getResName.__name__, message, TypeError) except: message ="""UNEXPECTED ERROR!! Send a e-mail to the developer(s) with all information\n"""\ """needed to reproduce this error""" printError(getresname.__module__ + '.' + getresname.__name__, message, RuntimeError) #All work is done if isDone: return resonance, resonanceLatex #Including others.. # FIXME: To be DEPRECATED for name, (resLatex, res) in sorted(adjectDict.iteritems(), reverse=True): if aFile.find(name) != -1: resonanceLatex += resLatex resonance += res return resonance, resonanceLatex
def getEffFromDict(dataset, input_effName='efficiency', **keywords): """.. function:: getEffFromDict(RooDataSet, effName, var1=value[,var2=value2, ...]) -> eff, effErrorLow, effErrorHigh, dict Giving a binned variables returns the efficiency which corresponds to those values. If the introduced variables are the exhausted set of the RooDataSet, the output will be a tuple of efficiency plus a None object (CASE 1). Otherwise if the input variables don't cover all the RooDataSet binned variables, the output will be the efficiency tuple plus a dictionary which the names of the remaining variables and efficiency as keys and the tuples of their values as dictionary values (CASE 2). :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name. Default value 'efficiency' :type effName: string :keyword var1: name of the value with its value :rtype var1: float :return: tuple with efficiency values and a dictionary (None) :rtype: float,float,float,dict :raise AttributeError: if the dataset do not contain ``var`` :raise UserWarning: if do not introduce at least one variable as keyword """ #--- All the binned variables in the dataset datasetVarList, effName = getVarNames(dataset, input_effName) #--- Checking if vars are in, and storing them in a list nameVarValueList = [] nameVarList = [] for var, value in keywords.iteritems(): if not isbinnedVar(dataset, var, effName): message = """The RooDataSet '%s' does not contain '%s' as binned variable""" % ( dataset.GetName(), var) printError(getEff.__module__ + '.' + getEff.__name__, message, AttributeError) nameVarValueList.append((var, value)) nameVarList.append(var) #---- Sanity check if len(nameVarList) < 1: message = """You must introduce at least one variable""" printError(getEffFromDict.__module__ + '.' + getEffFromDict.__name__, message, UserWarning) #--- Binned variables which are not entered as arguments of this function noAskVar = filter(lambda x: x not in nameVarList, datasetVarList) #--- Has introduce the user all the binned variables? #--- If so, when find the efficiency value just return it #--- otherwise it must store all the efficiency values #--- which corresponds to the same variable value (the other #--- binned variables will vary). isbinnedComplete = False dictReturn = None noAskStr = '' if len(noAskVar) == 0: isbinnedComplete = True else: dictReturn = {effName: []} #-- Want to keep the values of the binned values don't ask by the user #-- in order to save them to the dictionary tupleNoAskStr = '' for var in noAskVar: dictReturn[var] = [] noAskStr += ',_table[\'' + var + '\']' _table = tableEff(dataset, effName) #-- Checking the position where there are matches indexDict = {} for var, value in nameVarValueList: _ind = 0 indexDict[var] = [] for central, low, high in _table[var]: if low <= value and high > value: indexDict[var].append(_ind) _ind += 1 #-- Merging all the matches indexes indexList = indexDict.values() indexSet = set(indexList[0]) for i in xrange(len(indexList) - 1): indexSet = indexSet.intersection(indexList[i + 1]) _tableList = eval('zip(_table[effName]' + noAskStr + ')') for i in filter(lambda _ind: _ind in indexSet, xrange(len(_tableList))): try: eff, theOthers = _tableList[i] #-- Note the behaviour of tuple: (a,b,c) != ((a,b,c),) if len(theOthers) == 3: theOthers = (theOthers, ) dictReturn[effName].append(eff) _index = 0 for name in noAskVar: #-- The order of variables are in noAskVar dictReturn[name].append(theOthers[_index]) _index += 1 except ValueError: #-- Note: due to the zip, the output will be ((eff,effL,effH),) eff, effL, effH = _tableList[i][0] return eff, effL, effH, None if (len(dictReturn[effName])) > 0: return dictReturn
def tableLatex(dataset, inputEffName='efficiency'): """ tableLatex( dataset, inputEffName ) -> list Giving a RooDataSet, the function returns a table in latex format :param dataset: dataset :type dataset: ROOT.RooDataSet :param inputEffName: efficiency name :type inputEffName: string :return: string in latex format :rtype: string """ #---- Checking the variables in dataset _swapDict = getVarDict(dataset) #--- All the binned variables in the dataset datasetVarList = filter(lambda x: x.lower().find(inputEffName) == -1, _swapDict.iterkeys()) _swapeffList = filter(lambda x: x.lower().find(inputEffName) != -1, _swapDict.iterkeys()) #---- Sanity check if len(_swapeffList) != 1: message ="""ERROR: Unexpected Error!! It seems that in '%s' there is no"""\ """ efficiency variable...""" % dataSet.GetName() printError(tableLatex.__module__ + '.' + tableLatex.__name__, message, AttributeError) effName = _swapeffList[0] #Getting table effList = listTableEff(dataset) ## Getting bins of variables #---- Dictionary with the bins for each binned variable binsTMP = map( lambda nameVar: {nameVar: set([(i[nameVar][1], i[nameVar][2]) for i in effList])}, datasetVarList) bins = {} #List from the map, only each item is a dict. Joining for Dict in binsTMP: for key, valDict in Dict.iteritems(): bins[key] = valDict for key, SET in bins.iteritems(): bins[key] = sorted(list(SET)) #Assuming we have 2 binned variables: if len(bins) != 2: message = """\033[1;31mtableLatex Error: only two variables, by the moment\033[1;31m""" print message #FIXME etaBins = None for i, j in sorted(bins.iteritems()): etaBins = j etaName = i break ptBins = None KK = 0 for i, j in sorted(bins.iteritems()): if KK == 1: ptBins = j ptName = i break KK += 1 etaNbins = len(etaBins) ptNbins = len(ptBins) #Some usefuls function edges = lambda x, y: '(%0.1f, %0.1f)' % (x, y) effsetter = lambda eff, lo, hi: '$%.3f\\pm^{%.3f}_{%.3f}$ & ' % ( eff, hi - eff, eff - lo) central = lambda low, high: (high + low) / 2.0 toLatex = '\\begin{tabular}{c' #Number of columns toLatex += 'c' * etaNbins + '}\\hline\n' #header toLatex += '$p_T^\\mu({\\rm GeV})$ {\\boldmath$\\backslash$}$\\eta^\\mu$ & ' for low, high in etaBins: toLatex += edges(low, high) + ' & ' toLatex = toLatex[:-2] + '\\\\ \\hline\n' #Filling the table for lowPt, highPt in ptBins: toLatex += edges(lowPt, highPt) + ' & ' for lowEta, highEta in etaBins: try: eff,effErrorLow,effErrorHig = eval('getEff(dataset,inputEffName,'+\ ptName+'=central(lowPt,highPt), '+etaName+'=central(lowEta,highEta))') toLatex += effsetter(eff, effErrorLow, effErrorHig) #Empty bin except TypeError: toLatex += ' & ' toLatex = toLatex[:-2] + '\\\\\n' toLatex += ' \\hline\n' toLatex += '\\end{tabular}' # print toLatex return toLatex
def plotEff1D( self, name, inputVarName, Lumi ): """.. method:: plotEff1D( dataname, variable, Lumi ) Given a name directory-like for a ROOT.RooDataSet object, the function creates a 1-dim plot of 'variable_name' extracted from the object and it will save it in a eps file. Also it will store the graph object creating a new key in the dataset dictionary:: self[nameRooDataSet]['tgraphs'] = { 'class_graph_name': TGraphAsymmErrors, ... } :param name: name of the dataset :type name: string :param variable: binned variable to use :type variable: string :param Lumi: luminosity :type Lumi: string :raise KeyError: the dataset is not in the root file (to be changed to NameError) :raise KeyError: the binned variable is not in the dataset """ #import rootlogon from tnputils import listTableEff,getEff, graphclassname from pytnp.steerplots.plotfunctions import plotAsymGraphXY dataset = None #-- Getting the class graph name _graphclassname = graphclassname( self, name ) #-- Checking if the object exists try: dataset = self.RooDataSet[name] except KeyError: message = """you must introduce a valid name, '%s' is not a RooDataSet in the root file""" % name printError( self.__module__, message, KeyError ) #--- Empty dataset if self.RooDataSet[name].numEntries() == 0: message = """Empty RooDataSet '%s'. Skipping...""" % name printWarning( self.__module__+'.plotEff1D',message) return None #--- Checking variable if not inputVarName in self[name]['binnedVar'].keys(): message = """you must introduce a valid binned variable name, '%s' is not in the '%s' RooDataSet\n""" % (inputVarName,name ) message += """The list of binned variables are '%s'""" % str(self[name]['binnedVar'].keys()) printError( self.__module__, message, KeyError ) self[name]['tgraphs'] = { _graphclassname: {} } # Special case: we have only one variable if len(self[name]['binnedVar']) == 1: graphName = self.resonance+'_'+self[name]['effType']+'_'+self[name]['objectType']+'_'+\ self[name]['methodUsed']+'__'+inputVarName if self[name]['isMC'] == 1: graphName += '__mcTrue' #--- Extracting the efficiency values per bin plotList = listTableEff( dataset ) _min = 0 _max = 0 #--- Setting the points and extracting the min and max value #--- in order to build the frame to plot XPoints = [] YPoints = [] for varDict in plotList: (eff,effLo,effHi) = varDict[self.effName] (var,varLo,varHi) = varDict[inputVarName] XPoints.append( (var, varLo, varHi) ) YPoints.append( (eff, effLo, effHi) ) _min = min( _min, varLo ) _max = max( _max, varHi ) #--- Cosmethics to storing the plot #title = self[name]['objectType']+' category' xtitle = self[name]['variables'][inputVarName]['latexName']+' '+self[name]['variables'][inputVarName]['unit'] ytitle = 'efficiency' title = ' CMS Preliminary,'+Lumi+' #sqrt{s}=7 TeV ' self[name]['tgraphs'][_graphclassname][graphName] = plotAsymGraphXY( XPoints, YPoints, xtitle, ytitle,\ returnGraph=True, rangeFrame = (_min,0,_max,1.05), title=title, graphname=graphName ) return #-- More than one binned variable for varName in filter( lambda x: x != inputVarName, self[name]['binnedVar'].keys()): _otherVarList_ = filter( lambda x: x != varName, self[name]['binnedVar'].keys() ) _otherVar_ = '' for i in _otherVarList_: _otherVar_ += i+', ' _otherVar_ = _otherVar_[:-2] if len(_otherVar_ ) != 0: _otherVar_ = ' in all the range of \'' +_otherVar_+'\'' print '\033[1;34m'+name+': \''+varName+'\' bins'+_otherVar_+'\033[1;m' #--- Extracting bins and array of bins binsN = self[name]['variables'][varName]['binN'] arrayBins = self[name]['variables'][varName]['arrayBins'] for bin in xrange(binsN): arrayBins = self[name]['variables'][varName]['arrayBins'] Lo = arrayBins[bin] Hi = arrayBins[bin+1] Central = (Hi+Lo)/2.0 graphName = self.resonance+'_'+self[name]['effType']+'_'+self[name]['objectType']+'_'+\ self[name]['methodUsed']+'__'+varName+'_bin'+str(bin)+'_' #graphName = self.resonance+'_'+self[name]['methodUsed']+'_'+self[name]['effType']+'_'+\ # self[name]['objectType']+'__'+varName+'_bin'+str(bin)+'_' #Getting list of efficiency values plus variables _plotList = eval('getEff(dataset,self.effName,'+varName+'='+str(Central)+')') #print _plotList #Extracting info to plot #try: (eff,effErrorLo,effErrorHi),otherVarDict = _plotList[0] if len(filter( lambda (eff,__dic): eff[0] == 0.0, _plotList )) == len(_plotList): printWarning( self.__module__+'.plotEff1D',"Skipping... Efficiencies in the dataset not calculated") continue _max = {} _min = {} varPoints = {} effPoints = {} for otherVarName, val in otherVarDict.iteritems(): varPoints[otherVarName] = [] effPoints[otherVarName] = [] _max[otherVarName] = 0.0 _min[otherVarName] = 0.0 for (eff,effLo,effHi),otherVarDict in _plotList: for otherVarName, (central, low, high) in otherVarDict.iteritems(): _min[otherVarName] = min( _min[otherVarName], low ) _max[otherVarName] = max( _max[otherVarName], high ) varPoints[otherVarName].append( (central,low,high) ) effPoints[otherVarName].append( (eff, effLo, effHi) ) title = self.resLatex+', ('+str(Lo)+','+str(Hi)+') '+self[name]['variables'][varName]['latexName']+' range, ' title += self[name]['objectType']+' category' for otherVarName, (central, low, high) in otherVarDict.iteritems(): graphname = graphName+otherVarName if self[name]['isMC'] == 1: graphname += '__mcTrue' xtitle = self[name]['variables'][otherVarName]['latexName']+\ ' '+self[name]['variables'][otherVarName]['unit'] ytitle = 'efficiency' title = 'CMS Preliminary,'+Lumi+' #sqrt{s}=7 TeV' ranges = (_min[otherVarName],0,_max[otherVarName],1.05) self[name]['tgraphs'][_graphclassname][graphname] = plotAsymGraphXY( varPoints[otherVarName], effPoints[otherVarName],\ xtitle, ytitle, returnGraph=True, rangeFrame=ranges, title=title, graphname=graphname)
def getEff(dataSet, input_effName='efficiency', **keywords): """.. function:: getEff(dataset, effName='efficiency', var1=value[,var2=value2, ...]) -> eff, effErrorLow, effErrorHigh (,dict) Giving a binned variables returns the efficiency which corresponds to those values. There is 2 output signatures depending of the argument variables introduced; if the variables are the exhausted set of the RooDataSet, the output will be a tuple of efficiency (CASE 1). Otherwise if the input variables don't cover all the RooDataSet binned variables, the output will be the efficiency tuple plus a dictionary which the names of the resting variables as keys and the tuples of their bin values as values (CASE 2). :param dataset: dataset :type dataset: ROOT.RooDataSet :param input_effName: efficiency name :type input_effName: string :keyword var: var=value :rtype var: object :return: tuple with efficiency values (and a dictionary) :rtype: float,float,float(,dict) :raise UserWarning: if do not introduce at least one variable as keyword """ #---- Checking the variables in dataset _swapDict = getVarDict(dataSet) #--- All the binned variables in the dataset datasetVarList, effName = getVarNames(dataSet, input_effName) varList = [] nameVarList = [] for var, value in keywords.iteritems(): if not isbinnedVar(dataSet, var, effName, warning=True): raise KeyError varList.append((var, value)) nameVarList.append(var) #---- Sanity check if len(nameVarList) < 1: message = """You must introduce at least one variable""" printError(getEff.__module__ + '.' + getEff.__name__, message, UserWarning) #--- Variables the user don't ask. This is the case when the user #--- wants a list of efficiency given a fixed value of one variable noAskVar = filter(lambda x: x not in nameVarList, datasetVarList) listReturn = False effVarList = None if len(noAskVar) != 0: listReturn = True effVarList = [] #---- Sanity check if len(varList) > len( datasetVarList): #FIXME---> can be more than 2 variables... message = """You are using more variables than in dataset '%s'""" % dataSet.GetName( ) printError(getEff.__module__ + '.' + getEff.__name__, message, AttributeError) #-- Get the table of efficiencies tableList = listTableEff(dataSet) for valDict in tableList: #-- From the list of the variables we want the efficiencies (varList), put the value inside #--- of the ranges (valDict[var][1:][i]) in the list fList = filter( lambda (var, value): valDict[var][1:][0] <= value and valDict[var][ 1:][1] > value, varList) #-- If our variables are all the variables available, we have 1-to-1 correspondence #--- with a efficiency value-> return this value if not listReturn and len(fList) == len(varList): return valDict[effName] #-- If our variables are less than the variables available, we're going to return #--- a list with the (restOfvariables,efficiencies) in order to recover the 1-to-1 correspondence elif listReturn and len(fList) != 0: restVarDict = dict([(_name, valDict[_name]) for _name in noAskVar]) effVarList.append((valDict[effName], restVarDict)) if listReturn and len(effVarList) > 0: #--output: (tuple,dict) where tuple is efficiency values and dict have the #--- names of the variables as keys and tuple as values return effVarList message = '\033[1;34mpytnp.getEff Info: There is no bin where live ' for var, val in varList: message += var + '=' + str(val) + ', ' message = message[:-2] + '\033[1;m' print message # FIXME: Strange behaviour with version 3_6_1_patch4 (really with the RooFit (3.12 ??) included in this version: # The values of the listTableEff do not fill correctly. All the dictionary is filled of the same value (the last found value) # Still have this problem with RooFit 3.13, root-v5.27, python 2.6 ... return None
def plotEffMap( self, name, x, y, Lumi, **keywords ): """.. method:: plotEff2D( name, varX, varY, Lumi ) Giving a RooDataSet name in directory-like format, the function will do a bi-dimensional plot of efficiency with ``varX`` and ``varY`` variables. Also, it will stores the graph within the dataset dictionary :param name: name of the dataset :type name: string :param varX: binned variable to be used in the x-axis :type varX: string :param varY: binned variable to be used in the y-axis :type varY: string :param Lumi: luminosity :type Lumi: string :raise KeyError: the dataset is not in the root file (to be changed to NameError) :raise KeyError: some binned variables is not in the dataset """ import ROOT ROOT.gROOT.SetBatch(1) import pytnp.steerplots.rootlogon from tnputils import getBinning,listTableEff,getEff #FIXME: Meter los errores en la misma linea (ahora te salta # de linea (TEXT option) try: dataSet = self.RooDataSet[name] except KeyError: message = """There is no RooDataSet with name '%s'""" % name printError( self.__module__+'.plotEfMap', message, AttributeError ) #-- Are the variables in the RooDataSet? varNotInDatasetList = filter( lambda var: not var in self[name]['binnedVar'].keys(), [x, y] ) if len(varNotInDatasetList) != 0: message = 'No binned variable: ' for var in varNotInDatasetList: message += "'%s' " % var message += "in the RooDataSet '%s'. Skipping plot generation..." % name printWarning( self.__module__+'.plotEffMap', message ) # --- Skipping plot generation return #--- Name for the histo and for the plot file to be saved histoName = 'TH2F_'+name #--- Checking if the histo is already stored and plotted if self[name].has_key('TH2'): #### FIXME: has_key o has_attribute ??? #-- Skipping, work it's done! return None #---- Preparing all the stuff title = self.resLatex+', '+self[name]['objectType']+' '+self[name]['effType']+' '+dataSet.GetTitle() yNbins = self[name]['variables'][y]['binN'] #arrayBinsY = self[name]['variables'][y]['arrayBins']---> # I need the PyDoubleBuffer #------------------------------------------ __argSet__ = dataSet.get() dum, arrayBinsY = getBinning( __argSet__[y] ) #------------------------------------------ xNbins = self[name]['variables'][x]['binN'] #arrayBinsX = self[name]['variables'][x]['arrayBins']---> # I need the PyDoubleBuffer #------------------------------------------ dum, arrayBinsX = getBinning( __argSet__[x] ) #------------------------------------------ hTitleOfHist = name.replace('/','_') h = ROOT.TH2F( hTitleOfHist, '', xNbins, arrayBinsX, yNbins, arrayBinsY ) hlo = h.Clone("eff_lo") hlo.SetName( 'low_'+hTitleOfHist ) hhi = h.Clone("eff_hi") hhi.SetName( 'high_'+hTitleOfHist ) #-- Getting the efficiencies _listTableEffList = listTableEff(self.RooDataSet[name]) #skipPoints = False for binDict in _listTableEffList: #-- Extract error values #if abs(binDict[self[name]['eff']][0]-self.badPoint[0]) < 1e-9: # skipPoints = True # continue b = h.FindBin( binDict[x][0] , binDict[y][0] ) h.SetBinContent(b, binDict[self[name]['eff']][0]) h.SetBinError(b, (binDict[self[name]['eff']][2]-binDict[self[name]['eff']][1])/2.0 ) # WATCH: Error 'Simetrized' hlo.SetBinContent(b, binDict[self[name]['eff']][1]) hhi.SetBinContent(b, binDict[self[name]['eff']][2]) c = ROOT.TCanvas() #c.SetLogy(isLog[1]) h.GetYaxis().SetTitle(self[name]['variables'][y]['latexName']) h.GetXaxis().SetTitle(self[name]['variables'][x]['latexName']) h.GetZaxis().SetTitle(self[name]['variables'][self[name]['eff']]['latexName']) #h.SetTitle( title ) --> Out titles h.SetTitle( ' CMS Preliminary,'+Lumi+' #sqrt{s}=7 TeV ' ) #h.SetTitle('' ) h.Draw('COLZ') htext = h.Clone('htext') htext.SetMarkerSize(1.0) htext.SetMarkerColor(1) #if isLog[1]: # ROOT.gStyle.SetPaintTextFormat("1.2f") # htext.Draw('ESAMETEXT0') #else: ROOT.gStyle.SetPaintTextFormat("1.3f") #htext.SetMarkerSize(2.2) htext.Draw('SAMETEXTE0') #plotName = self.resonance+'_'+name.replace('/','_')+isLog[0]+'.eps' plotName = self.resonance+'_'+name.replace('/','_')+'.eps' c.SaveAs(plotName) # if skipPoints: # message = '\033[1;33mplotEff2D Warning: Some efficiencies points are failed in the fit, the last plot will skip '\ # 'values with %.4f\033[1;m' % self.badPoint[0] # print message #FIXME: attribute o llave del diccionario del rootdataset?? try: self[name]['TH2'][histoName] = (h, hlo, hhi) except KeyError: self[name]['TH2F'] = {} self[name]['TH2F'][histoName] = (h, hlo, hhi)
def newtableLatex(dataset, effName, varX, varY, **keyword): """.. function tableLatex( dataset, effName, 'var_column', 'var_row', [outfile='name.tex', varXname='latex name', varYname='latex name'] ) -> dict Giving a RooDataSet and two variables, the function returns a table in latex format. If enters the keyword 'outfile' also the table will put it into the file. (The keyword var is a list with the name of the variables the user want to dump. TODO, not yet implemented) :param dataset: dataset :type dataset: ROOT.RooDataSet :param effName: efficiency name :type effName: string :param varX: the name of the variable you want to be as column :rtype varX: string :param varY: the name of the variable you want to be as row .. seealso:: :func:`tableLatex` """ #TODO: The keyword var is a list with the name of the variables the user want to dump. #TODO: CHECK IF WORKS CORRECTLY message = "Use this function with caution! Still in development.\n Use instead the tableLatex function" printWarning(newtableLatex, message) #---- Checking the variables in dataset varDict = getVarDict(dataset) #--- All the binned variables in the dataset datasetVarList = filter(lambda x: x.lower().find(effName) == -1, varDict.iterkeys()) effList = filter(lambda x: x.lower().find(effName) != -1, varDict.iterkeys()) #---- Sanity check if len(effList) != 1: message ="""The RooDataSet '%s' does not contain a variable called '%s' as efficiency"""\ % ( dataset.GetName(), effName ) printError(tableLatex.__module__ + '.' + tableLatex.__name__, message, AttributeError) #---- Variables are there? for var in [varX, varY]: if var not in datasetVarList: message ="""The RooDataSet '%s' does not contain a binned variable called '%s'"""\ % ( dataset.GetName(), var ) printError(tableLatex.__module__ + '.' + tableLatex.__name__, message, AttributeError) # The table _tableDict = tableEff(dataset, effName) bins = {} varName = {} varUnit = {} for var in [varX, varY]: #-- dictionary-List with the min and max values per bin (min,max),... bins[var] = [ ( varDict[var]['arrayBins'][i], varDict[var]['arrayBins'][i+1] ) \ for i in xrange( len(varDict[var]['arrayBins'])-1) ] # Latex name of variables, maybe introduced by user otherwise take from construction try: # Remember to parse linux to latex \theta --> \\theta varName[var] = '$' + keywords[var].replace('\\', '\\\\') + '$' except NameError: varName[var] = '$' + varDict[var]['latexName'].replace( '\\', '\\\\').replace('#', '\\') + '$' varUnit[var] = varDict[var]['unit'] if len(varUnit[var]) != 0: varUnit[var] = '$({\\rm ' + varUnit[var] + '})$' #Some usefuls function to deal with latex edges = lambda x, y: '(%0.1f, %0.1f)' % (x, y) effsetter = lambda eff, lo, hi: '$%.3f\\pm^{%.3f}_{%.3f}$ & ' % ( eff, hi - eff, eff - lo) central = lambda low, high: (high + low) / 2.0 #-- Table latex construction toLatex = '\\begin{tabular}{c' #-- Number of table columns toLatex += 'c' * varDict[varY]['binN'] + '}\\hline\n' #-- Header (first line) toLatex += varName[varX]+varUnit[varX]+' {\\boldmath$\\backslash$}'+\ varName[varY]+varUnit[varX]+' & ' #-- varY bins are put on the first line for low, high in bins[varY]: toLatex += edges(low, high) + ' & ' toLatex = toLatex[:-2] + '\\\\ \\hline\n' #--- Finally, fill the table, line by line for lowX, highX in bins[varX]: toLatex += edges(lowX, highX) + ' & ' for lowY, highY in bins[varY]: try: eff,effErrorLow,effErrorHig = eval('getEff(dataset,effName,'+\ varX+'=central(lowX,highX), '+varY+'=central(lowY,highY))') toLatex += effsetter(eff, effErrorLow, effErrorHig) #Empty bin except TypeError: toLatex += ' & ' toLatex = toLatex[:-2] + '\\\\\n' toLatex += ' \\hline\n' toLatex += '\\end{tabular}' print toLatex return toLatex