5 (Semi-)Leptonic Working Group Skims for missing energy modes that use the `FullEventInterpretation` (FEI) algorithm.
14 from functools
import lru_cache, wraps
18 import modularAnalysis
as ma
19 from skimExpertFunctions
import BaseSkim, _sphinxify_decay, fancy_skim_header
20 from variables
import variables
as vm
22 __liaison__ =
"Shanette De La Motte <shanette.delamotte@adelaide.edu.au>"
25 def _merge_boolean_dicts(*dicts):
26 """Merge dicts of boolean, with `True` values taking precedence if values
29 This is a utility function for combining FEI configs. It acts in the following
32 >>> d1 = {"neutralB": True, "chargedB": False, "hadronic": True}
33 >>> d2 = {"chargedB": True, "semileptonic": True}
34 >>> _merge_FEI_configs(d1, d2)
35 {"chargedB": True, "hadronic": True, "neutralB": True, "semileptonic": True}
38 dicts (dict(str -> bool)): Any number of dicts of keyword-boolean pairs.
41 merged (dict(str -> bool)): A single dict, containing all the keys of the
44 keys = {k
for d
in dicts
for k
in d}
45 occurances = {k: [d
for d
in dicts
if k
in d]
for k
in keys}
46 merged = {k: any(d[k]
for d
in occurances[k])
for k
in keys}
49 merged = dict(sorted(merged.items()))
54 def _get_fei_channel_names(particleName, **kwargs):
55 """Create a list containing the decay strings of all decay channels available to a
56 particle. Any keyword arguments are passed to `fei.get_default_channels`.
58 This is a utility function for autogenerating FEI skim documentation.
61 particleName (str): the PDG name of a particle, e.g. ``'K+'``, ``'pi-'``, ``'D*0'``.
63 particleList = fei.get_default_channels(**kwargs)
64 particleDict = {particle.name: particle
for particle
in particleList}
67 particle = particleDict[particleName]
69 print(f
"Error! Couldn't find particle with name {particleName}")
72 channels = [channel.decayString
for channel
in particle.channels]
77 """Wrapper for `functools.lru_cache` to deal with dictionaries. Dictionaries are
78 mutable, so cannot be cached. This wrapper turns all dict arguments into a hashable
79 dict type, so we can use caching.
81 class HashableDict(dict):
83 return hash(frozenset(self.items()))
86 def wrapped(*args, **kwargs):
87 args = tuple([HashableDict(arg)
if isinstance(arg, dict)
else arg
for arg
in args])
88 kwargs = {k: HashableDict(v)
if isinstance(v, dict)
else v
for k, v
in kwargs.items()}
89 return func(*args, **kwargs)
94 """Base class for FEI skims. Applies event-level pre-cuts and applies the FEI."""
96 __authors__ = [
"Racha Cheaib",
"Hannah Wakeling",
"Phil Grace"]
97 __contact__ = __liaison__
98 __category__ =
"physics, Full Event Interpretation"
100 FEIPrefix =
"FEIv4_2021_MC14_release_05_01_12"
101 """Prefix label for the FEI training used in the FEI skims."""
104 """Dict of ``str -> bool`` pairs to be passed to `fei.get_default_channels`. When
105 inheriting from `BaseFEISkim`, override this value to apply the FEI for only *e.g.*
106 SL charged :math:`B`'s."""
108 MergeDataStructures = {
"FEIChannelArgs": _merge_boolean_dicts}
110 NoisyModules = [
"ParticleCombiner"]
112 ApplyHLTHadronCut =
True
113 produce_on_tau_samples =
False
119 Skim pre-cuts are applied before running the FEI, to reduce computation time.
120 This setup function is run by all FEI skims, so they all have the save
121 event-level pre-cuts:
123 * :math:`n_{\\text{cleaned tracks}} \\geq 3`
124 * :math:`n_{\\text{cleaned ECL clusters}} \\geq 3`
125 * :math:`\\text{Visible energy of event (CMS frame)}>4~{\\rm GeV}`
126 * :math:`2~{\\rm GeV}<E_{\\text{cleaned tracks & clusters in
129 We define "cleaned" tracks and clusters as:
131 * Cleaned tracks (``pi+:FEI_cleaned``): :math:`d_0 < 0.5~{\\rm cm}`,
132 :math:`|z_0| < 2~{\\rm cm}`, and :math:`p_T > 0.1~{\\rm GeV}` * Cleaned ECL
133 clusters (``gamma:FEI_cleaned``): :math:`0.296706 < \\theta < 2.61799`, and
134 :math:`E>0.1~{\\rm GeV}`
138 CleanedTrackCuts =
"abs(z0) < 2.0 and abs(d0) < 0.5 and pt > 0.1"
139 CleanedClusterCuts =
"E > 0.1 and 0.296706 < theta < 2.61799"
141 ma.fillParticleList(decayString=
"pi+:FEI_cleaned",
142 cut=CleanedTrackCuts, path=path)
143 ma.fillParticleList(decayString=
"gamma:FEI_cleaned",
144 cut=CleanedClusterCuts, path=path)
146 ma.buildEventKinematics(inputListNames=[
"pi+:FEI_cleaned",
147 "gamma:FEI_cleaned"],
150 EventCuts =
" and ".join(
152 f
"nCleanedTracks({CleanedTrackCuts})>=3",
153 f
"nCleanedECLClusters({CleanedClusterCuts})>=3",
154 "visibleEnergyOfEventCMS>4",
163 ConditionalPath = b2.Path()
164 eselect = path.add_module(
"VariableToReturnValue", variable=f
"passesEventCut({EventCuts})")
165 eselect.if_value(
'=1', ConditionalPath, b2.AfterConditionPath.CONTINUE)
167 return ConditionalPath
176 """Reconstruct hadronic and semileptonic :math:`B^0` and :math:`B^+` tags using
177 the generically trained FEI.
180 FEIChannelArgs (dict(str, bool)): A dict of keyword-boolean pairs to be
181 passed to `fei.get_default_channels`.
182 FEIPrefix (str): Prefix label for the FEI training used in the FEI skims.
183 path (`basf2.Path`): The skim path to be processed.
186 b2.conditions.prepend_globaltag(ma.getAnalysisGlobaltag())
187 particles = fei.get_default_channels(**FEIChannelArgs)
188 configuration = fei.config.FeiConfiguration(
192 feistate = fei.get_path(particles, configuration)
193 path.add_path(feistate.path)
198 def setup_fei_aliases(FEIChannelArgs):
200 vm.addAlias(
"E_ECL_pi_FEI",
201 "totalECLEnergyOfParticlesInList(pi+:FEI_cleaned)")
202 vm.addAlias(
"E_ECL_gamma_FEI",
203 "totalECLEnergyOfParticlesInList(gamma:FEI_cleaned)")
204 vm.addAlias(
"E_ECL_FEI",
"formula(E_ECL_pi_FEI+E_ECL_gamma_FEI)")
207 vm.addAlias(
"sigProb",
"extraInfo(SignalProbability)")
208 vm.addAlias(
"log10_sigProb",
"log10(extraInfo(SignalProbability))")
209 vm.addAlias(
"dmID",
"extraInfo(decayModeID)")
210 vm.addAlias(
"decayModeID",
"extraInfo(decayModeID)")
212 if "semileptonic" in FEIChannelArgs
and FEIChannelArgs[
"semileptonic"]:
214 vm.addAlias(
"cosThetaBY",
"cosThetaBetweenParticleAndNominalB")
215 vm.addAlias(
"d1_p_CMSframe",
"useCMSFrame(daughter(1,p))")
216 vm.addAlias(
"d2_p_CMSframe",
"useCMSFrame(daughter(2,p))")
219 "conditionalVariableSelector(dmID<4, d1_p_CMSframe, d2_p_CMSframe)"
223 """Apply pre-FEI event-level cuts and apply the FEI. This setup function is run
224 by all FEI skims, so they all have the save event-level pre-cuts.
226 This function passes `FEIChannelArgs` to the cached function `run_fei_for_skims`
227 to avoid applying the FEI twice.
230 `fei_precuts` for event-level cut definitions.
241 def _FEI_skim_header(ParticleNames):
242 """Decorator factory for applying the `fancy_skim_header` header and replacing
243 <CHANNELS> in the class docstring with a list of FEI channels.
245 The list is numbered with all of the corresponding decay mode IDs, and the decay
246 modes are formatted in beautiful LaTeX.
248 .. code-block:: python
250 @FEI_skim_header("B0")
251 class feiSLB0(BaseFEISkim):
252 # docstring here including the string '<CHANNELS>' somewhere
255 ParticleNames (str, list(str)): One of either ``B0`` or ``B+``, or a list of both.
258 def decorator(SkimClass):
259 if isinstance(ParticleNames, str):
260 particles = [ParticleNames]
262 particles = ParticleNames
264 ChannelsString =
"List of reconstructed channels and corresponding decay mode IDs:"
265 for particle
in particles:
266 channels = _get_fei_channel_names(particle, **SkimClass.FEIChannelArgs)
267 FormattedChannels = [_sphinxify_decay(channel)
for channel
in channels]
268 ChannelList =
"\n".join(
269 [f
" {dmID}. {channel}"
270 for (dmID, channel)
in enumerate(FormattedChannels)]
272 if len(particles) == 1:
273 ChannelsString +=
"\n\n" + ChannelList
275 ChannelsString += f
"\n\n ``{particle}`` channels:\n\n" + ChannelList
277 if SkimClass.__doc__
is None:
280 SkimClass.__doc__ = SkimClass.__doc__.replace(
"<CHANNELS>", ChannelsString)
282 return fancy_skim_header(SkimClass)
287 @_FEI_skim_header(
"B0")
290 Tag side :math:`B` cuts:
292 * :math:`M_{\\text{bc}} > 5.24~{\\rm GeV}`
293 * :math:`|\\Delta E| < 0.2~{\\rm GeV}`
294 * :math:`\\text{signal probability} > 0.001` (omitted for decay mode 23)
296 All available FEI :math:`B^0` hadronic tags are reconstructed. From `Thomas Keck's
297 thesis <https://docs.belle2.org/record/275/files/BELLE2-MTHESIS-2015-001.pdf>`_,
298 "the channel :math:`B^0 \\to \\overline{D}^0 \\pi^0` was used by the FR, but is not
299 yet used in the FEI due to unexpected technical restrictions in the KFitter
305 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
306 event-level cuts made before applying the FEI.
308 __description__ =
"FEI-tagged neutral :math:`B`'s decaying hadronically."
314 "semileptonic":
False,
320 ma.applyCuts(
"B0:generic",
"Mbc>5.24", path=path)
321 ma.applyCuts(
"B0:generic",
"abs(deltaE)<0.200", path=path)
322 ma.applyCuts(
"B0:generic",
"sigProb>0.001 or extraInfo(dmID)==23", path=path)
331 vm.addAlias(
"d0_massDiff",
"daughter(0,massDifference(0))")
332 vm.addAlias(
"d0_M",
"daughter(0,M)")
333 vm.addAlias(
"nDaug",
"countDaughters(1>0)")
335 histogramFilename = f
"{self}_Validation.root"
336 email =
"Phil Grace <philip.grace@adelaide.edu.au>"
340 (
"sigProb", 100, 0.0, 1.0,
"Signal probability", email,
341 "Signal probability of the reconstructed tag B candidates",
342 "Most around zero, with a tail at non-zero values.",
"Signal probability",
"Candidates",
"logy"),
343 (
"nDaug", 6, 0.0, 6,
"Number of daughters of tag B", email,
344 "Number of daughters of tag B",
"Some distribution of number of daughters",
"n_{daughters}",
"Candidates"),
345 (
"d0_massDiff", 100, 0.0, 0.5,
"Mass difference of D* and D", email,
346 "Mass difference of D^{*} and D",
"Peak at 0.14 GeV",
"m(D^{*})-m(D) [GeV]",
"Candidates",
"shifter"),
347 (
"d0_M", 100, 0.0, 3.0,
"Mass of zeroth daughter (D* or D)", email,
348 "Mass of zeroth daughter of tag B (either a $D^{*}$ or a D)",
"Peaks at 1.86 GeV and 2.00 GeV",
349 "m(D^{(*)}) [GeV]",
"Candidates",
"shifter"),
350 (
"deltaE", 100, -0.2, 0.2,
"#Delta E", email,
351 "$\\Delta E$ of event",
"Peak around zero",
"#Delta E [GeV]",
"Candidates"),
352 (
"Mbc", 100, 5.2, 5.3,
"Mbc", email,
353 "Beam-constrained mass of event",
"Peaking around B mass (5.28 GeV)",
"M_{bc} [GeV]",
"Candidates")
357 (
"deltaE", 100, -0.2, 0.2,
"Mbc", 100, 5.2, 5.3,
"Mbc vs deltaE", email,
358 "Plot of the $\\Delta E$ of the event against the beam constrained mass",
359 "Peak of $\\Delta E$ around zero, and $M_{bc}$ around B mass (5.28 GeV)",
360 "#Delta E [GeV]",
"M_{bc} [GeV]",
"colz, shifter"),
361 (
"decayModeID", 26, 0, 26,
"log10_sigProb", 100, -3.0, 0.0,
362 "Signal probability for each decay mode ID", email,
363 "Signal probability for each decay mode ID",
364 "Some distribtuion of candidates in the first few decay mode IDs",
365 "Decay mode ID",
"#log_10(signal probability)",
"colz")
368 create_validation_histograms(
369 rootfile=histogramFilename,
370 particlelist=SkimList,
371 variables_1d=variables_1d,
372 variables_2d=variables_2d,
377 @_FEI_skim_header(
"B+")
380 Tag side :math:`B` cuts:
382 * :math:`M_{\\text{bc}} > 5.24~{\\rm GeV}`
383 * :math:`|\\Delta E| < 0.2~{\\rm GeV}`
384 * :math:`\\text{signal probability} > 0.001` (omitted for decay mode 25)
386 All available FEI :math:`B^+` hadronic tags are reconstructed.
391 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
392 event-level cuts made before applying the FEI.
394 __description__ =
"FEI-tagged charged :math:`B`'s decaying hadronically."
400 "semileptonic":
False,
406 ma.applyCuts(
"B+:generic",
"Mbc>5.24", path=path)
407 ma.applyCuts(
"B+:generic",
"abs(deltaE)<0.200", path=path)
408 ma.applyCuts(
"B+:generic",
"sigProb>0.001 or extraInfo(dmID)==25", path=path)
417 vm.addAlias(
"d0_massDiff",
"daughter(0,massDifference(0))")
418 vm.addAlias(
"d0_M",
"daughter(0,M)")
419 vm.addAlias(
"nDaug",
"countDaughters(1>0)")
421 histogramFilename = f
"{self}_Validation.root"
422 email =
"Phil Grace <philip.grace@adelaide.edu.au>"
426 (
"sigProb", 100, 0.0, 1.0,
"Signal probability", email,
427 "Signal probability of the reconstructed tag B candidates",
428 "Most around zero, with a tail at non-zero values.",
"Signal probability",
"Candidates",
"logy"),
429 (
"nDaug", 6, 0.0, 6,
"Number of daughters of tag B", email,
430 "Number of daughters of tag B",
"Some distribution of number of daughters",
"n_{daughters}",
"Candidates"),
431 (
"d0_massDiff", 100, 0.0, 0.5,
"Mass difference of D* and D", email,
432 "Mass difference of D^{*} and D",
"Peak at 0.14 GeV",
"m(D^{*})-m(D) [GeV]",
"Candidates",
"shifter"),
433 (
"d0_M", 100, 0.0, 3.0,
"Mass of zeroth daughter (D* or D)", email,
434 "Mass of zeroth daughter of tag B (either a $D^{*}$ or a D)",
"Peaks at 1.86 GeV and 2.00 GeV",
435 "m(D^{(*)}) [GeV]",
"Candidates",
"shifter"),
436 (
"deltaE", 100, -0.2, 0.2,
"#Delta E", email,
437 "$\\Delta E$ of event",
"Peak around zero",
"#Delta E [GeV]",
"Candidates"),
438 (
"Mbc", 100, 5.2, 5.3,
"Mbc", email,
439 "Beam-constrained mass of event",
"Peaking around B mass (5.28 GeV)",
"M_{bc} [GeV]",
"Candidates")
443 (
"deltaE", 100, -0.2, 0.2,
"Mbc", 100, 5.2, 5.3,
"Mbc vs deltaE", email,
444 "Plot of the $\\Delta E$ of the event against the beam constrained mass",
445 "Peak of $\\Delta E$ around zero, and $M_{bc}$ around B mass (5.28 GeV)",
446 "#Delta E [GeV]",
"M_{bc} [GeV]",
"colz, shifter"),
447 (
"decayModeID", 29, 0, 29,
"log10_sigProb", 100, -3.0, 0.0,
448 "Signal probability for each decay mode ID", email,
449 "Signal probability for each decay mode ID",
450 "Some distribtuion of candidates in the first few decay mode IDs",
451 "Decay mode ID",
"#log_10(signal probability)",
"colz")
454 create_validation_histograms(
455 rootfile=histogramFilename,
456 particlelist=SkimList,
457 variables_1d=variables_1d,
458 variables_2d=variables_2d,
463 @_FEI_skim_header(
"B0")
466 Tag side :math:`B` cuts:
468 * :math:`-4 < \\cos\\theta_{BY} < 3`
469 * :math:`\\log_{10}(\\text{signal probability}) > -2.4`
470 * :math:`p_{\\ell}^{*} > 1.0~{\\rm GeV}` in CMS frame
472 SL :math:`B^0` tags are reconstructed. Hadronic :math:`B` with SL :math:`D` are not
473 reconstructed, as these are rare and time-intensive.
478 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
479 event-level cuts made before applying the FEI.
481 __description__ =
"FEI-tagged neutral :math:`B`'s decaying semileptonically."
487 "semileptonic":
True,
494 ma.applyCuts(
"B0:semileptonic",
"dmID<8", path=path)
495 ma.applyCuts(
"B0:semileptonic",
"log10(sigProb)>-2.4", path=path)
496 ma.applyCuts(
"B0:semileptonic",
"-4.0<cosThetaBY<3.0", path=path)
497 ma.applyCuts(
"B0:semileptonic",
"p_lepton_CMSframe>1.0", path=path)
506 vm.addAlias(
"d0_massDiff",
"daughter(0,massDifference(0))")
507 vm.addAlias(
"d0_M",
"daughter(0,M)")
508 vm.addAlias(
"nDaug",
"countDaughters(1>0)")
510 histogramFilename = f
"{self}_Validation.root"
511 email =
"Phil Grace <philip.grace@adelaide.edu.au>"
515 (
"sigProb", 100, 0.0, 1.0,
"Signal probability", email,
516 "Signal probability of the reconstructed tag B candidates",
517 "Most around zero, with a tail at non-zero values.",
518 "Signal probability",
"Candidates",
"logy"),
519 (
"nDaug", 6, 0.0, 6,
"Number of daughters of tag B", email,
520 "Number of daughters of tag B",
"Some distribution of number of daughters",
521 "n_{daughters}",
"Candidates"),
522 (
"cosThetaBetweenParticleAndNominalB", 100, -6.0, 4.0,
"#cos#theta_{BY}", email,
523 "Cosine of angle between the reconstructed B and the nominal B",
524 "Distribution peaking between -1 and 1",
"#cos#theta_{BY}",
"Candidates"),
525 (
"d0_massDiff", 100, 0.0, 0.5,
"Mass difference of D* and D", email,
526 "Mass difference of $D^{*}$ and D",
"Peak at 0.14 GeV",
"m(D^{*})-m(D) [GeV]",
527 "Candidates",
"shifter"),
528 (
"d0_M", 100, 0.0, 3.0,
"Mass of zeroth daughter (D* or D)", email,
529 "Mass of zeroth daughter of tag B (either a $D^{*}$ or a D)",
"Peaks at 1.86 GeV and 2.00 GeV",
530 "m(D^{(*)}) [GeV]",
"Candidates",
"shifter")
534 (
"decayModeID", 8, 0, 8,
"log10_sigProb", 100, -3.0, 0.0,
535 "Signal probability for each decay mode ID", email,
536 "Signal probability for each decay mode ID",
537 "Some distribtuion of candidates in the first few decay mode IDs",
538 "Decay mode ID",
"#log_10(signal probability)",
"colz")
541 create_validation_histograms(
542 rootfile=histogramFilename,
543 particlelist=SkimList,
544 variables_1d=variables_1d,
545 variables_2d=variables_2d,
550 @_FEI_skim_header(
"B+")
553 Tag side :math:`B` cuts:
555 * :math:`-4 < \\cos\\theta_{BY} < 3`
556 * :math:`\\log_{10}(\\text{signal probability}) > -2.4`
557 * :math:`p_{\\ell}^{*} > 1.0~{\\rm GeV}` in CMS frame
559 SL :math:`B^+` tags are reconstructed. Hadronic :math:`B^+` with SL :math:`D` are
560 not reconstructed, as these are rare and time-intensive.
565 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
566 event-level cuts made before applying the FEI.
568 __description__ =
"FEI-tagged charged :math:`B`'s decaying semileptonically."
574 "semileptonic":
True,
581 ma.applyCuts(
"B+:semileptonic",
"dmID<8", path=path)
582 ma.applyCuts(
"B+:semileptonic",
"log10_sigProb>-2.4", path=path)
583 ma.applyCuts(
"B+:semileptonic",
"-4.0<cosThetaBY<3.0", path=path)
584 ma.applyCuts(
"B+:semileptonic",
"p_lepton_CMSframe>1.0", path=path)
593 vm.addAlias(
"d0_massDiff",
"daughter(0,massDifference(0))")
594 vm.addAlias(
"d0_M",
"daughter(0,M)")
595 vm.addAlias(
"nDaug",
"countDaughters(1>0)")
597 histogramFilename = f
"{self}_Validation.root"
598 email =
"Phil Grace <philip.grace@adelaide.edu.au>"
602 (
"sigProb", 100, 0.0, 1.0,
"Signal probability", email,
603 "Signal probability of the reconstructed tag B candidates",
604 "Most around zero, with a tail at non-zero values.",
605 "Signal probability",
"Candidates",
"logy"),
606 (
"nDaug", 6, 0.0, 6,
"Number of daughters of tag B", email,
607 "Number of daughters of tag B",
"Some distribution of number of daughters",
608 "n_{daughters}",
"Candidates"),
609 (
"cosThetaBetweenParticleAndNominalB", 100, -6.0, 4.0,
"#cos#theta_{BY}", email,
610 "Cosine of angle between the reconstructed B and the nominal B",
611 "Distribution peaking between -1 and 1",
"#cos#theta_{BY}",
"Candidates"),
612 (
"d0_massDiff", 100, 0.0, 0.5,
"Mass difference of D* and D", email,
613 "Mass difference of $D^{*}$ and D",
"Peak at 0.14 GeV",
"m(D^{*})-m(D) [GeV]",
614 "Candidates",
"shifter"),
615 (
"d0_M", 100, 0.0, 3.0,
"Mass of zeroth daughter (D* or D)", email,
616 "Mass of zeroth daughter of tag B (either a $D^{*}$ or a D)",
"Peaks at 1.86 GeV and 2.00 GeV",
617 "m(D^{(*)}) [GeV]",
"Candidates",
"shifter")
621 (
"decayModeID", 8, 0, 8,
"log10_sigProb", 100, -3.0, 0.0,
622 "Signal probability for each decay mode ID", email,
623 "Signal probability for each decay mode ID",
624 "Some distribtuion of candidates in the first few decay mode IDs",
625 "Decay mode ID",
"#log_10(signal probability)",
"colz")
628 create_validation_histograms(
629 rootfile=histogramFilename,
630 particlelist=SkimList,
631 variables_1d=variables_1d,
632 variables_2d=variables_2d,
637 @_FEI_skim_header([
"B0",
"B+"])
640 Tag side :math:`B` cuts:
642 * :math:`M_{\\text{bc}} > 5.24~{\\rm GeV}`
643 * :math:`|\\Delta E| < 0.2~{\\rm GeV}`
644 * :math:`\\text{signal probability} > 0.001` (omitted for decay mode 23 for
645 :math:`B^+`, and decay mode 25 for :math:`B^0`)
647 All available FEI :math:`B^0` and :math:`B^+` hadronic tags are reconstructed. From
648 `Thomas Keck's thesis
649 <https://docs.belle2.org/record/275/files/BELLE2-MTHESIS-2015-001.pdf>`_, "the
650 channel :math:`B^0 \\to \\overline{D}^0 \\pi^0` was used by the FR, but is not yet
651 used in the FEI due to unexpected technical restrictions in the KFitter algorithm".
656 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
657 event-level cuts made before applying the FEI.
659 __description__ =
"FEI-tagged neutral and charged :math:`B`'s decaying hadronically."
665 "semileptonic":
False,
671 ma.copyList(
"B0:feiHadronic",
"B0:generic", path=path)
672 ma.copyList(
"B+:feiHadronic",
"B+:generic", path=path)
673 HadronicBLists = [
"B0:feiHadronic",
"B+:feiHadronic"]
675 for BList
in HadronicBLists:
676 ma.applyCuts(BList,
"Mbc>5.24", path=path)
677 ma.applyCuts(BList,
"abs(deltaE)<0.200", path=path)
679 ma.applyCuts(
"B+:feiHadronic",
"sigProb>0.001 or extraInfo(dmID)==25", path=path)
680 ma.applyCuts(
"B0:feiHadronic",
"sigProb>0.001 or extraInfo(dmID)==23", path=path)
685 @_FEI_skim_header([
"B0",
"B+"])
688 Tag side :math:`B` cuts:
690 * :math:`-4 < \\cos\\theta_{BY} < 3`
691 * :math:`\\log_{10}(\\text{signal probability}) > -2.4`
692 * :math:`p_{\\ell}^{*} > 1.0~{\\rm GeV}` in CMS frame
694 SL :math:`B^0` and :math:`B^+` tags are reconstructed. Hadronic :math:`B` with SL
695 :math:`D` are not reconstructed, as these are rare and time-intensive.
700 `BaseFEISkim.FEIPrefix` for FEI training used, and `BaseFEISkim.fei_precuts` for
701 event-level cuts made before applying the FEI.
703 __description__ =
"FEI-tagged neutral and charged :math:`B`'s decaying semileptonically."
709 "semileptonic":
True,
716 ma.copyList(
"B0:feiSL",
"B0:semileptonic", path=path)
717 ma.copyList(
"B+:feiSL",
"B+:semileptonic", path=path)
718 SLBLists = [
"B0:feiSL",
"B+:feiSL"]
720 Bcuts = [
"log10_sigProb>-2.4",
"-4.0<cosThetaBY<3.0",
"p_lepton_CMSframe>1.0"]
722 for BList
in SLBLists:
724 ma.applyCuts(BList, cut, path=path)