Skip to content

Commit 1182d1c

Browse files
Fix PP upload widget (#1348)
This PR addresses several issues with the pseudopotential upload widget. It implements a system of warnings w.r.t invalid uploads. If a valid, non-built-in pseudo is uploaded, the `functional`, `library`, and `family` are set to `None`. This required support in the plugin now provided in `aiida-quantumespresso v4.12.0`. Magnetization-to-moments conversion now uses `UpfData` nodes to extract Z values. Lastly, the summary is updated to show selected pseudopotentials and reflect custom states.
1 parent 20039d0 commit 1182d1c

14 files changed

Lines changed: 517 additions & 171 deletions

File tree

setup.cfg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ packages = find:
2626
install_requires =
2727
aiida-core~=2.5,<3
2828
Jinja2~=3.0
29-
aiida-quantumespresso~=4.10.0
29+
aiida-quantumespresso~=4.12.0
3030
aiidalab-widgets-base[optimade] @ git+https://github.com/aiidalab/aiidalab-widgets-base@master
3131
aiida-pseudo~=1.4
3232
filelock~=3.8
@@ -37,6 +37,7 @@ install_requires =
3737
shakenbreak~=3.3.1
3838
plotly~=5.24
3939
kaleido~=0.2.1
40+
upf_tools~=0.1.9
4041

4142
python_requires = >=3.9
4243

src/aiidalab_qe/app/configuration/advanced/magnetization/magnetization.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ def __init__(self, model: MagnetizationConfigurationSettingsModel, **kwargs):
3838
"spin_type",
3939
)
4040
self._model.observe(
41-
self._on_magnetization_type_change,
42-
"type",
41+
self._on_pseudos_dictionary_change,
42+
"dictionary",
4343
)
4444
self._model.observe(
45-
self._on_family_change,
46-
"family",
45+
self._on_magnetization_type_change,
46+
"type",
4747
)
4848

4949
def render(self):
@@ -123,13 +123,13 @@ def _on_electronic_type_change(self, _):
123123
def _on_spin_type_change(self, _):
124124
self.refresh(specific="spin")
125125

126+
def _on_pseudos_dictionary_change(self, _):
127+
self.refresh(specific="dictionary")
128+
126129
def _on_magnetization_type_change(self, _):
127130
self._toggle_widgets()
128131
self._model.update_type_help()
129132

130-
def _on_family_change(self, _):
131-
self._model._update_default_moments()
132-
133133
def _update(self, specific=""):
134134
if self.updated:
135135
return

src/aiidalab_qe/app/configuration/advanced/magnetization/model.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
from copy import deepcopy
22

33
import traitlets as tl
4-
from aiida_pseudo.groups.family import PseudoPotentialFamily
54

5+
from aiida import orm
66
from aiida_quantumespresso.workflows.protocols.utils import (
77
get_magnetization_parameters,
88
)
99
from aiidalab_qe.common.mixins import HasInputStructure
10-
from aiidalab_qe.utils import fetch_pseudo_family_by_label
1110

1211
from ..subsettings import AdvancedCalculationSubSettingsModel
1312

@@ -22,12 +21,16 @@ class MagnetizationConfigurationSettingsModel(
2221
"input_structure",
2322
"electronic_type",
2423
"spin_type",
25-
"pseudos.family",
24+
"pseudos.dictionary",
2625
]
2726

2827
electronic_type = tl.Unicode()
2928
spin_type = tl.Unicode()
30-
family = tl.Unicode()
29+
dictionary = tl.Dict(
30+
key_trait=tl.Unicode(), # kind name
31+
value_trait=tl.Unicode(), # pseudopotential node uuid
32+
default_value={},
33+
)
3134

