7 from AthenaCommon
import Logging
8 from ...decorators
import timed
9 from ...utility
import LHE, ProcessManager, SingleProcessThread
10 from xml.etree
import ElementTree
14 logger = Logging.logging.getLogger(
"PowhegControl")
17 @
timed(
"NNLO reweighter")
19 """! Move output to correctly named file.
21 @param process External NNLOPS process.
22 @param powheg_LHE_output Name of LHE file produced by PowhegBox.
24 @author James Robinson <james.robinson@cern.ch>
27 logger.info(
"Initialising NNLO reweighting")
28 output_LHE_name =
"{}.NNLO".
format(powheg_LHE_output)
29 aux_directory = os.path.join(*(process.executable.split(
"POWHEG")[:-1] + [
"AuxFiles"]))
32 logger.info(
"Using NNLO reweighter at {}".
format(process.executable))
35 logger.info(
"Removing comments from input LHE file")
36 os.system(
r"sed -i 's/\!.*$//g' {}".
format(powheg_LHE_output))
44 weight_pattern = re.compile(
r'MUR(\d+(\.\d+)?)_MUF(\d+(\.\d+)?)_PDF(\d+)')
47 def create_new_name(match):
48 mur_value = match.group(1)
49 muf_value = match.group(3)
50 pdf_number = match.group(5)
51 return f
'renscfact={mur_value} facscfact={muf_value} lhapdf={pdf_number}'
54 shutil.copy(input_filename,
'pwgevents.lhe_beforeNNLOPSreweighting')
57 with open(input_filename,
'r')
as input_file,
open(output_filename,
'w')
as output_file:
58 for line
in input_file:
60 if '<weight id' in line:
62 match = weight_pattern.search(line)
65 new_name = create_new_name(match)
67 line = line.replace(match.group(0), new_name)
68 elif '>nominal</weight>' in line:
70 line = line.replace(
'nominal',
'default')
72 output_file.write(line)
74 shutil.move(output_filename, powheg_LHE_output)
77 """! Get reweighting files from AuxFiles directory if not provided with job."""
78 for NNLO_reweighting_file_name
in NNLO_reweighting_inputs.values():
79 logger.info(
"Looking for configuration file {}...".
format(NNLO_reweighting_file_name))
80 if os.path.isfile(NNLO_reweighting_file_name):
81 logger.info(
"... found locally")
84 shutil.copy(glob.glob(
"{}/*/{}".
format(aux_directory, NNLO_reweighting_file_name))[0], NNLO_reweighting_file_name)
85 logger.info(
"... found in Powheg OTF auxiliary directory")
86 except (OSError, IndexError):
87 logger.warning(
"... NOT found!")
88 logger.warning(
"(1) if you generated this file then please ensure it is visible to Powheg on-the-fly.")
89 logger.warning(
"(2) if you expected Powheg on-the-fly to know about this file, please submit a bug report.")
90 raise IOError(
"NNLO reweighting inputs not found.")
94 """! Run the NNLO executable."""
96 NNLO_executable = process.executable
97 print(
"eA minnlo? ",NNLO_executable)
98 if "nnlopsreweighter" in NNLO_executable:
101 run_NNLOPS_executable(NNLO_executable, process.NNLO_reweighting_inputs, process.NNLO_weight_list, powheg_LHE_output, output_LHE_name)
103 elif "minnlo" in NNLO_executable:
104 run_DYNNLO_executable(NNLO_executable, process.NNLO_reweighting_inputs, powheg_LHE_output, output_LHE_name)
107 def run_NNLOPS_executable(NNLO_executable, NNLO_reweighting_inputs, NNLO_weight_list, powheg_LHE_output, output_LHE_name):
108 """! Run NNLOPSreweighter with appropriate run card."""
110 logger.info(
"Constructing NNLOPS run card")
111 with open(
"nnlopsreweighter.input",
"w")
as f_input_card:
113 f_input_card.write(
"lhfile {}\n\n".
format(powheg_LHE_output))
116 f_input_card.write(
"nnlofiles\n")
117 for label, NNLO_reweighting_file_name
in NNLO_reweighting_inputs.items():
118 f_input_card.write(
"'{}' {}\n".
format(label, NNLO_reweighting_file_name))
119 f_input_card.write(
"\n")
127 f_input_card.write(
"<initrwgt>\n")
128 f_input_card.write(
"<weightgroup name='NNLOPS'>\n")
129 for _, weight_ID, weight_name
in NNLO_weight_list:
130 f_input_card.write(
"<weight id='{}'> {} </weight>\n".
format(weight_ID, weight_name))
131 f_input_card.write(
"</weightgroup>\n")
132 f_input_card.write(
"</initrwgt>\n")
135 if not os.path.isfile(NNLO_executable):
136 raise OSError(
"NNLO reweighting executable {} not found!".
format(NNLO_executable))
137 manager = ProcessManager([SingleProcessThread(NNLO_executable)])
138 while manager.monitor():
142 shutil.move(
"pwgevents.lhe.nnlo", output_LHE_name)
146 """! Run DYNNLOPS reweighter with appropriate arguments."""
148 stage_1_command = [NNLO_executable, powheg_LHE_output, len(NNLO_reweighting_inputs)] +
list(NNLO_reweighting_inputs.values())
149 logger.info(
"Running reweighting stage 1: denominator calculation")
150 manager = ProcessManager([SingleProcessThread(stage_1_command)])
151 while manager.monitor():
155 stage_2_command = stage_1_command + [
"MINLO-W{}-denom.top".
format(idx)
for idx
in range(1, len(NNLO_reweighting_inputs) + 1)]
156 logger.info(
"Running reweighting stage 2: reweighting with pre-calculated denominators")
157 manager = ProcessManager([SingleProcessThread(stage_2_command)])
158 while manager.monitor():
162 shutil.move(
"pwgevents.lhe-nnlo", output_LHE_name)
166 """! Reformat NNLOPS and DYNNLO events."""
167 shutil.move(powheg_LHE_output,
"{}.NLO".
format(powheg_LHE_output))
168 logger.info(
"Reformatting NNLO reweighting output")
169 NNLO_executable = process.executable
171 if "nnlopsreweighter" in NNLO_executable:
174 elif "minnlo" in NNLO_executable:
179 """! Reformat NNLOPS events to fit ATLAS conventions."""
180 logger.info(
"Renaming NNLO weights")
182 with open(output_LHE_name,
'r')
as infile,
open(powheg_LHE_output,
'w')
as outfile:
189 inside_weight_block =
False
191 weight_number_NNLO = 0
196 if inside_weight_block:
198 if '</weights>' in line:
199 inside_weight_block =
False
202 line = line.replace(
'</weights>',
'</rwgt>')
205 weight_value = line.strip()
208 weight_id = weight_ids[weight_number]
211 line = f
'<wgt id="{weight_id}">{weight_value}</wgt>\n'
214 if '<weights>' in line:
215 inside_weight_block =
True
217 line = line.replace(
'<weights>',
'<rwgt>')
218 elif '#rwgt' in line:
221 elif '<weight id=' in line:
222 if 'default</weight>' in line:
223 match = re.search(
r'weight id=\'(\d+)\'\s*>(.*?)<', line)
224 weight_id = match.group(1)
225 line = line.replace(
'default',
'nominal')
226 weight_ids.append(weight_id)
227 elif '<weight id=\'nnlops-' in line:
229 match = re.search(
r"<weight id='(.*?)'\s>\s(.*?)\s<", line)
230 weight_id_NNLO = match.group(1)
231 weight_name = match.group(2)
232 line = line.replace(weight_id_NNLO,
str(NNLO_weight_list[weight_number_NNLO][0]))
234 renamed_name = weight_name.replace(
"'",
"")
236 renamed_name = renamed_name.replace(
" ",
"_")
237 line = line.replace(weight_name, renamed_name)
238 weight_number_NNLO += 1
241 match = re.search(
r'weight id=\'(\d+)\'\s*>(.*?)<', line)
243 weight_id = match.group(1)
244 weight_name = match.group(2)
245 weight_ids.append(weight_id)
247 renamed_name = re.sub(
r'renscfact=(\S+)\s+facscfact=(\S+)\s+lhapdf=(\d+)',
248 r'MUR\1_MUF\2_PDF\3', weight_name)
249 weight_mappings[weight_id] = renamed_name
251 line = line.replace(weight_name, renamed_name)
253 match = re.search(
r"<weight id='(.*?)</weight>", line)
255 removed_spaces = match.group(1).
replace(
" ",
"")
256 line = line.replace(match.group(1), removed_spaces)
258 elif '</header>' in line:
260 for nnlo_id, _, _
in NNLO_weight_list:
261 weight_ids.append(nnlo_id)
269 """! Reformat DYNNLO events to fit ATLAS conventions."""
270 logger.info(
"Converting output to LHEv3 format")
273 intro =
"\n".
join([elem
for elem
in [LHE.opening_tag(input_LHE_name), LHE.comment_block(input_LHE_name)]
if elem])
276 header = LHE.header_block(input_LHE_name)
277 init = LHE.init_block(input_LHE_name)
278 closing_string = LHE.postamble(input_LHE_name)
279 if closing_string.find(
"<LesHouchesEvents>") != -1:
280 footer = closing_string[closing_string.find(
"</LesHouchesEvents>"):]
282 footer =
"</LesHouchesEvents>"
285 logger.info(
"Adding LHEv3 weight: nominal")
286 header_elem = LHE.add_weight_to_header(header,
"nominal",
"nominal", 0)
289 weight_name_to_id = {}
291 w_elems = header_elem.iter(tag=
"weight")
292 except AttributeError:
293 w_elems = header_elem.getiterator(tag=
"weight")
294 weight_number_offset =
max(
filter(
lambda w: 4000 <= w < 5000, [
int(w_elem.attrib[
"id"])
for w_elem
in w_elems]) + [4000])
297 dynnlo_weight_names = [x[0]
for x
in LHE.string_to_weight(LHE.get_first_event(input_LHE_name))]
298 for idx, weight_name
in enumerate(dynnlo_weight_names, start=1):
299 logger.info(
"Adding LHEv3 weight: {}".
format(weight_name))
300 weight_name_to_id[weight_name] = weight_number_offset + idx
301 header_elem = LHE.add_weight_to_header(header_elem,
"dynnlo", weight_name, weight_name_to_id[weight_name])
304 logger.info(
"Converting Powheg output into LHEv3 format")
305 with open(powheg_LHE_output,
"w")
as f_output:
306 f_output.write(
"{}\n".
format(intro))
307 ElementTree.ElementTree(header_elem).
write(f_output)
308 f_output.write(
"{}\n".
format(init))
309 for event
in LHE.event_iterator(input_LHE_name):
310 f_output.write(LHE.Powheg2LHEv3(event, weight_name_to_id))
311 f_output.write(footer)
315 """! Construct list of NNLO weights."""
317 existing_weights, NNLO_weights = [], []
318 with open(powheg_LHE_output,
"r")
as f_input:
320 if "weight id=" in line:
321 existing_weights.append((
str(
int(line.split(
"'")[1])), line.split(
">")[1].
split(
"<")[0].strip()))
324 logger.info(
"Constructing list of weights")
325 for idx, (NNLO_weight_name, NNLOPS_command)
in enumerate(NNLO_output_weights.items(), start=4001):
326 NNLOPS_command = NNLOPS_command.replace(
"muR = 1.0, muF = 1.0",
"nominal")
328 for weight_ID, weight_name
in existing_weights:
330 re_match = re.search(
r"""["']{}["']""".
format(weight_name), NNLOPS_command)
331 if re_match
is not None:
332 NNLOPS_command = NNLOPS_command.replace(re_match.group(0), re_match.group(0).
replace(weight_name, weight_ID))
333 logger.info(
"... identified '{}' as weight ID '{}'".
format(weight_name, weight_ID))
335 existing_weights.append((idx, NNLO_weight_name))
336 NNLO_weights.append((idx, NNLO_weight_name, NNLOPS_command))