TB2J 0.8.2.8__py3-none-any.whl → 0.9.0.1__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/__init__.py +1 -1
- TB2J/abacus/abacus_wrapper.py +1 -2
- TB2J/exchange.py +3 -3
- TB2J/io_merge.py +125 -376
- TB2J/myTB.py +0 -2
- TB2J/rotate_atoms.py +22 -20
- TB2J/rotate_siestaDM.py +36 -0
- TB2J/sisl_wrapper.py +0 -1
- {TB2J-0.8.2.8.data → TB2J-0.9.0.1.data}/scripts/TB2J_merge.py +9 -2
- {TB2J-0.8.2.8.data → TB2J-0.9.0.1.data}/scripts/TB2J_rotate.py +6 -1
- TB2J-0.9.0.1.data/scripts/TB2J_rotateDM.py +21 -0
- {TB2J-0.8.2.8.dist-info → TB2J-0.9.0.1.dist-info}/METADATA +6 -9
- {TB2J-0.8.2.8.dist-info → TB2J-0.9.0.1.dist-info}/RECORD +23 -26
- {TB2J-0.8.2.8.dist-info → TB2J-0.9.0.1.dist-info}/WHEEL +1 -1
- TB2J/cut_cell.py +0 -82
- TB2J/io_exchange/io_pickle.py +0 -0
- TB2J/spinham/h_matrix.py +0 -68
- TB2J/spinham/obtain_J.py +0 -79
- TB2J/supercell.py +0 -532
- {TB2J-0.8.2.8.data → TB2J-0.9.0.1.data}/scripts/TB2J_downfold.py +0 -0
- {TB2J-0.8.2.8.data → TB2J-0.9.0.1.data}/scripts/TB2J_eigen.py +0 -0
- {TB2J-0.8.2.8.data → TB2J-0.9.0.1.data}/scripts/TB2J_magnon.py +0 -0
- {TB2J-0.8.2.8.data → TB2J-0.9.0.1.data}/scripts/TB2J_magnon_dos.py +0 -0
- {TB2J-0.8.2.8.data → TB2J-0.9.0.1.data}/scripts/abacus2J.py +0 -0
- {TB2J-0.8.2.8.data → TB2J-0.9.0.1.data}/scripts/siesta2J.py +0 -0
- {TB2J-0.8.2.8.data → TB2J-0.9.0.1.data}/scripts/wann2J.py +0 -0
- {TB2J-0.8.2.8.dist-info → TB2J-0.9.0.1.dist-info}/LICENSE +0 -0
- {TB2J-0.8.2.8.dist-info → TB2J-0.9.0.1.dist-info}/top_level.txt +0 -0
TB2J/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.
|
1
|
+
__version__ = "0.9.0.1"
|
TB2J/abacus/abacus_wrapper.py
CHANGED
@@ -18,8 +18,7 @@ class AbacusWrapper(AbstractTB):
|
|
18
18
|
def __init__(self, HR, SR, Rlist, nbasis, nspin=1):
|
19
19
|
self.R2kfactor = -2j * np.pi
|
20
20
|
self.is_orthogonal = False
|
21
|
-
self.
|
22
|
-
self._name = "Abacus"
|
21
|
+
self._name = "ABACUS"
|
23
22
|
self.HR = HR
|
24
23
|
self.SR = SR
|
25
24
|
self.Rlist = Rlist
|
TB2J/exchange.py
CHANGED
@@ -240,7 +240,7 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
|
|
240
240
|
self.mmats = {}
|
241
241
|
self.orbital_names = {}
|
242
242
|
self.norb_reduced = {}
|
243
|
-
if self.backend_name == "SIESTA":
|
243
|
+
if self.backend_name.upper() == "SIESTA":
|
244
244
|
syms = self.atoms.get_chemical_symbols()
|
245
245
|
for iatom, orbs in self.labels.items():
|
246
246
|
if (self.include_orbs is not None) and syms[iatom] in self.include_orbs:
|
@@ -305,7 +305,7 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
|
|
305
305
|
"""
|
306
306
|
sum up the contribution of all the orbitals with same (n,l,m)
|
307
307
|
"""
|
308
|
-
if self.backend_name == "SIESTA":
|
308
|
+
if self.backend_name.upper() == "SIESTA":
|
309
309
|
mmat_i = self.mmats[iatom]
|
310
310
|
mmat_j = self.mmats[jatom]
|
311
311
|
Jorbij = mmat_i.T @ Jorbij @ mmat_j
|
@@ -345,7 +345,7 @@ class ExchangeNCL(Exchange):
|
|
345
345
|
self.norb = self.G.norb
|
346
346
|
self.nbasis = self.G.nbasis
|
347
347
|
# self.rho = np.zeros((self.nbasis, self.nbasis), dtype=complex)
|
348
|
-
self.rho = self.G.get_density_matrix()
|
348
|
+
self.rho = self.G.get_density_matrix()
|
349
349
|
self.A_ijR_list = defaultdict(lambda: [])
|
350
350
|
self.A_ijR = defaultdict(lambda: np.zeros((4, 4), dtype=complex))
|
351
351
|
self.A_ijR_orb = dict()
|
TB2J/io_merge.py
CHANGED
@@ -1,435 +1,184 @@
|
|
1
1
|
import os
|
2
2
|
import copy
|
3
|
+
import warnings
|
3
4
|
import numpy as np
|
4
|
-
from
|
5
|
+
from itertools import combinations_with_replacement, product
|
5
6
|
from TB2J.io_exchange import SpinIO
|
6
|
-
from TB2J.tensor_rotate import remove_components
|
7
|
-
from TB2J.Jtensor import DMI_to_Jtensor, Jtensor_to_DMI
|
8
|
-
from TB2J.tensor_rotate import Rzx, Rzy, Rzz, Ryz, Rxz
|
9
7
|
|
8
|
+
u0 = np.zeros(3)
|
9
|
+
uy = np.array([0.0, 1.0, 0.0])
|
10
|
+
uz = np.array([0.0, 0.0, 1.0])
|
10
11
|
|
11
|
-
def
|
12
|
-
x = [1, 0, 0]
|
13
|
-
y = [0, 1, 0]
|
14
|
-
z = [0, 0, 1]
|
15
|
-
print(Rxz.apply(x))
|
16
|
-
print(Ryz.apply(y))
|
17
|
-
print(Rzx.apply(z))
|
18
|
-
print(Rzy.apply(z))
|
19
|
-
|
20
|
-
|
21
|
-
def recover_DMI_from_rotated_structure(Ddict, rotation):
|
22
|
-
"""
|
23
|
-
Recover the DMI vector from the rotated structure.
|
24
|
-
D: the dictionary of DMI vector in the rotated structure.
|
25
|
-
rotation: the rotation operator from the original structure to the rotated structure.
|
26
|
-
"""
|
27
|
-
for key, val in Ddict.items():
|
28
|
-
Ddict[key] = rotation.apply(val, inverse=True)
|
29
|
-
return Ddict
|
30
|
-
|
31
|
-
|
32
|
-
def recover_Jani_fom_rotated_structure(Janidict, rotation):
|
33
|
-
"""
|
34
|
-
Recover the Jani tensor from the rotated structure.
|
35
|
-
Janidict: the dictionary of Jani tensor in the rotated structure.
|
36
|
-
rotation: the from the original structure to the rotated structure.
|
37
|
-
"""
|
38
|
-
R = rotation.as_matrix()
|
39
|
-
RT = R.T
|
40
|
-
for key, Jani in Janidict.items():
|
41
|
-
# Note: E=Si J Sj , Si'= Si RT, Sj' = R Sj,
|
42
|
-
# Si' J' Sj' = Si RT R J RT R Sj => J' = R J RT
|
43
|
-
# But here we are doing the opposite rotation back to
|
44
|
-
# the original axis, so we replace R with RT.
|
45
|
-
Janidict[key] = RT @ Jani @ R
|
46
|
-
return Janidict
|
47
|
-
|
48
|
-
|
49
|
-
def recover_spinat_from_rotated_structure(spinat, rotation):
|
50
|
-
"""
|
51
|
-
Recover the spinat from the rotated structure.
|
52
|
-
spinat: the spinat in the rotated structure.
|
53
|
-
rotation: the rotation operator from the original structure to the rotated structure.
|
54
|
-
"""
|
55
|
-
for i, spin in enumerate(spinat):
|
56
|
-
spinat[i] = rotation.apply(spin, inverse=True)
|
57
|
-
return spinat
|
58
|
-
|
59
|
-
|
60
|
-
# test_rotation_matrix()
|
61
|
-
|
62
|
-
# R_xyz = [Rxz.as_matrix(), Ryz.as_matrix(), np.eye(3, dtype=float)]
|
63
|
-
|
64
|
-
|
65
|
-
def rot_merge_DMI(Dx, Dy, Dz):
|
66
|
-
Dx_z = Rzx.apply(Dx)
|
67
|
-
Dy_z = Rzy.apply(Dy)
|
68
|
-
D = (
|
69
|
-
np.array([0.0, 0.5, 0.5]) * Dx_z
|
70
|
-
+ np.array([0.5, 0.0, 0.5]) * Dy_z
|
71
|
-
+ np.array([0.5, 0.5, 0.0]) * Dz
|
72
|
-
)
|
73
|
-
return D
|
74
|
-
|
75
|
-
|
76
|
-
def rot_merge_DMI2(Dx, Dy, Dz):
|
77
|
-
Dx_z = Rzx.apply(Dx)
|
78
|
-
Dy_z = Rzy.apply(Dy)
|
79
|
-
D = (
|
80
|
-
np.array([1, 0, 0]) * Dx_z
|
81
|
-
+ np.array([0, 1, 0]) * Dy_z
|
82
|
-
+ np.array([0, 0, 1]) * Dz
|
83
|
-
)
|
84
|
-
return D
|
12
|
+
def get_Jani_coefficients(a, R=np.eye(3)):
|
85
13
|
|
14
|
+
if len(a) == 1:
|
15
|
+
u = a
|
16
|
+
v = a
|
17
|
+
else:
|
18
|
+
u = a[[0, 0, 1]]
|
19
|
+
v = a[[0, 1, 1]]
|
20
|
+
|
21
|
+
ur = u @ R.T
|
22
|
+
vr = v @ R.T
|
23
|
+
coefficients = np.hstack([ur*vr, np.roll(ur, -1, axis=-1)*vr + np.roll(vr, -1, axis=-1)*ur])
|
86
24
|
|
87
|
-
|
88
|
-
D = (
|
89
|
-
np.array([0.0, 0.5, 0.5]) * Dx
|
90
|
-
+ np.array([0.5, 0.0, 0.5]) * Dy
|
91
|
-
+ np.array([0.5, 0.5, 0.0]) * Dz
|
92
|
-
)
|
93
|
-
return D
|
25
|
+
return coefficients, u, v
|
94
26
|
|
27
|
+
def get_projections(a, b, tol=1e-2):
|
95
28
|
|
96
|
-
|
97
|
-
|
98
|
-
|
29
|
+
projections = np.empty((2, 3))
|
30
|
+
if np.linalg.matrix_rank([a, b], tol=tol) == 1:
|
31
|
+
if np.linalg.matrix_rank([a, uy], tol=tol) == 1:
|
32
|
+
projections[0] = np.cross(a, uz)
|
33
|
+
else:
|
34
|
+
projections[0] = np.cross(a, uy)
|
35
|
+
projections[1] = np.cross(a, projections[0])
|
36
|
+
projections /= np.linalg.norm(projections, axis=-1).reshape(-1, 1)
|
37
|
+
else:
|
38
|
+
projections[0] = np.cross(a, b)
|
39
|
+
projections[0] /= np.linalg.norm(projections[0])
|
40
|
+
projections[1] = u0
|
99
41
|
|
42
|
+
return projections
|
100
43
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
"""
|
106
|
-
idirections = list(idirections)
|
107
|
-
inv = [idirections[1], idirections[0]]
|
108
|
-
n = np.copy(m)
|
109
|
-
n[:, idirections] = n[:, inv]
|
110
|
-
n[idirections, :] = n[inv, :]
|
111
|
-
return n
|
44
|
+
class SpinIO_merge(SpinIO):
|
45
|
+
def __init__(self, *args, **kwargs):
|
46
|
+
super(SpinIO_merge, self).__init__(*args, **kwargs)
|
47
|
+
self.projv = None
|
112
48
|
|
49
|
+
def _set_projection_vectors(self):
|
113
50
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
51
|
+
spinat = self.spinat
|
52
|
+
idx = [self.ind_atoms[i] for i in self.index_spin if i >= 0]
|
53
|
+
projv = {}
|
54
|
+
for i, j in combinations_with_replacement(range(self.nspin), 2):
|
55
|
+
a, b = spinat[idx][[i, j]]
|
56
|
+
projv[i, j] = get_projections(a, b)
|
57
|
+
projv[j, i] = projv[i, j]
|
118
58
|
|
59
|
+
self.projv = projv
|
119
60
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
# + np.array([[1, 0, 1], [0, 0, 0], [1, 0, 1]]) * Janiy
|
125
|
-
# + np.array([[1, 1, 0], [1, 1, 0], [0, 0, 0]]) * Janiz
|
126
|
-
# ) / 2.0
|
127
|
-
wx = np.array([[0, 0, 0], [0, 1, 1], [0, 1, 1]])
|
128
|
-
wy = np.array([[1, 0, 1], [0, 0, 0], [1, 0, 1]])
|
129
|
-
wz = np.array([[1, 1, 0], [1, 1, 0], [0, 0, 0]])
|
130
|
-
Jani = (wx * Janix + wy * Janiy + wz * Janiz) / (wx + wy + wz)
|
131
|
-
return Jani
|
61
|
+
@classmethod
|
62
|
+
def load_pickle(cls, path='TB2J_results', fname='TB2J.pickle'):
|
63
|
+
obj = super(SpinIO_merge, cls).load_pickle(path=path, fname=fname)
|
64
|
+
obj._set_projection_vectors()
|
132
65
|
|
66
|
+
return obj
|
133
67
|
|
134
68
|
def read_pickle(path):
|
135
|
-
p1 = os.path.join(path,
|
136
|
-
p2 = os.path.join(path,
|
69
|
+
p1 = os.path.join(path, 'TB2J_results', 'TB2J.pickle')
|
70
|
+
p2 = os.path.join(path, 'TB2J.pickle')
|
137
71
|
if os.path.exists(p1) and os.path.exists(p2):
|
138
72
|
print(f" WARNING!: Both file {p1} and {p2} exist. Use default {p1}.")
|
139
73
|
if os.path.exists(p1):
|
140
|
-
ret =
|
74
|
+
ret = SpinIO_merge.load_pickle(os.path.join(path, 'TB2J_results'))
|
141
75
|
elif os.path.exists(p2):
|
142
|
-
ret =
|
76
|
+
ret = SpinIO_merge.load_pickle(path)
|
143
77
|
else:
|
144
78
|
raise FileNotFoundError(f"Cannot find either file {p1} or {p2}")
|
145
79
|
return ret
|
146
80
|
|
81
|
+
class Merger():
|
82
|
+
def __init__(self, *paths, main_path=None):
|
83
|
+
self.dat = [read_pickle(path) for path in paths]
|
147
84
|
|
148
|
-
|
149
|
-
|
150
|
-
self.method = method
|
151
|
-
if method.lower() == "spin":
|
152
|
-
self.load_with_rotated_spin(paths)
|
153
|
-
elif method.lower() == "structure":
|
154
|
-
self.load_with_rotated_structure(paths)
|
85
|
+
if main_path is None:
|
86
|
+
self.main_dat = copy.deepcopy(self.dat[-1])
|
155
87
|
else:
|
156
|
-
|
157
|
-
|
158
|
-
def load_with_rotated_structure(self, paths):
|
159
|
-
"""
|
160
|
-
Merge TB2J results from multiple calculations.
|
161
|
-
:param paths: a list of paths to the TB2J results.
|
162
|
-
:param method: 'structure' or 'spin'
|
163
|
-
"""
|
164
|
-
self.paths = paths
|
165
|
-
if len(self.paths) != 3:
|
166
|
-
raise ValueError(
|
167
|
-
"The number of paths should be 3, with structure rotated from z to x, y, z"
|
168
|
-
)
|
169
|
-
for i, path in enumerate(self.paths):
|
170
|
-
read_pickle(path)
|
171
|
-
self.indata = [read_pickle(path) for path in paths]
|
172
|
-
|
173
|
-
self.dat = copy.deepcopy(self.indata[-1])
|
174
|
-
# self.dat.description += (
|
175
|
-
# "Merged from TB2J results in paths: \n " + "\n ".join(paths) + "\n"
|
176
|
-
# )
|
177
|
-
Rotations = [Rzx, Rzy, Rzz]
|
178
|
-
for dat, rotation in zip(self.indata, Rotations):
|
179
|
-
dat.spinat = recover_spinat_from_rotated_structure(dat.spinat, rotation)
|
180
|
-
dat.dmi_ddict = recover_DMI_from_rotated_structure(dat.dmi_ddict, rotation)
|
181
|
-
dat.Jani_dict = recover_Jani_fom_rotated_structure(dat.Jani_dict, rotation)
|
182
|
-
|
183
|
-
def load_with_rotated_spin(self, paths):
|
184
|
-
"""
|
185
|
-
Merge TB2J results from multiple calculations.
|
186
|
-
:param paths: a list of paths to the TB2J results.
|
187
|
-
:param method: 'structure' or 'spin'
|
188
|
-
"""
|
189
|
-
self.paths = paths
|
190
|
-
self.indata = [read_pickle(path) for path in paths]
|
191
|
-
self.dat = copy.deepcopy(self.indata[-1])
|
192
|
-
# self.dat.description += (
|
193
|
-
# "Merged from TB2J results in paths: \n " + "\n ".join(paths) + "\n"
|
194
|
-
# )
|
195
|
-
|
196
|
-
def merge_Jani(self):
|
197
|
-
"""
|
198
|
-
Merge the anisotropic exchange tensor.
|
199
|
-
"""
|
200
|
-
Jani_dict = {}
|
201
|
-
for key, Jani in self.dat.Jani_dict.items():
|
202
|
-
R, i, j = key
|
203
|
-
weights = np.zeros((3, 3), dtype=float)
|
204
|
-
Jani_sum = np.zeros((3, 3), dtype=float)
|
205
|
-
for dat in self.indata:
|
206
|
-
Si = dat.get_spin_ispin(i)
|
207
|
-
Sj = dat.get_spin_ispin(j)
|
208
|
-
# print(f"{Si=}, {Sj=}")
|
209
|
-
Jani = dat.get_Jani(i, j, R, default=np.zeros((3, 3), dtype=float))
|
210
|
-
Jani_removed, w = remove_components(
|
211
|
-
Jani,
|
212
|
-
Si,
|
213
|
-
Sj,
|
214
|
-
remove_indices=[[0, 2], [1, 2], [2, 2], [2, 1], [2, 0]],
|
215
|
-
)
|
216
|
-
w = Jani_removed / Jani
|
217
|
-
Jani_sum += Jani * w # Jani_removed
|
218
|
-
# print(f"{Jani* w=}")
|
219
|
-
weights += w
|
220
|
-
# print(f"{weights=}")
|
221
|
-
if np.any(weights == 0):
|
222
|
-
raise RuntimeError(
|
223
|
-
"The data set to be merged does not give a complete anisotropic J tensor, please add more data"
|
224
|
-
)
|
225
|
-
Jani_dict[key] = Jani_sum / weights
|
226
|
-
self.dat.Jani_dict = Jani_dict
|
227
|
-
|
228
|
-
def merge_DMI(self):
|
229
|
-
"""
|
230
|
-
merge the DMI vector
|
231
|
-
"""
|
232
|
-
DMI = {}
|
233
|
-
for key, D in self.dat.dmi_ddict.items():
|
234
|
-
R, i, j = key
|
235
|
-
weights = np.zeros((3, 3), dtype=float)
|
236
|
-
Dtensor_sum = np.zeros((3, 3), dtype=float)
|
237
|
-
for dat in self.indata:
|
238
|
-
Si = dat.get_spin_ispin(i)
|
239
|
-
Sj = dat.get_spin_ispin(j)
|
240
|
-
D = dat.get_DMI(i, j, R, default=np.zeros((3,), dtype=float))
|
241
|
-
Dtensor = DMI_to_Jtensor(D)
|
242
|
-
Dtensor_removed, w = remove_components(
|
243
|
-
Dtensor, Si, Sj, remove_indices=[[0, 1], [1, 0]]
|
244
|
-
)
|
245
|
-
Dtensor_sum += Dtensor * w # Dtensor_removed
|
246
|
-
weights += w
|
247
|
-
if np.any(weights == 0):
|
248
|
-
raise RuntimeError(
|
249
|
-
"The data set to be merged does not give a complete DMI vector, please add more data"
|
250
|
-
)
|
251
|
-
DMI[key] = Jtensor_to_DMI(Dtensor_sum / weights)
|
252
|
-
self.dat.dmi_ddict = DMI
|
88
|
+
self.main_dat = read_pickle(main_path)
|
89
|
+
self.dat.append(copy.deepcopy(self.main_dat))
|
253
90
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
"""
|
258
|
-
Jiso = {}
|
259
|
-
for key, J in self.dat.exchange_Jdict.items():
|
260
|
-
R, i, j = key
|
261
|
-
weights = 0.0
|
262
|
-
Jiso_sum = 0.0
|
263
|
-
for dat in self.indata:
|
264
|
-
Si = dat.get_spin_ispin(i)
|
265
|
-
Sj = dat.get_spin_ispin(j)
|
266
|
-
J = dat.get_Jiso(i, j, R, default=0.0)
|
267
|
-
Jiso_sum += J # *np.eye(3, dtype=float)
|
268
|
-
weights += 1.0
|
269
|
-
if np.any(weights == 0):
|
270
|
-
raise RuntimeError(
|
271
|
-
"The data set to be merged does not give a complete isotropic exchange, please add more data"
|
272
|
-
)
|
273
|
-
Jiso[key] = Jiso_sum / weights
|
274
|
-
self.dat.exchange_Jdict = Jiso
|
91
|
+
self._set_projv()
|
92
|
+
|
93
|
+
def _set_projv(self):
|
275
94
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
:param path: the path to the folder to write the results.
|
280
|
-
"""
|
281
|
-
self.dat.description += (
|
282
|
-
"Merged from TB2J results in paths: \n " + "\n ".join(self.paths) + "\n"
|
95
|
+
cell = self.main_dat.atoms.cell.array
|
96
|
+
rotated_cells = np.stack(
|
97
|
+
[obj.atoms.cell.array for obj in self.dat], axis=0
|
283
98
|
)
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
99
|
+
R = np.linalg.solve(cell, rotated_cells)
|
100
|
+
indices = range(len(self.dat))
|
101
|
+
|
102
|
+
proju = {}; projv = {}; coeff_matrix = {}; projectors = {};
|
103
|
+
for key in self.main_dat.projv.keys():
|
104
|
+
vectors = [obj.projv[key] for obj in self.dat]
|
105
|
+
coefficients, u, v = zip(*[get_Jani_coefficients(vectors[i], R=R[i]) for i in indices])
|
106
|
+
projectors[key] = np.vstack([u[i] @ R[i].T for i in indices])
|
107
|
+
coeff_matrix[key] = np.vstack(coefficients)
|
108
|
+
proju[key] = np.stack(u)
|
109
|
+
projv[key] = np.stack(v)
|
110
|
+
if np.linalg.matrix_rank(coeff_matrix[key], tol=1e-2) < 6:
|
111
|
+
warnings.warn('''
|
112
|
+
WARNING: The matrix of equations to reconstruct the exchange tensors is
|
113
|
+
close to being singular. This happens when the magnetic moments between
|
114
|
+
different configurations are cloes to being parallel. You need to consider
|
115
|
+
more rotated spin configurations, otherwise the results might have a large
|
116
|
+
error.'''
|
117
|
+
)
|
118
|
+
|
119
|
+
self.proju = proju
|
120
|
+
self.projv = projv
|
121
|
+
self.coeff_matrix = coeff_matrix
|
122
|
+
self.projectors = projectors
|
303
123
|
|
304
124
|
def merge_Jani(self):
|
305
125
|
Jani_dict = {}
|
306
|
-
|
307
|
-
|
308
|
-
Janizdict = self.dat_z.Jani_dict
|
309
|
-
for key, Janiz in Janizdict.items():
|
126
|
+
proju = self.proju; projv = self.projv; coeff_matrix = self.coeff_matrix;
|
127
|
+
for key in self.main_dat.Jani_dict.keys():
|
310
128
|
try:
|
311
129
|
R, i, j = key
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
130
|
+
u = proju[i, j]
|
131
|
+
v = projv[i, j]
|
132
|
+
Jani = np.stack([sio.Jani_dict[key] for sio in self.dat])
|
133
|
+
projections = np.einsum('nmi,nij,nmj->nm', u, Jani, v).flatten()
|
316
134
|
except KeyError as err:
|
317
135
|
raise KeyError(
|
318
136
|
"Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
|
319
|
-
% err
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
self.dat.Jani_dict = Jani_dict
|
137
|
+
% err)
|
138
|
+
newJani = np.linalg.lstsq(coeff_matrix[i, j], projections, rcond=1e-2)[0]
|
139
|
+
Jani_dict[key] = np.array([
|
140
|
+
[newJani[0], newJani[3], newJani[5]],
|
141
|
+
[newJani[3], newJani[1], newJani[4]],
|
142
|
+
[newJani[5], newJani[4], newJani[2]]
|
143
|
+
])
|
144
|
+
self.main_dat.Jani_dict = Jani_dict
|
328
145
|
|
329
146
|
def merge_Jiso(self):
|
330
|
-
Jdict
|
331
|
-
|
332
|
-
Jydict = self.dat_y.exchange_Jdict
|
333
|
-
Jzdict = self.dat_z.exchange_Jdict
|
334
|
-
for key, J in Jzdict.items():
|
147
|
+
Jdict={}
|
148
|
+
for key in self.main_dat.exchange_Jdict.keys():
|
335
149
|
try:
|
336
|
-
|
337
|
-
Jy = Jydict[key]
|
338
|
-
Jz = Jzdict[key]
|
150
|
+
J = np.mean([obj.exchange_Jdict[key] for obj in self.dat])
|
339
151
|
except KeyError as err:
|
340
152
|
raise KeyError(
|
341
|
-
"Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
|
342
|
-
% err
|
343
|
-
)
|
344
|
-
Jdict[key] = (Jx + Jy + Jz) / 3.0
|
345
|
-
self.dat.exchange_Jdict = Jdict
|
346
|
-
|
347
|
-
def merge_DMI(self):
|
348
|
-
dmi_ddict = {}
|
349
|
-
if self.dat_x.has_dmi and self.dat_y.has_dmi and self.dat_z.has_dmi:
|
350
|
-
Dxdict = self.dat_x.dmi_ddict
|
351
|
-
Dydict = self.dat_y.dmi_ddict
|
352
|
-
Dzdict = self.dat_z.dmi_ddict
|
353
|
-
for key, Dz in Dzdict.items():
|
354
|
-
try:
|
355
|
-
R, i, j = key
|
356
|
-
keyx = R
|
357
|
-
keyy = R
|
358
|
-
Dx = Dxdict[(tuple(keyx), i, j)]
|
359
|
-
Dy = Dydict[(tuple(keyy), i, j)]
|
360
|
-
except KeyError as err:
|
361
|
-
raise KeyError(
|
362
153
|
"Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
|
363
|
-
% err
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
else:
|
368
|
-
dmi_ddict[key] = merge_DMI(Dx, Dy, Dz)
|
369
|
-
self.dat.dmi_ddict = dmi_ddict
|
154
|
+
% err)
|
155
|
+
Jdict[key] = J
|
156
|
+
self.main_dat.exchange_Jdict = Jdict
|
157
|
+
|
370
158
|
|
159
|
+
def merge_DMI(self):
|
371
160
|
dmi_ddict = {}
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
Dzdict = self.dat_z.debug_dict["DMI2"]
|
376
|
-
for key, Dz in Dzdict.items():
|
161
|
+
if all(obj.has_dmi for obj in self.dat):
|
162
|
+
projectors = self.projectors; proju = self.proju;
|
163
|
+
for key in self.main_dat.dmi_ddict.keys():
|
377
164
|
try:
|
378
165
|
R, i, j = key
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
Dy = Dydict[(tuple(keyy), i, j)]
|
166
|
+
u = proju[i, j]
|
167
|
+
DMI = np.stack([sio.dmi_ddict[key] for sio in self.dat])
|
168
|
+
projections = np.einsum('nmi,ni->nm', u, DMI).flatten()
|
383
169
|
except KeyError as err:
|
384
170
|
raise KeyError(
|
385
171
|
"Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
|
386
|
-
% err
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
elif self.method == "spin":
|
391
|
-
dmi_ddict[key] = merge_DMI2(Dx, Dy, Dz)
|
392
|
-
|
393
|
-
self.dat.debug_dict["DMI2"] = dmi_ddict
|
394
|
-
except:
|
395
|
-
pass
|
396
|
-
|
397
|
-
def write(self, path="TB2J_results"):
|
398
|
-
self.dat.description += (
|
399
|
-
"Merged from TB2J results in paths: \n " + "\n ".join(self.paths) + "\n"
|
400
|
-
)
|
401
|
-
if self.method == "spin":
|
402
|
-
self.dat.description += (
|
403
|
-
", which are from DFT data with spin along x, y, z orientation\n"
|
404
|
-
)
|
405
|
-
elif self.method == "structure":
|
406
|
-
self.dat.description += ", which are from DFT data with structure with z axis rotated to x, y, z\n"
|
407
|
-
self.dat.description += "\n"
|
408
|
-
self.dat.write_all(path=path)
|
409
|
-
|
410
|
-
|
411
|
-
def merge(path_x, path_y, path_z, method, save=True, path="TB2J_results"):
|
412
|
-
m = Merger(path_x, path_y, path_z, method)
|
413
|
-
m.merge_Jiso()
|
414
|
-
m.merge_DMI()
|
415
|
-
m.merge_Jani()
|
416
|
-
if save:
|
417
|
-
m.write(path=path)
|
418
|
-
return m.dat
|
419
|
-
|
172
|
+
% err)
|
173
|
+
newDMI = np.linalg.lstsq(projectors[i, j], projections, rcond=4e-1)[0]
|
174
|
+
dmi_ddict[key] = newDMI
|
175
|
+
self.main_dat.dmi_ddict = dmi_ddict
|
420
176
|
|
421
|
-
def
|
422
|
-
|
423
|
-
Merge TB2J results from multiple calculations.
|
424
|
-
:param paths: a list of paths to the TB2J results.
|
425
|
-
:param method: 'structure' or 'spin'
|
426
|
-
:param save: whether to save the merged results.
|
427
|
-
:param path: the path to the folder to write the results.
|
428
|
-
"""
|
429
|
-
m = Merger2(paths, method)
|
177
|
+
def merge(*paths, main_path=None, save=True, write_path='TB2J_results'):
|
178
|
+
m = Merger(*paths, main_path=main_path)
|
430
179
|
m.merge_Jiso()
|
431
180
|
m.merge_DMI()
|
432
181
|
m.merge_Jani()
|
433
182
|
if save:
|
434
|
-
m.
|
183
|
+
m.main_dat.write_all(path=write_path)
|
435
184
|
return m.dat
|
TB2J/myTB.py
CHANGED
@@ -16,7 +16,6 @@ class AbstractTB:
|
|
16
16
|
def __init__(self, R2kfactor, nspin, norb):
|
17
17
|
#: :math:`\alpha` used in :math:`H(k)=\sum_R H(R) \exp( \alpha k \cdot R)`,
|
18
18
|
#: Should be :math:`2\pi i` or :math:`-2\pi i`
|
19
|
-
self.is_siesta = False
|
20
19
|
self.is_orthogonal = True
|
21
20
|
self.R2kfactor = R2kfactor
|
22
21
|
|
@@ -125,7 +124,6 @@ class MyTB(AbstractTB):
|
|
125
124
|
self.atoms = None
|
126
125
|
self.R2kfactor = 2.0j * np.pi
|
127
126
|
self.k2Rfactor = -2.0j * np.pi
|
128
|
-
self.is_siesta = False
|
129
127
|
self.is_orthogonal = True
|
130
128
|
self._name = "Wannier"
|
131
129
|
|