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, hadronisation, 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
55 """Return a boolean of whether this set of generators requires the steering command line flag"""
56 if "EvtGen" not in gennames: return False
57 if any(("Pythia" in gen and "Pythia8" not in gen) for gen in gennames): return True
58 if any(("Herwig" in gen and "Herwig7" not in gen) for gen in gennames): return True
59 return False
60
61def gen_known(genname):
62 """Return whether a generator name is known"""
63 return genname in KnownGenerators
64
65def gens_known(gennames):
66 """Return whether all generator names are known"""
67 return all(gen_known(g) for g in gennames)
68
69def gen_lhef(genname):
70 """Return whether a generator uses LHEF input files"""
71 return genname in LHEFGenerators
72
73def gens_lhef(gennames):
74 """Return whether any of the generators uses LHEF input files"""
75 return any(gen_lhef(g) for g in gennames)
76
77def gen_testhepmc(genname):
78 """Return whether a generator should be sanity tested with TestHepMC"""
79 return genname not in NoTestHepMCGenerators
80
81def gens_testhepmc(gennames):
82 """Return whether all of the generators should be sanity tested with TestHepMC"""
83 return all(gen_testhepmc(g) for g in gennames)
84
85def gen_notune(genname):
86 """Return whether a generator is allowed to not provide PDF and tune information"""
87 return genname not in NoTuneGenerators
88
89def gens_notune(gennames):
90 """Return whether all of the generators are allowed to not provide PDF and tune information"""
91 return all(gen_notune(g) for g in gennames)
92
93def gen_purgenoendvtx(genname):
94 """Return whether a generator may produce unstable particles
95 without end vertex that have to be purged"""
96 return genname in PurgeNoEndVtxGenerators
97
98def gens_purgenoendvtx(gennames):
99 """Return whether any of the generators may produce unstable particles
100 without end vertex that have to be purged"""
101 return any(gen_purgenoendvtx(g) for g in gennames)
102
103def gen_sortkey(genname):
104 """Return a key suitable for sorting a generator name by stage, then alphabetically"""
105
106 # Sort mainly in order of generator stage
107 genstage = None
108 for istage, gens in enumerate([LHEFGenerators, HIMainGenerators, MainGenerators,AfterburnerGenerators]):
109 if genname in gens:
110 genstage = istage
111 break
112
113 # Return a tuple
114 return (genstage, genname)
115
116# Function to perform consistency check on jO
117def checkNaming(jofile):
118 import os, sys, string
119
120 joparts = (os.path.basename(jofile)).split(".")
121 # Perform some consistency checks
122 if joparts[0].startswith("mc") and all(c in string.digits for c in joparts[0][2:]):
123 # Check that there are exactly 4 name parts separated by '.': MCxx, DSID, physicsShort, .py
124 if len(joparts) != 3:
125 evgenLog.error(jofile + " name format is wrong: must be of the form mc.<physicsShort>.py: please rename.")
126 sys.exit(1)
127 # Check the length limit on the physicsShort portion of the filename
128 jo_physshortpart = joparts[1]
129 if len(jo_physshortpart) > 50:
130 evgenLog.error(jofile + " contains a physicsShort field of more than 60 characters: please rename.")
131 sys.exit(1)
132 # There must be at least 2 physicsShort sub-parts separated by '_': gens, (tune)+PDF, and process
133 jo_physshortparts = jo_physshortpart.split("_")
134 if len(jo_physshortparts) < 2:
135 evgenLog.error(jofile + " has too few physicsShort fields separated by '_': should contain <generators>(_<tune+PDF_if_available>)_<process>. Please rename.")
136 sys.exit(1)
137
138 # NOTE: a further check on physicsShort consistency is done below, after fragment loading
139 check_jofiles="/cvmfs/atlas.cern.ch/repo/sw/Generators/MC16JobOptions/scripts"
140 sys.path.append(check_jofiles)
141 from check_jo_consistency import check_naming
142 if os.path.exists(check_jofiles):
143 check_naming(os.path.basename(jofile))
144 else:
145 evgenLog.error("check_jo_consistency.py not found")
146 sys.exit(1)
147
148
150 if sample.nEventsPerJob < 1:
151 raise RuntimeError("nEventsPerJob must be at least 1")
152 elif sample.nEventsPerJob > 100000:
153 raise RuntimeError("nEventsPerJob can be max. 100000")
154 else:
155 allowed_nEventsPerJob_lt1000 = [1, 2, 5, 10, 20, 25, 50, 100, 200, 500, 1000]
156 if sample.nEventsPerJob >= 1000 and sample.nEventsPerJob <= 10000 and \
157 (sample.nEventsPerJob % 1000 != 0 or 10000 % sample.nEventsPerJob != 0):
158 raise RuntimeError("nEventsPerJob in range [1K, 10K] must be a multiple of 1K and a divisor of 10K")
159 elif sample.nEventsPerJob > 10000 and sample.nEventsPerJob % 10000 != 0:
160 raise RuntimeError("nEventsPerJob >10K must be a multiple of 10K")
161 elif sample.nEventsPerJob < 1000 and sample.nEventsPerJob not in allowed_nEventsPerJob_lt1000:
162 raise RuntimeError("nEventsPerJob in range <= 1000 must be one of %s" % allowed_nEventsPerJob_lt1000)
163
164def checkKeywords(sample, evgenLog):
165 import sys
166
167 # Get file containing keywords
168 from AthenaCommon.Utils.unixtools import find_datafile
169 kwpath = find_datafile("evgenkeywords.txt")
170
171 # Load the allowed keywords from the file
172 allowed_keywords = []
173 if kwpath:
174 evgenLog.info("evgenkeywords = %s", kwpath)
175 kwf = open(kwpath, "r")
176 for l in kwf:
177 allowed_keywords += l.strip().lower().split()
178 # Check the JO keywords against the allowed ones
179 evil_keywords = []
180 for k in sample.keywords:
181 if k.lower() not in allowed_keywords:
182 evil_keywords.append(k)
183 if evil_keywords:
184 msg = "keywords contains non-standard keywords: %s. " % ", ".join(evil_keywords)
185 msg += "Please check the allowed keywords list and fix."
186 evgenLog.error(msg)
187 sys.exit(1)
188 else:
189 evgenLog.warning("evgenkeywords.txt not found ")
190
191def checkCategories(sample, evgenLog):
192 import sys
193
194 # Get file containing category names
195 from AthenaCommon.Utils.unixtools import find_datafile
196 lkwpath = find_datafile("CategoryList.txt")
197
198 # Load the allowed categories names from the file
199 allowed_cat = []
200 if lkwpath:
201 from ast import literal_eval
202 with open(lkwpath, 'r') as catlist:
203 for line in catlist:
204 allowed_list = literal_eval(line)
205 allowed_cat.append(allowed_list)
206
207 # Check the JO categories against the allowed ones
208 bad_cat =[]
209 it = iter(sample.categories)
210 for x in it:
211 l1 = x
212 l2 = next(it)
213 if "L1:" in l2 and "L2:" in l1:
214 l1, l2 = l2, l1
215 print ("first",l1,"second",l2)
216 bad_cat.extend([l1, l2])
217 for a1,a2 in allowed_cat:
218 if l1.strip().lower()==a1.strip().lower() and l2.strip().lower()==a2.strip().lower():
219 bad_cat=[]
220 if bad_cat:
221 msg = "categories contains non-standard category: %s. " % ", ".join(bad_cat)
222 msg += "Please check the allowed categories list and fix."
223 evgenLog.error(msg)
224 sys.exit(1)
225 else:
226 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)