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
63 process_kwargs = {
"cores": int(os.environ.pop(
"ATHENA_CORE_NUMBER", 1))}
65 logger.warning(
"No run arguments found! Using defaults.")
68 if hasattr(run_args,
"ecmEnergy"):
69 process_kwargs[
"beam_energy"] = 0.5 * run_args.ecmEnergy
70 if hasattr(run_args,
"maxEvents")
and run_args.maxEvents > 0:
71 if hasattr(run_args,
"outputEVNTFile")
or hasattr(run_args,
"outputYODAFile"):
72 process_kwargs[
"nEvents"] = int(1.1 * run_args.maxEvents + 0.5)
74 process_kwargs[
"nEvents"] = run_args.maxEvents
76 if hasattr(run_args,
"outputEVNTFile")
or hasattr(run_args,
"outputYODAFile"):
77 process_kwargs[
"nEvents"] = 11000
79 process_kwargs[
"nEvents"] = 10000
80 if hasattr(run_args,
"randomSeed"):
81 process_kwargs[
"random_seed"] = run_args.randomSeed
82 if hasattr(run_args,
"outputTXTFile"):
83 for tarball_suffix
in [x
for x
in [
".tar.gz",
".tgz"]
if x
in run_args.outputTXTFile]:
85 self.
__output_LHE_file = run_args.outputTXTFile.split(tarball_suffix)[0] +
".events"
91 self.
process = getattr(processes.powheg, process_name)(os.environ[
"POWHEGPATH"].
replace(
"POWHEG-BOX",
""), **process_kwargs)
94 self.
process.check_using_integration_files()
97 for parameter
in self.
process.parameters:
98 if parameter.is_visible:
99 setattr(self, parameter.name, parameter.value)
102 for external
in self.
process.externals.values():
103 for parameter
in external.parameters:
104 if parameter.is_visible:
105 setattr(self, parameter.name, parameter.value)
114 if self.
process.cores == 1
and self.
process.powheg_version !=
"RES":
118 logger.info(
"Configuring this POWHEG-BOX-RES process to run in multistage mode")
121 logger.info(
"This job is running with an athenaMP-like whole-node setup, requesting {} cores".format(self.
process.cores))
122 if hasattr(run_opts,
"nprocs"):
123 logger.info(
"Re-configuring to keep athena running serially while parallelising POWHEG-BOX generation.")
126 logger.warning(
"Running in multicore mode but no 'nprocs' option was provided!")
129 list(self.
process.parameters_by_name(
"manyseeds"))[0].value = 1
135 logger.info(
"Configured for event generation with: {}".format(self.
process.executable))
163 """! Initialise runcard with appropriate options."""
165 if (hasattr(self,
"bornsuppfact")
and self.
bornsuppfact > 0.0)
and (hasattr(self,
"bornktmin")
and self.
bornktmin <= 0.0):
166 logger.warning(
"These settings: bornsuppfact = {} and bornktmin = {} cannot be used to generate events!".format(self.
bornsuppfact, self.
bornktmin))
167 logger.warning(
"Only fixed-order distributions can be produced with these settings!")
171 logger.info(
"Preparing to parallelise: running with {} jobs".format(self.
process.cores))
175 self.
process.validate_parameters()
178 parameters_unsorted = list(self.
process.parameters)
179 for external
in self.
process.externals.values():
180 parameters_unsorted.extend(external.parameters)
181 parameters_sorted = [x[1]
for x
in sorted(dict((p.name.lower(), p)
for p
in parameters_unsorted).items(), key=
lambda x: x[0])]
184 logger.info(
"=========================================================================================================")
185 logger.info(
"| User configurable parameters for this process |")
186 logger.info(
"=========================================================================================================")
187 logger.info(
"| Option name | ATLAS default | Description |")
188 logger.info(
"=========================================================================================================")
189 for parameter
in [p
for p
in parameters_sorted
if p.is_visible]:
190 _default_value =
"default" if (parameter.default_value
is None or parameter.default_value ==
"")
else str(parameter.default_value)
191 logger.info(
"| {:<25} | {:>19} | {}".format(parameter.name, _default_value, parameter.description))
192 logger.info(
"========================================================================================================")
195 parameters_changed = [p
for p
in parameters_sorted
if p.value
is not p.default_value]
196 logger.info(
"In these jobOptions {} parameter(s) have been changed from their default value:".format(len(parameters_changed)))
197 for idx, parameter
in enumerate(parameters_changed):
198 logger.info(
" {:<3} {:<19} {:>15} => {}".format(
"{})".format(idx + 1),
"{}:".format(parameter.name), str(parameter.default_value), parameter.value))
201 event_weight_options = []
205 logger.info(
"Writing POWHEG-BOX runcard to {}".format(run_card_path))
206 with open(run_card_path,
"w")
as f_runcard:
207 for parameter
in sorted(self.
process.parameters, key=
lambda p: p.keyword.lower()):
208 if parameter.name ==
"bornsuppfact" and parameter.value > 0:
209 event_weight_options.append((
"Born-level suppression",
"magnitude"))
210 if parameter.name ==
"withnegweights" and parameter.value > 0:
211 event_weight_options.append((
"negative event weights",
"sign"))
213 if parameter.name ==
"PDF" and isinstance(parameter.value, collections.abc.Iterable):
215 if len(parameter.value) < 2:
216 logger.error(
"Use 'PowhegConfig.PDF = {0}' rather than 'PowhegConfig.PDF = [{0}]'".format(parameter.value[0]
if len(parameter.value) > 0
else "<value>"))
217 raise TypeError(
"Use 'PowhegConfig.PDF = {0}' rather than 'PowhegConfig.PDF = [{0}]'".format(parameter.value[0]
if len(parameter.value) > 0
else "<value>"))
219 for PDF
in map(int, parameter.value[1:]):
222 if parameter.name
in [
"mu_F",
"mu_R"]
and isinstance(parameter.value, collections.abc.Iterable):
223 pdfs = list(self.
process.parameters_by_name(
"PDF"))[0].value
224 nominal_pdf = pdfs
if isinstance(pdfs, int)
or isinstance(pdfs, str)
else pdfs[0]
226 mu_Rs = list(self.
process.parameters_by_name(
"mu_R"))[0].value
227 mu_Fs = list(self.
process.parameters_by_name(
"mu_F"))[0].value
228 if len(parameter.value) < 2:
229 logger.error(
"Use 'PowhegConfig.{1} = {0}' rather than 'PowhegConfig.{1} = [{0}]'".format(parameter.value[0]
if len(parameter.value) > 0
else "<value>", parameter.name))
230 raise TypeError(
"Use 'PowhegConfig.{1} = {0}' rather than 'PowhegConfig.{1} = [{0}]'".format(parameter.value[0]
if len(parameter.value) > 0
else "<value>", parameter.name))
231 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):
232 logger.error(
"Number of mu_R and mu_F variations must be the same.")
233 raise ValueError(
"Number of mu_R and mu_F variations must be the same.")
235 for mu_R, mu_F
in zip(
map(float, mu_Rs[1:]),
map(float, mu_Fs[1:])):
238 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])
239 f_runcard.write(
"{}\n".format(parameter))
242 if len(event_weight_options) > 0:
244 logger.warning(
"POWHEG-BOX has been configured to run with {}".format(
" and ".join([x[0]
for x
in event_weight_options])))
245 logger.warning(
"This means that event weights will vary in {}.".format(
" and ".join([x[1]
for x
in event_weight_options])))
246 logger.warning(
"The cross-section passed to the parton shower will be inaccurate.")
247 logger.warning(
"Please use the cross-section printed in the log file before showering begins.")
250 doReweighting =
False
253 elif len(list(self.
process.parameters_by_keyword(
"for_reweighting"))) == 1:
254 if self.
process.parameters_by_keyword(
"for_reweighting")[0].value == 1:
255 logger.warning (
"No more than the nominal weight is requested, but for_reweighting is set to 1")
256 logger.warning (
"Therefore, reweighting is enabled anyway, otherwise virtual corrections wouldn't be included")
260 __ordered_event_weight_groups_list = []
261 for __key
in [
"scale_variation",
"PDF_variation"]:
265 __ordered_event_weight_groups_list.append(__item)
268 _n_weights = len(event_weight_group) - 3
271 logger.warning(
"Ignoring weight group '{}' as it does not have any variations defined. Check your jobOptions!".format(group_name))
275 logger.info(
"Adding new weight group '{}' which contains {} weights defined by varying {} parameters".format(group_name, _n_weights, len(event_weight_group[
"parameter_names"])))
276 for parameter_name
in event_weight_group[
"parameter_names"]:
277 logger.info(
"... {}".format(parameter_name))
278 if not self.
process.has_parameter(parameter_name):
279 logger.warning(
"Parameter '{}' does not exist for this process!".format(parameter_name))
280 raise ValueError(
"Parameter '{}' does not exist for this process!".format(parameter_name))
286 """! Generate events according to the scheduler."""
289 heartbeat.setName(
"heartbeat thread")
290 heartbeat.daemon =
True
294 logger.info(
"Using executable: {}".format(self.
process.executable))
297 extra_args = {
"quark colour fixer": [self.
process]}
300 for algorithm, external
in self.
process.externals.items():
301 if external.needs_scheduling(self.
process):
302 self.
scheduler.
add(algorithm, external, *extra_args.get(algorithm, []))
305 for algorithm
in self.
process.algorithms:
306 self.
scheduler.
add(algorithm, *extra_args.get(algorithm, []))
308 updated_xwgtup =
False
309 if len(list(self.
process.parameters_by_keyword(
"ubexcess_correct"))) == 1:
310 if list(self.
process.parameters_by_keyword(
"ubexcess_correct"))[0].value == 1:
311 algorithm =
"LHE ubexcess_correct weight updater"
312 self.
scheduler.
add(algorithm, *extra_args.get(algorithm, []))
313 algorithm =
"LHE file nominal weight updater"
314 self.
scheduler.
add(algorithm, *extra_args.get(algorithm, []))
315 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.")
316 logger.info (
"Will also run LHE file nominal weight updater so that XWGTUP value is updated with value of reweighted nominal weight.")
317 updated_xwgtup =
True
318 if not updated_xwgtup:
319 if len(list(self.
process.parameters_by_keyword(
"for_reweighting"))) == 1:
320 if list(self.
process.parameters_by_keyword(
"for_reweighting"))[0].value == 1:
321 algorithm =
"LHE file nominal weight updater"
322 self.
scheduler.
add(algorithm, *extra_args.get(algorithm, []))
323 logger.info (
"Since parameter for_reweighting was set to 1, virtual corrections are added at the reweighting stage only.")
324 logger.info (
"Will run LHE file nominal weight updater so that XWGTUP value is updated with value of reweighted nominal weight.")
330 if not is_bb4l_semilep:
362 """! Add a new event weight to an existing group.
364 @param group_name Name of the group of weights that this weight belongs to.
365 @param weight_name Name of this event weight.
366 @param parameter_values Values of the parameters.
369 raise ValueError(
"Weight group '{}' has not been defined.".format(group_name))
371 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:
372 parameter_values.append(1)
373 if len(parameter_values)
is not n_expected:
374 raise ValueError(
"Expected {} parameter values but only got {}".format(n_expected, len(parameter_values)))
376 for parameter_name, value
in zip(self.
__event_weight_groups[group_name][
"parameter_names"], parameter_values):
381 """! Override default attribute setting to stop users setting non-existent attributes.
383 @exceptions AttributeError Raise an AttributeError if the interface is frozen
385 @param key Attribute name.
386 @param value Value to set the attribute to.
389 if hasattr(self,
"process"):
391 for parameter
in self.
process.parameters_by_name(key):
392 parameter.ensure_default()
393 parameter.value = value
395 for external
in self.
process.externals.values():
396 for parameter
in external.parameters_by_name(key):
397 parameter.ensure_default()
398 parameter.value = value
401 if not hasattr(self, key):
402 raise AttributeError(
"This POWHEG-BOX process has no option '{}'".format(key))
403 object.__setattr__(self, key, value)