Skip to content

Commit e8a39ad

Browse files
mbercxMinotakm
authored andcommitted
✨ Protocols: Add support for spin-orbit
Add support for spin-orbit calculations to the `get_builder_from_protocol()` method of the `PwBaseWorkChain`. Typical spin-orbit calculations use non-collinear settings, with the addition of of setting `SYSTEM.lspinorb` to `True`. Additionally, the default pseudo-potential family is set to `PseudoDojo/0.4/PBEsol/FR/standard/upf`. The `get_magnetization` function in the protocol utility module is also adapted to cover `SpinType.SPIN_ORBIT`. Here, the logic of the function should be exactly the same as for `SpinType.COLLINEAR`. Co-authored-by: Michail Minotakis <mminotakis@gmail.com>
1 parent 78bdb5f commit e8a39ad

7 files changed

Lines changed: 52 additions & 26 deletions

File tree

src/aiida_quantumespresso/workflows/protocols/utils.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ def get_magnetization(
141141
"""
142142
magnetization = {
143143
'starting_magnetization': {},
144-
'angle1': {} if spin_type == SpinType.NON_COLLINEAR else None,
145-
'angle2': {} if spin_type == SpinType.NON_COLLINEAR else None,
144+
'angle1': {} if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT] else None,
145+
'angle2': {} if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT] else None,
146146
}
147147

148148
if initial_magnetic_moments is not None:
@@ -160,13 +160,13 @@ def get_magnetization(
160160
magnetization['starting_magnetization'][
161161
kind.name] = magmom / pseudo_family.get_pseudo(element=kind.symbol).z_valence
162162

163-
if spin_type == SpinType.NON_COLLINEAR:
163+
if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
164164
magnetization['angle1'][kind.name] = 0.0
165165
magnetization['angle2'][kind.name] = 0.0
166166

167167
elif isinstance(magmom, (list, tuple)):
168168

169-
if spin_type != SpinType.NON_COLLINEAR:
169+
if spin_type not in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
170170
raise TypeError(
171171
f'Spin type is set to `{spin_type}` but a `{type(magmom)}` is provided for the magnetic '
172172
f'moment of kind `{kind.name}`.'
@@ -200,7 +200,7 @@ def get_magnetization(
200200
magnetization['starting_magnetization'][
201201
kind.name] = magmom[0] / pseudo_family.get_pseudo(element=kind.symbol).z_valence
202202

203-
if spin_type == SpinType.NON_COLLINEAR:
203+
if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
204204
magnetization['angle1'][kind.name] = magmom[1]
205205
magnetization['angle2'][kind.name] = magmom[2]
206206

@@ -218,7 +218,7 @@ def get_magnetization(
218218
magnetic_parameters['default_magnetization'] if magnetic_moment == 0 else magnetic_moment /
219219
pseudo_family.get_pseudo(element=kind.symbol).z_valence
220220
)
221-
if spin_type == SpinType.NON_COLLINEAR:
221+
if spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
222222
magnetization['angle1'][kind.name] = 0.0
223223
magnetization['angle2'][kind.name] = 0.0
224224

src/aiida_quantumespresso/workflows/pw/base.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,17 +143,17 @@ def get_builder_from_protocol(
143143
if electronic_type not in [ElectronicType.METAL, ElectronicType.INSULATOR]:
144144
raise NotImplementedError(f'electronic type `{electronic_type}` is not supported.')
145145

146-
if spin_type not in [SpinType.NONE, SpinType.COLLINEAR, SpinType.NON_COLLINEAR]:
147-
raise NotImplementedError(f'spin type `{spin_type}` is not supported.')
148-
149-
if initial_magnetic_moments is not None and spin_type not in [SpinType.COLLINEAR, SpinType.NON_COLLINEAR]:
146+
if initial_magnetic_moments is not None and spin_type == SpinType.NONE:
150147
raise ValueError(f'`initial_magnetic_moments` is specified but spin type `{spin_type}` is incompatible.')
151148

152149
inputs = cls.get_protocol_inputs(protocol, overrides)
153150

154151
meta_parameters = inputs.pop('meta_parameters')
155152
pseudo_family = inputs.pop('pseudo_family')
156153

154+
if spin_type is SpinType.SPIN_ORBIT and overrides is not None and 'pseudo_family' not in overrides:
155+
pseudo_family = 'PseudoDojo/0.4/PBEsol/FR/standard/upf'
156+
157157
natoms = len(structure.sites)
158158

159159
try:
@@ -199,12 +199,14 @@ def get_builder_from_protocol(
199199
parameters['SYSTEM']['starting_magnetization'] = magnetization['starting_magnetization']
200200
parameters['SYSTEM']['nspin'] = 2
201201

202-
if spin_type is SpinType.NON_COLLINEAR:
202+
if spin_type in [SpinType.SPIN_ORBIT, SpinType.NON_COLLINEAR]:
203203
parameters['SYSTEM']['starting_magnetization'] = magnetization['starting_magnetization']
204204
parameters['SYSTEM']['angle1'] = magnetization['angle1']
205205
parameters['SYSTEM']['angle2'] = magnetization['angle2']
206206
parameters['SYSTEM']['noncolin'] = True
207207
parameters['SYSTEM']['nspin'] = 4
208+
if spin_type == SpinType.SPIN_ORBIT:
209+
parameters['SYSTEM']['lspinorb'] = True
208210

209211
# If overrides are provided, they are considered absolute
210212
if overrides:

tests/workflows/protocols/pw/test_bands.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,21 @@ def test_spin_type(fixture_code, generate_structure):
5252
code = fixture_code('quantumespresso.pw')
5353
structure = generate_structure()
5454

55-
with pytest.raises(NotImplementedError):
56-
for spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
57-
PwBandsWorkChain.get_builder_from_protocol(code, structure, spin_type=spin_type)
58-
5955
builder = PwBandsWorkChain.get_builder_from_protocol(code, structure, spin_type=SpinType.COLLINEAR)
6056

6157
for namespace in [builder.relax['base'], builder.scf, builder.bands]:
6258
parameters = namespace['pw']['parameters'].get_dict()
6359
assert parameters['SYSTEM']['nspin'] == 2
6460
assert parameters['SYSTEM']['starting_magnetization'] == {'Si': 0.1}
6561

62+
builder = PwBandsWorkChain.get_builder_from_protocol(code, structure, spin_type=SpinType.SPIN_ORBIT)
63+
64+
for namespace in [builder.relax['base'], builder.scf, builder.bands]:
65+
parameters = namespace['pw']['parameters'].get_dict() # pylint: disable=no-member
66+
assert parameters['SYSTEM']['noncolin'] is True
67+
assert parameters['SYSTEM']['lspinorb'] is True
68+
assert parameters['SYSTEM']['starting_magnetization'] == {'Si': 0.1}
69+
6670

6771
def test_relax_type(fixture_code, generate_structure):
6872
"""Test ``PwBandsWorkChain.get_builder_from_protocol`` setting the ``relax_type`` input."""

tests/workflows/protocols/pw/test_base.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,19 @@ def test_spin_type(fixture_code, generate_structure):
5757
assert 'starting_magnetization' not in builder.pw.parameters['SYSTEM'] # pylint: disable=no-member
5858
assert 'nspin' not in builder.pw.parameters['SYSTEM'] # pylint: disable=no-member
5959

60-
with pytest.raises(NotImplementedError):
61-
for spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
62-
PwBaseWorkChain.get_builder_from_protocol(code, structure, spin_type=spin_type)
63-
6460
builder = PwBaseWorkChain.get_builder_from_protocol(code, structure, spin_type=SpinType.COLLINEAR)
6561
parameters = builder.pw.parameters.get_dict() # pylint: disable=no-member
6662

6763
assert parameters['SYSTEM']['nspin'] == 2
6864
assert parameters['SYSTEM']['starting_magnetization'] == {'Si': 0.1}
6965

66+
builder = PwBaseWorkChain.get_builder_from_protocol(code, structure, spin_type=SpinType.SPIN_ORBIT)
67+
parameters = builder.pw.parameters.get_dict() # pylint: disable=no-member
68+
69+
assert parameters['SYSTEM']['noncolin'] is True
70+
assert parameters['SYSTEM']['lspinorb'] is True
71+
assert parameters['SYSTEM']['starting_magnetization'] == {'Si': 0.1}
72+
7073

7174
@pytest.mark.parametrize(
7275
'struc_name,assume_isolated', (

tests/workflows/protocols/pw/test_relax.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,21 @@ def test_spin_type(fixture_code, generate_structure):
5252
code = fixture_code('quantumespresso.pw')
5353
structure = generate_structure()
5454

55-
with pytest.raises(NotImplementedError):
56-
for spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
57-
PwRelaxWorkChain.get_builder_from_protocol(code, structure, spin_type=spin_type)
58-
5955
builder = PwRelaxWorkChain.get_builder_from_protocol(code, structure, spin_type=SpinType.COLLINEAR)
6056

6157
for namespace in [builder.base, builder.base_final_scf]:
6258
parameters = namespace['pw']['parameters'].get_dict()
6359
assert parameters['SYSTEM']['nspin'] == 2
6460
assert parameters['SYSTEM']['starting_magnetization'] == {'Si': 0.1}
6561

62+
builder = PwRelaxWorkChain.get_builder_from_protocol(code, structure, spin_type=SpinType.SPIN_ORBIT)
63+
64+
for namespace in [builder.base, builder.base_final_scf]:
65+
parameters = namespace['pw']['parameters'].get_dict()
66+
assert parameters['SYSTEM']['noncolin'] is True
67+
assert parameters['SYSTEM']['lspinorb'] is True
68+
assert parameters['SYSTEM']['starting_magnetization'] == {'Si': 0.1}
69+
6670

6771
def test_relax_type(fixture_code, generate_structure):
6872
"""Test ``PwRelaxWorkChain.get_builder_from_protocol`` with ``spin_type`` keyword."""

tests/workflows/protocols/test_pdos.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ def test_electronic_type(get_pdos_generator_inputs):
6060

6161
def test_spin_type(get_pdos_generator_inputs):
6262
"""Test ``PdosWorkChain.get_builder_from_protocol`` with ``spin_type`` keyword."""
63-
with pytest.raises(NotImplementedError):
64-
for spin_type in [SpinType.NON_COLLINEAR, SpinType.SPIN_ORBIT]:
65-
builder = PdosWorkChain.get_builder_from_protocol(**get_pdos_generator_inputs, spin_type=spin_type)
6663
builder = PdosWorkChain.get_builder_from_protocol(**get_pdos_generator_inputs, spin_type=SpinType.COLLINEAR)
6764
for namespace in [builder.scf, builder.nscf]:
6865
parameters = namespace['pw']['parameters'].get_dict()

tests/workflows/protocols/test_utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,22 @@ def test_recursive_merge():
6565
}
6666
},
6767
),
68+
(
69+
'cobalt-prim',
70+
None,
71+
SpinType.SPIN_ORBIT,
72+
{
73+
'starting_magnetization': {
74+
'Co': 1.25
75+
},
76+
'angle1': {
77+
'Co': 0
78+
},
79+
'angle2': {
80+
'Co': 0
81+
}
82+
},
83+
),
6884
(
6985
'cobalt-prim',
7086
{

0 commit comments

Comments
 (0)