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
15 def setAnalysisConfigParams(configParametersAndValues, path):
17 Sets analysis configuration parameters.
21 - 'tupleStyle': 'Default' (default) or 'Laconic'
22 o) defines the style of the branch name in the ntuple
24 - 'mcMatchingVersion': Specifies what version of mc matching algorithm is going to be used:
26 - 'MC5' - analysis of BelleII MC5
27 - 'Belle' - analysis of Belle MC
28 - 'BelleII' (default) - all other cases
30 @param configParametersAndValues dictionary of parameters and their values of the form {param1: value, param2: value, ...)
31 @param modules are added to this path
34 conf = register_module(
'AnalysisConfiguration')
36 allParameters = [
'tupleStyle',
'mcMatchingVersion']
38 keys = configParametersAndValues.keys()
40 if key
not in allParameters:
41 allParametersString =
', '.join(allParameters)
42 B2ERROR(
'Invalid analysis configuration parameter: ' + key +
'.\n'
43 'Please use one of the following: ' + allParametersString)
45 for param
in allParameters:
46 if param
in configParametersAndValues:
47 conf.param(param, configParametersAndValues.get(param))
52 def inputMdst(environmentType, filename, path, skipNEvents=0, entrySequence=None, *, parentLevel=0):
54 Loads the specified ROOT (DST/mDST/muDST) file with the RootInput module.
56 The correct environment (e.g. magnetic field settings) are determined from
57 the specified environment type. For the possible values please see
61 environmentType (str): type of the environment to be loaded
62 filename (str): the name of the file to be loaded
63 path (basf2.Path): modules are added to this path
64 skipNEvents (int): N events of the input file are skipped
65 entrySequence (str): The number sequences (e.g. 23:42,101) defining the entries which are processed.
66 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
68 if entrySequence
is not None:
69 entrySequence = [entrySequence]
71 inputMdstList(environmentType, [filename], path, skipNEvents, entrySequence, parentLevel=parentLevel)
74 def inputMdstList(environmentType, filelist, path, skipNEvents=0, entrySequences=None, *, parentLevel=0):
76 Loads the specified ROOT (DST/mDST/muDST) files with the RootInput module.
78 The correct environment (e.g. magnetic field settings) are determined from the specified environment type.
79 The currently available environments are:
81 - 'MC5': for analysis of Belle II MC samples produced with releases prior to build-2016-05-01.
82 This environment sets the constant magnetic field (B = 1.5 T)
83 - 'MC6': for analysis of Belle II MC samples produced with build-2016-05-01 or newer but prior to release-00-08-00
84 - 'MC7': for analysis of Belle II MC samples produced with build-2016-05-01 or newer but prior to release-00-08-00
85 - 'MC8', for analysis of Belle II MC samples produced with release-00-08-00 or newer but prior to release-02-00-00
86 - 'MC9', for analysis of Belle II MC samples produced with release-00-08-00 or newer but prior to release-02-00-00
87 - 'MC10', for analysis of Belle II MC samples produced with release-00-08-00 or newer but prior to release-02-00-00
88 - 'default': for analysis of Belle II MC samples produced with releases with release-02-00-00 or newer.
89 This environment sets the default magnetic field (see geometry settings)
90 - 'Belle': for analysis of converted (or during of conversion of) Belle MC/DATA samples
91 - 'None': for analysis of generator level information or during simulation/reconstruction of
92 previously generated events
94 Note that there is no difference between MC6 and MC7. Both are given for sake of completion.
95 The same is true for MC8, MC9 and MC10
98 environmentType (str): type of the environment to be loaded
99 filelist (list(str)): the filename list of files to be loaded
100 path (basf2.Path): modules are added to this path
101 skipNEvents (int): N events of the input files are skipped
102 entrySequences (list(str)): The number sequences (e.g. 23:42,101) defining
103 the entries which are processed for each inputFileName.
104 parentLevel (int): Number of generations of parent files (files used as input when creating a file) to be read
107 roinput = register_module(
'RootInput')
108 roinput.param(
'inputFileNames', filelist)
109 roinput.param(
'skipNEvents', skipNEvents)
110 if entrySequences
is not None:
111 roinput.param(
'entrySequences', entrySequences)
112 roinput.param(
'parentLevel', parentLevel)
114 path.add_module(roinput)
115 progress = register_module(
'ProgressBar')
116 path.add_module(progress)
120 environToMagneticField = {
'MC5':
'MagneticFieldConstant',
124 'Belle':
'MagneticFieldConstantBelle'}
126 fixECLClusters = {
'MC5':
True,
132 if environmentType
in environToMagneticField:
133 fieldType = environToMagneticField[environmentType]
134 if fieldType
is not None:
135 from ROOT
import Belle2
139 elif environmentType
in [
"MC8",
"MC9",
"MC10"]:
141 from basf2
import conditions
142 conditions.globaltags += [
"Legacy_MagneticField_MC8_MC9_MC10"]
143 elif environmentType
is 'None':
144 B2INFO(
'No magnetic field is loaded. This is OK, if generator level information only is studied.')
146 environments =
' '.join(list(environToMagneticField.keys()) + [
"MC8",
"MC9",
"MC10"])
147 B2FATAL(
'Incorrect environment type provided: ' + environmentType +
'! Please use one of the following:' + environments)
150 if environmentType
is 'Belle':
151 setAnalysisConfigParams({
'mcMatchingVersion':
'Belle'}, path)
154 if environmentType
is 'MC5':
155 setAnalysisConfigParams({
'mcMatchingVersion':
'MC5'}, path)
158 if fixECLClusters.get(environmentType)
is True:
159 fixECL = register_module(
'FixECLClusters')
160 path.add_module(fixECL)
163 def outputMdst(filename, path):
165 Saves mDST (mini-Data Summary Tables) to the output root file.
172 def outputUdst(filename, particleLists=[], includeArrays=[], path=None, dataDescription=None):
174 Save uDST (micro-Data Summary Tables) = MDST + Particles + ParticleLists
175 The charge-conjugate lists of those given in particleLists are also stored.
176 Additional Store Arrays and Relations to be stored can be specified via includeArrays
179 Note that this does not reduce the amount of Particle objects saved,
180 see skimOutputUdst() for a function that does.
186 plSet = set(particleLists)
187 for List
in particleLists:
188 name, label = List.split(
':')
191 partBranches = [
'Particles',
'ParticlesToMCParticles',
192 'ParticlesToPIDLikelihoods',
'ParticleExtraInfoMap',
193 'EventExtraInfo'] + includeArrays + list(plSet)
197 if dataDescription
is None:
200 dataDescription.update(dataLevel=
"udst")
203 additionalBranches=partBranches,
204 dataDescription=dataDescription)
207 def skimOutputUdst(skimDecayMode, skimParticleLists=[], outputParticleLists=[],
208 includeArrays=[], path=None, *,
209 outputFile=None, dataDescription=None):
211 Create a new path for events that contain a non-empty particle list specified via skimParticleLists.
212 Write the accepted events as a udst file, saving only particles from skimParticleLists
213 and from outputParticleLists.
214 Additional Store Arrays and Relations to be stored can be specified via includeArrays
217 :param str skimDecayMode: Name of the skim. If no outputFile is given this is
218 also the name of the output filename. This name will be added to the
219 FileMetaData as an extra data description "skimDecayMode"
220 :param list(str) skimParticleLists: Names of the particle lists to skim for.
221 An event will be accepted if at least one of the particle lists is not empty
222 :param list(str) outputParticleLists: Names of the particle lists to store in
223 the output in addition to the ones in skimParticleLists
224 :param list(str) includeArrays: datastore arrays/objects to write to the output
225 file in addition to mdst and particle information
226 :param basf2.Path path: Path to add the skim output to. Defaults to the default analysis path
227 :param str outputFile: Name of the output file if different from the skim name
228 :param dict dataDescription: Additional data descriptions to add to the output file. For example {"mcEventType":"mixed"}
231 from basf2
import AfterConditionPath
233 if outputFile
is None:
234 outputFile = skimDecayMode
237 if not outputFile.endswith(
".udst.root"):
238 outputFile +=
".udst.root"
240 skimfilter = register_module(
'SkimFilter')
241 skimfilter.set_name(
'SkimFilter_' + skimDecayMode)
242 skimfilter.param(
'particleLists', skimParticleLists)
243 path.add_module(skimfilter)
244 filter_path = create_path()
245 skimfilter.if_value(
'=1', filter_path, AfterConditionPath.CONTINUE)
248 skim_path = create_path()
249 saveParticleLists = skimParticleLists + outputParticleLists
254 if dataDescription
is None:
257 dataDescription.setdefault(
"skimDecayMode", skimDecayMode)
258 outputUdst(outputFile, saveParticleLists, includeArrays, path=skim_path,
259 dataDescription=dataDescription)
260 filter_path.add_independent_path(skim_path,
"skim_" + skimDecayMode)
263 def outputIndex(filename, path, includeArrays=[], keepParents=False, mc=True):
265 Write out all particle lists as an index file to be reprocessed using parentLevel flag.
266 Additional branches necessary for file to be read are automatically included.
267 Additional Store Arrays and Relations to be stored can be specified via includeArrays
270 @param str filename the name of the output index file
271 @param str path modules are added to this path
272 @param list(str) includeArrays: datastore arrays/objects to write to the output
273 file in addition to particle lists and related information
274 @param bool keepParents whether the parents of the input event will be saved as the parents of the same event
275 in the output index file. Useful if you are only adding more information to another index file
276 @param bool mc whether the input data is MC or not
280 onlyPLists = register_module(
'OnlyWriteOutParticleLists')
281 path.add_module(onlyPLists)
286 'ParticlesToMCParticles',
287 'ParticlesToPIDLikelihoods',
288 'ParticleExtraInfoMap',
291 branches = [
'EventMetaData']
292 persistentBranches = [
'FileMetaData']
296 branches += partBranches
297 branches += includeArrays
299 r1 = register_module(
'RootOutput')
300 r1.param(
'outputFileName', filename)
301 r1.param(
'additionalBranchNames', branches)
302 r1.param(
'branchNamesPersistent', persistentBranches)
303 r1.param(
'keepParents', keepParents)
307 def setupEventInfo(noEvents, path):
309 Prepare to generate events. This function sets up the EventInfoSetter.
310 You should call this before adding a generator from generators.
311 The experiment and run numbers are set to 0 (run independent generic MC in phase 3).
312 https://confluence.desy.de/display/BI/Experiment+numbering
315 noEvents (int): number of events to be generated
316 path (basf2.Path): modules are added to this path
318 evtnumbers = register_module(
'EventInfoSetter')
319 evtnumbers.param(
'evtNumList', [noEvents])
320 evtnumbers.param(
'runList', [0])
321 evtnumbers.param(
'expList', [0])
322 path.add_module(evtnumbers)
325 def loadGearbox(path, silence_warning=False):
327 Loads Gearbox module to the path.
330 Should be used in a job with *cosmic event generation only*
332 Needed for scripts which only generate cosmic events in order to
335 @param path modules are added to this path
336 @param silence_warning stops a verbose warning message if you know you want to use this function
339 if not silence_warning:
340 B2WARNING(
"""You are overwriting the geometry from the database with Gearbox.
341 This is fine if you're generating cosmic events. But in most other cases you probably don't want this.
343 If you're really sure you know what you're doing you can suppress this message with:
345 >>> loadGearbox(silence_warning=True)
349 paramloader = register_module(
'Gearbox')
350 path.add_module(paramloader)
353 def printPrimaryMCParticles(path):
355 Prints all primary MCParticles.
358 mcparticleprinter = register_module(
'PrintMCParticles')
359 path.add_module(mcparticleprinter)
362 def printMCParticles(onlyPrimaries=False, maxLevel=-1, path=None):
364 Prints all MCParticles or just primary MCParticles up to specified level. -1 means no limit.
367 mcparticleprinter = register_module(
'PrintMCParticles')
368 mcparticleprinter.param(
'onlyPrimaries', onlyPrimaries)
369 mcparticleprinter.param(
'maxLevel', maxLevel)
370 path.add_module(mcparticleprinter)
373 def correctBrems(outputList,
376 maximumAcceptance=3.0,
377 multiplePhotons=False,
378 usePhotonOnlyOnce=True,
382 For each particle in the given ``inputList``, copies it to the ``outputList`` and adds the
383 4-vector of the photon(s) in the ``gammaList`` which has(have) a weighted named relation to
384 the particle's track, set by the ``ECLTrackBremFinder`` module during reconstruction.
387 This can only work if the mdst file contains the *Bremsstrahlung* named relation. Official MC samples
388 up to and including MC12 and proc9 **do not** contain this. Newer production campaigns (from proc10 and MC13) will.
391 Please note that a new particle is always generated, with the old particle and -if found- one or more
392 photons as daughters.
394 The ``inputList`` should contain particles with associated tracks. Otherwise the module will exit with an error.
396 The ``gammaList`` should contain photons. Otherwise the module will exit with an error.
398 @param outputList The output particle list name containing the corrected particles
399 @param inputList The initial particle list name containing the particles to correct. *It should already exist.*
400 @param gammaList The photon list containing possibly bremsstrahlung photons; *It should already exist.*
401 @param maximumAcceptance Maximum value of the relation weight. Should be a number between [0,3)
402 @param multiplePhotons Whether to use only one photon (the one with the smallest acceptance) or as many as possible
403 @param usePhotonOnlyOnce If true, each brems candidate is used to correct only the track with the smallest relation weight
404 @param writeOut Whether `RootOutput` module should save the created ``outputList``
405 @param path The module is added to this path
408 bremscorrector = register_module(
'BremsFinder')
409 bremscorrector.set_name(
'bremsCorrector_' + outputList)
410 bremscorrector.param(
'inputList', inputList)
411 bremscorrector.param(
'outputList', outputList)
412 bremscorrector.param(
'gammaList', gammaList)
413 bremscorrector.param(
'maximumAcceptance', maximumAcceptance)
414 bremscorrector.param(
'multiplePhotons', multiplePhotons)
415 bremscorrector.param(
'usePhotonOnlyOnce', usePhotonOnlyOnce)
416 bremscorrector.param(
'writeOut', writeOut)
417 path.add_module(bremscorrector)
420 def copyList(outputListName, inputListName, writeOut=False, path=None):
422 Copy all Particle indices from input ParticleList to the output ParticleList.
423 Note that the Particles themselves are not copied. The original and copied
424 ParticleLists will point to the same Particles.
426 @param ouputListName copied ParticleList
427 @param inputListName original ParticleList to be copied
428 @param writeOut whether RootOutput module should save the created ParticleList
429 @param path modules are added to this path
432 copyLists(outputListName, [inputListName], writeOut, path)
435 def correctBremsBelle(outputListName,
438 multiplePhotons=True,
444 Run the Belle - like brems finding on the ``inputListName`` of charged particles.
445 Adds all photons in ``gammaListName`` to a copy of the charged particle that are within
446 ``angleThreshold`` and above ``minimumEnergy``.
449 outputListName (str): The output charged particle list containing the corrected charged particles
450 inputListName (str): The initial charged particle list containing the charged particles to correct.
451 gammaListName (str): The gammas list containing possibly radiative gammas, should already exist.
452 multiplePhotons (bool): How many photons should be added to the charged particle? nearest one -> False,
453 add all the photons within the cone -> True
454 angleThreshold (float): The maximum angle in radians between the charged particle and the (radiative)
455 gamma to be accepted.
456 minimumEnergy (float): The minimum energy in GeV of the (radiative) gamma to be accepted.
457 writeOut (bool): whether RootOutput module should save the created ParticleList
458 path (basf2.Path): modules are added to this path
461 fsrcorrector = register_module(
'BelleBremRecovery')
462 fsrcorrector.set_name(
'BelleFSRCorrection_' + outputListName)
463 fsrcorrector.param(
'inputListName', inputListName)
464 fsrcorrector.param(
'outputListName', outputListName)
465 fsrcorrector.param(
'gammaListName', gammaListName)
466 fsrcorrector.param(
'multiplePhotons', multiplePhotons)
467 fsrcorrector.param(
'angleThreshold', angleThreshold)
468 fsrcorrector.param(
'minimumEnergy', minimumEnergy)
469 fsrcorrector.param(
'writeOut', writeOut)
470 path.add_module(fsrcorrector)
473 def copyLists(outputListName, inputListNames, writeOut=False, path=None):
475 Copy all Particle indices from all input ParticleLists to the
476 single output ParticleList.
477 Note that the Particles themselves are not copied.
478 The original and copied ParticleLists will point to the same Particles.
480 Duplicates are removed based on the first-come, first-served principle.
481 Therefore, the order of the input ParticleLists matters.
484 If you want to select the best duplicate based on another criterion, have
485 a look at the function `mergeListsWithBestDuplicate`.
488 Two particles that differ only by the order of their daughters are
489 considered duplicates and one of them will be removed.
491 @param ouputListName copied ParticleList
492 @param inputListName vector of original ParticleLists to be copied
493 @param writeOut whether RootOutput module should save the created ParticleList
494 @param path modules are added to this path
497 pmanipulate = register_module(
'ParticleListManipulator')
498 pmanipulate.set_name(
'PListCopy_' + outputListName)
499 pmanipulate.param(
'outputListName', outputListName)
500 pmanipulate.param(
'inputListNames', inputListNames)
501 pmanipulate.param(
'writeOut', writeOut)
502 path.add_module(pmanipulate)
505 def copyParticles(outputListName, inputListName, writeOut=False, path=None):
507 Create copies of Particles given in the input ParticleList and add them to the output ParticleList.
509 The existing relations of the original Particle (or it's (grand-)^n-daughters)
510 are copied as well. Note that only the relation is copied and that the related
511 object is not. Copied particles are therefore related to the *same* object as
514 @param ouputListName new ParticleList filled with copied Particles
515 @param inputListName input ParticleList with original Particles
516 @param writeOut whether RootOutput module should save the created ParticleList
517 @param path modules are added to this path
521 pmanipulate = register_module(
'ParticleListManipulator')
522 pmanipulate.set_name(
'PListCopy_' + outputListName)
523 pmanipulate.param(
'outputListName', outputListName)
524 pmanipulate.param(
'inputListNames', [inputListName])
525 pmanipulate.param(
'writeOut', writeOut)
526 path.add_module(pmanipulate)
529 pcopy = register_module(
'ParticleCopier')
530 pcopy.param(
'inputListNames', [outputListName])
531 path.add_module(pcopy)
534 def cutAndCopyLists(outputListName, inputListNames, cut, writeOut=False, path=None):
536 Copy candidates from all lists in ``inputListNames`` to
537 ``outputListName`` if they pass ``cut`` (given selection criteria).
540 Note that the Particles themselves are not copied.
541 The original and copied ParticleLists will point to the same Particles.
544 Require energetic pions safely inside the cdc
546 >>> cutAndCopyLists("pi+:energeticPions", ["pi+:good", "pi+:loose"], "[E > 2] and [0.3 < theta < 2.6]", path=mypath)
549 You must use square braces ``[`` and ``]`` for conditional statements.
552 outputListName (str): the new ParticleList name
553 inputListName (list(str)): list of input ParticleList names
554 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
555 writeOut (bool): whether RootOutput module should save the created ParticleList
556 path (basf2.Path): modules are added to this path
558 pmanipulate = register_module(
'ParticleListManipulator')
559 pmanipulate.set_name(
'PListCutAndCopy_' + outputListName)
560 pmanipulate.param(
'outputListName', outputListName)
561 pmanipulate.param(
'inputListNames', inputListNames)
562 pmanipulate.param(
'cut', cut)
563 pmanipulate.param(
'writeOut', writeOut)
564 path.add_module(pmanipulate)
567 def cutAndCopyList(outputListName, inputListName, cut, writeOut=False, path=None):
569 Copy candidates from ``inputListName`` to ``outputListName`` if they pass
570 ``cut`` (given selection criteria).
573 Note the Particles themselves are not copied.
574 The original and copied ParticleLists will point to the same Particles.
577 require energetic pions safely inside the cdc
579 >>> cutAndCopyLists("pi+:energeticPions", "pi+:loose", "[E > 2] and [0.3 < theta < 2.6]", path=mypath)
582 You must use square braces ``[`` and ``]`` for conditional statements.
585 outputListName (str): the new ParticleList name
586 inputListName (str): input ParticleList name
587 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
588 writeOut (bool): whether RootOutput module should save the created ParticleList
589 path (basf2.Path): modules are added to this path
591 cutAndCopyLists(outputListName, [inputListName], cut, writeOut, path)
594 def trackingEfficiency(inputListNames, fraction, path=None):
596 Randomly remove tracks from the provided particle lists to estimate the tracking efficiency.
597 Takes care of the duplicates, if any.
600 inputListNames (list(str)): input particle list names
601 fraction (float): fraction of particles to be removed randomly
602 path (basf2.Path): module is added to this path
605 trackingefficiency = register_module(
'TrackingEfficiency')
606 trackingefficiency.param(
'particleLists', inputListNames)
607 trackingefficiency.param(
'frac', fraction)
608 path.add_module(trackingefficiency)
611 def trackingMomentum(inputListNames, scale, path=None):
613 Scale momenta of the particles (based on charged tracks) according to the scaling factor scale.
616 inputListNames (list(str)): input particle list names
617 scale (float): scaling factor (1.0 -- no scaling)
618 path (basf2.Path): module is added to this path
621 trackingmomentum = register_module(
'TrackingMomentum')
622 trackingmomentum.param(
'particleLists', inputListNames)
623 trackingmomentum.param(
'scale', scale)
624 path.add_module(trackingmomentum)
627 def mergeListsWithBestDuplicate(outputListName,
634 Merge input ParticleLists into one output ParticleList. Only the best
635 among duplicates is kept. The lowest or highest value (configurable via
636 preferLowest) of the provided variable determines which duplicate is the
639 @param ouputListName name of merged ParticleList
640 @param inputListName vector of original ParticleLists to be merged
641 @param variable variable to determine best duplicate
642 @param preferLowest whether lowest or highest value of variable should be preferred
643 @param writeOut whether RootOutput module should save the created ParticleList
644 @param path modules are added to this path
647 pmanipulate = register_module(
'ParticleListManipulator')
648 pmanipulate.set_name(
'PListMerger_' + outputListName)
649 pmanipulate.param(
'outputListName', outputListName)
650 pmanipulate.param(
'inputListNames', inputListNames)
651 pmanipulate.param(
'variable', variable)
652 pmanipulate.param(
'preferLowest', preferLowest)
653 pmanipulate.param(
'writeOut', writeOut)
654 path.add_module(pmanipulate)
657 def fillSignalSideParticleList(outputListName, decayString, path):
659 This function should only be used in the ROE path, that is a path
660 that is executed for each ROE object in the DataStore.
662 Example: fillSignalSideParticleList('gamma:sig','B0 -> K*0 ^gamma', roe_path)
664 Function will create a ParticleList with name 'gamma:sig' which will be filled
665 with the existing photon Particle, being the second daughter of the B0 candidate
666 to which the ROE object has to be related.
668 @param ouputListName name of the created ParticleList
669 @param decayString specify Particle to be added to the ParticleList
672 pload = register_module(
'SignalSideParticleListCreator')
673 pload.set_name(
'SSParticleList_' + outputListName)
674 pload.param(
'particleListName', outputListName)
675 pload.param(
'decayString', decayString)
676 path.add_module(pload)
679 def fillParticleLists(decayStringsWithCuts, writeOut=False, path=None, enforceFitHypothesis=False):
681 Creates Particles of the desired types from the corresponding ``mdst`` dataobjects,
682 loads them to the ``StoreArray<Particle>`` and fills the ParticleLists.
684 The multiple ParticleLists with their own selection criteria are specified
685 via list tuples (decayString, cut), for example
687 .. code-block:: python
689 kaons = ('K+:mykaons', 'kaonID>0.1')
690 pions = ('pi+:mypions','pionID>0.1')
691 fillParticleLists([kaons, pions])
693 If you are unsure what selection you want, you might like to see the
694 :doc:`StandardParticles` functions.
696 The type of the particles to be loaded is specified via the decayString module parameter.
697 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
698 the particle. The following types of the particles can be loaded:
700 * charged final state particles (input ``mdst`` type = Tracks)
701 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
703 * neutral final state particles
704 - "gamma" (input ``mdst`` type = ECLCluster)
705 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
706 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
709 For "K_S0" and "Lambda0" you must specify the daughter ordering.
711 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0s:
713 .. code-block:: python
715 v0lambdas = ('Lambda0 -> p+ pi-', '0.9 < M < 1.3')
716 fillParticleLists([kaons, pions, v0lambdas], path=mypath)
719 For "K_L0" it is now possible to load from ECLClusters, to revert to
720 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
722 .. code-block:: python
724 klongs = ('K_L0', 'isFromKLM > 0')
725 fillParticleLists([kaons, pions, klongs], path=mypath)
729 decayStringsWithCuts (list): A list of python ntuples of (decayString, cut).
730 The decay string determines the type of Particle
731 and determines the of the ParticleList.
732 If the input MDST type is V0 the whole
733 decay chain needs to be specified, so that
734 the user decides and controls the daughters
735 ' order (e.g. ``K_S0 -> pi+ pi-``)
736 The cut is the selection criteria
737 to be added to the ParticleList. It can be an empty string.
738 writeOut (bool): whether RootOutput module should save the created ParticleList
739 path (basf2.Path): modules are added to this path
740 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
741 using a mass hypothesis of the exact type passed to fillParticleLists().
742 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
743 in terms of mass difference will be used if the fit using exact particle
744 type is not available.
747 pload = register_module(
'ParticleLoader')
748 pload.set_name(
'ParticleLoader_' +
'PLists')
749 pload.param(
'decayStringsWithCuts', decayStringsWithCuts)
750 pload.param(
'writeOut', writeOut)
751 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
752 path.add_module(pload)
755 def fillParticleList(decayString, cut, writeOut=False, path=None, enforceFitHypothesis=False):
757 Creates Particles of the desired type from the corresponding ``mdst`` dataobjects,
758 loads them to the StoreArray<Particle> and fills the ParticleList.
761 the :doc:`StandardParticles` functions.
763 The type of the particles to be loaded is specified via the decayString module parameter.
764 The type of the ``mdst`` dataobject that is used as an input is determined from the type of
765 the particle. The following types of the particles can be loaded:
767 * charged final state particles (input ``mdst`` type = Tracks)
768 - e+, mu+, pi+, K+, p, deuteron (and charge conjugated particles)
770 * neutral final state particles
771 - "gamma" (input ``mdst`` type = ECLCluster)
772 - "K_S0", "Lambda0" (input ``mdst`` type = V0)
773 - "K_L0" (input ``mdst`` type = KLMCluster or ECLCluster)
776 For "K_S0" and "Lambda0" you must specify the daughter ordering.
778 For example, to load V0s as :math:`\\Lambda^0\\to p^+\\pi^-` decays from V0ss:
780 .. code-block:: python
782 fillParticleList('Lambda0 -> p+ pi-', '0.9 < M < 1.3', path=mypath)
785 For "K_L0" it is now possible to load from ECLClusters, to revert to
786 the old (Belle) behavior, you can require ``'isFromKLM > 0'``.
788 .. code-block:: python
790 fillParticleList('K_L0', 'isFromKLM > 0', path=mypath)
793 decayString (str): Type of Particle and determines the name of the ParticleList.
794 If the input MDST type is V0 the whole decay chain needs to be specified, so that
795 the user decides and controls the daughters' order (e.g. ``K_S0 -> pi+ pi-``)
796 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
797 writeOut (bool): whether RootOutput module should save the created ParticleList
798 path (basf2.Path): modules are added to this path
799 enforceFitHypothesis (bool): If true, Particles will be created only for the tracks which have been fitted
800 using a mass hypothesis of the exact type passed to fillParticleLists().
801 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
802 in terms of mass difference will be used if the fit using exact particle
803 type is not available.
806 pload = register_module(
'ParticleLoader')
807 pload.set_name(
'ParticleLoader_' + decayString)
808 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
809 pload.param(
'writeOut', writeOut)
810 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
811 path.add_module(pload)
814 def fillParticleListWithTrackHypothesis(decayString,
818 enforceFitHypothesis=False,
821 As fillParticleList, but if used for a charged FSP, loads the particle with the requested hypothesis if available
823 @param decayString specifies type of Particles and determines the name of the ParticleList
824 @param cut Particles need to pass these selection criteria to be added to the ParticleList
825 @param hypothesis the PDG code of the desired track hypothesis
826 @param writeOut whether RootOutput module should save the created ParticleList
827 @param enforceFitHypothesis If true, Particles will be created only for the tracks which have been fitted
828 using a mass hypothesis of the exact type passed to fillParticleLists().
829 If enforceFitHypothesis is False (the default) the next closest fit hypothesis
830 in terms of mass difference will be used if the fit using exact particle
831 type is not available.
832 @param path modules are added to this path
835 pload = register_module(
'ParticleLoader')
836 pload.set_name(
'ParticleLoader_' + decayString)
837 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
838 pload.param(
'trackHypothesis', hypothesis)
839 pload.param(
'writeOut', writeOut)
840 pload.param(
"enforceFitHypothesis", enforceFitHypothesis)
841 path.add_module(pload)
844 def fillConvertedPhotonsList(decayString, cut, writeOut=False, path=None):
846 Creates photon Particle object for each e+e- combination in the V0 StoreArray.
849 You must specify the daughter ordering.
851 .. code-block:: python
853 fillConvertedPhotonsList('gamma:converted -> e+ e-', '')
856 decayString (str): Must be gamma to an e+e- pair. You muse specify the daughter ordering.
857 Will also determine the name of the particleList.
858 cut (str): Particles need to pass these selection criteria to be added to the ParticleList
859 writeOut (bool): whether RootOutput module should save the created ParticleList
860 path (basf2.Path): modules are added to this path
863 pload = register_module(
'ParticleLoader')
864 pload.set_name(
'ParticleLoader_' + decayString)
865 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
866 pload.param(
'addDaughters',
True)
867 pload.param(
'writeOut', writeOut)
868 path.add_module(pload)
871 def fillParticleListFromROE(decayString,
874 sourceParticleListName='',
879 Creates Particle object for each ROE of the desired type found in the
880 StoreArray<RestOfEvent>, loads them to the StoreArray<Particle>
881 and fills the ParticleList. If useMissing is True, then the missing
882 momentum is used instead of ROE.
884 The type of the particles to be loaded is specified via the decayString module parameter.
886 @param decayString specifies type of Particles and determines the name of the ParticleList.
887 Source ROEs can be taken as a daughter list, for example:
888 'B0:tagFromROE -> B0:signal'
889 @param cut Particles need to pass these selection criteria to be added to the ParticleList
890 @param maskName Name of the ROE mask to use
891 @param sourceParticleListName Use related ROEs to this particle list as a source
892 @param useMissing Use missing momentum instead of ROE momentum
893 @param writeOut whether RootOutput module should save the created ParticleList
894 @param path modules are added to this path
897 pload = register_module(
'ParticleLoader')
898 pload.set_name(
'ParticleLoader_' + decayString)
899 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
900 pload.param(
'writeOut', writeOut)
901 pload.param(
'roeMaskName', maskName)
902 pload.param(
'useMissing', useMissing)
903 pload.param(
'sourceParticleListName', sourceParticleListName)
904 pload.param(
'useROEs',
True)
905 path.add_module(pload)
908 def fillParticleListFromMC(decayString,
911 skipNonPrimaryDaughters=False,
915 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
916 loads them to the StoreArray<Particle> and fills the ParticleList.
918 The type of the particles to be loaded is specified via the decayString module parameter.
920 @param decayString specifies type of Particles and determines the name of the ParticleList
921 @param cut Particles need to pass these selection criteria to be added to the ParticleList
922 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
923 sets mother-daughter relations
924 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
925 @param writeOut whether RootOutput module should save the created ParticleList
926 @param path modules are added to this path
929 pload = register_module(
'ParticleLoader')
930 pload.set_name(
'ParticleLoader_' + decayString)
931 pload.param(
'decayStringsWithCuts', [(decayString, cut)])
932 pload.param(
'addDaughters', addDaughters)
933 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
934 pload.param(
'writeOut', writeOut)
935 pload.param(
'useMCParticles',
True)
936 path.add_module(pload)
939 def fillParticleListsFromMC(decayStringsWithCuts,
941 skipNonPrimaryDaughters=False,
945 Creates Particle object for each MCParticle of the desired type found in the StoreArray<MCParticle>,
946 loads them to the StoreArray<Particle> and fills the ParticleLists.
948 The types of the particles to be loaded are specified via the (decayString, cut) tuples given in a list.
950 kaons = ('K+:gen', '')
951 pions = ('pi+:gen', 'pionID>0.1')
952 fillParticleListsFromMC([kaons, pions])
954 @param decayString specifies type of Particles and determines the name of the ParticleList
955 @param cut Particles need to pass these selection criteria to be added to the ParticleList
956 @param addDaughters adds the bottom part of the decay chain of the particle to the datastore and
957 sets mother-daughter relations
958 @param skipNonPrimaryDaughters if true, skip non primary daughters, useful to study final state daughter particles
959 @param writeOut whether RootOutput module should save the created ParticleList
960 @param path modules are added to this path
963 pload = register_module(
'ParticleLoader')
964 pload.set_name(
'ParticleLoader_' +
'PLists')
965 pload.param(
'decayStringsWithCuts', decayStringsWithCuts)
966 pload.param(
'addDaughters', addDaughters)
967 pload.param(
'skipNonPrimaryDaughters', skipNonPrimaryDaughters)
968 pload.param(
'writeOut', writeOut)
969 pload.param(
'useMCParticles',
True)
970 path.add_module(pload)
973 def applyCuts(list_name, cut, path):
975 Removes particle candidates from ``list_name`` that do not pass ``cut``
976 (given selection criteria).
979 require energetic pions safely inside the cdc
981 >>> applyCuts("pi+:mypions", "[E > 2] and [0.3 < theta < 2.6]", path=mypath)
984 You must use square braces ``[`` and ``]`` for conditional statements.
987 list_name (str): input ParticleList name
988 cut (str): Candidates that do not pass these selection criteria are removed from the ParticleList
989 path (basf2.Path): modules are added to this path
992 pselect = register_module(
'ParticleSelector')
993 pselect.set_name(
'ParticleSelector_applyCuts_' + list_name)
994 pselect.param(
'decayString', list_name)
995 pselect.param(
'cut', cut)
996 path.add_module(pselect)
999 def applyEventCuts(cut, path):
1001 Removes events that do not pass the ``cut`` (given selection criteria).
1004 continuum events (in mc only) with more than 5 tracks
1006 >>> applyEventCuts("[nTracks > 5] and [isContinuumEvent], path=mypath)
1009 You must use square braces ``[`` and ``]`` for conditional statements.
1012 cut (str): Events that do not pass these selection criteria are skipped
1013 path (basf2.Path): modules are added to this path
1016 eselect = register_module(
'VariableToReturnValue')
1017 eselect.param(
'variable',
'passesEventCut(' + cut +
')')
1018 path.add_module(eselect)
1019 empty_path = create_path()
1020 eselect.if_value(
'<1', empty_path)
1023 def reconstructDecay(decayString,
1028 candidate_limit=None,
1029 ignoreIfTooManyCandidates=True,
1030 chargeConjugation=True,
1031 allowChargeViolation=False):
1033 Creates new Particles by making combinations of existing Particles - it reconstructs unstable particles via their specified
1034 decay mode, e.g. in form of a :ref:`DecayString`: :code:`D0 -> K- pi+` or :code:`B+ -> anti-D0 pi+`, ... All possible
1035 combinations are created (particles are used only once per candidate) and combinations that pass the specified selection
1036 criteria are saved to a newly created (mother) ParticleList. By default the charge conjugated decay is reconstructed as well
1037 (meaning that the charge conjugated mother list is created as well) but this can be deactivated.
1039 One can use an ``@``-sign to mark a particle as unspecified, e.g. in form of a DecayString: :code:`\@Xsd -> K+ pi-`. If the
1040 particle is marked as unspecified, its identity will not be checked when doing :ref:`MCMatching`. Any particle which decays into
1041 the correct daughters will be flagged as correct. For example the DecayString :code:`\@Xsd -> K+ pi-` would match all particles
1042 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
1043 correctly so this can be used for "sum of exclusive" decays.
1046 The input ParticleLists are typically ordered according to the upstream reconstruction algorithm.
1047 Therefore, if you combine two or more identical particles in the decay chain you should not expect to see the same
1048 distribution for the daughter kinematics as they may be sorted by geometry, momentum etc.
1050 For example, in the decay :code:`D0 -> pi0 pi0` the momentum distributions of the two ``pi0`` s are not identical.
1051 This can be solved by manually randomising the lists before combining.
1055 * `Particle combiner how does it work? <https://questions.belle2.org/question/4318/particle-combiner-how-does-it-work/>`_
1056 * `Identical particles in decay chain <https://questions.belle2.org/question/5724/identical-particles-in-decay-chain/>`_
1058 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1059 (from the DecayString the mother and daughter ParticleLists are determined)
1060 @param cut created (mother) Particles are added to the mother ParticleList if they
1061 pass give cuts (in VariableManager style) and rejected otherwise
1062 @param dmID user specified decay mode identifier
1063 @param writeOut whether RootOutput module should save the created ParticleList
1064 @param path modules are added to this path
1065 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1066 the number of candidates is exceeded a Warning will be
1068 By default, all these candidates will be removed and event will be ignored.
1069 This behaviour can be changed by \'ignoreIfTooManyCandidates\' flag.
1070 If no value is given the amount is limited to a sensible
1071 default. A value <=0 will disable this limit and can
1072 cause huge memory amounts so be careful.
1073 @param ignoreIfTooManyCandidates whether event should be ignored or not if number of reconstructed
1074 candidates reaches limit. If event is ignored, no candidates are reconstructed,
1075 otherwise, number of candidates in candidate_limit is reconstructed.
1076 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1077 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1080 pmake = register_module(
'ParticleCombiner')
1081 pmake.set_name(
'ParticleCombiner_' + decayString)
1082 pmake.param(
'decayString', decayString)
1083 pmake.param(
'cut', cut)
1084 pmake.param(
'decayMode', dmID)
1085 pmake.param(
'writeOut', writeOut)
1086 if candidate_limit
is not None:
1087 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1088 pmake.param(
"ignoreIfTooManyCandidates", ignoreIfTooManyCandidates)
1089 pmake.param(
'chargeConjugation', chargeConjugation)
1090 pmake.param(
"allowChargeViolation", allowChargeViolation)
1091 path.add_module(pmake)
1094 def combineAllParticles(inputParticleLists, outputList, cut='', writeOut=False, path=None):
1096 Creates a new Particle as the combination of all Particles from all
1097 provided inputParticleLists. However, each particle is used only once
1098 (even if duplicates are provided) and the combination has to pass the
1099 specified selection criteria to be saved in the newly created (mother)
1102 @param inputParticleLists List of input particle lists which are combined to the new Particle
1103 @param outputList Name of the particle combination created with this module
1104 @param cut created (mother) Particle is added to the mother ParticleList if it passes
1105 these given cuts (in VariableManager style) and is rejected otherwise
1106 @param writeOut whether RootOutput module should save the created ParticleList
1107 @param path module is added to this path
1110 pmake = register_module(
'AllParticleCombiner')
1111 pmake.set_name(
'AllParticleCombiner_' + outputList)
1112 pmake.param(
'inputListNames', inputParticleLists)
1113 pmake.param(
'outputListName', outputList)
1114 pmake.param(
'cut', cut)
1115 pmake.param(
'writeOut', writeOut)
1116 path.add_module(pmake)
1119 def reconstructMissingKlongDecayExpert(decayString,
1126 Creates a list of K_L0's with their momentum determined from kinematic constraints of B->K_L0 + something else.
1128 @param decayString DecayString specifying what kind of the decay should be reconstructed
1129 (from the DecayString the mother and daughter ParticleLists are determined)
1130 @param cut Particles are added to the K_L0 ParticleList if they
1131 pass the given cuts (in VariableManager style) and rejected otherwise
1132 @param dmID user specified decay mode identifier
1133 @param writeOut whether RootOutput module should save the created ParticleList
1134 @param path modules are added to this path
1135 @param recoList suffix appended to original K_L0 ParticleList that identifies the newly created K_L0 list
1138 pcalc = register_module(
'KlongMomentumCalculatorExpert')
1139 pcalc.set_name(
'KlongMomentumCalculatorExpert_' + decayString)
1140 pcalc.param(
'decayString', decayString)
1141 pcalc.param(
'cut', cut)
1142 pcalc.param(
'decayMode', dmID)
1143 pcalc.param(
'writeOut', writeOut)
1144 pcalc.param(
'recoList', recoList)
1145 path.add_module(pcalc)
1147 rmake = register_module(
'KlongDecayReconstructorExpert')
1148 rmake.set_name(
'KlongDecayReconstructorExpert_' + decayString)
1149 rmake.param(
'decayString', decayString)
1150 rmake.param(
'cut', cut)
1151 rmake.param(
'decayMode', dmID)
1152 rmake.param(
'writeOut', writeOut)
1153 rmake.param(
'recoList', recoList)
1154 path.add_module(rmake)
1157 def replaceMass(replacerName, particleLists=[], pdgCode=22, path=None):
1159 replaces the mass of the particles inside the given particleLists
1160 with the invariant mass of the particle corresponding to the given pdgCode.
1162 @param particleLists new ParticleList filled with copied Particles
1163 @param pdgCode PDG code for mass reference
1164 @param path modules are added to this path
1168 pmassupdater = register_module(
'ParticleMassUpdater')
1169 pmassupdater.set_name(
'ParticleMassUpdater_' + replacerName)
1170 pmassupdater.param(
'particleLists', particleLists)
1171 pmassupdater.param(
'pdgCode', pdgCode)
1172 path.add_module(pmassupdater)
1175 def reconstructRecoil(decayString,
1180 candidate_limit=None,
1181 allowChargeViolation=False):
1183 Creates new Particles that recoil against the input particles.
1185 For example the decay string M -> D1 D2 D3 will:
1186 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1187 - Particles D1, D2, D3 will be appended as daughters to M
1188 - the 4-momentum of the mother Particle M is given by
1189 p(M) = p(HER) + p(LER) - Sum_i p(Di)
1191 @param decayString DecayString specifying what kind of the decay should be reconstructed
1192 (from the DecayString the mother and daughter ParticleLists are determined)
1193 @param cut created (mother) Particles are added to the mother ParticleList if they
1194 pass give cuts (in VariableManager style) and rejected otherwise
1195 @param dmID user specified decay mode identifier
1196 @param writeOut whether RootOutput module should save the created ParticleList
1197 @param path modules are added to this path
1198 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1199 the number of candidates is exceeded no candidate will be
1200 reconstructed for that event and a Warning will be
1202 If no value is given the amount is limited to a sensible
1203 default. A value <=0 will disable this limit and can
1204 cause huge memory amounts so be careful.
1205 @param allowChargeViolation whether the decay string needs to conserve the electric charge
1208 pmake = register_module(
'ParticleCombiner')
1209 pmake.set_name(
'ParticleCombiner_' + decayString)
1210 pmake.param(
'decayString', decayString)
1211 pmake.param(
'cut', cut)
1212 pmake.param(
'decayMode', dmID)
1213 pmake.param(
'writeOut', writeOut)
1214 pmake.param(
'recoilParticleType', 1)
1215 if candidate_limit
is not None:
1216 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1217 pmake.param(
'allowChargeViolation', allowChargeViolation)
1218 path.add_module(pmake)
1221 def reconstructRecoilDaughter(decayString,
1226 candidate_limit=None,
1227 allowChargeViolation=False):
1229 Creates new Particles that are daughters of the particle reconstructed in the recoil (always assumed to be the first daughter).
1231 For example the decay string M -> D1 D2 D3 will:
1232 - create mother Particle M for each unique combination of D1, D2, D3 Particles
1233 - Particles D1, D2, D3 will be appended as daughters to M
1234 - the 4-momentum of the mother Particle M is given by
1235 p(M) = p(D1) - Sum_i p(Di), where i>1
1237 @param decayString DecayString specifying what kind of the decay should be reconstructed
1238 (from the DecayString the mother and daughter ParticleLists are determined)
1239 @param cut created (mother) Particles are added to the mother ParticleList if they
1240 pass give cuts (in VariableManager style) and rejected otherwise
1241 @param dmID user specified decay mode identifier
1242 @param writeOut whether RootOutput module should save the created ParticleList
1243 @param path modules are added to this path
1244 @param candidate_limit Maximum amount of candidates to be reconstructed. If
1245 the number of candidates is exceeded no candidate will be
1246 reconstructed for that event and a Warning will be
1248 If no value is given the amount is limited to a sensible
1249 default. A value <=0 will disable this limit and can
1250 cause huge memory amounts so be careful.
1251 @param allowChargeViolation whether the decay string needs to conserve the electric charge taking into account that the first
1252 daughter is actually the mother
1255 pmake = register_module(
'ParticleCombiner')
1256 pmake.set_name(
'ParticleCombiner_' + decayString)
1257 pmake.param(
'decayString', decayString)
1258 pmake.param(
'cut', cut)
1259 pmake.param(
'decayMode', dmID)
1260 pmake.param(
'writeOut', writeOut)
1261 pmake.param(
'recoilParticleType', 2)
1262 if candidate_limit
is not None:
1263 pmake.param(
"maximumNumberOfCandidates", candidate_limit)
1264 pmake.param(
'allowChargeViolation', allowChargeViolation)
1265 path.add_module(pmake)
1268 def rankByHighest(particleList,
1272 allowMultiRank=False,
1276 Ranks particles in the input list by the given variable (highest to lowest), and stores an integer rank for each Particle
1277 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1278 The list is also sorted from best to worst candidate
1279 (each charge, e.g. B+/B-, separately).
1280 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1281 a non-zero value for 'numBest'.
1284 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1285 These variable names can become clunky, so it's probably a good idea to set an alias.
1286 For example if you rank your B candidates by momentum,
1290 rankByHighest("B0:myCandidates", "p", path=mypath)
1291 vm.addAlias("momentumRank", "extraInfo(p_rank)")
1294 @param particleList The input ParticleList
1295 @param variable Variable to order Particles by.
1296 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1297 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1298 @param allowMultiRank If true, candidates with the same value will get the same rank.
1299 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1300 @param path modules are added to this path
1303 bcs = register_module(
'BestCandidateSelection')
1304 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1305 bcs.param(
'particleList', particleList)
1306 bcs.param(
'variable', variable)
1307 bcs.param(
'numBest', numBest)
1308 bcs.param(
'outputVariable', outputVariable)
1309 bcs.param(
'allowMultiRank', allowMultiRank)
1310 bcs.param(
'cut', cut)
1311 path.add_module(bcs)
1314 def rankByLowest(particleList,
1318 allowMultiRank=False,
1322 Ranks particles in the input list by the given variable (lowest to highest), and stores an integer rank for each Particle
1323 in an :b2:var:`extraInfo` field ``${variable}_rank`` starting at 1 (best).
1324 The list is also sorted from best to worst candidate
1325 (each charge, e.g. B+/B-, separately).
1326 This can be used to perform a best candidate selection by cutting on the corresponding rank value, or by specifying
1327 a non-zero value for 'numBest'.
1330 Extra-info fields can be accessed by the :b2:var:`extraInfo` metavariable.
1331 These variable names can become clunky, so it's probably a good idea to set an alias.
1332 For example if you rank your B candidates by :b2:var:`dM`,
1336 rankByLowest("B0:myCandidates", "dM", path=mypath)
1337 vm.addAlias("massDifferenceRank", "extraInfo(dM_rank)")
1340 @param particleList The input ParticleList
1341 @param variable Variable to order Particles by.
1342 @param numBest If not zero, only the $numBest Particles in particleList with rank <= numBest are kept.
1343 @param outputVariable Name for the variable that will be created which contains the rank, Default is '${variable}_rank'.
1344 @param allowMultiRank If true, candidates with the same value will get the same rank.
1345 @param cut Only candidates passing the cut will be ranked. The others will have rank -1
1346 @param path modules are added to this path
1349 bcs = register_module(
'BestCandidateSelection')
1350 bcs.set_name(
'BestCandidateSelection_' + particleList +
'_' + variable)
1351 bcs.param(
'particleList', particleList)
1352 bcs.param(
'variable', variable)
1353 bcs.param(
'numBest', numBest)
1354 bcs.param(
'selectLowest',
True)
1355 bcs.param(
'allowMultiRank', allowMultiRank)
1356 bcs.param(
'outputVariable', outputVariable)
1357 bcs.param(
'cut', cut)
1358 path.add_module(bcs)
1361 def applyRandomCandidateSelection(particleList, path=None):
1363 If there are multiple candidates in the provided particleList, all but one of them are removed randomly.
1364 This is done on a event-by-event basis.
1366 @param particleList ParticleList for which the random candidate selection should be applied
1367 @param path module is added to this path
1370 rcs = register_module(
'BestCandidateSelection')
1371 rcs.set_name(
'RandomCandidateSelection_' + particleList)
1372 rcs.param(
'particleList', particleList)
1373 rcs.param(
'variable',
'random')
1374 rcs.param(
'selectLowest',
False)
1375 rcs.param(
'allowMultiRank',
False)
1376 rcs.param(
'numBest', 1)
1377 rcs.param(
'cut',
'')
1378 rcs.param(
'outputVariable',
'')
1379 path.add_module(rcs)
1384 Prints the contents of DataStore in the first event (or a specific event number or all events).
1385 Will list all objects and arrays (including size).
1388 The command line tool: ``b2file-size``.
1391 eventNumber (int): Print the datastore only for this event. The default
1392 (-1) prints only the first event, 0 means print for all events (can produce large output)
1393 path (basf2.Path): the PrintCollections module is added to this path
1396 This will print a lot of output if you print it for all events and process many events.
1400 printDS = register_module(
'PrintCollections')
1401 printDS.param(
'printForEvent', eventNumber)
1402 path.add_module(printDS)
1405 def printVariableValues(list_name, var_names, path):
1407 Prints out values of specified variables of all Particles included in given ParticleList. For debugging purposes.
1409 @param list_name input ParticleList name
1410 @param var_names vector of variable names to be printed
1411 @param path modules are added to this path
1414 prlist = register_module(
'ParticlePrinter')
1415 prlist.set_name(
'ParticlePrinter_' + list_name)
1416 prlist.param(
'listName', list_name)
1417 prlist.param(
'fullPrint',
False)
1418 prlist.param(
'variables', var_names)
1419 path.add_module(prlist)
1422 def printList(list_name, full, path):
1424 Prints the size and executes Particle->print() (if full=True)
1425 method for all Particles in given ParticleList. For debugging purposes.
1427 @param list_name input ParticleList name
1428 @param full execute Particle->print() method for all Particles
1429 @param path modules are added to this path
1432 prlist = register_module(
'ParticlePrinter')
1433 prlist.set_name(
'ParticlePrinter_' + list_name)
1434 prlist.param(
'listName', list_name)
1435 prlist.param(
'fullPrint', full)
1436 path.add_module(prlist)
1439 def variablesToNtuple(decayString, variables, treename='variables', filename='ntuple.root', path=None):
1441 Creates and fills a flat ntuple with the specified variables from the VariableManager.
1442 If a decayString is provided, then there will be one entry per candidate (for particle in list of candidates).
1443 If an empty decayString is provided, there will be one entry per event (useful for trigger studies, etc).
1446 decayString (str): specifies type of Particles and determines the name of the ParticleList
1447 variables (list(str)): the list of variables (which must be registered in the VariableManager)
1448 treename (str): name of the ntuple tree
1449 filename (str): which is used to store the variables
1450 path (basf2.Path): the basf2 path where the analysis is processed
1453 output = register_module(
'VariablesToNtuple')
1454 output.set_name(
'VariablesToNtuple_' + decayString)
1455 output.param(
'particleList', decayString)
1456 output.param(
'variables', variables)
1457 output.param(
'fileName', filename)
1458 output.param(
'treeName', treename)
1459 path.add_module(output)
1465 filename='ntuple.root',
1468 prefixDecayString=False):
1470 Creates and fills a flat ntuple with the specified variables from the VariableManager
1473 decayString (str): specifies type of Particles and determines the name of the ParticleList
1474 variables (list(tuple))): variables + binning which must be registered in the VariableManager
1475 variables_2d (list(tuple)): pair of variables + binning for each which must be registered in the VariableManager
1476 filename (str): which is used to store the variables
1477 path (basf2.Path): the basf2 path where the analysis is processed
1478 directory (str): directory inside the output file where the histograms should be saved.
1479 Useful if you want to have different histograms in the same file to separate them.
1480 prefixDecayString (bool): If True the decayString will be prepended to the directory name to allow for more
1481 programmatic naming of the structure in the file.
1484 output = register_module(
'VariablesToHistogram')
1485 output.set_name(
'VariablesToHistogram_' + decayString)
1486 output.param(
'particleList', decayString)
1487 output.param(
'variables', variables)
1488 output.param(
'variables_2d', variables_2d)
1489 output.param(
'fileName', filename)
1490 if directory
is not None or prefixDecayString:
1491 if directory
is None:
1493 if prefixDecayString:
1494 directory = decayString +
"_" + directory
1495 output.param(
"directory", directory)
1496 path.add_module(output)
1501 For each particle in the input list the selected variables are saved in an extra-info field with the given name.
1502 Can be used when wanting to save variables before modifying them, e.g. when performing vertex fits.
1504 An existing extra info with the same name will be overwritten if the new
1505 value is lower / will never be overwritten / will be overwritten if the
1506 new value is higher / will always be overwritten (-1/0/1/2).
1508 @param particleList The input ParticleList
1509 @param variables Dictionary of Variables and extraInfo names.
1510 @param path modules are added to this path
1513 mod = register_module(
'VariablesToExtraInfo')
1514 mod.set_name(
'VariablesToExtraInfo_' + particleList)
1515 mod.param(
'particleList', particleList)
1516 mod.param(
'variables', variables)
1517 mod.param(
'overwrite', option)
1518 path.add_module(mod)
1521 def variablesToDaughterExtraInfo(particleList, decayString, variables, option=0, path=None):
1523 For each daughter particle specified via decay string the selected variables (estimated for the mother particle)
1524 are saved in an extra-info field with the given name. In other words, the property of mother is saved as extra-info
1525 to specified daughter particle.
1527 An existing extra info with the same name will be overwritten if the new
1528 value is lower / will never be overwritten / will be overwritten if the
1529 new value is higher / will always be overwritten (-1/0/1/2).
1531 @param particleList The input ParticleList
1532 @param decayString Decay string that specifies to which daughter the extra info should be appended
1533 @param variables Dictionary of Variables and extraInfo names.
1534 @param option Various options for overwriting
1535 @param path modules are added to this path
1538 mod = register_module(
'VariablesToExtraInfo')
1539 mod.set_name(
'VariablesToDaughterExtraInfo_' + particleList)
1540 mod.param(
'particleList', particleList)
1541 mod.param(
'decayString', decayString)
1542 mod.param(
'variables', variables)
1543 mod.param(
'overwrite', option)
1544 path.add_module(mod)
1547 def variablesToEventExtraInfo(particleList, variables, option=0, path=None):
1549 For each particle in the input list the selected variables are saved in an event-extra-info field with the given name,
1550 Can be used to save MC truth information, for example, in a ntuple of reconstructed particles.
1552 An existing extra info with the same name will be overwritten if the new
1553 value is lower / will never be overwritten / will be overwritten if the
1554 new value is higher / will always be overwritten (-1/0/1/2).
1556 @param particleList The input ParticleList
1557 @param variables Dictionary of Variables and extraInfo names.
1558 @param path modules are added to this path
1561 mod = register_module(
'VariablesToEventExtraInfo')
1562 mod.set_name(
'VariablesToEventExtraInfo_' + particleList)
1563 mod.param(
'particleList', particleList)
1564 mod.param(
'variables', variables)
1565 mod.param(
'overwrite', option)
1566 path.add_module(mod)
1569 def variableToSignalSideExtraInfo(particleList, varToExtraInfo, path):
1571 Write the value of specified variables estimated for the single particle in the input list (has to contain exactly 1
1572 particle) as an extra info to the particle related to current ROE.
1573 Should be used only in the for_each roe path.
1575 @param particleList The input ParticleList
1576 @param varToExtraInfo Dictionary of Variables and extraInfo names.
1577 @param path modules are added to this path
1579 mod = register_module(
'SignalSideVariablesToExtraInfo')
1580 mod.set_name(
'SigSideVarToExtraInfo_' + particleList)
1581 mod.param(
'particleListName', particleList)
1582 mod.param(
'variableToExtraInfo', varToExtraInfo)
1583 path.add_module(mod)
1586 def signalRegion(particleList, cut, path=None, name="isSignalRegion", blind_data=True):
1588 Define and blind a signal region.
1589 Per default, the defined signal region is cut out if ran on data.
1590 This function will provide a new variable 'isSignalRegion' as default, which is either 0 or 1 depending on the cut
1594 >>> ma.reconstructDecay("B+:sig -> D+ pi0", "Mbc>5.2", path=path)
1595 >>> ma.signalRegion("B+:sig",
1596 >>> "Mbc>5.27 and abs(deltaE)<0.2",
1597 >>> blind_data=True,
1599 >>> ma.variablesToNtuples("B+:sig", ["isSignalRegion"], path=path)
1602 particleList (str): The input ParticleList
1603 cut (str): Cut string describing the signal region
1604 path (basf2.Path):: Modules are added to this path
1605 name (str): Name of the Signal region in the variable manager
1606 blind_data (bool): Automatically exclude signal region from data
1610 from variables
import variables
1611 mod = register_module(
'VariablesToExtraInfo')
1612 mod.set_name(f
'{name}_' + particleList)
1613 mod.param(
'particleList', particleList)
1614 mod.param(
'variables', {f
"passesCut({cut})": name})
1615 variables.addAlias(name, f
"extraInfo({name})")
1616 path.add_module(mod)
1620 applyCuts(particleList, f
"{name}==0 or isMC==1", path=path)
1623 def removeExtraInfo(particleLists=[], removeEventExtraInfo=False, path=None):
1625 Removes the ExtraInfo of the given particleLists. If specified (removeEventExtraInfo = True) also the EventExtraInfo is removed.
1628 mod = register_module(
'ExtraInfoRemover')
1629 mod.param(
'particleLists', particleLists)
1630 mod.param(
'removeEventExtraInfo', removeEventExtraInfo)
1631 path.add_module(mod)
1634 def signalSideParticleFilter(particleList, selection, roe_path, deadEndPath):
1636 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
1637 to the particle from the input ParticleList. Additional selection criteria can be applied.
1638 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
1639 meet the selection criteria the execution of deadEndPath is started. This path, as the name
1640 suggests should be empty and its purpose is to end the execution of for_each roe path for
1641 the current ROE object.
1643 @param particleList The input ParticleList
1644 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
1645 @param for_each roe path in which this filter is executed
1646 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
1648 mod = register_module(
'SignalSideParticleFilter')
1649 mod.set_name(
'SigSideParticleFilter_' + particleList)
1650 mod.param(
'particleLists', [particleList])
1651 mod.param(
'selection', selection)
1652 roe_path.add_module(mod)
1653 mod.if_false(deadEndPath)
1656 def signalSideParticleListsFilter(particleLists, selection, roe_path, deadEndPath):
1658 Checks if the current ROE object in the for_each roe path (argument roe_path) is related
1659 to the particle from the input ParticleList. Additional selection criteria can be applied.
1660 If ROE is not related to any of the Particles from ParticleList or the Particle doesn't
1661 meet the selection criteria the execution of deadEndPath is started. This path, as the name
1662 suggests should be empty and its purpose is to end the execution of for_each roe path for
1663 the current ROE object.
1665 @param particleLists The input ParticleLists
1666 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
1667 @param for_each roe path in which this filter is executed
1668 @param deadEndPath empty path that ends execution of or_each roe path for the current ROE object.
1670 mod = register_module(
'SignalSideParticleFilter')
1671 mod.set_name(
'SigSideParticleFilter_' + particleLists[0])
1672 mod.param(
'particleLists', particleLists)
1673 mod.param(
'selection', selection)
1674 roe_path.add_module(mod)
1675 mod.if_false(deadEndPath)
1684 chargeConjugation=True,
1687 Finds and creates a ``ParticleList`` from given decay string.
1688 ``ParticleList`` of daughters with sub-decay is created.
1690 Only signal particle, which means :b2:var:`isSignal` is equal to 1, is stored. One can use the decay string grammar
1691 to change the behavior of :b2:var:`isSignal`. One can find detailed information in :ref:`DecayString`.
1694 If one uses same sub-decay twice, same particles are registered to a ``ParticleList``. For example,
1695 ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] [pi0:gg =direct=> gamma:MC gamma:MC]``.
1696 One can skip the second sub-decay, ``K_S0:pi0pi0 =direct=> [pi0:gg =direct=> gamma:MC gamma:MC] pi0:gg``.
1699 @param decayString :ref:`DecayString` specifying what kind of the decay should be reconstructed
1700 (from the DecayString the mother and daughter ParticleLists are determined)
1701 @param cut created (mother) Particles are added to the mother ParticleList if they
1702 pass given cuts (in VariableManager style) and rejected otherwise
1703 isSignal==1 is always required by default.
1704 @param dmID user specified decay mode identifier
1705 @param writeOut whether RootOutput module should save the created ParticleList
1706 @param path modules are added to this path
1707 @param chargeConjugation boolean to decide whether charge conjugated mode should be reconstructed as well (on by default)
1710 pmake = register_module(
'ParticleCombinerFromMC')
1711 pmake.set_name(
'ParticleCombinerFromMC_' + decayString)
1712 pmake.param(
'decayString', decayString)
1713 pmake.param(
'cut', cut)
1714 pmake.param(
'decayMode', dmID)
1715 pmake.param(
'writeOut', writeOut)
1716 pmake.param(
'chargeConjugation', chargeConjugation)
1717 path.add_module(pmake)
1728 This function is not fully tested and maintained.
1729 Please consider to use reconstructMCDecay() instead.
1731 Finds and creates a ``ParticleList`` for all ``MCParticle`` decays matching a given :ref:`DecayString`.
1732 The decay string is required to describe correctly what you want.
1733 In the case of inclusive decays, you can use :ref:`Grammar_for_custom_MCMatching`
1735 @param list_name The output particle list name
1736 @param decay The decay string which you want
1737 @param writeOut Whether `RootOutput` module should save the created ``outputList``
1738 @param path modules are added to this path
1740 B2WARNING(
"This function is not fully tested and maintained."
1741 "Please consider to use reconstructMCDecay() instead.")
1743 decayfinder = register_module(
'MCDecayFinder')
1744 decayfinder.set_name(
'MCDecayFinder_' + list_name)
1745 decayfinder.param(
'listName', list_name)
1746 decayfinder.param(
'decayString', decay)
1747 decayfinder.param(
'writeOut', writeOut)
1748 path.add_module(decayfinder)
1751 def summaryOfLists(particleLists, path):
1753 Prints out Particle statistics at the end of the job: number of events with at
1754 least one candidate, average number of candidates per event, etc.
1756 @param particleLists list of input ParticleLists
1759 particleStats = register_module(
'ParticleStats')
1760 particleStats.param(
'particleLists', particleLists)
1761 path.add_module(particleStats)
1764 def matchMCTruth(list_name, path):
1766 Performs MC matching (sets relation Particle->MCParticle) for
1767 all particles (and its (grand)^N-daughter particles) in the specified
1770 @param list_name name of the input ParticleList
1771 @param path modules are added to this path
1774 mcMatch = register_module(
'MCMatcherParticles')
1775 mcMatch.set_name(
'MCMatch_' + list_name)
1776 mcMatch.param(
'listName', list_name)
1777 path.add_module(mcMatch)
1780 def looseMCTruth(list_name, path):
1782 Performs loose MC matching for all particles in the specified
1784 The difference between loose and normal mc matching algorithm is that
1785 the loose algorithm will find the common mother of the majority of daughter
1786 particles while the normal algorithm finds the common mother of all daughters.
1787 The results of loose mc matching algorithm are stored to the following extraInfo
1790 - looseMCMotherPDG: PDG code of most common mother
1791 - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother
1792 - looseMCWrongDaughterN: number of daughters that don't originate from the most
1794 - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from
1795 the most common mother
1796 (only if looseMCWrongDaughterN = 1)
1797 - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background
1800 @param list_name name of the input ParticleList
1801 @param path modules are added to this path
1804 mcMatch = register_module(
'MCMatcherParticles')
1805 mcMatch.set_name(
'LooseMCMatch_' + list_name)
1806 mcMatch.param(
'listName', list_name)
1807 mcMatch.param(
'looseMCMatching',
True)
1808 path.add_module(mcMatch)
1811 def buildRestOfEvent(target_list_name, inputParticlelists=None,
1812 fillWithMostLikely=False,
1813 chargedPIDPriors=None, path=None):
1815 Creates for each Particle in the given ParticleList a RestOfEvent
1816 dataobject and makes BASF2 relation between them. User can provide additional
1817 particle lists with a different particle hypotheses like ['K+:good, e+:good'], etc.
1819 @param target_list_name name of the input ParticleList
1820 @param inputParticlelists list of input particle list names, which serve
1821 as a source of particles to build ROE, the FSP particles from
1822 target_list_name are excluded from ROE object
1823 @param fillWithMostLikely if True, the module uses particle mass hypothesis for charged particles
1824 according to PID likelihood and the inputParticlelists
1825 option will be ignored.
1826 @param chargedPIDPriors The prior PID fractions, that are used to regulate
1827 amount of certain charged particle species, should be a list of
1828 six floats if not None. The order of particle types is
1829 the following: [e-, mu-, pi-, K-, p+, d+]
1830 @param path modules are added to this path
1832 if inputParticlelists
is None:
1833 inputParticlelists = []
1834 fillParticleList(
'pi+:roe_default',
'', path=path)
1835 if fillWithMostLikely:
1836 from stdCharged
import stdMostLikely
1837 stdMostLikely(chargedPIDPriors,
'_roe', path=path)
1838 inputParticlelists = [
'%s:mostlikely_roe' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+']]
1841 fillParticleList(
'gamma:roe_default',
'', path=path)
1842 fillParticleList(
'K_L0:roe_default',
'isFromKLM > 0', path=path)
1843 inputParticlelists += [
'pi+:roe_default',
'gamma:roe_default',
'K_L0:roe_default']
1845 inputParticlelists += [
'pi+:roe_default',
'gamma:mdst']
1846 roeBuilder = register_module(
'RestOfEventBuilder')
1847 roeBuilder.set_name(
'ROEBuilder_' + target_list_name)
1848 roeBuilder.param(
'particleList', target_list_name)
1849 roeBuilder.param(
'particleListsInput', inputParticlelists)
1850 path.add_module(roeBuilder)
1853 def buildNestedRestOfEvent(target_list_name, maskName='', path=None):
1855 Creates for each Particle in the given ParticleList a RestOfEvent
1856 @param target_list_name name of the input ParticleList
1857 @param mask_name name of the ROEMask to be used
1858 @param path modules are added to this path
1860 roeBuilder = register_module(
'RestOfEventBuilder')
1861 roeBuilder.set_name(
'NestedROEBuilder_' + target_list_name)
1862 roeBuilder.param(
'particleList', target_list_name)
1863 roeBuilder.param(
'nestedROEMask', maskName)
1864 roeBuilder.param(
'createNestedROE',
True)
1865 path.add_module(roeBuilder)
1868 def buildRestOfEventFromMC(target_list_name, inputParticlelists=[], path=None):
1870 Creates for each Particle in the given ParticleList a RestOfEvent
1871 @param target_list_name name of the input ParticleList
1872 @param inputParticlelists list of input particle list names, which serve
1873 as a source of particles to build ROE, the FSP particles from
1874 target_list_name are excluded from ROE object
1875 @param path modules are added to this path
1877 if (len(inputParticlelists) == 0):
1881 types = [
'gamma',
'e+',
'mu+',
'pi+',
'K+',
'p+',
'K_L0',
1882 'n0',
'nu_e',
'nu_mu',
'nu_tau',
1885 fillParticleListFromMC(
"%s:roe_default_gen" % t,
'mcPrimary > 0 and nDaughters == 0',
1886 True,
True, path=path)
1887 inputParticlelists += [
"%s:roe_default_gen" % t]
1888 roeBuilder = register_module(
'RestOfEventBuilder')
1889 roeBuilder.set_name(
'MCROEBuilder_' + target_list_name)
1890 roeBuilder.param(
'particleList', target_list_name)
1891 roeBuilder.param(
'particleListsInput', inputParticlelists)
1892 roeBuilder.param(
'fromMC',
True)
1893 path.add_module(roeBuilder)
1896 def appendROEMask(list_name,
1899 eclClusterSelection,
1902 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
1903 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
1905 - append a ROE mask with all tracks in ROE coming from the IP region
1907 >>> appendROEMask('B+:sig', 'IPtracks', 'abs(d0) < 0.05 and abs(z0) < 0.1', '')
1909 - append a ROE mask with only ECLClusters that pass as good photon candidates
1911 >>> good_photons = 'theta > 0.296706 and theta < 2.61799 and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
1912 >>> appendROEMask('B+:sig', 'goodROEGamma', '', good_photons)
1915 @param list_name name of the input ParticleList
1916 @param mask_name name of the appended ROEMask
1917 @param trackSelection decay string for the tracks in ROE
1918 @param eclClusterSelection decay string for the tracks in ROE
1919 @param path modules are added to this path
1922 roeMask = register_module(
'RestOfEventInterpreter')
1923 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
1924 roeMask.param(
'particleList', list_name)
1925 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection)])
1926 path.add_module(roeMask)
1929 def appendROEMasks(list_name, mask_tuples, path=None):
1931 Loads the ROE object of a particle and creates a ROE mask with a specific name. It applies
1932 selection criteria for tracks and eclClusters which will be used by variables in ROEVariables.cc.
1934 The multiple ROE masks with their own selection criteria are specified
1935 via list of tuples (mask_name, trackSelection, eclClusterSelection) or
1936 (mask_name, trackSelection, eclClusterSelection) in case with fractions.
1938 - Example for two tuples, one with and one without fractions
1940 >>> ipTracks = ('IPtracks', 'abs(d0) < 0.05 and abs(z0) < 0.1', '')
1941 >>> good_photons = 'theta > 0.296706 and theta < 2.61799 and clusterErrorTiming < 1e6 and [clusterE1E9 > 0.4 or E > 0.075]'
1942 >>> goodROEGamma = ('ROESel', 'abs(d0) < 0.05 and abs(z0) < 0.1', good_photons)
1943 >>> appendROEMasks('B+:sig', [ipTracks, goodROEGamma])
1945 @param list_name name of the input ParticleList
1946 @param mask_tuples array of ROEMask list tuples to be appended
1947 @param path modules are added to this path
1950 roeMask = register_module(
'RestOfEventInterpreter')
1951 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
1952 roeMask.param(
'particleList', list_name)
1953 roeMask.param(
'ROEMasks', mask_tuples)
1954 path.add_module(roeMask)
1957 def updateROEMask(list_name,
1960 eclClusterSelection='',
1963 Update an existing ROE mask by applying additional selection cuts for
1964 tracks and/or clusters.
1966 See function `appendROEMask`!
1968 @param list_name name of the input ParticleList
1969 @param mask_name name of the ROEMask to update
1970 @param trackSelection decay string for the tracks in ROE
1971 @param eclClusterSelection decay string for the tracks in ROE
1972 @param path modules are added to this path
1975 roeMask = register_module(
'RestOfEventInterpreter')
1976 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' + mask_name)
1977 roeMask.param(
'particleList', list_name)
1978 roeMask.param(
'ROEMasks', [(mask_name, trackSelection, eclClusterSelection)])
1979 roeMask.param(
'update',
True)
1980 path.add_module(roeMask)
1983 def updateROEMasks(list_name, mask_tuples, path):
1985 Update existing ROE masks by applying additional selection cuts for tracks
1988 The multiple ROE masks with their own selection criteria are specified
1989 via list tuples (mask_name, trackSelection, eclClusterSelection)
1991 See function `appendROEMasks`!
1993 @param list_name name of the input ParticleList
1994 @param mask_tuples array of ROEMask list tuples to be appended
1995 @param path modules are added to this path
1998 roeMask = register_module(
'RestOfEventInterpreter')
1999 roeMask.set_name(
'RestOfEventInterpreter_' + list_name +
'_' +
'MaskList')
2000 roeMask.param(
'particleList', list_name)
2001 roeMask.param(
'ROEMasks', mask_tuples)
2002 roeMask.param(
'update',
True)
2003 path.add_module(roeMask)
2006 def keepInROEMasks(list_name, mask_names, cut_string, path=None):
2008 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2009 With this function one can KEEP the tracks/eclclusters used in particles from provided particle list.
2010 This function should be executed only in the for_each roe path for the current ROE object.
2012 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2013 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2014 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2015 pion particle list (e.g. 'pi+:someLabel').
2017 Updating a non-existing mask will create a new one.
2019 - keep only those tracks that were used in provided particle list
2021 >>> keepInROEMasks('pi+:goodTracks', 'mask', '')
2023 - keep only those clusters that were used in provided particle list and pass a cut, apply to several masks
2025 >>> keepInROEMasks('gamma:goodClusters', ['mask1', 'mask2'], 'E > 0.1')
2028 @param list_name name of the input ParticleList
2029 @param mask_names array of ROEMasks to be updated
2030 @param cut_string decay string with which the mask will be updated
2031 @param path modules are added to this path
2034 updateMask = register_module(
'RestOfEventUpdater')
2035 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2036 updateMask.param(
'particleList', list_name)
2037 updateMask.param(
'updateMasks', mask_names)
2038 updateMask.param(
'cutString', cut_string)
2039 updateMask.param(
'discard',
False)
2040 path.add_module(updateMask)
2043 def discardFromROEMasks(list_name, mask_names, cut_string, path=None):
2045 This function is used to apply particle list specific cuts on one or more ROE masks (track or eclCluster).
2046 With this function one can DISCARD the tracks/eclclusters used in particles from provided particle list.
2047 This function should be executed only in the for_each roe path for the current ROE object.
2049 To avoid unnecessary computation, the input particle list should only contain particles from ROE
2050 (use cut 'isInRestOfEvent == 1'). To update the ECLCluster masks, the input particle list should be a photon
2051 particle list (e.g. 'gamma:someLabel'). To update the Track masks, the input particle list should be a charged
2052 pion particle list (e.g. 'pi+:someLabel').
2054 Updating a non-existing mask will create a new one.
2056 - discard tracks that were used in provided particle list
2058 >>> discardFromROEMasks('pi+:badTracks', 'mask', '')
2060 - discard clusters that were used in provided particle list and pass a cut, apply to several masks
2062 >>> discardFromROEMasks('gamma:badClusters', ['mask1', 'mask2'], 'E < 0.1')
2065 @param list_name name of the input ParticleList
2066 @param mask_names array of ROEMasks to be updated
2067 @param cut_string decay string with which the mask will be updated
2068 @param path modules are added to this path
2071 updateMask = register_module(
'RestOfEventUpdater')
2072 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2073 updateMask.param(
'particleList', list_name)
2074 updateMask.param(
'updateMasks', mask_names)
2075 updateMask.param(
'cutString', cut_string)
2076 updateMask.param(
'discard',
True)
2077 path.add_module(updateMask)
2080 def optimizeROEWithV0(list_name, mask_names, cut_string, path=None):
2082 This function is used to apply particle list specific cuts on one or more ROE masks for Tracks.
2083 It is possible to optimize the ROE selection by treating tracks from V0's separately, meaning,
2084 taking V0's 4-momentum into account instead of 4-momenta of tracks. A cut for only specific V0's
2085 passing it can be applied.
2087 The input particle list should be a V0 particle list: K_S0 ('K_S0:someLabel', ''),
2088 Lambda ('Lambda:someLabel', '') or converted photons ('gamma:someLabel').
2090 Updating a non-existing mask will create a new one.
2092 - treat tracks from K_S0 inside mass window separately, replace track momenta with K_S0 momentum
2094 >>> optimizeROEWithV0('K_S0:opt', 'mask', '0.450 < M < 0.550')
2096 @param list_name name of the input ParticleList
2097 @param mask_names array of ROEMasks to be updated
2098 @param cut_string decay string with which the mask will be updated
2099 @param path modules are added to this path
2102 updateMask = register_module(
'RestOfEventUpdater')
2103 updateMask.set_name(
'RestOfEventUpdater_' + list_name +
'_masks')
2104 updateMask.param(
'particleList', list_name)
2105 updateMask.param(
'updateMasks', mask_names)
2106 updateMask.param(
'cutString', cut_string)
2107 path.add_module(updateMask)
2110 def printROEInfo(mask_names=[], which_mask='both', full_print=False, path=None):
2112 This function prints out the information for the current ROE, so it should only be used in the for_each path.
2113 It prints out basic ROE object info.
2115 If mask names are provided, specific information for those masks will be printed out. By default, basic
2116 ECLCluster and Track mask info will be printed out, but it is possible to do this only for one, if needed.
2118 It is also possible to print out the specific mask values for each Track and ECLCluster by setting the 'full_print'
2121 @param mask_names array of ROEMask names for printing out info
2122 @param which_mask print out info for Tracks ('track'), ECLClusters ('cluster') or ('both')
2123 @param full_print print out mask values for each Track/ECLCLuster in mask
2124 @param path modules are added to this path
2126 if not isinstance(path, Path):
2127 B2FATAL(
"Error from printROEInfo, please add this to the for_each path")
2129 printMask = register_module(
'RestOfEventPrinter')
2130 printMask.set_name(
'RestOfEventPrinter')
2131 printMask.param(
'maskNames', mask_names)
2132 printMask.param(
'whichMask', which_mask)
2133 printMask.param(
'fullPrint', full_print)
2134 path.add_module(printMask)
2137 def buildContinuumSuppression(list_name, roe_mask, path):
2139 Creates for each Particle in the given ParticleList a ContinuumSuppression
2140 dataobject and makes BASF2 relation between them.
2142 @param list_name name of the input ParticleList
2143 @param path modules are added to this path
2146 qqBuilder = register_module(
'ContinuumSuppressionBuilder')
2147 qqBuilder.set_name(
'QQBuilder_' + list_name)
2148 qqBuilder.param(
'particleList', list_name)
2149 qqBuilder.param(
'ROEMask', roe_mask)
2150 path.add_module(qqBuilder)
2155 Removes all Particles that are not in a given list of ParticleLists (or daughters of those).
2156 All relations from/to Particles, daughter indices, and other ParticleLists are fixed.
2158 @param lists_to_keep Keep the Particles and their daughters in these ParticleLists.
2159 @param path modules are added to this path
2162 mod = register_module(
'RemoveParticlesNotInLists')
2163 mod.param(
'particleLists', lists_to_keep)
2164 path.add_module(mod)
2167 def inclusiveBtagReconstruction(upsilon_list_name, bsig_list_name, btag_list_name, input_lists_names, path):
2169 Reconstructs Btag from particles in given ParticleLists which do not share any final state particles (mdstSource) with Bsig.
2171 @param upsilon_list_name Name of the ParticleList to be filled with 'Upsilon(4S) -> B:sig anti-B:tag'
2172 @param bsig_list_name Name of the Bsig ParticleList
2173 @param btag_list_name Name of the Bsig ParticleList
2174 @param input_lists_names List of names of the ParticleLists which are used to reconstruct Btag from
2176 btag = register_module(
'InclusiveBtagReconstruction')
2177 btag.set_name(
'InclusiveBtagReconstruction_' + bsig_list_name)
2178 btag.param(
'upsilonListName', upsilon_list_name)
2179 btag.param(
'bsigListName', bsig_list_name)
2180 btag.param(
'btagListName', btag_list_name)
2181 btag.param(
'inputListsNames', input_lists_names)
2182 path.add_module(btag)
2185 def selectDaughters(particle_list_name, decay_string, path):
2187 Redefine the Daughters of a particle: select from decayString
2189 @param particle_list_name input particle list
2190 @param decay_string for selecting the Daughters to be preserved
2192 seld = register_module(
'SelectDaughters')
2193 seld.set_name(
'SelectDaughters_' + particle_list_name)
2194 seld.param(
'listName', particle_list_name)
2195 seld.param(
'decayString', decay_string)
2196 path.add_module(seld)
2199 def markDuplicate(particleList, prioritiseV0, path):
2201 Call DuplicateVertexMarker to find duplicate particles in a list and
2202 flag the ones that should be kept
2204 @param particleList input particle list
2205 @param prioritiseV0 if true, give V0s a higher priority
2207 markdup = register_module(
'DuplicateVertexMarker')
2208 markdup.param(
'particleList', particleList)
2209 markdup.param(
'prioritiseV0', prioritiseV0)
2210 path.add_module(markdup)
2213 PI0ETAVETO_COUNTER = 0
2216 def oldwritePi0EtaVeto(
2219 workingDirectory='.',
2220 pi0vetoname='Pi0_Prob',
2221 etavetoname='Eta_Prob',
2227 Give pi0/eta probability for hard photon.
2229 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.
2231 The current default weight files are optimised using MC9.
2232 The input variables are as below. Aliases are set to some variables during training.
2234 * M: pi0/eta candidates Invariant mass
2235 * lowE: soft photon energy in lab frame
2236 * cTheta: soft photon ECL cluster's polar angle
2237 * Zmva: soft photon output of MVA using Zernike moments of the cluster
2238 * minC2Hdist: soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2240 If you don't have weight files in your workingDirectory,
2241 these files are downloaded from database to your workingDirectory automatically.
2242 Please refer to analysis/examples/tutorials/B2A306-B02RhoGamma-withPi0EtaVeto.py
2243 about how to use this function.
2246 Please don't use following ParticleList names elsewhere:
2248 ``gamma:HARDPHOTON``, ``pi0:PI0VETO``, ``eta:ETAVETO``,
2249 ``gamma:PI0SOFT + str(PI0ETAVETO_COUNTER)``, ``gamma:ETASOFT + str(PI0ETAVETO_COUNTER)``
2251 Please don't use ``lowE``, ``cTheta``, ``Zmva``, ``minC2Hdist`` as alias elsewhere.
2253 @param particleList The input ParticleList
2254 @param decayString specify Particle to be added to the ParticleList
2255 @param workingDirectory The weight file directory
2256 @param downloadFlag whether download default weight files or not
2257 @param pi0vetoname extraInfo name of pi0 probability
2258 @param etavetoname extraInfo name of eta probability
2259 @param selection Selection criteria that Particle needs meet in order for for_each ROE path to continue
2260 @param path modules are added to this path
2266 global PI0ETAVETO_COUNTER
2268 if PI0ETAVETO_COUNTER == 0:
2269 from variables
import variables
2270 variables.addAlias(
'lowE',
'daughter(1,E)')
2271 variables.addAlias(
'cTheta',
'daughter(1,clusterTheta)')
2272 variables.addAlias(
'Zmva',
'daughter(1,clusterZernikeMVA)')
2273 variables.addAlias(
'minC2Tdist',
'daughter(1,minC2TDist)')
2274 variables.addAlias(
'cluNHits',
'daughter(1,clusterNHits)')
2275 variables.addAlias(
'E9E21',
'daughter(1,clusterE9E21)')
2277 PI0ETAVETO_COUNTER = PI0ETAVETO_COUNTER + 1
2279 roe_path = create_path()
2281 deadEndPath = create_path()
2283 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
2285 fillSignalSideParticleList(
'gamma:HARDPHOTON', decayString, path=roe_path)
2287 pi0softname =
'gamma:PI0SOFT'
2288 etasoftname =
'gamma:ETASOFT'
2289 softphoton1 = pi0softname + str(PI0ETAVETO_COUNTER)
2290 softphoton2 = etasoftname + str(PI0ETAVETO_COUNTER)
2294 '[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
2296 applyCuts(softphoton1,
'abs(clusterTiming)<120', path=roe_path)
2299 '[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
2301 applyCuts(softphoton2,
'abs(clusterTiming)<120', path=roe_path)
2303 reconstructDecay(
'pi0:PI0VETO -> gamma:HARDPHOTON ' + softphoton1,
'', path=roe_path)
2304 reconstructDecay(
'eta:ETAVETO -> gamma:HARDPHOTON ' + softphoton2,
'', path=roe_path)
2306 if not os.path.isdir(workingDirectory):
2307 os.mkdir(workingDirectory)
2308 B2INFO(
'oldwritePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
2310 if not os.path.isfile(workingDirectory +
'/pi0veto.root'):
2312 basf2_mva.download(
'Pi0VetoIdentifier', workingDirectory +
'/pi0veto.root')
2313 B2INFO(
'oldwritePi0EtaVeto: pi0veto.root has been downloaded from database to workingDirectory.')
2315 if not os.path.isfile(workingDirectory +
'/etaveto.root'):
2317 basf2_mva.download(
'EtaVetoIdentifier', workingDirectory +
'/etaveto.root')
2318 B2INFO(
'oldwritePi0EtaVeto: etaveto.root has been downloaded from database to workingDirectory.')
2320 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:PI0VETO'], extraInfoName=
'Pi0Veto',
2321 identifier=workingDirectory +
'/pi0veto.root')
2322 roe_path.add_module(
'MVAExpert', listNames=[
'eta:ETAVETO'], extraInfoName=
'EtaVeto',
2323 identifier=workingDirectory +
'/etaveto.root')
2325 rankByHighest(
'pi0:PI0VETO',
'extraInfo(Pi0Veto)', numBest=1, path=roe_path)
2326 rankByHighest(
'eta:ETAVETO',
'extraInfo(EtaVeto)', numBest=1, path=roe_path)
2328 variableToSignalSideExtraInfo(
'pi0:PI0VETO', {
'extraInfo(Pi0Veto)': pi0vetoname}, path=roe_path)
2329 variableToSignalSideExtraInfo(
'eta:ETAVETO', {
'extraInfo(EtaVeto)': etavetoname}, path=roe_path)
2331 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2334 def writePi0EtaVeto(
2337 workingDirectory='.',
2344 Give pi0/eta probability for hard photon.
2346 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.
2348 The current default weight files are optimised using MC12.
2350 The input variables of the mva training are:
2352 * M: pi0/eta candidates Invariant mass
2353 * daughter(1,E): soft photon energy in lab frame
2354 * daughter(1,clusterTheta): soft photon ECL cluster's polar angle
2355 * daughter(1,minC2TDist): soft photon distance from eclCluster to nearest point on nearest Helix at the ECL cylindrical radius
2356 * daughter(1,clusterZernikeMVA): soft photon output of MVA using Zernike moments of the cluster
2357 * daughter(1,clusterNHits): soft photon total crystal weights sum(w_i) with w_i<=1
2358 * daughter(1,clusterE9E21): soft photon ratio of energies in inner 3x3 crystals and 5x5 crystals without corners
2359 * cosHelicityAngleMomentum: pi0/eta candidates cosHelicityAngleMomentum
2361 If you don't have weight files in your workingDirectory,
2362 these files are downloaded from the database to your workingDirectory automatically.
2364 The following strings are available for mode:
2366 * standard: loose energy cut and no clusterNHits cut are applied to soft photon
2367 * tight: tight energy cut and no clusterNHits cut are applied to soft photon
2368 * cluster: loose energy cut and clusterNHits cut are applied to soft photon
2369 * both: tight energy cut and clusterNHits cut are applied to soft photon
2371 One can obtain the result of pi0/eta veto from `pi0Prob`/`etaProb`
2374 Please don't use following ParticleList names elsewhere:
2376 ``gamma:HardPhoton``,
2377 ``gamma:Pi0Soft + ListName + '_' + particleList.replace(':', '_')``,
2378 ``gamma:EtaSoft + ListName + '_' + particleList.replace(':', '_')``,
2379 ``pi0:EtaVeto + ListName``,
2380 ``eta:EtaVeto + ListName``
2382 @param particleList the input ParticleList
2383 @param decayString specify Particle to be added to the ParticleList
2384 @param workingDirectory the weight file directory
2385 @param mode choose one mode out of 'standard', 'tight', 'cluster' and 'both'
2386 @param downloadFlag whether download default weight files or not
2387 @param selection selection criteria that Particle needs meet in order for for_each ROE path to continue
2388 @param path modules are added to this path
2394 roe_path = create_path()
2395 deadEndPath = create_path()
2396 signalSideParticleFilter(particleList, selection, roe_path, deadEndPath)
2397 fillSignalSideParticleList(
'gamma:HardPhoton', decayString, path=roe_path)
2398 if not os.path.isdir(workingDirectory):
2399 os.mkdir(workingDirectory)
2400 B2INFO(
'writePi0EtaVeto: ' + workingDirectory +
' has been created as workingDirectory.')
2402 dictListName = {
'standard':
'Origin',
2403 'tight':
'TightEnergyThreshold',
2404 'cluster':
'LargeClusterSize',
2405 'both':
'TightEnrgyThresholdAndLargeClusterSize'}
2407 dictPi0EnergyCut = {
'standard':
'[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
2408 'tight':
'[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]',
2409 'cluster':
'[clusterReg==1 and E>0.025] or [clusterReg==2 and E>0.02] or [clusterReg==3 and E>0.02]',
2410 'both':
'[clusterReg==1 and E>0.03] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.04]'}
2412 dictEtaEnergyCut = {
'standard':
'[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
2413 'tight':
'[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]',
2414 'cluster':
'[clusterReg==1 and E>0.035] or [clusterReg==2 and E>0.03] or [clusterReg==3 and E>0.03]',
2415 'both':
'[clusterReg==1 and E>0.06] or [clusterReg==2 and E>0.06] or [clusterReg==3 and E>0.06]'}
2417 dictTimingAndNHitsCut = {
'standard':
'abs(clusterTiming)<clusterErrorTiming',
2418 'tight':
'abs(clusterTiming)<clusterErrorTiming',
2419 'cluster':
'abs(clusterTiming)<clusterErrorTiming and clusterNHits >= 2',
2420 'both':
'abs(clusterTiming)<clusterErrorTiming and clusterNHits >= 2'}
2422 dictPi0WeightFileName = {
'standard':
'pi0veto_origin.root',
2423 'tight':
'pi0veto_tight.root',
2424 'cluster':
'pi0veto_cluster.root',
2425 'both':
'pi0veto_both.root'}
2427 dictEtaWeightFileName = {
'standard':
'etaveto_origin.root',
2428 'tight':
'etaveto_tight.root',
2429 'cluster':
'etaveto_cluster.root',
2430 'both':
'etaveto_both.root'}
2432 dictPi0PayloadName = {
'standard':
'Pi0VetoIdentifierStandard',
2433 'tight':
'Pi0VetoIdentifierWithHigherEnergyThreshold',
2434 'cluster':
'Pi0VetoIdentifierWithLargerClusterSize',
2435 'both':
'Pi0VetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
2437 dictEtaPayloadName = {
'standard':
'EtaVetoIdentifierStandard',
2438 'tight':
'EtaVetoIdentifierWithHigherEnergyThreshold',
2439 'cluster':
'EtaVetoIdentifierWithLargerClusterSize',
2440 'both':
'EtaVetoIdentifierWithHigherEnergyThresholdAndLargerClusterSize'}
2442 dictPi0ExtraInfoName = {
'standard':
'Pi0VetoOrigin',
2443 'tight':
'Pi0VetoTightEnergyThreshold',
2444 'cluster':
'Pi0VetoLargeClusterSize',
2445 'both':
'Pi0VetoTightEnergyThresholdAndLargeClusterSize'}
2447 dictEtaExtraInfoName = {
'standard':
'EtaVetoOrigin',
2448 'tight':
'EtaVetoTightEnergyThreshold',
2449 'cluster':
'EtaVetoLargeClusterSize',
2450 'both':
'EtaVetoTightEnergyThresholdAndLargeClusterSize'}
2452 dictPi0ExtraInfoRename = {
'standard':
'Pi0ProbOrigin',
2453 'tight':
'Pi0ProbTightEnergyThreshold',
2454 'cluster':
'Pi0ProbLargeClusterSize',
2455 'both':
'Pi0ProbTightEnergyThresholdAndLargeClusterSize'}
2457 dictEtaExtraInfoRename = {
'standard':
'EtaProbOrigin',
2458 'tight':
'EtaProbTightEnergyThreshold',
2459 'cluster':
'EtaProbLargeClusterSize',
2460 'both':
'EtaProbTightEnergyThresholdAndLargeClusterSize'}
2462 ListName = dictListName[mode]
2463 Pi0EnergyCut = dictPi0EnergyCut[mode]
2464 EtaEnergyCut = dictEtaEnergyCut[mode]
2465 TimingAndNHitsCut = dictTimingAndNHitsCut[mode]
2466 Pi0WeightFileName = dictPi0WeightFileName[mode]
2467 EtaWeightFileName = dictEtaWeightFileName[mode]
2468 Pi0PayloadName = dictPi0PayloadName[mode]
2469 EtaPayloadName = dictEtaPayloadName[mode]
2470 Pi0ExtraInfoName = dictPi0ExtraInfoName[mode]
2471 EtaExtraInfoName = dictEtaExtraInfoName[mode]
2472 Pi0ExtraInfoRename = dictPi0ExtraInfoRename[mode]
2473 EtaExtraInfoRename = dictEtaExtraInfoRename[mode]
2479 pi0soft =
'gamma:Pi0Soft' + ListName +
'_' + particleList.replace(
':',
'_')
2481 fillParticleList(pi0soft, Pi0EnergyCut, path=roe_path)
2483 applyCuts(pi0soft, TimingAndNHitsCut, path=roe_path)
2485 reconstructDecay(
'pi0:Pi0Veto' + ListName +
' -> gamma:HardPhoton ' + pi0soft,
'', path=roe_path)
2488 if not os.path.isfile(workingDirectory +
'/' + Pi0WeightFileName):
2490 basf2_mva.download(Pi0PayloadName, workingDirectory +
'/' + Pi0WeightFileName)
2491 B2INFO(
'writePi0EtaVeto: ' + Pi0WeightFileName +
' has been downloaded from database to workingDirectory.')
2493 roe_path.add_module(
'MVAExpert', listNames=[
'pi0:Pi0Veto' + ListName],
2494 extraInfoName=Pi0ExtraInfoName, identifier=workingDirectory +
'/' + Pi0WeightFileName)
2496 rankByHighest(
'pi0:Pi0Veto' + ListName,
'extraInfo(' + Pi0ExtraInfoName +
')', numBest=1, path=roe_path)
2498 variableToSignalSideExtraInfo(
'pi0:Pi0Veto' + ListName,
2499 {
'extraInfo(' + Pi0ExtraInfoName +
')': Pi0ExtraInfoRename}, path=roe_path)
2504 etasoft =
'gamma:EtaSoft' + ListName +
'_' + particleList.replace(
':',
'_')
2505 fillParticleList(etasoft, EtaEnergyCut, path=roe_path)
2506 applyCuts(etasoft, TimingAndNHitsCut, path=roe_path)
2507 reconstructDecay(
'eta:EtaVeto' + ListName +
' -> gamma:HardPhoton ' + etasoft,
'', path=roe_path)
2508 if not os.path.isfile(workingDirectory +
'/' + EtaWeightFileName):
2510 basf2_mva.download(EtaPayloadName, workingDirectory +
'/' + EtaWeightFileName)
2511 B2INFO(
'writePi0EtaVeto: ' + EtaWeightFileName +
'has been downloaded from database to workingDirectory.')
2512 roe_path.add_module(
'MVAExpert', listNames=[
'eta:EtaVeto' + ListName],
2513 extraInfoName=EtaExtraInfoName, identifier=workingDirectory +
'/' + EtaWeightFileName)
2514 rankByHighest(
'eta:EtaVeto' + ListName,
'extraInfo(' + EtaExtraInfoName +
')', numBest=1, path=roe_path)
2515 variableToSignalSideExtraInfo(
'eta:EtaVeto' + ListName,
2516 {
'extraInfo(' + EtaExtraInfoName +
')': EtaExtraInfoRename}, path=roe_path)
2518 path.for_each(
'RestOfEvent',
'RestOfEvents', roe_path)
2521 def buildEventKinematics(inputListNames=[], default_cleanup=True,
2522 chargedPIDPriors=None, fillWithMostLikely=False, path=None):
2524 Calculates the global kinematics of the event (visible energy, missing momentum, missing mass...)
2525 using ParticleLists provided. If no ParticleList is provided, default ParticleLists are used
2526 (all track and all hits in ECL without associated track).
2528 The visible energy missing values are
2529 stored in a EventKinematics dataobject.
2531 @param inputListNames list of ParticleLists used to calculate the global event kinematics.
2532 If the list is empty, default ParticleLists pi+:evtkin and gamma:evtkin are filled.
2533 @param fillWithMostLikely if True, the module uses the most likely particle mass hypothesis for charged particles
2534 according to the PID likelihood and the option inputListNames will be ignored.
2535 @param chargedPIDPriors The prior PID fractions, that are used to regulate
2536 amount of certain charged particle species, should be a list of
2537 six floats if not None. The order of particle types is
2538 the following: [e-, mu-, pi-, K-, p+, d+]
2539 @param default_cleanup if True and either inputListNames empty or fillWithMostLikely True, default clean up cuts are applied
2540 @param path modules are added to this path
2542 trackCuts =
'pt > 0.1'
2543 trackCuts +=
' and thetaInCDCAcceptance'
2544 trackCuts +=
' and abs(dz) < 3'
2545 trackCuts +=
' and dr < 0.5'
2547 gammaCuts =
'E > 0.05'
2548 gammaCuts +=
' and thetaInCDCAcceptance'
2550 if fillWithMostLikely:
2551 from stdCharged
import stdMostLikely
2552 stdMostLikely(chargedPIDPriors,
'_evtkin', path=path)
2553 inputListNames = [
'%s:mostlikely_evtkin' % ptype
for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']]
2554 fillParticleList(
'gamma:evtkin',
'', path=path)
2555 inputListNames += [
'gamma:evtkin']
2557 B2INFO(
"Using default cleanup in EventKinematics module.")
2558 for ptype
in [
'K+',
'p+',
'e+',
'mu+',
'pi+']:
2559 applyCuts(f
'{ptype}:mostlikely_evtkin', trackCuts, path=path)
2560 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
2562 B2INFO(
"No cleanup in EventKinematics module.")
2563 if not inputListNames:
2564 B2INFO(
"Creating particle lists pi+:evtkin and gamma:evtkin to get the global kinematics of the event.")
2565 fillParticleList(
'pi+:evtkin',
'', path=path)
2566 fillParticleList(
'gamma:evtkin',
'', path=path)
2567 particleLists = [
'pi+:evtkin',
'gamma:evtkin']
2569 B2INFO(
"Using default cleanup in EventKinematics module.")
2570 applyCuts(
'pi+:evtkin', trackCuts, path=path)
2571 applyCuts(
'gamma:evtkin', gammaCuts, path=path)
2573 B2INFO(
"No cleanup in EventKinematics module.")
2575 particleLists = inputListNames
2577 eventKinematicsModule = register_module(
'EventKinematics')
2578 eventKinematicsModule.set_name(
'EventKinematics_')
2579 eventKinematicsModule.param(
'particleLists', particleLists)
2580 path.add_module(eventKinematicsModule)
2583 def buildEventShape(inputListNames=[],
2584 default_cleanup=True,
2589 harmonicMoments=True,
2593 checkForDuplicates=False,
2596 Calculates the event-level shape quantities (thrust, sphericity, Fox-Wolfram moments...)
2597 using the particles in the lists provided by the user. If no particle list is provided,
2598 the function will internally create a list of good tracks and a list of good photons
2599 with (optionally) minimal quality cuts.
2602 The results of the calculation are then stored into the EventShapeContainer dataobject,
2603 and are accessible using the variables of the EventShape group.
2605 The user can switch the calculation of certain quantities on or off to save computing
2606 time. By default the calculation of the high-order moments (5-8) is turned off.
2607 Switching off an option will make the corresponding variables not available.
2610 The user can provide as many particle lists
2611 as needed, using also combined particles, but the function will always assume that
2612 the lists are independent.
2613 If the lists provided by the user contain several times the same track (either with
2614 different mass hypothesis, or once as an independent particle and once as daughter of a
2615 combined particle) the results won't be reliable.
2616 A basic check for duplicates is available setting the checkForDuplicate flags,
2617 but is usually quite time consuming.
2620 @param inputListNames List of ParticleLists used to calculate the
2621 event shape variables. If the list is empty the default
2622 particleLists pi+:evtshape and gamma:evtshape are filled.
2623 @param default_cleanup If True, applies standard cuts on pt and cosTheta when
2624 defining the internal lists. This option is ignored if the
2625 particleLists are provided by the user.
2626 @param path Path to append the eventShape modules to.
2627 @param thrust Enables the calculation of thrust-related quantities (CLEO
2628 cones, Harmonic moments, jets).
2629 @param collisionAxis Enables the calculation of the quantities related to the
2631 @param foxWolfram Enables the calculation of the Fox-Wolfram moments.
2632 @param harmonicMoments Enables the calculation of the Harmonic moments with respect
2633 to both the thrust axis and, if collisionAxis = True, the collision axis.
2634 @param allMoments If True, calculates also the FW and harmonic moments from order
2635 5 to 8 instead of the low-order ones only.
2636 @param cleoCones Enables the calculation of the CLEO cones with respect to both the thrust
2637 axis and, if collisionAxis = True, the collision axis.
2638 @param jets Enables the calculation of the hemisphere momenta and masses.
2639 Requires thrust = True.
2640 @param sphericity Enables the calculation of the sphericity-related quantities.
2641 @param checkForDuplicates Perform a check for duplicate particles before adding them. This option
2642 is quite time consuming, instead of using it consider sanitizing
2643 the lists you are passing to the function.
2645 if not inputListNames:
2646 B2INFO(
"Creating particle lists pi+:evtshape and gamma:evtshape to get the event shape variables.")
2647 fillParticleList(
'pi+:evtshape',
'', path=path)
2648 fillParticleList(
'gamma:evtshape',
'', path=path)
2649 particleLists = [
'pi+:evtshape',
'gamma:evtshape']
2652 B2INFO(
"Applying standard cuts")
2653 trackCuts =
'pt > 0.1'
2654 trackCuts +=
' and thetaInCDCAcceptance'
2655 trackCuts +=
' and abs(dz) < 3.0'
2656 trackCuts +=
' and dr < 0.5'
2657 applyCuts(
'pi+:evtshape', trackCuts, path=path)
2659 gammaCuts =
'E > 0.05'
2660 gammaCuts +=
' and thetaInCDCAcceptance'
2661 applyCuts(
'gamma:evtshape', gammaCuts, path=path)
2663 B2WARNING(
"Creating the default lists with no cleanup.")
2665 particleLists = inputListNames
2667 eventShapeModule = register_module(
'EventShapeCalculator')
2668 eventShapeModule.set_name(
'EventShape')
2669 eventShapeModule.param(
'particleListNames', particleLists)
2670 eventShapeModule.param(
'enableAllMoments', allMoments)
2671 eventShapeModule.param(
'enableCleoCones', cleoCones)
2672 eventShapeModule.param(
'enableCollisionAxis', collisionAxis)
2673 eventShapeModule.param(
'enableFoxWolfram', foxWolfram)
2674 eventShapeModule.param(
'enableJets', jets)
2675 eventShapeModule.param(
'enableHarmonicMoments', harmonicMoments)
2676 eventShapeModule.param(
'enableSphericity', sphericity)
2677 eventShapeModule.param(
'enableThrust', thrust)
2678 eventShapeModule.param(
'checkForDuplicates', checkForDuplicates)
2680 path.add_module(eventShapeModule)
2683 def labelTauPairMC(printDecayInfo=False, path=None):
2685 Search tau leptons into the MC information of the event. If confirms it's a generated tau pair decay,
2686 labels the decay generated of the positive and negative leptons using the ID of KKMC tau decay table.
2688 @param printDecayInfo: If true, prints ID and prong of each tau lepton in the event.
2689 @param path: module is added to this path
2691 tauDecayMarker = register_module(
'TauDecayMarker')
2692 tauDecayMarker.set_name(
'TauDecayMarker_')
2694 path.add_module(tauDecayMarker, printDecayInfo=printDecayInfo)
2697 def tagCurlTracks(particleLists,
2706 The cut selector is not calibrated with Belle II data and should not be used without extensive study.
2708 Identifies curl tracks and tags them with extraInfo(isCurl=1) for later removal.
2709 For Belle data with a `b2bii` analysis the available cut based selection is described in `BN1079`_.
2711 .. _BN1079: https://belle.kek.jp/secured/belle_note/gn1079/bn1079.pdf
2714 The module loops over all particles in a given list that meet the preselection **ptCut** and assigns them to
2715 bundles based on the response of the chosen **selector** and the required minimum response set by the
2716 **responseCut**. Once all particles are assigned they are ranked by 25dr^2+dz^2. All but the lowest are tagged
2717 with extraInfo(isCurl=1) to allow for later removal by cutting the list or removing these from ROE as
2721 @param particleLists: list of particle lists to check for curls.
2722 @param mcTruth: bool flag to additionally assign particles with extraInfo(isTruthCurl) and
2723 extraInfo(truthBundleSize). To calculate these particles are assigned to bundles by their
2724 genParticleIndex then ranked and tagged as normal.
2725 @param responseCut: float min classifier response that considers two tracks to come from the same particle.
2726 Note 'cut' selector is binary 0/1.
2727 @param selectorType: string name of selector to use. The available options are 'cut' and 'mva'.
2728 It is strongly recommended to used the 'mva' selection. The 'cut' selection
2729 is based on BN1079 and is only calibrated for Belle data.
2730 @param ptCut: pre-selection cut on transverse momentum.
2731 @param train: flag to set training mode if selector has a training mode (mva).
2732 @param path: module is added to this path.
2738 if (
not isinstance(particleLists, list)):
2739 particleLists = [particleLists]
2741 curlTagger = register_module(
'CurlTagger')
2742 curlTagger.set_name(
'CurlTagger_')
2743 curlTagger.param(
'particleLists', particleLists)
2744 curlTagger.param(
'belle', belle)
2745 curlTagger.param(
'mcTruth', mcTruth)
2746 curlTagger.param(
'responseCut', responseCut)
2747 curlTagger.param(
'selectorType', selectorType)
2748 curlTagger.param(
'ptCut', ptCut)
2749 curlTagger.param(
'train', train)
2751 path.add_module(curlTagger)
2754 def applyChargedPidMVA(particleLists, path, trainingMode, binaryHypoPDGCodes=(0, 0)):
2756 Use an MVA to perform particle identification for charged stable particles, using the `ChargedPidMVA` module.
2758 The module decorates Particle objects in the input ParticleList(s) with variables
2759 containing the appropriate MVA score, which can be used to select candidates by placing a cut on it.
2762 The MVA algorithm used is a gradient boosted decision tree (**TMVA 4.2.1**, **ROOT 6.14/06**).
2764 The module can perform either 'binary' PID between input S, B particle mass hypotheses according to the following scheme:
2766 - e (11) vs. pi (211)
2767 - mu (13) vs. pi (211)
2768 - pi (211) vs. K (321)
2769 - K (321) vs. pi (211)
2770 - p (2212) vs. pi (211)
2771 - d (1000010020) vs pi (211)
2773 , or 'global' PID, namely "one-vs-others" separation. The latter makes use of an MVA algorithm trained in multi-class mode,
2774 and it's the default behaviour.
2777 Currently the MVA is charge-agnostic, i.e. the training is not done independently for +/- charged particles.
2780 particleLists (list(str)): list of names of ParticleList objects for charged stable particles.
2781 The charge-conjugate ParticleLists will be also processed automatically.
2782 path (basf2.Path): the module is added to this path.
2783 trainingMode (``Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode``): enum identifier of the training mode.
2784 Needed to pick up the correct payload from the DB. Available choices:
2786 * c_Classification=0
2788 * c_ECL_Classification=2
2789 * c_ECL_Multiclass=3
2790 * c_PSD_Classification=4
2791 * c_PSD_Multiclass=5
2792 * c_ECL_PSD_Classification=6
2793 * c_ECL_PSD_Multiclass=7
2795 binaryHypoPDGCodes (tuple(int, int), ``optional``): the pdgIds of the signal, background mass hypothesis.
2796 Required only for binary PID mode.
2799 from ROOT
import Belle2
2801 plSet = set(particleLists)
2805 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_Classification:
2806 {
"mode":
"Classification",
"detector":
"ALL"},
2807 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_Multiclass:
2808 {
"mode":
"Multiclass",
"detector":
"ALL"},
2809 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_ECL_Classification:
2810 {
"mode":
"ECL_Classification",
"detector":
"ECL"},
2811 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_ECL_Multiclass:
2812 {
"mode":
"ECL_Multiclass",
"detector":
"ECL"},
2813 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_PSD_Classification:
2814 {
"mode":
"PSD_Classification",
"detector":
"ALL"},
2815 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_PSD_Multiclass:
2816 {
"mode":
"PSD_Multiclass",
"detector":
"ALL"},
2817 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_ECL_PSD_Classification:
2818 {
"mode":
"ECL_PSD_Classification",
"detector":
"ECL"},
2819 Belle2.ChargedPidMVAWeights.ChargedPidMVATrainingMode.c_ECL_PSD_Multiclass:
2820 {
"mode":
"ECL_PSD_Multiclass",
"detector":
"ECL"},
2823 if payloadNames.get(trainingMode)
is None:
2824 B2FATAL(
"The chosen training mode integer identifier:\n", trainingMode,
2825 "\nis not supported. Please choose among the following:\n",
2826 "\n".join(f
"{key}:{val.get('mode')}" for key, val
in sorted(payloadNames.items())))
2828 mode = payloadNames.get(trainingMode).get(
"mode")
2829 detector = payloadNames.get(trainingMode).get(
"detector")
2831 payloadName = f
"ChargedPidMVAWeights_{mode}"
2833 if binaryHypoPDGCodes == (0, 0):
2836 chargedpid = register_module(
"ChargedPidMVAMulticlass")
2837 chargedpid.set_name(f
"ChargedPidMVAMulticlass_{mode}")
2844 (Belle2.Const.electron.getPDGCode(), Belle2.Const.pion.getPDGCode()),
2845 (Belle2.Const.muon.getPDGCode(), Belle2.Const.pion.getPDGCode()),
2846 (Belle2.Const.pion.getPDGCode(), Belle2.Const.kaon.getPDGCode()),
2847 (Belle2.Const.kaon.getPDGCode(), Belle2.Const.pion.getPDGCode()),
2848 (Belle2.Const.proton.getPDGCode(), Belle2.Const.pion.getPDGCode()),
2849 (Belle2.Const.deuteron.getPDGCode(), Belle2.Const.pion.getPDGCode())
2852 if binaryHypoPDGCodes
not in binaryOpts:
2853 B2FATAL(
"No charged pid MVA was trained to separate ", binaryHypoPDGCodes[0],
" vs. ", binaryHypoPDGCodes[1],
2854 ". Please choose among the following pairs:\n",
2855 "\n".join(f
"{opt[0]} vs. {opt[1]}" for opt
in binaryOpts))
2857 chargedpid = register_module(
"ChargedPidMVA")
2858 chargedpid.set_name(f
"ChargedPidMVA_{binaryHypoPDGCodes[0]}_vs_{binaryHypoPDGCodes[1]}_{mode}")
2859 chargedpid.param(
"sigHypoPDGCode", binaryHypoPDGCodes[0])
2860 chargedpid.param(
"bkgHypoPDGCode", binaryHypoPDGCodes[1])
2862 chargedpid.param(
"particleLists", list(plSet))
2864 chargedpid.param(
"payloadName", payloadName)
2867 if detector ==
"ECL":
2868 chargedpid.param(
"useECLOnlyTraining",
True)
2870 path.add_module(chargedpid)
2873 def calculateDistance(list_name, decay_string, mode='vertextrack', path=None):
2875 Calculates distance between two vertices, distance of closest approach between a vertex and a track,\
2876 distance of closest approach between a vertex and btube. For track, this calculation ignores track curvature,\
2877 it's negligible for small distances.The user should use extraInfo(CalculatedDistance)\
2878 to get it. A full example steering file is at analysis/tests/test_DistanceCalculator.py
2881 >>> from modularAnalysis import calculateDistance
2882 >>>calculateDistance('list_name', 'decay_string', "mode", path=user_path)
2884 @param list_name name of the input ParticleList
2885 @param decay_string select particles between the distance of closest approch will be calculated
2886 @param mode Specifies how the distance is calculated
2887 vertextrack: calculate the distance of closest appreach between a track and a\
2888 vertex, taking the first candidate as vertex, default
2889 trackvertex: calculate the distance of closest appreach between a track and a\
2890 vertex, taking the first candidate as track
2891 2tracks: calculates the distance of closest appreach between two tracks
2892 2vertices: calculates the distance between two vertices
2893 vertexbtube: calculates the distance of closest appreach between a vertex and btube
2894 trackbtube: calculates the distance of closest appreach between a track and btube
2895 @param path modules are added to this path
2899 dist_mod = register_module(
'DistanceCalculator')
2901 dist_mod.set_name(
'DistanceCalculator_' + list_name)
2902 dist_mod.param(
'listName', list_name)
2903 dist_mod.param(
'decayString', decay_string)
2904 dist_mod.param(
'mode', mode)
2905 path.add_module(dist_mod)
2908 def addInclusiveDstarReconstruction(inputPionList, outputDstarList, slowPionCut, path):
2910 Adds the InclusiveDstarReconstruction module to the given path.
2911 This module creates a D* particle list by estimating the D* four momenta
2912 from slow pions, specified by a given cut. The D* energy is approximated
2913 as E(D*) = m(D*)/(m(D*) - m(D)) * E(pi). The absolute value of the D*
2914 momentum is calculated using the D* PDG mass and the direction is collinear
2915 to the slow pion direction. The charge of the given pion list has to be consistent
2918 @param inputPionList Name of the input pion particle list
2919 @param outputDstarList Name of the output D* particle list
2920 @param slowPionCut Cut applied to the pion list to identify slow pions
2921 @param path the module is added to this path
2923 incl_dstar = register_module(
"InclusiveDstarReconstruction")
2924 incl_dstar.param(
"pionListName", inputPionList)
2925 incl_dstar.param(
"DstarListName", outputDstarList)
2926 incl_dstar.param(
"slowPionCut", slowPionCut)
2927 path.add_module(incl_dstar)
2930 def getAnalysisGlobaltag():
2932 Returns a string containing the name of the latest and recommended analysis globaltag.
2934 tags = subprocess.check_output([
'b2conditionsdb-recommend',
'--oneline']).decode(
'UTF-8').rstrip().split(
' ')
2937 if tag.startswith(
'analysis_tools'):
2942 if __name__ ==
'__main__':
2944 pretty_print_module(__name__,
"modularAnalysis")