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