3 __author__ =
'Javier Montejo'
4 __version__=
"$Revision: 2.0 $"
5 __doc__=
"Class containing all the information of an HLT chain"
8 from TriggerMenuMT.TriggerAPI.TriggerEnums
import TriggerType, TriggerPeriod
9 from collections
import Counter
11 from AthenaCommon.Logging
import logging
12 log = logging.getLogger(__name__)
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
18 def __init__(self,period=0, customGRL=None, release=None, flags=None):
24 if not period
and not customGRL:
return
25 from .TriggerDataAccess
import getHLTlist
27 for hlt, l1, livefraction, activeLB, hasRerun, activeLBByRun
in HLTlist:
40 tc.setRunRange(start,end,totalLB)
43 return f
"<TriggerMenuMT.TriggerAPI.TriggerInfo.TriggerInfo object with {len(self.triggerChains)} triggerChains, period={self.period}, totalLB={self.totalLB}>"
50 from copy
import deepcopy
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
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())
74 from TriggerMenuMT.TriggerAPI.TriggerPeriodData
import TriggerPeriodData
75 return TriggerPeriodData.testCustomGRL(grl)
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)]
84 chainList = [ x
for x
in self.
triggerChains if x.isUnprescaled(livefraction)
and x.passType(triggerType, additionalTriggerType)
and re.search(matchPattern, x.name)]
86 for chain
in chainList:
87 if chain.triggerType
not in typeMap:
88 typeMap[chain.triggerType] = [chain]
91 for other
in typeMap[chain.triggerType][:]:
92 comp = chain.isLowerThan(other,self.
period)
97 if comp == 1: typeMap[chain.triggerType].
remove(other)
99 typeMap[chain.triggerType].
append(chain)
100 return [x.name
for t
in six.itervalues (typeMap)
for x
in t ]
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)}
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)]
115 if not (probe1.passType(triggerType, additionalTriggerType)
and re.search(matchPattern, probe1.name)):
continue
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)
130 types = (
'e',
'j',
'mu',
'tau',
'xe',
'g',
'ht')
131 uctTypes = (
'isotrk',
'fslrt',
'dedxtrk',
'hitdvjet',
'fsvsi',
'distrk',
'dispjet',
'dispvtx')
132 legpattern = re.compile(
'([0-9]*)(%s)([0-9]+)(noL1)?' %
'|'.
join(types+uctTypes))
133 detailpattern = re.compile(
r'(?:-?\d+)|(?:[^0-9 -]+)')
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')
139 def __init__(self,legname, chainseed, chainname=None):
143 chainseed= chainseed.replace(
"L1_",
"")
144 blocks = legname.split(
"_L1")
146 for token
in blocks[0].
split(
"_"):
149 count,legtype,thr,noL1 = m.groups()
154 else: self.
legtype = TriggerType.el_single
155 elif legtype ==
'mu':
157 else: self.
legtype = TriggerType.mu_single
160 else: self.
legtype = TriggerType.j_single
161 elif legtype ==
'tau':
163 else: self.
legtype = TriggerType.tau_single
166 else: self.
legtype = TriggerType.g_single
167 elif legtype ==
'xe':
169 elif legtype ==
'ht':
172 self.
legtype = TriggerType.exotics
174 details.append(legtype)
176 log.info(
"Unknown trigger type: %s",legtype)
177 if noL1: details.append(noL1)
180 if self.
legtype == TriggerType.j_single: self.
legtype = TriggerType.bj_single
181 if self.
legtype == TriggerType.j_multi: self.
legtype = TriggerType.bj_multi
183 self.
legtype = TriggerType.mu_bphys
185 self.
legtype = TriggerType.exotics
188 details.append(token)
190 for l1seed
in blocks[1:]:
192 self.
legtype = TriggerType.exotics
195 if l1seed == chainseed:
continue
197 assert self.
l1seed==
"", (self.
l1seed, chainseed, chainname, blocks[1:])
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)
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.
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}")
225 log.info(self.
details == other.details)
226 log.info(
"DEBUG LEGS END --------")
228 if self.
legtype != other.legtype:
return -9
230 if self.
thr < other.thr:
return 1
231 if self.
thr > other.thr:
return 0
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.
244 from copy
import deepcopy
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:
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")]
258 if compno ==0
or compno == -1:
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:
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")]
270 if compno ==0
or compno == -1:
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:
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")]
282 if compno ==1
or compno == -1:
285 compl1seed = self.
compareTags(self.
l1seed, other.l1seed, stringSubset=
True, 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}")
292 if self.
details == other.details:
293 if debug: log.info(f
"compareTags 2: {compl1seed}")
296 if compl1seed == compdetails:
300 def compareTags(self, tag1, tag2, stringSubset=False,debug=False):
302 ''' Return -9 for different strings,
303 -1 for identical strings/nums,
304 0/1 for high/low numbers or string subsets
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
328 if tag1 == tag2:
return -1
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+
"-")
338 if len(reself) != len(reother):
return -9
339 thecomp = [mycomp(a,b)
for a,b
in zip(reself,reother)]
340 if debug: log.info(f
"thecomp: {thecomp} {reself} {reother}")
341 if any([x == -9
for x
in thecomp]):
return -9
342 if all([x !=0
for x
in thecomp])
and any([x == 1
for x
in thecomp]):
return 1
343 if all([x !=1
for x
in thecomp])
and any([x == 0
for x
in thecomp]):
return 0
349 name = name.replace(
"HLT_",
"")
350 for token
in name.split(
"_"):
353 legsname.append(token)
355 legsname[-1] +=
"_"+token
359 return [
TriggerLeg(l,l1seed,chainname)
for l
in legsname]
362 l1types = (
'EM',
'J',
'MU',
'TAU',
'XE',
'XS',
'HT',
'eEM',
'eTAU',
'jJ',
'jTAU',
'jXE',
'gXEJWOJ',
'gJ',
'gLJ',
'jEM')
363 l1pattern = re.compile(
'([0-9]*)(%s)([0-9]+)' %
'|'.
join(l1types))
365 def __init__(self,name,l1seed,livefraction,activeLB=1,hasRerun=False, activeLBByRun={}):
368 tmplegs = TriggerLeg.parse_legs(name,l1seed,name)
378 This method is called by the owning TriggerInfo method to adjust the livefractions and activeLB
379 to only the given runs
399 from copy
import deepcopy
401 for triggerType
in TriggerType:
403 if not l.legtype == triggerType:
continue
404 for i
in range(l.count):
407 if tmp.legtype & TriggerType.el_multi:
408 tmp.legtype |= TriggerType.el_single
409 tmp.legtype &= ~TriggerType.el_multi
410 elif tmp.legtype & TriggerType.mu_multi:
411 tmp.legtype |= TriggerType.mu_single
412 tmp.legtype &= ~TriggerType.mu_multi
413 elif tmp.legtype & TriggerType.tau_multi:
414 tmp.legtype |= TriggerType.tau_single
415 tmp.legtype &= ~TriggerType.tau_multi
416 elif tmp.legtype & TriggerType.j_multi:
417 tmp.legtype |= TriggerType.j_single
418 tmp.legtype &= ~TriggerType.j_multi
419 elif tmp.legtype & TriggerType.bj_multi:
420 tmp.legtype |= TriggerType.bj_single
421 tmp.legtype &= ~TriggerType.bj_multi
422 elif tmp.legtype & TriggerType.g_multi:
423 tmp.legtype |= TriggerType.g_single
424 tmp.legtype &= ~TriggerType.g_multi
463 mtype = TriggerType.UNDEFINED
466 if mtype & TriggerType.el
and l.legtype & TriggerType.el:
467 mtype |= TriggerType.el_multi
468 mtype &= ~TriggerType.el_single
469 elif mtype & TriggerType.mu
and l.legtype & TriggerType.mu:
470 mtype |= TriggerType.mu_multi
471 mtype &= ~TriggerType.mu_single
472 elif mtype & TriggerType.tau
and l.legtype & TriggerType.tau:
473 mtype |= TriggerType.tau_multi
474 mtype &= ~TriggerType.tau_single
475 elif mtype & TriggerType.j
and l.legtype & TriggerType.j:
476 mtype |= TriggerType.j_multi
477 mtype &= ~TriggerType.j_single
478 elif mtype & TriggerType.bj
and l.legtype & TriggerType.bj:
479 mtype |= TriggerType.bj_multi
480 mtype &= ~TriggerType.bj_single
481 elif mtype & TriggerType.g
and l.legtype & TriggerType.g:
482 mtype |= TriggerType.g_multi
483 mtype &= ~TriggerType.g_single
484 elif l.legtype & TriggerType.mu_bphys:
485 mtype |= TriggerType.mu_bphys
486 mtype &= ~(TriggerType.mu_single | TriggerType.mu_multi)
487 elif l.legtype & TriggerType.exotics:
488 mtype |= TriggerType.exotics
489 elif l.legtype & TriggerType.afp:
490 mtype = TriggerType.afp
494 l1seed= l1seed.replace(
"L1_",
"")
495 if mtype & TriggerType.exotics
or mtype & TriggerType.afp:
497 for token
in l1seed.split(
"_"):
500 count,legtype,thr = m.groups()
501 count =
int(count)
if count
else 1
502 if 'EM' in legtype
or 'TAU' in legtype:
504 elif 'MU' in legtype:
505 if not mtype & TriggerType.mu_bphys:
506 if count > 1: mtype |= TriggerType.mu_multi
507 elif not mtype & TriggerType.mu_multi: mtype |= TriggerType.mu_single
509 if not mtype & TriggerType.bj
and not mtype & TriggerType.j
and not mtype & TriggerType.tau
and not mtype & TriggerType.ht:
510 if count > 1: mtype |= TriggerType.j_multi
511 elif not mtype & TriggerType.j_multi: mtype |= TriggerType.j_single
512 elif 'XE' in legtype
or 'XS' in legtype:
513 mtype |= TriggerType.xe
514 elif 'HT' in legtype:
515 mtype |= TriggerType.ht
517 log.info(
"Unknown trigger type:",(legtype, mtype, token, self.
name))
523 return not self.
isActive(livefraction)
531 def passType(self, triggerType, additionalTriggerType):
532 if self.
triggerType == TriggerType.UNDEFINED:
return False
533 if self.
triggerType == TriggerType.ALL:
return True
535 if not match:
return False
539 for t
in additionalTriggerType:
540 match = (tmpType & t)
541 if not match:
return False
542 tmpType = tmpType & ~t
544 if additionalTriggerType!=TriggerType.UNDEFINED:
545 match = (tmpType & additionalTriggerType)
546 if not match:
return False
547 tmpType = tmpType & ~additionalTriggerType
549 return tmpType == TriggerType.UNDEFINED
555 ''' Returns -1 if none of them is a strict subset of the other
556 Returns 0 if the legs in other are a subset of self.
557 Returns 1 if the legs in self are a subset of other.
559 if not self.
legs or not other.legs:
return -1
560 selfcounter = Counter(self.
legs)
561 othercounter = Counter(other.legs)
562 for leg, count
in selfcounter.items():
563 if leg
not in othercounter
or count > othercounter[leg]:
break
565 for leg, count
in othercounter.items():
566 if leg
not in selfcounter
or count > selfcounter[leg]:
break
571 ''' Returns -1 if none of them is lower than the other (e.g. asymmetric dilepton).
572 Returns 0 if other is lower than self.
573 Returns 1 if self is lower than other.
575 is2015 = period & TriggerPeriod.y2015
and not TriggerPeriod.isRunNumber(period)
576 is2015 |= period <= 284484
and TriggerPeriod.isRunNumber(period)
577 if self.
triggerType != other.triggerType:
return -1
578 if len(self.
legs) != len(other.legs):
return -1
582 if debug: log.info(
"DEBUG:",self.
name,other.name)
583 for selfleg, otherleg
in zip(self.
legs, other.legs):
584 legcomp = selfleg.isLegLowerThan(otherleg, is2015, debug)
585 if debug: log.info(
"DEBUG LEG return:", legcomp)
586 if legcomp == -9:
return -1
587 elif legcomp == -1:
continue
588 elif legcomp == 0
and comp == 1:
return -1
589 elif legcomp == 1
and comp == 0:
return -1
590 elif legcomp == 0 : comp = 0
591 elif legcomp == 1 : comp = 1
592 if debug: log.info(
"DEBUG FINAL:",comp)
597 a =
TriggerChain(
"HLT_j50_gsc65_bmv2c1040_split_3j50_gsc65_boffperf_split",
"L1J100",1)
599 log.info(
bin(a.getType()))
600 log.info(a.passType(TriggerType.j_multi, TriggerType.UNDEFINED))
601 log.info(a.passType(TriggerType.j_multi | TriggerType.bj_single, TriggerType.UNDEFINED))
602 log.info(a.isUnprescaled())
604 if __name__ ==
"__main__":