12This module defines wrapper functions around the analysis modules.
16from basf2
import register_module, create_path
17from basf2
import B2INFO, B2WARNING, B2ERROR, B2FATAL
22def 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))
59def 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':
80We have simplified the arguments to inputMdst! If you are running on Belle II
81data 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":
89We have reordered the arguments to inputMdst! If you are running on Belle 1
90data 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':
136We have simplified the arguments to inputMdstList! If you are running on
137Belle 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":
145We have reordered the arguments to inputMdstList! If you are running on
146Belle 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/"]
183def 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.
198def 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)
217def 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)
264def 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://xwiki.desy.de/xwiki/rest/p/59192
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)
283def 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)
311def 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)
323def 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
334 ╰── Upsilon(4S) (300553)
336 │ ├── anti-D_0*0 (-10421)
339 │ │ │ │ ├── anti-K0 (-311)
340 │ │ │ │ │ ╰── K_S0 (310)
341 │ │ │ │ │ ├── pi+ (211)
342 │ │ │ │ │ │ ╰╶╶ p+ (2212)
343 │ │ │ │ │ ╰── pi- (-211)
344 │ │ │ │ │ ├╶╶ e- (11)
345 │ │ │ │ │ ├╶╶ n0 (2112)
346 │ │ │ │ │ ├╶╶ n0 (2112)
347 │ │ │ │ │ ╰╶╶ n0 (2112)
348 │ │ │ │ ╰── pi- (-211)
349 │ │ │ │ ├╶╶ anti-nu_mu (-14)
351 │ │ │ │ ├╶╶ nu_mu (14)
352 │ │ │ │ ├╶╶ anti-nu_e (-12)
356 │ │ │ │ ├── gamma (22)
357 │ │ │ │ ╰── gamma (22)
363 │ │ ├╶╶ anti-nu_mu (-14)
371 There's a distinction between primary and secondary particles. Primary
372 particles are the ones created by the physics generator while secondary
373 particles are ones generated by the simulation of the detector interaction.
375 Secondaries are indicated with a dashed line leading to the particle name
376 and if the output is to the terminal they will be printed in red. If
377 ``onlyPrimaries`` is True they will not be included in the tree.
379 On demand, extra information on all the particles can be displayed by
380 enabling any of the ``showProperties``, ``showMomenta``, ``showVertices``
381 and ``showStatus`` flags. Enabling all of them will look like
386 │ mass=0.14 energy=0.445 charge=-1 lifetime=6.36
387 │ p=(0.257, -0.335, 0.0238) |p|=0.423
388 │ production vertex=(0.113, -0.0531, 0.0156), time=0.00589
389 │ status flags=PrimaryParticle, StableInGenerator, StoppedInDetector
393 mass=0.94 energy=0.94 charge=0 lifetime=5.28e+03
394 p=(-0.000238, -0.0127, 0.0116) |p|=0.0172
395 production vertex=(144, 21.9, -1.29), time=39
396 status flags=StoppedInDetector
397 creation process=HadronInelastic
400 The first line of extra information is enabled by ``showProperties``, the
401 second line by ``showMomenta``, the third line by ``showVertices`` and the
402 last two lines by ``showStatus``. Note that all values are given in Belle II
403 standard units, that is GeV, centimeter and nanoseconds.
405 The depth of the tree can be limited with the ``maxLevel`` argument: If it's
406 bigger than zero it will limit the tree to the given number of generations.
407 A visual indicator will be added after each particle which would have
408 additional daughters that are skipped due to this limit. An example event
409 with ``maxLevel=3`` is given below. In this case only the tau neutrino and
410 the pion don't have additional daughters. ::
412 [INFO] Content of MCParticle list
415 ╰── Upsilon(4S) (300553)
417 │ ├── anti-D*0 (-423) → …
426 The same information will be stored in the branch ``__MCDecayString__`` of
427 TTree created by `VariablesToNtuple` or `VariablesToEventBasedTree` module.
428 This branch is automatically created when `PrintMCParticles` modules is called.
429 Printing the information on the log message can be suppressed if ``suppressPrint``
430 is True, while the branch ``__MCDecayString__``. This option helps to reduce the
431 size of the log message.
434 onlyPrimaries (bool): If True show only primary particles, that is particles coming from
435 the generator and not created by the simulation.
436 maxLevel (int): If 0 or less print the whole tree, otherwise stop after n generations
437 showProperties (bool): If True show mass, energy and charge of the particles
438 showMomenta (bool): if True show the momenta of the particles
439 showVertices (bool): if True show production vertex and production time of all particles
440 showStatus (bool): if True show some status information on the particles.
441 For secondary particles this includes creation process.
442 suppressPrint (bool): if True printing the information on the log message is suppressed.
443 Even if True, the branch ``__MCDecayString__`` is created.
446 return path.add_module(
448 onlyPrimaries=onlyPrimaries,
450 showProperties=showProperties,
451 showMomenta=showMomenta,
452 showVertices=showVertices,
453 showStatus=showStatus,
454 suppressPrint=suppressPrint,
458def correctBrems(outputList,
461 maximumAcceptance=3.0,
462 multiplePhotons=False,
463 usePhotonOnlyOnce=True,
467 For each particle in the given ``inputList``, copies it to the ``outputList`` and adds the
468 4-vector of the photon(s) in the ``gammaList`` which has(have) a weighted named relation to
469 the particle's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
472 This can only work if the mdst file contains the *Bremsstrahlung* named relation. Official MC samples
473 up to and including MC12 and proc9 **do not** contain this. Newer production campaigns (from proc10 and MC13) do.
474 However, studies by the tau WG revealed that the cuts applied by the ``ECLTrackBremFinder`` module are too tight.
475 These will be loosened but this will only have effect with proc13 and MC15.
476 If your analysis is very sensitive to the Bremsstrahlung corrections, it is advised to use `correctBremsBelle`.
479 A detailed description of how the weights are set can be found directly at the documentation of the
480 `BremsFinder` module.
482 Please note that a new particle is always generated, with the old particle and -if found- one or more
483 photons as daughters.
485 The ``inputList`` should contain particles with associated tracks. Otherwise, the module will exit with an error.
487 The ``gammaList`` should contain photons. Otherwise, the module will exit with an error.
489 @param outputList The output particle list name containing the corrected particles
490 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
491 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
492 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
493 @param multiplePhotons Whether to use only one photon (the one with the smallest acceptance) or as many as possible
494 @param usePhotonOnlyOnce If true, each brems candidate is used to correct only the track with the smallest relation weight
495 @param writeOut Whether `RootOutput` module should save the created ``outputList``
496 @param path The module is added to this path
501 B2ERROR(
"The BremsFinder can only be run over Belle II data.")
503 bremscorrector = register_module(
'BremsFinder')
504 bremscorrector.set_name(
'bremsCorrector_' + outputList)
505 bremscorrector.param(
'inputList', inputList)
506 bremscorrector.param(
'outputList', outputList)
507 bremscorrector.param(
'gammaList', gammaList)
508 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
509 bremscorrector.param(
'multiplePhotons', multiplePhotons)
510 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
511 bremscorrector.param(
'writeOut', writeOut)
512 path.add_module(bremscorrector)
515def copyList(outputListName, inputListName, writeOut=False, path=None):
517 Copy all Particle indices from input ParticleList to the output ParticleList.
518 Note that the Particles themselves are not copied. The original and copied
519 ParticleLists will point to the same Particles.
521 @param ouputListName copied ParticleList
522 @param inputListName original ParticleList to be copied
523 @param writeOut whether RootOutput module should save the created ParticleList
524 @param path modules are added to this path
527 copyLists(outputListName, [inputListName], writeOut, path)
530def correctBremsBelle(outputListName,
533 multiplePhotons=True,
535 usePhotonOnlyOnce=False,
539 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
540 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
544 Studies by the tau WG show that using a rather wide opening angle (up to
545 0.2 rad) and rather low energetic photons results in good correction.
546 However, this should only serve as a starting point for your own studies
547 because the optimal criteria are likely mode-dependent
550 outputListName (str): The output charged particle list containing the corrected charged particles
551 inputListName (str): The initial charged particle list containing the charged particles to correct.
552 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
553 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one -> False,
554 add all the photons within the cone -> True
555 angleThreshold (float): The maximum angle in radians between the charged particle and the (radiative)
556 gamma to be accepted.
557 writeOut (bool): whether RootOutput module should save the created ParticleList
558 usePhotonOnlyOnce (bool): If true, a photon is used for correction of the closest charged particle in the inputList.
559 If false, a photon is allowed to be used for correction multiple times (Default).
562 One cannot use a photon twice to reconstruct a composite particle. Thus, for example, if ``e+`` and ``e-`` are corrected
563 with a ``gamma``, the pair of ``e+`` and ``e-`` cannot form a ``J/psi -> e+ e-`` candidate.
565 path (basf2.Path): modules are added to this path
568 fsrcorrector = register_module(
'BelleBremRecovery')
569 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
570 fsrcorrector.param(
'inputListName', inputListName)
571 fsrcorrector.param(
'outputListName', outputListName)
572 fsrcorrector.param(
'gammaListName', gammaListName)
573 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
574 fsrcorrector.param(
'angleThreshold', angleThreshold)
575 fsrcorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
576 fsrcorrector.param(
'writeOut', writeOut)
577 path.add_module(fsrcorrector)
580def copyLists(outputListName, inputListNames, writeOut=False, path=None):
582 Copy all Particle indices from all input ParticleLists to the
583 single output ParticleList.
584 Note that the Particles themselves are not copied.
585 The original and copied ParticleLists will point to the same Particles.
587 Duplicates are removed based on the first-come, first-served principle.
588 Therefore, the order of the input ParticleLists matters.
591 If you want to select the best duplicate based on another criterion, have
592 a look at the function `mergeListsWithBestDuplicate`.
595 Two particles that differ only by the order of their daughters are
596 considered duplicates and one of them will be removed.
598 @param ouputListName copied ParticleList
599 @param inputListName vector of original ParticleLists to be copied
600 @param writeOut whether RootOutput module should save the created ParticleList
601 @param path modules are added to this path
604 pmanipulate = register_module(
'ParticleListManipulator')
605 pmanipulate.set_name(
'PListCopy_' + outputListName)
606 pmanipulate.param(
'outputListName', outputListName)
607 pmanipulate.param(
'inputListNames', inputListNames)
608 pmanipulate.param(
'writeOut', writeOut)
609 path.add_module(pmanipulate)
612def copyParticles(outputListName, inputListName, writeOut=False, path=None):
614 Create copies of Particles given in the input ParticleList and add them to the output ParticleList.
616 The existing relations of the original Particle (or it's (grand-)^n-daughters)
617 are copied as well. Note that only the relation is copied and that the related
618 object is not. Copied particles are therefore related to the *same* object as
621 @param ouputListName new ParticleList filled with copied Particles
622 @param inputListName input ParticleList with original Particles
623 @param writeOut whether RootOutput module should save the created ParticleList
624 @param path modules are added to this path
628 pmanipulate = register_module(
'ParticleListManipulator')
629 pmanipulate.set_name(
'PListCopy_' + outputListName)
630 pmanipulate.param(
'outputListName', outputListName)
631 pmanipulate.param(
'inputListNames', [inputListName])
632 pmanipulate.param(
'writeOut', writeOut)
633 path.add_module(pmanipulate)
636 pcopy = register_module(
'ParticleCopier')
637 pcopy.param(
'inputListNames', [outputListName])
638 path.add_module(pcopy)
641def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
643 Copy candidates from all lists in ``inputListNames`` to
644 ``outputListName`` if they pass ``cut`` (given selection criteria).
647 Note that the Particles themselves are not copied.
648 The original and copied ParticleLists will point to the same Particles.
651 Require energetic pions safely inside the cdc
653 .. code-block:: python
655 cutAndCopyLists("pi+:energeticPions", ["pi+:good", "pi+:loose"], "[E > 2] and thetaInCDCAcceptance", path=mypath)
658 You must use square braces ``[`` and ``]`` for conditional statements.
661 outputListName (str): the new ParticleList name
662 inputListName (list(str)): list of input ParticleList names
663 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
664 writeOut (bool): whether RootOutput module should save the created ParticleList
665 path (basf2.Path): modules are added to this path
668 pmanipulate = register_module(
'ParticleListManipulator')
669 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
670 pmanipulate.param(
'outputListName', outputListName)
671 pmanipulate.param(
'inputListNames', inputListNames)
672 pmanipulate.param(
'cut', cut)
673 pmanipulate.param(
'writeOut', writeOut)
674 path.add_module(pmanipulate)
677def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
679 Copy candidates from ``inputListName`` to ``outputListName`` if they pass
680 ``cut`` (given selection criteria).
683 Note the Particles themselves are not copied.
684 The original and copied ParticleLists will point to the same Particles.
687 require energetic pions safely inside the cdc
689 .. code-block:: python
691 cutAndCopyList("pi+:energeticPions", "pi+:loose", "[E > 2] and thetaInCDCAcceptance", path=mypath)
694 You must use square braces ``[`` and ``]`` for conditional statements.
697 outputListName (str): the new ParticleList name
698 inputListName (str): input ParticleList name
699 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
700 writeOut (bool): whether RootOutput module should save the created ParticleList
701 path (basf2.Path): modules are added to this path
704 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
707def removeTracksForTrackingEfficiencyCalculation(inputListNames, fraction, path=None):
709 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
710 Takes care of the duplicates, if any.
713 inputListNames (list(str)): input particle list names
714 fraction (float): fraction of particles to be removed randomly
715 path (basf2.Path): module is added to this path
718 trackingefficiency = register_module(
'TrackingEfficiency')
719 trackingefficiency.param(
'particleLists', inputListNames)
720 trackingefficiency.param(
'frac', fraction)
721 path.add_module(trackingefficiency)
724def scaleTrackMomenta(inputListNames, scale=float(
'nan'), payloadName=
"", scalingFactorName=
"SF", path=
None):
726 Scale momenta of the particles according to a scaling factor scale.
727 This scaling factor can either be given as constant number or as the name of the payload which contains
728 the variable scale factors.
729 If the particle list contains composite particles, the momenta of the track-based daughters are scaled.
730 Subsequently, the momentum of the mother particle is updated as well.
733 inputListNames (list(str)): input particle list names
734 scale (float): scaling factor (1.0 -- no scaling)
735 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
736 scalingFactorName (str): name of scaling factor variable in the payload.
737 path (basf2.Path): module is added to this path
742 B2ERROR(
"The tracking momentum scaler can only be run over Belle II data.")
744 TrackingMomentumScaleFactors = register_module(
'TrackingMomentumScaleFactors')
745 TrackingMomentumScaleFactors.param(
'particleLists', inputListNames)
746 TrackingMomentumScaleFactors.param(
'scale', scale)
747 TrackingMomentumScaleFactors.param(
'payloadName', payloadName)
748 TrackingMomentumScaleFactors.param(
'scalingFactorName', scalingFactorName)
750 path.add_module(TrackingMomentumScaleFactors)
753def correctTrackEnergy(inputListNames, correction=float(
'nan'), payloadName=
"", correctionName=
"SF", path=
None):
755 Correct the energy loss of tracks according to a 'correction' value.
756 This correction can either be given as constant number or as the name of the payload which contains
757 the variable corrections.
758 If the particle list contains composite particles, the momenta of the track-based daughters are corrected.
759 Subsequently, the momentum of the mother particle is updated as well.
762 inputListNames (list(str)): input particle list names
763 correction (float): correction value to be subtracted to the particle energy (0.0 -- no correction)
764 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
765 correctionName (str): name of correction variable in the payload.
766 path (basf2.Path): module is added to this path
771 B2ERROR(
"The tracking energy correction can only be run over Belle II data.")
773 TrackingEnergyLossCorrection = register_module(
'TrackingEnergyLossCorrection')
774 TrackingEnergyLossCorrection.param(
'particleLists', inputListNames)
775 TrackingEnergyLossCorrection.param(
'correction', correction)
776 TrackingEnergyLossCorrection.param(
'payloadName', payloadName)
777 TrackingEnergyLossCorrection.param(
'correctionName', correctionName)
779 path.add_module(TrackingEnergyLossCorrection)
782def smearTrackMomenta(inputListNames, payloadName="", smearingFactorName="smear", path=None):
784 Smear the momenta of the particles according the values read from the given payload.
785 If the particle list contains composite particles, the momenta of the track-based daughters are smeared.
786 Subsequently, the momentum of the mother particle is updated as well.
789 inputListNames (list(str)): input particle list names
790 payloadName (str): name of the payload which contains the smearing values
791 smearingFactorName (str): name of smearing factor variable in the payload.
792 path (basf2.Path): module is added to this path
795 TrackingMomentumScaleFactors = register_module(
'TrackingMomentumScaleFactors')
796 TrackingMomentumScaleFactors.param(
'particleLists', inputListNames)
797 TrackingMomentumScaleFactors.param(
'payloadName', payloadName)
798 TrackingMomentumScaleFactors.param(
'smearingFactorName', smearingFactorName)
800 path.add_module(TrackingMomentumScaleFactors)
803def mergeListsWithBestDuplicate(outputListName,
808 ignoreMotherFlavor=False,
811 Merge input ParticleLists into one output ParticleList. Only the best
812 among duplicates is kept. The lowest or highest value (configurable via
813 preferLowest) of the provided variable determines which duplicate is the
816 @param ouputListName name of merged ParticleList
817 @param inputListName vector of original ParticleLists to be merged
818 @param variable variable to determine best duplicate
819 @param preferLowest whether lowest or highest value of variable should be preferred
820 @param writeOut whether RootOutput module should save the created ParticleList
821 @param ignoreMotherFlavor whether the flavor of the mother particle is ignored when trying to find duplicates
822 @param path modules are added to this path
825 pmanipulate = register_module(
'ParticleListManipulator')
826 pmanipulate.set_name(
'PListMerger_' + outputListName)
827 pmanipulate.param(
'outputListName', outputListName)
828 pmanipulate.param(
'inputListNames', inputListNames)
829 pmanipulate.param(
'variable', variable)
830 pmanipulate.param(
'preferLowest', preferLowest)
831 pmanipulate.param(
'writeOut', writeOut)
832 pmanipulate.param(
'ignoreMotherFlavor', ignoreMotherFlavor)
833 path.add_module(pmanipulate)
836def fillSignalSideParticleList(outputListName, decayString, path):
838 This function should only be used in the ROE path, that is a path
839 that is executed for each ROE object in the DataStore.
841 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
843 Function will create a ParticleList with name 'gamma:sig' which will be filled
844 with the existing photon Particle, being the second daughter of the B0 candidate
845 to which the ROE object has to be related.
847 @param ouputListName name of the created ParticleList
848 @param decayString specify Particle to be added to the ParticleList
851 pload = register_module(
'SignalSideParticleListCreator')
852 pload.set_name(
'SSParticleList_' + outputListName)
853 pload.param(
'particleListName', outputListName)
854 pload.param(
'decayString', decayString)
855 path.add_module(pload)
858def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False,
859 loadPhotonsFromKLM=False):
861 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
862 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
864 The multiple ParticleLists with their own selection criteria are specified
865 via list tuples (decayString, cut), for example
867 .. code-block:: python
869 kaons = ('K+:mykaons', 'kaonID>0.1')
870 pions = ('pi+:mypions','pionID>0.1')
871 fillParticleLists([kaons, pions], path=mypath)
873 If you are unsure what selection you want, you might like to see the
874 :doc:`StandardParticles` functions.
876 The type of the particles to be loaded is specified via the decayString module parameter.
877 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
878 the particle. The following types of the particles can be loaded:
880 * charged final state particles (input ``mdst`` type = Tracks)
881 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
883 * neutral final state particles
884 - "gamma" (input ``mdst`` type = ECLCluster)
885 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
886 - "K_L0", "n0" (input ``mdst`` type = KLMCluster or ECLCluster)
889 For "K_S0" and "Lambda0" you must specify the daughter ordering.
891 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
893 .. code-block:: python
895 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
896 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
899 Gammas can also be loaded from KLMClusters by explicitly setting the
900 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
901 done in selected use-cases and the effect should be studied carefully.
904 For "K_L0" it is now possible to load from ECLClusters, to revert to
905 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
907 .. code-block:: python
909 klongs = ('K_L0', 'isFromKLM > 0')
910 fillParticleLists([kaons, pions, klongs], path=mypath)
912 * Charged kinks final state particles (input ``mdst`` type = Kink)
915 To reconstruct charged particle kink you must specify the daughter.
917 For example, to load Kinks as :math:`K^- \\to \\pi^-\\pi^0` decays from Kinks:
919 .. code-block:: python
921 kinkKaons = ('K- -> pi-', yourCut)
922 fillParticleLists([kaons, pions, v0lambdas, kinkKaons], path=mypath)
926 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
927 The decay string determines the type of Particle
928 and the name of the ParticleList.
929 If the input MDST type is V0 the whole
930 decay chain needs to be specified, so that
931 the user decides and controls the daughters
932 ' order (e.g. ``K_S0 -> pi+ pi-``).
933 If the input MDST type is Kink the decay chain needs to be specified
934 with only one daughter (e.g. ``K- -> pi-``).
935 The cut is the selection criteria
936 to be added to the ParticleList. It can be an empty string.
937 writeOut (bool): whether RootOutput module should save the created ParticleList
938 path (basf2.Path): modules are added to this path
939 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
940 using a mass hypothesis of the exact type passed to fillParticleLists().
941 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
942 in terms of mass difference will be used if the fit using exact particle
943 type is not available.
944 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
947 pload = register_module(
'ParticleLoader')
948 pload.set_name(
'ParticleLoader_' +
'PLists')
949 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
950 pload.param(
'writeOut', writeOut)
951 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
952 path.add_module(pload)
954 from ROOT
import Belle2
956 for decayString, cut
in decayStringsWithCuts:
957 if not decayDescriptor.init(decayString):
958 raise ValueError(
"Invalid decay string")
960 if decayDescriptor.getNDaughters() > 0:
965 if (decayDescriptor.getNDaughters() == 1)
and (decayDescriptor.getMother().getLabel() !=
'kink'):
966 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':kink',
968 if (decayDescriptor.getNDaughters() > 1)
and (decayDescriptor.getMother().getLabel() !=
'V0'):
969 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
970 elif (decayDescriptor.getMother().getLabel() !=
'all' and
971 abs(decayDescriptor.getMother().getPDGCode()) != Belle2.Const.neutron.getPDGCode()):
974 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
978 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
980 if decayString.startswith(
"gamma"):
983 if not loadPhotonsFromKLM:
984 applyCuts(decayString,
'isFromECL', path)
987def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False,
988 loadPhotonsFromKLM=False):
990 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
991 loads them to the StoreArray<Particle> and fills the ParticleList.
994 the :doc:`StandardParticles` functions.
996 The type of the particles to be loaded is specified via the decayString module parameter.
997 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
998 the particle. The following types of the particles can be loaded:
1000 * charged final state particles (input ``mdst`` type = Tracks)
1001 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
1003 * neutral final state particles
1004 - "gamma" (input ``mdst`` type = ECLCluster)
1005 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
1006 - "K_L0", "n0" (input ``mdst`` type = KLMCluster or ECLCluster)
1009 For "K_S0" and "Lambda0" you must specify the daughter ordering.
1011 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
1013 .. code-block:: python
1015 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
1018 Gammas can also be loaded from KLMClusters by explicitly setting the
1019 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
1020 done in selected use-cases and the effect should be studied carefully.
1023 For "K_L0" it is now possible to load from ECLClusters, to revert to
1024 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
1026 .. code-block:: python
1028 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
1030 * Charged kinks final state particles (input ``mdst`` type = Kink)
1033 To reconstruct charged particle kink you must specify the daughter.
1035 For example, to load Kinks as :math:`K^- \\to \\pi^-\\pi^0` decays from Kinks:
1037 .. code-block:: python
1039 fillParticleList('K- -> pi-', yourCut, path=mypath)
1043 decayString (str): Type of Particle and determines the name of the ParticleList.
1044 If the input MDST type is V0 the whole decay chain needs to be specified, so that
1045 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``).
1046 If the input MDST type is Kink the decay chain needs to be specified
1047 with only one daughter (e.g. ``K- -> pi-``).
1048 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1049 writeOut (bool): whether RootOutput module should save the created ParticleList
1050 path (basf2.Path): modules are added to this path
1051 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
1052 using a mass hypothesis of the exact type passed to fillParticleLists().
1053 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1054 in terms of mass difference will be used if the fit using exact particle
1055 type is not available.
1056 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
1059 pload = register_module(
'ParticleLoader')
1060 pload.set_name(
'ParticleLoader_' + decayString)
1061 pload.param(
'decayStrings', [decayString])
1062 pload.param(
'writeOut', writeOut)
1063 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1064 path.add_module(pload)
1067 from ROOT
import Belle2
1069 if not decayDescriptor.init(decayString):
1070 raise ValueError(
"Invalid decay string")
1071 if decayDescriptor.getNDaughters() > 0:
1076 if (decayDescriptor.getNDaughters() == 1)
and (decayDescriptor.getMother().getLabel() !=
'kink'):
1077 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':kink',
1079 if (decayDescriptor.getNDaughters() > 1)
and (decayDescriptor.getMother().getLabel() !=
'V0'):
1080 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut,
1082 elif (decayDescriptor.getMother().getLabel() !=
'all' and
1083 abs(decayDescriptor.getMother().getPDGCode()) != Belle2.Const.neutron.getPDGCode()):
1086 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1090 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1092 if decayString.startswith(
"gamma"):
1095 if not loadPhotonsFromKLM:
1096 applyCuts(decayString,
'isFromECL', path)
1099def fillParticleListWithTrackHypothesis(decayString,
1103 enforceFitHypothesis=False,
1106 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
1108 @param decayString specifies type of Particles and determines the name of the ParticleList
1109 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1110 @param hypothesis the PDG code of the desired track hypothesis
1111 @param writeOut whether RootOutput module should save the created ParticleList
1112 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
1113 using a mass hypothesis of the exact type passed to fillParticleLists().
1114 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1115 in terms of mass difference will be used if the fit using exact particle
1116 type is not available.
1117 @param path modules are added to this path
1120 pload = register_module(
'ParticleLoader')
1121 pload.set_name(
'ParticleLoader_' + decayString)
1122 pload.param(
'decayStrings', [decayString])
1123 pload.param(
'trackHypothesis', hypothesis)
1124 pload.param(
'writeOut', writeOut)
1125 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1126 path.add_module(pload)
1128 from ROOT
import Belle2
1130 if not decayDescriptor.init(decayString):
1131 raise ValueError(
"Invalid decay string")
1132 if decayDescriptor.getMother().getLabel() !=
'all':
1135 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1139 applyCuts(decayString, cut, path)
1142def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
1144 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
1147 You must specify the daughter ordering.
1149 .. code-block:: python
1151 fillConvertedPhotonsList('gamma:converted -> e+ e-', '', path=mypath)
1154 decayString (str): Must be gamma to an e+e- pair. You must specify the daughter ordering.
1155 Will also determine the name of the particleList.
1156 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1157 writeOut (bool): whether RootOutput module should save the created ParticleList
1158 path (basf2.Path): modules are added to this path
1164 B2ERROR(
'For Belle converted photons are available in the pre-defined list "gamma:v0mdst".')
1166 pload = register_module(
'ParticleLoader')
1167 pload.set_name(
'ParticleLoader_' + decayString)
1168 pload.param(
'decayStrings', [decayString])
1169 pload.param(
'addDaughters',
True)
1170 pload.param(
'writeOut', writeOut)
1171 path.add_module(pload)
1173 from ROOT
import Belle2
1175 if not decayDescriptor.init(decayString):
1176 raise ValueError(
"Invalid decay string")
1177 if decayDescriptor.getMother().getLabel() !=
'V0':
1180 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1184 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1187def fillParticleListFromROE(decayString,
1190 sourceParticleListName='',
1195 Creates Particle object for each ROE of the desired type found in the
1196 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
1197 and fills the ParticleList. If useMissing is True, then the missing
1198 momentum is used instead of ROE.
1200 The type of the particles to be loaded is specified via the decayString module parameter.
1202 @param decayString specifies type of Particles and determines the name of the ParticleList.
1203 Source ROEs can be taken as a daughter list, for example:
1204 'B0:tagFromROE -> B0:signal'
1205 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1206 @param maskName Name of the ROE mask to use
1207 @param sourceParticleListName Use related ROEs to this particle list as a source
1208 @param useMissing Use missing momentum instead of ROE momentum
1209 @param writeOut whether RootOutput module should save the created ParticleList
1210 @param path modules are added to this path
1213 pload = register_module(
'ParticleLoader')
1214 pload.set_name(
'ParticleLoader_' + decayString)
1215 pload.param(
'decayStrings', [decayString])
1216 pload.param(
'writeOut', writeOut)
1217 pload.param(
'roeMaskName', maskName)
1218 pload.param(
'useMissing', useMissing)
1219 pload.param(
'sourceParticleListName', sourceParticleListName)
1220 pload.param(
'useROEs',
True)
1221 path.add_module(pload)
1223 from ROOT
import Belle2
1225 if not decayDescriptor.init(decayString):
1226 raise ValueError(
"Invalid decay string")
1230 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1233def fillParticleListFromDummy(decayString,
1236 treatAsInvisible=True,
1240 Creates a ParticleList and fills it with dummy Particles. For self-conjugated Particles one dummy
1241 Particle is created, for Particles that are not self-conjugated one Particle and one anti-Particle is
1242 created. The four-momentum is set to zero.
1244 The type of the particles to be loaded is specified via the decayString module parameter.
1246 @param decayString specifies type of Particles and determines the name of the ParticleList
1247 @param mdstIndex sets the mdst index of Particles
1248 @param covMatrix sets the value of the diagonal covariance matrix of Particles
1249 @param treatAsInvisible whether treeFitter should treat the Particles as invisible
1250 @param writeOut whether RootOutput module should save the created ParticleList
1251 @param path modules are added to this path
1254 pload = register_module(
'ParticleLoader')
1255 pload.set_name(
'ParticleLoader_' + decayString)
1256 pload.param(
'decayStrings', [decayString])
1257 pload.param(
'useDummy',
True)
1258 pload.param(
'dummyMDSTIndex', mdstIndex)
1259 pload.param(
'dummyCovMatrix', covMatrix)
1260 pload.param(
'dummyTreatAsInvisible', treatAsInvisible)
1261 pload.param(
'writeOut', writeOut)
1262 path.add_module(pload)
1265def fillParticleListFromMC(decayString,
1268 skipNonPrimaryDaughters=False,
1271 skipNonPrimary=False,
1274 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1275 loads them to the StoreArray<Particle> and fills the ParticleList.
1277 The type of the particles to be loaded is specified via the decayString module parameter.
1279 @param decayString specifies type of Particles and determines the name of the ParticleList
1280 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1281 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1282 sets mother-daughter relations
1283 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1284 @param writeOut whether RootOutput module should save the created ParticleList
1285 @param path modules are added to this path
1286 @param skipNonPrimary if true, skip non primary particle
1287 @param skipInitial if true, skip initial particles
1290 pload = register_module(
'ParticleLoader')
1291 pload.set_name(
'ParticleLoader_' + decayString)
1292 pload.param(
'decayStrings', [decayString])
1293 pload.param(
'addDaughters', addDaughters)
1294 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1295 pload.param(
'writeOut', writeOut)
1296 pload.param(
'useMCParticles',
True)
1297 pload.param(
'skipNonPrimary', skipNonPrimary)
1298 pload.param(
'skipInitial', skipInitial)
1299 path.add_module(pload)
1301 from ROOT
import Belle2
1303 if not decayDescriptor.init(decayString):
1304 raise ValueError(
"Invalid decay string")
1308 applyCuts(decayString, cut, path)
1311def fillParticleListsFromMC(decayStringsWithCuts,
1313 skipNonPrimaryDaughters=False,
1316 skipNonPrimary=False,
1319 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1320 loads them to the StoreArray<Particle> and fills the ParticleLists.
1322 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
1325 .. code-block:: python
1327 kaons = ('K+:gen', '')
1328 pions = ('pi+:gen', 'pionID>0.1')
1329 fillParticleListsFromMC([kaons, pions], path=mypath)
1332 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not final state particle.
1333 Thus, when one reconstructs a particle from ``Lambda0``, that is created with
1334 ``addDaughters=True`` and ``skipNonPrimaryDaughters=True``, the particle always has ``isSignal==0``.
1335 Please set options for ``Lambda0`` to use MC-matching variables properly as follows,
1336 ``addDaughters=True`` and ``skipNonPrimaryDaughters=False``.
1338 @param decayString specifies type of Particles and determines the name of the ParticleList
1339 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1340 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1341 sets mother-daughter relations
1342 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1343 @param writeOut whether RootOutput module should save the created ParticleList
1344 @param path modules are added to this path
1345 @param skipNonPrimary if true, skip non primary particle
1346 @param skipInitial if true, skip initial particles
1349 pload = register_module(
'ParticleLoader')
1350 pload.set_name(
'ParticleLoader_' +
'PLists')
1351 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
1352 pload.param(
'addDaughters', addDaughters)
1353 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1354 pload.param(
'writeOut', writeOut)
1355 pload.param(
'useMCParticles',
True)
1356 pload.param(
'skipNonPrimary', skipNonPrimary)
1357 pload.param(
'skipInitial', skipInitial)
1358 path.add_module(pload)
1360 from ROOT
import Belle2
1362 for decayString, cut
in decayStringsWithCuts:
1363 if not decayDescriptor.init(decayString):
1364 raise ValueError(
"Invalid decay string")
1368 applyCuts(decayString, cut, path)
1371def fillParticleListFromChargedCluster(outputParticleList,
1374 useOnlyMostEnergeticECLCluster=True,
1378 Creates the Particle object from ECLCluster and KLMCluster that are being matched with the Track of inputParticleList.
1380 @param outputParticleList The output ParticleList. Only neutral final state particles are supported.
1381 @param inputParticleList The input ParticleList that is required to have the relation to the Track object.
1382 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1383 @param useOnlyMostEnergeticECLCluster If True, only the most energetic ECLCluster among ones that are matched with the Track is
1384 used. If False, all matched ECLClusters are loaded. The default is True. Regardless of
1385 this option, the KLMCluster is loaded.
1386 @param writeOut whether RootOutput module should save the created ParticleList
1387 @param path modules are added to this path
1390 pload = register_module(
'ParticleLoader')
1391 pload.set_name(
'ParticleLoader_' + outputParticleList)
1393 pload.param(
'decayStrings', [outputParticleList])
1394 pload.param(
'sourceParticleListName', inputParticleList)
1395 pload.param(
'writeOut', writeOut)
1396 pload.param(
'loadChargedCluster',
True)
1397 pload.param(
'useOnlyMostEnergeticECLCluster', useOnlyMostEnergeticECLCluster)
1398 path.add_module(pload)
1402 applyCuts(outputParticleList, cut, path)
1405def extractParticlesFromROE(particleLists,
1406 signalSideParticleList=None,
1411 Extract Particle objects that belong to the Rest-Of-Events and fill them into the ParticleLists.
1412 The types of the particles other than those specified by ``particleLists`` are not stored.
1413 If one creates a ROE with ``fillWithMostLikely=True`` via `buildRestOfEvent`, for example,
1414 one should create particleLists for not only ``pi+``, ``gamma``, ``K_L0`` but also other charged final state particles.
1416 When one calls the function in the main path, one has to set the argument ``signalSideParticleList`` and the signal side
1417 ParticleList must have only one candidate.
1419 .. code-block:: python
1421 buildRestOfEvent('B0:sig', fillWithMostLikely=True, path=mypath)
1423 roe_path = create_path()
1424 deadEndPath = create_path()
1425 signalSideParticleFilter('B0:sig', '', roe_path, deadEndPath)
1427 plists = ['%s:in_roe' % ptype for ptype in ['pi+', 'gamma', 'K_L0', 'K+', 'p+', 'e+', 'mu+']]
1428 extractParticlesFromROE(plists, maskName='all', path=roe_path)
1430 # one can analyze these ParticleLists in the roe_path
1432 mypath.for_each('RestOfEvent', 'RestOfEvents', roe_path)
1434 rankByLowest('B0:sig', 'deltaE', numBest=1, path=mypath)
1435 extractParticlesFromROE(plists, signalSideParticleList='B0:sig', maskName='all', path=mypath)
1437 # one can analyze these ParticleLists in the main path
1440 @param particleLists (str or list(str)) Name of output ParticleLists
1441 @param signalSideParticleList (str) Name of signal side ParticleList
1442 @param maskName (str) Name of the ROE mask to be applied on Particles
1443 @param writeOut (bool) whether RootOutput module should save the created ParticleList
1444 @param path (basf2.Path) modules are added to this path
1447 if isinstance(particleLists, str):
1448 particleLists = [particleLists]
1450 pext = register_module(
'ParticleExtractorFromROE')
1451 pext.set_name(
'ParticleExtractorFromROE_' +
'_'.join(particleLists))
1452 pext.param(
'outputListNames', particleLists)
1453 if signalSideParticleList
is not None:
1454 pext.param(
'signalSideParticleListName', signalSideParticleList)
1455 pext.param(
'maskName', maskName)
1456 pext.param(
'writeOut', writeOut)
1457 path.add_module(pext)
1460def applyCuts(list_name, cut, path):
1462 Removes particle candidates from ``list_name`` that do not pass ``cut``
1463 (given selection criteria).
1466 require energetic pions safely inside the cdc
1468 .. code-block:: python
1470 applyCuts("pi+:mypions", "[E > 2] and thetaInCDCAcceptance", path=mypath)
1473 You must use square braces ``[`` and ``]`` for conditional statements.
1476 list_name (str): input ParticleList name
1477 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
1478 path (basf2.Path): modules are added to this path
1481 pselect = register_module(
'ParticleSelector')
1482 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
1483 pselect.param(
'decayString', list_name)
1484 pselect.param(
'cut', cut)
1485 path.add_module(pselect)
1488def applyEventCuts(cut, path, metavariables=None):
1490 Removes events that do not pass the ``cut`` (given selection criteria).
1493 continuum events (in mc only) with more than 5 tracks
1495 .. code-block:: python
1497 applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1500 Only event-based variables are allowed in this function
1501 and only square brackets ``[`` and ``]`` for conditional statements.
1504 cut (str): Events that do not pass these selection criteria are skipped
1505 path (basf2.Path): modules are added to this path
1506 metavariables (list(str)): List of meta variables to be considered in decomposition of cut
1510 from variables
import variables
1512 def find_vars(t: tuple, var_list: list, meta_list: list) ->
None:
1513 """ Recursive helper function to find variable names """
1514 if not isinstance(t, tuple):
1516 if t[0] == b2parser.B2ExpressionParser.node_types[
'IdentifierNode']:
1519 if t[0] == b2parser.B2ExpressionParser.node_types[
'FunctionNode']:
1520 meta_list.append(list(t[1:]))
1523 if isinstance(i, tuple):
1524 find_vars(i, var_list, meta_list)
1526 def check_variable(var_list: list, metavar_ids: list) ->
None:
1527 for var_string
in var_list:
1529 orig_name = variables.resolveAlias(var_string)
1530 if orig_name != var_string:
1533 find_vars(
b2parser.parse(orig_name), var_list_temp, meta_list_temp)
1535 check_variable(var_list_temp, metavar_ids)
1536 check_meta(meta_list_temp, metavar_ids)
1539 var = variables.getVariable(var_string)
1540 if event_var_id
not in var.description:
1541 B2ERROR(f
'Variable {var_string} is not an event-based variable! "\
1542 "Please check your inputs to the applyEventCuts method!')
1544 def check_meta(meta_list: list, metavar_ids: list) ->
None:
1545 for meta_string_list
in meta_list:
1547 while meta_string_list[0]
in metavar_ids:
1549 meta_string_list.pop(0)
1550 for meta_string
in meta_string_list[0].split(
","):
1551 find_vars(
b2parser.parse(meta_string), var_list_temp, meta_string_list)
1552 if len(meta_string_list) > 0:
1553 meta_string_list.pop(0)
1554 if len(meta_string_list) == 0:
1556 if len(meta_string_list) > 1:
1557 meta_list += meta_string_list[1:]
1558 if isinstance(meta_string_list[0], list):
1559 meta_string_list = [element
for element
in meta_string_list[0]]
1561 check_variable(var_list_temp, metavar_ids)
1563 if len(meta_string_list) == 0:
1565 elif len(meta_string_list) == 1:
1566 var = variables.getVariable(meta_string_list[0])
1568 var = variables.getVariable(meta_string_list[0], meta_string_list[1].split(
","))
1570 if event_var_id
in var.description:
1573 B2ERROR(f
'Variable {var.name} is not an event-based variable! Please check your inputs to the applyEventCuts method!')
1575 event_var_id =
'[Eventbased]'
1576 metavar_ids = [
'formula',
'abs',
1580 'exp',
'log',
'log10',
1582 'isNAN',
'ifNANgiveX']
1584 metavar_ids += metavariables
1588 find_vars(
b2parser.parse(cut), var_list=var_list, meta_list=meta_list)
1590 if len(var_list) == 0
and len(meta_list) == 0:
1591 B2WARNING(f
'Cut string "{cut}" has no variables for applyEventCuts helper function!')
1593 check_variable(var_list, metavar_ids)
1594 check_meta(meta_list, metavar_ids)
1596 eselect = register_module(
'VariableToReturnValue')
1597 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1598 path.add_module(eselect)
1599 empty_path = create_path()
1600 eselect.if_value(
'<1', empty_path)
1603def reconstructDecay(decayString,
1608 candidate_limit=None,
1609 ignoreIfTooManyCandidates=True,
1610 chargeConjugation=True,
1611 allowChargeViolation=False):
1613 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1614 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1615 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1616 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1617 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1619 One can use an ``@``-sign to mark a particle as unspecified for inclusive analyses,
1620 e.g. in a DecayString: :code:`'@Xsd -> K+ pi-'`.
1622 .. seealso:: :ref:`Marker_of_unspecified_particle`
1625 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1626 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1627 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1629 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1630 This can be solved by manually randomising the lists before combining.
1634 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1635 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1637 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1638 (from the DecayString the mother and daughter ParticleLists are determined)
1639 @param cut created (mother) Particles are added to the mother ParticleList if they
1640 pass give cuts (in VariableManager style) and rejected otherwise
1641 @param dmID user specified decay mode identifier
1642 @param writeOut whether RootOutput module should save the created ParticleList
1643 @param path modules are added to this path
1644 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1645 the number of candidates is exceeded a Warning will be
1647 By default, all these candidates will be removed and event will be ignored.
1648 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1649 If no value is given the amount is limited to a sensible
1650 default. A value <=0 will disable this limit and can
1651 cause huge memory amounts so be careful.
1652 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1653 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1654 otherwise, number of candidates in candidate_limit is reconstructed.
1655 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1656 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1659 pmake = register_module(
'ParticleCombiner')
1660 pmake.set_name(
'ParticleCombiner_' + decayString)
1661 pmake.param(
'decayString', decayString)
1662 pmake.param(
'cut', cut)
1663 pmake.param(
'decayMode', dmID)
1664 pmake.param(
'writeOut', writeOut)
1665 if candidate_limit
is not None:
1666 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1667 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1668 pmake.param(
'chargeConjugation', chargeConjugation)
1669 pmake.param(
"allowChargeViolation", allowChargeViolation)
1670 path.add_module(pmake)
1673def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1675 Creates a new Particle as the combination of all Particles from all
1676 provided inputParticleLists. However, each particle is used only once
1677 (even if duplicates are provided) and the combination has to pass the
1678 specified selection criteria to be saved in the newly created (mother)
1681 @param inputParticleLists List of input particle lists which are combined to the new Particle
1682 @param outputList Name of the particle combination created with this module
1683 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1684 these given cuts (in VariableManager style) and is rejected otherwise
1685 @param writeOut whether RootOutput module should save the created ParticleList
1686 @param path module is added to this path
1689 pmake = register_module(
'AllParticleCombiner')
1690 pmake.set_name(
'AllParticleCombiner_' + outputList)
1691 pmake.param(
'inputListNames', inputParticleLists)
1692 pmake.param(
'outputListName', outputList)
1693 pmake.param(
'cut', cut)
1694 pmake.param(
'writeOut', writeOut)
1695 path.add_module(pmake)
1698def reconstructMissingKlongDecayExpert(decayString,
1705 Creates a list of K_L0's and of B -> K_L0 + X, with X being a fully-reconstructed state.
1706 The K_L0 momentum is determined from kinematic constraints of the two-body B decay into K_L0 and X
1708 @param decayString DecayString specifying what kind of the decay should be reconstructed
1709 (from the DecayString the mother and daughter ParticleLists are determined)
1710 @param cut Particles are added to the K_L0 and B ParticleList if the B candidates
1711 pass the given cuts (in VariableManager style) and rejected otherwise
1712 @param dmID user specified decay mode identifier
1713 @param writeOut whether RootOutput module should save the created ParticleList
1714 @param path modules are added to this path
1715 @param recoList suffix appended to original K_L0 and B ParticleList that identify the newly created K_L0 and B lists
1718 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1719 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1720 pcalc.param(
'decayString', decayString)
1721 pcalc.param(
'writeOut', writeOut)
1722 pcalc.param(
'recoList', recoList)
1723 path.add_module(pcalc)
1725 rmake = register_module(
'KlongDecayReconstructorExpert')
1726 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1727 rmake.param(
'decayString', decayString)
1728 rmake.param(
'cut', cut)
1729 rmake.param(
'decayMode', dmID)
1730 rmake.param(
'writeOut', writeOut)
1731 rmake.param(
'recoList', recoList)
1732 path.add_module(rmake)
1735def setBeamConstrainedMomentum(particleList, decayStringTarget, decayStringDaughters, path=None):
1737 Replace the four-momentum of the target Particle by p(beam) - p(selected daughters).
1738 The momentum of the mother Particle will not be changed.
1740 @param particleList mother Particlelist
1741 @param decayStringTarget DecayString specifying the target particle whose momentum
1743 @param decayStringDaughters DecayString specifying the daughter particles used to replace
1744 the momentum of the target particle by p(beam)-p(daughters)
1747 mod = register_module(
'ParticleMomentumUpdater')
1748 mod.set_name(
'ParticleMomentumUpdater' + particleList)
1749 mod.param(
'particleList', particleList)
1750 mod.param(
'decayStringTarget', decayStringTarget)
1751 mod.param(
'decayStringDaughters', decayStringDaughters)
1752 path.add_module(mod)
1755def updateKlongKinematicsExpert(particleList,
1759 Calculates and updates the kinematics of B->K_L0 + something else with same method as
1760 `reconstructMissingKlongDecayExpert`. This helps to revert the kinematics after the vertex fitting.
1762 @param particleList input ParticleList of B meson that decays to K_L0 + X
1763 @param writeOut whether RootOutput module should save the ParticleList
1764 @param path modules are added to this path
1767 mod = register_module(
'KlongMomentumUpdaterExpert')
1768 mod.set_name(
'KlongMomentumUpdaterExpert_' + particleList)
1769 mod.param(
'listName', particleList)
1770 mod.param(
'writeOut', writeOut)
1771 path.add_module(mod)
1774def replaceMass(replacerName, particleLists=None, pdgCode=22, path=None):
1776 replaces the mass of the particles inside the given particleLists
1777 with the invariant mass of the particle corresponding to the given pdgCode.
1779 @param particleLists new ParticleList filled with copied Particles
1780 @param pdgCode PDG code for mass reference
1781 @param path modules are added to this path
1784 if particleLists
is None:
1788 pmassupdater = register_module(
'ParticleMassUpdater')
1789 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1790 pmassupdater.param(
'particleLists', particleLists)
1791 pmassupdater.param(
'pdgCode', pdgCode)
1792 path.add_module(pmassupdater)
1795def reconstructRecoil(decayString,
1800 candidate_limit=None,
1801 allowChargeViolation=False):
1803 Creates new Particles that recoil against the input particles.
1805 For example the decay string M -> D1 D2 D3 will:
1806 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1807 - Particles D1, D2, D3 will be appended as daughters to M
1808 - the 4-momentum of the mother Particle M is given by
1809 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1811 @param decayString DecayString specifying what kind of the decay should be reconstructed
1812 (from the DecayString the mother and daughter ParticleLists are determined)
1813 @param cut created (mother) Particles are added to the mother ParticleList if they
1814 pass give cuts (in VariableManager style) and rejected otherwise
1815 @param dmID user specified decay mode identifier
1816 @param writeOut whether RootOutput module should save the created ParticleList
1817 @param path modules are added to this path
1818 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1819 the number of candidates is exceeded no candidate will be
1820 reconstructed for that event and a Warning will be
1822 If no value is given the amount is limited to a sensible
1823 default. A value <=0 will disable this limit and can
1824 cause huge memory amounts so be careful.
1825 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1828 pmake = register_module(
'ParticleCombiner')
1829 pmake.set_name(
'ParticleCombiner_' + decayString)
1830 pmake.param(
'decayString', decayString)
1831 pmake.param(
'cut', cut)
1832 pmake.param(
'decayMode', dmID)
1833 pmake.param(
'writeOut', writeOut)
1834 pmake.param(
'recoilParticleType', 1)
1835 if candidate_limit
is not None:
1836 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1837 pmake.param(
'allowChargeViolation', allowChargeViolation)
1838 path.add_module(pmake)
1841def reconstructRecoilDaughter(decayString,
1846 candidate_limit=None,
1847 allowChargeViolation=False):
1849 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1851 For example the decay string M -> D1 D2 D3 will:
1852 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1853 - Particles D1, D2, D3 will be appended as daughters to M
1854 - the 4-momentum of the mother Particle M is given by
1855 p(M) = p(D1) - Sum_i p(Di), where i>1
1857 @param decayString DecayString specifying what kind of the decay should be reconstructed
1858 (from the DecayString the mother and daughter ParticleLists are determined)
1859 @param cut created (mother) Particles are added to the mother ParticleList if they
1860 pass give cuts (in VariableManager style) and rejected otherwise
1861 @param dmID user specified decay mode identifier
1862 @param writeOut whether RootOutput module should save the created ParticleList
1863 @param path modules are added to this path
1864 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1865 the number of candidates is exceeded no candidate will be
1866 reconstructed for that event and a Warning will be
1868 If no value is given the amount is limited to a sensible
1869 default. A value <=0 will disable this limit and can
1870 cause huge memory amounts so be careful.
1871 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1872 daughter is actually the mother
1875 pmake = register_module(
'ParticleCombiner')
1876 pmake.set_name(
'ParticleCombiner_' + decayString)
1877 pmake.param(
'decayString', decayString)
1878 pmake.param(
'cut', cut)
1879 pmake.param(
'decayMode', dmID)
1880 pmake.param(
'writeOut', writeOut)
1881 pmake.param(
'recoilParticleType', 2)
1882 if candidate_limit
is not None:
1883 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1884 pmake.param(
'allowChargeViolation', allowChargeViolation)
1885 path.add_module(pmake)
1888def rankByHighest(particleList,
1892 allowMultiRank=False,
1894 overwriteRank=False,
1897 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1898 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1899 The list is also sorted from best to worst candidate
1900 (each charge, e.g. B+/B-, separately).
1901 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1902 a non-zero value for 'numBest'.
1905 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1906 These variable names can become clunky, so it's probably a good idea to set an alias.
1907 For example if you rank your B candidates by momentum,
1911 rankByHighest("B0:myCandidates", "p", path=mypath)
1912 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1915 @param particleList The input ParticleList
1916 @param variable Variable to order Particles by.
1917 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1918 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1919 @param allowMultiRank If true, candidates with the same value will get the same rank.
1920 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1921 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1922 @param path modules are added to this path
1925 bcs = register_module(
'BestCandidateSelection')
1926 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1927 bcs.param(
'particleList', particleList)
1928 bcs.param(
'variable', variable)
1929 bcs.param(
'numBest', numBest)
1930 bcs.param(
'outputVariable', outputVariable)
1931 bcs.param(
'allowMultiRank', allowMultiRank)
1932 bcs.param(
'cut', cut)
1933 bcs.param(
'overwriteRank', overwriteRank)
1934 path.add_module(bcs)
1937def rankByLowest(particleList,
1941 allowMultiRank=False,
1943 overwriteRank=False,
1946 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1947 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1948 The list is also sorted from best to worst candidate
1949 (each charge, e.g. B+/B-, separately).
1950 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1951 a non-zero value for 'numBest'.
1954 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1955 These variable names can become clunky, so it's probably a good idea to set an alias.
1956 For example if you rank your B candidates by :b2:var:`dM`,
1960 rankByLowest("B0:myCandidates", "dM", path=mypath)
1961 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1964 @param particleList The input ParticleList
1965 @param variable Variable to order Particles by.
1966 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1967 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1968 @param allowMultiRank If true, candidates with the same value will get the same rank.
1969 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1970 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1971 @param path modules are added to this path
1974 bcs = register_module(
'BestCandidateSelection')
1975 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1976 bcs.param(
'particleList', particleList)
1977 bcs.param(
'variable', variable)
1978 bcs.param(
'numBest', numBest)
1979 bcs.param(
'selectLowest',
True)
1980 bcs.param(
'allowMultiRank', allowMultiRank)
1981 bcs.param(
'outputVariable', outputVariable)
1982 bcs.param(
'cut', cut)
1983 bcs.param(
'overwriteRank', overwriteRank)
1984 path.add_module(bcs)
1987def applyRandomCandidateSelection(particleList, path=None):
1989 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1990 This is done on a event-by-event basis.
1992 @param particleList ParticleList for which the random candidate selection should be applied
1993 @param path module is added to this path
1996 rcs = register_module(
'BestCandidateSelection')
1997 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1998 rcs.param(
'particleList', particleList)
1999 rcs.param(
'variable',
'random')
2000 rcs.param(
'selectLowest',
False)
2001 rcs.param(
'allowMultiRank',
False)
2002 rcs.param(
'numBest', 1)
2003 rcs.param(
'cut',
'')
2004 rcs.param(
'outputVariable',
'')
2005 path.add_module(rcs)
2010 Prints the contents of DataStore in the first event (or a specific event number or all events).
2011 Will list all objects and arrays (including size).
2014 The command line tool: ``b2file-size``.
2017 eventNumber (int): Print the datastore only for this event. The default
2018 (-1) prints only the first event, 0 means print for all events (can produce large output)
2019 path (basf2.Path): the PrintCollections module is added to this path
2022 This will print a lot of output if you print it for all events and process many events.
2026 printDS = register_module(
'PrintCollections')
2027 printDS.param(
'printForEvent', eventNumber)
2028 path.add_module(printDS)
2031def printVariableValues(list_name, var_names, path):
2033 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
2035 @param list_name input ParticleList name
2036 @param var_names vector of variable names to be printed
2037 @param path modules are added to this path
2040 prlist = register_module(
'ParticlePrinter')
2041 prlist.set_name(
'ParticlePrinter_' + list_name)
2042 prlist.param(
'listName', list_name)
2043 prlist.param(
'fullPrint',
False)
2044 prlist.param(
'variables', var_names)
2045 path.add_module(prlist)
2048def printList(list_name, full, path):
2050 Prints the size and executes Particle->print() (if full=True)
2051 method for all Particles in given ParticleList. For debugging purposes.
2053 @param list_name input ParticleList name
2054 @param full execute Particle->print() method for all Particles
2055 @param path modules are added to this path
2058 prlist = register_module(
'ParticlePrinter')
2059 prlist.set_name(
'ParticlePrinter_' + list_name)
2060 prlist.param(
'listName', list_name)
2061 prlist.param(
'fullPrint', full)
2062 path.add_module(prlist)
2065def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None, basketsize=1600,
2066 signalSideParticleList="", filenameSuffix="", useFloat=False, storeEventType=True,
2067 ignoreCommandLineOverride=False):
2069 Creates and fills a flat ntuple with the specified variables from the VariableManager.
2070 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
2071 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
2074 decayString (str): specifies type of Particles and determines the name of the ParticleList
2075 variables (list(str)): the list of variables (which must be registered in the VariableManager)
2076 treename (str): name of the ntuple tree
2077 filename (str): which is used to store the variables
2078 path (basf2.Path): the basf2 path where the analysis is processed
2079 basketsize (int): size of baskets in the output ntuple in bytes
2080 signalSideParticleList (str): The name of the signal-side ParticleList.
2081 Only valid if the module is called in a for_each loop over the RestOfEvent.
2082 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2083 useFloat (bool): Use single precision (float) instead of double precision (double)
2084 for floating-point numbers.
2085 storeEventType (bool) : if true, the branch __eventType__ is added for the MC event type information.
2086 The information is available from MC16 on.
2087 ignoreCommandLineOverride (bool) : if true, ignore override of file name via command line argument ``-o``.
2089 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2092 output = register_module(
'VariablesToNtuple')
2093 output.set_name(
'VariablesToNtuple_' + decayString)
2094 output.param(
'particleList', decayString)
2095 output.param(
'variables', variables)
2096 output.param(
'fileName', filename)
2097 output.param(
'treeName', treename)
2098 output.param(
'basketSize', basketsize)
2099 output.param(
'signalSideParticleList', signalSideParticleList)
2100 output.param(
'fileNameSuffix', filenameSuffix)
2101 output.param(
'useFloat', useFloat)
2102 output.param(
'storeEventType', storeEventType)
2103 output.param(
'ignoreCommandLineOverride', ignoreCommandLineOverride)
2104 path.add_module(output)
2110 filename='ntuple.root',
2113 prefixDecayString=False,
2115 ignoreCommandLineOverride=False):
2117 Creates and fills a flat ntuple with the specified variables from the VariableManager
2120 decayString (str): specifies type of Particles and determines the name of the ParticleList
2121 variables (list(tuple))): variables + binning which must be registered in the VariableManager
2122 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
2123 filename (str): which is used to store the variables
2124 path (basf2.Path): the basf2 path where the analysis is processed
2125 directory (str): directory inside the output file where the histograms should be saved.
2126 Useful if you want to have different histograms in the same file to separate them.
2127 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
2128 programmatic naming of the structure in the file.
2129 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2130 ignoreCommandLineOverride (bool) : if true, ignore override of file name via command line argument ``-o``.
2132 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2135 if variables_2d
is None:
2137 output = register_module(
'VariablesToHistogram')
2138 output.set_name(
'VariablesToHistogram_' + decayString)
2139 output.param(
'particleList', decayString)
2140 output.param(
'variables', variables)
2141 output.param(
'variables_2d', variables_2d)
2142 output.param(
'fileName', filename)
2143 output.param(
'fileNameSuffix', filenameSuffix)
2144 output.param(
'ignoreCommandLineOverride', ignoreCommandLineOverride)
2145 if directory
is not None or prefixDecayString:
2146 if directory
is None:
2148 if prefixDecayString:
2149 directory = decayString +
"_" + directory
2150 output.param(
"directory", directory)
2151 path.add_module(output)
2156 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
2157 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
2160 particleList (str): The input ParticleList
2161 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2162 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2163 An existing extra info with the same name will be overwritten if the new
2164 value is lower / will never be overwritten / will be overwritten if the
2165 new value is higher / will always be overwritten (option = -1/0/1/2).
2166 path (basf2.Path): modules are added to this path
2169 mod = register_module(
'VariablesToExtraInfo')
2170 mod.set_name(
'VariablesToExtraInfo_' + particleList)
2171 mod.param(
'particleList', particleList)
2172 mod.param(
'variables', variables)
2173 mod.param(
'overwrite', option)
2174 path.add_module(mod)
2177def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
2179 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
2180 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
2181 to specified daughter particle.
2184 particleList (str): The input ParticleList
2185 decayString (str): Decay string that specifies to which daughter the extra info should be appended
2186 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2187 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2188 An existing extra info with the same name will be overwritten if the new
2189 value is lower / will never be overwritten / will be overwritten if the
2190 new value is higher / will always be overwritten (option = -1/0/1/2).
2191 path (basf2.Path): modules are added to this path
2194 mod = register_module(
'VariablesToExtraInfo')
2195 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
2196 mod.param(
'particleList', particleList)
2197 mod.param(
'decayString', decayString)
2198 mod.param(
'variables', variables)
2199 mod.param(
'overwrite', option)
2200 path.add_module(mod)
2203def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
2205 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
2206 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
2209 When the function is called first time not in the main path but in a sub-path e.g. ``roe_path``,
2210 the eventExtraInfo cannot be accessed from the main path because of the shorter lifetime of the event-extra-info field.
2211 If one wants to call the function in a sub-path, one has to call the function in the main path beforehand.
2214 particleList (str): The input ParticleList
2215 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2216 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2217 An existing extra info with the same name will be overwritten if the new
2218 value is lower / will never be overwritten / will be overwritten if the
2219 new value is higher / will always be overwritten (option = -1/0/1/2).
2220 path (basf2.Path): modules are added to this path
2223 mod = register_module(
'VariablesToEventExtraInfo')
2224 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
2225 mod.param(
'particleList', particleList)
2226 mod.param(
'variables', variables)
2227 mod.param(
'overwrite', option)
2228 path.add_module(mod)
2231def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
2233 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
2234 particle) as an extra info to the particle related to current ROE.
2235 Should be used only in the for_each roe path.
2238 particleList (str): The input ParticleList
2239 varToExtraInfo (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2240 path (basf2.Path): modules are added to this path
2243 mod = register_module(
'SignalSideVariablesToExtraInfo')
2244 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
2245 mod.param(
'particleListName', particleList)
2246 mod.param(
'variableToExtraInfo', varToExtraInfo)
2247 path.add_module(mod)
2250def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
2252 Define and blind a signal region.
2253 Per default, the defined signal region is cut out if ran on data.
2254 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
2258 .. code-block:: python
2260 ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
2261 ma.signalRegion("B+:sig",
2262 "Mbc>5.27 and abs(deltaE)<0.2",
2265 ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
2268 particleList (str): The input ParticleList
2269 cut (str): Cut string describing the signal region
2270 path (basf2.Path):: Modules are added to this path
2271 name (str): Name of the Signal region in the variable manager
2272 blind_data (bool): Automatically exclude signal region from data
2276 from variables
import variables
2277 mod = register_module(
'VariablesToExtraInfo')
2278 mod.set_name(f
'{name}_' + particleList)
2279 mod.param(
'particleList', particleList)
2280 mod.param(
'variables', {f
"passesCut({cut})": name})
2281 variables.addAlias(name, f
"extraInfo({name})")
2282 path.add_module(mod)
2286 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
2289def removeExtraInfo(particleLists=None, removeEventExtraInfo=False, path=None):
2291 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
2294 if particleLists
is None:
2296 mod = register_module(
'ExtraInfoRemover')
2297 mod.param(
'particleLists', particleLists)
2298 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
2299 path.add_module(mod)
2302def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
2304 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2305 to the particle from the input ParticleList. Additional selection criteria can be applied.
2306 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2307 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2308 suggests should be empty and its purpose is to end the execution of for_each roe path for
2309 the current ROE object.
2311 @param particleList The input ParticleList
2312 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2313 @param for_each roe path in which this filter is executed
2314 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2317 mod = register_module(
'SignalSideParticleFilter')
2318 mod.set_name(
'SigSideParticleFilter_' + particleList)
2319 mod.param(
'particleLists', [particleList])
2320 mod.param(
'selection', selection)
2321 roe_path.add_module(mod)
2322 mod.if_false(deadEndPath)
2325def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
2327 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2328 to the particle from the input ParticleList. Additional selection criteria can be applied.
2329 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2330 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2331 suggests should be empty and its purpose is to end the execution of for_each roe path for
2332 the current ROE object.
2334 @param particleLists The input ParticleLists
2335 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2336 @param for_each roe path in which this filter is executed
2337 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2340 mod = register_module(
'SignalSideParticleFilter')
2341 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
2342 mod.param(
'particleLists', particleLists)
2343 mod.param(
'selection', selection)
2344 roe_path.add_module(mod)
2345 mod.if_false(deadEndPath)
2354 chargeConjugation=True,
2357 Finds and creates a ``ParticleList`` from given decay string.
2358 ``ParticleList`` of daughters with sub-decay is created.
2360 Only the particles made from MCParticle, which can be loaded by `fillParticleListFromMC`, are accepted as daughters.
2362 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
2363 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
2366 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
2367 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
2368 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
2371 It is recommended to use only primary particles as daughter particles unless you want to explicitly study the secondary
2372 particles. The behavior of MC-matching for secondary particles from a stable particle decay is not guaranteed.
2373 Please consider to use `fillParticleListFromMC` with ``skipNonPrimary=True`` to load daughter particles.
2374 Moreover, it is recommended to load ``K_S0`` and ``Lambda0`` directly from MCParticle by `fillParticleListFromMC` rather
2375 than reconstructing from two pions or a proton-pion pair, because their direct daughters can be the secondary particle.
2378 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
2379 (from the DecayString the mother and daughter ParticleLists are determined)
2380 @param cut created (mother) Particles are added to the mother ParticleList if they
2381 pass given cuts (in VariableManager style) and rejected otherwise
2382 isSignal==1 is always required by default.
2383 @param dmID user specified decay mode identifier
2384 @param writeOut whether RootOutput module should save the created ParticleList
2385 @param path modules are added to this path
2386 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
2389 pmake = register_module(
'ParticleCombinerFromMC')
2390 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
2391 pmake.param(
'decayString', decayString)
2392 pmake.param(
'cut', cut)
2393 pmake.param(
'decayMode', dmID)
2394 pmake.param(
'writeOut', writeOut)
2395 pmake.param(
'chargeConjugation', chargeConjugation)
2396 path.add_module(pmake)
2403 appendAllDaughters=False,
2404 skipNonPrimaryDaughters=True,
2408 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
2409 The decay string is required to describe correctly what you want.
2410 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
2412 The output particles has only the daughter particles written in the given decay string, if
2413 ``appendAllDaughters=False`` (default). If ``appendAllDaughters=True``, all daughters of the matched MCParticle are
2414 appended in the order defined at the MCParticle level. For example,
2416 .. code-block:: python
2418 findMCDecay('B0:Xee', 'B0 -> e+ e- ... ?gamma', appendAllDaughters=False, path=mypath)
2420 The output ParticleList ``B0:Xee`` will match the inclusive ``B0 -> e+ e-`` decays (but neutrinos are not included),
2421 in both cases of ``appendAllDaughters`` is false and true.
2422 If the ``appendAllDaughters=False`` as above example, the ``B0:Xee`` has only two electrons as daughters.
2423 While, if ``appendAllDaughters=True``, all daughters of the matched MCParticles are appended. When the truth decay mode of
2424 the MCParticle is ``B0 -> [K*0 -> K+ pi-] [J/psi -> e+ e-]``, the first daughter of ``B0:Xee`` is ``K*0`` and ``e+``
2425 will be the first daughter of second daughter of ``B0:Xee``.
2427 The option ``skipNonPrimaryDaughters`` only has an effect if ``appendAllDaughters=True``. If ``skipNonPrimaryDaughters=True``,
2428 all primary daughters are appended but the secondary particles are not.
2431 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not a final state particle.
2432 In order for the MCMatching to work properly, the daughters of ``Lambda0`` are appended to
2433 ``Lambda0`` regardless of the value of the option ``skipNonPrimaryDaughters``.
2436 @param list_name The output particle list name
2437 @param decay The decay string which you want
2438 @param writeOut Whether `RootOutput` module should save the created ``outputList``
2439 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
2440 @param appendAllDaughters if true, not only the daughters described in the decay string but all daughters are appended
2441 @param path modules are added to this path
2444 decayfinder = register_module(
'MCDecayFinder')
2445 decayfinder.set_name(
'MCDecayFinder_' + list_name)
2446 decayfinder.param(
'listName', list_name)
2447 decayfinder.param(
'decayString', decay)
2448 decayfinder.param(
'appendAllDaughters', appendAllDaughters)
2449 decayfinder.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
2450 decayfinder.param(
'writeOut', writeOut)
2451 path.add_module(decayfinder)
2454def summaryOfLists(particleLists, outputFile=None, path=None):
2456 Prints out Particle statistics at the end of the job: number of events with at
2457 least one candidate, average number of candidates per event, etc.
2458 If an output file name is provided the statistics is also dumped into a json file with that name.
2460 @param particleLists list of input ParticleLists
2461 @param outputFile output file name (not created by default)
2464 particleStats = register_module(
'ParticleStats')
2465 particleStats.param(
'particleLists', particleLists)
2466 if outputFile
is not None:
2467 particleStats.param(
'outputFile', outputFile)
2468 path.add_module(particleStats)
2471def matchMCTruth(list_name, path):
2473 Performs MC matching (sets relation Particle->MCParticle) for
2474 all particles (and its (grand)^N-daughter particles) in the specified
2477 @param list_name name of the input ParticleList
2478 @param path modules are added to this path
2481 mcMatch = register_module(
'MCMatcherParticles')
2482 mcMatch.set_name(
'MCMatch_' + list_name)
2483 mcMatch.param(
'listName', list_name)
2484 path.add_module(mcMatch)
2487def looseMCTruth(list_name, path):
2489 Performs loose MC matching for all particles in the specified
2491 The difference between loose and normal mc matching algorithm is that
2492 the loose algorithm will find the common mother of the majority of daughter
2493 particles while the normal algorithm finds the common mother of all daughters.
2494 The results of loose mc matching algorithm are stored to the following extraInfo
2497 - looseMCMotherPDG: PDG code of most common mother
2498 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
2499 - looseMCWrongDaughterN: number of daughters that don't originate from the most common mother
2500 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from the most common mother (only if
2501 looseMCWrongDaughterN = 1)
2502 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background Particle
2504 @param list_name name of the input ParticleList
2505 @param path modules are added to this path
2508 mcMatch = register_module(
'MCMatcherParticles')
2509 mcMatch.set_name(
'LooseMCMatch_' + list_name)
2510 mcMatch.param(
'listName', list_name)
2511 mcMatch.param(
'looseMCMatching',
True)
2512 path.add_module(mcMatch)
2515def buildRestOfEvent(target_list_name, inputParticlelists=None,
2516 fillWithMostLikely=True,
2517 chargedPIDPriors=None, path=None):
2519 Creates for each Particle in the given ParticleList a RestOfEvent
2520 dataobject and makes basf2 relation between them. User can provide additional
2521 particle lists with a different particle hypothesis like ['K+:good, e+:good'], etc.
2523 @param target_list_name name of the input ParticleList
2524 @param inputParticlelists list of user-defined input particle list names, which serve
2525 as source of particles to build the ROE, the FSP particles from
2526 target_list_name are automatically excluded from the ROE object
2527 @param fillWithMostLikely By default the module uses the most likely particle mass hypothesis for charged particles
2528 based on the PID likelihood. Turn this behavior off if you want to configure your own
2529 input particle lists.
2530 @param chargedPIDPriors The prior PID fractions, that are used to regulate the
2531 amount of certain charged particle species, should be a list of
2532 six floats if not None. The order of particle types is
2533 the following: [e-, mu-, pi-, K-, p+, d+]
2534 @param path modules are added to this path
2537 if inputParticlelists
is None:
2538 inputParticlelists = []
2539 fillParticleList(
'pi+:all',
'', path=path)
2540 if fillWithMostLikely:
2541 from stdCharged
import stdMostLikely
2542 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
2543 inputParticlelists = [f
'{ptype}:mostlikely_roe' for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
2546 fillParticleList(
'gamma:all',
'', path=path)
2547 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
2548 inputParticlelists += [
'pi+:all',
'gamma:all',
'K_L0:roe_default']
2550 inputParticlelists += [
'pi+:all',
'gamma:mdst']
2551 roeBuilder = register_module(
'RestOfEventBuilder')
2552 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
2553 roeBuilder.param(
'particleList', target_list_name)
2554 roeBuilder.param(
'particleListsInput', inputParticlelists)
2555 roeBuilder.param(
'mostLikely', fillWithMostLikely)
2556 path.add_module(roeBuilder)
2559def buildNestedRestOfEvent(target_list_name, maskName='all', path=None):
2561 Creates for each Particle in the given ParticleList a RestOfEvent
2562 @param target_list_name name of the input ParticleList
2563 @param mask_name name of the ROEMask to be used
2564 @param path modules are added to this path
2567 roeBuilder = register_module(
'RestOfEventBuilder')
2568 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
2569 roeBuilder.param(
'particleList', target_list_name)
2570 roeBuilder.param(
'nestedROEMask', maskName)
2571 roeBuilder.param(
'createNestedROE',
True)
2572 path.add_module(roeBuilder)
2575def buildRestOfEventFromMC(target_list_name, inputParticlelists=None, path=None):
2577 Creates for each Particle in the given ParticleList a RestOfEvent
2578 @param target_list_name name of the input ParticleList
2579 @param inputParticlelists list of input particle list names, which serve
2580 as a source of particles to build ROE, the FSP particles from
2581 target_list_name are excluded from ROE object
2582 @param path modules are added to this path
2585 if inputParticlelists
is None:
2586 inputParticlelists = []
2587 if (len(inputParticlelists) == 0):
2591 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
2592 'n0',
'nu_e',
'nu_mu',
'nu_tau',
2595 fillParticleListFromMC(f
"{t}:roe_default_gen",
'mcPrimary > 0 and nDaughters == 0',
2596 True,
True, path=path)
2597 inputParticlelists += [f
"{t}:roe_default_gen"]
2598 roeBuilder = register_module(
'RestOfEventBuilder')
2599 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
2600 roeBuilder.param(
'particleList', target_list_name)
2601 roeBuilder.param(
'particleListsInput', inputParticlelists)
2602 roeBuilder.param(
'fromMC',
True)
2603 path.add_module(roeBuilder)
2606def appendROEMask(list_name,
2609 eclClusterSelection,
2610 klmClusterSelection='',
2613 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2614 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
2616 - append a ROE mask with all tracks in ROE coming from the IP region
2618 .. code-block:: python
2620 appendROEMask('B+:sig', 'IPtracks', '[dr < 2] and [abs(dz) < 5]', path=mypath)
2622 - append a ROE mask with only ECL-based particles that pass as good photon candidates
2624 .. code-block:: python
2626 goodPhotons = 'inCDCAcceptance and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
2627 appendROEMask('B+:sig', 'goodROEGamma', '', goodPhotons, path=mypath)
2630 @param list_name name of the input ParticleList
2631 @param mask_name name of the appended ROEMask
2632 @param trackSelection decay string for the track-based particles in ROE
2633 @param eclClusterSelection decay string for the ECL-based particles in ROE
2634 @param klmClusterSelection decay string for the KLM-based particles in ROE
2635 @param path modules are added to this path
2638 roeMask = register_module(
'RestOfEventInterpreter')
2639 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2640 roeMask.param(
'particleList', list_name)
2641 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2642 path.add_module(roeMask)
2645def appendROEMasks(list_name, mask_tuples, path=None):
2647 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2648 selection criteria for track-, ECL- and KLM-based particles which will be used by ROE variables.
2650 The multiple ROE masks with their own selection criteria are specified
2651 via list of tuples (mask_name, trackParticleSelection, eclParticleSelection, klmParticleSelection) or
2652 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
2654 - Example for two tuples, one with and one without fractions
2656 .. code-block:: python
2658 ipTracks = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', '')
2659 goodPhotons = 'inCDCAcceptance and [clusterErrorTiming < 1e6] and [clusterE1E9 > 0.4 or E > 0.075]'
2660 goodROEGamma = ('ROESel', '[dr < 2] and [abs(dz) < 5]', goodPhotons, '')
2661 goodROEKLM = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', 'nKLMClusterTrackMatches == 0')
2662 appendROEMasks('B+:sig', [ipTracks, goodROEGamma, goodROEKLM], path=mypath)
2664 @param list_name name of the input ParticleList
2665 @param mask_tuples array of ROEMask list tuples to be appended
2666 @param path modules are added to this path
2669 compatible_masks = []
2670 for mask
in mask_tuples:
2673 compatible_masks += [(*mask,
'')]
2675 compatible_masks += [mask]
2676 roeMask = register_module(
'RestOfEventInterpreter')
2677 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2678 roeMask.param(
'particleList', list_name)
2679 roeMask.param(
'ROEMasks', compatible_masks)
2680 path.add_module(roeMask)
2683def updateROEMask(list_name,
2686 eclClusterSelection='',
2687 klmClusterSelection='',
2690 Update an existing ROE mask by applying additional selection cuts for
2691 tracks and/or clusters.
2693 See function `appendROEMask`!
2695 @param list_name name of the input ParticleList
2696 @param mask_name name of the ROEMask to update
2697 @param trackSelection decay string for the track-based particles in ROE
2698 @param eclClusterSelection decay string for the ECL-based particles in ROE
2699 @param klmClusterSelection decay string for the KLM-based particles in ROE
2700 @param path modules are added to this path
2703 roeMask = register_module(
'RestOfEventInterpreter')
2704 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2705 roeMask.param(
'particleList', list_name)
2706 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2707 roeMask.param(
'update',
True)
2708 path.add_module(roeMask)
2711def updateROEMasks(list_name, mask_tuples, path):
2713 Update existing ROE masks by applying additional selection cuts for tracks
2716 The multiple ROE masks with their own selection criteria are specified
2717 via list tuples (mask_name, trackSelection, eclClusterSelection, klmClusterSelection)
2719 See function `appendROEMasks`!
2721 @param list_name name of the input ParticleList
2722 @param mask_tuples array of ROEMask list tuples to be appended
2723 @param path modules are added to this path
2726 compatible_masks = []
2727 for mask
in mask_tuples:
2730 compatible_masks += [(*mask,
'')]
2732 compatible_masks += [mask]
2734 roeMask = register_module(
'RestOfEventInterpreter')
2735 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2736 roeMask.param(
'particleList', list_name)
2737 roeMask.param(
'ROEMasks', compatible_masks)
2738 roeMask.param(
'update',
True)
2739 path.add_module(roeMask)
2742def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2744 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2745 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2746 This function should be executed only in the for_each roe path for the current ROE object.
2748 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2749 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2750 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2751 pion particle list (e.g. 'pi+:someLabel').
2753 Updating a non-existing mask will create a new one.
2755 - keep only those tracks that were used in provided particle list
2757 .. code-block:: python
2759 keepInROEMasks('pi+:goodTracks', 'mask', '', path=mypath)
2761 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2763 .. code-block:: python
2765 keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1', path=mypath)
2768 @param list_name name of the input ParticleList
2769 @param mask_names array of ROEMasks to be updated
2770 @param cut_string decay string with which the mask will be updated
2771 @param path modules are added to this path
2774 updateMask = register_module(
'RestOfEventUpdater')
2775 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2776 updateMask.param(
'particleList', list_name)
2777 updateMask.param(
'updateMasks', mask_names)
2778 updateMask.param(
'cutString', cut_string)
2779 updateMask.param(
'discard',
False)
2780 path.add_module(updateMask)
2783def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2785 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2786 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2787 This function should be executed only in the for_each roe path for the current ROE object.
2789 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2790 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2791 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2792 pion particle list (e.g. 'pi+:someLabel').
2794 Updating a non-existing mask will create a new one.
2796 - discard tracks that were used in provided particle list
2798 .. code-block:: python
2800 discardFromROEMasks('pi+:badTracks', 'mask', '', path=mypath)
2802 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2804 .. code-block:: python
2806 discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1', path=mypath)
2809 @param list_name name of the input ParticleList
2810 @param mask_names array of ROEMasks to be updated
2811 @param cut_string decay string with which the mask will be updated
2812 @param path modules are added to this path
2815 updateMask = register_module(
'RestOfEventUpdater')
2816 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2817 updateMask.param(
'particleList', list_name)
2818 updateMask.param(
'updateMasks', mask_names)
2819 updateMask.param(
'cutString', cut_string)
2820 updateMask.param(
'discard',
True)
2821 path.add_module(updateMask)
2824def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2826 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2827 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2828 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2829 passing it can be applied.
2831 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2832 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2834 Updating a non-existing mask will create a new one.
2836 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2838 .. code-block:: python
2840 optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550', path=mypath)
2842 @param list_name name of the input ParticleList
2843 @param mask_names array of ROEMasks to be updated
2844 @param cut_string decay string with which the mask will be updated
2845 @param path modules are added to this path
2848 updateMask = register_module(
'RestOfEventUpdater')
2849 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2850 updateMask.param(
'particleList', list_name)
2851 updateMask.param(
'updateMasks', mask_names)
2852 updateMask.param(
'cutString', cut_string)
2853 path.add_module(updateMask)
2856def updateROEUsingV0Lists(target_particle_list, mask_names, default_cleanup=True, selection_cuts=None,
2857 apply_mass_fit=False, fitter='treefit', path=None):
2859 This function creates V0 particle lists (photons, :math:`K^0_S` and :math:`\\Lambda^0`)
2860 and it uses V0 candidates to update the Rest Of Event, which is associated to the target particle list.
2861 It is possible to apply a standard or customized selection and mass fit to the V0 candidates.
2864 @param target_particle_list name of the input ParticleList
2865 @param mask_names array of ROE masks to be applied
2866 @param default_cleanup if True, predefined cuts will be applied on the V0 lists
2867 @param selection_cuts a single string of selection cuts or tuple of three strings (photon_cuts, K_S0_cuts, Lambda0_cuts),
2868 which will be applied to the V0 lists. These cuts will have a priority over the default ones.
2869 @param apply_mass_fit if True, a mass fit will be applied to the V0 particles
2870 @param fitter string, that represent a fitter choice: "treefit" for TreeFitter and "kfit" for KFit
2871 @param path modules are added to this path
2874 roe_path = create_path()
2875 deadEndPath = create_path()
2876 signalSideParticleFilter(target_particle_list,
'', roe_path, deadEndPath)
2878 if (default_cleanup
and selection_cuts
is None):
2879 B2INFO(
"Using default cleanup in updateROEUsingV0Lists.")
2880 selection_cuts =
'abs(dM) < 0.1 '
2881 selection_cuts +=
'and daughter(0,particleID) > 0.2 and daughter(1,particleID) > 0.2 '
2882 selection_cuts +=
'and daughter(0,thetaInCDCAcceptance) and daughter(1,thetaInCDCAcceptance)'
2883 if (selection_cuts
is None or selection_cuts ==
''):
2884 B2INFO(
"No cleanup in updateROEUsingV0Lists.")
2885 selection_cuts = (
'True',
'True',
'True')
2886 if (isinstance(selection_cuts, str)):
2887 selection_cuts = (selection_cuts, selection_cuts, selection_cuts)
2889 roe_cuts =
'isInRestOfEvent > 0'
2890 fillConvertedPhotonsList(
'gamma:v0_roe -> e+ e-', f
'{selection_cuts[0]} and {roe_cuts}',
2892 fillParticleList(
'K_S0:v0_roe -> pi+ pi-', f
'{selection_cuts[1]} and {roe_cuts}',
2894 fillParticleList(
'Lambda0:v0_roe -> p+ pi-', f
'{selection_cuts[2]} and {roe_cuts}',
2896 fitter = fitter.lower()
2897 if (fitter !=
'treefit' and fitter !=
'kfit'):
2898 B2WARNING(
'Argument "fitter" in updateROEUsingV0Lists has only "treefit" and "kfit" options, '
2899 f
'but "{fitter}" was provided! TreeFitter will be used instead.')
2901 from vertex
import kFit, treeFit
2902 for v0
in [
'gamma:v0_roe',
'K_S0:v0_roe',
'Lambda0:v0_roe']:
2903 if (apply_mass_fit
and fitter ==
'kfit'):
2904 kFit(v0, conf_level=0.0, fit_type=
'massvertex', path=roe_path)
2905 if (apply_mass_fit
and fitter ==
'treefit'):
2906 treeFit(v0, conf_level=0.0, massConstraint=[v0.split(
':')[0]], path=roe_path)
2907 optimizeROEWithV0(v0, mask_names,
'', path=roe_path)
2908 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2911def printROEInfo(mask_names=None, full_print=False,
2912 unpackComposites=True, path=None):
2914 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2915 It prints out basic ROE object info.
2917 If mask names are provided, specific information for those masks will be printed out.
2919 It is also possible to print out all particles in a given mask if the
2920 'full_print' is set to True.
2922 @param mask_names array of ROEMask names for printing out info
2923 @param unpackComposites if true, replace composite particles by their daughters
2924 @param full_print print out particles in mask
2925 @param path modules are added to this path
2928 if mask_names
is None:
2930 printMask = register_module(
'RestOfEventPrinter')
2931 printMask.set_name(
'RestOfEventPrinter')
2932 printMask.param(
'maskNames', mask_names)
2933 printMask.param(
'fullPrint', full_print)
2934 printMask.param(
'unpackComposites', unpackComposites)
2935 path.add_module(printMask)
2938def buildContinuumSuppression(list_name, roe_mask, path):
2940 Creates for each Particle in the given ParticleList a ContinuumSuppression
2941 dataobject and makes basf2 relation between them.
2943 :param list_name: name of the input ParticleList
2944 :param roe_mask: name of the ROE mask
2945 :param path: modules are added to this path
2948 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2949 qqBuilder.set_name(
'QQBuilder_' + list_name)
2950 qqBuilder.param(
'particleList', list_name)
2951 qqBuilder.param(
'ROEMask', roe_mask)
2952 path.add_module(qqBuilder)
2957 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2958 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2960 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2961 @param path modules are added to this path
2964 mod = register_module(
'RemoveParticlesNotInLists')
2965 mod.param(
'particleLists', lists_to_keep)
2966 path.add_module(mod)
2969def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2971 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2973 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2974 @param bsig_list_name Name of the Bsig ParticleList
2975 @param btag_list_name Name of the Bsig ParticleList
2976 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2979 btag = register_module(
'InclusiveBtagReconstruction')
2980 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2981 btag.param(
'upsilonListName', upsilon_list_name)
2982 btag.param(
'bsigListName', bsig_list_name)
2983 btag.param(
'btagListName', btag_list_name)
2984 btag.param(
'inputListsNames', input_lists_names)
2985 path.add_module(btag)
2988def selectDaughters(particle_list_name, decay_string, path):
2990 Redefine the Daughters of a particle: select from decayString
2992 @param particle_list_name input particle list
2993 @param decay_string for selecting the Daughters to be preserved
2996 seld = register_module(
'SelectDaughters')
2997 seld.set_name(
'SelectDaughters_' + particle_list_name)
2998 seld.param(
'listName', particle_list_name)
2999 seld.param(
'decayString', decay_string)
3000 path.add_module(seld)
3003def markDuplicate(particleList, prioritiseV0, path):
3005 Call DuplicateVertexMarker to find duplicate particles in a list and
3006 flag the ones that should be kept
3008 @param particleList input particle list
3009 @param prioritiseV0 if true, give V0s a higher priority
3012 markdup = register_module(
'DuplicateVertexMarker')
3013 markdup.param(
'particleList', particleList)
3014 markdup.param(
'prioritiseV0', prioritiseV0)
3015 path.add_module(markdup)
3018PI0ETAVETO_COUNTER = 0
3021def oldwritePi0EtaVeto(
3024 workingDirectory='.',
3025 pi0vetoname='Pi0_Prob',
3026 etavetoname='Eta_Prob',
3032 Give pi0/eta probability for hard photon.
3034 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.
3036 The current default weight files are optimised using MC9.
3037 The input variables are as below. Aliases are set to some variables during training.
3039 * M: pi0/eta candidates Invariant mass
3040 * lowE: soft photon energy in lab frame
3041 * cTheta: soft photon ECL cluster's polar angle
3042 * Zmva: soft photon output of MVA using Zernike moments of the cluster
3043 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3045 If you don't have weight files in your workingDirectory,
3046 these files are downloaded from database to your workingDirectory automatically.
3047 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
3048 about how to use this function.
3051 Please don't use following ParticleList names elsewhere:
3053 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
3054 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
3056 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
3058 @param particleList The input ParticleList
3059 @param decayString specify Particle to be added to the ParticleList
3060 @param workingDirectory The weight file directory
3061 @param downloadFlag whether download default weight files or not
3062 @param pi0vetoname extraInfo name of pi0 probability
3063 @param etavetoname extraInfo name of eta probability
3064 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
3065 @param path modules are added to this path
3070 B2ERROR(
"The old pi0 / eta veto is not suitable for Belle analyses.")
3075 global PI0ETAVETO_COUNTER
3077 if PI0ETAVETO_COUNTER == 0:
3078 from variables
import variables
3079 variables.addAlias(
'lowE',
'daughter(1,E)')
3080 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
3081 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
3082 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
3083 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
3084 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
3086 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
3088 roe_path = create_path()
3090 deadEndPath = create_path()
3092 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3094 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
3096 pi0softname =
'gamma:PI0SOFT'
3097 etasoftname =
'gamma:ETASOFT'
3098 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
3099 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
3103 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
3105 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
3108 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
3110 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
3112 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
3113 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
3115 if not os.path.isdir(workingDirectory):
3116 os.mkdir(workingDirectory)
3117 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
3119 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
3121 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
3122 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
3124 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
3126 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
3127 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
3129 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
3130 identifier=workingDirectory +
'/pi0veto.root')
3131 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
3132 identifier=workingDirectory +
'/etaveto.root')
3134 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
3135 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
3137 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
3138 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
3140 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3146 mode='standardMC15rd',
3150 hardParticle='gamma',
3151 pi0PayloadNameOverride=None,
3152 pi0SoftPhotonCutOverride=None,
3153 etaPayloadNameOverride=None,
3154 etaSoftPhotonCutOverride=None,
3155 requireSoftPhotonIsInROE=False,
3156 pi0Selection='[0.03 < M < 0.23]',
3157 etaSelection='[0.25 < M < 0.75]'
3160 Give pi0/eta probability for hard photon.
3162 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.
3163 For MC15rd weight files, the BtoXGamma skim is applied during the MVA training.
3165 The current default weight files are optimised using MC15rd. The weight files for MC12 (last version) are still available.
3167 The input variables of the mva training for pi0 veto using MC15rd are:
3169 * M: Invariant mass of pi0 candidates
3170 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons in the pi0 rest frame
3171 and momentum of pi0 in lab frame
3172 * daughter(1,E): soft photon energy in lab frame
3173 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3174 * daughter(1,clusterLAT): soft photon lateral energy distribution
3176 The input variables of the mva training for eta veto using MC15rd are:
3178 * M: Invariant mass of eta candidates
3179 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons in the eta rest frame
3180 and momentum of eta in lab frame
3181 * daughter(1,E): soft photon energy in lab frame
3182 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3183 * daughter(1,clusterLAT): soft photon lateral energy distribution
3184 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
3185 * daughter(1,clusterE1E9): soft photon ratio between energies of central crystal and inner 3x3 crystals
3186 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
3187 * daughter(1,clusterSecondMoment): soft photon second moment
3188 * daughter(1,clusterAbsZernikeMoment40): soft photon Zernike moment 40
3189 * daughter(1,clusterAbsZernikeMoment51): soft photon Zernike moment 51
3191 The input variables of the mva training using MC12 are:
3193 * M: Invariant mass of pi0/eta candidates
3194 * daughter(1,E): soft photon energy in lab frame
3195 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3196 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3197 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
3198 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
3199 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
3200 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons in the pi0/eta rest frame
3201 and momentum of pi0/eta in lab frame
3203 The following strings are available for mode:
3205 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
3206 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
3207 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
3208 * both: tight energy cut and clusterNHits cut are applied to soft photon
3209 * standardMC15rd: loose energy cut is applied to soft photon and the weight files are trained using MC15rd
3210 * tightMC15rd: tight energy cut is applied to soft photon and the weight files are trained using MC15rd
3212 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
3213 `pi0Prob`/`etaProb`. Otherwise, it is available as '{Pi0, Eta}ProbOrigin', '{Pi0, Eta}ProbTightEnergyThreshold', '{Pi0,
3214 Eta}ProbLargeClusterSize', '{Pi0, Eta}ProbTightEnergyThresholdAndLargeClusterSize', '{Pi0, Eta}ProbOriginMC15rd', or
3215 '{Pi0, Eta}ProbTightEnergyThresholdMC15rd' for the six modes described above, with the chosen suffix appended. If one would
3216 like to call this veto twice in one script, add suffix in the second time!
3217 The second highest probability of the pi0/eta veto also is stored as an extraInfo, with a prefix of 'second' to the previous
3218 ones, e.g. secondPi0ProbOrigin{suffix}. This can be used to do validation/systematics study.
3221 Please don't use following ParticleList names elsewhere:
3223 ``gamma:HardPhoton``,
3224 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
3225 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
3226 ``pi0:EtaVeto + ListName``,
3227 ``eta:EtaVeto + ListName``
3229 @param particleList the input ParticleList
3230 @param decayString specify Particle to be added to the ParticleList
3231 @param mode choose one mode out of 'standardMC15rd', 'tightMC15rd', 'standard', 'tight', 'cluster' and 'both'
3232 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
3233 @param path modules are added to this path
3234 @param suffix optional suffix to be appended to the usual extraInfo name
3235 @param hardParticle particle name which is used to calculate the pi0/eta probability (default is gamma)
3236 @param pi0PayloadNameOverride specify the payload name of pi0 veto only if one wants to use non-default one. (default is None)
3237 @param pi0SoftPhotonCutOverride specify the soft photon selection criteria of pi0 veto only if one wants to use non-default one.
3239 @param etaPayloadNameOverride specify the payload name of eta veto only if one wants to use non-default one. (default is None)
3240 @param etaSoftPhotonCutOverride specify the soft photon selection criteria of eta veto only if one wants to use non-default one.
3242 @param requireSoftPhotonIsInROE specify if the soft photons used to build pi0 and eta candidates have to be in the current ROE
3243 or not. Default is False, i.e. all soft photons in the event are used.
3244 @param pi0Selection Selection for the pi0 reconstruction. Default is '(0.03 < M < 0.23)'.
3245 @param etaSelection Selection for the eta reconstruction. Default is '(0.25 < M < 0.75)'.
3250 B2ERROR(
"The pi0 / eta veto is not suitable for Belle analyses.")
3252 if (requireSoftPhotonIsInROE):
3253 B2WARNING(
"Requiring the soft photon to being in the ROE was not done for the MVA training. "
3254 "Please check the results carefully.")
3255 if (mode ==
'standardMC15rd' or mode ==
'tightMC15rd'):
3256 if (pi0Selection !=
'[0.03 < M < 0.23]' or etaSelection !=
'[0.25 < M < 0.75]'):
3258 "Personal selection criteria for the pi0 or the eta during reconstructDecay were not used during the MVA training. "
3259 "Please check the results carefully.")
3261 if (pi0Selection !=
'' or etaSelection !=
''):
3263 "Personal selection criteria for the pi0 or the eta during reconstructDecay were not used during the MVA training. "
3264 "Please check the results carefully.")
3266 renameSuffix =
False
3268 for module
in path.modules():
3269 if module.type() ==
"SubEvent" and not renameSuffix:
3270 for subpath
in [p.values
for p
in module.available_params()
if p.name ==
"path"]:
3273 for submodule
in subpath.modules():
3274 if f
'{hardParticle}:HardPhoton{suffix}' in submodule.name():
3276 B2WARNING(
"Same extension already used in writePi0EtaVeto, append '_0'")
3280 roe_path = create_path()
3281 deadEndPath = create_path()
3282 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3283 fillSignalSideParticleList(f
'{hardParticle}:HardPhoton{suffix}', decayString, path=roe_path)
3285 dictListName = {
'standard':
'Origin',
3286 'tight':
'TightEnergyThreshold',
3287 'cluster':
'LargeClusterSize',
3288 'both':
'TightEnrgyThresholdAndLargeClusterSize',
3289 'standardMC15rd':
'OriginMC15rd',
3290 'tightMC15rd':
'TightEnergyThresholdMC15rd'}
3292 dictPi0EnergyCut = {
3293 'standard':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3294 'tight':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3295 'cluster':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3296 'both':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3297 'standardMC15rd':
'[[clusterReg==1 and E>0.0225] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3298 'tightMC15rd':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3300 dictEtaEnergyCut = {
3301 'standard':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3302 'tight':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3303 'cluster':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3304 'both':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3305 'standardMC15rd':
'[[clusterReg==1 and E>0.0225] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3306 'tightMC15rd':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3308 dictNHitsTimingCut = {
'standard':
'clusterNHits >= 0 and abs(clusterTiming)<clusterErrorTiming',
3309 'tight':
'clusterNHits >= 0 and abs(clusterTiming)<clusterErrorTiming',
3310 'cluster':
'clusterNHits >= 2 and abs(clusterTiming)<clusterErrorTiming',
3311 'both':
'clusterNHits >= 2 and abs(clusterTiming)<clusterErrorTiming',
3312 'standardMC15rd':
'clusterNHits > 1.5 and abs(clusterTiming) < 200',
3313 'tightMC15rd':
'clusterNHits > 1.5 and abs(clusterTiming) < 200'}
3315 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
3316 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
3317 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
3318 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize',
3319 'standardMC15rd':
'Pi0VetoIdentifierStandardMC15rd',
3320 'tightMC15rd':
'Pi0VetoIdentifierWithHigherEnergyThresholdMC15rd'}
3322 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
3323 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
3324 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
3325 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize',
3326 'standardMC15rd':
'EtaVetoIdentifierStandardMC15rd',
3327 'tightMC15rd':
'EtaVetoIdentifierWithHigherEnergyThresholdMC15rd'}
3329 dictPi0ExtraInfoName = {
'standard':
'Pi0ProbOrigin',
3330 'tight':
'Pi0ProbTightEnergyThreshold',
3331 'cluster':
'Pi0ProbLargeClusterSize',
3332 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize',
3333 'standardMC15rd':
'Pi0ProbOriginMC15rd',
3334 'tightMC15rd':
'Pi0ProbTightEnergyThresholdMC15rd'}
3336 dictEtaExtraInfoName = {
'standard':
'EtaProbOrigin',
3337 'tight':
'EtaProbTightEnergyThreshold',
3338 'cluster':
'EtaProbLargeClusterSize',
3339 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize',
3340 'standardMC15rd':
'EtaProbOriginMC15rd',
3341 'tightMC15rd':
'EtaProbTightEnergyThresholdMC15rd'}
3343 ListName = dictListName[mode]
3344 Pi0EnergyCut = dictPi0EnergyCut[mode]
3345 EtaEnergyCut = dictEtaEnergyCut[mode]
3346 NHitsTimingCut = dictNHitsTimingCut[mode]
3347 Pi0PayloadName = dictPi0PayloadName[mode]
3348 EtaPayloadName = dictEtaPayloadName[mode]
3349 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
3350 EtaExtraInfoName = dictEtaExtraInfoName[mode]
3353 if pi0PayloadNameOverride
is not None:
3354 Pi0PayloadName = pi0PayloadNameOverride
3355 B2WARNING(
"You're using personal weight files, be careful. ")
3356 if pi0SoftPhotonCutOverride
is None:
3357 Pi0SoftPhotonCut = Pi0EnergyCut +
' and ' + NHitsTimingCut
3359 Pi0SoftPhotonCut = pi0SoftPhotonCutOverride
3360 B2WARNING(
"You're applying personal cuts on the soft photon candidates, be careful. ")
3362 if requireSoftPhotonIsInROE:
3363 Pi0SoftPhotonCut +=
' and isInRestOfEvent==1'
3366 pi0soft = f
'gamma:Pi0Soft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3368 fillParticleList(pi0soft, Pi0SoftPhotonCut, path=roe_path)
3370 reconstructDecay(
'pi0:Pi0Veto' + ListName + suffix + f
' -> {hardParticle}:HardPhoton{suffix} ' + pi0soft, pi0Selection,
3371 allowChargeViolation=
True, path=roe_path)
3373 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName + suffix],
3374 extraInfoName=Pi0ExtraInfoName, identifier=Pi0PayloadName)
3377 'pi0:Pi0Veto' + ListName + suffix,
3378 'extraInfo(' + Pi0ExtraInfoName +
')',
3380 outputVariable=
"Pi0VetoRank",
3382 cutAndCopyList(outputListName=
'pi0:Pi0VetoFirst' + ListName + suffix,
3383 inputListName=
'pi0:Pi0Veto' + ListName + suffix,
3384 cut=
'extraInfo(Pi0VetoRank)==1',
3386 variableToSignalSideExtraInfo(
'pi0:Pi0VetoFirst' + ListName + suffix,
3387 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoName + suffix}, path=roe_path)
3389 cutAndCopyList(outputListName=
'pi0:Pi0VetoSecond' + ListName + suffix,
3390 inputListName=
'pi0:Pi0Veto' + ListName + suffix,
3391 cut=
'extraInfo(Pi0VetoRank)==2',
3393 variableToSignalSideExtraInfo(
'pi0:Pi0VetoSecond' + ListName + suffix,
3394 {
'extraInfo(' + Pi0ExtraInfoName +
')':
'second' + Pi0ExtraInfoName + suffix}, path=roe_path)
3397 if etaPayloadNameOverride
is not None:
3398 EtaPayloadName = etaPayloadNameOverride
3399 B2WARNING(
"You're using personal weight files, be careful. ")
3400 if etaSoftPhotonCutOverride
is None:
3401 EtaSoftPhotonCut = EtaEnergyCut +
' and ' + NHitsTimingCut
3403 EtaSoftPhotonCut = etaSoftPhotonCutOverride
3404 B2WARNING(
"You're applying personal cuts on the soft photon candidates, be careful. ")
3406 if requireSoftPhotonIsInROE:
3407 EtaSoftPhotonCut +=
' and isInRestOfEvent==1'
3409 etasoft = f
'gamma:EtaSoft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3410 fillParticleList(etasoft, EtaSoftPhotonCut, path=roe_path)
3411 reconstructDecay(
'eta:EtaVeto' + ListName + suffix + f
' -> {hardParticle}:HardPhoton{suffix} ' + etasoft, etaSelection,
3412 allowChargeViolation=
True, path=roe_path)
3413 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName + suffix],
3414 extraInfoName=EtaExtraInfoName, identifier=EtaPayloadName)
3416 'eta:EtaVeto' + ListName + suffix,
3417 'extraInfo(' + EtaExtraInfoName +
')',
3419 outputVariable=
"EtaVetoRank",
3421 cutAndCopyList(outputListName=
'eta:EtaVetoFirst' + ListName + suffix,
3422 inputListName=
'eta:EtaVeto' + ListName + suffix,
3423 cut=
'extraInfo(EtaVetoRank)==1',
3425 variableToSignalSideExtraInfo(
'eta:EtaVetoFirst' + ListName + suffix,
3426 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoName + suffix}, path=roe_path)
3427 cutAndCopyList(outputListName=
'eta:EtaVetoSecond' + ListName + suffix,
3428 inputListName=
'eta:EtaVeto' + ListName + suffix,
3429 cut=
'extraInfo(EtaVetoRank)==2',
3431 variableToSignalSideExtraInfo(
'eta:EtaVetoSecond' + ListName + suffix,
3432 {
'extraInfo(' + EtaExtraInfoName +
')':
'second' + EtaExtraInfoName + suffix}, path=roe_path)
3434 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3437def lowEnergyPi0Identification(pi0List, gammaList, payloadNameSuffix,
3440 Calculate low-energy pi0 identification.
3441 The result is stored as ExtraInfo ``lowEnergyPi0Identification`` for
3445 pi0List (str): Pi0 list.
3447 gammaList (str): Gamma list. First, an energy cut E > 0.2 is applied to the photons from this list.
3448 Then, all possible combinations with a pi0 daughter photon are formed except the one
3449 corresponding to the reconstructed pi0.
3450 The maximum low-energy pi0 veto value is calculated for such photon pairs
3451 and used as one of the input variables for the identification classifier.
3453 payloadNameSuffix (str): Payload name suffix. The weight payloads are stored in the analysis global
3454 tag and have the following names:\n
3455 * ``'LowEnergyPi0Veto' + payloadNameSuffix``
3456 * ``'LowEnergyPi0Identification' + payloadNameSuffix``\n
3457 The possible suffixes are:\n
3458 * ``'Belle1'`` for Belle data.
3459 * ``'Belle2Release5'`` for Belle II release 5 data (MC14, proc12, buckets 16 - 25).
3460 * ``'Belle2Release6'`` for Belle II release 6 data (MC15, proc13, buckets 26 - 36).
3462 path (basf2.Path): Module path.
3466 gammaListVeto = f
'{gammaList}_pi0veto'
3467 cutAndCopyList(gammaListVeto, gammaList,
'E > 0.2', path=path)
3469 payload_name =
'LowEnergyPi0Veto' + payloadNameSuffix
3470 path.add_module(
'LowEnergyPi0VetoExpert', identifier=payload_name,
3471 VetoPi0Daughters=
True, GammaListName=gammaListVeto,
3473 payload_name =
'LowEnergyPi0Identification' + payloadNameSuffix
3474 path.add_module(
'LowEnergyPi0IdentificationExpert',
3475 identifier=payload_name, Pi0ListName=pi0List,
3479def getNeutralHadronGeomMatches(
3483 efficiencyCorrectionKl=0.83,
3484 efficiencyCorrectionNeutrons=1.0,
3487 For an ECL-based list, assign the mcdistanceKL and mcdistanceNeutron variables that correspond
3488 to the distance to the closest MC KL and neutron, respectively.
3489 @param particleLists the input ParticleLists, must be ECL-based lists (e.g. photons)
3490 @param addKL (default True) add distance to MC KL
3491 @param addNeutrons (default False) add distance to MC neutrons
3492 @param efficiencyCorrectionKl (default 0.83) apply overall efficiency correction
3493 @param efficiencyCorrectionNeutrons (default 1.0) apply overall efficiency correction
3494 @param path modules are added to this path
3496 from ROOT
import Belle2
3501 "NeutralHadronMatcher",
3502 particleLists=particleLists,
3503 mcPDGcode=Const.Klong.getPDGCode(),
3504 efficiencyCorrection=efficiencyCorrectionKl)
3507 "NeutralHadronMatcher",
3508 particleLists=particleLists,
3509 mcPDGcode=Const.neutron.getPDGCode(),
3510 efficiencyCorrection=efficiencyCorrectionNeutrons)
3513def getBeamBackgroundProbability(particleList, weight, path=None):
3515 Assign a probability to each ECL cluster as being signal like (1) compared to beam background like (0)
3516 @param particleList the input ParticleList, must be a photon list
3517 @param weight type of weight file to use
3518 @param path modules are added to this path
3523 B2WARNING(
"weight type must be 'Belle' for b2bii.")
3525 path.add_module(
'MVAExpert',
3526 listNames=particleList,
3527 extraInfoName=
'beamBackgroundSuppression',
3528 identifier=f
'BeamBackgroundMVA_{weight}')
3531def getFakePhotonProbability(particleList, weight, path=None):
3533 Assign a probability to each ECL cluster as being signal like (1) compared to fake photon like (0)
3534 @param particleList the input ParticleList, must be a photon list
3535 @param weight type of weight file to use
3536 @param path modules are added to this path
3541 B2WARNING(
"weight type must be 'Belle' for b2bii.")
3543 path.add_module(
'MVAExpert',
3544 listNames=particleList,
3545 extraInfoName=
'fakePhotonSuppression',
3546 identifier=f
'FakePhotonMVA_{weight}')
3549def buildEventKinematics(inputListNames=None, default_cleanup=True, custom_cuts=None,
3550 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
3552 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3553 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
3554 (all track and all hits in ECL without associated track).
3556 The visible energy missing values are
3557 stored in a EventKinematics dataobject.
3559 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3560 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
3561 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
3562 according to the PID likelihood and the option inputListNames will be ignored.
3563 @param chargedPIDPriors The prior PID fractions, that are used to regulate
3564 amount of certain charged particle species, should be a list of
3565 six floats if not None. The order of particle types is
3566 the following: [e-, mu-, pi-, K-, p+, d+]
3567 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
3568 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3569 which would result in a standard predefined selection cuts
3570 @param path modules are added to this path
3573 if inputListNames
is None:
3575 trackCuts =
'pt > 0.1'
3576 trackCuts +=
' and thetaInCDCAcceptance'
3577 trackCuts +=
' and abs(dz) < 3'
3578 trackCuts +=
' and dr < 0.5'
3580 gammaCuts =
'E > 0.05'
3581 gammaCuts +=
' and thetaInCDCAcceptance'
3583 gammaCuts +=
' and abs(clusterTiming) < 200'
3584 if (custom_cuts
is not None):
3585 trackCuts, gammaCuts = custom_cuts
3587 if fillWithMostLikely:
3588 from stdCharged
import stdMostLikely
3589 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
3590 inputListNames = [f
'{ptype}:mostlikely_evtkin' for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
3592 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3594 fillParticleList(
'gamma:evtkin',
'', path=path)
3595 inputListNames += [
'gamma:evtkin']
3597 B2INFO(
"Using default cleanup in EventKinematics module.")
3598 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
3599 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
3600 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3602 B2INFO(
"No cleanup in EventKinematics module.")
3603 if not inputListNames:
3604 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
3605 fillParticleList(
'pi+:evtkin',
'', path=path)
3607 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3609 fillParticleList(
'gamma:evtkin',
'', path=path)
3610 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
3612 if (custom_cuts
is not None):
3613 B2INFO(
"Using default cleanup in EventKinematics module.")
3614 applyCuts(
'pi+:evtkin', trackCuts, path=path)
3615 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3617 B2INFO(
"No cleanup in EventKinematics module.")
3619 particleLists = inputListNames
3621 eventKinematicsModule = register_module(
'EventKinematics')
3622 eventKinematicsModule.set_name(
'EventKinematics_reco')
3623 eventKinematicsModule.param(
'particleLists', particleLists)
3624 path.add_module(eventKinematicsModule)
3627def buildEventKinematicsFromMC(inputListNames=None, selectionCut='', path=None):
3629 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3630 using generated particles. If no ParticleList is provided, default generated ParticleLists are used.
3632 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3633 If the list is empty, default ParticleLists are filled.
3634 @param selectionCut optional selection cuts
3635 @param path Path to append the eventKinematics module to.
3638 if inputListNames
is None:
3640 if (len(inputListNames) == 0):
3644 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
3647 fillParticleListFromMC(f
"{t}:evtkin_default_gen",
'mcPrimary > 0 and nDaughters == 0',
3648 True,
True, path=path)
3649 if (selectionCut !=
''):
3650 applyCuts(f
"{t}:evtkin_default_gen", selectionCut, path=path)
3651 inputListNames += [f
"{t}:evtkin_default_gen"]
3653 eventKinematicsModule = register_module(
'EventKinematics')
3654 eventKinematicsModule.set_name(
'EventKinematics_gen')
3655 eventKinematicsModule.param(
'particleLists', inputListNames)
3656 eventKinematicsModule.param(
'usingMC',
True)
3657 path.add_module(eventKinematicsModule)
3660def buildEventShape(inputListNames=None,
3661 default_cleanup=True,
3667 harmonicMoments=True,
3671 checkForDuplicates=False,
3674 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
3675 using the particles in the lists provided by the user. If no particle list is provided,
3676 the function will internally create a list of good tracks and a list of good photons
3677 with (optionally) minimal quality cuts.
3680 The results of the calculation are then stored into the EventShapeContainer dataobject,
3681 and are accessible using the variables of the EventShape group.
3683 The user can switch the calculation of certain quantities on or off to save computing
3684 time. By default the calculation of the high-order moments (5-8) is turned off.
3685 Switching off an option will make the corresponding variables not available.
3688 The user can provide as many particle lists as needed, using also composite particles.
3689 In these cases, it is recommended to activate the checkForDuplicates flag since it
3690 will eliminate duplicates, e.g., if the same track is provided multiple times
3691 (either with different mass hypothesis or once as an independent particle and once
3692 as daughter of a composite particle). The first occurrence will be used in the
3693 calculations so the order in which the particle lists are given as well as within
3694 the particle lists matters.
3696 @param inputListNames List of ParticleLists used to calculate the
3697 event shape variables. If the list is empty the default
3698 particleLists pi+:evtshape and gamma:evtshape are filled.
3699 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
3700 defining the internal lists. This option is ignored if the
3701 particleLists are provided by the user.
3702 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3703 which would result in a standard predefined selection cuts
3704 @param path Path to append the eventShape modules to.
3705 @param thrust Enables the calculation of thrust-related quantities (CLEO
3706 cones, Harmonic moments, jets).
3707 @param collisionAxis Enables the calculation of the quantities related to the
3709 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
3710 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
3711 to both the thrust axis and, if collisionAxis = True, the collision axis.
3712 @param allMoments If True, calculates also the FW and harmonic moments from order
3713 5 to 8 instead of the low-order ones only.
3714 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
3715 axis and, if collisionAxis = True, the collision axis.
3716 @param jets Enables the calculation of the hemisphere momenta and masses.
3717 Requires thrust = True.
3718 @param sphericity Enables the calculation of the sphericity-related quantities.
3719 @param checkForDuplicates Perform a check for duplicate particles before adding them. Regardless of the value of this option,
3720 it is recommended to consider sanitizing the lists you are passing to the function since this will
3721 speed up the processing.
3725 if inputListNames
is None:
3727 trackCuts =
'pt > 0.1'
3728 trackCuts +=
' and thetaInCDCAcceptance'
3729 trackCuts +=
' and abs(dz) < 3.0'
3730 trackCuts +=
' and dr < 0.5'
3732 gammaCuts =
'E > 0.05'
3733 gammaCuts +=
' and thetaInCDCAcceptance'
3735 gammaCuts +=
' and abs(clusterTiming) < 200'
3736 if (custom_cuts
is not None):
3737 trackCuts, gammaCuts = custom_cuts
3739 if not inputListNames:
3740 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
3741 fillParticleList(
'pi+:evtshape',
'', path=path)
3743 copyList(
'gamma:evtshape',
'gamma:mdst', path=path)
3749 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
3752 if (custom_cuts
is not None):
3753 B2INFO(
"Applying standard cuts")
3754 applyCuts(
'pi+:evtshape', trackCuts, path=path)
3756 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
3758 B2WARNING(
"Creating the default lists with no cleanup.")
3760 particleLists = inputListNames
3762 eventShapeModule = register_module(
'EventShapeCalculator')
3763 eventShapeModule.set_name(
'EventShape')
3764 eventShapeModule.param(
'particleListNames', particleLists)
3765 eventShapeModule.param(
'enableAllMoments', allMoments)
3766 eventShapeModule.param(
'enableCleoCones', cleoCones)
3767 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
3768 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
3769 eventShapeModule.param(
'enableJets', jets)
3770 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
3771 eventShapeModule.param(
'enableSphericity', sphericity)
3772 eventShapeModule.param(
'enableThrust', thrust)
3773 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
3775 path.add_module(eventShapeModule)
3778def labelTauPairMC(printDecayInfo=False, path=None, TauolaBelle=False, mapping_minus=None, mapping_plus=None):
3780 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
3781 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
3783 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
3784 @param path: module is added to this path
3785 @param TauolaBelle: if False, TauDecayMode is set. If True, TauDecayMarker is set.
3786 @param mapping_minus: if None, the map is the default one, else the path for the map is given by the user for tau-
3787 @param mapping_plus: if None, the map is the default one, else the path for the map is given by the user for tau+
3790 from basf2
import find_file
3796 m_printmode =
'default'
3798 if mapping_minus
is None:
3799 mp_file_minus = find_file(
'data/analysis/modules/TauDecayMode/map_tauminus.txt')
3801 mp_file_minus = mapping_minus
3803 if mapping_plus
is None:
3804 mp_file_plus = find_file(
'data/analysis/modules/TauDecayMode/map_tauplus.txt')
3806 mp_file_plus = mapping_plus
3808 path.add_module(
'TauDecayMode', printmode=m_printmode, file_minus=mp_file_minus, file_plus=mp_file_plus)
3811 tauDecayMarker = register_module(
'TauDecayMarker')
3812 tauDecayMarker.set_name(
'TauDecayMarker_')
3814 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
3817def tagCurlTracks(particleLists,
3827 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
3829 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
3830 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
3832 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
3835 The module loops over all particles in a given list with a transverse momentum below the pre-selection **ptCut**
3836 and assigns them to bundles based on the response of the chosen **selector** and the required minimum response set by the
3837 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
3838 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
3842 @param particleLists: list of particle lists to check for curls.
3843 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
3844 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
3845 genParticleIndex then ranked and tagged as normal.
3846 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
3847 If set to ``-1`` a cut value optimised to maximise the accuracy on a BBbar sample is used.
3848 Note 'cut' selector is binary 0/1.
3849 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
3850 It is strongly recommended to used the 'mva' selection. The 'cut' selection
3851 is based on BN1079 and is only calibrated for Belle data.
3853 @param ptCut: Pre-selection cut on transverse momentum. Only tracks below that are considered as curler candidates.
3855 @param expert_train: flag to set training mode if selector has a training mode (mva).
3856 @param expert_filename: set file name of produced training ntuple (mva).
3857 @param path: module is added to this path.
3863 if (
not isinstance(particleLists, list)):
3864 particleLists = [particleLists]
3866 curlTagger = register_module(
'CurlTagger')
3867 curlTagger.set_name(
'CurlTagger_')
3868 curlTagger.param(
'particleLists', particleLists)
3869 curlTagger.param(
'belle', belle)
3870 curlTagger.param(
'mcTruth', mcTruth)
3871 curlTagger.param(
'responseCut', responseCut)
3872 if abs(responseCut + 1) < 1e-9:
3873 curlTagger.param(
'usePayloadCut',
True)
3875 curlTagger.param(
'usePayloadCut',
False)
3877 curlTagger.param(
'selectorType', selectorType)
3878 curlTagger.param(
'ptCut', ptCut)
3879 curlTagger.param(
'train', expert_train)
3880 curlTagger.param(
'trainFilename', expert_filename)
3882 path.add_module(curlTagger)
3885def applyChargedPidMVA(particleLists, path, trainingMode, chargeIndependent=False, binaryHypoPDGCodes=(0, 0)):
3887 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
3889 The module decorates Particle objects in the input ParticleList(s) with variables
3890 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
3893 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.3.0**, **ROOT 6.20/04**).
3895 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
3897 * e (11) vs. pi (211)
3898 * mu (13) vs. pi (211)
3899 * pi (211) vs. K (321)
3900 * K (321) vs. pi (211)
3902 , or 'global' PID, namely "one-vs-others" separation. The latter exploits an MVA algorithm trained in multi-class mode,
3903 and it's the default behaviour. Currently, the multi-class training separates the following standard charged hypotheses:
3905 - e (11), mu (13), pi (211), K (321)
3908 In order to run the `ChargedPidMVA` and ensure the most up-to-date MVA training weights are applied,
3909 it is necessary to append the latest analysis global tag (GT) to the steering script.
3912 particleLists (list(str)): the input list of DecayStrings, where each selected (^) daughter should correspond to a
3913 standard charged ParticleList, e.g. ``['Lambda0:sig -> ^p+ ^pi-', 'J/psi:sig -> ^mu+ ^mu-']``.
3914 One can also directly pass a list of standard charged ParticleLists,
3915 e.g. ``['e+:my_electrons', 'pi+:my_pions']``.
3916 Note that charge-conjugated ParticleLists will automatically be included.
3917 path (basf2.Path): the module is added to this path.
3918 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
3919 Needed to pick up the correct payload from the DB. Available choices:
3921 * c_Classification=0
3923 * c_ECL_Classification=2
3924 * c_ECL_Multiclass=3
3925 * c_PSD_Classification=4
3926 * c_PSD_Multiclass=5
3927 * c_ECL_PSD_Classification=6
3928 * c_ECL_PSD_Multiclass=7
3930 chargeIndependent (bool, ``optional``): use a BDT trained on a sample of inclusively charged particles.
3931 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
3932 Required only for binary PID mode.
3937 B2ERROR(
"Charged PID via MVA is not available for Belle data.")
3939 from ROOT
import Belle2
3941 TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
3944 plSet = set(particleLists)
3948 TrainingMode.c_Classification:
3949 {
"mode":
"Classification",
"detector":
"ALL"},
3950 TrainingMode.c_Multiclass:
3951 {
"mode":
"Multiclass",
"detector":
"ALL"},
3952 TrainingMode.c_ECL_Classification:
3953 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
3954 TrainingMode.c_ECL_Multiclass:
3955 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
3956 TrainingMode.c_PSD_Classification:
3957 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
3958 TrainingMode.c_PSD_Multiclass:
3959 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
3960 TrainingMode.c_ECL_PSD_Classification:
3961 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
3962 TrainingMode.c_ECL_PSD_Multiclass:
3963 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
3966 if payloadNames.get(trainingMode)
is None:
3967 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
3968 "\nis not supported. Please choose among the following:\n",
3969 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
3971 mode = payloadNames.get(trainingMode).get(
"mode")
3972 detector = payloadNames.get(trainingMode).get(
"detector")
3974 payloadName = f
"ChargedPidMVAWeights_{mode}"
3979 Const.electron.getPDGCode():
3980 {
"pName":
"e",
"pFullName":
"electron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3981 Const.muon.getPDGCode():
3982 {
"pName":
"mu",
"pFullName":
"muon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3983 Const.pion.getPDGCode():
3984 {
"pName":
"pi",
"pFullName":
"pion",
"pNameBkg":
"K",
"pdgIdBkg": Const.kaon.getPDGCode()},
3985 Const.kaon.getPDGCode():
3986 {
"pName":
"K",
"pFullName":
"kaon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3987 Const.proton.getPDGCode():
3988 {
"pName":
"p",
"pFullName":
"proton",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3989 Const.deuteron.getPDGCode():
3990 {
"pName":
"d",
"pFullName":
"deuteron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3993 if binaryHypoPDGCodes == (0, 0):
3996 chargedpid = register_module(
"ChargedPidMVAMulticlass")
3997 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
4004 binaryOpts = [(pdgIdSig, info[
"pdgIdBkg"])
for pdgIdSig, info
in stdChargedMap.items()]
4006 if binaryHypoPDGCodes
not in binaryOpts:
4007 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
4008 ". Please choose among the following pairs:\n",
4009 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
4013 if not decayDescriptor.init(name):
4014 raise ValueError(f
"Invalid particle list {name} in applyChargedPidMVA!")
4015 msg = f
"Input ParticleList: {name}"
4016 pdgs = [abs(decayDescriptor.getMother().getPDGCode())]
4017 daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
4018 if len(daughter_pdgs) > 0:
4019 pdgs = daughter_pdgs
4020 for idaughter, pdg
in enumerate(pdgs):
4021 if abs(pdg)
not in binaryHypoPDGCodes:
4023 msg = f
"Selected daughter {idaughter} in ParticleList: {name}"
4025 f
"{msg} (PDG={pdg}) is neither signal ({binaryHypoPDGCodes[0]}) nor background ({binaryHypoPDGCodes[1]}).")
4027 chargedpid = register_module(
"ChargedPidMVA")
4028 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
4029 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
4030 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
4032 chargedpid.param(
"particleLists", list(plSet))
4033 chargedpid.param(
"payloadName", payloadName)
4034 chargedpid.param(
"chargeIndependent", chargeIndependent)
4037 if detector ==
"ECL":
4038 chargedpid.param(
"useECLOnlyTraining",
True)
4040 path.add_module(chargedpid)
4043def calculateTrackIsolation(
4047 reference_list_name=None,
4048 vars_for_nearest_part=[],
4049 highest_prob_mass_for_ext=True,
4050 exclude_pid_det_weights=False):
4052 Given an input decay string, compute variables that quantify track helix-based isolation of the charged
4053 stable particles in the input decay chain.
4056 An "isolation score" can be defined using the distance
4057 of each particle to its closest neighbour, defined as the segment connecting the two
4058 extrapolated track helices intersection points on a given cylindrical surface.
4059 The distance variables defined in the `VariableManager` is named `minET2ETDist`,
4060 the isolation scores are named `minET2ETIsoScore`, `minET2ETIsoScoreAsWeightedAvg`.
4062 The definition of distance and the number of distances that are calculated per sub-detector is based on
4063 the following recipe:
4065 * **CDC**: as the segmentation is very coarse along :math:`z`,
4066 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
4067 A total of 9 distances are calculated: the cylindrical surfaces are defined at radiuses
4068 that correspond to the positions of the 9 CDC wire superlayers: :math:`R_{i}^{\\mathrm{CDC}}~(i \\in \\{0,...,8\\})`.
4070 * **TOP**: as there is no segmentation along :math:`z`,
4071 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
4072 Only one distance at the TOP entry radius :math:`R_{0}^{\\mathrm{TOP}}` is calculated.
4074 * **ARICH**: as there is no segmentation along :math:`z`,
4075 the distance is defined as the distance on the :math:`(\\rho=R, \\phi)` plane at fixed :math:`z=Z`.
4076 Only one distance at the ARICH photon detector entry coordinate :math:`Z_{0}^{\\mathrm{ARICH}}` is calculated.
4078 * **ECL**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
4079 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
4080 Two distances are calculated: one at the ECL entry surface :math:`R_{0}^{\\mathrm{ECL}}` (barrel),
4081 :math:`Z_{0}^{\\mathrm{ECL}}` (endcaps), and one at :math:`R_{1}^{\\mathrm{ECL}}` (barrel),
4082 :math:`Z_{1}^{\\mathrm{ECL}}` (endcaps), corresponding roughly to the mid-point
4083 of the longitudinal size of the crystals.
4085 * **KLM**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
4086 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
4087 Only one distance at the KLM first strip entry surface :math:`R_{0}^{\\mathrm{KLM}}` (barrel),
4088 :math:`Z_{0}^{\\mathrm{KLM}}` (endcaps) is calculated.
4091 decay_string (str): name of the input decay string with selected charged stable daughters,
4092 for example: ``Lambda0:merged -> ^p+ ^pi-``.
4093 Alternatively, it can be a particle list for charged stable particles
4094 as defined in ``Const::chargedStableSet``, for example: ``mu+:all``.
4095 The charge-conjugate particle list will be also processed automatically.
4096 path (basf2.Path): path to which module(s) will be added.
4097 *detectors: detectors for which track isolation variables will be calculated.
4098 Choose among: ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
4099 reference_list_name (Optional[str]): name of the input charged stable particle list for the reference tracks.
4100 By default, the ``:all`` ParticleList of the same type
4101 of the selected particle in ``decay_string`` is used.
4102 The charge-conjugate particle list will be also processed automatically.
4103 vars_for_nearest_part (Optional[list(str)]): a list of variables to calculate for the nearest particle in the reference
4104 list at each detector surface. It uses the metavariable `minET2ETDistVar`.
4105 If unset, only the distances to the nearest neighbour
4106 per detector are calculated.
4107 highest_prob_mass_for_hex (Optional[bool]): if this option is set to True (default), the helix extrapolation
4108 for the particles will use the track fit result for the most
4109 probable mass hypothesis, namely, the one that gives the highest
4110 chi2Prob of the fit. Otherwise, it uses the mass hypothesis that
4111 corresponds to the particle lists PDG.
4112 exclude_pid_det_weights (Optional[bool]): if this option is set to False (default), the isolation score
4113 calculation will take into account the weight that each detector has on the PID
4114 for the particle species of interest.
4117 dict(int, list(str)): a dictionary mapping the PDG of each reference particle list to its isolation variables.
4122 from ROOT
import Belle2, TDatabasePDG
4125 if not decayDescriptor.init(decay_string):
4126 B2FATAL(f
"Invalid particle list {decay_string} in calculateTrackIsolation!")
4127 no_reference_list_name =
not reference_list_name
4130 "CDC": list(range(9)),
4136 if any(d
not in det_and_layers
for d
in detectors):
4138 "Your input detector list: ",
4140 " contains an invalid choice. Please select among: ",
4142 det_and_layers.keys()))
4147 processed_decay_strings = []
4148 if select_symbol
in decay_string:
4149 splitted_ds = decay_string.split(select_symbol)
4150 for i
in range(decay_string.count(select_symbol)):
4151 tmp = list(splitted_ds)
4152 tmp.insert(i+1, select_symbol)
4153 processed_decay_strings += [
''.join(tmp)]
4155 processed_decay_strings += [decay_string]
4157 reference_lists_to_vars = {}
4159 for processed_dec
in processed_decay_strings:
4160 if no_reference_list_name:
4161 decayDescriptor.init(processed_dec)
4162 selected_daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
4163 if len(selected_daughter_pdgs) > 0:
4164 reference_list_name = f
'{TDatabasePDG.Instance().GetParticle(abs(selected_daughter_pdgs[-1])).GetName()}:all'
4166 reference_list_name = f
'{processed_dec.split(":")[0]}:all'
4170 trackiso = path.add_module(
"TrackIsoCalculator",
4171 decayString=processed_dec,
4172 detectorNames=list(detectors),
4173 particleListReference=reference_list_name,
4174 useHighestProbMassForExt=highest_prob_mass_for_ext,
4175 excludePIDDetWeights=exclude_pid_det_weights)
4176 trackiso.set_name(f
"TrackIsoCalculator_{'_'.join(detectors)}_{processed_dec}_VS_{reference_list_name}")
4182 f
"minET2ETDist({d}, {d_layer}, {reference_list_name}, {int(highest_prob_mass_for_ext)})"
4183 for d
in detectors
for d_layer
in det_and_layers[d]]
4186 f
"minET2ETIsoScore({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4187 f
"minET2ETIsoScoreAsWeightedAvg({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4190 if vars_for_nearest_part:
4191 trackiso_vars.extend(
4193 f
"minET2ETDistVar({d}, {d_layer}, {reference_list_name}, {v})"
4194 for d
in detectors
for d_layer
in det_and_layers[d]
for v
in vars_for_nearest_part
4196 trackiso_vars.sort()
4198 reference_lists_to_vars[ref_pdg] = trackiso_vars
4200 return reference_lists_to_vars
4203def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
4205 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
4206 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
4207 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
4208 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
4211 .. code-block:: python
4213 from modularAnalysis import calculateDistance
4214 calculateDistance('list_name', 'decay_string', "mode", path=user_path)
4216 @param list_name name of the input ParticleList
4217 @param decay_string select particles between the distance of closest approach will be calculated
4218 @param mode Specifies how the distance is calculated
4219 vertextrack: calculate the distance of closest approach between a track and a\
4220 vertex, taking the first candidate as vertex, default
4221 trackvertex: calculate the distance of closest approach between a track and a\
4222 vertex, taking the first candidate as track
4223 2tracks: calculates the distance of closest approach between two tracks
4224 2vertices: calculates the distance between two vertices
4225 vertexbtube: calculates the distance of closest approach between a vertex and btube
4226 trackbtube: calculates the distance of closest approach between a track and btube
4227 @param path modules are added to this path
4231 dist_mod = register_module(
'DistanceCalculator')
4233 dist_mod.set_name(
'DistanceCalculator_' + list_name)
4234 dist_mod.param(
'listName', list_name)
4235 dist_mod.param(
'decayString', decay_string)
4236 dist_mod.param(
'mode', mode)
4237 path.add_module(dist_mod)
4240def addInclusiveDstarReconstruction(decayString, slowPionCut, DstarCut, path):
4242 Adds the InclusiveDstarReconstruction module to the given path.
4243 This module creates a D* particle list by estimating the D* four momenta
4244 from slow pions, specified by a given cut. The D* energy is approximated
4245 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
4246 momentum is calculated using the D* PDG mass and the direction is collinear
4247 to the slow pion direction. The charge of the given pion list has to be consistent
4250 @param decayString Decay string, must be of form ``D* -> pi``
4251 @param slowPionCut Cut applied to the input pion list to identify slow pions
4252 @param DstarCut Cut applied to the output D* list
4253 @param path the module is added to this path
4256 incl_dstar = register_module(
"InclusiveDstarReconstruction")
4257 incl_dstar.param(
"decayString", decayString)
4258 incl_dstar.param(
"slowPionCut", slowPionCut)
4259 incl_dstar.param(
"DstarCut", DstarCut)
4260 path.add_module(incl_dstar)
4263def scaleError(outputListName, inputListName,
4264 scaleFactors=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4265 scaleFactorsNoPXD=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4266 d0Resolution=[0.00115328, 0.00134704],
4267 z0Resolution=[0.00124327, 0.0013272],
4272 This module creates a new charged particle list.
4273 The helix errors of the new particles are scaled by constant factors.
4274 Two sets of five scale factors are defined for tracks with and without a PXD hit.
4275 The scale factors are in order of (d0, phi0, omega, z0, tanlambda).
4276 For tracks with a PXD hit, in order to avoid severe underestimation of d0 and z0 errors,
4277 lower limits (best resolution) can be set in a momentum-dependent form.
4278 This module is supposed to be used only for TDCPV analysis and for low-momentum (0-3 GeV/c) tracks in BBbar events.
4279 Details will be documented in a Belle II note, BELLE2-NOTE-PH-2021-038.
4281 @param inputListName Name of input charged particle list to be scaled
4282 @param outputListName Name of output charged particle list with scaled error
4283 @param scaleFactors List of five constants to be multiplied to each of helix errors (for tracks with a PXD hit)
4284 @param scaleFactorsNoPXD List of five constants to be multiplied to each of helix errors (for tracks without a PXD hit)
4285 @param d0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4286 defining d0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**1.5))**2 }
4287 @param z0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4288 defining z0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**2.5))**2 }
4289 @param d0MomThr d0 best resolution is kept constant below this momentum
4290 @param z0MomThr z0 best resolution is kept constant below this momentum
4294 scale_error = register_module(
"HelixErrorScaler")
4295 scale_error.set_name(
'ScaleError_' + inputListName)
4296 scale_error.param(
'inputListName', inputListName)
4297 scale_error.param(
'outputListName', outputListName)
4298 scale_error.param(
'scaleFactors_PXD', scaleFactors)
4299 scale_error.param(
'scaleFactors_noPXD', scaleFactorsNoPXD)
4300 scale_error.param(
'd0ResolutionParameters', d0Resolution)
4301 scale_error.param(
'z0ResolutionParameters', z0Resolution)
4302 scale_error.param(
'd0MomentumThreshold', d0MomThr)
4303 scale_error.param(
'z0MomentumThreshold', z0MomThr)
4304 path.add_module(scale_error)
4307def estimateAndAttachTrackFitResult(inputListName, path=None):
4309 Create a TrackFitResult from the momentum of the Particle assuming it originates from the IP and make a relation between them.
4310 The covariance, detector hit information, and fit-related information (pValue, NDF) are assigned meaningless values. The input
4311 Particles must not have already Track or TrackFitResult and thus are supposed to be composite particles, recoil, dummy
4312 particles, and so on.
4315 .. warning:: Since the source type is not overwritten as Track, not all track-related variables are guaranteed to be available.
4318 @param inputListName Name of input ParticleList
4321 estimator = register_module(
"TrackFitResultEstimator")
4322 estimator.set_name(
"trackFitResultEstimator_" + inputListName)
4323 estimator.param(
"inputListName", inputListName)
4324 path.add_module(estimator)
4327def correctEnergyBias(inputListNames, tableName, path=None):
4329 Scale energy of the particles according to the scaling factor.
4330 If the particle list contains composite particles, the energy of the daughters are scaled.
4331 Subsequently, the energy of the mother particle is updated as well.
4334 inputListNames (list(str)): input particle list names
4335 tableName : stored in localdb and created using ParticleWeightingLookUpCreator
4336 path (basf2.Path): module is added to this path
4341 B2ERROR(
"The energy bias cannot be corrected with this tool for Belle data.")
4343 correctenergybias = register_module(
'EnergyBiasCorrection')
4344 correctenergybias.param(
'particleLists', inputListNames)
4345 correctenergybias.param(
'tableName', tableName)
4346 path.add_module(correctenergybias)
4349def twoBodyISRPhotonCorrector(outputListName, inputListName, massiveParticle, path=None):
4351 Sets photon kinematics to corrected values in two body decays with an ISR photon
4352 and a massive particle. The original photon kinematics are kept in the input
4353 particleList and can be accessed using the originalParticle() metavariable on the
4356 @param ouputListName new ParticleList filled with copied Particles
4357 @param inputListName input ParticleList with original Particles
4358 @param massiveParticle name or PDG code of massive particle participating in the two
4359 body decay with the ISR photon
4360 @param path modules are added to this path
4364 photon_energy_correction = register_module(
'TwoBodyISRPhotonCorrector')
4365 photon_energy_correction.set_name(
'TwoBodyISRPhotonCorrector_' + outputListName)
4366 photon_energy_correction.param(
'outputGammaList', outputListName)
4367 photon_energy_correction.param(
'inputGammaList', inputListName)
4370 if isinstance(massiveParticle, int):
4371 photon_energy_correction.param(
'massiveParticlePDGCode', massiveParticle)
4373 from ROOT
import Belle2
4375 if not decayDescriptor.init(massiveParticle):
4376 raise ValueError(
"TwoBodyISRPhotonCorrector: value of massiveParticle must be" +
4377 " an int or valid decay string.")
4378 pdgCode = decayDescriptor.getMother().getPDGCode()
4379 photon_energy_correction.param(
'massiveParticlePDGCode', pdgCode)
4381 path.add_module(photon_energy_correction)
4384def addPhotonEfficiencyRatioVariables(inputListNames, tableName, path=None):
4386 Add photon Data/MC detection efficiency ratio weights to the specified particle list
4389 inputListNames (list(str)): input particle list names
4390 tableName : taken from database with appropriate name
4391 path (basf2.Path): module is added to this path
4396 B2ERROR(
"For Belle data the photon data/MC detection efficiency ratio is not available with this tool.")
4398 photon_efficiency_correction = register_module(
'PhotonEfficiencySystematics')
4399 photon_efficiency_correction.param(
'particleLists', inputListNames)
4400 photon_efficiency_correction.param(
'tableName', tableName)
4401 path.add_module(photon_efficiency_correction)
4404def addPi0VetoEfficiencySystematics(particleList, decayString, tableName, threshold, mode='standard', suffix='', path=None):
4406 Add pi0 veto Data/MC efficiency ratio weights to the specified particle list
4408 @param particleList the input ParticleList
4409 @param decayString specify hard photon to be performed pi0 veto (e.g. 'B+:sig -> rho+:sig ^gamma:hard')
4410 @param tableName table name corresponding to payload version (e.g. 'Pi0VetoEfficiencySystematics_Mar2022')
4411 @param threshold pi0 veto threshold (0.10, 0.11, ..., 0.99)
4412 @param mode choose one mode (same as writePi0EtaVeto) out of 'standard', 'tight', 'cluster' and 'both'
4413 @param suffix optional suffix to be appended to the usual extraInfo name
4414 @param path the module is added to this path
4416 The following extraInfo are available related with the given particleList:
4418 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_ratio : weight of Data/MC for the veto efficiency
4419 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_stat : the statistical uncertainty of the weight
4420 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_sys : the systematic uncertainty of the weight
4421 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_total : the total uncertainty of the weight
4422 * Pi0VetoEfficiencySystematics_{mode}{suffix}_threshold : threshold of the pi0 veto
4427 B2ERROR(
"For Belle data the pi0 veto data/MC efficiency ratio weights are not available via this tool.")
4429 pi0veto_efficiency_correction = register_module(
'Pi0VetoEfficiencySystematics')
4430 pi0veto_efficiency_correction.param(
'particleLists', particleList)
4431 pi0veto_efficiency_correction.param(
'decayString', decayString)
4432 pi0veto_efficiency_correction.param(
'tableName', tableName)
4433 pi0veto_efficiency_correction.param(
'threshold', threshold)
4434 pi0veto_efficiency_correction.param(
'mode', mode)
4435 pi0veto_efficiency_correction.param(
'suffix', suffix)
4436 path.add_module(pi0veto_efficiency_correction)
4439def getAnalysisGlobaltag(timeout=180) -> str:
4441 Returns a string containing the name of the latest and recommended analysis globaltag.
4444 timeout: Seconds to wait for b2conditionsdb-recommend
4449 B2ERROR(
"The getAnalysisGlobaltag() function cannot be used for Belle data.")
4454 tags = subprocess.check_output(
4455 [
'b2conditionsdb-recommend',
'--oneline'],
4457 ).decode(
'UTF-8').rstrip().split(
' ')
4460 if tag.startswith(
'analysis_tools'):
4464 except subprocess.TimeoutExpired
as te:
4465 B2FATAL(f
'A {te} exception was raised during the call of getAnalysisGlobaltag(). '
4466 'The function took too much time to retrieve the requested information '
4467 'from the versioning repository.\n'
4468 'Please try to re-run your job. In case of persistent failures, there may '
4469 'be issues with the DESY collaborative services, so please contact the experts.')
4470 except subprocess.CalledProcessError
as ce:
4471 B2FATAL(f
'A {ce} exception was raised during the call of getAnalysisGlobaltag(). '
4472 'Please try to re-run your job. In case of persistent failures, please contact '
4476def getAnalysisGlobaltagB2BII() -> str:
4478 Get recommended global tag for B2BII analysis.
4483 B2ERROR(
'The getAnalysisGlobaltagB2BII() function cannot be used for Belle II data.')
4484 from versioning
import recommended_b2bii_analysis_global_tag
4485 return recommended_b2bii_analysis_global_tag()
4488def getECLKLID(particleList: str, variable=
'ECLKLID', path=
None):
4490 The function calculates the PID value for Klongs that are constructed from ECL cluster.
4492 @param particleList the input ParticleList
4493 @param variable the variable name for Klong ID
4494 @param path modules are added to this path
4500 B2ERROR(
"The ECL variables based Klong Identification is only available for Belle II data.")
4502 from variables
import variables
4503 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'ECLKLID', identifier=
'ECLKLID')
4505 variables.addAlias(variable,
'conditionalVariableSelector(isFromECL and PDG==130, extraInfo(ECLKLID), constant(NaN))')
4508def getNbarIDMVA(particleList: str, path=
None):
4510 This function can give a score to predict if it is a anti-n0.
4511 It is not used to predict n0.
4512 Currently, this can be used only for ECL cluster.
4513 output will be stored in extraInfo(nbarID); -1 means MVA invalid
4515 @param particleList The input ParticleList name or a decay string which contains a full mother particle list name.
4516 Only one selected daughter is supported.
4517 @param path modules are added to this path
4520 from ROOT
import Belle2
4523 B2ERROR(
"The MVA-based anti-neutron PID is only available for Belle II data.")
4525 from variables
import variables
4527 variables.addAlias(
'V1',
'clusterHasPulseShapeDiscrimination')
4528 variables.addAlias(
'V2',
'clusterE')
4529 variables.addAlias(
'V3',
'clusterLAT')
4530 variables.addAlias(
'V4',
'clusterE1E9')
4531 variables.addAlias(
'V5',
'clusterE9E21')
4532 variables.addAlias(
'V6',
'clusterZernikeMVA')
4533 variables.addAlias(
'V7',
'clusterAbsZernikeMoment40')
4534 variables.addAlias(
'V8',
'clusterAbsZernikeMoment51')
4538 'passesCut(V1 == 1 and V2 >= 0 and V3 >= 0 and V4 >= 0 and V5 >= 0 and V6 >= 0 and V7 >= 0 and V8 >= 0)')
4539 variables.addAlias(
'nbarIDmod',
'conditionalVariableSelector(nbarIDValid == 1, extraInfo(nbarIDFromMVA), constant(-1.0))')
4541 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'nbarIDFromMVA', identifier=
'db_nbarIDECL')
4543 if not decayDescriptor.init(particleList):
4544 raise ValueError(f
"Provided decay string is invalid: {particleList}")
4545 if decayDescriptor.getNDaughters() == 0:
4548 listname = decayDescriptor.getMother().getFullName()
4549 variablesToDaughterExtraInfo(listname, particleList, {
'nbarIDmod':
'nbarID'}, option=2, path=path)
4552def reconstructDecayWithNeutralHadron(decayString, cut, allowGamma=False, allowAnyParticleSource=False, path=None, **kwargs):
4554 Reconstructs decay with a long-lived neutral hadron e.g.
4555 :math:`B^0 \to J/\psi K_L^0`,
4556 :math:`B^0 \to p \bar{n} D^*(2010)^-`.
4558 The calculation is done with IP constraint and mother mass constraint.
4560 The decay string passed in must satisfy the following rules:
4562 - The neutral hadron must be **selected** in the decay string with the
4563 caret (``^``) e.g. ``B0:sig -> J/psi:sig ^K_L0:sig``. (Note the caret
4564 next to the neutral hadron.)
4565 - There can only be **one neutral hadron in a decay**.
4566 - The neutral hadron has to be a direct daughter of its mother.
4568 .. note:: This function forwards its arguments to `reconstructDecay`,
4569 so please check the documentation of `reconstructDecay` for all
4572 @param decayString A decay string following the mentioned rules
4573 @param cut Cut to apply to the particle list
4574 @param allowGamma Whether allow the selected particle to be ``gamma``
4575 @param allowAnyParticleSource Whether allow the selected particle to be from any source.
4576 Should only be used when studying control sample.
4577 @param path The path to put in the module
4580 reconstructDecay(decayString, cut, path=path, **kwargs)
4581 module = register_module(
'NeutralHadron4MomentumCalculator')
4582 module.set_name(
'NeutralHadron4MomentumCalculator_' + decayString)
4583 module.param(
'decayString', decayString)
4584 module.param(
'allowGamma', allowGamma)
4585 module.param(
'allowAnyParticleSource', allowAnyParticleSource)
4586 path.add_module(module)
4589def updateMassHypothesis(particleList, pdg, writeOut=False, path=None):
4591 Module to update the mass hypothesis of a given input particle list with the chosen PDG.
4592 A new particle list is created with updated mass hypothesis.
4593 The allowed mass hypotheses for both input and output are electrons, muons, pions, kaons and protons.
4596 The new particle list is named after the input one, with the additional suffix ``_converted_from_OLDHYPOTHESIS``,
4597 e.g. ``e+:all`` converted to muons becomes ``mu+:all_converted_from_e``.
4599 @param particleList The input particle list name
4600 @param pdg The PDG code for the new mass hypothesis, in [11, 13, 211, 321, 2212]
4601 @param writeOut Whether `RootOutput` module should save the new particle list
4602 @param path Modules are added to this path
4604 mass_updater = register_module(
"ParticleMassHypothesesUpdater")
4605 mass_updater.set_name(
"ParticleMassHypothesesUpdater_" + particleList +
"_to_" + str(pdg))
4606 mass_updater.param(
"particleList", particleList)
4607 mass_updater.param(
"writeOut", writeOut)
4608 mass_updater.param(
"pdgCode", pdg)
4609 path.add_module(mass_updater)
4612func_requiring_analysisGT = [
4613 correctTrackEnergy, scaleTrackMomenta, smearTrackMomenta, oldwritePi0EtaVeto, writePi0EtaVeto, lowEnergyPi0Identification,
4614 getBeamBackgroundProbability, getFakePhotonProbability, tagCurlTracks, applyChargedPidMVA, correctEnergyBias,
4615 addPhotonEfficiencyRatioVariables, addPi0VetoEfficiencySystematics, getNbarIDMVA, getECLKLID]
4616for _
in func_requiring_analysisGT:
4617 _.__doc__ +=
"\n .. note:: This function (optionally) requires a payload stored in the analysis GlobalTag. "\
4618 "Please append or prepend the latest one from `getAnalysisGlobaltag` or `getAnalysisGlobaltagB2BII`.\n"
4621if __name__ ==
'__main__':
4623 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.
add_mdst_output(path, mc=True, filename='mdst.root', additionalBranches=[], dataDescription=None)
add_udst_output(path, filename, particleLists=None, additionalBranches=None, dataDescription=None, mc=True)