ATLAS Offline Software
Loading...
Searching...
No Matches
Gen_tf.py
Go to the documentation of this file.
1#! /usr/bin/env python
2
3# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
4#
5"""
6# Run event generation and produce an EVNT file.
7"""
8
9import os, sys, time, shutil
10from PyJobTransforms.trfLogger import msg
11from PyJobTransforms.transform import transform
12from PyJobTransforms.trfExe import athenaExecutor
13from PyJobTransforms.trfArgs import addAthenaArguments
14from PyJobTransforms.trfDecorators import stdTrfExceptionHandler, sigUsrStackTrace
15from EvgenJobTransforms.evgenTrfArgs import addStdEvgenArgs
16
17
19ListOfDefaultPositionalKeys=['--AMIConfig', '--AMITag', '--argJSON', '--asetup', '--athena',
20'--athenaMPMergeTargetSize', '--athenaopts', '--attempt', '--checkEventCount', '--command',
21'--dumpJSON', '--dumpPickle', '--ecmEnergy', '--env', '--eventAcceptanceEfficiency',
22'--evgenJobOpts', '--execOnly', '--fileValidation', '--firstEvent', '--ignoreErrors',
23'--ignoreFiles', '--ignorePatterns', '--imf', '--inputEVNT_PreFile', '--inputFileValidation',
24'--inputGenConfFile', '--inputGeneratorFile', '--jobConfig', '--jobid', '--maxEvents', '--orphanKiller', '--outputEVNTFile', '--outputEVNT_PreFile', '--outputHEPMCFile', '--outputFileValidation', '--outputNTUP_TRUTHFile', '--outputTXTFile', '--parallelFileValidation', '--postExec', '--postInclude', '--preExec', '--preInclude', '--wprintEvts', '--randomSeed', '--reportName', '--reportType', '--rivetAnas', '--runNumber', '--showGraph', '--showPath', '--showSteps', '--skipEvents', '--skipFileValidation', '--skipInputFileValidation', '--skipOutputFileValidation', '--steering', '--taskid', '--tcmalloc', '--valgrind', '--valgrindbasicopts', '--valgrindextraopts', '--lheOnly', '--localPath', '--cleanOut', '--saveList', '--avoidExtracting']
25
26class EvgenExecutor(athenaExecutor):
27 "Specialised trf executor class for event generation jobs"
28 def __init__(self, name="generate", skeleton=None, skeletonCA=None, substep=None, inData=set(), outData=set()):
29 athenaExecutor.__init__(self, name=name, skeletonFile=skeleton, skeletonCA=skeletonCA,
30 substep=substep, inputEventTest=False, tryDropAndReload=False,
31 inData=inData, outData=outData)
32
33 def preExecute(self, input=set(), output=set()):
34 "Get input tarball, unpack and set up env if an evgenJobOpts arg was provided."
35
36
37 super(EvgenExecutor, self).preExecute(input, output)
38
39 def expand_if_archive(filename):
40 "Function to expand a file if it is a zip archive or tarball"
41 if ".tar" in filename or ".tgz" in filename:
42 import tarfile
43 with tarfile.open(filename) as tf:
44 tf.extractall()
45 elif filename.endswith(".zip"):
46 import zipfile
47 zf = zipfile.ZipFile(filename)
48 zf.extractall()
49 zf.close()
50 elif ".gz" in filename:
51 shouldExtract = True
52 if "avoidExtracting" in self._trf.argdict:
53 shouldExtract = not self._trf.argdict["avoidExtracting"].value
54 if shouldExtract:
55 import gzip
56 with gzip.open(filename, 'rb') as f_in:
57 lfilename=os.path.basename(filename)
58 with open(lfilename[:-3], 'wb') as f_out:
59 shutil.copyfileobj(f_in, f_out)
60 else:
61 msg.info("Avoid extracting gz input generator file.")
62 def get_immediate_subdirectories(a_dir):
63 return [name for name in os.listdir(a_dir)
64 if os.path.isdir(os.path.join(a_dir, name))]
65
66
68 os.environ['LOCAL_INSTALL_DIR'] = (os.environ['JOBOPTSEARCHPATH']).split(":")[0]
69 if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common'):
70 CommonCvmfsDir = '/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common'
71 os.environ["JOBOPTSEARCHPATH"] = CommonCvmfsDir+":"+os.environ["JOBOPTSEARCHPATH"]
72 if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common/MadGraphControl/dat/'):
73 datCvmfsDir = '/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common/MadGraphControl/dat/'
74 os.environ["DATAPATH"] = datCvmfsDir+":"+os.environ["DATAPATH"]
75# dsidparam = (self._trf.argdict["jobConfig"].value).values()[0][0]
76 dsidpar = (self._trf.argdict["jobConfig"].value).values()
77 dsidparam = list(dsidpar)[0][0]
78 # Adding cvmfs path to JOBOPTSEARCHPATH
79 if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/'):
80 BaseCvmfsPath = "/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/"
81
82 if dsidparam.isdigit() and (len(dsidparam)==6 or len(dsidparam)==7):
83 #only dsid is provided, add cvmfs folder like 123xxx to JOBOPTSEARCHPATH
84 Jodir = dsidparam[:3]+'xxx'
85 if len(dsidparam)==7:
86 Jodir = dsidparam[0] + '/' + dsidparam[:4]+'xxx'
87 cwdir = os.getcwd()
88 cwd_ful = os.path.join(cwdir, dsidparam)
89 if (os.path.isdir(cwd_ful)):
90 os.environ["JOBOPTSEARCHPATH"] = cwd_ful+":"+os.environ["JOBOPTSEARCHPATH"]
91 os.environ["DATAPATH"] = cwd_ful+":"+os.environ["DATAPATH"]
92 else:
93 cwd_Jodir = os.path.join(cwdir,Jodir)
94 cwd_Jodir_ful = os.path.join(cwd_Jodir,dsidparam)
95 if (os.path.isdir(cwd_Jodir_ful)):
96 os.environ["JOBOPTSEARCHPATH"] = cwd_Jodir_ful+":"+os.environ["JOBOPTSEARCHPATH"]
97 os.environ["DATAPATH"] = cwd_Jodir_ful+":"+os.environ["DATAPATH"]
98 else:
99 if (os.path.isdir(BaseCvmfsPath)):
100 JoCvmfsPath = os.path.join(BaseCvmfsPath, Jodir)
101 JoCvmfsPath_ful = os.path.join(JoCvmfsPath, dsidparam)
102 os.environ["JOBOPTSEARCHPATH"] = JoCvmfsPath_ful+":"+os.environ["JOBOPTSEARCHPATH"]
103 os.environ["DATAPATH"] = JoCvmfsPath_ful+":"+os.environ["DATAPATH"]
104 else:
105 msg.error("No access to JOs cvmfs location. JOs should be placed in working directory or full path should be given.")
106 raise RuntimeError("JOs not found - no cvmfs access")
107 else: #Suppose full path of dsid folder is provided(/afs/.../123xxx/123456), add cvmfs floder and local path(/afs/.../123xxx) to JOBOPTSEARCHPATH
108 if dsidparam.startswith("Test"): # for testing
109 for token in (os.environ['JOBOPTSEARCHPATH']).split(":"):
110 if "jobOptions" in token:
111 search_token = token
112 break
113 search_token += "/EvgenJobTransforms/EvgenTest/" + dsidparam.split("Test")[-1]
114 os.environ["JOBOPTSEARCHPATH"] = search_token+":"+os.environ["JOBOPTSEARCHPATH"]
115 os.environ["DATAPATH"] = search_token+":"+os.environ["DATAPATH"]
116 elif (os.path.isdir(dsidparam)):
117 os.environ["JOBOPTSEARCHPATH"] = dsidparam+":"+os.environ["JOBOPTSEARCHPATH"]
118 os.environ["DATAPATH"] = dsidparam+":"+os.environ["DATAPATH"]
119 else:
120 msg.error("JOs not found, please check = '%s'", dsidparam)
121 raise RuntimeError("JOs not found")
122
123 msg.info("Using JOBOPTSEARCHPATH = '%s'", os.environ["JOBOPTSEARCHPATH"])
124 msg.info("Using DATAPATH = '%s'", os.environ["DATAPATH"])
125
126 if "evgenJobOpts" in self._trf.argdict:
127 tarball = self._trf.argdict["evgenJobOpts"].value
128
130 if tarball.startswith("http"):
131 url = tarball
132 tarball = os.basename(tarball)
133 else:
134 url = "http://cern.ch/atlas-computing/links/kitsDirectory/EvgenJobOpts/" + tarball
135
136 if not os.path.exists(tarball):
137 from EvgenJobTransforms.download import downloadUsingProxy
138 status, output = downloadUsingProxy(url)
139 if status != 0:
140 raise EnvironmentError('Error downloading tarball %s. Downloader reports: %s' % (tarball, output))
141 msg.info('Evgen tarball download success: %s', output)
142
143 expand_if_archive(tarball)
144
146
147 # copy config files to cwd
148 FIRST_DIR = (os.environ['JOBOPTSEARCHPATH']).split(":")[0]
149 configFiles = [f for f in os.listdir(FIRST_DIR) if ( "GRID" in f)]
150 confFile=None
151 if len(configFiles) == 1:
152 msg.info("gridpack for only one energy available ")
153 elif len(configFiles) >1:
154 msg.info("more then one gridpack ! ")
155 if len(configFiles) >=1:
156 if "--ecmEnergy" in str(sys.argv[1:]):
157 split_args=str(sys.argv[1:]).split("ecmEnergy",1)[1]
158 split_args=split_args.lstrip("\',=")
159 ener_GeV=split_args.split(",")[0].strip(" ,\']")
160 energy=str(float(ener_GeV)/1000.0).replace('.','p').strip(r"=0\p']")
161 msg.info("Should be used gridpack for energy "+energy)
162 else:
163 msg.info("no ecm energy given, assuming 13.6 TeV ")
164 energy="13p6"
165 for x in configFiles:
166 gridS="mc_"+energy+"TeV"
167 msg.info("Gridpack should start from "+gridS)
168 if x.startswith(gridS):
169 confFile = os.path.join(FIRST_DIR, x)
170 msg.info("using gridpack = "+confFile)
171 if confFile is None:
172 msg.error("No *GRID* config files, for requested energy = '%s' please check = '%s'", energy, dsidparam)
173 sys.exit(1)
174
175 if confFile is not None:
176 expand_if_archive(confFile)
177# os.system("cp %s ." % confFile)
178 msg.info("Configuration input gridpack found " + confFile)
179
180 #Expand if a tarball is found in local directory
181 loc_files = os.listdir(os.getcwd())
182 for loc_file in loc_files:
183 if "GRID" not in loc_file:
184 expand_if_archive(loc_file)
185
186
187 if "inputGeneratorFile" in self._trf.argdict:
188# expand_if_archive(self._trf.argdict["inputGeneratorFile"].value)
189 myinputfiles = self._trf.argdict["inputGeneratorFile"].value
190 genInputFiles = myinputfiles.split(',')
191 for file in genInputFiles:
192 expand_if_archive(file)
193 if "inputGenConfFile" in self._trf.argdict:
194 expand_if_archive(self._trf.argdict["inputGenConfFile"].value)
195
196def move_files(main_dir,tmp_dir,allowedlist):
197 files = os.listdir(tmp_dir)
198 files.sort()
199 for f in files:
200 for i in allowedlist:
201 if i in f:
202 src = tmp_dir+"/"+f
203 dest = main_dir+"/"+f
204 os.rename(src,dest)
205 break
206
207
209 exeSet = set()
210 msg.info("Transform arguments %s", sys.argv[1:])
211 if "--outputEVNTFile" in str(sys.argv[1:]):
212 exeSet.add(EvgenExecutor(name="generate", skeleton="EvgenJobTransforms/skel.GENtoEVGEN.py", skeletonCA="EvgenJobTransforms.GEN_Skeleton", inData=["inNULL"], outData=["YODA", "EVNT", "EVNT_Pre", "TXT"]))
213 msg.info("Output EVNT file")
214 elif "--outputYODAFile" in str(sys.argv[1:]):
215 exeSet.add(EvgenExecutor(name="generate", skeleton="EvgenJobTransforms/skel.GENtoEVGEN.py", skeletonCA="EvgenJobTransforms.GEN_Skeleton", inData=["inNULL"], outData=["YODA", "TXT"]))
216 msg.info("Output EVNT file")
217 elif "--outputTXTFile" in str(sys.argv[1:]):
218 exeSet.add(EvgenExecutor(name="generate", skeleton="EvgenJobTransforms/skel.GENtoTXT.py", skeletonCA="EvgenJobTransforms.GEN_Skeleton", inData=["inNULL"], outData=["TXT"]))
219 msg.info("Output TXT file")
220 elif "--outputHEPMCFile" not in str(sys.argv[1:]):
221 msg.error("Output cannot be recognised")
222
223 exeSet.add(EvgenExecutor(name="afterburn", skeleton="EvgenJobTransforms/skel.ABtoEVGEN.py", skeletonCA="EvgenJobTransforms.GEN_Skeleton", inData=["EVNT_Pre"], outData=["EVNT"]))
224 exeSet.add(athenaExecutor(name = "AODtoDPD", skeletonFile = "PATJobTransforms/skeleton.AODtoDPD_tf.py",
225 substep = "a2d", inData = ["EVNT"], outData = ["NTUP_TRUTH"], perfMonFile = "ntuple_AODtoDPD.pmon.gz"))
226 exeSet.add(athenaExecutor(name = 'EVNTtoHEPMC', skeletonCA = 'EvgenJobTransforms.POOLtoHEPMC_Skeleton',
227 substep = "a2d", perfMonFile = 'ntuple.pmon.gz', inData=['EVNT'], outData=['HEPMC']))
228 trf = transform(executor=exeSet)
229 addAthenaArguments(trf.parser, maxEventsDefaultSubstep='all')
230 addStdEvgenArgs(trf.parser)
231 return trf
232
233
234@stdTrfExceptionHandler
235@sigUsrStackTrace
236def main():
237 msg.info("This is %s", sys.argv[0])
238
239 main_dir = os.getcwd()
240 trf = getTransform()
241 trf.parseCmdLineArgs(sys.argv[1:])
242 if (("cleanOut" in trf.argdict) and (trf.argdict["cleanOut"].value != 0)):
243 name_tmpdir = "tmprun"
244 tmp_dir = os.path.join(main_dir, name_tmpdir)
245 if os.path.isdir(tmp_dir):
246 shutil.rmtree(tmp_dir, ignore_errors=True)
247 os.mkdir("tmprun")
248 os.chdir("tmprun")
249 tmp_dir = os.getcwd()
250 allowedlist_in = ['MC','group','TXT']
251 move_files(tmp_dir,main_dir,allowedlist_in)
252
253 trf.execute()
254 trf.generateReport()
255 msg.info("%s stopped at %s, trf exit code %d", sys.argv[0], time.asctime(), trf.exitCode)
256
257
258# read files/dirs that should be saved and if present in cwd - remove
259
260 if (("cleanOut" in trf.argdict) and (trf.argdict["cleanOut"].value!=0)):
261 allowedlist_out = ['log.generate','.root']
262 if "outputTXTFile" in trf.argdict:
263 allowedlist_out.append('TXT')
264 if "saveList" in trf.argdict:
265 saveList_dic= trf.argdict["saveList"].value
266 saveList_str= str(saveList_dic)
267 saveList_str=saveList_str[10:-3]
268 saveList= saveList_str.split(",")
269 for item in saveList:
270 test_ex = os.path.join(main_dir,str(item))
271 if os.path.isdir(test_ex):
272 shutil.rmtree(test_ex, ignore_errors=True)
273 elif os.path.isfile(test_ex):
274 os.remove(test_ex)
275 if not saveList[0].isdigit():
276 allowedlist_out=allowedlist_out+saveList
277
278 move_files(main_dir,tmp_dir,allowedlist_out)
279 os.chdir(main_dir)
280 if "saveList" not in trf.argdict:
281 shutil.rmtree(tmp_dir, ignore_errors=True)
282 elif not saveList[0].isdigit():
283 shutil.rmtree(tmp_dir, ignore_errors=True)
284# if cleanOut is not defined and multipleinput preset, remove the merged file
285 elif ("inputGeneratorFile" in trf.argdict):
286 myinputfiles = trf.argdict["inputGeneratorFile"].value
287 genInputFiles = myinputfiles.split(',')
288 numberOfFiles = len(genInputFiles)
289 merge_file = 'merged_lhef._0.events'
290 if((numberOfFiles>1) and (os.path.exists(merge_file))):
291 os.remove(merge_file)
292#
293 if (("lheOnly" in trf.argdict ) and (trf.argdict["lheOnly"].value == 1)):
294 outputName = ''.join(trf.argdict["outputEVNTFile"].value)
295 os.remove(outputName)
296 sys.exit(trf.exitCode)
297
298
299# TODO: Open resulting EVNT file to extract cross-section, generator names+versions, etc. from the HepMC::GenRun or whatever... in an executor postExecute?
300
301
302if __name__ == "__main__":
303 main()
if(pathvar)
preExecute(self, input=set(), output=set())
Definition Gen_tf.py:33
__init__(self, name="generate", skeleton=None, skeletonCA=None, substep=None, inData=set(), outData=set())
Definition Gen_tf.py:28
STL class.
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:312
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
getTransform()
Definition Gen_tf.py:208
move_files(main_dir, tmp_dir, allowedlist)
Definition Gen_tf.py:196
main()
Definition Gen_tf.py:236
Main package for new style ATLAS job transforms.
Transform execution functions.
Logging configuration for ATLAS job transforms.