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/supercell.py
DELETED
@@ -1,532 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
A helper class for building supercells
|
3
|
-
"""
|
4
|
-
import numpy as np
|
5
|
-
from collections import OrderedDict, defaultdict
|
6
|
-
from itertools import product
|
7
|
-
from functools import lru_cache
|
8
|
-
from ase.build import make_supercell
|
9
|
-
from ase.atoms import Atoms
|
10
|
-
|
11
|
-
|
12
|
-
def close_to_int(x, tol=1e-4):
|
13
|
-
return np.allclose(x, np.round(x), atol=tol)
|
14
|
-
|
15
|
-
|
16
|
-
class SupercellMaker(object):
|
17
|
-
|
18
|
-
def __init__(self, sc_matrix, center=False):
|
19
|
-
"""
|
20
|
-
a helper class for making supercells.
|
21
|
-
sc_matrix, supercell matrix. sc_matrix .dot. unitcell = supercell
|
22
|
-
"""
|
23
|
-
sc_matrix = np.array(sc_matrix, dtype=int)
|
24
|
-
if len(sc_matrix.flatten()) == 3:
|
25
|
-
sc_matrix = np.diag(sc_matrix)
|
26
|
-
elif sc_matrix.shape == (3, 3):
|
27
|
-
pass
|
28
|
-
else:
|
29
|
-
raise ValueError('sc_matrix should be 3 or 3*3 matrix')
|
30
|
-
self.sc_matrix = sc_matrix
|
31
|
-
self.center = center
|
32
|
-
if center:
|
33
|
-
self.shift = np.array([0.5, 0.5, 0.5])
|
34
|
-
else:
|
35
|
-
self.shift = np.zeros(3, dtype=float)
|
36
|
-
self.inv_scmat = np.linalg.inv(self.sc_matrix.T)
|
37
|
-
self.build_sc_vec()
|
38
|
-
self.ncell = int(round(abs(np.linalg.det(sc_matrix))))
|
39
|
-
|
40
|
-
def to_red_sc(self, x):
|
41
|
-
return np.dot(self.inv_scmat, x) + self.shift
|
42
|
-
|
43
|
-
def build_sc_vec(self):
|
44
|
-
eps_shift = np.sqrt(
|
45
|
-
2.0) * 1.0E-8 # shift of the grid, so to avoid double counting
|
46
|
-
#max_R = np.max(np.abs(self.sc_matrix)) * 3
|
47
|
-
if self.center:
|
48
|
-
minr = -0.5
|
49
|
-
maxr = 0.5
|
50
|
-
else:
|
51
|
-
minr = 0.0
|
52
|
-
maxr = 1.0
|
53
|
-
sc_vec = []
|
54
|
-
newcell = self.sc_matrix
|
55
|
-
scorners_newcell = np.array([[0., 0., 0.], [0., 0., 1.], [0., 1., 0.],
|
56
|
-
[0., 1., 1.], [1., 0., 0.], [1., 0., 1.],
|
57
|
-
[1., 1., 0.], [1., 1., 1.]])
|
58
|
-
corners = np.dot(scorners_newcell - self.shift, newcell)
|
59
|
-
scorners = corners
|
60
|
-
#rep = np.ceil(scorners.ptp(axis=0)).astype('int') + 1
|
61
|
-
minrep = np.ceil(np.min(scorners, axis=0)).astype('int')
|
62
|
-
maxrep = np.ceil(np.max(scorners, axis=0)).astype('int') + 1
|
63
|
-
|
64
|
-
# sc_vec: supercell vector (map atom from unit cell to supercell)
|
65
|
-
# for vec in product(range(rep[0]), range(rep[1]), range(rep[2])):
|
66
|
-
for vec in product(range(minrep[0], maxrep[0]),
|
67
|
-
range(minrep[1], maxrep[1]),
|
68
|
-
range(minrep[2], maxrep[2])):
|
69
|
-
# compute reduced coordinates of this candidate vector in the super-cell frame
|
70
|
-
tmp_red = self.to_red_sc(vec)
|
71
|
-
# check if in the interior
|
72
|
-
if (not (tmp_red <= -eps_shift).any()) and (
|
73
|
-
not (tmp_red > 1.0 - eps_shift).any()):
|
74
|
-
sc_vec.append(np.array(vec))
|
75
|
-
|
76
|
-
# number of times unit cell is repeated in the super-cell
|
77
|
-
num_sc = len(sc_vec)
|
78
|
-
|
79
|
-
# check that found enough super-cell vectors
|
80
|
-
if int(round(np.abs(np.linalg.det(self.sc_matrix)))) != num_sc:
|
81
|
-
raise Exception(
|
82
|
-
"\n\nSuper-cell generation failed! Wrong number of super-cell vectors found."
|
83
|
-
)
|
84
|
-
|
85
|
-
sc_vec = np.array(sc_vec)
|
86
|
-
self.sc_vec = np.array(sc_vec)
|
87
|
-
svtuple = (tuple(s) for s in sc_vec)
|
88
|
-
self.sc_vec_dict = dict(zip(svtuple, range(sc_vec.shape[0])))
|
89
|
-
|
90
|
-
def get_R(self):
|
91
|
-
return self.sc_vec
|
92
|
-
|
93
|
-
@property
|
94
|
-
def R_sc(self):
|
95
|
-
return self.sc_vec
|
96
|
-
|
97
|
-
def sc_cell(self, cell):
|
98
|
-
cell = np.array(cell)
|
99
|
-
if len(cell.flatten()) == 3:
|
100
|
-
cell = np.diag(cell)
|
101
|
-
return np.dot(self.sc_matrix, cell)
|
102
|
-
|
103
|
-
def sc_pos(self, positions, return_R=False):
|
104
|
-
"""
|
105
|
-
pos -> pos in supercell (reduced.)
|
106
|
-
"""
|
107
|
-
sc_pos = []
|
108
|
-
sc_R = []
|
109
|
-
for cur_sc_vec in self.sc_vec: # go over all super-cell vectors
|
110
|
-
for pos in positions:
|
111
|
-
# shift orbital and compute coordinates in
|
112
|
-
# reduced coordinates of super-cell
|
113
|
-
sc_pos.append(self.to_red_sc(pos + cur_sc_vec))
|
114
|
-
sc_R.append(cur_sc_vec)
|
115
|
-
if return_R:
|
116
|
-
return sc_pos, sc_R
|
117
|
-
else:
|
118
|
-
return sc_pos
|
119
|
-
|
120
|
-
def sc_trans_invariant(self, q, return_R=False):
|
121
|
-
"""
|
122
|
-
translation invariant quantities. Like on-site energy of tight binding,
|
123
|
-
chemical symbols, magnetic moments of spin.
|
124
|
-
"""
|
125
|
-
sc_q = []
|
126
|
-
sc_R = [] # supercell R
|
127
|
-
for cur_sc_vec in self.sc_vec: # go over all super-cell vectors
|
128
|
-
for qitem in q:
|
129
|
-
sc_q.append(qitem)
|
130
|
-
sc_R.append(cur_sc_vec)
|
131
|
-
if return_R:
|
132
|
-
return sc_q, sc_R
|
133
|
-
else:
|
134
|
-
return sc_q
|
135
|
-
|
136
|
-
def sc_trans_kvector(self, x, kpt, phase=0.0, real=False):
|
137
|
-
"""
|
138
|
-
x is a vector of quantities inside the primitive cell.
|
139
|
-
qpoint is the wavevector
|
140
|
-
phase
|
141
|
-
x_sc= x * exp(i(qR + phase))
|
142
|
-
|
143
|
-
Note: if x is a 2D m*n array, the first m*n block is the primitive cell.
|
144
|
-
[block1, block2, block3, ... block_ncell]
|
145
|
-
"""
|
146
|
-
factor = self.phase_factor(kpt, phase=phase)
|
147
|
-
ret = np.kron(factor, x)
|
148
|
-
if real:
|
149
|
-
ret = np.real(ret)
|
150
|
-
return ret
|
151
|
-
|
152
|
-
def Rvector_for_each_element(self, n_ind=1):
|
153
|
-
"""
|
154
|
-
repeat the R_sc vectors.
|
155
|
-
"""
|
156
|
-
return np.kron(self.sc_vec, np.ones((n_ind, 1)))
|
157
|
-
|
158
|
-
def sc_index(self, indices, n_ind=None):
|
159
|
-
"""
|
160
|
-
Note that the number of indices could be inequal to the repeat period.
|
161
|
-
e.g. for n_orb of orbitals, the indices of atoms iatom for each orbital.
|
162
|
-
In that case, in the second unit cell (c=1 here), iatom-> iatom+n_ind,
|
163
|
-
where n_ind=natoms in primitive cell.
|
164
|
-
"""
|
165
|
-
sc_ind = []
|
166
|
-
if n_ind is None:
|
167
|
-
n_ind = len(indices)
|
168
|
-
for c, cur_sc_vec in enumerate(
|
169
|
-
self.sc_vec): # go over all super-cell vectors
|
170
|
-
for ind in indices:
|
171
|
-
sc_ind.append(ind + c * n_ind)
|
172
|
-
return sc_ind
|
173
|
-
|
174
|
-
@lru_cache(maxsize=5000)
|
175
|
-
def _sc_R_to_pair_ind(self, R_plus_Rv):
|
176
|
-
"""
|
177
|
-
R: initial R vector (e.g. R in (i, jR) pair)
|
178
|
-
Rv: translation vector. (e.g. for Rv in self.sc_vec)
|
179
|
-
|
180
|
-
Returns:
|
181
|
-
sc_part: R in
|
182
|
-
pair_ind:
|
183
|
-
"""
|
184
|
-
R_plus_Rv = np.asarray(R_plus_Rv)
|
185
|
-
sc_part = np.floor(self.to_red_sc(R_plus_Rv)) # round down!
|
186
|
-
sc_part = np.array(sc_part, dtype=int)
|
187
|
-
# find remaining vector in the original reduced coordinates
|
188
|
-
orig_part = R_plus_Rv - np.dot(sc_part, self.sc_matrix)
|
189
|
-
pair_ind1 = self.sc_vec_dict[tuple(orig_part)]
|
190
|
-
return sc_part, pair_ind1
|
191
|
-
|
192
|
-
def sc_jR_to_scjR(self, j, R, Rv, n_basis):
|
193
|
-
"""
|
194
|
-
(j, R) in primitive cell to (j', R') in supercell.
|
195
|
-
"""
|
196
|
-
Rprim, pair_ind = self._sc_R_to_pair_ind(
|
197
|
-
tuple(np.array(R) + np.array(Rv)))
|
198
|
-
return j + pair_ind * n_basis, tuple(Rprim)
|
199
|
-
|
200
|
-
def sc_i_to_sci(self, i, ind_Rv, n_basis):
|
201
|
-
return i + ind_Rv * n_basis
|
202
|
-
|
203
|
-
def sc_ijR_only(self, i, j, R, n_basis):
|
204
|
-
ret = []
|
205
|
-
for c, cur_sc_vec in enumerate(
|
206
|
-
self.sc_vec): # go over all super-cell vectors
|
207
|
-
sc_part, pair_ind = self._sc_R_to_pair_ind(tuple(R + cur_sc_vec))
|
208
|
-
sc_i = i + c * n_basis
|
209
|
-
sc_j = j + pair_ind * n_basis
|
210
|
-
ret.append((sc_i, sc_j, tuple(sc_part)))
|
211
|
-
return ret
|
212
|
-
|
213
|
-
def sc_jR(self, jlist, Rjlist, n_basis):
|
214
|
-
sc_jlist = []
|
215
|
-
sc_Rjlist = []
|
216
|
-
for c, cur_sc_vec in enumerate(
|
217
|
-
self.sc_vec): # go over all super-cell vectors
|
218
|
-
# for i , j, ind_R, val in
|
219
|
-
for j, Rj in zip(jlist, Rjlist):
|
220
|
-
sc_part, pair_ind = self._sc_R_to_pair_ind(
|
221
|
-
tuple(Rj + cur_sc_vec))
|
222
|
-
sc_j = j + pair_ind * n_basis
|
223
|
-
sc_jlist.append(sc_j)
|
224
|
-
sc_Rjlist.append(tuple(sc_part))
|
225
|
-
return sc_jlist, sc_Rjlist
|
226
|
-
|
227
|
-
def sc_ijR(self, terms, n_basis):
|
228
|
-
"""
|
229
|
-
# TODO very slow when supercell is large, should improve it.
|
230
|
-
map Val(i, j, R) which is a funciton of (R+rj-ri) to supercell.
|
231
|
-
e.g. hopping in Tight binding. exchange in heisenberg model,...
|
232
|
-
Args:
|
233
|
-
========================
|
234
|
-
terms: either list of [i, j, R, val] or dict{(i,j, R): val}
|
235
|
-
pos: reduced positions in the unit cell.
|
236
|
-
Returns:
|
237
|
-
=======================
|
238
|
-
"""
|
239
|
-
ret_dict = OrderedDict()
|
240
|
-
for c, cur_sc_vec in enumerate(
|
241
|
-
self.sc_vec): # go over all super-cell vectors
|
242
|
-
# for i , j, ind_R, val in
|
243
|
-
for (i, j, ind_R), val in terms.items():
|
244
|
-
sc_part, pair_ind = self._sc_R_to_pair_ind(
|
245
|
-
tuple(ind_R + cur_sc_vec))
|
246
|
-
# index of "from" and "to" hopping indices
|
247
|
-
sc_i = i + c * n_basis
|
248
|
-
sc_j = j + pair_ind * n_basis
|
249
|
-
|
250
|
-
# hi = self._hoppings[h][1] + c * self._norb
|
251
|
-
# hj = self._hoppings[h][2] + pair_ind * self._norb
|
252
|
-
ret_dict[(sc_i, sc_j, tuple(sc_part))] = val
|
253
|
-
return ret_dict
|
254
|
-
|
255
|
-
def sc_Rlist_HR(self, Rlist, HR, n_basis):
|
256
|
-
"""
|
257
|
-
terms: H[R][i,j] = val
|
258
|
-
========================
|
259
|
-
terms: either list of [i, j, R, val] or dict{(i,j, R): val}
|
260
|
-
pos: reduced positions in the unit cell.
|
261
|
-
Returns:
|
262
|
-
=======================
|
263
|
-
"""
|
264
|
-
sc_Rlist = []
|
265
|
-
sc_HR = []
|
266
|
-
for c, cur_sc_vec in enumerate(
|
267
|
-
self.sc_vec): # go over all super-cell vectors
|
268
|
-
# for i , j, ind_R, val in
|
269
|
-
for iR, R in enumerate(Rlist):
|
270
|
-
H = HR[iR]
|
271
|
-
sc_part, pair_ind = self._sc_R_to_pair_ind(
|
272
|
-
tuple(R + cur_sc_vec))
|
273
|
-
sc_Rlist.append(sc_part)
|
274
|
-
sc_val = np.zeros((n_basis * self.ncell, n_basis * self.ncell),
|
275
|
-
dtype=HR.dtype)
|
276
|
-
for i in range(n_basis):
|
277
|
-
for j in range(n_basis):
|
278
|
-
sc_i = i + c * n_basis
|
279
|
-
sc_j = j + pair_ind * n_basis
|
280
|
-
sc_val[sc_i, sc_j] = H[i, j]
|
281
|
-
sc_HR.append(sc_val)
|
282
|
-
return np.array(sc_Rlist, dtype=int), np.array(sc_HR)
|
283
|
-
|
284
|
-
def sc_RHdict(self, RHdict, n_basis):
|
285
|
-
"""
|
286
|
-
terms: H[R][i,j] = val
|
287
|
-
========================
|
288
|
-
terms: either list of [i, j, R, val] or dict{(i,j, R): val}
|
289
|
-
pos: reduced positions in the unit cell.
|
290
|
-
Returns:
|
291
|
-
=======================
|
292
|
-
"""
|
293
|
-
sc_RHdict = defaultdict(lambda: np.zeros(
|
294
|
-
(n_basis * self.ncell, n_basis * self.ncell), dtype=H.dtype))
|
295
|
-
for c, cur_sc_vec in enumerate(
|
296
|
-
self.sc_vec): # go over all super-cell vectors
|
297
|
-
for R, H in RHdict.items():
|
298
|
-
sc_part, pair_ind = self._sc_R_to_pair_ind(
|
299
|
-
tuple(R + cur_sc_vec))
|
300
|
-
ii = c * n_basis
|
301
|
-
jj = pair_ind * n_basis
|
302
|
-
sc_RHdict[tuple(sc_part)][ii:ii + n_basis,
|
303
|
-
jj:jj + n_basis] += H
|
304
|
-
return sc_RHdict
|
305
|
-
|
306
|
-
def sc_RHdict_notrans(self, RHdict, n_basis, Rshift=(0, 0, 0)):
|
307
|
-
sc_RHdict = defaultdict(lambda: np.zeros(
|
308
|
-
(n_basis * self.ncell, n_basis * self.ncell), dtype=H.dtype))
|
309
|
-
cur_sc_vec = np.array(Rshift)
|
310
|
-
for R, H in RHdict.items():
|
311
|
-
sc_part, pair_ind = self._sc_R_to_pair_ind(
|
312
|
-
tuple(np.array(R) + cur_sc_vec))
|
313
|
-
c = self.sc_vec_dict[Rshift]
|
314
|
-
ii = c * n_basis
|
315
|
-
jj = pair_ind * n_basis
|
316
|
-
sc_RHdict[tuple(sc_part)][ii:ii + n_basis, jj:jj + n_basis] += H
|
317
|
-
return sc_RHdict
|
318
|
-
|
319
|
-
def sc_H_RpRk_notrans(self, Rplist, Rklist, n_basis, Rpprime, H):
|
320
|
-
"""
|
321
|
-
For a given perturbation at Rp',
|
322
|
-
<Rm|Rp'=Rp+Rm|Rk+Rm>
|
323
|
-
=H(Rp,Rk)=<0|Rp|Rk> is a matrix of nbasis*nbasis
|
324
|
-
First: Rm = Rp'-Rp, Rk+Rm = Rp'-Rp+Rm
|
325
|
-
Input: Rplist, Rklist, H
|
326
|
-
H: [iRg, iRk, ibasis, ibasis]
|
327
|
-
"""
|
328
|
-
sc_RHdict = defaultdict(lambda: np.zeros(
|
329
|
-
(n_basis * self.ncell, n_basis * self.ncell), dtype=H.dtype))
|
330
|
-
for iRp, Rp in enumerate(Rplist):
|
331
|
-
Rm = np.array(Rpprime) - np.array(Rp)
|
332
|
-
|
333
|
-
sc_part_i, pair_ind_i = self._sc_R_to_pair_ind(tuple(np.array(Rm)))
|
334
|
-
ii = pair_ind_i * n_basis
|
335
|
-
if tuple(sc_part_i) == (0, 0, 0):
|
336
|
-
for iRk, Rk in enumerate(Rklist):
|
337
|
-
sc_part_j, pair_ind_j = self._sc_R_to_pair_ind(
|
338
|
-
tuple(np.array(Rk) + np.array(Rm)))
|
339
|
-
jj = pair_ind_j * n_basis
|
340
|
-
sc_RHdict[tuple(sc_part_j)][ii:ii + n_basis, jj:jj +
|
341
|
-
n_basis] += H[iRp, iRk, :, :]
|
342
|
-
# elif tuple(sc_part_j) == (0, 0, 0):
|
343
|
-
# sc_RHdict[tuple(-sc_part_j)][jj:jj + n_basis,
|
344
|
-
# ii:ii + n_basis] += H[iRp, iRk, :, :].T.conj()
|
345
|
-
|
346
|
-
return sc_RHdict
|
347
|
-
|
348
|
-
def sc_atoms(self, atoms):
|
349
|
-
"""
|
350
|
-
This function is compatible with ase.build.make_supercell.
|
351
|
-
They should produce the same result.
|
352
|
-
"""
|
353
|
-
sc_cell = self.sc_cell(atoms.get_cell())
|
354
|
-
sc_pos = self.sc_pos(atoms.get_scaled_positions())
|
355
|
-
sc_numbers = self.sc_trans_invariant(atoms.get_atomic_numbers())
|
356
|
-
sc_magmoms = self.sc_trans_invariant(
|
357
|
-
atoms.get_initial_magnetic_moments())
|
358
|
-
return Atoms(cell=sc_cell,
|
359
|
-
scaled_positions=sc_pos,
|
360
|
-
numbers=sc_numbers,
|
361
|
-
magmoms=sc_magmoms)
|
362
|
-
|
363
|
-
def phase_factor(self, qpoint, phase=0, real=True):
|
364
|
-
f = np.exp(2j * np.pi * np.einsum('i, ji -> j', qpoint, self.sc_vec) +
|
365
|
-
1j * phase)
|
366
|
-
if real:
|
367
|
-
f = np.real(f)
|
368
|
-
return f
|
369
|
-
|
370
|
-
def modulation_function_R(self, func):
|
371
|
-
return [func(R) for R in self.R_sc]
|
372
|
-
|
373
|
-
def _make_translate_maps(positions, basis, sc_mat, tol_r=1e-4):
|
374
|
-
"""
|
375
|
-
find the mapping between supercell and translated cell.
|
376
|
-
Returns:
|
377
|
-
===============
|
378
|
-
A N * nbasis array.
|
379
|
-
index[i] is the mapping from supercell to translated supercell so that
|
380
|
-
T(r_i) psi = psi[indices[i]].
|
381
|
-
|
382
|
-
"""
|
383
|
-
a1 = Atoms(symbols='H', positions=[(0, 0, 0)], cell=[1, 1, 1])
|
384
|
-
sc = make_supercell(a1, self._scmat)
|
385
|
-
rs = sc.get_scaled_positions()
|
386
|
-
|
387
|
-
indices = np.zeros([len(rs), len(positions)], dtype='int32')
|
388
|
-
for i, ri in enumerate(rs):
|
389
|
-
inds = []
|
390
|
-
Tpositions = positions + np.array(ri)
|
391
|
-
for i_basis, pos in enumerate(positions):
|
392
|
-
for j_basis, Tpos in enumerate(Tpositions):
|
393
|
-
dpos = Tpos - pos
|
394
|
-
if close_to_int(dpos, tol_r) and (self._basis[i_basis]
|
395
|
-
== self._basis[j_basis]):
|
396
|
-
indices[i, j_basis] = i_basis
|
397
|
-
|
398
|
-
self._trans_rs = rs
|
399
|
-
self._trans_indices = indices
|
400
|
-
|
401
|
-
|
402
|
-
def smod(x):
|
403
|
-
x = np.mod(x, 1)
|
404
|
-
return x if x < 0.5 else x - 1
|
405
|
-
|
406
|
-
|
407
|
-
smod = np.vectorize(smod)
|
408
|
-
|
409
|
-
|
410
|
-
def map_to_primitive(atoms, primitive_atoms, offset=(0, 0, 0)):
|
411
|
-
"""
|
412
|
-
Find the mapping of a supercell to a primitive cell.
|
413
|
-
:param atoms: the positions of atoms
|
414
|
-
:param primitive_atoms:
|
415
|
-
:param offset:
|
416
|
-
:param 0:
|
417
|
-
:param 0):
|
418
|
-
|
419
|
-
"""
|
420
|
-
ilist = []
|
421
|
-
Rlist = []
|
422
|
-
offset = np.array(offset, dtype=float)
|
423
|
-
ppos = primitive_atoms.get_positions()
|
424
|
-
pos = atoms.get_positions()
|
425
|
-
cell = primitive_atoms.get_cell()
|
426
|
-
for p in pos:
|
427
|
-
found = False
|
428
|
-
for i, pp in enumerate(ppos):
|
429
|
-
res0 = np.linalg.solve(cell.T, p - pp)
|
430
|
-
res = smod(res0)
|
431
|
-
if np.linalg.norm(res) < 0.01:
|
432
|
-
found = True
|
433
|
-
R = res0 - res
|
434
|
-
ilist.append(i)
|
435
|
-
Rlist.append(R)
|
436
|
-
break
|
437
|
-
if not found:
|
438
|
-
print("Not found")
|
439
|
-
ilist.append(-1)
|
440
|
-
Rlist.append([-999, -999, -999])
|
441
|
-
return np.array(ilist, dtype=int), np.array(Rlist, dtype=int)
|
442
|
-
|
443
|
-
|
444
|
-
def find_primitive_cell(atoms,
|
445
|
-
sc_matrix,
|
446
|
-
origin_atom_id=None,
|
447
|
-
thr=1e-5,
|
448
|
-
perfect=True):
|
449
|
-
"""
|
450
|
-
Find a primitive cell atoms from the supercell atom structure.
|
451
|
-
:param atoms: the supercell structure.
|
452
|
-
:param sc_matrix: the matrix which maps the primitive cell to supercell.
|
453
|
-
:param origin: the origin of the primitive cell.
|
454
|
-
:param thr: the atoms which the reduced position is within -thr to 1.0+thr are considered as inside the primitive atoms
|
455
|
-
:params perfect: True|False, whether the primitive cell should contains the same number of atoms .
|
456
|
-
:returns: (patoms, selected)
|
457
|
-
patoms: the primitive cell atoms
|
458
|
-
selected: the selected indices of the atoms in the supercell.
|
459
|
-
"""
|
460
|
-
scell = atoms.get_cell().array
|
461
|
-
inv_scmat = np.linalg.inv(sc_matrix)
|
462
|
-
pcell = scell@inv_scmat
|
463
|
-
print(f"{inv_scmat=}")
|
464
|
-
|
465
|
-
xcart = atoms.get_positions()
|
466
|
-
xred = atoms.get_scaled_positions()
|
467
|
-
print(xred)
|
468
|
-
if origin_atom_id is not None:
|
469
|
-
origin = xred[origin_atom_id]
|
470
|
-
else:
|
471
|
-
origin = np.zeros(3)
|
472
|
-
# check if some atom is exactly at the origin.
|
473
|
-
# if so, shift the positions by thr so that this atom is inside the cell
|
474
|
-
# if np.any(np.linalg.norm(xred - origin[None, :], axis=1) < thr):
|
475
|
-
# xred += thr
|
476
|
-
#xred += 0.05
|
477
|
-
|
478
|
-
sc_xred = xred@sc_matrix
|
479
|
-
print(sc_xred)
|
480
|
-
#np.all(sc_xred<1 and sc_xred>=0.0)
|
481
|
-
# print(sc_xred<1)
|
482
|
-
x = np.logical_and(sc_xred < 1+thr, sc_xred >= -thr)
|
483
|
-
print(np.all(x, axis=1))
|
484
|
-
selected = np.where(np.all(x, axis=1))[0]
|
485
|
-
print(selected)
|
486
|
-
symbols = atoms.get_chemical_symbols()
|
487
|
-
psymbols = [symbols[i] for i in selected]
|
488
|
-
patoms = Atoms(symbols=psymbols, positions=xcart[selected], cell=pcell)
|
489
|
-
ncell = abs(np.linalg.det(sc_matrix))
|
490
|
-
natom = len(atoms)
|
491
|
-
if perfect:
|
492
|
-
assert len(symbols) == int(
|
493
|
-
natom/ncell), "The number of atoms in the found primitive cell does not equal to natom in the supercell divided by the size of the cell"
|
494
|
-
return patoms, selected
|
495
|
-
|
496
|
-
|
497
|
-
def test_find_primitive_cell():
|
498
|
-
atoms = Atoms('HO', positions=[[0, 0, 0], [0, 0.2, 0]], cell=[1, 1, 1])
|
499
|
-
sc_matrix = np.diag([1, 1, 3])
|
500
|
-
atoms2 = make_supercell(atoms, sc_matrix)
|
501
|
-
patoms = find_primitive_cell(atoms2, sc_matrix)
|
502
|
-
|
503
|
-
|
504
|
-
def test():
|
505
|
-
sc_mat = np.diag([1, 1, 3])
|
506
|
-
#sc_mat[0, 1] = 2
|
507
|
-
spm = SupercellMaker(sc_matrix=sc_mat, center=False)
|
508
|
-
print("sc_vec", spm.sc_vec)
|
509
|
-
print(spm.sc_cell([1, 1, 1]))
|
510
|
-
print(spm.sc_pos([[0.5, 1, 1]]))
|
511
|
-
print(spm.sc_pos([[0.5, 1, 0.5]]))
|
512
|
-
print(spm.sc_trans_invariant(['Fe']))
|
513
|
-
print(spm.sc_ijR({
|
514
|
-
(0, 0, (0, 0, 1)): 1.2,
|
515
|
-
(1, 1, (0, 0, 1)): 1.2,
|
516
|
-
}, 2))
|
517
|
-
print(spm.sc_index(indices=(1, 2)))
|
518
|
-
print(spm.sc_index(indices=(1, 2), n_ind=4))
|
519
|
-
from ase.atoms import Atoms
|
520
|
-
atoms = Atoms('HO', positions=[[0, 0, 0], [0, 0.2, 0]], cell=[1, 1, 1])
|
521
|
-
from ase.build import make_supercell
|
522
|
-
atoms2 = make_supercell(atoms, sc_mat)
|
523
|
-
atoms3 = spm.sc_atoms(atoms)
|
524
|
-
# print(atoms2.get_positions())
|
525
|
-
# print(atoms3.get_positions())
|
526
|
-
assert (atoms2 == atoms3)
|
527
|
-
assert (atoms2.get_positions() == atoms3.get_positions()).all()
|
528
|
-
|
529
|
-
|
530
|
-
if __name__ == '__main__':
|
531
|
-
# test()
|
532
|
-
test_find_primitive_cell()
|