3 from AthenaCommon
import Logging
4 from ...decorators
import timed
5 from ...utility
import FileParser
6 from ..generators
import multicore_untimed, singlecore_untimed
13 logger = Logging.logging.getLogger(
"PowhegControl")
16 WeightTuple = collections.namedtuple(
"WeightTuple", [
"parameter_settings",
"keywords",
"ID",
"name",
"combine",
"group",
"parallel_xml_compatible"])
19 """! Returns True if the LHE file contains a weight called "nominal".
21 The weight must be present before the beginning of the first <event> block,
22 otherwise the function returns False.
24 @param powheg_LHE_output Name of LHE file produced by PowhegBox.
26 search_string =
"<weight id='0' >default</weight>"
27 with open(powheg_LHE_output,
'r')
as lhe_file:
29 if search_string
in line:
38 def reweighter(process, weight_groups, powheg_LHE_output):
39 """! Add a series of additional weights to an LHE file.
41 @param process PowhegBox process.
42 @param weight_groups OrderedDict containing groups of weights to add.
43 @param powheg_LHE_output Name of LHE file produced by PowhegBox.
45 logger.info(
"Starting to run PowhegControl PDF and QCD scale reweighter")
50 non_weight_attributes = [
"parameter_names",
"combination_method",
"keywords"]
53 xml_kwds = {
"renscfact":
"renscfact",
"facscfact":
"facscfact",
"lhans1":
"lhapdf",
"lhans2":
"lhapdf",
"width_correction" :
"width_correction",
"run_mode":
"run_mode"}
56 _idx_scale_start, _idx_PDF_start, _idx_other_start = 1001, 2001, 3001
58 if not process.use_XML_reweighting:
59 logger.warning(
"... XML-style reweighting is not enabled for this process. Will use old (multiple-pass) method.")
62 for group_name, weight_group
in weight_groups.items():
63 logger.info(
"Preparing weight group: {:<19} with {} weights".
format(group_name, len(weight_group) - len(non_weight_attributes)))
66 is_parallel_xml_compatible = process.use_XML_reweighting
and all([k
in xml_kwds.keys()
for _kw_set
in weight_group[
"keywords"]
for k
in _kw_set])
67 if is_parallel_xml_compatible:
68 _keywords = [
list(
set([xml_kwds[k]
for k
in _kw_set]))
for _kw_set
in weight_group[
"keywords"]]
70 if process.use_XML_reweighting:
71 logger.warning(
"... this weight group is incompatible with XML-style reweighting. Will use old (multiple-pass) method.")
72 _keywords = weight_group[
"keywords"]
73 keyword_dict = dict((n, k)
for n, k
in zip(weight_group[
"parameter_names"], _keywords))
76 tuple_kwargs = {
"keywords": keyword_dict,
"combine": weight_group[
"combination_method"],
"group": group_name,
"parallel_xml_compatible": is_parallel_xml_compatible}
80 weight_list.append(
WeightTuple(parameter_settings=weight_group[
"nominal"], ID=0, name=
"nominal", **tuple_kwargs))
83 elif group_name ==
"scale_variation":
84 for idx, name
in enumerate([k
for k
in weight_group.keys()
if k
not in non_weight_attributes], start=_idx_scale_start):
85 weight_list.append(
WeightTuple(parameter_settings=weight_group[name], ID=idx, name=name, **tuple_kwargs))
86 _idx_scale_start = idx + 1
89 elif group_name ==
"PDF_variation":
90 for idx, name
in enumerate([k
for k
in weight_group.keys()
if k
not in non_weight_attributes], start=_idx_PDF_start):
91 weight_list.append(
WeightTuple(parameter_settings=weight_group[name], ID=idx, name=name, **tuple_kwargs))
92 _idx_PDF_start = idx + 1
96 for idx, name
in enumerate([k
for k
in weight_group.keys()
if k
not in non_weight_attributes], start=_idx_other_start):
97 weight_list.append(
WeightTuple(parameter_settings=weight_group[name], ID=idx, name=name, **tuple_kwargs))
98 _idx_other_start = idx + 1
101 if os.path.isfile(
"pwgcounters.dat"):
102 shutil.copy(
"pwgcounters.dat",
"pwgcounters.dat.bak")
106 shutil.copy(
"powheg.input",
"powheg.input.before_reweighting")
108 raise IOError(
"Powheg input card ('powheg.input') cannot be found at the start of reweighting. In a normal setup, PowhegControl generates this input card. Its absence is probably a sign of problems --- please investigate or contact the PowhegControl experts.")
112 shutil.copy(powheg_LHE_output,
"{}.before_reweighting".
format(powheg_LHE_output))
114 raise IOError(
"Nominal LHE file could not be found. Probably POWHEG-BOX crashed during event generation.")
117 if process.use_XML_reweighting:
120 if process.has_parameter(
"run_mode")
and process.parameters_by_keyword(
"run_mode")[0].value != 1
and hasattr(process,
"reweight_for_MiNNLO")
and process.reweight_for_MiNNLO:
121 weight_list = [
WeightTuple(ID=0, name=
"nominal", group=
"nominal", parallel_xml_compatible=
True, parameter_settings=[(
"run_mode",1)], keywords={
"run_mode":[
"run_mode"]}, combine=
None)] + weight_list
123 weight_list = [
WeightTuple(ID=0, name=
"nominal", group=
"nominal", parallel_xml_compatible=
True, parameter_settings=[], keywords=
None, combine=
None)] + weight_list
125 FileParser(
"powheg.input").text_replace(
"pdfreweight .*",
"pdfreweight 0")
127 xml_lines, serial_xml_weight_list, current_weightgroup = [], [],
None
128 for weight
in weight_list:
130 if weight.parallel_xml_compatible
and weight.group != current_weightgroup:
131 xml_lines.append(
"</weightgroup>")
132 current_weightgroup = weight.group
133 xml_lines.append(
"<weightgroup name='{}' combine='{}'>".
format(weight.group, weight.combine))
135 if weight.parallel_xml_compatible:
136 keyword_pairs_str =
" ".
join([
"{}={}".
format(k, v)
for p, v
in weight.parameter_settings
for k
in weight.keywords[p]])
137 xml_lines.append(
"<weight id='{}'> {} </weight>".
format(weight.ID, keyword_pairs_str))
139 serial_xml_weight_list.append(weight)
140 xml_lines.append(xml_lines.pop(0))
141 n_parallel_xml_weights = len(weight_list) - len(serial_xml_weight_list)
144 if n_parallel_xml_weights > 0:
146 with open(
"reweighting_input.xml",
"w")
as f_rwgt:
147 f_rwgt.write(
"<initrwgt>\n")
148 [f_rwgt.write(
"{}\n".
format(xml_line))
for xml_line
in xml_lines]
149 f_rwgt.write(
"</initrwgt>")
154 FileParser(
"powheg.input").text_replace(
"rwl_file .*",
"rwl_file 'reweighting_input.xml'")
155 FileParser(
"powheg.input").text_replace(
"rwl_add .*",
"rwl_add 1")
156 FileParser(
"powheg.input").text_replace(
"clobberlhe .*",
"clobberlhe 1")
157 if process.has_parameter(
"run_mode")
and process.parameters_by_keyword(
"run_mode")[0].value != 1
and hasattr(process,
"reweight_for_MiNNLO")
and process.reweight_for_MiNNLO:
158 FileParser(
"powheg.input").text_replace(
"run_mode .*",
"run_mode 1")
160 logger.info(
"Preparing simultaneous calculation of {} additional weights for generated events.".
format(n_parallel_xml_weights))
163 if list(process.parameters_by_name(
"manyseeds"))[0].value == 1:
164 if process.powheg_version ==
"RES":
165 os.system(
'cp reweighting_input.xml backup_of_reweighting_input.xml')
166 os.system(
'cp powheg.input powheg.input.for_reweighting')
169 FileParser(
"powheg.input").text_replace(
"manyseeds .*",
"manyseeds 0")
170 FileParser(
"powheg.input").text_replace(
"parallelstage .*",
"parallelstage -1")
171 os.system(
'cp reweighting_input.xml backup_of_reweighting_input.xml')
172 os.system(
'cp powheg.input powheg.input.for_reweighting')
175 os.system(
'cp reweighting_input.xml backup_of_reweighting_input.xml')
176 os.system(
'cp powheg.input powheg.input.for_reweighting')
183 if len(serial_xml_weight_list) > 0:
184 logger.info(
"Preparing individual calculation of {} additional weights for generated events.".
format(len(serial_xml_weight_list)))
185 shutil.move(
"reweighting_input.xml",
"reweighting_input.nominal")
186 for idx_weight, weight
in enumerate(serial_xml_weight_list, start=1):
187 add_single_weight(process, weight, idx_weight, len(serial_xml_weight_list), use_XML=
True)
189 shutil.move(
"reweighting_input.nominal",
"reweighting_input.xml")
194 logger.info(
"Preparing individual calculation of {} additional weights for generated events.".
format(len(weight_list)))
195 for idx_weight, weight
in enumerate(weight_list, start=1):
199 if process.use_XML_reweighting:
200 comment_patterns = [
"#pdf",
"#rwgt",
"#new weight",
"#matching",
" #Random" ]
201 if process.remove_oldStyle_rwt_comments:
203 logger.info(
"Removing comment lines from lhe file - these lines can be added back using the 'remove_oldStyle_rwt_comments=False' argument in generate()")
205 for pattern
in comment_patterns:
206 removed = FileParser(powheg_LHE_output).text_remove(
"^"+pattern)
207 logger.info(
"{} line(s) starting with '{}' were removed from {}".
format(removed, pattern, powheg_LHE_output))
209 logger.info(
"Fixing comment lines from lhe file - these lines can be simply removed using the 'remove_oldStyle_rwt_comments=True' argument in generate()")
210 for pattern
in comment_patterns:
215 for weight
in weight_list:
216 replacelist += [[
".* id='{}' .*".
format(weight.ID),
"<weight id='{weight_id}'>{weight_name}</weight>".
format(weight_id=weight.ID, weight_name=weight.name), 1]]
219 replacelist += [[
'LesHouchesEvents version="1.0"',
'LesHouchesEvents version="3.0"', 1]]
220 FileParser(powheg_LHE_output).text_replace_multi(replacelist)
223 shutil.move(
"powheg_nominal.input",
"powheg.input")
224 if os.path.isfile(
"pwgcounters.dat.bak"):
225 shutil.move(
"pwgcounters.dat.bak",
"pwgcounters.dat")
228 """! Add a single additional weight to an LHE file.
230 @param process PowhegBox process.
231 @param weight Tuple with details of the weight to be added.
232 @param idx_weight Which number this weight is.
233 @param n_total Total number of weights being added.
234 @param use_XML Whether to use XML or old-style reweighting.
236 @
timed(
"weight variation {}/{}".
format(idx_weight, n_total))
237 def __timed_inner_fn():
238 logger.info(
"... weight name is: {}".
format(weight.name))
239 logger.info(
"... weight index ID is: {}".
format(weight.ID))
240 shutil.copy(
"powheg_nominal.input",
"powheg.input")
244 FileParser(
"powheg.input").text_replace(
"rwl_file .*",
"rwl_file 'reweighting_input.xml'")
245 FileParser(
"powheg.input").text_replace(
"rwl_add .*",
"rwl_add 1")
246 FileParser(
"powheg.input").text_replace(
"clobberlhe .*",
"clobberlhe 1")
247 FileParser(
"powheg.input").text_replace(
"pdfreweight .*",
"pdfreweight 0")
250 FileParser(
"powheg.input").text_replace(
"compute_rwgt 0",
"compute_rwgt 1")
252 FileParser(
"powheg.input").text_replace(
"manyseeds .*",
"manyseeds 0")
253 FileParser(
"powheg.input").text_replace(
"parallelstage .*",
"parallelstage -1")
256 for (parameter, value)
in weight.parameter_settings:
258 for keyword
in weight.keywords[parameter]:
259 FileParser(
"powheg.input").text_replace(
"^{} .*".
format(keyword),
"{} {}".
format(keyword, value))
260 logger.info(
"... setting {} to {}".
format(parameter, value))
262 logger.warning(
"Parameter '{}' not recognised. Cannot reweight!".
format(parameter))
266 with open(
"reweighting_input.xml",
"w")
as f_rwgt:
267 f_rwgt.write(
"<initrwgt>\n")
268 f_rwgt.write(
"<weightgroup name='{}' combine='{}'>\n".
format(weight.group, weight.combine))
269 f_rwgt.write(
"<weight id='{}'> </weight>\n".
format(weight.ID))
270 f_rwgt.write(
"</weightgroup>\n")
271 f_rwgt.write(
"</initrwgt>")
274 FileParser(
"powheg.input").text_replace(
"lhrwgt_descr .*",
"lhrwgt_descr '{}'".
format(weight.name))
275 FileParser(
"powheg.input").text_replace(
"lhrwgt_id .*",
"lhrwgt_id '{}'".
format(weight.ID))
276 FileParser(
"powheg.input").text_replace(
"lhrwgt_group_combine .*",
"lhrwgt_group_combine '{}'".
format(weight.combine))
277 FileParser(
"powheg.input").text_replace(
"lhrwgt_group_name .*",
"lhrwgt_group_name '{}'".
format(weight.group))
280 if list(process.parameters_by_name(
"manyseeds"))[0].value == 1:
281 if process.powheg_version ==
"RES":
284 FileParser(
"powheg.input").text_replace(
"manyseeds .*",
"manyseeds 0")
285 FileParser(
"powheg.input").text_replace(
"parallelstage .*",
"parallelstage -1")
295 reweighted_events_file_name = powheg_LHE_output.replace(
".lhe",
"-rwgt.lhe")
297 shutil.move(reweighted_events_file_name, powheg_LHE_output)
299 raise IOError(
"Reweighted LHE file '{filename}' could not be found. Probably POWHEG-BOX crashed during reweighting.".
format(filename=reweighted_events_file_name))
305 if not os.path.isfile(
"{}.before_reweighting".
format(lheFile)):
306 logger.error(
"Impossible to find file {}.before_reweighting".
format(lheFile))
310 shutil.move(lheFile,
"{}.text_replace_backup".
format(lheFile))
314 with open(
"{}.text_replace_backup".
format(lheFile),
"rb")
as f_input:
315 line_in = f_input.readline()
317 if re.search(
"^"+pattern.lstrip(), line_in.decode().lstrip()):
319 elif re.search(
"^</event>", line_in.decode().lstrip()):
321 line_in = f_input.readline()
323 n_found_noWeights = 0
324 n_events_noWeights = 0
325 with open(
"{}.before_reweighting".
format(lheFile),
"rb")
as f_input:
326 line_in = f_input.readline()
328 if re.search(
"^"+pattern.lstrip(), line_in.decode().lstrip()):
329 n_found_noWeights += 1
330 elif re.search(
"^</event>", line_in.decode().lstrip()):
331 n_events_noWeights += 1
332 line_in = f_input.readline()
335 impossible_to_fix =
False
340 with open(lheFile,
"w")
as f_output:
342 if n_found == n_found_noWeights:
344 with open(
"{}.text_replace_backup".
format(lheFile),
"rb")
as f_input,
open(
"{}.before_reweighting".
format(lheFile),
"rb")
as f_input_noWeights:
345 line_in = f_input.readline()
346 line_in_noWeights = f_input_noWeights.readline()
348 if re.search(
"^"+pattern.lstrip(), line_in.decode().lstrip()):
350 while line_in_noWeights:
351 if re.search(
"^"+pattern, line_in_noWeights.decode().lstrip()):
352 if (line_in.decode().rstrip().lstrip() != line_in_noWeights.decode().rstrip().lstrip()):
353 f_output.write(line_in_noWeights.decode())
356 f_output.write(line_in.decode())
357 line_in_noWeights = f_input_noWeights.readline()
361 line_in_noWeights = f_input_noWeights.readline()
363 line_in = f_input.readline()
365 impossible_to_fix =
True
367 if impossible_to_fix:
370 f_output.write(line_in.decode())
371 line_in = f_input.readline()
374 while line_in_noWeights:
375 if re.search(
"^"+pattern, line_in_noWeights.decode()):
376 impossible_to_fix =
True
378 if impossible_to_fix:
380 line_in_noWeights = f_input_noWeights.readline()
382 elif n_found == 0
and n_found_noWeights == n_events_noWeights
and n_events == n_events_noWeights:
384 with open(
"{}.text_replace_backup".
format(lheFile),
"rb")
as f_input,
open(
"{}.before_reweighting".
format(lheFile),
"rb")
as f_input_noWeights:
385 line_in = f_input.readline()
386 line_in_noWeights = f_input_noWeights.readline()
387 while line_in_noWeights:
388 if re.search(
"^"+pattern, line_in_noWeights.decode().lstrip()):
390 if re.search(
"^</event>", line_in.decode().lstrip()):
391 f_output.write(line_in_noWeights.decode())
392 f_output.write(line_in.decode())
394 line_in = f_input.readline()
397 f_output.write(line_in.decode())
398 line_in = f_input.readline()
399 line_in_noWeights = f_input_noWeights.readline()
401 f_output.write(line_in.decode())
402 line_in = f_input.readline()
405 if n_found == 0
and n_found_noWeights == 0:
406 shutil.move(
"{}.text_replace_backup".
format(lheFile), lheFile)
407 logger.info(
"No line with pattern '{}' was found in lhe file before or after reweighting, so need to fix it".
format(pattern))
408 elif impossible_to_fix:
409 shutil.move(
"{}.text_replace_backup".
format(lheFile), lheFile)
410 logger.info(
"Impossible to fix the possibly buggy comment lines with pattern {} in {} using the corresponding lines from {}.before_reweighting".
format(pattern, lheFile, lheFile))
411 logger.info(
"Keeping those lines as they are in '{}".
format(lheFile))
413 os.remove(
"{}.text_replace_backup".
format(lheFile))
415 logger.info(
"{} line(s) starting with '{}' replaced in {} using the corresponding line(s) from {}.before_reweighting".
format(n_replaced, pattern, lheFile, lheFile))
416 elif n_found != 0
and n_replaced == 0:
417 logger.info(
"No line starting with '{}' was replaced in {} ({} were found) since none seems buggy".
format(pattern, lheFile, n_found))
418 elif n_added_back !=0:
419 logger.info(
"{} line(s) starting with '{}' added back in {} using the corresponding line(s) from {}.before_reweighting".
format(n_added_back, pattern, lheFile, lheFile))