Skip to content

Commit a4e728b

Browse files
committed
clean up/isolate CSV-specific disambiguation
1 parent 3be0013 commit a4e728b

File tree

6 files changed

+58
-58
lines changed

6 files changed

+58
-58
lines changed

src/ansys/systemcoupling/core/adaptor/impl/injected_commands.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,12 @@ def _create_plot_spec(
228228
continue
229229
intf_spec = InterfaceSpec(interface_name, interface_disp_name)
230230
spec.interfaces.append(intf_spec)
231-
transfer_disp_names = [
232-
interface_object.data_transfer[trans_name].display_name
233-
for trans_name in transfer_names
234-
]
235-
for transfer in transfer_disp_names:
231+
for trans_name in transfer_names:
232+
disp_name = interface_object.data_transfer[trans_name].display_name
236233
intf_spec.transfers.append(
237234
DataTransferSpec(
238-
display_name=transfer,
235+
name=trans_name,
236+
display_name=disp_name,
239237
show_convergence=show_convergence,
240238
show_transfer_values=show_transfer_values,
241239
)

src/ansys/systemcoupling/core/charts/chart_datatypes.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates.
1+
# Copyright (C) 2023 - 2026 ANSYS, Inc. and/or its affiliates.
22
# SPDX-License-Identifier: MIT
33
#
44
#
@@ -22,7 +22,6 @@
2222

2323
from dataclasses import dataclass, field
2424
from enum import Enum
25-
from typing import Optional
2625

2726
"""Common data types for the storage of metadata and data for chart series.
2827
@@ -51,10 +50,10 @@ class TransferSeriesInfo:
5150
The display name of the data transfer. This is a primary identifier for data
5251
transfers because CSV data sources do not currently include information about
5352
the underlying data model names of data transfers.
54-
disambiguation_index: int
55-
This should be set to 0, unless there is more than one data transfer with the
56-
same display name. A contiguous range of indexes starting at 0 should be assigned
57-
to the list of data transfers with the same display name.
53+
transfer_id : str
54+
The internal unique identifier of the data transfer. This could be the internal
55+
datamodel name. In the CSV case, the internal name cannot be determined from the
56+
data, so an ID based on the display name and an integer suffix is used.
5857
participant_display_name : str, optional
5958
The display name of the participant. This is required for transfer value series
6059
but not for convergence series.
@@ -68,10 +67,10 @@ class TransferSeriesInfo:
6867

6968
series_type: SeriesType
7069
transfer_display_name: str
71-
disambiguation_index: int
70+
transfer_id: str
7271
# Remainder for non-CONVERGENCE series only
73-
participant_display_name: Optional[str] = None
74-
component_suffix: Optional[str] = None
72+
participant_display_name: str | None = None
73+
component_suffix: str | None = None
7574

7675

7776
@dataclass

src/ansys/systemcoupling/core/charts/csv_chartdata.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def read_data(self) -> bool:
5656
return True # File exists - haven't necessarily read anything yet
5757
except FileNotFoundError:
5858
# It is expected that the file is not necessarily immediately available
59-
print(f"Failed to open {self._file_or_filename}")
59+
# print(f"Failed to open {self._file_or_filename}")
6060
return False
6161
except Exception as e:
6262
# Temporary - see if anything else goes wrong
@@ -234,7 +234,6 @@ def parse_csv_metadata(interface_name: str, headers: list[str]) -> InterfaceInfo
234234
intf_info.is_transient = headers[2] == "Time"
235235

236236
start_index = 3 if intf_info.is_transient else 2
237-
prev_part_name = ""
238237

239238
transfer_disambig: dict[str, int] = {}
240239
for i in range(start_index, len(headers)):
@@ -265,8 +264,7 @@ def parse_csv_metadata(interface_name: str, headers: list[str]) -> InterfaceInfo
265264
series_info = TransferSeriesInfo(
266265
series_type=series_type,
267266
transfer_display_name=trans_disp_name,
268-
# get(..., 0) for case where transfer_disambig empty (see note above)
269-
disambiguation_index=transfer_disambig.get(trans_disp_name, 0),
267+
transfer_id=f"{trans_disp_name}:{transfer_disambig.get(trans_disp_name, 0)}",
270268
)
271269
intf_info.transfer_info.append(series_info)
272270
else:
@@ -275,7 +273,7 @@ def parse_csv_metadata(interface_name: str, headers: list[str]) -> InterfaceInfo
275273
TransferSeriesInfo(
276274
series_type=series_type,
277275
transfer_display_name=trans_disp_name,
278-
disambiguation_index=transfer_disambig.get(trans_disp_name, 0),
276+
transfer_id=f"{trans_disp_name}:{transfer_disambig.get(trans_disp_name, 0)}",
279277
participant_display_name=part_disp_name,
280278
component_suffix=_parse_suffix(header, part_disp_name) or None,
281279
)

src/ansys/systemcoupling/core/charts/plot_functions.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ def cancel(self) -> None: ...
5454
def read_data(self) -> None: ...
5555

5656

57-
def _create_and_show_impl(spec: PlotSpec, readers: list[ChartDataReader]) -> Plotter:
58-
manager = PlotDefinitionManager(spec)
57+
def _create_and_show_impl(
58+
spec: PlotSpec, readers: list[ChartDataReader], is_csv_source: bool = False
59+
) -> Plotter:
60+
manager = PlotDefinitionManager(spec, is_csv_source=is_csv_source)
5961
plotter = Plotter(manager)
6062

6163
for ireader, reader in enumerate(readers):
@@ -89,15 +91,16 @@ def create_and_show_plot_csv(spec: PlotSpec, csv_list: list[str]) -> Plotter:
8991
CsvChartDataReader(intf.name, csvfile)
9092
for intf, csvfile in zip(spec.interfaces, csv_list)
9193
]
92-
return _create_and_show_impl(spec, readers)
94+
return _create_and_show_impl(spec, readers, is_csv_source=True)
9395

9496

9597
def _solve_with_live_plot_impl(
9698
spec,
9799
make_live_data_source: Callable[[str, Callable], LiveDataSource],
98100
solve_func: Callable[[], None],
101+
is_csv_source: bool = False,
99102
):
100-
manager = PlotDefinitionManager(spec)
103+
manager = PlotDefinitionManager(spec, is_csv_source=is_csv_source)
101104
dispatcher = MessageDispatcher()
102105
plotter = Plotter(manager, request_update=dispatcher.dispatch_messages)
103106
dispatcher.set_plotter(plotter)
@@ -138,6 +141,7 @@ def solve_with_live_plot_csv(
138141
interface_names, csv_list, put_msg
139142
),
140143
solve_func,
144+
is_csv_source=True,
141145
)
142146

143147
# Show a non-blocking static plot

src/ansys/systemcoupling/core/charts/plotdefinition_manager.py

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
# SOFTWARE.
2222

2323
from dataclasses import dataclass, field
24-
from typing import Optional
2524

2625
from ansys.systemcoupling.core.charts.chart_datatypes import InterfaceInfo, SeriesType
2726

@@ -31,6 +30,7 @@ class DataTransferSpec:
3130
# It's not ideal, but we have to work in terms of display names for transfers,
3231
# as that is all we have in the data (the CSV data, at least).
3332
# TODO: add optional internal name field which we will use if provided.
33+
name: str
3434
display_name: str
3535
show_convergence: bool = True
3636
show_transfer_values: bool = True
@@ -100,12 +100,15 @@ class SubplotDefinition:
100100

101101

102102
class SubplotManager:
103-
def __init__(self, is_transient: bool, intf_spec: InterfaceSpec):
103+
def __init__(
104+
self, is_transient: bool, intf_spec: InterfaceSpec, is_csv_source: bool = False
105+
):
104106
self._is_time: bool = is_transient
105107
self._intf_spec = intf_spec
108+
self._is_csv_source = is_csv_source
106109

107110
self._conv_subplot: SubplotDefinition | None = None
108-
self._transfer_subplots: dict[tuple[str, int], SubplotDefinition] = {}
111+
self._transfer_subplots: dict[str, SubplotDefinition] = {}
109112
self._subplots: list[SubplotDefinition] = []
110113
self._data_index_map: dict[int, tuple[SubplotDefinition, int]] = {}
111114
self._allocate_subplots()
@@ -116,7 +119,7 @@ def subplots(self) -> list[SubplotDefinition]:
116119

117120
def subplot_for_data_index(
118121
self, data_index: int
119-
) -> tuple[Optional[SubplotDefinition], int]:
122+
) -> tuple[SubplotDefinition | None, int]:
120123
"""Return the subplot definition, and the line index within the
121124
subplot, corresponding to a given ``data_index``.
122125
@@ -166,10 +169,16 @@ def _allocate_subplots(self):
166169
keep_conv = False
167170
transfer_disambig: dict[str, int] = {}
168171
for transfer in self._intf_spec.transfers:
169-
if transfer.display_name in transfer_disambig:
170-
transfer_disambig[transfer.display_name] += 1
171-
else:
172-
transfer_disambig[transfer.display_name] = 0
172+
if self._is_csv_source:
173+
# In the CSV case, we have to create a unique ID for each transfer
174+
# based on display name and an integer suffix, because we don't
175+
# have internal names in the data. 'transfer_disambig' keeps track of
176+
# how many times we've seen a given display name so far and we use that
177+
# to create the unique ID.
178+
if transfer.display_name in transfer_disambig:
179+
transfer_disambig[transfer.display_name] += 1
180+
else:
181+
transfer_disambig[transfer.display_name] = 0
173182
if transfer.show_convergence:
174183
keep_conv = True
175184
if transfer.show_transfer_values:
@@ -180,12 +189,12 @@ def _allocate_subplots(self):
180189
x_axis_label="Time" if self._is_time else "Iteration",
181190
y_axis_label="",
182191
)
183-
transfer_subplots[
184-
(
185-
transfer.display_name,
186-
transfer_disambig[transfer.display_name],
187-
)
188-
] = transfer_value
192+
if self._is_csv_source:
193+
disambig = transfer_disambig.get(transfer.display_name, 0)
194+
transfer_id = f"{transfer.display_name}:{disambig}"
195+
else:
196+
transfer_id = transfer.name
197+
transfer_subplots[transfer_id] = transfer_value
189198
subplots.append(transfer_value)
190199
if keep_conv:
191200
self._conv_subplot = conv
@@ -194,9 +203,7 @@ def _allocate_subplots(self):
194203
self._subplots = [subplot for subplot in subplots if subplot is not None]
195204
for i, subplot in enumerate(self._subplots):
196205
subplot.index = i
197-
self._transfer_subplots: dict[tuple[str, int], SubplotDefinition] = (
198-
transfer_subplots
199-
)
206+
self._transfer_subplots: dict[str, SubplotDefinition] = transfer_subplots
200207

201208
def set_metadata(self, metadata: InterfaceInfo):
202209
"""Reconcile the metadata for a single interface with the pre-allocated
@@ -231,10 +238,7 @@ def set_metadata(self, metadata: InterfaceInfo):
231238
transfer_value_line_count: dict[tuple[str, int], int] = {}
232239

233240
for data_index, transfer in enumerate(metadata.transfer_info):
234-
transfer_key = (
235-
transfer.transfer_display_name,
236-
transfer.disambiguation_index,
237-
)
241+
transfer_key = transfer.transfer_id
238242
if transfer.series_type == SeriesType.CONVERGENCE:
239243
if transfer.transfer_display_name not in active_transfers:
240244
# We don't want this transfer on the convergence plot
@@ -252,9 +256,7 @@ def set_metadata(self, metadata: InterfaceInfo):
252256
self._conv_subplot.series_labels.append(transfer.transfer_display_name)
253257
iconv += 1
254258
else:
255-
transfer_value_subplot = self._transfer_subplots.get(
256-
(transfer_key[0], transfer_key[1])
257-
)
259+
transfer_value_subplot = self._transfer_subplots.get(transfer_key)
258260
if transfer_value_subplot:
259261
value_type = (
260262
"Sum"
@@ -282,14 +284,16 @@ def set_metadata(self, metadata: InterfaceInfo):
282284

283285

284286
class PlotDefinitionManager:
285-
def __init__(self, spec: PlotSpec):
287+
def __init__(self, spec: PlotSpec, is_csv_source: bool = False):
286288
self._subplot_mgrs: dict[str, SubplotManager] = {}
287-
self._init(spec)
289+
self._init(spec, is_csv_source)
288290

289-
def _init(self, spec: PlotSpec):
291+
def _init(self, spec: PlotSpec, is_csv_source: bool):
290292
is_time = spec.plot_time
291293
for interface in spec.interfaces:
292-
self._subplot_mgrs[interface.name] = SubplotManager(is_time, interface)
294+
self._subplot_mgrs[interface.name] = SubplotManager(
295+
is_time, interface, is_csv_source
296+
)
293297

294298
@property
295299
def interface_names(self) -> list[str]:

src/ansys/systemcoupling/core/charts/plotter.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
SubplotManager,
4040
)
4141
from ansys.systemcoupling.core.util.assertion import assert_
42-
from ansys.systemcoupling.core.util.logging import LOG
42+
43+
# from ansys.systemcoupling.core.util.logging import LOG
4344

4445

4546
def _process_timestep_data(
@@ -290,18 +291,14 @@ def show_animated(self):
290291
self._animation = FuncAnimation(
291292
self._fig,
292293
self._update_animation,
293-
# frames=x_axis_pts,
294294
save_count=sys.maxsize,
295-
# init_func=self._init_plots,
296295
blit=False,
297296
interval=200,
298297
repeat=False,
299298
)
300-
# plt.show()
301299

302300
def _update_animation(self, frame: int):
303-
# print("calling update animation")
304-
LOG.debug("FigurePlotter updating animation frame: %s", frame)
301+
# LOG.debug("FigurePlotter updating animation frame: %s", frame)
305302
return self._request_update()
306303

307304
def _init_plots(self):

0 commit comments

Comments
 (0)