Esempio n. 1
0
def _getBestResult(dataSetResults):
    """
    Returns the best result according to the expected upper limit

    :param datasetPredictions: list of TheoryPredictionList objects
    :return: best result (TheoryPrediction object)
    """

    #In the case of UL analyses or efficiency-maps with a single signal region
    #return the single result:
    if len(dataSetResults) == 1:
        return dataSetResults[0]

    #For efficiency-map analyses with multipler signal regions,
    #select the best one according to the expected upper limit:
    bestExpectedR = 0.
    bestXsec = 0.*fb
    for predList in dataSetResults:
        if len(predList) != 1:
            logger.error("Multiple clusters should only exist for upper limit results!")
            raise SModelSError()
        dataset = predList[0].dataset
        if dataset.getType() != 'efficiencyMap':
            txt = "Multiple data sets should only exist for efficiency map results, but we have them for %s?" % (predList[0].analysisId())
            logger.error( txt )
            raise SModelSError( txt )
        pred = predList[0]
        xsec = pred.xsection
        expectedR = (xsec.value/dataset.getSRUpperLimit(0.05,True,False) ).asNumber()
        if expectedR > bestExpectedR or (expectedR == bestExpectedR and xsec.value > bestXsec):
            bestExpectedR = expectedR
            bestPred = pred
            bestXsec = xsec.value

    return bestPred
Esempio n. 2
0
def _evalConstraint(cluster):
    """
    Evaluate the constraint inside an element cluster.
    If the cluster refers to a specific TxName, sum all the elements' weights
    according to the analysis constraint.
    For efficiency map results, sum all the elements' weights.

    :parameter cluster: cluster of elements (ElementCluster object)
    :returns: cluster cross section
    """

    if cluster.getDataType() == 'efficiencyMap':
        return cluster.getTotalXSec()
    elif cluster.getDataType() == 'upperLimit':
        if len(cluster.txnames) != 1:
            logger.error("An upper limit cluster should never contain more than one TxName")
            raise SModelSError()
        txname = cluster.txnames[0]
        if not txname.constraint or txname.constraint == "not yet assigned":
            return txname.constraint
        exprvalue = _evalExpression(txname.constraint,cluster)
        return exprvalue
    else:
        logger.error("Unknown data type %s" %(str(cluster.getDataType())))
        raise SModelSError()
Esempio n. 3
0
    def getDataType(self):
        """
        Checks to which type of data (efficiency map or upper limit)
        the cluster refers to. It uses the cluster.txnames attribute.
        If not defined, returns None
        :return: upperLimits or efficiencyMap (string)
        """

        if not hasattr(self, 'txnames') or not self.txnames:
            return None
        else:
            #Check the data types
            #for txname in self.txnames:
            #    if not txname.txnameData._data:
            #        txname.txnameData.loadData()  #Make sure the _data is loaded

            dataTag = list(set([txname.txnameData.dataTag for txname in self.txnames]))
            if len(dataTag) != 1:
                logger.error("A single cluster contain mixed data types!")
                raise SModelSError()
            elif 'upperLimit' in dataTag[0]:
                return 'upperLimit'
            elif 'efficiencyMap' in dataTag[0]:
                return 'efficiencyMap'
            else:
                logger.error("Unknown data type %s" % (dataTag[0]))
                raise SModelSError()
Esempio n. 4
0
    def setMasses(self, mass, sameOrder=True, opposOrder=False):
        """
        Set the element masses to the input mass array.
        
        
        :parameter mass: list of masses ([[masses for branch1],[masses for branch2]])
        :parameter sameOrder: if True, set the masses to the same branch ordering
                              If True and opposOrder=True, set the masses to the
                              smaller of the two orderings.
        :parameter opposOrder: if True, set the masses to the opposite branch ordering.
                               If True and sameOrder=True, set the masses to the
                               smaller of the two orderings.             
        """
        if sameOrder and opposOrder:
            newmass = sorted(mass)
        elif sameOrder:
            newmass = mass
        elif opposOrder:
            newmass = [mass[1], mass[0]]
        else:
            logger.error("Called with no possible ordering")
            raise SModelSError()
        if len(newmass) != len(self.branches):
            logger.error("Called with wrong number of mass branches")
            raise SModelSError()

        for i, mass in enumerate(newmass):
            self.branches[i].masses = mass[:]
