Skip to content

Commit d865f4e

Browse files
committed
refactor settings
1 parent 1034d0a commit d865f4e

File tree

4 files changed

+60
-49
lines changed

4 files changed

+60
-49
lines changed

waveform_editor/gui/shape_editor.py

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,18 @@ class ShapeEditor(Viewer):
3131
pf_passive = param.ClassSelector(class_=IDSToplevel)
3232
wall = param.ClassSelector(class_=IDSToplevel)
3333
iron_core = param.ClassSelector(class_=IDSToplevel)
34-
nice_mode = param.Selector(
35-
objects=[NiceSettings.INVERSE_MODE, NiceSettings.DIRECT_MODE],
36-
default=NiceSettings.INVERSE_MODE,
37-
)
3834

3935
def __init__(self):
4036
super().__init__()
4137
self.factory = imas.IDSFactory()
4238
self.communicator = NiceIntegration(self.factory)
4339
self.plasma_shape = PlasmaShape()
4440
self.plasma_properties = PlasmaProperties()
45-
self.coil_currents = CoilCurrents(nice_mode=self.param.nice_mode)
41+
self.coil_currents = CoilCurrents()
4642
self.nice_plotter = NicePlotter(
4743
communicator=self.communicator,
4844
plasma_shape=self.plasma_shape,
4945
plasma_properties=self.plasma_properties,
50-
nice_mode=self.param.nice_mode,
5146
)
5247
self.nice_settings = settings.nice
5348

@@ -67,30 +62,34 @@ def __init__(self):
6762
button_start.disabled = (
6863
(
6964
self.plasma_shape.param.has_shape.rx.not_()
70-
& (self.param.nice_mode.rx() == NiceSettings.INVERSE_MODE)
65+
& (
66+
self.nice_settings.param.mode.rx()
67+
== self.nice_settings.INVERSE_MODE
68+
)
7169
)
7270
| self.plasma_properties.param.has_properties.rx.not_()
73-
| param.rx(self.required_nice_settings_filled).rx.not_()
71+
| self.nice_settings.param.are_required_filled.rx.not_()
7472
)
7573
button_stop = pn.widgets.Button(name="Stop", on_click=self.stop_nice)
7674
nice_mode_radio = pn.widgets.RadioBoxGroup.from_param(
77-
self.param.nice_mode, inline=True, margin=(15, 20, 0, 20)
75+
self.nice_settings.param.mode, inline=True, margin=(15, 20, 0, 20)
7876
)
7977
buttons = pn.Row(button_start, button_stop, nice_mode_radio)
8078

8179
# Accordion does not allow dynamic titles, so use separate card for each option
8280
options = pn.Column(
8381
self._create_card(
84-
pn.bind(self.nice_settings.panel, nice_mode=self.param.nice_mode),
82+
self.nice_settings.panel,
8583
"NICE Configuration",
86-
is_valid=param.rx(self.required_nice_settings_filled),
84+
is_valid=self.nice_settings.param.are_required_filled.rx(),
8785
),
8886
self._create_card(self.nice_plotter, "Plotting Parameters"),
8987
self._create_card(
9088
self.plasma_shape,
9189
"Plasma Shape",
9290
is_valid=self.plasma_shape.param.has_shape,
93-
visible=self.param.nice_mode.rx() == NiceSettings.INVERSE_MODE,
91+
visible=self.nice_settings.param.mode.rx()
92+
== self.nice_settings.INVERSE_MODE,
9493
),
9594
self._create_card(
9695
pn.Column(self.plasma_properties, self.nice_plotter.profiles_pane),
@@ -111,26 +110,6 @@ def __init__(self):
111110
),
112111
)
113112

114-
@param.depends(
115-
"nice_mode",
116-
*(f"nice_settings.{p}" for p in NiceSettings.BASE_REQUIRED),
117-
"nice_settings.inv_executable",
118-
"nice_settings.dir_executable",
119-
)
120-
def required_nice_settings_filled(self):
121-
"""Checks if all required base settings and the mode-specific
122-
executable are filled."""
123-
base_ready = all(
124-
getattr(self.nice_settings, p) for p in self.nice_settings.BASE_REQUIRED
125-
)
126-
if not base_ready:
127-
return False
128-
129-
if self.nice_mode == NiceSettings.INVERSE_MODE:
130-
return bool(self.nice_settings.inv_executable)
131-
else:
132-
return bool(self.nice_settings.dir_executable)
133-
134113
def _create_card(self, panel_object, title, is_valid=None, visible=True):
135114
"""Create a collapsed card containing a panel object and a title.
136115
@@ -212,7 +191,7 @@ def _create_equilibrium(self):
212191
equilibrium.vacuum_toroidal_field.b0.resize(1)
213192

214193
# Only fill plasma shape for NICE inverse mode
215-
if self.nice_mode == NiceSettings.INVERSE_MODE:
194+
if self.nice_settings.mode == self.nice_settings.INVERSE_MODE:
216195
equilibrium.time_slice[0].boundary.outline.r = self.plasma_shape.outline_r
217196
equilibrium.time_slice[0].boundary.outline.z = self.plasma_shape.outline_z
218197

@@ -237,7 +216,7 @@ async def submit(self, event=None):
237216
description IDSs and an input equilibrium IDS."""
238217

