TB2J 0.9.8rc0__tar.gz → 0.9.9rc0__tar.gz

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 (100) hide show
  1. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/PKG-INFO +1 -1
  2. tb2j-0.9.9rc0/TB2J/MAEGreen.py +197 -0
  3. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/exchange.py +17 -6
  4. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/exchange_params.py +27 -2
  5. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/abacus/abacus_wrapper.py +1 -0
  6. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/abacus/gen_exchange_abacus.py +5 -3
  7. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/abacus/orbital_api.py +10 -8
  8. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/siesta_interface.py +8 -20
  9. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/orbmap.py +18 -2
  10. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J.egg-info/PKG-INFO +1 -1
  11. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/abacus2J.py +5 -11
  12. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/siesta2J.py +12 -10
  13. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/setup.py +1 -1
  14. tb2j-0.9.8rc0/TB2J/MAEGreen.py +0 -84
  15. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/LICENSE +0 -0
  16. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/README.md +0 -0
  17. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/Jdownfolder.py +0 -0
  18. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/Jtensor.py +0 -0
  19. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/MAE.py +0 -0
  20. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/Oiju.py +0 -0
  21. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/Oiju_epc.py +0 -0
  22. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/__init__.py +0 -0
  23. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/anisotropy.py +0 -0
  24. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/basis.py +0 -0
  25. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/citation.py +0 -0
  26. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/contour.py +0 -0
  27. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/density_matrix.py +0 -0
  28. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/epc.py +0 -0
  29. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/exchangeCL2.py +0 -0
  30. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/exchange_pert.py +0 -0
  31. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/exchange_qspace.py +0 -0
  32. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/external/__init__.py +0 -0
  33. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/external/p_tqdm.py +0 -0
  34. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/gpaw_wrapper.py +0 -0
  35. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/green.py +0 -0
  36. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/greentest.py +0 -0
  37. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/__init__.py +0 -0
  38. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/abacus/__init__.py +0 -0
  39. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/abacus/abacus_api.py +0 -0
  40. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/abacus/stru_api.py +0 -0
  41. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/abacus/test_density_matrix.py +0 -0
  42. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/abacus/test_read_HRSR.py +0 -0
  43. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/abacus/test_read_stru.py +0 -0
  44. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/gpaw_interface.py +0 -0
  45. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/lawaf_interface.py +0 -0
  46. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/manager.py +0 -0
  47. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/interfaces/wannier90_interface.py +0 -0
  48. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/io_exchange/__init__.py +0 -0
  49. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/io_exchange/io_exchange.py +0 -0
  50. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/io_exchange/io_multibinit.py +0 -0
  51. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/io_exchange/io_tomsasd.py +0 -0
  52. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/io_exchange/io_txt.py +0 -0
  53. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/io_exchange/io_uppasd.py +0 -0
  54. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/io_exchange/io_vampire.py +0 -0
  55. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/io_merge.py +0 -0
  56. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/kpoints.py +0 -0
  57. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/mathutils/__init__.py +0 -0
  58. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/mathutils/fermi.py +0 -0
  59. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/mathutils/kR_convert.py +0 -0
  60. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/mathutils/lowdin.py +0 -0
  61. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/mathutils/rotate_spin.py +0 -0
  62. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/myTB.py +0 -0
  63. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/pauli.py +0 -0
  64. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/pert.py +0 -0
  65. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/plot.py +0 -0
  66. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/rotate_atoms.py +0 -0
  67. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/rotate_siestaDM.py +0 -0
  68. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/sisl_wrapper.py +0 -0
  69. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/__init__.py +0 -0
  70. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/base_parser.py +0 -0
  71. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/constants.py +0 -0
  72. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/hamiltonian.py +0 -0
  73. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/hamiltonian_terms.py +0 -0
  74. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/plot.py +0 -0
  75. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/qsolver.py +0 -0
  76. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/spin_api.py +0 -0
  77. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/spin_xml.py +0 -0
  78. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/spinham/supercell.py +0 -0
  79. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/symmetrize_J.py +0 -0
  80. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/tensor_rotate.py +0 -0
  81. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/utest.py +0 -0
  82. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/utils.py +0 -0
  83. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/versioninfo.py +0 -0
  84. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/wannier/__init__.py +0 -0
  85. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/wannier/w90_parser.py +0 -0
  86. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J/wannier/w90_tb_parser.py +0 -0
  87. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J.egg-info/SOURCES.txt +0 -0
  88. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J.egg-info/dependency_links.txt +0 -0
  89. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J.egg-info/entry_points.txt +0 -0
  90. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J.egg-info/requires.txt +0 -0
  91. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/TB2J.egg-info/top_level.txt +0 -0
  92. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/TB2J_downfold.py +0 -0
  93. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/TB2J_eigen.py +0 -0
  94. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/TB2J_magnon.py +0 -0
  95. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/TB2J_magnon_dos.py +0 -0
  96. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/TB2J_merge.py +0 -0
  97. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/TB2J_rotate.py +0 -0
  98. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/TB2J_rotateDM.py +0 -0
  99. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/scripts/wann2J.py +0 -0
  100. {tb2j-0.9.8rc0 → tb2j-0.9.9rc0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: TB2J
3
- Version: 0.9.8rc0
3
+ Version: 0.9.9rc0
4
4
  Summary: TB2J: First principle to Heisenberg exchange J using tight-binding Green function method
5
5
  Author: Xu He
6
6
  Author-email: mailhexu@gmail.com
@@ -0,0 +1,197 @@
1
+ from pathlib import Path
2
+
3
+ import numpy as np
4
+ import tqdm
5
+ from typing_extensions import DefaultDict
6
+
7
+ from HamiltonIO.abacus.abacus_wrapper import AbacusSplitSOCParser
8
+ from TB2J.exchange import ExchangeNCL
9
+
10
+ # from HamiltonIO.model.rotate_spin import rotate_Matrix_from_z_to_axis, rotate_Matrix_from_z_to_sperical
11
+ # from TB2J.abacus.abacus_wrapper import AbacusWrapper, AbacusParser
12
+ from TB2J.mathutils.rotate_spin import (
13
+ rotate_spinor_matrix,
14
+ )
15
+
16
+
17
+ class MAEGreen(ExchangeNCL):
18
+ def __init__(self, angles=[], **kwargs):
19
+ super().__init__(**kwargs)
20
+ self.natoms = len(self.atoms)
21
+ nangles = len(angles[0])
22
+ self.es = np.zeros(nangles, dtype=complex)
23
+ self.es_atom = np.zeros((nangles, self.natoms), dtype=complex)
24
+ self.es_atom_orb = DefaultDict(lambda: 0)
25
+ if angles is None or angles == "axis":
26
+ self.set_angles_axis()
27
+ elif angles == "scan":
28
+ self.set_angles_scan()
29
+ else:
30
+ self.thetas = angles[0]
31
+ self.phis = angles[1]
32
+
33
+ def set_angles_axis(self):
34
+ """theta and phi are defined as the x, y, z, axis."""
35
+ self.thetas = [0, np.pi / 2, np.pi / 2, np.pi / 2]
36
+ self.phis = [0, 0, np.pi / 2, np.pi / 4]
37
+
38
+ def set_angles_scan(self, step=15):
39
+ self.thetas = []
40
+ self.phis = []
41
+ for i in range(0, 181, step):
42
+ for j in range(0, 181, step):
43
+ self.thetas.append(i * np.pi / 180)
44
+ self.phis.append(j * np.pi / 180)
45
+
46
+ def get_perturbed(self, e, thetas, phis):
47
+ self.tbmodel.set_so_strength(0.0)
48
+ G0K = self.G.get_Gk_all(e)
49
+ Hsoc_k = self.tbmodel.get_Hk_soc(self.G.kpts)
50
+ na = len(thetas)
51
+ dE_angle = np.zeros(na, dtype=complex)
52
+ dE_angle_atom = np.zeros((na, self.natoms), dtype=complex)
53
+ # dE_angle_orbitals = np.zeros((na, self.natoms, self.norb, self.norb), dtype=complex)
54
+ # dE_angle_orbitals = DefaultDict(lambda: 0)
55
+ dE_angle_atom_orb = DefaultDict(lambda: 0)
56
+ for iangle, (theta, phi) in enumerate(zip(thetas, phis)):
57
+ for ik, dHk in enumerate(Hsoc_k):
58
+ dHi = rotate_spinor_matrix(dHk, theta, phi)
59
+ GdH = G0K[ik] @ dHi
60
+ # dE += np.trace(GdH @ G0K[i].T.conj() @ dHi) * self.kweights[i]
61
+ # diagonal of second order perturbation.
62
+ # dG2diag = np.diag(GdH @ GdH)
63
+ #dG2 = np.einsum("ij,ji->ij", GdH, GdH)
64
+ dG2 = GdH * GdH.T
65
+ dG2sum = np.sum(dG2)
66
+
67
+ # dG2diag = np.diag(GdH @G0K[i].T.conj() @ dHi)
68
+ #dE_angle[iangle] += np.trace(GdH@GdH) * self.G.kweights[ik]
69
+ #dE_angle[iangle] += np.trace(GdH@G0K[ik].T.conj()@dHi ) * self.G.kweights[ik]
70
+ dE_angle[iangle] += dG2sum * self.G.kweights[ik]
71
+ for iatom in range(self.natoms):
72
+ iorb = self.iorb(iatom)
73
+ #dG2= dG2[::2, ::2] + dG2[1::2, 1::2] + dG2[1::2, ::2] + dG2[::2, 1::2]
74
+ dE_atom_orb = dG2[np.ix_(iorb, iorb)] * self.G.kweights[ik]
75
+ dE_atom_orb = dE_atom_orb[::2, ::2] + dE_atom_orb[1::2, 1::2] + dE_atom_orb[1::2, ::2] + dE_atom_orb[::2, 1::2]
76
+ mmat = self.mmats[iatom]
77
+ dE_atom_orb = mmat.T @ dE_atom_orb @ mmat
78
+
79
+ dE_angle_atom_orb[(iangle, iatom)] += dE_atom_orb
80
+
81
+ dE_atom = np.sum(dE_atom_orb)
82
+ dE_angle_atom[iangle, iatom] += dE_atom
83
+ return dE_angle, dE_angle_atom, dE_angle_atom_orb
84
+
85
+ def get_perturbed_R(self, e, thetas, phis):
86
+ self.tbmodel.set_so_strength(0.0)
87
+ # Here only the first R vector is considered.
88
+ # TODO: consider all R vectors.
89
+ # Rlist = np.zeros((1, 3), dtype=float)
90
+ # G0K = self.G.get_Gk_all(e)
91
+ # G0R = k_to_R(self.G.kpts, Rlist, G0K, self.G.kweights)
92
+ # dE_angle = np.zeros(len(thetas), dtype=complex)
93
+ # dE_angle_atoms = np.zeros((len(thetas), self.natoms), dtype=complex)
94
+ pass
95
+
96
+ def get_band_energy_vs_angles(self, thetas, phis):
97
+ for ie, e in enumerate(tqdm.tqdm(self.contour.path)):
98
+ dE_angle, dE_angle_atom, dE_angle_atom_orb = self.get_perturbed(
99
+ e, thetas, phis
100
+ )
101
+ self.es += dE_angle * self.contour.weights[ie]
102
+ self.es_atom += dE_angle_atom * self.contour.weights[ie]
103
+ for key, value in dE_angle_atom_orb.items():
104
+ self.es_atom_orb[key] += dE_angle_atom_orb[key] * self.contour.weights[ie]
105
+
106
+ self.es = -np.imag(self.es) / np.pi
107
+ self.es_atom = -np.imag(self.es_atom) / np.pi
108
+ for key, value in self.es_atom_orb.items():
109
+ self.es_atom_orb[key] = -np.imag(value) / np.pi
110
+
111
+ def output(self, output_path="TB2J_anisotropy"):
112
+ Path(output_path).mkdir(exist_ok=True)
113
+ fname = f"{output_path}/MAE.dat"
114
+ fname_orb = f"{output_path}/MAE_orb.dat"
115
+ with open(fname, "w") as f:
116
+ f.write("# theta, phi, MAE(total), MAE(atom-wise) Unit: meV\n")
117
+ for i, (theta, phi, e, es) in enumerate(
118
+ zip(self.thetas, self.phis, self.es, self.es_atom)
119
+ ):
120
+ f.write(f"{theta:.5f} {phi:.5f} {e*1e3:.8f} ")
121
+ for ea in es:
122
+ f.write(f"{ea*1e3:.8f} ")
123
+ f.write("\n")
124
+
125
+ with open(fname_orb, "w") as f:
126
+ f.write("=" * 80 + "\n")
127
+ f.write("Orbitals for each atom: \n")
128
+ f.write("=" * 80 + "\n")
129
+ f.write("Note: the energies are in meV\n")
130
+ for iatom in range(self.natoms):
131
+ f.write(f"Atom {iatom:03d}: ")
132
+ for orb in self.orbital_names[iatom]:
133
+ f.write(f"{orb} ")
134
+ f.write("\n")
135
+ for i, (theta, phi, e, eatom) in enumerate(
136
+ zip(self.thetas, self.phis, self.es, self.es_atom)
137
+ ):
138
+ f.write("-" * 60 + "\n")
139
+ f.write(f"Angle {i:03d}: theta={theta:.5f} phi={phi:.5f} \n ")
140
+ f.write(f"E: {e*1e3:.8f} \n")
141
+ for iatom, ea in enumerate(eatom):
142
+ f.write(f"Atom {iatom:03d}: {ea*1e3:.8f} \n")
143
+ f.write("Orbital: ")
144
+ eorb = self.es_atom_orb[(i, iatom)]
145
+
146
+ # write numpy matrix to file
147
+ f.write(
148
+ np.array2string(
149
+ eorb*1e3, precision=4, separator=",", suppress_small=True
150
+ )
151
+ )
152
+
153
+ eorb_diff = eorb - self.es_atom_orb[(0, iatom)]
154
+ f.write("Diference to the first angle: ")
155
+ f.write(
156
+ np.array2string(
157
+ eorb_diff*1e3, precision=4, separator=",", suppress_small=True
158
+ )
159
+ )
160
+ f.write("\n")
161
+
162
+ def run(self, output_path="TB2J_anisotropy"):
163
+ self.get_band_energy_vs_angles(self.thetas, self.phis)
164
+ self.output(output_path=output_path)
165
+
166
+
167
+ def abacus_get_MAE(
168
+ path_nosoc,
169
+ path_soc,
170
+ kmesh,
171
+ thetas,
172
+ phis,
173
+ gamma=True,
174
+ output_path="TB2J_anisotropy",
175
+ magnetic_elements=None,
176
+ nel=None,
177
+ width=0.1,
178
+ **kwargs
179
+ ):
180
+ """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."""
181
+ parser = AbacusSplitSOCParser(
182
+ outpath_nosoc=path_nosoc, outpath_soc=path_soc, binary=False
183
+ )
184
+ model = parser.parse()
185
+ if nel is not None:
186
+ model.nel = nel
187
+ mae = MAEGreen(tbmodels=model, atoms = model.atoms, kmesh=kmesh, efermi=None, basis=model.basis, angles=[thetas, phis], magnetic_elements=magnetic_elements, **kwargs)
188
+ mae.run(output_path=output_path)
189
+ #es = mae.get_band_energy_vs_angles(thetas, phis)
190
+ #if outfile:
191
+ # with open(outfile, "w") as f:
192
+ # f.write("#theta, phi, energy\n")
193
+ # for theta, phi, e in zip(thetas, phis, es):
194
+ # f.write(f"{theta:5.3f}, {phi:5.3f}, {e:10.9f}\n")
195
+ #return es
196
+
197
+
@@ -50,7 +50,8 @@ class Exchange(ExchangeParams):
50
50
  os.makedirs(self.orbpath, exist_ok=True)
51
51
 
52
52
  def _adjust_emin(self):
53
- self.emin = self.G.find_energy_ingap(rbound=self.efermi - 5.0) - self.efermi
53
+ #self.emin = self.G.find_energy_ingap(rbound=self.efermi - 10.0) - self.efermi
54
+ self.emin = -12.0
54
55
  print(f"A gap is found at {self.emin}, set emin to it.")
55
56
 
56
57
  def set_tbmodels(self, tbmodels):
@@ -114,14 +115,19 @@ class Exchange(ExchangeParams):
114
115
  # e.g. Fe2, dxy, _, _
115
116
  if isinstance(base, str):
116
117
  atom_sym, orb_sym = base.split("|")[:2]
118
+ iatom = sdict[atom_sym]
117
119
  else:
118
- atom_sym, orb_sym = base[:2]
120
+ try:
121
+ atom_sym, orb_sym = base[:2]
122
+ except Exception as e:
123
+ iatom = base.iatom
124
+ atom_sym = base.iatom
125
+ orb_sym = base.sym
119
126
 
120
127
  if atom_sym in adict:
121
128
  adict[atom_sym].append(orb_sym)
122
129
  else:
123
130
  adict[atom_sym] = [orb_sym]
124
- iatom = sdict[atom_sym]
125
131
  if iatom not in self.orb_dict:
126
132
  self.orb_dict[iatom] = [i]
127
133
  self.labels[iatom] = [orb_sym]
@@ -144,8 +150,9 @@ class Exchange(ExchangeParams):
144
150
  )