Esempio n. 5
0
    def __init__(self, smodelsFolder, slhaFolder, parameterFile, indexfile):
        """
        Initializes the class.

        :parameter smodelsFolder: path to the folder containing the smodels (python) output files
        :parameter slhaFolder: path to the folder containing the SLHA input files
        :parameter parameterFile: path to the file containing the plotting definitions
        """

        self.data_dict = []
        self.smodelsFolder = smodelsFolder
        self.slhaFolder = slhaFolder
        self.indexfile = indexfile
        self.parameterFile = parameterFile

        self.slha_hover_information = None
        self.ctau_hover_information = None
        self.BR_hover_information = None
        self.SModelS_hover_information = None
        self.plot_data = None
        self.variable_x = None
        self.variable_y = None
        self.plot_list = None
        self.BR_get_top = None

        if not os.path.isfile(parameterFile):
            raise SModelSError('Parameters file %s not found' % parameterFile)
        if not os.path.isdir(smodelsFolder):
            raise SModelSError("Folder %s not found" % smodelsFolder)
        if not os.path.isdir(slhaFolder):
            raise SModelSError("Folder %s not found" % slhaFolder)

        self.loadParameters()
        self.initializeDataDict()
Esempio n. 6
0
 def __init__(self, info=None):
     """
     Initializes the branch. If info is defined, tries to generate
     the branch using it.
     
     :parameter info: string describing the branch in bracket notation
                      (e.g. [[e+],[jet]])
     """
     self.masses = []
     self.particles = []
     self.PIDs = []
     self.maxWeight = None
     self.vertnumb = None
     self.vertparts = None
     if type(info) == type(str()):
         branch = elementsInStr(info)
         if not branch or len(branch) > 1:
             logger.error("Wrong input string " + info)
             raise SModelSError()
         else:
             branch = branch[0]
             vertices = elementsInStr(branch[1:-1])
             for vertex in vertices:
                 ptcs = vertex[1:-1].split(',')
                 # Syntax check:
                 for ptc in ptcs:
                     if not ptc in rEven.values() \
                             and not ptc in ptcDic:
                         logger.error("Unknown particle. Add " + ptc +
                                      " to smodels/particle.py")
                         raise SModelSError()
                 self.particles.append(ptcs)
         self.vertnumb = len(self.particles)
         self.vertparts = [len(v) for v in self.particles]
Esempio n. 7
0
def elementsInStr(instring, removeQuotes=True):
    """
    Parse instring and return a list of elements appearing in instring.
    instring can also be a list of strings.

    :param instring: string containing elements (e.g. "[[['e+']],[['e-']]]+[[['mu+']],[['mu-']]]")
    :param removeQuotes: If True, it will remove the quotes from the particle labels.
                         Set to False, if one wants to run eval on the output.

    :returns: list of elements appearing in instring in string format

    """
    outstr = ""
    if isinstance(instring, str):
        outstr = instring
    elif isinstance(instring, list):
        for st in instring:
            if not isinstance(st, str):
                logger.error("Input must be a string or a list of strings")
                raise SModelSError()
            # Combine list of strings in a single string
            outstr += st
    else:
        raise SModelSError ( "syntax error in constraint/condition: ``%s''." \
              "Check your constraints and conditions in your database." % str(instring) )

    elements = []
    outstr = outstr.replace(" ", "")
    if removeQuotes:
        outstr = outstr.replace("'", "")
    elStr = ""
    nc = 0
    # Parse the string and looks for matching ['s and ]'s, when the matching is
    # complete, store element
    for c in outstr:
        delta = 0
        if c == '[':
            delta = -1
        elif c == ']':
            delta = 1
        nc += delta
        if nc != 0:
            elStr += c
        if nc == 0 and delta != 0:
            elements.append(elStr + c)
            elStr = ""
            # Syntax checks
            ptclist = elements[-1].replace(']', ',').replace('[', ',').\
                    split(',')
            for ptc in ptclist:
                ptc = ptc.replace("'", "")
                if not ptc:
                    continue

    # Check if there are not unmatched ['s and/or ]'s in the string
    if nc != 0:
        raise SModelSError("Wrong input (incomplete elements?) " + instring)

    return elements
