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})
480if hasattr( evgenConfig, "hardPDF" ) : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"hardPDF": evgenConfig.hardPDF})
481if hasattr( evgenConfig, "softPDF" ) : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"softPDF": evgenConfig.softPDF})
482if hasattr( runArgs, "randomSeed") : svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"randomSeed": str(runArgs.randomSeed)})
483svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"keywords": ", ".join(evgenConfig.keywords).lower()})
484
485# print version of HepMC to the log
486evgenLog.info("HepMC version " + str(os.environ['HEPMCVER']))
487
488# Set AMITag in in-file metadata
489from PyUtils import AMITagHelper
490AMITagHelper.SetAMITag(runArgs=runArgs)
491
492
493svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"beam_energy": str(int(runArgs.ecmEnergy*Units.GeV/2.0))})
494svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"beam_type": 'collisions'})
495
496
497from OutputStreamAthenaPool.OutputStreamAthenaPoolConf import CopyEventStreamInfo
498streamInfoTool = CopyEventStreamInfo( "StreamEVGEN_CopyEventStreamInfo" )
499ToolSvc += streamInfoTool
500svcMgr.MetaDataSvc.MetaDataTools += [ streamInfoTool ]
501
502
504include("EvgenJobTransforms/Generate_ecmenergies.py")
505
506if 'ParticleGun' in evgenConfig.generators:
507
508 from RngComps.RngCompsConf import AtRndmGenSvc
509 svcMgr += AtRndmGenSvc()
510 include("EvgenJobTransforms/Generate_randomseeds.py")
511else:
512# Propagate DSID and seed to the generators
513 include("EvgenJobTransforms/Generate_dsid_ranseed.py")
514
515
516generatorsList = evgenConfig.generators.copy()
517if hasattr(genSeq, "Pythia8"):
518 if (hasattr(genSeq.Pythia8, "Beam1") and genSeq.Pythia8.Beam1 != "PROTON" ) or \
519 (hasattr(genSeq.Pythia8, "Beam2") and genSeq.Pythia8.Beam2 != "PROTON" ):
520 # generator name is still "Pythia8", even when colliding nuclei
521 generatorsList.append("Pythia8-Angantyr")
522if gens_purgenoendvtx(generatorsList):
523 fixSeq.FixHepMC.PurgeUnstableWithoutEndVtx = True
524
525
526if 'Sherpa' in evgenConfig.generators:
527 fixSeq.FixHepMC.IgnoreSemiDisconnected = True
528
529
530if (hasattr( runArgs, "VERBOSE") and runArgs.VERBOSE ) or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "DEBUG") or (hasattr( runArgs, "loglevel") and runArgs.loglevel == "VERBOSE"):
531 include("EvgenJobTransforms/Generate_debug_level.py")
532
533
534svcMgr.TagInfoMgr.ExtraTagValuePairs.update({"specialConfiguration": evgenConfig.specialConfig })
535
536
538if hasattr(testSeq, "TestHepMC") and not gens_testhepmc(evgenConfig.generators):
539 evgenLog.info("Removing TestHepMC sanity checker")
540 del testSeq.TestHepMC
541
542
546def checkBlockList(relFlavour,cache,generatorName) :
547 isError = None
548 with open('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common/BlackList_caches.txt') as bfile:
549 for line in bfile.readlines():
550 if not line.strip():
551 continue
552 # Blocklisted release flavours
553 badRelFlav=line.split(',')[0].strip()
554 # Blocklisted caches
555 badCache=line.split(',')[1].strip()
556 # Blocklisted generators
557 badGens=line.split(',')[2].strip()
558
559 used_gens = ','.join(generatorName)
560 #Match Generator and release type e.g. AtlasProduction, MCProd
561 if relFlavour==badRelFlav and cache==badCache and re.search(badGens,used_gens) is not None:
562 if badGens=="": badGens="all generators"
563 isError=relFlavour+","+cache+" is blocklisted for " + badGens
564 return isError
565 return isError
566
567def checkPurpleList(relFlavour,cache,generatorName) :
568 isError = None
569 with open('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common/PurpleList_generators.txt') as bfile:
570 for line in bfile.readlines():
571 if not line.strip():
572 continue
573 # Purple-listed release flavours
574 purpleRelFlav=line.split(',')[0].strip()
575 # Purple-listed caches
576 purpleCache=line.split(',')[1].strip()
577 # Purple-listed generators
578 purpleGens=line.split(',')[2].strip()
579 # Purple-listed process
580 purpleProcess=line.split(',')[3].strip()
581
582 used_gens = ','.join(generatorName)
583 #Match Generator and release type e.g. AtlasProduction, MCProd
584 if relFlavour==purpleRelFlav and cache==purpleCache and re.search(purpleGens,used_gens) is not None:
585 isError=relFlavour+","+cache+" is blocklisted for " + purpleGens + " if it uses " + purpleProcess
586 return isError
587 return isError
588
589
590evgenLog.debug("****************** CHECKING RELEASE IS NOT BLACKLISTED *****************")
591if os.path.exists('/cvmfs/atlas.cern.ch/repo/sw/Generators/MCJobOptions/common'):
592 errorBL = checkBlockList("AthGeneration",rel,gennames)
593 if (errorBL):
594 if (hasattr( runArgs, "ignoreBlackList") and runArgs.ignoreBlackList):
595 evgenLog.warning("This run is blocklisted for this generator, please use a different one for production !! "+ errorBL )
596 else:
597 raise RuntimeError("This run is blocklisted for this generator, please use a different one !! "+ errorBL)
598
599 errorPL = checkPurpleList("AthGeneration",rel,gennames)
600 if (errorPL):
601 evgenLog.warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
602 evgenLog.warning("!!! WARNING !!! "+ errorPL )
603 evgenLog.warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
604
605else:
606 msg.waring("No access to cvmfs, so blocklisted runs will not be checked")
607
610
611if hasattr(runArgs, "postInclude"):
612 for fragment in runArgs.postInclude:
613 include(fragment)
614
615if hasattr(runArgs, "postExec"):
616 evgenLog.info("Transform post-exec")
617 for cmd in runArgs.postExec:
618 evgenLog.info(cmd)
619 exec(cmd)
620
621
622
625acas.dumpMasterSequence()
626
627
628
631
632
633evgenLog.debug("****************** HANDLING EVGEN INPUT FILES *****************")
634
635
636datFile = None
637if "McAtNlo" in evgenConfig.generators and "Herwig" in evgenConfig.generators:
638 datFile = "inparmMcAtNlo.dat"
639elif "Alpgen" in evgenConfig.generators:
640 datFile = "inparmAlpGen.dat"
641elif "Protos" in evgenConfig.generators:
642 datFile = "protos.dat"
643elif "ProtosLHEF" in evgenConfig.generators:
644 datFile = "protoslhef.dat"
645elif "AcerMC" in evgenConfig.generators:
646 datFile = "inparmAcerMC.dat"
647elif "CompHep" in evgenConfig.generators:
648 datFile = "inparmCompHep.dat"
649
650
651eventsFile = None
652if "Alpgen" in evgenConfig.generators:
653 eventsFile = "alpgen.unw_events"
654elif "Protos" in evgenConfig.generators:
655 eventsFile = "protos.events"
656elif "ProtosLHEF" in evgenConfig.generators:
657 eventsFile = "protoslhef.events"
658elif "BeamHaloGenerator" in evgenConfig.generators:
659 eventsFile = "beamhalogen.events"
660elif "HepMCAscii" in evgenConfig.generators:
661 eventsFile = "events.hepmc"
662elif "ReadMcAscii" in evgenConfig.generators:
663 eventsFile = "events.hepmc"
664elif gens_lhef(evgenConfig.generators):
665 inputGeneratorFile = getattr(runArgs, "inputGeneratorFile", "")
666 # Determine whether to use compressed LHE file based on the
667 # inputGeneratorFile extension and avoidExtracting flag
668 # avoidExtracting is False by default, but can be set to True
669 # in the transform to instruct the shower to use the
670 # compressed LHE file.
671 useCompressedLHE = (getattr(runArgs, "avoidExtracting", False)
672 and inputGeneratorFile.endswith(".events.gz"))
673 eventsFile = "events.lhe.gz" if useCompressedLHE else "events.lhe"
674
675
676
677def find_unique_file(pattern):
678 "Return a matching file, provided it is unique"
679 import glob
680 files = glob.glob(pattern)
681
682 if not files:
683 raise RuntimeError("No '%s' file found" % pattern)
684 elif len(files) > 1:
685 raise RuntimeError("More than one '%s' file found" % pattern)
686 return files[0]
687
688# This function merges a list of input LHE file to make one outputFile. The header is taken from the first
689# file, but the number of events is updated to equal the total number of events in all the input files
690def merge_lhe_files(listOfFiles,outputFile):
691 if(os.path.exists(outputFile)):
692 print ("outputFile ",outputFile," already exists. Will rename to ",outputFile,".OLD")
693 os.rename(outputFile,outputFile+".OLD")
694 output = open(outputFile,'w')
695 holdHeader = ""
696 nevents=0
697 for file in listOfFiles:
698 cmd = "grep /event "+file+" | wc -l"
699 nevents+=int(subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True))
700
701 for file in listOfFiles:
702 inHeader = True
703 header = ""
704 print ("*** Starting file ",file)
705 for line in open(file,"r"):
706
711 if("<event" in line and inHeader):
712 inHeader = False
713 if(len(holdHeader)<1):
714 holdHeader = header
715 output.write(header)
716 output.write(line)
717
719 elif(not inHeader and not ("</LesHouchesEvents>" in line)):
720 output.write(line)
721 if(inHeader):
722
723 if("nevents" in line):
724
725 tmp = line.split("=")
726 line = line.replace(tmp[0],str(nevents))
727 elif("numevts" in line):
728
729 tmp = line.split(" ")
730 nnn = str(nevents)
731 line = line.replace(tmp[1],nnn)
732 header+=line
733 output.write("</LesHouchesEvents>\n")
734 output.close()
735
736
737def mk_symlink(srcfile, dstfile):
738 "Make a symlink safely"
739 if dstfile:
740 if os.path.exists(dstfile) and not os.path.samefile(dstfile, srcfile):
741 os.remove(dstfile)
742 if not os.path.exists(dstfile):
743 evgenLog.info("Symlinking %s to %s" % (srcfile, dstfile))
744 print ("Symlinking %s to %s" % (srcfile, dstfile))
745 os.symlink(srcfile, dstfile)
746 else:
747 evgenLog.debug("Symlinking: %s is already the same as %s" % (dstfile, srcfile))
748
749
750if eventsFile or datFile:
751 if not hasattr(runArgs, "inputGeneratorFile") or runArgs.inputGeneratorFile == "NONE":
752 raise RuntimeError("%s needs input file (argument inputGeneratorFile)" % runArgs.jobConfig)
753 if evgenConfig.inputfilecheck and not re.search(evgenConfig.inputfilecheck, runArgs.inputGeneratorFile):
754 raise RuntimeError("inputGeneratorFile=%s is incompatible with inputfilecheck '%s' in %s" %
755 (runArgs.inputGeneratorFile, evgenConfig.inputfilecheck, runArgs.jobConfig))
756 if datFile:
757 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
758 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
759 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
760 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
761 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
762 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
763 else:
764 inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
765
766 realDatFile = find_unique_file('*%s*.dat' % inputroot)
767 mk_symlink(realDatFile, datFile)
768 if eventsFile:
769 myinputfiles = runArgs.inputGeneratorFile
770 genInputFiles = myinputfiles.split(',')
771 numberOfFiles = len(genInputFiles)
772 # if there is a single file, make a symlink. If multiple files, merge them into one output eventsFile
773 if(numberOfFiles<2):
774 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
775 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
776 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
777 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
778 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
779 if eventsFile.endswith(".gz"):
780 inputroot = os.path.basename(runArgs.inputGeneratorFile)
781 else:
782 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
783 else:
784 inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
785
786 if "events" in inputroot :
787 inputroot = inputroot.replace(".events","")
788 if eventsFile.endswith(".gz"):
789 inputroot = inputroot.replace(".gz","")
790 realEventsFile = find_unique_file('*%s.*ev*ts.gz' % inputroot)
791 else:
792 realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
793 mk_symlink(realEventsFile, eventsFile)
794 else:
795 allFiles = []
796 for file in genInputFiles:
797# Since we can have multiple files from the same task, inputroot must include more of the filename
798# to make it unique
799 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
800 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
801 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
802 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
803 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
804 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
805 else:
806 input0 = os.path.basename(file).split("._")[0]
807 input1 = (os.path.basename(file).split("._")[1]).split(".")[0]
808 inputroot = input0+"._"+input1
809 evgenLog.info("inputroot = %s",inputroot)
810 realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
811# The only input format where merging is permitted is LHE
812 with open(realEventsFile, 'r') as f:
813 first_line = f.readline()
814 if(not ("LesHouche" in first_line)):
815 raise RuntimeError("%s is NOT a LesHouche file" % realEventsFile)
816 allFiles.append(realEventsFile)
817 merge_lhe_files(allFiles,eventsFile)
818
819else:
820 if hasattr(runArgs, "inputGeneratorFile") and runArgs.inputGeneratorFile != "NONE":
821 raise RuntimeError("inputGeneratorFile arg specified for %s, but generators %s do not require an input file" %
822 (runArgs.jobConfig, str(gennames)))
823 if evgenConfig.inputfilecheck:
824 raise RuntimeError("evgenConfig.inputfilecheck specified in %s, but generators %s do not require an input file" %
825 (runArgs.jobConfig, str(gennames)))
826
827
828if evgenConfig.auxfiles:
829 from PyJobTransformsCore.trfutil import get_files
830 get_files(evgenConfig.auxfiles, keepDir=False, errorIfNotFound=True)
831
832
833
836
837def _checkattr(attr, required=False):
838 if not hasattr(evgenConfig, attr) or not getattr(evgenConfig, attr):
839 msg = "evgenConfig attribute '%s' not found." % attr
840 if required:
841 raise RuntimeError("Required " + msg)
842 return False
843 return True
844
845if hasattr(runArgs, "outputTXTFile"):
846 # counting the number of events in LHE output
847 count_ev = 0
848 with open(eventsFile) as f:
849 for line in f:
850 count_ev += line.count('/event')
851
852 print("MetaData: %s = %s" % ("Number of produced LHE events ", count_ev))
853elif hasattr(runArgs, "inputGeneratorFile"):
854 # counting the number of events in LHE input
855 count_ev = 0
856 if eventsFile.endswith("gz"):
857 import gzip
858 with gzip.open(eventsFile, 'rt') as f:
859 for line in f:
860 count_ev += line.count('/event')
861 else:
862 with open(eventsFile) as f:
863 for line in f:
864 count_ev += line.count('/event')
865
866 print("MetaData: %s = %s" % ("Number of input LHE events ", count_ev))
867
868
869if _checkattr("description", required=True):
870 msg = evgenConfig.description
871 if _checkattr("notes"):
872 msg += " " + evgenConfig.notes
873 print ("MetaData: %s = %s" % ("physicsComment", msg))
874
875if _checkattr("generators", required=True):
876 print ("MetaData: %s = %s" % ("generatorName", "+".join(gennamesvers)))
877if _checkattr("process"):
878 print ("MetaData: %s = %s" % ("physicsProcess", evgenConfig.process))
879if _checkattr("tune"):
880 print ("MetaData: %s = %s" % ("generatorTune", evgenConfig.tune))
881if _checkattr("hardPDF"):
882 print ("MetaData: %s = %s" % ("hardPDF", evgenConfig.hardPDF))
883if _checkattr("softPDF"):
884 print ("MetaData: %s = %s" % ("softPDF", evgenConfig.softPDF))
885if _checkattr("nEventsPerJob"):
886 print ("MetaData: %s = %s" % ("nEventsPerJob", evgenConfig.nEventsPerJob))
887if _checkattr("keywords"):
888 print ("MetaData: %s = %s" % ("keywords", ", ".join(evgenConfig.keywords).lower()))
889if _checkattr("categories"):
890 print ("MetaData: %s = %s" % ("categories", ", ".join(evgenConfig.categories)))
891if _checkattr("specialConfig"):
892 print ("MetaData: %s = %s" % ("specialConfig", evgenConfig.specialConfig))
893# TODO: Require that a contact / JO author is always set
894if _checkattr("contact"):
895 print ("MetaData: %s = %s" % ("contactPhysicist", ", ".join(evgenConfig.contact)))
896print ("MetaData: %s = %s" % ("randomSeed", str(runArgs.randomSeed)))
897
898# Output list of generator filters used
899filterNames = [alg.getType() for alg in acas.iter_algseq(filtSeq)]
900excludedNames = ['AthSequencer', 'PyAthena::Alg', 'TestHepMC']
901filterNames = list(set(filterNames) - set(excludedNames))
902print ("MetaData: %s = %s" % ("genFilterNames", ", ".join(filterNames)))
903
904if (hasattr( runArgs, "allowOldFilter") and runArgs.allowOldFilter):
905 for alg in acas.iter_algseq(filtSeq):
906 filtName = alg.getType()
907 exceptName =['xAOD','Jet']
908 if filtName not in excludedNames:
909 if not any(ex in filtName for ex in exceptName):
910 alg.AllowOldFilter=True
911
912
915
916from PyJobTransformsCore.runargs import RunArguments
917runPars = RunArguments()
918runPars.nEventsPerJob = evgenConfig.nEventsPerJob
919runPars.maxeventsstrategy = evgenConfig.maxeventsstrategy
920with open("config.pickle", "wb") as f:
921 import pickle
922 pickle.dump(runPars, f)
923
924
925
928evgenLog.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
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)