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
133 if runVersion <= 2
or runVersion > 4:
134 errMsg=
"ERROR the getRawTriggerEDMList function supports runs 3 and 4."
136 raise RuntimeError(errMsg)
139 edmListCopy = TriggerHLTListRun3.copy()
141 edmListCopy = TriggerHLTListRun4.copy()
143 if flags
and flags.Trigger.ExtraEDMList:
144 log.info(
"Adding extra collections to EDM %i: %s", runVersion,
str(flags.Trigger.ExtraEDMList))
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)
159 runVersion = flags.Trigger.EDMVersion
164 elif runVersion == 2:
168 elif runVersion >= 3:
174 for i
in range(len(RawEDMList)-1, -1, -1):
175 for r4item
in TriggerHLTListRun4:
176 if RawEDMList[i][0] == r4item[0]:
179 RawEDMList.extend(TriggerHLTListRun4)
181 if key
not in AllowedOutputFormats:
182 log.warning(
'Output format: %s is not in list of allowed formats, please check!', key)
192 elif "AODSLIM" in key:
196 if len(varToRemoveFromAODSLIM) == 0:
198 log.info(
"No decorations are listed to be removed from AODSLIM")
201 log.info(
"The following decorations are going to be removed from the listed collections in AODSLIM {}".
format(varToRemoveFromAODSLIM))
204 for cont, values
in Run3TrigEDMSLIM.items():
205 if (isinstance(values, list)):
209 coll = value.split(
'.')[0]
211 varRemovedFlag =
False
212 for myTuple
in varToRemoveFromAODSLIM:
215 if var
in value
and coll
in myTuple:
216 varRemovedFlag =
True
217 removeVar =
'.'+var+
'.'
218 newValue = newValue.replace(removeVar,
'.')
220 if newValue[-1:] ==
'.':
221 newValue = newValue[:-1]
223 if varRemovedFlag
is False:
224 newValues.append(value)
225 elif varRemovedFlag
is True:
226 newValues.append(newValue)
228 raise RuntimeError(
"Decoration removed but no new Value was available, not sure what to do...")
231 Run3TrigEDM[cont] = newValues
233 raise RuntimeError(
"Value in Run3TrigEDM dictionary is not a list")
238 log.debug(
'TriggerEDM for EDM set {} contains the following collections: {}'.
format(key, Run3TrigEDM) )
243 raise RuntimeError(
"Invalid runVersion=%s supplied to getTriggerEDMList" % runVersion)
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)
254 from TrigEDMConfig.TriggerEDMRun3
import InViews
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]))
265 keyNoAux = el.split(
'.')[0].
replace(
'Aux',
'')
268 if el.split(
'.')[1] ==
'':
272 return el.split(
'.')[0]+
'.viewIndex'
275 return el.split(
'.')[0]+
'.-'
280 return el+
'.viewIndex'
290 The keys should contain BS and all the identifiers used for scouting.
291 Returns list of tuples (typename#key, [keys], [properties]).
294 from TrigEDMConfig.TriggerEDMRun3
import persistent
298 for definition
in _HLTList:
300 typename,collkey = definition[0].
split(
"#")
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 []) )
315 Gives back the Python dictionary with the content of ESD/AOD (dst) which can be inserted in OKS.
317 dset =
set(destination.split())
318 from collections
import OrderedDict
319 toadd = OrderedDict()
322 for item
in itertools.chain(*trigEDMList):
332 if colltype
in toadd:
333 if k
not in toadd[colltype]:
334 toadd[colltype] += [k]
336 toadd[colltype] = [k]
344 Modified EDM list to remove all dynamic variables
345 Requires changing the list to have 'Aux.-'
348 from collections
import OrderedDict
349 output = OrderedDict()
350 for k,v
in _edmList.items():
365 Modified EDM list to remove all dynamic variables
366 Requires changing the list to have 'Aux.-'
369 for k,v
in edmList.items():
373 newnames+=[el.split(
'.')[0]+
'.-']
380 """ From name of object in AOD/ESD found by checkFileTrigSize.py, return category """
382 """ Clean up object name """
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')]
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:]
407 elif s12.startswith(
'HLT_'):
409 if s12.count(
'_'): s12 = s12[s12.index(
'_')+1:]
410 if s12.count(
'_'): s12 = s12[s12.index(
'_')+1:]
413 TriggerListRun1 = TriggerL2List + TriggerEFList + TriggerResultsRun1List
414 TriggerListRun2 = TriggerResultsList + TriggerLvl1List + TriggerIDTruth + TriggerHLTList
420 """ Loop over all objects already defined in lists (and hopefully categorized!!) """
421 for item
in TriggerListRun1+TriggerListRun2:
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)):
432 if k.count(
'.'): k = k[:k.index(
'.')]
437 for item
in TriggerListRun3:
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(
'>')]
445 if (s.startswith(t)
and s.endswith(k))
and (len(t) > len(bestMatch)):
449 if k.count(
'.'): k = k[:k.index(
'.')]
454 if category ==
'' and 'HLTNav' in s:
457 if category ==
'':
return 'NOTFOUND'
463 """ From the strings containing type and key of trigger EDM extract type and key
465 return s[:s.index(
'#')], s[s.index(
'#')+1:]
468 """ The key is usually HLT_*, this function returns second part of it or empty string
473 return key[key.index(
'_'):].lstrip(
'_')
477 Gives back the Python dictionary with the content of ESD/AOD (dst) which can be inserted in OKS.
479 dset =
set(destination.split())
484 for item
in itertools.chain(*lst):
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]
497 toadd[colltype] = [k]
503 Gives back the Python dictionary with the truth trigger content of ESD/AOD (dst) which can be inserted in OKS.
509 Gives back the Python dictionary with the lvl1 trigger result content of ESD which can be inserted in OKS.
515 Gives back the Python dictionary with the lvl1 trigger result content of AOD which can be inserted in OKS.
523 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for L2
526 for item
in TriggerL2List:
527 if len (item[1]) == 0:
continue
536 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for EF
539 for item
in TriggerEFList:
540 if len (item[1]) == 0:
continue
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
552 for item
in TriggerHLTList:
553 if len (item[1]) == 0:
continue
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)'
575 l=
list(dict.fromkeys(objs))
577 raise RuntimeError(
"Invalid version=%s supplied to getPreregistrationList" % version)
582 """ List of L2 types to be read from BS, used by the TP
585 for item
in TriggerL2List:
588 if 'collection' in EDMDetails[t]:
589 ctype = EDMDetails[t][
'collection']
594 """ List of EF types to be read from BS, used by the TP
597 for item
in TriggerEFList:
600 if 'collection' in EDMDetails[t]:
601 ctype = EDMDetails[t][
'collection']
606 """ List of HLT types to be read from BS, used by the TP
609 for item
in TriggerHLTList:
612 if 'collection' in EDMDetails[t]:
613 ctype = EDMDetails[t][
'collection']
619 Mapping of Transient objects to Peristent during serialization (BS creation)
620 version can be: '1 (Run1)', '2 (Run2)'
628 raise RuntimeError(
"Invalid version=%s supplied to getTPList" % version)
630 for t,d
in EDMDetails.items():
632 if 'collection' in d:
633 colltype = EDMDetails[t][
'collection']
634 if colltype
in bslist:
635 l[colltype] = d[
'persistent']
645 for k,v
in typedict.items():
648 if el.startswith(
'HLT_')
or el ==
'HLT':
649 prefixAndLabel = el.split(
'_',1)
650 containername = k
if 'Aux' not in k
else EDMDetails[k][
'parent']
652 containername = re.sub(
'::',
'__',re.sub(
'_v[0-9]+$',
'',containername))
653 newnames+=[
'_'.
join([prefixAndLabel[0],containername]+([prefixAndLabel[1]]
if len(prefixAndLabel) > 1
else []))]
661 List of EF trigger objects that were written to ByteStream in Run 1
664 for item
in TriggerEFEvolutionList:
665 if len (item[1]) == 0:
continue
672 List of Run-2 containers equivalent to Run-1 EF containers
675 for item
in TriggerEFEvolutionList:
676 if len (item[1]) == 0:
continue
683 List of L2 trigger objects that were written to ByteStream in Run 1
686 for item
in TriggerL2EvolutionList:
687 if len (item[1]) == 0:
continue
694 List of Run-2 containers equivalent to Run-1 L2 containers
697 for item
in TriggerL2EvolutionList:
698 if len (item[1]) == 0:
continue
705 Checks container type name is hashable
707 c = cgen.genClidFromName(typename)
708 return (cgen.getNameFromClid(c)
is not None)
712 Checks EDM list entries for serialization and configuration compliance.
716 _noAuxList = [
"xAOD::" + contType
for contType
in [
"TrigConfKeys",
"BunchConfKey"]]
718 cgen = clidGenerator(
"",
False)
720 found_allow_truncation =
False
721 serializable_names = []
722 serializable_names_no_label = []
723 serializable_names_no_properties = []
725 for i, edm
in enumerate(edm_list):
729 log.error(
"EDM entry too short for " + edm[0])
733 serializable_name = edm[0]
734 serializable_name_no_label = re.sub(
r"\#.*",
"", serializable_name)
735 serializable_name_no_properties = serializable_name.split(
'.')[0]
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)
743 log.error(
"no CLID for " + serializable_name)
747 if "Aux" not in serializable_name
and "." in serializable_name:
748 log.error(
"A '.' found in non-Aux container name " + serializable_name)
752 if "Aux" in serializable_name
and "Aux." not in serializable_name:
753 log.error(
"no final Aux. in label for " + serializable_name)
757 if serializable_name.count(
"#") != 1:
758 log.error(
"Invalid naming structure for " + serializable_name)
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:
766 if len(edm_list) == i+1:
768 cont_to_test =
"nothing"
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):
775 shallow_pattern = re.compile(
"xAOD::ShallowAuxContainer#"+cont_name+
"Aux.")
776 if not shallow_pattern.match(cont_to_test):
779 log.error(
"Expected relevant Aux container following interface container %s, but found %s instead.",serializable_name,cont_to_test)
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)
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")
799 file_types = edm[1].
split()
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)
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)
810 tags = edm[3]
if len(edm) > 3
else None
811 allow_truncation_flag =
False
813 allow_truncation_flag = allowTruncation
in tags
814 if allow_truncation_flag:
815 found_allow_truncation =
True
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")
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():
830 log.error(
str(count) +
"x: " +
str(item))
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: