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 OrderedDict, defaultdict
41 log = logging.getLogger( __name__ )
45 """ Returns a TriggerSummaryAlg connected to given decisions"""
48 summary.InputDecision =
"HLTSeedingSummary"
49 summary.FinalDecisions =
list(OrderedDict.fromkeys(flatDecisions))
54 """ Elementary HLT filter step: OR node containing all Filters of the sequences. The node gates execution of next reco step """
56 log.debug(
"Create filter step %s with %d filters", name, len(seq_list))
57 stepCF =
parOR(name + CFNaming.FILTER_POSTFIX)
60 filterAlg = seq.filter.Alg
61 log.debug(
"createStepFilterNode: Add %s to filter node %s", filterAlg.getName(), name)
62 if filterAlg
not in filter_list:
63 filter_list.append(filterAlg)
65 stepCF =
parOR(name + CFNaming.FILTER_POSTFIX, subs=filter_list)
67 dumpSequence (stepCF, indent=0)
78 def __getHyposOfStep( step ):
79 if len(step.sequences):
84 mx = defaultdict(list)
86 for stepNumber,cfseq_list
in enumerate(allCFSeq, 1):
87 for cfseq
in cfseq_list:
88 chains = __getHyposOfStep(cfseq.step)
89 for seq
in cfseq.step.sequences:
90 if seq.name ==
"Empty":
91 mx[stepNumber,
"Empty"].
extend(chains)
93 mx[stepNumber, seq.sequence.Alg.getName()].
extend(chains)
96 sorted_mx = OrderedDict(
sorted(
list(mx.items()), key=
lambda k: k[0]))
100 log.debug(
"Cumulative Summary of steps")
102 for (step, seq), chains
in list(sorted_mx.items()):
103 log.debug(
"(step, sequence) ==> (%d, %s) is in chains: ", step, seq)
105 log.debug(
" %s",chain)
111 """ Checks the alignement of sequences and steps in the tree"""
116 _seqMapInStep = defaultdict(set)
118 def _mapSequencesInSteps(seq, stepIndex, childInView):
119 """ Recursively finds the steps in which sequences are used"""
122 match=re.search(
'^Step([0-9]+)_filter',seq.name)
124 stepIndex = match.group(1)
125 log.debug(
"sequenceScanner: This is another step: %s %s", seq.name, stepIndex)
128 for c
in seq.Members:
132 inView = c.getName()==inViewSequence
or childInView
133 stepIndex = _mapSequencesInSteps(c, stepIndex, childInView=inView)
134 _seqMapInStep[c.name].
add((stepIndex,inView))
135 log.verbose(
"sequenceScanner: Child %s of sequence %s is in view? %s --> '%s'", c.name, seq.name, inView, inViewSequence)
137 if isinstance(c, CompFactory.EventViewCreatorAlgorithm):
138 inViewSequence = c.ViewNodeName
139 log.verbose(
"sequenceScanner: EventViewCreatorAlg %s is child of sequence %s with ViewNodeName %s", c.name, seq.name, c.ViewNodeName)
140 log.debug(
"sequenceScanner: Sequence %s is in view? %s --> '%s'", seq.name, inView, inViewSequence)
144 final_step=_mapSequencesInSteps(HLTNode, 0, childInView=
False)
146 for alg, steps
in _seqMapInStep.items():
147 if 'PassSequence' in alg
or 'HLTCaloClusterMakerFSRecoSequence' in alg \
148 or 'HLTCaloCellMakerFSRecoSequence' in alg:
151 nonViewSteps =
sum([0
if isInViews
else 1
for (stepIndex,isInViews)
in steps])
153 steplist = [stepIndex
for stepIndex,inViewSequence
in steps]
154 log.error(
"sequenceScanner: Sequence %s is expected outside of a view in more than one step: %s", alg, steplist)
155 match=re.search(
'Step([0-9]+)',alg)
157 candidateStep=match.group(1)
158 log.error(
"sequenceScanner: ---> candidate good step is %s", candidateStep)
160 raise RuntimeError(f
"Duplicated event-scope sequence {alg} in steps {steplist}")
162 log.debug(
"sequenceScanner: scanned %s steps with status %d", final_step, _status)
167 """ Creates the decision tree, given the starting node and the chains containing the sequences """
168 log.info(
"[decisionTreeFromChains] Run decisionTreeFromChains on %s", HLTNode.getName())
169 HLTNodeName = HLTNode.getName()
173 log.info(
"[decisionTreeFromChains] Configuring empty decisionTree")
174 acc.addSequence(HLTNode)
184 log.debug(
"finalDecisions: %s", finalDecisions)
185 if flags.Trigger.generateMenuDiagnostics:
192 return (finalDecisions,CFseq_list, acc)
195 """ Creates the filters and connect them to the menu sequences"""
198 chainWithMaxSteps =
max(chains, key =
lambda chain: len(chain.steps))
199 NSTEPS = len(chainWithMaxSteps.steps)
200 log.info(
"[createDataFlow] creating DF for %d chains and total %d steps", len(chains), NSTEPS)
203 finalDecisions = [ []
for n
in range(NSTEPS) ]
204 CFseqList = [ []
for n
in range(NSTEPS) ]
205 CFSeqByFilterName = [ {}
for n
in range(NSTEPS) ]
209 log.debug(
"\n Configuring chain %s with %d steps: \n - %s ", chain.name,len(chain.steps),
'\n - '.
join(map(str, [{step.name:step.multiplicity}
for step
in chain.steps])))
213 for nstep, chainStep
in enumerate( chain.steps ):
214 if not flags.Trigger.fastMenuGeneration:
216 chainStep.createSequences()
217 log.debug(
"\n************* Start connecting step %d %s for chain %s", nstep+1, chainStep.name, chain.name)
219 filterInput = chain.L1decisions
221 filterInput = lastDecisions
222 if len(filterInput) == 0 :
223 log.error(
"[createDataFlow] Filter for step %s has %d inputs! At least one is expected", chainStep.name, len(filterInput))
224 raise Exception(
"[createDataFlow] Cannot proceed, exiting.")
226 log.debug(
"Set Filter input: %s while setting the chain: %s", filterInput, chain.name)
229 sequenceFilter =
None
230 filterName = CFNaming.filterName(chainStep.name)
231 if chainStep.isEmpty:
232 filterOutput = filterInput
234 filterOutput = [CFNaming.filterOutName(filterName, inputName)
for inputName
in filterInput ]
237 foundCFgroup = CFSeqByFilterName[nstep].
get(filterName,
None)
238 log.debug(
"%s CF sequences with filter name %s",
"Not found" if foundCFgroup
is None else "Found", filterName)
239 if foundCFgroup
is None:
240 sequenceFilter =
buildFilter(filterName, filterInput, chainStep.isEmpty)
241 if flags.Trigger.fastMenuGeneration:
243 chainStep.createSequences()
245 CFgroup = CFGroup( ChainStep = chainStep, FilterAlg = sequenceFilter)
246 CFgroup.connect(filterOutput)
247 CFSeqByFilterName[nstep][sequenceFilter.Alg.getName()] = CFgroup
248 CFseqList[nstep].
append(CFgroup)
249 lastCFgroup = CFgroup
251 lastCFgroup = foundCFgroup
252 sequenceFilter = lastCFgroup.sequenceCA.filterNode
254 [ sequenceFilter.addInput(inputName)
for inputName
in filterInput ]
255 [ sequenceFilter.addOutput(outputName)
for outputName
in filterOutput ]
256 lastCFgroup.connect(filterOutput)
258 lastDecisions = lastCFgroup.sequenceCA.decisions
261 chainLegs = chainStep.getChainLegs()
262 if len(chainLegs) != len(filterInput):
263 log.error(
"[createDataFlow] lengths of chainlegs = %s differ from inputs = %s",
str(chainLegs),
str(filterInput))
264 raise Exception(
"[createDataFlow] Cannot proceed, exiting.")
265 for finput, leg
in zip(filterInput, chainLegs):
266 log.debug(
"Adding chain %s to input %s of %s", leg, finput, sequenceFilter.Alg.name)
267 sequenceFilter.addChain(leg, finput)
269 log.debug(
"Now Filter has chains: %s", sequenceFilter.getChains())
270 log.debug(
"Now Filter has chains/input: %s", sequenceFilter.getChainsPerInput())
272 lastCFgroup.addStepLeg(chainStep, chain.name)
274 if len(chain.steps) == nstep+1:
275 log.debug(
"Adding finalDecisions for chain %s at step %d:", chain.name, nstep+1)
276 for dec
in lastDecisions:
277 finalDecisions[nstep].
append(dec)
281 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.multiplicity}
for step
in chain.steps])))
284 log.debug(
"End of createDataFlow for %d chains and total %d steps", len(chains), NSTEPS)
285 return (finalDecisions, CFseqList)
289 """ Creates Control Flow Tree starting from the CFSequences"""
290 HLTNodeName = HLTNode.getName()
291 log.debug(
"[createControlFlow] on node %s with %d CFsequences",HLTNodeName, len(CFseqList))
294 acc.addSequence(HLTNode)
296 for nstep, sequences
in enumerate(CFseqList):
297 stepSequenceName = CFNaming.stepName(nstep)
298 log.debug(
"\n******** Create CF Tree %s with %d AthSequencers", stepSequenceName, len(sequences))
301 log.debug(
"[createControlFlow] Create filter step %s with %d filters", stepSequenceName, len(CFseqList[nstep]))
302 stepCFFilter =
parOR(stepSequenceName + CFNaming.FILTER_POSTFIX)
303 acc.addSequence(stepCFFilter, parentName=HLTNodeName)
307 for cgroup
in sequences:
308 filterAlg = cgroup.sequenceCA.filterNode.Alg
309 if filterAlg.getName()
not in filter_list:
310 log.debug(
"[createControlFlow] Add %s to filter node %s", filterAlg.getName(), stepSequenceName)
311 filter_list.append(filterAlg.getName())
312 stepCFFilter.Members += [filterAlg]
315 log.debug(
"[createControlFlow] Create reco step %s with %d sequences", stepSequenceName, len(CFseqList))
316 stepCFReco =
parOR(stepSequenceName + CFNaming.RECO_POSTFIX)
317 acc.addSequence(stepCFReco, parentName = HLTNodeName)
321 for cgroup
in sequences:
322 cseq=cgroup.sequenceCA
323 if cseq.step.isEmpty
and addedEmtpy:
326 if cseq.step.isEmpty:
328 log.debug(
" *** Create CF Tree for CFSequence %s", cseq.step.name)
329 acc.merge(cseq.ca, sequenceName=stepCFReco.getName())
333 for CFseq
in CFseqList[nstep]:
334 stepDecisions.extend(CFseq.sequenceCA.decisions)
336 summary =
makeSummary( flags, stepSequenceName, stepDecisions )
337 acc.addEventAlgo([summary],sequenceName = HLTNode.getName())
339 if flags.Trigger.generateMenuDiagnostics:
340 log.debug(
"Now Draw Menu Diagnostic dot graphs...")
344 log.debug(
"************* End of step %d, %s", nstep+1, stepSequenceName)
349 for groupsInStep
in CFseq_list:
350 for cfgroup
in groupsInStep:
351 chains = cfgroup.chains
352 CFS = cfgroup.sequenceCA
354 if CFS.step.combo
is not None:
356 CFS.step.combo.addChain( [d
for d
in allDicts
if d[
'chainName'] == chain ][0])
357 log.debug(
"Added chains to ComboHypo: %s",CFS.step.combo.getChains())
360 cfgroup.createHypoTools(flags)
367 one filter per previous sequence at the start of the sequence: always create a new one
368 if the previous hypo has more than one output, try to get all of them
369 one filter per previous sequence: 1 input/previous seq, 1 output/next seq
372 log.debug(
"Calling PassFilterNode %s", filter_name)
373 sfilter = PassFilterNode(name = filter_name)
374 for i
in filter_input:
378 sfilter = RoRSequenceFilterNode(name = filter_name)
379 for i
in filter_input:
381 sfilter.addOutput(CFNaming.filterOutName(filter_name, i))
383 log.debug(
"Added inputs to filter: %s", sfilter.getInputList())
384 log.debug(
"Added outputs to filter: %s", sfilter.getOutputList())
385 log.debug(
"Filter Done: %s", sfilter.Alg.name)