From a7d2e3f177f64737b520920ceaa7b3853862d7c9 Mon Sep 17 00:00:00 2001 From: Edan Bainglass <45081142+edan-bainglass@users.noreply.github.com> Date: Mon, 13 Jan 2025 17:08:31 +0100 Subject: [PATCH] Utilize external resource setup notebook for code management (#986) This PR provides a button (top-level and in step 3) that links to the new external resource setup notebook in aiidalab-home (aiidalab/aiidalab-home#188). It also removes the code setup widget buttons from the individual code selectors in step 3 (in favor of the external notebook). --- src/aiidalab_qe/app/submission/__init__.py | 52 +++++++++++++------ .../app/submission/global_settings/model.py | 1 + .../app/submission/global_settings/setting.py | 9 ---- src/aiidalab_qe/app/wrapper.py | 10 +++- src/aiidalab_qe/common/panel.py | 21 ++++---- src/aiidalab_qe/common/widgets.py | 6 ++- .../test_create_builder_default.yml | 7 --- 7 files changed, 62 insertions(+), 44 deletions(-) diff --git a/src/aiidalab_qe/app/submission/__init__.py b/src/aiidalab_qe/app/submission/__init__.py index f4db7c51b..c3777adfd 100644 --- a/src/aiidalab_qe/app/submission/__init__.py +++ b/src/aiidalab_qe/app/submission/__init__.py @@ -19,7 +19,7 @@ ) from aiidalab_qe.common.setup_codes import QESetupWidget from aiidalab_qe.common.setup_pseudos import PseudosInstallWidget -from aiidalab_qe.common.widgets import QeDependentWizardStep +from aiidalab_qe.common.widgets import LinkButton, QeDependentWizardStep from .global_settings import GlobalResourceSettingsModel, GlobalResourceSettingsPanel from .model import SubmissionStepModel @@ -135,6 +135,20 @@ def _render(self): (self.submission_warning_messages, "value"), ) + self.setup_new_codes_button = LinkButton( + description="Setup resources", + link="../home/code_setup.ipynb", + icon="database", + ) + + self.refresh_resources_button = ipw.Button( + description="Refresh resources", + icon="refresh", + button_style="primary", + layout=ipw.Layout(width="fit-content", margin="2px 2px 12px"), + ) + self.refresh_resources_button.on_click(self._refresh_resources) + self.tabs = ipw.Tab( layout=ipw.Layout(min_height="250px"), selected_index=None, @@ -146,33 +160,35 @@ def _render(self): self.children = [ InAppGuide(identifier="submission-step"), - ipw.HTML(""" -
-

Codes

-
- """), ipw.HTML("""
- Select the code to use for running the calculations. The codes on + Select the codes to use for running the calculations. The codes on the local machine (localhost) are installed by default, but you can configure new ones on potentially more powerful machines by clicking - on "Setup new code". + on Setup resources (also at + the top of the app). Make sure to click the Refresh resources + button below after making changes to AiiDA resources to update the + app resources.
"""), + ipw.HBox( + children=[ + self.setup_new_codes_button, + self.refresh_resources_button, + ], + layout=ipw.Layout(grid_gap="5px"), + ), self.tabs, self.sssp_installation, self.qe_setup, self.submission_blocker_messages, self.submission_warning_messages, ipw.HTML(""" -
-

Labeling your job

-

- Label your job and provide a brief description. These details - help identify the job later and make the search process easier. - While optional, adding a description is recommended for better - clarity. -

+
+ Label your job and provide a brief description. These details + help identify the job later and make the search process easier. + While optional, adding a description is recommended for better + clarity.
"""), self.process_label, @@ -277,6 +293,10 @@ def _toggle_qe_installation_widget(self): qe_installation_display = "none" if self._model.qe_installed else "block" self.qe_setup.layout.display = qe_installation_display + def _refresh_resources(self, _=None): + for _, model in self._model.get_models(): + model.refresh_codes() + def _update_tabs(self): children = [] titles = [] diff --git a/src/aiidalab_qe/app/submission/global_settings/model.py b/src/aiidalab_qe/app/submission/global_settings/model.py index 4e36ac5ad..5ef16482e 100644 --- a/src/aiidalab_qe/app/submission/global_settings/model.py +++ b/src/aiidalab_qe/app/submission/global_settings/model.py @@ -93,6 +93,7 @@ def add_global_model( description=name, default_calc_job_plugin=default_calc_job_plugin, ) + base_code_model.activate() else: base_code_model = CodeModel( name=name, diff --git a/src/aiidalab_qe/app/submission/global_settings/setting.py b/src/aiidalab_qe/app/submission/global_settings/setting.py index 6db0fdeb6..d7f330d2b 100644 --- a/src/aiidalab_qe/app/submission/global_settings/setting.py +++ b/src/aiidalab_qe/app/submission/global_settings/setting.py @@ -56,7 +56,6 @@ def render(self): self.rendered = True # Render any active codes - self._model.get_model("quantumespresso.pw").activate() for _, code_model in self._model.get_models(): if code_model.is_active: self._toggle_code(code_model) @@ -118,14 +117,6 @@ def _render_code_widget( ], ) - def update_options(_, model=code_model): - model.update(self._model.DEFAULT_USER_EMAIL, refresh=True) - - code_widget.code_selection.code_select_dropdown.observe( - update_options, - "options", - ) - def toggle_widget(_=None, model=code_model, widget=code_widget): widget = self.code_widgets[model.name] widget.layout.display = "block" if model.is_active else "none" diff --git a/src/aiidalab_qe/app/wrapper.py b/src/aiidalab_qe/app/wrapper.py index 18883a6e1..edc93fbc9 100644 --- a/src/aiidalab_qe/app/wrapper.py +++ b/src/aiidalab_qe/app/wrapper.py @@ -212,13 +212,21 @@ def __init__(self) -> None: disabled=True, ) + self.setup_resources_link = LinkButton( + description="Setup resources", + link="../home/code_setup.ipynb", + icon="database", + disabled=True, + ) + self.controls = ipw.HBox( children=[ self.guide_toggle, self.about_toggle, self.calculation_history_link, + self.setup_resources_link, self.new_workchain_link, - ] + ], ) self.controls.add_class("app-controls") diff --git a/src/aiidalab_qe/common/panel.py b/src/aiidalab_qe/common/panel.py index 0d91a0ffc..8228adef4 100644 --- a/src/aiidalab_qe/common/panel.py +++ b/src/aiidalab_qe/common/panel.py @@ -219,6 +219,10 @@ def add_model(self, identifier, model): super().add_model(identifier, model) model.update(self.DEFAULT_USER_EMAIL) + def refresh_codes(self): + for _, code_model in self.get_models(): + code_model.update(self.DEFAULT_USER_EMAIL, refresh=True) + def update_submission_blockers(self): self.submission_blockers = list(self._check_submission_blockers()) @@ -227,6 +231,7 @@ def get_model_state(self): "codes": { identifier: code_model.get_model_state() for identifier, code_model in self.get_models() + if code_model.is_ready }, } @@ -335,7 +340,6 @@ def _render_code_widget( code_model.observe( self._on_code_resource_change, [ - "options", "selected", "num_cpus", "num_nodes", @@ -358,6 +362,10 @@ class PluginResourceSettingsModel(ResourceSettingsModel): override = tl.Bool(False) + def add_model(self, identifier, model: CodeModel): + super().add_model(identifier, model) + model.activate() + def update(self): """Updates the code models from the global resources. @@ -370,9 +378,6 @@ def update(self): default_calc_job_plugin = code_model.default_calc_job_plugin if default_calc_job_plugin in self.global_codes: code_resources: dict = self.global_codes[default_calc_job_plugin] # type: ignore - options = code_resources.get("options", []) - if options != code_model.options: - code_model.update(self.DEFAULT_USER_EMAIL, refresh=True) code_model.set_model_state(code_resources) def get_model_state(self): @@ -442,7 +447,8 @@ def render(self): # Render any active codes for _, code_model in self._model.get_models(): - self._toggle_code(code_model) + if code_model.is_active: + self._toggle_code(code_model) return self.code_widgets_container @@ -478,11 +484,6 @@ def _link_override_to_widget_disable(self, code_model, code_widget): (code_widget.num_nodes, "disabled"), lambda override: not override, ) - ipw.dlink( - (code_model, "override"), - (code_widget.code_selection.btn_setup_new_code, "disabled"), - lambda override: not override, - ) ipw.dlink( (code_model, "override"), (code_widget.btn_setup_resource_detail, "disabled"), diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py index 394e23b68..1db953d96 100644 --- a/src/aiidalab_qe/common/widgets.py +++ b/src/aiidalab_qe/common/widgets.py @@ -687,7 +687,11 @@ def __init__(self, **kwargs): """Widget to setup the compute resources, which include the code, the number of nodes and the number of cpus. """ - self.code_selection = ComputationalResourcesWidget(**kwargs) + self.code_selection = ComputationalResourcesWidget( + include_setup_widget=False, + fetch_codes=True, # TODO resolve testing issues when set to `False` + **kwargs, + ) self.code_selection.layout.width = "80%" self.num_nodes = ipw.BoundedIntText( diff --git a/tests/test_submit_qe_workchain/test_create_builder_default.yml b/tests/test_submit_qe_workchain/test_create_builder_default.yml index 1ddd16d4a..40ce8a14b 100644 --- a/tests/test_submit_qe_workchain/test_create_builder_default.yml +++ b/tests/test_submit_qe_workchain/test_create_builder_default.yml @@ -60,13 +60,6 @@ codes: nodes: 1 ntasks_per_node: 2 parallelization: {} - quantumespresso.xspectra: - code: null - cpus: 1 - cpus_per_task: 1 - max_wallclock_seconds: 43200 - nodes: 1 - ntasks_per_node: 1 pdos: codes: dos: