ansys-fluent-core 0.31.dev1__py3-none-any.whl → 0.31.1__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 +11 -3
- ansys/fluent/core/codegen/settingsgen.py +6 -0
- ansys/fluent/core/codegen/tuigen.py +1 -2
- ansys/fluent/core/docker/docker_compose.py +243 -0
- ansys/fluent/core/field_data_interfaces.py +6 -0
- ansys/fluent/core/file_session.py +158 -128
- ansys/fluent/core/filereader/data_file.py +11 -0
- ansys/fluent/core/filereader/pre_processor.py +22 -0
- ansys/fluent/core/fluent_connection.py +48 -20
- ansys/fluent/core/generated/api_tree/api_objects.json +1 -1
- ansys/fluent/core/generated/datamodel_231/flicing.py +35 -35
- ansys/fluent/core/generated/datamodel_231/meshing.py +189 -189
- ansys/fluent/core/generated/datamodel_232/flicing.py +35 -35
- ansys/fluent/core/generated/datamodel_232/meshing.py +237 -237
- ansys/fluent/core/generated/datamodel_241/flicing.py +45 -45
- ansys/fluent/core/generated/datamodel_241/meshing.py +295 -295
- ansys/fluent/core/generated/datamodel_242/flicing.py +60 -60
- ansys/fluent/core/generated/datamodel_242/meshing.py +285 -285
- ansys/fluent/core/generated/datamodel_242/part_management.py +6 -6
- ansys/fluent/core/generated/datamodel_251/flicing.py +55 -55
- ansys/fluent/core/generated/datamodel_251/meshing.py +370 -370
- ansys/fluent/core/generated/datamodel_251/part_management.py +6 -6
- ansys/fluent/core/generated/datamodel_252/flicing.py +55 -55
- ansys/fluent/core/generated/datamodel_252/meshing.py +790 -428
- ansys/fluent/core/generated/datamodel_252/part_management.py +10 -10
- ansys/fluent/core/generated/datamodel_252/preferences.py +1 -1
- ansys/fluent/core/generated/fluent_version_252.py +4 -4
- ansys/fluent/core/generated/meshing/tui_252.py +1133 -1178
- ansys/fluent/core/generated/solver/settings_252.py +2241 -1649
- ansys/fluent/core/generated/solver/settings_252.pyi +1785 -1430
- ansys/fluent/core/generated/solver/settings_builtin.pyi +104 -0
- ansys/fluent/core/generated/solver/tui_252.py +2174 -2005
- ansys/fluent/core/launcher/container_launcher.py +39 -8
- ansys/fluent/core/launcher/fluent_container.py +61 -22
- ansys/fluent/core/launcher/launcher.py +24 -13
- ansys/fluent/core/launcher/launcher_utils.py +8 -0
- ansys/fluent/core/launcher/process_launch_string.py +2 -6
- ansys/fluent/core/launcher/slurm_launcher.py +1 -0
- ansys/fluent/core/report.py +2 -0
- ansys/fluent/core/services/deprecated_field_data.py +74 -46
- ansys/fluent/core/services/field_data.py +104 -69
- ansys/fluent/core/services/reduction.py +55 -66
- ansys/fluent/core/services/solution_variables.py +9 -1
- ansys/fluent/core/session.py +15 -12
- ansys/fluent/core/session_meshing.py +3 -0
- ansys/fluent/core/session_solver.py +20 -43
- ansys/fluent/core/session_utilities.py +429 -0
- ansys/fluent/core/solver/flobject.py +28 -0
- ansys/fluent/core/utils/deprecate.py +46 -0
- ansys/fluent/core/utils/file_transfer_service.py +19 -3
- ansys/fluent/core/utils/fluent_version.py +42 -11
- ansys/fluent/core/variable_strategies/__init__.py +29 -0
- ansys/fluent/core/variable_strategies/expr.py +186 -0
- ansys/fluent/core/variable_strategies/field.py +186 -0
- ansys/fluent/core/variable_strategies/svar.py +61 -0
- {ansys_fluent_core-0.31.dev1.dist-info → ansys_fluent_core-0.31.1.dist-info}/METADATA +9 -6
- {ansys_fluent_core-0.31.dev1.dist-info → ansys_fluent_core-0.31.1.dist-info}/RECORD +59 -53
- {ansys_fluent_core-0.31.dev1.dist-info → ansys_fluent_core-0.31.1.dist-info}/WHEEL +1 -1
- {ansys_fluent_core-0.31.dev1.dist-info → ansys_fluent_core-0.31.1.dist-info/licenses}/LICENSE +0 -0
ansys/fluent/core/__init__.py
CHANGED
|
@@ -57,14 +57,22 @@ from ansys.fluent.core.pyfluent_warnings import ( # noqa: F401
|
|
|
57
57
|
from ansys.fluent.core.search import search # noqa: F401
|
|
58
58
|
from ansys.fluent.core.services.batch_ops import BatchOps # noqa: F401
|
|
59
59
|
from ansys.fluent.core.session import BaseSession as Fluent # noqa: F401
|
|
60
|
+
from ansys.fluent.core.session_utilities import ( # noqa: F401
|
|
61
|
+
Meshing,
|
|
62
|
+
PrePost,
|
|
63
|
+
PureMeshing,
|
|
64
|
+
Solver,
|
|
65
|
+
SolverAero,
|
|
66
|
+
SolverIcing,
|
|
67
|
+
)
|
|
60
68
|
from ansys.fluent.core.streaming_services.events_streaming import * # noqa: F401, F403
|
|
61
69
|
from ansys.fluent.core.utils import fldoc, get_examples_download_dir
|
|
62
70
|
from ansys.fluent.core.utils.fluent_version import FluentVersion # noqa: F401
|
|
63
71
|
from ansys.fluent.core.utils.setup_for_fluent import setup_for_fluent # noqa: F401
|
|
64
72
|
|
|
65
|
-
__version__ = "0.31.
|
|
73
|
+
__version__ = "0.31.1"
|
|
66
74
|
|
|
67
|
-
_VERSION_INFO = "Build date:
|
|
75
|
+
_VERSION_INFO = "Build date: August 15, 2025 03:41 UTC ShaID: e30f89c"
|
|
68
76
|
"""
|
|
69
77
|
Global variable indicating the version info of the PyFluent package.
|
|
70
78
|
Build timestamp and commit hash are added to this variable during packaging.
|
|
@@ -106,7 +114,7 @@ EXAMPLES_PATH = str(get_examples_download_dir())
|
|
|
106
114
|
CONTAINER_MOUNT_SOURCE = None
|
|
107
115
|
|
|
108
116
|
# Path inside the container where the host path is mounted
|
|
109
|
-
CONTAINER_MOUNT_TARGET = "/
|
|
117
|
+
CONTAINER_MOUNT_TARGET = "/home/container/workdir"
|
|
110
118
|
|
|
111
119
|
# Set this to False to stop automatically inferring and setting REMOTING_SERVER_ADDRESS
|
|
112
120
|
INFER_REMOTING_IP = True
|
|
@@ -124,6 +124,7 @@ def _populate_data(cls, api_tree: dict, version: str) -> dict:
|
|
|
124
124
|
data["argument_names"] = getattr(cls, "argument_names", [])
|
|
125
125
|
data["child_aliases"] = getattr(cls, "_child_aliases", {})
|
|
126
126
|
data["return_type"] = getattr(cls, "return_type", None)
|
|
127
|
+
data["deprecated_version"] = getattr(cls, "_deprecated_version", None)
|
|
127
128
|
child_classes = data.setdefault("child_classes", {})
|
|
128
129
|
for k, v in cls._child_classes.items():
|
|
129
130
|
if k in command_names:
|
|
@@ -227,6 +228,11 @@ def _write_data(cls_name: str, python_name: str, data: dict, f: IO, f_stub: IO |
|
|
|
227
228
|
s.write(f" {doc}\n")
|
|
228
229
|
s.write(' """\n')
|
|
229
230
|
s.write(f" _version = {data['version']!r}\n")
|
|
231
|
+
deprecated = data["deprecated_version"]
|
|
232
|
+
if deprecated:
|
|
233
|
+
release_version = "20" + data["deprecated_version"].replace(".", "R")
|
|
234
|
+
s.write(f" _deprecated_version = {release_version!r}\n")
|
|
235
|
+
s_stub.write(" _deprecated_version: str\n")
|
|
230
236
|
s.write(f" fluent_name = {data['fluent_name']!r}\n")
|
|
231
237
|
# _python_name preserves the original non-suffixed name of the class.
|
|
232
238
|
s.write(f" _python_name = {python_name!r}\n")
|
|
@@ -58,7 +58,6 @@ from ansys.fluent.core.services.datamodel_tui import (
|
|
|
58
58
|
)
|
|
59
59
|
from ansys.fluent.core.utils.fix_doc import escape_wildcards
|
|
60
60
|
from ansys.fluent.core.utils.fluent_version import (
|
|
61
|
-
AnsysVersionNotFound,
|
|
62
61
|
FluentVersion,
|
|
63
62
|
get_version_for_file_name,
|
|
64
63
|
)
|
|
@@ -130,7 +129,7 @@ def _copy_tui_help_xml_file(version: str):
|
|
|
130
129
|
shutil.copy(str(xml_source), _XML_HELP_FILE)
|
|
131
130
|
else:
|
|
132
131
|
logger.warning("fluent_gui_help.xml is not found.")
|
|
133
|
-
except
|
|
132
|
+
except FileNotFoundError:
|
|
134
133
|
logger.warning("fluent_gui_help.xml is not found.")
|
|
135
134
|
|
|
136
135
|
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""Launch Fluent through docker compose."""
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates.
|
|
4
|
+
# SPDX-License-Identifier: MIT
|
|
5
|
+
#
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
# in the Software without restriction, including without limitation the rights
|
|
10
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
# furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
# copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
# SOFTWARE.
|
|
24
|
+
|
|
25
|
+
import os
|
|
26
|
+
import subprocess
|
|
27
|
+
import uuid
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ComposeBasedLauncher:
|
|
31
|
+
"""Launch Fluent through docker or Podman compose."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, *, container_dict):
|
|
34
|
+
self._compose_name = f"pyfluent_compose_{uuid.uuid4().hex}"
|
|
35
|
+
self._container_dict = container_dict
|
|
36
|
+
self._image_name = (
|
|
37
|
+
container_dict.get("fluent_image")
|
|
38
|
+
or f"ghcr.io/ansys/pyfluent:{os.getenv('FLUENT_IMAGE_TAG')}"
|
|
39
|
+
)
|
|
40
|
+
self._container_source = self._set_compose_cmds()
|
|
41
|
+
self._container_source.remove("compose")
|
|
42
|
+
|
|
43
|
+
self._compose_file = self._get_compose_file(container_dict)
|
|
44
|
+
|
|
45
|
+
def _is_podman_selected(self):
|
|
46
|
+
return os.getenv("PYFLUENT_USE_PODMAN_COMPOSE") == "1"
|
|
47
|
+
|
|
48
|
+
def _get_compose_file(self, container_dict):
|
|
49
|
+
"""Generates compose file for the Docker Compose setup.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
container_dict: dict
|
|
54
|
+
A dictionary containing container configuration.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
indent = " "
|
|
58
|
+
|
|
59
|
+
if container_dict.get("ports"):
|
|
60
|
+
ports = list(container_dict.get("ports").values())
|
|
61
|
+
else:
|
|
62
|
+
ports = [container_dict.get("fluent_port", "")]
|
|
63
|
+
|
|
64
|
+
compose_file = f"""
|
|
65
|
+
services:
|
|
66
|
+
fluent:
|
|
67
|
+
image: {container_dict.get("fluent_image")}
|
|
68
|
+
command: {" ".join(container_dict["command"])}
|
|
69
|
+
working_dir: {container_dict.get("mount_target")}
|
|
70
|
+
volumes:
|
|
71
|
+
{indent}- {container_dict.get("mount_source")}:{container_dict.get("mount_target")}
|
|
72
|
+
ports:
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
for port in ports:
|
|
76
|
+
if len(ports) == 1:
|
|
77
|
+
compose_file += f"{indent * 3}- {port}:{port}"
|
|
78
|
+
else:
|
|
79
|
+
if port == ports[0]:
|
|
80
|
+
compose_file += f"{indent * 3}- {port}:{port}\n"
|
|
81
|
+
elif port == ports[-1]:
|
|
82
|
+
compose_file += f"{indent * 7}- {port}:{port}"
|
|
83
|
+
else:
|
|
84
|
+
compose_file += f"{indent * 7}- {port}:{port}\n"
|
|
85
|
+
|
|
86
|
+
compose_file_env = f"""
|
|
87
|
+
{indent * 2}environment:
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
for key, value in container_dict["environment"].items():
|
|
91
|
+
if key == "ANSYSLMD_LICENSE_FILE":
|
|
92
|
+
compose_file_env += f"""{indent * 3}- {key}={value}\n"""
|
|
93
|
+
else:
|
|
94
|
+
compose_file_env += f"""{indent * 7}- {key}={value}\n"""
|
|
95
|
+
|
|
96
|
+
compose_file += compose_file_env
|
|
97
|
+
|
|
98
|
+
return compose_file
|
|
99
|
+
|
|
100
|
+
def _extract_ports(self, port_string):
|
|
101
|
+
"""
|
|
102
|
+
Extracts ports from a string containing port mappings.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
port_string: str
|
|
107
|
+
A string containing port mappings.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
ports: list
|
|
112
|
+
A list of extracted ports.
|
|
113
|
+
"""
|
|
114
|
+
ports = []
|
|
115
|
+
for line in port_string.split("\n"):
|
|
116
|
+
if line:
|
|
117
|
+
_, target = line.split("->")
|
|
118
|
+
port = target.split(":")[1]
|
|
119
|
+
ports.append(port)
|
|
120
|
+
return [port for port in ports if port.isdigit()]
|
|
121
|
+
|
|
122
|
+
def _set_compose_cmds(self):
|
|
123
|
+
"""Sets the compose commands based on available tools and permissions.
|
|
124
|
+
|
|
125
|
+
Raises
|
|
126
|
+
------
|
|
127
|
+
RuntimeError
|
|
128
|
+
If neither Docker nor Podman is specified.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
# Determine the compose command
|
|
132
|
+
if os.getenv("PYFLUENT_USE_PODMAN_COMPOSE") == "1":
|
|
133
|
+
self._compose_cmds = (
|
|
134
|
+
["sudo", "podman", "compose"]
|
|
135
|
+
if hasattr(self, "_container_source")
|
|
136
|
+
and "sudo" in self._container_source
|
|
137
|
+
else ["podman", "compose"]
|
|
138
|
+
)
|
|
139
|
+
elif os.getenv("PYFLUENT_USE_DOCKER_COMPOSE") == "1":
|
|
140
|
+
self._compose_cmds = ["docker", "compose"]
|
|
141
|
+
else:
|
|
142
|
+
raise RuntimeError("Neither Docker nor Podman is specified.")
|
|
143
|
+
|
|
144
|
+
return self._compose_cmds
|
|
145
|
+
|
|
146
|
+
def check_image_exists(self) -> bool:
|
|
147
|
+
"""Check if the image exists locally."""
|
|
148
|
+
try:
|
|
149
|
+
cmd = self._container_source + ["images", "-q", self._image_name]
|
|
150
|
+
# Podman users do not always configure rootless mode in /etc/subuids and /etc/subgids
|
|
151
|
+
if self._is_podman_selected():
|
|
152
|
+
sudo_cmd = ["sudo"] + cmd
|
|
153
|
+
output_1 = subprocess.check_output(cmd)
|
|
154
|
+
output_2 = subprocess.check_output(sudo_cmd)
|
|
155
|
+
output_1_result = output_1.decode("utf-8").strip() != ""
|
|
156
|
+
output_2_result = output_2.decode("utf-8").strip() != ""
|
|
157
|
+
if output_2_result and not output_1_result:
|
|
158
|
+
self._container_source.insert(0, "sudo")
|
|
159
|
+
return output_1_result or output_2_result
|
|
160
|
+
else:
|
|
161
|
+
output = subprocess.check_output(cmd)
|
|
162
|
+
return output.decode("utf-8").strip() != ""
|
|
163
|
+
except subprocess.CalledProcessError as e: # noqa: F841
|
|
164
|
+
return False
|
|
165
|
+
|
|
166
|
+
def pull_image(self) -> None:
|
|
167
|
+
"""Pull a Docker image if it does not exist locally."""
|
|
168
|
+
|
|
169
|
+
cmd = self._container_source + ["pull", self._image_name]
|
|
170
|
+
|
|
171
|
+
subprocess.check_call(cmd)
|
|
172
|
+
|
|
173
|
+
def _start_stop_helper(
|
|
174
|
+
self, compose_cmd: list[str], cmd: list[str], timeout: float
|
|
175
|
+
) -> None:
|
|
176
|
+
"""Helper function to start or stop the services.
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
compose_cmd: list[str]
|
|
180
|
+
The command to run.
|
|
181
|
+
cmd: list[str]
|
|
182
|
+
The command to run.
|
|
183
|
+
timeout: float
|
|
184
|
+
The timeout for the command.
|
|
185
|
+
"""
|
|
186
|
+
process = subprocess.Popen(
|
|
187
|
+
compose_cmd + cmd,
|
|
188
|
+
stdin=subprocess.PIPE,
|
|
189
|
+
text=True,
|
|
190
|
+
stdout=subprocess.DEVNULL,
|
|
191
|
+
stderr=subprocess.DEVNULL,
|
|
192
|
+
)
|
|
193
|
+
process.communicate(input=self._compose_file, timeout=timeout)
|
|
194
|
+
return_code = process.wait(timeout=timeout)
|
|
195
|
+
|
|
196
|
+
if return_code != 0:
|
|
197
|
+
raise subprocess.CalledProcessError(return_code, compose_cmd + cmd)
|
|
198
|
+
|
|
199
|
+
def start(self) -> None:
|
|
200
|
+
"""Start the services.
|
|
201
|
+
|
|
202
|
+
Raises
|
|
203
|
+
------
|
|
204
|
+
subprocess.CalledProcessError
|
|
205
|
+
If the command fails.
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
cmd = [
|
|
209
|
+
"-f",
|
|
210
|
+
"-",
|
|
211
|
+
"--project-name",
|
|
212
|
+
self._compose_name,
|
|
213
|
+
"up",
|
|
214
|
+
"--detach",
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
self._start_stop_helper(self._set_compose_cmds(), cmd, 60)
|
|
218
|
+
|
|
219
|
+
def stop(self) -> None:
|
|
220
|
+
"""Stop the services.
|
|
221
|
+
|
|
222
|
+
Raises
|
|
223
|
+
------
|
|
224
|
+
subprocess.CalledProcessError
|
|
225
|
+
If the command fails.
|
|
226
|
+
"""
|
|
227
|
+
cmd = [
|
|
228
|
+
"-f",
|
|
229
|
+
"-",
|
|
230
|
+
"--project-name",
|
|
231
|
+
self._compose_name,
|
|
232
|
+
"down",
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
self._start_stop_helper(self._set_compose_cmds(), cmd, 30)
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def ports(self) -> list[str]:
|
|
239
|
+
"""Return the ports of the launched services."""
|
|
240
|
+
output = subprocess.check_output(
|
|
241
|
+
self._container_source + ["port", f"{self._compose_name}-fluent-1"],
|
|
242
|
+
)
|
|
243
|
+
return self._extract_ports(output.decode("utf-8").strip())
|
|
@@ -30,6 +30,11 @@ import numpy as np
|
|
|
30
30
|
import numpy.typing as npt
|
|
31
31
|
|
|
32
32
|
from ansys.fluent.core.exceptions import DisallowedValuesError
|
|
33
|
+
from ansys.fluent.core.variable_strategies import (
|
|
34
|
+
FluentFieldDataNamingStrategy as naming_strategy,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
_to_field_name_str = naming_strategy().to_string if naming_strategy else lambda s: s
|
|
33
38
|
|
|
34
39
|
|
|
35
40
|
class SurfaceDataType(Enum):
|
|
@@ -311,6 +316,7 @@ class _AllowedFieldNames(_AllowedNames):
|
|
|
311
316
|
|
|
312
317
|
def valid_name(self, field_name):
|
|
313
318
|
"""Returns valid names."""
|
|
319
|
+
field_name = _to_field_name_str(field_name)
|
|
314
320
|
if validate_inputs:
|
|
315
321
|
names = self
|
|
316
322
|
if not names.is_valid(field_name, respect_data_valid=False):
|