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,92 @@
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 threading
24
+ from typing import Callable
25
+
26
+ from ansys.systemcoupling.core.charts.csv_chartdata import CsvChartDataReader
27
+ from ansys.systemcoupling.core.charts.live_csv_datasource import LiveCsvDataSource
28
+ from ansys.systemcoupling.core.charts.message_dispatcher import MessageDispatcher
29
+ from ansys.systemcoupling.core.charts.plotdefinition_manager import (
30
+ PlotDefinitionManager,
31
+ PlotSpec,
32
+ )
33
+ from ansys.systemcoupling.core.charts.plotter import Plotter
34
+
35
+
36
+ def create_and_show_plot(spec: PlotSpec, csv_list: list[str]) -> Plotter:
37
+ assert len(spec.interfaces) == 1, "Plots currently only support one interface"
38
+ assert len(spec.interfaces) == len(csv_list)
39
+
40
+ manager = PlotDefinitionManager(spec)
41
+ reader = CsvChartDataReader(spec.interfaces[0].name, csv_list[0])
42
+ plotter = Plotter(manager)
43
+
44
+ reader.read_metadata()
45
+ plotter.set_metadata(reader.metadata)
46
+
47
+ reader.read_new_data()
48
+ data = reader.data
49
+ if reader.metadata.is_transient:
50
+ plotter.set_timestep_data(reader.timestep_data)
51
+
52
+ for line_series in data.series:
53
+ plotter.update_line_series(line_series)
54
+
55
+ plotter.show_plot(noblock=True)
56
+ return plotter
57
+
58
+
59
+ def solve_with_live_plot(
60
+ spec: PlotSpec,
61
+ csv_list: list[str],
62
+ solve_func: Callable[[], None],
63
+ ):
64
+ assert len(spec.interfaces) == 1, "Plots currently only support one interface"
65
+ assert len(spec.interfaces) == len(csv_list)
66
+
67
+ manager = PlotDefinitionManager(spec)
68
+ dispatcher = MessageDispatcher()
69
+ plotter = Plotter(manager, dispatcher.dispatch_messages)
70
+ dispatcher.set_plotter(plotter)
71
+
72
+ data_source = LiveCsvDataSource(
73
+ spec.interfaces[0].name, csv_list[0], dispatcher.put_msg
74
+ )
75
+ data_thread = threading.Thread(target=data_source.read_data)
76
+
77
+ def solve():
78
+ solve_func()
79
+ data_source.cancel()
80
+
81
+ solve_thread = threading.Thread(target=solve)
82
+
83
+ data_thread.start()
84
+ solve_thread.start()
85
+
86
+ plotter.show_animated()
87
+ data_source.cancel()
88
+ data_thread.join()
89
+ solve_thread.join()
90
+
91
+ # Show a non-blocking static plot
92
+ return create_and_show_plot(spec, csv_list)
@@ -0,0 +1,303 @@
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
+ from dataclasses import dataclass, field
24
+ from typing import Optional
25
+
26
+ from ansys.systemcoupling.core.charts.chart_datatypes import InterfaceInfo, SeriesType
27
+
28
+
29
+ @dataclass
30
+ class DataTransferSpec:
31
+ # It's not ideal, but we have to work in terms of display names for transfers,
32
+ # as that is all we have in the data (the CSV data, at least).
33
+ display_name: str
34
+ show_convergence: bool = True
35
+ show_transfer_values: bool = True
36
+
37
+
38
+ @dataclass
39
+ class InterfaceSpec:
40
+ name: str
41
+ display_name: str
42
+ transfers: list[DataTransferSpec] = field(default_factory=list)
43
+
44
+
45
+ @dataclass
46
+ class PlotSpec:
47
+ interfaces: list[InterfaceSpec] = field(default_factory=list)
48
+ plot_time: bool = False
49
+
50
+
51
+ """
52
+ Convergence subplot:
53
+ title - Data Transfer Convergence for <interface disp name>
54
+ x-axis label - Iteration/Time
55
+ y-axis label - RMS Change in Target Value
56
+
57
+ # x-data: []
58
+ y-data: [([], <label=transfer disp name>)]
59
+
60
+ # y-data - we actually want an index
61
+
62
+
63
+ Transfer values subplot:
64
+ title - <interface display name> - <transfer display name> (<value type>)
65
+ x-axis label: Iteration/time
66
+ y-axis label: <NOT SET>
67
+
68
+ y-data: [([], <label=source|tgt disp name + suffix)]
69
+
70
+ """
71
+
72
+
73
+ @dataclass
74
+ class SubplotDefinition:
75
+ """Various data - mainly title and label strings - used in the rendering of
76
+ a subplot.
77
+
78
+ Attributes
79
+ ----------
80
+ title: str
81
+ The title of the subplot.
82
+ is_log_y: bool
83
+ Whether the y-axis is logarithmic.
84
+ x_axis_label: str
85
+ The label shown on the x-axis.
86
+ y_axis_label: str
87
+ The label shown on the y-axis. This is an empty string for convergence plots.
88
+ index: int = -1
89
+ The index of this subplot within the list of subplots in the current figure.
90
+ (In `matplotlib` terms it also indexes the corresponding ``Axes`` item in
91
+ the figure.)
92
+ series_labels: list[str] = field(default_factory=list)
93
+ Labels for each series of the subplot.
94
+ """
95
+
96
+ title: str
97
+ is_log_y: bool
98
+ x_axis_label: str
99
+ y_axis_label: str
100
+ index: int = -1
101
+ series_labels: list[str] = field(default_factory=list)
102
+
103
+
104
+ class PlotDefinitionManager:
105
+ def __init__(self, spec: PlotSpec):
106
+ self._plot_spec = spec
107
+ self._data_index_map: dict[str, dict[int, tuple[SubplotDefinition, int]]] = {}
108
+ self._conv_subplots: dict[str, SubplotDefinition] = {}
109
+ self._transfer_subplots: dict[tuple[str, str, int], SubplotDefinition] = {}
110
+ self._subplots: list[SubplotDefinition] = []
111
+ self._allocate_subplots()
112
+
113
+ @property
114
+ def subplots(self) -> list[SubplotDefinition]:
115
+ return self._subplots
116
+
117
+ def subplot_for_data_index(
118
+ self, interface_name: str, data_index: int
119
+ ) -> tuple[Optional[SubplotDefinition], int]:
120
+ """Return the subplot definition, and the line index within the
121
+ subplot, corresponding to a given ``data_index``.
122
+
123
+ The ``data_index`` is a "global" line index for the interface.
124
+
125
+ If there is no subplot corresponding to the provided index,
126
+ return a tuple ``(None, -1)``
127
+ """
128
+ try:
129
+ return self._data_index_map[interface_name][data_index]
130
+ except KeyError:
131
+ return (None, -1)
132
+
133
+ def get_layout(self) -> tuple[int, int]:
134
+ nsubplot = len(self._subplots)
135
+
136
+ if nsubplot == 1:
137
+ ncol = 1
138
+ elif nsubplot < 6:
139
+ ncol = 2
140
+ elif nsubplot < 12:
141
+ ncol = 3
142
+ elif nsubplot < 18:
143
+ ncol = 4
144
+ elif nsubplot < 26:
145
+ ncol = 5
146
+ else:
147
+ raise ValueError(f"Too many subplots requested: {nsubplot}")
148
+ nrow = nsubplot // ncol
149
+ if nsubplot % ncol != 0:
150
+ nrow += 1
151
+
152
+ return (nrow, ncol)
153
+
154
+ def _allocate_subplots(self):
155
+ is_time = self._plot_spec.plot_time
156
+ conv_subplots = {}
157
+ transfer_subplots = {}
158
+ subplots = []
159
+ for interface in self._plot_spec.interfaces:
160
+ conv = SubplotDefinition(
161
+ title=f"Data transfer convergence on {interface.display_name}",
162
+ is_log_y=True,
163
+ x_axis_label="Time" if is_time else "Iteration",
164
+ y_axis_label="RMS Change in target value",
165
+ )
166
+ # Add this now so that it is before transfer values plots but we may end
167
+ # up removing it if none of the transfers add a convergence line to it
168
+ conv_index = len(subplots)
169
+ subplots.append(conv)
170
+ keep_conv = False
171
+ transfer_disambig: dict[str, int] = {}
172
+ for transfer in interface.transfers:
173
+ if transfer.display_name in transfer_disambig:
174
+ transfer_disambig[transfer.display_name] += 1
175
+ else:
176
+ transfer_disambig[transfer.display_name] = 0
177
+ if transfer.show_convergence:
178
+ keep_conv = True
179
+ if transfer.show_transfer_values:
180
+ transfer_value = SubplotDefinition(
181
+ # NB: <VALUETYPE> is a placeholder - substitute later from metadata info
182
+ title=f"{interface.display_name} - {transfer.display_name} (<VALUETYPE>)",
183
+ is_log_y=False,
184
+ x_axis_label="Time" if is_time else "Iteration",
185
+ y_axis_label="",
186
+ )
187
+ transfer_subplots[
188
+ (
189
+ interface.name,
190
+ transfer.display_name,
191
+ transfer_disambig[transfer.display_name],
192
+ )
193
+ ] = transfer_value
194
+ subplots.append(transfer_value)
195
+ if keep_conv:
196
+ conv_subplots[interface.name] = conv
197
+ else:
198
+ subplots[conv_index] = None
199
+ # Clean out inactive convergence plots
200
+ self._subplots = [subplot for subplot in subplots if subplot is not None]
201
+ for i, subplot in enumerate(self._subplots):
202
+ subplot.index = i
203
+ self._conv_subplots: dict[str, SubplotDefinition] = conv_subplots
204
+ self._transfer_subplots: dict[tuple[str, str, int], SubplotDefinition] = (
205
+ transfer_subplots
206
+ )
207
+
208
+ def set_metadata(self, metadata: InterfaceInfo):
209
+ """Reconcile the metadata for a single interface with the pre-allocated
210
+ sub-plots and set up any necessary data routing.
211
+
212
+ Typically, this data only starts to be provided once the raw plot data starts
213
+ being generated.
214
+ """
215
+
216
+ # If a subset of transfers was specified in the plot spec, this is already
217
+ # implicitly accounted for in self._tranfer_subplots, which will contain only
218
+ # the active ones. However, some additional work has to be done to filter the
219
+ # transfers shown on the convergence subplot and we have to go back to the plot
220
+ # spec to get a list of active transfers.
221
+ active_transfers = []
222
+ for intf in self._plot_spec.interfaces:
223
+ if intf.name == metadata.name:
224
+ active_transfers = [trans.display_name for trans in intf.transfers]
225
+ break
226
+ if not active_transfers:
227
+ # TODO: should this be an exception?
228
+ return
229
+
230
+ # map from source data index to corresponding (subplot, line index within subplot)
231
+ data_index_map: dict[int, tuple[SubplotDefinition, int]] = {}
232
+ interface_name = metadata.name
233
+ iconv = 0
234
+
235
+ # Keep a running count of the transfer value lines associated with a given
236
+ # transfer. There will be multiple if the transfer variable has vector
237
+ # and or real/imag components. Note that a transfer is uniquely identified by a
238
+ # pair (transfer_name, int) because transfer names are not guaranteed to be unique.
239
+ # The integer is the "disambiguation_index" the transfer's TransferSeriesInfo.
240
+ transfer_value_line_count: dict[tuple[str, int], int] = {}
241
+
242
+ for transfer in metadata.transfer_info:
243
+ transfer_key = (
244
+ transfer.transfer_display_name,
245
+ transfer.disambiguation_index,
246
+ )
247
+ if transfer.series_type == SeriesType.CONVERGENCE:
248
+ if transfer.transfer_display_name not in active_transfers:
249
+ # We don't want this transfer on the convergence plot
250
+ continue
251
+ # Clear the entry in case transfer names are not unique. (If another transfer
252
+ # with the same name needs plotting, then it should appear as a second entry
253
+ # in active_transfers.)
254
+ active_transfers[
255
+ active_transfers.index(transfer.transfer_display_name)
256
+ ] = ""
257
+
258
+ if conv_subplot := self._conv_subplots.get(interface_name):
259
+ data_index_map[transfer.data_index] = (conv_subplot, iconv)
260
+ # Add a new series list to y_data, and label to series_labels
261
+ # Both will be at position iconv of respective lists
262
+ # conv_subplot.y_data.append([])
263
+ conv_subplot.series_labels.append(transfer.transfer_display_name)
264
+ iconv += 1
265
+ else:
266
+ transfer_value_subplot = self._transfer_subplots.get(
267
+ (interface_name, transfer_key[0], transfer_key[1])
268
+ )
269
+ if transfer_value_subplot:
270
+ value_type = (
271
+ "Sum"
272
+ if transfer.series_type == SeriesType.SUM
273
+ else "Weighted Average"
274
+ )
275
+ transfer_value_subplot.title = transfer_value_subplot.title.replace(
276
+ "<VALUETYPE>", value_type
277
+ )
278
+ itransval = transfer_value_line_count.get(transfer_key, 0)
279
+ if not transfer.line_suffixes:
280
+ data_index_map[transfer.data_index] = (
281
+ transfer_value_subplot,
282
+ itransval,
283
+ )
284
+ transfer_value_subplot.series_labels.append(
285
+ transfer.participant_display_name
286
+ )
287
+ itransval += 1
288
+ transfer_value_line_count[transfer_key] = itransval
289
+ else:
290
+ for i, suffix in enumerate(transfer.line_suffixes):
291
+ data_index_map[transfer.data_index + i] = (
292
+ transfer_value_subplot,
293
+ itransval + i,
294
+ )
295
+ transfer_value_subplot.series_labels.append(
296
+ transfer.participant_display_name + suffix
297
+ )
298
+ transfer_value_line_count[transfer_key] = itransval + len(
299
+ transfer.line_suffixes
300
+ )
301
+
302
+ # This will be what allows us to update subplot data as new data received
303
+ self._data_index_map[interface_name] = data_index_map