From 7c9f32d7edc7f1ec429f186b8c30780adc81dc14 Mon Sep 17 00:00:00 2001 From: Eivind Jahren Date: Tue, 20 Aug 2024 15:28:30 +0200 Subject: [PATCH] Write eclbase to runpath_list if present --- docs/reference/configuration/keywords.rst | 17 +++++++++--- src/ert/libres_facade.py | 1 + .../workflows/export_runpath.py | 1 + src/ert/run_models/base_run_model.py | 1 + src/ert/runpaths.py | 15 +++++++---- src/ert/simulator/batch_simulator_context.py | 1 + tests/unit_tests/test_runpaths.py | 27 ++++++++++++------- 7 files changed, 45 insertions(+), 18 deletions(-) diff --git a/docs/reference/configuration/keywords.rst b/docs/reference/configuration/keywords.rst index 5125f59aef4..0c2f1333263 100644 --- a/docs/reference/configuration/keywords.rst +++ b/docs/reference/configuration/keywords.rst @@ -520,10 +520,19 @@ the filesystem. Since the number of realisations can be quite high this will easily overflow the commandline buffer; the solution used is to let ERT write a regular file. It looks like this:: - 0 /path/to/realization-0 CASE0 iter - 1 /path/to/realization-1 CASE1 iter - ... - N /path/to/realization-N CASEN iter + 003 /cwd/realization-3/iteration-0 case3 000 + 004 /cwd/realization-4/iteration-0 case4 000 + 003 /cwd/realization-3/iteration-1 case3 001 + 004 /cwd/realization-4/iteration-1 case4 001 + +The first column is the realization number, the second column is the runpath, +the third column is `` or `` if `` is not set, and +the last column is the iteration number. + +Note that several tools (such as fmu-ensemble) often expect the third column to +be the path to the reservoir simulator case, but when there is no reservoir +simulator involved, the third column is not a path at all but just the job +name. The path to this file can then be passed to the scripts using the magic string . The RUNPATH_FILE will by default be diff --git a/src/ert/libres_facade.py b/src/ert/libres_facade.py index 51847a62194..cfbdd10a685 100644 --- a/src/ert/libres_facade.py +++ b/src/ert/libres_facade.py @@ -143,6 +143,7 @@ def load_from_forward_model( runpath_format=self.config.model_config.runpath_format_string, filename=str(self.config.runpath_file), substitution_list=self.config.substitution_list, + eclbase=self.config.ensemble_config.eclbase, ), realisations, ensemble=ensemble, diff --git a/src/ert/plugins/hook_implementations/workflows/export_runpath.py b/src/ert/plugins/hook_implementations/workflows/export_runpath.py index 12e406e0992..5a578252568 100644 --- a/src/ert/plugins/hook_implementations/workflows/export_runpath.py +++ b/src/ert/plugins/hook_implementations/workflows/export_runpath.py @@ -40,6 +40,7 @@ def run(self, ert_config: ErtConfig, workflow_args: List[Any]) -> None: runpath_format=ert_config.model_config.runpath_format_string, filename=str(ert_config.runpath_file), substitution_list=ert_config.substitution_list, + eclbase=ert_config.ensemble_config.eclbase, ) run_paths.write_runpath_list( *self.get_ranges( diff --git a/src/ert/run_models/base_run_model.py b/src/ert/run_models/base_run_model.py index 1d9cc28875d..c4985a68239 100644 --- a/src/ert/run_models/base_run_model.py +++ b/src/ert/run_models/base_run_model.py @@ -178,6 +178,7 @@ def __init__( runpath_format=config.model_config.runpath_format_string, filename=str(config.runpath_file), substitution_list=self.substitution_list, + eclbase=config.ensemble_config.eclbase, ) self._iter_snapshot: Dict[int, Snapshot] = {} self._status_queue = status_queue diff --git a/src/ert/runpaths.py b/src/ert/runpaths.py index f5f134e2734..557dc5a4ab1 100644 --- a/src/ert/runpaths.py +++ b/src/ert/runpaths.py @@ -34,11 +34,13 @@ def __init__( runpath_format: str, filename: Union[str, Path] = ".ert_runpath_list", substitution_list: Optional[SubstitutionList] = None, + eclbase: Optional[str] = None, ): self._jobname_format = jobname_format self.runpath_list_filename = Path(filename) self._runpath_format = str(Path(runpath_format).resolve()) self._substitution_list = substitution_list or SubstitutionList() + self._eclbase = eclbase def set_ert_ensemble(self, ensemble_name: str) -> None: self._substitution_list[""] = ensemble_name @@ -78,8 +80,8 @@ def write_runpath_list( 003 /cwd/realization-3/iteration-1 job3 001 004 /cwd/realization-4/iteration-1 job4 001 - The example assumes that jobname_format is "job" and - runpath_format is "realization/iteration-" + The example assumes that jobname_format is "job", that there is + no eclbase and runpath_format is "realization/iteration-" :param iteration_numbers: The list of iterations to write entries for :param realization_numbers: The list of realizations to write entries for @@ -88,12 +90,15 @@ def write_runpath_list( with open(self.runpath_list_filename, "w", encoding="utf-8") as filehandle: for iteration in iteration_numbers: for realization in realization_numbers: - job_name = self._substitution_list.substitute_real_iter( - self._jobname_format, realization, iteration + job_name_or_eclbase = self._substitution_list.substitute_real_iter( + self._eclbase if self._eclbase else self._jobname_format, + realization, + iteration, ) runpath = self._substitution_list.substitute_real_iter( self._runpath_format, realization, iteration ) + filehandle.write( - f"{realization:03d} {runpath} {job_name} {iteration:03d}\n" + f"{realization:03d} {runpath} {job_name_or_eclbase} {iteration:03d}\n" ) diff --git a/src/ert/simulator/batch_simulator_context.py b/src/ert/simulator/batch_simulator_context.py index 136889bee0c..c433b531e23 100644 --- a/src/ert/simulator/batch_simulator_context.py +++ b/src/ert/simulator/batch_simulator_context.py @@ -139,6 +139,7 @@ def __post_init__(self) -> None: runpath_format=ert_config.model_config.runpath_format_string, filename=str(ert_config.runpath_file), substitution_list=global_substitutions, + eclbase=ert_config.ensemble_config.eclbase, ) self.run_args = create_run_arguments( run_paths, diff --git a/tests/unit_tests/test_runpaths.py b/tests/unit_tests/test_runpaths.py index 86e6a25280e..e5f11e522ea 100644 --- a/tests/unit_tests/test_runpaths.py +++ b/tests/unit_tests/test_runpaths.py @@ -85,13 +85,22 @@ def test_runpath_file_writer_substitution(tmp_path): ) -def render_dynamic_values(s, itr, iens, geo_id): - dynamic_magic_strings = { - "": geo_id, - "": itr, - "": iens, - } - for key, val in dynamic_magic_strings.items(): - s = s.replace(key, str(val)) +def test_runpath_file_writes_eclbase_when_present(tmp_path): + runpath_file = tmp_path / "runpath_file" - return s + context = SubstitutionList() + context[""] = "my_case" + runpaths = Runpaths( + "_job", + "/path//ensemble-/iteration", + runpath_file, + context, + "path/to/eclbase", + ) + + runpaths.write_runpath_list([1], [1]) + + assert ( + runpath_file.read_text() + == "001 /path/my_case/ensemble-1/iteration1 path/to/eclbase 001\n" + )