12 This module defines wrapper functions around the analysis modules.
15 from basf2
import register_module, create_path
16 from basf2
import B2INFO, B2WARNING, B2ERROR, B2FATAL
21 def setAnalysisConfigParams(configParametersAndValues, path):
23 Sets analysis configuration parameters.
27 - 'tupleStyle': 'Default' (default) or 'Laconic'
28 o) defines the style of the branch name in the ntuple
30 - 'mcMatchingVersion': Specifies what version of mc matching algorithm is going to be used:
32 - 'MC5' - analysis of BelleII MC5
33 - 'Belle' - analysis of Belle MC
34 - 'BelleII' (default) - all other cases
36 @param configParametersAndValues dictionary of parameters and their values of the form {param1: value, param2: value, ...)
37 @param modules are added to this path
40 conf = register_module(
'AnalysisConfiguration')
42 allParameters = [
'tupleStyle',
'mcMatchingVersion']
44 keys = configParametersAndValues.keys()
46 if key
not in allParameters:
47 allParametersString =
', '.join(allParameters)
48 B2ERROR(
'Invalid analysis configuration parameter: ' + key +
'.\n'
49 'Please use one of the following: ' + allParametersString)
51 for param
in allParameters:
52 if param
in configParametersAndValues:
53 conf.param(param, configParametersAndValues.get(param))
58 def inputMdst(environmentType, filename, path, skipNEvents=0, entrySequence=None, *, parentLevel=0, **kwargs):
60 Loads the specified ROOT (DST/mDST/muDST) file with the RootInput module.
62 The correct environment (e.g. magnetic field settings) are determined from
63 the specified environment type. For the possible values please see
67 environmentType (str): type of the environment to be loaded
68 filename (str): the name of the file to be loaded
69 path (basf2.Path): modules are added to this path
70 skipNEvents (int): N events of the input file are skipped
71 entrySequence (str): The number sequences (e.g. 23:42,101) defining the entries which are processed.
72 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
74 if entrySequence
is not None:
75 entrySequence = [entrySequence]
77 inputMdstList(environmentType, [filename], path, skipNEvents, entrySequence, parentLevel=parentLevel, **kwargs)
88 useB2BIIDBCache=True):
90 Loads the specified ROOT (DST/mDST/muDST) files with the RootInput module.
92 The correct environment (e.g. magnetic field settings) are determined from the specified environment type.
93 The currently available environments are:
95 - 'MC5': for analysis of Belle II MC samples produced with releases prior to build-2016-05-01.
96 This environment sets the constant magnetic field (B = 1.5 T)
97 - 'MC6': for analysis of Belle II MC samples produced with build-2016-05-01 or newer but prior to release-00-08-00
98 - 'MC7': for analysis of Belle II MC samples produced with build-2016-05-01 or newer but prior to release-00-08-00
99 - 'MC8', for analysis of Belle II MC samples produced with release-00-08-00 or newer but prior to release-02-00-00
100 - 'MC9', for analysis of Belle II MC samples produced with release-00-08-00 or newer but prior to release-02-00-00
101 - 'MC10', for analysis of Belle II MC samples produced with release-00-08-00 or newer but prior to release-02-00-00
102 - 'default': for analysis of Belle II MC samples produced with releases with release-02-00-00 or newer.
103 This environment sets the default magnetic field (see geometry settings)
104 - 'Belle': for analysis of converted (or during of conversion of) Belle MC/DATA samples
105 - 'None': for analysis of generator level information or during simulation/reconstruction of
106 previously generated events
108 Note that there is no difference between MC6 and MC7. Both are given for sake of completion.
109 The same is true for MC8, MC9 and MC10
112 environmentType (str): type of the environment to be loaded
113 filelist (list(str)): the filename list of files to be loaded
114 path (basf2.Path): modules are added to this path
115 skipNEvents (int): N events of the input files are skipped
116 entrySequences (list(str)): The number sequences (e.g. 23:42,101) defining
117 the entries which are processed for each inputFileName.
118 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
119 useB2BIIDBCache (bool): Loading of local KEKCC database (only to be deactivated in very special cases)
122 roinput = register_module(
'RootInput')
123 roinput.param(
'inputFileNames', filelist)
124 roinput.param(
'skipNEvents', skipNEvents)
125 if entrySequences
is not None:
126 roinput.param(
'entrySequences', entrySequences)
127 roinput.param(
'parentLevel', parentLevel)
129 path.add_module(roinput)
130 path.add_module(
'ProgressBar')
134 environToMagneticField = {
'MC5':
'MagneticFieldConstant',
138 'Belle':
'MagneticFieldConstantBelle'}
140 fixECLClusters = {
'MC5':
True,
146 if environmentType
in environToMagneticField:
147 fieldType = environToMagneticField[environmentType]
148 if fieldType
is not None:
149 from ROOT
import Belle2
153 elif environmentType
in [
"MC8",
"MC9",
"MC10"]:
155 from basf2
import conditions
156 conditions.globaltags += [
"Legacy_MagneticField_MC8_MC9_MC10"]
157 elif environmentType ==
'None':
158 B2INFO(
'No magnetic field is loaded. This is OK, if generator level information only is studied.')
160 environments =
' '.join(list(environToMagneticField.keys()) + [
"MC8",
"MC9",
"MC10"])
161 B2FATAL(
'Incorrect environment type provided: ' + environmentType +
'! Please use one of the following:' + environments)
164 if environmentType ==
'Belle':
165 setAnalysisConfigParams({
'mcMatchingVersion':
'Belle'}, path)
169 basf2.conditions.metadata_providers = [
"/sw/belle/b2bii/database/conditions/b2bii.sqlite"]
170 basf2.conditions.payload_locations = [
"/sw/belle/b2bii/database/conditions/"]
172 if environmentType ==
'MC5':
173 setAnalysisConfigParams({
'mcMatchingVersion':
'MC5'}, path)
176 if fixECLClusters.get(environmentType)
is True:
177 fixECL = register_module(
'FixECLClusters')
178 path.add_module(fixECL)
181 def outputMdst(filename, path):
183 Saves mDST (mini-Data Summary Tables) to the output root file.
187 This function is kept for backward-compatibility.
188 Better to use `mdst.add_mdst_output` directly.
196 def outputUdst(filename, particleLists=None, includeArrays=None, path=None, dataDescription=None):
198 Save uDST (user-defined Data Summary Tables) = MDST + Particles + ParticleLists
199 The charge-conjugate lists of those given in particleLists are also stored.
200 Additional Store Arrays and Relations to be stored can be specified via includeArrays
204 This does not reduce the amount of Particle objects saved,
205 see `udst.add_skimmed_udst_output` for a function that does.
210 path=path, filename=filename, particleLists=particleLists,
211 additionalBranches=includeArrays, dataDescription=dataDescription)
214 def outputIndex(filename, path, includeArrays=None, keepParents=False, mc=True):
216 Write out all particle lists as an index file to be reprocessed using parentLevel flag.
217 Additional branches necessary for file to be read are automatically included.
218 Additional Store Arrays and Relations to be stored can be specified via includeArrays
221 @param str filename the name of the output index file
222 @param str path modules are added to this path
223 @param list(str) includeArrays: datastore arrays/objects to write to the output
224 file in addition to particle lists and related information
225 @param bool keepParents whether the parents of the input event will be saved as the parents of the same event
226 in the output index file. Useful if you are only adding more information to another index file
227 @param bool mc whether the input data is MC or not
229 if includeArrays
is None:
233 onlyPLists = register_module(
'OnlyWriteOutParticleLists')
234 path.add_module(onlyPLists)
239 'ParticlesToMCParticles',
240 'ParticlesToPIDLikelihoods',
241 'ParticleExtraInfoMap',
244 branches = [
'EventMetaData']
245 persistentBranches = [
'FileMetaData']
249 branches += partBranches
250 branches += includeArrays
252 r1 = register_module(
'RootOutput')
253 r1.param(
'outputFileName', filename)
254 r1.param(
'additionalBranchNames', branches)
255 r1.param(
'branchNamesPersistent', persistentBranches)
256 r1.param(
'keepParents', keepParents)
260 def setupEventInfo(noEvents, path):
262 Prepare to generate events. This function sets up the EventInfoSetter.
263 You should call this before adding a generator from generators.
264 The experiment and run numbers are set to 0 (run independent generic MC in phase 3).
265 https://confluence.desy.de/display/BI/Experiment+numbering
268 noEvents (int): number of events to be generated
269 path (basf2.Path): modules are added to this path
271 evtnumbers = register_module(
'EventInfoSetter')
272 evtnumbers.param(
'evtNumList', [noEvents])
273 evtnumbers.param(
'runList', [0])
274 evtnumbers.param(
'expList', [0])
275 path.add_module(evtnumbers)
278 def loadGearbox(path, silence_warning=False):
280 Loads Gearbox module to the path.
283 Should be used in a job with *cosmic event generation only*
285 Needed for scripts which only generate cosmic events in order to
288 @param path modules are added to this path
289 @param silence_warning stops a verbose warning message if you know you want to use this function
292 if not silence_warning:
293 B2WARNING(
"""You are overwriting the geometry from the database with Gearbox.
294 This is fine if you're generating cosmic events. But in most other cases you probably don't want this.
296 If you're really sure you know what you're doing you can suppress this message with:
298 >>> loadGearbox(silence_warning=True)
302 paramloader = register_module(
'Gearbox')
303 path.add_module(paramloader)
306 def printPrimaryMCParticles(path, **kwargs):
308 Prints all primary MCParticles, that is particles from
309 the physics generator and not particles created by the simulation
311 This is equivalent to `printMCParticles(onlyPrimaries=True, path=path) <printMCParticles>` and additional
312 keyword arguments are just forwarded to that function
314 return printMCParticles(onlyPrimaries=
True, path=path, **kwargs)
317 def printMCParticles(onlyPrimaries=False, maxLevel=-1, path=None, *,
318 showProperties=False, showMomenta=False, showVertices=False, showStatus=False):
320 Prints all MCParticles or just primary MCParticles up to specified level. -1 means no limit.
322 By default this will print a tree of just the particle names and their pdg
323 codes in the event, for example ::
325 [INFO] Content of MCParticle list
326 ╰── Upsilon(4S) (300553)
328 │ ├── anti-D_0*0 (-10421)
329 │ │ ├── D- (-411)
330 │ │ │ ├── K*- (-323)
331 │ │ │ │ ├── anti-K0 (-311)
332 │ │ │ │ │ ╰── K_S0 (310)
333 │ │ │ │ │ ├── pi+ (211)
334 │ │ │ │ │ │ ╰╶╶ p+ (2212)
335 │ │ │ │ │ ╰── pi- (-211)
336 │ │ │ │ │ ├╶╶ e- (11)
337 │ │ │ │ │ ├╶╶ n0 (2112)
338 │ │ │ │ │ ├╶╶ n0 (2112)
339 │ │ │ │ │ ╰╶╶ n0 (2112)
340 │ │ │ │ ╰── pi- (-211)
341 │ │ │ │ ├╶╶ anti-nu_mu (-14)
342 │ │ │ │ ╰╶╶ mu- (13)
343 │ │ │ │ ├╶╶ nu_mu (14)
344 │ │ │ │ ├╶╶ anti-nu_e (-12)
345 │ │ │ │ ╰╶╶ e- (11)
346 │ │ │ ╰── K_S0 (310)
347 │ │ │ ├── pi0 (111)
348 │ │ │ │ ├── gamma (22)
349 │ │ │ │ ╰── gamma (22)
350 │ │ │ ╰── pi0 (111)
351 │ │ │ ├── gamma (22)
352 │ │ │ ╰── gamma (22)
353 │ │ ╰── pi+ (211)
354 │ ├── mu+ (-13)
355 │ │ ├╶╶ anti-nu_mu (-14)
356 │ │ ├╶╶ nu_e (12)
357 │ │ ╰╶╶ e+ (-11)
358 │ ├── nu_mu (14)
359 │ ╰── gamma (22)
363 There's a distinction between primary and secondary particles. Primary
364 particles are the ones created by the physics generator while secondary
365 particles are ones generated by the simulation of the detector interaction.
367 Secondaries are indicated with a dashed line leading to the particle name
368 and if the output is to the terminal they will be printed in red. If
369 ``onlyPrimaries`` is True they will not be included in the tree.
371 On demand, extra information on all the particles can be displayed by
372 enabling any of the ``showProperties``, ``showMomenta``, ``showVertices``
373 and ``showStatus`` flags. Enabling all of them will look like
378 │ mass=0.14 energy=0.445 charge=-1 lifetime=6.36
379 │ p=(0.257, -0.335, 0.0238) |p|=0.423
380 │ production vertex=(0.113, -0.0531, 0.0156), time=0.00589
381 │ status flags=PrimaryParticle, StableInGenerator, StoppedInDetector
385 mass=0.94 energy=0.94 charge=0 lifetime=5.28e+03
386 p=(-0.000238, -0.0127, 0.0116) |p|=0.0172
387 production vertex=(144, 21.9, -1.29), time=39
388 status flags=StoppedInDetector
389 creation process=HadronInelastic
392 The first line of extra information is enabled by ``showProperties``, the
393 second line by ``showMomenta``, the third line by ``showVertices`` and the
394 last two lines by ``showStatus``. Note that all values are given in Belle II
395 standard units, that is GeV, centimeter and nanoseconds.
397 The depth of the tree can be limited with the ``maxLevel`` argument: If it's
398 bigger than zero it will limit the tree to the given number of generations.
399 A visual indicator will be added after each particle which would have
400 additional daughters that are skipped due to this limit. An example event
401 with ``maxLevel=3`` is given below. In this case only the tau neutrino and
402 the pion don't have additional daughters. ::
404 [INFO] Content of MCParticle list
405 ╰── Upsilon(4S) (300553)
407 │ ├── anti-D*0 (-423) → …
408 │ ├── tau+ (-15) → …
409 │ ╰── nu_tau (16)
411 ├── D*0 (423) → …
412 ├── K*- (-323) → …
413 ├── K*+ (323) → …
418 onlyPrimaries (bool): If True show only primary particles, that is particles coming from
419 the generator and not created by the simulation.
420 maxLevel (int): If 0 or less print the whole tree, otherwise stop after n generations
421 showProperties (bool): If True show mass, energy and charge of the particles
422 showMomenta (bool): if True show the momenta of the particles
423 showVertices (bool): if True show production vertex and production time of all particles
424 showStatus (bool): if True show some status information on the particles.
425 For secondary particles this includes creation process.
428 return path.add_module(
430 onlyPrimaries=onlyPrimaries,
432 showProperties=showProperties,
433 showMomenta=showMomenta,
434 showVertices=showVertices,
435 showStatus=showStatus,
439 def correctBrems(outputList,
442 maximumAcceptance=3.0,
443 multiplePhotons=False,
444 usePhotonOnlyOnce=True,
448 For each particle in the given ``inputList``, copies it to the ``outputList`` and adds the
449 4-vector of the photon(s) in the ``gammaList`` which has(have) a weighted named relation to
450 the particle's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
453 This can only work if the mdst file contains the *Bremsstrahlung* named relation. Official MC samples
454 up to and including MC12 and proc9 **do not** contain this. Newer production campaigns (from proc10 and MC13) do.
455 However, studies by the tau WG revealed that the cuts applied by the ``ECLTrackBremFinder`` module are too tight.
456 These will be loosened but this will only have effect with proc13 and MC15.
457 If your analysis is very sensitive to the Bremsstrahlung corrections, it is advised to use `correctBremsBelle`.
460 A detailed description of how the weights are set can be found directly at the documentation of the
461 `BremsFinder` module.
463 Please note that a new particle is always generated, with the old particle and -if found- one or more
464 photons as daughters.
466 The ``inputList`` should contain particles with associated tracks. Otherwise, the module will exit with an error.
468 The ``gammaList`` should contain photons. Otherwise, the module will exit with an error.
470 @param outputList The output particle list name containing the corrected particles
471 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
472 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
473 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
474 @param multiplePhotons Whether to use only one photon (the one with the smallest acceptance) or as many as possible
475 @param usePhotonOnlyOnce If true, each brems candidate is used to correct only the track with the smallest relation weight
476 @param writeOut Whether `RootOutput` module should save the created ``outputList``
477 @param path The module is added to this path
480 bremscorrector = register_module(
'BremsFinder')
481 bremscorrector.set_name(
'bremsCorrector_' + outputList)
482 bremscorrector.param(
'inputList', inputList)
483 bremscorrector.param(
'outputList', outputList)
484 bremscorrector.param(
'gammaList', gammaList)
485 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
486 bremscorrector.param(
'multiplePhotons', multiplePhotons)
487 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
488 bremscorrector.param(
'writeOut', writeOut)
489 path.add_module(bremscorrector)
492 def copyList(outputListName, inputListName, writeOut=False, path=None):
494 Copy all Particle indices from input ParticleList to the output ParticleList.
495 Note that the Particles themselves are not copied. The original and copied
496 ParticleLists will point to the same Particles.
498 @param ouputListName copied ParticleList
499 @param inputListName original ParticleList to be copied
500 @param writeOut whether RootOutput module should save the created ParticleList
501 @param path modules are added to this path
504 copyLists(outputListName, [inputListName], writeOut, path)
507 def correctBremsBelle(outputListName,
510 multiplePhotons=True,
515 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
516 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
520 Studies by the tau WG show that using a rather wide opening angle (up to
521 0.2 rad) and rather low energetic photons results in good correction.
522 However, this should only serve as a starting point for your own studies
523 because the optimal criteria are likely mode-dependent
526 outputListName (str): The output charged particle list containing the corrected charged particles
527 inputListName (str): The initial charged particle list containing the charged particles to correct.
528 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
529 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one -> False,
530 add all the photons within the cone -> True
531 angleThreshold (float): The maximum angle in radians between the charged particle and the (radiative)
532 gamma to be accepted.
533 writeOut (bool): whether RootOutput module should save the created ParticleList
534 path (basf2.Path): modules are added to this path
537 fsrcorrector = register_module(
'BelleBremRecovery')
538 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
539 fsrcorrector.param(
'inputListName', inputListName)
540 fsrcorrector.param(
'outputListName', outputListName)
541 fsrcorrector.param(
'gammaListName', gammaListName)
542 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
543 fsrcorrector.param(
'angleThreshold', angleThreshold)
544 fsrcorrector.param(
'writeOut', writeOut)
545 path.add_module(fsrcorrector)
548 def copyLists(outputListName, inputListNames, writeOut=False, path=None):
550 Copy all Particle indices from all input ParticleLists to the
551 single output ParticleList.
552 Note that the Particles themselves are not copied.
553 The original and copied ParticleLists will point to the same Particles.
555 Duplicates are removed based on the first-come, first-served principle.
556 Therefore, the order of the input ParticleLists matters.
559 If you want to select the best duplicate based on another criterion, have
560 a look at the function `mergeListsWithBestDuplicate`.
563 Two particles that differ only by the order of their daughters are
564 considered duplicates and one of them will be removed.
566 @param ouputListName copied ParticleList
567 @param inputListName vector of original ParticleLists to be copied
568 @param writeOut whether RootOutput module should save the created ParticleList
569 @param path modules are added to this path
572 pmanipulate = register_module(
'ParticleListManipulator')
573 pmanipulate.set_name(
'PListCopy_' + outputListName)
574 pmanipulate.param(
'outputListName', outputListName)
575 pmanipulate.param(
'inputListNames', inputListNames)
576 pmanipulate.param(
'writeOut', writeOut)
577 path.add_module(pmanipulate)
580 def copyParticles(outputListName, inputListName, writeOut=False, path=None):
582 Create copies of Particles given in the input ParticleList and add them to the output ParticleList.
584 The existing relations of the original Particle (or it's (grand-)^n-daughters)
585 are copied as well. Note that only the relation is copied and that the related
586 object is not. Copied particles are therefore related to the *same* object as
589 @param ouputListName new ParticleList filled with copied Particles
590 @param inputListName input ParticleList with original Particles
591 @param writeOut whether RootOutput module should save the created ParticleList
592 @param path modules are added to this path
596 pmanipulate = register_module(
'ParticleListManipulator')
597 pmanipulate.set_name(
'PListCopy_' + outputListName)
598 pmanipulate.param(
'outputListName', outputListName)
599 pmanipulate.param(
'inputListNames', [inputListName])
600 pmanipulate.param(
'writeOut', writeOut)
601 path.add_module(pmanipulate)
604 pcopy = register_module(
'ParticleCopier')
605 pcopy.param(
'inputListNames', [outputListName])
606 path.add_module(pcopy)
609 def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
611 Copy candidates from all lists in ``inputListNames`` to
612 ``outputListName`` if they pass ``cut`` (given selection criteria).
615 Note that the Particles themselves are not copied.
616 The original and copied ParticleLists will point to the same Particles.
619 Require energetic pions safely inside the cdc
621 .. code-block:: python
623 cutAndCopyLists("pi+:energeticPions", ["pi+:good", "pi+:loose"], "[E > 2] and thetaInCDCAcceptance", path=mypath)
626 You must use square braces ``[`` and ``]`` for conditional statements.
629 outputListName (str): the new ParticleList name
630 inputListName (list(str)): list of input ParticleList names
631 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
632 writeOut (bool): whether RootOutput module should save the created ParticleList
633 path (basf2.Path): modules are added to this path
635 pmanipulate = register_module(
'ParticleListManipulator')
636 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
637 pmanipulate.param(
'outputListName', outputListName)
638 pmanipulate.param(
'inputListNames', inputListNames)
639 pmanipulate.param(
'cut', cut)
640 pmanipulate.param(
'writeOut', writeOut)
641 path.add_module(pmanipulate)
644 def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
646 Copy candidates from ``inputListName`` to ``outputListName`` if they pass
647 ``cut`` (given selection criteria).
650 Note the Particles themselves are not copied.
651 The original and copied ParticleLists will point to the same Particles.
654 require energetic pions safely inside the cdc
656 .. code-block:: python
658 cutAndCopyList("pi+:energeticPions", "pi+:loose", "[E > 2] and thetaInCDCAcceptance", path=mypath)
661 You must use square braces ``[`` and ``]`` for conditional statements.
664 outputListName (str): the new ParticleList name
665 inputListName (str): input ParticleList name
666 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
667 writeOut (bool): whether RootOutput module should save the created ParticleList
668 path (basf2.Path): modules are added to this path
670 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
673 def removeTracksForTrackingEfficiencyCalculation(inputListNames, fraction, path=None):
675 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
676 Takes care of the duplicates, if any.
679 inputListNames (list(str)): input particle list names
680 fraction (float): fraction of particles to be removed randomly
681 path (basf2.Path): module is added to this path
684 trackingefficiency = register_module(
'TrackingEfficiency')
685 trackingefficiency.param(
'particleLists', inputListNames)
686 trackingefficiency.param(
'frac', fraction)
687 path.add_module(trackingefficiency)
690 def scaleTrackMomenta(inputListNames, scale, path=None):
693 Scale momenta of the particles according to the scaling factor scale.
694 If the particle list contains composite particles, the momenta of the track-based daughters are scaled.
695 Subsequently, the momentum of the mother particle is updated as well.
698 inputListNames (list(str)): input particle list names
699 scale (float): scaling factor (1.0 -- no scaling)
700 path (basf2.Path): module is added to this path
703 trackingmomentum = register_module(
'TrackingMomentum')
704 trackingmomentum.param(
'particleLists', inputListNames)
705 trackingmomentum.param(
'scale', scale)
706 path.add_module(trackingmomentum)
709 def mergeListsWithBestDuplicate(outputListName,
716 Merge input ParticleLists into one output ParticleList. Only the best
717 among duplicates is kept. The lowest or highest value (configurable via
718 preferLowest) of the provided variable determines which duplicate is the
721 @param ouputListName name of merged ParticleList
722 @param inputListName vector of original ParticleLists to be merged
723 @param variable variable to determine best duplicate
724 @param preferLowest whether lowest or highest value of variable should be preferred
725 @param writeOut whether RootOutput module should save the created ParticleList
726 @param path modules are added to this path
729 pmanipulate = register_module(
'ParticleListManipulator')
730 pmanipulate.set_name(
'PListMerger_' + outputListName)
731 pmanipulate.param(
'outputListName', outputListName)
732 pmanipulate.param(
'inputListNames', inputListNames)
733 pmanipulate.param(
'variable', variable)
734 pmanipulate.param(
'preferLowest', preferLowest)
735 pmanipulate.param(
'writeOut', writeOut)
736 path.add_module(pmanipulate)
739 def fillSignalSideParticleList(outputListName, decayString, path):
741 This function should only be used in the ROE path, that is a path
742 that is executed for each ROE object in the DataStore.
744 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
746 Function will create a ParticleList with name 'gamma:sig' which will be filled
747 with the existing photon Particle, being the second daughter of the B0 candidate
748 to which the ROE object has to be related.
750 @param ouputListName name of the created ParticleList
751 @param decayString specify Particle to be added to the ParticleList
754 pload = register_module(
'SignalSideParticleListCreator')
755 pload.set_name(
'SSParticleList_' + outputListName)
756 pload.param(
'particleListName', outputListName)
757 pload.param(
'decayString', decayString)
758 path.add_module(pload)
761 def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False,
762 loadPhotonsFromKLM=False, loadPhotonBeamBackgroundMVA=False):
764 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
765 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
767 The multiple ParticleLists with their own selection criteria are specified
768 via list tuples (decayString, cut), for example
770 .. code-block:: python
772 kaons = ('K+:mykaons', 'kaonID>0.1')
773 pions = ('pi+:mypions','pionID>0.1')
774 fillParticleLists([kaons, pions], path=mypath)
776 If you are unsure what selection you want, you might like to see the
777 :doc:`StandardParticles` functions.
779 The type of the particles to be loaded is specified via the decayString module parameter.
780 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
781 the particle. The following types of the particles can be loaded:
783 * charged final state particles (input ``mdst`` type = Tracks)
784 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
786 * neutral final state particles
787 - "gamma" (input ``mdst`` type = ECLCluster)
788 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
789 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
792 For "K_S0" and "Lambda0" you must specify the daughter ordering.
794 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
796 .. code-block:: python
798 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
799 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
802 Gammas can also be loaded from KLMClusters by explicitly setting the
803 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
804 done in selected use-cases and the effect should be studied carefully.
807 For "K_L0" it is now possible to load from ECLClusters, to revert to
808 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
810 .. code-block:: python
812 klongs = ('K_L0', 'isFromKLM > 0')
813 fillParticleLists([kaons, pions, klongs], path=mypath)
817 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
818 The decay string determines the type of Particle
819 and the name of the ParticleList.
820 If the input MDST type is V0 the whole
821 decay chain needs to be specified, so that
822 the user decides and controls the daughters
823 ' order (e.g. ``K_S0 -> pi+ pi-``)
824 The cut is the selection criteria
825 to be added to the ParticleList. It can be an empty string.
826 writeOut (bool): whether RootOutput module should save the created ParticleList
827 path (basf2.Path): modules are added to this path
828 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
829 using a mass hypothesis of the exact type passed to fillParticleLists().
830 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
831 in terms of mass difference will be used if the fit using exact particle
832 type is not available.
833 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
834 loadPhotonBeamBackgroundMVA (bool): If true, photon candidates will be assigned a beam background probability.
837 pload = register_module(
'ParticleLoader')
838 pload.set_name(
'ParticleLoader_' +
'PLists')
839 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
840 pload.param(
'writeOut', writeOut)
841 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
842 path.add_module(pload)
844 from ROOT
import Belle2
846 for decayString, cut
in decayStringsWithCuts:
847 if not decayDescriptor.init(decayString):
848 raise ValueError(
"Invalid decay string")
850 if decayDescriptor.getNDaughters() > 0:
854 if decayDescriptor.getMother().getLabel() !=
'V0':
855 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
856 elif decayDescriptor.getMother().getLabel() !=
'all':
859 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
863 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
865 if decayString.startswith(
"gamma"):
868 if not loadPhotonsFromKLM:
869 applyCuts(decayString,
'isFromECL', path)
873 if loadPhotonBeamBackgroundMVA:
874 getBeamBackgroundProbabilityMVA(decayString, path)
877 def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False,
878 loadPhotonsFromKLM=False, loadPhotonBeamBackgroundMVA=False):
880 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
881 loads them to the StoreArray<Particle> and fills the ParticleList.
884 the :doc:`StandardParticles` functions.
886 The type of the particles to be loaded is specified via the decayString module parameter.
887 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
888 the particle. The following types of the particles can be loaded:
890 * charged final state particles (input ``mdst`` type = Tracks)
891 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
893 * neutral final state particles
894 - "gamma" (input ``mdst`` type = ECLCluster)
895 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
896 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
899 For "K_S0" and "Lambda0" you must specify the daughter ordering.
901 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
903 .. code-block:: python
905 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
908 Gammas can also be loaded from KLMClusters by explicitly setting the
909 parameter ``loadPhotonsFromKLM`` to True. However, this should only be
910 done in selected use-cases and the effect should be studied carefully.
913 For "K_L0" it is now possible to load from ECLClusters, to revert to
914 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
916 .. code-block:: python
918 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
921 decayString (str): Type of Particle and determines the name of the ParticleList.
922 If the input MDST type is V0 the whole decay chain needs to be specified, so that
923 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``)
924 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
925 writeOut (bool): whether RootOutput module should save the created ParticleList
926 path (basf2.Path): modules are added to this path
927 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
928 using a mass hypothesis of the exact type passed to fillParticleLists().
929 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
930 in terms of mass difference will be used if the fit using exact particle
931 type is not available.
932 loadPhotonsFromKLM (bool): If true, photon candidates will be created from KLMClusters as well.
934 loadPhotonBeamBackgroundMVA (bool): If true, photon candidates will be assigned a beam background probability.
937 pload = register_module(
'ParticleLoader')
938 pload.set_name(
'ParticleLoader_' + decayString)
939 pload.param(
'decayStrings', [decayString])
940 pload.param(
'writeOut', writeOut)
941 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
942 path.add_module(pload)
945 from ROOT
import Belle2
947 if not decayDescriptor.init(decayString):
948 raise ValueError(
"Invalid decay string")
949 if decayDescriptor.getNDaughters() > 0:
953 if decayDescriptor.getMother().getLabel() !=
'V0':
954 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
955 elif decayDescriptor.getMother().getLabel() !=
'all':
958 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
962 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
964 if decayString.startswith(
"gamma"):
967 if not loadPhotonsFromKLM:
968 applyCuts(decayString,
'isFromECL', path)
972 if loadPhotonBeamBackgroundMVA:
973 getBeamBackgroundProbabilityMVA(decayString, path)
976 def fillParticleListWithTrackHypothesis(decayString,
980 enforceFitHypothesis=False,
983 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
985 @param decayString specifies type of Particles and determines the name of the ParticleList
986 @param cut Particles need to pass these selection criteria to be added to the ParticleList
987 @param hypothesis the PDG code of the desired track hypothesis
988 @param writeOut whether RootOutput module should save the created ParticleList
989 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
990 using a mass hypothesis of the exact type passed to fillParticleLists().
991 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
992 in terms of mass difference will be used if the fit using exact particle
993 type is not available.
994 @param path modules are added to this path
997 pload = register_module(
'ParticleLoader')
998 pload.set_name(
'ParticleLoader_' + decayString)
999 pload.param(
'decayStrings', [decayString])
1000 pload.param(
'trackHypothesis', hypothesis)
1001 pload.param(
'writeOut', writeOut)
1002 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
1003 path.add_module(pload)
1005 from ROOT
import Belle2
1007 if not decayDescriptor.init(decayString):
1008 raise ValueError(
"Invalid decay string")
1009 if decayDescriptor.getMother().getLabel() !=
'all':
1012 copyList(decayString, decayDescriptor.getMother().getName() +
':all', writeOut, path)
1016 applyCuts(decayString, cut, path)
1019 def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
1021 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
1024 You must specify the daughter ordering.
1026 .. code-block:: python
1028 fillConvertedPhotonsList('gamma:converted -> e+ e-', '', path=mypath)
1031 decayString (str): Must be gamma to an e+e- pair. You must specify the daughter ordering.
1032 Will also determine the name of the particleList.
1033 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
1034 writeOut (bool): whether RootOutput module should save the created ParticleList
1035 path (basf2.Path): modules are added to this path
1038 pload = register_module(
'ParticleLoader')
1039 pload.set_name(
'ParticleLoader_' + decayString)
1040 pload.param(
'decayStrings', [decayString])
1041 pload.param(
'addDaughters',
True)
1042 pload.param(
'writeOut', writeOut)
1043 path.add_module(pload)
1045 from ROOT
import Belle2
1047 if not decayDescriptor.init(decayString):
1048 raise ValueError(
"Invalid decay string")
1049 if decayDescriptor.getMother().getLabel() !=
'V0':
1052 copyList(decayDescriptor.getMother().getFullName(), decayDescriptor.getMother().getName() +
':V0', writeOut, path)
1056 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1059 def fillParticleListFromROE(decayString,
1062 sourceParticleListName='',
1067 Creates Particle object for each ROE of the desired type found in the
1068 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
1069 and fills the ParticleList. If useMissing is True, then the missing
1070 momentum is used instead of ROE.
1072 The type of the particles to be loaded is specified via the decayString module parameter.
1074 @param decayString specifies type of Particles and determines the name of the ParticleList.
1075 Source ROEs can be taken as a daughter list, for example:
1076 'B0:tagFromROE -> B0:signal'
1077 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1078 @param maskName Name of the ROE mask to use
1079 @param sourceParticleListName Use related ROEs to this particle list as a source
1080 @param useMissing Use missing momentum instead of ROE momentum
1081 @param writeOut whether RootOutput module should save the created ParticleList
1082 @param path modules are added to this path
1085 pload = register_module(
'ParticleLoader')
1086 pload.set_name(
'ParticleLoader_' + decayString)
1087 pload.param(
'decayStrings', [decayString])
1088 pload.param(
'writeOut', writeOut)
1089 pload.param(
'roeMaskName', maskName)
1090 pload.param(
'useMissing', useMissing)
1091 pload.param(
'sourceParticleListName', sourceParticleListName)
1092 pload.param(
'useROEs',
True)
1093 path.add_module(pload)
1095 from ROOT
import Belle2
1097 if not decayDescriptor.init(decayString):
1098 raise ValueError(
"Invalid decay string")
1102 applyCuts(decayDescriptor.getMother().getFullName(), cut, path)
1105 def fillParticleListFromMC(decayString,
1108 skipNonPrimaryDaughters=False,
1112 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1113 loads them to the StoreArray<Particle> and fills the ParticleList.
1115 The type of the particles to be loaded is specified via the decayString module parameter.
1117 @param decayString specifies type of Particles and determines the name of the ParticleList
1118 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1119 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1120 sets mother-daughter relations
1121 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1122 @param writeOut whether RootOutput module should save the created ParticleList
1123 @param path modules are added to this path
1126 pload = register_module(
'ParticleLoader')
1127 pload.set_name(
'ParticleLoader_' + decayString)
1128 pload.param(
'decayStrings', [decayString])
1129 pload.param(
'addDaughters', addDaughters)
1130 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1131 pload.param(
'writeOut', writeOut)
1132 pload.param(
'useMCParticles',
True)
1133 path.add_module(pload)
1135 from ROOT
import Belle2
1137 if not decayDescriptor.init(decayString):
1138 raise ValueError(
"Invalid decay string")
1139 if decayDescriptor.getMother().getLabel() !=
'MC':
1142 copyList(decayString, decayDescriptor.getMother().getName() +
':MC', writeOut, path)
1146 applyCuts(decayString, cut, path)
1149 def fillParticleListsFromMC(decayStringsWithCuts,
1151 skipNonPrimaryDaughters=False,
1155 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
1156 loads them to the StoreArray<Particle> and fills the ParticleLists.
1158 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
1161 .. code-block:: python
1163 kaons = ('K+:gen', '')
1164 pions = ('pi+:gen', 'pionID>0.1')
1165 fillParticleListsFromMC([kaons, pions], path=mypath)
1167 @param decayString specifies type of Particles and determines the name of the ParticleList
1168 @param cut Particles need to pass these selection criteria to be added to the ParticleList
1169 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
1170 sets mother-daughter relations
1171 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
1172 @param writeOut whether RootOutput module should save the created ParticleList
1173 @param path modules are added to this path
1176 pload = register_module(
'ParticleLoader')
1177 pload.set_name(
'ParticleLoader_' +
'PLists')
1178 pload.param(
'decayStrings', [decayString
for decayString, cut
in decayStringsWithCuts])
1179 pload.param(
'addDaughters', addDaughters)
1180 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
1181 pload.param(
'writeOut', writeOut)
1182 pload.param(
'useMCParticles',
True)
1183 path.add_module(pload)
1185 from ROOT
import Belle2
1187 for decayString, cut
in decayStringsWithCuts:
1188 if not decayDescriptor.init(decayString):
1189 raise ValueError(
"Invalid decay string")
1190 if decayDescriptor.getMother().getLabel() !=
'MC':
1193 copyList(decayString, decayDescriptor.getMother().getName() +
':MC', writeOut, path)
1197 applyCuts(decayString, cut, path)
1200 def applyCuts(list_name, cut, path):
1202 Removes particle candidates from ``list_name`` that do not pass ``cut``
1203 (given selection criteria).
1206 require energetic pions safely inside the cdc
1208 .. code-block:: python
1210 applyCuts("pi+:mypions", "[E > 2] and thetaInCDCAcceptance", path=mypath)
1213 You must use square braces ``[`` and ``]`` for conditional statements.
1216 list_name (str): input ParticleList name
1217 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
1218 path (basf2.Path): modules are added to this path
1221 pselect = register_module(
'ParticleSelector')
1222 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
1223 pselect.param(
'decayString', list_name)
1224 pselect.param(
'cut', cut)
1225 path.add_module(pselect)
1228 def applyEventCuts(cut, path):
1230 Removes events that do not pass the ``cut`` (given selection criteria).
1233 continuum events (in mc only) with more than 5 tracks
1235 .. code-block:: python
1237 applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1240 You must use square braces ``[`` and ``]`` for conditional statements.
1243 cut (str): Events that do not pass these selection criteria are skipped
1244 path (basf2.Path): modules are added to this path
1247 eselect = register_module(
'VariableToReturnValue')
1248 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1249 path.add_module(eselect)
1250 empty_path = create_path()
1251 eselect.if_value(
'<1', empty_path)
1254 def reconstructDecay(decayString,
1259 candidate_limit=None,
1260 ignoreIfTooManyCandidates=True,
1261 chargeConjugation=True,
1262 allowChargeViolation=False):
1264 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1265 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1266 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1267 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1268 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1270 One can use an ``@``-sign to mark a particle as unspecified for inclusive analyses,
1271 e.g. in a DecayString: :code:`'@Xsd -> K+ pi-'`.
1273 .. seealso:: :ref:`Marker_of_unspecified_particle`
1276 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1277 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1278 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1280 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1281 This can be solved by manually randomising the lists before combining.
1285 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1286 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1288 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1289 (from the DecayString the mother and daughter ParticleLists are determined)
1290 @param cut created (mother) Particles are added to the mother ParticleList if they
1291 pass give cuts (in VariableManager style) and rejected otherwise
1292 @param dmID user specified decay mode identifier
1293 @param writeOut whether RootOutput module should save the created ParticleList
1294 @param path modules are added to this path
1295 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1296 the number of candidates is exceeded a Warning will be
1298 By default, all these candidates will be removed and event will be ignored.
1299 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1300 If no value is given the amount is limited to a sensible
1301 default. A value <=0 will disable this limit and can
1302 cause huge memory amounts so be careful.
1303 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1304 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1305 otherwise, number of candidates in candidate_limit is reconstructed.
1306 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1307 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1310 pmake = register_module(
'ParticleCombiner')
1311 pmake.set_name(
'ParticleCombiner_' + decayString)
1312 pmake.param(
'decayString', decayString)
1313 pmake.param(
'cut', cut)
1314 pmake.param(
'decayMode', dmID)
1315 pmake.param(
'writeOut', writeOut)
1316 if candidate_limit
is not None:
1317 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1318 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1319 pmake.param(
'chargeConjugation', chargeConjugation)
1320 pmake.param(
"allowChargeViolation", allowChargeViolation)
1321 path.add_module(pmake)
1324 def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1326 Creates a new Particle as the combination of all Particles from all
1327 provided inputParticleLists. However, each particle is used only once
1328 (even if duplicates are provided) and the combination has to pass the
1329 specified selection criteria to be saved in the newly created (mother)
1332 @param inputParticleLists List of input particle lists which are combined to the new Particle
1333 @param outputList Name of the particle combination created with this module
1334 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1335 these given cuts (in VariableManager style) and is rejected otherwise
1336 @param writeOut whether RootOutput module should save the created ParticleList
1337 @param path module is added to this path
1340 pmake = register_module(
'AllParticleCombiner')
1341 pmake.set_name(
'AllParticleCombiner_' + outputList)
1342 pmake.param(
'inputListNames', inputParticleLists)
1343 pmake.param(
'outputListName', outputList)
1344 pmake.param(
'cut', cut)
1345 pmake.param(
'writeOut', writeOut)
1346 path.add_module(pmake)
1349 def reconstructMissingKlongDecayExpert(decayString,
1356 Creates a list of K_L0's with their momentum determined from kinematic constraints of B->K_L0 + something else.
1358 @param decayString DecayString specifying what kind of the decay should be reconstructed
1359 (from the DecayString the mother and daughter ParticleLists are determined)
1360 @param cut Particles are added to the K_L0 ParticleList if they
1361 pass the given cuts (in VariableManager style) and rejected otherwise
1362 @param dmID user specified decay mode identifier
1363 @param writeOut whether RootOutput module should save the created ParticleList
1364 @param path modules are added to this path
1365 @param recoList suffix appended to original K_L0 ParticleList that identifies the newly created K_L0 list
1368 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1369 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1370 pcalc.param(
'decayString', decayString)
1371 pcalc.param(
'cut', cut)
1372 pcalc.param(
'decayMode', dmID)
1373 pcalc.param(
'writeOut', writeOut)
1374 pcalc.param(
'recoList', recoList)
1375 path.add_module(pcalc)
1377 rmake = register_module(
'KlongDecayReconstructorExpert')
1378 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1379 rmake.param(
'decayString', decayString)
1380 rmake.param(
'cut', cut)
1381 rmake.param(
'decayMode', dmID)
1382 rmake.param(
'writeOut', writeOut)
1383 rmake.param(
'recoList', recoList)
1384 path.add_module(rmake)
1387 def replaceMass(replacerName, particleLists=None, pdgCode=22, path=None):
1389 replaces the mass of the particles inside the given particleLists
1390 with the invariant mass of the particle corresponding to the given pdgCode.
1392 @param particleLists new ParticleList filled with copied Particles
1393 @param pdgCode PDG code for mass reference
1394 @param path modules are added to this path
1396 if particleLists
is None:
1400 pmassupdater = register_module(
'ParticleMassUpdater')
1401 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1402 pmassupdater.param(
'particleLists', particleLists)
1403 pmassupdater.param(
'pdgCode', pdgCode)
1404 path.add_module(pmassupdater)
1407 def reconstructRecoil(decayString,
1412 candidate_limit=None,
1413 allowChargeViolation=False):
1415 Creates new Particles that recoil against the input particles.
1417 For example the decay string M -> D1 D2 D3 will:
1418 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1419 - Particles D1, D2, D3 will be appended as daughters to M
1420 - the 4-momentum of the mother Particle M is given by
1421 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1423 @param decayString DecayString specifying what kind of the decay should be reconstructed
1424 (from the DecayString the mother and daughter ParticleLists are determined)
1425 @param cut created (mother) Particles are added to the mother ParticleList if they
1426 pass give cuts (in VariableManager style) and rejected otherwise
1427 @param dmID user specified decay mode identifier
1428 @param writeOut whether RootOutput module should save the created ParticleList
1429 @param path modules are added to this path
1430 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1431 the number of candidates is exceeded no candidate will be
1432 reconstructed for that event and a Warning will be
1434 If no value is given the amount is limited to a sensible
1435 default. A value <=0 will disable this limit and can
1436 cause huge memory amounts so be careful.
1437 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1440 pmake = register_module(
'ParticleCombiner')
1441 pmake.set_name(
'ParticleCombiner_' + decayString)
1442 pmake.param(
'decayString', decayString)
1443 pmake.param(
'cut', cut)
1444 pmake.param(
'decayMode', dmID)
1445 pmake.param(
'writeOut', writeOut)
1446 pmake.param(
'recoilParticleType', 1)
1447 if candidate_limit
is not None:
1448 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1449 pmake.param(
'allowChargeViolation', allowChargeViolation)
1450 path.add_module(pmake)
1453 def reconstructRecoilDaughter(decayString,
1458 candidate_limit=None,
1459 allowChargeViolation=False):
1461 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1463 For example the decay string M -> D1 D2 D3 will:
1464 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1465 - Particles D1, D2, D3 will be appended as daughters to M
1466 - the 4-momentum of the mother Particle M is given by
1467 p(M) = p(D1) - Sum_i p(Di), where i>1
1469 @param decayString DecayString specifying what kind of the decay should be reconstructed
1470 (from the DecayString the mother and daughter ParticleLists are determined)
1471 @param cut created (mother) Particles are added to the mother ParticleList if they
1472 pass give cuts (in VariableManager style) and rejected otherwise
1473 @param dmID user specified decay mode identifier
1474 @param writeOut whether RootOutput module should save the created ParticleList
1475 @param path modules are added to this path
1476 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1477 the number of candidates is exceeded no candidate will be
1478 reconstructed for that event and a Warning will be
1480 If no value is given the amount is limited to a sensible
1481 default. A value <=0 will disable this limit and can
1482 cause huge memory amounts so be careful.
1483 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1484 daughter is actually the mother
1487 pmake = register_module(
'ParticleCombiner')
1488 pmake.set_name(
'ParticleCombiner_' + decayString)
1489 pmake.param(
'decayString', decayString)
1490 pmake.param(
'cut', cut)
1491 pmake.param(
'decayMode', dmID)
1492 pmake.param(
'writeOut', writeOut)
1493 pmake.param(
'recoilParticleType', 2)
1494 if candidate_limit
is not None:
1495 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1496 pmake.param(
'allowChargeViolation', allowChargeViolation)
1497 path.add_module(pmake)
1500 def rankByHighest(particleList,
1504 allowMultiRank=False,
1508 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1509 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1510 The list is also sorted from best to worst candidate
1511 (each charge, e.g. B+/B-, separately).
1512 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1513 a non-zero value for 'numBest'.
1516 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1517 These variable names can become clunky, so it's probably a good idea to set an alias.
1518 For example if you rank your B candidates by momentum,
1522 rankByHighest("B0:myCandidates", "p", path=mypath)
1523 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1526 @param particleList The input ParticleList
1527 @param variable Variable to order Particles by.
1528 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1529 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1530 @param allowMultiRank If true, candidates with the same value will get the same rank.
1531 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1532 @param path modules are added to this path
1535 bcs = register_module(
'BestCandidateSelection')
1536 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1537 bcs.param(
'particleList', particleList)
1538 bcs.param(
'variable', variable)
1539 bcs.param(
'numBest', numBest)
1540 bcs.param(
'outputVariable', outputVariable)
1541 bcs.param(
'allowMultiRank', allowMultiRank)
1542 bcs.param(
'cut', cut)
1543 path.add_module(bcs)
1546 def rankByLowest(particleList,
1550 allowMultiRank=False,
1554 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1555 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1556 The list is also sorted from best to worst candidate
1557 (each charge, e.g. B+/B-, separately).
1558 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1559 a non-zero value for 'numBest'.
1562 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1563 These variable names can become clunky, so it's probably a good idea to set an alias.
1564 For example if you rank your B candidates by :b2:var:`dM`,
1568 rankByLowest("B0:myCandidates", "dM", path=mypath)
1569 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1572 @param particleList The input ParticleList
1573 @param variable Variable to order Particles by.
1574 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1575 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1576 @param allowMultiRank If true, candidates with the same value will get the same rank.
1577 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1578 @param path modules are added to this path
1581 bcs = register_module(
'BestCandidateSelection')
1582 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1583 bcs.param(
'particleList', particleList)
1584 bcs.param(
'variable', variable)
1585 bcs.param(
'numBest', numBest)
1586 bcs.param(
'selectLowest',
True)
1587 bcs.param(
'allowMultiRank', allowMultiRank)
1588 bcs.param(
'outputVariable', outputVariable)
1589 bcs.param(
'cut', cut)
1590 path.add_module(bcs)
1593 def applyRandomCandidateSelection(particleList, path=None):
1595 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1596 This is done on a event-by-event basis.
1598 @param particleList ParticleList for which the random candidate selection should be applied
1599 @param path module is added to this path
1602 rcs = register_module(
'BestCandidateSelection')
1603 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1604 rcs.param(
'particleList', particleList)
1605 rcs.param(
'variable',
'random')
1606 rcs.param(
'selectLowest',
False)
1607 rcs.param(
'allowMultiRank',
False)
1608 rcs.param(
'numBest', 1)
1609 rcs.param(
'cut',
'')
1610 rcs.param(
'outputVariable',
'')
1611 path.add_module(rcs)
1616 Prints the contents of DataStore in the first event (or a specific event number or all events).
1617 Will list all objects and arrays (including size).
1620 The command line tool: ``b2file-size``.
1623 eventNumber (int): Print the datastore only for this event. The default
1624 (-1) prints only the first event, 0 means print for all events (can produce large output)
1625 path (basf2.Path): the PrintCollections module is added to this path
1628 This will print a lot of output if you print it for all events and process many events.
1632 printDS = register_module(
'PrintCollections')
1633 printDS.param(
'printForEvent', eventNumber)
1634 path.add_module(printDS)
1637 def printVariableValues(list_name, var_names, path):
1639 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
1641 @param list_name input ParticleList name
1642 @param var_names vector of variable names to be printed
1643 @param path modules are added to this path
1646 prlist = register_module(
'ParticlePrinter')
1647 prlist.set_name(
'ParticlePrinter_' + list_name)
1648 prlist.param(
'listName', list_name)
1649 prlist.param(
'fullPrint',
False)
1650 prlist.param(
'variables', var_names)
1651 path.add_module(prlist)
1654 def printList(list_name, full, path):
1656 Prints the size and executes Particle->print() (if full=True)
1657 method for all Particles in given ParticleList. For debugging purposes.
1659 @param list_name input ParticleList name
1660 @param full execute Particle->print() method for all Particles
1661 @param path modules are added to this path
1664 prlist = register_module(
'ParticlePrinter')
1665 prlist.set_name(
'ParticlePrinter_' + list_name)
1666 prlist.param(
'listName', list_name)
1667 prlist.param(
'fullPrint', full)
1668 path.add_module(prlist)
1671 def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None):
1673 Creates and fills a flat ntuple with the specified variables from the VariableManager.
1674 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
1675 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
1678 decayString (str): specifies type of Particles and determines the name of the ParticleList
1679 variables (list(str)): the list of variables (which must be registered in the VariableManager)
1680 treename (str): name of the ntuple tree
1681 filename (str): which is used to store the variables
1682 path (basf2.Path): the basf2 path where the analysis is processed
1685 output = register_module(
'VariablesToNtuple')
1686 output.set_name(
'VariablesToNtuple_' + decayString)
1687 output.param(
'particleList', decayString)
1688 output.param(
'variables', variables)
1689 output.param(
'fileName', filename)
1690 output.param(
'treeName', treename)
1691 path.add_module(output)
1697 filename='ntuple.root',
1700 prefixDecayString=False):
1702 Creates and fills a flat ntuple with the specified variables from the VariableManager
1705 decayString (str): specifies type of Particles and determines the name of the ParticleList
1706 variables (list(tuple))): variables + binning which must be registered in the VariableManager
1707 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
1708 filename (str): which is used to store the variables
1709 path (basf2.Path): the basf2 path where the analysis is processed
1710 directory (str): directory inside the output file where the histograms should be saved.
1711 Useful if you want to have different histograms in the same file to separate them.
1712 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
1713 programmatic naming of the structure in the file.
1715 if variables_2d
is None:
1717 output = register_module(
'VariablesToHistogram')
1718 output.set_name(
'VariablesToHistogram_' + decayString)
1719 output.param(
'particleList', decayString)
1720 output.param(
'variables', variables)
1721 output.param(
'variables_2d', variables_2d)
1722 output.param(
'fileName', filename)
1723 if directory
is not None or prefixDecayString:
1724 if directory
is None:
1726 if prefixDecayString:
1727 directory = decayString +
"_" + directory
1728 output.param(
"directory", directory)
1729 path.add_module(output)
1734 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
1735 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
1737 An existing extra info with the same name will be overwritten if the new
1738 value is lower / will never be overwritten / will be overwritten if the
1739 new value is higher / will always be overwritten (-1/0/1/2).
1741 @param particleList The input ParticleList
1742 @param variables Dictionary of Variables and extraInfo names.
1743 @param path modules are added to this path
1746 mod = register_module(
'VariablesToExtraInfo')
1747 mod.set_name(
'VariablesToExtraInfo_' + particleList)
1748 mod.param(
'particleList', particleList)
1749 mod.param(
'variables', variables)
1750 mod.param(
'overwrite', option)
1751 path.add_module(mod)
1754 def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
1756 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
1757 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
1758 to specified daughter particle.
1760 An existing extra info with the same name will be overwritten if the new
1761 value is lower / will never be overwritten / will be overwritten if the
1762 new value is higher / will always be overwritten (-1/0/1/2).
1764 @param particleList The input ParticleList
1765 @param decayString Decay string that specifies to which daughter the extra info should be appended
1766 @param variables Dictionary of Variables and extraInfo names.
1767 @param option Various options for overwriting
1768 @param path modules are added to this path
1771 mod = register_module(
'VariablesToExtraInfo')
1772 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
1773 mod.param(
'particleList', particleList)
1774 mod.param(
'decayString', decayString)
1775 mod.param(
'variables', variables)
1776 mod.param(
'overwrite', option)
1777 path.add_module(mod)
1780 def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
1782 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
1783 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
1785 An existing extra info with the same name will be overwritten if the new
1786 value is lower / will never be overwritten / will be overwritten if the
1787 new value is higher / will always be overwritten (-1/0/1/2).
1789 @param particleList The input ParticleList
1790 @param variables Dictionary of Variables and extraInfo names.
1791 @param path modules are added to this path
1794 mod = register_module(
'VariablesToEventExtraInfo')
1795 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
1796 mod.param(
'particleList', particleList)
1797 mod.param(
'variables', variables)
1798 mod.param(
'overwrite', option)
1799 path.add_module(mod)
1802 def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
1804 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
1805 particle) as an extra info to the particle related to current ROE.
1806 Should be used only in the for_each roe path.
1808 @param particleList The input ParticleList
1809 @param varToExtraInfo Dictionary of Variables and extraInfo names.
1810 @param path modules are added to this path
1812 mod = register_module(
'SignalSideVariablesToExtraInfo')
1813 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
1814 mod.param(
'particleListName', particleList)
1815 mod.param(
'variableToExtraInfo', varToExtraInfo)
1816 path.add_module(mod)
1819 def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
1821 Define and blind a signal region.
1822 Per default, the defined signal region is cut out if ran on data.
1823 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
1827 .. code-block:: python
1829 ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
1830 ma.signalRegion("B+:sig",
1831 "Mbc>5.27 and abs(deltaE)<0.2",
1834 ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
1837 particleList (str): The input ParticleList
1838 cut (str): Cut string describing the signal region
1839 path (basf2.Path):: Modules are added to this path
1840 name (str): Name of the Signal region in the variable manager
1841 blind_data (bool): Automatically exclude signal region from data
1845 from variables
import variables
1846 mod = register_module(
'VariablesToExtraInfo')
1847 mod.set_name(f
'{name}_' + particleList)
1848 mod.param(
'particleList', particleList)
1849 mod.param(
'variables', {f
"passesCut({cut})": name})
1850 variables.addAlias(name, f
"extraInfo({name})")
1851 path.add_module(mod)
1855 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
1858 def removeExtraInfo(particleLists=None, removeEventExtraInfo=False, path=None):
1860 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
1862 if particleLists
is None:
1864 mod = register_module(
'ExtraInfoRemover')
1865 mod.param(
'particleLists', particleLists)
1866 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
1867 path.add_module(mod)
1870 def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
1872 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
1873 to the particle from the input ParticleList. Additional selection criteria can be applied.
1874 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
1875 meet the selection criteria the execution of deadEndPath is started. This path, as the name
1876 suggests should be empty and its purpose is to end the execution of for_each roe path for
1877 the current ROE object.
1879 @param particleList The input ParticleList
1880 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
1881 @param for_each roe path in which this filter is executed
1882 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
1884 mod = register_module(
'SignalSideParticleFilter')
1885 mod.set_name(
'SigSideParticleFilter_' + particleList)
1886 mod.param(
'particleLists', [particleList])
1887 mod.param(
'selection', selection)
1888 roe_path.add_module(mod)
1889 mod.if_false(deadEndPath)
1892 def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
1894 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
1895 to the particle from the input ParticleList. Additional selection criteria can be applied.
1896 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
1897 meet the selection criteria the execution of deadEndPath is started. This path, as the name
1898 suggests should be empty and its purpose is to end the execution of for_each roe path for
1899 the current ROE object.
1901 @param particleLists The input ParticleLists
1902 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
1903 @param for_each roe path in which this filter is executed
1904 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
1906 mod = register_module(
'SignalSideParticleFilter')
1907 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
1908 mod.param(
'particleLists', particleLists)
1909 mod.param(
'selection', selection)
1910 roe_path.add_module(mod)
1911 mod.if_false(deadEndPath)
1920 chargeConjugation=True,
1923 Finds and creates a ``ParticleList`` from given decay string.
1924 ``ParticleList`` of daughters with sub-decay is created.
1926 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
1927 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
1930 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
1931 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
1932 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
1935 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1936 (from the DecayString the mother and daughter ParticleLists are determined)
1937 @param cut created (mother) Particles are added to the mother ParticleList if they
1938 pass given cuts (in VariableManager style) and rejected otherwise
1939 isSignal==1 is always required by default.
1940 @param dmID user specified decay mode identifier
1941 @param writeOut whether RootOutput module should save the created ParticleList
1942 @param path modules are added to this path
1943 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1946 pmake = register_module(
'ParticleCombinerFromMC')
1947 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
1948 pmake.param(
'decayString', decayString)
1949 pmake.param(
'cut', cut)
1950 pmake.param(
'decayMode', dmID)
1951 pmake.param(
'writeOut', writeOut)
1952 pmake.param(
'chargeConjugation', chargeConjugation)
1953 path.add_module(pmake)
1964 This function is not fully tested and maintained.
1965 Please consider to use reconstructMCDecay() instead.
1967 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
1968 The decay string is required to describe correctly what you want.
1969 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
1971 @param list_name The output particle list name
1972 @param decay The decay string which you want
1973 @param writeOut Whether `RootOutput` module should save the created ``outputList``
1974 @param path modules are added to this path
1976 B2WARNING(
"This function is not fully tested and maintained."
1977 "Please consider to use reconstructMCDecay() instead.")
1979 decayfinder = register_module(
'MCDecayFinder')
1980 decayfinder.set_name(
'MCDecayFinder_' + list_name)
1981 decayfinder.param(
'listName', list_name)
1982 decayfinder.param(
'decayString', decay)
1983 decayfinder.param(
'writeOut', writeOut)
1984 path.add_module(decayfinder)
1987 def summaryOfLists(particleLists, outputFile=None, path=None):
1989 Prints out Particle statistics at the end of the job: number of events with at
1990 least one candidate, average number of candidates per event, etc.
1991 If an output file name is provided the statistics is also dumped into a json file with that name.
1993 @param particleLists list of input ParticleLists
1994 @param outputFile output file name (not created by default)
1997 particleStats = register_module(
'ParticleStats')
1998 particleStats.param(
'particleLists', particleLists)
1999 if outputFile
is not None:
2000 particleStats.param(
'outputFile', outputFile)
2001 path.add_module(particleStats)
2004 def matchMCTruth(list_name, path):
2006 Performs MC matching (sets relation Particle->MCParticle) for
2007 all particles (and its (grand)^N-daughter particles) in the specified
2010 @param list_name name of the input ParticleList
2011 @param path modules are added to this path
2014 mcMatch = register_module(
'MCMatcherParticles')
2015 mcMatch.set_name(
'MCMatch_' + list_name)
2016 mcMatch.param(
'listName', list_name)
2017 path.add_module(mcMatch)
2020 def looseMCTruth(list_name, path):
2022 Performs loose MC matching for all particles in the specified
2024 The difference between loose and normal mc matching algorithm is that
2025 the loose algorithm will find the common mother of the majority of daughter
2026 particles while the normal algorithm finds the common mother of all daughters.
2027 The results of loose mc matching algorithm are stored to the following extraInfo
2030 - looseMCMotherPDG: PDG code of most common mother
2031 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
2032 - looseMCWrongDaughterN: number of daughters that don't originate from the most
2034 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from
2035 the most common mother
2036 (only if looseMCWrongDaughterN = 1)
2037 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background
2040 @param list_name name of the input ParticleList
2041 @param path modules are added to this path
2044 mcMatch = register_module(
'MCMatcherParticles')
2045 mcMatch.set_name(
'LooseMCMatch_' + list_name)
2046 mcMatch.param(
'listName', list_name)
2047 mcMatch.param(
'looseMCMatching',
True)
2048 path.add_module(mcMatch)
2051 def buildRestOfEvent(target_list_name, inputParticlelists=None,
2052 fillWithMostLikely=True,
2053 chargedPIDPriors=None, path=None):
2055 Creates for each Particle in the given ParticleList a RestOfEvent
2056 dataobject and makes basf2 relation between them. User can provide additional
2057 particle lists with a different particle hypothesis like ['K+:good, e+:good'], etc.
2059 @param target_list_name name of the input ParticleList
2060 @param inputParticlelists list of user-defined input particle list names, which serve
2061 as source of particles to build the ROE, the FSP particles from
2062 target_list_name are automatically excluded from the ROE object
2063 @param fillWithMostLikely By default the module uses the most likely particle mass hypothesis for charged particles
2064 based on the PID likelihood. Turn this behavior off if you want to configure your own
2065 input particle lists.
2066 @param chargedPIDPriors The prior PID fractions, that are used to regulate the
2067 amount of certain charged particle species, should be a list of
2068 six floats if not None. The order of particle types is
2069 the following: [e-, mu-, pi-, K-, p+, d+]
2070 @param path modules are added to this path
2072 if inputParticlelists
is None:
2073 inputParticlelists = []
2074 fillParticleList(
'pi+:all',
'', path=path)
2075 if fillWithMostLikely:
2076 from stdCharged
import stdMostLikely
2077 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
2078 inputParticlelists = [
'%s:mostlikely_roe' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
2081 fillParticleList(
'gamma:all',
'', path=path)
2082 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
2083 inputParticlelists += [
'pi+:all',
'gamma:all',
'K_L0:roe_default']
2085 inputParticlelists += [
'pi+:all',
'gamma:mdst']
2086 roeBuilder = register_module(
'RestOfEventBuilder')
2087 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
2088 roeBuilder.param(
'particleList', target_list_name)
2089 roeBuilder.param(
'particleListsInput', inputParticlelists)
2090 roeBuilder.param(
'mostLikely', fillWithMostLikely)
2091 path.add_module(roeBuilder)
2094 def buildNestedRestOfEvent(target_list_name, maskName='', path=None):
2096 Creates for each Particle in the given ParticleList a RestOfEvent
2097 @param target_list_name name of the input ParticleList
2098 @param mask_name name of the ROEMask to be used
2099 @param path modules are added to this path
2101 roeBuilder = register_module(
'RestOfEventBuilder')
2102 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
2103 roeBuilder.param(
'particleList', target_list_name)
2104 roeBuilder.param(
'nestedROEMask', maskName)
2105 roeBuilder.param(
'createNestedROE',
True)
2106 path.add_module(roeBuilder)
2109 def buildRestOfEventFromMC(target_list_name, inputParticlelists=None, path=None):
2111 Creates for each Particle in the given ParticleList a RestOfEvent
2112 @param target_list_name name of the input ParticleList
2113 @param inputParticlelists list of input particle list names, which serve
2114 as a source of particles to build ROE, the FSP particles from
2115 target_list_name are excluded from ROE object
2116 @param path modules are added to this path
2118 if inputParticlelists
is None:
2119 inputParticlelists = []
2120 if (len(inputParticlelists) == 0):
2124 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
2125 'n0',
'nu_e',
'nu_mu',
'nu_tau',
2128 fillParticleListFromMC(
"%s:roe_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
2129 True,
True, path=path)
2130 inputParticlelists += [
"%s:roe_default_gen" % t]
2131 roeBuilder = register_module(
'RestOfEventBuilder')
2132 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
2133 roeBuilder.param(
'particleList', target_list_name)
2134 roeBuilder.param(
'particleListsInput', inputParticlelists)
2135 roeBuilder.param(
'fromMC',
True)
2136 path.add_module(roeBuilder)
2139 def appendROEMask(list_name,
2142 eclClusterSelection,
2143 klmClusterSelection='',
2146 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2147 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
2149 - append a ROE mask with all tracks in ROE coming from the IP region
2151 .. code-block:: python
2153 appendROEMask('B+:sig', 'IPtracks', '[dr < 2] and [abs(dz) < 5]', path=mypath)
2155 - append a ROE mask with only ECL-based particles that pass as good photon candidates
2157 .. code-block:: python
2159 goodPhotons = 'inCDCAcceptance and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
2160 appendROEMask('B+:sig', 'goodROEGamma', '', goodPhotons, path=mypath)
2163 @param list_name name of the input ParticleList
2164 @param mask_name name of the appended ROEMask
2165 @param trackSelection decay string for the track-based particles in ROE
2166 @param eclClusterSelection decay string for the ECL-based particles in ROE
2167 @param klmClusterSelection decay string for the KLM-based particles in ROE
2168 @param path modules are added to this path
2171 roeMask = register_module(
'RestOfEventInterpreter')
2172 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2173 roeMask.param(
'particleList', list_name)
2174 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2175 path.add_module(roeMask)
2178 def appendROEMasks(list_name, mask_tuples, path=None):
2180 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
2181 selection criteria for track-, ECL- and KLM-based particles which will be used by ROE variables.
2183 The multiple ROE masks with their own selection criteria are specified
2184 via list of tuples (mask_name, trackParticleSelection, eclParticleSelection, klmParticleSelection) or
2185 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
2187 - Example for two tuples, one with and one without fractions
2189 .. code-block:: python
2191 ipTracks = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', '')
2192 goodPhotons = 'inCDCAcceptance and [clusterErrorTiming < 1e6] and [clusterE1E9 > 0.4 or E > 0.075]'
2193 goodROEGamma = ('ROESel', '[dr < 2] and [abs(dz) < 5]', goodPhotons, '')
2194 goodROEKLM = ('IPtracks', '[dr < 2] and [abs(dz) < 5]', '', 'nKLMClusterTrackMatches == 0')
2195 appendROEMasks('B+:sig', [ipTracks, goodROEGamma, goodROEKLM], path=mypath)
2197 @param list_name name of the input ParticleList
2198 @param mask_tuples array of ROEMask list tuples to be appended
2199 @param path modules are added to this path
2201 compatible_masks = []
2202 for mask
in mask_tuples:
2205 compatible_masks += [(*mask,
'')]
2207 compatible_masks += [mask]
2208 roeMask = register_module(
'RestOfEventInterpreter')
2209 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2210 roeMask.param(
'particleList', list_name)
2211 roeMask.param(
'ROEMasks', compatible_masks)
2212 path.add_module(roeMask)
2215 def updateROEMask(list_name,
2218 eclClusterSelection='',
2219 klmClusterSelection='',
2222 Update an existing ROE mask by applying additional selection cuts for
2223 tracks and/or clusters.
2225 See function `appendROEMask`!
2227 @param list_name name of the input ParticleList
2228 @param mask_name name of the ROEMask to update
2229 @param trackSelection decay string for the track-based particles in ROE
2230 @param eclClusterSelection decay string for the ECL-based particles in ROE
2231 @param klmClusterSelection decay string for the KLM-based particles in ROE
2232 @param path modules are added to this path
2235 roeMask = register_module(
'RestOfEventInterpreter')
2236 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
2237 roeMask.param(
'particleList', list_name)
2238 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection, klmClusterSelection)])
2239 roeMask.param(
'update',
True)
2240 path.add_module(roeMask)
2243 def updateROEMasks(list_name, mask_tuples, path):
2245 Update existing ROE masks by applying additional selection cuts for tracks
2248 The multiple ROE masks with their own selection criteria are specified
2249 via list tuples (mask_name, trackSelection, eclClusterSelection, klmClusterSelection)
2251 See function `appendROEMasks`!
2253 @param list_name name of the input ParticleList
2254 @param mask_tuples array of ROEMask list tuples to be appended
2255 @param path modules are added to this path
2257 compatible_masks = []
2258 for mask
in mask_tuples:
2261 compatible_masks += [(*mask,
'')]
2263 compatible_masks += [mask]
2265 roeMask = register_module(
'RestOfEventInterpreter')
2266 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2267 roeMask.param(
'particleList', list_name)
2268 roeMask.param(
'ROEMasks', compatible_masks)
2269 roeMask.param(
'update',
True)
2270 path.add_module(roeMask)
2273 def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2275 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2276 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2277 This function should be executed only in the for_each roe path for the current ROE object.
2279 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2280 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2281 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2282 pion particle list (e.g. 'pi+:someLabel').
2284 Updating a non-existing mask will create a new one.
2286 - keep only those tracks that were used in provided particle list
2288 .. code-block:: python
2290 keepInROEMasks('pi+:goodTracks', 'mask', '', path=mypath)
2292 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2294 .. code-block:: python
2296 keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1', path=mypath)
2299 @param list_name name of the input ParticleList
2300 @param mask_names array of ROEMasks to be updated
2301 @param cut_string decay string with which the mask will be updated
2302 @param path modules are added to this path
2305 updateMask = register_module(
'RestOfEventUpdater')
2306 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2307 updateMask.param(
'particleList', list_name)
2308 updateMask.param(
'updateMasks', mask_names)
2309 updateMask.param(
'cutString', cut_string)
2310 updateMask.param(
'discard',
False)
2311 path.add_module(updateMask)
2314 def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2316 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2317 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2318 This function should be executed only in the for_each roe path for the current ROE object.
2320 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2321 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2322 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2323 pion particle list (e.g. 'pi+:someLabel').
2325 Updating a non-existing mask will create a new one.
2327 - discard tracks that were used in provided particle list
2329 .. code-block:: python
2331 discardFromROEMasks('pi+:badTracks', 'mask', '', path=mypath)
2333 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2335 .. code-block:: python
2337 discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1', path=mypath)
2340 @param list_name name of the input ParticleList
2341 @param mask_names array of ROEMasks to be updated
2342 @param cut_string decay string with which the mask will be updated
2343 @param path modules are added to this path
2346 updateMask = register_module(
'RestOfEventUpdater')
2347 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2348 updateMask.param(
'particleList', list_name)
2349 updateMask.param(
'updateMasks', mask_names)
2350 updateMask.param(
'cutString', cut_string)
2351 updateMask.param(
'discard',
True)
2352 path.add_module(updateMask)
2355 def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2357 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2358 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2359 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2360 passing it can be applied.
2362 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2363 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2365 Updating a non-existing mask will create a new one.
2367 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2369 .. code-block:: python
2371 optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550', path=mypath)
2373 @param list_name name of the input ParticleList
2374 @param mask_names array of ROEMasks to be updated
2375 @param cut_string decay string with which the mask will be updated
2376 @param path modules are added to this path
2379 updateMask = register_module(
'RestOfEventUpdater')
2380 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2381 updateMask.param(
'particleList', list_name)
2382 updateMask.param(
'updateMasks', mask_names)
2383 updateMask.param(
'cutString', cut_string)
2384 path.add_module(updateMask)
2387 def updateROEUsingV0Lists(target_particle_list, mask_names, default_cleanup=True, selection_cuts=None,
2388 apply_mass_fit=False, fitter='treefit', path=None):
2390 This function creates V0 particle lists (photons, :math:`K^0_S` and :math:`\\Lambda^0`)
2391 and it uses V0 candidates to update the Rest Of Event, which is associated to the target particle list.
2392 It is possible to apply a standard or customized selection and mass fit to the V0 candidates.
2395 @param target_particle_list name of the input ParticleList
2396 @param mask_names array of ROE masks to be applied
2397 @param default_cleanup if True, predefined cuts will be applied on the V0 lists
2398 @param selection_cuts a single string of selection cuts or tuple of three strings (photon_cuts, K_S0_cuts, Lambda0_cuts),
2399 which will be applied to the V0 lists. These cuts will have a priority over the default ones.
2400 @param apply_mass_fit if True, a mass fit will be applied to the V0 particles
2401 @param fitter string, that represent a fitter choice: "treefit" for TreeFitter and "kfit" for KFit
2402 @param path modules are added to this path
2404 roe_path = create_path()
2405 deadEndPath = create_path()
2406 signalSideParticleFilter(target_particle_list,
'', roe_path, deadEndPath)
2408 if (default_cleanup
and selection_cuts
is None):
2409 B2INFO(
"Using default cleanup in updateROEUsingV0Lists.")
2410 selection_cuts =
'abs(dM) < 0.1 '
2411 selection_cuts +=
'and daughter(0,particleID) > 0.2 and daughter(1,particleID) > 0.2 '
2412 selection_cuts +=
'and daughter(0,thetaInCDCAcceptance) and daughter(1,thetaInCDCAcceptance)'
2413 if (selection_cuts
is None or selection_cuts ==
''):
2414 B2INFO(
"No cleanup in updateROEUsingV0Lists.")
2415 selection_cuts = (
'True',
'True',
'True')
2416 if (isinstance(selection_cuts, str)):
2417 selection_cuts = (selection_cuts, selection_cuts, selection_cuts)
2419 roe_cuts =
'isInRestOfEvent > 0'
2420 fillConvertedPhotonsList(
'gamma:v0_roe -> e+ e-', f
'{selection_cuts[0]} and {roe_cuts}',
2422 fillParticleList(
'K_S0:v0_roe -> pi+ pi-', f
'{selection_cuts[1]} and {roe_cuts}',
2424 fillParticleList(
'Lambda0:v0_roe -> p+ pi-', f
'{selection_cuts[2]} and {roe_cuts}',
2426 fitter = fitter.lower()
2427 if (fitter !=
'treefit' and fitter !=
'kfit'):
2428 B2WARNING(
'Argument "fitter" in updateROEUsingV0Lists has only "treefit" and "kfit" options, '
2429 f
'but "{fitter}" was provided! TreeFitter will be used instead.')
2431 from vertex
import kFit, treeFit
2432 for v0
in [
'gamma:v0_roe',
'K_S0:v0_roe',
'Lambda0:v0_roe']:
2433 if (apply_mass_fit
and fitter ==
'kfit'):
2434 kFit(v0, conf_level=0.0, fit_type=
'massvertex', path=roe_path)
2435 if (apply_mass_fit
and fitter ==
'treefit'):
2436 treeFit(v0, conf_level=0.0, massConstraint=[v0.split(
':')[0]], path=roe_path)
2437 optimizeROEWithV0(v0, mask_names,
'', path=roe_path)
2438 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2441 def printROEInfo(mask_names=None, full_print=False,
2442 unpackComposites=True, path=None):
2444 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2445 It prints out basic ROE object info.
2447 If mask names are provided, specific information for those masks will be printed out.
2449 It is also possible to print out all particles in a given mask if the
2450 'full_print' is set to True.
2452 @param mask_names array of ROEMask names for printing out info
2453 @param unpackComposites if true, replace composite particles by their daughters
2454 @param full_print print out particles in mask
2455 @param path modules are added to this path
2457 if mask_names
is None:
2459 printMask = register_module(
'RestOfEventPrinter')
2460 printMask.set_name(
'RestOfEventPrinter')
2461 printMask.param(
'maskNames', mask_names)
2462 printMask.param(
'fullPrint', full_print)
2463 printMask.param(
'unpackComposites', unpackComposites)
2464 path.add_module(printMask)
2467 def buildContinuumSuppression(list_name, roe_mask, path):
2469 Creates for each Particle in the given ParticleList a ContinuumSuppression
2470 dataobject and makes basf2 relation between them.
2472 :param list_name: name of the input ParticleList
2473 :param roe_mask: name of the ROE mask
2474 :param path: modules are added to this path
2477 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2478 qqBuilder.set_name(
'QQBuilder_' + list_name)
2479 qqBuilder.param(
'particleList', list_name)
2480 qqBuilder.param(
'ROEMask', roe_mask)
2481 path.add_module(qqBuilder)
2486 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2487 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2489 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2490 @param path modules are added to this path
2493 mod = register_module(
'RemoveParticlesNotInLists')
2494 mod.param(
'particleLists', lists_to_keep)
2495 path.add_module(mod)
2498 def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2500 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2502 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2503 @param bsig_list_name Name of the Bsig ParticleList
2504 @param btag_list_name Name of the Bsig ParticleList
2505 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2507 btag = register_module(
'InclusiveBtagReconstruction')
2508 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2509 btag.param(
'upsilonListName', upsilon_list_name)
2510 btag.param(
'bsigListName', bsig_list_name)
2511 btag.param(
'btagListName', btag_list_name)
2512 btag.param(
'inputListsNames', input_lists_names)
2513 path.add_module(btag)
2516 def selectDaughters(particle_list_name, decay_string, path):
2518 Redefine the Daughters of a particle: select from decayString
2520 @param particle_list_name input particle list
2521 @param decay_string for selecting the Daughters to be preserved
2523 seld = register_module(
'SelectDaughters')
2524 seld.set_name(
'SelectDaughters_' + particle_list_name)
2525 seld.param(
'listName', particle_list_name)
2526 seld.param(
'decayString', decay_string)
2527 path.add_module(seld)
2530 def markDuplicate(particleList, prioritiseV0, path):
2532 Call DuplicateVertexMarker to find duplicate particles in a list and
2533 flag the ones that should be kept
2535 @param particleList input particle list
2536 @param prioritiseV0 if true, give V0s a higher priority
2538 markdup = register_module(
'DuplicateVertexMarker')
2539 markdup.param(
'particleList', particleList)
2540 markdup.param(
'prioritiseV0', prioritiseV0)
2541 path.add_module(markdup)
2544 PI0ETAVETO_COUNTER = 0
2547 def oldwritePi0EtaVeto(
2550 workingDirectory='.',
2551 pi0vetoname='Pi0_Prob',
2552 etavetoname='Eta_Prob',
2558 Give pi0/eta probability for hard photon.
2560 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.
2562 The current default weight files are optimised using MC9.
2563 The input variables are as below. Aliases are set to some variables during training.
2565 * M: pi0/eta candidates Invariant mass
2566 * lowE: soft photon energy in lab frame
2567 * cTheta: soft photon ECL cluster's polar angle
2568 * Zmva: soft photon output of MVA using Zernike moments of the cluster
2569 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2571 If you don't have weight files in your workingDirectory,
2572 these files are downloaded from database to your workingDirectory automatically.
2573 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
2574 about how to use this function.
2577 Please don't use following ParticleList names elsewhere:
2579 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
2580 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
2582 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
2584 @param particleList The input ParticleList
2585 @param decayString specify Particle to be added to the ParticleList
2586 @param workingDirectory The weight file directory
2587 @param downloadFlag whether download default weight files or not
2588 @param pi0vetoname extraInfo name of pi0 probability
2589 @param etavetoname extraInfo name of eta probability
2590 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2591 @param path modules are added to this path
2597 global PI0ETAVETO_COUNTER
2599 if PI0ETAVETO_COUNTER == 0:
2600 from variables
import variables
2601 variables.addAlias(
'lowE',
'daughter(1,E)')
2602 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
2603 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
2604 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
2605 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
2606 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
2608 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
2610 roe_path = create_path()
2612 deadEndPath = create_path()
2614 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
2616 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
2618 pi0softname =
'gamma:PI0SOFT'
2619 etasoftname =
'gamma:ETASOFT'
2620 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
2621 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
2625 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
2627 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
2630 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
2632 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
2634 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
2635 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
2637 if not os.path.isdir(workingDirectory):
2638 os.mkdir(workingDirectory)
2639 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
2641 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
2643 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
2644 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
2646 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
2648 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
2649 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
2651 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
2652 identifier=workingDirectory +
'/pi0veto.root')
2653 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
2654 identifier=workingDirectory +
'/etaveto.root')
2656 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
2657 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
2659 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
2660 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
2662 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2665 def writePi0EtaVeto(
2672 hardParticle='gamma',
2673 pi0PayloadNameOverride=None,
2674 pi0SoftPhotonCutOverride=None,
2675 etaPayloadNameOverride=None,
2676 etaSoftPhotonCutOverride=None
2679 Give pi0/eta probability for hard photon.
2681 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.
2683 The current default weight files are optimised using MC12.
2685 The input variables of the mva training are:
2687 * M: pi0/eta candidates Invariant mass
2688 * daughter(1,E): soft photon energy in lab frame
2689 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
2690 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2691 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
2692 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
2693 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
2694 * cosHelicityAngleMomentum: pi0/eta candidates cosHelicityAngleMomentum
2696 The following strings are available for mode:
2698 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
2699 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
2700 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
2701 * both: tight energy cut and clusterNHits cut are applied to soft photon
2703 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
2704 `pi0Prob`/`etaProb`. Otherwise, it is available as '{Pi0, Eta}ProbOrigin', '{Pi0, Eta}ProbTightEnergyThreshold', '{Pi0,
2705 Eta}ProbLargeClusterSize', or '{Pi0, Eta}ProbTightEnergyThresholdAndLargeClusterSize'} for the four modes described above, with
2706 the chosen suffix appended.
2709 Please don't use following ParticleList names elsewhere:
2711 ``gamma:HardPhoton``,
2712 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
2713 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
2714 ``pi0:EtaVeto + ListName``,
2715 ``eta:EtaVeto + ListName``
2717 @param particleList the input ParticleList
2718 @param decayString specify Particle to be added to the ParticleList
2719 @param mode choose one mode out of 'standard', 'tight', 'cluster' and 'both'
2720 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
2721 @param path modules are added to this path
2722 @param suffix optional suffix to be appended to the usual extraInfo name
2723 @param hardParticle particle name which is used to calculate the pi0/eta probability (default is gamma)
2724 @param pi0PayloadNameOverride specify the payload name of pi0 veto only if one wants to use non-default one. (default is None)
2725 @param pi0SoftPhotonCutOverride specify the soft photon selection criteria of pi0 veto only if one wants to use non-default one.
2727 @param etaPayloadNameOverride specify the payload name of eta veto only if one wants to use non-default one. (default is None)
2728 @param etaSoftPhotonCutOverride specify the soft photon selection criteria of eta veto only if one wants to use non-default one.
2732 renameSuffix =
False
2734 for module
in path.modules():
2735 if module.type() ==
"SubEvent" and not renameSuffix:
2736 for subpath
in [p.values
for p
in module.available_params()
if p.name ==
"path"]:
2739 for submodule
in subpath.modules():
2740 if f
'{hardParticle}:HardPhoton{suffix}' in submodule.name():
2742 B2WARNING(
"Same extension already used in writePi0EtaVeto, append '_0'")
2746 roe_path = create_path()
2747 deadEndPath = create_path()
2748 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
2749 fillSignalSideParticleList(f
'{hardParticle}:HardPhoton{suffix}', decayString, path=roe_path)
2751 dictListName = {
'standard':
'Origin',
2752 'tight':
'TightEnergyThreshold',
2753 'cluster':
'LargeClusterSize',
2754 'both':
'TightEnrgyThresholdAndLargeClusterSize'}
2756 dictPi0EnergyCut = {
'standard':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
2757 'tight':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]',
2758 'cluster':
'[[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]]',
2759 'both':
'[[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]]'}
2761 dictEtaEnergyCut = {
'standard':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
2762 'tight':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]',
2763 'cluster':
'[[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]]',
2764 'both':
'[[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]]'}
2766 dictNHitsCut = {
'standard':
'clusterNHits >= 0',
2767 'tight':
'clusterNHits >= 0',
2768 'cluster':
'clusterNHits >= 2',
2769 'both':
'clusterNHits >= 2'}
2771 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
2772 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
2773 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
2774 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
2776 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
2777 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
2778 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
2779 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
2781 dictPi0ExtraInfoName = {
'standard':
'Pi0ProbOrigin',
2782 'tight':
'Pi0ProbTightEnergyThreshold',
2783 'cluster':
'Pi0ProbLargeClusterSize',
2784 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize'}
2786 dictEtaExtraInfoName = {
'standard':
'EtaProbOrigin',
2787 'tight':
'EtaProbTightEnergyThreshold',
2788 'cluster':
'EtaProbLargeClusterSize',
2789 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize'}
2791 ListName = dictListName[mode]
2792 Pi0EnergyCut = dictPi0EnergyCut[mode]
2793 EtaEnergyCut = dictEtaEnergyCut[mode]
2794 TimingCut =
'abs(clusterTiming)<clusterErrorTiming'
2795 NHitsCut = dictNHitsCut[mode]
2796 Pi0PayloadName = dictPi0PayloadName[mode]
2797 EtaPayloadName = dictEtaPayloadName[mode]
2798 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
2799 EtaExtraInfoName = dictEtaExtraInfoName[mode]
2804 if pi0PayloadNameOverride
is not None:
2805 Pi0PayloadName = pi0PayloadNameOverride
2806 if pi0SoftPhotonCutOverride
is None:
2807 Pi0SoftPhotonCut = Pi0EnergyCut +
' and ' + NHitsCut
2811 Pi0SoftPhotonCut +=
' and ' + TimingCut
2813 Pi0SoftPhotonCut = pi0SoftPhotonCutOverride
2816 pi0soft = f
'gamma:Pi0Soft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
2818 fillParticleList(pi0soft, Pi0SoftPhotonCut, path=roe_path)
2820 reconstructDecay(
'pi0:Pi0Veto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + pi0soft,
'',
2821 allowChargeViolation=
True, path=roe_path)
2823 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName],
2824 extraInfoName=Pi0ExtraInfoName, identifier=Pi0PayloadName)
2826 rankByHighest(
'pi0:Pi0Veto' + ListName,
'extraInfo(' + Pi0ExtraInfoName +
')', numBest=1, path=roe_path)
2828 variableToSignalSideExtraInfo(
'pi0:Pi0Veto' + ListName,
2829 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoName + suffix}, path=roe_path)
2834 if etaPayloadNameOverride
is not None:
2835 EtaPayloadName = etaPayloadNameOverride
2836 if etaSoftPhotonCutOverride
is None:
2837 EtaSoftPhotonCut = EtaEnergyCut +
' and ' + NHitsCut
2841 EtaSoftPhotonCut +=
' and ' + TimingCut
2843 EtaSoftPhotonCut = etaSoftPhotonCutOverride
2845 etasoft = f
'gamma:EtaSoft{suffix}' + ListName +
'_' + particleList.replace(
':',
'_')
2846 fillParticleList(etasoft, EtaSoftPhotonCut, path=roe_path)
2847 reconstructDecay(
'eta:EtaVeto' + ListName + f
' -> {hardParticle}:HardPhoton{suffix} ' + etasoft,
'',
2848 allowChargeViolation=
True, path=roe_path)
2849 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName],
2850 extraInfoName=EtaExtraInfoName, identifier=EtaPayloadName)
2851 rankByHighest(
'eta:EtaVeto' + ListName,
'extraInfo(' + EtaExtraInfoName +
')', numBest=1, path=roe_path)
2852 variableToSignalSideExtraInfo(
'eta:EtaVeto' + ListName,
2853 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoName + suffix}, path=roe_path)
2855 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2858 def getBeamBackgroundProbabilityMVA(
2863 Assign a probability to each ECL cluster as being background like (0) or signal like (1)
2864 @param particleList The input ParticleList, must be a photon list
2865 @param path modules are added to this path
2868 basf2.conditions.prepend_globaltag(getAnalysisGlobaltag())
2871 listNames=particleList,
2872 extraInfoName=
'beamBackgroundProbabilityMVA',
2873 identifier=
'BeamBackgroundMVA')
2876 def buildEventKinematics(inputListNames=None, default_cleanup=True, custom_cuts=None,
2877 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
2879 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
2880 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
2881 (all track and all hits in ECL without associated track).
2883 The visible energy missing values are
2884 stored in a EventKinematics dataobject.
2886 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
2887 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
2888 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
2889 according to the PID likelihood and the option inputListNames will be ignored.
2890 @param chargedPIDPriors The prior PID fractions, that are used to regulate
2891 amount of certain charged particle species, should be a list of
2892 six floats if not None. The order of particle types is
2893 the following: [e-, mu-, pi-, K-, p+, d+]
2894 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
2895 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
2896 which would result in a standard predefined selection cuts
2897 @param path modules are added to this path
2899 if inputListNames
is None:
2901 trackCuts =
'pt > 0.1'
2902 trackCuts +=
' and thetaInCDCAcceptance'
2903 trackCuts +=
' and abs(dz) < 3'
2904 trackCuts +=
' and dr < 0.5'
2906 gammaCuts =
'E > 0.05'
2907 gammaCuts +=
' and thetaInCDCAcceptance'
2908 gammaCuts +=
' and abs(clusterTiming) < 200'
2909 if (custom_cuts
is not None):
2910 trackCuts, gammaCuts = custom_cuts
2912 if fillWithMostLikely:
2913 from stdCharged
import stdMostLikely
2914 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
2915 inputListNames = [
'%s:mostlikely_evtkin' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
2916 fillParticleList(
'gamma:evtkin',
'', loadPhotonBeamBackgroundMVA=
False, path=path)
2917 inputListNames += [
'gamma:evtkin']
2919 B2INFO(
"Using default cleanup in EventKinematics module.")
2920 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
2921 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
2922 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
2924 B2INFO(
"No cleanup in EventKinematics module.")
2925 if not inputListNames:
2926 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
2927 fillParticleList(
'pi+:evtkin',
'', path=path)
2928 fillParticleList(
'gamma:evtkin',
'', loadPhotonBeamBackgroundMVA=
False, path=path)
2929 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
2931 if (custom_cuts
is not None):
2932 B2INFO(
"Using default cleanup in EventKinematics module.")
2933 applyCuts(
'pi+:evtkin', trackCuts, path=path)
2934 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
2936 B2INFO(
"No cleanup in EventKinematics module.")
2938 particleLists = inputListNames
2940 eventKinematicsModule = register_module(
'EventKinematics')
2941 eventKinematicsModule.set_name(
'EventKinematics_reco')
2942 eventKinematicsModule.param(
'particleLists', particleLists)
2943 path.add_module(eventKinematicsModule)
2946 def buildEventKinematicsFromMC(inputListNames=None, selectionCut='', path=None):
2948 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
2949 using generated particles. If no ParticleList is provided, default generated ParticleLists are used.
2951 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
2952 If the list is empty, default ParticleLists are filled.
2953 @param selectionCut optional selection cuts
2954 @param path Path to append the eventKinematics module to.
2956 if inputListNames
is None:
2958 if (len(inputListNames) == 0):
2962 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
2965 fillParticleListFromMC(
"%s:evtkin_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
2966 True,
True, path=path)
2967 if (selectionCut !=
''):
2968 applyCuts(
"%s:evtkin_default_gen" % t, selectionCut, path=path)
2969 inputListNames += [
"%s:evtkin_default_gen" % t]
2971 eventKinematicsModule = register_module(
'EventKinematics')
2972 eventKinematicsModule.set_name(
'EventKinematics_gen')
2973 eventKinematicsModule.param(
'particleLists', inputListNames)
2974 eventKinematicsModule.param(
'usingMC',
True)
2975 path.add_module(eventKinematicsModule)
2978 def buildEventShape(inputListNames=None,
2979 default_cleanup=True,
2985 harmonicMoments=True,
2989 checkForDuplicates=False,
2992 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
2993 using the particles in the lists provided by the user. If no particle list is provided,
2994 the function will internally create a list of good tracks and a list of good photons
2995 with (optionally) minimal quality cuts.
2998 The results of the calculation are then stored into the EventShapeContainer dataobject,
2999 and are accessible using the variables of the EventShape group.
3001 The user can switch the calculation of certain quantities on or off to save computing
3002 time. By default the calculation of the high-order moments (5-8) is turned off.
3003 Switching off an option will make the corresponding variables not available.
3006 The user can provide as many particle lists
3007 as needed, using also combined particles, but the function will always assume that
3008 the lists are independent.
3009 If the lists provided by the user contain several times the same track (either with
3010 different mass hypothesis, or once as an independent particle and once as daughter of a
3011 combined particle) the results won't be reliable.
3012 A basic check for duplicates is available setting the checkForDuplicate flags,
3013 but is usually quite time consuming.
3016 @param inputListNames List of ParticleLists used to calculate the
3017 event shape variables. If the list is empty the default
3018 particleLists pi+:evtshape and gamma:evtshape are filled.
3019 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
3020 defining the internal lists. This option is ignored if the
3021 particleLists are provided by the user.
3022 @param custom_cuts tuple of selection cut strings of form (trackCuts, photonCuts), default is None,
3023 which would result in a standard predefined selection cuts
3024 @param path Path to append the eventShape modules to.
3025 @param thrust Enables the calculation of thrust-related quantities (CLEO
3026 cones, Harmonic moments, jets).
3027 @param collisionAxis Enables the calculation of the quantities related to the
3029 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
3030 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
3031 to both the thrust axis and, if collisionAxis = True, the collision axis.
3032 @param allMoments If True, calculates also the FW and harmonic moments from order
3033 5 to 8 instead of the low-order ones only.
3034 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
3035 axis and, if collisionAxis = True, the collision axis.
3036 @param jets Enables the calculation of the hemisphere momenta and masses.
3037 Requires thrust = True.
3038 @param sphericity Enables the calculation of the sphericity-related quantities.
3039 @param checkForDuplicates Perform a check for duplicate particles before adding them. This option
3040 is quite time consuming, instead of using it consider sanitizing
3041 the lists you are passing to the function.
3043 if inputListNames
is None:
3045 trackCuts =
'pt > 0.1'
3046 trackCuts +=
' and thetaInCDCAcceptance'
3047 trackCuts +=
' and abs(dz) < 3.0'
3048 trackCuts +=
' and dr < 0.5'
3050 gammaCuts =
'E > 0.05'
3051 gammaCuts +=
' and thetaInCDCAcceptance'
3052 gammaCuts +=
' and abs(clusterTiming) < 200'
3053 if (custom_cuts
is not None):
3054 trackCuts, gammaCuts = custom_cuts
3056 if not inputListNames:
3057 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
3058 fillParticleList(
'pi+:evtshape',
'', path=path)
3059 fillParticleList(
'gamma:evtshape',
'', loadPhotonBeamBackgroundMVA=
False, path=path)
3060 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
3063 if (custom_cuts
is not None):
3064 B2INFO(
"Applying standard cuts")
3065 applyCuts(
'pi+:evtshape', trackCuts, path=path)
3067 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
3069 B2WARNING(
"Creating the default lists with no cleanup.")
3071 particleLists = inputListNames
3073 eventShapeModule = register_module(
'EventShapeCalculator')
3074 eventShapeModule.set_name(
'EventShape')
3075 eventShapeModule.param(
'particleListNames', particleLists)
3076 eventShapeModule.param(
'enableAllMoments', allMoments)
3077 eventShapeModule.param(
'enableCleoCones', cleoCones)
3078 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
3079 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
3080 eventShapeModule.param(
'enableJets', jets)
3081 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
3082 eventShapeModule.param(
'enableSphericity', sphericity)
3083 eventShapeModule.param(
'enableThrust', thrust)
3084 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
3086 path.add_module(eventShapeModule)
3089 def labelTauPairMC(printDecayInfo=False, path=None, TauolaBelle=False, mapping_minus=None, mapping_plus=None):
3091 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
3092 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
3094 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
3095 @param path: module is added to this path
3096 @param TauolaBelle: if False, TauDecayMarker is set. If True, TauDecayMode is set.
3097 @param mapping_minus: if None, the map is the default one, else the path for the map is given by the user for tau-
3098 @param mapping_plus: if None, the map is the default one, else the path for the map is given by the user for tau+
3100 from basf2
import find_file
3106 m_printmode =
'default'
3108 if mapping_minus
is None:
3109 mp_file_minus = find_file(
'data/analysis/modules/TauDecayMode/map_tauminus.txt')
3111 mp_file_minus = mapping_minus
3113 if mapping_plus
is None:
3114 mp_file_plus = find_file(
'data/analysis/modules/TauDecayMode/map_tauplus.txt')
3116 mp_file_plus = mapping_plus
3118 path.add_module(
'TauDecayMode', printmode=m_printmode, file_minus=mp_file_minus, file_plus=mp_file_plus)
3121 tauDecayMarker = register_module(
'TauDecayMarker')
3122 tauDecayMarker.set_name(
'TauDecayMarker_')
3124 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
3127 def tagCurlTracks(particleLists,
3136 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
3138 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
3139 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
3141 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
3144 The module loops over all particles in a given list that meet the preselection **ptCut** and assigns them to
3145 bundles based on the response of the chosen **selector** and the required minimum response set by the
3146 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
3147 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
3151 @param particleLists: list of particle lists to check for curls.
3152 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
3153 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
3154 genParticleIndex then ranked and tagged as normal.
3155 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
3156 Note 'cut' selector is binary 0/1.
3157 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
3158 It is strongly recommended to used the 'mva' selection. The 'cut' selection
3159 is based on BN1079 and is only calibrated for Belle data.
3160 @param ptCut: pre-selection cut on transverse momentum.
3161 @param train: flag to set training mode if selector has a training mode (mva).
3162 @param path: module is added to this path.
3168 if (
not isinstance(particleLists, list)):
3169 particleLists = [particleLists]
3171 curlTagger = register_module(
'CurlTagger')
3172 curlTagger.set_name(
'CurlTagger_')
3173 curlTagger.param(
'particleLists', particleLists)
3174 curlTagger.param(
'belle', belle)
3175 curlTagger.param(
'mcTruth', mcTruth)
3176 curlTagger.param(
'responseCut', responseCut)
3177 curlTagger.param(
'selectorType', selectorType)
3178 curlTagger.param(
'ptCut', ptCut)
3179 curlTagger.param(
'train', train)
3181 path.add_module(curlTagger)
3184 def applyChargedPidMVA(particleLists, path, trainingMode, chargeIndependent=False, binaryHypoPDGCodes=(0, 0)):
3186 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
3188 The module decorates Particle objects in the input ParticleList(s) with variables
3189 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
3192 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.3.0**, **ROOT 6.20/04**).
3194 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
3196 - e (11) vs. pi (211)
3197 - mu (13) vs. pi (211)
3198 - pi (211) vs. K (321)
3199 - K (321) vs. pi (211)
3201 , or 'global' PID, namely "one-vs-others" separation. The latter exploits an MVA algorithm trained in multi-class mode,
3202 and it's the default behaviour. Currently, the multi-class training separates the following standard charged hypotheses:
3204 - e (11), mu (13), pi (211), K (321)
3207 In order to run the `ChargedPidMVA` and ensure the most up-to-date MVA training weights are applied,
3208 it is necessary to append the latest analysis global tag (GT) to the steering script.
3211 particleLists (list(str)): list of names of ParticleList objects for charged stable particles.
3212 The charge-conjugate ParticleLists will be also processed automatically.
3213 path (basf2.Path): the module is added to this path.
3214 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
3215 Needed to pick up the correct payload from the DB. Available choices:
3217 * c_Classification=0
3219 * c_ECL_Classification=2
3220 * c_ECL_Multiclass=3
3221 * c_PSD_Classification=4
3222 * c_PSD_Multiclass=5
3223 * c_ECL_PSD_Classification=6
3224 * c_ECL_PSD_Multiclass=7
3226 chargeIndependent (bool, ``optional``): use a BDT trained on a sample of inclusively charged particles.
3227 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
3228 Required only for binary PID mode.
3231 from ROOT
import Belle2
3232 from variables
import variables
as vm
3236 TrainingMode = Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode
3239 plSet = set(particleLists)
3243 TrainingMode.c_Classification:
3244 {
"mode":
"Classification",
"detector":
"ALL"},
3245 TrainingMode.c_Multiclass:
3246 {
"mode":
"Multiclass",
"detector":
"ALL"},
3247 TrainingMode.c_ECL_Classification:
3248 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
3249 TrainingMode.c_ECL_Multiclass:
3250 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
3251 TrainingMode.c_PSD_Classification:
3252 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
3253 TrainingMode.c_PSD_Multiclass:
3254 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
3255 TrainingMode.c_ECL_PSD_Classification:
3256 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
3257 TrainingMode.c_ECL_PSD_Multiclass:
3258 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
3261 if payloadNames.get(trainingMode)
is None:
3262 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
3263 "\nis not supported. Please choose among the following:\n",
3264 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
3266 mode = payloadNames.get(trainingMode).get(
"mode")
3267 detector = payloadNames.get(trainingMode).get(
"detector")
3269 payloadName = f
"ChargedPidMVAWeights_{mode}"
3274 Const.electron.getPDGCode():
3275 {
"pName":
"e",
"pFullName":
"electron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3276 Const.muon.getPDGCode():
3277 {
"pName":
"mu",
"pFullName":
"muon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3278 Const.pion.getPDGCode():
3279 {
"pName":
"pi",
"pFullName":
"pion",
"pNameBkg":
"K",
"pdgIdBkg": Const.kaon.getPDGCode()},
3280 Const.kaon.getPDGCode():
3281 {
"pName":
"K",
"pFullName":
"kaon",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3282 Const.proton.getPDGCode():
3283 {
"pName":
"p",
"pFullName":
"proton",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3284 Const.deuteron.getPDGCode():
3285 {
"pName":
"d",
"pFullName":
"deuteron",
"pNameBkg":
"pi",
"pdgIdBkg": Const.pion.getPDGCode()},
3289 vm.addAlias(
"__event__",
"evtNum")
3291 for detID
in Const.PIDDetectors.c_set:
3294 if detID == Const.EDetector.SVD:
3295 B2WARNING(
"The ChargedPidMVA training currently does not include the SVD.")
3298 detName = Const.parseDetectors(detID)
3300 for pdgIdSig, info
in stdChargedMap.items():
3302 if binaryHypoPDGCodes == (0, 0):
3304 pFullName = info[
"pFullName"]
3308 alias = f
"{pFullName}ID_{detName}"
3309 orig = f
"pidProbabilityExpert({pdgIdSig}, {detName})"
3310 vm.addAlias(alias, orig)
3313 alias_trf = f
"{pFullName}ID_{detName}_LogTransfo"
3314 orig_trf = f
"formula(-1. * log10(formula(((1. - {orig}) + {epsilon}) / ({orig} + {epsilon}))))"
3315 vm.addAlias(alias_trf, orig_trf)
3319 alias_trf = f
"{pFullName}ID_LogTransfo"
3320 orig_trf = f
"formula(-1. * log10(formula(((1. - {pFullName}ID) + {epsilon}) / ({pFullName}ID + {epsilon}))))"
3321 vm.addAlias(alias_trf, orig_trf)
3325 pName, pNameBkg, pdgIdBkg = info[
"pName"], info[
"pNameBkg"], info[
"pdgIdBkg"]
3329 alias = f
"deltaLogL_{pName}_{pNameBkg}_{detName}"
3330 orig = f
"pidDeltaLogLikelihoodValueExpert({pdgIdSig}, {pdgIdBkg}, {detName})"
3331 vm.addAlias(alias, orig)
3335 alias = f
"deltaLogL_{pName}_{pNameBkg}_ALL"
3336 orig = f
"pidDeltaLogLikelihoodValueExpert({pdgIdSig}, {pdgIdBkg}, ALL)"
3337 vm.addAlias(alias, orig)
3341 if binaryHypoPDGCodes == (0, 0):
3344 chargedpid = register_module(
"ChargedPidMVAMulticlass")
3345 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
3352 binaryOpts = [(pdgIdSig, info[
"pdgIdBkg"])
for pdgIdSig, info
in stdChargedMap.items()]
3354 if binaryHypoPDGCodes
not in binaryOpts:
3355 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
3356 ". Please choose among the following pairs:\n",
3357 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
3359 chargedpid = register_module(
"ChargedPidMVA")
3360 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
3361 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
3362 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
3364 chargedpid.param(
"particleLists", list(plSet))
3365 chargedpid.param(
"payloadName", payloadName)
3366 chargedpid.param(
"chargeIndependent", chargeIndependent)
3369 if detector ==
"ECL":
3370 chargedpid.param(
"useECLOnlyTraining",
True)
3372 path.add_module(chargedpid)
3375 def calculateTrackIsolation(list_name, path, *detectors, use2DRhoPhiDist=False, alias=None):
3377 Given a list of charged stable particles, compute variables that quantify "isolation" of the associated tracks.
3379 Currently, a proxy for isolation is defined as the 3D distance (or optionally, a 2D distance projecting on r-phi)
3380 of each particle's track to its closest neighbour at a given detector entry surface.
3383 list_name (str): name of the input ParticleList.
3384 It must be a list of charged stable particles as defined in ``Const::chargedStableSet``.
3385 The charge-conjugate ParticleList will be also processed automatically.
3386 path (basf2.Path): the module is added to this path.
3387 use2DRhoPhiDist (Optional[bool]): if true, will calculate the pair-wise track distance
3388 as the cord length on the (rho, phi) projection.
3389 By default, a 3D distance is calculated.
3390 alias (Optional[str]): An alias to the extraInfo variable computed by the `TrackIsoCalculator` module.
3391 Please note, for each input detector a variable is calculated,
3392 and the detector's name is appended to the alias to distinguish them.
3393 *detectors: detectors at whose entry surface track isolation variables will be calculated.
3394 Choose among: "CDC", "PID", "ECL", "KLM" (NB: 'PID' indicates TOP+ARICH entry surface.)
3398 from variables
import variables
3400 det_choices = (
"CDC",
"PID",
"ECL",
"KLM")
3401 if any(d
not in det_choices
for d
in detectors):
3402 B2ERROR(
"Your input detector list: ", detectors,
" contains an invalid choice. Please select among: ", det_choices)
3404 for det
in detectors:
3405 path.add_module(
"TrackIsoCalculator",
3406 particleList=list_name,
3407 detectorInnerSurface=det,
3408 use2DRhoPhiDist=use2DRhoPhiDist)
3409 if isinstance(alias, str):
3410 if not use2DRhoPhiDist:
3411 variables.addAlias(f
"{alias}{det}", f
"extraInfo(dist3DToClosestTrkAt{det}Surface)")
3413 variables.addAlias(f
"{alias}{det}", f
"extraInfo(dist2DRhoPhiToClosestTrkAt{det}Surface)")
3416 def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
3418 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
3419 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
3420 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
3421 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
3424 .. code-block:: python
3426 from modularAnalysis import calculateDistance
3427 calculateDistance('list_name', 'decay_string', "mode", path=user_path)
3429 @param list_name name of the input ParticleList
3430 @param decay_string select particles between the distance of closest approach will be calculated
3431 @param mode Specifies how the distance is calculated
3432 vertextrack: calculate the distance of closest approach between a track and a\
3433 vertex, taking the first candidate as vertex, default
3434 trackvertex: calculate the distance of closest approach between a track and a\
3435 vertex, taking the first candidate as track
3436 2tracks: calculates the distance of closest approach between two tracks
3437 2vertices: calculates the distance between two vertices
3438 vertexbtube: calculates the distance of closest approach between a vertex and btube
3439 trackbtube: calculates the distance of closest approach between a track and btube
3440 @param path modules are added to this path
3444 dist_mod = register_module(
'DistanceCalculator')
3446 dist_mod.set_name(
'DistanceCalculator_' + list_name)
3447 dist_mod.param(
'listName', list_name)
3448 dist_mod.param(
'decayString', decay_string)
3449 dist_mod.param(
'mode', mode)
3450 path.add_module(dist_mod)
3453 def addInclusiveDstarReconstruction(decayString, slowPionCut, DstarCut, path):
3455 Adds the InclusiveDstarReconstruction module to the given path.
3456 This module creates a D* particle list by estimating the D* four momenta
3457 from slow pions, specified by a given cut. The D* energy is approximated
3458 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
3459 momentum is calculated using the D* PDG mass and the direction is collinear
3460 to the slow pion direction. The charge of the given pion list has to be consistent
3463 @param decayString Decay string, must be of form ``D* -> pi``
3464 @param slowPionCut Cut applied to the input pion list to identify slow pions
3465 @param DstarCut Cut applied to the output D* list
3466 @param path the module is added to this path
3468 incl_dstar = register_module(
"InclusiveDstarReconstruction")
3469 incl_dstar.param(
"decayString", decayString)
3470 incl_dstar.param(
"slowPionCut", slowPionCut)
3471 incl_dstar.param(
"DstarCut", DstarCut)
3472 path.add_module(incl_dstar)
3475 def scaleError(outputListName, inputListName,
3476 scaleFactors=[1.17, 1.12, 1.16, 1.15, 1.13],
3477 d0Resolution=[12.2e-4, 14.1e-4],
3478 z0Resolution=[13.4e-4, 15.3e-4],
3481 This module creates a new charged particle list.
3482 The helix errors of the new particles are scaled by constant factors.
3483 These scale factors are defined for each helix parameter (d0, phi0, omega, z0, tanlambda).
3484 The impact parameter resolution can be defined in a pseudo-momentum dependent form,
3485 which limits the d0 and z0 errors so that they do not shrink below the resolution.
3486 This module is supposed to be used for low-momentum (0-3 GeV/c) tracks in BBbar events.
3487 Details will be documented in a Belle II note by the Belle II Japan ICPV group.
3489 @param inputListName Name of input charged particle list to be scaled
3490 @param outputListName Name of output charged particle list with scaled error
3491 @param scaleFactors List of five constants to be multiplied to each of helix errors
3492 @param d0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
3493 defining d0 resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**1.5))**2 }
3494 @param z0Resolution List of two parameters, (a [cm], b [cm/(GeV/c)]),
3495 defining z0 resolution as sqrt{ a**2 + (b / (p*beta*sinTheta**2.5))**2 }
3497 scale_error = register_module(
"HelixErrorScaler")
3498 scale_error.set_name(
'ScaleError_' + inputListName)
3499 scale_error.param(
'inputListName', inputListName)
3500 scale_error.param(
'outputListName', outputListName)
3501 scale_error.param(
'scaleFactors', scaleFactors)
3502 scale_error.param(
'd0ResolutionParameters', d0Resolution)
3503 scale_error.param(
'z0ResolutionParameters', z0Resolution)
3504 path.add_module(scale_error)
3507 def correctEnergyBias(inputListNames, tableName, path=None):
3509 Scale energy of the particles according to the scaling factor.
3510 If the particle list contains composite particles, the energy of the daughters are scaled.
3511 Subsequently, the energy of the mother particle is updated as well.
3514 inputListNames (list(str)): input particle list names
3515 tableName : stored in localdb and created using ParticleWeightingLookUpCreator
3516 path (basf2.Path): module is added to this path
3519 correctenergybias = register_module(
'EnergyBiasCorrection')
3520 correctenergybias.param(
'particleLists', inputListNames)
3521 correctenergybias.param(
'tableName', tableName)
3522 path.add_module(correctenergybias)
3525 def addPhotonEfficiencyRatioVariables(inputListNames, tableName, path=None):
3527 Add photon Data/MC detection efficiency ratio weights to the specified particle list
3530 inputListNames (list(str)): input particle list names
3531 tableName : taken from database with appropriate name
3532 path (basf2.Path): module is added to this path
3535 photon_efficiency_correction = register_module(
'PhotonEfficiencySystematics')
3536 photon_efficiency_correction.param(
'particleLists', inputListNames)
3537 photon_efficiency_correction.param(
'tableName', tableName)
3538 path.add_module(photon_efficiency_correction)
3541 def getAnalysisGlobaltag(timeout=180) -> str:
3543 Returns a string containing the name of the latest and recommended analysis globaltag.
3546 timeout: Seconds to wait for b2conditionsdb-recommend
3551 tags = subprocess.check_output(
3552 [
'b2conditionsdb-recommend',
'--oneline'],
3554 ).decode(
'UTF-8').rstrip().split(
' ')
3557 if tag.startswith(
'analysis_tools'):
3561 except subprocess.TimeoutExpired
as te:
3562 B2FATAL(f
'A {te} exception was raised during the call of getAnalysisGlobaltag(). '
3563 'The function took too much time to retrieve the requested information '
3564 'from the versioning repository.\n'
3565 'Plase try to re-run your job. In case of persistent failures, there may '
3566 'be issues with the DESY collaborative services, so please contact the experts.')
3567 except subprocess.CalledProcessError
as ce:
3568 B2FATAL(f
'A {ce} exception was raised during the call of getAnalysisGlobaltag(). '
3569 'Please try to re-run your job. In case of persistent failures, please contact '
3573 def getNbarIDMVA(particleList, path=None, ):
3575 This function can give a score to predict if it is a anti-n0.
3576 It is not used to predict n0.
3577 Currently, this can be used only for ECL cluster.
3578 output will be stored in extraInfo(nbarID); -1 means MVA invalid
3579 @param particleList The input ParticleList
3580 @param path modules are added to this path
3582 from variables
import variables
3583 variables.addAlias(
'V1',
'clusterHasPulseShapeDiscrimination')
3584 variables.addAlias(
'V2',
'clusterE')
3585 variables.addAlias(
'V3',
'clusterLAT')
3586 variables.addAlias(
'V4',
'clusterE1E9')
3587 variables.addAlias(
'V5',
'clusterE9E21')
3588 variables.addAlias(
'V6',
'clusterZernikeMVA')
3589 variables.addAlias(
'V7',
'clusterAbsZernikeMoment40')
3590 variables.addAlias(
'V8',
'clusterAbsZernikeMoment51')
3592 variables.addAlias(
'nbarIDValid',
3593 'passesCut(V1 == 1 and V2 >= 0 and V3 >= 0 and V4 >= 0 and V5 >= 0 and V6 >= 0 and V7 >= 0 and V8 >= 0)')
3594 variables.addAlias(
'nbarIDmod',
'conditionalVariableSelector(nbarIDValid == 1, extraInfo(nbarIDFromMVA), constant(-1.0))')
3595 basf2.conditions.prepend_globaltag(getAnalysisGlobaltag())
3596 path.add_module(
'MVAExpert', listNames=particleList, extraInfoName=
'nbarIDFromMVA', identifier=
'db_nbarIDECL')
3600 if __name__ ==
'__main__':
3602 pretty_print_module(__name__,
"modularAnalysis")
This class provides a set of constants for the framework.
The DecayDescriptor stores information about a decay tree or parts of a decay tree.
Describe one component of the Geometry.
static DBStore & Instance()
Instance of a singleton DBStore.
def add_mdst_output(path, mc=True, filename='mdst.root', additionalBranches=[], dataDescription=None)
def add_udst_output(path, filename, particleLists=None, additionalBranches=None, dataDescription=None, mc=True)