TB2J 0.9.0.1__py3-none-any.whl → 0.9.2rc0__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.
Files changed (38) hide show
  1. TB2J/Jdownfolder.py +110 -24
  2. TB2J/Jtensor.py +1 -1
  3. TB2J/MAE.py +185 -0
  4. TB2J/abacus/MAE.py +320 -0
  5. TB2J/abacus/abacus_wrapper.py +103 -4
  6. TB2J/abacus/occupations.py +278 -0
  7. TB2J/abacus/test_density_matrix.py +38 -0
  8. TB2J/cut_cell.py +82 -0
  9. TB2J/exchange.py +99 -73
  10. TB2J/exchangeCL2.py +10 -5
  11. TB2J/green.py +14 -15
  12. TB2J/io_exchange/io_pickle.py +0 -0
  13. TB2J/manager.py +10 -4
  14. TB2J/mathutils/__init__.py +1 -0
  15. TB2J/mathutils/fermi.py +22 -0
  16. TB2J/mathutils/kR_convert.py +90 -0
  17. TB2J/mathutils/lowdin.py +12 -0
  18. TB2J/mathutils/rotate_spin.py +56 -0
  19. TB2J/patch.py +50 -0
  20. TB2J/pauli.py +17 -0
  21. TB2J/spinham/h_matrix.py +68 -0
  22. TB2J/spinham/obtain_J.py +79 -0
  23. TB2J/supercell.py +532 -0
  24. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/TB2J_downfold.py +8 -0
  25. {TB2J-0.9.0.1.dist-info → TB2J-0.9.2rc0.dist-info}/METADATA +1 -1
  26. {TB2J-0.9.0.1.dist-info → TB2J-0.9.2rc0.dist-info}/RECORD +38 -23
  27. {TB2J-0.9.0.1.dist-info → TB2J-0.9.2rc0.dist-info}/WHEEL +1 -1
  28. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/TB2J_eigen.py +0 -0
  29. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/TB2J_magnon.py +0 -0
  30. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/TB2J_magnon_dos.py +0 -0
  31. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/TB2J_merge.py +0 -0
  32. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/TB2J_rotate.py +0 -0
  33. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/TB2J_rotateDM.py +0 -0
  34. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/abacus2J.py +0 -0
  35. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/siesta2J.py +0 -0
  36. {TB2J-0.9.0.1.data → TB2J-0.9.2rc0.data}/scripts/wann2J.py +0 -0
  37. {TB2J-0.9.0.1.dist-info → TB2J-0.9.2rc0.dist-info}/LICENSE +0 -0
  38. {TB2J-0.9.0.1.dist-info → TB2J-0.9.2rc0.dist-info}/top_level.txt +0 -0
