diff --git a/src/aiidalab_qe/app/configuration/advanced/advanced.py b/src/aiidalab_qe/app/configuration/advanced/advanced.py
index 0007796e3..f157ad155 100644
--- a/src/aiidalab_qe/app/configuration/advanced/advanced.py
+++ b/src/aiidalab_qe/app/configuration/advanced/advanced.py
@@ -7,6 +7,7 @@
from aiidalab_qe.common.infobox import InAppGuide
from aiidalab_qe.common.panel import ConfigurationSettingsPanel
+from aiidalab_qe.common.widgets import HBoxWithUnits
from .hubbard import (
HubbardConfigurationSettingsModel,
@@ -84,7 +85,7 @@ def render(self):
self.clean_workdir = ipw.Checkbox(
description="Delete the work directory after the calculation",
indent=False,
- layout=ipw.Layout(width="fit-content"),
+ layout=ipw.Layout(width="fit-content", margin="5px 2px"),
)
ipw.link(
(self._model, "clean_workdir"),
@@ -153,7 +154,6 @@ def render(self):
self.scf_conv_thr = ipw.BoundedFloatText(
min=1e-15,
max=1.0,
- format="0.0e",
description="SCF:",
style={"description_width": "150px"},
)
@@ -226,16 +226,38 @@ def render(self):
self.clean_workdir,
self.total_charge,
self.van_der_waals,
- self.magnetization,
- ipw.HTML("Convergence thresholds"),
- self.forc_conv_thr,
- self.etot_conv_thr,
+ ipw.HTML("
+ Control the convergence criteria of the self-consistent field (SCF)
+ geometry optimization cycles.
+
+ """),
+ ipw.HTML("
+ Setting thresholds for energy, force, and self-consistency ensures calculation accuracy and stability.
+
+ Lower values increase the accuracy but also the computational cost.
+
+ The default values are set by the protocol are usually a
+ good starting point.
+
+ """),
+ HBoxWithUnits(self.forc_conv_thr, "a.u."),
+ HBoxWithUnits(self.etot_conv_thr, "a.u."),
self.scf_conv_thr,
- ipw.HTML("
+ Setting a maximum number of electronic and ionic optimization steps
+ ensures that the calculation does not run indefinitely.
+
+ """),
self.electron_maxstep,
self.optimization_maxsteps,
self.smearing,
- ipw.HTML("
The k-points mesh density of the SCF calculation is set by the
@@ -249,12 +271,12 @@ def render(self):
"""),
ipw.HBox(
children=[
- self.kpoints_distance,
- ipw.HTML("Å
-1"),
+ HBoxWithUnits(self.kpoints_distance, "Å
-1"),
self.mesh_grid,
],
layout=ipw.Layout(align_items="center"),
),
+ self.magnetization,
self.hubbard,
self.pseudos,
]
diff --git a/src/aiidalab_qe/app/configuration/advanced/hubbard/hubbard.py b/src/aiidalab_qe/app/configuration/advanced/hubbard/hubbard.py
index 053b150cc..9170e9e81 100644
--- a/src/aiidalab_qe/app/configuration/advanced/hubbard/hubbard.py
+++ b/src/aiidalab_qe/app/configuration/advanced/hubbard/hubbard.py
@@ -1,5 +1,7 @@
import ipywidgets as ipw
+from aiidalab_qe.common.widgets import HBoxWithUnits
+
from ..subsettings import AdvancedConfigurationSubSettingsPanel
from .model import HubbardConfigurationSettingsModel
@@ -36,10 +38,13 @@ def render(self):
(self.activate_hubbard_checkbox, "value"),
)
- self.eigenvalues_help = ipw.HTML(
- value="For transition metals and lanthanoids, the starting eigenvalues can be defined (Magnetic calculation).",
- layout=ipw.Layout(width="auto"),
- )
+ self.eigenvalues_help = ipw.HTML("""
+
+ For transition metals and lanthanoids, the starting eigenvalues can be defined (magnetic calculation).
+
+ It is useful to suggest the desired orbital occupations when the default choice takes another path.
+
+ """)
self.define_eigenvalues_checkbox = ipw.Checkbox(
description="Define eigenvalues",
indent=False,
@@ -62,7 +67,7 @@ def render(self):
self.container = ipw.VBox()
self.children = [
- ipw.HTML("
Hubbard (DFT+U)"),
+ ipw.HTML("
Hubbard (DFT+U)
"),
self.activate_hubbard_checkbox,
self.container,
]
@@ -121,14 +126,7 @@ def _build_hubbard_widget(self):
],
)
self.links.append(link)
- children.append(
- ipw.HBox(
- children=[
- float_widget,
- ipw.HTML("eV"),
- ],
- )
- )
+ children.append(HBoxWithUnits(float_widget, "eV"))
if self._model.needs_eigenvalues_widget:
children.append(self.eigenvalues_container)
@@ -151,8 +149,15 @@ def update(index, spin, state, symbol, value):
(kind_name, num_states),
) in enumerate(self._model.applicable_kind_names):
label_layout = ipw.Layout(justify_content="flex-start", width="50px")
- spin_up_row = ipw.HBox([ipw.Label("Up:", layout=label_layout)])
- spin_down_row = ipw.HBox([ipw.Label("Down:", layout=label_layout)])
+ spin_row_layout = ipw.Layout(grid_gap="5px")
+ spin_up_row = ipw.HBox(
+ children=[ipw.Label("Up:", layout=label_layout)],
+ layout=spin_row_layout,
+ )
+ spin_down_row = ipw.HBox(
+ children=[ipw.Label("Down:", layout=label_layout)],
+ layout=spin_row_layout,
+ )
for state_index in range(num_states):
eigenvalues_up = ipw.Dropdown(
@@ -224,7 +229,13 @@ def update(index, spin, state, symbol, value):
children.append(
ipw.HBox(
[
- ipw.Label(kind_name, layout=label_layout),
+ ipw.Label(
+ kind_name,
+ layout=ipw.Layout(
+ justify_content="flex-start",
+ width="80px",
+ ),
+ ),
ipw.VBox(
children=[
spin_up_row,
diff --git a/src/aiidalab_qe/app/configuration/advanced/magnetization/magnetization.py b/src/aiidalab_qe/app/configuration/advanced/magnetization/magnetization.py
index 27c673f7d..5ccfd9c05 100644
--- a/src/aiidalab_qe/app/configuration/advanced/magnetization/magnetization.py
+++ b/src/aiidalab_qe/app/configuration/advanced/magnetization/magnetization.py
@@ -1,5 +1,7 @@
import ipywidgets as ipw
+from aiidalab_qe.common.widgets import HBoxWithUnits
+
from ..subsettings import AdvancedConfigurationSubSettingsPanel
from .model import MagnetizationConfigurationSettingsModel
@@ -48,9 +50,9 @@ def render(self):
if self.rendered:
return
- self.header = ipw.HTML("
Magnetization")
+ self.header = ipw.HTML("
Magnetization
")
- self.unit = ipw.HTML("µ
B")
+ self.unit = "µ
B"
self.magnetization_type_help = ipw.HTML()
ipw.dlink(
@@ -83,11 +85,9 @@ def render(self):
(self.tot_magnetization, "value"),
)
- self.tot_magnetization_with_unit = ipw.HBox(
- children=[
- self.tot_magnetization,
- self.unit,
- ],
+ self.tot_magnetization_with_unit = HBoxWithUnits(
+ self.tot_magnetization,
+ self.unit,
)
self.kind_moment_widgets = ipw.VBox()
@@ -168,14 +168,7 @@ def _build_kinds_widget(self):
],
)
self.links.append(link)
- children.append(
- ipw.HBox(
- children=[
- kind_moment_widget,
- self.unit,
- ],
- )
- )
+ children.append(HBoxWithUnits(kind_moment_widget, "µ
B"))
self.kind_moment_widgets.children = children
diff --git a/src/aiidalab_qe/app/configuration/advanced/pseudos/pseudos.py b/src/aiidalab_qe/app/configuration/advanced/pseudos/pseudos.py
index 6bf026069..5fd621b82 100644
--- a/src/aiidalab_qe/app/configuration/advanced/pseudos/pseudos.py
+++ b/src/aiidalab_qe/app/configuration/advanced/pseudos/pseudos.py
@@ -7,7 +7,7 @@
from aiida import orm
from aiida.plugins import DataFactory, GroupFactory
-from aiidalab_qe.common.widgets import LoadingWidget
+from aiidalab_qe.common.widgets import HBoxWithUnits, LoadingWidget
from aiidalab_widgets_base.utils import StatusHTML
from ..subsettings import AdvancedConfigurationSubSettingsPanel
@@ -134,7 +134,7 @@ def render(self):
)
self.children = [
- ipw.HTML("
Accuracy and precision
"),
+ ipw.HTML("
Accuracy and precision
"),
ipw.HTML("""
The exchange-correlation functional and pseudopotential library is
@@ -158,7 +158,7 @@ def render(self):
self.family_help,
],
),
- ipw.HTML("
Pseudopotentials"),
+ ipw.HTML("
Pseudopotentials
"),
ipw.HTML("""
The pseudopotential for each kind of atom in the structure can be
@@ -172,28 +172,23 @@ def render(self):
"""), # noqa: RUF001
self.setter_widget,
- ipw.HTML("
Cutoffs"),
+ ipw.HTML("
Cutoffs
"),
ipw.HTML("""
- The cutoffs used for the calculation are the maximum of the
- default cutoffs from all pseudopotentials.
+ The
+
+ default cutoffs
+ used for the calculation are the maximum of the default cutoffs
+ from all pseudopotentials.
+
You can override them here.
"""),
- ipw.HBox(
- children=[
- self.ecutwfc,
- ipw.HTML("Ry"),
- ],
- layout=ipw.Layout(align_items="center"),
- ),
- ipw.HBox(
- children=[
- self.ecutrho,
- ipw.HTML("Ry"),
- ],
- layout=ipw.Layout(align_items="center"),
- ),
+ HBoxWithUnits(self.ecutwfc, "Ry"),
+ HBoxWithUnits(self.ecutrho, "Ry"),
self._status_message,
]
@@ -249,13 +244,11 @@ def _update_family_link(self):
pseudo_family_link = "http://www.pseudo-dojo.org/"
self.family_prompt.value = f"""
-
+
"""
def _show_loading(self):
diff --git a/src/aiidalab_qe/app/configuration/advanced/smearing/smearing.py b/src/aiidalab_qe/app/configuration/advanced/smearing/smearing.py
index 60ecf1613..474e4f198 100644
--- a/src/aiidalab_qe/app/configuration/advanced/smearing/smearing.py
+++ b/src/aiidalab_qe/app/configuration/advanced/smearing/smearing.py
@@ -1,5 +1,7 @@
import ipywidgets as ipw
+from aiidalab_qe.common.widgets import HBoxWithUnits
+
from ..subsettings import AdvancedConfigurationSubSettingsPanel
from .model import SmearingConfigurationSettingsModel
@@ -20,7 +22,7 @@ def render(self):
return
self.smearing = ipw.Dropdown(
- description="Smearing type:",
+ description="Type:",
style={"description_width": "150px"},
)
ipw.dlink(
@@ -34,7 +36,7 @@ def render(self):
self.degauss = ipw.FloatText(
step=0.005,
- description="Smearing width:",
+ description="Width:",
style={"description_width": "150px"},
)
ipw.link(
@@ -43,10 +45,15 @@ def render(self):
)
self.children = [
- ipw.HTML("
Smearing"),
+ ipw.HTML("
Smearing
"),
ipw.HTML("""
- The smearing type and width is set by the chosen
protocol.
+ Smear electronic state occupations near the Fermi level to
+ simulate finite temperature.
+
+ This helps to stabilize the SCF calculation and is important for metallic systems.
+
+ The smearing type and width are set by the chosen
protocol.
Changes are not advised unless you've mastered
"""),
self.smearing,
- ipw.HBox(
- children=[
- self.degauss,
- ipw.HTML("Ry"),
- ],
- ),
+ HBoxWithUnits(self.degauss, "Ry"),
]
self.rendered = True
diff --git a/src/aiidalab_qe/common/widgets.py b/src/aiidalab_qe/common/widgets.py
index 38537fbfd..394e23b68 100644
--- a/src/aiidalab_qe/common/widgets.py
+++ b/src/aiidalab_qe/common/widgets.py
@@ -169,7 +169,7 @@ def _observe_filename(self, change):
overflow:hidden;
text-overflow:ellipsis;
{width_style}">
- {icon} {change['new']}
+ {icon} {change["new"]}
"""
@@ -537,7 +537,7 @@ def _display_table(self, _=None):
symbol = chemichal_symbols[index]
if tag == 0:
tag = ""
- table_data.append([f"{index+ 1}", f"{symbol}", f"{tag}"])
+ table_data.append([f"{index + 1}", f"{symbol}", f"{tag}"])
# Create an HTML table
table_html = "
"
@@ -1328,3 +1328,18 @@ class TableWidget(anywidget.AnyWidget):
"""
data = traitlets.List().tag(sync=True)
selected_rows = traitlets.List().tag(sync=True)
+
+
+class HBoxWithUnits(ipw.HBox):
+ def __init__(self, widget: ipw.ValueWidget, units: str, **kwargs):
+ super().__init__(
+ children=[
+ widget,
+ ipw.HTML(units),
+ ],
+ layout=ipw.Layout(
+ align_items="center",
+ grid_gap="2px",
+ ),
+ **kwargs,
+ )