12This module defines wrapper functions around the analysis modules.
16from basf2
import register_module, create_path
17from basf2
import B2INFO, B2WARNING, B2ERROR, B2FATAL
22def setAnalysisConfigParams(configParametersAndValues, path):
24 Sets analysis configuration parameters.
28 - 'tupleStyle':
'Default' (default)
or 'Laconic'
30 - defines the style of the branch name
in the ntuple
32 -
'mcMatchingVersion': Specifies what version of mc matching algorithm
is going to be used:
34 -
'Belle' - analysis of Belle MC
35 -
'BelleII' (default) - all other cases
37 @param configParametersAndValues dictionary of parameters
and their values of the form {param1: value, param2: value, ...)
38 @param modules are added to this path
41 conf = register_module('AnalysisConfiguration')
43 allParameters = [
'tupleStyle',
'mcMatchingVersion']
45 keys = configParametersAndValues.keys()
47 if key
not in allParameters:
48 allParametersString =
', '.join(allParameters)
49 B2ERROR(
'Invalid analysis configuration parameter: ' + key +
'.\n'
50 'Please use one of the following: ' + allParametersString)
52 for param
in allParameters:
53 if param
in configParametersAndValues:
54 conf.param(param, configParametersAndValues.get(param))
59def inputMdst(filename, path, environmentType='default', skipNEvents=0, entrySequence=None, *, parentLevel=0, **kwargs):
61 Loads the specified :ref:`mDST <mdst>` (or :ref:`uDST <analysis_udstoutput>`) file
with the RootInput module.
63 The correct environment (e.g. magnetic field settings)
is determined
from
64 ``environmentType``. Options are either:
'default' (
for Belle II MC
and
65 data: falls back to database),
'Belle':
for analysis of converted Belle 1
69 filename (str): the name of the file to be loaded
70 path (basf2.Path): modules are added to this path
71 environmentType (str): type of the environment to be loaded (either
'default' or 'Belle')
72 skipNEvents (int): N events of the input file are skipped
73 entrySequence (str): The number sequences (e.g. 23:42,101) defining the entries which are processed.
74 parentLevel (int): Number of generations of parent files (files used
as input when creating a file) to be read
78 if filename ==
'default':
80We have simplified the arguments to inputMdst! If you are running on Belle II
81data or MC, you don't have to use "default" any more.
83 inputMdst("default",
"/your/input/file.root", path=mypath)
85 inputMdst(
"/your/input/file.root", path=mypath)
87 elif filename ==
"Belle":
89We have reordered the arguments to inputMdst! If you are running on Belle 1
90data or MC, you need to specify the 'environmentType'.
92 inputMdst("Belle",
"/your/input/file.root", path=mypath)
94 inputMdst(
"/your/input/file.root", path=mypath, environmentType=
'Belle')
96 elif filename
in [f
"MC{i}" for i
in range(5, 10)]:
97 B2FATAL(f
"We no longer support the MC version {filename}. Sorry.")
99 if entrySequence
is not None:
100 entrySequence = [entrySequence]
102 inputMdstList([filename], path, environmentType, skipNEvents, entrySequence, parentLevel=parentLevel, **kwargs)
108 environmentType='default',
113 useB2BIIDBCache=True):
115 Loads the specified list of :ref:`mDST <mdst>` (or :ref:`uDST <analysis_udstoutput>`) files
with the RootInput module.
117 The correct environment (e.g. magnetic field settings)
is determined
from
118 ``environmentType``. Options are either:
'default' (
for Belle II MC
and
119 data: falls back to database),
'Belle':
for analysis of converted Belle 1
123 filelist (list(str)): the filename list of files to be loaded
124 path (basf2.Path): modules are added to this path
125 environmentType (str): type of the environment to be loaded (either
'default' or 'Belle')
126 skipNEvents (int): N events of the input files are skipped
127 entrySequences (list(str)): The number sequences (e.g. 23:42,101) defining
128 the entries which are processed
for each inputFileName.
129 parentLevel (int): Number of generations of parent files (files used
as input when creating a file) to be read
130 useB2BIIDBCache (bool): Loading of local KEKCC database (only to be deactivated
in very special cases)
134 if filelist ==
'default':
136We have simplified the arguments to inputMdstList! If you are running on
137Belle II data or MC, you don't have to use "default" any more.
139 inputMdstList("default", list_of_your_files, path=mypath)
141 inputMdstList(list_of_your_files, path=mypath)
143 elif filelist ==
"Belle":
145We have reordered the arguments to inputMdstList! If you are running on
146Belle 1 data or MC, you need to specify the 'environmentType'.
148 inputMdstList("Belle", list_of_your_files, path=mypath)
150 inputMdstList(list_of_your_files, path=mypath, environmentType=
'Belle')
152 elif filelist
in [f
"MC{i}" for i
in range(5, 10)]:
153 B2FATAL(f
"We no longer support the MC version {filelist}. Sorry.")
155 roinput = register_module(
'RootInput')
156 roinput.param(
'inputFileNames', filelist)
157 roinput.param(
'skipNEvents', skipNEvents)
158 if entrySequences
is not None:
159 roinput.param(
'entrySequences', entrySequences)
160 roinput.param(
'parentLevel', parentLevel)
162 path.add_module(roinput)
163 path.add_module(
'ProgressBar')
165 if environmentType ==
'Belle':
170 from ROOT
import Belle2
176 setAnalysisConfigParams({
'mcMatchingVersion':
'Belle'}, path)
179 basf2.conditions.metadata_providers = [
"/sw/belle/b2bii/database/conditions/b2bii.sqlite"]
180 basf2.conditions.payload_locations = [
"/sw/belle/b2bii/database/conditions/"]
183def outputMdst(filename, path):
185 Saves mDST (mini-Data Summary Tables) to the output root file.
189 This function is kept
for backward-compatibility.
190 Better to use `mdst.add_mdst_output` directly.
198def outputUdst(filename, particleLists=None, includeArrays=None, path=None, dataDescription=None):
200 Save uDST (user-defined Data Summary Tables) = MDST + Particles + ParticleLists
201 The charge-conjugate lists of those given in particleLists are also stored.
202 Additional Store Arrays
and Relations to be stored can be specified via includeArrays
206 This does
not reduce the amount of Particle objects saved,
207 see `udst.add_skimmed_udst_output`
for a function that does.
213 path=path, filename=filename, particleLists=particleLists,
214 additionalBranches=includeArrays, dataDescription=dataDescription)
217def outputIndex(filename, path, includeArrays=None, keepParents=False, mc=True):
219 Write out all particle lists as an index file to be reprocessed using parentLevel flag.
220 Additional branches necessary
for file to be read are automatically included.
221 Additional Store Arrays
and Relations to be stored can be specified via includeArrays
224 @param str filename the name of the output index file
225 @param str path modules are added to this path
226 @param list(str) includeArrays: datastore arrays/objects to write to the output
227 file
in addition to particle lists
and related information
228 @param bool keepParents whether the parents of the input event will be saved
as the parents of the same event
229 in the output index file. Useful
if you are only adding more information to another index file
230 @param bool mc whether the input data
is MC
or not
233 if includeArrays
is None:
237 onlyPLists = register_module(
'OnlyWriteOutParticleLists')
238 path.add_module(onlyPLists)
243 'ParticlesToMCParticles',
244 'ParticlesToPIDLikelihoods',
245 'ParticleExtraInfoMap',
248 branches = [
'EventMetaData']
249 persistentBranches = [
'FileMetaData']
253 branches += partBranches
254 branches += includeArrays
256 r1 = register_module(
'RootOutput')
257 r1.param(
'outputFileName', filename)
258 r1.param(
'additionalBranchNames', branches)
259 r1.param(
'branchNamesPersistent', persistentBranches)
260 r1.param(
'keepParents', keepParents)
264def setupEventInfo(noEvents, path):
266 Prepare to generate events. This function sets up the EventInfoSetter.
267 You should call this before adding a generator from generators.
268 The experiment
and run numbers are set to 0 (run independent generic MC
in phase 3).
269 https://xwiki.desy.de/xwiki/rest/p/59192
272 noEvents (int): number of events to be generated
273 path (basf2.Path): modules are added to this path
276 evtnumbers = register_module('EventInfoSetter')
277 evtnumbers.param(
'evtNumList', [noEvents])
278 evtnumbers.param(
'runList', [0])
279 evtnumbers.param(
'expList', [0])
280 path.add_module(evtnumbers)
283def loadGearbox(path, silence_warning=False):
285 Loads Gearbox module to the path.
288 Should be used in a job
with *cosmic event generation only*
290 Needed
for scripts which only generate cosmic events
in order to
293 @param path modules are added to this path
294 @param silence_warning stops a verbose warning message
if you know you want to use this function
297 if not silence_warning:
298 B2WARNING(
"""You are overwriting the geometry from the database with Gearbox.
299 This is fine
if you
're generating cosmic events. But in most other cases you probably don't want this.
301 If you
're really sure you know what you're doing you can suppress this message
with:
303 >>> loadGearbox(silence_warning=
True)
307 paramloader = register_module('Gearbox')
308 path.add_module(paramloader)
311def printPrimaryMCParticles(path, **kwargs):
313 Prints all primary MCParticles, that is particles
from
314 the physics generator
and not particles created by the simulation
316 This
is equivalent to `printMCParticles(onlyPrimaries=
True, path=path) <printMCParticles>`
and additional
317 keyword arguments are just forwarded to that function
320 return printMCParticles(onlyPrimaries=
True, path=path, **kwargs)
323def printMCParticles(onlyPrimaries=False, maxLevel=-1, path=None, *,
324 showProperties=False, showMomenta=False, showVertices=False, showStatus=False, suppressPrint=False):
326 Prints all MCParticles or just primary MCParticles up to specified level. -1 means no limit.
328 By default this will
print a tree of just the particle names
and their pdg
329 codes
in the event,
for example ::
331 [INFO] Content of MCParticle list
334 ╰── Upsilon(4S) (300553)
336 │ ├── anti-D_0*0 (-10421)
337 │ │ ├── D- (-411)
338 │ │ │ ├── K*- (-323)
339 │ │ │ │ ├── anti-K0 (-311)
340 │ │ │ │ │ ╰── K_S0 (310)
341 │ │ │ │ │ ├── pi+ (211)
342 │ │ │ │ │ │ ╰╶╶ p+ (2212)
343 │ │ │ │ │ ╰── pi- (-211)
344 │ │ │ │ │ ├╶╶ e- (11)
345 │ │ │ │ │ ├╶╶ n0 (2112)
346 │ │ │ │ │ ├╶╶ n0 (2112)
347 │ │ │ │ │ ╰╶╶ n0 (2112)
348 │ │ │ │ ╰── pi- (-211)
349 │ │ │ │ ├╶╶ anti-nu_mu (-14)
350 │ │ │ │ ╰╶╶ mu- (13)
351 │ │ │ │ ├╶╶ nu_mu (14)
352 │ │ │ │ ├╶╶ anti-nu_e (-12)
353 │ │ │ │ ╰╶╶ e- (11)
354 │ │ │ ╰── K_S0 (310)
355 │ │ │ ├── pi0 (111)
356 │ │ │ │ ├── gamma (22)
357 │ │ │ │ ╰── gamma (22)
358 │ │ │ ╰── pi0 (111)
359 │ │ │ ├── gamma (22)
360 │ │ │ ╰── gamma (22)
361 │ │ ╰── pi+ (211)
362 │ ├── mu+ (-13)
363 │ │ ├╶╶ anti-nu_mu (-14)
364 │ │ ├╶╶ nu_e (12)
365 │ │ ╰╶╶ e+ (-11)
366 │ ├── nu_mu (14)
367 │ ╰── gamma (22)
371 There
's a distinction between primary and secondary particles. Primary particles are the ones created by the physics generator while secondary
372 particles are ones generated by the simulation of the detector interaction.
374 Secondaries are indicated
with a dashed line leading to the particle name
375 and if the output
is to the terminal they will be printed
in red. If
376 ``onlyPrimaries``
is True they will
not be included
in the tree.
378 On demand, extra information on all the particles can be displayed by
379 enabling any of the ``showProperties``, ``showMomenta``, ``showVertices``
380 and ``showStatus`` flags. Enabling all of them will look like
385 │ mass=0.14 energy=0.445 charge=-1 lifetime=6.36
386 │ p=(0.257, -0.335, 0.0238) |p|=0.423
387 │ production vertex=(0.113, -0.0531, 0.0156), time=0.00589
388 │ status flags=PrimaryParticle, StableInGenerator, StoppedInDetector
392 mass=0.94 energy=0.94 charge=0 lifetime=5.28e+03
393 p=(-0.000238, -0.0127, 0.0116) |p|=0.0172
394 production vertex=(144, 21.9, -1.29), time=39
395 status flags=StoppedInDetector
396 creation process=HadronInelastic
399 The first line of extra information
is enabled by ``showProperties``, the
400 second line by ``showMomenta``, the third line by ``showVertices``
and the
401 last two lines by ``showStatus``. Note that all values are given
in Belle II
402 standard units, that
is GeV, centimeter
and nanoseconds.
404 The depth of the tree can be limited
with the ``maxLevel`` argument: If it
's
405 bigger than zero it will limit the tree to the given number of generations.
406 A visual indicator will be added after each particle which would have
407 additional daughters that are skipped due to this limit. An example event
408 with ``maxLevel=3``
is given below. In this case only the tau neutrino
and
409 the pion don
't have additional daughters. ::
411 [INFO] Content of MCParticle list
414 ╰── Upsilon(4S) (300553)
416 │ ├── anti-D*0 (-423) → …
417 │ ├── tau+ (-15) → …
418 │ ╰── nu_tau (16)
420 ├── D*0 (423) → …
421 ├── K*- (-323) → …
422 ├── K*+ (323) → …
425 The same information will be stored in the branch ``__MCDecayString__`` of
426 TTree created by `VariablesToNtuple`
or `VariablesToEventBasedTree` module.
427 This branch
is automatically created when `PrintMCParticles` modules
is called.
428 Printing the information on the log message can be suppressed
if ``suppressPrint``
429 is True,
while the branch ``__MCDecayString__``. This option helps to reduce the
430 size of the log message.
433 onlyPrimaries (bool): If
True show only primary particles, that
is particles coming
from
434 the generator
and not created by the simulation.
435 maxLevel (int): If 0
or less
print the whole tree, otherwise stop after n generations
436 showProperties (bool): If
True show mass, energy
and charge of the particles
437 showMomenta (bool):
if True show the momenta of the particles
438 showVertices (bool):
if True show production vertex
and production time of all particles
439 showStatus (bool):
if True show some status information on the particles.
440 For secondary particles this includes creation process.
441 suppressPrint (bool):
if True printing the information on the log message
is suppressed.
442 Even
if True, the branch ``__MCDecayString__``
is created.
445 return path.add_module(
447 onlyPrimaries=onlyPrimaries,
449 showProperties=showProperties,
450 showMomenta=showMomenta,
451 showVertices=showVertices,
452 showStatus=showStatus,
453 suppressPrint=suppressPrint,
457def correctBrems(outputList,
460 maximumAcceptance=3.0,
461 multiplePhotons=False,
462 usePhotonOnlyOnce=True,
466 For each particle in the given ``inputList``, copies it to the ``outputList``
and adds the
467 4-vector of the photon(s)
in the ``gammaList`` which has(have) a weighted named relation to
468 the particle
's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
471 This can only work if the mdst file contains the *Bremsstrahlung* named relation. Official MC samples
472 up to
and including MC12
and proc9 **do
not** contain this. Newer production campaigns (
from proc10
and MC13) do.
473 However, studies by the tau WG revealed that the cuts applied by the ``ECLTrackBremFinder`` module are too tight.
474 These will be loosened but this will only have effect
with proc13
and MC15.
475 If your analysis
is very sensitive to the Bremsstrahlung corrections, it
is advised to use `correctBremsBelle`.
478 A detailed description of how the weights are set can be found directly at the documentation of the
479 `BremsFinder` module.
481 Please note that a new particle
is always generated,
with the old particle
and -
if found- one
or more
482 photons
as daughters.
484 The ``inputList`` should contain particles
with associated tracks. Otherwise, the module will exit
with an error.
486 The ``gammaList`` should contain photons. Otherwise, the module will exit
with an error.
488 @param outputList The output particle list name containing the corrected particles
489 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
490 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
491 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
492 @param multiplePhotons Whether to use only one photon (the one
with the smallest acceptance)
or as many
as possible
493 @param usePhotonOnlyOnce If true, each brems candidate
is used to correct only the track
with the smallest relation weight
494 @param writeOut Whether `RootOutput` module should save the created ``outputList``
495 @param path The module
is added to this path
500 B2ERROR(
"The BremsFinder can only be run over Belle II data.")
502 bremscorrector = register_module(
'BremsFinder')
503 bremscorrector.set_name(
'bremsCorrector_' + outputList)
504 bremscorrector.param(
'inputList', inputList)
505 bremscorrector.param(
'outputList', outputList)
506 bremscorrector.param(
'gammaList', gammaList)
507 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
508 bremscorrector.param(
'multiplePhotons', multiplePhotons)
509 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
510 bremscorrector.param(
'writeOut', writeOut)
511 path.add_module(bremscorrector)
514def copyList(outputListName, inputListName, writeOut=False, path=None):
516 Copy all Particle indices from input ParticleList to the output ParticleList.
517 Note that the Particles themselves are
not copied. The original
and copied
518 ParticleLists will point to the same Particles.
520 @param ouputListName copied ParticleList
521 @param inputListName original ParticleList to be copied
522 @param writeOut whether RootOutput module should save the created ParticleList
523 @param path modules are added to this path
526 copyLists(outputListName, [inputListName], writeOut, path)
529def correctBremsBelle(outputListName,
532 multiplePhotons=True,
534 usePhotonOnlyOnce=False,
538 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
539 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
543 Studies by the tau WG show that using a rather wide opening angle (up to
544 0.2 rad)
and rather low energetic photons results
in good correction.
545 However, this should only serve
as a starting point
for your own studies
546 because the optimal criteria are likely mode-dependent
549 outputListName (str): The output charged particle list containing the corrected charged particles
550 inputListName (str): The initial charged particle list containing the charged particles to correct.
551 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
552 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one ->
False,
553 add all the photons within the cone ->
True
554 angleThreshold (float): The maximum angle
in radians between the charged particle
and the (radiative)
555 gamma to be accepted.
556 writeOut (bool): whether RootOutput module should save the created ParticleList
557 usePhotonOnlyOnce (bool): If true, a photon
is used
for correction of the closest charged particle
in the inputList.
558 If false, a photon
is allowed to be used
for correction multiple times (Default).
561 One cannot use a photon twice to reconstruct a composite particle. Thus,
for example,
if ``e+``
and ``e-`` are corrected
562 with a ``gamma``, the pair of ``e+``
and ``e-`` cannot form a ``J/psi -> e+ e-`` candidate.
564 path (basf2.Path): modules are added to this path
567 fsrcorrector = register_module('BelleBremRecovery')
568 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
569 fsrcorrector.param(
'inputListName', inputListName)
570 fsrcorrector.param(
'outputListName', outputListName)
571 fsrcorrector.param(
'gammaListName', gammaListName)
572 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
573 fsrcorrector.param(
'angleThreshold', angleThreshold)
574 fsrcorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
575 fsrcorrector.param(
'writeOut', writeOut)
576 path.add_module(fsrcorrector)
579def copyLists(outputListName, inputListNames, writeOut=False, path=None):
581 Copy all Particle indices from all input ParticleLists to the
582 single output ParticleList.
583 Note that the Particles themselves are
not copied.
584 The original
and copied ParticleLists will point to the same Particles.
586 Duplicates are removed based on the first-come, first-served principle.
587 Therefore, the order of the input ParticleLists matters.
590 If you want to select the best duplicate based on another criterion, have
591 a look at the function `mergeListsWithBestDuplicate`.
594 Two particles that differ only by the order of their daughters are
595 considered duplicates
and one of them will be removed.
597 @param ouputListName copied ParticleList
598 @param inputListName vector of original ParticleLists to be copied
599 @param writeOut whether RootOutput module should save the created ParticleList
600 @param path modules are added to this path
603 pmanipulate = register_module('ParticleListManipulator')
604 pmanipulate.set_name(
'PListCopy_' + outputListName)
605 pmanipulate.param(
'outputListName', outputListName)
606 pmanipulate.param(
'inputListNames', inputListNames)
607 pmanipulate.param(
'writeOut', writeOut)
608 path.add_module(pmanipulate)
611def copyParticles(outputListName, inputListName, writeOut=False, path=None):
613 Create copies of Particles given in the input ParticleList
and add them to the output ParticleList.
615 The existing relations of the original Particle (
or it
's (grand-)^n-daughters)
616 are copied as well. Note that only the relation
is copied
and that the related
617 object
is not. Copied particles are therefore related to the *same* object
as
620 @param ouputListName new ParticleList filled
with copied Particles
621 @param inputListName input ParticleList
with original Particles
622 @param writeOut whether RootOutput module should save the created ParticleList
623 @param path modules are added to this path
627 pmanipulate = register_module(
'ParticleListManipulator')
628 pmanipulate.set_name(
'PListCopy_' + outputListName)
629 pmanipulate.param(
'outputListName', outputListName)
630 pmanipulate.param(
'inputListNames', [inputListName])
631 pmanipulate.param(
'writeOut', writeOut)
632 path.add_module(pmanipulate)
635 pcopy = register_module(
'ParticleCopier')
636 pcopy.param(
'inputListNames', [outputListName])
637 path.add_module(pcopy)
640def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
642 Copy candidates from all lists
in ``inputListNames`` to
643 ``outputListName``
if they
pass ``cut`` (given selection criteria).
646 Note that the Particles themselves are
not copied.
647 The original
and copied ParticleLists will point to the same Particles.
650 Require energetic pions safely inside the cdc
652 .. code-block:: python
654 cutAndCopyLists(
"pi+:energeticPions", [
"pi+:good",
"pi+:loose"],
"[E > 2] and thetaInCDCAcceptance", path=mypath)
657 You must use square braces ``[``
and ``]``
for conditional statements.
660 outputListName (str): the new ParticleList name
661 inputListName (list(str)): list of input ParticleList names
662 cut (str): Candidates that do
not pass these selection criteria are removed
from the ParticleList
663 writeOut (bool): whether RootOutput module should save the created ParticleList
664 path (basf2.Path): modules are added to this path
667 pmanipulate = register_module('ParticleListManipulator')
668 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
669 pmanipulate.param(
'outputListName', outputListName)
670 pmanipulate.param(
'inputListNames', inputListNames)
671 pmanipulate.param(
'cut', cut)
672 pmanipulate.param(
'writeOut', writeOut)
673 path.add_module(pmanipulate)
676def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
678 Copy candidates from ``inputListName`` to ``outputListName``
if they
pass
679 ``cut`` (given selection criteria).
682 Note the Particles themselves are
not copied.
683 The original
and copied ParticleLists will point to the same Particles.
686 require energetic pions safely inside the cdc
688 .. code-block:: python
690 cutAndCopyList(
"pi+:energeticPions",
"pi+:loose",
"[E > 2] and thetaInCDCAcceptance", path=mypath)
693 You must use square braces ``[``
and ``]``
for conditional statements.
696 outputListName (str): the new ParticleList name
697 inputListName (str): input ParticleList name
698 cut (str): Candidates that do
not pass these selection criteria are removed
from the ParticleList
699 writeOut (bool): whether RootOutput module should save the created ParticleList
700 path (basf2.Path): modules are added to this path
703 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
706def removeTracksForTrackingEfficiencyCalculation(inputListNames, fraction, path=None):
708 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
709 Takes care of the duplicates,
if any.
712 inputListNames (list(str)): input particle list names
713 fraction (float): fraction of particles to be removed randomly
714 path (basf2.Path): module
is added to this path
717 trackingefficiency = register_module('TrackingEfficiency')
718 trackingefficiency.param(
'particleLists', inputListNames)
719 trackingefficiency.param(
'frac', fraction)
720 path.add_module(trackingefficiency)
723def scaleTrackMomenta(inputListNames, scale=float(
'nan'), payloadName=
"", scalingFactorName=
"SF", path=
None):
725 Scale momenta of the particles according to a scaling factor scale.
726 This scaling factor can either be given as constant number
or as the name of the payload which contains
727 the variable scale factors.
728 If the particle list contains composite particles, the momenta of the track-based daughters are scaled.
729 Subsequently, the momentum of the mother particle
is updated
as well.
732 inputListNames (list(str)): input particle list names
733 scale (float): scaling factor (1.0 -- no scaling)
734 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
735 scalingFactorName (str): name of scaling factor variable
in the payload.
736 path (basf2.Path): module
is added to this path
741 B2ERROR(
"The tracking momentum scaler can only be run over Belle II data.")
743 TrackingMomentumScaleFactors = register_module(
'TrackingMomentumScaleFactors')
744 TrackingMomentumScaleFactors.param(
'particleLists', inputListNames)
745 TrackingMomentumScaleFactors.param(
'scale', scale)
746 TrackingMomentumScaleFactors.param(
'payloadName', payloadName)
747 TrackingMomentumScaleFactors.param(
'scalingFactorName', scalingFactorName)
749 path.add_module(TrackingMomentumScaleFactors)
752def correctTrackEnergy(inputListNames, correction=float(
'nan'), payloadName=
"", correctionName=
"SF", path=
None):
754 Correct the energy loss of tracks according to a 'correction' value.
755 This correction can either be given
as constant number
or as the name of the payload which contains
756 the variable corrections.
757 If the particle list contains composite particles, the momenta of the track-based daughters are corrected.
758 Subsequently, the momentum of the mother particle
is updated
as well.
761 inputListNames (list(str)): input particle list names
762 correction (float): correction value to be subtracted to the particle energy (0.0 -- no correction)
763 payloadName (str): name of the payload which contains the phase-space dependent scaling factors
764 correctionName (str): name of correction variable
in the payload.
765 path (basf2.Path): module
is added to this path
770 B2ERROR(
"The tracking energy correction can only be run over Belle II data.")
772 TrackingEnergyLossCorrection = register_module(
'TrackingEnergyLossCorrection')
773 TrackingEnergyLossCorrection.param(
'particleLists', inputListNames)
774 TrackingEnergyLossCorrection.param(
'correction', correction)
775 TrackingEnergyLossCorrection.param(
'payloadName', payloadName)
776 TrackingEnergyLossCorrection.param(
'correctionName', correctionName)
778 path.add_module(TrackingEnergyLossCorrection)
781def smearTrackMomenta(inputListNames, payloadName="", smearingFactorName="smear", path=None):
783 Smear the momenta of the particles according the values read from the given payload.
784 If the particle list contains composite particles, the momenta of the track-based daughters are smeared.
785 Subsequently, the momentum of the mother particle
is updated
as well.
788 inputListNames (list(str)): input particle list names
789 payloadName (str): name of the payload which contains the smearing values
790 smearingFactorName (str): name of smearing factor variable
in the payload.
791 path (basf2.Path): module
is added to this path
794 TrackingMomentumScaleFactors = register_module('TrackingMomentumScaleFactors')
795 TrackingMomentumScaleFactors.param(
'particleLists', inputListNames)
796 TrackingMomentumScaleFactors.param(
'payloadName', payloadName)
797 TrackingMomentumScaleFactors.param(
'smearingFactorName', smearingFactorName)
799 path.add_module(TrackingMomentumScaleFactors)
802def mergeListsWithBestDuplicate(outputListName,
807 ignoreMotherFlavor=False,
810 Merge input ParticleLists into one output ParticleList. Only the best
811 among duplicates is kept. The lowest
or highest value (configurable via
812 preferLowest) of the provided variable determines which duplicate
is the
815 @param ouputListName name of merged ParticleList
816 @param inputListName vector of original ParticleLists to be merged
817 @param variable variable to determine best duplicate
818 @param preferLowest whether lowest
or highest value of variable should be preferred
819 @param writeOut whether RootOutput module should save the created ParticleList
820 @param ignoreMotherFlavor whether the flavor of the mother particle
is ignored when trying to find duplicates
821 @param path modules are added to this path
824 pmanipulate = register_module('ParticleListManipulator')
825 pmanipulate.set_name(
'PListMerger_' + outputListName)
826 pmanipulate.param(
'outputListName', outputListName)
827 pmanipulate.param(
'inputListNames', inputListNames)
828 pmanipulate.param(
'variable', variable)
829 pmanipulate.param(
'preferLowest', preferLowest)
830 pmanipulate.param(
'writeOut', writeOut)
831 pmanipulate.param(
'ignoreMotherFlavor', ignoreMotherFlavor)
832 path.add_module(pmanipulate)
835def fillSignalSideParticleList(outputListName, decayString, path):
837 This function should only be used in the ROE path, that
is a path
838 that
is executed
for each ROE object
in the DataStore.
840 Example: fillSignalSideParticleList(
'gamma:sig',
'B0 -> K*0 ^gamma', roe_path)
842 Function will create a ParticleList
with name
'gamma:sig' which will be filled
843 with the existing photon Particle, being the second daughter of the B0 candidate
844 to which the ROE object has to be related.
846 @param ouputListName name of the created ParticleList
847 @param decayString specify Particle to be added to the ParticleList
850 pload = register_module('SignalSideParticleListCreator')
851 pload.set_name(
'SSParticleList_' + outputListName)
852 pload.param(
'particleListName', outputListName)
853 pload.param(
'decayString', decayString)
854 path.add_module(pload)
857def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False,
858 loadPhotonsFromKLM=False):
860 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
861 loads them to the ``StoreArray<Particle>``
and fills the ParticleLists.
863 The multiple ParticleLists
with their own selection criteria are specified
864 via list tuples (decayString, cut),
for example
866 .. code-block:: python
868 kaons = (
'K+:mykaons',
'kaonID>0.1')
869 pions = (
'pi+:mypions',
'pionID>0.1')
870 fillParticleLists([kaons, pions], path=mypath)
872 If you are unsure what selection you want, you might like to see the
873 :doc:`StandardParticles` functions.
875 The type of the particles to be loaded
is specified via the decayString module parameter.
876 The type of the ``mdst`` dataobject that
is used
as an input
is determined
from the type of
877 the particle. The following types of the particles can be loaded:
879 * charged final state particles (input ``mdst`` type = Tracks)
880 - e+, mu+, pi+, K+, p, deuteron (
and charge conjugated particles)
882 * neutral final state particles
883 -
"gamma" (input ``mdst`` type = ECLCluster)
884 -
"K_S0",
"Lambda0" (input ``mdst`` type = V0)
885 -
"K_L0" (input ``mdst`` type = KLMCluster
or ECLCluster)
888 For
"K_S0" and "Lambda0" you must specify the daughter ordering.
890 For example, to load V0s
as :math:`\\Lambda^0\\to p^+\\pi^-` decays
from V0s:
892 .. code-block:: python
894 v0lambdas = (
'Lambda0 -> p+ pi-',
'0.9 < M < 1.3')
895 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
898 Gammas can also be loaded
from KLMClusters by explicitly setting the
899 parameter ``loadPhotonsFromKLM`` to
True. However, this should only be
900 done
in selected use-cases
and the effect should be studied carefully.
903 For
"K_L0" it
is now possible to load
from ECLClusters, to revert to
904 the old (Belle) behavior, you can require ``
'isFromKLM > 0'``.
906 .. code-block:: python
908 klongs = (
'K_L0',
'isFromKLM > 0')
909 fillParticleLists([kaons, pions, klongs], path=mypath)
911 * Charged kinks final state particles (input ``mdst`` type = Kink)
914 To reconstruct charged particle kink you must specify the daughter.
916 For example, to load Kinks
as :math:`K^- \\to \\pi^-\\pi^0` decays
from Kinks:
918 .. code-block:: python
920 kinkKaons = (
'K- -> pi-', yourCut)
921 fillParticleLists([kaons, pions, v0lambdas, kinkKaons], path=mypath)
925 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
926 The decay string determines the type of Particle
927 and the name of the ParticleList.
928 If the input MDST type
is V0 the whole
929 decay chain needs to be specified, so that
930 the user decides
and controls the daughters
931 ' order (e.g. ``K_S0 -> pi+ pi-``).
932 If the input MDST type is Kink the decay chain needs to be specified
933 with only one daughter (e.g. ``K- -> pi-``).
934 The cut
is the selection criteria
935 to be added to the ParticleList. It can be an empty string.
936 writeOut (bool): whether RootOutput module should save the created ParticleList
937 path (basf2.Path): modules are added to this path
938 enforceFitHypothesis (bool): If true, Particles will be created only
for the tracks which have been fitted
939 using a mass hypothesis of the exact type passed to fillParticleLists().
940 If enforceFitHypothesis
is False (the default) the next closest fit hypothesis
941 in terms of mass difference will be used
if the fit using exact particle
942 type
is not available.
943 loadPhotonsFromKLM (bool): If true, photon candidates will be created
from KLMClusters
as well.
946 pload = register_module('ParticleLoader')
947 pload.set_name(
'ParticleLoader_' +
'PLists')
948 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
949 pload.param(
'writeOut', writeOut)
950 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
951 path.add_module(pload)
953 from ROOT
import Belle2
955 for decayString, cut
in decayStringsWithCuts:
956 if not decayDescriptor.init(decayString):
957 raise ValueError(
"Invalid decay string")
959 if decayDescriptor.getNDaughters() > 0:
964 if (decayDescriptor.getNDaughters() == 1) & (decayDescriptor.getMother().getLabel() !=
'kink'):
965 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':kink',
967 if (decayDescriptor.getNDaughters() > 1) & (decayDescriptor.getMother().getLabel() !=
'V0'):
968 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
969 elif decayDescriptor.getMother().getLabel() !=
'all':
972 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
976 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
978 if decayString.startswith(
"gamma"):
981 if not loadPhotonsFromKLM:
982 applyCuts(decayString,
'isFromECL', path)
985def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False,
986 loadPhotonsFromKLM=False):
988 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
989 loads them to the StoreArray<Particle>
and fills the ParticleList.
992 the :doc:`StandardParticles` functions.
994 The type of the particles to be loaded
is specified via the decayString module parameter.
995 The type of the ``mdst`` dataobject that
is used
as an input
is determined
from the type of
996 the particle. The following types of the particles can be loaded:
998 * charged final state particles (input ``mdst`` type = Tracks)
999 - e+, mu+, pi+, K+, p, deuteron (
and charge conjugated particles)
1001 * neutral final state particles
1002 -
"gamma" (input ``mdst`` type = ECLCluster)
1003 -
"K_S0",
"Lambda0" (input ``mdst`` type = V0)
1004 -
"K_L0" (input ``mdst`` type = KLMCluster
or ECLCluster)
1007 For
"K_S0" and "Lambda0" you must specify the daughter ordering.
1009 For example, to load V0s
as :math:`\\Lambda^0\\to p^+\\pi^-` decays
from V0s:
1011 .. code-block:: python
1013 fillParticleList(
'Lambda0 -> p+ pi-',
'0.9 < M < 1.3', path=mypath)
1016 Gammas can also be loaded
from KLMClusters by explicitly setting the
1017 parameter ``loadPhotonsFromKLM`` to
True. However, this should only be
1018 done
in selected use-cases
and the effect should be studied carefully.
1021 For
"K_L0" it
is now possible to load
from ECLClusters, to revert to
1022 the old (Belle) behavior, you can require ``
'isFromKLM > 0'``.
1024 .. code-block:: python
1026 fillParticleList(
'K_L0',
'isFromKLM > 0', path=mypath)
1028 * Charged kinks final state particles (input ``mdst`` type = Kink)
1031 To reconstruct charged particle kink you must specify the daughter.
1033 For example, to load Kinks
as :math:`K^- \\to \\pi^-\\pi^0` decays
from Kinks:
1035 .. code-block:: python
1037 fillParticleList(
'K- -> pi-', yourCut, path=mypath)
1041 decayString (str): Type of Particle
and determines the name of the ParticleList.
1042 If the input MDST type
is V0 the whole decay chain needs to be specified, so that
1043 the user decides
and controls the daughters
' order (e.g. ``K_S0 -> pi+ pi-``).
1044 If the input MDST type is Kink the decay chain needs to be specified
1045 with only one daughter (e.g. ``K- -> pi-``).
1046 cut (str): Particles need to
pass these selection criteria to be added to the ParticleList
1047 writeOut (bool): whether RootOutput module should save the created ParticleList
1048 path (basf2.Path): modules are added to this path
1049 enforceFitHypothesis (bool): If true, Particles will be created only
for the tracks which have been fitted
1050 using a mass hypothesis of the exact type passed to fillParticleLists().
1051 If enforceFitHypothesis
is False (the default) the next closest fit hypothesis
1052 in terms of mass difference will be used
if the fit using exact particle
1053 type
is not available.
1054 loadPhotonsFromKLM (bool): If true, photon candidates will be created
from KLMClusters
as well.
1057 pload = register_module('ParticleLoader')
1058 pload.set_name(
'ParticleLoader_' + decayString)
1059 pload.param(
'decayStrings', [decayString])
1060 pload.param(
'writeOut', writeOut)
1061 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1062 path.add_module(pload)
1065 from ROOT
import Belle2
1067 if not decayDescriptor.init(decayString):
1068 raise ValueError(
"Invalid decay string")
1069 if decayDescriptor.getNDaughters() > 0:
1074 if (decayDescriptor.getNDaughters() == 1) & (decayDescriptor.getMother().getLabel() !=
'kink'):
1075 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':kink',
1077 if (decayDescriptor.getNDaughters() > 1) & (decayDescriptor.getMother().getLabel() !=
'V0'):
1078 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut,
1080 elif decayDescriptor.getMother().getLabel() !=
'all':
1083 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1087 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1089 if decayString.startswith(
"gamma"):
1092 if not loadPhotonsFromKLM:
1093 applyCuts(decayString,
'isFromECL', path)
1096def fillParticleListWithTrackHypothesis(decayString,
1100 enforceFitHypothesis=False,
1103 As fillParticleList, but if used
for a charged FSP, loads the particle
with the requested hypothesis
if available
1105 @param decayString specifies type of Particles
and determines the name of the ParticleList
1106 @param cut Particles need to
pass these selection criteria to be added to the ParticleList
1107 @param hypothesis the PDG code of the desired track hypothesis
1108 @param writeOut whether RootOutput module should save the created ParticleList
1109 @param enforceFitHypothesis If true, Particles will be created only
for the tracks which have been fitted
1110 using a mass hypothesis of the exact type passed to fillParticleLists().
1111 If enforceFitHypothesis
is False (the default) the next closest fit hypothesis
1112 in terms of mass difference will be used
if the fit using exact particle
1113 type
is not available.
1114 @param path modules are added to this path
1117 pload = register_module('ParticleLoader')
1118 pload.set_name(
'ParticleLoader_' + decayString)
1119 pload.param(
'decayStrings', [decayString])
1120 pload.param(
'trackHypothesis', hypothesis)
1121 pload.param(
'writeOut', writeOut)
1122 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1123 path.add_module(pload)
1125 from ROOT
import Belle2
1127 if not decayDescriptor.init(decayString):
1128 raise ValueError(
"Invalid decay string")
1129 if decayDescriptor.getMother().getLabel() !=
'all':
1132 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1136 applyCuts(decayString, cut, path)
1139def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
1141 Creates photon Particle object for each e+e- combination
in the V0 StoreArray.
1144 You must specify the daughter ordering.
1146 .. code-block:: python
1148 fillConvertedPhotonsList(
'gamma:converted -> e+ e-',
'', path=mypath)
1151 decayString (str): Must be gamma to an e+e- pair. You must specify the daughter ordering.
1152 Will also determine the name of the particleList.
1153 cut (str): Particles need to
pass these selection criteria to be added to the ParticleList
1154 writeOut (bool): whether RootOutput module should save the created ParticleList
1155 path (basf2.Path): modules are added to this path
1161 B2ERROR(
'For Belle converted photons are available in the pre-defined list "gamma:v0mdst".')
1163 pload = register_module(
'ParticleLoader')
1164 pload.set_name(
'ParticleLoader_' + decayString)
1165 pload.param(
'decayStrings', [decayString])
1166 pload.param(
'addDaughters',
True)
1167 pload.param(
'writeOut', writeOut)
1168 path.add_module(pload)
1170 from ROOT
import Belle2
1172 if not decayDescriptor.init(decayString):
1173 raise ValueError(
"Invalid decay string")
1174 if decayDescriptor.getMother().getLabel() !=
'V0':
1177 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1181 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1184def fillParticleListFromROE(decayString,
1187 sourceParticleListName='',
1192 Creates Particle object for each ROE of the desired type found
in the
1193 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
1194 and fills the ParticleList. If useMissing
is True, then the missing
1195 momentum
is used instead of ROE.
1197 The type of the particles to be loaded
is specified via the decayString module parameter.
1199 @param decayString specifies type of Particles
and determines the name of the ParticleList.
1200 Source ROEs can be taken
as a daughter list,
for example:
1201 'B0:tagFromROE -> B0:signal'
1202 @param cut Particles need to
pass these selection criteria to be added to the ParticleList
1203 @param maskName Name of the ROE mask to use
1204 @param sourceParticleListName Use related ROEs to this particle list
as a source
1205 @param useMissing Use missing momentum instead of ROE momentum
1206 @param writeOut whether RootOutput module should save the created ParticleList
1207 @param path modules are added to this path
1210 pload = register_module('ParticleLoader')
1211 pload.set_name(
'ParticleLoader_' + decayString)
1212 pload.param(
'decayStrings', [decayString])
1213 pload.param(
'writeOut', writeOut)
1214 pload.param(
'roeMaskName', maskName)
1215 pload.param(
'useMissing', useMissing)
1216 pload.param(
'sourceParticleListName', sourceParticleListName)
1217 pload.param(
'useROEs',
True)
1218 path.add_module(pload)
1220 from ROOT
import Belle2
1222 if not decayDescriptor.init(decayString):
1223 raise ValueError(
"Invalid decay string")
1227 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1230def fillParticleListFromDummy(decayString,
1233 treatAsInvisible=True,
1237 Creates a ParticleList and fills it
with dummy Particles. For self-conjugated Particles one dummy
1238 Particle
is created,
for Particles that are
not self-conjugated one Particle
and one anti-Particle
is
1239 created. The four-momentum
is set to zero.
1241 The type of the particles to be loaded
is specified via the decayString module parameter.
1243 @param decayString specifies type of Particles
and determines the name of the ParticleList
1244 @param mdstIndex sets the mdst index of Particles
1245 @param covMatrix sets the value of the diagonal covariance matrix of Particles
1246 @param treatAsInvisible whether treeFitter should treat the Particles
as invisible
1247 @param writeOut whether RootOutput module should save the created ParticleList
1248 @param path modules are added to this path
1251 pload = register_module('ParticleLoader')
1252 pload.set_name(
'ParticleLoader_' + decayString)
1253 pload.param(
'decayStrings', [decayString])
1254 pload.param(
'useDummy',
True)
1255 pload.param(
'dummyMDSTIndex', mdstIndex)
1256 pload.param(
'dummyCovMatrix', covMatrix)
1257 pload.param(
'dummyTreatAsInvisible', treatAsInvisible)
1258 pload.param(
'writeOut', writeOut)
1259 path.add_module(pload)
1262def fillParticleListFromMC(decayString,
1265 skipNonPrimaryDaughters=False,
1268 skipNonPrimary=False,
1271 Creates Particle object for each MCParticle of the desired type found
in the StoreArray<MCParticle>,
1272 loads them to the StoreArray<Particle>
and fills the ParticleList.
1274 The type of the particles to be loaded
is specified via the decayString module parameter.
1276 @param decayString specifies type of Particles
and determines the name of the ParticleList
1277 @param cut Particles need to
pass these selection criteria to be added to the ParticleList
1278 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore
and
1279 sets mother-daughter relations
1280 @param skipNonPrimaryDaughters
if true, skip non primary daughters, useful to study final state daughter particles
1281 @param writeOut whether RootOutput module should save the created ParticleList
1282 @param path modules are added to this path
1283 @param skipNonPrimary
if true, skip non primary particle
1284 @param skipInitial
if true, skip initial particles
1287 pload = register_module('ParticleLoader')
1288 pload.set_name(
'ParticleLoader_' + decayString)
1289 pload.param(
'decayStrings', [decayString])
1290 pload.param(
'addDaughters', addDaughters)
1291 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1292 pload.param(
'writeOut', writeOut)
1293 pload.param(
'useMCParticles',
True)
1294 pload.param(
'skipNonPrimary', skipNonPrimary)
1295 pload.param(
'skipInitial', skipInitial)
1296 path.add_module(pload)
1298 from ROOT
import Belle2
1300 if not decayDescriptor.init(decayString):
1301 raise ValueError(
"Invalid decay string")
1305 applyCuts(decayString, cut, path)
1308def fillParticleListsFromMC(decayStringsWithCuts,
1310 skipNonPrimaryDaughters=False,
1313 skipNonPrimary=False,
1316 Creates Particle object for each MCParticle of the desired type found
in the StoreArray<MCParticle>,
1317 loads them to the StoreArray<Particle>
and fills the ParticleLists.
1319 The types of the particles to be loaded are specified via the (decayString, cut) tuples given
in a list.
1322 .. code-block:: python
1324 kaons = (
'K+:gen',
'')
1325 pions = (
'pi+:gen',
'pionID>0.1')
1326 fillParticleListsFromMC([kaons, pions], path=mypath)
1329 Daughters of ``Lambda0`` are
not primary, but ``Lambda0``
is not final state particle.
1330 Thus, when one reconstructs a particle
from ``Lambda0``, that
is created
with
1331 ``addDaughters=
True``
and ``skipNonPrimaryDaughters=
True``, the particle always has ``isSignal==0``.
1332 Please set options
for ``Lambda0`` to use MC-matching variables properly
as follows,
1333 ``addDaughters=
True``
and ``skipNonPrimaryDaughters=
False``.
1335 @param decayString specifies type of Particles
and determines the name of the ParticleList
1336 @param cut Particles need to
pass these selection criteria to be added to the ParticleList
1337 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore
and
1338 sets mother-daughter relations
1339 @param skipNonPrimaryDaughters
if true, skip non primary daughters, useful to study final state daughter particles
1340 @param writeOut whether RootOutput module should save the created ParticleList
1341 @param path modules are added to this path
1342 @param skipNonPrimary
if true, skip non primary particle
1343 @param skipInitial
if true, skip initial particles
1346 pload = register_module('ParticleLoader')
1347 pload.set_name(
'ParticleLoader_' +
'PLists')
1348 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
1349 pload.param(
'addDaughters', addDaughters)
1350 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1351 pload.param(
'writeOut', writeOut)
1352 pload.param(
'useMCParticles',
True)
1353 pload.param(
'skipNonPrimary', skipNonPrimary)
1354 pload.param(
'skipInitial', skipInitial)
1355 path.add_module(pload)
1357 from ROOT
import Belle2
1359 for decayString, cut
in decayStringsWithCuts:
1360 if not decayDescriptor.init(decayString):
1361 raise ValueError(
"Invalid decay string")
1365 applyCuts(decayString, cut, path)
1368def fillParticleListFromChargedCluster(outputParticleList,
1371 useOnlyMostEnergeticECLCluster=True,
1375 Creates the Particle object from ECLCluster
and KLMCluster that are being matched
with the Track of inputParticleList.
1377 @param outputParticleList The output ParticleList. Only neutral final state particles are supported.
1378 @param inputParticleList The input ParticleList that
is required to have the relation to the Track object.
1379 @param cut Particles need to
pass these selection criteria to be added to the ParticleList
1380 @param useOnlyMostEnergeticECLCluster If
True, only the most energetic ECLCluster among ones that are matched
with the Track
is
1381 used. If
False, all matched ECLClusters are loaded. The default
is True. Regardless of
1382 this option, the KLMCluster
is loaded.
1383 @param writeOut whether RootOutput module should save the created ParticleList
1384 @param path modules are added to this path
1387 pload = register_module('ParticleLoader')
1388 pload.set_name(
'ParticleLoader_' + outputParticleList)
1390 pload.param(
'decayStrings', [outputParticleList])
1391 pload.param(
'sourceParticleListName', inputParticleList)
1392 pload.param(
'writeOut', writeOut)
1393 pload.param(
'loadChargedCluster',
True)
1394 pload.param(
'useOnlyMostEnergeticECLCluster', useOnlyMostEnergeticECLCluster)
1395 path.add_module(pload)
1399 applyCuts(outputParticleList, cut, path)
1402def extractParticlesFromROE(particleLists,
1403 signalSideParticleList=None,
1408 Extract Particle objects that belong to the Rest-Of-Events and fill them into the ParticleLists.
1409 The types of the particles other than those specified by ``particleLists`` are
not stored.
1410 If one creates a ROE
with ``fillWithMostLikely=
True`` via `buildRestOfEvent`,
for example,
1411 one should create particleLists
for not only ``pi+``, ``gamma``, ``K_L0`` but also other charged final state particles.
1413 When one calls the function
in the main path, one has to set the argument ``signalSideParticleList``
and the signal side
1414 ParticleList must have only one candidate.
1416 .. code-block:: python
1418 buildRestOfEvent(
'B0:sig', fillWithMostLikely=
True, path=mypath)
1420 roe_path = create_path()
1421 deadEndPath = create_path()
1422 signalSideParticleFilter(
'B0:sig',
'', roe_path, deadEndPath)
1424 plists = [
'%s:in_roe' % ptype
for ptype
in [
'pi+',
'gamma',
'K_L0',
'K+',
'p+',
'e+',
'mu+']]
1425 extractParticlesFromROE(plists, maskName=
'all', path=roe_path)
1429 mypath.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
1431 rankByLowest(
'B0:sig',
'deltaE', numBest=1, path=mypath)
1432 extractParticlesFromROE(plists, signalSideParticleList=
'B0:sig', maskName=
'all', path=mypath)
1437 @param particleLists (str
or list(str)) Name of output ParticleLists
1438 @param signalSideParticleList (str) Name of signal side ParticleList
1439 @param maskName (str) Name of the ROE mask to be applied on Particles
1440 @param writeOut (bool) whether RootOutput module should save the created ParticleList
1441 @param path (basf2.Path) modules are added to this path
1444 if isinstance(particleLists, str):
1445 particleLists = [particleLists]
1447 pext = register_module(
'ParticleExtractorFromROE')
1448 pext.set_name(
'ParticleExtractorFromROE_' +
'_'.join(particleLists))
1449 pext.param(
'outputListNames', particleLists)
1450 if signalSideParticleList
is not None:
1451 pext.param(
'signalSideParticleListName', signalSideParticleList)
1452 pext.param(
'maskName', maskName)
1453 pext.param(
'writeOut', writeOut)
1454 path.add_module(pext)
1457def applyCuts(list_name, cut, path):
1459 Removes particle candidates from ``list_name`` that do
not pass ``cut``
1460 (given selection criteria).
1463 require energetic pions safely inside the cdc
1465 .. code-block:: python
1467 applyCuts(
"pi+:mypions",
"[E > 2] and thetaInCDCAcceptance", path=mypath)
1470 You must use square braces ``[``
and ``]``
for conditional statements.
1473 list_name (str): input ParticleList name
1474 cut (str): Candidates that do
not pass these selection criteria are removed
from the ParticleList
1475 path (basf2.Path): modules are added to this path
1478 pselect = register_module('ParticleSelector')
1479 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
1480 pselect.param(
'decayString', list_name)
1481 pselect.param(
'cut', cut)
1482 path.add_module(pselect)
1485def applyEventCuts(cut, path, metavariables=None):
1487 Removes events that do not pass the ``cut`` (given selection criteria).
1490 continuum events (
in mc only)
with more than 5 tracks
1492 .. code-block:: python
1494 applyEventCuts(
"[nTracks > 5] and [isContinuumEvent], path=mypath)
1497 Only event-based variables are allowed in this function
1498 and only square brackets ``[``
and ``]``
for conditional statements.
1501 cut (str): Events that do
not pass these selection criteria are skipped
1502 path (basf2.Path): modules are added to this path
1503 metavariables (list(str)): List of meta variables to be considered
in decomposition of cut
1507 from variables
import variables
1509 def find_vars(t: tuple, var_list: list, meta_list: list) ->
None:
1510 """ Recursive helper function to find variable names """
1511 if not isinstance(t, tuple):
1513 if t[0] == b2parser.B2ExpressionParser.node_types[
'IdentifierNode']:
1516 if t[0] == b2parser.B2ExpressionParser.node_types[
'FunctionNode']:
1517 meta_list.append(list(t[1:]))
1520 if isinstance(i, tuple):
1521 find_vars(i, var_list, meta_list)
1523 def check_variable(var_list: list, metavar_ids: list) ->
None:
1524 for var_string
in var_list:
1526 orig_name = variables.resolveAlias(var_string)
1527 if orig_name != var_string:
1530 find_vars(
b2parser.parse(orig_name), var_list_temp, meta_list_temp)
1532 check_variable(var_list_temp, metavar_ids)
1533 check_meta(meta_list_temp, metavar_ids)
1536 var = variables.getVariable(var_string)
1537 if event_var_id
not in var.description:
1538 B2ERROR(f
'Variable {var_string} is not an event-based variable! "\
1539 "Please check your inputs to the applyEventCuts method!')
1541 def check_meta(meta_list: list, metavar_ids: list) ->
None:
1542 for meta_string_list
in meta_list:
1544 while meta_string_list[0]
in metavar_ids:
1546 meta_string_list.pop(0)
1547 for meta_string
in meta_string_list[0].split(
","):
1548 find_vars(
b2parser.parse(meta_string), var_list_temp, meta_string_list)
1549 if len(meta_string_list) > 0:
1550 meta_string_list.pop(0)
1551 if len(meta_string_list) == 0:
1553 if len(meta_string_list) > 1:
1554 meta_list += meta_string_list[1:]
1555 if isinstance(meta_string_list[0], list):
1556 meta_string_list = [element
for element
in meta_string_list[0]]
1558 check_variable(var_list_temp, metavar_ids)
1560 if len(meta_string_list) == 0:
1562 elif len(meta_string_list) == 1:
1563 var = variables.getVariable(meta_string_list[0])
1565 var = variables.getVariable(meta_string_list[0], meta_string_list[1].split(
","))
1567 if event_var_id
in var.description:
1570 B2ERROR(f
'Variable {var.name} is not an event-based variable! Please check your inputs to the applyEventCuts method!')
1572 event_var_id =
'[Eventbased]'
1573 metavar_ids = [
'formula',
'abs',
1577 'exp',
'log',
'log10',
1581 metavar_ids += metavariables
1585 find_vars(
b2parser.parse(cut), var_list=var_list, meta_list=meta_list)
1587 if len(var_list) == 0
and len(meta_list) == 0:
1588 B2WARNING(f
'Cut string "{cut}" has no variables for applyEventCuts helper function!')
1590 check_variable(var_list, metavar_ids)
1591 check_meta(meta_list, metavar_ids)
1593 eselect = register_module(
'VariableToReturnValue')
1594 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1595 path.add_module(eselect)
1596 empty_path = create_path()
1597 eselect.if_value(
'<1', empty_path)
1600def reconstructDecay(decayString,
1605 candidate_limit=None,
1606 ignoreIfTooManyCandidates=True,
1607 chargeConjugation=True,
1608 allowChargeViolation=False):
1610 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1611 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+`
or :code:`B+ -> anti-D0 pi+`, ... All possible
1612 combinations are created (particles are used only once per candidate)
and combinations that
pass the specified selection
1613 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay
is reconstructed
as well
1614 (meaning that the charge conjugated mother list
is created
as well) but this can be deactivated.
1616 One can use an ``@``-sign to mark a particle
as unspecified
for inclusive analyses,
1617 e.g.
in a DecayString: :code:`
'@Xsd -> K+ pi-'`.
1619 .. seealso:: :ref:`Marker_of_unspecified_particle`
1622 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1623 Therefore,
if you combine two
or more identical particles
in the decay chain you should
not expect to see the same
1624 distribution
for the daughter kinematics
as they may be sorted by geometry, momentum etc.
1626 For example,
in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are
not identical.
1627 This can be solved by manually randomising the lists before combining.
1631 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1632 * `Identical particles
in decay chain <https://questions.belle2.org/question/5724/identical-particles-
in-decay-chain/>`_
1634 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1635 (
from the DecayString the mother
and daughter ParticleLists are determined)
1636 @param cut created (mother) Particles are added to the mother ParticleList
if they
1637 pass give cuts (
in VariableManager style)
and rejected otherwise
1638 @param dmID user specified decay mode identifier
1639 @param writeOut whether RootOutput module should save the created ParticleList
1640 @param path modules are added to this path
1641 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1642 the number of candidates
is exceeded a Warning will be
1644 By default, all these candidates will be removed
and event will be ignored.
1645 This behaviour can be changed by \
'ignoreIfTooManyCandidates\' flag.
1646 If no value is given the amount
is limited to a sensible
1647 default. A value <=0 will disable this limit
and can
1648 cause huge memory amounts so be careful.
1649 @param ignoreIfTooManyCandidates whether event should be ignored
or not if number of reconstructed
1650 candidates reaches limit. If event
is ignored, no candidates are reconstructed,
1651 otherwise, number of candidates
in candidate_limit
is reconstructed.
1652 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed
as well (on by default)
1653 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1656 pmake = register_module('ParticleCombiner')
1657 pmake.set_name(
'ParticleCombiner_' + decayString)
1658 pmake.param(
'decayString', decayString)
1659 pmake.param(
'cut', cut)
1660 pmake.param(
'decayMode', dmID)
1661 pmake.param(
'writeOut', writeOut)
1662 if candidate_limit
is not None:
1663 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1664 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1665 pmake.param(
'chargeConjugation', chargeConjugation)
1666 pmake.param(
"allowChargeViolation", allowChargeViolation)
1667 path.add_module(pmake)
1670def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1672 Creates a new Particle as the combination of all Particles
from all
1673 provided inputParticleLists. However, each particle
is used only once
1674 (even
if duplicates are provided)
and the combination has to
pass the
1675 specified selection criteria to be saved
in the newly created (mother)
1678 @param inputParticleLists List of input particle lists which are combined to the new Particle
1679 @param outputList Name of the particle combination created
with this module
1680 @param cut created (mother) Particle
is added to the mother ParticleList
if it passes
1681 these given cuts (
in VariableManager style)
and is rejected otherwise
1682 @param writeOut whether RootOutput module should save the created ParticleList
1683 @param path module
is added to this path
1686 pmake = register_module('AllParticleCombiner')
1687 pmake.set_name(
'AllParticleCombiner_' + outputList)
1688 pmake.param(
'inputListNames', inputParticleLists)
1689 pmake.param(
'outputListName', outputList)
1690 pmake.param(
'cut', cut)
1691 pmake.param(
'writeOut', writeOut)
1692 path.add_module(pmake)
1695def reconstructMissingKlongDecayExpert(decayString,
1702 Creates a list of K_L0's and of B -> K_L0 + X, with X being a fully-reconstructed state.
1703 The K_L0 momentum is determined
from kinematic constraints of the two-body B decay into K_L0
and X
1705 @param decayString DecayString specifying what kind of the decay should be reconstructed
1706 (
from the DecayString the mother
and daughter ParticleLists are determined)
1707 @param cut Particles are added to the K_L0
and B ParticleList
if the B candidates
1708 pass the given cuts (
in VariableManager style)
and rejected otherwise
1709 @param dmID user specified decay mode identifier
1710 @param writeOut whether RootOutput module should save the created ParticleList
1711 @param path modules are added to this path
1712 @param recoList suffix appended to original K_L0
and B ParticleList that identify the newly created K_L0
and B lists
1715 pcalc = register_module('KlongMomentumCalculatorExpert')
1716 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1717 pcalc.param(
'decayString', decayString)
1718 pcalc.param(
'writeOut', writeOut)
1719 pcalc.param(
'recoList', recoList)
1720 path.add_module(pcalc)
1722 rmake = register_module(
'KlongDecayReconstructorExpert')
1723 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1724 rmake.param(
'decayString', decayString)
1725 rmake.param(
'cut', cut)
1726 rmake.param(
'decayMode', dmID)
1727 rmake.param(
'writeOut', writeOut)
1728 rmake.param(
'recoList', recoList)
1729 path.add_module(rmake)
1732def setBeamConstrainedMomentum(particleList, decayStringTarget, decayStringDaughters, path=None):
1734 Replace the four-momentum of the target Particle by p(beam) - p(selected daughters).
1735 The momentum of the mother Particle will not be changed.
1737 @param particleList mother Particlelist
1738 @param decayStringTarget DecayString specifying the target particle whose momentum
1740 @param decayStringDaughters DecayString specifying the daughter particles used to replace
1741 the momentum of the target particle by p(beam)-p(daughters)
1744 mod = register_module('ParticleMomentumUpdater')
1745 mod.set_name(
'ParticleMomentumUpdater' + particleList)
1746 mod.param(
'particleList', particleList)
1747 mod.param(
'decayStringTarget', decayStringTarget)
1748 mod.param(
'decayStringDaughters', decayStringDaughters)
1749 path.add_module(mod)
1752def updateKlongKinematicsExpert(particleList,
1756 Calculates and updates the kinematics of B->K_L0 + something
else with same method
as
1757 `reconstructMissingKlongDecayExpert`. This helps to revert the kinematics after the vertex fitting.
1759 @param particleList input ParticleList of B meson that decays to K_L0 + X
1760 @param writeOut whether RootOutput module should save the ParticleList
1761 @param path modules are added to this path
1764 mod = register_module('KlongMomentumUpdaterExpert')
1765 mod.set_name(
'KlongMomentumUpdaterExpert_' + particleList)
1766 mod.param(
'listName', particleList)
1767 mod.param(
'writeOut', writeOut)
1768 path.add_module(mod)
1771def replaceMass(replacerName, particleLists=None, pdgCode=22, path=None):
1773 replaces the mass of the particles inside the given particleLists
1774 with the invariant mass of the particle corresponding to the given pdgCode.
1776 @param particleLists new ParticleList filled
with copied Particles
1777 @param pdgCode PDG code
for mass reference
1778 @param path modules are added to this path
1781 if particleLists
is None:
1785 pmassupdater = register_module(
'ParticleMassUpdater')
1786 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1787 pmassupdater.param(
'particleLists', particleLists)
1788 pmassupdater.param(
'pdgCode', pdgCode)
1789 path.add_module(pmassupdater)
1792def reconstructRecoil(decayString,
1797 candidate_limit=None,
1798 allowChargeViolation=False):
1800 Creates new Particles that recoil against the input particles.
1802 For example the decay string M -> D1 D2 D3 will:
1803 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1804 - Particles D1, D2, D3 will be appended
as daughters to M
1805 - the 4-momentum of the mother Particle M
is given by
1806 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1808 @param decayString DecayString specifying what kind of the decay should be reconstructed
1809 (
from the DecayString the mother
and daughter ParticleLists are determined)
1810 @param cut created (mother) Particles are added to the mother ParticleList
if they
1811 pass give cuts (
in VariableManager style)
and rejected otherwise
1812 @param dmID user specified decay mode identifier
1813 @param writeOut whether RootOutput module should save the created ParticleList
1814 @param path modules are added to this path
1815 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1816 the number of candidates
is exceeded no candidate will be
1817 reconstructed
for that event
and a Warning will be
1819 If no value
is given the amount
is limited to a sensible
1820 default. A value <=0 will disable this limit
and can
1821 cause huge memory amounts so be careful.
1822 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1825 pmake = register_module('ParticleCombiner')
1826 pmake.set_name(
'ParticleCombiner_' + decayString)
1827 pmake.param(
'decayString', decayString)
1828 pmake.param(
'cut', cut)
1829 pmake.param(
'decayMode', dmID)
1830 pmake.param(
'writeOut', writeOut)
1831 pmake.param(
'recoilParticleType', 1)
1832 if candidate_limit
is not None:
1833 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1834 pmake.param(
'allowChargeViolation', allowChargeViolation)
1835 path.add_module(pmake)
1838def reconstructRecoilDaughter(decayString,
1843 candidate_limit=None,
1844 allowChargeViolation=False):
1846 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1848 For example the decay string M -> D1 D2 D3 will:
1849 - create mother Particle M
for each unique combination of D1, D2, D3 Particles
1850 - Particles D1, D2, D3 will be appended
as daughters to M
1851 - the 4-momentum of the mother Particle M
is given by
1852 p(M) = p(D1) - Sum_i p(Di), where i>1
1854 @param decayString DecayString specifying what kind of the decay should be reconstructed
1855 (
from the DecayString the mother
and daughter ParticleLists are determined)
1856 @param cut created (mother) Particles are added to the mother ParticleList
if they
1857 pass give cuts (
in VariableManager style)
and rejected otherwise
1858 @param dmID user specified decay mode identifier
1859 @param writeOut whether RootOutput module should save the created ParticleList
1860 @param path modules are added to this path
1861 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1862 the number of candidates
is exceeded no candidate will be
1863 reconstructed
for that event
and a Warning will be
1865 If no value
is given the amount
is limited to a sensible
1866 default. A value <=0 will disable this limit
and can
1867 cause huge memory amounts so be careful.
1868 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1869 daughter
is actually the mother
1872 pmake = register_module('ParticleCombiner')
1873 pmake.set_name(
'ParticleCombiner_' + decayString)
1874 pmake.param(
'decayString', decayString)
1875 pmake.param(
'cut', cut)
1876 pmake.param(
'decayMode', dmID)
1877 pmake.param(
'writeOut', writeOut)
1878 pmake.param(
'recoilParticleType', 2)
1879 if candidate_limit
is not None:
1880 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1881 pmake.param(
'allowChargeViolation', allowChargeViolation)
1882 path.add_module(pmake)
1885def rankByHighest(particleList,
1889 allowMultiRank=False,
1891 overwriteRank=False,
1894 Ranks particles in the input list by the given variable (highest to lowest),
and stores an integer rank
for each Particle
1895 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1896 The list
is also sorted
from best to worst candidate
1897 (each charge, e.g. B+/B-, separately).
1898 This can be used to perform a best candidate selection by cutting on the corresponding rank value,
or by specifying
1899 a non-zero value
for 'numBest'.
1902 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1903 These variable names can become clunky, so it
's probably a good idea to set an alias.
1904 For example if you rank your B candidates by momentum,
1908 rankByHighest(
"B0:myCandidates",
"p", path=mypath)
1909 vm.addAlias(
"momentumRank",
"extraInfo(p_rank)")
1912 @param particleList The input ParticleList
1913 @param variable Variable to order Particles by.
1914 @param numBest If
not zero, only the $numBest Particles
in particleList
with rank <= numBest are kept.
1915 @param outputVariable Name
for the variable that will be created which contains the rank, Default
is '${variable}_rank'.
1916 @param allowMultiRank If true, candidates
with the same value will get the same rank.
1917 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1918 @param overwriteRank If true, the extraInfo of rank
is overwritten when the particle has already the extraInfo.
1919 @param path modules are added to this path
1922 bcs = register_module('BestCandidateSelection')
1923 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1924 bcs.param(
'particleList', particleList)
1925 bcs.param(
'variable', variable)
1926 bcs.param(
'numBest', numBest)
1927 bcs.param(
'outputVariable', outputVariable)
1928 bcs.param(
'allowMultiRank', allowMultiRank)
1929 bcs.param(
'cut', cut)
1930 bcs.param(
'overwriteRank', overwriteRank)
1931 path.add_module(bcs)
1934def rankByLowest(particleList,
1938 allowMultiRank=False,
1940 overwriteRank=False,
1943 Ranks particles in the input list by the given variable (lowest to highest),
and stores an integer rank
for each Particle
1944 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1945 The list
is also sorted
from best to worst candidate
1946 (each charge, e.g. B+/B-, separately).
1947 This can be used to perform a best candidate selection by cutting on the corresponding rank value,
or by specifying
1948 a non-zero value
for 'numBest'.
1951 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1952 These variable names can become clunky, so it
's probably a good idea to set an alias.
1953 For example if you rank your B candidates by :b2:var:`dM`,
1957 rankByLowest(
"B0:myCandidates",
"dM", path=mypath)
1958 vm.addAlias(
"massDifferenceRank",
"extraInfo(dM_rank)")
1961 @param particleList The input ParticleList
1962 @param variable Variable to order Particles by.
1963 @param numBest If
not zero, only the $numBest Particles
in particleList
with rank <= numBest are kept.
1964 @param outputVariable Name
for the variable that will be created which contains the rank, Default
is '${variable}_rank'.
1965 @param allowMultiRank If true, candidates
with the same value will get the same rank.
1966 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1967 @param overwriteRank If true, the extraInfo of rank
is overwritten when the particle has already the extraInfo.
1968 @param path modules are added to this path
1971 bcs = register_module('BestCandidateSelection')
1972 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1973 bcs.param(
'particleList', particleList)
1974 bcs.param(
'variable', variable)
1975 bcs.param(
'numBest', numBest)
1976 bcs.param(
'selectLowest',
True)
1977 bcs.param(
'allowMultiRank', allowMultiRank)
1978 bcs.param(
'outputVariable', outputVariable)
1979 bcs.param(
'cut', cut)
1980 bcs.param(
'overwriteRank', overwriteRank)
1981 path.add_module(bcs)
1984def applyRandomCandidateSelection(particleList, path=None):
1986 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1987 This
is done on a event-by-event basis.
1989 @param particleList ParticleList
for which the random candidate selection should be applied
1990 @param path module
is added to this path
1993 rcs = register_module('BestCandidateSelection')
1994 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1995 rcs.param(
'particleList', particleList)
1996 rcs.param(
'variable',
'random')
1997 rcs.param(
'selectLowest',
False)
1998 rcs.param(
'allowMultiRank',
False)
1999 rcs.param(
'numBest', 1)
2000 rcs.param(
'cut',
'')
2001 rcs.param(
'outputVariable',
'')
2002 path.add_module(rcs)
2007 Prints the contents of DataStore in the first event (
or a specific event number
or all events).
2008 Will list all objects
and arrays (including size).
2011 The command line tool: ``b2file-size``.
2014 eventNumber (int): Print the datastore only
for this event. The default
2015 (-1) prints only the first event, 0 means
print for all events (can produce large output)
2016 path (basf2.Path): the PrintCollections module
is added to this path
2019 This will
print a lot of output
if you
print it
for all events
and process many events.
2023 printDS = register_module('PrintCollections')
2024 printDS.param(
'printForEvent', eventNumber)
2025 path.add_module(printDS)
2028def printVariableValues(list_name, var_names, path):
2030 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
2032 @param list_name input ParticleList name
2033 @param var_names vector of variable names to be printed
2034 @param path modules are added to this path
2037 prlist = register_module('ParticlePrinter')
2038 prlist.set_name(
'ParticlePrinter_' + list_name)
2039 prlist.param(
'listName', list_name)
2040 prlist.param(
'fullPrint',
False)
2041 prlist.param(
'variables', var_names)
2042 path.add_module(prlist)
2045def printList(list_name, full, path):
2047 Prints the size and executes Particle->print() (
if full=
True)
2048 method
for all Particles
in given ParticleList. For debugging purposes.
2050 @param list_name input ParticleList name
2051 @param full execute Particle->print() method
for all Particles
2052 @param path modules are added to this path
2055 prlist = register_module('ParticlePrinter')
2056 prlist.set_name(
'ParticlePrinter_' + list_name)
2057 prlist.param(
'listName', list_name)
2058 prlist.param(
'fullPrint', full)
2059 path.add_module(prlist)
2062def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None, basketsize=1600,
2063 signalSideParticleList="", filenameSuffix="", useFloat=False, storeEventType=True,
2064 ignoreCommandLineOverride=False):
2066 Creates and fills a flat ntuple
with the specified variables
from the VariableManager.
2067 If a decayString
is provided, then there will be one entry per candidate (
for particle
in list of candidates).
2068 If an empty decayString
is provided, there will be one entry per event (useful
for trigger studies, etc).
2071 decayString (str): specifies type of Particles
and determines the name of the ParticleList
2072 variables (list(str)): the list of variables (which must be registered
in the VariableManager)
2073 treename (str): name of the ntuple tree
2074 filename (str): which
is used to store the variables
2075 path (basf2.Path): the basf2 path where the analysis
is processed
2076 basketsize (int): size of baskets
in the output ntuple
in bytes
2077 signalSideParticleList (str): The name of the signal-side ParticleList.
2078 Only valid
if the module
is called
in a for_each loop over the RestOfEvent.
2079 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2080 useFloat (bool): Use single precision (float) instead of double precision (double)
2081 for floating-point numbers.
2082 storeEventType (bool) :
if true, the branch __eventType__
is added
for the MC event type information.
2083 The information
is available
from MC16 on.
2084 ignoreCommandLineOverride (bool) :
if true, ignore override of file name via command line argument ``-o``.
2086 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2089 output = register_module('VariablesToNtuple')
2090 output.set_name(
'VariablesToNtuple_' + decayString)
2091 output.param(
'particleList', decayString)
2092 output.param(
'variables', variables)
2093 output.param(
'fileName', filename)
2094 output.param(
'treeName', treename)
2095 output.param(
'basketSize', basketsize)
2096 output.param(
'signalSideParticleList', signalSideParticleList)
2097 output.param(
'fileNameSuffix', filenameSuffix)
2098 output.param(
'useFloat', useFloat)
2099 output.param(
'storeEventType', storeEventType)
2100 output.param(
'ignoreCommandLineOverride', ignoreCommandLineOverride)
2101 path.add_module(output)
2107 filename='ntuple.root',
2110 prefixDecayString=False,
2112 ignoreCommandLineOverride=False):
2114 Creates and fills a flat ntuple
with the specified variables
from the VariableManager
2117 decayString (str): specifies type of Particles
and determines the name of the ParticleList
2118 variables (list(tuple))): variables + binning which must be registered
in the VariableManager
2119 variables_2d (list(tuple)): pair of variables + binning
for each which must be registered
in the VariableManager
2120 filename (str): which
is used to store the variables
2121 path (basf2.Path): the basf2 path where the analysis
is processed
2122 directory (str): directory inside the output file where the histograms should be saved.
2123 Useful
if you want to have different histograms
in the same file to separate them.
2124 prefixDecayString (bool): If
True the decayString will be prepended to the directory name to allow
for more
2125 programmatic naming of the structure
in the file.
2126 filenameSuffix (str): suffix to be appended to the filename before ``.root``.
2127 ignoreCommandLineOverride (bool) :
if true, ignore override of file name via command line argument ``-o``.
2129 .. tip:: The output filename can be overridden using the ``-o`` argument of basf2.
2132 if variables_2d
is None:
2134 output = register_module(
'VariablesToHistogram')
2135 output.set_name(
'VariablesToHistogram_' + decayString)
2136 output.param(
'particleList', decayString)
2137 output.param(
'variables', variables)
2138 output.param(
'variables_2d', variables_2d)
2139 output.param(
'fileName', filename)
2140 output.param(
'fileNameSuffix', filenameSuffix)
2141 output.param(
'ignoreCommandLineOverride', ignoreCommandLineOverride)
2142 if directory
is not None or prefixDecayString:
2143 if directory
is None:
2145 if prefixDecayString:
2146 directory = decayString +
"_" + directory
2147 output.param(
"directory", directory)
2148 path.add_module(output)
2153 For each particle in the input list the selected variables are saved
in an extra-info field
with the given name.
2154 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
2157 particleList (str): The input ParticleList
2158 variables (dict[str,str]): Dictionary of Variables (key)
and extraInfo names (value).
2159 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2160 An existing extra info
with the same name will be overwritten
if the new
2161 value
is lower / will never be overwritten / will be overwritten
if the
2162 new value
is higher / will always be overwritten (option = -1/0/1/2).
2163 path (basf2.Path): modules are added to this path
2166 mod = register_module('VariablesToExtraInfo')
2167 mod.set_name(
'VariablesToExtraInfo_' + particleList)
2168 mod.param(
'particleList', particleList)
2169 mod.param(
'variables', variables)
2170 mod.param(
'overwrite', option)
2171 path.add_module(mod)
2174def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
2176 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
2177 are saved
in an extra-info field
with the given name. In other words, the property of mother
is saved
as extra-info
2178 to specified daughter particle.
2181 particleList (str): The input ParticleList
2182 decayString (str): Decay string that specifies to which daughter the extra info should be appended
2183 variables (dict[str,str]): Dictionary of Variables (key)
and extraInfo names (value).
2184 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2185 An existing extra info
with the same name will be overwritten
if the new
2186 value
is lower / will never be overwritten / will be overwritten
if the
2187 new value
is higher / will always be overwritten (option = -1/0/1/2).
2188 path (basf2.Path): modules are added to this path
2191 mod = register_module('VariablesToExtraInfo')
2192 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
2193 mod.param(
'particleList', particleList)
2194 mod.param(
'decayString', decayString)
2195 mod.param(
'variables', variables)
2196 mod.param(
'overwrite', option)
2197 path.add_module(mod)
2200def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
2202 For each particle in the input list the selected variables are saved
in an event-extra-info field
with the given name,
2203 Can be used to save MC truth information,
for example,
in a ntuple of reconstructed particles.
2206 When the function
is called first time
not in the main path but
in a sub-path e.g. ``roe_path``,
2207 the eventExtraInfo cannot be accessed
from the main path because of the shorter lifetime of the event-extra-info field.
2208 If one wants to call the function
in a sub-path, one has to call the function
in the main path beforehand.
2211 particleList (str): The input ParticleList
2212 variables (dict[str,str]): Dictionary of Variables (key)
and extraInfo names (value).
2213 option (int): Option to overwrite an existing extraInfo. Choose among -1, 0, 1, 2.
2214 An existing extra info
with the same name will be overwritten
if the new
2215 value
is lower / will never be overwritten / will be overwritten
if the
2216 new value
is higher / will always be overwritten (option = -1/0/1/2).
2217 path (basf2.Path): modules are added to this path
2220 mod = register_module('VariablesToEventExtraInfo')
2221 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
2222 mod.param(
'particleList', particleList)
2223 mod.param(
'variables', variables)
2224 mod.param(
'overwrite', option)
2225 path.add_module(mod)
2228def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
2230 Write the value of specified variables estimated for the single particle
in the input list (has to contain exactly 1
2231 particle)
as an extra info to the particle related to current ROE.
2232 Should be used only
in the for_each roe path.
2235 particleList (str): The input ParticleList
2236 varToExtraInfo (dict[str,str]): Dictionary of Variables (key)
and extraInfo names (value).
2237 path (basf2.Path): modules are added to this path
2240 mod = register_module('SignalSideVariablesToExtraInfo')
2241 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
2242 mod.param(
'particleListName', particleList)
2243 mod.param(
'variableToExtraInfo', varToExtraInfo)
2244 path.add_module(mod)
2247def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
2249 Define and blind a signal region.
2250 Per default, the defined signal region
is cut out
if ran on data.
2251 This function will provide a new variable
'isSignalRegion' as default, which
is either 0
or 1 depending on the cut
2255 .. code-block:: python
2257 ma.reconstructDecay(
"B+:sig -> D+ pi0",
"Mbc>5.2", path=path)
2258 ma.signalRegion(
"B+:sig",
2259 "Mbc>5.27 and abs(deltaE)<0.2",
2262 ma.variablesToNtuples(
"B+:sig", [
"isSignalRegion"], path=path)
2265 particleList (str): The input ParticleList
2266 cut (str): Cut string describing the signal region
2267 path (basf2.Path):: Modules are added to this path
2268 name (str): Name of the Signal region
in the variable manager
2269 blind_data (bool): Automatically exclude signal region
from data
2273 from variables
import variables
2274 mod = register_module(
'VariablesToExtraInfo')
2275 mod.set_name(f
'{name}_' + particleList)
2276 mod.param(
'particleList', particleList)
2277 mod.param(
'variables', {f
"passesCut({cut})": name})
2278 variables.addAlias(name, f
"extraInfo({name})")
2279 path.add_module(mod)
2283 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
2286def removeExtraInfo(particleLists=None, removeEventExtraInfo=False, path=None):
2288 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo
is removed.
2291 if particleLists
is None:
2293 mod = register_module(
'ExtraInfoRemover')
2294 mod.param(
'particleLists', particleLists)
2295 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
2296 path.add_module(mod)
2299def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
2301 Checks if the current ROE object
in the for_each roe path (argument roe_path)
is related
2302 to the particle
from the input ParticleList. Additional selection criteria can be applied.
2303 If ROE
is not related to any of the Particles
from ParticleList
or the Particle doesn
't
2304 meet the selection criteria the execution of deadEndPath is started. This path,
as the name
2305 suggests should be empty
and its purpose
is to end the execution of for_each roe path
for
2306 the current ROE object.
2308 @param particleList The input ParticleList
2309 @param selection Selection criteria that Particle needs meet
in order
for for_each ROE path to
continue
2310 @param for_each roe path
in which this filter
is executed
2311 @param deadEndPath empty path that ends execution of or_each roe path
for the current ROE object.
2314 mod = register_module('SignalSideParticleFilter')
2315 mod.set_name(
'SigSideParticleFilter_' + particleList)
2316 mod.param(
'particleLists', [particleList])
2317 mod.param(
'selection', selection)
2318 roe_path.add_module(mod)
2319 mod.if_false(deadEndPath)
2322def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
2324 Checks if the current ROE object
in the for_each roe path (argument roe_path)
is related
2325 to the particle
from the input ParticleList. Additional selection criteria can be applied.
2326 If ROE
is not related to any of the Particles
from ParticleList
or the Particle doesn
't
2327 meet the selection criteria the execution of deadEndPath is started. This path,
as the name
2328 suggests should be empty
and its purpose
is to end the execution of for_each roe path
for
2329 the current ROE object.
2331 @param particleLists The input ParticleLists
2332 @param selection Selection criteria that Particle needs meet
in order
for for_each ROE path to
continue
2333 @param for_each roe path
in which this filter
is executed
2334 @param deadEndPath empty path that ends execution of or_each roe path
for the current ROE object.
2337 mod = register_module('SignalSideParticleFilter')
2338 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
2339 mod.param(
'particleLists', particleLists)
2340 mod.param(
'selection', selection)
2341 roe_path.add_module(mod)
2342 mod.if_false(deadEndPath)
2351 chargeConjugation=True,
2354 Finds and creates a ``ParticleList``
from given decay string.
2355 ``ParticleList`` of daughters
with sub-decay
is created.
2357 Only the particles made
from MCParticle, which can be loaded by `fillParticleListFromMC`, are accepted
as daughters.
2359 Only signal particle, which means :b2:var:`isSignal`
is equal to 1,
is stored. One can use the decay string grammar
2360 to change the behavior of :b2:var:`isSignal`. One can find detailed information
in :ref:`DecayString`.
2363 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
2364 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
2365 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
2368 It
is recommended to use only primary particles
as daughter particles unless you want to explicitly study the secondary
2369 particles. The behavior of MC-matching
for secondary particles
from a stable particle decay
is not guaranteed.
2370 Please consider to use `fillParticleListFromMC`
with ``skipNonPrimary=
True`` to load daughter particles.
2371 Moreover, it
is recommended to load ``K_S0``
and ``Lambda0`` directly
from MCParticle by `fillParticleListFromMC` rather
2372 than reconstructing
from two pions
or a proton-pion pair, because their direct daughters can be the secondary particle.
2375 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
2376 (
from the DecayString the mother
and daughter ParticleLists are determined)
2377 @param cut created (mother) Particles are added to the mother ParticleList
if they
2378 pass given cuts (
in VariableManager style)
and rejected otherwise
2379 isSignal==1
is always required by default.
2380 @param dmID user specified decay mode identifier
2381 @param writeOut whether RootOutput module should save the created ParticleList
2382 @param path modules are added to this path
2383 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed
as well (on by default)
2386 pmake = register_module('ParticleCombinerFromMC')
2387 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
2388 pmake.param(
'decayString', decayString)
2389 pmake.param(
'cut', cut)
2390 pmake.param(
'decayMode', dmID)
2391 pmake.param(
'writeOut', writeOut)
2392 pmake.param(
'chargeConjugation', chargeConjugation)
2393 path.add_module(pmake)
2400 appendAllDaughters=False,
2401 skipNonPrimaryDaughters=True,
2405 Finds and creates a ``ParticleList``
for all ``MCParticle`` decays matching a given :ref:`DecayString`.
2406 The decay string
is required to describe correctly what you want.
2407 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
2409 The output particles has only the daughter particles written
in the given decay string,
if
2410 ``appendAllDaughters=
False`` (default). If ``appendAllDaughters=
True``, all daughters of the matched MCParticle are
2411 appended
in the order defined at the MCParticle level. For example,
2413 .. code-block:: python
2415 findMCDecay(
'B0:Xee',
'B0 -> e+ e- ... ?gamma', appendAllDaughters=
False, path=mypath)
2417 The output ParticleList ``B0:Xee`` will match the inclusive ``B0 -> e+ e-`` decays (but neutrinos are
not included),
2418 in both cases of ``appendAllDaughters``
is false
and true.
2419 If the ``appendAllDaughters=
False``
as above example, the ``B0:Xee`` has only two electrons
as daughters.
2420 While,
if ``appendAllDaughters=
True``, all daughters of the matched MCParticles are appended. When the truth decay mode of
2421 the MCParticle
is ``B0 -> [K*0 -> K+ pi-] [J/psi -> e+ e-]``, the first daughter of ``B0:Xee``
is ``K*0``
and ``e+``
2422 will be the first daughter of second daughter of ``B0:Xee``.
2424 The option ``skipNonPrimaryDaughters`` only has an effect
if ``appendAllDaughters=
True``. If ``skipNonPrimaryDaughters=
True``,
2425 all primary daughters are appended but the secondary particles are
not.
2428 Daughters of ``Lambda0`` are
not primary, but ``Lambda0``
is not a final state particle.
2429 In order
for the MCMatching to work properly, the daughters of ``Lambda0`` are appended to
2430 ``Lambda0`` regardless of the value of the option ``skipNonPrimaryDaughters``.
2433 @param list_name The output particle list name
2434 @param decay The decay string which you want
2435 @param writeOut Whether `RootOutput` module should save the created ``outputList``
2436 @param skipNonPrimaryDaughters
if true, skip non primary daughters, useful to study final state daughter particles
2437 @param appendAllDaughters
if true,
not only the daughters described
in the decay string but all daughters are appended
2438 @param path modules are added to this path
2441 decayfinder = register_module('MCDecayFinder')
2442 decayfinder.set_name(
'MCDecayFinder_' + list_name)
2443 decayfinder.param(
'listName', list_name)
2444 decayfinder.param(
'decayString', decay)
2445 decayfinder.param(
'appendAllDaughters', appendAllDaughters)
2446 decayfinder.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
2447 decayfinder.param(
'writeOut', writeOut)
2448 path.add_module(decayfinder)
2451def summaryOfLists(particleLists, outputFile=None, path=None):
2453 Prints out Particle statistics at the end of the job: number of events with at
2454 least one candidate, average number of candidates per event, etc.
2455 If an output file name
is provided the statistics
is also dumped into a json file
with that name.
2457 @param particleLists list of input ParticleLists
2458 @param outputFile output file name (
not created by default)
2461 particleStats = register_module('ParticleStats')
2462 particleStats.param(
'particleLists', particleLists)
2463 if outputFile
is not None:
2464 particleStats.param(
'outputFile', outputFile)
2465 path.add_module(particleStats)
2468def matchMCTruth(list_name, path):
2470 Performs MC matching (sets relation Particle->MCParticle) for
2471 all particles (
and its (grand)^N-daughter particles)
in the specified
2474 @param list_name name of the input ParticleList
2475 @param path modules are added to this path
2478 mcMatch = register_module('MCMatcherParticles')
2479 mcMatch.set_name(
'MCMatch_' + list_name)
2480 mcMatch.param(
'listName', list_name)
2481 path.add_module(mcMatch)
2484def looseMCTruth(list_name, path):
2486 Performs loose MC matching for all particles
in the specified
2488 The difference between loose
and normal mc matching algorithm
is that
2489 the loose algorithm will find the common mother of the majority of daughter
2490 particles
while the normal algorithm finds the common mother of all daughters.
2491 The results of loose mc matching algorithm are stored to the following extraInfo
2494 - looseMCMotherPDG: PDG code of most common mother
2495 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
2496 - looseMCWrongDaughterN: number of daughters that don
't originate from the most common mother
2497 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from the most common mother (only if
2498 looseMCWrongDaughterN = 1)
2499 - looseMCWrongDaughterBiB: 1 if the wrong daughter
is Beam Induced Background Particle
2501 @param list_name name of the input ParticleList
2502 @param path modules are added to this path
2505 mcMatch = register_module('MCMatcherParticles')
2506 mcMatch.set_name(
'LooseMCMatch_' + list_name)
2507 mcMatch.param(
'listName', list_name)
2508 mcMatch.param(
'looseMCMatching',
True)
2509 path.add_module(mcMatch)
2512def buildRestOfEvent(target_list_name, inputParticlelists=None,
2513 fillWithMostLikely=True,
2514 chargedPIDPriors=None, path=None):
2516 Creates for each Particle
in the given ParticleList a RestOfEvent
2517 dataobject
and makes basf2 relation between them. User can provide additional
2518 particle lists
with a different particle hypothesis like [
'K+:good, e+:good'], etc.
2520 @param target_list_name name of the input ParticleList
2521 @param inputParticlelists list of user-defined input particle list names, which serve
2522 as source of particles to build the ROE, the FSP particles
from
2523 target_list_name are automatically excluded
from the ROE object
2524 @param fillWithMostLikely By default the module uses the most likely particle mass hypothesis
for charged particles
2525 based on the PID likelihood. Turn this behavior off
if you want to configure your own
2526 input particle lists.
2527 @param chargedPIDPriors The prior PID fractions, that are used to regulate the
2528 amount of certain charged particle species, should be a list of
2529 six floats
if not None. The order of particle types
is
2530 the following: [e-, mu-, pi-, K-, p+, d+]
2531 @param path modules are added to this path
2534 if inputParticlelists
is None:
2535 inputParticlelists = []
2536 fillParticleList(
'pi+:all',
'', path=path)
2537 if fillWithMostLikely:
2538 from stdCharged
import stdMostLikely
2539 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
2540 inputParticlelists = [f
'{ptype}:mostlikely_roe' for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
2543 fillParticleList(
'gamma:all',
'', path=path)
2544 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
2545 inputParticlelists += [
'pi+:all',
'gamma:all',
'K_L0:roe_default']
2547 inputParticlelists += [
'pi+:all',
'gamma:mdst']
2548 roeBuilder = register_module(
'RestOfEventBuilder')
2549 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
2550 roeBuilder.param(
'particleList', target_list_name)
2551 roeBuilder.param(
'particleListsInput', inputParticlelists)
2552 roeBuilder.param(
'mostLikely', fillWithMostLikely)
2553 path.add_module(roeBuilder)
2556def buildNestedRestOfEvent(target_list_name, maskName='all', path=None):
2558 Creates for each Particle
in the given ParticleList a RestOfEvent
2559 @param target_list_name name of the input ParticleList
2560 @param mask_name name of the ROEMask to be used
2561 @param path modules are added to this path
2564 roeBuilder = register_module('RestOfEventBuilder')
2565 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
2566 roeBuilder.param(
'particleList', target_list_name)
2567 roeBuilder.param(
'nestedROEMask', maskName)
2568 roeBuilder.param(
'createNestedROE',
True)
2569 path.add_module(roeBuilder)
2572def buildRestOfEventFromMC(target_list_name, inputParticlelists=None, path=None):
2574 Creates for each Particle
in the given ParticleList a RestOfEvent
2575 @param target_list_name name of the input ParticleList
2576 @param inputParticlelists list of input particle list names, which serve
2577 as a source of particles to build ROE, the FSP particles
from
2578 target_list_name are excluded
from ROE object
2579 @param path modules are added to this path
2582 if inputParticlelists
is None:
2583 inputParticlelists = []
2584 if (len(inputParticlelists) == 0):
2588 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
2589 'n0',
'nu_e',
'nu_mu',
'nu_tau',
2592 fillParticleListFromMC(f
"{t}:roe_default_gen",
'mcPrimary > 0 and nDaughters == 0',
2593 True,
True, path=path)
2594 inputParticlelists += [f
"{t}:roe_default_gen"]
2595 roeBuilder = register_module(
'RestOfEventBuilder')
2596 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
2597 roeBuilder.param(
'particleList', target_list_name)
2598 roeBuilder.param(
'particleListsInput', inputParticlelists)
2599 roeBuilder.param(
'fromMC',
True)
2600 path.add_module(roeBuilder)
2603def appendROEMask(list_name,
2606 eclClusterSelection,
2607 klmClusterSelection='',
2610 Loads the ROE object of a particle and creates a ROE mask
with a specific name. It applies
2611 selection criteria
for tracks
and eclClusters which will be used by variables
in ROEVariables.cc.
2613 - append a ROE mask
with all tracks
in ROE coming
from the IP region
2615 .. code-block:: python
2617 appendROEMask(
'B+:sig',
'IPtracks',
'[dr < 2] and [abs(dz) < 5]', path=mypath)
2619 - append a ROE mask
with only ECL-based particles that
pass as good photon candidates
2621 .. code-block:: python
2623 goodPhotons =
'inCDCAcceptance and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
2624 appendROEMask(
'B+:sig',
'goodROEGamma',
'', goodPhotons, path=mypath)
2627 @param list_name name of the input ParticleList
2628 @param mask_name name of the appended ROEMask
2629 @param trackSelection decay string
for the track-based particles
in ROE
2630 @param eclClusterSelection decay string
for the ECL-based particles
in ROE
2631 @param klmClusterSelection decay string
for the KLM-based particles
in ROE
2632 @param path modules are added to this path
2635 roeMask = register_module('RestOfEventInterpreter')
2636 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2637 roeMask.param(
'particleList', list_name)
2638 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2639 path.add_module(roeMask)
2642def appendROEMasks(list_name, mask_tuples, path=None):
2644 Loads the ROE object of a particle and creates a ROE mask
with a specific name. It applies
2645 selection criteria
for track-, ECL-
and KLM-based particles which will be used by ROE variables.
2647 The multiple ROE masks
with their own selection criteria are specified
2648 via list of tuples (mask_name, trackParticleSelection, eclParticleSelection, klmParticleSelection)
or
2649 (mask_name, trackSelection, eclClusterSelection)
in case
with fractions.
2651 - Example
for two tuples, one
with and one without fractions
2653 .. code-block:: python
2655 ipTracks = (
'IPtracks',
'[dr < 2] and [abs(dz) < 5]',
'',
'')
2656 goodPhotons =
'inCDCAcceptance and [clusterErrorTiming < 1e6] and [clusterE1E9 > 0.4 or E > 0.075]'
2657 goodROEGamma = (
'ROESel',
'[dr < 2] and [abs(dz) < 5]', goodPhotons,
'')
2658 goodROEKLM = (
'IPtracks',
'[dr < 2] and [abs(dz) < 5]',
'',
'nKLMClusterTrackMatches == 0')
2659 appendROEMasks(
'B+:sig', [ipTracks, goodROEGamma, goodROEKLM], path=mypath)
2661 @param list_name name of the input ParticleList
2662 @param mask_tuples array of ROEMask list tuples to be appended
2663 @param path modules are added to this path
2666 compatible_masks = []
2667 for mask
in mask_tuples:
2670 compatible_masks += [(*mask,
'')]
2672 compatible_masks += [mask]
2673 roeMask = register_module(
'RestOfEventInterpreter')
2674 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2675 roeMask.param(
'particleList', list_name)
2676 roeMask.param(
'ROEMasks', compatible_masks)
2677 path.add_module(roeMask)
2680def updateROEMask(list_name,
2683 eclClusterSelection='',
2684 klmClusterSelection='',
2687 Update an existing ROE mask by applying additional selection cuts for
2688 tracks
and/
or clusters.
2690 See function `appendROEMask`!
2692 @param list_name name of the input ParticleList
2693 @param mask_name name of the ROEMask to update
2694 @param trackSelection decay string
for the track-based particles
in ROE
2695 @param eclClusterSelection decay string
for the ECL-based particles
in ROE
2696 @param klmClusterSelection decay string
for the KLM-based particles
in ROE
2697 @param path modules are added to this path
2700 roeMask = register_module('RestOfEventInterpreter')
2701 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2702 roeMask.param(
'particleList', list_name)
2703 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2704 roeMask.param(
'update',
True)
2705 path.add_module(roeMask)
2708def updateROEMasks(list_name, mask_tuples, path):
2710 Update existing ROE masks by applying additional selection cuts for tracks
2713 The multiple ROE masks
with their own selection criteria are specified
2714 via list tuples (mask_name, trackSelection, eclClusterSelection, klmClusterSelection)
2716 See function `appendROEMasks`!
2718 @param list_name name of the input ParticleList
2719 @param mask_tuples array of ROEMask list tuples to be appended
2720 @param path modules are added to this path
2723 compatible_masks = []
2724 for mask
in mask_tuples:
2727 compatible_masks += [(*mask,
'')]
2729 compatible_masks += [mask]
2731 roeMask = register_module(
'RestOfEventInterpreter')
2732 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2733 roeMask.param(
'particleList', list_name)
2734 roeMask.param(
'ROEMasks', compatible_masks)
2735 roeMask.param(
'update',
True)
2736 path.add_module(roeMask)
2739def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2741 This function is used to apply particle list specific cuts on one
or more ROE masks (track
or eclCluster).
2742 With this function one can KEEP the tracks/eclclusters used
in particles
from provided particle list.
2743 This function should be executed only
in the for_each roe path
for the current ROE object.
2745 To avoid unnecessary computation, the input particle list should only contain particles
from ROE
2746 (use cut
'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2747 particle list (e.g.
'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2748 pion particle list (e.g.
'pi+:someLabel').
2750 Updating a non-existing mask will create a new one.
2752 - keep only those tracks that were used
in provided particle list
2754 .. code-block:: python
2756 keepInROEMasks(
'pi+:goodTracks',
'mask',
'', path=mypath)
2758 - keep only those clusters that were used
in provided particle list
and pass a cut, apply to several masks
2760 .. code-block:: python
2762 keepInROEMasks(
'gamma:goodClusters', [
'mask1',
'mask2'],
'E > 0.1', path=mypath)
2765 @param list_name name of the input ParticleList
2766 @param mask_names array of ROEMasks to be updated
2767 @param cut_string decay string
with which the mask will be updated
2768 @param path modules are added to this path
2771 updateMask = register_module('RestOfEventUpdater')
2772 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2773 updateMask.param(
'particleList', list_name)
2774 updateMask.param(
'updateMasks', mask_names)
2775 updateMask.param(
'cutString', cut_string)
2776 updateMask.param(
'discard',
False)
2777 path.add_module(updateMask)
2780def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2782 This function is used to apply particle list specific cuts on one
or more ROE masks (track
or eclCluster).
2783 With this function one can DISCARD the tracks/eclclusters used
in particles
from provided particle list.
2784 This function should be executed only
in the for_each roe path
for the current ROE object.
2786 To avoid unnecessary computation, the input particle list should only contain particles
from ROE
2787 (use cut
'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2788 particle list (e.g.
'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2789 pion particle list (e.g.
'pi+:someLabel').
2791 Updating a non-existing mask will create a new one.
2793 - discard tracks that were used
in provided particle list
2795 .. code-block:: python
2797 discardFromROEMasks(
'pi+:badTracks',
'mask',
'', path=mypath)
2799 - discard clusters that were used
in provided particle list
and pass a cut, apply to several masks
2801 .. code-block:: python
2803 discardFromROEMasks(
'gamma:badClusters', [
'mask1',
'mask2'],
'E < 0.1', path=mypath)
2806 @param list_name name of the input ParticleList
2807 @param mask_names array of ROEMasks to be updated
2808 @param cut_string decay string
with which the mask will be updated
2809 @param path modules are added to this path
2812 updateMask = register_module('RestOfEventUpdater')
2813 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2814 updateMask.param(
'particleList', list_name)
2815 updateMask.param(
'updateMasks', mask_names)
2816 updateMask.param(
'cutString', cut_string)
2817 updateMask.param(
'discard',
True)
2818 path.add_module(updateMask)
2821def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2823 This function is used to apply particle list specific cuts on one
or more ROE masks
for Tracks.
2824 It
is possible to optimize the ROE selection by treating tracks
from V0
's separately, meaning,
2825 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2826 passing it can be applied.
2828 The input particle list should be a V0 particle list: K_S0 (
'K_S0:someLabel',
''),
2829 Lambda (
'Lambda:someLabel',
'')
or converted photons (
'gamma:someLabel').
2831 Updating a non-existing mask will create a new one.
2833 - treat tracks
from K_S0 inside mass window separately, replace track momenta
with K_S0 momentum
2835 .. code-block:: python
2837 optimizeROEWithV0(
'K_S0:opt',
'mask',
'0.450 < M < 0.550', path=mypath)
2839 @param list_name name of the input ParticleList
2840 @param mask_names array of ROEMasks to be updated
2841 @param cut_string decay string
with which the mask will be updated
2842 @param path modules are added to this path
2845 updateMask = register_module('RestOfEventUpdater')
2846 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2847 updateMask.param(
'particleList', list_name)
2848 updateMask.param(
'updateMasks', mask_names)
2849 updateMask.param(
'cutString', cut_string)
2850 path.add_module(updateMask)
2853def updateROEUsingV0Lists(target_particle_list, mask_names, default_cleanup=True, selection_cuts=None,
2854 apply_mass_fit=False, fitter='treefit', path=None):
2856 This function creates V0 particle lists (photons, :math:`K^0_S` and :math:`\\Lambda^0`)
2857 and it uses V0 candidates to update the Rest Of Event, which
is associated to the target particle list.
2858 It
is possible to apply a standard
or customized selection
and mass fit to the V0 candidates.
2861 @param target_particle_list name of the input ParticleList
2862 @param mask_names array of ROE masks to be applied
2863 @param default_cleanup
if True, predefined cuts will be applied on the V0 lists
2864 @param selection_cuts a single string of selection cuts
or tuple of three strings (photon_cuts, K_S0_cuts, Lambda0_cuts),
2865 which will be applied to the V0 lists. These cuts will have a priority over the default ones.
2866 @param apply_mass_fit
if True, a mass fit will be applied to the V0 particles
2867 @param fitter string, that represent a fitter choice:
"treefit" for TreeFitter
and "kfit" for KFit
2868 @param path modules are added to this path
2871 roe_path = create_path()
2872 deadEndPath = create_path()
2873 signalSideParticleFilter(target_particle_list, '', roe_path, deadEndPath)
2875 if (default_cleanup
and selection_cuts
is None):
2876 B2INFO(
"Using default cleanup in updateROEUsingV0Lists.")
2877 selection_cuts =
'abs(dM) < 0.1 '
2878 selection_cuts +=
'and daughter(0,particleID) > 0.2 and daughter(1,particleID) > 0.2 '
2879 selection_cuts +=
'and daughter(0,thetaInCDCAcceptance) and daughter(1,thetaInCDCAcceptance)'
2880 if (selection_cuts
is None or selection_cuts ==
''):
2881 B2INFO(
"No cleanup in updateROEUsingV0Lists.")
2882 selection_cuts = (
'True',
'True',
'True')
2883 if (isinstance(selection_cuts, str)):
2884 selection_cuts = (selection_cuts, selection_cuts, selection_cuts)
2886 roe_cuts =
'isInRestOfEvent > 0'
2887 fillConvertedPhotonsList(
'gamma:v0_roe -> e+ e-', f
'{selection_cuts[0]} and {roe_cuts}',
2889 fillParticleList(
'K_S0:v0_roe -> pi+ pi-', f
'{selection_cuts[1]} and {roe_cuts}',
2891 fillParticleList(
'Lambda0:v0_roe -> p+ pi-', f
'{selection_cuts[2]} and {roe_cuts}',
2893 fitter = fitter.lower()
2894 if (fitter !=
'treefit' and fitter !=
'kfit'):
2895 B2WARNING(
'Argument "fitter" in updateROEUsingV0Lists has only "treefit" and "kfit" options, '
2896 f
'but "{fitter}" was provided! TreeFitter will be used instead.')
2898 from vertex
import kFit, treeFit
2899 for v0
in [
'gamma:v0_roe',
'K_S0:v0_roe',
'Lambda0:v0_roe']:
2900 if (apply_mass_fit
and fitter ==
'kfit'):
2901 kFit(v0, conf_level=0.0, fit_type=
'massvertex', path=roe_path)
2902 if (apply_mass_fit
and fitter ==
'treefit'):
2903 treeFit(v0, conf_level=0.0, massConstraint=[v0.split(
':')[0]], path=roe_path)
2904 optimizeROEWithV0(v0, mask_names,
'', path=roe_path)
2905 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2908def printROEInfo(mask_names=None, full_print=False,
2909 unpackComposites=True, path=None):
2911 This function prints out the information for the current ROE, so it should only be used
in the for_each path.
2912 It prints out basic ROE object info.
2914 If mask names are provided, specific information
for those masks will be printed out.
2916 It
is also possible to
print out all particles
in a given mask
if the
2917 'full_print' is set to
True.
2919 @param mask_names array of ROEMask names
for printing out info
2920 @param unpackComposites
if true, replace composite particles by their daughters
2921 @param full_print
print out particles
in mask
2922 @param path modules are added to this path
2925 if mask_names
is None:
2927 printMask = register_module(
'RestOfEventPrinter')
2928 printMask.set_name(
'RestOfEventPrinter')
2929 printMask.param(
'maskNames', mask_names)
2930 printMask.param(
'fullPrint', full_print)
2931 printMask.param(
'unpackComposites', unpackComposites)
2932 path.add_module(printMask)
2935def buildContinuumSuppression(list_name, roe_mask, path):
2937 Creates for each Particle
in the given ParticleList a ContinuumSuppression
2938 dataobject
and makes basf2 relation between them.
2940 :param list_name: name of the input ParticleList
2941 :param roe_mask: name of the ROE mask
2942 :param path: modules are added to this path
2945 qqBuilder = register_module('ContinuumSuppressionBuilder')
2946 qqBuilder.set_name(
'QQBuilder_' + list_name)
2947 qqBuilder.param(
'particleList', list_name)
2948 qqBuilder.param(
'ROEMask', roe_mask)
2949 path.add_module(qqBuilder)
2954 Removes all Particles that are not in a given list of ParticleLists (
or daughters of those).
2955 All relations
from/to Particles, daughter indices,
and other ParticleLists are fixed.
2957 @param lists_to_keep Keep the Particles
and their daughters
in these ParticleLists.
2958 @param path modules are added to this path
2961 mod = register_module('RemoveParticlesNotInLists')
2962 mod.param(
'particleLists', lists_to_keep)
2963 path.add_module(mod)
2966def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2968 Reconstructs Btag from particles
in given ParticleLists which do
not share any final state particles (mdstSource)
with Bsig.
2970 @param upsilon_list_name Name of the ParticleList to be filled
with 'Upsilon(4S) -> B:sig anti-B:tag'
2971 @param bsig_list_name Name of the Bsig ParticleList
2972 @param btag_list_name Name of the Bsig ParticleList
2973 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag
from
2976 btag = register_module('InclusiveBtagReconstruction')
2977 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2978 btag.param(
'upsilonListName', upsilon_list_name)
2979 btag.param(
'bsigListName', bsig_list_name)
2980 btag.param(
'btagListName', btag_list_name)
2981 btag.param(
'inputListsNames', input_lists_names)
2982 path.add_module(btag)
2985def selectDaughters(particle_list_name, decay_string, path):
2987 Redefine the Daughters of a particle: select from decayString
2989 @param particle_list_name input particle list
2990 @param decay_string
for selecting the Daughters to be preserved
2993 seld = register_module('SelectDaughters')
2994 seld.set_name(
'SelectDaughters_' + particle_list_name)
2995 seld.param(
'listName', particle_list_name)
2996 seld.param(
'decayString', decay_string)
2997 path.add_module(seld)
3000def markDuplicate(particleList, prioritiseV0, path):
3002 Call DuplicateVertexMarker to find duplicate particles in a list
and
3003 flag the ones that should be kept
3005 @param particleList input particle list
3006 @param prioritiseV0
if true, give V0s a higher priority
3009 markdup = register_module('DuplicateVertexMarker')
3010 markdup.param(
'particleList', particleList)
3011 markdup.param(
'prioritiseV0', prioritiseV0)
3012 path.add_module(markdup)
3015PI0ETAVETO_COUNTER = 0
3018def oldwritePi0EtaVeto(
3021 workingDirectory='.',
3022 pi0vetoname='Pi0_Prob',
3023 etavetoname='Eta_Prob',
3029 Give pi0/eta probability for hard photon.
3031 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.
3033 The current default weight files are optimised using MC9.
3034 The input variables are
as below. Aliases are set to some variables during training.
3036 * M: pi0/eta candidates Invariant mass
3037 * lowE: soft photon energy
in lab frame
3038 * cTheta: soft photon ECL cluster
's polar angle
3039 * Zmva: soft photon output of MVA using Zernike moments of the cluster
3040 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3042 If you don
't have weight files in your workingDirectory,
3043 these files are downloaded from database to your workingDirectory automatically.
3044 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
3045 about how to use this function.
3048 Please don
't use following ParticleList names elsewhere:
3050 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
3051 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
3053 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
3055 @param particleList The input ParticleList
3056 @param decayString specify Particle to be added to the ParticleList
3057 @param workingDirectory The weight file directory
3058 @param downloadFlag whether download default weight files
or not
3059 @param pi0vetoname extraInfo name of pi0 probability
3060 @param etavetoname extraInfo name of eta probability
3061 @param selection Selection criteria that Particle needs meet
in order
for for_each ROE path to
continue
3062 @param path modules are added to this path
3067 B2ERROR(
"The old pi0 / eta veto is not suitable for Belle analyses.")
3072 global PI0ETAVETO_COUNTER
3074 if PI0ETAVETO_COUNTER == 0:
3075 from variables
import variables
3076 variables.addAlias(
'lowE',
'daughter(1,E)')
3077 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
3078 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
3079 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
3080 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
3081 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
3083 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
3085 roe_path = create_path()
3087 deadEndPath = create_path()
3089 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3091 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
3093 pi0softname =
'gamma:PI0SOFT'
3094 etasoftname =
'gamma:ETASOFT'
3095 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
3096 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
3100 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
3102 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
3105 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
3107 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
3109 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
3110 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
3112 if not os.path.isdir(workingDirectory):
3113 os.mkdir(workingDirectory)
3114 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
3116 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
3118 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
3119 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
3121 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
3123 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
3124 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
3126 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
3127 identifier=workingDirectory +
'/pi0veto.root')
3128 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
3129 identifier=workingDirectory +
'/etaveto.root')
3131 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
3132 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
3134 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
3135 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
3137 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3143 mode='standardMC15rd',
3147 hardParticle='gamma',
3148 pi0PayloadNameOverride=None,
3149 pi0SoftPhotonCutOverride=None,
3150 etaPayloadNameOverride=None,
3151 etaSoftPhotonCutOverride=None,
3152 requireSoftPhotonIsInROE=False,
3153 pi0Selection='[0.03 < M < 0.23]',
3154 etaSelection='[0.25 < M < 0.75]'
3157 Give pi0/eta probability for hard photon.
3159 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.
3160 For MC15rd weight files, the BtoXGamma skim
is applied during the MVA training.
3162 The current default weight files are optimised using MC15rd. The weight files
for MC12 (last version) are still available.
3164 The input variables of the mva training
for pi0 veto using MC15rd are:
3166 * M: Invariant mass of pi0 candidates
3167 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons
in the pi0 rest frame
3168 and momentum of pi0
in lab frame
3169 * daughter(1,E): soft photon energy
in lab frame
3170 * daughter(1,clusterTheta): soft photon ECL cluster
's polar angle
3171 * daughter(1,clusterLAT): soft photon lateral energy distribution
3173 The input variables of the mva training for eta veto using MC15rd are:
3175 * M: Invariant mass of eta candidates
3176 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons
in the eta rest frame
3177 and momentum of eta
in lab frame
3178 * daughter(1,E): soft photon energy
in lab frame
3179 * daughter(1,clusterTheta): soft photon ECL cluster
's polar angle
3180 * daughter(1,clusterLAT): soft photon lateral energy distribution
3181 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
3182 * daughter(1,clusterE1E9): soft photon ratio between energies of central crystal
and inner 3x3 crystals
3183 * daughter(1,clusterE9E21): soft photon ratio of energies
in inner 3x3 crystals
and 5x5 crystals without corners
3184 * daughter(1,clusterSecondMoment): soft photon second moment
3185 * daughter(1,clusterAbsZernikeMoment40): soft photon Zernike moment 40
3186 * daughter(1,clusterAbsZernikeMoment51): soft photon Zernike moment 51
3188 The input variables of the mva training using MC12 are:
3190 * M: Invariant mass of pi0/eta candidates
3191 * daughter(1,E): soft photon energy
in lab frame
3192 * daughter(1,clusterTheta): soft photon ECL cluster
's polar angle
3193 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
3194 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
3195 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i)
with w_i<=1
3196 * daughter(1,clusterE9E21): soft photon ratio of energies
in inner 3x3 crystals
and 5x5 crystals without corners
3197 * cosHelicityAngleMomentum: Cosine of angle between momentum difference of the photons
in the pi0/eta rest frame
3198 and momentum of pi0/eta
in lab frame
3200 The following strings are available
for mode:
3202 * standard: loose energy cut
and no clusterNHits cut are applied to soft photon
3203 * tight: tight energy cut
and no clusterNHits cut are applied to soft photon
3204 * cluster: loose energy cut
and clusterNHits cut are applied to soft photon
3205 * both: tight energy cut
and clusterNHits cut are applied to soft photon
3206 * standardMC15rd: loose energy cut
is applied to soft photon
and the weight files are trained using MC15rd
3207 * tightMC15rd: tight energy cut
is applied to soft photon
and the weight files are trained using MC15rd
3209 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
3210 `pi0Prob`/`etaProb`. Otherwise, it
is available
as '{Pi0, Eta}ProbOrigin',
'{Pi0, Eta}ProbTightEnergyThreshold',
'{Pi0,
3211 Eta}ProbLargeClusterSize', '{Pi0, Eta}ProbTightEnergyThresholdAndLargeClusterSize
', '{Pi0, Eta}ProbOriginMC15rd
', or
3212 '{Pi0, Eta}ProbTightEnergyThresholdMC15rd' for the six modes described above,
with the chosen suffix appended. If one would
3213 like to call this veto twice
in one script, add suffix
in the second time!
3214 The second highest probability of the pi0/eta veto also
is stored
as an extraInfo,
with a prefix of
'second' to the previous
3215 ones, e.g. secondPi0ProbOrigin{suffix}. This can be used to do validation/systematics study.
3218 Please don
't use following ParticleList names elsewhere:
3220 ``gamma:HardPhoton``,
3221 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(
':',
'_')``,
3222 ``gamma:EtaSoft + ListName +
'_' + particleList.replace(
':',
'_')``,
3223 ``pi0:EtaVeto + ListName``,
3224 ``eta:EtaVeto + ListName``
3226 @param particleList the input ParticleList
3227 @param decayString specify Particle to be added to the ParticleList
3228 @param mode choose one mode out of
'standardMC15rd',
'tightMC15rd',
'standard',
'tight',
'cluster' and 'both'
3229 @param selection selection criteria that Particle needs meet
in order
for for_each ROE path to
continue
3230 @param path modules are added to this path
3231 @param suffix optional suffix to be appended to the usual extraInfo name
3232 @param hardParticle particle name which
is used to calculate the pi0/eta probability (default
is gamma)
3233 @param pi0PayloadNameOverride specify the payload name of pi0 veto only
if one wants to use non-default one. (default
is None)
3234 @param pi0SoftPhotonCutOverride specify the soft photon selection criteria of pi0 veto only
if one wants to use non-default one.
3236 @param etaPayloadNameOverride specify the payload name of eta veto only
if one wants to use non-default one. (default
is None)
3237 @param etaSoftPhotonCutOverride specify the soft photon selection criteria of eta veto only
if one wants to use non-default one.
3239 @param requireSoftPhotonIsInROE specify
if the soft photons used to build pi0
and eta candidates have to be
in the current ROE
3240 or not. Default
is False, i.e. all soft photons
in the event are used.
3241 @param pi0Selection Selection
for the pi0 reconstruction. Default
is '(0.03 < M < 0.23)'.
3242 @param etaSelection Selection
for the eta reconstruction. Default
is '(0.25 < M < 0.75)'.
3247 B2ERROR(
"The pi0 / eta veto is not suitable for Belle analyses.")
3249 if (requireSoftPhotonIsInROE):
3250 B2WARNING(
"Requiring the soft photon to being in the ROE was not done for the MVA training. "
3251 "Please check the results carefully.")
3252 if (mode ==
'standardMC15rd' or mode ==
'tightMC15rd'):
3253 if (pi0Selection !=
'[0.03 < M < 0.23]' or etaSelection !=
'[0.25 < M < 0.75]'):
3255 "Personal selection criteria for the pi0 or the eta during reconstructDecay were not used during the MVA training. "
3256 "Please check the results carefully.")
3258 if (pi0Selection !=
'' or etaSelection !=
''):
3260 "Personal selection criteria for the pi0 or the eta during reconstructDecay were not used during the MVA training. "
3261 "Please check the results carefully.")
3263 renameSuffix =
False
3265 for module
in path.modules():
3266 if module.type() ==
"SubEvent" and not renameSuffix:
3267 for subpath
in [p.values
for p
in module.available_params()
if p.name ==
"path"]:
3270 for submodule
in subpath.modules():
3271 if f
'{hardParticle}:HardPhoton{suffix}' in submodule.name():
3273 B2WARNING(
"Same extension already used in writePi0EtaVeto, append '_0'")
3277 roe_path = create_path()
3278 deadEndPath = create_path()
3279 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
3280 fillSignalSideParticleList(f
'{hardParticle}:HardPhoton{suffix}', decayString, path=roe_path)
3282 dictListName = {
'standard':
'Origin',
3283 'tight':
'TightEnergyThreshold',
3284 'cluster':
'LargeClusterSize',
3285 'both':
'TightEnrgyThresholdAndLargeClusterSize',
3286 'standardMC15rd':
'OriginMC15rd',
3287 'tightMC15rd':
'TightEnergyThresholdMC15rd'}
3289 dictPi0EnergyCut = {
3290 'standard':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3291 'tight':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3292 'cluster':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3293 'both':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
3294 'standardMC15rd':
'[[clusterReg==1 and E>0.0225] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3295 'tightMC15rd':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3297 dictEtaEnergyCut = {
3298 'standard':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3299 'tight':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3300 'cluster':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
3301 'both':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
3302 'standardMC15rd':
'[[clusterReg==1 and E>0.0225] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
3303 'tightMC15rd':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
3305 dictNHitsTimingCut = {
'standard':
'clusterNHits >= 0 and abs(clusterTiming)<clusterErrorTiming',
3306 'tight':
'clusterNHits >= 0 and abs(clusterTiming)<clusterErrorTiming',
3307 'cluster':
'clusterNHits >= 2 and abs(clusterTiming)<clusterErrorTiming',
3308 'both':
'clusterNHits >= 2 and abs(clusterTiming)<clusterErrorTiming',
3309 'standardMC15rd':
'clusterNHits > 1.5 and abs(clusterTiming) < 200',
3310 'tightMC15rd':
'clusterNHits > 1.5 and abs(clusterTiming) < 200'}
3312 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
3313 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
3314 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
3315 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize',
3316 'standardMC15rd':
'Pi0VetoIdentifierStandardMC15rd',
3317 'tightMC15rd':
'Pi0VetoIdentifierWithHigherEnergyThresholdMC15rd'}
3319 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
3320 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
3321 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
3322 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize',
3323 'standardMC15rd':
'EtaVetoIdentifierStandardMC15rd',
3324 'tightMC15rd':
'EtaVetoIdentifierWithHigherEnergyThresholdMC15rd'}
3326 dictPi0ExtraInfoName = {
'standard':
'Pi0ProbOrigin',
3327 'tight':
'Pi0ProbTightEnergyThreshold',
3328 'cluster':
'Pi0ProbLargeClusterSize',
3329 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize',
3330 'standardMC15rd':
'Pi0ProbOriginMC15rd',
3331 'tightMC15rd':
'Pi0ProbTightEnergyThresholdMC15rd'}
3333 dictEtaExtraInfoName = {
'standard':
'EtaProbOrigin',
3334 'tight':
'EtaProbTightEnergyThreshold',
3335 'cluster':
'EtaProbLargeClusterSize',
3336 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize',
3337 'standardMC15rd':
'EtaProbOriginMC15rd',
3338 'tightMC15rd':
'EtaProbTightEnergyThresholdMC15rd'}
3340 ListName = dictListName[mode]
3341 Pi0EnergyCut = dictPi0EnergyCut[mode]
3342 EtaEnergyCut = dictEtaEnergyCut[mode]
3343 NHitsTimingCut = dictNHitsTimingCut[mode]
3344 Pi0PayloadName = dictPi0PayloadName[mode]
3345 EtaPayloadName = dictEtaPayloadName[mode]
3346 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
3347 EtaExtraInfoName = dictEtaExtraInfoName[mode]
3350 if pi0PayloadNameOverride
is not None:
3351 Pi0PayloadName = pi0PayloadNameOverride
3352 B2WARNING(
"You're using personal weight files, be careful. ")
3353 if pi0SoftPhotonCutOverride
is None:
3354 Pi0SoftPhotonCut = Pi0EnergyCut +
' and ' + NHitsTimingCut
3356 Pi0SoftPhotonCut = pi0SoftPhotonCutOverride
3357 B2WARNING(
"You're applying personal cuts on the soft photon candidates, be careful. ")
3359 if requireSoftPhotonIsInROE:
3360 Pi0SoftPhotonCut +=
' and isInRestOfEvent==1'
3363 pi0soft = f
'gamma:Pi0Soft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3365 fillParticleList(pi0soft, Pi0SoftPhotonCut, path=roe_path)
3367 reconstructDecay(
'pi0:Pi0Veto' + ListName + suffix + f
' -> {hardParticle}:HardPhoton{suffix} ' + pi0soft, pi0Selection,
3368 allowChargeViolation=
True, path=roe_path)
3370 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName + suffix],
3371 extraInfoName=Pi0ExtraInfoName, identifier=Pi0PayloadName)
3374 'pi0:Pi0Veto' + ListName + suffix,
3375 'extraInfo(' + Pi0ExtraInfoName +
')',
3377 outputVariable=
"Pi0VetoRank",
3379 cutAndCopyList(outputListName=
'pi0:Pi0VetoFirst' + ListName + suffix,
3380 inputListName=
'pi0:Pi0Veto' + ListName + suffix,
3381 cut=
'extraInfo(Pi0VetoRank)==1',
3383 variableToSignalSideExtraInfo(
'pi0:Pi0VetoFirst' + ListName + suffix,
3384 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoName + suffix}, path=roe_path)
3386 cutAndCopyList(outputListName=
'pi0:Pi0VetoSecond' + ListName + suffix,
3387 inputListName=
'pi0:Pi0Veto' + ListName + suffix,
3388 cut=
'extraInfo(Pi0VetoRank)==2',
3390 variableToSignalSideExtraInfo(
'pi0:Pi0VetoSecond' + ListName + suffix,
3391 {
'extraInfo(' + Pi0ExtraInfoName +
')':
'second' + Pi0ExtraInfoName + suffix}, path=roe_path)
3394 if etaPayloadNameOverride
is not None:
3395 EtaPayloadName = etaPayloadNameOverride
3396 B2WARNING(
"You're using personal weight files, be careful. ")
3397 if etaSoftPhotonCutOverride
is None:
3398 EtaSoftPhotonCut = EtaEnergyCut +
' and ' + NHitsTimingCut
3400 EtaSoftPhotonCut = etaSoftPhotonCutOverride
3401 B2WARNING(
"You're applying personal cuts on the soft photon candidates, be careful. ")
3403 if requireSoftPhotonIsInROE:
3404 EtaSoftPhotonCut +=
' and isInRestOfEvent==1'
3406 etasoft = f
'gamma:EtaSoft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
3407 fillParticleList(etasoft, EtaSoftPhotonCut, path=roe_path)
3408 reconstructDecay(
'eta:EtaVeto' + ListName + suffix + f
' -> {hardParticle}:HardPhoton{suffix} ' + etasoft, etaSelection,
3409 allowChargeViolation=
True, path=roe_path)
3410 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName + suffix],
3411 extraInfoName=EtaExtraInfoName, identifier=EtaPayloadName)
3413 'eta:EtaVeto' + ListName + suffix,
3414 'extraInfo(' + EtaExtraInfoName +
')',
3416 outputVariable=
"EtaVetoRank",
3418 cutAndCopyList(outputListName=
'eta:EtaVetoFirst' + ListName + suffix,
3419 inputListName=
'eta:EtaVeto' + ListName + suffix,
3420 cut=
'extraInfo(EtaVetoRank)==1',
3422 variableToSignalSideExtraInfo(
'eta:EtaVetoFirst' + ListName + suffix,
3423 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoName + suffix}, path=roe_path)
3424 cutAndCopyList(outputListName=
'eta:EtaVetoSecond' + ListName + suffix,
3425 inputListName=
'eta:EtaVeto' + ListName + suffix,
3426 cut=
'extraInfo(EtaVetoRank)==2',
3428 variableToSignalSideExtraInfo(
'eta:EtaVetoSecond' + ListName + suffix,
3429 {
'extraInfo(' + EtaExtraInfoName +
')':
'second' + EtaExtraInfoName + suffix}, path=roe_path)
3431 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
3434def lowEnergyPi0Identification(pi0List, gammaList, payloadNameSuffix,
3437 Calculate low-energy pi0 identification.
3438 The result is stored
as ExtraInfo ``lowEnergyPi0Identification``
for
3442 pi0List (str): Pi0 list.
3444 gammaList (str): Gamma list. First, an energy cut E > 0.2
is applied to the photons
from this list.
3445 Then, all possible combinations
with a pi0 daughter photon are formed
except the one
3446 corresponding to the reconstructed pi0.
3447 The maximum low-energy pi0 veto value
is calculated
for such photon pairs
3448 and used
as one of the input variables
for the identification classifier.
3450 payloadNameSuffix (str): Payload name suffix. The weight payloads are stored
in the analysis
global
3451 tag
and have the following names:\n
3452 * ``
'LowEnergyPi0Veto' + payloadNameSuffix``
3453 * ``
'LowEnergyPi0Identification' + payloadNameSuffix``\n
3454 The possible suffixes are:\n
3455 * ``
'Belle1'``
for Belle data.
3456 * ``
'Belle2Release5'``
for Belle II release 5 data (MC14, proc12, buckets 16 - 25).
3457 * ``
'Belle2Release6'``
for Belle II release 6 data (MC15, proc13, buckets 26 - 36).
3459 path (basf2.Path): Module path.
3463 gammaListVeto = f
'{gammaList}_pi0veto'
3464 cutAndCopyList(gammaListVeto, gammaList,
'E > 0.2', path=path)
3466 payload_name =
'LowEnergyPi0Veto' + payloadNameSuffix
3467 path.add_module(
'LowEnergyPi0VetoExpert', identifier=payload_name,
3468 VetoPi0Daughters=
True, GammaListName=gammaListVeto,
3470 payload_name =
'LowEnergyPi0Identification' + payloadNameSuffix
3471 path.add_module(
'LowEnergyPi0IdentificationExpert',
3472 identifier=payload_name, Pi0ListName=pi0List,
3476def getNeutralHadronGeomMatches(
3480 efficiencyCorrectionKl=0.83,
3481 efficiencyCorrectionNeutrons=1.0,
3484 For an ECL-based list, assign the mcdistanceKL and mcdistanceNeutron variables that correspond
3485 to the distance to the closest MC KL
and neutron, respectively.
3486 @param particleLists the input ParticleLists, must be ECL-based lists (e.g. photons)
3487 @param addKL (default
True) add distance to MC KL
3488 @param addNeutrons (default
False) add distance to MC neutrons
3489 @param efficiencyCorrectionKl (default 0.83) apply overall efficiency correction
3490 @param efficiencyCorrectionNeutrons (default 1.0) apply overall efficiency correction
3491 @param path modules are added to this path
3493 from ROOT
import Belle2
3498 "NeutralHadronMatcher",
3499 particleLists=particleLists,
3500 mcPDGcode=Const.Klong.getPDGCode(),
3501 efficiencyCorrection=efficiencyCorrectionKl)
3504 "NeutralHadronMatcher",
3505 particleLists=particleLists,
3506 mcPDGcode=Const.neutron.getPDGCode(),
3507 efficiencyCorrection=efficiencyCorrectionNeutrons)
3510def getBeamBackgroundProbability(particleList, weight, path=None):
3512 Assign a probability to each ECL cluster as being signal like (1) compared to beam background like (0)
3513 @param particleList the input ParticleList, must be a photon list
3514 @param weight type of weight file to use
3515 @param path modules are added to this path
3520 B2WARNING(
"weight type must be 'Belle' for b2bii.")
3522 path.add_module(
'MVAExpert',
3523 listNames=particleList,
3524 extraInfoName=
'beamBackgroundSuppression',
3525 identifier=f
'BeamBackgroundMVA_{weight}')
3528def getFakePhotonProbability(particleList, weight, path=None):
3530 Assign a probability to each ECL cluster as being signal like (1) compared to fake photon like (0)
3531 @param particleList the input ParticleList, must be a photon list
3532 @param weight type of weight file to use
3533 @param path modules are added to this path
3538 B2WARNING(
"weight type must be 'Belle' for b2bii.")
3540 path.add_module(
'MVAExpert',
3541 listNames=particleList,
3542 extraInfoName=
'fakePhotonSuppression',
3543 identifier=f
'FakePhotonMVA_{weight}')
3546def buildEventKinematics(inputListNames=None, default_cleanup=True, custom_cuts=None,
3547 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
3549 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3550 using ParticleLists provided. If no ParticleList
is provided, default ParticleLists are used
3551 (all track
and all hits
in ECL without associated track).
3553 The visible energy missing values are
3554 stored
in a EventKinematics dataobject.
3556 @param inputListNames list of ParticleLists used to calculate the
global event kinematics.
3557 If the list
is empty, default ParticleLists pi+:evtkin
and gamma:evtkin are filled.
3558 @param fillWithMostLikely
if True, the module uses the most likely particle mass hypothesis
for charged particles
3559 according to the PID likelihood
and the option inputListNames will be ignored.
3560 @param chargedPIDPriors The prior PID fractions, that are used to regulate
3561 amount of certain charged particle species, should be a list of
3562 six floats
if not None. The order of particle types
is
3563 the following: [e-, mu-, pi-, K-, p+, d+]
3564 @param default_cleanup
if True and either inputListNames empty
or fillWithMostLikely
True, default clean up cuts are applied
3565 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default
is None,
3566 which would result
in a standard predefined selection cuts
3567 @param path modules are added to this path
3570 if inputListNames
is None:
3572 trackCuts =
'pt > 0.1'
3573 trackCuts +=
' and thetaInCDCAcceptance'
3574 trackCuts +=
' and abs(dz) < 3'
3575 trackCuts +=
' and dr < 0.5'
3577 gammaCuts =
'E > 0.05'
3578 gammaCuts +=
' and thetaInCDCAcceptance'
3580 gammaCuts +=
' and abs(clusterTiming) < 200'
3581 if (custom_cuts
is not None):
3582 trackCuts, gammaCuts = custom_cuts
3584 if fillWithMostLikely:
3585 from stdCharged
import stdMostLikely
3586 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
3587 inputListNames = [f
'{ptype}:mostlikely_evtkin' for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
3589 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3591 fillParticleList(
'gamma:evtkin',
'', path=path)
3592 inputListNames += [
'gamma:evtkin']
3594 B2INFO(
"Using default cleanup in EventKinematics module.")
3595 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
3596 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
3597 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3599 B2INFO(
"No cleanup in EventKinematics module.")
3600 if not inputListNames:
3601 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
3602 fillParticleList(
'pi+:evtkin',
'', path=path)
3604 copyList(
'gamma:evtkin',
'gamma:mdst', path=path)
3606 fillParticleList(
'gamma:evtkin',
'', path=path)
3607 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
3609 if (custom_cuts
is not None):
3610 B2INFO(
"Using default cleanup in EventKinematics module.")
3611 applyCuts(
'pi+:evtkin', trackCuts, path=path)
3612 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
3614 B2INFO(
"No cleanup in EventKinematics module.")
3616 particleLists = inputListNames
3618 eventKinematicsModule = register_module(
'EventKinematics')
3619 eventKinematicsModule.set_name(
'EventKinematics_reco')
3620 eventKinematicsModule.param(
'particleLists', particleLists)
3621 path.add_module(eventKinematicsModule)
3624def buildEventKinematicsFromMC(inputListNames=None, selectionCut='', path=None):
3626 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
3627 using generated particles. If no ParticleList
is provided, default generated ParticleLists are used.
3629 @param inputListNames list of ParticleLists used to calculate the
global event kinematics.
3630 If the list
is empty, default ParticleLists are filled.
3631 @param selectionCut optional selection cuts
3632 @param path Path to append the eventKinematics module to.
3635 if inputListNames
is None:
3637 if (len(inputListNames) == 0):
3641 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
3644 fillParticleListFromMC(f
"{t}:evtkin_default_gen",
'mcPrimary > 0 and nDaughters == 0',
3645 True,
True, path=path)
3646 if (selectionCut !=
''):
3647 applyCuts(f
"{t}:evtkin_default_gen", selectionCut, path=path)
3648 inputListNames += [f
"{t}:evtkin_default_gen"]
3650 eventKinematicsModule = register_module(
'EventKinematics')
3651 eventKinematicsModule.set_name(
'EventKinematics_gen')
3652 eventKinematicsModule.param(
'particleLists', inputListNames)
3653 eventKinematicsModule.param(
'usingMC',
True)
3654 path.add_module(eventKinematicsModule)
3657def buildEventShape(inputListNames=None,
3658 default_cleanup=True,
3664 harmonicMoments=True,
3668 checkForDuplicates=False,
3671 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
3672 using the particles in the lists provided by the user. If no particle list
is provided,
3673 the function will internally create a list of good tracks
and a list of good photons
3674 with (optionally) minimal quality cuts.
3677 The results of the calculation are then stored into the EventShapeContainer dataobject,
3678 and are accessible using the variables of the EventShape group.
3680 The user can switch the calculation of certain quantities on
or off to save computing
3681 time. By default the calculation of the high-order moments (5-8)
is turned off.
3682 Switching off an option will make the corresponding variables
not available.
3685 The user can provide
as many particle lists
as needed, using also composite particles.
3686 In these cases, it
is recommended to activate the checkForDuplicates flag since it
3687 will eliminate duplicates, e.g.,
if the same track
is provided multiple times
3688 (either
with different mass hypothesis
or once
as an independent particle
and once
3689 as daughter of a composite particle). The first occurrence will be used
in the
3690 calculations so the order
in which the particle lists are given
as well
as within
3691 the particle lists matters.
3693 @param inputListNames List of ParticleLists used to calculate the
3694 event shape variables. If the list
is empty the default
3695 particleLists pi+:evtshape
and gamma:evtshape are filled.
3696 @param default_cleanup If
True, applies standard cuts on pt
and cosTheta when
3697 defining the internal lists. This option
is ignored
if the
3698 particleLists are provided by the user.
3699 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default
is None,
3700 which would result
in a standard predefined selection cuts
3701 @param path Path to append the eventShape modules to.
3702 @param thrust Enables the calculation of thrust-related quantities (CLEO
3703 cones, Harmonic moments, jets).
3704 @param collisionAxis Enables the calculation of the quantities related to the
3706 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
3707 @param harmonicMoments Enables the calculation of the Harmonic moments
with respect
3708 to both the thrust axis
and,
if collisionAxis =
True, the collision axis.
3709 @param allMoments If
True, calculates also the FW
and harmonic moments
from order
3710 5 to 8 instead of the low-order ones only.
3711 @param cleoCones Enables the calculation of the CLEO cones
with respect to both the thrust
3712 axis
and,
if collisionAxis =
True, the collision axis.
3713 @param jets Enables the calculation of the hemisphere momenta
and masses.
3714 Requires thrust =
True.
3715 @param sphericity Enables the calculation of the sphericity-related quantities.
3716 @param checkForDuplicates Perform a check
for duplicate particles before adding them. Regardless of the value of this option,
3717 it
is recommended to consider sanitizing the lists you are passing to the function since this will
3718 speed up the processing.
3722 if inputListNames
is None:
3724 trackCuts =
'pt > 0.1'
3725 trackCuts +=
' and thetaInCDCAcceptance'
3726 trackCuts +=
' and abs(dz) < 3.0'
3727 trackCuts +=
' and dr < 0.5'
3729 gammaCuts =
'E > 0.05'
3730 gammaCuts +=
' and thetaInCDCAcceptance'
3732 gammaCuts +=
' and abs(clusterTiming) < 200'
3733 if (custom_cuts
is not None):
3734 trackCuts, gammaCuts = custom_cuts
3736 if not inputListNames:
3737 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
3738 fillParticleList(
'pi+:evtshape',
'', path=path)
3740 copyList(
'gamma:evtshape',
'gamma:mdst', path=path)
3746 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
3749 if (custom_cuts
is not None):
3750 B2INFO(
"Applying standard cuts")
3751 applyCuts(
'pi+:evtshape', trackCuts, path=path)
3753 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
3755 B2WARNING(
"Creating the default lists with no cleanup.")
3757 particleLists = inputListNames
3759 eventShapeModule = register_module(
'EventShapeCalculator')
3760 eventShapeModule.set_name(
'EventShape')
3761 eventShapeModule.param(
'particleListNames', particleLists)
3762 eventShapeModule.param(
'enableAllMoments', allMoments)
3763 eventShapeModule.param(
'enableCleoCones', cleoCones)
3764 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
3765 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
3766 eventShapeModule.param(
'enableJets', jets)
3767 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
3768 eventShapeModule.param(
'enableSphericity', sphericity)
3769 eventShapeModule.param(
'enableThrust', thrust)
3770 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
3772 path.add_module(eventShapeModule)
3775def labelTauPairMC(printDecayInfo=False, path=None, TauolaBelle=False, mapping_minus=None, mapping_plus=None):
3777 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
3778 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
3780 @param printDecayInfo: If true, prints ID
and prong of each tau lepton
in the event.
3781 @param path: module
is added to this path
3782 @param TauolaBelle:
if False, TauDecayMode
is set. If
True, TauDecayMarker
is set.
3783 @param mapping_minus:
if None, the map
is the default one,
else the path
for the map
is given by the user
for tau-
3784 @param mapping_plus:
if None, the map
is the default one,
else the path
for the map
is given by the user
for tau+
3787 from basf2
import find_file
3793 m_printmode =
'default'
3795 if mapping_minus
is None:
3796 mp_file_minus = find_file(
'data/analysis/modules/TauDecayMode/map_tauminus.txt')
3798 mp_file_minus = mapping_minus
3800 if mapping_plus
is None:
3801 mp_file_plus = find_file(
'data/analysis/modules/TauDecayMode/map_tauplus.txt')
3803 mp_file_plus = mapping_plus
3805 path.add_module(
'TauDecayMode', printmode=m_printmode, file_minus=mp_file_minus, file_plus=mp_file_plus)
3808 tauDecayMarker = register_module(
'TauDecayMarker')
3809 tauDecayMarker.set_name(
'TauDecayMarker_')
3811 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
3814def tagCurlTracks(particleLists,
3824 The cut selector is not calibrated
with Belle II data
and should
not be used without extensive study.
3826 Identifies curl tracks
and tags them
with extraInfo(isCurl=1)
for later removal.
3827 For Belle data
with a `b2bii` analysis the available cut based selection
is described
in `BN1079`_.
3829 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
3832 The module loops over all particles
in a given list
with a transverse momentum below the pre-selection **ptCut**
3833 and assigns them to bundles based on the response of the chosen **selector**
and the required minimum response set by the
3834 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
3835 with extraInfo(isCurl=1) to allow
for later removal by cutting the list
or removing these
from ROE
as
3839 @param particleLists: list of particle lists to check
for curls.
3840 @param mcTruth: bool flag to additionally assign particles
with extraInfo(isTruthCurl)
and
3841 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
3842 genParticleIndex then ranked
and tagged
as normal.
3843 @param responseCut: float min classifier response that considers two tracks to come
from the same particle.
3844 If set to ``-1`` a cut value optimised to maximise the accuracy on a BBbar sample
is used.
3845 Note
'cut' selector
is binary 0/1.
3846 @param selectorType: string name of selector to use. The available options are
'cut' and 'mva'.
3847 It
is strongly recommended to used the
'mva' selection. The
'cut' selection
3848 is based on BN1079
and is only calibrated
for Belle data.
3850 @param ptCut: Pre-selection cut on transverse momentum. Only tracks below that are considered
as curler candidates.
3852 @param expert_train: flag to set training mode
if selector has a training mode (mva).
3853 @param expert_filename: set file name of produced training ntuple (mva).
3854 @param path: module
is added to this path.
3860 if (
not isinstance(particleLists, list)):
3861 particleLists = [particleLists]
3863 curlTagger = register_module(
'CurlTagger')
3864 curlTagger.set_name(
'CurlTagger_')
3865 curlTagger.param(
'particleLists', particleLists)
3866 curlTagger.param(
'belle', belle)
3867 curlTagger.param(
'mcTruth', mcTruth)
3868 curlTagger.param(
'responseCut', responseCut)
3869 if abs(responseCut + 1) < 1e-9:
3870 curlTagger.param(
'usePayloadCut',
True)
3872 curlTagger.param(
'usePayloadCut',
False)
3874 curlTagger.param(
'selectorType', selectorType)
3875 curlTagger.param(
'ptCut', ptCut)
3876 curlTagger.param(
'train', expert_train)
3877 curlTagger.param(
'trainFilename', expert_filename)
3879 path.add_module(curlTagger)
3882def applyChargedPidMVA(particleLists, path, trainingMode, chargeIndependent=False, binaryHypoPDGCodes=(0, 0)):
3884 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
3886 The module decorates Particle objects
in the input ParticleList(s)
with variables
3887 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
3890 The MVA algorithm used
is a gradient boosted decision tree (**TMVA 4.3.0**, **ROOT 6.20/04**).
3892 The module can perform either
'binary' PID between input S, B particle mass hypotheses according to the following scheme:
3894 * e (11) vs. pi (211)
3895 * mu (13) vs. pi (211)
3896 * pi (211) vs. K (321)
3897 * K (321) vs. pi (211)
3899 ,
or 'global' PID, namely
"one-vs-others" separation. The latter exploits an MVA algorithm trained
in multi-
class mode,
3900 and it
's the default behaviour. Currently, the multi-class training separates the following standard charged hypotheses:
3902 - e (11), mu (13), pi (211), K (321)
3905 In order to run the `ChargedPidMVA` and ensure the most up-to-date MVA training weights are applied,
3906 it
is necessary to append the latest analysis
global tag (GT) to the steering script.
3909 particleLists (list(str)): the input list of DecayStrings, where each selected (^) daughter should correspond to a
3910 standard charged ParticleList, e.g. ``[
'Lambda0:sig -> ^p+ ^pi-',
'J/psi:sig -> ^mu+ ^mu-']``.
3911 One can also directly
pass a list of standard charged ParticleLists,
3912 e.g. ``[
'e+:my_electrons',
'pi+:my_pions']``.
3913 Note that charge-conjugated ParticleLists will automatically be included.
3914 path (basf2.Path): the module
is added to this path.
3915 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
3916 Needed to pick up the correct payload
from the DB. Available choices:
3918 * c_Classification=0
3920 * c_ECL_Classification=2
3921 * c_ECL_Multiclass=3
3922 * c_PSD_Classification=4
3923 * c_PSD_Multiclass=5
3924 * c_ECL_PSD_Classification=6
3925 * c_ECL_PSD_Multiclass=7
3927 chargeIndependent (bool, ``optional``): use a BDT trained on a sample of inclusively charged particles.
3928 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
3929 Required only
for binary PID mode.
3934 B2ERROR(
"Charged PID via MVA is not available for Belle data.")
3936 from ROOT
import Belle2
3938 TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
3941 plSet = set(particleLists)
3945 TrainingMode.c_Classification:
3946 {
"mode":
"Classification",
"detector":
"ALL"},
3947 TrainingMode.c_Multiclass:
3948 {
"mode":
"Multiclass",
"detector":
"ALL"},
3949 TrainingMode.c_ECL_Classification:
3950 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
3951 TrainingMode.c_ECL_Multiclass:
3952 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
3953 TrainingMode.c_PSD_Classification:
3954 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
3955 TrainingMode.c_PSD_Multiclass:
3956 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
3957 TrainingMode.c_ECL_PSD_Classification:
3958 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
3959 TrainingMode.c_ECL_PSD_Multiclass:
3960 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
3963 if payloadNames.get(trainingMode)
is None:
3964 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
3965 "\nis not supported. Please choose among the following:\n",
3966 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
3968 mode = payloadNames.get(trainingMode).get(
"mode")
3969 detector = payloadNames.get(trainingMode).get(
"detector")
3971 payloadName = f
"ChargedPidMVAWeights_{mode}"
3976 Const.electron.getPDGCode():
3977 {
"pName":
"e",
"pFullName":
"electron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3978 Const.muon.getPDGCode():
3979 {
"pName":
"mu",
"pFullName":
"muon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3980 Const.pion.getPDGCode():
3981 {
"pName":
"pi",
"pFullName":
"pion",
"pNameBkg":
"K",
"pdgIdBkg": Const.kaon.getPDGCode()},
3982 Const.kaon.getPDGCode():
3983 {
"pName":
"K",
"pFullName":
"kaon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3984 Const.proton.getPDGCode():
3985 {
"pName":
"p",
"pFullName":
"proton",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3986 Const.deuteron.getPDGCode():
3987 {
"pName":
"d",
"pFullName":
"deuteron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3990 if binaryHypoPDGCodes == (0, 0):
3993 chargedpid = register_module(
"ChargedPidMVAMulticlass")
3994 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
4001 binaryOpts = [(pdgIdSig, info[
"pdgIdBkg"])
for pdgIdSig, info
in stdChargedMap.items()]
4003 if binaryHypoPDGCodes
not in binaryOpts:
4004 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
4005 ". Please choose among the following pairs:\n",
4006 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
4010 if not decayDescriptor.init(name):
4011 raise ValueError(f
"Invalid particle list {name} in applyChargedPidMVA!")
4012 msg = f
"Input ParticleList: {name}"
4013 pdgs = [abs(decayDescriptor.getMother().getPDGCode())]
4014 daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
4015 if len(daughter_pdgs) > 0:
4016 pdgs = daughter_pdgs
4017 for idaughter, pdg
in enumerate(pdgs):
4018 if abs(pdg)
not in binaryHypoPDGCodes:
4020 msg = f
"Selected daughter {idaughter} in ParticleList: {name}"
4022 f
"{msg} (PDG={pdg}) is neither signal ({binaryHypoPDGCodes[0]}) nor background ({binaryHypoPDGCodes[1]}).")
4024 chargedpid = register_module(
"ChargedPidMVA")
4025 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
4026 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
4027 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
4029 chargedpid.param(
"particleLists", list(plSet))
4030 chargedpid.param(
"payloadName", payloadName)
4031 chargedpid.param(
"chargeIndependent", chargeIndependent)
4034 if detector ==
"ECL":
4035 chargedpid.param(
"useECLOnlyTraining",
True)
4037 path.add_module(chargedpid)
4040def calculateTrackIsolation(
4044 reference_list_name=None,
4045 vars_for_nearest_part=[],
4046 highest_prob_mass_for_ext=True,
4047 exclude_pid_det_weights=False):
4049 Given an input decay string, compute variables that quantify track helix-based isolation of the charged
4050 stable particles in the input decay chain.
4053 An
"isolation score" can be defined using the distance
4054 of each particle to its closest neighbour, defined
as the segment connecting the two
4055 extrapolated track helices intersection points on a given cylindrical surface.
4056 The distance variables defined
in the `VariableManager`
is named `minET2ETDist`,
4057 the isolation scores are named `minET2ETIsoScore`, `minET2ETIsoScoreAsWeightedAvg`.
4059 The definition of distance
and the number of distances that are calculated per sub-detector
is based on
4060 the following recipe:
4062 * **CDC**:
as the segmentation
is very coarse along :math:`z`,
4063 the distance
is defined
as the cord length on the :math:`(\\rho=R, \\phi)` plane.
4064 A total of 9 distances are calculated: the cylindrical surfaces are defined at radiuses
4065 that correspond to the positions of the 9 CDC wire superlayers: :math:`R_{i}^{\\mathrm{CDC}}~(i \\
in \\{0,...,8\\})`.
4067 * **TOP**:
as there
is no segmentation along :math:`z`,
4068 the distance
is defined
as the cord length on the :math:`(\\rho=R, \\phi)` plane.
4069 Only one distance at the TOP entry radius :math:`R_{0}^{\\mathrm{TOP}}`
is calculated.
4071 * **ARICH**:
as there
is no segmentation along :math:`z`,
4072 the distance
is defined
as the distance on the :math:`(\\rho=R, \\phi)` plane at fixed :math:`z=Z`.
4073 Only one distance at the ARICH photon detector entry coordinate :math:`Z_{0}^{\\mathrm{ARICH}}`
is calculated.
4075 * **ECL**: the distance
is defined on the :math:`(\\rho=R, \\phi, z)` surface
in the barrel,
4076 on the :math:`(\\rho, \\phi, z=Z)` surface
in the endcaps.
4077 Two distances are calculated: one at the ECL entry surface :math:`R_{0}^{\\mathrm{ECL}}` (barrel),
4078 :math:`Z_{0}^{\\mathrm{ECL}}` (endcaps),
and one at :math:`R_{1}^{\\mathrm{ECL}}` (barrel),
4079 :math:`Z_{1}^{\\mathrm{ECL}}` (endcaps), corresponding roughly to the mid-point
4080 of the longitudinal size of the crystals.
4082 * **KLM**: the distance
is defined on the :math:`(\\rho=R, \\phi, z)` surface
in the barrel,
4083 on the :math:`(\\rho, \\phi, z=Z)` surface
in the endcaps.
4084 Only one distance at the KLM first strip entry surface :math:`R_{0}^{\\mathrm{KLM}}` (barrel),
4085 :math:`Z_{0}^{\\mathrm{KLM}}` (endcaps)
is calculated.
4088 decay_string (str): name of the input decay string
with selected charged stable daughters,
4089 for example: ``Lambda0:merged -> ^p+ ^pi-``.
4090 Alternatively, it can be a particle list
for charged stable particles
4091 as defined
in ``Const::chargedStableSet``,
for example: ``mu+:all``.
4092 The charge-conjugate particle list will be also processed automatically.
4093 path (basf2.Path): path to which module(s) will be added.
4094 *detectors: detectors
for which track isolation variables will be calculated.
4095 Choose among: ``{
'CDC',
'TOP',
'ARICH',
'ECL',
'KLM'}``.
4096 reference_list_name (Optional[str]): name of the input charged stable particle list
for the reference tracks.
4097 By default, the ``:all`` ParticleList of the same type
4098 of the selected particle
in ``decay_string``
is used.
4099 The charge-conjugate particle list will be also processed automatically.
4100 vars_for_nearest_part (Optional[list(str)]): a list of variables to calculate
for the nearest particle
in the reference
4101 list at each detector surface. It uses the metavariable `minET2ETDistVar`.
4102 If unset, only the distances to the nearest neighbour
4103 per detector are calculated.
4104 highest_prob_mass_for_hex (Optional[bool]):
if this option
is set to
True (default), the helix extrapolation
4105 for the particles will use the track fit result
for the most
4106 probable mass hypothesis, namely, the one that gives the highest
4107 chi2Prob of the fit. Otherwise, it uses the mass hypothesis that
4108 corresponds to the particle lists PDG.
4109 exclude_pid_det_weights (Optional[bool]):
if this option
is set to
False (default), the isolation score
4110 calculation will take into account the weight that each detector has on the PID
4111 for the particle species of interest.
4114 dict(int, list(str)): a dictionary mapping the PDG of each reference particle list to its isolation variables.
4119 from ROOT
import Belle2, TDatabasePDG
4122 if not decayDescriptor.init(decay_string):
4123 B2FATAL(f
"Invalid particle list {decay_string} in calculateTrackIsolation!")
4124 no_reference_list_name =
not reference_list_name
4127 "CDC": list(range(9)),
4133 if any(d
not in det_and_layers
for d
in detectors):
4135 "Your input detector list: ",
4137 " contains an invalid choice. Please select among: ",
4139 det_and_layers.keys()))
4144 processed_decay_strings = []
4145 if select_symbol
in decay_string:
4146 splitted_ds = decay_string.split(select_symbol)
4147 for i
in range(decay_string.count(select_symbol)):
4148 tmp = list(splitted_ds)
4149 tmp.insert(i+1, select_symbol)
4150 processed_decay_strings += [
''.join(tmp)]
4152 processed_decay_strings += [decay_string]
4154 reference_lists_to_vars = {}
4156 for processed_dec
in processed_decay_strings:
4157 if no_reference_list_name:
4158 decayDescriptor.init(processed_dec)
4159 selected_daughter_pdgs = decayDescriptor.getSelectionPDGCodes()
4160 if len(selected_daughter_pdgs) > 0:
4161 reference_list_name = f
'{TDatabasePDG.Instance().GetParticle(abs(selected_daughter_pdgs[-1])).GetName()}:all'
4163 reference_list_name = f
'{processed_dec.split(":")[0]}:all'
4167 trackiso = path.add_module(
"TrackIsoCalculator",
4168 decayString=processed_dec,
4169 detectorNames=list(detectors),
4170 particleListReference=reference_list_name,
4171 useHighestProbMassForExt=highest_prob_mass_for_ext,
4172 excludePIDDetWeights=exclude_pid_det_weights)
4173 trackiso.set_name(f
"TrackIsoCalculator_{'_'.join(detectors)}_{processed_dec}_VS_{reference_list_name}")
4179 f
"minET2ETDist({d}, {d_layer}, {reference_list_name}, {int(highest_prob_mass_for_ext)})"
4180 for d
in detectors
for d_layer
in det_and_layers[d]]
4183 f
"minET2ETIsoScore({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4184 f
"minET2ETIsoScoreAsWeightedAvg({reference_list_name}, {int(highest_prob_mass_for_ext)}, {', '.join(detectors)})",
4187 if vars_for_nearest_part:
4188 trackiso_vars.extend(
4190 f
"minET2ETDistVar({d}, {d_layer}, {reference_list_name}, {v})"
4191 for d
in detectors
for d_layer
in det_and_layers[d]
for v
in vars_for_nearest_part
4193 trackiso_vars.sort()
4195 reference_lists_to_vars[ref_pdg] = trackiso_vars
4197 return reference_lists_to_vars
4200def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
4202 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
4203 distance of closest approach between a vertex
and btube. For track, this calculation ignores track curvature,\
4204 it
's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
4205 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
4208 .. code-block:: python
4210 from modularAnalysis
import calculateDistance
4211 calculateDistance(
'list_name',
'decay_string',
"mode", path=user_path)
4213 @param list_name name of the input ParticleList
4214 @param decay_string select particles between the distance of closest approach will be calculated
4215 @param mode Specifies how the distance
is calculated
4216 vertextrack: calculate the distance of closest approach between a track
and a\
4217 vertex, taking the first candidate
as vertex, default
4218 trackvertex: calculate the distance of closest approach between a track
and a\
4219 vertex, taking the first candidate
as track
4220 2tracks: calculates the distance of closest approach between two tracks
4221 2vertices: calculates the distance between two vertices
4222 vertexbtube: calculates the distance of closest approach between a vertex
and btube
4223 trackbtube: calculates the distance of closest approach between a track
and btube
4224 @param path modules are added to this path
4228 dist_mod = register_module('DistanceCalculator')
4230 dist_mod.set_name(
'DistanceCalculator_' + list_name)
4231 dist_mod.param(
'listName', list_name)
4232 dist_mod.param(
'decayString', decay_string)
4233 dist_mod.param(
'mode', mode)
4234 path.add_module(dist_mod)
4237def addInclusiveDstarReconstruction(decayString, slowPionCut, DstarCut, path):
4239 Adds the InclusiveDstarReconstruction module to the given path.
4240 This module creates a D* particle list by estimating the D* four momenta
4241 from slow pions, specified by a given cut. The D* energy
is approximated
4242 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
4243 momentum
is calculated using the D* PDG mass
and the direction
is collinear
4244 to the slow pion direction. The charge of the given pion list has to be consistent
4247 @param decayString Decay string, must be of form ``D* -> pi``
4248 @param slowPionCut Cut applied to the input pion list to identify slow pions
4249 @param DstarCut Cut applied to the output D* list
4250 @param path the module
is added to this path
4253 incl_dstar = register_module("InclusiveDstarReconstruction")
4254 incl_dstar.param(
"decayString", decayString)
4255 incl_dstar.param(
"slowPionCut", slowPionCut)
4256 incl_dstar.param(
"DstarCut", DstarCut)
4257 path.add_module(incl_dstar)
4260def scaleError(outputListName, inputListName,
4261 scaleFactors=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4262 scaleFactorsNoPXD=[1.149631, 1.085547, 1.151704, 1.096434, 1.086659],
4263 d0Resolution=[0.00115328, 0.00134704],
4264 z0Resolution=[0.00124327, 0.0013272],
4269 This module creates a new charged particle list.
4270 The helix errors of the new particles are scaled by constant factors.
4271 Two sets of five scale factors are defined for tracks
with and without a PXD hit.
4272 The scale factors are
in order of (d0, phi0, omega, z0, tanlambda).
4273 For tracks
with a PXD hit,
in order to avoid severe underestimation of d0
and z0 errors,
4274 lower limits (best resolution) can be set
in a momentum-dependent form.
4275 This module
is supposed to be used only
for TDCPV analysis
and for low-momentum (0-3 GeV/c) tracks
in BBbar events.
4276 Details will be documented
in a Belle II note, BELLE2-NOTE-PH-2021-038.
4278 @param inputListName Name of input charged particle list to be scaled
4279 @param outputListName Name of output charged particle list
with scaled error
4280 @param scaleFactors List of five constants to be multiplied to each of helix errors (
for tracks
with a PXD hit)
4281 @param scaleFactorsNoPXD List of five constants to be multiplied to each of helix errors (
for tracks without a PXD hit)
4282 @param d0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4283 defining d0 best resolution
as sqrt{ a**2 + (b / (p*beta*sinTheta**1.5))**2 }
4284 @param z0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
4285 defining z0 best resolution
as sqrt{ a**2 + (b / (p*beta*sinTheta**2.5))**2 }
4286 @param d0MomThr d0 best resolution
is kept constant below this momentum
4287 @param z0MomThr z0 best resolution
is kept constant below this momentum
4291 scale_error = register_module("HelixErrorScaler")
4292 scale_error.set_name(
'ScaleError_' + inputListName)
4293 scale_error.param(
'inputListName', inputListName)
4294 scale_error.param(
'outputListName', outputListName)
4295 scale_error.param(
'scaleFactors_PXD', scaleFactors)
4296 scale_error.param(
'scaleFactors_noPXD', scaleFactorsNoPXD)
4297 scale_error.param(
'd0ResolutionParameters', d0Resolution)
4298 scale_error.param(
'z0ResolutionParameters', z0Resolution)
4299 scale_error.param(
'd0MomentumThreshold', d0MomThr)
4300 scale_error.param(
'z0MomentumThreshold', z0MomThr)
4301 path.add_module(scale_error)
4304def estimateAndAttachTrackFitResult(inputListName, path=None):
4306 Create a TrackFitResult from the momentum of the Particle assuming it originates
from the IP
and make a relation between them.
4307 The covariance, detector hit information,
and fit-related information (pValue, NDF) are assigned meaningless values. The input
4308 Particles must
not have already Track
or TrackFitResult
and thus are supposed to be composite particles, recoil, dummy
4309 particles,
and so on.
4312 .. warning:: Since the source type
is not overwritten
as Track,
not all track-related variables are guaranteed to be available.
4315 @param inputListName Name of input ParticleList
4318 estimator = register_module("TrackFitResultEstimator")
4319 estimator.set_name(
"trackFitResultEstimator_" + inputListName)
4320 estimator.param(
"inputListName", inputListName)
4321 path.add_module(estimator)
4324def correctEnergyBias(inputListNames, tableName, path=None):
4326 Scale energy of the particles according to the scaling factor.
4327 If the particle list contains composite particles, the energy of the daughters are scaled.
4328 Subsequently, the energy of the mother particle is updated
as well.
4331 inputListNames (list(str)): input particle list names
4332 tableName : stored
in localdb
and created using ParticleWeightingLookUpCreator
4333 path (basf2.Path): module
is added to this path
4338 B2ERROR(
"The energy bias cannot be corrected with this tool for Belle data.")
4340 correctenergybias = register_module(
'EnergyBiasCorrection')
4341 correctenergybias.param(
'particleLists', inputListNames)
4342 correctenergybias.param(
'tableName', tableName)
4343 path.add_module(correctenergybias)
4346def twoBodyISRPhotonCorrector(outputListName, inputListName, massiveParticle, path=None):
4348 Sets photon kinematics to corrected values in two body decays
with an ISR photon
4349 and a massive particle. The original photon kinematics are kept
in the input
4350 particleList
and can be accessed using the originalParticle() metavariable on the
4353 @param ouputListName new ParticleList filled
with copied Particles
4354 @param inputListName input ParticleList
with original Particles
4355 @param massiveParticle name
or PDG code of massive particle participating
in the two
4356 body decay
with the ISR photon
4357 @param path modules are added to this path
4361 photon_energy_correction = register_module(
'TwoBodyISRPhotonCorrector')
4362 photon_energy_correction.set_name(
'TwoBodyISRPhotonCorrector_' + outputListName)
4363 photon_energy_correction.param(
'outputGammaList', outputListName)
4364 photon_energy_correction.param(
'inputGammaList', inputListName)
4367 if isinstance(massiveParticle, int):
4368 photon_energy_correction.param(
'massiveParticlePDGCode', massiveParticle)
4370 from ROOT
import Belle2
4372 if not decayDescriptor.init(massiveParticle):
4373 raise ValueError(
"TwoBodyISRPhotonCorrector: value of massiveParticle must be" +
4374 " an int or valid decay string.")
4375 pdgCode = decayDescriptor.getMother().getPDGCode()
4376 photon_energy_correction.param(
'massiveParticlePDGCode', pdgCode)
4378 path.add_module(photon_energy_correction)
4381def addPhotonEfficiencyRatioVariables(inputListNames, tableName, path=None):
4383 Add photon Data/MC detection efficiency ratio weights to the specified particle list
4386 inputListNames (list(str)): input particle list names
4387 tableName : taken from database
with appropriate name
4388 path (basf2.Path): module
is added to this path
4393 B2ERROR(
"For Belle data the photon data/MC detection efficiency ratio is not available with this tool.")
4395 photon_efficiency_correction = register_module(
'PhotonEfficiencySystematics')
4396 photon_efficiency_correction.param(
'particleLists', inputListNames)
4397 photon_efficiency_correction.param(
'tableName', tableName)
4398 path.add_module(photon_efficiency_correction)
4401def addPi0VetoEfficiencySystematics(particleList, decayString, tableName, threshold, mode='standard', suffix='', path=None):
4403 Add pi0 veto Data/MC efficiency ratio weights to the specified particle list
4405 @param particleList the input ParticleList
4406 @param decayString specify hard photon to be performed pi0 veto (e.g.
'B+:sig -> rho+:sig ^gamma:hard')
4407 @param tableName table name corresponding to payload version (e.g.
'Pi0VetoEfficiencySystematics_Mar2022')
4408 @param threshold pi0 veto threshold (0.10, 0.11, ..., 0.99)
4409 @param mode choose one mode (same
as writePi0EtaVeto) out of
'standard',
'tight',
'cluster' and 'both'
4410 @param suffix optional suffix to be appended to the usual extraInfo name
4411 @param path the module
is added to this path
4413 The following extraInfo are available related
with the given particleList:
4415 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_ratio : weight of Data/MC
for the veto efficiency
4416 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_stat : the statistical uncertainty of the weight
4417 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_sys : the systematic uncertainty of the weight
4418 * Pi0VetoEfficiencySystematics_{mode}{suffix}_data_MC_uncertainty_total : the total uncertainty of the weight
4419 * Pi0VetoEfficiencySystematics_{mode}{suffix}_threshold : threshold of the pi0 veto
4424 B2ERROR(
"For Belle data the pi0 veto data/MC efficiency ratio weights are not available via this tool.")
4426 pi0veto_efficiency_correction = register_module(
'Pi0VetoEfficiencySystematics')
4427 pi0veto_efficiency_correction.param(
'particleLists', particleList)
4428 pi0veto_efficiency_correction.param(
'decayString', decayString)
4429 pi0veto_efficiency_correction.param(
'tableName', tableName)
4430 pi0veto_efficiency_correction.param(
'threshold', threshold)
4431 pi0veto_efficiency_correction.param(
'mode', mode)
4432 pi0veto_efficiency_correction.param(
'suffix', suffix)
4433 path.add_module(pi0veto_efficiency_correction)
4436def getAnalysisGlobaltag(timeout=180) -> str:
4438 Returns a string containing the name of the latest and recommended analysis globaltag.
4441 timeout: Seconds to wait
for b2conditionsdb-recommend
4446 B2ERROR(
"The getAnalysisGlobaltag() function cannot be used for Belle data.")
4451 tags = subprocess.check_output(
4452 [
'b2conditionsdb-recommend',
'--oneline'],
4454 ).decode(
'UTF-8').rstrip().split(
' ')
4457 if tag.startswith(
'analysis_tools'):
4461 except subprocess.TimeoutExpired
as te:
4462 B2FATAL(f
'A {te} exception was raised during the call of getAnalysisGlobaltag(). '
4463 'The function took too much time to retrieve the requested information '
4464 'from the versioning repository.\n'
4465 'Please try to re-run your job. In case of persistent failures, there may '
4466 'be issues with the DESY collaborative services, so please contact the experts.')
4467 except subprocess.CalledProcessError
as ce:
4468 B2FATAL(f
'A {ce} exception was raised during the call of getAnalysisGlobaltag(). '
4469 'Please try to re-run your job. In case of persistent failures, please contact '
4473def getAnalysisGlobaltagB2BII() -> str:
4475 Get recommended global tag
for B2BII analysis.
4480 B2ERROR(
'The getAnalysisGlobaltagB2BII() function cannot be used for Belle II data.')
4481 from versioning
import recommended_b2bii_analysis_global_tag
4482 return recommended_b2bii_analysis_global_tag()
4485def getNbarIDMVA(particleList: str, path=
None):
4487 This function can give a score to predict if it
is a anti-n0.
4488 It
is not used to predict n0.
4489 Currently, this can be used only
for ECL cluster.
4490 output will be stored
in extraInfo(nbarID); -1 means MVA invalid
4492 @param particleList The input ParticleList name
or a decay string which contains a full mother particle list name.
4493 Only one selected daughter
is supported.
4494 @param path modules are added to this path
4497 from ROOT
import Belle2
4500 B2ERROR(
"The MVA-based anti-neutron PID is only available for Belle II data.")
4502 from variables
import variables
4504 variables.addAlias(
'V1',
'clusterHasPulseShapeDiscrimination')
4505 variables.addAlias(
'V2',
'clusterE')
4506 variables.addAlias(
'V3',
'clusterLAT')
4507 variables.addAlias(
'V4',
'clusterE1E9')
4508 variables.addAlias(
'V5',
'clusterE9E21')
4509 variables.addAlias(
'V6',
'clusterZernikeMVA')
4510 variables.addAlias(
'V7',
'clusterAbsZernikeMoment40')
4511 variables.addAlias(
'V8',
'clusterAbsZernikeMoment51')
4515 'passesCut(V1 == 1 and V2 >= 0 and V3 >= 0 and V4 >= 0 and V5 >= 0 and V6 >= 0 and V7 >= 0 and V8 >= 0)')
4516 variables.addAlias(
'nbarIDmod',
'conditionalVariableSelector(nbarIDValid == 1, extraInfo(nbarIDFromMVA), constant(-1.0))')
4518 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'nbarIDFromMVA', identifier=
'db_nbarIDECL')
4520 if not decayDescriptor.init(particleList):
4521 raise ValueError(f
"Provided decay string is invalid: {particleList}")
4522 if decayDescriptor.getNDaughters() == 0:
4525 listname = decayDescriptor.getMother().getFullName()
4526 variablesToDaughterExtraInfo(listname, particleList, {
'nbarIDmod':
'nbarID'}, option=2, path=path)
4529def reconstructDecayWithNeutralHadron(decayString, cut, allowGamma=False, allowAnyParticleSource=False, path=None, **kwargs):
4531 Reconstructs decay with a long-lived neutral hadron e.g.
4532 :math:`B^0 \to J/\psi K_L^0`,
4533 :math:`B^0 \to p \bar{n} D^*(2010)^-`.
4535 The calculation
is done
with IP constraint
and mother mass constraint.
4537 The decay string passed
in must satisfy the following rules:
4539 - The neutral hadron must be **selected**
in the decay string
with the
4540 caret (``^``) e.g. ``B0:sig -> J/psi:sig ^K_L0:sig``. (Note the caret
4541 next to the neutral hadron.)
4542 - There can only be **one neutral hadron
in a decay**.
4543 - The neutral hadron has to be a direct daughter of its mother.
4545 .. note:: This function forwards its arguments to `reconstructDecay`,
4546 so please check the documentation of `reconstructDecay`
for all
4549 @param decayString A decay string following the mentioned rules
4550 @param cut Cut to apply to the particle list
4551 @param allowGamma Whether allow the selected particle to be ``gamma``
4552 @param allowAnyParticleSource Whether allow the selected particle to be
from any source.
4553 Should only be used when studying control sample.
4554 @param path The path to put
in the module
4557 reconstructDecay(decayString, cut, path=path, **kwargs)
4558 module = register_module('NeutralHadron4MomentumCalculator')
4559 module.set_name(
'NeutralHadron4MomentumCalculator_' + decayString)
4560 module.param(
'decayString', decayString)
4561 module.param(
'allowGamma', allowGamma)
4562 module.param(
'allowAnyParticleSource', allowAnyParticleSource)
4563 path.add_module(module)
4566def updateMassHypothesis(particleList, pdg, writeOut=False, path=None):
4568 Module to update the mass hypothesis of a given input particle list with the chosen PDG.
4569 A new particle list
is created
with updated mass hypothesis.
4570 The allowed mass hypotheses
for both input
and output are electrons, muons, pions, kaons
and protons.
4573 The new particle list
is named after the input one,
with the additional suffix ``_converted_from_OLDHYPOTHESIS``,
4574 e.g. ``e+:all`` converted to muons becomes ``mu+:all_converted_from_e``.
4576 @param particleList The input particle list name
4577 @param pdg The PDG code
for the new mass hypothesis,
in [11, 13, 211, 321, 2212]
4578 @param writeOut Whether `RootOutput` module should save the new particle list
4579 @param path Modules are added to this path
4581 mass_updater = register_module("ParticleMassHypothesesUpdater")
4582 mass_updater.set_name(
"ParticleMassHypothesesUpdater_" + particleList +
"_to_" + str(pdg))
4583 mass_updater.param(
"particleList", particleList)
4584 mass_updater.param(
"writeOut", writeOut)
4585 mass_updater.param(
"pdgCode", pdg)
4586 path.add_module(mass_updater)
4589func_requiring_analysisGT = [
4590 correctTrackEnergy, scaleTrackMomenta, smearTrackMomenta, oldwritePi0EtaVeto, writePi0EtaVeto, lowEnergyPi0Identification,
4591 getBeamBackgroundProbability, getFakePhotonProbability, tagCurlTracks, applyChargedPidMVA, correctEnergyBias,
4592 addPhotonEfficiencyRatioVariables, addPi0VetoEfficiencySystematics, getNbarIDMVA]
4593for _
in func_requiring_analysisGT:
4594 _.__doc__ +=
"\n .. note:: This function (optionally) requires a payload stored in the analysis GlobalTag. "\
4595 "Please append or prepend the latest one from `getAnalysisGlobaltag` or `getAnalysisGlobaltagB2BII`.\n"
4598if __name__ ==
'__main__':
4600 pretty_print_module(__name__,
"modularAnalysis")
tuple parse(str cut, verbose=False)
This class provides a set of constants for the framework.
The DecayDescriptor stores information about a decay tree or parts of a decay tree.
Describe one component of the Geometry.
static DBStore & Instance()
Instance of a singleton DBStore.
def add_mdst_output(path, mc=True, filename='mdst.root', additionalBranches=[], dataDescription=None)
def add_udst_output(path, filename, particleLists=None, additionalBranches=None, dataDescription=None, mc=True)