TB2J/abacus/MAE.py ADDED
@@ -0,0 +1,320 @@
1
+ import numpy as np
2
+ from TB2J.abacus.abacus_wrapper import AbacusWrapper, AbacusParser
3
+ from TB2J.mathutils.rotate_spin import rotate_Matrix_from_z_to_axis
4
+ from TB2J.kpoints import monkhorst_pack
5
+ from TB2J.mathutils.fermi import fermi
6
+ from TB2J.mathutils.kR_convert import R_to_k
7
+ from scipy.linalg import eigh
8
+ from copy import deepcopy
9
+ from scipy.spatial.transform import Rotation
10
+ import matplotlib.pyplot as plt
11
+ from pathlib import Path
12
+ from TB2J.abacus.occupations import Occupations
13
+
14
+ # TODO List:
15
+ # - [x] Add the class AbacusSplitSOCWrapper
16
+ # - [x] Add the function to rotate the XC part
17
+ # - [x] Compute the band energy at arbitrary angle
18
+
19
+
20
+ def get_occupation(evals, kweights, nel, width=0.1):
21
+ occ = Occupations(nel=nel, width=width, wk=kweights, nspin=2)
22
+ return occ.occupy(evals)
23
+
24
+
25
+ def get_density_matrix(evals=None, evecs=None, kweights=None, nel=None, width=0.1):
26
+ occ = get_occupation(evals, kweights, nel, width=width)
27
+ rho = np.einsum("kib, kb, kjb -> kij", evecs, occ, evecs.conj())
28
+ return rho
29
+
30
+
31
+ def spherical_to_cartesian(theta, phi, normalize=True):
32
+ """
33
+ Convert spherical coordinates to cartesian
34
+ """
35
+ x = np.sin(theta) * np.cos(phi)
36
+ y = np.sin(theta) * np.sin(phi)
37
+ z = np.cos(theta)
38
+ vec = np.array([x, y, z])
39
+ if normalize:
40
+ vec = vec / np.linalg.norm(vec)
41
+ return vec
42
+
43
+
44
+ class AbacusSplitSOCWrapper(AbacusWrapper):
45
+ """
46
+ Abacus wrapper with Hamiltonian split to SOC and non-SOC parts
47
+ """
48
+
49
+ def __init__(self, *args, **kwargs):
50
+ HR_soc = kwargs.pop("HR_soc", None)
51
+ # nbasis = HR_soc.shape[1]
52
+ # kwargs["nbasis"] = nbasis
53
+ super().__init__(*args, **kwargs)
54
+ self._HR_copy = deepcopy(self._HR)
55
+ self.HR_soc = HR_soc
56
+ self.soc_lambda = 1.0
57
+ self.nel = 16
58
+ self.width = 0.1
59
+
60
+ @property
61
+ def HR(self):
62
+ return self._HR + self.HR_soc * self.soc_lambda
63
+
64
+ def rotate_HR_xc(self, axis):
65
+ """
66
+ Rotate SOC part of Hamiltonian
67
+ """
68
+ for iR, R in enumerate(self.Rlist):
69
+ self._HR[iR] = rotate_Matrix_from_z_to_axis(self._HR_copy[iR], axis)
70
+
71
+ def rotate_Hk_xc(self, axis):
72
+ """
73
+ Rotate SOC part of Hamiltonian
74
+ """
75
+ for ik in range(len(self._Hk)):
76
+ self._Hk[ik] = rotate_Matrix_from_z_to_axis(self._Hk_copy[ik], axis)
77
+
78
+ def get_density_matrix(self, kpts, kweights=None):
79
+ rho = np.zeros((len(kpts), self.nbasis, self.nbasis), dtype=complex)
80
+ evals, evecs = self.solve_all(kpts)
81
+ occ = get_occupation(evals, kweights, self.nel, width=self.width)
82
+ rho = np.einsum(
83
+ "kib, kb, kjb -> kij", evecs, occ, evecs.conj()
84
+ ) # should multiply S to the the real DM.
85
+ return rho
86
+
87
+ def rotate_DM(self, rho, axis):
88
+ """
89
+ Rotate the density matrix
90
+ """
91
+ for ik in range(len(rho)):
92
+ rho[ik] = rotate_Matrix_from_z_to_axis(rho[ik], axis)
93
+ return rho
94
+
95
+
96
+ class RotateHam:
97
+ def __init__(self, model, kmesh, gamma=True):
98
+ self.model = model
99
+ self.kpts = monkhorst_pack(kmesh, gamma_center=gamma)
100
+ self.kweights = np.ones(len(self.kpts), dtype=float) / len(self.kpts)
101
+
102
+ def get_band_energy2(self):
103
+ for ik, kpt in enumerate(self.kpts):
104
+ Hk, Sk = self.model.gen_ham(kpt)
105
+ evals, evecs = eigh(Hk, Sk)
106
+ rho = np.einsum(
107
+ "ib, b, jb -> ij",
108
+ evecs,
109
+ fermi(evals, self.model.efermi, width=0.05),
110
+ evecs.conj(),
111
+ )
112
+ eband1 = np.sum(evals * fermi(evals, self.model.efermi, width=0.05))
113
+ eband2 = np.trace(Hk @ rho)
114
+ print(eband1, eband2)
115
+
116
+ def get_band_energy(self, dm=False):
117
+ evals, evecs = self.model.solve_all(self.kpts)
118
+ occ = get_occupation(
119
+ evals, self.kweights, self.model.nel, width=self.model.width
120
+ )
121
+ eband = np.sum(evals * occ * self.kweights[:, np.newaxis])
122
+ # * fermi(evals, self.model.efermi, width=0.05)
123
+ if dm:
124
+ density_matrix = self.model.get_density_matrix(evecs)
125
+ return eband, density_matrix
126
+ else:
127
+ return eband
128
+
129
+ def calc_ref(self):
130
+ # calculate the Hk_ref, Sk_ref, Hk_soc_ref, and rho_ref
131
+ self.Sk_ref = R_to_k(self.kpts, self.model.Rlist, self.model.SR)
132
+ self.Hk_xc_ref = R_to_k(self.kpts, self.model.Rlist, self.model._HR_copy)
133
+ self.Hk_soc_ref = R_to_k(self.kpts, self.model.Rlist, self.model.HR_soc)
134
+ self.rho_ref = np.zeros(
135
+ (len(self.kpts), self.model.nbasis, self.model.nbasis), dtype=complex
136
+ )
137
+
138
+ evals = np.zeros((len(self.kpts), self.model.nbasis), dtype=float)
139
+ evecs = np.zeros(
140
+ (len(self.kpts), self.model.nbasis, self.model.nbasis), dtype=complex
141
+ )
142
+
143
+ for ik, kpt in enumerate(self.kpts):
144
+ # evals, evecs = eigh(self.Hk_xc_ref[ik]+self.Hk_soc_ref[ik], self.Sk_ref[ik])
145
+ evals[ik], evecs[ik] = eigh(self.Hk_xc_ref[ik], self.Sk_ref[ik])
146
+ occ = get_occupation(
147
+ evals, self.kweights, self.model.nel, width=self.model.width
148
+ )
149
+ # occ = fermi(evals, self.model.efermi, width=self.model.width)
150
+ self.rho_ref = np.einsum("kib, kb, kjb -> kij", evecs, occ, evecs.conj())
151
+
152
+ def get_band_energy_from_rho(self, axis):
153
+ """
154
+ This is wrong!! Should use second order perturbation theory to get the band energy instead.
155
+ """
156
+ eband = 0.0
157
+ for ik, k in enumerate(self.kpts):
158
+ rho = rotate_Matrix_from_z_to_axis(self.rho_ref[ik], axis)
159
+ Hk_xc = rotate_Matrix_from_z_to_axis(self.Hk_xc_ref[ik], axis)
160
+ Hk_soc = self.Hk_soc_ref[ik]
161
+ Htot = Hk_xc + Hk_soc * self.model.soc_lambda
162
+ # Sk = self.Sk_ref[ik]
163
+ # evals, evecs = eigh(Htot, Sk)
164
+ # rho2= np.einsum("ib, b, jb -> ij", evecs, fermi(evals, self.model.efermi, width=0.05), evecs.conj())
165
+ if ik == 0 and False:
166
+ pass
167
+ # print(f"{evecs[:4,0:4].real=}")
168
+ # print(f"{evals[:4]=}")
169
+ # print(f"{Hk_xc[:4,0:4].real=}")
170
+ # print(f"{Htot[:4,0:4].real=}")
171
+ # print(f"{Sk[:4,0:4].real=}")
172
+ # print(f"{rho[:4,0:4].real=}")
173
+ # print(f"{rho2[:4,0:4].real=}")
174
+ # eband1 = np.sum(evals * fermi(evals, self.model.efermi, width=0.05))
175
+ # eband2 = np.trace(Htot @ rho2).real
176
+ # eband3 = np.trace(Htot @ rho).real
177
+ # print(eband1, eband2, eband3)
178
+ e_soc = np.trace(Hk_soc @ rho) * self.kweights[ik] * self.model.soc_lambda
179
+ eband += e_soc
180
+ return eband
181
+
182
+ def get_band_energy_vs_angles(
183
+ self,
184
+ thetas,
185
+ psis,
186
+ ):
187
+ es = []
188
+ # es2 = []
189
+ # e,rho = self.model.get_band_energy(dm=True)
190
+ # self.calc_ref()
191
+ # thetas = np.linspace(*angle_range, npoints)
192
+ for i, theta, phi in enumerate(zip(thetas, psis)):
193
+ axis = spherical_to_cartesian(theta, phi)
194
+ self.model.rotate_HR_xc(axis)
195
+ # self.get_band_energy2()
196
+ e = self.get_band_energy()
197
+ es.append(e)
198
+ # es2.append(e2)
199
+ return es
200
+
201
+
202
+ def get_model_energy(model, kmesh, gamma=True):
203
+ ham = RotateHam(model, kmesh, gamma=gamma)
204
+ return ham.get_band_energy()
205
+
206
+
207
+ class AbacusSplitSOCParser:
208
+ """
209
+ Abacus parser with Hamiltonian split to SOC and non-SOC parts
210
+ """
211
+
212
+ def __init__(self, outpath_nosoc=None, outpath_soc=None, binary=False):
213
+ self.outpath_nosoc = outpath_nosoc
214
+ self.outpath_soc = outpath_soc
215
+ self.binary = binary
216
+ self.parser_nosoc = AbacusParser(outpath=outpath_nosoc, binary=binary)
217
+ self.parser_soc = AbacusParser(outpath=outpath_soc, binary=binary)
218
+ spin1 = self.parser_nosoc.read_spin()
219
+ spin2 = self.parser_soc.read_spin()
220
+ if spin1 != "noncollinear" or spin2 != "noncollinear":
221
+ raise ValueError("Spin should be noncollinear")
222
+
223
+ def parse(self):
224
+ nbasis, Rlist, HR, SR = self.parser_nosoc.Read_HSR_noncollinear()
225
+ nbasis2, Rlist2, HR2, SR2 = self.parser_soc.Read_HSR_noncollinear()
226
+ # print(HR[0])
227
+ HR_soc = HR2 - HR
228
+ model = AbacusSplitSOCWrapper(HR, SR, Rlist, nbasis, nspin=2, HR_soc=HR_soc)
229
+ model.efermi = self.parser_soc.efermi
230
+ model.basis = self.parser_nosoc.basis
231
+ model.atoms = self.parser_nosoc.atoms
232
+ return model
233
+
234
+
235
+ def abacus_get_MAE(
236
+ path_nosoc, path_soc, kmesh, thetas, psis, gamma=True, outfile="MAE.txt"
237
+ ):
238
+ """Get MAE from Abacus with magnetic force theorem. Two calculations are needed. First we do an calculation with SOC but the soc_lambda is set to 0. Save the density. The next calculatin we start with the density from the first calculation and set the SOC prefactor to 1. With the information from the two calcualtions, we can get the band energy with magnetic moments in the direction, specified in two list, thetas, and phis."""
239
+ parser = AbacusSplitSOCParser(
240
+ outpath_nosoc=path_nosoc, outpath_soc=path_soc, binary=False
241
+ )
242
+ model = parser.parse()
243
+ ham = RotateHam(model, kmesh, gamma=gamma)
244
+ es = []
245
+ for theta, psi in zip(thetas, psis):
246
+ axis = spherical_to_cartesian(theta, psi)
247
+ model.rotate_HR_xc(axis)
248
+ e = ham.get_band_energy()
249
+ es.append(ham.get_band_energy())
250
+ if outfile:
251
+ with open(outfile, "w") as f:
252
+ f.write("theta, psi, energy\n")
253
+ for theta, psi, e in zip(thetas, psis, es):
254
+ f.write(f"{theta}, {psi}, {e}\n")
255
+ return es
256
+
257
+
258
+ def test_AbacusSplitSOCWrapper():
259
+ # path = Path("~/projects/2D_Fe").expanduser()
260
+ path = Path("~/projects/TB2Jflows/examples/2D_Fe/Fe_z").expanduser()
261
+ outpath_nosoc = f"{path}/soc0/OUT.ABACUS"
262
+ outpath_soc = f"{path}/soc1/OUT.ABACUS"
263
+ parser = AbacusSplitSOCParser(
264
+ outpath_nosoc=outpath_nosoc, outpath_soc=outpath_soc, binary=False
265
+ )
266
+ model = parser.parse()
267
+ kmesh = [6, 6, 1]
268
+
269
+ r = RotateHam(model, kmesh)
270
+ # thetas, es = r.get_band_energy_vs_theta(angle_range=(0, np.pi*2), rotation_axis="z", initial_direction=(1,0,0), npoints=21)
271
+ thetas, es, es2 = r.get_band_energy_vs_theta(
272
+ angle_range=(0, np.pi * 2),
273
+ rotation_axis="y",
274
+ initial_direction=(0, 0, 1),
275
+ npoints=11,
276
+ )
277
+ # print the table of thetas and es, es2
278
+ print("theta, e, e2")
279
+ for theta, e, e2 in zip(thetas, es, es2):
280
+ print(f"{theta=}, {e=}, {e2=}")
281
+
282
+ plt.plot(thetas / np.pi, es - es[0], marker="o")
283
+ plt.plot(thetas / np.pi, es2 - es2[0], marker=".")
284
+ plt.savefig("E_along_z_x_z.png")
285
+ plt.show()
286
+
287
+
288
+ def abacus_get_MAE_cli():
289
+ import argparse
290
+
291
+ parser = argparse.ArgumentParser(
292
+ description="Get MAE from Abacus with magnetic force theorem. Two calculations are needed. First we do an calculation with SOC but the soc_lambda is set to 0. Save the density. The next calculatin we start with the density from the first calculation and set the SOC prefactor to 1. With the information from the two calcualtions, we can get the band energy with magnetic moments in the direction, specified in two list, thetas, and phis. "
293
+ )
294
+ parser.add_argument("path_nosoc", type=str, help="Path to the calculation with ")
295
+ parser.add_argument("path_soc", type=str, help="Path to the SOC calculation")
296
+ parser.add_argument("thetas", type=float, nargs="+", help="Thetas")
297
+ parser.add_argument("psis", type=float, nargs="+", help="Phis")
298
+ parser.add_argument("kmesh", type=int, nargs=3, help="K-mesh")
299
+ parser.add_argument(
300
+ "--gamma", action="store_true", help="Use Gamma centered kpoints"
301
+ )
302
+ parser.add_argument(
303
+ "--outfile",
304
+ type=str,
305
+ help="The angles and the energey will be saved in this file.",
306
+ )
307
+ args = parser.parse_args()
308
+ abacus_get_MAE(
309
+ args.path_nosoc,
310
+ args.path_soc,
311
+ args.kmesh,
312
+ args.thetas,
313
+ args.psis,
314
+ gamma=args.gamma,
315
+ outfile=args.outfile,
316
+ )
317
+
318
+
319
+ if __name__ == "__main__":
320
+ abacus_get_MAE_cli()
@@ -7,6 +7,8 @@ from pathlib import Path
7
7
  import os
