ATLAS Offline Software
Loading...
Searching...
No Matches
plugin_miniSim.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3
4# this plugin is for mini simulation of a set of GlobalSim algorithms
5
6# Example:
7# l1global-minisim --algs JET1 --filesInput JET1.topoc_pu_type:/eos/atlas/atlascerngroupdisk/det-gbl/online/ValidationGate/input_data/hex/mc_events/JET1/myfile_tree.hex.txt --filesOutput JET1.topoc_pu_type:loopback.txt JET1.main_output:output.txt
8
9
10def setup(flags):
11 from AthenaCommon.Logging import logging
12 log = logging.getLogger('plugin_miniSim')
13
14 # turn off everything else from the steering script
15 flags.DQ.doMonitoring=False
16 flags.Trigger.enableL1CaloPhase1=False
17
18 flags.addFlag("GlobalSim.Algs",[])
19 flags.addFlag("GlobalSim.txtInputs",[])
20 flags.addFlag("GlobalSim.txtOutputs",[])
21
22 from AthenaConfiguration.ComponentFactory import CompFactory
23 availableAlgs = [f[:-3] for f in CompFactory.GlobalSim._getEntries()[-1] if f.endswith('Alg')]
24
25 if flags.hasFlag("L1CaloAthMon.UnknownArgs"):
26 # declare additional parser arguments, and parse!
27 import argparse
28 parser = argparse.ArgumentParser()
29 parser.add_argument('--algs',nargs='*',default=[],help=f"algs to run. Available are: {', '.join(availableAlgs)}")
30 parser.add_argument('--filesInput',nargs='*',default=[],help="inputs. If nibbler, specify as <key>:<path>. <key> can be storegate key or algorithm input property (<alg>.<input>)") # just here for help dialog
31 parser.add_argument('--filesOutput',nargs='*',default=[],help="outputs to save, specify similarly to inputs")
32 args,unknown = parser.parse_known_args(flags.L1CaloAthMon.UnknownArgs)
33 flags.L1CaloAthMon.UnknownArgs = unknown
34 flags.GlobalSim.Algs = args.algs
35 flags.GlobalSim.txtOutputs = args.filesOutput
36
37 if len(flags.GlobalSim.Algs) == 0:
38 log.fatal("You must specify what algorithms to run. Use the --algs option")
39 log.fatal(f"Available algs: {availableAlgs}")
40 exit(-1)
41
42 # determine inputs required (while checking algs exist)
43 algInputs = set()
44 algOutputs = set()
45 inputsMap = {}
46 outputsMap = {}
47 knownTypes = {} # if can identify the type from the alg metadata, will collect the types here
48 for alg in flags.GlobalSim.Algs:
49 # check alg exists
50 algType,algName = (alg.split("/") if "/" in alg else [alg,alg])
51 if not hasattr(CompFactory.GlobalSim,algType+"Alg"):
52 log.fatal(f"Unknown Alg: {algType}")
53 log.fatal(f"Available Algs: {availableAlgs}")
54 exit(-1)
55 # now iterate through read and write handles
56 from GaudiKernel.DataHandle import DataHandle
57 from AthenaCommon import CfgMgr
58 propDocs = getattr(CfgMgr,f"GlobalSim__{algType}Alg")._propertyDocDct
59 for propName,propVal in getattr(CompFactory.GlobalSim,algType+"Alg").getDefaultProperties().items():
60 if not isinstance(propVal,DataHandle): continue # skip non-handle properties
61 sgKey = propVal.Path.split('+')[-1]
62 # try to get the "type" from the property description
63 for item in propDocs[propName].split(";"):
64 item = item.strip()
65 if item.startswith("type="):
66 knownTypes[sgKey] = item[len("type="):]
67 knownTypes[f"{algName}.{propName}"] = item[len("type="):]
68 break
69 if propVal.Mode == 'W':
70 algOutputs.add(sgKey)
71 if sgKey not in outputsMap: outputsMap[sgKey] = []
72 outputsMap[sgKey] += [f"{algName}.{propName}"]
73 else:
74 algInputs.add(sgKey)
75 if sgKey not in inputsMap: inputsMap[sgKey] = []
76 inputsMap[sgKey] += [f"{algName}.{propName}"]
77
78 # remove from inputs the outputs of the other algs
79 # what is left will be what we need provided externally
80 algInputs -= algOutputs
81
82 log.info(f"Your algorithms {flags.GlobalSim.Algs} require the following inputs: {[i for a in algInputs for i in inputsMap[a]]}")
83 log.info(f"and produces the following outputs: {[i for a in algOutputs for i in outputsMap[a]]}")
84
85 # move any txt inputs into the txtInputs flag
86 cleanList = []
87 for f in flags.Input.Files:
88 if f.endswith(".txt"):
89 # must have two ":" in it ... check
90 if f.count(":") != 2:
91 if f.count(":")==1:
92 if f.split(":")[0] in knownTypes:
93 f = knownTypes[f.split(":")[0]] + ":" + f
94 else:
95 log.fatal(f"{f.split(':')[0]} has no known type. Add to algorithm metadata or otherwise specify it explicitly with '<type>:' prefix")
96 exit(-1)
97 else:
98 log.fatal("txt input must be specified in form <type>:<SGkey>:<filepath>")
99 exit(-1)
100 flags.GlobalSim.txtInputs += [f]
101 else:
102 cleanList += [f]
103 flags.Input.Files = cleanList
104
105 if len(flags.GlobalSim.txtInputs):
106 flags.Input.isMC = True # tell parts of job to behave as this was a simulation
107
108 if flags.Exec.MaxEvents==-1:
109 # determine max number of events of given input file types
110 maxVals = {}
111 for f in flags.GlobalSim.txtInputs:
112 typeAndName,path = f.rsplit(":",1)
113 if typeAndName not in maxVals: maxVals[typeAndName]=0
114 maxVals[typeAndName] += sum(1 for _ in open(path))
115 flags.Exec.MaxEvents = max(maxVals.values())
116 # use the total number of lines in all the input files as the max events
117 log.info(f"Processing {flags.Exec.MaxEvents} events from txt filesInput")
118
119 txtOutputs = list(flags.GlobalSim.txtOutputs)
120 flags.GlobalSim.txtOutputs = []
121 for f in txtOutputs:
122 if f.endswith(".txt"):
123 # must have two ":" in it ... check
124 if f.count(":") != 2:
125 if f.count(":")==1:
126 if f.split(":")[0] in knownTypes:
127 f = knownTypes[f.split(":")[0]] + ":" + f
128 else:
129 log.fatal(f"{f.split(':')[0]} has no known type. Add to algorithm metadata or otherwise specify it explicitly with '<type>:' prefix")
130 exit(-1)
131 else:
132 log.fatal("txt output must be specified in form <type>:<SGkey>:<filepath>")
133 exit(-1)
134 flags.GlobalSim.txtOutputs += [f]
135 else:
136 pass # todo: should check if root file and if so, add to aod list
137
138
139# I may move this subsequence creation up into the steering script if I can figure out way to control `addEventAlgo` calls
140sequenceName = "GlobalSim"
141cfg.addSequence(CompFactory.AthSequencer(sequenceName,StopOverride=True),parentName="AthAlgSeq")
142
143
144
145
146# ---------------
147# algorithms added here:
148
149# create algos first, as will use properties to create readers
150algos = []
151for alg in flags.GlobalSim.Algs:
152 algType,algName = (alg.split("/") if "/" in alg else [alg,alg])
153 theAlg = getattr(CompFactory.GlobalSim,algType+"Alg")(algName)
154 algos += [theAlg]
155
156
157# add any readers for processing txt files
158readerNames = []
159for f in flags.GlobalSim.txtInputs:
160 tobType,sgKey,filepath = f.split(":")
161 if "." in sgKey:
162 # is an algo property not a key
163 foundProp = False
164 for a in algos:
165 if a.name == sgKey.split(".")[0]:
166 sgKey = getattr(a,sgKey.split(".")[1]).Path.split('+')[-1]
167 foundProp=True
168 break
169 if not foundProp:
170 log.fatal(f"Unknown input property: {sgKey}")
171 exit(-1)
172
173 cfg.addEventAlgo( CompFactory.GlobalSim.TOBTextReader(
174 sgKey+"Reader",BitSpec=tobType,
175 InputFile=filepath,
176 Output=sgKey), sequenceName=sequenceName )
177 readerNames += [sgKey+"Reader"]
178
179# now add the algs
180for theAlg in algos: cfg.addEventAlgo( theAlg, sequenceName=sequenceName )
181
182# add any writers
183for f in flags.GlobalSim.txtOutputs:
184 tobType,sgKey,filepath = f.split(":")
185 if "." in sgKey:
186 # is an algo property not a key
187 foundProp = False
188 for a in algos:
189 if a.name == sgKey.split(".")[0]:
190 sgKey = getattr(a,sgKey.split(".")[1]).Path.split('+')[-1]
191 foundProp=True
192 break
193 if not foundProp:
194 log.fatal(f"Unknown output property: {sgKey}")
195 exit(-1)
196 cfg.addEventAlgo( CompFactory.GlobalSim.TOBTextWriter(
197 sgKey+"Writer",
198 BitSpec=tobType,
199 Input=sgKey,
200 OutputFile=filepath), sequenceName=sequenceName )
201
202
203
204# ----------------
205
206# add the GraphSvc to visualize job
207cfg.addService( CompFactory.GlobalSim.GraphSvc(SequenceNameFilter=sequenceName,OutputLevel=3), create=True )
208
209if flags.Output.AODFileName != "":
210
211 def storeOutput(algName):
212 # this helper method should probably be relocated to python folder for general use t some point
213 from OutputStreamAthenaPool.OutputStreamConfig import OutputStreamCfg
214 from GaudiKernel.DataHandle import DataHandle
215 algo = cfg.getEventAlgo(algName)
216 items = []
217 for propName in algo.getDefaultProperties().keys():
218 p = algo.__getattribute__(propName)
219 if isinstance(p,DataHandle) and p.Mode=='W':
220 items += [f"{p.Type}#{p.Path.split('+')[-1]}",f"xAOD::AuxContainerBase#{p.Path.split('+')[-1]}Aux."]
221 cfg.merge(OutputStreamCfg(flags, 'AOD', ItemList=items,takeItemsFromInput=False,disableEventTag=True))
222
223 for r in readerNames: storeOutput(r)
224 for a in algos: storeOutput(a.name)
#define max(a, b)
Definition cfImp.cxx:41
STL class.
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179