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
77 if entrySequence
is not None:
78 entrySequence = [entrySequence]
80 inputMdstList([filename], path, environmentType, skipNEvents, entrySequence, parentLevel=parentLevel, **kwargs)
86 environmentType='default',
91 useB2BIIDBCache=True):
93 Loads the specified list of :ref:`mDST <mdst>` (or :ref:`uDST <analysis_udstoutput>`) files with the RootInput module.
95 The correct environment (e.g. magnetic field settings) is determined from
96 ``environmentType``. Options are either: 'default' (for Belle II MC and
97 data: falls back to database), 'Belle': for analysis of converted Belle 1
101 filelist (list(str)): the filename list of files to be loaded
102 path (basf2.Path): modules are added to this path
103 environmentType (str): type of the environment to be loaded (either 'default' or 'Belle')
104 skipNEvents (int): N events of the input files are skipped
105 entrySequences (list(str)): The number sequences (e.g. 23:42,101) defining
106 the entries which are processed for each inputFileName.
107 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
108 useB2BIIDBCache (bool): Loading of local KEKCC database (only to be deactivated in very special cases)
111 roinput = register_module(
'RootInput')
112 roinput.param(
'inputFileNames', filelist)
113 roinput.param(
'skipNEvents', skipNEvents)
114 if entrySequences
is not None:
115 roinput.param(
'entrySequences', entrySequences)
116 roinput.param(
'parentLevel', parentLevel)
118 path.add_module(roinput)
119 path.add_module(
'ProgressBar')
121 if environmentType ==
'Belle':
126 from ROOT
import Belle2
132 setAnalysisConfigParams({
'mcMatchingVersion':
'Belle'}, path)
135 basf2.conditions.metadata_providers = [
"/sw/belle/b2bii/database/conditions/b2bii.sqlite"]
136 basf2.conditions.payload_locations = [
"/sw/belle/b2bii/database/conditions/"]
139def outputMdst(filename, path):
141 Saves mDST (mini-Data Summary Tables) to the output root file.
145 This function is kept for backward-compatibility.
146 Better to use `mdst.add_mdst_output` directly.
154def outputUdst(filename, particleLists=None, includeArrays=None, path=None, dataDescription=None):
156 Save uDST (user-defined Data Summary Tables) = MDST + Particles + ParticleLists
157 The charge-conjugate lists of those given in particleLists are also stored.
158 Additional Store Arrays and Relations to be stored can be specified via includeArrays
162 This does not reduce the amount of Particle objects saved,
163 see `udst.add_skimmed_udst_output` for a function that does.
169 path=path, filename=filename, particleLists=particleLists,
170 additionalBranches=includeArrays, dataDescription=dataDescription)
173def outputIndex(filename, path, includeArrays=None, keepParents=False, mc=True):
175 Write out all particle lists as an index file to be reprocessed using parentLevel flag.
176 Additional branches necessary for file to be read are automatically included.
177 Additional Store Arrays and Relations to be stored can be specified via includeArrays
180 @param str filename the name of the output index file
181 @param str path modules are added to this path
182 @param list(str) includeArrays: datastore arrays/objects to write to the output
183 file in addition to particle lists and related information
184 @param bool keepParents whether the parents of the input event will be saved as the parents of the same event
185 in the output index file. Useful if you are only adding more information to another index file
186 @param bool mc whether the input data is MC or not
189 if includeArrays
is None:
193 onlyPLists = register_module(
'OnlyWriteOutParticleLists')
194 path.add_module(onlyPLists)
199 'ParticlesToMCParticles',
200 'ParticlesToPIDLikelihoods',
201 'ParticleExtraInfoMap',
204 branches = [
'EventMetaData']
205 persistentBranches = [
'FileMetaData']
209 branches += partBranches
210 branches += includeArrays
212 r1 = register_module(
'RootOutput')
213 r1.param(
'outputFileName', filename)
214 r1.param(
'additionalBranchNames', branches)
215 r1.param(
'branchNamesPersistent', persistentBranches)
216 r1.param(
'keepParents', keepParents)
220def setupEventInfo(noEvents, path):
222 Prepare to generate events. This function sets up the EventInfoSetter.
223 You should call this before adding a generator from generators.
224 The experiment and run numbers are set to 0 (run independent generic MC in phase 3).
225 https://xwiki.desy.de/xwiki/rest/p/59192
228 noEvents (int): number of events to be generated
229 path (basf2.Path): modules are added to this path
232 evtnumbers = register_module(
'EventInfoSetter')
233 evtnumbers.param(
'evtNumList', [noEvents])
234 evtnumbers.param(
'runList', [0])
235 evtnumbers.param(
'expList', [0])
236 path.add_module(evtnumbers)
239def loadGearbox(path, silence_warning=False):
241 Loads Gearbox module to the path.
244 Should be used in a job with *cosmic event generation only*
246 Needed for scripts which only generate cosmic events in order to
249 @param path modules are added to this path
250 @param silence_warning stops a verbose warning message if you know you want to use this function
253 if not silence_warning:
254 B2WARNING(
"""You are overwriting the geometry from the database with Gearbox.
255 This is fine if you're generating cosmic events. But in most other cases you probably don't want this.
257 If you're really sure you know what you're doing you can suppress this message with:
259 >>> loadGearbox(silence_warning=True)
263 paramloader = register_module(
'Gearbox')
264 path.add_module(paramloader)
267def printPrimaryMCParticles(path, **kwargs):
269 Prints all primary MCParticles, that is particles from
270 the physics generator and not particles created by the simulation
272 This is equivalent to `printMCParticles(onlyPrimaries=True, path=path) <printMCParticles>` and additional
273 keyword arguments are just forwarded to that function
276 return printMCParticles(onlyPrimaries=
True, path=path, **kwargs)
279def printMCParticles(onlyPrimaries=False, maxLevel=-1, path=None, *,
280 showProperties=False, showMomenta=False, showVertices=False, showStatus=False, suppressPrint=False):
282 Prints all MCParticles or just primary MCParticles up to specified level. -1 means no limit.
284 By default this will print a tree of just the particle names and their pdg
285 codes in the event, for example ::
287 [INFO] Content of MCParticle list
290 ╰── Upsilon(4S) (300553)
292 │ ├── anti-D_0*0 (-10421)
295 │ │ │ │ ├── anti-K0 (-311)
296 │ │ │ │ │ ╰── K_S0 (310)
297 │ │ │ │ │ ├── pi+ (211)
298 │ │ │ │ │ │ ╰╶╶ p+ (2212)
299 │ │ │ │ │ ╰── pi- (-211)
300 │ │ │ │ │ ├╶╶ e- (11)
301 │ │ │ │ │ ├╶╶ n0 (2112)
302 │ │ │ │ │ ├╶╶ n0 (2112)
303 │ │ │ │ │ ╰╶╶ n0 (2112)
304 │ │ │ │ ╰── pi- (-211)
305 │ │ │ │ ├╶╶ anti-nu_mu (-14)
307 │ │ │ │ ├╶╶ nu_mu (14)
308 │ │ │ │ ├╶╶ anti-nu_e (-12)
312 │ │ │ │ ├── gamma (22)
313 │ │ │ │ ╰── gamma (22)
319 │ │ ├╶╶ anti-nu_mu (-14)
327 There's a distinction between primary and secondary particles. Primary
328 particles are the ones created by the physics generator while secondary
329 particles are ones generated by the simulation of the detector interaction.
331 Secondaries are indicated with a dashed line leading to the particle name
332 and if the output is to the terminal they will be printed in red. If
333 ``onlyPrimaries`` is True they will not be included in the tree.
335 On demand, extra information on all the particles can be displayed by
336 enabling any of the ``showProperties``, ``showMomenta``, ``showVertices``
337 and ``showStatus`` flags. Enabling all of them will look like
342 │ mass=0.14 energy=0.445 charge=-1 lifetime=6.36
343 │ p=(0.257, -0.335, 0.0238) |p|=0.423
344 │ production vertex=(0.113, -0.0531, 0.0156), time=0.00589
345 │ status flags=PrimaryParticle, StableInGenerator, StoppedInDetector
349 mass=0.94 energy=0.94 charge=0 lifetime=5.28e+03
350 p=(-0.000238, -0.0127, 0.0116) |p|=0.0172
351 production vertex=(144, 21.9, -1.29), time=39
352 status flags=StoppedInDetector
353 creation process=HadronInelastic
356 The first line of extra information is enabled by ``showProperties``, the
357 second line by ``showMomenta``, the third line by ``showVertices`` and the
358 last two lines by ``showStatus``. Note that all values are given in Belle II
359 standard units, that is GeV, centimeter and nanoseconds.
361 The depth of the tree can be limited with the ``maxLevel`` argument: If it's
362 bigger than zero it will limit the tree to the given number of generations.
363 A visual indicator will be added after each particle which would have
364 additional daughters that are skipped due to this limit. An example event
365 with ``maxLevel=3`` is given below. In this case only the tau neutrino and
366 the pion don't have additional daughters. ::
368 [INFO] Content of MCParticle list
371 ╰── Upsilon(4S) (300553)
373 │ ├── anti-D*0 (-423) → …
382 The same information will be stored in the branch ``__MCDecayString__`` of
383 TTree created by `VariablesToNtuple` or `VariablesToEventBasedTree` module.
384 This branch is automatically created when `PrintMCParticles` modules is called.
385 Printing the information on the log message can be suppressed if ``suppressPrint``
386 is True, while the branch ``__MCDecayString__``. This option helps to reduce the
387 size of the log message.
390 onlyPrimaries (bool): If True show only primary particles, that is particles coming from
391 the generator and not created by the simulation.
392 maxLevel (int): If 0 or less print the whole tree, otherwise stop after n generations
393 showProperties (bool): If True show mass, energy and charge of the particles
394 showMomenta (bool): if True show the momenta of the particles
395 showVertices (bool): if True show production vertex and production time of all particles
396 showStatus (bool): if True show some status information on the particles.
397 For secondary particles this includes creation process.
398 suppressPrint (bool): if True printing the information on the log message is suppressed.
399 Even if True, the branch ``__MCDecayString__`` is created.
402 return path.add_module(
404 onlyPrimaries=onlyPrimaries,
406 showProperties=showProperties,
407 showMomenta=showMomenta,
408 showVertices=showVertices,
409 showStatus=showStatus,
410 suppressPrint=suppressPrint,
414def correctBrems(outputList,
417 maximumAcceptance=3.0,
418 multiplePhotons=False,
419 usePhotonOnlyOnce=True,
423 For each particle in the given ``inputList``, copies it to the ``outputList`` and adds the
424 4-vector of the photon(s) in the ``gammaList`` which has(have) a weighted named relation to
425 the particle's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
428 So far, there haven't been any comprehensive comparisons of the performance of the `BremsFinder` module, which
429 is called in this function, with the `BelleBremRecovery` module, which is called via the `correctBremsBelle`
430 function. If your analysis is very sensitive to the Bremsstrahlung corrections, it is currently advised to use
433 The reason is that studies by the tau WG revealed that in the past the cuts applied by the
434 ``ECLTrackBremFinder`` module were too tight. They were only loosened for proc16 and MC16. New performance
435 studies are needed to verify that now this module outperforms the Belle-like approach.
438 A detailed description of how the weights are set can be found directly at the documentation of the
439 `BremsFinder` module.
441 Please note that a new particle is always generated, with the old particle and -if found- one or more
442 photons as daughters.
444 The ``inputList`` should contain particles with associated tracks. Otherwise, the module will exit with an error.
446 The ``gammaList`` should contain photons. Otherwise, the module will exit with an error.
448 @param outputList The output particle list name containing the corrected particles
449 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
450 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
451 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
452 @param multiplePhotons Whether to use only one photon (the one with the smallest acceptance) or as many as possible
453 @param usePhotonOnlyOnce If true, each brems candidate is used to correct only the track with the smallest relation weight
454 @param writeOut Whether `RootOutput` module should save the created ``outputList``
455 @param path The module is added to this path
460 B2ERROR(
"The BremsFinder can only be run over Belle II data.")
462 bremscorrector = register_module(
'BremsFinder')
463 bremscorrector.set_name(
'bremsCorrector_' + outputList)
464 bremscorrector.param(
'inputList', inputList)
465 bremscorrector.param(
'outputList', outputList)
466 bremscorrector.param(
'gammaList', gammaList)
467 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
468 bremscorrector.param(
'multiplePhotons', multiplePhotons)
469 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
470 bremscorrector.param(
'writeOut', writeOut)
471 path.add_module(bremscorrector)
474def copyList(outputListName, inputListName, writeOut=False, path=None):
476 Copy all Particle indices from input ParticleList to the output ParticleList.
477 Note that the Particles themselves are not copied. The original and copied
478 ParticleLists will point to the same Particles.
480 @param ouputListName copied ParticleList
481 @param inputListName original ParticleList to be copied
482 @param writeOut whether RootOutput module should save the created ParticleList
483 @param path modules are added to this path
486 copyLists(outputListName, [inputListName], writeOut, path)
489def correctBremsBelle(outputListName,
492 multiplePhotons=True,
494 usePhotonOnlyOnce=False,
498 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
499 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
503 Studies by the tau WG show that using a rather wide opening angle (up to
504 0.2 rad) and rather low energetic photons results in good correction.
505 However, this should only serve as a starting point for your own studies
506 because the optimal criteria are likely mode-dependent
509 outputListName (str): The output charged particle list containing the corrected charged particles
510 inputListName (str): The initial charged particle list containing the charged particles to correct.
511 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
512 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one -> False,
513 add all the photons within the cone -> True
514 angleThreshold (float): The maximum angle in radians between the charged particle and the (radiative)
515 gamma to be accepted.
516 writeOut (bool): whether RootOutput module should save the created ParticleList
517 usePhotonOnlyOnce (bool): If true, a photon is used for correction of the closest charged particle in the inputList.
518 If false, a photon is allowed to be used for correction multiple times (Default).
521 One cannot use a photon twice to reconstruct a composite particle. Thus, for example, if ``e+`` and ``e-`` are corrected
522 with a ``gamma``, the pair of ``e+`` and ``e-`` cannot form a ``J/psi -> e+ e-`` candidate.
524 path (basf2.Path): modules are added to this path
527 fsrcorrector = register_module(
'BelleBremRecovery')
528 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
529 fsrcorrector.param(
'inputListName', inputListName)
530 fsrcorrector.param(
'outputListName', outputListName)
531 fsrcorrector.param(
'gammaListName', gammaListName)
532 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
533 fsrcorrector.param(
'angleThreshold', angleThreshold)
534 fsrcorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
535 fsrcorrector.param(
'writeOut', writeOut)
536 path.add_module(fsrcorrector)
539def copyLists(outputListName, inputListNames, writeOut=False, path=None):
541 Copy all Particle indices from all input ParticleLists to the
542 single output ParticleList.
543 Note that the Particles themselves are not copied.
544 The original and copied ParticleLists will point to the same Particles.
546 Duplicates are removed based on the first-come, first-served principle.
547 Therefore, the order of the input ParticleLists matters.
550 If you want to select the best duplicate based on another criterion, have
551 a look at the function `mergeListsWithBestDuplicate`.
554 Two particles that differ only by the order of their daughters are
555 considered duplicates and one of them will be removed.
557 @param ouputListName copied ParticleList
558 @param inputListName vector of original ParticleLists to be copied
559 @param writeOut whether RootOutput module should save the created ParticleList
560 @param path modules are added to this path
563 pmanipulate = register_module(
'ParticleListManipulator')
564 pmanipulate.set_name(
'PListCopy_' + outputListName)
565 pmanipulate.param(
'outputListName', outputListName)
566 pmanipulate.param(
'inputListNames', inputListNames)
567 pmanipulate.param(
'writeOut', writeOut)
568 path.add_module(pmanipulate)
571def copyParticles(outputListName, inputListName, writeOut=False, path=None):
573 Create copies of Particles given in the input ParticleList and add them to the output ParticleList.
575 The existing relations of the original Particle (or it's (grand-)^n-daughters)
576 are copied as well. Note that only the relation is copied and that the related
577 object is not. Copied particles are therefore related to the *same* object as
580 @param ouputListName new ParticleList filled with copied Particles
581 @param inputListName input ParticleList with original Particles
582 @param writeOut whether RootOutput module should save the created ParticleList
583 @param path modules are added to this path
587 pmanipulate = register_module(
'ParticleListManipulator')
588 pmanipulate.set_name(
'PListCopy_' + outputListName)
589 pmanipulate.param(
'outputListName', outputListName)
590 pmanipulate.param(
'inputListNames', [inputListName])
591 pmanipulate.param(
'writeOut', writeOut)
592 path.add_module(pmanipulate)
595 pcopy = register_module(
'ParticleCopier')
596 pcopy.param(
'inputListNames', [outputListName])
597 path.add_module(pcopy)
600def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
602 Copy candidates from all lists in ``inputListNames`` to
603 ``outputListName`` if they pass ``cut`` (given selection criteria).
606 Note that the Particles themselves are not copied.
607 The original and copied ParticleLists will point to the same Particles.
610 Require energetic pions safely inside the cdc
612 .. code-block:: python
614 cutAndCopyLists("pi+:energeticPions", ["pi+:good", "pi+:loose"], "[E > 2] and thetaInCDCAcceptance", path=mypath)
617 You must use square braces ``[`` and ``]`` for conditional statements.
620 outputListName (str): the new ParticleList name
621 inputListName (list(str)): list of input ParticleList names
622 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
623 writeOut (bool): whether RootOutput module should save the created ParticleList
624 path (basf2.Path): modules are added to this path
627 pmanipulate = register_module(
'ParticleListManipulator')
628 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
629 pmanipulate.param(
'outputListName', outputListName)
630 pmanipulate.param(
'inputListNames', inputListNames)
631 pmanipulate.param(
'cut', cut)
632 pmanipulate.param(
'writeOut', writeOut)
633 path.add_module(pmanipulate)
636def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
638 Copy candidates from ``inputListName`` to ``outputListName`` if they pass
639 ``cut`` (given selection criteria).
642 Note the Particles themselves are not copied.
643 The original and copied ParticleLists will point to the same Particles.
646 require energetic pions safely inside the cdc
648 .. code-block:: python
650 cutAndCopyList("pi+:energeticPions", "pi+:loose", "[E > 2] and thetaInCDCAcceptance", path=mypath)
653 You must use square braces ``[`` and ``]`` for conditional statements.
656 outputListName (str): the new ParticleList name
657 inputListName (str): input ParticleList name
658 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
659 writeOut (bool): whether RootOutput module should save the created ParticleList
660 path (basf2.Path): modules are added to this path
663 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
666def removeTracksForTrackingEfficiencyCalculation(inputListNames, fraction, path=None):
668 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
669 Takes care of the duplicates, if any.
672 inputListNames (list(str)): input particle list names
673 fraction (float): fraction of particles to be removed randomly
674 path (basf2.Path): module is added to this path
677 trackingefficiency = register_module(
'TrackingEfficiency')
678 trackingefficiency.param(
'particleLists', inputListNames)
679 trackingefficiency.param(
'frac', fraction)
680 path.add_module(trackingefficiency)
683def scaleTrackMomenta(inputListNames, scale=float(
'nan'), payloadName=
"", scalingFactorName=
"SF", path=
None):
685 Scale momenta of the particles according to a scaling factor scale.
686 This scaling factor can either be given as constant number or as the name of the payload which contains
687 the variable scale factors.
688 If the particle list contains composite particles, the momenta of the track-based daughters are scaled.
689 Subsequently, the momentum of the mother particle is updated as well.
692 inputListNames (list(str)): input particle list names
693 scale (float): scaling factor (1.0 -- no scaling)
694 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
695 scalingFactorName (str): name of scaling factor variable in the payload.
696 path (basf2.Path): module is added to this path
701 B2ERROR(
"The tracking momentum scaler can only be run over Belle II data.")
703 TrackingMomentumScaleFactors = register_module(
'TrackingMomentumScaleFactors')
704 TrackingMomentumScaleFactors.param(
'particleLists', inputListNames)
705 TrackingMomentumScaleFactors.param(
'scale', scale)
706 TrackingMomentumScaleFactors.param(
'payloadName', payloadName)
707 TrackingMomentumScaleFactors.param(
'scalingFactorName', scalingFactorName)
709 path.add_module(TrackingMomentumScaleFactors)
712def correctTrackEnergy(inputListNames, correction=float(
'nan'), payloadName=
"", correctionName=
"SF", path=
None):
714 Correct the energy loss of tracks according to a 'correction' value.
715 This correction can either be given as constant number or as the name of the payload which contains
716 the variable corrections.
717 If the particle list contains composite particles, the momenta of the track-based daughters are corrected.
718 Subsequently, the momentum of the mother particle is updated as well.
721 inputListNames (list(str)): input particle list names
722 correction (float): correction value to be subtracted to the particle energy (0.0 -- no correction)
723 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
724 correctionName (str): name of correction variable in the payload.
725 path (basf2.Path): module is added to this path
730 B2ERROR(
"The tracking energy correction can only be run over Belle II data.")
732 TrackingEnergyLossCorrection = register_module(
'TrackingEnergyLossCorrection')
733 TrackingEnergyLossCorrection.param(
'particleLists', inputListNames)
734 TrackingEnergyLossCorrection.param(
'correction', correction)
735 TrackingEnergyLossCorrection.param(
'payloadName', payloadName)
736 TrackingEnergyLossCorrection.param(
'correctionName', correctionName)
738 path.add_module(TrackingEnergyLossCorrection)
741def smearTrackMomenta(inputListNames, payloadName="", smearingFactorName="smear", path=None):
743 Smear the momenta of the particles according the values read from the given payload.
744 If the particle list contains composite particles, the momenta of the track-based daughters are smeared.
745 Subsequently, the momentum of the mother particle is updated as well.
748 inputListNames (list(str)): input particle list names
749 payloadName (str): name of the payload which contains the smearing values
750 smearingFactorName (str): name of smearing factor variable in the payload.
751 path (basf2.Path): module is added to this path
754 TrackingMomentumScaleFactors = register_module(
'TrackingMomentumScaleFactors')
755 TrackingMomentumScaleFactors.param(
'particleLists', inputListNames)
756 TrackingMomentumScaleFactors.param(
'payloadName', payloadName)
757 TrackingMomentumScaleFactors.param(
'smearingFactorName', smearingFactorName)
759 path.add_module(TrackingMomentumScaleFactors)
762def mergeListsWithBestDuplicate(outputListName,
767 ignoreMotherFlavor=False,
770 Merge input ParticleLists into one output ParticleList. Only the best
771 among duplicates is kept. The lowest or highest value (configurable via
772 preferLowest) of the provided variable determines which duplicate is the
775 @param ouputListName name of merged ParticleList
776 @param inputListName vector of original ParticleLists to be merged
777 @param variable variable to determine best duplicate
778 @param preferLowest whether lowest or highest value of variable should be preferred
779 @param writeOut whether RootOutput module should save the created ParticleList
780 @param ignoreMotherFlavor whether the flavor of the mother particle is ignored when trying to find duplicates
781 @param path modules are added to this path
784 pmanipulate = register_module(
'ParticleListManipulator')
785 pmanipulate.set_name(
'PListMerger_' + outputListName)
786 pmanipulate.param(
'outputListName', outputListName)
787 pmanipulate.param(
'inputListNames', inputListNames)
788 pmanipulate.param(
'variable', variable)
789 pmanipulate.param(
'preferLowest', preferLowest)
790 pmanipulate.param(
'writeOut', writeOut)
791 pmanipulate.param(
'ignoreMotherFlavor', ignoreMotherFlavor)
792 path.add_module(pmanipulate)
795def fillSignalSideParticleList(outputListName, decayString, path):
797 This function should only be used in the ROE path, that is a path
798 that is executed for each ROE object in the DataStore.
800 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
802 Function will create a ParticleList with name 'gamma:sig' which will be filled
803 with the existing photon Particle, being the second daughter of the B0 candidate
804 to which the ROE object has to be related.
806 @param ouputListName name of the created ParticleList
807 @param decayString specify Particle to be added to the ParticleList
810 pload = register_module(
'SignalSideParticleListCreator')
811 pload.set_name(
'SSParticleList_' + outputListName)
812 pload.param(
'particleListName', outputListName)
813 pload.param(
'decayString', decayString)
814 path.add_module(pload)
817def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False,
818 loadPhotonsFromKLM=False):
820 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
821 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
823 The multiple ParticleLists with their own selection criteria are specified
824 via list tuples (decayString, cut), for example
826 .. code-block:: python
828 kaons = ('K+:mykaons', 'kaonID>0.1')
829 pions = ('pi+:mypions','pionID>0.1')
830 fillParticleLists([kaons, pions], path=mypath)
832 If you are unsure what selection you want, you might like to see the
833 :doc:`StandardParticles` functions.
835 The type of the particles to be loaded is specified via the decayString module parameter.
836 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
837 the particle. The following types of the particles can be loaded:
839 * charged final state particles (input ``mdst`` type = Tracks)
840 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
842 * neutral final state particles
843 - "gamma" (input ``mdst`` type = ECLCluster)
844 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
845 - "K_L0", "n0" (input ``mdst`` type = KLMCluster or ECLCluster)
848 For "K_S0" and "Lambda0" you must specify the daughter ordering.
850 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
852 .. code-block:: python
854 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
855 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
858 Gammas can also be loaded from KLMClusters by explicitly setting the
859 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
860 done in selected use-cases and the effect should be studied carefully.
863 For "K_L0" it is now possible to load from ECLClusters, to revert to
864 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
866 .. code-block:: python
868 klongs = ('K_L0', 'isFromKLM > 0')
869 fillParticleLists([kaons, pions, klongs], path=mypath)
871 * Charged kinks final state particles (input ``mdst`` type = Kink)
874 To reconstruct charged particle kink you must specify the daughter.
876 For example, to load Kinks as :math:`K^- \\to \\pi^-\\pi^0` decays from Kinks:
878 .. code-block:: python
880 kinkKaons = ('K- -> pi-', yourCut)
881 fillParticleLists([kaons, pions, v0lambdas, kinkKaons], path=mypath)
885 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
886 The decay string determines the type of Particle
887 and the name of the ParticleList.
888 If the input MDST type is V0 the whole
889 decay chain needs to be specified, so that
890 the user decides and controls the daughters
891 ' order (e.g. ``K_S0 -> pi+ pi-``).
892 If the input MDST type is Kink the decay chain needs to be specified
893 with only one daughter (e.g. ``K- -> pi-``).
894 The cut is the selection criteria
895 to be added to the ParticleList. It can be an empty string.
896 writeOut (bool): whether RootOutput module should save the created ParticleList
897 path (basf2.Path): modules are added to this path
898 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
899 using a mass hypothesis of the exact type passed to fillParticleLists().
900 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
901 in terms of mass difference will be used if the fit using exact particle
902 type is not available.
903 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
906 pload = register_module(
'ParticleLoader')
907 pload.set_name(
'ParticleLoader_' +
'PLists')
908 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
909 pload.param(
'writeOut', writeOut)
910 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
911 path.add_module(pload)
913 from ROOT
import Belle2
915 for decayString, cut
in decayStringsWithCuts:
916 if not decayDescriptor.init(decayString):
917 raise ValueError(
"Invalid decay string")
919 if decayDescriptor.getNDaughters() > 0:
924 if (decayDescriptor.getNDaughters() == 1)
and (decayDescriptor.getMother().getLabel() !=
'kink'):
925 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':kink',
927 if (decayDescriptor.getNDaughters() > 1)
and (decayDescriptor.getMother().getLabel() !=
'V0'):
928 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
929 elif (decayDescriptor.getMother().getLabel() !=
'all' and
930 abs(decayDescriptor.getMother().getPDGCode()) != Belle2.Const.neutron.getPDGCode()):
933 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
937 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
939 if decayString.startswith(
"gamma"):
942 if not loadPhotonsFromKLM:
943 applyCuts(decayString,
'isFromECL', path)
946def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False,
947 loadPhotonsFromKLM=False):
949 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
950 loads them to the StoreArray<Particle> and fills the ParticleList.
953 the :doc:`StandardParticles` functions.
955 The type of the particles to be loaded is specified via the decayString module parameter.
956 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
957 the particle. The following types of the particles can be loaded:
959 * charged final state particles (input ``mdst`` type = Tracks)
960 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
962 * neutral final state particles
963 - "gamma" (input ``mdst`` type = ECLCluster)
964 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
965 - "K_L0", "n0" (input ``mdst`` type = KLMCluster or ECLCluster)
968 For "K_S0" and "Lambda0" you must specify the daughter ordering.
970 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
972 .. code-block:: python
974 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
977 Gammas can also be loaded from KLMClusters by explicitly setting the
978 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
979 done in selected use-cases and the effect should be studied carefully.
982 For "K_L0" it is now possible to load from ECLClusters, to revert to
983 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
985 .. code-block:: python
987 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
989 * Charged kinks final state particles (input ``mdst`` type = Kink)
992 To reconstruct charged particle kink you must specify the daughter.
994 For example, to load Kinks as :math:`K^- \\to \\pi^-\\pi^0` decays from Kinks:
996 .. code-block:: python
998 fillParticleList('K- -> pi-', yourCut, path=mypath)
1002 decayString (str): Type of Particle and determines the name of the ParticleList.
1003 If the input MDST type is V0 the whole decay chain needs to be specified, so that
1004 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``).
1005 If the input MDST type is Kink the decay chain needs to be specified
1006 with only one daughter (e.g. ``K- -> pi-``).
1007 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1008 writeOut (bool): whether RootOutput module should save the created ParticleList
1009 path (basf2.Path): modules are added to this path
1010 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
1011 using a mass hypothesis of the exact type passed to fillParticleLists().
1012 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1013 in terms of mass difference will be used if the fit using exact particle
1014 type is not available.
1015 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
1018 pload = register_module(
'ParticleLoader')
1019 pload.set_name(
'ParticleLoader_' + decayString)
1020 pload.param(
'decayStrings', [decayString])
1021 pload.param(
'writeOut', writeOut)
1022 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1023 path.add_module(pload)
1026 from ROOT
import Belle2
1028 if not decayDescriptor.init(decayString):
1029 raise ValueError(
"Invalid decay string")
1030 if decayDescriptor.getNDaughters() > 0:
1035 if (decayDescriptor.getNDaughters() == 1)
and (decayDescriptor.getMother().getLabel() !=
'kink'):
1036 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':kink',
1038 if (decayDescriptor.getNDaughters() > 1)
and (decayDescriptor.getMother().getLabel() !=
'V0'):
1039 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut,
1041 elif (decayDescriptor.getMother().getLabel() !=
'all' and
1042 abs(decayDescriptor.getMother().getPDGCode()) != Belle2.Const.neutron.getPDGCode()):
1045 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1049 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1051 if decayString.startswith(
"gamma"):
1054 if not loadPhotonsFromKLM:
1055 applyCuts(decayString,
'isFromECL', path)
1058def fillParticleListWithTrackHypothesis(decayString,
1062 enforceFitHypothesis=False,
1065 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
1067 @param decayString specifies type of Particles and determines the name of the ParticleList
1068 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1069 @param hypothesis the PDG code of the desired track hypothesis
1070 @param writeOut whether RootOutput module should save the created ParticleList
1071 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
1072 using a mass hypothesis of the exact type passed to fillParticleLists().
1073 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1074 in terms of mass difference will be used if the fit using exact particle
1075 type is not available.
1076 @param path modules are added to this path
1079 pload = register_module(
'ParticleLoader')
1080 pload.set_name(
'ParticleLoader_' + decayString)
1081 pload.param(
'decayStrings', [decayString])
1082 pload.param(
'trackHypothesis', hypothesis)
1083 pload.param(
'writeOut', writeOut)
1084 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1085 path.add_module(pload)
1087 from ROOT
import Belle2
1089 if not decayDescriptor.init(decayString):
1090 raise ValueError(
"Invalid decay string")
1091 if decayDescriptor.getMother().getLabel() !=
'all':
1094 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1098 applyCuts(decayString, cut, path)
1101def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
1103 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
1106 You must specify the daughter ordering.
1108 .. code-block:: python
1110 fillConvertedPhotonsList('gamma:converted -> e+ e-', '', path=mypath)
1113 decayString (str): Must be gamma to an e+e- pair. You must specify the daughter ordering.
1114 Will also determine the name of the particleList.
1115 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1116 writeOut (bool): whether RootOutput module should save the created ParticleList
1117 path (basf2.Path): modules are added to this path
1123 B2ERROR(
'For Belle converted photons are available in the pre-defined list "gamma:v0mdst".')
1125 pload = register_module(
'ParticleLoader')
1126 pload.set_name(
'ParticleLoader_' + decayString)
1127 pload.param(
'decayStrings', [decayString])
1128 pload.param(
'addDaughters',
True)
1129 pload.param(
'writeOut', writeOut)
1130 path.add_module(pload)
1132 from ROOT
import Belle2
1134 if not decayDescriptor.init(decayString):
1135 raise ValueError(
"Invalid decay string")
1136 if decayDescriptor.getMother().getLabel() !=
'V0':
1139 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1143 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1146def fillParticleListFromROE(decayString,
1149 sourceParticleListName='',
1154 Creates Particle object for each ROE of the desired type found in the
1155 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
1156 and fills the ParticleList. If useMissing is True, then the missing
1157 momentum is used instead of ROE.
1159 The type of the particles to be loaded is specified via the decayString module parameter.
1161 @param decayString specifies type of Particles and determines the name of the ParticleList.
1162 Source ROEs can be taken as a daughter list, for example:
1163 'B0:tagFromROE -> B0:signal'
1164 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1165 @param maskName Name of the ROE mask to use
1166 @param sourceParticleListName Use related ROEs to this particle list as a source
1167 @param useMissing Use missing momentum instead of ROE momentum
1168 @param writeOut whether RootOutput module should save the created ParticleList
1169 @param path modules are added to this path
1172 pload = register_module(
'ParticleLoader')
1173 pload.set_name(
'ParticleLoader_' + decayString)
1174 pload.param(
'decayStrings', [decayString])
1175 pload.param(
'writeOut', writeOut)
1176 pload.param(
'roeMaskName', maskName)
1177 pload.param(
'useMissing', useMissing)
1178 pload.param(
'sourceParticleListName', sourceParticleListName)
1179 pload.param(
'useROEs',
True)
1180 path.add_module(pload)
1182 from ROOT
import Belle2
1184 if not decayDescriptor.init(decayString):
1185 raise ValueError(
"Invalid decay string")
1189 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1192def fillParticleListFromDummy(decayString,
1195 treatAsInvisible=True,
1199 Creates a ParticleList and fills it with dummy Particles. For self-conjugated Particles one dummy
1200 Particle is created, for Particles that are not self-conjugated one Particle and one anti-Particle is
1201 created. The four-momentum is set to zero.
1203 The type of the particles to be loaded is specified via the decayString module parameter.
1205 @param decayString specifies type of Particles and determines the name of the ParticleList
1206 @param mdstIndex sets the mdst index of Particles
1207 @param covMatrix sets the value of the diagonal covariance matrix of Particles
1208 @param treatAsInvisible whether treeFitter should treat the Particles as invisible
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(
'useDummy',
True)
1217 pload.param(
'dummyMDSTIndex', mdstIndex)
1218 pload.param(
'dummyCovMatrix', covMatrix)
1219 pload.param(
'dummyTreatAsInvisible', treatAsInvisible)
1220 pload.param(
'writeOut', writeOut)
1221 path.add_module(pload)
1224def fillParticleListFromMC(decayString,
1227 skipNonPrimaryDaughters=False,
1230 skipNonPrimary=False,
1233 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1234 loads them to the StoreArray<Particle> and fills the ParticleList.
1236 The type of the particles to be loaded is specified via the decayString module parameter.
1238 @param decayString specifies type of Particles and determines the name of the ParticleList
1239 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1240 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1241 sets mother-daughter relations
1242 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1243 @param writeOut whether RootOutput module should save the created ParticleList
1244 @param path modules are added to this path
1245 @param skipNonPrimary if true, skip non primary particle
1246 @param skipInitial if true, skip initial particles
1249 pload = register_module(
'ParticleLoader')
1250 pload.set_name(
'ParticleLoader_' + decayString)
1251 pload.param(
'decayStrings', [decayString])
1252 pload.param(
'addDaughters', addDaughters)
1253 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1254 pload.param(
'writeOut', writeOut)
1255 pload.param(
'useMCParticles',
True)
1256 pload.param(
'skipNonPrimary', skipNonPrimary)
1257 pload.param(
'skipInitial', skipInitial)
1258 path.add_module(pload)
1260 from ROOT
import Belle2
1262 if not decayDescriptor.init(decayString):
1263 raise ValueError(
"Invalid decay string")
1267 applyCuts(decayString, cut, path)
1270def fillParticleListsFromMC(decayStringsWithCuts,
1272 skipNonPrimaryDaughters=False,
1275 skipNonPrimary=False,
1278 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1279 loads them to the StoreArray<Particle> and fills the ParticleLists.
1281 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
1284 .. code-block:: python
1286 kaons = ('K+:gen', '')
1287 pions = ('pi+:gen', 'pionID>0.1')
1288 fillParticleListsFromMC([kaons, pions], path=mypath)
1291 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not final state particle.
1292 Thus, when one reconstructs a particle from ``Lambda0``, that is created with
1293 ``addDaughters=True`` and ``skipNonPrimaryDaughters=True``, the particle always has ``isSignal==0``.
1294 Please set options for ``Lambda0`` to use MC-matching variables properly as follows,
1295 ``addDaughters=True`` and ``skipNonPrimaryDaughters=False``.
1297 @param decayString specifies type of Particles and determines the name of the ParticleList
1298 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1299 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1300 sets mother-daughter relations
1301 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1302 @param writeOut whether RootOutput module should save the created ParticleList
1303 @param path modules are added to this path
1304 @param skipNonPrimary if true, skip non primary particle
1305 @param skipInitial if true, skip initial particles
1308 pload = register_module(
'ParticleLoader')
1309 pload.set_name(
'ParticleLoader_' +
'PLists')
1310 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
1311 pload.param(
'addDaughters', addDaughters)
1312 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1313 pload.param(
'writeOut', writeOut)
1314 pload.param(
'useMCParticles',
True)
1315 pload.param(
'skipNonPrimary', skipNonPrimary)
1316 pload.param(
'skipInitial', skipInitial)
1317 path.add_module(pload)
1319 from ROOT
import Belle2
1321 for decayString, cut
in decayStringsWithCuts:
1322 if not decayDescriptor.init(decayString):
1323 raise ValueError(
"Invalid decay string")
1327 applyCuts(decayString, cut, path)
1330def fillParticleListFromChargedCluster(outputParticleList,
1333 useOnlyMostEnergeticECLCluster=True,
1337 Creates the Particle object from ECLCluster and KLMCluster that are being matched with the Track of inputParticleList.
1339 @param outputParticleList The output ParticleList. Only neutral final state particles are supported.
1340 @param inputParticleList The input ParticleList that is required to have the relation to the Track object.
1341 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1342 @param useOnlyMostEnergeticECLCluster If True, only the most energetic ECLCluster among ones that are matched with the Track is
1343 used. If False, all matched ECLClusters are loaded. The default is True. Regardless of
1344 this option, the KLMCluster is loaded.
1345 @param writeOut whether RootOutput module should save the created ParticleList
1346 @param path modules are added to this path
1349 pload = register_module(
'ParticleLoader')
1350 pload.set_name(
'ParticleLoader_' + outputParticleList)
1352 pload.param(
'decayStrings', [outputParticleList])
1353 pload.param(
'sourceParticleListName', inputParticleList)
1354 pload.param(
'writeOut', writeOut)
1355 pload.param(
'loadChargedCluster',
True)
1356 pload.param(
'useOnlyMostEnergeticECLCluster', useOnlyMostEnergeticECLCluster)
1357 path.add_module(pload)
1361 applyCuts(outputParticleList, cut, path)
1364def extractParticlesFromROE(particleLists,
1365 signalSideParticleList=None,
1370 Extract Particle objects that belong to the Rest-Of-Events and fill them into the ParticleLists.
1371 The types of the particles other than those specified by ``particleLists`` are not stored.
1372 If one creates a ROE with ``fillWithMostLikely=True`` via `buildRestOfEvent`, for example,
1373 one should create particleLists for not only ``pi+``, ``gamma``, ``K_L0`` but also other charged final state particles.
1375 When one calls the function in the main path, one has to set the argument ``signalSideParticleList`` and the signal side
1376 ParticleList must have only one candidate.
1378 .. code-block:: python
1380 buildRestOfEvent('B0:sig', fillWithMostLikely=True, path=mypath)
1382 roe_path = create_path()
1383 deadEndPath = create_path()
1384 signalSideParticleFilter('B0:sig', '', roe_path, deadEndPath)
1386 plists = ['%s:in_roe' % ptype for ptype in ['pi+', 'gamma', 'K_L0', 'K+', 'p+', 'e+', 'mu+']]
1387 extractParticlesFromROE(plists, maskName='all', path=roe_path)
1389 # one can analyze these ParticleLists in the roe_path
1391 mypath.for_each('RestOfEvent', 'RestOfEvents', roe_path)
1393 rankByLowest('B0:sig', 'deltaE', numBest=1, path=mypath)
1394 extractParticlesFromROE(plists, signalSideParticleList='B0:sig', maskName='all', path=mypath)
1396 # one can analyze these ParticleLists in the main path
1399 @param particleLists (str or list(str)) Name of output ParticleLists
1400 @param signalSideParticleList (str) Name of signal side ParticleList
1401 @param maskName (str) Name of the ROE mask to be applied on Particles
1402 @param writeOut (bool) whether RootOutput module should save the created ParticleList
1403 @param path (basf2.Path) modules are added to this path
1406 if isinstance(particleLists, str):
1407 particleLists = [particleLists]
1409 pext = register_module(
'ParticleExtractorFromROE')
1410 pext.set_name(
'ParticleExtractorFromROE_' +
'_'.join(particleLists))
1411 pext.param(
'outputListNames', particleLists)
1412 if signalSideParticleList
is not None:
1413 pext.param(
'signalSideParticleListName', signalSideParticleList)
1414 pext.param(
'maskName', maskName)
1415 pext.param(
'writeOut', writeOut)
1416 path.add_module(pext)
1419def applyCuts(list_name, cut, path):
1421 Removes particle candidates from ``list_name`` that do not pass ``cut``
1422 (given selection criteria).
1425 require energetic pions safely inside the cdc
1427 .. code-block:: python
1429 applyCuts("pi+:mypions", "[E > 2] and thetaInCDCAcceptance", path=mypath)
1432 You must use square braces ``[`` and ``]`` for conditional statements.
1435 list_name (str): input ParticleList name
1436 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
1437 path (basf2.Path): modules are added to this path
1440 pselect = register_module(
'ParticleSelector')
1441 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
1442 pselect.param(
'decayString', list_name)
1443 pselect.param(
'cut', cut)
1444 path.add_module(pselect)
1447def applyEventCuts(cut, path, metavariables=None):
1449 Removes events that do not pass the ``cut`` (given selection criteria).
1452 continuum events (in mc only) with more than 5 tracks
1454 .. code-block:: python
1456 applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1459 Only event-based variables are allowed in this function
1460 and only square brackets ``[`` and ``]`` for conditional statements.
1463 cut (str): Events that do not pass these selection criteria are skipped
1464 path (basf2.Path): modules are added to this path
1465 metavariables (list(str)): List of meta variables to be considered in decomposition of cut
1469 from variables
import variables
1471 def find_vars(t: tuple, var_list: list, meta_list: list) ->
None:
1472 """ Recursive helper function to find variable names """
1473 if not isinstance(t, tuple):
1475 if t[0] == b2parser.B2ExpressionParser.node_types[
'IdentifierNode']:
1478 if t[0] == b2parser.B2ExpressionParser.node_types[
'FunctionNode']:
1479 meta_list.append(list(t[1:]))
1482 if isinstance(i, tuple):
1483 find_vars(i, var_list, meta_list)
1485 def check_variable(var_list: list, metavar_ids: list) ->
None:
1486 for var_string
in var_list:
1488 orig_name = variables.resolveAlias(var_string)
1489 if orig_name != var_string:
1492 find_vars(
b2parser.parse(orig_name), var_list_temp, meta_list_temp)
1494 check_variable(var_list_temp, metavar_ids)
1495 check_meta(meta_list_temp, metavar_ids)
1498 var = variables.getVariable(var_string)
1499 if event_var_id
not in var.description:
1500 B2ERROR(f
'Variable {var_string} is not an event-based variable! "\
1501 "Please check your inputs to the applyEventCuts method!')
1503 def check_meta(meta_list: list, metavar_ids: list) ->
None:
1504 for meta_string_list
in meta_list:
1506 while meta_string_list[0]
in metavar_ids:
1508 meta_string_list.pop(0)
1509 for meta_string
in meta_string_list[0].split(
","):
1510 find_vars(
b2parser.parse(meta_string), var_list_temp, meta_string_list)
1511 if len(meta_string_list) > 0:
1512 meta_string_list.pop(0)
1513 if len(meta_string_list) == 0:
1515 if len(meta_string_list) > 1:
1516 meta_list += meta_string_list[1:]
1517 if isinstance(meta_string_list[0], list):
1518 meta_string_list = [element
for element
in meta_string_list[0]]
1520 check_variable(var_list_temp, metavar_ids)
1522 if len(meta_string_list) == 0:
1524 elif len(meta_string_list) == 1:
1525 var = variables.getVariable(meta_string_list[0])
1527 var = variables.getVariable(meta_string_list[0], meta_string_list[1].split(
","))
1529 if event_var_id
in var.description:
1532 B2ERROR(f
'Variable {var.name} is not an event-based variable! Please check your inputs to the applyEventCuts method!')
1534 event_var_id =
'[Eventbased]'
1535 metavar_ids = [
'formula',
'abs',
1539 'exp',
'log',
'log10',
1541 'isNAN',
'ifNANgiveX']
1543 metavar_ids += metavariables
1547 find_vars(
b2parser.parse(cut), var_list=var_list, meta_list=meta_list)
1549 if len(var_list) == 0
and len(meta_list) == 0:
1550 B2WARNING(f
'Cut string "{cut}" has no variables for applyEventCuts helper function!')
1552 check_variable(var_list, metavar_ids)
1553 check_meta(meta_list, metavar_ids)
1555 eselect = register_module(
'VariableToReturnValue')
1556 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1557 path.add_module(eselect)
1558 empty_path = create_path()
1559 eselect.if_value(
'<1', empty_path)
1562def reconstructDecay(decayString,
1567 candidate_limit=None,
1568 ignoreIfTooManyCandidates=True,
1569 chargeConjugation=True,
1570 allowChargeViolation=False):
1572 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1573 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1574 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1575 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1576 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1578 One can use an ``@``-sign to mark a particle as unspecified for inclusive analyses,
1579 e.g. in a DecayString: :code:`'@Xsd -> K+ pi-'`.
1581 .. seealso:: :ref:`Marker_of_unspecified_particle`
1584 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1585 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1586 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1588 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1589 This can be solved by manually randomising the lists before combining.
1593 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1594 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1596 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1597 (from the DecayString the mother and daughter ParticleLists are determined)
1598 @param cut created (mother) Particles are added to the mother ParticleList if they
1599 pass give cuts (in VariableManager style) and rejected otherwise
1600 @param dmID user specified decay mode identifier
1601 @param writeOut whether RootOutput module should save the created ParticleList
1602 @param path modules are added to this path
1603 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1604 the number of candidates is exceeded a Warning will be
1606 By default, all these candidates will be removed and event will be ignored.
1607 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1608 If no value is given the amount is limited to a sensible
1609 default. A value <=0 will disable this limit and can
1610 cause huge memory amounts so be careful.
1611 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1612 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1613 otherwise, number of candidates in candidate_limit is reconstructed.
1614 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1615 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1618 pmake = register_module(
'ParticleCombiner')
1619 pmake.set_name(
'ParticleCombiner_' + decayString)
1620 pmake.param(
'decayString', decayString)
1621 pmake.param(
'cut', cut)
1622 pmake.param(
'decayMode', dmID)
1623 pmake.param(
'writeOut', writeOut)
1624 if candidate_limit
is not None:
1625 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1626 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1627 pmake.param(
'chargeConjugation', chargeConjugation)
1628 pmake.param(
"allowChargeViolation", allowChargeViolation)
1629 path.add_module(pmake)
1632def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1634 Creates a new Particle as the combination of all Particles from all
1635 provided inputParticleLists. However, each particle is used only once
1636 (even if duplicates are provided) and the combination has to pass the
1637 specified selection criteria to be saved in the newly created (mother)
1640 @param inputParticleLists List of input particle lists which are combined to the new Particle
1641 @param outputList Name of the particle combination created with this module
1642 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1643 these given cuts (in VariableManager style) and is rejected otherwise
1644 @param writeOut whether RootOutput module should save the created ParticleList
1645 @param path module is added to this path
1648 pmake = register_module(
'AllParticleCombiner')
1649 pmake.set_name(
'AllParticleCombiner_' + outputList)
1650 pmake.param(
'inputListNames', inputParticleLists)
1651 pmake.param(
'outputListName', outputList)
1652 pmake.param(
'cut', cut)
1653 pmake.param(
'writeOut', writeOut)
1654 path.add_module(pmake)
1657def reconstructMissingKlongDecayExpert(decayString,
1664 Creates a list of K_L0's and of B -> K_L0 + X, with X being a fully-reconstructed state.
1665 The K_L0 momentum is determined from kinematic constraints of the two-body B decay into K_L0 and X
1667 @param decayString DecayString specifying what kind of the decay should be reconstructed
1668 (from the DecayString the mother and daughter ParticleLists are determined)
1669 @param cut Particles are added to the K_L0 and B ParticleList if the B candidates
1670 pass the given cuts (in VariableManager style) and rejected otherwise
1671 @param dmID user specified decay mode identifier
1672 @param writeOut whether RootOutput module should save the created ParticleList
1673 @param path modules are added to this path
1674 @param recoList suffix appended to original K_L0 and B ParticleList that identify the newly created K_L0 and B lists
1677 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1678 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1679 pcalc.param(
'decayString', decayString)
1680 pcalc.param(
'writeOut', writeOut)
1681 pcalc.param(
'recoList', recoList)
1682 path.add_module(pcalc)
1684 rmake = register_module(
'KlongDecayReconstructorExpert')
1685 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1686 rmake.param(
'decayString', decayString)
1687 rmake.param(
'cut', cut)
1688 rmake.param(
'decayMode', dmID)
1689 rmake.param(
'writeOut', writeOut)
1690 rmake.param(
'recoList', recoList)
1691 path.add_module(rmake)
1694def setBeamConstrainedMomentum(particleList, decayStringTarget, decayStringDaughters, path=None):
1696 Replace the four-momentum of the target Particle by p(beam) - p(selected daughters).
1697 The momentum of the mother Particle will not be changed.
1699 @param particleList mother Particlelist
1700 @param decayStringTarget DecayString specifying the target particle whose momentum
1702 @param decayStringDaughters DecayString specifying the daughter particles used to replace
1703 the momentum of the target particle by p(beam)-p(daughters)
1706 mod = register_module(
'ParticleMomentumUpdater')
1707 mod.set_name(
'ParticleMomentumUpdater' + particleList)
1708 mod.param(
'particleList', particleList)
1709 mod.param(
'decayStringTarget', decayStringTarget)
1710 mod.param(
'decayStringDaughters', decayStringDaughters)
1711 path.add_module(mod)
1714def updateKlongKinematicsExpert(particleList,
1718 Calculates and updates the kinematics of B->K_L0 + something else with same method as
1719 `reconstructMissingKlongDecayExpert`. This helps to revert the kinematics after the vertex fitting.
1721 @param particleList input ParticleList of B meson that decays to K_L0 + X
1722 @param writeOut whether RootOutput module should save the ParticleList
1723 @param path modules are added to this path
1726 mod = register_module(
'KlongMomentumUpdaterExpert')
1727 mod.set_name(
'KlongMomentumUpdaterExpert_' + particleList)
1728 mod.param(
'listName', particleList)
1729 mod.param(
'writeOut', writeOut)
1730 path.add_module(mod)
1733def replaceMass(replacerName, particleLists=None, pdgCode=22, path=None):
1735 replaces the mass of the particles inside the given particleLists
1736 with the invariant mass of the particle corresponding to the given pdgCode.
1738 @param particleLists new ParticleList filled with copied Particles
1739 @param pdgCode PDG code for mass reference
1740 @param path modules are added to this path
1743 if particleLists
is None:
1747 pmassupdater = register_module(
'ParticleMassUpdater')
1748 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1749 pmassupdater.param(
'particleLists', particleLists)
1750 pmassupdater.param(
'pdgCode', pdgCode)
1751 path.add_module(pmassupdater)
1754def reconstructRecoil(decayString,
1759 candidate_limit=None,
1760 allowChargeViolation=False):
1762 Creates new Particles that recoil against the input particles.
1764 For example the decay string M -> D1 D2 D3 will:
1766 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1767 - Particles D1, D2, D3 will be appended as daughters to M
1768 - the 4-momentum of the mother Particle M is given by
1769 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1771 @param decayString DecayString specifying what kind of the decay should be reconstructed
1772 (from the DecayString the mother and daughter ParticleLists are determined)
1773 @param cut created (mother) Particles are added to the mother ParticleList if they
1774 pass give cuts (in VariableManager style) and rejected otherwise
1775 @param dmID user specified decay mode identifier
1776 @param writeOut whether RootOutput module should save the created ParticleList
1777 @param path modules are added to this path
1778 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1779 the number of candidates is exceeded no candidate will be
1780 reconstructed for that event and a Warning will be
1782 If no value is given the amount is limited to a sensible
1783 default. A value <=0 will disable this limit and can
1784 cause huge memory amounts so be careful.
1785 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1788 pmake = register_module(
'ParticleCombiner')
1789 pmake.set_name(
'ParticleCombiner_' + decayString)
1790 pmake.param(
'decayString', decayString)
1791 pmake.param(
'cut', cut)
1792 pmake.param(
'decayMode', dmID)
1793 pmake.param(
'writeOut', writeOut)
1794 pmake.param(
'recoilParticleType', 1)
1795 if candidate_limit
is not None:
1796 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1797 pmake.param(
'allowChargeViolation', allowChargeViolation)
1798 path.add_module(pmake)
1801def reconstructRecoilDaughter(decayString,
1806 candidate_limit=None,
1807 allowChargeViolation=False):
1809 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1811 For example the decay string M -> D1 D2 D3 will:
1813 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1814 - Particles D1, D2, D3 will be appended as daughters to M
1815 - the 4-momentum of the mother Particle M is given by
1816 p(M) = p(D1) - Sum_i p(Di), where i>1
1818 @param decayString DecayString specifying what kind of the decay should be reconstructed
1819 (from the DecayString the mother and daughter ParticleLists are determined)
1820 @param cut created (mother) Particles are added to the mother ParticleList if they
1821 pass give cuts (in VariableManager style) and rejected otherwise
1822 @param dmID user specified decay mode identifier
1823 @param writeOut whether RootOutput module should save the created ParticleList
1824 @param path modules are added to this path
1825 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1826 the number of candidates is exceeded no candidate will be
1827 reconstructed for that event and a Warning will be
1829 If no value is given the amount is limited to a sensible
1830 default. A value <=0 will disable this limit and can
1831 cause huge memory amounts so be careful.
1832 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1833 daughter is actually the mother
1836 pmake = register_module(
'ParticleCombiner')
1837 pmake.set_name(
'ParticleCombiner_' + decayString)
1838 pmake.param(
'decayString', decayString)
1839 pmake.param(
'cut', cut)
1840 pmake.param(
'decayMode', dmID)
1841 pmake.param(
'writeOut', writeOut)
1842 pmake.param(
'recoilParticleType', 2)
1843 if candidate_limit
is not None:
1844 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1845 pmake.param(
'allowChargeViolation', allowChargeViolation)
1846 path.add_module(pmake)
1849def rankByHighest(particleList,
1853 allowMultiRank=False,
1855 overwriteRank=False,
1858 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1859 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1860 The list is also sorted from best to worst candidate
1861 (each charge, e.g. B+/B-, separately).
1862 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1863 a non-zero value for 'numBest'.
1866 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1867 These variable names can become clunky, so it's probably a good idea to set an alias.
1868 For example if you rank your B candidates by momentum,
1872 rankByHighest("B0:myCandidates", "p", path=mypath)
1873 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1876 @param particleList The input ParticleList
1877 @param variable Variable to order Particles by.
1878 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1879 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1880 @param allowMultiRank If true, candidates with the same value will get the same rank.
1881 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1882 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1883 @param path modules are added to this path
1886 bcs = register_module(
'BestCandidateSelection')
1887 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1888 bcs.param(
'particleList', particleList)
1889 bcs.param(
'variable', variable)
1890 bcs.param(
'numBest', numBest)
1891 bcs.param(
'outputVariable', outputVariable)
1892 bcs.param(
'allowMultiRank', allowMultiRank)
1893 bcs.param(
'cut', cut)
1894 bcs.param(
'overwriteRank', overwriteRank)
1895 path.add_module(bcs)
1898def rankByLowest(particleList,
1902 allowMultiRank=False,
1904 overwriteRank=False,
1907 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1908 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1909 The list is also sorted from best to worst candidate
1910 (each charge, e.g. B+/B-, separately).
1911 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1912 a non-zero value for 'numBest'.
1915 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1916 These variable names can become clunky, so it's probably a good idea to set an alias.
1917 For example if you rank your B candidates by :b2:var:`dM`,
1921 rankByLowest("B0:myCandidates", "dM", path=mypath)
1922 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1925 @param particleList The input ParticleList
1926 @param variable Variable to order Particles by.
1927 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1928 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1929 @param allowMultiRank If true, candidates with the same value will get the same rank.
1930 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1931 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1932 @param path modules are added to this path
1935 bcs = register_module(
'BestCandidateSelection')
1936 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1937 bcs.param(
'particleList', particleList)
1938 bcs.param(
'variable', variable)
1939 bcs.param(
'numBest', numBest)
1940 bcs.param(
'selectLowest',
True)
1941 bcs.param(
'allowMultiRank', allowMultiRank)
1942 bcs.param(
'outputVariable', outputVariable)
1943 bcs.param(
'cut', cut)
1944 bcs.param(
'overwriteRank', overwriteRank)
1945 path.add_module(bcs)
1948def applyRandomCandidateSelection(particleList, path=None):
1950 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1951 This is done on a event-by-event basis.
1953 @param particleList ParticleList for which the random candidate selection should be applied
1954 @param path module is added to this path
1957 rcs = register_module(
'BestCandidateSelection')
1958 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1959 rcs.param(
'particleList', particleList)
1960 rcs.param(
'variable',
'random')
1961 rcs.param(
'selectLowest',
False)
1962 rcs.param(
'allowMultiRank',
False)
1963 rcs.param(
'numBest', 1)
1964 rcs.param(
'cut',
'')
1965 rcs.param(
'outputVariable',
'')
1966 path.add_module(rcs)
1971 Prints the contents of DataStore in the first event (or a specific event number or all events).
1972 Will list all objects and arrays (including size).
1975 The command line tool: ``b2file-size``.
1978 eventNumber (int): Print the datastore only for this event. The default
1979 (-1) prints only the first event, 0 means print for all events (can produce large output)
1980 path (basf2.Path): the PrintCollections module is added to this path
1983 This will print a lot of output if you print it for all events and process many events.
1987 printDS = register_module(
'PrintCollections')
1988 printDS.param(
'printForEvent', eventNumber)
1989 path.add_module(printDS)
1992def printVariableValues(list_name, var_names, path):
1994 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
1996 @param list_name input ParticleList name
1997 @param var_names vector of variable names to be printed
1998 @param path modules are added to this path
2001 prlist = register_module(
'ParticlePrinter')
2002 prlist.set_name(
'ParticlePrinter_' + list_name)
2003 prlist.param(
'listName', list_name)
2004 prlist.param(
'fullPrint',
False)
2005 prlist.param(
'variables', var_names)
2006 path.add_module(prlist)
2009def printList(list_name, full, path):
2011 Prints the size and executes Particle->print() (if full=True)
2012 method for all Particles in given ParticleList. For debugging purposes.
2014 @param list_name input ParticleList name
2015 @param full execute Particle->print() method for all Particles
2016 @param path modules are added to this path
2019 prlist = register_module(
'ParticlePrinter')
2020 prlist.set_name(
'ParticlePrinter_' + list_name)
2021 prlist.param(
'listName', list_name)
2022 prlist.param(
'fullPrint', full)
2023 path.add_module(prlist)
2026def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None, basketsize=1600,
2027 signalSideParticleList="", filenameSuffix="", useFloat=False, storeEventType=True,
2028 ignoreCommandLineOverride=False):
2030 Creates and fills a flat ntuple with the specified variables from the VariableManager.
2031 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
2032 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
2035 decayString (str): specifies type of Particles and determines the name of the ParticleList
2036 variables (list(str)): the list of variables (which must be registered in the VariableManager)
2037 treename (str): name of the ntuple tree
2038 filename (str): which is used to store the variables
2039 path (basf2.Path): the basf2 path where the analysis is processed
2040 basketsize (int): size of baskets in the output ntuple in bytes
2041 signalSideParticleList (str): The name of the signal-side ParticleList.
2042 Only valid if the module is called in a for_each loop over the RestOfEvent.
2043 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2044 useFloat (bool): Use single precision (float) instead of double precision (double)
2045 for floating-point numbers.
2046 storeEventType (bool) : if true, the branch __eventType__ is added for the MC event type information.
2047 The information is available from MC16 on.
2048 ignoreCommandLineOverride (bool) : if true, ignore override of file name via command line argument ``-o``.
2050 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2053 output = register_module(
'VariablesToNtuple')
2054 output.set_name(
'VariablesToNtuple_' + decayString)
2055 output.param(
'particleList', decayString)
2056 output.param(
'variables', variables)
2057 output.param(
'fileName', filename)
2058 output.param(
'treeName', treename)
2059 output.param(
'basketSize', basketsize)
2060 output.param(
'signalSideParticleList', signalSideParticleList)
2061 output.param(
'fileNameSuffix', filenameSuffix)
2062 output.param(
'useFloat', useFloat)
2063 output.param(
'storeEventType', storeEventType)
2064 output.param(
'ignoreCommandLineOverride', ignoreCommandLineOverride)
2065 path.add_module(output)
2071 filename='ntuple.root',
2074 prefixDecayString=False,
2076 ignoreCommandLineOverride=False):
2078 Creates and fills a flat ntuple with the specified variables from the VariableManager
2081 decayString (str): specifies type of Particles and determines the name of the ParticleList
2082 variables (list(tuple))): variables + binning which must be registered in the VariableManager
2083 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
2084 filename (str): which is used to store the variables
2085 path (basf2.Path): the basf2 path where the analysis is processed
2086 directory (str): directory inside the output file where the histograms should be saved.
2087 Useful if you want to have different histograms in the same file to separate them.
2088 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
2089 programmatic naming of the structure in the file.
2090 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2091 ignoreCommandLineOverride (bool) : if true, ignore override of file name via command line argument ``-o``.
2093 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2096 if variables_2d
is None:
2098 output = register_module(
'VariablesToHistogram')
2099 output.set_name(
'VariablesToHistogram_' + decayString)
2100 output.param(
'particleList', decayString)
2101 output.param(
'variables', variables)
2102 output.param(
'variables_2d', variables_2d)
2103 output.param(
'fileName', filename)
2104 output.param(
'fileNameSuffix', filenameSuffix)
2105 output.param(
'ignoreCommandLineOverride', ignoreCommandLineOverride)
2106 if directory
is not None or prefixDecayString:
2107 if directory
is None:
2109 if prefixDecayString:
2110 directory = decayString +
"_" + directory
2111 output.param(
"directory", directory)
2112 path.add_module(output)
2117 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
2118 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
2121 particleList (str): The input ParticleList
2122 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2123 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2124 An existing extra info with the same name will be overwritten if the new
2125 value is lower / will never be overwritten / will be overwritten if the
2126 new value is higher / will always be overwritten (option = -1/0/1/2).
2127 path (basf2.Path): modules are added to this path
2130 mod = register_module(
'VariablesToExtraInfo')
2131 mod.set_name(
'VariablesToExtraInfo_' + particleList)
2132 mod.param(
'particleList', particleList)
2133 mod.param(
'variables', variables)
2134 mod.param(
'overwrite', option)
2135 path.add_module(mod)
2138def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
2140 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
2141 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
2142 to specified daughter particle.
2145 particleList (str): The input ParticleList
2146 decayString (str): Decay string that specifies to which daughter the extra info should be appended
2147 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2148 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2149 An existing extra info with the same name will be overwritten if the new
2150 value is lower / will never be overwritten / will be overwritten if the
2151 new value is higher / will always be overwritten (option = -1/0/1/2).
2152 path (basf2.Path): modules are added to this path
2155 mod = register_module(
'VariablesToExtraInfo')
2156 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
2157 mod.param(
'particleList', particleList)
2158 mod.param(
'decayString', decayString)
2159 mod.param(
'variables', variables)
2160 mod.param(
'overwrite', option)
2161 path.add_module(mod)
2164def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
2166 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
2167 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
2170 When the function is called first time not in the main path but in a sub-path e.g. ``roe_path``,
2171 the eventExtraInfo cannot be accessed from the main path because of the shorter lifetime of the event-extra-info field.
2172 If one wants to call the function in a sub-path, one has to call the function in the main path beforehand.
2175 particleList (str): The input ParticleList
2176 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2177 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2178 An existing extra info with the same name will be overwritten if the new
2179 value is lower / will never be overwritten / will be overwritten if the
2180 new value is higher / will always be overwritten (option = -1/0/1/2).
2181 path (basf2.Path): modules are added to this path
2184 mod = register_module(
'VariablesToEventExtraInfo')
2185 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
2186 mod.param(
'particleList', particleList)
2187 mod.param(
'variables', variables)
2188 mod.param(
'overwrite', option)
2189 path.add_module(mod)
2192def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
2194 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
2195 particle) as an extra info to the particle related to current ROE.
2196 Should be used only in the for_each roe path.
2199 particleList (str): The input ParticleList
2200 varToExtraInfo (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2201 path (basf2.Path): modules are added to this path
2204 mod = register_module(
'SignalSideVariablesToExtraInfo')
2205 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
2206 mod.param(
'particleListName', particleList)
2207 mod.param(
'variableToExtraInfo', varToExtraInfo)
2208 path.add_module(mod)
2211def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
2213 Define and blind a signal region.
2214 Per default, the defined signal region is cut out if ran on data.
2215 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
2219 .. code-block:: python
2221 ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
2222 ma.signalRegion("B+:sig",
2223 "Mbc>5.27 and abs(deltaE)<0.2",
2226 ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
2229 particleList (str): The input ParticleList
2230 cut (str): Cut string describing the signal region
2231 path (basf2.Path):: Modules are added to this path
2232 name (str): Name of the Signal region in the variable manager
2233 blind_data (bool): Automatically exclude signal region from data
2237 from variables
import variables
2238 mod = register_module(
'VariablesToExtraInfo')
2239 mod.set_name(f
'{name}_' + particleList)
2240 mod.param(
'particleList', particleList)
2241 mod.param(
'variables', {f
"passesCut({cut})": name})
2242 variables.addAlias(name, f
"extraInfo({name})")
2243 path.add_module(mod)
2247 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
2250def removeExtraInfo(particleLists=None, removeEventExtraInfo=False, path=None):
2252 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
2255 if particleLists
is None:
2257 mod = register_module(
'ExtraInfoRemover')
2258 mod.param(
'particleLists', particleLists)
2259 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
2260 path.add_module(mod)
2263def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
2265 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2266 to the particle from the input ParticleList. Additional selection criteria can be applied.
2267 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2268 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2269 suggests should be empty and its purpose is to end the execution of for_each roe path for
2270 the current ROE object.
2272 @param particleList The input ParticleList
2273 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2274 @param for_each roe path in which this filter is executed
2275 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2278 mod = register_module(
'SignalSideParticleFilter')
2279 mod.set_name(
'SigSideParticleFilter_' + particleList)
2280 mod.param(
'particleLists', [particleList])
2281 mod.param(
'selection', selection)
2282 roe_path.add_module(mod)
2283 mod.if_false(deadEndPath)
2286def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
2288 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2289 to the particle from the input ParticleList. Additional selection criteria can be applied.
2290 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2291 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2292 suggests should be empty and its purpose is to end the execution of for_each roe path for
2293 the current ROE object.
2295 @param particleLists The input ParticleLists
2296 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2297 @param for_each roe path in which this filter is executed
2298 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2301 mod = register_module(
'SignalSideParticleFilter')
2302 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
2303 mod.param(
'particleLists', particleLists)
2304 mod.param(
'selection', selection)
2305 roe_path.add_module(mod)
2306 mod.if_false(deadEndPath)
2315 chargeConjugation=True,
2318 Finds and creates a ``ParticleList`` from given decay string.
2319 ``ParticleList`` of daughters with sub-decay is created.
2321 Only the particles made from MCParticle, which can be loaded by `fillParticleListFromMC`, are accepted as daughters.
2323 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
2324 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
2327 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
2328 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
2329 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
2332 It is recommended to use only primary particles as daughter particles unless you want to explicitly study the secondary
2333 particles. The behavior of MC-matching for secondary particles from a stable particle decay is not guaranteed.
2334 Please consider to use `fillParticleListFromMC` with ``skipNonPrimary=True`` to load daughter particles.
2335 Moreover, it is recommended to load ``K_S0`` and ``Lambda0`` directly from MCParticle by `fillParticleListFromMC` rather
2336 than reconstructing from two pions or a proton-pion pair, because their direct daughters can be the secondary particle.
2339 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
2340 (from the DecayString the mother and daughter ParticleLists are determined)
2341 @param cut created (mother) Particles are added to the mother ParticleList if they
2342 pass given cuts (in VariableManager style) and rejected otherwise
2343 isSignal==1 is always required by default.
2344 @param dmID user specified decay mode identifier
2345 @param writeOut whether RootOutput module should save the created ParticleList
2346 @param path modules are added to this path
2347 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
2350 pmake = register_module(
'ParticleCombinerFromMC')
2351 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
2352 pmake.param(
'decayString', decayString)
2353 pmake.param(
'cut', cut)
2354 pmake.param(
'decayMode', dmID)
2355 pmake.param(
'writeOut', writeOut)
2356 pmake.param(
'chargeConjugation', chargeConjugation)
2357 path.add_module(pmake)
2364 appendAllDaughters=False,
2365 skipNonPrimaryDaughters=True,
2369 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
2370 The decay string is required to describe correctly what you want.
2371 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
2373 The output particles has only the daughter particles written in the given decay string, if
2374 ``appendAllDaughters=False`` (default). If ``appendAllDaughters=True``, all daughters of the matched MCParticle are
2375 appended in the order defined at the MCParticle level. For example,
2377 .. code-block:: python
2379 findMCDecay('B0:Xee', 'B0 -> e+ e- ... ?gamma', appendAllDaughters=False, path=mypath)
2381 The output ParticleList ``B0:Xee`` will match the inclusive ``B0 -> e+ e-`` decays (but neutrinos are not included),
2382 in both cases of ``appendAllDaughters`` is false and true.
2383 If the ``appendAllDaughters=False`` as above example, the ``B0:Xee`` has only two electrons as daughters.
2384 While, if ``appendAllDaughters=True``, all daughters of the matched MCParticles are appended. When the truth decay mode of
2385 the MCParticle is ``B0 -> [K*0 -> K+ pi-] [J/psi -> e+ e-]``, the first daughter of ``B0:Xee`` is ``K*0`` and ``e+``
2386 will be the first daughter of second daughter of ``B0:Xee``.
2388 The option ``skipNonPrimaryDaughters`` only has an effect if ``appendAllDaughters=True``. If ``skipNonPrimaryDaughters=True``,
2389 all primary daughters are appended but the secondary particles are not.
2392 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not a final state particle.
2393 In order for the MCMatching to work properly, the daughters of ``Lambda0`` are appended to
2394 ``Lambda0`` regardless of the value of the option ``skipNonPrimaryDaughters``.
2397 @param list_name The output particle list name
2398 @param decay The decay string which you want
2399 @param writeOut Whether `RootOutput` module should save the created ``outputList``
2400 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
2401 @param appendAllDaughters if true, not only the daughters described in the decay string but all daughters are appended
2402 @param path modules are added to this path
2405 decayfinder = register_module(
'MCDecayFinder')
2406 decayfinder.set_name(
'MCDecayFinder_' + list_name)
2407 decayfinder.param(
'listName', list_name)
2408 decayfinder.param(
'decayString', decay)
2409 decayfinder.param(
'appendAllDaughters', appendAllDaughters)
2410 decayfinder.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
2411 decayfinder.param(
'writeOut', writeOut)
2412 path.add_module(decayfinder)
2415def summaryOfLists(particleLists, outputFile=None, path=None):
2417 Prints out Particle statistics at the end of the job: number of events with at
2418 least one candidate, average number of candidates per event, etc.
2419 If an output file name is provided the statistics is also dumped into a json file with that name.
2421 @param particleLists list of input ParticleLists
2422 @param outputFile output file name (not created by default)
2425 particleStats = register_module(
'ParticleStats')
2426 particleStats.param(
'particleLists', particleLists)
2427 if outputFile
is not None:
2428 particleStats.param(
'outputFile', outputFile)
2429 path.add_module(particleStats)
2432def matchMCTruth(list_name, path):
2434 Performs MC matching (sets relation Particle->MCParticle) for
2435 all particles (and its (grand)^N-daughter particles) in the specified
2438 @param list_name name of the input ParticleList
2439 @param path modules are added to this path
2442 mcMatch = register_module(
'MCMatcherParticles')
2443 mcMatch.set_name(
'MCMatch_' + list_name)
2444 mcMatch.param(
'listName', list_name)
2445 path.add_module(mcMatch)
2448def looseMCTruth(list_name, path):
2450 Performs loose MC matching for all particles in the specified
2452 The difference between loose and normal mc matching algorithm is that
2453 the loose algorithm will find the common mother of the majority of daughter
2454 particles while the normal algorithm finds the common mother of all daughters.
2455 The results of loose mc matching algorithm are stored to the following extraInfo
2458 - looseMCMotherPDG: PDG code of most common mother
2459 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
2460 - looseMCWrongDaughterN: number of daughters that don't originate from the most common mother
2461 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from the most common mother (only if
2462 looseMCWrongDaughterN = 1)
2463 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background Particle
2465 @param list_name name of the input ParticleList
2466 @param path modules are added to this path
2469 mcMatch = register_module(
'MCMatcherParticles')
2470 mcMatch.set_name(
'LooseMCMatch_' + list_name)
2471 mcMatch.param(
'listName', list_name)
2472 mcMatch.param(
'looseMCMatching',
True)
2473 path.add_module(mcMatch)
2476def buildRestOfEvent(target_list_name, inputParticlelists=None,
2477 fillWithMostLikely=True,
2478 chargedPIDPriors=None, path=None):
2480 Creates for each Particle in the given ParticleList a RestOfEvent
2481 dataobject and makes basf2 relation between them. User can provide additional
2482 particle lists with a different particle hypothesis like ['K+:good, e+:good'], etc.
2484 @param target_list_name name of the input ParticleList
2485 @param inputParticlelists list of user-defined input particle list names, which serve
2486 as source of particles to build the ROE, the FSP particles from
2487 target_list_name are automatically excluded from the ROE object
2488 @param fillWithMostLikely By default the module uses the most likely particle mass hypothesis for charged particles
2489 based on the PID likelihood. Turn this behavior off if you want to configure your own
2490 input particle lists.
2491 @param chargedPIDPriors The prior PID fractions, that are used to regulate the
2492 amount of certain charged particle species, should be a list of
2493 six floats if not None. The order of particle types is
2494 the following: [e-, mu-, pi-, K-, p+, d+]
2495 @param path modules are added to this path
2498 if inputParticlelists
is None:
2499 inputParticlelists = []
2500 fillParticleList(
'pi+:all',
'', path=path)
2501 if fillWithMostLikely:
2502 from stdCharged
import stdMostLikely
2503 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
2504 inputParticlelists = [f
'{ptype}:mostlikely_roe' for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
2507 fillParticleList(
'gamma:all',
'', path=path)
2508 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
2509 inputParticlelists += [
'pi+:all',
'gamma:all',
'K_L0:roe_default']
2511 inputParticlelists += [
'pi+:all',
'gamma:mdst']
2512 roeBuilder = register_module(
'RestOfEventBuilder')
2513 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
2514 roeBuilder.param(
'particleList', target_list_name)
2515 roeBuilder.param(
'particleListsInput', inputParticlelists)
2516 roeBuilder.param(
'mostLikely', fillWithMostLikely)
2517 path.add_module(roeBuilder)
2520def buildNestedRestOfEvent(target_list_name, maskName='all', path=None):
2522 Creates for each Particle in the given ParticleList a RestOfEvent
2523 @param target_list_name name of the input ParticleList
2524 @param mask_name name of the ROEMask to be used
2525 @param path modules are added to this path
2528 roeBuilder = register_module(
'RestOfEventBuilder')
2529 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
2530 roeBuilder.param(
'particleList', target_list_name)
2531 roeBuilder.param(
'nestedROEMask', maskName)
2532 roeBuilder.param(
'createNestedROE',
True)
2533 path.add_module(roeBuilder)
2536def buildRestOfEventFromMC(target_list_name, inputParticlelists=None, path=None):
2538 Creates for each Particle in the given ParticleList a RestOfEvent
2539 @param target_list_name name of the input ParticleList
2540 @param inputParticlelists list of input particle list names, which serve
2541 as a source of particles to build ROE, the FSP particles from
2542 target_list_name are excluded from ROE object
2543 @param path modules are added to this path
2546 if inputParticlelists
is None:
2547 inputParticlelists = []
2548 if (len(inputParticlelists) == 0):
2552 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
2553 'n0',
'nu_e',
'nu_mu',
'nu_tau',
2556 fillParticleListFromMC(f
"{t}:roe_default_gen",
'mcPrimary > 0 and nDaughters == 0',
2557 True,
True, path=path)
2558 inputParticlelists += [f
"{t}:roe_default_gen"]
2559 roeBuilder = register_module(
'RestOfEventBuilder')
2560 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
2561 roeBuilder.param(
'particleList', target_list_name)
2562 roeBuilder.param(
'particleListsInput', inputParticlelists)
2563 roeBuilder.param(
'fromMC',
True)
2564 path.add_module(roeBuilder)
2567def appendROEMask(list_name,
2570 eclClusterSelection,
2571 klmClusterSelection='',
2574 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2575 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
2577 - append a ROE mask with all tracks in ROE coming from the IP region
2579 .. code-block:: python
2581 appendROEMask('B+:sig', 'IPtracks', '[dr < 2] and [abs(dz) < 5]', path=mypath)
2583 - append a ROE mask with only ECL-based particles that pass as good photon candidates
2585 .. code-block:: python
2587 goodPhotons = 'inCDCAcceptance and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
2588 appendROEMask('B+:sig', 'goodROEGamma', '', goodPhotons, path=mypath)
2591 @param list_name name of the input ParticleList
2592 @param mask_name name of the appended ROEMask
2593 @param trackSelection decay string for the track-based particles in ROE
2594 @param eclClusterSelection decay string for the ECL-based particles in ROE
2595 @param klmClusterSelection decay string for the KLM-based particles in ROE
2596 @param path modules are added to this path
2599 roeMask = register_module(
'RestOfEventInterpreter')
2600 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2601 roeMask.param(
'particleList', list_name)
2602 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2603 path.add_module(roeMask)
2606def appendROEMasks(list_name, mask_tuples, path=None):
2608 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2609 selection criteria for track-, ECL- and KLM-based particles which will be used by ROE variables.
2611 The multiple ROE masks with their own selection criteria are specified
2612 via list of tuples (mask_name, trackParticleSelection, eclParticleSelection, klmParticleSelection) or
2613 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
2615 - Example for two tuples, one with and one without fractions
2617 .. code-block:: python
2619 ipTracks = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', '')
2620 goodPhotons = 'inCDCAcceptance and [clusterErrorTiming < 1e6] and [clusterE1E9 > 0.4 or E > 0.075]'
2621 goodROEGamma = ('ROESel', '[dr < 2] and [abs(dz) < 5]', goodPhotons, '')
2622 goodROEKLM = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', 'nKLMClusterTrackMatches == 0')
2623 appendROEMasks('B+:sig', [ipTracks, goodROEGamma, goodROEKLM], path=mypath)
2625 @param list_name name of the input ParticleList
2626 @param mask_tuples array of ROEMask list tuples to be appended
2627 @param path modules are added to this path
2630 compatible_masks = []
2631 for mask
in mask_tuples:
2634 compatible_masks += [(*mask,
'')]
2636 compatible_masks += [mask]
2637 roeMask = register_module(
'RestOfEventInterpreter')
2638 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2639 roeMask.param(
'particleList', list_name)
2640 roeMask.param(
'ROEMasks', compatible_masks)
2641 path.add_module(roeMask)
2644def updateROEMask(list_name,
2647 eclClusterSelection='',
2648 klmClusterSelection='',
2651 Update an existing ROE mask by applying additional selection cuts for
2652 tracks and/or clusters.
2654 See function `appendROEMask`!
2656 @param list_name name of the input ParticleList
2657 @param mask_name name of the ROEMask to update
2658 @param trackSelection decay string for the track-based particles in ROE
2659 @param eclClusterSelection decay string for the ECL-based particles in ROE
2660 @param klmClusterSelection decay string for the KLM-based particles in ROE
2661 @param path modules are added to this path
2664 roeMask = register_module(
'RestOfEventInterpreter')
2665 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2666 roeMask.param(
'particleList', list_name)
2667 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2668 roeMask.param(
'update',
True)
2669 path.add_module(roeMask)
2672def updateROEMasks(list_name, mask_tuples, path):
2674 Update existing ROE masks by applying additional selection cuts for tracks
2677 The multiple ROE masks with their own selection criteria are specified
2678 via list tuples (mask_name, trackSelection, eclClusterSelection, klmClusterSelection)
2680 See function `appendROEMasks`!
2682 @param list_name name of the input ParticleList
2683 @param mask_tuples array of ROEMask list tuples to be appended
2684 @param path modules are added to this path
2687 compatible_masks = []
2688 for mask
in mask_tuples:
2691 compatible_masks += [(*mask,
'')]
2693 compatible_masks += [mask]
2695 roeMask = register_module(
'RestOfEventInterpreter')
2696 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2697 roeMask.param(
'particleList', list_name)
2698 roeMask.param(
'ROEMasks', compatible_masks)
2699 roeMask.param(
'update',
True)
2700 path.add_module(roeMask)
2703def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2705 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2706 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2707 This function should be executed only in the for_each roe path for the current ROE object.
2709 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2710 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2711 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2712 pion particle list (e.g. 'pi+:someLabel').
2714 Updating a non-existing mask will create a new one.
2716 - keep only those tracks that were used in provided particle list
2718 .. code-block:: python
2720 keepInROEMasks('pi+:goodTracks', 'mask', '', path=mypath)
2722 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2724 .. code-block:: python
2726 keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1', path=mypath)
2729 @param list_name name of the input ParticleList
2730 @param mask_names array of ROEMasks to be updated
2731 @param cut_string decay string with which the mask will be updated
2732 @param path modules are added to this path
2735 updateMask = register_module(
'RestOfEventUpdater')
2736 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2737 updateMask.param(
'particleList', list_name)
2738 updateMask.param(
'updateMasks', mask_names)
2739 updateMask.param(
'cutString', cut_string)
2740 updateMask.param(
'discard',
False)
2741 path.add_module(updateMask)
2744def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2746 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2747 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2748 This function should be executed only in the for_each roe path for the current ROE object.
2750 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2751 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2752 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2753 pion particle list (e.g. 'pi+:someLabel').
2755 Updating a non-existing mask will create a new one.
2757 - discard tracks that were used in provided particle list
2759 .. code-block:: python
2761 discardFromROEMasks('pi+:badTracks', 'mask', '', path=mypath)
2763 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2765 .. code-block:: python
2767 discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1', path=mypath)
2770 @param list_name name of the input ParticleList
2771 @param mask_names array of ROEMasks to be updated
2772 @param cut_string decay string with which the mask will be updated
2773 @param path modules are added to this path
2776 updateMask = register_module(
'RestOfEventUpdater')
2777 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2778 updateMask.param(
'particleList', list_name)
2779 updateMask.param(
'updateMasks', mask_names)
2780 updateMask.param(
'cutString', cut_string)
2781 updateMask.param(
'discard',
True)
2782 path.add_module(updateMask)
2785def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2787 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2788 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2789 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2790 passing it can be applied.
2792 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2793 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2795 Updating a non-existing mask will create a new one.
2797 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2799 .. code-block:: python
2801 optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550', path=mypath)
2803 @param list_name name of the input ParticleList
2804 @param mask_names array of ROEMasks to be updated
2805 @param cut_string decay string with which the mask will be updated
2806 @param path modules are added to this path
2809 updateMask = register_module(
'RestOfEventUpdater')
2810 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2811 updateMask.param(
'particleList', list_name)
2812 updateMask.param(
'updateMasks', mask_names)
2813 updateMask.param(
'cutString', cut_string)
2814 path.add_module(updateMask)
2817def updateROEUsingV0Lists(target_particle_list, mask_names, default_cleanup=True, selection_cuts=None,
2818 apply_mass_fit=False, fitter='treefit', path=None):
2820 This function creates V0 particle lists (photons, :math:`K^0_S` and :math:`\\Lambda^0`)
2821 and it uses V0 candidates to update the Rest Of Event, which is associated to the target particle list.
2822 It is possible to apply a standard or customized selection and mass fit to the V0 candidates.
2825 @param target_particle_list name of the input ParticleList
2826 @param mask_names array of ROE masks to be applied
2827 @param default_cleanup if True, predefined cuts will be applied on the V0 lists
2828 @param selection_cuts a single string of selection cuts or tuple of three strings (photon_cuts, K_S0_cuts, Lambda0_cuts),
2829 which will be applied to the V0 lists. These cuts will have a priority over the default ones.
2830 @param apply_mass_fit if True, a mass fit will be applied to the V0 particles
2831 @param fitter string, that represent a fitter choice: "treefit" for TreeFitter and "kfit" for KFit
2832 @param path modules are added to this path
2835 roe_path = create_path()
2836 deadEndPath = create_path()
2837 signalSideParticleFilter(target_particle_list,
'', roe_path, deadEndPath)
2839 if (default_cleanup
and selection_cuts
is None):
2840 B2INFO(
"Using default cleanup in updateROEUsingV0Lists.")
2841 selection_cuts =
'abs(dM) < 0.1 '
2842 selection_cuts +=
'and daughter(0,particleID) > 0.2 and daughter(1,particleID) > 0.2 '
2843 selection_cuts +=
'and daughter(0,thetaInCDCAcceptance) and daughter(1,thetaInCDCAcceptance)'
2844 if (selection_cuts
is None or selection_cuts ==
''):
2845 B2INFO(
"No cleanup in updateROEUsingV0Lists.")
2846 selection_cuts = (
'True',
'True',
'True')
2847 if (isinstance(selection_cuts, str)):
2848 selection_cuts = (selection_cuts, selection_cuts, selection_cuts)
2850 roe_cuts =
'isInRestOfEvent > 0'
2851 fillConvertedPhotonsList(
'gamma:v0_roe -> e+ e-', f
'{selection_cuts[0]} and {roe_cuts}',
2853 fillParticleList(
'K_S0:v0_roe -> pi+ pi-', f
'{selection_cuts[1]} and {roe_cuts}',
2855 fillParticleList(
'Lambda0:v0_roe -> p+ pi-', f
'{selection_cuts[2]} and {roe_cuts}',
2857 fitter = fitter.lower()
2858 if (fitter !=
'treefit' and fitter !=
'kfit'):
2859 B2WARNING(
'Argument "fitter" in updateROEUsingV0Lists has only "treefit" and "kfit" options, '
2860 f
'but "{fitter}" was provided! TreeFitter will be used instead.')
2862 from vertex
import kFit, treeFit
2863 for v0
in [
'gamma:v0_roe',
'K_S0:v0_roe',
'Lambda0:v0_roe']:
2864 if (apply_mass_fit
and fitter ==
'kfit'):
2865 kFit(v0, conf_level=0.0, fit_type=
'massvertex', path=roe_path)
2866 if (apply_mass_fit
and fitter ==
'treefit'):
2867 treeFit(v0, conf_level=0.0, massConstraint=[v0.split(
':')[0]], path=roe_path)
2868 optimizeROEWithV0(v0, mask_names,
'', path=roe_path)
2869 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2872def printROEInfo(mask_names=None, full_print=False,
2873 unpackComposites=True, path=None):
2875 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2876 It prints out basic ROE object info.
2878 If mask names are provided, specific information for those masks will be printed out.
2880 It is also possible to print out all particles in a given mask if the
2881 'full_print' is set to True.
2883 @param mask_names array of ROEMask names for printing out info
2884 @param unpackComposites if true, replace composite particles by their daughters
2885 @param full_print print out particles in mask
2886 @param path modules are added to this path
2889 if mask_names
is None:
2891 printMask = register_module(
'RestOfEventPrinter')
2892 printMask.set_name(
'RestOfEventPrinter')
2893 printMask.param(
'maskNames', mask_names)
2894 printMask.param(
'fullPrint', full_print)
2895 printMask.param(
'unpackComposites', unpackComposites)
2896 path.add_module(printMask)
2899def buildContinuumSuppression(list_name, roe_mask, ipprofile_fit=False, path=None):
2901 Creates for each Particle in the given ParticleList a ContinuumSuppression
2902 dataobject and makes basf2 relation between them.
2904 :param list_name: name of the input ParticleList
2905 :param roe_mask: name of the ROE mask
2906 :param ipprofile_fit: turn on vertex fit of input tracks with IP profile constraint
2907 :param path: modules are added to this path
2910 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2911 qqBuilder.set_name(
'QQBuilder_' + list_name)
2912 qqBuilder.param(
'particleList', list_name)
2913 qqBuilder.param(
'ROEMask', roe_mask)
2914 qqBuilder.param(
'performIPProfileFit', ipprofile_fit)
2915 path.add_module(qqBuilder)
2920 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2921 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2923 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2924 @param path modules are added to this path
2927 mod = register_module(
'RemoveParticlesNotInLists')
2928 mod.param(
'particleLists', lists_to_keep)
2929 path.add_module(mod)
2932def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2934 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2936 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2937 @param bsig_list_name Name of the Bsig ParticleList
2938 @param btag_list_name Name of the Bsig ParticleList
2939 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2942 btag = register_module(
'InclusiveBtagReconstruction')
2943 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2944 btag.param(
'upsilonListName', upsilon_list_name)
2945 btag.param(
'bsigListName', bsig_list_name)
2946 btag.param(
'btagListName', btag_list_name)
2947 btag.param(
'inputListsNames', input_lists_names)
2948 path.add_module(btag)
2951def selectDaughters(particle_list_name, decay_string, path):
2953 Redefine the Daughters of a particle: select from decayString
2955 @param particle_list_name input particle list
2956 @param decay_string for selecting the Daughters to be preserved
2959 seld = register_module(
'SelectDaughters')
2960 seld.set_name(
'SelectDaughters_' + particle_list_name)
2961 seld.param(
'listName', particle_list_name)
2962 seld.param(
'decayString', decay_string)
2963 path.add_module(seld)
2966def markDuplicate(particleList, prioritiseV0, path):
2968 Call DuplicateVertexMarker to find duplicate particles in a list and
2969 flag the ones that should be kept
2971 @param particleList input particle list
2972 @param prioritiseV0 if true, give V0s a higher priority
2975 markdup = register_module(
'DuplicateVertexMarker')
2976 markdup.param(
'particleList', particleList)
2977 markdup.param(
'prioritiseV0', prioritiseV0)
2978 path.add_module(markdup)
2981PI0ETAVETO_COUNTER = 0
2984def oldwritePi0EtaVeto(
2987 workingDirectory='.',
2988 pi0vetoname='Pi0_Prob',
2989 etavetoname='Eta_Prob',
2995 Give pi0/eta probability for hard photon.
2997 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.
2999 The current default weight files are optimised using MC9.
3000 The input variables are as below. Aliases are set to some variables during training.
3002 * M: pi0/eta candidates Invariant mass
3003 * lowE: soft photon energy in lab frame
3004 * cTheta: soft photon ECL cluster's polar angle
3005 * Zmva: soft photon output of MVA using Zernike moments of the cluster
3006 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3008 If you don't have weight files in your workingDirectory,
3009 these files are downloaded from database to your workingDirectory automatically.
3010 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
3011 about how to use this function.
3014 Please don't use following ParticleList names elsewhere:
3016 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
3017 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
3019 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
3021 @param particleList The input ParticleList
3022 @param decayString specify Particle to be added to the ParticleList
3023 @param workingDirectory The weight file directory
3024 @param downloadFlag whether download default weight files or not
3025 @param pi0vetoname extraInfo name of pi0 probability
3026 @param etavetoname extraInfo name of eta probability
3027 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
3028 @param path modules are added to this path
3033 B2ERROR(
"The old pi0 / eta veto is not suitable for Belle analyses.")
3038 global PI0ETAVETO_COUNTER
3040 if PI0ETAVETO_COUNTER == 0:
3041 from variables
import variables
3042 variables.addAlias(
'lowE',
'daughter(1,E)')
3043 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
3044 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
3045 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
3046 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
3047 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
3049 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
3051 roe_path = create_path()
3053 deadEndPath = create_path()
3055 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3057 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
3059 pi0softname =
'gamma:PI0SOFT'
3060 etasoftname =
'gamma:ETASOFT'
3061 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
3062 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
3066 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
3068 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
3071 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
3073 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
3075 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
3076 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
3078 if not os.path.isdir(workingDirectory):
3079 os.mkdir(workingDirectory)
3080 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
3082 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
3084 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
3085 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
3087 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
3089 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
3090 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
3092 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
3093 identifier=workingDirectory +
'/pi0veto.root')
3094 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
3095 identifier=workingDirectory +
'/etaveto.root')
3097 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
3098 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
3100 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
3101 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
3103 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3109 mode='standardMC16rd',
3113 hardParticle='gamma',
3114 pi0PayloadNameOverride=None,
3115 pi0SoftPhotonCutOverride=None,
3116 etaPayloadNameOverride=None,
3117 etaSoftPhotonCutOverride=None,
3118 requireSoftPhotonIsInROE=False,
3123 Give pi0/eta probability for hard photon.
3125 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.
3126 For MC15rd/MC16rd weight files, the BtoXGamma skim is applied during the MVA training.
3128 The current default weight files are for MC16rd. The weight files for MC15rd/MC12 are still available.
3130 The input variables of the mva training for pi0 veto using MC16rd are:
3132 * M: Invariant mass of pi0 candidates
3133 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons in the pi0 rest frame
3134 and momentum of pi0 in lab frame
3135 * daughter(1,E): soft photon energy in lab frame
3136 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3137 * daughter(1,clusterLAT): soft photon lateral energy distribution
3138 * daughter(1,beamBackgroundSuppression): soft photon beam background suppression MVA output
3139 * daughter(1,fakePhotonSuppression): soft photon fake photon suppression MVA output
3141 The input variables of the mva training for eta veto using MC16rd are:
3143 * M: Invariant mass of eta candidates
3144 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons in the eta rest frame
3145 and momentum of eta in lab frame
3146 * daughter(1,E): soft photon energy in lab frame
3147 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3148 * daughter(1,clusterLAT): soft photon lateral energy distribution
3149 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
3150 * daughter(1,clusterE1E9): soft photon ratio between energies of central crystal and inner 3x3 crystals
3151 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
3152 * daughter(1,clusterSecondMoment): soft photon second moment
3153 * daughter(1,clusterAbsZernikeMoment40): soft photon Zernike moment 40
3154 * daughter(1,clusterAbsZernikeMoment51): soft photon Zernike moment 51
3155 * daughter(1,beamBackgroundSuppression): soft photon beam background suppression MVA output
3156 * daughter(1,fakePhotonSuppression): soft photon fake photon suppression MVA output
3159 The input variables of the mva training for pi0 veto using MC15rd are:
3161 * M: Invariant mass of pi0 candidates
3162 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons in the pi0 rest frame
3163 and momentum of pi0 in lab frame
3164 * daughter(1,E): soft photon energy in lab frame
3165 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3166 * daughter(1,clusterLAT): soft photon lateral energy distribution
3168 The input variables of the mva training for eta veto using MC15rd are:
3170 * M: Invariant mass of eta candidates
3171 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons in the eta rest frame
3172 and momentum of eta in lab frame
3173 * daughter(1,E): soft photon energy in lab frame
3174 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3175 * daughter(1,clusterLAT): soft photon lateral energy distribution
3176 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
3177 * daughter(1,clusterE1E9): soft photon ratio between energies of central crystal and inner 3x3 crystals
3178 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
3179 * daughter(1,clusterSecondMoment): soft photon second moment
3180 * daughter(1,clusterAbsZernikeMoment40): soft photon Zernike moment 40
3181 * daughter(1,clusterAbsZernikeMoment51): soft photon Zernike moment 51
3183 The input variables of the mva training using MC12 are:
3185 * M: Invariant mass of pi0/eta candidates
3186 * daughter(1,E): soft photon energy in lab frame
3187 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3188 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3189 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
3190 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
3191 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
3192 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons in the pi0/eta rest frame
3193 and momentum of pi0/eta in lab frame
3195 The following strings are available for mode:
3197 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
3198 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
3199 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
3200 * both: tight energy cut and clusterNHits cut are applied to soft photon
3201 * standardMC15rd: loose energy cut is applied to soft photon and the weight files are trained using MC15rd
3202 * tightMC15rd: tight energy cut is applied to soft photon and the weight files are trained using MC15rd
3203 * standardMC16rd: loose energy cut is applied to soft photon and the weight files are trained using MC16rd
3204 * tightMC16rd: tight energy cut is applied to soft photon and the weight files are trained using MC16rd
3206 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
3207 `pi0Prob`/`etaProb`. Otherwise, it is available as '{Pi0, Eta}ProbOrigin', '{Pi0, Eta}ProbTightEnergyThreshold', '{Pi0,
3208 Eta}ProbLargeClusterSize', '{Pi0, Eta}ProbTightEnergyThresholdAndLargeClusterSize', '{Pi0, Eta}ProbOriginMC15rd', or
3209 '{Pi0, Eta}ProbTightEnergyThresholdMC15rd' for the six modes described above, with the chosen suffix appended. If one would
3210 like to call this veto twice in one script, add suffix in the second time!
3211 The second highest probability of the pi0/eta veto also is stored as an extraInfo, with a prefix of 'second' to the previous
3212 ones, e.g. secondPi0ProbOrigin{suffix}. This can be used to do validation/systematics study.
3215 Please don't use following ParticleList names elsewhere:
3217 ``gamma:HardPhoton``,
3218 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
3219 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
3220 ``pi0:EtaVeto + ListName``,
3221 ``eta:EtaVeto + ListName``
3223 @param particleList the input ParticleList
3224 @param decayString specify Particle to be added to the ParticleList
3225 @param mode choose one mode out of 'standardMC16rd', 'tightMC16rd', 'standardMC15rd', 'tightMC15rd',
3226 'standard', 'tight', 'cluster' and 'both'
3227 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
3228 @param path modules are added to this path
3229 @param suffix optional suffix to be appended to the usual extraInfo name
3230 @param hardParticle particle name which is used to calculate the pi0/eta probability (default is gamma)
3231 @param pi0PayloadNameOverride specify the payload name of pi0 veto only if one wants to use non-default one. (default is None)
3232 @param pi0SoftPhotonCutOverride specify the soft photon selection criteria of pi0 veto only if one wants to use non-default one.
3234 @param etaPayloadNameOverride specify the payload name of eta veto only if one wants to use non-default one. (default is None)
3235 @param etaSoftPhotonCutOverride specify the soft photon selection criteria of eta veto only if one wants to use non-default one.
3237 @param requireSoftPhotonIsInROE specify if the soft photons used to build pi0 and eta candidates have to be in the current ROE
3238 or not. Default is False, i.e. all soft photons in the event are used.
3239 @param pi0Selection Selection for the pi0 reconstruction. Default is "".
3240 @param etaSelection Selection for the eta reconstruction. Default is "".
3245 B2ERROR(
"The pi0 / eta veto is not suitable for Belle analyses.")
3247 if (requireSoftPhotonIsInROE):
3248 B2WARNING(
"Requiring the soft photon to being in the ROE was not done for the MVA training. "
3249 "Please check the results carefully.")
3252 if (mode ==
'standardMC15rd' or mode ==
'tightMC15rd'):
3253 if (pi0Selection !=
'[0.03 < M < 0.23]' or etaSelection !=
'[0.25 < M < 0.75]'):
3256 if (pi0Selection !=
'' or etaSelection !=
''):
3260 "Selection criteria for the pi0 or the eta during reconstructDecay differ from those used during the MVA training. "
3261 "You may get NAN value. Please check the results carefully.")
3263 renameSuffix =
False
3265 for module
in path.modules():
3266 if module.type() ==
"SubEvent" and not renameSuffix:
3267 for subpath
in [p.values
for p
in module.available_params()
if p.name ==
"path"]:
3270 for submodule
in subpath.modules():
3271 if f
'{hardParticle}:HardPhoton{suffix}' in submodule.name():
3273 B2WARNING(
"Same extension already used in writePi0EtaVeto, append '_0'")
3277 roe_path = create_path()
3278 deadEndPath = create_path()
3279 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3280 fillSignalSideParticleList(f
'{hardParticle}:HardPhoton{suffix}', decayString, path=roe_path)
3282 dictListName = {
'standard':
'Origin',
3283 'tight':
'TightEnergyThreshold',
3284 'cluster':
'LargeClusterSize',
3285 'both':
'TightEnrgyThresholdAndLargeClusterSize',
3286 'standardMC15rd':
'OriginMC15rd',
3287 'tightMC15rd':
'TightEnergyThresholdMC15rd',
3288 'standardMC16rd':
'OriginMC16rd',
3289 'tightMC16rd':
'TightEnergyThresholdMC16rd'}
3291 dictPi0EnergyCut = {
3292 'standard':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3293 'tight':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3294 'cluster':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3295 'both':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3296 'standardMC15rd':
'[[clusterReg==1 and E>0.0225] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3297 'tightMC15rd':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3298 'standardMC16rd':
'[[clusterReg==1 and E>0.0225] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3299 'tightMC16rd':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3301 dictEtaEnergyCut = {
3302 'standard':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3303 'tight':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3304 'cluster':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3305 'both':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3306 'standardMC15rd':
'[[clusterReg==1 and E>0.0225] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3307 'tightMC15rd':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3308 'standardMC16rd':
'[[clusterReg==1 and E>0.0225] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3309 'tightMC16rd':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3311 dictNHitsTimingCut = {
'standard':
'clusterNHits >= 0 and abs(clusterTiming)<clusterErrorTiming',
3312 'tight':
'clusterNHits >= 0 and abs(clusterTiming)<clusterErrorTiming',
3313 'cluster':
'clusterNHits >= 2 and abs(clusterTiming)<clusterErrorTiming',
3314 'both':
'clusterNHits >= 2 and abs(clusterTiming)<clusterErrorTiming',
3315 'standardMC15rd':
'clusterNHits > 1.5 and abs(clusterTiming) < 200',
3316 'tightMC15rd':
'clusterNHits > 1.5 and abs(clusterTiming) < 200',
3317 'standardMC16rd':
'clusterNHits > 1.5 and abs(clusterTiming) < 200',
3318 'tightMC16rd':
'clusterNHits > 1.5 and abs(clusterTiming) < 200'}
3320 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
3321 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
3322 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
3323 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize',
3324 'standardMC15rd':
'Pi0VetoIdentifierStandardMC15rd',
3325 'tightMC15rd':
'Pi0VetoIdentifierWithHigherEnergyThresholdMC15rd',
3326 'standardMC16rd':
'Pi0VetoIdentifierStandardMC16rd',
3327 'tightMC16rd':
'Pi0VetoIdentifierWithHigherEnergyThresholdMC16rd'}
3329 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
3330 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
3331 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
3332 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize',
3333 'standardMC15rd':
'EtaVetoIdentifierStandardMC15rd',
3334 'tightMC15rd':
'EtaVetoIdentifierWithHigherEnergyThresholdMC15rd',
3335 'standardMC16rd':
'EtaVetoIdentifierStandardMC16rd',
3336 'tightMC16rd':
'EtaVetoIdentifierWithHigherEnergyThresholdMC16rd'}
3338 dictPi0ExtraInfoName = {
'standard':
'Pi0ProbOrigin',
3339 'tight':
'Pi0ProbTightEnergyThreshold',
3340 'cluster':
'Pi0ProbLargeClusterSize',
3341 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize',
3342 'standardMC15rd':
'Pi0ProbOriginMC15rd',
3343 'tightMC15rd':
'Pi0ProbTightEnergyThresholdMC15rd',
3344 'standardMC16rd':
'Pi0ProbOriginMC16rd',
3345 'tightMC16rd':
'Pi0ProbTightEnergyThresholdMC16rd'}
3347 dictEtaExtraInfoName = {
'standard':
'EtaProbOrigin',
3348 'tight':
'EtaProbTightEnergyThreshold',
3349 'cluster':
'EtaProbLargeClusterSize',
3350 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize',
3351 'standardMC15rd':
'EtaProbOriginMC15rd',
3352 'tightMC15rd':
'EtaProbTightEnergyThresholdMC15rd',
3353 'standardMC16rd':
'EtaProbOriginMC16rd',
3354 'tightMC16rd':
'EtaProbTightEnergyThresholdMC16rd'}
3356 ListName = dictListName[mode]
3357 Pi0EnergyCut = dictPi0EnergyCut[mode]
3358 EtaEnergyCut = dictEtaEnergyCut[mode]
3359 NHitsTimingCut = dictNHitsTimingCut[mode]
3360 Pi0PayloadName = dictPi0PayloadName[mode]
3361 EtaPayloadName = dictEtaPayloadName[mode]
3362 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
3363 EtaExtraInfoName = dictEtaExtraInfoName[mode]
3366 if pi0PayloadNameOverride
is not None:
3367 Pi0PayloadName = pi0PayloadNameOverride
3368 B2WARNING(
"You're using personal weight files, be careful. ")
3369 if pi0SoftPhotonCutOverride
is None:
3370 Pi0SoftPhotonCut = Pi0EnergyCut +
' and ' + NHitsTimingCut
3372 Pi0SoftPhotonCut = pi0SoftPhotonCutOverride
3373 B2WARNING(
"You're applying personal cuts on the soft photon candidates, be careful. ")
3375 if requireSoftPhotonIsInROE:
3376 Pi0SoftPhotonCut +=
' and isInRestOfEvent==1'
3379 pi0soft = f
'gamma:Pi0Soft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3381 fillParticleList(pi0soft, Pi0SoftPhotonCut, path=roe_path)
3383 if 'MC16rd' in mode:
3384 getBeamBackgroundProbability(pi0soft, weight=
"MC16rd", path=roe_path)
3385 getFakePhotonProbability(pi0soft, weight=
"MC16rd", path=roe_path)
3387 reconstructDecay(
'pi0:Pi0Veto' + ListName + suffix + f
' -> {hardParticle}:HardPhoton{suffix} ' + pi0soft, pi0Selection,
3388 allowChargeViolation=
True, path=roe_path)
3390 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName + suffix],
3391 extraInfoName=Pi0ExtraInfoName, identifier=Pi0PayloadName)
3394 'pi0:Pi0Veto' + ListName + suffix,
3395 'extraInfo(' + Pi0ExtraInfoName +
')',
3397 outputVariable=
"Pi0VetoRank",
3399 cutAndCopyList(outputListName=
'pi0:Pi0VetoFirst' + ListName + suffix,
3400 inputListName=
'pi0:Pi0Veto' + ListName + suffix,
3401 cut=
'extraInfo(Pi0VetoRank)==1',
3403 variableToSignalSideExtraInfo(
'pi0:Pi0VetoFirst' + ListName + suffix,
3404 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoName + suffix}, path=roe_path)
3406 cutAndCopyList(outputListName=
'pi0:Pi0VetoSecond' + ListName + suffix,
3407 inputListName=
'pi0:Pi0Veto' + ListName + suffix,
3408 cut=
'extraInfo(Pi0VetoRank)==2',
3410 variableToSignalSideExtraInfo(
'pi0:Pi0VetoSecond' + ListName + suffix,
3411 {
'extraInfo(' + Pi0ExtraInfoName +
')':
'second' + Pi0ExtraInfoName + suffix}, path=roe_path)
3414 if etaPayloadNameOverride
is not None:
3415 EtaPayloadName = etaPayloadNameOverride
3416 B2WARNING(
"You're using personal weight files, be careful. ")
3417 if etaSoftPhotonCutOverride
is None:
3418 EtaSoftPhotonCut = EtaEnergyCut +
' and ' + NHitsTimingCut
3420 EtaSoftPhotonCut = etaSoftPhotonCutOverride
3421 B2WARNING(
"You're applying personal cuts on the soft photon candidates, be careful. ")
3423 if requireSoftPhotonIsInROE:
3424 EtaSoftPhotonCut +=
' and isInRestOfEvent==1'
3426 etasoft = f
'gamma:EtaSoft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3427 fillParticleList(etasoft, EtaSoftPhotonCut, path=roe_path)
3429 if 'MC16rd' in mode:
3430 getBeamBackgroundProbability(etasoft, weight=
"MC16rd", path=roe_path)
3431 getFakePhotonProbability(etasoft, weight=
"MC16rd", path=roe_path)
3432 reconstructDecay(
'eta:EtaVeto' + ListName + suffix + f
' -> {hardParticle}:HardPhoton{suffix} ' + etasoft, etaSelection,
3433 allowChargeViolation=
True, path=roe_path)
3434 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName + suffix],
3435 extraInfoName=EtaExtraInfoName, identifier=EtaPayloadName)
3437 'eta:EtaVeto' + ListName + suffix,
3438 'extraInfo(' + EtaExtraInfoName +
')',
3440 outputVariable=
"EtaVetoRank",
3442 cutAndCopyList(outputListName=
'eta:EtaVetoFirst' + ListName + suffix,
3443 inputListName=
'eta:EtaVeto' + ListName + suffix,
3444 cut=
'extraInfo(EtaVetoRank)==1',
3446 variableToSignalSideExtraInfo(
'eta:EtaVetoFirst' + ListName + suffix,
3447 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoName + suffix}, path=roe_path)
3448 cutAndCopyList(outputListName=
'eta:EtaVetoSecond' + ListName + suffix,
3449 inputListName=
'eta:EtaVeto' + ListName + suffix,
3450 cut=
'extraInfo(EtaVetoRank)==2',
3452 variableToSignalSideExtraInfo(
'eta:EtaVetoSecond' + ListName + suffix,
3453 {
'extraInfo(' + EtaExtraInfoName +
')':
'second' + EtaExtraInfoName + suffix}, path=roe_path)
3455 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3458def lowEnergyPi0Identification(pi0List, gammaList, payloadNameSuffix,
3461 Calculate low-energy pi0 identification.
3462 The result is stored as ExtraInfo ``lowEnergyPi0Identification`` for
3466 pi0List (str): Pi0 list.
3468 gammaList (str): Gamma list. First, an energy cut E > 0.2 is applied to the photons from this list.
3469 Then, all possible combinations with a pi0 daughter photon are formed except the one
3470 corresponding to the reconstructed pi0.
3471 The maximum low-energy pi0 veto value is calculated for such photon pairs
3472 and used as one of the input variables for the identification classifier.
3474 payloadNameSuffix (str): Payload name suffix. The weight payloads are stored in the analysis global
3475 tag and have the following names:\n
3476 * ``'LowEnergyPi0Veto' + payloadNameSuffix``
3477 * ``'LowEnergyPi0Identification' + payloadNameSuffix``\n
3478 The possible suffixes are:\n
3479 * ``'Belle1'`` for Belle data.
3480 * ``'Belle2Release5'`` for Belle II release 5 data (MC14, proc12, buckets 16 - 25).
3481 * ``'Belle2Release6'`` for Belle II release 6 data (MC15, proc13, buckets 26 - 36).
3483 path (basf2.Path): Module path.
3487 gammaListVeto = f
'{gammaList}_pi0veto'
3488 cutAndCopyList(gammaListVeto, gammaList,
'E > 0.2', path=path)
3490 payload_name =
'LowEnergyPi0Veto' + payloadNameSuffix
3491 path.add_module(
'LowEnergyPi0VetoExpert', identifier=payload_name,
3492 VetoPi0Daughters=
True, GammaListName=gammaListVeto,
3494 payload_name =
'LowEnergyPi0Identification' + payloadNameSuffix
3495 path.add_module(
'LowEnergyPi0IdentificationExpert',
3496 identifier=payload_name, Pi0ListName=pi0List,
3500def getNeutralHadronGeomMatches(
3504 efficiencyCorrectionKl=0.83,
3505 efficiencyCorrectionNeutrons=1.0,
3508 For an ECL-based list, assign the mcdistanceKL and mcdistanceNeutron variables that correspond
3509 to the distance to the closest MC KL and neutron, respectively.
3510 @param particleLists the input ParticleLists, must be ECL-based lists (e.g. photons)
3511 @param addKL (default True) add distance to MC KL
3512 @param addNeutrons (default False) add distance to MC neutrons
3513 @param efficiencyCorrectionKl (default 0.83) apply overall efficiency correction
3514 @param efficiencyCorrectionNeutrons (default 1.0) apply overall efficiency correction
3515 @param path modules are added to this path
3517 from ROOT
import Belle2
3522 "NeutralHadronMatcher",
3523 particleLists=particleLists,
3524 mcPDGcode=Const.Klong.getPDGCode(),
3525 efficiencyCorrection=efficiencyCorrectionKl)
3528 "NeutralHadronMatcher",
3529 particleLists=particleLists,
3530 mcPDGcode=Const.neutron.getPDGCode(),
3531 efficiencyCorrection=efficiencyCorrectionNeutrons)
3534def getBeamBackgroundProbability(particleList, weight, path=None):
3536 Assign a probability to each ECL cluster as being signal like (1) compared to beam background like (0)
3537 @param particleList the input ParticleList, must be a photon list
3538 @param weight type of weight file to use
3539 @param path modules are added to this path
3544 B2WARNING(
"weight type must be 'Belle' for b2bii.")
3546 path.add_module(
'MVAExpert',
3547 listNames=particleList,
3548 extraInfoName=
'beamBackgroundSuppression',
3549 identifier=f
'BeamBackgroundMVA_{weight}')
3552def getFakePhotonProbability(particleList, weight, path=None):
3554 Assign a probability to each ECL cluster as being signal like (1) compared to fake photon like (0)
3555 @param particleList the input ParticleList, must be a photon list
3556 @param weight type of weight file to use
3557 @param path modules are added to this path
3562 B2WARNING(
"weight type must be 'Belle' for b2bii.")
3564 path.add_module(
'MVAExpert',
3565 listNames=particleList,
3566 extraInfoName=
'fakePhotonSuppression',
3567 identifier=f
'FakePhotonMVA_{weight}')
3570def buildEventKinematics(inputListNames=None, default_cleanup=True, custom_cuts=None,
3571 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
3573 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3574 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
3575 (all track and all hits in ECL without associated track).
3577 The visible energy missing values are
3578 stored in a EventKinematics dataobject.
3580 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3581 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
3582 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
3583 according to the PID likelihood and the option inputListNames will be ignored.
3584 @param chargedPIDPriors The prior PID fractions, that are used to regulate
3585 amount of certain charged particle species, should be a list of
3586 six floats if not None. The order of particle types is
3587 the following: [e-, mu-, pi-, K-, p+, d+]
3588 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
3589 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3590 which would result in a standard predefined selection cuts
3591 @param path modules are added to this path
3594 if inputListNames
is None:
3596 trackCuts =
'pt > 0.1'
3597 trackCuts +=
' and thetaInCDCAcceptance'
3598 trackCuts +=
' and abs(dz) < 3'
3599 trackCuts +=
' and dr < 0.5'
3601 gammaCuts =
'E > 0.05'
3602 gammaCuts +=
' and thetaInCDCAcceptance'
3604 gammaCuts +=
' and abs(clusterTiming) < 200'
3605 if (custom_cuts
is not None):
3606 trackCuts, gammaCuts = custom_cuts
3608 if fillWithMostLikely:
3609 from stdCharged
import stdMostLikely
3610 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
3611 inputListNames = [f
'{ptype}:mostlikely_evtkin' for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
3613 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3615 fillParticleList(
'gamma:evtkin',
'', path=path)
3616 inputListNames += [
'gamma:evtkin']
3618 B2INFO(
"Using default cleanup in EventKinematics module.")
3619 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
3620 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
3621 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3623 B2INFO(
"No cleanup in EventKinematics module.")
3624 if not inputListNames:
3625 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
3626 fillParticleList(
'pi+:evtkin',
'', path=path)
3628 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3630 fillParticleList(
'gamma:evtkin',
'', path=path)
3631 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
3633 if (custom_cuts
is not None):
3634 B2INFO(
"Using default cleanup in EventKinematics module.")
3635 applyCuts(
'pi+:evtkin', trackCuts, path=path)
3636 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3638 B2INFO(
"No cleanup in EventKinematics module.")
3640 particleLists = inputListNames
3642 eventKinematicsModule = register_module(
'EventKinematics')
3643 eventKinematicsModule.set_name(
'EventKinematics_reco')
3644 eventKinematicsModule.param(
'particleLists', particleLists)
3645 path.add_module(eventKinematicsModule)
3648def buildEventKinematicsFromMC(inputListNames=None, selectionCut='', path=None):
3650 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3651 using generated particles. If no ParticleList is provided, default generated ParticleLists are used.
3653 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3654 If the list is empty, default ParticleLists are filled.
3655 @param selectionCut optional selection cuts
3656 @param path Path to append the eventKinematics module to.
3659 if inputListNames
is None:
3661 if (len(inputListNames) == 0):
3665 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
3668 fillParticleListFromMC(f
"{t}:evtkin_default_gen",
'mcPrimary > 0 and nDaughters == 0',
3669 True,
True, path=path)
3670 if (selectionCut !=
''):
3671 applyCuts(f
"{t}:evtkin_default_gen", selectionCut, path=path)
3672 inputListNames += [f
"{t}:evtkin_default_gen"]
3674 eventKinematicsModule = register_module(
'EventKinematics')
3675 eventKinematicsModule.set_name(
'EventKinematics_gen')
3676 eventKinematicsModule.param(
'particleLists', inputListNames)
3677 eventKinematicsModule.param(
'usingMC',
True)
3678 path.add_module(eventKinematicsModule)
3681def buildEventShape(inputListNames=None,
3682 default_cleanup=True,
3688 harmonicMoments=True,
3692 checkForDuplicates=False,
3695 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
3696 using the particles in the lists provided by the user. If no particle list is provided,
3697 the function will internally create a list of good tracks and a list of good photons
3698 with (optionally) minimal quality cuts.
3701 The results of the calculation are then stored into the EventShapeContainer dataobject,
3702 and are accessible using the variables of the EventShape group.
3704 The user can switch the calculation of certain quantities on or off to save computing
3705 time. By default the calculation of the high-order moments (5-8) is turned off.
3706 Switching off an option will make the corresponding variables not available.
3709 The user can provide as many particle lists as needed, using also composite particles.
3710 In these cases, it is recommended to activate the checkForDuplicates flag since it
3711 will eliminate duplicates, e.g., if the same track is provided multiple times
3712 (either with different mass hypothesis or once as an independent particle and once
3713 as daughter of a composite particle). The first occurrence will be used in the
3714 calculations so the order in which the particle lists are given as well as within
3715 the particle lists matters.
3717 @param inputListNames List of ParticleLists used to calculate the
3718 event shape variables. If the list is empty the default
3719 particleLists pi+:evtshape and gamma:evtshape are filled.
3720 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
3721 defining the internal lists. This option is ignored if the
3722 particleLists are provided by the user.
3723 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3724 which would result in a standard predefined selection cuts
3725 @param path Path to append the eventShape modules to.
3726 @param thrust Enables the calculation of thrust-related quantities (CLEO
3727 cones, Harmonic moments, jets).
3728 @param collisionAxis Enables the calculation of the quantities related to the
3730 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
3731 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
3732 to both the thrust axis and, if collisionAxis = True, the collision axis.
3733 @param allMoments If True, calculates also the FW and harmonic moments from order
3734 5 to 8 instead of the low-order ones only.
3735 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
3736 axis and, if collisionAxis = True, the collision axis.
3737 @param jets Enables the calculation of the hemisphere momenta and masses.
3738 Requires thrust = True.
3739 @param sphericity Enables the calculation of the sphericity-related quantities.
3740 @param checkForDuplicates Perform a check for duplicate particles before adding them. Regardless of the value of this option,
3741 it is recommended to consider sanitizing the lists you are passing to the function since this will
3742 speed up the processing.
3746 if inputListNames
is None:
3748 trackCuts =
'pt > 0.1'
3749 trackCuts +=
' and thetaInCDCAcceptance'
3750 trackCuts +=
' and abs(dz) < 3.0'
3751 trackCuts +=
' and dr < 0.5'
3753 gammaCuts =
'E > 0.05'
3754 gammaCuts +=
' and thetaInCDCAcceptance'
3756 gammaCuts +=
' and abs(clusterTiming) < 200'
3757 if (custom_cuts
is not None):
3758 trackCuts, gammaCuts = custom_cuts
3760 if not inputListNames:
3761 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
3762 fillParticleList(
'pi+:evtshape',
'', path=path)
3764 copyList(
'gamma:evtshape',
'gamma:mdst', path=path)
3770 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
3773 if (custom_cuts
is not None):
3774 B2INFO(
"Applying standard cuts")
3775 applyCuts(
'pi+:evtshape', trackCuts, path=path)
3777 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
3779 B2WARNING(
"Creating the default lists with no cleanup.")
3781 particleLists = inputListNames
3783 eventShapeModule = register_module(
'EventShapeCalculator')
3784 eventShapeModule.set_name(
'EventShape')
3785 eventShapeModule.param(
'particleListNames', particleLists)
3786 eventShapeModule.param(
'enableAllMoments', allMoments)
3787 eventShapeModule.param(
'enableCleoCones', cleoCones)
3788 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
3789 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
3790 eventShapeModule.param(
'enableJets', jets)
3791 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
3792 eventShapeModule.param(
'enableSphericity', sphericity)
3793 eventShapeModule.param(
'enableThrust', thrust)
3794 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
3796 path.add_module(eventShapeModule)
3799def labelTauPairMC(printDecayInfo=False, path=None, TauolaBelle=False, mapping_minus=None, mapping_plus=None):
3801 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
3802 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
3804 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
3805 @param path: module is added to this path
3806 @param TauolaBelle: if False, TauDecayMode is set. If True, TauDecayMarker is set.
3807 @param mapping_minus: if None, the map is the default one, else the path for the map is given by the user for tau-
3808 @param mapping_plus: if None, the map is the default one, else the path for the map is given by the user for tau+
3811 from basf2
import find_file
3817 m_printmode =
'default'
3819 if mapping_minus
is None:
3820 mp_file_minus = find_file(
'data/analysis/modules/TauDecayMode/map_tauminus.txt')
3822 mp_file_minus = mapping_minus
3824 if mapping_plus
is None:
3825 mp_file_plus = find_file(
'data/analysis/modules/TauDecayMode/map_tauplus.txt')
3827 mp_file_plus = mapping_plus
3829 path.add_module(
'TauDecayMode', printmode=m_printmode, file_minus=mp_file_minus, file_plus=mp_file_plus)
3832 tauDecayMarker = register_module(
'TauDecayMarker')
3833 tauDecayMarker.set_name(
'TauDecayMarker_')
3835 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
3838def tagCurlTracks(particleLists,
3848 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
3850 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
3851 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
3853 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
3856 The module loops over all particles in a given list with a transverse momentum below the pre-selection **ptCut**
3857 and assigns them to bundles based on the response of the chosen **selector** and the required minimum response set by the
3858 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
3859 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
3863 @param particleLists: list of particle lists to check for curls.
3864 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
3865 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
3866 genParticleIndex then ranked and tagged as normal.
3867 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
3868 If set to ``-1`` a cut value optimised to maximise the accuracy on a BBbar sample is used.
3869 Note 'cut' selector is binary 0/1.
3870 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
3871 It is strongly recommended to used the 'mva' selection. The 'cut' selection
3872 is based on BN1079 and is only calibrated for Belle data.
3874 @param ptCut: Pre-selection cut on transverse momentum. Only tracks below that are considered as curler candidates.
3876 @param expert_train: flag to set training mode if selector has a training mode (mva).
3877 @param expert_filename: set file name of produced training ntuple (mva).
3878 @param path: module is added to this path.
3884 if (
not isinstance(particleLists, list)):
3885 particleLists = [particleLists]
3887 curlTagger = register_module(
'CurlTagger')
3888 curlTagger.set_name(
'CurlTagger_')
3889 curlTagger.param(
'particleLists', particleLists)
3890 curlTagger.param(
'belle', belle)
3891 curlTagger.param(
'mcTruth', mcTruth)
3892 curlTagger.param(
'responseCut', responseCut)
3893 if abs(responseCut + 1) < 1e-9:
3894 curlTagger.param(
'usePayloadCut',
True)
3896 curlTagger.param(
'usePayloadCut',
False)
3898 curlTagger.param(
'selectorType', selectorType)
3899 curlTagger.param(
'ptCut', ptCut)
3900 curlTagger.param(
'train', expert_train)
3901 curlTagger.param(
'trainFilename', expert_filename)
3903 path.add_module(curlTagger)
3906def applyChargedPidMVA(particleLists, path, trainingMode, chargeIndependent=False, binaryHypoPDGCodes=(0, 0)):
3908 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
3910 The module decorates Particle objects in the input ParticleList(s) with variables
3911 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
3914 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.3.0**, **ROOT 6.20/04**).
3916 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
3918 * e (11) vs. pi (211)
3919 * mu (13) vs. pi (211)
3920 * pi (211) vs. K (321)
3921 * K (321) vs. pi (211)
3923 , or 'global' PID, namely "one-vs-others" separation. The latter exploits an MVA algorithm trained in multi-class mode,
3924 and it's the default behaviour. Currently, the multi-class training separates the following standard charged hypotheses:
3926 - e (11), mu (13), pi (211), K (321)
3929 In order to run the `ChargedPidMVA` and ensure the most up-to-date MVA training weights are applied,
3930 it is necessary to append the latest analysis global tag (GT) to the steering script.
3933 particleLists (list(str)): the input list of DecayStrings, where each selected (^) daughter should correspond to a
3934 standard charged ParticleList, e.g. ``['Lambda0:sig -> ^p+ ^pi-', 'J/psi:sig -> ^mu+ ^mu-']``.
3935 One can also directly pass a list of standard charged ParticleLists,
3936 e.g. ``['e+:my_electrons', 'pi+:my_pions']``.
3937 Note that charge-conjugated ParticleLists will automatically be included.
3938 path (basf2.Path): the module is added to this path.
3939 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
3940 Needed to pick up the correct payload from the DB. Available choices:
3942 * c_Classification=0
3944 * c_ECL_Classification=2
3945 * c_ECL_Multiclass=3
3946 * c_PSD_Classification=4
3947 * c_PSD_Multiclass=5
3948 * c_ECL_PSD_Classification=6
3949 * c_ECL_PSD_Multiclass=7
3951 chargeIndependent (bool, ``optional``): use a BDT trained on a sample of inclusively charged particles.
3952 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
3953 Required only for binary PID mode.
3958 B2ERROR(
"Charged PID via MVA is not available for Belle data.")
3960 from ROOT
import Belle2
3962 TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
3965 plSet = set(particleLists)
3969 TrainingMode.c_Classification:
3970 {
"mode":
"Classification",
"detector":
"ALL"},
3971 TrainingMode.c_Multiclass:
3972 {
"mode":
"Multiclass",
"detector":
"ALL"},
3973 TrainingMode.c_ECL_Classification:
3974 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
3975 TrainingMode.c_ECL_Multiclass:
3976 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
3977 TrainingMode.c_PSD_Classification:
3978 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
3979 TrainingMode.c_PSD_Multiclass:
3980 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
3981 TrainingMode.c_ECL_PSD_Classification:
3982 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
3983 TrainingMode.c_ECL_PSD_Multiclass:
3984 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
3987 if payloadNames.get(trainingMode)
is None:
3988 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
3989 "\nis not supported. Please choose among the following:\n",
3990 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
3992 mode = payloadNames.get(trainingMode).get(
"mode")
3993 detector = payloadNames.get(trainingMode).get(
"detector")
3995 payloadName = f
"ChargedPidMVAWeights_{mode}"
4000 Const.electron.getPDGCode():
4001 {
"pName":
"e",
"pFullName":
"electron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
4002 Const.muon.getPDGCode():
4003 {
"pName":
"mu",
"pFullName":
"muon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
4004 Const.pion.getPDGCode():
4005 {
"pName":
"pi",
"pFullName":
"pion",
"pNameBkg":
"K",
"pdgIdBkg": Const.kaon.getPDGCode()},
4006 Const.kaon.getPDGCode():
4007 {
"pName":
"K",
"pFullName":
"kaon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
4008 Const.proton.getPDGCode():
4009 {
"pName":
"p",
"pFullName":
"proton",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
4010 Const.deuteron.getPDGCode():
4011 {
"pName":
"d",
"pFullName":
"deuteron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
4014 if binaryHypoPDGCodes == (0, 0):
4017 chargedpid = register_module(
"ChargedPidMVAMulticlass")
4018 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
4025 binaryOpts = [(pdgIdSig, info[
"pdgIdBkg"])
for pdgIdSig, info
in stdChargedMap.items()]
4027 if binaryHypoPDGCodes
not in binaryOpts:
4028 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
4029 ". Please choose among the following pairs:\n",
4030 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
4034 if not decayDescriptor.init(name):
4035 raise ValueError(f
"Invalid particle list {name} in applyChargedPidMVA!")
4036 msg = f
"Input ParticleList: {name}"
4037 pdgs = [abs(decayDescriptor.getMother().getPDGCode())]
4038 daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
4039 if len(daughter_pdgs) > 0:
4040 pdgs = daughter_pdgs
4041 for idaughter, pdg
in enumerate(pdgs):
4042 if abs(pdg)
not in binaryHypoPDGCodes:
4044 msg = f
"Selected daughter {idaughter} in ParticleList: {name}"
4046 f
"{msg} (PDG={pdg}) is neither signal ({binaryHypoPDGCodes[0]}) nor background ({binaryHypoPDGCodes[1]}).")
4048 chargedpid = register_module(
"ChargedPidMVA")
4049 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
4050 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
4051 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
4053 chargedpid.param(
"particleLists", list(plSet))
4054 chargedpid.param(
"payloadName", payloadName)
4055 chargedpid.param(
"chargeIndependent", chargeIndependent)
4058 if detector ==
"ECL":
4059 chargedpid.param(
"useECLOnlyTraining",
True)
4061 path.add_module(chargedpid)
4064def calculateTrackIsolation(
4068 reference_list_name=None,
4069 vars_for_nearest_part=[],
4070 highest_prob_mass_for_ext=True,
4071 exclude_pid_det_weights=False):
4073 Given an input decay string, compute variables that quantify track helix-based isolation of the charged
4074 stable particles in the input decay chain.
4077 An "isolation score" can be defined using the distance
4078 of each particle to its closest neighbour, defined as the segment connecting the two
4079 extrapolated track helices intersection points on a given cylindrical surface.
4080 The distance variables defined in the `VariableManager` is named `minET2ETDist`,
4081 the isolation scores are named `minET2ETIsoScore`, `minET2ETIsoScoreAsWeightedAvg`.
4083 The definition of distance and the number of distances that are calculated per sub-detector is based on
4084 the following recipe:
4086 * **CDC**: as the segmentation is very coarse along :math:`z`,
4087 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
4088 A total of 9 distances are calculated: the cylindrical surfaces are defined at radiuses
4089 that correspond to the positions of the 9 CDC wire superlayers: :math:`R_{i}^{\\mathrm{CDC}}~(i \\in \\{0,...,8\\})`.
4091 * **TOP**: as there is no segmentation along :math:`z`,
4092 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
4093 Only one distance at the TOP entry radius :math:`R_{0}^{\\mathrm{TOP}}` is calculated.
4095 * **ARICH**: as there is no segmentation along :math:`z`,
4096 the distance is defined as the distance on the :math:`(\\rho=R, \\phi)` plane at fixed :math:`z=Z`.
4097 Only one distance at the ARICH photon detector entry coordinate :math:`Z_{0}^{\\mathrm{ARICH}}` is calculated.
4099 * **ECL**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
4100 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
4101 Two distances are calculated: one at the ECL entry surface :math:`R_{0}^{\\mathrm{ECL}}` (barrel),
4102 :math:`Z_{0}^{\\mathrm{ECL}}` (endcaps), and one at :math:`R_{1}^{\\mathrm{ECL}}` (barrel),
4103 :math:`Z_{1}^{\\mathrm{ECL}}` (endcaps), corresponding roughly to the mid-point
4104 of the longitudinal size of the crystals.
4106 * **KLM**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
4107 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
4108 Only one distance at the KLM first strip entry surface :math:`R_{0}^{\\mathrm{KLM}}` (barrel),
4109 :math:`Z_{0}^{\\mathrm{KLM}}` (endcaps) is calculated.
4112 decay_string (str): name of the input decay string with selected charged stable daughters,
4113 for example: ``Lambda0:merged -> ^p+ ^pi-``.
4114 Alternatively, it can be a particle list for charged stable particles
4115 as defined in ``Const::chargedStableSet``, for example: ``mu+:all``.
4116 The charge-conjugate particle list will be also processed automatically.
4117 path (basf2.Path): path to which module(s) will be added.
4118 *detectors: detectors for which track isolation variables will be calculated.
4119 Choose among: ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
4120 reference_list_name (Optional[str]): name of the input charged stable particle list for the reference tracks.
4121 By default, the ``:all`` ParticleList of the same type
4122 of the selected particle in ``decay_string`` is used.
4123 The charge-conjugate particle list will be also processed automatically.
4124 vars_for_nearest_part (Optional[list(str)]): a list of variables to calculate for the nearest particle in the reference
4125 list at each detector surface. It uses the metavariable `minET2ETDistVar`.
4126 If unset, only the distances to the nearest neighbour
4127 per detector are calculated.
4128 highest_prob_mass_for_hex (Optional[bool]): if this option is set to True (default), the helix extrapolation
4129 for the particles will use the track fit result for the most
4130 probable mass hypothesis, namely, the one that gives the highest
4131 chi2Prob of the fit. Otherwise, it uses the mass hypothesis that
4132 corresponds to the particle lists PDG.
4133 exclude_pid_det_weights (Optional[bool]): if this option is set to False (default), the isolation score
4134 calculation will take into account the weight that each detector has on the PID
4135 for the particle species of interest.
4138 dict(int, list(str)): a dictionary mapping the PDG of each reference particle list to its isolation variables.
4143 from ROOT
import Belle2, TDatabasePDG
4146 if not decayDescriptor.init(decay_string):
4147 B2FATAL(f
"Invalid particle list {decay_string} in calculateTrackIsolation!")
4148 no_reference_list_name =
not reference_list_name
4151 "CDC": list(range(9)),
4157 if any(d
not in det_and_layers
for d
in detectors):
4159 "Your input detector list: ",
4161 " contains an invalid choice. Please select among: ",
4163 det_and_layers.keys()))
4168 processed_decay_strings = []
4169 if select_symbol
in decay_string:
4170 splitted_ds = decay_string.split(select_symbol)
4171 for i
in range(decay_string.count(select_symbol)):
4172 tmp = list(splitted_ds)
4173 tmp.insert(i+1, select_symbol)
4174 processed_decay_strings += [
''.join(tmp)]
4176 processed_decay_strings += [decay_string]
4178 reference_lists_to_vars = {}
4180 for processed_dec
in processed_decay_strings:
4181 if no_reference_list_name:
4182 decayDescriptor.init(processed_dec)
4183 selected_daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
4184 if len(selected_daughter_pdgs) > 0:
4185 reference_list_name = f
'{TDatabasePDG.Instance().GetParticle(abs(selected_daughter_pdgs[-1])).GetName()}:all'
4187 reference_list_name = f
'{processed_dec.split(":")[0]}:all'
4191 trackiso = path.add_module(
"TrackIsoCalculator",
4192 decayString=processed_dec,
4193 detectorNames=list(detectors),
4194 particleListReference=reference_list_name,
4195 useHighestProbMassForExt=highest_prob_mass_for_ext,
4196 excludePIDDetWeights=exclude_pid_det_weights)
4197 trackiso.set_name(f
"TrackIsoCalculator_{'_'.join(detectors)}_{processed_dec}_VS_{reference_list_name}")
4203 f
"minET2ETDist({d}, {d_layer}, {reference_list_name}, {int(highest_prob_mass_for_ext)})"
4204 for d
in detectors
for d_layer
in det_and_layers[d]]
4207 f
"minET2ETIsoScore({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4208 f
"minET2ETIsoScoreAsWeightedAvg({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4211 if vars_for_nearest_part:
4212 trackiso_vars.extend(
4214 f
"minET2ETDistVar({d}, {d_layer}, {reference_list_name}, {v})"
4215 for d
in detectors
for d_layer
in det_and_layers[d]
for v
in vars_for_nearest_part
4217 trackiso_vars.sort()
4219 reference_lists_to_vars[ref_pdg] = trackiso_vars
4221 return reference_lists_to_vars
4224def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
4226 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
4227 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
4228 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
4229 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
4232 .. code-block:: python
4234 from modularAnalysis import calculateDistance
4235 calculateDistance('list_name', 'decay_string', "mode", path=user_path)
4237 @param list_name name of the input ParticleList
4238 @param decay_string select particles between the distance of closest approach will be calculated
4239 @param mode Specifies how the distance is calculated
4240 vertextrack: calculate the distance of closest approach between a track and a\
4241 vertex, taking the first candidate as vertex, default
4242 trackvertex: calculate the distance of closest approach between a track and a\
4243 vertex, taking the first candidate as track
4244 2tracks: calculates the distance of closest approach between two tracks
4245 2vertices: calculates the distance between two vertices
4246 vertexbtube: calculates the distance of closest approach between a vertex and btube
4247 trackbtube: calculates the distance of closest approach between a track and btube
4248 @param path modules are added to this path
4252 dist_mod = register_module(
'DistanceCalculator')
4254 dist_mod.set_name(
'DistanceCalculator_' + list_name)
4255 dist_mod.param(
'listName', list_name)
4256 dist_mod.param(
'decayString', decay_string)
4257 dist_mod.param(
'mode', mode)
4258 path.add_module(dist_mod)
4261def addInclusiveDstarReconstruction(decayString, slowPionCut, DstarCut, path):
4263 Adds the InclusiveDstarReconstruction module to the given path.
4264 This module creates a D* particle list by estimating the D* four momenta
4265 from slow pions, specified by a given cut. The D* energy is approximated
4266 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
4267 momentum is calculated using the D* PDG mass and the direction is collinear
4268 to the slow pion direction. The charge of the given pion list has to be consistent
4271 @param decayString Decay string, must be of form ``D* -> pi``
4272 @param slowPionCut Cut applied to the input pion list to identify slow pions
4273 @param DstarCut Cut applied to the output D* list
4274 @param path the module is added to this path
4277 incl_dstar = register_module(
"InclusiveDstarReconstruction")
4278 incl_dstar.param(
"decayString", decayString)
4279 incl_dstar.param(
"slowPionCut", slowPionCut)
4280 incl_dstar.param(
"DstarCut", DstarCut)
4281 path.add_module(incl_dstar)
4284def scaleError(outputListName, inputListName,
4285 scaleFactors=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4286 scaleFactorsNoPXD=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4287 d0Resolution=[0.00115328, 0.00134704],
4288 z0Resolution=[0.00124327, 0.0013272],
4293 This module creates a new charged particle list.
4294 The helix errors of the new particles are scaled by constant factors.
4295 Two sets of five scale factors are defined for tracks with and without a PXD hit.
4296 The scale factors are in order of (d0, phi0, omega, z0, tanlambda).
4297 For tracks with a PXD hit, in order to avoid severe underestimation of d0 and z0 errors,
4298 lower limits (best resolution) can be set in a momentum-dependent form.
4299 This module is supposed to be used only for TDCPV analysis and for low-momentum (0-3 GeV/c) tracks in BBbar events.
4300 Details will be documented in a Belle II note, BELLE2-NOTE-PH-2021-038.
4302 @param inputListName Name of input charged particle list to be scaled
4303 @param outputListName Name of output charged particle list with scaled error
4304 @param scaleFactors List of five constants to be multiplied to each of helix errors (for tracks with a PXD hit)
4305 @param scaleFactorsNoPXD List of five constants to be multiplied to each of helix errors (for tracks without a PXD hit)
4306 @param d0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4307 defining d0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**1.5))**2 }
4308 @param z0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4309 defining z0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**2.5))**2 }
4310 @param d0MomThr d0 best resolution is kept constant below this momentum
4311 @param z0MomThr z0 best resolution is kept constant below this momentum
4315 scale_error = register_module(
"HelixErrorScaler")
4316 scale_error.set_name(
'ScaleError_' + inputListName)
4317 scale_error.param(
'inputListName', inputListName)
4318 scale_error.param(
'outputListName', outputListName)
4319 scale_error.param(
'scaleFactors_PXD', scaleFactors)
4320 scale_error.param(
'scaleFactors_noPXD', scaleFactorsNoPXD)
4321 scale_error.param(
'd0ResolutionParameters', d0Resolution)
4322 scale_error.param(
'z0ResolutionParameters', z0Resolution)
4323 scale_error.param(
'd0MomentumThreshold', d0MomThr)
4324 scale_error.param(
'z0MomentumThreshold', z0MomThr)
4325 path.add_module(scale_error)
4328def estimateAndAttachTrackFitResult(inputListName, path=None):
4330 Create a TrackFitResult from the momentum of the Particle assuming it originates from the IP and make a relation between them.
4331 The covariance, detector hit information, and fit-related information (pValue, NDF) are assigned meaningless values. The input
4332 Particles must not have already Track or TrackFitResult and thus are supposed to be composite particles, recoil, dummy
4333 particles, and so on.
4336 .. warning:: Since the source type is not overwritten as Track, not all track-related variables are guaranteed to be available.
4339 @param inputListName Name of input ParticleList
4342 estimator = register_module(
"TrackFitResultEstimator")
4343 estimator.set_name(
"trackFitResultEstimator_" + inputListName)
4344 estimator.param(
"inputListName", inputListName)
4345 path.add_module(estimator)
4348def correctEnergyBias(inputListNames, tableName, path=None):
4350 Scale energy of the particles according to the scaling factor.
4351 If the particle list contains composite particles, the energy of the daughters are scaled.
4352 Subsequently, the energy of the mother particle is updated as well.
4355 inputListNames (list(str)): input particle list names
4356 tableName : stored in localdb and created using ParticleWeightingLookUpCreator
4357 path (basf2.Path): module is added to this path
4362 B2ERROR(
"The energy bias cannot be corrected with this tool for Belle data.")
4364 correctenergybias = register_module(
'EnergyBiasCorrection')
4365 correctenergybias.param(
'particleLists', inputListNames)
4366 correctenergybias.param(
'tableName', tableName)
4367 path.add_module(correctenergybias)
4370def twoBodyISRPhotonCorrector(outputListName, inputListName, massiveParticle, path=None):
4372 Sets photon kinematics to corrected values in two body decays with an ISR photon
4373 and a massive particle. The original photon kinematics are kept in the input
4374 particleList and can be accessed using the originalParticle() metavariable on the
4377 @param ouputListName new ParticleList filled with copied Particles
4378 @param inputListName input ParticleList with original Particles
4379 @param massiveParticle name or PDG code of massive particle participating in the two
4380 body decay with the ISR photon
4381 @param path modules are added to this path
4385 photon_energy_correction = register_module(
'TwoBodyISRPhotonCorrector')
4386 photon_energy_correction.set_name(
'TwoBodyISRPhotonCorrector_' + outputListName)
4387 photon_energy_correction.param(
'outputGammaList', outputListName)
4388 photon_energy_correction.param(
'inputGammaList', inputListName)
4391 if isinstance(massiveParticle, int):
4392 photon_energy_correction.param(
'massiveParticlePDGCode', massiveParticle)
4394 from ROOT
import Belle2
4396 if not decayDescriptor.init(massiveParticle):
4397 raise ValueError(
"TwoBodyISRPhotonCorrector: value of massiveParticle must be" +
4398 " an int or valid decay string.")
4399 pdgCode = decayDescriptor.getMother().getPDGCode()
4400 photon_energy_correction.param(
'massiveParticlePDGCode', pdgCode)
4402 path.add_module(photon_energy_correction)
4405def addPhotonEfficiencyRatioVariables(inputListNames, tableName, path=None):
4407 Add photon Data/MC detection efficiency ratio weights to the specified particle list
4410 inputListNames (list(str)): input particle list names
4411 tableName : taken from database with appropriate name
4412 path (basf2.Path): module is added to this path
4417 B2ERROR(
"For Belle data the photon data/MC detection efficiency ratio is not available with this tool.")
4419 photon_efficiency_correction = register_module(
'PhotonEfficiencySystematics')
4420 photon_efficiency_correction.param(
'particleLists', inputListNames)
4421 photon_efficiency_correction.param(
'tableName', tableName)
4422 path.add_module(photon_efficiency_correction)
4425def addPi0VetoEfficiencySystematics(particleList, decayString, tableName, threshold, mode='standard', suffix='', path=None):
4427 Add pi0 veto Data/MC efficiency ratio weights to the specified particle list
4429 @param particleList the input ParticleList
4430 @param decayString specify hard photon to be performed pi0 veto (e.g. 'B+:sig -> rho+:sig ^gamma:hard')
4431 @param tableName table name corresponding to payload version (e.g. 'Pi0VetoEfficiencySystematics_Mar2022')
4432 @param threshold pi0 veto threshold (0.10, 0.11, ..., 0.99)
4433 @param mode choose one mode (same as writePi0EtaVeto) out of 'standard', 'tight', 'cluster' and 'both'
4434 @param suffix optional suffix to be appended to the usual extraInfo name
4435 @param path the module is added to this path
4437 The following extraInfo are available related with the given particleList:
4439 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_ratio : weight of Data/MC for the veto efficiency
4440 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_stat : the statistical uncertainty of the weight
4441 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_sys : the systematic uncertainty of the weight
4442 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_total : the total uncertainty of the weight
4443 * Pi0VetoEfficiencySystematics_{mode}{suffix}_threshold : threshold of the pi0 veto
4448 B2ERROR(
"For Belle data the pi0 veto data/MC efficiency ratio weights are not available via this tool.")
4450 pi0veto_efficiency_correction = register_module(
'Pi0VetoEfficiencySystematics')
4451 pi0veto_efficiency_correction.param(
'particleLists', particleList)
4452 pi0veto_efficiency_correction.param(
'decayString', decayString)
4453 pi0veto_efficiency_correction.param(
'tableName', tableName)
4454 pi0veto_efficiency_correction.param(
'threshold', threshold)
4455 pi0veto_efficiency_correction.param(
'mode', mode)
4456 pi0veto_efficiency_correction.param(
'suffix', suffix)
4457 path.add_module(pi0veto_efficiency_correction)
4460def getAnalysisGlobaltag(timeout=180) -> str:
4462 Returns a string containing the name of the latest and recommended analysis globaltag.
4465 timeout: Seconds to wait for b2conditionsdb-recommend
4470 B2ERROR(
"The getAnalysisGlobaltag() function cannot be used for Belle data.")
4475 tags = subprocess.check_output(
4476 [
'b2conditionsdb-recommend',
'--oneline'],
4478 ).decode(
'UTF-8').rstrip().split(
' ')
4481 if tag.startswith(
'analysis_tools'):
4485 except subprocess.TimeoutExpired
as te:
4486 B2FATAL(f
'A {te} exception was raised during the call of getAnalysisGlobaltag(). '
4487 'The function took too much time to retrieve the requested information '
4488 'from the versioning repository.\n'
4489 'Please try to re-run your job. In case of persistent failures, there may '
4490 'be issues with the DESY collaborative services, so please contact the experts.')
4491 except subprocess.CalledProcessError
as ce:
4492 B2FATAL(f
'A {ce} exception was raised during the call of getAnalysisGlobaltag(). '
4493 'Please try to re-run your job. In case of persistent failures, please contact '
4497def getAnalysisGlobaltagB2BII() -> str:
4499 Get recommended global tag for B2BII analysis.
4504 B2ERROR(
'The getAnalysisGlobaltagB2BII() function cannot be used for Belle II data.')
4505 from versioning
import recommended_b2bii_analysis_global_tag
4506 return recommended_b2bii_analysis_global_tag()
4509def getECLKLID(particleList: str, variable=
'ECLKLID', path=
None):
4511 The function calculates the PID value for Klongs that are constructed from ECL cluster.
4513 @param particleList the input ParticleList
4514 @param variable the variable name for Klong ID
4515 @param path modules are added to this path
4521 B2ERROR(
"The ECL variables based Klong Identification is only available for Belle II data.")
4523 from variables
import variables
4524 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'ECLKLID', identifier=
'ECLKLID')
4526 variables.addAlias(variable,
'conditionalVariableSelector(isFromECL and PDG==130, extraInfo(ECLKLID), constant(NaN))')
4529def getNbarIDMVA(particleList: str, path=
None):
4531 This function can give a score to predict if it is a anti-n0.
4532 It is not used to predict n0.
4533 Currently, this can be used only for ECL cluster.
4534 output will be stored in extraInfo(nbarID); -1 means MVA invalid
4536 @param particleList The input ParticleList name or a decay string which contains a full mother particle list name.
4537 Only one selected daughter is supported.
4538 @param path modules are added to this path
4541 from ROOT
import Belle2
4544 B2ERROR(
"The MVA-based anti-neutron PID is only available for Belle II data.")
4546 from variables
import variables
4548 variables.addAlias(
'V1',
'clusterHasPulseShapeDiscrimination')
4549 variables.addAlias(
'V2',
'clusterE')
4550 variables.addAlias(
'V3',
'clusterLAT')
4551 variables.addAlias(
'V4',
'clusterE1E9')
4552 variables.addAlias(
'V5',
'clusterE9E21')
4553 variables.addAlias(
'V6',
'clusterZernikeMVA')
4554 variables.addAlias(
'V7',
'clusterAbsZernikeMoment40')
4555 variables.addAlias(
'V8',
'clusterAbsZernikeMoment51')
4559 'passesCut(V1 == 1 and V2 >= 0 and V3 >= 0 and V4 >= 0 and V5 >= 0 and V6 >= 0 and V7 >= 0 and V8 >= 0)')
4560 variables.addAlias(
'nbarIDmod',
'conditionalVariableSelector(nbarIDValid == 1, extraInfo(nbarIDFromMVA), constant(-1.0))')
4562 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'nbarIDFromMVA', identifier=
'db_nbarIDECL')
4564 if not decayDescriptor.init(particleList):
4565 raise ValueError(f
"Provided decay string is invalid: {particleList}")
4566 if decayDescriptor.getNDaughters() == 0:
4569 listname = decayDescriptor.getMother().getFullName()
4570 variablesToDaughterExtraInfo(listname, particleList, {
'nbarIDmod':
'nbarID'}, option=2, path=path)
4573def reconstructDecayWithNeutralHadron(decayString, cut, allowGamma=False, allowAnyParticleSource=False, path=None, **kwargs):
4575 Reconstructs decay with a long-lived neutral hadron e.g.
4576 :math:`B^0 \to J/\psi K_L^0`,
4577 :math:`B^0 \to p \bar{n} D^*(2010)^-`.
4579 The calculation is done with IP constraint and mother mass constraint.
4581 The decay string passed in must satisfy the following rules:
4583 - The neutral hadron must be **selected** in the decay string with the
4584 caret (``^``) e.g. ``B0:sig -> J/psi:sig ^K_L0:sig``. (Note the caret
4585 next to the neutral hadron.)
4586 - There can only be **one neutral hadron in a decay**.
4587 - The neutral hadron has to be a direct daughter of its mother.
4589 .. note:: This function forwards its arguments to `reconstructDecay`,
4590 so please check the documentation of `reconstructDecay` for all
4593 @param decayString A decay string following the mentioned rules
4594 @param cut Cut to apply to the particle list
4595 @param allowGamma Whether allow the selected particle to be ``gamma``
4596 @param allowAnyParticleSource Whether allow the selected particle to be from any source.
4597 Should only be used when studying control sample.
4598 @param path The path to put in the module
4601 reconstructDecay(decayString, cut, path=path, **kwargs)
4602 module = register_module(
'NeutralHadron4MomentumCalculator')
4603 module.set_name(
'NeutralHadron4MomentumCalculator_' + decayString)
4604 module.param(
'decayString', decayString)
4605 module.param(
'allowGamma', allowGamma)
4606 module.param(
'allowAnyParticleSource', allowAnyParticleSource)
4607 path.add_module(module)
4610def updateMassHypothesis(particleList, pdg, writeOut=False, path=None):
4612 Module to update the mass hypothesis of a given input particle list with the chosen PDG.
4613 A new particle list is created with updated mass hypothesis.
4614 The allowed mass hypotheses for both input and output are electrons, muons, pions, kaons and protons.
4617 The new particle list is named after the input one, with the additional suffix ``_converted_from_OLDHYPOTHESIS``,
4618 e.g. ``e+:all`` converted to muons becomes ``mu+:all_converted_from_e``.
4620 @param particleList The input particle list name
4621 @param pdg The PDG code for the new mass hypothesis, in [11, 13, 211, 321, 2212]
4622 @param writeOut Whether `RootOutput` module should save the new particle list
4623 @param path Modules are added to this path
4625 mass_updater = register_module(
"ParticleMassHypothesesUpdater")
4626 mass_updater.set_name(
"ParticleMassHypothesesUpdater_" + particleList +
"_to_" + str(pdg))
4627 mass_updater.param(
"particleList", particleList)
4628 mass_updater.param(
"writeOut", writeOut)
4629 mass_updater.param(
"pdgCode", pdg)
4630 path.add_module(mass_updater)
4633func_requiring_analysisGT = [
4634 correctTrackEnergy, scaleTrackMomenta, smearTrackMomenta, oldwritePi0EtaVeto, writePi0EtaVeto, lowEnergyPi0Identification,
4635 getBeamBackgroundProbability, getFakePhotonProbability, tagCurlTracks, applyChargedPidMVA, correctEnergyBias,
4636 addPhotonEfficiencyRatioVariables, addPi0VetoEfficiencySystematics, getNbarIDMVA, getECLKLID]
4637for _
in func_requiring_analysisGT:
4638 _.__doc__ +=
"\n .. note:: This function (optionally) requires a payload stored in the analysis GlobalTag. "\
4639 "Please append or prepend the latest one from `getAnalysisGlobaltag` or `getAnalysisGlobaltagB2BII`.\n"
4642if __name__ ==
'__main__':
4644 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)