##########################################################################
# basf2 (Belle II Analysis Software Framework) #
# Author: The Belle II Collaboration #
# #
# See git log for contributors and copyright holders. #
# This file is licensed under LGPL-3.0, see LICENSE.md. #
##########################################################################
__all__ = ["graFEI", "lcaSaver"]
from grafei.modules.GraFEIModule import GraFEIModule
from grafei.modules.LCASaverModule import LCASaverModule
import modularAnalysis as ma
import basf2 as b2
[docs]
def graFEI(
list_name,
path,
particle_lists=None,
store_mc_truth=False,
cfg_path=None,
param_file=None,
sig_side_lcas=None,
sig_side_masses=None,
gpu=False,
payload_config_name="graFEIConfigFile",
payload_model_name="graFEIModelFile",
):
"""
Wrapper function to add the GraFEIModule to the path and perform other actions behind the scenes.
Applies graFEI model to a (list of) particle list(s) in basf2.
GraFEI information is stored as eventExtraInfos.
.. note::
``list_name`` should always be provided. This is the name of the particle list to be given as input to the graFEI.
If ``list_name`` refers to an existing particle list, it is used as input to the model.
If also a list of final state particle lists is provided in ``particle_lists``, these are combined to form
a new list called ``list_name`` (if ``list_name`` already exists an error is thrown).
If ``particle_list`` is provided, the mass hypotheses of final state particles are updated to match graFEI predictions.
Args:
list_name (str): Name of particle list given as input to the model.
path (basf2.Path): Module is added to this path.
particle_lists (list): List of particle lists. If provided, these are combined to form ``list_name``.
store_mc_truth (bool): Whether to store MC truth information.
cfg_path (str): Path to config file. If `None` the config file in the global tag is used.
param_file (str): Path to parameter file containing the model. If `None` the parameter file in the global tag is used.
sig_side_lcas (list): List containing LCAS matrix of signal-side.
sig_side_masses (list): List containing mass hypotheses of signal-side.
gpu (bool): Whether to run on a GPU.
payload_config_name (str): Name of config file payload. The default should be kept, except in basf2 examples.
payload_model_name (str): Name of model file payload. The default should be kept, except in basf2 examples.
Returns:
list: List of graFEI variables.
"""
if particle_lists:
ma.combineAllParticles(particle_lists, list_name, path=path)
if store_mc_truth:
ma.matchMCTruth(list_name, path=path)
ma.fillParticleListFromMC("Upsilon(4S):MC", "", path=path)
ma.fillParticleListFromMC("B0:MC", "", path=path)
ma.fillParticleListFromMC("B+:MC", "", path=path)
graFEI = GraFEIModule(
list_name,
cfg_path=cfg_path,
param_file=param_file,
sig_side_lcas=sig_side_lcas,
sig_side_masses=sig_side_masses,
gpu=gpu,
payload_config_name=payload_config_name,
payload_model_name=payload_model_name,
)
path.add_module(graFEI)
graFEI_vars = [
"graFEI_probEdgeProd",
"graFEI_probEdgeMean",
"graFEI_probEdgeGeom",
"graFEI_validTree",
"graFEI_goodEvent",
"graFEI_nFSP",
"graFEI_nCharged_preFit",
"graFEI_nElectrons_preFit",
"graFEI_nMuons_preFit",
"graFEI_nPions_preFit",
"graFEI_nKaons_preFit",
"graFEI_nProtons_preFit",
"graFEI_nLeptons_preFit",
"graFEI_nPhotons_preFit",
"graFEI_nOthers_preFit",
"graFEI_nCharged_postFit",
"graFEI_nElectrons_postFit",
"graFEI_nMuons_postFit",
"graFEI_nPions_postFit",
"graFEI_nKaons_postFit",
"graFEI_nProtons_postFit",
"graFEI_nLeptons_postFit",
"graFEI_nPhotons_postFit",
"graFEI_nOthers_postFit",
"graFEI_nPredictedUnmatched",
"graFEI_nPredictedUnmatched_noPhotons",
]
if store_mc_truth:
graFEI_vars.extend(
[
"graFEI_truth_perfectLCA",
"graFEI_truth_perfectMasses",
"graFEI_truth_perfectEvent",
"graFEI_truth_isSemileptonic",
"graFEI_truth_nFSP",
"graFEI_truth_nPhotons",
"graFEI_truth_nElectrons",
"graFEI_truth_nMuons",
"graFEI_truth_nPions",
"graFEI_truth_nKaons",
"graFEI_truth_nProtons",
"graFEI_truth_nOthers",
]
)
ma.variablesToEventExtraInfo(
list_name,
dict((f"extraInfo({var})", var) for var in graFEI_vars),
path=path,
)
# Update mass hypotheses
if particle_lists:
charged_lists = [ls for ls in particle_lists if "gamma:" not in ls]
photon_lists = [ls for ls in particle_lists if "gamma:" in ls]
hypotheses = { # PDG code and graFEI class for each mass hypothesis
"K": (321, 4),
"pi": (211, 3),
"mu": (13, 2),
"e": (11, 1),
"p": (2212, 5),
}
for newHyp in hypotheses: # Loop over all possible final mass hypotheses
newPDG = hypotheses[newHyp][0]
newClass = hypotheses[newHyp][1]
final_lists = []
for oldList in charged_lists: # Loop over all charged particle lists
ma.cutAndCopyList( # Retain only particles with predicted mass hypothesis equal to `newClass`
f"{oldList}_to_{newHyp}_",
oldList,
f"extraInfo(graFEI_massHypothesis) == {newClass}",
path=path,
)
ma.updateMassHypothesis( # Update basf2 mass hypothesis
f"{oldList}_to_{newHyp}_", newPDG, path=path
)
label = oldList[oldList.find(':')+1:]
oldHyp = oldList[:oldList.find(':')-1]
final_lists.append(f"{newHyp}+:{label}_to_{newHyp}__converted_from_{oldHyp}")
ma.copyLists( # Merge all temporary lists into final `newHyp` list
f"{newHyp}+:graFEI",
final_lists,
writeOut=True,
path=path,
)
# Take care of photons
if len(photon_lists) > 0:
ma.cutAndCopyList(
"gamma:graFEI",
photon_lists[0],
"extraInfo(graFEI_massHypothesis) == 6",
writeOut=True,
path=path,
)
elif len(photon_lists) == 0:
b2.B2WARNING("grafei.graFEI You did not define a photon input list. Therefore you don't have any as output.")
if len(photon_lists) > 1:
b2.B2WARNING("grafei.graFEI You defined more than one photon input list. Using the first one.")
return graFEI_vars
[docs]
def lcaSaver(
particle_lists,
features,
mcparticle_list,
output_file,
path,
):
"""
Wrapper function to add the LCASaverModule to the path.
Save Lowest Common Ancestor matrix of each MC Particle in the given list.
Args:
particle_lists (list): Name of particle lists to save features of.
features (list): List of features to save for each particle.
mcparticle_list (str): Name of particle list to build LCAs from (used as root).
output_file (str): Path to output file to save.
path (basf2.Path): Module is added to this path.
"""
root_saver_module = LCASaverModule(
particle_lists=particle_lists,
features=features,
mcparticle_list=mcparticle_list,
output_file=output_file,
)
path.add_module(root_saver_module)
print(
r"""
____ ____ _ ____ ____ _
| _ |__| /_\ |___ |___ |
|__| | \ / \ | |___ |
o
/ \
/ \ x-----x _ _
/ \ |-----\ |\ /| |-----\ |0 1 3 3 5|
o \ |----- \ | \ / | |----- \ |1 0 3 3 5|
/ \ \ |----- / | x | |----- / |3 3 0 1 5|
/ \ \ |-----/ | / \ | |-----/ |3 3 1 0 5|
/ \ \ |/ \| |5 5 5 5 0|
o o \ x-----x  ̄  ̄
/ \ / \ \
x x x x x
Authors: Jacopo Cerasoli, Giulio Dujany, Lucas Martel, Corentin Santos. 2022 - 2024
Model description: https://indico.cern.ch/event/1106990/papers/4996235/files/12252-ACAT_2022_proceedings.pdf
Based on the work of Kahn et al: https://iopscience.iop.org/article/10.1088/2632-2153/ac8de0
Please consider citing both articles.
Code adapted from https://github.com/Helmholtz-AI-Energy/BaumBauen
"""
)