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
234if joparts[0].startswith("mc") and all(c in string.digits for c in joparts[0][2:]):
235
236 if len(joparts) != 3:
237 evgenLog.error(jofile + " name format is wrong: must be of the form mc.<physicsShort>.py: please rename.")
238 sys.exit(1)
239
240 jo_physshortpart = joparts[1]
241 max_jo_physshort_length = 50
242 if len(jo_physshortpart) > max_jo_physshort_length:
243 evgenLog.error(f"{jofile} contains a physicsShort field of more than {max_jo_physshort_length} characters: please rename.")
244 sys.exit(1)
245
246 jo_physshortparts = jo_physshortpart.split("_")
247 if len(jo_physshortparts) < 2:
248 evgenLog.error(jofile + " has too few physicsShort fields separated by '_': should contain <generators>(_<tune+PDF_if_available>)_<process>. Please rename.")
249 sys.exit(1)
250
251 check_jofiles="/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/scripts/check_jo_consistency.py"
252 if os.path.exists(check_jofiles):
253 include(check_jofiles)
254 check_naming(os.path.basename(jofile))
255 else:
256 evgenLog.waring("check_jo_consistency.py not found, will proceed without JOs check.")
257else:
258
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)
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 sys.exit(1)
423 else:
424 evgenLog.warning("Could not find CategoryList.txt file %s in $DATAPATH" % lkwfile)
425
426if hasattr( runArgs, "outputEVNTFile") or hasattr( runArgs, "outputEVNT_PreFile"):
427
428 from AthenaPoolCnvSvc.WriteAthenaPool import AthenaPoolOutputStream
429 from AthenaPoolCnvSvc.AthenaPoolCnvSvcConf import AthenaPoolCnvSvc
430 if hasattr(runArgs, "outputEVNTFile"):
431 poolFile = runArgs.outputEVNTFile
432 elif hasattr(runArgs, "outputEVNT_PreFile"):
433 poolFile = runArgs.outputEVNT_PreFile
434 else:
435 raise RuntimeError("Output pool file, either EVNT or EVNT_Pre, is not known.")
436
437 # ROOT inadvertently broke forward compatibility in v6.30+ (see root/issues/15964)
438 # This workaround is needed so that older releases can read files created by the new ones
439 # For more information see ATEAM-1001 and ATEAM-1015 (for DataHeaderForm)
440 svcMgr.AthenaPoolCnvSvc.PoolAttributes += [ f"DatabaseName = '{poolFile}'; FILEFORWARD_COMPATIBILITY = '1'" ]
441 svcMgr.AthenaPoolCnvSvc.OneDataHeaderForm = False
442
443 StreamEVGEN = AthenaPoolOutputStream("StreamEVGEN", poolFile, noTag=True, eventInfoKey="EventInfo")
444
445 StreamEVGEN.ForceRead = True
446 StreamEVGEN.ItemList += ["EventInfo#*", "xAOD::EventInfo#EventInfo*", "xAOD::EventAuxInfo#EventInfoAux.*", "McEventCollection#*"]
447 StreamEVGEN.RequireAlgs += ["EvgenFilterSeq"]
448
449 if evgenConfig.saveJets:
450 StreamEVGEN.ItemList += ["xAOD::JetContainer#AntiKt4TruthJets", "xAOD::AuxContainerBase!#AntiKt4TruthJetsAux.-PseudoJet.-constituentLinks.-constituentWeights"]
451 StreamEVGEN.ItemList += ["xAOD::JetContainer#AntiKt6TruthJets", "xAOD::AuxContainerBase!#AntiKt6TruthJetsAux.-PseudoJet.-constituentLinks.-constituentWeights"]
452 if evgenConfig.savePileupTruthParticles:
453 StreamEVGEN.ItemList += ["xAOD::TruthParticleContainer#TruthPileupParticles*"]
454 StreamEVGEN.ItemList += ["xAOD::TruthParticleAuxContainer#TruthPileupParticlesAux.*"]
455
456 # Remove any requested items from the ItemList so as not to write out
457 for removeItem in evgenConfig.doNotSaveItems: StreamEVGEN.ItemList.remove( removeItem )
458
459 # Allow (re-)addition to the output stream
460 for addItem in evgenConfig.extraSaveItems: StreamEVGEN.ItemList += [ addItem ]
461
462
463dsid = os.path.basename(runArgs.jobConfig[0])
464if not dsid.isdigit():
465 dsid = "999999"
466svcMgr.EventSelector.RunNumber = int(dsid)
467
468
469from GeneratorConfig.Versioning import generatorsGetInitialVersionedDictionary, generatorsVersionedStringList
470gendict = generatorsGetInitialVersionedDictionary(gennames)
471gennamesvers = generatorsVersionedStringList(gendict)
472
473import EventInfoMgt.EventInfoMgtInit
474svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"hepmc_version": "HepMC" + str(os.environ['HEPMCVER'])})
475svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"mc_channel_number":str(dsid)})
476svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"lhefGenerator": '+'.join( filter( gen_lhef, gennames ) ) })
477svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"generators": '+'.join(gennamesvers)})
478svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"evgenProcess": evgenConfig.process})
479svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"evgenTune": evgenConfig.tune})
480svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"hadronizationModel": evgenConfig.hadronizationModel})
481svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"partonShowerModel": evgenConfig.partonShowerModel})
482if hasattr( evgenConfig, "hardPDF" ) : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"hardPDF": evgenConfig.hardPDF})
483if hasattr( evgenConfig, "softPDF" ) : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"softPDF": evgenConfig.softPDF})
484if hasattr( runArgs, "randomSeed") : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"randomSeed": str(runArgs.randomSeed)})
485svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"keywords": ", ".join(evgenConfig.keywords).lower()})
486
487# print version of HepMC to the log
488evgenLog.info("HepMC version " + str(os.environ['HEPMCVER']))
489
490# Set AMITag in in-file metadata
491from PyUtils import AMITagHelper
492AMITagHelper.SetAMITag(runArgs=runArgs)
493
494
495svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"beam_energy": str(int(runArgs.ecmEnergy*Units.GeV/2.0))})
496svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"beam_type": 'collisions'})
497
498
499from OutputStreamAthenaPool.OutputStreamAthenaPoolConf import CopyEventStreamInfo
500streamInfoTool = CopyEventStreamInfo( "StreamEVGEN_CopyEventStreamInfo" )
501ToolSvc += streamInfoTool
502svcMgr.MetaDataSvc.MetaDataTools += [ streamInfoTool ]
503
504
506include("EvgenJobTransforms/Generate_ecmenergies.py")
507
508if 'ParticleGun' in evgenConfig.generators:
509
510 from RngComps.RngCompsConf import AtRndmGenSvc
511 svcMgr += AtRndmGenSvc()
512 include("EvgenJobTransforms/Generate_randomseeds.py")
513else:
514# Propagate DSID and seed to the generators
515 include("EvgenJobTransforms/Generate_dsid_ranseed.py")
516
517
518generatorsList = evgenConfig.generators.copy()
519if hasattr(genSeq, "Pythia8"):
520 if (hasattr(genSeq.Pythia8, "Beam1") and genSeq.Pythia8.Beam1 != "PROTON" ) or \
521 (hasattr(genSeq.Pythia8, "Beam2") and genSeq.Pythia8.Beam2 != "PROTON" ):
522 # generator name is still "Pythia8", even when colliding nuclei
523 generatorsList.append("Pythia8-Angantyr")
524if gens_purgenoendvtx(generatorsList):
525 fixSeq.FixHepMC.PurgeUnstableWithoutEndVtx = True
526
527
528if 'Sherpa' in evgenConfig.generators:
529 fixSeq.FixHepMC.IgnoreSemiDisconnected = True
530
531
532if (hasattr( runArgs, "VERBOSE") and runArgs.VERBOSE ) or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "DEBUG") or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "VERBOSE"):
533 include("EvgenJobTransforms/Generate_debug_level.py")
534
535
536svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"specialConfiguration": evgenConfig.specialConfig })
537
538
540if hasattr(testSeq, "TestHepMC") and not gens_testhepmc(evgenConfig.generators):
541 evgenLog.info("Removing TestHepMC sanity checker")
542 del testSeq.TestHepMC
543
544
548def checkBlockList(relFlavour,cache,generatorName) :
549 isError = None
550 with open('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common/BlackList_caches.txt') as bfile:
551 for line in bfile.readlines():
552 if not line.strip():
553 continue
554 # Blocklisted release flavours
555 badRelFlav=line.split(',')[0].strip()
556 # Blocklisted caches
557 badCache=line.split(',')[1].strip()
558 # Blocklisted generators
559 badGens=line.split(',')[2].strip()
560
561 used_gens = ','.join(generatorName)
562 #Match Generator and release type e.g. AtlasProduction, MCProd
563 if relFlavour==badRelFlav and cache==badCache and re.search(badGens,used_gens) is not None:
564 if badGens=="": badGens="all generators"
565 isError=relFlavour+","+cache+" is blocklisted for " + badGens
566 return isError
567 return isError
568
569def checkPurpleList(relFlavour,cache,generatorName) :
570 isError = None
571 with open('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common/PurpleList_generators.txt') as bfile:
572 for line in bfile.readlines():
573 if not line.strip():
574 continue
575 # Purple-listed release flavours
576 purpleRelFlav=line.split(',')[0].strip()
577 # Purple-listed caches
578 purpleCache=line.split(',')[1].strip()
579 # Purple-listed generators
580 purpleGens=line.split(',')[2].strip()
581 # Purple-listed process
582 purpleProcess=line.split(',')[3].strip()
583
584 used_gens = ','.join(generatorName)
585 #Match Generator and release type e.g. AtlasProduction, MCProd
586 if relFlavour==purpleRelFlav and cache==purpleCache and re.search(purpleGens,used_gens) is not None:
587 isError=relFlavour+","+cache+" is blocklisted for " + purpleGens + " if it uses " + purpleProcess
588 return isError
589 return isError
590
591
592evgenLog.debug("****************** CHECKING RELEASE IS NOT BLACKLISTED *****************")
593if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common'):
594 errorBL = checkBlockList("AthGeneration",rel,gennames)
595 if (errorBL):
596 if (hasattr( runArgs, "ignoreBlackList") and runArgs.ignoreBlackList):
597 evgenLog.warning("This run is blocklisted for this generator, please use a different one for production !! "+ errorBL )
598 else:
599 raise RuntimeError("This run is blocklisted for this generator, please use a different one !! "+ errorBL)
600
601 errorPL = checkPurpleList("AthGeneration",rel,gennames)
602 if (errorPL):
603 evgenLog.warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
604 evgenLog.warning("!!! WARNING !!! "+ errorPL )
605 evgenLog.warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
606
607else:
608 msg.waring("No access to cvmfs, so blocklisted runs will not be checked")
609
612
613if hasattr(runArgs, "postInclude"):
614 for fragment in runArgs.postInclude:
615 include(fragment)
616
617if hasattr(runArgs, "postExec"):
618 evgenLog.info("Transform post-exec")
619 for cmd in runArgs.postExec:
620 evgenLog.info(cmd)
621 exec(cmd)
622
623
624
627acas.dumpMasterSequence()
628
629
630
633
634
635evgenLog.debug("****************** HANDLING EVGEN INPUT FILES *****************")
636
637
638datFile = None
639if "McAtNlo" in evgenConfig.generators and "Herwig" in evgenConfig.generators:
640 datFile = "inparmMcAtNlo.dat"
641elif "Alpgen" in evgenConfig.generators:
642 datFile = "inparmAlpGen.dat"
643elif "Protos" in evgenConfig.generators:
644 datFile = "protos.dat"
645elif "ProtosLHEF" in evgenConfig.generators:
646 datFile = "protoslhef.dat"
647elif "AcerMC" in evgenConfig.generators:
648 datFile = "inparmAcerMC.dat"
649elif "CompHep" in evgenConfig.generators:
650 datFile = "inparmCompHep.dat"
651
652
653eventsFile = None
654if "Alpgen" in evgenConfig.generators:
655 eventsFile = "alpgen.unw_events"
656elif "Protos" in evgenConfig.generators:
657 eventsFile = "protos.events"
658elif "ProtosLHEF" in evgenConfig.generators:
659 eventsFile = "protoslhef.events"
660elif "BeamHaloGenerator" in evgenConfig.generators:
661 eventsFile = "beamhalogen.events"
662elif "HepMCAscii" in evgenConfig.generators:
663 eventsFile = "events.hepmc"
664elif "ReadMcAscii" in evgenConfig.generators:
665 eventsFile = "events.hepmc"
666elif gens_lhef(evgenConfig.generators):
667 inputGeneratorFile = getattr(runArgs, "inputGeneratorFile", "")
668 # Determine whether to use compressed LHE file based on the
669 # inputGeneratorFile extension and avoidExtracting flag
670 # avoidExtracting is False by default, but can be set to True
671 # in the transform to instruct the shower to use the
672 # compressed LHE file.
673 useCompressedLHE = (getattr(runArgs, "avoidExtracting", False)
674 and inputGeneratorFile.endswith(".events.gz"))
675 eventsFile = "events.lhe.gz" if useCompressedLHE else "events.lhe"
676
677
678
679def find_unique_file(pattern):
680 "Return a matching file, provided it is unique"
681 import glob
682 files = glob.glob(pattern)
683
684 if not files:
685 raise RuntimeError("No '%s' file found" % pattern)
686 elif len(files) > 1:
687 raise RuntimeError("More than one '%s' file found" % pattern)
688 return files[0]
689
690# This function merges a list of input LHE file to make one outputFile. The header is taken from the first
691# file, but the number of events is updated to equal the total number of events in all the input files
692def merge_lhe_files(listOfFiles,outputFile):
693 if(os.path.exists(outputFile)):
694 print ("outputFile ",outputFile," already exists. Will rename to ",outputFile,".OLD")
695 os.rename(outputFile,outputFile+".OLD")
696 output = open(outputFile,'w')
697 holdHeader = ""
698 nevents=0
699 for file in listOfFiles:
700 cmd = "grep /event "+file+" | wc -l"
701 nevents+=int(subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True))
702
703 for file in listOfFiles:
704 inHeader = True
705 header = ""
706 print ("*** Starting file ",file)
707 for line in open(file,"r"):
708
713 if("<event" in line and inHeader):
714 inHeader = False
715 if(len(holdHeader)<1):
716 holdHeader = header
717 output.write(header)
718 output.write(line)
719
721 elif(not inHeader and not ("</LesHouchesEvents>" in line)):
722 output.write(line)
723 if(inHeader):
724
725 if("nevents" in line):
726
727 tmp = line.split("=")
728 line = line.replace(tmp[0],str(nevents))
729 elif("numevts" in line):
730
731 tmp = line.split(" ")
732 nnn = str(nevents)
733 line = line.replace(tmp[1],nnn)
734 header+=line
735 output.write("</LesHouchesEvents>\n")
736 output.close()
737
738
739def mk_symlink(srcfile, dstfile):
740 "Make a symlink safely"
741 if dstfile:
742 if os.path.exists(dstfile) and not os.path.samefile(dstfile, srcfile):
743 os.remove(dstfile)
744 if not os.path.exists(dstfile):
745 evgenLog.info("Symlinking %s to %s" % (srcfile, dstfile))
746 print ("Symlinking %s to %s" % (srcfile, dstfile))
747 os.symlink(srcfile, dstfile)
748 else:
749 evgenLog.debug("Symlinking: %s is already the same as %s" % (dstfile, srcfile))
750
751
752if eventsFile or datFile:
753 if not hasattr(runArgs, "inputGeneratorFile") or runArgs.inputGeneratorFile == "NONE":
754 raise RuntimeError("%s needs input file (argument inputGeneratorFile)" % runArgs.jobConfig)
755 if evgenConfig.inputfilecheck and not re.search(evgenConfig.inputfilecheck, runArgs.inputGeneratorFile):
756 raise RuntimeError("inputGeneratorFile=%s is incompatible with inputfilecheck '%s' in %s" %
757 (runArgs.inputGeneratorFile, evgenConfig.inputfilecheck, runArgs.jobConfig))
758 if datFile:
759 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
760 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
761 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
762 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
763 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
764 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
765 else:
766 inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
767
768 realDatFile = find_unique_file('*%s*.dat' % inputroot)
769 mk_symlink(realDatFile, datFile)
770 if eventsFile:
771 myinputfiles = runArgs.inputGeneratorFile
772 genInputFiles = myinputfiles.split(',')
773 numberOfFiles = len(genInputFiles)
774 # if there is a single file, make a symlink. If multiple files, merge them into one output eventsFile
775 if(numberOfFiles<2):
776 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
777 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
778 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
779 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
780 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
781 if eventsFile.endswith(".gz"):
782 inputroot = os.path.basename(runArgs.inputGeneratorFile)
783 else:
784 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
785 else:
786 inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
787
788 if "events" in inputroot :
789 inputroot = inputroot.replace(".events","")
790 if eventsFile.endswith(".gz"):
791 inputroot = inputroot.replace(".gz","")
792 realEventsFile = find_unique_file('*%s.*ev*ts.gz' % inputroot)
793 else:
794 realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
795 mk_symlink(realEventsFile, eventsFile)
796 else:
797 allFiles = []
798 for file in genInputFiles:
799# Since we can have multiple files from the same task, inputroot must include more of the filename
800# to make it unique
801 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
802 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
803 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
804 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
805 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
806 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
807 else:
808 input0 = os.path.basename(file).split("._")[0]
809 input1 = (os.path.basename(file).split("._")[1]).split(".")[0]
810 inputroot = input0+"._"+input1
811 evgenLog.info("inputroot = %s",inputroot)
812 realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
813# The only input format where merging is permitted is LHE
814 with open(realEventsFile, 'r') as f:
815 first_line = f.readline()
816 if(not ("LesHouche" in first_line)):
817 raise RuntimeError("%s is NOT a LesHouche file" % realEventsFile)
818 allFiles.append(realEventsFile)
819 merge_lhe_files(allFiles,eventsFile)
820
821else:
822 if hasattr(runArgs, "inputGeneratorFile") and runArgs.inputGeneratorFile != "NONE":
823 raise RuntimeError("inputGeneratorFile arg specified for %s, but generators %s do not require an input file" %
824 (runArgs.jobConfig, str(gennames)))
825 if evgenConfig.inputfilecheck:
826 raise RuntimeError("evgenConfig.inputfilecheck specified in %s, but generators %s do not require an input file" %
827 (runArgs.jobConfig, str(gennames)))
828
829
830if evgenConfig.auxfiles:
831 from PyJobTransformsCore.trfutil import get_files
832 get_files(evgenConfig.auxfiles, keepDir=False, errorIfNotFound=True)
833
834
835
838
839def _checkattr(attr, required=False):
840 if not hasattr(evgenConfig, attr) or not getattr(evgenConfig, attr):
841 msg = "evgenConfig attribute '%s' not found." % attr
842 if required:
843 raise RuntimeError("Required " + msg)
844 return False
845 return True
846
847if hasattr(runArgs, "outputTXTFile"):
848 # counting the number of events in LHE output
849 count_ev = 0
850 with open(eventsFile) as f:
851 for line in f:
852 count_ev += line.count('/event')
853
854 print("MetaData: %s = %s" % ("Number of produced LHE events ", count_ev))
855elif hasattr(runArgs, "inputGeneratorFile"):
856 # counting the number of events in LHE input
857 count_ev = 0
858 if eventsFile.endswith("gz"):
859 import gzip
860 with gzip.open(eventsFile, 'rt') as f:
861 for line in f:
862 count_ev += line.count('/event')
863 else:
864 with open(eventsFile) as f:
865 for line in f:
866 count_ev += line.count('/event')
867
868 print("MetaData: %s = %s" % ("Number of input LHE events ", count_ev))
869
870
871if _checkattr("description", required=True):
872 msg = evgenConfig.description
873 if _checkattr("notes"):
874 msg += " " + evgenConfig.notes
875 print ("MetaData: %s = %s" % ("physicsComment", msg))
876
877if _checkattr("generators", required=True):
878 print ("MetaData: %s = %s" % ("generatorName", "+".join(gennamesvers)))
879if _checkattr("process"):
880 print ("MetaData: %s = %s" % ("physicsProcess", evgenConfig.process))
881if _checkattr("tune"):
882 print ("MetaData: %s = %s" % ("generatorTune", evgenConfig.tune))
883if _checkattr("hadronizationModel"):
884 print ("MetaData: %s = %s" % ("hadronizationModel", evgenConfig.hadronizationModel))
885if _checkattr("partonShowerModel"):
886 print ("MetaData: %s = %s" % ("partonShowerModel", evgenConfig.partonShowerModel))
887if _checkattr("hardPDF"):
888 print ("MetaData: %s = %s" % ("hardPDF", evgenConfig.hardPDF))
889if _checkattr("softPDF"):
890 print ("MetaData: %s = %s" % ("softPDF", evgenConfig.softPDF))
891if _checkattr("nEventsPerJob"):
892 print ("MetaData: %s = %s" % ("nEventsPerJob", evgenConfig.nEventsPerJob))
893if _checkattr("keywords"):
894 print ("MetaData: %s = %s" % ("keywords", ", ".join(evgenConfig.keywords).lower()))
895if _checkattr("categories"):
896 print ("MetaData: %s = %s" % ("categories", ", ".join(evgenConfig.categories)))
897if _checkattr("specialConfig"):
898 print ("MetaData: %s = %s" % ("specialConfig", evgenConfig.specialConfig))
899# TODO: Require that a contact / JO author is always set
900if _checkattr("contact"):
901 print ("MetaData: %s = %s" % ("contactPhysicist", ", ".join(evgenConfig.contact)))
902print ("MetaData: %s = %s" % ("randomSeed", str(runArgs.randomSeed)))
903
904# Output list of generator filters used
905filterNames = [alg.getType() for alg in acas.iter_algseq(filtSeq)]
906excludedNames = ['AthSequencer', 'PyAthena::Alg', 'TestHepMC']
907filterNames = list(set(filterNames) - set(excludedNames))
908print ("MetaData: %s = %s" % ("genFilterNames", ", ".join(filterNames)))
909
910if (hasattr( runArgs, "allowOldFilter") and runArgs.allowOldFilter):
911 for alg in acas.iter_algseq(filtSeq):
912 filtName = alg.getType()
913 exceptName =['xAOD','Jet']
914 if filtName not in excludedNames:
915 if not any(ex in filtName for ex in exceptName):
916 alg.AllowOldFilter=True
917
918
921
922from PyJobTransformsCore.runargs import RunArguments
923runPars = RunArguments()
924runPars.nEventsPerJob = evgenConfig.nEventsPerJob
925runPars.maxeventsstrategy = evgenConfig.maxeventsstrategy
926with open("config.pickle", "wb") as f:
927 import pickle
928 pickle.dump(runPars, f)
929
930
931
934evgenLog.info("****************** STARTING EVENT GENERATION *****************")
if(pathvar)
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:15
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:34
STL class.
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:312
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
OutputTXTFile()
==============================================================
checkBlockList(relFlavour, cache, generatorName)
Add special config option (extended model info for BSM scenarios).
checkPurpleList(relFlavour, cache, generatorName)
_checkattr(attr, required=False)
==============================================================
get_immediate_subdirectories(a_dir)
==============================================================
mk_symlink(srcfile, dstfile)
IovVectorMap_t read(const Folder &theFolder, const SelectionCriterion &choice, const unsigned int limit=10)