def testreweightFactorFor(self): n1 = mssm.n1.copy() n1.totalwidth = 0. * GeV st1 = mssm.st1.copy() st1.totalwidth = 1e-13 * GeV F_prompt = 0.3228249017964917 Fdisp = 0.6771750982035083 gluino = mssm.gluino.copy() gluino.totalwidth = 1. * 10**(-30) * GeV t = SMparticles.t branch1 = Branch() branch1.oddParticles = [n1] branch2 = Branch() branch2.oddParticles = [gluino] el1 = Element([branch1, branch2]) f = reweightFactorFor(el1, 'prompt') self.assertAlmostEqual(f, 1., places=3) f = reweightFactorFor(el1, 'displaced') self.assertAlmostEqual(f, 0., places=3) branch3 = Branch() branch3.oddParticles = [st1, n1] branch3.evenParticles = [[t]] el2 = Element([branch1, branch3]) f = reweightFactorFor(el2, resType='prompt') self.assertAlmostEqual(f, F_prompt, places=3) f = reweightFactorFor(el2, resType='displaced') self.assertAlmostEqual(f, Fdisp, places=3)
def __init__(self, el, missingX, smFinalStates, bsmFinalStates): self.branches = [Branch() for _ in el.branches] self.missingX = missingX self.finalBSMstates = [] for ib, branch in enumerate(el.branches): newParticles = [] for vertex in branch.evenParticles: newVertex = vertex[:] for ip, particle in enumerate(vertex): for particleList in smFinalStates: if particleList.contains(particle): newVertex[ip] = particleList newParticles.append(ParticleList(newVertex)) self.branches[ib].evenParticles = newParticles finalBSM = branch.oddParticles[-1] for bsmFS in bsmFinalStates: if finalBSM == bsmFS: finalBSM = bsmFS break self.branches[ib].finalBSMstate = finalBSM self.branches[ib].setInfo() self.sortBranches() self.finalBSMstates = [br.finalBSMstate for br in self.branches] self._contributingElements = [el] self._outputDescription = str(self)
def __init__(self, info=None): """ Initializes the element. If info is defined, tries to generate the element using it. :parameter info: string describing the element in bracket notation (e.g. [[[e+],[jet]],[[e-],[jet]]]) """ self.branches = [Branch(), Branch()] self.weight = crossSection.XSectionList() self.motherElements = [] self.elID = 0 self.covered = False self.tested = False if info: # Create element from particle string if type(info) == type(str()): elements = elementsInStr(info) if not elements or len(elements) > 1: nel = 0 if elements: nel = len(elements) logger.error( "Malformed input string. Number of elements " "is %d (expected 1) in: ``%s''", nel, info) return None else: el = elements[0] branches = elementsInStr(el[1:-1]) if not branches or len(branches) != 2: logger.error( "Malformed input string. Number of " "branches is %d (expected 2) in: ``%s''", len(branches), info) return None self.branches = [] for branch in branches: self.branches.append(Branch(branch)) # Create element from branch pair elif type(info) == type([]) and type(info[0]) == type(Branch()): for ib, branch in enumerate(info): self.branches[ib] = branch.copy()
def testElementCombine(self): gluino.mass = 500. * GeV st1.mass = 400. * GeV n1.mass = 250. * GeV n2.mass = 300. * GeV n3.mass = 320. * GeV n1.totalwidth = 0. * GeV n2.totalwidth = 0. * GeV #just for the sake of the example w1 = XSectionList() w1.xSections.append(XSection()) w1.xSections[0].info = XSectionInfo() w1.xSections[0].info.sqrts = 8. * TeV w1.xSections[0].info.label = '8 TeV' w1.xSections[0].info.order = 0 w1.xSections[0].value = 10. * fb w2 = w1.copy() w2.xSections[0].value = 22. * fb w3 = w1.copy() w3.xSections[0].value = 2. * fb b1 = Branch() b2 = Branch() b1.evenParticles = [[g]] b1.oddParticles = [gluino, n1] b2.evenParticles = [[g]] b2.oddParticles = [gluino, n2] el1 = Element(info=[b1, b1]) el1.weight = w1 el2 = Element(info=[b2, b2]) el2.weight = w2 el3 = Element(info=[b1, b2]) el3.weight = w3 el1 += el2 self.assertEqual(el1.weight[0].value, 32. * fb) self.assertEqual( el1.pdg, [[1000021, [1000022, 1000023]], [1000021, [1000022, 1000023]]]) self.assertEqual(el1.getAverage('mass'), [[gluino.mass, (n1.mass + n2.mass) / 2.]] * 2) el1 += el3 self.assertEqual(el1.weight[0].value, 34. * fb) self.assertEqual( el1.pdg, [[1000021, [1000022, 1000023]], [1000021, [1000022, 1000023]]]) self.assertEqual(el1.getAverage('mass'), [[gluino.mass, (n1.mass + n2.mass) / 2.]] * 2)
def testEffReweight(self): n1 = mssm.n1.copy() n1.totalwidth = 1e-18 * GeV st1 = mssm.st1.copy() st1.totalwidth = 5e-15 * GeV gluino = mssm.gluino.copy() gluino.totalwidth = 1e-15 * GeV branch1 = Branch() branch1.oddParticles = [st1, n1] branch2 = Branch() branch2.oddParticles = [gluino, n1] el1 = Element([branch1, branch2]) r = defaultEffReweight(el1) #Use default values self.assertAlmostEqual(r * 1e5, 6.991, places=2) r = defaultEffReweight(el1, Leff_inner=0.1, Leff_outer=15.0) self.assertAlmostEqual(r, 0.314, places=2)
def __init__(self, info=None, finalState=None, intermediateState=None, model=None): """ Initializes the element. If info is defined, tries to generate the element using it. :parameter info: string describing the element in bracket notation (e.g. [[[e+],[jet]],[[e-],[jet]]]) :parameter finalState: list containing the final state labels for each branch (e.g. ['MET', 'HSCP'] or ['MET','MET']) :parameter intermediateState: nested list containing intermediate state labels for each branch (e.g. [['gluino'], ['gluino']]) :parameter model: The model (Model object) to be used when converting particle labels to particle objects (only used if info, finalState or intermediateState != None). """ self.branches = [Branch(), Branch()] self.weight = crossSection.XSectionList( ) # gives the weight for all decays promptly self.decayLabels = [] self.motherElements = [ self ] #The motheElements includes self to keep track of merged elements self.elID = 0 self.coveredBy = set() self.testedBy = set() if info: # Create element from particle string if type(info) == type(str()): elements = elementsInStr(info) if not elements or len(elements) > 1: nel = 0 if elements: nel = len(elements) logger.error( "Malformed input string. Number of elements " "is %d (expected 1) in: ``%s''", nel, info) return None else: el = elements[0] branches = elementsInStr(el[1:-1]) if not branches or len(branches) != 2: logger.error( "Malformed input string. Number of " "branches is %d (expected 2) in: ``%s''", len(branches), info) return None self.branches = [] if intermediateState: if len(intermediateState) != len(branches): raise SModelSError( "Number of intermediate states (%i) does not match number of branches (%i)" % (len(intermediateState), len(branches))) else: intermediateState = [None] * len(branches) if finalState: if len(finalState) != len(branches): raise SModelSError( "Number of final states (%i) does not match number of branches (%i)" % (len(finalState), len(branches))) else: finalState = [None] * len(branches) for ibr, branch in enumerate(branches): if branch == '[*]': self.branches.append( InclusiveBranch( finalState[ibr], intermediateState=intermediateState[ibr], model=model)) else: self.branches.append( Branch(branch, finalState[ibr], intermediateState[ibr], model=model)) # Create element from branch pair elif isinstance(info, list) and all( isinstance(x, (Branch, InclusiveBranch)) for x in info): self.branches = [br.copy() for br in info] else: raise SModelSError( "Can not create element from input type %s" % type(info)) self.setEinfo()
def testElementInclusive(self): b1 = Branch() b1.evenParticles = [[em], [em, nue]] b1.oddParticles = [gluino, st1, n1] b1.setInfo() b1b = Branch() b1b.evenParticles = [[L], [L, nue]] b1b.oddParticles = [gluino, st1, n1] b1b.setInfo() b2 = Branch() b2.evenParticles = [[L, nue]] b2.oddParticles = [st1, n1] b2.setInfo() b2b = Branch() b2b.evenParticles = [[em, nue]] b2b.oddParticles = [st1, n1] b2b.setInfo() el1 = Element() el1.branches = [b1, b2] el2 = Element() el2.branches = [b2b, b1b] self.assertTrue(el1 == el2) #Elements match (using inclusive labels)
def testElementStr(self): b1 = Branch() b1.evenParticles = [ParticleList([t]), ParticleList([b, t])] b1.oddParticles = [gluino, st1, n1] b2 = Branch() b2.evenParticles = [ParticleList([b, t])] b2.oddParticles = [st1, n1] b1.setInfo() b2.setInfo() el1 = Element() el1.branches = [b1, b2] elstrA = Element('[[[t+],[b,t+]],[[b,t+]]]', finalState=['MET', 'MET'], model=finalStates) elstrB = Element('[[[b,t+]],[[t+],[b,t+]]]', finalState=['MET', 'MET'], model=finalStates) elstrC = Element('[[[b,t+]],[[t],[b,t]]]', finalState=['MET', 'MET'], model=finalStates) self.assertTrue(el1 == elstrA) #Elements should be equal self.assertTrue( el1 == elstrB) #Elements should be equal (only branch order differs) self.assertTrue( el1 == elstrC) #Elements should be equal (inclusive labels)
def decompose(model, sigmacut=0.1 * fb, doCompress=True, doInvisible=True, minmassgap=0 * GeV): """ Perform decomposition using the information stored in model. :param sigmacut: minimum sigma*BR to be generated, by default sigmacut = 0.1 fb :param doCompress: turn mass compression on/off :param doInvisible: turn invisible compression on/off :param minmassgap: maximum value (in GeV) for considering two R-odd particles degenerate (only revelant for doCompress=True ) :returns: list of topologies (TopologyList object) """ t1 = time.time() xSectionList = model.xsections pdgList = model.getValuesFor('pdg') if doCompress and minmassgap / GeV < 0.: logger.error( "Asked for compression without specifying minmassgap. Please set minmassgap." ) raise SModelSError() if isinstance(sigmacut, (float, int)): sigmacut = sigmacut * fb sigmacut = sigmacut.asNumber(fb) xSectionList.removeLowerOrder() # Order xsections by PDGs to improve performance xSectionList.order() # Get maximum cross sections (weights) for single particles (irrespective # of sqrtS) maxWeight = {} for pid in xSectionList.getPIDs(): maxWeight[pid] = xSectionList.getXsecsFor(pid).getMaxXsec().asNumber( fb) # Generate dictionary, where keys are the PIDs and values # are the list of cross sections for the PID pair (for performance) xSectionListDict = {} for pids in xSectionList.getPIDpairs(): xSectionListDict[pids] = xSectionList.getXsecsFor(pids) # Create 1-particle branches with all possible mothers branchList = [] for pid in maxWeight: branchList.append(Branch()) bsmParticle = model.getParticlesWith(pdg=pid) if not bsmParticle: raise SModelSError("Particle for pdg %i has not been defined.") if len(bsmParticle) != 1: raise SModelSError( "Particle with pdg %i has multiple definitions.") branchList[-1].oddParticles = [bsmParticle[0]] if not pid in pdgList: logger.error("PDG %i has not been defined" % int(pid)) branchList[-1].maxWeight = maxWeight[pid] # Generate final branches (after all R-odd particles have decayed) finalBranchList = decayBranches(branchList, sigmacut) # Generate dictionary, where keys are the PIDs and values are the list of branches for the PID (for performance) branchListDict = {} for branch in finalBranchList: if branch.oddParticles[0].pdg in branchListDict: branchListDict[branch.oddParticles[0].pdg].append(branch) else: branchListDict[branch.oddParticles[0].pdg] = [branch] for pid in xSectionList.getPIDs(): if not pid in branchListDict: branchListDict[pid] = [] #Sort the branch lists by max weight to improve performance: for pid in branchListDict: branchListDict[pid] = sorted(branchListDict[pid], key=lambda br: br.maxWeight, reverse=True) smsTopList = topology.TopologyList() # Combine pairs of branches into elements according to production # cross section list for pids in xSectionList.getPIDpairs(): weightList = xSectionListDict[pids] maxxsec = weightList.getMaxXsec().asNumber(fb) if maxxsec == 0.: ## protection continue minBR = sigmacut / maxxsec if minBR > 1.: continue for branch1 in branchListDict[pids[0]]: BR1 = branch1.maxWeight / maxWeight[ pids[0]] #Branching ratio for first branch if BR1 < minBR: break #Stop loop if BR1 is already too low for branch2 in branchListDict[pids[1]]: BR2 = branch2.maxWeight / maxWeight[ pids[1]] #Branching ratio for second branch if BR2 < minBR: break #Stop loop if BR2 is already too low finalBR = BR1 * BR2 if finalBR < minBR: continue # Skip elements with xsec below sigmacut newElement = element.Element([branch1, branch2]) newElement.weight = weightList * finalBR newElement.sortBranches( ) #Make sure elements are sorted BEFORE adding them smsTopList.addElement(newElement) smsTopList.compressElements(doCompress, doInvisible, minmassgap) smsTopList._setElementIds() logger.debug("decomposer done in %.2f s." % (time.time() - t1)) return smsTopList
def testElement(self): b1 = Branch() b1.evenParticles = [[t], [b, t]] b1.oddParticles = [gluino, st1, n1] b2 = Branch() b2.evenParticles = [[b, t]] b2.oddParticles = [st1, n1] b1.setInfo() b2.setInfo() el1 = Element() el1.branches = [b1, b2] el2 = Element() el2.branches = [b2, b2] el1B = Element() el1B.branches = [b2, b1] self.assertEqual(el1 > el2, True) #Bigger by number of vertices self.assertEqual(el1, el1B) #Just differ by branch ordering el1.sortBranches() e1Info = {"vertnumb": [1, 2], "vertparts": [[2], [1, 2]]} self.assertEqual(el1.getEinfo() == e1Info, True)
def testElementMassComp(self): b1 = Branch() b1.evenParticles = [[t], [b, t]] b1.oddParticles = [gluino, st1, n1] b2 = Branch() b2.evenParticles = [[b, t]] b2.oddParticles = [st1, n1] b1.setInfo() b2.setInfo() el1 = Element() el1.branches = [b1, b2] #Compress gluino-stop1 gluino.mass = 400. * GeV gluino.totalwidth = float('inf') * GeV st1.mass = 398. * GeV st1.totalwidth = float('inf') * GeV n1.mass = 390. * GeV n1.totalwidth = 0. * GeV el1Comp = el1.massCompress(minmassgap=5. * GeV) b1Comp = Branch() b1Comp.evenParticles = [[b, t]] b1Comp.oddParticles = [st1, n1] b2Comp = Branch() b2Comp.evenParticles = [[b, t]] b2Comp.oddParticles = [st1, n1] el2 = Element() el2.branches = [b1Comp, b2Comp] el2.setEinfo() self.assertEqual(el1Comp, el2) #Elements should be equal #Compress stop1-neutralino1 gluino.mass = 400. * GeV st1.mass = 393. * GeV n1.mass = 390. * GeV el1Comp = el1.massCompress(minmassgap=5. * GeV) b1Comp = Branch() b1Comp.evenParticles = [[t]] b1Comp.oddParticles = [gluino, n1] b2Comp = Branch() b2Comp.evenParticles = [] b2Comp.oddParticles = [n1] el2 = Element(info=[b1Comp, b2Comp]) el1.sortBranches() el2.sortBranches() self.assertEqual(el1Comp, el2) #Elements should be equal #Compress everything el1Comp = el1.massCompress(minmassgap=10. * GeV) #Fully compress b1Comp = Branch() b1Comp.evenParticles = [] b1Comp.oddParticles = [n1] b2Comp = b1Comp.copy() el2 = Element(info=[b1Comp, b2Comp]) self.assertEqual(el1Comp, el2) #Elements should be equal
def testElementInvComp(self): gluino.mass = 500. * GeV st1.mass = 400. * GeV n1.mass = 300. * GeV n2.mass = 310. * GeV n3.mass = 320. * GeV n4.mass = 330. * GeV #Compress one step: #N3 --> N1 + [nue,nue] #gluino --> st_1 + [t+]/st_1 --> N3 + [t+]/N3 --> N1 + [nue,nue] b1 = Branch() b1.evenParticles = [[t], [t], [nue, nue]] b1.oddParticles = [gluino, st1, n3, n1] b2 = Branch() b2.evenParticles = [[nue, nue]] b2.oddParticles = [n3, n1] el1 = Element(info=[b1, b2]) el1Comp = el1.invisibleCompress() b1Comp = Branch() b1Comp.evenParticles = [[t], [t]] b1Comp.oddParticles = [gluino, st1, n3] b2Comp = Branch() b2Comp.evenParticles = [] b2Comp.oddParticles = [n3] el2 = Element(info=[b1Comp, b2Comp]) el2.sortBranches() self.assertEqual(el1Comp, el2) #Elements should be equal #Compress two steps: #N3 --> N1 + [nue,nue] #gluino --> st_1 + [t+]/st_1 --> N3 + [t+]/N3 --> N2 + [nue]/N2 --> N1 + [nue,nue,nue,nue] b1 = Branch() b1.evenParticles = [[nue, nue]] b1.oddParticles = [n3, n1] b2 = Branch() b2.evenParticles = [[t], [t], [nue], [nue, nue, nue, nue]] b2.oddParticles = [gluino, st1, n3, n2, n1] el1 = Element(info=[b1, b2]) el1Comp = el1.invisibleCompress() b1Comp = Branch() b1Comp.evenParticles = [] b1Comp.oddParticles = [n3] b2Comp = Branch() b2Comp.evenParticles = [[t], [t]] b2Comp.oddParticles = [gluino, st1, n3] el2 = Element(info=[b1Comp, b2Comp]) self.assertEqual(el1Comp, el2) #Elements should be equal #Make sure compression only happens at the end: #N3 --> N1 + [nue,nue] #gluino --> st_1 + [t+]/st_1 --> N3 + [t+]/N3 --> N2 + [nue]/N2 --> N1 + [e-,nue,nue,nue] b1 = Branch() b1.evenParticles = [[nue, nue]] b1.oddParticles = [n3, n1] b2 = Branch() b2.evenParticles = [[t], [t], [nue], [e, nue, nue, nue]] b2.oddParticles = [gluino, st1, n3, n2, n1] el1 = Element(info=[b1, b2]) el1Comp = el1.invisibleCompress() b1Comp = Branch() b1Comp.evenParticles = [] b1Comp.oddParticles = [n3] b2Comp = b2.copy() el2 = Element(info=[b1Comp, b2Comp]) self.assertEqual(el1Comp, el2) #Elements should be equal
n3 = mssm.n3 n4 = mssm.n4 w1 = XSectionList() w1.xSections.append(XSection()) w1.xSections[0].info = XSectionInfo() w1.xSections[0].info.sqrts = 8. * TeV w1.xSections[0].info.label = '8 TeV' w1.xSections[0].info.order = 0 w1.xSections[0].value = 10. * fb w2 = w1.copy() w2.xSections[0].value = 22. * fb w3 = w1.copy() w3.xSections[0].value = 2. * fb b1 = Branch() b1.evenParticles = [[t], [b, t]] b1.oddParticles = [gluino, st1, n1] b1b = Branch() b1b.evenParticles = [[t], [b, t]] b1b.oddParticles = [gluino, st1, n1] b2 = Branch() b2.evenParticles = [[b, t]] b2.oddParticles = [st1, n1] b1.setInfo() b2.setInfo() el1 = Element() el1.branches = [b1, b2] el1.weight = w1 el2 = Element()
def testUncovered(self): topolist = TopologyList() # prompt b1 = Branch() b1.evenParticles = [[b,t]] b1.oddParticles = [st1,n1] b1.setInfo() el1 = Element() el1.branches=[b1,b1] # long-lived b3 = Branch() b3.evenParticles = [] b3.oddParticles = [gluino] b4 = Branch() b4.evenParticles = [[b,t]] b4.oddParticles = [st1,n1] b3.setInfo() b4.setInfo() el2 = Element() el2.branches=[b3,b4] # prompt and displaced b5 = Branch() b5.evenParticles = [[t],[b,t]] b5.oddParticles = [st2,st1,n1] b6 = Branch() b6.evenParticles = [[b,t]] b6.oddParticles = [st1,n1] b5.setInfo() b6.setInfo() el3 = Element() el3.branches=[b5,b6] w1 = XSectionList() w1.xSections.append(XSection()) w1.xSections[0].info = XSectionInfo() w1.xSections[0].info.sqrts = 8.*TeV w1.xSections[0].info.label = '8 TeV' w1.xSections[0].info.order = 0 w1.xSections[0].value = 10.*fb el1.weight = w1 el2.weight = w1 el3.weight = w1 topolist.addElement(el1) topolist.addElement(el2) topolist.addElement(el3) topolist._setElementIds() uncovered = Uncovered(topolist,groupFilters=filters,groupFactors=factors) longLived = uncovered.getGroup('missing non-MET (prompt)') MET = uncovered.getGroup('missing MET (prompt)') displaced = uncovered.getGroup('missing (displaced)') self.assertEqual(len(longLived.generalElements), 1) self.assertEqual(len(displaced.generalElements), 1) self.assertEqual(len(MET.generalElements), 2) self.assertAlmostEqual(longLived.generalElements[0].missingX, 10.) self.assertAlmostEqual(displaced.generalElements[0].missingX, 9.96109334317542,places=4) self.assertAlmostEqual(MET.generalElements[0].missingX, 10.) self.assertAlmostEqual(MET.generalElements[1].missingX, 0.03890665682,places=4)
def testTxnameDataReweight(self): c1 = mssm.c1.copy() c1.totalwidth = 1e-17 * GeV c1.mass = 100 * GeV gluino = mssm.gluino.copy() gluino.totalwidth = 1e-15 * GeV gluino.mass = 500 * GeV branch1 = Branch() branch1.oddParticles = [gluino, c1] branch2 = Branch() branch2.oddParticles = [gluino, c1] el1 = Element([branch1, branch2]) listofanalyses = database.getExpResults(analysisIDs=["CMS-EXO-13-006"], dataTypes=['efficiencyMap']) exp = listofanalyses[0] ds = [d for d in exp.datasets if d.dataInfo.dataId == 'c000'][0] tx = [t for t in ds.txnameList if str(t) == 'THSCPM3'][0] effDefault = tx.getEfficiencyFor(el1) self.assertAlmostEqual(tx.txnameData.Leff_inner, 0.007) self.assertAlmostEqual(tx.txnameData.Leff_outer, 7.0) self.assertAlmostEqual(effDefault / 1e-5, 5.223348, places=3) ds = [d for d in exp.datasets if d.dataInfo.dataId == 'c000track'][0] tx = [t for t in ds.txnameList if str(t) == 'THSCPM3'][0] effNewSize = tx.getEfficiencyFor(el1) self.assertAlmostEqual(tx.txnameData.Leff_inner, 0.007) self.assertAlmostEqual(tx.txnameData.Leff_outer, 3.0) self.assertAlmostEqual(effNewSize / 1e-5, 7.83466, places=3) branch1 = Branch() branch1.oddParticles = [c1] branch2 = Branch() branch2.oddParticles = [c1] el2 = Element([branch1, branch2]) ds = [d for d in exp.datasets if d.dataInfo.dataId == 'c000'][0] tx = [t for t in ds.txnameList if str(t) == 'THSCPM1'][0] effDefault = tx.getEfficiencyFor(el2) self.assertAlmostEqual(tx.txnameData.Leff_inner, 0.007) self.assertAlmostEqual(tx.txnameData.Leff_outer, 7.0) self.assertAlmostEqual(effDefault, 0.073292924, places=3) ds = [d for d in exp.datasets if d.dataInfo.dataId == 'c000track'][0] tx = [t for t in ds.txnameList if str(t) == 'THSCPM1'][0] effNewSize = tx.getEfficiencyFor(el2) self.assertAlmostEqual(tx.txnameData.Leff_inner, 0.1) self.assertAlmostEqual(tx.txnameData.Leff_outer, 5.0) self.assertAlmostEqual(effNewSize, 0.0897630, places=3)
def decompose(slhafile, sigcut=.1 * fb, doCompress=False, doInvisible=False, minmassgap=-1. * GeV, useXSecs=None): """ Perform SLHA-based decomposition. :param sigcut: minimum sigma*BR to be generated, by default sigcut = 0.1 fb :param doCompress: turn mass compression on/off :param doInvisible: turn invisible compression on/off :param minmassgap: maximum value (in GeV) for considering two R-odd particles degenerate (only revelant for doCompress=True ) :param useXSecs: optionally a dictionary with cross sections for pair production, by default reading the cross sections from the SLHA file. :returns: list of topologies (TopologyList object) """ t1 = time.time() if doCompress and minmassgap / GeV < 0.: logger.error( "Asked for compression without specifying minmassgap. Please set minmassgap." ) raise SModelSError() if type(sigcut) == type(1.): sigcut = sigcut * fb try: f = pyslha.readSLHAFile(slhafile) except pyslha.ParseError as e: logger.error("The file %s cannot be parsed as an SLHA file: %s" % (slhafile, e)) raise SModelSError() # Get cross section from file xSectionList = crossSection.getXsecFromSLHAFile(slhafile, useXSecs) # Get BRs and masses from file brDic, massDic = _getDictionariesFromSLHA(slhafile) # Only use the highest order cross sections for each process xSectionList.removeLowerOrder() # Order xsections by PDGs to improve performance xSectionList.order() # Get maximum cross sections (weights) for single particles (irrespective # of sqrtS) maxWeight = {} for pid in xSectionList.getPIDs(): maxWeight[pid] = xSectionList.getXsecsFor(pid).getMaxXsec() # Generate dictionary, where keys are the PIDs and values # are the list of cross sections for the PID pair (for performance) xSectionListDict = {} for pids in xSectionList.getPIDpairs(): xSectionListDict[pids] = xSectionList.getXsecsFor(pids) # Create 1-particle branches with all possible mothers branchList = [] for pid in maxWeight: branchList.append(Branch()) branchList[-1].PIDs = [[pid]] if not pid in massDic: logger.error( "pid %d does not appear in masses dictionary %s in slhafile %s" % (pid, massDic, slhafile)) branchList[-1].masses = [massDic[pid]] branchList[-1].maxWeight = maxWeight[pid] # Generate final branches (after all R-odd particles have decayed) finalBranchList = decayBranches(branchList, brDic, massDic, sigcut) # Generate dictionary, where keys are the PIDs and values are the list of branches for the PID (for performance) branchListDict = {} for branch in finalBranchList: if len(branch.PIDs) != 1: logger.error("During decomposition the branches should \ not have multiple PID lists!") return False if branch.PIDs[0][0] in branchListDict: branchListDict[branch.PIDs[0][0]].append(branch) else: branchListDict[branch.PIDs[0][0]] = [branch] for pid in xSectionList.getPIDs(): if not pid in branchListDict: branchListDict[pid] = [] #Sort the branch lists by max weight to improve performance: for pid in branchListDict: branchListDict[pid] = sorted(branchListDict[pid], key=lambda br: br.maxWeight, reverse=True) smsTopList = topology.TopologyList() # Combine pairs of branches into elements according to production # cross section list for pids in xSectionList.getPIDpairs(): weightList = xSectionListDict[pids] minBR = (sigcut / weightList.getMaxXsec()).asNumber() if minBR > 1.: continue for branch1 in branchListDict[pids[0]]: BR1 = branch1.maxWeight / maxWeight[ pids[0]] #Branching ratio for first branch if BR1 < minBR: break #Stop loop if BR1 is already too low for branch2 in branchListDict[pids[1]]: BR2 = branch2.maxWeight / maxWeight[ pids[1]] #Branching ratio for second branch if BR2 < minBR: break #Stop loop if BR2 is already too low finalBR = BR1 * BR2 if type(finalBR) == type(1. * fb): finalBR = finalBR.asNumber() if finalBR < minBR: continue # Skip elements with xsec below sigcut if len(branch1.PIDs) != 1 or len(branch2.PIDs) != 1: logger.error("During decomposition the branches should \ not have multiple PID lists!") return False newElement = element.Element([branch1, branch2]) newElement.weight = weightList * finalBR allElements = [newElement] # Perform compression if doCompress or doInvisible: allElements += newElement.compressElement( doCompress, doInvisible, minmassgap) for el in allElements: el.sortBranches( ) #Make sure elements are sorted BEFORE adding them smsTopList.addElement(el) smsTopList._setElementIds() logger.debug("slhaDecomposer done in %.2f s." % (time.time() - t1)) return smsTopList
# Get maximum cross-sections (weights) for single particles (irrespective # of sqrtS) maxWeight = {} for pid in xSectionList.getPIDs(): maxWeight[pid] = xSectionList.getXsecsFor(pid).getMaxXsec() # Generate dictionary, where keys are the PIDs and values # are the list of cross-sections for the PID pair (for performance) xSectionListDict = {} for pids in xSectionList.getPIDpairs(): xSectionListDict[pids] = xSectionList.getXsecsFor(pids) # Create 1-particle branches with all possible mothers branchList = [] for pid in maxWeight: branchList.append(Branch()) branchList[-1].momID = pid branchList[-1].daughterID = pid branchList[-1].masses = [massDic[pid]] branchList[-1].maxWeight = maxWeight[pid] # Generate final branches (after all R-odd particles have decayed) finalBranchList = decayBranches(branchList, brDic, massDic, sigcut) # Generate dictionary, where keys are the PIDs and values are the list of branches for the PID (for performance) branchListDict = {} for branch in finalBranchList: if branch.momID in branchListDict: branchListDict[branch.momID].append(branch) else: branchListDict[branch.momID] = [branch] for pid in xSectionList.getPIDs():
def testSimpleCluster(self): """ test the mass clusterer """ data = [[[[674.99 * GeV, 199.999 * GeV], [674.99 * GeV, 199.999 * GeV]], .03 * fb], [[[725.0001 * GeV, 200. * GeV], [725.0001 * GeV, 200. * GeV]], .06 * fb], [[[750. * GeV, 250. * GeV], [750. * GeV, 250. * GeV]], .03 * fb]] info = Info( "./database/8TeV/ATLAS/ATLAS-SUSY-2013-05/data/dataInfo.txt") globalInfo = Info( "./database/8TeV/ATLAS/ATLAS-SUSY-2013-05/globalInfo.txt") txnameData = TxNameData(data, "upperLimit", Id=1) txname = TxName( "./database/8TeV/ATLAS/ATLAS-SUSY-2013-05/data/T2bb.txt", globalInfo, info, finalStates) txname.txnameData = txnameData dataset = DataSet(info=globalInfo, createInfo=False) dataset.dataInfo = info dataset.txnameList = [txname] u = SMparticles.u gluino = mssm.gluino.copy() gluino.__setattr__("mass", 675. * GeV) gluino.__setattr__('totalwidth', float('inf') * GeV) n1 = mssm.n1.copy() n1.__setattr__("mass", 200. * GeV) n1.__setattr__('totalwidth', 0. * GeV) w1 = XSectionList() w1.xSections.append(XSection()) w1.xSections[0].info = XSectionInfo() w1.xSections[0].info.sqrts = 8. * TeV w1.xSections[0].info.label = '8 TeV' w1.xSections[0].info.order = 0 w1.xSections[0].value = 10. * fb b1 = Branch() b1.evenParticles = [[u, u]] b1.oddParticles = [gluino, n1] b2 = b1.copy() el1 = Element() el1.branches = [b1, b2] el1.weight = w1 el1.txname = txname el1.eff = 1. #(Used in clustering) ## make a second element with a slightly different gluino mass el2 = el1.copy() el2.motherElements = [el2] #Enforce el2 and el1 not to be related el2.txname = txname el2.branches[0].oddParticles = [ ptc.copy() for ptc in el1.branches[0].oddParticles ] el2.branches[1].oddParticles = [ ptc.copy() for ptc in el1.branches[1].oddParticles ] el2.branches[0].oddParticles[0].__setattr__("mass", 725. * GeV) el2.branches[1].oddParticles[0].__setattr__("mass", 725. * GeV) el2.eff = 1. #(Used in clustering) #Cluster for upper limits (all elements close in upper limit should be clustered together) maxDist = 5. #Cluster all elements newel = clusterTools.clusterElements([el1, el2], maxDist, dataset)[0] newmasses = newel.averageElement().mass self.assertEqual(newmasses, [[700. * GeV, 200. * GeV]] * 2) maxDist = 0.5 #Elements differ and should not be clustered newel = clusterTools.clusterElements([el1, el2], maxDist, dataset) #in this example the distance is not in maxdist, so we dont cluster self.assertTrue(len(newel) == 2) info = Info( "./database/8TeV/CMS/CMS-SUS-13-012-eff/6NJet8_1000HT1250_200MHT300/dataInfo.txt" ) globalInfo = Info( "./database/8TeV/CMS/CMS-SUS-13-012-eff/globalInfo.txt") txnameData = TxNameData(data, "efficiencyMap", Id=1) txname = TxName( "./database/8TeV/CMS/CMS-SUS-13-012-eff/6NJet8_1000HT1250_200MHT300/T2.txt", globalInfo, info, finalStates) txname.txnameData = txnameData dataset = DataSet(info=globalInfo, createInfo=False) dataset.dataInfo = info dataset.txnameList = [txname] #Cluster for efficiency maps (all elements should be clustered together independent of maxDist) maxDist = 0.001 newel = clusterTools.clusterElements([el1, el2], maxDist, dataset)[0] newmasses = newel.averageElement().mass self.assertEqual(newmasses, [[700. * GeV, 200. * GeV]] * 2)
def testClustererLifeTimes(self): """ test the clustering with distinct lifetimes""" data = [[[[674.99 * GeV, 199.999 * GeV], [674.99 * GeV, 199.999 * GeV]], .03 * fb], [[[725.0001 * GeV, 200. * GeV], [725.0001 * GeV, 200. * GeV]], .06 * fb], [[[750. * GeV, 250. * GeV], [750. * GeV, 250. * GeV]], .03 * fb]] info = Info( "./database/8TeV/ATLAS/ATLAS-SUSY-2013-05/data/dataInfo.txt") globalInfo = Info( "./database/8TeV/ATLAS/ATLAS-SUSY-2013-05/globalInfo.txt") txnameData = TxNameData(data, "upperLimit", Id=1) txname = TxName( "./database/8TeV/ATLAS/ATLAS-SUSY-2013-05/data/T2bb.txt", globalInfo, info, finalStates) txname.txnameData = txnameData dataset = DataSet(info=globalInfo, createInfo=False) dataset.dataInfo = info dataset.txnameList = [txname] u = SMparticles.u gluino = mssm.gluino.copy() gluino.__setattr__("mass", 675. * GeV) gluino.__setattr__('totalwidth', 1e-15 * GeV) n1 = mssm.n1.copy() n1.__setattr__("mass", 200. * GeV) n1.__setattr__('totalwidth', 0. * GeV) w1 = XSectionList() w1.xSections.append(XSection()) w1.xSections[0].info = XSectionInfo() w1.xSections[0].info.sqrts = 8. * TeV w1.xSections[0].info.label = '8 TeV' w1.xSections[0].info.order = 0 w1.xSections[0].value = 10. * fb b1 = Branch() b1.evenParticles = [ParticleList([u, u])] b1.oddParticles = [gluino, n1] b2 = b1.copy() el1 = Element() el1.branches = [b1, b2] el1.weight = w1 el1.txname = txname el1.eff = 1. #(Used in clustering) ## make a second element with a slightly different gluino width el2 = el1.copy() el2.motherElements = [el2] #Enforce el2 and el1 not to be related el2.txname = txname el2.branches[0].oddParticles = [ ptc.copy() for ptc in el1.branches[0].oddParticles ] el2.branches[1].oddParticles = [ ptc.copy() for ptc in el1.branches[1].oddParticles ] el2.eff = 1. #(Used in clustering) el2.branches[0].oddParticles[0].__setattr__("mass", 675. * GeV) el2.branches[1].oddParticles[0].__setattr__("mass", 675. * GeV) el2.branches[0].oddParticles[0].__setattr__("totalwidth", 0.9e-15 * GeV) el2.branches[1].oddParticles[0].__setattr__("totalwidth", 0.9e-15 * GeV) newel = clusterTools.clusterElements([el1, el2], 5., dataset) ## this example gives an avg cluster mass of 700 gev self.assertEqual(newel[0].averageElement().mass[0][0], 675. * GeV) self.assertAlmostEqual( newel[0].averageElement().totalwidth[0][0].asNumber(GeV) * 1e15, 0.95) newel = clusterTools.clusterElements([el1, el2], .5, dataset) #in this example the distance is in maxdist, so we cluster self.assertTrue(len(newel) == 1) newel = clusterTools.clusterElements([el1, el2], .1, dataset) #in this example the distance is not in maxdist, so we dont cluster self.assertTrue(len(newel) == 2)