ATLAS Offline Software
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 
9 import os, sys, time, shutil
10 from PyJobTransforms.trfLogger import msg
11 from PyJobTransforms.transform import transform
12 from PyJobTransforms.trfExe import athenaExecutor
13 from PyJobTransforms.trfArgs import addAthenaArguments
14 from PyJobTransforms.trfDecorators import stdTrfExceptionHandler, sigUsrStackTrace
15 from EvgenJobTransforms.evgenTrfArgs import addStdEvgenArgs
16 
17 
19 ListOfDefaultPositionalKeys=['--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 
26 class 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)
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 
190 def 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
230 def 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 
296 if __name__ == "__main__":
297  main()
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:310
Gen_tf.move_files
def move_files(main_dir, tmp_dir, allowedlist)
Definition: Gen_tf.py:190
python.jo_proxy.get_immediate_subdirectories
def get_immediate_subdirectories(a_dir)
Definition: jo_proxy.py:6
python.Bindings.values
values
Definition: Control/AthenaPython/python/Bindings.py:808
Gen_tf.getTransform
def getTransform()
Definition: Gen_tf.py:202
python.trfArgs.addAthenaArguments
def addAthenaArguments(parser, maxEventsDefaultSubstep='first', addValgrind=True, addPerfMon=True, addVTune=True)
Options related to running athena in general TODO: Some way to mask certain options (perExec,...
Definition: trfArgs.py:59
Amg::transform
Amg::Vector3D transform(Amg::Vector3D &v, Amg::Transform3D &tr)
Transform a point from a Trasformation3D.
Definition: GeoPrimitivesHelpers.h:156
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
Gen_tf.EvgenExecutor.preExecute
def preExecute(self, input=set(), output=set())
Definition: Gen_tf.py:33
python.download.downloadUsingProxy
def downloadUsingProxy(url, filename=None)
Definition: download.py:3
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
Gen_tf.EvgenExecutor.__init__
def __init__(self, name="generate", skeleton=None, skeletonCA=None, substep=None, inData=set(), outData=set())
Definition: Gen_tf.py:28
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
PyJobTransforms.trfExe
Transform execution functions.
Trk::open
@ open
Definition: BinningType.h:40
python.evgenTrfArgs.addStdEvgenArgs
def addStdEvgenArgs(parser)
Definition: evgenTrfArgs.py:5
PyJobTransforms.trfLogger
Logging configuration for ATLAS job transforms.
if
if(febId1==febId2)
Definition: LArRodBlockPhysicsV0.cxx:567
PyJobTransforms.transform
Main package for new style ATLAS job transforms.
str
Definition: BTagTrackIpAccessor.cxx:11
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
Gen_tf.EvgenExecutor
Definition: Gen_tf.py:26
Gen_tf.main
def main()
Definition: Gen_tf.py:230
python.LArMinBiasAlgConfig.float
float
Definition: LArMinBiasAlgConfig.py:65