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
20from AthenaCommon.Logging
import logging
21log = logging.getLogger(
'TriggerEDM')
32AllowedOutputFormats = [
'BS',
'ESD',
'AODFULL',
'AODSLIM',
'AODBLSSLIM' ]
33from TrigEDMConfig
import DataScoutingInfo
34AllowedOutputFormats.extend(DataScoutingInfo.getAllDataScoutingIdentifiers())
36_allowedEDMPrefixes = [
'HLT_',
'L1_',
'LVL1']
39 Verify that the name is in the list of recorded objects and conform to the name convention
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.
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
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.
54 name = str(arg).
replace(
'StoreGateSvc+',
'')
57 log.error(
"Don't call recordable({0}), or add any \"HLTNav_\" collection manually to the EDM. See:collectDecisionObjects.".format( name ) )
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 '.'" )
66 for entry
in TriggerHLTListRun3:
67 if entry[0].
split(
"#" )[1] == name:
69 msg =
"The collection name {0} is not declared to be stored by HLT. Add it to TriggerEDMRun3.py".format( name )
70 log.error(
"ERROR in recordable() - see following stack trace.")
71 raise RuntimeError( msg )
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.
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:
86 edmList.insert(insert_idx+1,item)
88 edmList.insert(insert_idx,item)
89 log.info(
"added new item to Trigger EDM: {}".format(item))
92 isAux =
"Aux." in item[0]
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]]
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))
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]
114 tags = existingItem[3]
if len(existingItem) > 3
else None
115 edmList.pop(existing_item_nr[0])
116 combName = typename +
"#" + colname
118 combName +=
"." + newVars
120 edmList.insert(existing_item_nr[0], (combName, newTargets, signature, tags))
122 edmList.insert(existing_item_nr[0] , (combName, newTargets, signature))
123 log.info(
"updated item in Trigger EDM: {}".format(edmList[existing_item_nr[0]]))
125 if testEDMList(edmList, error_on_edmdetails=
False):
126 log.error(
"edmList contains inconsistencies!")
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
134 runVersion = flags.Trigger.EDMVersion
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))
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):
147 for r4item
in edm4ListCopy:
148 if edm3ListCopy[i][0] == r4item[0]:
150 log.debug(f
"- Dupe: {r4item} is removed from TriggerHLTListRun3 to be updated by TriggerHLTListRun4")
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 if testEDMList(edmListCopy, error_on_edmdetails=
False):
158 log.error(
"edmList contains inconsistencies!")
160 errMsg=
"ERROR the getRawTriggerEDMList function supports runs 3 and 4."
162 raise RuntimeError(errMsg)
164 if flags
and flags.Trigger.ExtraEDMList:
165 log.info(
"Adding extra collections to EDM %i: %s", runVersion, str(flags.Trigger.ExtraEDMList))
172 List (Literally Python dict) of trigger objects to be placed with flags:
173 flags is the CA flag container
174 key can be" 'ESD', 'AODSLIM', 'AODFULL'
175 runVersion can be: '-1 (Auto-configure)', '1 (Run1)', '2 (Run2)', '3' (Run 3), '4' (Run 4)
179 runVersion = flags.Trigger.EDMVersion
184 elif runVersion == 2:
188 elif runVersion >= 3:
191 if key
not in AllowedOutputFormats:
192 log.warning(
'Output format: %s is not in list of allowed formats, please check!', key)
202 elif "AODSLIM" in key:
206 if len(varToRemoveFromAODSLIM) == 0:
208 log.info(
"No decorations are listed to be removed from AODSLIM")
211 log.info(
"The following decorations are going to be removed from the listed collections in AODSLIM {}".format(varToRemoveFromAODSLIM))
214 for cont, values
in Run3TrigEDMSLIM.items():
215 if (isinstance(values, list)):
219 coll = value.split(
'.')[0]
221 varRemovedFlag =
False
222 for myTuple
in varToRemoveFromAODSLIM:
225 if var
in value
and coll
in myTuple:
226 varRemovedFlag =
True
227 removeVar =
'.'+var+
'.'
228 newValue = newValue.replace(removeVar,
'.')
230 if newValue[-1:] ==
'.':
231 newValue = newValue[:-1]
233 if varRemovedFlag
is False:
234 newValues.append(value)
235 elif varRemovedFlag
is True:
236 newValues.append(newValue)
238 raise RuntimeError(
"Decoration removed but no new Value was available, not sure what to do...")
241 Run3TrigEDM[cont] = newValues
243 raise RuntimeError(
"Value in Run3TrigEDM dictionary is not a list")
248 log.debug(
'TriggerEDM for EDM set {} contains the following collections: {}'.format(key, Run3TrigEDM) )
253 raise RuntimeError(
"Invalid runVersion=%s supplied to getTriggerEDMList" % runVersion)
260 Finds a given key from within the trigEDMList.
261 Returns true if this collection is produced inside EventViews
262 (Hence, has the special viewIndex Aux decoration applied by steering)
264 from TrigEDMConfig.TriggerEDMRun3
import InViews
266 return any(coll
for coll
in itertools.chain(*trigEDMList)
if
267 len(coll)>3
and theKey==coll[0].
split(
'#')[1]
and
268 any(isinstance(v, InViews)
for v
in coll[3]))
274 keyNoAux = el.split(
'.')[0].
replace(
'Aux',
'')
277 if el.split(
'.')[1] ==
'':
281 return el.split(
'.')[0]+
'.viewIndex'
284 return el.split(
'.')[0]+
'.-'
289 return el+
'.viewIndex'
299 The keys should contain BS and all the identifiers used for scouting.
300 Returns list of tuples (typename#key, [keys], [properties]).
303 from TrigEDMConfig.TriggerEDMRun3
import persistent
307 for definition
in _HLTList:
309 typename,collkey = definition[0].
split(
"#")
311 typename = persistent(typename)
313 destination = keys &
set(definition[1].
split())
314 if len(destination) > 0:
315 collections.append( (typename+
"#"+collkey, list(destination),
316 definition[3]
if len(definition)>3
else []) )
324 Gives back the Python dictionary with the content of ESD/AOD (dst) which can be inserted in OKS.
326 dset =
set(destination.split())
327 toadd = defaultdict(list)
329 for item
in itertools.chain(*trigEDMList):
338 if k
not in toadd[colltype]:
339 toadd[colltype] += [k]
347 Modified EDM list to remove all dynamic variables
348 Requires changing the list to have 'Aux.-'
353 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())
483 for item
in itertools.chain(*lst):
490 if 'collection' in EDMDetails[t]:
491 colltype = EDMDetails[t][
'collection']
492 if colltype
in toadd:
493 if k
not in toadd[colltype]:
494 toadd[colltype] += [k]
496 toadd[colltype] = [k]
502 Gives back the Python dictionary with the truth trigger content of ESD/AOD (dst) which can be inserted in OKS.
508 Gives back the Python dictionary with the lvl1 trigger result content of ESD which can be inserted in OKS.
514 Gives back the Python dictionary with the lvl1 trigger result content of AOD which can be inserted in OKS.
522 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for L2
525 for item
in TriggerL2List:
526 if len (item[1]) == 0:
continue
535 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for EF
538 for item
in TriggerEFList:
539 if len (item[1]) == 0:
continue
548 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
551 for item
in TriggerHLTList:
552 if len (item[1]) == 0:
continue
562 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want for all levels
563 version can be: '1 (Run1)', '2 (Run2)'
574 l=list(dict.fromkeys(objs))
576 raise RuntimeError(
"Invalid version=%s supplied to getPreregistrationList" % version)
581 """ List of L2 types to be read from BS, used by the TP
584 for item
in TriggerL2List:
587 if 'collection' in EDMDetails[t]:
588 ctype = EDMDetails[t][
'collection']
593 """ List of EF types to be read from BS, used by the TP
596 for item
in TriggerEFList:
599 if 'collection' in EDMDetails[t]:
600 ctype = EDMDetails[t][
'collection']
605 """ List of HLT types to be read from BS, used by the TP
608 for item
in TriggerHLTList:
611 if 'collection' in EDMDetails[t]:
612 ctype = EDMDetails[t][
'collection']
618 Mapping of Transient objects to Peristent during serialization (BS creation)
619 version can be: '1 (Run1)', '2 (Run2)'
627 raise RuntimeError(
"Invalid version=%s supplied to getTPList" % version)
629 for t,d
in EDMDetails.items():
631 if 'collection' in d:
632 colltype = EDMDetails[t][
'collection']
633 if colltype
in bslist:
634 l[colltype] = d[
'persistent']
644 for k,v
in typedict.items():
647 if el.startswith(
'HLT_')
or el ==
'HLT':
648 prefixAndLabel = el.split(
'_',1)
649 containername = k
if 'Aux' not in k
else EDMDetails[k][
'parent']
651 containername = re.sub(
'::',
'__',re.sub(
'_v[0-9]+$',
'',containername))
652 newnames+=[
'_'.join([prefixAndLabel[0],containername]+([prefixAndLabel[1]]
if len(prefixAndLabel) > 1
else []))]
660 List of EF trigger objects that were written to ByteStream in Run 1
663 for item
in TriggerEFEvolutionList:
664 if len (item[1]) == 0:
continue
671 List of Run-2 containers equivalent to Run-1 EF containers
674 for item
in TriggerEFEvolutionList:
675 if len (item[1]) == 0:
continue
682 List of L2 trigger objects that were written to ByteStream in Run 1
685 for item
in TriggerL2EvolutionList:
686 if len (item[1]) == 0:
continue
693 List of Run-2 containers equivalent to Run-1 L2 containers
696 for item
in TriggerL2EvolutionList:
697 if len (item[1]) == 0:
continue
704 Checks container type name is hashable
706 c = cgen.genClidFromName(typename)
707 return (cgen.getNameFromClid(c)
is not None)
711 Checks EDM list entries for serialization and configuration compliance.
715 _noAuxList = [
"xAOD::" + contType
for contType
in [
"TrigConfKeys",
"BunchConfKey"]]
717 cgen = clidGenerator(
"",
False)
719 found_allow_truncation =
False
720 serializable_names = []
721 serializable_names_no_label = []
722 serializable_names_no_properties = []
724 for i, edm
in enumerate(edm_list):
728 log.error(
"EDM entry too short for " + edm[0])
732 serializable_name = edm[0]
733 serializable_name_no_label = re.sub(
r"\#.*",
"", serializable_name)
734 serializable_name_no_properties = serializable_name.split(
'.')[0]
736 serializable_names.append(serializable_name)
737 serializable_names_no_label.append(serializable_name_no_label)
738 serializable_names_no_properties.append(serializable_name_no_properties)
742 log.error(
"no CLID for " + serializable_name)
746 if "Aux" not in serializable_name
and "." in serializable_name:
747 log.error(
"A '.' found in non-Aux container name " + serializable_name)
751 if "Aux" in serializable_name
and "Aux." not in serializable_name:
752 log.error(
"no final Aux. in label for " + serializable_name)
756 if serializable_name.count(
"#") != 1:
757 log.error(
"Invalid naming structure for " + serializable_name)
761 if serializable_name.startswith(
"xAOD")
and "Aux" not in serializable_name:
762 cont_type,cont_name = serializable_name.split(
"#")
763 if cont_type
not in _noAuxList:
765 if len(edm_list) == i+1:
767 cont_to_test =
"nothing"
769 cont_to_test = edm_list[i+1][0].
split(
".")[0]+
"."
770 cont_type_short = cont_type.replace(
"Container",
"")
771 pattern = re.compile(cont_type_short+
r".*Aux.*\#"+cont_name+
"Aux.")
772 if not pattern.match(cont_to_test):
774 shallow_pattern = re.compile(
"xAOD::ShallowAuxContainer#"+cont_name+
"Aux.")
775 if not shallow_pattern.match(cont_to_test):
778 log.error(
"Expected relevant Aux container following interface container %s, but found %s instead.",serializable_name,cont_to_test)
783 if len(edm_list[i+1]) > 1
and cont_to_test.count(
"#") == 1:
784 contname_to_test = cont_to_test.split(
"#")[1]
785 targets_to_test =
set(edm_list[i+1][1].
split())
786 if len(targets ^ targets_to_test) > 0:
787 log.error(
"Targets of %s (%s) and %s (%s) do not match",cont_name,targets,contname_to_test,targets_to_test)
791 if i>0
and "Aux" in serializable_name
and "Aux" in edm_list[i-1][0]:
792 log.error(f
"Aux container {serializable_name} needs to folow the "
793 "associated interface container in the EDM list")
798 file_types = edm[1].
split()
799 for file_type
in file_types:
800 if file_type
not in AllowedOutputFormats:
801 log.error(
"unknown file type " + file_type +
" for " + serializable_name)
803 for higher_level,required_lower_level
in [(
'AOD',
'ESD'), (
'SLIM',
'AODFULL')]:
804 if higher_level
in file_type
and required_lower_level
not in file_types:
805 log.error(
"Target list for %s containing '%s' must also contain lower level target '%s'.",serializable_name,file_type,required_lower_level)
809 tags = edm[3]
if len(edm) > 3
else None
810 allow_truncation_flag =
False
812 allow_truncation_flag = allowTruncation
in tags
813 if allow_truncation_flag:
814 found_allow_truncation =
True
816 if found_allow_truncation
and not allow_truncation_flag:
817 log.error(
"All instances of 'allowTruncation' need to be at the END of the EDM serialisation list")
824 if not len(
set(serializable_names_no_properties)) == len(serializable_names_no_properties):
825 log.error(
"Duplicates in EDM list! Duplicates found:")
827 for item, count
in collections.Counter(serializable_names_no_properties).items():
829 log.error(str(count) +
"x: " + str(item))
833 for EDMDetail
in EDMDetailsRun3.keys():
834 if EDMDetail
not in serializable_names_no_label:
835 msg =
"EDMDetail for " + EDMDetail +
" does not correspond to any name in TriggerList"
836 if error_on_edmdetails:
std::string replace(std::string s, const std::string &s2, const std::string &s3)
std::vector< std::string > split(const std::string &s, const std::string &t=":")
getPreregistrationList(version=2, doxAODConversion=True)
getL2Run2EquivalentList()
isCLIDDefined(cgen, typename)
_getRun3TrigEDMSlimList(key, HLTList)
getRun3BSList(flags, keys)
recordable(arg, runVersion=3)
_getHLTPreregistrationList()
_getTriggerRun1Run2ObjList(destination, lst)
_getRun3TrigObjList(destination, trigEDMList)
_getL2PreregistrationList()
_getEFPreregistrationList()
getTriggerEDMList(flags, key, runVersion=-1)
_InsertContainerNameForHLT(typedict)
testEDMList(edm_list, error_on_edmdetails=True)
_addExtraCollectionsToEDMList(edmList, extraList)
_getTriggerRun2EDMSlimList(key, edmList)
_getRun3TrigObjProducedInView(theKey, trigEDMList)
getRawTriggerEDMList(flags, runVersion=-1)
_handleRun3ViewContainers(el, HLTList)
getEFRun2EquivalentList()