Skip to content

Commit

Permalink
IMPROVE: Workflow summary
Browse files Browse the repository at this point in the history
Change the workflow summary to have two tables with the "WorkChain
setings" and the "Advanced Settings". Fix several pieces in the code to
make sure the output it obtained correctly.

Also move to using jinja files and CSS to write down these somewhat
larger HTML parts that can do with some styling.
  • Loading branch information
mbercx committed Jun 9, 2021
1 parent ee7f26c commit 0022b4d
Show file tree
Hide file tree
Showing 7 changed files with 281 additions and 112 deletions.
59 changes: 14 additions & 45 deletions aiidalab_qe/node_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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()
Expand All @@ -181,50 +184,16 @@ def _fmt_yes_no(truthy):
"fmt_yes_no": _fmt_yes_no,
}
)
template = env.from_string(
"""
<pre style="{style}">
<table>
<tr>
<td>Structure geometry optimized:</td>
<td>{{ relaxed | fmt_yes_no }}</td>
</tr>
<tr>
<td>Pseudopotential library:</td>
<td>{{ pseudo_family }}</td>
</tr>
<tr>
<td>Energy cutoff (wave functions):</td>
<td>{{ energy_cutoff_wfc }}</td>
</tr>
<tr>
<td>Energy cutoff (charge density):</td>
<td>{{ energy_cutoff_rho }}</td>
</tr>
<tr>
<td>K-point mesh distance (SCF):</td>
<td>{{ scf_kpoints_distance }}</td>
</tr>
{% if bands_computed %}
<tr>
<td>K-point line distance (Bands)</td>
<td>{{ bands_kpoints_distance }}</td>
</tr>
{% endif %}
{% if pdos_computed %}
<tr>
<td>K-point mesh distance (NSCF)</td>
<td>{{ nscf_kpoints_distance }}</td>
</tr>
{% endif %}
</table>
</pre>
"""
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.")
Expand Down
91 changes: 45 additions & 46 deletions aiidalab_qe/report.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,50 @@
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",
"moderate": "SSSP/1.1/PBE/efficiency",
"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:
Expand All @@ -27,78 +55,49 @@ 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
scf_kpoints_distance = None
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
yield "scf_kpoints_distance", scf_kpoints_distance
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`
Expand Down
Empty file added aiidalab_qe/static/__init__.py
Empty file.
42 changes: 42 additions & 0 deletions aiidalab_qe/static/style.css
Original file line number Diff line number Diff line change
@@ -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;
}
27 changes: 27 additions & 0 deletions aiidalab_qe/static/welcome.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<head>
<style>
{{ style }}
</style>
</head>

<body>

<div style="padding-top: 0px; padding-bottom: 0px; line-height: 140%;">
<h3>Welcome to the AiiDAlab Quantum ESPRESSO app! 👋</h3>

The <a href="https://www.quantum-espresso.org/" target="_blank">Quantum ESPRESSO</a> 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 <a href="https://www.aiida.net/" target="_bland"> AiiDA engine</a>, and maintained in the <a href="https://aiida-quantumespresso.readthedocs.io/en/latest/" target="_blank"> Quantum ESPRESSO plugin</a> for AiiDA.

<p style="padding-top: 10px; padding-bottom: 10px;">The QEapp allows you to calculate material properties in a simple 3-step process:</p>

<ol style="list-style-type:none">
<li style="padding-top: 2px; padding-bottom: 2px;">🔍 <b>Step 1:</b> Select the structure you want to run.</li>
<li style="padding-top: 2px; padding-bottom: 2px;">⚙️ <b>Step 2:</b> Select the properties you are interested in.</li>
<li style="padding-top: 2px; padding-bottom: 2px;">🚀 <b>Step 3:</b> Submit your workflow!</li>
</ol>

<p style="padding-top: 5px; padding-bottom: 5px;">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.</p>
<p style="padding-top: 5px; padding-bottom: 5px;"><em>Happy computing! 🎉</em></p>
</div>

</body>
85 changes: 85 additions & 0 deletions aiidalab_qe/static/workflow_summary.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<head>
<style>
{{ style }}
</style>
</head>

<body>

<div class="row">
<div class="column">
<h3>Workchain settings</h3>
<table>
<tr>
<td>Structure geometry optimized</td>
<td>{{ relaxed | fmt_yes_no }}</td>
</tr>
{% if relaxed %}
<tr>
<td>Optimization method</td>
<td>{{ relax_method }}</td>
</tr>
{% endif %}
<tr>
<td>Work chain protocol</td>
<td>{{ protocol }}</td>
</tr>
<tr>
<td>Magnetism</td>
<td>{{ material_magnetic }}</td>
</tr>
<tr>
<td>Electronic type</td>
<td>{{ electronic_type }}</td>
</tr>

</table>
</div>
<div class="column">
<h3>Advanced settings</h3>
<table>
<tr>
<td>Functional</td>
<td>
<a href="{{ functional_link }}" target="_blank">
{{ functional }}
</a>
</td>
</tr>
<tr>
<td>Pseudopotential library</td>
<td>
<a href="{{ pseudo_link }}" target="_blank">
{{ pseudo_library }} {{ pseudo_protocol }} v{{ pseudo_version }}
</a>
</td>
</tr>
<tr>
<td>Energy cutoff (wave functions)</td>
<td>{{ energy_cutoff_wfc }} Ry</td>
</tr>
<tr>
<td>Energy cutoff (charge density)</td>
<td>{{ energy_cutoff_rho }} Ry</td>
</tr>
<tr>
<td>K-point mesh distance (SCF)</td>
<td>{{ scf_kpoints_distance }} &#8491;<sup>-1</sup></td>
</tr>
{% if bands_computed %}
<tr>
<td>K-point line distance (Bands)</td>
<td>{{ bands_kpoints_distance }} &#8491;<sup>-1</sup></td>
</tr>
{% endif %}
{% if pdos_computed %}
<tr>
<td>K-point mesh distance (NSCF)</td>
<td>{{ nscf_kpoints_distance }}</td>
</tr>
{% endif %}
</table>
</div>
</div>

</body>
Loading

0 comments on commit 0022b4d

Please sign in to comment.