Angular analysis of B+->K*+(K+pi0)mumu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

357 lines
13 KiB

  1. from ROOT import gROOT, gDirectory, gStyle, TChain, TTree, TAxis, TH1D
  2. import subprocess
  3. import time
  4. import numpy as np
  5. import re #for splitting with multiple deliminers
  6. from array import array
  7. import numexpr
  8. import argparse
  9. import sys
  10. import os
  11. import re
  12. from Globals import *
  13. '''
  14. Tools used in compareUlitmate.py
  15. '''
  16. #Define a list of variables that are considered integers
  17. intVarsList = ["nTracks"
  18. ,"nLongTracks"
  19. ,"nVeloTracks"
  20. ,"nTTracks"
  21. ,"nDownstreamTracks"
  22. ,"nUpstreamTracks"
  23. ,"nCandidate"
  24. ,"totCandidates"
  25. ,"nSPDHits"
  26. ,"nPV"
  27. ,"B_plus_ID"
  28. ,"B_plus_TRUEID"
  29. ,"K_star_plus_ID"
  30. ,"K_plus_ID"
  31. ,"pi_zero_resolved_ID"
  32. ,"mu_plus_ID"
  33. ,"mu_minus_ID"
  34. ,"Polarity"
  35. ,"nDiMuonMassBin"
  36. ,"TMedBKGCAT"
  37. ]
  38. def expressionList():
  39. return ["Sqrt"
  40. ,"Abs"
  41. ,"Sin"
  42. ,"Cos"
  43. ,"Exp"
  44. ,"Log"
  45. ]
  46. #Define a function that returns true for variables that are integers
  47. def isInt(variable=""):
  48. if variable in intVarsList:
  49. return True
  50. else:
  51. return False
  52. def treeName(MC=False, TM=False, Preselected=False):
  53. if (TM or (MC and Preselected)): #TODO
  54. return "DecayTreeTruthMatched"
  55. elif (not Preselected):
  56. return "b2KstKs0pimumu_Tuple" if KshortChannel() else "b2KstKpi0mumuResolvedTuple/DecayTree"
  57. else:
  58. return "DecayTree"
  59. def getOptionsDictionary(year, Run, magnet, MC, TM, ReferenceChannel, PHSP, Preselected,
  60. BDTed, sWeighted, bWeighted, b2Dweighted, weightBranch, KshortDecaysInVelo, UseLowQ2Range):
  61. dictionaryTmp = {
  62. 'year': year,
  63. 'Run' : Run,
  64. 'magnet' : magnet,
  65. 'MC' : int(MC),
  66. 'TM' : int(TM),
  67. 'ReferenceChannel' : int(ReferenceChannel),
  68. 'PHSP' : int(PHSP),
  69. 'Preselected' : int(Preselected),
  70. 'BDTed' : BDTed,
  71. 'sWeighted' : sWeighted,
  72. 'bWeighted' : bWeighted,
  73. 'b2Dweighted' : b2Dweighted,
  74. 'weightBranch' : weightBranch,
  75. 'KshortDecaysInVelo' : int(KshortDecaysInVelo),
  76. 'UseLowQ2Range' : UseLowQ2Range
  77. }
  78. return dictionaryTmp
  79. def checkYearSample(optionsDict): #If wrong year/MC, skip
  80. if optionsDict['year'] not in yearList(): return False, "Wrong Year!"
  81. if (not optionsDict['MC']): return True, ""
  82. else:
  83. if (KshortChannel()):
  84. if (optionsDict['PHSP']): return True, ""
  85. elif (optionsDict['ReferenceChannel']):
  86. if (optionsDict['year'] < 2013 or optionsDict['year'] == 2016): return True, "" #Referenche channel available only for Run I
  87. else: return False, "RefChannel only available for Run I!"
  88. else: return True, ""
  89. else:
  90. if (optionsDict['PHSP']):
  91. if (optionsDict['year'] < 2018): return True, ""
  92. else: return False, ""
  93. elif (optionsDict['ReferenceChannel']):
  94. if (optionsDict['year'] < 2017): return True, "" #Referenche channel available only for Run I
  95. else: return False, "RefChannel only available for < 2017!"
  96. else:
  97. if (optionsDict['year'] > 2017):
  98. return False, "No MC for 2018!"
  99. else: return True, ""
  100. def getTreePath(optionsDict, verbose):
  101. #getPathForPython usage:
  102. # getPathForPython command year Run magnet Preselected MC ReferenceChannel PHSP KshortDecayInVelo Selection UseLowQ2Range
  103. #It has to have everything to keep it easy
  104. #Get first file name
  105. filePath2 = ""
  106. command = "/home/lhcb/kopecna/B2KstarMuMu/code/ewp-Bplus2Kstmumu-AngAna/CodeForTests/CompareUltimate/getPathForPython " #TODO maybe replace by a current path
  107. if(optionsDict['BDTed']):
  108. options = "BDToutput %(year)i %(Run)i %(magnet)s 0 %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
  109. if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
  110. #Read second line from the c++ script (first one is the Hello...)
  111. filePath = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
  112. elif (optionsDict['sWeighted'] or optionsDict['bWeighted'] or optionsDict['b2Dweighted']):
  113. options = "BDTinput %(year)i %(Run)i %(magnet)s 0 %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
  114. if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
  115. #Read second line from the c++ script (first one is the Hello...)
  116. filePath = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
  117. else:
  118. if (optionsDict['magnet']=="both"):
  119. #down
  120. options = "input %(year)i %(Run)i down %(Preselected)r %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
  121. if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
  122. filePath = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
  123. #up
  124. options = "input %(year)i %(Run)i up %(Preselected)r %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
  125. if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
  126. filePath2 = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
  127. else:
  128. options = "input %(year)i %(Run)i %(magnet)s %(Preselected)r %(MC)r %(ReferenceChannel)r %(PHSP)r %(KshortDecaysInVelo)r 0 %(UseLowQ2Range)r" %optionsDict
  129. if verbose: print "[DEBUG]\t\tRunning a c++ script to get the name of the file to open: ", command + options
  130. filePath = subprocess.check_output(command + options, shell=True,universal_newlines=True).split('\n')[1]
  131. return filePath, filePath2
  132. def addToTChain(tree, optionsDict, verbose):
  133. filePath, filePath2 = getTreePath(optionsDict=optionsDict, verbose=verbose)
  134. #Get first file name
  135. if(optionsDict['BDTed'] or optionsDict['sWeighted'] or optionsDict['bWeighted'] or optionsDict['b2Dweighted']):
  136. print "[INFO]\tOpening", filePath
  137. tree.Add(filePath)
  138. else:
  139. if (optionsDict['magnet']=="both"):
  140. print "[INFO]\tOpening", filePath
  141. tree.Add(filePath)
  142. print "[INFO]\tOpening", filePath2
  143. tree.Add(filePath2)
  144. else:
  145. print "[INFO]\tOpening", filePath
  146. tree.Add(filePath)
  147. def addTMathTags(varName):
  148. for expr in expressionList():
  149. varName = varName.replace(expr,"TMath::"+expr)
  150. return varName
  151. def list_of_DTF_vars ():
  152. return [
  153. "_PT",
  154. "_PX",
  155. "_PY",
  156. "_PZ",
  157. "_PE",
  158. "_P"
  159. "_ETA" ,
  160. "_MM",
  161. "B_plus_M" ,
  162. "K_star_plus_M" ,
  163. "pi_zero_resolved_plus_M"
  164. ]
  165. def replace_variables_to_DTF(variable = ""):
  166. #Append "_DTF" to everything in the list above by
  167. for var in list_of_DTF_vars():
  168. if (variable.find(var) != -1):
  169. positions = [i.start() for i in re.finditer(var, variable)]
  170. #print positions
  171. for i in range(len(positions)):
  172. pos=positions[i]
  173. variable = variable[:pos+len(var)] + "_DTF" + variable[pos+len(var):]
  174. positions = [x+4 for x in positions]
  175. #Remove false DTF variales, such as MinIP (searching for _M)
  176. removeList = re.findall('DTF[A-Z]', variable)
  177. #print removeList
  178. for remove in removeList:
  179. positions = [i.start() for i in re.finditer(remove, variable)]
  180. for i in range(len(positions)):
  181. pos=positions[i]
  182. variable = variable[:pos-1] + variable[pos+3:]
  183. positions = [x-4 for x in positions]
  184. return variable
  185. def getListOfUsedVariables(variable, cut):
  186. tmp = str(variable) + "|" + str(cut) #| is there as a separator
  187. tmp = tmp.replace("gamma1","gammaa")
  188. tmp = tmp.replace("gamma2","gammab") #Protect from removing numbers
  189. tmp = re.sub(r'[0-9]+', '', tmp) #remove numbers
  190. tmp = tmp.replace("gammaa","gamma1")
  191. tmp = tmp.replace("gammab","gamma2") #Protect from removing numbers
  192. tmp = tmp.replace("CHI","CHI2") #check CHI2 numbers
  193. tmp = tmp.replace("DOCA","DOCA1") #check CHI2 numbers
  194. tmp = tmp.replace("Q","Q2") #check Q2 numbers #TODO
  195. tmp = tmp.replace(".","") #remove decimals left from numbers
  196. tmp = tmp.replace("-","|") #remove minus from negative numbers, keep an operator
  197. tmp = tmp.replace("TMath::","") #remove functions
  198. for expr in expressionList():
  199. tmp = tmp.replace(expr,"") #Remove expressions
  200. tmp = tmp.replace(expr.lower(),"") #remove expressions without capital
  201. tmp = tmp.replace("<=","<")
  202. tmp = tmp.replace(">=",">")
  203. tmp = tmp.replace("==","=")
  204. tmp = tmp.replace("&&","&")
  205. tmp = tmp.replace("||","|")
  206. tmp = tmp.replace("!","")
  207. #tmp = re.sub(r"\s+", "", tmp) #Removes whitespaces, s matches all whitespaces
  208. branchList = re.split('[+ - * / ( ) < > = & | ]', tmp)
  209. branchList = filter(None, branchList) #removes empty strings
  210. branchList = np.unique(branchList) #Removes duplicates
  211. return branchList
  212. def evaluateCut(cut,variablesDict):
  213. #TODO: should be easy to let it be able take operations into account
  214. if (cut == ""): return True
  215. tmp = str(cut)
  216. for varName,varValue in variablesDict.items():
  217. tmp = tmp.replace(str(varName),str(varValue[0]))
  218. tmp = tmp.replace ("||"," or ")
  219. tmp = tmp.replace ("&&"," and ")
  220. tmp = tmp.replace ("="," == ")
  221. tmp = tmp.replace ("! =="," != ") #in case
  222. #print "[DEBUG]\t\t", tmp
  223. return eval(tmp)
  224. def makeVariablePythonFriendly(variable):
  225. tmp = variable
  226. tmp = tmp.replace("TMath::","") #remove ROOT tags
  227. tmp = tmp.lower() #replaces e.g. Log by log and so on
  228. return tmp
  229. def evaluateVariable(variable,variablesDict):
  230. tmp = variable
  231. for varName,varValue in variablesDict.items():
  232. tmp = tmp.replace(str(varName),str(varValue[0]))
  233. tmp = makeVariablePythonFriendly(tmp)
  234. return numexpr.evaluate(tmp).item()
  235. def evaluateWeight(variablesDict,optionsDict): #TODO
  236. if (optionsDict["sWeighted"]): return variablesDict["N_Bplus_sw"][0]
  237. elif (optionsDict["bWeighted"]): return variablesDict["weight_nLongTracks"][0]
  238. elif (optionsDict["b2Dweighted"]): return variablesDict["weight2D_nLongTracks"][0]
  239. else: return 1.0
  240. def datasetTag(optionsDict):
  241. tag = ""
  242. if (optionsDict['MC']):
  243. if (optionsDict['ReferenceChannel']):
  244. tag = "RefChannel"
  245. elif (optionsDict['PHSP']):
  246. tag = "PHSP"
  247. else:
  248. tag = "MC"
  249. if (optionsDict['TM']):
  250. tag = tag + "_TM"
  251. else:
  252. tag = "data"
  253. if not (optionsDict['Preselected']):
  254. tag = tag + "_Strip"
  255. return tag
  256. def weightTag(optionsDict):
  257. tag = ""
  258. if (optionsDict['sWeighted']): tag = "_sWeighted"
  259. if (optionsDict['bWeighted']): tag = "_1DWeight"
  260. if (optionsDict['b2Dweighted']): tag = "_2DWeight"
  261. return tag
  262. def KshortDecaysInVeloTag(KshortDecaysInVelo=False):
  263. return "" if not KshortChannel() else ("_LL" if KshortDecaysInVelo else "_DD" )
  264. def variableTag(variable=""):
  265. name = variable.replace("TMath::","")
  266. name = name.replace("(","")
  267. name = name.replace(")","")
  268. name = name.replace("|","")
  269. name = name.replace("/","_over_")
  270. name = name.replace("*","_x_")
  271. return name
  272. def histName(variable, optionsDict):
  273. name = variableTag(variable)
  274. name = name.replace("TMath::","") #remove functions
  275. for expr in (expressionList()): #For whatever reason I have to but the brackets there
  276. name = name.replace(expr.lower(),expr) #Add capitals to functions
  277. name = "Hist_" + str(optionsDict['year']) + "_" + datasetTag(optionsDict)
  278. name = name + KshortDecaysInVeloTag(optionsDict) + weightTag(optionsDict)
  279. return name
  280. def stopWatch(value):
  281. '''From seconds to Days;Hours:Minutes;Seconds'''
  282. valueD = (((value/365)/24)/60)
  283. Days = int (valueD)
  284. valueH = (valueD-Days)*365
  285. Hours = int(valueH)
  286. valueM = (valueH - Hours)*24
  287. Minutes = int(valueM)
  288. valueS = (valueM - Minutes)*60
  289. Seconds = int(valueS)
  290. print Days,";",Hours,":",Minutes,";",Seconds
  291. class ShowArgumentsParser(argparse.ArgumentParser):
  292. def error(self, message):
  293. sys.stderr.write('error: %s\n\n' %message)
  294. parser.print_usage(sys.stderr)
  295. sys.stderr.write('\n'+self.description)
  296. sys.exit(2)
  297. def checkMCyear(year, ReferenceChannel, PHSP):
  298. if ((not KshortChannel()) and (not ReferenceChannel) and (not PHSP) and year == 2015): return 2016
  299. else: return year