diff --git a/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py b/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py index 28b49acc3..83b5e0710 100644 --- a/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py +++ b/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py @@ -1,5 +1,6 @@ from trame.widgets import vuetify +from ...Input.trameFunctions import TrameFunctions from ...trame_setup import setup_server from ..generalFunctions import generalFunctions @@ -39,6 +40,9 @@ def card(): with vuetify.VCard(v_show="csr", style="width: 170px;"): with vuetify.VCardTitle("CSR"): vuetify.VSpacer() + TrameFunctions.create_refresh_button( + lambda: generalFunctions.reset_inputs("csr") + ) vuetify.VIcon( "mdi-information", classes="ml-2", diff --git a/src/python/impactx/dashboard/Input/defaults.py b/src/python/impactx/dashboard/Input/defaults.py index f5b552781..856833ac7 100644 --- a/src/python/impactx/dashboard/Input/defaults.py +++ b/src/python/impactx/dashboard/Input/defaults.py @@ -7,9 +7,12 @@ class DashboardDefaults: # Inputs by section # ------------------------------------------------------------------------- - INPUT_PARAMETERS = { + SELECTION = { "space_charge": False, "csr": False, + } + + INPUT_PARAMETERS = { "charge_qe": -1, "mass_MeV": 0.51099895, "npart": 1000, @@ -33,8 +36,12 @@ class DashboardDefaults: "poisson_solver": "fft", "particle_shape": 2, "max_level": 0, - "n_cell": 32, - "blocking_factor": 16, + "n_cell_x": 32, + "n_cell_y": 32, + "n_cell_z": 32, + "blocking_factor_x": 16, + "blocking_factor_y": 16, + "blocking_factor_z": 16, "prob_relative_first_value_fft": 1.1, "prob_relative_first_value_multigrid": 3.1, "mlmg_relative_tolerance": 1.0e-7, @@ -61,6 +68,7 @@ class DashboardDefaults: # ------------------------------------------------------------------------- DEFAULT_VALUES = { + **SELECTION, **INPUT_PARAMETERS, **DISTRIBUTION, **LATTICE, diff --git a/src/python/impactx/dashboard/Input/distributionParameters/distributionFunctions.py b/src/python/impactx/dashboard/Input/distributionParameters/distributionFunctions.py index 7565c2c5c..b482a90e2 100644 --- a/src/python/impactx/dashboard/Input/distributionParameters/distributionFunctions.py +++ b/src/python/impactx/dashboard/Input/distributionParameters/distributionFunctions.py @@ -25,7 +25,7 @@ def convert_distribution_parameters_to_valid_type(): param["parameter_name"]: float(param["parameter_default_value"]) if param_is_valid else 0.0 - for param in state.selectedDistributionParameters + for param in state.selected_distribution_parameters if (param_is_valid := param["parameter_error_message"] == []) } diff --git a/src/python/impactx/dashboard/Input/distributionParameters/distributionMain.py b/src/python/impactx/dashboard/Input/distributionParameters/distributionMain.py index 563522359..a37b8a32f 100644 --- a/src/python/impactx/dashboard/Input/distributionParameters/distributionMain.py +++ b/src/python/impactx/dashboard/Input/distributionParameters/distributionMain.py @@ -13,6 +13,7 @@ from impactx import distribution +from ...Input.trameFunctions import TrameFunctions from ...trame_setup import setup_server from ..generalFunctions import generalFunctions from .distributionFunctions import DistributionFunctions @@ -34,13 +35,13 @@ # Defaults # ----------------------------------------------------------------------------- -state.selectedDistribution = generalFunctions.get_default( +state.selected_distribution = generalFunctions.get_default( "selected_distribution", "default_values" ) -state.selectedDistributionType = generalFunctions.get_default( +state.selected_distribution_type = generalFunctions.get_default( "selected_distribution_type", "default_values" ) -state.selectedDistributionParameters = [] +state.selected_distribution_parameters = [] state.distributionTypeDisabled = False # ----------------------------------------------------------------------------- @@ -48,16 +49,16 @@ # ----------------------------------------------------------------------------- -def populate_distribution_parameters(selectedDistribution): +def populate_distribution_parameters(selected_distribution): """ Populates distribution parameters based on the selected distribution. - :param selectedDistribution (str): The name of the selected distribution + :param selected_distribution (str): The name of the selected distribution whose parameters need to be populated. """ - if state.selectedDistributionType == "Twiss": + if state.selected_distribution_type == "Twiss": sig = inspect.signature(twiss) - state.selectedDistributionParameters = [ + state.selected_distribution_parameters = [ { "parameter_name": param.name, "parameter_default_value": param.default @@ -76,13 +77,13 @@ def populate_distribution_parameters(selectedDistribution): ] else: # when type == 'Quadratic Form' - selectedDistributionParameters = ( + selected_distribution_parameters = ( state.listOfDistributionsAndParametersAndDefault.get( - selectedDistribution, [] + selected_distribution, [] ) ) - state.selectedDistributionParameters = [ + state.selected_distribution_parameters = [ { "parameter_name": parameter[0], "parameter_default_value": parameter[1], @@ -95,11 +96,11 @@ def populate_distribution_parameters(selectedDistribution): else "", "parameter_step": generalFunctions.get_default(parameter[0], "steps"), } - for parameter in selectedDistributionParameters + for parameter in selected_distribution_parameters ] - generalFunctions.update_simulation_validation_status() - return selectedDistributionParameters + generalFunctions.update_simulation_validation_status() + return state.selected_distribution_parameters def update_distribution_parameters( @@ -113,13 +114,13 @@ def update_distribution_parameters( :param parameterErrorMessage: The error message related to the parameter's value. """ - for param in state.selectedDistributionParameters: + for param in state.selected_distribution_parameters: if param["parameter_name"] == parameterName: param["parameter_default_value"] = parameterValue param["parameter_error_message"] = parameterErrorMessage generalFunctions.update_simulation_validation_status() - state.dirty("selectedDistributionParameters") + state.dirty("selected_distribution_parameters") # ----------------------------------------------------------------------------- @@ -133,10 +134,10 @@ def distribution_parameters(): initialized with the appropriate parameters provided by the user. """ - distribution_name = state.selectedDistribution + distribution_name = state.selected_distribution parameters = DistributionFunctions.convert_distribution_parameters_to_valid_type() - if state.selectedDistributionType == "Twiss": + if state.selected_distribution_type == "Twiss": twiss_params = twiss(**parameters) distr = getattr(distribution, distribution_name)(**twiss_params) else: @@ -150,20 +151,20 @@ def distribution_parameters(): # ----------------------------------------------------------------------------- -@state.change("selectedDistribution") -def on_distribution_name_change(selectedDistribution, **kwargs): - if selectedDistribution == "Thermal": - state.selectedDistributionType = "Quadratic Form" +@state.change("selected_distribution") +def on_distribution_name_change(selected_distribution, **kwargs): + if selected_distribution == "Thermal": + state.selected_distribution_type = "Quadratic Form" state.distributionTypeDisabled = True - state.dirty("selectedDistributionType") + state.dirty("selected_distribution_type") else: state.distributionTypeDisabled = False - populate_distribution_parameters(selectedDistribution) + populate_distribution_parameters(selected_distribution) -@state.change("selectedDistributionType") +@state.change("selected_distribution_type") def on_distribution_type_change(**kwargs): - populate_distribution_parameters(state.selectedDistribution) + populate_distribution_parameters(state.selected_distribution) @ctrl.add("updateDistributionParameters") @@ -193,6 +194,9 @@ def card(): with vuetify.VCard(style="width: 340px; height: 300px"): with vuetify.VCardTitle("Distribution Parameters"): vuetify.VSpacer() + TrameFunctions.create_refresh_button( + lambda: generalFunctions.reset_inputs("distribution") + ) vuetify.VIcon( "mdi-information", style="color: #00313C;", @@ -204,13 +208,13 @@ def card(): with vuetify.VCol(cols=6): vuetify.VCombobox( label="Select Distribution", - v_model=("selectedDistribution",), + v_model=("selected_distribution",), items=("listOfDistributions",), dense=True, ) with vuetify.VCol(cols=6): vuetify.VSelect( - v_model=("selectedDistributionType",), + v_model=("selected_distribution_type",), label="Type", items=( generalFunctions.get_default( @@ -224,7 +228,7 @@ def card(): for i in range(3): with vuetify.VCol(cols=4, classes="py-0"): with vuetify.VRow( - v_for="(parameter, index) in selectedDistributionParameters" + v_for="(parameter, index) in selected_distribution_parameters" ): with vuetify.VCol( v_if=f"index % 3 == {i}", classes="py-1" diff --git a/src/python/impactx/dashboard/Input/generalFunctions.py b/src/python/impactx/dashboard/Input/generalFunctions.py index fc033737b..49280e8ec 100644 --- a/src/python/impactx/dashboard/Input/generalFunctions.py +++ b/src/python/impactx/dashboard/Input/generalFunctions.py @@ -139,14 +139,14 @@ def update_simulation_validation_status(): error_details = [] # Check for errors in distribution parameters - for param in state.selectedDistributionParameters: + for param in state.selected_distribution_parameters: if param["parameter_error_message"]: error_details.append( f"{param['parameter_name']}: {param['parameter_error_message']}" ) # Check for errors in lattice parameters - for lattice in state.selectedLatticeList: + for lattice in state.selected_lattice_list: for param in lattice["parameters"]: if param["parameter_error_message"]: error_details.append( @@ -165,7 +165,7 @@ def update_simulation_validation_status(): if state.mass_MeV_validation: error_details.append(f"Ref. Particle Mass: {state.mass_MeV}") - if state.selectedLatticeList == []: + if state.selected_lattice_list == []: error_details.append("LatticeListIsEmpty") # Check for errors in CSR parameters @@ -326,3 +326,32 @@ def convert_to_correct_type(value, desired_type): return str(value) else: raise ValueError("Unknown type") + + @staticmethod + def reset_inputs(input_section): + """ + Resets dashboard inputs to default values. + + :param input_section: The input section to reset. + """ + + possible_section_names = [] + for name in vars(DashboardDefaults): + if name != "DEFAULT_VALUES" and name.isupper(): + possible_section_names.append(name) + + if input_section.upper() in possible_section_names: + state.update(getattr(DashboardDefaults, input_section.upper())) + + if input_section == "distribution": + state.dirty("selected_distribution_type") + elif input_section == "lattice": + state.selected_lattice_list = [] + elif input_section == "space_charge": + state.dirty("max_level") + + elif input_section == "all": + state.update(DashboardDefaults.DEFAULT_VALUES) + state.dirty("selected_distribution_type") + state.selected_lattice_list = [] + state.dirty("max_level") diff --git a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py index de6b78b54..7441ae284 100644 --- a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py +++ b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py @@ -8,6 +8,7 @@ from trame.widgets import vuetify +from ...Input.trameFunctions import TrameFunctions from ...trame_setup import setup_server from ..generalFunctions import generalFunctions from .inputFunctions import InputFunctions @@ -97,6 +98,9 @@ def card(self): with vuetify.VCard(style="width: 340px; height: 350px"): with vuetify.VCardTitle("Input Parameters"): vuetify.VSpacer() + TrameFunctions.create_refresh_button( + lambda: generalFunctions.reset_inputs("input_parameters") + ) vuetify.VIcon( "mdi-information", style="color: #00313C;", diff --git a/src/python/impactx/dashboard/Input/latticeConfiguration/latticeMain.py b/src/python/impactx/dashboard/Input/latticeConfiguration/latticeMain.py index 83bb8e529..9b5b80a8f 100644 --- a/src/python/impactx/dashboard/Input/latticeConfiguration/latticeMain.py +++ b/src/python/impactx/dashboard/Input/latticeConfiguration/latticeMain.py @@ -10,6 +10,7 @@ from impactx import elements +from ...Input.trameFunctions import TrameFunctions from ...trame_setup import setup_server from ..generalFunctions import generalFunctions @@ -32,8 +33,10 @@ # Default # ----------------------------------------------------------------------------- -state.selectedLattice = generalFunctions.get_default("lattice", "default_values") -state.selectedLatticeList = [] +state.selected_lattice = generalFunctions.get_default( + "selected_lattice", "default_values" +) +state.selected_lattice_list = [] state.nsliceDefaultValue = generalFunctions.get_default("n_slice", "default_values") # ----------------------------------------------------------------------------- @@ -48,13 +51,13 @@ def add_lattice_element(): :return: dictionary representing the added lattice element with its parameters. """ - selectedLattice = state.selectedLattice - selectedLatticeParameters = state.listOfLatticeElementParametersAndDefault.get( - selectedLattice, [] + selected_lattice = state.selected_lattice + selected_lattice_parameters = state.listOfLatticeElementParametersAndDefault.get( + selected_lattice, [] ) - selectedLatticeElement = { - "name": selectedLattice, + selected_lattice_element = { + "name": selected_lattice, "parameters": [ { "parameter_name": parameter[0], @@ -64,13 +67,13 @@ def add_lattice_element(): parameter[1], parameter[2] ), } - for parameter in selectedLatticeParameters + for parameter in selected_lattice_parameters ], } - state.selectedLatticeList.append(selectedLatticeElement) + state.selected_lattice_list.append(selected_lattice_element) generalFunctions.update_simulation_validation_status() - return selectedLatticeElement + return selected_lattice_element def update_latticeElement_parameters( @@ -80,13 +83,13 @@ def update_latticeElement_parameters( Updates parameter value and includes error message if user input is not valid """ - for param in state.selectedLatticeList[index]["parameters"]: + for param in state.selected_lattice_list[index]["parameters"]: if param["parameter_name"] == parameterName: param["parameter_default_value"] = parameterValue param["parameter_error_message"] = parameterErrorMessage generalFunctions.update_simulation_validation_status() - state.dirty("selectedLatticeList") + state.dirty("selected_lattice_list") # ----------------------------------------------------------------------------- @@ -124,7 +127,7 @@ def lattice_elements(): """ elements_list = [] - for latticeElement in state.selectedLatticeList: + for latticeElement in state.selected_lattice_list: latticeElement_name = latticeElement["name"] parameters = parameter_input_checker_for_lattice(latticeElement) @@ -139,31 +142,31 @@ def lattice_elements(): # ----------------------------------------------------------------------------- -@state.change("selectedLatticeList") -def on_selectedLatticeList_change(selectedLatticeList, **kwargs): - if selectedLatticeList == []: +@state.change("selected_lattice_list") +def on_selected_lattice_list_change(selected_lattice_list, **kwargs): + if selected_lattice_list == []: state.isSelectedLatticeListEmpty = "Please select a lattice element" generalFunctions.update_simulation_validation_status() else: state.isSelectedLatticeListEmpty = "" -@state.change("selectedLattice") -def on_lattice_element_name_change(selectedLattice, **kwargs): +@state.change("selected_lattice") +def on_lattice_element_name_change(selected_lattice, **kwargs): return @ctrl.add("add_latticeElement") def on_add_lattice_element_click(): - selectedLattice = state.selectedLattice + selected_lattice = state.selected_lattice - if selectedLattice not in state.listOfLatticeElements: + if selected_lattice not in state.listOfLatticeElements: state.isSelectedLatticeListEmpty = ( - f"Lattice element '{selectedLattice}' does not exist." + f"Lattice element '{selected_lattice}' does not exist." ) else: add_lattice_element() - state.dirty("selectedLatticeList") + state.dirty("selected_lattice_list") @ctrl.add("updateLatticeElementParameters") @@ -178,35 +181,30 @@ def on_lattice_element_parameter_change( ) -@ctrl.add("clear_latticeElements") -def on_clear_lattice_element_click(): - state.selectedLatticeList = [] - - @ctrl.add("deleteLatticeElement") def on_delete_LatticeElement_click(index): - state.selectedLatticeList.pop(index) - state.dirty("selectedLatticeList") + state.selected_lattice_list.pop(index) + state.dirty("selected_lattice_list") @ctrl.add("move_latticeElementIndex_up") def on_move_latticeElementIndex_up_click(index): if index > 0: - state.selectedLatticeList[index], state.selectedLatticeList[index - 1] = ( - state.selectedLatticeList[index - 1], - state.selectedLatticeList[index], + state.selected_lattice_list[index], state.selected_lattice_list[index - 1] = ( + state.selected_lattice_list[index - 1], + state.selected_lattice_list[index], ) - state.dirty("selectedLatticeList") + state.dirty("selected_lattice_list") @ctrl.add("move_latticeElementIndex_down") def on_move_latticeElementIndex_down_click(index): - if index < len(state.selectedLatticeList) - 1: - state.selectedLatticeList[index], state.selectedLatticeList[index + 1] = ( - state.selectedLatticeList[index + 1], - state.selectedLatticeList[index], + if index < len(state.selected_lattice_list) - 1: + state.selected_lattice_list[index], state.selected_lattice_list[index + 1] = ( + state.selected_lattice_list[index + 1], + state.selected_lattice_list[index], ) - state.dirty("selectedLatticeList") + state.dirty("selected_lattice_list") @ctrl.add("nsliceDefaultChange") @@ -246,6 +244,9 @@ def card(): with vuetify.VCard(style="width: 696px;"): with vuetify.VCardTitle("Lattice Configuration"): vuetify.VSpacer() + TrameFunctions.create_refresh_button( + lambda: generalFunctions.reset_inputs("lattice") + ) vuetify.VIcon( "mdi-information", classes="ml-2", @@ -255,10 +256,10 @@ def card(): vuetify.VDivider() with vuetify.VCardText(): with vuetify.VRow(align="center", no_gutters=True): - with vuetify.VCol(cols=8): + with vuetify.VCol(cols=10): vuetify.VCombobox( label="Select Accelerator Lattice", - v_model=("selectedLattice", None), + v_model=("selected_lattice", None), items=("listOfLatticeElements",), error_messages=("isSelectedLatticeListEmpty",), dense=True, @@ -272,14 +273,6 @@ def card(): classes="mr-2", click=ctrl.add_latticeElement, ) - with vuetify.VCol(cols="auto"): - vuetify.VBtn( - "CLEAR", - color="secondary", - dense=True, - classes="mr-2", - click=ctrl.clear_latticeElements, - ) with vuetify.VCol(cols="auto"): vuetify.VIcon( "mdi-cog", @@ -302,7 +295,7 @@ def card(): vuetify.VDivider() with vuetify.VContainer(fluid=True): with vuetify.VRow( - v_for="(latticeElement, index) in selectedLatticeList", + v_for="(latticeElement, index) in selected_lattice_list", align="center", no_gutters=True, style="min-width: 1500px;", @@ -369,7 +362,7 @@ def dialog_lattice_elementList(): vuetify.VDivider() with vuetify.VContainer(fluid=True): with vuetify.VRow( - v_for="(latticeElement, index) in selectedLatticeList", + v_for="(latticeElement, index) in selected_lattice_list", align="center", no_gutters=True, style="min-width: 1500px;", diff --git a/src/python/impactx/dashboard/Input/space_charge_configuration/spaceChargeMain.py b/src/python/impactx/dashboard/Input/space_charge_configuration/spaceChargeMain.py index a6eac919d..c9a920b49 100644 --- a/src/python/impactx/dashboard/Input/space_charge_configuration/spaceChargeMain.py +++ b/src/python/impactx/dashboard/Input/space_charge_configuration/spaceChargeMain.py @@ -1,5 +1,6 @@ from trame.widgets import vuetify +from ...Input.trameFunctions import TrameFunctions from ...trame_setup import setup_server from ..generalFunctions import generalFunctions from .spaceChargeFunctions import SpaceChargeFunctions @@ -19,18 +20,18 @@ state.prob_relative_fields = [] state.n_cell = [] -state.n_cell_x = generalFunctions.get_default("n_cell", "default_values") -state.n_cell_y = generalFunctions.get_default("n_cell", "default_values") -state.n_cell_z = generalFunctions.get_default("n_cell", "default_values") +state.n_cell_x = generalFunctions.get_default("n_cell_x", "default_values") +state.n_cell_y = generalFunctions.get_default("n_cell_y", "default_values") +state.n_cell_z = generalFunctions.get_default("n_cell_z", "default_values") state.blocking_factor_x = generalFunctions.get_default( - "blocking_factor", "default_values" + "blocking_factor_x", "default_values" ) state.blocking_factor_y = generalFunctions.get_default( - "blocking_factor", "default_values" + "blocking_factor_y", "default_values" ) state.blocking_factor_z = generalFunctions.get_default( - "blocking_factor", "default_values" + "blocking_factor_z", "default_values" ) state.mlmg_relative_tolerance = generalFunctions.get_default( @@ -204,6 +205,9 @@ def card(): click="showSpaceChargeDialog = true", style="cursor: pointer;", ) + TrameFunctions.create_refresh_button( + lambda: generalFunctions.reset_inputs("space_charge") + ) vuetify.VIcon( "mdi-information", classes="ml-2", diff --git a/src/python/impactx/dashboard/Input/trameFunctions.py b/src/python/impactx/dashboard/Input/trameFunctions.py index 599e00c03..ef9c58246 100644 --- a/src/python/impactx/dashboard/Input/trameFunctions.py +++ b/src/python/impactx/dashboard/Input/trameFunctions.py @@ -41,3 +41,15 @@ def create_route(route_title, mdi_icon): vuetify.VIcon(mdi_icon) with vuetify.VListItemContent(): vuetify.VListItemTitle(route_title) + + @staticmethod + def create_refresh_button(reset_function_name): + """ + Creates a standardized refresh button. + :param reset_function: The reset function to call when clicked. + """ + return vuetify.VIcon( + "mdi-refresh", + style="color: #00313C;", + click=reset_function_name, + ) diff --git a/src/python/impactx/dashboard/Toolbar/exportTemplate.py b/src/python/impactx/dashboard/Toolbar/exportTemplate.py index c7fb192e5..c01b53e82 100644 --- a/src/python/impactx/dashboard/Toolbar/exportTemplate.py +++ b/src/python/impactx/dashboard/Toolbar/exportTemplate.py @@ -14,15 +14,15 @@ def build_distribution_list(): Generates an instance of distribution inputs as a string for exporting purposes. """ - distribution_name = state.selectedDistribution + distribution_name = state.selected_distribution parameters = DistributionFunctions.convert_distribution_parameters_to_valid_type() - indentation = " " * (8 if state.selectedDistributionType == "Twiss" else 4) + indentation = " " * (8 if state.selected_distribution_type == "Twiss" else 4) distribution_parameters = ",\n".join( f"{indentation}{key}={value}" for key, value in parameters.items() ) - if state.selectedDistributionType == "Twiss": + if state.selected_distribution_type == "Twiss": return ( f"distr = distribution.{distribution_name}(\n" f" **twiss(\n" @@ -51,7 +51,7 @@ def build_lattice_list(): for key, value in parameter_input_checker_for_lattice(element).items() ) + ")" - for element in state.selectedLatticeList + for element in state.selected_lattice_list ) return f"lattice_configuration = [\n {lattice_elements}\n]" diff --git a/src/python/impactx/dashboard/Toolbar/toolbarMain.py b/src/python/impactx/dashboard/Toolbar/toolbarMain.py index 4b71b0aca..810a3ac62 100644 --- a/src/python/impactx/dashboard/Toolbar/toolbarMain.py +++ b/src/python/impactx/dashboard/Toolbar/toolbarMain.py @@ -6,8 +6,9 @@ License: BSD-3-Clause-LBNL """ -from trame.widgets import vuetify +from trame.widgets import html, vuetify +from ..Input.generalFunctions import generalFunctions from ..trame_setup import setup_server from .exportTemplate import input_file @@ -66,6 +67,16 @@ def run_simulation_button(): disabled=("disableRunSimulationButton", True), ) + @staticmethod + def reset_inputs_button(): + with vuetify.VBtn( + click=lambda: generalFunctions.reset_inputs("all"), + outlined=True, + small=True, + ): + vuetify.VIcon("mdi-refresh", left=True) + html.Span("Reset") + @staticmethod def dashboard_info(): """ @@ -96,6 +107,7 @@ def input_toolbar(): (ToolbarElements.dashboard_info(),) vuetify.VSpacer() + ToolbarElements.reset_inputs_button() ToolbarElements.export_input_data() @staticmethod