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)
337 │ │ ├── D- (-411)
338 │ │ │ ├── K*- (-323)
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)
350 │ │ │ │ ╰╶╶ mu- (13)
351 │ │ │ │ ├╶╶ nu_mu (14)
352 │ │ │ │ ├╶╶ anti-nu_e (-12)
353 │ │ │ │ ╰╶╶ e- (11)
354 │ │ │ ╰── K_S0 (310)
355 │ │ │ ├── pi0 (111)
356 │ │ │ │ ├── gamma (22)
357 │ │ │ │ ╰── gamma (22)
358 │ │ │ ╰── pi0 (111)
359 │ │ │ ├── gamma (22)
360 │ │ │ ╰── gamma (22)
361 │ │ ╰── pi+ (211)
362 │ ├── mu+ (-13)
363 │ │ ├╶╶ anti-nu_mu (-14)
364 │ │ ├╶╶ nu_e (12)
365 │ │ ╰╶╶ e+ (-11)
366 │ ├── nu_mu (14)
367 │ ╰── gamma (22)
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) → …
418 │ ├── tau+ (-15) → …
419 │ ╰── nu_tau (16)
421 ├── D*0 (423) → …
422 ├── K*- (-323) → …
423 ├── K*+ (323) → …
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 TrackingMomentumScaleFactors = register_module(
'TrackingMomentumScaleFactors')
745 TrackingMomentumScaleFactors.param(
'particleLists', inputListNames)
746 TrackingMomentumScaleFactors.param(
'scale', scale)
747 TrackingMomentumScaleFactors.param(
'payloadName', payloadName)
748 TrackingMomentumScaleFactors.param(
'scalingFactorName', scalingFactorName)
750 path.add_module(TrackingMomentumScaleFactors)
753 def correctTrackEnergy(inputListNames, correction=float(
'nan'), payloadName=
"", correctionName=
"SF", path=
None):
755 Correct the energy loss of tracks according to a 'correction' value.
756 This correction can either be given as constant number or as the name of the payload which contains
757 the variable corrections.
758 If the particle list contains composite particles, the momenta of the track-based daughters are corrected.
759 Subsequently, the momentum of the mother particle is updated as well.
762 inputListNames (list(str)): input particle list names
763 correction (float): correction value to be subtracted to the particle energy (0.0 -- no correction)
764 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
765 correctionName (str): name of correction variable in the payload.
766 path (basf2.Path): module is added to this path
771 B2ERROR(
"The tracking energy correction can only be run over Belle II data.")
773 TrackingEnergyLossCorrection = register_module(
'TrackingEnergyLossCorrection')
774 TrackingEnergyLossCorrection.param(
'particleLists', inputListNames)
775 TrackingEnergyLossCorrection.param(
'correction', correction)
776 TrackingEnergyLossCorrection.param(
'payloadName', payloadName)
777 TrackingEnergyLossCorrection.param(
'correctionName', correctionName)
779 path.add_module(TrackingEnergyLossCorrection)
782 def smearTrackMomenta(inputListNames, payloadName="", smearingFactorName="smear", path=None):
784 Smear the momenta of the particles according the values read from the given payload.
785 If the particle list contains composite particles, the momenta of the track-based daughters are smeared.
786 Subsequently, the momentum of the mother particle is updated as well.
789 inputListNames (list(str)): input particle list names
790 payloadName (str): name of the payload which contains the smearing values
791 smearingFactorName (str): name of smearing factor variable in the payload.
792 path (basf2.Path): module is added to this path
795 TrackingMomentumScaleFactors = register_module(
'TrackingMomentumScaleFactors')
796 TrackingMomentumScaleFactors.param(
'particleLists', inputListNames)
797 TrackingMomentumScaleFactors.param(
'payloadName', payloadName)
798 TrackingMomentumScaleFactors.param(
'smearingFactorName', smearingFactorName)
800 path.add_module(TrackingMomentumScaleFactors)
803 def mergeListsWithBestDuplicate(outputListName,
808 ignoreMotherFlavor=False,
811 Merge input ParticleLists into one output ParticleList. Only the best
812 among duplicates is kept. The lowest or highest value (configurable via
813 preferLowest) of the provided variable determines which duplicate is the
816 @param ouputListName name of merged ParticleList
817 @param inputListName vector of original ParticleLists to be merged
818 @param variable variable to determine best duplicate
819 @param preferLowest whether lowest or highest value of variable should be preferred
820 @param writeOut whether RootOutput module should save the created ParticleList
821 @param ignoreMotherFlavor whether the flavor of the mother particle is ignored when trying to find duplicates
822 @param path modules are added to this path
825 pmanipulate = register_module(
'ParticleListManipulator')
826 pmanipulate.set_name(
'PListMerger_' + outputListName)
827 pmanipulate.param(
'outputListName', outputListName)
828 pmanipulate.param(
'inputListNames', inputListNames)
829 pmanipulate.param(
'variable', variable)
830 pmanipulate.param(
'preferLowest', preferLowest)
831 pmanipulate.param(
'writeOut', writeOut)
832 pmanipulate.param(
'ignoreMotherFlavor', ignoreMotherFlavor)
833 path.add_module(pmanipulate)
836 def fillSignalSideParticleList(outputListName, decayString, path):
838 This function should only be used in the ROE path, that is a path
839 that is executed for each ROE object in the DataStore.
841 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
843 Function will create a ParticleList with name 'gamma:sig' which will be filled
844 with the existing photon Particle, being the second daughter of the B0 candidate
845 to which the ROE object has to be related.
847 @param ouputListName name of the created ParticleList
848 @param decayString specify Particle to be added to the ParticleList
851 pload = register_module(
'SignalSideParticleListCreator')
852 pload.set_name(
'SSParticleList_' + outputListName)
853 pload.param(
'particleListName', outputListName)
854 pload.param(
'decayString', decayString)
855 path.add_module(pload)
858 def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False,
859 loadPhotonsFromKLM=False):
861 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
862 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
864 The multiple ParticleLists with their own selection criteria are specified
865 via list tuples (decayString, cut), for example
867 .. code-block:: python
869 kaons = ('K+:mykaons', 'kaonID>0.1')
870 pions = ('pi+:mypions','pionID>0.1')
871 fillParticleLists([kaons, pions], path=mypath)
873 If you are unsure what selection you want, you might like to see the
874 :doc:`StandardParticles` functions.
876 The type of the particles to be loaded is specified via the decayString module parameter.
877 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
878 the particle. The following types of the particles can be loaded:
880 * charged final state particles (input ``mdst`` type = Tracks)
881 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
883 * neutral final state particles
884 - "gamma" (input ``mdst`` type = ECLCluster)
885 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
886 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
889 For "K_S0" and "Lambda0" you must specify the daughter ordering.
891 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
893 .. code-block:: python
895 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
896 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
899 Gammas can also be loaded from KLMClusters by explicitly setting the
900 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
901 done in selected use-cases and the effect should be studied carefully.
904 For "K_L0" it is now possible to load from ECLClusters, to revert to
905 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
907 .. code-block:: python
909 klongs = ('K_L0', 'isFromKLM > 0')
910 fillParticleLists([kaons, pions, klongs], path=mypath)
914 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
915 The decay string determines the type of Particle
916 and the name of the ParticleList.
917 If the input MDST type is V0 the whole
918 decay chain needs to be specified, so that
919 the user decides and controls the daughters
920 ' order (e.g. ``K_S0 -> pi+ pi-``)
921 The cut is the selection criteria
922 to be added to the ParticleList. It can be an empty string.
923 writeOut (bool): whether RootOutput module should save the created ParticleList
924 path (basf2.Path): modules are added to this path
925 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
926 using a mass hypothesis of the exact type passed to fillParticleLists().
927 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
928 in terms of mass difference will be used if the fit using exact particle
929 type is not available.
930 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
933 pload = register_module(
'ParticleLoader')
934 pload.set_name(
'ParticleLoader_' +
'PLists')
935 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
936 pload.param(
'writeOut', writeOut)
937 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
938 path.add_module(pload)
940 from ROOT
import Belle2
942 for decayString, cut
in decayStringsWithCuts:
943 if not decayDescriptor.init(decayString):
944 raise ValueError(
"Invalid decay string")
946 if decayDescriptor.getNDaughters() > 0:
950 if decayDescriptor.getMother().getLabel() !=
'V0':
951 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
952 elif decayDescriptor.getMother().getLabel() !=
'all':
955 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
959 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
961 if decayString.startswith(
"gamma"):
964 if not loadPhotonsFromKLM:
965 applyCuts(decayString,
'isFromECL', path)
968 def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False,
969 loadPhotonsFromKLM=False):
971 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
972 loads them to the StoreArray<Particle> and fills the ParticleList.
975 the :doc:`StandardParticles` functions.
977 The type of the particles to be loaded is specified via the decayString module parameter.
978 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
979 the particle. The following types of the particles can be loaded:
981 * charged final state particles (input ``mdst`` type = Tracks)
982 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
984 * neutral final state particles
985 - "gamma" (input ``mdst`` type = ECLCluster)
986 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
987 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
990 For "K_S0" and "Lambda0" you must specify the daughter ordering.
992 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
994 .. code-block:: python
996 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
999 Gammas can also be loaded from KLMClusters by explicitly setting the
1000 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
1001 done in selected use-cases and the effect should be studied carefully.
1004 For "K_L0" it is now possible to load from ECLClusters, to revert to
1005 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
1007 .. code-block:: python
1009 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
1012 decayString (str): Type of Particle and determines the name of the ParticleList.
1013 If the input MDST type is V0 the whole decay chain needs to be specified, so that
1014 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``)
1015 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1016 writeOut (bool): whether RootOutput module should save the created ParticleList
1017 path (basf2.Path): modules are added to this path
1018 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
1019 using a mass hypothesis of the exact type passed to fillParticleLists().
1020 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1021 in terms of mass difference will be used if the fit using exact particle
1022 type is not available.
1023 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
1026 pload = register_module(
'ParticleLoader')
1027 pload.set_name(
'ParticleLoader_' + decayString)
1028 pload.param(
'decayStrings', [decayString])
1029 pload.param(
'writeOut', writeOut)
1030 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1031 path.add_module(pload)
1034 from ROOT
import Belle2
1036 if not decayDescriptor.init(decayString):
1037 raise ValueError(
"Invalid decay string")
1038 if decayDescriptor.getNDaughters() > 0:
1042 if decayDescriptor.getMother().getLabel() !=
'V0':
1043 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1044 elif decayDescriptor.getMother().getLabel() !=
'all':
1047 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1051 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1053 if decayString.startswith(
"gamma"):
1056 if not loadPhotonsFromKLM:
1057 applyCuts(decayString,
'isFromECL', path)
1060 def fillParticleListWithTrackHypothesis(decayString,
1064 enforceFitHypothesis=False,
1067 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
1069 @param decayString specifies type of Particles and determines the name of the ParticleList
1070 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1071 @param hypothesis the PDG code of the desired track hypothesis
1072 @param writeOut whether RootOutput module should save the created ParticleList
1073 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
1074 using a mass hypothesis of the exact type passed to fillParticleLists().
1075 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1076 in terms of mass difference will be used if the fit using exact particle
1077 type is not available.
1078 @param path modules are added to this path
1081 pload = register_module(
'ParticleLoader')
1082 pload.set_name(
'ParticleLoader_' + decayString)
1083 pload.param(
'decayStrings', [decayString])
1084 pload.param(
'trackHypothesis', hypothesis)
1085 pload.param(
'writeOut', writeOut)
1086 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1087 path.add_module(pload)
1089 from ROOT
import Belle2
1091 if not decayDescriptor.init(decayString):
1092 raise ValueError(
"Invalid decay string")
1093 if decayDescriptor.getMother().getLabel() !=
'all':
1096 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1100 applyCuts(decayString, cut, path)
1103 def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
1105 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
1108 You must specify the daughter ordering.
1110 .. code-block:: python
1112 fillConvertedPhotonsList('gamma:converted -> e+ e-', '', path=mypath)
1115 decayString (str): Must be gamma to an e+e- pair. You must specify the daughter ordering.
1116 Will also determine the name of the particleList.
1117 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1118 writeOut (bool): whether RootOutput module should save the created ParticleList
1119 path (basf2.Path): modules are added to this path
1125 B2ERROR(
'For Belle converted photons are available in the pre-defined list "gamma:v0mdst".')
1127 pload = register_module(
'ParticleLoader')
1128 pload.set_name(
'ParticleLoader_' + decayString)
1129 pload.param(
'decayStrings', [decayString])
1130 pload.param(
'addDaughters',
True)
1131 pload.param(
'writeOut', writeOut)
1132 path.add_module(pload)
1134 from ROOT
import Belle2
1136 if not decayDescriptor.init(decayString):
1137 raise ValueError(
"Invalid decay string")
1138 if decayDescriptor.getMother().getLabel() !=
'V0':
1141 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1145 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1148 def fillParticleListFromROE(decayString,
1151 sourceParticleListName='',
1156 Creates Particle object for each ROE of the desired type found in the
1157 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
1158 and fills the ParticleList. If useMissing is True, then the missing
1159 momentum is used instead of ROE.
1161 The type of the particles to be loaded is specified via the decayString module parameter.
1163 @param decayString specifies type of Particles and determines the name of the ParticleList.
1164 Source ROEs can be taken as a daughter list, for example:
1165 'B0:tagFromROE -> B0:signal'
1166 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1167 @param maskName Name of the ROE mask to use
1168 @param sourceParticleListName Use related ROEs to this particle list as a source
1169 @param useMissing Use missing momentum instead of ROE momentum
1170 @param writeOut whether RootOutput module should save the created ParticleList
1171 @param path modules are added to this path
1174 pload = register_module(
'ParticleLoader')
1175 pload.set_name(
'ParticleLoader_' + decayString)
1176 pload.param(
'decayStrings', [decayString])
1177 pload.param(
'writeOut', writeOut)
1178 pload.param(
'roeMaskName', maskName)
1179 pload.param(
'useMissing', useMissing)
1180 pload.param(
'sourceParticleListName', sourceParticleListName)
1181 pload.param(
'useROEs',
True)
1182 path.add_module(pload)
1184 from ROOT
import Belle2
1186 if not decayDescriptor.init(decayString):
1187 raise ValueError(
"Invalid decay string")
1191 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1194 def fillParticleListFromDummy(decayString,
1197 treatAsInvisible=True,
1201 Creates a ParticleList and fills it with dummy Particles. For self-conjugated Particles one dummy
1202 Particle is created, for Particles that are not self-conjugated one Particle and one anti-Particle is
1203 created. The four-momentum is set to zero.
1205 The type of the particles to be loaded is specified via the decayString module parameter.
1207 @param decayString specifies type of Particles and determines the name of the ParticleList
1208 @param mdstIndex sets the mdst index of Particles
1209 @param covMatrix sets the value of the diagonal covariance matrix of Particles
1210 @param treatAsInvisible whether treeFitter should treat the Particles as invisible
1211 @param writeOut whether RootOutput module should save the created ParticleList
1212 @param path modules are added to this path
1215 pload = register_module(
'ParticleLoader')
1216 pload.set_name(
'ParticleLoader_' + decayString)
1217 pload.param(
'decayStrings', [decayString])
1218 pload.param(
'useDummy',
True)
1219 pload.param(
'dummyMDSTIndex', mdstIndex)
1220 pload.param(
'dummyCovMatrix', covMatrix)
1221 pload.param(
'dummyTreatAsInvisible', treatAsInvisible)
1222 pload.param(
'writeOut', writeOut)
1223 path.add_module(pload)
1226 def fillParticleListFromMC(decayString,
1229 skipNonPrimaryDaughters=False,
1232 skipNonPrimary=False,
1235 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1236 loads them to the StoreArray<Particle> and fills the ParticleList.
1238 The type of the particles to be loaded is specified via the decayString module parameter.
1240 @param decayString specifies type of Particles and determines the name of the ParticleList
1241 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1242 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1243 sets mother-daughter relations
1244 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1245 @param writeOut whether RootOutput module should save the created ParticleList
1246 @param path modules are added to this path
1247 @param skipNonPrimary if true, skip non primary particle
1248 @param skipInitial if true, skip initial particles
1251 pload = register_module(
'ParticleLoader')
1252 pload.set_name(
'ParticleLoader_' + decayString)
1253 pload.param(
'decayStrings', [decayString])
1254 pload.param(
'addDaughters', addDaughters)
1255 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1256 pload.param(
'writeOut', writeOut)
1257 pload.param(
'useMCParticles',
True)
1258 pload.param(
'skipNonPrimary', skipNonPrimary)
1259 pload.param(
'skipInitial', skipInitial)
1260 path.add_module(pload)
1262 from ROOT
import Belle2
1264 if not decayDescriptor.init(decayString):
1265 raise ValueError(
"Invalid decay string")
1269 applyCuts(decayString, cut, path)
1272 def fillParticleListsFromMC(decayStringsWithCuts,
1274 skipNonPrimaryDaughters=False,
1277 skipNonPrimary=False,
1280 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1281 loads them to the StoreArray<Particle> and fills the ParticleLists.
1283 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
1286 .. code-block:: python
1288 kaons = ('K+:gen', '')
1289 pions = ('pi+:gen', 'pionID>0.1')
1290 fillParticleListsFromMC([kaons, pions], path=mypath)
1293 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not final state particle.
1294 Thus, when one reconstructs a particle from ``Lambda0``, that is created with
1295 ``addDaughters=True`` and ``skipNonPrimaryDaughters=True``, the particle always has ``isSignal==0``.
1296 Please set options for ``Lambda0`` to use MC-matching variables properly as follows,
1297 ``addDaughters=True`` and ``skipNonPrimaryDaughters=False``.
1299 @param decayString specifies type of Particles and determines the name of the ParticleList
1300 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1301 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1302 sets mother-daughter relations
1303 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1304 @param writeOut whether RootOutput module should save the created ParticleList
1305 @param path modules are added to this path
1306 @param skipNonPrimary if true, skip non primary particle
1307 @param skipInitial if true, skip initial particles
1310 pload = register_module(
'ParticleLoader')
1311 pload.set_name(
'ParticleLoader_' +
'PLists')
1312 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
1313 pload.param(
'addDaughters', addDaughters)
1314 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1315 pload.param(
'writeOut', writeOut)
1316 pload.param(
'useMCParticles',
True)
1317 pload.param(
'skipNonPrimary', skipNonPrimary)
1318 pload.param(
'skipInitial', skipInitial)
1319 path.add_module(pload)
1321 from ROOT
import Belle2
1323 for decayString, cut
in decayStringsWithCuts:
1324 if not decayDescriptor.init(decayString):
1325 raise ValueError(
"Invalid decay string")
1329 applyCuts(decayString, cut, path)
1332 def fillParticleListFromChargedCluster(outputParticleList,
1335 useOnlyMostEnergeticECLCluster=True,
1339 Creates the Particle object from ECLCluster and KLMCluster that are being matched with the Track of inputParticleList.
1341 @param outputParticleList The output ParticleList. Only neutral final state particles are supported.
1342 @param inputParticleList The input ParticleList that is required to have the relation to the Track object.
1343 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1344 @param useOnlyMostEnergeticECLCluster If True, only the most energetic ECLCluster among ones that are matched with the Track is
1345 used. If False, all matched ECLClusters are loaded. The default is True. Regardless of
1346 this option, the KLMCluster is loaded.
1347 @param writeOut whether RootOutput module should save the created ParticleList
1348 @param path modules are added to this path
1351 pload = register_module(
'ParticleLoader')
1352 pload.set_name(
'ParticleLoader_' + outputParticleList)
1354 pload.param(
'decayStrings', [outputParticleList])
1355 pload.param(
'sourceParticleListName', inputParticleList)
1356 pload.param(
'writeOut', writeOut)
1357 pload.param(
'loadChargedCluster',
True)
1358 pload.param(
'useOnlyMostEnergeticECLCluster', useOnlyMostEnergeticECLCluster)
1359 path.add_module(pload)
1363 applyCuts(outputParticleList, cut, path)
1366 def extractParticlesFromROE(particleLists,
1367 signalSideParticleList=None,
1372 Extract Particle objects that belong to the Rest-Of-Events and fill them into the ParticleLists.
1373 The types of the particles other than those specified by ``particleLists`` are not stored.
1374 If one creates a ROE with ``fillWithMostLikely=True`` via `buildRestOfEvent`, for example,
1375 one should create particleLists for not only ``pi+``, ``gamma``, ``K_L0`` but also other charged final state particles.
1377 When one calls the function in the main path, one has to set the argument ``signalSideParticleList`` and the signal side
1378 ParticleList must have only one candidate.
1380 .. code-block:: python
1382 buildRestOfEvent('B0:sig', fillWithMostLikely=True, path=mypath)
1384 roe_path = create_path()
1385 deadEndPath = create_path()
1386 signalSideParticleFilter('B0:sig', '', roe_path, deadEndPath)
1388 plists = ['%s:in_roe' % ptype for ptype in ['pi+', 'gamma', 'K_L0', 'K+', 'p+', 'e+', 'mu+']]
1389 extractParticlesFromROE(plists, maskName='all', path=roe_path)
1391 # one can analyze these ParticleLists in the roe_path
1393 mypath.for_each('RestOfEvent', 'RestOfEvents', roe_path)
1395 rankByLowest('B0:sig', 'deltaE', numBest=1, path=mypath)
1396 extractParticlesFromROE(plists, signalSideParticleList='B0:sig', maskName='all', path=mypath)
1398 # one can analyze these ParticleLists in the main path
1401 @param particleLists (str or list(str)) Name of output ParticleLists
1402 @param signalSideParticleList (str) Name of signal side ParticleList
1403 @param maskName (str) Name of the ROE mask to be applied on Particles
1404 @param writeOut (bool) whether RootOutput module should save the created ParticleList
1405 @param path (basf2.Path) modules are added to this path
1408 if isinstance(particleLists, str):
1409 particleLists = [particleLists]
1411 pext = register_module(
'ParticleExtractorFromROE')
1412 pext.set_name(
'ParticleExtractorFromROE_' +
'_'.join(particleLists))
1413 pext.param(
'outputListNames', particleLists)
1414 if signalSideParticleList
is not None:
1415 pext.param(
'signalSideParticleListName', signalSideParticleList)
1416 pext.param(
'maskName', maskName)
1417 pext.param(
'writeOut', writeOut)
1418 path.add_module(pext)
1421 def applyCuts(list_name, cut, path):
1423 Removes particle candidates from ``list_name`` that do not pass ``cut``
1424 (given selection criteria).
1427 require energetic pions safely inside the cdc
1429 .. code-block:: python
1431 applyCuts("pi+:mypions", "[E > 2] and thetaInCDCAcceptance", path=mypath)
1434 You must use square braces ``[`` and ``]`` for conditional statements.
1437 list_name (str): input ParticleList name
1438 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
1439 path (basf2.Path): modules are added to this path
1442 pselect = register_module(
'ParticleSelector')
1443 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
1444 pselect.param(
'decayString', list_name)
1445 pselect.param(
'cut', cut)
1446 path.add_module(pselect)
1449 def applyEventCuts(cut, path, metavariables=None):
1451 Removes events that do not pass the ``cut`` (given selection criteria).
1454 continuum events (in mc only) with more than 5 tracks
1456 .. code-block:: python
1458 applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1461 Only event-based variables are allowed in this function
1462 and only square brackets ``[`` and ``]`` for conditional statements.
1465 cut (str): Events that do not pass these selection criteria are skipped
1466 path (basf2.Path): modules are added to this path
1467 metavariables (list(str)): List of meta variables to be considered in decomposition of cut
1471 from variables
import variables
1473 def find_vars(t: tuple, var_list: list, meta_list: list) ->
None:
1474 """ Recursive helper function to find variable names """
1475 if not isinstance(t, tuple):
1477 if t[0] == b2parser.B2ExpressionParser.node_types[
'IdentifierNode']:
1480 if t[0] == b2parser.B2ExpressionParser.node_types[
'FunctionNode']:
1481 meta_list.append(list(t[1:]))
1484 if isinstance(i, tuple):
1485 find_vars(i, var_list, meta_list)
1487 def check_variable(var_list: list, metavar_ids: list) ->
None:
1488 for var_string
in var_list:
1490 orig_name = variables.resolveAlias(var_string)
1491 if orig_name != var_string:
1494 find_vars(
b2parser.parse(orig_name), var_list_temp, meta_list_temp)
1496 check_variable(var_list_temp, metavar_ids)
1497 check_meta(meta_list_temp, metavar_ids)
1500 var = variables.getVariable(var_string)
1501 if event_var_id
not in var.description:
1502 B2ERROR(f
'Variable {var_string} is not an event-based variable! "\
1503 "Please check your inputs to the applyEventCuts method!')
1505 def check_meta(meta_list: list, metavar_ids: list) ->
None:
1506 for meta_string_list
in meta_list:
1508 while meta_string_list[0]
in metavar_ids:
1510 meta_string_list.pop(0)
1511 for meta_string
in meta_string_list[0].split(
","):
1512 find_vars(
b2parser.parse(meta_string), var_list_temp, meta_string_list)
1513 if len(meta_string_list) > 0:
1514 meta_string_list.pop(0)
1515 if len(meta_string_list) == 0:
1517 if len(meta_string_list) > 1:
1518 meta_list += meta_string_list[1:]
1519 if isinstance(meta_string_list[0], list):
1520 meta_string_list = [element
for element
in meta_string_list[0]]
1522 check_variable(var_list_temp, metavar_ids)
1524 if len(meta_string_list) == 0:
1526 elif len(meta_string_list) == 1:
1527 var = variables.getVariable(meta_string_list[0])
1529 var = variables.getVariable(meta_string_list[0], meta_string_list[1].split(
","))
1531 if event_var_id
in var.description:
1534 B2ERROR(f
'Variable {var.name} is not an event-based variable! Please check your inputs to the applyEventCuts method!')
1536 event_var_id =
'[Eventbased]'
1537 metavar_ids = [
'formula',
'abs',
1541 'exp',
'log',
'log10',
1545 metavar_ids += metavariables
1549 find_vars(
b2parser.parse(cut), var_list=var_list, meta_list=meta_list)
1551 if len(var_list) == 0
and len(meta_list) == 0:
1552 B2WARNING(f
'Cut string "{cut}" has no variables for applyEventCuts helper function!')
1554 check_variable(var_list, metavar_ids)
1555 check_meta(meta_list, metavar_ids)
1557 eselect = register_module(
'VariableToReturnValue')
1558 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1559 path.add_module(eselect)
1560 empty_path = create_path()
1561 eselect.if_value(
'<1', empty_path)
1564 def reconstructDecay(decayString,
1569 candidate_limit=None,
1570 ignoreIfTooManyCandidates=True,
1571 chargeConjugation=True,
1572 allowChargeViolation=False):
1574 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1575 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1576 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1577 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1578 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1580 One can use an ``@``-sign to mark a particle as unspecified for inclusive analyses,
1581 e.g. in a DecayString: :code:`'@Xsd -> K+ pi-'`.
1583 .. seealso:: :ref:`Marker_of_unspecified_particle`
1586 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1587 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1588 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1590 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1591 This can be solved by manually randomising the lists before combining.
1595 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1596 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1598 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1599 (from the DecayString the mother and daughter ParticleLists are determined)
1600 @param cut created (mother) Particles are added to the mother ParticleList if they
1601 pass give cuts (in VariableManager style) and rejected otherwise
1602 @param dmID user specified decay mode identifier
1603 @param writeOut whether RootOutput module should save the created ParticleList
1604 @param path modules are added to this path
1605 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1606 the number of candidates is exceeded a Warning will be
1608 By default, all these candidates will be removed and event will be ignored.
1609 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1610 If no value is given the amount is limited to a sensible
1611 default. A value <=0 will disable this limit and can
1612 cause huge memory amounts so be careful.
1613 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1614 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1615 otherwise, number of candidates in candidate_limit is reconstructed.
1616 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1617 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1620 pmake = register_module(
'ParticleCombiner')
1621 pmake.set_name(
'ParticleCombiner_' + decayString)
1622 pmake.param(
'decayString', decayString)
1623 pmake.param(
'cut', cut)
1624 pmake.param(
'decayMode', dmID)
1625 pmake.param(
'writeOut', writeOut)
1626 if candidate_limit
is not None:
1627 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1628 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1629 pmake.param(
'chargeConjugation', chargeConjugation)
1630 pmake.param(
"allowChargeViolation", allowChargeViolation)
1631 path.add_module(pmake)
1634 def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1636 Creates a new Particle as the combination of all Particles from all
1637 provided inputParticleLists. However, each particle is used only once
1638 (even if duplicates are provided) and the combination has to pass the
1639 specified selection criteria to be saved in the newly created (mother)
1642 @param inputParticleLists List of input particle lists which are combined to the new Particle
1643 @param outputList Name of the particle combination created with this module
1644 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1645 these given cuts (in VariableManager style) and is rejected otherwise
1646 @param writeOut whether RootOutput module should save the created ParticleList
1647 @param path module is added to this path
1650 pmake = register_module(
'AllParticleCombiner')
1651 pmake.set_name(
'AllParticleCombiner_' + outputList)
1652 pmake.param(
'inputListNames', inputParticleLists)
1653 pmake.param(
'outputListName', outputList)
1654 pmake.param(
'cut', cut)
1655 pmake.param(
'writeOut', writeOut)
1656 path.add_module(pmake)
1659 def reconstructMissingKlongDecayExpert(decayString,
1666 Creates a list of K_L0's with their momentum determined from kinematic constraints of B->K_L0 + something else.
1668 @param decayString DecayString specifying what kind of the decay should be reconstructed
1669 (from the DecayString the mother and daughter ParticleLists are determined)
1670 @param cut Particles are added to the K_L0 ParticleList if they
1671 pass the given cuts (in VariableManager style) and rejected otherwise
1672 @param dmID user specified decay mode identifier
1673 @param writeOut whether RootOutput module should save the created ParticleList
1674 @param path modules are added to this path
1675 @param recoList suffix appended to original K_L0 ParticleList that identifies the newly created K_L0 list
1678 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1679 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1680 pcalc.param(
'decayString', decayString)
1681 pcalc.param(
'cut', cut)
1682 pcalc.param(
'decayMode', dmID)
1683 pcalc.param(
'writeOut', writeOut)
1684 pcalc.param(
'recoList', recoList)
1685 path.add_module(pcalc)
1687 rmake = register_module(
'KlongDecayReconstructorExpert')
1688 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1689 rmake.param(
'decayString', decayString)
1690 rmake.param(
'cut', cut)
1691 rmake.param(
'decayMode', dmID)
1692 rmake.param(
'writeOut', writeOut)
1693 rmake.param(
'recoList', recoList)
1694 path.add_module(rmake)
1697 def setBeamConstrainedMomentum(particleList, decayStringTarget, decayStringDaughters, path=None):
1699 Replace the four-momentum of the target Particle by p(beam) - p(selected daughters).
1700 The momentum of the mother Particle will not be changed.
1702 @param particleList mother Particlelist
1703 @param decayStringTarget DecayString specifying the target particle whose momentum
1705 @param decayStringDaughters DecayString specifying the daughter particles used to replace
1706 the momentum of the target particle by p(beam)-p(daughters)
1709 mod = register_module(
'ParticleMomentumUpdater')
1710 mod.set_name(
'ParticleMomentumUpdater' + particleList)
1711 mod.param(
'particleList', particleList)
1712 mod.param(
'decayStringTarget', decayStringTarget)
1713 mod.param(
'decayStringDaughters', decayStringDaughters)
1714 path.add_module(mod)
1717 def updateKlongKinematicsExpert(particleList,
1721 Calculates and updates the kinematics of B->K_L0 + something else with same method as
1722 `reconstructMissingKlongDecayExpert`. This helps to revert the kinematics after the vertex fitting.
1724 @param particleList input ParticleList of B meson that decays to K_L0 + X
1725 @param writeOut whether RootOutput module should save the ParticleList
1726 @param path modules are added to this path
1729 mod = register_module(
'KlongMomentumUpdaterExpert')
1730 mod.set_name(
'KlongMomentumUpdaterExpert_' + particleList)
1731 mod.param(
'listName', particleList)
1732 mod.param(
'writeOut', writeOut)
1733 path.add_module(mod)
1736 def replaceMass(replacerName, particleLists=None, pdgCode=22, path=None):
1738 replaces the mass of the particles inside the given particleLists
1739 with the invariant mass of the particle corresponding to the given pdgCode.
1741 @param particleLists new ParticleList filled with copied Particles
1742 @param pdgCode PDG code for mass reference
1743 @param path modules are added to this path
1746 if particleLists
is None:
1750 pmassupdater = register_module(
'ParticleMassUpdater')
1751 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1752 pmassupdater.param(
'particleLists', particleLists)
1753 pmassupdater.param(
'pdgCode', pdgCode)
1754 path.add_module(pmassupdater)
1757 def reconstructRecoil(decayString,
1762 candidate_limit=None,
1763 allowChargeViolation=False):
1765 Creates new Particles that recoil against the input particles.
1767 For example the decay string M -> D1 D2 D3 will:
1768 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1769 - Particles D1, D2, D3 will be appended as daughters to M
1770 - the 4-momentum of the mother Particle M is given by
1771 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1773 @param decayString DecayString specifying what kind of the decay should be reconstructed
1774 (from the DecayString the mother and daughter ParticleLists are determined)
1775 @param cut created (mother) Particles are added to the mother ParticleList if they
1776 pass give cuts (in VariableManager style) and rejected otherwise
1777 @param dmID user specified decay mode identifier
1778 @param writeOut whether RootOutput module should save the created ParticleList
1779 @param path modules are added to this path
1780 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1781 the number of candidates is exceeded no candidate will be
1782 reconstructed for that event and a Warning will be
1784 If no value is given the amount is limited to a sensible
1785 default. A value <=0 will disable this limit and can
1786 cause huge memory amounts so be careful.
1787 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1790 pmake = register_module(
'ParticleCombiner')
1791 pmake.set_name(
'ParticleCombiner_' + decayString)
1792 pmake.param(
'decayString', decayString)
1793 pmake.param(
'cut', cut)
1794 pmake.param(
'decayMode', dmID)
1795 pmake.param(
'writeOut', writeOut)
1796 pmake.param(
'recoilParticleType', 1)
1797 if candidate_limit
is not None:
1798 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1799 pmake.param(
'allowChargeViolation', allowChargeViolation)
1800 path.add_module(pmake)
1803 def reconstructRecoilDaughter(decayString,
1808 candidate_limit=None,
1809 allowChargeViolation=False):
1811 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1813 For example the decay string M -> D1 D2 D3 will:
1814 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1815 - Particles D1, D2, D3 will be appended as daughters to M
1816 - the 4-momentum of the mother Particle M is given by
1817 p(M) = p(D1) - Sum_i p(Di), where i>1
1819 @param decayString DecayString specifying what kind of the decay should be reconstructed
1820 (from the DecayString the mother and daughter ParticleLists are determined)
1821 @param cut created (mother) Particles are added to the mother ParticleList if they
1822 pass give cuts (in VariableManager style) and rejected otherwise
1823 @param dmID user specified decay mode identifier
1824 @param writeOut whether RootOutput module should save the created ParticleList
1825 @param path modules are added to this path
1826 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1827 the number of candidates is exceeded no candidate will be
1828 reconstructed for that event and a Warning will be
1830 If no value is given the amount is limited to a sensible
1831 default. A value <=0 will disable this limit and can
1832 cause huge memory amounts so be careful.
1833 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1834 daughter is actually the mother
1837 pmake = register_module(
'ParticleCombiner')
1838 pmake.set_name(
'ParticleCombiner_' + decayString)
1839 pmake.param(
'decayString', decayString)
1840 pmake.param(
'cut', cut)
1841 pmake.param(
'decayMode', dmID)
1842 pmake.param(
'writeOut', writeOut)
1843 pmake.param(
'recoilParticleType', 2)
1844 if candidate_limit
is not None:
1845 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1846 pmake.param(
'allowChargeViolation', allowChargeViolation)
1847 path.add_module(pmake)
1850 def rankByHighest(particleList,
1854 allowMultiRank=False,
1856 overwriteRank=False,
1859 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1860 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1861 The list is also sorted from best to worst candidate
1862 (each charge, e.g. B+/B-, separately).
1863 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1864 a non-zero value for 'numBest'.
1867 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1868 These variable names can become clunky, so it's probably a good idea to set an alias.
1869 For example if you rank your B candidates by momentum,
1873 rankByHighest("B0:myCandidates", "p", path=mypath)
1874 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1877 @param particleList The input ParticleList
1878 @param variable Variable to order Particles by.
1879 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1880 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1881 @param allowMultiRank If true, candidates with the same value will get the same rank.
1882 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1883 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1884 @param path modules are added to this path
1887 bcs = register_module(
'BestCandidateSelection')
1888 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1889 bcs.param(
'particleList', particleList)
1890 bcs.param(
'variable', variable)
1891 bcs.param(
'numBest', numBest)
1892 bcs.param(
'outputVariable', outputVariable)
1893 bcs.param(
'allowMultiRank', allowMultiRank)
1894 bcs.param(
'cut', cut)
1895 bcs.param(
'overwriteRank', overwriteRank)
1896 path.add_module(bcs)
1899 def rankByLowest(particleList,
1903 allowMultiRank=False,
1905 overwriteRank=False,
1908 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1909 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1910 The list is also sorted from best to worst candidate
1911 (each charge, e.g. B+/B-, separately).
1912 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1913 a non-zero value for 'numBest'.
1916 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1917 These variable names can become clunky, so it's probably a good idea to set an alias.
1918 For example if you rank your B candidates by :b2:var:`dM`,
1922 rankByLowest("B0:myCandidates", "dM", path=mypath)
1923 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1926 @param particleList The input ParticleList
1927 @param variable Variable to order Particles by.
1928 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1929 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1930 @param allowMultiRank If true, candidates with the same value will get the same rank.
1931 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1932 @param overwriteRank If true, the extraInfo of rank is overwritten when the particle has already the extraInfo.
1933 @param path modules are added to this path
1936 bcs = register_module(
'BestCandidateSelection')
1937 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1938 bcs.param(
'particleList', particleList)
1939 bcs.param(
'variable', variable)
1940 bcs.param(
'numBest', numBest)
1941 bcs.param(
'selectLowest',
True)
1942 bcs.param(
'allowMultiRank', allowMultiRank)
1943 bcs.param(
'outputVariable', outputVariable)
1944 bcs.param(
'cut', cut)
1945 bcs.param(
'overwriteRank', overwriteRank)
1946 path.add_module(bcs)
1949 def applyRandomCandidateSelection(particleList, path=None):
1951 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1952 This is done on a event-by-event basis.
1954 @param particleList ParticleList for which the random candidate selection should be applied
1955 @param path module is added to this path
1958 rcs = register_module(
'BestCandidateSelection')
1959 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1960 rcs.param(
'particleList', particleList)
1961 rcs.param(
'variable',
'random')
1962 rcs.param(
'selectLowest',
False)
1963 rcs.param(
'allowMultiRank',
False)
1964 rcs.param(
'numBest', 1)
1965 rcs.param(
'cut',
'')
1966 rcs.param(
'outputVariable',
'')
1967 path.add_module(rcs)
1972 Prints the contents of DataStore in the first event (or a specific event number or all events).
1973 Will list all objects and arrays (including size).
1976 The command line tool: ``b2file-size``.
1979 eventNumber (int): Print the datastore only for this event. The default
1980 (-1) prints only the first event, 0 means print for all events (can produce large output)
1981 path (basf2.Path): the PrintCollections module is added to this path
1984 This will print a lot of output if you print it for all events and process many events.
1988 printDS = register_module(
'PrintCollections')
1989 printDS.param(
'printForEvent', eventNumber)
1990 path.add_module(printDS)
1993 def printVariableValues(list_name, var_names, path):
1995 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
1997 @param list_name input ParticleList name
1998 @param var_names vector of variable names to be printed
1999 @param path modules are added to this path
2002 prlist = register_module(
'ParticlePrinter')
2003 prlist.set_name(
'ParticlePrinter_' + list_name)
2004 prlist.param(
'listName', list_name)
2005 prlist.param(
'fullPrint',
False)
2006 prlist.param(
'variables', var_names)
2007 path.add_module(prlist)
2010 def printList(list_name, full, path):
2012 Prints the size and executes Particle->print() (if full=True)
2013 method for all Particles in given ParticleList. For debugging purposes.
2015 @param list_name input ParticleList name
2016 @param full execute Particle->print() method for all Particles
2017 @param path modules are added to this path
2020 prlist = register_module(
'ParticlePrinter')
2021 prlist.set_name(
'ParticlePrinter_' + list_name)
2022 prlist.param(
'listName', list_name)
2023 prlist.param(
'fullPrint', full)
2024 path.add_module(prlist)
2027 def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None, basketsize=1600,
2028 signalSideParticleList="", filenameSuffix="", useFloat=False, storeEventType=True):
2030 Creates and fills a flat ntuple with the specified variables from the VariableManager.
2031 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
2032 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
2035 decayString (str): specifies type of Particles and determines the name of the ParticleList
2036 variables (list(str)): the list of variables (which must be registered in the VariableManager)
2037 treename (str): name of the ntuple tree
2038 filename (str): which is used to store the variables
2039 path (basf2.Path): the basf2 path where the analysis is processed
2040 basketsize (int): size of baskets in the output ntuple in bytes
2041 signalSideParticleList (str): The name of the signal-side ParticleList.
2042 Only valid if the module is called in a for_each loop over the RestOfEvent.
2043 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2044 useFloat (bool): Use single precision (float) instead of double precision (double)
2045 for floating-point numbers.
2046 storeEventType (bool) : if true, the branch __eventType__ is added for the MC event type information.
2047 The information is available from MC16 on.
2049 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2052 output = register_module(
'VariablesToNtuple')
2053 output.set_name(
'VariablesToNtuple_' + decayString)
2054 output.param(
'particleList', decayString)
2055 output.param(
'variables', variables)
2056 output.param(
'fileName', filename)
2057 output.param(
'treeName', treename)
2058 output.param(
'basketSize', basketsize)
2059 output.param(
'signalSideParticleList', signalSideParticleList)
2060 output.param(
'fileNameSuffix', filenameSuffix)
2061 output.param(
'useFloat', useFloat)
2062 output.param(
'storeEventType', storeEventType)
2063 path.add_module(output)
2069 filename='ntuple.root',
2072 prefixDecayString=False,
2075 Creates and fills a flat ntuple with the specified variables from the VariableManager
2078 decayString (str): specifies type of Particles and determines the name of the ParticleList
2079 variables (list(tuple))): variables + binning which must be registered in the VariableManager
2080 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
2081 filename (str): which is used to store the variables
2082 path (basf2.Path): the basf2 path where the analysis is processed
2083 directory (str): directory inside the output file where the histograms should be saved.
2084 Useful if you want to have different histograms in the same file to separate them.
2085 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
2086 programmatic naming of the structure in the file.
2087 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2089 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2092 if variables_2d
is None:
2094 output = register_module(
'VariablesToHistogram')
2095 output.set_name(
'VariablesToHistogram_' + decayString)
2096 output.param(
'particleList', decayString)
2097 output.param(
'variables', variables)
2098 output.param(
'variables_2d', variables_2d)
2099 output.param(
'fileName', filename)
2100 output.param(
'fileNameSuffix', filenameSuffix)
2101 if directory
is not None or prefixDecayString:
2102 if directory
is None:
2104 if prefixDecayString:
2105 directory = decayString +
"_" + directory
2106 output.param(
"directory", directory)
2107 path.add_module(output)
2112 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
2113 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
2116 particleList (str): The input ParticleList
2117 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2118 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2119 An existing extra info with the same name will be overwritten if the new
2120 value is lower / will never be overwritten / will be overwritten if the
2121 new value is higher / will always be overwritten (option = -1/0/1/2).
2122 path (basf2.Path): modules are added to this path
2125 mod = register_module(
'VariablesToExtraInfo')
2126 mod.set_name(
'VariablesToExtraInfo_' + particleList)
2127 mod.param(
'particleList', particleList)
2128 mod.param(
'variables', variables)
2129 mod.param(
'overwrite', option)
2130 path.add_module(mod)
2133 def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
2135 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
2136 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
2137 to specified daughter particle.
2140 particleList (str): The input ParticleList
2141 decayString (str): Decay string that specifies to which daughter the extra info should be appended
2142 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2143 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2144 An existing extra info with the same name will be overwritten if the new
2145 value is lower / will never be overwritten / will be overwritten if the
2146 new value is higher / will always be overwritten (option = -1/0/1/2).
2147 path (basf2.Path): modules are added to this path
2150 mod = register_module(
'VariablesToExtraInfo')
2151 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
2152 mod.param(
'particleList', particleList)
2153 mod.param(
'decayString', decayString)
2154 mod.param(
'variables', variables)
2155 mod.param(
'overwrite', option)
2156 path.add_module(mod)
2159 def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
2161 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
2162 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
2165 When the function is called first time not in the main path but in a sub-path e.g. ``roe_path``,
2166 the eventExtraInfo cannot be accessed from the main path because of the shorter lifetime of the event-extra-info field.
2167 If one wants to call the function in a sub-path, one has to call the function in the main path beforehand.
2170 particleList (str): The input ParticleList
2171 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2172 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2173 An existing extra info with the same name will be overwritten if the new
2174 value is lower / will never be overwritten / will be overwritten if the
2175 new value is higher / will always be overwritten (option = -1/0/1/2).
2176 path (basf2.Path): modules are added to this path
2179 mod = register_module(
'VariablesToEventExtraInfo')
2180 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
2181 mod.param(
'particleList', particleList)
2182 mod.param(
'variables', variables)
2183 mod.param(
'overwrite', option)
2184 path.add_module(mod)
2187 def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
2189 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
2190 particle) as an extra info to the particle related to current ROE.
2191 Should be used only in the for_each roe path.
2194 particleList (str): The input ParticleList
2195 varToExtraInfo (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2196 path (basf2.Path): modules are added to this path
2199 mod = register_module(
'SignalSideVariablesToExtraInfo')
2200 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
2201 mod.param(
'particleListName', particleList)
2202 mod.param(
'variableToExtraInfo', varToExtraInfo)
2203 path.add_module(mod)
2206 def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
2208 Define and blind a signal region.
2209 Per default, the defined signal region is cut out if ran on data.
2210 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
2214 .. code-block:: python
2216 ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
2217 ma.signalRegion("B+:sig",
2218 "Mbc>5.27 and abs(deltaE)<0.2",
2221 ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
2224 particleList (str): The input ParticleList
2225 cut (str): Cut string describing the signal region
2226 path (basf2.Path):: Modules are added to this path
2227 name (str): Name of the Signal region in the variable manager
2228 blind_data (bool): Automatically exclude signal region from data
2232 from variables
import variables
2233 mod = register_module(
'VariablesToExtraInfo')
2234 mod.set_name(f
'{name}_' + particleList)
2235 mod.param(
'particleList', particleList)
2236 mod.param(
'variables', {f
"passesCut({cut})": name})
2237 variables.addAlias(name, f
"extraInfo({name})")
2238 path.add_module(mod)
2242 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
2245 def removeExtraInfo(particleLists=None, removeEventExtraInfo=False, path=None):
2247 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
2250 if particleLists
is None:
2252 mod = register_module(
'ExtraInfoRemover')
2253 mod.param(
'particleLists', particleLists)
2254 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
2255 path.add_module(mod)
2258 def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
2260 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2261 to the particle from the input ParticleList. Additional selection criteria can be applied.
2262 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2263 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2264 suggests should be empty and its purpose is to end the execution of for_each roe path for
2265 the current ROE object.
2267 @param particleList The input ParticleList
2268 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2269 @param for_each roe path in which this filter is executed
2270 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2273 mod = register_module(
'SignalSideParticleFilter')
2274 mod.set_name(
'SigSideParticleFilter_' + particleList)
2275 mod.param(
'particleLists', [particleList])
2276 mod.param(
'selection', selection)
2277 roe_path.add_module(mod)
2278 mod.if_false(deadEndPath)
2281 def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
2283 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2284 to the particle from the input ParticleList. Additional selection criteria can be applied.
2285 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2286 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2287 suggests should be empty and its purpose is to end the execution of for_each roe path for
2288 the current ROE object.
2290 @param particleLists The input ParticleLists
2291 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2292 @param for_each roe path in which this filter is executed
2293 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2296 mod = register_module(
'SignalSideParticleFilter')
2297 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
2298 mod.param(
'particleLists', particleLists)
2299 mod.param(
'selection', selection)
2300 roe_path.add_module(mod)
2301 mod.if_false(deadEndPath)
2310 chargeConjugation=True,
2313 Finds and creates a ``ParticleList`` from given decay string.
2314 ``ParticleList`` of daughters with sub-decay is created.
2316 Only the particles made from MCParticle, which can be loaded by `fillParticleListFromMC`, are accepted as daughters.
2318 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
2319 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
2322 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
2323 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
2324 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
2327 It is recommended to use only primary particles as daughter particles unless you want to explicitly study the secondary
2328 particles. The behavior of MC-matching for secondary particles from a stable particle decay is not guaranteed.
2329 Please consider to use `fillParticleListFromMC` with ``skipNonPrimary=True`` to load daughter particles.
2330 Moreover, it is recommended to load ``K_S0`` and ``Lambda0`` directly from MCParticle by `fillParticleListFromMC` rather
2331 than reconstructing from two pions or a proton-pion pair, because their direct daughters can be the secondary particle.
2334 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
2335 (from the DecayString the mother and daughter ParticleLists are determined)
2336 @param cut created (mother) Particles are added to the mother ParticleList if they
2337 pass given cuts (in VariableManager style) and rejected otherwise
2338 isSignal==1 is always required by default.
2339 @param dmID user specified decay mode identifier
2340 @param writeOut whether RootOutput module should save the created ParticleList
2341 @param path modules are added to this path
2342 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
2345 pmake = register_module(
'ParticleCombinerFromMC')
2346 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
2347 pmake.param(
'decayString', decayString)
2348 pmake.param(
'cut', cut)
2349 pmake.param(
'decayMode', dmID)
2350 pmake.param(
'writeOut', writeOut)
2351 pmake.param(
'chargeConjugation', chargeConjugation)
2352 path.add_module(pmake)
2359 appendAllDaughters=False,
2360 skipNonPrimaryDaughters=True,
2364 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
2365 The decay string is required to describe correctly what you want.
2366 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
2368 The output particles has only the daughter particles written in the given decay string, if
2369 ``appendAllDaughters=False`` (default). If ``appendAllDaughters=True``, all daughters of the matched MCParticle are
2370 appended in the order defined at the MCParticle level. For example,
2372 .. code-block:: python
2374 findMCDecay('B0:Xee', 'B0 -> e+ e- ... ?gamma', appendAllDaughters=False, path=mypath)
2376 The output ParticleList ``B0:Xee`` will match the inclusive ``B0 -> e+ e-`` decays (but neutrinos are not included),
2377 in both cases of ``appendAllDaughters`` is false and true.
2378 If the ``appendAllDaughters=False`` as above example, the ``B0:Xee`` has only two electrons as daughters.
2379 While, if ``appendAllDaughters=True``, all daughters of the matched MCParticles are appended. When the truth decay mode of
2380 the MCParticle is ``B0 -> [K*0 -> K+ pi-] [J/psi -> e+ e-]``, the first daughter of ``B0:Xee`` is ``K*0`` and ``e+``
2381 will be the first daughter of second daughter of ``B0:Xee``.
2383 The option ``skipNonPrimaryDaughters`` only has an effect if ``appendAllDaughters=True``. If ``skipNonPrimaryDaughters=True``,
2384 all primary daughters are appended but the secondary particles are not.
2387 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not a final state particle.
2388 In order for the MCMatching to work properly, the daughters of ``Lambda0`` are appended to
2389 ``Lambda0`` regardless of the value of the option ``skipNonPrimaryDaughters``.
2392 @param list_name The output particle list name
2393 @param decay The decay string which you want
2394 @param writeOut Whether `RootOutput` module should save the created ``outputList``
2395 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
2396 @param appendAllDaughters if true, not only the daughters described in the decay string but all daughters are appended
2397 @param path modules are added to this path
2400 decayfinder = register_module(
'MCDecayFinder')
2401 decayfinder.set_name(
'MCDecayFinder_' + list_name)
2402 decayfinder.param(
'listName', list_name)
2403 decayfinder.param(
'decayString', decay)
2404 decayfinder.param(
'appendAllDaughters', appendAllDaughters)
2405 decayfinder.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
2406 decayfinder.param(
'writeOut', writeOut)
2407 path.add_module(decayfinder)
2410 def summaryOfLists(particleLists, outputFile=None, path=None):
2412 Prints out Particle statistics at the end of the job: number of events with at
2413 least one candidate, average number of candidates per event, etc.
2414 If an output file name is provided the statistics is also dumped into a json file with that name.
2416 @param particleLists list of input ParticleLists
2417 @param outputFile output file name (not created by default)
2420 particleStats = register_module(
'ParticleStats')
2421 particleStats.param(
'particleLists', particleLists)
2422 if outputFile
is not None:
2423 particleStats.param(
'outputFile', outputFile)
2424 path.add_module(particleStats)
2427 def matchMCTruth(list_name, path):
2429 Performs MC matching (sets relation Particle->MCParticle) for
2430 all particles (and its (grand)^N-daughter particles) in the specified
2433 @param list_name name of the input ParticleList
2434 @param path modules are added to this path
2437 mcMatch = register_module(
'MCMatcherParticles')
2438 mcMatch.set_name(
'MCMatch_' + list_name)
2439 mcMatch.param(
'listName', list_name)
2440 path.add_module(mcMatch)
2443 def looseMCTruth(list_name, path):
2445 Performs loose MC matching for all particles in the specified
2447 The difference between loose and normal mc matching algorithm is that
2448 the loose algorithm will find the common mother of the majority of daughter
2449 particles while the normal algorithm finds the common mother of all daughters.
2450 The results of loose mc matching algorithm are stored to the following extraInfo
2453 - looseMCMotherPDG: PDG code of most common mother
2454 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
2455 - looseMCWrongDaughterN: number of daughters that don't originate from the most common mother
2456 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from the most common mother (only if
2457 looseMCWrongDaughterN = 1)
2458 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background Particle
2460 @param list_name name of the input ParticleList
2461 @param path modules are added to this path
2464 mcMatch = register_module(
'MCMatcherParticles')
2465 mcMatch.set_name(
'LooseMCMatch_' + list_name)
2466 mcMatch.param(
'listName', list_name)
2467 mcMatch.param(
'looseMCMatching',
True)
2468 path.add_module(mcMatch)
2471 def buildRestOfEvent(target_list_name, inputParticlelists=None,
2472 fillWithMostLikely=True,
2473 chargedPIDPriors=None, path=None):
2475 Creates for each Particle in the given ParticleList a RestOfEvent
2476 dataobject and makes basf2 relation between them. User can provide additional
2477 particle lists with a different particle hypothesis like ['K+:good, e+:good'], etc.
2479 @param target_list_name name of the input ParticleList
2480 @param inputParticlelists list of user-defined input particle list names, which serve
2481 as source of particles to build the ROE, the FSP particles from
2482 target_list_name are automatically excluded from the ROE object
2483 @param fillWithMostLikely By default the module uses the most likely particle mass hypothesis for charged particles
2484 based on the PID likelihood. Turn this behavior off if you want to configure your own
2485 input particle lists.
2486 @param chargedPIDPriors The prior PID fractions, that are used to regulate the
2487 amount of certain charged particle species, should be a list of
2488 six floats if not None. The order of particle types is
2489 the following: [e-, mu-, pi-, K-, p+, d+]
2490 @param path modules are added to this path
2493 if inputParticlelists
is None:
2494 inputParticlelists = []
2495 fillParticleList(
'pi+:all',
'', path=path)
2496 if fillWithMostLikely:
2497 from stdCharged
import stdMostLikely
2498 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
2499 inputParticlelists = [f
'{ptype}:mostlikely_roe' for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
2502 fillParticleList(
'gamma:all',
'', path=path)
2503 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
2504 inputParticlelists += [
'pi+:all',
'gamma:all',
'K_L0:roe_default']
2506 inputParticlelists += [
'pi+:all',
'gamma:mdst']
2507 roeBuilder = register_module(
'RestOfEventBuilder')
2508 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
2509 roeBuilder.param(
'particleList', target_list_name)
2510 roeBuilder.param(
'particleListsInput', inputParticlelists)
2511 roeBuilder.param(
'mostLikely', fillWithMostLikely)
2512 path.add_module(roeBuilder)
2515 def buildNestedRestOfEvent(target_list_name, maskName='all', path=None):
2517 Creates for each Particle in the given ParticleList a RestOfEvent
2518 @param target_list_name name of the input ParticleList
2519 @param mask_name name of the ROEMask to be used
2520 @param path modules are added to this path
2523 roeBuilder = register_module(
'RestOfEventBuilder')
2524 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
2525 roeBuilder.param(
'particleList', target_list_name)
2526 roeBuilder.param(
'nestedROEMask', maskName)
2527 roeBuilder.param(
'createNestedROE',
True)
2528 path.add_module(roeBuilder)
2531 def buildRestOfEventFromMC(target_list_name, inputParticlelists=None, path=None):
2533 Creates for each Particle in the given ParticleList a RestOfEvent
2534 @param target_list_name name of the input ParticleList
2535 @param inputParticlelists list of input particle list names, which serve
2536 as a source of particles to build ROE, the FSP particles from
2537 target_list_name are excluded from ROE object
2538 @param path modules are added to this path
2541 if inputParticlelists
is None:
2542 inputParticlelists = []
2543 if (len(inputParticlelists) == 0):
2547 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
2548 'n0',
'nu_e',
'nu_mu',
'nu_tau',
2551 fillParticleListFromMC(f
"{t}:roe_default_gen",
'mcPrimary > 0 and nDaughters == 0',
2552 True,
True, path=path)
2553 inputParticlelists += [f
"{t}:roe_default_gen"]
2554 roeBuilder = register_module(
'RestOfEventBuilder')
2555 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
2556 roeBuilder.param(
'particleList', target_list_name)
2557 roeBuilder.param(
'particleListsInput', inputParticlelists)
2558 roeBuilder.param(
'fromMC',
True)
2559 path.add_module(roeBuilder)
2562 def appendROEMask(list_name,
2565 eclClusterSelection,
2566 klmClusterSelection='',
2569 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2570 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
2572 - append a ROE mask with all tracks in ROE coming from the IP region
2574 .. code-block:: python
2576 appendROEMask('B+:sig', 'IPtracks', '[dr < 2] and [abs(dz) < 5]', path=mypath)
2578 - append a ROE mask with only ECL-based particles that pass as good photon candidates
2580 .. code-block:: python
2582 goodPhotons = 'inCDCAcceptance and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
2583 appendROEMask('B+:sig', 'goodROEGamma', '', goodPhotons, path=mypath)
2586 @param list_name name of the input ParticleList
2587 @param mask_name name of the appended ROEMask
2588 @param trackSelection decay string for the track-based particles in ROE
2589 @param eclClusterSelection decay string for the ECL-based particles in ROE
2590 @param klmClusterSelection decay string for the KLM-based particles in ROE
2591 @param path modules are added to this path
2594 roeMask = register_module(
'RestOfEventInterpreter')
2595 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2596 roeMask.param(
'particleList', list_name)
2597 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2598 path.add_module(roeMask)
2601 def appendROEMasks(list_name, mask_tuples, path=None):
2603 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2604 selection criteria for track-, ECL- and KLM-based particles which will be used by ROE variables.
2606 The multiple ROE masks with their own selection criteria are specified
2607 via list of tuples (mask_name, trackParticleSelection, eclParticleSelection, klmParticleSelection) or
2608 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
2610 - Example for two tuples, one with and one without fractions
2612 .. code-block:: python
2614 ipTracks = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', '')
2615 goodPhotons = 'inCDCAcceptance and [clusterErrorTiming < 1e6] and [clusterE1E9 > 0.4 or E > 0.075]'
2616 goodROEGamma = ('ROESel', '[dr < 2] and [abs(dz) < 5]', goodPhotons, '')
2617 goodROEKLM = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', 'nKLMClusterTrackMatches == 0')
2618 appendROEMasks('B+:sig', [ipTracks, goodROEGamma, goodROEKLM], path=mypath)
2620 @param list_name name of the input ParticleList
2621 @param mask_tuples array of ROEMask list tuples to be appended
2622 @param path modules are added to this path
2625 compatible_masks = []
2626 for mask
in mask_tuples:
2629 compatible_masks += [(*mask,
'')]
2631 compatible_masks += [mask]
2632 roeMask = register_module(
'RestOfEventInterpreter')
2633 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2634 roeMask.param(
'particleList', list_name)
2635 roeMask.param(
'ROEMasks', compatible_masks)
2636 path.add_module(roeMask)
2639 def updateROEMask(list_name,
2642 eclClusterSelection='',
2643 klmClusterSelection='',
2646 Update an existing ROE mask by applying additional selection cuts for
2647 tracks and/or clusters.
2649 See function `appendROEMask`!
2651 @param list_name name of the input ParticleList
2652 @param mask_name name of the ROEMask to update
2653 @param trackSelection decay string for the track-based particles in ROE
2654 @param eclClusterSelection decay string for the ECL-based particles in ROE
2655 @param klmClusterSelection decay string for the KLM-based particles in ROE
2656 @param path modules are added to this path
2659 roeMask = register_module(
'RestOfEventInterpreter')
2660 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2661 roeMask.param(
'particleList', list_name)
2662 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2663 roeMask.param(
'update',
True)
2664 path.add_module(roeMask)
2667 def updateROEMasks(list_name, mask_tuples, path):
2669 Update existing ROE masks by applying additional selection cuts for tracks
2672 The multiple ROE masks with their own selection criteria are specified
2673 via list tuples (mask_name, trackSelection, eclClusterSelection, klmClusterSelection)
2675 See function `appendROEMasks`!
2677 @param list_name name of the input ParticleList
2678 @param mask_tuples array of ROEMask list tuples to be appended
2679 @param path modules are added to this path
2682 compatible_masks = []
2683 for mask
in mask_tuples:
2686 compatible_masks += [(*mask,
'')]
2688 compatible_masks += [mask]
2690 roeMask = register_module(
'RestOfEventInterpreter')
2691 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2692 roeMask.param(
'particleList', list_name)
2693 roeMask.param(
'ROEMasks', compatible_masks)
2694 roeMask.param(
'update',
True)
2695 path.add_module(roeMask)
2698 def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2700 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2701 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2702 This function should be executed only in the for_each roe path for the current ROE object.
2704 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2705 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2706 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2707 pion particle list (e.g. 'pi+:someLabel').
2709 Updating a non-existing mask will create a new one.
2711 - keep only those tracks that were used in provided particle list
2713 .. code-block:: python
2715 keepInROEMasks('pi+:goodTracks', 'mask', '', path=mypath)
2717 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2719 .. code-block:: python
2721 keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1', path=mypath)
2724 @param list_name name of the input ParticleList
2725 @param mask_names array of ROEMasks to be updated
2726 @param cut_string decay string with which the mask will be updated
2727 @param path modules are added to this path
2730 updateMask = register_module(
'RestOfEventUpdater')
2731 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2732 updateMask.param(
'particleList', list_name)
2733 updateMask.param(
'updateMasks', mask_names)
2734 updateMask.param(
'cutString', cut_string)
2735 updateMask.param(
'discard',
False)
2736 path.add_module(updateMask)
2739 def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2741 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2742 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2743 This function should be executed only in the for_each roe path for the current ROE object.
2745 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2746 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2747 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2748 pion particle list (e.g. 'pi+:someLabel').
2750 Updating a non-existing mask will create a new one.
2752 - discard tracks that were used in provided particle list
2754 .. code-block:: python
2756 discardFromROEMasks('pi+:badTracks', 'mask', '', path=mypath)
2758 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2760 .. code-block:: python
2762 discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1', path=mypath)
2765 @param list_name name of the input ParticleList
2766 @param mask_names array of ROEMasks to be updated
2767 @param cut_string decay string with which the mask will be updated
2768 @param path modules are added to this path
2771 updateMask = register_module(
'RestOfEventUpdater')
2772 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2773 updateMask.param(
'particleList', list_name)
2774 updateMask.param(
'updateMasks', mask_names)
2775 updateMask.param(
'cutString', cut_string)
2776 updateMask.param(
'discard',
True)
2777 path.add_module(updateMask)
2780 def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2782 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2783 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2784 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2785 passing it can be applied.
2787 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2788 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2790 Updating a non-existing mask will create a new one.
2792 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2794 .. code-block:: python
2796 optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550', path=mypath)
2798 @param list_name name of the input ParticleList
2799 @param mask_names array of ROEMasks to be updated
2800 @param cut_string decay string with which the mask will be updated
2801 @param path modules are added to this path
2804 updateMask = register_module(
'RestOfEventUpdater')
2805 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2806 updateMask.param(
'particleList', list_name)
2807 updateMask.param(
'updateMasks', mask_names)
2808 updateMask.param(
'cutString', cut_string)
2809 path.add_module(updateMask)
2812 def updateROEUsingV0Lists(target_particle_list, mask_names, default_cleanup=True, selection_cuts=None,
2813 apply_mass_fit=False, fitter='treefit', path=None):
2815 This function creates V0 particle lists (photons, :math:`K^0_S` and :math:`\\Lambda^0`)
2816 and it uses V0 candidates to update the Rest Of Event, which is associated to the target particle list.
2817 It is possible to apply a standard or customized selection and mass fit to the V0 candidates.
2820 @param target_particle_list name of the input ParticleList
2821 @param mask_names array of ROE masks to be applied
2822 @param default_cleanup if True, predefined cuts will be applied on the V0 lists
2823 @param selection_cuts a single string of selection cuts or tuple of three strings (photon_cuts, K_S0_cuts, Lambda0_cuts),
2824 which will be applied to the V0 lists. These cuts will have a priority over the default ones.
2825 @param apply_mass_fit if True, a mass fit will be applied to the V0 particles
2826 @param fitter string, that represent a fitter choice: "treefit" for TreeFitter and "kfit" for KFit
2827 @param path modules are added to this path
2830 roe_path = create_path()
2831 deadEndPath = create_path()
2832 signalSideParticleFilter(target_particle_list,
'', roe_path, deadEndPath)
2834 if (default_cleanup
and selection_cuts
is None):
2835 B2INFO(
"Using default cleanup in updateROEUsingV0Lists.")
2836 selection_cuts =
'abs(dM) < 0.1 '
2837 selection_cuts +=
'and daughter(0,particleID) > 0.2 and daughter(1,particleID) > 0.2 '
2838 selection_cuts +=
'and daughter(0,thetaInCDCAcceptance) and daughter(1,thetaInCDCAcceptance)'
2839 if (selection_cuts
is None or selection_cuts ==
''):
2840 B2INFO(
"No cleanup in updateROEUsingV0Lists.")
2841 selection_cuts = (
'True',
'True',
'True')
2842 if (isinstance(selection_cuts, str)):
2843 selection_cuts = (selection_cuts, selection_cuts, selection_cuts)
2845 roe_cuts =
'isInRestOfEvent > 0'
2846 fillConvertedPhotonsList(
'gamma:v0_roe -> e+ e-', f
'{selection_cuts[0]} and {roe_cuts}',
2848 fillParticleList(
'K_S0:v0_roe -> pi+ pi-', f
'{selection_cuts[1]} and {roe_cuts}',
2850 fillParticleList(
'Lambda0:v0_roe -> p+ pi-', f
'{selection_cuts[2]} and {roe_cuts}',
2852 fitter = fitter.lower()
2853 if (fitter !=
'treefit' and fitter !=
'kfit'):
2854 B2WARNING(
'Argument "fitter" in updateROEUsingV0Lists has only "treefit" and "kfit" options, '
2855 f
'but "{fitter}" was provided! TreeFitter will be used instead.')
2857 from vertex
import kFit, treeFit
2858 for v0
in [
'gamma:v0_roe',
'K_S0:v0_roe',
'Lambda0:v0_roe']:
2859 if (apply_mass_fit
and fitter ==
'kfit'):
2860 kFit(v0, conf_level=0.0, fit_type=
'massvertex', path=roe_path)
2861 if (apply_mass_fit
and fitter ==
'treefit'):
2862 treeFit(v0, conf_level=0.0, massConstraint=[v0.split(
':')[0]], path=roe_path)
2863 optimizeROEWithV0(v0, mask_names,
'', path=roe_path)
2864 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2867 def printROEInfo(mask_names=None, full_print=False,
2868 unpackComposites=True, path=None):
2870 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2871 It prints out basic ROE object info.
2873 If mask names are provided, specific information for those masks will be printed out.
2875 It is also possible to print out all particles in a given mask if the
2876 'full_print' is set to True.
2878 @param mask_names array of ROEMask names for printing out info
2879 @param unpackComposites if true, replace composite particles by their daughters
2880 @param full_print print out particles in mask
2881 @param path modules are added to this path
2884 if mask_names
is None:
2886 printMask = register_module(
'RestOfEventPrinter')
2887 printMask.set_name(
'RestOfEventPrinter')
2888 printMask.param(
'maskNames', mask_names)
2889 printMask.param(
'fullPrint', full_print)
2890 printMask.param(
'unpackComposites', unpackComposites)
2891 path.add_module(printMask)
2894 def buildContinuumSuppression(list_name, roe_mask, path):
2896 Creates for each Particle in the given ParticleList a ContinuumSuppression
2897 dataobject and makes basf2 relation between them.
2899 :param list_name: name of the input ParticleList
2900 :param roe_mask: name of the ROE mask
2901 :param path: modules are added to this path
2904 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2905 qqBuilder.set_name(
'QQBuilder_' + list_name)
2906 qqBuilder.param(
'particleList', list_name)
2907 qqBuilder.param(
'ROEMask', roe_mask)
2908 path.add_module(qqBuilder)
2913 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2914 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2916 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2917 @param path modules are added to this path
2920 mod = register_module(
'RemoveParticlesNotInLists')
2921 mod.param(
'particleLists', lists_to_keep)
2922 path.add_module(mod)
2925 def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2927 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2929 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2930 @param bsig_list_name Name of the Bsig ParticleList
2931 @param btag_list_name Name of the Bsig ParticleList
2932 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2935 btag = register_module(
'InclusiveBtagReconstruction')
2936 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2937 btag.param(
'upsilonListName', upsilon_list_name)
2938 btag.param(
'bsigListName', bsig_list_name)
2939 btag.param(
'btagListName', btag_list_name)
2940 btag.param(
'inputListsNames', input_lists_names)
2941 path.add_module(btag)
2944 def selectDaughters(particle_list_name, decay_string, path):
2946 Redefine the Daughters of a particle: select from decayString
2948 @param particle_list_name input particle list
2949 @param decay_string for selecting the Daughters to be preserved
2952 seld = register_module(
'SelectDaughters')
2953 seld.set_name(
'SelectDaughters_' + particle_list_name)
2954 seld.param(
'listName', particle_list_name)
2955 seld.param(
'decayString', decay_string)
2956 path.add_module(seld)
2959 def markDuplicate(particleList, prioritiseV0, path):
2961 Call DuplicateVertexMarker to find duplicate particles in a list and
2962 flag the ones that should be kept
2964 @param particleList input particle list
2965 @param prioritiseV0 if true, give V0s a higher priority
2968 markdup = register_module(
'DuplicateVertexMarker')
2969 markdup.param(
'particleList', particleList)
2970 markdup.param(
'prioritiseV0', prioritiseV0)
2971 path.add_module(markdup)
2974 PI0ETAVETO_COUNTER = 0
2977 def oldwritePi0EtaVeto(
2980 workingDirectory='.',
2981 pi0vetoname='Pi0_Prob',
2982 etavetoname='Eta_Prob',
2988 Give pi0/eta probability for hard photon.
2990 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.
2992 The current default weight files are optimised using MC9.
2993 The input variables are as below. Aliases are set to some variables during training.
2995 * M: pi0/eta candidates Invariant mass
2996 * lowE: soft photon energy in lab frame
2997 * cTheta: soft photon ECL cluster's polar angle
2998 * Zmva: soft photon output of MVA using Zernike moments of the cluster
2999 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3001 If you don't have weight files in your workingDirectory,
3002 these files are downloaded from database to your workingDirectory automatically.
3003 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
3004 about how to use this function.
3007 Please don't use following ParticleList names elsewhere:
3009 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
3010 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
3012 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
3014 @param particleList The input ParticleList
3015 @param decayString specify Particle to be added to the ParticleList
3016 @param workingDirectory The weight file directory
3017 @param downloadFlag whether download default weight files or not
3018 @param pi0vetoname extraInfo name of pi0 probability
3019 @param etavetoname extraInfo name of eta probability
3020 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
3021 @param path modules are added to this path
3026 B2ERROR(
"The old pi0 / eta veto is not suitable for Belle analyses.")
3031 global PI0ETAVETO_COUNTER
3033 if PI0ETAVETO_COUNTER == 0:
3034 from variables
import variables
3035 variables.addAlias(
'lowE',
'daughter(1,E)')
3036 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
3037 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
3038 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
3039 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
3040 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
3042 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
3044 roe_path = create_path()
3046 deadEndPath = create_path()
3048 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3050 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
3052 pi0softname =
'gamma:PI0SOFT'
3053 etasoftname =
'gamma:ETASOFT'
3054 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
3055 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
3059 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
3061 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
3064 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
3066 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
3068 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
3069 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
3071 if not os.path.isdir(workingDirectory):
3072 os.mkdir(workingDirectory)
3073 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
3075 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
3077 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
3078 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
3080 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
3082 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
3083 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
3085 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
3086 identifier=workingDirectory +
'/pi0veto.root')
3087 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
3088 identifier=workingDirectory +
'/etaveto.root')
3090 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
3091 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
3093 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
3094 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
3096 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3099 def writePi0EtaVeto(
3106 hardParticle='gamma',
3107 pi0PayloadNameOverride=None,
3108 pi0SoftPhotonCutOverride=None,
3109 etaPayloadNameOverride=None,
3110 etaSoftPhotonCutOverride=None
3113 Give pi0/eta probability for hard photon.
3115 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.
3117 The current default weight files are optimised using MC12.
3119 The input variables of the mva training are:
3121 * M: pi0/eta candidates Invariant mass
3122 * daughter(1,E): soft photon energy in lab frame
3123 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
3124 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3125 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
3126 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
3127 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
3128 * cosHelicityAngleMomentum: pi0/eta candidates cosHelicityAngleMomentum
3130 The following strings are available for mode:
3132 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
3133 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
3134 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
3135 * both: tight energy cut and clusterNHits cut are applied to soft photon
3137 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
3138 `pi0Prob`/`etaProb`. Otherwise, it is available as '{Pi0, Eta}ProbOrigin', '{Pi0, Eta}ProbTightEnergyThreshold', '{Pi0,
3139 Eta}ProbLargeClusterSize', or '{Pi0, Eta}ProbTightEnergyThresholdAndLargeClusterSize'} for the four modes described above, with
3140 the chosen suffix appended.
3143 Please don't use following ParticleList names elsewhere:
3145 ``gamma:HardPhoton``,
3146 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
3147 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
3148 ``pi0:EtaVeto + ListName``,
3149 ``eta:EtaVeto + ListName``
3151 @param particleList the input ParticleList
3152 @param decayString specify Particle to be added to the ParticleList
3153 @param mode choose one mode out of 'standard', 'tight', 'cluster' and 'both'
3154 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
3155 @param path modules are added to this path
3156 @param suffix optional suffix to be appended to the usual extraInfo name
3157 @param hardParticle particle name which is used to calculate the pi0/eta probability (default is gamma)
3158 @param pi0PayloadNameOverride specify the payload name of pi0 veto only if one wants to use non-default one. (default is None)
3159 @param pi0SoftPhotonCutOverride specify the soft photon selection criteria of pi0 veto only if one wants to use non-default one.
3161 @param etaPayloadNameOverride specify the payload name of eta veto only if one wants to use non-default one. (default is None)
3162 @param etaSoftPhotonCutOverride specify the soft photon selection criteria of eta veto only if one wants to use non-default one.
3168 B2ERROR(
"The pi0 / eta veto is not suitable for Belle analyses.")
3170 renameSuffix =
False
3172 for module
in path.modules():
3173 if module.type() ==
"SubEvent" and not renameSuffix:
3174 for subpath
in [p.values
for p
in module.available_params()
if p.name ==
"path"]:
3177 for submodule
in subpath.modules():
3178 if f
'{hardParticle}:HardPhoton{suffix}' in submodule.name():
3180 B2WARNING(
"Same extension already used in writePi0EtaVeto, append '_0'")
3184 roe_path = create_path()
3185 deadEndPath = create_path()
3186 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3187 fillSignalSideParticleList(f
'{hardParticle}:HardPhoton{suffix}', decayString, path=roe_path)
3189 dictListName = {
'standard':
'Origin',
3190 'tight':
'TightEnergyThreshold',
3191 'cluster':
'LargeClusterSize',
3192 'both':
'TightEnrgyThresholdAndLargeClusterSize'}
3194 dictPi0EnergyCut = {
'standard':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3195 'tight':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3196 'cluster':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3197 'both':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3199 dictEtaEnergyCut = {
'standard':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3200 'tight':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3201 'cluster':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3202 'both':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]'}
3204 dictNHitsCut = {
'standard':
'clusterNHits >= 0',
3205 'tight':
'clusterNHits >= 0',
3206 'cluster':
'clusterNHits >= 2',
3207 'both':
'clusterNHits >= 2'}
3209 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
3210 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
3211 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
3212 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
3214 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
3215 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
3216 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
3217 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
3219 dictPi0ExtraInfoName = {
'standard':
'Pi0ProbOrigin',
3220 'tight':
'Pi0ProbTightEnergyThreshold',
3221 'cluster':
'Pi0ProbLargeClusterSize',
3222 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize'}
3224 dictEtaExtraInfoName = {
'standard':
'EtaProbOrigin',
3225 'tight':
'EtaProbTightEnergyThreshold',
3226 'cluster':
'EtaProbLargeClusterSize',
3227 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize'}
3229 ListName = dictListName[mode]
3230 Pi0EnergyCut = dictPi0EnergyCut[mode]
3231 EtaEnergyCut = dictEtaEnergyCut[mode]
3232 TimingCut =
'abs(clusterTiming)<clusterErrorTiming'
3233 NHitsCut = dictNHitsCut[mode]
3234 Pi0PayloadName = dictPi0PayloadName[mode]
3235 EtaPayloadName = dictEtaPayloadName[mode]
3236 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
3237 EtaExtraInfoName = dictEtaExtraInfoName[mode]
3240 if pi0PayloadNameOverride
is not None:
3241 Pi0PayloadName = pi0PayloadNameOverride
3242 if pi0SoftPhotonCutOverride
is None:
3243 Pi0SoftPhotonCut = Pi0EnergyCut +
' and ' + NHitsCut
3247 Pi0SoftPhotonCut +=
' and ' + TimingCut
3249 Pi0SoftPhotonCut = pi0SoftPhotonCutOverride
3252 pi0soft = f
'gamma:Pi0Soft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3254 fillParticleList(pi0soft, Pi0SoftPhotonCut, path=roe_path)
3256 reconstructDecay(
'pi0:Pi0Veto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + pi0soft,
'',
3257 allowChargeViolation=
True, path=roe_path)
3259 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName],
3260 extraInfoName=Pi0ExtraInfoName, identifier=Pi0PayloadName)
3262 rankByHighest(
'pi0:Pi0Veto' + ListName,
'extraInfo(' + Pi0ExtraInfoName +
')', numBest=1, path=roe_path)
3264 variableToSignalSideExtraInfo(
'pi0:Pi0Veto' + ListName,
3265 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoName + suffix}, path=roe_path)
3268 if etaPayloadNameOverride
is not None:
3269 EtaPayloadName = etaPayloadNameOverride
3270 if etaSoftPhotonCutOverride
is None:
3271 EtaSoftPhotonCut = EtaEnergyCut +
' and ' + NHitsCut
3275 EtaSoftPhotonCut +=
' and ' + TimingCut
3277 EtaSoftPhotonCut = etaSoftPhotonCutOverride
3279 etasoft = f
'gamma:EtaSoft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3280 fillParticleList(etasoft, EtaSoftPhotonCut, path=roe_path)
3281 reconstructDecay(
'eta:EtaVeto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + etasoft,
'',
3282 allowChargeViolation=
True, path=roe_path)
3283 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName],
3284 extraInfoName=EtaExtraInfoName, identifier=EtaPayloadName)
3285 rankByHighest(
'eta:EtaVeto' + ListName,
'extraInfo(' + EtaExtraInfoName +
')', numBest=1, path=roe_path)
3286 variableToSignalSideExtraInfo(
'eta:EtaVeto' + ListName,
3287 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoName + suffix}, path=roe_path)
3289 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3292 def lowEnergyPi0Identification(pi0List, gammaList, payloadNameSuffix,
3295 Calculate low-energy pi0 identification.
3296 The result is stored as ExtraInfo ``lowEnergyPi0Identification`` for
3300 pi0List (str): Pi0 list.
3302 gammaList (str): Gamma list. First, an energy cut E > 0.2 is applied to the photons from this list.
3303 Then, all possible combinations with a pi0 daughter photon are formed except the one
3304 corresponding to the reconstructed pi0.
3305 The maximum low-energy pi0 veto value is calculated for such photon pairs
3306 and used as one of the input variables for the identification classifier.
3308 payloadNameSuffix (str): Payload name suffix. The weight payloads are stored in the analysis global
3309 tag and have the following names:\n
3310 * ``'LowEnergyPi0Veto' + payloadNameSuffix``
3311 * ``'LowEnergyPi0Identification' + payloadNameSuffix``\n
3312 The possible suffixes are:\n
3313 * ``'Belle1'`` for Belle data.
3314 * ``'Belle2Release5'`` for Belle II release 5 data (MC14, proc12, buckets 16 - 25).
3315 * ``'Belle2Release6'`` for Belle II release 6 data (MC15, proc13, buckets 26 - 36).
3317 path (basf2.Path): Module path.
3321 gammaListVeto = f
'{gammaList}_pi0veto'
3322 cutAndCopyList(gammaListVeto, gammaList,
'E > 0.2', path=path)
3324 payload_name =
'LowEnergyPi0Veto' + payloadNameSuffix
3325 path.add_module(
'LowEnergyPi0VetoExpert', identifier=payload_name,
3326 VetoPi0Daughters=
True, GammaListName=gammaListVeto,
3328 payload_name =
'LowEnergyPi0Identification' + payloadNameSuffix
3329 path.add_module(
'LowEnergyPi0IdentificationExpert',
3330 identifier=payload_name, Pi0ListName=pi0List,
3334 def getNeutralHadronGeomMatches(
3338 efficiencyCorrectionKl=0.83,
3339 efficiencyCorrectionNeutrons=1.0,
3342 For an ECL-based list, assign the mcdistanceKL and mcdistanceNeutron variables that correspond
3343 to the distance to the closest MC KL and neutron, respectively.
3344 @param particleLists the input ParticleLists, must be ECL-based lists (e.g. photons)
3345 @param addKL (default True) add distance to MC KL
3346 @param addNeutrons (default False) add distance to MC neutrons
3347 @param efficiencyCorrectionKl (default 0.83) apply overall efficiency correction
3348 @param efficiencyCorrectionNeutrons (default 1.0) apply overall efficiency correction
3349 @param path modules are added to this path
3351 from ROOT
import Belle2
3356 "NeutralHadronMatcher",
3357 particleLists=particleLists,
3358 mcPDGcode=Const.Klong.getPDGCode(),
3359 efficiencyCorrection=efficiencyCorrectionKl)
3362 "NeutralHadronMatcher",
3363 particleLists=particleLists,
3364 mcPDGcode=Const.neutron.getPDGCode(),
3365 efficiencyCorrection=efficiencyCorrectionNeutrons)
3368 def getBeamBackgroundProbability(particleList, weight, path=None):
3370 Assign a probability to each ECL cluster as being signal like (1) compared to beam background like (0)
3371 @param particleList the input ParticleList, must be a photon list
3372 @param weight type of weight file to use
3373 @param path modules are added to this path
3378 B2WARNING(
"weight type must be 'Belle' for b2bii.")
3380 path.add_module(
'MVAExpert',
3381 listNames=particleList,
3382 extraInfoName=
'beamBackgroundSuppression',
3383 identifier=f
'BeamBackgroundMVA_{weight}')
3386 def getFakePhotonProbability(particleList, weight, path=None):
3388 Assign a probability to each ECL cluster as being signal like (1) compared to fake photon like (0)
3389 @param particleList the input ParticleList, must be a photon list
3390 @param weight type of weight file to use
3391 @param path modules are added to this path
3396 B2WARNING(
"weight type must be 'Belle' for b2bii.")
3398 path.add_module(
'MVAExpert',
3399 listNames=particleList,
3400 extraInfoName=
'fakePhotonSuppression',
3401 identifier=f
'FakePhotonMVA_{weight}')
3404 def buildEventKinematics(inputListNames=None, default_cleanup=True, custom_cuts=None,
3405 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
3407 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3408 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
3409 (all track and all hits in ECL without associated track).
3411 The visible energy missing values are
3412 stored in a EventKinematics dataobject.
3414 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3415 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
3416 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
3417 according to the PID likelihood and the option inputListNames will be ignored.
3418 @param chargedPIDPriors The prior PID fractions, that are used to regulate
3419 amount of certain charged particle species, should be a list of
3420 six floats if not None. The order of particle types is
3421 the following: [e-, mu-, pi-, K-, p+, d+]
3422 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
3423 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3424 which would result in a standard predefined selection cuts
3425 @param path modules are added to this path
3428 if inputListNames
is None:
3430 trackCuts =
'pt > 0.1'
3431 trackCuts +=
' and thetaInCDCAcceptance'
3432 trackCuts +=
' and abs(dz) < 3'
3433 trackCuts +=
' and dr < 0.5'
3435 gammaCuts =
'E > 0.05'
3436 gammaCuts +=
' and thetaInCDCAcceptance'
3438 gammaCuts +=
' and abs(clusterTiming) < 200'
3439 if (custom_cuts
is not None):
3440 trackCuts, gammaCuts = custom_cuts
3442 if fillWithMostLikely:
3443 from stdCharged
import stdMostLikely
3444 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
3445 inputListNames = [f
'{ptype}:mostlikely_evtkin' for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
3447 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3449 fillParticleList(
'gamma:evtkin',
'', path=path)
3450 inputListNames += [
'gamma:evtkin']
3452 B2INFO(
"Using default cleanup in EventKinematics module.")
3453 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
3454 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
3455 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3457 B2INFO(
"No cleanup in EventKinematics module.")
3458 if not inputListNames:
3459 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
3460 fillParticleList(
'pi+:evtkin',
'', path=path)
3462 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3464 fillParticleList(
'gamma:evtkin',
'', path=path)
3465 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
3467 if (custom_cuts
is not None):
3468 B2INFO(
"Using default cleanup in EventKinematics module.")
3469 applyCuts(
'pi+:evtkin', trackCuts, path=path)
3470 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3472 B2INFO(
"No cleanup in EventKinematics module.")
3474 particleLists = inputListNames
3476 eventKinematicsModule = register_module(
'EventKinematics')
3477 eventKinematicsModule.set_name(
'EventKinematics_reco')
3478 eventKinematicsModule.param(
'particleLists', particleLists)
3479 path.add_module(eventKinematicsModule)
3482 def buildEventKinematicsFromMC(inputListNames=None, selectionCut='', path=None):
3484 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3485 using generated particles. If no ParticleList is provided, default generated ParticleLists are used.
3487 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3488 If the list is empty, default ParticleLists are filled.
3489 @param selectionCut optional selection cuts
3490 @param path Path to append the eventKinematics module to.
3493 if inputListNames
is None:
3495 if (len(inputListNames) == 0):
3499 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
3502 fillParticleListFromMC(f
"{t}:evtkin_default_gen",
'mcPrimary > 0 and nDaughters == 0',
3503 True,
True, path=path)
3504 if (selectionCut !=
''):
3505 applyCuts(f
"{t}:evtkin_default_gen", selectionCut, path=path)
3506 inputListNames += [f
"{t}:evtkin_default_gen"]
3508 eventKinematicsModule = register_module(
'EventKinematics')
3509 eventKinematicsModule.set_name(
'EventKinematics_gen')
3510 eventKinematicsModule.param(
'particleLists', inputListNames)
3511 eventKinematicsModule.param(
'usingMC',
True)
3512 path.add_module(eventKinematicsModule)
3515 def buildEventShape(inputListNames=None,
3516 default_cleanup=True,
3522 harmonicMoments=True,
3526 checkForDuplicates=False,
3529 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
3530 using the particles in the lists provided by the user. If no particle list is provided,
3531 the function will internally create a list of good tracks and a list of good photons
3532 with (optionally) minimal quality cuts.
3535 The results of the calculation are then stored into the EventShapeContainer dataobject,
3536 and are accessible using the variables of the EventShape group.
3538 The user can switch the calculation of certain quantities on or off to save computing
3539 time. By default the calculation of the high-order moments (5-8) is turned off.
3540 Switching off an option will make the corresponding variables not available.
3543 The user can provide as many particle lists
3544 as needed, using also combined particles, but the function will always assume that
3545 the lists are independent.
3546 If the lists provided by the user contain several times the same track (either with
3547 different mass hypothesis, or once as an independent particle and once as daughter of a
3548 combined particle) the results won't be reliable.
3549 A basic check for duplicates is available setting the checkForDuplicate flags.
3552 @param inputListNames List of ParticleLists used to calculate the
3553 event shape variables. If the list is empty the default
3554 particleLists pi+:evtshape and gamma:evtshape are filled.
3555 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
3556 defining the internal lists. This option is ignored if the
3557 particleLists are provided by the user.
3558 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3559 which would result in a standard predefined selection cuts
3560 @param path Path to append the eventShape modules to.
3561 @param thrust Enables the calculation of thrust-related quantities (CLEO
3562 cones, Harmonic moments, jets).
3563 @param collisionAxis Enables the calculation of the quantities related to the
3565 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
3566 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
3567 to both the thrust axis and, if collisionAxis = True, the collision axis.
3568 @param allMoments If True, calculates also the FW and harmonic moments from order
3569 5 to 8 instead of the low-order ones only.
3570 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
3571 axis and, if collisionAxis = True, the collision axis.
3572 @param jets Enables the calculation of the hemisphere momenta and masses.
3573 Requires thrust = True.
3574 @param sphericity Enables the calculation of the sphericity-related quantities.
3575 @param checkForDuplicates Perform a check for duplicate particles before adding them. Regardless of the value of this option,
3576 it is recommended to consider sanitizing the lists you are passing to the function.
3580 if inputListNames
is None:
3582 trackCuts =
'pt > 0.1'
3583 trackCuts +=
' and thetaInCDCAcceptance'
3584 trackCuts +=
' and abs(dz) < 3.0'
3585 trackCuts +=
' and dr < 0.5'
3587 gammaCuts =
'E > 0.05'
3588 gammaCuts +=
' and thetaInCDCAcceptance'
3590 gammaCuts +=
' and abs(clusterTiming) < 200'
3591 if (custom_cuts
is not None):
3592 trackCuts, gammaCuts = custom_cuts
3594 if not inputListNames:
3595 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
3596 fillParticleList(
'pi+:evtshape',
'', path=path)
3598 copyList(
'gamma:evtshape',
'gamma:mdst', path=path)
3604 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
3607 if (custom_cuts
is not None):
3608 B2INFO(
"Applying standard cuts")
3609 applyCuts(
'pi+:evtshape', trackCuts, path=path)
3611 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
3613 B2WARNING(
"Creating the default lists with no cleanup.")
3615 particleLists = inputListNames
3617 eventShapeModule = register_module(
'EventShapeCalculator')
3618 eventShapeModule.set_name(
'EventShape')
3619 eventShapeModule.param(
'particleListNames', particleLists)
3620 eventShapeModule.param(
'enableAllMoments', allMoments)
3621 eventShapeModule.param(
'enableCleoCones', cleoCones)
3622 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
3623 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
3624 eventShapeModule.param(
'enableJets', jets)
3625 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
3626 eventShapeModule.param(
'enableSphericity', sphericity)
3627 eventShapeModule.param(
'enableThrust', thrust)
3628 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
3630 path.add_module(eventShapeModule)
3633 def labelTauPairMC(printDecayInfo=False, path=None, TauolaBelle=False, mapping_minus=None, mapping_plus=None):
3635 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
3636 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
3638 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
3639 @param path: module is added to this path
3640 @param TauolaBelle: if False, TauDecayMode is set. If True, TauDecayMarker is set.
3641 @param mapping_minus: if None, the map is the default one, else the path for the map is given by the user for tau-
3642 @param mapping_plus: if None, the map is the default one, else the path for the map is given by the user for tau+
3645 from basf2
import find_file
3651 m_printmode =
'default'
3653 if mapping_minus
is None:
3654 mp_file_minus = find_file(
'data/analysis/modules/TauDecayMode/map_tauminus.txt')
3656 mp_file_minus = mapping_minus
3658 if mapping_plus
is None:
3659 mp_file_plus = find_file(
'data/analysis/modules/TauDecayMode/map_tauplus.txt')
3661 mp_file_plus = mapping_plus
3663 path.add_module(
'TauDecayMode', printmode=m_printmode, file_minus=mp_file_minus, file_plus=mp_file_plus)
3666 tauDecayMarker = register_module(
'TauDecayMarker')
3667 tauDecayMarker.set_name(
'TauDecayMarker_')
3669 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
3672 def tagCurlTracks(particleLists,
3682 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
3684 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
3685 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
3687 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
3690 The module loops over all particles in a given list with a transverse momentum below the pre-selection **ptCut**
3691 and assigns them to bundles based on the response of the chosen **selector** and the required minimum response set by the
3692 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
3693 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
3697 @param particleLists: list of particle lists to check for curls.
3698 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
3699 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
3700 genParticleIndex then ranked and tagged as normal.
3701 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
3702 If set to ``-1`` a cut value optimised to maximise the accuracy on a BBbar sample is used.
3703 Note 'cut' selector is binary 0/1.
3704 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
3705 It is strongly recommended to used the 'mva' selection. The 'cut' selection
3706 is based on BN1079 and is only calibrated for Belle data.
3708 @param ptCut: Pre-selection cut on transverse momentum. Only tracks below that are considered as curler candidates.
3710 @param expert_train: flag to set training mode if selector has a training mode (mva).
3711 @param expert_filename: set file name of produced training ntuple (mva).
3712 @param path: module is added to this path.
3718 if (
not isinstance(particleLists, list)):
3719 particleLists = [particleLists]
3721 curlTagger = register_module(
'CurlTagger')
3722 curlTagger.set_name(
'CurlTagger_')
3723 curlTagger.param(
'particleLists', particleLists)
3724 curlTagger.param(
'belle', belle)
3725 curlTagger.param(
'mcTruth', mcTruth)
3726 curlTagger.param(
'responseCut', responseCut)
3727 if abs(responseCut + 1) < 1e-9:
3728 curlTagger.param(
'usePayloadCut',
True)
3730 curlTagger.param(
'usePayloadCut',
False)
3732 curlTagger.param(
'selectorType', selectorType)
3733 curlTagger.param(
'ptCut', ptCut)
3734 curlTagger.param(
'train', expert_train)
3735 curlTagger.param(
'trainFilename', expert_filename)
3737 path.add_module(curlTagger)
3740 def applyChargedPidMVA(particleLists, path, trainingMode, chargeIndependent=False, binaryHypoPDGCodes=(0, 0)):
3742 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
3744 The module decorates Particle objects in the input ParticleList(s) with variables
3745 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
3748 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.3.0**, **ROOT 6.20/04**).
3750 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
3752 * e (11) vs. pi (211)
3753 * mu (13) vs. pi (211)
3754 * pi (211) vs. K (321)
3755 * K (321) vs. pi (211)
3757 , or 'global' PID, namely "one-vs-others" separation. The latter exploits an MVA algorithm trained in multi-class mode,
3758 and it's the default behaviour. Currently, the multi-class training separates the following standard charged hypotheses:
3760 - e (11), mu (13), pi (211), K (321)
3763 In order to run the `ChargedPidMVA` and ensure the most up-to-date MVA training weights are applied,
3764 it is necessary to append the latest analysis global tag (GT) to the steering script.
3767 particleLists (list(str)): the input list of DecayStrings, where each selected (^) daughter should correspond to a
3768 standard charged ParticleList, e.g. ``['Lambda0:sig -> ^p+ ^pi-', 'J/psi:sig -> ^mu+ ^mu-']``.
3769 One can also directly pass a list of standard charged ParticleLists,
3770 e.g. ``['e+:my_electrons', 'pi+:my_pions']``.
3771 Note that charge-conjugated ParticleLists will automatically be included.
3772 path (basf2.Path): the module is added to this path.
3773 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
3774 Needed to pick up the correct payload from the DB. Available choices:
3776 * c_Classification=0
3778 * c_ECL_Classification=2
3779 * c_ECL_Multiclass=3
3780 * c_PSD_Classification=4
3781 * c_PSD_Multiclass=5
3782 * c_ECL_PSD_Classification=6
3783 * c_ECL_PSD_Multiclass=7
3785 chargeIndependent (bool, ``optional``): use a BDT trained on a sample of inclusively charged particles.
3786 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
3787 Required only for binary PID mode.
3792 B2ERROR(
"Charged PID via MVA is not available for Belle data.")
3794 from ROOT
import Belle2
3796 TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
3799 plSet = set(particleLists)
3803 TrainingMode.c_Classification:
3804 {
"mode":
"Classification",
"detector":
"ALL"},
3805 TrainingMode.c_Multiclass:
3806 {
"mode":
"Multiclass",
"detector":
"ALL"},
3807 TrainingMode.c_ECL_Classification:
3808 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
3809 TrainingMode.c_ECL_Multiclass:
3810 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
3811 TrainingMode.c_PSD_Classification:
3812 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
3813 TrainingMode.c_PSD_Multiclass:
3814 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
3815 TrainingMode.c_ECL_PSD_Classification:
3816 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
3817 TrainingMode.c_ECL_PSD_Multiclass:
3818 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
3821 if payloadNames.get(trainingMode)
is None:
3822 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
3823 "\nis not supported. Please choose among the following:\n",
3824 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
3826 mode = payloadNames.get(trainingMode).get(
"mode")
3827 detector = payloadNames.get(trainingMode).get(
"detector")
3829 payloadName = f
"ChargedPidMVAWeights_{mode}"
3834 Const.electron.getPDGCode():
3835 {
"pName":
"e",
"pFullName":
"electron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3836 Const.muon.getPDGCode():
3837 {
"pName":
"mu",
"pFullName":
"muon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3838 Const.pion.getPDGCode():
3839 {
"pName":
"pi",
"pFullName":
"pion",
"pNameBkg":
"K",
"pdgIdBkg": Const.kaon.getPDGCode()},
3840 Const.kaon.getPDGCode():
3841 {
"pName":
"K",
"pFullName":
"kaon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3842 Const.proton.getPDGCode():
3843 {
"pName":
"p",
"pFullName":
"proton",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3844 Const.deuteron.getPDGCode():
3845 {
"pName":
"d",
"pFullName":
"deuteron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3848 if binaryHypoPDGCodes == (0, 0):
3851 chargedpid = register_module(
"ChargedPidMVAMulticlass")
3852 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
3859 binaryOpts = [(pdgIdSig, info[
"pdgIdBkg"])
for pdgIdSig, info
in stdChargedMap.items()]
3861 if binaryHypoPDGCodes
not in binaryOpts:
3862 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
3863 ". Please choose among the following pairs:\n",
3864 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
3868 if not decayDescriptor.init(name):
3869 raise ValueError(f
"Invalid particle list {name} in applyChargedPidMVA!")
3870 msg = f
"Input ParticleList: {name}"
3871 pdgs = [abs(decayDescriptor.getMother().getPDGCode())]
3872 daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
3873 if len(daughter_pdgs) > 0:
3874 pdgs = daughter_pdgs
3875 for idaughter, pdg
in enumerate(pdgs):
3876 if abs(pdg)
not in binaryHypoPDGCodes:
3878 msg = f
"Selected daughter {idaughter} in ParticleList: {name}"
3880 f
"{msg} (PDG={pdg}) is neither signal ({binaryHypoPDGCodes[0]}) nor background ({binaryHypoPDGCodes[1]}).")
3882 chargedpid = register_module(
"ChargedPidMVA")
3883 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
3884 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
3885 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
3887 chargedpid.param(
"particleLists", list(plSet))
3888 chargedpid.param(
"payloadName", payloadName)
3889 chargedpid.param(
"chargeIndependent", chargeIndependent)
3892 if detector ==
"ECL":
3893 chargedpid.param(
"useECLOnlyTraining",
True)
3895 path.add_module(chargedpid)
3898 def calculateTrackIsolation(
3902 reference_list_name=None,
3903 vars_for_nearest_part=[],
3904 highest_prob_mass_for_ext=True,
3905 exclude_pid_det_weights=False):
3907 Given an input decay string, compute variables that quantify track helix-based isolation of the charged
3908 stable particles in the input decay chain.
3911 An "isolation score" can be defined using the distance
3912 of each particle to its closest neighbour, defined as the segment connecting the two
3913 extrapolated track helices intersection points on a given cylindrical surface.
3914 The distance variables defined in the `VariableManager` is named `minET2ETDist`,
3915 the isolation scores are named `minET2ETIsoScore`, `minET2ETIsoScoreAsWeightedAvg`.
3917 The definition of distance and the number of distances that are calculated per sub-detector is based on
3918 the following recipe:
3920 * **CDC**: as the segmentation is very coarse along :math:`z`,
3921 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
3922 A total of 9 distances are calculated: the cylindrical surfaces are defined at radiuses
3923 that correspond to the positions of the 9 CDC wire superlayers: :math:`R_{i}^{\\mathrm{CDC}}~(i \\in \\{0,...,8\\})`.
3925 * **TOP**: as there is no segmentation along :math:`z`,
3926 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
3927 Only one distance at the TOP entry radius :math:`R_{0}^{\\mathrm{TOP}}` is calculated.
3929 * **ARICH**: as there is no segmentation along :math:`z`,
3930 the distance is defined as the distance on the :math:`(\\rho=R, \\phi)` plane at fixed :math:`z=Z`.
3931 Only one distance at the ARICH photon detector entry coordinate :math:`Z_{0}^{\\mathrm{ARICH}}` is calculated.
3933 * **ECL**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
3934 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
3935 Two distances are calculated: one at the ECL entry surface :math:`R_{0}^{\\mathrm{ECL}}` (barrel),
3936 :math:`Z_{0}^{\\mathrm{ECL}}` (endcaps), and one at :math:`R_{1}^{\\mathrm{ECL}}` (barrel),
3937 :math:`Z_{1}^{\\mathrm{ECL}}` (endcaps), corresponding roughly to the mid-point
3938 of the longitudinal size of the crystals.
3940 * **KLM**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
3941 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
3942 Only one distance at the KLM first strip entry surface :math:`R_{0}^{\\mathrm{KLM}}` (barrel),
3943 :math:`Z_{0}^{\\mathrm{KLM}}` (endcaps) is calculated.
3946 decay_string (str): name of the input decay string with selected charged stable daughters,
3947 for example: ``Lambda0:merged -> ^p+ ^pi-``.
3948 Alternatively, it can be a particle list for charged stable particles
3949 as defined in ``Const::chargedStableSet``, for example: ``mu+:all``.
3950 The charge-conjugate particle list will be also processed automatically.
3951 path (basf2.Path): path to which module(s) will be added.
3952 *detectors: detectors for which track isolation variables will be calculated.
3953 Choose among: ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
3954 reference_list_name (Optional[str]): name of the input charged stable particle list for the reference tracks.
3955 By default, the ``:all`` ParticleList of the same type
3956 of the selected particle in ``decay_string`` is used.
3957 The charge-conjugate particle list will be also processed automatically.
3958 vars_for_nearest_part (Optional[list(str)]): a list of variables to calculate for the nearest particle in the reference
3959 list at each detector surface. It uses the metavariable `minET2ETDistVar`.
3960 If unset, only the distances to the nearest neighbour
3961 per detector are calculated.
3962 highest_prob_mass_for_hex (Optional[bool]): if this option is set to True (default), the helix extrapolation
3963 for the particles will use the track fit result for the most
3964 probable mass hypothesis, namely, the one that gives the highest
3965 chi2Prob of the fit. Otherwise, it uses the mass hypothesis that
3966 corresponds to the particle lists PDG.
3967 exclude_pid_det_weights (Optional[bool]): if this option is set to False (default), the isolation score
3968 calculation will take into account the weight that each detector has on the PID
3969 for the particle species of interest.
3972 dict(int, list(str)): a dictionary mapping the PDG of each reference particle list to its isolation variables.
3977 from ROOT
import Belle2, TDatabasePDG
3980 if not decayDescriptor.init(decay_string):
3981 B2FATAL(f
"Invalid particle list {decay_string} in calculateTrackIsolation!")
3982 no_reference_list_name =
not reference_list_name
3985 "CDC": list(range(9)),
3991 if any(d
not in det_and_layers
for d
in detectors):
3993 "Your input detector list: ",
3995 " contains an invalid choice. Please select among: ",
3997 det_and_layers.keys()))
4002 processed_decay_strings = []
4003 if select_symbol
in decay_string:
4004 splitted_ds = decay_string.split(select_symbol)
4005 for i
in range(decay_string.count(select_symbol)):
4006 tmp = list(splitted_ds)
4007 tmp.insert(i+1, select_symbol)
4008 processed_decay_strings += [
''.join(tmp)]
4010 processed_decay_strings += [decay_string]
4012 reference_lists_to_vars = {}
4014 for processed_dec
in processed_decay_strings:
4015 if no_reference_list_name:
4016 decayDescriptor.init(processed_dec)
4017 selected_daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
4018 if len(selected_daughter_pdgs) > 0:
4019 reference_list_name = f
'{TDatabasePDG.Instance().GetParticle(abs(selected_daughter_pdgs[-1])).GetName()}:all'
4021 reference_list_name = f
'{processed_dec.split(":")[0]}:all'
4025 trackiso = path.add_module(
"TrackIsoCalculator",
4026 decayString=processed_dec,
4027 detectorNames=list(detectors),
4028 particleListReference=reference_list_name,
4029 useHighestProbMassForExt=highest_prob_mass_for_ext,
4030 excludePIDDetWeights=exclude_pid_det_weights)
4031 trackiso.set_name(f
"TrackIsoCalculator_{'_'.join(detectors)}_{processed_dec}_VS_{reference_list_name}")
4037 f
"minET2ETDist({d}, {d_layer}, {reference_list_name}, {int(highest_prob_mass_for_ext)})"
4038 for d
in detectors
for d_layer
in det_and_layers[d]]
4041 f
"minET2ETIsoScore({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4042 f
"minET2ETIsoScoreAsWeightedAvg({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4045 if vars_for_nearest_part:
4046 trackiso_vars.extend(
4048 f
"minET2ETDistVar({d}, {d_layer}, {reference_list_name}, {v})"
4049 for d
in detectors
for d_layer
in det_and_layers[d]
for v
in vars_for_nearest_part
4051 trackiso_vars.sort()
4053 reference_lists_to_vars[ref_pdg] = trackiso_vars
4055 return reference_lists_to_vars
4058 def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
4060 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
4061 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
4062 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
4063 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
4066 .. code-block:: python
4068 from modularAnalysis import calculateDistance
4069 calculateDistance('list_name', 'decay_string', "mode", path=user_path)
4071 @param list_name name of the input ParticleList
4072 @param decay_string select particles between the distance of closest approach will be calculated
4073 @param mode Specifies how the distance is calculated
4074 vertextrack: calculate the distance of closest approach between a track and a\
4075 vertex, taking the first candidate as vertex, default
4076 trackvertex: calculate the distance of closest approach between a track and a\
4077 vertex, taking the first candidate as track
4078 2tracks: calculates the distance of closest approach between two tracks
4079 2vertices: calculates the distance between two vertices
4080 vertexbtube: calculates the distance of closest approach between a vertex and btube
4081 trackbtube: calculates the distance of closest approach between a track and btube
4082 @param path modules are added to this path
4086 dist_mod = register_module(
'DistanceCalculator')
4088 dist_mod.set_name(
'DistanceCalculator_' + list_name)
4089 dist_mod.param(
'listName', list_name)
4090 dist_mod.param(
'decayString', decay_string)
4091 dist_mod.param(
'mode', mode)
4092 path.add_module(dist_mod)
4095 def addInclusiveDstarReconstruction(decayString, slowPionCut, DstarCut, path):
4097 Adds the InclusiveDstarReconstruction module to the given path.
4098 This module creates a D* particle list by estimating the D* four momenta
4099 from slow pions, specified by a given cut. The D* energy is approximated
4100 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
4101 momentum is calculated using the D* PDG mass and the direction is collinear
4102 to the slow pion direction. The charge of the given pion list has to be consistent
4105 @param decayString Decay string, must be of form ``D* -> pi``
4106 @param slowPionCut Cut applied to the input pion list to identify slow pions
4107 @param DstarCut Cut applied to the output D* list
4108 @param path the module is added to this path
4111 incl_dstar = register_module(
"InclusiveDstarReconstruction")
4112 incl_dstar.param(
"decayString", decayString)
4113 incl_dstar.param(
"slowPionCut", slowPionCut)
4114 incl_dstar.param(
"DstarCut", DstarCut)
4115 path.add_module(incl_dstar)
4118 def scaleError(outputListName, inputListName,
4119 scaleFactors=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4120 scaleFactorsNoPXD=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4121 d0Resolution=[0.00115328, 0.00134704],
4122 z0Resolution=[0.00124327, 0.0013272],
4127 This module creates a new charged particle list.
4128 The helix errors of the new particles are scaled by constant factors.
4129 Two sets of five scale factors are defined for tracks with and without a PXD hit.
4130 The scale factors are in order of (d0, phi0, omega, z0, tanlambda).
4131 For tracks with a PXD hit, in order to avoid severe underestimation of d0 and z0 errors,
4132 lower limits (best resolution) can be set in a momentum-dependent form.
4133 This module is supposed to be used only for TDCPV analysis and for low-momentum (0-3 GeV/c) tracks in BBbar events.
4134 Details will be documented in a Belle II note, BELLE2-NOTE-PH-2021-038.
4136 @param inputListName Name of input charged particle list to be scaled
4137 @param outputListName Name of output charged particle list with scaled error
4138 @param scaleFactors List of five constants to be multiplied to each of helix errors (for tracks with a PXD hit)
4139 @param scaleFactorsNoPXD List of five constants to be multiplied to each of helix errors (for tracks without a PXD hit)
4140 @param d0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4141 defining d0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**1.5))**2 }
4142 @param z0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4143 defining z0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**2.5))**2 }
4144 @param d0MomThr d0 best resolution is kept constant below this momentum
4145 @param z0MomThr z0 best resolution is kept constant below this momentum
4149 scale_error = register_module(
"HelixErrorScaler")
4150 scale_error.set_name(
'ScaleError_' + inputListName)
4151 scale_error.param(
'inputListName', inputListName)
4152 scale_error.param(
'outputListName', outputListName)
4153 scale_error.param(
'scaleFactors_PXD', scaleFactors)
4154 scale_error.param(
'scaleFactors_noPXD', scaleFactorsNoPXD)
4155 scale_error.param(
'd0ResolutionParameters', d0Resolution)
4156 scale_error.param(
'z0ResolutionParameters', z0Resolution)
4157 scale_error.param(
'd0MomentumThreshold', d0MomThr)
4158 scale_error.param(
'z0MomentumThreshold', z0MomThr)
4159 path.add_module(scale_error)
4162 def estimateAndAttachTrackFitResult(inputListName, path=None):
4164 Create a TrackFitResult from the momentum of the Particle assuming it originates from the IP and make a relation between them.
4165 The covariance, detector hit information, and fit-related information (pValue, NDF) are assigned meaningless values. The input
4166 Particles must not have already Track or TrackFitResult and thus are supposed to be composite particles, recoil, dummy
4167 particles, and so on.
4170 .. warning:: Since the source type is not overwritten as Track, not all track-related variables are guaranteed to be available.
4173 @param inputListName Name of input ParticleList
4176 estimator = register_module(
"TrackFitResultEstimator")
4177 estimator.set_name(
"trackFitResultEstimator_" + inputListName)
4178 estimator.param(
"inputListName", inputListName)
4179 path.add_module(estimator)
4182 def correctEnergyBias(inputListNames, tableName, path=None):
4184 Scale energy of the particles according to the scaling factor.
4185 If the particle list contains composite particles, the energy of the daughters are scaled.
4186 Subsequently, the energy of the mother particle is updated as well.
4189 inputListNames (list(str)): input particle list names
4190 tableName : stored in localdb and created using ParticleWeightingLookUpCreator
4191 path (basf2.Path): module is added to this path
4196 B2ERROR(
"The energy bias cannot be corrected with this tool for Belle data.")
4198 correctenergybias = register_module(
'EnergyBiasCorrection')
4199 correctenergybias.param(
'particleLists', inputListNames)
4200 correctenergybias.param(
'tableName', tableName)
4201 path.add_module(correctenergybias)
4204 def twoBodyISRPhotonCorrector(outputListName, inputListName, massiveParticle, path=None):
4206 Sets photon kinematics to corrected values in two body decays with an ISR photon
4207 and a massive particle. The original photon kinematics are kept in the input
4208 particleList and can be accessed using the originalParticle() metavariable on the
4211 @param ouputListName new ParticleList filled with copied Particles
4212 @param inputListName input ParticleList with original Particles
4213 @param massiveParticle name or PDG code of massive particle participating in the two
4214 body decay with the ISR photon
4215 @param path modules are added to this path
4219 photon_energy_correction = register_module(
'TwoBodyISRPhotonCorrector')
4220 photon_energy_correction.set_name(
'TwoBodyISRPhotonCorrector_' + outputListName)
4221 photon_energy_correction.param(
'outputGammaList', outputListName)
4222 photon_energy_correction.param(
'inputGammaList', inputListName)
4225 if isinstance(massiveParticle, int):
4226 photon_energy_correction.param(
'massiveParticlePDGCode', massiveParticle)
4228 from ROOT
import Belle2
4230 if not decayDescriptor.init(massiveParticle):
4231 raise ValueError(
"TwoBodyISRPhotonCorrector: value of massiveParticle must be" +
4232 " an int or valid decay string.")
4233 pdgCode = decayDescriptor.getMother().getPDGCode()
4234 photon_energy_correction.param(
'massiveParticlePDGCode', pdgCode)
4236 path.add_module(photon_energy_correction)
4239 def addPhotonEfficiencyRatioVariables(inputListNames, tableName, path=None):
4241 Add photon Data/MC detection efficiency ratio weights to the specified particle list
4244 inputListNames (list(str)): input particle list names
4245 tableName : taken from database with appropriate name
4246 path (basf2.Path): module is added to this path
4251 B2ERROR(
"For Belle data the photon data/MC detection efficiency ratio is not available with this tool.")
4253 photon_efficiency_correction = register_module(
'PhotonEfficiencySystematics')
4254 photon_efficiency_correction.param(
'particleLists', inputListNames)
4255 photon_efficiency_correction.param(
'tableName', tableName)
4256 path.add_module(photon_efficiency_correction)
4259 def addPi0VetoEfficiencySystematics(particleList, decayString, tableName, threshold, mode='standard', suffix='', path=None):
4261 Add pi0 veto Data/MC efficiency ratio weights to the specified particle list
4263 @param particleList the input ParticleList
4264 @param decayString specify hard photon to be performed pi0 veto (e.g. 'B+:sig -> rho+:sig ^gamma:hard')
4265 @param tableName table name corresponding to payload version (e.g. 'Pi0VetoEfficiencySystematics_Mar2022')
4266 @param threshold pi0 veto threshold (0.10, 0.11, ..., 0.99)
4267 @param mode choose one mode (same as writePi0EtaVeto) out of 'standard', 'tight', 'cluster' and 'both'
4268 @param suffix optional suffix to be appended to the usual extraInfo name
4269 @param path the module is added to this path
4271 The following extraInfo are available related with the given particleList:
4273 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_ratio : weight of Data/MC for the veto efficiency
4274 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_stat : the statistical uncertainty of the weight
4275 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_sys : the systematic uncertainty of the weight
4276 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_total : the total uncertainty of the weight
4277 * Pi0VetoEfficiencySystematics_{mode}{suffix}_threshold : threshold of the pi0 veto
4282 B2ERROR(
"For Belle data the pi0 veto data/MC efficiency ratio weights are not available via this tool.")
4284 pi0veto_efficiency_correction = register_module(
'Pi0VetoEfficiencySystematics')
4285 pi0veto_efficiency_correction.param(
'particleLists', particleList)
4286 pi0veto_efficiency_correction.param(
'decayString', decayString)
4287 pi0veto_efficiency_correction.param(
'tableName', tableName)
4288 pi0veto_efficiency_correction.param(
'threshold', threshold)
4289 pi0veto_efficiency_correction.param(
'mode', mode)
4290 pi0veto_efficiency_correction.param(
'suffix', suffix)
4291 path.add_module(pi0veto_efficiency_correction)
4294 def getAnalysisGlobaltag(timeout=180) -> str:
4296 Returns a string containing the name of the latest and recommended analysis globaltag.
4299 timeout: Seconds to wait for b2conditionsdb-recommend
4304 B2ERROR(
"The getAnalysisGlobaltag() function cannot be used for Belle data.")
4309 tags = subprocess.check_output(
4310 [
'b2conditionsdb-recommend',
'--oneline'],
4312 ).decode(
'UTF-8').rstrip().split(
' ')
4315 if tag.startswith(
'analysis_tools'):
4319 except subprocess.TimeoutExpired
as te:
4320 B2FATAL(f
'A {te} exception was raised during the call of getAnalysisGlobaltag(). '
4321 'The function took too much time to retrieve the requested information '
4322 'from the versioning repository.\n'
4323 'Please try to re-run your job. In case of persistent failures, there may '
4324 'be issues with the DESY collaborative services, so please contact the experts.')
4325 except subprocess.CalledProcessError
as ce:
4326 B2FATAL(f
'A {ce} exception was raised during the call of getAnalysisGlobaltag(). '
4327 'Please try to re-run your job. In case of persistent failures, please contact '
4331 def getAnalysisGlobaltagB2BII() -> str:
4333 Get recommended global tag for B2BII analysis.
4338 B2ERROR(
'The getAnalysisGlobaltagB2BII() function cannot be used for Belle II data.')
4339 from versioning
import recommended_b2bii_analysis_global_tag
4340 return recommended_b2bii_analysis_global_tag()
4343 def getNbarIDMVA(particleList: str, path=
None):
4345 This function can give a score to predict if it is a anti-n0.
4346 It is not used to predict n0.
4347 Currently, this can be used only for ECL cluster.
4348 output will be stored in extraInfo(nbarID); -1 means MVA invalid
4350 @param particleList The input ParticleList name or a decay string which contains a full mother particle list name.
4351 Only one selected daughter is supported.
4352 @param path modules are added to this path
4355 from ROOT
import Belle2
4358 B2ERROR(
"The MVA-based anti-neutron PID is only available for Belle II data.")
4360 from variables
import variables
4362 variables.addAlias(
'V1',
'clusterHasPulseShapeDiscrimination')
4363 variables.addAlias(
'V2',
'clusterE')
4364 variables.addAlias(
'V3',
'clusterLAT')
4365 variables.addAlias(
'V4',
'clusterE1E9')
4366 variables.addAlias(
'V5',
'clusterE9E21')
4367 variables.addAlias(
'V6',
'clusterZernikeMVA')
4368 variables.addAlias(
'V7',
'clusterAbsZernikeMoment40')
4369 variables.addAlias(
'V8',
'clusterAbsZernikeMoment51')
4373 'passesCut(V1 == 1 and V2 >= 0 and V3 >= 0 and V4 >= 0 and V5 >= 0 and V6 >= 0 and V7 >= 0 and V8 >= 0)')
4374 variables.addAlias(
'nbarIDmod',
'conditionalVariableSelector(nbarIDValid == 1, extraInfo(nbarIDFromMVA), constant(-1.0))')
4376 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'nbarIDFromMVA', identifier=
'db_nbarIDECL')
4378 if not decayDescriptor.init(particleList):
4379 raise ValueError(f
"Provided decay string is invalid: {particleList}")
4380 if decayDescriptor.getNDaughters() == 0:
4383 listname = decayDescriptor.getMother().getFullName()
4384 variablesToDaughterExtraInfo(listname, particleList, {
'nbarIDmod':
'nbarID'}, option=2, path=path)
4387 def reconstructDecayWithNeutralHadron(decayString, cut, allowGamma=False, allowAnyParticleSource=False, path=None, **kwargs):
4389 Reconstructs decay with a long-lived neutral hadron e.g.
4390 :math:`B^0 \to J/\psi K_L^0`,
4391 :math:`B^0 \to p \bar{n} D^*(2010)^-`.
4393 The calculation is done with IP constraint and mother mass constraint.
4395 The decay string passed in must satisfy the following rules:
4397 - The neutral hadron must be **selected** in the decay string with the
4398 caret (``^``) e.g. ``B0:sig -> J/psi:sig ^K_L0:sig``. (Note the caret
4399 next to the neutral hadron.)
4400 - There can only be **one neutral hadron in a decay**.
4401 - The neutral hadron has to be a direct daughter of its mother.
4403 .. note:: This function forwards its arguments to `reconstructDecay`,
4404 so please check the documentation of `reconstructDecay` for all
4407 @param decayString A decay string following the mentioned rules
4408 @param cut Cut to apply to the particle list
4409 @param allowGamma Whether allow the selected particle to be ``gamma``
4410 @param allowAnyParticleSource Whether allow the selected particle to be from any source.
4411 Should only be used when studying control sample.
4412 @param path The path to put in the module
4415 reconstructDecay(decayString, cut, path=path, **kwargs)
4416 module = register_module(
'NeutralHadron4MomentumCalculator')
4417 module.set_name(
'NeutralHadron4MomentumCalculator_' + decayString)
4418 module.param(
'decayString', decayString)
4419 module.param(
'allowGamma', allowGamma)
4420 module.param(
'allowAnyParticleSource', allowAnyParticleSource)
4421 path.add_module(module)
4424 func_requiring_analysisGT = [
4425 correctTrackEnergy, scaleTrackMomenta, smearTrackMomenta, oldwritePi0EtaVeto, writePi0EtaVeto, lowEnergyPi0Identification,
4426 getBeamBackgroundProbability, getFakePhotonProbability, tagCurlTracks, applyChargedPidMVA, correctEnergyBias,
4427 addPhotonEfficiencyRatioVariables, addPi0VetoEfficiencySystematics, getNbarIDMVA]
4428 for _
in func_requiring_analysisGT:
4429 _.__doc__ +=
"\n .. note:: This function (optionally) requires a payload stored in the analysis GlobalTag. "\
4430 "Please append or prepend the latest one from `getAnalysisGlobaltag` or `getAnalysisGlobaltagB2BII`.\n"
4433 if __name__ ==
'__main__':
4435 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)