ATLAS Offline Software
Loading...
Searching...
No Matches
TriggerRecoConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
4from AthenaConfiguration.ComponentFactory import CompFactory
5from AthenaConfiguration.Enums import Format
6from TrigT1ResultByteStream.TrigT1ResultByteStreamConfig import L1TriggerByteStreamDecoderCfg
7from TrigConfigSvc.TrigConfigSvcCfg import TrigConfigSvcCfg
8from TriggerJobOpts.TriggerByteStreamConfig import ByteStreamReadCfg
9from TrigEDMConfig.TriggerEDM import getTriggerEDMList
10from TrigEDMConfig.Utils import edmDictToList
11from OutputStreamAthenaPool.OutputStreamConfig import addToAOD, addToESD
12
13from AthenaCommon.Logging import logging
14log = logging.getLogger('TriggerRecoConfig')
15
16
17def TriggerRecoCfg(flags):
18 if flags.Input.isMC:
19 return TriggerRecoCfgMC(flags)
20 else:
21 return TriggerRecoCfgData(flags)
22
24 """
25 Configures trigger data decoding
26 Run 3 data:
27 HLTResultMTByteStreamDecoderAlg -> TriggerEDMDeserialiserAlg
28
29 Run 2 data:
30 TrigBSExtraction -> TrigDecisionMaker -> DecisionConv to xAOD -> NavigationConv to xAOD
31
32 Run 1 data:
33 not supported anymore
34 """
35 log.debug("TriggerRecoCfgData: Preparing the trigger handling of reconstruction of data")
36 acc = ComponentAccumulator()
37 acc.merge( ByteStreamReadCfg(flags) )
38 if flags.Trigger.L1.doMuon or flags.Trigger.L1.doCalo or flags.Trigger.L1.doTopo or flags.Trigger.L1.doCTP:
39 acc.merge( L1TriggerByteStreamDecoderCfg(flags) )
40
41 metadataAcc, _ = TriggerMetadataWriterCfg(flags)
42 acc.merge( metadataAcc )
43
44 # Run 3+
45 if flags.Trigger.EDMVersion >= 3:
46 acc.merge(Run3TriggerBSUnpackingCfg(flags))
47
48 from TrigDecisionMaker.TrigDecisionMakerConfig import Run3DecisionMakerCfg
49 acc.merge(Run3DecisionMakerCfg(flags))
50
51 if flags.Trigger.doNavigationSlimming:
52 from TrigNavSlimmingMT.TrigNavSlimmingMTConfig import TrigNavSlimmingMTCfg
53 acc.merge(TrigNavSlimmingMTCfg(flags))
54
55 # Run 2
56 elif flags.Trigger.EDMVersion == 2:
57 acc.merge( Run2BSExtractionCfg(flags) )
58
59 from TrigDecisionMaker.TrigDecisionMakerConfig import Run1Run2DecisionMakerCfg
60 acc.merge (Run1Run2DecisionMakerCfg(flags) )
61
62 acc.merge(Run2Run1NavigationSlimmingCfg(flags))
63 # Run 1
64 elif flags.Trigger.EDMVersion == 1:
65 raise RuntimeError("Run-1 trigger reconstruction is no longer supported")
66 else:
67 raise RuntimeError("Invalid EDMVersion=%s " % flags.Trigger.EDMVersion)
68
69 # Legacy L1Calo, L1Topo reco
70 if flags.Trigger.enableL1CaloLegacy:
71 from AnalysisTriggerAlgs.AnalysisTriggerAlgsConfig import RoIBResultToxAODCfg
72 xRoIBResultAcc, _ = RoIBResultToxAODCfg(flags)
73 acc.merge( xRoIBResultAcc )
74
75 if flags.Input.Format is Format.BS and flags.Input.DataYear < 2024:
76 from L1TopoByteStream.L1TopoByteStreamConfig import L1TopoRawDataContainerBSCnvCfg
77 acc.merge( L1TopoRawDataContainerBSCnvCfg(flags) )
78 topoEDM = ['xAOD::L1TopoRawDataContainer#L1TopoRawData',
79 'xAOD::L1TopoRawDataAuxContainer#L1TopoRawDataAux.']
80 acc.merge(addToESD(flags, topoEDM))
81 acc.merge(addToAOD(flags, topoEDM))
82
83 acc.merge(TriggerEDMCfg(flags))
84
85 return acc
86
88 """
89 Configures trigger MC handing during reconstruction
90 Note that a lot of the T0 handling of the trigger output for data is bundled into
91 the RDO to RDO_TRIG sub-step for MC, hence there is much less to do here for MC.
92 Notably: the xAOD::TrigDecision and all metadata should already be in the RDO_TRIG.
93
94 Run 3 MC:
95 Propagation of Run 3 HLT collections from input RDO_TRIG to output POOL files.
96 Execution of Run-3 reconstruction-level trigger navigation slimming.
97
98 Run 2 MC:
99 Propagation of Run 2 HLT collections from input RDO_TRIG to output POOL files.
100 Execution of Run 2 style reconstruction-level trigger navigation slimming.
101 Optional conversion of Run 2 navigation to Run 3 navigation.
102 Optional execution of Run 3 reconstruction-level trigger navigation slimming on conversion output.
103
104 Run 1 MC:
105 No current workflows are able to run the Run 1 trigger MC simulation. Unsupported.
106 """
107
108 # Check for currently unsupported operational modes, these may be supported in the future if needed
109 if flags.Input.Format is Format.BS:
110 log.warning("TriggerRecoCfgMC does not currently support MC files encoded as bytestream. Switching off handling of trigger inputs.")
111 return ComponentAccumulator()
112 if flags.Trigger.EDMVersion == 1:
113 log.warning("TriggerRecoCfgMC does not currently support MC files with Run 1 trigger payload. Switching off handling of trigger inputs.")
114 return ComponentAccumulator()
115
116 log.debug("TriggerRecoCfgMC: Preparing the trigger handling of reconstruction of MC")
117 acc = ComponentAccumulator()
118
119 # This will kick into action for Run 2 (Run-1 gets blocked above)
120 acc.merge(Run2Run1NavigationSlimmingCfg(flags))
121
122 # This may kick into action for Run 2, based on flags.Trigger.doEDMVersionConversion
123 from TrigNavTools.NavConverterConfig import NavConverterCfg
124 acc.merge(NavConverterCfg(flags))
125
126 # This will kick into action for Run 3, and may for Run 2 if based on the navigation conversion above
127 from TrigNavSlimmingMT.TrigNavSlimmingMTConfig import TrigNavSlimmingMTCfg
128 acc.merge(TrigNavSlimmingMTCfg(flags))
129
130 acc.merge(TriggerEDMCfg(flags))
131
132 return acc
133
135 """Sets up access to HLT, L1, BGRP, Monitoring, HLT PS and L1 PS JSON files from 'FILE' or 'DB', writes JSON to metaStore and keys to eventStore"""
136 acc = ComponentAccumulator()
137 keyWriterOutput = ""
138 if flags.Trigger.triggerConfig != 'INFILE':
139 acc.merge( TrigConfigSvcCfg(flags) )
140 keyWriterTool = CompFactory.TrigConf.KeyWriterTool("KeyWriterToolOffline")
141 keyWriterOutput = str(keyWriterTool.ConfKeys)
142 acc.addEventAlgo( CompFactory.TrigConf.xAODMenuWriter("xAODMenuWriter", KeyWriterTool = keyWriterTool) )
143 return acc, keyWriterOutput
144
145def TriggerEDMCfg(flags):
146 """Configures which trigger collections are recorded"""
147 acc = ComponentAccumulator()
148
149 # Check if we have anything to do
150 if flags.Output.doWriteESD is False and flags.Output.doWriteAOD is False:
151 log.debug("TriggerEDMCfg: Nothing to do as both Output.doWriteAOD and Output.doWriteESD are False")
152 return acc
153
154 # standard collections & metadata
155 # TODO consider unifying with TriggerConfig.triggerPOOLOutputCfg - there the assumption is that Run3
156 # metadata
157 menuMetadata = ["xAOD::TriggerMenuJsonContainer#*", "xAOD::TriggerMenuJsonAuxContainer#*",]
158 if flags.Trigger.EDMVersion in [1,2]:
159 menuMetadata += ['xAOD::TriggerMenuAuxContainer#*', 'xAOD::TriggerMenuContainer#*',]
160 # Add LVL1 collections (for Run-3 they are part of the "regular" EDM lists)
161 from TrigEDMConfig.TriggerEDM import getLvl1ESDList, getLvl1AODList
162 acc.merge(addToESD(flags, edmDictToList(getLvl1ESDList())))
163 acc.merge(addToAOD(flags, edmDictToList(getLvl1AODList())))
164
165 edmVersion = max(2, flags.Trigger.EDMVersion)
166 _TriggerESDList = getTriggerEDMList(flags, key=flags.Trigger.ESDEDMSet, runVersion=edmVersion)
167 _TriggerAODList = getTriggerEDMList(flags, key=flags.Trigger.AODEDMSet, runVersion=edmVersion)
168 log.debug("ESD EDM list: %s", _TriggerESDList)
169 log.debug("AOD EDM list: %s", _TriggerAODList)
170
171 # Highlight what is in AOD list but not in ESD list, as this can cause
172 # the "different number of entries in branch" problem, when it is in the
173 # AOD list but the empty container per event is not created
174 # Just compares keys of dicts, which are the class names, not their string keys in StoreGate
175 not_in = [ element for element in _TriggerAODList if element not in _TriggerESDList ]
176 if (len(not_in)>0):
177 log.warning("In AOD list but not in ESD list: ")
178 log.warning(not_in)
179 else:
180 log.info("AOD list is subset of ESD list - good.")
181
182 # there is internal gating in addTo* if AOD or ESD do not need to be written out
183 acc.merge(addToESD(flags, edmDictToList(_TriggerESDList), MetadataItemList = menuMetadata))
184 acc.merge(addToAOD(flags, edmDictToList(_TriggerAODList), MetadataItemList = menuMetadata))
185
186 log.info("AOD content set according to the AODEDMSet flag: %s and EDM version %d", flags.Trigger.AODEDMSet, flags.Trigger.EDMVersion)
187 # navigation for Run 3
188 if flags.Trigger.EDMVersion == 3 and not flags.Trigger.doOnlineNavigationCompactification and not flags.Trigger.doNavigationSlimming:
189 nav = ['xAOD::TrigCompositeContainer#HLTNav*', 'xAOD::TrigCompositeAuxContainer#HLTNav*',]
190 acc.merge(addToAOD(flags, nav))
191 acc.merge(addToESD(flags, nav))
192 # extra jet keys
193 jetSpecials = ["JetKeyDescriptor#JetKeyMap", "JetMomentMap#TrigJetRecMomentMap",]
194 acc.merge(addToESD(flags, jetSpecials))
195 acc.merge(addToAOD(flags, jetSpecials))
196
197 # RoIs
198 if flags.Output.doWriteAOD and flags.Trigger.EDMVersion == 2:
199 from TrigRoiConversion.TrigRoiConversionConfig import RoiWriterCfg
200 acc.merge(RoiWriterCfg(flags))
201
202 return acc
203
205 """Configures legacy Run1/2 navigation slimming"""
206 acc = ComponentAccumulator()
207
208 if flags.Trigger.decodeHLT is False:
209 log.debug("Run2Run1NavigationSlimmingCfg: Nothing to do as Trigger.decodeHLT is False")
210 return acc
211
212 if flags.Trigger.doNavigationSlimming is False:
213 log.debug("Run2Run1NavigationSlimmingCfg: Nothing to do as Trigger.doNavigationSlimming is False")
214 return acc
215
216 if flags.Trigger.EDMVersion >= 3:
217 log.debug("Run2Run1NavigationSlimmingCfg: Nothing to do for EDMVersion >= 3.")
218 return acc
219
220 if flags.Trigger.ExtraEDMList:
221 log.warning("Run2Run1NavigationSlimmingCfg: ExtraEDMList only works for Run 3 and beyond")
222
223 def _flatten(edm):
224 return list(y.split('-')[0] for x in edm.values() for y in x)
225 from TrigNavTools.TrigNavToolsConfig import TrigNavigationThinningSvcCfg
226
227 from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
228
229 if flags.Output.doWriteAOD:
230 _TriggerAODList = getTriggerEDMList(flags, key=flags.Trigger.AODEDMSet)
231 thinningSvc = acc.getPrimaryAndMerge(TrigNavigationThinningSvcCfg(flags,
232 {'name' : 'HLTNav_StreamAOD',
233 'mode' : 'cleanup_noreload',
234 'result' : 'HLTResult_HLT',
235 'features' : _flatten(_TriggerAODList)}))
236 acc.merge(OutputStreamCfg(flags, "AOD", trigNavThinningSvc = thinningSvc))
237
238 if flags.Output.doWriteESD:
239 _TriggerESDList = getTriggerEDMList(flags, key=flags.Trigger.ESDEDMSet)
240 thinningSvc = acc.getPrimaryAndMerge(TrigNavigationThinningSvcCfg(flags,
241 {'name' : 'HLTNav_StreamESD',
242 'mode' : 'cleanup_noreload',
243 'result' : 'HLTResult_HLT',
244 'features' : _flatten(_TriggerESDList)}))
245 acc.merge(OutputStreamCfg(flags, "ESD", trigNavThinningSvc = thinningSvc))
246
247 return acc
248
249
251 """Configures Trigger data from BS extraction """
252 from SGComps.AddressRemappingConfig import InputRenameCfg
253
254 acc = ComponentAccumulator()
255 extr = CompFactory.TrigBSExtraction()
256 robIDMap = {} # map of result keys and their ROB ID
257
258 # Add fictional output to ensure data dependency in AthenaMT
259 extr.ExtraOutputs.add(("TrigBSExtractionOutput", "StoreGateSvc+TrigBSExtractionOutput"))
260
261 if flags.Trigger.decodeHLT:
262 serialiserTool = CompFactory.TrigTSerializer()
263 acc.addPublicTool(serialiserTool)
264 extr.Navigation = CompFactory.HLT.Navigation("Navigation")
265 from TrigEDMConfig.TriggerEDM import getEDMLibraries
266 extr.Navigation.Dlls = getEDMLibraries()
267 from TrigEDMConfig.TriggerEDM import getPreregistrationList
268 extr.Navigation.ClassesToPreregister = getPreregistrationList(flags.Trigger.EDMVersion, flags.Trigger.doxAODConversion)
269 from eformat import helper as efh
270
271 if flags.Trigger.EDMVersion == 1:
272 raise RuntimeError("Run-1 trigger reconstruction is no longer supported")
273 else:
274 acc.merge(InputRenameCfg("HLT::HLTResult", "HLTResult_HLT", "HLTResult_HLT_BS"))
275 robIDMap["HLTResult_HLT_BS"] = efh.SourceIdentifier(efh.SubDetector.TDAQ_HLT, 0).code()
276 extr.HLTResultKeyIn = "HLTResult_HLT_BS"
277 extr.HLTResultKeyOut = "HLTResult_HLT"
278
279 # Configure Run-2 DataScouting
280 if flags.Trigger.EDMVersion == 2:
281 stream = flags.Input.TriggerStream
282 if stream.startswith('calibration_DataScouting_'):
283 ds_tag = '_'.join(stream.split('_')[1:3]) # e.g. DataScouting_05
284 ds_id = int(stream.split('_')[2]) # e.g. 05
285 acc.merge(InputRenameCfg("HLT::HLTResult", ds_tag, ds_tag+"_BS"))
286 robIDMap[ds_tag+"_BS"] = efh.SourceIdentifier(efh.SubDetector.TDAQ_HLT, ds_id).code()
287 extr.DSResultKeysIn += [ ds_tag+"_BS" ]
288 extr.DSResultKeysOut += [ ds_tag ]
289
290 else:
291 log.info("Will not schedule real HLT bytestream extraction, instead EDM gap filling is running")
292 # if data doesn't have HLT info set HLTResult keys as empty strings to avoid warnings
293 # but the extraction algorithm must run
294 extr.HLTResultKeyIn = ""
295 extr.HLTResultKeyOut = ""
296
297 HLTResults = [ f"HLT::HLTResult/{k}" for k in robIDMap ]
298 acc.addService( CompFactory.ByteStreamAddressProviderSvc( TypeNames = HLTResults) )
299
300 from TrigEDMConfig.TriggerEDM import getTPList
301 acc.addPublicTool( CompFactory.TrigSerTPTool(TPMap = getTPList((flags.Trigger.EDMVersion))) )
302
303 acc.addPublicTool( CompFactory.TrigSerializeConvHelper(doTP = True) )
304
305 acc.addPublicTool( CompFactory.HLT.HLTResultByteStreamTool(HLTResultRobIdMap = robIDMap))
306
307 acc.addEventAlgo(extr)
308
309 return acc
310
311
313 """Configures conversions BS -> HLTResultMT -> Collections """
314 acc = ComponentAccumulator()
315
316 if flags.Trigger.decodeHLT is False:
317 log.debug("Run3TriggerBSUnpackingCfg: Nothing to do as Trigger.decodeHLT is False")
318 return acc
319
320 from AthenaCommon.CFElements import seqAND
321 from TrigEDMConfig.DataScoutingInfo import (
322 getDataScoutingStreams, getDataScoutingTypeFromStream,
323 getFullHLTResultID, getDataScoutingResultID,
324 )
325 from TriggerJobOpts.TriggerConfig import triggerEDMGapFillerCfg
326 from TrigDecisionTool.TrigDecisionToolConfig import getRun3NavigationContainerFromInput
327 ids_to_decode = []
328
329 # Map the trigger stream to the event building type
330 if flags.Input.TriggerStream in getDataScoutingStreams():
331 dstype = getDataScoutingTypeFromStream(flags.Input.TriggerStream)
332 # If writing a Data Scouting EDM format, only decode that ID
333 log.info(f'Configuring BS decoding/deserialisation of HLT result for \'{dstype}\' only')
334 ids_to_decode = [getDataScoutingResultID(dstype)]
335 id_to_deserialise = {dstype: getDataScoutingResultID(dstype)}
336 else:
337 # Set up to read the full HLT result ID
338 ids_to_decode = [getFullHLTResultID()]
339 id_to_deserialise = {'': getFullHLTResultID()}
340
341 # In addition, decode any available IDs. We need to check which streams were active in the file.
342 log.debug('Configuring BS decoding of all HLT results and deserialisation of full HLT')
343 partialHLT_streams = [
344 stream for stream in getDataScoutingStreams() if stream.split('_')[1] in flags.Input.ProcessingTags
345 ]
346 partialHLT_dstypes = [
347 getDataScoutingTypeFromStream(stream) for stream in partialHLT_streams
348 ]
349 partialHLT_dsids = [
350 getDataScoutingResultID(dstype) for dstype in partialHLT_dstypes
351 ]
352 log.debug(f'Configuring BS decoding and deserialisation of all HLT results: full HLT + {partialHLT_dstypes}')
353
354 ids_to_decode += partialHLT_dsids
355 # A bit ugly but avoid importing the actual dict to ensure we never modify it
356 id_to_deserialise.update({
357 dstype:dsid for dstype,dsid in zip(partialHLT_dstypes, partialHLT_dsids)
358 })
359
360 decoder = CompFactory.HLTResultMTByteStreamDecoderAlg(ModuleIdsToDecode=ids_to_decode)
361 acc.addSequence(seqAND("HLTDecodingSeq"))
362 acc.addEventAlgo( decoder, "HLTDecodingSeq")
363 for dstype, id in id_to_deserialise.items():
364 deserialiser = CompFactory.TriggerEDMDeserialiserAlg(
365 f"TrigDeserialiser{dstype}",
366 ModuleID=id,
367 )
368 # Full HLT result also has slimmed navigation summary
369 if dstype == '':
370 deserialiser.ExtraOutputs.add(('xAOD::TrigCompositeContainer' , 'StoreGateSvc+DummyForGapFiller'))
371 else:
372 deserialiser.SkipDuplicateRecords = True
373 deserialiser.PermitMissingModule = True
374 acc.addEventAlgo( deserialiser, "HLTDecodingSeq")
375
376 if dstype=='':
377 # Create empty EDM collections for types not created online
378 # Add output dependency on Navigation to enforce ordering
379 gapFiller = triggerEDMGapFillerCfg(
380 flags, edmSet=['BS'],
381 extraInputs=[('xAOD::TrigCompositeContainer' , 'StoreGateSvc+DummyForGapFiller')],
382 extraOutputs=[(
383 'xAOD::TrigCompositeContainer',
384 'StoreGateSvc+'+getRun3NavigationContainerFromInput(flags)
385 )])
386 else:
387 # Create empty EDM collections for types not created online
388 gapFiller = triggerEDMGapFillerCfg(flags, edmSet=[dstype])
389 acc.merge( gapFiller, "HLTDecodingSeq" )
390
391 log.debug("Configured HLT result BS decoding sequence")
392 return acc
393
394
395if __name__ == '__main__':
396 from AthenaConfiguration.MainServicesConfig import MainServicesCfg
397 from AthenaConfiguration.AllConfigFlags import initConfigFlags
398 import sys
399
400 flags = initConfigFlags()
401 args = flags.fillFromArgs()
402
403 if not args.filesInput:
404 from AthenaConfiguration.TestDefaults import defaultTestFiles
405 flags.Input.Files = defaultTestFiles.RAW_RUN3 # need to update this depending on EDMversion
406 flags.Exec.MaxEvents = 5
407 log.info('Checking setup for EDMVersion %d with default input files', flags.Trigger.EDMVersion)
408 if flags.Trigger.EDMVersion==1:
409 log.error('Run-1 reconstruction is no longer supported')
410 sys.exit(1)
411 elif flags.Trigger.EDMVersion==2:
412 flags.Input.Files = defaultTestFiles.RAW_RUN2
413 elif flags.Trigger.EDMVersion==3:
414 flags.Input.Files = defaultTestFiles.RAW_RUN3
415
416 from AthenaConfiguration.TestDefaults import defaultGeometryTags
417 flags.GeoModel.AtlasVersion = defaultGeometryTags.autoconfigure(flags)
418
419 flags.lock()
420
421 acc = MainServicesCfg(flags)
422 acc.merge( TriggerRecoCfg(flags) )
423 if log.getEffectiveLevel() <= logging.DEBUG:
424 acc.printConfig(withDetails=True)
425
426 sys.exit(acc.run().isFailure())
#define max(a, b)
Definition cfImp.cxx:41