Skip to content

Commit 95dae3f

Browse files
mbercxedan-bainglass
authored andcommitted
👌 get_magnetization: Replace pseudo_family input by z_valences
The current `get_magnetization` utility function has an input `pseudo_family` that expects an `aiida-pseudo` `PseudoPotentialFamily` to extract the number of valence electrons in the pseudo potential. However, when a user wants to use custom pseudo potentials e.g. through the `overrides` of the `get_builder_from_protocol()` method, it would still be beneficial to use the `get_magnetization` function to determine the correct Quantum ESPRESSO inputs. Here we make the function more generic by replacing the `pseudo_family` input by `z_valences`, a simple dictionary that maps each kind name to the corresponding number of valence electrons in the pseudo potential. Co-authored-by: Edan Bainglass <edan.bainglass@gmail.com>
1 parent e8a39ad commit 95dae3f

3 files changed

Lines changed: 36 additions & 22 deletions

File tree

‎src/aiida_quantumespresso/workflows/protocols/utils.py‎

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def get_magnetization_parameters() -> dict:
119119

120120
def get_magnetization(
121121
structure: StructureData,
122-
pseudo_family: PseudoPotentialFamily,
122+
z_valences: dict,
123123
initial_magnetic_moments: Optional[dict] = None,
124124
spin_type: SpinType = SpinType.COLLINEAR
125125
) -> dict:
@@ -134,7 +134,8 @@ def get_magnetization(
134134
In case the `spin_type` is set to `SpinType.COLLINEAR`, the values for `angle1` and `angle2` will be set to `None`.
135135
136136
:param structure: the structure.
137-
:param pseudo_family: pseudopotential family.
137+
:param z_valences: dictionary mapping each kind in the structure to the number of valence electrons in the pseudo
138+
potential.
138139
:param initial_magnetic_moments: dictionary mapping each kind in the structure to its magnetic moment.
139140
:param spin_type: the `SpinType` of the calculation.
140141
:returns: dictionary of the magnetization.
@@ -144,6 +145,8 @@ def get_magnetization(
144145
'angle1': {} if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT] else None,
145146
'angle2': {} if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT] else None,
146147
}
148+
if sorted(z_valences.keys()) != sorted(structure.get_kind_names()):
149+
raise ValueError(f'`z_valences` needs one value for each of the {len(structure.kinds)} kinds.')
147150

148151
if initial_magnetic_moments is not None:
149152

