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 """Get list of classes to ignore during deserialization"""
576 if flags.Trigger.EDMVersion == 2:
579 l.append(
"145610168")
580 l.append(
"1271751257")
581 l.append(
"1142962358")
586 """ List of L2 types to be read from BS, used by the TP
589 for item
in TriggerL2List:
592 if 'collection' in EDMDetails[t]:
593 ctype = EDMDetails[t][
'collection']
598 """ List of EF types to be read from BS, used by the TP
601 for item
in TriggerEFList:
604 if 'collection' in EDMDetails[t]:
605 ctype = EDMDetails[t][
'collection']
610 """ List of HLT types to be read from BS, used by the TP
613 for item
in TriggerHLTList:
616 if 'collection' in EDMDetails[t]:
617 ctype = EDMDetails[t][
'collection']
623 Mapping of Transient objects to Peristent during serialization (BS creation)
624 version can be: '1 (Run1)', '2 (Run2)'
632 raise RuntimeError(
"Invalid version=%s supplied to getTPList" % version)
634 for t,d
in EDMDetails.items():
636 if 'collection' in d:
637 colltype = EDMDetails[t][
'collection']
638 if colltype
in bslist:
639 l[colltype] = d[
'persistent']
649 for k,v
in typedict.items():
652 if el.startswith(
'HLT_')
or el ==
'HLT':
653 prefixAndLabel = el.split(
'_',1)
654 containername = k
if 'Aux' not in k
else EDMDetails[k][
'parent']
656 containername = re.sub(
'::',
'__',re.sub(
'_v[0-9]+$',
'',containername))
657 newnames+=[
'_'.join([prefixAndLabel[0],containername]+([prefixAndLabel[1]]
if len(prefixAndLabel) > 1
else []))]
665 List of EF trigger objects that were written to ByteStream in Run 1
668 for item
in TriggerEFEvolutionList:
669 if len (item[1]) == 0:
continue
676 List of Run-2 containers equivalent to Run-1 EF containers
679 for item
in TriggerEFEvolutionList:
680 if len (item[1]) == 0:
continue
687 List of L2 trigger objects that were written to ByteStream in Run 1
690 for item
in TriggerL2EvolutionList:
691 if len (item[1]) == 0:
continue
698 List of Run-2 containers equivalent to Run-1 L2 containers
701 for item
in TriggerL2EvolutionList:
702 if len (item[1]) == 0:
continue
709 Checks container type name is hashable
711 c = cgen.genClidFromName(typename)
712 return (cgen.getNameFromClid(c)
is not None)
716 Checks EDM list entries for serialization and configuration compliance.
720 _noAuxList = [
"xAOD::" + contType
for contType
in [
"TrigConfKeys",
"BunchConfKey"]]
722 cgen = clidGenerator(
"",
False)
724 found_allow_truncation =
False
725 serializable_names = []
726 serializable_names_no_label = []
727 serializable_names_no_properties = []
729 for i, edm
in enumerate(edm_list):
733 log.error(
"EDM entry too short for " + edm[0])
737 serializable_name = edm[0]
738 serializable_name_no_label = re.sub(
r"\#.*",
"", serializable_name)
739 serializable_name_no_properties = serializable_name.split(
'.')[0]
741 serializable_names.append(serializable_name)
742 serializable_names_no_label.append(serializable_name_no_label)
743 serializable_names_no_properties.append(serializable_name_no_properties)
747 log.error(
"no CLID for " + serializable_name)
751 if "Aux" not in serializable_name
and "." in serializable_name:
752 log.error(
"A '.' found in non-Aux container name " + serializable_name)
756 if "Aux" in serializable_name
and "Aux." not in serializable_name:
757 log.error(
"no final Aux. in label for " + serializable_name)
761 if serializable_name.count(
"#") != 1:
762 log.error(
"Invalid naming structure for " + serializable_name)
766 if serializable_name.startswith(
"xAOD")
and "Aux" not in serializable_name:
767 cont_type,cont_name = serializable_name.split(
"#")
768 if cont_type
not in _noAuxList:
770 if len(edm_list) == i+1:
772 cont_to_test =
"nothing"
774 cont_to_test = edm_list[i+1][0].
split(
".")[0]+
"."
775 cont_type_short = cont_type.replace(
"Container",
"")
776 pattern = re.compile(cont_type_short+
r".*Aux.*\#"+cont_name+
"Aux.")
777 if not pattern.match(cont_to_test):
779 shallow_pattern = re.compile(
"xAOD::ShallowAuxContainer#"+cont_name+
"Aux.")
780 if not shallow_pattern.match(cont_to_test):
783 log.error(
"Expected relevant Aux container following interface container %s, but found %s instead.",serializable_name,cont_to_test)
788 if len(edm_list[i+1]) > 1
and cont_to_test.count(
"#") == 1:
789 contname_to_test = cont_to_test.split(
"#")[1]
790 targets_to_test =
set(edm_list[i+1][1].
split())
791 if len(targets ^ targets_to_test) > 0:
792 log.error(
"Targets of %s (%s) and %s (%s) do not match",cont_name,targets,contname_to_test,targets_to_test)
796 if i>0
and "Aux" in serializable_name
and "Aux" in edm_list[i-1][0]:
797 log.error(f
"Aux container {serializable_name} needs to folow the "
798 "associated interface container in the EDM list")
803 file_types = edm[1].
split()
804 for file_type
in file_types:
805 if file_type
not in AllowedOutputFormats:
806 log.error(
"unknown file type " + file_type +
" for " + serializable_name)
808 for higher_level,required_lower_level
in [(
'AOD',
'ESD'), (
'SLIM',
'AODFULL')]:
809 if higher_level
in file_type
and required_lower_level
not in file_types:
810 log.error(
"Target list for %s containing '%s' must also contain lower level target '%s'.",serializable_name,file_type,required_lower_level)
814 tags = edm[3]
if len(edm) > 3
else None
815 allow_truncation_flag =
False
817 allow_truncation_flag = allowTruncation
in tags
818 if allow_truncation_flag:
819 found_allow_truncation =
True
821 if found_allow_truncation
and not allow_truncation_flag:
822 log.error(
"All instances of 'allowTruncation' need to be at the END of the EDM serialisation list")
829 if len(
set(serializable_names_no_properties)) != len(serializable_names_no_properties):
830 log.error(
"Duplicates in EDM list! Duplicates found:")
832 for item, count
in collections.Counter(serializable_names_no_properties).items():
834 log.error(str(count) +
"x: " + str(item))
838 for EDMDetail
in EDMDetailsRun3:
839 if EDMDetail
not in serializable_names_no_label:
840 msg =
"EDMDetail for " + EDMDetail +
" does not correspond to any name in TriggerList"
841 if error_on_edmdetails:
851 edmDict = dict([(fmt,
getTriggerEDMList(flags=
None, key=fmt, runVersion=runVersion))
for fmt
in AllowedOutputFormats])
852 with open(fileName,
'w')
as f:
853 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()
getClassesToIgnore(flags)
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)