Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose precedent and extra_args in TemplateEvaluator #216

Merged
merged 2 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion optimas/evaluators/template_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ class TemplateEvaluator(Evaluator):
n_gpus : int, optional
The number of GPUs that will be made available for each evaluation. By
default, 0.
precedent : str, optional
Any string that should directly precede the ``executable``.
By default, if ``precedent`` is not specified and ``sim_template`` is
a Python file, the ``precedent`` will be set to ``sys.executable``,
which is the absolute path of the executable binary for the Python
interpreter.
extra_args : str, optional
Additional command line arguments to supply to MPI runner.
env_script : str, optional
The full path of a shell script to set up the environment for the
launched simulation. This is useful when the simulation needs to run
Expand Down Expand Up @@ -64,6 +72,8 @@ def __init__(
sim_files: Optional[List[str]] = None,
n_procs: Optional[int] = None,
n_gpus: Optional[int] = None,
precedent: Optional[str] = None,
extra_args: Optional[str] = None,
env_script: Optional[str] = None,
env_mpi: Optional[str] = None,
timeout: Optional[float] = None,
Expand All @@ -76,6 +86,8 @@ def __init__(
self.sim_template = sim_template
self.analysis_func = analysis_func
self.executable = executable
self.precedent = precedent
self.extra_args = extra_args
self.env_script = env_script
self.env_mpi = env_mpi
self.timeout = timeout
Expand Down Expand Up @@ -110,6 +122,7 @@ def get_sim_specs(
sim_specs["user"]["app_name"] = self._app_name
sim_specs["user"]["num_procs"] = self._n_procs
sim_specs["user"]["num_gpus"] = self._n_gpus
sim_specs["user"]["extra_args"] = self.extra_args
sim_specs["user"]["env_script"] = self.env_script
sim_specs["user"]["env_mpi"] = self.env_mpi
sim_specs["user"]["timeout"] = self.timeout
Expand Down Expand Up @@ -152,5 +165,7 @@ def _register_app(self) -> None:

# Register app.
Executor.executor.register_app(
full_path=executable_path, app_name=self._app_name
full_path=executable_path,
app_name=self._app_name,
precedent=self.precedent,
)
86 changes: 28 additions & 58 deletions optimas/sim_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,40 @@ def run_template_simulation(H, persis_info, sim_specs, libE_info):

# Launch and analyze each simulation step.
for step_specs in simulation_step_specs:
calc_status = execute_and_analyze_simulation(
# Create simulation input file.
sim_template = step_specs["sim_template"]
with open(sim_template, "r") as f:
template = jinja2.Template(f.read(), keep_trailing_newline=True)
with open(sim_template, "w") as f:
f.write(template.render(input_values))

# If the template is a python file, no need to provide it as argument
# (it has already been registered by libEnsemble as such).
if sim_template.endswith(".py"):
sim_template = None

# Launch simulation.
task = Executor.executor.submit(
app_name=step_specs["app_name"],
sim_template=step_specs["sim_template"],
input_values=input_values,
analysis_func=step_specs["analysis_func"],
libE_output=libE_output,
app_args=sim_template,
stdout=step_specs["stdout"],
stderr=step_specs["stderr"],
num_procs=step_specs["num_procs"],
num_gpus=step_specs["num_gpus"],
env_script=step_specs["env_script"],
mpi_runner_type=step_specs["env_mpi"],
timeout=step_specs["timeout"],
stdout=step_specs["stdout"],
stderr=step_specs["stderr"],
extra_args=step_specs["extra_args"],
)
calc_status = Executor.executor.polling_loop(
task, timeout=step_specs["timeout"]
)

# Data analysis from the last simulation
if calc_status == WORKER_DONE:
if step_specs["analysis_func"] is not None:
# Extract the objective function for the current simulation,
# as well as a few diagnostics
step_specs["analysis_func"](task.workdir, libE_output[0])
# If a step has failed, do not continue with next steps.
if calc_status != WORKER_DONE:
break
Expand All @@ -85,56 +105,6 @@ def run_template_simulation(H, persis_info, sim_specs, libE_info):
return libE_output, persis_info, calc_status


def execute_and_analyze_simulation(
app_name,
sim_template,
input_values,
analysis_func,
libE_output,
num_procs,
num_gpus,
env_script,
mpi_runner_type,
timeout,
stdout,
stderr,
):
"""Run simulation, handle outcome and analyze results."""
# Create simulation input file.
with open(sim_template, "r") as f:
template = jinja2.Template(f.read(), keep_trailing_newline=True)
with open(sim_template, "w") as f:
f.write(template.render(input_values))

# If the template is a python file, no need to provide it as argument
# (it has already been registered by libEnsemble as such).
if sim_template.endswith(".py"):
sim_template = None

# Launch simulation.
task = Executor.executor.submit(
app_name=app_name,
app_args=sim_template,
stdout=stdout,
stderr=stderr,
num_procs=num_procs,
num_gpus=num_gpus,
env_script=env_script,
mpi_runner_type=mpi_runner_type,
)

calc_status = Executor.executor.polling_loop(task, timeout=timeout)

# Data analysis from the last simulation
if calc_status == WORKER_DONE:
if analysis_func is not None:
# Extract the objective function for the current simulation,
# as well as a few diagnostics
analysis_func(task.workdir, libE_output[0])

return calc_status


def run_function(H, persis_info, sim_specs, libE_info):
"""Run an evaluation defined with a `FunctionEvaluator`."""
input_values = {}
Expand Down