8
8
  import numpy as np
9
9
  from scipy.linalg import eigh
10
+ from copy import deepcopy
11
+ from TB2J.mathutils.rotate_spin import rotate_Matrix_from_z_to_spherical
10
12
  from TB2J.utils import symbol_number_list
11
13
  from TB2J.myTB import AbstractTB
12
14
  from TB2J.abacus.abacus_api import read_HR_SR
@@ -15,17 +17,55 @@ from TB2J.abacus.stru_api import read_abacus, read_abacus_out
15
17
 
16
18
 
17
19
  class AbacusWrapper(AbstractTB):
18
- def __init__(self, HR, SR, Rlist, nbasis, nspin=1):
19
- self.R2kfactor = -2j * np.pi
20
+ def __init__(
21
+ self, HR, SR, Rlist, nbasis, nspin=1, HR_soc=None, HR_nosoc=None, nel=None
22
+ ):
23
+ self.R2kfactor = 2j * np.pi
20
24
  self.is_orthogonal = False
25
+ self.split_soc = False
21
26
  self._name = "ABACUS"
22
- self.HR = HR
27
+ self._HR = HR
23
28
  self.SR = SR
24
29
  self.Rlist = Rlist
25
30
  self.nbasis = nbasis
26
31
  self.nspin = nspin