@@ -157,8 +160,8 @@ def get_magnetization(
157160
magmom = initial_magnetic_moments[kind.name]
158161

159162
if isinstance(magmom, (int, float)):
160-
magnetization['starting_magnetization'][
161-
kind.name] = magmom / pseudo_family.get_pseudo(element=kind.symbol).z_valence
163+
scaled_magmom = magmom / z_valences[kind.name]
164+
magnetization['starting_magnetization'][kind.name] = scaled_magmom
162165

163166
if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
164167
magnetization['angle1'][kind.name] = 0.0
@@ -172,8 +175,8 @@ def get_magnetization(
172175
f'moment of kind `{kind.name}`.'
173176
)
174177

175-
magnetization['starting_magnetization'][
176-
kind.name] = magmom[0] / pseudo_family.get_pseudo(element=kind.symbol).z_valence
178+
scaled_magmom = magmom[0] / z_valences[kind.name]
179+
magnetization['starting_magnetization'][kind.name] = scaled_magmom
177180
magnetization['angle1'][kind.name] = magmom[1]
178181
magnetization['angle2'][kind.name] = magmom[2]
179182
else:
@@ -197,8 +200,8 @@ def get_magnetization(
197200

198201
magmom = kind.get_magmom_coord()
199202

200-
magnetization['starting_magnetization'][
201-
kind.name] = magmom[0] / pseudo_family.get_pseudo(element=kind.symbol).z_valence
203+
scaled_magmom = magmom[0] / z_valences[kind.name]
204+
magnetization['starting_magnetization'][kind.name] = scaled_magmom
202205

203206
if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
204207
magnetization['angle1'][kind.name] = magmom[1]
@@ -216,7 +219,7 @@ def get_magnetization(
216219

217220
magnetization['starting_magnetization'][kind.name] = (
218221
magnetic_parameters['default_magnetization'] if magnetic_moment == 0 else magnetic_moment /
219-
pseudo_family.get_pseudo(element=kind.symbol).z_valence
222+
z_valences[kind.name]
220223
)
221224
if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
222225
magnetization['angle1'][kind.name] = 0.0

‎src/aiida_quantumespresso/workflows/pw/base.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def get_builder_from_protocol(
191191

192192
magnetization = get_magnetization(
193193
structure=structure,
194-
pseudo_family=pseudo_family,
194+
z_valences={kind.name: pseudo_family.get_pseudo(element=kind.symbol).z_valence for kind in structure.kinds},
195195
initial_magnetic_moments=initial_magnetic_moments,
196196
spin_type=spin_type
197197
)

‎tests/workflows/protocols/test_utils.py‎

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ def test_recursive_merge():
116116
),
117117
)
118118
def test_get_magnetization(
119-
pseudo_family,
120119
generate_structure,
121120
structure_id,
122121
initial_magnetic_moments,
@@ -125,31 +124,43 @@ def test_get_magnetization(
125124
):
126125
"""Test the `get_magnetization` function."""
127126
from aiida_quantumespresso.workflows.protocols.utils import get_magnetization
127+
structure = generate_structure(structure_id)
128+
z_valences = {kind: 4.0 for kind in structure.get_kind_names()}
128129

129-
magnetization = get_magnetization(
130-
generate_structure(structure_id), pseudo_family, initial_magnetic_moments, spin_type
131-
)
130+
magnetization = get_magnetization(structure, z_valences, initial_magnetic_moments, spin_type)
132131

133132
assert magnetization == expected_magnetization
134133

135134

136135
@pytest.mark.parametrize(
137-
'structure_id,initial_magnetic_moments,spin_type,expected_error,error_message',
136+
'structure_id,z_valences,initial_magnetic_moments,spin_type,expected_error,error_message',
138137
(
139-
('silicon', {}, SpinType.COLLINEAR, ValueError, '`initial_magnetic_moments` needs one value for each of'),
138+
('silicon', {}, {
139+
'Si': 1.0
140+
}, SpinType.COLLINEAR, ValueError, '`z_valences` needs one value for each of'),
141+
(
142+
'silicon', {
143+
'Si': 4.0
144+
}, {}, SpinType.COLLINEAR, ValueError, '`initial_magnetic_moments` needs one value for each of'
145+
),
140146
('silicon', {
147+
'Si': 4.0
148+
}, {
141149
'Si': (1, 2, 3)
142150
}, SpinType.COLLINEAR, TypeError, 'Spin type is set to '),
143-
('silicon', {
144-
'Si': 'zero'
145-
}, SpinType.COLLINEAR, TypeError, 'Unrecognised type for magnetic moment'),
151+
(
152+
'silicon', {
153+
'Si': 4.0
154+
}, {
155+
'Si': 'zero'
156+
}, SpinType.COLLINEAR, TypeError, 'Unrecognised type for magnetic moment'
157+
),
146158
),
147159
)
148160
def test_get_magnetization_failure(
149-
pseudo_family, generate_structure, structure_id, initial_magnetic_moments, spin_type, expected_error, error_message
161+
generate_structure, structure_id, z_valences, initial_magnetic_moments, spin_type, expected_error, error_message
150162
):
151163
"""Test the `get_magnetization` function."""
152164
from aiida_quantumespresso.workflows.protocols.utils import get_magnetization
153-
154165
with pytest.raises(expected_error, match=error_message):
155-
get_magnetization(generate_structure(structure_id), pseudo_family, initial_magnetic_moments, spin_type)
166+
get_magnetization(generate_structure(structure_id), z_valences, initial_magnetic_moments, spin_type)

0 commit comments

Comments
 (0)