ATLAS Offline Software
TriggerInfo.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 __author__ = 'Javier Montejo'
4 __version__="$Revision: 2.0 $"
5 __doc__="Class containing all the information of an HLT chain"
6 
7 import re
8 from TriggerMenuMT.TriggerAPI.TriggerEnums import TriggerType, TriggerPeriod
9 from collections import Counter
10 import six
11 from AthenaCommon.Logging import logging
12 log = logging.getLogger(__name__)
13 
15  ''' Object containing all the HLT information related to a given period.
16  Stores a list of TriggerChain objects and the functions to skim them
17  '''
18  def __init__(self,period=0, customGRL=None, release=None, flags=None):
19  self.triggerChains = []
20  self.period = period
21  self.totalLB = 0
22  self.totalLBByRun = {}
23 
24  if not period and not customGRL: return
25  from .TriggerDataAccess import getHLTlist
26  HLTlist, self.totalLB, self.totalLBByRun = getHLTlist(period, customGRL, release, flags)
27  for hlt, l1, livefraction, activeLB, hasRerun, activeLBByRun in HLTlist:
28  self.triggerChains.append( TriggerChain(hlt, l1, livefraction, activeLB, hasRerun, activeLBByRun))
29 
30  def setRunRange(self,start=0,end=999999):
31  if not self.totalLBByRun:
32  # empty dict means either loaded from trigger menu or from old json
33  totalLB = self.totalLB
34  else:
35  totalLB = 0
36  for run,efflb in self.totalLBByRun.items():
37  if int(run)<int(start) or int(run)>int(end): continue
38  totalLB += efflb
39  for tc in self.triggerChains:
40  tc.setRunRange(start,end,totalLB)
41 
42  def __str__(self):
43  return f"<TriggerMenuMT.TriggerAPI.TriggerInfo.TriggerInfo object with {len(self.triggerChains)} triggerChains, period={self.period}, totalLB={self.totalLB}>"
44 
45  def toJSON(self):
46  return dict(period= TriggerPeriod.toName(self.period), totalLB=self.totalLB,triggerChains=self.triggerChains,totalLBByRun=self.totalLBByRun)
47 
48  @classmethod
49  def merge(cls,listofTI):
50  from copy import deepcopy
51  mergedTI = TriggerInfo()
52  mergedHLTmap = {}
53  for ti in listofTI:
54  mergedTI.period |= ti.period
55  mergedTI.totalLB += ti.totalLB
56  for run,lb in ti.totalLBByRun.items():
57  if run not in mergedTI.totalLBByRun: mergedTI.totalLBByRun[run] = 0
58  mergedTI.totalLBByRun[run] += lb
59  for tc in ti.triggerChains:
60  if tc.name not in mergedHLTmap: mergedHLTmap[tc.name] = deepcopy(tc)
61  else: mergedHLTmap[tc.name].activeLB += tc.activeLB
62  # copy activeLBByRun values too
63  for run,lb in tc.activeLBByRun.items():
64  if run not in mergedHLTmap[tc.name].activeLBByRun: mergedHLTmap[tc.name].activeLBByRun = 0
65  mergedHLTmap[tc.name].activeLBByRun += lb
66  for tc in six.itervalues (mergedHLTmap):
67  tc.livefraction = tc.activeLB/float(mergedTI.totalLB)
68  mergedTI.triggerChains = list(mergedHLTmap.values())
69  return mergedTI
70 
71 
72  @classmethod
73  def testCustomGRL(cls, grl):
74  from TriggerMenuMT.TriggerAPI.TriggerPeriodData import TriggerPeriodData
75  return TriggerPeriodData.testCustomGRL(grl)
76 
77  def reparse(self):
78  self.triggerChains = [ TriggerChain(t.name, t.l1seed, t.livefraction, t.activeLB) for t in self.triggerChains ]
79 
80  def _getUnprescaled(self,triggerType, additionalTriggerType, matchPattern, livefraction=1.0):
81  return [x.name for x in self.triggerChains if x.isUnprescaled(livefraction) and x.passType(triggerType, additionalTriggerType) and re.search(matchPattern, x.name)]
82 
83  def _getLowestUnprescaled(self,triggerType, additionalTriggerType, matchPattern, livefraction=1.0):
84  chainList = [ x for x in self.triggerChains if x.isUnprescaled(livefraction) and x.passType(triggerType, additionalTriggerType) and re.search(matchPattern, x.name)]
85  typeMap = {}
86  for chain in chainList:
87  if chain.triggerType not in typeMap:
88  typeMap[chain.triggerType] = [chain]
89  continue
90  append = False
91  for other in typeMap[chain.triggerType][:]:
92  comp = chain.isLowerThan(other,self.period)
93  if comp == 0:
94  append = False
95  break
96  append = True
97  if comp == 1: typeMap[chain.triggerType].remove(other)
98  if append:
99  typeMap[chain.triggerType].append(chain)
100  return [x.name for t in six.itervalues (typeMap) for x in t ]
101 
102 
103  def _getAllHLT(self,triggerType, additionalTriggerType, matchPattern, livefraction):
104  return {x.name: x.livefraction for x in self.triggerChains if x.passType(triggerType, additionalTriggerType) and re.search(matchPattern, x.name) and x.isUnprescaled(livefraction)}
105 
106  def _getActive(self,triggerType, additionalTriggerType, matchPattern, livefraction):
107  return [x.name for x in self.triggerChains if x.isActive(livefraction) and x.passType(triggerType, additionalTriggerType) and re.search(matchPattern, x.name)]
108  def _getInactive(self,triggerType, additionalTriggerType, matchPattern, livefraction):
109  return [x.name for x in self.triggerChains if x.isInactive(livefraction) and x.passType(triggerType, additionalTriggerType) and re.search(matchPattern, x.name)]
110 
111  def _checkPeriodConsistency(self,triggerType, additionalTriggerType, matchPattern):
112  inconsistent = set()
113  for i in range(len(self.triggerChains)):
114  probe1 = self.triggerChains[i]
115  if not (probe1.passType(triggerType, additionalTriggerType) and re.search(matchPattern, probe1.name)): continue
116  for j in range(i+1,len(self.triggerChains)):
117  probe2 = self.triggerChains[j]
118  if not (probe2.passType(triggerType, additionalTriggerType) and re.search(matchPattern, probe2.name)): continue
119  if probe1.isUnprescaled() and not probe2.isUnprescaled() and probe1.isLowerThan(probe2,self.period)==1:
120  log.error(f"Found {probe2.name} that is tighter than Primary {probe1.name}")
121  inconsistent.add(probe2.name)
122  if probe2.isUnprescaled() and not probe1.isUnprescaled() and probe2.isLowerThan(probe1,self.period)==1:
123  log.error(f"Found {probe1.name} that is tighter than Primary {probe2.name}")
124  inconsistent.add(probe1.name)
125 
126  return inconsistent
127 
128 
130  types = ('e','j','mu','tau','xe','g','ht')
131  uctTypes = ('isotrk', 'fslrt', 'dedxtrk', 'hitdvjet', 'fsvsi', 'distrk', 'dispjet', 'dispvtx') # unconventional tracking types
132  legpattern = re.compile('([0-9]*)(%s)([0-9]+)(noL1)?' % '|'.join(types+uctTypes))
133  detailpattern = re.compile(r'(?:-?\d+)|(?:[^0-9 -]+)') #split into text-only vs number-only
134  bjetpattern = re.compile('bmv|bhmv|btight|bmedium|bloose|bld1|bgn1|bgn2|bdl1')
135  bphyspattern = re.compile('b[A-Z]')
136  exoticspattern = re.compile('llp|LLP|muvtx|hiptrt|LATE|NOMATCH|distrk|hitdvjet')
137  afppattern = re.compile('afp|AFP')
138 
139  def __init__(self,legname, chainseed, chainname=None):
140  self.legname = legname
141  self.l1seed = ""
142  details = []
143  chainseed= chainseed.replace("L1_","")
144  blocks = legname.split("_L1")
145 
146  for token in blocks[0].split("_"):
147  m = self.legpattern.match(token)
148  if m:
149  count,legtype,thr,noL1 = m.groups()
150  self.count = int(count) if count else 1
151  self.thr = int(thr)
152  if legtype == 'e':
153  if self.count > 1: self.legtype = TriggerType.el_multi
154  else: self.legtype = TriggerType.el_single
155  elif legtype == 'mu':
156  if self.count > 1: self.legtype = TriggerType.mu_multi
157  else: self.legtype = TriggerType.mu_single
158  elif legtype == 'j':
159  if self.count > 1: self.legtype = TriggerType.j_multi
160  else: self.legtype = TriggerType.j_single
161  elif legtype == 'tau':
162  if self.count > 1: self.legtype = TriggerType.tau_multi
163  else: self.legtype = TriggerType.tau_single
164  elif legtype == 'g':
165  if self.count > 1: self.legtype = TriggerType.g_multi
166  else: self.legtype = TriggerType.g_single
167  elif legtype == 'xe':
168  self.legtype = TriggerType.xe
169  elif legtype == 'ht':
170  self.legtype = TriggerType.ht
171  elif legtype in self.uctTypes:
172  self.legtype = TriggerType.exotics
173  # all these leg types are actually distinct, so include legtype in the detail list too
174  details.append(legtype)
175  else:
176  log.info("Unknown trigger type: %s",legtype)
177  if noL1: details.append(noL1)
178  else:
179  if self.bjetpattern.match(token):
180  if self.legtype == TriggerType.j_single: self.legtype = TriggerType.bj_single
181  if self.legtype == TriggerType.j_multi: self.legtype = TriggerType.bj_multi
182  if self.bphyspattern.match(token):
183  self.legtype = TriggerType.mu_bphys
184  if self.exoticspattern.search(token):
185  self.legtype = TriggerType.exotics
186  if self.afppattern.search(token):
187  self.legtype = TriggerType.afp
188  details.append(token)
189 
190  for l1seed in blocks[1:]:
191  if self.exoticspattern.search(l1seed):
192  self.legtype = TriggerType.exotics
193  if self.afppattern.search(l1seed):
194  self.legtype = TriggerType.afp
195  if l1seed == chainseed: continue
196  else:
197  assert self.l1seed=="", (self.l1seed, chainseed, chainname, blocks[1:])
198  self.l1seed = l1seed
199  if not self.l1seed: self.l1seed = chainseed
200  self.details = tuple(details)
201 
202  def __eq__(self,other):
203  return (self.l1seed == other.l1seed and self.count == other.count and self.thr == other.thr and self.legtype == other.legtype and self.details == other.details)
204 
205  def __hash__(self):
206  return hash((self.l1seed,self.count,self.thr,self.legtype,self.details))
207 
208  def __repr__(self):
209  return "{0} l1seed={1} count={2} thr={3} details={4} legtype={5}".format(self.legname,self.l1seed,self.count,self.thr,self.details,TriggerType.toStr(self.legtype))
210 
211  def isLegLowerThan(self, other, is2015, debug=False):
212  ''' Returns -9 if none of them is lower than the other (e.g. different met flavour).
213  Returns -1 if identical
214  Returns 0 if other is lower than self.
215  Returns 1 if self is lower than other.
216  '''
217  if debug:
218  log.info("DEBUG LEGS --------")
219  log.info(f"{self.legname} {other.legname}")
220  log.info(f"{self.legtype} {other.legtype}")
221  log.info(f"{self.l1seed} {other.l1seed}")
222  log.info(f"{self.details} {other.details}")
223  log.info(f"{self.thr} {other.thr}")
224  log.info(self.compareDetails(other, is2015, debug=True))
225  log.info(self.details == other.details)
226  log.info("DEBUG LEGS END --------")
227 
228  if self.legtype != other.legtype: return -9
229  if self.compareDetails(other, is2015) == -1:
230  if self.thr < other.thr: return 1
231  if self.thr > other.thr: return 0
232  else: return -1
233 
234  if self.compareDetails(other, is2015) == 1 and self.thr <= other.thr: return 1
235  if self.compareDetails(other, is2015) == 0 and other.thr <= self.thr: return 0
236  return -9
237 
238  def compareDetails(self, other, is2015, debug=False):
239  ''' Returns -9 if none of them is lower than the other (e.g. different met flavour).
240  Returns -1 if identical
241  Returns 0 if other is lower than self.
242  Returns 1 if self is lower than other.
243  '''
244  from copy import deepcopy
245 
246  if debug: log.info(f"compareDetails: {len(self.details)} {len(other.details)} {(self.l1seed == other.l1seed)} {(self.details == other.details)}")
247  if len(self.details) != len(other.details):
248  if not is2015 and any([x.startswith("noL1") for x in self.details]):
249  cloneself = deepcopy(self)
250  cloneself.details = [ x for x in self.details if not x.startswith("noL1")]
251  compno = cloneself.compareDetails(other,is2015,debug)
252  if compno ==1 or compno == -1:
253  return 1
254  if not is2015 and any([x.startswith("noL1") for x in other.details]):
255  cloneother = deepcopy(other)
256  cloneother.details = [ x for x in other.details if not x.startswith("noL1")]
257  compno = self.compareDetails(cloneother,is2015,debug)
258  if compno ==0 or compno == -1:
259  return 0
260  if not is2015 and any([x.startswith("nod0") for x in self.details]):
261  cloneself = deepcopy(self)
262  cloneself.details = [ x for x in self.details if not x.startswith("nod0")]
263  compno = cloneself.compareDetails(other,is2015,debug)
264  if compno ==1 or compno == -1:
265  return 1
266  if not is2015 and any([x.startswith("nod0") for x in other.details]):
267  cloneother = deepcopy(other)
268  cloneother.details = [ x for x in other.details if not x.startswith("nod0")]
269  compno = self.compareDetails(cloneother,is2015,debug)
270  if compno ==0 or compno == -1:
271  return 0
272  if any([x.startswith("cut") for x in self.details]):
273  cloneself = deepcopy(self)
274  cloneself.details = [ x for x in self.details if not x.startswith("cut")]
275  compno = cloneself.compareDetails(other,is2015,debug)
276  if compno ==0 or compno == -1:
277  return 0
278  if any([x.startswith("cut") for x in other.details]):
279  cloneother = deepcopy(other)
280  cloneother.details = [ x for x in other.details if not x.startswith("cut")]
281  compno = self.compareDetails(cloneother,is2015,debug)
282  if compno ==1 or compno == -1:
283  return 1
284  return -9
285  compl1seed = self.compareTags(self.l1seed, other.l1seed, stringSubset=True, debug=debug)
286  compdetails = self.compareTags(" ".join(self.details), " ".join(other.details), debug=debug )
287  if self.l1seed == other.l1seed:
288  if self.details == other.details: return -1
289  if debug: log.info(f"compareTags 1: {compdetails}")
290  return compdetails
291 
292  if self.details == other.details:
293  if debug: log.info(f"compareTags 2: {compl1seed}")
294  return compl1seed
295 
296  if compl1seed == compdetails:
297  return compl1seed
298  return -9
299 
300  def compareTags(self, tag1, tag2, stringSubset=False,debug=False):
301  def mycomp(x,y):
302  ''' Return -9 for different strings,
303  -1 for identical strings/nums,
304  0/1 for high/low numbers or string subsets
305  '''
306  try:
307  x,y = int(x), int(y)
308  if x < y: return 1
309  elif x > y: return 0
310  else: return -1
311  except ValueError:
312  if x==y: return -1
313  if x == y.replace("vloose","loose"): return 0
314  if x == y.replace("vloose","loose").replace("loose","medium"): return 0
315  if x == y.replace("vloose","loose").replace("loose","medium").replace("medium","tight"): return 0
316  if y == x.replace("vloose","loose"): return 1
317  if y == x.replace("vloose","loose").replace("loose","medium"): return 1
318  if y == x.replace("vloose","loose").replace("loose","medium").replace("medium","tight"): return 1
319  l1ThresholdLevels = ["L","M","T"]
320  if x in l1ThresholdLevels and y in l1ThresholdLevels:
321  if l1ThresholdLevels.index(x) > l1ThresholdLevels.index(y): return 0
322  return 1 # don't need to check for equality, that was done above
323  if stringSubset:
324  if x in y: return 1
325  if y in x: return 0
326  return -9
327 
328  if tag1 == tag2: return -1
329  #lower mv2 and deltaR/deltaZ/deltaPhi values are tighter, put a minus sign to trick it
330  inverseCuts = ("mv2c","dr","dz","dphi","dl1d","dl1r","gn1","gn2")
331  for cut in inverseCuts:
332  tag1 = tag1.replace(cut,cut+"-")
333  tag2 = tag2.replace(cut,cut+"-")
334  #only make a statement on the numerical values, with everything else identical
335  extra_inverseCuts = ("b","emf","bgtwo","gntau") # all only appear in "presel" block
336  def findall(tag): # do the findall per tag block, so that can apply special rule to presel block only
337  out = []
338  for s in tag.split(" "):
339  l = self.detailpattern.findall(s)
340  if len(l) and l[0]=='presel':
341  for i,s in enumerate(l):
342  for cut in extra_inverseCuts:
343  if s==cut: l[i+1] = "-" + l[i+1] # adds a minus sign to the number that follows
344  out += l
345  return out
346  reself = findall(tag1)
347  reother = findall(tag2)
348 
349  if len(reself) != len(reother): return -9
350  thecomp = [mycomp(a,b) for a,b in zip(reself,reother)]
351  if debug: log.info(f"thecomp: {thecomp} {reself} {reother}")
352  if any([x == -9 for x in thecomp]): return -9
353  if all([x !=0 for x in thecomp]) and any([x == 1 for x in thecomp]): return 1
354  if all([x !=1 for x in thecomp]) and any([x == 0 for x in thecomp]): return 0
355  return -9
356 
357  @classmethod
358  def parse_legs(cls,name,l1seed,chainname):
359  legsname = []
360  name = name.replace("HLT_","")
361  for token in name.split("_"):
362  m = cls.legpattern.match(token)
363  if m:
364  legsname.append(token)
365  elif legsname:
366  legsname[-1] += "_"+token
367  else: #first token doesn't match
368  #log.info("parse_legs: Problem parsing",name)
369  return []
370  return [TriggerLeg(l,l1seed,chainname) for l in legsname]
371 
373  l1types = ('EM','J','MU','TAU','XE','XS','HT','eEM','eTAU','jJ','jTAU','jXE','gXEJWOJ','gJ','gLJ','jEM')
374  l1pattern = re.compile('([0-9]*)(%s)([0-9]+)' % '|'.join(l1types))
375 
376  def __init__(self,name,l1seed,livefraction,activeLB=1,hasRerun=False, activeLBByRun={}):
377  self.name = name
378  self.l1seed = l1seed
379  tmplegs = TriggerLeg.parse_legs(name,l1seed,name)
380  self.legs = self.splitAndOrderLegs(tmplegs)
381  self.livefraction = livefraction
382  self.activeLB = activeLB
383  self.hasRerun = hasRerun
384  self.activeLBByRun = activeLBByRun
385  self.triggerType = self.getTriggerType(self.legs, l1seed)
386 
387  def setRunRange(self,start,end,totalLB):
388  """
389  This method is called by the owning TriggerInfo method to adjust the livefractions and activeLB
390  to only the given runs
391  :param start:
392  :param end:
393  :param totalLB:
394  :return:
395  """
396  if not self.activeLBByRun:
397  # empty dict means either loaded from trigger menu or from old json
398  return
399  self.activeLB = 0
400  for run,efflb in self.activeLBByRun.items():
401  if int(run)<int(start) or int(run)>int(end): continue
402  self.activeLB += efflb
403  self.livefraction = self.activeLB/totalLB
404  pass
405 
406  def toJSON(self):
407  return dict(name=self.name, l1seed=self.l1seed, livefraction=self.livefraction, activeLB=self.activeLB, hasRerun=self.hasRerun,activeLBByRun=self.activeLBByRun)
408 
409  def splitAndOrderLegs(self, legs):
410  from copy import deepcopy
411  newLegs = []
412  for triggerType in TriggerType:
413  for l in legs:
414  if not l.legtype == triggerType: continue
415  for i in range(l.count): #split into N single legs
416  tmp = deepcopy(l)
417  tmp.count = 1
418  if tmp.legtype & TriggerType.el_multi:
419  tmp.legtype |= TriggerType.el_single
420  tmp.legtype &= ~TriggerType.el_multi
421  elif tmp.legtype & TriggerType.mu_multi:
422  tmp.legtype |= TriggerType.mu_single
423  tmp.legtype &= ~TriggerType.mu_multi
424  elif tmp.legtype & TriggerType.tau_multi:
425  tmp.legtype |= TriggerType.tau_single
426  tmp.legtype &= ~TriggerType.tau_multi
427  elif tmp.legtype & TriggerType.j_multi:
428  tmp.legtype |= TriggerType.j_single
429  tmp.legtype &= ~TriggerType.j_multi
430  elif tmp.legtype & TriggerType.bj_multi:
431  tmp.legtype |= TriggerType.bj_single
432  tmp.legtype &= ~TriggerType.bj_multi
433  elif tmp.legtype & TriggerType.g_multi:
434  tmp.legtype |= TriggerType.g_single
435  tmp.legtype &= ~TriggerType.g_multi
436  newLegs.append(tmp)
437  return newLegs
438 
439 
440  # def getChainGroupTriggerType(self):
441  # """
442  # :return: triggerType determined by chainGroup information
443  # """
444  # mtype = TriggerType.UNDEFINED
445  #
446  # # decide trigger type on chainGroup's "RATE:" group if present
447  # for group in self.chainGroups:
448  # if not group.startswith("RATE:"): continue
449  # rateGroup = group[5:] # strip prefix
450  # if rateGroup=="SingleElectron": mtype |= TriggerType.el_single
451  # elif rateGroup=="SingleMuon": mtype |= TriggerType.mu_single
452  # elif rateGroup=="MultiElectron": mtype |= TriggerType.el_multi
453  # elif rateGroup=="MultiMuon": mtype |= TriggerType.mu_multi
454  # elif rateGroup=="SinglePhoton": mtype |= TriggerType.g_single
455  # elif rateGroup=="MultiPhoton": mtype |= TriggerType.g_multi
456  # elif rateGroup=="SingleJet": mtype |= TriggerType.j_single
457  # elif rateGroup=="MultiJet": mtype |= TriggerType.j_multi
458  # elif rateGroup=="SingleBJet": mtype |= TriggerType.bj_single
459  # elif rateGroup=="MultiBJet": mtype |= TriggerType.bj_multi
460  # elif rateGroup=="SingleTau": mtype |= TriggerType.tau_single
461  # elif rateGroup=="MultiTau": mtype |= TriggerType.tau_multi
462  # else:
463  # if "Bphysics" in rateGroup: mtype |= TriggerType.mu_bphys
464  # if "MET" in rateGroup: mtype |= TriggerType.xe
465  # if "Muon" in rateGroup: mtype |= TriggerType.mu
466  # if "Electron" in rateGroup: mtype |= TriggerType.el
467  # if "Bjet" in rateGroup: mtype |= TriggerType.bj
468  # if "Jet" in rateGroup: mtype |= TriggerType.j
469  # if "Tau" in rateGroup: mtype |= TriggerType.tau
470  #
471  # return mtype
472 
473  def getTriggerType(self, legs, l1seed):
474  mtype = TriggerType.UNDEFINED
475 
476  for l in legs:
477  if mtype & TriggerType.el and l.legtype & TriggerType.el:
478  mtype |= TriggerType.el_multi
479  mtype &= ~TriggerType.el_single
480  elif mtype & TriggerType.mu and l.legtype & TriggerType.mu:
481  mtype |= TriggerType.mu_multi
482  mtype &= ~TriggerType.mu_single
483  elif mtype & TriggerType.tau and l.legtype & TriggerType.tau:
484  mtype |= TriggerType.tau_multi
485  mtype &= ~TriggerType.tau_single
486  elif mtype & TriggerType.j and l.legtype & TriggerType.j:
487  mtype |= TriggerType.j_multi
488  mtype &= ~TriggerType.j_single
489  elif mtype & TriggerType.bj and l.legtype & TriggerType.bj:
490  mtype |= TriggerType.bj_multi
491  mtype &= ~TriggerType.bj_single
492  elif mtype & TriggerType.g and l.legtype & TriggerType.g:
493  mtype |= TriggerType.g_multi
494  mtype &= ~TriggerType.g_single
495  elif l.legtype & TriggerType.mu_bphys:
496  mtype |= TriggerType.mu_bphys
497  mtype &= ~(TriggerType.mu_single | TriggerType.mu_multi)
498  elif l.legtype & TriggerType.exotics:
499  mtype |= TriggerType.exotics
500  elif l.legtype & TriggerType.afp:
501  mtype = TriggerType.afp #on purpose not OR-ed
502  else:
503  mtype |= l.legtype
504 
505  l1seed= l1seed.replace("L1_","")
506  if mtype & TriggerType.exotics or mtype & TriggerType.afp:
507  return mtype
508  for token in l1seed.split("_"):
509  m = self.l1pattern.match(token)
510  if m:
511  count,legtype,thr = m.groups()
512  count = int(count) if count else 1
513  if 'EM' in legtype or 'TAU' in legtype:
514  pass
515  elif 'MU' in legtype:
516  if not mtype & TriggerType.mu_bphys:
517  if count > 1: mtype |= TriggerType.mu_multi
518  elif not mtype & TriggerType.mu_multi: mtype |= TriggerType.mu_single
519  elif 'J' in legtype:
520  if not mtype & TriggerType.bj and not mtype & TriggerType.j and not mtype & TriggerType.tau and not mtype & TriggerType.ht:
521  if count > 1: mtype |= TriggerType.j_multi
522  elif not mtype & TriggerType.j_multi: mtype |= TriggerType.j_single
523  elif 'XE' in legtype or 'XS' in legtype:
524  mtype |= TriggerType.xe
525  elif 'HT' in legtype:
526  mtype |= TriggerType.ht
527  else:
528  log.info("Unknown trigger type:",(legtype, mtype, token, self.name))
529  return mtype
530 
531  def isActive(self, livefraction=1e-99):
532  return self.livefraction > livefraction or self.hasRerun
533  def isInactive(self, livefraction=1e-99):
534  return not self.isActive(livefraction)
535 
536  def isUnprescaled(self, livefraction=1.0):
537  return self.livefraction >= livefraction
538 
539  def getType(self):
540  return self.triggerType
541 
542  def passType(self, triggerType, additionalTriggerType):
543  if self.triggerType == TriggerType.UNDEFINED: return False
544  if self.triggerType == TriggerType.ALL: return True
545  match = (self.triggerType & triggerType)
546  if not match: return False
547  tmpType = self.triggerType & ~triggerType
548 
549  try:
550  for t in additionalTriggerType:
551  match = (tmpType & t)
552  if not match: return False
553  tmpType = tmpType & ~t
554  except TypeError: #Not iterable
555  if additionalTriggerType!=TriggerType.UNDEFINED:
556  match = (tmpType & additionalTriggerType)
557  if not match: return False
558  tmpType = tmpType & ~additionalTriggerType
559 
560  return tmpType == TriggerType.UNDEFINED #After matches nothing remains
561 
562  def __repr__(self):
563  return repr({"name":self.name, "legs":self.legs, "triggerType":TriggerType.toStr(self.triggerType), "livefraction":self.livefraction, "activeLB":self.activeLB})
564 
565  def isSubsetOf(self, other):
566  ''' Returns -1 if none of them is a strict subset of the other
567  Returns 0 if the legs in other are a subset of self.
568  Returns 1 if the legs in self are a subset of other.
569  '''
570  if not self.legs or not other.legs: return -1 #problems with AFP
571  selfcounter = Counter(self.legs)
572  othercounter = Counter(other.legs)
573  for leg, count in selfcounter.items():
574  if leg not in othercounter or count > othercounter[leg]: break
575  else: return 1
576  for leg, count in othercounter.items():
577  if leg not in selfcounter or count > selfcounter[leg]: break
578  else: return 0
579  return -1
580 
581  def isLowerThan(self, other,period=TriggerPeriod.future):
582  ''' Returns -1 if none of them is lower than the other (e.g. asymmetric dilepton).
583  Returns 0 if other is lower than self.
584  Returns 1 if self is lower than other.
585  '''
586  is2015 = period & TriggerPeriod.y2015 and not TriggerPeriod.isRunNumber(period)
587  is2015 |= period <= 284484 and TriggerPeriod.isRunNumber(period)
588  if self.triggerType != other.triggerType: return -1
589  if len(self.legs) != len(other.legs): return -1
590  comp = -1
591  debug = False
592  #if re.search("HLT_j55_gsc75_bmv2c1040_split_3j55_gsc75_boffperf_split", self.name): debug = True
593  if debug: log.info("DEBUG:",self.name,other.name)
594  for selfleg, otherleg in zip(self.legs, other.legs):
595  legcomp = selfleg.isLegLowerThan(otherleg, is2015, debug)
596  if debug: log.info("DEBUG LEG return:", legcomp)
597  if legcomp == -9: return -1
598  elif legcomp == -1: continue
599  elif legcomp == 0 and comp == 1: return -1
600  elif legcomp == 1 and comp == 0: return -1
601  elif legcomp == 0 : comp = 0
602  elif legcomp == 1 : comp = 1
603  if debug: log.info("DEBUG FINAL:",comp)
604  return comp
605 
606 
607 def test():
608  a = TriggerChain("HLT_j50_gsc65_bmv2c1040_split_3j50_gsc65_boffperf_split", "L1J100",1)
609  log.info(a)
610  log.info(bin(a.getType()))
611  log.info(a.passType(TriggerType.j_multi, TriggerType.UNDEFINED))
612  log.info(a.passType(TriggerType.j_multi | TriggerType.bj_single, TriggerType.UNDEFINED))
613  log.info(a.isUnprescaled())
614 
615 if __name__ == "__main__":
616  import sys
617  sys.exit(test())
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
python.TriggerAPI.TriggerInfo.TriggerChain.isLowerThan
def isLowerThan(self, other, period=TriggerPeriod.future)
Definition: TriggerInfo.py:581
python.TriggerAPI.TriggerInfo.TriggerLeg.bphyspattern
bphyspattern
Definition: TriggerInfo.py:135
python.TriggerAPI.TriggerInfo.TriggerInfo._getUnprescaled
def _getUnprescaled(self, triggerType, additionalTriggerType, matchPattern, livefraction=1.0)
Definition: TriggerInfo.py:80
python.TriggerAPI.TriggerInfo.TriggerChain.activeLB
activeLB
Definition: TriggerInfo.py:382
python.TriggerAPI.TriggerInfo.TriggerChain.isInactive
def isInactive(self, livefraction=1e-99)
Definition: TriggerInfo.py:533
python.TriggerAPI.TriggerInfo.TriggerLeg
Definition: TriggerInfo.py:129
python.TriggerAPI.TriggerInfo.TriggerLeg.count
count
Definition: TriggerInfo.py:150
vtune_athena.format
format
Definition: vtune_athena.py:14
python.TriggerAPI.TriggerInfo.TriggerChain.hasRerun
hasRerun
Definition: TriggerInfo.py:383
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
python.TriggerAPI.TriggerInfo.TriggerChain.legs
legs
Definition: TriggerInfo.py:380
python.TriggerAPI.TriggerInfo.TriggerChain.livefraction
livefraction
Definition: TriggerInfo.py:381
python.TriggerAPI.TriggerInfo.TriggerChain.passType
def passType(self, triggerType, additionalTriggerType)
Definition: TriggerInfo.py:542
python.TriggerAPI.TriggerInfo.TriggerLeg.__eq__
def __eq__(self, other)
Definition: TriggerInfo.py:202
Cut::all
@ all
Definition: SUSYToolsAlg.cxx:67
bin
Definition: BinsDiffFromStripMedian.h:43
python.TriggerAPI.TriggerInfo.TriggerChain.toJSON
def toJSON(self)
Definition: TriggerInfo.py:406
python.TriggerAPI.TriggerInfo.TriggerLeg.uctTypes
uctTypes
Definition: TriggerInfo.py:131
python.TriggerAPI.TriggerInfo.TriggerChain.name
name
Definition: TriggerInfo.py:377
python.TriggerAPI.TriggerInfo.TriggerInfo._getAllHLT
def _getAllHLT(self, triggerType, additionalTriggerType, matchPattern, livefraction)
Definition: TriggerInfo.py:103
python.TriggerAPI.TriggerInfo.TriggerChain.isActive
def isActive(self, livefraction=1e-99)
Definition: TriggerInfo.py:531
python.TriggerAPI.TriggerInfo.TriggerChain.setRunRange
def setRunRange(self, start, end, totalLB)
Definition: TriggerInfo.py:387
python.TriggerAPI.TriggerInfo.TriggerChain.isSubsetOf
def isSubsetOf(self, other)
Definition: TriggerInfo.py:565
python.TriggerAPI.TriggerInfo.TriggerInfo._getActive
def _getActive(self, triggerType, additionalTriggerType, matchPattern, livefraction)
Definition: TriggerInfo.py:106
python.TriggerAPI.TriggerInfo.TriggerLeg.__init__
def __init__(self, legname, chainseed, chainname=None)
Definition: TriggerInfo.py:139
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.TriggerAPI.TriggerInfo.TriggerChain.getType
def getType(self)
Definition: TriggerInfo.py:539
search
void search(TDirectory *td, const std::string &s, std::string cwd, node *n)
recursive directory search for TH1 and TH2 and TProfiles
Definition: hcg.cxx:738
python.TriggerAPI.TriggerInfo.TriggerLeg.__repr__
def __repr__(self)
Definition: TriggerInfo.py:208
python.TriggerAPI.TriggerInfo.TriggerInfo.triggerChains
triggerChains
Definition: TriggerInfo.py:19
python.TriggerAPI.TriggerInfo.TriggerChain.getTriggerType
def getTriggerType(self, legs, l1seed)
Definition: TriggerInfo.py:473
python.TriggerAPI.TriggerInfo.TriggerInfo.reparse
def reparse(self)
Definition: TriggerInfo.py:77
python.TriggerAPI.TriggerInfo.TriggerChain.activeLBByRun
activeLBByRun
Definition: TriggerInfo.py:384
python.TriggerAPI.TriggerInfo.TriggerLeg.__hash__
def __hash__(self)
Definition: TriggerInfo.py:205
python.TriggerAPI.TriggerInfo.TriggerInfo.toJSON
def toJSON(self)
Definition: TriggerInfo.py:45
python.TriggerAPI.TriggerInfo.TriggerChain.isUnprescaled
def isUnprescaled(self, livefraction=1.0)
Definition: TriggerInfo.py:536
PixelModuleFeMask_create_db.remove
string remove
Definition: PixelModuleFeMask_create_db.py:83
python.TriggerAPI.TriggerInfo.TriggerChain.splitAndOrderLegs
def splitAndOrderLegs(self, legs)
Definition: TriggerInfo.py:409
python.TriggerAPI.TriggerInfo.TriggerLeg.parse_legs
def parse_legs(cls, name, l1seed, chainname)
Definition: TriggerInfo.py:358
python.TriggerAPI.TriggerInfo.TriggerLeg.l1seed
l1seed
Definition: TriggerInfo.py:141
python.TriggerAPI.TriggerInfo.TriggerLeg.compareDetails
def compareDetails(self, other, is2015, debug=False)
Definition: TriggerInfo.py:238
python.TriggerAPI.TriggerInfo.TriggerInfo.period
period
Definition: TriggerInfo.py:20
python.TriggerAPI.TriggerInfo.TriggerChain.l1seed
l1seed
Definition: TriggerInfo.py:378
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
PyAthena::repr
std::string repr(PyObject *o)
returns the string representation of a python object equivalent of calling repr(o) in python
Definition: PyAthenaUtils.cxx:106
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
python.TriggerAPI.TriggerInfo.TriggerLeg.compareTags
def compareTags(self, tag1, tag2, stringSubset=False, debug=False)
Definition: TriggerInfo.py:300
python.TriggerAPI.TriggerInfo.TriggerInfo.totalLBByRun
totalLBByRun
Definition: TriggerInfo.py:22
python.TriggerAPI.TriggerInfo.TriggerInfo._getInactive
def _getInactive(self, triggerType, additionalTriggerType, matchPattern, livefraction)
Definition: TriggerInfo.py:108
python.TriggerAPI.TriggerInfo.TriggerInfo.totalLB
totalLB
Definition: TriggerInfo.py:21
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.TriggerAPI.TriggerInfo.test
def test()
Definition: TriggerInfo.py:607
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:79
python.TriggerAPI.TriggerInfo.TriggerChain
Definition: TriggerInfo.py:372
python.TriggerAPI.TriggerInfo.TriggerLeg.legpattern
legpattern
Definition: TriggerInfo.py:132
python.TriggerAPI.TriggerInfo.TriggerInfo._checkPeriodConsistency
def _checkPeriodConsistency(self, triggerType, additionalTriggerType, matchPattern)
Definition: TriggerInfo.py:111
python.TriggerAPI.TriggerInfo.TriggerLeg.legname
legname
Definition: TriggerInfo.py:140
python.TriggerAPI.TriggerInfo.TriggerLeg.detailpattern
detailpattern
Definition: TriggerInfo.py:133
CaloCondBlobAlgs_fillNoiseFromASCII.hash
dictionary hash
Definition: CaloCondBlobAlgs_fillNoiseFromASCII.py:109
python.TriggerAPI.TriggerInfo.TriggerInfo._getLowestUnprescaled
def _getLowestUnprescaled(self, triggerType, additionalTriggerType, matchPattern, livefraction=1.0)
Definition: TriggerInfo.py:83
python.TriggerAPI.TriggerInfo.TriggerLeg.afppattern
afppattern
Definition: TriggerInfo.py:137
python.TriggerAPI.TriggerInfo.TriggerInfo.testCustomGRL
def testCustomGRL(cls, grl)
Definition: TriggerInfo.py:73
python.TriggerAPI.TriggerInfo.TriggerLeg.thr
thr
Definition: TriggerInfo.py:151
python.TriggerAPI.TriggerInfo.TriggerInfo.__init__
def __init__(self, period=0, customGRL=None, release=None, flags=None)
Definition: TriggerInfo.py:18
python.TriggerAPI.TriggerInfo.TriggerLeg.isLegLowerThan
def isLegLowerThan(self, other, is2015, debug=False)
Definition: TriggerInfo.py:211
python.TriggerAPI.TriggerInfo.TriggerChain.__repr__
def __repr__(self)
Definition: TriggerInfo.py:562
python.TriggerAPI.TriggerInfo.TriggerInfo.merge
def merge(cls, listofTI)
Definition: TriggerInfo.py:49
python.TriggerAPI.TriggerInfo.TriggerLeg.details
details
Definition: TriggerInfo.py:200
python.TriggerAPI.TriggerDataAccess.getHLTlist
def getHLTlist(period, customGRL, release, flags=None)
Definition: TriggerDataAccess.py:393
python.TriggerAPI.TriggerInfo.TriggerChain.triggerType
triggerType
Definition: TriggerInfo.py:385
python.TriggerAPI.TriggerInfo.TriggerLeg.bjetpattern
bjetpattern
Definition: TriggerInfo.py:134
python.TriggerAPI.TriggerInfo.TriggerChain.__init__
def __init__(self, name, l1seed, livefraction, activeLB=1, hasRerun=False, activeLBByRun={})
Definition: TriggerInfo.py:376
readCCLHist.float
float
Definition: readCCLHist.py:83
python.TriggerAPI.TriggerInfo.TriggerInfo
Definition: TriggerInfo.py:14
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
python.TriggerAPI.TriggerInfo.TriggerInfo.__str__
def __str__(self)
Definition: TriggerInfo.py:42
python.TriggerAPI.TriggerInfo.TriggerLeg.exoticspattern
exoticspattern
Definition: TriggerInfo.py:136
match
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition: hcg.cxx:356
python.TriggerAPI.TriggerInfo.TriggerInfo.setRunRange
def setRunRange(self, start=0, end=999999)
Definition: TriggerInfo.py:30
python.TriggerAPI.TriggerInfo.TriggerChain.l1pattern
l1pattern
Definition: TriggerInfo.py:374
python.TriggerAPI.TriggerInfo.TriggerLeg.legtype
legtype
Definition: TriggerInfo.py:153