Skip to content

Commit 73ab343

Browse files
authored
Clean up and organize dashboard code (#830)
* Organize main toolbar file * Separate simulation logic from Analyze section * cleanup dashboard file import code
1 parent dfe55da commit 73ab343

File tree

5 files changed

+163
-116
lines changed

5 files changed

+163
-116
lines changed

src/python/impactx/dashboard/Analyze/plotsMain.py

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,11 @@
66
License: BSD-3-Clause-LBNL
77
"""
88

9-
import asyncio
109
import glob
11-
import io
1210
import os
1311

1412
from trame.widgets import matplotlib, plotly, vuetify
15-
from wurlitzer import pipes
1613

17-
from ..simulation import run_simulation
1814
from ..trame_setup import setup_server
1915
from .analyzeFunctions import AnalyzeFunctions
2016
from .plot_ParameterEvolutionOverS.overS import line_plot_1d
@@ -137,24 +133,6 @@ def update_plot():
137133
state.show_table = False
138134

139135

140-
def run_simulation_impactX():
141-
buf = io.StringIO()
142-
143-
with pipes(stdout=buf, stderr=buf):
144-
run_simulation()
145-
146-
buf.seek(0)
147-
lines = [line.strip() for line in buf.getvalue().splitlines()]
148-
149-
# Use $nextTick to ensure the terminal is fully rendered before printing
150-
async def print_lines():
151-
for line in lines:
152-
ctrl.terminal_print(line)
153-
ctrl.terminal_print("Simulation complete.")
154-
155-
asyncio.create_task(print_lines())
156-
157-
158136
# -----------------------------------------------------------------------------
159137
# State changes
160138
# -----------------------------------------------------------------------------
@@ -173,14 +151,6 @@ def on_filtered_data_change(**kwargs):
173151
update_plot()
174152

175153

176-
@ctrl.add("run_simulation")
177-
def run_simulation_and_store():
178-
state.plot_options = available_plot_options(simulationClicked=True)
179-
run_simulation_impactX()
180-
update_plot()
181-
load_dataTable_data()
182-
183-
184154
# -----------------------------------------------------------------------------
185155
# GUI
186156
# -----------------------------------------------------------------------------

src/python/impactx/dashboard/Run/__init__.py

Whitespace-only changes.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import asyncio
2+
import io
3+
4+
from wurlitzer import pipes
5+
6+
from ..simulation import run_simulation
7+
from ..trame_setup import setup_server
8+
9+
server, state, ctrl = setup_server()
10+
11+
12+
def execute_impactx_sim():
13+
buf = io.StringIO()
14+
15+
with pipes(stdout=buf, stderr=buf):
16+
run_simulation()
17+
18+
buf.seek(0)
19+
lines = [line.strip() for line in buf.getvalue().splitlines()]
20+
21+
# Use $nextTick to ensure the terminal is fully rendered before printing
22+
async def print_lines():
23+
for line in lines:
24+
ctrl.terminal_print(line)
25+
ctrl.terminal_print("Simulation complete.")
26+
27+
asyncio.create_task(print_lines())

src/python/impactx/dashboard/Toolbar/toolbarMain.py renamed to src/python/impactx/dashboard/Toolbar/controls.py

Lines changed: 132 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
from trame.widgets import html, vuetify
1010

11+
from ..Analyze.plotsMain import available_plot_options, load_dataTable_data, update_plot
1112
from ..Input.generalFunctions import generalFunctions
13+
from ..Run.controls import execute_impactx_sim
1214
from ..trame_setup import setup_server
1315
from .exportTemplate import input_file
1416
from .importParser import DashboardParser
@@ -22,54 +24,53 @@
2224
state.importing_file = False
2325

2426

25-
# -----------------------------------------------------------------------------
26-
# Triggers/Controllers
27-
# -----------------------------------------------------------------------------
28-
def reset_importing_states():
29-
state.import_file_error = None
30-
state.import_file_details = None
31-
state.import_file = None
32-
state.importing_file = False
33-
34-
35-
@ctrl.add("reset_all")
36-
def reset_all():
37-
reset_importing_states()
38-
generalFunctions.reset_inputs("all")
39-
40-
41-
@ctrl.trigger("export")
42-
def on_export_click():
43-
return input_file()
44-
45-
46-
@state.change("import_file")
47-
def on_import_file_change(import_file, **kwargs):
48-
if import_file:
49-
try:
50-
state.importing_file = True
51-
DashboardParser.file_details(import_file)
52-
DashboardParser.populate_impactx_simulation_file_to_ui(import_file)
53-
except Exception:
54-
state.import_file_error = True
55-
state.import_file_error_message = "Unable to parse"
56-
finally:
57-
state.importing_file = False
27+
class ToolbarImport:
28+
@state.change("import_file")
29+
def on_import_file_change(import_file, **kwargs):
30+
if import_file:
31+
try:
32+
state.importing_file = True
33+
DashboardParser.file_details(import_file)
34+
DashboardParser.populate_impactx_simulation_file_to_ui(import_file)
35+
except Exception:
36+
state.import_file_error = True
37+
state.import_file_error_message = "Unable to parse"
38+
finally:
39+
state.importing_file = False
5840

41+
@staticmethod
42+
def reset_importing_states():
43+
"""
44+
Resets import related states to default.
45+
"""
5946

60-
# -----------------------------------------------------------------------------
61-
# Common toolbar elements
62-
# -----------------------------------------------------------------------------
47+
state.import_file_error = None
48+
state.import_file_details = None
49+
state.import_file = None
50+
state.importing_file = False
6351

6452

65-
class ToolbarElements:
53+
class InputToolbar:
6654
"""
67-
Helper functions to create
68-
Vuetify UI elements for toolbar.
55+
Contains toolbar elements for the Input page.
6956
"""
7057

58+
@ctrl.trigger("export")
59+
def on_export_click():
60+
return input_file()
61+
62+
@ctrl.add("reset_all")
63+
def reset_all():
64+
ToolbarImport.reset_importing_states()
65+
generalFunctions.reset_inputs("all")
66+
7167
@staticmethod
72-
def export_button():
68+
def export_button() -> vuetify.VBtn:
69+
"""
70+
Creates an export button to download a .py file
71+
containing the user's current input values.
72+
"""
73+
7374
with vuetify.VBtn(
7475
click="utils.download('impactx_simulation.py', trigger('export'), 'text/plain')",
7576
outlined=True,
@@ -81,28 +82,12 @@ def export_button():
8182
html.Span("Export")
8283

8384
@staticmethod
84-
def plot_options():
85-
vuetify.VSelect(
86-
v_model=("active_plot", "1D plots over s"),
87-
items=("plot_options",),
88-
label="Select plot to view",
89-
hide_details=True,
90-
dense=True,
91-
style="max-width: 250px",
92-
disabled=("disableRunSimulationButton", True),
93-
)
94-
95-
@staticmethod
96-
def run_simulation_button():
97-
vuetify.VBtn(
98-
"Run Simulation",
99-
style="background-color: #00313C; color: white; margin: 0 20px;",
100-
click=ctrl.run_simulation,
101-
disabled=("disableRunSimulationButton", True),
102-
)
85+
def import_button() -> None:
86+
"""
87+
Displays the 'import' button on the input section
88+
of the dashboard.
89+
"""
10390

104-
@staticmethod
105-
def import_button():
10691
vuetify.VFileInput(
10792
v_model=("import_file",),
10893
accept=".py",
@@ -146,7 +131,12 @@ def import_button():
146131
)
147132

148133
@staticmethod
149-
def reset_inputs_button():
134+
def reset_inputs_button() -> vuetify.VBtn:
135+
"""
136+
Creates a button to reset all input fields to
137+
default values.
138+
"""
139+
150140
with vuetify.VBtn(
151141
click=ctrl.reset_all,
152142
outlined=True,
@@ -155,43 +145,103 @@ def reset_inputs_button():
155145
vuetify.VIcon("mdi-refresh", left=True)
156146
html.Span("Reset")
157147

148+
149+
class RunToolbar:
150+
"""
151+
Contains toolbar elements for the Run page.
152+
"""
153+
154+
@ctrl.add("begin_sim")
155+
def run():
156+
state.plot_options = available_plot_options(simulationClicked=True)
157+
execute_impactx_sim()
158+
update_plot()
159+
load_dataTable_data()
160+
158161
@staticmethod
159-
def dashboard_info():
162+
def run_simulation_button() -> vuetify.VBtn:
160163
"""
161-
Creates an alert box with dashboard information.
164+
Creates a button to run an ImpactX simulation
165+
with the current user-provided inputs.
162166
"""
163167

164-
vuetify.VAlert(
165-
"ImpactX Dashboard is provided as a preview and continues to be developed. "
166-
"Thus, it may not yet include all the features available in ImpactX.",
167-
type="info",
168+
return vuetify.VBtn(
169+
"Run Simulation",
170+
style="background-color: #00313C; color: white; margin: 0 20px;",
171+
click=ctrl.begin_sim,
172+
disabled=("disableRunSimulationButton", True),
173+
)
174+
175+
176+
class AnalyzeToolbar:
177+
"""
178+
Contains toolbar elements for the Analyze page.
179+
"""
180+
181+
@staticmethod
182+
def plot_options() -> vuetify.VSelect:
183+
"""
184+
Creates a dropdown menu for selecting a plot
185+
to visualize simulation results.
186+
"""
187+
188+
return vuetify.VSelect(
189+
v_model=("active_plot", "1D plots over s"),
190+
items=("plot_options",),
191+
label="Select plot to view",
192+
hide_details=True,
168193
dense=True,
169-
dismissible=True,
170-
v_model=("show_dashboard_alert", True),
171-
classes="mt-4",
194+
style="max-width: 250px",
195+
disabled=("disableRunSimulationButton", True),
172196
)
173197

174198

175-
class Toolbars:
199+
class GeneralToolbar:
176200
"""
177-
Builds toolbar for dashboard.
201+
General tolbar elements.
178202
"""
179203

180204
@staticmethod
181205
def dashboard_toolbar(toolbar_name: str) -> None:
206+
"""
207+
Builds and displays the appropriate toolbar
208+
based on the selected dashboard section.
209+
210+
:param toolbar_name: The name of the dashboard section
211+
for which the toolbar is needed.
212+
"""
213+
182214
toolbar_name = toolbar_name.lower()
183215
if toolbar_name == "input":
184-
(ToolbarElements.dashboard_info(),)
216+
(GeneralToolbar.dashboard_info(),)
185217
vuetify.VSpacer()
186-
ToolbarElements.import_button()
187-
ToolbarElements.export_button()
188-
ToolbarElements.reset_inputs_button()
189-
218+
InputToolbar.import_button()
219+
InputToolbar.export_button()
220+
InputToolbar.reset_inputs_button()
190221
elif toolbar_name == "run":
191-
(ToolbarElements.dashboard_info(),)
222+
(GeneralToolbar.dashboard_info(),)
192223
(vuetify.VSpacer(),)
193-
(ToolbarElements.run_simulation_button(),)
224+
(RunToolbar.run_simulation_button(),)
194225
elif toolbar_name == "analyze":
195-
(ToolbarElements.dashboard_info(),)
226+
(GeneralToolbar.dashboard_info(),)
196227
vuetify.VSpacer()
197-
ToolbarElements.plot_options()
228+
AnalyzeToolbar.plot_options()
229+
230+
@staticmethod
231+
def dashboard_info() -> vuetify.VAlert:
232+
"""
233+
Creates an informational alert box for the dashboard to
234+
notify users that the ImpactX dashboard is still in development.
235+
236+
:return: A Vuetify alert component displaying the dashboard notice.
237+
"""
238+
239+
return vuetify.VAlert(
240+
"ImpactX Dashboard is provided as a preview and continues to be developed. "
241+
"Thus, it may not yet include all the features available in ImpactX.",
242+
type="info",
243+
dense=True,
244+
dismissible=True,
245+
v_model=("show_dashboard_alert", True),
246+
classes="mt-4",
247+
)

src/python/impactx/dashboard/__main__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from .Input.latticeConfiguration.latticeMain import LatticeConfiguration
2121
from .Input.space_charge_configuration.spaceChargeMain import SpaceChargeConfiguration
2222
from .start import main
23-
from .Toolbar.toolbarMain import Toolbars
23+
from .Toolbar.controls import GeneralToolbar
2424
from .trame_setup import setup_server
2525

2626
server, state, ctrl = setup_server()
@@ -72,11 +72,11 @@ def application():
7272
layout.title.hide()
7373
with layout.toolbar:
7474
with vuetify.Template(v_if="$route.path == '/Analyze'"):
75-
Toolbars.dashboard_toolbar("analyze")
75+
GeneralToolbar.dashboard_toolbar("analyze")
7676
with vuetify.Template(v_if="$route.path == '/Input'"):
77-
Toolbars.dashboard_toolbar("input")
77+
GeneralToolbar.dashboard_toolbar("input")
7878
with vuetify.Template(v_if="$route.path == '/Run'"):
79-
Toolbars.dashboard_toolbar("run")
79+
GeneralToolbar.dashboard_toolbar("run")
8080

8181
with layout.drawer as drawer:
8282
drawer.width = 200

0 commit comments

Comments
 (0)