13 (Semi-)Leptonic Working Group Skims for missing energy modes that use the `FullEventInterpretation` (FEI) algorithm.
16 from functools
import lru_cache, wraps
20 import modularAnalysis
as ma
21 from skim
import BaseSkim, fancy_skim_header
22 from skim.utils.misc
import _sphinxify_decay
23 from variables
import variables
as vm
25 __liaison__ =
"Shanette De La Motte <shanette.delamotte@adelaide.edu.au>"
26 _VALIDATION_SAMPLE =
"mdst14.root"
29 def _merge_boolean_dicts(*dicts):
30 """Merge dicts of boolean, with `True` values taking precedence if values
33 This is a utility function for combining FEI configs. It acts in the following
36 >>> d1 = {"neutralB": True, "chargedB": False, "hadronic": True}
37 >>> d2 = {"chargedB": True, "semileptonic": True}
38 >>> _merge_FEI_configs(d1, d2)
39 {"chargedB": True, "hadronic": True, "neutralB": True, "semileptonic": True}
42 dicts (dict(str -> bool)): Any number of dicts of keyword-boolean pairs.
45 merged (dict(str -> bool)): A single dict, containing all the keys of the
48 keys = {k
for d
in dicts
for k
in d}
49 occurances = {k: [d
for d
in dicts
if k
in d]
for k
in keys}
50 merged = {k: any(d[k]
for d
in occurances[k])
for k
in keys}
53 merged = dict(sorted(merged.items()))
58 def _get_fei_channel_names(particleName, **kwargs):
59 """Create a list containing the decay strings of all decay channels available to a
60 particle. Any keyword arguments are passed to `fei.get_default_channels`.
62 This is a utility function for autogenerating FEI skim documentation.
65 particleName (str): the PDG name of a particle, e.g. ``'K+'``, ``'pi-'``, ``'D*0'``.
67 particleList = fei.get_default_channels(**kwargs)
68 particleDict = {particle.name: particle
for particle
in particleList}
71 particle = particleDict[particleName]
73 print(f
"Error! Couldn't find particle with name {particleName}")
76 channels = [channel.decayString
for channel
in particle.channels]
81 """Wrapper for `functools.lru_cache` to deal with dictionaries. Dictionaries are
82 mutable, so cannot be cached. This wrapper turns all dict arguments into a hashable
83 dict type, so we can use caching.
85 class HashableDict(dict):
87 return hash(frozenset(self.items()))
90 def wrapped(*args, **kwargs):
91 args = tuple([HashableDict(arg)
if isinstance(arg, dict)
else arg
for arg
in args])
92 kwargs = {k: HashableDict(v)
if isinstance(v, dict)
else v
for k, v
in kwargs.items()}
93 return func(*args, **kwargs)
98 """Base class for FEI skims. Applies event-level pre-cuts and applies the FEI."""
100 __authors__ = [
"Racha Cheaib",
"Hannah Wakeling",
"Phil Grace"]
101 __contact__ = __liaison__
102 __category__ =
"physics, Full Event Interpretation"
104 FEIPrefix =
"FEIv4_2022_MC15_light-2205-abys"
105 """Prefix label for the FEI training used in the FEI skims."""
108 """Dict of ``str -> bool`` pairs to be passed to `fei.get_default_channels`. When
109 inheriting from `BaseFEISkim`, override this value to apply the FEI for only *e.g.*
110 SL charged :math:`B`'s."""
112 MergeDataStructures = {
"FEIChannelArgs": _merge_boolean_dicts}
114 NoisyModules = [
"ParticleCombiner"]
116 ApplyHLTHadronCut =
True
117 produce_on_tau_samples =
False
123 Skim pre-cuts are applied before running the FEI, to reduce computation time.
124 This setup function is run by all FEI skims, so they all have the save
125 event-level pre-cuts:
127 * :math:`n_{\\text{cleaned tracks}} \\geq 3`
128 * :math:`n_{\\text{cleaned ECL clusters}} \\geq 3`
129 * :math:`\\text{Visible energy of event (CMS frame)}>4~{\\rm GeV}`
131 We define "cleaned" tracks and clusters as:
133 * Cleaned tracks (``pi+:FEI_cleaned``): :math:`d_0 < 0.5~{\\rm cm}`,
134 :math:`|z_0| < 2~{\\rm cm}`, and :math:`p_T > 0.1~{\\rm GeV}` * Cleaned ECL
135 clusters (``gamma:FEI_cleaned``): :math:`0.296706 < \\theta < 2.61799`, and
136 :math:`E>0.1~{\\rm GeV}`
140 CleanedTrackCuts =
"abs(z0) < 2.0 and abs(d0) < 0.5 and pt > 0.1"
141 CleanedClusterCuts =
"E > 0.1 and 0.296706 < theta < 2.61799"
143 ma.fillParticleList(decayString=
"pi+:FEI_cleaned",
144 cut=CleanedTrackCuts, path=path)
145 ma.fillParticleList(decayString=
"gamma:FEI_cleaned",
146 cut=CleanedClusterCuts, path=path, loadPhotonBeamBackgroundMVA=
False)
148 ma.buildEventKinematics(inputListNames=[
"pi+:FEI_cleaned",
149 "gamma:FEI_cleaned"],
152 EventCuts =
" and ".join(
154 f
"nCleanedTracks({CleanedTrackCuts})>=3",
155 f
"nCleanedECLClusters({CleanedClusterCuts})>=3",
156 "visibleEnergyOfEventCMS>4",
164 ConditionalPath = b2.Path()
165 eselect = path.add_module(
"VariableToReturnValue", variable=f
"passesEventCut({EventCuts})")
166 eselect.if_value(
'=1', ConditionalPath, b2.AfterConditionPath.CONTINUE)
168 return ConditionalPath
177 """Reconstruct hadronic and semileptonic :math:`B^0` and :math:`B^+` tags using
178 the generically trained FEI.
181 FEIChannelArgs (dict(str, bool)): A dict of keyword-boolean pairs to be
182 passed to `fei.get_default_channels`.
183 FEIPrefix (str): Prefix label for the FEI training used in the FEI skims.
184 path (`basf2.Path`): The skim path to be processed.
187 if analysisGlobaltag
is None:
188 b2.B2FATAL(
"The analysis globaltag is not set in the FEI skim.")
189 b2.conditions.prepend_globaltag(analysisGlobaltag)
190 particles = fei.get_default_channels(**FEIChannelArgs)
191 configuration = fei.config.FeiConfiguration(
195 feistate = fei.get_path(particles, configuration)
196 path.add_path(feistate.path)
201 def setup_fei_aliases(FEIChannelArgs):
203 vm.addAlias(
"E_ECL_pi_FEI",
204 "totalECLEnergyOfParticlesInList(pi+:FEI_cleaned)")
205 vm.addAlias(
"E_ECL_gamma_FEI",
206 "totalECLEnergyOfParticlesInList(gamma:FEI_cleaned)")
207 vm.addAlias(
"E_ECL_FEI",
"formula(E_ECL_pi_FEI+E_ECL_gamma_FEI)")
210 vm.addAlias(
"sigProb",
"extraInfo(SignalProbability)")
211 vm.addAlias(
"log10_sigProb",
"log10(extraInfo(SignalProbability))")
212 vm.addAlias(
"dmID",
"extraInfo(decayModeID)")
213 vm.addAlias(
"decayModeID",
"extraInfo(decayModeID)")
215 if "semileptonic" in FEIChannelArgs
and FEIChannelArgs[
"semileptonic"]:
217 vm.addAlias(
"cosThetaBY",
"cosThetaBetweenParticleAndNominalB")
218 vm.addAlias(
"d1_p_CMSframe",
"useCMSFrame(daughter(1,p))")
219 vm.addAlias(
"d2_p_CMSframe",
"useCMSFrame(daughter(2,p))")
222 "conditionalVariableSelector(dmID<4, d1_p_CMSframe, d2_p_CMSframe)"
226 """Apply pre-FEI event-level cuts and apply the FEI. This setup function is run
227 by all FEI skims, so they all have the save event-level pre-cuts.
229 This function passes `FEIChannelArgs` to the cached function `run_fei_for_skims`
230 to avoid applying the FEI twice.
233 `fei_precuts` for event-level cut definitions.
244 def _FEI_skim_header(ParticleNames):
245 """Decorator factory for applying the `fancy_skim_header` header and replacing
246 <CHANNELS> in the class docstring with a list of FEI channels.
248 The list is numbered with all of the corresponding decay mode IDs, and the decay
249 modes are formatted in beautiful LaTeX.
251 .. code-block:: python
253 @FEI_skim_header("B0")
254 class feiSLB0(BaseFEISkim):
255 # docstring here including the string '<CHANNELS>' somewhere
258 ParticleNames (str, list(str)): One of either ``B0`` or ``B+``, or a list of both.
261 def decorator(SkimClass):
262 if isinstance(ParticleNames, str):
263 particles = [ParticleNames]
265 particles = ParticleNames
267 ChannelsString =
"List of reconstructed channels and corresponding decay mode IDs:"
268 for particle
in particles:
269 channels = _get_fei_channel_names(particle, **SkimClass.FEIChannelArgs)
270 FormattedChannels = [_sphinxify_decay(channel)
for channel
in channels]
271 ChannelList =
"\n".join(
272 [f
" {dmID}. {channel}"
273 for (dmID, channel)
in enumerate(FormattedChannels)]
275 if len(particles) == 1:
276 ChannelsString +=
"\n\n" + ChannelList
278 ChannelsString += f
"\n\n ``{particle}`` channels:\n\n" + ChannelList
280 if SkimClass.__doc__
is None:
283 SkimClass.__doc__ = SkimClass.__doc__.replace(
"<CHANNELS>", ChannelsString)
285 return fancy_skim_header(SkimClass)
290 @_FEI_skim_header("B0")
293 Tag side :math:`B` cuts:
295 * :math:`M_{\\text{bc}} > 5.2~{\\rm GeV}`
296 * :math:`|\\Delta E| < 0.3~{\\rm GeV}`
297 * :math:`\\text{signal probability} > 0.001` (omitted for decay mode 23)
299 All available FEI :math:`B^0` hadronic tags are reconstructed. From `Thomas Keck's
300 thesis <https://docs.belle2.org/record/275/files/BELLE2-MTHESIS-2015-001.pdf>`_,
301 "the channel :math:`B^0 \\to \\overline{D}^0 \\pi^0` was used by the FR, but is not
302 yet used in the FEI due to unexpected technical restrictions in the KFitter
308 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
309 event-level cuts made before applying the FEI.
311 __description__ =
"FEI-tagged neutral :math:`B`'s decaying hadronically."
312 validation_sample = _VALIDATION_SAMPLE
318 "semileptonic":
False,
324 ma.applyCuts(
"B0:generic",
"Mbc>5.2", path=path)
325 ma.applyCuts(
"B0:generic",
"abs(deltaE)<0.300", path=path)
326 ma.applyCuts(
"B0:generic",
"sigProb>0.001 or extraInfo(dmID)==23", path=path)
328 return [
"B0:generic"]
335 vm.addAlias(
'sigProb',
'extraInfo(SignalProbability)')
336 vm.addAlias(
'log10_sigProb',
'log10(extraInfo(SignalProbability))')
337 vm.addAlias(
'd0_massDiff',
'daughter(0,massDifference(0))')
338 vm.addAlias(
'd0_M',
'daughter(0,M)')
339 vm.addAlias(
'decayModeID',
'extraInfo(decayModeID)')
340 vm.addAlias(
'nDaug',
'countDaughters(1>0)')
342 histogramFilename = f
"{self}_Validation.root"
344 create_validation_histograms(
345 rootfile=histogramFilename,
346 particlelist=
'B0:generic',
348 (
'sigProb', 100, 0.0, 1.0,
'Signal probability', __liaison__,
349 'Signal probability of the reconstructed tag B candidates',
350 'Most around zero, with a tail at non-zero values.',
'Signal probability',
'Candidates',
'logy'),
351 (
'nDaug', 6, 0.0, 6,
'Number of daughters of tag B', __liaison__,
352 'Number of daughters of tag B',
'Some distribution of number of daughters',
'n_{daughters}',
'Candidates'),
353 (
'd0_massDiff', 100, 0.0, 0.5,
'Mass difference of D* and D', __liaison__,
354 'Mass difference of D^{*} and D',
'Peak at 0.14 GeV',
'm(D^{*})-m(D) [GeV]',
'Candidates',
'shifter'),
355 (
'd0_M', 100, 0.0, 3.0,
'Mass of zeroth daughter (D* or D)', __liaison__,
356 'Mass of zeroth daughter of tag B (either a $D^{*}$ or a D)',
'Peaks at 1.86 GeV and 2.00 GeV',
357 'm(D^{(*)}) [GeV]',
'Candidates',
'shifter'),
358 (
'deltaE', 40, -0.3, 0.3,
'#Delta E', __liaison__,
359 '$\\Delta E$ of event',
'Peak around zero',
'#Delta E [GeV]',
'Candidates',
'shifter'),
360 (
'Mbc', 40, 5.2, 5.3,
'Mbc', __liaison__,
361 'Beam-constrained mass of event',
'Peaking around B mass (5.28 GeV)',
'M_{bc} [GeV]',
'Candidates',
'shifter')],
362 variables_2d=[(
'deltaE', 100, -0.3, 0.3,
'Mbc', 100, 5.2, 5.3,
'Mbc vs deltaE', __liaison__,
363 'Plot of the $\\Delta E$ of the event against the beam constrained mass',
364 'Peak of $\\Delta E$ around zero, and $M_{bc}$ around B mass (5.28 GeV)',
365 '#Delta E [GeV]',
'M_{bc} [GeV]',
'colz'),
366 (
'decayModeID', 26, 0, 26,
'log10_sigProb', 100, -3.0, 0.0,
367 'Signal probability for each decay mode ID', __liaison__,
368 'Signal probability for each decay mode ID',
369 'Some distribtuion of candidates in the first few decay mode IDs',
370 'Decay mode ID',
'#log_10(signal probability)',
'colz')],
374 @_FEI_skim_header("B+")
377 Tag side :math:`B` cuts:
379 * :math:`M_{\\text{bc}} > 5.2~{\\rm GeV}`
380 * :math:`|\\Delta E| < 0.3~{\\rm GeV}`
381 * :math:`\\text{signal probability} > 0.001` (omitted for decay mode 25)
383 All available FEI :math:`B^+` hadronic tags are reconstructed.
388 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
389 event-level cuts made before applying the FEI.
391 __description__ =
"FEI-tagged charged :math:`B`'s decaying hadronically."
392 validation_sample = _VALIDATION_SAMPLE
398 "semileptonic":
False,
404 ma.applyCuts(
"B+:generic",
"Mbc>5.2", path=path)
405 ma.applyCuts(
"B+:generic",
"abs(deltaE)<0.300", path=path)
406 ma.applyCuts(
"B+:generic",
"sigProb>0.001 or extraInfo(dmID)==25", path=path)
408 return [
"B+:generic"]
415 vm.addAlias(
'sigProb',
'extraInfo(SignalProbability)')
416 vm.addAlias(
'log10_sigProb',
'log10(extraInfo(SignalProbability))')
417 vm.addAlias(
'd0_massDiff',
'daughter(0,massDifference(0))')
418 vm.addAlias(
'd0_M',
'daughter(0,M)')
419 vm.addAlias(
'decayModeID',
'extraInfo(decayModeID)')
420 vm.addAlias(
'nDaug',
'countDaughters(1>0)')
422 histogramFilename = f
"{self}_Validation.root"
424 create_validation_histograms(
425 rootfile=histogramFilename,
426 particlelist=
'B+:generic',
428 (
'sigProb', 100, 0.0, 1.0,
'Signal probability', __liaison__,
429 'Signal probability of the reconstructed tag B candidates',
'Most around zero, with a tail at non-zero values.',
430 'Signal probability',
'Candidates',
'logy'),
431 (
'nDaug', 6, 0.0, 6,
'Number of daughters of tag B', __liaison__,
432 'Number of daughters of tag B',
'Some distribution of number of daughters',
'n_{daughters}',
'Candidates'),
433 (
'd0_massDiff', 100, 0.0, 0.5,
'Mass difference of D* and D', __liaison__,
434 'Mass difference of D^{*} and D',
'Peak at 0.14 GeV',
'm(D^{*})-m(D) [GeV]',
'Candidates',
'shifter'),
435 (
'd0_M', 100, 0.0, 3.0,
'Mass of zeroth daughter (D* or D)', __liaison__,
436 'Mass of zeroth daughter of tag B (either a $D^{*}$ or a D)',
'Peaks at 1.86 GeV and 2.00 GeV',
437 'm(D^{(*)}) [GeV]',
'Candidates',
'shifter'),
438 (
'deltaE', 40, -0.3, 0.3,
'#Delta E', __liaison__,
439 '$\\Delta E$ of event',
'Peak around zero',
'#Delta E [GeV]',
'Candidates',
'shifter'),
440 (
'Mbc', 40, 5.2, 5.3,
'Mbc', __liaison__,
441 'Beam-constrained mass of event',
'Peak around B mass (5.28 GeV)',
'M_{bc} [GeV]',
'Candidates',
'shifter')],
442 variables_2d=[(
'deltaE', 100, -0.3, 0.3,
'Mbc', 100, 5.2, 5.3,
'Mbc vs deltaE', __liaison__,
443 'Plot of the $\\Delta E$ of the event against the beam constrained mass',
444 'Peak of $\\Delta E$ around zero, and $M_{bc}$ around B mass (5.28 GeV)',
445 '#Delta E [GeV]',
'M_{bc} [GeV]',
'colz'),
446 (
'decayModeID', 29, 0, 29,
'log10_sigProb', 100, -3.0, 0.0,
447 'Signal probability for each decay mode ID', __liaison__,
448 'Signal probability for each decay mode ID',
449 'Some distribtuion of candidates in the first few decay mode IDs',
450 'Decay mode ID',
'#log_10(signal probability)',
'colz')],
454 @_FEI_skim_header("B0")
457 Tag side :math:`B` cuts:
459 * :math:`-4 < \\cos\\theta_{BY} < 3`
460 * :math:`\\log_{10}(\\text{signal probability}) > -2.4`
461 * :math:`p_{\\ell}^{*} > 1.0~{\\rm GeV}` in CMS frame
463 SL :math:`B^0` tags are reconstructed. Hadronic :math:`B` with SL :math:`D` are not
464 reconstructed, as these are rare and time-intensive.
469 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
470 event-level cuts made before applying the FEI.
472 __description__ =
"FEI-tagged neutral :math:`B`'s decaying semileptonically."
473 validation_sample = _VALIDATION_SAMPLE
479 "semileptonic":
True,
486 ma.applyCuts(
"B0:semileptonic",
"dmID<8", path=path)
487 ma.applyCuts(
"B0:semileptonic",
"log10(sigProb)>-2.4", path=path)
488 ma.applyCuts(
"B0:semileptonic",
"-4.0<cosThetaBY<3.0", path=path)
489 ma.applyCuts(
"B0:semileptonic",
"p_lepton_CMSframe>1.0", path=path)
491 return [
"B0:semileptonic"]
498 vm.addAlias(
'sigProb',
'extraInfo(SignalProbability)')
499 vm.addAlias(
'log10_sigProb',
'log10(extraInfo(SignalProbability))')
500 vm.addAlias(
'd0_massDiff',
'daughter(0,massDifference(0))')
501 vm.addAlias(
'd0_M',
'daughter(0,M)')
502 vm.addAlias(
'decayModeID',
'extraInfo(decayModeID)')
503 vm.addAlias(
'nDaug',
'countDaughters(1>0)')
505 histogramFilename = f
"{self}_Validation.root"
507 create_validation_histograms(
508 rootfile=histogramFilename,
509 particlelist=
'B0:semileptonic',
511 (
'sigProb', 100, 0.0, 1.0,
'Signal probability', __liaison__,
512 'Signal probability of the reconstructed tag B candidates',
'Most around zero, with a tail at non-zero values.',
513 'Signal probability',
'Candidates',
'logy'),
514 (
'nDaug', 6, 0.0, 6,
'Number of daughters of tag B', __liaison__,
515 'Number of daughters of tag B',
'Some distribution of number of daughters',
'n_{daughters}',
'Candidates'),
516 (
'cosThetaBetweenParticleAndNominalB', 100, -6.0, 4.0,
'#cos#theta_{BY}', __liaison__,
517 'Cosine of angle between the reconstructed B and the nominal B',
'Distribution peaking between -1 and 1',
518 '#cos#theta_{BY}',
'Candidates'),
519 (
'd0_massDiff', 100, 0.0, 0.5,
'Mass difference of D* and D', __liaison__,
520 'Mass difference of $D^{*}$ and D',
'Peak at 0.14 GeV',
'm(D^{*})-m(D) [GeV]',
'Candidates',
'shifter'),
521 (
'd0_M', 100, 0.0, 3.0,
'Mass of zeroth daughter (D* or D)', __liaison__,
522 'Mass of zeroth daughter of tag B (either a $D^{*}$ or a D)',
'Peaks at 1.86 GeV and 2.00 GeV',
523 'm(D^{(*)}) [GeV]',
'Candidates',
'shifter')],
524 variables_2d=[(
'decayModeID', 8, 0, 8,
'log10_sigProb', 100, -3.0, 0.0,
525 'Signal probability for each decay mode ID', __liaison__,
526 'Signal probability for each decay mode ID',
527 'Some distribtuion of candidates in the first few decay mode IDs',
528 'Decay mode ID',
'#log_10(signal probability)',
'colz')],
532 @_FEI_skim_header("B+")
535 Tag side :math:`B` cuts:
537 * :math:`-4 < \\cos\\theta_{BY} < 3`
538 * :math:`\\log_{10}(\\text{signal probability}) > -2.4`
539 * :math:`p_{\\ell}^{*} > 1.0~{\\rm GeV}` in CMS frame
541 SL :math:`B^+` tags are reconstructed. Hadronic :math:`B^+` with SL :math:`D` are
542 not reconstructed, as these are rare and time-intensive.
547 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
548 event-level cuts made before applying the FEI.
550 __description__ =
"FEI-tagged charged :math:`B`'s decaying semileptonically."
551 validation_sample = _VALIDATION_SAMPLE
557 "semileptonic":
True,
564 ma.applyCuts(
"B+:semileptonic",
"dmID<8", path=path)
565 ma.applyCuts(
"B+:semileptonic",
"log10_sigProb>-2.4", path=path)
566 ma.applyCuts(
"B+:semileptonic",
"-4.0<cosThetaBY<3.0", path=path)
567 ma.applyCuts(
"B+:semileptonic",
"p_lepton_CMSframe>1.0", path=path)
569 return [
"B+:semileptonic"]
576 vm.addAlias(
'sigProb',
'extraInfo(SignalProbability)')
577 vm.addAlias(
'log10_sigProb',
'log10(extraInfo(SignalProbability))')
578 vm.addAlias(
'd0_massDiff',
'daughter(0,massDifference(0))')
579 vm.addAlias(
'd0_M',
'daughter(0,M)')
580 vm.addAlias(
'decayModeID',
'extraInfo(decayModeID)')
581 vm.addAlias(
'nDaug',
'countDaughters(1>0)')
583 histogramFilename = f
"{self}_Validation.root"
585 create_validation_histograms(
586 rootfile=histogramFilename,
587 particlelist=
'B+:semileptonic',
589 (
'sigProb', 100, 0.0, 1.0,
'Signal probability', __liaison__,
590 'Signal probability of the reconstructed tag B candidates',
591 'Most around zero, with a tail at non-zero values.',
'Signal probability',
'Candidates',
'logy'),
592 (
'nDaug', 6, 0.0, 6,
'Number of daughters of tag B', __liaison__,
593 'Number of daughters of tag B',
'Some distribution of number of daughters',
'n_{daughters}',
'Candidates'),
594 (
'cosThetaBetweenParticleAndNominalB', 100, -6.0, 4.0,
'#cos#theta_{BY}', __liaison__,
595 'Cosine of angle between the reconstructed B and the nominal B',
'Distribution peaking between -1 and 1',
596 '#cos#theta_{BY}',
'Candidates'),
597 (
'd0_massDiff', 100, 0.0, 0.5,
'Mass difference of D* and D', __liaison__,
598 'Mass difference of $D^{*}$ and D',
'Peak at 0.14 GeV',
'm(D^{*})-m(D) [GeV]',
'Candidates',
'shifter'),
599 (
'd0_M', 100, 0.0, 3.0,
'Mass of zeroth daughter (D* or D)', __liaison__,
600 'Mass of zeroth daughter of tag B (either a $D^{*}$ or a D)',
'Peaks at 1.86 GeV and 2.00 GeV',
601 'm(D^{(*)}) [GeV]',
'Candidates',
'shifter')],
602 variables_2d=[(
'decayModeID', 8, 0, 8,
'log10_sigProb', 100, -3.0, 0.0,
603 'Signal probability for each decay mode ID', __liaison__,
604 'Signal probability for each decay mode ID',
605 'Some distribtuion of candidates in the first few decay mode IDs',
606 'Decay mode ID',
'#log_10(signal probability)',
'colz')],
610 @_FEI_skim_header(["B0", "B+"])
613 Tag side :math:`B` cuts:
615 * :math:`M_{\\text{bc}} > 5.2~{\\rm GeV}`
616 * :math:`|\\Delta E| < 0.3~{\\rm GeV}`
617 * :math:`\\text{signal probability} > 0.001` (omitted for decay mode 23 for
618 :math:`B^+`, and decay mode 25 for :math:`B^0`)
620 All available FEI :math:`B^0` and :math:`B^+` hadronic tags are reconstructed. From
621 `Thomas Keck's thesis
622 <https://docs.belle2.org/record/275/files/BELLE2-MTHESIS-2015-001.pdf>`_, "the
623 channel :math:`B^0 \\to \\overline{D}^0 \\pi^0` was used by the FR, but is not yet
624 used in the FEI due to unexpected technical restrictions in the KFitter algorithm".
629 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
630 event-level cuts made before applying the FEI.
632 __description__ =
"FEI-tagged neutral and charged :math:`B`'s decaying hadronically."
638 "semileptonic":
False,
644 ma.copyList(
"B0:feiHadronic",
"B0:generic", path=path)
645 ma.copyList(
"B+:feiHadronic",
"B+:generic", path=path)
646 HadronicBLists = [
"B0:feiHadronic",
"B+:feiHadronic"]
648 for BList
in HadronicBLists:
649 ma.applyCuts(BList,
"Mbc>5.2", path=path)
650 ma.applyCuts(BList,
"abs(deltaE)<0.300", path=path)
652 ma.applyCuts(
"B+:feiHadronic",
"sigProb>0.001 or extraInfo(dmID)==25", path=path)
653 ma.applyCuts(
"B0:feiHadronic",
"sigProb>0.001 or extraInfo(dmID)==23", path=path)
655 return HadronicBLists
658 @_FEI_skim_header(["B0", "B+"])
661 Tag side :math:`B` cuts:
663 * :math:`-4 < \\cos\\theta_{BY} < 3`
664 * :math:`\\log_{10}(\\text{signal probability}) > -2.4`
665 * :math:`p_{\\ell}^{*} > 1.0~{\\rm GeV}` in CMS frame
667 SL :math:`B^0` and :math:`B^+` tags are reconstructed. Hadronic :math:`B` with SL
668 :math:`D` are not reconstructed, as these are rare and time-intensive.
673 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
674 event-level cuts made before applying the FEI.
676 __description__ =
"FEI-tagged neutral and charged :math:`B`'s decaying semileptonically."
682 "semileptonic":
True,
689 ma.copyList(
"B0:feiSL",
"B0:semileptonic", path=path)
690 ma.copyList(
"B+:feiSL",
"B+:semileptonic", path=path)
691 SLBLists = [
"B0:feiSL",
"B+:feiSL"]
693 Bcuts = [
"log10_sigProb>-2.4",
"-4.0<cosThetaBY<3.0",
"p_lepton_CMSframe>1.0"]
695 for BList
in SLBLists:
697 ma.applyCuts(BList, cut, path=path)
def run_fei_for_skims(FEIChannelArgs, FEIPrefix, analysisGlobaltag, *path)
def additional_setup(self, path)
def setup_fei_aliases(FEIChannelArgs)
dictionary FEIChannelArgs
def build_lists(self, path)
def validation_histograms(self, path)
def build_lists(self, path)
def validation_histograms(self, path)
def build_lists(self, path)
def build_lists(self, path)
def validation_histograms(self, path)
def build_lists(self, path)
def validation_histograms(self, path)
def build_lists(self, path)