Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move to App widget and call from notebook #442

Merged
merged 3 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 4 additions & 146 deletions qe.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -35,168 +35,26 @@
"outputs": [],
"source": [
"import ipywidgets as ipw\n",
"from aiida.orm import load_node\n",
"from aiidalab_widgets_base import (\n",
" BasicCellEditor,\n",
" BasicStructureEditor,\n",
" OptimadeQueryWidget,\n",
" StructureBrowserWidget,\n",
" StructureExamplesWidget,\n",
" StructureManagerWidget,\n",
" StructureUploadWidget,\n",
" WizardAppWidget,\n",
" WizardAppWidgetStep,\n",
")\n",
"from aiidalab_widgets_base.bug_report import (\n",
" install_create_github_issue_exception_handler,\n",
")\n",
"from importlib_resources import files\n",
"from IPython.display import display\n",
"from jinja2 import Environment\n",
"\n",
"from aiidalab_qe.app import static\n",
"from aiidalab_qe.app.common.process import QeAppWorkChainSelector\n",
"from aiidalab_qe.app.common.widgets import AddingTagsEditor\n",
"from aiidalab_qe.app.configuration import ConfigureQeAppWorkChainStep\n",
"from aiidalab_qe.app.result import ViewQeAppWorkChainStatusAndResultsStep\n",
"from aiidalab_qe.app.structure import Examples, StructureSelectionStep\n",
"from aiidalab_qe.app.submission import SubmitQeAppWorkChainStep\n",
"from aiidalab_qe.app import App, static\n",
"from aiidalab_qe.version import __version__\n",
"\n",
"OptimadeQueryWidget.title = \"OPTIMADE\" # monkeypatch\n",
"\n",
"\n",
"# Create the application steps\n",
"structure_manager_widget = StructureManagerWidget(\n",
" importers=[\n",
" StructureUploadWidget(title=\"Upload file\"),\n",
" OptimadeQueryWidget(embedded=False),\n",
" StructureBrowserWidget(title=\"AiiDA database\"),\n",
" StructureExamplesWidget(title=\"From Examples\", examples=Examples),\n",
" ],\n",
" editors=[\n",
" BasicCellEditor(title=\"Edit cell\"),\n",
" BasicStructureEditor(title=\"Edit structure\"),\n",
" AddingTagsEditor(title=\"Edit tags\"),\n",
" ],\n",
" node_class=\"StructureData\",\n",
" storable=False,\n",
" configuration_tabs=[\"Cell\", \"Selection\", \"Appearance\", \"Download\"],\n",
")\n",
"structure_selection_step = StructureSelectionStep(\n",
" manager=structure_manager_widget, auto_advance=True\n",
")\n",
"configure_qe_app_work_chain_step = ConfigureQeAppWorkChainStep(auto_advance=True)\n",
"submit_qe_app_work_chain_step = SubmitQeAppWorkChainStep(auto_advance=True)\n",
"view_qe_app_work_chain_status_and_results_step = (\n",
" ViewQeAppWorkChainStatusAndResultsStep()\n",
")\n",
"\n",
"# Link the application steps\n",
"ipw.dlink(\n",
" (structure_selection_step, \"state\"),\n",
" (configure_qe_app_work_chain_step, \"previous_step_state\"),\n",
")\n",
"ipw.dlink(\n",
" (structure_selection_step, \"confirmed_structure\"),\n",
" (submit_qe_app_work_chain_step, \"input_structure\"),\n",
")\n",
"ipw.dlink(\n",
" (structure_selection_step, \"confirmed_structure\"),\n",
" (configure_qe_app_work_chain_step, \"input_structure\"),\n",
")\n",
"ipw.dlink(\n",
" (configure_qe_app_work_chain_step, \"state\"),\n",
" (submit_qe_app_work_chain_step, \"previous_step_state\"),\n",
")\n",
"ipw.dlink(\n",
" (configure_qe_app_work_chain_step, \"workchain_settings\"),\n",
" (submit_qe_app_work_chain_step, \"workchain_settings\"),\n",
")\n",
"ipw.dlink(\n",
" (configure_qe_app_work_chain_step, \"advanced_settings\"),\n",
" (submit_qe_app_work_chain_step, \"advanced_settings\"),\n",
")\n",
"ipw.dlink(\n",
" (configure_qe_app_work_chain_step, \"pseudo_family_selector\"),\n",
" (submit_qe_app_work_chain_step, \"pseudo_family_selector\"),\n",
")\n",
"ipw.dlink(\n",
" (configure_qe_app_work_chain_step, \"pseudo_setter\"),\n",
" (submit_qe_app_work_chain_step, \"pseudo_setter\"),\n",
")\n",
"\n",
"ipw.dlink(\n",
" (submit_qe_app_work_chain_step, \"process\"),\n",
" (view_qe_app_work_chain_status_and_results_step, \"process\"),\n",
" transform=lambda node: node.uuid if node is not None else None,\n",
")\n",
"\n",
"# Add the application steps to the application\n",
"app = WizardAppWidget(\n",
" steps=[\n",
" (\"Select structure\", structure_selection_step),\n",
" (\"Configure workflow\", configure_qe_app_work_chain_step),\n",
" (\"Choose computational resources\", submit_qe_app_work_chain_step),\n",
" (\"Status & Results\", view_qe_app_work_chain_status_and_results_step),\n",
" ]\n",
")\n",
"\n",
"# Reset all subsequent steps in case that a new structure is selected\n",
"\n",
"\n",
"def _observe_structure_selection(change):\n",
" with structure_selection_step.hold_sync():\n",
" if (\n",
" structure_selection_step.confirmed_structure is not None\n",
" and structure_selection_step.confirmed_structure != change[\"new\"]\n",
" ):\n",
" app.reset()\n",
"\n",
"\n",
"structure_selection_step.observe(_observe_structure_selection, \"structure\")\n",
"\n",
"# Add process selection header\n",
"work_chain_selector = QeAppWorkChainSelector(layout=ipw.Layout(width=\"auto\"))\n",
"\n",
"\n",
"def _observe_process_selection(change):\n",
" if change[\"old\"] == change[\"new\"]:\n",
" return\n",
" pk = change[\"new\"]\n",
" if pk is None:\n",
" app.reset()\n",
" app.selected_index = 0\n",
" else:\n",
" process = load_node(pk)\n",
" with structure_manager_widget.hold_sync():\n",
" with structure_selection_step.hold_sync():\n",
" app.selected_index = 3\n",
" structure_manager_widget.input_structure = process.inputs.structure\n",
" structure_selection_step.structure = process.inputs.structure\n",
" structure_selection_step.confirmed_structure = process.inputs.structure\n",
" configure_qe_app_work_chain_step.state = (\n",
" WizardAppWidgetStep.State.SUCCESS\n",
" )\n",
" submit_qe_app_work_chain_step.process = process\n",
"\n",
"\n",
"work_chain_selector.observe(_observe_process_selection, \"value\")\n",
"ipw.dlink(\n",
" (submit_qe_app_work_chain_step, \"process\"),\n",
" (work_chain_selector, \"value\"),\n",
" transform=lambda node: None if node is None else node.pk,\n",
")\n",
"\n",
"env = Environment()\n",
"\n",
"template = files(static).joinpath(\"welcome.jinja\").read_text()\n",
"style = files(static).joinpath(\"style.css\").read_text()\n",
"welcome_message = ipw.HTML(env.from_string(template).render(style=style))\n",
"footer = ipw.HTML(\n",
" f'<p style=\"text-align:right;\">Copyright (c) 2022 AiiDAlab team (EPFL)&#8195Version: {__version__}</p>'\n",
" f'<p style=\"text-align:right;\">Copyright (c) 2023 AiiDAlab team (EPFL)&#8195Version: {__version__}</p>'\n",
")\n",
"\n",
"app_with_work_chain_selector = ipw.VBox(children=[work_chain_selector, app])\n",
"app_with_work_chain_selector = App(qe_auto_setup=True)\n",
"\n",
"output = ipw.Output()\n",
"install_create_github_issue_exception_handler(\n",
Expand Down
12 changes: 2 additions & 10 deletions src/aiidalab_qe/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
"""Package for the AiiDAlab QE app."""

from .common import WorkChainSelector
from .configuration import ConfigureQeAppWorkChainStep
from .result import ViewQeAppWorkChainStatusAndResultsStep
from .structure import StructureSelectionStep
from .submission import SubmitQeAppWorkChainStep
from .main import App

__all__ = [
"StructureSelectionStep",
"ConfigureQeAppWorkChainStep",
"SubmitQeAppWorkChainStep",
"ViewQeAppWorkChainStatusAndResultsStep",
"WorkChainSelector",
"App",
]
5 changes: 4 additions & 1 deletion src/aiidalab_qe/app/common/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# trigger registration of the viewer widget:
from .node_view import CalcJobNodeViewerWidget # noqa: F401
from .process import WorkChainSelector
from .process import QeAppWorkChainSelector, WorkChainSelector
from .widgets import AddingTagsEditor

__all__ = [
"WorkChainSelector",
"QeAppWorkChainSelector",
"AddingTagsEditor",
]
166 changes: 166 additions & 0 deletions src/aiidalab_qe/app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# -*- coding: utf-8 -*-
"""The main widget that shows the application in the Jupyter notebook.

Authors: AiiDAlab team
"""

import ipywidgets as ipw
from aiida.orm import load_node
from aiidalab_widgets_base import (
BasicCellEditor,
BasicStructureEditor,
OptimadeQueryWidget,
StructureBrowserWidget,
StructureExamplesWidget,
StructureManagerWidget,
StructureUploadWidget,
WizardAppWidget,
WizardAppWidgetStep,
)

from aiidalab_qe.app.common import AddingTagsEditor, QeAppWorkChainSelector
from aiidalab_qe.app.configuration import ConfigureQeAppWorkChainStep
from aiidalab_qe.app.result import ViewQeAppWorkChainStatusAndResultsStep
from aiidalab_qe.app.structure import Examples, StructureSelectionStep
from aiidalab_qe.app.submission import SubmitQeAppWorkChainStep

OptimadeQueryWidget.title = "OPTIMADE" # monkeypatch


class App(ipw.VBox):
"""The main widget that combines all the application steps together."""

def __init__(self, qe_auto_setup=True):
# Create the application steps
self.structure_manager_widget = StructureManagerWidget(
importers=[
StructureUploadWidget(title="Upload file"),
OptimadeQueryWidget(embedded=False),
StructureBrowserWidget(title="AiiDA database"),
StructureExamplesWidget(title="From Examples", examples=Examples),
],
editors=[
BasicCellEditor(title="Edit cell"),
BasicStructureEditor(title="Edit structure"),
AddingTagsEditor(title="Edit tags"),
],
node_class="StructureData",
storable=False,
configuration_tabs=["Cell", "Selection", "Appearance", "Download"],
)
self.structure_selection_step = StructureSelectionStep(
manager=self.structure_manager_widget, auto_advance=True
)
self.structure_selection_step.observe(
self._observe_structure_selection, "structure"
)

self.configure_qe_app_work_chain_step = ConfigureQeAppWorkChainStep(
auto_advance=True
)
self.submit_qe_app_work_chain_step = SubmitQeAppWorkChainStep(
auto_advance=True, qe_auto_setup=qe_auto_setup
)
view_qe_app_work_chain_status_and_results_step = (
ViewQeAppWorkChainStatusAndResultsStep()
)

# Link the application steps
ipw.dlink(
(self.structure_selection_step, "state"),
(self.configure_qe_app_work_chain_step, "previous_step_state"),
)
ipw.dlink(
(self.structure_selection_step, "confirmed_structure"),
(self.submit_qe_app_work_chain_step, "input_structure"),
)
ipw.dlink(
(self.structure_selection_step, "confirmed_structure"),
(self.configure_qe_app_work_chain_step, "input_structure"),
)
ipw.dlink(
(self.configure_qe_app_work_chain_step, "state"),
(self.submit_qe_app_work_chain_step, "previous_step_state"),
)
ipw.dlink(
(self.configure_qe_app_work_chain_step, "workchain_settings"),
(self.submit_qe_app_work_chain_step, "workchain_settings"),
)
ipw.dlink(
(self.configure_qe_app_work_chain_step, "advanced_settings"),
(self.submit_qe_app_work_chain_step, "advanced_settings"),
)
ipw.dlink(
(self.configure_qe_app_work_chain_step, "pseudo_family_selector"),
(self.submit_qe_app_work_chain_step, "pseudo_family_selector"),
)
ipw.dlink(
(self.configure_qe_app_work_chain_step, "pseudo_setter"),
(self.submit_qe_app_work_chain_step, "pseudo_setter"),
)

ipw.dlink(
(self.submit_qe_app_work_chain_step, "process"),
(view_qe_app_work_chain_status_and_results_step, "process"),
transform=lambda node: node.uuid if node is not None else None,
)

# Add the application steps to the application
self._wizard_app_widget = WizardAppWidget(
steps=[
("Select structure", self.structure_selection_step),
("Configure workflow", self.configure_qe_app_work_chain_step),
("Choose computational resources", self.submit_qe_app_work_chain_step),
("Status & Results", view_qe_app_work_chain_status_and_results_step),
]
)

# Add process selection header
work_chain_selector = QeAppWorkChainSelector(layout=ipw.Layout(width="auto"))
work_chain_selector.observe(self._observe_process_selection, "value")

ipw.dlink(
(self.submit_qe_app_work_chain_step, "process"),
(work_chain_selector, "value"),
transform=lambda node: None if node is None else node.pk,
)

super().__init__(
children=[
work_chain_selector,
self._wizard_app_widget,
]
)

# Reset all subsequent steps in case that a new structure is selected
def _observe_structure_selection(self, change):
with self.structure_selection_step.hold_sync():
if (
self.structure_selection_step.confirmed_structure is not None
and self.structure_selection_step.confirmed_structure != change["new"]
):
self._wizard_app_widget.reset()

def _observe_process_selection(self, change):
if change["old"] == change["new"]:
return
pk = change["new"]
if pk is None:
self._wizard_app_widget.reset()
self._wizard_app_widget.selected_index = 0
else:
process = load_node(pk)
with self.structure_manager_widget.hold_sync():
with self.structure_selection_step.hold_sync():
self._wizard_app_widget.selected_index = 3
self.structure_manager_widget.input_structure = (
process.inputs.structure
)
self.structure_selection_step.structure = process.inputs.structure
self.structure_selection_step.confirmed_structure = (
process.inputs.structure
)
self.configure_qe_app_work_chain_step.state = (
WizardAppWidgetStep.State.SUCCESS
)
self.submit_qe_app_work_chain_step.process = process