def simParticles(plist1, plist2, useDict=True):
    """
    Compares two lists of particle names. Allows for dictionary
    labels (Ex: L = l, l+ = l, l = l-,...). Ignores particle ordering inside
    the list
 
    :param plist1: first list of particle names, e.g. ['l','jet']
    :param plist2: second list of particle names 
    :param useDict: use the translation dictionary, i.e. allow e to stand for
                    e+ or e-, l+ to stand for e+ or mu+, etc 
    :returns: True/False if the particles list match (ignoring order)    
    """

    if not isinstance(plist1, list) or type(plist1) != type(plist2):
        logger.error("Input must be a list")
        raise SModelSError()
    if len(plist1) != len(plist2):
        return False
    for i, p in enumerate(plist1):
        if not isinstance(p, str) or not isinstance(plist2[i], str):
            logger.error("Input must be a list of particle strings")
            raise SModelSError()
        elif not p in list(ptcDic.keys()) + list(rEven.values()):
            logger.error("Unknow particle: %s" % p)
            raise SModelSError()
        elif not plist2[i] in list(ptcDic.keys()) + list(rEven.values()):
            logger.error("Unknow particle: %s" % plist2[i])
            raise SModelSError()

    l1 = sorted(plist1)
    l2 = sorted(plist2)
    if not useDict:
        return l1 == l2

    #If dictionary is to be used, replace particles by their dictionay entries
    #e.g. [jet,mu+] -> [[q,g,c],[mu+]], [jet,mu] -> [[q,g,c],[mu+,mu-]]
    extendedL1 = []
    for i, p in enumerate(plist1):
        if not p in ptcDic:
            extendedL1.append([p])
        else:
            extendedL1.append(ptcDic[p])
    extendedL2 = []
    for i, p in enumerate(plist2):
        if not p in ptcDic:
            extendedL2.append([p])
        else:
            extendedL2.append(ptcDic[p])

    #Generate all combinations of particle lists (already sorted to avoid ordering issues)
    #e.g. [[q,g,c],[mu+]] -> [[q,mu+],[g,mu+],[c,mu+]]
    extendedL1 = [sorted(list(i)) for i in itertools.product(*extendedL1)]
    extendedL2 = [sorted(list(i)) for i in itertools.product(*extendedL2)]

    #Now compare the two lists and see if there is a match:
    for plist in extendedL1:
        if plist in extendedL2: return True

    return False
def elementsInStr(instring):
    """
    Parse instring and return a list of elements appearing in instring.
    instring can also be a list of strings.
    
    :returns: list of elements appearing in instring in string format
    
    """

    outstr = ""
    if type(instring) == type('st'):
        outstr = instring
    elif type(instring) == type([]):
        for st in instring:
            if type(st) != type('st'):
                logger.error("Input must be a string or a list of strings")
                raise SModelSError()
            # Combine list of strings in a single string
            outstr += st
    else:
        raise SModelSError ( "syntax error in constraint/condition: ``%s''." \
              "Check your constraints and conditions in your database." % str(instring) )

    elements = []
    outstr = outstr.replace(" ", "").replace("'", "")
    elStr = ""
    nc = 0
    # Parse the string and looks for matching ['s and ]'s, when the matching is
    # complete, store element
    for c in outstr:
        delta = 0
        if c == '[':
            delta = -1
        elif c == ']':
            delta = 1
        nc += delta
        if nc != 0:
            elStr += c
        if nc == 0 and delta != 0:
            elements.append(elStr + c)
            elStr = ""
            # Syntax checks
            ptclist = elements[-1].replace(']', ',').replace('[', ',').\
                    split(',')
            for ptc in ptclist:
                if not ptc:
                    continue
                if not ptc in rEven.values() and not ptc in ptcDic:
                    logger.error("Unknown particle. Add " + ptc +
                                 " to smodels/particles.py")
                    raise SModelSError()

    # Check if there are not unmatched ['s and/or ]'s in the string
    if nc != 0:
        logger.error("Wrong input (incomplete elements?) " + instring)
        raise SModelSError()

    return elements
Esempio n. 10
0
 def _checkSLHA(self, slhafile):
     if not os.path.isfile(slhafile):
         logger.error("SLHA file %s not found.", slhafile)
         raise SModelSError()
     try:
         f = pyslha.readSLHAFile(slhafile)
     except pyslha.ParseError as e:
         logger.error("File cannot be parsed as SLHA file: %s" % e)
         raise SModelSError()
def vertInStr(instring):
    """
    Parses instring (or a list of strings) and returns the list of particle
    vertices appearing in instring.
    
    """
    if type(instring) == type('st'):
        outstr = instring
    elif type(instring) == type([]):
        outstr = ""
        for st in instring:
            if type(st) != type('st'):
                logger.error("Input must be a string or a list of strings")
                raise SModelSError()
            # Combine list of strings in a single string
            outstr += st

    vertices = []
    outstr = outstr.replace(" ", "").replace("'", "")
    vertStr = ""
    nc = 0
    # Parse the string and looks for matching ['s and ]'s, when the matching is
    # complete, store element
    for c in outstr:
        delta = 0
        if c == '[':
            delta = -1
        elif c == ']':
            delta = 1
        nc += delta
        if c == '[':
            vertStr = ""
        if nc != 0 and c != '[' and c != ']':
            vertStr += c
        if delta > 0 and vertStr:
            vertices.append(vertStr.split(','))
            # Syntax checks:
            for ptc in vertices[-1]:
                if not ptc:
                    continue
                if not ptc in rEven.values() and not ptc in ptcDic:
                    logger.error("Unknown particle. Add " + ptc +
                                 " to smodels/particle.py")
                    raise SModelSError()
            vertStr = ""

    # Check if there are not unmatched ['s and/or ]'s in the string
    if nc != 0:
        logger.error("Wrong input (incomplete elements?) " + instring)
        raise SModelSError()

    return vertices
Esempio n. 12
0
    def __init__(self, finalState=None, intermediateState=None, model=None):
        """
        :parameter info: string describing the branch in bracket notation
                         (e.g. [[e+],[jet]])

        :parameter finalState: final state label string for the branch
                         (e.g. 'MET' or 'HSCP')
        :parameter intermediateState: list containing intermediate state labels
                                      (e.g. ['gluino','C1+'])
        :parameter model: The model (Model object) to be used when converting particle labels to particle objects (only used if info, finalState or intermediateState != None).
        """
        Branch.__init__(self)
        self.mass = InclusiveList()
        self.totalwidth = InclusiveList()
        self.evenParticles = InclusiveList()
        self.oddParticles = []
        #Get labels of intermediate states
        if intermediateState:
            if not isinstance(intermediateState, list):
                raise SModelSError(
                    "Intermediate state (``%s'') should be a list)" %
                    intermediateState)
            bsmLabels = intermediateState[:]
        else:
            bsmLabels = []
        if finalState:
            bsmLabels.append(finalState)
        else:
            bsmLabels.append('anyOdd')
        for bsmLabel in bsmLabels:
            bsmParticle = model.getParticlesWith(label=bsmLabel)
            if not bsmParticle:
                raise SModelSError(
                    "BSM particle ``%s'' has not been defined in model %s" %
                    (bsmLabel, model))
            elif len(bsmParticle) != 1:
                raise SModelSError(
                    "Ambiguous definition of label ``%s'' in model %s" %
                    (bsmLabel, model))
            else:
                self.oddParticles.append(bsmParticle[0])

        #If intintermediateState is defined, the number of vertexParticles
        #(odd particles) must be used for comparison. Otherwise accept any number.
        if intermediateState:
            self.vertnumb = len(intermediateState)
        else:
            self.vertnumb = InclusiveValue()
        self.vertparts = InclusiveList()
