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

Implement constant but relaxation-dependent structure results panel #1015

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
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .model import StructureResultsModel
from .structure import StructureResults
from .structure import StructureResultsPanel

__all__ = [
"StructureResultsModel",
"StructureResults",
"StructureResultsPanel",
]
18 changes: 15 additions & 3 deletions src/aiidalab_qe/app/result/components/viewer/structure/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ class StructureResultsModel(ResultsModel):

_this_process_label = "PwRelaxWorkChain"

@property
def include(self):
return "relax" in self.properties
source = None

def update(self):
super().update()
is_relaxed = "relax" in self.properties
self.title = "Relaxed structure" if is_relaxed else "Initial structure"
self.source = self.outputs if is_relaxed else self.inputs
self.auto_render = not is_relaxed # auto-render initial structure

def get_structure(self):
try:
return self.source.structure if self.source else None
except AttributeError:
# If source is outputs but job failed, there may not be a structure
return None
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
from .model import StructureResultsModel


class StructureResults(ResultsPanel[StructureResultsModel]):
class StructureResultsPanel(ResultsPanel[StructureResultsModel]):
def _render(self):
if not hasattr(self, "widget"):
self.widget = StructureDataViewer(structure=self._model.outputs.structure)
structure = self._model.get_structure()
self.widget = StructureDataViewer(structure=structure)
self.children = [self.widget]

# HACK to resize the NGL viewer in cases where it auto-rendered when its
Expand Down
12 changes: 5 additions & 7 deletions src/aiidalab_qe/app/result/components/viewer/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
from aiidalab_qe.common.panel import ResultsPanel

from .model import WorkChainResultsViewerModel
from .structure import StructureResults, StructureResultsModel
from .structure import StructureResultsModel, StructureResultsPanel


class WorkChainResultsViewer(ResultsComponent[WorkChainResultsViewerModel]):
def __init__(self, model: WorkChainResultsViewerModel, **kwargs):
super().__init__(model=model, **kwargs)
self.panels: dict[str, ResultsPanel] = {}
self._add_structure_panel() # TODO consider refactoring structure panel as a plugin
self._fetch_plugin_results()

def _on_process_change(self, _):
Expand Down Expand Up @@ -42,10 +43,6 @@ def _render(self):
"selected_index",
)

# TODO consider refactoring structure relaxation panel as a plugin
if "relax" in self._model.properties:
self._add_structure_panel()

self.children = [
self.title,
self.tabs,
Expand All @@ -60,7 +57,8 @@ def _update_panels(self):
self.panels = {
identifier: panel
for identifier, panel in self.panels.items()
if identifier in properties
if identifier == "structure"
or identifier in properties
or (identifier == "electronic_structure" and need_electronic_structure)
}

Expand All @@ -82,7 +80,7 @@ def _set_tabs(self):
def _add_structure_panel(self):
structure_model = StructureResultsModel()
structure_model.process_uuid = self._model.process_uuid
self.structure_results = StructureResults(model=structure_model)
self.structure_results = StructureResultsPanel(model=structure_model)
identifier = structure_model.identifier
self._model.add_model(identifier, structure_model)
self.panels = {
Expand Down
14 changes: 10 additions & 4 deletions src/aiidalab_qe/common/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,8 @@ class ResultsModel(PanelModel, HasProcess):
_this_process_label = ""
_this_process_uuid = None

auto_render = False

CSS_MAP = {
"finished": "success",
"failed": "danger",
Expand All @@ -522,6 +524,10 @@ def has_results(self):
node = self._fetch_child_process_node()
return node and node.is_finished_ok

def update(self):
if self.has_results:
self.auto_render = True

def update_process_status_notification(self):
self.process_status_notification = self._get_child_process_status()

Expand Down Expand Up @@ -616,13 +622,13 @@ def render(self):
return
if self.has_controls or not self._model.has_process:
return
if not self._model.has_results:
self._render_controls()
else:
if self._model.auto_render:
self._load_results()
else:
self._render_controls()

def _on_process_change(self, _):
pass
self._model.update()

def _on_monitor_counter_change(self, _):
self._model.update_process_status_notification()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_plugins_electronic_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def test_electronic_structure(generate_qeapp_workchain):
model = ElectronicStructureResultsModel()
model.process_uuid = workchain.node.uuid
result = ElectronicStructureResultsPanel(model=model)
result.render()
result._render()

widget = result.children[0]
model = widget._model
Expand Down
22 changes: 21 additions & 1 deletion tests/test_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
WorkChainResultsViewer,
WorkChainResultsViewerModel,
)
from aiidalab_qe.app.result.components.viewer.structure import StructureResultsModel
from aiidalab_qe.app.result.components.viewer.structure.structure import (
StructureResultsPanel,
)


def test_result_step(app_to_submit, generate_qeapp_workchain):
Expand Down Expand Up @@ -37,7 +41,7 @@ def test_workchainview(generate_qeapp_workchain):
model.process_uuid = workchain.node.uuid
viewer.render()
assert len(viewer.tabs.children) == 4
assert viewer.tabs._titles["0"] == "Final Geometry" # type: ignore
assert viewer.tabs._titles["0"] == "Relaxed structure" # type: ignore


def test_summary_report(data_regression, generate_qeapp_workchain):
Expand Down Expand Up @@ -76,3 +80,19 @@ def test_summary_view(generate_qeapp_workchain):
for key, value in parameters.items():
td = parsed.find("td", text=key).find_next_sibling("td")
assert td.text == value


def test_structure_results_panel(generate_qeapp_workchain):
"""Test the structure results panel can be properly generated."""
model = StructureResultsModel()
_ = StructureResultsPanel(model=model)

wc = generate_qeapp_workchain(relax_type="none")
model.process_uuid = wc.node.uuid
assert model.title == "Initial structure"
assert "properties" in model.source # source should be inputs

wc = generate_qeapp_workchain(relax_type="positions_cell")
model.process_uuid = wc.node.uuid
assert model.title == "Relaxed structure"
assert "properties" not in model.source # source should be outputs
Loading