TB2J 0.9.1rc0__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.
- TB2J/Jdownfolder.py +110 -24
- TB2J/Jtensor.py +1 -1
- TB2J/MAE.py +185 -0
- TB2J/abacus/abacus_wrapper.py +84 -3
- TB2J/exchange.py +99 -73
- TB2J/exchangeCL2.py +10 -5
- TB2J/green.py +12 -2
- TB2J/manager.py +10 -4
- TB2J/mathutils/rotate_spin.py +21 -0
- TB2J/patch.py +50 -0
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/TB2J_downfold.py +8 -0
- {TB2J-0.9.1rc0.dist-info → TB2J-0.9.2rc0.dist-info}/METADATA +1 -1
- {TB2J-0.9.1rc0.dist-info → TB2J-0.9.2rc0.dist-info}/RECORD +25 -23
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/TB2J_eigen.py +0 -0
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/TB2J_magnon.py +0 -0
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/TB2J_magnon_dos.py +0 -0
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/TB2J_merge.py +0 -0
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/TB2J_rotate.py +0 -0
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/TB2J_rotateDM.py +0 -0
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/abacus2J.py +0 -0
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/siesta2J.py +0 -0
- {TB2J-0.9.1rc0.data → TB2J-0.9.2rc0.data}/scripts/wann2J.py +0 -0
- {TB2J-0.9.1rc0.dist-info → TB2J-0.9.2rc0.dist-info}/LICENSE +0 -0
- {TB2J-0.9.1rc0.dist-info → TB2J-0.9.2rc0.dist-info}/WHEEL +0 -0
- {TB2J-0.9.1rc0.dist-info → TB2J-0.9.2rc0.dist-info}/top_level.txt +0 -0
TB2J/Jdownfolder.py
CHANGED
@@ -17,9 +17,23 @@ def ind_to_indn(ind, n=3):
|
|
17
17
|
return indn
|
18
18
|
|
19
19
|
|
20
|
+
class JR_model:
|
21
|
+
def __init__(self, JR, Rlist):
|
22
|
+
self.JR = JR
|
23
|
+
self.Rlist = Rlist
|
24
|
+
self.nR = len(Rlist)
|
25
|
+
|
26
|
+
def get_Jq(self, q):
|
27
|
+
Jq = np.zeros(self.JR[0].shape, dtype=complex)
|
28
|
+
for iR, R in enumerate(self.Rlist):
|
29
|
+
phase = np.exp(2.0j * np.pi * np.dot(q, R))
|
30
|
+
Jq += self.JR[iR] * phase
|
31
|
+
return Jq
|
32
|
+
|
33
|
+
|
20
34
|
class JDownfolder:
|
21
35
|
def __init__(self, JR, Rlist, iM, iL, qmesh, iso_only=False):
|
22
|
-
self.
|
36
|
+
self.model = JR_model(JR, Rlist)
|
23
37
|
self.Rlist = Rlist
|
24
38
|
self.nR = len(Rlist)
|
25
39
|
self.nM = len(iM)
|
@@ -34,25 +48,18 @@ class JDownfolder:
|
|
34
48
|
self.nLn = self.nL * 3
|
35
49
|
self.iso_only = iso_only
|
36
50
|
|
37
|
-
def get_Jq(self, q):
|
38
|
-
Jq = np.zeros(self.JR[0].shape, dtype=complex)
|
39
|
-
for iR, R in enumerate(self.Rlist):
|
40
|
-
phase = np.exp(2.0j * np.pi * np.dot(q, R))
|
41
|
-
Jq += self.JR[iR] * phase
|
42
|
-
return Jq
|
43
|
-
|
44
51
|
def get_JR(self):
|
45
52
|
JR_downfolded = np.zeros((self.nR, self.nMn, self.nMn), dtype=float)
|
46
53
|
Jq_downfolded = np.zeros((self.nqpt, self.nMn, self.nMn), dtype=complex)
|
47
54
|
self.iMn = ind_to_indn(self.iM, n=3)
|
48
55
|
self.iLn = ind_to_indn(self.iL, n=3)
|
49
56
|
for iq, q in enumerate(self.qpts):
|
50
|
-
Jq = self.get_Jq(q)
|
57
|
+
Jq = self.model.get_Jq(q)
|
51
58
|
Jq_downfolded[iq] = self.downfold_oneq(Jq)
|
52
59
|
for iR, R in enumerate(self.Rlist):
|
53
60
|
phase = np.exp(-2.0j * np.pi * np.dot(q, R))
|
54
61
|
JR_downfolded[iR] += np.real(Jq_downfolded[iq] * phase / self.nqpt)
|
55
|
-
return JR_downfolded
|
62
|
+
return JR_downfolded, self.Rlist
|
56
63
|
|
57
64
|
def downfold_oneq(self, J):
|
58
65
|
JMM = J[np.ix_(self.iMn, self.iMn)]
|
@@ -63,17 +70,80 @@ class JDownfolder:
|
|
63
70
|
return Jn
|
64
71
|
|
65
72
|
|
73
|
+
class PWFDownfolder:
|
74
|
+
def __init__(self, JR, Rlist, iM, iL, qmesh, atoms=None, iso_only=False, **kwargs):
|
75
|
+
from lawaf.interfaces.magnon.magnon_downfolder import (
|
76
|
+
MagnonWrapper,
|
77
|
+
MagnonDownfolder,
|
78
|
+
)
|
79
|
+
|
80
|
+
model = MagnonWrapper(JR, Rlist, atoms)
|
81
|
+
wann = MagnonDownfolder(model)
|
82
|
+
# Downfold the band structure.
|
83
|
+
index_basis = []
|
84
|
+
for i in iM:
|
85
|
+
index_basis += list(range(i * 3, i * 3 + 3))
|
86
|
+
params = dict(
|
87
|
+
method="projected",
|
88
|
+
# method="maxprojected",
|
89
|
+
kmesh=qmesh,
|
90
|
+
nwann=len(index_basis),
|
91
|
+
selected_basis=index_basis,
|
92
|
+
# anchors={(0, 0, 0): (-1, -2, -3, -4)},
|
93
|
+
# anchors={(0, 0, 0): ()},
|
94
|
+
# use_proj=True,
|
95
|
+
enhance_Amn=2.0,
|
96
|
+
)
|
97
|
+
params.update(kwargs)
|
98
|
+
wann.set_parameters(**params)
|
99
|
+
print("begin downfold")
|
100
|
+
ewf = wann.downfold()
|
101
|
+
ewf.save_hr_pickle("downfolded_JR.pickle")
|
102
|
+
|
103
|
+
# Plot the band structure.
|
104
|
+
wann.plot_band_fitting(
|
105
|
+
# kvectors=np.array([[0, 0, 0], [0.5, 0, 0],
|
106
|
+
# [0.5, 0.5, 0], [0, 0, 0],
|
107
|
+
# [.5, .5, .5]]),
|
108
|
+
# knames=['$\Gamma$', 'X', 'M', '$\Gamma$', 'R'],
|
109
|
+
cell=model.atoms.cell,
|
110
|
+
supercell_matrix=None,
|
111
|
+
npoints=100,
|
112
|
+
efermi=None,
|
113
|
+
erange=None,
|
114
|
+
fullband_color="blue",
|
115
|
+
downfolded_band_color="green",
|
116
|
+
marker="o",
|
117
|
+
ax=None,
|
118
|
+
savefig="downfold_band.png",
|
119
|
+
show=True,
|
120
|
+
)
|
121
|
+
self.JR_downfolded = ewf.HwannR
|
122
|
+
self.Rlist = ewf.Rlist
|
123
|
+
|
124
|
+
def get_JR(self):
|
125
|
+
return self.JR_downfolded, self.Rlist
|
126
|
+
|
127
|
+
|
66
128
|
class JDownfolder_pickle:
|
67
129
|
def __init__(
|
68
|
-
self,
|
130
|
+
self,
|
131
|
+
inpath,
|
132
|
+
metals,
|
133
|
+
ligands,
|
134
|
+
outpath,
|
135
|
+
qmesh=[7, 7, 7],
|
136
|
+
iso_only=False,
|
137
|
+
method="pwf",
|
138
|
+
**kwargs
|
69
139
|
):
|
70
140
|
self.exc = SpinIO.load_pickle(path=inpath, fname="TB2J.pickle")
|
71
141
|
|
72
142
|
self.iso_only = (self.exc.dmi_ddict is None) or iso_only
|
73
|
-
|
74
143
|
self.metals = metals
|
75
144
|
self.ligands = ligands
|
76
145
|
self.outpath = outpath
|
146
|
+
self.method = method
|
77
147
|
|
78
148
|
# read atomic structure
|
79
149
|
self.atoms = self.exc.atoms
|
@@ -83,7 +153,8 @@ class JDownfolder_pickle:
|
|
83
153
|
self.Rcut = None
|
84
154
|
self._build_atom_index()
|
85
155
|
self._prepare_distance()
|
86
|
-
self._downfold()
|
156
|
+
Jd, Rlist = self._downfold(**kwargs)
|
157
|
+
self._Jd_to_exchange(Jd, Rlist)
|
87
158
|
|
88
159
|
def _build_atom_index(self):
|
89
160
|
self.magnetic_elements = self.metals
|
@@ -101,18 +172,33 @@ class JDownfolder_pickle:
|
|
101
172
|
self.nL = len(self.iL)
|
102
173
|
self.nsite = self.nM + self.nL
|
103
174
|
|
104
|
-
def _downfold(self):
|
175
|
+
def _downfold(self, **kwargs):
|
105
176
|
JR2 = self.exc.get_full_Jtensor_for_Rlist(asr=True)
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
177
|
+
if self.method == "lowdin":
|
178
|
+
d = JDownfolder(
|
179
|
+
JR2,
|
180
|
+
self.exc.Rlist,
|
181
|
+
iM=self.iM,
|
182
|
+
iL=self.iL,
|
183
|
+
qmesh=self.qmesh,
|
184
|
+
iso_only=self.iso_only,
|
185
|
+
)
|
186
|
+
Jd, Rlist = d.get_JR()
|
187
|
+
else:
|
188
|
+
d = PWFDownfolder(
|
189
|
+
JR2,
|
190
|
+
self.exc.Rlist,
|
191
|
+
iM=self.iM,
|
192
|
+
iL=self.iL,
|
193
|
+
qmesh=self.qmesh,
|
194
|
+
atoms=self.atoms,
|
195
|
+
iso_only=self.iso_only,
|
196
|
+
**kwargs
|
197
|
+
)
|
198
|
+
Jd, Rlist = d.get_JR()
|
199
|
+
return Jd, Rlist
|
115
200
|
|
201
|
+
def _Jd_to_exchange(self, Jd, Rlist):
|
116
202
|
self._prepare_distance()
|
117
203
|
self._prepare_index_spin()
|
118
204
|
self.Jdict = {}
|
@@ -123,7 +209,7 @@ class JDownfolder_pickle:
|
|
123
209
|
self.DMIdict = {}
|
124
210
|
self.Janidict = {}
|
125
211
|
|
126
|
-
for iR, R in enumerate(
|
212
|
+
for iR, R in enumerate(Rlist):
|
127
213
|
for i, ispin in enumerate(self.index_spin):
|
128
214
|
for j, jspin in enumerate(self.index_spin):
|
129
215
|
if ispin >= 0 and jspin >= 0:
|
TB2J/Jtensor.py
CHANGED
@@ -79,7 +79,7 @@ def combine_J_tensor(Jiso=0.0, D=np.zeros(3), Jani=np.zeros((3, 3), dtype=float)
|
|
79
79
|
:param Jani: 3x3 matrix anisotropic exchange
|
80
80
|
:returns: A 3x3 matrix, the exchange paraemter in tensor form.
|
81
81
|
"""
|
82
|
-
Jtensor = np.zeros((3, 3), dtype=
|
82
|
+
Jtensor = np.zeros((3, 3), dtype=complex)
|
83
83
|
if Jiso is not None:
|
84
84
|
Jtensor += np.eye(3, dtype=float) * Jiso
|
85
85
|
if Jani is not None:
|
TB2J/MAE.py
ADDED
@@ -0,0 +1,185 @@
|
|
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.mathutils.rotate_spin import spherical_to_cartesian
|
13
|
+
from HamiltonIO.occupations import Occupations
|
14
|
+
from TB2J.abacus.abacus_wrapper import AbacusSplitSOCParser
|
15
|
+
from HamiltonIO.siesta import SislWrapper
|
16
|
+
import tqdm
|
17
|
+
|
18
|
+
|
19
|
+
def get_occupation(evals, kweights, nel, width=0.1):
|
20
|
+
occ = Occupations(nel=nel, width=width, wk=kweights, nspin=2)
|
21
|
+
return occ.occupy(evals)
|
22
|
+
|
23
|
+
|
24
|
+
def get_density_matrix(evals=None, evecs=None, kweights=None, nel=None, width=0.1):
|
25
|
+
occ = get_occupation(evals, kweights, nel, width=width)
|
26
|
+
rho = np.einsum("kib, kb, kjb -> kij", evecs, occ, evecs.conj())
|
27
|
+
return rho
|
28
|
+
|
29
|
+
|
30
|
+
class MAE:
|
31
|
+
def __init__(self, model, kmesh, gamma=True, width=0.1, nel=None):
|
32
|
+
self.model = model
|
33
|
+
if nel is not None:
|
34
|
+
self.model.nel = nel
|
35
|
+
self.kpts = monkhorst_pack(kmesh, gamma_center=gamma)
|
36
|
+
self.kweights = np.ones(len(self.kpts), dtype=float) / len(self.kpts)
|
37
|
+
self.width = width
|
38
|
+
|
39
|
+
def get_band_energy(self):
|
40
|
+
evals, evecs = self.model.solve_all(self.kpts)
|
41
|
+
occ = get_occupation(evals, self.kweights, self.model.nel, width=self.width)
|
42
|
+
eband = np.sum(evals * occ * self.kweights[:, np.newaxis])
|
43
|
+
return eband
|
44
|
+
|
45
|
+
def calc_ref(self):
|
46
|
+
# calculate the Hk_ref, Sk_ref, Hk_soc_ref, and rho_ref
|
47
|
+
self.Sk_ref = R_to_k(self.kpts, self.model.Rlist, self.model.SR)
|
48
|
+
self.Hk_xc_ref = R_to_k(self.kpts, self.model.Rlist, self.model._HR_copy)
|
49
|
+
self.Hk_soc_ref = R_to_k(self.kpts, self.model.Rlist, self.model.HR_soc)
|
50
|
+
self.rho_ref = np.zeros(
|
51
|
+
(len(self.kpts), self.model.nbasis, self.model.nbasis), dtype=complex
|
52
|
+
)
|
53
|
+
|
54
|
+
evals = np.zeros((len(self.kpts), self.model.nbasis), dtype=float)
|
55
|
+
evecs = np.zeros(
|
56
|
+
(len(self.kpts), self.model.nbasis, self.model.nbasis), dtype=complex
|
57
|
+
)
|
58
|
+
|
59
|
+
for ik, kpt in enumerate(self.kpts):
|
60
|
+
# evals, evecs = eigh(self.Hk_xc_ref[ik]+self.Hk_soc_ref[ik], self.Sk_ref[ik])
|
61
|
+
evals[ik], evecs[ik] = eigh(self.Hk_xc_ref[ik], self.Sk_ref[ik])
|
62
|
+
occ = get_occupation(
|
63
|
+
evals, self.kweights, self.model.nel, width=self.model.width
|
64
|
+
)
|
65
|
+
# occ = fermi(evals, self.model.efermi, width=self.model.width)
|
66
|
+
self.rho_ref = np.einsum("kib, kb, kjb -> kij", evecs, occ, evecs.conj())
|
67
|
+
|
68
|
+
def get_band_energy_vs_angles(
|
69
|
+
self,
|
70
|
+
thetas,
|
71
|
+
phis,
|
72
|
+
):
|
73
|
+
es = []
|
74
|
+
# es2 = []
|
75
|
+
# e,rho = self.model.get_band_energy(dm=True)
|
76
|
+
# self.calc_ref()
|
77
|
+
# thetas = np.linspace(*angle_range, npoints)
|
78
|
+
for i, (theta, phi) in tqdm.tqdm(enumerate(zip(thetas, phis))):
|
79
|
+
self.model.set_Hsoc_rotation_angle([theta, phi])
|
80
|
+
e = self.get_band_energy()
|
81
|
+
es.append(e)
|
82
|
+
# es2.append(e2)
|
83
|
+
return es
|
84
|
+
|
85
|
+
|
86
|
+
def get_model_energy(model, kmesh, gamma=True):
|
87
|
+
ham = MAE(model, kmesh, gamma=gamma)
|
88
|
+
return ham.get_band_energy()
|
89
|
+
|
90
|
+
|
91
|
+
def abacus_get_MAE(
|
92
|
+
path_nosoc, path_soc, kmesh, thetas, psis, gamma=True, outfile="MAE.txt", nel=None
|
93
|
+
):
|
94
|
+
"""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."""
|
95
|
+
parser = AbacusSplitSOCParser(
|
96
|
+
outpath_nosoc=path_nosoc, outpath_soc=path_soc, binary=False
|
97
|
+
)
|
98
|
+
model = parser.parse()
|
99
|
+
model.nel = 16
|
100
|
+
ham = MAE(model, kmesh, gamma=gamma)
|
101
|
+
es = ham.get_band_energy_vs_angles(thetas, psis)
|
102
|
+
if outfile:
|
103
|
+
with open(outfile, "w") as f:
|
104
|
+
f.write("#theta, psi, energy\n")
|
105
|
+
for theta, psi, e in zip(thetas, psis, es):
|
106
|
+
f.write(f"{theta}, {psi}, {e}\n")
|
107
|
+
return es
|
108
|
+
|
109
|
+
|
110
|
+
def siesta_get_MAE(fdf_fname, kmesh, thetas, phis, gamma=True, outfile="MAE.txt"):
|
111
|
+
""" """
|
112
|
+
parser = SiestaParser(fdf_fname=fdf_fname, read_H_soc=True)
|
113
|
+
model = parser.parse()
|
114
|
+
ham = MAE(model, kmesh, gamma=gamma)
|
115
|
+
es = ham.get_band_energy_vs_angles(thetas, phis)
|
116
|
+
if outfile:
|
117
|
+
with open(outfile, "w") as f:
|
118
|
+
f.write("#theta, psi, energy\n")
|
119
|
+
for theta, psi, e in zip(thetas, phis, es):
|
120
|
+
f.write(f"{theta}, {psi}, {e}\n")
|
121
|
+
return es
|
122
|
+
|
123
|
+
|
124
|
+
def test_AbacusSplitSOCWrapper():
|
125
|
+
# path = Path("~/projects/2D_Fe").expanduser()
|
126
|
+
path = Path("~/projects/TB2Jflows/examples/2D_Fe/Fe_z").expanduser()
|
127
|
+
outpath_nosoc = f"{path}/soc0/OUT.ABACUS"
|
128
|
+
outpath_soc = f"{path}/soc1/OUT.ABACUS"
|
129
|
+
parser = AbacusSplitSOCParser(
|
130
|
+
outpath_nosoc=outpath_nosoc, outpath_soc=outpath_soc, binary=False
|
131
|
+
)
|
132
|
+
model = parser.parse()
|
133
|
+
kmesh = [6, 6, 1]
|
134
|
+
|
135
|
+
r = MAE(model, kmesh, gamma=True)
|
136
|
+
# thetas, es = r.get_band_energy_vs_theta(angle_range=(0, np.pi*2), rotation_axis="z", initial_direction=(1,0,0), npoints=21)
|
137
|
+
thetas, es, es2 = r.get_band_energy_vs_theta(
|
138
|
+
angle_range=(0, np.pi),
|
139
|
+
rotation_axis="y",
|
140
|
+
initial_direction=(0, 0, 1),
|
141
|
+
npoints=11,
|
142
|
+
)
|
143
|
+
# print the table of thetas and es, es2
|
144
|
+
for theta, e, e2 in zip(thetas, es, es2):
|
145
|
+
print(f"{theta=}, {e=}, {e2=}")
|
146
|
+
|
147
|
+
plt.plot(thetas / np.pi, es - es[0], marker="o")
|
148
|
+
plt.plot(thetas / np.pi, es2 - es2[0], marker=".")
|
149
|
+
plt.savefig("E_along_z_x_z.png")
|
150
|
+
plt.show()
|
151
|
+
|
152
|
+
|
153
|
+
def abacus_get_MAE_cli():
|
154
|
+
import argparse
|
155
|
+
|
156
|
+
parser = argparse.ArgumentParser(
|
157
|
+
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. "
|
158
|
+
)
|
159
|
+
parser.add_argument("path_nosoc", type=str, help="Path to the calculation with ")
|
160
|
+
parser.add_argument("path_soc", type=str, help="Path to the SOC calculation")
|
161
|
+
parser.add_argument("thetas", type=float, nargs="+", help="Thetas")
|
162
|
+
parser.add_argument("psis", type=float, nargs="+", help="Phis")
|
163
|
+
parser.add_argument("kmesh", type=int, nargs=3, help="K-mesh")
|
164
|
+
parser.add_argument(
|
165
|
+
"--gamma", action="store_true", help="Use Gamma centered kpoints"
|
166
|
+
)
|
167
|
+
parser.add_argument(
|
168
|
+
"--outfile",
|
169
|
+
type=str,
|
170
|
+
help="The angles and the energey will be saved in this file.",
|
171
|
+
)
|
172
|
+
args = parser.parse_args()
|
173
|
+
abacus_get_MAE(
|
174
|
+
args.path_nosoc,
|
175
|
+
args.path_soc,
|
176
|
+
args.kmesh,
|
177
|
+
args.thetas,
|
178
|
+
args.psis,
|
179
|
+
gamma=args.gamma,
|
180
|
+
outfile=args.outfile,
|
181
|
+
)
|
182
|
+
|
183
|
+
|
184
|
+
if __name__ == "__main__":
|
185
|
+
abacus_get_MAE_cli()
|
TB2J/abacus/abacus_wrapper.py
CHANGED
@@ -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,9 +17,12 @@ from TB2J.abacus.stru_api import read_abacus, read_abacus_out
|
|
15
17
|
|
16
18
|
|
17
19
|
class AbacusWrapper(AbstractTB):
|
18
|
-
def __init__(
|
20
|
+
def __init__(
|
21
|
+
self, HR, SR, Rlist, nbasis, nspin=1, HR_soc=None, HR_nosoc=None, nel=None
|
22
|
+
):
|
19
23
|
self.R2kfactor = 2j * np.pi
|
20
24
|
self.is_orthogonal = False
|
25
|
+
self.split_soc = False
|
21
26
|
self._name = "ABACUS"
|
22
27
|
self._HR = HR
|
23
28
|
self.SR = SR
|
@@ -25,11 +30,38 @@ class AbacusWrapper(AbstractTB):
|
|
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
|
29
52
|
|
30
53
|
@property
|
31
54
|
def HR(self):
|
32
|
-
|
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
|
33
65
|
|
34
66
|
@HR.setter
|
35
67
|
def set_HR(self, HR):
|
@@ -214,6 +246,20 @@ class AbacusParser:
|
|
214
246
|
raise ValueError(f"EFERMI not found in the {str(fname)} file.")
|
215
247
|
return efermi
|
216
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
|
+
|
217
263
|
def get_basis(self):
|
218
264
|
slist = symbol_number_list(self.atoms)
|
219
265
|
if self.spin == "collinear":
|
@@ -231,6 +277,42 @@ class AbacusParser:
|
|
231
277
|
return basis
|
232
278
|
|
233
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
|
+
|
234
316
|
def test_abacus_wrapper_collinear():
|
235
317
|
outpath = "/Users/hexu/projects/TB2J_abacus/abacus-tb2j-master/abacus_example/case_Fe/1_no_soc/OUT.Fe"
|
236
318
|
parser = AbacusParser(outpath=outpath, spin=None, binary=False)
|
@@ -239,7 +321,6 @@ def test_abacus_wrapper_collinear():
|
|
239
321
|
# parser.read_HSR_collinear()
|
240
322
|
model_up, model_dn = parser.get_models()
|
241
323
|
H, S, E, V = model_up.HSE_k([0, 0, 0])
|
242
|
-
# print(H.shape)
|
243
324
|
# print(H.diagonal().real)
|
244
325
|
# print(model_up.get_HR0().diagonal().real)
|
245
326
|
print(parser.efermi)
|
TB2J/exchange.py
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
from collections import defaultdict, OrderedDict
|
2
2
|
import os
|
3
3
|
import numpy as np
|
4
|
+
import pickle
|
5
|
+
from dataclasses import dataclass
|
6
|
+
import yaml
|
4
7
|
from TB2J.green import TBGreen
|
5
8
|
from TB2J.pauli import pauli_block_all, pauli_block_sigma_norm, pauli_mat
|
6
9
|
from TB2J.utils import symbol_number, kmesh_to_R
|
@@ -10,25 +13,47 @@ from TB2J.external import p_map
|
|
10
13
|
from TB2J.contour import Contour
|
11
14
|
from TB2J.utils import simpson_nonuniform, trapezoidal_nonuniform, split_symbol_number
|
12
15
|
from TB2J.orbmap import map_orbs_matrix
|
13
|
-
import
|
16
|
+
from typing import List, Tuple
|
14
17
|
|
15
18
|
|
19
|
+
@dataclass
|
16
20
|
class ExchangeParams:
|
21
|
+
"""
|
22
|
+
A class to store the parameters for exchange calculation.
|
23
|
+
"""
|
24
|
+
|
25
|
+
efermi: float
|
26
|
+
basis: list = None
|
27
|
+
magnetic_elements: list = None
|
28
|
+
include_orbs = {}
|
29
|
+
_kmesh = [4, 4, 4]
|
30
|
+
emin: float = -15
|
31
|
+
emax: float = 0.05
|
32
|
+
nz: int = 100
|
33
|
+
exclude_orbs = []
|
34
|
+
ne: int = None
|
35
|
+
Rcut: float = None
|
36
|
+
_use_cache: bool = False
|
37
|
+
np: int = 1
|
38
|
+
description: str = ""
|
39
|
+
write_density_matrix: bool = False
|
40
|
+
orb_decomposition: bool = False
|
41
|
+
output_path: str = "TB2J_results"
|
42
|
+
mae_angles = None
|
43
|
+
|
17
44
|
def __init__(
|
18
45
|
self,
|
19
|
-
efermi,
|
46
|
+
efermi=-10.0,
|
20
47
|
basis=None,
|
21
|
-
magnetic_elements=
|
22
|
-
include_orbs=
|
48
|
+
magnetic_elements=None,
|
49
|
+
include_orbs=None,
|
23
50
|
kmesh=[4, 4, 4],
|
24
|
-
emin=-15,
|
25
|
-
# integration upper bound. Should be 0 (fermi energy). But DFT codes define Fermi energy in various ways.
|
51
|
+
emin=-15,
|
26
52
|
emax=0.05,
|
27
53
|
nz=100,
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
Rcut=None, # Rcut.
|
54
|
+
exclude_orbs=[],
|
55
|
+
ne=None,
|
56
|
+
Rcut=None,
|
32
57
|
use_cache=False,
|
33
58
|
np=1,
|
34
59
|
description="",
|
@@ -37,70 +62,41 @@ class ExchangeParams:
|
|
37
62
|
output_path="TB2J_results",
|
38
63
|
):
|
39
64
|
self.efermi = efermi
|
40
|
-
self.emin = emin
|
41
|
-
self.emax = emax
|
42
|
-
self.nz = nz
|
43
|
-
self.Rcut = Rcut
|
44
65
|
self.basis = basis
|
45
66
|
self.magnetic_elements = magnetic_elements
|
46
67
|
self.include_orbs = include_orbs
|
47
|
-
|
68
|
+
self._kmesh = kmesh
|
69
|
+
self.emin = emin
|
70
|
+
self.emax = emax
|
71
|
+
self.nz = nz
|
48
72
|
self.exclude_orbs = exclude_orbs
|
49
73
|
self.ne = ne
|
74
|
+
self.Rcut = Rcut
|
50
75
|
self._use_cache = use_cache
|
51
76
|
self.np = np
|
52
|
-
self._kmesh = kmesh
|
53
|
-
self.orb_decomposition = orb_decomposition
|
54
|
-
self.write_density_matrix = write_density_matrix
|
55
77
|
self.description = description
|
78
|
+
self.write_density_matrix = write_density_matrix
|
79
|
+
self.orb_decomposition = orb_decomposition
|
56
80
|
self.output_path = output_path
|
57
81
|
|
82
|
+
def set_params(self, **kwargs):
|
83
|
+
for key, val in kwargs.items():
|
84
|
+
setattr(self, key, val)
|
85
|
+
|
86
|
+
def save_to_yaml(self, fname):
|
87
|
+
with open(fname, "w") as myfile:
|
88
|
+
yaml.dump(self.__dict__, myfile)
|
89
|
+
|
58
90
|
|
59
91
|
class Exchange(ExchangeParams):
|
60
92
|
def __init__(
|
61
93
|
self,
|
62
94
|
tbmodels,
|
63
95
|
atoms,
|
64
|
-
|
65
|
-
basis=None,
|
66
|
-
magnetic_elements=[],
|
67
|
-
include_orbs={},
|
68
|
-
kmesh=[4, 4, 4],
|
69
|
-
emin=-15, # integration lower bound, relative to fermi energy
|
70
|
-
# integration upper bound. Should be 0 (fermi energy). But DFT codes define Fermi energy in various ways.
|
71
|
-
emax=0.05,
|
72
|
-
nz=100,
|
73
|
-
# the delta in the (i delta) in green's function to prevent divergence
|
74
|
-
exclude_orbs=[], #
|
75
|
-
ne=None, # number of electrons in Wannier function.
|
76
|
-
Rcut=None, # Rcut.
|
77
|
-
use_cache=False,
|
78
|
-
np=1,
|
79
|
-
description="",
|
80
|
-
write_density_matrix=False,
|
81
|
-
output_path="TB2J_results",
|
82
|
-
orb_decomposition=False,
|
96
|
+
**params: ExchangeParams,
|
83
97
|
):
|
84
98
|
self.atoms = atoms
|
85
|
-
super().__init__(
|
86
|
-
efermi=efermi,
|
87
|
-
basis=basis,
|
88
|
-
magnetic_elements=magnetic_elements,
|
89
|
-
include_orbs=include_orbs,
|
90
|
-
kmesh=kmesh,
|
91
|
-
emin=emin,
|
92
|
-
emax=emax,
|
93
|
-
nz=nz,
|
94
|
-
exclude_orbs=exclude_orbs,
|
95
|
-
ne=ne,
|
96
|
-
Rcut=Rcut,
|
97
|
-
use_cache=use_cache,
|
98
|
-
np=np,
|
99
|
-
description=description,
|
100
|
-
write_density_matrix=write_density_matrix,
|
101
|
-
orb_decomposition=orb_decomposition,
|
102
|
-
output_path=output_path,
|
103
|
-
)
|
99
|
+
super().__init__(**params)
|
104
100
|
self._prepare_kmesh(self._kmesh)
|
105
101
|
self._prepare_Rlist()
|
106
102
|
self.set_tbmodels(tbmodels)
|
@@ -334,7 +330,6 @@ class ExchangeNCL(Exchange):
|
|
334
330
|
"""
|
335
331
|
self.tbmodel = tbmodels
|
336
332
|
self.backend_name = self.tbmodel.name
|
337
|
-
# TODO: check if tbmodels are really a tbmodel with SOC.
|
338
333
|
self.G = TBGreen(
|
339
334
|
self.tbmodel,
|
340
335
|
self.kmesh,
|
@@ -355,6 +350,12 @@ class ExchangeNCL(Exchange):
|
|
355
350
|
if self.write_density_matrix:
|
356
351
|
self.G.write_rho_R()
|
357
352
|
|
353
|
+
def get_MAE(self, thetas, phis):
|
354
|
+
"""
|
355
|
+
Calculate the magnetic anisotropy energy.
|
356
|
+
"""
|
357
|
+
pass
|
358
|
+
|
358
359
|
def _prepare_NijR(self):
|
359
360
|
self.N = {}
|
360
361
|
for R in self.Rlist:
|
@@ -615,7 +616,7 @@ class ExchangeNCL(Exchange):
|
|
615
616
|
def calculate_DMI_NJT(self):
|
616
617
|
"""
|
617
618
|
calculate exchange and DMI with the
|
618
|
-
|
619
|
+
This did not work and should be removed.
|
619
620
|
"""
|
620
621
|
Ddict_NJT = {}
|
621
622
|
Jdict_NJT = {}
|
@@ -679,10 +680,36 @@ class ExchangeNCL(Exchange):
|
|
679
680
|
self.contour.path, AijRs_orb[(R, iatom, jatom)]
|
680
681
|
)
|
681
682
|
|
682
|
-
def
|
683
|
-
|
683
|
+
def get_quantities_per_e(self, e):
|
684
|
+
Gk_all = self.G.get_Gk_all(e)
|
685
|
+
mae = self.get_mae_kspace(Gk_all)
|
686
|
+
# TODO: get the MAE from Gk_all
|
687
|
+
GR = self.G.get_GR(self.short_Rlist, energy=e, get_rho=False, Gk_all=Gk_all)
|
688
|
+
# TODO: define the quantities for one energy.
|
684
689
|
AijR, AijR_orb = self.get_all_A(GR)
|
685
|
-
return AijR, AijR_orb
|
690
|
+
return dict(AijR=AijR, AijR_orb=AijR_orb, mae=mae)
|
691
|
+
|
692
|
+
def get_mae_kspace(self, Gk_all):
|
693
|
+
"""
|
694
|
+
get the MAE from Gk_all
|
695
|
+
TODO: This is only a place holder.
|
696
|
+
"""
|
697
|
+
return None
|
698
|
+
Hso_k = self.model.get_Hso_k(k)
|
699
|
+
mae_e = np.zeros(len(self.mae_angles), dtype=complex)
|
700
|
+
# rotate the Hso_k to angles
|
701
|
+
for ik, k in enumerate(self.G.kpoints):
|
702
|
+
Gk = Gk_all[ik]
|
703
|
+
for i_angle, angle in enumerate(self.mae_angles):
|
704
|
+
# TODO: implementa rotate_H
|
705
|
+
Hso_k_rot = rotate_H(Hso_k, angle)
|
706
|
+
mae_e[i_angle] = Gk @ Hso_k @ Gk @ Hso_k
|
707
|
+
return mae_e
|
708
|
+
|
709
|
+
def get_mae_rspace(self, GR):
|
710
|
+
"""
|
711
|
+
get the MAE from GR
|
712
|
+
"""
|
686
713
|
|
687
714
|
def save_AijR(self, AijRs, fname):
|
688
715
|
result = dict(path=self.contour.path, AijRs=AijRs)
|
@@ -693,6 +720,7 @@ class ExchangeNCL(Exchange):
|
|
693
720
|
"""
|
694
721
|
Do some sanity check before proceding.
|
695
722
|
"""
|
723
|
+
pass
|
696
724
|
|
697
725
|
def calculate_all(self):
|
698
726
|
"""
|
@@ -701,40 +729,38 @@ class ExchangeNCL(Exchange):
|
|
701
729
|
print("Green's function Calculation started.")
|
702
730
|
|
703
731
|
AijRs = {}
|
704
|
-
|
705
732
|
AijRs_orb = {}
|
706
733
|
|
707
734
|
self.validate()
|
708
735
|
|
709
736
|
npole = len(self.contour.path)
|
710
737
|
if self.np > 1:
|
711
|
-
results = p_map(
|
738
|
+
results = p_map(
|
739
|
+
self.get_quantities_per_e, self.contour.path, num_cpus=self.np
|
740
|
+
)
|
712
741
|
else:
|
713
|
-
results = map(
|
742
|
+
results = map(
|
743
|
+
self.get_quantities_per_e, tqdm(self.contour.path, total=npole)
|
744
|
+
)
|
714
745
|
|
715
746
|
for i, result in enumerate(results):
|
716
747
|
for iR, R in enumerate(self.R_ijatom_dict):
|
717
748
|
for iatom, jatom in self.R_ijatom_dict[R]:
|
718
749
|
if (R, iatom, jatom) in AijRs:
|
719
|
-
AijRs[(R, iatom, jatom)].append(result[
|
750
|
+
AijRs[(R, iatom, jatom)].append(result["AijR"][R, iatom, jatom])
|
720
751
|
if self.orb_decomposition:
|
721
752
|
AijRs_orb[(R, iatom, jatom)].append(
|
722
|
-
result[
|
753
|
+
result["AijR_orb"][R, iatom, jatom]
|
723
754
|
)
|
724
755
|
|
725
756
|
else:
|
726
757
|
AijRs[(R, iatom, jatom)] = []
|
727
|
-
AijRs[(R, iatom, jatom)].append(result[
|
758
|
+
AijRs[(R, iatom, jatom)].append(result["AijR"][R, iatom, jatom])
|
728
759
|
if self.orb_decomposition:
|
729
760
|
AijRs_orb[(R, iatom, jatom)] = []
|
730
761
|
AijRs_orb[(R, iatom, jatom)].append(
|
731
|
-
result[
|
762
|
+
result["AijR_orb"][R, iatom, jatom]
|
732
763
|
)
|
733
|
-
if self.np > 1:
|
734
|
-
# executor.close()
|
735
|
-
# executor.join()
|
736
|
-
# executor.clear()
|
737
|
-
pass
|
738
764
|
|
739
765
|
# self.save_AijRs(AijRs)
|
740
766
|
self.integrate(AijRs, AijRs_orb)
|
TB2J/exchangeCL2.py
CHANGED
@@ -234,11 +234,11 @@ class ExchangeCL2(ExchangeCL):
|
|
234
234
|
self.contour.path, self.JJ_list[(R, iatom, jatom)]
|
235
235
|
)
|
236
236
|
|
237
|
-
def
|
237
|
+
def get_quantities_per_e(self, e):
|
238
238
|
GR_up = self.Gup.get_GR(self.short_Rlist, energy=e, get_rho=False)
|
239
239
|
GR_dn = self.Gdn.get_GR(self.short_Rlist, energy=e, get_rho=False)
|
240
240
|
Jorb_list, JJ_list = self.get_all_A(GR_up, GR_dn)
|
241
|
-
return Jorb_list, JJ_list
|
241
|
+
return dict(Jorb_list=Jorb_list, JJ_list=JJ_list)
|
242
242
|
|
243
243
|
def calculate_all(self):
|
244
244
|
"""
|
@@ -248,13 +248,18 @@ class ExchangeCL2(ExchangeCL):
|
|
248
248
|
|
249
249
|
npole = len(self.contour.path)
|
250
250
|
if self.np == 1:
|
251
|
-
results = map(
|
251
|
+
results = map(
|
252
|
+
self.get_quantities_per_e, tqdm(self.contour.path, total=npole)
|
253
|
+
)
|
252
254
|
else:
|
253
255
|
# pool = ProcessPool(nodes=self.np)
|
254
256
|
# results = pool.map(self.get_AijR_rhoR ,self.contour.path)
|
255
|
-
results = p_map(
|
257
|
+
results = p_map(
|
258
|
+
self.get_quantities_per_e, self.contour.path, num_cpus=self.np
|
259
|
+
)
|
256
260
|
for i, result in enumerate(results):
|
257
|
-
Jorb_list
|
261
|
+
Jorb_list = result["Jorb_list"]
|
262
|
+
JJ_list = result["JJ_list"]
|
258
263
|
for iR, R in enumerate(self.R_ijatom_dict):
|
259
264
|
for iatom, jatom in self.R_ijatom_dict[R]:
|
260
265
|
key = (R, iatom, jatom)
|
TB2J/green.py
CHANGED
@@ -270,7 +270,14 @@ class TBGreen:
|
|
270
270
|
# Gk = np.linalg.inv((energy+self.efermi)*self.S[ik,:,:] - self.H[ik,:,:])
|
271
271
|
return Gk
|
272
272
|
|
273
|
-
def
|
273
|
+
def get_Gk_all(self, energy):
|
274
|
+
"""Green's function G(k) for one energy for all kpoints"""
|
275
|
+
Gk_all = np.zeros((self.nkpts, self.nbasis, self.nbasis), dtype=complex)
|
276
|
+
for ik, _ in enumerate(self.kpts):
|
277
|
+
Gk_all[ik] = self.get_Gk(ik, energy)
|
278
|
+
return Gk_all
|
279
|
+
|
280
|
+
def get_GR(self, Rpts, energy, get_rho=False, Gk_all=None):
|
274
281
|
"""calculate real space Green's function for one energy, all R points.
|
275
282
|
G(R, epsilon) = G(k, epsilon) exp(-2\pi i R.dot. k)
|
276
283
|
:param Rpts: R points
|
@@ -282,7 +289,10 @@ class TBGreen:
|
|
282
289
|
GR = defaultdict(lambda: 0.0j)
|
283
290
|
rhoR = defaultdict(lambda: 0.0j)
|
284
291
|
for ik, kpt in enumerate(self.kpts):
|
285
|
-
|
292
|
+
if Gk_all is None:
|
293
|
+
Gk = self.get_Gk(ik, energy)
|
294
|
+
else:
|
295
|
+
Gk = Gk_all[ik]
|
286
296
|
if get_rho:
|
287
297
|
if self.is_orthogonal:
|
288
298
|
rhok = Gk
|
TB2J/manager.py
CHANGED
@@ -6,7 +6,13 @@ from TB2J.exchangeCL2 import ExchangeCL2
|
|
6
6
|
from TB2J.exchange_qspace import ExchangeCLQspace
|
7
7
|
from TB2J.utils import read_basis, auto_assign_basis_name
|
8
8
|
from ase.io import read
|
9
|
-
|
9
|
+
|
10
|
+
#from TB2J.sisl_wrapper import SislWrapper
|
11
|
+
try:
|
12
|
+
from HamiltonIO.siesta import SislWrapper
|
13
|
+
except ImportError:
|
14
|
+
print("Cannot import SislWrapper from HamiltonIO.siesta. Please install HamiltonIO first.")
|
15
|
+
from TB2J.sisl_wrapper import SislWrapper
|
10
16
|
from TB2J.gpaw_wrapper import GPAWWrapper
|
11
17
|
from TB2J.wannier import parse_atoms
|
12
18
|
|
@@ -283,8 +289,8 @@ def gen_exchange_siesta(
|
|
283
289
|
geom = H.geometry
|
284
290
|
if H.spin.is_colinear:
|
285
291
|
print("Reading Siesta hamiltonian: colinear spin.")
|
286
|
-
tbmodel_up = SislWrapper(H, spin=0, geom=geom)
|
287
|
-
tbmodel_dn = SislWrapper(H, spin=1, geom=geom)
|
292
|
+
tbmodel_up = SislWrapper(fdf_fname=None,sisl_hamiltonian=H, spin=0, geom=geom)
|
293
|
+
tbmodel_dn = SislWrapper(fdf_fname=None, sisl_hamiltonian=H, spin=1, geom=geom)
|
288
294
|
basis = dict(zip(tbmodel_up.orbs, list(range(tbmodel_up.norb))))
|
289
295
|
print("Starting to calculate exchange.")
|
290
296
|
description = f""" Input from collinear Siesta data.
|
@@ -351,7 +357,7 @@ def gen_exchange_siesta(
|
|
351
357
|
|
352
358
|
elif H.spin.is_spinorbit or H.spin.is_noncolinear:
|
353
359
|
print("Reading Siesta hamiltonian: non-colinear spin.")
|
354
|
-
tbmodel = SislWrapper(H, spin=None, geom=geom)
|
360
|
+
tbmodel = SislWrapper(fdf_fname=None, sisl_hamiltonian=H, spin=None, geom=geom)
|
355
361
|
basis = dict(zip(tbmodel.orbs, list(range(tbmodel.nbasis))))
|
356
362
|
print("Starting to calculate exchange.")
|
357
363
|
description = f""" Input from non-collinear Siesta data.
|
TB2J/mathutils/rotate_spin.py
CHANGED
@@ -14,6 +14,27 @@ def rotate_Matrix_from_z_to_axis(M, axis, normalize=True):
|
|
14
14
|
return M_new
|
15
15
|
|
16
16
|
|
17
|
+
def spherical_to_cartesian(theta, phi, normalize=True):
|
18
|
+
"""
|
19
|
+
Convert spherical coordinates to cartesian
|
20
|
+
"""
|
21
|
+
x = np.sin(theta) * np.cos(phi)
|
22
|
+
y = np.sin(theta) * np.sin(phi)
|
23
|
+
z = np.cos(theta)
|
24
|
+
vec = np.array([x, y, z])
|
25
|
+
if normalize:
|
26
|
+
vec = vec / np.linalg.norm(vec)
|
27
|
+
return vec
|
28
|
+
|
29
|
+
|
30
|
+
def rotate_Matrix_from_z_to_spherical(M, theta, phi, normalize=True):
|
31
|
+
"""
|
32
|
+
Given a spinor matrix M, rotate it from z-axis to spherical coordinates
|
33
|
+
"""
|
34
|
+
axis = spherical_to_cartesian(theta, phi, normalize)
|
35
|
+
return rotate_Matrix_from_z_to_axis(M, axis, normalize)
|
36
|
+
|
37
|
+
|
17
38
|
def test_rotate_Matrix_from_z_to_axis():
|
18
39
|
M = np.array([[1.1, 0], [0, 0.9]])
|
19
40
|
print(pauli_block_all(M))
|
TB2J/patch.py
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
import types
|
2
|
+
from unittest import mock
|
3
|
+
|
4
|
+
class A(object):#but seems to work for old style objects too
|
5
|
+
def funcx(self,x):
|
6
|
+
print("x1=",x)
|
7
|
+
print("called from", self)
|
8
|
+
|
9
|
+
def method(self,x):
|
10
|
+
print("xmethod=",x)
|
11
|
+
print("called from", self)
|
12
|
+
|
13
|
+
def patch_me(target):
|
14
|
+
def method(target,x):
|
15
|
+
print("x=",x)
|
16
|
+
print("called from", target)
|
17
|
+
target.method = types.MethodType(method,target)
|
18
|
+
|
19
|
+
def method(self,x):
|
20
|
+
print("x=",x)
|
21
|
+
print("called from", self)
|
22
|
+
|
23
|
+
@mock.patch("__main__.A")
|
24
|
+
def funcx(self,x):
|
25
|
+
print("new x=",x)
|
26
|
+
print("called from", self)
|
27
|
+
|
28
|
+
A.method=method
|
29
|
+
#add more if needed
|
30
|
+
a = A()
|
31
|
+
print(A.__dict__)
|
32
|
+
print(a)
|
33
|
+
#out: <__main__.A object at 0x2b73ac88bfd0>
|
34
|
+
|
35
|
+
@mock.patch("__main__.a")
|
36
|
+
def funcx(self,x):
|
37
|
+
print("x=",x)
|
38
|
+
print("called from", self)
|
39
|
+
|
40
|
+
a.funcx(3)
|
41
|
+
patch_me(a) #patch instance
|
42
|
+
a.method=method
|
43
|
+
#a.method(5)
|
44
|
+
#out: x= 5
|
45
|
+
#out: called from <__main__.A object at 0x2b73ac88bfd0>
|
46
|
+
patch_me(A)
|
47
|
+
|
48
|
+
a.method(6) #can patch class too
|
49
|
+
#out: x= 6
|
50
|
+
#out: called from <class '__main__.A'>
|
@@ -58,6 +58,13 @@ def main():
|
|
58
58
|
default=False,
|
59
59
|
)
|
60
60
|
|
61
|
+
parser.add_argument(
|
62
|
+
"--method",
|
63
|
+
help="The method to downfold the exchange parameter. Options are Lowdin and PWF (projected Wannier function). ",
|
64
|
+
type=str,
|
65
|
+
default="Lowdin",
|
66
|
+
)
|
67
|
+
|
61
68
|
args = parser.parse_args()
|
62
69
|
|
63
70
|
if len(args.metals) == []:
|
@@ -73,6 +80,7 @@ def main():
|
|
73
80
|
outpath=args.outpath,
|
74
81
|
qmesh=args.qmesh,
|
75
82
|
iso_only=args.iso_only,
|
83
|
+
method=args.method,
|
76
84
|
)
|
77
85
|
|
78
86
|
|
@@ -1,5 +1,6 @@
|
|
1
|
-
TB2J/Jdownfolder.py,sha256=
|
2
|
-
TB2J/Jtensor.py,sha256=
|
1
|
+
TB2J/Jdownfolder.py,sha256=Rmg6KfQ-Lkhei5daTJ2POzr0XL-R1WM-rzUnDcfoDhc,9595
|
2
|
+
TB2J/Jtensor.py,sha256=t6OsqrSlYW6Im4H7ykVAW8Al_pFXN4C5yj2UEsV6r7g,3181
|
3
|
+
TB2J/MAE.py,sha256=0w2kOgj7lczrN4rS4OHKPoRueXGvbYtmvRvacZHgUnY,7390
|
3
4
|
TB2J/Oiju.py,sha256=cNGv8N5uH_swGq7cnAt2OyiDfqtjLlLrwseGu0E4iaM,3383
|
4
5
|
TB2J/Oiju_epc.py,sha256=oytM3NYW7nWmklrGgNlqwIpI_JYv_hb7ZnR4o9nYNog,6809
|
5
6
|
TB2J/__init__.py,sha256=hcEWkag_UvLm1ZSbjsgcTWkGVlR3Bwmzg1QYAwsvf-g,24
|
@@ -9,19 +10,20 @@ TB2J/contour.py,sha256=aw8LX6wVFCRPhcpkzuI0jGnHisvk4cezvUhkF_6Yx94,2633
|
|
9
10
|
TB2J/cut_cell.py,sha256=kr9WeQhBQLm8QXL2B3NcsSYmSw-OAtJk3f9wksAOZbs,2952
|
10
11
|
TB2J/density_matrix.py,sha256=D5k8Oe21OCiLVORNYbo4TZOFG0slrQSbj91kJ3TMFjs,1514
|
11
12
|
TB2J/epc.py,sha256=zLbtqZJhDr8DnnGN6YENcXwrMb3Qxu6KB08mLy9Pw20,3474
|
12
|
-
TB2J/exchange.py,sha256=
|
13
|
-
TB2J/exchangeCL2.py,sha256=
|
13
|
+
TB2J/exchange.py,sha256=Tltunv85eNr-jsVL_SvfqG_WVkQyJX99RszaJRQRBD8,29945
|
14
|
+
TB2J/exchangeCL2.py,sha256=QSbQ_WxgJyiByn2U-tJ3xy2iYIQI8YMrN3vhw9_k2Cs,11149
|
14
15
|
TB2J/exchange_pert.py,sha256=jmFMtQbYa_uczM4VAeS6TijkIHRFIqEzZJswzE9Wfuo,8523
|
15
16
|
TB2J/exchange_qspace.py,sha256=ZL68qBGFUaQ9BsSPsJaaoWOr9RssPiqX34R_9I3nk_8,8436
|
16
17
|
TB2J/gpaw_wrapper.py,sha256=aJ--9Dtyq7jOP1Hkh-Sh1nWcfXm6zKcljOCO0DNCAr0,6890
|
17
|
-
TB2J/green.py,sha256=
|
18
|
+
TB2J/green.py,sha256=giWSPhrLKc3ZKOpwyY3snUKFWH08GMqBlsJWbFG9Qo8,13565
|
18
19
|
TB2J/greentest.py,sha256=2ISSfhor9ecSEOi_E6b4Cv26wEIQlwlzca0ru8z44_E,1603
|
19
20
|
TB2J/io_merge.py,sha256=t85k3L6IL9X5ys-PWK7CzResb3xJsyqM3LAlKPUe9vM,6825
|
20
21
|
TB2J/kpoints.py,sha256=6XK2KqTncidEq3o9GuO6VEZRPNTRtWeXg9QfcV-9smI,532
|
21
|
-
TB2J/manager.py,sha256=
|
22
|
+
TB2J/manager.py,sha256=Ogb_yRCnroNmGttKPRcbF70ddF9UNV_1UytdKbNFN4E,15685
|
22
23
|
TB2J/mathutils.py,sha256=tHA6q3KPDpXLIbZHdDZ2NU5s886VVM_oEG490zQ6Ris,300
|
23
24
|
TB2J/myTB.py,sha256=ok_B4my29bOIghMSZfx0Es6G8FaXaIiLP4gPxTdSj00,17659
|
24
25
|
TB2J/orbmap.py,sha256=RCMJkOPGbfPrcZzcc5ia1ZMKBQWxGcyj8W1ve8BJaEw,6669
|
26
|
+
TB2J/patch.py,sha256=Z3KZklID9U8zKuk6Ek1Tq95JcY3eT4770dsdcXz6mAA,1067
|
25
27
|
TB2J/pauli.py,sha256=zOELm7Vgxw6SMaO5l7qVWx1pBKZt25RLnEpnVM3dz_0,4545
|
26
28
|
TB2J/pert.py,sha256=RaCJfewl0doht4cjAnzzGKe-uj2le4aqe0iPKFrq9fo,1192
|
27
29
|
TB2J/plot.py,sha256=AnFIFWE2vlmj7Z6f_7-dX_O1stJN-qbuiurPj43dUCM,4104
|
@@ -36,7 +38,7 @@ TB2J/versioninfo.py,sha256=wZwS9QDFRVDe7rf8JyPDDI8UGdTQiO6Pb_sWv8GAegA,337
|
|
36
38
|
TB2J/abacus/MAE.py,sha256=q9aSVDRZFAnZL3gHdNmde7sxj80oe-BRjwDO-ipyfew,12237
|
37
39
|
TB2J/abacus/__init__.py,sha256=5sHiDnF2L-Y80QeET9zOiS83a5T_TQAXvnIhcYB6wNU,56
|
38
40
|
TB2J/abacus/abacus_api.py,sha256=D_NyXW-Pno92d3RVHByx0l1HDPHQAvXsmQVt8cfIGR8,7267
|
39
|
-
TB2J/abacus/abacus_wrapper.py,sha256=
|
41
|
+
TB2J/abacus/abacus_wrapper.py,sha256=k0ZyTQ0jungp7jtlVCcdFQVK9YKeWokZvASCvfKCuKs,11880
|
40
42
|
TB2J/abacus/gen_exchange_abacus.py,sha256=lKZqkWMnLQtaSwgn8O5Fzr-pV6tzwoMqfZU_vbET6gU,2973
|
41
43
|
TB2J/abacus/occupations.py,sha256=vaMVeZwldgzGDxjA7i3-2-V6akXjpgJwJFWKozJ-l2k,8947
|
42
44
|
TB2J/abacus/orbital_api.py,sha256=l48Hn5z7TA0TH7Is4NDmz74b6B9L2ztYO4dRR37U4mQ,1562
|
@@ -58,7 +60,7 @@ TB2J/mathutils/__init__.py,sha256=tQLBfHkZqdVfVxPOahy42qMUkFYnFFFhM-uc4QsYFxI,27
|
|
58
60
|
TB2J/mathutils/fermi.py,sha256=tzEicVoxE_5DxPDDZMvi4ynR1_Iqf-Qh0-0zfm-iVBo,480
|
59
61
|
TB2J/mathutils/kR_convert.py,sha256=p_9XWJVNanTzTK2rI6KRjTkbSq42la6N448-zJOsMwY,2671
|
60
62
|
TB2J/mathutils/lowdin.py,sha256=tHA6q3KPDpXLIbZHdDZ2NU5s886VVM_oEG490zQ6Ris,300
|
61
|
-
TB2J/mathutils/rotate_spin.py,sha256=
|
63
|
+
TB2J/mathutils/rotate_spin.py,sha256=NT12khB8lN1qf_jQ2SwnAhhtWxptZXkzpUQ2JvZEnkM,1710
|
62
64
|
TB2J/spinham/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
63
65
|
TB2J/spinham/base_parser.py,sha256=oQRHvFE_BlUtTaTZykKgvicu40oXcbICB-D1aAt-qlA,2196
|
64
66
|
TB2J/spinham/constants.py,sha256=y4-hRyl5EAR42k24Oa5XhAsUQtKVn1MAgyqNf-p3PrM,762
|
@@ -74,18 +76,18 @@ TB2J/spinham/supercell.py,sha256=y17uUC6r3gQb278FhxIW4CABihfLTvKFj6flyXrCPR8,122
|
|
74
76
|
TB2J/wannier/__init__.py,sha256=7ojCbM84PYv1X1Tbo4NHI-d3gWmQsZB_xiYqbfxVV1E,80
|
75
77
|
TB2J/wannier/w90_parser.py,sha256=dbd63LuKyv2DVUzqRINGsbDzEsOxsQyE8_Ear_LQIRg,4620
|
76
78
|
TB2J/wannier/w90_tb_parser.py,sha256=qt8pnuprmPp9iIAYwPkPbmEzk6ZPgMq2xognoQp7vwc,4610
|
77
|
-
TB2J-0.9.
|
78
|
-
TB2J-0.9.
|
79
|
-
TB2J-0.9.
|
80
|
-
TB2J-0.9.
|
81
|
-
TB2J-0.9.
|
82
|
-
TB2J-0.9.
|
83
|
-
TB2J-0.9.
|
84
|
-
TB2J-0.9.
|
85
|
-
TB2J-0.9.
|
86
|
-
TB2J-0.9.
|
87
|
-
TB2J-0.9.
|
88
|
-
TB2J-0.9.
|
89
|
-
TB2J-0.9.
|
90
|
-
TB2J-0.9.
|
91
|
-
TB2J-0.9.
|
79
|
+
TB2J-0.9.2rc0.data/scripts/TB2J_downfold.py,sha256=i4BVqnpDdgrX_amookVWeLGefGBn-qeAutWiwuY9SfQ,2099
|
80
|
+
TB2J-0.9.2rc0.data/scripts/TB2J_eigen.py,sha256=Qs9v2hnMm2Tpfoa4h53muUKty2dZjwx8948MBoQooNg,1128
|
81
|
+
TB2J-0.9.2rc0.data/scripts/TB2J_magnon.py,sha256=q7UwAmorRcFNk4tfE7gl_ny05l6p7pbD9Wm_LkIpKEw,3101
|
82
|
+
TB2J-0.9.2rc0.data/scripts/TB2J_magnon_dos.py,sha256=TMXQvD2dIbO5FZ4tUMmxJgCgH2O2hDAPUNfEKO4z-x4,110
|
83
|
+
TB2J-0.9.2rc0.data/scripts/TB2J_merge.py,sha256=y834SF4rIRn1L1ptkhczvavQpC-8Px6DTmDOOSaq_DE,1854
|
84
|
+
TB2J-0.9.2rc0.data/scripts/TB2J_rotate.py,sha256=zgiDFuYZNmzKK0rwDmTaYD2OpRlmKA_VGeBx83w2Xwc,873
|
85
|
+
TB2J-0.9.2rc0.data/scripts/TB2J_rotateDM.py,sha256=kCvF7gotuqAX1VnJ06cwfVm7RrhrdtiV5v7d9P2Pn_E,567
|
86
|
+
TB2J-0.9.2rc0.data/scripts/abacus2J.py,sha256=M4B07lvTCDczTPTqvnDh_PERzCARAd09TLKv4aIdSQM,4408
|
87
|
+
TB2J-0.9.2rc0.data/scripts/siesta2J.py,sha256=hBzS7ZgoHM3oXlTCQd-xVA07Ks2FiIwyRpQWUFITRPE,4303
|
88
|
+
TB2J-0.9.2rc0.data/scripts/wann2J.py,sha256=2t2hWwyELskYCwkGDziCgiIAnfr6odLLJ6cQBJ2RQwQ,5714
|
89
|
+
TB2J-0.9.2rc0.dist-info/LICENSE,sha256=CbZI-jyRTjiqIcWa244cRSHJdjjtUNqGR4HeJkgEwJw,1332
|
90
|
+
TB2J-0.9.2rc0.dist-info/METADATA,sha256=oV593Fk_girgJbc0w4u3U9PBEC_Crhx6B1p9ff1pcBY,1421
|
91
|
+
TB2J-0.9.2rc0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
92
|
+
TB2J-0.9.2rc0.dist-info/top_level.txt,sha256=whYa5ByLYhl5XnTPBHSWr-IGD6VWmr5Ql2bye2qwV_s,5
|
93
|
+
TB2J-0.9.2rc0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|