41 def __init__(self, process_name, run_args=None, run_opts=None):
44 @param run_args Generate_tf run arguments
45 @param run_opts athena run options
55 pythonpath = os.environ.get(
"PYTHONPATH")
57 pythonpath = os.getenv(
"PYTHONPATH")
74 process_kwargs = {
"cores": int(os.environ.pop(
"ATHENA_CORE_NUMBER", 1))}
76 logger.warning(
"No run arguments found! Using defaults.")
79 if hasattr(run_args,
"ecmEnergy"):
80 process_kwargs[
"beam_energy"] = 0.5 * run_args.ecmEnergy
81 if hasattr(run_args,
"maxEvents")
and run_args.maxEvents > 0:
82 if hasattr(run_args,
"outputEVNTFile")
or hasattr(run_args,
"outputYODAFile"):
83 process_kwargs[
"nEvents"] = int(1.1 * run_args.maxEvents + 0.5)
85 process_kwargs[
"nEvents"] = run_args.maxEvents
87 if hasattr(run_args,
"outputEVNTFile")
or hasattr(run_args,
"outputYODAFile"):
88 process_kwargs[
"nEvents"] = 11000
90 process_kwargs[
"nEvents"] = 10000
91 if hasattr(run_args,
"randomSeed"):
92 process_kwargs[
"random_seed"] = run_args.randomSeed
93 if hasattr(run_args,
"outputTXTFile"):
94 for tarball_suffix
in [x
for x
in [
".tar.gz",
".tgz"]
if x
in run_args.outputTXTFile]:
96 self.
__output_LHE_file = run_args.outputTXTFile.split(tarball_suffix)[0] +
".events"
102 self.
process = getattr(processes.powheg, process_name)(os.environ[
"POWHEGPATH"].
replace(
"POWHEG-BOX",
""), **process_kwargs)
105 self.
process.check_using_integration_files()
108 for parameter
in self.
process.parameters:
109 if parameter.is_visible:
110 setattr(self, parameter.name, parameter.value)
113 for external
in self.
process.externals.values():
114 for parameter
in external.parameters:
115 if parameter.is_visible:
116 setattr(self, parameter.name, parameter.value)
125 if self.
process.cores == 1
and self.
process.powheg_version !=
"RES":
129 logger.info(
"Configuring this POWHEG-BOX-RES process to run in multistage mode")
132 logger.info(
"This job is running with an athenaMP-like whole-node setup, requesting {} cores".format(self.
process.cores))
133 if hasattr(run_opts,
"nprocs"):
134 logger.info(
"Re-configuring to keep athena running serially while parallelising POWHEG-BOX generation.")
137 logger.warning(
"Running in multicore mode but no 'nprocs' option was provided!")
140 list(self.
process.parameters_by_name(
"manyseeds"))[0].value = 1
146 logger.info(
"Configured for event generation with: {}".format(self.
process.executable))
174 """! Initialise runcard with appropriate options."""
176 if (hasattr(self,
"bornsuppfact")
and self.
bornsuppfact > 0.0)
and (hasattr(self,
"bornktmin")
and self.
bornktmin <= 0.0):
177 logger.warning(
"These settings: bornsuppfact = {} and bornktmin = {} cannot be used to generate events!".format(self.
bornsuppfact, self.
bornktmin))
178 logger.warning(
"Only fixed-order distributions can be produced with these settings!")
182 logger.info(
"Preparing to parallelise: running with {} jobs".format(self.
process.cores))
186 self.
process.validate_parameters()
189 parameters_unsorted = list(self.
process.parameters)
190 for external
in self.
process.externals.values():
191 parameters_unsorted.extend(external.parameters)
192 parameters_sorted = [x[1]
for x
in sorted(dict((p.name.lower(), p)
for p
in parameters_unsorted).items(), key=
lambda x: x[0])]
195 logger.info(
"=========================================================================================================")
196 logger.info(
"| User configurable parameters for this process |")
197 logger.info(
"=========================================================================================================")
198 logger.info(
"| Option name | ATLAS default | Description |")
199 logger.info(
"=========================================================================================================")
200 for parameter
in [p
for p
in parameters_sorted
if p.is_visible]:
201 _default_value =
"default" if (parameter.default_value
is None or parameter.default_value ==
"")
else str(parameter.default_value)
202 logger.info(
"| {:<25} | {:>19} | {}".format(parameter.name, _default_value, parameter.description))
203 logger.info(
"========================================================================================================")
206 parameters_changed = [p
for p
in parameters_sorted
if p.value
is not p.default_value]
207 logger.info(
"In these jobOptions {} parameter(s) have been changed from their default value:".format(len(parameters_changed)))
208 for idx, parameter
in enumerate(parameters_changed):
209 logger.info(
" {:<3} {:<19} {:>15} => {}".format(
"{})".format(idx + 1),
"{}:".format(parameter.name), str(parameter.default_value), parameter.value))
212 event_weight_options = []
216 logger.info(
"Writing POWHEG-BOX runcard to {}".format(run_card_path))
217 with open(run_card_path,
"w")
as f_runcard:
218 for parameter
in sorted(self.
process.parameters, key=
lambda p: p.keyword.lower()):
219 if parameter.name ==
"bornsuppfact" and parameter.value > 0:
220 event_weight_options.append((
"Born-level suppression",
"magnitude"))
221 if parameter.name ==
"withnegweights" and parameter.value > 0:
222 event_weight_options.append((
"negative event weights",
"sign"))
224 if parameter.name ==
"PDF" and isinstance(parameter.value, collections.abc.Iterable):
226 if len(parameter.value) < 2:
227 logger.error(
"Use 'PowhegConfig.PDF = {0}' rather than 'PowhegConfig.PDF = [{0}]'".format(parameter.value[0]
if len(parameter.value) > 0
else "<value>"))
228 raise TypeError(
"Use 'PowhegConfig.PDF = {0}' rather than 'PowhegConfig.PDF = [{0}]'".format(parameter.value[0]
if len(parameter.value) > 0
else "<value>"))
230 for PDF
in map(int, parameter.value[1:]):
233 if parameter.name
in [
"mu_F",
"mu_R"]
and isinstance(parameter.value, collections.abc.Iterable):
234 pdfs = list(self.
process.parameters_by_name(
"PDF"))[0].value
235 nominal_pdf = pdfs
if isinstance(pdfs, int)
or isinstance(pdfs, str)
else pdfs[0]
237 mu_Rs = list(self.
process.parameters_by_name(
"mu_R"))[0].value
238 mu_Fs = list(self.
process.parameters_by_name(
"mu_F"))[0].value
239 if len(parameter.value) < 2:
240 logger.error(
"Use 'PowhegConfig.{1} = {0}' rather than 'PowhegConfig.{1} = [{0}]'".format(parameter.value[0]
if len(parameter.value) > 0
else "<value>", parameter.name))
241 raise TypeError(
"Use 'PowhegConfig.{1} = {0}' rather than 'PowhegConfig.{1} = [{0}]'".format(parameter.value[0]
if len(parameter.value) > 0
else "<value>", parameter.name))
242 if not isinstance(mu_Rs, collections.abc.Iterable)
or not isinstance(mu_Fs, collections.abc.Iterable)
or len(mu_Rs)
is not len(mu_Fs):
243 logger.error(
"Number of mu_R and mu_F variations must be the same.")
244 raise ValueError(
"Number of mu_R and mu_F variations must be the same.")
246 for mu_R, mu_F
in zip(
map(float, mu_Rs[1:]),
map(float, mu_Fs[1:])):
249 self.
add_weight_to_group(
"scale_variation",
"MUR{mur}_MUF{muf}_PDF{nominal_pdf}".format(mur=mu_R_text, muf=mu_F_text, nominal_pdf=nominal_pdf), [mu_R, mu_F])
250 f_runcard.write(
"{}\n".format(parameter))
253 if len(event_weight_options) > 0:
255 logger.warning(
"POWHEG-BOX has been configured to run with {}".format(
" and ".join([x[0]
for x
in event_weight_options])))
256 logger.warning(
"This means that event weights will vary in {}.".format(
" and ".join([x[1]
for x
in event_weight_options])))
257 logger.warning(
"The cross-section passed to the parton shower will be inaccurate.")
258 logger.warning(
"Please use the cross-section printed in the log file before showering begins.")
261 doReweighting =
False
264 elif len(list(self.
process.parameters_by_keyword(
"for_reweighting"))) == 1:
265 if self.
process.parameters_by_keyword(
"for_reweighting")[0].value == 1:
266 logger.warning (
"No more than the nominal weight is requested, but for_reweighting is set to 1")
267 logger.warning (
"Therefore, reweighting is enabled anyway, otherwise virtual corrections wouldn't be included")
271 __ordered_event_weight_groups_list = []
272 for __key
in [
"scale_variation",
"PDF_variation"]:
276 __ordered_event_weight_groups_list.append(__item)
279 _n_weights = len(event_weight_group) - 3
282 logger.warning(
"Ignoring weight group '{}' as it does not have any variations defined. Check your jobOptions!".format(group_name))
286 logger.info(
"Adding new weight group '{}' which contains {} weights defined by varying {} parameters".format(group_name, _n_weights, len(event_weight_group[
"parameter_names"])))
287 for parameter_name
in event_weight_group[
"parameter_names"]:
288 logger.info(
"... {}".format(parameter_name))
289 if not self.
process.has_parameter(parameter_name):
290 logger.warning(
"Parameter '{}' does not exist for this process!".format(parameter_name))
291 raise ValueError(
"Parameter '{}' does not exist for this process!".format(parameter_name))
297 """! Generate events according to the scheduler."""
300 heartbeat.setName(
"heartbeat thread")
301 heartbeat.daemon =
True
305 logger.info(
"Using executable: {}".format(self.
process.executable))
308 extra_args = {
"quark colour fixer": [self.
process]}
311 for algorithm, external
in self.
process.externals.items():
312 if external.needs_scheduling(self.
process):
313 self.
scheduler.
add(algorithm, external, *extra_args.get(algorithm, []))
316 for algorithm
in self.
process.algorithms:
317 self.
scheduler.
add(algorithm, *extra_args.get(algorithm, []))
319 updated_xwgtup =
False
320 if len(list(self.
process.parameters_by_keyword(
"ubexcess_correct"))) == 1:
321 if list(self.
process.parameters_by_keyword(
"ubexcess_correct"))[0].value == 1:
322 algorithm =
"LHE ubexcess_correct weight updater"
323 self.
scheduler.
add(algorithm, *extra_args.get(algorithm, []))
324 algorithm =
"LHE file nominal weight updater"
325 self.
scheduler.
add(algorithm, *extra_args.get(algorithm, []))
326 logger.info (
"Since parameter ubexcess_correct was set to 1, event weights need to be modified by correction factor which is calculated during event generation.")
327 logger.info (
"Will also run LHE file nominal weight updater so that XWGTUP value is updated with value of reweighted nominal weight.")
328 updated_xwgtup =
True
329 if not updated_xwgtup:
330 if len(list(self.
process.parameters_by_keyword(
"for_reweighting"))) == 1:
331 if list(self.
process.parameters_by_keyword(
"for_reweighting"))[0].value == 1:
332 algorithm =
"LHE file nominal weight updater"
333 self.
scheduler.
add(algorithm, *extra_args.get(algorithm, []))
334 logger.info (
"Since parameter for_reweighting was set to 1, virtual corrections are added at the reweighting stage only.")
335 logger.info (
"Will run LHE file nominal weight updater so that XWGTUP value is updated with value of reweighted nominal weight.")
341 if not is_bb4l_semilep:
373 """! Add a new event weight to an existing group.
375 @param group_name Name of the group of weights that this weight belongs to.
376 @param weight_name Name of this event weight.
377 @param parameter_values Values of the parameters.
380 raise ValueError(
"Weight group '{}' has not been defined.".format(group_name))
382 if self.
process.has_parameter(
"run_mode")
and self.
process.parameters_by_keyword(
"run_mode")[0].value != 1
and hasattr(self.
process,
"reweight_for_MiNNLO")
and self.
process.reweight_for_MiNNLO:
383 parameter_values.append(1)
384 if len(parameter_values)
is not n_expected:
385 raise ValueError(
"Expected {} parameter values but only got {}".format(n_expected, len(parameter_values)))
387 for parameter_name, value
in zip(self.
__event_weight_groups[group_name][
"parameter_names"], parameter_values):
392 """! Override default attribute setting to stop users setting non-existent attributes.
394 @exceptions AttributeError Raise an AttributeError if the interface is frozen
396 @param key Attribute name.
397 @param value Value to set the attribute to.
400 if hasattr(self,
"process"):
402 for parameter
in self.
process.parameters_by_name(key):
403 parameter.ensure_default()
404 parameter.value = value
406 for external
in self.
process.externals.values():
407 for parameter
in external.parameters_by_name(key):
408 parameter.ensure_default()
409 parameter.value = value
412 if not hasattr(self, key):
413 raise AttributeError(
"This POWHEG-BOX process has no option '{}'".format(key))
414 object.__setattr__(self, key, value)