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-2025 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('L1CaloPhase1Monitoring.py')
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","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
53# flags for rerunning simulation - on by default only in online environment
54flags.Trigger.L1.doCalo = partition.isValid()
55flags.Trigger.L1.doeFex = partition.isValid()
56flags.Trigger.L1.dojFex = partition.isValid()
57flags.Trigger.L1.dogFex = partition.isValid()
58flags.Trigger.L1.doTopo = partition.isValid()
59# if running online, override these with autoconfig values
60# will set things like the GlobalTag automatically
61if partition.isValid():
62 # must ensure doLVL1 and doHLT are False, otherwise will get ByteStreamCnvSvc conflicts (TrigByteStreamCnvSvc is setup, but EMon setup provides ByteStreamCnvSvc)
63 # see TriggerByteStreamConfig.py
64 flags.Trigger.doLVL1 = False
65 flags.Trigger.doHLT = False
66 from AthenaConfiguration.AutoConfigOnlineRecoFlags import autoConfigOnlineRecoFlags
67 autoConfigOnlineRecoFlags(flags, partition.name()) # sets things like projectName etc which would otherwise be inferred from input file
68else:
69 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)
70#flags.IOVDb.GlobalTag = lambda s: "OFLCOND-MC23-SDR-RUN3-02" if s.Input.isMC else "CONDBR2-ES1PA-2022-07" #"CONDBR2-HLTP-2022-02"
71
72# now parse
73
74parser = flags.getArgumentParser(epilog="""
75Extra flags are specified after a " -- " and the following are most relevant flags for this script:
76
77 Trigger.enableL1CaloPhase1 : turn on/off the offline simulation [default: True]
78 DQ.doMonitoring : turn on/off the monitoring [default: True]
79 Trigger.L1.doCaloInputs : controls input readout decoding and monitoring [default: False*]
80 Trigger.L1.doCalo : controls trex (legacy syst) monitoring [default: False]
81 Trigger.L1.doeFex : controls efex simulation and monitoring [default: False*]
82 Trigger.L1.dojFex : controls jfex simulation and monitoring [default: False*]
83 Trigger.L1.dogFex : controls gfex simulation and monitoring [default: False*]
84 Trigger.L1.doTopo : controls topo simulation and monitoring [default: False*] (from 2023 Onwards)
85 DQ.useTrigger : controls if JetEfficiency monitoring alg is run or not [default: False]
86 PerfMon.doFullMonMT : print info about execution time of algorithms and memory use etc [default: False]
87 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)]
88
89Note: If you do not specify any flags, then all the flags that are marked with a * will automatically become True
90
91E.g. to run just the jFex monitoring, without offline simulation, you can do:
92
93athena TrigT1CaloMonitoring/L1CalPhase1Monitoring.py .... -- Trigger.enableL1CaloPhase1=False Trigger.L1.doCaloInputs=False Trigger.L1.doeFex=False Trigger.L1.dogFex=False
94
95Further notes: Run with "--evtMax 0" to print flags and ca config, and generate a hanConfig file.
96 Run with "--evtMax 1" to dump StoreGate contents after the first event
97
98""")
99import argparse
100#class combinedFormatter(parser.formatter_class,argparse.RawDescriptionHelpFormatter): pass
101parser.formatter_class = argparse.RawDescriptionHelpFormatter
102parser.add_argument('--runNumber',default=None,help="specify to select a run number")
103parser.add_argument('--lumiBlock',default=None,help="specify to select a lumiBlock")
104parser.add_argument('--evtNumber',default=None,nargs="+",type=int,help="specify to select an evtNumber")
105parser.add_argument('--stream',default="*",help="stream to lookup files in")
106parser.add_argument('--fexReadoutFilter',action='store_true',help="If specified, will skip events without fexReadout")
107parser.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 ")
108parser.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.'")
109args,unknown_args = flags.fillFromArgs(parser=parser,return_unknown=True)
110args.postConfig += [x[4:] for x in unknown_args if x.startswith("cfg.")]
111if any([not x.startswith("cfg.") for x in unknown_args]):
112 raise KeyError("Unknown flags: " + " ".join([x for x in unknown_args if not x.startswith("cfg.")]))
113if 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]):
114 log.info("No steering flags specified, turning on phase 1 sim+monitoring (trex,efex,jfex,gfex,topo)")
115 flags.Trigger.L1.doCaloInputs = True # flag for saying if inputs should be decoded or not
116 flags.Trigger.L1.doCalo = True
117 flags.Trigger.L1.doeFex = True
118 flags.Trigger.L1.dojFex = True
119 flags.Trigger.L1.dogFex = True
120 flags.Trigger.L1.doTopo = True
121if args.runNumber is not None:
122 # todo: if an exact event number is provided, we can in theory use the event index and rucio to obtain a filename:
123 # e.g: event-lookup -D RAW "477048 3459682284"
124 # use GUID result to do:
125 # ~/getRucioLFNbyGUID.sh 264A4214-E922-EF11-AB28-B8CEF6444828
126 # gives a filename (last part): data24_13p6TeV.00477048.physics_Main.daq.RAW._lb0975._SFO-13._0001.data
127 from glob import glob
128 if args.lumiBlock is None: args.lumiBlock="*"
129 log.info(" ".join(("Looking up files in atlastier0 for run",args.runNumber,"lb =",args.lumiBlock)))
130 flags.Input.Files = []
131 for lb in args.lumiBlock.split(","):
132 if lb=="*":
133 tryStr = f"/eos/atlas/atlastier0/rucio/data*/{args.stream}/*{args.runNumber}/*RAW/*lb*.*"
134 else:
135 tryStr = f"/eos/atlas/atlastier0/rucio/data*/{args.stream}/*{args.runNumber}/*RAW/*lb{int(lb):04}.*"
136 log.info(" ".join(("Trying",tryStr)))
137 flags.Input.Files += glob(tryStr)
138 log.info(" ".join(("Found",str(len(flags.Input.Files)),"files")))
139
140customMenuFile = ""
141if flags.Trigger.triggerConfig.startswith("FILE:"):
142 customMenuFile = flags.Trigger.triggerConfig.split(":",1)[-1]
143 flags.Trigger.triggerConfig="FILE"
144
145standalone = False
146# require at least 1 input file if running offline, unless running config-generating mode ....
147if not flags.Common.isOnline and len(flags.Input.Files)==0:
148 if flags.Exec.MaxEvents==0:
149 # this test file is used for generating the han config file
150 flags.Input.Files = ["/eos/atlas/atlascerngroupdisk/det-l1calo/OfflineSoftware/TestFiles/data24_13p6TeV/data24_13p6TeV.00477048.physics_Main.daq.RAW._lb0821._SFO-20._0001.data"]
151 else:
152 log.fatal("Running in offline mode but no input files provided")
153 exit(1)
154elif flags.Common.isOnline:
155 log.info("Running Online with Partition: "+partition.name())
156 # if the partition name is not set in the flags, run the autoconfig again
157 # this occurs when running the online monitoring config in offline environment for testing
158 if flags.Trigger.Online.partitionName == '':
159 # must ensure doLVL1 and doHLT are False, otherwise will get ByteStreamCnvSvc conflicts (TrigByteStreamCnvSvc is setup, but EMon setup provides ByteStreamCnvSvc)
160 # see TriggerByteStreamConfig.py
161 flags.Trigger.doLVL1 = False
162 flags.Trigger.doHLT = False
163 from AthenaConfiguration.AutoConfigOnlineRecoFlags import autoConfigOnlineRecoFlags
164 autoConfigOnlineRecoFlags(flags, partition.name())
165 standalone = (partition.name()!="ATLAS")
166 if standalone : log.info("Using local menu because partition is not ATLAS")
167 elif len(flags.Input.Files)==0 and partition.isValid():
168 # wait here for 2 minutes, to give LAr time to put fw info in the database
169 import time
170 log.info("Waiting 2 minutes for LATOME to get their databases in order")
171 time.sleep(120)
172
173# if running on an input file, change the DQ environment, which will allow debug tree creation from monitoring algs
174if len(flags.Input.Files)>0:
175 flags.DQ.Environment = "user"
176 # triggerConfig should default to DB which is appropriate if running on data
177 # standalone if project tag is data_test of dataXX_calib
178 standalone = ((flags.Input.ProjectName == "data_test") or (re.match(r"data\d\d_calib", flags.Input.ProjectName)))
179 if standalone : print("Using local menu because project_name=",flags.Input.ProjectName)
180 if flags.Input.isMC : flags.Trigger.triggerConfig='FILE' # uses the generated L1Menu (see below)
181 elif flags.Trigger.triggerConfig=='INFILE':
182 # this happens with AOD data files, but this is incompatible with the setup of the LVL1ConfigSvc
183 flags.Trigger.triggerConfig="DB" # so force onto DB usage
184 # legacy monitoring doesn't work with MC, so disable that if running on mc
185 if flags.Input.isMC and flags.Trigger.L1.doCalo:
186 log.info("Disabling legacy monitoring because it doesn't work with MC")
187 flags.Trigger.L1.doCalo=False
188
189if standalone :
190 flags.Trigger.triggerConfig='FILE' #Uses generated L1Menu In online on input files
191
192
193if flags.Exec.MaxEvents == 0:
194 # in this mode, ensure all monitoring activated, so that generated han config is complete
195 flags.DQ.doMonitoring=True
196 flags.Trigger.L1.doCalo=True
197 flags.Trigger.L1.doCaloInputs=True
198 flags.Trigger.L1.doeFex=True
199 flags.Trigger.L1.dojFex=True
200 flags.Trigger.L1.dogFex=True
201 flags.Trigger.L1.doTopo=True
202 flags.DQ.useTrigger=True # enables JetEfficiency algorithms
203 flags.Exec.OutputLevel = Constants.INFO
204
205# 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
206if flags.GeoModel.AtlasVersion is None:
207 from AthenaConfiguration.TestDefaults import defaultGeometryTags
208 flags.GeoModel.AtlasVersion = defaultGeometryTags.autoconfigure(flags)
209
210if flags.Trigger.triggerConfig=="FILE" and flags.Trigger.L1.doCalo:
211 # HLTConfgSvc fails to load if using a json file for the menu
212 # so disable the legacy monitoring which triggers that svc
213 log.warning("Cannot run Legacy sim/mon when using json l1 menu. Disabling")
214 flags.Trigger.L1.doCalo=False
215
216if (flags.Input.Format == Format.POOL): flags.Trigger.L1.doTopo = False #Deactivating L1Topo if Format is POOL
217if not flags.Trigger.L1.doTopo: flags.Trigger.L1.doMuon = False # don't do muons if not doing topo
218
219if flags.Trigger.enableL1CaloPhase1:
220 # add detector conditions flags required for rerunning simulation
221 # needs input files declared if offline, hence doing after parsing
222 from AthenaConfiguration.DetectorConfigFlags import setupDetectorsFromList
223 setupDetectorsFromList(flags,['LAr','Tile','MBTS'] + (['RPC','TGC','MDT'] if flags.Trigger.L1.doMuon else []),True)
224
225from AthenaConfiguration.MainServicesConfig import MainServicesCfg
226cfg = MainServicesCfg(flags)
227
228log.setLevel(logging.INFO)
229
230flags.lock()
231if flags.Exec.MaxEvents == 0: flags.dump(evaluate=True)
232
233# if nothing enabled, exit out here
234if 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]):
235 log.fatal("You did not set any flags to specify what to run. ")
236 log.fatal("Please set at least one of the flags in Trigger.L1.(doCaloInputs, doCalo, doeFex, dojFex, dogFex, doTopo) ")
237 log.fatal("or use '--all' option to turn on everything (but that is slow)")
238 log.fatal("See --help for more info about the flags")
239 exit(1)
240
241if flags.Common.isOnline and len(flags.Input.Files)==0:
242 flags.dump(evaluate=True)
243 from ByteStreamEmonSvc.EmonByteStreamConfig import EmonByteStreamCfg
244 cfg.merge(EmonByteStreamCfg(flags)) # setup EmonSvc
245 bsSvc = cfg.getService("ByteStreamInputSvc")
246 bsSvc.Partition = partition.name()
247 bsSvc.Key = os.environ.get("L1CALO_PTIO_KEY", "REB" if partition.name()=="L1CaloStandalone" else "dcm") # set the Sampler Key Type name (default is SFI)
248 if partition.name()=="L1CaloSTF": bsSvc.Key = "SWROD"
249 bsSvc.KeyCount = int(os.environ.get("L1CALO_PTIO_KEY_COUNT","25"))
250 bsSvc.ISServer = "Histogramming" # IS server on which to create this provider
251 bsSvc.BufferSize = 10 # event buffer size for each sampler
252 bsSvc.UpdatePeriod = 30 # time in seconds between updating plots
253 bsSvc.Timeout = 240000 # timeout (not sure what this does)
254 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)
255 bsSvc.StreamType = os.getenv("L1CALO_PTIO_STREAM_TYPE","physics") # name of the stream type (physics,express, etc.)
256 bsSvc.ExitOnPartitionShutdown = False
257 bsSvc.ClearHistograms = True # clear hists at start of new run
258 bsSvc.GroupName = "RecExOnline"
259 # 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
260 bsSvc.StreamNames = os.getenv("L1CALO_PTIO_STREAM_NAME","L1Calo:Main:MinBias:MinBiasOverlay:UPC:EnhancedBias:ZeroBias:HardProbes:Standby:ALFACalib").split(":")
261 bsSvc.StreamLogic = os.getenv("L1CALO_PTIO_STREAM_LOGIC","Or") if partition.name() != "L1CaloStandalone" else "Ignore"
262 bsSvc.LVL1Names = [] # name of L1 items to select
263 bsSvc.LVL1Logic = "Ignore" # one of: Ignore, Or, And
264elif flags.Input.Format == Format.POOL:
265 log.info(f"Running Offline on {len(flags.Input.Files)} POOL files")
266 from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
267 cfg.merge(PoolReadCfg(flags))
268else:
269 log.info(f"Running Offline on {len(flags.Input.Files)} bytestream files")
270 #from ByteStreamCnvSvc.ByteStreamConfig import ByteStreamReadCfg
271 #TODO: Figure out why the above line causes CA conflict @ P1 if try to run on a RAW file there
272 from TriggerJobOpts.TriggerByteStreamConfig import ByteStreamReadCfg
273 cfg.merge(ByteStreamReadCfg(flags)) # configure reading bytestream
274
275# ensure histsvc is set up
276from AthenaMonitoring.AthMonitorCfgHelper import getDQTHistSvc
277cfg.merge(getDQTHistSvc(flags))
278
279# Create run3 L1 menu (needed for L1Calo EDMs)
280from TrigConfigSvc.TrigConfigSvcCfg import L1ConfigSvcCfg,generateL1Menu, createL1PrescalesFileFromMenu,getL1MenuFileName
281if flags.Trigger.triggerConfig=="FILE":
282 # for MC we set the TriggerConfig to "FILE" above, so must generate a menu for it to load (will be the release's menu)
283 menuFilename = getL1MenuFileName(flags)
284 if customMenuFile == "":
285 if os.path.exists(menuFilename): os.remove(menuFilename)
286 generateL1Menu(flags)
287 else:
288 # create a symlink to the custom file
289 import os,errno
290 try:
291 os.symlink(customMenuFile, menuFilename)
292 except OSError as e:
293 if e.errno == errno.EEXIST:
294 os.remove(menuFilename)
295 os.symlink(customMenuFile, menuFilename)
296 else:
297 raise e
298 menuFilename = customMenuFile
299 if os.path.exists(menuFilename):
300 log.info(f"Using L1Menu: {menuFilename}")
301 else:
302 log.fatal(f"L1Menu file does not exist: {menuFilename}")
303 exit(1)
304 createL1PrescalesFileFromMenu(flags)
305cfg.merge(L1ConfigSvcCfg(flags))
306
307# -------- CHANGES GO BELOW ------------
308# setup the L1Calo software we want to monitor
309
310decoderTools = []
311
312if flags.Common.isOnline or (flags.Input.Format != Format.POOL and not flags.Input.isMC):
313 from L1CaloFEXByteStream.L1CaloFEXByteStreamConfig import eFexByteStreamToolCfg, jFexRoiByteStreamToolCfg, jFexInputByteStreamToolCfg, gFexByteStreamToolCfg, gFexInputByteStreamToolCfg
314 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))]
315 if flags.Trigger.L1.dojFex: decoderTools += [cfg.popToolsAndMerge(jFexRoiByteStreamToolCfg(flags=flags,name="jFexBSDecoderTool",writeBS=False))]
316 if flags.Trigger.L1.dogFex: decoderTools += [cfg.popToolsAndMerge(gFexByteStreamToolCfg(flags=flags,name="gFexBSDecoderTool",writeBS=False))]
317
318 if flags.Trigger.L1.doMuon:
319 from MuonConfig.MuonBytestreamDecodeConfig import RpcBytestreamDecodeCfg,TgcBytestreamDecodeCfg
320 cfg.merge(RpcBytestreamDecodeCfg(flags))
321 cfg.merge(TgcBytestreamDecodeCfg(flags))
322 from TrigT1ResultByteStream.TrigT1ResultByteStreamConfig import MuonRoIByteStreamToolCfg
323 decoderTools += [cfg.popToolsAndMerge(MuonRoIByteStreamToolCfg(flags, name="L1MuonBSDecoderTool", writeBS=False))]
324
325
326 if flags.Trigger.L1.doCaloInputs:
327 if flags.Trigger.L1.dojFex: decoderTools += [cfg.popToolsAndMerge(jFexInputByteStreamToolCfg(flags=flags,name='jFexInputBSDecoderTool',writeBS=False))]
328 if flags.Trigger.L1.dogFex: decoderTools += [cfg.popToolsAndMerge(gFexInputByteStreamToolCfg(flags=flags,name='gFexInputBSDecoderTool',writeBS=False))]
329
330 if len(decoderTools) > 0:
331 from TrigT1ResultByteStream.TrigT1ResultByteStreamMonitoringConfig import L1TriggerByteStreamDecoderMonitoringCfg
332 cfg.addEventAlgo(CompFactory.L1TriggerByteStreamDecoderAlg(
333 name="L1TriggerByteStreamDecoder",
334 OutputLevel=Constants.ERROR, # hides warnings about non-zero status codes in fragments ... will show up in hists
335 DecoderTools=decoderTools,
336 ByteStreamMetadataRHKey = '', # seems necessary @ P1 if trying to run on a raw file
337 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
338 MonTool= cfg.popToolsAndMerge(L1TriggerByteStreamDecoderMonitoringCfg(flags,"L1TriggerByteStreamDecoder", decoderTools))
339 ),sequenceName='AthAlgSeq'
340 )
341
342# rerun sim if required
343if flags.Trigger.enableL1CaloPhase1:
344 from L1CaloFEXSim.L1CaloFEXSimCfg import L1CaloFEXSimCfg
345 # note to self ... could look into input key remapping to avoid conflict with sim from input:
346 # from SGComps.AddressRemappingConfig import InputRenameCfg
347 # acc.merge(InputRenameCfg('xAOD::TriggerTowerContainer', 'xAODTriggerTowers_rerun', 'xAODTriggerTowers'))
348 cfg.merge(L1CaloFEXSimCfg(flags,outputSuffix="_ReSim" if flags.Input.Format == Format.POOL else ""))
349
350 if flags.Trigger.L1.doeFex:
351 # print the algoVersions of the eFex from menu:
352 from TrigConfigSvc.TriggerConfigAccess import getL1MenuAccess
353 L1_menu = getL1MenuAccess(flags)
354 L1_menu.printSummary()
355 em_algoVersion = L1_menu.thresholdExtraInfo("eEM").get("algoVersion", 0)
356 tau_algoVersion = L1_menu.thresholdExtraInfo("eTAU").get("algoVersion", 0)
357 log.info(f"algoVersions: eEM: {em_algoVersion}, eTAU: {tau_algoVersion}")
358
359
360 # scheduling simulation of topo
361 if flags.Trigger.L1.doTopo:
362 from L1TopoSimulation.L1TopoSimulationConfig import L1TopoSimulationCfg
363 cfg.merge(L1TopoSimulationCfg(flags,readMuCTPI=True,doMonitoring=False)) # monitoring scheduled separately below
364
365 # do otf masking:
366 # from IOVDbSvc.IOVDbSvcConfig import addFolders,addOverride
367 # #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!
368 # 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
369 # cfg.addCondAlgo(CompFactory.LArBadChannelCondAlg(name="MaskedSCCondAlg",ReadKey="/LAR/BadChannels/MaskedSC",isSC=True,CablingKey="LArOnOffIdMapSC",WriteKey="LArMaskedSC"))
370 # # note to self, if need to flag extensible after loaded elsewhere, look at property: cfg.getService("IOVDbSvc").Folders ... extend relevant entry with "<extensible/>"
371 # print(cfg.getService("MessageSvc"))
372 # cfg.getService("MessageSvc").errorLimit = 0
373 #
374 # cfg.getEventAlgo("L1_eFexEmulatedTowers").LArBadChannelKey = "LArMaskedSC"
375
376
377
378if flags.DQ.doMonitoring:
379 if flags.Trigger.L1.doCalo:
380 from TrigT1CaloMonitoring.PprMonitorAlgorithm import PprMonitoringConfig
381 cfg.merge(PprMonitoringConfig(flags))
382 from TrigT1CaloMonitoring.PPMSimBSMonitorAlgorithm import PPMSimBSMonitoringConfig
383 cfg.merge(PPMSimBSMonitoringConfig(flags))
384 from TrigT1CaloMonitoring.OverviewMonitorAlgorithm import OverviewMonitoringConfig
385 cfg.merge(OverviewMonitoringConfig(flags))
386 # CPM was disabled for run 480893 onwards, so stop monitoring that part
387 # could have used detectorMask to determine if CPM is disabled, but will just assume it here
388 OverviewMonAlg = cfg.getEventAlgo("OverviewMonAlg")
389 OverviewMonAlg.CPMErrorLocation = ""
390 OverviewMonAlg.CPMMismatchLocation = ""
391
392 if flags.Trigger.L1.doeFex:
393 from TrigT1CaloMonitoring.EfexMonitorAlgorithm import EfexMonitoringConfig
394 cfg.merge(EfexMonitoringConfig(flags))
395 EfexMonAlg = cfg.getEventAlgo('EfexMonAlg')
396 # do we need next lines??
397 EfexMonAlg.eFexEMTobKeyList = ['L1_eEMRoI', 'L1_eEMxRoI'] # default is just L1_eEMRoI
398 EfexMonAlg.eFexTauTobKeyList = ['L1_eTauRoI', 'L1_eTauxRoI']
399 # Adjust eFEX containers to be monitored to also monitor the sim RoI unless running on raw without simulation
400 if flags.Input.Format == Format.POOL or flags.Trigger.enableL1CaloPhase1:
401 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 ]
402 # monitoring of simulation vs hardware
403 if not flags.Input.isMC and flags.Trigger.enableL1CaloPhase1:
404 from TrigT1CaloMonitoring.EfexSimMonitorAlgorithm import EfexSimMonitoringConfig
405 cfg.merge(EfexSimMonitoringConfig(flags))
406 # EfexSimMonitorAlgorithm = cfg.getEventAlgo('EfexSimMonAlg')
407 # and now book the histograms that depend on the containers
408 from TrigT1CaloMonitoring.EfexMonitorAlgorithm import EfexMonitoringHistConfig
409 cfg.merge(EfexMonitoringHistConfig(flags,EfexMonAlg))
410
411 if flags.Trigger.L1.dojFex:
412 from TrigT1CaloMonitoring.JfexMonitorAlgorithm import JfexMonitoringConfig
413 cfg.merge(JfexMonitoringConfig(flags))
414 if not flags.Input.isMC and flags.Trigger.enableL1CaloPhase1:
415 from TrigT1CaloMonitoring.JfexSimMonitorAlgorithm import JfexSimMonitoringConfig
416 cfg.merge(JfexSimMonitoringConfig(flags))
417 if flags.Trigger.L1.dogFex:
418 from TrigT1CaloMonitoring.GfexMonitorAlgorithm import GfexMonitoringConfig
419 cfg.merge(GfexMonitoringConfig(flags))
420 if not flags.Input.isMC and flags.Trigger.enableL1CaloPhase1:
421 from TrigT1CaloMonitoring.GfexSimMonitorAlgorithm import GfexSimMonitoringConfig
422 cfg.merge(GfexSimMonitoringConfig(flags))
423 # generally can't include efficiency monitoring because requires too many things we don't have
424 # but b.c. alg requires TrigDecisionTool, we activate it if DQ.useTrigger explicitly set
425 if flags.DQ.useTrigger:
426 from TrigT1CaloMonitoring.JetEfficiencyMonitorAlgorithm import JetEfficiencyMonitoringConfig
427 cfg.merge(JetEfficiencyMonitoringConfig(flags))
428
429 if flags.Trigger.L1.doTopo:
430 from L1TopoOnlineMonitoring.L1TopoOnlineMonitoringConfig import Phase1TopoMonitoringCfg
431 cfg.merge(Phase1TopoMonitoringCfg(flags))
432
433 # input data monitoring
434 if flags.Trigger.L1.doCaloInputs and not flags.Input.isMC:
435 from TrigT1CaloMonitoring.EfexInputMonitorAlgorithm import EfexInputMonitoringConfig
436 if flags.Trigger.L1.doeFex: cfg.merge(EfexInputMonitoringConfig(flags))
437 from TrigT1CaloMonitoring.JfexInputMonitorAlgorithm import JfexInputMonitoringConfig
438 if flags.Trigger.L1.dojFex: cfg.merge(JfexInputMonitoringConfig(flags))
439 from TrigT1CaloMonitoring.GfexInputMonitorAlgorithm import GfexInputMonitoringConfig
440 if flags.Trigger.L1.dogFex: cfg.merge(GfexInputMonitoringConfig(flags))
441
442mainSeq = "AthAllAlgSeq"
443if args.fexReadoutFilter:
444 # want to take existing AthAllSeqSeq and move it inside a new sequence
445 topSeq = cfg.getSequence("AthAlgEvtSeq")
446 algSeq = cfg.getSequence(mainSeq)
447 mainSeq = "New" + mainSeq
448 # topSeq has three sub-sequencers ... preserve first and last
449 topSeq.Members = [topSeq.Members[0],CompFactory.AthSequencer(mainSeq),topSeq.Members[-1]]
450 cfg.addEventAlgo(CompFactory.L1IDFilterAlgorithm(),sequenceName=mainSeq)
451 cfg.getSequence(mainSeq).Members += [algSeq]
452
453if args.evtNumber is not None:
454 print("filtering events",args.evtNumber)
455 # similar adjustment with an event filter
456 topSeq = cfg.getSequence("AthAlgEvtSeq")
457 algSeq = cfg.getSequence(mainSeq)
458 mainSeq = "New" + mainSeq
459 # topSeq has three sub-sequencers ... preserve first and last
460 topSeq.Members = [topSeq.Members[0],CompFactory.AthSequencer(mainSeq),topSeq.Members[-1]]
461 cfg.addEventAlgo(CompFactory.EventNumberFilterAlgorithm("EvtNumberFilter",EventNumbers=args.evtNumber),sequenceName=mainSeq)
462 cfg.getSequence(mainSeq).Members += [algSeq]
463
464from PerfMonComps.PerfMonCompsConfig import PerfMonMTSvcCfg
465cfg.merge( PerfMonMTSvcCfg(flags) )
466
467from AthenaConfiguration.Utils import setupLoggingLevels
468setupLoggingLevels(flags,cfg)
469
470if any([s.name=="AthenaEventLoopMgr" for s in cfg.getServices()]): cfg.getService("AthenaEventLoopMgr").IntervalInSeconds = 30
471if any([s.name=="AvalancheSchedulerSvc" for s in cfg.getServices()]):
472 cfg.getService("AvalancheSchedulerSvc").ShowDataDependencies=True
473
474# need to override a folder tag for LAr while testing v6 firmware...
475if not flags.Input.isMC:
476 from LArConditionsCommon.LArRunFormat import getLArDTInfoForRun
477 runinfo = getLArDTInfoForRun(flags.Input.RunNumbers[0], connstring="COOLONL_LAR/CONDBR2")
478 if runinfo.FWversion()==6:
479 # need a dbOverride ... add it
480 if args.dbOverrides is None: args.dbOverrides = []
481 args.dbOverrides += ["/LAR/Identifier/LatomeMapping:LARIdentifierLatomeMapping-fw6"]
482
483
484
485if type(args.dbOverrides)==list:
486 from IOVDbSvc.IOVDbSvcConfig import addOverride
487 #examples:
488 #cfg.merge( addOverride(flags, folder="/TRIGGER/L1Calo/V1/Calibration/EfexEnergyCalib", db="sqlite://;schema=mytest.db;dbname=CONDBR2",tag="" ) )
489 #cfg.merge( addOverride(flags, folder="/TRIGGER/L1Calo/V1/Calibration/EfexNoiseCuts", db="sqlite://;schema=/afs/cern.ch/user/w/will/calib.sqlite;dbname=L1CALO",tag="" ) )
490 for override in args.dbOverrides:
491 folderName,dbPath = override.split("=",1) if "=" in override else (override,"")
492 if folderName == "": raise ValueError("Cannot parse dbOverride: " + override)
493 db = ""
494 if dbPath != "":
495 if ";dbname=" not in dbPath: dbPath += ";dbname=CONDBR2"
496 dbPath,dbInst = dbPath.split(";dbname=")
497 if not os.path.exists(dbPath): raise ValueError("dbOverride file doesn't exist: " + dbPath)
498 db = f"sqlite://;schema={dbPath};dbname={dbInst}"
499 tag = ""
500 if ":" in folderName:
501 folderName,tag = folderName.split(":",1)
502 if folderName[0] != "/": folderName = "/TRIGGER/L1Calo/V1/Calibration/" + folderName
503 log.info(" ".join(("Overriding COOL folder=",folderName,"db=",db,"tag=",tag)))
504 if db=="":
505 cfg.merge( addOverride(flags,folder=folderName,tag=tag))
506 else:
507 cfg.merge( addOverride(flags,folder=folderName,db=db,tag=tag))
508
509
510# configure output AOD if requested
511if flags.Output.AODFileName != "":
512 def addEDM(edmType, edmName):
513 if edmName.endswith("Sim") and flags.Input.Format == Format.POOL: edmName = edmName.replace("Sim","_ReSim")
514 auxType = edmType.replace('Container','AuxContainer')
515 return [f'{edmType}#{edmName}', f'{auxType}#{edmName}Aux.']
516
517 outputEDM = []
518
519 if flags.Trigger.L1.doeFex:
520 outputEDM += addEDM('xAOD::eFexEMRoIContainer' , "L1_eEMRoI")
521 outputEDM += addEDM('xAOD::eFexEMRoIContainer' , "L1_eEMRoISim")
522 outputEDM += addEDM('xAOD::eFexEMRoIContainer' , "L1_eEMxRoI")
523 outputEDM += addEDM('xAOD::eFexEMRoIContainer' , "L1_eEMxRoISim")
524
525 outputEDM += addEDM('xAOD::eFexTauRoIContainer' , "L1_eTauRoI")
526 outputEDM += addEDM('xAOD::eFexTauRoIContainer' , "L1_eTauRoISim")
527 outputEDM += addEDM('xAOD::eFexTauRoIContainer' , "L1_eTauxRoI")
528 outputEDM += addEDM('xAOD::eFexTauRoIContainer' , "L1_eTauxRoISim")
529
530 if flags.Trigger.L1.dojFex:
531 outputEDM += addEDM('xAOD::jFexTowerContainer' , "L1_jFexDataTowers")
532 outputEDM += addEDM('xAOD::jFexTowerContainer' , "L1_jFexEmulatedTowers")
533 outputEDM += addEDM('xAOD::jFexSRJetRoIContainer', 'L1_jFexSRJetRoISim')
534 outputEDM += addEDM('xAOD::jFexLRJetRoIContainer', 'L1_jFexLRJetRoISim')
535 outputEDM += addEDM('xAOD::jFexTauRoIContainer' , 'L1_jFexTauRoISim' )
536 outputEDM += addEDM('xAOD::jFexFwdElRoIContainer', 'L1_jFexFwdElRoISim')
537 outputEDM += addEDM('xAOD::jFexSumETRoIContainer', 'L1_jFexSumETRoISim')
538 outputEDM += addEDM('xAOD::jFexMETRoIContainer' , 'L1_jFexMETRoISim' )
539 outputEDM += addEDM('xAOD::jFexSRJetRoIContainer', 'L1_jFexSRJetRoI')
540 outputEDM += addEDM('xAOD::jFexLRJetRoIContainer', 'L1_jFexLRJetRoI')
541 outputEDM += addEDM('xAOD::jFexTauRoIContainer' , 'L1_jFexTauRoI' )
542 outputEDM += addEDM('xAOD::jFexFwdElRoIContainer', 'L1_jFexFwdElRoI')
543 outputEDM += addEDM('xAOD::jFexSumETRoIContainer', 'L1_jFexSumETRoI')
544 outputEDM += addEDM('xAOD::jFexMETRoIContainer' , 'L1_jFexMETRoI' )
545
546 outputEDM += addEDM('xAOD::jFexSRJetRoIContainer', 'L1_jFexSRJetxRoI')
547 outputEDM += addEDM('xAOD::jFexLRJetRoIContainer', 'L1_jFexLRJetxRoI')
548 outputEDM += addEDM('xAOD::jFexTauRoIContainer' , 'L1_jFexTauxRoI' )
549 outputEDM += addEDM('xAOD::jFexFwdElRoIContainer', 'L1_jFexFwdElxRoI')
550 outputEDM += addEDM('xAOD::jFexSumETRoIContainer', 'L1_jFexSumETxRoI')
551 outputEDM += addEDM('xAOD::jFexMETRoIContainer' , 'L1_jFexMETxRoI' )
552
553 if flags.Trigger.L1.dogFex:
554 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMETComponentsJwoj')
555 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMETComponentsJwojSim')
556 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMHTComponentsJwoj')
557 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMHTComponentsJwojSim')
558 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMSTComponentsJwoj')
559 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gMSTComponentsJwojSim')
560 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gScalarEJwoj')
561 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gScalarEJwojSim')
562 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gScalarENoiseCutSim')
563 outputEDM += addEDM('xAOD::gFexGlobalRoIContainer','L1_gScalarERmsSim')
564
565 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexLRJetRoI')
566 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexLRJetRoISim')
567 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexSRJetRoI')
568 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexSRJetRoISim')
569 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexRhoRoI')
570 outputEDM += addEDM('xAOD::gFexJetRoIContainer','L1_gFexRhoRoISim')
571
572
573
574 from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
575 cfg.merge(OutputStreamCfg(flags, 'AOD', ItemList=outputEDM, takeItemsFromInput=True))
576 from xAODMetaDataCnv.InfileMetaDataConfig import SetupMetaDataForStreamCfg
577 cfg.merge(SetupMetaDataForStreamCfg(flags, 'AOD'))
578
579
580if "MuonAlignmentCondAlg" in [a.name for a in cfg.getCondAlgos()]: cfg.getCondAlgo("MuonAlignmentCondAlg").OutputLevel=Constants.ERROR # this alg produces warnings every time, silence it!
581
582
583if flags.Trigger.L1.doeFex and (args.evtNumber is not None):
584 # when debugging individual events, add the eFex event dumper to the job
585 cfg.addEventAlgo(CompFactory.LVL1.eFexEventDumper(TowersKey="L1_eFexDataTowers",EMRoIKey="L1_eEMRoI",TauRoIKey="L1_eTauRoI"))
586
587# example of adding user algorithm
588# cfg.addEventAlgo(CompFactory.AnotherPackageAlg(),sequenceName="AthAlgSeq")
589
590for conf in args.postConfig:
591 compName,propNameAndVal=conf.split(".",1)
592 propName,propVal=propNameAndVal.split("=",1)
593 applied = False
594 from collections import defaultdict
595 availableComps = defaultdict(list)
596 for comp in [c for c in cfg._allComponents()]+cfg.getServices():
597 availableComps[comp.getType()] += [comp.getName()]
598 if comp.getName()==compName or comp.getType()==compName or comp.toStringProperty()==compName:
599 applied = True
600 try:
601 log.info("Setting "+compName+" property: "+propNameAndVal)
602 exec(f"comp.{propNameAndVal}")
603 except AttributeError as e:
604 log.fatal("Unknown property of " + compName +" : " + propNameAndVal)
605 log.fatal("See next line for available properties:")
606 print(comp)
607 raise e
608 break
609 if not applied:
610 print("Available comps:")
611 for k,v in availableComps.items():
612 print(k,":",*v,sep="\n\t")
613 raise ValueError(f"postConfig {conf} had no effect ... typo? See list above of available components")
614
615# -------- CHANGES GO ABOVE ------------
616
617if flags.Exec.MaxEvents==0: cfg.printConfig(withDetails = True, summariseProps = True, printDefaults = True)
618log.info( " ".join(("Configured Services:",*[svc.name for svc in cfg.getServices()])) )
619#print("Configured EventAlgos:",*[alg.name for alg in cfg.getEventAlgos()])
620#print("Configured CondAlgos:",*[alg.name for alg in cfg.getCondAlgos()])
621
622if flags.Exec.MaxEvents==1:
623 # special debugging mode
624 cfg.getService("StoreGateSvc").Dump=True
625 cfg.getService("DetectorStore").Dump=True
626
627# ensure printout level is low enough if dumping
628if cfg.getService("StoreGateSvc").Dump:
629 cfg.getService("StoreGateSvc").OutputLevel=3
630if cfg.getService("DetectorStore").Dump:
631 cfg.getService("DetectorStore").OutputLevel=3
632
633if flags.Exec.MaxEvents==0:
634 # create a han config file if running in config-only mode
635 # command used to generate official config:
636 # athena TrigT1CaloMonitoring/L1CaloPhase1Monitoring.py --evtMax 0
637 from TrigT1CaloMonitoring.LVL1CaloMonitoringConfig import L1CaloMonitorCfgHelper
638 L1CaloMonitorCfgHelper.printHanConfig()
639 cfg._wasMerged = True # prevents spurious error message showing up about cfg that wasn't used
640 exit(0)
641
642if cfg.run().isFailure():
643 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:130
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177