27
32
  self.norb = nbasis * nspin
33
+ self.nel = nel
28
34
  self._build_Rdict()
35
+ if HR_soc is not None:
36
+ self.set_HR_soc(HR_soc=HR_soc, HR_nosoc=HR_nosoc, HR_full=HR)
37
+ self.soc_rotation_angle = 0.0
38
+
39
+ def set_HR_soc(self, HR_soc=None, HR_nosoc=None, HR_full=None):
40
+ self.split_soc = True
41
+ self.HR_soc = HR_soc
42
+ if HR_nosoc is not None:
43
+ self.HR_nosoc = HR_nosoc
44
+ if HR_full is not None:
45
+ self.HR_nosoc = HR_full - HR_soc
46
+
47
+ def set_Hsoc_rotation_angle(self, angle):
48
+ """
49
+ Set the rotation angle for SOC part of Hamiltonian
50
+ """
51
+ self.soc_rotation_angle = angle
52
+
53
+ @property
54
+ def HR(self):
55
+ if self.split_soc:
56
+ _HR = np.zeros_like(self.HR_soc)
57
+ for iR, _ in enumerate(self.Rlist):
58
+ theta, phi = self.soc_rotation_angle
59
+ _HR[iR] = self.HR_nosoc[iR] + rotate_Matrix_from_z_to_spherical(
60
+ self.HR_soc[iR], theta, phi
61
+ )
62
+ return _HR
63
+ else:
64
+ return self._HR
65
+
66
+ @HR.setter
67
+ def set_HR(self, HR):
68
+ self._HR = HR
29
69
 
