Skip to content

Commit 7d5fb2f

Browse files
committed
clean up
1 parent a547bc1 commit 7d5fb2f

File tree

2 files changed

+99
-48
lines changed

2 files changed

+99
-48
lines changed

waveform_editor/gui/shape_editor.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import xml.etree.ElementTree as ET
33

44
import imas
5-
import numpy as np
65
import panel as pn
76
import param
87
from imas.ids_toplevel import IDSToplevel

waveform_editor/shape_editor/coil_currents.py

Lines changed: 99 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
from panel.viewable import Viewer
77

88
from waveform_editor.derived_waveform import DerivedWaveform
9-
from waveform_editor.tendencies.linear import LinearTendency
109
from waveform_editor.tendencies.piecewise import PiecewiseLinearTendency
11-
from waveform_editor.waveform import Waveform
1210

1311

1412
class CoilCurrents(Viewer):
1513
coil_ui = param.List(
1614
doc="List of tuples containing the checkboxes and sliders for the coil currents"
1715
)
18-
export_time = param.Number(doc="Time to export coil currents to")
16+
export_time = param.Number(
17+
doc="Select a time at which coil currents will be saved to waveforms"
18+
)
1919

2020
def __init__(self, main_gui):
2121
super().__init__()
@@ -36,19 +36,17 @@ def __init__(self, main_gui):
3636
confirm_button = pn.widgets.Button(
3737
on_click=lambda event: self._store_coil_currents(),
3838
name="Save Currents as Waveforms",
39-
margin=30,
39+
margin=(30, 0, 0, 0),
4040
)
4141
self.panel = pn.Column(
42-
pn.Row(export_time_input, confirm_button, no_ids_message),
42+
pn.Row(
43+
export_time_input, confirm_button, visible=self.param.coil_ui.rx.bool()
44+
),
45+
no_ids_message,
4346
guide_message,
4447
self.sliders_ui,
45-
self.modal,
4648
)
4749

48-
def _open_modal(self):
49-
self._coil_currents_valid()
50-
self.modal.show()
51-
5250
@param.depends("export_time", watch=True)
5351
def _coil_currents_valid(self):
5452
self.coil_export_valid = True
@@ -95,65 +93,119 @@ def create_ui(self, pf_active):
9593
self.coil_ui = new_coil_ui
9694

9795
def _store_coil_currents(self):
96+
"""Store the current values from the coil UI sliders into the waveform
97+
configuration.
98+
"""
9899
coil_currents = self._get_currents()
99100
config = self.main_gui.config
100101
new_waveforms_created = False
102+
group_name = "Coil Currents"
101103

102-
for i in range(len(self.coil_ui)):
103-
name = f"pf_active/coil({i + 1})/current/data"
104-
if name in self.main_gui.config.waveform_map:
105-
tendencies = self.main_gui.config[name].tendencies
106-
if tendencies:
107-
end_time = tendencies[-1].end
108-
if end_time >= self.export_time:
109-
pn.state.notifications.error(
110-
"Export time must be later than the end of any existing waveforms"
111-
)
112-
return
104+
if not self._has_valid_export_time():
105+
return
113106

