#!/usr/bin/env python3
"""
.. module:: particlesLoader
:synopsis: Loads the file defining the list of BSM particles to be used.
.. moduleauthor:: Andre Lessa <lessa.a.p@gmail.com>
"""
import os
import sys
from smodels.base.exceptions import SModelSBaseError as SModelSError
from smodels.base.smodelsLogging import logger
from smodels.base.particle import Particle
from smodels.installation import installDirectory
from smodels.share.models.SMparticles import SMList
from importlib import import_module
[docs]def getParticlesFromSLHA(slhafile):
"""
Defines BSM particles from the QNUMBERS blocks in the slhafile.
:param slhafile: Path to the SLHA file
:return: List with Particle objects
"""
checkDirs = [os.path.join(installDirectory(), "smodels", "share", "models"), installDirectory(),
os.path.join(installDirectory(), "smodels")]
# Create a list of SM PDGs, so if a QNUMBERS block for a SM particle
# is present, it will be ignored.
SMpdgs = set()
for ptc in SMList:
if isinstance(ptc.pdg,(int,float)):
SMpdgs.add(int(abs(ptc.pdg)))
else:
for pdg in ptc.pdg:
SMpdgs.add(int(abs(pdg)))
SMpdgs = list(SMpdgs)
filename = slhafile
#If file does not exist, check if it is in any of the default folders:
if not os.path.isfile(slhafile):
for dirPath in checkDirs:
if os.path.isfile(os.path.join(dirPath, slhafile)):
filename = os.path.join(dirPath, slhafile)
break
if not os.path.isfile(filename):
logger.error("Model file %s not found." % slhafile)
raise SModelSError()
logger.debug("Trying to define BSM particles from SLHA input file %s" % filename)
#Read file and extract blocks:
with open(filename, 'r') as f:
data = f.read()
data = data.lower()
qnumberBlocks = []
qBlock = False
for l in data.splitlines():
l = l.strip()
# Ignore empty lines and comments
if not l or l.startswith('#'):
continue
# Beginning of QNUMBERS block
if l.startswith('block qnumbers'):
qBlock = True
qnumberBlocks.append([l])
continue
# If any other block is starting set qBlock to False
elif l.startswith('block'):
qBlock = False
continue
# If a cross-section or decay block is starting set qBlock to False
elif l.startswith('xsection') or l.startswith('decay'):
qBlock = False
continue
# If current block is not a qnumbers block, skip
if not qBlock:
continue
# Add line to qnumbers block
qnumberBlocks[-1].append(l)
if not qnumberBlocks:
logger.error("No QNUMBERS blocks were found in %s" %slhafile)
raise SModelSError()
#Build list of BSM particles:
BSMList = []
for b in qnumberBlocks:
headerInfo = [x for x in b[0].replace('block','').replace('qnumbers','').split()
if x != '#']
if headerInfo[0].replace('-','').replace('+','').isdigit():
pdg = eval(headerInfo[0])
else:
logger.error("Error obtaining PDG number from QNUMBERS block:\n %s \n" %b)
if any(p.pdg == pdg for p in BSMList):
logger.warning("Particle with pdg %i appears multiple times in QNUMBERS blocks" %pdg)
continue
if len(headerInfo) > 1:
label = headerInfo[1].strip()
else:
label = str(pdg)
logger.debug("Could not find label for particle %i, will use its PDG number" %pdg)
try:
numbers = [l[:l.find('#')].lstrip().split() for l in b[1:]]
numbers = dict([x for x in numbers if x])
numbers = dict([[eval(x),eval(y)] for x,y in numbers.items()])
except:
logger.error("Error reading quantum numbers from block: \n %s \n" %b)
continue
if any(not x in numbers for x in [1,2,3]):
logger.error("Missing quantum numbers in block:\n %s\n" %b)
continue
# Ignore SM blocks:
if abs(pdg) in SMpdgs:
continue
# If it is not a SM particle, assume it is a BSM particle
newParticle = Particle(isSM=False, label=label, pdg=pdg,
eCharge=numbers[1]/3.,
colordim=numbers[3],
spin=(numbers[2]-1.)/2.)
BSMList.append(newParticle)
if numbers[4]: # Particle is not its own anti-particle
newParticleC = newParticle.chargeConjugate()
if any(p.pdg == newParticleC.pdg for p in BSMList):
continue
BSMList.append(newParticleC)
return BSMList
[docs]def getParticlesFromModule(modelFile):
"""
Reads the python model file and retrieves the list of BSM particles (BSMList)
:param modelFile: Name/path to the python module containing the BSM particle definitions
:return: a list of Particle objects
"""
fulldir = os.path.join(installDirectory(), "smodels", "share", "models")
sys.path.insert(0, installDirectory())
sys.path.insert(0, os.path.join(installDirectory(), "smodels"))
sys.path.insert(0, fulldir)
sys.path.insert(0, ".")
logger.debug("Trying to load model file: %s" % modelFile)
fname = modelFile[:]
if "/" in fname:
import shutil
filename = os.path.basename(fname)
if not os.path.exists ( filename ) or not os.path.samefile ( fname, filename ):
shutil.copy(fname, filename)
else:
filename = fname
if filename.endswith(".py"):
importName = filename[:-3]
else:
importName = filename
pM=import_module(importName, package='smodels')
logger.debug("Found model file at %s" % pM.__file__)
if filename != fname:
os.remove(filename)
BSMList = pM.BSMList
return BSMList
[docs]def load():
from smodels.base.runtime import modelFile
try:
BSMList = getParticlesFromModule(modelFile)
#If failed, assume the input is an SLHA file:
except (ImportError, AttributeError, SModelSError):
try:
BSMList = getParticlesFromSLHA(modelFile)
except SModelSError:
logger.error("Could not load input model from %s. The file should be either a python module with particle definitions or a SLHA file with QNUMBERS blocks." % modelFile)
raise SModelSError()
return BSMList