145
151
  if not self._is_collinear:
146
152
  for iatom, orb in self.orb_dict.items():
153
+ print(f"iatom: {iatom}, orb: {orb}")
147
154
  nsorb = len(self.orb_dict[iatom])
148
- if nsorb % 2 != 0:
155
+ if nsorb % 2 != 0 and False:
149
156
  raise ValueError(
150
157
  f"""The number of spin-orbitals for atom {iatom} is not even,
151
158
  {nsorb} spin-orbitals are found near this atom.
@@ -166,7 +173,10 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
166
173
  self.mmats = {}
167
174
  self.orbital_names = {}
168
175
  self.norb_reduced = {}
169
- if self.backend_name.upper() == "SIESTA":
176
+ print(f"self.backend_name: {self.backend_name}")
177
+ if self.backend_name.upper() in ["SIESTA", "ABACUS", "LCAOHAMILTONIAN"]:
178
+ print(f"magntic_elements: {self.magnetic_elements}")
179
+ print(f"include_orbs: {self.include_orbs}")
170
180
  syms = self.atoms.get_chemical_symbols()
171
181
  for iatom, orbs in self.labels.items():
172
182
  if (self.include_orbs is not None) and syms[iatom] in self.include_orbs:
@@ -176,6 +186,7 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
176
186
  include_only=self.include_orbs[syms[iatom]],
177
187
  )
178
188
  else:
189
+ print(f"orbs: {orbs}")
179
190
  mmat, reduced_orbs = map_orbs_matrix(
180
191
  orbs, spinor=not (self._is_collinear), include_only=None
181
192
  )
@@ -231,7 +242,7 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
231
242
  """
232
243
  sum up the contribution of all the orbitals with same (n,l,m)
233
244
  """
234
- if self.backend_name.upper() == "SIESTA":
245
+ if self.backend_name.upper() in ["SIESTA", "ABACUS", "LCAOHAMILTONIAN"]:
235
246
  mmat_i = self.mmats[iatom]
236
247
  mmat_j = self.mmats[jatom]
237
248
  Jorbij = mmat_i.T @ Jorbij @ mmat_j
@@ -56,8 +56,11 @@ class ExchangeParams:
56
56
  ):
57
57
  self.efermi = efermi
58
58
  self.basis = basis
59
- self.magnetic_elements = magnetic_elements
60
- self.include_orbs = include_orbs
59
+ # self.magnetic_elements = magnetic_elements
60
+ # self.include_orbs = include_orbs
61
+ self.magnetic_elements, self.include_orbs = self.set_magnetic_elements(
62
+ magnetic_elements, include_orbs
63
+ )
61
64
  self._kmesh = kmesh
62
65
  self.emin = emin
63
66
  self.emax = emax
@@ -82,6 +85,28 @@ class ExchangeParams:
82
85
  with open(fname, "w") as myfile:
83
86
  yaml.dump(self.__dict__, myfile)
84
87
 
88
+ def set_magnetic_elements(self, magnetic_elements, include_orbs):
89
+ # magnetic_elements = exargs.pop("magnetic_elements")
90
+ # include_orbs = exargs.pop("include_orbs")
91
+ if include_orbs is None:
92
+ include_orbs = {}
93
+ if isinstance(magnetic_elements, str):
94
+ magnetic_elements = [magnetic_elements]
95
+ print(f"magnetic_elements: {magnetic_elements}")
96
+ print(f"include_orbs: {include_orbs}")
97
+ for element in magnetic_elements:
98
+ if "_" in element:
99
+ elem = element.split("_")[0]
100
+ orb = element.split("_")[1:]
101
+ include_orbs[elem] = orb
102
+ else:
103
+ include_orbs[element] = None
104
+
105
+ print(f"magnetic_elements: {magnetic_elements}")
106
+ print(f"include_orbs: {include_orbs}")
107
+ magnetic_elements = list(include_orbs.keys())
108
+ return magnetic_elements, include_orbs
109
+
85
110
 
86
111
  def add_exchange_args_to_parser(parser: argparse.ArgumentParser):
87
112
  parser.add_argument(
@@ -192,6 +192,7 @@ class AbacusParser:
192
192
  def read_basis(self):
193
193
  fname = str(Path(self.outpath) / "Orbital")
194
194
  self.basis = parse_abacus_orbital(fname)
195
+ print(self.basis)
195
196
  return self.basis
196
197
 
197
198
  def read_HSR_collinear(self, binary=None):
@@ -27,7 +27,7 @@ def gen_exchange_abacus(
27
27
  exclude_orbs=[],
28
28
  Rcut=None,
29
29
  use_cache=False,
30
- np=1,
30
+ nproc=1,
31
31
  output_path="TB2J_results",
32
32
  orb_decomposition=False,
33
33
  description=None,
@@ -60,9 +60,10 @@ data directory: {outpath}
60
60
  nz=nz,
61
61
  exclude_orbs=exclude_orbs,
62
62
  Rcut=Rcut,
63
- np=np,
63
+ nproc=nproc,
64
64
  use_cache=use_cache,
65
65
  output_path=output_path,
66
+ orb_decomposition=orb_decomposition,
66
67
  description=description,
67
68
  )
68
69
  exchange.run(path=output_path)
@@ -86,8 +87,9 @@ data directory: {outpath}
86
87
  nz=nz,
87
88
  exclude_orbs=exclude_orbs,
88
89
  Rcut=Rcut,
89
- np=np,
90
+ nproc=nproc,
90
91
  use_cache=use_cache,
92
+ orb_decomposition=orb_decomposition,
91
93
  description=description,
92
94
  )
93
95
  exchange.run()
@@ -16,13 +16,14 @@ class AbacusOrbital:
16
16
  Orbital class
17
17
  """
18
18
 
19
- iatom: int
20
- sym: str
21
- spin: int
22
- element: str
23
- l: int
24
- m: int
25
- z: int
19
+ iatom: int = 0
20
+ sym: str = ""
21
+ spin: int = 0
22
+ element: str = ""
23
+ n: int = 0
24
+ l: int = 0
25
+ m: int = 0
26
+ z: int = 0
26
27
 
27
28
 
28
29
  def parse_abacus_orbital(fname):
@@ -38,10 +39,11 @@ def parse_abacus_orbital(fname):
38
39
  iatom, element, l, m, z, sym = seg
39
40
  iatom = int(iatom)
40
41
  ispin = 0
42
+ n = 0
41
43
  l = int(l)
42
44
  m = int(m)
43
45
  z = int(z)
44
- orbs.append(AbacusOrbital(iatom, sym, ispin, element, l, m, z))
46
+ orbs.append(AbacusOrbital(iatom, sym, ispin, element, n, l, m, z))
45
47
  line = myfile.readline()
46
48
  return orbs
47
49
 
@@ -89,18 +89,6 @@ def gen_exchange_siesta(fdf_fname, read_H_soc=False, **kwargs):
89
89
  f"sisl version is {sisl.__version__}, but should be larger than 0.10.0."
90
90
  )