Esempio n. 13
0
def makePlots(smodelsFolder,
              slhaFolder,
              outputFolder,
              parameters,
              npoints,
              verbosity,
              indexfile="index.html"):
    """
    Main interface for the interactive-plots.

    :parameter smodelsFolder: Path to the folder containing the SModelS python output
    :parameter slhaFolder: Path to the folder containing the SLHA files corresponding to the SModelS output
    :parameter parameters: Path to the parameter file setting the options for the interactive plots
    :parameter npoints: Number of points used to produce the plot. If -1, all points will be used.
    :parameter verbosity: Verbosity of the output (debug,info,warning,error)
    :parameter indexfile: name of the starting web page (index.html)

    :return: True if the plot creation was successfull

    """

    try:
        import plotly
    except ImportError:
        raise SModelSError(
            "Plotly is not installed. To use this tool, please install plotly")

    try:
        import pandas
    except ImportError:
        raise SModelSError(
            "Pandas is not installed. To use this tool, please install pandas")

    setLogLevel(verbosity)

    #Basic checks:
    smodelsFolder = smodelsFolder
    slhaFolder = slhaFolder
    parFile = parameters

    dataHolder = DataHolder(smodelsFolder, slhaFolder, parFile, indexfile)
    loadData = dataHolder.loadData(npoints)
    if not loadData:
        raise SModelSError("Error loading data from folders:\n %s\n %s" %
                           (smodelsFolder, slhaFolder))

    dataHolder.makePlots(outputFolder)

    return outputFolder
Esempio n. 14
0
def removeInclusives(massArray, shapeArray):
    """
    Remove all entries corresponding to '*' in shapeArray.
    If shapeArray contains entries = '*', the corresponding entries
    in value will be removed from the output.

    :param massArray: Array to be formatted (e.g. [[200.,100.],[200.,100.]] or [[200.,'*'],'*'],0.4])
    :param shapeArray: Array with format info (e.g. ['*',[float,float]])

    :return: formatted array (e.g. [[200.,100.]] or [[200.]],0.4])
    """

    if shapeArray == '*':
        return None
    elif isinstance(massArray, list):
        if len(shapeArray) != len(massArray):
            raise SModelSError("Input value and data shape mismatch (%s,%s)" %
                               (len(shapeArray), len(massArray)))
        else:
            return [
                removeInclusives(xi, shapeArray[i])
                for i, xi in enumerate(massArray)
                if not removeInclusives(xi, shapeArray[i]) is None
            ]
    else:
        return massArray
Esempio n. 15
0
def _evalConditions(cluster):
    """
    Evaluate the conditions (if any) inside an element cluster.

    :parameter cluster: cluster of elements (ElementCluster object)
    :returns: list of condition values (floats) if analysis type == upper limit. None, otherwise.
    """

    conditionVals = {}
    for txname in cluster.txnames:
        if not txname.condition or txname.condition == "not yet assigned":
            continue
        #Make sure conditions is always a list
        if isinstance(txname.condition,str):
            conditions =  [txname.condition]
        elif isinstance(txname.condition,list):
            conditions = txname.condition
        else:
            logger.error("Conditions should be a list or a string")
            raise SModelSError()

        # Loop over conditions
        for cond in conditions:
            exprvalue = _evalExpression(cond,cluster)
            if isinstance(exprvalue,crossSection.XSection):
                conditionVals[cond] = exprvalue.value
            else:
                conditionVals[cond] = exprvalue

    if not conditionVals:
        return None
    else:
        return conditionVals