3235
type_options = tl.List(
3336
trait=tl.List(tl.Unicode()),
@@ -103,21 +106,25 @@ def _update_default_moments(self):
103106
# and should be carefully checked!
104107
return
105108

106-
family = fetch_pseudo_family_by_label(self.family)
107109
self._defaults["moments"] = {
108-
kind.name: self._get_moment(kind.symbol, family)
109-
for kind in self.input_structure.kinds
110+
kind.name: self._get_moment(kind) for kind in self.input_structure.kinds
110111
}
111112

112-
def _get_moment(self, symbol: str, family: PseudoPotentialFamily) -> float:
113+
def _get_moment(self, kind) -> float:
113114
"""Convert the default magnetization to an initial magnetic moment."""
114-
moment = self._DEFAULT_MOMENTS.get(symbol, {}).get("magmom", 0)
115+
moment = self._DEFAULT_MOMENTS.get(kind.symbol, {}).get("magmom", 0)
115116
if moment != 0:
116117
return moment
117118

119+
try:
120+
pseudo_uuid = self.dictionary.get(kind.name)
121+
z_valence = orm.load_node(pseudo_uuid).z_valence
122+
except Exception:
123+
z_valence = 0
124+
118125
# If no default moment is defined, or if it's 0, use 0.1 as default magnetization
119126
# and convert it to moments.
120-
return round(0.1 * family.get_pseudo(symbol).z_valence, 3)
127+
return round(0.1 * z_valence, 3)
121128

122129
def _get_default_moments(self):
123130
return deepcopy(self._defaults.get("moments", {}))

src/aiidalab_qe/app/configuration/advanced/model.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,18 @@ def get_model_state(self):
183183

184184
def set_model_state(self, parameters):
185185
pseudos: PseudosConfigurationSettingsModel = self.get_model("pseudos") # type: ignore
186-
if "pseudo_family" in parameters:
187-
pseudo_family = PseudoFamily.from_string(parameters["pseudo_family"])
186+
if pseudo_family_string := parameters.get("pseudo_family"):
187+
pseudo_family = PseudoFamily.from_string(pseudo_family_string)
188188
library = pseudo_family.library
189189
accuracy = pseudo_family.accuracy
190190
pseudos.library = f"{library} {accuracy}"
191191
pseudos.functional = pseudo_family.functional
192-
pseudos.family = parameters["pseudo_family"]
192+
pseudos.family = pseudo_family_string
193+
else:
194+
pseudos.library = None
195+
pseudos.functional = None
196+
pseudos.family = None
197+
pseudos.show_upload_warning = True
193198

194199
if "pseudos" in parameters["pw"]:
195200
pseudos.dictionary = parameters["pw"]["pseudos"]

src/aiidalab_qe/app/configuration/advanced/pseudos/model.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,13 @@ class PseudosConfigurationSettingsModel(
5050
DEFAULT["advanced"]["pseudo_family"]["functional"],
5151
DEFAULT["advanced"]["pseudo_family"]["accuracy"],
5252
]
53-
)
53+
),
54+
allow_none=True,
55+
)
56+
functional = tl.Unicode(
57+
DEFAULT["advanced"]["pseudo_family"]["functional"],
58+
allow_none=True,
5459
)
55-
functional = tl.Unicode(DEFAULT["advanced"]["pseudo_family"]["functional"])
5660
functional_options = tl.List(
5761
trait=tl.Unicode(),
5862
default_value=[
@@ -66,7 +70,8 @@ class PseudosConfigurationSettingsModel(
6670
DEFAULT["advanced"]["pseudo_family"]["library"],
6771
DEFAULT["advanced"]["pseudo_family"]["accuracy"],
6872
]
69-
)
73+
),
74+
allow_none=True,
7075
)
7176
library_options = tl.List(
7277
trait=tl.Unicode(),
@@ -83,7 +88,8 @@ class PseudosConfigurationSettingsModel(
8388
)
8489
ecutwfc = tl.Float()
8590
ecutrho = tl.Float()
86-
status_message = tl.Unicode("")
91+
status_message = tl.Unicode("", allow_none=True)
92+
show_upload_warning = tl.Bool(False)
8793

8894
PSEUDO_HELP_SOC = """
8995
<div class="pseudo-text">
@@ -111,8 +117,6 @@ class PseudosConfigurationSettingsModel(
111117

112118
family_help_message = tl.Unicode(PSEUDO_HELP_WO_SOC)
113119

114-
pseudo_filename_reset_trigger = tl.Int(0)
115-
116120
def update(self, specific=""): # noqa: ARG002
117121
with self.hold_trait_notifications():
118122
if not self.has_structure:
@@ -276,7 +280,6 @@ def reset(self):
276280
self.family = self._get_default("family")
277281
self.family_help_message = self._get_default("family_help_message")
278282
self.status_message = self._get_default("status_message")
279-
self.pseudo_filename_reset_trigger += 1
280283

281284
def _get_default(self, trait):
282285
if trait == "dictionary":

0 commit comments

Comments
 (0)