ATLAS Offline Software
Loading...
Searching...
No Matches
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
12import ast
13import os, re, string, subprocess
14import AthenaCommon.AlgSequence as acas
15import AthenaCommon.AppMgr as acam
16from AthenaCommon.AthenaCommonFlags import jobproperties
17
18from xAODEventInfoCnv.xAODEventInfoCnvConf import xAODMaker__EventInfoCnvAlg
19acam.athMasterSeq += xAODMaker__EventInfoCnvAlg(xAODKey="TMPEvtInfo")
20
21theApp = acam.theApp
22acam.athMasterSeq += acas.AlgSequence("EvgenGenSeq")
23genSeq = acam.athMasterSeq.EvgenGenSeq
24acam.athMasterSeq += acas.AlgSequence("EvgenFixSeq")
25fixSeq = acam.athMasterSeq.EvgenFixSeq
26acam.athMasterSeq += acas.AlgSequence("EvgenPreFilterSeq")
27prefiltSeq = acam.athMasterSeq.EvgenPreFilterSeq
28acam.athMasterSeq += acas.AlgSequence("EvgenTestSeq")
29testSeq = acam.athMasterSeq.EvgenTestSeq
30
31from EvgenProdTools.LogicalExpressionFilter import LogicalExpressionFilter
32acam.athMasterSeq += LogicalExpressionFilter("EvgenFilterSeq")
33filtSeq = acam.athMasterSeq.EvgenFilterSeq
34topSeq = acas.AlgSequence()
35anaSeq = topSeq
36topSeq += acas.AlgSequence("EvgenPostSeq")
37postSeq = topSeq.EvgenPostSeq
38#topAlg = topSeq #< alias commented out for now, so that accidental use throws an error
39
40
41
44
45
46import AthenaCommon.AtlasUnixGeneratorJob
47include("PartPropSvc/PartPropSvc.py")
48
49
50from PerfMonComps.PerfMonFlags import jobproperties as perfmonjp
51perfmonjp.PerfMonFlags.doFastMonMT = True
52
53
54from RngComps.RngCompsConf import AthRNGSvc
55svcMgr += AthRNGSvc()
56
57
58jobproperties.AthenaCommonFlags.AllowIgnoreConfigError = False
59
60
61from AthenaCommon.Logging import logging
62evgenLog = logging.getLogger('Gen_tf')
63
64
67
68
69evgenLog.debug("****************** CHECKING EVENT GENERATION ARGS *****************")
70evgenLog.debug(str(runArgs))
71
72if hasattr(runArgs, "inputGeneratorFile"):
73 evgenLog.info("inputGeneratorFile = " + runArgs.inputGeneratorFile)
74
75if hasattr(runArgs, "outputYODAFile"):
76 evgenLog.info("specified outputYODAFile = " + runArgs.outputYODAFile)
77
78
80if 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
88if not hasattr(runArgs, "ecmEnergy"):
89 raise RuntimeError("No center of mass energy provided.")
90else:
91 evgenLog.info('ecmEnergy = ' + str(runArgs.ecmEnergy) )
92if not hasattr(runArgs, "randomSeed"):
93 raise RuntimeError("No random seed provided.")
94 # TODO: or guess it from the JO name??
95if not hasattr(runArgs, "firstEvent"):
96 raise RuntimeError("No first number provided.")
97if ( runArgs.firstEvent <= 0):
98 evgenLog.warning("Run argument firstEvent should be > 0")
99
100
103
104
105evgenLog.debug("****************** CONFIGURING EVENT GENERATION *****************")
106
107
109from EvgenJobTransforms.EvgenConfig import evgenConfig
110from GeneratorConfig.GenConfigHelpers import gens_known, gen_lhef, gens_lhef, gen_sortkey, gens_testhepmc, gens_notune, gen_require_steering, gens_purgenoendvtx
111
112
113from EvgenProdTools.EvgenProdToolsConf import FixHepMC
114if not hasattr(fixSeq, "FixHepMC"):
115 fixSeq += FixHepMC()
116
117
118from EvgenProdTools.EvgenProdToolsConf import TestHepMC
119testSeq += TestHepMC(CmEnergy=runArgs.ecmEnergy*Units.GeV)
120#testSeq += TestHepMC(CmEnergy=runArgs.ecmEnergy)
121if not hasattr(svcMgr, 'THistSvc'):
122 from GaudiSvc.GaudiSvcConf import THistSvc
123 svcMgr += THistSvc()
124svcMgr.THistSvc.Output = ["TestHepMCname DATAFILE='TestHepMC.root' OPT='RECREATE'"]
125
126
128from EvgenProdTools.EvgenProdToolsConf import CopyEventWeight
129if not hasattr(postSeq, "CopyEventWeight"):
130 postSeq += CopyEventWeight(mcEventWeightsKey="TMPEvtInfo.mcEventWeights")
131
132from EvgenProdTools.EvgenProdToolsConf import FillFilterValues
133if not hasattr(postSeq, "FillFilterValues"):
134 postSeq += FillFilterValues(mcFilterHTKey="TMPEvtInfo.mcFilterHT")
135
136
138from EvgenProdTools.EvgenProdToolsConf import CountHepMC
139svcMgr.EventSelector.FirstEvent = runArgs.firstEvent
140theApp.EvtMax = -1
141# This is necessary for athenaMP # commented out for now
142#if hasattr(runArgs, "maxEvents"):
143# theApp.EvtMax = runArgs.maxEvents
144
145if not hasattr(postSeq, "CountHepMC"):
146 postSeq += CountHepMC(InputEventInfo="TMPEvtInfo",
147 OutputEventInfo="EventInfo",
148 mcEventWeightsKey="mcEventWeights")
149#postSeq.CountHepMC.RequestedOutput = evgenConfig.nEventsPerJob if runArgs.maxEvents == -1 else runArgs.maxEvents
150
151postSeq.CountHepMC.FirstEvent = runArgs.firstEvent
152postSeq.CountHepMC.CorrectHepMC = True
153postSeq.CountHepMC.CorrectEventID = True
154
155
157if 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
167from EvgenProdTools.EvgenProdToolsConf import SimTimeEstimate
168if not hasattr(postSeq, "SimTimeEstimate"):
169 postSeq += SimTimeEstimate()
170
171
173if 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
182rel = os.popen("echo $AtlasVersion").read()
183rel = rel.strip()
184if 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
193evgenLog.debug("****************** LOADING PRE-INCLUDES AND JOB CONFIG *****************")
194
195
196if hasattr(runArgs, "preInclude"):
197 for fragment in runArgs.preInclude:
198 include(fragment)
199
200
201if 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!!!
212def OutputTXTFile():
213 outputTXTFile = None
214 if hasattr(runArgs,"outputTXTFile"): outputTXTFile=runArgs.outputTXTFile
215 return outputTXTFile
216
218if 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
223evgenLog.info("Using JOBOPTSEARCHPATH (as seen in skeleton) = '%s'" % os.environ["JOBOPTSEARCHPATH"])
224FIRST_DIR = (os.environ['JOBOPTSEARCHPATH']).split(":")[0]
225
226jofiles = [f for f in os.listdir(FIRST_DIR) if (f.startswith('mc') and f.endswith('.py'))]
227if len(jofiles) !=1:
228 evgenLog.error("You must supply one and only one jobOption file in DSID directory")
229 sys.exit(1)
230jofile = jofiles[0]
231
232joparts = (os.path.basename(jofile)).split(".")
233
234officialJO = False
235if 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
262include(jofile)
263
264
267
268
269evgenLog.debug("****************** CHECKING EVGEN CONFIGURATION *****************")
270
271if hasattr(runArgs,'inputGeneratorFile') and int(evgenConfig.inputFilesPerJob) == 0 :
272 evgenConfig.inputFilesPerJob = 1
273
274
275for opt in str(evgenConfig).split(os.linesep):
276 evgenLog.info(opt)
277evgenLog.info(".transform = Gen_tf")
278
279
280evgenLog.info(".platform = "+str(os.environ['BINARY_TAG']))
281
282
285if evgenConfig.obsolete:
286 evgenLog.error("JOs or icludes are obsolete, please check them")
287 sys.exit(1)
288
289if not evgenConfig.generators:
290 evgenLog.error("No entries in evgenConfig.generators: invalid configuration, please check your JO")
291 sys.exit(1)
292
293if 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
297gennames = sorted(evgenConfig.generators, key=gen_sortkey)
298
299if 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
333if 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
340rounding = 0
341if hasattr(runArgs,'inputGeneratorFile') and ',' in runArgs.inputGeneratorFile: multiInput = runArgs.inputGeneratorFile.count(',')+1
342else:
343 multiInput = 0
344
345# check if default nEventsPerJob used
346if not evgenConfig.nEventsPerJob:
347 evgenLog.info('#############################################################')
348 evgenLog.info(' !!!! no nEventsPerJob set !!! The default 10000 used. !!! ')
349 evgenLog.info('#############################################################')
350else:
351 evgenLog.info(' nEventsPerJob = ' + str(evgenConfig.nEventsPerJob) )
352
353if evgenConfig.minevents > 0 :
354 raise RuntimeError("evgenConfig.minevents is obsolete and should be removed from the JOs")
355if evgenConfig.nEventsPerJob < 1:
356 raise RuntimeError("evgenConfig.nEventsPerJob must be at least 1")
357elif evgenConfig.nEventsPerJob > 100000:
358 raise RuntimeError("evgenConfig.nEventsPerJob can be max. 100000")
359else:
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
382if evgenConfig.keywords:
383 from GeneratorConfig.GenConfigHelpers import checkKeywords
384 checkKeywords(evgenConfig, evgenLog, officialJO)
385
386
387if 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
427if 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
464dsid = os.path.basename(runArgs.jobConfig[0])
465if not dsid.isdigit():
466 dsid = "999999"
467svcMgr.EventSelector.RunNumber = int(dsid)
468
469
470from GeneratorConfig.Versioning import generatorsGetInitialVersionedDictionary, generatorsVersionedStringList
471gendict = generatorsGetInitialVersionedDictionary(gennames)
472gennamesvers = generatorsVersionedStringList(gendict)
473
474import EventInfoMgt.EventInfoMgtInit
475svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"hepmc_version": "HepMC" + str(os.environ['HEPMCVER'])})
476svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"mc_channel_number":str(dsid)})
477svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"lhefGenerator": '+'.join( filter( gen_lhef, gennames ) ) })
478svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"generators": '+'.join(gennamesvers)})
479svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"evgenProcess": evgenConfig.process})
480svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"evgenTune": evgenConfig.tune})
481if hasattr( evgenConfig, "hardPDF" ) : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"hardPDF": evgenConfig.hardPDF})
482if hasattr( evgenConfig, "softPDF" ) : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"softPDF": evgenConfig.softPDF})
483if hasattr( runArgs, "randomSeed") : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"randomSeed": str(runArgs.randomSeed)})
484svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"keywords": ", ".join(evgenConfig.keywords).lower()})
485
486# print version of HepMC to the log
487evgenLog.info("HepMC version " + str(os.environ['HEPMCVER']))
488
489# Set AMITag in in-file metadata
490from PyUtils import AMITagHelper
491AMITagHelper.SetAMITag(runArgs=runArgs)
492
493
494svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"beam_energy": str(int(runArgs.ecmEnergy*Units.GeV/2.0))})
495svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"beam_type": 'collisions'})
496
497
498from OutputStreamAthenaPool.OutputStreamAthenaPoolConf import CopyEventStreamInfo
499streamInfoTool = CopyEventStreamInfo( "StreamEVGEN_CopyEventStreamInfo" )
500ToolSvc += streamInfoTool
501svcMgr.MetaDataSvc.MetaDataTools += [ streamInfoTool ]
502
503
505include("EvgenJobTransforms/Generate_ecmenergies.py")
506
507if 'ParticleGun' in evgenConfig.generators:
508
509 from RngComps.RngCompsConf import AtRndmGenSvc
510 svcMgr += AtRndmGenSvc()
511 include("EvgenJobTransforms/Generate_randomseeds.py")
512else:
513# Propagate DSID and seed to the generators
514 include("EvgenJobTransforms/Generate_dsid_ranseed.py")
515
516
517generatorsList = evgenConfig.generators.copy()
518if hasattr(genSeq, "Pythia8"):
519 if (hasattr(genSeq.Pythia8, "Beam1") and genSeq.Pythia8.Beam1 != "PROTON" ) or \
520 (hasattr(genSeq.Pythia8, "Beam2") and genSeq.Pythia8.Beam2 != "PROTON" ):
521 # generator name is still "Pythia8", even when colliding nuclei
522 generatorsList.append("Pythia8-Angantyr")
523if gens_purgenoendvtx(generatorsList):
524 fixSeq.FixHepMC.PurgeUnstableWithoutEndVtx = True
525
526
527if 'Sherpa' in evgenConfig.generators:
528 fixSeq.FixHepMC.IgnoreSemiDisconnected = True
529
530
531if (hasattr( runArgs, "VERBOSE") and runArgs.VERBOSE ) or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "DEBUG") or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "VERBOSE"):
532 include("EvgenJobTransforms/Generate_debug_level.py")
533
534
535svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"specialConfiguration": evgenConfig.specialConfig })
536
537
539if hasattr(testSeq, "TestHepMC") and not gens_testhepmc(evgenConfig.generators):
540 evgenLog.info("Removing TestHepMC sanity checker")
541 del testSeq.TestHepMC
542
543
547def checkBlockList(relFlavour,cache,generatorName) :
548 isError = None
549 with open('/cvmfs/atlas.cern.ch/repo/sw/Generators/MC16JobOptions/common/BlackList_caches.txt') as bfile:
550 for line in bfile.readlines():
551 if not line.strip():
552 continue
553 # Blocklisted release flavours
554 badRelFlav=line.split(',')[0].strip()
555 # Blocklisted caches
556 badCache=line.split(',')[1].strip()
557 # Blocklisted generators
558 badGens=line.split(',')[2].strip()
559
560 used_gens = ','.join(generatorName)
561 #Match Generator and release type e.g. AtlasProduction, MCProd
562 if relFlavour==badRelFlav and cache==badCache and re.search(badGens,used_gens) is not None:
563 if badGens=="": badGens="all generators"
564 isError=relFlavour+","+cache+" is blocklisted for " + badGens
565 return isError
566 return isError
567
568def checkPurpleList(relFlavour,cache,generatorName) :
569 isError = None
570 with open('/cvmfs/atlas.cern.ch/repo/sw/Generators/MC16JobOptions/common/PurpleList_generators.txt') as bfile:
571 for line in bfile.readlines():
572 if not line.strip():
573 continue
574 # Purple-listed release flavours
575 purpleRelFlav=line.split(',')[0].strip()
576 # Purple-listed caches
577 purpleCache=line.split(',')[1].strip()
578 # Purple-listed generators
579 purpleGens=line.split(',')[2].strip()
580 # Purple-listed process
581 purpleProcess=line.split(',')[3].strip()
582
583 used_gens = ','.join(generatorName)
584 #Match Generator and release type e.g. AtlasProduction, MCProd
585 if relFlavour==purpleRelFlav and cache==purpleCache and re.search(purpleGens,used_gens) is not None:
586 isError=relFlavour+","+cache+" is blocklisted for " + purpleGens + " if it uses " + purpleProcess
587 return isError
588 return isError
589
590
591evgenLog.debug("****************** CHECKING RELEASE IS NOT BLACKLISTED *****************")
592if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MC16JobOptions/common'):
593 errorBL = checkBlockList("AthGeneration",rel,gennames)
594 if (errorBL):
595 if (hasattr( runArgs, "ignoreBlackList") and runArgs.ignoreBlackList):
596 evgenLog.warning("This run is blocklisted for this generator, please use a different one for production !! "+ errorBL )
597 else:
598 raise RuntimeError("This run is blocklisted for this generator, please use a different one !! "+ errorBL)
599
600 errorPL = checkPurpleList("AthGeneration",rel,gennames)
601 if (errorPL):
602 evgenLog.warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
603 evgenLog.warning("!!! WARNING !!! "+ errorPL )
604 evgenLog.warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
605
606else:
607 msg.waring("No access to cvmfs, so blocklisted runs will not be checked")
608
611
612if hasattr(runArgs, "postInclude"):
613 for fragment in runArgs.postInclude:
614 include(fragment)
615
616if hasattr(runArgs, "postExec"):
617 evgenLog.info("Transform post-exec")
618 for cmd in runArgs.postExec:
619 evgenLog.info(cmd)
620 exec(cmd)
621
622
623
626acas.dumpMasterSequence()
627
628
629
632
633
634evgenLog.debug("****************** HANDLING EVGEN INPUT FILES *****************")
635
636
637datFile = None
638if "McAtNlo" in evgenConfig.generators and "Herwig" in evgenConfig.generators:
639 datFile = "inparmMcAtNlo.dat"
640elif "Alpgen" in evgenConfig.generators:
641 datFile = "inparmAlpGen.dat"
642elif "Protos" in evgenConfig.generators:
643 datFile = "protos.dat"
644elif "ProtosLHEF" in evgenConfig.generators:
645 datFile = "protoslhef.dat"
646elif "AcerMC" in evgenConfig.generators:
647 datFile = "inparmAcerMC.dat"
648elif "CompHep" in evgenConfig.generators:
649 datFile = "inparmCompHep.dat"
650
651
652eventsFile = None
653if "Alpgen" in evgenConfig.generators:
654 eventsFile = "alpgen.unw_events"
655elif "Protos" in evgenConfig.generators:
656 eventsFile = "protos.events"
657elif "ProtosLHEF" in evgenConfig.generators:
658 eventsFile = "protoslhef.events"
659elif "BeamHaloGenerator" in evgenConfig.generators:
660 eventsFile = "beamhalogen.events"
661elif "HepMCAscii" in evgenConfig.generators:
662 eventsFile = "events.hepmc"
663elif "ReadMcAscii" in evgenConfig.generators:
664 eventsFile = "events.hepmc"
665elif gens_lhef(evgenConfig.generators):
666 eventsFile = "events.lhe"
667
668
669
670def find_unique_file(pattern):
671 "Return a matching file, provided it is unique"
672 import glob
673 files = glob.glob(pattern)
674
675 if not files:
676 raise RuntimeError("No '%s' file found" % pattern)
677 elif len(files) > 1:
678 raise RuntimeError("More than one '%s' file found" % pattern)
679 return files[0]
680
681# This function merges a list of input LHE file to make one outputFile. The header is taken from the first
682# file, but the number of events is updated to equal the total number of events in all the input files
683def merge_lhe_files(listOfFiles,outputFile):
684 if(os.path.exists(outputFile)):
685 print ("outputFile ",outputFile," already exists. Will rename to ",outputFile,".OLD")
686 os.rename(outputFile,outputFile+".OLD")
687 output = open(outputFile,'w')
688 holdHeader = ""
689 nevents=0
690 for file in listOfFiles:
691 cmd = "grep /event "+file+" | wc -l"
692 nevents+=int(subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True))
693
694 for file in listOfFiles:
695 inHeader = True
696 header = ""
697 print ("*** Starting file ",file)
698 for line in open(file,"r"):
699
704 if("<event" in line and inHeader):
705 inHeader = False
706 if(len(holdHeader)<1):
707 holdHeader = header
708 output.write(header)
709 output.write(line)
710
712 elif(not inHeader and not ("</LesHouchesEvents>" in line)):
713 output.write(line)
714 if(inHeader):
715
716 if("nevents" in line):
717
718 tmp = line.split("=")
719 line = line.replace(tmp[0],str(nevents))
720 elif("numevts" in line):
721
722 tmp = line.split(" ")
723 nnn = str(nevents)
724 line = line.replace(tmp[1],nnn)
725 header+=line
726 output.write("</LesHouchesEvents>\n")
727 output.close()
728
729
730def mk_symlink(srcfile, dstfile):
731 "Make a symlink safely"
732 if dstfile:
733 if os.path.exists(dstfile) and not os.path.samefile(dstfile, srcfile):
734 os.remove(dstfile)
735 if not os.path.exists(dstfile):
736 evgenLog.info("Symlinking %s to %s" % (srcfile, dstfile))
737 print ("Symlinking %s to %s" % (srcfile, dstfile))
738 os.symlink(srcfile, dstfile)
739 else:
740 evgenLog.debug("Symlinking: %s is already the same as %s" % (dstfile, srcfile))
741
742
743if eventsFile or datFile:
744 if not hasattr(runArgs, "inputGeneratorFile") or runArgs.inputGeneratorFile == "NONE":
745 raise RuntimeError("%s needs input file (argument inputGeneratorFile)" % runArgs.jobConfig)
746 if evgenConfig.inputfilecheck and not re.search(evgenConfig.inputfilecheck, runArgs.inputGeneratorFile):
747 raise RuntimeError("inputGeneratorFile=%s is incompatible with inputfilecheck '%s' in %s" %
748 (runArgs.inputGeneratorFile, evgenConfig.inputfilecheck, runArgs.jobConfig))
749 if datFile:
750 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
751 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
752 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
753 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
754 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
755 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
756 else:
757 inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
758
759 realDatFile = find_unique_file('*%s*.dat' % inputroot)
760 mk_symlink(realDatFile, datFile)
761 if eventsFile:
762 myinputfiles = runArgs.inputGeneratorFile
763 genInputFiles = myinputfiles.split(',')
764 numberOfFiles = len(genInputFiles)
765 # if there is a single file, make a symlink. If multiple files, merge them into one output eventsFile
766 if(numberOfFiles<2):
767 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
768 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
769 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
770 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
771 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
772 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
773 else:
774 inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
775
776 if "events" in inputroot :
777 inputroot = inputroot.replace(".events","")
778 realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
779 mk_symlink(realEventsFile, eventsFile)
780 else:
781 allFiles = []
782 for file in genInputFiles:
783# Since we can have multiple files from the same task, inputroot must include more of the filename
784# to make it unique
785 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
786 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
787 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
788 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
789 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
790 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
791 else:
792 input0 = os.path.basename(file).split("._")[0]
793 input1 = (os.path.basename(file).split("._")[1]).split(".")[0]
794 inputroot = input0+"._"+input1
795 evgenLog.info("inputroot = %s",inputroot)
796 realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
797# The only input format where merging is permitted is LHE
798 with open(realEventsFile, 'r') as f:
799 first_line = f.readline()
800 if(not ("LesHouche" in first_line)):
801 raise RuntimeError("%s is NOT a LesHouche file" % realEventsFile)
802 allFiles.append(realEventsFile)
803 merge_lhe_files(allFiles,eventsFile)
804
805else:
806 if hasattr(runArgs, "inputGeneratorFile") and runArgs.inputGeneratorFile != "NONE":
807 raise RuntimeError("inputGeneratorFile arg specified for %s, but generators %s do not require an input file" %
808 (runArgs.jobConfig, str(gennames)))
809 if evgenConfig.inputfilecheck:
810 raise RuntimeError("evgenConfig.inputfilecheck specified in %s, but generators %s do not require an input file" %
811 (runArgs.jobConfig, str(gennames)))
812
813
814if evgenConfig.auxfiles:
815 from PyJobTransformsCore.trfutil import get_files
816 get_files(evgenConfig.auxfiles, keepDir=False, errorIfNotFound=True)
817
818
819
822
823def _checkattr(attr, required=False):
824 if not hasattr(evgenConfig, attr) or not getattr(evgenConfig, attr):
825 msg = "evgenConfig attribute '%s' not found." % attr
826 if required:
827 raise RuntimeError("Required " + msg)
828 return False
829 return True
830
831if hasattr(runArgs, "outputTXTFile"):
832 # counting the number of events in LHE output
833 count_ev = 0
834 with open(eventsFile) as f:
835 for line in f:
836 count_ev += line.count('/event')
837
838 print("MetaData: %s = %s" % ("Number of produced LHE events ", count_ev))
839elif hasattr(runArgs, "inputGeneratorFile"):
840 # counting the number of events in LHE input
841 count_ev = 0
842 with open(eventsFile) as f:
843 for line in f:
844 count_ev += line.count('/event')
845
846 print("MetaData: %s = %s" % ("Number of input LHE events ", count_ev))
847
848
849if _checkattr("description", required=True):
850 msg = evgenConfig.description
851 if _checkattr("notes"):
852 msg += " " + evgenConfig.notes
853 print ("MetaData: %s = %s" % ("physicsComment", msg))
854
855if _checkattr("generators", required=True):
856 print ("MetaData: %s = %s" % ("generatorName", "+".join(gennamesvers)))
857if _checkattr("process"):
858 print ("MetaData: %s = %s" % ("physicsProcess", evgenConfig.process))
859if _checkattr("tune"):
860 print ("MetaData: %s = %s" % ("generatorTune", evgenConfig.tune))
861if _checkattr("hardPDF"):
862 print ("MetaData: %s = %s" % ("hardPDF", evgenConfig.hardPDF))
863if _checkattr("softPDF"):
864 print ("MetaData: %s = %s" % ("softPDF", evgenConfig.softPDF))
865if _checkattr("nEventsPerJob"):
866 print ("MetaData: %s = %s" % ("nEventsPerJob", evgenConfig.nEventsPerJob))
867if _checkattr("keywords"):
868 print ("MetaData: %s = %s" % ("keywords", ", ".join(evgenConfig.keywords).lower()))
869if _checkattr("categories"):
870 print ("MetaData: %s = %s" % ("categories", ", ".join(evgenConfig.categories)))
871if _checkattr("specialConfig"):
872 print ("MetaData: %s = %s" % ("specialConfig", evgenConfig.specialConfig))
873# TODO: Require that a contact / JO author is always set
874if _checkattr("contact"):
875 print ("MetaData: %s = %s" % ("contactPhysicist", ", ".join(evgenConfig.contact)))
876print ("MetaData: %s = %s" % ("randomSeed", str(runArgs.randomSeed)))
877
878# Output list of generator filters used
879filterNames = [alg.getType() for alg in acas.iter_algseq(filtSeq)]
880excludedNames = ['AthSequencer', 'PyAthena::Alg', 'TestHepMC']
881filterNames = list(set(filterNames) - set(excludedNames))
882print ("MetaData: %s = %s" % ("genFilterNames", ", ".join(filterNames)))
883
884if (hasattr( runArgs, "allowOldFilter") and runArgs.allowOldFilter):
885 for alg in acas.iter_algseq(filtSeq):
886 filtName = alg.getType()
887 exceptName =['xAOD','Jet']
888 if filtName not in excludedNames:
889 if not any(ex in filtName for ex in exceptName):
890 alg.AllowOldFilter=True
891
892
895
896from PyJobTransformsCore.runargs import RunArguments
897runPars = RunArguments()
898runPars.nEventsPerJob = evgenConfig.nEventsPerJob
899runPars.maxeventsstrategy = evgenConfig.maxeventsstrategy
900with open("config.pickle", "wb") as f:
901 import pickle
902 pickle.dump(runPars, f)
903
904
905
908evgenLog.info("****************** STARTING EVENT GENERATION *****************")
if(febId1==febId2)
void print(char *figname, TCanvas *c1)
A random number engine manager, based on Ranecu.
A service to manage multiple RNG streams in thread-safe way.
Definition AthRNGSvc.h:34
This class provides an algorithm to make the EventStreamInfo object and update it.
Copy MC truth event weights into the event info store.
Count the number of events to pass all algorithms/filters.
Definition CountHepMC.h:26
Copy MC gen values we filter on into the event info store.
A "fix-up" algorithm to correct weird event records.
Definition FixHepMC.h:31
Print MC event details for a range of event numbers.
Definition PrintMC.h:12
Interface to the Rivet analysis package.
Definition Rivet_i.h:31
Algorithm to estimate the amount of CPU time that simulation will take.
Filtering algorithm to sanity check HepMC event features.
Definition TestHepMC.h:33
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
get_immediate_subdirectories(a_dir)
==============================================================
checkBlockList(relFlavour, cache, generatorName)
Add special config option (extended model info for BSM scenarios)
_checkattr(attr, required=False)
==============================================================
mk_symlink(srcfile, dstfile)
OutputTXTFile()
==============================================================
checkPurpleList(relFlavour, cache, generatorName)
IovVectorMap_t read(const Folder &theFolder, const SelectionCriterion &choice, const unsigned int limit=10)