def xsecToBlock(xsec, inPDGs=(2212, 2212), comment=None, xsecUnit=pb):
    """
    Generate a string for a XSECTION block in the SLHA format from a XSection
    object.

    :param inPDGs: defines the PDGs of the incoming states
                   (default = 2212,2212)

    :param comment: is added at the end of the header as a comment
    :param xsecUnit: unit of cross sections to be written (default is pb). Must be a Unum unit.

    """
    if type(xsec) != type(crossSection.XSection()):
        logger.error("Wrong input")
        raise SModelSError()
    # Sqrt(s) in GeV
    header = "XSECTION  " + str(xsec.info.sqrts / GeV)
    for pdg in inPDGs:
        # PDGs of incoming states
        header += " " + str(pdg)
    # Number of outgoing states
    header += " " + str(len(xsec.pid))
    for pid in xsec.pid:
        # PDGs of outgoing states
        header += " " + str(pid)
    if comment:
        header += "   # " + str(comment)  # Comment
    entry = "  0  " + str(xsec.info.order) + "  0  0  0  0  " + \
            str("%16.8E" % (xsec.value / xsecUnit) ) + " SModelS " + installation.version()

    return "\n" + header + "\n" + entry
Esempio n. 17
0
    def __add__(self, other):
        """
        Adds two branches. Should only be used if the branches
        have the same topologies. The odd and even particles are combined.
        """

        if self.getInfo() != other.getInfo():
            raise SModelSError("Can not add branches with distinct topologies")

        newBranch = self.__class__()
        #Combine odd particles
        for iptc, ptc in enumerate(self.oddParticles):
            newBranch.oddParticles.append(ptc + other.oddParticles[iptc])

        #Combine even particles (if they are the same nothing changes)
        for iv, vertex in enumerate(self.evenParticles):
            vertexParticles = []
            for iptc, ptc in enumerate(vertex):
                vertexParticles.append(ptc + other.evenParticles[iv][iptc])

            vertexParticles = ParticleList(vertexParticles)
            newBranch.evenParticles.append(vertexParticles)

        if not self.maxWeight is None and not other.maxWeight is None:
            newBranch.maxWeight = self.maxWeight + other.maxWeight

        return newBranch
Esempio n. 18
0
    def setFinalState(self, finalState=None):
        """
        If finalState = None, define the branch final state according to the PID of the
        last R-odd particle appearing in the cascade decay.
        Else set the final state to the finalState given
        :parameter finalState: String defining the final state
        """

        if finalState:
            if finalState == '*':
                finalState = InclusiveStr()
            if not finalState in list(finalStates.keys()):
                raise SModelSError(
                    "Final state %s has not been defined. Add it to particles.py."
                    % finalState)
            else:
                self.finalState = finalState
        #If PIDs have been defined, use it:
        elif self.PIDs:
            fStates = set()
            for pidList in self.PIDs:
                fStates.add(getFinalStateLabel(pidList[-1]))

            if len(fStates) != 1:
                logger.error("Error obtaining the final state for branch %s" %
                             self)
                raise SModelSError
            else:
                self.finalState = list(fStates)[0]
        #Else do nothing
        else:
            self.finalState = None
Esempio n. 19
0
def groupElements(elements,dataset):
    """
    Group elements into groups where the average element
    identical to all the elements in group.
    The groups contain all elements which share the same mass,width and upper limit
    and can be replaced by their average element when building clusters.

    :parameter elements: list of all elements to be grouped
    :parameter dataset: Dataset object to be used when computing distances in upper limit space

    :returns: a list of AverageElement objects
              which represents a group of elements with same mass, width and upper limit.
    """

    # First make sure all elements contain their upper limits
    for el in elements:
        if not hasattr(el,'._upperLimit'):
            el._upperLimit = dataset.getUpperLimitFor(el,txnames=el.txname)
        if el._upperLimit is None:
            raise SModelSError("Trying to cluster element outside the grid.")

    #Group elements if they have the same UL
    #and give the same average element (same mass and same width)
    avgElements = []
    for iA,elA in enumerate(elements):
        avgEl = AverageElement([elA])
        avgEl._upperLimit = elA._upperLimit
        for iB,elB in enumerate(elements):
            if iB <= iA:
                continue
            if elA._upperLimit != elB._upperLimit:
                continue
            if avgEl != elB:
                continue
            avgEl.elements.append(elB)
            avgEl.weight += elB.weight
        if not avgEl in avgElements:
            avgElements.append(avgEl)


    #Make sure each element belongs to a average element:
    for el in elements:
        nclusters = sum([avgEl.contains(el) for avgEl in avgElements])
        if nclusters != 1:
            raise SModelSError("Error computing average elements. Element %s belongs to %i average elements."
                               %(str(el),nclusters))
    return avgElements
