ATLAS Offline Software
Loading...
Searching...
No Matches
L1CaloPhase1Monitoring.py
Go to the documentation of this file.
1#!/usr/bin/env athena
2# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3
4
10
11from AthenaCommon.Logging import logging
12from AthenaCommon.Logging import log as topLog
13topLog.setLevel(logging.WARNING) # default to suppressing all info logging except our own
14log = logging.getLogger('l1calo-ath-mon')
15log.setLevel(logging.INFO)
16
17from TrigT1CaloMonitoring.LVL1CaloMonitoringConfig import L1CaloMonitorCfgHelper
18L1CaloMonitorCfgHelper.embargoed = ["Expert/Efficiency/gFEX/MuonReferenceTrigger/SRpt_L1_gJ400p0ETA25"]#,"Expert/Sim/L1TopoAlgoMismatchRateVsLB","Expert/Sim/L1TopoMultiplicityMismatchRateVsLumi"]
19
20
21
22from AthenaConfiguration.ComponentFactory import CompFactory
23from AthenaConfiguration.AllConfigFlags import initConfigFlags
24from AthenaConfiguration.Enums import LHCPeriod,Format
25from AthenaCommon import Constants
26import os
27import ispy
28import re
29partition = ispy.IPCPartition(os.getenv("TDAQ_PARTITION","ATLAS"))
30
31flags = initConfigFlags()
32flags.Input.Files = [] # so that when no files given we can detect that
33
34# Note: The order in which all these flag defaults get set is very fragile
35# so don't reorder the setup of this flags stuff
36
37
38flags.Exec.OutputLevel = Constants.WARNING # by default make everything output at WARNING level
39flags.Exec.InfoMessageComponents = ["AthenaEventLoopMgr","AthenaHiveEventLoopMgr","THistSvc","PerfMonMTSvc","ApplicationMgr","AvalancheSchedulerSvc"] # Re-enable some info messaging though
40flags.Exec.PrintAlgsSequence = True # print the alg sequence at the start of the job (helpful to see what is scheduled)
41# flags.Exec.FPE = -2 # disable FPE auditing ... set to 0 to re-enable
42
43
44flags.GeoModel.Run = LHCPeriod.Run3 # needed for LArGMConfig - or can infer from above
45flags.Common.useOnlineLumi = True # needed for lumi-scaled monitoring, only have lumi in online DB at this time
46flags.DQ.doMonitoring = True # use this flag to turn on/off monitoring in this application
47flags.DQ.enableLumiAccess = False # in fact, we don't need lumi access for now ... this turns it all off
48flags.DQ.FileKey = "" if partition.isValid() else "EXPERT" # histsvc file "name" to record to - Rafal asked it to be blank @ P1 ... means monitoring.root will be empty
49flags.Output.HISTFileName = os.getenv("L1CALO_ATHENA_JOB_NAME","") + "monitoring.root" # control names of monitoring root file - ensure each online monitoring job gets a different filename to avoid collision between processes
50flags.DQ.useTrigger = False # don't do TrigDecisionTool in MonitorCfg helper methods
51flags.Trigger.L1.doCaloInputs = partition.isValid() # flag for saying if inputs should be decoded or not
52flags.Trigger.enableL1CaloPhase1 = True # used by this script to turn on/off the simulation
53flags.Trigger.enableL1MuonPhase1 = False # used by this script to turn on/off the l1 muon simulation
54# flags for rerunning simulation - on by default only in online environment
55flags.Trigger.L1.doCalo = partition.isValid()
56flags.Trigger.L1.doeFex = partition.isValid()
57flags.Trigger.L1.dojFex = partition.isValid()
58flags.Trigger.L1.dogFex = partition.isValid()
59flags.Trigger.L1.doTopo = partition.isValid()
60# if running online, override these with autoconfig values
61# will set things like the GlobalTag automatically
62if partition.isValid():
63 # must ensure doLVL1 and doHLT are False, otherwise will get ByteStreamCnvSvc conflicts (TrigByteStreamCnvSvc is setup, but EMon setup provides ByteStreamCnvSvc)
64 # see TriggerByteStreamConfig.py
65 flags.Trigger.doLVL1 = False
66 flags.Trigger.doHLT = False
67 from AthenaConfiguration.AutoConfigOnlineRecoFlags import autoConfigOnlineRecoFlags
68 autoConfigOnlineRecoFlags(flags, partition.name()) # sets things like projectName etc which would otherwise be inferred from input file
69else:
70 flags.Trigger.doLVL1 = True # set this just so that IOBDb.GlobalTag is autoconfigured based on release setup if running on RAW (autoconfig will take it from POOL file if running on that)
71#flags.IOVDb.GlobalTag = lambda s: "OFLCOND-MC23-SDR-RUN3-02" if s.Input.isMC else "CONDBR2-ES1PA-2022-07" #"CONDBR2-HLTP-2022-02"
72
73import sys
74if "--help" in sys.argv:
75 # remove unused flag categories to clean up help printout.
76 neededCats = ["DQ","Trigger","PerfMon"]
77 for cat in list(flags._dynaflags.keys()):
78 if cat not in neededCats: del flags._dynaflags[cat]
79
80# now parse
81
82parser = flags.getArgumentParser(epilog="""
83Extra flags are specified after a " -- " and the following are most relevant flags for this script:
84
85 Trigger.enableL1CaloPhase1 : turn on/off the offline simulation [default: True]
86 DQ.doMonitoring : turn on/off the monitoring [default: True]
87 Trigger.L1.doCaloInputs : controls input readout decoding and monitoring [default: False*]
88 Trigger.L1.doCalo : controls trex (legacy syst) monitoring [default: False]
89 Trigger.L1.doeFex : controls efex simulation and monitoring [default: False*]
90 Trigger.L1.dojFex : controls jfex simulation and monitoring [default: False*]
91 Trigger.L1.dogFex : controls gfex simulation and monitoring [default: False*]
92 Trigger.L1.doTopo : controls topo simulation and monitoring [default: False*] (from 2023 Onwards)
93 Trigger.L1.doGlobal : controls global simulation and monitoring [default: False]
94 DQ.useTrigger : controls if JetEfficiency monitoring alg is run or not [default: False]
95 PerfMon.doFullMonMT : print info about execution time of algorithms and memory use etc [default: False]
96 Trigger.triggerConfig : if you specifying this as "FILE:<filename>" the script will use that L1 json menu. [default: "DB" (takes menu from DB for data)]
97
98Note: If you do not specify any flags, then all the flags that are marked with a * will automatically become True
99
100E.g. to run just the jFex monitoring, without offline simulation, you can do:
101
102l1calo-ath-mon .... -- Trigger.enableL1CaloPhase1=False Trigger.L1.doCaloInputs=False Trigger.L1.doeFex=False Trigger.L1.dogFex=False
103
104To run with a plugin you can do e.g:
105
106l1calo-ath-mon PluginPackage/plugin.py --evtMax 10 ...
107
108Further notes: Run with "--evtMax 0" to print flags and ca config, and generate a hanConfig file.
109 Run with "--evtMax 1" to dump StoreGate contents after the first event
110
111""")
112import argparse
113#class combinedFormatter(parser.formatter_class,argparse.RawDescriptionHelpFormatter): pass
114parser.formatter_class = argparse.RawDescriptionHelpFormatter
115parser.add_argument('--runNumber',default=None,help="specify to select a run number")
116parser.add_argument('--lumiBlock',default=None,help="specify to select a lumiBlock")
117parser.add_argument('--evtNumber',default=None,nargs="+",type=int,help="specify to select an evtNumber")
118parser.add_argument('--stream',default="*",help="stream to lookup files in")
119parser.add_argument('--fexReadoutFilter',action='store_true',help="If specified, will skip events without fexReadout")
120parser.add_argument('--dbOverrides',default=None,nargs="+",type=str,help="specify overrides of COOL database folders in form <folder>=<dbPath> or <folder>:<tag>[=<dbPath>] to override a tag, example: /TRIGGER/L1Calo/V1/Calibration/EfexEnergyCalib=mytest.db ")
121parser.add_argument('--postConfig',default=[],nargs="+",type=str,help="specify component properties to apply at the end of the config. Can also specify in the flags section if start with 'cfg.' Use '--postHelp' option to explore the configurables and their properties")
122parser.add_argument('--postInclude',default=[],nargs="+",type=str,help="specify python files to call before configuration completes")
123parser.add_argument('--postHelp',default=None,nargs="*",help="Displays configurables and their properties")
124
125# divide args up into preHelp and postHelp ... will call fillFromArgs with just the help a second time after flag setting is done
126sys.argv = ["--help" if x=="-h" else x for x in sys.argv]
127preHelpArgs = sys.argv[0:sys.argv.index("--help")] if "--help" in sys.argv else sys.argv
128postHelpArgs = sys.argv[sys.argv.index("--help"):] if "--help" in sys.argv else []
129args,unknown_args = flags.fillFromArgs(parser=parser,return_unknown=True,listOfArgs=preHelpArgs[1:])
130# check for files in unknown_args list ... will assume are plugins
131# this is copied from Include.py ... seems if I try import it, I get CA behaviour blockage
132try:
133 optionsPathEnv = os.environ[ 'JOBOPTSEARCHPATH' ]
134except Exception:
135 optionsPathEnv = os.curdir
136optionsPath = re.split( ',|' + os.pathsep, optionsPathEnv )
137if '' in optionsPath:
138 optionsPath[ optionsPath.index( '' ) ] = str(os.curdir)
139for fn in unknown_args:
140 from AthenaCommon.Utils.unixtools import FindFile
141 name = FindFile( os.path.expanduser( os.path.expandvars( fn ) ), optionsPath, os.R_OK )
142 if not name: name = FindFile( os.path.basename( fn ), optionsPath, os.R_OK )
143 if name:
144 args.postInclude += [fn]
145 unknown_args.remove(fn)
146args.postConfig += [x[4:] for x in unknown_args if x.startswith("cfg.")]
147if any([not x.startswith("cfg.") for x in unknown_args]):
148 raise KeyError("Unknown flags: " + " ".join([x for x in unknown_args if not x.startswith("cfg.")]))
149
150# before doing any postInclude interactions, do the file setup...
151
152# check input files
153if len(flags.Input.Files)>0:
154 # check input files list for alias to default test files ... substituting them
155 from AthenaConfiguration.TestDefaults import defaultTestFiles
156 flags.Input.Files = [getattr(defaultTestFiles,f,f) for f in flags.Input.Files]
157 flags.Input.Files = [item for x in flags.Input.Files for item in (x if isinstance(x,list) else [x])] # flatten mix of str and list
158 # now also check for non-existent input files before continuing
159 for f in flags.Input.Files:
160 if not os.path.exists(f):
161 log.fatal(f"file '{f}' does not exist")
162 exit(-1)
163
164if args.runNumber is not None:
165 # todo: if an exact event number is provided, we can in theory use the event index and rucio to obtain a filename:
166 # e.g: event-lookup -D RAW "477048 3459682284"
167 # use GUID result to do:
168 # ~/getRucioLFNbyGUID.sh 264A4214-E922-EF11-AB28-B8CEF6444828
169 # gives a filename (last part): data24_13p6TeV.00477048.physics_Main.daq.RAW._lb0975._SFO-13._0001.data
170 from glob import glob
171 if args.lumiBlock is None: args.lumiBlock="*"
172 log.info(" ".join(("Looking up files in atlastier0 for run",args.runNumber,"lb =",args.lumiBlock)))
173 flags.Input.Files = []
174 for lb in args.lumiBlock.split(","):
175 if lb=="*":
176 tryStr = f"/eos/atlas/atlastier0/rucio/data*/{args.stream}/*{args.runNumber}/*RAW/*lb*.*"
177 else:
178 tryStr = f"/eos/atlas/atlastier0/rucio/data*/{args.stream}/*{args.runNumber}/*RAW/*lb{int(lb):04}.*"
179 log.info(" ".join(("Trying",tryStr)))
180 flags.Input.Files += glob(tryStr)
181 log.info(" ".join(("Found",str(len(flags.Input.Files)),"files")))
182
183standalone = False
184# require at least 1 input file if running offline, unless running config-generating mode ....
185if not flags.Common.isOnline and len(flags.Input.Files)==0:
186 if flags.Exec.MaxEvents==0:
187 # this test file is used for generating the han config file
188 flags.Input.Files = ["/eos/atlas/atlascerngroupdisk/det-l1calo/OfflineSoftware/TestFiles/data24_13p6TeV/data24_13p6TeV.00477048.physics_Main.daq.RAW._lb0821._SFO-20._0001.data"]
189 else:
190 if len(postHelpArgs): flags.fillFromArgs(listOfArgs=postHelpArgs)
191 log.fatal("Running in offline mode but no input files provided. Please specify with: --filesInput <file>")
192 from AthenaConfiguration.TestDefaults import defaultTestFiles
193 log.fatal("You can specify one of the default test files:" + ",".join([f for f in dir(defaultTestFiles) if f[0].isupper()]))
194 exit(-1)
195elif flags.Common.isOnline:
196 log.info("Running Online with Partition: "+partition.name())
197 # if the partition name is not set in the flags, run the autoconfig again
198 # this occurs when running the online monitoring config in offline environment for testing
199 if flags.Trigger.Online.partitionName == '':
200 # must ensure doLVL1 and doHLT are False, otherwise will get ByteStreamCnvSvc conflicts (TrigByteStreamCnvSvc is setup, but EMon setup provides ByteStreamCnvSvc)
201 # see TriggerByteStreamConfig.py
202 flags.Trigger.doLVL1 = False
203 flags.Trigger.doHLT = False
204 from AthenaConfiguration.AutoConfigOnlineRecoFlags import autoConfigOnlineRecoFlags
205 autoConfigOnlineRecoFlags(flags, partition.name())
206 standalone = (partition.name()!="ATLAS")
207 if standalone : log.info("Using local menu because partition is not ATLAS")
208 elif len(flags.Input.Files)==0 and partition.isValid():
209 # wait here for 2 minutes, to give LAr time to put fw info in the database
210 import time
211 log.info("Waiting 2 minutes for LATOME to get their databases in order")
212 time.sleep(120)
213
214
215if len(args.postInclude):
216 # call setup methods if any exist in the postIncludes
217 from AthenaCommon.Configurable import ConfigurableCABehavior
218 with ConfigurableCABehavior():
219 from AthenaCommon.Utils.unixtools import FindFile
220 import ast
221
222 def load_function(file_path, function_name):
223 with open(file_path, "r", encoding="utf-8") as f:
224 source = f.read()
225 tree = ast.parse(source, filename=file_path)
226 for node in tree.body:
227 if isinstance(node, ast.FunctionDef) and node.name == function_name:
228 # Create a module containing only this function
229 mod = ast.Module(body=[node], type_ignores=[])
230 # Compile it
231 code = compile(mod, filename=file_path, mode="exec")
232 namespace = {}
233 # Execute only the function definition
234 exec(code, namespace)
235 return namespace[function_name]
236 for fn in args.postInclude:
237 name = FindFile( os.path.expanduser( os.path.expandvars( fn ) ), optionsPath, os.R_OK )
238 if not name:
239 name = FindFile( os.path.basename( fn ), optionsPath, os.R_OK )
240 if not name: raise RuntimeError( 'plugin file %s can not be found' % fn )
241 func = load_function(name,"setup")
242 if func:
243 topLog.setLevel(logging.INFO) # take back to info level before doing postInclude setup
244 func(flags)
245 topLog.setLevel(logging.WARNING)
246
247if len(args.postInclude)==0 and not any([flags.Trigger.L1.doCalo,flags.Trigger.L1.doCaloInputs,flags.Trigger.L1.doeFex,flags.Trigger.L1.dojFex,flags.Trigger.L1.dogFex,flags.Trigger.L1.doTopo,flags.DQ.useTrigger]):
248 log.info("No steering flags specified and no postInclude, turning on all phase 1 systems (trex,efex,jfex,gfex,topo)")
249 flags.Trigger.L1.doCaloInputs = True # flag for saying if inputs should be decoded or not
250 flags.Trigger.L1.doCalo = True
251 flags.Trigger.L1.doeFex = True
252 flags.Trigger.L1.dojFex = True
253 flags.Trigger.L1.dogFex = True
254 flags.Trigger.L1.doTopo = True
255
256
257customMenuFile = ""
258if type(flags.Trigger.triggerConfig)==str and flags.Trigger.triggerConfig.startswith("FILE:"):
259 customMenuFile = flags.Trigger.triggerConfig.split(":",1)[-1]
260 flags.Trigger.triggerConfig="FILE"
261
262
263
264# if running on an input file, change the DQ environment, which will allow debug tree creation from monitoring algs
265if len(flags.Input.Files)>0:
266 flags.DQ.Environment = "user"
267 # triggerConfig should default to DB which is appropriate if running on data
268 # standalone if project tag is data_test of dataXX_calib
269 standalone = ((flags.Input.ProjectName == "data_test") or (re.match(r"data\d\d_calib", flags.Input.ProjectName)))
270 if standalone : print("Using local menu because project_name=",flags.Input.ProjectName)
271 if flags.Input.isMC : flags.Trigger.triggerConfig='FILE' # uses the generated L1Menu (see below)
272 elif flags.Trigger.triggerConfig=='INFILE':
273 # this happens with AOD data files, but this is incompatible with the setup of the LVL1ConfigSvc
274 flags.Trigger.triggerConfig="DB" # so force onto DB usage
275 # legacy monitoring doesn't work with MC, so disable that if running on mc
276 if flags.Input.isMC and flags.Trigger.L1.doCalo:
277 log.info("Disabling legacy monitoring because it doesn't work with MC")
278 flags.Trigger.L1.doCalo=False
279
280if standalone :
281 flags.Trigger.triggerConfig='FILE' #Uses generated L1Menu In online on input files
282
283
284if flags.Exec.MaxEvents == 0:
285 # in this mode, ensure all monitoring activated, so that generated han config is complete
286 flags.DQ.doMonitoring=True
287 flags.Trigger.L1.doCalo=True
288 flags.Trigger.L1.doCaloInputs=True
289 flags.Trigger.L1.doeFex=True
290 flags.Trigger.L1.dojFex=True
291 flags.Trigger.L1.dogFex=True
292 flags.Trigger.L1.doTopo=True
293 flags.DQ.useTrigger=True # enables JetEfficiency algorithms
294 flags.Exec.OutputLevel = Constants.INFO
295
296# due to https://gitlab.cern.ch/atlas/athena/-/merge_requests/65253 must now specify geomodel explicitly if cant take from input file, but can autoconfigure it based on LHCPeriod set above
297if flags.GeoModel.AtlasVersion is None:
298 from AthenaConfiguration.TestDefaults import defaultGeometryTags
299 flags.GeoModel.AtlasVersion = defaultGeometryTags.autoconfigure(flags)
300
301if flags.Trigger.triggerConfig=="FILE" and flags.Trigger.L1.doCalo:
302 # HLTConfgSvc fails to load if using a json file for the menu
303 # so disable the legacy monitoring which triggers that svc
304 log.warning("Cannot run Legacy sim/mon when using json l1 menu. Disabling")
305 flags.Trigger.L1.doCalo=False
306
307if (flags.Input.Format == Format.POOL): flags.Trigger.L1.doTopo = False #Deactivating L1Topo if Format is POOL
308if not flags.Trigger.L1.doTopo: flags.Trigger.L1.doMuon = False # don't do muons if not doing topo
309
310if flags.Trigger.enableL1CaloPhase1:
311 # add detector conditions flags required for rerunning simulation
312 # needs input files declared if offline, hence doing after parsing
313 from AthenaConfiguration.DetectorConfigFlags import setupDetectorsFromList
314 setupDetectorsFromList(flags,['LAr','Tile','MBTS'] + (['RPC','TGC','MDT'] if flags.Trigger.L1.doMuon else []),True)
315
316from AthenaConfiguration.MainServicesConfig import MainServicesCfg
317cfg = MainServicesCfg(flags)
318
319log.setLevel(logging.INFO)
320
321
322
323
324if len(postHelpArgs): flags.fillFromArgs(listOfArgs=postHelpArgs)
325
326flags.lock()
327if flags.Exec.MaxEvents == 0: flags.dump(evaluate=True)
328
329# if nothing enabled, exit out here
330if len(args.postInclude)==0 and not any([flags.Trigger.L1.doCaloInputs,flags.Trigger.L1.doCalo,flags.Trigger.L1.doeFex,flags.Trigger.L1.dojFex,flags.Trigger.L1.dogFex,flags.Trigger.L1.doTopo]):
331 log.fatal("You did not set any flags to specify what to run. ")
332 log.fatal("Please set at least one of the flags in Trigger.L1.(doCaloInputs, doCalo, doeFex, dojFex, dogFex, doTopo) ")
333 log.fatal("or use '--all' option to turn on everything (but that is slow)")
334 log.fatal("See --help for more info about the flags")
335 exit(1)
336
337if flags.Common.isOnline and len(flags.Input.Files)==0:
338 flags.dump(evaluate=True)
339 from ByteStreamEmonSvc.EmonByteStreamConfig import EmonByteStreamCfg
340 cfg.merge(EmonByteStreamCfg(flags)) # setup EmonSvc
341 bsSvc = cfg.getService("ByteStreamInputSvc")
342 bsSvc.Partition = partition.name()
343 bsSvc.Key = os.environ.get("L1CALO_PTIO_KEY", "REB" if partition.name()=="L1CaloStandalone" else "dcm") # set the Sampler Key Type name (default is SFI)
344 if partition.name()=="L1CaloSTF": bsSvc.Key = "SWROD"
345 bsSvc.KeyCount = int(os.environ.get("L1CALO_PTIO_KEY_COUNT","25"))
346 bsSvc.ISServer = "Histogramming" # IS server on which to create this provider
347 bsSvc.BufferSize = 10 # event buffer size for each sampler
348 bsSvc.UpdatePeriod = 30 # time in seconds between updating plots
349 bsSvc.Timeout = 240000 # timeout (not sure what this does)
350 bsSvc.PublishName = os.getenv("L1CALO_ATHENA_JOB_NAME","testing") # set name of this publisher as it will appear in IS (default is "l1calo-athenaHLT"; change to something sensible for testing)
351 bsSvc.StreamType = os.getenv("L1CALO_PTIO_STREAM_TYPE","physics") # name of the stream type (physics,express, etc.)
352 bsSvc.ExitOnPartitionShutdown = False
353 bsSvc.ClearHistograms = True # clear hists at start of new run
354 bsSvc.GroupName = "RecExOnline"
355 # name of the stream (Egamma,JetTauEtmiss,MinBias,Standby, etc.), this can be a colon(:) separated list of streams that use the 'streamLogic' to combine stream for 2016 HI run
356 bsSvc.StreamNames = os.getenv("L1CALO_PTIO_STREAM_NAME","L1Calo:Main:MinBias:MinBiasOverlay:UPC:EnhancedBias:ZeroBias:HardProbes:Standby:ALFACalib").split(":")
357 bsSvc.StreamLogic = os.getenv("L1CALO_PTIO_STREAM_LOGIC","Or") if partition.name() != "L1CaloStandalone" else "Ignore"
358 bsSvc.LVL1Names = [] # name of L1 items to select
359 bsSvc.LVL1Logic = "Ignore" # one of: Ignore, Or, And
360elif flags.Input.Format == Format.POOL:
361 log.info(f"Running Offline on {len(flags.Input.Files)} POOL files: {flags.Input.Files[0]} ...")
362 from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
363 cfg.merge(PoolReadCfg(flags))
364elif len(flags.Input.Files)>0:
365 log.info(f"Running Offline on {len(flags.Input.Files)} bytestream files: {flags.Input.Files[0]} ...")
366 #from ByteStreamCnvSvc.ByteStreamConfig import ByteStreamReadCfg
367 #TODO: Figure out why the above line causes CA conflict @ P1 if try to run on a RAW file there
368 from TriggerJobOpts.TriggerByteStreamConfig import ByteStreamReadCfg
369 cfg.merge(ByteStreamReadCfg(flags)) # configure reading bytestream
370
371# ensure histsvc is set up
372from AthenaMonitoring.AthMonitorCfgHelper import getDQTHistSvc
373cfg.merge(getDQTHistSvc(flags))
374
375# Create run3 L1 menu (needed for L1Calo EDMs)
376from TrigConfigSvc.TrigConfigSvcCfg import L1ConfigSvcCfg,generateL1Menu, createL1PrescalesFileFromMenu,getL1MenuFileName
377if flags.Trigger.triggerConfig=="FILE":
378 # for MC we set the TriggerConfig to "FILE" above, so must generate a menu for it to load (will be the release's menu)
379 menuFilename = getL1MenuFileName(flags)
380 if customMenuFile == "":
381 if os.path.exists(menuFilename): os.remove(menuFilename)
382 generateL1Menu(flags)
383 else:
384 # create a symlink to the custom file
385 import os,errno
386 try:
387 os.symlink(customMenuFile, menuFilename)
388 except OSError as e:
389 if e.errno == errno.EEXIST:
390 os.remove(menuFilename)
391 os.symlink(customMenuFile, menuFilename)
392 else:
393 raise e
394 menuFilename = customMenuFile
395 if os.path.exists(menuFilename):
396 log.info(f"Using L1Menu: {menuFilename}")
397 else:
398 log.fatal(f"L1Menu file does not exist: {menuFilename}")
399 exit(1)
400 createL1PrescalesFileFromMenu(flags)
401
402# Add L1 Config unless in inputless offline mode
403if not (not flags.Common.isOnline and len(flags.Input.Files)==0): cfg.merge(L1ConfigSvcCfg(flags))
404
405# -------- CHANGES GO BELOW ------------
406# setup the L1Calo software we want to monitor
407
408decoderTools = []
409
410if flags.Common.isOnline or (flags.Input.Format != Format.POOL and not flags.Input.isMC):
411 from L1CaloFEXByteStream.L1CaloFEXByteStreamConfig import eFexByteStreamToolCfg, jFexRoiByteStreamToolCfg, jFexInputByteStreamToolCfg, gFexByteStreamToolCfg, gFexInputByteStreamToolCfg
412 if flags.Trigger.L1.doeFex: decoderTools += [cfg.popToolsAndMerge(eFexByteStreamToolCfg(flags=flags,name='eFexBSDecoderTool',TOBs=flags.Trigger.L1.doeFex,xTOBs=flags.Trigger.L1.doeFex,decodeInputs=flags.Trigger.L1.doCaloInputs,multiSlice=True))]
413 if flags.Trigger.L1.dojFex: decoderTools += [cfg.popToolsAndMerge(jFexRoiByteStreamToolCfg(flags=flags,name="jFexBSDecoderTool",writeBS=False))]
414 if flags.Trigger.L1.dogFex: decoderTools += [cfg.popToolsAndMerge(gFexByteStreamToolCfg(flags=flags,name="gFexBSDecoderTool",writeBS=False))]
415 if flags.Trigger.L1.doTopo:
416 from L1TopoByteStream.L1TopoByteStreamConfig import L1TopoPhase1ByteStreamToolCfg
417 decoderTools += [cfg.popToolsAndMerge(L1TopoPhase1ByteStreamToolCfg(flags=flags,name="L1TopoBSDecoderTool",writeBS=False))]
418
419 if flags.Trigger.L1.doMuon:
420 from MuonConfig.MuonBytestreamDecodeConfig import RpcBytestreamDecodeCfg,TgcBytestreamDecodeCfg
421 cfg.merge(RpcBytestreamDecodeCfg(flags))
422 cfg.merge(TgcBytestreamDecodeCfg(flags))
423 from TrigT1ResultByteStream.TrigT1ResultByteStreamConfig import MuonRoIByteStreamToolCfg
424 decoderTools += [cfg.popToolsAndMerge(MuonRoIByteStreamToolCfg(flags, name="L1MuonBSDecoderTool", writeBS=False))]
425
426
427 if flags.Trigger.L1.doCaloInputs:
428 if flags.Trigger.L1.dojFex: decoderTools += [cfg.popToolsAndMerge(jFexInputByteStreamToolCfg(flags=flags,name='jFexInputBSDecoderTool',writeBS=False))]
429 if flags.Trigger.L1.dogFex: decoderTools += [cfg.popToolsAndMerge(gFexInputByteStreamToolCfg(flags=flags,name='gFexInputBSDecoderTool',writeBS=False))]
430
431 if len(decoderTools) > 0:
432 from TrigT1ResultByteStream.TrigT1ResultByteStreamMonitoringConfig import L1TriggerByteStreamDecoderMonitoringCfg
433 cfg.addEventAlgo(CompFactory.L1TriggerByteStreamDecoderAlg(
434 name="L1TriggerByteStreamDecoder",
435 OutputLevel=Constants.ERROR, # hides warnings about non-zero status codes in fragments ... will show up in hists
436 DecoderTools=decoderTools,
437 ByteStreamMetadataRHKey = '', # seems necessary @ P1 if trying to run on a raw file
438 MaybeMissingROBs= [id for tool in decoderTools for id in tool.ROBIDs ] if partition.name()!="ATLAS" or not flags.Common.isOnline else [], # allow missing ROBs away from online ATLAS partition
439 MonTool= cfg.popToolsAndMerge(L1TriggerByteStreamDecoderMonitoringCfg(flags,"L1TriggerByteStreamDecoder", decoderTools))
440 ),sequenceName='AthAlgSeq'
441 )
442
443# rerun sim if required
444if flags.Trigger.enableL1CaloPhase1:
445 from L1CaloFEXSim.L1CaloFEXSimCfg import L1CaloFEXSimCfg
446 # create a subsequence for the sim to live in; primarily keeps the config tidy
447 cfg.addSequence(CompFactory.AthSequencer("L1Sim",StopOverride=True),parentName="AthAlgSeq") # this matches the sequence name the helpers will create
448
449 # note to self ... could look into input key remapping to avoid conflict with sim from input:
450 # from SGComps.AddressRemappingConfig import InputRenameCfg
451 # acc.merge(InputRenameCfg('xAOD::TriggerTowerContainer', 'xAODTriggerTowers_rerun', 'xAODTriggerTowers'))
452 cfg.merge(L1CaloFEXSimCfg(flags,outputSuffix="_ReSim" if flags.Input.Format == Format.POOL and flags.Input.ProcessingTags != ['StreamRDO'] else ""),sequenceName="L1Sim")
453 # scheduling simulation of topo
454 if flags.Trigger.L1.doTopo:
455 from L1TopoSimulation.L1TopoSimulationConfig import L1TopoSimulationCfg
456 cfg.merge(L1TopoSimulationCfg(flags,readMuCTPI=True,doMonitoring=False),sequenceName="L1Sim") # monitoring scheduled separately below
457 # check there aren't any duplicates in L1sim that are already in the main sequence
458 for alg in cfg.getSequence("L1Sim").Members:
459 if alg.name in [a.name for a in cfg.getSequence("AthAlgSeq").Members]:
460 cfg.getSequence("L1Sim").Members.remove(alg)
461
462
463 # Phase II Global simulation...
464 if "doGlobal" in flags.Trigger.L1 and flags.Trigger.L1.doGlobal:
465 # we will create a subsequence just for globalsim too
466 cfg.addSequence(CompFactory.AthSequencer("L1GlobalSim",StopOverride=True),parentName="AthAlgSeq")
467 from GlobalSimulation.GlobalSimulationConfig import GlobalSimulationCfg
468 cfg.merge(GlobalSimulationCfg(flags),sequenceName="L1GlobalSim")
469
470 if flags.Trigger.L1.doeFex:
471 # print the algoVersions of the eFex from menu:
472 from TrigConfigSvc.TriggerConfigAccess import getL1MenuAccess
473 L1_menu = getL1MenuAccess(flags)
474 L1_menu.printSummary()
475 em_algoVersion = L1_menu.thresholdExtraInfo("eEM").get("algoVersion", 0)
476 tau_algoVersion = L1_menu.thresholdExtraInfo("eTAU").get("algoVersion", 0)
477 log.info(f"algoVersions: eEM: {em_algoVersion}, eTAU: {tau_algoVersion}")
478
479
480
481 # do otf masking:
482 # from IOVDbSvc.IOVDbSvcConfig import addFolders,addOverride
483 # #cfg.merge(addFolders(flags,"<db>sqlite://;schema=/afs/cern.ch/user/w/will/new_maskedSCs_run457976.db;dbname=CONDBR2</db> /LAR/BadChannels/NoisyChannelsSC",className="CondAttrListCollection")) # dmCorr from DB!
484 # cfg.merge(addFolders(flags,"/LAR/BadChannels/MaskedSC","LAR_ONL",tag="LARBadChannelsMaskedSC-RUN3-UPD1-00",className="CondAttrListCollection",extensible=False)) # when run online, need folder to be extensible to force reload each event
485 # cfg.addCondAlgo(CompFactory.LArBadChannelCondAlg(name="MaskedSCCondAlg",ReadKey="/LAR/BadChannels/MaskedSC",isSC=True,CablingKey="LArOnOffIdMapSC",WriteKey="LArMaskedSC"))
486 # # note to self, if need to flag extensible after loaded elsewhere, look at property: cfg.getService("IOVDbSvc").Folders ... extend relevant entry with "<extensible/>"
487 # print(cfg.getService("MessageSvc"))
488 # cfg.getService("MessageSvc").errorLimit = 0
489 #
490 # cfg.getEventAlgo("L1_eFexEmulatedTowers").LArBadChannelKey = "LArMaskedSC"
491
492if flags.Trigger.enableL1MuonPhase1:
493 # run L1 Muon simulation
494 cfg.addSequence(CompFactory.AthSequencer("L1MuonSim",StopOverride=True),parentName="AthAlgSeq")
495 from TriggerJobOpts.Lvl1MuonSimulationConfig import Lvl1MuonSimulationCfg
496 cfg.merge(Lvl1MuonSimulationCfg(flags), sequenceName='L1MuonSim')
497
498
499if flags.DQ.doMonitoring:
500 # create a subsequence for the sim to live in; primarily keeps the config tidy
501 cfg.addSequence(CompFactory.AthSequencer("L1Mon",StopOverride=True),parentName="AthAlgSeq") # this matches the sequence name the helpers will create
502 if flags.Trigger.L1.doCalo:
503 from TrigT1CaloMonitoring.PprMonitorAlgorithm import PprMonitoringConfig
504 cfg.merge(PprMonitoringConfig(flags),sequenceName="L1Mon")
505 from TrigT1CaloMonitoring.PPMSimBSMonitorAlgorithm import PPMSimBSMonitoringConfig
506 cfg.merge(PPMSimBSMonitoringConfig(flags),sequenceName="L1Mon")
507 from TrigT1CaloMonitoring.OverviewMonitorAlgorithm import OverviewMonitoringConfig
508 cfg.merge(OverviewMonitoringConfig(flags),sequenceName="L1Mon")
509 # CPM was disabled for run 480893 onwards, so stop monitoring that part
510 # could have used detectorMask to determine if CPM is disabled, but will just assume it here
511 OverviewMonAlg = cfg.getEventAlgo("OverviewMonAlg")
512 OverviewMonAlg.CPMErrorLocation = ""
513 OverviewMonAlg.CPMMismatchLocation = ""
514
515 if flags.Trigger.L1.doeFex:
516 from TrigT1CaloMonitoring.EfexMonitorAlgorithm import EfexMonitoringConfig
517 cfg.merge(EfexMonitoringConfig(flags),sequenceName="L1Mon")
518 EfexMonAlg = cfg.getEventAlgo('EfexMonAlg')
519 # do we need next lines??
520 EfexMonAlg.eFexEMTobKeyList = ['L1_eEMRoI', 'L1_eEMxRoI'] # default is just L1_eEMRoI
521 EfexMonAlg.eFexTauTobKeyList = ['L1_eTauRoI', 'L1_eTauxRoI']
522 # Adjust eFEX containers to be monitored to also monitor the sim RoI unless running on raw without simulation
523 if flags.Input.Format == Format.POOL or flags.Trigger.enableL1CaloPhase1:
524 for l in [EfexMonAlg.eFexEMTobKeyList,EfexMonAlg.eFexTauTobKeyList]: l += [x + ("_ReSim" if flags.Input.Format == Format.POOL and flags.Trigger.enableL1CaloPhase1 else "Sim") for x in l ]
525 # monitoring of simulation vs hardware
526 if not flags.Input.isMC and flags.Trigger.enableL1CaloPhase1:
527 from TrigT1CaloMonitoring.EfexSimMonitorAlgorithm import EfexSimMonitoringConfig
528 cfg.merge(EfexSimMonitoringConfig(flags),sequenceName="L1Mon")
529 # EfexSimMonitorAlgorithm = cfg.getEventAlgo('EfexSimMonAlg')
530 # and now book the histograms that depend on the containers
531 from TrigT1CaloMonitoring.EfexMonitorAlgorithm import EfexMonitoringHistConfig
532 cfg.merge(EfexMonitoringHistConfig(flags,EfexMonAlg),sequenceName="L1Mon")
533
534 if flags.Trigger.L1.dojFex:
535 from TrigT1CaloMonitoring.JfexMonitorAlgorithm import JfexMonitoringConfig
536 cfg.merge(JfexMonitoringConfig(flags),sequenceName="L1Mon")
537 if not flags.Input.isMC and flags.Trigger.enableL1CaloPhase1:
538 from TrigT1CaloMonitoring.JfexSimMonitorAlgorithm import JfexSimMonitoringConfig
539 cfg.merge(JfexSimMonitoringConfig(flags),sequenceName="L1Mon")
540 if flags.Trigger.L1.dogFex:
541 from TrigT1CaloMonitoring.GfexMonitorAlgorithm import GfexMonitoringConfig
542 cfg.merge(GfexMonitoringConfig(flags),sequenceName="L1Mon")
543 if not flags.Input.isMC and flags.Trigger.enableL1CaloPhase1:
544 from TrigT1CaloMonitoring.GfexSimMonitorAlgorithm import GfexSimMonitoringConfig
545 cfg.merge(GfexSimMonitoringConfig(flags),sequenceName="L1Mon")
546 # generally can't include efficiency monitoring because requires too many things we don't have
547 # but b.c. alg requires TrigDecisionTool, we activate it if DQ.useTrigger explicitly set
548 if flags.DQ.useTrigger:
549 from TrigT1CaloMonitoring.JetEfficiencyMonitorAlgorithm import JetEfficiencyMonitoringConfig
550 cfg.merge(JetEfficiencyMonitoringConfig(flags),sequenceName="L1Mon")
551
552 if flags.Trigger.L1.doTopo:
553 from L1TopoOnlineMonitoring.L1TopoOnlineMonitoringConfig import Phase1TopoMonitoringCfg
554 cfg.merge(Phase1TopoMonitoringCfg(flags))
555
556 # input data monitoring
557 if flags.Trigger.L1.doCaloInputs and not flags.Input.isMC:
558 from TrigT1CaloMonitoring.EfexInputMonitorAlgorithm import EfexInputMonitoringConfig
559 if flags.Trigger.L1.doeFex: cfg.merge(EfexInputMonitoringConfig(flags),sequenceName="L1Mon")
560 from TrigT1CaloMonitoring.JfexInputMonitorAlgorithm import JfexInputMonitoringConfig
561 if flags.Trigger.L1.dojFex: cfg.merge(JfexInputMonitoringConfig(flags),sequenceName="L1Mon")
562 from TrigT1CaloMonitoring.GfexInputMonitorAlgorithm import GfexInputMonitoringConfig
563 if flags.Trigger.L1.dogFex: cfg.merge(GfexInputMonitoringConfig(flags),sequenceName="L1Mon")
564
565mainSeq = "AthAllAlgSeq"
566if args.fexReadoutFilter:
567 # want to take existing AthAllSeqSeq and move it inside a new sequence
568 topSeq = cfg.getSequence("AthAlgEvtSeq")
569 algSeq = cfg.getSequence(mainSeq)
570 mainSeq = "New" + mainSeq
571 # topSeq has three sub-sequencers ... preserve first and last
572 topSeq.Members = [topSeq.Members[0],CompFactory.AthSequencer(mainSeq),topSeq.Members[-1]]
573 cfg.addEventAlgo(CompFactory.L1IDFilterAlgorithm(),sequenceName=mainSeq)
574 cfg.getSequence(mainSeq).Members += [algSeq]
575
576if args.evtNumber is not None:
577 print("filtering events",args.evtNumber)
578 # similar adjustment with an event filter
579 topSeq = cfg.getSequence("AthAlgEvtSeq")
580 algSeq = cfg.getSequence(mainSeq)
581 mainSeq = "New" + mainSeq
582 # topSeq has three sub-sequencers ... preserve first and last
583 topSeq.Members = [topSeq.Members[0],CompFactory.AthSequencer(mainSeq),topSeq.Members[-1]]
584 cfg.addEventAlgo(CompFactory.EventNumberFilterAlgorithm("EvtNumberFilter",EventNumbers=args.evtNumber),sequenceName=mainSeq)
585 cfg.getSequence(mainSeq).Members += [algSeq]
586
587from PerfMonComps.PerfMonCompsConfig import PerfMonMTSvcCfg
588cfg.merge( PerfMonMTSvcCfg(flags) )
589
590from AthenaConfiguration.Utils import setupLoggingLevels
591setupLoggingLevels(flags,cfg)
592
593if any([s.name=="AthenaEventLoopMgr" for s in cfg.getServices()]): cfg.getService("AthenaEventLoopMgr").IntervalInSeconds = 30
594if any([s.name=="AthenaHiveEventLoopMgr" for s in cfg.getServices()]): cfg.getService("AthenaHiveEventLoopMgr").EventPrintoutInterval = 100
595if any([s.name=="AvalancheSchedulerSvc" for s in cfg.getServices()]): cfg.getService("AvalancheSchedulerSvc").ShowDataDependencies=True
596
597# need to override a folder tag for LAr while testing v6 firmware...
598if not flags.Input.isMC:
599 from LArConditionsCommon.LArRunFormat import getLArDTInfoForRun
600 runinfo = getLArDTInfoForRun(flags.Input.RunNumbers[0], connstring="COOLONL_LAR/CONDBR2")
601 if runinfo.FWversion()==6:
602 # need a dbOverride ... add it
603 if args.dbOverrides is None: args.dbOverrides = []
604 args.dbOverrides += ["/LAR/Identifier/LatomeMapping:LARIdentifierLatomeMapping-fw6"]
605
606
607
608if type(args.dbOverrides)==list:
609 from IOVDbSvc.IOVDbSvcConfig import addOverride
610 #examples:
611 #cfg.merge( addOverride(flags, folder="/TRIGGER/L1Calo/V1/Calibration/EfexEnergyCalib", db="sqlite://;schema=mytest.db;dbname=CONDBR2",tag="" ) )
612 #cfg.merge( addOverride(flags, folder="/TRIGGER/L1Calo/V1/Calibration/EfexNoiseCuts", db="sqlite://;schema=/afs/cern.ch/user/w/will/calib.sqlite;dbname=L1CALO",tag="" ) )
613 for override in args.dbOverrides:
614 folderName,dbPath = override.split("=",1) if "=" in override else (override,"")
615 if folderName == "": raise ValueError("Cannot parse dbOverride: " + override)
616 db = ""
617 if dbPath != "":
618 if ";dbname=" not in dbPath: dbPath += ";dbname=CONDBR2"
619 dbPath,dbInst = dbPath.split(";dbname=")
620 if not os.path.exists(dbPath): raise ValueError("dbOverride file doesn't exist: " + dbPath)
621 db = f"sqlite://;schema={dbPath};dbname={dbInst}"
622 tag = ""
623 if ":" in folderName:
624 folderName,tag = folderName.split(":",1)
625 if folderName[0] != "/": folderName = "/TRIGGER/L1Calo/V1/Calibration/" + folderName
626 log.info(" ".join(("Overriding COOL folder=",folderName,"db=",db,"tag=",tag)))
627 if db=="":
628 cfg.merge( addOverride(flags,folder=folderName,tag=tag))
629 else:
630 cfg.merge( addOverride(flags,folder=folderName,db=db,tag=tag))
631
632
633# configure output AOD if requested
634# don't set this up if running in inputless mode (which some plugins use for unusual input jobs like text files)
635if flags.Output.AODFileName != "" and len(flags.Input.Files)>0:
636 def addEDM(edmType, edmName):
637 if edmName.endswith("Sim") and flags.Input.Format == Format.POOL: edmName = edmName.replace("Sim","_ReSim")
638 auxType = edmType.replace('Container','AuxContainer')
639 return [f'{edmType}#{edmName}', f'{auxType}#{edmName}Aux.']
640
641 outputEDM = []
642
643 if flags.Trigger.L1.doeFex:
644 outputEDM += addEDM('xAOD::eFexEMRoIContainer' , "L1_eEMRoI")
645 outputEDM += addEDM('xAOD::eFexEMRoIContainer' , "L1_eEMRoISim")
646 outputEDM += addEDM('xAOD::eFexEMRoIContainer' , "L1_eEMxRoI")
647 outputEDM += addEDM('xAOD::eFexEMRoIContainer' , "L1_eEMxRoISim")
648
649 outputEDM += addEDM('xAOD::eFexTauRoIContainer' , "L1_eTauRoI")
650 outputEDM += addEDM('xAOD::eFexTauRoIContainer' , "L1_eTauRoISim")
651 outputEDM += addEDM('xAOD::eFexTauRoIContainer' , "L1_eTauxRoI")
652 outputEDM += addEDM('xAOD::eFexTauRoIContainer' , "L1_eTauxRoISim")
653
654 if flags.Trigger.L1.dojFex:
655 outputEDM += addEDM('xAOD::jFexTowerContainer' , "L1_jFexDataTowers")
656 outputEDM += addEDM('xAOD::jFexTowerContainer' , "L1_jFexEmulatedTowers")
657 outputEDM += addEDM('xAOD::jFexSRJetRoIContainer', 'L1_jFexSRJetRoISim')
658 outputEDM += addEDM('xAOD::jFexLRJetRoIContainer', 'L1_jFexLRJetRoISim')
659 outputEDM += addEDM('xAOD::jFexTauRoIContainer' , 'L1_jFexTauRoISim' )
660 outputEDM += addEDM('xAOD::jFexFwdElRoIContainer', 'L1_jFexFwdElRoISim')
661 outputEDM += addEDM('xAOD::jFexSumETRoIContainer', 'L1_jFexSumETRoISim')
662 outputEDM += addEDM('xAOD::jFexMETRoIContainer' , 'L1_jFexMETRoISim' )
663 outputEDM += addEDM('xAOD::jFexSRJetRoIContainer', 'L1_jFexSRJetRoI')
664 outputEDM += addEDM('xAOD::jFexLRJetRoIContainer', 'L1_jFexLRJetRoI')
665 outputEDM += addEDM('xAOD::jFexTauRoIContainer' , 'L1_jFexTauRoI' )
666 outputEDM += addEDM('xAOD::jFexFwdElRoIContainer', 'L1_jFexFwdElRoI')
667 outputEDM += addEDM('xAOD::jFexSumETRoIContainer', 'L1_jFexSumETRoI')
668 outputEDM += addEDM('xAOD::jFexMETRoIContainer' , 'L1_jFexMETRoI' )
669
670 outputEDM += addEDM('xAOD::jFexSRJetRoIContainer', 'L1_jFexSRJetxRoI')
671 outputEDM += addEDM('xAOD::jFexLRJetRoIContainer', 'L1_jFexLRJetxRoI')
672 outputEDM += addEDM('xAOD::jFexTauRoIContainer' , 'L1_jFexTauxRoI' )
673 outputEDM += addEDM('xAOD::jFexFwdElRoIContainer', 'L1_jFexFwdElxRoI')
674 outputEDM += addEDM('xAOD::jFexSumETRoIContainer', 'L1_jFexSumETxRoI')
675 outputEDM += addEDM('xAOD::jFexMETRoIContainer' , 'L1_jFexMETxRoI' )
676
677 if flags.Trigger.L1.dogFex:
678 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMETComponentsJwoj')
679 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMETComponentsJwojSim')
680 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMHTComponentsJwoj')
681 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMHTComponentsJwojSim')
682 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMSTComponentsJwoj')
683 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMSTComponentsJwojSim')
684 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gScalarEJwoj')
685 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gScalarEJwojSim')
686 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gScalarENoiseCutSim')
687 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gScalarERmsSim')
688
689 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexLRJetRoI')
690 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexLRJetRoISim')
691 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexSRJetRoI')
692 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexSRJetRoISim')
693 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexRhoRoI')
694 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexRhoRoISim')
695
696
697
698 from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
699 cfg.merge(OutputStreamCfg(flags, 'AOD', ItemList=outputEDM, takeItemsFromInput=True))
700 from xAODMetaDataCnv.InfileMetaDataConfig import SetupMetaDataForStreamCfg
701 cfg.merge(SetupMetaDataForStreamCfg(flags, 'AOD'))
702
703# configure RAW output if requested
704if flags.Output.BSFileName != "":
705 from TrigT1ResultByteStream.TrigT1ResultByteStreamConfig import L1TriggerByteStreamEncoderCfg
706 cfg.merge(L1TriggerByteStreamEncoderCfg(flags))
707
708 # create A TrigCompositeContainer with the things we want to write out
709 algo = CompFactory.L1TriggerResultMaker("OutputBSTCCMaker",
710 MuRoIKeys=[],
711 eFexEMRoIKeys=[], eFexTauRoIKeys=[],
712 jFexFwdElRoIKeys=[], jFexTauRoIKeys = [],
713 jFexSRJetRoIKeys = [], jFexLRJetRoIKeys = [],
714 gFexSRJetRoIKeys = [], gFexLRJetRoIKeys = [],
715 cTauRoIKey = "", cjTauLinkKey = "", ThresholdPatternTools= [],
716 CTPKey = "",
717 L1TriggerResultWHKey = "OutputBSTCC")
718 # since we dont create TrigDecision objects, dont set those trigger bits in the bytestream
719 cfg.getService("ByteStreamCnvSvc").FillTriggerBits=False
720 if flags.Trigger.L1.doeFex:
721 algo.eFexEMRoIKeys = ["L1_eEMRoI","L1_eEMxRoI"] # will write these containers
722 algo.eFexTauRoIKeys = ["L1_eTauRoI","L1_eTauxRoI"]
723
724 if flags.Trigger.L1.dojFex:
725 algo.jFexSRJetRoIKeys = ["L1_jFexSRJetRoI"]
726 algo.jFexLRJetRoIKeys = ["L1_jFexLRJetRoI"]
727 algo.jFexTauRoIKeys = ["L1_jFexTauRoI"]
728 algo.jFexFwdElRoIKeys = ["L1_jFexFwdElRoI"]
729
730 if flags.Trigger.L1.dogFex:
731 algo.gFexSRJetRoIKeys = ["L1_gFexSRJetRoI"]
732 algo.gFexLRJetRoIKeys = ["L1_gFexLRJetRoI"]
733 algo.gScalarEJwojKeys = ["L1_gScalarEJwoj"]
734 algo.gMETComponentsJwojKeys = ["L1_gMETComponentsJwoj"]
735
736 cfg.addEventAlgo(algo)
737 from ByteStreamCnvSvc.ByteStreamConfig import ByteStreamWriteCfg
738 write = ByteStreamWriteCfg(flags, ["xAOD::TrigCompositeContainer#OutputBSTCC"])
739 cfg.merge(write)
740
741if "MuonAlignmentCondAlg" in [a.name for a in cfg.getCondAlgos()]: cfg.getCondAlgo("MuonAlignmentCondAlg").OutputLevel=Constants.ERROR # this alg produces warnings every time, silence it!
742
743
744if flags.Trigger.L1.doeFex and (args.evtNumber is not None):
745 # when debugging individual events, add the eFex event dumper to the job
746 cfg.addEventAlgo(CompFactory.LVL1.eFexEventDumper(TowersKey="L1_eFexDataTowers",EMRoIKey="L1_eEMRoI",TauRoIKey="L1_eTauRoI"))
747
748# example of adding user algorithm
749# cfg.addEventAlgo(CompFactory.AnotherPackageAlg(),sequenceName="AthAlgSeq")
750
751from AthenaCommon.Include import include
752from AthenaCommon.Configurable import ConfigurableCABehavior
753with ConfigurableCABehavior():
754 for inc in args.postInclude:
755 try:
756 topLog.setLevel(logging.INFO) # take back to info level before doing postInclude
757 include(inc)
758 topLog.setLevel(logging.WARNING)
759 except Exception as e:
760 import traceback
761 print(f"Exception from {inc}")
762 tb = e.__traceback__
763
764 # Skip frames until we reach a particular file
765 while tb is not None:
766 if tb.tb_frame.f_code.co_filename.endswith(inc):
767 break
768 tb = tb.tb_next
769
770 traceback.print_exception(type(e), e, tb)
771 exit(1)
772
773for conf in args.postConfig:
774 compName,propNameAndVal=conf.split(".",1)
775 propName,propVal=propNameAndVal.split("=",1)
776 applied = False
777 from collections import defaultdict
778 availableComps = defaultdict(list)
779 for comp in [c for c in cfg._allComponents()]+cfg.getServices():
780 availableComps[comp.getType()] += [comp.getName()]
781 if comp.getName()==compName or comp.getType()==compName or comp.toStringProperty()==compName:
782 applied = True
783 try:
784 log.info("Setting "+compName+" property: "+propNameAndVal)
785 exec(f"comp.{propNameAndVal}")
786 except AttributeError as e:
787 log.fatal("Unknown property of " + compName +" : " + propNameAndVal)
788 log.fatal("See next line for available properties:")
789 print(comp)
790 raise e
791 break
792 if not applied:
793 print("Available comps:")
794 for k,v in availableComps.items():
795 print(k,":",*v,sep="\n\t")
796 raise ValueError(f"postConfig {conf} had no effect ... typo? See list above of available components")
797
798if args.postHelp is not None:
799 from collections import defaultdict
800 availableComps = defaultdict(list)
801 for comp in [c for c in cfg._allComponents()]+cfg.getServices():
802 availableComps[comp.getType()] += [comp.getName()]
803 print("Available comps:")
804 for k,v in availableComps.items():
805 print("",k,":",", ".join(v))
806 exit(0)
807
808# -------- CHANGES GO ABOVE ------------
809
810if flags.Exec.MaxEvents==0: cfg.printConfig(withDetails = True, summariseProps = True, printDefaults = True)
811log.info( " ".join(("Configured Services:",*[svc.name for svc in cfg.getServices()])) )
812#print("Configured EventAlgos:",*[alg.name for alg in cfg.getEventAlgos()])
813#print("Configured CondAlgos:",*[alg.name for alg in cfg.getCondAlgos()])
814
815if flags.Exec.MaxEvents==1:
816 # special debugging mode
817 cfg.getService("StoreGateSvc").Dump=True
818 cfg.getService("DetectorStore").Dump=True
819
820# ensure printout level is low enough if dumping
821if cfg.getService("StoreGateSvc").Dump:
822 cfg.getService("StoreGateSvc").OutputLevel=3
823if cfg.getService("DetectorStore").Dump:
824 cfg.getService("DetectorStore").OutputLevel=3
825
826if args.interactive:
827 from AthenaConfiguration.ComponentAccumulator import startInteractive
828 oldLevel = int(cfg._msg.getEffectiveLevel()) # need effectivelevel to account for inheriting
829 cfg._msg.setLevel(logging.INFO) # reverting to info level to ease interactive
830 print("\n\nEntering interactive configuration mode. You can explore and edit the cfg object. Ctrl+D to configure application and move to pre-initialize step")
831 startInteractive(locals()|{"self":cfg})
832 cfg._msg.setLevel(oldLevel)
833 # force writing the history file so that if job fails we still get our history
834 import readline, os
835 readline.write_history_file(os.path.expanduser( '~/.athena.history' ))
836
837if flags.Exec.MaxEvents==0:
838 # create a han config file if running in config-only mode
839 # command used to generate official config:
840 # athena TrigT1CaloMonitoring/L1CaloPhase1Monitoring.py --evtMax 0
841 from TrigT1CaloMonitoring.LVL1CaloMonitoringConfig import L1CaloMonitorCfgHelper
842 L1CaloMonitorCfgHelper.printHanConfig()
843 cfg._wasMerged = True # prevents spurious error message showing up about cfg that wasn't used
844 exit(0)
845
846if cfg.run().isFailure():
847 exit(1)
void print(char *figname, TCanvas *c1)
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
load_function(file_path, function_name)