239218
self.coil_currents.fill_pf_active(self.pf_active)
240-
if self.nice_mode == NiceSettings.DIRECT_MODE:
219+
if self.nice_settings.mode == self.nice_settings.DIRECT_MODE:
241220
xml_params = self.xml_params_dir
242221
else:
243222
xml_params = self.xml_params_inv
@@ -248,7 +227,9 @@ async def submit(self, event=None):
248227
equilibrium = self._create_equilibrium()
249228
if not self.communicator.running:
250229
await self.communicator.run(
251-
is_direct_mode=(self.nice_mode == NiceSettings.DIRECT_MODE)
230+
is_direct_mode=(
231+
self.nice_settings.mode == self.nice_settings.DIRECT_MODE
232+
)
252233
)
253234
await self.communicator.submit(
254235
ET.tostring(xml_params, encoding="unicode"),
@@ -260,7 +241,7 @@ async def submit(self, event=None):
260241
)
261242
self.coil_currents.sync_ui_with_pf_active(self.communicator.pf_active)
262243

263-
@param.depends("nice_mode", watch=True)
244+
@param.depends("nice_settings.mode", watch=True)
264245
async def stop_nice(self, event=None):
265246
logger.info("Stopping NICE...")
266247
await self.communicator.close()

waveform_editor/settings.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,25 @@ class NiceSettings(param.Parameterized):
4343
md_wall = param.String(label="'wall' machine description URI")
4444
md_iron_core = param.String(label="'iron_core' machine description URI")
4545
verbose = param.Integer(label="NICE verbosity (set to 1 for more verbose output)")
46+
mode = param.Selector(
47+
objects=[INVERSE_MODE, DIRECT_MODE], default=INVERSE_MODE, precedence=-1
48+
)
49+
are_required_filled = param.Boolean(precedence=-1)
50+
51+
@param.depends(
52+
*BASE_REQUIRED, "inv_executable", "dir_executable", "mode", watch=True
53+
)
54+
def check_required_params_filled(self):
55+
base_ready = all(getattr(self, p) for p in self.BASE_REQUIRED)
56+
57+
if not base_ready:
58+
self.are_required_filled = False
59+
return
60+
61+
if self.mode == self.INVERSE_MODE:
62+
self.are_required_filled = bool(self.inv_executable)
63+
else:
64+
self.are_required_filled = bool(self.dir_executable)
4665

4766
def apply_settings(self, params):
4867
"""Update parameters from a dictionary, skipping unknown keys."""
@@ -56,16 +75,16 @@ def to_dict(self):
5675
"""Returns a dictionary representation of current parameter values."""
5776
return {p: getattr(self, p) for p in self.param if p != "name"}
5877

59-
def panel(self, nice_mode):
78+
def panel(self):
6079
items = []
6180

6281
for p in self.param:
6382
if p == "name":
6483
continue
6584

6685
# Add warning indicator if required parameter is not filled
67-
is_inv_required = p == "inv_executable" and nice_mode == self.INVERSE_MODE
68-
is_dir_required = p == "dir_executable" and nice_mode == self.DIRECT_MODE
86+
is_inv_required = p == "inv_executable" and self.mode == self.INVERSE_MODE
87+
is_dir_required = p == "dir_executable" and self.mode == self.DIRECT_MODE
6988
is_base_required = p in self.BASE_REQUIRED
7089

7190
row_content = [pn.Param(self.param[p], show_name=False)]

waveform_editor/shape_editor/coil_currents.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
import param
66
from panel.viewable import Viewer
77

8-
from waveform_editor.settings import NiceSettings
8+
from waveform_editor.settings import settings
99

1010

1111
class CoilCurrents(Viewer):
1212
coil_ui = param.List(
1313
doc="List of tuples containing the checkboxes and sliders for the coil currents"
1414
)
15-
nice_mode = param.Selector(allow_refs=True)
1615

