Coverage for sparkle/CLI/add_solver.py: 0%
82 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-27 09:10 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-27 09:10 +0000
1#!/usr/bin/env python3
2"""Sparkle command to add a solver to the Sparkle platform."""
3import os
4import stat
5import sys
6import argparse
7import shutil
8from pathlib import Path
10import runrunner as rrr
12from sparkle.platform import file_help as sfh
13from sparkle.CLI.help import global_variables as gv
14from sparkle.structures import PerformanceDataFrame
15from sparkle.CLI.run_solvers import running_solvers_performance_data
16from sparkle.solver import Solver
17from sparkle.CLI.help import logging as sl
18from sparkle.platform import CommandName, COMMAND_DEPENDENCIES
19from sparkle.CLI.initialise import check_for_initialise
20from sparkle.CLI.help import argparse_custom as ac
21from sparkle.platform.settings_objects import SettingState
24def parser_function() -> argparse.ArgumentParser:
25 """Define the command line arguments."""
26 parser = argparse.ArgumentParser(
27 description="Add a solver to the Sparkle platform.",
28 epilog="")
29 parser.add_argument(*ac.DeterministicArgument.names,
30 **ac.DeterministicArgument.kwargs)
31 parser.add_argument(*ac.RunSolverNowArgument.names,
32 **ac.RunSolverNowArgument.kwargs)
33 parser.add_argument(*ac.NicknameSolverArgument.names,
34 **ac.NicknameSolverArgument.kwargs)
35 parser.add_argument(*ac.SolverPathArgument.names,
36 **ac.SolverPathArgument.kwargs)
37 parser.add_argument(*ac.RunOnArgument.names,
38 **ac.RunOnArgument.kwargs)
39 parser.add_argument(*ac.SkipChecksArgument.names,
40 **ac.SkipChecksArgument.kwargs)
41 return parser
44if __name__ == "__main__":
45 # Log command call
46 sl.log_command(sys.argv)
48 # Define command line arguments
49 parser = parser_function()
51 # Process command line arguments
52 args = parser.parse_args()
53 solver_source = Path(args.solver_path)
54 deterministic = args.deterministic
56 check_for_initialise(COMMAND_DEPENDENCIES[CommandName.ADD_SOLVER])
58 if not solver_source.exists():
59 print(f'Solver path "{solver_source}" does not exist!')
60 sys.exit(-1)
62 nickname = args.nickname
64 if args.run_on is not None:
65 gv.settings().set_run_on(
66 args.run_on.value, SettingState.CMD_LINE)
67 run_on = gv.settings().get_run_on()
69 if args.run_checks:
70 print("Running checks...")
71 solver = Solver(Path(solver_source))
72 pcs_file = solver.get_pcs_file()
73 if pcs_file is None:
74 print("None or multiple .pcs files found. Solver "
75 "is not valid for configuration.")
76 else:
77 print(f"One pcs file detected: {pcs_file.name}. ", end="")
78 if solver.read_pcs_file():
79 print("Can read the pcs file.")
80 else:
81 print("WARNING: Can not read the provided pcs file format.")
83 configurator_wrapper_path = solver_source / Solver.wrapper
84 if not (configurator_wrapper_path.is_file()
85 and os.access(configurator_wrapper_path, os.X_OK)):
86 print(f"WARNING: Solver {solver_source.name} does not have a solver wrapper "
87 f"(Missing file {Solver.wrapper}) or is not executable. ")
89 # Start add solver
90 solver_directory = gv.settings().DEFAULT_solver_dir / solver_source.name
91 if not solver_directory.exists():
92 solver_directory.mkdir(parents=True, exist_ok=True)
93 else:
94 print(f"ERROR: Solver {solver_source.name} already exists! "
95 "Can not add new solver.")
96 sys.exit(-1)
97 shutil.copytree(solver_source, solver_directory, dirs_exist_ok=True)
98 # Save the deterministic bool in the solver
99 with (solver_directory / Solver.meta_data).open("w+") as fout:
100 fout.write(str({"deterministic": deterministic}))
102 # Add RunSolver executable to the solver
103 runsolver_path = gv.settings().DEFAULT_runsolver_exec
104 if runsolver_path.name in [file.name for file in solver_directory.iterdir()]:
105 print("Warning! RunSolver executable detected in Solver "
106 f"{solver_source.name}. This will be replaced with "
107 f"Sparkle's version of RunSolver. ({runsolver_path})")
108 runsolver_target = solver_directory / runsolver_path.name
109 shutil.copyfile(runsolver_path, runsolver_target)
110 runsolver_target.chmod(os.stat(runsolver_target).st_mode | stat.S_IEXEC)
112 performance_data = PerformanceDataFrame(
113 gv.settings().DEFAULT_performance_data_path,
114 objectives=gv.settings().get_general_sparkle_objectives())
115 performance_data.add_solver(solver_directory)
116 performance_data.save_csv()
118 print(f"Adding solver {solver_source.name} done!")
120 if nickname is not None:
121 sfh.add_remove_platform_item(solver_directory,
122 gv.solver_nickname_list_path, key=nickname)
124 if args.run_solver_now:
125 num_job_in_parallel = gv.settings().get_number_of_jobs_in_parallel()
126 dependency_run_list = [running_solvers_performance_data(
127 gv.settings().DEFAULT_performance_data_path, num_job_in_parallel,
128 rerun=False, run_on=run_on
129 )]
131 sbatch_options = gv.settings().get_slurm_extra_options(as_args=True)
132 srun_options = ["-N1", "-n1"] + sbatch_options
133 run_construct_portfolio_selector = rrr.add_to_queue(
134 cmd="sparkle/CLI/construct_portfolio_selector.py",
135 name=CommandName.CONSTRUCT_PORTFOLIO_SELECTOR,
136 dependencies=dependency_run_list,
137 base_dir=sl.caller_log_dir,
138 sbatch_options=sbatch_options,
139 srun_options=srun_options)
141 dependency_run_list.append(run_construct_portfolio_selector)
143 run_generate_report = rrr.add_to_queue(
144 cmd="sparkle/CLI/generate_report.py",
145 name=CommandName.GENERATE_REPORT,
146 dependencies=dependency_run_list,
147 base_dir=sl.caller_log_dir,
148 sbatch_options=sbatch_options,
149 srun_options=srun_options)
151 # Write used settings to file
152 gv.settings().write_used_settings()