diff --git a/lib/ramble/ramble/application.py b/lib/ramble/ramble/application.py index fbe9f2e33..4d7b563ab 100644 --- a/lib/ramble/ramble/application.py +++ b/lib/ramble/ramble/application.py @@ -2062,6 +2062,11 @@ def _analysis_dicts(self, criteria_list): # Extract file paths for all criteria for criteria in criteria_list.all_criteria(): log_path = self.expander.expand_var(criteria.file) + + # Ensure log path is absolute. If not, prepend the experiment run directory + if not os.path.isabs(log_path) and self.expander.experiment_run_dir not in log_path: + log_path = os.path.join(self.expander.experiment_run_dir, log_path) + if log_path not in files and os.path.exists(log_path): files[log_path] = self._new_file_dict() @@ -2094,6 +2099,10 @@ def _analysis_dicts(self, criteria_list): for fom, conf in fom_definitions.items(): log_path = self.expander.expand_var(conf["log_file"]) + # Ensure log path is absolute. If not, prepend the experiment run directory + if not os.path.isabs(log_path) and self.expander.experiment_run_dir not in log_path: + log_path = os.path.join(self.expander.experiment_run_dir, log_path) + if log_path not in files: files[log_path] = self._new_file_dict() diff --git a/lib/ramble/ramble/test/end_to_end/fom_log_file_path.py b/lib/ramble/ramble/test/end_to_end/fom_log_file_path.py new file mode 100644 index 000000000..295ab5ae5 --- /dev/null +++ b/lib/ramble/ramble/test/end_to_end/fom_log_file_path.py @@ -0,0 +1,59 @@ +# Copyright 2022-2025 The Ramble Authors +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +import os + +import pytest + +import ramble.workspace +import ramble.config +import ramble.software_environments +from ramble.main import RambleCommand + + +# everything here uses the mock_workspace_path +pytestmark = pytest.mark.usefixtures( + "mutable_config", "mutable_mock_workspace_path", "mock_applications" +) + +on = RambleCommand("on") +workspace = RambleCommand("workspace") + + +def test_relative_fom_log_works(mutable_config, mutable_mock_workspace_path, request): + workspace_name = request.node.name + + global_args = ["-w", workspace_name] + + ws = ramble.workspace.create(workspace_name) + workspace( + "manage", + "experiments", + "fom-log-path", + "-v", + "n_nodes=1", + "-v", + "n_ranks=1", + "-v", + "batch_submit={execute_experiment}", + global_args=global_args, + ) + ws._re_read() + + workspace("setup", global_args=global_args) + + on(global_args=global_args) + + workspace("analyze", global_args=global_args) + + with open(os.path.join(ws.root, "results.latest.txt")) as f: + data = f.read() + + assert "FAILED" not in data + assert "SUCCESS" in data + assert "test_fom = test" in data diff --git a/var/ramble/repos/builtin.mock/applications/fom-log-path/application.py b/var/ramble/repos/builtin.mock/applications/fom-log-path/application.py new file mode 100644 index 000000000..7bfa5a23c --- /dev/null +++ b/var/ramble/repos/builtin.mock/applications/fom-log-path/application.py @@ -0,0 +1,34 @@ +# Copyright 2022-2025 The Ramble Authors +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +from ramble.appkit import * + + +class FomLogPath(ExecutableApplication): + name = "fom-log-path" + + executable( + "write-fom", "echo 'fom: test'", redirect="log.file", use_mpi=False + ) + + workload("test", executable="write-fom") + + figure_of_merit( + "test_fom", + fom_regex=r"fom: (?P.*)", + group_name="test", + log_file="log.file", + units="", + ) + + success_criteria( + "found_test", + mode="string", + match=r"fom: test", + file="log.file", + )