Belle II Software  release-06-02-00
ewp.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 """
13 
14 Skim list building functions for EWP inclusive skims:
15 B->Xgamma, B->Xll, B->Xll (LFV modes)
16 
17 """
18 
19 import basf2 as b2
20 import modularAnalysis as ma
21 from skim import BaseSkim, fancy_skim_header
22 from stdCharged import stdE, stdK, stdMu, stdPi
23 from stdPhotons import stdPhotons
24 from variables import variables as vm
25 
26 __liaison__ = "Rahul Tiwary <rahul.tiwary@tifr.res.in>"
27 _VALIDATION_SAMPLE = "mdst14.root"
28 
29 
30 @fancy_skim_header
32  """
33  Reconstructed decay modes:
34 
35  * :math:`B^+ \\to X\\gamma` inclusive
36 
37  Event-level cuts:
38 
39  * :math:`\\text{foxWolframR2} < 0.7` constructed using tracks with
40  :math:`p_T>0.1\\,\\text{GeV}` and clusters with :math:`E>0.1\\,\\text{GeV}`.
41  * :math:`n_{\\text{tracks}} \\geq 3`
42 
43  Cuts on photons:
44 
45  * :math:`\\text{clusterE9E21}>0.9`
46  * :math:`1.4\\,\\text{GeV}<\\E_{\\gamma}<3.4\\,\\text{GeV}` in CMS frame
47  """
48 
49  __authors__ = ["Trevor Shillington"]
50  __description__ = ":math:`B\\to X\\gamma` inclusive skim."
51  __contact__ = __liaison__
52  __category__ = "physics, electroweak penguins, radiative decays"
53 
54  validation_sample = _VALIDATION_SAMPLE
55 
56  def load_standard_lists(self, path):
57  stdPi("all", path=path)
58  stdPhotons("loose", path=path, loadPhotonBeamBackgroundMVA=False)
59 
60  def build_lists(self, path):
61  """Build the skim list for :math:`B \\to X\\gamma` decays."""
62  # event level cuts: R2 and require a minimum number of tracks + decent photons
63  ma.fillParticleList(decayString='pi+:BtoXgamma_eventshape', cut='pt > 0.1', path=path)
64  ma.fillParticleList(decayString='gamma:BtoXgamma_eventshape', cut='E > 0.1', path=path,
65  loadPhotonBeamBackgroundMVA=False)
66 
67  ma.buildEventShape(inputListNames=['pi+:BtoXgamma_eventshape', 'gamma:BtoXgamma_eventshape'],
68  allMoments=False,
69  foxWolfram=True,
70  harmonicMoments=False,
71  cleoCones=False,
72  thrust=False,
73  collisionAxis=False,
74  jets=False,
75  sphericity=False,
76  checkForDuplicates=False,
77  path=path)
78 
79  # Apply event cuts R2 < 0.7 and nTracks >= 3
80  path = self.skim_event_cutsskim_event_cuts('foxWolframR2 < 0.7 and nTracks >= 3', path=path)
81 
82  # Apply gamma cuts clusterE9E21 > 0.9 and 1.4 < E_gamma < 3.4 GeV (in CMS frame)
83  ma.cutAndCopyList('gamma:ewp', 'gamma:loose', 'clusterE9E21 > 0.9 and 1.4 < useCMSFrame(E) < 3.4', path=path)
84 
85  ma.reconstructDecay('B+:gamma -> gamma:ewp', '', path=path, allowChargeViolation=True)
86 
87  return ['B+:gamma']
88 
89  def validation_histograms(self, path):
90  # NOTE: the validation package is not part of the light releases, so this import
91  # must be made here rather than at the top of the file.
92  from validation_tools.metadata import create_validation_histograms
93 
94  histogram_filename = f'{self}_Validation.root'
95 
96  stdK('all', path=path)
97  stdPhotons('cdc', path=path, loadPhotonBeamBackgroundMVA=False)
98  ma.cutAndCopyList('gamma:sig', 'gamma:cdc', 'clusterNHits > 1.5 and E > 1.5', True, path)
99 
100  ma.reconstructDecay('K*0:sig -> K+:all pi-:all', '0.6 < M < 1.6', path=path)
101  ma.reconstructDecay('B0:sig -> K*0:sig gamma:sig', '5.22 < Mbc < 5.3 and abs(deltaE)< .5', path=path)
102 
103  # the variables that are printed out are: Mbc and deltaE
104  create_validation_histograms(
105  rootfile=histogram_filename,
106  particlelist='B0:sig',
107  variables_1d=[
108  ('Mbc', 100, 5.2, 5.3, 'Signal B0 Mbc', __liaison__,
109  'Mbc of the signal B0', '', 'Mbc [GeV/c^2]', 'Candidates'),
110  ('deltaE', 100, -1, 1, 'Signal B0 deltaE', __liaison__,
111  'deltaE of the signal B0', '', 'deltaE [GeV]', 'Candidates')
112  ],
113  variables_2d=[],
114  path=path)
115 
116 
117 @fancy_skim_header
119  """
120  Reconstructed decay modes:
121 
122  * :math:`B^+ \\to X e^+ e^-`
123  * :math:`B^+ \\to X e^+ e^+`
124  * :math:`B^+ \\to X \\mu^+ \\mu^-`
125  * :math:`B^+ \\to X \\mu^+ \\mu^+`
126 
127 
128  Event-level cuts:
129 
130  * :math:`\\text{foxWolframR2} < 0.7` constructed using tracks with
131  :math:`p_T>0.1\\,\\text{GeV}` and clusters with :math:`E>0.1\\,\\text{GeV}`.
132  * :math:`n_{\\text{tracks}} \\geq 3`
133 
134  Cuts on electrons:
135 
136  * :math:`\\text{electronID} > 0.1`
137  * :math:`p > 0.395\\,\\text{GeV}` in lab frame
138  * :math:`dr<0.5 and abs(dz)<2`
139 
140  Cuts on muons:
141 
142  * :math:`\\text{muonID} > 0.5`
143  * :math:`p > 0.395\\,\\text{GeV}` in lab frame
144  * :math:`dr<0.5 and abs(dz)<2`
145 
146 
147  Cut on dilepton energy:
148 
149  * :math:`E_{\\ell\\ell}>1.5\\,\\text{GeV}` in CMS frame.
150  """
151 
152  __authors__ = ["Trevor Shillington"]
153  __description__ = ":math:`B\\to X\\ell\\ell` (no LFV modes) inclusive skim."
154  __contact__ = __liaison__
155  __category__ = "physics, electroweak penguins, radiative decays"
156 
157  validation_sample = _VALIDATION_SAMPLE
158 
159  def load_standard_lists(self, path):
160  stdE("all", path=path)
161  stdMu("all", path=path)
162  stdPi("all", path=path)
163  stdPhotons("all", path=path, loadPhotonBeamBackgroundMVA=False)
164 
165  def build_lists(self, path):
166  """Build the skim list for :math:`B \\to X\\ell\\ell` non-LFV decays."""
167 
168  # event level cuts: R2 and require a minimum number of tracks
169  ma.fillParticleList(decayString='pi+:BtoXll_eventshape', cut='pt > 0.1', path=path)
170  ma.fillParticleList(decayString='gamma:BtoXll_eventshape', cut='E > 0.1', path=path)
171 
172  ma.buildEventShape(inputListNames=['pi+:BtoXll_eventshape', 'gamma:BtoXll_eventshape'],
173  allMoments=False,
174  foxWolfram=True,
175  harmonicMoments=False,
176  cleoCones=False,
177  thrust=False,
178  collisionAxis=False,
179  jets=False,
180  sphericity=False,
181  checkForDuplicates=False,
182  path=path)
183 
184  # Apply event cuts R2 < 0.7 and nTracks >= 3
185  path = self.skim_event_cutsskim_event_cuts('foxWolframR2 < 0.7 and nTracks >= 3', path=path)
186 
187  # Apply electron cut p > 0.395 GeV, electronID > 0.1 + fairTrack
188  # Apply muon cuts p > 0.395 GeV, muonID > 0.5 + fairTrack
189  fairTrack = 'dr < 0.5 and abs(dz) < 2'
190 
191  ma.cutAndCopyList('e+:ewp', 'e+:all', 'p > 0.395 and electronID_noTOP > 0.1 and ' + fairTrack, path=path)
192  ma.cutAndCopyList('mu+:ewp', 'mu+:all', 'p > 0.395 and muonID > 0.5 and ' + fairTrack, path=path)
193 
194  # Apply dilepton cut E_ll > 1.5 GeV (in CMS frame)
195  E_dilep_cut = 'formula(daughter(0, useCMSFrame(E))+daughter(1, useCMSFrame(E))) > 1.5'
196 
197  # B+ reconstruction:
198  # oppositely charged leptons
199  ma.reconstructDecay('B+:ch1 -> e+:ewp e-:ewp', E_dilep_cut, dmID=1, path=path, allowChargeViolation=True)
200  ma.reconstructDecay('B+:ch2 -> mu+:ewp mu-:ewp', E_dilep_cut, dmID=2, path=path, allowChargeViolation=True)
201  # same charge leptons
202  ma.reconstructDecay('B+:ch3 -> e+:ewp e+:ewp', E_dilep_cut, dmID=3, path=path, allowChargeViolation=True)
203  ma.reconstructDecay('B+:ch4 -> mu+:ewp mu+:ewp', E_dilep_cut, dmID=4, path=path, allowChargeViolation=True)
204 
205  ma.copyLists('B+:xll', ['B+:ch1', 'B+:ch2', 'B+:ch3', 'B+:ch4'], path=path)
206 
207  return ['B+:xll']
208 
209  def validation_histograms(self, path):
210  # NOTE: the validation package is not part of the light releases, so this import
211  # must be made here rather than at the top of the file.
212  from validation_tools.metadata import create_validation_histograms
213 
214  histogram_filename = f'{self}_Validation.root'
215 
216  stdK(listtype='good', path=path)
217  stdMu(listtype='good', path=path)
218  ma.reconstructDecay("B+:signal -> K+:good mu+:good mu-:good", "Mbc > 5.2 and deltaE < 0.5 and deltaE > -0.5", path=path)
219 
220  create_validation_histograms(
221  rootfile=histogram_filename,
222  particlelist='B+:signal',
223  variables_1d=[
224  ('deltaE', 100, -0.5, 0.5, 'Signal B deltaE', __liaison__,
225  'deltaE of the Signal B', '', 'deltaE [GeV]', 'Candidates'),
226  ('Mbc', 100, 5.2, 5.3, 'Signal B Mbc', __liaison__,
227  'Mbc of the signal B', '', 'Mbc [GeV/c^2]', 'Candidates')],
228  variables_2d=[],
229  path=path)
230 
231 
232 @fancy_skim_header
234  """
235  Reconstructed decay modes:
236 
237  * :math:`B^+ \\to X e^+ \\mu^-`
238  * :math:`B^+ \\to X \\mu^+ e^-`
239  * :math:`B^+ \\to X e^+ \\mu^+`
240 
241 
242  Event-level cuts:
243 
244  * :math:`\\text{foxWolframR2} < 0.7` constructed using tracks with
245  :math:`p_T>0.1\\,\\text{GeV}` and clusters with :math:`E>0.1\\,\\text{GeV}`.
246  * :math:`n_{\\text{tracks}} \\geq 3`
247 
248  Cuts on electrons:
249 
250  * :math:`\\text{electronID} > 0.1`
251  * :math:`p > 0.395\\,\\text{GeV}` in lab frame
252  * :math:`dr<0.5 and abs(dz)<2`
253 
254  Cuts on muons:
255 
256  * :math:`\\text{muonID} > 0.5`
257  * :math:`p > 0.395\\,\\text{GeV}` in lab frame
258  * :math:`dr<0.5 and abs(dz)<2`
259 
260 
261  Cut on dilepton energy:
262 
263  * :math:`E_{\\ell\\ell}>1.5\\,\\text{GeV}` in CMS frame.
264  """
265 
266  __authors__ = ["Trevor Shillington"]
267  __description__ = ":math:`B\\to X\\ell\\ell` (LFV modes only) inclusive skim."
268  __contact__ = __liaison__
269  __category__ = "physics, electroweak penguins, radiative decays"
270 
271  def load_standard_lists(self, path):
272  stdE("all", path=path)
273  stdMu("all", path=path)
274  stdPi("all", path=path)
275  stdPhotons("all", path=path, loadPhotonBeamBackgroundMVA=False)
276 
277  def build_lists(self, path):
278  """Build the skim list for :math:`B \\to X\\ell\\ell` LFV decays."""
279  # Create lists for buildEventShape (basically all tracks and clusters)
280  ma.cutAndCopyList('pi+:BtoXllLFV_eventshape', 'pi+:all', 'pt> 0.1', path=path)
281  ma.cutAndCopyList('gamma:BtoXllLFV_eventshape', 'gamma:all', 'E > 0.1', path=path)
282 
283  # buildEventShape to access R2
284  ma.buildEventShape(inputListNames=['pi+:BtoXllLFV_eventshape', 'gamma:BtoXllLFV_eventshape'],
285  allMoments=False,
286  foxWolfram=True,
287  harmonicMoments=False,
288  cleoCones=False,
289  thrust=False,
290  collisionAxis=False,
291  jets=False,
292  sphericity=False,
293  checkForDuplicates=False,
294  path=path)
295 
296  # Apply event cuts R2 < 0.7 and nTracks >= 3
297  path = self.skim_event_cutsskim_event_cuts('foxWolframR2 < 0.7 and nTracks >= 3', path=path)
298 
299  # Apply electron cut p > 0.395 GeV, electronID > 0.1 + fairTrack
300  # Apply muon cuts p > 0.395 GeV, muonID > 0.5 + fairTrack
301  fairTrack = 'dr < 0.5 and abs(dz) < 2'
302 
303  ma.cutAndCopyList('e+:ewp', 'e+:all', 'p > 0.395 and electronID_noTOP > 0.1 and ' + fairTrack, path=path)
304  ma.cutAndCopyList('mu+:ewp', 'mu+:all', 'p > 0.395 and muonID > 0.5 and ' + fairTrack, path=path)
305 
306  # Apply dilepton cut E_ll > 1.5 GeV (in CMS frame)
307  E_dilep_cut = 'formula(daughter(0, useCMSFrame(E))+daughter(1, useCMSFrame(E))) > 1.5'
308 
309  # B+ reconstruction:
310  # oppositely charged leptons
311  ma.reconstructDecay('B+:lfvch1 -> e+:ewp mu-:ewp', E_dilep_cut, dmID=1, path=path, allowChargeViolation=True)
312  ma.reconstructDecay('B+:lfvch2 -> mu+:ewp e-:ewp', E_dilep_cut, dmID=2, path=path, allowChargeViolation=True)
313  # same charge leptons
314  ma.reconstructDecay('B+:lfvch3 -> e+:ewp mu+:ewp', E_dilep_cut, dmID=3, path=path, allowChargeViolation=True)
315 
316  ma.copyLists('B+:lfv', ['B+:lfvch1', 'B+:lfvch2', 'B+:lfvch3'], path=path)
317 
318  return ['B+:lfv']
319 
320 
322  """
323  Reconstructed decay modes:
324 
325  * :math:`B^+ \\to K\\nu\\nu` inclusive
326 
327  Track cleanup:
328  * :math:`p_t > 0.1`
329  * :math:`thetaInCDCAcceptance`
330  * :math:`dr<0.5 and abs(dz)<3.0`
331 
332  Event cleanup:
333  * :math:`3 < nCleanedTracks < 11`
334 
335  Kaon cuts:
336  * :math:`track cleanup + event cleanup + nPXDHits > 0`
337  * :math:`p_t rank=1`
338  * :math:`kaonID>0.01`
339 
340  MVA info and cuts:
341  * mva_identifier: MVAFastBDT_InclusiveBplusToKplusNuNu_Skim
342  * Global Tag: mva_inclusiveBplusToKplusNuNu
343  * :math:`mva\\_identifier > 0.5`
344  """
345 
346  __authors__ = ["Cyrille Praz"]
347  __description__ = "Inclusive skim for :math:`B\\to K\\nu\\nu` analysis"
348  __contact__ = __liaison__
349  __category__ = "physics, electroweak penguins, radiative decays"
350 
351  NoisyModules = ["ParticleCombiner"]
352  validation_sample = _VALIDATION_SAMPLE
353 
354  def build_lists(self, path):
355 
356  # Default cleanup also used in and ma.buildEventShape
357  track_cleanup = 'pt > 0.1'
358  track_cleanup += ' and thetaInCDCAcceptance'
359  track_cleanup += ' and abs(dz) < 3.0'
360  track_cleanup += ' and dr < 0.5'
361 
362  # Min 4 tracks and Max 10 tracks per event.
363  event_cleanup = 'nCleanedTracks({}) > 3'.format(track_cleanup)
364  event_cleanup += ' and nCleanedTracks({}) < 11'.format(track_cleanup)
365 
366  # Define the signal
367  total_cleanup = track_cleanup + ' and ' + event_cleanup + ' and ' + 'nPXDHits>0'
368  ma.fillParticleList('K+:inclusiveBplusToKplusNuNu', cut=total_cleanup, path=path)
369  ma.rankByHighest('K+:inclusiveBplusToKplusNuNu', 'pt', path=path)
370  ma.applyCuts('K+:inclusiveBplusToKplusNuNu', 'extraInfo(pt_rank)==1', path=path)
371  ma.applyCuts('K+:inclusiveBplusToKplusNuNu', 'kaonID>1e-2', path=path)
372  ma.reconstructDecay(decayString='B+:inclusiveBplusToKplusNuNu -> K+:inclusiveBplusToKplusNuNu', cut='', path=path)
373 
374  # Build the event-based variables that we need
375  ma.buildEventShape(inputListNames=[],
376  default_cleanup=True,
377  allMoments=False,
378  cleoCones=True,
379  collisionAxis=False,
380  foxWolfram=True,
381  harmonicMoments=True,
382  jets=False,
383  sphericity=True,
384  thrust=True,
385  checkForDuplicates=False,
386  path=path)
387 
388  # Apply a MVA by reading from the DB
389  mva_identifier = 'MVAFastBDT_InclusiveBplusToKplusNuNu_Skim'
390  b2.conditions.append_globaltag('mva_inclusiveBplusToKplusNuNu')
391  path.add_module('MVAExpert', listNames=['B+:inclusiveBplusToKplusNuNu'],
392  extraInfoName=mva_identifier, identifier=mva_identifier)
393  vm.addAlias(mva_identifier, f'extraInfo({mva_identifier})')
394  ma.applyCuts('B+:inclusiveBplusToKplusNuNu', mva_identifier + '>0.5', path=path)
395 
396  return ['B+:inclusiveBplusToKplusNuNu']
397 
398  def validation_histograms(self, path):
399  # NOTE: the validation package is not part of the light releases, so this import
400  # must be made here rather than at the top of the file.
401  from validation_tools.metadata import create_validation_histograms
402 
403  histogram_filename = f'{self}_Validation.root'
404  # Default cleanup also used in and ma.buildEventShape
405  track_cleanup = 'pt > 0.1'
406  track_cleanup += ' and thetaInCDCAcceptance'
407  track_cleanup += ' and abs(dz) < 3.0'
408  track_cleanup += ' and abs(dr) < 0.5'
409 
410  # Define a couple of aliases
411  vm.addAlias('kaon_pt', 'daughter(0,pt)')
412  vm.addAlias('nCleanedTracks_simple_cleanup', 'nCleanedTracks({})'.format(track_cleanup))
413 
414  # Output validation histograms
415  create_validation_histograms(
416  rootfile=histogram_filename,
417  particlelist='B+:inclusiveBplusToKplusNuNu',
418  variables_1d=[
419  ('kaon_pt',
420  10,
421  0,
422  5,
423  'Kaon pt',
424  __liaison__,
425  'Transverse momentum of the kaon candidate',
426  'Maximum between 1.5 and 2 GeV/c',
427  'Kaon pt [GeV/c]',
428  'Candidates'),
429  ('nCleanedTracks_simple_cleanup',
430  12,
431  0,
432  12,
433  'Number of cleaned tracks',
434  __liaison__,
435  'Number of cleaned tracks in the event',
436  'Should be between 4 and 10, with two local maxima at 4 and 6',
437  'Number of cleaned tracks',
438  'Events'),
439  ('sphericity',
440  10,
441  0,
442  1,
443  'Event Sphericity',
444  __liaison__,
445  'Sphericity computed by ma.buildEventShape',
446  'Maximum around 0.3',
447  'Event Sphericity',
448  'Events')],
449  variables_2d=[],
450  path=path)
def build_lists(self, path)
Definition: ewp.py:60
def validation_histograms(self, path)
Definition: ewp.py:89
def load_standard_lists(self, path)
Definition: ewp.py:56
def build_lists(self, path)
Definition: ewp.py:277
def load_standard_lists(self, path)
Definition: ewp.py:271
def build_lists(self, path)
Definition: ewp.py:165
def validation_histograms(self, path)
Definition: ewp.py:209
def load_standard_lists(self, path)
Definition: ewp.py:159
def build_lists(self, path)
Definition: ewp.py:354
def validation_histograms(self, path)
Definition: ewp.py:398
def skim_event_cuts(self, cut, *path)
Definition: core.py:272