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'
29 o) defines the style of the branch name in the ntuple
31 - 'mcMatchingVersion': Specifies what version of mc matching algorithm is going to be used:
33 - 'Belle' - analysis of Belle MC
34 - 'BelleII' (default) - all other cases
36 @param configParametersAndValues dictionary of parameters and their values of the form {param1: value, param2: value, ...)
37 @param modules are added to this path
40 conf = register_module(
'AnalysisConfiguration')
42 allParameters = [
'tupleStyle',
'mcMatchingVersion']
44 keys = configParametersAndValues.keys()
46 if key
not in allParameters:
47 allParametersString =
', '.join(allParameters)
48 B2ERROR(
'Invalid analysis configuration parameter: ' + key +
'.\n'
49 'Please use one of the following: ' + allParametersString)
51 for param
in allParameters:
52 if param
in configParametersAndValues:
53 conf.param(param, configParametersAndValues.get(param))
58 def inputMdst(filename, path, environmentType='default', skipNEvents=0, entrySequence=None, *, parentLevel=0, **kwargs):
60 Loads the specified :ref:`mDST <mdst>` (or :ref:`uDST <analysis_udstoutput>`) file with the RootInput module.
62 The correct environment (e.g. magnetic field settings) is determined from
63 ``environmentType``. Options are either: 'default' (for Belle II MC and
64 data: falls back to database), 'Belle': for analysis of converted Belle 1
68 filename (str): the name of the file to be loaded
69 path (basf2.Path): modules are added to this path
70 environmentType (str): type of the environment to be loaded (either 'default' or 'Belle')
71 skipNEvents (int): N events of the input file are skipped
72 entrySequence (str): The number sequences (e.g. 23:42,101) defining the entries which are processed.
73 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
77 if filename ==
'default':
79 We have simplified the arguments to inputMdst! If you are running on Belle II
80 data or MC, you don't have to use "default" any more.
82 inputMdst("default", "/your/input/file.root", path=mypath)
84 inputMdst("/your/input/file.root", path=mypath)
86 elif filename ==
"Belle":
88 We have reordered the arguments to inputMdst! If you are running on Belle 1
89 data or MC, you need to specify the 'environmentType'.
91 inputMdst("Belle", "/your/input/file.root", path=mypath)
93 inputMdst("/your/input/file.root", path=mypath, environmentType='Belle')
95 elif filename
in [f
"MC{i}" for i
in range(5, 10)]:
96 B2FATAL(f
"We no longer support the MC version {filename}. Sorry.")
98 if entrySequence
is not None:
99 entrySequence = [entrySequence]
101 inputMdstList([filename], path, environmentType, skipNEvents, entrySequence, parentLevel=parentLevel, **kwargs)
107 environmentType='default',
112 useB2BIIDBCache=True):
114 Loads the specified list of :ref:`mDST <mdst>` (or :ref:`uDST <analysis_udstoutput>`) files with the RootInput module.
116 The correct environment (e.g. magnetic field settings) is determined from
117 ``environmentType``. Options are either: 'default' (for Belle II MC and
118 data: falls back to database), 'Belle': for analysis of converted Belle 1
122 filelist (list(str)): the filename list of files to be loaded
123 path (basf2.Path): modules are added to this path
124 environmentType (str): type of the environment to be loaded (either 'default' or 'Belle')
125 skipNEvents (int): N events of the input files are skipped
126 entrySequences (list(str)): The number sequences (e.g. 23:42,101) defining
127 the entries which are processed for each inputFileName.
128 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
129 useB2BIIDBCache (bool): Loading of local KEKCC database (only to be deactivated in very special cases)
133 if filelist ==
'default':
135 We have simplified the arguments to inputMdstList! If you are running on
136 Belle II data or MC, you don't have to use "default" any more.
138 inputMdstList("default", list_of_your_files, path=mypath)
140 inputMdstList(list_of_your_files, path=mypath)
142 elif filelist ==
"Belle":
144 We have reordered the arguments to inputMdstList! If you are running on
145 Belle 1 data or MC, you need to specify the 'environmentType'.
147 inputMdstList("Belle", list_of_your_files, path=mypath)
149 inputMdstList(list_of_your_files, path=mypath, environmentType='Belle')
151 elif filelist
in [f
"MC{i}" for i
in range(5, 10)]:
152 B2FATAL(f
"We no longer support the MC version {filelist}. Sorry.")
154 roinput = register_module(
'RootInput')
155 roinput.param(
'inputFileNames', filelist)
156 roinput.param(
'skipNEvents', skipNEvents)
157 if entrySequences
is not None:
158 roinput.param(
'entrySequences', entrySequences)
159 roinput.param(
'parentLevel', parentLevel)
161 path.add_module(roinput)
162 path.add_module(
'ProgressBar')
164 if environmentType ==
'Belle':
169 from ROOT
import Belle2
175 setAnalysisConfigParams({
'mcMatchingVersion':
'Belle'}, path)
178 basf2.conditions.metadata_providers = [
"/sw/belle/b2bii/database/conditions/b2bii.sqlite"]
179 basf2.conditions.payload_locations = [
"/sw/belle/b2bii/database/conditions/"]
182 def outputMdst(filename, path):
184 Saves mDST (mini-Data Summary Tables) to the output root file.
188 This function is kept for backward-compatibility.
189 Better to use `mdst.add_mdst_output` directly.
197 def outputUdst(filename, particleLists=None, includeArrays=None, path=None, dataDescription=None):
199 Save uDST (user-defined Data Summary Tables) = MDST + Particles + ParticleLists
200 The charge-conjugate lists of those given in particleLists are also stored.
201 Additional Store Arrays and Relations to be stored can be specified via includeArrays
205 This does not reduce the amount of Particle objects saved,
206 see `udst.add_skimmed_udst_output` for a function that does.
212 path=path, filename=filename, particleLists=particleLists,
213 additionalBranches=includeArrays, dataDescription=dataDescription)
216 def outputIndex(filename, path, includeArrays=None, keepParents=False, mc=True):
218 Write out all particle lists as an index file to be reprocessed using parentLevel flag.
219 Additional branches necessary for file to be read are automatically included.
220 Additional Store Arrays and Relations to be stored can be specified via includeArrays
223 @param str filename the name of the output index file
224 @param str path modules are added to this path
225 @param list(str) includeArrays: datastore arrays/objects to write to the output
226 file in addition to particle lists and related information
227 @param bool keepParents whether the parents of the input event will be saved as the parents of the same event
228 in the output index file. Useful if you are only adding more information to another index file
229 @param bool mc whether the input data is MC or not
232 if includeArrays
is None:
236 onlyPLists = register_module(
'OnlyWriteOutParticleLists')
237 path.add_module(onlyPLists)
242 'ParticlesToMCParticles',
243 'ParticlesToPIDLikelihoods',
244 'ParticleExtraInfoMap',
247 branches = [
'EventMetaData']
248 persistentBranches = [
'FileMetaData']
252 branches += partBranches
253 branches += includeArrays
255 r1 = register_module(
'RootOutput')
256 r1.param(
'outputFileName', filename)
257 r1.param(
'additionalBranchNames', branches)
258 r1.param(
'branchNamesPersistent', persistentBranches)
259 r1.param(
'keepParents', keepParents)
263 def setupEventInfo(noEvents, path):
265 Prepare to generate events. This function sets up the EventInfoSetter.
266 You should call this before adding a generator from generators.
267 The experiment and run numbers are set to 0 (run independent generic MC in phase 3).
268 https://confluence.desy.de/display/BI/Experiment+numbering
271 noEvents (int): number of events to be generated
272 path (basf2.Path): modules are added to this path
275 evtnumbers = register_module(
'EventInfoSetter')
276 evtnumbers.param(
'evtNumList', [noEvents])
277 evtnumbers.param(
'runList', [0])
278 evtnumbers.param(
'expList', [0])
279 path.add_module(evtnumbers)
282 def loadGearbox(path, silence_warning=False):
284 Loads Gearbox module to the path.
287 Should be used in a job with *cosmic event generation only*
289 Needed for scripts which only generate cosmic events in order to
292 @param path modules are added to this path
293 @param silence_warning stops a verbose warning message if you know you want to use this function
296 if not silence_warning:
297 B2WARNING(
"""You are overwriting the geometry from the database with Gearbox.
298 This is fine if you're generating cosmic events. But in most other cases you probably don't want this.
300 If you're really sure you know what you're doing you can suppress this message with:
302 >>> loadGearbox(silence_warning=True)
306 paramloader = register_module(
'Gearbox')
307 path.add_module(paramloader)
310 def printPrimaryMCParticles(path, **kwargs):
312 Prints all primary MCParticles, that is particles from
313 the physics generator and not particles created by the simulation
315 This is equivalent to `printMCParticles(onlyPrimaries=True, path=path) <printMCParticles>` and additional
316 keyword arguments are just forwarded to that function
319 return printMCParticles(onlyPrimaries=
True, path=path, **kwargs)
322 def printMCParticles(onlyPrimaries=False, maxLevel=-1, path=None, *,
323 showProperties=False, showMomenta=False, showVertices=False, showStatus=False, suppressPrint=False):
325 Prints all MCParticles or just primary MCParticles up to specified level. -1 means no limit.
327 By default this will print a tree of just the particle names and their pdg
328 codes in the event, for example ::
330 [INFO] Content of MCParticle list
331 ╰── Upsilon(4S) (300553)
333 │ ├── anti-D_0*0 (-10421)
334 │ │ ├── D- (-411)
335 │ │ │ ├── K*- (-323)
336 │ │ │ │ ├── anti-K0 (-311)
337 │ │ │ │ │ ╰── K_S0 (310)
338 │ │ │ │ │ ├── pi+ (211)
339 │ │ │ │ │ │ ╰╶╶ p+ (2212)
340 │ │ │ │ │ ╰── pi- (-211)
341 │ │ │ │ │ ├╶╶ e- (11)
342 │ │ │ │ │ ├╶╶ n0 (2112)
343 │ │ │ │ │ ├╶╶ n0 (2112)
344 │ │ │ │ │ ╰╶╶ n0 (2112)
345 │ │ │ │ ╰── pi- (-211)
346 │ │ │ │ ├╶╶ anti-nu_mu (-14)
347 │ │ │ │ ╰╶╶ mu- (13)
348 │ │ │ │ ├╶╶ nu_mu (14)
349 │ │ │ │ ├╶╶ anti-nu_e (-12)
350 │ │ │ │ ╰╶╶ e- (11)
351 │ │ │ ╰── K_S0 (310)
352 │ │ │ ├── pi0 (111)
353 │ │ │ │ ├── gamma (22)
354 │ │ │ │ ╰── gamma (22)
355 │ │ │ ╰── pi0 (111)
356 │ │ │ ├── gamma (22)
357 │ │ │ ╰── gamma (22)
358 │ │ ╰── pi+ (211)
359 │ ├── mu+ (-13)
360 │ │ ├╶╶ anti-nu_mu (-14)
361 │ │ ├╶╶ nu_e (12)
362 │ │ ╰╶╶ e+ (-11)
363 │ ├── nu_mu (14)
364 │ ╰── gamma (22)
368 There's a distinction between primary and secondary particles. Primary
369 particles are the ones created by the physics generator while secondary
370 particles are ones generated by the simulation of the detector interaction.
372 Secondaries are indicated with a dashed line leading to the particle name
373 and if the output is to the terminal they will be printed in red. If
374 ``onlyPrimaries`` is True they will not be included in the tree.
376 On demand, extra information on all the particles can be displayed by
377 enabling any of the ``showProperties``, ``showMomenta``, ``showVertices``
378 and ``showStatus`` flags. Enabling all of them will look like
383 │ mass=0.14 energy=0.445 charge=-1 lifetime=6.36
384 │ p=(0.257, -0.335, 0.0238) |p|=0.423
385 │ production vertex=(0.113, -0.0531, 0.0156), time=0.00589
386 │ status flags=PrimaryParticle, StableInGenerator, StoppedInDetector
390 mass=0.94 energy=0.94 charge=0 lifetime=5.28e+03
391 p=(-0.000238, -0.0127, 0.0116) |p|=0.0172
392 production vertex=(144, 21.9, -1.29), time=39
393 status flags=StoppedInDetector
394 creation process=HadronInelastic
397 The first line of extra information is enabled by ``showProperties``, the
398 second line by ``showMomenta``, the third line by ``showVertices`` and the
399 last two lines by ``showStatus``. Note that all values are given in Belle II
400 standard units, that is GeV, centimeter and nanoseconds.
402 The depth of the tree can be limited with the ``maxLevel`` argument: If it's
403 bigger than zero it will limit the tree to the given number of generations.
404 A visual indicator will be added after each particle which would have
405 additional daughters that are skipped due to this limit. An example event
406 with ``maxLevel=3`` is given below. In this case only the tau neutrino and
407 the pion don't have additional daughters. ::
409 [INFO] Content of MCParticle list
410 ╰── Upsilon(4S) (300553)
412 │ ├── anti-D*0 (-423) → …
413 │ ├── tau+ (-15) → …
414 │ ╰── nu_tau (16)
416 ├── D*0 (423) → …
417 ├── K*- (-323) → …
418 ├── K*+ (323) → …
421 The same information will be stored in the branch ``__MCDecayString__`` of
422 TTree created by `VariablesToNtuple` or `VariablesToEventBasedTree` module.
423 This branch is automatically created when `PrintMCParticles` modules is called.
424 Printing the information on the log message can be suppressed if ``suppressPrint``
425 is True, while the branch ``__MCDecayString__``. This option helps to reduce the
426 size of the log message.
429 onlyPrimaries (bool): If True show only primary particles, that is particles coming from
430 the generator and not created by the simulation.
431 maxLevel (int): If 0 or less print the whole tree, otherwise stop after n generations
432 showProperties (bool): If True show mass, energy and charge of the particles
433 showMomenta (bool): if True show the momenta of the particles
434 showVertices (bool): if True show production vertex and production time of all particles
435 showStatus (bool): if True show some status information on the particles.
436 For secondary particles this includes creation process.
437 suppressPrint (bool): if True printing the information on the log message is suppressed.
438 Even if True, the branch ``__MCDecayString__`` is created.
441 return path.add_module(
443 onlyPrimaries=onlyPrimaries,
445 showProperties=showProperties,
446 showMomenta=showMomenta,
447 showVertices=showVertices,
448 showStatus=showStatus,
449 suppressPrint=suppressPrint,
453 def correctBrems(outputList,
456 maximumAcceptance=3.0,
457 multiplePhotons=False,
458 usePhotonOnlyOnce=True,
462 For each particle in the given ``inputList``, copies it to the ``outputList`` and adds the
463 4-vector of the photon(s) in the ``gammaList`` which has(have) a weighted named relation to
464 the particle's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
467 This can only work if the mdst file contains the *Bremsstrahlung* named relation. Official MC samples
468 up to and including MC12 and proc9 **do not** contain this. Newer production campaigns (from proc10 and MC13) do.
469 However, studies by the tau WG revealed that the cuts applied by the ``ECLTrackBremFinder`` module are too tight.
470 These will be loosened but this will only have effect with proc13 and MC15.
471 If your analysis is very sensitive to the Bremsstrahlung corrections, it is advised to use `correctBremsBelle`.
474 A detailed description of how the weights are set can be found directly at the documentation of the
475 `BremsFinder` module.
477 Please note that a new particle is always generated, with the old particle and -if found- one or more
478 photons as daughters.
480 The ``inputList`` should contain particles with associated tracks. Otherwise, the module will exit with an error.
482 The ``gammaList`` should contain photons. Otherwise, the module will exit with an error.
484 @param outputList The output particle list name containing the corrected particles
485 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
486 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
487 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
488 @param multiplePhotons Whether to use only one photon (the one with the smallest acceptance) or as many as possible
489 @param usePhotonOnlyOnce If true, each brems candidate is used to correct only the track with the smallest relation weight
490 @param writeOut Whether `RootOutput` module should save the created ``outputList``
491 @param path The module is added to this path
496 B2ERROR(
"The BremsFinder can only be run over Belle II data.")
498 bremscorrector = register_module(
'BremsFinder')
499 bremscorrector.set_name(
'bremsCorrector_' + outputList)
500 bremscorrector.param(
'inputList', inputList)
501 bremscorrector.param(
'outputList', outputList)
502 bremscorrector.param(
'gammaList', gammaList)
503 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
504 bremscorrector.param(
'multiplePhotons', multiplePhotons)
505 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
506 bremscorrector.param(
'writeOut', writeOut)
507 path.add_module(bremscorrector)
510 def copyList(outputListName, inputListName, writeOut=False, path=None):
512 Copy all Particle indices from input ParticleList to the output ParticleList.
513 Note that the Particles themselves are not copied. The original and copied
514 ParticleLists will point to the same Particles.
516 @param ouputListName copied ParticleList
517 @param inputListName original ParticleList to be copied
518 @param writeOut whether RootOutput module should save the created ParticleList
519 @param path modules are added to this path
522 copyLists(outputListName, [inputListName], writeOut, path)
525 def correctBremsBelle(outputListName,
528 multiplePhotons=True,
533 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
534 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
538 Studies by the tau WG show that using a rather wide opening angle (up to
539 0.2 rad) and rather low energetic photons results in good correction.
540 However, this should only serve as a starting point for your own studies
541 because the optimal criteria are likely mode-dependent
544 outputListName (str): The output charged particle list containing the corrected charged particles
545 inputListName (str): The initial charged particle list containing the charged particles to correct.
546 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
547 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one -> False,
548 add all the photons within the cone -> True
549 angleThreshold (float): The maximum angle in radians between the charged particle and the (radiative)
550 gamma to be accepted.
551 writeOut (bool): whether RootOutput module should save the created ParticleList
552 path (basf2.Path): modules are added to this path
555 fsrcorrector = register_module(
'BelleBremRecovery')
556 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
557 fsrcorrector.param(
'inputListName', inputListName)
558 fsrcorrector.param(
'outputListName', outputListName)
559 fsrcorrector.param(
'gammaListName', gammaListName)
560 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
561 fsrcorrector.param(
'angleThreshold', angleThreshold)
562 fsrcorrector.param(
'writeOut', writeOut)
563 path.add_module(fsrcorrector)
566 def copyLists(outputListName, inputListNames, writeOut=False, path=None):
568 Copy all Particle indices from all input ParticleLists to the
569 single output ParticleList.
570 Note that the Particles themselves are not copied.
571 The original and copied ParticleLists will point to the same Particles.
573 Duplicates are removed based on the first-come, first-served principle.
574 Therefore, the order of the input ParticleLists matters.
577 If you want to select the best duplicate based on another criterion, have
578 a look at the function `mergeListsWithBestDuplicate`.
581 Two particles that differ only by the order of their daughters are
582 considered duplicates and one of them will be removed.
584 @param ouputListName copied ParticleList
585 @param inputListName vector of original ParticleLists to be copied
586 @param writeOut whether RootOutput module should save the created ParticleList
587 @param path modules are added to this path
590 pmanipulate = register_module(
'ParticleListManipulator')
591 pmanipulate.set_name(
'PListCopy_' + outputListName)
592 pmanipulate.param(
'outputListName', outputListName)
593 pmanipulate.param(
'inputListNames', inputListNames)
594 pmanipulate.param(
'writeOut', writeOut)
595 path.add_module(pmanipulate)
598 def copyParticles(outputListName, inputListName, writeOut=False, path=None):
600 Create copies of Particles given in the input ParticleList and add them to the output ParticleList.
602 The existing relations of the original Particle (or it's (grand-)^n-daughters)
603 are copied as well. Note that only the relation is copied and that the related
604 object is not. Copied particles are therefore related to the *same* object as
607 @param ouputListName new ParticleList filled with copied Particles
608 @param inputListName input ParticleList with original Particles
609 @param writeOut whether RootOutput module should save the created ParticleList
610 @param path modules are added to this path
614 pmanipulate = register_module(
'ParticleListManipulator')
615 pmanipulate.set_name(
'PListCopy_' + outputListName)
616 pmanipulate.param(
'outputListName', outputListName)
617 pmanipulate.param(
'inputListNames', [inputListName])
618 pmanipulate.param(
'writeOut', writeOut)
619 path.add_module(pmanipulate)
622 pcopy = register_module(
'ParticleCopier')
623 pcopy.param(
'inputListNames', [outputListName])
624 path.add_module(pcopy)
627 def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
629 Copy candidates from all lists in ``inputListNames`` to
630 ``outputListName`` if they pass ``cut`` (given selection criteria).
633 Note that the Particles themselves are not copied.
634 The original and copied ParticleLists will point to the same Particles.
637 Require energetic pions safely inside the cdc
639 .. code-block:: python
641 cutAndCopyLists("pi+:energeticPions", ["pi+:good", "pi+:loose"], "[E > 2] and thetaInCDCAcceptance", path=mypath)
644 You must use square braces ``[`` and ``]`` for conditional statements.
647 outputListName (str): the new ParticleList name
648 inputListName (list(str)): list of input ParticleList names
649 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
650 writeOut (bool): whether RootOutput module should save the created ParticleList
651 path (basf2.Path): modules are added to this path
654 pmanipulate = register_module(
'ParticleListManipulator')
655 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
656 pmanipulate.param(
'outputListName', outputListName)
657 pmanipulate.param(
'inputListNames', inputListNames)
658 pmanipulate.param(
'cut', cut)
659 pmanipulate.param(
'writeOut', writeOut)
660 path.add_module(pmanipulate)
663 def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
665 Copy candidates from ``inputListName`` to ``outputListName`` if they pass
666 ``cut`` (given selection criteria).
669 Note the Particles themselves are not copied.
670 The original and copied ParticleLists will point to the same Particles.
673 require energetic pions safely inside the cdc
675 .. code-block:: python
677 cutAndCopyList("pi+:energeticPions", "pi+:loose", "[E > 2] and thetaInCDCAcceptance", path=mypath)
680 You must use square braces ``[`` and ``]`` for conditional statements.
683 outputListName (str): the new ParticleList name
684 inputListName (str): input ParticleList name
685 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
686 writeOut (bool): whether RootOutput module should save the created ParticleList
687 path (basf2.Path): modules are added to this path
690 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
693 def removeTracksForTrackingEfficiencyCalculation(inputListNames, fraction, path=None):
695 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
696 Takes care of the duplicates, if any.
699 inputListNames (list(str)): input particle list names
700 fraction (float): fraction of particles to be removed randomly
701 path (basf2.Path): module is added to this path
704 trackingefficiency = register_module(
'TrackingEfficiency')
705 trackingefficiency.param(
'particleLists', inputListNames)
706 trackingefficiency.param(
'frac', fraction)
707 path.add_module(trackingefficiency)
710 def scaleTrackMomenta(inputListNames, scale=float(
'nan'), payloadName=
"", scalingFactorName=
"SF", path=
None):
712 Scale momenta of the particles according to a scaling factor scale.
713 This scaling factor can either be given as constant number or as the name of the payload which contains
714 the variable scale factors.
715 If the particle list contains composite particles, the momenta of the track-based daughters are scaled.
716 Subsequently, the momentum of the mother particle is updated as well.
719 inputListNames (list(str)): input particle list names
720 scale (float): scaling factor (1.0 -- no scaling)
721 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
722 scalingFactorName (str): name of scaling factor variable in the payload.
723 path (basf2.Path): module is added to this path
728 B2ERROR(
"The tracking momentum scaler can only be run over Belle II data.")
730 trackingmomentum = register_module(
'TrackingMomentum')
731 trackingmomentum.param(
'particleLists', inputListNames)
732 trackingmomentum.param(
'scale', scale)
733 trackingmomentum.param(
'payloadName', payloadName)
734 trackingmomentum.param(
'scalingFactorName', scalingFactorName)
736 path.add_module(trackingmomentum)
739 def smearTrackMomenta(inputListNames, payloadName="", smearingFactorName="smear", path=None):
741 Smear the momenta of the particles according the values read from the given payload.
742 If the particle list contains composite particles, the momenta of the track-based daughters are smeared.
743 Subsequently, the momentum of the mother particle is updated as well.
746 inputListNames (list(str)): input particle list names
747 payloadName (str): name of the payload which contains the smearing valuess
748 smearingFactorName (str): name of smearing factor variable in the payload.
749 path (basf2.Path): module is added to this path
752 trackingmomentum = register_module(
'TrackingMomentum')
753 trackingmomentum.param(
'particleLists', inputListNames)
754 trackingmomentum.param(
'payloadName', payloadName)
755 trackingmomentum.param(
'smearingFactorName', smearingFactorName)
757 path.add_module(trackingmomentum)
760 def mergeListsWithBestDuplicate(outputListName,
765 ignoreMotherFlavor=False,
768 Merge input ParticleLists into one output ParticleList. Only the best
769 among duplicates is kept. The lowest or highest value (configurable via
770 preferLowest) of the provided variable determines which duplicate is the
773 @param ouputListName name of merged ParticleList
774 @param inputListName vector of original ParticleLists to be merged
775 @param variable variable to determine best duplicate
776 @param preferLowest whether lowest or highest value of variable should be preferred
777 @param writeOut whether RootOutput module should save the created ParticleList
778 @param ignoreMotherFlavor whether the flavor of the mother particle is ignored when trying to find duplicates
779 @param path modules are added to this path
782 pmanipulate = register_module(
'ParticleListManipulator')
783 pmanipulate.set_name(
'PListMerger_' + outputListName)
784 pmanipulate.param(
'outputListName', outputListName)
785 pmanipulate.param(
'inputListNames', inputListNames)
786 pmanipulate.param(
'variable', variable)
787 pmanipulate.param(
'preferLowest', preferLowest)
788 pmanipulate.param(
'writeOut', writeOut)
789 pmanipulate.param(
'ignoreMotherFlavor', ignoreMotherFlavor)
790 path.add_module(pmanipulate)
793 def fillSignalSideParticleList(outputListName, decayString, path):
795 This function should only be used in the ROE path, that is a path
796 that is executed for each ROE object in the DataStore.
798 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
800 Function will create a ParticleList with name 'gamma:sig' which will be filled
801 with the existing photon Particle, being the second daughter of the B0 candidate
802 to which the ROE object has to be related.
804 @param ouputListName name of the created ParticleList
805 @param decayString specify Particle to be added to the ParticleList
808 pload = register_module(
'SignalSideParticleListCreator')
809 pload.set_name(
'SSParticleList_' + outputListName)
810 pload.param(
'particleListName', outputListName)
811 pload.param(
'decayString', decayString)
812 path.add_module(pload)
815 def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False,
816 loadPhotonsFromKLM=False, loadPhotonBeamBackgroundMVA=False, loadPhotonHadronicSplitOffMVA=False):
818 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
819 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
821 The multiple ParticleLists with their own selection criteria are specified
822 via list tuples (decayString, cut), for example
824 .. code-block:: python
826 kaons = ('K+:mykaons', 'kaonID>0.1')
827 pions = ('pi+:mypions','pionID>0.1')
828 fillParticleLists([kaons, pions], path=mypath)
830 If you are unsure what selection you want, you might like to see the
831 :doc:`StandardParticles` functions.
833 The type of the particles to be loaded is specified via the decayString module parameter.
834 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
835 the particle. The following types of the particles can be loaded:
837 * charged final state particles (input ``mdst`` type = Tracks)
838 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
840 * neutral final state particles
841 - "gamma" (input ``mdst`` type = ECLCluster)
842 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
843 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
846 For "K_S0" and "Lambda0" you must specify the daughter ordering.
848 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
850 .. code-block:: python
852 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
853 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
856 Gammas can also be loaded from KLMClusters by explicitly setting the
857 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
858 done in selected use-cases and the effect should be studied carefully.
861 For "K_L0" it is now possible to load from ECLClusters, to revert to
862 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
864 .. code-block:: python
866 klongs = ('K_L0', 'isFromKLM > 0')
867 fillParticleLists([kaons, pions, klongs], path=mypath)
871 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
872 The decay string determines the type of Particle
873 and the name of the ParticleList.
874 If the input MDST type is V0 the whole
875 decay chain needs to be specified, so that
876 the user decides and controls the daughters
877 ' order (e.g. ``K_S0 -> pi+ pi-``)
878 The cut is the selection criteria
879 to be added to the ParticleList. It can be an empty string.
880 writeOut (bool): whether RootOutput module should save the created ParticleList
881 path (basf2.Path): modules are added to this path
882 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
883 using a mass hypothesis of the exact type passed to fillParticleLists().
884 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
885 in terms of mass difference will be used if the fit using exact particle
886 type is not available.
887 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
888 loadPhotonBeamBackgroundMVA (bool): If true, photon candidates will be assigned a beam background probability.
889 loadPhotonHadronicSplitOffMVA (bool): If true, photon candidates will be assigned a hadronic splitoff probability.
892 pload = register_module(
'ParticleLoader')
893 pload.set_name(
'ParticleLoader_' +
'PLists')
894 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
895 pload.param(
'writeOut', writeOut)
896 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
897 path.add_module(pload)
899 from ROOT
import Belle2
901 for decayString, cut
in decayStringsWithCuts:
902 if not decayDescriptor.init(decayString):
903 raise ValueError(
"Invalid decay string")
905 if decayDescriptor.getNDaughters() > 0:
909 if decayDescriptor.getMother().getLabel() !=
'V0':
910 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
911 elif decayDescriptor.getMother().getLabel() !=
'all':
914 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
918 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
920 if decayString.startswith(
"gamma"):
923 if not loadPhotonsFromKLM:
924 applyCuts(decayString,
'isFromECL', path)
928 if loadPhotonBeamBackgroundMVA:
929 getBeamBackgroundProbability(decayString, path)
933 if loadPhotonHadronicSplitOffMVA:
934 getHadronicSplitOffProbability(decayString, path)
937 def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False,
938 loadPhotonsFromKLM=False, loadPhotonBeamBackgroundMVA=False, loadPhotonHadronicSplitOffMVA=False):
940 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
941 loads them to the StoreArray<Particle> and fills the ParticleList.
944 the :doc:`StandardParticles` functions.
946 The type of the particles to be loaded is specified via the decayString module parameter.
947 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
948 the particle. The following types of the particles can be loaded:
950 * charged final state particles (input ``mdst`` type = Tracks)
951 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
953 * neutral final state particles
954 - "gamma" (input ``mdst`` type = ECLCluster)
955 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
956 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
959 For "K_S0" and "Lambda0" you must specify the daughter ordering.
961 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
963 .. code-block:: python
965 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
968 Gammas can also be loaded from KLMClusters by explicitly setting the
969 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
970 done in selected use-cases and the effect should be studied carefully.
973 For "K_L0" it is now possible to load from ECLClusters, to revert to
974 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
976 .. code-block:: python
978 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
981 decayString (str): Type of Particle and determines the name of the ParticleList.
982 If the input MDST type is V0 the whole decay chain needs to be specified, so that
983 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``)
984 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
985 writeOut (bool): whether RootOutput module should save the created ParticleList
986 path (basf2.Path): modules are added to this path
987 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
988 using a mass hypothesis of the exact type passed to fillParticleLists().
989 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
990 in terms of mass difference will be used if the fit using exact particle
991 type is not available.
992 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
993 loadPhotonBeamBackgroundMVA (bool): If true, photon candidates will be assigned a beam background probability.
994 loadPhotonHadronicSplitOffMVA (bool): If true, photon candidates will be assigned a hadronic splitoff probability.
997 pload = register_module(
'ParticleLoader')
998 pload.set_name(
'ParticleLoader_' + decayString)
999 pload.param(
'decayStrings', [decayString])
1000 pload.param(
'writeOut', writeOut)
1001 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1002 path.add_module(pload)
1005 from ROOT
import Belle2
1007 if not decayDescriptor.init(decayString):
1008 raise ValueError(
"Invalid decay string")
1009 if decayDescriptor.getNDaughters() > 0:
1013 if decayDescriptor.getMother().getLabel() !=
'V0':
1014 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1015 elif decayDescriptor.getMother().getLabel() !=
'all':
1018 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1022 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1024 if decayString.startswith(
"gamma"):
1027 if not loadPhotonsFromKLM:
1028 applyCuts(decayString,
'isFromECL', path)
1032 if loadPhotonBeamBackgroundMVA:
1033 getBeamBackgroundProbability(decayString, path)
1037 if loadPhotonHadronicSplitOffMVA:
1038 getHadronicSplitOffProbability(decayString, path)
1041 def fillParticleListWithTrackHypothesis(decayString,
1045 enforceFitHypothesis=False,
1048 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
1050 @param decayString specifies type of Particles and determines the name of the ParticleList
1051 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1052 @param hypothesis the PDG code of the desired track hypothesis
1053 @param writeOut whether RootOutput module should save the created ParticleList
1054 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
1055 using a mass hypothesis of the exact type passed to fillParticleLists().
1056 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1057 in terms of mass difference will be used if the fit using exact particle
1058 type is not available.
1059 @param path modules are added to this path
1062 pload = register_module(
'ParticleLoader')
1063 pload.set_name(
'ParticleLoader_' + decayString)
1064 pload.param(
'decayStrings', [decayString])
1065 pload.param(
'trackHypothesis', hypothesis)
1066 pload.param(
'writeOut', writeOut)
1067 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1068 path.add_module(pload)
1070 from ROOT
import Belle2
1072 if not decayDescriptor.init(decayString):
1073 raise ValueError(
"Invalid decay string")
1074 if decayDescriptor.getMother().getLabel() !=
'all':
1077 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1081 applyCuts(decayString, cut, path)
1084 def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
1086 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
1089 You must specify the daughter ordering.
1091 .. code-block:: python
1093 fillConvertedPhotonsList('gamma:converted -> e+ e-', '', path=mypath)
1096 decayString (str): Must be gamma to an e+e- pair. You must specify the daughter ordering.
1097 Will also determine the name of the particleList.
1098 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1099 writeOut (bool): whether RootOutput module should save the created ParticleList
1100 path (basf2.Path): modules are added to this path
1106 B2ERROR(
'For Belle converted photons are available in the pre-defined list "gamma:v0mdst".')
1108 pload = register_module(
'ParticleLoader')
1109 pload.set_name(
'ParticleLoader_' + decayString)
1110 pload.param(
'decayStrings', [decayString])
1111 pload.param(
'addDaughters',
True)
1112 pload.param(
'writeOut', writeOut)
1113 path.add_module(pload)
1115 from ROOT
import Belle2
1117 if not decayDescriptor.init(decayString):
1118 raise ValueError(
"Invalid decay string")
1119 if decayDescriptor.getMother().getLabel() !=
'V0':
1122 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1126 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1129 def fillParticleListFromROE(decayString,
1132 sourceParticleListName='',
1137 Creates Particle object for each ROE of the desired type found in the
1138 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
1139 and fills the ParticleList. If useMissing is True, then the missing
1140 momentum is used instead of ROE.
1142 The type of the particles to be loaded is specified via the decayString module parameter.
1144 @param decayString specifies type of Particles and determines the name of the ParticleList.
1145 Source ROEs can be taken as a daughter list, for example:
1146 'B0:tagFromROE -> B0:signal'
1147 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1148 @param maskName Name of the ROE mask to use
1149 @param sourceParticleListName Use related ROEs to this particle list as a source
1150 @param useMissing Use missing momentum instead of ROE momentum
1151 @param writeOut whether RootOutput module should save the created ParticleList
1152 @param path modules are added to this path
1155 pload = register_module(
'ParticleLoader')
1156 pload.set_name(
'ParticleLoader_' + decayString)
1157 pload.param(
'decayStrings', [decayString])
1158 pload.param(
'writeOut', writeOut)
1159 pload.param(
'roeMaskName', maskName)
1160 pload.param(
'useMissing', useMissing)
1161 pload.param(
'sourceParticleListName', sourceParticleListName)
1162 pload.param(
'useROEs',
True)
1163 path.add_module(pload)
1165 from ROOT
import Belle2
1167 if not decayDescriptor.init(decayString):
1168 raise ValueError(
"Invalid decay string")
1172 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1175 def fillParticleListFromDummy(decayString,
1178 treatAsInvisible=True,
1182 Creates a ParticleList and fills it with dummy Particles. For self-conjugated Particles one dummy
1183 Particle is created, for Particles that are not self-conjugated one Particle and one anti-Particle is
1184 created. The four-momentum is set to zero.
1186 The type of the particles to be loaded is specified via the decayString module parameter.
1188 @param decayString specifies type of Particles and determines the name of the ParticleList
1189 @param mdstIndex sets the mdst index of Particles
1190 @param covMatrix sets the value of the diagonal covariance matrix of Particles
1191 @param treatAsInvisible whether treeFitter should treat the Particles as invisible
1192 @param writeOut whether RootOutput module should save the created ParticleList
1193 @param path modules are added to this path
1196 pload = register_module(
'ParticleLoader')
1197 pload.set_name(
'ParticleLoader_' + decayString)
1198 pload.param(
'decayStrings', [decayString])
1199 pload.param(
'useDummy',
True)
1200 pload.param(
'dummyMDSTIndex', mdstIndex)
1201 pload.param(
'dummyCovMatrix', covMatrix)
1202 pload.param(
'dummyTreatAsInvisible', treatAsInvisible)
1203 pload.param(
'writeOut', writeOut)
1204 path.add_module(pload)
1207 def fillParticleListFromMC(decayString,
1210 skipNonPrimaryDaughters=False,
1213 skipNonPrimary=False):
1215 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1216 loads them to the StoreArray<Particle> and fills the ParticleList.
1218 The type of the particles to be loaded is specified via the decayString module parameter.
1220 @param decayString specifies type of Particles and determines the name of the ParticleList
1221 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1222 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1223 sets mother-daughter relations
1224 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1225 @param writeOut whether RootOutput module should save the created ParticleList
1226 @param path modules are added to this path
1227 @param skipNonPrimary if true, skip non primary particle
1230 pload = register_module(
'ParticleLoader')
1231 pload.set_name(
'ParticleLoader_' + decayString)
1232 pload.param(
'decayStrings', [decayString])
1233 pload.param(
'addDaughters', addDaughters)
1234 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1235 pload.param(
'writeOut', writeOut)
1236 pload.param(
'useMCParticles',
True)
1237 pload.param(
'skipNonPrimary', skipNonPrimary)
1238 path.add_module(pload)
1240 from ROOT
import Belle2
1242 if not decayDescriptor.init(decayString):
1243 raise ValueError(
"Invalid decay string")
1247 applyCuts(decayString, cut, path)
1250 def fillParticleListsFromMC(decayStringsWithCuts,
1252 skipNonPrimaryDaughters=False,
1255 skipNonPrimary=False):
1257 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1258 loads them to the StoreArray<Particle> and fills the ParticleLists.
1260 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
1263 .. code-block:: python
1265 kaons = ('K+:gen', '')
1266 pions = ('pi+:gen', 'pionID>0.1')
1267 fillParticleListsFromMC([kaons, pions], path=mypath)
1270 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not final state particle.
1271 Thus, when one reconstructs a particle from ``Lambda0``, that is created with
1272 ``addDaughters=True`` and ``skipNonPrimaryDaughters=True``, the particle always has ``isSignal==0``.
1273 Please set options for ``Lambda0`` to use MC-matching variables properly as follows,
1274 ``addDaughters=True`` and ``skipNonPrimaryDaughters=False``.
1276 @param decayString specifies type of Particles and determines the name of the ParticleList
1277 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1278 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1279 sets mother-daughter relations
1280 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1281 @param writeOut whether RootOutput module should save the created ParticleList
1282 @param path modules are added to this path
1283 @param skipNonPrimary if true, skip non primary particle
1286 pload = register_module(
'ParticleLoader')
1287 pload.set_name(
'ParticleLoader_' +
'PLists')
1288 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
1289 pload.param(
'addDaughters', addDaughters)
1290 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1291 pload.param(
'writeOut', writeOut)
1292 pload.param(
'useMCParticles',
True)
1293 pload.param(
'skipNonPrimary', skipNonPrimary)
1294 path.add_module(pload)
1296 from ROOT
import Belle2
1298 for decayString, cut
in decayStringsWithCuts:
1299 if not decayDescriptor.init(decayString):
1300 raise ValueError(
"Invalid decay string")
1304 applyCuts(decayString, cut, path)
1307 def applyCuts(list_name, cut, path):
1309 Removes particle candidates from ``list_name`` that do not pass ``cut``
1310 (given selection criteria).
1313 require energetic pions safely inside the cdc
1315 .. code-block:: python
1317 applyCuts("pi+:mypions", "[E > 2] and thetaInCDCAcceptance", path=mypath)
1320 You must use square braces ``[`` and ``]`` for conditional statements.
1323 list_name (str): input ParticleList name
1324 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
1325 path (basf2.Path): modules are added to this path
1328 pselect = register_module(
'ParticleSelector')
1329 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
1330 pselect.param(
'decayString', list_name)
1331 pselect.param(
'cut', cut)
1332 path.add_module(pselect)
1335 def applyEventCuts(cut, path, metavariables=None):
1337 Removes events that do not pass the ``cut`` (given selection criteria).
1340 continuum events (in mc only) with more than 5 tracks
1342 .. code-block:: python
1344 applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1347 Only event-based variables are allowed in this function
1348 and only square brackets ``[`` and ``]`` for conditional statements.
1351 cut (str): Events that do not pass these selection criteria are skipped
1352 path (basf2.Path): modules are added to this path
1353 metavariables (list(str)): List of meta variables to be considered in decomposition of cut
1357 from variables
import variables
1359 def find_vars(t: tuple, var_list: list, meta_list: list) ->
None:
1360 """ Recursive helper function to find variable names """
1361 if not isinstance(t, tuple):
1363 if t[0] == b2parser.B2ExpressionParser.node_types[
'IdentifierNode']:
1366 if t[0] == b2parser.B2ExpressionParser.node_types[
'FunctionNode']:
1367 meta_list.append(list(t[1:]))
1370 if isinstance(i, tuple):
1371 find_vars(i, var_list, meta_list)
1373 def check_variable(var_list: list, metavar_ids: list) ->
None:
1374 for var_string
in var_list:
1376 orig_name = variables.resolveAlias(var_string)
1377 if orig_name != var_string:
1380 find_vars(
b2parser.parse(orig_name), var_list_temp, meta_list_temp)
1382 check_variable(var_list_temp, metavar_ids)
1383 check_meta(meta_list_temp, metavar_ids)
1386 var = variables.getVariable(var_string)
1387 if event_var_id
not in var.description:
1388 B2ERROR(f
'Variable {var_string} is not an event-based variable! "\
1389 "Please check your inputs to the applyEventCuts method!')
1391 def check_meta(meta_list: list, metavar_ids: list) ->
None:
1392 for meta_string_list
in meta_list:
1394 while meta_string_list[0]
in metavar_ids:
1396 meta_string_list.pop(0)
1397 for meta_string
in meta_string_list[0].split(
","):
1398 find_vars(
b2parser.parse(meta_string), var_list_temp, meta_string_list)
1399 if len(meta_string_list) > 0:
1400 meta_string_list.pop(0)
1401 if len(meta_string_list) == 0:
1403 if len(meta_string_list) > 1:
1404 meta_list += meta_string_list[1:]
1405 if isinstance(meta_string_list[0], list):
1406 meta_string_list = [element
for element
in meta_string_list[0]]
1408 check_variable(var_list_temp, metavar_ids)
1410 if len(meta_string_list) == 0:
1412 elif len(meta_string_list) == 1:
1413 var = variables.getVariable(meta_string_list[0])
1415 var = variables.getVariable(meta_string_list[0], meta_string_list[1].split(
","))
1417 if event_var_id
in var.description:
1420 B2ERROR(f
'Variable {var.name} is not an event-based variable! Please check your inputs to the applyEventCuts method!')
1422 event_var_id =
'[Eventbased]'
1423 metavar_ids = [
'formula',
'abs',
1427 'exp',
'log',
'log10',
1431 metavar_ids += metavariables
1435 find_vars(
b2parser.parse(cut), var_list=var_list, meta_list=meta_list)
1437 if len(var_list) == 0
and len(meta_list) == 0:
1438 B2WARNING(f
'Cut string "{cut}" has no variables for applyEventCuts helper function!')
1440 check_variable(var_list, metavar_ids)
1441 check_meta(meta_list, metavar_ids)
1443 eselect = register_module(
'VariableToReturnValue')
1444 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1445 path.add_module(eselect)
1446 empty_path = create_path()
1447 eselect.if_value(
'<1', empty_path)
1450 def reconstructDecay(decayString,
1455 candidate_limit=None,
1456 ignoreIfTooManyCandidates=True,
1457 chargeConjugation=True,
1458 allowChargeViolation=False):
1460 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1461 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1462 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1463 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1464 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1466 One can use an ``@``-sign to mark a particle as unspecified for inclusive analyses,
1467 e.g. in a DecayString: :code:`'@Xsd -> K+ pi-'`.
1469 .. seealso:: :ref:`Marker_of_unspecified_particle`
1472 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1473 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1474 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1476 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1477 This can be solved by manually randomising the lists before combining.
1481 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1482 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1484 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1485 (from the DecayString the mother and daughter ParticleLists are determined)
1486 @param cut created (mother) Particles are added to the mother ParticleList if they
1487 pass give cuts (in VariableManager style) and rejected otherwise
1488 @param dmID user specified decay mode identifier
1489 @param writeOut whether RootOutput module should save the created ParticleList
1490 @param path modules are added to this path
1491 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1492 the number of candidates is exceeded a Warning will be
1494 By default, all these candidates will be removed and event will be ignored.
1495 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1496 If no value is given the amount is limited to a sensible
1497 default. A value <=0 will disable this limit and can
1498 cause huge memory amounts so be careful.
1499 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1500 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1501 otherwise, number of candidates in candidate_limit is reconstructed.
1502 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1503 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1506 pmake = register_module(
'ParticleCombiner')
1507 pmake.set_name(
'ParticleCombiner_' + decayString)
1508 pmake.param(
'decayString', decayString)
1509 pmake.param(
'cut', cut)
1510 pmake.param(
'decayMode', dmID)
1511 pmake.param(
'writeOut', writeOut)
1512 if candidate_limit
is not None:
1513 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1514 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1515 pmake.param(
'chargeConjugation', chargeConjugation)
1516 pmake.param(
"allowChargeViolation", allowChargeViolation)
1517 path.add_module(pmake)
1520 def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1522 Creates a new Particle as the combination of all Particles from all
1523 provided inputParticleLists. However, each particle is used only once
1524 (even if duplicates are provided) and the combination has to pass the
1525 specified selection criteria to be saved in the newly created (mother)
1528 @param inputParticleLists List of input particle lists which are combined to the new Particle
1529 @param outputList Name of the particle combination created with this module
1530 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1531 these given cuts (in VariableManager style) and is rejected otherwise
1532 @param writeOut whether RootOutput module should save the created ParticleList
1533 @param path module is added to this path
1536 pmake = register_module(
'AllParticleCombiner')
1537 pmake.set_name(
'AllParticleCombiner_' + outputList)
1538 pmake.param(
'inputListNames', inputParticleLists)
1539 pmake.param(
'outputListName', outputList)
1540 pmake.param(
'cut', cut)
1541 pmake.param(
'writeOut', writeOut)
1542 path.add_module(pmake)
1545 def reconstructMissingKlongDecayExpert(decayString,
1552 Creates a list of K_L0's with their momentum determined from kinematic constraints of B->K_L0 + something else.
1554 @param decayString DecayString specifying what kind of the decay should be reconstructed
1555 (from the DecayString the mother and daughter ParticleLists are determined)
1556 @param cut Particles are added to the K_L0 ParticleList if they
1557 pass the given cuts (in VariableManager style) and rejected otherwise
1558 @param dmID user specified decay mode identifier
1559 @param writeOut whether RootOutput module should save the created ParticleList
1560 @param path modules are added to this path
1561 @param recoList suffix appended to original K_L0 ParticleList that identifies the newly created K_L0 list
1564 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1565 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1566 pcalc.param(
'decayString', decayString)
1567 pcalc.param(
'cut', cut)
1568 pcalc.param(
'decayMode', dmID)
1569 pcalc.param(
'writeOut', writeOut)
1570 pcalc.param(
'recoList', recoList)
1571 path.add_module(pcalc)
1573 rmake = register_module(
'KlongDecayReconstructorExpert')
1574 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1575 rmake.param(
'decayString', decayString)
1576 rmake.param(
'cut', cut)
1577 rmake.param(
'decayMode', dmID)
1578 rmake.param(
'writeOut', writeOut)
1579 rmake.param(
'recoList', recoList)
1580 path.add_module(rmake)
1583 def setBeamConstrainedMomentum(particleList, decayStringTarget, decayStringDaughters, path=None):
1585 Replace the four-momentum of the target Particle by p(beam) - p(selected daughters).
1586 The momentum of the mother Particle will not be changed.
1588 @param particleList mother Particlelist
1589 @param decayStringTarget DecayString specifying the target particle whose momentum
1591 @param decayStringDaughters DecayString specifying the daughter particles used to replace
1592 the momentum of the target particle by p(beam)-p(daughters)
1595 mod = register_module(
'ParticleMomentumUpdater')
1596 mod.set_name(
'ParticleMomentumUpdater' + particleList)
1597 mod.param(
'particleList', particleList)
1598 mod.param(
'decayStringTarget', decayStringTarget)
1599 mod.param(
'decayStringDaughters', decayStringDaughters)
1600 path.add_module(mod)
1603 def updateKlongKinematicsExpert(particleList,
1607 Calculates and updates the kinematics of B->K_L0 + something else with same method as
1608 `reconstructMissingKlongDecayExpert`. This helps to revert the kinematics after the vertex fitting.
1610 @param particleList input ParticleList of B meson that decays to K_L0 + X
1611 @param writeOut whether RootOutput module should save the ParticleList
1612 @param path modules are added to this path
1615 mod = register_module(
'KlongMomentumUpdaterExpert')
1616 mod.set_name(
'KlongMomentumUpdaterExpert_' + particleList)
1617 mod.param(
'listName', particleList)
1618 mod.param(
'writeOut', writeOut)
1619 path.add_module(mod)
1622 def replaceMass(replacerName, particleLists=None, pdgCode=22, path=None):
1624 replaces the mass of the particles inside the given particleLists
1625 with the invariant mass of the particle corresponding to the given pdgCode.
1627 @param particleLists new ParticleList filled with copied Particles
1628 @param pdgCode PDG code for mass reference
1629 @param path modules are added to this path
1632 if particleLists
is None:
1636 pmassupdater = register_module(
'ParticleMassUpdater')
1637 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1638 pmassupdater.param(
'particleLists', particleLists)
1639 pmassupdater.param(
'pdgCode', pdgCode)
1640 path.add_module(pmassupdater)
1643 def reconstructRecoil(decayString,
1648 candidate_limit=None,
1649 allowChargeViolation=False):
1651 Creates new Particles that recoil against the input particles.
1653 For example the decay string M -> D1 D2 D3 will:
1654 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1655 - Particles D1, D2, D3 will be appended as daughters to M
1656 - the 4-momentum of the mother Particle M is given by
1657 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1659 @param decayString DecayString specifying what kind of the decay should be reconstructed
1660 (from the DecayString the mother and daughter ParticleLists are determined)
1661 @param cut created (mother) Particles are added to the mother ParticleList if they
1662 pass give cuts (in VariableManager style) and rejected otherwise
1663 @param dmID user specified decay mode identifier
1664 @param writeOut whether RootOutput module should save the created ParticleList
1665 @param path modules are added to this path
1666 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1667 the number of candidates is exceeded no candidate will be
1668 reconstructed for that event and a Warning will be
1670 If no value is given the amount is limited to a sensible
1671 default. A value <=0 will disable this limit and can
1672 cause huge memory amounts so be careful.
1673 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1676 pmake = register_module(
'ParticleCombiner')
1677 pmake.set_name(
'ParticleCombiner_' + decayString)
1678 pmake.param(
'decayString', decayString)
1679 pmake.param(
'cut', cut)
1680 pmake.param(
'decayMode', dmID)
1681 pmake.param(
'writeOut', writeOut)
1682 pmake.param(
'recoilParticleType', 1)
1683 if candidate_limit
is not None:
1684 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1685 pmake.param(
'allowChargeViolation', allowChargeViolation)
1686 path.add_module(pmake)
1689 def reconstructRecoilDaughter(decayString,
1694 candidate_limit=None,
1695 allowChargeViolation=False):
1697 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1699 For example the decay string M -> D1 D2 D3 will:
1700 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1701 - Particles D1, D2, D3 will be appended as daughters to M
1702 - the 4-momentum of the mother Particle M is given by
1703 p(M) = p(D1) - Sum_i p(Di), where i>1
1705 @param decayString DecayString specifying what kind of the decay should be reconstructed
1706 (from the DecayString the mother and daughter ParticleLists are determined)
1707 @param cut created (mother) Particles are added to the mother ParticleList if they
1708 pass give cuts (in VariableManager style) and rejected otherwise
1709 @param dmID user specified decay mode identifier
1710 @param writeOut whether RootOutput module should save the created ParticleList
1711 @param path modules are added to this path
1712 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1713 the number of candidates is exceeded no candidate will be
1714 reconstructed for that event and a Warning will be
1716 If no value is given the amount is limited to a sensible
1717 default. A value <=0 will disable this limit and can
1718 cause huge memory amounts so be careful.
1719 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1720 daughter is actually the mother
1723 pmake = register_module(
'ParticleCombiner')
1724 pmake.set_name(
'ParticleCombiner_' + decayString)
1725 pmake.param(
'decayString', decayString)
1726 pmake.param(
'cut', cut)
1727 pmake.param(
'decayMode', dmID)
1728 pmake.param(
'writeOut', writeOut)
1729 pmake.param(
'recoilParticleType', 2)
1730 if candidate_limit
is not None:
1731 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1732 pmake.param(
'allowChargeViolation', allowChargeViolation)
1733 path.add_module(pmake)
1736 def rankByHighest(particleList,
1740 allowMultiRank=False,
1744 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1745 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1746 The list is also sorted from best to worst candidate
1747 (each charge, e.g. B+/B-, separately).
1748 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1749 a non-zero value for 'numBest'.
1752 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1753 These variable names can become clunky, so it's probably a good idea to set an alias.
1754 For example if you rank your B candidates by momentum,
1758 rankByHighest("B0:myCandidates", "p", path=mypath)
1759 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1762 @param particleList The input ParticleList
1763 @param variable Variable to order Particles by.
1764 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1765 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1766 @param allowMultiRank If true, candidates with the same value will get the same rank.
1767 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1768 @param path modules are added to this path
1771 bcs = register_module(
'BestCandidateSelection')
1772 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1773 bcs.param(
'particleList', particleList)
1774 bcs.param(
'variable', variable)
1775 bcs.param(
'numBest', numBest)
1776 bcs.param(
'outputVariable', outputVariable)
1777 bcs.param(
'allowMultiRank', allowMultiRank)
1778 bcs.param(
'cut', cut)
1779 path.add_module(bcs)
1782 def rankByLowest(particleList,
1786 allowMultiRank=False,
1790 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1791 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1792 The list is also sorted from best to worst candidate
1793 (each charge, e.g. B+/B-, separately).
1794 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1795 a non-zero value for 'numBest'.
1798 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1799 These variable names can become clunky, so it's probably a good idea to set an alias.
1800 For example if you rank your B candidates by :b2:var:`dM`,
1804 rankByLowest("B0:myCandidates", "dM", path=mypath)
1805 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1808 @param particleList The input ParticleList
1809 @param variable Variable to order Particles by.
1810 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1811 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1812 @param allowMultiRank If true, candidates with the same value will get the same rank.
1813 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1814 @param path modules are added to this path
1817 bcs = register_module(
'BestCandidateSelection')
1818 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1819 bcs.param(
'particleList', particleList)
1820 bcs.param(
'variable', variable)
1821 bcs.param(
'numBest', numBest)
1822 bcs.param(
'selectLowest',
True)
1823 bcs.param(
'allowMultiRank', allowMultiRank)
1824 bcs.param(
'outputVariable', outputVariable)
1825 bcs.param(
'cut', cut)
1826 path.add_module(bcs)
1829 def applyRandomCandidateSelection(particleList, path=None):
1831 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1832 This is done on a event-by-event basis.
1834 @param particleList ParticleList for which the random candidate selection should be applied
1835 @param path module is added to this path
1838 rcs = register_module(
'BestCandidateSelection')
1839 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1840 rcs.param(
'particleList', particleList)
1841 rcs.param(
'variable',
'random')
1842 rcs.param(
'selectLowest',
False)
1843 rcs.param(
'allowMultiRank',
False)
1844 rcs.param(
'numBest', 1)
1845 rcs.param(
'cut',
'')
1846 rcs.param(
'outputVariable',
'')
1847 path.add_module(rcs)
1852 Prints the contents of DataStore in the first event (or a specific event number or all events).
1853 Will list all objects and arrays (including size).
1856 The command line tool: ``b2file-size``.
1859 eventNumber (int): Print the datastore only for this event. The default
1860 (-1) prints only the first event, 0 means print for all events (can produce large output)
1861 path (basf2.Path): the PrintCollections module is added to this path
1864 This will print a lot of output if you print it for all events and process many events.
1868 printDS = register_module(
'PrintCollections')
1869 printDS.param(
'printForEvent', eventNumber)
1870 path.add_module(printDS)
1873 def printVariableValues(list_name, var_names, path):
1875 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
1877 @param list_name input ParticleList name
1878 @param var_names vector of variable names to be printed
1879 @param path modules are added to this path
1882 prlist = register_module(
'ParticlePrinter')
1883 prlist.set_name(
'ParticlePrinter_' + list_name)
1884 prlist.param(
'listName', list_name)
1885 prlist.param(
'fullPrint',
False)
1886 prlist.param(
'variables', var_names)
1887 path.add_module(prlist)
1890 def printList(list_name, full, path):
1892 Prints the size and executes Particle->print() (if full=True)
1893 method for all Particles in given ParticleList. For debugging purposes.
1895 @param list_name input ParticleList name
1896 @param full execute Particle->print() method for all Particles
1897 @param path modules are added to this path
1900 prlist = register_module(
'ParticlePrinter')
1901 prlist.set_name(
'ParticlePrinter_' + list_name)
1902 prlist.param(
'listName', list_name)
1903 prlist.param(
'fullPrint', full)
1904 path.add_module(prlist)
1907 def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None, basketsize=1600,
1908 signalSideParticleList=""):
1910 Creates and fills a flat ntuple with the specified variables from the VariableManager.
1911 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
1912 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
1915 decayString (str): specifies type of Particles and determines the name of the ParticleList
1916 variables (list(str)): the list of variables (which must be registered in the VariableManager)
1917 treename (str): name of the ntuple tree
1918 filename (str): which is used to store the variables
1919 path (basf2.Path): the basf2 path where the analysis is processed
1920 basketsize (int): size of baskets in the output ntuple in bytes
1921 signalSideParticleList (str): The name of the signal-side ParticleList.
1922 Only valid if the module is called in a for_each loop over the RestOfEvent.
1925 output = register_module(
'VariablesToNtuple')
1926 output.set_name(
'VariablesToNtuple_' + decayString)
1927 output.param(
'particleList', decayString)
1928 output.param(
'variables', variables)
1929 output.param(
'fileName', filename)
1930 output.param(
'treeName', treename)
1931 output.param(
'basketSize', basketsize)
1932 output.param(
'signalSideParticleList', signalSideParticleList)
1933 path.add_module(output)
1939 filename='ntuple.root',
1942 prefixDecayString=False):
1944 Creates and fills a flat ntuple with the specified variables from the VariableManager
1947 decayString (str): specifies type of Particles and determines the name of the ParticleList
1948 variables (list(tuple))): variables + binning which must be registered in the VariableManager
1949 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
1950 filename (str): which is used to store the variables
1951 path (basf2.Path): the basf2 path where the analysis is processed
1952 directory (str): directory inside the output file where the histograms should be saved.
1953 Useful if you want to have different histograms in the same file to separate them.
1954 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
1955 programmatic naming of the structure in the file.
1958 if variables_2d
is None:
1960 output = register_module(
'VariablesToHistogram')
1961 output.set_name(
'VariablesToHistogram_' + decayString)
1962 output.param(
'particleList', decayString)
1963 output.param(
'variables', variables)
1964 output.param(
'variables_2d', variables_2d)
1965 output.param(
'fileName', filename)
1966 if directory
is not None or prefixDecayString:
1967 if directory
is None:
1969 if prefixDecayString:
1970 directory = decayString +
"_" + directory
1971 output.param(
"directory", directory)
1972 path.add_module(output)
1977 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
1978 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
1981 particleList (str): The input ParticleList
1982 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
1983 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
1984 An existing extra info with the same name will be overwritten if the new
1985 value is lower / will never be overwritten / will be overwritten if the
1986 new value is higher / will always be overwritten (option = -1/0/1/2).
1987 path (basf2.Path): modules are added to this path
1990 mod = register_module(
'VariablesToExtraInfo')
1991 mod.set_name(
'VariablesToExtraInfo_' + particleList)
1992 mod.param(
'particleList', particleList)
1993 mod.param(
'variables', variables)
1994 mod.param(
'overwrite', option)
1995 path.add_module(mod)
1998 def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
2000 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
2001 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
2002 to specified daughter particle.
2005 particleList (str): The input ParticleList
2006 decayString (str): Decay string that specifies to which daughter the extra info should be appended
2007 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2008 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2009 An existing extra info with the same name will be overwritten if the new
2010 value is lower / will never be overwritten / will be overwritten if the
2011 new value is higher / will always be overwritten (option = -1/0/1/2).
2012 path (basf2.Path): modules are added to this path
2015 mod = register_module(
'VariablesToExtraInfo')
2016 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
2017 mod.param(
'particleList', particleList)
2018 mod.param(
'decayString', decayString)
2019 mod.param(
'variables', variables)
2020 mod.param(
'overwrite', option)
2021 path.add_module(mod)
2024 def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
2026 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
2027 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
2030 When the function is called first time not in the main path but in a sub-path e.g. ``roe_path``,
2031 the eventExtraInfo cannot be accessed from the main path because of the shorter lifetime of the event-extra-info field.
2032 If one wants to call the function in a sub-path, one has to call the function in the main path beforehand.
2035 particleList (str): The input ParticleList
2036 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2037 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2038 An existing extra info with the same name will be overwritten if the new
2039 value is lower / will never be overwritten / will be overwritten if the
2040 new value is higher / will always be overwritten (option = -1/0/1/2).
2041 path (basf2.Path): modules are added to this path
2044 mod = register_module(
'VariablesToEventExtraInfo')
2045 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
2046 mod.param(
'particleList', particleList)
2047 mod.param(
'variables', variables)
2048 mod.param(
'overwrite', option)
2049 path.add_module(mod)
2052 def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
2054 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
2055 particle) as an extra info to the particle related to current ROE.
2056 Should be used only in the for_each roe path.
2059 particleList (str): The input ParticleList
2060 varToExtraInfo (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
2061 path (basf2.Path): modules are added to this path
2064 mod = register_module(
'SignalSideVariablesToExtraInfo')
2065 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
2066 mod.param(
'particleListName', particleList)
2067 mod.param(
'variableToExtraInfo', varToExtraInfo)
2068 path.add_module(mod)
2071 def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
2073 Define and blind a signal region.
2074 Per default, the defined signal region is cut out if ran on data.
2075 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
2079 .. code-block:: python
2081 ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
2082 ma.signalRegion("B+:sig",
2083 "Mbc>5.27 and abs(deltaE)<0.2",
2086 ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
2089 particleList (str): The input ParticleList
2090 cut (str): Cut string describing the signal region
2091 path (basf2.Path):: Modules are added to this path
2092 name (str): Name of the Signal region in the variable manager
2093 blind_data (bool): Automatically exclude signal region from data
2097 from variables
import variables
2098 mod = register_module(
'VariablesToExtraInfo')
2099 mod.set_name(f
'{name}_' + particleList)
2100 mod.param(
'particleList', particleList)
2101 mod.param(
'variables', {f
"passesCut({cut})": name})
2102 variables.addAlias(name, f
"extraInfo({name})")
2103 path.add_module(mod)
2107 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
2110 def removeExtraInfo(particleLists=None, removeEventExtraInfo=False, path=None):
2112 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
2115 if particleLists
is None:
2117 mod = register_module(
'ExtraInfoRemover')
2118 mod.param(
'particleLists', particleLists)
2119 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
2120 path.add_module(mod)
2123 def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
2125 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2126 to the particle from the input ParticleList. Additional selection criteria can be applied.
2127 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2128 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2129 suggests should be empty and its purpose is to end the execution of for_each roe path for
2130 the current ROE object.
2132 @param particleList The input ParticleList
2133 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2134 @param for_each roe path in which this filter is executed
2135 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2138 mod = register_module(
'SignalSideParticleFilter')
2139 mod.set_name(
'SigSideParticleFilter_' + particleList)
2140 mod.param(
'particleLists', [particleList])
2141 mod.param(
'selection', selection)
2142 roe_path.add_module(mod)
2143 mod.if_false(deadEndPath)
2146 def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
2148 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
2149 to the particle from the input ParticleList. Additional selection criteria can be applied.
2150 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
2151 meet the selection criteria the execution of deadEndPath is started. This path, as the name
2152 suggests should be empty and its purpose is to end the execution of for_each roe path for
2153 the current ROE object.
2155 @param particleLists The input ParticleLists
2156 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2157 @param for_each roe path in which this filter is executed
2158 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
2161 mod = register_module(
'SignalSideParticleFilter')
2162 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
2163 mod.param(
'particleLists', particleLists)
2164 mod.param(
'selection', selection)
2165 roe_path.add_module(mod)
2166 mod.if_false(deadEndPath)
2175 chargeConjugation=True,
2178 Finds and creates a ``ParticleList`` from given decay string.
2179 ``ParticleList`` of daughters with sub-decay is created.
2181 Only the particles made from MCParticle, which can be loaded by `fillParticleListFromMC`, are accepted as daughters.
2183 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
2184 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
2187 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
2188 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
2189 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
2192 It is recommended to use only primary particles as daughter particles unless you want to explicitly study the secondary
2193 particles. The behavior of MC-matching for secondary particles from a stable particle decay is not guaranteed.
2194 Please consider to use `fillParticleListFromMC` with ``skipNonPrimary=True`` to load daughter particles.
2195 Moreover, it is recommended to load ``K_S0`` and ``Lambda0`` directly from MCParticle by `fillParticleListFromMC` rather
2196 than reconstructing from two pions or a proton-pion pair, because their direct daughters can be the secondary particle.
2199 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
2200 (from the DecayString the mother and daughter ParticleLists are determined)
2201 @param cut created (mother) Particles are added to the mother ParticleList if they
2202 pass given cuts (in VariableManager style) and rejected otherwise
2203 isSignal==1 is always required by default.
2204 @param dmID user specified decay mode identifier
2205 @param writeOut whether RootOutput module should save the created ParticleList
2206 @param path modules are added to this path
2207 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
2210 pmake = register_module(
'ParticleCombinerFromMC')
2211 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
2212 pmake.param(
'decayString', decayString)
2213 pmake.param(
'cut', cut)
2214 pmake.param(
'decayMode', dmID)
2215 pmake.param(
'writeOut', writeOut)
2216 pmake.param(
'chargeConjugation', chargeConjugation)
2217 path.add_module(pmake)
2224 appendAllDaughters=False,
2225 skipNonPrimaryDaughters=True,
2229 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
2230 The decay string is required to describe correctly what you want.
2231 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
2233 The output particles has only the daughter particles written in the given decay string, if
2234 ``appendAllDaughters=False`` (default). If ``appendAllDaughters=True``, all daughters of the matched MCParticle are
2235 appended in the order defined at the MCParticle level. For example,
2237 .. code-block:: python
2239 findMCDecay('B0:Xee', 'B0 -> e+ e- ... ?gamma', appendAllDaughters=False, path=mypath)
2241 The output ParticleList ``B0:Xee`` will match the inclusive ``B0 -> e+ e-`` decays (but neutrinos are not included),
2242 in both cases of ``appendAllDaughters`` is false and true.
2243 If the ``appendAllDaughters=False`` as above example, the ``B0:Xee`` has only two electrons as daughters.
2244 While, if ``appendAllDaughters=True``, all daughters of the matched MCParticles are appended. When the truth decay mode of
2245 the MCParticle is ``B0 -> [K*0 -> K+ pi-] [J/psi -> e+ e-]``, the first daughter of ``B0:Xee`` is ``K*0`` and ``e+``
2246 will be the first daughter of second daughter of ``B0:Xee``.
2248 The option ``skipNonPrimaryDaughters`` only has an effect if ``appendAllDaughters=True``. If ``skipNonPrimaryDaughters=True``,
2249 all primary daughters are appended but the secondary particles are not.
2252 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not a final state particle.
2253 In order for the MCMatching to work properly, the daughters of ``Lambda0`` are appended to
2254 ``Lambda0`` regardless of the value of the option ``skipNonPrimaryDaughters``.
2257 @param list_name The output particle list name
2258 @param decay The decay string which you want
2259 @param writeOut Whether `RootOutput` module should save the created ``outputList``
2260 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
2261 @param appendAllDaughters if true, not only the daughters described in the decay string but all daughters are appended
2262 @param path modules are added to this path
2265 decayfinder = register_module(
'MCDecayFinder')
2266 decayfinder.set_name(
'MCDecayFinder_' + list_name)
2267 decayfinder.param(
'listName', list_name)
2268 decayfinder.param(
'decayString', decay)
2269 decayfinder.param(
'appendAllDaughters', appendAllDaughters)
2270 decayfinder.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
2271 decayfinder.param(
'writeOut', writeOut)
2272 path.add_module(decayfinder)
2275 def summaryOfLists(particleLists, outputFile=None, path=None):
2277 Prints out Particle statistics at the end of the job: number of events with at
2278 least one candidate, average number of candidates per event, etc.
2279 If an output file name is provided the statistics is also dumped into a json file with that name.
2281 @param particleLists list of input ParticleLists
2282 @param outputFile output file name (not created by default)
2285 particleStats = register_module(
'ParticleStats')
2286 particleStats.param(
'particleLists', particleLists)
2287 if outputFile
is not None:
2288 particleStats.param(
'outputFile', outputFile)
2289 path.add_module(particleStats)
2292 def matchMCTruth(list_name, path):
2294 Performs MC matching (sets relation Particle->MCParticle) for
2295 all particles (and its (grand)^N-daughter particles) in the specified
2298 @param list_name name of the input ParticleList
2299 @param path modules are added to this path
2302 mcMatch = register_module(
'MCMatcherParticles')
2303 mcMatch.set_name(
'MCMatch_' + list_name)
2304 mcMatch.param(
'listName', list_name)
2305 path.add_module(mcMatch)
2308 def looseMCTruth(list_name, path):
2310 Performs loose MC matching for all particles in the specified
2312 The difference between loose and normal mc matching algorithm is that
2313 the loose algorithm will find the common mother of the majority of daughter
2314 particles while the normal algorithm finds the common mother of all daughters.
2315 The results of loose mc matching algorithm are stored to the following extraInfo
2318 - looseMCMotherPDG: PDG code of most common mother
2319 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
2320 - looseMCWrongDaughterN: number of daughters that don't originate from the most
2322 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from
2323 the most common mother
2324 (only if looseMCWrongDaughterN = 1)
2325 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background
2328 @param list_name name of the input ParticleList
2329 @param path modules are added to this path
2332 mcMatch = register_module(
'MCMatcherParticles')
2333 mcMatch.set_name(
'LooseMCMatch_' + list_name)
2334 mcMatch.param(
'listName', list_name)
2335 mcMatch.param(
'looseMCMatching',
True)
2336 path.add_module(mcMatch)
2339 def buildRestOfEvent(target_list_name, inputParticlelists=None,
2340 fillWithMostLikely=True,
2341 chargedPIDPriors=None, path=None):
2343 Creates for each Particle in the given ParticleList a RestOfEvent
2344 dataobject and makes basf2 relation between them. User can provide additional
2345 particle lists with a different particle hypothesis like ['K+:good, e+:good'], etc.
2347 @param target_list_name name of the input ParticleList
2348 @param inputParticlelists list of user-defined input particle list names, which serve
2349 as source of particles to build the ROE, the FSP particles from
2350 target_list_name are automatically excluded from the ROE object
2351 @param fillWithMostLikely By default the module uses the most likely particle mass hypothesis for charged particles
2352 based on the PID likelihood. Turn this behavior off if you want to configure your own
2353 input particle lists.
2354 @param chargedPIDPriors The prior PID fractions, that are used to regulate the
2355 amount of certain charged particle species, should be a list of
2356 six floats if not None. The order of particle types is
2357 the following: [e-, mu-, pi-, K-, p+, d+]
2358 @param path modules are added to this path
2361 if inputParticlelists
is None:
2362 inputParticlelists = []
2363 fillParticleList(
'pi+:all',
'', path=path)
2364 if fillWithMostLikely:
2365 from stdCharged
import stdMostLikely
2366 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
2367 inputParticlelists = [
'%s:mostlikely_roe' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
2370 fillParticleList(
'gamma:all',
'', path=path)
2371 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
2372 inputParticlelists += [
'pi+:all',
'gamma:all',
'K_L0:roe_default']
2374 inputParticlelists += [
'pi+:all',
'gamma:mdst']
2375 roeBuilder = register_module(
'RestOfEventBuilder')
2376 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
2377 roeBuilder.param(
'particleList', target_list_name)
2378 roeBuilder.param(
'particleListsInput', inputParticlelists)
2379 roeBuilder.param(
'mostLikely', fillWithMostLikely)
2380 path.add_module(roeBuilder)
2383 def buildNestedRestOfEvent(target_list_name, maskName='all', path=None):
2385 Creates for each Particle in the given ParticleList a RestOfEvent
2386 @param target_list_name name of the input ParticleList
2387 @param mask_name name of the ROEMask to be used
2388 @param path modules are added to this path
2391 roeBuilder = register_module(
'RestOfEventBuilder')
2392 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
2393 roeBuilder.param(
'particleList', target_list_name)
2394 roeBuilder.param(
'nestedROEMask', maskName)
2395 roeBuilder.param(
'createNestedROE',
True)
2396 path.add_module(roeBuilder)
2399 def buildRestOfEventFromMC(target_list_name, inputParticlelists=None, path=None):
2401 Creates for each Particle in the given ParticleList a RestOfEvent
2402 @param target_list_name name of the input ParticleList
2403 @param inputParticlelists list of input particle list names, which serve
2404 as a source of particles to build ROE, the FSP particles from
2405 target_list_name are excluded from ROE object
2406 @param path modules are added to this path
2409 if inputParticlelists
is None:
2410 inputParticlelists = []
2411 if (len(inputParticlelists) == 0):
2415 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
2416 'n0',
'nu_e',
'nu_mu',
'nu_tau',
2419 fillParticleListFromMC(
"%s:roe_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
2420 True,
True, path=path)
2421 inputParticlelists += [
"%s:roe_default_gen" % t]
2422 roeBuilder = register_module(
'RestOfEventBuilder')
2423 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
2424 roeBuilder.param(
'particleList', target_list_name)
2425 roeBuilder.param(
'particleListsInput', inputParticlelists)
2426 roeBuilder.param(
'fromMC',
True)
2427 path.add_module(roeBuilder)
2430 def appendROEMask(list_name,
2433 eclClusterSelection,
2434 klmClusterSelection='',
2437 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2438 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
2440 - append a ROE mask with all tracks in ROE coming from the IP region
2442 .. code-block:: python
2444 appendROEMask('B+:sig', 'IPtracks', '[dr < 2] and [abs(dz) < 5]', path=mypath)
2446 - append a ROE mask with only ECL-based particles that pass as good photon candidates
2448 .. code-block:: python
2450 goodPhotons = 'inCDCAcceptance and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
2451 appendROEMask('B+:sig', 'goodROEGamma', '', goodPhotons, path=mypath)
2454 @param list_name name of the input ParticleList
2455 @param mask_name name of the appended ROEMask
2456 @param trackSelection decay string for the track-based particles in ROE
2457 @param eclClusterSelection decay string for the ECL-based particles in ROE
2458 @param klmClusterSelection decay string for the KLM-based particles in ROE
2459 @param path modules are added to this path
2462 roeMask = register_module(
'RestOfEventInterpreter')
2463 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2464 roeMask.param(
'particleList', list_name)
2465 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2466 path.add_module(roeMask)
2469 def appendROEMasks(list_name, mask_tuples, path=None):
2471 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2472 selection criteria for track-, ECL- and KLM-based particles which will be used by ROE variables.
2474 The multiple ROE masks with their own selection criteria are specified
2475 via list of tuples (mask_name, trackParticleSelection, eclParticleSelection, klmParticleSelection) or
2476 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
2478 - Example for two tuples, one with and one without fractions
2480 .. code-block:: python
2482 ipTracks = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', '')
2483 goodPhotons = 'inCDCAcceptance and [clusterErrorTiming < 1e6] and [clusterE1E9 > 0.4 or E > 0.075]'
2484 goodROEGamma = ('ROESel', '[dr < 2] and [abs(dz) < 5]', goodPhotons, '')
2485 goodROEKLM = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', 'nKLMClusterTrackMatches == 0')
2486 appendROEMasks('B+:sig', [ipTracks, goodROEGamma, goodROEKLM], path=mypath)
2488 @param list_name name of the input ParticleList
2489 @param mask_tuples array of ROEMask list tuples to be appended
2490 @param path modules are added to this path
2493 compatible_masks = []
2494 for mask
in mask_tuples:
2497 compatible_masks += [(*mask,
'')]
2499 compatible_masks += [mask]
2500 roeMask = register_module(
'RestOfEventInterpreter')
2501 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2502 roeMask.param(
'particleList', list_name)
2503 roeMask.param(
'ROEMasks', compatible_masks)
2504 path.add_module(roeMask)
2507 def updateROEMask(list_name,
2510 eclClusterSelection='',
2511 klmClusterSelection='',
2514 Update an existing ROE mask by applying additional selection cuts for
2515 tracks and/or clusters.
2517 See function `appendROEMask`!
2519 @param list_name name of the input ParticleList
2520 @param mask_name name of the ROEMask to update
2521 @param trackSelection decay string for the track-based particles in ROE
2522 @param eclClusterSelection decay string for the ECL-based particles in ROE
2523 @param klmClusterSelection decay string for the KLM-based particles in ROE
2524 @param path modules are added to this path
2527 roeMask = register_module(
'RestOfEventInterpreter')
2528 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2529 roeMask.param(
'particleList', list_name)
2530 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2531 roeMask.param(
'update',
True)
2532 path.add_module(roeMask)
2535 def updateROEMasks(list_name, mask_tuples, path):
2537 Update existing ROE masks by applying additional selection cuts for tracks
2540 The multiple ROE masks with their own selection criteria are specified
2541 via list tuples (mask_name, trackSelection, eclClusterSelection, klmClusterSelection)
2543 See function `appendROEMasks`!
2545 @param list_name name of the input ParticleList
2546 @param mask_tuples array of ROEMask list tuples to be appended
2547 @param path modules are added to this path
2550 compatible_masks = []
2551 for mask
in mask_tuples:
2554 compatible_masks += [(*mask,
'')]
2556 compatible_masks += [mask]
2558 roeMask = register_module(
'RestOfEventInterpreter')
2559 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2560 roeMask.param(
'particleList', list_name)
2561 roeMask.param(
'ROEMasks', compatible_masks)
2562 roeMask.param(
'update',
True)
2563 path.add_module(roeMask)
2566 def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2568 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2569 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2570 This function should be executed only in the for_each roe path for the current ROE object.
2572 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2573 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2574 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2575 pion particle list (e.g. 'pi+:someLabel').
2577 Updating a non-existing mask will create a new one.
2579 - keep only those tracks that were used in provided particle list
2581 .. code-block:: python
2583 keepInROEMasks('pi+:goodTracks', 'mask', '', path=mypath)
2585 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2587 .. code-block:: python
2589 keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1', path=mypath)
2592 @param list_name name of the input ParticleList
2593 @param mask_names array of ROEMasks to be updated
2594 @param cut_string decay string with which the mask will be updated
2595 @param path modules are added to this path
2598 updateMask = register_module(
'RestOfEventUpdater')
2599 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2600 updateMask.param(
'particleList', list_name)
2601 updateMask.param(
'updateMasks', mask_names)
2602 updateMask.param(
'cutString', cut_string)
2603 updateMask.param(
'discard',
False)
2604 path.add_module(updateMask)
2607 def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2609 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2610 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2611 This function should be executed only in the for_each roe path for the current ROE object.
2613 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2614 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2615 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2616 pion particle list (e.g. 'pi+:someLabel').
2618 Updating a non-existing mask will create a new one.
2620 - discard tracks that were used in provided particle list
2622 .. code-block:: python
2624 discardFromROEMasks('pi+:badTracks', 'mask', '', path=mypath)
2626 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2628 .. code-block:: python
2630 discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1', path=mypath)
2633 @param list_name name of the input ParticleList
2634 @param mask_names array of ROEMasks to be updated
2635 @param cut_string decay string with which the mask will be updated
2636 @param path modules are added to this path
2639 updateMask = register_module(
'RestOfEventUpdater')
2640 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2641 updateMask.param(
'particleList', list_name)
2642 updateMask.param(
'updateMasks', mask_names)
2643 updateMask.param(
'cutString', cut_string)
2644 updateMask.param(
'discard',
True)
2645 path.add_module(updateMask)
2648 def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2650 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2651 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2652 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2653 passing it can be applied.
2655 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2656 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2658 Updating a non-existing mask will create a new one.
2660 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2662 .. code-block:: python
2664 optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550', path=mypath)
2666 @param list_name name of the input ParticleList
2667 @param mask_names array of ROEMasks to be updated
2668 @param cut_string decay string with which the mask will be updated
2669 @param path modules are added to this path
2672 updateMask = register_module(
'RestOfEventUpdater')
2673 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2674 updateMask.param(
'particleList', list_name)
2675 updateMask.param(
'updateMasks', mask_names)
2676 updateMask.param(
'cutString', cut_string)
2677 path.add_module(updateMask)
2680 def updateROEUsingV0Lists(target_particle_list, mask_names, default_cleanup=True, selection_cuts=None,
2681 apply_mass_fit=False, fitter='treefit', path=None):
2683 This function creates V0 particle lists (photons, :math:`K^0_S` and :math:`\\Lambda^0`)
2684 and it uses V0 candidates to update the Rest Of Event, which is associated to the target particle list.
2685 It is possible to apply a standard or customized selection and mass fit to the V0 candidates.
2688 @param target_particle_list name of the input ParticleList
2689 @param mask_names array of ROE masks to be applied
2690 @param default_cleanup if True, predefined cuts will be applied on the V0 lists
2691 @param selection_cuts a single string of selection cuts or tuple of three strings (photon_cuts, K_S0_cuts, Lambda0_cuts),
2692 which will be applied to the V0 lists. These cuts will have a priority over the default ones.
2693 @param apply_mass_fit if True, a mass fit will be applied to the V0 particles
2694 @param fitter string, that represent a fitter choice: "treefit" for TreeFitter and "kfit" for KFit
2695 @param path modules are added to this path
2698 roe_path = create_path()
2699 deadEndPath = create_path()
2700 signalSideParticleFilter(target_particle_list,
'', roe_path, deadEndPath)
2702 if (default_cleanup
and selection_cuts
is None):
2703 B2INFO(
"Using default cleanup in updateROEUsingV0Lists.")
2704 selection_cuts =
'abs(dM) < 0.1 '
2705 selection_cuts +=
'and daughter(0,particleID) > 0.2 and daughter(1,particleID) > 0.2 '
2706 selection_cuts +=
'and daughter(0,thetaInCDCAcceptance) and daughter(1,thetaInCDCAcceptance)'
2707 if (selection_cuts
is None or selection_cuts ==
''):
2708 B2INFO(
"No cleanup in updateROEUsingV0Lists.")
2709 selection_cuts = (
'True',
'True',
'True')
2710 if (isinstance(selection_cuts, str)):
2711 selection_cuts = (selection_cuts, selection_cuts, selection_cuts)
2713 roe_cuts =
'isInRestOfEvent > 0'
2714 fillConvertedPhotonsList(
'gamma:v0_roe -> e+ e-', f
'{selection_cuts[0]} and {roe_cuts}',
2716 fillParticleList(
'K_S0:v0_roe -> pi+ pi-', f
'{selection_cuts[1]} and {roe_cuts}',
2718 fillParticleList(
'Lambda0:v0_roe -> p+ pi-', f
'{selection_cuts[2]} and {roe_cuts}',
2720 fitter = fitter.lower()
2721 if (fitter !=
'treefit' and fitter !=
'kfit'):
2722 B2WARNING(
'Argument "fitter" in updateROEUsingV0Lists has only "treefit" and "kfit" options, '
2723 f
'but "{fitter}" was provided! TreeFitter will be used instead.')
2725 from vertex
import kFit, treeFit
2726 for v0
in [
'gamma:v0_roe',
'K_S0:v0_roe',
'Lambda0:v0_roe']:
2727 if (apply_mass_fit
and fitter ==
'kfit'):
2728 kFit(v0, conf_level=0.0, fit_type=
'massvertex', path=roe_path)
2729 if (apply_mass_fit
and fitter ==
'treefit'):
2730 treeFit(v0, conf_level=0.0, massConstraint=[v0.split(
':')[0]], path=roe_path)
2731 optimizeROEWithV0(v0, mask_names,
'', path=roe_path)
2732 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2735 def printROEInfo(mask_names=None, full_print=False,
2736 unpackComposites=True, path=None):
2738 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2739 It prints out basic ROE object info.
2741 If mask names are provided, specific information for those masks will be printed out.
2743 It is also possible to print out all particles in a given mask if the
2744 'full_print' is set to True.
2746 @param mask_names array of ROEMask names for printing out info
2747 @param unpackComposites if true, replace composite particles by their daughters
2748 @param full_print print out particles in mask
2749 @param path modules are added to this path
2752 if mask_names
is None:
2754 printMask = register_module(
'RestOfEventPrinter')
2755 printMask.set_name(
'RestOfEventPrinter')
2756 printMask.param(
'maskNames', mask_names)
2757 printMask.param(
'fullPrint', full_print)
2758 printMask.param(
'unpackComposites', unpackComposites)
2759 path.add_module(printMask)
2762 def buildContinuumSuppression(list_name, roe_mask, path):
2764 Creates for each Particle in the given ParticleList a ContinuumSuppression
2765 dataobject and makes basf2 relation between them.
2767 :param list_name: name of the input ParticleList
2768 :param roe_mask: name of the ROE mask
2769 :param path: modules are added to this path
2772 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2773 qqBuilder.set_name(
'QQBuilder_' + list_name)
2774 qqBuilder.param(
'particleList', list_name)
2775 qqBuilder.param(
'ROEMask', roe_mask)
2776 path.add_module(qqBuilder)
2781 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2782 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2784 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2785 @param path modules are added to this path
2788 mod = register_module(
'RemoveParticlesNotInLists')
2789 mod.param(
'particleLists', lists_to_keep)
2790 path.add_module(mod)
2793 def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2795 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2797 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2798 @param bsig_list_name Name of the Bsig ParticleList
2799 @param btag_list_name Name of the Bsig ParticleList
2800 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2803 btag = register_module(
'InclusiveBtagReconstruction')
2804 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2805 btag.param(
'upsilonListName', upsilon_list_name)
2806 btag.param(
'bsigListName', bsig_list_name)
2807 btag.param(
'btagListName', btag_list_name)
2808 btag.param(
'inputListsNames', input_lists_names)
2809 path.add_module(btag)
2812 def selectDaughters(particle_list_name, decay_string, path):
2814 Redefine the Daughters of a particle: select from decayString
2816 @param particle_list_name input particle list
2817 @param decay_string for selecting the Daughters to be preserved
2820 seld = register_module(
'SelectDaughters')
2821 seld.set_name(
'SelectDaughters_' + particle_list_name)
2822 seld.param(
'listName', particle_list_name)
2823 seld.param(
'decayString', decay_string)
2824 path.add_module(seld)
2827 def markDuplicate(particleList, prioritiseV0, path):
2829 Call DuplicateVertexMarker to find duplicate particles in a list and
2830 flag the ones that should be kept
2832 @param particleList input particle list
2833 @param prioritiseV0 if true, give V0s a higher priority
2836 markdup = register_module(
'DuplicateVertexMarker')
2837 markdup.param(
'particleList', particleList)
2838 markdup.param(
'prioritiseV0', prioritiseV0)
2839 path.add_module(markdup)
2842 PI0ETAVETO_COUNTER = 0
2845 def oldwritePi0EtaVeto(
2848 workingDirectory='.',
2849 pi0vetoname='Pi0_Prob',
2850 etavetoname='Eta_Prob',
2856 Give pi0/eta probability for hard photon.
2858 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.
2860 The current default weight files are optimised using MC9.
2861 The input variables are as below. Aliases are set to some variables during training.
2863 * M: pi0/eta candidates Invariant mass
2864 * lowE: soft photon energy in lab frame
2865 * cTheta: soft photon ECL cluster's polar angle
2866 * Zmva: soft photon output of MVA using Zernike moments of the cluster
2867 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2869 If you don't have weight files in your workingDirectory,
2870 these files are downloaded from database to your workingDirectory automatically.
2871 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
2872 about how to use this function.
2875 Please don't use following ParticleList names elsewhere:
2877 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
2878 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
2880 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
2882 @param particleList The input ParticleList
2883 @param decayString specify Particle to be added to the ParticleList
2884 @param workingDirectory The weight file directory
2885 @param downloadFlag whether download default weight files or not
2886 @param pi0vetoname extraInfo name of pi0 probability
2887 @param etavetoname extraInfo name of eta probability
2888 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2889 @param path modules are added to this path
2894 B2ERROR(
"The old pi0 / eta veto is not suitable for Belle analyses.")
2899 global PI0ETAVETO_COUNTER
2901 if PI0ETAVETO_COUNTER == 0:
2902 from variables
import variables
2903 variables.addAlias(
'lowE',
'daughter(1,E)')
2904 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
2905 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
2906 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
2907 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
2908 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
2910 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
2912 roe_path = create_path()
2914 deadEndPath = create_path()
2916 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
2918 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
2920 pi0softname =
'gamma:PI0SOFT'
2921 etasoftname =
'gamma:ETASOFT'
2922 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
2923 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
2927 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
2929 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
2932 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
2934 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
2936 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
2937 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
2939 if not os.path.isdir(workingDirectory):
2940 os.mkdir(workingDirectory)
2941 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
2943 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
2945 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
2946 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
2948 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
2950 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
2951 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
2953 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
2954 identifier=workingDirectory +
'/pi0veto.root')
2955 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
2956 identifier=workingDirectory +
'/etaveto.root')
2958 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
2959 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
2961 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
2962 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
2964 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2967 def writePi0EtaVeto(
2974 hardParticle='gamma',
2975 pi0PayloadNameOverride=None,
2976 pi0SoftPhotonCutOverride=None,
2977 etaPayloadNameOverride=None,
2978 etaSoftPhotonCutOverride=None
2981 Give pi0/eta probability for hard photon.
2983 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.
2985 The current default weight files are optimised using MC12.
2987 The input variables of the mva training are:
2989 * M: pi0/eta candidates Invariant mass
2990 * daughter(1,E): soft photon energy in lab frame
2991 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
2992 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2993 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
2994 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
2995 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
2996 * cosHelicityAngleMomentum: pi0/eta candidates cosHelicityAngleMomentum
2998 The following strings are available for mode:
3000 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
3001 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
3002 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
3003 * both: tight energy cut and clusterNHits cut are applied to soft photon
3005 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
3006 `pi0Prob`/`etaProb`. Otherwise, it is available as '{Pi0, Eta}ProbOrigin', '{Pi0, Eta}ProbTightEnergyThreshold', '{Pi0,
3007 Eta}ProbLargeClusterSize', or '{Pi0, Eta}ProbTightEnergyThresholdAndLargeClusterSize'} for the four modes described above, with
3008 the chosen suffix appended.
3011 Please don't use following ParticleList names elsewhere:
3013 ``gamma:HardPhoton``,
3014 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
3015 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
3016 ``pi0:EtaVeto + ListName``,
3017 ``eta:EtaVeto + ListName``
3019 @param particleList the input ParticleList
3020 @param decayString specify Particle to be added to the ParticleList
3021 @param mode choose one mode out of 'standard', 'tight', 'cluster' and 'both'
3022 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
3023 @param path modules are added to this path
3024 @param suffix optional suffix to be appended to the usual extraInfo name
3025 @param hardParticle particle name which is used to calculate the pi0/eta probability (default is gamma)
3026 @param pi0PayloadNameOverride specify the payload name of pi0 veto only if one wants to use non-default one. (default is None)
3027 @param pi0SoftPhotonCutOverride specify the soft photon selection criteria of pi0 veto only if one wants to use non-default one.
3029 @param etaPayloadNameOverride specify the payload name of eta veto only if one wants to use non-default one. (default is None)
3030 @param etaSoftPhotonCutOverride specify the soft photon selection criteria of eta veto only if one wants to use non-default one.
3036 B2ERROR(
"The pi0 / eta veto is not suitable for Belle analyses.")
3038 renameSuffix =
False
3040 for module
in path.modules():
3041 if module.type() ==
"SubEvent" and not renameSuffix:
3042 for subpath
in [p.values
for p
in module.available_params()
if p.name ==
"path"]:
3045 for submodule
in subpath.modules():
3046 if f
'{hardParticle}:HardPhoton{suffix}' in submodule.name():
3048 B2WARNING(
"Same extension already used in writePi0EtaVeto, append '_0'")
3052 roe_path = create_path()
3053 deadEndPath = create_path()
3054 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3055 fillSignalSideParticleList(f
'{hardParticle}:HardPhoton{suffix}', decayString, path=roe_path)
3057 dictListName = {
'standard':
'Origin',
3058 'tight':
'TightEnergyThreshold',
3059 'cluster':
'LargeClusterSize',
3060 'both':
'TightEnrgyThresholdAndLargeClusterSize'}
3062 dictPi0EnergyCut = {
'standard':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3063 'tight':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3064 'cluster':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3065 'both':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3067 dictEtaEnergyCut = {
'standard':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3068 'tight':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3069 'cluster':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3070 'both':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]'}
3072 dictNHitsCut = {
'standard':
'clusterNHits >= 0',
3073 'tight':
'clusterNHits >= 0',
3074 'cluster':
'clusterNHits >= 2',
3075 'both':
'clusterNHits >= 2'}
3077 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
3078 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
3079 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
3080 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
3082 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
3083 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
3084 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
3085 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
3087 dictPi0ExtraInfoName = {
'standard':
'Pi0ProbOrigin',
3088 'tight':
'Pi0ProbTightEnergyThreshold',
3089 'cluster':
'Pi0ProbLargeClusterSize',
3090 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize'}
3092 dictEtaExtraInfoName = {
'standard':
'EtaProbOrigin',
3093 'tight':
'EtaProbTightEnergyThreshold',
3094 'cluster':
'EtaProbLargeClusterSize',
3095 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize'}
3097 ListName = dictListName[mode]
3098 Pi0EnergyCut = dictPi0EnergyCut[mode]
3099 EtaEnergyCut = dictEtaEnergyCut[mode]
3100 TimingCut =
'abs(clusterTiming)<clusterErrorTiming'
3101 NHitsCut = dictNHitsCut[mode]
3102 Pi0PayloadName = dictPi0PayloadName[mode]
3103 EtaPayloadName = dictEtaPayloadName[mode]
3104 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
3105 EtaExtraInfoName = dictEtaExtraInfoName[mode]
3108 if pi0PayloadNameOverride
is not None:
3109 Pi0PayloadName = pi0PayloadNameOverride
3110 if pi0SoftPhotonCutOverride
is None:
3111 Pi0SoftPhotonCut = Pi0EnergyCut +
' and ' + NHitsCut
3115 Pi0SoftPhotonCut +=
' and ' + TimingCut
3117 Pi0SoftPhotonCut = pi0SoftPhotonCutOverride
3120 pi0soft = f
'gamma:Pi0Soft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3122 fillParticleList(pi0soft, Pi0SoftPhotonCut, path=roe_path)
3124 reconstructDecay(
'pi0:Pi0Veto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + pi0soft,
'',
3125 allowChargeViolation=
True, path=roe_path)
3127 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName],
3128 extraInfoName=Pi0ExtraInfoName, identifier=Pi0PayloadName)
3130 rankByHighest(
'pi0:Pi0Veto' + ListName,
'extraInfo(' + Pi0ExtraInfoName +
')', numBest=1, path=roe_path)
3132 variableToSignalSideExtraInfo(
'pi0:Pi0Veto' + ListName,
3133 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoName + suffix}, path=roe_path)
3136 if etaPayloadNameOverride
is not None:
3137 EtaPayloadName = etaPayloadNameOverride
3138 if etaSoftPhotonCutOverride
is None:
3139 EtaSoftPhotonCut = EtaEnergyCut +
' and ' + NHitsCut
3143 EtaSoftPhotonCut +=
' and ' + TimingCut
3145 EtaSoftPhotonCut = etaSoftPhotonCutOverride
3147 etasoft = f
'gamma:EtaSoft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3148 fillParticleList(etasoft, EtaSoftPhotonCut, path=roe_path)
3149 reconstructDecay(
'eta:EtaVeto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + etasoft,
'',
3150 allowChargeViolation=
True, path=roe_path)
3151 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName],
3152 extraInfoName=EtaExtraInfoName, identifier=EtaPayloadName)
3153 rankByHighest(
'eta:EtaVeto' + ListName,
'extraInfo(' + EtaExtraInfoName +
')', numBest=1, path=roe_path)
3154 variableToSignalSideExtraInfo(
'eta:EtaVeto' + ListName,
3155 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoName + suffix}, path=roe_path)
3157 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3160 def lowEnergyPi0Identification(pi0List, gammaList, payloadNameSuffix,
3163 Calculate low-energy pi0 identification.
3164 The result is stored as ExtraInfo ``lowEnergyPi0Identification``.
3166 @param pi0List Pi0 list.
3167 @param gammaList Gamma list. First, an energy cut E > 0.2 is applied
3168 to the photons from this list. Then, all possible combinations with a pi0
3169 daughter photon are formed except the one corresponding to
3170 the reconstructed pi0. The maximum low-energy pi0 veto value is calculated
3171 for such photon pairs and used as one of the input variables for
3172 the identification classifier.
3173 @param payloadNameSuffix Payload name suffix. The weight payloads are stored in
3174 the analysis global tag and have the following names:\n
3175 * ``'LowEnergyPi0Veto' + payloadNameSuffix``
3176 * ``'LowEnergyPi0Identification' + payloadNameSuffix``\n
3177 The possible suffixes are:\n
3178 * ``'Belle1'`` for Belle data.
3179 * ``'Belle2Release5'`` for Belle II release 5 data (MC14, proc12, buckets 16 - 25).\n
3180 @param path Module path.
3185 tag = getAnalysisGlobaltagB2BII()
3187 tag = getAnalysisGlobaltag()
3188 basf2.conditions.prepend_globaltag(tag)
3190 cutAndCopyList(
'gamma:pi0veto', gammaList,
'E > 0.2', path=path)
3192 payload_name =
'LowEnergyPi0Veto' + payloadNameSuffix
3193 path.add_module(
'LowEnergyPi0VetoExpert', identifier=payload_name,
3194 VetoPi0Daughters=
True, GammaListName=
'gamma:pi0veto',
3196 payload_name =
'LowEnergyPi0Identification' + payloadNameSuffix
3197 path.add_module(
'LowEnergyPi0IdentificationExpert',
3198 identifier=payload_name, Pi0ListName=pi0List,
3202 def getBeamBackgroundProbability(particleList, path=None):
3204 Assign a probability to each ECL cluster as being signal like (1) compared to beam background like (0)
3205 @param particleList The input ParticleList, must be a photon list
3206 @param path modules are added to this path
3211 B2ERROR(
"The beam background probability is not trained for Belle data.")
3213 basf2.conditions.prepend_globaltag(getAnalysisGlobaltag())
3214 path.add_module(
'MVAExpert',
3215 listNames=particleList,
3216 extraInfoName=
'beamBackgroundSuppression',
3217 identifier=
'BeamBackgroundMVA')
3220 def getHadronicSplitOffProbability(particleList, path=None,):
3222 Assign a probability to each ECL cluster as being signal like (1) compared to hadronic splitoff like (0)
3223 @param particleList The input ParticleList, must be a photon list
3224 @param path modules are added to this path
3229 B2ERROR(
"The hadronic splitoff probability is not trained for Belle data.")
3231 basf2.conditions.prepend_globaltag(getAnalysisGlobaltag())
3232 path.add_module(
'MVAExpert',
3233 listNames=particleList,
3234 extraInfoName=
'hadronicSplitOffSuppression',
3235 identifier=
'HadronicSplitOffMVA')
3238 def buildEventKinematics(inputListNames=None, default_cleanup=True, custom_cuts=None,
3239 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
3241 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3242 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
3243 (all track and all hits in ECL without associated track).
3245 The visible energy missing values are
3246 stored in a EventKinematics dataobject.
3248 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3249 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
3250 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
3251 according to the PID likelihood and the option inputListNames will be ignored.
3252 @param chargedPIDPriors The prior PID fractions, that are used to regulate
3253 amount of certain charged particle species, should be a list of
3254 six floats if not None. The order of particle types is
3255 the following: [e-, mu-, pi-, K-, p+, d+]
3256 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
3257 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3258 which would result in a standard predefined selection cuts
3259 @param path modules are added to this path
3262 if inputListNames
is None:
3264 trackCuts =
'pt > 0.1'
3265 trackCuts +=
' and thetaInCDCAcceptance'
3266 trackCuts +=
' and abs(dz) < 3'
3267 trackCuts +=
' and dr < 0.5'
3269 gammaCuts =
'E > 0.05'
3270 gammaCuts +=
' and thetaInCDCAcceptance'
3272 gammaCuts +=
' and abs(clusterTiming) < 200'
3273 if (custom_cuts
is not None):
3274 trackCuts, gammaCuts = custom_cuts
3276 if fillWithMostLikely:
3277 from stdCharged
import stdMostLikely
3278 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
3279 inputListNames = [
'%s:mostlikely_evtkin' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
3281 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3283 fillParticleList(
'gamma:evtkin',
'', loadPhotonBeamBackgroundMVA=
False, loadPhotonHadronicSplitOffMVA=
False, path=path)
3284 inputListNames += [
'gamma:evtkin']
3286 B2INFO(
"Using default cleanup in EventKinematics module.")
3287 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
3288 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
3289 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3291 B2INFO(
"No cleanup in EventKinematics module.")
3292 if not inputListNames:
3293 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
3294 fillParticleList(
'pi+:evtkin',
'', path=path)
3296 copyList(
'gamma:evtshape',
'gamma:mdst', path=path)
3298 fillParticleList(
'gamma:evtkin',
'', loadPhotonBeamBackgroundMVA=
False, loadPhotonHadronicSplitOffMVA=
False, path=path)
3299 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
3301 if (custom_cuts
is not None):
3302 B2INFO(
"Using default cleanup in EventKinematics module.")
3303 applyCuts(
'pi+:evtkin', trackCuts, path=path)
3304 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3306 B2INFO(
"No cleanup in EventKinematics module.")
3308 particleLists = inputListNames
3310 eventKinematicsModule = register_module(
'EventKinematics')
3311 eventKinematicsModule.set_name(
'EventKinematics_reco')
3312 eventKinematicsModule.param(
'particleLists', particleLists)
3313 path.add_module(eventKinematicsModule)
3316 def buildEventKinematicsFromMC(inputListNames=None, selectionCut='', path=None):
3318 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3319 using generated particles. If no ParticleList is provided, default generated ParticleLists are used.
3321 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3322 If the list is empty, default ParticleLists are filled.
3323 @param selectionCut optional selection cuts
3324 @param path Path to append the eventKinematics module to.
3327 if inputListNames
is None:
3329 if (len(inputListNames) == 0):
3333 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
3336 fillParticleListFromMC(
"%s:evtkin_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
3337 True,
True, path=path)
3338 if (selectionCut !=
''):
3339 applyCuts(
"%s:evtkin_default_gen" % t, selectionCut, path=path)
3340 inputListNames += [
"%s:evtkin_default_gen" % t]
3342 eventKinematicsModule = register_module(
'EventKinematics')
3343 eventKinematicsModule.set_name(
'EventKinematics_gen')
3344 eventKinematicsModule.param(
'particleLists', inputListNames)
3345 eventKinematicsModule.param(
'usingMC',
True)
3346 path.add_module(eventKinematicsModule)
3349 def buildEventShape(inputListNames=None,
3350 default_cleanup=True,
3356 harmonicMoments=True,
3360 checkForDuplicates=False,
3363 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
3364 using the particles in the lists provided by the user. If no particle list is provided,
3365 the function will internally create a list of good tracks and a list of good photons
3366 with (optionally) minimal quality cuts.
3369 The results of the calculation are then stored into the EventShapeContainer dataobject,
3370 and are accessible using the variables of the EventShape group.
3372 The user can switch the calculation of certain quantities on or off to save computing
3373 time. By default the calculation of the high-order moments (5-8) is turned off.
3374 Switching off an option will make the corresponding variables not available.
3377 The user can provide as many particle lists
3378 as needed, using also combined particles, but the function will always assume that
3379 the lists are independent.
3380 If the lists provided by the user contain several times the same track (either with
3381 different mass hypothesis, or once as an independent particle and once as daughter of a
3382 combined particle) the results won't be reliable.
3383 A basic check for duplicates is available setting the checkForDuplicate flags,
3384 but is usually quite time consuming.
3387 @param inputListNames List of ParticleLists used to calculate the
3388 event shape variables. If the list is empty the default
3389 particleLists pi+:evtshape and gamma:evtshape are filled.
3390 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
3391 defining the internal lists. This option is ignored if the
3392 particleLists are provided by the user.
3393 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3394 which would result in a standard predefined selection cuts
3395 @param path Path to append the eventShape modules to.
3396 @param thrust Enables the calculation of thrust-related quantities (CLEO
3397 cones, Harmonic moments, jets).
3398 @param collisionAxis Enables the calculation of the quantities related to the
3400 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
3401 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
3402 to both the thrust axis and, if collisionAxis = True, the collision axis.
3403 @param allMoments If True, calculates also the FW and harmonic moments from order
3404 5 to 8 instead of the low-order ones only.
3405 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
3406 axis and, if collisionAxis = True, the collision axis.
3407 @param jets Enables the calculation of the hemisphere momenta and masses.
3408 Requires thrust = True.
3409 @param sphericity Enables the calculation of the sphericity-related quantities.
3410 @param checkForDuplicates Perform a check for duplicate particles before adding them. This option
3411 is quite time consuming, instead of using it consider sanitizing
3412 the lists you are passing to the function.
3415 if inputListNames
is None:
3417 trackCuts =
'pt > 0.1'
3418 trackCuts +=
' and thetaInCDCAcceptance'
3419 trackCuts +=
' and abs(dz) < 3.0'
3420 trackCuts +=
' and dr < 0.5'
3422 gammaCuts =
'E > 0.05'
3423 gammaCuts +=
' and thetaInCDCAcceptance'
3425 gammaCuts +=
' and abs(clusterTiming) < 200'
3426 if (custom_cuts
is not None):
3427 trackCuts, gammaCuts = custom_cuts
3429 if not inputListNames:
3430 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
3431 fillParticleList(
'pi+:evtshape',
'', path=path)
3433 copyList(
'gamma:evtshape',
'gamma:mdst', path=path)
3438 loadPhotonBeamBackgroundMVA=
False,
3439 loadPhotonHadronicSplitOffMVA=
False,
3441 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
3444 if (custom_cuts
is not None):
3445 B2INFO(
"Applying standard cuts")
3446 applyCuts(
'pi+:evtshape', trackCuts, path=path)
3448 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
3450 B2WARNING(
"Creating the default lists with no cleanup.")
3452 particleLists = inputListNames
3454 eventShapeModule = register_module(
'EventShapeCalculator')
3455 eventShapeModule.set_name(
'EventShape')
3456 eventShapeModule.param(
'particleListNames', particleLists)
3457 eventShapeModule.param(
'enableAllMoments', allMoments)
3458 eventShapeModule.param(
'enableCleoCones', cleoCones)
3459 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
3460 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
3461 eventShapeModule.param(
'enableJets', jets)
3462 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
3463 eventShapeModule.param(
'enableSphericity', sphericity)
3464 eventShapeModule.param(
'enableThrust', thrust)
3465 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
3467 path.add_module(eventShapeModule)
3470 def labelTauPairMC(printDecayInfo=False, path=None, TauolaBelle=False, mapping_minus=None, mapping_plus=None):
3472 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
3473 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
3475 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
3476 @param path: module is added to this path
3477 @param TauolaBelle: if False, TauDecayMode is set. If True, TauDecayMarker is set.
3478 @param mapping_minus: if None, the map is the default one, else the path for the map is given by the user for tau-
3479 @param mapping_plus: if None, the map is the default one, else the path for the map is given by the user for tau+
3482 from basf2
import find_file
3488 m_printmode =
'default'
3490 if mapping_minus
is None:
3491 mp_file_minus = find_file(
'data/analysis/modules/TauDecayMode/map_tauminus.txt')
3493 mp_file_minus = mapping_minus
3495 if mapping_plus
is None:
3496 mp_file_plus = find_file(
'data/analysis/modules/TauDecayMode/map_tauplus.txt')
3498 mp_file_plus = mapping_plus
3500 path.add_module(
'TauDecayMode', printmode=m_printmode, file_minus=mp_file_minus, file_plus=mp_file_plus)
3503 tauDecayMarker = register_module(
'TauDecayMarker')
3504 tauDecayMarker.set_name(
'TauDecayMarker_')
3506 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
3509 def tagCurlTracks(particleLists,
3519 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
3521 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
3522 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
3524 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
3527 The module loops over all particles in a given list with a transverse momentum below the pre-selection **ptCut**
3528 and assigns them to bundles based on the response of the chosen **selector** and the required minimum response set by the
3529 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
3530 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
3534 @param particleLists: list of particle lists to check for curls.
3535 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
3536 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
3537 genParticleIndex then ranked and tagged as normal.
3538 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
3539 If set to ``-1`` a cut value optimised to maximise the accuracy on a BBbar sample is used.
3540 Note 'cut' selector is binary 0/1.
3541 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
3542 It is strongly recommended to used the 'mva' selection. The 'cut' selection
3543 is based on BN1079 and is only calibrated for Belle data.
3545 @param ptCut: Pre-selection cut on transverse momentum. Only tracks below that are considered as curler candidates.
3547 @param expert_train: flag to set training mode if selector has a training mode (mva).
3548 @param expert_filename: set file name of produced training ntuple (mva).
3549 @param path: module is added to this path.
3555 if (
not isinstance(particleLists, list)):
3556 particleLists = [particleLists]
3558 curlTagger = register_module(
'CurlTagger')
3559 curlTagger.set_name(
'CurlTagger_')
3560 curlTagger.param(
'particleLists', particleLists)
3561 curlTagger.param(
'belle', belle)
3562 curlTagger.param(
'mcTruth', mcTruth)
3563 curlTagger.param(
'responseCut', responseCut)
3564 if abs(responseCut + 1) < 1e-9:
3565 curlTagger.param(
'usePayloadCut',
True)
3567 curlTagger.param(
'usePayloadCut',
False)
3569 curlTagger.param(
'selectorType', selectorType)
3570 curlTagger.param(
'ptCut', ptCut)
3571 curlTagger.param(
'train', expert_train)
3572 curlTagger.param(
'trainFilename', expert_filename)
3574 path.add_module(curlTagger)
3577 def applyChargedPidMVA(particleLists, path, trainingMode, chargeIndependent=False, binaryHypoPDGCodes=(0, 0)):
3579 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
3581 The module decorates Particle objects in the input ParticleList(s) with variables
3582 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
3585 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.3.0**, **ROOT 6.20/04**).
3587 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
3589 * e (11) vs. pi (211)
3590 * mu (13) vs. pi (211)
3591 * pi (211) vs. K (321)
3592 * K (321) vs. pi (211)
3594 , or 'global' PID, namely "one-vs-others" separation. The latter exploits an MVA algorithm trained in multi-class mode,
3595 and it's the default behaviour. Currently, the multi-class training separates the following standard charged hypotheses:
3597 - e (11), mu (13), pi (211), K (321)
3600 In order to run the `ChargedPidMVA` and ensure the most up-to-date MVA training weights are applied,
3601 it is necessary to append the latest analysis global tag (GT) to the steering script.
3604 particleLists (list(str)): the input list of DecayStrings, where each selected (^) daughter should correspond to a
3605 standard charged ParticleList, e.g. ``['Lambda0:sig -> ^p+ ^pi-', 'J/psi:sig -> ^mu+ ^mu-']``.
3606 One can also directly pass a list of standard charged ParticleLists,
3607 e.g. ``['e+:my_electrons', 'pi+:my_pions']``.
3608 Note that charge-conjugated ParticleLists will automatically be included.
3609 path (basf2.Path): the module is added to this path.
3610 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
3611 Needed to pick up the correct payload from the DB. Available choices:
3613 * c_Classification=0
3615 * c_ECL_Classification=2
3616 * c_ECL_Multiclass=3
3617 * c_PSD_Classification=4
3618 * c_PSD_Multiclass=5
3619 * c_ECL_PSD_Classification=6
3620 * c_ECL_PSD_Multiclass=7
3622 chargeIndependent (bool, ``optional``): use a BDT trained on a sample of inclusively charged particles.
3623 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
3624 Required only for binary PID mode.
3629 B2ERROR(
"Charged PID via MVA is not available for Belle data.")
3631 from ROOT
import Belle2
3633 TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
3636 plSet = set(particleLists)
3640 TrainingMode.c_Classification:
3641 {
"mode":
"Classification",
"detector":
"ALL"},
3642 TrainingMode.c_Multiclass:
3643 {
"mode":
"Multiclass",
"detector":
"ALL"},
3644 TrainingMode.c_ECL_Classification:
3645 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
3646 TrainingMode.c_ECL_Multiclass:
3647 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
3648 TrainingMode.c_PSD_Classification:
3649 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
3650 TrainingMode.c_PSD_Multiclass:
3651 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
3652 TrainingMode.c_ECL_PSD_Classification:
3653 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
3654 TrainingMode.c_ECL_PSD_Multiclass:
3655 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
3658 if payloadNames.get(trainingMode)
is None:
3659 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
3660 "\nis not supported. Please choose among the following:\n",
3661 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
3663 mode = payloadNames.get(trainingMode).get(
"mode")
3664 detector = payloadNames.get(trainingMode).get(
"detector")
3666 payloadName = f
"ChargedPidMVAWeights_{mode}"
3671 Const.electron.getPDGCode():
3672 {
"pName":
"e",
"pFullName":
"electron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3673 Const.muon.getPDGCode():
3674 {
"pName":
"mu",
"pFullName":
"muon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3675 Const.pion.getPDGCode():
3676 {
"pName":
"pi",
"pFullName":
"pion",
"pNameBkg":
"K",
"pdgIdBkg": Const.kaon.getPDGCode()},
3677 Const.kaon.getPDGCode():
3678 {
"pName":
"K",
"pFullName":
"kaon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3679 Const.proton.getPDGCode():
3680 {
"pName":
"p",
"pFullName":
"proton",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3681 Const.deuteron.getPDGCode():
3682 {
"pName":
"d",
"pFullName":
"deuteron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3685 if binaryHypoPDGCodes == (0, 0):
3688 chargedpid = register_module(
"ChargedPidMVAMulticlass")
3689 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
3696 binaryOpts = [(pdgIdSig, info[
"pdgIdBkg"])
for pdgIdSig, info
in stdChargedMap.items()]
3698 if binaryHypoPDGCodes
not in binaryOpts:
3699 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
3700 ". Please choose among the following pairs:\n",
3701 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
3705 if not decayDescriptor.init(name):
3706 raise ValueError(f
"Invalid particle list {name} in applyChargedPidMVA!")
3707 msg = f
"Input ParticleList: {name}"
3708 pdgs = [abs(decayDescriptor.getMother().getPDGCode())]
3709 daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
3710 if len(daughter_pdgs) > 0:
3711 pdgs = daughter_pdgs
3712 for idaughter, pdg
in enumerate(pdgs):
3713 if abs(pdg)
not in binaryHypoPDGCodes:
3715 msg = f
"Selected daughter {idaughter} in ParticleList: {name}"
3717 f
"{msg} (PDG={pdg}) is neither signal ({binaryHypoPDGCodes[0]}) nor background ({binaryHypoPDGCodes[1]}).")
3719 chargedpid = register_module(
"ChargedPidMVA")
3720 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
3721 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
3722 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
3724 chargedpid.param(
"particleLists", list(plSet))
3725 chargedpid.param(
"payloadName", payloadName)
3726 chargedpid.param(
"chargeIndependent", chargeIndependent)
3729 if detector ==
"ECL":
3730 chargedpid.param(
"useECLOnlyTraining",
True)
3732 path.add_module(chargedpid)
3735 def calculateTrackIsolation(
3739 reference_list_name=None,
3740 vars_for_nearest_part=[],
3741 highest_prob_mass_for_ext=True,
3742 exclude_pid_det_weights=False):
3744 Given an input decay string, compute variables that quantify track helix-based isolation of the charged
3745 stable particles in the input decay chain.
3748 An "isolation score" can be defined using the distance
3749 of each particle to its closest neighbour, defined as the segment connecting the two
3750 extrapolated track helices intersection points on a given cylindrical surface.
3751 The distance variables defined in the `VariableManager` is named `minET2ETDist`,
3752 the isolation scores are named `minET2ETIsoScore`.
3754 The definition of distance and the number of distances that are calculated per sub-detector is based on
3755 the following recipe:
3757 * **CDC**: as the segmentation is very coarse along :math:`z`,
3758 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
3759 A total of 9 distances are calculated: the cylindrical surfaces are defined at radiuses
3760 that correspond to the positions of the 9 CDC wire superlayers: :math:`R_{i}^{\\mathrm{CDC}}~(i \\in \\{0,...,8\\})`.
3762 * **TOP**: as there is no segmentation along :math:`z`,
3763 the distance is defined as the cord length on the :math:`(\\rho=R, \\phi)` plane.
3764 Only one distance at the TOP entry radius :math:`R_{0}^{\\mathrm{TOP}}` is calculated.
3766 * **ARICH**: as there is no segmentation along :math:`z`,
3767 the distance is defined as the distance on the :math:`(\\rho=R, \\phi)` plane at fixed :math:`z=Z`.
3768 Only one distance at the ARICH photon detector entry coordinate :math:`Z_{0}^{\\mathrm{ARICH}}` is calculated.
3770 * **ECL**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
3771 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
3772 Two distances are calculated: one at the ECL entry surface :math:`R_{0}^{\\mathrm{ECL}}` (barrel),
3773 :math:`Z_{0}^{\\mathrm{ECL}}` (endcaps), and one at :math:`R_{1}^{\\mathrm{ECL}}` (barrel),
3774 :math:`Z_{1}^{\\mathrm{ECL}}` (endcaps), corresponding roughly to the mid-point
3775 of the longitudinal size of the crystals.
3777 * **KLM**: the distance is defined on the :math:`(\\rho=R, \\phi, z)` surface in the barrel,
3778 on the :math:`(\\rho, \\phi, z=Z)` surface in the endcaps.
3779 Only one distance at the KLM first strip entry surface :math:`R_{0}^{\\mathrm{KLM}}` (barrel),
3780 :math:`Z_{0}^{\\mathrm{KLM}}` (endcaps) is calculated.
3783 decay_string (str): name of the input decay string with selected charged stable daughters,
3784 for example: ``Lambda0:merged -> ^p+ ^pi-``.
3785 Alternatively, it can be a particle list for charged stable particles
3786 as defined in ``Const::chargedStableSet``, for example: ``mu+:all``.
3787 The charge-conjugate particle list will be also processed automatically.
3788 path (basf2.Path): path to which module(s) will be added.
3789 *detectors: detectors for which track isolation variables will be calculated.
3790 Choose among: ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
3791 reference_list_name (Optional[str]): name of the input charged stable particle list for the reference tracks.
3792 By default, the ``:all`` ParticleList of the same type
3793 of the selected particle in ``decay_string`` is used.
3794 The charge-conjugate particle list will be also processed automatically.
3795 vars_for_nearest_part (Optional[list(str)]): a list of variables to calculate for the nearest particle in the reference
3796 list at each detector surface. It uses the metavariable `minET2ETDistVar`.
3797 If unset, only the distances to the nearest neighbour
3798 per detector are calculated.
3799 highest_prob_mass_for_hex (Optional[bool]): if this option is set to True (default), the helix extrapolation
3800 for the particles will use the track fit result for the most
3801 probable mass hypothesis, namely, the one that gives the highest
3802 chi2Prob of the fit. Otherwise, it uses the mass hypothesis that
3803 corresponds to the particle lists PDG.
3804 exclude_pid_det_weights (Optional[bool]): if this option is set to False (default), the isolation score
3805 calculation will take into account the weight that each detector has on the PID
3806 for the particle species of interest.
3809 dict(int, list(str)): a dictionary mapping the PDG of each reference particle list to its isolation variables.
3814 from ROOT
import Belle2, TDatabasePDG
3817 if not decayDescriptor.init(decay_string):
3818 B2FATAL(f
"Invalid particle list {decay_string} in calculateTrackIsolation!")
3819 no_reference_list_name =
not reference_list_name
3822 "CDC": list(range(9)),
3828 if any(d
not in det_and_layers
for d
in detectors):
3830 "Your input detector list: ",
3832 " contains an invalid choice. Please select among: ",
3834 det_and_layers.keys()))
3839 processed_decay_strings = []
3840 if select_symbol
in decay_string:
3841 splitted_ds = decay_string.split(select_symbol)
3842 for i
in range(decay_string.count(select_symbol)):
3843 tmp = list(splitted_ds)
3844 tmp.insert(i+1, select_symbol)
3845 processed_decay_strings += [
''.join(tmp)]
3847 processed_decay_strings += [decay_string]
3849 reference_lists_to_vars = {}
3851 for processed_dec
in processed_decay_strings:
3852 if no_reference_list_name:
3853 decayDescriptor.init(processed_dec)
3854 selected_daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
3855 if len(selected_daughter_pdgs) > 0:
3856 reference_list_name = f
'{TDatabasePDG.Instance().GetParticle(abs(selected_daughter_pdgs[-1])).GetName()}:all'
3858 reference_list_name = f
'{processed_dec.split(":")[0]}:all'
3862 for det
in detectors:
3863 trackiso = path.add_module(
"TrackIsoCalculator",
3864 decayString=processed_dec,
3866 particleListReference=reference_list_name,
3867 useHighestProbMassForExt=highest_prob_mass_for_ext,
3868 excludePIDDetWeights=exclude_pid_det_weights)
3869 trackiso.set_name(f
"TrackIsoCalculator{det}_{processed_dec}_VS_{reference_list_name}")
3875 f
"minET2ETDist({d}, {d_layer}, {reference_list_name}, {int(highest_prob_mass_for_ext)})"
3876 for d
in detectors
for d_layer
in det_and_layers[d]]
3878 trackiso_vars += [f
"minET2ETIsoScore({reference_list_name}, {int(highest_prob_mass_for_ext)}, {','.join(detectors)})"]
3880 if vars_for_nearest_part:
3881 trackiso_vars.extend(
3883 f
"minET2ETDistVar({d}, {d_layer}, {reference_list_name}, {v})"
3884 for d
in detectors
for d_layer
in det_and_layers[d]
for v
in vars_for_nearest_part
3886 trackiso_vars.sort()
3888 reference_lists_to_vars[ref_pdg] = trackiso_vars
3890 return reference_lists_to_vars
3893 def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
3895 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
3896 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
3897 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
3898 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
3901 .. code-block:: python
3903 from modularAnalysis import calculateDistance
3904 calculateDistance('list_name', 'decay_string', "mode", path=user_path)
3906 @param list_name name of the input ParticleList
3907 @param decay_string select particles between the distance of closest approach will be calculated
3908 @param mode Specifies how the distance is calculated
3909 vertextrack: calculate the distance of closest approach between a track and a\
3910 vertex, taking the first candidate as vertex, default
3911 trackvertex: calculate the distance of closest approach between a track and a\
3912 vertex, taking the first candidate as track
3913 2tracks: calculates the distance of closest approach between two tracks
3914 2vertices: calculates the distance between two vertices
3915 vertexbtube: calculates the distance of closest approach between a vertex and btube
3916 trackbtube: calculates the distance of closest approach between a track and btube
3917 @param path modules are added to this path
3921 dist_mod = register_module(
'DistanceCalculator')
3923 dist_mod.set_name(
'DistanceCalculator_' + list_name)
3924 dist_mod.param(
'listName', list_name)
3925 dist_mod.param(
'decayString', decay_string)
3926 dist_mod.param(
'mode', mode)
3927 path.add_module(dist_mod)
3930 def addInclusiveDstarReconstruction(decayString, slowPionCut, DstarCut, path):
3932 Adds the InclusiveDstarReconstruction module to the given path.
3933 This module creates a D* particle list by estimating the D* four momenta
3934 from slow pions, specified by a given cut. The D* energy is approximated
3935 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
3936 momentum is calculated using the D* PDG mass and the direction is collinear
3937 to the slow pion direction. The charge of the given pion list has to be consistent
3940 @param decayString Decay string, must be of form ``D* -> pi``
3941 @param slowPionCut Cut applied to the input pion list to identify slow pions
3942 @param DstarCut Cut applied to the output D* list
3943 @param path the module is added to this path
3946 incl_dstar = register_module(
"InclusiveDstarReconstruction")
3947 incl_dstar.param(
"decayString", decayString)
3948 incl_dstar.param(
"slowPionCut", slowPionCut)
3949 incl_dstar.param(
"DstarCut", DstarCut)
3950 path.add_module(incl_dstar)
3953 def scaleError(outputListName, inputListName,
3954 scaleFactors=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
3955 scaleFactorsNoPXD=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
3956 d0Resolution=[0.00115328, 0.00134704],
3957 z0Resolution=[0.00124327, 0.0013272],
3962 This module creates a new charged particle list.
3963 The helix errors of the new particles are scaled by constant factors.
3964 Two sets of five scale factors are defined for tracks with and without a PXD hit.
3965 The scale factors are in order of (d0, phi0, omega, z0, tanlambda).
3966 For tracks with a PXD hit, in order to avoid severe underestimation of d0 and z0 errors,
3967 lower limits (best resolution) can be set in a momentum-dependent form.
3968 This module is supposed to be used only for TDCPV analysis and for low-momentum (0-3 GeV/c) tracks in BBbar events.
3969 Details will be documented in a Belle II note, BELLE2-NOTE-PH-2021-038.
3971 @param inputListName Name of input charged particle list to be scaled
3972 @param outputListName Name of output charged particle list with scaled error
3973 @param scaleFactors List of five constants to be multiplied to each of helix errors (for tracks with a PXD hit)
3974 @param scaleFactorsNoPXD List of five constants to be multiplied to each of helix errors (for tracks without a PXD hit)
3975 @param d0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
3976 defining d0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**1.5))**2 }
3977 @param z0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
3978 defining z0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**2.5))**2 }
3979 @param d0MomThr d0 best resolution is kept constant below this momentum
3980 @param z0MomThr z0 best resolution is kept constant below this momentum
3984 scale_error = register_module(
"HelixErrorScaler")
3985 scale_error.set_name(
'ScaleError_' + inputListName)
3986 scale_error.param(
'inputListName', inputListName)
3987 scale_error.param(
'outputListName', outputListName)
3988 scale_error.param(
'scaleFactors_PXD', scaleFactors)
3989 scale_error.param(
'scaleFactors_noPXD', scaleFactorsNoPXD)
3990 scale_error.param(
'd0ResolutionParameters', d0Resolution)
3991 scale_error.param(
'z0ResolutionParameters', z0Resolution)
3992 scale_error.param(
'd0MomentumThreshold', d0MomThr)
3993 scale_error.param(
'z0MomentumThreshold', z0MomThr)
3994 path.add_module(scale_error)
3997 def correctEnergyBias(inputListNames, tableName, path=None):
3999 Scale energy of the particles according to the scaling factor.
4000 If the particle list contains composite particles, the energy of the daughters are scaled.
4001 Subsequently, the energy of the mother particle is updated as well.
4004 inputListNames (list(str)): input particle list names
4005 tableName : stored in localdb and created using ParticleWeightingLookUpCreator
4006 path (basf2.Path): module is added to this path
4011 B2ERROR(
"The energy bias cannot be corrected with this tool for Belle data.")
4013 correctenergybias = register_module(
'EnergyBiasCorrection')
4014 correctenergybias.param(
'particleLists', inputListNames)
4015 correctenergybias.param(
'tableName', tableName)
4016 path.add_module(correctenergybias)
4019 def addPhotonEfficiencyRatioVariables(inputListNames, tableName, path=None):
4021 Add photon Data/MC detection efficiency ratio weights to the specified particle list
4024 inputListNames (list(str)): input particle list names
4025 tableName : taken from database with appropriate name
4026 path (basf2.Path): module is added to this path
4031 B2ERROR(
"For Belle data the photon data/MC detection efficiency ratio is not available with this tool.")
4033 photon_efficiency_correction = register_module(
'PhotonEfficiencySystematics')
4034 photon_efficiency_correction.param(
'particleLists', inputListNames)
4035 photon_efficiency_correction.param(
'tableName', tableName)
4036 path.add_module(photon_efficiency_correction)
4039 def addPi0VetoEfficiencySystematics(particleList, decayString, tableName, threshold, mode='standard', suffix='', path=None):
4041 Add pi0 veto Data/MC efficiency ratio weights to the specified particle list
4043 @param particleList the input ParticleList
4044 @param decayString specify hard photon to be performed pi0 veto (e.g. 'B+:sig -> rho+:sig ^gamma:hard')
4045 @param tableName table name corresponding to payload version (e.g. 'Pi0VetoEfficiencySystematics_Mar2022')
4046 @param threshold pi0 veto threshold (0.10, 0.11, ..., 0.99)
4047 @param mode choose one mode (same as writePi0EtaVeto) out of 'standard', 'tight', 'cluster' and 'both'
4048 @param suffix optional suffix to be appended to the usual extraInfo name
4049 @param path the module is added to this path
4051 The following extraInfo are available related with the given particleList:
4052 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_ratio : weight of Data/MC for the veto efficiency
4053 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_stat : the statistical uncertainty of the weight
4054 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_sys : the systematic uncertainty of the weight
4055 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_total : the total uncertainty of the weight
4056 * Pi0VetoEfficiencySystematics_{mode}{suffix}_threshold : threshold of the pi0 veto
4061 B2ERROR(
"For Belle data the pi0 veto data/MC efficiency ratio weights are not available via this tool.")
4063 pi0veto_efficiency_correction = register_module(
'Pi0VetoEfficiencySystematics')
4064 pi0veto_efficiency_correction.param(
'particleLists', particleList)
4065 pi0veto_efficiency_correction.param(
'decayString', decayString)
4066 pi0veto_efficiency_correction.param(
'tableName', tableName)
4067 pi0veto_efficiency_correction.param(
'threshold', threshold)
4068 pi0veto_efficiency_correction.param(
'mode', mode)
4069 pi0veto_efficiency_correction.param(
'suffix', suffix)
4070 path.add_module(pi0veto_efficiency_correction)
4073 def getAnalysisGlobaltag(timeout=180) -> str:
4075 Returns a string containing the name of the latest and recommended analysis globaltag.
4078 timeout: Seconds to wait for b2conditionsdb-recommend
4083 B2ERROR(
"The getAnalysisGlobaltag() function cannot be used for Belle data.")
4088 tags = subprocess.check_output(
4089 [
'b2conditionsdb-recommend',
'--oneline'],
4091 ).decode(
'UTF-8').rstrip().split(
' ')
4094 if tag.startswith(
'analysis_tools'):
4098 except subprocess.TimeoutExpired
as te:
4099 B2FATAL(f
'A {te} exception was raised during the call of getAnalysisGlobaltag(). '
4100 'The function took too much time to retrieve the requested information '
4101 'from the versioning repository.\n'
4102 'Please try to re-run your job. In case of persistent failures, there may '
4103 'be issues with the DESY collaborative services, so please contact the experts.')
4104 except subprocess.CalledProcessError
as ce:
4105 B2FATAL(f
'A {ce} exception was raised during the call of getAnalysisGlobaltag(). '
4106 'Please try to re-run your job. In case of persistent failures, please contact '
4110 def getAnalysisGlobaltagB2BII() -> str:
4112 Get recommended global tag for B2BII analysis.
4117 B2ERROR(
'The getAnalysisGlobaltagB2BII() function cannot be used for Belle II data.')
4118 from versioning
import recommended_b2bii_analysis_global_tag
4119 return recommended_b2bii_analysis_global_tag()
4122 def getNbarIDMVA(particleList, path=None):
4124 This function can give a score to predict if it is a anti-n0.
4125 It is not used to predict n0.
4126 Currently, this can be used only for ECL cluster.
4127 output will be stored in extraInfo(nbarID); -1 means MVA invalid
4128 @param particleList The input ParticleList
4129 @param path modules are added to this path
4134 B2ERROR(
"The MVA-based anti-neutron PID is only available for Belle II data.")
4136 from variables
import variables
4137 variables.addAlias(
'V1',
'clusterHasPulseShapeDiscrimination')
4138 variables.addAlias(
'V2',
'clusterE')
4139 variables.addAlias(
'V3',
'clusterLAT')
4140 variables.addAlias(
'V4',
'clusterE1E9')
4141 variables.addAlias(
'V5',
'clusterE9E21')
4142 variables.addAlias(
'V6',
'clusterZernikeMVA')
4143 variables.addAlias(
'V7',
'clusterAbsZernikeMoment40')
4144 variables.addAlias(
'V8',
'clusterAbsZernikeMoment51')
4146 variables.addAlias(
'nbarIDValid',
4147 'passesCut(V1 == 1 and V2 >= 0 and V3 >= 0 and V4 >= 0 and V5 >= 0 and V6 >= 0 and V7 >= 0 and V8 >= 0)')
4148 variables.addAlias(
'nbarIDmod',
'conditionalVariableSelector(nbarIDValid == 1, extraInfo(nbarIDFromMVA), constant(-1.0))')
4149 basf2.conditions.prepend_globaltag(getAnalysisGlobaltag())
4150 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'nbarIDFromMVA', identifier=
'db_nbarIDECL')
4154 def reconstructDecayWithNeutralHadron(decayString, cut, allowGamma=False, allowAnyParticleSource=False, path=None, **kwargs):
4156 Reconstructs decay with a long-lived neutral hadron e.g.
4157 :math:`B^0 \to J/\psi K_L^0`,
4158 :math:`B^0 \to p \bar{n} D^*(2010)^-`.
4160 The calculation is done with IP constraint and mother mass constraint.
4162 The decay string passed in must satisfy the following rules:
4164 - The neutral hadron must be **selected** in the decay string with the
4165 caret (``^``) e.g. ``B0:sig -> J/psi:sig ^K_L0:sig``. (Note the caret
4166 next to the neutral hadron.)
4167 - There can only be **one neutral hadron in a decay**.
4168 - The neutral hadron has to be a direct daughter of its mother.
4170 .. note:: This function forwards its arguments to `reconstructDecay`,
4171 so please check the documentation of `reconstructDecay` for all
4174 @param decayString A decay string following the mentioned rules
4175 @param cut Cut to apply to the particle list
4176 @param allowGamma Whether allow the selected particle to be ``gamma``
4177 @param allowAnyParticleSource Whether allow the selected particle to be from any source.
4178 Should only be used when studying control sample.
4179 @param path The path to put in the module
4182 reconstructDecay(decayString, cut, path=path, **kwargs)
4183 module = register_module(
'NeutralHadron4MomentumCalculator')
4184 module.set_name(
'NeutralHadron4MomentumCalculator_' + decayString)
4185 module.param(
'decayString', decayString)
4186 module.param(
'allowGamma', allowGamma)
4187 module.param(
'allowAnyParticleSource', allowAnyParticleSource)
4188 path.add_module(module)
4191 if __name__ ==
'__main__':
4193 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)