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 eventsFile = "events.lhe"
666
667
668
669def find_unique_file(pattern):
670 "Return a matching file, provided it is unique"
671 import glob
672 files = glob.glob(pattern)
673
674 if not files:
675 raise RuntimeError("No '%s' file found" % pattern)
676 elif len(files) > 1:
677 raise RuntimeError("More than one '%s' file found" % pattern)
678 return files[0]
679
680# This function merges a list of input LHE file to make one outputFile. The header is taken from the first
681# file, but the number of events is updated to equal the total number of events in all the input files
682def merge_lhe_files(listOfFiles,outputFile):
683 if(os.path.exists(outputFile)):
684 print ("outputFile ",outputFile," already exists. Will rename to ",outputFile,".OLD")
685 os.rename(outputFile,outputFile+".OLD")
686 output = open(outputFile,'w')
687 holdHeader = ""
688 nevents=0
689 for file in listOfFiles:
690 cmd = "grep /event "+file+" | wc -l"
691 nevents+=int(subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True))
692
693 for file in listOfFiles:
694 inHeader = True
695 header = ""
696 print ("*** Starting file ",file)
697 for line in open(file,"r"):
698
703 if("<event" in line and inHeader):
704 inHeader = False
705 if(len(holdHeader)<1):
706 holdHeader = header
707 output.write(header)
708 output.write(line)
709
711 elif(not inHeader and not ("</LesHouchesEvents>" in line)):
712 output.write(line)
713 if(inHeader):
714
715 if("nevents" in line):
716
717 tmp = line.split("=")
718 line = line.replace(tmp[0],str(nevents))
719 elif("numevts" in line):
720
721 tmp = line.split(" ")
722 nnn = str(nevents)
723 line = line.replace(tmp[1],nnn)
724 header+=line
725 output.write("</LesHouchesEvents>\n")
726 output.close()
727
728
729def mk_symlink(srcfile, dstfile):
730 "Make a symlink safely"
731 if dstfile:
732 if os.path.exists(dstfile) and not os.path.samefile(dstfile, srcfile):
733 os.remove(dstfile)
734 if not os.path.exists(dstfile):
735 evgenLog.info("Symlinking %s to %s" % (srcfile, dstfile))
736 print ("Symlinking %s to %s" % (srcfile, dstfile))
737 os.symlink(srcfile, dstfile)
738 else:
739 evgenLog.debug("Symlinking: %s is already the same as %s" % (dstfile, srcfile))
740
741
742if eventsFile or datFile:
743 if not hasattr(runArgs, "inputGeneratorFile") or runArgs.inputGeneratorFile == "NONE":
744 raise RuntimeError("%s needs input file (argument inputGeneratorFile)" % runArgs.jobConfig)
745 if evgenConfig.inputfilecheck and not re.search(evgenConfig.inputfilecheck, runArgs.inputGeneratorFile):
746 raise RuntimeError("inputGeneratorFile=%s is incompatible with inputfilecheck '%s' in %s" %
747 (runArgs.inputGeneratorFile, evgenConfig.inputfilecheck, runArgs.jobConfig))
748 if datFile:
749 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
750 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
751 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
752 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
753 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
754 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
755 else:
756 inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
757
758 realDatFile = find_unique_file('*%s*.dat' % inputroot)
759 mk_symlink(realDatFile, datFile)
760 if eventsFile:
761 myinputfiles = runArgs.inputGeneratorFile
762 genInputFiles = myinputfiles.split(',')
763 numberOfFiles = len(genInputFiles)
764 # if there is a single file, make a symlink. If multiple files, merge them into one output eventsFile
765 if(numberOfFiles<2):
766 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
767 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
768 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
769 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
770 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
771 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
772 else:
773 inputroot = os.path.basename(runArgs.inputGeneratorFile).split("._")[0]
774
775 if "events" in inputroot :
776 inputroot = inputroot.replace(".events","")
777 realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
778 mk_symlink(realEventsFile, eventsFile)
779 else:
780 allFiles = []
781 for file in genInputFiles:
782# Since we can have multiple files from the same task, inputroot must include more of the filename
783# to make it unique
784 if ".tar" in os.path.basename(runArgs.inputGeneratorFile):
785 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tar.")[0]
786 elif ".tgz" in os.path.basename(runArgs.inputGeneratorFile):
787 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".tgz")[0]
788 elif ".gz" in os.path.basename(runArgs.inputGeneratorFile):
789 inputroot = os.path.basename(runArgs.inputGeneratorFile).split(".gz")[0]
790 else:
791 input0 = os.path.basename(file).split("._")[0]
792 input1 = (os.path.basename(file).split("._")[1]).split(".")[0]
793 inputroot = input0+"._"+input1
794 evgenLog.info("inputroot = %s",inputroot)
795 realEventsFile = find_unique_file('*%s.*ev*ts' % inputroot)
796# The only input format where merging is permitted is LHE
797 with open(realEventsFile, 'r') as f:
798 first_line = f.readline()
799 if(not ("LesHouche" in first_line)):
800 raise RuntimeError("%s is NOT a LesHouche file" % realEventsFile)
801 allFiles.append(realEventsFile)
802 merge_lhe_files(allFiles,eventsFile)
803
804else:
805 if hasattr(runArgs, "inputGeneratorFile") and runArgs.inputGeneratorFile != "NONE":
806 raise RuntimeError("inputGeneratorFile arg specified for %s, but generators %s do not require an input file" %
807 (runArgs.jobConfig, str(gennames)))
808 if evgenConfig.inputfilecheck:
809 raise RuntimeError("evgenConfig.inputfilecheck specified in %s, but generators %s do not require an input file" %
810 (runArgs.jobConfig, str(gennames)))
811
812
813if evgenConfig.auxfiles:
814 from PyJobTransformsCore.trfutil import get_files
815 get_files(evgenConfig.auxfiles, keepDir=False, errorIfNotFound=True)
816
817
818
821
822def _checkattr(attr, required=False):
823 if not hasattr(evgenConfig, attr) or not getattr(evgenConfig, attr):
824 msg = "evgenConfig attribute '%s' not found." % attr
825 if required:
826 raise RuntimeError("Required " + msg)
827 return False
828 return True
829
830if hasattr(runArgs, "outputTXTFile"):
831 # counting the number of events in LHE output
832 count_ev = 0
833 with open(eventsFile) as f:
834 for line in f:
835 count_ev += line.count('/event')
836
837 print("MetaData: %s = %s" % ("Number of produced LHE events ", count_ev))
838elif hasattr(runArgs, "inputGeneratorFile"):
839 # counting the number of events in LHE input
840 count_ev = 0
841 with open(eventsFile) as f:
842 for line in f:
843 count_ev += line.count('/event')
844
845 print("MetaData: %s = %s" % ("Number of input LHE events ", count_ev))
846
847
848if _checkattr("description", required=True):
849 msg = evgenConfig.description
850 if _checkattr("notes"):
851 msg += " " + evgenConfig.notes
852 print ("MetaData: %s = %s" % ("physicsComment", msg))
853
854if _checkattr("generators", required=True):
855 print ("MetaData: %s = %s" % ("generatorName", "+".join(gennamesvers)))
856if _checkattr("process"):
857 print ("MetaData: %s = %s" % ("physicsProcess", evgenConfig.process))
858if _checkattr("tune"):
859 print ("MetaData: %s = %s" % ("generatorTune", evgenConfig.tune))
860if _checkattr("hardPDF"):
861 print ("MetaData: %s = %s" % ("hardPDF", evgenConfig.hardPDF))
862if _checkattr("softPDF"):
863 print ("MetaData: %s = %s" % ("softPDF", evgenConfig.softPDF))
864if _checkattr("nEventsPerJob"):
865 print ("MetaData: %s = %s" % ("nEventsPerJob", evgenConfig.nEventsPerJob))
866if _checkattr("keywords"):
867 print ("MetaData: %s = %s" % ("keywords", ", ".join(evgenConfig.keywords).lower()))
868if _checkattr("categories"):
869 print ("MetaData: %s = %s" % ("categories", ", ".join(evgenConfig.categories)))
870if _checkattr("specialConfig"):
871 print ("MetaData: %s = %s" % ("specialConfig", evgenConfig.specialConfig))
872# TODO: Require that a contact / JO author is always set
873if _checkattr("contact"):
874 print ("MetaData: %s = %s" % ("contactPhysicist", ", ".join(evgenConfig.contact)))
875print ("MetaData: %s = %s" % ("randomSeed", str(runArgs.randomSeed)))
876
877# Output list of generator filters used
878filterNames = [alg.getType() for alg in acas.iter_algseq(filtSeq)]
879excludedNames = ['AthSequencer', 'PyAthena::Alg', 'TestHepMC']
880filterNames = list(set(filterNames) - set(excludedNames))
881print ("MetaData: %s = %s" % ("genFilterNames", ", ".join(filterNames)))
882
883if (hasattr( runArgs, "allowOldFilter") and runArgs.allowOldFilter):
884 for alg in acas.iter_algseq(filtSeq):
885 filtName = alg.getType()
886 exceptName =['xAOD','Jet']
887 if filtName not in excludedNames:
888 if not any(ex in filtName for ex in exceptName):
889 alg.AllowOldFilter=True
890
891
894
895from PyJobTransformsCore.runargs import RunArguments
896runPars = RunArguments()
897runPars.nEventsPerJob = evgenConfig.nEventsPerJob
898runPars.maxeventsstrategy = evgenConfig.maxeventsstrategy
899with open("config.pickle", "wb") as f:
900 import pickle
901 pickle.dump(runPars, f)
902
903
904
907evgenLog.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: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: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)