30
70
  def _build_Rdict(self):
31
71
  if hasattr(self, "Rdict"):
@@ -62,6 +102,8 @@ class AbacusWrapper(AbstractTB):
62
102
  S = self.SR[iR] * phase
63
103
  # Sk += S + S.conjugate().T
64
104
  Sk += S
105
+ # Hk = (Hk + Hk.conj().T)/2
106
+ # Sk = (Sk + Sk.conj().T)/2
65
107
  elif convention == 1:
66
108
  # TODO: implement the first convention (the r convention)
67
109
  raise NotImplementedError("convention 1 is not implemented yet.")
@@ -74,6 +116,14 @@ class AbacusWrapper(AbstractTB):
74
116
  Hk, Sk = self.gen_ham(k, convention=convention)
75
117
  return eigh(Hk, Sk)
76
118
 
119
+ def solve_all(self, kpts, convention=2):
120
+ nk = len(kpts)
121
+ evals = np.zeros((nk, self.nbasis), dtype=float)
122
+ evecs = np.zeros((nk, self.nbasis, self.nbasis), dtype=complex)
123
+ for ik, k in enumerate(kpts):
124
+ evals[ik], evecs[ik] = self.solve(k, convention=convention)
125
+ return evals, evecs
126
+
77
127
  def HSE_k(self, kpt, convention=2):