Esempio n. 20
0
    def findIllegalDecay(self, findIllegal):
        """
        Find decays for which the sum of daughter masses excels the mother mass
        
        :parameter findIllegal: True if check should be run
        :returns: status flag and message
        
        """
        if not findIllegal:
            return 0, "Did not check for illegal decays"
        st = 1
        badDecay = "Illegal decay for PIDs "
        for particle, block in self.slha.decays.items():
            if particle in SMpdgs: continue
            if not particle in self.slha.blocks["MASS"].keys(): continue
            mMom = abs(self.slha.blocks["MASS"][particle])
            for dcy in block.decays:
                mDau = 0.
                for ptc in dcy.ids:
                    ptc = abs(ptc)
                    if ptc in SMpdgs:
                        smParticle = self.model.getParticlesWith(pdg=ptc)
                        if not smParticle:
                            raise SModelSError(
                                "Particle with PDG = %i could not be found." %
                                ptc)
                        elif len(smParticle) != 1:
                            raise SModelSError(
                                "Multiple particles defined with PDG = %i in model"
                                % ptc)
                        else:
                            smParticle = smParticle[0]
                        mDau += smParticle.mass / GeV
                    elif ptc in self.slha.blocks["MASS"].keys():
                        mDau += abs(self.slha.blocks["MASS"][ptc])
                    else:
                        return -2, "Unknown PID %s in decay of %s" % (
                            str(ptc), str(particle) + ". Add " + str(ptc) +
                            " to smodels/particle.py")
                if mDau > mMom:
                    st = -1
                    if not str(particle) in badDecay:
                        badDecay += str(particle) + " "
        if st == 1:
            badDecay = "No illegal decay blocks"

        return st, badDecay
Esempio n. 21
0
def clusterElements(elements, maxDist, dataset):
    """
    Cluster the original elements according to their distance in upper limit space.

    :parameter elements: list of elements (Element objects)
    :parameter dataset: Dataset object to be used when computing distances in upper limit space
    :parameter maxDist: maximum distance for clustering two elements

    :returns: list of clusters (ElementCluster objects)
    """
    if len(elements) == 0:
        return []

    if any(not isinstance(el,Element) for el in elements):
        raise SModelSError("Asked to cluster non Element objects")
    if not isinstance(dataset,(DataSet,CombinedDataSet)):
        raise SModelSError("A dataset object must be defined for clustering")

    txnames = list(set([el.txname for el in elements]))
    if dataset.getType() == 'upperLimit' and len(txnames) != 1 :
        logger.error("Clustering elements with different Txnames for an UL result.")
        raise SModelSError()

    #Make sure only unique elements are clustered together (avoids double counting weights)
    #Sort element, so the ones with highest contribution (weight*eff) come first:
    elementList = sorted(elements, key = lambda el: el.weight.getMaxXsec()*el.eff, reverse=True)
    #Remove duplicated elements:
    elementsUnique = []
    for el in elementList:
        #Skip the element if it is related to any another element in the list
        if any(el.isRelatedTo(elB) for elB in elementsUnique):
            continue
        elementsUnique.append(el)

    if dataset.getType() == 'upperLimit': #Group according to upper limit values
        clusters = doCluster(elementsUnique, dataset, maxDist)
    elif dataset.getType() == 'efficiencyMap': #Group all elements together
        distanceMatrix = np.zeros((len(elementsUnique),len(elementsUnique)))
        cluster = ElementCluster(dataset=dataset,distanceMatrix=distanceMatrix)
        for iel,el in enumerate(elementsUnique):
            el._index = iel
        cluster.elements = elementsUnique
        clusters = [cluster]

    for cluster in clusters:
        cluster.txnames = txnames
    return clusters
