TB2J 0.9.5rc0__py3-none-any.whl → 0.9.7rc0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- TB2J/MAE.py +144 -27
- TB2J/MAEGreen.py +84 -0
- TB2J/anisotropy.py +672 -0
- TB2J/contour.py +8 -0
- TB2J/exchange.py +38 -172
- TB2J/exchangeCL2.py +11 -13
- TB2J/exchange_params.py +213 -0
- TB2J/green.py +62 -27
- TB2J/interfaces/__init__.py +12 -0
- TB2J/interfaces/abacus/__init__.py +4 -0
- TB2J/{abacus → interfaces/abacus}/abacus_api.py +3 -3
- TB2J/{abacus → interfaces/abacus}/abacus_wrapper.py +11 -8
- TB2J/{abacus → interfaces/abacus}/gen_exchange_abacus.py +5 -3
- TB2J/{abacus → interfaces/abacus}/orbital_api.py +4 -4
- TB2J/{abacus → interfaces/abacus}/stru_api.py +11 -11
- TB2J/{abacus → interfaces/abacus}/test_read_HRSR.py +0 -1
- TB2J/{abacus → interfaces/abacus}/test_read_stru.py +5 -3
- TB2J/interfaces/gpaw_interface.py +54 -0
- TB2J/interfaces/lawaf_interface.py +129 -0
- TB2J/interfaces/manager.py +23 -0
- TB2J/interfaces/siesta_interface.py +202 -0
- TB2J/interfaces/wannier90_interface.py +115 -0
- TB2J/io_exchange/io_exchange.py +21 -7
- TB2J/io_merge.py +2 -1
- TB2J/mathutils/fermi.py +11 -6
- TB2J/mathutils/lowdin.py +12 -2
- TB2J/mathutils/rotate_spin.py +222 -4
- TB2J/pauli.py +11 -3
- TB2J/symmetrize_J.py +120 -0
- TB2J/utils.py +82 -1
- {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/abacus2J.py +5 -4
- {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/siesta2J.py +21 -4
- TB2J-0.9.7rc0.data/scripts/wann2J.py +96 -0
- {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/METADATA +5 -3
- {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/RECORD +47 -46
- {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/WHEEL +1 -1
- TB2J-0.9.7rc0.dist-info/entry_points.txt +3 -0
- TB2J/abacus/MAE.py +0 -320
- TB2J/abacus/__init__.py +0 -1
- TB2J/abacus/occupations.py +0 -278
- TB2J/cut_cell.py +0 -82
- TB2J/io_exchange/io_pickle.py +0 -0
- TB2J/manager.py +0 -445
- TB2J/mathutils.py +0 -12
- TB2J/patch.py +0 -50
- TB2J/spinham/h_matrix.py +0 -68
- TB2J/spinham/obtain_J.py +0 -79
- TB2J/supercell.py +0 -532
- TB2J-0.9.5rc0.data/scripts/wann2J.py +0 -194
- TB2J/{abacus → interfaces/abacus}/test_density_matrix.py +1 -1
- {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_downfold.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_eigen.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_magnon.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_magnon_dos.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_merge.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_rotate.py +0 -0
- {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_rotateDM.py +0 -0
- {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/LICENSE +0 -0
- {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/top_level.txt +0 -0
TB2J/green.py
CHANGED
@@ -1,14 +1,19 @@
|
|
1
|
-
import
|
2
|
-
from collections import defaultdict
|
3
|
-
from ase.dft.kpoints import monkhorst_pack
|
4
|
-
from shutil import rmtree
|
1
|
+
import copy
|
5
2
|
import os
|
3
|
+
import pickle
|
4
|
+
import sys
|
6
5
|
import tempfile
|
6
|
+
from collections import defaultdict
|
7
|
+
from shutil import rmtree
|
8
|
+
|
9
|
+
import numpy as np
|
10
|
+
from HamiltonIO.model.occupations import Occupations
|
11
|
+
from HamiltonIO.model.occupations import myfermi as fermi
|
7
12
|
from pathos.multiprocessing import ProcessPool
|
8
|
-
|
9
|
-
import
|
10
|
-
|
11
|
-
from TB2J.mathutils.fermi import fermi
|
13
|
+
|
14
|
+
from TB2J.kpoints import monkhorst_pack
|
15
|
+
|
16
|
+
# from TB2J.mathutils.fermi import fermi
|
12
17
|
|
13
18
|
MAX_EXP_ARGUMENT = np.log(sys.float_info.max)
|
14
19
|
|
@@ -22,9 +27,16 @@ def eigen_to_G(evals, evecs, efermi, energy):
|
|
22
27
|
:returns: Green's function G,
|
23
28
|
:rtype: Matrix with same shape of the Hamiltonian (and eigenvector)
|
24
29
|
"""
|
25
|
-
return (
|
26
|
-
|
27
|
-
|
30
|
+
# return (
|
31
|
+
# np.einsum("ij, j-> ij", evecs, 1.0 / (-evals + (energy + efermi)))
|
32
|
+
# @ evecs.conj().T
|
33
|
+
# )
|
34
|
+
return np.einsum(
|
35
|
+
"ib, b, jb-> ij",
|
36
|
+
evecs,
|
37
|
+
1.0 / (-evals + (energy + efermi)),
|
38
|
+
evecs.conj(),
|
39
|
+
optimize=True,
|
28
40
|
)
|
29
41
|
|
30
42
|
|
@@ -46,8 +58,10 @@ class TBGreen:
|
|
46
58
|
def __init__(
|
47
59
|
self,
|
48
60
|
tbmodel,
|
49
|
-
kmesh, # [ikpt, 3]
|
50
|
-
efermi, # efermi
|
61
|
+
kmesh=None, # [ikpt, 3]
|
62
|
+
efermi=None, # efermi
|
63
|
+
gamma=False,
|
64
|
+
kpts=None,
|
51
65
|
k_sym=False,
|
52
66
|
use_cache=False,
|
53
67
|
cache_path=None,
|
@@ -67,12 +81,14 @@ class TBGreen:
|
|
67
81
|
self.cache_path = cache_path
|
68
82
|
if use_cache:
|
69
83
|
self._prepare_cache()
|
70
|
-
if
|
71
|
-
self.kpts =
|
84
|
+
if kpts is not None:
|
85
|
+
self.kpts = kpts
|
86
|
+
elif kmesh is not None:
|
87
|
+
self.kpts = monkhorst_pack(kmesh, gamma_center=gamma)
|
72
88
|
else:
|
73
89
|
self.kpts = tbmodel.get_kpts()
|
74
90
|
self.nkpts = len(self.kpts)
|
75
|
-
self.kweights = [1.0 / self.nkpts] * self.nkpts
|
91
|
+
self.kweights = np.array([1.0 / self.nkpts] * self.nkpts)
|
76
92
|
self.norb = tbmodel.norb
|
77
93
|
self.nbasis = tbmodel.nbasis
|
78
94
|
self.k_sym = k_sym
|
@@ -145,9 +161,19 @@ class TBGreen:
|
|
145
161
|
if not saveH:
|
146
162
|
self.H = None
|
147
163
|
|
148
|
-
|
149
|
-
|
150
|
-
|
164
|
+
# get efermi
|
165
|
+
if self.efermi is None:
|
166
|
+
print("Calculating Fermi energy from eigenvalues")
|
167
|
+
print(f"Number of electrons: {self.tbmodel.nel} ")
|
168
|
+
occ = Occupations(
|
169
|
+
nel=self.tbmodel.nel, width=0.1, wk=self.kweights, nspin=2
|
170
|
+
)
|
171
|
+
self.efermi = occ.efermi(copy.deepcopy(self.evals))
|
172
|
+
print(f"Fermi energy found: {self.efermi}")
|
173
|
+
|
174
|
+
# self.evals, self.evecs = self._reduce_eigens(
|
175
|
+
# self.evals, self.evecs, emin=self.efermi - 15.0, emax=self.efermi + 10.1
|
176
|
+
# )
|
151
177
|
if self._use_cache:
|
152
178
|
evecs = self.evecs
|
153
179
|
self.evecs_shape = self.evecs.shape
|
@@ -216,20 +242,22 @@ class TBGreen:
|
|
216
242
|
rho = np.zeros((self.nbasis, self.nbasis), dtype=complex)
|
217
243
|
if self.is_orthogonal:
|
218
244
|
for ik, _ in enumerate(self.kpts):
|
245
|
+
evecs_k = self.get_evecs(ik)
|
246
|
+
# chekc if any of the evecs element is nan
|
219
247
|
rho += (
|
220
|
-
(
|
221
|
-
@
|
248
|
+
(evecs_k * fermi(self.evals[ik], self.efermi, nspin=2))
|
249
|
+
@ evecs_k.T.conj()
|
222
250
|
* self.kweights[ik]
|
223
251
|
)
|
224
252
|
else:
|
225
253
|
for ik, _ in enumerate(self.kpts):
|
226
254
|
rho += (
|
227
|
-
(self.get_evecs(ik) * fermi(self.evals[ik], self.efermi))
|
255
|
+
(self.get_evecs(ik) * fermi(self.evals[ik], self.efermi, nspin=2))
|
228
256
|
@ self.get_evecs(ik).T.conj()
|
229
257
|
@ self.get_Sk(ik)
|
230
258
|
* self.kweights[ik]
|
231
259
|
)
|
232
|
-
|
260
|
+
# check if rho has nan values
|
233
261
|
return rho
|
234
262
|
|
235
263
|
def get_rho_R(self, Rlist):
|
@@ -238,7 +266,10 @@ class TBGreen:
|
|
238
266
|
for ik, kpt in enumerate(self.kpts):
|
239
267
|
evec = self.get_evecs(ik)
|
240
268
|
rhok = np.einsum(
|
241
|
-
"ib,b, bj-> ij",
|
269
|
+
"ib,b, bj-> ij",
|
270
|
+
evec,
|
271
|
+
fermi(self.evals[ik], self.efermi, nspin=2),
|
272
|
+
evec.conj().T,
|
242
273
|
)
|
243
274
|
for iR, R in enumerate(Rlist):
|
244
275
|
rho_R[iR] += rhok * np.exp(self.k2Rfactor * kpt @ R) * self.kweights[ik]
|
@@ -252,16 +283,20 @@ class TBGreen:
|
|
252
283
|
def get_density(self):
|
253
284
|
return np.real(np.diag(self.get_density_matrix()))
|
254
285
|
|
255
|
-
def get_Gk(self, ik, energy):
|
286
|
+
def get_Gk(self, ik, energy, evals=None, evecs=None):
|
256
287
|
"""Green's function G(k) for one energy
|
257
288
|
G(\epsilon)= (\epsilon I- H)^{-1}
|
258
289
|
:param ik: indices for kpoint
|
259
290
|
:returns: Gk
|
260
291
|
:rtype: a matrix of indices (nbasis, nbasis)
|
261
292
|
"""
|
293
|
+
if evals is None:
|
294
|
+
evals = self.get_evalue(ik)
|
295
|
+
if evecs is None:
|
296
|
+
evecs = self.get_evecs(ik)
|
262
297
|
Gk = eigen_to_G(
|
263
|
-
evals=
|
264
|
-
evecs=
|
298
|
+
evals=evals,
|
299
|
+
evecs=evecs,
|
265
300
|
efermi=self.efermi,
|
266
301
|
energy=energy,
|
267
302
|
)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from .abacus import gen_exchange_abacus
|
2
|
+
from .manager import Manager
|
3
|
+
from .siesta_interface import gen_exchange_siesta
|
4
|
+
from .wannier90_interface import WannierManager, gen_exchange
|
5
|
+
|
6
|
+
__all__ = [
|
7
|
+
"Manager",
|
8
|
+
"gen_exchange_siesta",
|
9
|
+
"WannierManager",
|
10
|
+
"gen_exchange",
|
11
|
+
"gen_exchange_abacus",
|
12
|
+
]
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
import numpy as np
|
3
|
-
from scipy import sparse
|
4
|
-
from scipy.sparse import csr_matrix
|
5
2
|
import re
|
6
3
|
import struct
|
7
4
|
|
5
|
+
import numpy as np
|
6
|
+
from scipy.sparse import csr_matrix
|
7
|
+
|
8
8
|
|
9
9
|
class XR_matrix:
|
10
10
|
def __init__(self, nspin, XR_fileName):
|
@@ -3,17 +3,20 @@
|
|
3
3
|
"""
|
4
4
|
The abacus wrapper
|
5
5
|
"""
|
6
|
-
|
6
|
+
|
7
7
|
import os
|
8
|
+
from pathlib import Path
|
9
|
+
|
8
10
|
import numpy as np
|
9
11
|
from scipy.linalg import eigh
|
10
|
-
|
12
|
+
|
11
13
|
from TB2J.mathutils.rotate_spin import rotate_Matrix_from_z_to_spherical
|
12
|
-
from TB2J.utils import symbol_number_list
|
13
14
|
from TB2J.myTB import AbstractTB
|
14
|
-
from TB2J.
|
15
|
-
|
16
|
-
from
|
15
|
+
from TB2J.utils import symbol_number_list
|
16
|
+
|
17
|
+
from .abacus_api import read_HR_SR
|
18
|
+
from .orbital_api import parse_abacus_orbital
|
19
|
+
from .stru_api import read_abacus
|
17
20
|
|
18
21
|
|
19
22
|
class AbacusWrapper(AbstractTB):
|
@@ -36,7 +39,6 @@ class AbacusWrapper(AbstractTB):
|
|
36
39
|
self.set_HR_soc(HR_soc=HR_soc, HR_nosoc=HR_nosoc, HR_full=HR)
|
37
40
|
self.soc_rotation_angle = 0.0
|
38
41
|
|
39
|
-
|
40
42
|
def set_HR_soc(self, HR_soc=None, HR_nosoc=None, HR_full=None):
|
41
43
|
self.split_soc = True
|
42
44
|
self.HR_soc = HR_soc
|
@@ -329,16 +331,17 @@ def test_abacus_wrapper_collinear():
|
|
329
331
|
# print(H.diagonal().real)
|
330
332
|
# print(model_up.get_HR0().diagonal().real)
|
331
333
|
print(parser.efermi)
|
334
|
+
print(atoms)
|
332
335
|
|
333
336
|
|
334
337
|
def test_abacus_wrapper_ncl():
|
335
338
|
outpath = "/Users/hexu/projects/TB2J_abacus/abacus-tb2j-master/abacus_example/case_Fe/2_soc/OUT.Fe"
|
336
|
-
|
337
339
|
parser = AbacusParser(outpath=outpath, spin=None, binary=False)
|
338
340
|
atoms = parser.read_atoms()
|
339
341
|
model = parser.get_models()
|
340
342
|
H, S, E, V = model.HSE_k([0, 0, 0])
|
341
343
|
print(parser.efermi)
|
344
|
+
print(atoms)
|
342
345
|
|
343
346
|
|
344
347
|
if __name__ == "__main__":
|
@@ -6,9 +6,11 @@ The main function to compute exchange interaction from abacus data
|
|
6
6
|
|
7
7
|
import os
|
8
8
|
from pathlib import Path
|
9
|
-
|
9
|
+
|
10
|
+
# from TB2J.abacus.abacus_wrapper import AbacusParser
|
10
11
|
from HamiltonIO.abacus import AbacusParser
|
11
|
-
|
12
|
+
|
13
|
+
from TB2J.exchange import ExchangeNCL
|
12
14
|
from TB2J.exchangeCL2 import ExchangeCL2
|
13
15
|
|
14
16
|
|
@@ -65,7 +67,7 @@ data directory: {outpath}
|
|
65
67
|
)
|
66
68
|
exchange.run(path=output_path)
|
67
69
|
print("\n")
|
68
|
-
print(f"All calculation
|
70
|
+
print(f"All calculation finished. The results are in {output_path} directory.")
|
69
71
|
else:
|
70
72
|
tbmodel = parser.get_models()
|
71
73
|
print("Starting to calculate exchange.")
|
@@ -3,11 +3,11 @@
|
|
3
3
|
"""
|
4
4
|
Parser for the abacus orbital file
|
5
5
|
"""
|
6
|
-
|
7
|
-
import numpy as np
|
6
|
+
|
8
7
|
from dataclasses import dataclass
|
9
|
-
from
|
10
|
-
|
8
|
+
from pathlib import Path
|
9
|
+
|
10
|
+
from TB2J.utils import symbol_number_list
|
11
11
|
|
12
12
|
|
13
13
|
@dataclass
|
@@ -8,17 +8,17 @@ Modified on Wed Aug 01 11:44:51 2022
|
|
8
8
|
@author: Ji Yu-yang
|
9
9
|
"""
|
10
10
|
|
11
|
-
import re
|
12
|
-
import warnings
|
13
|
-
import numpy as np
|
14
11
|
import os
|
12
|
+
import re
|
15
13
|
import shutil
|
14
|
+
import warnings
|
16
15
|
from pathlib import Path
|
17
16
|
|
17
|
+
import numpy as np
|
18
18
|
from ase import Atoms
|
19
|
-
from ase.units import Bohr, Hartree, GPa, mol, _me, Rydberg
|
20
|
-
from ase.utils import lazymethod, lazyproperty, reader, writer
|
21
19
|
from ase.calculators.singlepoint import SinglePointDFTCalculator, arrays_to_kpoints
|
20
|
+
from ase.units import Bohr, GPa, Hartree, Rydberg, _me, mol
|
21
|
+
from ase.utils import lazymethod, lazyproperty, reader, writer
|
22
22
|
|
23
23
|
_re_float = r"[-+]?\d+\.*\d*(?:[Ee][-+]\d+)?"
|
24
24
|
AU_to_MASS = mol * _me * 1e3
|
@@ -697,7 +697,7 @@ def read_abacus(fd, latname=None, verbose=False):
|
|
697
697
|
)
|
698
698
|
symbols = specie_lines[:, 0]
|
699
699
|
ntype = len(symbols)
|
700
|
-
mass = specie_lines[:, 1].astype(float)
|
700
|
+
# mass = specie_lines[:, 1].astype(float)
|
701
701
|
try:
|
702
702
|
atom_potential = dict(zip(symbols, specie_lines[:, 2].tolist()))
|
703
703
|
except IndexError:
|
@@ -789,7 +789,7 @@ def read_abacus(fd, latname=None, verbose=False):
|
|
789
789
|
|
790
790
|
# symbols, magnetism
|
791
791
|
sym = [symbol] * number
|
792
|
-
masses = [mass] * number
|
792
|
+
# masses = [mass] * number
|
793
793
|
atom_mags = [float(sub_block.group(1))] * number
|
794
794
|
for j in range(number):
|
795
795
|
atom_symbol.append(sym[j])
|
@@ -1121,7 +1121,7 @@ class AbacusOutHeaderChunk(AbacusOutChunk):
|
|
1121
1121
|
def str_to_kpoints(val_in):
|
1122
1122
|
lines = (
|
1123
1123
|
re.search(
|
1124
|
-
|
1124
|
+
r"KPOINTS\s*DIRECT_X\s*DIRECT_Y\s*DIRECT_Z\s*WEIGHT([\s\S]+?)DONE",
|
1125
1125
|
val_in,
|
1126
1126
|
)
|
1127
1127
|
.group(1)
|
@@ -1349,7 +1349,7 @@ class AbacusOutCalcChunk(AbacusOutChunk):
|
|
1349
1349
|
def _parse_ionic_block(self):
|
1350
1350
|
"""Parse the ionic block from the output file"""
|
1351
1351
|
step_pattern = re.compile(
|
1352
|
-
|
1352
|
+
r"(?:[NON]*SELF-|STEP OF|RELAX CELL)([\s\S]+?)charge density convergence is achieved"
|
1353
1353
|
)
|
1354
1354
|
|
1355
1355
|
return step_pattern.findall(self.contents)
|
@@ -1384,7 +1384,7 @@ class AbacusOutCalcChunk(AbacusOutChunk):
|
|
1384
1384
|
== "Lattice relaxation is converged!"
|
1385
1385
|
)
|
1386
1386
|
res = np.zeros((self.ion_steps), dtype=bool)
|
1387
|
-
if lat_arr[-1]
|
1387
|
+
if lat_arr[-1]:
|
1388
1388
|
res[-1] = 1
|
1389
1389
|
|
1390
1390
|
return res.astype(bool)
|
@@ -1805,7 +1805,7 @@ class AbacusOutCalcChunk(AbacusOutChunk):
|
|
1805
1805
|
@lazyproperty
|
1806
1806
|
def n_iter(self):
|
1807
1807
|
"""The number of SCF iterations needed to converge the SCF cycle for the chunk"""
|
1808
|
-
step_pattern = re.compile(
|
1808
|
+
step_pattern = re.compile(r"ELEC\s*=\s*[+]?(\d+)")
|
1809
1809
|
|
1810
1810
|
try:
|
1811
1811
|
return int(step_pattern.findall(self._ionic_block)[-1])
|
@@ -3,15 +3,17 @@
|
|
3
3
|
"""
|
4
4
|
@File : test_read_stru.py
|
5
5
|
@Time : 2024/02/02 09:52:23
|
6
|
-
@Author : Shen Zhen-Xiong
|
6
|
+
@Author : Shen Zhen-Xiong
|
7
7
|
@Email : shenzx@iai.ustc.edu.cn
|
8
8
|
"""
|
9
|
+
|
9
10
|
import os
|
10
|
-
|
11
|
+
|
12
|
+
from stru_api import read_abacus, read_input, write_abacus
|
11
13
|
|
12
14
|
|
13
15
|
def main():
|
14
|
-
stru_fe = read_abacus(os.path.join(os.getcwd(), "input/Fe.STRU"))
|
16
|
+
# stru_fe = read_abacus(os.path.join(os.getcwd(), "input/Fe.STRU"))
|
15
17
|
stru_sr2mn2o6 = read_abacus(
|
16
18
|
os.path.join(os.getcwd(), "input/Sr2Mn2O6.STRU"), verbose=True
|
17
19
|
)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
|
5
|
+
from TB2J.exchange import ExchangeNCL
|
6
|
+
from TB2J.gpaw_wrapper import GPAWWrapper
|
7
|
+
from TB2J.utils import auto_assign_basis_name
|
8
|
+
|
9
|
+
|
10
|
+
def gen_exchange_gpaw(
|
11
|
+
gpw_fname,
|
12
|
+
magnetic_elements=[],
|
13
|
+
kmesh=[3, 3, 3],
|
14
|
+
emin=-12.0,
|
15
|
+
emax=0.0,
|
16
|
+
nz=50,
|
17
|
+
exclude_orbs=[],
|
18
|
+
Rcut=None,
|
19
|
+
use_cache=False,
|
20
|
+
output_path="TB2J_results",
|
21
|
+
description="",
|
22
|
+
):
|
23
|
+
print("Reading from GPAW data and calculate electronic structure.")
|
24
|
+
model = GPAWWrapper(gpw_fname=gpw_fname)
|
25
|
+
efermi = model.calc.get_fermi_level()
|
26
|
+
print(f"Fermi Energy: {efermi}")
|
27
|
+
poses = np.vstack([model.positions, model.positions])
|
28
|
+
basis, _ = auto_assign_basis_name(
|
29
|
+
poses,
|
30
|
+
model.atoms,
|
31
|
+
write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
|
32
|
+
)
|
33
|
+
|
34
|
+
if model.calc.get_spin_polarized():
|
35
|
+
print("Starting to calculate exchange.")
|
36
|
+
exchange = ExchangeNCL(
|
37
|
+
tbmodels=model,
|
38
|
+
atoms=model.atoms,
|
39
|
+
efermi=efermi,
|
40
|
+
basis=basis,
|
41
|
+
magnetic_elements=magnetic_elements,
|
42
|
+
kmesh=kmesh,
|
43
|
+
emin=emin,
|
44
|
+
emax=emax,
|
45
|
+
nz=nz,
|
46
|
+
exclude_orbs=exclude_orbs,
|
47
|
+
Rcut=Rcut,
|
48
|
+
use_cache=use_cache,
|
49
|
+
output_path=output_path,
|
50
|
+
description=description,
|
51
|
+
)
|
52
|
+
exchange.run(path=output_path)
|
53
|
+
print("\n")
|
54
|
+
print(f"All calculation finished. The results are in {output_path} directory.")
|
@@ -0,0 +1,129 @@
|
|
1
|
+
import argparse
|
2
|
+
import os
|
3
|
+
import sys
|
4
|
+
|
5
|
+
from HamiltonIO.lawaf import LawafHamiltonian as Ham
|
6
|
+
|
7
|
+
from TB2J.exchange_params import add_exchange_args_to_parser, parser_argument_to_dict
|
8
|
+
from TB2J.versioninfo import print_license
|
9
|
+
|
10
|
+
from .manager import Manager
|
11
|
+
|
12
|
+
|
13
|
+
class LaWaFManager(Manager):
|
14
|
+
def __init__(
|
15
|
+
self,
|
16
|
+
path,
|
17
|
+
prefix_up,
|
18
|
+
prefix_dn,
|
19
|
+
prefix_SOC,
|
20
|
+
colinear=True,
|
21
|
+
wannier_type="LaWaF",
|
22
|
+
**kwargs,
|
23
|
+
):
|
24
|
+
# models and basis
|
25
|
+
if colinear:
|
26
|
+
tbmodels, basis, atoms = self.prepare_model_colinear(
|
27
|
+
path, prefix_up, prefix_dn
|
28
|
+
)
|
29
|
+
else:
|
30
|
+
tbmodels, basis, atoms = self.prepare_model_ncl(path, prefix_SOC)
|
31
|
+
|
32
|
+
description = self.description(path, prefix_up, prefix_dn, prefix_SOC, colinear)
|
33
|
+
kwargs["description"] = description
|
34
|
+
|
35
|
+
super().__init__(atoms, tbmodels, basis, colinear=colinear, **kwargs)
|
36
|
+
|
37
|
+
def prepare_model_colinear(self, path, prefix_up, prefix_dn):
|
38
|
+
print("Reading LawaF hamiltonian: spin up.")
|
39
|
+
tbmodel_up = Ham.load_pickle(os.path.join(path, f"{prefix_up}.pickle"))
|
40
|
+
print("Reading LaWaF hamiltonian: spin down.")
|
41
|
+
tbmodel_dn = Ham.load_pickle(os.path.join(path, f"{prefix_dn}.pickle"))
|
42
|
+
tbmodels = (tbmodel_up, tbmodel_dn)
|
43
|
+
basis = tbmodel_up.wann_names
|
44
|
+
atoms = tbmodel_up.atoms
|
45
|
+
return tbmodels, basis, atoms
|
46
|
+
|
47
|
+
def prepare_model_ncl(self, path, prefix_SOC):
|
48
|
+
print("Reading LaWaF hamiltonian: non-colinear spin.")
|
49
|
+
tbmodel = Ham.load_pickle(os.path.join(path, f"{prefix_SOC}.pickle"))
|
50
|
+
basis = tbmodel.wann_names
|
51
|
+
atoms = tbmodel.atoms
|
52
|
+
return tbmodel, basis, atoms
|
53
|
+
|
54
|
+
def description(self, path, prefix_up, prefix_dn, prefix_SOC, colinear=True):
|
55
|
+
if colinear:
|
56
|
+
description = f""" Input from collinear LaWaF data.
|
57
|
+
Tight binding data from {path}.
|
58
|
+
Prefix of wannier function files:{prefix_up} and {prefix_dn}.
|
59
|
+
Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
|
60
|
+
\n"""
|
61
|
+
|
62
|
+
else:
|
63
|
+
description = f""" Input from non-collinear LaWaF data.
|
64
|
+
Tight binding data from {path}.
|
65
|
+
Prefix of wannier function files:{prefix_SOC}.
|
66
|
+
Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
|
67
|
+
The DMI component parallel to the spin orientation, the Jani which has the component of that orientation should be disregarded
|
68
|
+
e.g. if the spins are along z, the xz, yz, zz, zx, zy components and the z component of DMI.
|
69
|
+
If you need these component, try to do three calculations with spin along x, y, z, or use structure with z rotated to x, y and z. And then use TB2J_merge.py to get the full set of parameters.\n"""
|
70
|
+
|
71
|
+
return description
|
72
|
+
|
73
|
+
|
74
|
+
def lawaf2J_cli():
|
75
|
+
print_license()
|
76
|
+
parser = argparse.ArgumentParser(
|
77
|
+
description="lawaf2J: Using magnetic force theorem to calculate exchange parameter J from wannier functions in LaWaF"
|
78
|
+
)
|
79
|
+
parser.add_argument(
|
80
|
+
"--path", help="path to the wannier files", default="./", type=str
|
81
|
+
)
|
82
|
+
|
83
|
+
parser.add_argument(
|
84
|
+
"--spinor",
|
85
|
+
help="if the calculation is spinor, default is False",
|
86
|
+
default=False,
|
87
|
+
action="store_true",
|
88
|
+
)
|
89
|
+
|
90
|
+
parser.add_argument(
|
91
|
+
"--prefix_spinor",
|
92
|
+
help="prefix to the spinor wannier files",
|
93
|
+
default="lawaf_spinor.pickle",
|
94
|
+
type=str,
|
95
|
+
)
|
96
|
+
parser.add_argument(
|
97
|
+
"--prefix_up",
|
98
|
+
help="prefix to the spin up wannier files",
|
99
|
+
default="lawaf_up",
|
100
|
+
type=str,
|
101
|
+
)
|
102
|
+
parser.add_argument(
|
103
|
+
"--prefix_down",
|
104
|
+
help="prefix to the spin down wannier files",
|
105
|
+
default="lawaf_dn",
|
106
|
+
type=str,
|
107
|
+
)
|
108
|
+
add_exchange_args_to_parser(parser)
|
109
|
+
|
110
|
+
args = parser.parse_args()
|
111
|
+
|
112
|
+
if args.efermi is None:
|
113
|
+
print("Please input fermi energy using --efermi ")
|
114
|
+
sys.exit()
|
115
|
+
if args.elements is None:
|
116
|
+
print("Please input the magnetic elements, e.g. --elements Fe Ni")
|
117
|
+
sys.exit()
|
118
|
+
|
119
|
+
kwargs = parser_argument_to_dict(args)
|
120
|
+
|
121
|
+
manager = LaWaFManager(
|
122
|
+
path=args.path,
|
123
|
+
prefix_up=args.prefix_up,
|
124
|
+
prefix_dn=args.prefix_down,
|
125
|
+
prefix_SOC=args.prefix_spinor,
|
126
|
+
colinear=not args.spinor,
|
127
|
+
**kwargs,
|
128
|
+
)
|
129
|
+
return manager
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from TB2J.exchange import ExchangeNCL
|
2
|
+
from TB2J.exchange_qspace import ExchangeCLQspace
|
3
|
+
from TB2J.exchangeCL2 import ExchangeCL2
|
4
|
+
|
5
|
+
|
6
|
+
class Manager:
|
7
|
+
def __init__(self, atoms, models, basis, colinear, **kwargs):
|
8
|
+
# computing exchange
|
9
|
+
print("Starting to calculate exchange.")
|
10
|
+
ExchangeClass = self.select_exchange(colinear)
|
11
|
+
exchange = ExchangeClass(tbmodels=models, atoms=atoms, basis=basis, **kwargs)
|
12
|
+
output_path = kwargs.get("output_path", "TB2J_results")
|
13
|
+
exchange.run(path=output_path)
|
14
|
+
print(f"All calculation finished. The results are in {output_path} directory.")
|
15
|
+
|
16
|
+
def select_exchange(self, colinear, qspace=False):
|
17
|
+
if colinear:
|
18
|
+
if qspace:
|
19
|
+
return ExchangeCLQspace
|
20
|
+
else:
|
21
|
+
return ExchangeCL2
|
22
|
+
else:
|
23
|
+
return ExchangeNCL
|