91
91
 
92
- magnetic_elements = exargs.pop("magnetic_elements")
93
- include_orbs = exargs.pop("include_orbs")
94
- if isinstance(magnetic_elements, str):
95
- magnetic_elements = [magnetic_elements]
96
- for element in magnetic_elements:
97
- if "_" in element:
98
- elem = element.split("_")[0]
99
- orb = element.split("_")[1:]
100
- include_orbs[elem] = orb
101
- else:
102
- include_orbs[element] = None
103
- magnetic_elements = list(include_orbs.keys())
104
92
  output_path = exargs.pop("output_path")
105
93
 
106
94
  parser = SislParser(
@@ -122,8 +110,8 @@ def gen_exchange_siesta(fdf_fname, read_H_soc=False, **kwargs):
122
110
  atoms=tbmodel_up.atoms,
123
111
  basis=basis,
124
112
  efermi=0.0,
125
- magnetic_elements=magnetic_elements,
126
- include_orbs=include_orbs,
113
+ # magnetic_elements=exargs['magnetic_elements'],
114
+ # include_orbs=ex
127
115
  **exargs,
128
116
  )
129
117
  exchange.run(path=output_path)
@@ -149,8 +137,8 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
149
137
  atoms=model.atoms,
150
138
  basis=basis,
151
139
  efermi=0.0,
152
- magnetic_elements=magnetic_elements,
153
- include_orbs=include_orbs,
140
+ # magnetic_elements=magnetic_elements,
141
+ # include_orbs=include_orbs,
154
142
  output_path=output_path,
155
143
  **exargs,
156
144
  )
@@ -167,8 +155,8 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
167
155
  atoms=model.atoms,
168
156
  basis=basis,
169
157
  efermi=None,
170
- magnetic_elements=magnetic_elements,
171
- include_orbs=include_orbs,
158
+ # magnetic_elements=magnetic_elements,
159
+ # include_orbs=include_orbs,
172
160
  **exargs,
173
161
  )
174
162
  # thetas = [0, np.pi / 2, np.pi, 3 * np.pi / 2]
@@ -191,8 +179,8 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
191
179
  atoms=model.atoms,
192
180
  basis=basis,
193
181
  efermi=None, # set to None, compute from efermi.
194
- magnetic_elements=magnetic_elements,
195
- include_orbs=include_orbs,
182
+ # magnetic_elements=magnetic_elements,
183
+ # include_orbs=include_orbs,
196
184
  **exargs,
197
185
  )
198
186
  exchange.run(path=output_path_full)
@@ -1,5 +1,6 @@
1
1
  import re
2
2
  from collections import defaultdict