1716
def __init__(self, **params):
1817
super().__init__(**params)
18+
self.nice_settings = settings.nice
1919
self.sliders_ui = pn.Column(visible=self.param.coil_ui.rx.bool())
2020
guide_message = pn.pane.Markdown(
2121
"_To fix a coil to a specific current, enable the checkbox and provide "
@@ -49,15 +49,19 @@ def create_ui(self, pf_active):
4949
coil_current = coil.current
5050
checkbox = pn.widgets.Checkbox(
5151
margin=(30, 10, 10, 10),
52-
disabled=self.param.nice_mode.rx() == NiceSettings.DIRECT_MODE,
52+
disabled=self.nice_settings.param.mode.rx()
53+
== self.nice_settings.DIRECT_MODE,
5354
)
5455
slider = pn.widgets.EditableFloatSlider(
5556
name=f"{coil.name} Current [{coil_current.metadata.units}]",
5657
value=coil_current.data[0] if coil_current.data.has_value else 0.0,
5758
start=-5e4,
5859
end=5e4,
5960
disabled=checkbox.param.value.rx.not_()
60-
& (self.param.nice_mode.rx() == NiceSettings.INVERSE_MODE),
61+
& (
62+
self.nice_settings.param.mode.rx()
63+
== self.nice_settings.INVERSE_MODE
64+
),
6165
format="0",
6266
width=450,
6367
)
@@ -75,7 +79,10 @@ def fill_pf_active(self, pf_active):
7579
"""
7680
for i, coil_ui in enumerate(self.coil_ui):
7781
checkbox, slider = coil_ui.objects
78-
if checkbox.value or self.nice_mode == NiceSettings.DIRECT_MODE:
82+
if (
83+
checkbox.value
84+
or self.nice_settings.mode == self.nice_settings.DIRECT_MODE
85+
):
7986
pf_active.coil[i].current.data = np.array([slider.value])
8087

8188
def sync_ui_with_pf_active(self, pf_active):

waveform_editor/shape_editor/nice_plotter.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from imas.ids_toplevel import IDSToplevel
1111
from panel.viewable import Viewer
1212

13-
from waveform_editor.settings import NiceSettings
13+
from waveform_editor.settings import NiceSettings, settings
1414
from waveform_editor.shape_editor.nice_integration import NiceIntegration
1515
from waveform_editor.shape_editor.plasma_properties import PlasmaProperties
1616
from waveform_editor.shape_editor.plasma_shape import PlasmaShape
@@ -26,7 +26,7 @@ class NicePlotter(Viewer):
2626
pf_active = param.ClassSelector(class_=IDSToplevel, precedence=-1)
2727
plasma_shape = param.ClassSelector(class_=PlasmaShape, precedence=-1)
2828
plasma_properties = param.ClassSelector(class_=PlasmaProperties, precedence=-1)
29-
nice_mode = param.Selector(precedence=-1, allow_refs=True)
29+
nice_settings = param.ClassSelector(class_=NiceSettings, precedence=-1)
3030

3131
# Plot parameters
3232
show_contour = param.Boolean(default=True, label="Show contour lines")
@@ -57,6 +57,7 @@ def __init__(self, **params):
5757
xlabel="r [m]",
5858
ylabel="z [m]",
5959
)
60+
self.nice_settings = settings.nice
6061
self.CONTOUR_OPTS = hv.opts.Contours(
6162
cmap="viridis",
6263
colorbar=True,
@@ -93,7 +94,8 @@ def __init__(self, **params):
9394
show_name=False,
9495
widgets={
9596
"show_desired_shape": {
96-
"visible": self.param.nice_mode.rx() == NiceSettings.INVERSE_MODE
97+
"visible": self.nice_settings.param.mode.rx()
98+
== self.nice_settings.INVERSE_MODE
9799
}
98100
},
99101
)
@@ -131,10 +133,12 @@ def _plot_profiles(self):
131133
hv.opts.Overlay(title="Plasma Profiles"), hv.opts.Curve(framewise=True)
132134
)
133135

134-
@pn.depends("plasma_shape.shape_updated", "show_desired_shape", "nice_mode")
136+
@pn.depends(
137+
"plasma_shape.shape_updated", "show_desired_shape", "nice_settings.mode"
138+
)
135139
def _plot_plasma_shape(self):
136140
if (
137-
self.nice_mode == NiceSettings.DIRECT_MODE
141+
self.nice_settings.mode == self.nice_settings.DIRECT_MODE
138142
or not self.show_desired_shape
139143
or not self.plasma_shape.has_shape
140144
):

0 commit comments

Comments
 (0)