78
128
  H, S = self.gen_ham(tuple(kpt), convention=convention)
79
129
  evals, evecs = eigh(H, S)
@@ -196,6 +246,20 @@ class AbacusParser:
196
246
  raise ValueError(f"EFERMI not found in the {str(fname)} file.")
197
247
  return efermi
198
248
 
249
+ def read_nel(self):
250
+ """
251
+ Reading the number of electrons from the scf log file.
252
+ """
253
+ fname = str(Path(self.outpath) / "running_scf.log")
254
+ nel = None
255
+ with open(fname, "r") as myfile:
256
+ for line in myfile:
257
+ if "NELECT" in line:
258
+ nel = float(line.split()[2])
259
+ if nel is None:
260
+ raise ValueError(f"NELECT not found in the {str(fname)} file.")
261
+ return nel
262
+
199
263
  def get_basis(self):
200
264
  slist = symbol_number_list(self.atoms)
201
265
  if self.spin == "collinear":
@@ -213,6 +277,42 @@ class AbacusParser:
213
277
  return basis
214
278
 
215
279
 
280
+ class AbacusSplitSOCParser:
281
+ """
282
+ Abacus parser with Hamiltonian split to SOC and non-SOC parts
283
+ """
284
+
285
+ def __init__(self, outpath_nosoc=None, outpath_soc=None, binary=False):
286
+ self.outpath_nosoc = outpath_nosoc
287
+ self.outpath_soc = outpath_soc
288
+ self.binary = binary
289
+ self.parser_nosoc = AbacusParser(outpath=outpath_nosoc, binary=binary)
290
+ self.parser_soc = AbacusParser(outpath=outpath_soc, binary=binary)
291
+ spin1 = self.parser_nosoc.read_spin()
292
+ spin2 = self.parser_soc.read_spin()
293
+ if spin1 != "noncollinear" or spin2 != "noncollinear":
294
+ raise ValueError("Spin should be noncollinear")
295
+
296
+ def parse(self):
297
+ nbasis, Rlist, HR_nosoc, SR = self.parser_nosoc.Read_HSR_noncollinear()
298
+ nbasis2, Rlist2, HR2, SR2 = self.parser_soc.Read_HSR_noncollinear()
299
+ # print(HR[0])
300
+ HR_soc = HR2 - HR_nosoc
301
+ model = AbacusWrapper(
302
+ HR=None,
303
+ SR=SR,
304
+ Rlist=Rlist,
305
+ nbasis=nbasis,
306
+ nspin=2,
307
+ HR_soc=HR_soc,
308
+ HR_nosoc=HR_nosoc,
309
+ )
310
+ model.efermi = self.parser_soc.efermi
311
+ model.basis = self.parser_nosoc.basis
312
+ model.atoms = self.parser_nosoc.atoms
313
+ return model
314
+
315
+
216
316
  def test_abacus_wrapper_collinear():
217
317
  outpath = "/Users/hexu/projects/TB2J_abacus/abacus-tb2j-master/abacus_example/case_Fe/1_no_soc/OUT.Fe"
218
318
  parser = AbacusParser(outpath=outpath, spin=None, binary=False)
@@ -221,7 +321,6 @@ def test_abacus_wrapper_collinear():
221
321
  # parser.read_HSR_collinear()
222
322
  model_up, model_dn = parser.get_models()
223
323
  H, S, E, V = model_up.HSE_k([0, 0, 0])
224
- # print(H.shape)
225
324
  # print(H.diagonal().real)
226
325
  # print(model_up.get_HR0().diagonal().real)
227
326
  print(parser.efermi)