7 from pathlib
import Path
10 from AthenaCommon
import Logging
11 athMsgLog = Logging.logging.getLogger(
'Herwig7ConfigDecoder')
13 def extract_herwig_lines(input_file="Herwig.run", temp_file="HerwigConfigDecoder_RunCardDump.txt", skip_particles=False, skip_decays=False):
14 """Extract unique lines containing '/Herwig/' (excluding 'cvmfs') from the input file and save to a temporary file.
17 input_file (str): Path to the input Herwig run card file (default: 'Herwig.run').
18 temp_file (str): Path to the temporary output file for extracted lines (default: 'HerwigConfigDecoder_RunCardDump.txt').
19 skip_particles (bool): If True, skip lines related to /Herwig/Particles, /Herwig/Masses, and /Herwig/Widths.
20 skip_decays (bool): If True, skip lines related to /Herwig/Decays.
23 list: List of unique Herwig configuration lines extracted.
27 with open(input_file,
'r')
as infile:
28 all_lines = [line.strip()
for line
in infile
if '/Herwig/' in line
and 'cvmfs' not in line]
31 skip_particles_count = 0
33 for line
in all_lines:
35 if skip_particles
and (
'/Herwig/Particles' in line
or '/Herwig/Masses' in line
or '/Herwig/Widths' in line):
36 skip_particles_count += 1
39 if skip_decays
and '/Herwig/Decays' in line:
40 skip_decays_count += 1
43 if line
in seen_paths:
44 athMsgLog.debug(f
"Skipped duplicate path: {line}")
47 herwig_lines.append(line)
49 for i
in range(len(herwig_lines)):
50 if '|}/Herwig' in herwig_lines[i]:
51 herwig_lines[i] = herwig_lines[i].
replace(
'|}/Herwig',
'/Herwig')
52 elif '}/Herwig' in herwig_lines[i]:
53 herwig_lines[i] = herwig_lines[i].
replace(
'}/Herwig',
'/Herwig')
56 skipped_count = len(all_lines) - len(herwig_lines)
58 athMsgLog.debug(f
"Skipped {skipped_count} lines (including {len(all_lines) - len(seen_paths) - skip_particles_count - skip_decays_count} duplicates)")
59 if skip_particles_count > 0:
60 athMsgLog.debug(f
"Skipped {skip_particles_count} /Herwig/Particles, /Herwig/Masses and /Herwig/Widths lines due to --skip-particles")
61 if skip_decays_count > 0:
62 athMsgLog.debug(f
"Skipped {skip_decays_count} /Herwig/Decays lines due to --skip-decays")
65 with open(temp_file,
'w')
as outfile:
66 outfile.writelines(line +
'\n' for line
in herwig_lines)
68 athMsgLog.info(f
"Successfully extracted {len(herwig_lines)} unique lines to {temp_file}")
70 except FileNotFoundError:
71 athMsgLog.info(f
"Error: Input file '{input_file}' not found")
73 except Exception
as e:
74 athMsgLog.info(f
"Error: An error occurred: {str(e)}")
78 """Execute multiple Herwig 'get' commands in a single shell session and parse the output.
81 commands (list): List of commands or tuples (for interfaces) to execute.
82 phase (str): Execution phase, either 'paths' for path commands or 'interfaces' for interface commands.
85 list: List of tuples containing the command and its output or error message.
91 herwig_path = os.getenv(
'HERWIG7_PATH')
93 return [(cmd,
"Error: Environment variable HERWIG7_PATH is not set")
for cmd
in commands]
96 herwig_cmd = f
"{herwig_path}/bin/Herwig read --repo={herwig_path}/share/Herwig/HerwigDefaults.rpo"
100 temp_script = f
"temp_herwig_script_{os.getpid()}.in"
101 with open(temp_script,
'w')
as f:
104 f.write(f
"get {cmd}\n")
106 f.write(f
"get {cmd[0]}:{cmd[1]}\n")
109 cmd = f
"cat {temp_script} | {herwig_cmd}"
110 result = subprocess.run(
115 timeout=10 * len(commands)
119 output = result.stdout.strip()
121 output += f
"\nError: {result.stderr.strip()}"
124 Path(temp_script).unlink()
127 outputs = output.split(
"Herwig> get ")[1:]
if output
else []
129 for i, cmd
in enumerate(commands):
131 raw_output = outputs[i].strip()
133 cmd_str = cmd
if phase ==
"paths" else f
"{cmd[0]}:{cmd[1]}"
134 if raw_output.startswith(cmd_str):
135 raw_output = raw_output[len(cmd_str):].strip()
136 if phase ==
"interfaces":
138 if len(raw_output.split(
"\n")) == 1:
139 if raw_output.split(
"\n")[0] !=
'' and raw_output.split(
"\n")[0] !=
'Herwig>':
140 filtered_output = raw_output.split(
"\n")[0]
141 elif raw_output.split(
"\n")[0] !=
'Herwig>':
142 filtered_output =
"No response from the interface"
144 filtered_output =
"No response from the interface"
145 elif len(raw_output.split(
"\n")) == 2:
146 filtered_output =
"No response from the interface"
147 elif len(raw_output.split(
"\n")) == 3:
148 if all(
"Herwig" in line
for line
in raw_output.split(
"\n")):
149 filtered_output =
"No response from the interface"
151 filtered_output = raw_output.split(
"\n")[1]
153 filtered_output = raw_output
154 results.append((cmd[0], f
"{cmd[0]}:{cmd[1]}", filtered_output))
156 results.append((cmd, raw_output))
158 if phase ==
"interfaces":
159 results.append((cmd[0], f
"{cmd[0]}:{cmd[1]}",
"Error: No output received"))
161 results.append((cmd,
"Error: No output received"))
165 except subprocess.TimeoutExpired:
166 return [(cmd,
"Error: Command timed out")
if phase ==
"paths" else (cmd[0], f
"{cmd[0]}:{cmd[1]}",
"Error: Command timed out")
for cmd
in commands]
167 except Exception
as e:
168 return [(cmd, f
"Error: {str(e)}")
if phase ==
"paths" else (cmd[0], f
"{cmd[0]}:{cmd[1]}", f
"Error: {str(e)}")
for cmd
in commands]
170 def execute_herwig_get(herwig_lines, output_file="HerwigConfigDecoder_InterfaceDump.txt", max_lines=None):
171 """Execute Herwig 'get' commands for all provided paths in a single shell session and save the results.
174 herwig_lines (list): List of Herwig configuration paths to process.
175 output_file (str): Path to the output file for results (default: 'HerwigConfigDecoder_InterfaceDump.txt').
176 max_lines (int, optional): Maximum number of lines to process (default: None, processes all lines).
180 herwig_path = os.getenv(
'HERWIG7_PATH')
182 athMsgLog.error(
"Error: Environment variable HERWIG7_PATH is not set")
186 lines_to_process = herwig_lines[:max_lines]
if max_lines
is not None else herwig_lines
189 with open(output_file,
'w')
as outfile:
190 total_tasks = len(lines_to_process)
191 athMsgLog.info(f
"Processing {total_tasks} Herwig paths")
195 results.sort(key=
lambda x: lines_to_process.index(x[0])
if x[0]
in lines_to_process
else float(
'inf'))
198 for line, output
in results:
201 outfile.write(f
"{line}\n{output}\n\n")
202 athMsgLog.debug(f
"Success! Parsed the options for: {line}")
204 athMsgLog.info(f
"Results saved to {output_file} (processed {len(lines_to_process)} lines)")
206 except Exception
as e:
207 athMsgLog.info(f
"Error: An error occurred during execution: {str(e)}")
209 def process_valid_interfaces(input_file="HerwigConfigDecoder_InterfaceDump.txt", output_file="HerwigConfigDecoder_ConfigParameters.txt"):
210 """Process valid interfaces for each /Herwig/ path, execute 'get' commands, and save results.
213 input_file (str): Path to the input file containing Herwig paths and interfaces (default: 'HerwigConfigDecoder_InterfaceDump.txt').
214 output_file (str): Path to the output file for interface results (default: 'HerwigConfigDecoder_ConfigParameters.txt').
218 herwig_path_env = os.getenv(
'HERWIG7_PATH')
219 if not herwig_path_env:
220 athMsgLog.error(
"Error: Environment variable HERWIG7_PATH is not set")
224 with open(input_file,
'r')
as infile,
open(output_file,
'w')
as outfile:
225 content = infile.read()
226 blocks = content.split(
'\n\n')
233 lines = block.split(
'\n')
234 if not lines
or not lines[0].startswith(
'/Herwig/'):
237 herwig_path = lines[0].strip()
238 if herwig_path
in seen_paths:
239 athMsgLog.debug(f
"Skipped duplicate path in herwig_results.txt: {herwig_path}")
241 seen_paths.add(herwig_path)
242 block_paths.append(herwig_path)
245 line.strip()[2:]
for line
in lines[1:]
246 if line.strip().startswith(
'* ')
249 if not valid_interfaces:
250 errors.append((herwig_path, f
"No valid interfaces found for {herwig_path}"))
251 outfile.write(f
"{herwig_path}\nNo valid interfaces found\n\n")
254 all_tasks.extend([(herwig_path, interface)
for interface
in valid_interfaces])
257 athMsgLog.info(
"No interfaces to process")
259 for _, error_msg
in errors:
260 athMsgLog.debug(error_msg)
264 athMsgLog.info(f
"Processing {len(all_tasks)} interfaces")
268 for _, error_msg
in errors:
269 athMsgLog.debug(error_msg)
273 for herwig_path, get_command, filtered_output
in results:
274 if herwig_path
not in path_results:
275 path_results[herwig_path] = []
276 path_results[herwig_path].
append((get_command, filtered_output))
279 for herwig_path
in block_paths:
280 if herwig_path
not in path_results:
282 athMsgLog.debug(f
"Processing interfaces for {herwig_path}:")
283 outfile.write(f
"{herwig_path}\n")
284 for get_command, filtered_output
in path_results[herwig_path]:
285 athMsgLog.debug(f
"{get_command} ::: {filtered_output}")
286 outfile.write(f
"{get_command} ::: {filtered_output}\n")
289 athMsgLog.info(f
"Interface results saved to {output_file}")
291 except FileNotFoundError:
292 athMsgLog.info(f
"Error: Input file '{input_file}' not found")
293 except Exception
as e:
294 athMsgLog.info(f
"Error: An error occurred during interface processing: {str(e)}")
297 """Remove duplicate blocks in the configuration parameters file, keeping the first occurrence.
300 input_file (str): Path to the input file to process (default: 'HerwigConfigDecoder_ConfigParameters.txt').
304 with open(input_file,
'r')
as infile:
305 content = infile.read()
306 blocks = content.rstrip().
split(
'\n\n')
311 lines = block.split(
'\n')
312 if not lines
or not lines[0].startswith(
'/Herwig/'):
314 herwig_path = lines[0].strip()
315 if herwig_path
not in path_blocks:
316 path_blocks[herwig_path] = block
318 athMsgLog.debug(f
"Removed duplicate block for {herwig_path}")
324 lines = block.split(
'\n')
325 if not lines
or not lines[0].startswith(
'/Herwig/'):
327 herwig_path = lines[0].strip()
328 if herwig_path
not in seen_paths:
329 seen_paths.add(herwig_path)
330 unique_blocks.append(path_blocks[herwig_path])
333 with open(input_file,
'w')
as outfile:
334 outfile.write(
'\n\n'.
join(unique_blocks) +
'\n')
336 athMsgLog.info(f
"Removed duplicate blocks in {input_file}")
337 athMsgLog.info(f
"Retained {len(unique_blocks)} unique blocks")
339 except FileNotFoundError:
340 athMsgLog.info(f
"Error: Input file '{input_file}' not found")
341 except Exception
as e:
342 athMsgLog.info(f
"Error: An error occurred while removing duplicate blocks: {str(e)}")
344 def DecodeRunCard(input_file='Herwig.run', skip_particles=False, skip_decays=False):
345 """Main function to decode a Herwig run card by extracting paths, executing commands, and processing interfaces.
348 input_file (str): Path to the Herwig run card file (default: 'Herwig.run').
349 skip_particles (bool): If True, skip particle-related lines.
350 skip_decays (bool): If True, skip decay-related lines.
352 athMsgLog.info(
"Hello from the config-decoder!")
356 input_file=input_file,
357 skip_particles=skip_particles,
358 skip_decays=skip_decays
371 athMsgLog.info(
"Goodbye from the config-decoder!")