ansys-systemcoupling-core 0.4.1__py3-none-any.whl → 0.6__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 +11 -5
- ansys/systemcoupling/core/adaptor/api_23_1/_clear_state.py +13 -0
- ansys/systemcoupling/core/adaptor/api_23_1/case_root.py +7 -1
- ansys/systemcoupling/core/adaptor/api_23_1/clear_state.py +4 -2
- ansys/systemcoupling/core/adaptor/api_23_1/show_plot.py +75 -0
- ansys/systemcoupling/core/adaptor/api_23_1/solution_root.py +7 -1
- ansys/systemcoupling/core/adaptor/api_23_2/_clear_state.py +13 -0
- ansys/systemcoupling/core/adaptor/api_23_2/case_root.py +7 -1
- ansys/systemcoupling/core/adaptor/api_23_2/clear_state.py +4 -2
- ansys/systemcoupling/core/adaptor/api_23_2/show_plot.py +75 -0
- ansys/systemcoupling/core/adaptor/api_23_2/solution_root.py +7 -1
- ansys/systemcoupling/core/adaptor/api_24_1/_clear_state.py +13 -0
- ansys/systemcoupling/core/adaptor/api_24_1/case_root.py +7 -1
- ansys/systemcoupling/core/adaptor/api_24_1/clear_state.py +4 -2
- ansys/systemcoupling/core/adaptor/api_24_1/show_plot.py +75 -0
- ansys/systemcoupling/core/adaptor/api_24_1/solution_root.py +7 -1
- ansys/systemcoupling/core/adaptor/api_24_2/_add_participant.py +80 -0
- ansys/systemcoupling/core/adaptor/api_24_2/_clear_state.py +13 -0
- ansys/systemcoupling/core/adaptor/api_24_2/_solve.py +13 -0
- ansys/systemcoupling/core/adaptor/api_24_2/abort.py +39 -0
- ansys/systemcoupling/core/adaptor/api_24_2/activate_hidden.py +46 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_aerodamping_data_transfers.py +43 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_data_transfer.py +190 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_data_transfer_by_display_names.py +191 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_expression_function.py +61 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_fsi_data_transfers.py +43 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_interface.py +77 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_interface_by_display_names.py +78 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_named_expression.py +42 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_ordered_data_transfers.py +32 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_participant.py +162 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_reference_frame.py +40 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_thermal_data_transfers.py +43 -0
- ansys/systemcoupling/core/adaptor/api_24_2/add_transformation.py +102 -0
- ansys/systemcoupling/core/adaptor/api_24_2/analysis_control.py +283 -0
- ansys/systemcoupling/core/adaptor/api_24_2/apip.py +33 -0
- ansys/systemcoupling/core/adaptor/api_24_2/ascii_output.py +44 -0
- ansys/systemcoupling/core/adaptor/api_24_2/attribute.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/attribute_child.py +54 -0
- ansys/systemcoupling/core/adaptor/api_24_2/automatic_alignment_options.py +46 -0
- ansys/systemcoupling/core/adaptor/api_24_2/available_ports.py +40 -0
- ansys/systemcoupling/core/adaptor/api_24_2/avoid_data_reconstruction.py +46 -0
- ansys/systemcoupling/core/adaptor/api_24_2/case_root.py +62 -0
- ansys/systemcoupling/core/adaptor/api_24_2/clear_state.py +18 -0
- ansys/systemcoupling/core/adaptor/api_24_2/connect_ensight_dvs.py +41 -0
- ansys/systemcoupling/core/adaptor/api_24_2/coupling_interface.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/coupling_interface_child.py +42 -0
- ansys/systemcoupling/core/adaptor/api_24_2/coupling_participant.py +23 -0
- ansys/systemcoupling/core/adaptor/api_24_2/coupling_participant_child.py +265 -0
- ansys/systemcoupling/core/adaptor/api_24_2/create_restart_point.py +29 -0
- ansys/systemcoupling/core/adaptor/api_24_2/data_transfer.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/data_transfer_child.py +187 -0
- ansys/systemcoupling/core/adaptor/api_24_2/delete_snapshot.py +28 -0
- ansys/systemcoupling/core/adaptor/api_24_2/delete_transformation.py +42 -0
- ansys/systemcoupling/core/adaptor/api_24_2/dimensionality.py +96 -0
- ansys/systemcoupling/core/adaptor/api_24_2/execution_control.py +246 -0
- ansys/systemcoupling/core/adaptor/api_24_2/execution_control_1.py +24 -0
- ansys/systemcoupling/core/adaptor/api_24_2/expression.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/expression_child.py +36 -0
- ansys/systemcoupling/core/adaptor/api_24_2/expression_function.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/expression_function_child.py +46 -0
- ansys/systemcoupling/core/adaptor/api_24_2/external_data_file.py +24 -0
- ansys/systemcoupling/core/adaptor/api_24_2/fluent_input.py +77 -0
- ansys/systemcoupling/core/adaptor/api_24_2/fmu_parameter.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/fmu_parameter_child.py +156 -0
- ansys/systemcoupling/core/adaptor/api_24_2/generate_input_file.py +41 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_add_data_transfer_group_commands.py +29 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_execution_command.py +30 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_machines.py +13 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_mode_shape_variables.py +29 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_region_names_for_participant.py +31 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_setup_summary.py +25 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_status_messages.py +52 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_supported_participant_types.py +13 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_thermal_data_transfer_options.py +32 -0
- ansys/systemcoupling/core/adaptor/api_24_2/get_transformation.py +43 -0
- ansys/systemcoupling/core/adaptor/api_24_2/global_stabilization.py +143 -0
- ansys/systemcoupling/core/adaptor/api_24_2/has_input_file_changed.py +36 -0
- ansys/systemcoupling/core/adaptor/api_24_2/import_system_coupling_input_file.py +36 -0
- ansys/systemcoupling/core/adaptor/api_24_2/initialize.py +27 -0
- ansys/systemcoupling/core/adaptor/api_24_2/instancing.py +23 -0
- ansys/systemcoupling/core/adaptor/api_24_2/instancing_child.py +62 -0
- ansys/systemcoupling/core/adaptor/api_24_2/interrupt.py +39 -0
- ansys/systemcoupling/core/adaptor/api_24_2/library.py +37 -0
- ansys/systemcoupling/core/adaptor/api_24_2/live_visualization.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/live_visualization_child.py +100 -0
- ansys/systemcoupling/core/adaptor/api_24_2/mapping_control.py +239 -0
- ansys/systemcoupling/core/adaptor/api_24_2/open.py +102 -0
- ansys/systemcoupling/core/adaptor/api_24_2/open_results_in_ensight.py +56 -0
- ansys/systemcoupling/core/adaptor/api_24_2/open_snapshot.py +37 -0
- ansys/systemcoupling/core/adaptor/api_24_2/output_control.py +134 -0
- ansys/systemcoupling/core/adaptor/api_24_2/parameter.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/parameter_child.py +56 -0
- ansys/systemcoupling/core/adaptor/api_24_2/partition_participants.py +138 -0
- ansys/systemcoupling/core/adaptor/api_24_2/properties.py +36 -0
- ansys/systemcoupling/core/adaptor/api_24_2/record_interactions.py +46 -0
- ansys/systemcoupling/core/adaptor/api_24_2/reference_frame.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/reference_frame_child.py +71 -0
- ansys/systemcoupling/core/adaptor/api_24_2/region.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/region_child.py +71 -0
- ansys/systemcoupling/core/adaptor/api_24_2/reload_expression_function_modules.py +14 -0
- ansys/systemcoupling/core/adaptor/api_24_2/results.py +89 -0
- ansys/systemcoupling/core/adaptor/api_24_2/save.py +51 -0
- ansys/systemcoupling/core/adaptor/api_24_2/save_snapshot.py +54 -0
- ansys/systemcoupling/core/adaptor/api_24_2/setup_root.py +251 -0
- ansys/systemcoupling/core/adaptor/api_24_2/show_plot.py +75 -0
- ansys/systemcoupling/core/adaptor/api_24_2/shutdown.py +25 -0
- ansys/systemcoupling/core/adaptor/api_24_2/side.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/side_child.py +56 -0
- ansys/systemcoupling/core/adaptor/api_24_2/solution_control.py +115 -0
- ansys/systemcoupling/core/adaptor/api_24_2/solution_root.py +122 -0
- ansys/systemcoupling/core/adaptor/api_24_2/solve.py +30 -0
- ansys/systemcoupling/core/adaptor/api_24_2/stabilization.py +157 -0
- ansys/systemcoupling/core/adaptor/api_24_2/start_participants.py +47 -0
- ansys/systemcoupling/core/adaptor/api_24_2/step.py +57 -0
- ansys/systemcoupling/core/adaptor/api_24_2/transformation.py +21 -0
- ansys/systemcoupling/core/adaptor/api_24_2/transformation_child.py +62 -0
- ansys/systemcoupling/core/adaptor/api_24_2/type.py +38 -0
- ansys/systemcoupling/core/adaptor/api_24_2/unmapped_value_options.py +158 -0
- ansys/systemcoupling/core/adaptor/api_24_2/update_control.py +43 -0
- ansys/systemcoupling/core/adaptor/api_24_2/update_participant.py +61 -0
- ansys/systemcoupling/core/adaptor/api_24_2/variable.py +20 -0
- ansys/systemcoupling/core/adaptor/api_24_2/variable_child.py +231 -0
- ansys/systemcoupling/core/adaptor/api_24_2/write_csv_chart_files.py +21 -0
- ansys/systemcoupling/core/adaptor/api_24_2/write_ensight.py +46 -0
- ansys/systemcoupling/core/adaptor/impl/injected_commands.py +228 -27
- ansys/systemcoupling/core/adaptor/impl/static_info.py +17 -0
- ansys/systemcoupling/core/adaptor/impl/syc_proxy.py +3 -0
- ansys/systemcoupling/core/adaptor/impl/syc_proxy_interface.py +4 -0
- ansys/systemcoupling/core/adaptor/impl/types.py +1 -1
- ansys/systemcoupling/core/charts/chart_datatypes.py +169 -0
- ansys/systemcoupling/core/charts/csv_chartdata.py +299 -0
- ansys/systemcoupling/core/charts/live_csv_datasource.py +87 -0
- ansys/systemcoupling/core/charts/message_dispatcher.py +84 -0
- ansys/systemcoupling/core/charts/plot_functions.py +92 -0
- ansys/systemcoupling/core/charts/plotdefinition_manager.py +303 -0
- ansys/systemcoupling/core/charts/plotter.py +343 -0
- ansys/systemcoupling/core/client/grpc_client.py +6 -1
- ansys/systemcoupling/core/participant/manager.py +25 -9
- ansys/systemcoupling/core/participant/protocol.py +1 -0
- ansys/systemcoupling/core/session.py +4 -4
- ansys/systemcoupling/core/syc_version.py +1 -1
- ansys/systemcoupling/core/util/file_transfer.py +4 -0
- ansys/systemcoupling/core/util/logging.py +1 -1
- {ansys_systemcoupling_core-0.4.1.dist-info → ansys_systemcoupling_core-0.6.dist-info}/METADATA +17 -16
- {ansys_systemcoupling_core-0.4.1.dist-info → ansys_systemcoupling_core-0.6.dist-info}/RECORD +148 -26
- {ansys_systemcoupling_core-0.4.1.dist-info → ansys_systemcoupling_core-0.6.dist-info}/LICENSE +0 -0
- {ansys_systemcoupling_core-0.4.1.dist-info → ansys_systemcoupling_core-0.6.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
|
|
23
|
+
import math
|
|
24
|
+
import sys
|
|
25
|
+
from typing import Callable, Optional, Union
|
|
26
|
+
|
|
27
|
+
from matplotlib.animation import FuncAnimation
|
|
28
|
+
from matplotlib.figure import Figure
|
|
29
|
+
from matplotlib.lines import Line2D
|
|
30
|
+
import matplotlib.pyplot as plt
|
|
31
|
+
|
|
32
|
+
from ansys.systemcoupling.core.charts.chart_datatypes import (
|
|
33
|
+
InterfaceInfo,
|
|
34
|
+
SeriesData,
|
|
35
|
+
TimestepData,
|
|
36
|
+
)
|
|
37
|
+
from ansys.systemcoupling.core.charts.plotdefinition_manager import (
|
|
38
|
+
PlotDefinitionManager,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _process_timestep_data(
|
|
43
|
+
timestep_data: TimestepData,
|
|
44
|
+
) -> tuple[list[int], list[float]]:
|
|
45
|
+
if not timestep_data.timestep:
|
|
46
|
+
return [], []
|
|
47
|
+
|
|
48
|
+
# TODO: for a dynamically updating case, it should be possible to do a partial update.
|
|
49
|
+
time_indexes = [0]
|
|
50
|
+
times = [None]
|
|
51
|
+
curr_step = timestep_data.timestep[0]
|
|
52
|
+
for i, step in enumerate(timestep_data.timestep):
|
|
53
|
+
time = timestep_data.time[i]
|
|
54
|
+
if step == curr_step:
|
|
55
|
+
# Still in the same step, so update
|
|
56
|
+
times[-1] = time
|
|
57
|
+
time_indexes[-1] = i
|
|
58
|
+
else:
|
|
59
|
+
# New step
|
|
60
|
+
times.append(time)
|
|
61
|
+
time_indexes.append(i)
|
|
62
|
+
curr_step = step
|
|
63
|
+
return (time_indexes, times)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _calc_new_ylimits_linear(
|
|
67
|
+
ynew: list[float], old_lim: Optional[tuple[float, float]]
|
|
68
|
+
) -> tuple[float, float]:
|
|
69
|
+
resize_tol = 0.02
|
|
70
|
+
resize_delta = 0.1
|
|
71
|
+
|
|
72
|
+
min_y = min(ynew)
|
|
73
|
+
max_y = max(ynew)
|
|
74
|
+
|
|
75
|
+
# Try to do something reasonable while we still don't have much data.
|
|
76
|
+
# Try to account for case where we don't have much data and range & value both zero.
|
|
77
|
+
data_range = min_y if abs(max_y - min_y) < 1.0e-7 else max_y - min_y
|
|
78
|
+
data_range = abs(data_range)
|
|
79
|
+
if data_range < 1.0e-7:
|
|
80
|
+
delta_limits = 1.0e-7
|
|
81
|
+
else:
|
|
82
|
+
delta_limits = resize_delta * data_range
|
|
83
|
+
|
|
84
|
+
if old_lim is None:
|
|
85
|
+
# First update - force calculation
|
|
86
|
+
old_l = min_y + 1
|
|
87
|
+
old_u = max_y - 1
|
|
88
|
+
else:
|
|
89
|
+
new_l, new_u = old_l, old_u = old_lim
|
|
90
|
+
|
|
91
|
+
if min_y < old_l + resize_tol * data_range:
|
|
92
|
+
new_l = min_y - delta_limits
|
|
93
|
+
if max_y > old_u - resize_tol * data_range:
|
|
94
|
+
new_u = max_y + delta_limits
|
|
95
|
+
|
|
96
|
+
return new_l, new_u
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _calc_new_ylimits_log(
|
|
100
|
+
ynew: list[float], old_lim: Optional[tuple[float, float]]
|
|
101
|
+
) -> tuple[float, float]:
|
|
102
|
+
|
|
103
|
+
min_y = min(ynew)
|
|
104
|
+
max_y = max(ynew)
|
|
105
|
+
|
|
106
|
+
if old_lim is not None:
|
|
107
|
+
new_l, new_u = old_lim
|
|
108
|
+
|
|
109
|
+
if old_lim is None or min_y < old_lim[0]:
|
|
110
|
+
log_l = math.log10(min_y)
|
|
111
|
+
exponent = math.floor(log_l)
|
|
112
|
+
new_l = math.pow(10.0, exponent)
|
|
113
|
+
if old_lim is None or max_y > old_lim[1]:
|
|
114
|
+
log_u = math.log10(max_y)
|
|
115
|
+
exponent = math.ceil(log_u)
|
|
116
|
+
new_u = math.pow(10.0, exponent)
|
|
117
|
+
# We do this in the GUI - is it needed?
|
|
118
|
+
new_u *= 1.0 + 1.0e-7
|
|
119
|
+
|
|
120
|
+
return new_l, new_u
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _update_xy_data(
|
|
124
|
+
time_info: Optional[tuple[list[int], list[float]]],
|
|
125
|
+
x_curr, # ArrayLike
|
|
126
|
+
y_curr, # ArrayLike
|
|
127
|
+
series_data: list[float],
|
|
128
|
+
new_start_index: int,
|
|
129
|
+
) -> tuple[Union[list[float], list[int]], list[float]]:
|
|
130
|
+
|
|
131
|
+
new_total_data_len = new_start_index + len(series_data)
|
|
132
|
+
x_new = []
|
|
133
|
+
y_new = []
|
|
134
|
+
if time_info:
|
|
135
|
+
time_indexes, time_values = time_info
|
|
136
|
+
# IMPORTANT: Assume that time data is updated ahead of any series data
|
|
137
|
+
# This means that (new_data_len - 1) should always be <= maximum known
|
|
138
|
+
# time index.
|
|
139
|
+
# time_indexes[-1] is the latest known 0-based iteration index that belongs
|
|
140
|
+
# to the latest timestep.
|
|
141
|
+
for i, time_iter in enumerate(time_indexes):
|
|
142
|
+
# Straight copy if not overlapping with new data yet
|
|
143
|
+
if time_iter < new_start_index:
|
|
144
|
+
x_new.append(time_values[i])
|
|
145
|
+
y_new.append(y_curr[i])
|
|
146
|
+
|
|
147
|
+
# Don't assume we have data yet for all known timesteps
|
|
148
|
+
elif time_iter < new_total_data_len:
|
|
149
|
+
x_new.append(time_values[i])
|
|
150
|
+
y_new.append(series_data[time_iter - new_start_index])
|
|
151
|
+
else:
|
|
152
|
+
for i in range(new_total_data_len):
|
|
153
|
+
if i < new_start_index:
|
|
154
|
+
x_new.append(x_curr[i])
|
|
155
|
+
y_new.append(y_curr[i])
|
|
156
|
+
else:
|
|
157
|
+
x_new.append(i + 1)
|
|
158
|
+
y_new.append(series_data[i - new_start_index])
|
|
159
|
+
return (x_new, y_new)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
# TODO: Only handles one interface at the moment! Generalise to multiple
|
|
163
|
+
class Plotter:
|
|
164
|
+
def __init__(
|
|
165
|
+
self,
|
|
166
|
+
mgr: PlotDefinitionManager,
|
|
167
|
+
request_update: Optional[Callable[[], None]] = None,
|
|
168
|
+
):
|
|
169
|
+
self._mgr = mgr
|
|
170
|
+
self._request_update = request_update
|
|
171
|
+
|
|
172
|
+
self._fig: Figure = plt.figure()
|
|
173
|
+
self._subplot_lines: list[list[Line2D]] = []
|
|
174
|
+
self._subplot_limits_set: list[bool] = []
|
|
175
|
+
self._metadata: Optional[InterfaceInfo] = None
|
|
176
|
+
|
|
177
|
+
# Empty if not transient:
|
|
178
|
+
self._times: list[float] = [] # Time value at each time step
|
|
179
|
+
self._time_indexes: list[int] = [] # Iteration to take value at time i from
|
|
180
|
+
|
|
181
|
+
def set_metadata(self, metadata: InterfaceInfo):
|
|
182
|
+
self._metadata = metadata
|
|
183
|
+
self._mgr.set_metadata(metadata)
|
|
184
|
+
# We now have enough information to create the (empty) plots
|
|
185
|
+
self._init_plots()
|
|
186
|
+
|
|
187
|
+
def set_timestep_data(self, timestep_data: TimestepData):
|
|
188
|
+
|
|
189
|
+
if timestep_data.timestep and not self._metadata.is_transient:
|
|
190
|
+
raise RuntimeError("Attempt to set timestep data on non-transient case")
|
|
191
|
+
|
|
192
|
+
self._time_indexes, self._times = _process_timestep_data(timestep_data)
|
|
193
|
+
|
|
194
|
+
def update_line_series(self, series_data: SeriesData):
|
|
195
|
+
"""Update the line series determined by the provided ``series_data`` with the
|
|
196
|
+
incremental data that it contains.
|
|
197
|
+
|
|
198
|
+
The ``series_data`` contains the "start index" in the full series, the index
|
|
199
|
+
to start writing the new data.
|
|
200
|
+
"""
|
|
201
|
+
if not self._metadata:
|
|
202
|
+
raise RuntimeError(
|
|
203
|
+
"Attempt to add series data to plot before metadata provided."
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
trans = self._metadata.transfer_info[series_data.transfer_index]
|
|
207
|
+
offset = (
|
|
208
|
+
series_data.component_index
|
|
209
|
+
if series_data.component_index is not None
|
|
210
|
+
else 0
|
|
211
|
+
)
|
|
212
|
+
subplot_defn, subplot_line_index = self._mgr.subplot_for_data_index(
|
|
213
|
+
self._metadata.name, trans.data_index + offset
|
|
214
|
+
)
|
|
215
|
+
if subplot_defn is None:
|
|
216
|
+
# This can happen if the list of plots being show is filtered.
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
subplot_line = self._subplot_lines[subplot_defn.index][subplot_line_index]
|
|
220
|
+
|
|
221
|
+
# We don't assume that all provided series_data are fully up to
|
|
222
|
+
# date with the latest iteration or timestep that pertains globally
|
|
223
|
+
# over all plots.
|
|
224
|
+
|
|
225
|
+
if len(series_data.data) == 0:
|
|
226
|
+
return
|
|
227
|
+
|
|
228
|
+
x_curr, y_curr = subplot_line.get_data()
|
|
229
|
+
x_new, y_new = _update_xy_data(
|
|
230
|
+
(self._time_indexes, self._times) if self._times else None,
|
|
231
|
+
x_curr,
|
|
232
|
+
y_curr,
|
|
233
|
+
series_data.data,
|
|
234
|
+
series_data.start_index,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
self.update_limits(subplot_defn.index, subplot_defn.is_log_y, x_new, y_new)
|
|
238
|
+
subplot_line.set_data(x_new, y_new)
|
|
239
|
+
|
|
240
|
+
def update_limits(self, subplot_index, is_log_y, x_new, y_new):
|
|
241
|
+
axes = self._fig.axes[subplot_index]
|
|
242
|
+
|
|
243
|
+
are_limits_initialised = self._subplot_limits_set[subplot_index]
|
|
244
|
+
|
|
245
|
+
old_xlim = (0, 0)
|
|
246
|
+
old_ylim = None
|
|
247
|
+
if are_limits_initialised:
|
|
248
|
+
old_xlim = axes.get_xlim()
|
|
249
|
+
old_ylim = axes.get_ylim()
|
|
250
|
+
|
|
251
|
+
new_ylimits = (
|
|
252
|
+
_calc_new_ylimits_log(y_new, old_ylim)
|
|
253
|
+
if is_log_y
|
|
254
|
+
else _calc_new_ylimits_linear(y_new, old_ylim)
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
new_xlimits = old_xlim
|
|
258
|
+
if self._times:
|
|
259
|
+
if x_new[-1] >= old_xlim[1] * 0.95:
|
|
260
|
+
new_xlimits = (0.0, x_new[-1] * 1.1)
|
|
261
|
+
else:
|
|
262
|
+
if len(x_new) >= old_xlim[1] - 1:
|
|
263
|
+
new_xlimits = (1, len(x_new) + 1)
|
|
264
|
+
|
|
265
|
+
axes.set_xlim(new_xlimits)
|
|
266
|
+
axes.set_ylim(new_ylimits)
|
|
267
|
+
|
|
268
|
+
self._subplot_limits_set[subplot_index] = True
|
|
269
|
+
|
|
270
|
+
def close(self):
|
|
271
|
+
if self._fig:
|
|
272
|
+
plt.close(self._fig)
|
|
273
|
+
|
|
274
|
+
def show_plot(self, noblock=False):
|
|
275
|
+
if noblock:
|
|
276
|
+
plt.ion()
|
|
277
|
+
plt.show()
|
|
278
|
+
|
|
279
|
+
def show_animated(self):
|
|
280
|
+
# NB: if using the wait_for_metadata() approach
|
|
281
|
+
# supported by MessageDispatcher, do it here like
|
|
282
|
+
# this (assume the wait function is stored as an
|
|
283
|
+
# attribute):
|
|
284
|
+
#
|
|
285
|
+
# assert self._wait_for_metadata is not None
|
|
286
|
+
# metadata = self._wait_for_metadata()
|
|
287
|
+
# if metadata is not None:
|
|
288
|
+
# self.set_metadata(metadata)
|
|
289
|
+
# else:
|
|
290
|
+
# return
|
|
291
|
+
assert self._request_update is not None
|
|
292
|
+
|
|
293
|
+
self.ani = FuncAnimation(
|
|
294
|
+
self._fig,
|
|
295
|
+
self._update_animation,
|
|
296
|
+
# frames=x_axis_pts,
|
|
297
|
+
save_count=sys.maxsize,
|
|
298
|
+
# init_func=self._init_plots,
|
|
299
|
+
blit=False,
|
|
300
|
+
interval=200,
|
|
301
|
+
repeat=False,
|
|
302
|
+
)
|
|
303
|
+
plt.show()
|
|
304
|
+
|
|
305
|
+
def _update_animation(self, frame: int):
|
|
306
|
+
# print("calling update animation")
|
|
307
|
+
return self._request_update()
|
|
308
|
+
|
|
309
|
+
def _init_plots(self):
|
|
310
|
+
# plt.ion()
|
|
311
|
+
nrow, ncol = self._mgr.get_layout()
|
|
312
|
+
self._fig.subplots(nrow, ncol, gridspec_kw={"hspace": 0.5})
|
|
313
|
+
subplot_defns = self._mgr.subplots
|
|
314
|
+
if len(subplot_defns) != 1 and len(subplot_defns) % 2 == 1:
|
|
315
|
+
self._fig.delaxes(self._fig.axes[-1])
|
|
316
|
+
|
|
317
|
+
# Add labels and legends
|
|
318
|
+
for axes, subplot_defn in zip(self._fig.axes, subplot_defns):
|
|
319
|
+
axes.set_title(subplot_defn.title, fontsize=8)
|
|
320
|
+
if subplot_defn.is_log_y:
|
|
321
|
+
axes.set_yscale("log")
|
|
322
|
+
axes.set_xlabel(subplot_defn.x_axis_label, fontsize=8)
|
|
323
|
+
axes.set_ylabel(subplot_defn.y_axis_label, fontsize=8)
|
|
324
|
+
lines = []
|
|
325
|
+
for label in subplot_defn.series_labels:
|
|
326
|
+
(ln,) = axes.plot([], [], label=label)
|
|
327
|
+
lines.append(ln)
|
|
328
|
+
axes.legend(fontsize=6)
|
|
329
|
+
|
|
330
|
+
# Set arbitrary axes limits
|
|
331
|
+
if self._metadata.is_transient:
|
|
332
|
+
axes.set_xlim(0.0, 1.0)
|
|
333
|
+
else:
|
|
334
|
+
axes.set_xlim(1, 5)
|
|
335
|
+
if subplot_defn.is_log_y:
|
|
336
|
+
axes.set_ylim(1e-20, 1)
|
|
337
|
+
else:
|
|
338
|
+
axes.set_ylim(0, 1.0)
|
|
339
|
+
|
|
340
|
+
# Keep hold of lines so that we can assign data when it's available
|
|
341
|
+
self._subplot_lines.append(lines)
|
|
342
|
+
# The limits on this subplot are essentially unset until we start getting data
|
|
343
|
+
self._subplot_limits_set.append(False)
|
|
@@ -119,6 +119,7 @@ class SycGrpc(object):
|
|
|
119
119
|
working_dir = kwargs.pop("working_dir", None)
|
|
120
120
|
port = kwargs.pop("port", None)
|
|
121
121
|
version = kwargs.pop("version", None)
|
|
122
|
+
start_output = kwargs.pop("start_output", None)
|
|
122
123
|
|
|
123
124
|
if os.environ.get("SYC_LAUNCH_CONTAINER") == "1":
|
|
124
125
|
mounted_from = working_dir if working_dir else "./"
|
|
@@ -137,6 +138,8 @@ class SycGrpc(object):
|
|
|
137
138
|
)
|
|
138
139
|
LOG.debug("...started")
|
|
139
140
|
self._connect(_LOCALHOST_IP, port)
|
|
141
|
+
if start_output:
|
|
142
|
+
self.start_output()
|
|
140
143
|
|
|
141
144
|
def start_container_and_connect(
|
|
142
145
|
self,
|
|
@@ -153,7 +156,7 @@ class SycGrpc(object):
|
|
|
153
156
|
LOG.debug("...started")
|
|
154
157
|
self._connect(_LOCALHOST_IP, port)
|
|
155
158
|
|
|
156
|
-
def start_pim_and_connect(self, version: str = None):
|
|
159
|
+
def start_pim_and_connect(self, version: str = None, start_output: bool = False):
|
|
157
160
|
"""Start PIM-managed instance.
|
|
158
161
|
|
|
159
162
|
Currently for internal use only.
|
|
@@ -171,6 +174,8 @@ class SycGrpc(object):
|
|
|
171
174
|
self.__pim_instance = instance
|
|
172
175
|
channel = instance.build_grpc_channel()
|
|
173
176
|
self._connect(channel=channel)
|
|
177
|
+
if start_output:
|
|
178
|
+
self.start_output()
|
|
174
179
|
|
|
175
180
|
def upload_file(self, *args, **kwargs):
|
|
176
181
|
"""Supports file upload to remote instance.
|
|
@@ -24,6 +24,7 @@ import threading
|
|
|
24
24
|
from typing import Dict, List, Tuple
|
|
25
25
|
|
|
26
26
|
from ansys.systemcoupling.core.participant.protocol import ParticipantProtocol
|
|
27
|
+
from ansys.systemcoupling.core.syc_version import compare_versions
|
|
27
28
|
from ansys.systemcoupling.core.util.logging import LOG
|
|
28
29
|
|
|
29
30
|
|
|
@@ -54,10 +55,11 @@ class ParticipantManager:
|
|
|
54
55
|
until more participant types support the protocol.
|
|
55
56
|
"""
|
|
56
57
|
|
|
57
|
-
def __init__(self, syc_session):
|
|
58
|
+
def __init__(self, syc_session, server_version: str):
|
|
58
59
|
self.__participants: Dict[str, ParticipantProtocol] = {}
|
|
59
60
|
self.__syc_session = syc_session
|
|
60
61
|
self.__connection_lock = threading.Lock()
|
|
62
|
+
self.__server_version = server_version
|
|
61
63
|
self.clear()
|
|
62
64
|
|
|
63
65
|
def clear(self):
|
|
@@ -66,6 +68,11 @@ class ParticipantManager:
|
|
|
66
68
|
self.__solve_exception = None
|
|
67
69
|
|
|
68
70
|
def add_participant(self, participant_session: ParticipantProtocol) -> str:
|
|
71
|
+
if compare_versions(self.__server_version, "24.1") < 0:
|
|
72
|
+
raise RuntimeError(
|
|
73
|
+
f"System Coupling server version '{self.__server_version}' is too low to"
|
|
74
|
+
"support this form of 'add_participant'. Minimum version is '24.1'."
|
|
75
|
+
)
|
|
69
76
|
participant_name = (
|
|
70
77
|
f"{participant_session.participant_type}-{len(self.__participants) + 1}"
|
|
71
78
|
)
|
|
@@ -96,14 +103,23 @@ class ParticipantManager:
|
|
|
96
103
|
)
|
|
97
104
|
|
|
98
105
|
for region in participant_session.get_regions():
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
region_state = {
|
|
107
|
+
"topology": region.topology,
|
|
108
|
+
"input_variables": region.input_variables,
|
|
109
|
+
"output_variables": region.output_variables,
|
|
110
|
+
"display_name": region.display_name,
|
|
111
|
+
}
|
|
112
|
+
if compare_versions(self.__server_version, "24.2") >= 0:
|
|
113
|
+
region_state.update(
|
|
114
|
+
{
|
|
115
|
+
"region_discretization_type": (
|
|
116
|
+
region.region_discretization_type
|
|
117
|
+
if hasattr(region, "region_discretization_type")
|
|
118
|
+
else "Mesh Region"
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
part_state.region.create(region.name).set_state(region_state)
|
|
107
123
|
|
|
108
124
|
self.__participants[participant_name] = participant_session
|
|
109
125
|
return participant_name
|
|
@@ -83,7 +83,7 @@ class Session:
|
|
|
83
83
|
self.__rpc = rpc
|
|
84
84
|
self.__native_api = None
|
|
85
85
|
self.__syc_version = None
|
|
86
|
-
self.__part_mgr =
|
|
86
|
+
self.__part_mgr = None
|
|
87
87
|
|
|
88
88
|
def exit(self) -> None:
|
|
89
89
|
"""Close the System Coupling server instance.
|
|
@@ -176,10 +176,10 @@ class Session:
|
|
|
176
176
|
version = sycproxy.get_version()
|
|
177
177
|
self.__syc_version = version.replace(".", "_")
|
|
178
178
|
root = get_root(sycproxy, category=category, version=self.__syc_version)
|
|
179
|
+
if self.__part_mgr is None:
|
|
180
|
+
self.__part_mgr = ParticipantManager(self, self.__syc_version)
|
|
179
181
|
sycproxy.set_injected_commands(
|
|
180
|
-
get_injected_cmd_map(
|
|
181
|
-
self.__syc_version, category, root, self.__part_mgr, self.__rpc
|
|
182
|
-
)
|
|
182
|
+
get_injected_cmd_map(category, self, self.__part_mgr, self.__rpc)
|
|
183
183
|
)
|
|
184
184
|
return (root, sycproxy)
|
|
185
185
|
|
|
@@ -25,7 +25,7 @@ from typing import Tuple
|
|
|
25
25
|
# Define constants relating to the default/current version of System Coupling
|
|
26
26
|
|
|
27
27
|
SYC_MAJOR_VERSION = 24
|
|
28
|
-
SYC_MINOR_VERSION =
|
|
28
|
+
SYC_MINOR_VERSION = 2
|
|
29
29
|
|
|
30
30
|
SYC_VERSION_CONCAT = f"{SYC_MAJOR_VERSION}{SYC_MINOR_VERSION}"
|
|
31
31
|
SYC_VERSION_DOT = f"{SYC_MAJOR_VERSION}.{SYC_MINOR_VERSION}"
|
|
@@ -88,6 +88,10 @@ class PimFileTransferService: # pragma: no cover
|
|
|
88
88
|
"""
|
|
89
89
|
if os.path.isfile(file_name):
|
|
90
90
|
remote_file_name = remote_file_name or os.path.basename(file_name)
|
|
91
|
+
if os.path.dirname(file_name):
|
|
92
|
+
raise IsADirectoryError(
|
|
93
|
+
f"{remote_file_name} is not in the current working directory"
|
|
94
|
+
)
|
|
91
95
|
if not overwrite and self.file_service.file_exist(remote_file_name):
|
|
92
96
|
raise FileExistsError(f"{remote_file_name} already exists remotely.")
|
|
93
97
|
self.file_service.upload_file(file_name, remote_file_name)
|
{ansys_systemcoupling_core-0.4.1.dist-info → ansys_systemcoupling_core-0.6.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.6
|
|
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>
|
|
@@ -20,34 +20,35 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
20
20
|
Requires-Dist: ansys-api-systemcoupling==0.1.0
|
|
21
21
|
Requires-Dist: ansys-platform-instancemanagement~=1.0
|
|
22
22
|
Requires-Dist: grpcio>=1.30.0
|
|
23
|
-
Requires-Dist: grpcio-status>=1.30.0,<1.
|
|
23
|
+
Requires-Dist: grpcio-status>=1.30.0,<1.64.2
|
|
24
24
|
Requires-Dist: googleapis-common-protos>=1.50.0
|
|
25
25
|
Requires-Dist: protobuf>=3.20.1,<4.0.0
|
|
26
26
|
Requires-Dist: psutil>=5.7.0
|
|
27
27
|
Requires-Dist: pyyaml
|
|
28
28
|
Requires-Dist: appdirs>=1.4.0
|
|
29
29
|
Requires-Dist: importlib-metadata>=4.0
|
|
30
|
+
Requires-Dist: matplotlib>=3.8.2
|
|
30
31
|
Requires-Dist: build ; extra == "build"
|
|
31
|
-
Requires-Dist: black==24.
|
|
32
|
+
Requires-Dist: black==24.4.2 ; extra == "classesgen"
|
|
32
33
|
Requires-Dist: isort==5.13.2 ; extra == "classesgen"
|
|
33
|
-
Requires-Dist: ansys-sphinx-theme==0.
|
|
34
|
+
Requires-Dist: ansys-sphinx-theme==0.16.6 ; extra == "doc"
|
|
34
35
|
Requires-Dist: jupyter_sphinx==0.5.3 ; extra == "doc"
|
|
35
36
|
Requires-Dist: matplotlib ; extra == "doc"
|
|
36
|
-
Requires-Dist: numpydoc==1.
|
|
37
|
-
Requires-Dist: pypandoc==1.
|
|
38
|
-
Requires-Dist: pytest-sphinx==0.6.
|
|
39
|
-
Requires-Dist: Sphinx==7.
|
|
40
|
-
Requires-Dist: sphinx-autobuild==2024.
|
|
41
|
-
Requires-Dist: sphinx-autodoc-typehints==
|
|
37
|
+
Requires-Dist: numpydoc==1.7.0 ; extra == "doc"
|
|
38
|
+
Requires-Dist: pypandoc==1.13 ; extra == "doc"
|
|
39
|
+
Requires-Dist: pytest-sphinx==0.6.3 ; extra == "doc"
|
|
40
|
+
Requires-Dist: Sphinx==7.3.7 ; extra == "doc"
|
|
41
|
+
Requires-Dist: sphinx-autobuild==2024.4.16 ; extra == "doc"
|
|
42
|
+
Requires-Dist: sphinx-autodoc-typehints==2.2.2 ; extra == "doc"
|
|
42
43
|
Requires-Dist: sphinx-copybutton==0.5.2 ; extra == "doc"
|
|
43
|
-
Requires-Dist: sphinx-gallery==0.
|
|
44
|
-
Requires-Dist: sphinx-notfound-page==1.0.
|
|
44
|
+
Requires-Dist: sphinx-gallery==0.16.0 ; extra == "doc"
|
|
45
|
+
Requires-Dist: sphinx-notfound-page==1.0.2 ; extra == "doc"
|
|
45
46
|
Requires-Dist: sphinxcontrib-websupport==1.2.7 ; extra == "doc"
|
|
46
47
|
Requires-Dist: sphinxemoji==0.3.1 ; extra == "doc"
|
|
47
48
|
Requires-Dist: ansys-fluent-core ; extra == "doc"
|
|
48
49
|
Requires-Dist: ansys-dpf-core ; extra == "doc"
|
|
49
|
-
Requires-Dist: codespell==2.
|
|
50
|
-
Requires-Dist: flake8==7.
|
|
50
|
+
Requires-Dist: codespell==2.3.0 ; extra == "style"
|
|
51
|
+
Requires-Dist: flake8==7.1.0 ; extra == "style"
|
|
51
52
|
Requires-Dist: pytest ; extra == "tests"
|
|
52
53
|
Requires-Dist: pytest-cov ; extra == "tests"
|
|
53
54
|
Requires-Dist: psutil>=5.7.0 ; extra == "tests"
|
|
@@ -136,12 +137,12 @@ in this order:
|
|
|
136
137
|
|
|
137
138
|
* ``SYSC_ROOT``
|
|
138
139
|
* ``AWP_ROOT``
|
|
139
|
-
* ``
|
|
140
|
+
* ``AWP_ROOT242``
|
|
140
141
|
|
|
141
142
|
If a variable is set but does not refer to a valid installation, PySystemCoupling
|
|
142
143
|
fails at that point, rather than attempting to use the next variable.
|
|
143
144
|
|
|
144
|
-
In a standard user installation, the expectation is that only ``
|
|
145
|
+
In a standard user installation, the expectation is that only ``AWP_ROOT242`` is set.
|
|
145
146
|
|
|
146
147
|
(It is also possible to provide a different version number as an argument to the ``launch()``
|
|
147
148
|
function. This will affect which ``AWP_ROOT<version>`` environment variable is examined.)
|