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
@@ -1,278 +0,0 @@
1
- """
2
- This file is stolen from the hotbit programm, with some modification.
3
- """
4
-
5
- import numpy as np
6
- from scipy.optimize import brentq
7
- import sys
8
-
9
- from ase.dft.dos import DOS
10
- from scipy import integrate
11
-
12
- # import numba
13
-
14
- # from numba import float64, int32
15
-
16
- MAX_EXP_ARGUMENT = np.log(sys.float_info.max)
17
-
18
- # @numba.vectorize(nopython=True)
19
- # def myfermi(e, mu, width, nspin):
20
- # x = (e - mu) / width
21
- # if x < -10:
22
- # ret = 2.0 / nspin
23
- # elif x > 10:
24
- # ret = 0.0
25
- # else:
26
- # ret = 2.0 / nspin / (math.exp(x) + 1)
27
- # return ret
28
-
29
-
30
- def myfermi(e, mu, width, nspin):
31
- x = (e - mu) / width
32
- return np.where(x < 10, 2.0 / (nspin * (np.exp(x) + 1.0)), 0.0)
33
-
34
-
35
- class Occupations(object):
36
- def __init__(self, nel, width, wk, nspin=1):
37
- """
38
- Initialize parameters for occupations.
39
- :param nel: Number of electrons
40
- :param width: Fermi-broadening
41
- :param wk: k-point weights. eg. If only gamma, [1.0]
42
- :param nspin(optional): number of spin, if spin=1 multiplicity=2 else, multiplicity=1.
43
- """
44
- self.nel = nel
45
- self.width = width
46
- self.wk = wk
47
- self.nk = len(wk)
48
- self.nspin = nspin
49
-
50
- def get_mu(self):
51
- """Return the Fermi-level (or chemical potential)."""
52
- return self.mu
53
-
54
- def fermi(self, mu):
55
- """
56
- Occupy states with given chemical potential.
57
- Occupations are 0...2; without k-point weights
58
- """
59
- return myfermi(self.e, mu, self.width, self.nspin)
60
-
61
- def root_function(self, mu):
62
- """This function is exactly zero when mu is right."""
63
- f = self.fermi(mu)
64
- return np.einsum("i, ij->", self.wk, f) - self.nel
65
-
66
- def occupy(self, e, xtol=1e-11):
67
- """
68
- Calculate occupation numbers with given Fermi-broadening.
69
-
70
- @param e: e[ind_k,ind_orb] energy of k-point, state a
71
- Note added by hexu: With spin=2,e[k,a,sigma], it also work. only the *2 should be removed.
72
- @param wk: wk[:] weights for k-points
73
- @param width: The Fermi-broadening
74
-
75
- Returns: fermi[ind_k, ind_orb]
76
- """
77
- self.e = e
78
- eflat = e.flatten()
79
- ind = np.argsort(eflat)
80
- e_sorted = eflat[ind]
81
- if self.nspin == 1:
82
- m = 2
83
- elif self.nspin == 2:
84
- m = 1
85
- n_sorted = (self.wk[:, None, None] * np.ones_like(e) * m).flatten()[ind]
86
-
87
- sum = n_sorted.cumsum()
88
- if self.nel < sum[0]:
89
- ifermi = 0
90
- elif self.nel > sum[-1]:
91
- raise ("number of electrons larger than number of orbital*spin")
92
- else:
93
- ifermi = np.searchsorted(sum, self.nel)
94
- try:
95
- if ifermi == 0:
96
- elo = e_sorted[0]
97
- else:
98
- elo = e_sorted[ifermi - 1]
99
- if ifermi == len(e_sorted) - 1:
100
- ehi = e_sorted[-1]
101
- else:
102
- ehi = e_sorted[ifermi + 1]
103
- guess = e_sorted[ifermi]
104
- dmu = np.max((self.width, guess - elo, ehi - guess))
105
- mu = brentq(self.root_function, guess - dmu, guess + dmu, xtol=xtol)
106
- # mu = brent(
107
- # self.root_function,
108
- # brack=(guess - elo, guess, guess + dmu),
109
- # tol=xtol)
110
- except Exception as E:
111
- # probably a bad guess
112
- print("Error in finding Fermi level: ", E)
113
- dmu = self.width
114
- if self.nel < 1e-3:
115
- mu = min(e_sorted) - dmu * 20
116
- elif self.nel - sum[-1] > -1e-3:
117
- mu = max(e_sorted) + dmu * 20
118
- else:
119
- # mu = brent(
120
- # self.root_function,
121
- # brack=(e_sorted[0] - dmu * 10,
122
- # guess,
123
- # e_sorted[-1] + dmu * 10),
124
- # tol=xtol)
125
- mu = brentq(
126
- self.root_function,
127
- e_sorted[0] - dmu * 20,
128
- e_sorted[-1] + dmu * 20,
129
- xtol=xtol,
130
- )
131
-
132
- if np.abs(self.root_function(mu)) > xtol * 1e4:
133
- # raise RuntimeError(
134
- # 'Fermi level could not be assigned reliably. Has the system fragmented?'
135
- # )
136
- print(
137
- "Fermi level could not be assigned reliably. Has the system fragmented?"
138
- )
139
-
140
- f = self.fermi(mu)
141
- # rho=(self.eigenvecs*f).dot(self.eigenvecs.transpose())
142
-
143
- self.mu, self.f = mu, f
144
- return f
145
-
146
- def plot(self):
147
- import pylab as pl
148
-
149
- for ik in range(self.nk):
150
- pl.plot(self.e[ik, :], self.f[ik, :])
151
- pl.scatter(self.e[ik, :], self.f[ik, :])
152
- pl.title("occupations")
153
- pl.xlabel("energy (Ha)")
154
- pl.ylabel("occupation")
155
- pl.show()
156
-
157
-
158
- class GaussOccupations(Occupations):
159
- def get_mu(self):
160
- return self.mu
161
-
162
- def delta(self, energy):
163
- """Return a delta-function centered at 'energy'."""
164
- x = -(((self.e - energy) / self.width) ** 2)
165
- return np.exp(x) / (np.sqrt(np.pi) * self.width)
166
-
167
- def get_dos(self, npts=500):
168
- eflat = self.e.flatten()
169
- ind = np.argsort(eflat)
170
- ##e_sorted = eflat[ind]
171
- if self.nspin == 1:
172
- m = 2
173
- elif self.nspin == 2:
174
- m = 1
175
- # n_sorted = (self.wk * np.ones_like(self.e) * m).flatten()[ind]
176
- dos = np.zeros(npts)
177
- for w, e_n in zip(self.w_k, self.e_skn[0]):
178
- for e in e_n:
179
- dos += w * self.delta(e)
180
-
181
- def root_function(self, mu):
182
- pass
183
-
184
- # @profile
185
- def occupy(self, e, xtol=1e-8, guess=0.0):
186
- self.e = e
187
- dos = myDOS(kweights=self.wk, eigenvalues=e, width=self.width, npts=501)
188
- edos = dos.get_energies()
189
- d = dos.get_dos()
190
- idos = integrate.cumtrapz(d, edos, initial=0) - self.nel
191
- # f_idos = interpolate.interp1d(edos, idos)
192
- # ret = optimize.fmin(f_idos, x0=edos[400], xtol=xtol, disp=True)
193
- ifermi = np.searchsorted(idos, 0.0)
194
- # self.mu = ret[0]
195
- self.mu = edos[ifermi]
196
- self.f = self.fermi(self.mu)
197
- return self.f
198
-
199
-
200
- class myDOS(DOS):
201
- def __init__(
202
- self, kweights, eigenvalues, nspin=1, width=0.1, window=None, npts=1001
203
- ):
204
- """Electronic Density Of States object.
205
-
206
- calc: calculator object
207
- Any ASE compliant calculator object.
208
- width: float
209
- Width of guassian smearing. Use width=0.0 for linear tetrahedron
210
- interpolation.
211
- window: tuple of two float
212
- Use ``window=(emin, emax)``. If not specified, a window
213
- big enough to hold all the eigenvalues will be used.
214
- npts: int
215
- Number of points.
216
-
217
- """
218
- self.npts = npts
219
- self.width = width
220
- # self.w_k = calc.get_k_point_weights()
221
- self.w_k = kweights
222
- self.nspins = nspin
223
- # self.e_skn = np.array([[calc.get_eigenvalues(kpt=k, spin=s)
224
- # for k in range(len(self.w_k))]
225
- # for s in range(self.nspins)])
226
- # self.e_skn -= calc.get_fermi_level()
227
- self.e_skn = np.array([eigenvalues.T]) # eigenvalues: iband, ikpt
228
-
229
- if window is None:
230
- emin = None
231
- emax = None
232
- else:
233
- emin, emax = window
234
-
235
- if emin is None:
236
- emin = self.e_skn.min() - 10 * self.width
237
- if emax is None:
238
- emax = self.e_skn.max() + 10 * self.width
239
-
240
- self.energies = np.linspace(emin, emax, npts)
241
-
242
- # if width == 0.0: # To use tetrahedron method
243
- # bzkpts = calc.get_bz_k_points()
244
- # size, offset = get_monkhorst_pack_size_and_offset(bzkpts)
245
- # bz2ibz = calc.get_bz_to_ibz_map()
246
- # shape = (self.nspins,) + tuple(size) + (-1,)
247
- # self.e_skn = self.e_skn[:, bz2ibz].reshape(shape)
248
- # self.cell = calc.atoms.cell
249
-
250
- def get_idos(self):
251
- e, d = self.get_dos()
252
- return np.trapz(d, e)
253
-
254
- def delta(self, energy):
255
- """Return a delta-function centered at 'energy'."""
256
- x = -(((self.energies - energy) / self.width) ** 2)
257
- return np.exp(x) / (np.sqrt(np.pi) * self.width)
258
-
259
- def get_dos(self, spin=None):
260
- """Get array of DOS values.
261
-
262
- The *spin* argument can be 0 or 1 (spin up or down) - if not
263
- specified, the total DOS is returned.
264
- """
265
-
266
- if spin is None:
267
- if self.nspins == 2:
268
- # Spin-polarized calculation, but no spin specified -
269
- # return the total DOS:
270
- return self.get_dos(spin=0) + self.get_dos(spin=1)
271
- else:
272
- spin = 0
273
-
274
- dos = np.zeros(self.npts)
275
- for w, e_n in zip(self.w_k, self.e_skn[spin]):
276
- for e in e_n:
277
- dos += w * self.delta(e)
278
- return dos
TB2J/cut_cell.py DELETED
@@ -1,82 +0,0 @@
1
- import numpy as np
2
- from TB2J.supercell import find_primitive_cell, map_to_primitive
3
- from TB2J.io_exchange.io_exchange import SpinIO, gen_distance_dict
4
-
5
-
6
- def cut_cell(path, output_path, sc_matrix, origin_atom_id, thr=1e-5):
7
- """
8
- Cut the exchange parameters
9
- :param path: the original TB2J_results path
10
- :param output_path: the output path.
11
- :param sc_matrix: the matrix which maps the primitive cell to supercell.
12
- :param origin: the origin of the primitive cell.
13
- :param thr: the atoms which the reduced position is within -thr to 1.0+thr are considered as inside the primitive atoms
14
- :returns:
15
- """
16
- sc_matrix = np.asarray(sc_matrix, dtype=int)
17
- sc_excparams = SpinIO.load_pickle(path=path, fname='TB2J.pickle')
18
- sc_atoms = sc_excparams.atoms
19
- uc_atoms, ids = find_primitive_cell(sc_atoms,
20
- sc_matrix,
21
- origin_atom_id=origin_atom_id,
22
- thr=thr,
23
- perfect=False)
24
- uc_charges = sc_excparams.charges[ids]
25
- uc_spinat = sc_excparams.spinat[ids]
26
- indmap, Rmap = map_to_primitive(sc_atoms, uc_atoms)
27
-
28
- # TODO index_spin: {iatom: ispin}
29
-
30
- # list of iatom for each spin index.
31
- uc_index_spin = [sc_excparams.index_spin[i] for i in ids]
32
-
33
- uc_ind_atoms = {}
34
- for iatom, ispin in enumerate(uc_index_spin):
35
- if ispin >= 0:
36
- uc_ind_atoms[ispin] = iatom
37
-
38
- uc_Jdict = {}
39
- uc_Rset = set()
40
- for key, val in sc_excparams.exchange_Jdict.items():
41
- R, ispin, jspin = key
42
- iatom = sc_excparams.ind_atoms[ispin]
43
- jatom = sc_excparams.ind_atoms[jspin]
44
- uc_ispin = uc_index_spin[indmap[iatom]]
45
- uc_jspin = uc_index_spin[indmap[jatom]]
46
- uc_R = R @ sc_matrix + Rmap[jatom] - Rmap[iatom]
47
- uc_R = tuple(uc_R)
48
- if iatom in ids:
49
- #print(f"{iatom=}, {indmap[iatom]=},{uc_ispin=}, {uc_jspin=}, {uc_R=} ")
50
- uc_Jdict[(uc_R, uc_ispin, uc_jspin)] = val
51
- uc_Rset.add(uc_R)
52
-
53
- uc_distance_dict = gen_distance_dict(uc_ind_atoms, uc_atoms, list(uc_Rset))
54
-
55
- assert sc_excparams.colinear, "Cut supercell for non-collinear spin is not yet implemented."
56
-
57
- uc_exc = SpinIO(uc_atoms,
58
- spinat=uc_spinat,
59
- charges=uc_charges,
60
- index_spin=uc_index_spin,
61
- colinear=sc_excparams.colinear,
62
- distance_dict=uc_distance_dict,
63
- exchange_Jdict=uc_Jdict,
64
- description="Cutted")
65
-
66
- uc_exc.write_all(output_path)
67
-
68
-
69
- def run_cut_cell(
70
- path="TB2J_results",
71
- output_path="./TB2J_cutted",
72
- sc_matrix=np.array([[1, 1, 0], [-1, 1, 0], [0, 0, 2]]),
73
- ):
74
- cut_cell(path,
75
- output_path,
76
- np.array(sc_matrix),
77
- origin_atom_id=0,
78
- thr=1e-19)
79
-
80
-
81
- if __name__ == "__main__":
82
- run_cut_cell()
File without changes