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']
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 import gzip
52 with gzip.open(filename, 'rb') as f_in:
53 lfilename=os.path.basename(filename)
54 with open(lfilename[:-3], 'wb') as f_out:
55 shutil.copyfileobj(f_in, f_out)
56 def get_immediate_subdirectories(a_dir):
57 return [name for name in os.listdir(a_dir)
58 if os.path.isdir(os.path.join(a_dir, name))]
59
60
62 os.environ['LOCAL_INSTALL_DIR'] = (os.environ['JOBOPTSEARCHPATH']).split(":")[0]
63 if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common'):
64 CommonCvmfsDir = '/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common'
65 os.environ["JOBOPTSEARCHPATH"] = CommonCvmfsDir+":"+os.environ["JOBOPTSEARCHPATH"]
66 if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common/MadGraphControl/dat/'):
67 datCvmfsDir = '/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common/MadGraphControl/dat/'
68 os.environ["DATAPATH"] = datCvmfsDir+":"+os.environ["DATAPATH"]
69# dsidparam = (self._trf.argdict["jobConfig"].value).values()[0][0]
70 dsidpar = (self._trf.argdict["jobConfig"].value).values()
71 dsidparam = list(dsidpar)[0][0]
72 # Adding cvmfs path to JOBOPTSEARCHPATH
73 if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/'):
74 BaseCvmfsPath = "/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/"
75
76 if dsidparam.isdigit() and (len(dsidparam)==6 or len(dsidparam)==7):
77 #only dsid is provided, add cvmfs folder like 123xxx to JOBOPTSEARCHPATH
78 Jodir = dsidparam[:3]+'xxx'
79 if len(dsidparam)==7:
80 Jodir = dsidparam[0] + '/' + dsidparam[:4]+'xxx'
81 cwdir = os.getcwd()
82 cwd_ful = os.path.join(cwdir, dsidparam)
83 if (os.path.isdir(cwd_ful)):
84 os.environ["JOBOPTSEARCHPATH"] = cwd_ful+":"+os.environ["JOBOPTSEARCHPATH"]
85 os.environ["DATAPATH"] = cwd_ful+":"+os.environ["DATAPATH"]
86 else:
87 cwd_Jodir = os.path.join(cwdir,Jodir)
88 cwd_Jodir_ful = os.path.join(cwd_Jodir,dsidparam)
89 if (os.path.isdir(cwd_Jodir_ful)):
90 os.environ["JOBOPTSEARCHPATH"] = cwd_Jodir_ful+":"+os.environ["JOBOPTSEARCHPATH"]
91 os.environ["DATAPATH"] = cwd_Jodir_ful+":"+os.environ["DATAPATH"]
92 else:
93 if (os.path.isdir(BaseCvmfsPath)):
94 JoCvmfsPath = os.path.join(BaseCvmfsPath, Jodir)
95 JoCvmfsPath_ful = os.path.join(JoCvmfsPath, dsidparam)
96 os.environ["JOBOPTSEARCHPATH"] = JoCvmfsPath_ful+":"+os.environ["JOBOPTSEARCHPATH"]
97 os.environ["DATAPATH"] = JoCvmfsPath_ful+":"+os.environ["DATAPATH"]
98 else:
99 msg.error("No access to JOs cvmfs location. JOs should be placed in working directory or full path should be given.")
100 raise RuntimeError("JOs not found - no cvmfs access")
101 else: #Suppose full path of dsid folder is provided(/afs/.../123xxx/123456), add cvmfs floder and local path(/afs/.../123xxx) to JOBOPTSEARCHPATH
102 if dsidparam.startswith("Test"): # for testing
103 for token in (os.environ['JOBOPTSEARCHPATH']).split(":"):
104 if "jobOptions" in token:
105 search_token = token
106 break
107 search_token += "/EvgenJobTransforms/EvgenTest/" + dsidparam.split("Test")[-1]
108 os.environ["JOBOPTSEARCHPATH"] = search_token+":"+os.environ["JOBOPTSEARCHPATH"]
109 os.environ["DATAPATH"] = search_token+":"+os.environ["DATAPATH"]
110 elif (os.path.isdir(dsidparam)):
111 os.environ["JOBOPTSEARCHPATH"] = dsidparam+":"+os.environ["JOBOPTSEARCHPATH"]
112 os.environ["DATAPATH"] = dsidparam+":"+os.environ["DATAPATH"]
113 else:
114 msg.error("JOs not found, please check = '%s'", dsidparam)
115 raise RuntimeError("JOs not found")
116
117 msg.info("Using JOBOPTSEARCHPATH = '%s'", os.environ["JOBOPTSEARCHPATH"])
118 msg.info("Using DATAPATH = '%s'", os.environ["DATAPATH"])
119
120 if "evgenJobOpts" in self._trf.argdict:
121 tarball = self._trf.argdict["evgenJobOpts"].value
122
124 if tarball.startswith("http"):
125 url = tarball
126 tarball = os.basename(tarball)
127 else:
128 url = "http://cern.ch/atlas-computing/links/kitsDirectory/EvgenJobOpts/" + tarball
129
130 if not os.path.exists(tarball):
131 from EvgenJobTransforms.download import downloadUsingProxy
132 status, output = downloadUsingProxy(url)
133 if status != 0:
134 raise EnvironmentError('Error downloading tarball %s. Downloader reports: %s' % (tarball, output))
135 msg.info('Evgen tarball download success: %s', output)
136
137 expand_if_archive(tarball)
138
140
141 # copy config files to cwd
142 FIRST_DIR = (os.environ['JOBOPTSEARCHPATH']).split(":")[0]
143 configFiles = [f for f in os.listdir(FIRST_DIR) if ( "GRID" in f)]
144 confFile=None
145 if len(configFiles) == 1:
146 msg.info("gridpack for only one energy available ")
147 elif len(configFiles) >1:
148 msg.info("more then one gridpack ! ")
149 if len(configFiles) >=1:
150 if "--ecmEnergy" in str(sys.argv[1:]):
151 split_args=str(sys.argv[1:]).split("ecmEnergy",1)[1]
152 split_args=split_args.lstrip("\',=")
153 ener_GeV=split_args.split(",")[0].strip(" ,\']")
154 energy=str(float(ener_GeV)/1000.0).replace('.','p').strip(r"=0\p']")
155 msg.info("Should be used gridpack for energy "+energy)
156 else:
157 msg.info("no ecm energy given, assuming 13.6 TeV ")
158 energy="13p6"
159 for x in configFiles:
160 gridS="mc_"+energy+"TeV"
161 msg.info("Gridpack should start from "+gridS)
162 if x.startswith(gridS):
163 confFile = os.path.join(FIRST_DIR, x)
164 msg.info("using gridpack = "+confFile)
165 if confFile is None:
166 msg.error("No *GRID* config files, for requested energy = '%s' please check = '%s'", energy, dsidparam)
167 sys.exit(1)
168
169 if confFile is not None:
170 expand_if_archive(confFile)
171# os.system("cp %s ." % confFile)
172 msg.info("Configuration input gridpack found " + confFile)
173
174 #Expand if a tarball is found in local directory
175 loc_files = os.listdir(os.getcwd())
176 for loc_file in loc_files:
177 if "GRID" not in loc_file:
178 expand_if_archive(loc_file)
179
180
181 if "inputGeneratorFile" in self._trf.argdict:
182# expand_if_archive(self._trf.argdict["inputGeneratorFile"].value)
183 myinputfiles = self._trf.argdict["inputGeneratorFile"].value
184 genInputFiles = myinputfiles.split(',')
185 for file in genInputFiles:
186 expand_if_archive(file)
187 if "inputGenConfFile" in self._trf.argdict:
188 expand_if_archive(self._trf.argdict["inputGenConfFile"].value)
189
190def move_files(main_dir,tmp_dir,allowedlist):
191 files = os.listdir(tmp_dir)
192 files.sort()
193 for f in files:
194 for i in allowedlist:
195 if i in f:
196 src = tmp_dir+"/"+f
197 dest = main_dir+"/"+f
198 os.rename(src,dest)
199 break
200
201
203 exeSet = set()
204 msg.info("Transform arguments %s", sys.argv[1:])
205 if "--outputEVNTFile" in str(sys.argv[1:]):
206 exeSet.add(EvgenExecutor(name="generate", skeleton="EvgenJobTransforms/skel.GENtoEVGEN.py", skeletonCA="EvgenJobTransforms.GENtoEVGEN_Skeleton", inData=["inNULL"], outData=["YODA", "EVNT", "EVNT_Pre", "TXT"]))
207 msg.info("Output EVNT file")
208 elif "--outputYODAFile" in str(sys.argv[1:]):
209 exeSet.add(EvgenExecutor(name="generate", skeleton="EvgenJobTransforms/skel.GENtoEVGEN.py", skeletonCA="EvgenJobTransforms.GENtoEVGEN_Skeleton", inData=["inNULL"], outData=["YODA", "TXT"]))
210 msg.info("Output EVNT file")
211 elif "--outputTXTFile" in str(sys.argv[1:]):
212 exeSet.add(EvgenExecutor(name="generate", skeleton="EvgenJobTransforms/skel.GENtoTXT.py", inData=["inNULL"], outData=["TXT"]))
213 msg.info("Output TXT file")
214 elif "--outputHEPMCFile" not in str(sys.argv[1:]):
215 msg.error("Output cannot be recognised")
216
217 exeSet.add(EvgenExecutor(name="afterburn", skeleton="EvgenJobTransforms/skel.ABtoEVGEN.py", skeletonCA="EvgenJobTransforms.GENtoEVGEN_Skeleton", inData=["EVNT_Pre"], outData=["EVNT"]))
218 exeSet.add(athenaExecutor(name = "AODtoDPD", skeletonFile = "PATJobTransforms/skeleton.AODtoDPD_tf.py",
219 substep = "a2d", inData = ["EVNT"], outData = ["NTUP_TRUTH"], perfMonFile = "ntuple_AODtoDPD.pmon.gz"))
220 exeSet.add(athenaExecutor(name = 'EVNTtoHEPMC', skeletonCA = 'EvgenJobTransforms.POOLtoHEPMC_Skeleton',
221 substep = "a2d", perfMonFile = 'ntuple.pmon.gz', inData=['EVNT'], outData=['HEPMC']))
222 trf = transform(executor=exeSet)
223 addAthenaArguments(trf.parser, maxEventsDefaultSubstep='all')
224 addStdEvgenArgs(trf.parser)
225 return trf
226
227
228@stdTrfExceptionHandler
229@sigUsrStackTrace
230def main():
231 msg.info("This is %s", sys.argv[0])
232
233 main_dir = os.getcwd()
234 trf = getTransform()
235 trf.parseCmdLineArgs(sys.argv[1:])
236 if (("cleanOut" in trf.argdict) and (trf.argdict["cleanOut"].value != 0)):
237 name_tmpdir = "tmprun"
238 tmp_dir = os.path.join(main_dir, name_tmpdir)
239 if os.path.isdir(tmp_dir):
240 shutil.rmtree(tmp_dir, ignore_errors=True)
241 os.mkdir("tmprun")
242 os.chdir("tmprun")
243 tmp_dir = os.getcwd()
244 allowedlist_in = ['MC','group','TXT']
245 move_files(tmp_dir,main_dir,allowedlist_in)
246
247 trf.execute()
248 trf.generateReport()
249 msg.info("%s stopped at %s, trf exit code %d", sys.argv[0], time.asctime(), trf.exitCode)
250
251
252# read files/dirs that should be saved and if present in cwd - remove
253
254 if (("cleanOut" in trf.argdict) and (trf.argdict["cleanOut"].value!=0)):
255 allowedlist_out = ['log.generate','.root']
256 if "outputTXTFile" in trf.argdict:
257 allowedlist_out.append('TXT')
258 if "saveList" in trf.argdict:
259 saveList_dic= trf.argdict["saveList"].value
260 saveList_str= str(saveList_dic)
261 saveList_str=saveList_str[10:-3]
262 saveList= saveList_str.split(",")
263 for item in saveList:
264 test_ex = os.path.join(main_dir,str(item))
265 if os.path.isdir(test_ex):
266 shutil.rmtree(test_ex, ignore_errors=True)
267 elif os.path.isfile(test_ex):
268 os.remove(test_ex)
269 if not saveList[0].isdigit():
270 allowedlist_out=allowedlist_out+saveList
271
272 move_files(main_dir,tmp_dir,allowedlist_out)
273 os.chdir(main_dir)
274 if "saveList" not in trf.argdict:
275 shutil.rmtree(tmp_dir, ignore_errors=True)
276 elif not saveList[0].isdigit():
277 shutil.rmtree(tmp_dir, ignore_errors=True)
278# if cleanOut is not defined and multipleinput preset, remove the merged file
279 elif ("inputGeneratorFile" in trf.argdict):
280 myinputfiles = trf.argdict["inputGeneratorFile"].value
281 genInputFiles = myinputfiles.split(',')
282 numberOfFiles = len(genInputFiles)
283 merge_file = 'merged_lhef._0.events'
284 if((numberOfFiles>1) and (os.path.exists(merge_file))):
285 os.remove(merge_file)
286#
287 if (("lheOnly" in trf.argdict ) and (trf.argdict["lheOnly"].value == 1)):
288 outputName = ''.join(trf.argdict["outputEVNTFile"].value)
289 os.remove(outputName)
290 sys.exit(trf.exitCode)
291
292
293# TODO: Open resulting EVNT file to extract cross-section, generator names+versions, etc. from the HepMC::GenRun or whatever... in an executor postExecute?
294
295
296if __name__ == "__main__":
297 main()
if(febId1==febId2)
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:310
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
getTransform()
Definition Gen_tf.py:202
move_files(main_dir, tmp_dir, allowedlist)
Definition Gen_tf.py:190
main()
Definition Gen_tf.py:230
Main package for new style ATLAS job transforms.
Transform execution functions.
Logging configuration for ATLAS job transforms.