10from TrigEDMConfig.TriggerEDMRun1
import TriggerL2List,TriggerEFList,TriggerResultsRun1List
11from TrigEDMConfig.TriggerEDMRun2
import TriggerResultsList,TriggerLvl1List,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 + 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 + 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 lvl1 trigger result content of ESD which can be inserted in OKS.
506 Gives back the Python dictionary with the lvl1 trigger result content of AOD which can be inserted in OKS.
514 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for L2
517 for item
in TriggerL2List:
518 if len (item[1]) == 0:
continue
527 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want in every event for EF
530 for item
in TriggerEFList:
531 if len (item[1]) == 0:
continue
540 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
543 for item
in TriggerHLTList:
544 if len (item[1]) == 0:
continue
554 List (Literally Python list) of trigger objects to be preregistered i.e. this objects we want for all levels
555 version can be: '1 (Run1)', '2 (Run2)'
566 l=list(dict.fromkeys(objs))
568 raise RuntimeError(
"Invalid version=%s supplied to getPreregistrationList" % version)
573 """ List of L2 types to be read from BS, used by the TP
576 for item
in TriggerL2List:
579 if 'collection' in EDMDetails[t]:
580 ctype = EDMDetails[t][
'collection']
585 """ List of EF types to be read from BS, used by the TP
588 for item
in TriggerEFList:
591 if 'collection' in EDMDetails[t]:
592 ctype = EDMDetails[t][
'collection']
597 """ List of HLT types to be read from BS, used by the TP
600 for item
in TriggerHLTList:
603 if 'collection' in EDMDetails[t]:
604 ctype = EDMDetails[t][
'collection']
610 Mapping of Transient objects to Peristent during serialization (BS creation)
611 version can be: '1 (Run1)', '2 (Run2)'
619 raise RuntimeError(
"Invalid version=%s supplied to getTPList" % version)
621 for t,d
in EDMDetails.items():
623 if 'collection' in d:
624 colltype = EDMDetails[t][
'collection']
625 if colltype
in bslist:
626 l[colltype] = d[
'persistent']
636 for k,v
in typedict.items():
639 if el.startswith(
'HLT_')
or el ==
'HLT':
640 prefixAndLabel = el.split(
'_',1)
641 containername = k
if 'Aux' not in k
else EDMDetails[k][
'parent']
643 containername = re.sub(
'::',
'__',re.sub(
'_v[0-9]+$',
'',containername))
644 newnames+=[
'_'.join([prefixAndLabel[0],containername]+([prefixAndLabel[1]]
if len(prefixAndLabel) > 1
else []))]
652 List of EF trigger objects that were written to ByteStream in Run 1
655 for item
in TriggerEFEvolutionList:
656 if len (item[1]) == 0:
continue
663 List of Run-2 containers equivalent to Run-1 EF containers
666 for item
in TriggerEFEvolutionList:
667 if len (item[1]) == 0:
continue
674 List of L2 trigger objects that were written to ByteStream in Run 1
677 for item
in TriggerL2EvolutionList:
678 if len (item[1]) == 0:
continue
685 List of Run-2 containers equivalent to Run-1 L2 containers
688 for item
in TriggerL2EvolutionList:
689 if len (item[1]) == 0:
continue
696 Checks container type name is hashable
698 c = cgen.genClidFromName(typename)
699 return (cgen.getNameFromClid(c)
is not None)
703 Checks EDM list entries for serialization and configuration compliance.
707 _noAuxList = [
"xAOD::" + contType
for contType
in [
"TrigConfKeys",
"BunchConfKey"]]
709 cgen = clidGenerator(
"",
False)
711 found_allow_truncation =
False
712 serializable_names = []
713 serializable_names_no_label = []
714 serializable_names_no_properties = []
716 for i, edm
in enumerate(edm_list):
720 log.error(
"EDM entry too short for " + edm[0])
724 serializable_name = edm[0]
725 serializable_name_no_label = re.sub(
r"\#.*",
"", serializable_name)
726 serializable_name_no_properties = serializable_name.split(
'.')[0]
728 serializable_names.append(serializable_name)
729 serializable_names_no_label.append(serializable_name_no_label)
730 serializable_names_no_properties.append(serializable_name_no_properties)
734 log.error(
"no CLID for " + serializable_name)
738 if "Aux" not in serializable_name
and "." in serializable_name:
739 log.error(
"A '.' found in non-Aux container name " + serializable_name)
743 if "Aux" in serializable_name
and "Aux." not in serializable_name:
744 log.error(
"no final Aux. in label for " + serializable_name)
748 if serializable_name.count(
"#") != 1:
749 log.error(
"Invalid naming structure for " + serializable_name)
753 if serializable_name.startswith(
"xAOD")
and "Aux" not in serializable_name:
754 cont_type,cont_name = serializable_name.split(
"#")
755 if cont_type
not in _noAuxList:
757 if len(edm_list) == i+1:
759 cont_to_test =
"nothing"
761 cont_to_test = edm_list[i+1][0].
split(
".")[0]+
"."
762 cont_type_short = cont_type.replace(
"Container",
"")
763 pattern = re.compile(cont_type_short+
r".*Aux.*\#"+cont_name+
"Aux.")
764 if not pattern.match(cont_to_test):
766 shallow_pattern = re.compile(
"xAOD::ShallowAuxContainer#"+cont_name+
"Aux.")
767 if not shallow_pattern.match(cont_to_test):
770 log.error(
"Expected relevant Aux container following interface container %s, but found %s instead.",serializable_name,cont_to_test)
775 if len(edm_list[i+1]) > 1
and cont_to_test.count(
"#") == 1:
776 contname_to_test = cont_to_test.split(
"#")[1]
777 targets_to_test =
set(edm_list[i+1][1].
split())
778 if len(targets ^ targets_to_test) > 0:
779 log.error(
"Targets of %s (%s) and %s (%s) do not match",cont_name,targets,contname_to_test,targets_to_test)
783 if i>0
and "Aux" in serializable_name
and "Aux" in edm_list[i-1][0]:
784 log.error(f
"Aux container {serializable_name} needs to folow the "
785 "associated interface container in the EDM list")
790 file_types = edm[1].
split()
791 for file_type
in file_types:
792 if file_type
not in AllowedOutputFormats:
793 log.error(
"unknown file type " + file_type +
" for " + serializable_name)
795 for higher_level,required_lower_level
in [(
'AOD',
'ESD'), (
'SLIM',
'AODFULL')]:
796 if higher_level
in file_type
and required_lower_level
not in file_types:
797 log.error(
"Target list for %s containing '%s' must also contain lower level target '%s'.",serializable_name,file_type,required_lower_level)
801 tags = edm[3]
if len(edm) > 3
else None
802 allow_truncation_flag =
False
804 allow_truncation_flag = allowTruncation
in tags
805 if allow_truncation_flag:
806 found_allow_truncation =
True
808 if found_allow_truncation
and not allow_truncation_flag:
809 log.error(
"All instances of 'allowTruncation' need to be at the END of the EDM serialisation list")
816 if len(
set(serializable_names_no_properties)) != len(serializable_names_no_properties):
817 log.error(
"Duplicates in EDM list! Duplicates found:")
819 for item, count
in collections.Counter(serializable_names_no_properties).items():
821 log.error(str(count) +
"x: " + str(item))
825 for EDMDetail
in EDMDetailsRun3:
826 if EDMDetail
not in serializable_names_no_label:
827 msg =
"EDMDetail for " + EDMDetail +
" does not correspond to any name in TriggerList"
828 if error_on_edmdetails:
838 edmDict = dict([(fmt,
getTriggerEDMList(flags=
None, key=fmt, runVersion=runVersion))
for fmt
in AllowedOutputFormats])
839 with open(fileName,
'w')
as f:
840 json.dump(edmDict, f)
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=":")
_getRun3TrigObjList(destination, trigEDMList)
_getL2PreregistrationList()
getRun3BSList(flags, keys)
_getTriggerRun2EDMSlimList(key, edmList)
_getRun3TrigObjProducedInView(theKey, trigEDMList)
getPreregistrationList(version=2, doxAODConversion=True)
_getHLTPreregistrationList()
getL2Run2EquivalentList()
_getEFPreregistrationList()
testEDMList(edm_list, error_on_edmdetails=True)
dumpListToJson(fileName, runVersion)
_addExtraCollectionsToEDMList(edmList, extraList)
isCLIDDefined(cgen, typename)
_getTriggerRun1Run2ObjList(destination, lst)
getRawTriggerEDMList(flags, runVersion=-1)
_handleRun3ViewContainers(el, HLTList)
getEFRun2EquivalentList()
_getRun3TrigEDMSlimList(key, HLTList)
_InsertContainerNameForHLT(typedict)
getTriggerEDMList(flags, key, runVersion=-1)