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.
Files changed (59) hide show
  1. TB2J/MAE.py +144 -27
  2. TB2J/MAEGreen.py +84 -0
  3. TB2J/anisotropy.py +672 -0
  4. TB2J/contour.py +8 -0
  5. TB2J/exchange.py +38 -172
  6. TB2J/exchangeCL2.py +11 -13
  7. TB2J/exchange_params.py +213 -0
  8. TB2J/green.py +62 -27
  9. TB2J/interfaces/__init__.py +12 -0
  10. TB2J/interfaces/abacus/__init__.py +4 -0
  11. TB2J/{abacus → interfaces/abacus}/abacus_api.py +3 -3
  12. TB2J/{abacus → interfaces/abacus}/abacus_wrapper.py +11 -8
  13. TB2J/{abacus → interfaces/abacus}/gen_exchange_abacus.py +5 -3
  14. TB2J/{abacus → interfaces/abacus}/orbital_api.py +4 -4
  15. TB2J/{abacus → interfaces/abacus}/stru_api.py +11 -11
  16. TB2J/{abacus → interfaces/abacus}/test_read_HRSR.py +0 -1
  17. TB2J/{abacus → interfaces/abacus}/test_read_stru.py +5 -3
  18. TB2J/interfaces/gpaw_interface.py +54 -0
  19. TB2J/interfaces/lawaf_interface.py +129 -0
  20. TB2J/interfaces/manager.py +23 -0
  21. TB2J/interfaces/siesta_interface.py +202 -0
  22. TB2J/interfaces/wannier90_interface.py +115 -0
  23. TB2J/io_exchange/io_exchange.py +21 -7
  24. TB2J/io_merge.py +2 -1
  25. TB2J/mathutils/fermi.py +11 -6
  26. TB2J/mathutils/lowdin.py +12 -2
  27. TB2J/mathutils/rotate_spin.py +222 -4
  28. TB2J/pauli.py +11 -3
  29. TB2J/symmetrize_J.py +120 -0
  30. TB2J/utils.py +82 -1
  31. {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/abacus2J.py +5 -4
  32. {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/siesta2J.py +21 -4
  33. TB2J-0.9.7rc0.data/scripts/wann2J.py +96 -0
  34. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/METADATA +5 -3
  35. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/RECORD +47 -46
  36. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/WHEEL +1 -1
  37. TB2J-0.9.7rc0.dist-info/entry_points.txt +3 -0
  38. TB2J/abacus/MAE.py +0 -320
  39. TB2J/abacus/__init__.py +0 -1
  40. TB2J/abacus/occupations.py +0 -278
  41. TB2J/cut_cell.py +0 -82
  42. TB2J/io_exchange/io_pickle.py +0 -0
  43. TB2J/manager.py +0 -445
  44. TB2J/mathutils.py +0 -12
  45. TB2J/patch.py +0 -50
  46. TB2J/spinham/h_matrix.py +0 -68
  47. TB2J/spinham/obtain_J.py +0 -79
  48. TB2J/supercell.py +0 -532
  49. TB2J-0.9.5rc0.data/scripts/wann2J.py +0 -194
  50. TB2J/{abacus → interfaces/abacus}/test_density_matrix.py +1 -1
  51. {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_downfold.py +0 -0
  52. {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_eigen.py +0 -0
  53. {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_magnon.py +0 -0
  54. {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_magnon_dos.py +0 -0
  55. {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_merge.py +0 -0
  56. {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_rotate.py +0 -0
  57. {TB2J-0.9.5rc0.data → TB2J-0.9.7rc0.data}/scripts/TB2J_rotateDM.py +0 -0
  58. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/LICENSE +0 -0
  59. {TB2J-0.9.5rc0.dist-info → TB2J-0.9.7rc0.dist-info}/top_level.txt +0 -0
TB2J/manager.py DELETED
@@ -1,445 +0,0 @@
1
- import os
2
- from TB2J.myTB import MyTB, merge_tbmodels_spin
3
- import numpy as np
4
- from TB2J.exchange import ExchangeNCL
5
- from TB2J.exchangeCL2 import ExchangeCL2
6
- from TB2J.exchange_qspace import ExchangeCLQspace
7
- from TB2J.utils import read_basis, auto_assign_basis_name
8
- from ase.io import read
9
-
10
- # from TB2J.sisl_wrapper import SislWrapper
11
-
12
- from HamiltonIO.siesta import SislParser
13
- try:
14
- from HamiltonIO.siesta import SislParser
15
- except ImportError:
16
- print(
17
- "Cannot import SislWrapper from HamiltonIO.siesta. Please install HamiltonIO first."
18
- )
19
- from TB2J.sisl_wrapper import SislWrapper
20
- from TB2J.gpaw_wrapper import GPAWWrapper
21
- from TB2J.wannier import parse_atoms
22
-
23
-
24
- def gen_exchange(
25
- path,
26
- colinear=True,
27
- groupby="spin",
28
- posfile=None,
29
- prefix_up="wannier90.up",
30
- prefix_dn="wannier90.dn",
31
- prefix_SOC="wannier90",
32
- min_hopping_norm=1e-4,
33
- max_distance=None,
34
- efermi=0,
35
- magnetic_elements=[],
36
- kmesh=[4, 4, 4],
37
- emin=-12.0,
38
- emax=0.0,
39
- nz=100,
40
- exclude_orbs=[],
41
- Rcut=None,
42
- ne=None,
43
- use_cache=False,
44
- np=1,
45
- output_path="TB2J_results",
46
- wannier_type="wannier90",
47
- qspace=False,
48
- orb_decomposition=False,
49
- write_density_matrix=False,
50
- description="",
51
- ):
52
- try:
53
- fname = os.path.join(path, posfile)
54
- print(f"Reading atomic structure from file {fname}.")
55
- atoms = read(os.path.join(path, posfile))
56
- except Exception:
57
- print(
58
- f"Cannot read atomic structure from file {fname}. Trying to read from Wannier input."
59
- )
60
- if colinear:
61
- fname = os.path.join(path, f"{prefix_up}.win")
62
- else:
63
- fname = os.path.join(path, f"{prefix_SOC}.win")
64
-
65
- print(f"Reading atomic structure from file {fname}.")
66
- atoms = parse_atoms(fname)
67
-
68
- basis_fname = os.path.join(path, "basis.txt")
69
- if colinear:
70
- if wannier_type.lower() == "wannier90":
71
- print("Reading Wannier90 hamiltonian: spin up.")
72
- tbmodel_up = MyTB.read_from_wannier_dir(
73
- path=path, prefix=prefix_up, atoms=atoms, nls=False
74
- )
75
- print("Reading Wannier90 hamiltonian: spin down.")
76
- tbmodel_dn = MyTB.read_from_wannier_dir(
77
- path=path, prefix=prefix_dn, atoms=atoms, nls=False
78
- )
79
- if os.path.exists(basis_fname):
80
- basis = read_basis(basis_fname)
81
- else:
82
- basis, _ = auto_assign_basis_name(
83
- tbmodel_up.xred,
84
- atoms,
85
- write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
86
- )
87
- elif wannier_type.lower() == "banddownfolder":
88
- print("Reading Banddownfolder hamiltonian: spin up.")
89
- tbmodel_up = MyTB.load_banddownfolder(
90
- path=path, prefix=prefix_up, atoms=atoms, nls=False
91
- )
92
- print("Reading Banddownfolder hamiltonian: spin down.")
93
- tbmodel_dn = MyTB.load_banddownfolder(
94
- path=path, prefix=prefix_dn, atoms=atoms, nls=False
95
- )
96
-
97
- basis, _ = auto_assign_basis_name(
98
- tbmodel_up.xred,
99
- atoms,
100
- write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
101
- )
102
- else:
103
- raise ValueError("wannier_type should be Wannier90 or banddownfolder.")
104
-
105
- print("Starting to calculate exchange.")
106
- description = f""" Input from collinear Wannier90 data.
107
- Tight binding data from {path}.
108
- Prefix of wannier function files:{prefix_up} and {prefix_dn}.
109
- Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
110
- \n"""
111
- if not qspace:
112
- exchange = ExchangeCL2(
113
- tbmodels=(tbmodel_up, tbmodel_dn),
114
- atoms=atoms,
115
- basis=basis,
116
- efermi=efermi,
117
- magnetic_elements=magnetic_elements,
118
- kmesh=kmesh,
119
- emin=emin,
120
- emax=emax,
121
- nz=nz,
122
- exclude_orbs=exclude_orbs,
123
- Rcut=Rcut,
124
- ne=ne,
125
- np=np,
126
- use_cache=use_cache,
127
- output_path=output_path,
128
- write_density_matrix=write_density_matrix,
129
- description=description,
130
- )
131
- else:
132
- exchange = ExchangeCLQspace(
133
- tbmodels=(tbmodel_up, tbmodel_dn),
134
- atoms=atoms,
135
- basis=basis,
136
- efermi=efermi,
137
- magnetic_elements=magnetic_elements,
138
- kmesh=kmesh,
139
- emin=emin,
140
- emax=emax,
141
- nz=nz,
142
- exclude_orbs=exclude_orbs,
143
- Rcut=Rcut,
144
- ne=ne,
145
- np=np,
146
- use_cache=use_cache,
147
- output_path=output_path,
148
- write_density_matrix=write_density_matrix,
149
- description=description,
150
- )
151
-
152
- exchange.run(path=output_path)
153
- print("All calculation finsihed. The results are in TB2J_results directory.")
154
-
155
- elif colinear and wannier_type.lower() == "banddownfolder":
156
- print("Reading Wannier90 hamiltonian: spin up.")
157
- tbmodel_up = MyTB.read_from_wannier_dir(
158
- path=path, prefix=prefix_up, atoms=atoms, groupby=None, nls=False
159
- )
160
- print("Reading Wannier90 hamiltonian: spin down.")
161
- tbmodel_dn = MyTB.read_from_wannier_dir(
162
- path=path, prefix=prefix_dn, atoms=atoms, groupby=None, nls=False
163
- )
164
- tbmodel = merge_tbmodels_spin(tbmodel_up, tbmodel_dn)
165
- basis, _ = auto_assign_basis_name(
166
- tbmodel.xred,
167
- atoms,
168
- write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
169
- )
170
- description = f""" Input from collinear BandDownfolder data.
171
- Tight binding data from {path}.
172
- Prefix of wannier function files:{prefix_up} and {prefix_dn}.
173
- Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
174
- \n"""
175
- print("Starting to calculate exchange.")
176
- exchange = ExchangeCL2(
177
- tbmodels=tbmodel,
178
- atoms=atoms,
179
- basis=basis,
180
- efermi=efermi,
181
- magnetic_elements=magnetic_elements,
182
- kmesh=kmesh,
183
- emin=emin,
184
- emax=emax,
185
- nz=nz,
186
- exclude_orbs=exclude_orbs,
187
- Rcut=Rcut,
188
- ne=ne,
189
- np=np,
190
- use_cache=use_cache,
191
- output_path=output_path,
192
- write_density_matrix=write_density_matrix,
193
- description=description,
194
- )
195
- exchange.run(path=output_path)
196
- print("All calculation finsihed. The results are in TB2J_results directory.")
197
- else:
198
- print("Reading Wannier90 hamiltonian: non-colinear spin.")
199
- groupby = groupby.lower().strip()
200
- if groupby not in ["spin", "orbital"]:
201
- raise ValueError("groupby can only be spin or orbital.")
202
- tbmodel = MyTB.read_from_wannier_dir(
203
- path=path, prefix=prefix_SOC, atoms=atoms, groupby=groupby, nls=True
204
- )
205
- if os.path.exists(basis_fname):
206
- print("The use of basis file is deprecated. It will be ignored.")
207
- # basis = read_basis(basis_fname)
208
- else:
209
- basis, _ = auto_assign_basis_name(
210
- tbmodel.xred,
211
- atoms,
212
- write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
213
- )
214
- description = f""" Input from non-collinear Wannier90 data.
215
- Tight binding data from {path}.
216
- Prefix of wannier function files:{prefix_SOC}.
217
- Warning: Please check if the noise level of Wannier function Hamiltonian to make sure it is much smaller than the exchange values.
218
- The DMI component parallel to the spin orientation, the Jani which has the component of that orientation should be disregarded
219
- e.g. if the spins are along z, the xz, yz, zz, zx, zy components and the z component of DMI.
220
- If you need these component, try to do three calculations with spin along x, y, z, or use structure with z rotated to x, y and z. And then use TB2J_merge.py to get the full set of parameters.
221
-
222
- \n"""
223
- print("Starting to calculate exchange.")
224
- exchange = ExchangeNCL(
225
- tbmodels=tbmodel,
226
- atoms=atoms,
227
- basis=basis,
228
- efermi=efermi,
229
- magnetic_elements=magnetic_elements,
230
- kmesh=kmesh,
231
- emin=emin,
232
- emax=emax,
233
- nz=nz,
234
- exclude_orbs=exclude_orbs,
235
- Rcut=Rcut,
236
- ne=ne,
237
- np=np,
238
- use_cache=use_cache,
239
- description=description,
240
- output_path=output_path,
241
- write_density_matrix=write_density_matrix,
242
- orb_decomposition=orb_decomposition,
243
- )
244
- print("\n")
245
- exchange.run(path=output_path)
246
- print(f"All calculation finsihed. The results are in {output_path} directory.")
247
-
248
-
249
- def gen_exchange_siesta(
250
- fdf_fname,
251
- magnetic_elements=[],
252
- include_orbs=None,
253
- kmesh=[5, 5, 5],
254
- emin=-12.0,
255
- emax=0.0,
256
- nz=100,
257
- exclude_orbs=[],
258
- Rcut=None,
259
- ne=None,
260
- np=1,
261
- use_cache=False,
262
- output_path="TB2J_results",
263
- orb_decomposition=False,
264
- description="",
265
- ):
266
- try:
267
- import sisl
268
- except:
269
- raise ImportError("sisl cannot be imported. Please install sisl first.")
270
-
271
- from packaging import version
272
-
273
- if version.parse(sisl.__version__) <= version.parse("0.10.0"):
274
- raise ImportError(
275
- f"sisl version is {sisl.__version__}, but should be larger than 0.10.0."
276
- )
277
-
278
- include_orbs = {}
279
- if isinstance(magnetic_elements, str):
280
- magnetic_elements = [magnetic_elements]
281
- for element in magnetic_elements:
282
- if "_" in element:
283
- elem = element.split("_")[0]
284
- orb = element.split("_")[1:]
285
- include_orbs[elem] = orb
286
- else:
287
- include_orbs[element] = None
288
- magnetic_elements = list(include_orbs.keys())
289
-
290
- #fdf = sisl.get_sile(fdf_fname)
291
- # geom = fdf.read_geometry()
292
- #H = fdf.read_hamiltonian()
293
- #geom = H.geometry
294
- parser=SislParser(fdf_fname=fdf_fname, ispin=None, read_H_soc=False)
295
- if parser.spin.is_colinear:
296
- print("Reading Siesta hamiltonian: colinear spin.")
297
- #tbmodel_up = SislWrapper(fdf_fname=None, sisl_hamiltonian=H, spin=0, geom=geom)
298
- #tbmodel_dn = SislWrapper(fdf_fname=None, sisl_hamiltonian=H, spin=1, geom=geom)
299
- tbmodel_up, tbmodel_dn = parser.get_model()
300
- basis = dict(zip(tbmodel_up.orbs, list(range(tbmodel_up.norb))))
301
- print("Starting to calculate exchange.")
302
- description = f""" Input from collinear Siesta data.
303
- working directory: {os.getcwd()}
304
- fdf_fname: {fdf_fname}.
305
- \n"""
306
- exchange = ExchangeCL2(
307
- tbmodels=(tbmodel_up, tbmodel_dn),
308
- atoms=tbmodel_up.atoms,
309
- basis=basis,
310
- efermi=0.0,
311
- magnetic_elements=magnetic_elements,
312
- include_orbs=include_orbs,
313
- kmesh=kmesh,
314
- emin=emin,
315
- emax=emax,
316
- nz=nz,
317
- exclude_orbs=exclude_orbs,
318
- Rcut=Rcut,
319
- ne=ne,
320
- np=np,
321
- use_cache=use_cache,
322
- output_path=output_path,
323
- description=description,
324
- )
325
- exchange.run(path=output_path)
326
- print("\n")
327
- print(f"All calculation finsihed. The results are in {output_path} directory.")
328
-
329
- elif parser.spin.is_colinear and False:
330
- print(
331
- "Reading Siesta hamiltonian: colinear spin. Treat as non-colinear. For testing only."
332
- )
333
- tbmodel = SislWrapper(H, spin="merge", geom=geom)
334
- basis = dict(zip(tbmodel.orbs, list(range(tbmodel.nbasis))))
335
- print("Starting to calculate exchange.")
336
- description = f""" Input from collinear Siesta data.
337
- working directory: {os.getcwd()}
338
- fdf_fname: {fdf_fname}.
339
- \n"""
340
- exchange = ExchangeNCL(
341
- tbmodels=tbmodel,
342
- atoms=tbmodel.atoms,
343
- basis=basis,
344
- efermi=0.0,
345
- magnetic_elements=magnetic_elements,
346
- include_orbs=include_orbs,
347
- kmesh=kmesh,
348
- emin=emin,
349
- emax=emax,
350
- nz=nz,
351
- exclude_orbs=exclude_orbs,
352
- Rcut=Rcut,
353
- ne=ne,
354
- np=np,
355
- use_cache=use_cache,
356
- description=description,
357
- output_path=output_path,
358
- orb_decomposition=orb_decomposition,
359
- )
360
- exchange.run(path=output_path)
361
- print("\n")
362
- print(f"All calculation finsihed. The results are in {output_path} directory.")
363
-
364
- elif parser.spin.is_spinorbit or H.spin.is_noncolinear:
365
- print("Reading Siesta hamiltonian: non-colinear spin.")
366
- model = parser.get_model()
367
- basis = dict(zip(model.orbs, list(range(model.nbasis))))
368
- print("Starting to calculate exchange.")
369
- description = f""" Input from non-collinear Siesta data.
370
- working directory: {os.getcwd()}
371
- fdf_fname: {fdf_fname}.
372
- Warning: The DMI component parallel to the spin orientation, the Jani which has the component of that orientation should be disregarded
373
- e.g. if the spins are along z, the xz, yz, zz, zx, zy components and the z component of DMI.
374
- If you need these component, try to do three calculations with spin along x, y, z, or use structure with z rotated to x, y and z. And then use TB2J_merge.py to get the full set of parameters.
375
- \n"""
376
- exchange = ExchangeNCL(
377
- tbmodels=model,
378
- atoms=model.atoms,
379
- basis=basis,
380
- efermi=0.0,
381
- magnetic_elements=magnetic_elements,
382
- include_orbs=include_orbs,
383
- kmesh=kmesh,
384
- emin=emin,
385
- emax=emax,
386
- nz=nz,
387
- exclude_orbs=exclude_orbs,
388
- Rcut=Rcut,
389
- ne=ne,
390
- np=np,
391
- use_cache=use_cache,
392
- description=description,
393
- output_path=output_path,
394
- orb_decomposition=orb_decomposition,
395
- )
396
- exchange.run(path=output_path)
397
- print("\n")
398
- print(f"All calculation finsihed. The results are in {output_path} directory.")
399
-
400
-
401
- def gen_exchange_gpaw(
402
- gpw_fname,
403
- magnetic_elements=[],
404
- kmesh=[3, 3, 3],
405
- emin=-12.0,
406
- emax=0.0,
407
- nz=50,
408
- exclude_orbs=[],
409
- Rcut=None,
410
- use_cache=False,
411
- output_path="TB2J_results",
412
- description="",
413
- ):
414
- print("Reading from GPAW data and calculate electronic structure.")
415
- model = GPAWWrapper(gpw_fname=gpw_fname)
416
- efermi = model.calc.get_fermi_level()
417
- print(f"Fermi Energy: {efermi}")
418
- poses = np.vstack([model.positions, model.positions])
419
- basis, _ = auto_assign_basis_name(
420
- poses,
421
- model.atoms,
422
- write_basis_file=os.path.join(output_path, "assigned_basis.txt"),
423
- )
424
-
425
- if model.calc.get_spin_polarized():
426
- print("Starting to calculate exchange.")
427
- exchange = ExchangeNCL(
428
- tbmodels=model,
429
- atoms=model.atoms,
430
- efermi=efermi,
431
- basis=basis,
432
- magnetic_elements=magnetic_elements,
433
- kmesh=kmesh,
434
- emin=emin,
435
- emax=emax,
436
- nz=nz,
437
- exclude_orbs=exclude_orbs,
438
- Rcut=Rcut,
439
- use_cache=use_cache,
440
- output_path=output_path,
441
- description=description,
442
- )
443
- exchange.run(path=output_path)
444
- print("\n")
445
- print(f"All calculation finsihed. The results are in {output_path} directory.")
TB2J/mathutils.py DELETED
@@ -1,12 +0,0 @@
1
- import numpy as np
2
- from scipy.linalg import inv, eigh
3
-
4
-
5
- def Lowdin(S):
6
- """
7
- Calculate S^(-1/2).
8
- Which is used in lowind's symmetric orthonormalization.
9
- psi_prime = S^(-1/2) psi
10
- """
11
- eigval, eigvec = eigh(S)
12
- return eigvec @ np.diag(np.sqrt(1.0 / eigval)) @ (eigvec.T.conj())
TB2J/patch.py DELETED
@@ -1,50 +0,0 @@
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'>
TB2J/spinham/h_matrix.py DELETED
@@ -1,68 +0,0 @@
1
- import numpy as np
2
- import matplotlib.pyplot as plt
3
- import aiida
4
- from aiida_tb2j.data import ExchangeData
5
-
6
- def plot_dispersion(bands, kpoint_labels, color='blue', title=None):
7
-
8
- fig, axs = plt.subplots(1, 1, constrained_layout=True)
9
- fig.set_size_inches(6, 6/1.618)
10
-
11
- '''
12
- Plot the bands
13
- '''
14
- kpoints = np.arange(len(bands))
15
- axs.plot(kpoints, bands, color=color, linewidth=1.5)
16
-
17
- '''
18
- Plot the symmetry points
19
- '''
20
- bmin = bands.min(); bmax = bands.max()
21
- ymin = bmin - 0.05*np.abs(bmin-bmax); ymax = bmax + 0.05*np.abs(bmax-bmin);
22
- axs.set_xticks(kpoint_labels[0], kpoint_labels[1], fontsize=10)
23
- axs.vlines(x=kpoint_labels[0], ymin=ymin, ymax=ymax, color='black', linewidth=0.5)
24
- axs.set_xlim([0, len(kpoints)])
25
- axs.set_ylim([ymin, ymax])
26
-
27
- if title is not None:
28
- plt.title(title, fontsize=10)
29
-
30
- plt.show()
31
-
32
-
33
- if __name__ == "__main__":
34
-
35
- from argparse import ArgumentParser
36
-
37
- parser = ArgumentParser()
38
- parser.add_argument('-f', '--pickle_filename', type=str, help="Path of the 'TB2J.pickle' file.", required=True)
39
- args = parser.parse_args()
40
-
41
- '''
42
- Right now the implementation depends on AiiDA and so we must create and load an AiiDA profile,
43
- even if we do not store any information on a data base.
44
- '''
45
- aiida.load_profile()
46
- '''
47
- Create an ExchangeData object with the informations from the TB2J.pickle file
48
- '''
49
- exchange = ExchangeData.load_tb2j(pickle_file=args.pickle_filename, isotropic=False, pbc=(True, True, True))
50
- '''
51
- Compute the magnon band structure along a high symmetry path generated with
52
- the ASE package. The informations is stored in an AiiDA BandsData object.
53
- Here tol is the symmetry tolerance to determine the space group of the system.
54
- They are in units of eV
55
- '''
56
- magnon_data = exchange.get_magnon_bands(npoints=300, tol=1e-1, with_DMI=True, with_Jani=True)
57
- magnon_bands = 1000*magnon_data.get_bands() # Convert to meV
58
- raw_labels = [(k, '$\Gamma$') if s == 'GAMMA' else (k, s) for k, s in magnon_data.labels]
59
- kpoint_labels = list( zip( *raw_labels ) )
60
- plot_dispersion(magnon_bands, kpoint_labels, color='blue', title='Magnon Bands')
61
- '''
62
- We can also obtain the dynamical matrix h instead of the actual magnon bands. The result
63
- is stored in a numpy array with shape (number of kpoints, 2*natoms, 2*natoms)
64
- '''
65
- kpoints = magnon_data.get_kpoints() # The shape of the kpoints must be (nkpoints, 3)
66
- h_matrix = 1000*exchange._H_matrix(kpoints, with_DMI=True, with_Jani=True) # Convert to meV
67
- h_dispersion = np.linalg.eigvalsh(h_matrix) # We can also get the eigenvectors with np.linalg.eigh
68
- plot_dispersion(h_dispersion, kpoint_labels, color='red', title='h matrix dispersion')
TB2J/spinham/obtain_J.py DELETED
@@ -1,79 +0,0 @@
1
- import numpy as np
2
- from aiida_tb2j.data import ExchangeData
3
- from aiida_tb2j.data.exchange import get_rotation_arrays
4
- from itertools import combinations_with_replacement
5
-
6
- ux, uy, uz = np.eye(3).reshape((3, 1, 3))
7
-
8
- def combine_arrays(u, v):
9
-
10
- return np.concatenate([u*v, np.roll(u, -1, axis=-1)*v, np.roll(v, -1, axis=-1)*u], axis=-1)
11
-
12
- def get_coefficients(magmoms, indices):
13
-
14
- i, j = indices
15
-
16
- U, V = zip(*[get_rotation_arrays(magmoms, u=u) for u in [ux, uy, uz]])
17
- U = np.stack(U).swapaxes(0, 1)
18
- V = np.stack(V).swapaxes(0, 1)
19
-
20
- uc = combine_arrays(U[i], U[j].conj())
21
- ur = combine_arrays(U[i], U[j])
22
- uc2 = combine_arrays(U[i].conj(), U[j])
23
- u = np.concatenate([uc, ur, uc2], axis=1)
24
-
25
- return u, V
26
-
27
- def get_C(H0, u, V):
28
-
29
- n = int(H0.shape[-1]/2)
30
- upi = np.triu_indices(n)
31
- dig = np.diag_indices(n)
32
-
33
- i, j = upi
34
- AB0 = H0[:, [i, i, i+n], [j, j+n, j+n]]
35
- AB0 = np.swapaxes(AB0, 0, 2).reshape(len(i), 9)
36
- J0_flat = np.linalg.solve(u, AB0)
37
-
38
- J0 = np.empty((n, n, 3, 3), dtype=complex)
39
- J0[*upi] = J0_flat[:, [0, 6, 5, 3, 1, 7, 8, 4, 2]].reshape(-1, 3, 3)
40
- J0 += J0.swapaxes(0, 1)
41
- J0[*dig] = 0.0
42
-
43
- C = np.array([np.diag(a) for a in np.einsum('imx,ijxy,jmy->mi', V, 2*J0, V)])
44
-
45
- return C
46
-
47
- def get_J(H, kpoints, exchange):
48
-
49
- n = int(H.shape[-1]/2)
50
- upi = np.triu_indices(n)
51
- dig = np.diag_indices(n)
52
- i, j = upi
53
-
54
- magmoms = exchange.magmoms()[np.unique(exchange.pairs)]
55
- magmoms /= np.linalg.norm(magmoms, axis=-1).reshape(-1, 1)
56
- u, V = get_coefficients(magmoms, indices=upi)
57
-
58
- H0 = np.stack([1000*exchange._H_matrix(kpoints=np.zeros((1, 3)), with_DMI=True, with_Jani=True, u=u) for u in [ux, uy, uz]])[:, 0, :, :]
59
- C = get_C(H0, u, V)
60
- H[:, :, :n, :n] += C.reshape(3, 1, n, n)
61
- H[:, :, n:, n:] += C.reshape(3, 1, n, n)
62
-
63
- AB = H[:, :, [i, i, i+n], [j, j+n, j+n]]
64
- AB[:, :, 2, :] = AB[:, ::-1, 2, :]
65
- AB = np.moveaxis(AB, [2, 3], [1, 0]).reshape(len(i), 9, -1)
66
-
67
- vectors = exchange.get_vectors()
68
- exp_summand = np.exp( -2j*np.pi*vectors @ kpoints.T )
69
- nAB = np.einsum('nik,ndk->nid', AB, exp_summand) / len(kpoints)
70
-
71
- ii = np.where(i == j)
72
- i0 = np.where(np.linalg.norm(vectors, axis=-1) == 0.0)
73
- J = np.linalg.solve(u, nAB).swapaxes(1, 2)
74
- J = J[:, :, [0, 6, 5, 3, 1, 7, 8, 4, 2]].reshape(len(i), -1, 3, 3)
75
- J *= -1
76
- J[ii] *= 2
77
- J[i0] *= 0
78
-
79
- return J