TB2J 0.9.4rc0__py3-none-any.whl → 0.9.6rc0__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 (58) hide show
  1. TB2J/MAE.py +108 -24
  2. TB2J/anisotropy.py +672 -0
  3. TB2J/contour.py +8 -0
  4. TB2J/exchange.py +43 -103
  5. TB2J/exchangeCL2.py +11 -13
  6. TB2J/exchange_params.py +213 -0
  7. TB2J/green.py +62 -27
  8. TB2J/interfaces/__init__.py +12 -0
  9. TB2J/interfaces/abacus/__init__.py +4 -0
  10. TB2J/{abacus → interfaces/abacus}/abacus_api.py +3 -3
  11. TB2J/{abacus → interfaces/abacus}/abacus_wrapper.py +11 -7
  12. TB2J/{abacus → interfaces/abacus}/gen_exchange_abacus.py +6 -3
  13. TB2J/{abacus → interfaces/abacus}/orbital_api.py +4 -4
  14. TB2J/{abacus → interfaces/abacus}/stru_api.py +11 -11
  15. TB2J/{abacus → interfaces/abacus}/test_read_HRSR.py +0 -1
  16. TB2J/{abacus → interfaces/abacus}/test_read_stru.py +5 -3
  17. TB2J/interfaces/gpaw_interface.py +54 -0
  18. TB2J/interfaces/lawaf_interface.py +129 -0
  19. TB2J/interfaces/manager.py +23 -0
  20. TB2J/interfaces/siesta_interface.py +174 -0
  21. TB2J/interfaces/wannier90_interface.py +115 -0
  22. TB2J/io_exchange/io_exchange.py +21 -7
  23. TB2J/io_merge.py +2 -1
  24. TB2J/mathutils/fermi.py +11 -6
  25. TB2J/mathutils/lowdin.py +12 -2
  26. TB2J/mathutils/rotate_spin.py +222 -4
  27. TB2J/pauli.py +38 -2
  28. TB2J/symmetrize_J.py +120 -0
  29. TB2J/utils.py +82 -1
  30. {TB2J-0.9.4rc0.data → TB2J-0.9.6rc0.data}/scripts/abacus2J.py +5 -4
  31. {TB2J-0.9.4rc0.data → TB2J-0.9.6rc0.data}/scripts/siesta2J.py +21 -4
  32. TB2J-0.9.6rc0.data/scripts/wann2J.py +96 -0
  33. {TB2J-0.9.4rc0.dist-info → TB2J-0.9.6rc0.dist-info}/METADATA +4 -3
  34. {TB2J-0.9.4rc0.dist-info → TB2J-0.9.6rc0.dist-info}/RECORD +46 -46
  35. {TB2J-0.9.4rc0.dist-info → TB2J-0.9.6rc0.dist-info}/WHEEL +1 -1
  36. TB2J-0.9.6rc0.dist-info/entry_points.txt +3 -0
  37. TB2J/abacus/MAE.py +0 -320
  38. TB2J/abacus/__init__.py +0 -1
  39. TB2J/abacus/occupations.py +0 -278
  40. TB2J/cut_cell.py +0 -82
  41. TB2J/io_exchange/io_pickle.py +0 -0
  42. TB2J/manager.py +0 -441
  43. TB2J/mathutils.py +0 -12
  44. TB2J/patch.py +0 -50
  45. TB2J/spinham/h_matrix.py +0 -68
  46. TB2J/spinham/obtain_J.py +0 -79
  47. TB2J/supercell.py +0 -532
  48. TB2J-0.9.4rc0.data/scripts/wann2J.py +0 -194
  49. TB2J/{abacus → interfaces/abacus}/test_density_matrix.py +1 -1
  50. {TB2J-0.9.4rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_downfold.py +0 -0
  51. {TB2J-0.9.4rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_eigen.py +0 -0
  52. {TB2J-0.9.4rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_magnon.py +0 -0
  53. {TB2J-0.9.4rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_magnon_dos.py +0 -0
  54. {TB2J-0.9.4rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_merge.py +0 -0
  55. {TB2J-0.9.4rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_rotate.py +0 -0
  56. {TB2J-0.9.4rc0.data → TB2J-0.9.6rc0.data}/scripts/TB2J_rotateDM.py +0 -0
  57. {TB2J-0.9.4rc0.dist-info → TB2J-0.9.6rc0.dist-info}/LICENSE +0 -0
  58. {TB2J-0.9.4rc0.dist-info → TB2J-0.9.6rc0.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()