ATLAS Offline Software
Loading...
Searching...
No Matches
HLTMenuJSON.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3import re
4import json
5from collections import defaultdict
6
7from TrigConfigSvc.TrigConfigSvcCfg import getHLTMenuFileName
8from AthenaCommon.CFElements import getSequenceChildren
9from AthenaCommon.Logging import logging
10__log = logging.getLogger( __name__ )
11
12# remove prescale suffixes
13def __getMenuBaseName(menuName):
14 pattern = re.compile(r'_v\d+|DC14')
15 patternPos = pattern.search(menuName)
16 if patternPos:
17 menuName=menuName[:patternPos.end()]
18 else:
19 __log.info('Can\'t find pattern to shorten menu name, either non-existent in name or not implemented.')
20 return menuName
21
23 """ Generates a list where the index corresponds to a Step number and the stored object is a list of Sequencers making up the Step
24 """
25 stepsData = []
26 if HLTAllSteps is not None:
27 for HLTStep in HLTAllSteps.Members:
28 if "_reco" not in HLTStep.getName(): # Avoid the pre-step Filter execution
29 for Step in getSequenceChildren( HLTStep ):
30 for View in getSequenceChildren( Step ):
31 for Reco in getSequenceChildren( View ):
32 if "_reco" in Reco.getName() and HLTStep.getName() not in stepsData:
33 stepsData.append( HLTStep.Members )
34 break
35 continue
36
37 stepsData.append( HLTStep.Members )
38 else:
39 __log.warn( "No HLTAllSteps sequencer, will not export per-Step data for chains.")
40 return stepsData
41
42def __getFilterChains(filterAlg):
43 try:
44 # Format: leg000_CHAIN or CHAIN
45 return set(ch[7:] if ch.startswith('leg') else ch for ch in filterAlg.Chains)
46 except AttributeError: # no "Chains"
47 return set()
48
49def __getChainSequencers(stepsData):
50 """ Finds the Filter which is responsible for each Chain in each Step.
51 Returns a dictionary mapping the chain name to a list of the per-Step name
52 of the Sequencer which is unlocked by the Chain's Filter in the Step.
53 """
54 numSteps = len(stepsData)
55 chainSequencers = defaultdict(lambda : [""] * numSteps)
56 for counter, step in enumerate(stepsData):
57 for sequencer in step:
58 try:
59 sequencerFilter = sequencer.Members[0] # Always the first child in the step
60 except (AttributeError, IndexError):
61 continue # empty steps
62
63 for chainName in __getFilterChains(sequencerFilter):
64 if chainSequencers[chainName][counter] != "":
65 __log.error( "Multiple Filters found (corresponding Sequencers %s, %s) for %s in Step %i!",
66 chainSequencers[chainName][counter], sequencer.getName(), chainName, counter+1)
67 chainSequencers[chainName][counter] = sequencer.getName()
68
69 # drop trailing empty names
70 for chainName, seqList in chainSequencers.items():
71 while seqList and seqList[-1] == "":
72 del seqList[-1]
73
74 return chainSequencers
75
76def __getSequencerAlgs(stepsData):
77 """ For each Sequencer in each Step, return a flat list of the full name of all Algorithms under the Sequencer
78 """
79 from AthenaCommon.CFElements import findAllAlgorithms
80 sequencerAlgs = {}
81 for step in stepsData:
82 for sequencer in step:
83 sequencerAlgs[ sequencer.getName() ] = list(map(lambda x: x.getFullJobOptName(), findAllAlgorithms(sequencer)))
84 return sorted(sequencerAlgs.items(), key=lambda t: t[0])
85
86def generateJSON(flags, chainDicts, HLTAllSteps):
87 """ Generates JSON given the ChainProps and sequences
88 """
89 # Menu dictionary that is used to create the JSON content
90 menuDict = {"filetype": "hltmenu",
91 "name": __getMenuBaseName(flags.Trigger.triggerMenuSetup),
92 "chains": {},
93 "streams": {},
94 "sequencers": {}}
95
96 # List of steps data for sequencers
97 stepsData = __getStepsDataFromAlgSequence(HLTAllSteps)
98 chainSequencers = __getChainSequencers(stepsData)
99 from TriggerMenuMT.HLT.Menu import StreamInfo
100 for chain in chainDicts:
101 # Prepare information for stream list and fill separate dictionary
102 chainStreamTags = []
103 for streamName in chain["stream"]:
104 streamTag = StreamInfo.getStreamTag(streamName)
105 # Stream needs to have been defined in StreamInfo.py otherwise is not added to JSON
106 if streamTag is None:
107 __log.error('Stream %s does not have StreamTags defined excluding from JSON', streamName)
108 continue
109 # Add stream to the chain
110 chainStreamTags.append(streamName)
111 # If not already listed, add stream details to stream dictionary
112 if streamName not in menuDict["streams"]:
113 menuDict["streams"][streamName] = {
114 "name": streamName,
115 "type": streamTag.type(),
116 "obeyLB": streamTag.obeysLumiBlock(),
117 "forceFullEventBuilding": streamTag.forceFullEventBuilding()
118 }
119
120 # Find L1 Threshold information for current chain
121 l1Thresholds = []
122
123 [ l1Thresholds.append(p['L1threshold']) for p in chain['chainParts'] ]
124
125 # Now have all information to write the chain to the menu dictionary
126 chainName = chain["chainName"]
127 menuDict["chains"][chainName] = {
128 "counter": chain["chainCounter"],
129 "nameHash": chain["chainNameHash"],
130 "legMultiplicities": chain["chainMultiplicities"],
131 "l1item": chain["L1item"],
132 "l1thresholds": l1Thresholds,
133 "groups": chain["groups"],
134 "streams": chainStreamTags,
135 "sequencers": chainSequencers.get(chainName, [])
136 }
137
138 # All algorithms executed by a given Sequencer
139 menuDict["sequencers"].update( __getSequencerAlgs(stepsData) )
140
141 __validateJSON(menuDict)
142
143 # Menu dictionary now completed, write to JSON
144 fileName = getHLTMenuFileName( flags)
145 __log.info( "Writing HLT Menu JSON to %s", fileName )
146 with open( fileName, 'w' ) as fp:
147 json.dump( menuDict, fp, indent=4, sort_keys=False )
148
149
150def __validateJSON(menuDict):
151 """ Runs some validation checks which may pick up on issues with the menu
152 """
153 pass
154 #__validateGlobalAlgs(menuDict) # To be enabled once the current offenders are fixed
155
157 """ Check that global algs only go into one Step
158 """
159 algToStep = {}
160 import re
161 from AthenaConfiguration.ComponentFactory import CompFactory
162 inError = False
163 for seqName, seqeuncer in menuDict["sequencers"].items():
164 stepNumber = int(re.search(r'\d+', seqName).group()) # Obtain first number from string
165 fullEventMode = False
166 for alg in seqeuncer:
167 if isinstance(alg, CompFactory.EventViewCreatorAlgorithm):
168 fullEventMode = False
169 elif isinstance(alg, CompFactory.InputMakerForRoI):
170 fullEventMode = True
171 if not fullEventMode:
172 continue
173 if alg in algToStep and algToStep[alg] != stepNumber:
174 __log.error("{} is a full-event context alg, it should only be running in one Step, however it is in both Steps {} and {}".format(alg, stepNumber, algToStep[alg]))
175 inError = True
176 else:
177 algToStep[alg] = stepNumber
178 if inError:
179 raise Exception("[validateJSON] Problems detected in validateGlobalAlgs().")
STL class.
STL class.
__validateGlobalAlgs(menuDict)
__getMenuBaseName(menuName)
__getChainSequencers(stepsData)
__getStepsDataFromAlgSequence(HLTAllSteps)
generateJSON(flags, chainDicts, HLTAllSteps)
__validateJSON(menuDict)
__getSequencerAlgs(stepsData)
__getFilterChains(filterAlg)