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", {}))