ansys-fluent-core 0.28.2__py3-none-any.whl → 0.29.dev1__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 +1 -1
- ansys/fluent/core/_version.py +2 -2
- ansys/fluent/core/codegen/tuigen.py +1 -1
- ansys/fluent/core/codegen/walk_api.py +45 -18
- ansys/fluent/core/generated/api_tree/api_objects.json +1 -1
- ansys/fluent/core/generated/datamodel_252/meshing.py +1 -0
- ansys/fluent/core/generated/fluent_version_252.py +3 -3
- ansys/fluent/core/generated/solver/settings_252.py +251 -160
- ansys/fluent/core/generated/solver/settings_252.pyi +146 -54
- ansys/fluent/core/generated/solver/tui_252.py +48 -24
- ansys/fluent/core/launcher/container_launcher.py +4 -3
- ansys/fluent/core/launcher/fluent_container.py +22 -19
- ansys/fluent/core/launcher/launcher.py +2 -2
- ansys/fluent/core/launcher/pim_launcher.py +2 -2
- ansys/fluent/core/launcher/slurm_launcher.py +2 -2
- ansys/fluent/core/launcher/standalone_launcher.py +2 -2
- ansys/fluent/core/logging.py +2 -0
- ansys/fluent/core/logging_config.yaml +3 -0
- ansys/fluent/core/services/datamodel_se.py +4 -1
- ansys/fluent/core/services/field_data.py +252 -0
- ansys/fluent/core/services/interceptors.py +28 -2
- ansys/fluent/core/session.py +7 -2
- ansys/fluent/core/session_solver.py +21 -0
- {ansys_fluent_core-0.28.2.dist-info → ansys_fluent_core-0.29.dev1.dist-info}/LICENSE +1 -1
- {ansys_fluent_core-0.28.2.dist-info → ansys_fluent_core-0.29.dev1.dist-info}/METADATA +53 -32
- {ansys_fluent_core-0.28.2.dist-info → ansys_fluent_core-0.29.dev1.dist-info}/RECORD +61 -137
- {ansys_fluent_core-0.28.2.dist-info → ansys_fluent_core-0.29.dev1.dist-info}/WHEEL +1 -1
- ansys/fluent/core/docs/README.rst +0 -155
- ansys/fluent/tests/conftest.py +0 -415
- ansys/fluent/tests/fluent_fixtures.py +0 -195
- ansys/fluent/tests/integration/test_optislang/test_optislang_integration.py +0 -263
- ansys/fluent/tests/parametric/test_local_parametric_run.py +0 -36
- ansys/fluent/tests/parametric/test_local_parametric_setup.py +0 -34
- ansys/fluent/tests/parametric/test_parametric_workflow.py +0 -279
- ansys/fluent/tests/test_aero_session.py +0 -88
- ansys/fluent/tests/test_batch_ops.py +0 -39
- ansys/fluent/tests/test_builtin_settings.py +0 -761
- ansys/fluent/tests/test_cad_to_post_ftm.py +0 -525
- ansys/fluent/tests/test_cad_to_post_wtm.py +0 -250
- ansys/fluent/tests/test_casereader.py +0 -324
- ansys/fluent/tests/test_codegen.py +0 -783
- ansys/fluent/tests/test_creatable.py +0 -31
- ansys/fluent/tests/test_data_model_cache.py +0 -434
- ansys/fluent/tests/test_datamodel_api.py +0 -429
- ansys/fluent/tests/test_datamodel_service.py +0 -814
- ansys/fluent/tests/test_datareader.py +0 -103
- ansys/fluent/tests/test_error_handling.py +0 -24
- ansys/fluent/tests/test_events_manager.py +0 -214
- ansys/fluent/tests/test_field_data.py +0 -466
- ansys/fluent/tests/test_file_session.py +0 -355
- ansys/fluent/tests/test_file_transfer_service.py +0 -165
- ansys/fluent/tests/test_fix_doc.py +0 -29
- ansys/fluent/tests/test_flobject.py +0 -1235
- ansys/fluent/tests/test_fluent_fixes.py +0 -106
- ansys/fluent/tests/test_fluent_session.py +0 -270
- ansys/fluent/tests/test_fluent_version.py +0 -66
- ansys/fluent/tests/test_fluent_version_marker.py +0 -65
- ansys/fluent/tests/test_icing_session.py +0 -9
- ansys/fluent/tests/test_launcher.py +0 -529
- ansys/fluent/tests/test_launcher_remote.py +0 -272
- ansys/fluent/tests/test_lispy.py +0 -40
- ansys/fluent/tests/test_logging.py +0 -16
- ansys/fluent/tests/test_mapped_api.py +0 -766
- ansys/fluent/tests/test_meshing_utilities.py +0 -2436
- ansys/fluent/tests/test_meshing_workflow.py +0 -421
- ansys/fluent/tests/test_meshingmode/test_meshing_launch.py +0 -168
- ansys/fluent/tests/test_new_meshing_workflow.py +0 -1801
- ansys/fluent/tests/test_preferences.py +0 -89
- ansys/fluent/tests/test_pure_mesh_vs_mesh_workflow.py +0 -101
- ansys/fluent/tests/test_reduction.py +0 -484
- ansys/fluent/tests/test_rp_vars.py +0 -77
- ansys/fluent/tests/test_scheduler.py +0 -471
- ansys/fluent/tests/test_scheme_eval_222.py +0 -338
- ansys/fluent/tests/test_scheme_eval_231.py +0 -243
- ansys/fluent/tests/test_search.py +0 -344
- ansys/fluent/tests/test_session.py +0 -594
- ansys/fluent/tests/test_settings_api.py +0 -606
- ansys/fluent/tests/test_settings_reader.py +0 -85
- ansys/fluent/tests/test_slurm_future.py +0 -67
- ansys/fluent/tests/test_solution_variables.py +0 -241
- ansys/fluent/tests/test_solver_monitors.py +0 -83
- ansys/fluent/tests/test_solvermode/boundaries_periodic_expDict +0 -1712
- ansys/fluent/tests/test_solvermode/test_boundaries.py +0 -127
- ansys/fluent/tests/test_solvermode/test_calculationactivities.py +0 -20
- ansys/fluent/tests/test_solvermode/test_controls.py +0 -131
- ansys/fluent/tests/test_solvermode/test_general.py +0 -109
- ansys/fluent/tests/test_solvermode/test_initialization.py +0 -83
- ansys/fluent/tests/test_solvermode/test_materials.py +0 -40
- ansys/fluent/tests/test_solvermode/test_methods.py +0 -65
- ansys/fluent/tests/test_solvermode/test_models.py +0 -99
- ansys/fluent/tests/test_solvermode/test_named_expressions.py +0 -35
- ansys/fluent/tests/test_solvermode/test_post_vector.py +0 -22
- ansys/fluent/tests/test_solvermode/test_species_model.py +0 -67
- ansys/fluent/tests/test_streaming_services.py +0 -52
- ansys/fluent/tests/test_systemcoupling.py +0 -44
- ansys/fluent/tests/test_topy.py +0 -179
- ansys/fluent/tests/test_tui_api.py +0 -70
- ansys/fluent/tests/test_type_stub.py +0 -37
- ansys/fluent/tests/test_utils.py +0 -82
- ansys/fluent/tests/util/__init__.py +0 -36
- ansys/fluent/tests/util/meshing_workflow.py +0 -33
- ansys/fluent/tests/util/solver.py +0 -72
- ansys_fluent_core-0.28.2.dist-info/AUTHORS +0 -12
|
@@ -239,16 +239,23 @@ def configure_container_dict(
|
|
|
239
239
|
logger.warning(
|
|
240
240
|
f"Starting Fluent container mounted to {mount_source}, with this path available as {mount_target} for the Fluent session running inside the container."
|
|
241
241
|
)
|
|
242
|
-
|
|
243
|
-
if not
|
|
242
|
+
port_mapping = {port: port} if port else {}
|
|
243
|
+
if not port_mapping and "ports" in container_dict:
|
|
244
244
|
# take the specified 'port', OR the first port value from the specified 'ports', for Fluent to use
|
|
245
|
-
|
|
246
|
-
if not
|
|
245
|
+
port_mapping = container_dict["ports"]
|
|
246
|
+
if not port_mapping and pyfluent.LAUNCH_FLUENT_PORT:
|
|
247
247
|
port = pyfluent.LAUNCH_FLUENT_PORT
|
|
248
|
-
|
|
248
|
+
port_mapping = {port: port}
|
|
249
|
+
if not port_mapping:
|
|
249
250
|
port = get_free_port()
|
|
251
|
+
port_mapping = {port: port}
|
|
250
252
|
|
|
251
|
-
container_dict.update(
|
|
253
|
+
container_dict.update(
|
|
254
|
+
ports={str(x): y for x, y in port_mapping.items()}
|
|
255
|
+
) # container port : host port
|
|
256
|
+
container_grpc_port = next(
|
|
257
|
+
iter(port_mapping.values())
|
|
258
|
+
) # the first port in the mapping is chosen as the gRPC port
|
|
252
259
|
|
|
253
260
|
if "environment" not in container_dict:
|
|
254
261
|
if not license_server:
|
|
@@ -259,7 +266,7 @@ def configure_container_dict(
|
|
|
259
266
|
container_dict.update(
|
|
260
267
|
environment={
|
|
261
268
|
"ANSYSLMD_LICENSE_FILE": license_server,
|
|
262
|
-
"REMOTING_PORTS": f"{
|
|
269
|
+
"REMOTING_PORTS": f"{container_grpc_port}/portspan=2",
|
|
263
270
|
}
|
|
264
271
|
)
|
|
265
272
|
|
|
@@ -319,16 +326,10 @@ def configure_container_dict(
|
|
|
319
326
|
container_dict["environment"] = {}
|
|
320
327
|
container_dict["environment"]["FLUENT_NO_AUTOMATIC_TRANSCRIPT"] = "1"
|
|
321
328
|
|
|
322
|
-
if (
|
|
323
|
-
os.getenv("REMOTING_NEW_DM_API") == "1"
|
|
324
|
-
or os.getenv("REMOTING_MAPPED_NEW_DM_API") == "1"
|
|
325
|
-
):
|
|
329
|
+
if os.getenv("REMOTING_NEW_DM_API") == "1":
|
|
326
330
|
if "environment" not in container_dict:
|
|
327
331
|
container_dict["environment"] = {}
|
|
328
|
-
|
|
329
|
-
container_dict["environment"]["REMOTING_NEW_DM_API"] = "1"
|
|
330
|
-
if os.getenv("REMOTING_MAPPED_NEW_DM_API") == "1":
|
|
331
|
-
container_dict["environment"]["REMOTING_MAPPED_NEW_DM_API"] = "1"
|
|
332
|
+
container_dict["environment"]["REMOTING_NEW_DM_API"] = "1"
|
|
332
333
|
|
|
333
334
|
if pyfluent.LAUNCH_FLUENT_IP or os.getenv("REMOTING_SERVER_ADDRESS"):
|
|
334
335
|
if "environment" not in container_dict:
|
|
@@ -360,7 +361,7 @@ def configure_container_dict(
|
|
|
360
361
|
return (
|
|
361
362
|
container_dict,
|
|
362
363
|
timeout,
|
|
363
|
-
|
|
364
|
+
container_grpc_port,
|
|
364
365
|
host_server_info_file,
|
|
365
366
|
remove_server_info_file,
|
|
366
367
|
)
|
|
@@ -368,7 +369,7 @@ def configure_container_dict(
|
|
|
368
369
|
|
|
369
370
|
def start_fluent_container(
|
|
370
371
|
args: List[str], container_dict: dict | None = None
|
|
371
|
-
) ->
|
|
372
|
+
) -> tuple[int, str, Any]:
|
|
372
373
|
"""Start a Fluent container.
|
|
373
374
|
|
|
374
375
|
Parameters
|
|
@@ -439,7 +440,9 @@ def start_fluent_container(
|
|
|
439
440
|
|
|
440
441
|
logger.debug("Starting Fluent docker container...")
|
|
441
442
|
|
|
442
|
-
docker_client.containers.run(
|
|
443
|
+
container = docker_client.containers.run(
|
|
444
|
+
config_dict.pop("fluent_image"), **config_dict
|
|
445
|
+
)
|
|
443
446
|
|
|
444
447
|
success = timeout_loop(
|
|
445
448
|
lambda: host_server_info_file.stat().st_mtime > last_mtime, timeout
|
|
@@ -452,7 +455,7 @@ def start_fluent_container(
|
|
|
452
455
|
else:
|
|
453
456
|
_, _, password = _parse_server_info_file(str(host_server_info_file))
|
|
454
457
|
|
|
455
|
-
return port, password
|
|
458
|
+
return port, password, container
|
|
456
459
|
finally:
|
|
457
460
|
if remove_server_info_file and host_server_info_file.exists():
|
|
458
461
|
host_server_info_file.unlink()
|
|
@@ -130,8 +130,8 @@ def launch_fluent(
|
|
|
130
130
|
Parameters
|
|
131
131
|
----------
|
|
132
132
|
product_version : FluentVersion or str or float or int, optional
|
|
133
|
-
Version of Ansys Fluent to launch. To use Fluent version
|
|
134
|
-
any of ``FluentVersion.
|
|
133
|
+
Version of Ansys Fluent to launch. To use Fluent version 2025 R1, pass
|
|
134
|
+
any of ``FluentVersion.v251``, ``"25.1.0"``, ``"25.1"``, ``25.1``or ``251``.
|
|
135
135
|
The default is ``None``, in which case the newest installed version is used.
|
|
136
136
|
dimension : Dimension or int, optional
|
|
137
137
|
Geometric dimensionality of the Fluent simulation. The default is ``None``,
|
|
@@ -76,8 +76,8 @@ class PIMLauncher:
|
|
|
76
76
|
``FluentWindowsGraphicsDriver`` enum in Windows or the values of the
|
|
77
77
|
``FluentLinuxGraphicsDriver`` enum in Linux.
|
|
78
78
|
product_version : FluentVersion or str or float or int, optional
|
|
79
|
-
Version of Ansys Fluent to launch. To use Fluent version
|
|
80
|
-
``FluentVersion.
|
|
79
|
+
Version of Ansys Fluent to launch. To use Fluent version 2025 R1, pass
|
|
80
|
+
``FluentVersion.v251``, ``"25.1.0"``, ``"25.1"``, ``25.1``, or ``251``.
|
|
81
81
|
The default is ``None``, in which case the newest installed version is used.
|
|
82
82
|
dimension : Dimension or int, optional
|
|
83
83
|
Geometric dimensionality of the Fluent simulation. The default is ``None``,
|
|
@@ -301,8 +301,8 @@ class SlurmLauncher:
|
|
|
301
301
|
``FluentWindowsGraphicsDriver`` enum in Windows or the values of the
|
|
302
302
|
``FluentLinuxGraphicsDriver`` enum in Linux.
|
|
303
303
|
product_version : FluentVersion or str or float or int, optional
|
|
304
|
-
Version of Ansys Fluent to launch. To use Fluent version
|
|
305
|
-
``FluentVersion.
|
|
304
|
+
Version of Ansys Fluent to launch. To use Fluent version 2025 R1, pass
|
|
305
|
+
``FluentVersion.v251``, ``"25.1.0"``, ``"25.1"``, ``25.1``, or ``251``.
|
|
306
306
|
The default is ``None``, in which case the newest installed version is used.
|
|
307
307
|
dimension : Dimension or int, optional
|
|
308
308
|
Geometric dimensionality of the Fluent simulation. The default is ``None``,
|
|
@@ -96,8 +96,8 @@ class StandaloneLauncher:
|
|
|
96
96
|
``FluentWindowsGraphicsDriver`` enum in Windows or the values of the
|
|
97
97
|
``FluentLinuxGraphicsDriver`` enum in Linux.
|
|
98
98
|
product_version : FluentVersion or str or float or int, optional
|
|
99
|
-
Version of Ansys Fluent to launch. To use Fluent version
|
|
100
|
-
``FluentVersion.
|
|
99
|
+
Version of Ansys Fluent to launch. To use Fluent version 2025 R1, pass
|
|
100
|
+
``FluentVersion.v251``, ``"25.1.0"``, ``"25.1"``, ``25.1``, or ``251``.
|
|
101
101
|
The default is ``None``, in which case the newest installed version is used.
|
|
102
102
|
dimension : Dimension or int, optional
|
|
103
103
|
Geometric dimensionality of the Fluent simulation. The default is ``None``,
|
ansys/fluent/core/logging.py
CHANGED
|
@@ -61,6 +61,8 @@ def get_default_config() -> dict:
|
|
|
61
61
|
'maxBytes': 10485760}},
|
|
62
62
|
'loggers': {'pyfluent.datamodel': {'handlers': ['pyfluent_file'],
|
|
63
63
|
'level': 'DEBUG'},
|
|
64
|
+
'pyfluent.field_data': {'handlers': ['pyfluent_file'],
|
|
65
|
+
'level': 'DEBUG'},
|
|
64
66
|
'pyfluent.general': {'handlers': ['pyfluent_file'],
|
|
65
67
|
'level': 'DEBUG'},
|
|
66
68
|
'pyfluent.launcher': {'handlers': ['pyfluent_file'],
|
|
@@ -176,6 +176,8 @@ class DatamodelServiceImpl:
|
|
|
176
176
|
self._stub = DataModelGrpcModule.DataModelStub(intercept_channel)
|
|
177
177
|
self._metadata = metadata
|
|
178
178
|
self.file_transfer_service = file_transfer_service
|
|
179
|
+
if os.getenv("REMOTING_MAPPED_NEW_DM_API") == "1":
|
|
180
|
+
self._metadata.append(("mapped", "1"))
|
|
179
181
|
|
|
180
182
|
# TODO: Remove it from the proto interface
|
|
181
183
|
def initialize_datamodel(
|
|
@@ -1969,7 +1971,8 @@ class PyCommand:
|
|
|
1969
1971
|
id,
|
|
1970
1972
|
static_info.get("args"),
|
|
1971
1973
|
)
|
|
1972
|
-
|
|
1974
|
+
# Possible error thrown from the grpc layer
|
|
1975
|
+
except (RuntimeError, ValueError):
|
|
1973
1976
|
logger.warning(
|
|
1974
1977
|
"Create command arguments object is available from 23.1 onwards"
|
|
1975
1978
|
)
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"""Wrappers over FieldData gRPC service of Fluent."""
|
|
2
2
|
|
|
3
|
+
from dataclasses import dataclass, field
|
|
3
4
|
from enum import Enum
|
|
4
5
|
from functools import reduce
|
|
6
|
+
import logging
|
|
7
|
+
import time
|
|
5
8
|
from typing import Callable, Dict, List, Tuple
|
|
9
|
+
import weakref
|
|
6
10
|
|
|
7
11
|
import grpc
|
|
8
12
|
import numpy as np
|
|
@@ -19,6 +23,8 @@ from ansys.fluent.core.services.interceptors import (
|
|
|
19
23
|
from ansys.fluent.core.services.streaming import StreamingService
|
|
20
24
|
from ansys.fluent.core.utils.deprecate import deprecate_argument, deprecate_arguments
|
|
21
25
|
|
|
26
|
+
logger = logging.getLogger("pyfluent.field_data")
|
|
27
|
+
|
|
22
28
|
|
|
23
29
|
def override_help_text(func, func_to_be_wrapped):
|
|
24
30
|
"""Override function help text."""
|
|
@@ -82,6 +88,28 @@ class FieldDataService(StreamingService):
|
|
|
82
88
|
)
|
|
83
89
|
return chunk_iterator
|
|
84
90
|
|
|
91
|
+
def get_solver_mesh_nodes(
|
|
92
|
+
self, request: FieldDataProtoModule.GetSolverMeshNodesRequest
|
|
93
|
+
):
|
|
94
|
+
"""GetSolverMeshNodesDouble RPC of FieldData service."""
|
|
95
|
+
responses = self._stub.GetSolverMeshNodesDouble(
|
|
96
|
+
request, metadata=self._metadata
|
|
97
|
+
)
|
|
98
|
+
nested_nodes = []
|
|
99
|
+
for response in responses:
|
|
100
|
+
nested_nodes.append(response.nodes)
|
|
101
|
+
return nested_nodes
|
|
102
|
+
|
|
103
|
+
def get_solver_mesh_elements(
|
|
104
|
+
self, request: FieldDataProtoModule.GetSolverMeshElementsRequest
|
|
105
|
+
):
|
|
106
|
+
"""GetSolverMeshElements RPC of FieldData service."""
|
|
107
|
+
responses = self._stub.GetSolverMeshElements(request, metadata=self._metadata)
|
|
108
|
+
elementss = []
|
|
109
|
+
for response in responses:
|
|
110
|
+
elementss.append(response.elements)
|
|
111
|
+
return elementss
|
|
112
|
+
|
|
85
113
|
|
|
86
114
|
class FieldInfo:
|
|
87
115
|
"""Provides access to Fluent field information.
|
|
@@ -922,6 +950,134 @@ class ChunkParser:
|
|
|
922
950
|
return fields_data
|
|
923
951
|
|
|
924
952
|
|
|
953
|
+
# Root domain id in Fluent.
|
|
954
|
+
ROOT_DOMAIN_ID = 1
|
|
955
|
+
|
|
956
|
+
|
|
957
|
+
class ZoneType(Enum):
|
|
958
|
+
"""Zone types for mesh."""
|
|
959
|
+
|
|
960
|
+
CELL = 1
|
|
961
|
+
FACE = 2
|
|
962
|
+
|
|
963
|
+
|
|
964
|
+
@dataclass
|
|
965
|
+
class ZoneInfo:
|
|
966
|
+
"""Zone information for mesh.
|
|
967
|
+
|
|
968
|
+
Attributes:
|
|
969
|
+
-----------
|
|
970
|
+
_id : int
|
|
971
|
+
Zone ID.
|
|
972
|
+
name : str
|
|
973
|
+
Name of the zone.
|
|
974
|
+
zone_type : ZoneType
|
|
975
|
+
Type of the zone for mesh.
|
|
976
|
+
"""
|
|
977
|
+
|
|
978
|
+
_id: int
|
|
979
|
+
name: str
|
|
980
|
+
zone_type: ZoneType
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
@dataclass
|
|
984
|
+
class Node:
|
|
985
|
+
"""Node class for mesh.
|
|
986
|
+
|
|
987
|
+
Attributes:
|
|
988
|
+
-----------
|
|
989
|
+
x : float
|
|
990
|
+
x-coordinate of the node.
|
|
991
|
+
y : float
|
|
992
|
+
y-coordinate of the node.
|
|
993
|
+
z : float
|
|
994
|
+
z-coordinate of the node.
|
|
995
|
+
"""
|
|
996
|
+
|
|
997
|
+
_id: int
|
|
998
|
+
x: float
|
|
999
|
+
y: float
|
|
1000
|
+
z: float
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
class CellElementType(Enum):
|
|
1004
|
+
"""Element types for a cell element."""
|
|
1005
|
+
|
|
1006
|
+
# 3 nodes, 3 faces
|
|
1007
|
+
TRIANGLE = 1
|
|
1008
|
+
# 4 nodes, 4 faces
|
|
1009
|
+
TETRAHEDRON = 2
|
|
1010
|
+
# 4 nodes, 4 faces
|
|
1011
|
+
QUADRILATERAL = 3
|
|
1012
|
+
# 8 nodes, 6 faces
|
|
1013
|
+
HEXAHEDRON = 4
|
|
1014
|
+
# 5 nodes, 5 faces
|
|
1015
|
+
PYRAMID = 5
|
|
1016
|
+
# 6 nodes, 5 faces
|
|
1017
|
+
WEDGE = 6
|
|
1018
|
+
# Arbitrary number of nodes and faces
|
|
1019
|
+
POLYHEDRON = 7
|
|
1020
|
+
# 2 nodes, 1 face (only in 2D)
|
|
1021
|
+
GHOST = 8
|
|
1022
|
+
# 10 nodes, 4 faces
|
|
1023
|
+
QUADRATIC_TETRAHEDRON = 9
|
|
1024
|
+
# 20 nodes, 6 faces
|
|
1025
|
+
QUADRATIC_HEXAHEDRON = 10
|
|
1026
|
+
# 13 nodes, 5 faces
|
|
1027
|
+
QUADRATIC_PYRAMID = 11
|
|
1028
|
+
# 15 nodes, 5 faces
|
|
1029
|
+
QUADRATIC_WEDGE = 12
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
@dataclass
|
|
1033
|
+
class Facet:
|
|
1034
|
+
"""Facet class within a mesh element.
|
|
1035
|
+
|
|
1036
|
+
Attributes:
|
|
1037
|
+
-----------
|
|
1038
|
+
node_indices : list[int]
|
|
1039
|
+
0-based node indices of the facet.
|
|
1040
|
+
"""
|
|
1041
|
+
|
|
1042
|
+
node_indices: list[int]
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
@dataclass
|
|
1046
|
+
class Element:
|
|
1047
|
+
"""Element class for mesh.
|
|
1048
|
+
|
|
1049
|
+
Attributes:
|
|
1050
|
+
-----------
|
|
1051
|
+
element_type : CellElementType
|
|
1052
|
+
Element type of the element.
|
|
1053
|
+
node_indices : list[int]
|
|
1054
|
+
0-based node indices of the element. Populated for standard elements.
|
|
1055
|
+
facets : list[Facet]
|
|
1056
|
+
List of facets of the element. Populated for polyhedral elements.
|
|
1057
|
+
"""
|
|
1058
|
+
|
|
1059
|
+
_id: int
|
|
1060
|
+
element_type: CellElementType
|
|
1061
|
+
node_indices: list[int] = field(default_factory=list)
|
|
1062
|
+
facets: list[Facet] = field(default_factory=list)
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
@dataclass
|
|
1066
|
+
class Mesh:
|
|
1067
|
+
"""Mesh class for Fluent field data.
|
|
1068
|
+
|
|
1069
|
+
Attributes:
|
|
1070
|
+
-----------
|
|
1071
|
+
nodes : list[Node]
|
|
1072
|
+
List of nodes in the mesh.
|
|
1073
|
+
elements : list[Element]
|
|
1074
|
+
List of elements in the mesh.
|
|
1075
|
+
"""
|
|
1076
|
+
|
|
1077
|
+
nodes: list[Node]
|
|
1078
|
+
elements: list[Element]
|
|
1079
|
+
|
|
1080
|
+
|
|
925
1081
|
class FieldData:
|
|
926
1082
|
"""Provides access to Fluent field data on surfaces."""
|
|
927
1083
|
|
|
@@ -931,12 +1087,14 @@ class FieldData:
|
|
|
931
1087
|
field_info: FieldInfo,
|
|
932
1088
|
is_data_valid: Callable[[], bool],
|
|
933
1089
|
scheme_eval=None,
|
|
1090
|
+
get_zones_info: weakref.WeakMethod[Callable[[], list[ZoneInfo]]] | None = None,
|
|
934
1091
|
):
|
|
935
1092
|
"""__init__ method of FieldData class."""
|
|
936
1093
|
self._service = service
|
|
937
1094
|
self._field_info = field_info
|
|
938
1095
|
self.is_data_valid = is_data_valid
|
|
939
1096
|
self.scheme_eval = scheme_eval
|
|
1097
|
+
self.get_zones_info = lambda: get_zones_info()()
|
|
940
1098
|
|
|
941
1099
|
self._allowed_surface_names = _AllowedSurfaceNames(field_info)
|
|
942
1100
|
|
|
@@ -1285,3 +1443,97 @@ class FieldData:
|
|
|
1285
1443
|
field_name: pathlines_data[surface_ids[count]][field_name],
|
|
1286
1444
|
}
|
|
1287
1445
|
return path_lines_dict
|
|
1446
|
+
|
|
1447
|
+
def get_mesh(self, zone: str | int) -> Mesh:
|
|
1448
|
+
"""Get mesh for a zone.
|
|
1449
|
+
|
|
1450
|
+
Parameters
|
|
1451
|
+
----------
|
|
1452
|
+
zone : str | int
|
|
1453
|
+
Zone name or id. Currently, only cell zones are supported.
|
|
1454
|
+
|
|
1455
|
+
Returns
|
|
1456
|
+
-------
|
|
1457
|
+
Mesh
|
|
1458
|
+
Mesh object containing nodes and elements.
|
|
1459
|
+
|
|
1460
|
+
Raises
|
|
1461
|
+
------
|
|
1462
|
+
ValueError
|
|
1463
|
+
If the zone is not found.
|
|
1464
|
+
NotImplementedError
|
|
1465
|
+
If a face zone is provided.
|
|
1466
|
+
"""
|
|
1467
|
+
zone_info = None
|
|
1468
|
+
for zone_info in self.get_zones_info():
|
|
1469
|
+
if zone_info.name == zone or zone_info._id == zone:
|
|
1470
|
+
break
|
|
1471
|
+
if zone_info is None:
|
|
1472
|
+
raise ValueError(f"Zone {zone} not found.")
|
|
1473
|
+
if zone_info.zone_type == ZoneType.FACE:
|
|
1474
|
+
raise NotImplementedError("Face zone mesh is not supported.")
|
|
1475
|
+
|
|
1476
|
+
# Mesh data is retrieved from the root domain in Fluent
|
|
1477
|
+
logger.info(f"Getting nodes data for zone {zone_info._id}")
|
|
1478
|
+
start_time = time.time()
|
|
1479
|
+
nodes_request = FieldDataProtoModule.GetSolverMeshNodesRequest(
|
|
1480
|
+
domain_id=ROOT_DOMAIN_ID, thread_id=zone_info._id
|
|
1481
|
+
)
|
|
1482
|
+
nested_nodes = self._service.get_solver_mesh_nodes(nodes_request)
|
|
1483
|
+
logger.info(f"Nodes data received in {time.time() - start_time} seconds")
|
|
1484
|
+
logger.info(f"Getting elements for zone {zone_info._id}")
|
|
1485
|
+
start_time = time.time()
|
|
1486
|
+
elements_request = FieldDataProtoModule.GetSolverMeshElementsRequest(
|
|
1487
|
+
domain_id=ROOT_DOMAIN_ID, thread_id=zone_info._id
|
|
1488
|
+
)
|
|
1489
|
+
elementss_pb = self._service.get_solver_mesh_elements(elements_request)
|
|
1490
|
+
logger.info(f"Elements data received in {time.time() - start_time} seconds")
|
|
1491
|
+
logger.info("Constructing nodes structure in PyFluent")
|
|
1492
|
+
start_time = time.time()
|
|
1493
|
+
node_count = sum(len(nodes) for nodes in nested_nodes)
|
|
1494
|
+
nodes = np.empty(node_count, dtype=Node)
|
|
1495
|
+
node_index_by_id = {}
|
|
1496
|
+
i = 0
|
|
1497
|
+
for nodes_pb in nested_nodes:
|
|
1498
|
+
for node_pb in nodes_pb:
|
|
1499
|
+
nodes[i] = Node(_id=node_pb.id, x=node_pb.x, y=node_pb.y, z=node_pb.z)
|
|
1500
|
+
node_index_by_id[node_pb.id] = i
|
|
1501
|
+
i += 1
|
|
1502
|
+
logger.info(
|
|
1503
|
+
f"Nodes structure constructed in {time.time() - start_time} seconds"
|
|
1504
|
+
)
|
|
1505
|
+
logger.info("Constructing elements structure in PyFluent")
|
|
1506
|
+
start_time = time.time()
|
|
1507
|
+
element_count = sum(len(elements) for elements in elementss_pb)
|
|
1508
|
+
elements = np.empty(element_count, dtype=Element)
|
|
1509
|
+
i = 0
|
|
1510
|
+
for elements_pb in elementss_pb:
|
|
1511
|
+
for element_pb in elements_pb:
|
|
1512
|
+
element_type = CellElementType(element_pb.element_type)
|
|
1513
|
+
if element_type == CellElementType.POLYHEDRON:
|
|
1514
|
+
facets = []
|
|
1515
|
+
for facet_pb in element_pb.facets:
|
|
1516
|
+
facet = Facet(
|
|
1517
|
+
node_indices=[node_index_by_id[id] for id in facet_pb.node]
|
|
1518
|
+
)
|
|
1519
|
+
facets.append(facet)
|
|
1520
|
+
element = Element(
|
|
1521
|
+
_id=element_pb.id,
|
|
1522
|
+
element_type=element_type,
|
|
1523
|
+
facets=facets,
|
|
1524
|
+
)
|
|
1525
|
+
else:
|
|
1526
|
+
element = Element(
|
|
1527
|
+
_id=element_pb.id,
|
|
1528
|
+
element_type=element_type,
|
|
1529
|
+
node_indices=[
|
|
1530
|
+
node_index_by_id[id] for id in element_pb.node_ids
|
|
1531
|
+
],
|
|
1532
|
+
)
|
|
1533
|
+
elements[i] = element
|
|
1534
|
+
i += 1
|
|
1535
|
+
logger.info(
|
|
1536
|
+
f"Elements structure constructed in {time.time() - start_time} seconds"
|
|
1537
|
+
)
|
|
1538
|
+
logger.info("Returning mesh")
|
|
1539
|
+
return Mesh(nodes=nodes, elements=elements)
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"""Interceptor classes to use with gRPC services."""
|
|
2
2
|
|
|
3
|
+
import builtins
|
|
3
4
|
import logging
|
|
4
5
|
import os
|
|
5
6
|
from typing import Any
|
|
6
7
|
|
|
7
8
|
from google.protobuf.json_format import MessageToDict
|
|
8
|
-
from google.protobuf.message import Message
|
|
9
|
+
from google.protobuf.message import DecodeError, Message
|
|
9
10
|
import grpc
|
|
10
11
|
|
|
11
12
|
from ansys.fluent.core.services.batch_ops import BatchOps
|
|
@@ -15,6 +16,10 @@ log_bytes_limit: int = int(os.getenv("PYFLUENT_GRPC_LOG_BYTES_LIMIT", 1000))
|
|
|
15
16
|
truncate_len: int = log_bytes_limit // 5
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
def _upper_snake_case_to_camel_case(name: str) -> str:
|
|
20
|
+
return "".join([word.capitalize() for word in name.split("_") if word])
|
|
21
|
+
|
|
22
|
+
|
|
18
23
|
def _truncate_grpc_str(message: Message) -> str:
|
|
19
24
|
message_bytes = message.ByteSize()
|
|
20
25
|
message_str = str(MessageToDict(message))
|
|
@@ -107,7 +112,28 @@ class GrpcErrorInterceptor(grpc.UnaryUnaryClientInterceptor):
|
|
|
107
112
|
response = continuation(client_call_details, request)
|
|
108
113
|
if response.exception() is not None and response.code() != grpc.StatusCode.OK:
|
|
109
114
|
ex = response.exception()
|
|
110
|
-
|
|
115
|
+
new_ex_cls = RuntimeError
|
|
116
|
+
try:
|
|
117
|
+
from google.rpc import error_details_pb2
|
|
118
|
+
from grpc_status import rpc_status
|
|
119
|
+
|
|
120
|
+
status = rpc_status.from_call(ex)
|
|
121
|
+
if status:
|
|
122
|
+
for detail in status.details:
|
|
123
|
+
if detail.Is(error_details_pb2.ErrorInfo.DESCRIPTOR):
|
|
124
|
+
info = error_details_pb2.ErrorInfo()
|
|
125
|
+
detail.Unpack(info)
|
|
126
|
+
if info.domain == "Python":
|
|
127
|
+
reason = info.reason
|
|
128
|
+
ex_cls_name = _upper_snake_case_to_camel_case(reason)
|
|
129
|
+
if hasattr(builtins, ex_cls_name):
|
|
130
|
+
cls = getattr(builtins, ex_cls_name)
|
|
131
|
+
if issubclass(cls, Exception):
|
|
132
|
+
new_ex_cls = cls
|
|
133
|
+
break
|
|
134
|
+
except DecodeError:
|
|
135
|
+
pass
|
|
136
|
+
new_ex = new_ex_cls(
|
|
111
137
|
ex.details() if isinstance(ex, grpc.RpcError) else str(ex)
|
|
112
138
|
)
|
|
113
139
|
new_ex.__context__ = ex
|
ansys/fluent/core/session.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from enum import Enum
|
|
4
4
|
import json
|
|
5
5
|
import logging
|
|
6
|
-
from typing import Any, Dict
|
|
6
|
+
from typing import Any, Callable, Dict
|
|
7
7
|
import warnings
|
|
8
8
|
import weakref
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@ from ansys.fluent.core.fluent_connection import FluentConnection
|
|
|
11
11
|
from ansys.fluent.core.journaling import Journal
|
|
12
12
|
from ansys.fluent.core.services import service_creator
|
|
13
13
|
from ansys.fluent.core.services.app_utilities import AppUtilitiesOld
|
|
14
|
-
from ansys.fluent.core.services.field_data import FieldDataService
|
|
14
|
+
from ansys.fluent.core.services.field_data import FieldDataService, ZoneInfo
|
|
15
15
|
from ansys.fluent.core.services.scheme_eval import SchemeEval
|
|
16
16
|
from ansys.fluent.core.streaming_services.datamodel_event_streaming import (
|
|
17
17
|
DatamodelEvents,
|
|
@@ -85,6 +85,7 @@ class BaseSession:
|
|
|
85
85
|
Close the Fluent connection and exit Fluent.
|
|
86
86
|
"""
|
|
87
87
|
|
|
88
|
+
# We are passing around an WeakMethod to avoid circular references
|
|
88
89
|
def __init__(
|
|
89
90
|
self,
|
|
90
91
|
fluent_connection: FluentConnection,
|
|
@@ -93,6 +94,7 @@ class BaseSession:
|
|
|
93
94
|
start_transcript: bool = True,
|
|
94
95
|
launcher_args: Dict[str, Any] | None = None,
|
|
95
96
|
event_type: Enum | None = None,
|
|
97
|
+
get_zones_info: weakref.WeakMethod[Callable[[], list[ZoneInfo]]] | None = None,
|
|
96
98
|
):
|
|
97
99
|
"""BaseSession.
|
|
98
100
|
|
|
@@ -120,6 +122,7 @@ class BaseSession:
|
|
|
120
122
|
scheme_eval,
|
|
121
123
|
file_transfer_service,
|
|
122
124
|
event_type,
|
|
125
|
+
get_zones_info,
|
|
123
126
|
)
|
|
124
127
|
|
|
125
128
|
def _build_from_fluent_connection(
|
|
@@ -128,6 +131,7 @@ class BaseSession:
|
|
|
128
131
|
scheme_eval: SchemeEval,
|
|
129
132
|
file_transfer_service: Any | None = None,
|
|
130
133
|
event_type=None,
|
|
134
|
+
get_zones_info: weakref.WeakMethod[Callable[[], list[ZoneInfo]]] | None = None,
|
|
131
135
|
):
|
|
132
136
|
"""Build a BaseSession object from fluent_connection object."""
|
|
133
137
|
self._fluent_connection = fluent_connection
|
|
@@ -205,6 +209,7 @@ class BaseSession:
|
|
|
205
209
|
self.field_info,
|
|
206
210
|
self._is_solution_data_valid,
|
|
207
211
|
_session.scheme_eval,
|
|
212
|
+
get_zones_info,
|
|
208
213
|
)
|
|
209
214
|
self.field_data_streaming = FieldDataStreaming(
|
|
210
215
|
_session._fluent_connection._id, _session._field_data_service
|
|
@@ -6,9 +6,12 @@ import logging
|
|
|
6
6
|
import threading
|
|
7
7
|
from typing import Any, Dict
|
|
8
8
|
import warnings
|
|
9
|
+
import weakref
|
|
9
10
|
|
|
11
|
+
from ansys.api.fluent.v0 import svar_pb2 as SvarProtoModule
|
|
10
12
|
import ansys.fluent.core as pyfluent
|
|
11
13
|
from ansys.fluent.core.services import SchemeEval, service_creator
|
|
14
|
+
from ansys.fluent.core.services.field_data import ZoneInfo, ZoneType
|
|
12
15
|
from ansys.fluent.core.services.reduction import ReductionService
|
|
13
16
|
from ansys.fluent.core.services.solution_variables import (
|
|
14
17
|
SolutionVariableData,
|
|
@@ -106,6 +109,7 @@ class Solver(BaseSession):
|
|
|
106
109
|
start_transcript=start_transcript,
|
|
107
110
|
launcher_args=launcher_args,
|
|
108
111
|
event_type=SolverEvent,
|
|
112
|
+
get_zones_info=weakref.WeakMethod(self._get_zones_info),
|
|
109
113
|
)
|
|
110
114
|
self._build_from_fluent_connection(fluent_connection, scheme_eval)
|
|
111
115
|
|
|
@@ -176,6 +180,23 @@ class Solver(BaseSession):
|
|
|
176
180
|
)
|
|
177
181
|
return self.fields.solution_variable_info
|
|
178
182
|
|
|
183
|
+
def _get_zones_info(self) -> list[ZoneInfo]:
|
|
184
|
+
zones_info = []
|
|
185
|
+
for (
|
|
186
|
+
zone_info
|
|
187
|
+
) in self.fields.solution_variable_info.get_zones_info()._zones_info.values():
|
|
188
|
+
zone_type = (
|
|
189
|
+
ZoneType.CELL
|
|
190
|
+
if zone_info.thread_type == SvarProtoModule.ThreadType.CELL_THREAD
|
|
191
|
+
else ZoneType.FACE
|
|
192
|
+
)
|
|
193
|
+
zones_info.append(
|
|
194
|
+
ZoneInfo(
|
|
195
|
+
_id=zone_info.zone_id, name=zone_info.name, zone_type=zone_type
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
return zones_info
|
|
199
|
+
|
|
179
200
|
@property
|
|
180
201
|
def reduction(self):
|
|
181
202
|
"""``Reduction`` handle."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2025 ANSYS, Inc. All rights reserved.
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|