12 This module defines wrapper functions around the analysis modules.
16 from basf2
import register_module, create_path
17 from basf2
import B2INFO, B2WARNING, B2ERROR, B2FATAL
22 def setAnalysisConfigParams(configParametersAndValues, path):
24 Sets analysis configuration parameters.
28 - 'tupleStyle': 'Default' (default) or 'Laconic'
30 - defines the style of the branch name in the ntuple
32 - 'mcMatchingVersion': Specifies what version of mc matching algorithm is going to be used:
34 - 'Belle' - analysis of Belle MC
35 - 'BelleII' (default) - all other cases
37 @param configParametersAndValues dictionary of parameters and their values of the form {param1: value, param2: value, ...)
38 @param modules are added to this path
41 conf = register_module(
'AnalysisConfiguration')
43 allParameters = [
'tupleStyle',
'mcMatchingVersion']
45 keys = configParametersAndValues.keys()
47 if key
not in allParameters:
48 allParametersString =
', '.join(allParameters)
49 B2ERROR(
'Invalid analysis configuration parameter: ' + key +
'.\n'
50 'Please use one of the following: ' + allParametersString)
52 for param
in allParameters:
53 if param
in configParametersAndValues:
54 conf.param(param, configParametersAndValues.get(param))
59 def inputMdst(filename, path, environmentType='default', skipNEvents=0, entrySequence=None, *, parentLevel=0, **kwargs):
61 Loads the specified :ref:`mDST <mdst>` (or :ref:`uDST <analysis_udstoutput>`) file with the RootInput module.
63 The correct environment (e.g. magnetic field settings) is determined from
64 ``environmentType``. Options are either: 'default' (for Belle II MC and
65 data: falls back to database), 'Belle': for analysis of converted Belle 1
69 filename (str): the name of the file to be loaded
70 path (basf2.Path): modules are added to this path
71 environmentType (str): type of the environment to be loaded (either 'default' or 'Belle')
72 skipNEvents (int): N events of the input file are skipped
73 entrySequence (str): The number sequences (e.g. 23:42,101) defining the entries which are processed.
74 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
78 if filename ==
'default':
80 We have simplified the arguments to inputMdst! If you are running on Belle II
81 data or MC, you don't have to use "default" any more.
83 inputMdst("default", "/your/input/file.root", path=mypath)
85 inputMdst("/your/input/file.root", path=mypath)
87 elif filename ==
"Belle":
89 We have reordered the arguments to inputMdst! If you are running on Belle 1
90 data or MC, you need to specify the 'environmentType'.
92 inputMdst("Belle", "/your/input/file.root", path=mypath)
94 inputMdst("/your/input/file.root", path=mypath, environmentType='Belle')
96 elif filename
in [f
"MC{i}" for i
in range(5, 10)]:
97 B2FATAL(f
"We no longer support the MC version {filename}. Sorry.")
99 if entrySequence
is not None:
100 entrySequence = [entrySequence]
102 inputMdstList([filename], path, environmentType, skipNEvents, entrySequence, parentLevel=parentLevel, **kwargs)
108 environmentType='default',
113 useB2BIIDBCache=True):
115 Loads the specified list of :ref:`mDST <mdst>` (or :ref:`uDST <analysis_udstoutput>`) files with the RootInput module.
117 The correct environment (e.g. magnetic field settings) is determined from
118 ``environmentType``. Options are either: 'default' (for Belle II MC and
119 data: falls back to database), 'Belle': for analysis of converted Belle 1
123 filelist (list(str)): the filename list of files to be loaded
124 path (basf2.Path): modules are added to this path
125 environmentType (str): type of the environment to be loaded (either 'default' or 'Belle')
126 skipNEvents (int): N events of the input files are skipped
127 entrySequences (list(str)): The number sequences (e.g. 23:42,101) defining
128 the entries which are processed for each inputFileName.
129 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
130 useB2BIIDBCache (bool): Loading of local KEKCC database (only to be deactivated in very special cases)
134 if filelist ==
'default':
136 We have simplified the arguments to inputMdstList! If you are running on
137 Belle II data or MC, you don't have to use "default" any more.
139 inputMdstList("default", list_of_your_files, path=mypath)
141 inputMdstList(list_of_your_files, path=mypath)
143 elif filelist ==
"Belle":
145 We have reordered the arguments to inputMdstList! If you are running on
146 Belle 1 data or MC, you need to specify the 'environmentType'.
148 inputMdstList("Belle", list_of_your_files, path=mypath)
150 inputMdstList(list_of_your_files, path=mypath, environmentType='Belle')
152 elif filelist
in [f
"MC{i}" for i
in range(5, 10)]:
153 B2FATAL(f
"We no longer support the MC version {filelist}. Sorry.")
155 roinput = register_module(
'RootInput')
156 roinput.param(
'inputFileNames', filelist)
157 roinput.param(
'skipNEvents', skipNEvents)
158 if entrySequences
is not None:
159 roinput.param(
'entrySequences', entrySequences)
160 roinput.param(
'parentLevel', parentLevel)
162 path.add_module(roinput)
163 path.add_module(
'ProgressBar')
165 if environmentType ==
'Belle':
170 from ROOT
import Belle2
176 setAnalysisConfigParams({
'mcMatchingVersion':
'Belle'}, path)
179 basf2.conditions.metadata_providers = [
"/sw/belle/b2bii/database/conditions/b2bii.sqlite"]
180 basf2.conditions.payload_locations = [
"/sw/belle/b2bii/database/conditions/"]
183 def outputMdst(filename, path):
185 Saves mDST (mini-Data Summary Tables) to the output root file.
189 This function is kept for backward-compatibility.
190 Better to use `mdst.add_mdst_output` directly.
198 def outputUdst(filename, particleLists=None, includeArrays=None, path=None, dataDescription=None):
200 Save uDST (user-defined Data Summary Tables) = MDST + Particles + ParticleLists
201 The charge-conjugate lists of those given in particleLists are also stored.
202 Additional Store Arrays and Relations to be stored can be specified via includeArrays
206 This does not reduce the amount of Particle objects saved,
207 see `udst.add_skimmed_udst_output` for a function that does.
213 path=path, filename=filename, particleLists=particleLists,
214 additionalBranches=includeArrays, dataDescription=dataDescription)
217 def outputIndex(filename, path, includeArrays=None, keepParents=False, mc=True):
219 Write out all particle lists as an index file to be reprocessed using parentLevel flag.
220 Additional branches necessary for file to be read are automatically included.
221 Additional Store Arrays and Relations to be stored can be specified via includeArrays
224 @param str filename the name of the output index file
225 @param str path modules are added to this path
226 @param list(str) includeArrays: datastore arrays/objects to write to the output
227 file in addition to particle lists and related information
228 @param bool keepParents whether the parents of the input event will be saved as the parents of the same event
229 in the output index file. Useful if you are only adding more information to another index file
230 @param bool mc whether the input data is MC or not
233 if includeArrays
is None:
237 onlyPLists = register_module(
'OnlyWriteOutParticleLists')
238 path.add_module(onlyPLists)
243 'ParticlesToMCParticles',
244 'ParticlesToPIDLikelihoods',
245 'ParticleExtraInfoMap',
248 branches = [
'EventMetaData']
249 persistentBranches = [
'FileMetaData']
253 branches += partBranches
254 branches += includeArrays
256 r1 = register_module(
'RootOutput')
257 r1.param(
'outputFileName', filename)
258 r1.param(
'additionalBranchNames', branches)
259 r1.param(
'branchNamesPersistent', persistentBranches)
260 r1.param(
'keepParents', keepParents)
264 def setupEventInfo(noEvents, path):
266 Prepare to generate events. This function sets up the EventInfoSetter.
267 You should call this before adding a generator from generators.
268 The experiment and run numbers are set to 0 (run independent generic MC in phase 3).
269 https://confluence.desy.de/display/BI/Experiment+numbering
272 noEvents (int): number of events to be generated
273 path (basf2.Path): modules are added to this path
276 evtnumbers = register_module(
'EventInfoSetter')
277 evtnumbers.param(
'evtNumList', [noEvents])
278 evtnumbers.param(
'runList', [0])
279 evtnumbers.param(
'expList', [0])
280 path.add_module(evtnumbers)
283 def loadGearbox(path, silence_warning=False):
285 Loads Gearbox module to the path.
288 Should be used in a job with *cosmic event generation only*
290 Needed for scripts which only generate cosmic events in order to
293 @param path modules are added to this path
294 @param silence_warning stops a verbose warning message if you know you want to use this function
297 if not silence_warning:
298 B2WARNING(
"""You are overwriting the geometry from the database with Gearbox.
299 This is fine if you're generating cosmic events. But in most other cases you probably don't want this.
301 If you're really sure you know what you're doing you can suppress this message with:
303 >>> loadGearbox(silence_warning=True)
307 paramloader = register_module(
'Gearbox')
308 path.add_module(paramloader)
311 def printPrimaryMCParticles(path, **kwargs):
313 Prints all primary MCParticles, that is particles from
314 the physics generator and not particles created by the simulation
316 This is equivalent to `printMCParticles(onlyPrimaries=True, path=path) <printMCParticles>` and additional
317 keyword arguments are just forwarded to that function
320 return printMCParticles(onlyPrimaries=
True, path=path, **kwargs)
323 def printMCParticles(onlyPrimaries=False, maxLevel=-1, path=None, *,
324 showProperties=False, showMomenta=False, showVertices=False, showStatus=False, suppressPrint=False):
326 Prints all MCParticles or just primary MCParticles up to specified level. -1 means no limit.
328 By default this will print a tree of just the particle names and their pdg
329 codes in the event, for example ::
331 [INFO] Content of MCParticle list
332 ╰── Upsilon(4S) (300553)
334 │ ├── anti-D_0*0 (-10421)
335 │ │ ├── D- (-411)
336 │ │ │ ├── K*- (-323)
337 │ │ │ │ ├── anti-K0 (-311)
338 │ │ │ │ │ ╰── K_S0 (310)
339 │ │ │ │ │ ├── pi+ (211)
340 │ │ │ │ │ │ ╰╶╶ p+ (2212)
341 │ │ │ │ │ ╰── pi- (-211)
342 │ │ │ │ │ ├╶╶ e- (11)
343 │ │ │ │ │ ├╶╶ n0 (2112)
344 │ │ │ │ │ ├╶╶ n0 (2112)
345 │ │ │ │ │ ╰╶╶ n0 (2112)
346 │ │ │ │ ╰── pi- (-211)
347 │ │ │ │ ├╶╶ anti-nu_mu (-14)
348 │ │ │ │ ╰╶╶ mu- (13)
349 │ │ │ │ ├╶╶ nu_mu (14)
350 │ │ │ │ ├╶╶ anti-nu_e (-12)
351 │ │ │ │ ╰╶╶ e- (11)
352 │ │ │ ╰── K_S0 (310)
353 │ │ │ ├── pi0 (111)
354 │ │ │ │ ├── gamma (22)
355 │ │ │ │ ╰── gamma (22)
356 │ │ │ ╰── pi0 (111)
357 │ │ │ ├── gamma (22)
358 │ │ │ ╰── gamma (22)
359 │ │ ╰── pi+ (211)
360 │ ├── mu+ (-13)
361 │ │ ├╶╶ anti-nu_mu (-14)
362 │ │ ├╶╶ nu_e (12)
363 │ │ ╰╶╶ e+ (-11)
364 │ ├── nu_mu (14)
365 │ ╰── gamma (22)
369 There's a distinction between primary and secondary particles. Primary
370 particles are the ones created by the physics generator while secondary
371 particles are ones generated by the simulation of the detector interaction.
373 Secondaries are indicated with a dashed line leading to the particle name
374 and if the output is to the terminal they will be printed in red. If
375 ``onlyPrimaries`` is True they will not be included in the tree.
377 On demand, extra information on all the particles can be displayed by
378 enabling any of the ``showProperties``, ``showMomenta``, ``showVertices``
379 and ``showStatus`` flags. Enabling all of them will look like
384 │ mass=0.14 energy=0.445 charge=-1 lifetime=6.36
385 │ p=(0.257, -0.335, 0.0238) |p|=0.423
386 │ production vertex=(0.113, -0.0531, 0.0156), time=0.00589
387 │ status flags=PrimaryParticle, StableInGenerator, StoppedInDetector
391 mass=0.94 energy=0.94 charge=0 lifetime=5.28e+03
392 p=(-0.000238, -0.0127, 0.0116) |p|=0.0172
393 production vertex=(144, 21.9, -1.29), time=39
394 status flags=StoppedInDetector
395 creation process=HadronInelastic
398 The first line of extra information is enabled by ``showProperties``, the
399 second line by ``showMomenta``, the third line by ``showVertices`` and the
400 last two lines by ``showStatus``. Note that all values are given in Belle II
401 standard units, that is GeV, centimeter and nanoseconds.
403 The depth of the tree can be limited with the ``maxLevel`` argument: If it's
404 bigger than zero it will limit the tree to the given number of generations.
405 A visual indicator will be added after each particle which would have
406 additional daughters that are skipped due to this limit. An example event
407 with ``maxLevel=3`` is given below. In this case only the tau neutrino and
408 the pion don't have additional daughters. ::
410 [INFO] Content of MCParticle list
411 ╰── Upsilon(4S) (300553)
413 │ ├── anti-D*0 (-423) → …
414 │ ├── tau+ (-15) → …
415 │ ╰── nu_tau (16)
417 ├── D*0 (423) → …
418 ├── K*- (-323) → …
419 ├── K*+ (323) → …
422 The same information will be stored in the branch ``__MCDecayString__`` of
423 TTree created by `VariablesToNtuple` or `VariablesToEventBasedTree` module.
424 This branch is automatically created when `PrintMCParticles` modules is called.
425 Printing the information on the log message can be suppressed if ``suppressPrint``
426 is True, while the branch ``__MCDecayString__``. This option helps to reduce the
427 size of the log message.
430 onlyPrimaries (bool): If True show only primary particles, that is particles coming from
431 the generator and not created by the simulation.
432 maxLevel (int): If 0 or less print the whole tree, otherwise stop after n generations
433 showProperties (bool): If True show mass, energy and charge of the particles
434 showMomenta (bool): if True show the momenta of the particles
435 showVertices (bool): if True show production vertex and production time of all particles
436 showStatus (bool): if True show some status information on the particles.
437 For secondary particles this includes creation process.
438 suppressPrint (bool): if True printing the information on the log message is suppressed.
439 Even if True, the branch ``__MCDecayString__`` is created.
442 return path.add_module(
444 onlyPrimaries=onlyPrimaries,
446 showProperties=showProperties,
447 showMomenta=showMomenta,
448 showVertices=showVertices,
449 showStatus=showStatus,
450 suppressPrint=suppressPrint,
454 def correctBrems(outputList,
457 maximumAcceptance=3.0,
458 multiplePhotons=False,
459 usePhotonOnlyOnce=True,
463 For each particle in the given ``inputList``, copies it to the ``outputList`` and adds the
464 4-vector of the photon(s) in the ``gammaList`` which has(have) a weighted named relation to
465 the particle's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
468 This can only work if the mdst file contains the *Bremsstrahlung* named relation. Official MC samples
469 up to and including MC12 and proc9 **do not** contain this. Newer production campaigns (from proc10 and MC13) do.
470 However, studies by the tau WG revealed that the cuts applied by the ``ECLTrackBremFinder`` module are too tight.
471 These will be loosened but this will only have effect with proc13 and MC15.
472 If your analysis is very sensitive to the Bremsstrahlung corrections, it is advised to use `correctBremsBelle`.
475 A detailed description of how the weights are set can be found directly at the documentation of the
476 `BremsFinder` module.
478 Please note that a new particle is always generated, with the old particle and -if found- one or more
479 photons as daughters.
481 The ``inputList`` should contain particles with associated tracks. Otherwise, the module will exit with an error.
483 The ``gammaList`` should contain photons. Otherwise, the module will exit with an error.
485 @param outputList The output particle list name containing the corrected particles
486 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
487 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
488 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
489 @param multiplePhotons Whether to use only one photon (the one with the smallest acceptance) or as many as possible
490 @param usePhotonOnlyOnce If true, each brems candidate is used to correct only the track with the smallest relation weight
491 @param writeOut Whether `RootOutput` module should save the created ``outputList``
492 @param path The module is added to this path
497 B2ERROR(
"The BremsFinder can only be run over Belle II data.")
499 bremscorrector = register_module(
'BremsFinder')
500 bremscorrector.set_name(
'bremsCorrector_' + outputList)
501 bremscorrector.param(
'inputList', inputList)
502 bremscorrector.param(
'outputList', outputList)
503 bremscorrector.param(
'gammaList', gammaList)
504 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
505 bremscorrector.param(
'multiplePhotons', multiplePhotons)
506 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
507 bremscorrector.param(
'writeOut', writeOut)
508 path.add_module(bremscorrector)
511 def copyList(outputListName, inputListName, writeOut=False, path=None):
513 Copy all Particle indices from input ParticleList to the output ParticleList.
514 Note that the Particles themselves are not copied. The original and copied
515 ParticleLists will point to the same Particles.
517 @param ouputListName copied ParticleList
518 @param inputListName original ParticleList to be copied
519 @param writeOut whether RootOutput module should save the created ParticleList
520 @param path modules are added to this path
523 copyLists(outputListName, [inputListName], writeOut, path)
526 def correctBremsBelle(outputListName,
529 multiplePhotons=True,
531 usePhotonOnlyOnce=False,
535 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
536 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
540 Studies by the tau WG show that using a rather wide opening angle (up to
541 0.2 rad) and rather low energetic photons results in good correction.
542 However, this should only serve as a starting point for your own studies
543 because the optimal criteria are likely mode-dependent
546 outputListName (str): The output charged particle list containing the corrected charged particles
547 inputListName (str): The initial charged particle list containing the charged particles to correct.
548 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
549 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one -> False,
550 add all the photons within the cone -> True
551 angleThreshold (float): The maximum angle in radians between the charged particle and the (radiative)
552 gamma to be accepted.
553 writeOut (bool): whether RootOutput module should save the created ParticleList
554 usePhotonOnlyOnce (bool): If true, a photon is used for correction of the closest charged particle in the inputList.
555 If false, a photon is allowed to be used for correction multiple times (Default).
558 One cannot use a photon twice to reconstruct a composite particle. Thus, for example, if ``e+`` and ``e-`` are corrected
559 with a ``gamma``, the pair of ``e+`` and ``e-`` cannot form a ``J/psi -> e+ e-`` candidate.
561 path (basf2.Path): modules are added to this path
564 fsrcorrector = register_module(
'BelleBremRecovery')
565 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
566 fsrcorrector.param(
'inputListName', inputListName)
567 fsrcorrector.param(
'outputListName', outputListName)
568 fsrcorrector.param(
'gammaListName', gammaListName)
569 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
570 fsrcorrector.param(
'angleThreshold', angleThreshold)
571 fsrcorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
572 fsrcorrector.param(
'writeOut', writeOut)
573 path.add_module(fsrcorrector)
576 def copyLists(outputListName, inputListNames, writeOut=False, path=None):
578 Copy all Particle indices from all input ParticleLists to the
579 single output ParticleList.
580 Note that the Particles themselves are not copied.
581 The original and copied ParticleLists will point to the same Particles.
583 Duplicates are removed based on the first-come, first-served principle.
584 Therefore, the order of the input ParticleLists matters.
587 If you want to select the best duplicate based on another criterion, have
588 a look at the function `mergeListsWithBestDuplicate`.
591 Two particles that differ only by the order of their daughters are
592 considered duplicates and one of them will be removed.
594 @param ouputListName copied ParticleList
595 @param inputListName vector of original ParticleLists to be copied
596 @param writeOut whether RootOutput module should save the created ParticleList
597 @param path modules are added to this path
600 pmanipulate = register_module(
'ParticleListManipulator')
601 pmanipulate.set_name(
'PListCopy_' + outputListName)
602 pmanipulate.param(
'outputListName', outputListName)
603 pmanipulate.param(
'inputListNames', inputListNames)
604 pmanipulate.param(
'writeOut', writeOut)
605 path.add_module(pmanipulate)
608 def copyParticles(outputListName, inputListName, writeOut=False, path=None):
610 Create copies of Particles given in the input ParticleList and add them to the output ParticleList.
612 The existing relations of the original Particle (or it's (grand-)^n-daughters)
613 are copied as well. Note that only the relation is copied and that the related
614 object is not. Copied particles are therefore related to the *same* object as
617 @param ouputListName new ParticleList filled with copied Particles
618 @param inputListName input ParticleList with original Particles
619 @param writeOut whether RootOutput module should save the created ParticleList
620 @param path modules are added to this path
624 pmanipulate = register_module(
'ParticleListManipulator')
625 pmanipulate.set_name(
'PListCopy_' + outputListName)
626 pmanipulate.param(
'outputListName', outputListName)
627 pmanipulate.param(
'inputListNames', [inputListName])
628 pmanipulate.param(
'writeOut', writeOut)
629 path.add_module(pmanipulate)
632 pcopy = register_module(
'ParticleCopier')
633 pcopy.param(
'inputListNames', [outputListName])
634 path.add_module(pcopy)
637 def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
639 Copy candidates from all lists in ``inputListNames`` to
640 ``outputListName`` if they pass ``cut`` (given selection criteria).
643 Note that the Particles themselves are not copied.
644 The original and copied ParticleLists will point to the same Particles.
647 Require energetic pions safely inside the cdc
649 .. code-block:: python
651 cutAndCopyLists("pi+:energeticPions", ["pi+:good", "pi+:loose"], "[E > 2] and thetaInCDCAcceptance", path=mypath)
654 You must use square braces ``[`` and ``]`` for conditional statements.
657 outputListName (str): the new ParticleList name
658 inputListName (list(str)): list of input ParticleList names
659 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
660 writeOut (bool): whether RootOutput module should save the created ParticleList
661 path (basf2.Path): modules are added to this path
664 pmanipulate = register_module(
'ParticleListManipulator')
665 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
666 pmanipulate.param(
'outputListName', outputListName)
667 pmanipulate.param(
'inputListNames', inputListNames)
668 pmanipulate.param(
'cut', cut)
669 pmanipulate.param(
'writeOut', writeOut)
670 path.add_module(pmanipulate)
673 def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
675 Copy candidates from ``inputListName`` to ``outputListName`` if they pass
676 ``cut`` (given selection criteria).
679 Note the Particles themselves are not copied.
680 The original and copied ParticleLists will point to the same Particles.
683 require energetic pions safely inside the cdc
685 .. code-block:: python
687 cutAndCopyList("pi+:energeticPions", "pi+:loose", "[E > 2] and thetaInCDCAcceptance", path=mypath)
690 You must use square braces ``[`` and ``]`` for conditional statements.
693 outputListName (str): the new ParticleList name
694 inputListName (str): input ParticleList name
695 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
696 writeOut (bool): whether RootOutput module should save the created ParticleList
697 path (basf2.Path): modules are added to this path
700 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
703 def removeTracksForTrackingEfficiencyCalculation(inputListNames, fraction, path=None):
705 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
706 Takes care of the duplicates, if any.
709 inputListNames (list(str)): input particle list names
710 fraction (float): fraction of particles to be removed randomly
711 path (basf2.Path): module is added to this path
714 trackingefficiency = register_module(
'TrackingEfficiency')
715 trackingefficiency.param(
'particleLists', inputListNames)
716 trackingefficiency.param(
'frac', fraction)
717 path.add_module(trackingefficiency)
720 def scaleTrackMomenta(inputListNames, scale=float(
'nan'), payloadName=
"", scalingFactorName=
"SF", path=
None):
722 Scale momenta of the particles according to a scaling factor scale.
723 This scaling factor can either be given as constant number or as the name of the payload which contains
724 the variable scale factors.
725 If the particle list contains composite particles, the momenta of the track-based daughters are scaled.
726 Subsequently, the momentum of the mother particle is updated as well.
729 inputListNames (list(str)): input particle list names
730 scale (float): scaling factor (1.0 -- no scaling)
731 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
732 scalingFactorName (str): name of scaling factor variable in the payload.
733 path (basf2.Path): module is added to this path
738 B2ERROR(
"The tracking momentum scaler can only be run over Belle II data.")
740 trackingmomentum = register_module(
'TrackingMomentum')
741 trackingmomentum.param(
'particleLists', inputListNames)
742 trackingmomentum.param(
'scale', scale)
743 trackingmomentum.param(
'payloadName', payloadName)
744 trackingmomentum.param(
'scalingFactorName', scalingFactorName)
746 path.add_module(trackingmomentum)
749 def smearTrackMomenta(inputListNames, payloadName="", smearingFactorName="smear", path=None):
751 Smear the momenta of the particles according the values read from the given payload.
752 If the particle list contains composite particles, the momenta of the track-based daughters are smeared.
753 Subsequently, the momentum of the mother particle is updated as well.
756 inputListNames (list(str)): input particle list names
757 payloadName (str): name of the payload which contains the smearing valuess
758 smearingFactorName (str): name of smearing factor variable in the payload.
759 path (basf2.Path): module is added to this path
762 trackingmomentum = register_module(
'TrackingMomentum')
763 trackingmomentum.param(
'particleLists', inputListNames)
764 trackingmomentum.param(
'payloadName', payloadName)
765 trackingmomentum.param(
'smearingFactorName', smearingFactorName)
767 path.add_module(trackingmomentum)
770 def mergeListsWithBestDuplicate(outputListName,
775 ignoreMotherFlavor=False,
778 Merge input ParticleLists into one output ParticleList. Only the best
779 among duplicates is kept. The lowest or highest value (configurable via
780 preferLowest) of the provided variable determines which duplicate is the
783 @param ouputListName name of merged ParticleList
784 @param inputListName vector of original ParticleLists to be merged
785 @param variable variable to determine best duplicate
786 @param preferLowest whether lowest or highest value of variable should be preferred
787 @param writeOut whether RootOutput module should save the created ParticleList
788 @param ignoreMotherFlavor whether the flavor of the mother particle is ignored when trying to find duplicates
789 @param path modules are added to this path
792 pmanipulate = register_module(
'ParticleListManipulator')
793 pmanipulate.set_name(
'PListMerger_' + outputListName)
794 pmanipulate.param(
'outputListName', outputListName)
795 pmanipulate.param(
'inputListNames', inputListNames)
796 pmanipulate.param(
'variable', variable)
797 pmanipulate.param(
'preferLowest', preferLowest)
798 pmanipulate.param(
'writeOut', writeOut)
799 pmanipulate.param(
'ignoreMotherFlavor', ignoreMotherFlavor)
800 path.add_module(pmanipulate)
803 def fillSignalSideParticleList(outputListName, decayString, path):
805 This function should only be used in the ROE path, that is a path
806 that is executed for each ROE object in the DataStore.
808 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
810 Function will create a ParticleList with name 'gamma:sig' which will be filled
811 with the existing photon Particle, being the second daughter of the B0 candidate
812 to which the ROE object has to be related.
814 @param ouputListName name of the created ParticleList
815 @param decayString specify Particle to be added to the ParticleList
818 pload = register_module(
'SignalSideParticleListCreator')
819 pload.set_name(
'SSParticleList_' + outputListName)
820 pload.param(
'particleListName', outputListName)
821 pload.param(
'decayString', decayString)
822 path.add_module(pload)
825 def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False,
826 loadPhotonsFromKLM=False):
828 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
829 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
831 The multiple ParticleLists with their own selection criteria are specified
832 via list tuples (decayString, cut), for example
834 .. code-block:: python
836 kaons = ('K+:mykaons', 'kaonID>0.1')
837 pions = ('pi+:mypions','pionID>0.1')
838 fillParticleLists([kaons, pions], path=mypath)
840 If you are unsure what selection you want, you might like to see the
841 :doc:`StandardParticles` functions.
843 The type of the particles to be loaded is specified via the decayString module parameter.
844 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
845 the particle. The following types of the particles can be loaded:
847 * charged final state particles (input ``mdst`` type = Tracks)
848 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
850 * neutral final state particles
851 - "gamma" (input ``mdst`` type = ECLCluster)
852 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
853 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
856 For "K_S0" and "Lambda0" you must specify the daughter ordering.
858 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
860 .. code-block:: python
862 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
863 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
866 Gammas can also be loaded from KLMClusters by explicitly setting the
867 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
868 done in selected use-cases and the effect should be studied carefully.
871 For "K_L0" it is now possible to load from ECLClusters, to revert to
872 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
874 .. code-block:: python
876 klongs = ('K_L0', 'isFromKLM > 0')
877 fillParticleLists([kaons, pions, klongs], path=mypath)
881 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
882 The decay string determines the type of Particle
883 and the name of the ParticleList.
884 If the input MDST type is V0 the whole
885 decay chain needs to be specified, so that
886 the user decides and controls the daughters
887 ' order (e.g. ``K_S0 -> pi+ pi-``)
888 The cut is the selection criteria
889 to be added to the ParticleList. It can be an empty string.
890 writeOut (bool): whether RootOutput module should save the created ParticleList
891 path (basf2.Path): modules are added to this path
892 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
893 using a mass hypothesis of the exact type passed to fillParticleLists().
894 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
895 in terms of mass difference will be used if the fit using exact particle
896 type is not available.
897 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
900 pload = register_module(
'ParticleLoader')
901 pload.set_name(
'ParticleLoader_' +
'PLists')
902 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
903 pload.param(
'writeOut', writeOut)
904 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
905 path.add_module(pload)
907 from ROOT
import Belle2
909 for decayString, cut
in decayStringsWithCuts:
910 if not decayDescriptor.init(decayString):
911 raise ValueError(
"Invalid decay string")
913 if decayDescriptor.getNDaughters() > 0:
917 if decayDescriptor.getMother().getLabel() !=
'V0':
918 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
919 elif decayDescriptor.getMother().getLabel() !=
'all':
922 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
926 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
928 if decayString.startswith(
"gamma"):
931 if not loadPhotonsFromKLM:
932 applyCuts(decayString,
'isFromECL', path)
935 def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False,
936 loadPhotonsFromKLM=False):
938 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
939 loads them to the StoreArray<Particle> and fills the ParticleList.
942 the :doc:`StandardParticles` functions.
944 The type of the particles to be loaded is specified via the decayString module parameter.
945 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
946 the particle. The following types of the particles can be loaded:
948 * charged final state particles (input ``mdst`` type = Tracks)
949 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
951 * neutral final state particles
952 - "gamma" (input ``mdst`` type = ECLCluster)
953 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
954 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
957 For "K_S0" and "Lambda0" you must specify the daughter ordering.
959 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
961 .. code-block:: python
963 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
966 Gammas can also be loaded from KLMClusters by explicitly setting the
967 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
968 done in selected use-cases and the effect should be studied carefully.
971 For "K_L0" it is now possible to load from ECLClusters, to revert to
972 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
974 .. code-block:: python
976 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
979 decayString (str): Type of Particle and determines the name of the ParticleList.
980 If the input MDST type is V0 the whole decay chain needs to be specified, so that
981 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``)
982 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
983 writeOut (bool): whether RootOutput module should save the created ParticleList
984 path (basf2.Path): modules are added to this path
985 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
986 using a mass hypothesis of the exact type passed to fillParticleLists().
987 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
988 in terms of mass difference will be used if the fit using exact particle
989 type is not available.
990 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
993 pload = register_module(
'ParticleLoader')
994 pload.set_name(
'ParticleLoader_' + decayString)
995 pload.param(
'decayStrings', [decayString])
996 pload.param(
'writeOut', writeOut)
997 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
998 path.add_module(pload)
1001 from ROOT
import Belle2
1003 if not decayDescriptor.init(decayString):
1004 raise ValueError(
"Invalid decay string")
1005 if decayDescriptor.getNDaughters() > 0:
1009 if decayDescriptor.getMother().getLabel() !=
'V0':
1010 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1011 elif decayDescriptor.getMother().getLabel() !=
'all':
1014 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1018 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1020 if decayString.startswith(
"gamma"):
1023 if not loadPhotonsFromKLM:
1024 applyCuts(decayString,
'isFromECL', path)
1027 def fillParticleListWithTrackHypothesis(decayString,
1031 enforceFitHypothesis=False,
1034 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
1036 @param decayString specifies type of Particles and determines the name of the ParticleList
1037 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1038 @param hypothesis the PDG code of the desired track hypothesis
1039 @param writeOut whether RootOutput module should save the created ParticleList
1040 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
1041 using a mass hypothesis of the exact type passed to fillParticleLists().
1042 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1043 in terms of mass difference will be used if the fit using exact particle
1044 type is not available.
1045 @param path modules are added to this path
1048 pload = register_module(
'ParticleLoader')
1049 pload.set_name(
'ParticleLoader_' + decayString)
1050 pload.param(
'decayStrings', [decayString])
1051 pload.param(
'trackHypothesis', hypothesis)
1052 pload.param(
'writeOut', writeOut)
1053 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1054 path.add_module(pload)
1056 from ROOT
import Belle2
1058 if not decayDescriptor.init(decayString):
1059 raise ValueError(
"Invalid decay string")
1060 if decayDescriptor.getMother().getLabel() !=
'all':
1063 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1067 applyCuts(decayString, cut, path)
1070 def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
1072 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
1075 You must specify the daughter ordering.
1077 .. code-block:: python
1079 fillConvertedPhotonsList('gamma:converted -> e+ e-', '', path=mypath)
1082 decayString (str): Must be gamma to an e+e- pair. You must specify the daughter ordering.
1083 Will also determine the name of the particleList.
1084 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1085 writeOut (bool): whether RootOutput module should save the created ParticleList
1086 path (basf2.Path): modules are added to this path
1092 B2ERROR(
'For Belle converted photons are available in the pre-defined list "gamma:v0mdst".')
1094 pload = register_module(
'ParticleLoader')
1095 pload.set_name(
'ParticleLoader_' + decayString)
1096 pload.param(
'decayStrings', [decayString])
1097 pload.param(
'addDaughters',
True)
1098 pload.param(
'writeOut', writeOut)
1099 path.add_module(pload)
1101 from ROOT
import Belle2
1103 if not decayDescriptor.init(decayString):
1104 raise ValueError(
"Invalid decay string")
1105 if decayDescriptor.getMother().getLabel() !=
'V0':
1108 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1112 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1115 def fillParticleListFromROE(decayString,
1118 sourceParticleListName='',
1123 Creates Particle object for each ROE of the desired type found in the
1124 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
1125 and fills the ParticleList. If useMissing is True, then the missing
1126 momentum is used instead of ROE.
1128 The type of the particles to be loaded is specified via the decayString module parameter.
1130 @param decayString specifies type of Particles and determines the name of the ParticleList.
1131 Source ROEs can be taken as a daughter list, for example:
1132 'B0:tagFromROE -> B0:signal'
1133 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1134 @param maskName Name of the ROE mask to use
1135 @param sourceParticleListName Use related ROEs to this particle list as a source
1136 @param useMissing Use missing momentum instead of ROE momentum
1137 @param writeOut whether RootOutput module should save the created ParticleList
1138 @param path modules are added to this path
1141 pload = register_module(
'ParticleLoader')
1142 pload.set_name(
'ParticleLoader_' + decayString)
1143 pload.param(
'decayStrings', [decayString])
1144 pload.param(
'writeOut', writeOut)
1145 pload.param(
'roeMaskName', maskName)
1146 pload.param(
'useMissing', useMissing)
1147 pload.param(
'sourceParticleListName', sourceParticleListName)
1148 pload.param(
'useROEs',
True)
1149 path.add_module(pload)
1151 from ROOT
import Belle2
1153 if not decayDescriptor.init(decayString):
1154 raise ValueError(
"Invalid decay string")
1158 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1161 def fillParticleListFromDummy(decayString,
1164 treatAsInvisible=True,
1168 Creates a ParticleList and fills it with dummy Particles. For self-conjugated Particles one dummy
1169 Particle is created, for Particles that are not self-conjugated one Particle and one anti-Particle is
1170 created. The four-momentum is set to zero.
1172 The type of the particles to be loaded is specified via the decayString module parameter.
1174 @param decayString specifies type of Particles and determines the name of the ParticleList
1175 @param mdstIndex sets the mdst index of Particles
1176 @param covMatrix sets the value of the diagonal covariance matrix of Particles
1177 @param treatAsInvisible whether treeFitter should treat the Particles as invisible
1178 @param writeOut whether RootOutput module should save the created ParticleList
1179 @param path modules are added to this path
1182 pload = register_module(
'ParticleLoader')
1183 pload.set_name(
'ParticleLoader_' + decayString)
1184 pload.param(
'decayStrings', [decayString])
1185 pload.param(
'useDummy',
True)
1186 pload.param(
'dummyMDSTIndex', mdstIndex)
1187 pload.param(
'dummyCovMatrix', covMatrix)
1188 pload.param(
'dummyTreatAsInvisible', treatAsInvisible)
1189 pload.param(
'writeOut', writeOut)
1190 path.add_module(pload)
1193 def fillParticleListFromMC(decayString,
1196 skipNonPrimaryDaughters=False,
1199 skipNonPrimary=False):
1201 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1202 loads them to the StoreArray<Particle> and fills the ParticleList.
1204 The type of the particles to be loaded is specified via the decayString module parameter.
1206 @param decayString specifies type of Particles and determines the name of the ParticleList
1207 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1208 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1209 sets mother-daughter relations
1210 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1211 @param writeOut whether RootOutput module should save the created ParticleList
1212 @param path modules are added to this path
1213 @param skipNonPrimary if true, skip non primary particle
1216 pload = register_module(
'ParticleLoader')
1217 pload.set_name(
'ParticleLoader_' + decayString)
1218 pload.param(
'decayStrings', [decayString])
1219 pload.param(
'addDaughters', addDaughters)
1220 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1221 pload.param(
'writeOut', writeOut)
1222 pload.param(
'useMCParticles',
True)
1223 pload.param(
'skipNonPrimary', skipNonPrimary)
1224 path.add_module(pload)
1226 from ROOT
import Belle2
1228 if not decayDescriptor.init(decayString):
1229 raise ValueError(
"Invalid decay string")
1233 applyCuts(decayString, cut, path)
1236 def fillParticleListsFromMC(decayStringsWithCuts,
1238 skipNonPrimaryDaughters=False,
1241 skipNonPrimary=False):
1243 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1244 loads them to the StoreArray<Particle> and fills the ParticleLists.
1246 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
1249 .. code-block:: python
1251 kaons = ('K+:gen', '')
1252 pions = ('pi+:gen', 'pionID>0.1')
1253 fillParticleListsFromMC([kaons, pions], path=mypath)
1256 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not final state particle.
1257 Thus, when one reconstructs a particle from ``Lambda0``, that is created with
1258 ``addDaughters=True`` and ``skipNonPrimaryDaughters=True``, the particle always has ``isSignal==0``.
1259 Please set options for ``Lambda0`` to use MC-matching variables properly as follows,
1260 ``addDaughters=True`` and ``skipNonPrimaryDaughters=False``.
1262 @param decayString specifies type of Particles and determines the name of the ParticleList
1263 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1264 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1265 sets mother-daughter relations
1266 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1267 @param writeOut whether RootOutput module should save the created ParticleList
1268 @param path modules are added to this path
1269 @param skipNonPrimary if true, skip non primary particle
1272 pload = register_module(
'ParticleLoader')
1273 pload.set_name(
'ParticleLoader_' +
'PLists')
1274 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
1275 pload.param(
'addDaughters', addDaughters)
1276 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1277 pload.param(
'writeOut', writeOut)
1278 pload.param(
'useMCParticles',
True)
1279 pload.param(
'skipNonPrimary', skipNonPrimary)
1280 path.add_module(pload)
1282 from ROOT
import Belle2
1284 for decayString, cut
in decayStringsWithCuts:
1285 if not decayDescriptor.init(decayString):
1286 raise ValueError(
"Invalid decay string")
1290 applyCuts(decayString, cut, path)
1293 def fillParticleListFromChargedCluster(outputParticleList,
1296 useOnlyMostEnergeticECLCluster=True,
1300 Creates the Particle object from ECLCluster and KLMCluster that are being matched with the Track of inputParticleList.
1302 @param outputParticleList The output ParticleList. Only neutral final state particles are supported.
1303 @param inputParticleList The input ParticleList that is required to have the relation to the Track object.
1304 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1305 @param useOnlyMostEnergeticECLCluster If True, only the most energetic ECLCluster among ones that are matched with the Track is
1306 used. If False, all matched ECLClusters are loaded. The default is True. Regardless of
1307 this option, the KLMCluster is loaded.
1308 @param writeOut whether RootOutput module should save the created ParticleList
1309 @param path modules are added to this path
1312 pload = register_module(
'ParticleLoader')
1313 pload.set_name(
'ParticleLoader_' + outputParticleList)
1315 pload.param(
'decayStrings', [outputParticleList])
1316 pload.param(
'sourceParticleListName', inputParticleList)
1317 pload.param(
'writeOut', writeOut)
1318 pload.param(
'loadChargedCluster',
True)
1319 pload.param(
'useOnlyMostEnergeticECLCluster', useOnlyMostEnergeticECLCluster)
1320 path.add_module(pload)
1324 applyCuts(outputParticleList, cut, path)
1327 def extractParticlesFromROE(particleLists,
1328 signalSideParticleList=None,
1333 Extract Particle objects that belong to the Rest-Of-Events and fill them into the ParticleLists.
1334 The types of the particles other than those specified by ``particleLists`` are not stored.
1335 If one creates a ROE with ``fillWithMostLikely=True`` via `buildRestOfEvent`, for example,
1336 one should create particleLists for not only ``pi+``, ``gamma``, ``K_L0`` but also other charged final state particles.
1338 When one calls the function in the main path, one has to set the argument ``signalSideParticleList`` and the signal side
1339 ParticleList must have only one candidate.
1341 .. code-block:: python
1343 buildRestOfEvent('B0:sig', fillWithMostLikely=True, path=mypath)
1345 roe_path = create_path()
1346 deadEndPath = create_path()
1347 signalSideParticleFilter('B0:sig', '', roe_path, deadEndPath)
1349 plists = ['%s:in_roe' % ptype for ptype in ['pi+', 'gamma', 'K_L0', 'K+', 'p+', 'e+', 'mu+']]
1350 extractParticlesFromROE(plists, maskName='all', path=roe_path)
1352 # one can analyze these ParticleLists in the roe_path
1354 mypath.for_each('RestOfEvent', 'RestOfEvents', roe_path)
1356 rankByLowest('B0:sig', 'deltaE', numBest=1, path=mypath)
1357 extractParticlesFromROE(plists, signalSideParticleList='B0:sig', maskName='all', path=mypath)
1359 # one can analyze these ParticleLists in the main path
1362 @param particleLists (str or list(str)) Name of output ParticleLists
1363 @param signalSideParticleList (str) Name of signal side ParticleList
1364 @param maskName (str) Name of the ROE mask to be applied on Particles
1365 @param writeOut (bool) whether RootOutput module should save the created ParticleList
1366 @param path (basf2.Path) modules are added to this path
1369 if isinstance(particleLists, str):
1370 particleLists = [particleLists]
1372 pext = register_module(
'ParticleExtractorFromROE')
1373 pext.set_name(
'ParticleExtractorFromROE_' +
'_'.join(particleLists))
1374 pext.param(
'outputListNames', particleLists)
1375 if signalSideParticleList
is not None:
1376 pext.param(
'signalSideParticleListName', signalSideParticleList)
1377 pext.param(
'maskName', maskName)
1378 pext.param(
'writeOut', writeOut)
1379 path.add_module(pext)
1382 def applyCuts(list_name, cut, path):
1384 Removes particle candidates from ``list_name`` that do not pass ``cut``
1385 (given selection criteria).
1388 require energetic pions safely inside the cdc
1390 .. code-block:: python
1392 applyCuts("pi+:mypions", "[E > 2] and thetaInCDCAcceptance", path=mypath)
1395 You must use square braces ``[`` and ``]`` for conditional statements.
1398 list_name (str): input ParticleList name
1399 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
1400 path (basf2.Path): modules are added to this path
1403 pselect = register_module(
'ParticleSelector')
1404 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
1405 pselect.param(
'decayString', list_name)
1406 pselect.param(
'cut', cut)
1407 path.add_module(pselect)
1410 def applyEventCuts(cut, path, metavariables=None):
1412 Removes events that do not pass the ``cut`` (given selection criteria).
1415 continuum events (in mc only) with more than 5 tracks
1417 .. code-block:: python
1419 applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1422 Only event-based variables are allowed in this function
1423 and only square brackets ``[`` and ``]`` for conditional statements.
1426 cut (str): Events that do not pass these selection criteria are skipped
1427 path (basf2.Path): modules are added to this path
1428 metavariables (list(str)): List of meta variables to be considered in decomposition of cut
1432 from variables
import variables
1434 def find_vars(t: tuple, var_list: list, meta_list: list) ->
None:
1435 """ Recursive helper function to find variable names """
1436 if not isinstance(t, tuple):
1438 if t[0] == b2parser.B2ExpressionParser.node_types[
'IdentifierNode']:
1441 if t[0] == b2parser.B2ExpressionParser.node_types[
'FunctionNode']:
1442 meta_list.append(list(t[1:]))
1445 if isinstance(i, tuple):
1446 find_vars(i, var_list, meta_list)
1448 def check_variable(var_list: list, metavar_ids: list) ->
None:
1449 for var_string
in var_list:
1451 orig_name = variables.resolveAlias(var_string)
1452 if orig_name != var_string:
1455 find_vars(
b2parser.parse(orig_name), var_list_temp, meta_list_temp)
1457 check_variable(var_list_temp, metavar_ids)
1458 check_meta(meta_list_temp, metavar_ids)
1461 var = variables.getVariable(var_string)
1462 if event_var_id
not in var.description:
1463 B2ERROR(f
'Variable {var_string} is not an event-based variable! "\
1464 "Please check your inputs to the applyEventCuts method!')
1466 def check_meta(meta_list: list, metavar_ids: list) ->
None:
1467 for meta_string_list
in meta_list:
1469 while meta_string_list[0]
in metavar_ids:
1471 meta_string_list.pop(0)
1472 for meta_string
in meta_string_list[0].split(
","):
1473 find_vars(
b2parser.parse(meta_string), var_list_temp, meta_string_list)
1474 if len(meta_string_list) > 0:
1475 meta_string_list.pop(0)
1476 if len(meta_string_list) == 0:
1478 if len(meta_string_list) > 1:
1479 meta_list += meta_string_list[1:]
1480 if isinstance(meta_string_list[0], list):
1481 meta_string_list = [element
for element
in meta_string_list[0]]
1483 check_variable(var_list_temp, metavar_ids)
1485 if len(meta_string_list) == 0:
1487 elif len(meta_string_list) == 1:
1488 var = variables.getVariable(meta_string_list[0])
1490 var = variables.getVariable(meta_string_list[0], meta_string_list[1].split(
","))
1492 if event_var_id
in var.description:
1495 B2ERROR(f
'Variable {var.name} is not an event-based variable! Please check your inputs to the applyEventCuts method!')
1497 event_var_id =
'[Eventbased]'
1498 metavar_ids = [
'formula',
'abs',
1502 'exp',
'log',
'log10',
1506 metavar_ids += metavariables
1510 find_vars(
b2parser.parse(cut), var_list=var_list, meta_list=meta_list)
1512 if len(var_list) == 0
and len(meta_list) == 0:
1513 B2WARNING(f
'Cut string "{cut}" has no variables for applyEventCuts helper function!')
1515 check_variable(var_list, metavar_ids)
1516 check_meta(meta_list, metavar_ids)
1518 eselect = register_module(
'VariableToReturnValue')
1519 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1520 path.add_module(eselect)
1521 empty_path = create_path()
1522 eselect.if_value(
'<1', empty_path)
1525 def reconstructDecay(decayString,
1530 candidate_limit=None,
1531 ignoreIfTooManyCandidates=True,
1532 chargeConjugation=True,
1533 allowChargeViolation=False):
1535 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1536 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1537 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1538 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1539 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1541 One can use an ``@``-sign to mark a particle as unspecified for inclusive analyses,
1542 e.g. in a DecayString: :code:`'@Xsd -> K+ pi-'`.
1544 .. seealso:: :ref:`Marker_of_unspecified_particle`
1547 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1548 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1549 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1551 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1552 This can be solved by manually randomising the lists before combining.
1556 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1557 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1559 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1560 (from the DecayString the mother and daughter ParticleLists are determined)
1561 @param cut created (mother) Particles are added to the mother ParticleList if they
1562 pass give cuts (in VariableManager style) and rejected otherwise
1563 @param dmID user specified decay mode identifier
1564 @param writeOut whether RootOutput module should save the created ParticleList
1565 @param path modules are added to this path
1566 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1567 the number of candidates is exceeded a Warning will be
1569 By default, all these candidates will be removed and event will be ignored.
1570 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1571 If no value is given the amount is limited to a sensible
1572 default. A value <=0 will disable this limit and can
1573 cause huge memory amounts so be careful.
1574 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1575 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1576 otherwise, number of candidates in candidate_limit is reconstructed.
1577 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1578 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1581 pmake = register_module(
'ParticleCombiner')
1582 pmake.set_name(
'ParticleCombiner_' + decayString)
1583 pmake.param(
'decayString', decayString)
1584 pmake.param(
'cut', cut)
1585 pmake.param(
'decayMode', dmID)
1586 pmake.param(
'writeOut', writeOut)
1587 if candidate_limit
is not None:
1588 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1589 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1590 pmake.param(
'chargeConjugation', chargeConjugation)
1591 pmake.param(
"allowChargeViolation", allowChargeViolation)
1592 path.add_module(pmake)
1595 def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1597 Creates a new Particle as the combination of all Particles from all
1598 provided inputParticleLists. However, each particle is used only once
1599 (even if duplicates are provided) and the combination has to pass the
1600 specified selection criteria to be saved in the newly created (mother)
1603 @param inputParticleLists List of input particle lists which are combined to the new Particle
1604 @param outputList Name of the particle combination created with this module
1605 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1606 these given cuts (in VariableManager style) and is rejected otherwise
1607 @param writeOut whether RootOutput module should save the created ParticleList
1608 @param path module is added to this path
1611 pmake = register_module(
'AllParticleCombiner')
1612 pmake.set_name(
'AllParticleCombiner_' + outputList)
1613 pmake.param(
'inputListNames', inputParticleLists)
1614 pmake.param(
'outputListName', outputList)
1615 pmake.param(
'cut', cut)
1616 pmake.param(
'writeOut', writeOut)
1617 path.add_module(pmake)
1620 def reconstructMissingKlongDecayExpert(decayString,
1627 Creates a list of K_L0's with their momentum determined from kinematic constraints of B->K_L0 + something else.
1629 @param decayString DecayString specifying what kind of the decay should be reconstructed
1630 (from the DecayString the mother and daughter ParticleLists are determined)
1631 @param cut Particles are added to the K_L0 ParticleList if they
1632 pass the given cuts (in VariableManager style) and rejected otherwise
1633 @param dmID user specified decay mode identifier
1634 @param writeOut whether RootOutput module should save the created ParticleList
1635 @param path modules are added to this path
1636 @param recoList suffix appended to original K_L0 ParticleList that identifies the newly created K_L0 list
1639 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1640 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1641 pcalc.param(
'decayString', decayString)
1642 pcalc.param(
'cut', cut)
1643 pcalc.param(
'decayMode', dmID)
1644 pcalc.param(
'writeOut', writeOut)
1645 pcalc.param(
'recoList', recoList)
1646 path.add_module(pcalc)
1648 rmake = register_module(
'KlongDecayReconstructorExpert')
1649 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1650 rmake.param(
'decayString', decayString)
1651 rmake.param(
'cut', cut)
1652 rmake.param(
'decayMode', dmID)
1653 rmake.param(
'writeOut', writeOut)
1654 rmake.param(
'recoList', recoList)
1655 path.add_module(rmake)
1658 def setBeamConstrainedMomentum(particleList, decayStringTarget, decayStringDaughters, path=None):
1660 Replace the four-momentum of the target Particle by p(beam) - p(selected daughters).
1661 The momentum of the mother Particle will not be changed.
1663 @param particleList mother Particlelist
1664 @param decayStringTarget DecayString specifying the target particle whose momentum
1666 @param decayStringDaughters DecayString specifying the daughter particles used to replace
1667 the momentum of the target particle by p(beam)-p(daughters)
1670 mod = register_module(
'ParticleMomentumUpdater')
1671 mod.set_name(
'ParticleMomentumUpdater' + particleList)
1672 mod.param(
'particleList', particleList)
1673 mod.param(
'decayStringTarget', decayStringTarget)
1674 mod.param(
'decayStringDaughters', decayStringDaughters)
1675 path.add_module(mod)
1678 def updateKlongKinematicsExpert(particleList,
1682 Calculates and updates the kinematics of B->K_L0 + something else with same method as
1683 `reconstructMissingKlongDecayExpert`. This helps to revert the kinematics after the vertex fitting.
1685 @param particleList input ParticleList of B meson that decays to K_L0 + X
1686 @param writeOut whether RootOutput module should save the ParticleList
1687 @param path modules are added to this path
1690 mod = register_module(
'KlongMomentumUpdaterExpert')
1691 mod.set_name(
'KlongMomentumUpdaterExpert_' + particleList)
1692 mod.param(
'listName', particleList)
1693 mod.param(
'writeOut', writeOut)
1694 path.add_module(mod)
1697 def replaceMass(replacerName, particleLists=None, pdgCode=22, path=None):
1699 replaces the mass of the particles inside the given particleLists
1700 with the invariant mass of the particle corresponding to the given pdgCode.
1702 @param particleLists new ParticleList filled with copied Particles
1703 @param pdgCode PDG code for mass reference
1704 @param path modules are added to this path
1707 if particleLists
is None:
1711 pmassupdater = register_module(
'ParticleMassUpdater')
1712 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1713 pmassupdater.param(
'particleLists', particleLists)
1714 pmassupdater.param(
'pdgCode', pdgCode)
1715 path.add_module(pmassupdater)
1718 def reconstructRecoil(decayString,
1723 candidate_limit=None,
1724 allowChargeViolation=False):
1726 Creates new Particles that recoil against the input particles.
1728 For example the decay string M -> D1 D2 D3 will:
1729 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1730 - Particles D1, D2, D3 will be appended as daughters to M
1731 - the 4-momentum of the mother Particle M is given by
1732 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1734 @param decayString DecayString specifying what kind of the decay should be reconstructed
1735 (from the DecayString the mother and daughter ParticleLists are determined)
1736 @param cut created (mother) Particles are added to the mother ParticleList if they
1737 pass give cuts (in VariableManager style) and rejected otherwise
1738 @param dmID user specified decay mode identifier
1739 @param writeOut whether RootOutput module should save the created ParticleList
1740 @param path modules are added to this path
1741 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1742 the number of candidates is exceeded no candidate will be
1743 reconstructed for that event and a Warning will be
1745 If no value is given the amount is limited to a sensible
1746 default. A value <=0 will disable this limit and can
1747 cause huge memory amounts so be careful.
1748 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1751 pmake = register_module(
'ParticleCombiner')
1752 pmake.set_name(
'ParticleCombiner_' + decayString)
1753 pmake.param(
'decayString', decayString)
1754 pmake.param(
'cut', cut)
1755 pmake.param(
'decayMode', dmID)
1756 pmake.param(
'writeOut', writeOut)
1757 pmake.param(
'recoilParticleType', 1)
1758 if candidate_limit
is not None:
1759 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1760 pmake.param(
'allowChargeViolation', allowChargeViolation)
1761 path.add_module(pmake)
1764 def reconstructRecoilDaughter(decayString,
1769 candidate_limit=None,
1770 allowChargeViolation=False):
1772 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1774 For example the decay string M -> D1 D2 D3 will:
1775 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1776 - Particles D1, D2, D3 will be appended as daughters to M
1777 - the 4-momentum of the mother Particle M is given by
1778 p(M) = p(D1) - Sum_i p(Di), where i>1
1780 @param decayString DecayString specifying what kind of the decay should be reconstructed
1781 (from the DecayString the mother and daughter ParticleLists are determined)
1782 @param cut created (mother) Particles are added to the mother ParticleList if they
1783 pass give cuts (in VariableManager style) and rejected otherwise
1784 @param dmID user specified decay mode identifier
1785 @param writeOut whether RootOutput module should save the created ParticleList
1786 @param path modules are added to this path
1787 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1788 the number of candidates is exceeded no candidate will be
1789 reconstructed for that event and a Warning will be
1791 If no value is given the amount is limited to a sensible
1792 default. A value <=0 will disable this limit and can
1793 cause huge memory amounts so be careful.
1794 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1795 daughter is actually the mother
1798 pmake = register_module(
'ParticleCombiner')
1799 pmake.set_name(
'ParticleCombiner_' + decayString)
1800 pmake.param(
'decayString', decayString)
1801 pmake.param(
'cut', cut)
1802 pmake.param(
'decayMode', dmID)
1803 pmake.param(
'writeOut', writeOut)
1804 pmake.param(
'recoilParticleType', 2)
1805 if candidate_limit
is not None:
1806 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1807 pmake.param(
'allowChargeViolation', allowChargeViolation)
1808 path.add_module(pmake)
1811 def rankByHighest(particleList,
1815 allowMultiRank=False,
1817 overwriteRank=False,
1820 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1821 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1822 The list is also sorted from best to worst candidate
1823 (each charge, e.g. B+/B-, separately).
1824 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1825 a non-zero value for 'numBest'.
1828 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1829 These variable names can become clunky, so it's probably a good idea to set an alias.
1830 For example if you rank your B candidates by momentum,
1834 rankByHighest("B0:myCandidates", "p", path=mypath)
1835 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1838 @param particleList The input ParticleList
1839 @param variable Variable to order Particles by.
1840 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1841 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1842 @param allowMultiRank If true, candidates with the same value will get the same rank.
1843 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1844 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1845 @param path modules are added to this path
1848 bcs = register_module(
'BestCandidateSelection')
1849 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1850 bcs.param(
'particleList', particleList)
1851 bcs.param(
'variable', variable)
1852 bcs.param(
'numBest', numBest)
1853 bcs.param(
'outputVariable', outputVariable)
1854 bcs.param(
'allowMultiRank', allowMultiRank)
1855 bcs.param(
'cut', cut)
1856 bcs.param(
'overwriteRank', overwriteRank)
1857 path.add_module(bcs)
1860 def rankByLowest(particleList,
1864 allowMultiRank=False,
1866 overwriteRank=False,
1869 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1870 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1871 The list is also sorted from best to worst candidate
1872 (each charge, e.g. B+/B-, separately).
1873 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1874 a non-zero value for 'numBest'.
1877 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1878 These variable names can become clunky, so it's probably a good idea to set an alias.
1879 For example if you rank your B candidates by :b2:var:`dM`,
1883 rankByLowest("B0:myCandidates", "dM", path=mypath)
1884 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1887 @param particleList The input ParticleList
1888 @param variable Variable to order Particles by.
1889 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1890 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1891 @param allowMultiRank If true, candidates with the same value will get the same rank.
1892 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1893 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1894 @param path modules are added to this path
1897 bcs = register_module(
'BestCandidateSelection')
1898 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1899 bcs.param(
'particleList', particleList)
1900 bcs.param(
'variable', variable)
1901 bcs.param(
'numBest', numBest)
1902 bcs.param(
'selectLowest',
True)
1903 bcs.param(
'allowMultiRank', allowMultiRank)
1904 bcs.param(
'outputVariable', outputVariable)
1905 bcs.param(
'cut', cut)
1906 bcs.param(
'overwriteRank', overwriteRank)
1907 path.add_module(bcs)
1910 def applyRandomCandidateSelection(particleList, path=None):
1912 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1913 This is done on a event-by-event basis.
1915 @param particleList ParticleList for which the random candidate selection should be applied
1916 @param path module is added to this path
1919 rcs = register_module(
'BestCandidateSelection')
1920 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1921 rcs.param(
'particleList', particleList)
1922 rcs.param(
'variable',
'random')
1923 rcs.param(
'selectLowest',
False)
1924 rcs.param(
'allowMultiRank',
False)
1925 rcs.param(
'numBest', 1)
1926 rcs.param(
'cut',
'')
1927 rcs.param(
'outputVariable',
'')
1928 path.add_module(rcs)
1933 Prints the contents of DataStore in the first event (or a specific event number or all events).
1934 Will list all objects and arrays (including size).
1937 The command line tool: ``b2file-size``.
1940 eventNumber (int): Print the datastore only for this event. The default
1941 (-1) prints only the first event, 0 means print for all events (can produce large output)
1942 path (basf2.Path): the PrintCollections module is added to this path
1945 This will print a lot of output if you print it for all events and process many events.
1949 printDS = register_module(
'PrintCollections')
1950 printDS.param(
'printForEvent', eventNumber)
1951 path.add_module(printDS)
1954 def printVariableValues(list_name, var_names, path):
1956 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
1958 @param list_name input ParticleList name
1959 @param var_names vector of variable names to be printed
1960 @param path modules are added to this path
1963 prlist = register_module(
'ParticlePrinter')
1964 prlist.set_name(
'ParticlePrinter_' + list_name)
1965 prlist.param(
'listName', list_name)
1966 prlist.param(
'fullPrint',
False)
1967 prlist.param(
'variables', var_names)
1968 path.add_module(prlist)
1971 def printList(list_name, full, path):
1973 Prints the size and executes Particle->print() (if full=True)
1974 method for all Particles in given ParticleList. For debugging purposes.
1976 @param list_name input ParticleList name
1977 @param full execute Particle->print() method for all Particles
1978 @param path modules are added to this path
1981 prlist = register_module(
'ParticlePrinter')
1982 prlist.set_name(
'ParticlePrinter_' + list_name)
1983 prlist.param(
'listName', list_name)
1984 prlist.param(
'fullPrint', full)
1985 path.add_module(prlist)
1988 def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None, basketsize=1600,
1989 signalSideParticleList="", filenameSuffix=""):
1991 Creates and fills a flat ntuple with the specified variables from the VariableManager.
1992 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
1993 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
1996 decayString (str): specifies type of Particles and determines the name of the ParticleList
1997 variables (list(str)): the list of variables (which must be registered in the VariableManager)
1998 treename (str): name of the ntuple tree
1999 filename (str): which is used to store the variables
2000 path (basf2.Path): the basf2 path where the analysis is processed
2001 basketsize (int): size of baskets in the output ntuple in bytes
2002 signalSideParticleList (str): The name of the signal-side ParticleList.
2003 Only valid if the module is called in a for_each loop over the RestOfEvent.
2004 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2006 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2009 output = register_module(
'VariablesToNtuple')
2010 output.set_name(
'VariablesToNtuple_' + decayString)
2011 output.param(
'particleList', decayString)
2012 output.param(
'variables', variables)
2013 output.param(
'fileName', filename)
2014 output.param(
'treeName', treename)
2015 output.param(
'basketSize', basketsize)
2016 output.param(
'signalSideParticleList', signalSideParticleList)
2017 output.param(
'fileNameSuffix', filenameSuffix)
2018 path.add_module(output)
2024 filename='ntuple.root',
2027 prefixDecayString=False,
2030 Creates and fills a flat ntuple with the specified variables from the VariableManager
2033 decayString (str): specifies type of Particles and determines the name of the ParticleList
2034 variables (list(tuple))): variables + binning which must be registered in the VariableManager
2035 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
2036 filename (str): which is used to store the variables
2037 path (basf2.Path): the basf2 path where the analysis is processed
2038 directory (str): directory inside the output file where the histograms should be saved.
2039 Useful if you want to have different histograms in the same file to separate them.
2040 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
2041 programmatic naming of the structure in the file.
2042 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2044 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2047 if variables_2d
is None:
2049 output = register_module(
'VariablesToHistogram')
2050 output.set_name(
'VariablesToHistogram_' + decayString)
2051 output.param(
'particleList', decayString)
2052 output.param(
'variables', variables)
2053 output.param(
'variables_2d', variables_2d)
2054 output.param(
'fileName', filename)
2055 output.param(
'fileNameSuffix', filenameSuffix)
2056 if directory
is not None or prefixDecayString:
2057 if directory
is None:
2059 if prefixDecayString:
2060 directory = decayString +
"_" + directory
2061 output.param(
"directory", directory)
2062 path.add_module(output)
2067 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
2068 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
2071 particleList (str): The input ParticleList
2072 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2073 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2074 An existing extra info with the same name will be overwritten if the new
2075 value is lower / will never be overwritten / will be overwritten if the
2076 new value is higher / will always be overwritten (option = -1/0/1/2).
2077 path (basf2.Path): modules are added to this path
2080 mod = register_module(
'VariablesToExtraInfo')
2081 mod.set_name(
'VariablesToExtraInfo_' + particleList)
2082 mod.param(
'particleList', particleList)
2083 mod.param(
'variables', variables)
2084 mod.param(
'overwrite', option)
2085 path.add_module(mod)
2088 def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
2090 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
2091 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
2092 to specified daughter particle.
2095 particleList (str): The input ParticleList
2096 decayString (str): Decay string that specifies to which daughter the extra info should be appended
2097 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2098 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2099 An existing extra info with the same name will be overwritten if the new
2100 value is lower / will never be overwritten / will be overwritten if the
2101 new value is higher / will always be overwritten (option = -1/0/1/2).
2102 path (basf2.Path): modules are added to this path
2105 mod = register_module(
'VariablesToExtraInfo')
2106 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
2107 mod.param(
'particleList', particleList)
2108 mod.param(
'decayString', decayString)
2109 mod.param(
'variables', variables)
2110 mod.param(
'overwrite', option)
2111 path.add_module(mod)
2114 def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
2116 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
2117 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
2120 When the function is called first time not in the main path but in a sub-path e.g. ``roe_path``,
2121 the eventExtraInfo cannot be accessed from the main path because of the shorter lifetime of the event-extra-info field.
2122 If one wants to call the function in a sub-path, one has to call the function in the main path beforehand.
2125 particleList (str): The input ParticleList
2126 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2127 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2128 An existing extra info with the same name will be overwritten if the new
2129 value is lower / will never be overwritten / will be overwritten if the
2130 new value is higher / will always be overwritten (option = -1/0/1/2).
2131 path (basf2.Path): modules are added to this path
2134 mod = register_module(
'VariablesToEventExtraInfo')
2135 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
2136 mod.param(
'particleList', particleList)
2137 mod.param(
'variables', variables)
2138 mod.param(
'overwrite', option)
2139 path.add_module(mod)
2142 def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
2144 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
2145 particle) as an extra info to the particle related to current ROE.
2146 Should be used only in the for_each roe path.
2149 particleList (str): The input ParticleList
2150 varToExtraInfo (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2151 path (basf2.Path): modules are added to this path
2154 mod = register_module(
'SignalSideVariablesToExtraInfo')
2155 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
2156 mod.param(
'particleListName', particleList)
2157 mod.param(
'variableToExtraInfo', varToExtraInfo)
2158 path.add_module(mod)
2161 def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
2163 Define and blind a signal region.
2164 Per default, the defined signal region is cut out if ran on data.
2165 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
2169 .. code-block:: python
2171 ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
2172 ma.signalRegion("B+:sig",
2173 "Mbc>5.27 and abs(deltaE)<0.2",
2176 ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
2179 particleList (str): The input ParticleList
2180 cut (str): Cut string describing the signal region
2181 path (basf2.Path):: Modules are added to this path
2182 name (str): Name of the Signal region in the variable manager
2183 blind_data (bool): Automatically exclude signal region from data
2187 from variables
import variables
2188 mod = register_module(
'VariablesToExtraInfo')
2189 mod.set_name(f
'{name}_' + particleList)
2190 mod.param(
'particleList', particleList)
2191 mod.param(
'variables', {f
"passesCut({cut})": name})
2192 variables.addAlias(name, f
"extraInfo({name})")
2193 path.add_module(mod)
2197 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
2200 def removeExtraInfo(particleLists=None, removeEventExtraInfo=False, path=None):
2202 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
2205 if particleLists
is None:
2207 mod = register_module(
'ExtraInfoRemover')
2208 mod.param(
'particleLists', particleLists)
2209 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
2210 path.add_module(mod)
2213 def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
2215 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2216 to the particle from the input ParticleList. Additional selection criteria can be applied.
2217 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2218 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2219 suggests should be empty and its purpose is to end the execution of for_each roe path for
2220 the current ROE object.
2222 @param particleList The input ParticleList
2223 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2224 @param for_each roe path in which this filter is executed
2225 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2228 mod = register_module(
'SignalSideParticleFilter')
2229 mod.set_name(
'SigSideParticleFilter_' + particleList)
2230 mod.param(
'particleLists', [particleList])
2231 mod.param(
'selection', selection)
2232 roe_path.add_module(mod)
2233 mod.if_false(deadEndPath)
2236 def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
2238 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2239 to the particle from the input ParticleList. Additional selection criteria can be applied.
2240 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2241 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2242 suggests should be empty and its purpose is to end the execution of for_each roe path for
2243 the current ROE object.
2245 @param particleLists The input ParticleLists
2246 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2247 @param for_each roe path in which this filter is executed
2248 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2251 mod = register_module(
'SignalSideParticleFilter')
2252 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
2253 mod.param(
'particleLists', particleLists)
2254 mod.param(
'selection', selection)
2255 roe_path.add_module(mod)
2256 mod.if_false(deadEndPath)
2265 chargeConjugation=True,
2268 Finds and creates a ``ParticleList`` from given decay string.
2269 ``ParticleList`` of daughters with sub-decay is created.
2271 Only the particles made from MCParticle, which can be loaded by `fillParticleListFromMC`, are accepted as daughters.
2273 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
2274 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
2277 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
2278 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
2279 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
2282 It is recommended to use only primary particles as daughter particles unless you want to explicitly study the secondary
2283 particles. The behavior of MC-matching for secondary particles from a stable particle decay is not guaranteed.
2284 Please consider to use `fillParticleListFromMC` with ``skipNonPrimary=True`` to load daughter particles.
2285 Moreover, it is recommended to load ``K_S0`` and ``Lambda0`` directly from MCParticle by `fillParticleListFromMC` rather
2286 than reconstructing from two pions or a proton-pion pair, because their direct daughters can be the secondary particle.
2289 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
2290 (from the DecayString the mother and daughter ParticleLists are determined)
2291 @param cut created (mother) Particles are added to the mother ParticleList if they
2292 pass given cuts (in VariableManager style) and rejected otherwise
2293 isSignal==1 is always required by default.
2294 @param dmID user specified decay mode identifier
2295 @param writeOut whether RootOutput module should save the created ParticleList
2296 @param path modules are added to this path
2297 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
2300 pmake = register_module(
'ParticleCombinerFromMC')
2301 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
2302 pmake.param(
'decayString', decayString)
2303 pmake.param(
'cut', cut)
2304 pmake.param(
'decayMode', dmID)
2305 pmake.param(
'writeOut', writeOut)
2306 pmake.param(
'chargeConjugation', chargeConjugation)
2307 path.add_module(pmake)
2314 appendAllDaughters=False,
2315 skipNonPrimaryDaughters=True,
2319 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
2320 The decay string is required to describe correctly what you want.
2321 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
2323 The output particles has only the daughter particles written in the given decay string, if
2324 ``appendAllDaughters=False`` (default). If ``appendAllDaughters=True``, all daughters of the matched MCParticle are
2325 appended in the order defined at the MCParticle level. For example,
2327 .. code-block:: python
2329 findMCDecay('B0:Xee', 'B0 -> e+ e- ... ?gamma', appendAllDaughters=False, path=mypath)
2331 The output ParticleList ``B0:Xee`` will match the inclusive ``B0 -> e+ e-`` decays (but neutrinos are not included),
2332 in both cases of ``appendAllDaughters`` is false and true.
2333 If the ``appendAllDaughters=False`` as above example, the ``B0:Xee`` has only two electrons as daughters.
2334 While, if ``appendAllDaughters=True``, all daughters of the matched MCParticles are appended. When the truth decay mode of
2335 the MCParticle is ``B0 -> [K*0 -> K+ pi-] [J/psi -> e+ e-]``, the first daughter of ``B0:Xee`` is ``K*0`` and ``e+``
2336 will be the first daughter of second daughter of ``B0:Xee``.
2338 The option ``skipNonPrimaryDaughters`` only has an effect if ``appendAllDaughters=True``. If ``skipNonPrimaryDaughters=True``,
2339 all primary daughters are appended but the secondary particles are not.
2342 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not a final state particle.
2343 In order for the MCMatching to work properly, the daughters of ``Lambda0`` are appended to
2344 ``Lambda0`` regardless of the value of the option ``skipNonPrimaryDaughters``.
2347 @param list_name The output particle list name
2348 @param decay The decay string which you want
2349 @param writeOut Whether `RootOutput` module should save the created ``outputList``
2350 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
2351 @param appendAllDaughters if true, not only the daughters described in the decay string but all daughters are appended
2352 @param path modules are added to this path
2355 decayfinder = register_module(
'MCDecayFinder')
2356 decayfinder.set_name(
'MCDecayFinder_' + list_name)
2357 decayfinder.param(
'listName', list_name)
2358 decayfinder.param(
'decayString', decay)
2359 decayfinder.param(
'appendAllDaughters', appendAllDaughters)
2360 decayfinder.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
2361 decayfinder.param(
'writeOut', writeOut)
2362 path.add_module(decayfinder)
2365 def summaryOfLists(particleLists, outputFile=None, path=None):
2367 Prints out Particle statistics at the end of the job: number of events with at
2368 least one candidate, average number of candidates per event, etc.
2369 If an output file name is provided the statistics is also dumped into a json file with that name.
2371 @param particleLists list of input ParticleLists
2372 @param outputFile output file name (not created by default)
2375 particleStats = register_module(
'ParticleStats')
2376 particleStats.param(
'particleLists', particleLists)
2377 if outputFile
is not None:
2378 particleStats.param(
'outputFile', outputFile)
2379 path.add_module(particleStats)
2382 def matchMCTruth(list_name, path):
2384 Performs MC matching (sets relation Particle->MCParticle) for
2385 all particles (and its (grand)^N-daughter particles) in the specified
2388 @param list_name name of the input ParticleList
2389 @param path modules are added to this path
2392 mcMatch = register_module(
'MCMatcherParticles')
2393 mcMatch.set_name(
'MCMatch_' + list_name)
2394 mcMatch.param(
'listName', list_name)
2395 path.add_module(mcMatch)
2398 def looseMCTruth(list_name, path):
2400 Performs loose MC matching for all particles in the specified
2402 The difference between loose and normal mc matching algorithm is that
2403 the loose algorithm will find the common mother of the majority of daughter
2404 particles while the normal algorithm finds the common mother of all daughters.
2405 The results of loose mc matching algorithm are stored to the following extraInfo
2408 - looseMCMotherPDG: PDG code of most common mother
2409 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
2410 - looseMCWrongDaughterN: number of daughters that don't originate from the most common mother
2411 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from the most common mother (only if
2412 looseMCWrongDaughterN = 1)
2413 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background Particle
2415 @param list_name name of the input ParticleList
2416 @param path modules are added to this path
2419 mcMatch = register_module(
'MCMatcherParticles')
2420 mcMatch.set_name(
'LooseMCMatch_' + list_name)
2421 mcMatch.param(
'listName', list_name)
2422 mcMatch.param(
'looseMCMatching',
True)
2423 path.add_module(mcMatch)
2426 def buildRestOfEvent(target_list_name, inputParticlelists=None,
2427 fillWithMostLikely=True,
2428 chargedPIDPriors=None, path=None):
2430 Creates for each Particle in the given ParticleList a RestOfEvent
2431 dataobject and makes basf2 relation between them. User can provide additional
2432 particle lists with a different particle hypothesis like ['K+:good, e+:good'], etc.
2434 @param target_list_name name of the input ParticleList
2435 @param inputParticlelists list of user-defined input particle list names, which serve
2436 as source of particles to build the ROE, the FSP particles from
2437 target_list_name are automatically excluded from the ROE object
2438 @param fillWithMostLikely By default the module uses the most likely particle mass hypothesis for charged particles
2439 based on the PID likelihood. Turn this behavior off if you want to configure your own
2440 input particle lists.
2441 @param chargedPIDPriors The prior PID fractions, that are used to regulate the
2442 amount of certain charged particle species, should be a list of
2443 six floats if not None. The order of particle types is
2444 the following: [e-, mu-, pi-, K-, p+, d+]
2445 @param path modules are added to this path
2448 if inputParticlelists
is None:
2449 inputParticlelists = []
2450 fillParticleList(
'pi+:all',
'', path=path)
2451 if fillWithMostLikely:
2452 from stdCharged
import stdMostLikely
2453 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
2454 inputParticlelists = [
'%s:mostlikely_roe' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
2457 fillParticleList(
'gamma:all',
'', path=path)
2458 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
2459 inputParticlelists += [
'pi+:all',
'gamma:all',
'K_L0:roe_default']
2461 inputParticlelists += [
'pi+:all',
'gamma:mdst']
2462 roeBuilder = register_module(
'RestOfEventBuilder')
2463 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
2464 roeBuilder.param(
'particleList', target_list_name)
2465 roeBuilder.param(
'particleListsInput', inputParticlelists)
2466 roeBuilder.param(
'mostLikely', fillWithMostLikely)
2467 path.add_module(roeBuilder)
2470 def buildNestedRestOfEvent(target_list_name, maskName='all', path=None):
2472 Creates for each Particle in the given ParticleList a RestOfEvent
2473 @param target_list_name name of the input ParticleList
2474 @param mask_name name of the ROEMask to be used
2475 @param path modules are added to this path
2478 roeBuilder = register_module(
'RestOfEventBuilder')
2479 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
2480 roeBuilder.param(
'particleList', target_list_name)
2481 roeBuilder.param(
'nestedROEMask', maskName)
2482 roeBuilder.param(
'createNestedROE',
True)
2483 path.add_module(roeBuilder)
2486 def buildRestOfEventFromMC(target_list_name, inputParticlelists=None, path=None):
2488 Creates for each Particle in the given ParticleList a RestOfEvent
2489 @param target_list_name name of the input ParticleList
2490 @param inputParticlelists list of input particle list names, which serve
2491 as a source of particles to build ROE, the FSP particles from
2492 target_list_name are excluded from ROE object
2493 @param path modules are added to this path
2496 if inputParticlelists
is None:
2497 inputParticlelists = []
2498 if (len(inputParticlelists) == 0):
2502 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
2503 'n0',
'nu_e',
'nu_mu',
'nu_tau',
2506 fillParticleListFromMC(
"%s:roe_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
2507 True,
True, path=path)
2508 inputParticlelists += [
"%s:roe_default_gen" % t]
2509 roeBuilder = register_module(
'RestOfEventBuilder')
2510 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
2511 roeBuilder.param(
'particleList', target_list_name)
2512 roeBuilder.param(
'particleListsInput', inputParticlelists)
2513 roeBuilder.param(
'fromMC',
True)
2514 path.add_module(roeBuilder)
2517 def appendROEMask(list_name,
2520 eclClusterSelection,
2521 klmClusterSelection='',
2524 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2525 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
2527 - append a ROE mask with all tracks in ROE coming from the IP region
2529 .. code-block:: python
2531 appendROEMask('B+:sig', 'IPtracks', '[dr < 2] and [abs(dz) < 5]', path=mypath)
2533 - append a ROE mask with only ECL-based particles that pass as good photon candidates
2535 .. code-block:: python
2537 goodPhotons = 'inCDCAcceptance and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
2538 appendROEMask('B+:sig', 'goodROEGamma', '', goodPhotons, path=mypath)
2541 @param list_name name of the input ParticleList
2542 @param mask_name name of the appended ROEMask
2543 @param trackSelection decay string for the track-based particles in ROE
2544 @param eclClusterSelection decay string for the ECL-based particles in ROE
2545 @param klmClusterSelection decay string for the KLM-based particles in ROE
2546 @param path modules are added to this path
2549 roeMask = register_module(
'RestOfEventInterpreter')
2550 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2551 roeMask.param(
'particleList', list_name)
2552 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2553 path.add_module(roeMask)
2556 def appendROEMasks(list_name, mask_tuples, path=None):
2558 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2559 selection criteria for track-, ECL- and KLM-based particles which will be used by ROE variables.
2561 The multiple ROE masks with their own selection criteria are specified
2562 via list of tuples (mask_name, trackParticleSelection, eclParticleSelection, klmParticleSelection) or
2563 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
2565 - Example for two tuples, one with and one without fractions
2567 .. code-block:: python
2569 ipTracks = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', '')
2570 goodPhotons = 'inCDCAcceptance and [clusterErrorTiming < 1e6] and [clusterE1E9 > 0.4 or E > 0.075]'
2571 goodROEGamma = ('ROESel', '[dr < 2] and [abs(dz) < 5]', goodPhotons, '')
2572 goodROEKLM = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', 'nKLMClusterTrackMatches == 0')
2573 appendROEMasks('B+:sig', [ipTracks, goodROEGamma, goodROEKLM], path=mypath)
2575 @param list_name name of the input ParticleList
2576 @param mask_tuples array of ROEMask list tuples to be appended
2577 @param path modules are added to this path
2580 compatible_masks = []
2581 for mask
in mask_tuples:
2584 compatible_masks += [(*mask,
'')]
2586 compatible_masks += [mask]
2587 roeMask = register_module(
'RestOfEventInterpreter')
2588 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2589 roeMask.param(
'particleList', list_name)
2590 roeMask.param(
'ROEMasks', compatible_masks)
2591 path.add_module(roeMask)
2594 def updateROEMask(list_name,
2597 eclClusterSelection='',
2598 klmClusterSelection='',
2601 Update an existing ROE mask by applying additional selection cuts for
2602 tracks and/or clusters.
2604 See function `appendROEMask`!
2606 @param list_name name of the input ParticleList
2607 @param mask_name name of the ROEMask to update
2608 @param trackSelection decay string for the track-based particles in ROE
2609 @param eclClusterSelection decay string for the ECL-based particles in ROE
2610 @param klmClusterSelection decay string for the KLM-based particles in ROE
2611 @param path modules are added to this path
2614 roeMask = register_module(
'RestOfEventInterpreter')
2615 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2616 roeMask.param(
'particleList', list_name)
2617 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2618 roeMask.param(
'update',
True)
2619 path.add_module(roeMask)
2622 def updateROEMasks(list_name, mask_tuples, path):
2624 Update existing ROE masks by applying additional selection cuts for tracks
2627 The multiple ROE masks with their own selection criteria are specified
2628 via list tuples (mask_name, trackSelection, eclClusterSelection, klmClusterSelection)
2630 See function `appendROEMasks`!
2632 @param list_name name of the input ParticleList
2633 @param mask_tuples array of ROEMask list tuples to be appended
2634 @param path modules are added to this path
2637 compatible_masks = []
2638 for mask
in mask_tuples:
2641 compatible_masks += [(*mask,
'')]
2643 compatible_masks += [mask]
2645 roeMask = register_module(
'RestOfEventInterpreter')
2646 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2647 roeMask.param(
'particleList', list_name)
2648 roeMask.param(
'ROEMasks', compatible_masks)
2649 roeMask.param(
'update',
True)
2650 path.add_module(roeMask)
2653 def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2655 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2656 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2657 This function should be executed only in the for_each roe path for the current ROE object.
2659 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2660 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2661 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2662 pion particle list (e.g. 'pi+:someLabel').
2664 Updating a non-existing mask will create a new one.
2666 - keep only those tracks that were used in provided particle list
2668 .. code-block:: python
2670 keepInROEMasks('pi+:goodTracks', 'mask', '', path=mypath)
2672 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2674 .. code-block:: python
2676 keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1', path=mypath)
2679 @param list_name name of the input ParticleList
2680 @param mask_names array of ROEMasks to be updated
2681 @param cut_string decay string with which the mask will be updated
2682 @param path modules are added to this path
2685 updateMask = register_module(
'RestOfEventUpdater')
2686 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2687 updateMask.param(
'particleList', list_name)
2688 updateMask.param(
'updateMasks', mask_names)
2689 updateMask.param(
'cutString', cut_string)
2690 updateMask.param(
'discard',
False)
2691 path.add_module(updateMask)
2694 def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2696 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2697 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2698 This function should be executed only in the for_each roe path for the current ROE object.
2700 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2701 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2702 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2703 pion particle list (e.g. 'pi+:someLabel').
2705 Updating a non-existing mask will create a new one.
2707 - discard tracks that were used in provided particle list
2709 .. code-block:: python
2711 discardFromROEMasks('pi+:badTracks', 'mask', '', path=mypath)
2713 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2715 .. code-block:: python
2717 discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1', path=mypath)
2720 @param list_name name of the input ParticleList
2721 @param mask_names array of ROEMasks to be updated
2722 @param cut_string decay string with which the mask will be updated
2723 @param path modules are added to this path
2726 updateMask = register_module(
'RestOfEventUpdater')
2727 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2728 updateMask.param(
'particleList', list_name)
2729 updateMask.param(
'updateMasks', mask_names)
2730 updateMask.param(
'cutString', cut_string)
2731 updateMask.param(
'discard',
True)
2732 path.add_module(updateMask)
2735 def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2737 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2738 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2739 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2740 passing it can be applied.
2742 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2743 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2745 Updating a non-existing mask will create a new one.
2747 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2749 .. code-block:: python
2751 optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550', path=mypath)
2753 @param list_name name of the input ParticleList
2754 @param mask_names array of ROEMasks to be updated
2755 @param cut_string decay string with which the mask will be updated
2756 @param path modules are added to this path
2759 updateMask = register_module(
'RestOfEventUpdater')
2760 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2761 updateMask.param(
'particleList', list_name)
2762 updateMask.param(
'updateMasks', mask_names)
2763 updateMask.param(
'cutString', cut_string)
2764 path.add_module(updateMask)
2767 def updateROEUsingV0Lists(target_particle_list, mask_names, default_cleanup=True, selection_cuts=None,
2768 apply_mass_fit=False, fitter='treefit', path=None):
2770 This function creates V0 particle lists (photons, :math:`K^0_S` and :math:`\\Lambda^0`)
2771 and it uses V0 candidates to update the Rest Of Event, which is associated to the target particle list.
2772 It is possible to apply a standard or customized selection and mass fit to the V0 candidates.
2775 @param target_particle_list name of the input ParticleList
2776 @param mask_names array of ROE masks to be applied
2777 @param default_cleanup if True, predefined cuts will be applied on the V0 lists
2778 @param selection_cuts a single string of selection cuts or tuple of three strings (photon_cuts, K_S0_cuts, Lambda0_cuts),
2779 which will be applied to the V0 lists. These cuts will have a priority over the default ones.
2780 @param apply_mass_fit if True, a mass fit will be applied to the V0 particles
2781 @param fitter string, that represent a fitter choice: "treefit" for TreeFitter and "kfit" for KFit
2782 @param path modules are added to this path
2785 roe_path = create_path()
2786 deadEndPath = create_path()
2787 signalSideParticleFilter(target_particle_list,
'', roe_path, deadEndPath)
2789 if (default_cleanup
and selection_cuts
is None):
2790 B2INFO(
"Using default cleanup in updateROEUsingV0Lists.")
2791 selection_cuts =
'abs(dM) < 0.1 '
2792 selection_cuts +=
'and daughter(0,particleID) > 0.2 and daughter(1,particleID) > 0.2 '
2793 selection_cuts +=
'and daughter(0,thetaInCDCAcceptance) and daughter(1,thetaInCDCAcceptance)'
2794 if (selection_cuts
is None or selection_cuts ==
''):
2795 B2INFO(
"No cleanup in updateROEUsingV0Lists.")
2796 selection_cuts = (
'True',
'True',
'True')
2797 if (isinstance(selection_cuts, str)):
2798 selection_cuts = (selection_cuts, selection_cuts, selection_cuts)
2800 roe_cuts =
'isInRestOfEvent > 0'
2801 fillConvertedPhotonsList(
'gamma:v0_roe -> e+ e-', f
'{selection_cuts[0]} and {roe_cuts}',
2803 fillParticleList(
'K_S0:v0_roe -> pi+ pi-', f
'{selection_cuts[1]} and {roe_cuts}',
2805 fillParticleList(
'Lambda0:v0_roe -> p+ pi-', f
'{selection_cuts[2]} and {roe_cuts}',
2807 fitter = fitter.lower()
2808 if (fitter !=
'treefit' and fitter !=
'kfit'):
2809 B2WARNING(
'Argument "fitter" in updateROEUsingV0Lists has only "treefit" and "kfit" options, '
2810 f
'but "{fitter}" was provided! TreeFitter will be used instead.')
2812 from vertex
import kFit, treeFit
2813 for v0
in [
'gamma:v0_roe',
'K_S0:v0_roe',
'Lambda0:v0_roe']:
2814 if (apply_mass_fit
and fitter ==
'kfit'):
2815 kFit(v0, conf_level=0.0, fit_type=
'massvertex', path=roe_path)
2816 if (apply_mass_fit
and fitter ==
'treefit'):
2817 treeFit(v0, conf_level=0.0, massConstraint=[v0.split(
':')[0]], path=roe_path)
2818 optimizeROEWithV0(v0, mask_names,
'', path=roe_path)
2819 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2822 def printROEInfo(mask_names=None, full_print=False,
2823 unpackComposites=True, path=None):
2825 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2826 It prints out basic ROE object info.
2828 If mask names are provided, specific information for those masks will be printed out.
2830 It is also possible to print out all particles in a given mask if the
2831 'full_print' is set to True.
2833 @param mask_names array of ROEMask names for printing out info
2834 @param unpackComposites if true, replace composite particles by their daughters
2835 @param full_print print out particles in mask
2836 @param path modules are added to this path
2839 if mask_names
is None:
2841 printMask = register_module(
'RestOfEventPrinter')
2842 printMask.set_name(
'RestOfEventPrinter')
2843 printMask.param(
'maskNames', mask_names)
2844 printMask.param(
'fullPrint', full_print)
2845 printMask.param(
'unpackComposites', unpackComposites)
2846 path.add_module(printMask)
2849 def buildContinuumSuppression(list_name, roe_mask, path):
2851 Creates for each Particle in the given ParticleList a ContinuumSuppression
2852 dataobject and makes basf2 relation between them.
2854 :param list_name: name of the input ParticleList
2855 :param roe_mask: name of the ROE mask
2856 :param path: modules are added to this path
2859 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2860 qqBuilder.set_name(
'QQBuilder_' + list_name)
2861 qqBuilder.param(
'particleList', list_name)
2862 qqBuilder.param(
'ROEMask', roe_mask)
2863 path.add_module(qqBuilder)
2868 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2869 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2871 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2872 @param path modules are added to this path
2875 mod = register_module(
'RemoveParticlesNotInLists')
2876 mod.param(
'particleLists', lists_to_keep)
2877 path.add_module(mod)
2880 def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2882 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2884 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2885 @param bsig_list_name Name of the Bsig ParticleList
2886 @param btag_list_name Name of the Bsig ParticleList
2887 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2890 btag = register_module(
'InclusiveBtagReconstruction')
2891 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2892 btag.param(
'upsilonListName', upsilon_list_name)
2893 btag.param(
'bsigListName', bsig_list_name)
2894 btag.param(
'btagListName', btag_list_name)
2895 btag.param(
'inputListsNames', input_lists_names)
2896 path.add_module(btag)
2899 def selectDaughters(particle_list_name, decay_string, path):
2901 Redefine the Daughters of a particle: select from decayString
2903 @param particle_list_name input particle list
2904 @param decay_string for selecting the Daughters to be preserved
2907 seld = register_module(
'SelectDaughters')
2908 seld.set_name(
'SelectDaughters_' + particle_list_name)
2909 seld.param(
'listName', particle_list_name)
2910 seld.param(
'decayString', decay_string)
2911 path.add_module(seld)
2914 def markDuplicate(particleList, prioritiseV0, path):
2916 Call DuplicateVertexMarker to find duplicate particles in a list and
2917 flag the ones that should be kept
2919 @param particleList input particle list
2920 @param prioritiseV0 if true, give V0s a higher priority
2923 markdup = register_module(
'DuplicateVertexMarker')
2924 markdup.param(
'particleList', particleList)
2925 markdup.param(
'prioritiseV0', prioritiseV0)
2926 path.add_module(markdup)
2929 PI0ETAVETO_COUNTER = 0
2932 def oldwritePi0EtaVeto(
2935 workingDirectory='.',
2936 pi0vetoname='Pi0_Prob',
2937 etavetoname='Eta_Prob',
2943 Give pi0/eta probability for hard photon.
2945 In the default weight files a value of 1.4 GeV is set as the lower limit for the hard photon energy in the CMS frame.
2947 The current default weight files are optimised using MC9.
2948 The input variables are as below. Aliases are set to some variables during training.
2950 * M: pi0/eta candidates Invariant mass
2951 * lowE: soft photon energy in lab frame
2952 * cTheta: soft photon ECL cluster's polar angle
2953 * Zmva: soft photon output of MVA using Zernike moments of the cluster
2954 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2956 If you don't have weight files in your workingDirectory,
2957 these files are downloaded from database to your workingDirectory automatically.
2958 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
2959 about how to use this function.
2962 Please don't use following ParticleList names elsewhere:
2964 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
2965 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
2967 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
2969 @param particleList The input ParticleList
2970 @param decayString specify Particle to be added to the ParticleList
2971 @param workingDirectory The weight file directory
2972 @param downloadFlag whether download default weight files or not
2973 @param pi0vetoname extraInfo name of pi0 probability
2974 @param etavetoname extraInfo name of eta probability
2975 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2976 @param path modules are added to this path
2981 B2ERROR(
"The old pi0 / eta veto is not suitable for Belle analyses.")
2986 global PI0ETAVETO_COUNTER
2988 if PI0ETAVETO_COUNTER == 0:
2989 from variables
import variables
2990 variables.addAlias(
'lowE',
'daughter(1,E)')
2991 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
2992 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
2993 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
2994 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
2995 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
2997 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
2999 roe_path = create_path()
3001 deadEndPath = create_path()
3003 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3005 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
3007 pi0softname =
'gamma:PI0SOFT'
3008 etasoftname =
'gamma:ETASOFT'
3009 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
3010 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
3014 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
3016 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
3019 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
3021 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
3023 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
3024 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
3026 if not os.path.isdir(workingDirectory):
3027 os.mkdir(workingDirectory)
3028 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
3030 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
3032 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
3033 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
3035 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
3037 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
3038 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
3040 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
3041 identifier=workingDirectory +
'/pi0veto.root')
3042 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
3043 identifier=workingDirectory +
'/etaveto.root')
3045 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
3046 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
3048 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
3049 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
3051 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3054 def writePi0EtaVeto(
3061 hardParticle='gamma',
3062 pi0PayloadNameOverride=None,
3063 pi0SoftPhotonCutOverride=None,
3064 etaPayloadNameOverride=None,
3065 etaSoftPhotonCutOverride=None
3068 Give pi0/eta probability for hard photon.
3070 In the default weight files a value of 1.4 GeV is set as the lower limit for the hard photon energy in the CMS frame.
3072 The current default weight files are optimised using MC12.
3074 The input variables of the mva training are:
3076 * M: pi0/eta candidates Invariant mass
3077 * daughter(1,E): soft photon energy in lab frame
3078 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3079 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3080 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
3081 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
3082 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
3083 * cosHelicityAngleMomentum: pi0/eta candidates cosHelicityAngleMomentum
3085 The following strings are available for mode:
3087 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
3088 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
3089 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
3090 * both: tight energy cut and clusterNHits cut are applied to soft photon
3092 The final probability of the pi0/eta veto is stored as an extraInfo. If no suffix is set it can be obtained from the variables
3093 `pi0Prob`/`etaProb`. Otherwise, it is available as '{Pi0, Eta}ProbOrigin', '{Pi0, Eta}ProbTightEnergyThreshold', '{Pi0,
3094 Eta}ProbLargeClusterSize', or '{Pi0, Eta}ProbTightEnergyThresholdAndLargeClusterSize'} for the four modes described above, with
3095 the chosen suffix appended.
3098 Please don't use following ParticleList names elsewhere:
3100 ``gamma:HardPhoton``,
3101 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
3102 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
3103 ``pi0:EtaVeto + ListName``,
3104 ``eta:EtaVeto + ListName``
3106 @param particleList the input ParticleList
3107 @param decayString specify Particle to be added to the ParticleList
3108 @param mode choose one mode out of 'standard', 'tight', 'cluster' and 'both'
3109 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
3110 @param path modules are added to this path
3111 @param suffix optional suffix to be appended to the usual extraInfo name
3112 @param hardParticle particle name which is used to calculate the pi0/eta probability (default is gamma)
3113 @param pi0PayloadNameOverride specify the payload name of pi0 veto only if one wants to use non-default one. (default is None)
3114 @param pi0SoftPhotonCutOverride specify the soft photon selection criteria of pi0 veto only if one wants to use non-default one.
3116 @param etaPayloadNameOverride specify the payload name of eta veto only if one wants to use non-default one. (default is None)
3117 @param etaSoftPhotonCutOverride specify the soft photon selection criteria of eta veto only if one wants to use non-default one.
3123 B2ERROR(
"The pi0 / eta veto is not suitable for Belle analyses.")
3125 renameSuffix =
False
3127 for module
in path.modules():
3128 if module.type() ==
"SubEvent" and not renameSuffix:
3129 for subpath
in [p.values
for p
in module.available_params()
if p.name ==
"path"]:
3132 for submodule
in subpath.modules():
3133 if f
'{hardParticle}:HardPhoton{suffix}' in submodule.name():
3135 B2WARNING(
"Same extension already used in writePi0EtaVeto, append '_0'")
3139 roe_path = create_path()
3140 deadEndPath = create_path()
3141 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3142 fillSignalSideParticleList(f
'{hardParticle}:HardPhoton{suffix}', decayString, path=roe_path)
3144 dictListName = {
'standard':
'Origin',
3145 'tight':
'TightEnergyThreshold',
3146 'cluster':
'LargeClusterSize',
3147 'both':
'TightEnrgyThresholdAndLargeClusterSize'}
3149 dictPi0EnergyCut = {
'standard':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3150 'tight':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3151 'cluster':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3152 'both':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3154 dictEtaEnergyCut = {
'standard':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3155 'tight':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3156 'cluster':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3157 'both':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]'}
3159 dictNHitsCut = {
'standard':
'clusterNHits >= 0',
3160 'tight':
'clusterNHits >= 0',
3161 'cluster':
'clusterNHits >= 2',
3162 'both':
'clusterNHits >= 2'}
3164 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
3165 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
3166 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
3167 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
3169 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
3170 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
3171 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
3172 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
3174 dictPi0ExtraInfoName = {
'standard':
'Pi0ProbOrigin',
3175 'tight':
'Pi0ProbTightEnergyThreshold',
3176 'cluster':
'Pi0ProbLargeClusterSize',
3177 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize'}
3179 dictEtaExtraInfoName = {
'standard':
'EtaProbOrigin',
3180 'tight':
'EtaProbTightEnergyThreshold',
3181 'cluster':
'EtaProbLargeClusterSize',
3182 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize'}
3184 ListName = dictListName[mode]
3185 Pi0EnergyCut = dictPi0EnergyCut[mode]
3186 EtaEnergyCut = dictEtaEnergyCut[mode]
3187 TimingCut =
'abs(clusterTiming)<clusterErrorTiming'
3188 NHitsCut = dictNHitsCut[mode]
3189 Pi0PayloadName = dictPi0PayloadName[mode]
3190 EtaPayloadName = dictEtaPayloadName[mode]
3191 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
3192 EtaExtraInfoName = dictEtaExtraInfoName[mode]
3195 if pi0PayloadNameOverride
is not None:
3196 Pi0PayloadName = pi0PayloadNameOverride
3197 if pi0SoftPhotonCutOverride
is None:
3198 Pi0SoftPhotonCut = Pi0EnergyCut +
' and ' + NHitsCut
3202 Pi0SoftPhotonCut +=
' and ' + TimingCut
3204 Pi0SoftPhotonCut = pi0SoftPhotonCutOverride
3207 pi0soft = f
'gamma:Pi0Soft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3209 fillParticleList(pi0soft, Pi0SoftPhotonCut, path=roe_path)
3211 reconstructDecay(
'pi0:Pi0Veto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + pi0soft,
'',
3212 allowChargeViolation=
True, path=roe_path)
3214 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName],
3215 extraInfoName=Pi0ExtraInfoName, identifier=Pi0PayloadName)
3217 rankByHighest(
'pi0:Pi0Veto' + ListName,
'extraInfo(' + Pi0ExtraInfoName +
')', numBest=1, path=roe_path)
3219 variableToSignalSideExtraInfo(
'pi0:Pi0Veto' + ListName,
3220 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoName + suffix}, path=roe_path)
3223 if etaPayloadNameOverride
is not None:
3224 EtaPayloadName = etaPayloadNameOverride
3225 if etaSoftPhotonCutOverride
is None:
3226 EtaSoftPhotonCut = EtaEnergyCut +
' and ' + NHitsCut
3230 EtaSoftPhotonCut +=
' and ' + TimingCut
3232 EtaSoftPhotonCut = etaSoftPhotonCutOverride
3234 etasoft = f
'gamma:EtaSoft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3235 fillParticleList(etasoft, EtaSoftPhotonCut, path=roe_path)
3236 reconstructDecay(
'eta:EtaVeto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + etasoft,
'',
3237 allowChargeViolation=
True, path=roe_path)
3238 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName],
3239 extraInfoName=EtaExtraInfoName, identifier=EtaPayloadName)
3240 rankByHighest(
'eta:EtaVeto' + ListName,
'extraInfo(' + EtaExtraInfoName +
')', numBest=1, path=roe_path)
3241 variableToSignalSideExtraInfo(
'eta:EtaVeto' + ListName,
3242 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoName + suffix}, path=roe_path)
3244 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3247 def lowEnergyPi0Identification(pi0List, gammaList, payloadNameSuffix,
3250 Calculate low-energy pi0 identification.
3251 The result is stored as ExtraInfo ``lowEnergyPi0Identification`` for
3255 pi0List (str): Pi0 list.
3257 gammaList (str): Gamma list. First, an energy cut E > 0.2 is applied to the photons from this list.
3258 Then, all possible combinations with a pi0 daughter photon are formed except the one
3259 corresponding to the reconstructed pi0.
3260 The maximum low-energy pi0 veto value is calculated for such photon pairs
3261 and used as one of the input variables for the identification classifier.
3263 payloadNameSuffix (str): Payload name suffix. The weight payloads are stored in the analysis global
3264 tag and have the following names:\n
3265 * ``'LowEnergyPi0Veto' + payloadNameSuffix``
3266 * ``'LowEnergyPi0Identification' + payloadNameSuffix``\n
3267 The possible suffixes are:\n
3268 * ``'Belle1'`` for Belle data.
3269 * ``'Belle2Release5'`` for Belle II release 5 data (MC14, proc12, buckets 16 - 25).
3270 * ``'Belle2Release6'`` for Belle II release 6 data (MC15, proc13, buckets 26 - 36).
3272 path (basf2.Path): Module path.
3276 cutAndCopyList(
'gamma:pi0veto', gammaList,
'E > 0.2', path=path)
3278 payload_name =
'LowEnergyPi0Veto' + payloadNameSuffix
3279 path.add_module(
'LowEnergyPi0VetoExpert', identifier=payload_name,
3280 VetoPi0Daughters=
True, GammaListName=
'gamma:pi0veto',
3282 payload_name =
'LowEnergyPi0Identification' + payloadNameSuffix
3283 path.add_module(
'LowEnergyPi0IdentificationExpert',
3284 identifier=payload_name, Pi0ListName=pi0List,
3288 def getBeamBackgroundProbability(particleList, weight, path=None):
3290 Assign a probability to each ECL cluster as being signal like (1) compared to beam background like (0)
3291 @param particleList the input ParticleList, must be a photon list
3292 @param weight type of weight file to use
3293 @param path modules are added to this path
3298 B2ERROR(
"The beam background MVA is not trained for Belle data.")
3300 path.add_module(
'MVAExpert',
3301 listNames=particleList,
3302 extraInfoName=
'beamBackgroundSuppression',
3303 identifier=f
'BeamBackgroundMVA_{weight}')
3306 def getFakePhotonProbability(particleList, weight, path=None):
3308 Assign a probability to each ECL cluster as being signal like (1) compared to fake photon like (0)
3309 @param particleList the input ParticleList, must be a photon list
3310 @param weight type of weight file to use
3311 @param path modules are added to this path
3316 B2ERROR(
"The fake photon MVA is not trained for Belle data.")
3318 path.add_module(
'MVAExpert',
3319 listNames=particleList,
3320 extraInfoName=
'fakePhotonSuppression',
3321 identifier=f
'FakePhotonMVA_{weight}')
3324 def buildEventKinematics(inputListNames=None, default_cleanup=True, custom_cuts=None,
3325 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
3327 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3328 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
3329 (all track and all hits in ECL without associated track).
3331 The visible energy missing values are
3332 stored in a EventKinematics dataobject.
3334 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3335 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
3336 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
3337 according to the PID likelihood and the option inputListNames will be ignored.
3338 @param chargedPIDPriors The prior PID fractions, that are used to regulate
3339 amount of certain charged particle species, should be a list of
3340 six floats if not None. The order of particle types is
3341 the following: [e-, mu-, pi-, K-, p+, d+]
3342 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
3343 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3344 which would result in a standard predefined selection cuts
3345 @param path modules are added to this path
3348 if inputListNames
is None:
3350 trackCuts =
'pt > 0.1'
3351 trackCuts +=
' and thetaInCDCAcceptance'
3352 trackCuts +=
' and abs(dz) < 3'
3353 trackCuts +=
' and dr < 0.5'
3355 gammaCuts =
'E > 0.05'
3356 gammaCuts +=
' and thetaInCDCAcceptance'
3358 gammaCuts +=
' and abs(clusterTiming) < 200'
3359 if (custom_cuts
is not None):
3360 trackCuts, gammaCuts = custom_cuts
3362 if fillWithMostLikely:
3363 from stdCharged
import stdMostLikely
3364 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
3365 inputListNames = [
'%s:mostlikely_evtkin' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
3367 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3369 fillParticleList(
'gamma:evtkin',
'', path=path)
3370 inputListNames += [
'gamma:evtkin']
3372 B2INFO(
"Using default cleanup in EventKinematics module.")
3373 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
3374 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
3375 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3377 B2INFO(
"No cleanup in EventKinematics module.")
3378 if not inputListNames:
3379 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
3380 fillParticleList(
'pi+:evtkin',
'', path=path)
3382 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3384 fillParticleList(
'gamma:evtkin',
'', path=path)
3385 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
3387 if (custom_cuts
is not None):
3388 B2INFO(
"Using default cleanup in EventKinematics module.")
3389 applyCuts(
'pi+:evtkin', trackCuts, path=path)
3390 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3392 B2INFO(
"No cleanup in EventKinematics module.")
3394 particleLists = inputListNames
3396 eventKinematicsModule = register_module(
'EventKinematics')
3397 eventKinematicsModule.set_name(
'EventKinematics_reco')
3398 eventKinematicsModule.param(
'particleLists', particleLists)
3399 path.add_module(eventKinematicsModule)
3402 def buildEventKinematicsFromMC(inputListNames=None, selectionCut='', path=None):
3404 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3405 using generated particles. If no ParticleList is provided, default generated ParticleLists are used.
3407 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3408 If the list is empty, default ParticleLists are filled.
3409 @param selectionCut optional selection cuts
3410 @param path Path to append the eventKinematics module to.
3413 if inputListNames
is None:
3415 if (len(inputListNames) == 0):
3419 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
3422 fillParticleListFromMC(
"%s:evtkin_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
3423 True,
True, path=path)
3424 if (selectionCut !=
''):
3425 applyCuts(
"%s:evtkin_default_gen" % t, selectionCut, path=path)
3426 inputListNames += [
"%s:evtkin_default_gen" % t]
3428 eventKinematicsModule = register_module(
'EventKinematics')
3429 eventKinematicsModule.set_name(
'EventKinematics_gen')
3430 eventKinematicsModule.param(
'particleLists', inputListNames)
3431 eventKinematicsModule.param(
'usingMC',
True)
3432 path.add_module(eventKinematicsModule)
3435 def buildEventShape(inputListNames=None,
3436 default_cleanup=True,
3442 harmonicMoments=True,
3446 checkForDuplicates=False,
3449 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
3450 using the particles in the lists provided by the user. If no particle list is provided,
3451 the function will internally create a list of good tracks and a list of good photons
3452 with (optionally) minimal quality cuts.
3455 The results of the calculation are then stored into the EventShapeContainer dataobject,
3456 and are accessible using the variables of the EventShape group.
3458 The user can switch the calculation of certain quantities on or off to save computing
3459 time. By default the calculation of the high-order moments (5-8) is turned off.
3460 Switching off an option will make the corresponding variables not available.
3463 The user can provide as many particle lists
3464 as needed, using also combined particles, but the function will always assume that
3465 the lists are independent.
3466 If the lists provided by the user contain several times the same track (either with
3467 different mass hypothesis, or once as an independent particle and once as daughter of a
3468 combined particle) the results won't be reliable.
3469 A basic check for duplicates is available setting the checkForDuplicate flags.
3472 @param inputListNames List of ParticleLists used to calculate the
3473 event shape variables. If the list is empty the default
3474 particleLists pi+:evtshape and gamma:evtshape are filled.
3475 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
3476 defining the internal lists. This option is ignored if the
3477 particleLists are provided by the user.
3478 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3479 which would result in a standard predefined selection cuts
3480 @param path Path to append the eventShape modules to.
3481 @param thrust Enables the calculation of thrust-related quantities (CLEO
3482 cones, Harmonic moments, jets).
3483 @param collisionAxis Enables the calculation of the quantities related to the
3485 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
3486 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
3487 to both the thrust axis and, if collisionAxis = True, the collision axis.
3488 @param allMoments If True, calculates also the FW and harmonic moments from order
3489 5 to 8 instead of the low-order ones only.
3490 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
3491 axis and, if collisionAxis = True, the collision axis.
3492 @param jets Enables the calculation of the hemisphere momenta and masses.
3493 Requires thrust = True.
3494 @param sphericity Enables the calculation of the sphericity-related quantities.
3495 @param checkForDuplicates Perform a check for duplicate particles before adding them. Regardless of the value of this option,
3496 it is recommended to consider sanitizing the lists you are passing to the function.
3500 if inputListNames
is None:
3502 trackCuts =
'pt > 0.1'
3503 trackCuts +=
' and thetaInCDCAcceptance'
3504 trackCuts +=
' and abs(dz) < 3.0'
3505 trackCuts +=
' and dr < 0.5'
3507 gammaCuts =
'E > 0.05'
3508 gammaCuts +=
' and thetaInCDCAcceptance'
3510 gammaCuts +=
' and abs(clusterTiming) < 200'
3511 if (custom_cuts
is not None):
3512 trackCuts, gammaCuts = custom_cuts
3514 if not inputListNames:
3515 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
3516 fillParticleList(
'pi+:evtshape',
'', path=path)
3518 copyList(
'gamma:evtshape',
'gamma:mdst', path=path)
3524 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
3527 if (custom_cuts
is not None):
3528 B2INFO(
"Applying standard cuts")
3529 applyCuts(
'pi+:evtshape', trackCuts, path=path)
3531 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
3533 B2WARNING(
"Creating the default lists with no cleanup.")
3535 particleLists = inputListNames
3537 eventShapeModule = register_module(
'EventShapeCalculator')
3538 eventShapeModule.set_name(
'EventShape')
3539 eventShapeModule.param(
'particleListNames', particleLists)
3540 eventShapeModule.param(
'enableAllMoments', allMoments)
3541 eventShapeModule.param(
'enableCleoCones', cleoCones)
3542 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
3543 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
3544 eventShapeModule.param(
'enableJets', jets)
3545 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
3546 eventShapeModule.param(
'enableSphericity', sphericity)
3547 eventShapeModule.param(
'enableThrust', thrust)
3548 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
3550 path.add_module(eventShapeModule)
3553 def labelTauPairMC(printDecayInfo=False, path=None, TauolaBelle=False, mapping_minus=None, mapping_plus=None):
3555 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
3556 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
3558 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
3559 @param path: module is added to this path
3560 @param TauolaBelle: if False, TauDecayMode is set. If True, TauDecayMarker is set.
3561 @param mapping_minus: if None, the map is the default one, else the path for the map is given by the user for tau-
3562 @param mapping_plus: if None, the map is the default one, else the path for the map is given by the user for tau+
3565 from basf2
import find_file
3571 m_printmode =
'default'
3573 if mapping_minus
is None:
3574 mp_file_minus = find_file(
'data/analysis/modules/TauDecayMode/map_tauminus.txt')
3576 mp_file_minus = mapping_minus
3578 if mapping_plus
is None:
3579 mp_file_plus = find_file(
'data/analysis/modules/TauDecayMode/map_tauplus.txt')
3581 mp_file_plus = mapping_plus
3583 path.add_module(
'TauDecayMode', printmode=m_printmode, file_minus=mp_file_minus, file_plus=mp_file_plus)
3586 tauDecayMarker = register_module(
'TauDecayMarker')
3587 tauDecayMarker.set_name(
'TauDecayMarker_')
3589 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
3592 def tagCurlTracks(particleLists,
3602 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
3604 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
3605 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
3607 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
3610 The module loops over all particles in a given list with a transverse momentum below the pre-selection **ptCut**
3611 and assigns them to bundles based on the response of the chosen **selector** and the required minimum response set by the
3612 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
3613 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
3617 @param particleLists: list of particle lists to check for curls.
3618 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
3619 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
3620 genParticleIndex then ranked and tagged as normal.
3621 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
3622 If set to ``-1`` a cut value optimised to maximise the accuracy on a BBbar sample is used.
3623 Note 'cut' selector is binary 0/1.
3624 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
3625 It is strongly recommended to used the 'mva' selection. The 'cut' selection
3626 is based on BN1079 and is only calibrated for Belle data.
3628 @param ptCut: Pre-selection cut on transverse momentum. Only tracks below that are considered as curler candidates.
3630 @param expert_train: flag to set training mode if selector has a training mode (mva).
3631 @param expert_filename: set file name of produced training ntuple (mva).
3632 @param path: module is added to this path.
3638 if (
not isinstance(particleLists, list)):
3639 particleLists = [particleLists]
3641 curlTagger = register_module(
'CurlTagger')
3642 curlTagger.set_name(
'CurlTagger_')
3643 curlTagger.param(
'particleLists', particleLists)
3644 curlTagger.param(
'belle', belle)
3645 curlTagger.param(
'mcTruth', mcTruth)
3646 curlTagger.param(
'responseCut', responseCut)
3647 if abs(responseCut + 1) < 1e-9:
3648 curlTagger.param(
'usePayloadCut',
True)
3650 curlTagger.param(
'usePayloadCut',
False)
3652 curlTagger.param(
'selectorType', selectorType)
3653 curlTagger.param(
'ptCut', ptCut)
3654 curlTagger.param(
'train', expert_train)
3655 curlTagger.param(
'trainFilename', expert_filename)
3657 path.add_module(curlTagger)
3660 def applyChargedPidMVA(particleLists, path, trainingMode, chargeIndependent=False, binaryHypoPDGCodes=(0, 0)):
3662 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
3664 The module decorates Particle objects in the input ParticleList(s) with variables
3665 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
3668 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.3.0**, **ROOT 6.20/04**).
3670 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
3672 * e (11) vs. pi (211)
3673 * mu (13) vs. pi (211)
3674 * pi (211) vs. K (321)
3675 * K (321) vs. pi (211)
3677 , or 'global' PID, namely "one-vs-others" separation. The latter exploits an MVA algorithm trained in multi-class mode,
3678 and it's the default behaviour. Currently, the multi-class training separates the following standard charged hypotheses:
3680 - e (11), mu (13), pi (211), K (321)
3683 In order to run the `ChargedPidMVA` and ensure the most up-to-date MVA training weights are applied,
3684 it is necessary to append the latest analysis global tag (GT) to the steering script.
3687 particleLists (list(str)): the input list of DecayStrings, where each selected (^) daughter should correspond to a
3688 standard charged ParticleList, e.g. ``['Lambda0:sig -> ^p+ ^pi-', 'J/psi:sig -> ^mu+ ^mu-']``.
3689 One can also directly pass a list of standard charged ParticleLists,
3690 e.g. ``['e+:my_electrons', 'pi+:my_pions']``.
3691 Note that charge-conjugated ParticleLists will automatically be included.
3692 path (basf2.Path): the module is added to this path.
3693 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
3694 Needed to pick up the correct payload from the DB. Available choices:
3696 * c_Classification=0
3698 * c_ECL_Classification=2
3699 * c_ECL_Multiclass=3
3700 * c_PSD_Classification=4
3701 * c_PSD_Multiclass=5
3702 * c_ECL_PSD_Classification=6
3703 * c_ECL_PSD_Multiclass=7
3705 chargeIndependent (bool, ``optional``): use a BDT trained on a sample of inclusively charged particles.
3706 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
3707 Required only for binary PID mode.
3712 B2ERROR(
"Charged PID via MVA is not available for Belle data.")
3714 from ROOT
import Belle2
3716 TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
3719 plSet = set(particleLists)
3723 TrainingMode.c_Classification:
3724 {
"mode":
"Classification",
"detector":
"ALL"},
3725 TrainingMode.c_Multiclass:
3726 {
"mode":
"Multiclass",
"detector":
"ALL"},
3727 TrainingMode.c_ECL_Classification:
3728 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
3729 TrainingMode.c_ECL_Multiclass:
3730 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
3731 TrainingMode.c_PSD_Classification:
3732 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
3733 TrainingMode.c_PSD_Multiclass:
3734 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
3735 TrainingMode.c_ECL_PSD_Classification:
3736 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
3737 TrainingMode.c_ECL_PSD_Multiclass:
3738 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
3741 if payloadNames.get(trainingMode)
is None:
3742 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
3743 "\nis not supported. Please choose among the following:\n",
3744 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
3746 mode = payloadNames.get(trainingMode).get(
"mode")
3747 detector = payloadNames.get(trainingMode).get(
"detector")
3749 payloadName = f
"ChargedPidMVAWeights_{mode}"
3754 Const.electron.getPDGCode():
3755 {
"pName":
"e",
"pFullName":
"electron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3756 Const.muon.getPDGCode():
3757 {
"pName":
"mu",
"pFullName":
"muon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3758 Const.pion.getPDGCode():
3759 {
"pName":
"pi",
"pFullName":
"pion",
"pNameBkg":
"K",
"pdgIdBkg": Const.kaon.getPDGCode()},
3760 Const.kaon.getPDGCode():
3761 {
"pName":
"K",
"pFullName":
"kaon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3762 Const.proton.getPDGCode():
3763 {
"pName":
"p",
"pFullName":
"proton",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3764 Const.deuteron.getPDGCode():
3765 {
"pName":
"d",
"pFullName":
"deuteron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3768 if binaryHypoPDGCodes == (0, 0):
3771 chargedpid = register_module(
"ChargedPidMVAMulticlass")
3772 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
3779 binaryOpts = [(pdgIdSig, info[
"pdgIdBkg"])
for pdgIdSig, info
in stdChargedMap.items()]
3781 if binaryHypoPDGCodes
not in binaryOpts:
3782 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
3783 ". Please choose among the following pairs:\n",
3784 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
3788 if not decayDescriptor.init(name):
3789 raise ValueError(f
"Invalid particle list {name} in applyChargedPidMVA!")
3790 msg = f
"Input ParticleList: {name}"
3791 pdgs = [abs(decayDescriptor.getMother().getPDGCode())]
3792 daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
3793 if len(daughter_pdgs) > 0:
3794 pdgs = daughter_pdgs
3795 for idaughter, pdg
in enumerate(pdgs):
3796 if abs(pdg)
not in binaryHypoPDGCodes:
3798 msg = f
"Selected daughter {idaughter} in ParticleList: {name}"
3800 f
"{msg} (PDG={pdg}) is neither signal ({binaryHypoPDGCodes[0]}) nor background ({binaryHypoPDGCodes[1]}).")
3802 chargedpid = register_module(
"ChargedPidMVA")
3803 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
3804 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
3805 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
3807 chargedpid.param(
"particleLists", list(plSet))
3808 chargedpid.param(
"payloadName", payloadName)
3809 chargedpid.param(
"chargeIndependent", chargeIndependent)
3812 if detector ==
"ECL":
3813 chargedpid.param(
"useECLOnlyTraining",
True)
3815 path.add_module(chargedpid)
3818 def calculateTrackIsolation(
3822 reference_list_name=None,
3823 vars_for_nearest_part=[],
3824 highest_prob_mass_for_ext=True,
3825 exclude_pid_det_weights=False):
3827 Given an input decay string, compute variables that quantify track helix-based isolation of the charged
3828 stable particles in the input decay chain.
3831 An "isolation score" can be defined using the distance
3832 of each particle to its closest neighbour, defined as the segment connecting the two
3833 extrapolated track helices intersection points on a given cylindrical surface.
3834 The distance variables defined in the `VariableManager` is named `minET2ETDist`,
3835 the isolation scores are named `minET2ETIsoScore`, `minET2ETIsoScoreAsWeightedAvg`.
3837 The definition of distance and the number of distances that are calculated per sub-detector is based on
3838 the following recipe:
3840 * **CDC**: as the segmentation is very coarse along :math:`z`,
3841 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
3842 A total of 9 distances are calculated: the cylindrical surfaces are defined at radiuses
3843 that correspond to the positions of the 9 CDC wire superlayers: :math:`R_{i}^{\\mathrm{CDC}}~(i \\in \\{0,...,8\\})`.
3845 * **TOP**: as there is no segmentation along :math:`z`,
3846 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
3847 Only one distance at the TOP entry radius :math:`R_{0}^{\\mathrm{TOP}}` is calculated.
3849 * **ARICH**: as there is no segmentation along :math:`z`,
3850 the distance is defined as the distance on the :math:`(\\rho=R, \\phi)` plane at fixed :math:`z=Z`.
3851 Only one distance at the ARICH photon detector entry coordinate :math:`Z_{0}^{\\mathrm{ARICH}}` is calculated.
3853 * **ECL**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
3854 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
3855 Two distances are calculated: one at the ECL entry surface :math:`R_{0}^{\\mathrm{ECL}}` (barrel),
3856 :math:`Z_{0}^{\\mathrm{ECL}}` (endcaps), and one at :math:`R_{1}^{\\mathrm{ECL}}` (barrel),
3857 :math:`Z_{1}^{\\mathrm{ECL}}` (endcaps), corresponding roughly to the mid-point
3858 of the longitudinal size of the crystals.
3860 * **KLM**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
3861 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
3862 Only one distance at the KLM first strip entry surface :math:`R_{0}^{\\mathrm{KLM}}` (barrel),
3863 :math:`Z_{0}^{\\mathrm{KLM}}` (endcaps) is calculated.
3866 decay_string (str): name of the input decay string with selected charged stable daughters,
3867 for example: ``Lambda0:merged -> ^p+ ^pi-``.
3868 Alternatively, it can be a particle list for charged stable particles
3869 as defined in ``Const::chargedStableSet``, for example: ``mu+:all``.
3870 The charge-conjugate particle list will be also processed automatically.
3871 path (basf2.Path): path to which module(s) will be added.
3872 *detectors: detectors for which track isolation variables will be calculated.
3873 Choose among: ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
3874 reference_list_name (Optional[str]): name of the input charged stable particle list for the reference tracks.
3875 By default, the ``:all`` ParticleList of the same type
3876 of the selected particle in ``decay_string`` is used.
3877 The charge-conjugate particle list will be also processed automatically.
3878 vars_for_nearest_part (Optional[list(str)]): a list of variables to calculate for the nearest particle in the reference
3879 list at each detector surface. It uses the metavariable `minET2ETDistVar`.
3880 If unset, only the distances to the nearest neighbour
3881 per detector are calculated.
3882 highest_prob_mass_for_hex (Optional[bool]): if this option is set to True (default), the helix extrapolation
3883 for the particles will use the track fit result for the most
3884 probable mass hypothesis, namely, the one that gives the highest
3885 chi2Prob of the fit. Otherwise, it uses the mass hypothesis that
3886 corresponds to the particle lists PDG.
3887 exclude_pid_det_weights (Optional[bool]): if this option is set to False (default), the isolation score
3888 calculation will take into account the weight that each detector has on the PID
3889 for the particle species of interest.
3892 dict(int, list(str)): a dictionary mapping the PDG of each reference particle list to its isolation variables.
3897 from ROOT
import Belle2, TDatabasePDG
3900 if not decayDescriptor.init(decay_string):
3901 B2FATAL(f
"Invalid particle list {decay_string} in calculateTrackIsolation!")
3902 no_reference_list_name =
not reference_list_name
3905 "CDC": list(range(9)),
3911 if any(d
not in det_and_layers
for d
in detectors):
3913 "Your input detector list: ",
3915 " contains an invalid choice. Please select among: ",
3917 det_and_layers.keys()))
3922 processed_decay_strings = []
3923 if select_symbol
in decay_string:
3924 splitted_ds = decay_string.split(select_symbol)
3925 for i
in range(decay_string.count(select_symbol)):
3926 tmp = list(splitted_ds)
3927 tmp.insert(i+1, select_symbol)
3928 processed_decay_strings += [
''.join(tmp)]
3930 processed_decay_strings += [decay_string]
3932 reference_lists_to_vars = {}
3934 for processed_dec
in processed_decay_strings:
3935 if no_reference_list_name:
3936 decayDescriptor.init(processed_dec)
3937 selected_daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
3938 if len(selected_daughter_pdgs) > 0:
3939 reference_list_name = f
'{TDatabasePDG.Instance().GetParticle(abs(selected_daughter_pdgs[-1])).GetName()}:all'
3941 reference_list_name = f
'{processed_dec.split(":")[0]}:all'
3945 trackiso = path.add_module(
"TrackIsoCalculator",
3946 decayString=processed_dec,
3947 detectorNames=list(detectors),
3948 particleListReference=reference_list_name,
3949 useHighestProbMassForExt=highest_prob_mass_for_ext,
3950 excludePIDDetWeights=exclude_pid_det_weights)
3951 trackiso.set_name(f
"TrackIsoCalculator_{'_'.join(detectors)}_{processed_dec}_VS_{reference_list_name}")
3957 f
"minET2ETDist({d}, {d_layer}, {reference_list_name}, {int(highest_prob_mass_for_ext)})"
3958 for d
in detectors
for d_layer
in det_and_layers[d]]
3961 f
"minET2ETIsoScore({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
3962 f
"minET2ETIsoScoreAsWeightedAvg({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
3965 if vars_for_nearest_part:
3966 trackiso_vars.extend(
3968 f
"minET2ETDistVar({d}, {d_layer}, {reference_list_name}, {v})"
3969 for d
in detectors
for d_layer
in det_and_layers[d]
for v
in vars_for_nearest_part
3971 trackiso_vars.sort()
3973 reference_lists_to_vars[ref_pdg] = trackiso_vars
3975 return reference_lists_to_vars
3978 def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
3980 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
3981 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
3982 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
3983 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
3986 .. code-block:: python
3988 from modularAnalysis import calculateDistance
3989 calculateDistance('list_name', 'decay_string', "mode", path=user_path)
3991 @param list_name name of the input ParticleList
3992 @param decay_string select particles between the distance of closest approach will be calculated
3993 @param mode Specifies how the distance is calculated
3994 vertextrack: calculate the distance of closest approach between a track and a\
3995 vertex, taking the first candidate as vertex, default
3996 trackvertex: calculate the distance of closest approach between a track and a\
3997 vertex, taking the first candidate as track
3998 2tracks: calculates the distance of closest approach between two tracks
3999 2vertices: calculates the distance between two vertices
4000 vertexbtube: calculates the distance of closest approach between a vertex and btube
4001 trackbtube: calculates the distance of closest approach between a track and btube
4002 @param path modules are added to this path
4006 dist_mod = register_module(
'DistanceCalculator')
4008 dist_mod.set_name(
'DistanceCalculator_' + list_name)
4009 dist_mod.param(
'listName', list_name)
4010 dist_mod.param(
'decayString', decay_string)
4011 dist_mod.param(
'mode', mode)
4012 path.add_module(dist_mod)
4015 def addInclusiveDstarReconstruction(decayString, slowPionCut, DstarCut, path):
4017 Adds the InclusiveDstarReconstruction module to the given path.
4018 This module creates a D* particle list by estimating the D* four momenta
4019 from slow pions, specified by a given cut. The D* energy is approximated
4020 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
4021 momentum is calculated using the D* PDG mass and the direction is collinear
4022 to the slow pion direction. The charge of the given pion list has to be consistent
4025 @param decayString Decay string, must be of form ``D* -> pi``
4026 @param slowPionCut Cut applied to the input pion list to identify slow pions
4027 @param DstarCut Cut applied to the output D* list
4028 @param path the module is added to this path
4031 incl_dstar = register_module(
"InclusiveDstarReconstruction")
4032 incl_dstar.param(
"decayString", decayString)
4033 incl_dstar.param(
"slowPionCut", slowPionCut)
4034 incl_dstar.param(
"DstarCut", DstarCut)
4035 path.add_module(incl_dstar)
4038 def scaleError(outputListName, inputListName,
4039 scaleFactors=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4040 scaleFactorsNoPXD=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4041 d0Resolution=[0.00115328, 0.00134704],
4042 z0Resolution=[0.00124327, 0.0013272],
4047 This module creates a new charged particle list.
4048 The helix errors of the new particles are scaled by constant factors.
4049 Two sets of five scale factors are defined for tracks with and without a PXD hit.
4050 The scale factors are in order of (d0, phi0, omega, z0, tanlambda).
4051 For tracks with a PXD hit, in order to avoid severe underestimation of d0 and z0 errors,
4052 lower limits (best resolution) can be set in a momentum-dependent form.
4053 This module is supposed to be used only for TDCPV analysis and for low-momentum (0-3 GeV/c) tracks in BBbar events.
4054 Details will be documented in a Belle II note, BELLE2-NOTE-PH-2021-038.
4056 @param inputListName Name of input charged particle list to be scaled
4057 @param outputListName Name of output charged particle list with scaled error
4058 @param scaleFactors List of five constants to be multiplied to each of helix errors (for tracks with a PXD hit)
4059 @param scaleFactorsNoPXD List of five constants to be multiplied to each of helix errors (for tracks without a PXD hit)
4060 @param d0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4061 defining d0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**1.5))**2 }
4062 @param z0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4063 defining z0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**2.5))**2 }
4064 @param d0MomThr d0 best resolution is kept constant below this momentum
4065 @param z0MomThr z0 best resolution is kept constant below this momentum
4069 scale_error = register_module(
"HelixErrorScaler")
4070 scale_error.set_name(
'ScaleError_' + inputListName)
4071 scale_error.param(
'inputListName', inputListName)
4072 scale_error.param(
'outputListName', outputListName)
4073 scale_error.param(
'scaleFactors_PXD', scaleFactors)
4074 scale_error.param(
'scaleFactors_noPXD', scaleFactorsNoPXD)
4075 scale_error.param(
'd0ResolutionParameters', d0Resolution)
4076 scale_error.param(
'z0ResolutionParameters', z0Resolution)
4077 scale_error.param(
'd0MomentumThreshold', d0MomThr)
4078 scale_error.param(
'z0MomentumThreshold', z0MomThr)
4079 path.add_module(scale_error)
4082 def estimateAndAttachTrackFitResult(inputListName, path=None):
4084 Create a TrackFitResult from the momentum of the Particle assuming it originates from the IP and make a relation between them.
4085 The covariance, detector hit information, and fit-related information (pValue, NDF) are assigned meaningless values. The input
4086 Particles must not have already Track or TrackFitResult and thus are supposed to be composite particles, recoil, dummy
4087 particles, and so on.
4090 .. warning:: Since the source type is not overwritten as Track, not all track-related variables are guaranteed to be available.
4093 @param inputListName Name of input ParticleList
4096 estimator = register_module(
"TrackFitResultEstimator")
4097 estimator.set_name(
"trackFitResultEstimator_" + inputListName)
4098 estimator.param(
"inputListName", inputListName)
4099 path.add_module(estimator)
4102 def correctEnergyBias(inputListNames, tableName, path=None):
4104 Scale energy of the particles according to the scaling factor.
4105 If the particle list contains composite particles, the energy of the daughters are scaled.
4106 Subsequently, the energy of the mother particle is updated as well.
4109 inputListNames (list(str)): input particle list names
4110 tableName : stored in localdb and created using ParticleWeightingLookUpCreator
4111 path (basf2.Path): module is added to this path
4116 B2ERROR(
"The energy bias cannot be corrected with this tool for Belle data.")
4118 correctenergybias = register_module(
'EnergyBiasCorrection')
4119 correctenergybias.param(
'particleLists', inputListNames)
4120 correctenergybias.param(
'tableName', tableName)
4121 path.add_module(correctenergybias)
4124 def addPhotonEfficiencyRatioVariables(inputListNames, tableName, path=None):
4126 Add photon Data/MC detection efficiency ratio weights to the specified particle list
4129 inputListNames (list(str)): input particle list names
4130 tableName : taken from database with appropriate name
4131 path (basf2.Path): module is added to this path
4136 B2ERROR(
"For Belle data the photon data/MC detection efficiency ratio is not available with this tool.")
4138 photon_efficiency_correction = register_module(
'PhotonEfficiencySystematics')
4139 photon_efficiency_correction.param(
'particleLists', inputListNames)
4140 photon_efficiency_correction.param(
'tableName', tableName)
4141 path.add_module(photon_efficiency_correction)
4144 def addPi0VetoEfficiencySystematics(particleList, decayString, tableName, threshold, mode='standard', suffix='', path=None):
4146 Add pi0 veto Data/MC efficiency ratio weights to the specified particle list
4148 @param particleList the input ParticleList
4149 @param decayString specify hard photon to be performed pi0 veto (e.g. 'B+:sig -> rho+:sig ^gamma:hard')
4150 @param tableName table name corresponding to payload version (e.g. 'Pi0VetoEfficiencySystematics_Mar2022')
4151 @param threshold pi0 veto threshold (0.10, 0.11, ..., 0.99)
4152 @param mode choose one mode (same as writePi0EtaVeto) out of 'standard', 'tight', 'cluster' and 'both'
4153 @param suffix optional suffix to be appended to the usual extraInfo name
4154 @param path the module is added to this path
4156 The following extraInfo are available related with the given particleList:
4158 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_ratio : weight of Data/MC for the veto efficiency
4159 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_stat : the statistical uncertainty of the weight
4160 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_sys : the systematic uncertainty of the weight
4161 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_total : the total uncertainty of the weight
4162 * Pi0VetoEfficiencySystematics_{mode}{suffix}_threshold : threshold of the pi0 veto
4167 B2ERROR(
"For Belle data the pi0 veto data/MC efficiency ratio weights are not available via this tool.")
4169 pi0veto_efficiency_correction = register_module(
'Pi0VetoEfficiencySystematics')
4170 pi0veto_efficiency_correction.param(
'particleLists', particleList)
4171 pi0veto_efficiency_correction.param(
'decayString', decayString)
4172 pi0veto_efficiency_correction.param(
'tableName', tableName)
4173 pi0veto_efficiency_correction.param(
'threshold', threshold)
4174 pi0veto_efficiency_correction.param(
'mode', mode)
4175 pi0veto_efficiency_correction.param(
'suffix', suffix)
4176 path.add_module(pi0veto_efficiency_correction)
4179 def getAnalysisGlobaltag(timeout=180) -> str:
4181 Returns a string containing the name of the latest and recommended analysis globaltag.
4184 timeout: Seconds to wait for b2conditionsdb-recommend
4189 B2ERROR(
"The getAnalysisGlobaltag() function cannot be used for Belle data.")
4194 tags = subprocess.check_output(
4195 [
'b2conditionsdb-recommend',
'--oneline'],
4197 ).decode(
'UTF-8').rstrip().split(
' ')
4200 if tag.startswith(
'analysis_tools'):
4204 except subprocess.TimeoutExpired
as te:
4205 B2FATAL(f
'A {te} exception was raised during the call of getAnalysisGlobaltag(). '
4206 'The function took too much time to retrieve the requested information '
4207 'from the versioning repository.\n'
4208 'Please try to re-run your job. In case of persistent failures, there may '
4209 'be issues with the DESY collaborative services, so please contact the experts.')
4210 except subprocess.CalledProcessError
as ce:
4211 B2FATAL(f
'A {ce} exception was raised during the call of getAnalysisGlobaltag(). '
4212 'Please try to re-run your job. In case of persistent failures, please contact '
4216 def getAnalysisGlobaltagB2BII() -> str:
4218 Get recommended global tag for B2BII analysis.
4223 B2ERROR(
'The getAnalysisGlobaltagB2BII() function cannot be used for Belle II data.')
4224 from versioning
import recommended_b2bii_analysis_global_tag
4225 return recommended_b2bii_analysis_global_tag()
4228 def getNbarIDMVA(particleList, path=None):
4230 This function can give a score to predict if it is a anti-n0.
4231 It is not used to predict n0.
4232 Currently, this can be used only for ECL cluster.
4233 output will be stored in extraInfo(nbarID); -1 means MVA invalid
4235 @param particleList The input ParticleList
4236 @param path modules are added to this path
4241 B2ERROR(
"The MVA-based anti-neutron PID is only available for Belle II data.")
4243 from variables
import variables
4244 variables.addAlias(
'V1',
'clusterHasPulseShapeDiscrimination')
4245 variables.addAlias(
'V2',
'clusterE')
4246 variables.addAlias(
'V3',
'clusterLAT')
4247 variables.addAlias(
'V4',
'clusterE1E9')
4248 variables.addAlias(
'V5',
'clusterE9E21')
4249 variables.addAlias(
'V6',
'clusterZernikeMVA')
4250 variables.addAlias(
'V7',
'clusterAbsZernikeMoment40')
4251 variables.addAlias(
'V8',
'clusterAbsZernikeMoment51')
4253 variables.addAlias(
'nbarIDValid',
4254 'passesCut(V1 == 1 and V2 >= 0 and V3 >= 0 and V4 >= 0 and V5 >= 0 and V6 >= 0 and V7 >= 0 and V8 >= 0)')
4255 variables.addAlias(
'nbarIDmod',
'conditionalVariableSelector(nbarIDValid == 1, extraInfo(nbarIDFromMVA), constant(-1.0))')
4257 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'nbarIDFromMVA', identifier=
'db_nbarIDECL')
4261 def reconstructDecayWithNeutralHadron(decayString, cut, allowGamma=False, allowAnyParticleSource=False, path=None, **kwargs):
4263 Reconstructs decay with a long-lived neutral hadron e.g.
4264 :math:`B^0 \to J/\psi K_L^0`,
4265 :math:`B^0 \to p \bar{n} D^*(2010)^-`.
4267 The calculation is done with IP constraint and mother mass constraint.
4269 The decay string passed in must satisfy the following rules:
4271 - The neutral hadron must be **selected** in the decay string with the
4272 caret (``^``) e.g. ``B0:sig -> J/psi:sig ^K_L0:sig``. (Note the caret
4273 next to the neutral hadron.)
4274 - There can only be **one neutral hadron in a decay**.
4275 - The neutral hadron has to be a direct daughter of its mother.
4277 .. note:: This function forwards its arguments to `reconstructDecay`,
4278 so please check the documentation of `reconstructDecay` for all
4281 @param decayString A decay string following the mentioned rules
4282 @param cut Cut to apply to the particle list
4283 @param allowGamma Whether allow the selected particle to be ``gamma``
4284 @param allowAnyParticleSource Whether allow the selected particle to be from any source.
4285 Should only be used when studying control sample.
4286 @param path The path to put in the module
4289 reconstructDecay(decayString, cut, path=path, **kwargs)
4290 module = register_module(
'NeutralHadron4MomentumCalculator')
4291 module.set_name(
'NeutralHadron4MomentumCalculator_' + decayString)
4292 module.param(
'decayString', decayString)
4293 module.param(
'allowGamma', allowGamma)
4294 module.param(
'allowAnyParticleSource', allowAnyParticleSource)
4295 path.add_module(module)
4298 func_requiring_analysisGT = [
4299 scaleTrackMomenta, smearTrackMomenta, oldwritePi0EtaVeto, writePi0EtaVeto, lowEnergyPi0Identification,
4300 getBeamBackgroundProbability, getFakePhotonProbability, tagCurlTracks, applyChargedPidMVA, correctEnergyBias,
4301 addPhotonEfficiencyRatioVariables, addPi0VetoEfficiencySystematics, getNbarIDMVA]
4302 for _
in func_requiring_analysisGT:
4303 _.__doc__ +=
"\n .. note:: This function (optionally) requires a payload stored in the analysis GlobalTag. "\
4304 "Please append or prepend the latest one from `getAnalysisGlobaltag` or `getAnalysisGlobaltagB2BII`.\n"
4307 if __name__ ==
'__main__':
4309 pretty_print_module(__name__,
"modularAnalysis")
tuple parse(str cut, verbose=False)
This class provides a set of constants for the framework.
The DecayDescriptor stores information about a decay tree or parts of a decay tree.
Describe one component of the Geometry.
static DBStore & Instance()
Instance of a singleton DBStore.
def add_mdst_output(path, mc=True, filename='mdst.root', additionalBranches=[], dataDescription=None)
def add_udst_output(path, filename, particleLists=None, additionalBranches=None, dataDescription=None, mc=True)