Skip to content

Commit

Permalink
Factory pattern in launch_fluent (#2252)
Browse files Browse the repository at this point in the history
* Factory pattern in launch_fluent

* use match case anf update containet test

* update test

* remove match

* datamodelgen fix

* remove line 986 and 987

* Create separate launcher objects

* Add docstrings

* Update return type

* launch to __call__

* redesign

* make get_fluent_launcher_mode private

* Revert "make get_fluent_launcher_mode private"

This reverts commit 7c46a31.

* Revert "redesign"

This reverts commit d942189.

* Revert "launch to __call__"

This reverts commit ef8b7d7.

* standalone redesign and tests

* dry_run

* launch_fluent update

* _process_invalid_args update

* pim launcher redesign

* add docstrings

* add docstrings 1

* pim and container tests

* update call method

* separate launchers

* manage imports

* resolve import issues

* launcher_utils

* remove watchdog

* import update

* test fixes

* logger update

* fix connect_to_fluent bug

* update call() remove fluent_launch_mode from launchers

* update call() pim

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update src/ansys/fluent/core/launcher/launcher.py

Co-authored-by: Sean Pearson <93727996+seanpearsonuk@users.noreply.github.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* disable hanging test

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Sean Pearson <93727996+seanpearsonuk@users.noreply.github.com>
  • Loading branch information
3 people committed Nov 29, 2023
1 parent 53aa027 commit 7922254
Show file tree
Hide file tree
Showing 17 changed files with 1,475 additions and 778 deletions.
2 changes: 1 addition & 1 deletion codegen/allapigen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import settingsgen
import tuigen

from ansys.fluent.core.launcher.launcher import FluentVersion, get_ansys_version
from ansys.fluent.core.launcher.launcher_utils import FluentVersion, get_ansys_version
from ansys.fluent.core.utils.fluent_version import get_version_for_file_name
from ansys.fluent.core.utils.search import get_api_tree_file_name

Expand Down
2 changes: 1 addition & 1 deletion codegen/tuigen.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from data.tui_menu_descriptions import MENU_DESCRIPTIONS

import ansys.fluent.core as pyfluent
from ansys.fluent.core.launcher.launcher import get_ansys_version
from ansys.fluent.core.launcher.launcher_utils import get_ansys_version
from ansys.fluent.core.services.datamodel_tui import (
PyMenu,
convert_path_to_grpc_path,
Expand Down
6 changes: 4 additions & 2 deletions src/ansys/fluent/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@

from ansys.fluent.core._version import __version__ # noqa: F401
from ansys.fluent.core.launcher.launcher import ( # noqa: F401
FluentMode,
FluentVersion,
connect_to_fluent,
launch_fluent,
)
from ansys.fluent.core.launcher.launcher_utils import ( # noqa: F401
FluentMode,
FluentVersion,
)
from ansys.fluent.core.services.batch_ops import BatchOps # noqa: F401
from ansys.fluent.core.session import BaseSession as Fluent # noqa: F401
from ansys.fluent.core.utils import fldoc
Expand Down
219 changes: 219 additions & 0 deletions src/ansys/fluent/core/launcher/container_launcher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
"""Provides a module for launching Fluent in container mode."""

import logging
import os
from typing import Any, Dict, Optional, Union

from ansys.fluent.core.fluent_connection import FluentConnection
from ansys.fluent.core.launcher.fluent_container import (
configure_container_dict,
start_fluent_container,
)
from ansys.fluent.core.launcher.launcher_utils import (
FluentMode,
_build_fluent_launch_args_string,
_get_argvals,
_process_invalid_args,
_process_kwargs,
)
import ansys.fluent.core.launcher.watchdog as watchdog
from ansys.fluent.core.utils.file_transfer_service import RemoteFileHandler

_THIS_DIR = os.path.dirname(__file__)
_OPTIONS_FILE = os.path.join(_THIS_DIR, "fluent_launcher_options.json")
logger = logging.getLogger("pyfluent.launcher")


class DockerLauncher:
"""Instantiates Fluent session in container mode."""

def __init__(
self,
argvals: Optional[Any] = None,
product_version: Optional[str] = None,
version: Optional[str] = None,
precision: Optional[str] = None,
processor_count: Optional[int] = None,
journal_file_names: Union[None, str, list[str]] = None,
start_timeout: int = 60,
additional_arguments: Optional[str] = "",
env: Optional[Dict[str, Any]] = None,
start_container: Optional[bool] = None,
container_dict: Optional[dict] = None,
dry_run: bool = False,
cleanup_on_exit: bool = True,
start_transcript: bool = True,
show_gui: Optional[bool] = None,
case_file_name: Optional[str] = None,
case_data_file_name: Optional[str] = None,
lightweight_mode: Optional[bool] = None,
mode: Optional[Union[FluentMode, str, None]] = None,
py: Optional[bool] = None,
gpu: Optional[bool] = None,
cwd: Optional[str] = None,
topy: Optional[Union[str, list]] = None,
start_watchdog: Optional[bool] = None,
**kwargs,
):
"""Launch Fluent session in container mode.
Parameters
----------
product_version : str, optional
Select an installed version of ANSYS. The string must be in a format like
``"23.2.0"`` (for 2023 R2) matching the documented version format in the
FluentVersion class. The default is ``None``, in which case the newest installed
version is used.
version : str, optional
Geometric dimensionality of the Fluent simulation. The default is ``None``,
in which case ``"3d"`` is used. Options are ``"3d"`` and ``"2d"``.
precision : str, optional
Floating point precision. The default is ``None``, in which case ``"double"``
is used. Options are ``"double"`` and ``"single"``.
processor_count : int, optional
Number of processors. The default is ``None``, in which case ``1``
processor is used. In job scheduler environments the total number of
allocated cores is clamped to value of ``processor_count``.
journal_file_names : str or list of str, optional
The string path to a Fluent journal file, or a list of such paths. Fluent will execute the
journal(s). The default is ``None``.
start_timeout : int, optional
Maximum allowable time in seconds for connecting to the Fluent
server. The default is ``60``.
additional_arguments : str, optional
Additional arguments to send to Fluent as a string in the same
format they are normally passed to Fluent on the command line.
env : dict[str, str], optional
Mapping to modify environment variables in Fluent. The default
is ``None``.
start_container : bool, optional
Specifies whether to launch a Fluent Docker container image. For more details about containers, see
:mod:`~ansys.fluent.core.launcher.fluent_container`.
container_dict : dict, optional
Dictionary for Fluent Docker container configuration. If specified,
setting ``start_container = True`` as well is redundant.
Will launch Fluent inside a Docker container using the configuration changes specified.
See also :mod:`~ansys.fluent.core.launcher.fluent_container`.
dry_run : bool, optional
Defaults to False. If True, will not launch Fluent, and will instead print configuration information
that would be used as if Fluent was being launched. If dry running a container start,
``launch_fluent()`` will return the configured ``container_dict``.
cleanup_on_exit : bool, optional
Whether to shut down the connected Fluent session when PyFluent is
exited, or the ``exit()`` method is called on the session instance,
or if the session instance becomes unreferenced. The default is ``True``.
start_transcript : bool, optional
Whether to start streaming the Fluent transcript in the client. The
default is ``True``. You can stop and start the streaming of the
Fluent transcript subsequently via the method calls, ``transcript.start()``
and ``transcript.stop()`` on the session object.
show_gui : bool, optional
Whether to display the Fluent GUI. The default is ``None``, which does not
cause the GUI to be shown. If a value of ``False`` is
not explicitly provided, the GUI will also be shown if
the environment variable ``PYFLUENT_SHOW_SERVER_GUI`` is set to 1.
case_file_name : str, optional
If provided, the case file at ``case_file_name`` is read into the Fluent session.
case_data_file_name : str, optional
If provided, the case and data files at ``case_data_file_name`` are read into the Fluent session.
lightweight_mode : bool, optional
Whether to run in lightweight mode. In lightweight mode, the lightweight settings are read into the
current Fluent solver session. The mesh is read into a background Fluent solver session which will
replace the current Fluent solver session once the mesh read is complete and the lightweight settings
made by the user in the current Fluent solver session have been applied in the background Fluent
solver session. This is all orchestrated by PyFluent and requires no special usage.
This parameter is used only when ``case_file_name`` is provided. The default is ``False``.
mode : str, optional
Launch mode of Fluent to point to a specific session type.
The default value is ``None``. Options are ``"meshing"``,
``"pure-meshing"`` and ``"solver"``.
py : bool, optional
If True, Fluent will run in Python mode. Default is None.
gpu : bool, optional
If True, Fluent will start with GPU Solver.
cwd : str, Optional
Working directory for the Fluent client.
topy : bool or str, optional
A boolean flag to write the equivalent Python journal(s) from the journal(s) passed.
Can optionally take the file name of the new python journal file.
start_watchdog : bool, optional
When ``cleanup_on_exit`` is True, ``start_watchdog`` defaults to True,
which means an independent watchdog process is run to ensure
that any local GUI-less Fluent sessions started by PyFluent are properly closed (or killed if frozen)
when the current Python process ends.
Returns
-------
:obj:`~typing.Union` [:class:`Meshing<ansys.fluent.core.session_meshing.Meshing>`, \
:class:`~ansys.fluent.core.session_pure_meshing.PureMeshing`, \
:class:`~ansys.fluent.core.session_solver.Solver`, \
:class:`~ansys.fluent.core.session_solver_icing.SolverIcing`, dict]
Session object or configuration dictionary if ``dry_run = True``.
Raises
------
UnexpectedKeywordArgument
If an unexpected keyword argument is provided.
DockerContainerLaunchNotSupported
If a Fluent Docker container launch is not supported.
Notes
-----
Job scheduler environments such as SLURM, LSF, PBS, etc. allocates resources / compute nodes.
The allocated machines and core counts are queried from the scheduler environment and
passed to Fluent.
"""
_process_kwargs(kwargs)
del kwargs
del start_container
argvals = locals().copy()
_process_invalid_args(dry_run, "container", argvals)
args = _get_argvals(argvals, mode)
argvals.update(args)
for arg_name, arg_values in argvals.items():
setattr(self, arg_name, arg_values)
self.argvals = argvals

def __call__(self):
args = _build_fluent_launch_args_string(**self.argvals).split()
if self.meshing_mode:
args.append(" -meshing")

if self.dry_run:
if self.container_dict is None:
setattr(self, "container_dict", {})
config_dict, *_ = configure_container_dict(args, **self.container_dict)
from pprint import pprint

print("\nDocker container run configuration:\n")
print("config_dict = ")
if os.getenv("PYFLUENT_HIDE_LOG_SECRETS") != "1":
pprint(config_dict)
else:
config_dict_h = config_dict.copy()
config_dict_h.pop("environment")
pprint(config_dict_h)
del config_dict_h
return config_dict

port, password = start_fluent_container(args, self.container_dict)

session = self.new_session(
fluent_connection=FluentConnection(
port=port,
password=password,
cleanup_on_exit=self.cleanup_on_exit,
start_transcript=self.start_transcript,
launcher_args=self.argvals,
inside_container=True,
),
remote_file_handler=RemoteFileHandler(),
)

if self.start_watchdog is None and self.cleanup_on_exit:
setattr(self, "start_watchdog", True)
if self.start_watchdog:
logger.debug("Launching Watchdog for Fluent container...")
watchdog.launch(os.getpid(), port, password)

return session

0 comments on commit 7922254

Please sign in to comment.