4 ------ Documentation on HLT Tree creation -----
6 ++ Filter creation strategy
8 ++ Connections between InputMaker/HypoAlg/Filter
12 ++ Combined chain strategy
14 - The combined chains use duplicates of the single-object-HypoAlg, called HypoAlgName_for_stepName.
15 These duplicates are connected to a dedicated ComboHypoAlg (added by the framework), able to count object multiplicity
16 -- This is needed for two reasons:
17 -- the HypoAlg is designed to have only one input TC (that is already for the single object)
18 -- otherwise the HypoAlg would be equipped with differnt HypoTools with the same name (see for example e3_e8)
19 -- If the combined chain is symmetric (with multiplicity >1), the Hypo is duplicated only once,
20 equipped with a HypoTool configured as single object and followed by one ComboHypoAlg
25 from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFDot
import stepCF_DataFlow_to_dot, stepCF_ControlFlow_to_dot, all_DataFlow_to_dot
26 from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFComponents
import RoRSequenceFilterNode, PassFilterNode, CFGroup
27 from TriggerMenuMT.HLT.Config.ControlFlow.MenuComponentsNaming
import CFNaming
28 from AthenaCommon.CFElements
import parOR, isSequence
29 from AthenaCommon.AlgSequence
import dumpSequence
30 from AthenaCommon.Logging
import logging
32 from AthenaConfiguration.ComponentFactory
import CompFactory
34 from DecisionHandling.DecisionHandlingConfig
import TriggerSummaryAlg
35 from AthenaConfiguration.ComponentAccumulator
import ComponentAccumulator
37 from builtins
import map, range, str, zip
38 from collections
import defaultdict
41 log = logging.getLogger( __name__ )
45 """ Elementary HLT filter step: OR node containing all Filters of the sequences. The node gates execution of next reco step """
47 log.debug(
"Create filter step %s with %d filters", name, len(seq_list))
48 stepCF =
parOR(name + CFNaming.FILTER_POSTFIX)
51 filterAlg = seq.filter.Alg
52 log.debug(
"createStepFilterNode: Add %s to filter node %s", filterAlg.getName(), name)
53 if filterAlg
not in filter_list:
54 filter_list.append(filterAlg)
56 stepCF =
parOR(name + CFNaming.FILTER_POSTFIX, subs=filter_list)
58 dumpSequence (stepCF, indent=0)
69 def __getHyposOfStep( step ):
70 if len(step.sequences):
75 mx = defaultdict(list)
77 for stepNumber,cfseq_list
in enumerate(allCFSeq, 1):
78 for cfseq
in cfseq_list:
79 chains = __getHyposOfStep(cfseq.step)
80 for seq
in cfseq.step.sequences:
81 if seq.name ==
"Empty":
82 mx[stepNumber,
"Empty"].
extend(chains)
84 mx[stepNumber, seq.sequence.Alg.getName()].
extend(chains)
87 sorted_mx = dict(
sorted(
list(mx.items()), key=
lambda k: k[0]))
91 log.debug(
"Cumulative Summary of steps")
93 for (step, seq), chains
in list(sorted_mx.items()):
94 log.debug(
"(step, sequence) ==> (%d, %s) is in chains: ", step, seq)
96 log.debug(
" %s",chain)
102 """ Checks the alignement of sequences and steps in the tree"""
107 _seqMapInStep = defaultdict(set)
109 def _mapSequencesInSteps(seq, stepIndex, childInView):
110 """ Recursively finds the steps in which sequences are used"""
113 match=re.search(
'^Step([0-9]+)_filter',seq.name)
115 stepIndex = match.group(1)
116 log.debug(
"sequenceScanner: This is another step: %s %s", seq.name, stepIndex)
119 for c
in seq.Members:
123 inView = c.getName()==inViewSequence
or childInView
124 stepIndex = _mapSequencesInSteps(c, stepIndex, childInView=inView)
125 _seqMapInStep[c.name].
add((stepIndex,inView))
126 log.verbose(
"sequenceScanner: Child %s of sequence %s is in view? %s --> '%s'", c.name, seq.name, inView, inViewSequence)
128 if isinstance(c, CompFactory.EventViewCreatorAlgorithm):
129 inViewSequence = c.ViewNodeName
130 log.verbose(
"sequenceScanner: EventViewCreatorAlg %s is child of sequence %s with ViewNodeName %s", c.name, seq.name, c.ViewNodeName)
131 log.debug(
"sequenceScanner: Sequence %s is in view? %s --> '%s'", seq.name, inView, inViewSequence)
135 final_step=_mapSequencesInSteps(HLTNode, 0, childInView=
False)
137 for alg, steps
in _seqMapInStep.items():
138 if 'PassSequence' in alg
or 'HLTCaloClusterMakerFSRecoSequence' in alg \
139 or 'HLTCaloCellMakerFSRecoSequence' in alg:
142 nonViewSteps =
sum([0
if isInViews
else 1
for (stepIndex,isInViews)
in steps])
144 steplist = [stepIndex
for stepIndex,inViewSequence
in steps]
145 log.error(
"sequenceScanner: Sequence %s is expected outside of a view in more than one step: %s", alg, steplist)
146 match=re.search(
'Step([0-9]+)',alg)
148 candidateStep=match.group(1)
149 log.error(
"sequenceScanner: ---> candidate good step is %s", candidateStep)
151 raise RuntimeError(f
"Duplicated event-scope sequence {alg} in steps {steplist}")
153 log.debug(
"sequenceScanner: scanned %s steps with status %d", final_step, _status)
158 """ Creates the decision tree, given the starting node and the chains containing the sequences """
159 log.info(
"[decisionTreeFromChains] Run decisionTreeFromChains on %s", HLTNode.getName())
160 HLTNodeName = HLTNode.getName()
164 log.info(
"[decisionTreeFromChains] Configuring empty decisionTree")
165 acc.addSequence(HLTNode)
175 log.debug(
"finalDecisions: %s", finalDecisions)
176 if flags.Trigger.generateMenuDiagnostics:
183 return (finalDecisions,CFseq_list, acc)
186 """ Creates the filters and connect them to the menu sequences"""
189 chainWithMaxSteps =
max(chains, key =
lambda chain: len(chain.steps))
190 NSTEPS = len(chainWithMaxSteps.steps)
191 log.info(
"[createDataFlow] creating DF for %d chains and total %d steps", len(chains), NSTEPS)
194 finalDecisions = [ []
for n
in range(NSTEPS) ]
195 CFseqList = [ []
for n
in range(NSTEPS) ]
196 CFSeqByFilterName = [ {}
for n
in range(NSTEPS) ]
200 log.debug(
"\n Configuring chain %s with %d steps: \n - %s ", chain.name,len(chain.steps),
'\n - '.
join(map(str, [{step.name:step.nLegs}
for step
in chain.steps])))
204 for nstep, chainStep
in enumerate( chain.steps ):
205 if not flags.Trigger.fastMenuGeneration:
207 chainStep.createSequences()
208 log.debug(
"\n************* Start connecting step %d %s for chain %s", nstep+1, chainStep.name, chain.name)
210 filterInput = chain.L1decisions
212 filterInput = lastDecisions
213 if len(filterInput) == 0 :
214 log.error(
"[createDataFlow] Filter for step %s has %d inputs! At least one is expected", chainStep.name, len(filterInput))
215 raise Exception(
"[createDataFlow] Cannot proceed, exiting.")
217 log.debug(
"Set Filter input: %s while setting the chain: %s", filterInput, chain.name)
220 sequenceFilter =
None
221 filterName = CFNaming.filterName(chainStep.name)
222 if chainStep.isEmpty:
223 filterOutput = filterInput
225 filterOutput = [CFNaming.filterOutName(filterName, inputName)
for inputName
in filterInput ]
228 foundCFgroup = CFSeqByFilterName[nstep].
get(filterName,
None)
229 log.debug(
"%s CF sequences with filter name %s",
"Not found" if foundCFgroup
is None else "Found", filterName)
230 if foundCFgroup
is None:
231 sequenceFilter =
buildFilter(filterName, filterInput, chainStep.isEmpty)
232 if flags.Trigger.fastMenuGeneration:
234 chainStep.createSequences()
236 CFgroup = CFGroup( ChainStep = chainStep, FilterAlg = sequenceFilter)
237 CFgroup.connect(filterOutput)
238 CFSeqByFilterName[nstep][sequenceFilter.Alg.getName()] = CFgroup
239 CFseqList[nstep].
append(CFgroup)
240 lastCFgroup = CFgroup
242 lastCFgroup = foundCFgroup
243 sequenceFilter = lastCFgroup.sequenceCA.filterNode
245 [ sequenceFilter.addInput(inputName)
for inputName
in filterInput ]
246 [ sequenceFilter.addOutput(outputName)
for outputName
in filterOutput ]
247 lastCFgroup.connect(filterOutput)
249 lastDecisions = lastCFgroup.sequenceCA.decisions
252 chainLegs = chainStep.getChainLegs()
253 if len(chainLegs) != len(filterInput):
254 log.error(
"[createDataFlow] lengths of chainlegs = %s differ from inputs = %s",
str(chainLegs),
str(filterInput))
255 raise Exception(
"[createDataFlow] Cannot proceed, exiting.")
256 for finput, leg
in zip(filterInput, chainLegs):
257 log.debug(
"Adding chain %s to input %s of %s", leg, finput, sequenceFilter.Alg.name)
258 sequenceFilter.addChain(leg, finput)
260 log.debug(
"Now Filter has chains: %s", sequenceFilter.getChains())
261 log.debug(
"Now Filter has chains/input: %s", sequenceFilter.getChainsPerInput())
263 lastCFgroup.addStepLeg(chainStep, chain.name)
265 if len(chain.steps) == nstep+1:
266 log.debug(
"Adding finalDecisions for chain %s at step %d:", chain.name, nstep+1)
267 for dec
in lastDecisions:
268 finalDecisions[nstep].
append(dec)
272 log.debug(
"\n Built CD for chain %s with %d steps: \n - %s ", chain.name,len(chain.steps),
'\n - '.
join(map(str, [{step.name:step.nLegs}
for step
in chain.steps])))
275 log.debug(
"End of createDataFlow for %d chains and total %d steps", len(chains), NSTEPS)
276 return (finalDecisions, CFseqList)
280 """ Creates Control Flow Tree starting from the CFSequences"""
281 HLTNodeName = HLTNode.getName()
282 log.debug(
"[createControlFlow] on node %s with %d CFsequences",HLTNodeName, len(CFseqList))
285 acc.addSequence(HLTNode)
287 for nstep, sequences
in enumerate(CFseqList):
288 stepSequenceName = CFNaming.stepName(nstep)
289 log.debug(
"\n******** Create CF Tree %s with %d AthSequencers", stepSequenceName, len(sequences))
292 log.debug(
"[createControlFlow] Create filter step %s with %d filters", stepSequenceName, len(CFseqList[nstep]))
293 stepCFFilter =
parOR(stepSequenceName + CFNaming.FILTER_POSTFIX)
294 acc.addSequence(stepCFFilter, parentName=HLTNodeName)
298 for cgroup
in sequences:
299 filterAlg = cgroup.sequenceCA.filterNode.Alg
300 if filterAlg.getName()
not in filter_list:
301 log.debug(
"[createControlFlow] Add %s to filter node %s", filterAlg.getName(), stepSequenceName)
302 filter_list.append(filterAlg.getName())
303 stepCFFilter.Members += [filterAlg]
306 log.debug(
"[createControlFlow] Create reco step %s with %d sequences", stepSequenceName, len(CFseqList))
307 stepCFReco =
parOR(stepSequenceName + CFNaming.RECO_POSTFIX)
308 acc.addSequence(stepCFReco, parentName = HLTNodeName)
312 for cgroup
in sequences:
313 cseq=cgroup.sequenceCA
314 if cseq.step.isEmpty
and addedEmtpy:
317 if cseq.step.isEmpty:
319 log.debug(
" *** Create CF Tree for CFSequence %s", cseq.step.name)
320 acc.merge(cseq.ca, sequenceName=stepCFReco.getName())
324 for CFseq
in CFseqList[nstep]:
325 stepDecisions.extend(CFseq.sequenceCA.decisions)
327 summaryAlg =
TriggerSummaryAlg( flags, CFNaming.stepSummaryName(stepSequenceName),
328 InputDecision =
"HLTSeedingSummary",
329 FinalDecisions =
list(dict.fromkeys(stepDecisions)) )
331 acc.addEventAlgo(summaryAlg, sequenceName = HLTNode.getName())
333 if flags.Trigger.generateMenuDiagnostics:
334 log.debug(
"Now Draw Menu Diagnostic dot graphs...")
338 log.debug(
"************* End of step %d, %s", nstep+1, stepSequenceName)
343 for groupsInStep
in CFseq_list:
344 for cfgroup
in groupsInStep:
345 chains = cfgroup.chains
346 CFS = cfgroup.sequenceCA
348 if CFS.step.combo
is not None:
350 CFS.step.combo.addChain( [d
for d
in allDicts
if d[
'chainName'] == chain ][0])
351 log.debug(
"Added chains to ComboHypo: %s",CFS.step.combo.getChains())
354 cfgroup.createHypoTools(flags)
361 one filter per previous sequence at the start of the sequence: always create a new one
362 if the previous hypo has more than one output, try to get all of them
363 one filter per previous sequence: 1 input/previous seq, 1 output/next seq
366 log.debug(
"Calling PassFilterNode %s", filter_name)
367 sfilter = PassFilterNode(name = filter_name)
368 for i
in filter_input:
372 sfilter = RoRSequenceFilterNode(name = filter_name)
373 for i
in filter_input:
375 sfilter.addOutput(CFNaming.filterOutName(filter_name, i))
377 log.debug(
"Added inputs to filter: %s", sfilter.getInputList())
378 log.debug(
"Added outputs to filter: %s", sfilter.getOutputList())
379 log.debug(
"Filter Done: %s", sfilter.Alg.name)