Source code for src.simulation
import os
import subprocess
import re
import time
# GLPK's primal simplex occasionally fails to recover an optimal basis on these LPs
# ("glp_simplex: unable to recover undefined or non-optimal solution"); whether it happens depends
# on platform and build. The same LP then solves with the options below, all giving the same
# optimum. Earlier versions did not detect the failure and read stale result CSVs from the
# previous scenario (8 Welsch rows of the archived sweep have Total cost = 0 for this reason).
FALLBACK_OPTIONS = ["", "--nopresol", "--dual", "--exact"]
def _solved(output):
return ("OPTIMAL LP SOLUTION FOUND" in output) or ("OPTIMAL SOLUTION FOUND" in output)
[docs]
def run_simulation(case_info):
root_directory = case_info['root_directory']
# The model files write their result CSVs to ResultsPath = '<Model_X>/results', relative to the
# folder that holds the model folders, so glpsol runs from there (models/).
models_directory = os.path.dirname(os.path.abspath(root_directory))
case_folder = os.path.basename(os.path.normpath(root_directory))
data_infile_path = os.path.join(case_folder, case_info['output_otoole_txt'])
model_file_path = os.path.join(case_folder, case_info['model_file'])
data_glp_path = os.path.join(case_folder, case_info['data_glp'])
data_sol_path = os.path.join(case_folder, case_info['data_sol'])
start_time = time.time()
for option in FALLBACK_OPTIONS:
command = f"glpsol -m {model_file_path} -d {data_infile_path} --wglp {data_glp_path} --write {data_sol_path} {option}".strip()
result = subprocess.run(command, capture_output=True, text=True, shell=True, cwd=models_directory)
output = result.stdout + result.stderr
if _solved(output):
break
print(f"!!! {root_directory}: GLPK did not report an optimal solution with options '{option}'; retrying")
end_time = time.time()
execution_time = end_time - start_time
status = "optimal" if _solved(output) else "FAILED"
print(f"Simulation output:\n{output}")
time_used_search = re.search(r"Time used:\s+([\d.]+)\s+secs", output)
memory_used_search = re.search(r"Memory used:\s+([\d.]+)\s+Mb", output)
time_used = time_used_search.group(1) if time_used_search else "nan"
memory_used = memory_used_search.group(1) if memory_used_search else "nan"
print(f"Total Time: {execution_time:.2f} seconds")
print(f"Running Time: {time_used} seconds")
print(f"Memory Used: {memory_used} MB")
print(f"Solver status: {status} (options: '{option}')")
results_file_path = os.path.join(root_directory, "simulation_results.txt")
with open(results_file_path, 'w') as results_file:
results_file.write(f"Matrix + Running Time: {execution_time:.2f} seconds\n")
results_file.write(f"Running Time: {time_used} seconds\n")
results_file.write(f"Memory Used: {memory_used} MB\n")
results_file.write(f"Solver status: {status}\n")
results_file.write(f"GLPK options: {option or 'default'}\n")
return status