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
17 from AthenaCommon.Logging
import logging
18 log = logging.getLogger(
'TriggerEDM')
29 AllowedOutputFormats = [
'BS',
'ESD',
'AODFULL',
'AODSLIM',
'AODBLSSLIM' ]
30 from TrigEDMConfig
import DataScoutingInfo
31 AllowedOutputFormats.extend(DataScoutingInfo.getAllDataScoutingIdentifiers())
33 _allowedEDMPrefixes = [
'HLT_',
'L1_',
'LVL1']
36 Verify that the name is in the list of recorded objects and conform to the name convention
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.
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
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.
54 log.error(
"Don't call recordable({0}), or add any \"HLTNav_\" collection manually to the EDM. See:collectDecisionObjects.".
format( name ) )
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 '.'" )
63 for entry
in TriggerHLTListRun3:
64 if entry[0].
split(
"#" )[1] == name:
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 )
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.
76 existing_collections = [(c[0].
split(
"#")[1]).
split(
".")[0]
for c
in edmList]
78 for item
in extraList:
79 colname = (item[0].
split(
"#")[1]).
split(
".")[0]
80 if colname
not in existing_collections:
83 edmList.insert(insert_idx+1,item)
85 edmList.insert(insert_idx,item)
86 log.info(
"added new item to Trigger EDM: {}".
format(item))
89 isAux =
"Aux." in item[0]
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]]
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))
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]
111 tags = existingItem[3]
if len(existingItem) > 3
else None
112 edmList.pop(existing_item_nr[0])
113 combName = typename +
"#" + colname
115 combName +=
"." + newVars
117 edmList.insert(existing_item_nr[0], (combName, newTargets, signature, tags))
119 edmList.insert(existing_item_nr[0] , (combName, newTargets, signature))
120 log.info(
"updated item in Trigger EDM: {}".
format(edmList[existing_item_nr[0]]))
122 if testEDMList(edmList, error_on_edmdetails=
False):
123 log.error(
"edmList contains inconsistencies!")
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
131 runVersion = flags.Trigger.EDMVersion
134 edmListCopy = TriggerHLTListRun3.copy()
135 elif runVersion == 4:
136 edm4ListCopy = TriggerHLTListRun4.copy()
137 edm3ListCopy = TriggerHLTListRun3.copy()
138 log.debug(
"Removing duplicated item between TriggerHLTListRun3 and TriggerHLTListRun4.")
139 for i
in range(len(edm3ListCopy)-1, -1, -1):
140 for r4item
in edm4ListCopy:
141 if edm3ListCopy[i][0] == r4item[0]:
143 log.debug(f
"- Dupe: {r4item} is removed from TriggerHLTListRun3 to be updated by TriggerHLTListRun4")
145 lenPreMerge = len(edm3ListCopy)
146 edm4ListCopy.extend(edm3ListCopy)
147 lenPostMerge = len(edm4ListCopy)
148 edmListCopy = edm4ListCopy
149 log.info(f
"Added TriggerHLTListRun4 to TriggerHLTListRun3. EDM entries {lenPreMerge} -> {lenPostMerge}")
150 if testEDMList(edmListCopy, error_on_edmdetails=
False):
151 log.error(
"edmList contains inconsistencies!")
153 errMsg=
"ERROR the getRawTriggerEDMList function supports runs 3 and 4."
155 raise RuntimeError(errMsg)
157 if flags
and flags.Trigger.ExtraEDMList:
158 log.info(
"Adding extra collections to EDM %i: %s", runVersion,
str(flags.Trigger.ExtraEDMList))
165 List (Literally Python dict) of trigger objects to be placed with flags:
166 flags is the CA flag container
167 key can be" 'ESD', 'AODSLIM', 'AODFULL'
168 runVersion can be: '-1 (Auto-configure)', '1 (Run1)', '2 (Run2)', '3' (Run 3), '4' (Run 4)
172 runVersion = flags.Trigger.EDMVersion
177 elif runVersion == 2:
181 elif runVersion >= 3:
184 if key
not in AllowedOutputFormats:
185 log.warning(
'Output format: %s is not in list of allowed formats, please check!', key)
195 elif "AODSLIM" in key:
199 if len(varToRemoveFromAODSLIM) == 0:
201 log.info(
"No decorations are listed to be removed from AODSLIM")
204 log.info(
"The following decorations are going to be removed from the listed collections in AODSLIM {}".
format(varToRemoveFromAODSLIM))
207 for cont, values
in Run3TrigEDMSLIM.items():
208 if (isinstance(values, list)):
212 coll = value.split(
'.')[0]
214 varRemovedFlag =
False
215 for myTuple
in varToRemoveFromAODSLIM:
218 if var
in value
and coll
in myTuple:
219 varRemovedFlag =
True
220 removeVar =
'.'+var+
'.'
221 newValue = newValue.replace(removeVar,
'.')
223 if newValue[-1:] ==
'.':
224 newValue = newValue[:-1]
226 if varRemovedFlag
is False:
227 newValues.append(value)
228 elif varRemovedFlag
is True:
229 newValues.append(newValue)
231 raise RuntimeError(
"Decoration removed but no new Value was available, not sure what to do...")
234 Run3TrigEDM[cont] = newValues
236 raise RuntimeError(
"Value in Run3TrigEDM dictionary is not a list")
241 log.debug(
'TriggerEDM for EDM set {} contains the following collections: {}'.
format(key, Run3TrigEDM) )
246 raise RuntimeError(
"Invalid runVersion=%s supplied to getTriggerEDMList" % runVersion)
253 Finds a given key from within the trigEDMList.
254 Returns true if this collection is produced inside EventViews
255 (Hence, has the special viewIndex Aux decoration applied by steering)
257 from TrigEDMConfig.TriggerEDMRun3
import InViews
260 return any(coll
for coll
in itertools.chain(*trigEDMList)
if
261 len(coll)>3
and theKey==coll[0].
split(
'#')[1]
and
262 any(isinstance(v, InViews)
for v
in coll[3]))
268 keyNoAux = el.split(
'.')[0].
replace(
'Aux',
'')
271 if el.split(
'.')[1] ==
'':
275 return el.split(
'.')[0]+
'.viewIndex'
278 return el.split(
'.')[0]+
'.-'
283 return el+
'.viewIndex'
293 The keys should contain BS and all the identifiers used for scouting.
294 Returns list of tuples (typename#key, [keys], [properties]).
297 from TrigEDMConfig.TriggerEDMRun3
import persistent
301 for definition
in _HLTList:
303 typename,collkey = definition[0].
split(
"#")
307 destination = keys &
set(definition[1].
split())
308 if len(destination) > 0:
309 collections.append( (typename+
"#"+collkey,
list(destination),
310 definition[3]
if len(definition)>3
else []) )
318 Gives back the Python dictionary with the content of ESD/AOD (dst) which can be inserted in OKS.
320 dset =
set(destination.split())
321 from collections
import OrderedDict
322 toadd = OrderedDict()
325 for item
in itertools.chain(*trigEDMList):
335 if colltype
in toadd:
336 if k
not in toadd[colltype]:
337 toadd[colltype] += [k]
339 toadd[colltype] = [k]
347 Modified EDM list to remove all dynamic variables
348 Requires changing the list to have 'Aux.-'
351 from collections
import OrderedDict
352 output = OrderedDict()
353 for k,v
in _edmList.items():
368 Modified EDM list to remove all dynamic variables
369 Requires changing the list to have 'Aux.-'
372 for k,v
in edmList.items():
376 newnames+=[el.split(
'.')[0]+
'.-']
383 """ From name of object in AOD/ESD found by checkFileTrigSize.py, return category """
385 """ Clean up object name """
394 if s.count(
'.') : s = s[:s.index(
'.')]
395 if s.count(
'::'): s = s[s.index(
':')+2:]
396 if s.count(
'<'): s = s[s.index(
'<')+1:]
397 if s.count(
'>'): s = s[:s.index(
'>')]
398 if s.count(
'.') : s = s[:s.index(
'.')]
399 if s.count(
'Dyn') : s = s[:s.index(
'Dyn')]
405 if s12.startswith(
'HLT_xAOD__')
or s12.startswith(
'HLT_Rec__')
or s12.startswith(
'HLT_Analysis__') :
406 s12 = s12[s12.index(
'__')+2:]
407 s12 = s12[s12.index(
'_')+1:]
410 elif s12.startswith(
'HLT_'):
412 if s12.count(
'_'): s12 = s12[s12.index(
'_')+1:]
413 if s12.count(
'_'): s12 = s12[s12.index(
'_')+1:]
416 TriggerListRun1 = TriggerL2List + TriggerEFList + TriggerResultsRun1List
417 TriggerListRun2 = TriggerResultsList + TriggerLvl1List + TriggerIDTruth + TriggerHLTList
423 """ Loop over all objects already defined in lists (and hopefully categorized!!) """
424 for item
in TriggerListRun1+TriggerListRun2:
427 """ Clean up type name """
428 if t.count(
'::'): t = t[t.index(
':')+2:]
429 if t.count(
'<'): t = t[t.index(
'<')+1:]
430 if t.count(
'>'): t = t[:t.index(
'>')]
431 if (s12.startswith(t)
and s12.endswith(k))
and (len(t) > len(bestMatch)):
435 if k.count(
'.'): k = k[:k.index(
'.')]
440 for item
in TriggerListRun3:
443 """ Clean up type name """
444 if t.count(
'::'): t = t[t.index(
':')+2:]
445 if t.count(
'<'): t = t[t.index(
'<')+1:]
446 if t.count(
'>'): t = t[:t.index(
'>')]
448 if (s.startswith(t)
and s.endswith(k))
and (len(t) > len(bestMatch)):
452 if k.count(
'.'): k = k[:k.index(
'.')]
457 if category ==
'' and 'HLTNav' in s:
460 if category ==
'':
return 'NOTFOUND'
466 """ From the strings containing type and key of trigger EDM extract type and key
468 return s[:s.index(
'#')], s[s.index(
'#')+1:]
471 """ The key is usually HLT_*, this function returns second part of it or empty string
476 return key[key.index(
'_'):].lstrip(
'_')
480 Gives back the Python dictionary with the content of ESD/AOD (dst) which can be inserted in OKS.
482 dset =
set(destination.split())
487 for item
in itertools.chain(*lst):
494 if 'collection' in EDMDetails[t]:
495 colltype = EDMDetails[t][
'collection']
496 if colltype
in toadd:
497 if k
not in toadd[colltype]:
498 toadd[colltype] += [k]
500 toadd[colltype] = [k]
506 Gives back the Python dictionary with the truth trigger content of ESD/AOD (dst) which can be inserted in OKS.
512 Gives back the Python dictionary with the lvl1 trigger result content of ESD which can be inserted in OKS.
518 Gives back the Python dictionary with the lvl1 trigger result content of AOD which can be inserted in OKS.
526 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for L2
529 for item
in TriggerL2List:
530 if len (item[1]) == 0:
continue
539 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for EF
542 for item
in TriggerEFList:
543 if len (item[1]) == 0:
continue
552 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
555 for item
in TriggerHLTList:
556 if len (item[1]) == 0:
continue
566 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want for all levels
567 version can be: '1 (Run1)', '2 (Run2)'
578 l=
list(dict.fromkeys(objs))
580 raise RuntimeError(
"Invalid version=%s supplied to getPreregistrationList" % version)
585 """ List of L2 types to be read from BS, used by the TP
588 for item
in TriggerL2List:
591 if 'collection' in EDMDetails[t]:
592 ctype = EDMDetails[t][
'collection']
597 """ List of EF types to be read from BS, used by the TP
600 for item
in TriggerEFList:
603 if 'collection' in EDMDetails[t]:
604 ctype = EDMDetails[t][
'collection']
609 """ List of HLT types to be read from BS, used by the TP
612 for item
in TriggerHLTList:
615 if 'collection' in EDMDetails[t]:
616 ctype = EDMDetails[t][
'collection']
622 Mapping of Transient objects to Peristent during serialization (BS creation)
623 version can be: '1 (Run1)', '2 (Run2)'
631 raise RuntimeError(
"Invalid version=%s supplied to getTPList" % version)
633 for t,d
in EDMDetails.items():
635 if 'collection' in d:
636 colltype = EDMDetails[t][
'collection']
637 if colltype
in bslist:
638 l[colltype] = d[
'persistent']
648 for k,v
in typedict.items():
651 if el.startswith(
'HLT_')
or el ==
'HLT':
652 prefixAndLabel = el.split(
'_',1)
653 containername = k
if 'Aux' not in k
else EDMDetails[k][
'parent']
655 containername = re.sub(
'::',
'__',re.sub(
'_v[0-9]+$',
'',containername))
656 newnames+=[
'_'.
join([prefixAndLabel[0],containername]+([prefixAndLabel[1]]
if len(prefixAndLabel) > 1
else []))]
664 List of EF trigger objects that were written to ByteStream in Run 1
667 for item
in TriggerEFEvolutionList:
668 if len (item[1]) == 0:
continue
675 List of Run-2 containers equivalent to Run-1 EF containers
678 for item
in TriggerEFEvolutionList:
679 if len (item[1]) == 0:
continue
686 List of L2 trigger objects that were written to ByteStream in Run 1
689 for item
in TriggerL2EvolutionList:
690 if len (item[1]) == 0:
continue
697 List of Run-2 containers equivalent to Run-1 L2 containers
700 for item
in TriggerL2EvolutionList:
701 if len (item[1]) == 0:
continue
708 Checks container type name is hashable
710 c = cgen.genClidFromName(typename)
711 return (cgen.getNameFromClid(c)
is not None)
715 Checks EDM list entries for serialization and configuration compliance.
719 _noAuxList = [
"xAOD::" + contType
for contType
in [
"TrigConfKeys",
"BunchConfKey"]]
721 cgen = clidGenerator(
"",
False)
723 found_allow_truncation =
False
724 serializable_names = []
725 serializable_names_no_label = []
726 serializable_names_no_properties = []
728 for i, edm
in enumerate(edm_list):
732 log.error(
"EDM entry too short for " + edm[0])
736 serializable_name = edm[0]
737 serializable_name_no_label = re.sub(
r"\#.*",
"", serializable_name)
738 serializable_name_no_properties = serializable_name.split(
'.')[0]
740 serializable_names.append(serializable_name)
741 serializable_names_no_label.append(serializable_name_no_label)
742 serializable_names_no_properties.append(serializable_name_no_properties)
746 log.error(
"no CLID for " + serializable_name)
750 if "Aux" not in serializable_name
and "." in serializable_name:
751 log.error(
"A '.' found in non-Aux container name " + serializable_name)
755 if "Aux" in serializable_name
and "Aux." not in serializable_name:
756 log.error(
"no final Aux. in label for " + serializable_name)
760 if serializable_name.count(
"#") != 1:
761 log.error(
"Invalid naming structure for " + serializable_name)
765 if serializable_name.startswith(
"xAOD")
and "Aux" not in serializable_name:
766 cont_type,cont_name = serializable_name.split(
"#")
767 if cont_type
not in _noAuxList:
769 if len(edm_list) == i+1:
771 cont_to_test =
"nothing"
773 cont_to_test = edm_list[i+1][0].
split(
".")[0]+
"."
774 cont_type_short = cont_type.replace(
"Container",
"")
775 pattern = re.compile(cont_type_short+
r".*Aux.*\#"+cont_name+
"Aux.")
776 if not pattern.match(cont_to_test):
778 shallow_pattern = re.compile(
"xAOD::ShallowAuxContainer#"+cont_name+
"Aux.")
779 if not shallow_pattern.match(cont_to_test):
782 log.error(
"Expected relevant Aux container following interface container %s, but found %s instead.",serializable_name,cont_to_test)
787 if len(edm_list[i+1]) > 1
and cont_to_test.count(
"#") == 1:
788 contname_to_test = cont_to_test.split(
"#")[1]
789 targets_to_test =
set(edm_list[i+1][1].
split())
790 if len(targets ^ targets_to_test) > 0:
791 log.error(
"Targets of %s (%s) and %s (%s) do not match",cont_name,targets,contname_to_test,targets_to_test)
795 if i>0
and "Aux" in serializable_name
and "Aux" in edm_list[i-1][0]:
796 log.error(f
"Aux container {serializable_name} needs to folow the "
797 "associated interface container in the EDM list")
802 file_types = edm[1].
split()
803 for file_type
in file_types:
804 if file_type
not in AllowedOutputFormats:
805 log.error(
"unknown file type " + file_type +
" for " + serializable_name)
807 for higher_level,required_lower_level
in [(
'AOD',
'ESD'), (
'SLIM',
'AODFULL')]:
808 if higher_level
in file_type
and required_lower_level
not in file_types:
809 log.error(
"Target list for %s containing '%s' must also contain lower level target '%s'.",serializable_name,file_type,required_lower_level)
813 tags = edm[3]
if len(edm) > 3
else None
814 allow_truncation_flag =
False
816 allow_truncation_flag = allowTruncation
in tags
817 if allow_truncation_flag:
818 found_allow_truncation =
True
820 if found_allow_truncation
and not allow_truncation_flag:
821 log.error(
"All instances of 'allowTruncation' need to be at the END of the EDM serialisation list")
828 if not len(
set(serializable_names_no_properties)) == len(serializable_names_no_properties):
829 log.error(
"Duplicates in EDM list! Duplicates found:")
830 import collections.abc
831 for item, count
in collections.Counter(serializable_names_no_properties).
items():
833 log.error(
str(count) +
"x: " +
str(item))
837 for EDMDetail
in EDMDetailsRun3.keys():
838 if EDMDetail
not in serializable_names_no_label:
839 msg =
"EDMDetail for " + EDMDetail +
" does not correspond to any name in TriggerList"
840 if error_on_edmdetails: