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("

Convergence

"), + ipw.HTML(""" +
+ Control the convergence criteria of the self-consistent field (SCF) + geometry optimization cycles. +
+ """), + ipw.HTML("

Thresholds

"), + 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("Maximum cycle steps"), + ipw.HTML("

Maximum cycle steps

"), + 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("K-points"), + ipw.HTML("

K-points

"), 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""" - +

+ + Pseudopotential family + +

""" 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, + )