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.
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 + TriggerHLTListRun4:
67 if entry[0].
split(
"#" )[1] == name:
69 msg =
"The collection name {0} is not declared to be stored by HLT. Add it to TriggerEDMRun4.py".format( name )
70 log.error(
"ERROR in recordable() - see following stack trace.")
71 raise RuntimeError( msg )
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}")
158 errMsg=
"ERROR the getRawTriggerEDMList function supports runs 3 and 4."
160 raise RuntimeError(errMsg)
162 if flags
and flags.Trigger.ExtraEDMList:
163 log.info(
"Adding extra collections to EDM %i: %s", runVersion,
str(flags.Trigger.ExtraEDMList))
170 List (Literally Python dict) of trigger objects to be placed with flags:
171 flags is the CA flag container
172 key can be" 'ESD', 'AODSLIM', 'AODFULL'
173 runVersion can be: '-1 (Auto-configure)', '1 (Run1)', '2 (Run2)', '3' (Run 3), '4' (Run 4)
177 runVersion = flags.Trigger.EDMVersion
182 elif runVersion == 2:
186 elif runVersion >= 3:
189 if key
not in AllowedOutputFormats:
190 log.warning(
'Output format: %s is not in list of allowed formats, please check!', key)
200 elif "AODSLIM" in key:
204 if len(varToRemoveFromAODSLIM) == 0:
206 log.info(
"No decorations are listed to be removed from AODSLIM")
209 log.info(
"The following decorations are going to be removed from the listed collections in AODSLIM {}".format(varToRemoveFromAODSLIM))
212 for cont, values
in Run3TrigEDMSLIM.items():
213 if (isinstance(values, list)):
217 coll = value.split(
'.')[0]
219 varRemovedFlag =
False
220 for myTuple
in varToRemoveFromAODSLIM:
223 if var
in value
and coll
in myTuple:
224 varRemovedFlag =
True
225 removeVar =
'.'+var+
'.'
226 newValue = newValue.replace(removeVar,
'.')
228 if newValue[-1:] ==
'.':
229 newValue = newValue[:-1]
231 if varRemovedFlag
is False:
232 newValues.append(value)
233 elif varRemovedFlag
is True:
234 newValues.append(newValue)
236 raise RuntimeError(
"Decoration removed but no new Value was available, not sure what to do...")
239 Run3TrigEDM[cont] = newValues
241 raise RuntimeError(
"Value in Run3TrigEDM dictionary is not a list")
246 log.debug(
'TriggerEDM for EDM set {} contains the following collections: {}'.format(key, Run3TrigEDM) )
251 raise RuntimeError(
"Invalid runVersion=%s supplied to getTriggerEDMList" % runVersion)
258 Finds a given key from within the trigEDMList.
259 Returns true if this collection is produced inside EventViews
260 (Hence, has the special viewIndex Aux decoration applied by steering)
262 from TrigEDMConfig.TriggerEDMRun3
import InViews
264 return any(coll
for coll
in itertools.chain(*trigEDMList)
if
265 len(coll)>3
and theKey==coll[0].
split(
'#')[1]
and
266 any(isinstance(v, InViews)
for v
in coll[3]))
272 keyNoAux = el.split(
'.')[0].
replace(
'Aux',
'')
275 if el.split(
'.')[1] ==
'':
279 return el.split(
'.')[0]+
'.viewIndex'
282 return el.split(
'.')[0]+
'.-'
287 return el+
'.viewIndex'
297 The keys should contain BS and all the identifiers used for scouting.
298 Returns list of tuples (typename#key, [keys], [properties]).
301 from TrigEDMConfig.TriggerEDMRun3
import persistent
305 for definition
in _HLTList:
307 typename,collkey = definition[0].
split(
"#")
309 typename = persistent(typename)
311 destination = keys &
set(definition[1].
split())
312 if len(destination) > 0:
313 collections.append( (typename+
"#"+collkey, list(destination),
314 definition[3]
if len(definition)>3
else []) )
322 Gives back the Python dictionary with the content of ESD/AOD (dst) which can be inserted in OKS.
324 dset =
set(destination.split())
325 toadd = defaultdict(list)
327 for item
in itertools.chain(*trigEDMList):
336 if k
not in toadd[colltype]:
337 toadd[colltype] += [k]
345 Modified EDM list to remove all dynamic variables
346 Requires changing the list to have 'Aux.-'
351 for k,v
in _edmList.items():
363 Modified EDM list to remove all dynamic variables
364 Requires changing the list to have 'Aux.-'
367 for k,v
in edmList.items():
371 newnames+=[el.split(
'.')[0]+
'.-']
378 """ From name of object in AOD/ESD found by checkFileTrigSize.py, return category """
380 """ Clean up object name """
389 if s.count(
'.') : s = s[:s.index(
'.')]
390 if s.count(
'::'): s = s[s.index(
':')+2:]
391 if s.count(
'<'): s = s[s.index(
'<')+1:]
392 if s.count(
'>'): s = s[:s.index(
'>')]
393 if s.count(
'.') : s = s[:s.index(
'.')]
394 if s.count(
'Dyn') : s = s[:s.index(
'Dyn')]
400 if s12.startswith(
'HLT_xAOD__')
or s12.startswith(
'HLT_Rec__')
or s12.startswith(
'HLT_Analysis__') :
401 s12 = s12[s12.index(
'__')+2:]
402 s12 = s12[s12.index(
'_')+1:]
405 elif s12.startswith(
'HLT_'):
407 if s12.count(
'_'): s12 = s12[s12.index(
'_')+1:]
408 if s12.count(
'_'): s12 = s12[s12.index(
'_')+1:]
411 TriggerListRun1 = TriggerL2List + TriggerEFList + TriggerResultsRun1List
412 TriggerListRun2 = TriggerResultsList + TriggerLvl1List + TriggerIDTruth + TriggerHLTList
418 """ Loop over all objects already defined in lists (and hopefully categorized!!) """
419 for item
in TriggerListRun1+TriggerListRun2:
422 """ Clean up type name """
423 if t.count(
'::'): t = t[t.index(
':')+2:]
424 if t.count(
'<'): t = t[t.index(
'<')+1:]
425 if t.count(
'>'): t = t[:t.index(
'>')]
426 if (s12.startswith(t)
and s12.endswith(k))
and (len(t) > len(bestMatch)):
430 if k.count(
'.'): k = k[:k.index(
'.')]
435 for item
in TriggerListRun3:
438 """ Clean up type name """
439 if t.count(
'::'): t = t[t.index(
':')+2:]
440 if t.count(
'<'): t = t[t.index(
'<')+1:]
441 if t.count(
'>'): t = t[:t.index(
'>')]
443 if (s.startswith(t)
and s.endswith(k))
and (len(t) > len(bestMatch)):
447 if k.count(
'.'): k = k[:k.index(
'.')]
452 if category ==
'' and 'HLTNav' in s:
455 if category ==
'':
return 'NOTFOUND'
461 """ From the strings containing type and key of trigger EDM extract type and key
463 return s[:s.index(
'#')], s[s.index(
'#')+1:]
466 """ The key is usually HLT_*, this function returns second part of it or empty string
471 return key[key.index(
'_'):].lstrip(
'_')
475 Gives back the Python dictionary with the content of ESD/AOD (dst) which can be inserted in OKS.
477 dset =
set(destination.split())
481 for item
in itertools.chain(*lst):
488 if 'collection' in EDMDetails[t]:
489 colltype = EDMDetails[t][
'collection']
490 if colltype
in toadd:
491 if k
not in toadd[colltype]:
492 toadd[colltype] += [k]
494 toadd[colltype] = [k]
500 Gives back the Python dictionary with the truth trigger content of ESD/AOD (dst) which can be inserted in OKS.
506 Gives back the Python dictionary with the lvl1 trigger result content of ESD which can be inserted in OKS.
512 Gives back the Python dictionary with the lvl1 trigger result content of AOD which can be inserted in OKS.
520 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for L2
523 for item
in TriggerL2List:
524 if len (item[1]) == 0:
continue
533 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for EF
536 for item
in TriggerEFList:
537 if len (item[1]) == 0:
continue
546 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for merged L2/EF in addition to default L2 and EF
549 for item
in TriggerHLTList:
550 if len (item[1]) == 0:
continue
560 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want for all levels
561 version can be: '1 (Run1)', '2 (Run2)'
572 l=list(dict.fromkeys(objs))
574 raise RuntimeError(
"Invalid version=%s supplied to getPreregistrationList" % version)
579 """ List of L2 types to be read from BS, used by the TP
582 for item
in TriggerL2List:
585 if 'collection' in EDMDetails[t]:
586 ctype = EDMDetails[t][
'collection']
591 """ List of EF types to be read from BS, used by the TP
594 for item
in TriggerEFList:
597 if 'collection' in EDMDetails[t]:
598 ctype = EDMDetails[t][
'collection']
603 """ List of HLT types to be read from BS, used by the TP
606 for item
in TriggerHLTList:
609 if 'collection' in EDMDetails[t]:
610 ctype = EDMDetails[t][
'collection']
616 Mapping of Transient objects to Peristent during serialization (BS creation)
617 version can be: '1 (Run1)', '2 (Run2)'
625 raise RuntimeError(
"Invalid version=%s supplied to getTPList" % version)
627 for t,d
in EDMDetails.items():
629 if 'collection' in d:
630 colltype = EDMDetails[t][
'collection']
631 if colltype
in bslist:
632 l[colltype] = d[
'persistent']
642 for k,v
in typedict.items():
645 if el.startswith(
'HLT_')
or el ==
'HLT':
646 prefixAndLabel = el.split(
'_',1)
647 containername = k
if 'Aux' not in k
else EDMDetails[k][
'parent']
649 containername = re.sub(
'::',
'__',re.sub(
'_v[0-9]+$',
'',containername))
650 newnames+=[
'_'.join([prefixAndLabel[0],containername]+([prefixAndLabel[1]]
if len(prefixAndLabel) > 1
else []))]
658 List of EF trigger objects that were written to ByteStream in Run 1
661 for item
in TriggerEFEvolutionList:
662 if len (item[1]) == 0:
continue
669 List of Run-2 containers equivalent to Run-1 EF containers
672 for item
in TriggerEFEvolutionList:
673 if len (item[1]) == 0:
continue
680 List of L2 trigger objects that were written to ByteStream in Run 1
683 for item
in TriggerL2EvolutionList:
684 if len (item[1]) == 0:
continue
691 List of Run-2 containers equivalent to Run-1 L2 containers
694 for item
in TriggerL2EvolutionList:
695 if len (item[1]) == 0:
continue
702 Checks container type name is hashable
704 c = cgen.genClidFromName(typename)
705 return (cgen.getNameFromClid(c)
is not None)
709 Checks EDM list entries for serialization and configuration compliance.
713 _noAuxList = [
"xAOD::" + contType
for contType
in [
"TrigConfKeys",
"BunchConfKey"]]
715 cgen = clidGenerator(
"",
False)
717 found_allow_truncation =
False
718 serializable_names = []
719 serializable_names_no_label = []
720 serializable_names_no_properties = []
722 for i, edm
in enumerate(edm_list):
726 log.error(
"EDM entry too short for " + edm[0])
730 serializable_name = edm[0]
731 serializable_name_no_label = re.sub(
r"\#.*",
"", serializable_name)
732 serializable_name_no_properties = serializable_name.split(
'.')[0]
734 serializable_names.append(serializable_name)
735 serializable_names_no_label.append(serializable_name_no_label)
736 serializable_names_no_properties.append(serializable_name_no_properties)
740 log.error(
"no CLID for " + serializable_name)
744 if "Aux" not in serializable_name
and "." in serializable_name:
745 log.error(
"A '.' found in non-Aux container name " + serializable_name)
749 if "Aux" in serializable_name
and "Aux." not in serializable_name:
750 log.error(
"no final Aux. in label for " + serializable_name)
754 if serializable_name.count(
"#") != 1:
755 log.error(
"Invalid naming structure for " + serializable_name)
759 if serializable_name.startswith(
"xAOD")
and "Aux" not in serializable_name:
760 cont_type,cont_name = serializable_name.split(
"#")
761 if cont_type
not in _noAuxList:
763 if len(edm_list) == i+1:
765 cont_to_test =
"nothing"
767 cont_to_test = edm_list[i+1][0].
split(
".")[0]+
"."
768 cont_type_short = cont_type.replace(
"Container",
"")
769 pattern = re.compile(cont_type_short+
r".*Aux.*\#"+cont_name+
"Aux.")
770 if not pattern.match(cont_to_test):
772 shallow_pattern = re.compile(
"xAOD::ShallowAuxContainer#"+cont_name+
"Aux.")
773 if not shallow_pattern.match(cont_to_test):
776 log.error(
"Expected relevant Aux container following interface container %s, but found %s instead.",serializable_name,cont_to_test)
781 if len(edm_list[i+1]) > 1
and cont_to_test.count(
"#") == 1:
782 contname_to_test = cont_to_test.split(
"#")[1]
783 targets_to_test =
set(edm_list[i+1][1].
split())
784 if len(targets ^ targets_to_test) > 0:
785 log.error(
"Targets of %s (%s) and %s (%s) do not match",cont_name,targets,contname_to_test,targets_to_test)
789 if i>0
and "Aux" in serializable_name
and "Aux" in edm_list[i-1][0]:
790 log.error(f
"Aux container {serializable_name} needs to folow the "
791 "associated interface container in the EDM list")
796 file_types = edm[1].
split()
797 for file_type
in file_types:
798 if file_type
not in AllowedOutputFormats:
799 log.error(
"unknown file type " + file_type +
" for " + serializable_name)
801 for higher_level,required_lower_level
in [(
'AOD',
'ESD'), (
'SLIM',
'AODFULL')]:
802 if higher_level
in file_type
and required_lower_level
not in file_types:
803 log.error(
"Target list for %s containing '%s' must also contain lower level target '%s'.",serializable_name,file_type,required_lower_level)
807 tags = edm[3]
if len(edm) > 3
else None
808 allow_truncation_flag =
False
810 allow_truncation_flag = allowTruncation
in tags
811 if allow_truncation_flag:
812 found_allow_truncation =
True
814 if found_allow_truncation
and not allow_truncation_flag:
815 log.error(
"All instances of 'allowTruncation' need to be at the END of the EDM serialisation list")
822 if not len(
set(serializable_names_no_properties)) == len(serializable_names_no_properties):
823 log.error(
"Duplicates in EDM list! Duplicates found:")
825 for item, count
in collections.Counter(serializable_names_no_properties).items():
827 log.error(
str(count) +
"x: " +
str(item))
831 for EDMDetail
in EDMDetailsRun3.keys():
832 if EDMDetail
not in serializable_names_no_label:
833 msg =
"EDMDetail for " + EDMDetail +
" does not correspond to any name in TriggerList"
834 if error_on_edmdetails:
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)
_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()