示例#1
0
def _getPromptDecays(slhafile,
                     brDic,
                     l_inner=1. * mm,
                     gb_inner=1.3,
                     l_outer=10. * m,
                     gb_outer=1.43):
    """
    Using the widths in the slhafile, reweights the BR dictionary with the fraction
    of prompt decays and add the fraction of "long-lived decays".
    The fraction of prompt decays and "long-lived decays" are defined as:
    F_prompt = 1 - exp(-width*l_inner/gb_inner)
    F_long = exp(-width*l_outer/gb_outer)
    where l_inner is the inner radius of the detector, l_outer is the outer radius
    and gb_x is the estimate for the kinematical factor gamma*beta for each case.
    We use gb_outer = 10 and gb_inner= 0.5
    :param widthDic: Dictionary with the widths of the particles
    :param l_inner: Radius of the inner tracker
    :param gb_inner: Effective gamma*beta factor to be used for prompt decays
    :param l_outer: Radius of the outer detector
    :param gb_outer: Effective gamma*beta factor to be used for long-lived decays
    
    :return: Dictionary = {pid : decay}
    """

    hc = 197.327 * MeV * fm  #hbar * c

    #Get the widths:
    res = pyslha.readSLHAFile(slhafile)
    decays = res.decays

    #PID for displaced decays:
    dispPid = 0

    for pid in brDic:
        if pid == dispPid:
            continue
        width = abs(decays[abs(pid)].totalwidth) * GeV
        Fprompt = 1. - math.exp(-width * l_inner / (gb_inner * hc))
        Flong = math.exp(-width * l_outer / (gb_outer * hc))
        for decay in brDic[pid]:
            decay.br *= Fprompt  #Reweight by prompt fraction

        #Add long-lived fraction:
        if Flong > 1e-50:
            stableFraction = pyslha.Decay(br=Flong, ids=[], nda=0)
            brDic[pid].append(stableFraction)
        if (Flong + Fprompt) > 1.:
            logger.error("Sum of decay fractions > 1 for " + str(pid))
            return False
        Fdisp = 1 - Flong - Fprompt
        #Add displaced decay:
        if Fdisp > 0.001:
            displacedFraction = pyslha.Decay(br=Fdisp, ids=[dispPid], nda=1)
            brDic[pid].append(displacedFraction)

    return brDic
示例#2
0
def _getDictionariesFromSLHA(slhafile):
    """
    Create mass and BR dictionaries from an SLHA file.
    Ignore decay blocks with R-parity violating or unknown decays

    """

    from smodels.particlesLoader import rEven, rOdd

    res = pyslha.readSLHAFile(slhafile)

    # Get mass and branching ratios for all particles
    brDic = {}
    writeIgnoreMessage(res.decays.keys(), rEven, rOdd)

    for pid in res.decays.keys():
        if not pid in rOdd:
            continue
        brs = []
        for decay in res.decays[pid].decays:
            nEven = nOdd = 0.
            for pidd in decay.ids:
                if pidd in rOdd: nOdd += 1
                elif pidd in rEven: nEven += 1
                else:
                    logger.warning(
                        "Particle %i not defined in particles.py,decay %i -> [%s] will be ignored"
                        % (pidd, pid, decay.ids))
                    break
            if nOdd + nEven == len(decay.ids) and nOdd == 1:
                brs.append(decay)
            else:
                logger.info("Ignoring decay: %i -> [%s]", pid, decay.ids)

        brsConj = copy.deepcopy(brs)
        for br in brsConj:
            br.ids = [-x for x in br.ids]
        brDic[pid] = brs
        brDic[-pid] = brsConj
    # Get mass list for all particles
    massDic = dict(res.blocks['MASS'].items())
    for pid in list(massDic.keys())[:]:
        massDic[pid] = round(abs(massDic[pid]), 1) * GeV
        if not -pid in massDic: massDic[-pid] = massDic[pid]

    #Include proxy for displaced decays
    if 0 in massDic or 0 in brDic:
        logger.error(
            "PDG = 0 is reserved for displaced decays and it can not be used for other particles. Please redefine the input model PDG assignments."
        )
        raise SModelSError()
    else:
        dispPid = 0
        massDic[dispPid] = 0. * GeV
        dispDec = pyslha.Decay(br=1., ids=[], nda=0)
        brDic[dispPid] = [dispDec]

    return brDic, massDic
示例#3
0
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)
    masses = {}
    decays = {}
    for ip, particle in enumerate(particles):
        if particle.status == -1: #Ignore incoming particles
            continue

        if not particle.pdg in masses:
            masses[particle.pdg] = [particle.mass]
            decays[particle.pdg] = []

        #Get event decay:
        decay = pyslha.Decay(0, 0, [], particle.pdg)
        #Collect all daughters:
        for ipn,newparticle in enumerate(particles):
            if ipn == ip:
                continue
            if not ip+1 in newparticle.moms: #newparticle is not a daughter of particle
                continue

            # Check if particle has a single parent
            # (as it should)
            newparticle.moms = [mom for mom in newparticle.moms if mom != 0]
            if len(newparticle.moms) != 1:
                raise SModelSError("More than one parent particle found")

            decay.nda += 1
            decay.br = 1.
            decay.ids.append(newparticle.pdg)

        if decay.ids:
            decay.ids = sorted(decay.ids)
            decays[particle.pdg].append(decay)

    return masses,decays
示例#4
0
    def testEventDictionaries(self):

        filename = "./testFiles/lhe/simplyGluino.lhe"
        reader = lheReader.LheReader(filename)
        events = [event for event in reader]
        reader.close()

        massDict, decayDict = lheReader.getDictionariesFromEvent(events[0])
        self.assertEqual(massDict, {
            -1: [0.33],
            1000021: [675.0],
            1000022: [200.0],
            1: [0.33]
        })
        gluinoDec = [
            pyslha.Decay(br=1., nda=3, ids=[-1, 1, 1000022], parentid=1000021)
        ] * 2
        self.assertTrue(compareDecays(gluinoDec, decayDict[1000021]))
        self.assertEqual(decayDict[1000022], [])
示例#5
0
    def testDictionaries(self):

        filename = "./testFiles/lhe/simplyGluino.lhe"
        massDict, decayDict = lheReader.getDictionariesFrom(filename)
        self.assertEqual(massDict, {
            1000021: 675.0,
            1000022: 200.0,
            1: 0.33,
            2: 0.33
        })
        gluinoDecs = [
            pyslha.Decay(br=0.3, nda=3, ids=[-1, 1, 1000022],
                         parentid=1000021),
            pyslha.Decay(br=0.7, nda=3, ids=[-2, 2, 1000022], parentid=1000021)
        ]
        self.assertEqual(len(decayDict[1000021].decays), len(gluinoDecs))
        self.assertTrue(compareDecays(gluinoDecs, decayDict[1000021].decays))

        re = pyslha.readSLHAFile("./testFiles/slha/gluino_squarks.slha")

        filename = "./testFiles/lhe/gluino_squarks.lhe"
        massDict, decayDict = lheReader.getDictionariesFrom(filename)
        for pdg in massDict:
            if pdg < 100000:
                continue
            self.assertAlmostEqual(re.blocks['MASS'][pdg], massDict[pdg])

        #Expected answer:
        decayRes = {}
        decayRes[1000024] = [
            pyslha.Decay(br=1.0000, ids=[1000022, 24], parentid=1000024, nda=2)
        ]
        decayRes[1000023] = [
            pyslha.Decay(br=0.8571, ids=[1000022, 25], parentid=1000023,
                         nda=2),
            pyslha.Decay(br=0.1429, ids=[1000022, 23], parentid=1000023, nda=2)
        ]
        decayRes[1000001] = [
            pyslha.Decay(br=1.0000, ids=[1000021, 1], parentid=1000001, nda=2)
        ]
        decayRes[1000002] = [
            pyslha.Decay(br=0.5000, ids=[1000024, 1], parentid=1000002, nda=2),
            pyslha.Decay(br=0.2500, ids=[1000021, 2], parentid=1000002, nda=2),
            pyslha.Decay(br=0.2500, ids=[1000023, 2], parentid=1000002, nda=2)
        ]
        decayRes[2000002] = [
            pyslha.Decay(br=1.0000, ids=[1000021, 2], parentid=2000002, nda=2)
        ]
        decayRes[1000021] = [
            pyslha.Decay(br=0.2500,
                         ids=[-1000024, 4, -3],
                         parentid=1000021,
                         nda=3),
            pyslha.Decay(br=0.3750,
                         ids=[1000024, -2, 1],
                         parentid=1000021,
                         nda=3),
            pyslha.Decay(br=0.1250,
                         ids=[1000024, -4, 3],
                         parentid=1000021,
                         nda=3),
            pyslha.Decay(br=0.1250,
                         ids=[1000023, -2, 2],
                         parentid=1000021,
                         nda=3),
            pyslha.Decay(br=0.1250,
                         ids=[1000023, -6, 6],
                         parentid=1000021,
                         nda=3)
        ]

        for pdg in decayRes:
            self.assertTrue(compareDecays(decayDict[pdg].decays,
                                          decayRes[pdg]))
            self.assertEqual(decayDict[pdg].totalwidth, float('inf'))

        for pdg in decayDict:
            if not decayDict[pdg].decays:
                self.assertEqual(decayDict[pdg].totalwidth, 0.)
示例#6
0
def getDictionariesFrom(lheFile,nevts=None):
    """
    Reads all events in the LHE file and create mass and BR dictionaries for each branch in an event.

    :param lheFile: LHE file
    :param nevts: (maximum) number of events used in the decomposition. If
                  None, all events from file are processed.

    :returns: BR and mass dictionaries for the particles appearing in the event
    """

    reader = LheReader(lheFile, nevts)
    # Loop over events and decompose
    massDict = {}
    decaysDict = {}
    for event in reader:
        eventMass,eventDecays = getDictionariesFromEvent(event)
        for pdg,mass in eventMass.items():
            if not pdg in massDict:
                massDict[pdg] = mass
            else:
                massDict[pdg] += mass

        for pdg,decays in eventDecays.items():
            if not pdg in decaysDict:
                decaysDict[pdg] = decays
            else:
                decaysDict[pdg] += decays


    #Use averaged mass over all events:
    for pdg,masses in massDict.items():
        massDict[pdg] = sum(masses)/len(masses)
        if not pdg in decaysDict:
            decaysDict[pdg] = [] #Make sure all particles appear in decaysDict

    #Compute the decay dictionaries:
    for pdg,eventDecays in list(decaysDict.items()):
        daughterIDs = []
        for eventDec in eventDecays:
            pids = sorted(eventDec.ids)
            if not pids in daughterIDs:
                daughterIDs.append(pids)
        n = len(eventDecays) #Number of times the particle appears in all events
        combinedDecays = []
        for daughterID in daughterIDs:
            decay = pyslha.Decay(br=0.,nda=len(daughterID),ids=daughterID,parentid=pdg)
            for eventDecay in eventDecays:
                if sorted(eventDecay.ids) != daughterID:
                    continue
                decay.br += 1./float(n) #Count this decay
            combinedDecays.append(decay)
        decaysDict[pdg] = combinedDecays #Stable particles will appear with an empty list

    #Remove anti-particle decays and masses:
    for pdg in list(massDict.keys())[:]:
        if -abs(pdg) in massDict and abs(pdg) in massDict:
            massDict.pop(-abs(pdg))
    for pdg in list(decaysDict.keys())[:]:
        if -abs(pdg) in decaysDict and abs(pdg) in decaysDict:
            decaysDict.pop(-abs(pdg))

    #Add widths to decaysDict using the pyslha.Particle class:
    for pdg,decays in decaysDict.items():
        decaysDict[pdg] = pyslha.Particle(pid=pdg)
        if abs(pdg) in massDict:
            decaysDict[pdg].mass = massDict[abs(pdg)]
        if decays:
            decaysDict[pdg].totalwidth = float('inf')
        else:
            decaysDict[pdg].totalwidth = 0.
        decaysDict[pdg].decays = decays

    reader.close()

    return massDict,decaysDict
