ansys-fluent-core 0.34.dev0__py3-none-any.whl → 0.35.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansys-fluent-core might be problematic. Click here for more details.
- ansys/fluent/core/__init__.py +48 -84
- ansys/fluent/core/codegen/allapigen.py +2 -2
- ansys/fluent/core/codegen/builtin_settingsgen.py +41 -13
- ansys/fluent/core/codegen/datamodelgen.py +3 -1
- ansys/fluent/core/codegen/print_fluent_version.py +2 -2
- ansys/fluent/core/codegen/settingsgen.py +18 -6
- ansys/fluent/core/codegen/tuigen.py +6 -5
- ansys/fluent/core/data_model_cache.py +2 -2
- ansys/fluent/core/docker/docker_compose.py +11 -9
- ansys/fluent/core/docker/utils.py +35 -0
- ansys/fluent/core/examples/downloads.py +8 -11
- ansys/fluent/core/exceptions.py +13 -1
- ansys/fluent/core/field_data_interfaces.py +239 -38
- ansys/fluent/core/file_session.py +167 -61
- ansys/fluent/core/fluent_connection.py +41 -26
- ansys/fluent/core/generated/api_tree/api_objects.json +1 -1
- ansys/fluent/core/generated/datamodel_231/flicing.py +40 -40
- ansys/fluent/core/generated/datamodel_231/meshing.py +231 -231
- ansys/fluent/core/generated/datamodel_232/flicing.py +50 -50
- ansys/fluent/core/generated/datamodel_232/meshing.py +189 -189
- ansys/fluent/core/generated/datamodel_241/flicing.py +30 -30
- ansys/fluent/core/generated/datamodel_241/meshing.py +290 -290
- ansys/fluent/core/generated/datamodel_242/flicing.py +50 -50
- ansys/fluent/core/generated/datamodel_242/meshing.py +331 -331
- ansys/fluent/core/generated/datamodel_242/part_management.py +6 -6
- ansys/fluent/core/generated/datamodel_251/flicing.py +65 -65
- ansys/fluent/core/generated/datamodel_251/meshing.py +300 -300
- ansys/fluent/core/generated/datamodel_251/part_management.py +6 -6
- ansys/fluent/core/generated/datamodel_252/flicing.py +25 -25
- ansys/fluent/core/generated/datamodel_252/meshing.py +382 -382
- ansys/fluent/core/generated/datamodel_252/part_management.py +10 -10
- ansys/fluent/core/generated/datamodel_261/flicing.py +45 -45
- ansys/fluent/core/generated/datamodel_261/meshing.py +454 -435
- ansys/fluent/core/generated/datamodel_261/part_management.py +5 -5
- ansys/fluent/core/generated/datamodel_261/preferences.py +7 -0
- ansys/fluent/core/generated/fluent_version_252.py +1 -1
- ansys/fluent/core/generated/fluent_version_261.py +3 -3
- ansys/fluent/core/generated/meshing/tui_261.py +54 -3
- ansys/fluent/core/generated/solver/settings_231.py +1 -0
- ansys/fluent/core/generated/solver/settings_231.pyi +3025 -1
- ansys/fluent/core/generated/solver/settings_232.py +1 -0
- ansys/fluent/core/generated/solver/settings_232.pyi +3425 -1
- ansys/fluent/core/generated/solver/settings_241.py +1 -0
- ansys/fluent/core/generated/solver/settings_241.pyi +4423 -1
- ansys/fluent/core/generated/solver/settings_242.py +1 -0
- ansys/fluent/core/generated/solver/settings_242.pyi +5474 -1
- ansys/fluent/core/generated/solver/settings_251.py +11 -0
- ansys/fluent/core/generated/solver/settings_251.pyi +6006 -1
- ansys/fluent/core/generated/solver/settings_252.py +11 -1
- ansys/fluent/core/generated/solver/settings_252.pyi +6782 -2
- ansys/fluent/core/generated/solver/settings_261.py +5592 -2740
- ansys/fluent/core/generated/solver/settings_261.pyi +10335 -1994
- ansys/fluent/core/generated/solver/settings_builtin.py +560 -38
- ansys/fluent/core/generated/solver/settings_builtin.pyi +24 -18
- ansys/fluent/core/generated/solver/tui_261.py +409 -285
- ansys/fluent/core/launcher/container_launcher.py +25 -6
- ansys/fluent/core/launcher/error_handler.py +1 -1
- ansys/fluent/core/launcher/fluent_container.py +97 -45
- ansys/fluent/core/launcher/launch_options.py +5 -4
- ansys/fluent/core/launcher/launcher.py +18 -2
- ansys/fluent/core/launcher/launcher_utils.py +63 -15
- ansys/fluent/core/launcher/pim_launcher.py +17 -3
- ansys/fluent/core/launcher/process_launch_string.py +3 -2
- ansys/fluent/core/launcher/server_info.py +7 -3
- ansys/fluent/core/launcher/slurm_launcher.py +4 -2
- ansys/fluent/core/launcher/standalone_launcher.py +6 -3
- ansys/fluent/core/launcher/watchdog.py +6 -6
- ansys/fluent/core/launcher/watchdog_exec +1 -1
- ansys/fluent/core/logger.py +3 -1
- ansys/fluent/core/module_config.py +358 -0
- ansys/fluent/core/pyfluent_warnings.py +9 -3
- ansys/fluent/core/report.py +2 -2
- ansys/fluent/core/search.py +34 -13
- ansys/fluent/core/services/__init__.py +2 -2
- ansys/fluent/core/services/api_upgrade.py +3 -2
- ansys/fluent/core/services/app_utilities.py +39 -0
- ansys/fluent/core/services/datamodel_se.py +4 -2
- ansys/fluent/core/services/deprecated_field_data.py +4 -4
- ansys/fluent/core/services/field_data.py +185 -49
- ansys/fluent/core/services/health_check.py +3 -1
- ansys/fluent/core/services/interceptors.py +8 -6
- ansys/fluent/core/services/reduction.py +16 -5
- ansys/fluent/core/services/settings.py +1 -0
- ansys/fluent/core/session.py +47 -4
- ansys/fluent/core/session_pure_meshing.py +6 -6
- ansys/fluent/core/session_pure_meshing.pyi +1 -0
- ansys/fluent/core/session_shared.py +4 -4
- ansys/fluent/core/session_solver.py +41 -10
- ansys/fluent/core/session_solver.pyi +1 -0
- ansys/fluent/core/session_utilities.py +7 -0
- ansys/fluent/core/solver/error_message.py +2 -2
- ansys/fluent/core/solver/flobject.py +192 -123
- ansys/fluent/core/solver/function/reduction.py +37 -9
- ansys/fluent/core/solver/settings_builtin_bases.py +3 -3
- ansys/fluent/core/solver/settings_builtin_data.py +7 -17
- ansys/fluent/core/streaming_services/datamodel_event_streaming.py +3 -2
- ansys/fluent/core/streaming_services/datamodel_streaming.py +3 -1
- ansys/fluent/core/streaming_services/events_streaming.py +2 -18
- ansys/fluent/core/system_coupling.py +3 -1
- ansys/fluent/core/utils/__init__.py +0 -7
- ansys/fluent/core/utils/data_transfer.py +3 -3
- ansys/fluent/core/utils/file_transfer_service.py +24 -15
- ansys/fluent/core/utils/fluent_version.py +4 -6
- ansys/fluent/core/utils/networking.py +21 -11
- {ansys_fluent_core-0.34.dev0.dist-info → ansys_fluent_core-0.35.dev0.dist-info}/METADATA +10 -11
- {ansys_fluent_core-0.34.dev0.dist-info → ansys_fluent_core-0.35.dev0.dist-info}/RECORD +108 -106
- {ansys_fluent_core-0.34.dev0.dist-info → ansys_fluent_core-0.35.dev0.dist-info}/WHEEL +1 -1
- {ansys_fluent_core-0.34.dev0.dist-info/licenses → ansys_fluent_core-0.35.dev0.dist-info}/LICENSE +0 -0
|
@@ -56,7 +56,7 @@ from ansys.fluent.core.launcher.launch_options import (
|
|
|
56
56
|
UIMode,
|
|
57
57
|
_get_argvals_and_session,
|
|
58
58
|
)
|
|
59
|
-
from ansys.fluent.core.launcher.launcher_utils import
|
|
59
|
+
from ansys.fluent.core.launcher.launcher_utils import ComposeConfig
|
|
60
60
|
from ansys.fluent.core.launcher.process_launch_string import (
|
|
61
61
|
_build_fluent_launch_args_string,
|
|
62
62
|
)
|
|
@@ -108,6 +108,8 @@ class DockerLauncher:
|
|
|
108
108
|
gpu: bool | None = None,
|
|
109
109
|
start_watchdog: bool | None = None,
|
|
110
110
|
file_transfer_service: Any | None = None,
|
|
111
|
+
use_docker_compose: bool | None = None,
|
|
112
|
+
use_podman_compose: bool | None = None,
|
|
111
113
|
):
|
|
112
114
|
"""
|
|
113
115
|
Launch a Fluent session in container mode.
|
|
@@ -161,6 +163,10 @@ class DockerLauncher:
|
|
|
161
163
|
GUI-less Fluent sessions started by PyFluent are properly closed when the current Python process ends.
|
|
162
164
|
file_transfer_service : Any, optional
|
|
163
165
|
Service for uploading/downloading files to/from the server.
|
|
166
|
+
use_docker_compose: bool
|
|
167
|
+
Whether to use Docker Compose to launch Fluent.
|
|
168
|
+
use_podman_compose: bool
|
|
169
|
+
Whether to use Podman Compose to launch Fluent.
|
|
164
170
|
|
|
165
171
|
Returns
|
|
166
172
|
-------
|
|
@@ -198,12 +204,15 @@ class DockerLauncher:
|
|
|
198
204
|
self._args = _build_fluent_launch_args_string(**self.argvals).split()
|
|
199
205
|
if FluentMode.is_meshing(self.argvals["mode"]):
|
|
200
206
|
self._args.append(" -meshing")
|
|
207
|
+
self._compose_config = ComposeConfig(use_docker_compose, use_podman_compose)
|
|
201
208
|
|
|
202
209
|
def __call__(self):
|
|
203
210
|
|
|
204
211
|
if self.argvals["dry_run"]:
|
|
205
212
|
config_dict, *_ = configure_container_dict(
|
|
206
|
-
self._args,
|
|
213
|
+
self._args,
|
|
214
|
+
compose_config=self._compose_config,
|
|
215
|
+
**self.argvals["container_dict"],
|
|
207
216
|
)
|
|
208
217
|
dict_str = dict_to_str(config_dict)
|
|
209
218
|
print("\nDocker container run configuration:\n")
|
|
@@ -214,15 +223,21 @@ class DockerLauncher:
|
|
|
214
223
|
logger.debug(f"Fluent container launcher args: {self._args}")
|
|
215
224
|
logger.debug(f"Fluent container launcher argvals:\n{dict_to_str(self.argvals)}")
|
|
216
225
|
|
|
217
|
-
if is_compose
|
|
226
|
+
if self._compose_config.is_compose:
|
|
218
227
|
port, config_dict, container = start_fluent_container(
|
|
219
|
-
self._args,
|
|
228
|
+
self._args,
|
|
229
|
+
self.argvals["container_dict"],
|
|
230
|
+
self.argvals["start_timeout"],
|
|
231
|
+
compose_config=self._compose_config,
|
|
220
232
|
)
|
|
221
233
|
|
|
222
234
|
_, _, password = _get_server_info_from_container(config_dict=config_dict)
|
|
223
235
|
else:
|
|
224
236
|
port, password, container = start_fluent_container(
|
|
225
|
-
self._args,
|
|
237
|
+
self._args,
|
|
238
|
+
self.argvals["container_dict"],
|
|
239
|
+
self.argvals["start_timeout"],
|
|
240
|
+
compose_config=self._compose_config,
|
|
226
241
|
)
|
|
227
242
|
|
|
228
243
|
fluent_connection = FluentConnection(
|
|
@@ -233,18 +248,22 @@ class DockerLauncher:
|
|
|
233
248
|
slurm_job_id=self.argvals and self.argvals.get("slurm_job_id"),
|
|
234
249
|
inside_container=True,
|
|
235
250
|
container=container,
|
|
251
|
+
compose_config=self._compose_config,
|
|
236
252
|
)
|
|
237
253
|
|
|
254
|
+
self.argvals["compose_config"] = self._compose_config
|
|
255
|
+
|
|
238
256
|
session = self.new_session(
|
|
239
257
|
fluent_connection=fluent_connection,
|
|
240
258
|
scheme_eval=fluent_connection._connection_interface.scheme_eval,
|
|
241
259
|
file_transfer_service=self.file_transfer_service,
|
|
242
260
|
start_transcript=self.argvals["start_transcript"],
|
|
261
|
+
launcher_args=self.argvals,
|
|
243
262
|
)
|
|
244
263
|
|
|
245
264
|
session._container = container
|
|
246
265
|
|
|
247
|
-
if not is_compose
|
|
266
|
+
if not self._compose_config.is_compose:
|
|
248
267
|
if (
|
|
249
268
|
self.argvals["start_watchdog"] is None
|
|
250
269
|
and self.argvals["cleanup_on_exit"]
|
|
@@ -70,7 +70,7 @@ class LaunchFluentError(Exception):
|
|
|
70
70
|
|
|
71
71
|
def __init__(self, launch_string):
|
|
72
72
|
"""__init__ method of LaunchFluentError class."""
|
|
73
|
-
details = "\n" + "Fluent Launch
|
|
73
|
+
details = "\n" + "Fluent Launch command: " + launch_string
|
|
74
74
|
super().__init__(details)
|
|
75
75
|
|
|
76
76
|
|
|
@@ -62,7 +62,7 @@ config_dict =
|
|
|
62
62
|
'detach': True,
|
|
63
63
|
'environment': {'ANSYSLMD_LICENSE_FILE': '2048@licenseserver.com',
|
|
64
64
|
'REMOTING_PORTS': '54000/portspan=2'},
|
|
65
|
-
'fluent_image': '
|
|
65
|
+
'fluent_image': '<image registry>:v23.2.0',
|
|
66
66
|
'labels': {'test_name': 'none'},
|
|
67
67
|
'ports': {'54000': 54000},
|
|
68
68
|
'volumes': ['/home/user/.local/share/ansys_fluent_core/examples:/mnt/pyfluent'],
|
|
@@ -77,10 +77,16 @@ from pathlib import Path, PurePosixPath
|
|
|
77
77
|
from pprint import pformat
|
|
78
78
|
import tempfile
|
|
79
79
|
from typing import Any, List
|
|
80
|
+
import warnings
|
|
80
81
|
|
|
81
82
|
import ansys.fluent.core as pyfluent
|
|
82
83
|
from ansys.fluent.core.docker.docker_compose import ComposeBasedLauncher
|
|
83
|
-
from ansys.fluent.core.
|
|
84
|
+
from ansys.fluent.core.docker.utils import get_ghcr_fluent_image_name
|
|
85
|
+
from ansys.fluent.core.launcher.error_handler import (
|
|
86
|
+
LaunchFluentError,
|
|
87
|
+
)
|
|
88
|
+
from ansys.fluent.core.launcher.launcher_utils import ComposeConfig
|
|
89
|
+
from ansys.fluent.core.pyfluent_warnings import PyFluentDeprecationWarning
|
|
84
90
|
from ansys.fluent.core.session import _parse_server_info_file
|
|
85
91
|
from ansys.fluent.core.utils.deprecate import all_deprecators
|
|
86
92
|
from ansys.fluent.core.utils.execution import timeout_loop
|
|
@@ -125,7 +131,7 @@ def dict_to_str(dict: dict) -> str:
|
|
|
125
131
|
This is useful for logging purposes, to avoid printing sensitive information such as license server details.
|
|
126
132
|
"""
|
|
127
133
|
|
|
128
|
-
if "environment" in dict and
|
|
134
|
+
if "environment" in dict and pyfluent.config.hide_log_secrets:
|
|
129
135
|
modified_dict = dict.copy()
|
|
130
136
|
modified_dict.pop("environment")
|
|
131
137
|
return pformat(modified_dict)
|
|
@@ -155,7 +161,7 @@ def configure_container_dict(
|
|
|
155
161
|
args: List[str],
|
|
156
162
|
mount_source: str | Path | None = None,
|
|
157
163
|
mount_target: str | Path | None = None,
|
|
158
|
-
timeout: int =
|
|
164
|
+
timeout: int | None = None,
|
|
159
165
|
port: int | None = None,
|
|
160
166
|
license_server: str | None = None,
|
|
161
167
|
container_server_info_file: str | Path | None = None,
|
|
@@ -164,6 +170,7 @@ def configure_container_dict(
|
|
|
164
170
|
image_name: str | None = None,
|
|
165
171
|
image_tag: str | None = None,
|
|
166
172
|
file_transfer_service: Any | None = None,
|
|
173
|
+
compose_config: ComposeConfig | None = None,
|
|
167
174
|
**container_dict,
|
|
168
175
|
) -> (dict, int, int, Path, bool):
|
|
169
176
|
"""Parses the parameters listed below, and sets up the container configuration file.
|
|
@@ -180,7 +187,7 @@ def configure_container_dict(
|
|
|
180
187
|
Path inside the container where ``mount_source`` will be mounted. This will be the working directory path
|
|
181
188
|
visible to the Fluent process running inside the container.
|
|
182
189
|
timeout : int, optional
|
|
183
|
-
Time limit
|
|
190
|
+
Time limit for the Fluent container to start, in seconds.
|
|
184
191
|
port : int, optional
|
|
185
192
|
Port for Fluent container to use.
|
|
186
193
|
license_server : str, optional
|
|
@@ -198,6 +205,8 @@ def configure_container_dict(
|
|
|
198
205
|
Ignored if ``fluent_image`` has been specified.
|
|
199
206
|
file_transfer_service : optional
|
|
200
207
|
Supports file upload and download.
|
|
208
|
+
compose_config : ComposeConfig, optional
|
|
209
|
+
Configuration for Docker Compose, if using Docker Compose to launch the container.
|
|
201
210
|
**container_dict
|
|
202
211
|
Additional keyword arguments can be specified, they will be treated as Docker container run options
|
|
203
212
|
to be passed directly to the Docker run execution. See examples below and `Docker run`_ documentation.
|
|
@@ -231,24 +240,28 @@ def configure_container_dict(
|
|
|
231
240
|
See also :func:`start_fluent_container`.
|
|
232
241
|
"""
|
|
233
242
|
|
|
243
|
+
compose_config = compose_config if compose_config else ComposeConfig()
|
|
244
|
+
|
|
245
|
+
if timeout is not None:
|
|
246
|
+
warnings.warn(
|
|
247
|
+
"configure_container_dict(timeout) is deprecated, use launch_fluent(start_timeout) instead.",
|
|
248
|
+
PyFluentDeprecationWarning,
|
|
249
|
+
)
|
|
250
|
+
|
|
234
251
|
logger.debug(f"container_dict before processing:\n{dict_to_str(container_dict)}")
|
|
235
252
|
|
|
236
253
|
# Starting with 'mount_source' because it is not tied to the 'working_dir'.
|
|
237
254
|
# The intended 'mount_source' logic is as follows, if it is not directly specified:
|
|
238
255
|
# 1. If 'file_transfer_service' is provided, use its 'mount_source'.
|
|
239
|
-
# 2.
|
|
240
|
-
# 3.
|
|
241
|
-
# 4.
|
|
242
|
-
# 5. Finally, use the current working directory, which is always available.
|
|
256
|
+
# 2. Use the value from 'pyfluent.config.container_mount_source', if it is set.
|
|
257
|
+
# 3. If 'volumes' is specified in 'container_dict', try to infer the value from it.
|
|
258
|
+
# 4. Finally, use the current working directory, which is always available.
|
|
243
259
|
|
|
244
260
|
if not mount_source:
|
|
245
261
|
if file_transfer_service:
|
|
246
262
|
mount_source = file_transfer_service.mount_source
|
|
247
263
|
else:
|
|
248
|
-
mount_source =
|
|
249
|
-
"PYFLUENT_CONTAINER_MOUNT_SOURCE",
|
|
250
|
-
pyfluent.CONTAINER_MOUNT_SOURCE,
|
|
251
|
-
)
|
|
264
|
+
mount_source = pyfluent.config.container_mount_source
|
|
252
265
|
|
|
253
266
|
if "volumes" in container_dict:
|
|
254
267
|
if len(container_dict["volumes"]) != 1:
|
|
@@ -274,15 +287,14 @@ def configure_container_dict(
|
|
|
274
287
|
|
|
275
288
|
# The intended 'mount_target' logic is as follows, if it is not directly specified:
|
|
276
289
|
# 1. If 'working_dir' is specified in 'container_dict', use it as 'mount_target'.
|
|
277
|
-
# 2.
|
|
278
|
-
# 3.
|
|
279
|
-
# 4. Finally, use the value from 'pyfluent.CONTAINER_MOUNT_TARGET', which is always set.
|
|
290
|
+
# 2. Try to infer the value from the 'volumes' keyword in 'container_dict', if available.
|
|
291
|
+
# 3. Finally, use the value from 'pyfluent.config.container_mount_target', which is always set.
|
|
280
292
|
|
|
281
293
|
if not mount_target:
|
|
282
294
|
if "working_dir" in container_dict:
|
|
283
295
|
mount_target = container_dict["working_dir"]
|
|
284
296
|
else:
|
|
285
|
-
mount_target =
|
|
297
|
+
mount_target = pyfluent.config.container_mount_target
|
|
286
298
|
|
|
287
299
|
if "working_dir" in container_dict and mount_target:
|
|
288
300
|
# working_dir will be set later to the final value of mount_target
|
|
@@ -293,7 +305,7 @@ def configure_container_dict(
|
|
|
293
305
|
|
|
294
306
|
if not mount_target:
|
|
295
307
|
logger.debug("No container 'mount_target' specified, using default value.")
|
|
296
|
-
mount_target = pyfluent.
|
|
308
|
+
mount_target = pyfluent.config.container_mount_target
|
|
297
309
|
|
|
298
310
|
if "volumes" not in container_dict:
|
|
299
311
|
container_dict.update(volumes=[f"{mount_source}:{mount_target}"])
|
|
@@ -314,8 +326,8 @@ def configure_container_dict(
|
|
|
314
326
|
if not port_mapping and "ports" in container_dict:
|
|
315
327
|
# take the specified 'port', OR the first port value from the specified 'ports', for Fluent to use
|
|
316
328
|
port_mapping = container_dict["ports"]
|
|
317
|
-
if not port_mapping and pyfluent.
|
|
318
|
-
port = pyfluent.
|
|
329
|
+
if not port_mapping and pyfluent.config.launch_fluent_port:
|
|
330
|
+
port = pyfluent.config.launch_fluent_port
|
|
319
331
|
port_mapping = {port: port}
|
|
320
332
|
if not port_mapping:
|
|
321
333
|
port = get_free_port()
|
|
@@ -338,11 +350,12 @@ def configure_container_dict(
|
|
|
338
350
|
environment={
|
|
339
351
|
"ANSYSLMD_LICENSE_FILE": license_server,
|
|
340
352
|
"REMOTING_PORTS": f"{container_grpc_port}/portspan=2",
|
|
353
|
+
"FLUENT_ALLOW_REMOTE_GRPC_CONNECTION": "1",
|
|
341
354
|
}
|
|
342
355
|
)
|
|
343
356
|
|
|
344
357
|
if "labels" not in container_dict:
|
|
345
|
-
test_name =
|
|
358
|
+
test_name = pyfluent.config.test_name
|
|
346
359
|
container_dict.update(
|
|
347
360
|
labels={"test_name": test_name},
|
|
348
361
|
)
|
|
@@ -387,13 +400,14 @@ def configure_container_dict(
|
|
|
387
400
|
|
|
388
401
|
if not fluent_image:
|
|
389
402
|
if not image_tag:
|
|
390
|
-
image_tag =
|
|
391
|
-
|
|
403
|
+
image_tag = pyfluent.config.fluent_image_tag
|
|
404
|
+
if not image_name and image_tag:
|
|
405
|
+
image_name = (
|
|
406
|
+
pyfluent.config.fluent_image_name
|
|
407
|
+
or get_ghcr_fluent_image_name(image_tag)
|
|
392
408
|
)
|
|
393
|
-
if not image_name:
|
|
394
|
-
image_name = os.getenv("FLUENT_IMAGE_NAME", "ghcr.io/ansys/pyfluent")
|
|
395
409
|
if not image_tag or not image_name:
|
|
396
|
-
fluent_image =
|
|
410
|
+
fluent_image = pyfluent.config.fluent_container_name
|
|
397
411
|
elif image_tag and image_name:
|
|
398
412
|
if image_tag.startswith("sha"):
|
|
399
413
|
fluent_image = f"{image_name}@{image_tag}"
|
|
@@ -404,24 +418,19 @@ def configure_container_dict(
|
|
|
404
418
|
|
|
405
419
|
container_dict["fluent_image"] = fluent_image
|
|
406
420
|
|
|
407
|
-
if not pyfluent.
|
|
421
|
+
if not pyfluent.config.fluent_automatic_transcript:
|
|
408
422
|
if "environment" not in container_dict:
|
|
409
423
|
container_dict["environment"] = {}
|
|
410
424
|
container_dict["environment"]["FLUENT_NO_AUTOMATIC_TRANSCRIPT"] = "1"
|
|
411
425
|
|
|
412
|
-
if
|
|
413
|
-
if "environment" not in container_dict:
|
|
414
|
-
container_dict["environment"] = {}
|
|
415
|
-
container_dict["environment"]["REMOTING_NEW_DM_API"] = "1"
|
|
416
|
-
|
|
417
|
-
if pyfluent.LAUNCH_FLUENT_IP or os.getenv("REMOTING_SERVER_ADDRESS"):
|
|
426
|
+
if pyfluent.config.launch_fluent_ip or pyfluent.config.remoting_server_address:
|
|
418
427
|
if "environment" not in container_dict:
|
|
419
428
|
container_dict["environment"] = {}
|
|
420
429
|
container_dict["environment"]["REMOTING_SERVER_ADDRESS"] = (
|
|
421
|
-
pyfluent.
|
|
430
|
+
pyfluent.config.launch_fluent_ip or pyfluent.config.remoting_server_address
|
|
422
431
|
)
|
|
423
432
|
|
|
424
|
-
if pyfluent.
|
|
433
|
+
if pyfluent.config.launch_fluent_skip_password_check:
|
|
425
434
|
if "environment" not in container_dict:
|
|
426
435
|
container_dict["environment"] = {}
|
|
427
436
|
container_dict["environment"]["FLUENT_LAUNCHED_FROM_PYFLUENT"] = "1"
|
|
@@ -438,13 +447,13 @@ def configure_container_dict(
|
|
|
438
447
|
|
|
439
448
|
host_server_info_file = Path(mount_source) / container_server_info_file.name
|
|
440
449
|
|
|
441
|
-
if is_compose
|
|
450
|
+
if compose_config.is_compose:
|
|
442
451
|
container_dict["host_server_info_file"] = host_server_info_file
|
|
443
452
|
container_dict["mount_source"] = mount_source
|
|
444
453
|
container_dict["mount_target"] = mount_target
|
|
445
454
|
|
|
446
455
|
logger.debug(
|
|
447
|
-
f"Fluent container
|
|
456
|
+
f"Fluent container container_grpc_port: {container_grpc_port}, "
|
|
448
457
|
f"host_server_info_file: '{host_server_info_file}', "
|
|
449
458
|
f"remove_server_info_file: {remove_server_info_file}"
|
|
450
459
|
)
|
|
@@ -460,7 +469,10 @@ def configure_container_dict(
|
|
|
460
469
|
|
|
461
470
|
|
|
462
471
|
def start_fluent_container(
|
|
463
|
-
args: List[str],
|
|
472
|
+
args: List[str],
|
|
473
|
+
container_dict: dict | None = None,
|
|
474
|
+
start_timeout: int = 60,
|
|
475
|
+
compose_config: ComposeConfig | None = None,
|
|
464
476
|
) -> tuple[int, str, Any]:
|
|
465
477
|
"""Start a Fluent container.
|
|
466
478
|
|
|
@@ -470,6 +482,11 @@ def start_fluent_container(
|
|
|
470
482
|
List of Fluent launch arguments.
|
|
471
483
|
container_dict : dict, optional
|
|
472
484
|
Dictionary with Docker container configuration.
|
|
485
|
+
start_timeout : int, optional
|
|
486
|
+
Timeout in seconds for the container to start. If not specified, it defaults to 60
|
|
487
|
+
seconds.
|
|
488
|
+
compose_config : ComposeConfig, optional
|
|
489
|
+
Configuration for Docker Compose, if using Docker Compose to launch the container.
|
|
473
490
|
|
|
474
491
|
Returns
|
|
475
492
|
-------
|
|
@@ -491,10 +508,16 @@ def start_fluent_container(
|
|
|
491
508
|
:func:`~ansys.fluent.core.launcher.launcher.launch_fluent()`.
|
|
492
509
|
"""
|
|
493
510
|
|
|
511
|
+
compose_config = compose_config if compose_config else ComposeConfig()
|
|
512
|
+
|
|
494
513
|
if container_dict is None:
|
|
495
514
|
container_dict = {}
|
|
496
515
|
|
|
497
|
-
container_vars = configure_container_dict(
|
|
516
|
+
container_vars = configure_container_dict(
|
|
517
|
+
args,
|
|
518
|
+
compose_config=compose_config,
|
|
519
|
+
**container_dict,
|
|
520
|
+
)
|
|
498
521
|
|
|
499
522
|
(
|
|
500
523
|
config_dict,
|
|
@@ -503,12 +526,23 @@ def start_fluent_container(
|
|
|
503
526
|
host_server_info_file,
|
|
504
527
|
remove_server_info_file,
|
|
505
528
|
) = container_vars
|
|
529
|
+
launch_string = " ".join(config_dict["command"])
|
|
530
|
+
|
|
531
|
+
if timeout:
|
|
532
|
+
logger.warning(
|
|
533
|
+
"launch_fluent(start_timeout) overridden by configure_container_dict(timeout) value."
|
|
534
|
+
)
|
|
535
|
+
start_timeout = timeout
|
|
536
|
+
del timeout
|
|
506
537
|
|
|
507
538
|
try:
|
|
508
|
-
if is_compose
|
|
539
|
+
if compose_config.is_compose:
|
|
509
540
|
config_dict["fluent_port"] = port
|
|
510
541
|
|
|
511
|
-
compose_container = ComposeBasedLauncher(
|
|
542
|
+
compose_container = ComposeBasedLauncher(
|
|
543
|
+
compose_config=compose_config,
|
|
544
|
+
container_dict=config_dict,
|
|
545
|
+
)
|
|
512
546
|
|
|
513
547
|
if not compose_container.check_image_exists():
|
|
514
548
|
logger.debug(
|
|
@@ -536,18 +570,36 @@ def start_fluent_container(
|
|
|
536
570
|
config_dict.pop("fluent_image"), **config_dict
|
|
537
571
|
)
|
|
538
572
|
|
|
573
|
+
logger.debug(
|
|
574
|
+
f"Waiting for Fluent container for up to {start_timeout} seconds..."
|
|
575
|
+
)
|
|
576
|
+
|
|
539
577
|
success = timeout_loop(
|
|
540
|
-
lambda: host_server_info_file.stat().st_mtime > last_mtime,
|
|
578
|
+
lambda: host_server_info_file.stat().st_mtime > last_mtime,
|
|
579
|
+
start_timeout,
|
|
541
580
|
)
|
|
542
581
|
|
|
543
582
|
if not success:
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
583
|
+
try:
|
|
584
|
+
container.stop()
|
|
585
|
+
except Exception as stop_ex:
|
|
586
|
+
logger.error(f"Failed to stop container: {stop_ex}")
|
|
587
|
+
raise TimeoutError(
|
|
588
|
+
f"Fluent container launch has timed out after {start_timeout} seconds. "
|
|
589
|
+
f"Additionally, stopping the container failed: {stop_ex}"
|
|
590
|
+
) from stop_ex
|
|
591
|
+
else:
|
|
592
|
+
raise TimeoutError(
|
|
593
|
+
f"Fluent container launch has timed out after {start_timeout} seconds."
|
|
594
|
+
" The container was stopped."
|
|
595
|
+
)
|
|
547
596
|
else:
|
|
548
597
|
_, _, password = _parse_server_info_file(str(host_server_info_file))
|
|
549
598
|
|
|
550
599
|
return port, password, container
|
|
600
|
+
except Exception as ex:
|
|
601
|
+
logger.error(f"Exception caught - {type(ex).__name__}: {ex}")
|
|
602
|
+
raise LaunchFluentError(launch_string) from ex
|
|
551
603
|
finally:
|
|
552
604
|
if remove_server_info_file and host_server_info_file.exists():
|
|
553
605
|
host_server_info_file.unlink()
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
"""Provides a module for enums used in the PyFluent."""
|
|
24
24
|
|
|
25
25
|
from enum import Enum
|
|
26
|
-
import os
|
|
27
26
|
import warnings
|
|
28
27
|
|
|
29
28
|
from ansys.fluent.core.exceptions import DisallowedValuesError
|
|
@@ -267,11 +266,12 @@ def _get_fluent_launch_mode(start_container, container_dict, scheduler_options):
|
|
|
267
266
|
fluent_launch_mode: LaunchMode
|
|
268
267
|
Fluent launch mode.
|
|
269
268
|
"""
|
|
269
|
+
from ansys.fluent.core import config
|
|
270
|
+
|
|
270
271
|
if pypim.is_configured():
|
|
271
272
|
fluent_launch_mode = LaunchMode.PIM
|
|
272
273
|
elif start_container is True or (
|
|
273
|
-
start_container is None
|
|
274
|
-
and (container_dict or os.getenv("PYFLUENT_LAUNCH_CONTAINER") == "1")
|
|
274
|
+
start_container is None and (container_dict or config.launch_fluent_container)
|
|
275
275
|
):
|
|
276
276
|
fluent_launch_mode = LaunchMode.CONTAINER
|
|
277
277
|
# Currently, only Slurm scheduler is supported and within SlurmLauncher we check the value of the scheduler
|
|
@@ -344,6 +344,7 @@ def _get_standalone_launch_fluent_version(argvals) -> FluentVersion | None:
|
|
|
344
344
|
FluentVersion, optional
|
|
345
345
|
Fluent version or ``None``
|
|
346
346
|
"""
|
|
347
|
+
from ansys.fluent.core import config
|
|
347
348
|
|
|
348
349
|
# Look for Fluent version in the following order:
|
|
349
350
|
# 1. product_version parameter passed with launch_fluent
|
|
@@ -357,7 +358,7 @@ def _get_standalone_launch_fluent_version(argvals) -> FluentVersion | None:
|
|
|
357
358
|
|
|
358
359
|
# (DEV) if "PYFLUENT_FLUENT_ROOT" environment variable is defined, we cannot
|
|
359
360
|
# determine the Fluent version, so returning None.
|
|
360
|
-
if
|
|
361
|
+
if config.fluent_root:
|
|
361
362
|
return None
|
|
362
363
|
|
|
363
364
|
# 2. the latest ANSYS version from AWP_ROOT environment variables
|
|
@@ -103,7 +103,7 @@ def _show_gui_to_ui_mode(old_arg_val, **kwds):
|
|
|
103
103
|
return UIMode.NO_GUI
|
|
104
104
|
elif container_dict:
|
|
105
105
|
return UIMode.NO_GUI
|
|
106
|
-
elif
|
|
106
|
+
elif pyfluent.config.launch_fluent_container:
|
|
107
107
|
return UIMode.NO_GUI
|
|
108
108
|
else:
|
|
109
109
|
return UIMode.GUI
|
|
@@ -174,6 +174,8 @@ def launch_fluent(
|
|
|
174
174
|
start_watchdog: bool | None = None,
|
|
175
175
|
scheduler_options: dict | None = None,
|
|
176
176
|
file_transfer_service: Any | None = None,
|
|
177
|
+
use_docker_compose: bool | None = None,
|
|
178
|
+
use_podman_compose: bool | None = None,
|
|
177
179
|
) -> Meshing | PureMeshing | Solver | SolverIcing | SlurmFuture | dict:
|
|
178
180
|
"""Launch Fluent locally in server mode or connect to a running Fluent server
|
|
179
181
|
instance.
|
|
@@ -299,6 +301,10 @@ def launch_fluent(
|
|
|
299
301
|
specified in a similar manner to Fluent's scheduler options.
|
|
300
302
|
file_transfer_service : optional
|
|
301
303
|
File transfer service. Uploads/downloads files to/from the server.
|
|
304
|
+
use_docker_compose: bool
|
|
305
|
+
Whether to use Docker Compose to launch Fluent.
|
|
306
|
+
use_podman_compose: bool
|
|
307
|
+
Whether to use Podman Compose to launch Fluent.
|
|
302
308
|
|
|
303
309
|
Returns
|
|
304
310
|
-------
|
|
@@ -312,6 +318,8 @@ def launch_fluent(
|
|
|
312
318
|
------
|
|
313
319
|
UnexpectedKeywordArgument
|
|
314
320
|
If an unexpected keyword argument is provided.
|
|
321
|
+
ValueError
|
|
322
|
+
If both ``use_docker_compose`` and ``use_podman_compose`` are set to ``True``.
|
|
315
323
|
|
|
316
324
|
Notes
|
|
317
325
|
-----
|
|
@@ -322,6 +330,14 @@ def launch_fluent(
|
|
|
322
330
|
if env is None:
|
|
323
331
|
env = {}
|
|
324
332
|
|
|
333
|
+
if use_docker_compose and use_podman_compose:
|
|
334
|
+
raise ValueError(
|
|
335
|
+
"Cannot use both 'use_docker_compose' and 'use_podman_compose' at the same time."
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
if start_timeout is None:
|
|
339
|
+
start_timeout = pyfluent.config.launch_fluent_timeout
|
|
340
|
+
|
|
325
341
|
def _mode_to_launcher_type(fluent_launch_mode: LaunchMode):
|
|
326
342
|
launcher_mode_type = {
|
|
327
343
|
LaunchMode.CONTAINER: DockerLauncher,
|
|
@@ -346,7 +362,7 @@ def launch_fluent(
|
|
|
346
362
|
)
|
|
347
363
|
common_args = launch_fluent_args.intersection(launcher_type_args)
|
|
348
364
|
launcher_argvals = {arg: val for arg, val in argvals.items() if arg in common_args}
|
|
349
|
-
if pyfluent.
|
|
365
|
+
if pyfluent.config.start_watchdog is False:
|
|
350
366
|
launcher_argvals["start_watchdog"] = False
|
|
351
367
|
launcher = launcher_type(**launcher_argvals)
|
|
352
368
|
return launcher()
|
|
@@ -30,19 +30,61 @@ import socket
|
|
|
30
30
|
import subprocess
|
|
31
31
|
import time
|
|
32
32
|
from typing import Any, Dict
|
|
33
|
+
import warnings
|
|
33
34
|
|
|
34
35
|
from ansys.fluent.core.exceptions import InvalidArgument
|
|
36
|
+
from ansys.fluent.core.pyfluent_warnings import PyFluentDeprecationWarning
|
|
35
37
|
from ansys.fluent.core.utils.networking import find_remoting_ip
|
|
36
38
|
|
|
37
39
|
logger = logging.getLogger("pyfluent.launcher")
|
|
38
40
|
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
class ComposeConfig:
|
|
43
|
+
"""Configuration for Docker or Podman Compose usage in PyFluent."""
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
use_docker_compose: bool | None = None,
|
|
48
|
+
use_podman_compose: bool | None = None,
|
|
49
|
+
):
|
|
50
|
+
from ansys.fluent.core import config
|
|
51
|
+
|
|
52
|
+
self._env_docker = config.use_docker_compose
|
|
53
|
+
self._env_podman = config.use_podman_compose
|
|
54
|
+
|
|
55
|
+
self._use_docker = use_docker_compose
|
|
56
|
+
self._use_podman = use_podman_compose
|
|
57
|
+
|
|
58
|
+
if use_docker_compose is None and self._env_docker:
|
|
59
|
+
self._warn_env_deprecated()
|
|
60
|
+
if use_podman_compose is None and self._env_podman:
|
|
61
|
+
self._warn_env_deprecated()
|
|
62
|
+
|
|
63
|
+
def _warn_env_deprecated(self):
|
|
64
|
+
warnings.warn(
|
|
65
|
+
(
|
|
66
|
+
"The environment variables 'PYFLUENT_USE_DOCKER_COMPOSE' and "
|
|
67
|
+
"'PYFLUENT_USE_PODMAN_COMPOSE' are deprecated. "
|
|
68
|
+
"Use the 'use_docker_compose' and 'use_podman_compose' parameters instead."
|
|
69
|
+
),
|
|
70
|
+
category=PyFluentDeprecationWarning,
|
|
71
|
+
stacklevel=3,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def use_docker_compose(self) -> bool:
|
|
76
|
+
"""Check if Docker Compose is configured to be used."""
|
|
77
|
+
return self._use_docker if self._use_docker is not None else self._env_docker
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def use_podman_compose(self) -> bool:
|
|
81
|
+
"""Check if Podman Compose is configured to be used."""
|
|
82
|
+
return self._use_podman if self._use_podman is not None else self._env_podman
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def is_compose(self) -> bool:
|
|
86
|
+
"""Check if either Docker Compose or Podman Compose is configured to be used."""
|
|
87
|
+
return self.use_docker_compose or self.use_podman_compose
|
|
46
88
|
|
|
47
89
|
|
|
48
90
|
def is_windows():
|
|
@@ -60,7 +102,8 @@ def _get_subprocess_kwargs_for_fluent(env: Dict[str, Any], argvals) -> Dict[str,
|
|
|
60
102
|
kwargs.update(stdout=subprocess.PIPE)
|
|
61
103
|
else:
|
|
62
104
|
kwargs.update(
|
|
63
|
-
stdout=pyfluent.
|
|
105
|
+
stdout=pyfluent.config.launch_fluent_stdout,
|
|
106
|
+
stderr=pyfluent.config.launch_fluent_stderr,
|
|
64
107
|
)
|
|
65
108
|
if is_windows():
|
|
66
109
|
kwargs.update(shell=True, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
|
|
@@ -70,26 +113,31 @@ def _get_subprocess_kwargs_for_fluent(env: Dict[str, Any], argvals) -> Dict[str,
|
|
|
70
113
|
fluent_env.update({k: str(v) for k, v in env.items()})
|
|
71
114
|
fluent_env["REMOTING_THROW_LAST_TUI_ERROR"] = "1"
|
|
72
115
|
fluent_env["REMOTING_THROW_LAST_SETTINGS_ERROR"] = "1"
|
|
73
|
-
if pyfluent.
|
|
116
|
+
if pyfluent.config.clear_fluent_para_envs:
|
|
74
117
|
fluent_env.pop("PARA_NPROCS", None)
|
|
75
118
|
fluent_env.pop("PARA_MESH_NPROCS", None)
|
|
76
119
|
|
|
77
|
-
if pyfluent.
|
|
78
|
-
fluent_env["REMOTING_SERVER_ADDRESS"] = pyfluent.
|
|
120
|
+
if pyfluent.config.launch_fluent_ip:
|
|
121
|
+
fluent_env["REMOTING_SERVER_ADDRESS"] = pyfluent.config.launch_fluent_ip
|
|
79
122
|
|
|
80
|
-
if pyfluent.
|
|
81
|
-
fluent_env["REMOTING_PORTS"] =
|
|
123
|
+
if pyfluent.config.launch_fluent_port:
|
|
124
|
+
fluent_env["REMOTING_PORTS"] = (
|
|
125
|
+
f"{pyfluent.config.launch_fluent_port}/portspan=2"
|
|
126
|
+
)
|
|
82
127
|
|
|
83
|
-
if pyfluent.
|
|
128
|
+
if pyfluent.config.launch_fluent_skip_password_check:
|
|
84
129
|
fluent_env["FLUENT_LAUNCHED_FROM_PYFLUENT"] = "1"
|
|
85
130
|
|
|
86
131
|
if not is_slurm:
|
|
87
|
-
if
|
|
132
|
+
if (
|
|
133
|
+
pyfluent.config.infer_remoting_ip
|
|
134
|
+
and "REMOTING_SERVER_ADDRESS" not in fluent_env
|
|
135
|
+
):
|
|
88
136
|
remoting_ip = find_remoting_ip()
|
|
89
137
|
if remoting_ip:
|
|
90
138
|
fluent_env["REMOTING_SERVER_ADDRESS"] = remoting_ip
|
|
91
139
|
|
|
92
|
-
if not pyfluent.
|
|
140
|
+
if not pyfluent.config.fluent_automatic_transcript:
|
|
93
141
|
fluent_env["FLUENT_NO_AUTOMATIC_TRANSCRIPT"] = "1"
|
|
94
142
|
|
|
95
143
|
kwargs.update(env=fluent_env)
|