114107
for i, current in enumerate(coil_currents):
115108
name = f"pf_active/coil({i + 1})/current/data"
116-
eps = 1e-100
117-
# Piecewise tendencies must contain at least two points
118-
new_piecewise = f"- {{type: piecewise, time: [{self.export_time}, {self.export_time + eps}], value: [{current}, {current}]}}"
119-
if not name in config.waveform_map:
120-
group_name = "Coil Currents"
109+
if name not in config.waveform_map:
121110
if group_name not in config.groups:
122111
config.add_group(group_name, [])
123-
waveform = config.parser.parse_waveform(f"{name}:\n{new_piecewise}")
124-
config.add_waveform(waveform, [group_name])
112+
self._create_new_waveform(config, name, current, group_name)
125113
new_waveforms_created = True
126114
else:
127115
waveform = config[name]
128116
if isinstance(waveform, DerivedWaveform):
129-
pn.state.error(
130-
f"Could not store coil current in {name}, because it is a derived waveform"
117+
pn.state.notifications.error(
118+
f"Could not store coil current in waveform {name!r}, "
119+
"because it is a derived waveform"
131120
)
132121
continue
133-
134-
last_tendency = waveform.tendencies[-1]
135-
if isinstance(last_tendency, PiecewiseLinearTendency):
136-
waveform.yaml[-1]["time"].append(float(self.export_time))
137-
waveform.yaml[-1]["value"].append(float(current))
138-
yaml_str = f"{name}:\n{waveform.get_yaml_string()}"
139-
else:
140-
end = waveform.tendencies[-1].end
141-
append_new_piecewise = f"- {{type: piecewise, time: [{end}, {self.export_time}], value: [{current}, {current}]}}"
142-
yaml_str = (
143-
f"{name}:\n{waveform.get_yaml_string()}{append_new_piecewise}"
144-
)
145-
new_waveform = config.parse_waveform(yaml_str)
146-
config.replace_waveform(new_waveform)
122+
self._append_to_existing_waveform(config, name, current)
147123

148124
if new_waveforms_created:
149125
self.main_gui.selector.refresh()
150126
pn.state.notifications.warning(
151-
f"Could not find an existing waveform to store the coil current. A new waveform is created in the {group_name!r} group"
127+
"Could not find an existing waveform to store the coil current. "
128+
f"New waveform(s) are created in the {group_name!r} group"
152129
)
153130
else:
154131
pn.state.notifications.success(
155-
"The coil currents were appended to their respective waveforms."
132+
"The values of the coil currents were appended to their respective "
133+
"waveforms."
134+
)
135+
136+
def _append_to_existing_waveform(self, config, name, current):
137+
"""Append coil current value to an existing waveform. If the last tendency is a
138+
piecewise tendency, it is extended, otherwise a new piecewise tendency
139+
is added.
140+
141+
Args:
142+
config: The waveform configuration.
143+
name: Name of the waveform.
144+
current: Coil current value to append.
145+
"""
146+
waveform = config[name]
147+
last_tendency = waveform.tendencies[-1]
148+
149+
# Either append to existing piecewise linear tendency, or create new
150+
# piecewise linear tendency
151+
if isinstance(last_tendency, PiecewiseLinearTendency):
152+
waveform.yaml[-1]["time"].append(float(self.export_time))
153+
waveform.yaml[-1]["value"].append(float(current))
154+
yaml_str = f"{name}:\n{waveform.get_yaml_string()}"
155+
else:
156+
end = waveform.tendencies[-1].end
157+
new_piecewise = (
158+
f"- {{type: piecewise, time: [{end}, {self.export_time}], "
159+
f"value: [{current}, {current}]}}"
156160
)
161+
yaml_str = f"{name}:\n{waveform.get_yaml_string()}{new_piecewise}"
162+
163+
new_waveform = config.parse_waveform(yaml_str)
164+
config.replace_waveform(new_waveform)
165+
166+
def _create_new_waveform(self, config, name, current, group_name):
167+
"""Create a new waveform for a coil current when none exists.
168+
169+
Args:
170+
config: The waveform configuration.
171+
name: Name of the waveform.
172+
current: Coil current value to append.
173+
group_name: Name of the group to place the new waveform in.
174+
"""
175+
# Piecewise tendencies must contain at least two points
176+
eps = 1e-9
177+
new_piecewise = (
178+
f"- {{type: piecewise, time: [{self.export_time - eps}, "
179+
f"{self.export_time}], value: [{current}, {current}]}}"
180+
)
181+
waveform = config.parser.parse_waveform(f"{name}:\n{new_piecewise}")
182+
config.add_waveform(waveform, [group_name])
183+
184+
def _has_valid_export_time(self):
185+
"""Check whether the export time is later than the last tendency endpoint
186+
in all existing coil current waveforms.
187+
188+
Returns:
189+
True if export time is valid, False otherwise.
190+
"""
191+
latest_time = None
192+
for i in range(len(self.coil_ui)):
193+
name = f"pf_active/coil({i + 1})/current/data"
194+
if name in self.main_gui.config.waveform_map:
195+
tendencies = self.main_gui.config[name].tendencies
196+
if tendencies:
197+
end_time = tendencies[-1].end
198+
if latest_time is None or end_time > latest_time:
199+
latest_time = end_time
200+
201+
if latest_time is not None and latest_time >= self.export_time:
202+
pn.state.notifications.error(
203+
f"Invalid export time: {self.export_time}. It must be greater than the "
204+
f"last endpoint of existing coil current waveforms ({latest_time})."
205+
)
206+
return False
207+
208+
return True
157209

158210
def fill_pf_active(self, pf_active):
159211
"""Update the coil currents of the provided pf_active IDS. Only coils with
@@ -168,11 +220,11 @@ def fill_pf_active(self, pf_active):
168220
pf_active.coil[i].current.data = np.array([slider.value])
169221

170222
def _get_currents(self):
223+
"""Returns the coil current values in a list."""
171224
coil_currents = []
172225
for coil_ui in self.coil_ui:
173226
_, slider = coil_ui.objects
174227
coil_currents.append(slider.value)
175-
176228
return coil_currents
177229

178230
def sync_ui_with_pf_active(self, pf_active):

0 commit comments

Comments
 (0)