ATLAS Offline Software
Loading...
Searching...
No Matches
GenConfigHelpers.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3# Get logger
4from AthenaCommon.Logging import logging
5evgenLog = logging.getLogger('GenConfigHelpers')
6
7# Generators providing input events via the LHEF format
8# (used to determine the input file dummy-naming strategy for C++ generators)
9LHEFGenerators = ["Lhef", # generic name: prefer to use the names below
10 "aMcAtNlo", "McAtNlo", "Powheg", "MadGraph", "CompHep", "Geneva",
11 "MCFM", "JHU", "MEtop", "BCVEGPY", "Dire4Pythia8",
12 "BlackMax", "QBH", "gg2ww", "gg2zz", "gg2vv", "HvyN",
13 "VBFNLO", "FPMC", "ProtosLHEF",
14 "BCVEGPY", "STRINGS", "Phantom", "Pepper"]
15
16# "Main" generators which typically model QCD showers, hadronization, decays, etc.
17# Herwig family
18MainGenerators = ["Herwig7"]
19# Pythia family
20MainGenerators += ["Pythia8", "Pythia8B"]
21# Sherpa family
22MainGenerators += ["Sherpa"]
23# Soft QCD generators
24MainGenerators += ["Epos"]
25MainGenerators += ["Epos4"]
26# ATLAS-specific generators
27MainGenerators += ["ParticleGun"]
28MainGenerators += ["CosmicGenerator", "BeamHaloGenerator"]
29# Heavy ion generators - as a special group to avoid problems in sorting
30HIMainGenerators = ["AMPT","SuperChic","Starlight", "Hijing"]
31# Reading in fully-formed events
32
33MainGenerators += ["HepMCAscii"]
34
35# Special QED and decay afterburners
36# note: we have to use TauolaPP, because Tauolapp is used as a namespace in the external Tauolapp code
37AfterburnerGenerators = ["Photospp", "TauolaPP", "EvtGen", "ParticleDecayer"]
38
39# Set up list of allowed generators. The sample.generators list will be used
40# to set random seeds, determine input config and event files, and report used generators to AMI.
41KnownGenerators = LHEFGenerators + HIMainGenerators +MainGenerators + AfterburnerGenerators
42
43# Note which generators should NOT be sanity tested by the TestHepMC alg
44NoTestHepMCGenerators = ["Superchic","ParticleDecayer", "ParticleGun", "CosmicGenerator",
45 "BeamHaloGenerator", "FPMC", "Hijing", "Starlight"]
46
47# Generators with no flexibility/concept of a tune or PDF choice
48NoTuneGenerators = ["ParticleGun", "CosmicGenerator", "BeamHaloGenerator", "HepMCAscii"]
49
50# Generators whose unstable particles without end vertex have to be purged
51# n.b. "Pythia8-Angantyr" is not a 'real' name, the real name would be just 'Pythia8'
52PurgeNoEndVtxGenerators = ["Pythia8-Angantyr", "Herwig7", "Hijing"]
53
54# List of known parton showers
55KnownPartonShowerModels = [""] # default is empty string
56# Sherpa parton shower
57KnownPartonShowerModels += ["SherpaCSShower"]
58
59# List of known hadronization models
60KnownHadronizationModels = [""]
61# Sherpa models
62KnownHadronizationModels += ["SherpaAhadic", "SherpaPythia8"]
63
65 """Return a boolean of whether this set of generators requires the steering command line flag"""
66 if "EvtGen" not in gennames: return False
67 if any(("Pythia" in gen and "Pythia8" not in gen) for gen in gennames): return True
68 if any(("Herwig" in gen and "Herwig7" not in gen) for gen in gennames): return True
69 return False
70
71def gen_known(genname):
72 """Return whether a generator name is known"""
73 return genname in KnownGenerators
74
75def gens_known(gennames):
76 """Return whether all generator names are known"""
77 return all(gen_known(g) for g in gennames)
78
79def gen_lhef(genname):
80 """Return whether a generator uses LHEF input files"""
81 return genname in LHEFGenerators
82
83def gens_lhef(gennames):
84 """Return whether any of the generators uses LHEF input files"""
85 return any(gen_lhef(g) for g in gennames)
86
87def gen_testhepmc(genname):
88 """Return whether a generator should be sanity tested with TestHepMC"""
89 return genname not in NoTestHepMCGenerators
90
91def gens_testhepmc(gennames):
92 """Return whether all of the generators should be sanity tested with TestHepMC"""
93 return all(gen_testhepmc(g) for g in gennames)
94
95def gen_notune(genname):
96 """Return whether a generator is allowed to not provide PDF and tune information"""
97 return genname not in NoTuneGenerators
98
99def gens_notune(gennames):
100 """Return whether all of the generators are allowed to not provide PDF and tune information"""
101 return all(gen_notune(g) for g in gennames)
102
103def gen_purgenoendvtx(genname):
104 """Return whether a generator may produce unstable particles
105 without end vertex that have to be purged"""
106 return genname in PurgeNoEndVtxGenerators
107
108def gens_purgenoendvtx(gennames):
109 """Return whether any of the generators may produce unstable particles
110 without end vertex that have to be purged"""
111 return any(gen_purgenoendvtx(g) for g in gennames)
112
113def gen_sortkey(genname):
114 """Return a key suitable for sorting a generator name by stage, then alphabetically"""
115
116 # Sort mainly in order of generator stage
117 genstage = None
118 for istage, gens in enumerate([LHEFGenerators, HIMainGenerators, MainGenerators,AfterburnerGenerators]):
119 if genname in gens:
120 genstage = istage
121 break
122
123 # Return a tuple
124 return (genstage, genname)
125
126# Function to perform consistency check on jO
127def checkNaming(jofile):
128 import os, sys, string
129
130 joparts = (os.path.basename(jofile)).split(".")
131 # Perform some consistency checks
132 if joparts[0].startswith("mc") and all(c in string.digits for c in joparts[0][2:]):
133 # Check that there are exactly 4 name parts separated by '.': MCxx, DSID, physicsShort, .py
134 if len(joparts) != 3:
135 evgenLog.error(jofile + " name format is wrong: must be of the form mc.<physicsShort>.py: please rename.")
136 sys.exit(1)
137 # Check the length limit on the physicsShort portion of the filename
138 jo_physshortpart = joparts[1]
139 if len(jo_physshortpart) > 50:
140 evgenLog.error(jofile + " contains a physicsShort field of more than 60 characters: please rename.")
141 sys.exit(1)
142 # There must be at least 2 physicsShort sub-parts separated by '_': gens, (tune)+PDF, and process
143 jo_physshortparts = jo_physshortpart.split("_")
144 if len(jo_physshortparts) < 2:
145 evgenLog.error(jofile + " has too few physicsShort fields separated by '_': should contain <generators>(_<tune+PDF_if_available>)_<process>. Please rename.")
146 sys.exit(1)
147
148 # NOTE: a further check on physicsShort consistency is done below, after fragment loading
149 check_jofiles="/cvmfs/atlas.cern.ch/repo/sw/Generators/MC16JobOptions/scripts"
150 sys.path.append(check_jofiles)
151 from check_jo_consistency import check_naming
152 if os.path.exists(check_jofiles):
153 check_naming(os.path.basename(jofile))
154 else:
155 evgenLog.error("check_jo_consistency.py not found")
156 sys.exit(1)
157
158
160 if sample.nEventsPerJob < 1:
161 raise RuntimeError("nEventsPerJob must be at least 1")
162 elif sample.nEventsPerJob > 100000:
163 raise RuntimeError("nEventsPerJob can be max. 100000")
164 else:
165 allowed_nEventsPerJob_lt1000 = [1, 2, 5, 10, 20, 25, 50, 100, 200, 500, 1000]
166 if sample.nEventsPerJob >= 1000 and sample.nEventsPerJob <= 10000 and \
167 (sample.nEventsPerJob % 1000 != 0 or 10000 % sample.nEventsPerJob != 0):
168 raise RuntimeError("nEventsPerJob in range [1K, 10K] must be a multiple of 1K and a divisor of 10K")
169 elif sample.nEventsPerJob > 10000 and sample.nEventsPerJob % 10000 != 0:
170 raise RuntimeError("nEventsPerJob >10K must be a multiple of 10K")
171 elif sample.nEventsPerJob < 1000 and sample.nEventsPerJob not in allowed_nEventsPerJob_lt1000:
172 raise RuntimeError("nEventsPerJob in range <= 1000 must be one of %s" % allowed_nEventsPerJob_lt1000)
173
174def checkKeywords(sample, evgenLog):
175 import sys
176
177 # Get file containing keywords
178 from AthenaCommon.Utils.unixtools import find_datafile
179 kwpath = find_datafile("evgenkeywords.txt")
180
181 # Load the allowed keywords from the file
182 allowed_keywords = []
183 if kwpath:
184 evgenLog.info("evgenkeywords = %s", kwpath)
185 kwf = open(kwpath, "r")
186 for l in kwf:
187 allowed_keywords += l.strip().lower().split()
188 # Check the JO keywords against the allowed ones
189 evil_keywords = []
190 for k in sample.keywords:
191 if k.lower() not in allowed_keywords:
192 evil_keywords.append(k)
193 if evil_keywords:
194 msg = "keywords contains non-standard keywords: %s. " % ", ".join(evil_keywords)
195 msg += "Please check the allowed keywords list and fix."
196 evgenLog.error(msg)
197 sys.exit(1)
198 else:
199 evgenLog.warning("evgenkeywords.txt not found ")
200
201def checkCategories(sample, evgenLog):
202 import sys
203
204 # Get file containing category names
205 from AthenaCommon.Utils.unixtools import find_datafile
206 lkwpath = find_datafile("CategoryList.txt")
207
208 # Load the allowed categories names from the file
209 allowed_cat = []
210 if lkwpath:
211 from ast import literal_eval
212 with open(lkwpath, 'r') as catlist:
213 for line in catlist:
214 allowed_list = literal_eval(line)
215 allowed_cat.append(allowed_list)
216
217 # Check the JO categories against the allowed ones
218 bad_cat =[]
219 it = iter(sample.categories)
220 for x in it:
221 l1 = x
222 l2 = next(it)
223 if "L1:" in l2 and "L2:" in l1:
224 l1, l2 = l2, l1
225 print ("first",l1,"second",l2)
226 bad_cat.extend([l1, l2])
227 for a1,a2 in allowed_cat:
228 if l1.strip().lower()==a1.strip().lower() and l2.strip().lower()==a2.strip().lower():
229 bad_cat=[]
230 if bad_cat:
231 msg = "categories contains non-standard category: %s. " % ", ".join(bad_cat)
232 msg += "Please check the allowed categories list and fix."
233 evgenLog.error(msg)
234 sys.exit(1)
235 else:
236 evgenLog.warning("Could not find CategoryList.txt file ", lkwpath, " in $DATAPATH")
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
checkKeywords(sample, evgenLog)
checkCategories(sample, evgenLog)