Belle II Software  release-06-01-15
taupair.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 """ Skim list building functions for tau-pair analyses """
13 
14 import modularAnalysis as ma
15 from skim.standardlists.lightmesons import (loadStdAllF_0, loadStdAllKstar0,
16  loadStdAllPhi, loadStdAllRho0)
17 from skim import BaseSkim, fancy_skim_header
18 from stdCharged import stdE, stdK, stdMu, stdPi, stdPr
19 from stdPhotons import stdPhotons
20 from variables import variables as vm
21 
22 __liaison__ = "Kenji Inami <kenji.inami@desy.de>"
23 _VALIDATION_SAMPLE = "mdst14.root"
24 
25 
26 def tauskim_particle_selection(label, path):
27  # Track
28  trackCuts = "-3.0 < dz < 3.0 and dr < 1.0"
29  ma.cutAndCopyList(f"pi+:{label}", "pi+:all", trackCuts, path=path)
30 
31  # pi0
32 
33  gammaDetectorLocation = {
34  "FWD": "clusterReg == 1",
35  "BRL": "clusterReg == 2",
36  "BWD": "clusterReg == 3"
37  }
38 
39  gammaForPi0lists = []
40  for g in gammaDetectorLocation.keys():
41  gammaForPi0Cuts = gammaDetectorLocation[g]
42  gammaForPi0Cuts += ' and abs(clusterTiming) < 200'
43  gammaForPi0Cuts += ' and thetaInCDCAcceptance'
44  gammaForPi0Cuts += ' and clusterNHits > 1.5'
45  gammaForPi0Cuts += ' and [[minC2TDist > 40] or [E > 0.4]]' # new
46  gammaForPi0 = f'gamma:looseForPi0{label}{g}'
47  gammaForPi0lists.append(gammaForPi0)
48  ma.cutAndCopyLists(gammaForPi0, 'gamma:all', gammaForPi0Cuts, path=path)
49 
50  # -# -- -- cos of opening angle between the photons
51  vm.addAlias(
52  'cosAngle2Photons',
53  'formula((daughter(0, px) * daughter(1, px) + '
54  'daughter(0, py) * daughter(1, py) + '
55  'daughter(0, pz) * daughter(1, pz) ) / daughter(0, p) / daughter(1, p) )')
56 
57  vm.addAlias('leadingclusterE', 'formula(max(daughter(0, clusterE),daughter(1, clusterE)))')
58  vm.addAlias('subleadingclusterE', 'formula(min(daughter(0, clusterE),daughter(1, clusterE)))')
59 
60  # Determine pi0 reco for individual Detector Parts
61  Pi0CutLabel = ["leadingclusterE", "subleadingclusterE", "cosAngle2Photons", "p"]
62  Pi0CutValue = {
63  "FWD,FWD": [0.5625, 0.1625, 0.9458, 0.9444],
64  "BRL,BRL": [0.4125, 0.0625, 0.8875, 0.6333],
65  "BWD,BWD": [0.4125, 0.1125, 0.8708, 0.6111],
66  "BRL,FWD": [0.3625, 0.0875, 0.8875, 0.5889],
67  "BRL,BWD": [0.3625, 0.0875, 0.8875, 0.5889]
68  }
69 
70  Pi0lists = []
71  for cut in Pi0CutValue.keys():
72  gammalists = cut.split(",")
73  CurrentPi0List = f'pi0:fromLooseGammas{label}{gammalists[0]}{gammalists[1]}'
74  Pi0lists.append(CurrentPi0List)
75  Pi0Cut = '0.115 < M < 0.152'
76  for i, c in enumerate(Pi0CutLabel):
77  Pi0Cut += f' and {c} > {Pi0CutValue[cut][i]}'
78 
79  ma.reconstructDecay(f'{CurrentPi0List} -> gamma:looseForPi0{label}{gammalists[0]} gamma:looseForPi0{label}{gammalists[1]}',
80  Pi0Cut, path=path)
81 
82  ma.copyLists(f'pi0:{label}', Pi0lists, path=path)
83 
84  # gamma
85  gammaCuts = 'E > 0.2'
86  gammaCuts += ' and [[minC2TDist > 40] or [E > 0.4]]'
87  gammaCuts += ' and abs(clusterTiming) < 200'
88  gammaCuts += ' and thetaInCDCAcceptance'
89  gammaCuts += ' and clusterNHits > 1.5'
90  gammaCuts += f' and isDescendantOfList(pi0:{label}) == 0'
91  ma.cutAndCopyList(f'gamma:{label}', 'gamma:all', gammaCuts, path=path)
92 
93 
94 @fancy_skim_header
96  """
97  **Channel**: :math:`\\tau \\to l \\gamma, lll, l \\pi^0, l V^0, lhh, llp, phh`
98 
99  **Output particle lists**: ``e+:taulfv, mu+:taulfv, pi+:taulfv, K+:taulfv, p+:taulfv``,
100  ``gamma:taulfv, pi0:taulfv, K_S0:taulfv, eta:taulfv, eta':taulfv``,
101  ``omega:taulfv``
102 
103  **Criteria for 1 prong final states**: Number of good tracks < 5, :math:`1.0 < M < 2.0` GeV, :math:`-1.5 < \\Delta E < 0.5` GeV
104 
105  **Criteria for >1 prong final states**: Number of good tracks < 7, :math:`1.4 < M < 2.0` GeV, :math:`-1.0 < \\Delta E < 0.5` GeV
106  """
107  __authors__ = ["Kenji Inami"]
108  __description__ = "Skim for Tau LFV decays."
109  __contact__ = __liaison__
110  __category__ = "physics, tau"
111 
112  produce_on_tau_samples = False # retention is too high on taupair
113  validation_sample = _VALIDATION_SAMPLE
114 
115  def load_standard_lists(self, path):
116  stdE("all", path=path)
117  stdK("all", path=path)
118  stdMu("all", path=path)
119  stdPi("all", path=path)
120  stdPr("all", path=path)
121  stdPhotons("all", path=path, loadPhotonBeamBackgroundMVA=False)
122  loadStdAllRho0(path=path)
123  loadStdAllKstar0(path=path)
124  loadStdAllPhi(path=path)
125  loadStdAllF_0(path=path)
126 
127  def build_lists(self, path):
128  # particle selection
129  trackCuts = "-3.0 < dz < 3.0 and dr < 1.0"
130  ma.cutAndCopyList("e+:taulfv", "e+:all", trackCuts, path=path)
131  ma.cutAndCopyList("mu+:taulfv", "mu+:all", trackCuts, path=path)
132  ma.cutAndCopyList("pi+:taulfv", "pi+:all", trackCuts, path=path)
133  ma.cutAndCopyList("K+:taulfv", "K+:all", trackCuts, path=path)
134  ma.cutAndCopyList("p+:taulfv", "p+:all", trackCuts, path=path)
135 
136  ma.reconstructDecay("K_S0:taulfv -> pi+:all pi-:all", "0.3 < M < 0.7", path=path)
137 
138  gammaCuts = "E > 0.20 and clusterNHits > 1.5 and thetaInCDCAcceptance"
139  ma.cutAndCopyList("gamma:taulfv", "gamma:all", gammaCuts, path=path)
140 
141  gammaLooseCuts = "E > 0.1 and thetaInCDCAcceptance and clusterNHits > 1.5"
142  ma.cutAndCopyLists("gamma:taulfvloose", "gamma:all", gammaLooseCuts, path=path)
143  # pi0
144  ma.reconstructDecay("pi0:taulfv -> gamma:taulfvloose gamma:taulfvloose", "0.115 < M < 0.152", path=path)
145  # eta
146  ma.reconstructDecay("eta:taulfv1 -> gamma:taulfvloose gamma:taulfvloose", "0.4 < M < 0.6", path=path)
147  ma.reconstructDecay("eta:taulfv2 -> pi0:taulfv pi-:all pi+:all", "0.4 < M < 0.6", path=path)
148  ma.copyLists("eta:taulfv", ["eta:taulfv1", "eta:taulfv2"], path=path)
149  # eta"
150  ma.reconstructDecay("eta':taulfv1 -> pi+:all pi-:all gamma:taulfvloose", "0.8 < M < 1.1", path=path)
151  ma.reconstructDecay("eta':taulfv2 -> pi+:all pi-:all eta:taulfv", "0.8 < M < 1.1", path=path)
152  ma.copyLists("eta':taulfv", ["eta':taulfv1", "eta':taulfv2"], path=path)
153  # omega
154  ma.reconstructDecay("omega:taulfv -> pi0:taulfv pi-:all pi+:all", "0.73 < M < 0.83", path=path)
155 
156  # event selection
157  vm.addAlias("netChargeLFV", "formula(countInList(pi+:taulfv, charge == 1) - countInList(pi+:taulfv, charge == -1))")
158  tauLFVCuts1 = "nParticlesInList(pi+:taulfv) < 5 and 1.0 < M < 2.0 and -1.5 < deltaE < 0.5"
159  tauLFVCuts3 = "nParticlesInList(pi+:taulfv) < 7 and 1.4 < M < 2.0 and -1.0 < deltaE < 0.5"
160 
161  tau_lgamma_Channels = ["e+:taulfv gamma:taulfv",
162  "mu+:taulfv gamma:taulfv"
163  ]
164 
165  tau_lll_Channels = ["e+:taulfv e+:taulfv e-:taulfv",
166  "mu+:taulfv mu+:taulfv mu-:taulfv",
167  "mu+:taulfv e+:taulfv e-:taulfv",
168  "e+:taulfv mu+:taulfv mu-:taulfv",
169  "e+:taulfv e+:taulfv mu-:taulfv",
170  "mu+:taulfv mu+:taulfv e-:taulfv"
171  ]
172 
173  tau_lP01_Channels = ["e+:taulfv pi0:taulfv",
174  "mu+:taulfv pi0:taulfv",
175  "e+:taulfv eta:taulfv1",
176  "mu+:taulfv eta:taulfv1"
177  ]
178  tau_lP03_Channels = ["e+:taulfv eta:taulfv2",
179  "mu+:taulfv eta:taulfv2",
180  "e+:taulfv eta':taulfv",
181  "mu+:taulfv eta':taulfv",
182  "e+:taulfv K_S0:taulfv",
183  "mu+:taulfv K_S0:taulfv"
184  ]
185 
186  tau_lS0_Channels = ["e+:taulfv f_0:all",
187  "mu+:taulfv f_0:all"
188  ]
189 
190  tau_lV0_Channels = ["e+:taulfv rho0:all",
191  "mu+:taulfv rho0:all",
192  "e+:taulfv K*0:all",
193  "mu+:taulfv K*0:all",
194  "e+:taulfv anti-K*0:all",
195  "mu+:taulfv anti-K*0:all",
196  "e+:taulfv phi:all",
197  "mu+:taulfv phi:all",
198  "e+:taulfv omega:taulfv",
199  "mu+:taulfv omega:taulfv"
200  ]
201 
202  tau_lhh_Channels = ["e+:taulfv pi-:taulfv pi+:taulfv",
203  "mu+:taulfv pi-:taulfv pi+:taulfv",
204  "e-:taulfv pi+:taulfv pi+:taulfv",
205  "mu-:taulfv pi+:taulfv pi+:taulfv",
206  "e+:taulfv K-:taulfv K+:taulfv",
207  "mu+:taulfv K-:taulfv K+:taulfv",
208  "e-:taulfv K+:taulfv K+:taulfv",
209  "mu-:taulfv K+:taulfv K+:taulfv",
210  "e+:taulfv K-:taulfv pi+:taulfv",
211  "mu+:taulfv K-:taulfv pi+:taulfv",
212  "e-:taulfv K+:taulfv pi+:taulfv",
213  "mu-:taulfv K+:taulfv pi+:taulfv",
214  "e+:taulfv K_S0:taulfv K_S0:taulfv",
215  "mu+:taulfv K_S0:taulfv K_S0:taulfv"
216  ]
217 
218  tau_bnv_Channels = ["mu+:taulfv mu+:taulfv anti-p-:taulfv",
219  "mu-:taulfv mu+:taulfv p+:taulfv",
220  "anti-p-:taulfv pi+:taulfv pi+:taulfv",
221  "p+:taulfv pi-:taulfv pi+:taulfv",
222  "anti-p-:taulfv pi+:taulfv K+:taulfv",
223  "p+:taulfv pi-:taulfv K+:taulfv"
224  ]
225 
226  tau_lgamma_list = []
227  for chID, channel in enumerate(tau_lgamma_Channels):
228  ma.reconstructDecay("tau+:LFV_lgamma" + str(chID) + " -> " + channel, tauLFVCuts1, chID, path=path)
229  tau_lgamma_list.append("tau+:LFV_lgamma" + str(chID))
230 
231  tau_lll_list = []
232  for chID, channel in enumerate(tau_lll_Channels):
233  ma.reconstructDecay("tau+:LFV_lll" + str(chID) + " -> " + channel, tauLFVCuts3, chID, path=path)
234  tau_lll_list.append("tau+:LFV_lll" + str(chID))
235 
236  tau_lP0_list = []
237  for chID, channel in enumerate(tau_lP01_Channels):
238  ma.reconstructDecay("tau+:LFV_lP01" + str(chID) + " -> " + channel, tauLFVCuts1, chID, path=path)
239  tau_lP0_list.append("tau+:LFV_lP01" + str(chID))
240  for chID, channel in enumerate(tau_lP03_Channels):
241  ma.reconstructDecay("tau+:LFV_lP03" + str(chID) + " -> " + channel, tauLFVCuts3, chID, path=path)
242  tau_lP0_list.append("tau+:LFV_lP03" + str(chID))
243 
244  tau_lS0_list = []
245  for chID, channel in enumerate(tau_lS0_Channels):
246  ma.reconstructDecay("tau+:LFV_lS0" + str(chID) + " -> " + channel, tauLFVCuts3, chID, path=path)
247  tau_lS0_list.append("tau+:LFV_lS0" + str(chID))
248 
249  tau_lV0_list = []
250  for chID, channel in enumerate(tau_lV0_Channels):
251  ma.reconstructDecay("tau+:LFV_lV0" + str(chID) + " -> " + channel, tauLFVCuts3, chID, path=path)
252  tau_lV0_list.append("tau+:LFV_lV0" + str(chID))
253 
254  tau_lhh_list = []
255  for chID, channel in enumerate(tau_lhh_Channels):
256  ma.reconstructDecay("tau+:LFV_lhh" + str(chID) + " -> " + channel, tauLFVCuts3, chID, path=path)
257  tau_lhh_list.append("tau+:LFV_lhh" + str(chID))
258 
259  tau_bnv_list = []
260  for chID, channel in enumerate(tau_bnv_Channels):
261  ma.reconstructDecay("tau+:LFV_bnv" + str(chID) + " -> " + channel, tauLFVCuts3, chID, path=path)
262  tau_bnv_list.append("tau+:LFV_bnv" + str(chID))
263 
264  return tau_lgamma_list + tau_lll_list + tau_lP0_list + tau_lS0_list + tau_lV0_list + tau_lhh_list + tau_bnv_list
265 
266  def validation_histograms(self, path):
267  # NOTE: the validation package is not part of the light releases, so this import
268  # must be made here rather than at the top of the file.
269  from validation_tools.metadata import create_validation_histograms
270 
271  ma.copyLists('tau+:LFV', self.SkimListsSkimListsSkimLists, path=path)
272 
273  # add contact information to histogram
274  contact = "kenji@hepl.phys.nagoya-u.ac.jp"
275 
276  # the variables that are printed out are: M, deltaE
277  create_validation_histograms(
278  rootfile=f'{self}_Validation.root',
279  particlelist='tau+:LFV',
280  variables_1d=[
281  ('M', 100, 1.00, 2.00, '', contact, '', ''),
282  ('deltaE', 120, -1.6, 0.6, '', contact, '', '')],
283  variables_2d=[('M', 50, 1.00, 2.00, 'deltaE', 60, -1.6, 0.6, '', contact, '', '')],
284  path=path)
285 
286 
287 @fancy_skim_header
289  """
290  **Channel**: :math:`e^+ e^- \\to \\tau^+ \\tau^-`
291 
292  **Criteria**:
293 
294  Ntrk = 2
295 
296  1. Number of good tracks = 2, net charge < 2
297  2. ``visibleEnergyOfEventCMS < 10 GeV and E_ECLtrk < 6 GeV`` and ``missingMomentumOfEvent_theta < 2.6180``
298  3. ``visibleEnergyOfEventCMS > 3 GeV or max P_t > 1 GeV``
299  4. max. opening angle < 178 deg.
300 
301  Ntrk = 3,4
302 
303  1. Number of good tracks = 3 or 4, net charge < 2
304  2. ``visibleEnergyOfEventCMS < 10.5 GeV and E_ECLtrk < 6 GeV``
305  3. ``visibleEnergyOfEventCMS > 3 GeV or max P_t > 1 GeV``
306  4. max. opening angle < 178 deg.
307  5. Event divided by thrust axis; No. good tracks in tag side = 1 or 3
308  6. ``M_tag < 1.8 GeV`` and ``M_sig < 2.3 GeV``
309 
310  Ntrk = 5,6
311 
312  1. Number of good tracks = 5 or 6, net charge < 2
313  2. Event divided by thrust axis; No. good tracks in tag side = 1 or 3
314  3. ``M_tag < 1.8 GeV`` and ``M_sig < 2.3 GeV``
315  """
316  __authors__ = ["Kenji Inami"]
317  __description__ = "Skim for Tau generic decays."
318  __contact__ = __liaison__
319  __category__ = "physics, tau"
320 
321  produce_on_tau_samples = False # retention is too high on taupair
322  validation_sample = _VALIDATION_SAMPLE
323 
324  def load_standard_lists(self, path):
325  stdPi("all", path=path)
326  stdPhotons("all", path=path, loadPhotonBeamBackgroundMVA=False)
327 
328  def additional_setup(self, path):
329  """
330  Set particle lists and variables for TauGeneric skim.
331 
332  **Output particle lists**: ``pi+:tauskim, pi0:tauskim, gamma:tauskim, pi+:S1/S2, pi0:S1/S2, gamma:S1/S2``
333 
334  **Variables**:
335 
336  * ``nGoodTracks``: number of good tracks in an event
337  * ``netCharge``: total net charge of good tracks
338  * ``nTracksS1/nTracksS2:`` number of good tracks in each hemisphere ``S1/S2`` divided by thrust axis
339  * ``invMS1/invMS2``: invariant mass of particles in each hemisphere
340  * ``maxPt``: maximum Pt amoung good tracks
341  * ``E_ECLtrk``: total ECL energy of good tracks
342  """
343 
344  tauskim_particle_selection("tauskim", path)
345 
346  # Get EventShape variables
347  ma.buildEventShape(["pi+:tauskim", "pi0:tauskim", "gamma:tauskim"],
348  allMoments=False, foxWolfram=False, cleoCones=False,
349  sphericity=False, jets=False, path=path)
350  ma.buildEventKinematics(["pi+:tauskim", "pi0:tauskim", "gamma:tauskim"], path=path)
351 
352  # Split in signal and tag
353  ma.cutAndCopyList("pi+:S1", "pi+:tauskim", "cosToThrustOfEvent > 0", path=path)
354  ma.cutAndCopyList("pi+:S2", "pi+:tauskim", "cosToThrustOfEvent < 0", path=path)
355  ma.cutAndCopyList("pi0:S1", "pi0:tauskim", "cosToThrustOfEvent > 0", path=path)
356  ma.cutAndCopyList("pi0:S2", "pi0:tauskim", "cosToThrustOfEvent < 0", path=path)
357  ma.cutAndCopyList("gamma:S1", "gamma:tauskim", "cosToThrustOfEvent > 0", path=path)
358  ma.cutAndCopyList("gamma:S2", "gamma:tauskim", "cosToThrustOfEvent < 0", path=path)
359 
360  vm.addAlias("nGoodTracks", "nParticlesInList(pi+:tauskim)")
361  vm.addAlias("netCharge", "formula(countInList(pi+:tauskim, charge == 1) - countInList(pi+:tauskim, charge == -1))")
362  vm.addAlias("nTracksS1", "nParticlesInList(pi+:S1)")
363  vm.addAlias("nTracksS2", "nParticlesInList(pi+:S2)")
364  vm.addAlias("invMS1", "invMassInLists(pi+:S1, pi0:S1, gamma:S1)")
365  vm.addAlias("invMS2", "invMassInLists(pi+:S2, pi0:S2, gamma:S2)")
366  # vm.addAlias("Evis", "visibleEnergyOfEventCMS")
367  vm.addAlias("maxPt", "maxPtInList(pi+:tauskim)")
368  vm.addAlias("E_ECLtrk", "formula(totalECLEnergyOfParticlesInList(pi+:tauskim))")
369  vm.addAlias("maxOp", "useCMSFrame(maxOpeningAngleInList(pi+:tauskim))")
370 
371  def build_lists(self, path):
372  # reconstruct with each Ntrk case
373  ma.reconstructDecay('tau+:g2 -> pi+:S1', 'nGoodTracks == 2 and -2 < netCharge <2', path=path)
374  ma.reconstructDecay('tau+:g34 -> pi+:S1', '[nGoodTracks == 3 or nGoodTracks == 4] and -2 < netCharge <2', path=path)
375  ma.reconstructDecay('tau+:g56 -> pi+:S1', '[nGoodTracks == 5 or nGoodTracks == 6] and -2 < netCharge <2', path=path)
376 
377  # Selection criteria
378  # Ntrk=2
379  ma.applyCuts('tau+:g2', 'visibleEnergyOfEventCMS < 10', path=path)
380  ma.applyCuts('tau+:g2', 'E_ECLtrk < 6', path=path)
381  ma.applyCuts('tau+:g2', 'missingMomentumOfEvent_theta < 2.6180', path=path)
382  ma.applyCuts('tau+:g2', 'visibleEnergyOfEventCMS > 3 or maxPt > 1', path=path)
383  ma.applyCuts('tau+:g2', 'maxOp < 3.106686', path=path)
384  # Ntrk=3,4
385  ma.applyCuts('tau+:g34', 'visibleEnergyOfEventCMS < 10.5', path=path)
386  ma.applyCuts('tau+:g34', 'E_ECLtrk < 6', path=path)
387  ma.applyCuts('tau+:g34', 'visibleEnergyOfEventCMS > 3 or maxPt > 1', path=path)
388  ma.applyCuts('tau+:g34', 'maxOp < 3.106686', path=path)
389  ma.applyCuts('tau+:g34',
390  '[[ nTracksS1 == 1 or nTracksS1 == 3 ] and invMS1 < 1.8 and invMS2 < 2.3 ] or '
391  '[[ nTracksS2 == 1 or nTracksS2 == 3 ] and invMS2 < 1.8 and invMS1 < 2.3 ]', path=path)
392  # Ntrk=5,6
393  ma.applyCuts('tau+:g56',
394  '[[ nTracksS1 == 1 or nTracksS1 == 3 ] and invMS1 < 1.8 and invMS2 < 2.3 ] or '
395  '[[ nTracksS2 == 1 or nTracksS2 == 3 ] and invMS2 < 1.8 and invMS1 < 2.3 ]', path=path)
396 
397  # For skimming, the important thing is if the final particleList is empty or not.
398  return ['tau+:g2', 'tau+:g34', 'tau+:g56']
399 
400  def validation_histograms(self, path):
401  # NOTE: the validation package is not part of the light releases, so this import
402  # must be made here rather than at the top of the file.
403  from validation_tools.metadata import create_validation_histograms
404 
405  vm.addAlias('Theta_miss', 'formula(missingMomentumOfEvent_theta*180/3.14159)')
406 
407  # add contact information to histogram
408  contact = "kenji@hepl.phys.nagoya-u.ac.jp"
409 
410  ma.copyLists('tau+:generic', self.SkimListsSkimListsSkimLists, path=path)
411  ma.rankByHighest(particleList='tau+:generic',
412  variable='p',
413  numBest=1,
414  path=path)
415 
416  create_validation_histograms(
417  rootfile=f'{self}_Validation.root',
418  particlelist='tau+:generic',
419  variables_1d=[
420  ('nGoodTracks', 7, 1, 8, '', contact, '', ''),
421  ('visibleEnergyOfEventCMS', 40, 0, 12, '', contact, '', ''),
422  ('E_ECLtrk', 70, 0, 7, '', contact, '', ''),
423  ('maxPt', 30, 0, 6, '', contact, '', ''),
424  ('invMS1', 60, 0, 3, '', contact, '', '', '', ''),
425  ('invMS2', 60, 0, 3, '', contact, '', ''),
426  ('Theta_miss', 30, 0, 180, '', contact, '', '')],
427  variables_2d=[('invMS1', 30, 0, 3, 'invMS2', 30, 0, 3, '', contact, '', '')],
428  path=path)
429 
430 
431 @fancy_skim_header
433  """
434  **Channel**: :math:`e^+ e^- \\to \\tau^+ \\tau^-`
435 
436  **Criteria**:
437 
438  * ``1 < No. good tracks < 7``
439  * ``net charge == 0``
440  * Event divided by thrust axis; select 1x1, 1x3, 1x5, 3x3 topology
441  * ``0.8 < thrust``
442  * ``visibleEnergyOfEventCMS < 10.4 GeV``
443  * For 1x1 topology, ``thrust < 0.99``
444  * For 1x1 topology, ``1.5 < visibleEnergyOfEventCMS``
445  """
446  __authors__ = ["Ami Rostomyan", "Kenji Inami"]
447  __description__ = "Skim for Tau decays using thrust."
448  __contact__ = __liaison__
449  __category__ = "physics, tau"
450 
451  produce_on_tau_samples = False # retention is too high on taupair
452  validation_sample = _VALIDATION_SAMPLE
453 
454  def load_standard_lists(self, path):
455  stdPi("all", path=path)
456  stdPhotons("all", path=path, loadPhotonBeamBackgroundMVA=False)
457 
458  def additional_setup(self, path):
459  """
460  Set particle lists and variables for TauThrust skim.
461 
462  **Constructed particle lists**: ``pi+:thrust, gamma:thrust, pi+:thrustS1/thrustS2, pi0:thrust``
463 
464  **Variables**:
465 
466  * ``nGoodTracksThrust``: number of good tracks in an event
467  * ``netChargeThrust``: total net charge of good tracks
468  * ``nTracksS1Thrust/nTracksS2Thrust``: number of good tracks in each hemisphere S1/S2 divided by thrust axis
469  """
470 
471  tauskim_particle_selection("thrust", path)
472 
473  # Get EventShape variables
474  ma.buildEventShape(['pi+:thrust', 'pi0:thrust', 'gamma:thrust'],
475  allMoments=False, foxWolfram=False, cleoCones=False,
476  sphericity=False, jets=False, path=path)
477  ma.buildEventKinematics(['pi+:thrust', 'pi0:thrust', 'gamma:thrust'], path=path)
478 
479  # Split in signal and tag
480  ma.cutAndCopyList('pi+:thrustS1', 'pi+:thrust', 'cosToThrustOfEvent > 0', path=path)
481  ma.cutAndCopyList('pi+:thrustS2', 'pi+:thrust', 'cosToThrustOfEvent < 0', path=path)
482 
483  vm.addAlias('nGoodTracksThrust', 'nParticlesInList(pi+:thrust)')
484  vm.addAlias('netChargeThrust', 'formula(countInList(pi+:thrust, charge == 1) - countInList(pi+:thrust, charge == -1))')
485  vm.addAlias('nTracksS1Thrust', 'nParticlesInList(pi+:thrustS1)')
486  vm.addAlias('nTracksS2Thrust', 'nParticlesInList(pi+:thrustS2)')
487 
488  def build_lists(self, path):
489  ma.reconstructDecay("tau+:thrust -> pi+:thrustS1", "", path=path)
490  eventParticle = ["tau+:thrust"]
491 
492  # Selection criteria
493  ma.applyCuts("tau+:thrust", "1 < nGoodTracksThrust < 7", path=path) # cut1
494  ma.applyCuts("tau+:thrust", "netChargeThrust == 0", path=path) # cut2
495 
496  topologyCuts = "[nTracksS1Thrust == 1 and nTracksS2Thrust == 1]" # 1x1
497  topologyCuts += " or [nTracksS1Thrust == 1 and nTracksS2Thrust == 3]"\
498  " or [nTracksS1Thrust == 3 and nTracksS2Thrust == 1]" # 1x3, 3x1
499  topologyCuts += " or [nTracksS1Thrust == 1 and nTracksS2Thrust == 5]"\
500  " or [nTracksS1Thrust == 5 and nTracksS2Thrust == 1]" # 1x5, 5x1
501  topologyCuts += " or [nTracksS1Thrust == 3 and nTracksS2Thrust == 3]" # 3x3
502 
503  ma.applyCuts("tau+:thrust", topologyCuts, path=path) # cut3
504  ma.applyCuts("tau+:thrust", "0.8 < thrust", path=path) # cut4
505  ma.applyCuts("tau+:thrust", "visibleEnergyOfEventCMS < 10.4", path=path) # cut5
506  # cut for 1x1 topology
507  ma.applyCuts("tau+:thrust", "thrust < 0.99 or nGoodTracksThrust!=2", path=path)
508  ma.applyCuts("tau+:thrust", "1.5 < visibleEnergyOfEventCMS or nGoodTracksThrust!=2", path=path)
509 
510  return eventParticle
511 
512  def validation_histograms(self, path):
513  # NOTE: the validation package is not part of the light releases, so this import
514  # must be made here rather than at the top of the file.
515  from validation_tools.metadata import create_validation_histograms
516 
517  contact = "kenji@hepl.phys.nagoya-u.ac.jp"
518 
519  ma.rankByHighest(particleList='tau+:thrust',
520  variable='p',
521  numBest=1,
522  path=path)
523 
524  create_validation_histograms(
525  rootfile=f'{self}_Validation.root',
526  particlelist='tau+:thrust',
527  variables_1d=[
528  ('nGoodTracksThrust', 7, 1, 8, '', contact, '', ''),
529  ('visibleEnergyOfEventCMS', 40, 0, 12, '', contact, '', ''),
530  ('thrust', 50, 0.75, 1, '', contact, '', '')],
531  path=path)
list SkimLists
Definition: core.py:260
def additional_setup(self, path)
Definition: taupair.py:328
def build_lists(self, path)
Definition: taupair.py:371
def validation_histograms(self, path)
Definition: taupair.py:400
def load_standard_lists(self, path)
Definition: taupair.py:324
def build_lists(self, path)
Definition: taupair.py:127
def validation_histograms(self, path)
Definition: taupair.py:266
def load_standard_lists(self, path)
Definition: taupair.py:115
def additional_setup(self, path)
Definition: taupair.py:458
def build_lists(self, path)
Definition: taupair.py:488
def validation_histograms(self, path)
Definition: taupair.py:512
def load_standard_lists(self, path)
Definition: taupair.py:454