diff --git a/aiidalab_qe/node_view.py b/aiidalab_qe/node_view.py
index 1e4d40947..4b7f0ace0 100644
--- a/aiidalab_qe/node_view.py
+++ b/aiidalab_qe/node_view.py
@@ -6,16 +6,19 @@
"""
import json
+
import ipywidgets as ipw
import nglview
from aiida.orm import Node
from aiidalab_widgets_base import ProcessMonitor, register_viewer_widget
from aiidalab_widgets_base.viewers import BandsDataViewer, StructureDataViewer
from ase import Atoms
+from importlib_resources import files
from jinja2 import Environment
from monty.json import MontyEncoder, jsanitize
from traitlets import Instance, Int, List, Unicode, Union, default, observe, validate
+from aiidalab_qe import static
from aiidalab_qe.report import generate_report_dict
@@ -167,12 +170,12 @@ def __init__(self, caption, body, *args, **kwargs):
class SummaryView(ipw.VBox):
def __init__(self, wc_node, **kwargs):
+
self.wc_node = wc_node
def _fmt_yes_no(truthy):
- return "yes" if truthy else "no"
+ return "Yes" if truthy else "No"
- style = "background-color: #fafafa; line-height: normal"
report = generate_report_dict(self.wc_node)
env = Environment()
@@ -181,50 +184,16 @@ def _fmt_yes_no(truthy):
"fmt_yes_no": _fmt_yes_no,
}
)
- template = env.from_string(
- """
-
-
-
- Structure geometry optimized: |
- {{ relaxed | fmt_yes_no }} |
-
-
- Pseudopotential library: |
- {{ pseudo_family }} |
-
-
- Energy cutoff (wave functions): |
- {{ energy_cutoff_wfc }} |
-
-
- Energy cutoff (charge density): |
- {{ energy_cutoff_rho }} |
-
-
- K-point mesh distance (SCF): |
- {{ scf_kpoints_distance }} |
-
- {% if bands_computed %}
-
- K-point line distance (Bands) |
- {{ bands_kpoints_distance }} |
-
- {% endif %}
- {% if pdos_computed %}
-
- K-point mesh distance (NSCF) |
- {{ nscf_kpoints_distance }} |
-
- {% endif %}
-
-
- """
+ template = files(static).joinpath("workflow_summary.jinja").read_text()
+ style = files(static).joinpath("style.css").read_text()
+ self.summary_view = ipw.HTML(
+ env.from_string(template).render(style=style, **report)
+ )
+ super().__init__(
+ children=[self.summary_view],
+ layout=ipw.Layout(min_height="380px"),
+ **kwargs,
)
-
- self.summary_view = ipw.HTML(template.render(style=style, **report))
-
- super().__init__(children=[self.summary_view], **kwargs)
@register_viewer_widget("process.workflow.workchain.WorkChainNode.")
diff --git a/aiidalab_qe/report.py b/aiidalab_qe/report.py
index 7bbcde5cb..9f2624e09 100644
--- a/aiidalab_qe/report.py
+++ b/aiidalab_qe/report.py
@@ -1,11 +1,16 @@
-from aiida.common.exceptions import NotExistentAttributeError
+from aiida.plugins import WorkflowFactory
+
+PwBaseWorkChain = WorkflowFactory("quantumespresso.pw.base")
+
FUNCTIONAL_LINK_MAP = {
"PBE": "https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.77.3865",
"PBEsol": "https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.100.136406",
}
-PSEUDO_LINK_MAP = {"SSSP": "https://www.materialscloud.org/discover/sssp/table"}
+PSEUDO_LINK_MAP = {
+ "SSSP": "https://www.materialscloud.org/discover/sssp/table/efficiency"
+}
PROTOCOL_PSEUDO_MAP = {
"fast": "SSSP/1.1/PBE/efficiency",
@@ -13,10 +18,33 @@
"precise": "SSSP/1.1/PBE/precision",
}
+FUNCTIONAL_REPORT_MAP = {
+ "LDA": "local density approximation (LDA)",
+ "PBE": "generalized gradient approximation of Perdew-Burke-Ernzerhof (PBE)",
+ "PBEsol": "the revised generalized gradient approximation of Perdew-Burke-Ernzerhof (PBE) for solids",
+}
+
def _generate_report_dict(qeapp_wc):
builder_parameters = qeapp_wc.get_extra("builder_parameters", {})
+ # Properties
+ run_relax = builder_parameters["relax_type"] != "none"
+ run_bands = builder_parameters["run_bands"]
+ run_pdos = builder_parameters["run_pdos"]
+
+ yield "relaxed", run_relax
+ yield "relax_method", builder_parameters["relax_type"].upper()
+ yield "bands_computed", run_bands
+ yield "pdos_computed", run_pdos
+
+ # Material settings
+ yield "material_magnetic", builder_parameters["spin_type"].title()
+ yield "electronic_type", builder_parameters["electronic_type"].title()
+
+ # Calculation settings
+ yield "protocol", builder_parameters["protocol"]
+
try:
pseudo_family = builder_parameters.get("pseudo_family", None)
if pseudo_family is None:
@@ -27,16 +55,19 @@ def _generate_report_dict(qeapp_wc):
pseudo_family_list = pseudo_family.split("/")
pseudo_library = pseudo_family_list[0]
- yield "pseudo_library", pseudo_family_list[0]
+ yield "pseudo_library", pseudo_library
if pseudo_library == "SSSP":
yield "pseudo_version", pseudo_family_list[1]
- yield "functional", pseudo_family_list[2]
+ functional = pseudo_family_list[2]
+ yield "functional", functional
yield "pseudo_protocol", pseudo_family_list[3]
else:
raise NotImplementedError
except (KeyError, AttributeError):
pass
+ yield "pseudo_link", PSEUDO_LINK_MAP[pseudo_library]
+ yield "functional_link", FUNCTIONAL_LINK_MAP[functional]
energy_cutoff_wfc = None
energy_cutoff_rho = None
@@ -44,37 +75,16 @@ def _generate_report_dict(qeapp_wc):
bands_kpoints_distance = None
nscf_kpoints_distance = None
- for work_chain in qeapp_wc.called:
-
- if energy_cutoff_wfc is None or energy_cutoff_rho is None:
- try:
- parameters = work_chain.inputs.relax.base.pw.parameters.get_dict()
- energy_cutoff_wfc = round(parameters["SYSTEM"]["ecutwfc"])
- energy_cutoff_rho = round(parameters["SYSTEM"]["ecutrho"])
- except NotExistentAttributeError:
- pass
-
- if scf_kpoints_distance is None:
- try:
- scf_kpoints_distance = work_chain.inputs.base__kpoints_distance.value
- except (AttributeError, NotExistentAttributeError):
- pass
- try:
- scf_kpoints_distance = work_chain.inputs.scf__kpoints_distance.value
- except (AttributeError, NotExistentAttributeError):
- pass
-
- if bands_kpoints_distance is None:
- try:
- bands_kpoints_distance = work_chain.inputs.bands_kpoints_distance.value
- except (AttributeError, NotExistentAttributeError):
- pass
-
- if nscf_kpoints_distance is None:
- try:
- nscf_kpoints_distance = work_chain.inputs.nscf__kpoints_distance.value
- except (AttributeError, NotExistentAttributeError):
- pass
+ if run_relax:
+ pw_parameters = qeapp_wc.inputs.relax.base.pw.parameters.get_dict()
+ scf_kpoints_distance = qeapp_wc.inputs.relax.base.kpoints_distance.value
+ if run_bands:
+ pw_parameters = qeapp_wc.inputs.bands.scf.pw.parameters.get_dict()
+ scf_kpoints_distance = qeapp_wc.inputs.bands.scf.kpoints_distance.value
+ bands_kpoints_distance = qeapp_wc.inputs.bands.bands_kpoints_distance.value
+
+ energy_cutoff_wfc = round(pw_parameters["SYSTEM"]["ecutwfc"])
+ energy_cutoff_rho = round(pw_parameters["SYSTEM"]["ecutrho"])
yield "energy_cutoff_wfc", energy_cutoff_wfc
yield "energy_cutoff_rho", energy_cutoff_rho
@@ -82,23 +92,12 @@ def _generate_report_dict(qeapp_wc):
yield "bands_kpoints_distance", bands_kpoints_distance
yield "nscf_kpoints_distance", nscf_kpoints_distance
- yield "relaxed", "relax__base__pw__parameters" in qeapp_wc.inputs
- yield "bands_computed", "bands__bands__pw__parameters" in qeapp_wc.inputs
- yield "pdos_computed", "pdos__dos__parameters" in qeapp_wc.inputs
-
def generate_report_dict(qeapp_wc):
"""Generate a dictionary for reporting the inputs for the `QeAppWorkChain`"""
return dict(_generate_report_dict(qeapp_wc))
-FUNCTIONAL_REPORT_MAP = {
- "LDA": "local density approximation (LDA)",
- "PBE": "generalized gradient approximation of Perdew-Burke-Ernzerhof (PBE)",
- "PBEsol": "the revised generalized gradient approximation of Perdew-Burke-Ernzerhof (PBE) for solids",
-}
-
-
def generate_report_text(report_dict):
"""Generate a text for reporting the inputs for the `QeAppWorkChain`
diff --git a/aiidalab_qe/static/__init__.py b/aiidalab_qe/static/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/aiidalab_qe/static/style.css b/aiidalab_qe/static/style.css
new file mode 100644
index 000000000..446bcf711
--- /dev/null
+++ b/aiidalab_qe/static/style.css
@@ -0,0 +1,42 @@
+:root {
+ --lab-blue: #2097F3;
+ --lab-background: #d3ecff;
+}
+
+table {
+ font-family: arial, sans-serif;
+ border-collapse: collapse;
+ border:1px solid #bbbbbb;
+ width: 100%;
+}
+h3 {
+ margin-top: 0px;
+}
+td, tr {
+ border-left: 2px solid var(--lab-blue);
+ text-align: left;
+ padding: 8px;
+}
+tr {
+ background-color: var(--lab-background);
+}
+tr:nth-child(even) {
+ background-color: #ffffff;
+}
+td:nth-child(even) {
+ border-left: 0px;
+}
+/* Create two equal columns that floats next to each other */
+.column {
+ float: left;
+ width: 50%;
+ padding: 10px;
+ height: 300px; /* Should be removed. Only for demonstration */
+}
+
+/* Clear floats after the columns */
+.row:after {
+ content: "";
+ display: table;
+ clear: both;
+}
diff --git a/aiidalab_qe/static/welcome.jinja b/aiidalab_qe/static/welcome.jinja
new file mode 100644
index 000000000..de670d07e
--- /dev/null
+++ b/aiidalab_qe/static/welcome.jinja
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
Welcome to the AiiDAlab Quantum ESPRESSO app! 👋
+
+ The
Quantum ESPRESSO app (or QEapp for short) is a graphical interface for calculating material properties based on density-functional theory (DFT).
+ Each of the properties is calculated by workflows powered by the
AiiDA engine, and maintained in the
Quantum ESPRESSO plugin for AiiDA.
+
+
The QEapp allows you to calculate material properties in a simple 3-step process:
+
+
+ - 🔍 Step 1: Select the structure you want to run.
+ - ⚙️ Step 2: Select the properties you are interested in.
+ - 🚀 Step 3: Submit your workflow!
+
+
+
New users can go straight to the first step and select their structure. Once you've already calculated some properties, you can select the corresponding workflow using the dropdown below.
+
Happy computing! 🎉
+
+
+
diff --git a/aiidalab_qe/static/workflow_summary.jinja b/aiidalab_qe/static/workflow_summary.jinja
new file mode 100644
index 000000000..44d033574
--- /dev/null
+++ b/aiidalab_qe/static/workflow_summary.jinja
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
Workchain settings
+
+
+ Structure geometry optimized |
+ {{ relaxed | fmt_yes_no }} |
+
+ {% if relaxed %}
+
+ Optimization method |
+ {{ relax_method }} |
+
+ {% endif %}
+
+ Work chain protocol |
+ {{ protocol }} |
+
+
+ Magnetism |
+ {{ material_magnetic }} |
+
+
+ Electronic type |
+ {{ electronic_type }} |
+
+
+
+
+
+
Advanced settings
+
+
+ Functional |
+
+
+ {{ functional }}
+
+ |
+
+
+ Pseudopotential library |
+
+
+ {{ pseudo_library }} {{ pseudo_protocol }} v{{ pseudo_version }}
+
+ |
+
+
+ Energy cutoff (wave functions) |
+ {{ energy_cutoff_wfc }} Ry |
+
+
+ Energy cutoff (charge density) |
+ {{ energy_cutoff_rho }} Ry |
+
+
+ K-point mesh distance (SCF) |
+ {{ scf_kpoints_distance }} Å-1 |
+
+ {% if bands_computed %}
+
+ K-point line distance (Bands) |
+ {{ bands_kpoints_distance }} Å-1 |
+
+ {% endif %}
+ {% if pdos_computed %}
+
+ K-point mesh distance (NSCF) |
+ {{ nscf_kpoints_distance }} |
+
+ {% endif %}
+
+
+
+
+
\ No newline at end of file
diff --git a/qe.ipynb b/qe.ipynb
index 71a296ab8..fdb5526af 100644
--- a/qe.ipynb
+++ b/qe.ipynb
@@ -16,11 +16,63 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 2,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "cbcd2e00e9b04fb4a237039b76f4663d",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": []
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/opt/conda/lib/python3.7/site-packages/aiida/orm/computers.py:757: AiidaDeprecationWarning: this property is deprecated, use the `label` property instead\n",
+ " warnings.warn('this property is deprecated, use the `label` property instead', AiidaDeprecationWarning) # pylint: disable=no-member\n"
+ ]
+ },
+ {
+ "data": {
+ "application/vnd.jupyter.widget-view+json": {
+ "model_id": "8730b3d71edb443c8dbd45981c549e86",
+ "version_major": 2,
+ "version_minor": 0
+ },
+ "text/plain": [
+ "HTML(value='\\n