ansys-systemcoupling-core 0.2.0__py3-none-any.whl → 0.3.0__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-systemcoupling-core might be problematic. Click here for more details.
- ansys/systemcoupling/core/__init__.py +2 -4
- ansys/systemcoupling/core/adaptor/api_23_2/_add_participant.py +70 -0
- ansys/systemcoupling/core/adaptor/api_23_2/_solve.py +13 -0
- ansys/systemcoupling/core/adaptor/api_23_2/add_participant.py +38 -2
- ansys/systemcoupling/core/adaptor/api_23_2/case_root.py +13 -13
- ansys/systemcoupling/core/adaptor/api_23_2/setup_root.py +55 -49
- ansys/systemcoupling/core/adaptor/api_23_2/solution_root.py +42 -36
- ansys/systemcoupling/core/adaptor/api_23_2/solve.py +1 -1
- ansys/systemcoupling/core/adaptor/api_24_1/_add_participant.py +70 -0
- ansys/systemcoupling/core/adaptor/api_24_1/_solve.py +13 -0
- ansys/systemcoupling/core/adaptor/api_24_1/abort.py +39 -0
- ansys/systemcoupling/core/adaptor/api_24_1/activate_hidden.py +46 -0
- ansys/systemcoupling/core/adaptor/api_24_1/add_data_transfer.py +190 -0
- ansys/systemcoupling/core/adaptor/api_24_1/add_data_transfer_by_display_names.py +191 -0
- ansys/systemcoupling/core/adaptor/api_24_1/add_expression_function.py +61 -0
- ansys/systemcoupling/core/adaptor/api_24_1/add_interface.py +77 -0
- ansys/systemcoupling/core/adaptor/api_24_1/add_interface_by_display_names.py +78 -0
- ansys/systemcoupling/core/adaptor/api_24_1/add_named_expression.py +42 -0
- ansys/systemcoupling/core/adaptor/api_24_1/add_participant.py +140 -0
- ansys/systemcoupling/core/adaptor/api_24_1/add_reference_frame.py +40 -0
- ansys/systemcoupling/core/adaptor/api_24_1/add_transformation.py +102 -0
- ansys/systemcoupling/core/adaptor/api_24_1/analysis_control.py +249 -0
- ansys/systemcoupling/core/adaptor/api_24_1/apip.py +33 -0
- ansys/systemcoupling/core/adaptor/api_24_1/ascii_output.py +44 -0
- ansys/systemcoupling/core/adaptor/api_24_1/attribute.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/attribute_child.py +54 -0
- ansys/systemcoupling/core/adaptor/api_24_1/automatic_alignment_options.py +46 -0
- ansys/systemcoupling/core/adaptor/api_24_1/available_ports.py +40 -0
- ansys/systemcoupling/core/adaptor/api_24_1/avoid_data_reconstruction.py +46 -0
- ansys/systemcoupling/core/adaptor/api_24_1/case_root.py +62 -0
- ansys/systemcoupling/core/adaptor/api_24_1/clear_state.py +16 -0
- ansys/systemcoupling/core/adaptor/api_24_1/coupling_interface.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/coupling_interface_child.py +42 -0
- ansys/systemcoupling/core/adaptor/api_24_1/coupling_participant.py +23 -0
- ansys/systemcoupling/core/adaptor/api_24_1/coupling_participant_child.py +230 -0
- ansys/systemcoupling/core/adaptor/api_24_1/create_restart_point.py +29 -0
- ansys/systemcoupling/core/adaptor/api_24_1/data_transfer.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/data_transfer_child.py +187 -0
- ansys/systemcoupling/core/adaptor/api_24_1/delete_snapshot.py +28 -0
- ansys/systemcoupling/core/adaptor/api_24_1/delete_transformation.py +42 -0
- ansys/systemcoupling/core/adaptor/api_24_1/dimensionality.py +96 -0
- ansys/systemcoupling/core/adaptor/api_24_1/execution_control.py +186 -0
- ansys/systemcoupling/core/adaptor/api_24_1/expression.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/expression_child.py +36 -0
- ansys/systemcoupling/core/adaptor/api_24_1/expression_function.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/expression_function_child.py +46 -0
- ansys/systemcoupling/core/adaptor/api_24_1/external_data_file.py +24 -0
- ansys/systemcoupling/core/adaptor/api_24_1/fluent_input.py +67 -0
- ansys/systemcoupling/core/adaptor/api_24_1/fmu_parameter.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/fmu_parameter_child.py +156 -0
- ansys/systemcoupling/core/adaptor/api_24_1/generate_input_file.py +41 -0
- ansys/systemcoupling/core/adaptor/api_24_1/get_execution_command.py +30 -0
- ansys/systemcoupling/core/adaptor/api_24_1/get_machines.py +13 -0
- ansys/systemcoupling/core/adaptor/api_24_1/get_region_names_for_participant.py +31 -0
- ansys/systemcoupling/core/adaptor/api_24_1/get_setup_summary.py +25 -0
- ansys/systemcoupling/core/adaptor/api_24_1/get_snapshots.py +14 -0
- ansys/systemcoupling/core/adaptor/api_24_1/get_status_messages.py +52 -0
- ansys/systemcoupling/core/adaptor/api_24_1/get_transformation.py +43 -0
- ansys/systemcoupling/core/adaptor/api_24_1/global_stabilization.py +143 -0
- ansys/systemcoupling/core/adaptor/api_24_1/has_input_file_changed.py +36 -0
- ansys/systemcoupling/core/adaptor/api_24_1/import_system_coupling_input_file.py +36 -0
- ansys/systemcoupling/core/adaptor/api_24_1/initialize.py +27 -0
- ansys/systemcoupling/core/adaptor/api_24_1/instancing.py +23 -0
- ansys/systemcoupling/core/adaptor/api_24_1/instancing_child.py +62 -0
- ansys/systemcoupling/core/adaptor/api_24_1/interrupt.py +39 -0
- ansys/systemcoupling/core/adaptor/api_24_1/library.py +37 -0
- ansys/systemcoupling/core/adaptor/api_24_1/live_visualization.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/live_visualization_child.py +72 -0
- ansys/systemcoupling/core/adaptor/api_24_1/mapping_control.py +229 -0
- ansys/systemcoupling/core/adaptor/api_24_1/open.py +102 -0
- ansys/systemcoupling/core/adaptor/api_24_1/open_results_in_en_sight.py +56 -0
- ansys/systemcoupling/core/adaptor/api_24_1/open_snapshot.py +37 -0
- ansys/systemcoupling/core/adaptor/api_24_1/output_control.py +134 -0
- ansys/systemcoupling/core/adaptor/api_24_1/parameter.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/parameter_child.py +64 -0
- ansys/systemcoupling/core/adaptor/api_24_1/partition_participants.py +138 -0
- ansys/systemcoupling/core/adaptor/api_24_1/reference_frame.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/reference_frame_child.py +71 -0
- ansys/systemcoupling/core/adaptor/api_24_1/region.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/region_child.py +72 -0
- ansys/systemcoupling/core/adaptor/api_24_1/reload_expression_function_modules.py +14 -0
- ansys/systemcoupling/core/adaptor/api_24_1/results.py +89 -0
- ansys/systemcoupling/core/adaptor/api_24_1/save.py +51 -0
- ansys/systemcoupling/core/adaptor/api_24_1/save_snapshot.py +54 -0
- ansys/systemcoupling/core/adaptor/api_24_1/setup_root.py +195 -0
- ansys/systemcoupling/core/adaptor/api_24_1/shutdown.py +25 -0
- ansys/systemcoupling/core/adaptor/api_24_1/side.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/side_child.py +56 -0
- ansys/systemcoupling/core/adaptor/api_24_1/solution_control.py +103 -0
- ansys/systemcoupling/core/adaptor/api_24_1/solution_root.py +110 -0
- ansys/systemcoupling/core/adaptor/api_24_1/solve.py +30 -0
- ansys/systemcoupling/core/adaptor/api_24_1/stabilization.py +157 -0
- ansys/systemcoupling/core/adaptor/api_24_1/start_participants.py +47 -0
- ansys/systemcoupling/core/adaptor/api_24_1/step.py +57 -0
- ansys/systemcoupling/core/adaptor/api_24_1/transformation.py +21 -0
- ansys/systemcoupling/core/adaptor/api_24_1/transformation_child.py +62 -0
- ansys/systemcoupling/core/adaptor/api_24_1/type.py +38 -0
- ansys/systemcoupling/core/adaptor/api_24_1/unmapped_value_options.py +158 -0
- ansys/systemcoupling/core/adaptor/api_24_1/update_control.py +44 -0
- ansys/systemcoupling/core/adaptor/api_24_1/update_participant.py +61 -0
- ansys/systemcoupling/core/adaptor/api_24_1/variable.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_1/variable_child.py +232 -0
- ansys/systemcoupling/core/adaptor/api_24_1/write_csv_chart_files.py +21 -0
- ansys/systemcoupling/core/adaptor/api_24_1/write_ensight.py +46 -0
- ansys/systemcoupling/core/adaptor/impl/get_syc_version.py +35 -0
- ansys/systemcoupling/core/adaptor/impl/injected_commands.py +97 -5
- ansys/systemcoupling/core/adaptor/impl/root_source.py +2 -0
- ansys/systemcoupling/core/adaptor/impl/static_info.py +69 -41
- ansys/systemcoupling/core/adaptor/impl/syc_proxy.py +1 -1
- ansys/systemcoupling/core/adaptor/impl/types.py +12 -0
- ansys/systemcoupling/core/client/syc_container.py +2 -0
- ansys/systemcoupling/core/participant/manager.py +198 -0
- ansys/systemcoupling/core/participant/protocol.py +51 -0
- ansys/systemcoupling/core/session.py +7 -1
- ansys/systemcoupling/core/syc_version.py +26 -2
- {ansys_systemcoupling_core-0.2.0.dist-info → ansys_systemcoupling_core-0.3.0.dist-info}/METADATA +9 -9
- ansys_systemcoupling_core-0.3.0.dist-info/RECORD +230 -0
- ansys_systemcoupling_core-0.2.0.dist-info/RECORD +0 -129
- /ansys/systemcoupling/core/adaptor/{api_23_2 → api_24_1}/open_results_in_ensight.py +0 -0
- {ansys_systemcoupling_core-0.2.0.dist-info → ansys_systemcoupling_core-0.3.0.dist-info}/LICENSE +0 -0
- {ansys_systemcoupling_core-0.2.0.dist-info → ansys_systemcoupling_core-0.3.0.dist-info}/WHEEL +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from copy import deepcopy
|
|
2
|
-
from typing import Tuple
|
|
2
|
+
from typing import Dict, List, Tuple
|
|
3
3
|
|
|
4
4
|
from ansys.systemcoupling.core.adaptor.impl.injected_commands import (
|
|
5
5
|
get_injected_cmd_data,
|
|
6
6
|
)
|
|
7
|
-
from ansys.systemcoupling.core.syc_version import SYC_VERSION_DOT
|
|
8
7
|
from ansys.systemcoupling.core.util.name_util import to_python_name
|
|
9
8
|
|
|
10
9
|
|
|
@@ -289,22 +288,85 @@ def get_extended_cmd_metadata(api) -> list:
|
|
|
289
288
|
Object providing access to the System Coupling *native API*.
|
|
290
289
|
"""
|
|
291
290
|
|
|
291
|
+
def find_item_by_name(items: List[Dict], name: str) -> dict:
|
|
292
|
+
for item in items:
|
|
293
|
+
if item["name"] == name:
|
|
294
|
+
return item
|
|
295
|
+
raise RuntimeError(f"Did not find dict element of list with 'name' == {name}")
|
|
296
|
+
|
|
292
297
|
def merge_data(target: list, source: list) -> None:
|
|
293
298
|
target_names = set(d["name"] for d in target)
|
|
294
299
|
source_names = set(d["name"] for d in source)
|
|
295
300
|
new_names = source_names - target_names
|
|
296
301
|
common_names = source_names & target_names
|
|
297
302
|
|
|
303
|
+
# Injected commands can either be completely new commands injected into
|
|
304
|
+
# the set of available commands, or can be "overrides" that replace the
|
|
305
|
+
# SyC command that would have been generated. Occasionally, we still
|
|
306
|
+
# want to generate the command that is being replaced so that we can
|
|
307
|
+
# call it internally. This is identified by a "pysyc_internal_name"
|
|
308
|
+
# field. In this case we split the command data into an injected command
|
|
309
|
+
# and a "normal" command but with the internal name as the pysyc name
|
|
310
|
+
# for the latter.
|
|
311
|
+
|
|
312
|
+
special_injected_commands = [
|
|
313
|
+
name
|
|
314
|
+
for name in common_names
|
|
315
|
+
if "pysyc_internal_name" in find_item_by_name(source, name)
|
|
316
|
+
]
|
|
317
|
+
|
|
318
|
+
for name in special_injected_commands:
|
|
319
|
+
src_item = find_item_by_name(source, name)
|
|
320
|
+
tgt_item = find_item_by_name(target, name)
|
|
321
|
+
|
|
322
|
+
# Target item becomes a "normally" exposed SyC command except that
|
|
323
|
+
# it is "internal" on the PySyC side - only intended for internal
|
|
324
|
+
# PySyC use. It will be given a special internal name rather than
|
|
325
|
+
# the one derived from its SyC name. It will also have its doc
|
|
326
|
+
# info removed.
|
|
327
|
+
|
|
328
|
+
# - Take a copy of tgt before we remove doc.
|
|
329
|
+
tgt_copy = deepcopy(tgt_item)
|
|
330
|
+
if "doc" in tgt_item:
|
|
331
|
+
tgt_item["doc"] = "For internal use only."
|
|
332
|
+
|
|
333
|
+
for arg in tgt_item.get("args", []):
|
|
334
|
+
_, arg_info = arg
|
|
335
|
+
if "doc" in arg_info:
|
|
336
|
+
arg_info["doc"] = "..."
|
|
337
|
+
|
|
338
|
+
# - Name for PySyC exposure is the "pysyc_internal_name" from the source item
|
|
339
|
+
tgt_item["pyname"] = src_item["pysyc_internal_name"]
|
|
340
|
+
|
|
341
|
+
# Source item becomes a normal injected command. It is processed like the
|
|
342
|
+
# items in the common_names later but has special treatment for its
|
|
343
|
+
# doc and arguments. That is done here, so it will be removed from
|
|
344
|
+
# common_names and added to new_names.
|
|
345
|
+
for k, v in tgt_copy.items():
|
|
346
|
+
if k in ("essentialArgNames", "optionalArgNames", "args"):
|
|
347
|
+
src_item[k] = src_item.get(f"{k}_extra", []) + v
|
|
348
|
+
elif k == "doc":
|
|
349
|
+
prefix = src_item.get(f"{k}_prefix", "")
|
|
350
|
+
if prefix:
|
|
351
|
+
prefix += "\n\n"
|
|
352
|
+
suffix = src_item.get(f"{k}_suffix", "")
|
|
353
|
+
if suffix:
|
|
354
|
+
suffix = "\n" + suffix
|
|
355
|
+
src_item[k] = prefix + v + suffix
|
|
356
|
+
else:
|
|
357
|
+
src_item[k] = v
|
|
358
|
+
|
|
359
|
+
src_item["name"] = src_item["pyname"]
|
|
360
|
+
|
|
361
|
+
common_names.remove(name)
|
|
362
|
+
new_names.add(src_item["name"])
|
|
363
|
+
|
|
298
364
|
for src_item in source:
|
|
299
365
|
name = src_item["name"]
|
|
300
366
|
if name in new_names:
|
|
301
367
|
target.append(src_item)
|
|
302
368
|
elif name in common_names:
|
|
303
|
-
tgt_item =
|
|
304
|
-
for titem in target:
|
|
305
|
-
if titem["name"] == name:
|
|
306
|
-
tgt_item = titem
|
|
307
|
-
break
|
|
369
|
+
tgt_item = find_item_by_name(target, name)
|
|
308
370
|
|
|
309
371
|
# Single-level merge of source item dictionary into
|
|
310
372
|
# target item dictionary. If any aspect of the arguments
|
|
@@ -317,37 +379,3 @@ def get_extended_cmd_metadata(api) -> list:
|
|
|
317
379
|
injected_data = get_injected_cmd_data()
|
|
318
380
|
merge_data(cmd_metadata, injected_data)
|
|
319
381
|
return cmd_metadata
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
def get_syc_version(api) -> str:
|
|
323
|
-
"""Get the System Coupling version.
|
|
324
|
-
|
|
325
|
-
The version is returned in a string like ``"23.2"``.
|
|
326
|
-
|
|
327
|
-
System Coupling versions earlier than 23.2 (2023 R2) do not expose
|
|
328
|
-
the ``GetVersion`` query. Because the first version of the server
|
|
329
|
-
that PySystemCoupling is able to connect to is 23.1 (2023 R1), the
|
|
330
|
-
version is assumed to be 23.1 if no version query exists.
|
|
331
|
-
|
|
332
|
-
Parameters
|
|
333
|
-
----------
|
|
334
|
-
api : NativeApi
|
|
335
|
-
Object providing access to the System Coupling *native API* .
|
|
336
|
-
"""
|
|
337
|
-
|
|
338
|
-
def clean_version_string(version_in: str) -> str:
|
|
339
|
-
year, _, release = version_in.partition(" ")
|
|
340
|
-
if len(year) == 4 and year.startswith("20") and release.startswith("R"):
|
|
341
|
-
try:
|
|
342
|
-
year = int(year[2:])
|
|
343
|
-
release = int(release[1:])
|
|
344
|
-
return f"{year}.{release}"
|
|
345
|
-
except:
|
|
346
|
-
pass
|
|
347
|
-
raise RuntimeError(
|
|
348
|
-
f"Version string {version_in} has invalid format (expect '20yy Rn')."
|
|
349
|
-
)
|
|
350
|
-
|
|
351
|
-
cmds = api.GetCommandAndQueryMetadata()
|
|
352
|
-
exists = any(cmd["name"] == "GetVersion" for cmd in cmds)
|
|
353
|
-
return clean_version_string(api.GetVersion()) if exists else SYC_VERSION_DOT
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
from ansys.systemcoupling.core.adaptor.impl.get_syc_version import get_syc_version
|
|
1
2
|
from ansys.systemcoupling.core.adaptor.impl.static_info import (
|
|
2
3
|
get_dm_metadata,
|
|
3
4
|
get_extended_cmd_metadata,
|
|
4
|
-
get_syc_version,
|
|
5
5
|
make_cmdonly_metadata,
|
|
6
6
|
make_combined_metadata,
|
|
7
7
|
)
|
|
@@ -29,6 +29,7 @@ import sys
|
|
|
29
29
|
from typing import Dict, Generic, List, NewType, Tuple, TypeVar, Union
|
|
30
30
|
import weakref
|
|
31
31
|
|
|
32
|
+
from ansys.systemcoupling.core.participant.protocol import ParticipantProtocol
|
|
32
33
|
from ansys.systemcoupling.core.util import name_util
|
|
33
34
|
|
|
34
35
|
# Type hints
|
|
@@ -246,6 +247,17 @@ class SettingsBase(Base, Generic[StateT]):
|
|
|
246
247
|
out.flush()
|
|
247
248
|
|
|
248
249
|
|
|
250
|
+
# TODO: this doesn't make much sense as a "setting" but is needed to
|
|
251
|
+
# make the special form of add_participant work. Ideally we want to move
|
|
252
|
+
# away from treating command arguments as "settings" but that needs to be
|
|
253
|
+
# handled as a separate task.
|
|
254
|
+
class ParticipantSession(SettingsBase[ParticipantProtocol]):
|
|
255
|
+
"""Object conforming to the ``ParticipantProtocol`` runtime protocol
|
|
256
|
+
for participant session objects."""
|
|
257
|
+
|
|
258
|
+
_state_type = ParticipantProtocol
|
|
259
|
+
|
|
260
|
+
|
|
249
261
|
class Integer(SettingsBase[int]):
|
|
250
262
|
"""Provides an ``Integer`` object that represents an integer value setting."""
|
|
251
263
|
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
from typing import Dict, List, Tuple
|
|
3
|
+
|
|
4
|
+
from ansys.systemcoupling.core.participant.protocol import ParticipantProtocol
|
|
5
|
+
from ansys.systemcoupling.core.util.logging import LOG
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ParticipantManager:
|
|
9
|
+
"""Manages a System Coupling solution in which the participant solvers are
|
|
10
|
+
provided as "session" objects from other PyAnsys APIs.
|
|
11
|
+
|
|
12
|
+
These objects must conform (in a Python "duck typing" sense) to the
|
|
13
|
+
``ParticipantProtocol`` protocol.
|
|
14
|
+
|
|
15
|
+
The ParticipantManager will play a role whenever participants are added to the
|
|
16
|
+
analysis using the ``add_participant`` command with ``participant_session`` being the one
|
|
17
|
+
and only argument.
|
|
18
|
+
|
|
19
|
+
In this case, the manager creates ``coupling_participant`` data model objects
|
|
20
|
+
based on queries to the session object. It will also store the session object
|
|
21
|
+
for later use if a solve is initiated.
|
|
22
|
+
|
|
23
|
+
If ``solve`` is called on the manager, it will coordinate both the connection of the
|
|
24
|
+
participants to System Coupling and, subsequently, the invocation of their solve
|
|
25
|
+
operations. In standard System Coupling terms, the solves that are initiated from
|
|
26
|
+
the "PyAnsys" environment will be regarded by the System Coupling solver as
|
|
27
|
+
"externally managed".
|
|
28
|
+
|
|
29
|
+
.. warning:
|
|
30
|
+
This facility should be regarded as sub-Beta level.
|
|
31
|
+
It is likely to be subject to further development, and has fairly limited utility
|
|
32
|
+
until more participant types support the protocol.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, syc_session):
|
|
36
|
+
self.__participants: Dict[str, ParticipantProtocol] = {}
|
|
37
|
+
self.__syc_session = syc_session
|
|
38
|
+
self.__connection_lock = threading.Lock()
|
|
39
|
+
self.clear()
|
|
40
|
+
|
|
41
|
+
def clear(self):
|
|
42
|
+
self.__participants: Dict[str, ParticipantProtocol] = {}
|
|
43
|
+
self.__n_connected = 0
|
|
44
|
+
self.__solve_exception = None
|
|
45
|
+
|
|
46
|
+
def add_participant(self, participant_session: ParticipantProtocol) -> str:
|
|
47
|
+
participant_name = (
|
|
48
|
+
f"{participant_session.participant_type}-{len(self.__participants) + 1}"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
setup = self.__syc_session.setup
|
|
52
|
+
|
|
53
|
+
part_state = setup.coupling_participant.create(participant_name)
|
|
54
|
+
part_state.participant_type = participant_session.participant_type
|
|
55
|
+
part_state.participant_analysis_type = participant_session.get_analysis_type()
|
|
56
|
+
part_state.execution_control.option = "ExternallyManaged"
|
|
57
|
+
|
|
58
|
+
setup.analysis_control.analysis_type = (
|
|
59
|
+
participant_session.get_analysis_type()
|
|
60
|
+
) # TODO: this logic isn't quite right, maybe delegate to controller
|
|
61
|
+
|
|
62
|
+
for variable in participant_session.get_variables():
|
|
63
|
+
part_state.variable.create(variable.name).set_state(
|
|
64
|
+
{
|
|
65
|
+
"tensor_type": variable.tensor_type,
|
|
66
|
+
"is_extensive": variable.is_extensive,
|
|
67
|
+
"location": variable.location,
|
|
68
|
+
"quantity_type": variable.quantity_type,
|
|
69
|
+
"participant_display_name": variable.display_name,
|
|
70
|
+
"display_name": variable.display_name.replace(
|
|
71
|
+
" ", "_"
|
|
72
|
+
), # TODO: delegate this to controller
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
for region in participant_session.get_regions():
|
|
77
|
+
part_state.region.create(region.name).set_state(
|
|
78
|
+
{
|
|
79
|
+
"topology": region.topology,
|
|
80
|
+
"input_variables": region.input_variables,
|
|
81
|
+
"output_variables": region.output_variables,
|
|
82
|
+
"display_name": region.display_name,
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
self.__participants[participant_name] = participant_session
|
|
87
|
+
return participant_name
|
|
88
|
+
|
|
89
|
+
def solve(self):
|
|
90
|
+
self.__solve_exception = None
|
|
91
|
+
self._clear_n_connected()
|
|
92
|
+
|
|
93
|
+
if len(self.__participants) == 0:
|
|
94
|
+
# Fall back to normal solve
|
|
95
|
+
self.__syc_session.solution._solve()
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
# TODO : if we *don't* check for validation error before solve, and
|
|
99
|
+
# leave it for the SyC Solve() to find them, we see participants hang
|
|
100
|
+
# during connection. (This is independent of PySyC.)
|
|
101
|
+
|
|
102
|
+
if any(
|
|
103
|
+
msg
|
|
104
|
+
for msg in self.__syc_session.setup.get_status_messages()
|
|
105
|
+
if msg["level"] == "Error"
|
|
106
|
+
):
|
|
107
|
+
raise RuntimeError(
|
|
108
|
+
"The setup data contains errors. solve() cannot proceed until these are fixed."
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
syc_solve_thread = threading.Thread(target=self._syc_solve)
|
|
112
|
+
try:
|
|
113
|
+
self._do_solve(syc_solve_thread)
|
|
114
|
+
finally:
|
|
115
|
+
syc_solve_thread.join()
|
|
116
|
+
LOG.info("SyC solve joined.")
|
|
117
|
+
|
|
118
|
+
if self.__solve_exception:
|
|
119
|
+
raise self.__solve_exception
|
|
120
|
+
|
|
121
|
+
def _do_solve(self, syc_solve_thread):
|
|
122
|
+
connection_threads = [
|
|
123
|
+
threading.Thread(
|
|
124
|
+
target=lambda host_port, name=name, part=participant: self._participant_connect(
|
|
125
|
+
name, host_port, part
|
|
126
|
+
),
|
|
127
|
+
args=(self._get_host_and_port(name), name, participant),
|
|
128
|
+
)
|
|
129
|
+
for name, participant in self.__participants.items()
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
LOG.info("Starting SyC solve thread...")
|
|
133
|
+
syc_solve_thread.start()
|
|
134
|
+
LOG.info("Waiting for participants to connect.")
|
|
135
|
+
_start_threads(connection_threads)
|
|
136
|
+
_join_threads(connection_threads)
|
|
137
|
+
connection_threads.clear()
|
|
138
|
+
if self._get_n_connected() < len(self.__participants):
|
|
139
|
+
LOG.error("Some participants were unable to connect to System Coupling.")
|
|
140
|
+
self.__syc_session.solution.abort()
|
|
141
|
+
else:
|
|
142
|
+
LOG.info("Participants connected.")
|
|
143
|
+
|
|
144
|
+
LOG.info("Starting participant solve threads.")
|
|
145
|
+
partsolve_threads = [
|
|
146
|
+
threading.Thread(target=participant.solve)
|
|
147
|
+
for participant in self.__participants.values()
|
|
148
|
+
]
|
|
149
|
+
_start_threads(partsolve_threads)
|
|
150
|
+
|
|
151
|
+
LOG.info("Waiting for all solve threads to join.")
|
|
152
|
+
_join_threads(partsolve_threads)
|
|
153
|
+
LOG.info("All participant solve threads joined.")
|
|
154
|
+
|
|
155
|
+
def _clear_n_connected(self) -> None:
|
|
156
|
+
with self.__connection_lock:
|
|
157
|
+
self.__n_connected = 0
|
|
158
|
+
|
|
159
|
+
def _get_n_connected(self) -> int:
|
|
160
|
+
with self.__connection_lock:
|
|
161
|
+
return self.__n_connected
|
|
162
|
+
|
|
163
|
+
def _increment_n_connected(self) -> None:
|
|
164
|
+
with self.__connection_lock:
|
|
165
|
+
self.__n_connected += 1
|
|
166
|
+
|
|
167
|
+
def _get_host_and_port(self, participant_name: str) -> Tuple[str, int]:
|
|
168
|
+
port, host = self.__syc_session._native_api.GetServerInfo()
|
|
169
|
+
return host, port
|
|
170
|
+
|
|
171
|
+
def _participant_connect(
|
|
172
|
+
self, name: str, host_port: Tuple[str, int], participant: ParticipantProtocol
|
|
173
|
+
) -> None:
|
|
174
|
+
try:
|
|
175
|
+
participant.connect(*host_port, name)
|
|
176
|
+
self._increment_n_connected()
|
|
177
|
+
except Exception as e:
|
|
178
|
+
LOG.error(f"Participant {name} failed to connect. Exception: {e}")
|
|
179
|
+
|
|
180
|
+
def _syc_solve(self):
|
|
181
|
+
try:
|
|
182
|
+
# We use `syc_session.solution._solve` here as it is
|
|
183
|
+
# the lower level solve command. `sys_session.solution.solve`
|
|
184
|
+
# would bring us recursively back into *this* function
|
|
185
|
+
self.__syc_session.solution._solve()
|
|
186
|
+
except Exception as e:
|
|
187
|
+
self.__solve_exception = e
|
|
188
|
+
LOG.error(f"Solve terminated with exception: {e}.")
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _start_threads(threads: List[threading.Thread]) -> None:
|
|
192
|
+
for thread in threads:
|
|
193
|
+
thread.start()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _join_threads(threads: List[threading.Thread]) -> None:
|
|
197
|
+
for thread in threads:
|
|
198
|
+
thread.join()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import List, Protocol
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class Variable(Protocol):
|
|
7
|
+
name: str
|
|
8
|
+
display_name: str
|
|
9
|
+
tensor_type: str
|
|
10
|
+
is_extensive: bool
|
|
11
|
+
location: str
|
|
12
|
+
quantity_type: str
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class Region(Protocol):
|
|
17
|
+
name: str
|
|
18
|
+
display_name: str
|
|
19
|
+
topology: str
|
|
20
|
+
input_variables: List[str]
|
|
21
|
+
output_variables: List[str]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ParticipantProtocol(Protocol):
|
|
25
|
+
"""Protocol class to which PyAnsys sessions that are added to a PySystemCoupling
|
|
26
|
+
session must conform."""
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def participant_type(self) -> str:
|
|
30
|
+
"""Type of participant."""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
def get_variables(self) -> List[Variable]:
|
|
34
|
+
"""List of variables that can be transferred from the participant."""
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
def get_regions(self) -> List[Region]:
|
|
38
|
+
"""List of regions on which data transfers can occur."""
|
|
39
|
+
...
|
|
40
|
+
|
|
41
|
+
def get_analysis_type(self) -> str:
|
|
42
|
+
"""The type of the analysis - "Steady" or "Transient"."""
|
|
43
|
+
...
|
|
44
|
+
|
|
45
|
+
def connect(self, host: str, port: int, name: str) -> None:
|
|
46
|
+
"""Establish connection between the participant solver and System Coupling."""
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
def solve(self) -> None:
|
|
50
|
+
"""Run the participant's solve operation."""
|
|
51
|
+
...
|
|
@@ -8,6 +8,7 @@ from ansys.systemcoupling.core.adaptor.impl.injected_commands import (
|
|
|
8
8
|
from ansys.systemcoupling.core.adaptor.impl.root_source import get_root
|
|
9
9
|
from ansys.systemcoupling.core.adaptor.impl.syc_proxy import SycProxy
|
|
10
10
|
from ansys.systemcoupling.core.native_api import NativeApi
|
|
11
|
+
from ansys.systemcoupling.core.participant.manager import ParticipantManager
|
|
11
12
|
|
|
12
13
|
if os.environ.get("PYSYC_DOC_BUILD_VERSION"):
|
|
13
14
|
# It is useful to import explicit types while building doc as it
|
|
@@ -60,6 +61,7 @@ class Session:
|
|
|
60
61
|
self.__rpc = rpc
|
|
61
62
|
self.__native_api = None
|
|
62
63
|
self.__syc_version = None
|
|
64
|
+
self.__part_mgr = ParticipantManager(self)
|
|
63
65
|
|
|
64
66
|
def exit(self) -> None:
|
|
65
67
|
"""Close the System Coupling server instance.
|
|
@@ -152,7 +154,11 @@ class Session:
|
|
|
152
154
|
version = sycproxy.get_version()
|
|
153
155
|
self.__syc_version = version.replace(".", "_")
|
|
154
156
|
root = get_root(sycproxy, category=category, version=self.__syc_version)
|
|
155
|
-
sycproxy.set_injected_commands(
|
|
157
|
+
sycproxy.set_injected_commands(
|
|
158
|
+
get_injected_cmd_map(
|
|
159
|
+
self.__syc_version, category, root, self.__part_mgr, self.__rpc
|
|
160
|
+
)
|
|
161
|
+
)
|
|
156
162
|
return (root, sycproxy)
|
|
157
163
|
|
|
158
164
|
@property
|
|
@@ -2,8 +2,8 @@ from typing import Tuple
|
|
|
2
2
|
|
|
3
3
|
# Define constants relating to the default/current version of System Coupling
|
|
4
4
|
|
|
5
|
-
SYC_MAJOR_VERSION =
|
|
6
|
-
SYC_MINOR_VERSION =
|
|
5
|
+
SYC_MAJOR_VERSION = 24
|
|
6
|
+
SYC_MINOR_VERSION = 1
|
|
7
7
|
|
|
8
8
|
SYC_VERSION_CONCAT = f"{SYC_MAJOR_VERSION}{SYC_MINOR_VERSION}"
|
|
9
9
|
SYC_VERSION_DOT = f"{SYC_MAJOR_VERSION}.{SYC_MINOR_VERSION}"
|
|
@@ -56,3 +56,27 @@ def normalize_version(version: str) -> Tuple[int, int]:
|
|
|
56
56
|
return process_major_minor(version[0:2], version[2])
|
|
57
57
|
else:
|
|
58
58
|
raise_error()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def compare_versions(version_a: str, version_b: str) -> int:
|
|
62
|
+
"""Compares two version strings that are in any form that can be parsed by
|
|
63
|
+
``normalize_version``.
|
|
64
|
+
|
|
65
|
+
Returns < 0 if ``version_a`` is an earlier version than ``version_b``, 0
|
|
66
|
+
if they are the same version, and > 0 if ``version_a`` is a later version
|
|
67
|
+
than ``version_b``.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
version_a : str
|
|
72
|
+
The first version string to compare.
|
|
73
|
+
version_b: str
|
|
74
|
+
The second version string to compare.
|
|
75
|
+
"""
|
|
76
|
+
va_maj, va_min = normalize_version(version_a)
|
|
77
|
+
vb_maj, vb_min = normalize_version(version_b)
|
|
78
|
+
|
|
79
|
+
if va_maj == vb_maj:
|
|
80
|
+
return va_min - vb_min
|
|
81
|
+
else:
|
|
82
|
+
return va_maj - vb_maj
|
{ansys_systemcoupling_core-0.2.0.dist-info → ansys_systemcoupling_core-0.3.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ansys-systemcoupling-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A Python wrapper for Ansys System Coupling.
|
|
5
5
|
Author-email: "ANSYS, Inc." <pyansys.support@ansys.com>
|
|
6
6
|
Maintainer-email: PyAnsys developers <pyansys.maintainers@ansys.com>
|
|
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
20
|
Requires-Dist: ansys-api-systemcoupling==0.1.0
|
|
21
21
|
Requires-Dist: grpcio>=1.30.0
|
|
22
|
-
Requires-Dist: grpcio-status>=1.30.0,<1.
|
|
22
|
+
Requires-Dist: grpcio-status>=1.30.0,<1.58.1
|
|
23
23
|
Requires-Dist: googleapis-common-protos>=1.50.0
|
|
24
24
|
Requires-Dist: protobuf>=3.20.1,<4.0.0
|
|
25
25
|
Requires-Dist: psutil>=5.7.0
|
|
@@ -29,24 +29,24 @@ Requires-Dist: importlib-metadata>=4.0
|
|
|
29
29
|
Requires-Dist: build ; extra == "build"
|
|
30
30
|
Requires-Dist: black==23.7.0 ; extra == "classesgen"
|
|
31
31
|
Requires-Dist: isort==5.12.0 ; extra == "classesgen"
|
|
32
|
-
Requires-Dist: ansys-sphinx-theme==0.
|
|
32
|
+
Requires-Dist: ansys-sphinx-theme==0.11.2 ; extra == "doc"
|
|
33
33
|
Requires-Dist: jupyter_sphinx==0.4.0 ; extra == "doc"
|
|
34
34
|
Requires-Dist: matplotlib ; extra == "doc"
|
|
35
35
|
Requires-Dist: numpydoc==1.5.0 ; extra == "doc"
|
|
36
36
|
Requires-Dist: pypandoc==1.11 ; extra == "doc"
|
|
37
37
|
Requires-Dist: pytest-sphinx==0.5.0 ; extra == "doc"
|
|
38
|
-
Requires-Dist: Sphinx==7.
|
|
38
|
+
Requires-Dist: Sphinx==7.2.6 ; extra == "doc"
|
|
39
39
|
Requires-Dist: sphinx-autobuild==2021.3.14 ; extra == "doc"
|
|
40
|
-
Requires-Dist: sphinx-autodoc-typehints==1.
|
|
40
|
+
Requires-Dist: sphinx-autodoc-typehints==1.24.0 ; extra == "doc"
|
|
41
41
|
Requires-Dist: sphinx-copybutton==0.5.2 ; extra == "doc"
|
|
42
|
-
Requires-Dist: sphinx-gallery==0.
|
|
43
|
-
Requires-Dist: sphinx-notfound-page==0.
|
|
44
|
-
Requires-Dist: sphinxcontrib-websupport==1.2.
|
|
42
|
+
Requires-Dist: sphinx-gallery==0.14.0 ; extra == "doc"
|
|
43
|
+
Requires-Dist: sphinx-notfound-page==1.0.0 ; extra == "doc"
|
|
44
|
+
Requires-Dist: sphinxcontrib-websupport==1.2.6 ; extra == "doc"
|
|
45
45
|
Requires-Dist: sphinxemoji==0.2.0 ; extra == "doc"
|
|
46
46
|
Requires-Dist: ansys-fluent-core ; extra == "doc"
|
|
47
47
|
Requires-Dist: ansys-dpf-core ; extra == "doc"
|
|
48
48
|
Requires-Dist: codespell==2.2.5 ; extra == "style"
|
|
49
|
-
Requires-Dist: flake8==6.
|
|
49
|
+
Requires-Dist: flake8==6.1.0 ; extra == "style"
|
|
50
50
|
Requires-Dist: pytest ; extra == "tests"
|
|
51
51
|
Requires-Dist: pytest-cov ; extra == "tests"
|
|
52
52
|
Requires-Dist: psutil>=5.7.0 ; extra == "tests"
|