ATLAS Offline Software
Loading...
Searching...
No Matches
TriggerEDM.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3# ********************* All Tools/Functions for the TriggerEDM **********************
4# Keeping all functions from the original TriggerEDM.py (Run 2 EDM) in this file
5# with this name to not break backwards compatibility
6# Where possible, functions will be adapted to also work with Run 3, they will then be moved
7# to the Run 3 section
8# ***********************************************************************************
9
10from TrigEDMConfig.TriggerEDMRun1 import TriggerL2List,TriggerEFList,TriggerResultsRun1List
11from TrigEDMConfig.TriggerEDMRun2 import TriggerResultsList,TriggerLvl1List,TriggerIDTruth,TriggerHLTList,EDMDetails,EDMLibraries,TriggerL2EvolutionList,TriggerEFEvolutionList
12from TrigEDMConfig.TriggerEDMRun3 import TriggerHLTListRun3,varToRemoveFromAODSLIM,EDMDetailsRun3,getSafeEDMInsertPosition,getRun3LowMuEDM
13from TrigEDMConfig.TriggerEDMRun4 import TriggerHLTListRun4
14from TrigEDMConfig.TriggerEDMDefs import allowTruncation
15from CLIDComps.clidGenerator import clidGenerator
16from collections import defaultdict
17import itertools
18import re
19
20from AthenaCommon.Logging import logging
21log = logging.getLogger('TriggerEDM')
22
23#************************************************************
24#
25# For Run 3 and Run 4
26#
27#************************************************************
28
29# ------------------------------------------------------------
30# AllowedOutputFormats
31# ------------------------------------------------------------
32AllowedOutputFormats = ['BS', 'ESD', 'AODFULL', 'AODSLIM', 'AODBLSSLIM' ]
33from TrigEDMConfig import DataScoutingInfo
34AllowedOutputFormats.extend(DataScoutingInfo.getAllDataScoutingIdentifiers())
35
36_allowedEDMPrefixes = ['HLT_', 'L1_', 'LVL1']
37def recordable(arg):
38 """
39 Verify that the name is in the list of recorded objects and conform to the name convention
40
41 In Run 2 it was a delicate process to configure correctly what got recorded
42 as it had to be set in the algorithm that produced it as well in the TriggerEDM.py in a consistent manner.
43
44 For Run 3 every alg input/output key can be crosschecked against the list of objects to record which is defined here.
45 I.e. in the configuration alg developer would do this:
46 from TriggerEDM.TriggerEDMRun3 import recordable
47
48 alg.outputKey = recordable("SomeKey")
49 If the names are correct the outputKey is assigned with SomeKey, if there is a missmatch an exception is thrown.
50
51 """
52
53 # Allow passing DataHandle as argument - convert to string and remove store name
54 name = str(arg).replace('StoreGateSvc+','')
55
56 if "HLTNav_" in name:
57 log.error( "Don't call recordable({0}), or add any \"HLTNav_\" collection manually to the EDM. See:collectDecisionObjects.".format( name ) )
58 pass
59 else: #negative filtering
60 if not any([name.startswith(p) for p in _allowedEDMPrefixes]):
61 raise RuntimeError( f"The collection name {name} does not start with any of the allowed prefixes: {_allowedEDMPrefixes}" )
62 if "Aux" in name and not name[-1] != ".":
63 raise RuntimeError( f"The collection name {name} is Aux but the name does not end with the '.'" )
64
65 #TODO Remove TriggerHLTListRun3 once full Trigger EDM Run 4 list defined.
66 for entry in TriggerHLTListRun3 + TriggerHLTListRun4:
67 if entry[0].split( "#" )[1] == name:
68 return arg
69 msg = "The collection name {0} is not declared to be stored by HLT. Add it to TriggerEDMRun4.py".format( name )
70 log.error("ERROR in recordable() - see following stack trace.")
71 raise RuntimeError( msg )
72
73def _addExtraCollectionsToEDMList(edmList, extraList):
74 """
75 Extend edmList with extraList, keeping track whether a completely new
76 collection is being added, or a dynamic variable is added to an existing collection, or new targets are added to an existing collection.
77 The format of extraList is the same as those of TriggerHLTListRun3.
78 """
79 existing_collections = [(c[0].split("#")[1]).split(".")[0] for c in edmList]
80 insert_idx = getSafeEDMInsertPosition(edmList)
81 for item in extraList:
82 colname = (item[0].split("#")[1]).split(".")[0]
83 if colname not in existing_collections:
84 # a new collection and its Aux container are inserted in front of 'allowTruncation' items.
85 if 'Aux' in colname:
86 edmList.insert(insert_idx+1,item)
87 else:
88 edmList.insert(insert_idx,item)
89 log.info("added new item to Trigger EDM: {}".format(item))
90 else:
91 # Maybe extra dynamic variables or EDM targets are added
92 isAux = "Aux." in item[0]
93 # find the index of the existing item
94 existing_item_nr = [i for i,s in enumerate(edmList) if colname == (s[0].split("#")[1]).split(".")[0]]
95 if len(existing_item_nr) != 1:
96 log.error("Found {} existing edm items corresponding to new item {}, but it must be exactly one!".format(len(existing_item_nr), item))
97 existingItem = edmList[existing_item_nr[0]]
98 if isAux:
99 dynVars = (item[0].split("#")[1]).split(".")[1:]
100 existing_dynVars = (existingItem[0].split("#")[1]).split(".")[1:]
101 existing_dynVars.extend(dynVars)
102 dynVars = list(dict.fromkeys(existing_dynVars))
103 if '' in dynVars:
104 dynVars.remove('')
105 newVars = '.'.join(dynVars)
106 edmTargets = item[1].split(" ") if len(item) > 1 else []
107 existing_edmTargets = existingItem[1].split(" ")
108 edmTargets.extend(existing_edmTargets)
109 edmTargets = list(dict.fromkeys(edmTargets))
110 newTargets = " ".join(edmTargets)
111 typename = item[0].split("#")[0]
112 log.info("old item in Trigger EDM : {}".format(existingItem))
113 signature = existingItem[2] # NOT updated at the moment
114 tags = existingItem[3] if len(existingItem) > 3 else None # NOT updated at the moment
115 edmList.pop(existing_item_nr[0])
116 combName = typename + "#" + colname
117 if isAux:
118 combName += "." + newVars
119 if tags:
120 edmList.insert(existing_item_nr[0], (combName, newTargets, signature, tags))
121 else:
122 edmList.insert(existing_item_nr[0] , (combName, newTargets, signature))
123 log.info("updated item in Trigger EDM: {}".format(edmList[existing_item_nr[0]]))
124
125 if testEDMList(edmList, error_on_edmdetails=False):
126 log.error("edmList contains inconsistencies!")
127
128def getRawTriggerEDMList(flags, runVersion=-1):
129 """
130 The static EDM list does still need some light manipulation before it can be used commonly.
131 Never import TriggerHLTListRun3 or TriggerHLTListRun4 directly, always fetch them via this function
132 """
133 if runVersion == -1:
134 runVersion = flags.Trigger.EDMVersion
135
136 if runVersion == 3:
137 edmListCopy = TriggerHLTListRun3.copy()
138 if flags and flags.Trigger.addRun3LowMuEDM:
139 LowMuEDM = getRun3LowMuEDM(flags)
140 log.info( "Adding low mu collections to EDM %i: %s", runVersion, str(LowMuEDM))
141 _addExtraCollectionsToEDMList(edmListCopy, LowMuEDM)
142 elif runVersion == 4:
143 edm4ListCopy = TriggerHLTListRun4.copy()
144 edm3ListCopy = TriggerHLTListRun3.copy()
145 log.debug("Removing duplicated item between TriggerHLTListRun3 and TriggerHLTListRun4.")
146 for i in range(len(edm3ListCopy)-1, -1, -1): # Back iterate by index, we might be removing as we go
147 for r4item in edm4ListCopy:
148 if edm3ListCopy[i][0] == r4item[0]:
149 del edm3ListCopy[i]
150 log.debug(f"- Dupe: {r4item} is removed from TriggerHLTListRun3 to be updated by TriggerHLTListRun4")
151 break
152 lenPreMerge = len(edm3ListCopy)
153 edm4ListCopy.extend(edm3ListCopy)
154 lenPostMerge = len(edm4ListCopy)
155 edmListCopy = edm4ListCopy
156 log.info(f"Added TriggerHLTListRun4 to TriggerHLTListRun3. EDM entries {lenPreMerge} -> {lenPostMerge}")
157 else:
158 errMsg="ERROR the getRawTriggerEDMList function supports runs 3 and 4."
159 log.error(errMsg)
160 raise RuntimeError(errMsg)
161
162 if flags and flags.Trigger.ExtraEDMList:
163 log.info( "Adding extra collections to EDM %i: %s", runVersion, str(flags.Trigger.ExtraEDMList))
164 _addExtraCollectionsToEDMList(edmListCopy, flags.Trigger.ExtraEDMList)
165
166 return edmListCopy
167
168def getTriggerEDMList(flags, key, runVersion=-1):
169 """
170 List (Literally Python dict) of trigger objects to be placed with flags:
171 flags is the CA flag container
172 key can be" 'ESD', 'AODSLIM', 'AODFULL'
173 runVersion can be: '-1 (Auto-configure)', '1 (Run1)', '2 (Run2)', '3' (Run 3), '4' (Run 4)
174 """
175 # We allow for this to be overriden as Run1 bytestream actually need to request the Run2 EDM due to it additionally undergoing a transient xAOD migration.
176 if runVersion == -1:
177 runVersion = flags.Trigger.EDMVersion
178
179 if runVersion == 1:
180 return _getTriggerRun1Run2ObjList(key, [TriggerL2List,TriggerEFList, TriggerResultsRun1List])
181
182 elif runVersion == 2:
183 edmList = _getTriggerRun1Run2ObjList(key, [TriggerHLTList, TriggerResultsList])
184 return _getTriggerRun2EDMSlimList(key, edmList) if 'SLIM' in key else edmList
185
186 elif runVersion >= 3:
187 RawEDMList = getRawTriggerEDMList(flags=flags, runVersion=runVersion)
188
189 if key not in AllowedOutputFormats: # AllowedOutputFormats is the entire list of output formats including ESD
190 log.warning('Output format: %s is not in list of allowed formats, please check!', key)
191 return _getRun3TrigObjList(key, [RawEDMList])
192
193 # this keeps only the dynamic variables that have been specified in TriggerEDMRun3
194 Run3TrigEDM = {}
195 Run3TrigEDMSLIM = {}
196
197 if "AODFULL" in key:
198 Run3TrigEDM.update(_getRun3TrigEDMSlimList(key, RawEDMList))
199
200 elif "AODSLIM" in key:
201 # remove the variables that are defined in TriggerEDMRun3.varToRemoveFromAODSLIM from the containers
202
203 # get all containers from list that are marked with AODSLIM
204 if len(varToRemoveFromAODSLIM) == 0:
205 Run3TrigEDM.update(_getRun3TrigEDMSlimList(key, RawEDMList))
206 log.info("No decorations are listed to be removed from AODSLIM")
207 else:
208 Run3TrigEDMSLIM.update(_getRun3TrigEDMSlimList(key, RawEDMList))
209 log.info("The following decorations are going to be removed from the listed collections in AODSLIM {}".format(varToRemoveFromAODSLIM))
210 # Go through all container values and remove the variables to remove
211 # Format of Run3TrigEDMSLIM is {'xAOD::Cont': ['coll1.varA.varB', 'coll2.varD',...],...}
212 for cont, values in Run3TrigEDMSLIM.items():
213 if (isinstance(values, list)):
214 newValues = []
215 for value in values:
216 newValue = value+'.'
217 coll = value.split('.')[0]
218
219 varRemovedFlag = False
220 for myTuple in varToRemoveFromAODSLIM:
221 var = myTuple[0]
222
223 if var in value and coll in myTuple:
224 varRemovedFlag = True
225 removeVar = '.'+var+'.'
226 newValue = newValue.replace(removeVar, '.')
227
228 if newValue[-1:] == '.':
229 newValue = newValue[:-1]
230
231 if varRemovedFlag is False:
232 newValues.append(value)
233 elif varRemovedFlag is True:
234 newValues.append(newValue)
235 else:
236 raise RuntimeError("Decoration removed but no new Value was available, not sure what to do...")
237
238 # Filling the Run3TrigEDM dictionary with the new set of values for each cont
239 Run3TrigEDM[cont] = newValues
240 else:
241 raise RuntimeError("Value in Run3TrigEDM dictionary is not a list")
242
243 else: # ESD
244 Run3TrigEDM.update(_getRun3TrigEDMSlimList(key, RawEDMList))
245
246 log.debug('TriggerEDM for EDM set {} contains the following collections: {}'.format(key, Run3TrigEDM) )
247 return Run3TrigEDM
248
249
250 else:
251 raise RuntimeError("Invalid runVersion=%s supplied to getTriggerEDMList" % runVersion)
252
253
254
255def _getRun3TrigObjProducedInView(theKey, trigEDMList):
256 """
257 Run 3 only
258 Finds a given key from within the trigEDMList.
259 Returns true if this collection is produced inside EventViews
260 (Hence, has the special viewIndex Aux decoration applied by steering)
261 """
262 from TrigEDMConfig.TriggerEDMRun3 import InViews
263
264 return any(coll for coll in itertools.chain(*trigEDMList) if
265 len(coll)>3 and theKey==coll[0].split('#')[1] and
266 any(isinstance(v, InViews) for v in coll[3]))
267
268
269def _handleRun3ViewContainers( el, HLTList ):
270 if 'Aux.' in el:
271 # Get equivalent non-aux string (fragile!!!)
272 keyNoAux = el.split('.')[0].replace('Aux','')
273 # Check if this interface container is produced inside a View
274 inView = _getRun3TrigObjProducedInView(keyNoAux, [HLTList])
275 if el.split('.')[1] == '':
276 # Aux lists zero dynamic vars to save ...
277 if inView:
278 # ... but it was produced in a View, so we need to add the viewIndex dynamic aux
279 return el.split('.')[0]+'.viewIndex'
280 else:
281 # ... and was not in a View, strip all dynamic
282 return el.split('.')[0]+'.-'
283 else:
284 # Aux lists one or more dynamic vars to save ...
285 if inView:
286 # ... and was produced in a View, so add the viewIndex dynamic as well
287 return el+'.viewIndex'
288 else:
289 # ... and was not produced in a View, keep user-supplied list
290 return el
291 else: # no Aux
292 return el
293
294
295def getRun3BSList(flags, keys):
296 """
297 The keys should contain BS and all the identifiers used for scouting.
298 Returns list of tuples (typename#key, [keys], [properties]).
299 """
300
301 from TrigEDMConfig.TriggerEDMRun3 import persistent
302 keys = set(keys[:])
303 collections = []
304 _HLTList = getRawTriggerEDMList(flags, 3)
305 for definition in _HLTList:
306
307 typename,collkey = definition[0].split("#")
308 # normalise collection name and the key (decorations)
309 typename = persistent(typename)
310 collkey = _handleRun3ViewContainers( collkey, _HLTList )
311 destination = keys & set(definition[1].split())
312 if len(destination) > 0:
313 collections.append( (typename+"#"+collkey, list(destination),
314 definition[3] if len(definition)>3 else []) )
315
316 return collections
317
318
319def _getRun3TrigObjList(destination, trigEDMList):
320 """
321 Run 3 version
322 Gives back the Python dictionary with the content of ESD/AOD (dst) which can be inserted in OKS.
323 """
324 dset = set(destination.split())
325 toadd = defaultdict(list)
326
327 for item in itertools.chain(*trigEDMList):
328 if item[1] == '': # no output has been defined
329 continue
330
331 confset = set(item[1].split())
332
333 if dset & confset: # intersection of the sets
334 colltype, k = _getTypeAndKey(item[0])
335
336 if k not in toadd[colltype]:
337 toadd[colltype] += [k]
338
339 return toadd
340
341
342def _getRun3TrigEDMSlimList(key, HLTList):
343 """
344 Run 3 version
345 Modified EDM list to remove all dynamic variables
346 Requires changing the list to have 'Aux.-'
347 """
348 _edmList = _getRun3TrigObjList(key,[HLTList])
349
350 output = {}
351 for k,v in _edmList.items():
352 output[k] = [_handleRun3ViewContainers( el, HLTList ) for el in v]
353 return output
354
355#************************************************************
356#
357# For Run 1 and Run 2 (not modified (so far))
358#
359#************************************************************
361 """
362 Run 2 version
363 Modified EDM list to remove all dynamic variables
364 Requires changing the list to have 'Aux.-'
365 """
366 output = {}
367 for k,v in edmList.items():
368 newnames = []
369 for el in v:
370 if 'Aux' in el:
371 newnames+=[el.split('.')[0]+'.-']
372 else:
373 newnames+=[el]
374 output[k] = newnames
375 return output
376
378 """ From name of object in AOD/ESD found by checkFileTrigSize.py, return category """
379
380 """ Clean up object name """
381 s = s.strip()
382
383 # To-do
384 # seperate the first part of the string at the first '_'
385 # search in EDMDetails for the key corresponding to the persistent value
386 # if a key is found, use this as the first part of the original string
387 # put the string back together
388
389 if s.count('.') : s = s[:s.index('.')]
390 if s.count('::'): s = s[s.index(':')+2:]
391 if s.count('<'): s = s[s.index('<')+1:]
392 if s.count('>'): s = s[:s.index('>')]
393 if s.count('.') : s = s[:s.index('.')]
394 if s.count('Dyn') : s = s[:s.index('Dyn')]
395
396 # containers from Run 1-2 and 3 require different preprocessing
397 # s12 is for Run 1-2, s is for Run 3
398 s12 = s
399
400 if s12.startswith('HLT_xAOD__') or s12.startswith('HLT_Rec__') or s12.startswith('HLT_Analysis__') :
401 s12 = s12[s12.index('__')+2:]
402 s12 = s12[s12.index('_')+1:]
403 #if s12.count('.') : s12 = s12[:s12.index('.')]
404 s12 = "HLT_"+s12
405 elif s12.startswith('HLT_'):
406 #if s.count('Dyn') : s = s[:s.index('Dyn')]
407 if s12.count('_'): s12 = s12[s12.index('_')+1:]
408 if s12.count('_'): s12 = s12[s12.index('_')+1:]
409 s12 = "HLT_"+s12
410
411 TriggerListRun1 = TriggerL2List + TriggerEFList + TriggerResultsRun1List
412 TriggerListRun2 = TriggerResultsList + TriggerLvl1List + TriggerIDTruth + TriggerHLTList
413 TriggerListRun3 = getRawTriggerEDMList(flags=None, runVersion=3)
414
415 category = ''
416 bestMatch = ''
417
418 """ Loop over all objects already defined in lists (and hopefully categorized!!) """
419 for item in TriggerListRun1+TriggerListRun2:
420 t,k = _getTypeAndKey(item[0])
421
422 """ Clean up type name """
423 if t.count('::'): t = t[t.index(':')+2:]
424 if t.count('<'): t = t[t.index('<')+1:]
425 if t.count('>'): t = t[:t.index('>')]
426 if (s12.startswith(t) and s12.endswith(k)) and (len(t) > len(bestMatch)):
427 bestMatch = t
428 category = item[2]
429
430 if k.count('.'): k = k[:k.index('.')]
431 if (s12 == k):
432 bestMatch = k
433 category = item[2]
434
435 for item in TriggerListRun3:
436 t,k = _getTypeAndKey(item[0])
437
438 """ Clean up type name """
439 if t.count('::'): t = t[t.index(':')+2:]
440 if t.count('<'): t = t[t.index('<')+1:]
441 if t.count('>'): t = t[:t.index('>')]
442
443 if (s.startswith(t) and s.endswith(k)) and (len(t) > len(bestMatch)):
444 bestMatch = t
445 category = item[2]
446
447 if k.count('.'): k = k[:k.index('.')]
448 if (s == k):
449 bestMatch = k
450 category = item[2]
451
452 if category == '' and 'HLTNav' in s:
453 category = 'HLTNav'
454
455 if category == '': return 'NOTFOUND'
456 return category
457
458
459
461 """ From the strings containing type and key of trigger EDM extract type and key
462 """
463 return s[:s.index('#')], s[s.index('#')+1:]
464
465def _keyToLabel(key):
466 """ The key is usually HLT_*, this function returns second part of it or empty string
467 """
468 if '_' not in key:
469 return ''
470 else:
471 return key[key.index('_'):].lstrip('_')
472
473def _getTriggerRun1Run2ObjList(destination, lst):
474 """
475 Gives back the Python dictionary with the content of ESD/AOD (dst) which can be inserted in OKS.
476 """
477 dset = set(destination.split())
478
479 toadd = {}
480
481 for item in itertools.chain(*lst):
482 if item[1] == '':
483 continue
484 confset = set(item[1].split())
485 if dset & confset: # intersection of the sets
486 t,k = _getTypeAndKey(item[0])
487 colltype = t
488 if 'collection' in EDMDetails[t]:
489 colltype = EDMDetails[t]['collection']
490 if colltype in toadd:
491 if k not in toadd[colltype]:
492 toadd[colltype] += [k]
493 else:
494 toadd[colltype] = [k]
495 return _InsertContainerNameForHLT(toadd)
496
497
499 """
500 Gives back the Python dictionary with the truth trigger content of ESD/AOD (dst) which can be inserted in OKS.
501 """
502 return _getTriggerRun1Run2ObjList(dst,[TriggerIDTruth])
503
505 """
506 Gives back the Python dictionary with the lvl1 trigger result content of ESD which can be inserted in OKS.
507 """
508 return _getTriggerRun1Run2ObjList('ESD',[TriggerLvl1List])
509
511 """
512 Gives back the Python dictionary with the lvl1 trigger result content of AOD which can be inserted in OKS.
513 """
514 return _getTriggerRun1Run2ObjList('AODFULL',[TriggerLvl1List])
515
516
517
519 """
520 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for L2
521 """
522 l = []
523 for item in TriggerL2List:
524 if len (item[1]) == 0: continue
525 t,k = _getTypeAndKey(item[0])
526 if('Aux' in t):
527 continue #we don't wat to preregister Aux containers
528 l += [t+"#"+_keyToLabel(k)]
529 return l
530
532 """
533 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for EF
534 """
535 l = []
536 for item in TriggerEFList:
537 if len (item[1]) == 0: continue
538 t,k = _getTypeAndKey(item[0])
539 if('Aux' in t):
540 continue #we don't wat to preregister Aux containers
541 l += [t+"#"+_keyToLabel(k)]
542 return l
543
545 """
546 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for merged L2/EF in addition to default L2 and EF
547 """
548 l = []
549 for item in TriggerHLTList:
550 if len (item[1]) == 0: continue
551 t,k = _getTypeAndKey(item[0])
552 if('Aux' in t):
553 continue #we don't wat to preregister Aux containers
554 l += [t+"#"+_keyToLabel(k)]
555 return l
556
557
558def getPreregistrationList(version=2, doxAODConversion=True):
559 """
560 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want for all levels
561 version can be: '1 (Run1)', '2 (Run2)'
562 """
563
564 l=[]
565 if version==2:
567 elif version==1:
568 # remove duplicates while preserving order
570 if doxAODConversion:
572 l=list(dict.fromkeys(objs))
573 else:
574 raise RuntimeError("Invalid version=%s supplied to getPreregistrationList" % version)
575 return l
576
577
579 """ List of L2 types to be read from BS, used by the TP
580 """
581 l = []
582 for item in TriggerL2List:
583 t,k = _getTypeAndKey(item[0])
584 ctype = t
585 if 'collection' in EDMDetails[t]:
586 ctype = EDMDetails[t]['collection']
587 l += [ctype]
588 return l
589
591 """ List of EF types to be read from BS, used by the TP
592 """
593 l = []
594 for item in TriggerEFList:
595 t,k = _getTypeAndKey(item[0])
596 ctype = t
597 if 'collection' in EDMDetails[t]:
598 ctype = EDMDetails[t]['collection']
599 l += [ctype]
600 return l
601
603 """ List of HLT types to be read from BS, used by the TP
604 """
605 l = []
606 for item in TriggerHLTList:
607 t,k = _getTypeAndKey(item[0])
608 ctype = t
609 if 'collection' in EDMDetails[t]:
610 ctype = EDMDetails[t]['collection']
611 l += [ctype]
612 return l
613
614def getTPList(version=2):
615 """
616 Mapping of Transient objects to Peristent during serialization (BS creation)
617 version can be: '1 (Run1)', '2 (Run2)'
618 """
619 l = {}
620 if version==2:
621 bslist = _getHLTBSTypeList()
622 elif version==1:
623 bslist = list(set(_getL2BSTypeList() + _getEFBSTypeList()))
624 else:
625 raise RuntimeError("Invalid version=%s supplied to getTPList" % version)
626
627 for t,d in EDMDetails.items():
628 colltype = t
629 if 'collection' in d:
630 colltype = EDMDetails[t]['collection']
631 if colltype in bslist:
632 l[colltype] = d['persistent']
633 return l
634
635
637 return EDMLibraries
638
640 import re
641 output = {}
642 for k,v in typedict.items():
643 newnames = []
644 for el in v:
645 if el.startswith('HLT_') or el == 'HLT':
646 prefixAndLabel = el.split('_',1) #only split on first underscore
647 containername = k if 'Aux' not in k else EDMDetails[k]['parent'] #we want the type in the Aux SG key to be the parent type #104811
648 #maybe this is not needed anymore since we are now versionless with the CLIDs but it's not hurting either
649 containername = re.sub('::','__',re.sub('_v[0-9]+$','',containername))
650 newnames+=['_'.join([prefixAndLabel[0],containername]+([prefixAndLabel[1]] if len(prefixAndLabel) > 1 else []))]
651 else:
652 newnames+=[el]
653 output[k] = newnames
654 return output
655
657 """
658 List of EF trigger objects that were written to ByteStream in Run 1
659 """
660 l = []
661 for item in TriggerEFEvolutionList:
662 if len (item[1]) == 0: continue
663 t,k = _getTypeAndKey(item[0])
664 l += [t+"#"+_keyToLabel(k)]
665 return l
666
668 """
669 List of Run-2 containers equivalent to Run-1 EF containers
670 """
671 l = []
672 for item in TriggerEFEvolutionList:
673 if len (item[1]) == 0: continue
674 t,k = _getTypeAndKey(item[1])
675 l += [t+"#"+_keyToLabel(k)]
676 return l
677
679 """
680 List of L2 trigger objects that were written to ByteStream in Run 1
681 """
682 l = []
683 for item in TriggerL2EvolutionList:
684 if len (item[1]) == 0: continue
685 t,k = _getTypeAndKey(item[0])
686 l += [t+"#"+_keyToLabel(k)]
687 return l
688
690 """
691 List of Run-2 containers equivalent to Run-1 L2 containers
692 """
693 l = []
694 for item in TriggerL2EvolutionList:
695 if len (item[1]) == 0: continue
696 t,k = _getTypeAndKey(item[1])
697 l += [t+"#"+_keyToLabel(k)]
698 return l
699
700def isCLIDDefined(cgen,typename):
701 """
702 Checks container type name is hashable
703 """
704 c = cgen.genClidFromName(typename)
705 return (cgen.getNameFromClid(c) is not None)
706
707def testEDMList(edm_list, error_on_edmdetails = True):
708 """
709 Checks EDM list entries for serialization and configuration compliance.
710 """
711
712 #xAOD types that don't expect accompanying Aux containers
713 _noAuxList = ["xAOD::" + contType for contType in ["TrigConfKeys", "BunchConfKey"]]
714
715 cgen = clidGenerator("", False)
716 return_code = 0
717 found_allow_truncation = False
718 serializable_names = []
719 serializable_names_no_label = []
720 serializable_names_no_properties = []
721
722 for i, edm in enumerate(edm_list):
723
724 #check has sufficient entries
725 if len(edm) < 3:
726 log.error("EDM entry too short for " + edm[0])
727 return_code = 1
728 continue
729
730 serializable_name = edm[0]
731 serializable_name_no_label = re.sub(r"\#.*", "", serializable_name)
732 serializable_name_no_properties = serializable_name.split('.')[0]
733
734 serializable_names.append(serializable_name)
735 serializable_names_no_label.append(serializable_name_no_label)
736 serializable_names_no_properties.append(serializable_name_no_properties)
737
738 #check container type name is hashable
739 if not isCLIDDefined(cgen,serializable_name_no_label):
740 log.error("no CLID for " + serializable_name)
741 return_code = 1
742
743 #check that no '.' in entries _not_ containing 'Aux'
744 if "Aux" not in serializable_name and "." in serializable_name:
745 log.error("A '.' found in non-Aux container name " + serializable_name)
746 return_code = 1
747
748 #check for Aux "."
749 if "Aux" in serializable_name and "Aux." not in serializable_name:
750 log.error("no final Aux. in label for " + serializable_name)
751 return_code = 1
752
753 #check contains exactly one #
754 if serializable_name.count("#") != 1:
755 log.error("Invalid naming structure for " + serializable_name)
756 return_code = 1
757 else: # only proceed if type and name can be separated
758 #check that every interface xAOD container directly followed by matching Aux container.
759 if serializable_name.startswith("xAOD") and "Aux" not in serializable_name:
760 cont_type,cont_name = serializable_name.split("#")
761 if cont_type not in _noAuxList:
762 auxmismatch = False
763 if len(edm_list) == i+1:
764 auxmismatch = True
765 cont_to_test = "nothing"
766 else:
767 cont_to_test = edm_list[i+1][0].split(".")[0]+"."
768 cont_type_short = cont_type.replace("Container","")
769 pattern = re.compile(cont_type_short+r".*Aux.*\#"+cont_name+"Aux.")
770 if not pattern.match(cont_to_test):
771 #test if shallow container type.
772 shallow_pattern = re.compile("xAOD::ShallowAuxContainer#"+cont_name+"Aux.")
773 if not shallow_pattern.match(cont_to_test):
774 auxmismatch = True
775 if auxmismatch:
776 log.error("Expected relevant Aux container following interface container %s, but found %s instead.",serializable_name,cont_to_test)
777 return_code = 1
778 else:
779 #check that targets of interface and aux container match
780 targets = set(edm[1].split())
781 if len(edm_list[i+1]) > 1 and cont_to_test.count("#") == 1:
782 contname_to_test = cont_to_test.split("#")[1]
783 targets_to_test = set(edm_list[i+1][1].split())
784 if len(targets ^ targets_to_test) > 0:
785 log.error("Targets of %s (%s) and %s (%s) do not match",cont_name,targets,contname_to_test,targets_to_test)
786 return_code = 1
787
788 #check that Aux always follows non-Aux (our deserialiser relies on that)
789 if i>0 and "Aux" in serializable_name and "Aux" in edm_list[i-1][0]:
790 log.error(f"Aux container {serializable_name} needs to folow the "
791 "associated interface container in the EDM list")
792 return_code = 1
793
794 #check target types are valid. Check that target lists containing higher level targets
795 #have required low level targets (ESD for AOD targets, AODFULL for SLIM targets).
796 file_types = edm[1].split() # might return empty list, this is fine - 0 output file types allowed for an EDM entry (in case of obsolete containers)
797 for file_type in file_types:
798 if file_type not in AllowedOutputFormats:
799 log.error("unknown file type " + file_type + " for " + serializable_name)
800 return_code = 1
801 for higher_level,required_lower_level in [('AOD','ESD'), ('SLIM','AODFULL')]:
802 if higher_level in file_type and required_lower_level not in file_types:
803 log.error("Target list for %s containing '%s' must also contain lower level target '%s'.",serializable_name,file_type,required_lower_level)
804 return_code = 1
805
806 # Check allowTuncation is only at the end
807 tags = edm[3] if len(edm) > 3 else None
808 allow_truncation_flag = False
809 if tags:
810 allow_truncation_flag = allowTruncation in tags
811 if allow_truncation_flag:
812 found_allow_truncation = True
813
814 if found_allow_truncation and not allow_truncation_flag:
815 log.error("All instances of 'allowTruncation' need to be at the END of the EDM serialisation list")
816 return_code = 1
817
818 #end of for loop over entries. Now do complete list checks.
819
820 #check for duplicates:
821 #check that no two EDM entries match after stripping out characters afer '.'
822 if not len(set(serializable_names_no_properties)) == len(serializable_names_no_properties):
823 log.error("Duplicates in EDM list! Duplicates found:")
824 import collections.abc
825 for item, count in collections.Counter(serializable_names_no_properties).items():
826 if count > 1:
827 log.error(str(count) + "x: " + str(item))
828 return_code = 1
829
830 #check EDMDetails
831 for EDMDetail in EDMDetailsRun3.keys():
832 if EDMDetail not in serializable_names_no_label:
833 msg = "EDMDetail for " + EDMDetail + " does not correspond to any name in TriggerList"
834 if error_on_edmdetails:
835 log.error(msg)
836 return_code = 1
837 else:
838 log.warning(msg)
839
840 return return_code
if(pathvar)
STL class.
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:312
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
getPreregistrationList(version=2, doxAODConversion=True)
isCLIDDefined(cgen, typename)
_getRun3TrigEDMSlimList(key, HLTList)
getRun3BSList(flags, keys)
_getTriggerRun1Run2ObjList(destination, lst)
_getRun3TrigObjList(destination, trigEDMList)
getTPList(version=2)
getTriggerEDMList(flags, key, runVersion=-1)
_InsertContainerNameForHLT(typedict)
testEDMList(edm_list, error_on_edmdetails=True)
_addExtraCollectionsToEDMList(edmList, extraList)
Definition TriggerEDM.py:73
_getTriggerRun2EDMSlimList(key, edmList)
_getRun3TrigObjProducedInView(theKey, trigEDMList)
getRawTriggerEDMList(flags, runVersion=-1)
_handleRun3ViewContainers(el, HLTList)