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
174 setAnalysisConfigParams({
'mcMatchingVersion':
'Belle'}, path)
177 basf2.conditions.metadata_providers = [
"/sw/belle/b2bii/database/conditions/b2bii.sqlite"]
178 basf2.conditions.payload_locations = [
"/sw/belle/b2bii/database/conditions/"]
181 def outputMdst(filename, path):
183 Saves mDST (mini-Data Summary Tables) to the output root file.
187 This function is kept for backward-compatibility.
188 Better to use `mdst.add_mdst_output` directly.
196 def outputUdst(filename, particleLists=None, includeArrays=None, path=None, dataDescription=None):
198 Save uDST (user-defined Data Summary Tables) = MDST + Particles + ParticleLists
199 The charge-conjugate lists of those given in particleLists are also stored.
200 Additional Store Arrays and Relations to be stored can be specified via includeArrays
204 This does not reduce the amount of Particle objects saved,
205 see `udst.add_skimmed_udst_output` for a function that does.
210 path=path, filename=filename, particleLists=particleLists,
211 additionalBranches=includeArrays, dataDescription=dataDescription)
214 def outputIndex(filename, path, includeArrays=None, keepParents=False, mc=True):
216 Write out all particle lists as an index file to be reprocessed using parentLevel flag.
217 Additional branches necessary for file to be read are automatically included.
218 Additional Store Arrays and Relations to be stored can be specified via includeArrays
221 @param str filename the name of the output index file
222 @param str path modules are added to this path
223 @param list(str) includeArrays: datastore arrays/objects to write to the output
224 file in addition to particle lists and related information
225 @param bool keepParents whether the parents of the input event will be saved as the parents of the same event
226 in the output index file. Useful if you are only adding more information to another index file
227 @param bool mc whether the input data is MC or not
229 if includeArrays
is None:
233 onlyPLists = register_module(
'OnlyWriteOutParticleLists')
234 path.add_module(onlyPLists)
239 'ParticlesToMCParticles',
240 'ParticlesToPIDLikelihoods',
241 'ParticleExtraInfoMap',
244 branches = [
'EventMetaData']
245 persistentBranches = [
'FileMetaData']
249 branches += partBranches
250 branches += includeArrays
252 r1 = register_module(
'RootOutput')
253 r1.param(
'outputFileName', filename)
254 r1.param(
'additionalBranchNames', branches)
255 r1.param(
'branchNamesPersistent', persistentBranches)
256 r1.param(
'keepParents', keepParents)
260 def setupEventInfo(noEvents, path):
262 Prepare to generate events. This function sets up the EventInfoSetter.
263 You should call this before adding a generator from generators.
264 The experiment and run numbers are set to 0 (run independent generic MC in phase 3).
265 https://confluence.desy.de/display/BI/Experiment+numbering
268 noEvents (int): number of events to be generated
269 path (basf2.Path): modules are added to this path
271 evtnumbers = register_module(
'EventInfoSetter')
272 evtnumbers.param(
'evtNumList', [noEvents])
273 evtnumbers.param(
'runList', [0])
274 evtnumbers.param(
'expList', [0])
275 path.add_module(evtnumbers)
278 def loadGearbox(path, silence_warning=False):
280 Loads Gearbox module to the path.
283 Should be used in a job with *cosmic event generation only*
285 Needed for scripts which only generate cosmic events in order to
288 @param path modules are added to this path
289 @param silence_warning stops a verbose warning message if you know you want to use this function
292 if not silence_warning:
293 B2WARNING(
"""You are overwriting the geometry from the database with Gearbox.
294 This is fine if you're generating cosmic events. But in most other cases you probably don't want this.
296 If you're really sure you know what you're doing you can suppress this message with:
298 >>> loadGearbox(silence_warning=True)
302 paramloader = register_module(
'Gearbox')
303 path.add_module(paramloader)
306 def printPrimaryMCParticles(path, **kwargs):
308 Prints all primary MCParticles, that is particles from
309 the physics generator and not particles created by the simulation
311 This is equivalent to `printMCParticles(onlyPrimaries=True, path=path) <printMCParticles>` and additional
312 keyword arguments are just forwarded to that function
314 return printMCParticles(onlyPrimaries=
True, path=path, **kwargs)
317 def printMCParticles(onlyPrimaries=False, maxLevel=-1, path=None, *,
318 showProperties=False, showMomenta=False, showVertices=False, showStatus=False, suppressPrint=False):
320 Prints all MCParticles or just primary MCParticles up to specified level. -1 means no limit.
322 By default this will print a tree of just the particle names and their pdg
323 codes in the event, for example ::
325 [INFO] Content of MCParticle list
326 ╰── Upsilon(4S) (300553)
328 │ ├── anti-D_0*0 (-10421)
329 │ │ ├── D- (-411)
330 │ │ │ ├── K*- (-323)
331 │ │ │ │ ├── anti-K0 (-311)
332 │ │ │ │ │ ╰── K_S0 (310)
333 │ │ │ │ │ ├── pi+ (211)
334 │ │ │ │ │ │ ╰╶╶ p+ (2212)
335 │ │ │ │ │ ╰── pi- (-211)
336 │ │ │ │ │ ├╶╶ e- (11)
337 │ │ │ │ │ ├╶╶ n0 (2112)
338 │ │ │ │ │ ├╶╶ n0 (2112)
339 │ │ │ │ │ ╰╶╶ n0 (2112)
340 │ │ │ │ ╰── pi- (-211)
341 │ │ │ │ ├╶╶ anti-nu_mu (-14)
342 │ │ │ │ ╰╶╶ mu- (13)
343 │ │ │ │ ├╶╶ nu_mu (14)
344 │ │ │ │ ├╶╶ anti-nu_e (-12)
345 │ │ │ │ ╰╶╶ e- (11)
346 │ │ │ ╰── K_S0 (310)
347 │ │ │ ├── pi0 (111)
348 │ │ │ │ ├── gamma (22)
349 │ │ │ │ ╰── gamma (22)
350 │ │ │ ╰── pi0 (111)
351 │ │ │ ├── gamma (22)
352 │ │ │ ╰── gamma (22)
353 │ │ ╰── pi+ (211)
354 │ ├── mu+ (-13)
355 │ │ ├╶╶ anti-nu_mu (-14)
356 │ │ ├╶╶ nu_e (12)
357 │ │ ╰╶╶ e+ (-11)
358 │ ├── nu_mu (14)
359 │ ╰── gamma (22)
363 There's a distinction between primary and secondary particles. Primary
364 particles are the ones created by the physics generator while secondary
365 particles are ones generated by the simulation of the detector interaction.
367 Secondaries are indicated with a dashed line leading to the particle name
368 and if the output is to the terminal they will be printed in red. If
369 ``onlyPrimaries`` is True they will not be included in the tree.
371 On demand, extra information on all the particles can be displayed by
372 enabling any of the ``showProperties``, ``showMomenta``, ``showVertices``
373 and ``showStatus`` flags. Enabling all of them will look like
378 │ mass=0.14 energy=0.445 charge=-1 lifetime=6.36
379 │ p=(0.257, -0.335, 0.0238) |p|=0.423
380 │ production vertex=(0.113, -0.0531, 0.0156), time=0.00589
381 │ status flags=PrimaryParticle, StableInGenerator, StoppedInDetector
385 mass=0.94 energy=0.94 charge=0 lifetime=5.28e+03
386 p=(-0.000238, -0.0127, 0.0116) |p|=0.0172
387 production vertex=(144, 21.9, -1.29), time=39
388 status flags=StoppedInDetector
389 creation process=HadronInelastic
392 The first line of extra information is enabled by ``showProperties``, the
393 second line by ``showMomenta``, the third line by ``showVertices`` and the
394 last two lines by ``showStatus``. Note that all values are given in Belle II
395 standard units, that is GeV, centimeter and nanoseconds.
397 The depth of the tree can be limited with the ``maxLevel`` argument: If it's
398 bigger than zero it will limit the tree to the given number of generations.
399 A visual indicator will be added after each particle which would have
400 additional daughters that are skipped due to this limit. An example event
401 with ``maxLevel=3`` is given below. In this case only the tau neutrino and
402 the pion don't have additional daughters. ::
404 [INFO] Content of MCParticle list
405 ╰── Upsilon(4S) (300553)
407 │ ├── anti-D*0 (-423) → …
408 │ ├── tau+ (-15) → …
409 │ ╰── nu_tau (16)
411 ├── D*0 (423) → …
412 ├── K*- (-323) → …
413 ├── K*+ (323) → …
416 The same information will be stored in the branch ``__MCDecayString__`` of
417 TTree created by `VariablesToNtuple` or `VariablesToEventBasedTree` module.
418 This branch is automatically created when `PrintMCParticles` modules is called.
419 Printing the information on the log message can be suppressed if ``suppressPrint``
420 is True, while the branch ``__MCDecayString__``. This option helps to reduce the
421 size of the log message.
424 onlyPrimaries (bool): If True show only primary particles, that is particles coming from
425 the generator and not created by the simulation.
426 maxLevel (int): If 0 or less print the whole tree, otherwise stop after n generations
427 showProperties (bool): If True show mass, energy and charge of the particles
428 showMomenta (bool): if True show the momenta of the particles
429 showVertices (bool): if True show production vertex and production time of all particles
430 showStatus (bool): if True show some status information on the particles.
431 For secondary particles this includes creation process.
432 suppressPrint (bool): if True printing the information on the log message is suppressed.
433 Even if True, the branch ``__MCDecayString__`` is created.
436 return path.add_module(
438 onlyPrimaries=onlyPrimaries,
440 showProperties=showProperties,
441 showMomenta=showMomenta,
442 showVertices=showVertices,
443 showStatus=showStatus,
444 suppressPrint=suppressPrint,
448 def correctBrems(outputList,
451 maximumAcceptance=3.0,
452 multiplePhotons=False,
453 usePhotonOnlyOnce=True,
457 For each particle in the given ``inputList``, copies it to the ``outputList`` and adds the
458 4-vector of the photon(s) in the ``gammaList`` which has(have) a weighted named relation to
459 the particle's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
462 This can only work if the mdst file contains the *Bremsstrahlung* named relation. Official MC samples
463 up to and including MC12 and proc9 **do not** contain this. Newer production campaigns (from proc10 and MC13) do.
464 However, studies by the tau WG revealed that the cuts applied by the ``ECLTrackBremFinder`` module are too tight.
465 These will be loosened but this will only have effect with proc13 and MC15.
466 If your analysis is very sensitive to the Bremsstrahlung corrections, it is advised to use `correctBremsBelle`.
469 A detailed description of how the weights are set can be found directly at the documentation of the
470 `BremsFinder` module.
472 Please note that a new particle is always generated, with the old particle and -if found- one or more
473 photons as daughters.
475 The ``inputList`` should contain particles with associated tracks. Otherwise, the module will exit with an error.
477 The ``gammaList`` should contain photons. Otherwise, the module will exit with an error.
479 @param outputList The output particle list name containing the corrected particles
480 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
481 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
482 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
483 @param multiplePhotons Whether to use only one photon (the one with the smallest acceptance) or as many as possible
484 @param usePhotonOnlyOnce If true, each brems candidate is used to correct only the track with the smallest relation weight
485 @param writeOut Whether `RootOutput` module should save the created ``outputList``
486 @param path The module is added to this path
489 bremscorrector = register_module(
'BremsFinder')
490 bremscorrector.set_name(
'bremsCorrector_' + outputList)
491 bremscorrector.param(
'inputList', inputList)
492 bremscorrector.param(
'outputList', outputList)
493 bremscorrector.param(
'gammaList', gammaList)
494 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
495 bremscorrector.param(
'multiplePhotons', multiplePhotons)
496 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
497 bremscorrector.param(
'writeOut', writeOut)
498 path.add_module(bremscorrector)
501 def copyList(outputListName, inputListName, writeOut=False, path=None):
503 Copy all Particle indices from input ParticleList to the output ParticleList.
504 Note that the Particles themselves are not copied. The original and copied
505 ParticleLists will point to the same Particles.
507 @param ouputListName copied ParticleList
508 @param inputListName original ParticleList to be copied
509 @param writeOut whether RootOutput module should save the created ParticleList
510 @param path modules are added to this path
513 copyLists(outputListName, [inputListName], writeOut, path)
516 def correctBremsBelle(outputListName,
519 multiplePhotons=True,
524 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
525 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
529 Studies by the tau WG show that using a rather wide opening angle (up to
530 0.2 rad) and rather low energetic photons results in good correction.
531 However, this should only serve as a starting point for your own studies
532 because the optimal criteria are likely mode-dependent
535 outputListName (str): The output charged particle list containing the corrected charged particles
536 inputListName (str): The initial charged particle list containing the charged particles to correct.
537 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
538 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one -> False,
539 add all the photons within the cone -> True
540 angleThreshold (float): The maximum angle in radians between the charged particle and the (radiative)
541 gamma to be accepted.
542 writeOut (bool): whether RootOutput module should save the created ParticleList
543 path (basf2.Path): modules are added to this path
546 fsrcorrector = register_module(
'BelleBremRecovery')
547 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
548 fsrcorrector.param(
'inputListName', inputListName)
549 fsrcorrector.param(
'outputListName', outputListName)
550 fsrcorrector.param(
'gammaListName', gammaListName)
551 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
552 fsrcorrector.param(
'angleThreshold', angleThreshold)
553 fsrcorrector.param(
'writeOut', writeOut)
554 path.add_module(fsrcorrector)
557 def copyLists(outputListName, inputListNames, writeOut=False, path=None):
559 Copy all Particle indices from all input ParticleLists to the
560 single output ParticleList.
561 Note that the Particles themselves are not copied.
562 The original and copied ParticleLists will point to the same Particles.
564 Duplicates are removed based on the first-come, first-served principle.
565 Therefore, the order of the input ParticleLists matters.
568 If you want to select the best duplicate based on another criterion, have
569 a look at the function `mergeListsWithBestDuplicate`.
572 Two particles that differ only by the order of their daughters are
573 considered duplicates and one of them will be removed.
575 @param ouputListName copied ParticleList
576 @param inputListName vector of original ParticleLists to be copied
577 @param writeOut whether RootOutput module should save the created ParticleList
578 @param path modules are added to this path
581 pmanipulate = register_module(
'ParticleListManipulator')
582 pmanipulate.set_name(
'PListCopy_' + outputListName)
583 pmanipulate.param(
'outputListName', outputListName)
584 pmanipulate.param(
'inputListNames', inputListNames)
585 pmanipulate.param(
'writeOut', writeOut)
586 path.add_module(pmanipulate)
589 def copyParticles(outputListName, inputListName, writeOut=False, path=None):
591 Create copies of Particles given in the input ParticleList and add them to the output ParticleList.
593 The existing relations of the original Particle (or it's (grand-)^n-daughters)
594 are copied as well. Note that only the relation is copied and that the related
595 object is not. Copied particles are therefore related to the *same* object as
598 @param ouputListName new ParticleList filled with copied Particles
599 @param inputListName input ParticleList with original Particles
600 @param writeOut whether RootOutput module should save the created ParticleList
601 @param path modules are added to this path
605 pmanipulate = register_module(
'ParticleListManipulator')
606 pmanipulate.set_name(
'PListCopy_' + outputListName)
607 pmanipulate.param(
'outputListName', outputListName)
608 pmanipulate.param(
'inputListNames', [inputListName])
609 pmanipulate.param(
'writeOut', writeOut)
610 path.add_module(pmanipulate)
613 pcopy = register_module(
'ParticleCopier')
614 pcopy.param(
'inputListNames', [outputListName])
615 path.add_module(pcopy)
618 def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
620 Copy candidates from all lists in ``inputListNames`` to
621 ``outputListName`` if they pass ``cut`` (given selection criteria).
624 Note that the Particles themselves are not copied.
625 The original and copied ParticleLists will point to the same Particles.
628 Require energetic pions safely inside the cdc
630 .. code-block:: python
632 cutAndCopyLists("pi+:energeticPions", ["pi+:good", "pi+:loose"], "[E > 2] and thetaInCDCAcceptance", path=mypath)
635 You must use square braces ``[`` and ``]`` for conditional statements.
638 outputListName (str): the new ParticleList name
639 inputListName (list(str)): list of input ParticleList names
640 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
641 writeOut (bool): whether RootOutput module should save the created ParticleList
642 path (basf2.Path): modules are added to this path
644 pmanipulate = register_module(
'ParticleListManipulator')
645 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
646 pmanipulate.param(
'outputListName', outputListName)
647 pmanipulate.param(
'inputListNames', inputListNames)
648 pmanipulate.param(
'cut', cut)
649 pmanipulate.param(
'writeOut', writeOut)
650 path.add_module(pmanipulate)
653 def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
655 Copy candidates from ``inputListName`` to ``outputListName`` if they pass
656 ``cut`` (given selection criteria).
659 Note the Particles themselves are not copied.
660 The original and copied ParticleLists will point to the same Particles.
663 require energetic pions safely inside the cdc
665 .. code-block:: python
667 cutAndCopyList("pi+:energeticPions", "pi+:loose", "[E > 2] and thetaInCDCAcceptance", path=mypath)
670 You must use square braces ``[`` and ``]`` for conditional statements.
673 outputListName (str): the new ParticleList name
674 inputListName (str): input ParticleList name
675 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
676 writeOut (bool): whether RootOutput module should save the created ParticleList
677 path (basf2.Path): modules are added to this path
679 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
682 def removeTracksForTrackingEfficiencyCalculation(inputListNames, fraction, path=None):
684 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
685 Takes care of the duplicates, if any.
688 inputListNames (list(str)): input particle list names
689 fraction (float): fraction of particles to be removed randomly
690 path (basf2.Path): module is added to this path
693 trackingefficiency = register_module(
'TrackingEfficiency')
694 trackingefficiency.param(
'particleLists', inputListNames)
695 trackingefficiency.param(
'frac', fraction)
696 path.add_module(trackingefficiency)
699 def scaleTrackMomenta(inputListNames, scale=float(
'nan'), payloadName=
"", scalingFactorName=
"SF", path=
None):
702 Scale momenta of the particles according to a scaling factor scale.
703 This scaling factor can either be given as constant number or as the name of the payload which contains
704 the variable scale factors.
705 If the particle list contains composite particles, the momenta of the track-based daughters are scaled.
706 Subsequently, the momentum of the mother particle is updated as well.
709 inputListNames (list(str)): input particle list names
710 scale (float): scaling factor (1.0 -- no scaling)
711 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
712 scalingFactorName (str): name of scaling factor variable in the payload.
713 path (basf2.Path): module is added to this path
715 trackingmomentum = register_module(
'TrackingMomentum')
716 trackingmomentum.param(
'particleLists', inputListNames)
717 trackingmomentum.param(
'scale', scale)
718 trackingmomentum.param(
'payloadName', payloadName)
719 trackingmomentum.param(
'scalingFactorName', scalingFactorName)
721 path.add_module(trackingmomentum)
724 def smearTrackMomenta(inputListNames, payloadName="", smearingFactorName="smear", path=None):
726 Smear the momenta of the particles according the values read from the given payload.
727 If the particle list contains composite particles, the momenta of the track-based daughters are smeared.
728 Subsequently, the momentum of the mother particle is updated as well.
731 inputListNames (list(str)): input particle list names
732 payloadName (str): name of the payload which contains the smearing valuess
733 smearingFactorName (str): name of smearing factor variable in the payload.
734 path (basf2.Path): module is added to this path
736 trackingmomentum = register_module(
'TrackingMomentum')
737 trackingmomentum.param(
'particleLists', inputListNames)
738 trackingmomentum.param(
'payloadName', payloadName)
739 trackingmomentum.param(
'smearingFactorName', smearingFactorName)
741 path.add_module(trackingmomentum)
744 def mergeListsWithBestDuplicate(outputListName,
751 Merge input ParticleLists into one output ParticleList. Only the best
752 among duplicates is kept. The lowest or highest value (configurable via
753 preferLowest) of the provided variable determines which duplicate is the
756 @param ouputListName name of merged ParticleList
757 @param inputListName vector of original ParticleLists to be merged
758 @param variable variable to determine best duplicate
759 @param preferLowest whether lowest or highest value of variable should be preferred
760 @param writeOut whether RootOutput module should save the created ParticleList
761 @param path modules are added to this path
764 pmanipulate = register_module(
'ParticleListManipulator')
765 pmanipulate.set_name(
'PListMerger_' + outputListName)
766 pmanipulate.param(
'outputListName', outputListName)
767 pmanipulate.param(
'inputListNames', inputListNames)
768 pmanipulate.param(
'variable', variable)
769 pmanipulate.param(
'preferLowest', preferLowest)
770 pmanipulate.param(
'writeOut', writeOut)
771 path.add_module(pmanipulate)
774 def fillSignalSideParticleList(outputListName, decayString, path):
776 This function should only be used in the ROE path, that is a path
777 that is executed for each ROE object in the DataStore.
779 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
781 Function will create a ParticleList with name 'gamma:sig' which will be filled
782 with the existing photon Particle, being the second daughter of the B0 candidate
783 to which the ROE object has to be related.
785 @param ouputListName name of the created ParticleList
786 @param decayString specify Particle to be added to the ParticleList
789 pload = register_module(
'SignalSideParticleListCreator')
790 pload.set_name(
'SSParticleList_' + outputListName)
791 pload.param(
'particleListName', outputListName)
792 pload.param(
'decayString', decayString)
793 path.add_module(pload)
796 def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False,
797 loadPhotonsFromKLM=False, loadPhotonBeamBackgroundMVA=False, loadPhotonHadronicSplitOffMVA=False):
799 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
800 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
802 The multiple ParticleLists with their own selection criteria are specified
803 via list tuples (decayString, cut), for example
805 .. code-block:: python
807 kaons = ('K+:mykaons', 'kaonID>0.1')
808 pions = ('pi+:mypions','pionID>0.1')
809 fillParticleLists([kaons, pions], path=mypath)
811 If you are unsure what selection you want, you might like to see the
812 :doc:`StandardParticles` functions.
814 The type of the particles to be loaded is specified via the decayString module parameter.
815 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
816 the particle. The following types of the particles can be loaded:
818 * charged final state particles (input ``mdst`` type = Tracks)
819 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
821 * neutral final state particles
822 - "gamma" (input ``mdst`` type = ECLCluster)
823 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
824 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
827 For "K_S0" and "Lambda0" you must specify the daughter ordering.
829 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
831 .. code-block:: python
833 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
834 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
837 Gammas can also be loaded from KLMClusters by explicitly setting the
838 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
839 done in selected use-cases and the effect should be studied carefully.
842 For "K_L0" it is now possible to load from ECLClusters, to revert to
843 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
845 .. code-block:: python
847 klongs = ('K_L0', 'isFromKLM > 0')
848 fillParticleLists([kaons, pions, klongs], path=mypath)
852 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
853 The decay string determines the type of Particle
854 and the name of the ParticleList.
855 If the input MDST type is V0 the whole
856 decay chain needs to be specified, so that
857 the user decides and controls the daughters
858 ' order (e.g. ``K_S0 -> pi+ pi-``)
859 The cut is the selection criteria
860 to be added to the ParticleList. It can be an empty string.
861 writeOut (bool): whether RootOutput module should save the created ParticleList
862 path (basf2.Path): modules are added to this path
863 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
864 using a mass hypothesis of the exact type passed to fillParticleLists().
865 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
866 in terms of mass difference will be used if the fit using exact particle
867 type is not available.
868 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
869 loadPhotonBeamBackgroundMVA (bool): If true, photon candidates will be assigned a beam background probability.
870 loadPhotonHadronicSplitOffMVA (bool): If true, photon candidates will be assigned a hadronic splitoff probability.
873 pload = register_module(
'ParticleLoader')
874 pload.set_name(
'ParticleLoader_' +
'PLists')
875 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
876 pload.param(
'writeOut', writeOut)
877 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
878 path.add_module(pload)
880 from ROOT
import Belle2
882 for decayString, cut
in decayStringsWithCuts:
883 if not decayDescriptor.init(decayString):
884 raise ValueError(
"Invalid decay string")
886 if decayDescriptor.getNDaughters() > 0:
890 if decayDescriptor.getMother().getLabel() !=
'V0':
891 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
892 elif decayDescriptor.getMother().getLabel() !=
'all':
895 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
899 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
901 if decayString.startswith(
"gamma"):
904 if not loadPhotonsFromKLM:
905 applyCuts(decayString,
'isFromECL', path)
909 if loadPhotonBeamBackgroundMVA:
910 getBeamBackgroundProbability(decayString, path)
914 if loadPhotonHadronicSplitOffMVA:
915 getHadronicSplitOffProbability(decayString, path)
918 def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False,
919 loadPhotonsFromKLM=False, loadPhotonBeamBackgroundMVA=False, loadPhotonHadronicSplitOffMVA=False):
921 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
922 loads them to the StoreArray<Particle> and fills the ParticleList.
925 the :doc:`StandardParticles` functions.
927 The type of the particles to be loaded is specified via the decayString module parameter.
928 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
929 the particle. The following types of the particles can be loaded:
931 * charged final state particles (input ``mdst`` type = Tracks)
932 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
934 * neutral final state particles
935 - "gamma" (input ``mdst`` type = ECLCluster)
936 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
937 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
940 For "K_S0" and "Lambda0" you must specify the daughter ordering.
942 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
944 .. code-block:: python
946 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
949 Gammas can also be loaded from KLMClusters by explicitly setting the
950 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
951 done in selected use-cases and the effect should be studied carefully.
954 For "K_L0" it is now possible to load from ECLClusters, to revert to
955 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
957 .. code-block:: python
959 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
962 decayString (str): Type of Particle and determines the name of the ParticleList.
963 If the input MDST type is V0 the whole decay chain needs to be specified, so that
964 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``)
965 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
966 writeOut (bool): whether RootOutput module should save the created ParticleList
967 path (basf2.Path): modules are added to this path
968 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
969 using a mass hypothesis of the exact type passed to fillParticleLists().
970 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
971 in terms of mass difference will be used if the fit using exact particle
972 type is not available.
973 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
974 loadPhotonBeamBackgroundMVA (bool): If true, photon candidates will be assigned a beam background probability.
975 loadPhotonHadronicSplitOffMVA (bool): If true, photon candidates will be assigned a hadronic splitoff probability.
978 pload = register_module(
'ParticleLoader')
979 pload.set_name(
'ParticleLoader_' + decayString)
980 pload.param(
'decayStrings', [decayString])
981 pload.param(
'writeOut', writeOut)
982 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
983 path.add_module(pload)
986 from ROOT
import Belle2
988 if not decayDescriptor.init(decayString):
989 raise ValueError(
"Invalid decay string")
990 if decayDescriptor.getNDaughters() > 0:
994 if decayDescriptor.getMother().getLabel() !=
'V0':
995 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
996 elif decayDescriptor.getMother().getLabel() !=
'all':
999 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1003 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1005 if decayString.startswith(
"gamma"):
1008 if not loadPhotonsFromKLM:
1009 applyCuts(decayString,
'isFromECL', path)
1013 if loadPhotonBeamBackgroundMVA:
1014 getBeamBackgroundProbability(decayString, path)
1018 if loadPhotonHadronicSplitOffMVA:
1019 getHadronicSplitOffProbability(decayString, path)
1022 def fillParticleListWithTrackHypothesis(decayString,
1026 enforceFitHypothesis=False,
1029 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
1031 @param decayString specifies type of Particles and determines the name of the ParticleList
1032 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1033 @param hypothesis the PDG code of the desired track hypothesis
1034 @param writeOut whether RootOutput module should save the created ParticleList
1035 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
1036 using a mass hypothesis of the exact type passed to fillParticleLists().
1037 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
1038 in terms of mass difference will be used if the fit using exact particle
1039 type is not available.
1040 @param path modules are added to this path
1043 pload = register_module(
'ParticleLoader')
1044 pload.set_name(
'ParticleLoader_' + decayString)
1045 pload.param(
'decayStrings', [decayString])
1046 pload.param(
'trackHypothesis', hypothesis)
1047 pload.param(
'writeOut', writeOut)
1048 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1049 path.add_module(pload)
1051 from ROOT
import Belle2
1053 if not decayDescriptor.init(decayString):
1054 raise ValueError(
"Invalid decay string")
1055 if decayDescriptor.getMother().getLabel() !=
'all':
1058 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1062 applyCuts(decayString, cut, path)
1065 def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
1067 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
1070 You must specify the daughter ordering.
1072 .. code-block:: python
1074 fillConvertedPhotonsList('gamma:converted -> e+ e-', '', path=mypath)
1077 decayString (str): Must be gamma to an e+e- pair. You must specify the daughter ordering.
1078 Will also determine the name of the particleList.
1079 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1080 writeOut (bool): whether RootOutput module should save the created ParticleList
1081 path (basf2.Path): modules are added to this path
1084 pload = register_module(
'ParticleLoader')
1085 pload.set_name(
'ParticleLoader_' + decayString)
1086 pload.param(
'decayStrings', [decayString])
1087 pload.param(
'addDaughters',
True)
1088 pload.param(
'writeOut', writeOut)
1089 path.add_module(pload)
1091 from ROOT
import Belle2
1093 if not decayDescriptor.init(decayString):
1094 raise ValueError(
"Invalid decay string")
1095 if decayDescriptor.getMother().getLabel() !=
'V0':
1098 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1102 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1105 def fillParticleListFromROE(decayString,
1108 sourceParticleListName='',
1113 Creates Particle object for each ROE of the desired type found in the
1114 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
1115 and fills the ParticleList. If useMissing is True, then the missing
1116 momentum is used instead of ROE.
1118 The type of the particles to be loaded is specified via the decayString module parameter.
1120 @param decayString specifies type of Particles and determines the name of the ParticleList.
1121 Source ROEs can be taken as a daughter list, for example:
1122 'B0:tagFromROE -> B0:signal'
1123 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1124 @param maskName Name of the ROE mask to use
1125 @param sourceParticleListName Use related ROEs to this particle list as a source
1126 @param useMissing Use missing momentum instead of ROE momentum
1127 @param writeOut whether RootOutput module should save the created ParticleList
1128 @param path modules are added to this path
1131 pload = register_module(
'ParticleLoader')
1132 pload.set_name(
'ParticleLoader_' + decayString)
1133 pload.param(
'decayStrings', [decayString])
1134 pload.param(
'writeOut', writeOut)
1135 pload.param(
'roeMaskName', maskName)
1136 pload.param(
'useMissing', useMissing)
1137 pload.param(
'sourceParticleListName', sourceParticleListName)
1138 pload.param(
'useROEs',
True)
1139 path.add_module(pload)
1141 from ROOT
import Belle2
1143 if not decayDescriptor.init(decayString):
1144 raise ValueError(
"Invalid decay string")
1148 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1151 def fillParticleListFromMC(decayString,
1154 skipNonPrimaryDaughters=False,
1157 skipNonPrimary=False):
1159 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1160 loads them to the StoreArray<Particle> and fills the ParticleList.
1162 The type of the particles to be loaded is specified via the decayString module parameter.
1164 @param decayString specifies type of Particles and determines the name of the ParticleList
1165 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1166 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1167 sets mother-daughter relations
1168 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1169 @param writeOut whether RootOutput module should save the created ParticleList
1170 @param path modules are added to this path
1171 @param skipNonPrimary if true, skip non primary particle
1174 pload = register_module(
'ParticleLoader')
1175 pload.set_name(
'ParticleLoader_' + decayString)
1176 pload.param(
'decayStrings', [decayString])
1177 pload.param(
'addDaughters', addDaughters)
1178 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1179 pload.param(
'writeOut', writeOut)
1180 pload.param(
'useMCParticles',
True)
1181 pload.param(
'skipNonPrimary', skipNonPrimary)
1182 path.add_module(pload)
1184 from ROOT
import Belle2
1186 if not decayDescriptor.init(decayString):
1187 raise ValueError(
"Invalid decay string")
1188 if decayDescriptor.getMother().getLabel() !=
'MC':
1191 copyList(decayString, decayDescriptor.getMother().getName() +
':MC', writeOut, path)
1195 applyCuts(decayString, cut, path)
1198 def fillParticleListsFromMC(decayStringsWithCuts,
1200 skipNonPrimaryDaughters=False,
1203 skipNonPrimary=False):
1205 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1206 loads them to the StoreArray<Particle> and fills the ParticleLists.
1208 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
1211 .. code-block:: python
1213 kaons = ('K+:gen', '')
1214 pions = ('pi+:gen', 'pionID>0.1')
1215 fillParticleListsFromMC([kaons, pions], path=mypath)
1218 Daughters of ``Lambda0`` are not primary, but ``Lambda0`` is not final state particle.
1219 Thus, when one reconstructs a particle from ``Lambda0``, that is created with
1220 ``addDaughters=True`` and ``skipNonPrimaryDaughters=True``, the particle always has ``isSignal==0``.
1221 Please set options for ``Lambda0`` to use MC-matching variables properly as follows,
1222 ``addDaughters=True`` and ``skipNonPrimaryDaughters=False``.
1224 @param decayString specifies type of Particles and determines the name of the ParticleList
1225 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1226 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1227 sets mother-daughter relations
1228 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1229 @param writeOut whether RootOutput module should save the created ParticleList
1230 @param path modules are added to this path
1231 @param skipNonPrimary if true, skip non primary particle
1234 pload = register_module(
'ParticleLoader')
1235 pload.set_name(
'ParticleLoader_' +
'PLists')
1236 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
1237 pload.param(
'addDaughters', addDaughters)
1238 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1239 pload.param(
'writeOut', writeOut)
1240 pload.param(
'useMCParticles',
True)
1241 pload.param(
'skipNonPrimary', skipNonPrimary)
1242 path.add_module(pload)
1244 from ROOT
import Belle2
1246 for decayString, cut
in decayStringsWithCuts:
1247 if not decayDescriptor.init(decayString):
1248 raise ValueError(
"Invalid decay string")
1249 if decayDescriptor.getMother().getLabel() !=
'MC':
1252 copyList(decayString, decayDescriptor.getMother().getName() +
':MC', writeOut, path)
1256 applyCuts(decayString, cut, path)
1259 def applyCuts(list_name, cut, path):
1261 Removes particle candidates from ``list_name`` that do not pass ``cut``
1262 (given selection criteria).
1265 require energetic pions safely inside the cdc
1267 .. code-block:: python
1269 applyCuts("pi+:mypions", "[E > 2] and thetaInCDCAcceptance", path=mypath)
1272 You must use square braces ``[`` and ``]`` for conditional statements.
1275 list_name (str): input ParticleList name
1276 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
1277 path (basf2.Path): modules are added to this path
1280 pselect = register_module(
'ParticleSelector')
1281 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
1282 pselect.param(
'decayString', list_name)
1283 pselect.param(
'cut', cut)
1284 path.add_module(pselect)
1287 def applyEventCuts(cut, path):
1289 Removes events that do not pass the ``cut`` (given selection criteria).
1292 continuum events (in mc only) with more than 5 tracks
1294 .. code-block:: python
1296 applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1299 You must use square braces ``[`` and ``]`` for conditional statements.
1302 cut (str): Events that do not pass these selection criteria are skipped
1303 path (basf2.Path): modules are added to this path
1306 eselect = register_module(
'VariableToReturnValue')
1307 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1308 path.add_module(eselect)
1309 empty_path = create_path()
1310 eselect.if_value(
'<1', empty_path)
1313 def reconstructDecay(decayString,
1318 candidate_limit=None,
1319 ignoreIfTooManyCandidates=True,
1320 chargeConjugation=True,
1321 allowChargeViolation=False):
1323 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1324 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1325 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1326 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1327 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1329 One can use an ``@``-sign to mark a particle as unspecified for inclusive analyses,
1330 e.g. in a DecayString: :code:`'@Xsd -> K+ pi-'`.
1332 .. seealso:: :ref:`Marker_of_unspecified_particle`
1335 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1336 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1337 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1339 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1340 This can be solved by manually randomising the lists before combining.
1344 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1345 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1347 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1348 (from the DecayString the mother and daughter ParticleLists are determined)
1349 @param cut created (mother) Particles are added to the mother ParticleList if they
1350 pass give cuts (in VariableManager style) and rejected otherwise
1351 @param dmID user specified decay mode identifier
1352 @param writeOut whether RootOutput module should save the created ParticleList
1353 @param path modules are added to this path
1354 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1355 the number of candidates is exceeded a Warning will be
1357 By default, all these candidates will be removed and event will be ignored.
1358 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1359 If no value is given the amount is limited to a sensible
1360 default. A value <=0 will disable this limit and can
1361 cause huge memory amounts so be careful.
1362 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1363 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1364 otherwise, number of candidates in candidate_limit is reconstructed.
1365 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1366 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1369 pmake = register_module(
'ParticleCombiner')
1370 pmake.set_name(
'ParticleCombiner_' + decayString)
1371 pmake.param(
'decayString', decayString)
1372 pmake.param(
'cut', cut)
1373 pmake.param(
'decayMode', dmID)
1374 pmake.param(
'writeOut', writeOut)
1375 if candidate_limit
is not None:
1376 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1377 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1378 pmake.param(
'chargeConjugation', chargeConjugation)
1379 pmake.param(
"allowChargeViolation", allowChargeViolation)
1380 path.add_module(pmake)
1383 def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1385 Creates a new Particle as the combination of all Particles from all
1386 provided inputParticleLists. However, each particle is used only once
1387 (even if duplicates are provided) and the combination has to pass the
1388 specified selection criteria to be saved in the newly created (mother)
1391 @param inputParticleLists List of input particle lists which are combined to the new Particle
1392 @param outputList Name of the particle combination created with this module
1393 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1394 these given cuts (in VariableManager style) and is rejected otherwise
1395 @param writeOut whether RootOutput module should save the created ParticleList
1396 @param path module is added to this path
1399 pmake = register_module(
'AllParticleCombiner')
1400 pmake.set_name(
'AllParticleCombiner_' + outputList)
1401 pmake.param(
'inputListNames', inputParticleLists)
1402 pmake.param(
'outputListName', outputList)
1403 pmake.param(
'cut', cut)
1404 pmake.param(
'writeOut', writeOut)
1405 path.add_module(pmake)
1408 def reconstructMissingKlongDecayExpert(decayString,
1415 Creates a list of K_L0's with their momentum determined from kinematic constraints of B->K_L0 + something else.
1417 @param decayString DecayString specifying what kind of the decay should be reconstructed
1418 (from the DecayString the mother and daughter ParticleLists are determined)
1419 @param cut Particles are added to the K_L0 ParticleList if they
1420 pass the given cuts (in VariableManager style) and rejected otherwise
1421 @param dmID user specified decay mode identifier
1422 @param writeOut whether RootOutput module should save the created ParticleList
1423 @param path modules are added to this path
1424 @param recoList suffix appended to original K_L0 ParticleList that identifies the newly created K_L0 list
1427 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1428 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1429 pcalc.param(
'decayString', decayString)
1430 pcalc.param(
'cut', cut)
1431 pcalc.param(
'decayMode', dmID)
1432 pcalc.param(
'writeOut', writeOut)
1433 pcalc.param(
'recoList', recoList)
1434 path.add_module(pcalc)
1436 rmake = register_module(
'KlongDecayReconstructorExpert')
1437 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1438 rmake.param(
'decayString', decayString)
1439 rmake.param(
'cut', cut)
1440 rmake.param(
'decayMode', dmID)
1441 rmake.param(
'writeOut', writeOut)
1442 rmake.param(
'recoList', recoList)
1443 path.add_module(rmake)
1446 def replaceMass(replacerName, particleLists=None, pdgCode=22, path=None):
1448 replaces the mass of the particles inside the given particleLists
1449 with the invariant mass of the particle corresponding to the given pdgCode.
1451 @param particleLists new ParticleList filled with copied Particles
1452 @param pdgCode PDG code for mass reference
1453 @param path modules are added to this path
1455 if particleLists
is None:
1459 pmassupdater = register_module(
'ParticleMassUpdater')
1460 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1461 pmassupdater.param(
'particleLists', particleLists)
1462 pmassupdater.param(
'pdgCode', pdgCode)
1463 path.add_module(pmassupdater)
1466 def reconstructRecoil(decayString,
1471 candidate_limit=None,
1472 allowChargeViolation=False):
1474 Creates new Particles that recoil against the input particles.
1476 For example the decay string M -> D1 D2 D3 will:
1477 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1478 - Particles D1, D2, D3 will be appended as daughters to M
1479 - the 4-momentum of the mother Particle M is given by
1480 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1482 @param decayString DecayString specifying what kind of the decay should be reconstructed
1483 (from the DecayString the mother and daughter ParticleLists are determined)
1484 @param cut created (mother) Particles are added to the mother ParticleList if they
1485 pass give cuts (in VariableManager style) and rejected otherwise
1486 @param dmID user specified decay mode identifier
1487 @param writeOut whether RootOutput module should save the created ParticleList
1488 @param path modules are added to this path
1489 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1490 the number of candidates is exceeded no candidate will be
1491 reconstructed for that event and a Warning will be
1493 If no value is given the amount is limited to a sensible
1494 default. A value <=0 will disable this limit and can
1495 cause huge memory amounts so be careful.
1496 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1499 pmake = register_module(
'ParticleCombiner')
1500 pmake.set_name(
'ParticleCombiner_' + decayString)
1501 pmake.param(
'decayString', decayString)
1502 pmake.param(
'cut', cut)
1503 pmake.param(
'decayMode', dmID)
1504 pmake.param(
'writeOut', writeOut)
1505 pmake.param(
'recoilParticleType', 1)
1506 if candidate_limit
is not None:
1507 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1508 pmake.param(
'allowChargeViolation', allowChargeViolation)
1509 path.add_module(pmake)
1512 def reconstructRecoilDaughter(decayString,
1517 candidate_limit=None,
1518 allowChargeViolation=False):
1520 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1522 For example the decay string M -> D1 D2 D3 will:
1523 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1524 - Particles D1, D2, D3 will be appended as daughters to M
1525 - the 4-momentum of the mother Particle M is given by
1526 p(M) = p(D1) - Sum_i p(Di), where i>1
1528 @param decayString DecayString specifying what kind of the decay should be reconstructed
1529 (from the DecayString the mother and daughter ParticleLists are determined)
1530 @param cut created (mother) Particles are added to the mother ParticleList if they
1531 pass give cuts (in VariableManager style) and rejected otherwise
1532 @param dmID user specified decay mode identifier
1533 @param writeOut whether RootOutput module should save the created ParticleList
1534 @param path modules are added to this path
1535 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1536 the number of candidates is exceeded no candidate will be
1537 reconstructed for that event and a Warning will be
1539 If no value is given the amount is limited to a sensible
1540 default. A value <=0 will disable this limit and can
1541 cause huge memory amounts so be careful.
1542 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1543 daughter is actually the mother
1546 pmake = register_module(
'ParticleCombiner')
1547 pmake.set_name(
'ParticleCombiner_' + decayString)
1548 pmake.param(
'decayString', decayString)
1549 pmake.param(
'cut', cut)
1550 pmake.param(
'decayMode', dmID)
1551 pmake.param(
'writeOut', writeOut)
1552 pmake.param(
'recoilParticleType', 2)
1553 if candidate_limit
is not None:
1554 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1555 pmake.param(
'allowChargeViolation', allowChargeViolation)
1556 path.add_module(pmake)
1559 def rankByHighest(particleList,
1563 allowMultiRank=False,
1567 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1568 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1569 The list is also sorted from best to worst candidate
1570 (each charge, e.g. B+/B-, separately).
1571 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1572 a non-zero value for 'numBest'.
1575 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1576 These variable names can become clunky, so it's probably a good idea to set an alias.
1577 For example if you rank your B candidates by momentum,
1581 rankByHighest("B0:myCandidates", "p", path=mypath)
1582 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1585 @param particleList The input ParticleList
1586 @param variable Variable to order Particles by.
1587 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1588 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1589 @param allowMultiRank If true, candidates with the same value will get the same rank.
1590 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1591 @param path modules are added to this path
1594 bcs = register_module(
'BestCandidateSelection')
1595 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1596 bcs.param(
'particleList', particleList)
1597 bcs.param(
'variable', variable)
1598 bcs.param(
'numBest', numBest)
1599 bcs.param(
'outputVariable', outputVariable)
1600 bcs.param(
'allowMultiRank', allowMultiRank)
1601 bcs.param(
'cut', cut)
1602 path.add_module(bcs)
1605 def rankByLowest(particleList,
1609 allowMultiRank=False,
1613 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1614 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1615 The list is also sorted from best to worst candidate
1616 (each charge, e.g. B+/B-, separately).
1617 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1618 a non-zero value for 'numBest'.
1621 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1622 These variable names can become clunky, so it's probably a good idea to set an alias.
1623 For example if you rank your B candidates by :b2:var:`dM`,
1627 rankByLowest("B0:myCandidates", "dM", path=mypath)
1628 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1631 @param particleList The input ParticleList
1632 @param variable Variable to order Particles by.
1633 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1634 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1635 @param allowMultiRank If true, candidates with the same value will get the same rank.
1636 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1637 @param path modules are added to this path
1640 bcs = register_module(
'BestCandidateSelection')
1641 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1642 bcs.param(
'particleList', particleList)
1643 bcs.param(
'variable', variable)
1644 bcs.param(
'numBest', numBest)
1645 bcs.param(
'selectLowest',
True)
1646 bcs.param(
'allowMultiRank', allowMultiRank)
1647 bcs.param(
'outputVariable', outputVariable)
1648 bcs.param(
'cut', cut)
1649 path.add_module(bcs)
1652 def applyRandomCandidateSelection(particleList, path=None):
1654 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1655 This is done on a event-by-event basis.
1657 @param particleList ParticleList for which the random candidate selection should be applied
1658 @param path module is added to this path
1661 rcs = register_module(
'BestCandidateSelection')
1662 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1663 rcs.param(
'particleList', particleList)
1664 rcs.param(
'variable',
'random')
1665 rcs.param(
'selectLowest',
False)
1666 rcs.param(
'allowMultiRank',
False)
1667 rcs.param(
'numBest', 1)
1668 rcs.param(
'cut',
'')
1669 rcs.param(
'outputVariable',
'')
1670 path.add_module(rcs)
1675 Prints the contents of DataStore in the first event (or a specific event number or all events).
1676 Will list all objects and arrays (including size).
1679 The command line tool: ``b2file-size``.
1682 eventNumber (int): Print the datastore only for this event. The default
1683 (-1) prints only the first event, 0 means print for all events (can produce large output)
1684 path (basf2.Path): the PrintCollections module is added to this path
1687 This will print a lot of output if you print it for all events and process many events.
1691 printDS = register_module(
'PrintCollections')
1692 printDS.param(
'printForEvent', eventNumber)
1693 path.add_module(printDS)
1696 def printVariableValues(list_name, var_names, path):
1698 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
1700 @param list_name input ParticleList name
1701 @param var_names vector of variable names to be printed
1702 @param path modules are added to this path
1705 prlist = register_module(
'ParticlePrinter')
1706 prlist.set_name(
'ParticlePrinter_' + list_name)
1707 prlist.param(
'listName', list_name)
1708 prlist.param(
'fullPrint',
False)
1709 prlist.param(
'variables', var_names)
1710 path.add_module(prlist)
1713 def printList(list_name, full, path):
1715 Prints the size and executes Particle->print() (if full=True)
1716 method for all Particles in given ParticleList. For debugging purposes.
1718 @param list_name input ParticleList name
1719 @param full execute Particle->print() method for all Particles
1720 @param path modules are added to this path
1723 prlist = register_module(
'ParticlePrinter')
1724 prlist.set_name(
'ParticlePrinter_' + list_name)
1725 prlist.param(
'listName', list_name)
1726 prlist.param(
'fullPrint', full)
1727 path.add_module(prlist)
1730 def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None, basketsize=1600):
1732 Creates and fills a flat ntuple with the specified variables from the VariableManager.
1733 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
1734 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
1737 decayString (str): specifies type of Particles and determines the name of the ParticleList
1738 variables (list(str)): the list of variables (which must be registered in the VariableManager)
1739 treename (str): name of the ntuple tree
1740 filename (str): which is used to store the variables
1741 path (basf2.Path): the basf2 path where the analysis is processed
1742 basketsize (int): size of baskets in the output ntuple in bytes
1745 output = register_module(
'VariablesToNtuple')
1746 output.set_name(
'VariablesToNtuple_' + decayString)
1747 output.param(
'particleList', decayString)
1748 output.param(
'variables', variables)
1749 output.param(
'fileName', filename)
1750 output.param(
'treeName', treename)
1751 output.param(
'basketSize', basketsize)
1752 path.add_module(output)
1758 filename='ntuple.root',
1761 prefixDecayString=False):
1763 Creates and fills a flat ntuple with the specified variables from the VariableManager
1766 decayString (str): specifies type of Particles and determines the name of the ParticleList
1767 variables (list(tuple))): variables + binning which must be registered in the VariableManager
1768 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
1769 filename (str): which is used to store the variables
1770 path (basf2.Path): the basf2 path where the analysis is processed
1771 directory (str): directory inside the output file where the histograms should be saved.
1772 Useful if you want to have different histograms in the same file to separate them.
1773 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
1774 programmatic naming of the structure in the file.
1776 if variables_2d
is None:
1778 output = register_module(
'VariablesToHistogram')
1779 output.set_name(
'VariablesToHistogram_' + decayString)
1780 output.param(
'particleList', decayString)
1781 output.param(
'variables', variables)
1782 output.param(
'variables_2d', variables_2d)
1783 output.param(
'fileName', filename)
1784 if directory
is not None or prefixDecayString:
1785 if directory
is None:
1787 if prefixDecayString:
1788 directory = decayString +
"_" + directory
1789 output.param(
"directory", directory)
1790 path.add_module(output)
1795 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
1796 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
1799 particleList (str): The input ParticleList
1800 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
1801 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
1802 An existing extra info with the same name will be overwritten if the new
1803 value is lower / will never be overwritten / will be overwritten if the
1804 new value is higher / will always be overwritten (option = -1/0/1/2).
1805 path (basf2.Path): modules are added to this path
1808 mod = register_module(
'VariablesToExtraInfo')
1809 mod.set_name(
'VariablesToExtraInfo_' + particleList)
1810 mod.param(
'particleList', particleList)
1811 mod.param(
'variables', variables)
1812 mod.param(
'overwrite', option)
1813 path.add_module(mod)
1816 def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
1818 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
1819 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
1820 to specified daughter particle.
1823 particleList (str): The input ParticleList
1824 decayString (str): Decay string that specifies to which daughter the extra info should be appended
1825 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
1826 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
1827 An existing extra info with the same name will be overwritten if the new
1828 value is lower / will never be overwritten / will be overwritten if the
1829 new value is higher / will always be overwritten (option = -1/0/1/2).
1830 path (basf2.Path): modules are added to this path
1833 mod = register_module(
'VariablesToExtraInfo')
1834 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
1835 mod.param(
'particleList', particleList)
1836 mod.param(
'decayString', decayString)
1837 mod.param(
'variables', variables)
1838 mod.param(
'overwrite', option)
1839 path.add_module(mod)
1842 def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
1844 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
1845 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
1848 particleList (str): The input ParticleList
1849 variables (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
1850 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
1851 An existing extra info with the same name will be overwritten if the new
1852 value is lower / will never be overwritten / will be overwritten if the
1853 new value is higher / will always be overwritten (option = -1/0/1/2).
1854 path (basf2.Path): modules are added to this path
1857 mod = register_module(
'VariablesToEventExtraInfo')
1858 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
1859 mod.param(
'particleList', particleList)
1860 mod.param(
'variables', variables)
1861 mod.param(
'overwrite', option)
1862 path.add_module(mod)
1865 def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
1867 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
1868 particle) as an extra info to the particle related to current ROE.
1869 Should be used only in the for_each roe path.
1872 particleList (str): The input ParticleList
1873 varToExtraInfo (dict[str,str]): Dictionary of Variables (key) and extraInfo names (value).
1874 path (basf2.Path): modules are added to this path
1876 mod = register_module(
'SignalSideVariablesToExtraInfo')
1877 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
1878 mod.param(
'particleListName', particleList)
1879 mod.param(
'variableToExtraInfo', varToExtraInfo)
1880 path.add_module(mod)
1883 def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
1885 Define and blind a signal region.
1886 Per default, the defined signal region is cut out if ran on data.
1887 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
1891 .. code-block:: python
1893 ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
1894 ma.signalRegion("B+:sig",
1895 "Mbc>5.27 and abs(deltaE)<0.2",
1898 ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
1901 particleList (str): The input ParticleList
1902 cut (str): Cut string describing the signal region
1903 path (basf2.Path):: Modules are added to this path
1904 name (str): Name of the Signal region in the variable manager
1905 blind_data (bool): Automatically exclude signal region from data
1909 from variables
import variables
1910 mod = register_module(
'VariablesToExtraInfo')
1911 mod.set_name(f
'{name}_' + particleList)
1912 mod.param(
'particleList', particleList)
1913 mod.param(
'variables', {f
"passesCut({cut})": name})
1914 variables.addAlias(name, f
"extraInfo({name})")
1915 path.add_module(mod)
1919 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
1922 def removeExtraInfo(particleLists=None, removeEventExtraInfo=False, path=None):
1924 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
1926 if particleLists
is None:
1928 mod = register_module(
'ExtraInfoRemover')
1929 mod.param(
'particleLists', particleLists)
1930 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
1931 path.add_module(mod)
1934 def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
1936 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
1937 to the particle from the input ParticleList. Additional selection criteria can be applied.
1938 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
1939 meet the selection criteria the execution of deadEndPath is started. This path, as the name
1940 suggests should be empty and its purpose is to end the execution of for_each roe path for
1941 the current ROE object.
1943 @param particleList The input ParticleList
1944 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
1945 @param for_each roe path in which this filter is executed
1946 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
1948 mod = register_module(
'SignalSideParticleFilter')
1949 mod.set_name(
'SigSideParticleFilter_' + particleList)
1950 mod.param(
'particleLists', [particleList])
1951 mod.param(
'selection', selection)
1952 roe_path.add_module(mod)
1953 mod.if_false(deadEndPath)
1956 def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
1958 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
1959 to the particle from the input ParticleList. Additional selection criteria can be applied.
1960 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
1961 meet the selection criteria the execution of deadEndPath is started. This path, as the name
1962 suggests should be empty and its purpose is to end the execution of for_each roe path for
1963 the current ROE object.
1965 @param particleLists The input ParticleLists
1966 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
1967 @param for_each roe path in which this filter is executed
1968 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
1970 mod = register_module(
'SignalSideParticleFilter')
1971 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
1972 mod.param(
'particleLists', particleLists)
1973 mod.param(
'selection', selection)
1974 roe_path.add_module(mod)
1975 mod.if_false(deadEndPath)
1984 chargeConjugation=True,
1987 Finds and creates a ``ParticleList`` from given decay string.
1988 ``ParticleList`` of daughters with sub-decay is created.
1990 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
1991 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
1994 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
1995 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
1996 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
1999 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
2000 (from the DecayString the mother and daughter ParticleLists are determined)
2001 @param cut created (mother) Particles are added to the mother ParticleList if they
2002 pass given cuts (in VariableManager style) and rejected otherwise
2003 isSignal==1 is always required by default.
2004 @param dmID user specified decay mode identifier
2005 @param writeOut whether RootOutput module should save the created ParticleList
2006 @param path modules are added to this path
2007 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
2010 pmake = register_module(
'ParticleCombinerFromMC')
2011 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
2012 pmake.param(
'decayString', decayString)
2013 pmake.param(
'cut', cut)
2014 pmake.param(
'decayMode', dmID)
2015 pmake.param(
'writeOut', writeOut)
2016 pmake.param(
'chargeConjugation', chargeConjugation)
2017 path.add_module(pmake)
2028 This function is not fully tested and maintained.
2029 Please consider to use reconstructMCDecay() instead.
2031 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
2032 The decay string is required to describe correctly what you want.
2033 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
2035 @param list_name The output particle list name
2036 @param decay The decay string which you want
2037 @param writeOut Whether `RootOutput` module should save the created ``outputList``
2038 @param path modules are added to this path
2040 B2WARNING(
"This function is not fully tested and maintained."
2041 "Please consider to use reconstructMCDecay() instead.")
2043 decayfinder = register_module(
'MCDecayFinder')
2044 decayfinder.set_name(
'MCDecayFinder_' + list_name)
2045 decayfinder.param(
'listName', list_name)
2046 decayfinder.param(
'decayString', decay)
2047 decayfinder.param(
'writeOut', writeOut)
2048 path.add_module(decayfinder)
2051 def summaryOfLists(particleLists, outputFile=None, path=None):
2053 Prints out Particle statistics at the end of the job: number of events with at
2054 least one candidate, average number of candidates per event, etc.
2055 If an output file name is provided the statistics is also dumped into a json file with that name.
2057 @param particleLists list of input ParticleLists
2058 @param outputFile output file name (not created by default)
2061 particleStats = register_module(
'ParticleStats')
2062 particleStats.param(
'particleLists', particleLists)
2063 if outputFile
is not None:
2064 particleStats.param(
'outputFile', outputFile)
2065 path.add_module(particleStats)
2068 def matchMCTruth(list_name, path):
2070 Performs MC matching (sets relation Particle->MCParticle) for
2071 all particles (and its (grand)^N-daughter particles) in the specified
2074 @param list_name name of the input ParticleList
2075 @param path modules are added to this path
2078 mcMatch = register_module(
'MCMatcherParticles')
2079 mcMatch.set_name(
'MCMatch_' + list_name)
2080 mcMatch.param(
'listName', list_name)
2081 path.add_module(mcMatch)
2084 def looseMCTruth(list_name, path):
2086 Performs loose MC matching for all particles in the specified
2088 The difference between loose and normal mc matching algorithm is that
2089 the loose algorithm will find the common mother of the majority of daughter
2090 particles while the normal algorithm finds the common mother of all daughters.
2091 The results of loose mc matching algorithm are stored to the following extraInfo
2094 - looseMCMotherPDG: PDG code of most common mother
2095 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
2096 - looseMCWrongDaughterN: number of daughters that don't originate from the most
2098 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from
2099 the most common mother
2100 (only if looseMCWrongDaughterN = 1)
2101 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background
2104 @param list_name name of the input ParticleList
2105 @param path modules are added to this path
2108 mcMatch = register_module(
'MCMatcherParticles')
2109 mcMatch.set_name(
'LooseMCMatch_' + list_name)
2110 mcMatch.param(
'listName', list_name)
2111 mcMatch.param(
'looseMCMatching',
True)
2112 path.add_module(mcMatch)
2115 def buildRestOfEvent(target_list_name, inputParticlelists=None,
2116 fillWithMostLikely=True,
2117 chargedPIDPriors=None, path=None):
2119 Creates for each Particle in the given ParticleList a RestOfEvent
2120 dataobject and makes basf2 relation between them. User can provide additional
2121 particle lists with a different particle hypothesis like ['K+:good, e+:good'], etc.
2123 @param target_list_name name of the input ParticleList
2124 @param inputParticlelists list of user-defined input particle list names, which serve
2125 as source of particles to build the ROE, the FSP particles from
2126 target_list_name are automatically excluded from the ROE object
2127 @param fillWithMostLikely By default the module uses the most likely particle mass hypothesis for charged particles
2128 based on the PID likelihood. Turn this behavior off if you want to configure your own
2129 input particle lists.
2130 @param chargedPIDPriors The prior PID fractions, that are used to regulate the
2131 amount of certain charged particle species, should be a list of
2132 six floats if not None. The order of particle types is
2133 the following: [e-, mu-, pi-, K-, p+, d+]
2134 @param path modules are added to this path
2136 if inputParticlelists
is None:
2137 inputParticlelists = []
2138 fillParticleList(
'pi+:all',
'', path=path)
2139 if fillWithMostLikely:
2140 from stdCharged
import stdMostLikely
2141 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
2142 inputParticlelists = [
'%s:mostlikely_roe' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
2145 fillParticleList(
'gamma:all',
'', path=path)
2146 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
2147 inputParticlelists += [
'pi+:all',
'gamma:all',
'K_L0:roe_default']
2149 inputParticlelists += [
'pi+:all',
'gamma:mdst']
2150 roeBuilder = register_module(
'RestOfEventBuilder')
2151 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
2152 roeBuilder.param(
'particleList', target_list_name)
2153 roeBuilder.param(
'particleListsInput', inputParticlelists)
2154 roeBuilder.param(
'mostLikely', fillWithMostLikely)
2155 path.add_module(roeBuilder)
2158 def buildNestedRestOfEvent(target_list_name, maskName='all', path=None):
2160 Creates for each Particle in the given ParticleList a RestOfEvent
2161 @param target_list_name name of the input ParticleList
2162 @param mask_name name of the ROEMask to be used
2163 @param path modules are added to this path
2165 roeBuilder = register_module(
'RestOfEventBuilder')
2166 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
2167 roeBuilder.param(
'particleList', target_list_name)
2168 roeBuilder.param(
'nestedROEMask', maskName)
2169 roeBuilder.param(
'createNestedROE',
True)
2170 path.add_module(roeBuilder)
2173 def buildRestOfEventFromMC(target_list_name, inputParticlelists=None, path=None):
2175 Creates for each Particle in the given ParticleList a RestOfEvent
2176 @param target_list_name name of the input ParticleList
2177 @param inputParticlelists list of input particle list names, which serve
2178 as a source of particles to build ROE, the FSP particles from
2179 target_list_name are excluded from ROE object
2180 @param path modules are added to this path
2182 if inputParticlelists
is None:
2183 inputParticlelists = []
2184 if (len(inputParticlelists) == 0):
2188 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
2189 'n0',
'nu_e',
'nu_mu',
'nu_tau',
2192 fillParticleListFromMC(
"%s:roe_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
2193 True,
True, path=path)
2194 inputParticlelists += [
"%s:roe_default_gen" % t]
2195 roeBuilder = register_module(
'RestOfEventBuilder')
2196 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
2197 roeBuilder.param(
'particleList', target_list_name)
2198 roeBuilder.param(
'particleListsInput', inputParticlelists)
2199 roeBuilder.param(
'fromMC',
True)
2200 path.add_module(roeBuilder)
2203 def appendROEMask(list_name,
2206 eclClusterSelection,
2207 klmClusterSelection='',
2210 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2211 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
2213 - append a ROE mask with all tracks in ROE coming from the IP region
2215 .. code-block:: python
2217 appendROEMask('B+:sig', 'IPtracks', '[dr < 2] and [abs(dz) < 5]', path=mypath)
2219 - append a ROE mask with only ECL-based particles that pass as good photon candidates
2221 .. code-block:: python
2223 goodPhotons = 'inCDCAcceptance and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
2224 appendROEMask('B+:sig', 'goodROEGamma', '', goodPhotons, path=mypath)
2227 @param list_name name of the input ParticleList
2228 @param mask_name name of the appended ROEMask
2229 @param trackSelection decay string for the track-based particles in ROE
2230 @param eclClusterSelection decay string for the ECL-based particles in ROE
2231 @param klmClusterSelection decay string for the KLM-based particles in ROE
2232 @param path modules are added to this path
2235 roeMask = register_module(
'RestOfEventInterpreter')
2236 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2237 roeMask.param(
'particleList', list_name)
2238 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2239 path.add_module(roeMask)
2242 def appendROEMasks(list_name, mask_tuples, path=None):
2244 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2245 selection criteria for track-, ECL- and KLM-based particles which will be used by ROE variables.
2247 The multiple ROE masks with their own selection criteria are specified
2248 via list of tuples (mask_name, trackParticleSelection, eclParticleSelection, klmParticleSelection) or
2249 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
2251 - Example for two tuples, one with and one without fractions
2253 .. code-block:: python
2255 ipTracks = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', '')
2256 goodPhotons = 'inCDCAcceptance and [clusterErrorTiming < 1e6] and [clusterE1E9 > 0.4 or E > 0.075]'
2257 goodROEGamma = ('ROESel', '[dr < 2] and [abs(dz) < 5]', goodPhotons, '')
2258 goodROEKLM = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', 'nKLMClusterTrackMatches == 0')
2259 appendROEMasks('B+:sig', [ipTracks, goodROEGamma, goodROEKLM], path=mypath)
2261 @param list_name name of the input ParticleList
2262 @param mask_tuples array of ROEMask list tuples to be appended
2263 @param path modules are added to this path
2265 compatible_masks = []
2266 for mask
in mask_tuples:
2269 compatible_masks += [(*mask,
'')]
2271 compatible_masks += [mask]
2272 roeMask = register_module(
'RestOfEventInterpreter')
2273 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2274 roeMask.param(
'particleList', list_name)
2275 roeMask.param(
'ROEMasks', compatible_masks)
2276 path.add_module(roeMask)
2279 def updateROEMask(list_name,
2282 eclClusterSelection='',
2283 klmClusterSelection='',
2286 Update an existing ROE mask by applying additional selection cuts for
2287 tracks and/or clusters.
2289 See function `appendROEMask`!
2291 @param list_name name of the input ParticleList
2292 @param mask_name name of the ROEMask to update
2293 @param trackSelection decay string for the track-based particles in ROE
2294 @param eclClusterSelection decay string for the ECL-based particles in ROE
2295 @param klmClusterSelection decay string for the KLM-based particles in ROE
2296 @param path modules are added to this path
2299 roeMask = register_module(
'RestOfEventInterpreter')
2300 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2301 roeMask.param(
'particleList', list_name)
2302 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2303 roeMask.param(
'update',
True)
2304 path.add_module(roeMask)
2307 def updateROEMasks(list_name, mask_tuples, path):
2309 Update existing ROE masks by applying additional selection cuts for tracks
2312 The multiple ROE masks with their own selection criteria are specified
2313 via list tuples (mask_name, trackSelection, eclClusterSelection, klmClusterSelection)
2315 See function `appendROEMasks`!
2317 @param list_name name of the input ParticleList
2318 @param mask_tuples array of ROEMask list tuples to be appended
2319 @param path modules are added to this path
2321 compatible_masks = []
2322 for mask
in mask_tuples:
2325 compatible_masks += [(*mask,
'')]
2327 compatible_masks += [mask]
2329 roeMask = register_module(
'RestOfEventInterpreter')
2330 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2331 roeMask.param(
'particleList', list_name)
2332 roeMask.param(
'ROEMasks', compatible_masks)
2333 roeMask.param(
'update',
True)
2334 path.add_module(roeMask)
2337 def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2339 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2340 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2341 This function should be executed only in the for_each roe path for the current ROE object.
2343 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2344 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2345 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2346 pion particle list (e.g. 'pi+:someLabel').
2348 Updating a non-existing mask will create a new one.
2350 - keep only those tracks that were used in provided particle list
2352 .. code-block:: python
2354 keepInROEMasks('pi+:goodTracks', 'mask', '', path=mypath)
2356 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2358 .. code-block:: python
2360 keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1', path=mypath)
2363 @param list_name name of the input ParticleList
2364 @param mask_names array of ROEMasks to be updated
2365 @param cut_string decay string with which the mask will be updated
2366 @param path modules are added to this path
2369 updateMask = register_module(
'RestOfEventUpdater')
2370 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2371 updateMask.param(
'particleList', list_name)
2372 updateMask.param(
'updateMasks', mask_names)
2373 updateMask.param(
'cutString', cut_string)
2374 updateMask.param(
'discard',
False)
2375 path.add_module(updateMask)
2378 def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2380 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2381 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2382 This function should be executed only in the for_each roe path for the current ROE object.
2384 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2385 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2386 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2387 pion particle list (e.g. 'pi+:someLabel').
2389 Updating a non-existing mask will create a new one.
2391 - discard tracks that were used in provided particle list
2393 .. code-block:: python
2395 discardFromROEMasks('pi+:badTracks', 'mask', '', path=mypath)
2397 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2399 .. code-block:: python
2401 discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1', path=mypath)
2404 @param list_name name of the input ParticleList
2405 @param mask_names array of ROEMasks to be updated
2406 @param cut_string decay string with which the mask will be updated
2407 @param path modules are added to this path
2410 updateMask = register_module(
'RestOfEventUpdater')
2411 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2412 updateMask.param(
'particleList', list_name)
2413 updateMask.param(
'updateMasks', mask_names)
2414 updateMask.param(
'cutString', cut_string)
2415 updateMask.param(
'discard',
True)
2416 path.add_module(updateMask)
2419 def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2421 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2422 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2423 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2424 passing it can be applied.
2426 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2427 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2429 Updating a non-existing mask will create a new one.
2431 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2433 .. code-block:: python
2435 optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550', path=mypath)
2437 @param list_name name of the input ParticleList
2438 @param mask_names array of ROEMasks to be updated
2439 @param cut_string decay string with which the mask will be updated
2440 @param path modules are added to this path
2443 updateMask = register_module(
'RestOfEventUpdater')
2444 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2445 updateMask.param(
'particleList', list_name)
2446 updateMask.param(
'updateMasks', mask_names)
2447 updateMask.param(
'cutString', cut_string)
2448 path.add_module(updateMask)
2451 def updateROEUsingV0Lists(target_particle_list, mask_names, default_cleanup=True, selection_cuts=None,
2452 apply_mass_fit=False, fitter='treefit', path=None):
2454 This function creates V0 particle lists (photons, :math:`K^0_S` and :math:`\\Lambda^0`)
2455 and it uses V0 candidates to update the Rest Of Event, which is associated to the target particle list.
2456 It is possible to apply a standard or customized selection and mass fit to the V0 candidates.
2459 @param target_particle_list name of the input ParticleList
2460 @param mask_names array of ROE masks to be applied
2461 @param default_cleanup if True, predefined cuts will be applied on the V0 lists
2462 @param selection_cuts a single string of selection cuts or tuple of three strings (photon_cuts, K_S0_cuts, Lambda0_cuts),
2463 which will be applied to the V0 lists. These cuts will have a priority over the default ones.
2464 @param apply_mass_fit if True, a mass fit will be applied to the V0 particles
2465 @param fitter string, that represent a fitter choice: "treefit" for TreeFitter and "kfit" for KFit
2466 @param path modules are added to this path
2468 roe_path = create_path()
2469 deadEndPath = create_path()
2470 signalSideParticleFilter(target_particle_list,
'', roe_path, deadEndPath)
2472 if (default_cleanup
and selection_cuts
is None):
2473 B2INFO(
"Using default cleanup in updateROEUsingV0Lists.")
2474 selection_cuts =
'abs(dM) < 0.1 '
2475 selection_cuts +=
'and daughter(0,particleID) > 0.2 and daughter(1,particleID) > 0.2 '
2476 selection_cuts +=
'and daughter(0,thetaInCDCAcceptance) and daughter(1,thetaInCDCAcceptance)'
2477 if (selection_cuts
is None or selection_cuts ==
''):
2478 B2INFO(
"No cleanup in updateROEUsingV0Lists.")
2479 selection_cuts = (
'True',
'True',
'True')
2480 if (isinstance(selection_cuts, str)):
2481 selection_cuts = (selection_cuts, selection_cuts, selection_cuts)
2483 roe_cuts =
'isInRestOfEvent > 0'
2484 fillConvertedPhotonsList(
'gamma:v0_roe -> e+ e-', f
'{selection_cuts[0]} and {roe_cuts}',
2486 fillParticleList(
'K_S0:v0_roe -> pi+ pi-', f
'{selection_cuts[1]} and {roe_cuts}',
2488 fillParticleList(
'Lambda0:v0_roe -> p+ pi-', f
'{selection_cuts[2]} and {roe_cuts}',
2490 fitter = fitter.lower()
2491 if (fitter !=
'treefit' and fitter !=
'kfit'):
2492 B2WARNING(
'Argument "fitter" in updateROEUsingV0Lists has only "treefit" and "kfit" options, '
2493 f
'but "{fitter}" was provided! TreeFitter will be used instead.')
2495 from vertex
import kFit, treeFit
2496 for v0
in [
'gamma:v0_roe',
'K_S0:v0_roe',
'Lambda0:v0_roe']:
2497 if (apply_mass_fit
and fitter ==
'kfit'):
2498 kFit(v0, conf_level=0.0, fit_type=
'massvertex', path=roe_path)
2499 if (apply_mass_fit
and fitter ==
'treefit'):
2500 treeFit(v0, conf_level=0.0, massConstraint=[v0.split(
':')[0]], path=roe_path)
2501 optimizeROEWithV0(v0, mask_names,
'', path=roe_path)
2502 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2505 def printROEInfo(mask_names=None, full_print=False,
2506 unpackComposites=True, path=None):
2508 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2509 It prints out basic ROE object info.
2511 If mask names are provided, specific information for those masks will be printed out.
2513 It is also possible to print out all particles in a given mask if the
2514 'full_print' is set to True.
2516 @param mask_names array of ROEMask names for printing out info
2517 @param unpackComposites if true, replace composite particles by their daughters
2518 @param full_print print out particles in mask
2519 @param path modules are added to this path
2521 if mask_names
is None:
2523 printMask = register_module(
'RestOfEventPrinter')
2524 printMask.set_name(
'RestOfEventPrinter')
2525 printMask.param(
'maskNames', mask_names)
2526 printMask.param(
'fullPrint', full_print)
2527 printMask.param(
'unpackComposites', unpackComposites)
2528 path.add_module(printMask)
2531 def buildContinuumSuppression(list_name, roe_mask, path):
2533 Creates for each Particle in the given ParticleList a ContinuumSuppression
2534 dataobject and makes basf2 relation between them.
2536 :param list_name: name of the input ParticleList
2537 :param roe_mask: name of the ROE mask
2538 :param path: modules are added to this path
2541 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2542 qqBuilder.set_name(
'QQBuilder_' + list_name)
2543 qqBuilder.param(
'particleList', list_name)
2544 qqBuilder.param(
'ROEMask', roe_mask)
2545 path.add_module(qqBuilder)
2550 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2551 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2553 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2554 @param path modules are added to this path
2557 mod = register_module(
'RemoveParticlesNotInLists')
2558 mod.param(
'particleLists', lists_to_keep)
2559 path.add_module(mod)
2562 def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2564 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2566 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2567 @param bsig_list_name Name of the Bsig ParticleList
2568 @param btag_list_name Name of the Bsig ParticleList
2569 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2571 btag = register_module(
'InclusiveBtagReconstruction')
2572 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2573 btag.param(
'upsilonListName', upsilon_list_name)
2574 btag.param(
'bsigListName', bsig_list_name)
2575 btag.param(
'btagListName', btag_list_name)
2576 btag.param(
'inputListsNames', input_lists_names)
2577 path.add_module(btag)
2580 def selectDaughters(particle_list_name, decay_string, path):
2582 Redefine the Daughters of a particle: select from decayString
2584 @param particle_list_name input particle list
2585 @param decay_string for selecting the Daughters to be preserved
2587 seld = register_module(
'SelectDaughters')
2588 seld.set_name(
'SelectDaughters_' + particle_list_name)
2589 seld.param(
'listName', particle_list_name)
2590 seld.param(
'decayString', decay_string)
2591 path.add_module(seld)
2594 def markDuplicate(particleList, prioritiseV0, path):
2596 Call DuplicateVertexMarker to find duplicate particles in a list and
2597 flag the ones that should be kept
2599 @param particleList input particle list
2600 @param prioritiseV0 if true, give V0s a higher priority
2602 markdup = register_module(
'DuplicateVertexMarker')
2603 markdup.param(
'particleList', particleList)
2604 markdup.param(
'prioritiseV0', prioritiseV0)
2605 path.add_module(markdup)
2608 PI0ETAVETO_COUNTER = 0
2611 def oldwritePi0EtaVeto(
2614 workingDirectory='.',
2615 pi0vetoname='Pi0_Prob',
2616 etavetoname='Eta_Prob',
2622 Give pi0/eta probability for hard photon.
2624 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.
2626 The current default weight files are optimised using MC9.
2627 The input variables are as below. Aliases are set to some variables during training.
2629 * M: pi0/eta candidates Invariant mass
2630 * lowE: soft photon energy in lab frame
2631 * cTheta: soft photon ECL cluster's polar angle
2632 * Zmva: soft photon output of MVA using Zernike moments of the cluster
2633 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2635 If you don't have weight files in your workingDirectory,
2636 these files are downloaded from database to your workingDirectory automatically.
2637 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
2638 about how to use this function.
2641 Please don't use following ParticleList names elsewhere:
2643 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
2644 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
2646 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
2648 @param particleList The input ParticleList
2649 @param decayString specify Particle to be added to the ParticleList
2650 @param workingDirectory The weight file directory
2651 @param downloadFlag whether download default weight files or not
2652 @param pi0vetoname extraInfo name of pi0 probability
2653 @param etavetoname extraInfo name of eta probability
2654 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2655 @param path modules are added to this path
2661 global PI0ETAVETO_COUNTER
2663 if PI0ETAVETO_COUNTER == 0:
2664 from variables
import variables
2665 variables.addAlias(
'lowE',
'daughter(1,E)')
2666 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
2667 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
2668 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
2669 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
2670 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
2672 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
2674 roe_path = create_path()
2676 deadEndPath = create_path()
2678 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
2680 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
2682 pi0softname =
'gamma:PI0SOFT'
2683 etasoftname =
'gamma:ETASOFT'
2684 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
2685 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
2689 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
2691 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
2694 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
2696 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
2698 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
2699 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
2701 if not os.path.isdir(workingDirectory):
2702 os.mkdir(workingDirectory)
2703 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
2705 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
2707 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
2708 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
2710 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
2712 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
2713 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
2715 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
2716 identifier=workingDirectory +
'/pi0veto.root')
2717 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
2718 identifier=workingDirectory +
'/etaveto.root')
2720 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
2721 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
2723 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
2724 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
2726 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2729 def writePi0EtaVeto(
2736 hardParticle='gamma',
2737 pi0PayloadNameOverride=None,
2738 pi0SoftPhotonCutOverride=None,
2739 etaPayloadNameOverride=None,
2740 etaSoftPhotonCutOverride=None
2743 Give pi0/eta probability for hard photon.
2745 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.
2747 The current default weight files are optimised using MC12.
2749 The input variables of the mva training are:
2751 * M: pi0/eta candidates Invariant mass
2752 * daughter(1,E): soft photon energy in lab frame
2753 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
2754 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2755 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
2756 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
2757 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
2758 * cosHelicityAngleMomentum: pi0/eta candidates cosHelicityAngleMomentum
2760 The following strings are available for mode:
2762 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
2763 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
2764 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
2765 * both: tight energy cut and clusterNHits cut are applied to soft photon
2767 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
2768 `pi0Prob`/`etaProb`. Otherwise, it is available as '{Pi0, Eta}ProbOrigin', '{Pi0, Eta}ProbTightEnergyThreshold', '{Pi0,
2769 Eta}ProbLargeClusterSize', or '{Pi0, Eta}ProbTightEnergyThresholdAndLargeClusterSize'} for the four modes described above, with
2770 the chosen suffix appended.
2773 Please don't use following ParticleList names elsewhere:
2775 ``gamma:HardPhoton``,
2776 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
2777 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
2778 ``pi0:EtaVeto + ListName``,
2779 ``eta:EtaVeto + ListName``
2781 @param particleList the input ParticleList
2782 @param decayString specify Particle to be added to the ParticleList
2783 @param mode choose one mode out of 'standard', 'tight', 'cluster' and 'both'
2784 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
2785 @param path modules are added to this path
2786 @param suffix optional suffix to be appended to the usual extraInfo name
2787 @param hardParticle particle name which is used to calculate the pi0/eta probability (default is gamma)
2788 @param pi0PayloadNameOverride specify the payload name of pi0 veto only if one wants to use non-default one. (default is None)
2789 @param pi0SoftPhotonCutOverride specify the soft photon selection criteria of pi0 veto only if one wants to use non-default one.
2791 @param etaPayloadNameOverride specify the payload name of eta veto only if one wants to use non-default one. (default is None)
2792 @param etaSoftPhotonCutOverride specify the soft photon selection criteria of eta veto only if one wants to use non-default one.
2796 renameSuffix =
False
2798 for module
in path.modules():
2799 if module.type() ==
"SubEvent" and not renameSuffix:
2800 for subpath
in [p.values
for p
in module.available_params()
if p.name ==
"path"]:
2803 for submodule
in subpath.modules():
2804 if f
'{hardParticle}:HardPhoton{suffix}' in submodule.name():
2806 B2WARNING(
"Same extension already used in writePi0EtaVeto, append '_0'")
2810 roe_path = create_path()
2811 deadEndPath = create_path()
2812 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
2813 fillSignalSideParticleList(f
'{hardParticle}:HardPhoton{suffix}', decayString, path=roe_path)
2815 dictListName = {
'standard':
'Origin',
2816 'tight':
'TightEnergyThreshold',
2817 'cluster':
'LargeClusterSize',
2818 'both':
'TightEnrgyThresholdAndLargeClusterSize'}
2820 dictPi0EnergyCut = {
'standard':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
2821 'tight':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
2822 'cluster':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
2823 'both':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
2825 dictEtaEnergyCut = {
'standard':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
2826 'tight':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
2827 'cluster':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
2828 'both':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]'}
2830 dictNHitsCut = {
'standard':
'clusterNHits >= 0',
2831 'tight':
'clusterNHits >= 0',
2832 'cluster':
'clusterNHits >= 2',
2833 'both':
'clusterNHits >= 2'}
2835 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
2836 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
2837 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
2838 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
2840 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
2841 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
2842 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
2843 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
2845 dictPi0ExtraInfoName = {
'standard':
'Pi0ProbOrigin',
2846 'tight':
'Pi0ProbTightEnergyThreshold',
2847 'cluster':
'Pi0ProbLargeClusterSize',
2848 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize'}
2850 dictEtaExtraInfoName = {
'standard':
'EtaProbOrigin',
2851 'tight':
'EtaProbTightEnergyThreshold',
2852 'cluster':
'EtaProbLargeClusterSize',
2853 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize'}
2855 ListName = dictListName[mode]
2856 Pi0EnergyCut = dictPi0EnergyCut[mode]
2857 EtaEnergyCut = dictEtaEnergyCut[mode]
2858 TimingCut =
'abs(clusterTiming)<clusterErrorTiming'
2859 NHitsCut = dictNHitsCut[mode]
2860 Pi0PayloadName = dictPi0PayloadName[mode]
2861 EtaPayloadName = dictEtaPayloadName[mode]
2862 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
2863 EtaExtraInfoName = dictEtaExtraInfoName[mode]
2868 if pi0PayloadNameOverride
is not None:
2869 Pi0PayloadName = pi0PayloadNameOverride
2870 if pi0SoftPhotonCutOverride
is None:
2871 Pi0SoftPhotonCut = Pi0EnergyCut +
' and ' + NHitsCut
2875 Pi0SoftPhotonCut +=
' and ' + TimingCut
2877 Pi0SoftPhotonCut = pi0SoftPhotonCutOverride
2880 pi0soft = f
'gamma:Pi0Soft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
2882 fillParticleList(pi0soft, Pi0SoftPhotonCut, path=roe_path)
2884 reconstructDecay(
'pi0:Pi0Veto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + pi0soft,
'',
2885 allowChargeViolation=
True, path=roe_path)
2887 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName],
2888 extraInfoName=Pi0ExtraInfoName, identifier=Pi0PayloadName)
2890 rankByHighest(
'pi0:Pi0Veto' + ListName,
'extraInfo(' + Pi0ExtraInfoName +
')', numBest=1, path=roe_path)
2892 variableToSignalSideExtraInfo(
'pi0:Pi0Veto' + ListName,
2893 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoName + suffix}, path=roe_path)
2898 if etaPayloadNameOverride
is not None:
2899 EtaPayloadName = etaPayloadNameOverride
2900 if etaSoftPhotonCutOverride
is None:
2901 EtaSoftPhotonCut = EtaEnergyCut +
' and ' + NHitsCut
2905 EtaSoftPhotonCut +=
' and ' + TimingCut
2907 EtaSoftPhotonCut = etaSoftPhotonCutOverride
2909 etasoft = f
'gamma:EtaSoft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
2910 fillParticleList(etasoft, EtaSoftPhotonCut, path=roe_path)
2911 reconstructDecay(
'eta:EtaVeto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + etasoft,
'',
2912 allowChargeViolation=
True, path=roe_path)
2913 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName],
2914 extraInfoName=EtaExtraInfoName, identifier=EtaPayloadName)
2915 rankByHighest(
'eta:EtaVeto' + ListName,
'extraInfo(' + EtaExtraInfoName +
')', numBest=1, path=roe_path)
2916 variableToSignalSideExtraInfo(
'eta:EtaVeto' + ListName,
2917 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoName + suffix}, path=roe_path)
2919 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2922 def getBeamBackgroundProbability(particleList, path=None):
2924 Assign a probability to each ECL cluster as being signal like (1) compared to beam background like (0)
2925 @param particleList The input ParticleList, must be a photon list
2926 @param path modules are added to this path
2928 basf2.conditions.prepend_globaltag(getAnalysisGlobaltag())
2929 path.add_module(
'MVAExpert',
2930 listNames=particleList,
2931 extraInfoName=
'beamBackgroundSuppression',
2932 identifier=
'BeamBackgroundMVA')
2935 def getHadronicSplitOffProbability(particleList, path=None,):
2937 Assign a probability to each ECL cluster as being signal like (1) compared to hadronic splitoff like (0)
2938 @param particleList The input ParticleList, must be a photon list
2939 @param path modules are added to this path
2941 basf2.conditions.prepend_globaltag(getAnalysisGlobaltag())
2942 path.add_module(
'MVAExpert',
2943 listNames=particleList,
2944 extraInfoName=
'hadronicSplitOffSuppression',
2945 identifier=
'HadronicSplitOffMVA')
2948 def buildEventKinematics(inputListNames=None, default_cleanup=True, custom_cuts=None,
2949 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
2951 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
2952 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
2953 (all track and all hits in ECL without associated track).
2955 The visible energy missing values are
2956 stored in a EventKinematics dataobject.
2958 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
2959 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
2960 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
2961 according to the PID likelihood and the option inputListNames will be ignored.
2962 @param chargedPIDPriors The prior PID fractions, that are used to regulate
2963 amount of certain charged particle species, should be a list of
2964 six floats if not None. The order of particle types is
2965 the following: [e-, mu-, pi-, K-, p+, d+]
2966 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
2967 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
2968 which would result in a standard predefined selection cuts
2969 @param path modules are added to this path
2971 if inputListNames
is None:
2973 trackCuts =
'pt > 0.1'
2974 trackCuts +=
' and thetaInCDCAcceptance'
2975 trackCuts +=
' and abs(dz) < 3'
2976 trackCuts +=
' and dr < 0.5'
2978 gammaCuts =
'E > 0.05'
2979 gammaCuts +=
' and thetaInCDCAcceptance'
2980 gammaCuts +=
' and abs(clusterTiming) < 200'
2981 if (custom_cuts
is not None):
2982 trackCuts, gammaCuts = custom_cuts
2984 if fillWithMostLikely:
2985 from stdCharged
import stdMostLikely
2986 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
2987 inputListNames = [
'%s:mostlikely_evtkin' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
2988 fillParticleList(
'gamma:evtkin',
'', loadPhotonBeamBackgroundMVA=
False, loadPhotonHadronicSplitOffMVA=
False, path=path)
2989 inputListNames += [
'gamma:evtkin']
2991 B2INFO(
"Using default cleanup in EventKinematics module.")
2992 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
2993 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
2994 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
2996 B2INFO(
"No cleanup in EventKinematics module.")
2997 if not inputListNames:
2998 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
2999 fillParticleList(
'pi+:evtkin',
'', path=path)
3000 fillParticleList(
'gamma:evtkin',
'', loadPhotonBeamBackgroundMVA=
False, loadPhotonHadronicSplitOffMVA=
False, path=path)
3001 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
3003 if (custom_cuts
is not None):
3004 B2INFO(
"Using default cleanup in EventKinematics module.")
3005 applyCuts(
'pi+:evtkin', trackCuts, path=path)
3006 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3008 B2INFO(
"No cleanup in EventKinematics module.")
3010 particleLists = inputListNames
3012 eventKinematicsModule = register_module(
'EventKinematics')
3013 eventKinematicsModule.set_name(
'EventKinematics_reco')
3014 eventKinematicsModule.param(
'particleLists', particleLists)
3015 path.add_module(eventKinematicsModule)
3018 def buildEventKinematicsFromMC(inputListNames=None, selectionCut='', path=None):
3020 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3021 using generated particles. If no ParticleList is provided, default generated ParticleLists are used.
3023 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
3024 If the list is empty, default ParticleLists are filled.
3025 @param selectionCut optional selection cuts
3026 @param path Path to append the eventKinematics module to.
3028 if inputListNames
is None:
3030 if (len(inputListNames) == 0):
3034 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
3037 fillParticleListFromMC(
"%s:evtkin_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
3038 True,
True, path=path)
3039 if (selectionCut !=
''):
3040 applyCuts(
"%s:evtkin_default_gen" % t, selectionCut, path=path)
3041 inputListNames += [
"%s:evtkin_default_gen" % t]
3043 eventKinematicsModule = register_module(
'EventKinematics')
3044 eventKinematicsModule.set_name(
'EventKinematics_gen')
3045 eventKinematicsModule.param(
'particleLists', inputListNames)
3046 eventKinematicsModule.param(
'usingMC',
True)
3047 path.add_module(eventKinematicsModule)
3050 def buildEventShape(inputListNames=None,
3051 default_cleanup=True,
3057 harmonicMoments=True,
3061 checkForDuplicates=False,
3064 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
3065 using the particles in the lists provided by the user. If no particle list is provided,
3066 the function will internally create a list of good tracks and a list of good photons
3067 with (optionally) minimal quality cuts.
3070 The results of the calculation are then stored into the EventShapeContainer dataobject,
3071 and are accessible using the variables of the EventShape group.
3073 The user can switch the calculation of certain quantities on or off to save computing
3074 time. By default the calculation of the high-order moments (5-8) is turned off.
3075 Switching off an option will make the corresponding variables not available.
3078 The user can provide as many particle lists
3079 as needed, using also combined particles, but the function will always assume that
3080 the lists are independent.
3081 If the lists provided by the user contain several times the same track (either with
3082 different mass hypothesis, or once as an independent particle and once as daughter of a
3083 combined particle) the results won't be reliable.
3084 A basic check for duplicates is available setting the checkForDuplicate flags,
3085 but is usually quite time consuming.
3088 @param inputListNames List of ParticleLists used to calculate the
3089 event shape variables. If the list is empty the default
3090 particleLists pi+:evtshape and gamma:evtshape are filled.
3091 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
3092 defining the internal lists. This option is ignored if the
3093 particleLists are provided by the user.
3094 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3095 which would result in a standard predefined selection cuts
3096 @param path Path to append the eventShape modules to.
3097 @param thrust Enables the calculation of thrust-related quantities (CLEO
3098 cones, Harmonic moments, jets).
3099 @param collisionAxis Enables the calculation of the quantities related to the
3101 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
3102 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
3103 to both the thrust axis and, if collisionAxis = True, the collision axis.
3104 @param allMoments If True, calculates also the FW and harmonic moments from order
3105 5 to 8 instead of the low-order ones only.
3106 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
3107 axis and, if collisionAxis = True, the collision axis.
3108 @param jets Enables the calculation of the hemisphere momenta and masses.
3109 Requires thrust = True.
3110 @param sphericity Enables the calculation of the sphericity-related quantities.
3111 @param checkForDuplicates Perform a check for duplicate particles before adding them. This option
3112 is quite time consuming, instead of using it consider sanitizing
3113 the lists you are passing to the function.
3115 if inputListNames
is None:
3117 trackCuts =
'pt > 0.1'
3118 trackCuts +=
' and thetaInCDCAcceptance'
3119 trackCuts +=
' and abs(dz) < 3.0'
3120 trackCuts +=
' and dr < 0.5'
3122 gammaCuts =
'E > 0.05'
3123 gammaCuts +=
' and thetaInCDCAcceptance'
3124 gammaCuts +=
' and abs(clusterTiming) < 200'
3125 if (custom_cuts
is not None):
3126 trackCuts, gammaCuts = custom_cuts
3128 if not inputListNames:
3129 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
3130 fillParticleList(
'pi+:evtshape',
'', path=path)
3131 fillParticleList(
'gamma:evtshape',
'', loadPhotonBeamBackgroundMVA=
False, loadPhotonHadronicSplitOffMVA=
False, path=path)
3132 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
3135 if (custom_cuts
is not None):
3136 B2INFO(
"Applying standard cuts")
3137 applyCuts(
'pi+:evtshape', trackCuts, path=path)
3139 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
3141 B2WARNING(
"Creating the default lists with no cleanup.")
3143 particleLists = inputListNames
3145 eventShapeModule = register_module(
'EventShapeCalculator')
3146 eventShapeModule.set_name(
'EventShape')
3147 eventShapeModule.param(
'particleListNames', particleLists)
3148 eventShapeModule.param(
'enableAllMoments', allMoments)
3149 eventShapeModule.param(
'enableCleoCones', cleoCones)
3150 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
3151 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
3152 eventShapeModule.param(
'enableJets', jets)
3153 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
3154 eventShapeModule.param(
'enableSphericity', sphericity)
3155 eventShapeModule.param(
'enableThrust', thrust)
3156 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
3158 path.add_module(eventShapeModule)
3161 def labelTauPairMC(printDecayInfo=False, path=None, TauolaBelle=False, mapping_minus=None, mapping_plus=None):
3163 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
3164 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
3166 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
3167 @param path: module is added to this path
3168 @param TauolaBelle: if False, TauDecayMarker is set. If True, TauDecayMode is set.
3169 @param mapping_minus: if None, the map is the default one, else the path for the map is given by the user for tau-
3170 @param mapping_plus: if None, the map is the default one, else the path for the map is given by the user for tau+
3172 from basf2
import find_file
3178 m_printmode =
'default'
3180 if mapping_minus
is None:
3181 mp_file_minus = find_file(
'data/analysis/modules/TauDecayMode/map_tauminus.txt')
3183 mp_file_minus = mapping_minus
3185 if mapping_plus
is None:
3186 mp_file_plus = find_file(
'data/analysis/modules/TauDecayMode/map_tauplus.txt')
3188 mp_file_plus = mapping_plus
3190 path.add_module(
'TauDecayMode', printmode=m_printmode, file_minus=mp_file_minus, file_plus=mp_file_plus)
3193 tauDecayMarker = register_module(
'TauDecayMarker')
3194 tauDecayMarker.set_name(
'TauDecayMarker_')
3196 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
3199 def tagCurlTracks(particleLists,
3209 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
3211 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
3212 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
3214 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
3217 The module loops over all particles in a given list that meet the preselection **ptCut** and assigns them to
3218 bundles based on the response of the chosen **selector** and the required minimum response set by the
3219 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
3220 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
3224 @param particleLists: list of particle lists to check for curls.
3225 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
3226 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
3227 genParticleIndex then ranked and tagged as normal.
3228 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
3229 If set to ``-1`` a cut value optimised to maximise the accuracy on a BBbar sample is used.
3230 Note 'cut' selector is binary 0/1.
3231 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
3232 It is strongly recommended to used the 'mva' selection. The 'cut' selection
3233 is based on BN1079 and is only calibrated for Belle data.
3234 @param ptCut: pre-selection cut on transverse momentum.
3235 @param expert_train: flag to set training mode if selector has a training mode (mva).
3236 @param expert_filename: set file name of produced training ntuple (mva).
3237 @param path: module is added to this path.
3243 if (
not isinstance(particleLists, list)):
3244 particleLists = [particleLists]
3246 curlTagger = register_module(
'CurlTagger')
3247 curlTagger.set_name(
'CurlTagger_')
3248 curlTagger.param(
'particleLists', particleLists)
3249 curlTagger.param(
'belle', belle)
3250 curlTagger.param(
'mcTruth', mcTruth)
3251 curlTagger.param(
'responseCut', responseCut)
3252 if abs(responseCut + 1) < 1e-9:
3253 curlTagger.param(
'usePayloadCut',
True)
3255 curlTagger.param(
'usePayloadCut',
False)
3257 curlTagger.param(
'selectorType', selectorType)
3258 curlTagger.param(
'ptCut', ptCut)
3259 curlTagger.param(
'train', expert_train)
3260 curlTagger.param(
'trainFilename', expert_filename)
3262 path.add_module(curlTagger)
3265 def applyChargedPidMVA(particleLists, path, trainingMode, chargeIndependent=False, binaryHypoPDGCodes=(0, 0)):
3267 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
3269 The module decorates Particle objects in the input ParticleList(s) with variables
3270 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
3273 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.3.0**, **ROOT 6.20/04**).
3275 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
3277 - e (11) vs. pi (211)
3278 - mu (13) vs. pi (211)
3279 - pi (211) vs. K (321)
3280 - K (321) vs. pi (211)
3282 , or 'global' PID, namely "one-vs-others" separation. The latter exploits an MVA algorithm trained in multi-class mode,
3283 and it's the default behaviour. Currently, the multi-class training separates the following standard charged hypotheses:
3285 - e (11), mu (13), pi (211), K (321)
3288 In order to run the `ChargedPidMVA` and ensure the most up-to-date MVA training weights are applied,
3289 it is necessary to append the latest analysis global tag (GT) to the steering script.
3292 particleLists (list(str)): list of names of ParticleList objects for charged stable particles.
3293 The charge-conjugate ParticleLists will be also processed automatically.
3294 path (basf2.Path): the module is added to this path.
3295 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
3296 Needed to pick up the correct payload from the DB. Available choices:
3298 * c_Classification=0
3300 * c_ECL_Classification=2
3301 * c_ECL_Multiclass=3
3302 * c_PSD_Classification=4
3303 * c_PSD_Multiclass=5
3304 * c_ECL_PSD_Classification=6
3305 * c_ECL_PSD_Multiclass=7
3307 chargeIndependent (bool, ``optional``): use a BDT trained on a sample of inclusively charged particles.
3308 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
3309 Required only for binary PID mode.
3312 from ROOT
import Belle2
3313 from variables
import variables
as vm
3315 TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
3318 plSet = set(particleLists)
3322 TrainingMode.c_Classification:
3323 {
"mode":
"Classification",
"detector":
"ALL"},
3324 TrainingMode.c_Multiclass:
3325 {
"mode":
"Multiclass",
"detector":
"ALL"},
3326 TrainingMode.c_ECL_Classification:
3327 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
3328 TrainingMode.c_ECL_Multiclass:
3329 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
3330 TrainingMode.c_PSD_Classification:
3331 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
3332 TrainingMode.c_PSD_Multiclass:
3333 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
3334 TrainingMode.c_ECL_PSD_Classification:
3335 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
3336 TrainingMode.c_ECL_PSD_Multiclass:
3337 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
3340 if payloadNames.get(trainingMode)
is None:
3341 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
3342 "\nis not supported. Please choose among the following:\n",
3343 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
3345 mode = payloadNames.get(trainingMode).get(
"mode")
3346 detector = payloadNames.get(trainingMode).get(
"detector")
3348 payloadName = f
"ChargedPidMVAWeights_{mode}"
3353 Const.electron.getPDGCode():
3354 {
"pName":
"e",
"pFullName":
"electron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3355 Const.muon.getPDGCode():
3356 {
"pName":
"mu",
"pFullName":
"muon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3357 Const.pion.getPDGCode():
3358 {
"pName":
"pi",
"pFullName":
"pion",
"pNameBkg":
"K",
"pdgIdBkg": Const.kaon.getPDGCode()},
3359 Const.kaon.getPDGCode():
3360 {
"pName":
"K",
"pFullName":
"kaon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3361 Const.proton.getPDGCode():
3362 {
"pName":
"p",
"pFullName":
"proton",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3363 Const.deuteron.getPDGCode():
3364 {
"pName":
"d",
"pFullName":
"deuteron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3368 vm.addAlias(
"__event__",
"evtNum")
3370 for detID
in Const.PIDDetectors.c_set:
3373 if detID == Const.EDetector.SVD:
3374 B2WARNING(
"The ChargedPidMVA training currently does not include the SVD.")
3377 detName = Const.parseDetectors(detID)
3379 for pdgIdSig, info
in stdChargedMap.items():
3381 if binaryHypoPDGCodes == (0, 0):
3383 pFullName = info[
"pFullName"]
3387 alias = f
"{pFullName}ID_{detName}"
3388 orig = f
"pidProbabilityExpert({pdgIdSig}, {detName})"
3389 vm.addAlias(alias, orig)
3392 alias_trf = f
"{pFullName}ID_{detName}_LogTransfo"
3393 orig_trf = f
"formula(-1. * log10(formula(((1. - {orig}) + {epsilon}) / ({orig} + {epsilon}))))"
3394 vm.addAlias(alias_trf, orig_trf)
3398 alias_trf = f
"{pFullName}ID_LogTransfo"
3399 orig_trf = f
"formula(-1. * log10(formula(((1. - {pFullName}ID) + {epsilon}) / ({pFullName}ID + {epsilon}))))"
3400 vm.addAlias(alias_trf, orig_trf)
3404 pName, pNameBkg, pdgIdBkg = info[
"pName"], info[
"pNameBkg"], info[
"pdgIdBkg"]
3408 alias = f
"deltaLogL_{pName}_{pNameBkg}_{detName}"
3409 orig = f
"pidDeltaLogLikelihoodValueExpert({pdgIdSig}, {pdgIdBkg}, {detName})"
3410 vm.addAlias(alias, orig)
3414 alias = f
"deltaLogL_{pName}_{pNameBkg}_ALL"
3415 orig = f
"pidDeltaLogLikelihoodValueExpert({pdgIdSig}, {pdgIdBkg}, ALL)"
3416 vm.addAlias(alias, orig)
3420 if binaryHypoPDGCodes == (0, 0):
3423 chargedpid = register_module(
"ChargedPidMVAMulticlass")
3424 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
3431 binaryOpts = [(pdgIdSig, info[
"pdgIdBkg"])
for pdgIdSig, info
in stdChargedMap.items()]
3433 if binaryHypoPDGCodes
not in binaryOpts:
3434 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
3435 ". Please choose among the following pairs:\n",
3436 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
3440 if not decayDescriptor.init(name):
3441 raise ValueError(f
"Invalid particle list {name} in applyChargedPidMVA!")
3442 pdgs = [abs(decayDescriptor.getMother().getPDGCode())]
3443 daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
3444 if len(daughter_pdgs) > 0:
3445 pdgs = daughter_pdgs
3447 if pdg
not in binaryHypoPDGCodes:
3448 B2WARNING(
"Given ParticleList: ", name,
" (", pdg,
") is neither signal (", binaryHypoPDGCodes[0],
3449 ") nor background (", binaryHypoPDGCodes[1],
").")
3451 chargedpid = register_module(
"ChargedPidMVA")
3452 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
3453 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
3454 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
3456 chargedpid.param(
"particleLists", list(plSet))
3457 chargedpid.param(
"payloadName", payloadName)
3458 chargedpid.param(
"chargeIndependent", chargeIndependent)
3461 if detector ==
"ECL":
3462 chargedpid.param(
"useECLOnlyTraining",
True)
3464 path.add_module(chargedpid)
3467 def calculateTrackIsolation(decay_string, path, *detectors, reference_list_name=None, highest_prob_mass_for_ext=False):
3469 Given an input decay string, compute variables that quantify track-based "isolation" of the charged
3470 stable particles in the decay chain.
3473 Currently, a proxy for isolation is defined as the distance
3474 of each particle's track to its closest neighbour, defined as the segment connecting the two tracks
3475 intersection points on a given cylindrical surface.
3476 The calculation relies on the track helix extrapolation.
3478 The definition of distance and the number of distances that are calculated per sub-detector is based on
3479 the following recipe:
3481 - CDC: as the segmentation is very coarse along z,
3482 the distance is defined as the cord length on the (rho=R, phi) plane.
3483 A total of 9 distances are calculated: the cylindrical surfaces are defined at R values
3484 that correspond to the positions of the 9 CDC wire superlayers.
3485 - TOP: as there is no segmentation along z,
3486 the distance is defined as the cord length on the (rho=R, phi) plane.
3487 Only one distance at the TOP entry radius is calculated.
3488 - ARICH: as there is no segmentation along z,
3489 the distance is defined as the distance on the (rho, phi) plane at fixed z=Z.
3490 Only one distance at the ARICH photon detector Z entry coordinate is calculated.
3491 - ECL: the distance is defined on the (rho=R, phi, z) surface in the barrel,
3492 on the (rho, phi, z=Z) surface in the endcaps.
3493 Two distances are calculated: one at the ECL entry radius R (barrel), entry Z (endcaps),
3494 and one at R, Z corresponding roughly to the mid-point of the longitudinal size of the crystals.
3495 - KLM: the distance is defined on the (rho=R, phi, z) surface in the barrel,
3496 on the (rho, phi, z=Z) surface in the endcaps.
3497 Only one distance at the KLM first strip entry radius R (barrel), Z (endcaps) is calculated.
3500 decay_string (str): name of the input decay string with selected charged stable daughters,
3501 for example: ``Lambda0:merged -> ^p+ ^pi-``.
3502 Alternatively, it can be a particle list for charged stable particles
3503 as defined in ``Const::chargedStableSet``, for example: ``mu+:all``.
3504 The charge-conjugate particle list will be also processed automatically.
3505 path (basf2.Path): path to which module(s) will be added.
3506 *detectors: detectors for which track isolation variables will be calculated.
3507 Choose among: "CDC", "TOP", "ARICH", "ECL", "KLM"
3508 reference_list_name (Optional[str]): name of the input charged stable particle list for the reference tracks.
3509 By default, the ``:all`` ParticleList of the same type
3510 of the selected particle in ``decay_string`` is used.
3511 The charge-conjugate particle list will be also processed automatically.
3512 highest_prob_mass_for_hex (Optional[bool]): if this option is set, the helix extrapolation for the particles
3513 will use the track fit result for the most
3514 probable mass hypothesis, namely, the one that gives the highest
3515 chi2Prob of the fit.
3518 list(str): a list of aliases for the calculated distance variables.
3523 from ROOT
import Belle2, TDatabasePDG
3526 if not decayDescriptor.init(decay_string):
3527 B2FATAL(f
"Invalid particle list {decay_string} in calculateTrackIsolation!")
3528 no_reference_list_name =
not reference_list_name
3530 det_choices = [
"CDC",
"TOP",
"ARICH",
"ECL",
"KLM"]
3531 if any(d
not in det_choices
for d
in detectors):
3532 B2FATAL(
"Your input detector list: ", detectors,
" contains an invalid choice. Please select among: ", det_choices)
3535 for det
in detectors:
3537 det_labels.extend([f
"{det}{ilayer}" for ilayer
in range(9)])
3539 det_labels.extend([f
"{det}{ilayer}" for ilayer
in range(2)])
3541 det_labels.append(f
"{det}0")
3546 processed_decay_strings = []
3547 if select_symbol
in decay_string:
3548 splitted_ds = decay_string.split(select_symbol)
3549 for i
in range(decay_string.count(select_symbol)):
3550 tmp = list(splitted_ds)
3551 tmp.insert(i+1, select_symbol)
3552 processed_decay_strings += [
''.join(tmp)]
3554 processed_decay_strings += [decay_string]
3556 for processed_dec
in processed_decay_strings:
3557 if no_reference_list_name:
3558 decayDescriptor.init(processed_dec)
3559 daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
3560 if len(daughter_pdgs) > 0:
3561 reference_list_name = f
'{TDatabasePDG.Instance().GetParticle(abs(daughter_pdgs[0])).GetName()}:all'
3563 reference_list_name = f
'{processed_dec.split(":")[0]}:all'
3565 for det
in det_labels:
3566 trackiso = path.add_module(
"TrackIsoCalculator",
3567 decayString=processed_dec,
3568 detectorSurface=det,
3569 particleListReference=reference_list_name,
3570 useHighestProbMassForExt=highest_prob_mass_for_ext)
3571 trackiso.set_name(f
"TrackIsoCalculator{det}_{processed_dec}_VS_{reference_list_name}")
3575 extra_suffix =
"" if not highest_prob_mass_for_ext
else "__useHighestProbMassForExt"
3577 aliases = vu.create_aliases(
3578 [f
"distToClosestTrkAt{det}_VS_{reference_list_name}{extra_suffix}" for det
in det_labels],
"extraInfo({variable})")
3583 def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
3585 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
3586 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
3587 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
3588 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
3591 .. code-block:: python
3593 from modularAnalysis import calculateDistance
3594 calculateDistance('list_name', 'decay_string', "mode", path=user_path)
3596 @param list_name name of the input ParticleList
3597 @param decay_string select particles between the distance of closest approach will be calculated
3598 @param mode Specifies how the distance is calculated
3599 vertextrack: calculate the distance of closest approach between a track and a\
3600 vertex, taking the first candidate as vertex, default
3601 trackvertex: calculate the distance of closest approach between a track and a\
3602 vertex, taking the first candidate as track
3603 2tracks: calculates the distance of closest approach between two tracks
3604 2vertices: calculates the distance between two vertices
3605 vertexbtube: calculates the distance of closest approach between a vertex and btube
3606 trackbtube: calculates the distance of closest approach between a track and btube
3607 @param path modules are added to this path
3611 dist_mod = register_module(
'DistanceCalculator')
3613 dist_mod.set_name(
'DistanceCalculator_' + list_name)
3614 dist_mod.param(
'listName', list_name)
3615 dist_mod.param(
'decayString', decay_string)
3616 dist_mod.param(
'mode', mode)
3617 path.add_module(dist_mod)
3620 def addInclusiveDstarReconstruction(decayString, slowPionCut, DstarCut, path):
3622 Adds the InclusiveDstarReconstruction module to the given path.
3623 This module creates a D* particle list by estimating the D* four momenta
3624 from slow pions, specified by a given cut. The D* energy is approximated
3625 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
3626 momentum is calculated using the D* PDG mass and the direction is collinear
3627 to the slow pion direction. The charge of the given pion list has to be consistent
3630 @param decayString Decay string, must be of form ``D* -> pi``
3631 @param slowPionCut Cut applied to the input pion list to identify slow pions
3632 @param DstarCut Cut applied to the output D* list
3633 @param path the module is added to this path
3635 incl_dstar = register_module(
"InclusiveDstarReconstruction")
3636 incl_dstar.param(
"decayString", decayString)
3637 incl_dstar.param(
"slowPionCut", slowPionCut)
3638 incl_dstar.param(
"DstarCut", DstarCut)
3639 path.add_module(incl_dstar)
3642 def scaleError(outputListName, inputListName,
3643 scaleFactors=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
3644 scaleFactorsNoPXD=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
3645 d0Resolution=[0.00115328, 0.00134704],
3646 z0Resolution=[0.00124327, 0.0013272],
3651 This module creates a new charged particle list.
3652 The helix errors of the new particles are scaled by constant factors.
3653 Two sets of five scale factors are defined for tracks with and without a PXD hit.
3654 The scale factors are in order of (d0, phi0, omega, z0, tanlambda).
3655 For tracks with a PXD hit, in order to avoid severe underestimation of d0 and z0 errors,
3656 lower limits (best resolution) can be set in a momentum-dependent form.
3657 This module is supposed to be used only for TDCPV analysis and for low-momentum (0-3 GeV/c) tracks in BBbar events.
3658 Details will be documented in a Belle II note, BELLE2-NOTE-PH-2021-038.
3660 @param inputListName Name of input charged particle list to be scaled
3661 @param outputListName Name of output charged particle list with scaled error
3662 @param scaleFactors List of five constants to be multiplied to each of helix errors (for tracks with a PXD hit)
3663 @param scaleFactorsNoPXD List of five constants to be multiplied to each of helix errors (for tracks without a PXD hit)
3664 @param d0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
3665 defining d0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**1.5))**2 }
3666 @param z0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
3667 defining z0 best resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**2.5))**2 }
3668 @param d0MomThr d0 best resolution is kept constant below this momentum
3669 @param z0MomThr z0 best resolution is kept constant below this momentum
3672 scale_error = register_module(
"HelixErrorScaler")
3673 scale_error.set_name(
'ScaleError_' + inputListName)
3674 scale_error.param(
'inputListName', inputListName)
3675 scale_error.param(
'outputListName', outputListName)
3676 scale_error.param(
'scaleFactors_PXD', scaleFactors)
3677 scale_error.param(
'scaleFactors_noPXD', scaleFactorsNoPXD)
3678 scale_error.param(
'd0ResolutionParameters', d0Resolution)
3679 scale_error.param(
'z0ResolutionParameters', z0Resolution)
3680 scale_error.param(
'd0MomentumThreshold', d0MomThr)
3681 scale_error.param(
'z0MomentumThreshold', z0MomThr)
3682 path.add_module(scale_error)
3685 def correctEnergyBias(inputListNames, tableName, path=None):
3687 Scale energy of the particles according to the scaling factor.
3688 If the particle list contains composite particles, the energy of the daughters are scaled.
3689 Subsequently, the energy of the mother particle is updated as well.
3692 inputListNames (list(str)): input particle list names
3693 tableName : stored in localdb and created using ParticleWeightingLookUpCreator
3694 path (basf2.Path): module is added to this path
3697 correctenergybias = register_module(
'EnergyBiasCorrection')
3698 correctenergybias.param(
'particleLists', inputListNames)
3699 correctenergybias.param(
'tableName', tableName)
3700 path.add_module(correctenergybias)
3703 def addPhotonEfficiencyRatioVariables(inputListNames, tableName, path=None):
3705 Add photon Data/MC detection efficiency ratio weights to the specified particle list
3708 inputListNames (list(str)): input particle list names
3709 tableName : taken from database with appropriate name
3710 path (basf2.Path): module is added to this path
3713 photon_efficiency_correction = register_module(
'PhotonEfficiencySystematics')
3714 photon_efficiency_correction.param(
'particleLists', inputListNames)
3715 photon_efficiency_correction.param(
'tableName', tableName)
3716 path.add_module(photon_efficiency_correction)
3719 def addPi0VetoEfficiencySystematics(particleList, decayString, tableName, threshold, mode='standard', suffix='', path=None):
3721 Add pi0 veto Data/MC efficiency ratio weights to the specified particle list
3723 @param particleList the input ParticleList
3724 @param decayString specify hard photon to be performed pi0 veto (e.g. 'B+:sig -> rho+:sig ^gamma:hard')
3725 @param tableName table name corresponding to payload version (e.g. 'Pi0VetoEfficiencySystematics_Mar2022')
3726 @param threshold pi0 veto threshold (0.10, 0.11, ..., 0.99)
3727 @param mode choose one mode (same as writePi0EtaVeto) out of 'standard', 'tight', 'cluster' and 'both'
3728 @param suffix optional suffix to be appended to the usual extraInfo name
3729 @param path the module is added to this path
3731 The following extraInfo are available related with the given particleList:
3732 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_ratio : weight of Data/MC for the veto efficiency
3733 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_stat : the statistical uncertainty of the weight
3734 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_sys : the systematic uncertainty of the weight
3735 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_total : the total uncertainty of the weight
3736 * Pi0VetoEfficiencySystematics_{mode}{suffix}_threshold : threshold of the pi0 veto
3739 pi0veto_efficiency_correction = register_module(
'Pi0VetoEfficiencySystematics')
3740 pi0veto_efficiency_correction.param(
'particleLists', particleList)
3741 pi0veto_efficiency_correction.param(
'decayString', decayString)
3742 pi0veto_efficiency_correction.param(
'tableName', tableName)
3743 pi0veto_efficiency_correction.param(
'threshold', threshold)
3744 pi0veto_efficiency_correction.param(
'mode', mode)
3745 pi0veto_efficiency_correction.param(
'suffix', suffix)
3746 path.add_module(pi0veto_efficiency_correction)
3749 def getAnalysisGlobaltag(timeout=180) -> str:
3751 Returns a string containing the name of the latest and recommended analysis globaltag.
3754 timeout: Seconds to wait for b2conditionsdb-recommend
3759 tags = subprocess.check_output(
3760 [
'b2conditionsdb-recommend',
'--oneline'],
3762 ).decode(
'UTF-8').rstrip().split(
' ')
3765 if tag.startswith(
'analysis_tools'):
3769 except subprocess.TimeoutExpired
as te:
3770 B2FATAL(f
'A {te} exception was raised during the call of getAnalysisGlobaltag(). '
3771 'The function took too much time to retrieve the requested information '
3772 'from the versioning repository.\n'
3773 'Plase try to re-run your job. In case of persistent failures, there may '
3774 'be issues with the DESY collaborative services, so please contact the experts.')
3775 except subprocess.CalledProcessError
as ce:
3776 B2FATAL(f
'A {ce} exception was raised during the call of getAnalysisGlobaltag(). '
3777 'Please try to re-run your job. In case of persistent failures, please contact '
3781 def getNbarIDMVA(particleList, path=None, ):
3783 This function can give a score to predict if it is a anti-n0.
3784 It is not used to predict n0.
3785 Currently, this can be used only for ECL cluster.
3786 output will be stored in extraInfo(nbarID); -1 means MVA invalid
3787 @param particleList The input ParticleList
3788 @param path modules are added to this path
3790 from variables
import variables
3791 variables.addAlias(
'V1',
'clusterHasPulseShapeDiscrimination')
3792 variables.addAlias(
'V2',
'clusterE')
3793 variables.addAlias(
'V3',
'clusterLAT')
3794 variables.addAlias(
'V4',
'clusterE1E9')
3795 variables.addAlias(
'V5',
'clusterE9E21')
3796 variables.addAlias(
'V6',
'clusterZernikeMVA')
3797 variables.addAlias(
'V7',
'clusterAbsZernikeMoment40')
3798 variables.addAlias(
'V8',
'clusterAbsZernikeMoment51')
3800 variables.addAlias(
'nbarIDValid',
3801 'passesCut(V1 == 1 and V2 >= 0 and V3 >= 0 and V4 >= 0 and V5 >= 0 and V6 >= 0 and V7 >= 0 and V8 >= 0)')
3802 variables.addAlias(
'nbarIDmod',
'conditionalVariableSelector(nbarIDValid == 1, extraInfo(nbarIDFromMVA), constant(-1.0))')
3803 basf2.conditions.prepend_globaltag(getAnalysisGlobaltag())
3804 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'nbarIDFromMVA', identifier=
'db_nbarIDECL')
3808 def reconstructDecayWithNeutralHadron(decayString, cut, allowGamma=False, path=None, **kwargs):
3810 Reconstructs decay with a long-lived neutral hadron e.g.
3811 :math:`B^0 \to J/\psi K_L^0`,
3812 :math:`B^0 \to p \bar{n} D^*(2010)^-`.
3814 The calculation is done with IP constraint and mother mass constraint.
3816 The decay string passed in must satisfy the following rules:
3818 - The neutral hadron must be **selected** in the decay string with the
3819 caret (``^``) e.g. ``B0:sig -> J/psi:sig ^K_L0:sig``. (Note the caret
3820 next to the neutral hadron.)
3821 - There can only be **one neutral hadron in a decay**.
3822 - The neutral hadron has to be a direct daughter of its mother.
3824 .. note:: This function forwards its arguments to `reconstructDecay`,
3825 so please check the documentation of `reconstructDecay` for all
3828 @param decayString A decay string following the mentioned rules
3829 @param cut Cut to apply to the particle list
3830 @param allowGamma whether allow the selected particle to be ``gamma``
3831 @param path The path to put in the module
3833 reconstructDecay(decayString, cut, path=path, **kwargs)
3834 module = register_module(
'NeutralHadron4MomentumCalculator')
3835 module.set_name(
'NeutralHadron4MomentumCalculator_' + decayString)
3836 module.param(
'decayString', decayString)
3837 module.param(
'allowGamma', allowGamma)
3838 path.add_module(module)
3841 if __name__ ==
'__main__':
3843 pretty_print_module(__name__,
"modularAnalysis")
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)