#!/usr/bin/env python
"""
.. module:: lheDecomposer
:synopsis: Decomposition of LHE events and creation of TopologyLists.
.. moduleauthor:: Andre Lessa <lessa.a.p@gmail.com>
"""
from smodels.theory import lheReader, topology, crossSection, element
from smodels.theory import branch
from smodels.tools.physicsUnits import fb, GeV
from smodels.tools.smodelsLogging import logger
from smodels.theory.exceptions import SModelSTheoryError as SModelSError
import pyslha
import smodels.particles
import copy
[docs]def decompose(lhefile, inputXsecs=None, nevts=None, doCompress=False,
doInvisible=False, minmassgap=-1. * GeV ):
"""
Perform LHE-based decomposition.
:param lhefile: LHE file with e.g. pythia events
:param inputXsecs: xSectionList object with cross sections for the mothers
appearing in the LHE file. If None, use information from file.
:param nevts: (maximum) number of events used in the decomposition. If
None, all events from file are processed.
:param doCompress: mass compression option (True/False)
:param doInvisible: invisible compression option (True/False)
:param minmassgap: minimum mass gap for mass compression (only used if
doCompress=True)
:returns: list of topologies (TopologyList object)
"""
if doCompress and minmassgap < 0. * GeV:
logger.error("Asked for compression without specifying minmassgap. Please set minmassgap.")
raise SModelSError()
reader = lheReader.LheReader(lhefile, nevts)
smsTopList = topology.TopologyList()
# Get cross section from file (= event weight, assuming a common weight for
# all events)
if not inputXsecs:
xSectionList = crossSection.getXsecFromLHEFile(lhefile,
addEvents=False)
else:
xSectionList = inputXsecs
# Loop over events and decompose
for event in reader:
momPDG = tuple(sorted(event.getMom())) # Get mother PDGs
eventweight = xSectionList.getXsecsFor(momPDG)
# Get event element
newElement = elementFromEvent(event, eventweight)
if not newElement:
continue
allElements = [newElement]
# Perform compression
if doCompress or doInvisible:
allElements += newElement.compressElement(doCompress, doInvisible,
minmassgap)
for el in allElements:
el.sortBranches()
smsTopList.addElement(el)
smsTopList._setElementIds()
return smsTopList
[docs]def elementFromEvent(event, weight=None):
"""
Creates an element from a LHE event and the corresponding event weight.
:param event: LHE event
:param weight: event weight. Must be a XSectionList object (usually with a
single entry) or None if not specified.
:returns: element
"""
if not event.particles:
logger.error("Empty event")
return None
brDic, massDic = _getDictionariesFromEvent(event)
# Create branch list
finalBranchList = []
for ip, particle in enumerate(event.particles):
if not particle.pdg in smodels.particles.rEven.keys() + smodels.particles.rOdd.keys():
logger.warning("Particle %i not defined in particles.py, events containing this particle will be ignored" %(particle.pdg))
return None
# Particle came from initial state (primary mother)
if 1 in particle.moms:
mombranch = branch.Branch()
mombranch.PIDs = [[particle.pdg]]
if weight:
mombranch.maxWeight = weight.getMaxXsec()
# Get simple BR and Mass dictionaries for the corresponding branch
branchBR = brDic[ip]
branchMass = massDic[ip]
mombranch.masses = [branchMass[mombranch.PIDs[0][0]]]
# Generate final branches (after all R-odd particles have decayed)
finalBranchList += branch.decayBranches([mombranch], branchBR,
branchMass, sigcut=0. * fb )
if len(finalBranchList) != 2:
logger.error(str(len(finalBranchList)) + " branches found in event; "
"Possible R-parity violation")
raise SModelSError()
# Create element from event
newElement = element.Element(finalBranchList)
if weight:
newElement.weight = copy.deepcopy(weight)
return newElement
def _getDictionariesFromEvent(event):
"""
Create mass and BR dictionaries for each branch in an event.
:param event: LHE event
:returns: BR and mass dictionaries for the branches in the event
"""
particles = event.particles
# Identify and label to which branch each particle belongs
#(the branch label is the position of the primary mother)
branches = {}
for ip, particle in enumerate(particles):
if particle.status == -1:
continue
if particles[particle.moms[0]].status == -1:
# If a primary mother, the branch index is its own position
initMom = ip
else:
# If not a primary mother, check if particle has a single parent
# (as it should)
if particle.moms[0] != particle.moms[1] and \
min(particle.moms) != 0:
logger.error("More than one parent particle found")
raise SModelSError()
initMom = max(particle.moms) - 1
while particles[particles[initMom].moms[0]].status != -1:
# Find primary mother (labels the branch)
initMom = max(particles[initMom].moms) - 1
branches[ip] = initMom
# Get mass and BR dictionaries for all branches:
massDic = {}
brDic = {}
for ibranch in branches.values(): #ibranch = position of primary mother
massDic[ibranch] = {}
brDic[ibranch] = {}
for ip, particle in enumerate(particles):
if particle.pdg in smodels.particles.rEven or particle.status == -1:
# Ignore R-even particles and initial state particles
continue
ibranch = branches[ip] # Get particle branch
massDic[ibranch][particle.pdg] = particle.mass* GeV
# Create empty BRs
brDic[ibranch][particle.pdg] = [pyslha.Decay(0., 0, [], particle.pdg)]
# Get BRs from event
for ip, particle in enumerate(particles):
if particle.status == -1:
# Ignore initial state particles
continue
if particles[particle.moms[0]].status == -1:
# Ignore initial mothers
continue
ibranch = branches[ip]
momPdg = particles[max(particle.moms) - 1].pdg
if momPdg in smodels.particles.rEven:
# Ignore R-even decays
continue
# BR = 1 always for an event
brDic[ibranch][momPdg][0].br = 1.
brDic[ibranch][momPdg][0].nda += 1
brDic[ibranch][momPdg][0].ids.append(particle.pdg)
return brDic, massDic