From 5984ed4d96ce2a54283e60fdb9923d0d7310a15b Mon Sep 17 00:00:00 2001 From: Edan Bainglass Date: Thu, 9 Jan 2025 08:49:47 +0000 Subject: [PATCH] Add help text --- .../advanced/magnetization/magnetization.py | 53 +++++++++++---- .../advanced/magnetization/model.py | 67 ++++++++++++++----- 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/src/aiidalab_qe/app/configuration/advanced/magnetization/magnetization.py b/src/aiidalab_qe/app/configuration/advanced/magnetization/magnetization.py index f9bd79904..0ae6fcc5c 100644 --- a/src/aiidalab_qe/app/configuration/advanced/magnetization/magnetization.py +++ b/src/aiidalab_qe/app/configuration/advanced/magnetization/magnetization.py @@ -44,13 +44,18 @@ def render(self): if self.rendered: return - self.description = ipw.HTML(""" -
- Magnetization: -
- Default magnetic moments correspond to theoretical values. -
- """) + self.header = ipw.HTML("Magnetization:") + + self.unit = ipw.HTML( + value="ยตB", + layout=ipw.Layout(margin="2px 2px 5px"), + ) + + self.magnetization_type_help = ipw.HTML() + ipw.dlink( + (self._model, "type_help"), + (self.magnetization_type_help, "value"), + ) self.magnetization_type = ipw.ToggleButtons( style={ @@ -80,11 +85,19 @@ def render(self): (self.tot_magnetization, "value"), ) + self.tot_magnetization_with_unit = ipw.HBox( + children=[ + self.tot_magnetization, + self.unit, + ], + layout=ipw.Layout(align_items="center"), + ) + self.kind_moment_widgets = ipw.VBox() self.container = ipw.VBox( children=[ - self.tot_magnetization, + self.tot_magnetization_with_unit, ] ) @@ -99,12 +112,14 @@ def _on_input_structure_change(self, _): def _on_electronic_type_change(self, _): self._switch_widgets() + self._model.update_type_help() def _on_spin_type_change(self, _): self.refresh(specific="spin") def _on_magnetization_type_change(self, _): self._toggle_widgets() + self._model.update_type_help() def _update(self, specific=""): if self.updated: @@ -152,7 +167,15 @@ def _build_kinds_widget(self): ], ) self.links.append(link) - children.append(kind_moment_widget) + children.append( + ipw.HBox( + children=[ + kind_moment_widget, + self.unit, + ], + layout=ipw.Layout(align_items="center"), + ) + ) self.kind_moment_widgets.children = children @@ -162,23 +185,29 @@ def _switch_widgets(self): if self._model.spin_type == "none": children = [] else: - children = [self.description] + children = [self.header] if self._model.electronic_type == "metal": children.extend( [ self.magnetization_type, + self.magnetization_type_help, self.container, ] ) else: - children.append(self.tot_magnetization) + children.extend( + [ + self.magnetization_type_help, + self.tot_magnetization_with_unit, + ], + ) self.children = children def _toggle_widgets(self): if self._model.spin_type == "none" or not self.rendered: return self.container.children = [ - self.tot_magnetization + self.tot_magnetization_with_unit if self._model.type == "tot_magnetization" else self.kind_moment_widgets ] diff --git a/src/aiidalab_qe/app/configuration/advanced/magnetization/model.py b/src/aiidalab_qe/app/configuration/advanced/magnetization/model.py index 41c84d301..9e60b88ef 100644 --- a/src/aiidalab_qe/app/configuration/advanced/magnetization/model.py +++ b/src/aiidalab_qe/app/configuration/advanced/magnetization/model.py @@ -30,11 +30,12 @@ class MagnetizationConfigurationSettingsModel( type_options = tl.List( trait=tl.List(tl.Unicode()), default_value=[ - ["Magnetic moments", "starting_magnetization"], + ["Initial magnetic moments", "starting_magnetization"], ["Total magnetization", "tot_magnetization"], ], ) type = tl.Unicode("starting_magnetization") + type_help = tl.Unicode("") total = tl.Float(0.0) moments = tl.Dict( key_trait=tl.Unicode(), # kind name @@ -42,34 +43,66 @@ class MagnetizationConfigurationSettingsModel( default_value={}, ) + _TYPE_HELP_TEMPLATE = """ +
+ {content} +
+ """ + def update(self, specific=""): # noqa: ARG002 if self.spin_type == "none" or not self.has_structure: self._defaults["moments"] = {} else: - try: - family = fetch_pseudo_family_by_label(self.family) - initial_guess = get_starting_magnetization(self.input_structure, family) - self._defaults["moments"] = { - kind.name: round( - initial_guess[kind.name] - * family.get_pseudo(kind.symbol).z_valence, - 3, - ) - for kind in self.input_structure.kinds - } - except NotExistent: - self._defaults["moments"] = { - kind_name: 0.0 - for kind_name in self.input_structure.get_kind_names() - } + self.update_type_help() + self._update_default_moments() with self.hold_trait_notifications(): self.moments = self._get_default_moments() + def update_type_help(self): + if self.electronic_type == "insulator" or self.type == "tot_magnetization": + self.type_help = self._TYPE_HELP_TEMPLATE.format( + content=""" + Constrain the desired total electronic magnetization (difference + between majority and minority spin charge). + """ + ) + else: + self.type_help = self._TYPE_HELP_TEMPLATE.format( + content=""" + If a nonzero ground-state magnetization is expected, you + must assign a nonzero value to at least one atomic + type (note that the app might already provide tentative initial + values to chemical elements that typically display magnetism). + To simulate an antiferromagnetic state, first, if you have not + done so already, please use the atom tag editor (Select + structure -> Edit structure -> Edit atom tags) to mark atoms of + the species of interest as distinct by assigning each a different + integer tag. Once tagged, assign each an initial magnetic moments + of opposite sign. + """ + ) + def reset(self): with self.hold_trait_notifications(): self.type = self.traits()["type"].default_value self.total = self.traits()["total"].default_value self.moments = self._get_default_moments() + def _update_default_moments(self): + try: + family = fetch_pseudo_family_by_label(self.family) + initial_guess = get_starting_magnetization(self.input_structure, family) + self._defaults["moments"] = { + kind.name: round( + initial_guess[kind.name] * family.get_pseudo(kind.symbol).z_valence, + 3, + ) + for kind in self.input_structure.kinds + } + except NotExistent: + self._defaults["moments"] = { + kind_name: 0.0 for kind_name in self.input_structure.get_kind_names() + } + def _get_default_moments(self): return deepcopy(self._defaults.get("moments", {}))