12 This module defines wrapper functions around the analysis modules.
16 from basf2
import register_module, create_path
17 from basf2
import B2INFO, B2WARNING, B2ERROR, B2FATAL
22 def setAnalysisConfigParams(configParametersAndValues, path):
24 Sets analysis configuration parameters.
28 - 'tupleStyle': 'Default' (default) or 'Laconic'
30 - defines the style of the branch name in the ntuple
32 - 'mcMatchingVersion': Specifies what version of mc matching algorithm is going to be used:
34 - 'Belle' - analysis of Belle MC
35 - 'BelleII' (default) - all other cases
37 @param configParametersAndValues dictionary of parameters and their values of the form {param1: value, param2: value, ...)
38 @param modules are added to this path
41 conf = register_module(
'AnalysisConfiguration')
43 allParameters = [
'tupleStyle',
'mcMatchingVersion']
45 keys = configParametersAndValues.keys()
47 if key
not in allParameters:
48 allParametersString =
', '.join(allParameters)
49 B2ERROR(
'Invalid analysis configuration parameter: ' + key +
'.\n'
50 'Please use one of the following: ' + allParametersString)
52 for param
in allParameters:
53 if param
in configParametersAndValues:
54 conf.param(param, configParametersAndValues.get(param))
59 def inputMdst(filename, path, environmentType='default', skipNEvents=0, entrySequence=None, *, parentLevel=0, **kwargs):
61 Loads the specified :ref:`mDST <mdst>` (or :ref:`uDST <analysis_udstoutput>`) file with the RootInput module.
63 The correct environment (e.g. magnetic field settings) is determined from
64 ``environmentType``. Options are either: 'default' (for Belle II MC and
65 data: falls back to database), 'Belle': for analysis of converted Belle 1
69 filename (str): the name of the file to be loaded
70 path (basf2.Path): modules are added to this path
71 environmentType (str): type of the environment to be loaded (either 'default' or 'Belle')
72 skipNEvents (int): N events of the input file are skipped
73 entrySequence (str): The number sequences (e.g. 23:42,101) defining the entries which are processed.
74 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
78 if filename ==
'default':
80 We have simplified the arguments to inputMdst! If you are running on Belle II
81 data or MC, you don't have to use "default" any more.
83 inputMdst("default", "/your/input/file.root", path=mypath)
85 inputMdst("/your/input/file.root", path=mypath)
87 elif filename ==
"Belle":
89 We have reordered the arguments to inputMdst! If you are running on Belle 1
90 data or MC, you need to specify the 'environmentType'.
92 inputMdst("Belle", "/your/input/file.root", path=mypath)
94 inputMdst("/your/input/file.root", path=mypath, environmentType='Belle')
96 elif filename
in [f
"MC{i}" for i
in range(5, 10)]:
97 B2FATAL(f
"We no longer support the MC version {filename}. Sorry.")
99 if entrySequence
is not None:
100 entrySequence = [entrySequence]
102 inputMdstList([filename], path, environmentType, skipNEvents, entrySequence, parentLevel=parentLevel, **kwargs)
108 environmentType='default',
113 useB2BIIDBCache=True):
115 Loads the specified list of :ref:`mDST <mdst>` (or :ref:`uDST <analysis_udstoutput>`) files with the RootInput module.
117 The correct environment (e.g. magnetic field settings) is determined from
118 ``environmentType``. Options are either: 'default' (for Belle II MC and
119 data: falls back to database), 'Belle': for analysis of converted Belle 1
123 filelist (list(str)): the filename list of files to be loaded
124 path (basf2.Path): modules are added to this path
125 environmentType (str): type of the environment to be loaded (either 'default' or 'Belle')
126 skipNEvents (int): N events of the input files are skipped
127 entrySequences (list(str)): The number sequences (e.g. 23:42,101) defining
128 the entries which are processed for each inputFileName.
129 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
130 useB2BIIDBCache (bool): Loading of local KEKCC database (only to be deactivated in very special cases)
134 if filelist ==
'default':
136 We have simplified the arguments to inputMdstList! If you are running on
137 Belle II data or MC, you don't have to use "default" any more.
139 inputMdstList("default", list_of_your_files, path=mypath)
141 inputMdstList(list_of_your_files, path=mypath)
143 elif filelist ==
"Belle":
145 We have reordered the arguments to inputMdstList! If you are running on
146 Belle 1 data or MC, you need to specify the 'environmentType'.
148 inputMdstList("Belle", list_of_your_files, path=mypath)
150 inputMdstList(list_of_your_files, path=mypath, environmentType='Belle')
152 elif filelist
in [f
"MC{i}" for i
in range(5, 10)]:
153 B2FATAL(f
"We no longer support the MC version {filelist}. Sorry.")
155 roinput = register_module(
'RootInput')
156 roinput.param(
'inputFileNames', filelist)
157 roinput.param(
'skipNEvents', skipNEvents)
158 if entrySequences
is not None:
159 roinput.param(
'entrySequences', entrySequences)
160 roinput.param(
'parentLevel', parentLevel)
162 path.add_module(roinput)
163 path.add_module(
'ProgressBar')
165 if environmentType ==
'Belle':
170 from ROOT
import Belle2
176 setAnalysisConfigParams({
'mcMatchingVersion':
'Belle'}, path)
179 basf2.conditions.metadata_providers = [
"/sw/belle/b2bii/database/conditions/b2bii.sqlite"]
180 basf2.conditions.payload_locations = [
"/sw/belle/b2bii/database/conditions/"]
183 def outputMdst(filename, path):
185 Saves mDST (mini-Data Summary Tables) to the output root file.
189 This function is kept for backward-compatibility.
190 Better to use `mdst.add_mdst_output` directly.
198 def outputUdst(filename, particleLists=None, includeArrays=None, path=None, dataDescription=None):
200 Save uDST (user-defined Data Summary Tables) = MDST + Particles + ParticleLists
201 The charge-conjugate lists of those given in particleLists are also stored.
202 Additional Store Arrays and Relations to be stored can be specified via includeArrays
206 This does not reduce the amount of Particle objects saved,
207 see `udst.add_skimmed_udst_output` for a function that does.
213 path=path, filename=filename, particleLists=particleLists,
214 additionalBranches=includeArrays, dataDescription=dataDescription)
217 def outputIndex(filename, path, includeArrays=None, keepParents=False, mc=True):
219 Write out all particle lists as an index file to be reprocessed using parentLevel flag.
220 Additional branches necessary for file to be read are automatically included.
221 Additional Store Arrays and Relations to be stored can be specified via includeArrays
224 @param str filename the name of the output index file
225 @param str path modules are added to this path
226 @param list(str) includeArrays: datastore arrays/objects to write to the output
227 file in addition to particle lists and related information
228 @param bool keepParents whether the parents of the input event will be saved as the parents of the same event
229 in the output index file. Useful if you are only adding more information to another index file
230 @param bool mc whether the input data is MC or not
233 if includeArrays
is None:
237 onlyPLists = register_module(
'OnlyWriteOutParticleLists')
238 path.add_module(onlyPLists)
243 'ParticlesToMCParticles',
244 'ParticlesToPIDLikelihoods',
245 'ParticleExtraInfoMap',
248 branches = [
'EventMetaData']
249 persistentBranches = [
'FileMetaData']
253 branches += partBranches
254 branches += includeArrays
256 r1 = register_module(
'RootOutput')
257 r1.param(
'outputFileName', filename)
258 r1.param(
'additionalBranchNames', branches)
259 r1.param(
'branchNamesPersistent', persistentBranches)
260 r1.param(
'keepParents', keepParents)
264 def setupEventInfo(noEvents, path):
266 Prepare to generate events. This function sets up the EventInfoSetter.
267 You should call this before adding a generator from generators.
268 The experiment and run numbers are set to 0 (run independent generic MC in phase 3).
269 https://confluence.desy.de/display/BI/Experiment+numbering
272 noEvents (int): number of events to be generated
273 path (basf2.Path): modules are added to this path
276 evtnumbers = register_module(
'EventInfoSetter')
277 evtnumbers.param(
'evtNumList', [noEvents])
278 evtnumbers.param(
'runList', [0])
279 evtnumbers.param(
'expList', [0])
280 path.add_module(evtnumbers)
283 def loadGearbox(path, silence_warning=False):
285 Loads Gearbox module to the path.
288 Should be used in a job with *cosmic event generation only*
290 Needed for scripts which only generate cosmic events in order to
293 @param path modules are added to this path
294 @param silence_warning stops a verbose warning message if you know you want to use this function
297 if not silence_warning:
298 B2WARNING(
"""You are overwriting the geometry from the database with Gearbox.
299 This is fine if you're generating cosmic events. But in most other cases you probably don't want this.
301 If you're really sure you know what you're doing you can suppress this message with:
303 >>> loadGearbox(silence_warning=True)
307 paramloader = register_module(
'Gearbox')
308 path.add_module(paramloader)
311 def printPrimaryMCParticles(path, **kwargs):
313 Prints all primary MCParticles, that is particles from
314 the physics generator and not particles created by the simulation
316 This is equivalent to `printMCParticles(onlyPrimaries=True, path=path) <printMCParticles>` and additional
317 keyword arguments are just forwarded to that function
320 return printMCParticles(onlyPrimaries=
True, path=path, **kwargs)
323 def printMCParticles(onlyPrimaries=False, maxLevel=-1, path=None, *,
324 showProperties=False, showMomenta=False, showVertices=False, showStatus=False, suppressPrint=False):
326 Prints all MCParticles or just primary MCParticles up to specified level. -1 means no limit.
328 By default this will print a tree of just the particle names and their pdg
329 codes in the event, for example ::
331 [INFO] Content of MCParticle list
334 ╰── Upsilon(4S) (300553)
336 │ ├── anti-D_0*0 (-10421)
339 │ │ │ │ ├── anti-K0 (-311)
340 │ │ │ │ │ ╰── K_S0 (310)
341 │ │ │ │ │ ├── pi+ (211)
342 │ │ │ │ │ │ ╰╶╶ p+ (2212)
343 │ │ │ │ │ ╰── pi- (-211)
344 │ │ │ │ │ ├╶╶ e- (11)
345 │ │ │ │ │ ├╶╶ n0 (2112)
346 │ │ │ │ │ ├╶╶ n0 (2112)
347 │ │ │ │ │ ╰╶╶ n0 (2112)
348 │ │ │ │ ╰── pi- (-211)
349 │ │ │ │ ├╶╶ anti-nu_mu (-14)
351 │ │ │ │ ├╶╶ nu_mu (14)
352 │ │ │ │ ├╶╶ anti-nu_e (-12)
356 │ │ │ │ ├── gamma (22)
357 │ │ │ │ ╰── gamma (22)
363 │ │ ├╶╶ anti-nu_mu (-14)
371 There's a distinction between primary and secondary particles. Primary
372 particles are the ones created by the physics generator while secondary
373 particles are ones generated by the simulation of the detector interaction.
375 Secondaries are indicated with a dashed line leading to the particle name
376 and if the output is to the terminal they will be printed in red. If
377 ``onlyPrimaries`` is True they will not be included in the tree.
379 On demand, extra information on all the particles can be displayed by
380 enabling any of the ``showProperties``, ``showMomenta``, ``showVertices``
381 and ``showStatus`` flags. Enabling all of them will look like
386 │ mass=0.14 energy=0.445 charge=-1 lifetime=6.36
387 │ p=(0.257, -0.335, 0.0238) |p|=0.423
388 │ production vertex=(0.113, -0.0531, 0.0156), time=0.00589
389 │ status flags=PrimaryParticle, StableInGenerator, StoppedInDetector
393 mass=0.94 energy=0.94 charge=0 lifetime=5.28e+03
394 p=(-0.000238, -0.0127, 0.0116) |p|=0.0172
395 production vertex=(144, 21.9, -1.29), time=39
396 status flags=StoppedInDetector
397 creation process=HadronInelastic
400 The first line of extra information is enabled by ``showProperties``, the
401 second line by ``showMomenta``, the third line by ``showVertices`` and the
402 last two lines by ``showStatus``. Note that all values are given in Belle II
403 standard units, that is GeV, centimeter and nanoseconds.
405 The depth of the tree can be limited with the ``maxLevel`` argument: If it's
406 bigger than zero it will limit the tree to the given number of generations.
407 A visual indicator will be added after each particle which would have
408 additional daughters that are skipped due to this limit. An example event
409 with ``maxLevel=3`` is given below. In this case only the tau neutrino and
410 the pion don't have additional daughters. ::
412 [INFO] Content of MCParticle list
415 ╰── Upsilon(4S) (300553)
417 │ ├── anti-D*0 (-423) → …
426 The same information will be stored in the branch ``__MCDecayString__`` of
427 TTree created by `VariablesToNtuple` or `VariablesToEventBasedTree` module.
428 This branch is automatically created when `PrintMCParticles` modules is called.
429 Printing the information on the log message can be suppressed if ``suppressPrint``
430 is True, while the branch ``__MCDecayString__``. This option helps to reduce the
431 size of the log message.
434 onlyPrimaries (bool): If True show only primary particles, that is particles coming from
435 the generator and not created by the simulation.
436 maxLevel (int): If 0 or less print the whole tree, otherwise stop after n generations
437 showProperties (bool): If True show mass, energy and charge of the particles
438 showMomenta (bool): if True show the momenta of the particles
439 showVertices (bool): if True show production vertex and production time of all particles
440 showStatus (bool): if True show some status information on the particles.
441 For secondary particles this includes creation process.
442 suppressPrint (bool): if True printing the information on the log message is suppressed.
443 Even if True, the branch ``__MCDecayString__`` is created.
446 return path.add_module(
448 onlyPrimaries=onlyPrimaries,
450 showProperties=showProperties,
451 showMomenta=showMomenta,
452 showVertices=showVertices,
453 showStatus=showStatus,
454 suppressPrint=suppressPrint,
458 def correctBrems(outputList,
461 maximumAcceptance=3.0,
462 multiplePhotons=False,
463 usePhotonOnlyOnce=True,
467 For each particle in the given ``inputList``, copies it to the ``outputList`` and adds the
468 4-vector of the photon(s) in the ``gammaList`` which has(have) a weighted named relation to
469 the particle's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
472 This can only work if the mdst file contains the *Bremsstrahlung* named relation. Official MC samples
473 up to and including MC12 and proc9 **do not** contain this. Newer production campaigns (from proc10 and MC13) do.
474 However, studies by the tau WG revealed that the cuts applied by the ``ECLTrackBremFinder`` module are too tight.
475 These will be loosened but this will only have effect with proc13 and MC15.
476 If your analysis is very sensitive to the Bremsstrahlung corrections, it is advised to use `correctBremsBelle`.
479 A detailed description of how the weights are set can be found directly at the documentation of the
480 `BremsFinder` module.
482 Please note that a new particle is always generated, with the old particle and -if found- one or more
483 photons as daughters.
485 The ``inputList`` should contain particles with associated tracks. Otherwise, the module will exit with an error.
487 The ``gammaList`` should contain photons. Otherwise, the module will exit with an error.
489 @param outputList The output particle list name containing the corrected particles
490 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
491 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
492 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
493 @param multiplePhotons Whether to use only one photon (the one with the smallest acceptance) or as many as possible
494 @param usePhotonOnlyOnce If true, each brems candidate is used to correct only the track with the smallest relation weight
495 @param writeOut Whether `RootOutput` module should save the created ``outputList``
496 @param path The module is added to this path
501 B2ERROR(
"The BremsFinder can only be run over Belle II data.")
503 bremscorrector = register_module(
'BremsFinder')
504 bremscorrector.set_name(
'bremsCorrector_' + outputList)
505 bremscorrector.param(
'inputList', inputList)
506 bremscorrector.param(
'outputList', outputList)
507 bremscorrector.param(
'gammaList', gammaList)
508 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
509 bremscorrector.param(
'multiplePhotons', multiplePhotons)
510 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
511 bremscorrector.param(
'writeOut', writeOut)
512 path.add_module(bremscorrector)
515 def copyList(outputListName, inputListName, writeOut=False, path=None):
517 Copy all Particle indices from input ParticleList to the output ParticleList.
518 Note that the Particles themselves are not copied. The original and copied
519 ParticleLists will point to the same Particles.
521 @param ouputListName copied ParticleList
522 @param inputListName original ParticleList to be copied
523 @param writeOut whether RootOutput module should save the created ParticleList
524 @param path modules are added to this path
527 copyLists(outputListName, [inputListName], writeOut, path)
530 def correctBremsBelle(outputListName,
533 multiplePhotons=True,
535 usePhotonOnlyOnce=False,
539 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
540 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
544 Studies by the tau WG show that using a rather wide opening angle (up to
545 0.2 rad) and rather low energetic photons results in good correction.
546 However, this should only serve as a starting point for your own studies
547 because the optimal criteria are likely mode-dependent
550 outputListName (str): The output charged particle list containing the corrected charged particles
551 inputListName (str): The initial charged particle list containing the charged particles to correct.
552 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
553 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one -> False,
554 add all the photons within the cone -> True
555 angleThreshold (float): The maximum angle in radians between the charged particle and the (radiative)
556 gamma to be accepted.
557 writeOut (bool): whether RootOutput module should save the created ParticleList
558 usePhotonOnlyOnce (bool): If true, a photon is used for correction of the closest charged particle in the inputList.
559 If false, a photon is allowed to be used for correction multiple times (Default).
562 One cannot use a photon twice to reconstruct a composite particle. Thus, for example, if ``e+`` and ``e-`` are corrected
563 with a ``gamma``, the pair of ``e+`` and ``e-`` cannot form a ``J/psi -> e+ e-`` candidate.
565 path (basf2.Path): modules are added to this path
568 fsrcorrector = register_module(
'BelleBremRecovery')
569 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
570 fsrcorrector.param(
'inputListName', inputListName)
571 fsrcorrector.param(
'outputListName', outputListName)
572 fsrcorrector.param(
'gammaListName', gammaListName)
573 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
574 fsrcorrector.param(
'angleThreshold', angleThreshold)
575 fsrcorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
576 fsrcorrector.param(
'writeOut', writeOut)
577 path.add_module(fsrcorrector)
580 def copyLists(outputListName, inputListNames, writeOut=False, path=None):
582 Copy all Particle indices from all input ParticleLists to the
583 single output ParticleList.
584 Note that the Particles themselves are not copied.
585 The original and copied ParticleLists will point to the same Particles.
587 Duplicates are removed based on the first-come, first-served principle.
588 Therefore, the order of the input ParticleLists matters.
591 If you want to select the best duplicate based on another criterion, have
592 a look at the function `mergeListsWithBestDuplicate`.
595 Two particles that differ only by the order of their daughters are
596 considered duplicates and one of them will be removed.
598 @param ouputListName copied ParticleList
599 @param inputListName vector of original ParticleLists to be copied
600 @param writeOut whether RootOutput module should save the created ParticleList
601 @param path modules are added to this path
604 pmanipulate = register_module(
'ParticleListManipulator')
605 pmanipulate.set_name(
'PListCopy_' + outputListName)
606 pmanipulate.param(
'outputListName', outputListName)
607 pmanipulate.param(
'inputListNames', inputListNames)
608 pmanipulate.param(
'writeOut', writeOut)
609 path.add_module(pmanipulate)
612 def copyParticles(outputListName, inputListName, writeOut=False, path=None):
614 Create copies of Particles given in the input ParticleList and add them to the output ParticleList.
616 The existing relations of the original Particle (or it's (grand-)^n-daughters)
617 are copied as well. Note that only the relation is copied and that the related
618 object is not. Copied particles are therefore related to the *same* object as
621 @param ouputListName new ParticleList filled with copied Particles
622 @param inputListName input ParticleList with original Particles
623 @param writeOut whether RootOutput module should save the created ParticleList
624 @param path modules are added to this path
628 pmanipulate = register_module(
'ParticleListManipulator')
629 pmanipulate.set_name(
'PListCopy_' + outputListName)
630 pmanipulate.param(
'outputListName', outputListName)
631 pmanipulate.param(
'inputListNames', [inputListName])
632 pmanipulate.param(
'writeOut', writeOut)
633 path.add_module(pmanipulate)
636 pcopy = register_module(
'ParticleCopier')
637 pcopy.param(
'inputListNames', [outputListName])
638 path.add_module(pcopy)
641 def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
643 Copy candidates from all lists in ``inputListNames`` to
644 ``outputListName`` if they pass ``cut`` (given selection criteria).
647 Note that the Particles themselves are not copied.
648 The original and copied ParticleLists will point to the same Particles.
651 Require energetic pions safely inside the cdc
653 .. code-block:: python
655 cutAndCopyLists("pi+:energeticPions", ["pi+:good", "pi+:loose"], "[E > 2] and thetaInCDCAcceptance", path=mypath)
658 You must use square braces ``[`` and ``]`` for conditional statements.
661 outputListName (str): the new ParticleList name
662 inputListName (list(str)): list of input ParticleList names
663 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
664 writeOut (bool): whether RootOutput module should save the created ParticleList
665 path (basf2.Path): modules are added to this path
668 pmanipulate = register_module(
'ParticleListManipulator')
669 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
670 pmanipulate.param(
'outputListName', outputListName)
671 pmanipulate.param(
'inputListNames', inputListNames)
672 pmanipulate.param(
'cut', cut)
673 pmanipulate.param(
'writeOut', writeOut)
674 path.add_module(pmanipulate)
677 def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
679 Copy candidates from ``inputListName`` to ``outputListName`` if they pass
680 ``cut`` (given selection criteria).
683 Note the Particles themselves are not copied.
684 The original and copied ParticleLists will point to the same Particles.
687 require energetic pions safely inside the cdc
689 .. code-block:: python
691 cutAndCopyList("pi+:energeticPions", "pi+:loose", "[E > 2] and thetaInCDCAcceptance", path=mypath)
694 You must use square braces ``[`` and ``]`` for conditional statements.
697 outputListName (str): the new ParticleList name
698 inputListName (str): input ParticleList name
699 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
700 writeOut (bool): whether RootOutput module should save the created ParticleList
701 path (basf2.Path): modules are added to this path
704 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
707 def removeTracksForTrackingEfficiencyCalculation(inputListNames, fraction, path=None):
709 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
710 Takes care of the duplicates, if any.
713 inputListNames (list(str)): input particle list names
714 fraction (float): fraction of particles to be removed randomly
715 path (basf2.Path): module is added to this path
718 trackingefficiency = register_module(
'TrackingEfficiency')
719 trackingefficiency.param(
'particleLists', inputListNames)
720 trackingefficiency.param(
'frac', fraction)
721 path.add_module(trackingefficiency)
724 def scaleTrackMomenta(inputListNames, scale=float(
'nan'), payloadName=
"", scalingFactorName=
"SF", path=
None):
726 Scale momenta of the particles according to a scaling factor scale.
727 This scaling factor can either be given as constant number or as the name of the payload which contains
728 the variable scale factors.
729 If the particle list contains composite particles, the momenta of the track-based daughters are scaled.
730 Subsequently, the momentum of the mother particle is updated as well.
733 inputListNames (list(str)): input particle list names
734 scale (float): scaling factor (1.0 -- no scaling)
735 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
736 scalingFactorName (str): name of scaling factor variable in the payload.
737 path (basf2.Path): module is added to this path
742 B2ERROR(
"The tracking momentum scaler can only be run over Belle II data.")
744 trackingmomentum = register_module(
'TrackingMomentum')
745 trackingmomentum.param(
'particleLists', inputListNames)
746 trackingmomentum.param(
'scale', scale)
747 trackingmomentum.param(
'payloadName', payloadName)
748 trackingmomentum.param(
'scalingFactorName', scalingFactorName)
750 path.add_module(trackingmomentum)
753 def smearTrackMomenta(inputListNames, payloadName="", smearingFactorName="smear", path=None):
755 Smear the momenta of the particles according the values read from the given payload.
756 If the particle list contains composite particles, the momenta of the track-based daughters are smeared.
757 Subsequently, the momentum of the mother particle is updated as well.
760 inputListNames (list(str)): input particle list names
761 payloadName (str): name of the payload which contains the smearing valuess
762 smearingFactorName (str): name of smearing factor variable in the payload.
763 path (basf2.Path): module is added to this path
766 trackingmomentum = register_module(
'TrackingMomentum')
767 trackingmomentum.param(
'particleLists', inputListNames)
768 trackingmomentum.param(
'payloadName', payloadName)
769 trackingmomentum.param(
'smearingFactorName', smearingFactorName)
771 path.add_module(trackingmomentum)
774 def mergeListsWithBestDuplicate(outputListName,
779 ignoreMotherFlavor=False,
782 Merge input ParticleLists into one output ParticleList. Only the best
783 among duplicates is kept. The lowest or highest value (configurable via
784 preferLowest) of the provided variable determines which duplicate is the
787 @param ouputListName name of merged ParticleList
788 @param inputListName vector of original ParticleLists to be merged
789 @param variable variable to determine best duplicate
790 @param preferLowest whether lowest or highest value of variable should be preferred
791 @param writeOut whether RootOutput module should save the created ParticleList
792 @param ignoreMotherFlavor whether the flavor of the mother particle is ignored when trying to find duplicates
793 @param path modules are added to this path
796 pmanipulate = register_module(
'ParticleListManipulator')
797 pmanipulate.set_name(
'PListMerger_' + outputListName)
798 pmanipulate.param(
'outputListName', outputListName)
799 pmanipulate.param(
'inputListNames', inputListNames)
800 pmanipulate.param(
'variable', variable)
801 pmanipulate.param(
'preferLowest', preferLowest)
802 pmanipulate.param(
'writeOut', writeOut)
803 pmanipulate.param(
'ignoreMotherFlavor', ignoreMotherFlavor)
804 path.add_module(pmanipulate)
807 def fillSignalSideParticleList(outputListName, decayString, path):
809 This function should only be used in the ROE path, that is a path
810 that is executed for each ROE object in the DataStore.
812 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
814 Function will create a ParticleList with name 'gamma:sig' which will be filled
815 with the existing photon Particle, being the second daughter of the B0 candidate
816 to which the ROE object has to be related.
818 @param ouputListName name of the created ParticleList
819 @param decayString specify Particle to be added to the ParticleList
822 pload = register_module(
'SignalSideParticleListCreator')
823 pload.set_name(
'SSParticleList_' + outputListName)
824 pload.param(
'particleListName', outputListName)
825 pload.param(
'decayString', decayString)
826 path.add_module(pload)
829 def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False,
830 loadPhotonsFromKLM=False):
832 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
833 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
835 The multiple ParticleLists with their own selection criteria are specified
836 via list tuples (decayString, cut), for example
838 .. code-block:: python
840 kaons = ('K+:mykaons', 'kaonID>0.1')
841 pions = ('pi+:mypions','pionID>0.1')
842 fillParticleLists([kaons, pions], path=mypath)
844 If you are unsure what selection you want, you might like to see the
845 :doc:`StandardParticles` functions.
847 The type of the particles to be loaded is specified via the decayString module parameter.
848 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
849 the particle. The following types of the particles can be loaded:
851 * charged final state particles (input ``mdst`` type = Tracks)
852 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
854 * neutral final state particles
855 - "gamma" (input ``mdst`` type = ECLCluster)
856 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
857 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
860 For "K_S0" and "Lambda0" you must specify the daughter ordering.
862 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
864 .. code-block:: python
866 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
867 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
870 Gammas can also be loaded from KLMClusters by explicitly setting the
871 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
872 done in selected use-cases and the effect should be studied carefully.
875 For "K_L0" it is now possible to load from ECLClusters, to revert to
876 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
878 .. code-block:: python
880 klongs = ('K_L0', 'isFromKLM > 0')
881 fillParticleLists([kaons, pions, klongs], 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 The cut is the selection criteria
893 to be added to the ParticleList. It can be an empty string.
894 writeOut (bool): whether RootOutput module should save the created ParticleList
895 path (basf2.Path): modules are added to this path
896 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
897 using a mass hypothesis of the exact type passed to fillParticleLists().
898 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
899 in terms of mass difference will be used if the fit using exact particle
900 type is not available.
901 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
904 pload = register_module(
'ParticleLoader')
905 pload.set_name(
'ParticleLoader_' +
'PLists')
906 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
907 pload.param(
'writeOut', writeOut)
908 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
909 path.add_module(pload)
911 from ROOT
import Belle2
913 for decayString, cut
in decayStringsWithCuts:
914 if not decayDescriptor.init(decayString):
915 raise ValueError(
"Invalid decay string")
917 if decayDescriptor.getNDaughters() > 0:
921 if decayDescriptor.getMother().getLabel() !=
'V0':
922 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
923 elif decayDescriptor.getMother().getLabel() !=
'all':
926 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
930 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
932 if decayString.startswith(
"gamma"):
935 if not loadPhotonsFromKLM:
936 applyCuts(decayString,
'isFromECL', path)
939 def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False,
940 loadPhotonsFromKLM=False):
942 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
943 loads them to the StoreArray<Particle> and fills the ParticleList.
946 the :doc:`StandardParticles` functions.
948 The type of the particles to be loaded is specified via the decayString module parameter.
949 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
950 the particle. The following types of the particles can be loaded:
952 * charged final state particles (input ``mdst`` type = Tracks)
953 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
955 * neutral final state particles
956 - "gamma" (input ``mdst`` type = ECLCluster)
957 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
958 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
961 For "K_S0" and "Lambda0" you must specify the daughter ordering.
963 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
965 .. code-block:: python
967 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
970 Gammas can also be loaded from KLMClusters by explicitly setting the
971 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
972 done in selected use-cases and the effect should be studied carefully.
975 For "K_L0" it is now possible to load from ECLClusters, to revert to
976 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
978 .. code-block:: python
980 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
983 decayString (str): Type of Particle and determines the name of the ParticleList.
984 If the input MDST type is V0 the whole decay chain needs to be specified, so that
985 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``)
986 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
987 writeOut (bool): whether RootOutput module should save the created ParticleList
988 path (basf2.Path): modules are added to this path
989 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
990 using a mass hypothesis of the exact type passed to fillParticleLists().
991 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
992 in terms of mass difference will be used if the fit using exact particle
993 type is not available.
994 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
997 pload = register_module(
'ParticleLoader')
998 pload.set_name(
'ParticleLoader_' + decayString)
999 pload.param(
'decayStrings', [decayString])
1000 pload.param(
'writeOut', writeOut)
1001 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1002 path.add_module(pload)
1005 from ROOT
import Belle2
1007 if not decayDescriptor.init(decayString):
1008 raise ValueError(
"Invalid decay string")
1009 if decayDescriptor.getNDaughters() > 0:
1013 if decayDescriptor.getMother().getLabel() !=
'V0':
1014 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1015 elif decayDescriptor.getMother().getLabel() !=
'all':
1018 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1022 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1024 if decayString.startswith(
"gamma"):
1027 if not loadPhotonsFromKLM:
1028 applyCuts(decayString,
'isFromECL', path)
1031 def fillParticleListWithTrackHypothesis(decayString,
1035 enforceFitHypothesis=False,
1038 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
1040 @param decayString specifies type of Particles and determines the name of the ParticleList
1041 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1042 @param hypothesis the PDG code of the desired track hypothesis
1043 @param writeOut whether RootOutput module should save the created ParticleList
1044 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
1045 using a mass hypothesis of the exact type passed to fillParticleLists().
1046 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1047 in terms of mass difference will be used if the fit using exact particle
1048 type is not available.
1049 @param path modules are added to this path
1052 pload = register_module(
'ParticleLoader')
1053 pload.set_name(
'ParticleLoader_' + decayString)
1054 pload.param(
'decayStrings', [decayString])
1055 pload.param(
'trackHypothesis', hypothesis)
1056 pload.param(
'writeOut', writeOut)
1057 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1058 path.add_module(pload)
1060 from ROOT
import Belle2
1062 if not decayDescriptor.init(decayString):
1063 raise ValueError(
"Invalid decay string")
1064 if decayDescriptor.getMother().getLabel() !=
'all':
1067 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1071 applyCuts(decayString, cut, path)
1074 def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
1076 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
1079 You must specify the daughter ordering.
1081 .. code-block:: python
1083 fillConvertedPhotonsList('gamma:converted -> e+ e-', '', path=mypath)
1086 decayString (str): Must be gamma to an e+e- pair. You must specify the daughter ordering.
1087 Will also determine the name of the particleList.
1088 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1089 writeOut (bool): whether RootOutput module should save the created ParticleList
1090 path (basf2.Path): modules are added to this path
1096 B2ERROR(
'For Belle converted photons are available in the pre-defined list "gamma:v0mdst".')
1098 pload = register_module(
'ParticleLoader')
1099 pload.set_name(
'ParticleLoader_' + decayString)
1100 pload.param(
'decayStrings', [decayString])
1101 pload.param(
'addDaughters',
True)
1102 pload.param(
'writeOut', writeOut)
1103 path.add_module(pload)
1105 from ROOT
import Belle2
1107 if not decayDescriptor.init(decayString):
1108 raise ValueError(
"Invalid decay string")
1109 if decayDescriptor.getMother().getLabel() !=
'V0':
1112 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1116 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1119 def fillParticleListFromROE(decayString,
1122 sourceParticleListName='',
1127 Creates Particle object for each ROE of the desired type found in the
1128 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
1129 and fills the ParticleList. If useMissing is True, then the missing
1130 momentum is used instead of ROE.
1132 The type of the particles to be loaded is specified via the decayString module parameter.
1134 @param decayString specifies type of Particles and determines the name of the ParticleList.
1135 Source ROEs can be taken as a daughter list, for example:
1136 'B0:tagFromROE -> B0:signal'
1137 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1138 @param maskName Name of the ROE mask to use
1139 @param sourceParticleListName Use related ROEs to this particle list as a source
1140 @param useMissing Use missing momentum instead of ROE momentum
1141 @param writeOut whether RootOutput module should save the created ParticleList
1142 @param path modules are added to this path
1145 pload = register_module(
'ParticleLoader')
1146 pload.set_name(
'ParticleLoader_' + decayString)
1147 pload.param(
'decayStrings', [decayString])
1148 pload.param(
'writeOut', writeOut)
1149 pload.param(
'roeMaskName', maskName)
1150 pload.param(
'useMissing', useMissing)
1151 pload.param(
'sourceParticleListName', sourceParticleListName)
1152 pload.param(
'useROEs',
True)
1153 path.add_module(pload)
1155 from ROOT
import Belle2
1157 if not decayDescriptor.init(decayString):
1158 raise ValueError(
"Invalid decay string")
1162 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1165 def fillParticleListFromDummy(decayString,
1168 treatAsInvisible=True,
1172 Creates a ParticleList and fills it with dummy Particles. For self-conjugated Particles one dummy
1173 Particle is created, for Particles that are not self-conjugated one Particle and one anti-Particle is
1174 created. The four-momentum is set to zero.
1176 The type of the particles to be loaded is specified via the decayString module parameter.
1178 @param decayString specifies type of Particles and determines the name of the ParticleList
1179 @param mdstIndex sets the mdst index of Particles
1180 @param covMatrix sets the value of the diagonal covariance matrix of Particles
1181 @param treatAsInvisible whether treeFitter should treat the Particles as invisible
1182 @param writeOut whether RootOutput module should save the created ParticleList
1183 @param path modules are added to this path
1186 pload = register_module(
'ParticleLoader')
1187 pload.set_name(
'ParticleLoader_' + decayString)
1188 pload.param(
'decayStrings', [decayString])
1189 pload.param(
'useDummy',
True)
1190 pload.param(
'dummyMDSTIndex', mdstIndex)
1191 pload.param(
'dummyCovMatrix', covMatrix)
1192 pload.param(
'dummyTreatAsInvisible', treatAsInvisible)
1193 pload.param(
'writeOut', writeOut)
1194 path.add_module(pload)
1197 def fillParticleListFromMC(decayString,
1200 skipNonPrimaryDaughters=False,
1203 skipNonPrimary=False,
1206 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1207 loads them to the StoreArray<Particle> and fills the ParticleList.
1209 The type of the particles to be loaded is specified via the decayString module parameter.
1211 @param decayString specifies type of Particles and determines the name of the ParticleList
1212 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1213 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1214 sets mother-daughter relations
1215 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1216 @param writeOut whether RootOutput module should save the created ParticleList
1217 @param path modules are added to this path
1218 @param skipNonPrimary if true, skip non primary particle
1219 @param skipInitial if true, skip initial particles
1222 pload = register_module(
'ParticleLoader')
1223 pload.set_name(
'ParticleLoader_' + decayString)
1224 pload.param(
'decayStrings', [decayString])
1225 pload.param(
'addDaughters', addDaughters)
1226 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1227 pload.param(
'writeOut', writeOut)
1228 pload.param(
'useMCParticles',
True)
1229 pload.param(
'skipNonPrimary', skipNonPrimary)
1230 pload.param(
'skipInitial', skipInitial)
1231 path.add_module(pload)
1233 from ROOT
import Belle2
1235 if not decayDescriptor.init(decayString):
1236 raise ValueError(
"Invalid decay string")
1240 applyCuts(decayString, cut, path)
1243 def fillParticleListsFromMC(decayStringsWithCuts,
1245 skipNonPrimaryDaughters=False,
1248 skipNonPrimary=False,
1251 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1252 loads them to the StoreArray<Particle> and fills the ParticleLists.
1254 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
1257 .. code-block:: python
1259 kaons = ('K+:gen', '')
1260 pions = ('pi+:gen', 'pionID>0.1')
1261 fillParticleListsFromMC([kaons, pions], path=mypath)
1264 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not final state particle.
1265 Thus, when one reconstructs a particle from ``Lambda0``, that is created with
1266 ``addDaughters=True`` and ``skipNonPrimaryDaughters=True``, the particle always has ``isSignal==0``.
1267 Please set options for ``Lambda0`` to use MC-matching variables properly as follows,
1268 ``addDaughters=True`` and ``skipNonPrimaryDaughters=False``.
1270 @param decayString specifies type of Particles and determines the name of the ParticleList
1271 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1272 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1273 sets mother-daughter relations
1274 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1275 @param writeOut whether RootOutput module should save the created ParticleList
1276 @param path modules are added to this path
1277 @param skipNonPrimary if true, skip non primary particle
1278 @param skipInitial if true, skip initial particles
1281 pload = register_module(
'ParticleLoader')
1282 pload.set_name(
'ParticleLoader_' +
'PLists')
1283 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
1284 pload.param(
'addDaughters', addDaughters)
1285 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1286 pload.param(
'writeOut', writeOut)
1287 pload.param(
'useMCParticles',
True)
1288 pload.param(
'skipNonPrimary', skipNonPrimary)
1289 pload.param(
'skipInitial', skipInitial)
1290 path.add_module(pload)
1292 from ROOT
import Belle2
1294 for decayString, cut
in decayStringsWithCuts:
1295 if not decayDescriptor.init(decayString):
1296 raise ValueError(
"Invalid decay string")
1300 applyCuts(decayString, cut, path)
1303 def fillParticleListFromChargedCluster(outputParticleList,
1306 useOnlyMostEnergeticECLCluster=True,
1310 Creates the Particle object from ECLCluster and KLMCluster that are being matched with the Track of inputParticleList.
1312 @param outputParticleList The output ParticleList. Only neutral final state particles are supported.
1313 @param inputParticleList The input ParticleList that is required to have the relation to the Track object.
1314 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1315 @param useOnlyMostEnergeticECLCluster If True, only the most energetic ECLCluster among ones that are matched with the Track is
1316 used. If False, all matched ECLClusters are loaded. The default is True. Regardless of
1317 this option, the KLMCluster is loaded.
1318 @param writeOut whether RootOutput module should save the created ParticleList
1319 @param path modules are added to this path
1322 pload = register_module(
'ParticleLoader')
1323 pload.set_name(
'ParticleLoader_' + outputParticleList)
1325 pload.param(
'decayStrings', [outputParticleList])
1326 pload.param(
'sourceParticleListName', inputParticleList)
1327 pload.param(
'writeOut', writeOut)
1328 pload.param(
'loadChargedCluster',
True)
1329 pload.param(
'useOnlyMostEnergeticECLCluster', useOnlyMostEnergeticECLCluster)
1330 path.add_module(pload)
1334 applyCuts(outputParticleList, cut, path)
1337 def extractParticlesFromROE(particleLists,
1338 signalSideParticleList=None,
1343 Extract Particle objects that belong to the Rest-Of-Events and fill them into the ParticleLists.
1344 The types of the particles other than those specified by ``particleLists`` are not stored.
1345 If one creates a ROE with ``fillWithMostLikely=True`` via `buildRestOfEvent`, for example,
1346 one should create particleLists for not only ``pi+``, ``gamma``, ``K_L0`` but also other charged final state particles.
1348 When one calls the function in the main path, one has to set the argument ``signalSideParticleList`` and the signal side
1349 ParticleList must have only one candidate.
1351 .. code-block:: python
1353 buildRestOfEvent('B0:sig', fillWithMostLikely=True, path=mypath)
1355 roe_path = create_path()
1356 deadEndPath = create_path()
1357 signalSideParticleFilter('B0:sig', '', roe_path, deadEndPath)
1359 plists = ['%s:in_roe' % ptype for ptype in ['pi+', 'gamma', 'K_L0', 'K+', 'p+', 'e+', 'mu+']]
1360 extractParticlesFromROE(plists, maskName='all', path=roe_path)
1362 # one can analyze these ParticleLists in the roe_path
1364 mypath.for_each('RestOfEvent', 'RestOfEvents', roe_path)
1366 rankByLowest('B0:sig', 'deltaE', numBest=1, path=mypath)
1367 extractParticlesFromROE(plists, signalSideParticleList='B0:sig', maskName='all', path=mypath)
1369 # one can analyze these ParticleLists in the main path
1372 @param particleLists (str or list(str)) Name of output ParticleLists
1373 @param signalSideParticleList (str) Name of signal side ParticleList
1374 @param maskName (str) Name of the ROE mask to be applied on Particles
1375 @param writeOut (bool) whether RootOutput module should save the created ParticleList
1376 @param path (basf2.Path) modules are added to this path
1379 if isinstance(particleLists, str):
1380 particleLists = [particleLists]
1382 pext = register_module(
'ParticleExtractorFromROE')
1383 pext.set_name(
'ParticleExtractorFromROE_' +
'_'.join(particleLists))
1384 pext.param(
'outputListNames', particleLists)
1385 if signalSideParticleList
is not None:
1386 pext.param(
'signalSideParticleListName', signalSideParticleList)
1387 pext.param(
'maskName', maskName)
1388 pext.param(
'writeOut', writeOut)
1389 path.add_module(pext)
1392 def applyCuts(list_name, cut, path):
1394 Removes particle candidates from ``list_name`` that do not pass ``cut``
1395 (given selection criteria).
1398 require energetic pions safely inside the cdc
1400 .. code-block:: python
1402 applyCuts("pi+:mypions", "[E > 2] and thetaInCDCAcceptance", path=mypath)
1405 You must use square braces ``[`` and ``]`` for conditional statements.
1408 list_name (str): input ParticleList name
1409 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
1410 path (basf2.Path): modules are added to this path
1413 pselect = register_module(
'ParticleSelector')
1414 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
1415 pselect.param(
'decayString', list_name)
1416 pselect.param(
'cut', cut)
1417 path.add_module(pselect)
1420 def applyEventCuts(cut, path, metavariables=None):
1422 Removes events that do not pass the ``cut`` (given selection criteria).
1425 continuum events (in mc only) with more than 5 tracks
1427 .. code-block:: python
1429 applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1432 Only event-based variables are allowed in this function
1433 and only square brackets ``[`` and ``]`` for conditional statements.
1436 cut (str): Events that do not pass these selection criteria are skipped
1437 path (basf2.Path): modules are added to this path
1438 metavariables (list(str)): List of meta variables to be considered in decomposition of cut
1442 from variables
import variables
1444 def find_vars(t: tuple, var_list: list, meta_list: list) ->
None:
1445 """ Recursive helper function to find variable names """
1446 if not isinstance(t, tuple):
1448 if t[0] == b2parser.B2ExpressionParser.node_types[
'IdentifierNode']:
1451 if t[0] == b2parser.B2ExpressionParser.node_types[
'FunctionNode']:
1452 meta_list.append(list(t[1:]))
1455 if isinstance(i, tuple):
1456 find_vars(i, var_list, meta_list)
1458 def check_variable(var_list: list, metavar_ids: list) ->
None:
1459 for var_string
in var_list:
1461 orig_name = variables.resolveAlias(var_string)
1462 if orig_name != var_string:
1465 find_vars(
b2parser.parse(orig_name), var_list_temp, meta_list_temp)
1467 check_variable(var_list_temp, metavar_ids)
1468 check_meta(meta_list_temp, metavar_ids)
1471 var = variables.getVariable(var_string)
1472 if event_var_id
not in var.description:
1473 B2ERROR(f
'Variable {var_string} is not an event-based variable! "\
1474 "Please check your inputs to the applyEventCuts method!')
1476 def check_meta(meta_list: list, metavar_ids: list) ->
None:
1477 for meta_string_list
in meta_list:
1479 while meta_string_list[0]
in metavar_ids:
1481 meta_string_list.pop(0)
1482 for meta_string
in meta_string_list[0].split(
","):
1483 find_vars(
b2parser.parse(meta_string), var_list_temp, meta_string_list)
1484 if len(meta_string_list) > 0:
1485 meta_string_list.pop(0)
1486 if len(meta_string_list) == 0:
1488 if len(meta_string_list) > 1:
1489 meta_list += meta_string_list[1:]
1490 if isinstance(meta_string_list[0], list):
1491 meta_string_list = [element
for element
in meta_string_list[0]]
1493 check_variable(var_list_temp, metavar_ids)
1495 if len(meta_string_list) == 0:
1497 elif len(meta_string_list) == 1:
1498 var = variables.getVariable(meta_string_list[0])
1500 var = variables.getVariable(meta_string_list[0], meta_string_list[1].split(
","))
1502 if event_var_id
in var.description:
1505 B2ERROR(f
'Variable {var.name} is not an event-based variable! Please check your inputs to the applyEventCuts method!')
1507 event_var_id =
'[Eventbased]'
1508 metavar_ids = [
'formula',
'abs',
1512 'exp',
'log',
'log10',
1516 metavar_ids += metavariables
1520 find_vars(
b2parser.parse(cut), var_list=var_list, meta_list=meta_list)
1522 if len(var_list) == 0
and len(meta_list) == 0:
1523 B2WARNING(f
'Cut string "{cut}" has no variables for applyEventCuts helper function!')
1525 check_variable(var_list, metavar_ids)
1526 check_meta(meta_list, metavar_ids)
1528 eselect = register_module(
'VariableToReturnValue')
1529 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1530 path.add_module(eselect)
1531 empty_path = create_path()
1532 eselect.if_value(
'<1', empty_path)
1535 def reconstructDecay(decayString,
1540 candidate_limit=None,
1541 ignoreIfTooManyCandidates=True,
1542 chargeConjugation=True,
1543 allowChargeViolation=False):
1545 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1546 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1547 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1548 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1549 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1551 One can use an ``@``-sign to mark a particle as unspecified for inclusive analyses,
1552 e.g. in a DecayString: :code:`'@Xsd -> K+ pi-'`.
1554 .. seealso:: :ref:`Marker_of_unspecified_particle`
1557 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1558 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1559 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1561 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1562 This can be solved by manually randomising the lists before combining.
1566 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1567 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1569 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1570 (from the DecayString the mother and daughter ParticleLists are determined)
1571 @param cut created (mother) Particles are added to the mother ParticleList if they
1572 pass give cuts (in VariableManager style) and rejected otherwise
1573 @param dmID user specified decay mode identifier
1574 @param writeOut whether RootOutput module should save the created ParticleList
1575 @param path modules are added to this path
1576 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1577 the number of candidates is exceeded a Warning will be
1579 By default, all these candidates will be removed and event will be ignored.
1580 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1581 If no value is given the amount is limited to a sensible
1582 default. A value <=0 will disable this limit and can
1583 cause huge memory amounts so be careful.
1584 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1585 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1586 otherwise, number of candidates in candidate_limit is reconstructed.
1587 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1588 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1591 pmake = register_module(
'ParticleCombiner')
1592 pmake.set_name(
'ParticleCombiner_' + decayString)
1593 pmake.param(
'decayString', decayString)
1594 pmake.param(
'cut', cut)
1595 pmake.param(
'decayMode', dmID)
1596 pmake.param(
'writeOut', writeOut)
1597 if candidate_limit
is not None:
1598 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1599 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1600 pmake.param(
'chargeConjugation', chargeConjugation)
1601 pmake.param(
"allowChargeViolation", allowChargeViolation)
1602 path.add_module(pmake)
1605 def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1607 Creates a new Particle as the combination of all Particles from all
1608 provided inputParticleLists. However, each particle is used only once
1609 (even if duplicates are provided) and the combination has to pass the
1610 specified selection criteria to be saved in the newly created (mother)
1613 @param inputParticleLists List of input particle lists which are combined to the new Particle
1614 @param outputList Name of the particle combination created with this module
1615 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1616 these given cuts (in VariableManager style) and is rejected otherwise
1617 @param writeOut whether RootOutput module should save the created ParticleList
1618 @param path module is added to this path
1621 pmake = register_module(
'AllParticleCombiner')
1622 pmake.set_name(
'AllParticleCombiner_' + outputList)
1623 pmake.param(
'inputListNames', inputParticleLists)
1624 pmake.param(
'outputListName', outputList)
1625 pmake.param(
'cut', cut)
1626 pmake.param(
'writeOut', writeOut)
1627 path.add_module(pmake)
1630 def reconstructMissingKlongDecayExpert(decayString,
1637 Creates a list of K_L0's with their momentum determined from kinematic constraints of B->K_L0 + something else.
1639 @param decayString DecayString specifying what kind of the decay should be reconstructed
1640 (from the DecayString the mother and daughter ParticleLists are determined)
1641 @param cut Particles are added to the K_L0 ParticleList if they
1642 pass the given cuts (in VariableManager style) and rejected otherwise
1643 @param dmID user specified decay mode identifier
1644 @param writeOut whether RootOutput module should save the created ParticleList
1645 @param path modules are added to this path
1646 @param recoList suffix appended to original K_L0 ParticleList that identifies the newly created K_L0 list
1649 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1650 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1651 pcalc.param(
'decayString', decayString)
1652 pcalc.param(
'cut', cut)
1653 pcalc.param(
'decayMode', dmID)
1654 pcalc.param(
'writeOut', writeOut)
1655 pcalc.param(
'recoList', recoList)
1656 path.add_module(pcalc)
1658 rmake = register_module(
'KlongDecayReconstructorExpert')
1659 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1660 rmake.param(
'decayString', decayString)
1661 rmake.param(
'cut', cut)
1662 rmake.param(
'decayMode', dmID)
1663 rmake.param(
'writeOut', writeOut)
1664 rmake.param(
'recoList', recoList)
1665 path.add_module(rmake)
1668 def setBeamConstrainedMomentum(particleList, decayStringTarget, decayStringDaughters, path=None):
1670 Replace the four-momentum of the target Particle by p(beam) - p(selected daughters).
1671 The momentum of the mother Particle will not be changed.
1673 @param particleList mother Particlelist
1674 @param decayStringTarget DecayString specifying the target particle whose momentum
1676 @param decayStringDaughters DecayString specifying the daughter particles used to replace
1677 the momentum of the target particle by p(beam)-p(daughters)
1680 mod = register_module(
'ParticleMomentumUpdater')
1681 mod.set_name(
'ParticleMomentumUpdater' + particleList)
1682 mod.param(
'particleList', particleList)
1683 mod.param(
'decayStringTarget', decayStringTarget)
1684 mod.param(
'decayStringDaughters', decayStringDaughters)
1685 path.add_module(mod)
1688 def updateKlongKinematicsExpert(particleList,
1692 Calculates and updates the kinematics of B->K_L0 + something else with same method as
1693 `reconstructMissingKlongDecayExpert`. This helps to revert the kinematics after the vertex fitting.
1695 @param particleList input ParticleList of B meson that decays to K_L0 + X
1696 @param writeOut whether RootOutput module should save the ParticleList
1697 @param path modules are added to this path
1700 mod = register_module(
'KlongMomentumUpdaterExpert')
1701 mod.set_name(
'KlongMomentumUpdaterExpert_' + particleList)
1702 mod.param(
'listName', particleList)
1703 mod.param(
'writeOut', writeOut)
1704 path.add_module(mod)
1707 def replaceMass(replacerName, particleLists=None, pdgCode=22, path=None):
1709 replaces the mass of the particles inside the given particleLists
1710 with the invariant mass of the particle corresponding to the given pdgCode.
1712 @param particleLists new ParticleList filled with copied Particles
1713 @param pdgCode PDG code for mass reference
1714 @param path modules are added to this path
1717 if particleLists
is None:
1721 pmassupdater = register_module(
'ParticleMassUpdater')
1722 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1723 pmassupdater.param(
'particleLists', particleLists)
1724 pmassupdater.param(
'pdgCode', pdgCode)
1725 path.add_module(pmassupdater)
1728 def reconstructRecoil(decayString,
1733 candidate_limit=None,
1734 allowChargeViolation=False):
1736 Creates new Particles that recoil against the input particles.
1738 For example the decay string M -> D1 D2 D3 will:
1739 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1740 - Particles D1, D2, D3 will be appended as daughters to M
1741 - the 4-momentum of the mother Particle M is given by
1742 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1744 @param decayString DecayString specifying what kind of the decay should be reconstructed
1745 (from the DecayString the mother and daughter ParticleLists are determined)
1746 @param cut created (mother) Particles are added to the mother ParticleList if they
1747 pass give cuts (in VariableManager style) and rejected otherwise
1748 @param dmID user specified decay mode identifier
1749 @param writeOut whether RootOutput module should save the created ParticleList
1750 @param path modules are added to this path
1751 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1752 the number of candidates is exceeded no candidate will be
1753 reconstructed for that event and a Warning will be
1755 If no value is given the amount is limited to a sensible
1756 default. A value <=0 will disable this limit and can
1757 cause huge memory amounts so be careful.
1758 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1761 pmake = register_module(
'ParticleCombiner')
1762 pmake.set_name(
'ParticleCombiner_' + decayString)
1763 pmake.param(
'decayString', decayString)
1764 pmake.param(
'cut', cut)
1765 pmake.param(
'decayMode', dmID)
1766 pmake.param(
'writeOut', writeOut)
1767 pmake.param(
'recoilParticleType', 1)
1768 if candidate_limit
is not None:
1769 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1770 pmake.param(
'allowChargeViolation', allowChargeViolation)
1771 path.add_module(pmake)
1774 def reconstructRecoilDaughter(decayString,
1779 candidate_limit=None,
1780 allowChargeViolation=False):
1782 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1784 For example the decay string M -> D1 D2 D3 will:
1785 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1786 - Particles D1, D2, D3 will be appended as daughters to M
1787 - the 4-momentum of the mother Particle M is given by
1788 p(M) = p(D1) - Sum_i p(Di), where i>1
1790 @param decayString DecayString specifying what kind of the decay should be reconstructed
1791 (from the DecayString the mother and daughter ParticleLists are determined)
1792 @param cut created (mother) Particles are added to the mother ParticleList if they
1793 pass give cuts (in VariableManager style) and rejected otherwise
1794 @param dmID user specified decay mode identifier
1795 @param writeOut whether RootOutput module should save the created ParticleList
1796 @param path modules are added to this path
1797 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1798 the number of candidates is exceeded no candidate will be
1799 reconstructed for that event and a Warning will be
1801 If no value is given the amount is limited to a sensible
1802 default. A value <=0 will disable this limit and can
1803 cause huge memory amounts so be careful.
1804 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1805 daughter is actually the mother
1808 pmake = register_module(
'ParticleCombiner')
1809 pmake.set_name(
'ParticleCombiner_' + decayString)
1810 pmake.param(
'decayString', decayString)
1811 pmake.param(
'cut', cut)
1812 pmake.param(
'decayMode', dmID)
1813 pmake.param(
'writeOut', writeOut)
1814 pmake.param(
'recoilParticleType', 2)
1815 if candidate_limit
is not None:
1816 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1817 pmake.param(
'allowChargeViolation', allowChargeViolation)
1818 path.add_module(pmake)
1821 def rankByHighest(particleList,
1825 allowMultiRank=False,
1827 overwriteRank=False,
1830 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1831 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1832 The list is also sorted from best to worst candidate
1833 (each charge, e.g. B+/B-, separately).
1834 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1835 a non-zero value for 'numBest'.
1838 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1839 These variable names can become clunky, so it's probably a good idea to set an alias.
1840 For example if you rank your B candidates by momentum,
1844 rankByHighest("B0:myCandidates", "p", path=mypath)
1845 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1848 @param particleList The input ParticleList
1849 @param variable Variable to order Particles by.
1850 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1851 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1852 @param allowMultiRank If true, candidates with the same value will get the same rank.
1853 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1854 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1855 @param path modules are added to this path
1858 bcs = register_module(
'BestCandidateSelection')
1859 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1860 bcs.param(
'particleList', particleList)
1861 bcs.param(
'variable', variable)
1862 bcs.param(
'numBest', numBest)
1863 bcs.param(
'outputVariable', outputVariable)
1864 bcs.param(
'allowMultiRank', allowMultiRank)
1865 bcs.param(
'cut', cut)
1866 bcs.param(
'overwriteRank', overwriteRank)
1867 path.add_module(bcs)
1870 def rankByLowest(particleList,
1874 allowMultiRank=False,
1876 overwriteRank=False,
1879 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1880 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1881 The list is also sorted from best to worst candidate
1882 (each charge, e.g. B+/B-, separately).
1883 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1884 a non-zero value for 'numBest'.
1887 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1888 These variable names can become clunky, so it's probably a good idea to set an alias.
1889 For example if you rank your B candidates by :b2:var:`dM`,
1893 rankByLowest("B0:myCandidates", "dM", path=mypath)
1894 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1897 @param particleList The input ParticleList
1898 @param variable Variable to order Particles by.
1899 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1900 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1901 @param allowMultiRank If true, candidates with the same value will get the same rank.
1902 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1903 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1904 @param path modules are added to this path
1907 bcs = register_module(
'BestCandidateSelection')
1908 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1909 bcs.param(
'particleList', particleList)
1910 bcs.param(
'variable', variable)
1911 bcs.param(
'numBest', numBest)
1912 bcs.param(
'selectLowest',
True)
1913 bcs.param(
'allowMultiRank', allowMultiRank)
1914 bcs.param(
'outputVariable', outputVariable)
1915 bcs.param(
'cut', cut)
1916 bcs.param(
'overwriteRank', overwriteRank)
1917 path.add_module(bcs)
1920 def applyRandomCandidateSelection(particleList, path=None):
1922 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1923 This is done on a event-by-event basis.
1925 @param particleList ParticleList for which the random candidate selection should be applied
1926 @param path module is added to this path
1929 rcs = register_module(
'BestCandidateSelection')
1930 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1931 rcs.param(
'particleList', particleList)
1932 rcs.param(
'variable',
'random')
1933 rcs.param(
'selectLowest',
False)
1934 rcs.param(
'allowMultiRank',
False)
1935 rcs.param(
'numBest', 1)
1936 rcs.param(
'cut',
'')
1937 rcs.param(
'outputVariable',
'')
1938 path.add_module(rcs)
1943 Prints the contents of DataStore in the first event (or a specific event number or all events).
1944 Will list all objects and arrays (including size).
1947 The command line tool: ``b2file-size``.
1950 eventNumber (int): Print the datastore only for this event. The default
1951 (-1) prints only the first event, 0 means print for all events (can produce large output)
1952 path (basf2.Path): the PrintCollections module is added to this path
1955 This will print a lot of output if you print it for all events and process many events.
1959 printDS = register_module(
'PrintCollections')
1960 printDS.param(
'printForEvent', eventNumber)
1961 path.add_module(printDS)
1964 def printVariableValues(list_name, var_names, path):
1966 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
1968 @param list_name input ParticleList name
1969 @param var_names vector of variable names to be printed
1970 @param path modules are added to this path
1973 prlist = register_module(
'ParticlePrinter')
1974 prlist.set_name(
'ParticlePrinter_' + list_name)
1975 prlist.param(
'listName', list_name)
1976 prlist.param(
'fullPrint',
False)
1977 prlist.param(
'variables', var_names)
1978 path.add_module(prlist)
1981 def printList(list_name, full, path):
1983 Prints the size and executes Particle->print() (if full=True)
1984 method for all Particles in given ParticleList. For debugging purposes.
1986 @param list_name input ParticleList name
1987 @param full execute Particle->print() method for all Particles
1988 @param path modules are added to this path
1991 prlist = register_module(
'ParticlePrinter')
1992 prlist.set_name(
'ParticlePrinter_' + list_name)
1993 prlist.param(
'listName', list_name)
1994 prlist.param(
'fullPrint', full)
1995 path.add_module(prlist)
1998 def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None, basketsize=1600,
1999 signalSideParticleList="", filenameSuffix=""):
2001 Creates and fills a flat ntuple with the specified variables from the VariableManager.
2002 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
2003 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
2006 decayString (str): specifies type of Particles and determines the name of the ParticleList
2007 variables (list(str)): the list of variables (which must be registered in the VariableManager)
2008 treename (str): name of the ntuple tree
2009 filename (str): which is used to store the variables
2010 path (basf2.Path): the basf2 path where the analysis is processed
2011 basketsize (int): size of baskets in the output ntuple in bytes
2012 signalSideParticleList (str): The name of the signal-side ParticleList.
2013 Only valid if the module is called in a for_each loop over the RestOfEvent.
2014 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2016 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2019 output = register_module(
'VariablesToNtuple')
2020 output.set_name(
'VariablesToNtuple_' + decayString)
2021 output.param(
'particleList', decayString)
2022 output.param(
'variables', variables)
2023 output.param(
'fileName', filename)
2024 output.param(
'treeName', treename)
2025 output.param(
'basketSize', basketsize)
2026 output.param(
'signalSideParticleList', signalSideParticleList)
2027 output.param(
'fileNameSuffix', filenameSuffix)
2028 path.add_module(output)
2034 filename='ntuple.root',
2037 prefixDecayString=False,
2040 Creates and fills a flat ntuple with the specified variables from the VariableManager
2043 decayString (str): specifies type of Particles and determines the name of the ParticleList
2044 variables (list(tuple))): variables + binning which must be registered in the VariableManager
2045 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
2046 filename (str): which is used to store the variables
2047 path (basf2.Path): the basf2 path where the analysis is processed
2048 directory (str): directory inside the output file where the histograms should be saved.
2049 Useful if you want to have different histograms in the same file to separate them.
2050 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
2051 programmatic naming of the structure in the file.
2052 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2054 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2057 if variables_2d
is None:
2059 output = register_module(
'VariablesToHistogram')
2060 output.set_name(
'VariablesToHistogram_' + decayString)
2061 output.param(
'particleList', decayString)
2062 output.param(
'variables', variables)
2063 output.param(
'variables_2d', variables_2d)
2064 output.param(
'fileName', filename)
2065 output.param(
'fileNameSuffix', filenameSuffix)
2066 if directory
is not None or prefixDecayString:
2067 if directory
is None:
2069 if prefixDecayString:
2070 directory = decayString +
"_" + directory
2071 output.param(
"directory", directory)
2072 path.add_module(output)
2077 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
2078 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
2081 particleList (str): The input ParticleList
2082 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2083 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2084 An existing extra info with the same name will be overwritten if the new
2085 value is lower / will never be overwritten / will be overwritten if the
2086 new value is higher / will always be overwritten (option = -1/0/1/2).
2087 path (basf2.Path): modules are added to this path
2090 mod = register_module(
'VariablesToExtraInfo')
2091 mod.set_name(
'VariablesToExtraInfo_' + particleList)
2092 mod.param(
'particleList', particleList)
2093 mod.param(
'variables', variables)
2094 mod.param(
'overwrite', option)
2095 path.add_module(mod)
2098 def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
2100 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
2101 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
2102 to specified daughter particle.
2105 particleList (str): The input ParticleList
2106 decayString (str): Decay string that specifies to which daughter the extra info should be appended
2107 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2108 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2109 An existing extra info with the same name will be overwritten if the new
2110 value is lower / will never be overwritten / will be overwritten if the
2111 new value is higher / will always be overwritten (option = -1/0/1/2).
2112 path (basf2.Path): modules are added to this path
2115 mod = register_module(
'VariablesToExtraInfo')
2116 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
2117 mod.param(
'particleList', particleList)
2118 mod.param(
'decayString', decayString)
2119 mod.param(
'variables', variables)
2120 mod.param(
'overwrite', option)
2121 path.add_module(mod)
2124 def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
2126 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
2127 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
2130 When the function is called first time not in the main path but in a sub-path e.g. ``roe_path``,
2131 the eventExtraInfo cannot be accessed from the main path because of the shorter lifetime of the event-extra-info field.
2132 If one wants to call the function in a sub-path, one has to call the function in the main path beforehand.
2135 particleList (str): The input ParticleList
2136 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2137 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2138 An existing extra info with the same name will be overwritten if the new
2139 value is lower / will never be overwritten / will be overwritten if the
2140 new value is higher / will always be overwritten (option = -1/0/1/2).
2141 path (basf2.Path): modules are added to this path
2144 mod = register_module(
'VariablesToEventExtraInfo')
2145 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
2146 mod.param(
'particleList', particleList)
2147 mod.param(
'variables', variables)
2148 mod.param(
'overwrite', option)
2149 path.add_module(mod)
2152 def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
2154 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
2155 particle) as an extra info to the particle related to current ROE.
2156 Should be used only in the for_each roe path.
2159 particleList (str): The input ParticleList
2160 varToExtraInfo (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2161 path (basf2.Path): modules are added to this path
2164 mod = register_module(
'SignalSideVariablesToExtraInfo')
2165 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
2166 mod.param(
'particleListName', particleList)
2167 mod.param(
'variableToExtraInfo', varToExtraInfo)
2168 path.add_module(mod)
2171 def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
2173 Define and blind a signal region.
2174 Per default, the defined signal region is cut out if ran on data.
2175 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
2179 .. code-block:: python
2181 ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
2182 ma.signalRegion("B+:sig",
2183 "Mbc>5.27 and abs(deltaE)<0.2",
2186 ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
2189 particleList (str): The input ParticleList
2190 cut (str): Cut string describing the signal region
2191 path (basf2.Path):: Modules are added to this path
2192 name (str): Name of the Signal region in the variable manager
2193 blind_data (bool): Automatically exclude signal region from data
2197 from variables
import variables
2198 mod = register_module(
'VariablesToExtraInfo')
2199 mod.set_name(f
'{name}_' + particleList)
2200 mod.param(
'particleList', particleList)
2201 mod.param(
'variables', {f
"passesCut({cut})": name})
2202 variables.addAlias(name, f
"extraInfo({name})")
2203 path.add_module(mod)
2207 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
2210 def removeExtraInfo(particleLists=None, removeEventExtraInfo=False, path=None):
2212 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
2215 if particleLists
is None:
2217 mod = register_module(
'ExtraInfoRemover')
2218 mod.param(
'particleLists', particleLists)
2219 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
2220 path.add_module(mod)
2223 def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
2225 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2226 to the particle from the input ParticleList. Additional selection criteria can be applied.
2227 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2228 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2229 suggests should be empty and its purpose is to end the execution of for_each roe path for
2230 the current ROE object.
2232 @param particleList The input ParticleList
2233 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2234 @param for_each roe path in which this filter is executed
2235 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2238 mod = register_module(
'SignalSideParticleFilter')
2239 mod.set_name(
'SigSideParticleFilter_' + particleList)
2240 mod.param(
'particleLists', [particleList])
2241 mod.param(
'selection', selection)
2242 roe_path.add_module(mod)
2243 mod.if_false(deadEndPath)
2246 def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
2248 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2249 to the particle from the input ParticleList. Additional selection criteria can be applied.
2250 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2251 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2252 suggests should be empty and its purpose is to end the execution of for_each roe path for
2253 the current ROE object.
2255 @param particleLists The input ParticleLists
2256 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2257 @param for_each roe path in which this filter is executed
2258 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2261 mod = register_module(
'SignalSideParticleFilter')
2262 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
2263 mod.param(
'particleLists', particleLists)
2264 mod.param(
'selection', selection)
2265 roe_path.add_module(mod)
2266 mod.if_false(deadEndPath)
2275 chargeConjugation=True,
2278 Finds and creates a ``ParticleList`` from given decay string.
2279 ``ParticleList`` of daughters with sub-decay is created.
2281 Only the particles made from MCParticle, which can be loaded by `fillParticleListFromMC`, are accepted as daughters.
2283 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
2284 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
2287 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
2288 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
2289 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
2292 It is recommended to use only primary particles as daughter particles unless you want to explicitly study the secondary
2293 particles. The behavior of MC-matching for secondary particles from a stable particle decay is not guaranteed.
2294 Please consider to use `fillParticleListFromMC` with ``skipNonPrimary=True`` to load daughter particles.
2295 Moreover, it is recommended to load ``K_S0`` and ``Lambda0`` directly from MCParticle by `fillParticleListFromMC` rather
2296 than reconstructing from two pions or a proton-pion pair, because their direct daughters can be the secondary particle.
2299 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
2300 (from the DecayString the mother and daughter ParticleLists are determined)
2301 @param cut created (mother) Particles are added to the mother ParticleList if they
2302 pass given cuts (in VariableManager style) and rejected otherwise
2303 isSignal==1 is always required by default.
2304 @param dmID user specified decay mode identifier
2305 @param writeOut whether RootOutput module should save the created ParticleList
2306 @param path modules are added to this path
2307 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
2310 pmake = register_module(
'ParticleCombinerFromMC')
2311 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
2312 pmake.param(
'decayString', decayString)
2313 pmake.param(
'cut', cut)
2314 pmake.param(
'decayMode', dmID)
2315 pmake.param(
'writeOut', writeOut)
2316 pmake.param(
'chargeConjugation', chargeConjugation)
2317 path.add_module(pmake)
2324 appendAllDaughters=False,
2325 skipNonPrimaryDaughters=True,
2329 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
2330 The decay string is required to describe correctly what you want.
2331 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
2333 The output particles has only the daughter particles written in the given decay string, if
2334 ``appendAllDaughters=False`` (default). If ``appendAllDaughters=True``, all daughters of the matched MCParticle are
2335 appended in the order defined at the MCParticle level. For example,
2337 .. code-block:: python
2339 findMCDecay('B0:Xee', 'B0 -> e+ e- ... ?gamma', appendAllDaughters=False, path=mypath)
2341 The output ParticleList ``B0:Xee`` will match the inclusive ``B0 -> e+ e-`` decays (but neutrinos are not included),
2342 in both cases of ``appendAllDaughters`` is false and true.
2343 If the ``appendAllDaughters=False`` as above example, the ``B0:Xee`` has only two electrons as daughters.
2344 While, if ``appendAllDaughters=True``, all daughters of the matched MCParticles are appended. When the truth decay mode of
2345 the MCParticle is ``B0 -> [K*0 -> K+ pi-] [J/psi -> e+ e-]``, the first daughter of ``B0:Xee`` is ``K*0`` and ``e+``
2346 will be the first daughter of second daughter of ``B0:Xee``.
2348 The option ``skipNonPrimaryDaughters`` only has an effect if ``appendAllDaughters=True``. If ``skipNonPrimaryDaughters=True``,
2349 all primary daughters are appended but the secondary particles are not.
2352 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not a final state particle.
2353 In order for the MCMatching to work properly, the daughters of ``Lambda0`` are appended to
2354 ``Lambda0`` regardless of the value of the option ``skipNonPrimaryDaughters``.
2357 @param list_name The output particle list name
2358 @param decay The decay string which you want
2359 @param writeOut Whether `RootOutput` module should save the created ``outputList``
2360 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
2361 @param appendAllDaughters if true, not only the daughters described in the decay string but all daughters are appended
2362 @param path modules are added to this path
2365 decayfinder = register_module(
'MCDecayFinder')
2366 decayfinder.set_name(
'MCDecayFinder_' + list_name)
2367 decayfinder.param(
'listName', list_name)
2368 decayfinder.param(
'decayString', decay)
2369 decayfinder.param(
'appendAllDaughters', appendAllDaughters)
2370 decayfinder.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
2371 decayfinder.param(
'writeOut', writeOut)
2372 path.add_module(decayfinder)
2375 def summaryOfLists(particleLists, outputFile=None, path=None):
2377 Prints out Particle statistics at the end of the job: number of events with at
2378 least one candidate, average number of candidates per event, etc.
2379 If an output file name is provided the statistics is also dumped into a json file with that name.
2381 @param particleLists list of input ParticleLists
2382 @param outputFile output file name (not created by default)
2385 particleStats = register_module(
'ParticleStats')
2386 particleStats.param(
'particleLists', particleLists)
2387 if outputFile
is not None:
2388 particleStats.param(
'outputFile', outputFile)
2389 path.add_module(particleStats)
2392 def matchMCTruth(list_name, path):
2394 Performs MC matching (sets relation Particle->MCParticle) for
2395 all particles (and its (grand)^N-daughter particles) in the specified
2398 @param list_name name of the input ParticleList
2399 @param path modules are added to this path
2402 mcMatch = register_module(
'MCMatcherParticles')
2403 mcMatch.set_name(
'MCMatch_' + list_name)
2404 mcMatch.param(
'listName', list_name)
2405 path.add_module(mcMatch)
2408 def looseMCTruth(list_name, path):
2410 Performs loose MC matching for all particles in the specified
2412 The difference between loose and normal mc matching algorithm is that
2413 the loose algorithm will find the common mother of the majority of daughter
2414 particles while the normal algorithm finds the common mother of all daughters.
2415 The results of loose mc matching algorithm are stored to the following extraInfo
2418 - looseMCMotherPDG: PDG code of most common mother
2419 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
2420 - looseMCWrongDaughterN: number of daughters that don't originate from the most common mother
2421 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from the most common mother (only if
2422 looseMCWrongDaughterN = 1)
2423 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background Particle
2425 @param list_name name of the input ParticleList
2426 @param path modules are added to this path
2429 mcMatch = register_module(
'MCMatcherParticles')
2430 mcMatch.set_name(
'LooseMCMatch_' + list_name)
2431 mcMatch.param(
'listName', list_name)
2432 mcMatch.param(
'looseMCMatching',
True)
2433 path.add_module(mcMatch)
2436 def buildRestOfEvent(target_list_name, inputParticlelists=None,
2437 fillWithMostLikely=True,
2438 chargedPIDPriors=None, path=None):
2440 Creates for each Particle in the given ParticleList a RestOfEvent
2441 dataobject and makes basf2 relation between them. User can provide additional
2442 particle lists with a different particle hypothesis like ['K+:good, e+:good'], etc.
2444 @param target_list_name name of the input ParticleList
2445 @param inputParticlelists list of user-defined input particle list names, which serve
2446 as source of particles to build the ROE, the FSP particles from
2447 target_list_name are automatically excluded from the ROE object
2448 @param fillWithMostLikely By default the module uses the most likely particle mass hypothesis for charged particles
2449 based on the PID likelihood. Turn this behavior off if you want to configure your own
2450 input particle lists.
2451 @param chargedPIDPriors The prior PID fractions, that are used to regulate the
2452 amount of certain charged particle species, should be a list of
2453 six floats if not None. The order of particle types is
2454 the following: [e-, mu-, pi-, K-, p+, d+]
2455 @param path modules are added to this path
2458 if inputParticlelists
is None:
2459 inputParticlelists = []
2460 fillParticleList(
'pi+:all',
'', path=path)
2461 if fillWithMostLikely:
2462 from stdCharged
import stdMostLikely
2463 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
2464 inputParticlelists = [
'%s:mostlikely_roe' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
2467 fillParticleList(
'gamma:all',
'', path=path)
2468 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
2469 inputParticlelists += [
'pi+:all',
'gamma:all',
'K_L0:roe_default']
2471 inputParticlelists += [
'pi+:all',
'gamma:mdst']
2472 roeBuilder = register_module(
'RestOfEventBuilder')
2473 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
2474 roeBuilder.param(
'particleList', target_list_name)
2475 roeBuilder.param(
'particleListsInput', inputParticlelists)
2476 roeBuilder.param(
'mostLikely', fillWithMostLikely)
2477 path.add_module(roeBuilder)
2480 def buildNestedRestOfEvent(target_list_name, maskName='all', path=None):
2482 Creates for each Particle in the given ParticleList a RestOfEvent
2483 @param target_list_name name of the input ParticleList
2484 @param mask_name name of the ROEMask to be used
2485 @param path modules are added to this path
2488 roeBuilder = register_module(
'RestOfEventBuilder')
2489 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
2490 roeBuilder.param(
'particleList', target_list_name)
2491 roeBuilder.param(
'nestedROEMask', maskName)
2492 roeBuilder.param(
'createNestedROE',
True)
2493 path.add_module(roeBuilder)
2496 def buildRestOfEventFromMC(target_list_name, inputParticlelists=None, path=None):
2498 Creates for each Particle in the given ParticleList a RestOfEvent
2499 @param target_list_name name of the input ParticleList
2500 @param inputParticlelists list of input particle list names, which serve
2501 as a source of particles to build ROE, the FSP particles from
2502 target_list_name are excluded from ROE object
2503 @param path modules are added to this path
2506 if inputParticlelists
is None:
2507 inputParticlelists = []
2508 if (len(inputParticlelists) == 0):
2512 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
2513 'n0',
'nu_e',
'nu_mu',
'nu_tau',
2516 fillParticleListFromMC(
"%s:roe_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
2517 True,
True, path=path)
2518 inputParticlelists += [
"%s:roe_default_gen" % t]
2519 roeBuilder = register_module(
'RestOfEventBuilder')
2520 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
2521 roeBuilder.param(
'particleList', target_list_name)
2522 roeBuilder.param(
'particleListsInput', inputParticlelists)
2523 roeBuilder.param(
'fromMC',
True)
2524 path.add_module(roeBuilder)
2527 def appendROEMask(list_name,
2530 eclClusterSelection,
2531 klmClusterSelection='',
2534 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2535 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
2537 - append a ROE mask with all tracks in ROE coming from the IP region
2539 .. code-block:: python
2541 appendROEMask('B+:sig', 'IPtracks', '[dr < 2] and [abs(dz) < 5]', path=mypath)
2543 - append a ROE mask with only ECL-based particles that pass as good photon candidates
2545 .. code-block:: python
2547 goodPhotons = 'inCDCAcceptance and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
2548 appendROEMask('B+:sig', 'goodROEGamma', '', goodPhotons, path=mypath)
2551 @param list_name name of the input ParticleList
2552 @param mask_name name of the appended ROEMask
2553 @param trackSelection decay string for the track-based particles in ROE
2554 @param eclClusterSelection decay string for the ECL-based particles in ROE
2555 @param klmClusterSelection decay string for the KLM-based particles in ROE
2556 @param path modules are added to this path
2559 roeMask = register_module(
'RestOfEventInterpreter')
2560 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2561 roeMask.param(
'particleList', list_name)
2562 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2563 path.add_module(roeMask)
2566 def appendROEMasks(list_name, mask_tuples, path=None):
2568 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2569 selection criteria for track-, ECL- and KLM-based particles which will be used by ROE variables.
2571 The multiple ROE masks with their own selection criteria are specified
2572 via list of tuples (mask_name, trackParticleSelection, eclParticleSelection, klmParticleSelection) or
2573 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
2575 - Example for two tuples, one with and one without fractions
2577 .. code-block:: python
2579 ipTracks = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', '')
2580 goodPhotons = 'inCDCAcceptance and [clusterErrorTiming < 1e6] and [clusterE1E9 > 0.4 or E > 0.075]'
2581 goodROEGamma = ('ROESel', '[dr < 2] and [abs(dz) < 5]', goodPhotons, '')
2582 goodROEKLM = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', 'nKLMClusterTrackMatches == 0')
2583 appendROEMasks('B+:sig', [ipTracks, goodROEGamma, goodROEKLM], path=mypath)
2585 @param list_name name of the input ParticleList
2586 @param mask_tuples array of ROEMask list tuples to be appended
2587 @param path modules are added to this path
2590 compatible_masks = []
2591 for mask
in mask_tuples:
2594 compatible_masks += [(*mask,
'')]
2596 compatible_masks += [mask]
2597 roeMask = register_module(
'RestOfEventInterpreter')
2598 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2599 roeMask.param(
'particleList', list_name)
2600 roeMask.param(
'ROEMasks', compatible_masks)
2601 path.add_module(roeMask)
2604 def updateROEMask(list_name,
2607 eclClusterSelection='',
2608 klmClusterSelection='',
2611 Update an existing ROE mask by applying additional selection cuts for
2612 tracks and/or clusters.
2614 See function `appendROEMask`!
2616 @param list_name name of the input ParticleList
2617 @param mask_name name of the ROEMask to update
2618 @param trackSelection decay string for the track-based particles in ROE
2619 @param eclClusterSelection decay string for the ECL-based particles in ROE
2620 @param klmClusterSelection decay string for the KLM-based particles in ROE
2621 @param path modules are added to this path
2624 roeMask = register_module(
'RestOfEventInterpreter')
2625 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2626 roeMask.param(
'particleList', list_name)
2627 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2628 roeMask.param(
'update',
True)
2629 path.add_module(roeMask)
2632 def updateROEMasks(list_name, mask_tuples, path):
2634 Update existing ROE masks by applying additional selection cuts for tracks
2637 The multiple ROE masks with their own selection criteria are specified
2638 via list tuples (mask_name, trackSelection, eclClusterSelection, klmClusterSelection)
2640 See function `appendROEMasks`!
2642 @param list_name name of the input ParticleList
2643 @param mask_tuples array of ROEMask list tuples to be appended
2644 @param path modules are added to this path
2647 compatible_masks = []
2648 for mask
in mask_tuples:
2651 compatible_masks += [(*mask,
'')]
2653 compatible_masks += [mask]
2655 roeMask = register_module(
'RestOfEventInterpreter')
2656 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2657 roeMask.param(
'particleList', list_name)
2658 roeMask.param(
'ROEMasks', compatible_masks)
2659 roeMask.param(
'update',
True)
2660 path.add_module(roeMask)
2663 def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2665 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2666 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2667 This function should be executed only in the for_each roe path for the current ROE object.
2669 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2670 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2671 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2672 pion particle list (e.g. 'pi+:someLabel').
2674 Updating a non-existing mask will create a new one.
2676 - keep only those tracks that were used in provided particle list
2678 .. code-block:: python
2680 keepInROEMasks('pi+:goodTracks', 'mask', '', path=mypath)
2682 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2684 .. code-block:: python
2686 keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1', path=mypath)
2689 @param list_name name of the input ParticleList
2690 @param mask_names array of ROEMasks to be updated
2691 @param cut_string decay string with which the mask will be updated
2692 @param path modules are added to this path
2695 updateMask = register_module(
'RestOfEventUpdater')
2696 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2697 updateMask.param(
'particleList', list_name)
2698 updateMask.param(
'updateMasks', mask_names)
2699 updateMask.param(
'cutString', cut_string)
2700 updateMask.param(
'discard',
False)
2701 path.add_module(updateMask)
2704 def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2706 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2707 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2708 This function should be executed only in the for_each roe path for the current ROE object.
2710 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2711 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2712 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2713 pion particle list (e.g. 'pi+:someLabel').
2715 Updating a non-existing mask will create a new one.
2717 - discard tracks that were used in provided particle list
2719 .. code-block:: python
2721 discardFromROEMasks('pi+:badTracks', 'mask', '', path=mypath)
2723 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2725 .. code-block:: python
2727 discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1', path=mypath)
2730 @param list_name name of the input ParticleList
2731 @param mask_names array of ROEMasks to be updated
2732 @param cut_string decay string with which the mask will be updated
2733 @param path modules are added to this path
2736 updateMask = register_module(
'RestOfEventUpdater')
2737 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2738 updateMask.param(
'particleList', list_name)
2739 updateMask.param(
'updateMasks', mask_names)
2740 updateMask.param(
'cutString', cut_string)
2741 updateMask.param(
'discard',
True)
2742 path.add_module(updateMask)
2745 def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2747 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2748 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2749 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2750 passing it can be applied.
2752 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2753 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2755 Updating a non-existing mask will create a new one.
2757 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2759 .. code-block:: python
2761 optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550', path=mypath)
2763 @param list_name name of the input ParticleList
2764 @param mask_names array of ROEMasks to be updated
2765 @param cut_string decay string with which the mask will be updated
2766 @param path modules are added to this path
2769 updateMask = register_module(
'RestOfEventUpdater')
2770 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2771 updateMask.param(
'particleList', list_name)
2772 updateMask.param(
'updateMasks', mask_names)
2773 updateMask.param(
'cutString', cut_string)
2774 path.add_module(updateMask)
2777 def updateROEUsingV0Lists(target_particle_list, mask_names, default_cleanup=True, selection_cuts=None,
2778 apply_mass_fit=False, fitter='treefit', path=None):
2780 This function creates V0 particle lists (photons, :math:`K^0_S` and :math:`\\Lambda^0`)
2781 and it uses V0 candidates to update the Rest Of Event, which is associated to the target particle list.
2782 It is possible to apply a standard or customized selection and mass fit to the V0 candidates.
2785 @param target_particle_list name of the input ParticleList
2786 @param mask_names array of ROE masks to be applied
2787 @param default_cleanup if True, predefined cuts will be applied on the V0 lists
2788 @param selection_cuts a single string of selection cuts or tuple of three strings (photon_cuts, K_S0_cuts, Lambda0_cuts),
2789 which will be applied to the V0 lists. These cuts will have a priority over the default ones.
2790 @param apply_mass_fit if True, a mass fit will be applied to the V0 particles
2791 @param fitter string, that represent a fitter choice: "treefit" for TreeFitter and "kfit" for KFit
2792 @param path modules are added to this path
2795 roe_path = create_path()
2796 deadEndPath = create_path()
2797 signalSideParticleFilter(target_particle_list,
'', roe_path, deadEndPath)
2799 if (default_cleanup
and selection_cuts
is None):
2800 B2INFO(
"Using default cleanup in updateROEUsingV0Lists.")
2801 selection_cuts =
'abs(dM) < 0.1 '
2802 selection_cuts +=
'and daughter(0,particleID) > 0.2 and daughter(1,particleID) > 0.2 '
2803 selection_cuts +=
'and daughter(0,thetaInCDCAcceptance) and daughter(1,thetaInCDCAcceptance)'
2804 if (selection_cuts
is None or selection_cuts ==
''):
2805 B2INFO(
"No cleanup in updateROEUsingV0Lists.")
2806 selection_cuts = (
'True',
'True',
'True')
2807 if (isinstance(selection_cuts, str)):
2808 selection_cuts = (selection_cuts, selection_cuts, selection_cuts)
2810 roe_cuts =
'isInRestOfEvent > 0'
2811 fillConvertedPhotonsList(
'gamma:v0_roe -> e+ e-', f
'{selection_cuts[0]} and {roe_cuts}',
2813 fillParticleList(
'K_S0:v0_roe -> pi+ pi-', f
'{selection_cuts[1]} and {roe_cuts}',
2815 fillParticleList(
'Lambda0:v0_roe -> p+ pi-', f
'{selection_cuts[2]} and {roe_cuts}',
2817 fitter = fitter.lower()
2818 if (fitter !=
'treefit' and fitter !=
'kfit'):
2819 B2WARNING(
'Argument "fitter" in updateROEUsingV0Lists has only "treefit" and "kfit" options, '
2820 f
'but "{fitter}" was provided! TreeFitter will be used instead.')
2822 from vertex
import kFit, treeFit
2823 for v0
in [
'gamma:v0_roe',
'K_S0:v0_roe',
'Lambda0:v0_roe']:
2824 if (apply_mass_fit
and fitter ==
'kfit'):
2825 kFit(v0, conf_level=0.0, fit_type=
'massvertex', path=roe_path)
2826 if (apply_mass_fit
and fitter ==
'treefit'):
2827 treeFit(v0, conf_level=0.0, massConstraint=[v0.split(
':')[0]], path=roe_path)
2828 optimizeROEWithV0(v0, mask_names,
'', path=roe_path)
2829 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2832 def printROEInfo(mask_names=None, full_print=False,
2833 unpackComposites=True, path=None):
2835 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2836 It prints out basic ROE object info.
2838 If mask names are provided, specific information for those masks will be printed out.
2840 It is also possible to print out all particles in a given mask if the
2841 'full_print' is set to True.
2843 @param mask_names array of ROEMask names for printing out info
2844 @param unpackComposites if true, replace composite particles by their daughters
2845 @param full_print print out particles in mask
2846 @param path modules are added to this path
2849 if mask_names
is None:
2851 printMask = register_module(
'RestOfEventPrinter')
2852 printMask.set_name(
'RestOfEventPrinter')
2853 printMask.param(
'maskNames', mask_names)
2854 printMask.param(
'fullPrint', full_print)
2855 printMask.param(
'unpackComposites', unpackComposites)
2856 path.add_module(printMask)
2859 def buildContinuumSuppression(list_name, roe_mask, path):
2861 Creates for each Particle in the given ParticleList a ContinuumSuppression
2862 dataobject and makes basf2 relation between them.
2864 :param list_name: name of the input ParticleList
2865 :param roe_mask: name of the ROE mask
2866 :param path: modules are added to this path
2869 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2870 qqBuilder.set_name(
'QQBuilder_' + list_name)
2871 qqBuilder.param(
'particleList', list_name)
2872 qqBuilder.param(
'ROEMask', roe_mask)
2873 path.add_module(qqBuilder)
2878 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2879 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2881 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2882 @param path modules are added to this path
2885 mod = register_module(
'RemoveParticlesNotInLists')
2886 mod.param(
'particleLists', lists_to_keep)
2887 path.add_module(mod)
2890 def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2892 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2894 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2895 @param bsig_list_name Name of the Bsig ParticleList
2896 @param btag_list_name Name of the Bsig ParticleList
2897 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2900 btag = register_module(
'InclusiveBtagReconstruction')
2901 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2902 btag.param(
'upsilonListName', upsilon_list_name)
2903 btag.param(
'bsigListName', bsig_list_name)
2904 btag.param(
'btagListName', btag_list_name)
2905 btag.param(
'inputListsNames', input_lists_names)
2906 path.add_module(btag)
2909 def selectDaughters(particle_list_name, decay_string, path):
2911 Redefine the Daughters of a particle: select from decayString
2913 @param particle_list_name input particle list
2914 @param decay_string for selecting the Daughters to be preserved
2917 seld = register_module(
'SelectDaughters')
2918 seld.set_name(
'SelectDaughters_' + particle_list_name)
2919 seld.param(
'listName', particle_list_name)
2920 seld.param(
'decayString', decay_string)
2921 path.add_module(seld)
2924 def markDuplicate(particleList, prioritiseV0, path):
2926 Call DuplicateVertexMarker to find duplicate particles in a list and
2927 flag the ones that should be kept
2929 @param particleList input particle list
2930 @param prioritiseV0 if true, give V0s a higher priority
2933 markdup = register_module(
'DuplicateVertexMarker')
2934 markdup.param(
'particleList', particleList)
2935 markdup.param(
'prioritiseV0', prioritiseV0)
2936 path.add_module(markdup)
2939 PI0ETAVETO_COUNTER = 0
2942 def oldwritePi0EtaVeto(
2945 workingDirectory='.',
2946 pi0vetoname='Pi0_Prob',
2947 etavetoname='Eta_Prob',
2953 Give pi0/eta probability for hard photon.
2955 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.
2957 The current default weight files are optimised using MC9.
2958 The input variables are as below. Aliases are set to some variables during training.
2960 * M: pi0/eta candidates Invariant mass
2961 * lowE: soft photon energy in lab frame
2962 * cTheta: soft photon ECL cluster's polar angle
2963 * Zmva: soft photon output of MVA using Zernike moments of the cluster
2964 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2966 If you don't have weight files in your workingDirectory,
2967 these files are downloaded from database to your workingDirectory automatically.
2968 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
2969 about how to use this function.
2972 Please don't use following ParticleList names elsewhere:
2974 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
2975 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
2977 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
2979 @param particleList The input ParticleList
2980 @param decayString specify Particle to be added to the ParticleList
2981 @param workingDirectory The weight file directory
2982 @param downloadFlag whether download default weight files or not
2983 @param pi0vetoname extraInfo name of pi0 probability
2984 @param etavetoname extraInfo name of eta probability
2985 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2986 @param path modules are added to this path
2991 B2ERROR(
"The old pi0 / eta veto is not suitable for Belle analyses.")
2996 global PI0ETAVETO_COUNTER
2998 if PI0ETAVETO_COUNTER == 0:
2999 from variables
import variables
3000 variables.addAlias(
'lowE',
'daughter(1,E)')
3001 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
3002 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
3003 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
3004 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
3005 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
3007 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
3009 roe_path = create_path()
3011 deadEndPath = create_path()
3013 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3015 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
3017 pi0softname =
'gamma:PI0SOFT'
3018 etasoftname =
'gamma:ETASOFT'
3019 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
3020 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
3024 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
3026 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
3029 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
3031 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
3033 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
3034 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
3036 if not os.path.isdir(workingDirectory):
3037 os.mkdir(workingDirectory)
3038 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
3040 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
3042 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
3043 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
3045 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
3047 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
3048 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
3050 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
3051 identifier=workingDirectory +
'/pi0veto.root')
3052 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
3053 identifier=workingDirectory +
'/etaveto.root')
3055 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
3056 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
3058 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
3059 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
3061 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3064 def writePi0EtaVeto(
3071 hardParticle='gamma',
3072 pi0PayloadNameOverride=None,
3073 pi0SoftPhotonCutOverride=None,
3074 etaPayloadNameOverride=None,
3075 etaSoftPhotonCutOverride=None
3078 Give pi0/eta probability for hard photon.
3080 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.
3082 The current default weight files are optimised using MC12.
3084 The input variables of the mva training are:
3086 * M: pi0/eta candidates Invariant mass
3087 * daughter(1,E): soft photon energy in lab frame
3088 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3089 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3090 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
3091 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
3092 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
3093 * cosHelicityAngleMomentum: pi0/eta candidates cosHelicityAngleMomentum
3095 The following strings are available for mode:
3097 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
3098 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
3099 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
3100 * both: tight energy cut and clusterNHits cut are applied to soft photon
3102 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
3103 `pi0Prob`/`etaProb`. Otherwise, it is available as '{Pi0, Eta}ProbOrigin', '{Pi0, Eta}ProbTightEnergyThreshold', '{Pi0,
3104 Eta}ProbLargeClusterSize', or '{Pi0, Eta}ProbTightEnergyThresholdAndLargeClusterSize'} for the four modes described above, with
3105 the chosen suffix appended.
3108 Please don't use following ParticleList names elsewhere:
3110 ``gamma:HardPhoton``,
3111 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
3112 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
3113 ``pi0:EtaVeto + ListName``,
3114 ``eta:EtaVeto + ListName``
3116 @param particleList the input ParticleList
3117 @param decayString specify Particle to be added to the ParticleList
3118 @param mode choose one mode out of 'standard', 'tight', 'cluster' and 'both'
3119 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
3120 @param path modules are added to this path
3121 @param suffix optional suffix to be appended to the usual extraInfo name
3122 @param hardParticle particle name which is used to calculate the pi0/eta probability (default is gamma)
3123 @param pi0PayloadNameOverride specify the payload name of pi0 veto only if one wants to use non-default one. (default is None)
3124 @param pi0SoftPhotonCutOverride specify the soft photon selection criteria of pi0 veto only if one wants to use non-default one.
3126 @param etaPayloadNameOverride specify the payload name of eta veto only if one wants to use non-default one. (default is None)
3127 @param etaSoftPhotonCutOverride specify the soft photon selection criteria of eta veto only if one wants to use non-default one.
3133 B2ERROR(
"The pi0 / eta veto is not suitable for Belle analyses.")
3135 renameSuffix =
False
3137 for module
in path.modules():
3138 if module.type() ==
"SubEvent" and not renameSuffix:
3139 for subpath
in [p.values
for p
in module.available_params()
if p.name ==
"path"]:
3142 for submodule
in subpath.modules():
3143 if f
'{hardParticle}:HardPhoton{suffix}' in submodule.name():
3145 B2WARNING(
"Same extension already used in writePi0EtaVeto, append '_0'")
3149 roe_path = create_path()
3150 deadEndPath = create_path()
3151 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3152 fillSignalSideParticleList(f
'{hardParticle}:HardPhoton{suffix}', decayString, path=roe_path)
3154 dictListName = {
'standard':
'Origin',
3155 'tight':
'TightEnergyThreshold',
3156 'cluster':
'LargeClusterSize',
3157 'both':
'TightEnrgyThresholdAndLargeClusterSize'}
3159 dictPi0EnergyCut = {
'standard':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3160 'tight':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3161 'cluster':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3162 'both':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3164 dictEtaEnergyCut = {
'standard':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3165 'tight':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3166 'cluster':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3167 'both':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]'}
3169 dictNHitsCut = {
'standard':
'clusterNHits >= 0',
3170 'tight':
'clusterNHits >= 0',
3171 'cluster':
'clusterNHits >= 2',
3172 'both':
'clusterNHits >= 2'}
3174 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
3175 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
3176 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
3177 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
3179 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
3180 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
3181 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
3182 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
3184 dictPi0ExtraInfoName = {
'standard':
'Pi0ProbOrigin',
3185 'tight':
'Pi0ProbTightEnergyThreshold',
3186 'cluster':
'Pi0ProbLargeClusterSize',
3187 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize'}
3189 dictEtaExtraInfoName = {
'standard':
'EtaProbOrigin',
3190 'tight':
'EtaProbTightEnergyThreshold',
3191 'cluster':
'EtaProbLargeClusterSize',
3192 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize'}
3194 ListName = dictListName[mode]
3195 Pi0EnergyCut = dictPi0EnergyCut[mode]
3196 EtaEnergyCut = dictEtaEnergyCut[mode]
3197 TimingCut =
'abs(clusterTiming)<clusterErrorTiming'
3198 NHitsCut = dictNHitsCut[mode]
3199 Pi0PayloadName = dictPi0PayloadName[mode]
3200 EtaPayloadName = dictEtaPayloadName[mode]
3201 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
3202 EtaExtraInfoName = dictEtaExtraInfoName[mode]
3205 if pi0PayloadNameOverride
is not None:
3206 Pi0PayloadName = pi0PayloadNameOverride
3207 if pi0SoftPhotonCutOverride
is None:
3208 Pi0SoftPhotonCut = Pi0EnergyCut +
' and ' + NHitsCut
3212 Pi0SoftPhotonCut +=
' and ' + TimingCut
3214 Pi0SoftPhotonCut = pi0SoftPhotonCutOverride
3217 pi0soft = f
'gamma:Pi0Soft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3219 fillParticleList(pi0soft, Pi0SoftPhotonCut, path=roe_path)
3221 reconstructDecay(
'pi0:Pi0Veto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + pi0soft,
'',
3222 allowChargeViolation=
True, path=roe_path)
3224 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName],
3225 extraInfoName=Pi0ExtraInfoName, identifier=Pi0PayloadName)
3227 rankByHighest(
'pi0:Pi0Veto' + ListName,
'extraInfo(' + Pi0ExtraInfoName +
')', numBest=1, path=roe_path)
3229 variableToSignalSideExtraInfo(
'pi0:Pi0Veto' + ListName,
3230 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoName + suffix}, path=roe_path)
3233 if etaPayloadNameOverride
is not None:
3234 EtaPayloadName = etaPayloadNameOverride
3235 if etaSoftPhotonCutOverride
is None:
3236 EtaSoftPhotonCut = EtaEnergyCut +
' and ' + NHitsCut
3240 EtaSoftPhotonCut +=
' and ' + TimingCut
3242 EtaSoftPhotonCut = etaSoftPhotonCutOverride
3244 etasoft = f
'gamma:EtaSoft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3245 fillParticleList(etasoft, EtaSoftPhotonCut, path=roe_path)
3246 reconstructDecay(
'eta:EtaVeto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + etasoft,
'',
3247 allowChargeViolation=
True, path=roe_path)
3248 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName],
3249 extraInfoName=EtaExtraInfoName, identifier=EtaPayloadName)
3250 rankByHighest(
'eta:EtaVeto' + ListName,
'extraInfo(' + EtaExtraInfoName +
')', numBest=1, path=roe_path)
3251 variableToSignalSideExtraInfo(
'eta:EtaVeto' + ListName,
3252 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoName + suffix}, path=roe_path)
3254 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3257 def lowEnergyPi0Identification(pi0List, gammaList, payloadNameSuffix,
3260 Calculate low-energy pi0 identification.
3261 The result is stored as ExtraInfo ``lowEnergyPi0Identification`` for
3265 pi0List (str): Pi0 list.
3267 gammaList (str): Gamma list. First, an energy cut E > 0.2 is applied to the photons from this list.
3268 Then, all possible combinations with a pi0 daughter photon are formed except the one
3269 corresponding to the reconstructed pi0.
3270 The maximum low-energy pi0 veto value is calculated for such photon pairs
3271 and used as one of the input variables for the identification classifier.
3273 payloadNameSuffix (str): Payload name suffix. The weight payloads are stored in the analysis global
3274 tag and have the following names:\n
3275 * ``'LowEnergyPi0Veto' + payloadNameSuffix``
3276 * ``'LowEnergyPi0Identification' + payloadNameSuffix``\n
3277 The possible suffixes are:\n
3278 * ``'Belle1'`` for Belle data.
3279 * ``'Belle2Release5'`` for Belle II release 5 data (MC14, proc12, buckets 16 - 25).
3280 * ``'Belle2Release6'`` for Belle II release 6 data (MC15, proc13, buckets 26 - 36).
3282 path (basf2.Path): Module path.
3286 gammaListVeto = f
'{gammaList}_pi0veto'
3287 cutAndCopyList(gammaListVeto, gammaList,
'E > 0.2', path=path)
3289 payload_name =
'LowEnergyPi0Veto' + payloadNameSuffix
3290 path.add_module(
'LowEnergyPi0VetoExpert', identifier=payload_name,
3291 VetoPi0Daughters=
True, GammaListName=gammaListVeto,
3293 payload_name =
'LowEnergyPi0Identification' + payloadNameSuffix
3294 path.add_module(
'LowEnergyPi0IdentificationExpert',
3295 identifier=payload_name, Pi0ListName=pi0List,
3299 def getNeutralHadronGeomMatches(
3303 efficiencyCorrectionKl=0.83,
3304 efficiencyCorrectionNeutrons=1.0,
3307 For an ECL-based list, assign the mcdistanceKL and mcdistanceNeutron variables that correspond
3308 to the distance to the closest MC KL and neutron, respectively.
3309 @param particleLists the input ParticleLists, must be ECL-based lists (e.g. photons)
3310 @param addKL (default True) add distance to MC KL
3311 @param addNeutrons (default False) add distance to MC neutrons
3312 @param efficiencyCorrectionKl (default 0.83) apply overall efficiency correction
3313 @param efficiencyCorrectionNeutrons (default 1.0) apply overall efficiency correction
3314 @param path modules are added to this path
3316 from ROOT
import Belle2
3321 "NeutralHadronMatcher",
3322 particleLists=particleLists,
3323 mcPDGcode=Const.Klong.getPDGCode(),
3324 efficiencyCorrection=efficiencyCorrectionKl)
3327 "NeutralHadronMatcher",
3328 particleLists=particleLists,
3329 mcPDGcode=Const.neutron.getPDGCode(),
3330 efficiencyCorrection=efficiencyCorrectionNeutrons)
3333 def getBeamBackgroundProbability(particleList, weight, path=None):
3335 Assign a probability to each ECL cluster as being signal like (1) compared to beam background like (0)
3336 @param particleList the input ParticleList, must be a photon list
3337 @param weight type of weight file to use
3338 @param path modules are added to this path
3343 B2ERROR(
"The beam background MVA is not trained for Belle data.")
3345 path.add_module(
'MVAExpert',
3346 listNames=particleList,
3347 extraInfoName=
'beamBackgroundSuppression',
3348 identifier=f
'BeamBackgroundMVA_{weight}')
3351 def getFakePhotonProbability(particleList, weight, path=None):
3353 Assign a probability to each ECL cluster as being signal like (1) compared to fake photon like (0)
3354 @param particleList the input ParticleList, must be a photon list
3355 @param weight type of weight file to use
3356 @param path modules are added to this path
3361 B2ERROR(
"The fake photon MVA is not trained for Belle data.")
3363 path.add_module(
'MVAExpert',
3364 listNames=particleList,
3365 extraInfoName=
'fakePhotonSuppression',
3366 identifier=f
'FakePhotonMVA_{weight}')
3369 def buildEventKinematics(inputListNames=None, default_cleanup=True, custom_cuts=None,
3370 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
3372 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3373 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
3374 (all track and all hits in ECL without associated track).
3376 The visible energy missing values are
3377 stored in a EventKinematics dataobject.
3379 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3380 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
3381 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
3382 according to the PID likelihood and the option inputListNames will be ignored.
3383 @param chargedPIDPriors The prior PID fractions, that are used to regulate
3384 amount of certain charged particle species, should be a list of
3385 six floats if not None. The order of particle types is
3386 the following: [e-, mu-, pi-, K-, p+, d+]
3387 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
3388 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3389 which would result in a standard predefined selection cuts
3390 @param path modules are added to this path
3393 if inputListNames
is None:
3395 trackCuts =
'pt > 0.1'
3396 trackCuts +=
' and thetaInCDCAcceptance'
3397 trackCuts +=
' and abs(dz) < 3'
3398 trackCuts +=
' and dr < 0.5'
3400 gammaCuts =
'E > 0.05'
3401 gammaCuts +=
' and thetaInCDCAcceptance'
3403 gammaCuts +=
' and abs(clusterTiming) < 200'
3404 if (custom_cuts
is not None):
3405 trackCuts, gammaCuts = custom_cuts
3407 if fillWithMostLikely:
3408 from stdCharged
import stdMostLikely
3409 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
3410 inputListNames = [
'%s:mostlikely_evtkin' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
3412 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3414 fillParticleList(
'gamma:evtkin',
'', path=path)
3415 inputListNames += [
'gamma:evtkin']
3417 B2INFO(
"Using default cleanup in EventKinematics module.")
3418 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
3419 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
3420 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3422 B2INFO(
"No cleanup in EventKinematics module.")
3423 if not inputListNames:
3424 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
3425 fillParticleList(
'pi+:evtkin',
'', path=path)
3427 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3429 fillParticleList(
'gamma:evtkin',
'', path=path)
3430 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
3432 if (custom_cuts
is not None):
3433 B2INFO(
"Using default cleanup in EventKinematics module.")
3434 applyCuts(
'pi+:evtkin', trackCuts, path=path)
3435 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3437 B2INFO(
"No cleanup in EventKinematics module.")
3439 particleLists = inputListNames
3441 eventKinematicsModule = register_module(
'EventKinematics')
3442 eventKinematicsModule.set_name(
'EventKinematics_reco')
3443 eventKinematicsModule.param(
'particleLists', particleLists)
3444 path.add_module(eventKinematicsModule)
3447 def buildEventKinematicsFromMC(inputListNames=None, selectionCut='', path=None):
3449 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3450 using generated particles. If no ParticleList is provided, default generated ParticleLists are used.
3452 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3453 If the list is empty, default ParticleLists are filled.
3454 @param selectionCut optional selection cuts
3455 @param path Path to append the eventKinematics module to.
3458 if inputListNames
is None:
3460 if (len(inputListNames) == 0):
3464 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
3467 fillParticleListFromMC(
"%s:evtkin_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
3468 True,
True, path=path)
3469 if (selectionCut !=
''):
3470 applyCuts(
"%s:evtkin_default_gen" % t, selectionCut, path=path)
3471 inputListNames += [
"%s:evtkin_default_gen" % t]
3473 eventKinematicsModule = register_module(
'EventKinematics')
3474 eventKinematicsModule.set_name(
'EventKinematics_gen')
3475 eventKinematicsModule.param(
'particleLists', inputListNames)
3476 eventKinematicsModule.param(
'usingMC',
True)
3477 path.add_module(eventKinematicsModule)
3480 def buildEventShape(inputListNames=None,
3481 default_cleanup=True,
3487 harmonicMoments=True,
3491 checkForDuplicates=False,
3494 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
3495 using the particles in the lists provided by the user. If no particle list is provided,
3496 the function will internally create a list of good tracks and a list of good photons
3497 with (optionally) minimal quality cuts.
3500 The results of the calculation are then stored into the EventShapeContainer dataobject,
3501 and are accessible using the variables of the EventShape group.
3503 The user can switch the calculation of certain quantities on or off to save computing
3504 time. By default the calculation of the high-order moments (5-8) is turned off.
3505 Switching off an option will make the corresponding variables not available.
3508 The user can provide as many particle lists
3509 as needed, using also combined particles, but the function will always assume that
3510 the lists are independent.
3511 If the lists provided by the user contain several times the same track (either with
3512 different mass hypothesis, or once as an independent particle and once as daughter of a
3513 combined particle) the results won't be reliable.
3514 A basic check for duplicates is available setting the checkForDuplicate flags.
3517 @param inputListNames List of ParticleLists used to calculate the
3518 event shape variables. If the list is empty the default
3519 particleLists pi+:evtshape and gamma:evtshape are filled.
3520 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
3521 defining the internal lists. This option is ignored if the
3522 particleLists are provided by the user.
3523 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3524 which would result in a standard predefined selection cuts
3525 @param path Path to append the eventShape modules to.
3526 @param thrust Enables the calculation of thrust-related quantities (CLEO
3527 cones, Harmonic moments, jets).
3528 @param collisionAxis Enables the calculation of the quantities related to the
3530 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
3531 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
3532 to both the thrust axis and, if collisionAxis = True, the collision axis.
3533 @param allMoments If True, calculates also the FW and harmonic moments from order
3534 5 to 8 instead of the low-order ones only.
3535 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
3536 axis and, if collisionAxis = True, the collision axis.
3537 @param jets Enables the calculation of the hemisphere momenta and masses.
3538 Requires thrust = True.
3539 @param sphericity Enables the calculation of the sphericity-related quantities.
3540 @param checkForDuplicates Perform a check for duplicate particles before adding them. Regardless of the value of this option,
3541 it is recommended to consider sanitizing the lists you are passing to the function.
3545 if inputListNames
is None:
3547 trackCuts =
'pt > 0.1'
3548 trackCuts +=
' and thetaInCDCAcceptance'
3549 trackCuts +=
' and abs(dz) < 3.0'
3550 trackCuts +=
' and dr < 0.5'
3552 gammaCuts =
'E > 0.05'
3553 gammaCuts +=
' and thetaInCDCAcceptance'
3555 gammaCuts +=
' and abs(clusterTiming) < 200'
3556 if (custom_cuts
is not None):
3557 trackCuts, gammaCuts = custom_cuts
3559 if not inputListNames:
3560 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
3561 fillParticleList(
'pi+:evtshape',
'', path=path)
3563 copyList(
'gamma:evtshape',
'gamma:mdst', path=path)
3569 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
3572 if (custom_cuts
is not None):
3573 B2INFO(
"Applying standard cuts")
3574 applyCuts(
'pi+:evtshape', trackCuts, path=path)
3576 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
3578 B2WARNING(
"Creating the default lists with no cleanup.")
3580 particleLists = inputListNames
3582 eventShapeModule = register_module(
'EventShapeCalculator')
3583 eventShapeModule.set_name(
'EventShape')
3584 eventShapeModule.param(
'particleListNames', particleLists)
3585 eventShapeModule.param(
'enableAllMoments', allMoments)
3586 eventShapeModule.param(
'enableCleoCones', cleoCones)
3587 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
3588 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
3589 eventShapeModule.param(
'enableJets', jets)
3590 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
3591 eventShapeModule.param(
'enableSphericity', sphericity)
3592 eventShapeModule.param(
'enableThrust', thrust)
3593 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
3595 path.add_module(eventShapeModule)
3598 def labelTauPairMC(printDecayInfo=False, path=None, TauolaBelle=False, mapping_minus=None, mapping_plus=None):
3600 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
3601 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
3603 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
3604 @param path: module is added to this path
3605 @param TauolaBelle: if False, TauDecayMode is set. If True, TauDecayMarker is set.
3606 @param mapping_minus: if None, the map is the default one, else the path for the map is given by the user for tau-
3607 @param mapping_plus: if None, the map is the default one, else the path for the map is given by the user for tau+
3610 from basf2
import find_file
3616 m_printmode =
'default'
3618 if mapping_minus
is None:
3619 mp_file_minus = find_file(
'data/analysis/modules/TauDecayMode/map_tauminus.txt')
3621 mp_file_minus = mapping_minus
3623 if mapping_plus
is None:
3624 mp_file_plus = find_file(
'data/analysis/modules/TauDecayMode/map_tauplus.txt')
3626 mp_file_plus = mapping_plus
3628 path.add_module(
'TauDecayMode', printmode=m_printmode, file_minus=mp_file_minus, file_plus=mp_file_plus)
3631 tauDecayMarker = register_module(
'TauDecayMarker')
3632 tauDecayMarker.set_name(
'TauDecayMarker_')
3634 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
3637 def tagCurlTracks(particleLists,
3647 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
3649 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
3650 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
3652 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
3655 The module loops over all particles in a given list with a transverse momentum below the pre-selection **ptCut**
3656 and assigns them to bundles based on the response of the chosen **selector** and the required minimum response set by the
3657 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
3658 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
3662 @param particleLists: list of particle lists to check for curls.
3663 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
3664 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
3665 genParticleIndex then ranked and tagged as normal.
3666 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
3667 If set to ``-1`` a cut value optimised to maximise the accuracy on a BBbar sample is used.
3668 Note 'cut' selector is binary 0/1.
3669 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
3670 It is strongly recommended to used the 'mva' selection. The 'cut' selection
3671 is based on BN1079 and is only calibrated for Belle data.
3673 @param ptCut: Pre-selection cut on transverse momentum. Only tracks below that are considered as curler candidates.
3675 @param expert_train: flag to set training mode if selector has a training mode (mva).
3676 @param expert_filename: set file name of produced training ntuple (mva).
3677 @param path: module is added to this path.
3683 if (
not isinstance(particleLists, list)):
3684 particleLists = [particleLists]
3686 curlTagger = register_module(
'CurlTagger')
3687 curlTagger.set_name(
'CurlTagger_')
3688 curlTagger.param(
'particleLists', particleLists)
3689 curlTagger.param(
'belle', belle)
3690 curlTagger.param(
'mcTruth', mcTruth)
3691 curlTagger.param(
'responseCut', responseCut)
3692 if abs(responseCut + 1) < 1e-9:
3693 curlTagger.param(
'usePayloadCut',
True)
3695 curlTagger.param(
'usePayloadCut',
False)
3697 curlTagger.param(
'selectorType', selectorType)
3698 curlTagger.param(
'ptCut', ptCut)
3699 curlTagger.param(
'train', expert_train)
3700 curlTagger.param(
'trainFilename', expert_filename)
3702 path.add_module(curlTagger)
3705 def applyChargedPidMVA(particleLists, path, trainingMode, chargeIndependent=False, binaryHypoPDGCodes=(0, 0)):
3707 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
3709 The module decorates Particle objects in the input ParticleList(s) with variables
3710 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
3713 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.3.0**, **ROOT 6.20/04**).
3715 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
3717 * e (11) vs. pi (211)
3718 * mu (13) vs. pi (211)
3719 * pi (211) vs. K (321)
3720 * K (321) vs. pi (211)
3722 , or 'global' PID, namely "one-vs-others" separation. The latter exploits an MVA algorithm trained in multi-class mode,
3723 and it's the default behaviour. Currently, the multi-class training separates the following standard charged hypotheses:
3725 - e (11), mu (13), pi (211), K (321)
3728 In order to run the `ChargedPidMVA` and ensure the most up-to-date MVA training weights are applied,
3729 it is necessary to append the latest analysis global tag (GT) to the steering script.
3732 particleLists (list(str)): the input list of DecayStrings, where each selected (^) daughter should correspond to a
3733 standard charged ParticleList, e.g. ``['Lambda0:sig -> ^p+ ^pi-', 'J/psi:sig -> ^mu+ ^mu-']``.
3734 One can also directly pass a list of standard charged ParticleLists,
3735 e.g. ``['e+:my_electrons', 'pi+:my_pions']``.
3736 Note that charge-conjugated ParticleLists will automatically be included.
3737 path (basf2.Path): the module is added to this path.
3738 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
3739 Needed to pick up the correct payload from the DB. Available choices:
3741 * c_Classification=0
3743 * c_ECL_Classification=2
3744 * c_ECL_Multiclass=3
3745 * c_PSD_Classification=4
3746 * c_PSD_Multiclass=5
3747 * c_ECL_PSD_Classification=6
3748 * c_ECL_PSD_Multiclass=7
3750 chargeIndependent (bool, ``optional``): use a BDT trained on a sample of inclusively charged particles.
3751 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
3752 Required only for binary PID mode.
3757 B2ERROR(
"Charged PID via MVA is not available for Belle data.")
3759 from ROOT
import Belle2
3761 TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
3764 plSet = set(particleLists)
3768 TrainingMode.c_Classification:
3769 {
"mode":
"Classification",
"detector":
"ALL"},
3770 TrainingMode.c_Multiclass:
3771 {
"mode":
"Multiclass",
"detector":
"ALL"},
3772 TrainingMode.c_ECL_Classification:
3773 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
3774 TrainingMode.c_ECL_Multiclass:
3775 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
3776 TrainingMode.c_PSD_Classification:
3777 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
3778 TrainingMode.c_PSD_Multiclass:
3779 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
3780 TrainingMode.c_ECL_PSD_Classification:
3781 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
3782 TrainingMode.c_ECL_PSD_Multiclass:
3783 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
3786 if payloadNames.get(trainingMode)
is None:
3787 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
3788 "\nis not supported. Please choose among the following:\n",
3789 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
3791 mode = payloadNames.get(trainingMode).get(
"mode")
3792 detector = payloadNames.get(trainingMode).get(
"detector")
3794 payloadName = f
"ChargedPidMVAWeights_{mode}"
3799 Const.electron.getPDGCode():
3800 {
"pName":
"e",
"pFullName":
"electron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3801 Const.muon.getPDGCode():
3802 {
"pName":
"mu",
"pFullName":
"muon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3803 Const.pion.getPDGCode():
3804 {
"pName":
"pi",
"pFullName":
"pion",
"pNameBkg":
"K",
"pdgIdBkg": Const.kaon.getPDGCode()},
3805 Const.kaon.getPDGCode():
3806 {
"pName":
"K",
"pFullName":
"kaon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3807 Const.proton.getPDGCode():
3808 {
"pName":
"p",
"pFullName":
"proton",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3809 Const.deuteron.getPDGCode():
3810 {
"pName":
"d",
"pFullName":
"deuteron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3813 if binaryHypoPDGCodes == (0, 0):
3816 chargedpid = register_module(
"ChargedPidMVAMulticlass")
3817 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
3824 binaryOpts = [(pdgIdSig, info[
"pdgIdBkg"])
for pdgIdSig, info
in stdChargedMap.items()]
3826 if binaryHypoPDGCodes
not in binaryOpts:
3827 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
3828 ". Please choose among the following pairs:\n",
3829 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
3833 if not decayDescriptor.init(name):
3834 raise ValueError(f
"Invalid particle list {name} in applyChargedPidMVA!")
3835 msg = f
"Input ParticleList: {name}"
3836 pdgs = [abs(decayDescriptor.getMother().getPDGCode())]
3837 daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
3838 if len(daughter_pdgs) > 0:
3839 pdgs = daughter_pdgs
3840 for idaughter, pdg
in enumerate(pdgs):
3841 if abs(pdg)
not in binaryHypoPDGCodes:
3843 msg = f
"Selected daughter {idaughter} in ParticleList: {name}"
3845 f
"{msg} (PDG={pdg}) is neither signal ({binaryHypoPDGCodes[0]}) nor background ({binaryHypoPDGCodes[1]}).")
3847 chargedpid = register_module(
"ChargedPidMVA")
3848 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
3849 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
3850 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
3852 chargedpid.param(
"particleLists", list(plSet))
3853 chargedpid.param(
"payloadName", payloadName)
3854 chargedpid.param(
"chargeIndependent", chargeIndependent)
3857 if detector ==
"ECL":
3858 chargedpid.param(
"useECLOnlyTraining",
True)
3860 path.add_module(chargedpid)
3863 def calculateTrackIsolation(
3867 reference_list_name=None,
3868 vars_for_nearest_part=[],
3869 highest_prob_mass_for_ext=True,
3870 exclude_pid_det_weights=False):
3872 Given an input decay string, compute variables that quantify track helix-based isolation of the charged
3873 stable particles in the input decay chain.
3876 An "isolation score" can be defined using the distance
3877 of each particle to its closest neighbour, defined as the segment connecting the two
3878 extrapolated track helices intersection points on a given cylindrical surface.
3879 The distance variables defined in the `VariableManager` is named `minET2ETDist`,
3880 the isolation scores are named `minET2ETIsoScore`, `minET2ETIsoScoreAsWeightedAvg`.
3882 The definition of distance and the number of distances that are calculated per sub-detector is based on
3883 the following recipe:
3885 * **CDC**: as the segmentation is very coarse along :math:`z`,
3886 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
3887 A total of 9 distances are calculated: the cylindrical surfaces are defined at radiuses
3888 that correspond to the positions of the 9 CDC wire superlayers: :math:`R_{i}^{\\mathrm{CDC}}~(i \\in \\{0,...,8\\})`.
3890 * **TOP**: as there is no segmentation along :math:`z`,
3891 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
3892 Only one distance at the TOP entry radius :math:`R_{0}^{\\mathrm{TOP}}` is calculated.
3894 * **ARICH**: as there is no segmentation along :math:`z`,
3895 the distance is defined as the distance on the :math:`(\\rho=R, \\phi)` plane at fixed :math:`z=Z`.
3896 Only one distance at the ARICH photon detector entry coordinate :math:`Z_{0}^{\\mathrm{ARICH}}` is calculated.
3898 * **ECL**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
3899 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
3900 Two distances are calculated: one at the ECL entry surface :math:`R_{0}^{\\mathrm{ECL}}` (barrel),
3901 :math:`Z_{0}^{\\mathrm{ECL}}` (endcaps), and one at :math:`R_{1}^{\\mathrm{ECL}}` (barrel),
3902 :math:`Z_{1}^{\\mathrm{ECL}}` (endcaps), corresponding roughly to the mid-point
3903 of the longitudinal size of the crystals.
3905 * **KLM**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
3906 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
3907 Only one distance at the KLM first strip entry surface :math:`R_{0}^{\\mathrm{KLM}}` (barrel),
3908 :math:`Z_{0}^{\\mathrm{KLM}}` (endcaps) is calculated.
3911 decay_string (str): name of the input decay string with selected charged stable daughters,
3912 for example: ``Lambda0:merged -> ^p+ ^pi-``.
3913 Alternatively, it can be a particle list for charged stable particles
3914 as defined in ``Const::chargedStableSet``, for example: ``mu+:all``.
3915 The charge-conjugate particle list will be also processed automatically.
3916 path (basf2.Path): path to which module(s) will be added.
3917 *detectors: detectors for which track isolation variables will be calculated.
3918 Choose among: ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
3919 reference_list_name (Optional[str]): name of the input charged stable particle list for the reference tracks.
3920 By default, the ``:all`` ParticleList of the same type
3921 of the selected particle in ``decay_string`` is used.
3922 The charge-conjugate particle list will be also processed automatically.
3923 vars_for_nearest_part (Optional[list(str)]): a list of variables to calculate for the nearest particle in the reference
3924 list at each detector surface. It uses the metavariable `minET2ETDistVar`.
3925 If unset, only the distances to the nearest neighbour
3926 per detector are calculated.
3927 highest_prob_mass_for_hex (Optional[bool]): if this option is set to True (default), the helix extrapolation
3928 for the particles will use the track fit result for the most
3929 probable mass hypothesis, namely, the one that gives the highest
3930 chi2Prob of the fit. Otherwise, it uses the mass hypothesis that
3931 corresponds to the particle lists PDG.
3932 exclude_pid_det_weights (Optional[bool]): if this option is set to False (default), the isolation score
3933 calculation will take into account the weight that each detector has on the PID
3934 for the particle species of interest.
3937 dict(int, list(str)): a dictionary mapping the PDG of each reference particle list to its isolation variables.
3942 from ROOT
import Belle2, TDatabasePDG
3945 if not decayDescriptor.init(decay_string):
3946 B2FATAL(f
"Invalid particle list {decay_string} in calculateTrackIsolation!")
3947 no_reference_list_name =
not reference_list_name
3950 "CDC": list(range(9)),
3956 if any(d
not in det_and_layers
for d
in detectors):
3958 "Your input detector list: ",
3960 " contains an invalid choice. Please select among: ",
3962 det_and_layers.keys()))
3967 processed_decay_strings = []
3968 if select_symbol
in decay_string:
3969 splitted_ds = decay_string.split(select_symbol)
3970 for i
in range(decay_string.count(select_symbol)):
3971 tmp = list(splitted_ds)
3972 tmp.insert(i+1, select_symbol)
3973 processed_decay_strings += [
''.join(tmp)]
3975 processed_decay_strings += [decay_string]
3977 reference_lists_to_vars = {}
3979 for processed_dec
in processed_decay_strings:
3980 if no_reference_list_name:
3981 decayDescriptor.init(processed_dec)
3982 selected_daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
3983 if len(selected_daughter_pdgs) > 0:
3984 reference_list_name = f
'{TDatabasePDG.Instance().GetParticle(abs(selected_daughter_pdgs[-1])).GetName()}:all'
3986 reference_list_name = f
'{processed_dec.split(":")[0]}:all'
3990 trackiso = path.add_module(
"TrackIsoCalculator",
3991 decayString=processed_dec,
3992 detectorNames=list(detectors),
3993 particleListReference=reference_list_name,
3994 useHighestProbMassForExt=highest_prob_mass_for_ext,
3995 excludePIDDetWeights=exclude_pid_det_weights)
3996 trackiso.set_name(f
"TrackIsoCalculator_{'_'.join(detectors)}_{processed_dec}_VS_{reference_list_name}")
4002 f
"minET2ETDist({d}, {d_layer}, {reference_list_name}, {int(highest_prob_mass_for_ext)})"
4003 for d
in detectors
for d_layer
in det_and_layers[d]]
4006 f
"minET2ETIsoScore({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4007 f
"minET2ETIsoScoreAsWeightedAvg({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4010 if vars_for_nearest_part:
4011 trackiso_vars.extend(
4013 f
"minET2ETDistVar({d}, {d_layer}, {reference_list_name}, {v})"
4014 for d
in detectors
for d_layer
in det_and_layers[d]
for v
in vars_for_nearest_part
4016 trackiso_vars.sort()
4018 reference_lists_to_vars[ref_pdg] = trackiso_vars
4020 return reference_lists_to_vars
4023 def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
4025 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
4026 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
4027 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
4028 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
4031 .. code-block:: python
4033 from modularAnalysis import calculateDistance
4034 calculateDistance('list_name', 'decay_string', "mode", path=user_path)
4036 @param list_name name of the input ParticleList
4037 @param decay_string select particles between the distance of closest approach will be calculated
4038 @param mode Specifies how the distance is calculated
4039 vertextrack: calculate the distance of closest approach between a track and a\
4040 vertex, taking the first candidate as vertex, default
4041 trackvertex: calculate the distance of closest approach between a track and a\
4042 vertex, taking the first candidate as track
4043 2tracks: calculates the distance of closest approach between two tracks
4044 2vertices: calculates the distance between two vertices
4045 vertexbtube: calculates the distance of closest approach between a vertex and btube
4046 trackbtube: calculates the distance of closest approach between a track and btube
4047 @param path modules are added to this path
4051 dist_mod = register_module(
'DistanceCalculator')
4053 dist_mod.set_name(
'DistanceCalculator_' + list_name)
4054 dist_mod.param(
'listName', list_name)
4055 dist_mod.param(
'decayString', decay_string)
4056 dist_mod.param(
'mode', mode)
4057 path.add_module(dist_mod)
4060 def addInclusiveDstarReconstruction(decayString, slowPionCut, DstarCut, path):
4062 Adds the InclusiveDstarReconstruction module to the given path.
4063 This module creates a D* particle list by estimating the D* four momenta
4064 from slow pions, specified by a given cut. The D* energy is approximated
4065 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
4066 momentum is calculated using the D* PDG mass and the direction is collinear
4067 to the slow pion direction. The charge of the given pion list has to be consistent
4070 @param decayString Decay string, must be of form ``D* -> pi``
4071 @param slowPionCut Cut applied to the input pion list to identify slow pions
4072 @param DstarCut Cut applied to the output D* list
4073 @param path the module is added to this path
4076 incl_dstar = register_module(
"InclusiveDstarReconstruction")
4077 incl_dstar.param(
"decayString", decayString)
4078 incl_dstar.param(
"slowPionCut", slowPionCut)
4079 incl_dstar.param(
"DstarCut", DstarCut)
4080 path.add_module(incl_dstar)
4083 def scaleError(outputListName, inputListName,
4084 scaleFactors=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4085 scaleFactorsNoPXD=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4086 d0Resolution=[0.00115328, 0.00134704],
4087 z0Resolution=[0.00124327, 0.0013272],
4092 This module creates a new charged particle list.
4093 The helix errors of the new particles are scaled by constant factors.
4094 Two sets of five scale factors are defined for tracks with and without a PXD hit.
4095 The scale factors are in order of (d0, phi0, omega, z0, tanlambda).
4096 For tracks with a PXD hit, in order to avoid severe underestimation of d0 and z0 errors,
4097 lower limits (best resolution) can be set in a momentum-dependent form.
4098 This module is supposed to be used only for TDCPV analysis and for low-momentum (0-3 GeV/c) tracks in BBbar events.
4099 Details will be documented in a Belle II note, BELLE2-NOTE-PH-2021-038.
4101 @param inputListName Name of input charged particle list to be scaled
4102 @param outputListName Name of output charged particle list with scaled error
4103 @param scaleFactors List of five constants to be multiplied to each of helix errors (for tracks with a PXD hit)
4104 @param scaleFactorsNoPXD List of five constants to be multiplied to each of helix errors (for tracks without a PXD hit)
4105 @param d0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4106 defining d0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**1.5))**2 }
4107 @param z0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4108 defining z0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**2.5))**2 }
4109 @param d0MomThr d0 best resolution is kept constant below this momentum
4110 @param z0MomThr z0 best resolution is kept constant below this momentum
4114 scale_error = register_module(
"HelixErrorScaler")
4115 scale_error.set_name(
'ScaleError_' + inputListName)
4116 scale_error.param(
'inputListName', inputListName)
4117 scale_error.param(
'outputListName', outputListName)
4118 scale_error.param(
'scaleFactors_PXD', scaleFactors)
4119 scale_error.param(
'scaleFactors_noPXD', scaleFactorsNoPXD)
4120 scale_error.param(
'd0ResolutionParameters', d0Resolution)
4121 scale_error.param(
'z0ResolutionParameters', z0Resolution)
4122 scale_error.param(
'd0MomentumThreshold', d0MomThr)
4123 scale_error.param(
'z0MomentumThreshold', z0MomThr)
4124 path.add_module(scale_error)
4127 def estimateAndAttachTrackFitResult(inputListName, path=None):
4129 Create a TrackFitResult from the momentum of the Particle assuming it originates from the IP and make a relation between them.
4130 The covariance, detector hit information, and fit-related information (pValue, NDF) are assigned meaningless values. The input
4131 Particles must not have already Track or TrackFitResult and thus are supposed to be composite particles, recoil, dummy
4132 particles, and so on.
4135 .. warning:: Since the source type is not overwritten as Track, not all track-related variables are guaranteed to be available.
4138 @param inputListName Name of input ParticleList
4141 estimator = register_module(
"TrackFitResultEstimator")
4142 estimator.set_name(
"trackFitResultEstimator_" + inputListName)
4143 estimator.param(
"inputListName", inputListName)
4144 path.add_module(estimator)
4147 def correctEnergyBias(inputListNames, tableName, path=None):
4149 Scale energy of the particles according to the scaling factor.
4150 If the particle list contains composite particles, the energy of the daughters are scaled.
4151 Subsequently, the energy of the mother particle is updated as well.
4154 inputListNames (list(str)): input particle list names
4155 tableName : stored in localdb and created using ParticleWeightingLookUpCreator
4156 path (basf2.Path): module is added to this path
4161 B2ERROR(
"The energy bias cannot be corrected with this tool for Belle data.")
4163 correctenergybias = register_module(
'EnergyBiasCorrection')
4164 correctenergybias.param(
'particleLists', inputListNames)
4165 correctenergybias.param(
'tableName', tableName)
4166 path.add_module(correctenergybias)
4169 def addPhotonEfficiencyRatioVariables(inputListNames, tableName, path=None):
4171 Add photon Data/MC detection efficiency ratio weights to the specified particle list
4174 inputListNames (list(str)): input particle list names
4175 tableName : taken from database with appropriate name
4176 path (basf2.Path): module is added to this path
4181 B2ERROR(
"For Belle data the photon data/MC detection efficiency ratio is not available with this tool.")
4183 photon_efficiency_correction = register_module(
'PhotonEfficiencySystematics')
4184 photon_efficiency_correction.param(
'particleLists', inputListNames)
4185 photon_efficiency_correction.param(
'tableName', tableName)
4186 path.add_module(photon_efficiency_correction)
4189 def addPi0VetoEfficiencySystematics(particleList, decayString, tableName, threshold, mode='standard', suffix='', path=None):
4191 Add pi0 veto Data/MC efficiency ratio weights to the specified particle list
4193 @param particleList the input ParticleList
4194 @param decayString specify hard photon to be performed pi0 veto (e.g. 'B+:sig -> rho+:sig ^gamma:hard')
4195 @param tableName table name corresponding to payload version (e.g. 'Pi0VetoEfficiencySystematics_Mar2022')
4196 @param threshold pi0 veto threshold (0.10, 0.11, ..., 0.99)
4197 @param mode choose one mode (same as writePi0EtaVeto) out of 'standard', 'tight', 'cluster' and 'both'
4198 @param suffix optional suffix to be appended to the usual extraInfo name
4199 @param path the module is added to this path
4201 The following extraInfo are available related with the given particleList:
4203 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_ratio : weight of Data/MC for the veto efficiency
4204 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_stat : the statistical uncertainty of the weight
4205 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_sys : the systematic uncertainty of the weight
4206 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_total : the total uncertainty of the weight
4207 * Pi0VetoEfficiencySystematics_{mode}{suffix}_threshold : threshold of the pi0 veto
4212 B2ERROR(
"For Belle data the pi0 veto data/MC efficiency ratio weights are not available via this tool.")
4214 pi0veto_efficiency_correction = register_module(
'Pi0VetoEfficiencySystematics')
4215 pi0veto_efficiency_correction.param(
'particleLists', particleList)
4216 pi0veto_efficiency_correction.param(
'decayString', decayString)
4217 pi0veto_efficiency_correction.param(
'tableName', tableName)
4218 pi0veto_efficiency_correction.param(
'threshold', threshold)
4219 pi0veto_efficiency_correction.param(
'mode', mode)
4220 pi0veto_efficiency_correction.param(
'suffix', suffix)
4221 path.add_module(pi0veto_efficiency_correction)
4224 def getAnalysisGlobaltag(timeout=180) -> str:
4226 Returns a string containing the name of the latest and recommended analysis globaltag.
4229 timeout: Seconds to wait for b2conditionsdb-recommend
4234 B2ERROR(
"The getAnalysisGlobaltag() function cannot be used for Belle data.")
4239 tags = subprocess.check_output(
4240 [
'b2conditionsdb-recommend',
'--oneline'],
4242 ).decode(
'UTF-8').rstrip().split(
' ')
4245 if tag.startswith(
'analysis_tools'):
4249 except subprocess.TimeoutExpired
as te:
4250 B2FATAL(f
'A {te} exception was raised during the call of getAnalysisGlobaltag(). '
4251 'The function took too much time to retrieve the requested information '
4252 'from the versioning repository.\n'
4253 'Please try to re-run your job. In case of persistent failures, there may '
4254 'be issues with the DESY collaborative services, so please contact the experts.')
4255 except subprocess.CalledProcessError
as ce:
4256 B2FATAL(f
'A {ce} exception was raised during the call of getAnalysisGlobaltag(). '
4257 'Please try to re-run your job. In case of persistent failures, please contact '
4261 def getAnalysisGlobaltagB2BII() -> str:
4263 Get recommended global tag for B2BII analysis.
4268 B2ERROR(
'The getAnalysisGlobaltagB2BII() function cannot be used for Belle II data.')
4269 from versioning
import recommended_b2bii_analysis_global_tag
4270 return recommended_b2bii_analysis_global_tag()
4273 def getNbarIDMVA(particleList: str, path=
None):
4275 This function can give a score to predict if it is a anti-n0.
4276 It is not used to predict n0.
4277 Currently, this can be used only for ECL cluster.
4278 output will be stored in extraInfo(nbarID); -1 means MVA invalid
4280 @param particleList The input ParticleList name or a decay string which contains a full mother particle list name.
4281 Only one selected daughter is supported.
4282 @param path modules are added to this path
4285 from ROOT
import Belle2
4288 B2ERROR(
"The MVA-based anti-neutron PID is only available for Belle II data.")
4290 from variables
import variables
4292 variables.addAlias(
'V1',
'clusterHasPulseShapeDiscrimination')
4293 variables.addAlias(
'V2',
'clusterE')
4294 variables.addAlias(
'V3',
'clusterLAT')
4295 variables.addAlias(
'V4',
'clusterE1E9')
4296 variables.addAlias(
'V5',
'clusterE9E21')
4297 variables.addAlias(
'V6',
'clusterZernikeMVA')
4298 variables.addAlias(
'V7',
'clusterAbsZernikeMoment40')
4299 variables.addAlias(
'V8',
'clusterAbsZernikeMoment51')
4303 'passesCut(V1 == 1 and V2 >= 0 and V3 >= 0 and V4 >= 0 and V5 >= 0 and V6 >= 0 and V7 >= 0 and V8 >= 0)')
4304 variables.addAlias(
'nbarIDmod',
'conditionalVariableSelector(nbarIDValid == 1, extraInfo(nbarIDFromMVA), constant(-1.0))')
4306 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'nbarIDFromMVA', identifier=
'db_nbarIDECL')
4308 if not decayDescriptor.init(particleList):
4309 raise ValueError(f
"Provided decay string is invalid: {particleList}")
4310 if decayDescriptor.getNDaughters() == 0:
4313 listname = decayDescriptor.getMother().getFullName()
4314 variablesToDaughterExtraInfo(listname, particleList, {
'nbarIDmod':
'nbarID'}, option=2, path=path)
4317 def reconstructDecayWithNeutralHadron(decayString, cut, allowGamma=False, allowAnyParticleSource=False, path=None, **kwargs):
4319 Reconstructs decay with a long-lived neutral hadron e.g.
4320 :math:`B^0 \to J/\psi K_L^0`,
4321 :math:`B^0 \to p \bar{n} D^*(2010)^-`.
4323 The calculation is done with IP constraint and mother mass constraint.
4325 The decay string passed in must satisfy the following rules:
4327 - The neutral hadron must be **selected** in the decay string with the
4328 caret (``^``) e.g. ``B0:sig -> J/psi:sig ^K_L0:sig``. (Note the caret
4329 next to the neutral hadron.)
4330 - There can only be **one neutral hadron in a decay**.
4331 - The neutral hadron has to be a direct daughter of its mother.
4333 .. note:: This function forwards its arguments to `reconstructDecay`,
4334 so please check the documentation of `reconstructDecay` for all
4337 @param decayString A decay string following the mentioned rules
4338 @param cut Cut to apply to the particle list
4339 @param allowGamma Whether allow the selected particle to be ``gamma``
4340 @param allowAnyParticleSource Whether allow the selected particle to be from any source.
4341 Should only be used when studying control sample.
4342 @param path The path to put in the module
4345 reconstructDecay(decayString, cut, path=path, **kwargs)
4346 module = register_module(
'NeutralHadron4MomentumCalculator')
4347 module.set_name(
'NeutralHadron4MomentumCalculator_' + decayString)
4348 module.param(
'decayString', decayString)
4349 module.param(
'allowGamma', allowGamma)
4350 module.param(
'allowAnyParticleSource', allowAnyParticleSource)
4351 path.add_module(module)
4354 func_requiring_analysisGT = [
4355 scaleTrackMomenta, smearTrackMomenta, oldwritePi0EtaVeto, writePi0EtaVeto, lowEnergyPi0Identification,
4356 getBeamBackgroundProbability, getFakePhotonProbability, tagCurlTracks, applyChargedPidMVA, correctEnergyBias,
4357 addPhotonEfficiencyRatioVariables, addPi0VetoEfficiencySystematics, getNbarIDMVA]
4358 for _
in func_requiring_analysisGT:
4359 _.__doc__ +=
"\n .. note:: This function (optionally) requires a payload stored in the analysis GlobalTag. "\
4360 "Please append or prepend the latest one from `getAnalysisGlobaltag` or `getAnalysisGlobaltagB2BII`.\n"
4363 if __name__ ==
'__main__':
4365 pretty_print_module(__name__,
"modularAnalysis")
tuple parse(str cut, verbose=False)
This class provides a set of constants for the framework.
The DecayDescriptor stores information about a decay tree or parts of a decay tree.
Describe one component of the Geometry.
static DBStore & Instance()
Instance of a singleton DBStore.
def add_mdst_output(path, mc=True, filename='mdst.root', additionalBranches=[], dataDescription=None)
def add_udst_output(path, filename, particleLists=None, additionalBranches=None, dataDescription=None, mc=True)