Esempio n. 22
0
 def __getitem__(self, index):
     if len(self) <= index:
         txt = "Index in XSectionList out of bounds: idx(%d)>=length(%d). " \
                "(Are there cross sections given in the input?)" % \
                ( index, len(self) )
         logger.error(txt)
         raise SModelSError(txt)
     return self.xSections[index]
Esempio n. 23
0
    def __init__(self, info=None, finalState=None):
        """
        Initializes the branch. If info is defined, tries to generate
        the branch using it.
        
        :parameter info: string describing the branch in bracket notation
                         (e.g. [[e+],[jet]])

        :parameter finalState: final state label string for the branch
                         (e.g. 'MET' or 'HSCP')                         
        """

        from smodels.particlesLoader import rEven

        self.masses = []
        self.particles = []
        self.PIDs = []
        self.maxWeight = None
        self.vertnumb = None
        self.vertparts = None
        self.stable = False
        self.finalState = None
        if type(info) == type(str()):
            branch = elementsInStr(info)
            if not branch or len(branch) > 1:
                logger.error("Wrong input string " + info)
                raise SModelSError()
            else:
                branch = branch[0]
                vertices = elementsInStr(branch[1:-1])
                for vertex in vertices:
                    ptcs = vertex[1:-1].split(',')
                    # Syntax check:
                    for i, ptc in enumerate(ptcs):
                        if ptc == "*":
                            ptc = InclusiveStr()
                            ptcs[i] = ptc
                        if not ptc in rEven.values() \
                                and not ptc in list(ptcDic.keys()):
                            raise SModelSError("Unknown particle. Add " + ptc +
                                               " to smodels/particle.py")
                    self.particles.append(ptcs)
            self.vertnumb = len(self.particles)
            self.vertparts = [len(v) for v in self.particles]

        self.setFinalState(finalState)
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
Esempio n. 25
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
Esempio n. 26
0
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 = []
    from smodels.particlesLoader import rOdd, rEven
    for ip, particle in enumerate(event.particles):
        keys = list ( rEven.keys() ) + \
               list ( rOdd.keys() )
        if not particle.pdg in 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()
            else:
                mombranch.maxWeight = 0. * fb
            # 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
Esempio n. 27
0
 def addCommentToFile(self, comment, slhaFile):
     """ add the optional comment to file """
     if comment in [None, ""]:
         return
     if not os.path.isfile(slhaFile):
         logger.error("SLHA file %s not found." % slhaFile)
         raise SModelSError()
     outfile = open(slhaFile, 'a')
     outfile.write("# %s\n" % comment)
     outfile.close()
Esempio n. 28
0
    def checkConsistency(self):
        """
        Check if the all the elements in elementList are
        consistent with the topology (same number of vertices and final states)
        
        :returns: True if all the elements are consistent. Print error message
                  and exits otherwise.
        """

        for element in self.elementList:
            info = element.getEinfo()
            if self.vertnumb != info["vertnumb"]:
                logger.error("Inconsistent topology.")
                raise SModelSError()
            if self.vertparts != info["vertparts"]:
                logger.error("Inconsistent topology.")
                raise SModelSError()
        logger.info("Consistent topology.")
        return True
def get_slha_file(smodelsDict):
    """
    Returns the file name of the SLHA file corresponding to the output in smodelsDict
    """

    slhaFile = get_entry(smodelsDict, 'OutputStatus', 'input file')
    if not slhaFile:
        raise SModelSError()

    return os.path.basename(slhaFile)
Esempio n. 30
0
    def add(self, newxsec):
        """
        Append a XSection object to the list.

        """
        if type(newxsec) != type(XSection()):
            logger.error("Input object must be a XSection() object")
            raise SModelSError()
        else:
            self.xSections.append(newxsec.copy())