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