Belle II Software  release-05-02-19
lowMulti.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 """ Skim list building functions for the low multiplicity physics working group """
5 
6 __authors__ = [
7  "Xing-Yu Zhou",
8  "Hisaki Hayashii"
9 ]
10 
11 
12 import modularAnalysis as ma
13 from skimExpertFunctions import BaseSkim, fancy_skim_header, get_test_file
14 from stdCharged import stdE, stdPi
15 from stdPhotons import stdPhotons
16 
17 
18 @fancy_skim_header
20  """
21  **Physics channel**: :math:`e^{+}e^{-} \\to e^{+}e^{-}` and :math:`e^{+}e^{-} \\to \\mu^{+}\\mu^{-}`
22  """
23  __authors__ = "Xing-Yu Zhou"
24  __description__ = "Skim list for two track lepton (e+e- to e+e- and e+e- to mu+mu-) events for luminosity measurements."
25  __contact__ = "Xing-Yu Zhou <xing-yu.zhou@desy.de>"
26  __category__ = "physics, low multiplicity"
27 
28  TestFiles = [get_test_file("MC13_mumuBGx1")]
29  ApplyHLTHadronCut = False
30 
31  def __init__(self, prescale=1, **kwargs):
32  """
33  Parameters:
34  prescale (int): the prescale for this skim
35  **kwargs: Passed to the constructor of `BaseSkim`
36  """
37  # Redefine __init__ to allow for additional optional arguments
38  super().__init__(**kwargs)
39  self.prescale = prescale
40 
41  def build_lists(self, path):
42  # Skim label
43  skim_label = 'TwoTrackLeptonsForLuminosity'
44  # Skim label for the case of two tracks
45  skim_label_2 = 'TwoTrackLeptonsForLuminosity2'
46  # Skim label for the case of one track plus one cluster
47  skim_label_1 = 'TwoTrackLeptonsForLuminosity1'
48 
49  # Tracks from IP
50  IP_cut = '[abs(dz) < 5.0] and [abs(dr) < 2.0]'
51  # Tracks or clusters of momenta greater than 2 GeV in the CMS frame
52  p_cut = '[useCMSFrame(p) > 2.0]'
53  # Tracks pointing to or clusters locating in the barrel ECL + 10 degrees
54  theta_cut = '[0.561 < theta < 2.247]'
55 
56  single_track_cut = IP_cut + ' and ' + p_cut + ' and ' + theta_cut
57  single_cluster_cut = p_cut + ' and ' + theta_cut
58 
59  # Exactly 2 tracks
60  nTracks_cut_2 = '[nCleanedTracks(' + single_track_cut + ') == 2 or nCleanedTracks(' + single_track_cut + ') == 3]'
61  # Exactly 1 track
62  nTracks_cut_1 = '[nCleanedTracks(' + single_track_cut + ') == 1]'
63  # Acollinearity angle in the theta dimension less than 10 degrees in the CMS frame
64  # candidates are : vpho -> e+ e- or vpho -> e gamma
65  # daughter indices are: 0 1 0 1
66  deltaTheta_cut = (
67  '[abs(formula(daughter(0, useCMSFrame(theta)) + daughter(1, useCMSFrame(theta)) - 3.1415927)) < 0.17453293]'
68  )
69 
70  # convert the prescale from trigger convention
71  prescale = str(float(1.0 / self.prescale))
72  prescale_logic = 'eventRandom <= ' + prescale
73 
74  two_track_cut = nTracks_cut_2 + ' and ' + deltaTheta_cut + ' and ' + prescale_logic
75  track_cluster_cut = nTracks_cut_1 + ' and ' + deltaTheta_cut + ' and ' + prescale_logic
76 
77  # Reconstruct the event candidates with two tracks
78  ma.fillParticleList('e+:' + skim_label_2, single_track_cut + ' and ' + nTracks_cut_2, path=path)
79  ma.reconstructDecay('vpho:' + skim_label_2 + ' -> e+:' + skim_label_2 + ' e-:' + skim_label_2, two_track_cut, path=path)
80 
81  # Reconstruct the event candidates with one track plus one cluster
82  ma.fillParticleList('e+:' + skim_label_1, single_track_cut + ' and ' + nTracks_cut_1, path=path)
83  ma.fillParticleList('gamma:' + skim_label_1, single_cluster_cut + ' and ' + nTracks_cut_1, path=path)
84  ma.reconstructDecay(
85  'vpho:' +
86  skim_label_1 +
87  ' -> e+:' +
88  skim_label_1 +
89  ' gamma:' +
90  skim_label_1,
91  track_cluster_cut,
92  allowChargeViolation=True,
93  path=path)
94 
95  ma.copyLists('vpho:' + skim_label, ['vpho:' + skim_label_2, 'vpho:' + skim_label_1], path=path)
96  self.SkimLists = ['vpho:' + skim_label]
97 
98 
99 @fancy_skim_header
101  """
102 <<<<<<< HEAD
103  **Physics channel**: :math:`e^{+}e^{-} \\to \\gamma h^{+}h^{-}`
104 =======
105  **Physics channel**: :math:`e^{+}e^{-} \\to \\gamma h_{1}^{+}h_{2}^{-} X`
106 
107  .. Note::
108  The :math:`h_{1}^{+}` and :math:`h_{2}^{+}` here mean a positive particle
109  and a negative particle that could be either conjugate or non-conjugate. The
110  :math:`X` means arbitrary final state particles.
111 
112  **Decay Modes**
113 
114  1. :math:`e^{+}e^{-} \\to \\gamma \\pi^{+} \\pi^{-} X`,
115  2. :math:`e^{+}e^{-} \\to \\gamma K^{+} K^{-} X`,
116  3. :math:`e^{+}e^{-} \\to \\gamma K^{+} \\pi^{-} X`,
117  4. :math:`e^{+}e^{-} \\to \\gamma p \\overline{p} X`,
118  5. :math:`e^{+}e^{-} \\to \\gamma p \\pi^{-} X`,
119  6. :math:`e^{+}e^{-} \\to \\gamma p K^{-} X`,
120 >>>>>>> d98a3afd8c... update LowMassTwoTrack skim to include more channels
121  """
122  __authors__ = "Xing-Yu Zhou"
123  __description__ = "Skim list for low mass events with at least two tracks and one hard photon" \
124  " in final state."
125  __contact__ = "Xing-Yu Zhou <xing-yu.zhou@desy.de>"
126  __category__ = "physics, low multiplicity"
127 
128  TestFiles = [get_test_file("MC13_mumuBGx1"), get_test_file("MC13_uubarBGx1")]
129  ApplyHLTHadronCut = False
130 
131  def build_lists(self, path):
132  label = "LowMassTwoTrack"
133 
134  # Momenta of tracks greater than 0.5 GeV in the Lab frame
135  pCut = "p > 0.5"
136  # Energy of hard ISR gamma greater than 2 GeV in the CMS frame
137  ISRECut = "useCMSFrame(E) > 2"
138  # Invariant mass of h+h- system less than 3.5 GeV
139  hhMassWindow = "daughterInvM(1,2) < 3.5"
140 
141  # Event based cut
142  # Number of tracks passing the selection criteria, should be greater than or equal to to 2
143  nTracksCut = f"nCleanedTracks({pCut}) >= 2"
144  # Require at least one hard photon
145  nHardISRPhotonCut = f"nCleanedECLClusters({ISRECut}) > 0"
146 
147  # Apply event based cuts
148  ma.applyEventCuts(f"{nTracksCut} and {nHardISRPhotonCut}", path=path)
149 
150  # Reconstruct candidates
151  ma.fillParticleList(f"pi+:{label}", pCut, path=path)
152  ma.fillParticleList(f"K+:{label}", pCut, path=path)
153  ma.fillParticleList(f"p+:{label}", pCut, path=path)
154  ma.fillParticleList(f"gamma:{label}_ISR", ISRECut, path=path)
155 
156  # the mass hypothesis is different for p+, pi+ and K+ lists, so it is good to write them separately.
157  ModesAndCuts = [
158  (f"vpho:{label}_pipi", f" -> gamma:{label}_ISR pi+:{label} pi-:{label}", hhMassWindow),
159  (f"vpho:{label}_KK", f" -> gamma:{label}_ISR K+:{label} K-:{label}", hhMassWindow),
160  # Might be useful when one wants to reconstruct ISR K pi and missing other final state particles
161  (f"vpho:{label}_Kpi", f" -> gamma:{label}_ISR K+:{label} pi-:{label}", hhMassWindow),
162  (f"vpho:{label}_pp", f" -> gamma:{label}_ISR p+:{label} anti-p-:{label}", hhMassWindow),
163  # Useful for analyses for processes like ISR Lambda Lambda-bar (Sigma Sigma-bar) , especially when
164  # one wants to reconstruct the hard ISR photon and one of the Lambda (Sigma), missing anthoer
165  # Lambda (Sigma)
166  (f"vpho:{label}_ppi", f" -> gamma:{label}_ISR p+:{label} pi-:{label}", hhMassWindow),
167  # Might be useful when one wants to reconstruct ISR p K and missing other final state particles
168  (f"vpho:{label}_pK", f" -> gamma:{label}_ISR p+:{label} K-:{label}", hhMassWindow),
169  ]
170 
171  self.SkimLists = []
172  for dmID, (mode, decayString, cut) in enumerate(ModesAndCuts):
173  ma.reconstructDecay(mode + decayString, cut, dmID=dmID, path=path)
174  self.SkimLists.append(mode)
175 
176 
177 @fancy_skim_header
179  """
180  **Physics channel**: :math:`e^{+}e^{-} \\to e^{\\pm} (e^{\\mp}) \\pi^{0}/\\eta/\\eta^{\\prime}`
181 
182  **Decay Modes**
183 
184  1. :math:`\\pi^{0}\\to \\gamma \\gamma`,
185  2. :math:`\\eta \\to \\gamma\\gamma`,
186  3. :math:`\\eta \\to \\pi^{+}\\pi^{-}\\pi^{0}`,
187  4. :math:`\\eta \\to \\pi^{+}\\pi^{-}\\gamma`,
188  5. :math:`\\eta^{\\prime} \\to \\pi^{+}\\pi^{-}\\eta(\\to \\gamma\\gamma)`,
189  6. :math:`\\eta^{\\prime} \\to \\pi^{+}\\pi^{-}\\gamma`
190  """
191 
192  __authors__ = ["Hisaki Hayashii"]
193  __contact__ = "Hisaki Hayashii <hisaki.hayashii@desy.de>"
194  __description__ = "A skim script to select events with one high-energy electron and one or more pi0/eta/eta mesons."
195  __category__ = "physics, low multiplicity"
196  ApplyHLTHadronCut = False
197 
198  def load_standard_lists(self, path):
199  stdE("all", path=path)
200  stdPi("all", path=path)
201  stdPhotons("all", path=path)
202 
203  def build_lists(self, path):
204 
205  label = "PseudoScalarSkim"
206  TrackCuts = "abs(dz) < 2.0 and dr < 0.5 and pt > 0.15"
207 
208  ma.fillParticleList(f"e+:{label}", f"{TrackCuts} and E > 1.5 and electronID > 0.7", path=path)
209  ma.fillParticleList(f"pi+:{label}", f"{TrackCuts} and electronID < 0.7", path=path)
210  ma.fillParticleList(f"gamma:{label}", "clusterE > 0.1", path=path)
211 
212  pi0MassWindow = "0.06 < InvM < 0.18"
213  etaMassWindow = "0.50 < InvM < 0.60"
214  etapMassWindow = "0.91 < InvM < 1.10"
215  ModesAndCuts = [
216  (f"pi0:{label}_loose -> gamma:{label} gamma:{label}", pi0MassWindow),
217  (f"eta:gg -> gamma:{label} gamma:{label}", etaMassWindow),
218  (f"eta:pipipi0 -> pi+:{label} pi-:{label} pi0:{label}_loose", etaMassWindow),
219  (f"eta:pipig -> pi+:{label} pi-:{label} gamma:{label}", etaMassWindow),
220  (f"eta':pipieta_gg -> pi+:{label} pi-:{label} eta:gg", etapMassWindow),
221  (f"eta':pipig -> pi+:{label} pi-:{label} gamma:{label}", etapMassWindow),
222  ]
223  for dmID, (mode, cut) in enumerate(ModesAndCuts):
224  ma.reconstructDecay(mode, cut, dmID=dmID, path=path)
225 
226  ma.cutAndCopyList(f"pi0:{label}_highE", f"pi0:{label}_loose", "E > 0.5", path=path)
227 
228  particles = [
229  f"pi0:{label}_highE",
230  f"eta:gg",
231  f"eta:pipipi0",
232  f"eta:pipig",
233  f"eta':pipieta_gg",
234  f"eta':pipig"
235  ]
236  ModeSum = " + ".join(f"nParticlesInList({particle})" for particle in particles)
237  presel = f"nParticlesInList(e+:{label}) == 1 and nParticlesInList(pi+:{label}) <= 2"
238  EventCuts = f"{presel} and formula({ModeSum}) >= 1"
239 
240  # Although a condition of "mode_sum >= 1" looks like very loose,
241  # the reduction rate of this SingleTagPseudoScalar skim is very large, i.e. 1/50,
242  # since the requirements, one high-energy electron and <=2 other charged
243  # tracks, are quite stringent.
244  path = self.skim_event_cuts(EventCuts, path=path)
245 
246  self.SkimLists = [f"e+:{label}"]
skimExpertFunctions.BaseSkim.skim_event_cuts
def skim_event_cuts(self, cut, *path)
Definition: skimExpertFunctions.py:716
skim.lowMulti.TwoTrackLeptonsForLuminosity
Definition: lowMulti.py:19
skim.lowMulti.LowMassTwoTrack.SkimLists
SkimLists
Definition: lowMulti.py:171
skim.lowMulti.TwoTrackLeptonsForLuminosity.prescale
prescale
Definition: lowMulti.py:39
stdPhotons
Definition: stdPhotons.py:1
skim.lowMulti.TwoTrackLeptonsForLuminosity.SkimLists
SkimLists
Definition: lowMulti.py:96
skim.lowMulti.SingleTagPseudoScalar.load_standard_lists
def load_standard_lists(self, path)
Definition: lowMulti.py:198
skim.lowMulti.LowMassTwoTrack.build_lists
def build_lists(self, path)
Definition: lowMulti.py:131
skim.lowMulti.SingleTagPseudoScalar
Definition: lowMulti.py:178
skim.lowMulti.TwoTrackLeptonsForLuminosity.__init__
def __init__(self, prescale=1, **kwargs)
Definition: lowMulti.py:31
skim.lowMulti.SingleTagPseudoScalar.build_lists
def build_lists(self, path)
Definition: lowMulti.py:203
skimExpertFunctions.BaseSkim
Definition: skimExpertFunctions.py:504
skim.lowMulti.TwoTrackLeptonsForLuminosity.build_lists
def build_lists(self, path)
Definition: lowMulti.py:41
skim.lowMulti.LowMassTwoTrack
Definition: lowMulti.py:100
skim.lowMulti.SingleTagPseudoScalar.SkimLists
SkimLists
Definition: lowMulti.py:246