3
+
3
4
  import numpy as np
4
5
 
5
6
 
@@ -7,30 +8,45 @@ def split_orb_name(name):
7
8
  """
8
9
  split name to : n, l, label
9
10
  """
10
- m = re.findall(r"(\d[a-z\d\-]*)(.*)", name)
11
+ m = re.findall(r"([a-z\d\-\^\*]*)(.*)", name)
11
12
  m = m[0]
12
13
  return m[0], m[1]
13
14
 
14
15
 
15
16
  def map_orbs_matrix(orblist, spinor=False, include_only=None):
17
+ """
18
+ map the orbitals to a matrix
19
+ Method:
20
+ 1. split the orbital name to n, l, label
21
+ 2. group the orbitals by n, l
22
+ 3. create a matrix with 1 for each orbital in the group
23
+ 4. return the matrix and the group names
24
+ """
25
+
16
26
  if spinor:
17
27
  orblist = orblist[::2]
18
28
 
19
29
  norb = len(orblist)
20
30
 
31
+ print("orblist: ", orblist)
21
32
  ss = [split_orb_name(orb) for orb in orblist]
22
33
  orbdict = dict(zip(ss, range(norb)))
23
34
 
24
35
  reduced_orbdict = defaultdict(lambda: [])
25
36
 
37
+ print(f"Orbital dictionary: {orbdict}")
38
+ print("include_only: ", include_only)
39
+
26
40
  if include_only is None:
