ATLAS Offline Software
skel.GENtoEVGEN.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2 #
3 """Functionality core of the Gen_tf transform"""
4 
5 
8 
9 
11 
12 import ast
13 import os, re, string, subprocess
14 import AthenaCommon.AlgSequence as acas
15 import AthenaCommon.AppMgr as acam
16 from AthenaCommon.AthenaCommonFlags import jobproperties
17 
18 from xAODEventInfoCnv.xAODEventInfoCnvConf import xAODMaker__EventInfoCnvAlg
19 acam.athMasterSeq += xAODMaker__EventInfoCnvAlg(xAODKey="TMPEvtInfo")
20 
21 theApp = acam.theApp
22 acam.athMasterSeq += acas.AlgSequence("EvgenGenSeq")
23 genSeq = acam.athMasterSeq.EvgenGenSeq
24 acam.athMasterSeq += acas.AlgSequence("EvgenFixSeq")
25 fixSeq = acam.athMasterSeq.EvgenFixSeq
26 acam.athMasterSeq += acas.AlgSequence("EvgenPreFilterSeq")
27 prefiltSeq = acam.athMasterSeq.EvgenPreFilterSeq
28 acam.athMasterSeq += acas.AlgSequence("EvgenTestSeq")
29 testSeq = acam.athMasterSeq.EvgenTestSeq
30 
31 from EvgenProdTools.LogicalExpressionFilter import LogicalExpressionFilter
32 acam.athMasterSeq += LogicalExpressionFilter("EvgenFilterSeq")
33 filtSeq = acam.athMasterSeq.EvgenFilterSeq
34 topSeq = acas.AlgSequence()
35 anaSeq = topSeq
36 topSeq += acas.AlgSequence("EvgenPostSeq")
37 postSeq = topSeq.EvgenPostSeq
38 #topAlg = topSeq #< alias commented out for now, so that accidental use throws an error
39 
40 
41 
44 
45 
46 import AthenaCommon.AtlasUnixGeneratorJob
47 include("PartPropSvc/PartPropSvc.py")
48 
49 
50 from PerfMonComps.PerfMonFlags import jobproperties as perfmonjp
51 perfmonjp.PerfMonFlags.doFastMonMT = True
52 
53 
54 from RngComps.RngCompsConf import AthRNGSvc
55 svcMgr += AthRNGSvc()
56 
57 
58 jobproperties.AthenaCommonFlags.AllowIgnoreConfigError = False
59 
60 
61 from AthenaCommon.Logging import logging
62 evgenLog = logging.getLogger('Gen_tf')
63 
64 
67 
68 
69 evgenLog.debug("****************** CHECKING EVENT GENERATION ARGS *****************")
70 evgenLog.debug(str(runArgs))
71 
72 if hasattr(runArgs, "inputGeneratorFile"):
73  evgenLog.info("inputGeneratorFile = " + runArgs.inputGeneratorFile)
74 
75 if hasattr(runArgs, "outputYODAFile"):
76  evgenLog.info("specified outputYODAFile = " + runArgs.outputYODAFile)
77 
78 
80 if not hasattr(runArgs, "outputEVNTFile") and not hasattr(runArgs, "outputEVNT_PreFile"):
81  if hasattr(runArgs, "outputYODAFile"):
82  evgenLog.info("No outputEVNTFile specified but outputYODAFile is used")
83  evgenLog.info("Will run GENtoEVGEN without saving the output EVNT file, asuming a valid outputYODAFile will be produced")
84  else:
85  raise RuntimeError("No output evgen EVNT or EVNT_Pre file provided.")
86 
87 
88 if not hasattr(runArgs, "ecmEnergy"):
89  raise RuntimeError("No center of mass energy provided.")
90 else:
91  evgenLog.info('ecmEnergy = ' + str(runArgs.ecmEnergy) )
92 if not hasattr(runArgs, "randomSeed"):
93  raise RuntimeError("No random seed provided.")
94  # TODO: or guess it from the JO name??
95 if not hasattr(runArgs, "firstEvent"):
96  raise RuntimeError("No first number provided.")
97 if ( runArgs.firstEvent <= 0):
98  evgenLog.warning("Run argument firstEvent should be > 0")
99 
100 
103 
104 
105 evgenLog.debug("****************** CONFIGURING EVENT GENERATION *****************")
106 
107 
109 from EvgenJobTransforms.EvgenConfig import evgenConfig
110 from GeneratorConfig.GenConfigHelpers import gens_known, gen_lhef, gens_lhef, gen_sortkey, gens_testhepmc, gens_notune, gen_require_steering
111 
112 
113 from EvgenProdTools.EvgenProdToolsConf import FixHepMC
114 if not hasattr(fixSeq, "FixHepMC"):
115  fixSeq += FixHepMC()
116 
117 
118 from EvgenProdTools.EvgenProdToolsConf import TestHepMC
119 testSeq += TestHepMC(CmEnergy=runArgs.ecmEnergy*Units.GeV)
120 #testSeq += TestHepMC(CmEnergy=runArgs.ecmEnergy)
121 if not hasattr(svcMgr, 'THistSvc'):
122  from GaudiSvc.GaudiSvcConf import THistSvc
123  svcMgr += THistSvc()
124 svcMgr.THistSvc.Output = ["TestHepMCname DATAFILE='TestHepMC.root' OPT='RECREATE'"]
125 
126 
128 from EvgenProdTools.EvgenProdToolsConf import CopyEventWeight
129 if not hasattr(postSeq, "CopyEventWeight"):
130  postSeq += CopyEventWeight(mcEventWeightsKey="TMPEvtInfo.mcEventWeights")
131 
132 from EvgenProdTools.EvgenProdToolsConf import FillFilterValues
133 if not hasattr(postSeq, "FillFilterValues"):
134  postSeq += FillFilterValues(mcFilterHTKey="TMPEvtInfo.mcFilterHT")
135 
136 
138 from EvgenProdTools.EvgenProdToolsConf import CountHepMC
139 svcMgr.EventSelector.FirstEvent = runArgs.firstEvent
140 theApp.EvtMax = -1
141 # This is necessary for athenaMP # commented out for now
142 #if hasattr(runArgs, "maxEvents"):
143 # theApp.EvtMax = runArgs.maxEvents
144 
145 if not hasattr(postSeq, "CountHepMC"):
146  postSeq += CountHepMC(InputEventInfo="TMPEvtInfo",
147  OutputEventInfo="EventInfo",
148  mcEventWeightsKey="TMPEvtInfo.mcEventWeights")
149 #postSeq.CountHepMC.RequestedOutput = evgenConfig.nEventsPerJob if runArgs.maxEvents == -1 else runArgs.maxEvents
150 
151 postSeq.CountHepMC.FirstEvent = runArgs.firstEvent
152 postSeq.CountHepMC.CorrectHepMC = True
153 postSeq.CountHepMC.CorrectEventID = True
154 
155 
157 if hasattr(runArgs, "printEvts") and runArgs.printEvts > 0:
158  from TruthIO.TruthIOConf import PrintMC
159  postSeq += PrintMC()
160  postSeq.PrintMC.McEventKey = "GEN_EVENT"
161  postSeq.PrintMC.VerboseOutput = True
162  postSeq.PrintMC.PrintStyle = "Barcode"
163  postSeq.PrintMC.FirstEvent = 1
164  postSeq.PrintMC.LastEvent = runArgs.printEvts
165 
166 
167 from EvgenProdTools.EvgenProdToolsConf import SimTimeEstimate
168 if not hasattr(postSeq, "SimTimeEstimate"):
169  postSeq += SimTimeEstimate()
170 
171 
173 if hasattr(runArgs, "rivetAnas"):
174  from Rivet_i.Rivet_iConf import Rivet_i
175  anaSeq += Rivet_i()
176  anaSeq.Rivet_i.Analyses = runArgs.rivetAnas
177  anaSeq.Rivet_i.AnalysisPath = os.environ['PWD']
178  if hasattr(runArgs, "outputYODAFile"):
179  anaSeq.Rivet_i.HistoFile = runArgs.outputYODAFile
180 
181 # in case of mc23 protect against changing run number in McEventSelector
182 rel = os.popen("echo $AtlasVersion").read()
183 rel = rel.strip()
184 if not rel or int(rel[:2]) > 22:
185  from AthenaCommon.AppMgr import ServiceMgr
186  ServiceMgr.EventSelector.EventsPerRun = int(2**63 - 1) #sys.maxint on a 64-bit machine
187 
188 
191 
192 
193 evgenLog.debug("****************** LOADING PRE-INCLUDES AND JOB CONFIG *****************")
194 
195 
196 if hasattr(runArgs, "preInclude"):
197  for fragment in runArgs.preInclude:
198  include(fragment)
199 
200 
201 if hasattr(runArgs, "preExec"):
202  evgenLog.info("Transform pre-exec")
203  for cmd in runArgs.preExec:
204  evgenLog.info(cmd)
205  exec(cmd)
206 
208  return [name for name in os.listdir(a_dir)
209  if os.path.isdir(os.path.join(a_dir, name))]
210 
211 # TODO: Explain!!!
212 def OutputTXTFile():
213  outputTXTFile = None
214  if hasattr(runArgs,"outputTXTFile"): outputTXTFile=runArgs.outputTXTFile
215  return outputTXTFile
216 
218 if len(runArgs.jobConfig) != 1:
219  evgenLog.info("runArgs.jobConfig = %s" % runArgs.jobConfig)
220  evgenLog.error("You must supply one and only one jobConfig file argument")
221  sys.exit(1)
222 
223 evgenLog.info("Using JOBOPTSEARCHPATH (as seen in skeleton) = '%s'" % os.environ["JOBOPTSEARCHPATH"])
224 FIRST_DIR = (os.environ['JOBOPTSEARCHPATH']).split(":")[0]
225 
226 jofiles = [f for f in os.listdir(FIRST_DIR) if (f.startswith('mc') and f.endswith('.py'))]
227 if len(jofiles) !=1:
228  evgenLog.error("You must supply one and only one jobOption file in DSID directory")
229  sys.exit(1)
230 jofile = jofiles[0]
231 
232 joparts = (os.path.basename(jofile)).split(".")
233 
234 officialJO = False
235 if joparts[0].startswith("mc") and all(c in string.digits for c in joparts[0][2:]):
236  officialJO = True
237 
238  if len(joparts) != 3:
239  evgenLog.error(jofile + " name format is wrong: must be of the form mc.<physicsShort>.py: please rename.")
240  sys.exit(1)
241 
242  jo_physshortpart = joparts[1]
243  max_jo_physshort_length = 50
244  if len(jo_physshortpart) > max_jo_physshort_length:
245  evgenLog.error(f"{jofile} contains a physicsShort field of more than {max_jo_physshort_length} characters: please rename.")
246  sys.exit(1)
247 
248  jo_physshortparts = jo_physshortpart.split("_")
249  if len(jo_physshortparts) < 2:
250  evgenLog.error(jofile + " has too few physicsShort fields separated by '_': should contain <generators>(_<tune+PDF_if_available>)_<process>. Please rename.")
251  sys.exit(1)
252 
253  check_jofiles="/cvmfs/atlas.cern.ch/repo/sw/Generators/MC16JobOptions/scripts/check_jo_consistency.py"
254  if os.path.exists(check_jofiles):
255  include(check_jofiles)
256  check_naming(os.path.basename(jofile))
257  else:
258  evgenLog.waring("check_jo_consistency.py not found, will proceed without JOs check.")
259 # sys.exit(1)
260 
261 
262 include(jofile)
263 
264 
267 
268 
269 evgenLog.debug("****************** CHECKING EVGEN CONFIGURATION *****************")
270 
271 if hasattr(runArgs,'inputGeneratorFile') and int(evgenConfig.inputFilesPerJob) == 0 :
272  evgenConfig.inputFilesPerJob = 1
273 
274 
275 for opt in str(evgenConfig).split(os.linesep):
276  evgenLog.info(opt)
277 evgenLog.info(".transform = Gen_tf")
278 
279 
280 evgenLog.info(".platform = "+str(os.environ['BINARY_TAG']))
281 
282 
285 if evgenConfig.obsolete:
286  evgenLog.error("JOs or icludes are obsolete, please check them")
287  sys.exit(1)
288 
289 if not evgenConfig.generators:
290  evgenLog.error("No entries in evgenConfig.generators: invalid configuration, please check your JO")
291  sys.exit(1)
292 
293 if len(evgenConfig.generators) > len(set(evgenConfig.generators)):
294  evgenLog.error("Duplicate entries in evgenConfig.generators: invalid configuration, please check your JO")
295  sys.exit(1)
296 
297 gennames = sorted(evgenConfig.generators, key=gen_sortkey)
298 
299 if joparts[0].startswith("Mc"): #< if this is an "official" JO
300  genpart = jo_physshortparts[0]
301  expectedgenpart = ''.join(gennames)
302 
303  expectedgenpart = expectedgenpart.replace("HerwigJimmy", "Herwig")
304  def _norm(s):
305  # TODO: add EvtGen to this normalization for MC14?
306  return s.replace("Photospp", "").replace("Photos", "").replace("TauolaPP", "").replace("Tauolapp", "").replace("Tauola", "")
307  def _norm2(s):
308  if "P8B" in s:
309  return s.replace("P8B","Pythia8B").replace("MG","MadGraph").replace("Ph","Powheg").replace("Ag","Alpgen").replace("EG","EvtGen")
310  else:
311  return s.replace("Py","Pythia").replace("MG","MadGraph").replace("Ph","Powheg").replace("H7","Herwig7").replace("Sh","Sherpa").replace("Ag","Alpgen").replace("EG","EvtGen").replace("PG","ParticleGun").replace("HepMC","HepMCAscii")
312  def _short2(s):
313  if "Pythia8B" in s:
314  return s.replace("Pythia8B","P8B").replace("MadGraph","MG").replace("Powheg","Ph").replace("Herwig7","H7").replace("Sherpa","Sh").replace("Alpgen","Ag").replace("EvtGen","EG").replace("PG","ParticleGun")
315  else:
316  return s.replace("Pythia","Py").replace("MadGraph","MG").replace("Powheg","Ph").replace("Herwigpp","Hpp").replace("Sherpa","Sh").replace("Alpgen","Ag").replace("EvtGen","EG").replace("PG","ParticleGun").replace("HepMCAscii","HepMC")
317 
318  if genpart != _norm(expectedgenpart) and _norm2(genpart) != _norm(expectedgenpart):
319  evgenLog.error("Expected first part of JO name to be '%s' or '%s', but found '%s'" % (_norm(expectedgenpart), _norm(_short2(expectedgenpart)), genpart))
320  evgenLog.error("gennames '%s' " %(expectedgenpart))
321  sys.exit(1)
322 
323  del _norm
324 
325  if not gens_notune(gennames) and len(jo_physshortparts) < 3:
326  evgenLog.error(jofile + " with generators " + expectedgenpart +
327  " has too few physicsShort fields separated by '_'." +
328  " It should contain <generators>_<tune+PDF_<process>. Please rename.")
329  sys.exit(1)
330 
331 
333 if gen_require_steering(gennames):
334  if hasattr(runArgs, "outputEVNTFile") and not hasattr(runArgs, "outputEVNT_PreFile"):
335  raise RuntimeError("'EvtGen' found in job options name, please set '--steering=afterburn'")
336 
337 
338 
340 rounding = 0
341 if hasattr(runArgs,'inputGeneratorFile') and ',' in runArgs.inputGeneratorFile: multiInput = runArgs.inputGeneratorFile.count(',')+1
342 else:
343  multiInput = 0
344 
345 # check if default nEventsPerJob used
346 if not evgenConfig.nEventsPerJob:
347  evgenLog.info('#############################################################')
348  evgenLog.info(' !!!! no nEventsPerJob set !!! The default 10000 used. !!! ')
349  evgenLog.info('#############################################################')
350 else:
351  evgenLog.info(' nEventsPerJob = ' + str(evgenConfig.nEventsPerJob) )
352 
353 if evgenConfig.minevents > 0 :
354  raise RuntimeError("evgenConfig.minevents is obsolete and should be removed from the JOs")
355 if evgenConfig.nEventsPerJob < 1:
356  raise RuntimeError("evgenConfig.nEventsPerJob must be at least 1")
357 elif evgenConfig.nEventsPerJob > 100000:
358  raise RuntimeError("evgenConfig.nEventsPerJob can be max. 100000")
359 else:
360  allowed_nEventsPerJob_lt1000 = [1, 2, 5, 10, 20, 25, 50, 100, 200, 500, 1000]
361  msg = "evgenConfig.nEventsPerJob = %d: " % evgenConfig.nEventsPerJob
362 
363  if evgenConfig.nEventsPerJob >= 1000 and evgenConfig.nEventsPerJob <=10000 and (evgenConfig.nEventsPerJob % 1000 != 0 or 10000 % evgenConfig.nEventsPerJob != 0):
364  msg += "nEventsPerJob in range [1K, 10K] must be a multiple of 1K and a divisor of 10K"
365  raise RuntimeError(msg)
366  elif evgenConfig.nEventsPerJob > 10000 and evgenConfig.nEventsPerJob % 10000 != 0:
367  msg += "nEventsPerJob >10K must be a multiple of 10K"
368  raise RuntimeError(msg)
369  elif evgenConfig.nEventsPerJob < 1000 and evgenConfig.nEventsPerJob not in allowed_nEventsPerJob_lt1000:
370  msg += "nEventsPerJob in range <= 1000 must be one of %s" % allowed_nEventsPerJob_lt1000
371  raise RuntimeError(msg)
372  postSeq.CountHepMC.RequestedOutput = evgenConfig.nEventsPerJob if runArgs.maxEvents == -1 else runArgs.maxEvents
373  evgenLog.info('Requested output events = '+str(postSeq.CountHepMC.RequestedOutput))
374 
375  # Special case of N<100: adjust TestHepMC. We will allow _one_ event to fail the checks.
376  # This means the minimum efficiency is N/N+1 for N generated events. Note that if N<100,
377  # each failed event costs us more than 1% of efficiency.
378  if hasattr(testSeq, "TestHepMC") and postSeq.CountHepMC.RequestedOutput<100:
379  testSeq.TestHepMC.EffFailThreshold = postSeq.CountHepMC.RequestedOutput/(postSeq.CountHepMC.RequestedOutput+1) - 0.01
380 
381 
382 if evgenConfig.keywords:
383  from GeneratorConfig.GenConfigHelpers import checkKeywords
384  checkKeywords(evgenConfig, evgenLog, officialJO)
385 
386 
387 if evgenConfig.categories:
388 
390  lkwfile = "CategoryList.txt"
391  lkwpath = None
392  for p in os.environ["DATAPATH"].split(":"):
393  lkwpath = os.path.join(p, lkwfile)
394  if os.path.exists(lkwpath):
395  break
396  lkwpath = None
397 
398  allowed_cat = []
399  if lkwpath:
400  with open(lkwpath, 'r') as catlist:
401  for line in catlist:
402  allowed_list = ast.literal_eval(line)
403  allowed_cat.append(allowed_list)
404 
405 
406  bad_cat =[]
407  it = iter(evgenConfig.categories)
408  for x in it:
409  l1 = x
410  l2 = next(it)
411  if "L1:" in l2 and "L2:" in l1:
412  l1, l2 = l2, l1
413  print ("first",l1,"second",l2)
414  bad_cat.extend([l1, l2])
415  for a1,a2 in allowed_cat:
416  if l1.strip().lower()==a1.strip().lower() and l2.strip().lower()==a2.strip().lower():
417  bad_cat=[]
418  if bad_cat:
419  msg = "evgenConfig.categories contains non-standard category: %s. " % ", ".join(bad_cat)
420  msg += "Please check the allowed categories list and fix."
421  evgenLog.error(msg)
422  if officialJO:
423  sys.exit(1)
424  else:
425  evgenLog.warning("Could not find CategoryList.txt file %s in $DATAPATH" % lkwfile)
426 
427 if hasattr( runArgs, "outputEVNTFile") or hasattr( runArgs, "outputEVNT_PreFile"):
428 
429  from AthenaPoolCnvSvc.WriteAthenaPool import AthenaPoolOutputStream
430  from AthenaPoolCnvSvc.AthenaPoolCnvSvcConf import AthenaPoolCnvSvc
431  if hasattr(runArgs, "outputEVNTFile"):
432  poolFile = runArgs.outputEVNTFile
433  elif hasattr(runArgs, "outputEVNT_PreFile"):
434  poolFile = runArgs.outputEVNT_PreFile
435  else:
436  raise RuntimeError("Output pool file, either EVNT or EVNT_Pre, is not known.")
437 
438  # ROOT inadvertently broke forward compatibility in v6.30+ (see root/issues/15964)
439  # This workaround is needed so that older releases can read files created by the new ones
440  # For more information see ATEAM-1001 and ATEAM-1015 (for DataHeaderForm)
441  svcMgr.AthenaPoolCnvSvc.PoolAttributes += [ f"DatabaseName = '{poolFile}'; FILEFORWARD_COMPATIBILITY = '1'" ]
442  svcMgr.AthenaPoolCnvSvc.OneDataHeaderForm = False
443 
444  StreamEVGEN = AthenaPoolOutputStream("StreamEVGEN", poolFile, noTag=True, eventInfoKey="EventInfo")
445 
446  StreamEVGEN.ForceRead = True
447  StreamEVGEN.ItemList += ["EventInfo#*", "xAOD::EventInfo#EventInfo*", "xAOD::EventAuxInfo#EventInfoAux.*", "McEventCollection#*"]
448  StreamEVGEN.RequireAlgs += ["EvgenFilterSeq"]
449 
450  if evgenConfig.saveJets:
451  StreamEVGEN.ItemList += ["xAOD::JetContainer#AntiKt4TruthJets", "xAOD::AuxContainerBase!#AntiKt4TruthJetsAux.-PseudoJet.-constituentLinks.-constituentWeights"]
452  StreamEVGEN.ItemList += ["xAOD::JetContainer#AntiKt6TruthJets", "xAOD::AuxContainerBase!#AntiKt6TruthJetsAux.-PseudoJet.-constituentLinks.-constituentWeights"]
453  if evgenConfig.savePileupTruthParticles:
454  StreamEVGEN.ItemList += ["xAOD::TruthParticleContainer#TruthPileupParticles*"]
455  StreamEVGEN.ItemList += ["xAOD::TruthParticleAuxContainer#TruthPileupParticlesAux.*"]
456 
457  # Remove any requested items from the ItemList so as not to write out
458  for removeItem in evgenConfig.doNotSaveItems: StreamEVGEN.ItemList.remove( removeItem )
459 
460  # Allow (re-)addition to the output stream
461  for addItem in evgenConfig.extraSaveItems: StreamEVGEN.ItemList += [ addItem ]
462 
463 
464 dsid = os.path.basename(runArgs.jobConfig[0])
465 if not dsid.isdigit():
466  dsid = "999999"
467 svcMgr.EventSelector.RunNumber = int(dsid)
468 
469 
470 from GeneratorConfig.Versioning import generatorsGetInitialVersionedDictionary, generatorsVersionedStringList
472 gennamesvers = generatorsVersionedStringList(gendict)
473 
474 import EventInfoMgt.EventInfoMgtInit
475 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"hepmc_version": "HepMC" + str(os.environ['HEPMCVER'])})
476 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"mc_channel_number":str(dsid)})
477 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"lhefGenerator": '+'.join( filter( gen_lhef, gennames ) ) })
478 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"generators": '+'.join(gennamesvers)})
479 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"evgenProcess": evgenConfig.process})
480 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"evgenTune": evgenConfig.tune})
481 if hasattr( evgenConfig, "hardPDF" ) : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"hardPDF": evgenConfig.hardPDF})
482 if hasattr( evgenConfig, "softPDF" ) : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"softPDF": evgenConfig.softPDF})
483 if hasattr( runArgs, "randomSeed") : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"randomSeed": str(runArgs.randomSeed)})
484 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"keywords": ", ".join(evgenConfig.keywords).lower()})
485 
486 # print version of HepMC to the log
487 evgenLog.info("HepMC version " + str(os.environ['HEPMCVER']))
488 
489 # Set AMITag in in-file metadata
490 from PyUtils import AMITagHelper
491 AMITagHelper.SetAMITag(runArgs=runArgs)
492 
493 
494 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"beam_energy": str(int(runArgs.ecmEnergy*Units.GeV/2.0))})
495 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"beam_type": 'collisions'})
496 
497 
498 from OutputStreamAthenaPool.OutputStreamAthenaPoolConf import CopyEventStreamInfo
499 streamInfoTool = CopyEventStreamInfo( "StreamEVGEN_CopyEventStreamInfo" )
500 ToolSvc += streamInfoTool
501 svcMgr.MetaDataSvc.MetaDataTools += [ streamInfoTool ]
502 
503 
505 include("EvgenJobTransforms/Generate_ecmenergies.py")
506 
507 if 'ParticleGun' in evgenConfig.generators:
508 
509  from RngComps.RngCompsConf import AtRndmGenSvc
510  svcMgr += AtRndmGenSvc()
511  include("EvgenJobTransforms/Generate_randomseeds.py")
512 else:
513 # Propagate DSID and seed to the generators
514  include("EvgenJobTransforms/Generate_dsid_ranseed.py")
515 
516 
517 if 'Hijing' in evgenConfig.generators or 'Herwig7' in evgenConfig.generators:
518  fixSeq.FixHepMC.PurgeUnstableWithoutEndVtx = True
519 
520 
521 if 'Sherpa' in evgenConfig.generators:
522  fixSeq.FixHepMC.IgnoreSemiDisconnected = True
523 
524 
525 if (hasattr( runArgs, "VERBOSE") and runArgs.VERBOSE ) or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "DEBUG") or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "VERBOSE"):
526  include("EvgenJobTransforms/Generate_debug_level.py")
527 
528 
529 svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"specialConfiguration": evgenConfig.specialConfig })
530 
531 
533 if hasattr(testSeq, "TestHepMC") and not gens_testhepmc(evgenConfig.generators):
534  evgenLog.info("Removing TestHepMC sanity checker")
535  del testSeq.TestHepMC
536 
537 
541 def checkBlockList(relFlavour,cache,generatorName) :
542  isError = None
543  with open('/cvmfs/atlas.cern.ch/repo/sw/Generators/MC16JobOptions/common/BlackList_caches.txt') as bfile:
544  for line in bfile.readlines():
545  if not line.strip():
546  continue
547  # Blocklisted release flavours
548  badRelFlav=line.split(',')[0].strip()
549  # Blocklisted caches
550  badCache=line.split(',')[1].strip()
551  # Blocklisted generators
552  badGens=line.split(',')[2].strip()
553 
554  used_gens = ','.join(generatorName)
555  #Match Generator and release type e.g. AtlasProduction, MCProd
556  if relFlavour==badRelFlav and cache==badCache and re.search(badGens,used_gens) is not None:
557  if badGens=="": badGens="all generators"
558  isError=relFlavour+","+cache+" is blocklisted for " + badGens
559  return isError
560  return isError
561 
562 def checkPurpleList(relFlavour,cache,generatorName) :
563  isError = None
564  with open('/cvmfs/atlas.cern.ch/repo/sw/Generators/MC16JobOptions/common/PurpleList_generators.txt') as bfile:
565  for line in bfile.readlines():
566  if not line.strip():
567  continue
568  # Purple-listed release flavours
569  purpleRelFlav=line.split(',')[0].strip()
570  # Purple-listed caches
571  purpleCache=line.split(',')[1].strip()
572  # Purple-listed generators
573  purpleGens=line.split(',')[2].strip()
574  # Purple-listed process
575  purpleProcess=line.split(',')[3].strip()
576 
577  used_gens = ','.join(generatorName)
578  #Match Generator and release type e.g. AtlasProduction, MCProd
579  if relFlavour==purpleRelFlav and cache==purpleCache and re.search(purpleGens,used_gens) is not None:
580  isError=relFlavour+","+cache+" is blocklisted for " + purpleGens + " if it uses " + purpleProcess
581  return isError
582  return isError
583 
584 
585 evgenLog.debug("****************** CHECKING RELEASE IS NOT BLACKLISTED *****************")
586 if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MC16JobOptions/common'):
587  errorBL = checkBlockList("AthGeneration",rel,gennames)
588  if (errorBL):
589  if (hasattr( runArgs, "ignoreBlackList") and runArgs.ignoreBlackList):
590  evgenLog.warning("This run is blocklisted for this generator, please use a different one for production !! "+ errorBL )
591  else:
592  raise RuntimeError("This run is blocklisted for this generator, please use a different one !! "+ errorBL)
593 
594  errorPL = checkPurpleList("AthGeneration",rel,gennames)
595  if (errorPL):
596  evgenLog.warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
597  evgenLog.warning("!!! WARNING !!! "+ errorPL )
598  evgenLog.warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
599 
600 else:
601  msg.waring("No access to cvmfs, so blocklisted runs will not be checked")
602 
605 
606 if hasattr(runArgs, "postInclude"):
607  for fragment in runArgs.postInclude:
608  include(fragment)
609 
610 if hasattr(runArgs, "postExec"):
611  evgenLog.info("Transform post-exec")
612  for cmd in runArgs.postExec:
613  evgenLog.info(cmd)
614  exec(cmd)
615 
616 
617 
620 acas.dumpMasterSequence()
621 
622 
623 
626 
627 
628 evgenLog.debug("****************** HANDLING EVGEN INPUT FILES *****************")
629 
630 
631 datFile = None
632 if "McAtNlo" in evgenConfig.generators and "Herwig" in evgenConfig.generators:
633  datFile = "inparmMcAtNlo.dat"
634 elif "Alpgen" in evgenConfig.generators:
635  datFile = "inparmAlpGen.dat"
636 elif "Protos" in evgenConfig.generators:
637  datFile = "protos.dat"
638 elif "ProtosLHEF" in evgenConfig.generators:
639  datFile = "protoslhef.dat"
640 elif "AcerMC" in evgenConfig.generators:
641  datFile = "inparmAcerMC.dat"
642 elif "CompHep" in evgenConfig.generators:
643  datFile = "inparmCompHep.dat"
644 
645 
646 eventsFile = None
647 if "Alpgen" in evgenConfig.generators:
648  eventsFile = "alpgen.unw_events"
649 elif "Protos" in evgenConfig.generators:
650  eventsFile = "protos.events"
651 elif "ProtosLHEF" in evgenConfig.generators:
652  eventsFile = "protoslhef.events"
653 elif "BeamHaloGenerator" in evgenConfig.generators:
654  eventsFile = "beamhalogen.events"
655 elif "HepMCAscii" in evgenConfig.generators:
656  eventsFile = "events.hepmc"
657 elif "ReadMcAscii" in evgenConfig.generators:
658  eventsFile = "events.hepmc"
659 elif gens_lhef(evgenConfig.generators):
660  eventsFile = "events.lhe"
661 
662 
663 
664 def find_unique_file(pattern):
665  "Return a matching file, provided it is unique"
666  import glob
667  files = glob.glob(pattern)
668 
669  if not files:
670  raise RuntimeError("No '%s' file found" % pattern)
671  elif len(files) > 1:
672  raise RuntimeError("More than one '%s' file found" % pattern)
673  return files[0]
674 
675 # This function merges a list of input LHE file to make one outputFile. The header is taken from the first
676 # file, but the number of events is updated to equal the total number of events in all the input files
677 def merge_lhe_files(listOfFiles,outputFile):
678  if(os.path.exists(outputFile)):
679  print ("outputFile ",outputFile," already exists. Will rename to ",outputFile,".OLD")
680  os.rename(outputFile,outputFile+".OLD")
681  output = open(outputFile,'w')
682  holdHeader = ""
683  nevents=0
684  for file in listOfFiles:
685  cmd = "grep /event "+file+" | wc -l"
686  nevents+=int(subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True))
687 
688  for file in listOfFiles:
689  inHeader = True
690  header = ""
691  print ("*** Starting file ",file)
692  for line in open(file,"r"):
693 
698  if("<event" in line and inHeader):
699  inHeader = False
700  if(len(holdHeader)<1):
701  holdHeader = header
702  output.write(header)
703  output.write(line)
704 
706  elif(not inHeader and not ("</LesHouchesEvents>" in line)):
707  output.write(line)
708  if(inHeader):
709 
710  if("nevents" in line):
711 
712  tmp = line.split("=")
713  line = line.replace(tmp[0],str(nevents))
714  elif("numevts" in line):
715 
716  tmp = line.split(" ")
717  nnn = str(nevents)
718  line = line.replace(tmp[1],nnn)
719  header+=line
720  output.write("</LesHouchesEvents>\n")
721  output.close()
722 
723 
724 def mk_symlink(srcfile, dstfile):
725  "Make a symlink safely"
726  if dstfile:
727  if os.path.exists(dstfile) and not os.path.samefile(dstfile, srcfile):
728  os.remove(dstfile)
729  if not os.path.exists(dstfile):
730  evgenLog.info("Symlinking %s to %s" % (srcfile, dstfile))
731  print ("Symlinking %s to %s" % (srcfile, dstfile))
732  os.symlink(srcfile, dstfile)
733  else:
734  evgenLog.debug("Symlinking: %s is already the same as %s" % (dstfile, srcfile))
735 
736 
737 if eventsFile or datFile:
738  if not hasattr(runArgs, "inputGeneratorFile") or runArgs.inputGeneratorFile == "NONE":
739  raise RuntimeError("%s needs input file (argument inputGeneratorFile)" % runArgs.jobConfig)
740  if evgenConfig.inputfilecheck and not re.search(evgenConfig.inputfilecheck, runArgs.inputGeneratorFile):
741  raise RuntimeError("inputGeneratorFile=%s is incompatible with inputfilecheck '%s' in %s" %
742  (runArgs.inputGeneratorFile, evgenConfig.inputfilecheck, runArgs.jobConfig))
743  if datFile:
744  if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
745  inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
746  else:
747  inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
748 
749  realDatFile = find_unique_file('*%s*.dat' % inputroot)
750  mk_symlink(realDatFile, datFile)
751  if eventsFile:
752  myinputfiles = runArgs.inputGeneratorFile
753  genInputFiles = myinputfiles.split(',')
754  numberOfFiles = len(genInputFiles)
755  # if there is a single file, make a symlink. If multiple files, merge them into one output eventsFile
756  if(numberOfFiles<2):
757  if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
758  inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
759  else:
760  inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
761 
762  if "events" in inputroot :
763  inputroot = inputroot.replace(".events","")
764  realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
765  mk_symlink(realEventsFile, eventsFile)
766  else:
767  allFiles = []
768  for file in genInputFiles:
769 # Since we can have multiple files from the same task, inputroot must include more of the filename
770 # to make it unique
771  if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
772  inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
773  else:
774  input0 = os.path.basename(file).split("._")[0]
775  input1 = (os.path.basename(file).split("._")[1]).split(".")[0]
776  inputroot = input0+"._"+input1
777  evgenLog.info("inputroot = %s",inputroot)
778  realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
779 # The only input format where merging is permitted is LHE
780  with open(realEventsFile, 'r') as f:
781  first_line = f.readline()
782  if(not ("LesHouche" in first_line)):
783  raise RuntimeError("%s is NOT a LesHouche file" % realEventsFile)
784  allFiles.append(realEventsFile)
785  merge_lhe_files(allFiles,eventsFile)
786 
787 else:
788  if hasattr(runArgs, "inputGeneratorFile") and runArgs.inputGeneratorFile != "NONE":
789  raise RuntimeError("inputGeneratorFile arg specified for %s, but generators %s do not require an input file" %
790  (runArgs.jobConfig, str(gennames)))
791  if evgenConfig.inputfilecheck:
792  raise RuntimeError("evgenConfig.inputfilecheck specified in %s, but generators %s do not require an input file" %
793  (runArgs.jobConfig, str(gennames)))
794 
795 
796 if evgenConfig.auxfiles:
797  from PyJobTransformsCore.trfutil import get_files
798  get_files(evgenConfig.auxfiles, keepDir=False, errorIfNotFound=True)
799 
800 
801 
804 
805 def _checkattr(attr, required=False):
806  if not hasattr(evgenConfig, attr) or not getattr(evgenConfig, attr):
807  msg = "evgenConfig attribute '%s' not found." % attr
808  if required:
809  raise RuntimeError("Required " + msg)
810  return False
811  return True
812 
813 if hasattr(runArgs, "outputTXTFile"):
814  # counting the number of events in LHE output
815  count_ev = 0
816  with open(eventsFile) as f:
817  for line in f:
818  count_ev += line.count('/event')
819 
820  print("MetaData: %s = %s" % ("Number of produced LHE events ", count_ev))
821 elif hasattr(runArgs, "inputGeneratorFile"):
822  # counting the number of events in LHE input
823  count_ev = 0
824  with open(eventsFile) as f:
825  for line in f:
826  count_ev += line.count('/event')
827 
828  print("MetaData: %s = %s" % ("Number of input LHE events ", count_ev))
829 
830 
831 if _checkattr("description", required=True):
832  msg = evgenConfig.description
833  if _checkattr("notes"):
834  msg += " " + evgenConfig.notes
835  print ("MetaData: %s = %s" % ("physicsComment", msg))
836 
837 if _checkattr("generators", required=True):
838  print ("MetaData: %s = %s" % ("generatorName", "+".join(gennamesvers)))
839 if _checkattr("process"):
840  print ("MetaData: %s = %s" % ("physicsProcess", evgenConfig.process))
841 if _checkattr("tune"):
842  print ("MetaData: %s = %s" % ("generatorTune", evgenConfig.tune))
843 if _checkattr("hardPDF"):
844  print ("MetaData: %s = %s" % ("hardPDF", evgenConfig.hardPDF))
845 if _checkattr("softPDF"):
846  print ("MetaData: %s = %s" % ("softPDF", evgenConfig.softPDF))
847 if _checkattr("nEventsPerJob"):
848  print ("MetaData: %s = %s" % ("nEventsPerJob", evgenConfig.nEventsPerJob))
849 if _checkattr("keywords"):
850  print ("MetaData: %s = %s" % ("keywords", ", ".join(evgenConfig.keywords).lower()))
851 if _checkattr("categories"):
852  print ("MetaData: %s = %s" % ("categories", ", ".join(evgenConfig.categories)))
853 if _checkattr("specialConfig"):
854  print ("MetaData: %s = %s" % ("specialConfig", evgenConfig.specialConfig))
855 # TODO: Require that a contact / JO author is always set
856 if _checkattr("contact"):
857  print ("MetaData: %s = %s" % ("contactPhysicist", ", ".join(evgenConfig.contact)))
858 print ("MetaData: %s = %s" % ("randomSeed", str(runArgs.randomSeed)))
859 
860 # Output list of generator filters used
861 filterNames = [alg.getType() for alg in acas.iter_algseq(filtSeq)]
862 excludedNames = ['AthSequencer', 'PyAthena::Alg', 'TestHepMC']
863 filterNames = list(set(filterNames) - set(excludedNames))
864 print ("MetaData: %s = %s" % ("genFilterNames", ", ".join(filterNames)))
865 
866 if (hasattr( runArgs, "allowOldFilter") and runArgs.allowOldFilter):
867  for alg in acas.iter_algseq(filtSeq):
868  filtName = alg.getType()
869  exceptName =['xAOD','Jet']
870  if filtName not in excludedNames:
871  if not any(ex in filtName for ex in exceptName):
872  alg.AllowOldFilter=True
873 
874 
877 
878 from PyJobTransformsCore.runargs import RunArguments
879 runPars = RunArguments()
880 runPars.nEventsPerJob = evgenConfig.nEventsPerJob
881 runPars.maxeventsstrategy = evgenConfig.maxeventsstrategy
882 with open("config.pickle", "wb") as f:
883  import pickle
884  pickle.dump(runPars, f)
885 
886 
887 
890 evgenLog.info("****************** STARTING EVENT GENERATION *****************")
read
IovVectorMap_t read(const Folder &theFolder, const SelectionCriterion &choice, const unsigned int limit=10)
Definition: openCoraCool.cxx:569
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename R::value_type > sorted(const R &r, PROJ proj={})
Helper function to create a sorted vector from an unsorted range.
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
createLinkingScheme.iter
iter
Definition: createLinkingScheme.py:62
python.GenConfigHelpers.gens_testhepmc
def gens_testhepmc(gennames)
Definition: GenConfigHelpers.py:77
skel.find_unique_file
def find_unique_file(pattern)
Helper functions for input file handling.
Definition: skel.ABtoEVGEN.py:473
RngCompsConfig.AtRndmGenSvc
AtRndmGenSvc
Definition: RngCompsConfig.py:9
trfutil
skel.merge_lhe_files
def merge_lhe_files(listOfFiles, outputFile)
Check that there is exactly 1 match.
Definition: skel.GENtoEVGEN.py:677
skel.checkBlockList
def checkBlockList(relFlavour, cache, generatorName)
Propagate debug output level requirement to generators.
Definition: skel.GENtoEVGEN.py:541
covarianceTool.filter
filter
Definition: covarianceTool.py:514
skel.OutputTXTFile
def OutputTXTFile()
==============================================================
Definition: skel.ABtoEVGEN.py:181
find_unique_file
Definition: find_unique_file.py:1
fillPileUpNoiseLumi.next
next
Definition: fillPileUpNoiseLumi.py:52
LArG4FSStartPointFilter.exec
exec
Definition: LArG4FSStartPointFilter.py:103
python.GenConfigHelpers.gen_require_steering
def gen_require_steering(gennames)
Definition: GenConfigHelpers.py:50
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
LogicalExpressionFilter
Definition: LogicalExpressionFilter.py:1
python.Versioning.generatorsGetInitialVersionedDictionary
def generatorsGetInitialVersionedDictionary(generators)
Definition: Versioning.py:40
python.GenConfigHelpers.gens_notune
def gens_notune(gennames)
Definition: GenConfigHelpers.py:85
skel._short2
def _short2(s)
Definition: skel.ABtoEVGEN.py:272
python.GenConfigHelpers.gens_lhef
def gens_lhef(gennames)
Definition: GenConfigHelpers.py:69
RngCompsConfig.AthRNGSvc
AthRNGSvc
Definition: RngCompsConfig.py:9
python.Include.include
include
Definition: Include.py:318
python.GenConfigHelpers.checkKeywords
def checkKeywords(sample, evgenLog, officialJO)
Definition: GenConfigHelpers.py:151
merge_lhe_files
Definition: merge_lhe_files.py:1
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
print
void print(char *figname, TCanvas *c1)
Definition: TRTCalib_StrawStatusPlots.cxx:25
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
skel._norm
def _norm(s)
Definition: skel.ABtoEVGEN.py:266
skel.checkPurpleList
def checkPurpleList(relFlavour, cache, generatorName)
Definition: skel.GENtoEVGEN.py:562
python.Versioning.generatorsVersionedStringList
def generatorsVersionedStringList(generatorsDictionary)
Definition: Versioning.py:59
Lb2Lll.THistSvc
THistSvc
Definition: Lb2Lll.py:216
skel.get_immediate_subdirectories
def get_immediate_subdirectories(a_dir)
==============================================================
Definition: skel.GENtoEVGEN.py:207
Trk::open
@ open
Definition: BinningType.h:40
skel._checkattr
def _checkattr(attr, required=False)
==============================================================
Definition: skel.ABtoEVGEN.py:506
skel.mk_symlink
def mk_symlink(srcfile, dstfile)
Definition: skel.ABtoEVGEN.py:484
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
if
if(febId1==febId2)
Definition: LArRodBlockPhysicsV0.cxx:567
skel._norm2
def _norm2(s)
Definition: skel.ABtoEVGEN.py:269
str
Definition: BTagTrackIpAccessor.cxx:11
python.CreateOutputStreams.AthenaPoolOutputStream
def AthenaPoolOutputStream
backward compat
Definition: CreateOutputStreams.py:143
python.trfutil.get_files
def get_files(listOfFiles, fromWhere='data', doCopy='ifNotLocal', errorIfNotFound=True, keepDir=True, depth=0, sep=os.pathsep)
Definition: trfutil.py:40
Cut::all
@ all
Definition: SUSYToolsAlg.cxx:67
Trk::split
@ split
Definition: LayerMaterialProperties.h:38