5 This module defines wrapper functions around the analysis modules.
8 from basf2
import register_module, create_path
9 from basf2
import B2INFO, B2WARNING, B2ERROR, B2FATAL
14 def setAnalysisConfigParams(configParametersAndValues, path):
16 Sets analysis configuration parameters.
20 - 'tupleStyle': 'Default' (default) or 'Laconic'
21 o) defines the style of the branch name in the ntuple
23 - 'mcMatchingVersion': Specifies what version of mc matching algorithm is going to be used:
25 - 'MC5' - analysis of BelleII MC5
26 - 'Belle' - analysis of Belle MC
27 - 'BelleII' (default) - all other cases
29 @param configParametersAndValues dictionary of parameters and their values of the form {param1: value, param2: value, ...)
30 @param modules are added to this path
33 conf = register_module(
'AnalysisConfiguration')
35 allParameters = [
'tupleStyle',
'mcMatchingVersion']
37 keys = configParametersAndValues.keys()
39 if key
not in allParameters:
40 allParametersString =
', '.join(allParameters)
41 B2ERROR(
'Invalid analysis configuration parameter: ' + key +
'.\n'
42 'Please use one of the following: ' + allParametersString)
44 for param
in allParameters:
45 if param
in configParametersAndValues:
46 conf.param(param, configParametersAndValues.get(param))
51 def inputMdst(environmentType, filename, path, skipNEvents=0, entrySequence=None, *, parentLevel=0):
53 Loads the specified ROOT (DST/mDST/muDST) file with the RootInput module.
55 The correct environment (e.g. magnetic field settings) are determined from
56 the specified environment type. For the possible values please see
60 environmentType (str): type of the environment to be loaded
61 filename (str): the name of the file to be loaded
62 path (basf2.Path): modules are added to this path
63 skipNEvents (int): N events of the input file are skipped
64 entrySequence (str): The number sequences (e.g. 23:42,101) defining the entries which are processed.
65 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
67 if entrySequence
is not None:
68 entrySequence = [entrySequence]
70 inputMdstList(environmentType, [filename], path, skipNEvents, entrySequence, parentLevel=parentLevel)
73 def inputMdstList(environmentType, filelist, path, skipNEvents=0, entrySequences=None, *, parentLevel=0):
75 Loads the specified ROOT (DST/mDST/muDST) files with the RootInput module.
77 The correct environment (e.g. magnetic field settings) are determined from the specified environment type.
78 The currently available environments are:
80 - 'MC5': for analysis of Belle II MC samples produced with releases prior to build-2016-05-01.
81 This environment sets the constant magnetic field (B = 1.5 T)
82 - 'MC6': for analysis of Belle II MC samples produced with build-2016-05-01 or newer but prior to release-00-08-00
83 - 'MC7': for analysis of Belle II MC samples produced with build-2016-05-01 or newer but prior to release-00-08-00
84 - 'MC8', for analysis of Belle II MC samples produced with release-00-08-00 or newer but prior to release-02-00-00
85 - 'MC9', for analysis of Belle II MC samples produced with release-00-08-00 or newer but prior to release-02-00-00
86 - 'MC10', for analysis of Belle II MC samples produced with release-00-08-00 or newer but prior to release-02-00-00
87 - 'default': for analysis of Belle II MC samples produced with releases with release-02-00-00 or newer.
88 This environment sets the default magnetic field (see geometry settings)
89 - 'Belle': for analysis of converted (or during of conversion of) Belle MC/DATA samples
90 - 'None': for analysis of generator level information or during simulation/reconstruction of
91 previously generated events
93 Note that there is no difference between MC6 and MC7. Both are given for sake of completion.
94 The same is true for MC8, MC9 and MC10
97 environmentType (str): type of the environment to be loaded
98 filelist (list(str)): the filename list of files to be loaded
99 path (basf2.Path): modules are added to this path
100 skipNEvents (int): N events of the input files are skipped
101 entrySequences (list(str)): The number sequences (e.g. 23:42,101) defining
102 the entries which are processed for each inputFileName.
103 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
106 roinput = register_module(
'RootInput')
107 roinput.param(
'inputFileNames', filelist)
108 roinput.param(
'skipNEvents', skipNEvents)
109 if entrySequences
is not None:
110 roinput.param(
'entrySequences', entrySequences)
111 roinput.param(
'parentLevel', parentLevel)
113 path.add_module(roinput)
114 progress = register_module(
'ProgressBar')
115 path.add_module(progress)
119 environToMagneticField = {
'MC5':
'MagneticFieldConstant',
123 'Belle':
'MagneticFieldConstantBelle'}
125 fixECLClusters = {
'MC5':
True,
131 if environmentType
in environToMagneticField:
132 fieldType = environToMagneticField[environmentType]
133 if fieldType
is not None:
134 from ROOT
import Belle2
138 elif environmentType
in [
"MC8",
"MC9",
"MC10"]:
140 from basf2
import conditions
141 conditions.globaltags += [
"Legacy_MagneticField_MC8_MC9_MC10"]
142 elif environmentType
is 'None':
143 B2INFO(
'No magnetic field is loaded. This is OK, if generator level information only is studied.')
145 environments =
' '.join(list(environToMagneticField.keys()) + [
"MC8",
"MC9",
"MC10"])
146 B2FATAL(
'Incorrect environment type provided: ' + environmentType +
'! Please use one of the following:' + environments)
149 if environmentType
is 'Belle':
150 setAnalysisConfigParams({
'mcMatchingVersion':
'Belle'}, path)
153 if environmentType
is 'MC5':
154 setAnalysisConfigParams({
'mcMatchingVersion':
'MC5'}, path)
157 if fixECLClusters.get(environmentType)
is True:
158 fixECL = register_module(
'FixECLClusters')
159 path.add_module(fixECL)
162 def outputMdst(filename, path):
164 Saves mDST (mini-Data Summary Tables) to the output root file.
171 def outputUdst(filename, particleLists=[], includeArrays=[], path=None, dataDescription=None):
173 Save uDST (micro-Data Summary Tables) = MDST + Particles + ParticleLists
174 The charge-conjugate lists of those given in particleLists are also stored.
175 Additional Store Arrays and Relations to be stored can be specified via includeArrays
178 Note that this does not reduce the amount of Particle objects saved,
179 see skimOutputUdst() for a function that does.
185 plSet = set(particleLists)
186 for List
in particleLists:
187 name, label = List.split(
':')
190 partBranches = [
'Particles',
'ParticlesToMCParticles',
191 'ParticlesToPIDLikelihoods',
'ParticleExtraInfoMap',
192 'EventExtraInfo'] + includeArrays + list(plSet)
196 if dataDescription
is None:
199 dataDescription.update(dataLevel=
"udst")
202 additionalBranches=partBranches,
203 dataDescription=dataDescription)
206 def skimOutputUdst(skimDecayMode, skimParticleLists=[], outputParticleLists=[],
207 includeArrays=[], path=None, *,
208 outputFile=None, dataDescription=None):
210 Create a new path for events that contain a non-empty particle list specified via skimParticleLists.
211 Write the accepted events as a udst file, saving only particles from skimParticleLists
212 and from outputParticleLists.
213 Additional Store Arrays and Relations to be stored can be specified via includeArrays
216 :param str skimDecayMode: Name of the skim. If no outputFile is given this is
217 also the name of the output filename. This name will be added to the
218 FileMetaData as an extra data description "skimDecayMode"
219 :param list(str) skimParticleLists: Names of the particle lists to skim for.
220 An event will be accepted if at least one of the particle lists is not empty
221 :param list(str) outputParticleLists: Names of the particle lists to store in
222 the output in addition to the ones in skimParticleLists
223 :param list(str) includeArrays: datastore arrays/objects to write to the output
224 file in addition to mdst and particle information
225 :param basf2.Path path: Path to add the skim output to. Defaults to the default analysis path
226 :param str outputFile: Name of the output file if different from the skim name
227 :param dict dataDescription: Additional data descriptions to add to the output file. For example {"mcEventType":"mixed"}
230 from basf2
import AfterConditionPath
232 if outputFile
is None:
233 outputFile = skimDecayMode
236 if not outputFile.endswith(
".udst.root"):
237 outputFile +=
".udst.root"
239 skimfilter = register_module(
'SkimFilter')
240 skimfilter.set_name(
'SkimFilter_' + skimDecayMode)
241 skimfilter.param(
'particleLists', skimParticleLists)
242 path.add_module(skimfilter)
243 filter_path = create_path()
244 skimfilter.if_value(
'=1', filter_path, AfterConditionPath.CONTINUE)
247 skim_path = create_path()
248 saveParticleLists = skimParticleLists + outputParticleLists
253 if dataDescription
is None:
256 dataDescription.setdefault(
"skimDecayMode", skimDecayMode)
257 outputUdst(outputFile, saveParticleLists, includeArrays, path=skim_path,
258 dataDescription=dataDescription)
259 filter_path.add_independent_path(skim_path,
"skim_" + skimDecayMode)
262 def outputIndex(filename, path, includeArrays=[], keepParents=False, mc=True):
264 Write out all particle lists as an index file to be reprocessed using parentLevel flag.
265 Additional branches necessary for file to be read are automatically included.
266 Additional Store Arrays and Relations to be stored can be specified via includeArrays
269 @param str filename the name of the output index file
270 @param str path modules are added to this path
271 @param list(str) includeArrays: datastore arrays/objects to write to the output
272 file in addition to particle lists and related information
273 @param bool keepParents whether the parents of the input event will be saved as the parents of the same event
274 in the output index file. Useful if you are only adding more information to another index file
275 @param bool mc whether the input data is MC or not
279 onlyPLists = register_module(
'OnlyWriteOutParticleLists')
280 path.add_module(onlyPLists)
285 'ParticlesToMCParticles',
286 'ParticlesToPIDLikelihoods',
287 'ParticleExtraInfoMap',
290 branches = [
'EventMetaData']
291 persistentBranches = [
'FileMetaData']
295 branches += partBranches
296 branches += includeArrays
298 r1 = register_module(
'RootOutput')
299 r1.param(
'outputFileName', filename)
300 r1.param(
'additionalBranchNames', branches)
301 r1.param(
'branchNamesPersistent', persistentBranches)
302 r1.param(
'keepParents', keepParents)
306 def setupEventInfo(noEvents, path):
308 Prepare to generate events. This function sets up the EventInfoSetter.
309 You should call this before adding a generator from generators.
310 The experiment and run numbers are set to 0 (run independent generic MC in phase 3).
311 https://confluence.desy.de/display/BI/Experiment+numbering
314 noEvents (int): number of events to be generated
315 path (basf2.Path): modules are added to this path
317 evtnumbers = register_module(
'EventInfoSetter')
318 evtnumbers.param(
'evtNumList', [noEvents])
319 evtnumbers.param(
'runList', [0])
320 evtnumbers.param(
'expList', [0])
321 path.add_module(evtnumbers)
324 def loadGearbox(path, silence_warning=False):
326 Loads Gearbox module to the path.
329 Should be used in a job with *cosmic event generation only*
331 Needed for scripts which only generate cosmic events in order to
334 @param path modules are added to this path
335 @param silence_warning stops a verbose warning message if you know you want to use this function
338 if not silence_warning:
339 B2WARNING(
"""You are overwriting the geometry from the database with Gearbox.
340 This is fine if you're generating cosmic events. But in most other cases you probably don't want this.
342 If you're really sure you know what you're doing you can suppress this message with:
344 >>> loadGearbox(silence_warning=True)
348 paramloader = register_module(
'Gearbox')
349 path.add_module(paramloader)
352 def printPrimaryMCParticles(path):
354 Prints all primary MCParticles.
357 mcparticleprinter = register_module(
'PrintMCParticles')
358 path.add_module(mcparticleprinter)
361 def printMCParticles(onlyPrimaries=False, maxLevel=-1, path=None):
363 Prints all MCParticles or just primary MCParticles up to specified level. -1 means no limit.
366 mcparticleprinter = register_module(
'PrintMCParticles')
367 mcparticleprinter.param(
'onlyPrimaries', onlyPrimaries)
368 mcparticleprinter.param(
'maxLevel', maxLevel)
369 path.add_module(mcparticleprinter)
372 def correctBrems(outputList,
375 maximumAcceptance=3.0,
376 multiplePhotons=False,
377 usePhotonOnlyOnce=True,
381 For each particle in the given ``inputList``, copies it to the ``outputList`` and adds the
382 4-vector of the photon(s) in the ``gammaList`` which has(have) a weighted named relation to
383 the particle's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
386 This can only work if the mdst file contains the *Bremsstrahlung* named relation. Official MC samples
387 up to and including MC12 and proc9 **do not** contain this. Newer production campaigns (from proc10 and MC13) will.
390 Please note that a new particle is always generated, with the old particle and -if found- one or more
391 photons as daughters.
393 The ``inputList`` should contain particles with associated tracks. Otherwise the module will exit with an error.
395 The ``gammaList`` should contain photons. Otherwise the module will exit with an error.
397 @param outputList The output particle list name containing the corrected particles
398 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
399 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
400 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
401 @param multiplePhotons Whether to use only one photon (the one with the smallest acceptance) or as many as possible
402 @param usePhotonOnlyOnce If true, each brems candidate is used to correct only the track with the smallest relation weight
403 @param writeOut Whether `RootOutput` module should save the created ``outputList``
404 @param path The module is added to this path
407 bremscorrector = register_module(
'BremsFinder')
408 bremscorrector.set_name(
'bremsCorrector_' + outputList)
409 bremscorrector.param(
'inputList', inputList)
410 bremscorrector.param(
'outputList', outputList)
411 bremscorrector.param(
'gammaList', gammaList)
412 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
413 bremscorrector.param(
'multiplePhotons', multiplePhotons)
414 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
415 bremscorrector.param(
'writeOut', writeOut)
416 path.add_module(bremscorrector)
419 def copyList(outputListName, inputListName, writeOut=False, path=None):
421 Copy all Particle indices from input ParticleList to the output ParticleList.
422 Note that the Particles themselves are not copied. The original and copied
423 ParticleLists will point to the same Particles.
425 @param ouputListName copied ParticleList
426 @param inputListName original ParticleList to be copied
427 @param writeOut whether RootOutput module should save the created ParticleList
428 @param path modules are added to this path
431 copyLists(outputListName, [inputListName], writeOut, path)
434 def correctBremsBelle(outputListName,
437 multiplePhotons=True,
443 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
444 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
445 ``angleThreshold`` and above ``minimumEnergy``.
448 outputListName (str): The output charged particle list containing the corrected charged particles
449 inputListName (str): The initial charged particle list containing the charged particles to correct.
450 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
451 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one -> False,
452 add all the photons within the cone -> True
453 angleThreshold (float): The maximum angle in radians between the charged particle and the (radiative)
454 gamma to be accepted.
455 minimumEnergy (float): The minimum energy in GeV of the (radiative) gamma to be accepted.
456 writeOut (bool): whether RootOutput module should save the created ParticleList
457 path (basf2.Path): modules are added to this path
460 fsrcorrector = register_module(
'BelleBremRecovery')
461 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
462 fsrcorrector.param(
'inputListName', inputListName)
463 fsrcorrector.param(
'outputListName', outputListName)
464 fsrcorrector.param(
'gammaListName', gammaListName)
465 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
466 fsrcorrector.param(
'angleThreshold', angleThreshold)
467 fsrcorrector.param(
'minimumEnergy', minimumEnergy)
468 fsrcorrector.param(
'writeOut', writeOut)
469 path.add_module(fsrcorrector)
472 def copyLists(outputListName, inputListNames, writeOut=False, path=None):
474 Copy all Particle indices from all input ParticleLists to the
475 single output ParticleList.
476 Note that the Particles themselves are not copied.
477 The original and copied ParticleLists will point to the same Particles.
479 Duplicates are removed based on the first-come, first-served principle.
480 Therefore, the order of the input ParticleLists matters.
483 If you want to select the best duplicate based on another criterion, have
484 a look at the function `mergeListsWithBestDuplicate`.
487 Two particles that differ only by the order of their daughters are
488 considered duplicates and one of them will be removed.
490 @param ouputListName copied ParticleList
491 @param inputListName vector of original ParticleLists to be copied
492 @param writeOut whether RootOutput module should save the created ParticleList
493 @param path modules are added to this path
496 pmanipulate = register_module(
'ParticleListManipulator')
497 pmanipulate.set_name(
'PListCopy_' + outputListName)
498 pmanipulate.param(
'outputListName', outputListName)
499 pmanipulate.param(
'inputListNames', inputListNames)
500 pmanipulate.param(
'writeOut', writeOut)
501 path.add_module(pmanipulate)
504 def copyParticles(outputListName, inputListName, writeOut=False, path=None):
506 Create copies of Particles given in the input ParticleList and add them to the output ParticleList.
508 The existing relations of the original Particle (or it's (grand-)^n-daughters)
509 are copied as well. Note that only the relation is copied and that the related
510 object is not. Copied particles are therefore related to the *same* object as
513 @param ouputListName new ParticleList filled with copied Particles
514 @param inputListName input ParticleList with original Particles
515 @param writeOut whether RootOutput module should save the created ParticleList
516 @param path modules are added to this path
520 pmanipulate = register_module(
'ParticleListManipulator')
521 pmanipulate.set_name(
'PListCopy_' + outputListName)
522 pmanipulate.param(
'outputListName', outputListName)
523 pmanipulate.param(
'inputListNames', [inputListName])
524 pmanipulate.param(
'writeOut', writeOut)
525 path.add_module(pmanipulate)
528 pcopy = register_module(
'ParticleCopier')
529 pcopy.param(
'inputListNames', [outputListName])
530 path.add_module(pcopy)
533 def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
535 Copy candidates from all lists in ``inputListNames`` to
536 ``outputListName`` if they pass ``cut`` (given selection criteria).
539 Note that the Particles themselves are not copied.
540 The original and copied ParticleLists will point to the same Particles.
543 Require energetic pions safely inside the cdc
545 >>> cutAndCopyLists("pi+:energeticPions", ["pi+:good", "pi+:loose"], "[E > 2] and [0.3 < theta < 2.6]", path=mypath)
548 You must use square braces ``[`` and ``]`` for conditional statements.
551 outputListName (str): the new ParticleList name
552 inputListName (list(str)): list of input ParticleList names
553 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
554 writeOut (bool): whether RootOutput module should save the created ParticleList
555 path (basf2.Path): modules are added to this path
557 pmanipulate = register_module(
'ParticleListManipulator')
558 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
559 pmanipulate.param(
'outputListName', outputListName)
560 pmanipulate.param(
'inputListNames', inputListNames)
561 pmanipulate.param(
'cut', cut)
562 pmanipulate.param(
'writeOut', writeOut)
563 path.add_module(pmanipulate)
566 def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
568 Copy candidates from ``inputListName`` to ``outputListName`` if they pass
569 ``cut`` (given selection criteria).
572 Note the Particles themselves are not copied.
573 The original and copied ParticleLists will point to the same Particles.
576 require energetic pions safely inside the cdc
578 >>> cutAndCopyLists("pi+:energeticPions", "pi+:loose", "[E > 2] and [0.3 < theta < 2.6]", path=mypath)
581 You must use square braces ``[`` and ``]`` for conditional statements.
584 outputListName (str): the new ParticleList name
585 inputListName (str): input ParticleList name
586 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
587 writeOut (bool): whether RootOutput module should save the created ParticleList
588 path (basf2.Path): modules are added to this path
590 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
593 def trackingEfficiency(inputListNames, fraction, path=None):
595 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
596 Takes care of the duplicates, if any.
599 inputListNames (list(str)): input particle list names
600 fraction (float): fraction of particles to be removed randomly
601 path (basf2.Path): module is added to this path
604 trackingefficiency = register_module(
'TrackingEfficiency')
605 trackingefficiency.param(
'particleLists', inputListNames)
606 trackingefficiency.param(
'frac', fraction)
607 path.add_module(trackingefficiency)
610 def trackingMomentum(inputListNames, scale, path=None):
612 Scale momenta of the particles (based on charged tracks) according to the scaling factor scale.
615 inputListNames (list(str)): input particle list names
616 scale (float): scaling factor (1.0 -- no scaling)
617 path (basf2.Path): module is added to this path
620 trackingmomentum = register_module(
'TrackingMomentum')
621 trackingmomentum.param(
'particleLists', inputListNames)
622 trackingmomentum.param(
'scale', scale)
623 path.add_module(trackingmomentum)
626 def mergeListsWithBestDuplicate(outputListName,
633 Merge input ParticleLists into one output ParticleList. Only the best
634 among duplicates is kept. The lowest or highest value (configurable via
635 preferLowest) of the provided variable determines which duplicate is the
638 @param ouputListName name of merged ParticleList
639 @param inputListName vector of original ParticleLists to be merged
640 @param variable variable to determine best duplicate
641 @param preferLowest whether lowest or highest value of variable should be preferred
642 @param writeOut whether RootOutput module should save the created ParticleList
643 @param path modules are added to this path
646 pmanipulate = register_module(
'ParticleListManipulator')
647 pmanipulate.set_name(
'PListMerger_' + outputListName)
648 pmanipulate.param(
'outputListName', outputListName)
649 pmanipulate.param(
'inputListNames', inputListNames)
650 pmanipulate.param(
'variable', variable)
651 pmanipulate.param(
'preferLowest', preferLowest)
652 pmanipulate.param(
'writeOut', writeOut)
653 path.add_module(pmanipulate)
656 def fillSignalSideParticleList(outputListName, decayString, path):
658 This function should only be used in the ROE path, that is a path
659 that is executed for each ROE object in the DataStore.
661 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
663 Function will create a ParticleList with name 'gamma:sig' which will be filled
664 with the existing photon Particle, being the second daughter of the B0 candidate
665 to which the ROE object has to be related.
667 @param ouputListName name of the created ParticleList
668 @param decayString specify Particle to be added to the ParticleList
671 pload = register_module(
'SignalSideParticleListCreator')
672 pload.set_name(
'SSParticleList_' + outputListName)
673 pload.param(
'particleListName', outputListName)
674 pload.param(
'decayString', decayString)
675 path.add_module(pload)
678 def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False):
680 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
681 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
683 The multiple ParticleLists with their own selection criteria are specified
684 via list tuples (decayString, cut), for example
686 .. code-block:: python
688 kaons = ('K+:mykaons', 'kaonID>0.1')
689 pions = ('pi+:mypions','pionID>0.1')
690 fillParticleLists([kaons, pions])
692 If you are unsure what selection you want, you might like to see the
693 :doc:`StandardParticles` functions.
695 The type of the particles to be loaded is specified via the decayString module parameter.
696 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
697 the particle. The following types of the particles can be loaded:
699 * charged final state particles (input ``mdst`` type = Tracks)
700 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
702 * neutral final state particles
703 - "gamma" (input ``mdst`` type = ECLCluster)
704 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
705 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
708 For "K_S0" and "Lambda0" you must specify the daughter ordering.
710 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
712 .. code-block:: python
714 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
715 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
718 For "K_L0" it is now possible to load from ECLClusters, to revert to
719 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
721 .. code-block:: python
723 klongs = ('K_L0', 'isFromKLM > 0')
724 fillParticleLists([kaons, pions, klongs], path=mypath)
728 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
729 The decay string determines the type of Particle
730 and determines the of the ParticleList.
731 If the input MDST type is V0 the whole
732 decay chain needs to be specified, so that
733 the user decides and controls the daughters
734 ' order (e.g. ``K_S0 -> pi+ pi-``)
735 The cut is the selection criteria
736 to be added to the ParticleList. It can be an empty string.
737 writeOut (bool): whether RootOutput module should save the created ParticleList
738 path (basf2.Path): modules are added to this path
739 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
740 using a mass hypothesis of the exact type passed to fillParticleLists().
741 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
742 in terms of mass difference will be used if the fit using exact particle
743 type is not available.
746 pload = register_module(
'ParticleLoader')
747 pload.set_name(
'ParticleLoader_' +
'PLists')
748 pload.param(
'decayStringsWithCuts', decayStringsWithCuts)
749 pload.param(
'writeOut', writeOut)
750 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
751 path.add_module(pload)
754 def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False):
756 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
757 loads them to the StoreArray<Particle> and fills the ParticleList.
760 the :doc:`StandardParticles` functions.
762 The type of the particles to be loaded is specified via the decayString module parameter.
763 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
764 the particle. The following types of the particles can be loaded:
766 * charged final state particles (input ``mdst`` type = Tracks)
767 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
769 * neutral final state particles
770 - "gamma" (input ``mdst`` type = ECLCluster)
771 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
772 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
775 For "K_S0" and "Lambda0" you must specify the daughter ordering.
777 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0ss:
779 .. code-block:: python
781 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
784 For "K_L0" it is now possible to load from ECLClusters, to revert to
785 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
787 .. code-block:: python
789 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
792 decayString (str): Type of Particle and determines the name of the ParticleList.
793 If the input MDST type is V0 the whole decay chain needs to be specified, so that
794 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``)
795 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
796 writeOut (bool): whether RootOutput module should save the created ParticleList
797 path (basf2.Path): modules are added to this path
798 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
799 using a mass hypothesis of the exact type passed to fillParticleLists().
800 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
801 in terms of mass difference will be used if the fit using exact particle
802 type is not available.
805 pload = register_module(
'ParticleLoader')
806 pload.set_name(
'ParticleLoader_' + decayString)
807 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
808 pload.param(
'writeOut', writeOut)
809 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
810 path.add_module(pload)
813 def fillParticleListWithTrackHypothesis(decayString,
817 enforceFitHypothesis=False,
820 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
822 @param decayString specifies type of Particles and determines the name of the ParticleList
823 @param cut Particles need to pass these selection criteria to be added to the ParticleList
824 @param hypothesis the PDG code of the desired track hypothesis
825 @param writeOut whether RootOutput module should save the created ParticleList
826 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
827 using a mass hypothesis of the exact type passed to fillParticleLists().
828 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
829 in terms of mass difference will be used if the fit using exact particle
830 type is not available.
831 @param path modules are added to this path
834 pload = register_module(
'ParticleLoader')
835 pload.set_name(
'ParticleLoader_' + decayString)
836 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
837 pload.param(
'trackHypothesis', hypothesis)
838 pload.param(
'writeOut', writeOut)
839 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
840 path.add_module(pload)
843 def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
845 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
848 You must specify the daughter ordering.
850 .. code-block:: python
852 fillConvertedPhotonsList('gamma:converted -> e+ e-', '')
855 decayString (str): Must be gamma to an e+e- pair. You muse specify the daughter ordering.
856 Will also determine the name of the particleList.
857 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
858 writeOut (bool): whether RootOutput module should save the created ParticleList
859 path (basf2.Path): modules are added to this path
862 pload = register_module(
'ParticleLoader')
863 pload.set_name(
'ParticleLoader_' + decayString)
864 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
865 pload.param(
'addDaughters',
True)
866 pload.param(
'writeOut', writeOut)
867 path.add_module(pload)
870 def fillParticleListFromROE(decayString,
873 sourceParticleListName='',
878 Creates Particle object for each ROE of the desired type found in the
879 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
880 and fills the ParticleList. If useMissing is True, then the missing
881 momentum is used instead of ROE.
883 The type of the particles to be loaded is specified via the decayString module parameter.
885 @param decayString specifies type of Particles and determines the name of the ParticleList.
886 Source ROEs can be taken as a daughter list, for example:
887 'B0:tagFromROE -> B0:signal'
888 @param cut Particles need to pass these selection criteria to be added to the ParticleList
889 @param maskName Name of the ROE mask to use
890 @param sourceParticleListName Use related ROEs to this particle list as a source
891 @param useMissing Use missing momentum instead of ROE momentum
892 @param writeOut whether RootOutput module should save the created ParticleList
893 @param path modules are added to this path
896 pload = register_module(
'ParticleLoader')
897 pload.set_name(
'ParticleLoader_' + decayString)
898 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
899 pload.param(
'writeOut', writeOut)
900 pload.param(
'roeMaskName', maskName)
901 pload.param(
'useMissing', useMissing)
902 pload.param(
'sourceParticleListName', sourceParticleListName)
903 pload.param(
'useROEs',
True)
904 path.add_module(pload)
907 def fillParticleListFromMC(decayString,
910 skipNonPrimaryDaughters=False,
914 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
915 loads them to the StoreArray<Particle> and fills the ParticleList.
917 The type of the particles to be loaded is specified via the decayString module parameter.
919 @param decayString specifies type of Particles and determines the name of the ParticleList
920 @param cut Particles need to pass these selection criteria to be added to the ParticleList
921 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
922 sets mother-daughter relations
923 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
924 @param writeOut whether RootOutput module should save the created ParticleList
925 @param path modules are added to this path
928 pload = register_module(
'ParticleLoader')
929 pload.set_name(
'ParticleLoader_' + decayString)
930 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
931 pload.param(
'addDaughters', addDaughters)
932 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
933 pload.param(
'writeOut', writeOut)
934 pload.param(
'useMCParticles',
True)
935 path.add_module(pload)
938 def fillParticleListsFromMC(decayStringsWithCuts,
940 skipNonPrimaryDaughters=False,
944 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
945 loads them to the StoreArray<Particle> and fills the ParticleLists.
947 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
949 kaons = ('K+:gen', '')
950 pions = ('pi+:gen', 'pionID>0.1')
951 fillParticleListsFromMC([kaons, pions])
953 @param decayString specifies type of Particles and determines the name of the ParticleList
954 @param cut Particles need to pass these selection criteria to be added to the ParticleList
955 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
956 sets mother-daughter relations
957 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
958 @param writeOut whether RootOutput module should save the created ParticleList
959 @param path modules are added to this path
962 pload = register_module(
'ParticleLoader')
963 pload.set_name(
'ParticleLoader_' +
'PLists')
964 pload.param(
'decayStringsWithCuts', decayStringsWithCuts)
965 pload.param(
'addDaughters', addDaughters)
966 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
967 pload.param(
'writeOut', writeOut)
968 pload.param(
'useMCParticles',
True)
969 path.add_module(pload)
972 def applyCuts(list_name, cut, path):
974 Removes particle candidates from ``list_name`` that do not pass ``cut``
975 (given selection criteria).
978 require energetic pions safely inside the cdc
980 >>> applyCuts("pi+:mypions", "[E > 2] and [0.3 < theta < 2.6]", path=mypath)
983 You must use square braces ``[`` and ``]`` for conditional statements.
986 list_name (str): input ParticleList name
987 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
988 path (basf2.Path): modules are added to this path
991 pselect = register_module(
'ParticleSelector')
992 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
993 pselect.param(
'decayString', list_name)
994 pselect.param(
'cut', cut)
995 path.add_module(pselect)
998 def applyEventCuts(cut, path):
1000 Removes events that do not pass the ``cut`` (given selection criteria).
1003 continuum events (in mc only) with more than 5 tracks
1005 >>> applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1008 You must use square braces ``[`` and ``]`` for conditional statements.
1011 cut (str): Events that do not pass these selection criteria are skipped
1012 path (basf2.Path): modules are added to this path
1015 eselect = register_module(
'VariableToReturnValue')
1016 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1017 path.add_module(eselect)
1018 empty_path = create_path()
1019 eselect.if_value(
'<1', empty_path)
1022 def reconstructDecay(decayString,
1027 candidate_limit=None,
1028 ignoreIfTooManyCandidates=True,
1029 chargeConjugation=True,
1030 allowChargeViolation=False):
1032 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1033 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1034 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1035 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1036 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1038 One can use an ``@``-sign to mark a particle as unspecified, e.g. in form of a DecayString: :code:`\@Xsd -> K+ pi-`. If the
1039 particle is marked as unspecified, its identity will not be checked when doing :ref:`MCMatching`. Any particle which decays into
1040 the correct daughters will be flagged as correct. For example the DecayString :code:`\@Xsd -> K+ pi-` would match all particles
1041 which decay into a kaon and a pion, for example :math:`K^*`, :math:`B^0`, :math:`D^0`. Still the daughters need to be stated
1042 correctly so this can be used for "sum of exclusive" decays.
1045 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1046 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1047 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1049 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1050 This can be solved by manually randomising the lists before combining.
1054 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1055 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1057 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1058 (from the DecayString the mother and daughter ParticleLists are determined)
1059 @param cut created (mother) Particles are added to the mother ParticleList if they
1060 pass give cuts (in VariableManager style) and rejected otherwise
1061 @param dmID user specified decay mode identifier
1062 @param writeOut whether RootOutput module should save the created ParticleList
1063 @param path modules are added to this path
1064 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1065 the number of candidates is exceeded a Warning will be
1067 By default, all these candidates will be removed and event will be ignored.
1068 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1069 If no value is given the amount is limited to a sensible
1070 default. A value <=0 will disable this limit and can
1071 cause huge memory amounts so be careful.
1072 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1073 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1074 otherwise, number of candidates in candidate_limit is reconstructed.
1075 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1076 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1079 pmake = register_module(
'ParticleCombiner')
1080 pmake.set_name(
'ParticleCombiner_' + decayString)
1081 pmake.param(
'decayString', decayString)
1082 pmake.param(
'cut', cut)
1083 pmake.param(
'decayMode', dmID)
1084 pmake.param(
'writeOut', writeOut)
1085 if candidate_limit
is not None:
1086 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1087 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1088 pmake.param(
'chargeConjugation', chargeConjugation)
1089 pmake.param(
"allowChargeViolation", allowChargeViolation)
1090 path.add_module(pmake)
1093 def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1095 Creates a new Particle as the combination of all Particles from all
1096 provided inputParticleLists. However, each particle is used only once
1097 (even if duplicates are provided) and the combination has to pass the
1098 specified selection criteria to be saved in the newly created (mother)
1101 @param inputParticleLists List of input particle lists which are combined to the new Particle
1102 @param outputList Name of the particle combination created with this module
1103 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1104 these given cuts (in VariableManager style) and is rejected otherwise
1105 @param writeOut whether RootOutput module should save the created ParticleList
1106 @param path module is added to this path
1109 pmake = register_module(
'AllParticleCombiner')
1110 pmake.set_name(
'AllParticleCombiner_' + outputList)
1111 pmake.param(
'inputListNames', inputParticleLists)
1112 pmake.param(
'outputListName', outputList)
1113 pmake.param(
'cut', cut)
1114 pmake.param(
'writeOut', writeOut)
1115 path.add_module(pmake)
1118 def reconstructMissingKlongDecayExpert(decayString,
1125 Creates a list of K_L0's with their momentum determined from kinematic constraints of B->K_L0 + something else.
1127 @param decayString DecayString specifying what kind of the decay should be reconstructed
1128 (from the DecayString the mother and daughter ParticleLists are determined)
1129 @param cut Particles are added to the K_L0 ParticleList if they
1130 pass the given cuts (in VariableManager style) and rejected otherwise
1131 @param dmID user specified decay mode identifier
1132 @param writeOut whether RootOutput module should save the created ParticleList
1133 @param path modules are added to this path
1134 @param recoList suffix appended to original K_L0 ParticleList that identifies the newly created K_L0 list
1137 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1138 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1139 pcalc.param(
'decayString', decayString)
1140 pcalc.param(
'cut', cut)
1141 pcalc.param(
'decayMode', dmID)
1142 pcalc.param(
'writeOut', writeOut)
1143 pcalc.param(
'recoList', recoList)
1144 path.add_module(pcalc)
1146 rmake = register_module(
'KlongDecayReconstructorExpert')
1147 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1148 rmake.param(
'decayString', decayString)
1149 rmake.param(
'cut', cut)
1150 rmake.param(
'decayMode', dmID)
1151 rmake.param(
'writeOut', writeOut)
1152 rmake.param(
'recoList', recoList)
1153 path.add_module(rmake)
1156 def replaceMass(replacerName, particleLists=[], pdgCode=22, path=None):
1158 replaces the mass of the particles inside the given particleLists
1159 with the invariant mass of the particle corresponding to the given pdgCode.
1161 @param particleLists new ParticleList filled with copied Particles
1162 @param pdgCode PDG code for mass reference
1163 @param path modules are added to this path
1167 pmassupdater = register_module(
'ParticleMassUpdater')
1168 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1169 pmassupdater.param(
'particleLists', particleLists)
1170 pmassupdater.param(
'pdgCode', pdgCode)
1171 path.add_module(pmassupdater)
1174 def reconstructRecoil(decayString,
1179 candidate_limit=None,
1180 allowChargeViolation=False):
1182 Creates new Particles that recoil against the input particles.
1184 For example the decay string M -> D1 D2 D3 will:
1185 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1186 - Particles D1, D2, D3 will be appended as daughters to M
1187 - the 4-momentum of the mother Particle M is given by
1188 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1190 @param decayString DecayString specifying what kind of the decay should be reconstructed
1191 (from the DecayString the mother and daughter ParticleLists are determined)
1192 @param cut created (mother) Particles are added to the mother ParticleList if they
1193 pass give cuts (in VariableManager style) and rejected otherwise
1194 @param dmID user specified decay mode identifier
1195 @param writeOut whether RootOutput module should save the created ParticleList
1196 @param path modules are added to this path
1197 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1198 the number of candidates is exceeded no candidate will be
1199 reconstructed for that event and a Warning will be
1201 If no value is given the amount is limited to a sensible
1202 default. A value <=0 will disable this limit and can
1203 cause huge memory amounts so be careful.
1204 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1207 pmake = register_module(
'ParticleCombiner')
1208 pmake.set_name(
'ParticleCombiner_' + decayString)
1209 pmake.param(
'decayString', decayString)
1210 pmake.param(
'cut', cut)
1211 pmake.param(
'decayMode', dmID)
1212 pmake.param(
'writeOut', writeOut)
1213 pmake.param(
'recoilParticleType', 1)
1214 if candidate_limit
is not None:
1215 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1216 pmake.param(
'allowChargeViolation', allowChargeViolation)
1217 path.add_module(pmake)
1220 def reconstructRecoilDaughter(decayString,
1225 candidate_limit=None,
1226 allowChargeViolation=False):
1228 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1230 For example the decay string M -> D1 D2 D3 will:
1231 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1232 - Particles D1, D2, D3 will be appended as daughters to M
1233 - the 4-momentum of the mother Particle M is given by
1234 p(M) = p(D1) - Sum_i p(Di), where i>1
1236 @param decayString DecayString specifying what kind of the decay should be reconstructed
1237 (from the DecayString the mother and daughter ParticleLists are determined)
1238 @param cut created (mother) Particles are added to the mother ParticleList if they
1239 pass give cuts (in VariableManager style) and rejected otherwise
1240 @param dmID user specified decay mode identifier
1241 @param writeOut whether RootOutput module should save the created ParticleList
1242 @param path modules are added to this path
1243 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1244 the number of candidates is exceeded no candidate will be
1245 reconstructed for that event and a Warning will be
1247 If no value is given the amount is limited to a sensible
1248 default. A value <=0 will disable this limit and can
1249 cause huge memory amounts so be careful.
1250 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1251 daughter is actually the mother
1254 pmake = register_module(
'ParticleCombiner')
1255 pmake.set_name(
'ParticleCombiner_' + decayString)
1256 pmake.param(
'decayString', decayString)
1257 pmake.param(
'cut', cut)
1258 pmake.param(
'decayMode', dmID)
1259 pmake.param(
'writeOut', writeOut)
1260 pmake.param(
'recoilParticleType', 2)
1261 if candidate_limit
is not None:
1262 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1263 pmake.param(
'allowChargeViolation', allowChargeViolation)
1264 path.add_module(pmake)
1267 def rankByHighest(particleList,
1271 allowMultiRank=False,
1275 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1276 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1277 The list is also sorted from best to worst candidate
1278 (each charge, e.g. B+/B-, separately).
1279 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1280 a non-zero value for 'numBest'.
1283 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1284 These variable names can become clunky, so it's probably a good idea to set an alias.
1285 For example if you rank your B candidates by momentum,
1289 rankByHighest("B0:myCandidates", "p", path=mypath)
1290 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1293 @param particleList The input ParticleList
1294 @param variable Variable to order Particles by.
1295 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1296 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1297 @param allowMultiRank If true, candidates with the same value will get the same rank.
1298 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1299 @param path modules are added to this path
1302 bcs = register_module(
'BestCandidateSelection')
1303 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1304 bcs.param(
'particleList', particleList)
1305 bcs.param(
'variable', variable)
1306 bcs.param(
'numBest', numBest)
1307 bcs.param(
'outputVariable', outputVariable)
1308 bcs.param(
'allowMultiRank', allowMultiRank)
1309 bcs.param(
'cut', cut)
1310 path.add_module(bcs)
1313 def rankByLowest(particleList,
1317 allowMultiRank=False,
1321 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1322 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1323 The list is also sorted from best to worst candidate
1324 (each charge, e.g. B+/B-, separately).
1325 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1326 a non-zero value for 'numBest'.
1329 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1330 These variable names can become clunky, so it's probably a good idea to set an alias.
1331 For example if you rank your B candidates by :b2:var:`dM`,
1335 rankByLowest("B0:myCandidates", "dM", path=mypath)
1336 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1339 @param particleList The input ParticleList
1340 @param variable Variable to order Particles by.
1341 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1342 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1343 @param allowMultiRank If true, candidates with the same value will get the same rank.
1344 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1345 @param path modules are added to this path
1348 bcs = register_module(
'BestCandidateSelection')
1349 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1350 bcs.param(
'particleList', particleList)
1351 bcs.param(
'variable', variable)
1352 bcs.param(
'numBest', numBest)
1353 bcs.param(
'selectLowest',
True)
1354 bcs.param(
'allowMultiRank', allowMultiRank)
1355 bcs.param(
'outputVariable', outputVariable)
1356 bcs.param(
'cut', cut)
1357 path.add_module(bcs)
1360 def applyRandomCandidateSelection(particleList, path=None):
1362 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1363 This is done on a event-by-event basis.
1365 @param particleList ParticleList for which the random candidate selection should be applied
1366 @param path module is added to this path
1369 rcs = register_module(
'BestCandidateSelection')
1370 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1371 rcs.param(
'particleList', particleList)
1372 rcs.param(
'variable',
'random')
1373 rcs.param(
'selectLowest',
False)
1374 rcs.param(
'allowMultiRank',
False)
1375 rcs.param(
'numBest', 1)
1376 rcs.param(
'cut',
'')
1377 rcs.param(
'outputVariable',
'')
1378 path.add_module(rcs)
1383 Prints the contents of DataStore in the first event (or a specific event number or all events).
1384 Will list all objects and arrays (including size).
1387 The command line tool: ``b2file-size``.
1390 eventNumber (int): Print the datastore only for this event. The default
1391 (-1) prints only the first event, 0 means print for all events (can produce large output)
1392 path (basf2.Path): the PrintCollections module is added to this path
1395 This will print a lot of output if you print it for all events and process many events.
1399 printDS = register_module(
'PrintCollections')
1400 printDS.param(
'printForEvent', eventNumber)
1401 path.add_module(printDS)
1404 def printVariableValues(list_name, var_names, path):
1406 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
1408 @param list_name input ParticleList name
1409 @param var_names vector of variable names to be printed
1410 @param path modules are added to this path
1413 prlist = register_module(
'ParticlePrinter')
1414 prlist.set_name(
'ParticlePrinter_' + list_name)
1415 prlist.param(
'listName', list_name)
1416 prlist.param(
'fullPrint',
False)
1417 prlist.param(
'variables', var_names)
1418 path.add_module(prlist)
1421 def printList(list_name, full, path):
1423 Prints the size and executes Particle->print() (if full=True)
1424 method for all Particles in given ParticleList. For debugging purposes.
1426 @param list_name input ParticleList name
1427 @param full execute Particle->print() method for all Particles
1428 @param path modules are added to this path
1431 prlist = register_module(
'ParticlePrinter')
1432 prlist.set_name(
'ParticlePrinter_' + list_name)
1433 prlist.param(
'listName', list_name)
1434 prlist.param(
'fullPrint', full)
1435 path.add_module(prlist)
1438 def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None):
1440 Creates and fills a flat ntuple with the specified variables from the VariableManager.
1441 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
1442 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
1445 decayString (str): specifies type of Particles and determines the name of the ParticleList
1446 variables (list(str)): the list of variables (which must be registered in the VariableManager)
1447 treename (str): name of the ntuple tree
1448 filename (str): which is used to store the variables
1449 path (basf2.Path): the basf2 path where the analysis is processed
1452 output = register_module(
'VariablesToNtuple')
1453 output.set_name(
'VariablesToNtuple_' + decayString)
1454 output.param(
'particleList', decayString)
1455 output.param(
'variables', variables)
1456 output.param(
'fileName', filename)
1457 output.param(
'treeName', treename)
1458 path.add_module(output)
1464 filename='ntuple.root',
1467 prefixDecayString=False):
1469 Creates and fills a flat ntuple with the specified variables from the VariableManager
1472 decayString (str): specifies type of Particles and determines the name of the ParticleList
1473 variables (list(tuple))): variables + binning which must be registered in the VariableManager
1474 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
1475 filename (str): which is used to store the variables
1476 path (basf2.Path): the basf2 path where the analysis is processed
1477 directory (str): directory inside the output file where the histograms should be saved.
1478 Useful if you want to have different histograms in the same file to separate them.
1479 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
1480 programmatic naming of the structure in the file.
1483 output = register_module(
'VariablesToHistogram')
1484 output.set_name(
'VariablesToHistogram_' + decayString)
1485 output.param(
'particleList', decayString)
1486 output.param(
'variables', variables)
1487 output.param(
'variables_2d', variables_2d)
1488 output.param(
'fileName', filename)
1489 if directory
is not None or prefixDecayString:
1490 if directory
is None:
1492 if prefixDecayString:
1493 directory = decayString +
"_" + directory
1494 output.param(
"directory", directory)
1495 path.add_module(output)
1500 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
1501 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
1503 An existing extra info with the same name will be overwritten if the new
1504 value is lower / will never be overwritten / will be overwritten if the
1505 new value is higher / will always be overwritten (-1/0/1/2).
1507 @param particleList The input ParticleList
1508 @param variables Dictionary of Variables and extraInfo names.
1509 @param path modules are added to this path
1512 mod = register_module(
'VariablesToExtraInfo')
1513 mod.set_name(
'VariablesToExtraInfo_' + particleList)
1514 mod.param(
'particleList', particleList)
1515 mod.param(
'variables', variables)
1516 mod.param(
'overwrite', option)
1517 path.add_module(mod)
1520 def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
1522 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
1523 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
1524 to specified daughter particle.
1526 An existing extra info with the same name will be overwritten if the new
1527 value is lower / will never be overwritten / will be overwritten if the
1528 new value is higher / will always be overwritten (-1/0/1/2).
1530 @param particleList The input ParticleList
1531 @param decayString Decay string that specifies to which daughter the extra info should be appended
1532 @param variables Dictionary of Variables and extraInfo names.
1533 @param option Various options for overwriting
1534 @param path modules are added to this path
1537 mod = register_module(
'VariablesToExtraInfo')
1538 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
1539 mod.param(
'particleList', particleList)
1540 mod.param(
'decayString', decayString)
1541 mod.param(
'variables', variables)
1542 mod.param(
'overwrite', option)
1543 path.add_module(mod)
1546 def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
1548 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
1549 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
1551 An existing extra info with the same name will be overwritten if the new
1552 value is lower / will never be overwritten / will be overwritten if the
1553 new value is higher / will always be overwritten (-1/0/1/2).
1555 @param particleList The input ParticleList
1556 @param variables Dictionary of Variables and extraInfo names.
1557 @param path modules are added to this path
1560 mod = register_module(
'VariablesToEventExtraInfo')
1561 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
1562 mod.param(
'particleList', particleList)
1563 mod.param(
'variables', variables)
1564 mod.param(
'overwrite', option)
1565 path.add_module(mod)
1568 def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
1570 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
1571 particle) as an extra info to the particle related to current ROE.
1572 Should be used only in the for_each roe path.
1574 @param particleList The input ParticleList
1575 @param varToExtraInfo Dictionary of Variables and extraInfo names.
1576 @param path modules are added to this path
1578 mod = register_module(
'SignalSideVariablesToExtraInfo')
1579 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
1580 mod.param(
'particleListName', particleList)
1581 mod.param(
'variableToExtraInfo', varToExtraInfo)
1582 path.add_module(mod)
1585 def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
1587 Define and blind a signal region.
1588 Per default, the defined signal region is cut out if ran on data.
1589 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
1593 >>> ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
1594 >>> ma.signalRegion("B+:sig",
1595 >>> "Mbc>5.27 and abs(deltaE)<0.2",
1596 >>> blind_data=True,
1598 >>> ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
1601 particleList (str): The input ParticleList
1602 cut (str): Cut string describing the signal region
1603 path (basf2.Path):: Modules are added to this path
1604 name (str): Name of the Signal region in the variable manager
1605 blind_data (bool): Automatically exclude signal region from data
1609 from variables
import variables
1610 mod = register_module(
'VariablesToExtraInfo')
1611 mod.set_name(f
'{name}_' + particleList)
1612 mod.param(
'particleList', particleList)
1613 mod.param(
'variables', {f
"passesCut({cut})": name})
1614 variables.addAlias(name, f
"extraInfo({name})")
1615 path.add_module(mod)
1619 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
1622 def removeExtraInfo(particleLists=[], removeEventExtraInfo=False, path=None):
1624 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
1627 mod = register_module(
'ExtraInfoRemover')
1628 mod.param(
'particleLists', particleLists)
1629 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
1630 path.add_module(mod)
1633 def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
1635 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
1636 to the particle from the input ParticleList. Additional selection criteria can be applied.
1637 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
1638 meet the selection criteria the execution of deadEndPath is started. This path, as the name
1639 suggests should be empty and its purpose is to end the execution of for_each roe path for
1640 the current ROE object.
1642 @param particleList The input ParticleList
1643 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
1644 @param for_each roe path in which this filter is executed
1645 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
1647 mod = register_module(
'SignalSideParticleFilter')
1648 mod.set_name(
'SigSideParticleFilter_' + particleList)
1649 mod.param(
'particleLists', [particleList])
1650 mod.param(
'selection', selection)
1651 roe_path.add_module(mod)
1652 mod.if_false(deadEndPath)
1655 def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
1657 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
1658 to the particle from the input ParticleList. Additional selection criteria can be applied.
1659 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
1660 meet the selection criteria the execution of deadEndPath is started. This path, as the name
1661 suggests should be empty and its purpose is to end the execution of for_each roe path for
1662 the current ROE object.
1664 @param particleLists The input ParticleLists
1665 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
1666 @param for_each roe path in which this filter is executed
1667 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
1669 mod = register_module(
'SignalSideParticleFilter')
1670 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
1671 mod.param(
'particleLists', particleLists)
1672 mod.param(
'selection', selection)
1673 roe_path.add_module(mod)
1674 mod.if_false(deadEndPath)
1683 chargeConjugation=True,
1686 Finds and creates a ``ParticleList`` from given decay string.
1687 ``ParticleList`` of daughters with sub-decay is created.
1689 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
1690 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
1693 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
1694 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
1695 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
1698 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1699 (from the DecayString the mother and daughter ParticleLists are determined)
1700 @param cut created (mother) Particles are added to the mother ParticleList if they
1701 pass given cuts (in VariableManager style) and rejected otherwise
1702 isSignal==1 is always required by default.
1703 @param dmID user specified decay mode identifier
1704 @param writeOut whether RootOutput module should save the created ParticleList
1705 @param path modules are added to this path
1706 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1709 pmake = register_module(
'ParticleCombinerFromMC')
1710 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
1711 pmake.param(
'decayString', decayString)
1712 pmake.param(
'cut', cut)
1713 pmake.param(
'decayMode', dmID)
1714 pmake.param(
'writeOut', writeOut)
1715 pmake.param(
'chargeConjugation', chargeConjugation)
1716 path.add_module(pmake)
1727 This function is not fully tested and maintained.
1728 Please consider to use reconstructMCDecay() instead.
1730 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
1731 The decay string is required to describe correctly what you want.
1732 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
1734 @param list_name The output particle list name
1735 @param decay The decay string which you want
1736 @param writeOut Whether `RootOutput` module should save the created ``outputList``
1737 @param path modules are added to this path
1739 B2WARNING(
"This function is not fully tested and maintained."
1740 "Please consider to use reconstructMCDecay() instead.")
1742 decayfinder = register_module(
'MCDecayFinder')
1743 decayfinder.set_name(
'MCDecayFinder_' + list_name)
1744 decayfinder.param(
'listName', list_name)
1745 decayfinder.param(
'decayString', decay)
1746 decayfinder.param(
'writeOut', writeOut)
1747 path.add_module(decayfinder)
1750 def summaryOfLists(particleLists, path):
1752 Prints out Particle statistics at the end of the job: number of events with at
1753 least one candidate, average number of candidates per event, etc.
1755 @param particleLists list of input ParticleLists
1758 particleStats = register_module(
'ParticleStats')
1759 particleStats.param(
'particleLists', particleLists)
1760 path.add_module(particleStats)
1763 def matchMCTruth(list_name, path):
1765 Performs MC matching (sets relation Particle->MCParticle) for
1766 all particles (and its (grand)^N-daughter particles) in the specified
1769 @param list_name name of the input ParticleList
1770 @param path modules are added to this path
1773 mcMatch = register_module(
'MCMatcherParticles')
1774 mcMatch.set_name(
'MCMatch_' + list_name)
1775 mcMatch.param(
'listName', list_name)
1776 path.add_module(mcMatch)
1779 def looseMCTruth(list_name, path):
1781 Performs loose MC matching for all particles in the specified
1783 The difference between loose and normal mc matching algorithm is that
1784 the loose algorithm will find the common mother of the majority of daughter
1785 particles while the normal algorithm finds the common mother of all daughters.
1786 The results of loose mc matching algorithm are stored to the following extraInfo
1789 - looseMCMotherPDG: PDG code of most common mother
1790 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
1791 - looseMCWrongDaughterN: number of daughters that don't originate from the most
1793 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from
1794 the most common mother
1795 (only if looseMCWrongDaughterN = 1)
1796 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background
1799 @param list_name name of the input ParticleList
1800 @param path modules are added to this path
1803 mcMatch = register_module(
'MCMatcherParticles')
1804 mcMatch.set_name(
'LooseMCMatch_' + list_name)
1805 mcMatch.param(
'listName', list_name)
1806 mcMatch.param(
'looseMCMatching',
True)
1807 path.add_module(mcMatch)
1810 def buildRestOfEvent(target_list_name, inputParticlelists=None,
1811 fillWithMostLikely=False,
1812 chargedPIDPriors=None, path=None):
1814 Creates for each Particle in the given ParticleList a RestOfEvent
1815 dataobject and makes BASF2 relation between them. User can provide additional
1816 particle lists with a different particle hypotheses like ['K+:good, e+:good'], etc.
1818 @param target_list_name name of the input ParticleList
1819 @param inputParticlelists list of input particle list names, which serve
1820 as a source of particles to build ROE, the FSP particles from
1821 target_list_name are excluded from ROE object
1822 @param fillWithMostLikely if True, the module uses particle mass hypothesis for charged particles
1823 according to PID likelihood and the inputParticlelists
1824 option will be ignored.
1825 @param chargedPIDPriors The prior PID fractions, that are used to regulate
1826 amount of certain charged particle species, should be a list of
1827 six floats if not None. The order of particle types is
1828 the following: [e-, mu-, pi-, K-, p+, d+]
1829 @param path modules are added to this path
1831 if inputParticlelists
is None:
1832 inputParticlelists = []
1833 fillParticleList(
'pi+:roe_default',
'', path=path)
1834 if fillWithMostLikely:
1835 from stdCharged
import stdMostLikely
1836 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
1837 inputParticlelists = [
'%s:mostlikely_roe' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
1840 fillParticleList(
'gamma:roe_default',
'', path=path)
1841 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
1842 inputParticlelists += [
'pi+:roe_default',
'gamma:roe_default',
'K_L0:roe_default']
1844 inputParticlelists += [
'pi+:roe_default',
'gamma:mdst']
1845 roeBuilder = register_module(
'RestOfEventBuilder')
1846 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
1847 roeBuilder.param(
'particleList', target_list_name)
1848 roeBuilder.param(
'particleListsInput', inputParticlelists)
1849 path.add_module(roeBuilder)
1852 def buildNestedRestOfEvent(target_list_name, maskName='', path=None):
1854 Creates for each Particle in the given ParticleList a RestOfEvent
1855 @param target_list_name name of the input ParticleList
1856 @param mask_name name of the ROEMask to be used
1857 @param path modules are added to this path
1859 roeBuilder = register_module(
'RestOfEventBuilder')
1860 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
1861 roeBuilder.param(
'particleList', target_list_name)
1862 roeBuilder.param(
'nestedROEMask', maskName)
1863 roeBuilder.param(
'createNestedROE',
True)
1864 path.add_module(roeBuilder)
1867 def buildRestOfEventFromMC(target_list_name, inputParticlelists=[], path=None):
1869 Creates for each Particle in the given ParticleList a RestOfEvent
1870 @param target_list_name name of the input ParticleList
1871 @param inputParticlelists list of input particle list names, which serve
1872 as a source of particles to build ROE, the FSP particles from
1873 target_list_name are excluded from ROE object
1874 @param path modules are added to this path
1876 if (len(inputParticlelists) == 0):
1880 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
1881 'n0',
'nu_e',
'nu_mu',
'nu_tau',
1884 fillParticleListFromMC(
"%s:roe_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
1885 True,
True, path=path)
1886 inputParticlelists += [
"%s:roe_default_gen" % t]
1887 roeBuilder = register_module(
'RestOfEventBuilder')
1888 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
1889 roeBuilder.param(
'particleList', target_list_name)
1890 roeBuilder.param(
'particleListsInput', inputParticlelists)
1891 roeBuilder.param(
'fromMC',
True)
1892 path.add_module(roeBuilder)
1895 def appendROEMask(list_name,
1898 eclClusterSelection,
1901 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
1902 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
1904 - append a ROE mask with all tracks in ROE coming from the IP region
1906 >>> appendROEMask('B+:sig', 'IPtracks', 'abs(d0) < 0.05 and abs(z0) < 0.1', '')
1908 - append a ROE mask with only ECLClusters that pass as good photon candidates
1910 >>> good_photons = 'theta > 0.296706 and theta < 2.61799 and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
1911 >>> appendROEMask('B+:sig', 'goodROEGamma', '', good_photons)
1914 @param list_name name of the input ParticleList
1915 @param mask_name name of the appended ROEMask
1916 @param trackSelection decay string for the tracks in ROE
1917 @param eclClusterSelection decay string for the tracks in ROE
1918 @param path modules are added to this path
1921 roeMask = register_module(
'RestOfEventInterpreter')
1922 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
1923 roeMask.param(
'particleList', list_name)
1924 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection)])
1925 path.add_module(roeMask)
1928 def appendROEMasks(list_name, mask_tuples, path=None):
1930 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
1931 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
1933 The multiple ROE masks with their own selection criteria are specified
1934 via list of tuples (mask_name, trackSelection, eclClusterSelection) or
1935 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
1937 - Example for two tuples, one with and one without fractions
1939 >>> ipTracks = ('IPtracks', 'abs(d0) < 0.05 and abs(z0) < 0.1', '')
1940 >>> good_photons = 'theta > 0.296706 and theta < 2.61799 and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
1941 >>> goodROEGamma = ('ROESel', 'abs(d0) < 0.05 and abs(z0) < 0.1', good_photons)
1942 >>> appendROEMasks('B+:sig', [ipTracks, goodROEGamma])
1944 @param list_name name of the input ParticleList
1945 @param mask_tuples array of ROEMask list tuples to be appended
1946 @param path modules are added to this path
1949 roeMask = register_module(
'RestOfEventInterpreter')
1950 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
1951 roeMask.param(
'particleList', list_name)
1952 roeMask.param(
'ROEMasks', mask_tuples)
1953 path.add_module(roeMask)
1956 def updateROEMask(list_name,
1959 eclClusterSelection='',
1962 Update an existing ROE mask by applying additional selection cuts for
1963 tracks and/or clusters.
1965 See function `appendROEMask`!
1967 @param list_name name of the input ParticleList
1968 @param mask_name name of the ROEMask to update
1969 @param trackSelection decay string for the tracks in ROE
1970 @param eclClusterSelection decay string for the tracks in ROE
1971 @param path modules are added to this path
1974 roeMask = register_module(
'RestOfEventInterpreter')
1975 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
1976 roeMask.param(
'particleList', list_name)
1977 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection)])
1978 roeMask.param(
'update',
True)
1979 path.add_module(roeMask)
1982 def updateROEMasks(list_name, mask_tuples, path):
1984 Update existing ROE masks by applying additional selection cuts for tracks
1987 The multiple ROE masks with their own selection criteria are specified
1988 via list tuples (mask_name, trackSelection, eclClusterSelection)
1990 See function `appendROEMasks`!
1992 @param list_name name of the input ParticleList
1993 @param mask_tuples array of ROEMask list tuples to be appended
1994 @param path modules are added to this path
1997 roeMask = register_module(
'RestOfEventInterpreter')
1998 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
1999 roeMask.param(
'particleList', list_name)
2000 roeMask.param(
'ROEMasks', mask_tuples)
2001 roeMask.param(
'update',
True)
2002 path.add_module(roeMask)
2005 def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2007 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2008 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2009 This function should be executed only in the for_each roe path for the current ROE object.
2011 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2012 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2013 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2014 pion particle list (e.g. 'pi+:someLabel').
2016 Updating a non-existing mask will create a new one.
2018 - keep only those tracks that were used in provided particle list
2020 >>> keepInROEMasks('pi+:goodTracks', 'mask', '')
2022 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2024 >>> keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1')
2027 @param list_name name of the input ParticleList
2028 @param mask_names array of ROEMasks to be updated
2029 @param cut_string decay string with which the mask will be updated
2030 @param path modules are added to this path
2033 updateMask = register_module(
'RestOfEventUpdater')
2034 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2035 updateMask.param(
'particleList', list_name)
2036 updateMask.param(
'updateMasks', mask_names)
2037 updateMask.param(
'cutString', cut_string)
2038 updateMask.param(
'discard',
False)
2039 path.add_module(updateMask)
2042 def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2044 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2045 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2046 This function should be executed only in the for_each roe path for the current ROE object.
2048 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2049 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2050 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2051 pion particle list (e.g. 'pi+:someLabel').
2053 Updating a non-existing mask will create a new one.
2055 - discard tracks that were used in provided particle list
2057 >>> discardFromROEMasks('pi+:badTracks', 'mask', '')
2059 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2061 >>> discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1')
2064 @param list_name name of the input ParticleList
2065 @param mask_names array of ROEMasks to be updated
2066 @param cut_string decay string with which the mask will be updated
2067 @param path modules are added to this path
2070 updateMask = register_module(
'RestOfEventUpdater')
2071 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2072 updateMask.param(
'particleList', list_name)
2073 updateMask.param(
'updateMasks', mask_names)
2074 updateMask.param(
'cutString', cut_string)
2075 updateMask.param(
'discard',
True)
2076 path.add_module(updateMask)
2079 def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2081 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2082 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2083 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2084 passing it can be applied.
2086 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2087 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2089 Updating a non-existing mask will create a new one.
2091 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2093 >>> optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550')
2095 @param list_name name of the input ParticleList
2096 @param mask_names array of ROEMasks to be updated
2097 @param cut_string decay string with which the mask will be updated
2098 @param path modules are added to this path
2101 updateMask = register_module(
'RestOfEventUpdater')
2102 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2103 updateMask.param(
'particleList', list_name)
2104 updateMask.param(
'updateMasks', mask_names)
2105 updateMask.param(
'cutString', cut_string)
2106 path.add_module(updateMask)
2109 def printROEInfo(mask_names=[], which_mask='both', full_print=False, path=None):
2111 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2112 It prints out basic ROE object info.
2114 If mask names are provided, specific information for those masks will be printed out. By default, basic
2115 ECLCluster and Track mask info will be printed out, but it is possible to do this only for one, if needed.
2117 It is also possible to print out the specific mask values for each Track and ECLCluster by setting the 'full_print'
2120 @param mask_names array of ROEMask names for printing out info
2121 @param which_mask print out info for Tracks ('track'), ECLClusters ('cluster') or ('both')
2122 @param full_print print out mask values for each Track/ECLCLuster in mask
2123 @param path modules are added to this path
2125 if not isinstance(path, Path):
2126 B2FATAL(
"Error from printROEInfo, please add this to the for_each path")
2128 printMask = register_module(
'RestOfEventPrinter')
2129 printMask.set_name(
'RestOfEventPrinter')
2130 printMask.param(
'maskNames', mask_names)
2131 printMask.param(
'whichMask', which_mask)
2132 printMask.param(
'fullPrint', full_print)
2133 path.add_module(printMask)
2136 def buildContinuumSuppression(list_name, roe_mask, path):
2138 Creates for each Particle in the given ParticleList a ContinuumSuppression
2139 dataobject and makes BASF2 relation between them.
2141 @param list_name name of the input ParticleList
2142 @param path modules are added to this path
2145 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2146 qqBuilder.set_name(
'QQBuilder_' + list_name)
2147 qqBuilder.param(
'particleList', list_name)
2148 qqBuilder.param(
'ROEMask', roe_mask)
2149 path.add_module(qqBuilder)
2154 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2155 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2157 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2158 @param path modules are added to this path
2161 mod = register_module(
'RemoveParticlesNotInLists')
2162 mod.param(
'particleLists', lists_to_keep)
2163 path.add_module(mod)
2166 def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2168 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2170 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2171 @param bsig_list_name Name of the Bsig ParticleList
2172 @param btag_list_name Name of the Bsig ParticleList
2173 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2175 btag = register_module(
'InclusiveBtagReconstruction')
2176 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2177 btag.param(
'upsilonListName', upsilon_list_name)
2178 btag.param(
'bsigListName', bsig_list_name)
2179 btag.param(
'btagListName', btag_list_name)
2180 btag.param(
'inputListsNames', input_lists_names)
2181 path.add_module(btag)
2184 def selectDaughters(particle_list_name, decay_string, path):
2186 Redefine the Daughters of a particle: select from decayString
2188 @param particle_list_name input particle list
2189 @param decay_string for selecting the Daughters to be preserved
2191 seld = register_module(
'SelectDaughters')
2192 seld.set_name(
'SelectDaughters_' + particle_list_name)
2193 seld.param(
'listName', particle_list_name)
2194 seld.param(
'decayString', decay_string)
2195 path.add_module(seld)
2198 def markDuplicate(particleList, prioritiseV0, path):
2200 Call DuplicateVertexMarker to find duplicate particles in a list and
2201 flag the ones that should be kept
2203 @param particleList input particle list
2204 @param prioritiseV0 if true, give V0s a higher priority
2206 markdup = register_module(
'DuplicateVertexMarker')
2207 markdup.param(
'particleList', particleList)
2208 markdup.param(
'prioritiseV0', prioritiseV0)
2209 path.add_module(markdup)
2212 PI0ETAVETO_COUNTER = 0
2215 def oldwritePi0EtaVeto(
2218 workingDirectory='.',
2219 pi0vetoname='Pi0_Prob',
2220 etavetoname='Eta_Prob',
2226 Give pi0/eta probability for hard photon.
2228 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.
2230 The current default weight files are optimised using MC9.
2231 The input variables are as below. Aliases are set to some variables during training.
2233 * M: pi0/eta candidates Invariant mass
2234 * lowE: soft photon energy in lab frame
2235 * cTheta: soft photon ECL cluster's polar angle
2236 * Zmva: soft photon output of MVA using Zernike moments of the cluster
2237 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2239 If you don't have weight files in your workingDirectory,
2240 these files are downloaded from database to your workingDirectory automatically.
2241 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
2242 about how to use this function.
2245 Please don't use following ParticleList names elsewhere:
2247 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
2248 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
2250 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
2252 @param particleList The input ParticleList
2253 @param decayString specify Particle to be added to the ParticleList
2254 @param workingDirectory The weight file directory
2255 @param downloadFlag whether download default weight files or not
2256 @param pi0vetoname extraInfo name of pi0 probability
2257 @param etavetoname extraInfo name of eta probability
2258 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2259 @param path modules are added to this path
2265 global PI0ETAVETO_COUNTER
2267 if PI0ETAVETO_COUNTER == 0:
2268 from variables
import variables
2269 variables.addAlias(
'lowE',
'daughter(1,E)')
2270 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
2271 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
2272 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
2273 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
2274 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
2276 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
2278 roe_path = create_path()
2280 deadEndPath = create_path()
2282 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
2284 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
2286 pi0softname =
'gamma:PI0SOFT'
2287 etasoftname =
'gamma:ETASOFT'
2288 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
2289 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
2293 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
2295 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
2298 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
2300 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
2302 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
2303 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
2305 if not os.path.isdir(workingDirectory):
2306 os.mkdir(workingDirectory)
2307 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
2309 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
2311 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
2312 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
2314 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
2316 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
2317 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
2319 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
2320 identifier=workingDirectory +
'/pi0veto.root')
2321 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
2322 identifier=workingDirectory +
'/etaveto.root')
2324 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
2325 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
2327 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
2328 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
2330 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2333 def writePi0EtaVeto(
2336 workingDirectory='.',
2343 Give pi0/eta probability for hard photon.
2345 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.
2347 The current default weight files are optimised using MC12.
2349 The input variables of the mva training are:
2351 * M: pi0/eta candidates Invariant mass
2352 * daughter(1,E): soft photon energy in lab frame
2353 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
2354 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2355 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
2356 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
2357 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
2358 * cosHelicityAngleMomentum: pi0/eta candidates cosHelicityAngleMomentum
2360 If you don't have weight files in your workingDirectory,
2361 these files are downloaded from the database to your workingDirectory automatically.
2363 The following strings are available for mode:
2365 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
2366 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
2367 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
2368 * both: tight energy cut and clusterNHits cut are applied to soft photon
2370 One can obtain the result of pi0/eta veto from `pi0Prob`/`etaProb`
2373 Please don't use following ParticleList names elsewhere:
2375 ``gamma:HardPhoton``,
2376 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
2377 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
2378 ``pi0:EtaVeto + ListName``,
2379 ``eta:EtaVeto + ListName``
2381 @param particleList the input ParticleList
2382 @param decayString specify Particle to be added to the ParticleList
2383 @param workingDirectory the weight file directory
2384 @param mode choose one mode out of 'standard', 'tight', 'cluster' and 'both'
2385 @param downloadFlag whether download default weight files or not
2386 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
2387 @param path modules are added to this path
2393 roe_path = create_path()
2394 deadEndPath = create_path()
2395 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
2396 fillSignalSideParticleList(
'gamma:HardPhoton', decayString, path=roe_path)
2397 if not os.path.isdir(workingDirectory):
2398 os.mkdir(workingDirectory)
2399 B2INFO(
'writePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
2401 dictListName = {
'standard':
'Origin',
2402 'tight':
'TightEnergyThreshold',
2403 'cluster':
'LargeClusterSize',
2404 'both':
'TightEnrgyThresholdAndLargeClusterSize'}
2406 dictPi0EnergyCut = {
'standard':
'[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
2407 'tight':
'[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]',
2408 'cluster':
'[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
2409 'both':
'[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]'}
2411 dictEtaEnergyCut = {
'standard':
'[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
2412 'tight':
'[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]',
2413 'cluster':
'[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
2414 'both':
'[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]'}
2416 dictTimingAndNHitsCut = {
'standard':
'abs(clusterTiming)<clusterErrorTiming',
2417 'tight':
'abs(clusterTiming)<clusterErrorTiming',
2418 'cluster':
'abs(clusterTiming)<clusterErrorTiming and clusterNHits >= 2',
2419 'both':
'abs(clusterTiming)<clusterErrorTiming and clusterNHits >= 2'}
2421 dictPi0WeightFileName = {
'standard':
'pi0veto_origin.root',
2422 'tight':
'pi0veto_tight.root',
2423 'cluster':
'pi0veto_cluster.root',
2424 'both':
'pi0veto_both.root'}
2426 dictEtaWeightFileName = {
'standard':
'etaveto_origin.root',
2427 'tight':
'etaveto_tight.root',
2428 'cluster':
'etaveto_cluster.root',
2429 'both':
'etaveto_both.root'}
2431 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
2432 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
2433 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
2434 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
2436 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
2437 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
2438 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
2439 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
2441 dictPi0ExtraInfoName = {
'standard':
'Pi0VetoOrigin',
2442 'tight':
'Pi0VetoTightEnergyThreshold',
2443 'cluster':
'Pi0VetoLargeClusterSize',
2444 'both':
'Pi0VetoTightEnergyThresholdAndLargeClusterSize'}
2446 dictEtaExtraInfoName = {
'standard':
'EtaVetoOrigin',
2447 'tight':
'EtaVetoTightEnergyThreshold',
2448 'cluster':
'EtaVetoLargeClusterSize',
2449 'both':
'EtaVetoTightEnergyThresholdAndLargeClusterSize'}
2451 dictPi0ExtraInfoRename = {
'standard':
'Pi0ProbOrigin',
2452 'tight':
'Pi0ProbTightEnergyThreshold',
2453 'cluster':
'Pi0ProbLargeClusterSize',
2454 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize'}
2456 dictEtaExtraInfoRename = {
'standard':
'EtaProbOrigin',
2457 'tight':
'EtaProbTightEnergyThreshold',
2458 'cluster':
'EtaProbLargeClusterSize',
2459 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize'}
2461 ListName = dictListName[mode]
2462 Pi0EnergyCut = dictPi0EnergyCut[mode]
2463 EtaEnergyCut = dictEtaEnergyCut[mode]
2464 TimingAndNHitsCut = dictTimingAndNHitsCut[mode]
2465 Pi0WeightFileName = dictPi0WeightFileName[mode]
2466 EtaWeightFileName = dictEtaWeightFileName[mode]
2467 Pi0PayloadName = dictPi0PayloadName[mode]
2468 EtaPayloadName = dictEtaPayloadName[mode]
2469 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
2470 EtaExtraInfoName = dictEtaExtraInfoName[mode]
2471 Pi0ExtraInfoRename = dictPi0ExtraInfoRename[mode]
2472 EtaExtraInfoRename = dictEtaExtraInfoRename[mode]
2478 pi0soft =
'gamma:Pi0Soft' + ListName +
'_' + particleList.replace(
':',
'_')
2480 fillParticleList(pi0soft, Pi0EnergyCut, path=roe_path)
2482 applyCuts(pi0soft, TimingAndNHitsCut, path=roe_path)
2484 reconstructDecay(
'pi0:Pi0Veto' + ListName +
' -> gamma:HardPhoton ' + pi0soft,
'', path=roe_path)
2487 if not os.path.isfile(workingDirectory +
'/' + Pi0WeightFileName):
2489 basf2_mva.download(Pi0PayloadName, workingDirectory +
'/' + Pi0WeightFileName)
2490 B2INFO(
'writePi0EtaVeto: ' + Pi0WeightFileName +
' has been downloaded from database to workingDirectory.')
2492 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName],
2493 extraInfoName=Pi0ExtraInfoName, identifier=workingDirectory +
'/' + Pi0WeightFileName)
2495 rankByHighest(
'pi0:Pi0Veto' + ListName,
'extraInfo(' + Pi0ExtraInfoName +
')', numBest=1, path=roe_path)
2497 variableToSignalSideExtraInfo(
'pi0:Pi0Veto' + ListName,
2498 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoRename}, path=roe_path)
2503 etasoft =
'gamma:EtaSoft' + ListName +
'_' + particleList.replace(
':',
'_')
2504 fillParticleList(etasoft, EtaEnergyCut, path=roe_path)
2505 applyCuts(etasoft, TimingAndNHitsCut, path=roe_path)
2506 reconstructDecay(
'eta:EtaVeto' + ListName +
' -> gamma:HardPhoton ' + etasoft,
'', path=roe_path)
2507 if not os.path.isfile(workingDirectory +
'/' + EtaWeightFileName):
2509 basf2_mva.download(EtaPayloadName, workingDirectory +
'/' + EtaWeightFileName)
2510 B2INFO(
'writePi0EtaVeto: ' + EtaWeightFileName +
'has been downloaded from database to workingDirectory.')
2511 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName],
2512 extraInfoName=EtaExtraInfoName, identifier=workingDirectory +
'/' + EtaWeightFileName)
2513 rankByHighest(
'eta:EtaVeto' + ListName,
'extraInfo(' + EtaExtraInfoName +
')', numBest=1, path=roe_path)
2514 variableToSignalSideExtraInfo(
'eta:EtaVeto' + ListName,
2515 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoRename}, path=roe_path)
2517 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2520 def buildEventKinematics(inputListNames=[], default_cleanup=True,
2521 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
2523 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
2524 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
2525 (all track and all hits in ECL without associated track).
2527 The visible energy missing values are
2528 stored in a EventKinematics dataobject.
2530 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
2531 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
2532 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
2533 according to the PID likelihood and the option inputListNames will be ignored.
2534 @param chargedPIDPriors The prior PID fractions, that are used to regulate
2535 amount of certain charged particle species, should be a list of
2536 six floats if not None. The order of particle types is
2537 the following: [e-, mu-, pi-, K-, p+, d+]
2538 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
2539 @param path modules are added to this path
2541 trackCuts =
'pt > 0.1'
2542 trackCuts +=
' and thetaInCDCAcceptance'
2543 trackCuts +=
' and abs(dz) < 3'
2544 trackCuts +=
' and dr < 0.5'
2546 gammaCuts =
'E > 0.05'
2547 gammaCuts +=
' and thetaInCDCAcceptance'
2549 if fillWithMostLikely:
2550 from stdCharged
import stdMostLikely
2551 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
2552 inputListNames = [
'%s:mostlikely_evtkin' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
2553 fillParticleList(
'gamma:evtkin',
'', path=path)
2554 inputListNames += [
'gamma:evtkin']
2556 B2INFO(
"Using default cleanup in EventKinematics module.")
2557 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
2558 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
2559 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
2561 B2INFO(
"No cleanup in EventKinematics module.")
2562 if not inputListNames:
2563 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
2564 fillParticleList(
'pi+:evtkin',
'', path=path)
2565 fillParticleList(
'gamma:evtkin',
'', path=path)
2566 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
2568 B2INFO(
"Using default cleanup in EventKinematics module.")
2569 applyCuts(
'pi+:evtkin', trackCuts, path=path)
2570 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
2572 B2INFO(
"No cleanup in EventKinematics module.")
2574 particleLists = inputListNames
2576 eventKinematicsModule = register_module(
'EventKinematics')
2577 eventKinematicsModule.set_name(
'EventKinematics_')
2578 eventKinematicsModule.param(
'particleLists', particleLists)
2579 path.add_module(eventKinematicsModule)
2582 def buildEventShape(inputListNames=[],
2583 default_cleanup=True,
2588 harmonicMoments=True,
2592 checkForDuplicates=False,
2595 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
2596 using the particles in the lists provided by the user. If no particle list is provided,
2597 the function will internally create a list of good tracks and a list of good photons
2598 with (optionally) minimal quality cuts.
2601 The results of the calculation are then stored into the EventShapeContainer dataobject,
2602 and are accessible using the variables of the EventShape group.
2604 The user can switch the calculation of certain quantities on or off to save computing
2605 time. By default the calculation of the high-order moments (5-8) is turned off.
2606 Switching off an option will make the corresponding variables not available.
2609 The user can provide as many particle lists
2610 as needed, using also combined particles, but the function will always assume that
2611 the lists are independent.
2612 If the lists provided by the user contain several times the same track (either with
2613 different mass hypothesis, or once as an independent particle and once as daughter of a
2614 combined particle) the results won't be reliable.
2615 A basic check for duplicates is available setting the checkForDuplicate flags,
2616 but is usually quite time consuming.
2619 @param inputListNames List of ParticleLists used to calculate the
2620 event shape variables. If the list is empty the default
2621 particleLists pi+:evtshape and gamma:evtshape are filled.
2622 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
2623 defining the internal lists. This option is ignored if the
2624 particleLists are provided by the user.
2625 @param path Path to append the eventShape modules to.
2626 @param thrust Enables the calculation of thrust-related quantities (CLEO
2627 cones, Harmonic moments, jets).
2628 @param collisionAxis Enables the calculation of the quantities related to the
2630 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
2631 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
2632 to both the thrust axis and, if collisionAxis = True, the collision axis.
2633 @param allMoments If True, calculates also the FW and harmonic moments from order
2634 5 to 8 instead of the low-order ones only.
2635 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
2636 axis and, if collisionAxis = True, the collision axis.
2637 @param jets Enables the calculation of the hemisphere momenta and masses.
2638 Requires thrust = True.
2639 @param sphericity Enables the calculation of the sphericity-related quantities.
2640 @param checkForDuplicates Perform a check for duplicate particles before adding them. This option
2641 is quite time consuming, instead of using it consider sanitizing
2642 the lists you are passing to the function.
2644 if not inputListNames:
2645 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
2646 fillParticleList(
'pi+:evtshape',
'', path=path)
2647 fillParticleList(
'gamma:evtshape',
'', path=path)
2648 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
2651 B2INFO(
"Applying standard cuts")
2652 trackCuts =
'pt > 0.1'
2653 trackCuts +=
' and thetaInCDCAcceptance'
2654 trackCuts +=
' and abs(dz) < 3.0'
2655 trackCuts +=
' and dr < 0.5'
2656 applyCuts(
'pi+:evtshape', trackCuts, path=path)
2658 gammaCuts =
'E > 0.05'
2659 gammaCuts +=
' and thetaInCDCAcceptance'
2660 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
2662 B2WARNING(
"Creating the default lists with no cleanup.")
2664 particleLists = inputListNames
2666 eventShapeModule = register_module(
'EventShapeCalculator')
2667 eventShapeModule.set_name(
'EventShape')
2668 eventShapeModule.param(
'particleListNames', particleLists)
2669 eventShapeModule.param(
'enableAllMoments', allMoments)
2670 eventShapeModule.param(
'enableCleoCones', cleoCones)
2671 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
2672 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
2673 eventShapeModule.param(
'enableJets', jets)
2674 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
2675 eventShapeModule.param(
'enableSphericity', sphericity)
2676 eventShapeModule.param(
'enableThrust', thrust)
2677 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
2679 path.add_module(eventShapeModule)
2682 def labelTauPairMC(printDecayInfo=False, path=None):
2684 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
2685 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
2687 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
2688 @param path: module is added to this path
2690 tauDecayMarker = register_module(
'TauDecayMarker')
2691 tauDecayMarker.set_name(
'TauDecayMarker_')
2693 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
2696 def tagCurlTracks(particleLists,
2705 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
2707 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
2708 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
2710 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
2713 The module loops over all particles in a given list that meet the preselection **ptCut** and assigns them to
2714 bundles based on the response of the chosen **selector** and the required minimum response set by the
2715 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
2716 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
2720 @param particleLists: list of particle lists to check for curls.
2721 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
2722 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
2723 genParticleIndex then ranked and tagged as normal.
2724 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
2725 Note 'cut' selector is binary 0/1.
2726 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
2727 It is strongly recommended to used the 'mva' selection. The 'cut' selection
2728 is based on BN1079 and is only calibrated for Belle data.
2729 @param ptCut: pre-selection cut on transverse momentum.
2730 @param train: flag to set training mode if selector has a training mode (mva).
2731 @param path: module is added to this path.
2737 if (
not isinstance(particleLists, list)):
2738 particleLists = [particleLists]
2740 curlTagger = register_module(
'CurlTagger')
2741 curlTagger.set_name(
'CurlTagger_')
2742 curlTagger.param(
'particleLists', particleLists)
2743 curlTagger.param(
'belle', belle)
2744 curlTagger.param(
'mcTruth', mcTruth)
2745 curlTagger.param(
'responseCut', responseCut)
2746 curlTagger.param(
'selectorType', selectorType)
2747 curlTagger.param(
'ptCut', ptCut)
2748 curlTagger.param(
'train', train)
2750 path.add_module(curlTagger)
2753 def applyChargedPidMVA(particleLists, path, trainingMode, binaryHypoPDGCodes=(0, 0)):
2755 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
2757 The module decorates Particle objects in the input ParticleList(s) with variables
2758 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
2761 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.2.1**, **ROOT 6.14/06**).
2763 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
2765 - e (11) vs. pi (211)
2766 - mu (13) vs. pi (211)
2767 - pi (211) vs. K (321)
2768 - K (321) vs. pi (211)
2769 - p (2212) vs. pi (211)
2770 - d (1000010020) vs pi (211)
2772 , or 'global' PID, namely "one-vs-others" separation. The latter makes use of an MVA algorithm trained in multi-class mode,
2773 and it's the default behaviour.
2776 Currently the MVA is charge-agnostic, i.e. the training is not done independently for +/- charged particles.
2779 particleLists (list(str)): list of names of ParticleList objects for charged stable particles.
2780 The charge-conjugate ParticleLists will be also processed automatically.
2781 path (basf2.Path): the module is added to this path.
2782 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
2783 Needed to pick up the correct payload from the DB. Available choices:
2785 * c_Classification=0
2787 * c_ECL_Classification=2
2788 * c_ECL_Multiclass=3
2789 * c_PSD_Classification=4
2790 * c_PSD_Multiclass=5
2791 * c_ECL_PSD_Classification=6
2792 * c_ECL_PSD_Multiclass=7
2794 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
2795 Required only for binary PID mode.
2798 from ROOT
import Belle2
2800 plSet = set(particleLists)
2804 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_Classification:
2805 {
"mode":
"Classification",
"detector":
"ALL"},
2806 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_Multiclass:
2807 {
"mode":
"Multiclass",
"detector":
"ALL"},
2808 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_ECL_Classification:
2809 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
2810 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_ECL_Multiclass:
2811 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
2812 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_PSD_Classification:
2813 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
2814 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_PSD_Multiclass:
2815 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
2816 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_ECL_PSD_Classification:
2817 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
2818 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_ECL_PSD_Multiclass:
2819 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
2822 if payloadNames.get(trainingMode)
is None:
2823 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
2824 "\nis not supported. Please choose among the following:\n",
2825 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
2827 mode = payloadNames.get(trainingMode).get(
"mode")
2828 detector = payloadNames.get(trainingMode).get(
"detector")
2830 payloadName = f
"ChargedPidMVAWeights_{mode}"
2832 if binaryHypoPDGCodes == (0, 0):
2835 chargedpid = register_module(
"ChargedPidMVAMulticlass")
2836 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
2843 (Belle2.Const.electron.getPDGCode(), Belle2.Const.pion.getPDGCode()),
2844 (Belle2.Const.muon.getPDGCode(), Belle2.Const.pion.getPDGCode()),
2845 (Belle2.Const.pion.getPDGCode(), Belle2.Const.kaon.getPDGCode()),
2846 (Belle2.Const.kaon.getPDGCode(), Belle2.Const.pion.getPDGCode()),
2847 (Belle2.Const.proton.getPDGCode(), Belle2.Const.pion.getPDGCode()),
2848 (Belle2.Const.deuteron.getPDGCode(), Belle2.Const.pion.getPDGCode())
2851 if binaryHypoPDGCodes
not in binaryOpts:
2852 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
2853 ". Please choose among the following pairs:\n",
2854 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
2856 chargedpid = register_module(
"ChargedPidMVA")
2857 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
2858 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
2859 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
2861 chargedpid.param(
"particleLists", list(plSet))
2863 chargedpid.param(
"payloadName", payloadName)
2866 if detector ==
"ECL":
2867 chargedpid.param(
"useECLOnlyTraining",
True)
2869 path.add_module(chargedpid)
2872 def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
2874 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
2875 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
2876 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
2877 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
2880 >>> from modularAnalysis import calculateDistance
2881 >>>calculateDistance('list_name', 'decay_string', "mode", path=user_path)
2883 @param list_name name of the input ParticleList
2884 @param decay_string select particles between the distance of closest approch will be calculated
2885 @param mode Specifies how the distance is calculated
2886 vertextrack: calculate the distance of closest appreach between a track and a\
2887 vertex, taking the first candidate as vertex, default
2888 trackvertex: calculate the distance of closest appreach between a track and a\
2889 vertex, taking the first candidate as track
2890 2tracks: calculates the distance of closest appreach between two tracks
2891 2vertices: calculates the distance between two vertices
2892 vertexbtube: calculates the distance of closest appreach between a vertex and btube
2893 trackbtube: calculates the distance of closest appreach between a track and btube
2894 @param path modules are added to this path
2898 dist_mod = register_module(
'DistanceCalculator')
2900 dist_mod.set_name(
'DistanceCalculator_' + list_name)
2901 dist_mod.param(
'listName', list_name)
2902 dist_mod.param(
'decayString', decay_string)
2903 dist_mod.param(
'mode', mode)
2904 path.add_module(dist_mod)
2907 def addInclusiveDstarReconstruction(inputPionList, outputDstarList, slowPionCut, path):
2909 Adds the InclusiveDstarReconstruction module to the given path.
2910 This module creates a D* particle list by estimating the D* four momenta
2911 from slow pions, specified by a given cut. The D* energy is approximated
2912 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
2913 momentum is calculated using the D* PDG mass and the direction is collinear
2914 to the slow pion direction. The charge of the given pion list has to be consistent
2917 @param inputPionList Name of the input pion particle list
2918 @param outputDstarList Name of the output D* particle list
2919 @param slowPionCut Cut applied to the pion list to identify slow pions
2920 @param path the module is added to this path
2922 incl_dstar = register_module(
"InclusiveDstarReconstruction")
2923 incl_dstar.param(
"pionListName", inputPionList)
2924 incl_dstar.param(
"DstarListName", outputDstarList)
2925 incl_dstar.param(
"slowPionCut", slowPionCut)
2926 path.add_module(incl_dstar)
2929 def getAnalysisGlobaltag():
2931 Returns a string containing the name of the latest and recommended analysis globaltag.
2933 tags = subprocess.check_output([
'b2conditionsdb-recommend',
'--oneline']).decode(
'UTF-8').rstrip().split(
' ')
2936 if tag.startswith(
'analysis_tools'):
2941 if __name__ ==
'__main__':
2943 pretty_print_module(__name__,
"modularAnalysis")