27
41
  for key, val in orbdict.items():
28
42
  reduced_orbdict[key[0]].append(val)
29
43
  else:
30
44
  for key, val in orbdict.items():
31
- if key[0][:2] in include_only:
45
+ if key[0][:2] in include_only or key[0][:1] in include_only:
46
+ # [:2] for 3d, 4d, 5d, etc. and [:1] for s, p, d, etc
32
47
  reduced_orbdict[key[0]].append(val)
33
48
 
49
+ print(f"reduced_orbdict: {reduced_orbdict}")
34
50
  reduced_orbs = tuple(reduced_orbdict.keys())
35
51
  ngroup = len(reduced_orbdict)
36
52
  mmat = np.zeros((norb, ngroup), dtype=int)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: TB2J
3
- Version: 0.9.8rc0
3
+ Version: 0.9.9rc0
4
4
  Summary: TB2J: First principle to Heisenberg exchange J using tight-binding Green function method
5
5
  Author: Xu He
6
6
  Author-email: mailhexu@gmail.com
@@ -81,6 +81,7 @@ def run_abacus2J():
81
81
  )
82
82
 
83
83
  parser.add_argument(
84
+ "--nproc",
84
85
  "--np",
85
86
  help="number of cpu cores to use in parallel, default: 1",
86
87
  default=1,
@@ -121,28 +122,21 @@ def run_abacus2J():
121
122
  print("Please input the magnetic elements, e.g. --elements Fe Ni")
122
123
  sys.exit()
123
124
 
124
- include_orbs = {}
125
- for element in args.elements:
126
- if "_" in element:
127
- elem = element.split("_")[0]
128
- orb = element.split("_")[1:]
129
- include_orbs[elem] = orb
130
- else:
131
- include_orbs[element] = None
125
+ # include_orbs = {}
132
126
 
133
127
  gen_exchange_abacus(
134
128
  path=args.path,
135
129
  suffix=args.suffix,
136
130
  kmesh=args.kmesh,
137
- magnetic_elements=list(include_orbs.keys()),
138
- include_orbs=include_orbs,
131
+ magnetic_elements=args.elements,
132
+ include_orbs={},
139
133
  Rcut=args.rcut,
140
134
  emin=args.emin,
141
135
  nz=args.nz,
142
136
  description=args.description,
143
137
  output_path=args.output_path,
144
138
  use_cache=args.use_cache,
145
- nproc=args.np,
139
+ nproc=args.nproc,
146
140
  exclude_orbs=args.exclude_orbs,
147
141
  orb_decomposition=args.orb_decomposition,
148
142
  )
@@ -128,20 +128,22 @@ def run_siesta2J():
128
128
  print("Please input the magnetic elements, e.g. --elements Fe Ni")
129
129
  sys.exit()
130
130
 
131
- include_orbs = {}
132
- for element in args.elements:
133
- if "_" in element:
134
- elem = element.split("_")[0]
135
- orb = element.split("_")[1:]
136
- include_orbs[elem] = orb
137
- else:
138
- include_orbs[element] = None
131
+ # include_orbs = {}
132
+ # for element in args.elements:
133
+ # if "_" in element:
134
+ # elem = element.split("_")[0]
135
+ # orb = element.split("_")[1:]
136
+ # include_orbs[elem] = orb
137
+ # else:
138
+ # include_orbs[element] = None
139
139
 
140
140
  gen_exchange_siesta(
141
141
  fdf_fname=args.fdf_fname,
142
142
  kmesh=args.kmesh,
143
- magnetic_elements=list(include_orbs.keys()),
144
- include_orbs=include_orbs,
143
+ # magnetic_elements=list(include_orbs.keys()),
144
+ # include_orbs=include_orbs,
145
+ magnetic_elements=args.elements,
146
+ include_orbs={},
145
147
  Rcut=args.rcut,
146
148
  emin=args.emin,
147
149
  emax=args.emax,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python
2
2
  from setuptools import find_packages, setup
3
3
 
4
- __version__ = "0.9.8_pre"
4
+ __version__ = "0.9.9_pre"
5
5
 
6
6
  long_description = """TB2J is a Python package aimed to compute automatically the magnetic interactions (superexchange and Dzyaloshinskii-Moriya) between atoms of magnetic crystals from DFT Hamiltonian based on Wannier functions or Linear combination of atomic orbitals. It uses the Green's function method and take the local rigid spin rotation as a perturbation. The package can take the output from Wannier90, which is interfaced with many density functional theory codes or from codes based on localised orbitals. A minimal user input is needed, which allows for an easily integration into a high-throughput workflows. """
7
7
 
@@ -1,84 +0,0 @@
1
- from pathlib import Path
2
-
3
- import numpy as np
4
- import tqdm
5
-
6
- # from TB2J.abacus.abacus_wrapper import AbacusSplitSOCParser
7
- from TB2J.exchange import ExchangeNCL
8
-
9
- # from HamiltonIO.model.rotate_spin import rotate_Matrix_from_z_to_axis, rotate_Matrix_from_z_to_sperical
10
- # from TB2J.abacus.abacus_wrapper import AbacusWrapper, AbacusParser
11
- from TB2J.mathutils.rotate_spin import (
12
- rotate_spinor_matrix,
13
- )
14
-
15
-
16
- class MAEGreen(ExchangeNCL):
17
- def __init__(self, angles=None, **kwargs):
18
- super().__init__(**kwargs)
19
- self.es = None
20
- self.natoms = len(self.atoms)
21
- if angles is None or angles == "axis":
22
- self.set_angles_axis()
23
- elif angles == "scan":
24
- self.set_angles_scan()
25
-
26
- def set_angles_axis(self):
27
- """theta and phi are defined as the x, y, z, axis."""
28
- self.thetas = [0, np.pi / 2, np.pi / 2, np.pi / 2]
29
- self.phis = [0, 0, np.pi / 2, np.pi / 4]
30
-
31
- def set_angles_scan(self, step=15):
32
- self.thetas = []
33
- self.phis = []
34
- for i in range(0, 181, step):
35
- for j in range(0, 181, step):
36
- self.thetas.append(i * np.pi / 180)
37
- self.phis.append(j * np.pi / 180)
38
-
39
- def get_perturbed(self, e, thetas, phis):
40
- self.tbmodel.set_so_strength(0.0)
41
- G0K = self.G.get_Gk_all(e)
42
- Hsoc_k = self.tbmodel.get_Hk_soc(self.G.kpts)
43
- na = len(thetas)
44
- dE_angle = np.zeros(na, dtype=complex)
45
- dE_angle_atoms = np.zeros((na, self.natoms), dtype=complex)
46
- for iangle, (theta, phi) in enumerate(zip(thetas, phis)):
47
- for ik, dHk in enumerate(Hsoc_k):
48
- dHi = rotate_spinor_matrix(dHk, theta, phi)
49
- GdH = G0K[ik] @ dHi
50
- # dE += np.trace(GdH @ G0K[i].T.conj() @ dHi) * self.kweights[i]
51
- # diagonal of second order perturbation.
52
- dG2diag = np.diag(GdH @ GdH)
53
- # dG2diag = np.diag(GdH @G0K[i].T.conj() @ dHi)
54
- dE_angle[iangle] += np.sum(dG2diag) * self.G.kweights[ik]
55
- for iatom in range(self.natoms):
56
- dE_atom = np.sum(dG2diag[self.iorb(iatom)]) * self.G.kweights[ik]
57
- dE_angle_atoms[iangle, iatom] += dE_atom
58
- return dE_angle, dE_angle_atoms
59
-
60
- def get_band_energy_vs_angles(self, thetas, phis):
61
- nangles = len(thetas)
62
- self.es = np.zeros(nangles, dtype=float)
63
- self.es_atoms = np.zeros((nangles, self.natoms), dtype=float)
64
- for ie, e in enumerate(tqdm.tqdm(self.contour.path)):
65
- dE_angle, dE_angle_atoms = self.get_perturbed(e, thetas, phis)
66
- self.es -= np.imag(dE_angle * self.contour.weights[ie]) / np.pi
67
- self.es_atoms -= np.imag(dE_angle_atoms * self.contour.weights[ie]) / np.pi
68
-
69
- def output(self, output_path="TB2J_anisotropy"):
70
- Path(output_path).mkdir(exist_ok=True)
71
- fname = f"{output_path}/MAE.dat"
72
- with open(fname, "w") as f:
73
- f.write("# theta phi MAE, MAEatom1, atom2, ...\n")
74
- for i, (theta, phi, e, es) in enumerate(
75
- zip(self.thetas, self.phis, self.es, self.es_atoms)
76
- ):
77
- f.write(f"{theta:.5f} {phi:.5f} {e:.8f} ")
78
- for ea in es:
79
- f.write(f"{ea:.8f} ")
80
- f.write("\n")
81
-
82
- def run(self, output_path="TB2J_anisotropy"):
83
- self.get_band_energy_vs_angles(self.thetas, self.phis)
84
- self.output(output_path=output_path)
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
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
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes