diff --git a/doc/changelog.d/4265.fixed.md b/doc/changelog.d/4265.fixed.md new file mode 100644 index 00000000000..40d959e7507 --- /dev/null +++ b/doc/changelog.d/4265.fixed.md @@ -0,0 +1,2 @@ +- Fixed `launch_fluent()` ordering so `case_file_name`/`case_data_file_name` are processed before `journal_file_names` when both are provided. +- In lightweight mode, deferred journal replay now completes before the background sync step begins. \ No newline at end of file diff --git a/doc/changelog.d/4990.miscellaneous.md b/doc/changelog.d/4990.miscellaneous.md new file mode 100644 index 00000000000..e61b5c8ce96 --- /dev/null +++ b/doc/changelog.d/4990.miscellaneous.md @@ -0,0 +1 @@ +Couple of issues in launch fluent diff --git a/src/ansys/fluent/core/launcher/launcher_utils.py b/src/ansys/fluent/core/launcher/launcher_utils.py index c302e4017d0..b78c1b1c493 100644 --- a/src/ansys/fluent/core/launcher/launcher_utils.py +++ b/src/ansys/fluent/core/launcher/launcher_utils.py @@ -210,12 +210,16 @@ def _confirm_watchdog_start(start_watchdog, cleanup_on_exit, fluent_connection): def _build_journal_argument( - topy: None | bool | str, journal_file_names: None | str | list[str] + topy: None | bool | str, + journal_file_names: None | str | list[str], + include_journal_file_names: bool = True, ) -> str: """Build Fluent commandline journal argument.""" def _impl( - topy: None | bool | str, journal_file_names: None | str | list[str] + topy: None | bool | str, + journal_file_names: None | str | list[str], + include_journal_file_names: bool, ) -> str: if journal_file_names and not isinstance(journal_file_names, (str, list)): raise TypeError( @@ -228,7 +232,7 @@ def _impl( fluent_jou_arg = "" if isinstance(journal_file_names, str): journal_file_names = [journal_file_names] - if journal_file_names: + if journal_file_names and include_journal_file_names: fluent_jou_arg += "".join( [f' -i "{journal}"' for journal in journal_file_names] ) @@ -239,4 +243,4 @@ def _impl( fluent_jou_arg += " -topy" return fluent_jou_arg - return _impl(topy, journal_file_names) + return _impl(topy, journal_file_names, include_journal_file_names) diff --git a/src/ansys/fluent/core/launcher/standalone_launcher.py b/src/ansys/fluent/core/launcher/standalone_launcher.py index 11c6bbe1ac0..e429d5d0107 100644 --- a/src/ansys/fluent/core/launcher/standalone_launcher.py +++ b/src/ansys/fluent/core/launcher/standalone_launcher.py @@ -228,8 +228,14 @@ def __init__( ) if self.argvals["cwd"]: self._kwargs.update(cwd=self.argvals["cwd"]) + self._defer_journal_file_read = bool( + self.argvals["journal_file_names"] + and (self.argvals["case_file_name"] or self.argvals["case_data_file_name"]) + ) self._launch_string += _build_journal_argument( - self.argvals["topy"], self.argvals["journal_file_names"] + self.argvals["topy"], + self.argvals["journal_file_names"], + include_journal_file_names=not self._defer_journal_file_read, ) if is_windows(): @@ -294,26 +300,7 @@ def __call__(self): if len(values) == 3: ip, port, password = values watchdog.launch(os.getpid(), port, password, ip) - if self.argvals["case_file_name"]: - if FluentMode.is_meshing(self.argvals["mode"]): - session.tui.file.read_case(self.argvals["case_file_name"]) - elif self.argvals["lightweight_mode"]: - session.read_case_lightweight(self.argvals["case_file_name"]) - else: - session.settings.file.read( - file_type="case", - file_name=self.argvals["case_file_name"], - ) - if self.argvals["case_data_file_name"]: - if not FluentMode.is_meshing(self.argvals["mode"]): - session.settings.file.read( - file_type="case-data", - file_name=self.argvals["case_data_file_name"], - ) - else: - raise RuntimeError( - "Case and data file cannot be read in meshing mode." - ) + self._process_case_data_and_journals(session) return session except Exception as ex: @@ -323,3 +310,48 @@ def __call__(self): server_info_file = Path(self._server_info_file_name) if server_info_file.exists(): server_info_file.unlink() + + @staticmethod + def _get_journal_file_names( + journal_file_names: None | str | list[str], + ) -> list[str]: + if isinstance(journal_file_names, str): + return [journal_file_names] + return journal_file_names or [] + + def _read_journals(self, session) -> None: + for journal_file_name in self._get_journal_file_names( + self.argvals["journal_file_names"] + ): + session.execute_tui( + f'/file/read-journal "{Path(journal_file_name).as_posix()}"' + ) + + def _process_case_data_and_journals(self, session) -> None: + lightweight_sync_deferred = False + if self.argvals["case_file_name"]: + if FluentMode.is_meshing(self.argvals["mode"]): + session.tui.file.read_case(self.argvals["case_file_name"]) + elif self.argvals["lightweight_mode"]: + session.read_case_lightweight( + self.argvals["case_file_name"], + start_sync=not self._defer_journal_file_read, + ) + lightweight_sync_deferred = self._defer_journal_file_read + else: + session.settings.file.read( + file_type="case", + file_name=self.argvals["case_file_name"], + ) + if self.argvals["case_data_file_name"]: + if not FluentMode.is_meshing(self.argvals["mode"]): + session.settings.file.read( + file_type="case-data", + file_name=self.argvals["case_data_file_name"], + ) + else: + raise RuntimeError("Case and data file cannot be read in meshing mode.") + if self._defer_journal_file_read: + self._read_journals(session) + if lightweight_sync_deferred: + session.start_case_lightweight_sync() diff --git a/src/ansys/fluent/core/session_solver.py b/src/ansys/fluent/core/session_solver.py index ad7d904a948..05039ec3b17 100644 --- a/src/ansys/fluent/core/session_solver.py +++ b/src/ansys/fluent/core/session_solver.py @@ -316,13 +316,21 @@ def _stop_bg_sessions(self): if thread.is_alive(): thread.join() - def read_case_lightweight(self, file_name: str): + def start_case_lightweight_sync(self): + """Start pending lightweight background sync sessions.""" + for thread in self._bg_session_threads: + if thread.ident is None: + thread.start() + + def read_case_lightweight(self, file_name: str, start_sync: bool = True): """Read a case file using light IO mode. Parameters ---------- file_name : str Case file name + start_sync : bool, optional + Whether to immediately start lightweight background sync. """ self.settings.file.read( @@ -336,6 +344,8 @@ def read_case_lightweight(self, file_name: str): target=self._start_bg_session_and_sync, args=(launcher_args,) ) ) + if start_sync: + self.start_case_lightweight_sync() def get_state(self) -> StateT: """Get the state of the object.""" diff --git a/src/ansys/fluent/core/session_solver.pyi b/src/ansys/fluent/core/session_solver.pyi index 0fb2ca3385e..0284e0b6e6c 100644 --- a/src/ansys/fluent/core/session_solver.pyi +++ b/src/ansys/fluent/core/session_solver.pyi @@ -39,7 +39,8 @@ class Solver: def system_coupling(self) -> SystemCoupling: ... @property def preferences(self) -> preferences_root: ... - def read_case_lightweight(self, file_name: str): ... + def start_case_lightweight_sync(self): ... + def read_case_lightweight(self, file_name: str, start_sync: bool = True): ... def read_case(self, file_name: str): ... def write_case(self, file_name: str): ... @property diff --git a/tests/test_launcher.py b/tests/test_launcher.py index f90d8f961ab..7618b3e54f1 100644 --- a/tests/test_launcher.py +++ b/tests/test_launcher.py @@ -57,6 +57,7 @@ _build_fluent_launch_args_string, get_fluent_exe_path, ) +from ansys.fluent.core.launcher.standalone_launcher import StandaloneLauncher from ansys.fluent.core.utils.fluent_version import FluentVersion import ansys.platform.instancemanagement as pypim @@ -474,6 +475,46 @@ def test_build_journal_argument(topy, journal_file_names, result, raises): assert _build_journal_argument(topy, journal_file_names) == result +def test_build_journal_argument_without_journal_files_but_with_topy(): + assert ( + _build_journal_argument("a.py", ["a.jou"], include_journal_file_names=False) + == ' -topy="a.py"' + ) + + +def test_lightweight_case_journal_read_is_completed_before_sync_step(): + launcher = object.__new__(StandaloneLauncher) + launcher.argvals = { + "case_file_name": "a.cas.h5", + "case_data_file_name": None, + "mode": FluentMode.SOLVER, + "lightweight_mode": True, + "journal_file_names": ["a.jou", "b.jou"], + } + launcher._defer_journal_file_read = True + + calls = [] + + class _DummySession: + def read_case_lightweight(self, file_name, start_sync=True): + calls.append(("read_case_lightweight", file_name, start_sync)) + + def execute_tui(self, command): + calls.append(("execute_tui", command)) + + def start_case_lightweight_sync(self): + calls.append(("start_case_lightweight_sync",)) + + launcher._process_case_data_and_journals(_DummySession()) + + assert calls == [ + ("read_case_lightweight", "a.cas.h5", False), + ("execute_tui", '/file/read-journal "a.jou"'), + ("execute_tui", '/file/read-journal "b.jou"'), + ("start_case_lightweight_sync",), + ] + + def test_show_gui_raises_warning(): with pytest.warns(PyFluentDeprecationWarning): grpc_kwds = get_grpc_launcher_args_for_gh_runs()