示例#7
0
    def setDecays(self,decaysDict,promptWidth,stableWidth,erasePrompt):

        allPDGs = list(set(self.getValuesFor('pdg')))
        evenPDGs,oddPDGs = self.getEvenOddList()

        for particle in self.BSMparticles:
            if isinstance(particle,MultiParticle):
                continue

            if not hasattr(particle,'pdg') or not hasattr(particle,'Z2parity'):
                raise SModelSError("PDG and/or Z2-parity for particle %s has not been defined" %particle.label)

            pdg = particle.pdg
            particle.decays = []
            if pdg in decaysDict:
                particleData = decaysDict[pdg]
                chargeConj = 1
            elif -pdg in decaysDict:
                particleData = decaysDict[-pdg]
                chargeConj = -1
            else:
                logger.error("Decay information for particle %i could not be found" %pdg)
                raise SModelSError()

            particle.totalwidth = abs(particleData.totalwidth)*GeV
            if particle.totalwidth < stableWidth:
                particle.totalwidth = 0.*GeV  #Treat particle as stable
                logger.debug("Particle %s has width below the threshold and will be assumed as stable" %particle.pdg)
                continue

            if particle.totalwidth > promptWidth:
                particle.totalwidth = float('inf')*GeV  #Treat particle as prompt
                logger.debug("Particle %s has width above the threshold and will be assumed as prompt." %particle.pdg)
                if erasePrompt and particle.Z2parity == -1:
                    logger.debug("Erasing quantum numbers of (prompt) particle %s." %particle.pdg)
                    for attr in erasePrompt:
                        delattr(particle,attr)
            else:
                particle.decays.append(None) #Include possibility for particle being long-lived (non-prompt)

            for decay in particleData.decays:
                pids = decay.ids
                missingIDs = set(pids).difference(set(allPDGs))
                if missingIDs:
                    logger.info("Particle(s) %s is not defined within model. Decay %s will be ignored" %(missingIDs,decay))
                    continue
                oddPids = [pid for pid in decay.ids if abs(pid) in oddPDGs]
                evenPids = [pid for pid in decay.ids if abs(pid) in evenPDGs]
                if len(oddPids) != 1 or len(evenPids+oddPids) != len(decay.ids):
                    logger.debug("Decay %i -> %s is not of the form Z2-odd -> Z2-odd + [Z2-even particles] and will be ignored" %(pdg,pids))
                    continue

                #Conjugated decays if needed
                #(if pid*chargeConj is not in model, assume the particle is its own anti-particle)
                decayIDs = [pid*chargeConj if pid*chargeConj in allPDGs else pid for pid in decay.ids]
                newDecay = pyslha.Decay(br=decay.br,nda=decay.nda,parentid=decay.parentid,ids=decayIDs)

                #Convert PDGs to particle objects:
                daughters = []
                for pdg in newDecay.ids:
                    daughter = self.getParticlesWith(pdg=pdg)
                    if not daughter:
                        raise SModelSError("Particle with PDG = %i was not found in model. Check the model definitions." %pdg)
                    elif len(daughter) > 1:
                        raise SModelSError("Multiple particles defined with PDG = %i. PDG ids must be unique." %pdg)
                    else:
                        daughter = daughter[0]
                    daughters.append(daughter)
                oddParticles = [p for p in daughters if p.Z2parity == -1]
                evenParticles = ParticleList([p for p in daughters if p.Z2parity == 1])
                newDecay.oddParticles = oddParticles
                newDecay.evenParticles = evenParticles
                particle.decays.append(newDecay)

        #Check if all unstable particles have decay channels defined:
        for p in self.BSMparticles:
            if p.totalwidth < stableWidth:
                continue
            ndecays = len([dec for dec in p.decays if dec is not None])
            if ndecays == 0:
                if p.Z2parity == -1:
                    logger.warning("No valid decay found for %s. It will be considered stable." %p)
                p.totalwidth = 0.*GeV
示例#8
0
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] = {}
    from smodels.particlesLoader import rEven
    for ip, particle in enumerate(particles):
        if particle.pdg in rEven or particle.status == -1:
            # Ignore R-even particles and initial state particles
            continue
        ibranch = branches[ip]  # Get particle branch
        massDic[ibranch][particle.pdg] = round(particle.mass, 1) * 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 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