358 lines
13 KiB
Python
358 lines
13 KiB
Python
from ROOT import gROOT, gDirectory, gStyle, TChain, TTree, TAxis, TH1D
|
|
import subprocess
|
|
import time
|
|
import numpy as np
|
|
import re #for splitting with multiple deliminers
|
|
from array import array
|
|
import numexpr
|
|
import argparse
|
|
import sys
|
|
import os
|
|
import re
|
|
from Globals import *
|
|
|
|
'''
|
|
Tools used in compareUlitmate.py
|
|
'''
|
|
#Define a list of variables that are considered integers
|
|
intVarsList = ["nTracks"
|
|
,"nLongTracks"
|
|
,"nVeloTracks"
|
|
,"nTTracks"
|
|
,"nDownstreamTracks"
|
|
,"nUpstreamTracks"
|
|
,"nCandidate"
|
|
,"totCandidates"
|
|
,"nSPDHits"
|
|
,"nPV"
|
|
,"B_plus_ID"
|
|
,"B_plus_TRUEID"
|
|
,"K_star_plus_ID"
|
|
,"K_plus_ID"
|
|
,"pi_zero_resolved_ID"
|
|
,"mu_plus_ID"
|
|
,"mu_minus_ID"
|
|
,"Polarity"
|
|
,"nDiMuonMassBin"
|
|
,"TMedBKGCAT"
|
|
]
|
|
|
|
def expressionList():
|
|
return ["Sqrt"
|
|
,"Abs"
|
|
,"Sin"
|
|
,"Cos"
|
|
,"Exp"
|
|
,"Log"
|
|
]
|
|
|
|
|
|
#Define a function that returns true for variables that are integers
|
|
def isInt(variable=""):
|
|
if variable in intVarsList:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
def treeName(MC=False, TM=False, Preselected=False):
|
|
if (TM or (MC and Preselected)): #TODO
|
|
return "DecayTreeTruthMatched"
|
|
elif (not Preselected):
|
|
return "b2KstKs0pimumu_Tuple" if KshortChannel() else "b2KstKpi0mumuResolvedTuple/DecayTree"
|
|
else:
|
|
return "DecayTree"
|
|
|
|
def getOptionsDictionary(year, Run, magnet, MC, TM, ReferenceChannel, PHSP, Preselected,
|
|
BDTed, sWeighted, bWeighted, b2Dweighted, weightBranch, KshortDecaysInVelo, UseLowQ2Range):
|
|
dictionaryTmp = {
|
|
'year': year,
|
|
'Run' : Run,
|
|
'magnet' : magnet,
|
|
'MC' : int(MC),
|
|
'TM' : int(TM),
|
|
'ReferenceChannel' : int(ReferenceChannel),
|
|
'PHSP' : int(PHSP),
|
|
'Preselected' : int(Preselected),
|
|
'BDTed' : BDTed,
|
|
'sWeighted' : sWeighted,
|
|
'bWeighted' : bWeighted,
|
|
'b2Dweighted' : b2Dweighted,
|
|
'weightBranch' : weightBranch,
|
|
'KshortDecaysInVelo' : int(KshortDecaysInVelo),
|
|
'UseLowQ2Range' : UseLowQ2Range
|
|
|
|
}
|
|
return dictionaryTmp
|
|
|
|
def checkYearSample(optionsDict): #If wrong year/MC, skip
|
|
if optionsDict['year'] not in yearList(): return False, "Wrong Year!"
|
|
if (not optionsDict['MC']): return True, ""
|
|
else:
|
|
if (KshortChannel()):
|
|
if (optionsDict['PHSP']): return True, ""
|
|
elif (optionsDict['ReferenceChannel']):
|
|
if (optionsDict['year'] < 2013 or optionsDict['year'] == 2016): return True, "" #Referenche channel available only for Run I
|
|
else: return False, "RefChannel only available for Run I!"
|
|
else: return True, ""
|
|
else:
|
|
if (optionsDict['PHSP']):
|
|
if (optionsDict['year'] < 2018): return True, ""
|
|
else: return False, ""
|
|
elif (optionsDict['ReferenceChannel']):
|
|
if (optionsDict['year'] < 2017): return True, "" #Referenche channel available only for Run I
|
|
else: return False, "RefChannel only available for < 2017!"
|
|
else:
|
|
if (optionsDict['year'] > 2017):
|
|
return False, "No MC for 2018!"
|
|
else: return True, ""
|
|
|
|
def getTreePath(optionsDict, verbose):
|
|
#getPathForPython usage:
|
|
# getPathForPython command year Run magnet Preselected MC ReferenceChannel PHSP KshortDecayInVelo Selection UseLowQ2Range
|
|
#It has to have everything to keep it easy
|
|
#Get first file name
|
|
filePath2 = ""
|
|
command = "/home/lhcb/kopecna/B2KstarMuMu/code/ewp-Bplus2Kstmumu-AngAna/CodeForTests/CompareUltimate/getPathForPython " #TODO maybe replace by a current path
|
|
if(optionsDict['BDTed']):
|
|
options = "BDToutput %(year)i %(Run)i %(magnet)s 0 %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
|
|
if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
|
|
#Read second line from the c++ script (first one is the Hello...)
|
|
filePath = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
|
|
|
|
elif (optionsDict['sWeighted'] or optionsDict['bWeighted'] or optionsDict['b2Dweighted']):
|
|
options = "BDTinput %(year)i %(Run)i %(magnet)s 0 %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
|
|
if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
|
|
#Read second line from the c++ script (first one is the Hello...)
|
|
filePath = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
|
|
else:
|
|
|
|
if (optionsDict['magnet']=="both"):
|
|
#down
|
|
options = "input %(year)i %(Run)i down %(Preselected)r %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
|
|
if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
|
|
filePath = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
|
|
#up
|
|
options = "input %(year)i %(Run)i up %(Preselected)r %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
|
|
if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
|
|
filePath2 = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
|
|
else:
|
|
options = "input %(year)i %(Run)i %(magnet)s %(Preselected)r %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
|
|
if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
|
|
filePath = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
|
|
return filePath, filePath2
|
|
|
|
def addToTChain(tree, optionsDict, verbose):
|
|
filePath, filePath2 = getTreePath(optionsDict=optionsDict, verbose=verbose)
|
|
|
|
#Get first file name
|
|
if(optionsDict['BDTed'] or optionsDict['sWeighted'] or optionsDict['bWeighted'] or optionsDict['b2Dweighted']):
|
|
print "[INFO]\tOpening", filePath
|
|
tree.Add(filePath)
|
|
else:
|
|
if (optionsDict['magnet']=="both"):
|
|
print "[INFO]\tOpening", filePath
|
|
tree.Add(filePath)
|
|
print "[INFO]\tOpening", filePath2
|
|
tree.Add(filePath2)
|
|
else:
|
|
print "[INFO]\tOpening", filePath
|
|
tree.Add(filePath)
|
|
|
|
|
|
def addTMathTags(varName):
|
|
for expr in expressionList():
|
|
varName = varName.replace(expr,"TMath::"+expr)
|
|
return varName
|
|
|
|
def list_of_DTF_vars ():
|
|
return [
|
|
"_PT",
|
|
"_PX",
|
|
"_PY",
|
|
"_PZ",
|
|
"_PE",
|
|
"_P"
|
|
"_ETA" ,
|
|
"_MM",
|
|
"B_plus_M" ,
|
|
"K_star_plus_M" ,
|
|
"pi_zero_resolved_plus_M"
|
|
]
|
|
|
|
def replace_variables_to_DTF(variable = ""):
|
|
|
|
#Append "_DTF" to everything in the list above by
|
|
for var in list_of_DTF_vars():
|
|
if (variable.find(var) != -1):
|
|
positions = [i.start() for i in re.finditer(var, variable)]
|
|
#print positions
|
|
for i in range(len(positions)):
|
|
pos=positions[i]
|
|
variable = variable[:pos+len(var)] + "_DTF" + variable[pos+len(var):]
|
|
positions = [x+4 for x in positions]
|
|
|
|
|
|
#Remove false DTF variales, such as MinIP (searching for _M)
|
|
removeList = re.findall('DTF[A-Z]', variable)
|
|
#print removeList
|
|
for remove in removeList:
|
|
positions = [i.start() for i in re.finditer(remove, variable)]
|
|
for i in range(len(positions)):
|
|
pos=positions[i]
|
|
variable = variable[:pos-1] + variable[pos+3:]
|
|
positions = [x-4 for x in positions]
|
|
|
|
return variable
|
|
|
|
|
|
def getListOfUsedVariables(variable, cut):
|
|
tmp = str(variable) + "|" + str(cut) #| is there as a separator
|
|
|
|
tmp = tmp.replace("gamma1","gammaa")
|
|
tmp = tmp.replace("gamma2","gammab") #Protect from removing numbers
|
|
|
|
tmp = re.sub(r'[0-9]+', '', tmp) #remove numbers
|
|
|
|
tmp = tmp.replace("gammaa","gamma1")
|
|
tmp = tmp.replace("gammab","gamma2") #Protect from removing numbers
|
|
|
|
tmp = tmp.replace("CHI","CHI2") #check CHI2 numbers
|
|
tmp = tmp.replace("DOCA","DOCA1") #check CHI2 numbers
|
|
tmp = tmp.replace("Q","Q2") #check Q2 numbers #TODO
|
|
tmp = tmp.replace(".","") #remove decimals left from numbers
|
|
tmp = tmp.replace("-","|") #remove minus from negative numbers, keep an operator
|
|
|
|
tmp = tmp.replace("TMath::","") #remove functions
|
|
|
|
for expr in expressionList():
|
|
tmp = tmp.replace(expr,"") #Remove expressions
|
|
tmp = tmp.replace(expr.lower(),"") #remove expressions without capital
|
|
|
|
tmp = tmp.replace("<=","<")
|
|
tmp = tmp.replace(">=",">")
|
|
tmp = tmp.replace("==","=")
|
|
tmp = tmp.replace("&&","&")
|
|
tmp = tmp.replace("||","|")
|
|
tmp = tmp.replace("!","")
|
|
|
|
#tmp = re.sub(r"\s+", "", tmp) #Removes whitespaces, s matches all whitespaces
|
|
branchList = re.split('[+ - * / ( ) < > = & | ]', tmp)
|
|
branchList = filter(None, branchList) #removes empty strings
|
|
branchList = np.unique(branchList) #Removes duplicates
|
|
|
|
return branchList
|
|
|
|
|
|
def evaluateCut(cut,variablesDict):
|
|
#TODO: should be easy to let it be able take operations into account
|
|
if (cut == ""): return True
|
|
tmp = str(cut)
|
|
for varName,varValue in variablesDict.items():
|
|
tmp = tmp.replace(str(varName),str(varValue[0]))
|
|
tmp = tmp.replace ("||"," or ")
|
|
tmp = tmp.replace ("&&"," and ")
|
|
tmp = tmp.replace ("="," == ")
|
|
tmp = tmp.replace ("! =="," != ") #in case
|
|
#print "[DEBUG]\t\t", tmp
|
|
return eval(tmp)
|
|
|
|
def makeVariablePythonFriendly(variable):
|
|
tmp = variable
|
|
tmp = tmp.replace("TMath::","") #remove ROOT tags
|
|
tmp = tmp.lower() #replaces e.g. Log by log and so on
|
|
return tmp
|
|
|
|
def evaluateVariable(variable,variablesDict):
|
|
tmp = variable
|
|
for varName,varValue in variablesDict.items():
|
|
tmp = tmp.replace(str(varName),str(varValue[0]))
|
|
tmp = makeVariablePythonFriendly(tmp)
|
|
return numexpr.evaluate(tmp).item()
|
|
|
|
def evaluateWeight(variablesDict,optionsDict): #TODO
|
|
if (optionsDict["sWeighted"]): return variablesDict["N_Bplus_sw"][0]
|
|
elif (optionsDict["bWeighted"]): return variablesDict["weight_nLongTracks"][0]
|
|
elif (optionsDict["b2Dweighted"]): return variablesDict["weight2D_nLongTracks"][0]
|
|
else: return 1.0
|
|
|
|
|
|
def datasetTag(optionsDict):
|
|
tag = ""
|
|
if (optionsDict['MC']):
|
|
if (optionsDict['ReferenceChannel']):
|
|
tag = "RefChannel"
|
|
elif (optionsDict['PHSP']):
|
|
tag = "PHSP"
|
|
else:
|
|
tag = "MC"
|
|
if (optionsDict['TM']):
|
|
tag = tag + "_TM"
|
|
else:
|
|
tag = "data"
|
|
if not (optionsDict['Preselected']):
|
|
tag = tag + "_Strip"
|
|
return tag
|
|
|
|
def weightTag(optionsDict):
|
|
tag = ""
|
|
if (optionsDict['sWeighted']): tag = "_sWeighted"
|
|
if (optionsDict['bWeighted']): tag = "_1DWeight"
|
|
if (optionsDict['b2Dweighted']): tag = "_2DWeight"
|
|
return tag
|
|
|
|
def KshortDecaysInVeloTag(KshortDecaysInVelo=False):
|
|
return "" if not KshortChannel() else ("_LL" if KshortDecaysInVelo else "_DD" )
|
|
|
|
def variableTag(variable=""):
|
|
name = variable.replace("TMath::","")
|
|
name = name.replace("(","")
|
|
name = name.replace(")","")
|
|
name = name.replace("|","")
|
|
name = name.replace("/","_over_")
|
|
name = name.replace("*","_x_")
|
|
return name
|
|
|
|
|
|
def histName(variable, optionsDict):
|
|
name = variableTag(variable)
|
|
name = name.replace("TMath::","") #remove functions
|
|
for expr in (expressionList()): #For whatever reason I have to but the brackets there
|
|
name = name.replace(expr.lower(),expr) #Add capitals to functions
|
|
|
|
name = "Hist_" + str(optionsDict['year']) + "_" + datasetTag(optionsDict)
|
|
name = name + KshortDecaysInVeloTag(optionsDict) + weightTag(optionsDict)
|
|
return name
|
|
|
|
|
|
def stopWatch(value):
|
|
'''From seconds to Days;Hours:Minutes;Seconds'''
|
|
|
|
valueD = (((value/365)/24)/60)
|
|
Days = int (valueD)
|
|
|
|
valueH = (valueD-Days)*365
|
|
Hours = int(valueH)
|
|
|
|
valueM = (valueH - Hours)*24
|
|
Minutes = int(valueM)
|
|
|
|
valueS = (valueM - Minutes)*60
|
|
Seconds = int(valueS)
|
|
|
|
|
|
print Days,";",Hours,":",Minutes,";",Seconds
|
|
|
|
|
|
class ShowArgumentsParser(argparse.ArgumentParser):
|
|
def error(self, message):
|
|
sys.stderr.write('error: %s\n\n' %message)
|
|
parser.print_usage(sys.stderr)
|
|
sys.stderr.write('\n'+self.description)
|
|
sys.exit(2)
|
|
|
|
def checkMCyear(year, ReferenceChannel, PHSP):
|
|
if ((not KshortChannel()) and (not ReferenceChannel) and (not PHSP) and year == 2015): return 2016
|
|
else: return year
|
|
|