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.

Files changed (148) hide show
  1. ansys/systemcoupling/core/__init__.py +11 -5
  2. ansys/systemcoupling/core/adaptor/api_23_1/_clear_state.py +13 -0
  3. ansys/systemcoupling/core/adaptor/api_23_1/case_root.py +7 -1
  4. ansys/systemcoupling/core/adaptor/api_23_1/clear_state.py +4 -2
  5. ansys/systemcoupling/core/adaptor/api_23_1/show_plot.py +75 -0
  6. ansys/systemcoupling/core/adaptor/api_23_1/solution_root.py +7 -1
  7. ansys/systemcoupling/core/adaptor/api_23_2/_clear_state.py +13 -0
  8. ansys/systemcoupling/core/adaptor/api_23_2/case_root.py +7 -1
  9. ansys/systemcoupling/core/adaptor/api_23_2/clear_state.py +4 -2
  10. ansys/systemcoupling/core/adaptor/api_23_2/show_plot.py +75 -0
  11. ansys/systemcoupling/core/adaptor/api_23_2/solution_root.py +7 -1
  12. ansys/systemcoupling/core/adaptor/api_24_1/_clear_state.py +13 -0
  13. ansys/systemcoupling/core/adaptor/api_24_1/case_root.py +7 -1
  14. ansys/systemcoupling/core/adaptor/api_24_1/clear_state.py +4 -2
  15. ansys/systemcoupling/core/adaptor/api_24_1/show_plot.py +75 -0
  16. ansys/systemcoupling/core/adaptor/api_24_1/solution_root.py +7 -1
  17. ansys/systemcoupling/core/adaptor/api_24_2/_add_participant.py +80 -0
  18. ansys/systemcoupling/core/adaptor/api_24_2/_clear_state.py +13 -0
  19. ansys/systemcoupling/core/adaptor/api_24_2/_solve.py +13 -0
  20. ansys/systemcoupling/core/adaptor/api_24_2/abort.py +39 -0
  21. ansys/systemcoupling/core/adaptor/api_24_2/activate_hidden.py +46 -0
  22. ansys/systemcoupling/core/adaptor/api_24_2/add_aerodamping_data_transfers.py +43 -0
  23. ansys/systemcoupling/core/adaptor/api_24_2/add_data_transfer.py +190 -0
  24. ansys/systemcoupling/core/adaptor/api_24_2/add_data_transfer_by_display_names.py +191 -0
  25. ansys/systemcoupling/core/adaptor/api_24_2/add_expression_function.py +61 -0
  26. ansys/systemcoupling/core/adaptor/api_24_2/add_fsi_data_transfers.py +43 -0
  27. ansys/systemcoupling/core/adaptor/api_24_2/add_interface.py +77 -0
  28. ansys/systemcoupling/core/adaptor/api_24_2/add_interface_by_display_names.py +78 -0
  29. ansys/systemcoupling/core/adaptor/api_24_2/add_named_expression.py +42 -0
  30. ansys/systemcoupling/core/adaptor/api_24_2/add_ordered_data_transfers.py +32 -0
  31. ansys/systemcoupling/core/adaptor/api_24_2/add_participant.py +162 -0
  32. ansys/systemcoupling/core/adaptor/api_24_2/add_reference_frame.py +40 -0
  33. ansys/systemcoupling/core/adaptor/api_24_2/add_thermal_data_transfers.py +43 -0
  34. ansys/systemcoupling/core/adaptor/api_24_2/add_transformation.py +102 -0
  35. ansys/systemcoupling/core/adaptor/api_24_2/analysis_control.py +283 -0
  36. ansys/systemcoupling/core/adaptor/api_24_2/apip.py +33 -0
  37. ansys/systemcoupling/core/adaptor/api_24_2/ascii_output.py +44 -0
  38. ansys/systemcoupling/core/adaptor/api_24_2/attribute.py +20 -0
  39. ansys/systemcoupling/core/adaptor/api_24_2/attribute_child.py +54 -0
  40. ansys/systemcoupling/core/adaptor/api_24_2/automatic_alignment_options.py +46 -0
  41. ansys/systemcoupling/core/adaptor/api_24_2/available_ports.py +40 -0
  42. ansys/systemcoupling/core/adaptor/api_24_2/avoid_data_reconstruction.py +46 -0
  43. ansys/systemcoupling/core/adaptor/api_24_2/case_root.py +62 -0
  44. ansys/systemcoupling/core/adaptor/api_24_2/clear_state.py +18 -0
  45. ansys/systemcoupling/core/adaptor/api_24_2/connect_ensight_dvs.py +41 -0
  46. ansys/systemcoupling/core/adaptor/api_24_2/coupling_interface.py +20 -0
  47. ansys/systemcoupling/core/adaptor/api_24_2/coupling_interface_child.py +42 -0
  48. ansys/systemcoupling/core/adaptor/api_24_2/coupling_participant.py +23 -0
  49. ansys/systemcoupling/core/adaptor/api_24_2/coupling_participant_child.py +265 -0
  50. ansys/systemcoupling/core/adaptor/api_24_2/create_restart_point.py +29 -0
  51. ansys/systemcoupling/core/adaptor/api_24_2/data_transfer.py +20 -0
  52. ansys/systemcoupling/core/adaptor/api_24_2/data_transfer_child.py +187 -0
  53. ansys/systemcoupling/core/adaptor/api_24_2/delete_snapshot.py +28 -0
  54. ansys/systemcoupling/core/adaptor/api_24_2/delete_transformation.py +42 -0
  55. ansys/systemcoupling/core/adaptor/api_24_2/dimensionality.py +96 -0
  56. ansys/systemcoupling/core/adaptor/api_24_2/execution_control.py +246 -0
  57. ansys/systemcoupling/core/adaptor/api_24_2/execution_control_1.py +24 -0
  58. ansys/systemcoupling/core/adaptor/api_24_2/expression.py +20 -0
  59. ansys/systemcoupling/core/adaptor/api_24_2/expression_child.py +36 -0
  60. ansys/systemcoupling/core/adaptor/api_24_2/expression_function.py +20 -0
  61. ansys/systemcoupling/core/adaptor/api_24_2/expression_function_child.py +46 -0
  62. ansys/systemcoupling/core/adaptor/api_24_2/external_data_file.py +24 -0
  63. ansys/systemcoupling/core/adaptor/api_24_2/fluent_input.py +77 -0
  64. ansys/systemcoupling/core/adaptor/api_24_2/fmu_parameter.py +20 -0
  65. ansys/systemcoupling/core/adaptor/api_24_2/fmu_parameter_child.py +156 -0
  66. ansys/systemcoupling/core/adaptor/api_24_2/generate_input_file.py +41 -0
  67. ansys/systemcoupling/core/adaptor/api_24_2/get_add_data_transfer_group_commands.py +29 -0
  68. ansys/systemcoupling/core/adaptor/api_24_2/get_execution_command.py +30 -0
  69. ansys/systemcoupling/core/adaptor/api_24_2/get_machines.py +13 -0
  70. ansys/systemcoupling/core/adaptor/api_24_2/get_mode_shape_variables.py +29 -0
  71. ansys/systemcoupling/core/adaptor/api_24_2/get_region_names_for_participant.py +31 -0
  72. ansys/systemcoupling/core/adaptor/api_24_2/get_setup_summary.py +25 -0
  73. ansys/systemcoupling/core/adaptor/api_24_2/get_status_messages.py +52 -0
  74. ansys/systemcoupling/core/adaptor/api_24_2/get_supported_participant_types.py +13 -0
  75. ansys/systemcoupling/core/adaptor/api_24_2/get_thermal_data_transfer_options.py +32 -0
  76. ansys/systemcoupling/core/adaptor/api_24_2/get_transformation.py +43 -0
  77. ansys/systemcoupling/core/adaptor/api_24_2/global_stabilization.py +143 -0
  78. ansys/systemcoupling/core/adaptor/api_24_2/has_input_file_changed.py +36 -0
  79. ansys/systemcoupling/core/adaptor/api_24_2/import_system_coupling_input_file.py +36 -0
  80. ansys/systemcoupling/core/adaptor/api_24_2/initialize.py +27 -0
  81. ansys/systemcoupling/core/adaptor/api_24_2/instancing.py +23 -0
  82. ansys/systemcoupling/core/adaptor/api_24_2/instancing_child.py +62 -0
  83. ansys/systemcoupling/core/adaptor/api_24_2/interrupt.py +39 -0
  84. ansys/systemcoupling/core/adaptor/api_24_2/library.py +37 -0
  85. ansys/systemcoupling/core/adaptor/api_24_2/live_visualization.py +20 -0
  86. ansys/systemcoupling/core/adaptor/api_24_2/live_visualization_child.py +100 -0
  87. ansys/systemcoupling/core/adaptor/api_24_2/mapping_control.py +239 -0
  88. ansys/systemcoupling/core/adaptor/api_24_2/open.py +102 -0
  89. ansys/systemcoupling/core/adaptor/api_24_2/open_results_in_ensight.py +56 -0
  90. ansys/systemcoupling/core/adaptor/api_24_2/open_snapshot.py +37 -0
  91. ansys/systemcoupling/core/adaptor/api_24_2/output_control.py +134 -0
  92. ansys/systemcoupling/core/adaptor/api_24_2/parameter.py +20 -0
  93. ansys/systemcoupling/core/adaptor/api_24_2/parameter_child.py +56 -0
  94. ansys/systemcoupling/core/adaptor/api_24_2/partition_participants.py +138 -0
  95. ansys/systemcoupling/core/adaptor/api_24_2/properties.py +36 -0
  96. ansys/systemcoupling/core/adaptor/api_24_2/record_interactions.py +46 -0
  97. ansys/systemcoupling/core/adaptor/api_24_2/reference_frame.py +20 -0
  98. ansys/systemcoupling/core/adaptor/api_24_2/reference_frame_child.py +71 -0
  99. ansys/systemcoupling/core/adaptor/api_24_2/region.py +20 -0
  100. ansys/systemcoupling/core/adaptor/api_24_2/region_child.py +71 -0
  101. ansys/systemcoupling/core/adaptor/api_24_2/reload_expression_function_modules.py +14 -0
  102. ansys/systemcoupling/core/adaptor/api_24_2/results.py +89 -0
  103. ansys/systemcoupling/core/adaptor/api_24_2/save.py +51 -0
  104. ansys/systemcoupling/core/adaptor/api_24_2/save_snapshot.py +54 -0
  105. ansys/systemcoupling/core/adaptor/api_24_2/setup_root.py +251 -0
  106. ansys/systemcoupling/core/adaptor/api_24_2/show_plot.py +75 -0
  107. ansys/systemcoupling/core/adaptor/api_24_2/shutdown.py +25 -0
  108. ansys/systemcoupling/core/adaptor/api_24_2/side.py +20 -0
  109. ansys/systemcoupling/core/adaptor/api_24_2/side_child.py +56 -0
  110. ansys/systemcoupling/core/adaptor/api_24_2/solution_control.py +115 -0
  111. ansys/systemcoupling/core/adaptor/api_24_2/solution_root.py +122 -0
  112. ansys/systemcoupling/core/adaptor/api_24_2/solve.py +30 -0
  113. ansys/systemcoupling/core/adaptor/api_24_2/stabilization.py +157 -0
  114. ansys/systemcoupling/core/adaptor/api_24_2/start_participants.py +47 -0
  115. ansys/systemcoupling/core/adaptor/api_24_2/step.py +57 -0
  116. ansys/systemcoupling/core/adaptor/api_24_2/transformation.py +21 -0
  117. ansys/systemcoupling/core/adaptor/api_24_2/transformation_child.py +62 -0
  118. ansys/systemcoupling/core/adaptor/api_24_2/type.py +38 -0
  119. ansys/systemcoupling/core/adaptor/api_24_2/unmapped_value_options.py +158 -0
  120. ansys/systemcoupling/core/adaptor/api_24_2/update_control.py +43 -0
  121. ansys/systemcoupling/core/adaptor/api_24_2/update_participant.py +61 -0
  122. ansys/systemcoupling/core/adaptor/api_24_2/variable.py +20 -0
  123. ansys/systemcoupling/core/adaptor/api_24_2/variable_child.py +231 -0
  124. ansys/systemcoupling/core/adaptor/api_24_2/write_csv_chart_files.py +21 -0
  125. ansys/systemcoupling/core/adaptor/api_24_2/write_ensight.py +46 -0
  126. ansys/systemcoupling/core/adaptor/impl/injected_commands.py +228 -27
  127. ansys/systemcoupling/core/adaptor/impl/static_info.py +17 -0
  128. ansys/systemcoupling/core/adaptor/impl/syc_proxy.py +3 -0
  129. ansys/systemcoupling/core/adaptor/impl/syc_proxy_interface.py +4 -0
  130. ansys/systemcoupling/core/adaptor/impl/types.py +1 -1
  131. ansys/systemcoupling/core/charts/chart_datatypes.py +169 -0
  132. ansys/systemcoupling/core/charts/csv_chartdata.py +299 -0
  133. ansys/systemcoupling/core/charts/live_csv_datasource.py +87 -0
  134. ansys/systemcoupling/core/charts/message_dispatcher.py +84 -0
  135. ansys/systemcoupling/core/charts/plot_functions.py +92 -0
  136. ansys/systemcoupling/core/charts/plotdefinition_manager.py +303 -0
  137. ansys/systemcoupling/core/charts/plotter.py +343 -0
  138. ansys/systemcoupling/core/client/grpc_client.py +6 -1
  139. ansys/systemcoupling/core/participant/manager.py +25 -9
  140. ansys/systemcoupling/core/participant/protocol.py +1 -0
  141. ansys/systemcoupling/core/session.py +4 -4
  142. ansys/systemcoupling/core/syc_version.py +1 -1
  143. ansys/systemcoupling/core/util/file_transfer.py +4 -0
  144. ansys/systemcoupling/core/util/logging.py +1 -1
  145. {ansys_systemcoupling_core-0.4.1.dist-info → ansys_systemcoupling_core-0.6.dist-info}/METADATA +17 -16
  146. {ansys_systemcoupling_core-0.4.1.dist-info → ansys_systemcoupling_core-0.6.dist-info}/RECORD +148 -26
  147. {ansys_systemcoupling_core-0.4.1.dist-info → ansys_systemcoupling_core-0.6.dist-info}/LICENSE +0 -0
  148. {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
- part_state.region.create(region.name).set_state(
100
- {
101
- "topology": region.topology,
102
- "input_variables": region.input_variables,
103
- "output_variables": region.output_variables,
104
- "display_name": region.display_name,
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
@@ -41,6 +41,7 @@ class Region(Protocol):
41
41
  topology: str
42
42
  input_variables: List[str]
43
43
  output_variables: List[str]
44
+ region_discretization_type: str = "Mesh Region"
44
45
 
45
46
 
46
47
  class ParticipantProtocol(Protocol):
@@ -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 = ParticipantManager(self)
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 = 1
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)
@@ -55,7 +55,7 @@ class Logger:
55
55
  """
56
56
 
57
57
  def __init__(self, level: Any = logging.ERROR):
58
- self.logger = logging.getLogger()
58
+ self.logger = logging.getLogger("pysystem-coupling")
59
59
  self.stream_handler = None
60
60
  self.file_handler = None
61
61
  self.log_filepath = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ansys-systemcoupling-core
3
- Version: 0.4.1
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.60.2
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.1.1 ; extra == "classesgen"
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.13.3 ; extra == "doc"
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.6.0 ; extra == "doc"
37
- Requires-Dist: pypandoc==1.12 ; extra == "doc"
38
- Requires-Dist: pytest-sphinx==0.6.0 ; extra == "doc"
39
- Requires-Dist: Sphinx==7.2.6 ; extra == "doc"
40
- Requires-Dist: sphinx-autobuild==2024.2.4 ; extra == "doc"
41
- Requires-Dist: sphinx-autodoc-typehints==1.25.2 ; extra == "doc"
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.15.0 ; extra == "doc"
44
- Requires-Dist: sphinx-notfound-page==1.0.0 ; extra == "doc"
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.2.6 ; extra == "style"
50
- Requires-Dist: flake8==7.0.0 ; extra == "style"
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
- * ``AWP_ROOT241``
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 ``AWP_ROOT241`` is set.
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.)