From b8a3ce8ea1ac7e3fb2cde404b8c82d7470ed39d3 Mon Sep 17 00:00:00 2001 From: Parthib Roy Date: Sat, 8 Feb 2025 10:26:54 -0800 Subject: [PATCH 1/7] Use shared state for input parameters section --- .../Input/inputParameters/inputMain.py | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py index 0e4bb7647..ae0704373 100644 --- a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py +++ b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py @@ -17,26 +17,32 @@ # ----------------------------------------------------------------------------- -@ctrl.add("input_change") -def validate_and_convert_to_correct_type(state_name): - value = getattr(state, state_name) - desired_type = DashboardDefaults.TYPES[state_name] - validation_name = f"{state_name}_error_message" - conditions = DashboardDefaults.VALIDATION_CONDITION.get(state_name, None) +DEFAULTS = list(DashboardDefaults.INPUT_PARAMETERS.keys()) - validation_result = generalFunctions.validate_against( - value, desired_type, conditions - ) - setattr(state, validation_name, validation_result) - generalFunctions.update_simulation_validation_status() - if validation_result == []: - converted_value = generalFunctions.convert_to_correct_type(value, desired_type) +@state.change(*DEFAULTS) +def on_input_state_change(**_): + state_changes = state.modified_keys & set(DEFAULTS) + for state_name in state_changes: + print(f"{state_name} = {state[state_name]}") + value = getattr(state, state_name) + desired_type = DashboardDefaults.TYPES.get(state_name, None) + validation_name = f"{state_name}_error_message" + conditions = DashboardDefaults.VALIDATION_CONDITION.get(state_name, None) - if getattr(state, state_name) != converted_value: - setattr(state, state_name, converted_value) - if state_name == "kin_energy_on_ui": - on_kin_energy_unit_change() + validation_result = generalFunctions.validate_against( + value, desired_type, conditions + ) + setattr(state, validation_name, validation_result) + generalFunctions.update_simulation_validation_status() + + if validation_result == []: + converted_value = generalFunctions.convert_to_correct_type(value, desired_type) + + if getattr(state, state_name) != converted_value: + setattr(state, state_name, converted_value) + if state_name == "kin_energy_on_ui": + on_kin_energy_unit_change() @state.change("kin_energy_unit") @@ -81,27 +87,23 @@ def card(self): InputComponents.text_field( label="Ref. Particle Charge", v_model_name="charge_qe", - input=(ctrl.input_change, "['charge_qe']"), ) with vuetify.VCol(cols=6, classes="py-0"): InputComponents.text_field( label="Ref. Particle Mass", v_model_name="mass_MeV", - input=(ctrl.input_change, "['mass_MeV']"), ) with vuetify.VRow(classes="my-0"): with vuetify.VCol(cols=12, classes="py-0"): InputComponents.text_field( label="Number of Particles", v_model_name="npart", - input=(ctrl.input_change, "['npart']"), ) with vuetify.VRow(classes="my-2"): with vuetify.VCol(cols=8, classes="py-0"): InputComponents.text_field( label="Kinetic Energy", v_model_name="kin_energy_on_ui", - input=(ctrl.input_change, "['kin_energy_on_ui']"), classes="mr-2", ) with vuetify.VCol(cols=4, classes="py-0"): @@ -114,5 +116,4 @@ def card(self): InputComponents.text_field( label="Bunch Charge", v_model_name="bunch_charge_C", - input=(ctrl.input_change, "['bunch_charge_C']"), ) From b8a246c2c5a51680ad676ce6ef3206106e4dba9f Mon Sep 17 00:00:00 2001 From: Parthib Roy Date: Sat, 8 Feb 2025 10:32:53 -0800 Subject: [PATCH 2/7] Only call state change when input is string Since the state change converts the input value from a string to a numeric, we do not want the input value to be read in numerous times. --- .../Input/inputParameters/inputMain.py | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py index ae0704373..5cd52f299 100644 --- a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py +++ b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py @@ -24,25 +24,30 @@ def on_input_state_change(**_): state_changes = state.modified_keys & set(DEFAULTS) for state_name in state_changes: - print(f"{state_name} = {state[state_name]}") - value = getattr(state, state_name) - desired_type = DashboardDefaults.TYPES.get(state_name, None) - validation_name = f"{state_name}_error_message" - conditions = DashboardDefaults.VALIDATION_CONDITION.get(state_name, None) - - validation_result = generalFunctions.validate_against( - value, desired_type, conditions - ) - setattr(state, validation_name, validation_result) - generalFunctions.update_simulation_validation_status() - - if validation_result == []: - converted_value = generalFunctions.convert_to_correct_type(value, desired_type) - - if getattr(state, state_name) != converted_value: - setattr(state, state_name, converted_value) - if state_name == "kin_energy_on_ui": - on_kin_energy_unit_change() + if type(state[state_name]) is str: + print( + f"{state_name} = {state[state_name]} and type: {type(state[state_name])}" + ) + value = getattr(state, state_name) + desired_type = DashboardDefaults.TYPES.get(state_name, None) + validation_name = f"{state_name}_error_message" + conditions = DashboardDefaults.VALIDATION_CONDITION.get(state_name, None) + + validation_result = generalFunctions.validate_against( + value, desired_type, conditions + ) + setattr(state, validation_name, validation_result) + generalFunctions.update_simulation_validation_status() + + if validation_result == []: + converted_value = generalFunctions.convert_to_correct_type( + value, desired_type + ) + + if getattr(state, state_name) != converted_value: + setattr(state, state_name, converted_value) + if state_name == "kin_energy_on_ui": + on_kin_energy_unit_change() @state.change("kin_energy_unit") From f28ab2939831c1124b36fc15dd9c79e8b4fa4257 Mon Sep 17 00:00:00 2001 From: Parthib Roy Date: Sat, 8 Feb 2025 10:38:23 -0800 Subject: [PATCH 3/7] Update docstring for custom text_field --- src/python/impactx/dashboard/Input/components.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/python/impactx/dashboard/Input/components.py b/src/python/impactx/dashboard/Input/components.py index e562ecc78..f6eb75b5f 100644 --- a/src/python/impactx/dashboard/Input/components.py +++ b/src/python/impactx/dashboard/Input/components.py @@ -104,8 +104,14 @@ def text_field( label: str, v_model_name: Optional[str] = None, **kwargs ) -> vuetify.VTextField: """ - Creates a Vuetify VTextField component with - pre-filled components. + Creates a Vuetify VTextField component with the following default components: + - error_message state: It's init value is an empty list. + - step: The step value of the input (either set in defaults.py), or + by default is set to 1. + - suffix: The unit of the input (either set in defauts.py), or + by default is empty. + - type: set to 'number' to only allow a numeric input. + - dense: set to 'true' to minimize space usage. :param label: Display label :param v_model_name: v_model binding name. Optional, as default name From e3b5caf71ab30c63b93b4aa240eea31825972eab Mon Sep 17 00:00:00 2001 From: Parthib Roy Date: Sat, 8 Feb 2025 10:47:25 -0800 Subject: [PATCH 4/7] include csr to shared state can't include others (distribution parameters/lattice config/space charge because either their states are nested by dictionary use or they use different validation errors. In the future, it would be good to have a single validation function than multiple separate ones. --- .../impactx/dashboard/Input/csrConfiguration/csrMain.py | 1 - .../impactx/dashboard/Input/inputParameters/inputMain.py | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py b/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py index 9b431ca17..a08bede50 100644 --- a/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py +++ b/src/python/impactx/dashboard/Input/csrConfiguration/csrMain.py @@ -23,5 +23,4 @@ def card(): with vuetify.VCol(classes="py-0"): InputComponents.text_field( label="CSR Bins", - input=(ctrl.input_change, "['csr_bins']"), ) diff --git a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py index 5cd52f299..f7a46f19a 100644 --- a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py +++ b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py @@ -17,12 +17,14 @@ # ----------------------------------------------------------------------------- -DEFAULTS = list(DashboardDefaults.INPUT_PARAMETERS.keys()) +input_parameters_defaults = list(DashboardDefaults.INPUT_PARAMETERS.keys()) +space_charge_defaults = list(DashboardDefaults.CSR.keys()) +INPUT_DEFAULTS = input_parameters_defaults + space_charge_defaults -@state.change(*DEFAULTS) +@state.change(*INPUT_DEFAULTS) def on_input_state_change(**_): - state_changes = state.modified_keys & set(DEFAULTS) + state_changes = state.modified_keys & set(INPUT_DEFAULTS) for state_name in state_changes: if type(state[state_name]) is str: print( From a4960e7a3e80427739d439f1687368b389cde71d Mon Sep 17 00:00:00 2001 From: Parthib Roy Date: Sat, 8 Feb 2025 11:09:27 -0800 Subject: [PATCH 5/7] move shared state logic to new shared.py --- .../Input/inputParameters/inputMain.py | 57 ++----------------- src/python/impactx/dashboard/Input/shared.py | 44 ++++++++++++++ src/python/impactx/dashboard/__main__.py | 6 +- 3 files changed, 53 insertions(+), 54 deletions(-) create mode 100644 src/python/impactx/dashboard/Input/shared.py diff --git a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py index f7a46f19a..b6944b824 100644 --- a/src/python/impactx/dashboard/Input/inputParameters/inputMain.py +++ b/src/python/impactx/dashboard/Input/inputParameters/inputMain.py @@ -7,67 +7,22 @@ """ from ... import setup_server, vuetify -from .. import CardComponents, DashboardDefaults, InputComponents, generalFunctions +from .. import CardComponents, InputComponents from . import InputFunctions server, state, ctrl = setup_server() -# ----------------------------------------------------------------------------- -# Callbacks -# ----------------------------------------------------------------------------- - - -input_parameters_defaults = list(DashboardDefaults.INPUT_PARAMETERS.keys()) -space_charge_defaults = list(DashboardDefaults.CSR.keys()) -INPUT_DEFAULTS = input_parameters_defaults + space_charge_defaults - - -@state.change(*INPUT_DEFAULTS) -def on_input_state_change(**_): - state_changes = state.modified_keys & set(INPUT_DEFAULTS) - for state_name in state_changes: - if type(state[state_name]) is str: - print( - f"{state_name} = {state[state_name]} and type: {type(state[state_name])}" - ) - value = getattr(state, state_name) - desired_type = DashboardDefaults.TYPES.get(state_name, None) - validation_name = f"{state_name}_error_message" - conditions = DashboardDefaults.VALIDATION_CONDITION.get(state_name, None) - - validation_result = generalFunctions.validate_against( - value, desired_type, conditions - ) - setattr(state, validation_name, validation_result) - generalFunctions.update_simulation_validation_status() - - if validation_result == []: - converted_value = generalFunctions.convert_to_correct_type( - value, desired_type - ) - - if getattr(state, state_name) != converted_value: - setattr(state, state_name, converted_value) - if state_name == "kin_energy_on_ui": - on_kin_energy_unit_change() - - -@state.change("kin_energy_unit") -def on_kin_energy_unit_change(**kwargs) -> None: - if state.kin_energy_on_ui != 0: - InputFunctions.update_kin_energy_sim_value() - - -# ----------------------------------------------------------------------------- -# Content -# ----------------------------------------------------------------------------- - class InputParameters: """ User-Input section for beam properties. """ + @state.change("kin_energy_unit") + def on_kin_energy_unit_change(**kwargs) -> None: + if state.kin_energy_on_ui != 0: + InputFunctions.update_kin_energy_sim_value() + def card(self): """ Creates UI content for beam properties. diff --git a/src/python/impactx/dashboard/Input/shared.py b/src/python/impactx/dashboard/Input/shared.py new file mode 100644 index 000000000..5165fbafe --- /dev/null +++ b/src/python/impactx/dashboard/Input/shared.py @@ -0,0 +1,44 @@ +from .. import setup_server +from ..Input.inputParameters.inputMain import InputParameters +from . import DashboardDefaults, generalFunctions + +server, state, ctrl = setup_server() + + +input_parameters_defaults = list(DashboardDefaults.INPUT_PARAMETERS.keys()) +space_charge_defaults = list(DashboardDefaults.CSR.keys()) +INPUT_DEFAULTS = input_parameters_defaults + space_charge_defaults + + +class SharedUtilities: + @staticmethod + @state.change(*INPUT_DEFAULTS) + def on_input_state_change(**_): + state_changes = state.modified_keys & set(INPUT_DEFAULTS) + for state_name in state_changes: + if type(state[state_name]) is str: + print( + f"{state_name} = {state[state_name]} and type: {type(state[state_name])}" + ) + value = getattr(state, state_name) + desired_type = DashboardDefaults.TYPES.get(state_name, None) + validation_name = f"{state_name}_error_message" + conditions = DashboardDefaults.VALIDATION_CONDITION.get( + state_name, None + ) + + validation_result = generalFunctions.validate_against( + value, desired_type, conditions + ) + setattr(state, validation_name, validation_result) + generalFunctions.update_simulation_validation_status() + + if validation_result == []: + converted_value = generalFunctions.convert_to_correct_type( + value, desired_type + ) + + if getattr(state, state_name) != converted_value: + setattr(state, state_name, converted_value) + if state_name == "kin_energy_on_ui": + InputParameters.on_kin_energy_unit_change() diff --git a/src/python/impactx/dashboard/__main__.py b/src/python/impactx/dashboard/__main__.py index ba172c8f3..b31b89358 100644 --- a/src/python/impactx/dashboard/__main__.py +++ b/src/python/impactx/dashboard/__main__.py @@ -28,9 +28,9 @@ server, state, ctrl = setup_server() -# ----------------------------------------------------------------------------- -# Router Views -# ----------------------------------------------------------------------------- +from .Input.shared import SharedUtilities + +shared_utilities = SharedUtilities() inputParameters = InputParameters() From 367ce8d6b2dac0edbe5cc3d4c116c869ddfdb640 Mon Sep 17 00:00:00 2001 From: Parthib Roy Date: Sat, 8 Feb 2025 11:18:02 -0800 Subject: [PATCH 6/7] remove print statement --- src/python/impactx/dashboard/Input/shared.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/python/impactx/dashboard/Input/shared.py b/src/python/impactx/dashboard/Input/shared.py index 5165fbafe..2e8e50ca3 100644 --- a/src/python/impactx/dashboard/Input/shared.py +++ b/src/python/impactx/dashboard/Input/shared.py @@ -11,15 +11,13 @@ class SharedUtilities: + @staticmethod @state.change(*INPUT_DEFAULTS) def on_input_state_change(**_): state_changes = state.modified_keys & set(INPUT_DEFAULTS) for state_name in state_changes: if type(state[state_name]) is str: - print( - f"{state_name} = {state[state_name]} and type: {type(state[state_name])}" - ) value = getattr(state, state_name) desired_type = DashboardDefaults.TYPES.get(state_name, None) validation_name = f"{state_name}_error_message" From fb1b64fdaa94f638a2f1cee12622d3cb6490cdb5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 07:38:15 +0000 Subject: [PATCH 7/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/python/impactx/dashboard/Input/shared.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/python/impactx/dashboard/Input/shared.py b/src/python/impactx/dashboard/Input/shared.py index 2e8e50ca3..9a75b6b24 100644 --- a/src/python/impactx/dashboard/Input/shared.py +++ b/src/python/impactx/dashboard/Input/shared.py @@ -11,7 +11,6 @@ class SharedUtilities: - @staticmethod @state.change(*INPUT_DEFAULTS) def on_input_state_change(**_):