Belle II Software  release-08-01-10
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', beamBackgroundMVAWeight="", fakePhotonMVAWeight="", biasCorrectionTable="", path=None):
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 
92  beamBackgroundMVAWeight (str): type of weight file for beam background MVA; if empty, beam background MVA will not be used
93 
94  .. tip::
95  Please refer to the
96  `Neutrals Performance Confluence page <https://confluence.desy.de/display/BI/Neutrals+Performance>`_
97  for information on the beam background MVA.
98 
99  fakePhotonMVAWeight (str): type of weight file for fake photon MVA; if empty, fake photon MVA will not be used
100 
101  .. tip::
102  Please refer to the
103  `Neutrals Performance Confluence page <https://confluence.desy.de/display/BI/Neutrals+Performance>`_
104  for information on the fake photon MVA.
105 
106  biasCorrectionTable (str): correction table for the photon energy bias correction (should only be applied to data)
107 
108  .. tip::
109  Please refer to the
110  `Neutrals Performance Confluence page <https://confluence.desy.de/display/BI/Neutrals+Performance>`_
111  for information on the names of available correction tables.
112 
113  path (basf2.Path): modules are added to this path building the ``Xi0:std`` list
114  """
115 
116  if not isB2BII():
117  stdLambdas(path=path)
118  # 3.5 MeV Range around nominal mass (~7*sigma_core)
119  cutAndCopyList(
120  'Lambda0:reco',
121  'Lambda0:merged',
122  '[ abs( dM ) < 0.0035 ] and \
123  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
124  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.35 ] and \
125  [ daughter(0,protonID) > 0.01 ] and \
126  [ chiProb > 0.0 ]',
127  True, path=path)
128  # ~7*sigma Range around nominal mass
129  stdPhotons(
130  f'pi0{gammatype}_May2020',
131  path=path,
132  beamBackgroundMVAWeight=beamBackgroundMVAWeight,
133  fakePhotonMVAWeight=fakePhotonMVAWeight,
134  biasCorrectionTable=biasCorrectionTable)
135  reconstructDecay(f'pi0:reco -> gamma:pi0{gammatype}_May2020 gamma:pi0{gammatype}_May2020',
136  'abs( dM ) < 0.0406',
137  True, path=path)
138 
139  else:
140  # Rough pi0/Lambda0 cuts from J. Yelton Observations of an Excited Omega- Baryon
141  cutAndCopyList(
142  'pi0:reco',
143  'pi0:mdst',
144  '[ abs( dM ) < 0.0189 ] and \
145  [ [ daughter(0,clusterReg) == 1 and daughter(0,E) > 0.05 ] or [ daughter(0,clusterReg) == 3 and daughter(0,E) > 0.05 ] or \
146  [ daughter(0,clusterReg) == 2 and daughter(0,E) > 0.03 ] ] and \
147  [ [ daughter(1,clusterReg) == 1 and daughter(1,E) > 0.05 ] or [ daughter(1,clusterReg) == 3 and daughter(1,E) > 0.05 ] or \
148  [ daughter(1,clusterReg) == 2 and daughter(1,E) > 0.03 ] ]',
149  path=path)
150  kFit('Lambda0:mdst', conf_level=0.0, path=path) # Re-vertexing, recover vertex variables and error matrix
151  cutAndCopyList(
152  'Lambda0:reco',
153  'Lambda0:mdst',
154  '[ abs( dM ) < 0.0035 ] and \
155  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
156  [ dr > 0.35 ] and \
157  [ daughter(0,atcPIDBelle(4,3)) > 0.2 ] and \
158  [ daughter(0,atcPIDBelle(4,2)) > 0.2 ] and \
159  [ chiProb > 0.0 ]',
160  True, path=path)
161 
162  reconstructDecay(
163  'Xi0:prelim -> Lambda0:reco pi0:reco',
164  '1.225 < M < 1.405',
165  path=path)
166  treeFit('Xi0:prelim', conf_level=0.0, massConstraint=[3122], ipConstraint=True, updateAllDaughters=True, path=path)
167  # Selecting ~4*sigma around the pi0 nominal mass
168  # pi0 mass range is invariant for B2BII, tighter selection is required by user
169  applyCuts('Xi0:prelim', '[ abs( daughter(1,dM) ) < 0.0232 ]', path=path)
170  treeFit('Xi0:prelim', conf_level=0.0, massConstraint=[111, 3122], ipConstraint=True, updateAllDaughters=False, path=path)
171 
172  cutAndCopyList(
173  'Xi0:std',
174  'Xi0:prelim',
175  '[ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
176  [ daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane) < cosAngleBetweenMomentumAndVertexVectorInXYPlane ] and \
177  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.0 and \
178  formula([dr^2 + dz^2]^[0.5])<formula([daughter(0,dr)^2 + daughter(0,dz)^2]^[0.5])] and \
179  [ chiProb > 0.0 ]',
180  True,
181  path=path)
182 
183 
184 def stdOmega(fitter='TreeFit', path=None):
185  r"""
186  Reconstruct the standard :math:`\Omega^-` ``ParticleList`` named ``Omega-:std``.
187 
188  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
189 
190  Parameters:
191  fitter (str): specify either ``KFit`` or ``TreeFit`` for the vertex reconstructions (default ``TreeFit``)
192  path (basf2.Path): modules are added to this path building the ``Omega-:std`` list
193  """
194 
195  if not isB2BII():
196  stdLambdas(path=path)
197  # 3.5 MeV Range around the nominal mass
198  cutAndCopyList(
199  'Lambda0:reco',
200  'Lambda0:merged',
201  '[ abs( dM ) < 0.0035 ] and \
202  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
203  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.35 ] and \
204  [ daughter(0,protonID) > 0.01 ] and \
205  [ chiProb > 0.0 ]',
206  True, path=path)
207  else:
208  stdPi('all', path=path)
209  # Rough Lambda0 cuts from J. Yelton Observations of an Excited Omega- Baryon
210  kFit('Lambda0:mdst', conf_level=0.0, path=path) # Re-vertexing, recover vertex variables and error matrix
211  cutAndCopyList(
212  'Lambda0:reco',
213  'Lambda0:mdst',
214  '[ abs( dM ) < 0.0035 ] and \
215  [ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
216  [ dr > 0.35 ] and \
217  [ daughter(0,atcPIDBelle(4,3)) > 0.2 ] and \
218  [ daughter(0,atcPIDBelle(4,2)) > 0.2 ] and \
219  [ chiProb > 0.0 ]',
220  True, path=path)
221 
222  stdK('all', path=path)
223  # stdOmega-
224  if fitter == 'KFit':
225  kFit('Lambda0:reco', 0.0, fit_type='massvertex', path=path)
226  reconstructDecay('Omega-:reco -> Lambda0:reco K-:all', '1.622 < M < 1.722', path=path)
227  kFit('Omega-:reco', conf_level=0.0, path=path)
228  elif fitter == 'TreeFit':
229  reconstructDecay('Omega-:reco -> Lambda0:reco K-:all', '1.622 < M < 1.722', path=path)
230  treeFit('Omega-:reco', conf_level=0.0, massConstraint=[3122], path=path)
231  else:
232  B2ERROR(f"stdOmega: invalid fitter ({fitter}). Choose from KFit or TreeFit")
233 
234  if not isB2BII():
235  cutAndCopyList(
236  'Omega-:std',
237  'Omega-:reco',
238  '[ cosAngleBetweenMomentumAndVertexVector > 0.0] and \
239  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0. and \
240  formula([dr^2 + dz^2]^[0.5])<formula([daughter(0,dr)^2 + daughter(0,dz)^2]^[0.5])] and \
241  [ chiProb > 0.0 ] and \
242  [ daughter(1,kaonID) > 0.01 ]',
243  True,
244  path=path)
245 
246  else:
247  cutAndCopyList(
248  'Omega-:std',
249  'Omega-:reco',
250  '[ cosAngleBetweenMomentumAndVertexVector > 0.0 ] and \
251  [ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0. and \
252  formula([dr^2 + dz^2]^[0.5])<formula([daughter(0,dr)^2 + daughter(0,dz)^2 ]^[0.5])] and \
253  [ chiProb > 0.0 ] and \
254  [ daughter(1,atcPIDBelle(3,4)) > 0.2 and daughter(1,atcPIDBelle(3,2)) > 0.2 ]',
255  True,
256  path=path)
257 
258 
259 def goodXi(xitype='loose', path=None):
260  r"""
261  Select the standard good :math:`\Xi^-` ``ParticleList`` named ``Xi-:veryloose``, ``Xi-:loose``, or ``Xi-:tight``
262  from the reconstructed ``Xi-:std``.
263 
264  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
265 
266  Parameters:
267  xitype (str): specify either ``veryloose``, ``loose``, or ``tight`` for good ``ParticleList`` selection (default ``loose``)
268  path (basf2.Path): modules are added to this path building the ``Xi-:veryloose``, ``Xi-:loose``, or ``Xi-:tight``, list
269  """
270 
271  if not _std_hyperon_is_in_path("Xi-", path):
272  B2WARNING("Could not find standard Xi particle list! Creating it with default options.")
273  stdXi(path=path)
274  assert _std_hyperon_is_in_path("Xi-", path)
275 
276  if xitype == 'veryloose':
277  cutAndCopyList(
278  'Xi-:veryloose',
279  'Xi-:std',
280  '[ daughter(1,pt) > 0.05 and \
281  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.1 ]',
282  True,
283  path=path)
284 
285  elif xitype == 'loose':
286  cutAndCopyList(
287  'Xi-:loose',
288  'Xi-:std',
289  '[ daughter(1,pt) > 0.05 and \
290  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.1 and \
291  formula([daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane)/cosAngleBetweenMomentumAndVertexVectorInXYPlane])\
292 <1.006 ]',
293  True,
294  path=path)
295 
296  elif xitype == 'tight':
297  cutAndCopyList(
298  'Xi-:tight',
299  'Xi-:std',
300  '[ daughter(1,pt) > 0.1 and \
301  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.15 and \
302  formula([daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane)/cosAngleBetweenMomentumAndVertexVectorInXYPlane])\
303 <1.001 ]',
304  True,
305  path=path)
306  else:
307  raise ValueError(f"\"{xitype}\" is none of the allowed Xi- list types!")
308 
309 
310 def goodXi0(xitype='loose', path=None):
311  r"""
312  Select the standard good :math:`\Xi^0` ``ParticleList`` named ``Xi0:veryloose``, ``Xi0:loose``, or ``Xi0:tight``
313  from the reconstructed ``Xi0:std``.
314 
315  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
316 
317  Parameters:
318  xitype (str): specify either ``veryloose``, ``loose``, or ``tight`` for good ``ParticleList`` selection (default ``loose``)
319  path (basf2.Path): modules are added to this path building the ``Xi0:veryloose``, ``Xi0:loose``, or ``Xi0:tight``, list
320  """
321 
322  if not _std_hyperon_is_in_path("Xi0", path):
323  B2WARNING("Could not find standard Xi0 particle list! Creating it with default options.")
324  stdXi0(path=path)
325  assert _std_hyperon_is_in_path("Xi0", path)
326 
327  if xitype == 'veryloose':
328  # Select pi0 at 3*sigma around the nominal mass
329  cutAndCopyList(
330  'Xi0:veryloose',
331  'Xi0:std',
332  '[ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.25 and \
333  daughter(1,p) > 0.1 and \
334  abs( daughter(1,dM) ) < 0.0174 ]',
335  True,
336  path=path)
337 
338  elif xitype == 'loose':
339  # Select pi0 at 3*sigma around the nominal mass
340  cutAndCopyList(
341  'Xi0:loose',
342  'Xi0:std',
343  '[ formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.5 and \
344  daughter(1,p) > 0.15 and \
345  abs( daughter(1,dM) ) < 0.0174 ]',
346  True,
347  path=path)
348 
349  elif xitype == 'tight':
350  # Select pi0 at 2*sigma around the nominal mass
351  cutAndCopyList(
352  'Xi0:tight',
353  'Xi0:std',
354  '[ formula( [ dr^2 + dz^2 ]^[0.5] ) > 1.4 and \
355  daughter(1,p) > 0.25 and \
356  abs( daughter(1,dM) ) < 0.0116 ]',
357  True,
358  path=path)
359  else:
360  raise ValueError(f"\"{xitype}\" is none of the allowed Xi0 list types!")
361 
362 
363 def goodOmega(omegatype='loose', path=None):
364  r"""
365  Select the standard good :math:`\Omega^-` ``ParticleList`` named ``Omega-:veryloose``, ``Omega-:loose``,
366  or ``Omega-:tight`` from the reconstructed ``Omega-:std``.
367 
368  .. seealso:: `BELLE2-NOTE-PH-2019-011 <https://docs.belle2.org/record/BELLE2-NOTE-PH-2019-011.pdf>`_.
369 
370  Parameters:
371  omegatype (str): specify either ``veryloose``, ``loose``, or ``tight`` for good ``ParticleList`` selection
372  (default ``veryloose``)
373  path (basf2.Path): modules are added to this path building the ``Omega-:veryloose``, ``Omega-:loose``,
374  or ``Omega-:tight``, list
375  """
376 
377  if not _std_hyperon_is_in_path("Omega-", path):
378  B2WARNING("Could not find standard Omega particle list! Creating it with default options.")
379  stdOmega(path=path)
380  assert _std_hyperon_is_in_path("Omega-", path)
381 
382  if omegatype == 'veryloose':
383  cutAndCopyList(
384  'Omega-:veryloose',
385  'Omega-:std',
386  '[ daughter(1,pt) > 0.15 and \
387  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.05 ]',
388  True,
389  path=path)
390 
391  elif omegatype == 'loose':
392  cutAndCopyList(
393  'Omega-:loose',
394  'Omega-:std',
395  '[ daughter(1,pt) > 0.15 and \
396  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.15 and \
397  formula([daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane)/cosAngleBetweenMomentumAndVertexVectorInXYPlane])\
398 <1.0015 ]',
399  True,
400  path=path)
401 
402  elif omegatype == 'tight':
403  cutAndCopyList(
404  'Omega-:tight',
405  'Omega-:std',
406  '[ daughter(1,pt) > 0.3 and \
407  formula( [ dr^2 + dz^2 ]^[0.5] ) > 0.15 and \
408  formula([daughter(0,cosAngleBetweenMomentumAndVertexVectorInXYPlane)/cosAngleBetweenMomentumAndVertexVectorInXYPlane])\
409 <1.0005 ]',
410  True,
411  path=path)
412  else:
413  raise ValueError(f"\"{omegatype}\" is none of the allowed Omega list types!")
414 
415 
416 def _std_hyperon_is_in_path(hyperon, path):
417  """
418  Helper function to check if the std hyperon is already in the reconstruction path.
419 
420  Checks whether there is a ``PListCutAndCopy`` module with the
421  ``outputListName``: ``<hyperon>:std``.
422  :param hyperon: One of ["Xi-", "Xi0", "Omega-"]
423  :param path: Instance of basf2.Path
424  :returns: Boolean, whether ``PListCutAndCopy`` with ``outputListName`` ``<hyperon>:std`` was found in path.
425  """
426  # maybe this function could be generalized for other standard particles, but
427  # so far it has only been tested for standard hyperons:
428  allowed_hyperons = {"Xi-", "Xi0", "Omega-"}
429  if hyperon not in allowed_hyperons:
430  raise ValueError(
431  f"\"{hyperon}\" is not in list of hyperons that this function has been tested for ({allowed_hyperons})."
432  )
433  for module in path.modules():
434  if (module.name() == f"PListCutAndCopy_{hyperon}:std" or
435  module.name().split(" -> ")[0] == f"ParticleCombiner_{hyperon}:std"):
436  return True
437  return False