Belle II Software  light-2212-foldex
stdHyperons.py
1 #!/usr/bin/env python3
2 
3 
10 
11 from basf2 import B2ERROR, B2WARNING
12 from b2bii import isB2BII
13 from modularAnalysis import cutAndCopyList, reconstructDecay, applyCuts
14 from vertex import treeFit, kFit
15 
16 from stdCharged import stdPi, stdK
17 from stdV0s import stdLambdas
18 from stdPhotons import stdPhotons
19 
20 
21 def stdXi(fitter='TreeFit', path=None):
22  r"""
23  Reconstruct the standard :math:`\Xi^-` ``ParticleList`` named ``Xi-:std``.
24 
25  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
26 
27  Parameters:
28  fitter (str): specify either ``KFit`` or ``TreeFit`` for the vertex reconstructions (default ``TreeFit``)
29  path (basf2.Path): modules are added to this path building the ``Xi-:std`` list
30  """
31 
32  if not isB2BII():
33  stdLambdas(path=path)
34  # 3.5 MeV Range around the nominal mass
35  cutAndCopyList(
36  'Lambda0:reco',
37  'Lambda0:merged',
38  '[ abs( dM ) < 0.0035 ] and \
39  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
40  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.35 ] and \
41  [ daughter(0,protonID) > 0.01 ] and \
42  [ chiProb > 0.0 ]',
43  True, path=path)
44  else:
45  stdPi('all', path=path)
46  # Rough Lambda0 cuts from J. Yelton Observations of an Excited Omega- Baryon
47  kFit('Lambda0:mdst', conf_level=0.0, path=path) # Re-vertexing, recover vertex variables and error matrix
48  cutAndCopyList(
49  'Lambda0:reco',
50  'Lambda0:mdst',
51  '[ abs( dM ) < 0.0035 ] and \
52  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
53  [ dr > 0.35 ] and \
54  [ daughter(0,atcPIDBelle(4,3)) > 0.2 ] and \
55  [ daughter(0,atcPIDBelle(4,2)) > 0.2 ] and \
56  [ chiProb > 0.0 ]',
57  True, path=path)
58 
59  # stdXi-
60  if fitter == 'KFit':
61  kFit('Lambda0:reco', 0.0, fit_type='massvertex', path=path)
62  reconstructDecay('Xi-:reco -> Lambda0:reco pi-:all', '1.295 < M < 1.35', path=path)
63  kFit('Xi-:reco', conf_level=0.0, path=path)
64  elif fitter == 'TreeFit':
65  reconstructDecay('Xi-:reco -> Lambda0:reco pi-:all', '1.295 < M < 1.35', path=path)
66  treeFit('Xi-:reco', conf_level=0.0, massConstraint=[3122], path=path)
67  else:
68  B2ERROR(f"stdXi: invalid fitter ({fitter}). Choose from KFit or TreeFit")
69 
70  cutAndCopyList(
71  'Xi-:std',
72  'Xi-:reco',
73  '[ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
74  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0. and \
75  formula([dr^2 + dz^2 ]^[0.5])<formula([daughter(0,dr)^2 + daughter(0,dz)^2]^[0.5])] and \
76  [ chiProb > 0.0 ]',
77  True,
78  path=path)
79 
80 
81 def stdXi0(gammatype='eff40', path=None, loadPhotonBeamBackgroundMVA=True, loadPhotonHadronicSplitOffMVA=True):
82  r"""
83  Reconstruct the standard :math:`\Xi^0` ``ParticleList`` named ``Xi0:std``.
84 
85  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
86 
87  Parameters:
88  gammatype (str): specify either ``eff60``, ``eff50``, ``eff40``, ``eff30``, or ``eff20``
89  to select the signal efficiency of the photons used in the pi0 reconstruction
90  (default ``eff40``)
91  path (basf2.Path): modules are added to this path building the ``Xi0:std`` list
92  loadPhotonBeamBackgroundMVA (bool): If true, photon candidates will be assigned a beam background probability.
93  loadPhotonHadronicSplitOffMVA (bool): If true, photon candidates will be assigned a hadronic split-off probability.
94  """
95 
96  if not isB2BII():
97  stdLambdas(path=path)
98  # 3.5 MeV Range around nominal mass (~7*sigma_core)
99  cutAndCopyList(
100  'Lambda0:reco',
101  'Lambda0:merged',
102  '[ abs( dM ) < 0.0035 ] and \
103  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
104  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.35 ] and \
105  [ daughter(0,protonID) > 0.01 ] and \
106  [ chiProb > 0.0 ]',
107  True, path=path)
108  # ~7*sigma Range around nominal mass
109  stdPhotons(
110  f'pi0{gammatype}_May2020',
111  path=path,
112  loadPhotonBeamBackgroundMVA=loadPhotonBeamBackgroundMVA,
113  loadPhotonHadronicSplitOffMVA=loadPhotonHadronicSplitOffMVA)
114  reconstructDecay(f'pi0:reco -> gamma:pi0{gammatype}_May2020 gamma:pi0{gammatype}_May2020',
115  'abs( dM ) < 0.0406',
116  True, path=path)
117 
118  else:
119  # Rough pi0/Lambda0 cuts from J. Yelton Observations of an Excited Omega- Baryon
120  cutAndCopyList(
121  'pi0:reco',
122  'pi0:mdst',
123  '[ abs( dM ) < 0.0189 ] and \
124  [ [ daughter(0,clusterReg) == 1 and daughter(0,E) > 0.05 ] or [ daughter(0,clusterReg) == 3 and daughter(0,E) > 0.05 ] or \
125  [ daughter(0,clusterReg) == 2 and daughter(0,E) > 0.03 ] ] and \
126  [ [ daughter(1,clusterReg) == 1 and daughter(1,E) > 0.05 ] or [ daughter(1,clusterReg) == 3 and daughter(1,E) > 0.05 ] or \
127  [ daughter(1,clusterReg) == 2 and daughter(1,E) > 0.03 ] ]',
128  path=path)
129  kFit('Lambda0:mdst', conf_level=0.0, path=path) # Re-vertexing, recover vertex variables and error matrix
130  cutAndCopyList(
131  'Lambda0:reco',
132  'Lambda0:mdst',
133  '[ abs( dM ) < 0.0035 ] and \
134  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
135  [ dr > 0.35 ] and \
136  [ daughter(0,atcPIDBelle(4,3)) > 0.2 ] and \
137  [ daughter(0,atcPIDBelle(4,2)) > 0.2 ] and \
138  [ chiProb > 0.0 ]',
139  True, path=path)
140 
141  reconstructDecay(
142  'Xi0:prelim -> Lambda0:reco pi0:reco',
143  '1.225 < M < 1.405',
144  path=path)
145  treeFit('Xi0:prelim', conf_level=0.0, massConstraint=[3122], ipConstraint=True, updateAllDaughters=True, path=path)
146  # Selecting ~4*sigma around the pi0 nominal mass
147  # pi0 mass range is invariant for B2BII, tighter selection is required by user
148  applyCuts('Xi0:prelim', '[ abs( daughter(1,dM) ) < 0.0232 ]', path=path)
149  treeFit('Xi0:prelim', conf_level=0.0, massConstraint=[111, 3122], ipConstraint=True, updateAllDaughters=False, path=path)
150 
151  cutAndCopyList(
152  'Xi0:std',
153  'Xi0:prelim',
154  '[ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
155  [ daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane) < cosAngleBetweenMomentumAndVertexVectorInXYPlane ] and \
156  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.0 and \
157  formula([dr^2 + dz^2]^[0.5])<formula([daughter(0,dr)^2 + daughter(0,dz)^2]^[0.5])] and \
158  [ chiProb > 0.0 ]',
159  True,
160  path=path)
161 
162 
163 def stdOmega(fitter='TreeFit', path=None):
164  r"""
165  Reconstruct the standard :math:`\Omega^-` ``ParticleList`` named ``Omega-:std``.
166 
167  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
168 
169  Parameters:
170  fitter (str): specify either ``KFit`` or ``TreeFit`` for the vertex reconstructions (default ``TreeFit``)
171  path (basf2.Path): modules are added to this path building the ``Omega-:std`` list
172  """
173 
174  if not isB2BII():
175  stdLambdas(path=path)
176  # 3.5 MeV Range around the nominal mass
177  cutAndCopyList(
178  'Lambda0:reco',
179  'Lambda0:merged',
180  '[ abs( dM ) < 0.0035 ] and \
181  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
182  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.35 ] and \
183  [ daughter(0,protonID) > 0.01 ] and \
184  [ chiProb > 0.0 ]',
185  True, path=path)
186  else:
187  stdPi('all', path=path)
188  # Rough Lambda0 cuts from J. Yelton Observations of an Excited Omega- Baryon
189  kFit('Lambda0:mdst', conf_level=0.0, path=path) # Re-vertexing, recover vertex variables and error matrix
190  cutAndCopyList(
191  'Lambda0:reco',
192  'Lambda0:mdst',
193  '[ abs( dM ) < 0.0035 ] and \
194  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
195  [ dr > 0.35 ] and \
196  [ daughter(0,atcPIDBelle(4,3)) > 0.2 ] and \
197  [ daughter(0,atcPIDBelle(4,2)) > 0.2 ] and \
198  [ chiProb > 0.0 ]',
199  True, path=path)
200 
201  stdK('all', path=path)
202  # stdOmega-
203  if fitter == 'KFit':
204  kFit('Lambda0:reco', 0.0, fit_type='massvertex', path=path)
205  reconstructDecay('Omega-:reco -> Lambda0:reco K-:all', '1.622 < M < 1.722', path=path)
206  kFit('Omega-:reco', conf_level=0.0, path=path)
207  elif fitter == 'TreeFit':
208  reconstructDecay('Omega-:reco -> Lambda0:reco K-:all', '1.622 < M < 1.722', path=path)
209  treeFit('Omega-:reco', conf_level=0.0, massConstraint=[3122], path=path)
210  else:
211  B2ERROR(f"stdOmega: invalid fitter ({fitter}). Choose from KFit or TreeFit")
212 
213  if not isB2BII():
214  cutAndCopyList(
215  'Omega-:std',
216  'Omega-:reco',
217  '[ cosAngleBetweenMomentumAndVertexVector > 0.0] and \
218  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0. and \
219  formula([dr^2 + dz^2]^[0.5])<formula([daughter(0,dr)^2 + daughter(0,dz)^2]^[0.5])] and \
220  [ chiProb > 0.0 ] and \
221  [ daughter(1,kaonID) > 0.01 ]',
222  True,
223  path=path)
224 
225  else:
226  cutAndCopyList(
227  'Omega-:std',
228  'Omega-:reco',
229  '[ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
230  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0. and \
231  formula([dr^2 + dz^2]^[0.5])<formula([daughter(0,dr)^2 + daughter(0,dz)^2 ]^[0.5])] and \
232  [ chiProb > 0.0 ] and \
233  [ daughter(1,atcPIDBelle(3,4)) > 0.2 and daughter(1,atcPIDBelle(3,2)) > 0.2 ]',
234  True,
235  path=path)
236 
237 
238 def goodXi(xitype='loose', path=None):
239  r"""
240  Select the standard good :math:`\Xi^-` ``ParticleList`` named ``Xi-:veryloose``, ``Xi-:loose``, or ``Xi-:tight``
241  from the reconstructed ``Xi-:std``.
242 
243  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
244 
245  Parameters:
246  xitype (str): specify either ``veryloose``, ``loose``, or ``tight`` for good ``ParticleList`` selection (default ``loose``)
247  path (basf2.Path): modules are added to this path building the ``Xi-:veryloose``, ``Xi-:loose``, or ``Xi-:tight``, list
248  """
249 
250  if not _std_hyperon_is_in_path("Xi-", path):
251  B2WARNING("Could not find standard Xi particle list! Creating it with default options.")
252  stdXi(path=path)
253  assert _std_hyperon_is_in_path("Xi-", path)
254 
255  if xitype == 'veryloose':
256  cutAndCopyList(
257  'Xi-:veryloose',
258  'Xi-:std',
259  '[ daughter(1,pt) > 0.05 and \
260  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.1 ]',
261  True,
262  path=path)
263 
264  elif xitype == 'loose':
265  cutAndCopyList(
266  'Xi-:loose',
267  'Xi-:std',
268  '[ daughter(1,pt) > 0.05 and \
269  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.1 and \
270  formula([daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane)/cosAngleBetweenMomentumAndVertexVectorInXYPlane])\
271 <1.006 ]',
272  True,
273  path=path)
274 
275  elif xitype == 'tight':
276  cutAndCopyList(
277  'Xi-:tight',
278  'Xi-:std',
279  '[ daughter(1,pt) > 0.1 and \
280  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.15 and \
281  formula([daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane)/cosAngleBetweenMomentumAndVertexVectorInXYPlane])\
282 <1.001 ]',
283  True,
284  path=path)
285  else:
286  raise ValueError(f"\"{xitype}\" is none of the allowed Xi- list types!")
287 
288 
289 def goodXi0(xitype='loose', path=None):
290  r"""
291  Select the standard good :math:`\Xi^0` ``ParticleList`` named ``Xi0:veryloose``, ``Xi0:loose``, or ``Xi0:tight``
292  from the reconstructed ``Xi0:std``.
293 
294  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
295 
296  Parameters:
297  xitype (str): specify either ``veryloose``, ``loose``, or ``tight`` for good ``ParticleList`` selection (default ``loose``)
298  path (basf2.Path): modules are added to this path building the ``Xi0:veryloose``, ``Xi0:loose``, or ``Xi0:tight``, list
299  """
300 
301  if not _std_hyperon_is_in_path("Xi0", path):
302  B2WARNING("Could not find standard Xi0 particle list! Creating it with default options.")
303  stdXi0(path=path)
304  assert _std_hyperon_is_in_path("Xi0", path)
305 
306  if xitype == 'veryloose':
307  # Select pi0 at 3*sigma around the nominal mass
308  cutAndCopyList(
309  'Xi0:veryloose',
310  'Xi0:std',
311  '[ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.25 and \
312  daughter(1,p) > 0.1 and \
313  abs( daughter(1,dM) ) < 0.0174 ]',
314  True,
315  path=path)
316 
317  elif xitype == 'loose':
318  # Select pi0 at 3*sigma around the nominal mass
319  cutAndCopyList(
320  'Xi0:loose',
321  'Xi0:std',
322  '[ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.5 and \
323  daughter(1,p) > 0.15 and \
324  abs( daughter(1,dM) ) < 0.0174 ]',
325  True,
326  path=path)
327 
328  elif xitype == 'tight':
329  # Select pi0 at 2*sigma around the nominal mass
330  cutAndCopyList(
331  'Xi0:tight',
332  'Xi0:std',
333  '[ formula( [ dr^2 + dz^2 ]^[0.5] ) > 1.4 and \
334  daughter(1,p) > 0.25 and \
335  abs( daughter(1,dM) ) < 0.0116 ]',
336  True,
337  path=path)
338  else:
339  raise ValueError(f"\"{xitype}\" is none of the allowed Xi0 list types!")
340 
341 
342 def goodOmega(omegatype='loose', path=None):
343  r"""
344  Select the standard good :math:`\Omega^-` ``ParticleList`` named ``Omega-:veryloose``, ``Omega-:loose``,
345  or ``Omega-:tight`` from the reconstructed ``Omega-:std``.
346 
347  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
348 
349  Parameters:
350  omegatype (str): specify either ``veryloose``, ``loose``, or ``tight`` for good ``ParticleList`` selection
351  (default ``veryloose``)
352  path (basf2.Path): modules are added to this path building the ``Omega-:veryloose``, ``Omega-:loose``,
353  or ``Omega-:tight``, list
354  """
355 
356  if not _std_hyperon_is_in_path("Omega-", path):
357  B2WARNING("Could not find standard Omega particle list! Creating it with default options.")
358  stdOmega(path=path)
359  assert _std_hyperon_is_in_path("Omega-", path)
360 
361  if omegatype == 'veryloose':
362  cutAndCopyList(
363  'Omega-:veryloose',
364  'Omega-:std',
365  '[ daughter(1,pt) > 0.15 and \
366  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.05 ]',
367  True,
368  path=path)
369 
370  elif omegatype == 'loose':
371  cutAndCopyList(
372  'Omega-:loose',
373  'Omega-:std',
374  '[ daughter(1,pt) > 0.15 and \
375  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.15 and \
376  formula([daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane)/cosAngleBetweenMomentumAndVertexVectorInXYPlane])\
377 <1.0015 ]',
378  True,
379  path=path)
380 
381  elif omegatype == 'tight':
382  cutAndCopyList(
383  'Omega-:tight',
384  'Omega-:std',
385  '[ daughter(1,pt) > 0.3 and \
386  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.15 and \
387  formula([daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane)/cosAngleBetweenMomentumAndVertexVectorInXYPlane])\
388 <1.0005 ]',
389  True,
390  path=path)
391  else:
392  raise ValueError(f"\"{omegatype}\" is none of the allowed Omega list types!")
393 
394 
395 def _std_hyperon_is_in_path(hyperon, path):
396  """
397  Helper function to check if the std hyperon is already in the reconstruction path.
398 
399  Checks whether there is a ``PListCutAndCopy`` module with the
400  ``outputListName``: ``<hyperon>:std``.
401  :param hyperon: One of ["Xi-", "Xi0", "Omega-"]
402  :param path: Instance of basf2.Path
403  :returns: Boolean, whether ``PListCutAndCopy`` with ``outputListName`` ``<hyperon>:std`` was found in path.
404  """
405  # maybe this function could be generalized for other standard particles, but
406  # so far it has only been tested for standard hyperons:
407  allowed_hyperons = {"Xi-", "Xi0", "Omega-"}
408  if hyperon not in allowed_hyperons:
409  raise ValueError(
410  f"\"{hyperon}\" is not in list of hyperons that this function has been tested for ({allowed_hyperons})."
411  )
412  for module in path.modules():
413  if (module.name() == f"PListCutAndCopy_{hyperon}:std" or
414  module.name().split(" -> ")[0] == f"ParticleCombiner_{hyperon}:std"):
415  return True
416  return False